summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt81
-rw-r--r--README.txt9
-rw-r--r--bindings/python/clang/__init__.py8
-rw-r--r--bindings/python/clang/cindex.py318
-rw-r--r--bindings/python/tests/cindex/test_cursor.py83
-rw-r--r--bindings/python/tests/cindex/test_diagnostics.py8
-rw-r--r--bindings/python/tests/cindex/test_exception_specification_kind.py27
-rw-r--r--bindings/python/tests/cindex/test_index.py2
-rw-r--r--bindings/python/tests/cindex/test_linkage.py30
-rw-r--r--bindings/python/tests/cindex/test_tls_kind.py37
-rw-r--r--bindings/python/tests/cindex/test_translation_unit.py7
-rw-r--r--bindings/python/tests/cindex/test_type.py17
-rw-r--r--cmake/caches/Android-stage2.cmake52
-rw-r--r--cmake/caches/Android.cmake43
-rw-r--r--cmake/caches/Apple-stage1.cmake8
-rw-r--r--cmake/caches/Apple-stage2.cmake11
-rw-r--r--cmake/caches/BaremetalARM.cmake50
-rw-r--r--cmake/caches/DistributionExample.cmake13
-rw-r--r--cmake/caches/Fuchsia-stage2.cmake62
-rw-r--r--cmake/caches/Fuchsia.cmake14
-rw-r--r--cmake/modules/CMakeLists.txt2
-rw-r--r--cmake/modules/ClangConfig.cmake.in7
-rw-r--r--cmake/modules/FindZ3.cmake28
-rw-r--r--cmake/modules/ProtobufMutator.cmake19
-rw-r--r--docs/AddressSanitizer.rst3
-rw-r--r--docs/Block-ABI-Apple.rst8
-rw-r--r--docs/CMakeLists.txt2
-rw-r--r--docs/ClangCommandLineReference.rst183
-rw-r--r--docs/ClangFormat.rst18
-rw-r--r--docs/ClangFormatStyleOptions.rst766
-rw-r--r--docs/ControlFlowIntegrity.rst29
-rw-r--r--docs/ControlFlowIntegrityDesign.rst130
-rw-r--r--docs/DiagnosticsReference.rst917
-rw-r--r--docs/ExternalClangExamples.rst8
-rw-r--r--docs/InternalsManual.rst20
-rw-r--r--docs/LTOVisibility.rst17
-rw-r--r--docs/LanguageExtensions.rst376
-rw-r--r--docs/LeakSanitizer.rst4
-rw-r--r--docs/LibASTMatchersReference.html280
-rw-r--r--docs/LibFormat.rst4
-rw-r--r--docs/MemorySanitizer.rst2
-rw-r--r--docs/Modules.rst80
-rw-r--r--docs/RefactoringEngine.rst253
-rw-r--r--docs/ReleaseNotes.rst153
-rw-r--r--docs/SanitizerCoverage.rst646
-rw-r--r--docs/SanitizerSpecialCaseList.rst32
-rw-r--r--docs/SourceBasedCodeCoverage.rst5
-rw-r--r--docs/ThinLTO.rst76
-rw-r--r--docs/ThreadSafetyAnalysis.rst6
-rw-r--r--docs/Toolchain.rst6
-rw-r--r--docs/UndefinedBehaviorSanitizer.rst41
-rw-r--r--docs/UsersManual.rst123
-rw-r--r--docs/analyzer/DebugChecks.rst18
-rw-r--r--docs/analyzer/DesignDiscussions/InitializerLists.rst321
-rw-r--r--docs/analyzer/conf.py4
-rw-r--r--docs/conf.py4
-rw-r--r--docs/doxygen.cfg.in8
-rw-r--r--docs/index.rst1
-rwxr-xr-xdocs/tools/dump_format_style.py11
-rw-r--r--include/clang-c/CXCompilationDatabase.h2
-rw-r--r--include/clang-c/Index.h260
-rw-r--r--include/clang/AST/ASTContext.h295
-rw-r--r--include/clang/AST/ASTMutationListener.h4
-rw-r--r--include/clang/AST/ASTStructuralEquivalence.h103
-rw-r--r--include/clang/AST/BuiltinTypes.def3
-rw-r--r--include/clang/AST/CMakeLists.txt3
-rw-r--r--include/clang/AST/CXXInheritance.h9
-rw-r--r--include/clang/AST/CanonicalType.h3
-rw-r--r--include/clang/AST/CharUnits.h4
-rw-r--r--include/clang/AST/CommentSema.h4
-rw-r--r--include/clang/AST/DataCollection.h65
-rw-r--r--include/clang/AST/Decl.h263
-rw-r--r--include/clang/AST/DeclBase.h192
-rw-r--r--include/clang/AST/DeclCXX.h161
-rw-r--r--include/clang/AST/DeclContextInternals.h2
-rw-r--r--include/clang/AST/DeclGroup.h5
-rw-r--r--include/clang/AST/DeclObjC.h36
-rw-r--r--include/clang/AST/DeclOpenMP.h20
-rw-r--r--include/clang/AST/Expr.h256
-rw-r--r--include/clang/AST/ExprCXX.h23
-rw-r--r--include/clang/AST/ExternalASTMerger.h176
-rw-r--r--include/clang/AST/ExternalASTSource.h2
-rw-r--r--include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h164
-rw-r--r--include/clang/AST/NSAPI.h4
-rw-r--r--include/clang/AST/NestedNameSpecifier.h2
-rw-r--r--include/clang/AST/ODRHash.h2
-rw-r--r--include/clang/AST/OpenMPClause.h463
-rw-r--r--include/clang/AST/PrettyPrinter.h24
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h131
-rw-r--r--include/clang/AST/Redeclarable.h54
-rw-r--r--include/clang/AST/Stmt.h4
-rw-r--r--include/clang/AST/StmtCXX.h27
-rw-r--r--include/clang/AST/StmtDataCollectors.td242
-rw-r--r--include/clang/AST/StmtIterator.h16
-rw-r--r--include/clang/AST/StmtOpenMP.h243
-rw-r--r--include/clang/AST/StmtVisitor.h26
-rw-r--r--include/clang/AST/TemplateName.h8
-rw-r--r--include/clang/AST/Type.h182
-rw-r--r--include/clang/AST/TypeLoc.h76
-rw-r--r--include/clang/AST/TypeNodes.def3
-rw-r--r--include/clang/AST/TypeOrdering.h2
-rw-r--r--include/clang/AST/VTableBuilder.h22
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h313
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h248
-rw-r--r--include/clang/ASTMatchers/Dynamic/Diagnostics.h2
-rw-r--r--include/clang/ASTMatchers/Dynamic/Parser.h35
-rw-r--r--include/clang/ASTMatchers/Dynamic/Registry.h16
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h31
-rw-r--r--include/clang/Analysis/Analyses/Consumed.h2
-rw-r--r--include/clang/Analysis/Analyses/Dominators.h8
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h2
-rw-r--r--include/clang/Analysis/Analyses/PostOrderCFGView.h2
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h2
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyCommon.h2
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyTIL.h23
-rw-r--r--include/clang/Analysis/AnalysisDeclContext.h (renamed from include/clang/Analysis/AnalysisContext.h)23
-rw-r--r--include/clang/Analysis/BodyFarm.h (renamed from lib/Analysis/BodyFarm.h)11
-rw-r--r--include/clang/Analysis/CFG.h74
-rw-r--r--include/clang/Analysis/CloneDetection.h385
-rw-r--r--include/clang/Analysis/ProgramPoint.h26
-rw-r--r--include/clang/Basic/AddressSpaces.h45
-rw-r--r--include/clang/Basic/AlignedAllocation.h44
-rw-r--r--include/clang/Basic/AllDiagnostics.h4
-rw-r--r--include/clang/Basic/Attr.td469
-rw-r--r--include/clang/Basic/AttrDocs.td405
-rw-r--r--include/clang/Basic/AttrSubjectMatchRules.h32
-rw-r--r--include/clang/Basic/Attributes.h2
-rw-r--r--include/clang/Basic/Builtins.def76
-rw-r--r--include/clang/Basic/Builtins.h7
-rw-r--r--include/clang/Basic/BuiltinsAArch64.def9
-rw-r--r--include/clang/Basic/BuiltinsAMDGPU.def4
-rw-r--r--include/clang/Basic/BuiltinsARM.def92
-rw-r--r--include/clang/Basic/BuiltinsHexagon.def6
-rw-r--r--include/clang/Basic/BuiltinsNVPTX.def43
-rw-r--r--include/clang/Basic/BuiltinsNios2.def70
-rw-r--r--include/clang/Basic/BuiltinsPPC.def11
-rw-r--r--include/clang/Basic/BuiltinsSystemZ.def24
-rw-r--r--include/clang/Basic/BuiltinsWebAssembly.def4
-rw-r--r--include/clang/Basic/BuiltinsX86.def63
-rw-r--r--include/clang/Basic/BuiltinsX86_64.def9
-rw-r--r--include/clang/Basic/CMakeLists.txt7
-rw-r--r--include/clang/Basic/CharInfo.h42
-rw-r--r--include/clang/Basic/Cuda.h7
-rw-r--r--include/clang/Basic/Diagnostic.h78
-rw-r--r--include/clang/Basic/Diagnostic.td14
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td20
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td8
-rw-r--r--include/clang/Basic/DiagnosticCrossTUKinds.td18
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td71
-rw-r--r--include/clang/Basic/DiagnosticError.h61
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td5
-rw-r--r--include/clang/Basic/DiagnosticGroups.td114
-rw-r--r--include/clang/Basic/DiagnosticIDs.h77
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td78
-rw-r--r--include/clang/Basic/DiagnosticOptions.def2
-rw-r--r--include/clang/Basic/DiagnosticOptions.h8
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td162
-rw-r--r--include/clang/Basic/DiagnosticRefactoringKinds.td34
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td578
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td158
-rw-r--r--include/clang/Basic/IdentifierTable.h41
-rw-r--r--include/clang/Basic/LLVM.h4
-rw-r--r--include/clang/Basic/LangOptions.def20
-rw-r--r--include/clang/Basic/LangOptions.h62
-rw-r--r--include/clang/Basic/Linkage.h24
-rw-r--r--include/clang/Basic/MemoryBufferCache.h80
-rw-r--r--include/clang/Basic/Module.h49
-rw-r--r--include/clang/Basic/ObjCRuntime.h14
-rw-r--r--include/clang/Basic/OpenMPKinds.def14
-rw-r--r--include/clang/Basic/PartialDiagnostic.h9
-rw-r--r--include/clang/Basic/SanitizerBlacklist.h15
-rw-r--r--include/clang/Basic/SanitizerSpecialCaseList.h54
-rw-r--r--include/clang/Basic/Sanitizers.def19
-rw-r--r--include/clang/Basic/Sanitizers.h10
-rw-r--r--include/clang/Basic/SourceLocation.h157
-rw-r--r--include/clang/Basic/SourceManager.h103
-rw-r--r--include/clang/Basic/SourceManagerInternals.h2
-rw-r--r--include/clang/Basic/Specifiers.h3
-rw-r--r--include/clang/Basic/SyncScope.h154
-rw-r--r--include/clang/Basic/TargetBuiltins.h10
-rw-r--r--include/clang/Basic/TargetInfo.h82
-rw-r--r--include/clang/Basic/TargetOptions.h6
-rw-r--r--include/clang/Basic/TemplateKinds.h14
-rw-r--r--include/clang/Basic/TokenKinds.def24
-rw-r--r--include/clang/Basic/TypeTraits.h5
-rw-r--r--include/clang/Basic/Visibility.h3
-rw-r--r--include/clang/Basic/XRayLists.h55
-rw-r--r--include/clang/CodeGen/CGFunctionInfo.h17
-rw-r--r--include/clang/CodeGen/CodeGenABITypes.h17
-rw-r--r--include/clang/CodeGen/ConstantInitFuture.h6
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h4
-rw-r--r--include/clang/Config/config.h.cmake11
-rw-r--r--include/clang/CrossTU/CrossTUDiagnostic.h29
-rw-r--r--include/clang/CrossTU/CrossTranslationUnit.h159
-rw-r--r--include/clang/Driver/CC1Options.td91
-rw-r--r--include/clang/Driver/CLCompatOptions.td15
-rw-r--r--include/clang/Driver/Compilation.h22
-rw-r--r--include/clang/Driver/Distro.h9
-rw-r--r--include/clang/Driver/Driver.h20
-rw-r--r--include/clang/Driver/Job.h18
-rw-r--r--include/clang/Driver/Multilib.h9
-rw-r--r--include/clang/Driver/Options.h5
-rw-r--r--include/clang/Driver/Options.td581
-rw-r--r--include/clang/Driver/SanitizerArgs.h19
-rw-r--r--include/clang/Driver/Tool.h2
-rw-r--r--include/clang/Driver/ToolChain.h61
-rw-r--r--include/clang/Driver/XRayArgs.h38
-rw-r--r--include/clang/Edit/EditedSource.h23
-rw-r--r--include/clang/Format/Format.h615
-rw-r--r--include/clang/Frontend/ASTUnit.h244
-rw-r--r--include/clang/Frontend/CodeGenOptions.def40
-rw-r--r--include/clang/Frontend/CodeGenOptions.h26
-rw-r--r--include/clang/Frontend/CommandLineSourceLoc.h46
-rw-r--r--include/clang/Frontend/CompilerInstance.h24
-rw-r--r--include/clang/Frontend/CompilerInvocation.h5
-rw-r--r--include/clang/Frontend/DiagnosticRenderer.h83
-rw-r--r--include/clang/Frontend/FrontendAction.h11
-rw-r--r--include/clang/Frontend/FrontendActions.h20
-rw-r--r--include/clang/Frontend/FrontendOptions.h114
-rw-r--r--include/clang/Frontend/LangStandard.h28
-rw-r--r--include/clang/Frontend/LangStandards.def157
-rw-r--r--include/clang/Frontend/PrecompiledPreamble.h236
-rw-r--r--include/clang/Frontend/PreprocessorOutputOptions.h2
-rw-r--r--include/clang/Frontend/TextDiagnostic.h43
-rw-r--r--include/clang/Frontend/Utils.h9
-rw-r--r--include/clang/Frontend/VerifyDiagnosticConsumer.h3
-rw-r--r--include/clang/Index/IndexSymbol.h9
-rw-r--r--include/clang/Index/IndexingAction.h10
-rw-r--r--include/clang/Index/USRGeneration.h18
-rw-r--r--include/clang/Lex/HeaderSearch.h54
-rw-r--r--include/clang/Lex/HeaderSearchOptions.h4
-rw-r--r--include/clang/Lex/Lexer.h38
-rw-r--r--include/clang/Lex/LiteralSupport.h1
-rw-r--r--include/clang/Lex/MacroArgs.h38
-rw-r--r--include/clang/Lex/MacroInfo.h78
-rw-r--r--include/clang/Lex/ModuleLoader.h34
-rw-r--r--include/clang/Lex/ModuleMap.h93
-rw-r--r--include/clang/Lex/MultipleIncludeOpt.h2
-rw-r--r--include/clang/Lex/PPCallbacks.h56
-rw-r--r--include/clang/Lex/PTHLexer.h2
-rw-r--r--include/clang/Lex/PreprocessingRecord.h6
-rw-r--r--include/clang/Lex/Preprocessor.h182
-rw-r--r--include/clang/Lex/PreprocessorLexer.h8
-rw-r--r--include/clang/Lex/PreprocessorOptions.h26
-rw-r--r--include/clang/Lex/Token.h8
-rw-r--r--include/clang/Lex/TokenLexer.h59
-rw-r--r--include/clang/Lex/VariadicMacroSupport.h226
-rw-r--r--include/clang/Parse/CMakeLists.txt6
-rw-r--r--include/clang/Parse/ParseAST.h7
-rw-r--r--include/clang/Parse/Parser.h169
-rw-r--r--include/clang/Parse/RAIIObjectsForParser.h (renamed from lib/Parse/RAIIObjectsForParser.h)20
-rw-r--r--include/clang/Rewrite/Frontend/FrontendActions.h7
-rw-r--r--include/clang/Sema/AttributeList.h20
-rw-r--r--include/clang/Sema/DeclSpec.h87
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h14
-rw-r--r--include/clang/Sema/IdentifierResolver.h16
-rw-r--r--include/clang/Sema/Initialization.h17
-rw-r--r--include/clang/Sema/Lookup.h33
-rw-r--r--include/clang/Sema/MultiplexExternalSemaSource.h2
-rw-r--r--include/clang/Sema/Overload.h40
-rw-r--r--include/clang/Sema/Ownership.h3
-rw-r--r--include/clang/Sema/ParsedTemplate.h69
-rw-r--r--include/clang/Sema/Scope.h11
-rw-r--r--include/clang/Sema/ScopeInfo.h8
-rw-r--r--include/clang/Sema/Sema.h578
-rw-r--r--include/clang/Sema/SemaInternal.h3
-rw-r--r--include/clang/Sema/TemplateDeduction.h6
-rw-r--r--include/clang/Serialization/ASTBitCodes.h26
-rw-r--r--include/clang/Serialization/ASTReader.h91
-rw-r--r--include/clang/Serialization/ASTWriter.h13
-rw-r--r--include/clang/Serialization/Module.h6
-rw-r--r--include/clang/Serialization/ModuleManager.h22
-rw-r--r--include/clang/StaticAnalyzer/Checkers/Checkers.td42
-rw-r--r--include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def6
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h39
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h (renamed from include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h)6
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h16
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h17
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h29
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h7
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h18
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h50
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h300
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h13
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h68
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h17
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h16
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h73
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h10
-rw-r--r--include/clang/Tooling/ASTDiff/ASTDiff.h127
-rw-r--r--include/clang/Tooling/ASTDiff/ASTDiffInternal.h48
-rw-r--r--include/clang/Tooling/ArgumentsAdjusters.h4
-rw-r--r--include/clang/Tooling/CommonOptionsParser.h50
-rw-r--r--include/clang/Tooling/CompilationDatabase.h19
-rw-r--r--include/clang/Tooling/Core/Diagnostic.h6
-rw-r--r--include/clang/Tooling/Core/Replacement.h2
-rw-r--r--include/clang/Tooling/DiagnosticsYaml.h15
-rw-r--r--include/clang/Tooling/Execution.h168
-rw-r--r--include/clang/Tooling/FixIt.h7
-rw-r--r--include/clang/Tooling/Refactoring/ASTSelection.h155
-rw-r--r--include/clang/Tooling/Refactoring/AtomicChange.h50
-rw-r--r--include/clang/Tooling/Refactoring/Extract/Extract.h53
-rw-r--r--include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h122
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringAction.h64
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringActionRule.h74
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h123
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringActionRules.h94
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h158
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringDiagnostic.h30
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringOption.h64
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h62
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringOptions.h58
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringResultConsumer.h52
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringRuleContext.h90
-rw-r--r--include/clang/Tooling/Refactoring/Rename/RenamingAction.h100
-rw-r--r--include/clang/Tooling/Refactoring/Rename/SymbolName.h49
-rw-r--r--include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h91
-rw-r--r--include/clang/Tooling/Refactoring/Rename/USRFinder.h50
-rw-r--r--include/clang/Tooling/Refactoring/Rename/USRFindingAction.h68
-rw-r--r--include/clang/Tooling/Refactoring/Rename/USRLocFinder.h53
-rw-r--r--include/clang/Tooling/RefactoringCallbacks.h50
-rw-r--r--include/clang/Tooling/StandaloneExecution.h97
-rw-r--r--include/clang/Tooling/ToolExecutorPluginRegistry.h24
-rw-r--r--include/clang/Tooling/Tooling.h20
-rw-r--r--include/clang/module.modulemap24
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp2
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp1
-rw-r--r--lib/ARCMigrate/TransformActions.cpp1
-rw-r--r--lib/AST/ASTContext.cpp325
-rw-r--r--lib/AST/ASTDiagnostic.cpp1
-rw-r--r--lib/AST/ASTDumper.cpp175
-rw-r--r--lib/AST/ASTImporter.cpp1521
-rw-r--r--lib/AST/ASTStructuralEquivalence.cpp1377
-rw-r--r--lib/AST/CMakeLists.txt8
-rw-r--r--lib/AST/CXXInheritance.cpp122
-rw-r--r--lib/AST/Comment.cpp20
-rw-r--r--lib/AST/CommentSema.cpp44
-rw-r--r--lib/AST/DataCollection.cpp50
-rw-r--r--lib/AST/Decl.cpp684
-rw-r--r--lib/AST/DeclBase.cpp102
-rw-r--r--lib/AST/DeclCXX.cpp243
-rw-r--r--lib/AST/DeclObjC.cpp61
-rw-r--r--lib/AST/DeclPrinter.cpp59
-rw-r--r--lib/AST/DeclarationName.cpp4
-rw-r--r--lib/AST/Expr.cpp163
-rw-r--r--lib/AST/ExprCXX.cpp20
-rw-r--r--lib/AST/ExprClassification.cpp10
-rw-r--r--lib/AST/ExprConstant.cpp241
-rw-r--r--lib/AST/ExternalASTMerger.cpp402
-rw-r--r--lib/AST/ExternalASTSource.cpp2
-rw-r--r--lib/AST/ItaniumMangle.cpp219
-rw-r--r--lib/AST/Linkage.h159
-rw-r--r--lib/AST/Mangle.cpp5
-rw-r--r--lib/AST/MicrosoftMangle.cpp97
-rw-r--r--lib/AST/NSAPI.cpp1
-rw-r--r--lib/AST/NestedNameSpecifier.cpp1
-rw-r--r--lib/AST/ODRHash.cpp352
-rw-r--r--lib/AST/OpenMPClause.cpp127
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp66
-rw-r--r--lib/AST/Stmt.cpp10
-rw-r--r--lib/AST/StmtCXX.cpp22
-rw-r--r--lib/AST/StmtOpenMP.cpp124
-rw-r--r--lib/AST/StmtPrinter.cpp137
-rw-r--r--lib/AST/StmtProfile.cpp70
-rw-r--r--lib/AST/TemplateName.cpp17
-rw-r--r--lib/AST/Type.cpp355
-rw-r--r--lib/AST/TypeLoc.cpp1
-rw-r--r--lib/AST/TypePrinter.cpp121
-rw-r--r--lib/AST/VTableBuilder.cpp10
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp5
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp52
-rw-r--r--lib/ASTMatchers/Dynamic/Diagnostics.cpp4
-rw-r--r--lib/ASTMatchers/Dynamic/Marshallers.h122
-rw-r--r--lib/ASTMatchers/Dynamic/Parser.cpp106
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp89
-rw-r--r--lib/ASTMatchers/Dynamic/VariantValue.cpp64
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp40
-rw-r--r--lib/Analysis/BodyFarm.cpp357
-rw-r--r--lib/Analysis/CFG.cpp406
-rw-r--r--lib/Analysis/CloneDetection.cpp1141
-rw-r--r--lib/Analysis/Consumed.cpp5
-rw-r--r--lib/Analysis/LiveVariables.cpp2
-rw-r--r--lib/Analysis/PrintfFormatString.cpp11
-rw-r--r--lib/Analysis/PseudoConstantAnalysis.cpp1
-rw-r--r--lib/Analysis/ReachableCode.cpp21
-rw-r--r--lib/Analysis/ScanfFormatString.cpp11
-rw-r--r--lib/Analysis/ThreadSafety.cpp21
-rw-r--r--lib/Analysis/ThreadSafetyCommon.cpp2
-rw-r--r--lib/Analysis/ThreadSafetyTIL.cpp4
-rw-r--r--lib/Analysis/UninitializedValues.cpp17
-rw-r--r--lib/Basic/Attributes.cpp11
-rw-r--r--lib/Basic/Builtins.cpp10
-rw-r--r--lib/Basic/CMakeLists.txt43
-rw-r--r--lib/Basic/Cuda.cpp24
-rw-r--r--lib/Basic/Diagnostic.cpp31
-rw-r--r--lib/Basic/DiagnosticIDs.cpp82
-rw-r--r--lib/Basic/FileManager.cpp9
-rw-r--r--lib/Basic/IdentifierTable.cpp24
-rw-r--r--lib/Basic/LangOptions.cpp6
-rw-r--r--lib/Basic/MemoryBufferCache.cpp48
-rw-r--r--lib/Basic/Module.cpp92
-rw-r--r--lib/Basic/OpenMPKinds.cpp28
-rw-r--r--lib/Basic/SanitizerBlacklist.cpp27
-rw-r--r--lib/Basic/SanitizerSpecialCaseList.cpp64
-rw-r--r--lib/Basic/SourceLocation.cpp70
-rw-r--r--lib/Basic/SourceManager.cpp234
-rw-r--r--lib/Basic/TargetInfo.cpp51
-rw-r--r--lib/Basic/Targets.cpp8956
-rw-r--r--lib/Basic/Targets.h51
-rw-r--r--lib/Basic/Targets/AArch64.cpp550
-rw-r--r--lib/Basic/Targets/AArch64.h166
-rw-r--r--lib/Basic/Targets/AMDGPU.cpp373
-rw-r--r--lib/Basic/Targets/AMDGPU.h329
-rw-r--r--lib/Basic/Targets/ARM.cpp1067
-rw-r--r--lib/Basic/Targets/ARM.h252
-rw-r--r--lib/Basic/Targets/AVR.cpp320
-rw-r--r--lib/Basic/Targets/AVR.h184
-rw-r--r--lib/Basic/Targets/BPF.cpp25
-rw-r--r--lib/Basic/Targets/BPF.h94
-rw-r--r--lib/Basic/Targets/Hexagon.cpp154
-rw-r--r--lib/Basic/Targets/Hexagon.h128
-rw-r--r--lib/Basic/Targets/Lanai.cpp67
-rw-r--r--lib/Basic/Targets/Lanai.h92
-rw-r--r--lib/Basic/Targets/Le64.cpp39
-rw-r--r--lib/Basic/Targets/Le64.h64
-rw-r--r--lib/Basic/Targets/MSP430.cpp34
-rw-r--r--lib/Basic/Targets/MSP430.h92
-rw-r--r--lib/Basic/Targets/Mips.cpp245
-rw-r--r--lib/Basic/Targets/Mips.h397
-rw-r--r--lib/Basic/Targets/NVPTX.cpp198
-rw-r--r--lib/Basic/Targets/NVPTX.h132
-rw-r--r--lib/Basic/Targets/Nios2.cpp56
-rw-r--r--lib/Basic/Targets/Nios2.h147
-rw-r--r--lib/Basic/Targets/OSTargets.cpp143
-rw-r--r--lib/Basic/Targets/OSTargets.h736
-rw-r--r--lib/Basic/Targets/PNaCl.cpp30
-rw-r--r--lib/Basic/Targets/PNaCl.h87
-rw-r--r--lib/Basic/Targets/PPC.cpp544
-rw-r--r--lib/Basic/Targets/PPC.h368
-rw-r--r--lib/Basic/Targets/SPIR.cpp33
-rw-r--r--lib/Basic/Targets/SPIR.h126
-rw-r--r--lib/Basic/Targets/Sparc.cpp197
-rw-r--r--lib/Basic/Targets/Sparc.h270
-rw-r--r--lib/Basic/Targets/SystemZ.cpp118
-rw-r--r--lib/Basic/Targets/SystemZ.h145
-rw-r--r--lib/Basic/Targets/TCE.cpp35
-rw-r--r--lib/Basic/Targets/TCE.h123
-rw-r--r--lib/Basic/Targets/WebAssembly.cpp87
-rw-r--r--lib/Basic/Targets/WebAssembly.h144
-rw-r--r--lib/Basic/Targets/X86.cpp1663
-rw-r--r--lib/Basic/Targets/X86.h995
-rw-r--r--lib/Basic/Targets/XCore.cpp38
-rw-r--r--lib/Basic/Targets/XCore.h82
-rw-r--r--lib/Basic/VirtualFileSystem.cpp5
-rw-r--r--lib/Basic/XRayLists.cpp59
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/ABIInfo.h3
-rw-r--r--lib/CodeGen/BackendUtil.cpp502
-rw-r--r--lib/CodeGen/CGAtomic.cpp308
-rw-r--r--lib/CodeGen/CGBlocks.cpp422
-rw-r--r--lib/CodeGen/CGBuilder.h7
-rw-r--r--lib/CodeGen/CGBuiltin.cpp1553
-rw-r--r--lib/CodeGen/CGCUDANV.cpp2
-rw-r--r--lib/CodeGen/CGCXX.cpp34
-rw-r--r--lib/CodeGen/CGCXXABI.cpp39
-rw-r--r--lib/CodeGen/CGCXXABI.h2
-rw-r--r--lib/CodeGen/CGCall.cpp261
-rw-r--r--lib/CodeGen/CGCall.h49
-rw-r--r--lib/CodeGen/CGClass.cpp236
-rw-r--r--lib/CodeGen/CGCleanup.cpp14
-rw-r--r--lib/CodeGen/CGCoroutine.cpp589
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp304
-rw-r--r--lib/CodeGen/CGDebugInfo.h19
-rw-r--r--lib/CodeGen/CGDecl.cpp102
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp100
-rw-r--r--lib/CodeGen/CGException.cpp60
-rw-r--r--lib/CodeGen/CGExpr.cpp997
-rw-r--r--lib/CodeGen/CGExprAgg.cpp48
-rw-r--r--lib/CodeGen/CGExprCXX.cpp125
-rw-r--r--lib/CodeGen/CGExprComplex.cpp42
-rw-r--r--lib/CodeGen/CGExprConstant.cpp1253
-rw-r--r--lib/CodeGen/CGExprScalar.cpp467
-rw-r--r--lib/CodeGen/CGObjC.cpp131
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp136
-rw-r--r--lib/CodeGen/CGObjCMac.cpp324
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp61
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.cpp71
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.h21
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp1392
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.h306
-rw-r--r--lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp189
-rw-r--r--lib/CodeGen/CGOpenMPRuntimeNVPTX.h20
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp37
-rw-r--r--lib/CodeGen/CGStmt.cpp62
-rw-r--r--lib/CodeGen/CGStmtOpenMP.cpp1443
-rw-r--r--lib/CodeGen/CGVTables.cpp43
-rw-r--r--lib/CodeGen/CGValue.h89
-rw-r--r--lib/CodeGen/CodeGenABITypes.cpp23
-rw-r--r--lib/CodeGen/CodeGenAction.cpp86
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp252
-rw-r--r--lib/CodeGen/CodeGenFunction.h445
-rw-r--r--lib/CodeGen/CodeGenModule.cpp627
-rw-r--r--lib/CodeGen/CodeGenModule.h183
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp7
-rw-r--r--lib/CodeGen/CodeGenPGO.h7
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp155
-rw-r--r--lib/CodeGen/CodeGenTBAA.h156
-rw-r--r--lib/CodeGen/CodeGenTypeCache.h11
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp14
-rw-r--r--lib/CodeGen/CodeGenTypes.h6
-rw-r--r--lib/CodeGen/ConstantEmitter.h178
-rw-r--r--lib/CodeGen/CoverageMappingGen.cpp256
-rw-r--r--lib/CodeGen/CoverageMappingGen.h2
-rw-r--r--lib/CodeGen/EHScopeStack.h2
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp181
-rw-r--r--lib/CodeGen/MacroPPCallbacks.cpp7
-rw-r--r--lib/CodeGen/MacroPPCallbacks.h4
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp123
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp15
-rw-r--r--lib/CodeGen/ObjectFilePCHContainerOperations.cpp3
-rw-r--r--lib/CodeGen/SwiftCallingConv.cpp8
-rw-r--r--lib/CodeGen/TargetInfo.cpp985
-rw-r--r--lib/CodeGen/TargetInfo.h71
-rw-r--r--lib/CrossTU/CMakeLists.txt13
-rw-r--r--lib/CrossTU/CrossTranslationUnit.cpp269
-rw-r--r--lib/Driver/CMakeLists.txt5
-rw-r--r--lib/Driver/Compilation.cpp53
-rw-r--r--lib/Driver/Distro.cpp4
-rw-r--r--lib/Driver/Driver.cpp168
-rw-r--r--lib/Driver/DriverOptions.cpp19
-rw-r--r--lib/Driver/Job.cpp39
-rw-r--r--lib/Driver/Multilib.cpp8
-rw-r--r--lib/Driver/SanitizerArgs.cpp247
-rw-r--r--lib/Driver/ToolChain.cpp180
-rw-r--r--lib/Driver/ToolChains/AMDGPU.cpp41
-rw-r--r--lib/Driver/ToolChains/AMDGPU.h16
-rw-r--r--lib/Driver/ToolChains/Ananas.cpp119
-rw-r--r--lib/Driver/ToolChains/Ananas.h (renamed from lib/Driver/ToolChains/Bitrig.h)38
-rw-r--r--lib/Driver/ToolChains/Arch/AArch64.cpp25
-rw-r--r--lib/Driver/ToolChains/Arch/ARM.cpp69
-rw-r--r--lib/Driver/ToolChains/Arch/ARM.h9
-rw-r--r--lib/Driver/ToolChains/Arch/Mips.cpp118
-rw-r--r--lib/Driver/ToolChains/Arch/Mips.h4
-rw-r--r--lib/Driver/ToolChains/Arch/PPC.cpp16
-rw-r--r--lib/Driver/ToolChains/Arch/PPC.h1
-rw-r--r--lib/Driver/ToolChains/Arch/X86.cpp3
-rw-r--r--lib/Driver/ToolChains/BareMetal.cpp202
-rw-r--r--lib/Driver/ToolChains/BareMetal.h89
-rw-r--r--lib/Driver/ToolChains/Bitrig.cpp190
-rw-r--r--lib/Driver/ToolChains/Clang.cpp2618
-rw-r--r--lib/Driver/ToolChains/Clang.h4
-rw-r--r--lib/Driver/ToolChains/CloudABI.cpp4
-rw-r--r--lib/Driver/ToolChains/CommonArgs.cpp281
-rw-r--r--lib/Driver/ToolChains/CommonArgs.h14
-rw-r--r--lib/Driver/ToolChains/CrossWindows.cpp70
-rw-r--r--lib/Driver/ToolChains/CrossWindows.h2
-rw-r--r--lib/Driver/ToolChains/Cuda.cpp302
-rw-r--r--lib/Driver/ToolChains/Cuda.h25
-rw-r--r--lib/Driver/ToolChains/Darwin.cpp294
-rw-r--r--lib/Driver/ToolChains/Darwin.h37
-rw-r--r--lib/Driver/ToolChains/DragonFly.cpp3
-rw-r--r--lib/Driver/ToolChains/FreeBSD.cpp3
-rw-r--r--lib/Driver/ToolChains/Fuchsia.cpp127
-rw-r--r--lib/Driver/ToolChains/Fuchsia.h29
-rw-r--r--lib/Driver/ToolChains/Gnu.cpp335
-rw-r--r--lib/Driver/ToolChains/Gnu.h5
-rw-r--r--lib/Driver/ToolChains/Hexagon.cpp132
-rw-r--r--lib/Driver/ToolChains/Hexagon.h9
-rw-r--r--lib/Driver/ToolChains/Linux.cpp58
-rw-r--r--lib/Driver/ToolChains/MSVC.cpp765
-rw-r--r--lib/Driver/ToolChains/MSVC.h37
-rw-r--r--lib/Driver/ToolChains/MSVCSetupApi.h514
-rw-r--r--lib/Driver/ToolChains/MinGW.cpp50
-rw-r--r--lib/Driver/ToolChains/MinGW.h3
-rw-r--r--lib/Driver/ToolChains/Minix.cpp3
-rw-r--r--lib/Driver/ToolChains/MipsLinux.cpp2
-rw-r--r--lib/Driver/ToolChains/Myriad.cpp9
-rw-r--r--lib/Driver/ToolChains/NaCl.cpp16
-rw-r--r--lib/Driver/ToolChains/NetBSD.cpp28
-rw-r--r--lib/Driver/ToolChains/NetBSD.h6
-rw-r--r--lib/Driver/ToolChains/OpenBSD.cpp5
-rw-r--r--lib/Driver/ToolChains/PS4CPU.cpp3
-rw-r--r--lib/Driver/ToolChains/Solaris.cpp4
-rw-r--r--lib/Driver/ToolChains/Solaris.h2
-rw-r--r--lib/Driver/ToolChains/WebAssembly.cpp46
-rw-r--r--lib/Driver/ToolChains/WebAssembly.h3
-rw-r--r--lib/Driver/ToolChains/XCore.cpp3
-rw-r--r--lib/Driver/ToolChains/XCore.h3
-rw-r--r--lib/Driver/XRayArgs.cpp114
-rw-r--r--lib/Edit/EditedSource.cpp62
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp4
-rw-r--r--lib/Format/BreakableToken.cpp199
-rw-r--r--lib/Format/BreakableToken.h59
-rw-r--r--lib/Format/CMakeLists.txt1
-rw-r--r--lib/Format/ContinuationIndenter.cpp406
-rw-r--r--lib/Format/ContinuationIndenter.h42
-rw-r--r--lib/Format/Format.cpp314
-rw-r--r--lib/Format/FormatInternal.h79
-rw-r--r--lib/Format/FormatToken.cpp6
-rw-r--r--lib/Format/FormatToken.h207
-rw-r--r--lib/Format/FormatTokenLexer.cpp95
-rw-r--r--lib/Format/FormatTokenLexer.h3
-rw-r--r--lib/Format/NamespaceEndCommentsFixer.cpp74
-rw-r--r--lib/Format/NamespaceEndCommentsFixer.h2
-rw-r--r--lib/Format/SortJavaScriptImports.cpp16
-rw-r--r--lib/Format/TokenAnalyzer.cpp40
-rw-r--r--lib/Format/TokenAnalyzer.h47
-rw-r--r--lib/Format/TokenAnnotator.cpp470
-rw-r--r--lib/Format/TokenAnnotator.h5
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp350
-rw-r--r--lib/Format/UnwrappedLineFormatter.h16
-rw-r--r--lib/Format/UnwrappedLineParser.cpp448
-rw-r--r--lib/Format/UnwrappedLineParser.h46
-rw-r--r--lib/Format/UsingDeclarationsSorter.cpp156
-rw-r--r--lib/Format/UsingDeclarationsSorter.h37
-rw-r--r--lib/Format/WhitespaceManager.cpp247
-rw-r--r--lib/Format/WhitespaceManager.h19
-rw-r--r--lib/Frontend/ASTConsumers.cpp2
-rw-r--r--lib/Frontend/ASTMerge.cpp11
-rw-r--r--lib/Frontend/ASTUnit.cpp1134
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp2
-rw-r--r--lib/Frontend/CompilerInstance.cpp422
-rw-r--r--lib/Frontend/CompilerInvocation.cpp688
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp8
-rw-r--r--lib/Frontend/DependencyFile.cpp6
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp196
-rw-r--r--lib/Frontend/FrontendAction.cpp486
-rw-r--r--lib/Frontend/FrontendActions.cpp307
-rw-r--r--lib/Frontend/FrontendOptions.cpp36
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp3
-rw-r--r--lib/Frontend/InitPreprocessor.cpp87
-rw-r--r--lib/Frontend/LangStandards.cpp8
-rw-r--r--lib/Frontend/ModuleDependencyCollector.cpp2
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp7
-rw-r--r--lib/Frontend/PrecompiledPreamble.cpp572
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp178
-rw-r--r--lib/Frontend/Rewrite/CMakeLists.txt1
-rw-r--r--lib/Frontend/Rewrite/FrontendActions.cpp133
-rw-r--r--lib/Frontend/Rewrite/InclusionRewriter.cpp68
-rw-r--r--lib/Frontend/Rewrite/RewriteMacros.cpp2
-rw-r--r--lib/Frontend/Rewrite/RewriteModernObjC.cpp18
-rw-r--r--lib/Frontend/Rewrite/RewriteObjC.cpp9
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp108
-rw-r--r--lib/Frontend/SerializedDiagnosticReader.cpp4
-rw-r--r--lib/Frontend/TextDiagnostic.cpp330
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp7
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp15
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp21
-rw-r--r--lib/Headers/CMakeLists.txt4
-rw-r--r--lib/Headers/__clang_cuda_intrinsics.h124
-rw-r--r--lib/Headers/__clang_cuda_runtime_wrapper.h30
-rw-r--r--lib/Headers/altivec.h111
-rw-r--r--lib/Headers/arm64intr.h49
-rw-r--r--lib/Headers/arm_acle.h318
-rw-r--r--lib/Headers/avx2intrin.h15
-rw-r--r--lib/Headers/avx512bwintrin.h71
-rw-r--r--lib/Headers/avx512dqintrin.h38
-rw-r--r--lib/Headers/avx512fintrin.h321
-rw-r--r--lib/Headers/avx512vlbwintrin.h50
-rw-r--r--lib/Headers/avx512vldqintrin.h54
-rw-r--r--lib/Headers/avx512vlintrin.h69
-rw-r--r--lib/Headers/avx512vpopcntdqintrin.h70
-rw-r--r--lib/Headers/avxintrin.h516
-rw-r--r--lib/Headers/bmiintrin.h176
-rw-r--r--lib/Headers/clflushoptintrin.h2
-rw-r--r--lib/Headers/clwbintrin.h52
-rw-r--r--lib/Headers/cpuid.h118
-rw-r--r--lib/Headers/cuda_wrappers/new51
-rw-r--r--lib/Headers/emmintrin.h345
-rw-r--r--lib/Headers/f16cintrin.h10
-rw-r--r--lib/Headers/float.h23
-rw-r--r--lib/Headers/htmxlintrin.h14
-rw-r--r--lib/Headers/immintrin.h26
-rw-r--r--lib/Headers/intrin.h61
-rw-r--r--lib/Headers/lwpintrin.h150
-rw-r--r--lib/Headers/mmintrin.h103
-rw-r--r--lib/Headers/opencl-c.h1223
-rw-r--r--lib/Headers/pmmintrin.h8
-rw-r--r--lib/Headers/prfchwintrin.h6
-rw-r--r--lib/Headers/smmintrin.h273
-rw-r--r--lib/Headers/stdatomic.h20
-rw-r--r--lib/Headers/stdint.h29
-rw-r--r--lib/Headers/tgmath.h16
-rw-r--r--lib/Headers/tmmintrin.h88
-rw-r--r--lib/Headers/unwind.h80
-rw-r--r--lib/Headers/vecintrin.h1572
-rw-r--r--lib/Headers/x86intrin.h6
-rw-r--r--lib/Headers/xmmintrin.h57
-rw-r--r--lib/Index/CodegenNameGenerator.cpp39
-rw-r--r--lib/Index/CommentToXML.cpp5
-rw-r--r--lib/Index/IndexBody.cpp100
-rw-r--r--lib/Index/IndexDecl.cpp311
-rw-r--r--lib/Index/IndexSymbol.cpp73
-rw-r--r--lib/Index/IndexTypeSourceInfo.cpp62
-rw-r--r--lib/Index/IndexingAction.cpp12
-rw-r--r--lib/Index/IndexingContext.cpp124
-rw-r--r--lib/Index/IndexingContext.h9
-rw-r--r--lib/Index/USRGeneration.cpp197
-rw-r--r--lib/Lex/HeaderSearch.cpp64
-rw-r--r--lib/Lex/Lexer.cpp281
-rw-r--r--lib/Lex/LiteralSupport.cpp73
-rw-r--r--lib/Lex/MacroArgs.cpp63
-rw-r--r--lib/Lex/MacroInfo.cpp23
-rw-r--r--lib/Lex/ModuleMap.cpp637
-rw-r--r--lib/Lex/PPDirectives.cpp559
-rw-r--r--lib/Lex/PPExpressions.cpp84
-rw-r--r--lib/Lex/PPLexerChange.cpp188
-rw-r--r--lib/Lex/PPMacroExpansion.cpp20
-rw-r--r--lib/Lex/Pragma.cpp300
-rw-r--r--lib/Lex/PreprocessingRecord.cpp8
-rw-r--r--lib/Lex/Preprocessor.cpp78
-rw-r--r--lib/Lex/ScratchBuffer.cpp8
-rw-r--r--lib/Lex/TokenLexer.cpp322
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp51
-rw-r--r--lib/Parse/ParseDecl.cpp295
-rw-r--r--lib/Parse/ParseDeclCXX.cpp196
-rw-r--r--lib/Parse/ParseExpr.cpp176
-rw-r--r--lib/Parse/ParseExprCXX.cpp99
-rw-r--r--lib/Parse/ParseInit.cpp5
-rw-r--r--lib/Parse/ParseObjc.cpp141
-rw-r--r--lib/Parse/ParseOpenMP.cpp174
-rw-r--r--lib/Parse/ParsePragma.cpp795
-rw-r--r--lib/Parse/ParseStmt.cpp50
-rw-r--r--lib/Parse/ParseStmtAsm.cpp239
-rw-r--r--lib/Parse/ParseTemplate.cpp104
-rw-r--r--lib/Parse/ParseTentative.cpp49
-rw-r--r--lib/Parse/Parser.cpp164
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp6
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp216
-rw-r--r--lib/Sema/AttributeList.cpp26
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CoroutineStmtBuilder.h73
-rw-r--r--lib/Sema/DeclSpec.cpp8
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp6
-rw-r--r--lib/Sema/JumpDiagnostics.cpp9
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp6
-rw-r--r--lib/Sema/Sema.cpp327
-rw-r--r--lib/Sema/SemaAttr.cpp329
-rw-r--r--lib/Sema/SemaCUDA.cpp6
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp33
-rw-r--r--lib/Sema/SemaCast.cpp155
-rw-r--r--lib/Sema/SemaChecking.cpp878
-rw-r--r--lib/Sema/SemaCodeComplete.cpp222
-rw-r--r--lib/Sema/SemaCoroutine.cpp692
-rw-r--r--lib/Sema/SemaDecl.cpp1327
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1091
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1123
-rw-r--r--lib/Sema/SemaDeclObjC.cpp341
-rw-r--r--lib/Sema/SemaExpr.cpp1241
-rw-r--r--lib/Sema/SemaExprCXX.cpp409
-rw-r--r--lib/Sema/SemaExprMember.cpp117
-rw-r--r--lib/Sema/SemaExprObjC.cpp90
-rw-r--r--lib/Sema/SemaInit.cpp292
-rw-r--r--lib/Sema/SemaLambda.cpp84
-rw-r--r--lib/Sema/SemaLookup.cpp447
-rw-r--r--lib/Sema/SemaObjCProperty.cpp254
-rw-r--r--lib/Sema/SemaOpenMP.cpp1883
-rw-r--r--lib/Sema/SemaOverload.cpp902
-rw-r--r--lib/Sema/SemaPseudoObject.cpp42
-rw-r--r--lib/Sema/SemaStmt.cpp343
-rw-r--r--lib/Sema/SemaStmtAsm.cpp89
-rw-r--r--lib/Sema/SemaStmtAttr.cpp35
-rw-r--r--lib/Sema/SemaTemplate.cpp639
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp311
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp108
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp286
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp183
-rw-r--r--lib/Sema/SemaType.cpp598
-rw-r--r--lib/Sema/TreeTransform.h401
-rw-r--r--lib/Serialization/ASTCommon.cpp3
-rw-r--r--lib/Serialization/ASTReader.cpp1370
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp353
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp163
-rw-r--r--lib/Serialization/ASTWriter.cpp411
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp82
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp103
-rw-r--r--lib/Serialization/GeneratePCH.cpp7
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp4
-rw-r--r--lib/Serialization/ModuleManager.cpp39
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp49
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp46
-rw-r--r--lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp54
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt5
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp88
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/CloneChecker.cpp107
-rw-r--r--lib/StaticAnalyzer/Checkers/ConversionChecker.cpp85
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp1
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp153
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp83
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorChecker.cpp833
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp842
-rw-r--r--lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp112
-rw-r--r--lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp178
-rw-r--r--lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp526
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp140
-rw-r--r--lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp181
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp222
-rw-r--r--lib/StaticAnalyzer/Checkers/SelectorExtras.h40
-rw-r--r--lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp51
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp55
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ValistChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp453
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp42
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp26
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp103
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp119
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt18
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp52
-rw-r--r--lib/StaticAnalyzer/Core/CheckerContext.cpp32
-rw-r--r--lib/StaticAnalyzer/Core/CommonBugCategories.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/DynamicTypeMap.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp174
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp314
-rw-r--r--lib/StaticAnalyzer/Core/IssueHash.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/LoopUnrolling.cpp294
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp64
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp49
-rw-r--r--lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h2
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp100
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp60
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp133
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp52
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp1618
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp9
-rw-r--r--lib/StaticAnalyzer/Frontend/ModelInjector.cpp2
-rw-r--r--lib/Tooling/ASTDiff/ASTDiff.cpp1021
-rw-r--r--lib/Tooling/ASTDiff/CMakeLists.txt11
-rw-r--r--lib/Tooling/ArgumentsAdjusters.cpp27
-rw-r--r--lib/Tooling/CMakeLists.txt3
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp125
-rw-r--r--lib/Tooling/CompilationDatabase.cpp50
-rw-r--r--lib/Tooling/Core/Diagnostic.cpp6
-rw-r--r--lib/Tooling/Core/Replacement.cpp2
-rw-r--r--lib/Tooling/Execution.cpp89
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp8
-rw-r--r--lib/Tooling/Refactoring.cpp2
-rw-r--r--lib/Tooling/Refactoring/ASTSelection.cpp384
-rw-r--r--lib/Tooling/Refactoring/ASTSelectionRequirements.cpp48
-rw-r--r--lib/Tooling/Refactoring/AtomicChange.cpp195
-rw-r--r--lib/Tooling/Refactoring/CMakeLists.txt20
-rw-r--r--lib/Tooling/Refactoring/Extract.cpp195
-rw-r--r--lib/Tooling/Refactoring/RefactoringActions.cpp94
-rw-r--r--lib/Tooling/Refactoring/Rename/RenamingAction.cpp230
-rw-r--r--lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp37
-rw-r--r--lib/Tooling/Refactoring/Rename/USRFinder.cpp146
-rw-r--r--lib/Tooling/Refactoring/Rename/USRFindingAction.cpp274
-rw-r--r--lib/Tooling/Refactoring/Rename/USRLocFinder.cpp585
-rw-r--r--lib/Tooling/RefactoringCallbacks.cpp154
-rw-r--r--lib/Tooling/StandaloneExecution.cpp91
-rw-r--r--lib/Tooling/Tooling.cpp37
-rw-r--r--runtime/CMakeLists.txt7
-rw-r--r--test/ARCMT/remap-applying.c4
-rw-r--r--test/ARCMT/remap-applying.c.result4
-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/DeleteWithNonVirtualDtor.cpp187
-rw-r--r--test/Analysis/DynamicTypePropagation.m12
-rw-r--r--test/Analysis/Inputs/system-header-simulator-cxx.h387
-rw-r--r--test/Analysis/MismatchedDeallocator-path-notes.cpp2
-rw-r--r--test/Analysis/MisusedMovedObject.cpp675
-rw-r--r--test/Analysis/NewDelete-path-notes.cpp4
-rw-r--r--test/Analysis/additive-folding.cpp9
-rw-r--r--test/Analysis/analyzer-config.c11
-rw-r--r--test/Analysis/analyzer-config.cpp10
-rw-r--r--test/Analysis/analyzer_test.py43
-rw-r--r--test/Analysis/bitwise-ops.c27
-rw-r--r--test/Analysis/block-in-critical-section.cpp42
-rw-r--r--test/Analysis/block-in-critical-section.m10
-rw-r--r--test/Analysis/bstring.cpp41
-rw-r--r--test/Analysis/bug_hash_test.cpp1423
-rw-r--r--test/Analysis/bug_hash_test.m1182
-rw-r--r--test/Analysis/builtin-functions.cpp14
-rw-r--r--test/Analysis/call_once.cpp305
-rw-r--r--test/Analysis/casts.c31
-rw-r--r--test/Analysis/compound-literals.c9
-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/autogenerated_automoc.cpp19
-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/dbus_autogenerated.cpp19
-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/macros.cpp2
-rw-r--r--test/Analysis/copypaste/moc_autogenerated.cpp19
-rw-r--r--test/Analysis/copypaste/not-autogenerated.cpp14
-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/copypaste/ui_autogenerated.cpp19
-rw-r--r--test/Analysis/ctor.mm28
-rw-r--r--test/Analysis/diagnostics/diag-cross-file-boundaries.c12
-rw-r--r--test/Analysis/diagnostics/explicit-suppression.cpp2
-rw-r--r--test/Analysis/diagnostics/report-issues-within-main-file.cpp2
-rw-r--r--test/Analysis/edges-new.mm6
-rw-r--r--test/Analysis/enum.cpp43
-rw-r--r--test/Analysis/exercise-ps.c8
-rw-r--r--test/Analysis/expr-inspection.c3
-rw-r--r--test/Analysis/func-mapping-test.cpp7
-rw-r--r--test/Analysis/gmalloc.c110
-rw-r--r--test/Analysis/gtest.cpp14
-rw-r--r--test/Analysis/html-diag-singlefile.c14
-rw-r--r--test/Analysis/html-diag-singlefile.h (renamed from test/Analysis/diagnostics/diag-cross-file-boundaries.h)0
-rw-r--r--test/Analysis/html-diags-analyze-headers.c10
-rw-r--r--test/Analysis/html-diags-analyze-headers.h5
-rw-r--r--test/Analysis/html-diags-multifile.c5
-rw-r--r--test/Analysis/html-diags.c18
-rw-r--r--test/Analysis/initializer.cpp18
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.c53
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.cpp15
-rw-r--r--test/Analysis/iterator-past-end.cpp205
-rw-r--r--test/Analysis/iterator-range.cpp19
-rw-r--r--test/Analysis/lifetime-cfg-output.cpp783
-rw-r--r--test/Analysis/lit.local.cfg33
-rw-r--r--test/Analysis/localization-aggressive.m19
-rw-r--r--test/Analysis/loop-unrolling.cpp381
-rw-r--r--test/Analysis/loopexit-cfg-output.cpp476
-rw-r--r--test/Analysis/malloc-overflow2.c6
-rw-r--r--test/Analysis/malloc-plist.c36
-rw-r--r--test/Analysis/malloc.c10
-rw-r--r--test/Analysis/malloc.mm2
-rw-r--r--test/Analysis/max-nodes-suppress-on-sink.c52
-rw-r--r--test/Analysis/max-nodes-suppress-on-sink.cpp34
-rw-r--r--test/Analysis/nonnull-global-constants.mm103
-rw-r--r--test/Analysis/null-deref-offsets.c37
-rw-r--r--test/Analysis/null-deref-path-notes.c9
-rw-r--r--test/Analysis/null-deref-path-notes.cpp25
-rw-r--r--test/Analysis/null-deref-path-notes.m240
-rw-r--r--test/Analysis/null-deref-ps-region.c61
-rw-r--r--test/Analysis/null-deref-ps.c4
-rw-r--r--test/Analysis/nullability-notes.m204
-rw-r--r--test/Analysis/nullptr.cpp65
-rw-r--r--test/Analysis/objc-boxing.m35
-rw-r--r--test/Analysis/objc-encode.m9
-rw-r--r--test/Analysis/objc-for.m19
-rw-r--r--test/Analysis/plist-macros.cpp4
-rw-r--r--test/Analysis/pointer-arithmetic.c30
-rw-r--r--test/Analysis/properties.m16
-rw-r--r--test/Analysis/pthreadlock.c79
-rw-r--r--test/Analysis/ptr-arith.c5
-rw-r--r--test/Analysis/ptr-arith.cpp19
-rw-r--r--test/Analysis/reference.cpp11
-rw-r--r--test/Analysis/retain-release-inline.m90
-rw-r--r--test/Analysis/retain-release-safe.c72
-rw-r--r--test/Analysis/retain-release.m19
-rw-r--r--test/Analysis/retain-release.mm9
-rw-r--r--test/Analysis/simple-stream-checks.c2
-rw-r--r--test/Analysis/taint-generic.c41
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp81
-rw-r--r--test/Analysis/temporaries-callback-order.cpp36
-rw-r--r--test/Analysis/temporaries.cpp27
-rw-r--r--test/Analysis/uninit-const.cpp2
-rw-r--r--test/Analysis/unix-fns.c4
-rw-r--r--test/Analysis/unreachable-code-path.c10
-rw-r--r--test/Analysis/unsupported-types.c31
-rw-r--r--test/Analysis/virtualcall.cpp281
-rw-r--r--test/Analysis/virtualcall.h32
-rw-r--r--test/CMakeLists.txt16
-rw-r--r--test/CXX/basic/basic.link/p8.cpp78
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp1
-rw-r--r--test/CXX/basic/basic.scope/basic.scope.declarative/p4.cpp19
-rw-r--r--test/CXX/class.access/p4.cpp2
-rw-r--r--test/CXX/class/class.static/class.static.data/p3.cpp2
-rw-r--r--test/CXX/conv/conv.prom/p2.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp37
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp22
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp10
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp28
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp33
-rw-r--r--test/CXX/drs/dr0xx.cpp20
-rw-r--r--test/CXX/drs/dr11xx.cpp30
-rw-r--r--test/CXX/drs/dr13xx.cpp29
-rw-r--r--test/CXX/drs/dr1xx.cpp4
-rw-r--r--test/CXX/drs/dr20xx.cpp30
-rw-r--r--test/CXX/drs/dr2xx.cpp8
-rw-r--r--test/CXX/drs/dr3xx.cpp13
-rw-r--r--test/CXX/drs/dr4xx.cpp15
-rw-r--r--test/CXX/drs/dr5xx.cpp4
-rw-r--r--test/CXX/except/except.spec/p1.cpp9
-rw-r--r--test/CXX/except/except.spec/p11.cpp9
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp14
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp4
-rw-r--r--test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp41
-rw-r--r--test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm129
-rw-r--r--test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp23
-rw-r--r--test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp55
-rw-r--r--test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp19
-rw-r--r--test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp44
-rw-r--r--test/CXX/modules-ts/basic/basic.link/module-declaration.cpp56
-rw-r--r--test/CXX/modules-ts/basic/basic.link/p2/module.cpp17
-rw-r--r--test/CXX/modules-ts/basic/basic.link/p2/module.cppm29
-rw-r--r--test/CXX/modules-ts/basic/basic.link/p2/other.cpp16
-rw-r--r--test/CXX/modules-ts/basic/basic.link/p3.cppm11
-rw-r--r--test/CXX/modules-ts/basic/basic.search/module-import.cpp39
-rw-r--r--test/CXX/modules-ts/codegen-basics.cppm (renamed from test/CodeGenCXX/modules-ts.cppm)18
-rw-r--r--test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp49
-rw-r--r--test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp28
-rw-r--r--test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp14
-rw-r--r--test/CXX/modules-ts/dcl.dcl/dcl.module/p2.cpp6
-rw-r--r--test/CXX/modules-ts/dcl.dcl/dcl.module/p5.cpp33
-rw-r--r--test/CXX/over/over.match/over.match.best/p1.cpp6
-rw-r--r--test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp68
-rw-r--r--test/CXX/special/class.dtor/p5-implicit.cpp21
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp4
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p5.cpp13
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p4.cpp98
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp9
-rw-r--r--test/CodeCompletion/crash-func-init.cpp4
-rw-r--r--test/CodeCompletion/functions.cpp2
-rw-r--r--test/CodeCompletion/member-access.cpp112
-rw-r--r--test/CodeCompletion/uninstantiated_params.cpp13
-rw-r--r--test/CodeGen/2004-02-20-Builtins.c5
-rw-r--r--test/CodeGen/2005-07-20-SqrtNoErrno.c10
-rw-r--r--test/CodeGen/2006-05-19-SingleEltReturn.c11
-rw-r--r--test/CodeGen/2009-10-20-GlobalDebug.c4
-rw-r--r--test/CodeGen/2010-08-10-DbgConstant.c3
-rw-r--r--test/CodeGen/64bit-swiftcall.c27
-rw-r--r--test/CodeGen/Inputs/pgo-sample-thinlto-summary.prof4
-rw-r--r--test/CodeGen/Inputs/sanitizer-special-case-list.sanitized.txt4
-rw-r--r--test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized1.txt2
-rw-r--r--test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized2.txt4
-rw-r--r--test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized3.txt4
-rw-r--r--test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized4.txt4
-rw-r--r--test/CodeGen/Inputs/thinlto-multi-module.ll9
-rw-r--r--test/CodeGen/PR32874.c61
-rw-r--r--test/CodeGen/aarch64-args.cpp67
-rw-r--r--test/CodeGen/aarch64-neon-2velem.c554
-rw-r--r--test/CodeGen/aarch64-neon-3v.c2
-rw-r--r--test/CodeGen/aarch64-neon-across.c2
-rw-r--r--test/CodeGen/aarch64-neon-extract.c2
-rw-r--r--test/CodeGen/aarch64-neon-fcvt-intrinsics.c2
-rw-r--r--test/CodeGen/aarch64-neon-fma.c2
-rw-r--r--test/CodeGen/aarch64-neon-intrinsics.c1136
-rw-r--r--test/CodeGen/aarch64-neon-ldst-one.c2
-rw-r--r--test/CodeGen/aarch64-neon-misc.c332
-rw-r--r--test/CodeGen/aarch64-neon-perm.c2
-rw-r--r--test/CodeGen/aarch64-neon-scalar-copy.c3
-rw-r--r--test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c44
-rw-r--r--test/CodeGen/aarch64-neon-shifts.c2
-rw-r--r--test/CodeGen/aarch64-neon-tbl.c2
-rw-r--r--test/CodeGen/aarch64-neon-vcombine.c2
-rw-r--r--test/CodeGen/aarch64-neon-vget-hilo.c2
-rw-r--r--test/CodeGen/aarch64-neon-vget.c2
-rw-r--r--test/CodeGen/aarch64-poly128.c2
-rw-r--r--test/CodeGen/aarch64-poly64.c2
-rw-r--r--test/CodeGen/aarch64-type-sizes.c2
-rw-r--r--test/CodeGen/aarch64-varargs-ms.c11
-rw-r--r--test/CodeGen/adc-builtins.c4
-rw-r--r--test/CodeGen/address-safety-attr-kasan.cpp6
-rw-r--r--test/CodeGen/address-safety-attr.cpp8
-rw-r--r--test/CodeGen/address-space.c21
-rw-r--r--test/CodeGen/alloc-align-attr.c101
-rw-r--r--test/CodeGen/alloc-size.c2
-rw-r--r--test/CodeGen/altivec-ct.c82
-rw-r--r--test/CodeGen/altivec.c2
-rw-r--r--test/CodeGen/arm-crc32.c2
-rw-r--r--test/CodeGen/arm-execute-only.c78
-rw-r--r--test/CodeGen/arm-float-helpers.c233
-rw-r--r--test/CodeGen/arm-long-calls.c4
-rw-r--r--test/CodeGen/arm-metadata.c2
-rw-r--r--test/CodeGen/arm-neon-directed-rounding.c2
-rw-r--r--test/CodeGen/arm-neon-fma.c2
-rw-r--r--test/CodeGen/arm-neon-numeric-maxmin.c2
-rw-r--r--test/CodeGen/arm-neon-shifts.c1
-rw-r--r--test/CodeGen/arm-neon-vcvtX.c2
-rw-r--r--test/CodeGen/arm-neon-vget.c2
-rw-r--r--test/CodeGen/arm-no-movt.c4
-rw-r--r--test/CodeGen/arm-swiftcall.c8
-rw-r--r--test/CodeGen/arm-target-attr.c19
-rw-r--r--test/CodeGen/arm-target-features.c34
-rw-r--r--test/CodeGen/arm-thumb-mode-target-feature.c33
-rw-r--r--test/CodeGen/arm-v8.1a-neon-intrinsics.c2
-rw-r--r--test/CodeGen/arm64-crc32.c2
-rw-r--r--test/CodeGen/arm64-lanes.c4
-rw-r--r--test/CodeGen/arm64-microsoft-intrinsics.c26
-rw-r--r--test/CodeGen/arm64_vcopy.c2
-rw-r--r--test/CodeGen/arm64_vdupq_n_f64.c2
-rw-r--r--test/CodeGen/arm_acle.c393
-rw-r--r--test/CodeGen/arm_neon_intrinsics.c1087
-rw-r--r--test/CodeGen/asan-globals-gc.cpp18
-rw-r--r--test/CodeGen/asan-no-globals-no-comdat.cpp11
-rw-r--r--test/CodeGen/atomic-ops-libcall.c8
-rw-r--r--test/CodeGen/attr-availability.c6
-rw-r--r--test/CodeGen/attr-coldhot.c6
-rw-r--r--test/CodeGen/attr-naked.c5
-rw-r--r--test/CodeGen/attr-target-x86.c25
-rw-r--r--test/CodeGen/attributes.c10
-rw-r--r--test/CodeGen/avx-builtins.c75
-rw-r--r--test/CodeGen/avx2-builtins.c34
-rw-r--r--test/CodeGen/avx512-reduceMinMaxIntrin.c2852
-rw-r--r--test/CodeGen/avx512bw-builtins.c292
-rw-r--r--test/CodeGen/avx512dq-builtins.c22
-rw-r--r--test/CodeGen/avx512f-builtins.c488
-rw-r--r--test/CodeGen/avx512ifmavl-builtins.c4
-rw-r--r--test/CodeGen/avx512pf-builtins.c32
-rw-r--r--test/CodeGen/avx512vl-builtins.c112
-rw-r--r--test/CodeGen/avx512vlbw-builtins.c303
-rw-r--r--test/CodeGen/avx512vldq-builtins.c39
-rw-r--r--test/CodeGen/avx512vpopcntdqintrin.c38
-rw-r--r--test/CodeGen/bitscan-builtins.c3
-rw-r--r--test/CodeGen/blocks-opencl.cl17
-rw-r--r--test/CodeGen/builtin-clflushopt.c6
-rw-r--r--test/CodeGen/builtin-clwb.c9
-rw-r--r--test/CodeGen/builtin-clzero.c4
-rw-r--r--test/CodeGen/builtin-cpu-is.c53
-rw-r--r--test/CodeGen/builtin-cpu-supports.c4
-rw-r--r--test/CodeGen/builtin-sqrt.c19
-rw-r--r--test/CodeGen/builtins-arm-exclusive.c5
-rw-r--r--test/CodeGen/builtins-arm.c2
-rw-r--r--test/CodeGen/builtins-arm64.c2
-rw-r--r--test/CodeGen/builtins-hexagon.c12
-rw-r--r--test/CodeGen/builtins-mips-msa-error.c4
-rw-r--r--test/CodeGen/builtins-mips-msa.c2
-rw-r--r--test/CodeGen/builtins-nvptx-ptx60.cu97
-rw-r--r--test/CodeGen/builtins-nvptx-sm_70.cu166
-rw-r--r--test/CodeGen/builtins-nvptx.c33
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c6
-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.c55
-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.c115
-rw-r--r--test/CodeGen/builtins-systemz-vector2-error.c61
-rw-r--r--test/CodeGen/builtins-systemz-vector2.c136
-rw-r--r--test/CodeGen/builtins-systemz-zvector-error.c38
-rw-r--r--test/CodeGen/builtins-systemz-zvector.c88
-rw-r--r--test/CodeGen/builtins-systemz-zvector2-error.c153
-rw-r--r--test/CodeGen/builtins-systemz-zvector2.c545
-rw-r--r--test/CodeGen/builtins-wasm.c12
-rw-r--r--test/CodeGen/builtins-x86.c4
-rw-r--r--test/CodeGen/builtins.c523
-rw-r--r--test/CodeGen/captured-statements.c7
-rw-r--r--test/CodeGen/catch-undef-behavior.c13
-rw-r--r--test/CodeGen/cfi-check-fail.c5
-rw-r--r--test/CodeGen/cfi-icall-cross-dso.c10
-rw-r--r--test/CodeGen/cfi-icall-generalize.c19
-rw-r--r--test/CodeGen/cfi-icall.c10
-rw-r--r--test/CodeGen/cfi-unrelated-cast.cpp37
-rw-r--r--test/CodeGen/cleanup-destslot-simple.c8
-rw-r--r--test/CodeGen/coff-aarch64-type-sizes.c88
-rw-r--r--test/CodeGen/complex-math.c12
-rw-r--r--test/CodeGen/darwin-ppc-varargs.c28
-rw-r--r--test/CodeGen/debug-info-attributed-stmt.c12
-rw-r--r--test/CodeGen/debug-info-block-vars.c20
-rw-r--r--test/CodeGen/debug-info-global-constant.c3
-rw-r--r--test/CodeGen/debug-info-imported-entity.cpp3
-rw-r--r--test/CodeGen/debug-info-lto.c4
-rw-r--r--test/CodeGen/debug-info-preprocessed-file.i11
-rw-r--r--test/CodeGen/debug-info-static-const-fp.c11
-rw-r--r--test/CodeGen/debug-info-static.c2
-rw-r--r--test/CodeGen/debug-info-vla.c5
-rw-r--r--test/CodeGen/default-address-space.c61
-rw-r--r--test/CodeGen/dependent-lib.c8
-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-asm.c18
-rw-r--r--test/CodeGen/fp-contract-on-pragma.cpp76
-rw-r--r--test/CodeGen/fp16vec-ops.c162
-rw-r--r--test/CodeGen/function-attributes.c1
-rw-r--r--test/CodeGen/function-sections.c8
-rw-r--r--test/CodeGen/hexagon-inline-asm.c8
-rw-r--r--test/CodeGen/libcall-declarations.c600
-rw-r--r--test/CodeGen/libcalls.c27
-rw-r--r--test/CodeGen/lifetime-asan.c8
-rw-r--r--test/CodeGen/lifetime2.c24
-rw-r--r--test/CodeGen/linker-option.c4
-rw-r--r--test/CodeGen/linux-arm-atomic.c1
-rw-r--r--test/CodeGen/long-call-attr.c21
-rw-r--r--test/CodeGen/lto-newpm-pipeline.c53
-rw-r--r--test/CodeGen/lwp-builtins.c39
-rw-r--r--test/CodeGen/mangle-blocks.c6
-rw-r--r--test/CodeGen/mangle-ms.c9
-rw-r--r--test/CodeGen/mangle.c4
-rw-r--r--test/CodeGen/mcount.c43
-rw-r--r--test/CodeGen/micromips-attr.c12
-rw-r--r--test/CodeGen/mips-debug-info-bitfield.c17
-rw-r--r--test/CodeGen/mips-madd4.c87
-rw-r--r--test/CodeGen/mips-varargs.c67
-rw-r--r--test/CodeGen/mmx-builtins.c87
-rw-r--r--test/CodeGen/mozilla-ms-inline-asm.c38
-rw-r--r--test/CodeGen/ms-annotation.c26
-rw-r--r--test/CodeGen/ms-barriers-intrinsics.c6
-rw-r--r--test/CodeGen/ms-inline-asm-64.c20
-rw-r--r--test/CodeGen/ms-inline-asm-EVEN.c16
-rw-r--r--test/CodeGen/ms-inline-asm-avx512.c15
-rw-r--r--test/CodeGen/ms-inline-asm-enums.cpp55
-rw-r--r--test/CodeGen/ms-inline-asm-variables.c35
-rw-r--r--test/CodeGen/ms-inline-asm.c234
-rw-r--r--test/CodeGen/ms-inline-asm.cpp81
-rw-r--r--test/CodeGen/ms-intrinsics-other.c161
-rw-r--r--test/CodeGen/ms-intrinsics-rotations.c330
-rw-r--r--test/CodeGen/ms-intrinsics.c11
-rw-r--r--test/CodeGen/ms-x86-intrinsics.c65
-rw-r--r--test/CodeGen/ms_abi.c6
-rw-r--r--test/CodeGen/ms_abi_aarch64.c68
-rw-r--r--test/CodeGen/named_reg_global.c2
-rw-r--r--test/CodeGen/neon-aapcs-align.c17
-rw-r--r--test/CodeGen/neon-immediate-ubsan.c2
-rw-r--r--test/CodeGen/no-devirt.cpp59
-rw-r--r--test/CodeGen/nobuiltin.c4
-rw-r--r--test/CodeGen/noduplicate-cxx11-test.cpp2
-rw-r--r--test/CodeGen/nullptr-arithmetic.c47
-rw-r--r--test/CodeGen/object-size.c110
-rw-r--r--test/CodeGen/object-size.cpp14
-rw-r--r--test/CodeGen/pascal-wchar-string.c2
-rw-r--r--test/CodeGen/pause.c11
-rw-r--r--test/CodeGen/pgo-sample-thinlto-summary.c46
-rw-r--r--test/CodeGen/piclevels.c13
-rw-r--r--test/CodeGen/ppc-vector-compare.cc34
-rw-r--r--test/CodeGen/ppc64-align-struct.c2
-rw-r--r--test/CodeGen/ppc64-vector.c2
-rw-r--r--test/CodeGen/ppc64le-aggregates.c2
-rw-r--r--test/CodeGen/pr26099.c12
-rw-r--r--test/CodeGen/pr27892.c23
-rw-r--r--test/CodeGen/pr34021.c25
-rw-r--r--test/CodeGen/pr3997.c13
-rw-r--r--test/CodeGen/pragma-comment.c5
-rw-r--r--test/CodeGen/pragma-detect_mismatch.c4
-rw-r--r--test/CodeGen/pragma-weak.c2
-rw-r--r--test/CodeGen/preserve-call-conv.c3
-rw-r--r--test/CodeGen/profile-sample-accurate.c7
-rw-r--r--test/CodeGen/sanitize-recover.c22
-rw-r--r--test/CodeGen/sanitizer-special-case-list.c26
-rw-r--r--test/CodeGen/sparcv8-inline-asm.c11
-rw-r--r--test/CodeGen/split-debug-filename.c5
-rw-r--r--test/CodeGen/sse2-builtins.c23
-rw-r--r--test/CodeGen/sse41-builtins.c2
-rw-r--r--test/CodeGen/ssse3-builtins.c12
-rw-r--r--test/CodeGen/string-literal-short-wstring.c4
-rw-r--r--test/CodeGen/string-literal-unicode-conversion.c2
-rw-r--r--test/CodeGen/systemz-abi-vector.c4
-rw-r--r--test/CodeGen/systemz-abi.c4
-rw-r--r--test/CodeGen/target-builtin-noerror.c36
-rw-r--r--test/CodeGen/target-data.c10
-rw-r--r--test/CodeGen/tbaa-array.cpp18
-rw-r--r--test/CodeGen/tbaa-cast.cpp23
-rw-r--r--test/CodeGen/tbaa-for-vptr.cpp6
-rw-r--r--test/CodeGen/tbaa-reference.cpp37
-rw-r--r--test/CodeGen/tbaa-vec.cpp20
-rw-r--r--test/CodeGen/tbm-builtins.c96
-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.c14
-rw-r--r--test/CodeGen/thinlto-backend-option.ll15
-rw-r--r--test/CodeGen/thinlto-emit-llvm.c10
-rw-r--r--test/CodeGen/thinlto-multi-module.ll4
-rw-r--r--test/CodeGen/thinlto_backend.ll10
-rw-r--r--test/CodeGen/ubsan-builtin-checks.c44
-rw-r--r--test/CodeGen/ubsan-pointer-overflow.m220
-rw-r--r--test/CodeGen/ubsan-volatile.c7
-rw-r--r--test/CodeGen/union-align.c4
-rw-r--r--test/CodeGen/union-tbaa1.c44
-rw-r--r--test/CodeGen/unsigned-overflow-minimal.c21
-rw-r--r--test/CodeGen/unwind-attr.c2
-rw-r--r--test/CodeGen/vectorcall.c19
-rw-r--r--test/CodeGen/verify-debuginfo.ll17
-rw-r--r--test/CodeGen/wchar-size.c8
-rw-r--r--test/CodeGen/x86-GCC-inline-asm-Y-constraints.c68
-rw-r--r--test/CodeGen/x86-nontemporal.c93
-rw-r--r--test/CodeGen/x86_32-xsave.c60
-rw-r--r--test/CodeGen/x86_64-arguments.c4
-rw-r--r--test/CodeGen/x86_64-mno-sse.c15
-rw-r--r--test/CodeGen/x86_64-xsave.c120
-rw-r--r--test/CodeGen/xop-builtins-cmp.c405
-rw-r--r--test/CodeGen/xray-always-instrument.cpp15
-rw-r--r--test/CodeGen/xray-attributes-supported.cpp2
-rw-r--r--test/CodeGen/xray-customevent.cpp28
-rw-r--r--test/CodeGen/xray-imbue-arg1.cpp12
-rw-r--r--test/CodeGen/xray-instruction-threshold.cpp14
-rw-r--r--test/CodeGen/zvector2.c194
-rw-r--r--test/CodeGenCUDA/flush-denormals.cu4
-rw-r--r--test/CodeGenCUDA/fp-contract.cu4
-rw-r--r--test/CodeGenCXX/amdgcn-automatic-variable.cpp105
-rw-r--r--test/CodeGenCXX/anonymous-namespaces.cpp9
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp32
-rw-r--r--test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp2
-rw-r--r--test/CodeGenCXX/apple-kext-no-staticinit-section.cpp2
-rw-r--r--test/CodeGenCXX/arm64-constructor-return.cpp2
-rw-r--r--test/CodeGenCXX/array-default-argument.cpp36
-rw-r--r--test/CodeGenCXX/atomic-align.cpp30
-rw-r--r--test/CodeGenCXX/atomic-inline.cpp69
-rw-r--r--test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp31
-rw-r--r--test/CodeGenCXX/blocks.cpp1
-rw-r--r--test/CodeGenCXX/captured-statements.cpp17
-rw-r--r--test/CodeGenCXX/catch-undef-behavior.cpp123
-rw-r--r--test/CodeGenCXX/cfi-blacklist.cpp16
-rw-r--r--test/CodeGenCXX/cfi-icall.cpp19
-rw-r--r--test/CodeGenCXX/cfi-vcall-no-trap.cpp15
-rw-r--r--test/CodeGenCXX/clang-abi-compat.cpp19
-rw-r--r--test/CodeGenCXX/clang-sections-tentative.c41
-rw-r--r--test/CodeGenCXX/clang-sections.cpp78
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp151
-rw-r--r--test/CodeGenCXX/cxx11-extern-constexpr.cpp68
-rw-r--r--test/CodeGenCXX/cxx1z-class-deduction.cpp21
-rw-r--r--test/CodeGenCXX/cxx1z-copy-omission.cpp26
-rw-r--r--test/CodeGenCXX/cxx1z-inline-variables.cpp18
-rw-r--r--test/CodeGenCXX/cxx2a-destroying-delete.cpp161
-rw-r--r--test/CodeGenCXX/debug-info-anon-namespace.cpp18
-rw-r--r--test/CodeGenCXX/debug-info-codeview-display-name.cpp7
-rw-r--r--test/CodeGenCXX/debug-info-codeview-nested-types.cpp25
-rw-r--r--test/CodeGenCXX/debug-info-fwd-template-param.cpp20
-rw-r--r--test/CodeGenCXX/debug-info-global-ctor-dtor.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-inheriting-constructor.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-inlined.cpp29
-rw-r--r--test/CodeGenCXX/debug-info-method.cpp3
-rw-r--r--test/CodeGenCXX/debug-info-ms-abi.cpp9
-rw-r--r--test/CodeGenCXX/debug-info-namespace.cpp36
-rw-r--r--test/CodeGenCXX/debug-info-nested-exprs.cpp202
-rw-r--r--test/CodeGenCXX/debug-info-static-member.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-template-member.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-template.cpp6
-rw-r--r--test/CodeGenCXX/debug-info.cpp5
-rw-r--r--test/CodeGenCXX/default_calling_conv.cpp7
-rw-r--r--test/CodeGenCXX/destructors.cpp14
-rw-r--r--test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp50
-rw-r--r--test/CodeGenCXX/dllexport-dtor-thunks.cpp10
-rw-r--r--test/CodeGenCXX/dllexport-vtable-thunks.cpp23
-rw-r--r--test/CodeGenCXX/dllexport.cpp21
-rw-r--r--test/CodeGenCXX/dllimport-dtor-thunks.cpp49
-rw-r--r--test/CodeGenCXX/dllimport-members.cpp4
-rw-r--r--test/CodeGenCXX/dllimport-memptr-global.cpp58
-rw-r--r--test/CodeGenCXX/eh.cpp4
-rw-r--r--test/CodeGenCXX/exceptions-seh.cpp21
-rw-r--r--test/CodeGenCXX/extern-section-attribute.cpp11
-rw-r--r--test/CodeGenCXX/finegrain-bitfield-access.cpp162
-rw-r--r--test/CodeGenCXX/float16-declarations.cpp156
-rw-r--r--test/CodeGenCXX/implicit-exception-spec.cpp2
-rw-r--r--test/CodeGenCXX/inline-dllexport-member.cpp2
-rw-r--r--test/CodeGenCXX/invariant.group-for-vptrs.cpp23
-rw-r--r--test/CodeGenCXX/linetable-virtual-variadic.cpp6
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp32
-rw-r--r--test/CodeGenCXX/mangle-fail.cpp6
-rw-r--r--test/CodeGenCXX/mangle-lambdas.cpp28
-rw-r--r--test/CodeGenCXX/mangle-ms-cxx11.cpp7
-rw-r--r--test/CodeGenCXX/mangle-ms.cpp7
-rw-r--r--test/CodeGenCXX/mangle.cpp3
-rw-r--r--test/CodeGenCXX/member-expr-references-variable.cpp104
-rw-r--r--test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp4
-rw-r--r--test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp6
-rw-r--r--test/CodeGenCXX/microsoft-abi-static-initializers.cpp2
-rw-r--r--test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp9
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp15
-rw-r--r--test/CodeGenCXX/microsoft-inaccessible-base.cpp20
-rw-r--r--test/CodeGenCXX/ms-inline-asm-fields.cpp4
-rw-r--r--test/CodeGenCXX/ms-inline-asm-return.cpp4
-rw-r--r--test/CodeGenCXX/ms-thread_local.cpp4
-rw-r--r--test/CodeGenCXX/msabi-blocks.cpp113
-rw-r--r--test/CodeGenCXX/noescape.cpp67
-rw-r--r--test/CodeGenCXX/nrvo.cpp4
-rw-r--r--test/CodeGenCXX/optnone-templates.cpp2
-rw-r--r--test/CodeGenCXX/pr29160.cpp41
-rw-r--r--test/CodeGenCXX/pr33080.cpp33
-rw-r--r--test/CodeGenCXX/pr34163.cpp13
-rw-r--r--test/CodeGenCXX/regcall.cpp12
-rw-r--r--test/CodeGenCXX/rtti-mingw64.cpp5
-rw-r--r--test/CodeGenCXX/sanitize-dtor-callback.cpp3
-rw-r--r--test/CodeGenCXX/static-init-wasm.cpp12
-rw-r--r--test/CodeGenCXX/static-initializer-branch-weights.cpp126
-rw-r--r--test/CodeGenCXX/std-byte.cpp41
-rw-r--r--test/CodeGenCXX/stmtexpr.cpp32
-rw-r--r--test/CodeGenCXX/strict-vtable-pointers.cpp117
-rw-r--r--test/CodeGenCXX/thunks.cpp2
-rw-r--r--test/CodeGenCXX/tmp-md-nodes1.cpp18
-rw-r--r--test/CodeGenCXX/tmp-md-nodes2.cpp33
-rw-r--r--test/CodeGenCXX/ubsan-devirtualized-calls.cpp9
-rw-r--r--test/CodeGenCXX/ubsan-global-alignment.cpp29
-rw-r--r--test/CodeGenCXX/ubsan-nullability-assign.cpp35
-rw-r--r--test/CodeGenCXX/ubsan-suppress-checks.cpp244
-rw-r--r--test/CodeGenCXX/ubsan-suppress-null-checks.cpp188
-rw-r--r--test/CodeGenCXX/ubsan-type-checks.cpp69
-rw-r--r--test/CodeGenCXX/ubsan-vtable-checks.cpp4
-rw-r--r--test/CodeGenCXX/unaligned-member-qualifier.cpp20
-rw-r--r--test/CodeGenCXX/uncopyable-args.cpp158
-rw-r--r--test/CodeGenCXX/union-tbaa2.cpp45
-rw-r--r--test/CodeGenCXX/virt-dtor-key.cpp4
-rw-r--r--test/CodeGenCXX/visibility-inlines-hidden.cpp13
-rw-r--r--test/CodeGenCXX/vla.cpp84
-rw-r--r--test/CodeGenCXX/vtable-available-externally.cpp33
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp6
-rw-r--r--test/CodeGenCXX/warn-padded-packed.cpp93
-rw-r--r--test/CodeGenCXX/windows-itanium-dllexport.cpp25
-rw-r--r--test/CodeGenCXX/windows-itanium-type-info.cpp10
-rw-r--r--test/CodeGenCoroutines/Inputs/coroutine.h80
-rw-r--r--test/CodeGenCoroutines/coro-alloc.cpp88
-rw-r--r--test/CodeGenCoroutines/coro-await-domination.cpp38
-rw-r--r--test/CodeGenCoroutines/coro-await.cpp346
-rw-r--r--test/CodeGenCoroutines/coro-builtins.c22
-rw-r--r--test/CodeGenCoroutines/coro-cleanup.cpp97
-rw-r--r--test/CodeGenCoroutines/coro-eh-cleanup.cpp86
-rw-r--r--test/CodeGenCoroutines/coro-gro.cpp86
-rw-r--r--test/CodeGenCoroutines/coro-lambda.cpp58
-rw-r--r--test/CodeGenCoroutines/coro-params.cpp129
-rw-r--r--test/CodeGenCoroutines/coro-promise-dtor.cpp47
-rw-r--r--test/CodeGenCoroutines/coro-ret-void.cpp53
-rw-r--r--test/CodeGenCoroutines/coro-return.cpp20
-rw-r--r--test/CodeGenCoroutines/coro-unhandled-exception.cpp72
-rw-r--r--test/CodeGenObjC/NSFastEnumeration.m16
-rw-r--r--test/CodeGenObjC/arc-arm.m2
-rw-r--r--test/CodeGenObjC/arc-blocks.m68
-rw-r--r--test/CodeGenObjC/arc-bridged-cast.m8
-rw-r--r--test/CodeGenObjC/arc-foreach.m31
-rw-r--r--test/CodeGenObjC/arc-precise-lifetime.m68
-rw-r--r--test/CodeGenObjC/arc-property.m20
-rw-r--r--test/CodeGenObjC/arc-ternary-op.m12
-rw-r--r--test/CodeGenObjC/arc.m94
-rw-r--r--test/CodeGenObjC/attr-callconv.m2
-rw-r--r--test/CodeGenObjC/availability-cf-link-guard.m44
-rw-r--r--test/CodeGenObjC/debug-info-block-captured-self.m72
-rw-r--r--test/CodeGenObjC/debug-info-blocks.m21
-rw-r--r--test/CodeGenObjC/dllstorage.m10
-rw-r--r--test/CodeGenObjC/empty-collection-literals.m51
-rw-r--r--test/CodeGenObjC/exceptions-asm-attribute.m10
-rw-r--r--test/CodeGenObjC/exceptions.m4
-rw-r--r--test/CodeGenObjC/gnu-exceptions.m2
-rw-r--r--test/CodeGenObjC/image-info.m4
-rw-r--r--test/CodeGenObjC/ivar-layout-flexible-array.m28
-rw-r--r--test/CodeGenObjC/ivar-type-encoding.m16
-rw-r--r--test/CodeGenObjC/local-static-block.m11
-rw-r--r--test/CodeGenObjC/mangle-blocks.m6
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m16
-rw-r--r--test/CodeGenObjC/metadata_symbols.m10
-rw-r--r--test/CodeGenObjC/noescape.m71
-rw-r--r--test/CodeGenObjC/non-lazy-classes.m6
-rw-r--r--test/CodeGenObjC/objc_copyStruct.m16
-rw-r--r--test/CodeGenObjC/os_log.m78
-rw-r--r--test/CodeGenObjC/parameterized_classes.m56
-rw-r--r--test/CodeGenObjC/protocol-comdat.m8
-rw-r--r--test/CodeGenObjC/sections.m72
-rw-r--r--test/CodeGenObjC/stret-1.m11
-rw-r--r--test/CodeGenObjC/stret-lifetime.m34
-rw-r--r--test/CodeGenObjC/ubsan-nonnull-and-nullability.m34
-rw-r--r--test/CodeGenObjC/ubsan-nullability.m90
-rw-r--r--test/CodeGenObjCXX/arc-indirect.mm22
-rw-r--r--test/CodeGenObjCXX/arc-mangle.mm10
-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/boxing.mm12
-rw-r--r--test/CodeGenObjCXX/lambda-to-block.mm18
-rw-r--r--test/CodeGenObjCXX/literals.mm8
-rw-r--r--test/CodeGenObjCXX/mangle-blocks.mm10
-rw-r--r--test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm2
-rw-r--r--test/CodeGenObjCXX/msabi-objc-types.mm122
-rw-r--r--test/CodeGenObjCXX/objc-weak.mm69
-rw-r--r--test/CodeGenObjCXX/objfw-exceptions.mm17
-rw-r--r--test/CodeGenOpenCL/addr-space-struct-arg.cl116
-rw-r--r--test/CodeGenOpenCL/address-space-constant-initializers.cl2
-rw-r--r--test/CodeGenOpenCL/address-spaces-mangling.cl22
-rw-r--r--test/CodeGenOpenCL/address-spaces.cl99
-rw-r--r--test/CodeGenOpenCL/amdgcn-automatic-variable.cl68
-rw-r--r--test/CodeGenOpenCL/amdgcn-large-globals.cl12
-rw-r--r--test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl490
-rw-r--r--test/CodeGenOpenCL/amdgpu-alignment.cl1
-rw-r--r--test/CodeGenOpenCL/amdgpu-attrs.cl58
-rw-r--r--test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl21
-rw-r--r--test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl101
-rw-r--r--test/CodeGenOpenCL/amdgpu-enqueue-kernel.cl45
-rw-r--r--test/CodeGenOpenCL/amdgpu-env-amdgiz.cl9
-rw-r--r--test/CodeGenOpenCL/amdgpu-nullptr.cl53
-rw-r--r--test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl70
-rw-r--r--test/CodeGenOpenCL/atomic-ops-libcall.cl82
-rw-r--r--test/CodeGenOpenCL/atomic-ops.cl291
-rw-r--r--test/CodeGenOpenCL/blocks.cl49
-rw-r--r--test/CodeGenOpenCL/bool_cast.cl4
-rw-r--r--test/CodeGenOpenCL/builtins-amdgcn.cl29
-rw-r--r--test/CodeGenOpenCL/byval.cl19
-rw-r--r--test/CodeGenOpenCL/cl20-device-side-enqueue.cl258
-rw-r--r--test/CodeGenOpenCL/constant-addr-space-globals.cl8
-rw-r--r--test/CodeGenOpenCL/convergent.cl72
-rw-r--r--test/CodeGenOpenCL/func-call-dbg-loc.cl18
-rw-r--r--test/CodeGenOpenCL/gfx9-fp32-denorms.cl13
-rw-r--r--test/CodeGenOpenCL/half.cl17
-rw-r--r--test/CodeGenOpenCL/kernel-arg-info.cl58
-rw-r--r--test/CodeGenOpenCL/kernel-attributes.cl8
-rw-r--r--test/CodeGenOpenCL/kernel-metadata.cl2
-rw-r--r--test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl65
-rw-r--r--test/CodeGenOpenCL/lifetime.cl15
-rw-r--r--test/CodeGenOpenCL/no-half.cl39
-rw-r--r--test/CodeGenOpenCL/opencl_types.cl29
-rw-r--r--test/CodeGenOpenCL/overload.cl46
-rw-r--r--test/CodeGenOpenCL/pipe_builtin.cl4
-rw-r--r--test/CodeGenOpenCL/pipe_types.cl2
-rw-r--r--test/CodeGenOpenCL/preserve_vec3.cl24
-rw-r--r--test/CodeGenOpenCL/ptx-calls.cl2
-rw-r--r--test/CodeGenOpenCL/ptx-kernels.cl2
-rw-r--r--test/CodeGenOpenCL/relaxed-fpmath.cl29
-rw-r--r--test/CodeGenOpenCL/sampler.cl4
-rw-r--r--test/CodeGenOpenCL/size_t.cl3
-rw-r--r--test/CodeGenOpenCL/spir_version.cl17
-rw-r--r--test/CodeGenOpenCL/vectorLoadStore.cl17
-rw-r--r--test/CodeGenOpenCL/vla.cl12
-rw-r--r--test/Coverage/ast-printing.c1
-rw-r--r--test/Coverage/ast-printing.cpp1
-rw-r--r--test/Coverage/html-diagnostics.c7
-rw-r--r--test/Coverage/html-multifile-diagnostics.c21
-rw-r--r--test/Coverage/html-multifile-diagnostics.h3
-rw-r--r--test/CoverageMapping/abspath.cpp2
-rw-r--r--test/CoverageMapping/deferred-region.cpp193
-rw-r--r--test/CoverageMapping/empty-destructor.cpp11
-rw-r--r--test/CoverageMapping/header.cpp5
-rw-r--r--test/CoverageMapping/label.cpp25
-rw-r--r--test/CoverageMapping/logical.cpp15
-rw-r--r--test/CoverageMapping/macro-expansion.c6
-rw-r--r--test/CoverageMapping/md.cpp11
-rw-r--r--test/CoverageMapping/moremacros.c6
-rw-r--r--test/CoverageMapping/pr32679.cpp32
-rw-r--r--test/CoverageMapping/preprocessor.c53
-rw-r--r--test/CoverageMapping/return.c2
-rw-r--r--test/CoverageMapping/switch.cpp41
-rw-r--r--test/CoverageMapping/switchmacro.c1
-rw-r--r--test/CoverageMapping/trycatch.cpp2
-rw-r--r--test/CoverageMapping/unused_names.c2
-rw-r--r--test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/bin/.keep0
-rw-r--r--test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/include/.keep0
-rw-r--r--test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib/.keep0
-rw-r--r--test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib64/.keep0
-rw-r--r--test/Driver/Inputs/CUDA_90/usr/local/cuda/bin/.keep0
-rw-r--r--test/Driver/Inputs/CUDA_90/usr/local/cuda/include/.keep0
-rw-r--r--test/Driver/Inputs/CUDA_90/usr/local/cuda/lib/.keep0
-rw-r--r--test/Driver/Inputs/CUDA_90/usr/local/cuda/lib64/.keep0
-rw-r--r--test/Driver/Inputs/CUDA_90/usr/local/cuda/nvvm/libdevice/libdevice.10.bc0
-rw-r--r--test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt1
-rw-r--r--test/Driver/Inputs/baremetal_arm/include/c++/5.0.0/.keep0
-rw-r--r--test/Driver/Inputs/baremetal_arm/include/c++/6.0.0/.keep0
-rw-r--r--test/Driver/Inputs/baremetal_arm/include/c++/v1/.keep0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/i686-unknown-linux/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i686-unknown-linux/4.6.0/crtbegin.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtbegin.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtend.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crt1.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crti.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crtn.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtbegin.o0
-rw-r--r--test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtend.o0
-rw-r--r--test/Driver/Inputs/resource_dir/ubsan_blacklist.txt0
-rw-r--r--test/Driver/XRay/lit.local.cfg22
-rw-r--r--test/Driver/XRay/xray-shared-noxray.cpp16
-rw-r--r--test/Driver/aarch64-cpus.c257
-rw-r--r--test/Driver/aarch64-dotprod.c11
-rw-r--r--test/Driver/aarch64-ras.c2
-rw-r--r--test/Driver/aarch64-rcpc.s14
-rw-r--r--test/Driver/aarch64-rdm.c9
-rw-r--r--test/Driver/amdgpu-features.c4
-rw-r--r--test/Driver/amdgpu-mcpu.cl (renamed from test/Driver/r600-mcpu.cl)72
-rw-r--r--test/Driver/amdgpu-toolchain-opencl.cl19
-rw-r--r--test/Driver/ananas.c9
-rw-r--r--test/Driver/android-ndk-standalone.cpp14
-rw-r--r--test/Driver/android-pie.c66
-rw-r--r--test/Driver/arch-specific-libdir-rpath.c81
-rw-r--r--test/Driver/arch-specific-libdir.c12
-rw-r--r--test/Driver/arm-cortex-cpus.c45
-rw-r--r--test/Driver/arm-darwin-builtin.c14
-rw-r--r--test/Driver/arm-default-build-attributes.s20
-rw-r--r--test/Driver/arm-dotprod.c11
-rw-r--r--test/Driver/arm-execute-only.c72
-rw-r--r--test/Driver/arm-no-neg-immediates.c8
-rw-r--r--test/Driver/arm-ras.c2
-rw-r--r--test/Driver/arm-thumb-only-cores.c12
-rw-r--r--test/Driver/arm-wchar_t-defaults.c53
-rw-r--r--test/Driver/autocomplete.c112
-rw-r--r--test/Driver/avr-mmcu.c5
-rw-r--r--test/Driver/baremetal.cpp85
-rw-r--r--test/Driver/bitrig.c29
-rw-r--r--test/Driver/cl-cc-flags.c33
-rw-r--r--test/Driver/cl-diagnostics.c28
-rw-r--r--test/Driver/cl-include.c14
-rw-r--r--test/Driver/cl-link-at-file.c1
-rw-r--r--test/Driver/cl-link.c2
-rw-r--r--test/Driver/cl-options.c19
-rw-r--r--test/Driver/cl-outputs.c4
-rw-r--r--test/Driver/cl-zc.cpp5
-rw-r--r--test/Driver/clang-translation.c40
-rw-r--r--test/Driver/clang_f_opts.c48
-rw-r--r--test/Driver/compilation_database.c2
-rw-r--r--test/Driver/compress-noias.c37
-rw-r--r--test/Driver/compress.c38
-rw-r--r--test/Driver/constructors.c14
-rw-r--r--test/Driver/cpath.c8
-rw-r--r--test/Driver/crash-report-crashfile.m33
-rw-r--r--test/Driver/crash-report-spaces.c (renamed from test/Driver/crash report spaces.c)3
-rw-r--r--test/Driver/cuda-arch-translation.cu36
-rw-r--r--test/Driver/cuda-bad-arch.cu6
-rw-r--r--test/Driver/cuda-detect.cu16
-rw-r--r--test/Driver/cuda-external-tools.cu10
-rw-r--r--test/Driver/cxa-atexit.cpp27
-rw-r--r--test/Driver/darwin-iphone-defaults.m2
-rw-r--r--test/Driver/darwin-ld-lto.c8
-rw-r--r--test/Driver/darwin-ld.c24
-rw-r--r--test/Driver/darwin-sdk-vs-os-version.c10
-rw-r--r--test/Driver/darwin-simulator-macro.c12
-rw-r--r--test/Driver/darwin-version.c57
-rw-r--r--test/Driver/debug-options.c33
-rw-r--r--test/Driver/emulated-tls.cpp4
-rw-r--r--test/Driver/fast-math.c23
-rw-r--r--test/Driver/flags.c3
-rw-r--r--test/Driver/fopenmp.c16
-rw-r--r--test/Driver/freebsd.c2
-rw-r--r--test/Driver/fsanitize-blacklist.c6
-rw-r--r--test/Driver/fsanitize-coverage.c88
-rw-r--r--test/Driver/fsanitize-object-size.c31
-rw-r--r--test/Driver/fsanitize.c174
-rw-r--r--test/Driver/fuchsia.c43
-rw-r--r--test/Driver/fuchsia.cpp13
-rw-r--r--test/Driver/fuzzer.c34
-rw-r--r--test/Driver/gfortran.f902
-rw-r--r--test/Driver/gold-lto-new-pass-man.c7
-rw-r--r--test/Driver/gold-lto.c10
-rw-r--r--test/Driver/hexagon-hvx.c90
-rw-r--r--test/Driver/hexagon-toolchain-elf.c24
-rw-r--r--test/Driver/immediate-options.c5
-rw-r--r--test/Driver/include-default-header.cl6
-rw-r--r--test/Driver/linker-opts.c6
-rw-r--r--test/Driver/linux-as.c42
-rw-r--r--test/Driver/linux-ld.c87
-rw-r--r--test/Driver/lto-plugin-darwin.c6
-rw-r--r--test/Driver/lto-plugin-linux.c6
-rw-r--r--test/Driver/lto-plugin-windows.c6
-rw-r--r--test/Driver/lto-unit.c2
-rw-r--r--test/Driver/lto.c6
-rw-r--r--test/Driver/m_and_mm.c12
-rw-r--r--test/Driver/mingw-msvcrt.c5
-rw-r--r--test/Driver/mips-abi.c2
-rw-r--r--test/Driver/mips-abicalls-warning.c9
-rw-r--r--test/Driver/mips-features.c155
-rw-r--r--test/Driver/mips-gpopt-warning.c6
-rw-r--r--test/Driver/mips-mabs-warning.c6
-rw-r--r--test/Driver/modules-ts.cpp14
-rw-r--r--test/Driver/myriad-toolchain.c4
-rw-r--r--test/Driver/nacl-direct.c2
-rw-r--r--test/Driver/nios2-cpu.c26
-rw-r--r--test/Driver/nostdlib.c2
-rw-r--r--test/Driver/nostdlibxx.cpp8
-rw-r--r--test/Driver/nozlibcompress.c9
-rw-r--r--test/Driver/openbsd.c5
-rw-r--r--test/Driver/openmp-offload-gpu.c112
-rw-r--r--test/Driver/openmp-offload.c128
-rw-r--r--test/Driver/opt-record.c4
-rw-r--r--test/Driver/output-file-cleanup.c50
-rw-r--r--test/Driver/parse-progname.c80
-rw-r--r--test/Driver/pic.c50
-rw-r--r--test/Driver/ppc-features.cpp57
-rw-r--r--test/Driver/print-libgcc-file-name-clangrt.c30
-rw-r--r--test/Driver/ps4-linker-non-win.c18
-rw-r--r--test/Driver/ps4-linker-win.c15
-rw-r--r--test/Driver/reloc-model.c4
-rw-r--r--test/Driver/response-file.c9
-rw-r--r--test/Driver/rewrite-legacy-objc.m6
-rw-r--r--test/Driver/rewrite-objc.m2
-rw-r--r--test/Driver/sanitizer-ld.c163
-rw-r--r--test/Driver/split-debug.c23
-rw-r--r--test/Driver/split-debug.h9
-rw-r--r--test/Driver/stack-protector.c17
-rw-r--r--test/Driver/std.cpp10
-rw-r--r--test/Driver/systemz-march.c4
-rw-r--r--test/Driver/target-override.c16
-rw-r--r--test/Driver/thinlto.c6
-rw-r--r--test/Driver/unavailable_aligned_allocation.cpp54
-rw-r--r--test/Driver/unknown-arg.c4
-rw-r--r--test/Driver/unknown-std.c28
-rw-r--r--test/Driver/unknown-std.cl2
-rw-r--r--test/Driver/unknown-std.cpp22
-rw-r--r--test/Driver/unsupported-faltivec.c10
-rw-r--r--test/Driver/warning-options.cpp2
-rw-r--r--test/Driver/wasm-toolchain.c14
-rw-r--r--test/Driver/whole-program-vtables.c9
-rw-r--r--test/Driver/windows-cross.c26
-rw-r--r--test/Driver/x86-march.c4
-rw-r--r--test/FixIt/Inputs/nullability-objc.h48
-rw-r--r--test/FixIt/fixit-add-synthesize-to-property.m14
-rw-r--r--test/FixIt/fixit-availability.c18
-rw-r--r--test/FixIt/fixit-availability.mm150
-rw-r--r--test/FixIt/fixit-cxx0x.cpp1
-rw-r--r--test/FixIt/fixit-format-darwin.m86
-rw-r--r--test/FixIt/fixit-format-ios.m26
-rw-r--r--test/FixIt/fixit-include.c11
-rw-r--r--test/FixIt/fixit-pragma-attribute.c6
-rw-r--r--test/FixIt/fixit-pragma-attribute.cpp83
-rw-r--r--test/FixIt/fixit-pragma-pack.c5
-rw-r--r--test/FixIt/fixit-vexing-parse.cpp21
-rw-r--r--test/FixIt/fixit.c3
-rw-r--r--test/FixIt/fixit.cpp2
-rw-r--r--test/FixIt/format-darwin.m23
-rw-r--r--test/FixIt/format.m44
-rw-r--r--test/FixIt/nullability.mm2
-rw-r--r--test/Format/incomplete.cpp2
-rw-r--r--test/Format/style-on-command-line.cpp19
-rw-r--r--test/Format/verbose.cpp16
-rw-r--r--test/Frontend/Inputs/SystemHeaderPrefix/line-directive-in-system.h2
-rw-r--r--test/Frontend/Inputs/SystemHeaderPrefix/noline.h1
-rw-r--r--test/Frontend/Inputs/empty.h0
-rw-r--r--test/Frontend/Inputs/line-directive.h2
-rw-r--r--test/Frontend/Inputs/optimization-remark-with-hotness-sample.proftext7
-rw-r--r--test/Frontend/clang-abi-compat.cpp15
-rw-r--r--test/Frontend/float16.cpp326
-rw-r--r--test/Frontend/gnu-inline.c4
-rw-r--r--test/Frontend/gnu-mcount.c21
-rw-r--r--test/Frontend/optimization-remark-extra-analysis.c11
-rw-r--r--test/Frontend/optimization-remark-options.c2
-rw-r--r--test/Frontend/optimization-remark-with-hotness.c33
-rw-r--r--test/Frontend/optimization-remark.c3
-rw-r--r--test/Frontend/pp-only-no-editor-placeholders.c4
-rw-r--r--test/Frontend/remove-file-on-signal.c7
-rw-r--r--test/Frontend/rewrite-includes-filenotfound.c6
-rw-r--r--test/Frontend/rewrite-includes-line-markers.c8
-rw-r--r--test/Frontend/rewrite-includes-modules.c27
-rw-r--r--test/Frontend/system-header-line-directive-ms-lineendings.c21
-rw-r--r--test/Frontend/system-header-line-directive.c23
-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/float16.c65
-rw-r--r--test/Headers/htm-header.c19
-rw-r--r--test/Headers/ms-cppoperkey.cpp16
-rw-r--r--test/Headers/ms-cppoperkey1.cpp27
-rw-r--r--test/Headers/ms-cppoperkey2.cpp11
-rw-r--r--test/Headers/ms-intrin.cpp4
-rw-r--r--test/Headers/stdarg.cpp36
-rw-r--r--test/Headers/stdatomic.c1
-rw-r--r--test/Headers/stdint-typeof-MINMAX.cpp32
-rw-r--r--test/Headers/tgmath-darwin.c12
-rw-r--r--test/Headers/wchar_limits.cpp2
-rw-r--r--test/Import/conflicting-struct/Inputs/S1.cpp6
-rw-r--r--test/Import/conflicting-struct/Inputs/S2.cpp7
-rw-r--r--test/Import/conflicting-struct/test.cpp7
-rw-r--r--test/Import/direct/Inputs/S.c3
-rw-r--r--test/Import/direct/test.c5
-rw-r--r--test/Import/enum/Inputs/S.cpp4
-rw-r--r--test/Import/enum/test.cpp4
-rw-r--r--test/Import/extern-c-function/Inputs/F.cpp3
-rw-r--r--test/Import/extern-c-function/test.cpp4
-rw-r--r--test/Import/forward-declared-objc-class/Inputs/S1.m1
-rw-r--r--test/Import/forward-declared-objc-class/Inputs/S2.m6
-rw-r--r--test/Import/forward-declared-objc-class/Inputs/S3.m1
-rw-r--r--test/Import/forward-declared-objc-class/test.m6
-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/Inputs/S3.c1
-rw-r--r--test/Import/forward-declared-struct/test.c5
-rw-r--r--test/Import/import-overrides/Inputs/Hierarchy.cpp9
-rw-r--r--test/Import/import-overrides/test.cpp7
-rw-r--r--test/Import/in-class-initializer/Inputs/S.cpp3
-rw-r--r--test/Import/in-class-initializer/test.cpp5
-rw-r--r--test/Import/indirect-struct-member-access/Inputs/S.c3
-rw-r--r--test/Import/indirect-struct-member-access/test.c4
-rw-r--r--test/Import/local-struct-use-origins/Inputs/Callee.cpp12
-rw-r--r--test/Import/local-struct-use-origins/test.cpp7
-rw-r--r--test/Import/local-struct/Inputs/Callee.cpp12
-rw-r--r--test/Import/local-struct/test.cpp7
-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/objc-definitions-in-expression/Inputs/S.m4
-rw-r--r--test/Import/objc-definitions-in-expression/test.m21
-rw-r--r--test/Import/objc-method/Inputs/S.m4
-rw-r--r--test/Import/objc-method/test.m5
-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-and-var/Inputs/S1.cpp1
-rw-r--r--test/Import/struct-and-var/Inputs/S2.cpp3
-rw-r--r--test/Import/struct-and-var/test.cpp5
-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/struct-layout/Inputs/Callee.cpp9
-rw-r--r--test/Import/struct-layout/test.cpp6
-rw-r--r--test/Import/template-specialization/Inputs/T.cpp14
-rw-r--r--test/Import/template-specialization/test.cpp7
-rw-r--r--test/Import/template/Inputs/T.cpp5
-rw-r--r--test/Import/template/test.cpp4
-rw-r--r--test/Index/Core/Inputs/sys/system-head.h36
-rw-r--r--test/Index/Core/external-source-symbol-attr.m104
-rw-r--r--test/Index/Core/index-dependent-source.cpp226
-rw-r--r--test/Index/Core/index-instantiated-source.cpp88
-rw-r--r--test/Index/Core/index-source-invalid-name.cpp13
-rw-r--r--test/Index/Core/index-source.cpp461
-rw-r--r--test/Index/Core/index-source.m218
-rw-r--r--test/Index/Core/index-system.mm3
-rw-r--r--test/Index/Core/no-templated-canonical-decl.cpp4
-rw-r--r--test/Index/Inputs/empty.dia0
-rw-r--r--test/Index/KeepGoingWithLotsOfErrors.mm29
-rw-r--r--test/Index/USR/array-type.cpp11
-rw-r--r--test/Index/USR/func-type.cpp18
-rw-r--r--test/Index/allow-editor-placeholders.cpp5
-rw-r--r--test/Index/annotate-attribute.cpp12
-rw-r--r--test/Index/availability.c18
-rw-r--r--test/Index/code-completion.cpp16
-rw-r--r--test/Index/comment-cplus-decls.cpp8
-rw-r--r--test/Index/comment-to-html-xml-conversion-with-original-literals.cpp26
-rw-r--r--test/Index/complete-access-checks.cpp24
-rw-r--r--test/Index/complete-available.m20
-rw-r--r--test/Index/complete-call.cpp61
-rw-r--r--test/Index/complete-constructor-params.cpp17
-rw-r--r--test/Index/complete-cxx-inline-methods.cpp4
-rw-r--r--test/Index/complete-method-decls.m22
-rw-r--r--test/Index/complete-optional-params.cpp36
-rw-r--r--test/Index/complete-qualified.cpp2
-rw-r--r--test/Index/complete-super.cpp5
-rw-r--r--test/Index/complete-with-annotations.cpp4
-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/ctor-init-source-loc.cpp117
-rw-r--r--test/Index/cursor-dynamic-call.mm12
-rw-r--r--test/Index/get-cursor.cpp17
-rw-r--r--test/Index/get-cursor.m44
-rw-r--r--test/Index/index-attrs.c10
-rw-r--r--test/Index/index-attrs.cpp14
-rw-r--r--test/Index/index-module.m3
-rw-r--r--test/Index/index-pch.cpp2
-rw-r--r--test/Index/index-refs.cpp1
-rw-r--r--test/Index/index-template-template-param.cpp7
-rw-r--r--test/Index/index-templates.cpp2
-rw-r--r--test/Index/keep-going.cpp4
-rw-r--r--test/Index/linkage.c2
-rw-r--r--test/Index/opencl-types.cl104
-rw-r--r--test/Index/overriding-method-comments.mm2
-rw-r--r--test/Index/pipe-size.cl16
-rw-r--r--test/Index/preamble-conditionals-crash.cpp12
-rw-r--r--test/Index/preamble-conditionals-inverted-with-error.cpp8
-rw-r--r--test/Index/preamble-conditionals-inverted.cpp8
-rw-r--r--test/Index/preamble-conditionals.cpp8
-rw-r--r--test/Index/print-objc-manglings.m18
-rw-r--r--test/Index/print-type-declaration.cpp7
-rw-r--r--test/Index/print-type.cpp5
-rw-r--r--test/Index/read-empty-diags.test2
-rw-r--r--test/Index/recover-bad-code-rdar_7487294.c2
-rw-r--r--test/Index/single-file-parse.m121
-rw-r--r--test/Index/skipped-ranges.c6
-rw-r--r--test/Index/target-info.c6
-rw-r--r--test/Index/usrs.cpp11
-rw-r--r--test/Index/usrs.m2
-rw-r--r--test/Integration/carbon.c1
-rw-r--r--test/Integration/cocoa-pch.m1
-rw-r--r--test/Integration/cocoa.m1
-rw-r--r--test/Integration/thinlto_profile_sample_accurate.c9
-rw-r--r--test/Lexer/asm-preproc-no-unicode.s8
-rw-r--r--test/Lexer/case-insensitive-include-ms.c10
-rw-r--r--test/Lexer/case-insensitive-include-pr31836.sh6
-rw-r--r--test/Lexer/case-insensitive-include.c14
-rw-r--r--test/Lexer/case-insensitive-system-include.c10
-rw-r--r--test/Lexer/cxx-features.cpp32
-rw-r--r--test/Lexer/cxx1z-trigraphs.cpp7
-rw-r--r--test/Lexer/cxx2a_keyword_as_cxx17.cpp9
-rw-r--r--test/Lexer/half-literal.cpp3
-rw-r--r--test/Lexer/hexfloat.cpp10
-rw-r--r--test/Lexer/keywords_test.cpp3
-rw-r--r--test/Lexer/newline-nul.cbin0 -> 332 bytes
-rw-r--r--test/Lexer/preamble.c11
-rw-r--r--test/Lexer/preamble2.c19
-rw-r--r--test/Lexer/wchar.c2
-rw-r--r--test/Misc/Inputs/module.modulemap1
-rw-r--r--test/Misc/ast-dump-attr.cpp30
-rw-r--r--test/Misc/ast-dump-c-attr.c46
-rw-r--r--test/Misc/ast-dump-decl.c24
-rw-r--r--test/Misc/ast-dump-decl.cpp61
-rw-r--r--test/Misc/ast-dump-invalid.cpp2
-rw-r--r--test/Misc/ast-print-objectivec.m15
-rw-r--r--test/Misc/ast-print-out-of-line-func.cpp95
-rw-r--r--test/Misc/backend-stack-frame-diagnostics.cpp2
-rw-r--r--test/Misc/caret-diags-multiline.cpp239
-rw-r--r--test/Misc/cc1as-compress.s8
-rw-r--r--test/Misc/diag-mapping2.c1
-rw-r--r--test/Misc/find-diagnostic-id.c7
-rw-r--r--test/Misc/pr32207.c4
-rw-r--r--test/Misc/pragma-attribute-cxx-subject-match-rules.cpp169
-rw-r--r--test/Misc/pragma-attribute-cxx.cpp106
-rw-r--r--test/Misc/pragma-attribute-objc-subject-match-rules.m113
-rw-r--r--test/Misc/pragma-attribute-objc.m164
-rw-r--r--test/Misc/pragma-attribute-strict-subjects.c222
-rw-r--r--test/Misc/pragma-attribute-supported-attributes-list.test71
-rw-r--r--test/Misc/warning-flags-tree.c11
-rw-r--r--test/Misc/warning-flags.c7
-rw-r--r--test/Modules/DebugInfoNamespace.cpp19
-rw-r--r--test/Modules/DebugInfoSubmoduleImport.c5
-rw-r--r--test/Modules/DebugInfoTransitiveImport.m4
-rw-r--r--test/Modules/ExtDebugInfo.cpp17
-rw-r--r--test/Modules/Inputs/DebugCXX.h6
-rw-r--r--test/Modules/Inputs/DebugInfoNamespace/A.h3
-rw-r--r--test/Modules/Inputs/DebugInfoNamespace/B.h3
-rw-r--r--test/Modules/Inputs/DebugInfoNamespace/module.modulemap8
-rw-r--r--test/Modules/Inputs/DebugObjCImport.h2
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/coroutines.h3
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/Headers/not_coroutines.h3
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/module.map9
-rw-r--r--test/Modules/Inputs/F.framework/Headers/F.h1
-rw-r--r--test/Modules/Inputs/F.framework/Modules/module.modulemap7
-rw-r--r--test/Modules/Inputs/F.framework/Modules/module.private.modulemap7
-rw-r--r--test/Modules/Inputs/F.framework/PrivateHeaders/NS.h19
-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/MainA.framework/Frameworks/Sub.framework/Headers/B.h1
-rw-r--r--test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/Headers/Sub.h2
-rw-r--r--test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h1
-rw-r--r--test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h1
-rw-r--r--test/Modules/Inputs/MainA.framework/Headers/A.h1
-rw-r--r--test/Modules/Inputs/MainA.framework/Headers/Main.h2
-rw-r--r--test/Modules/Inputs/MainA.framework/Modules/module.modulemap12
-rw-r--r--test/Modules/Inputs/MainA.framework/Modules/module.private.modulemap12
-rw-r--r--test/Modules/Inputs/MainA.framework/PrivateHeaders/APriv.h1
-rw-r--r--test/Modules/Inputs/MainA.framework/PrivateHeaders/MainPriv.h1
-rw-r--r--test/Modules/Inputs/SameHeader/A.h3
-rw-r--r--test/Modules/Inputs/SameHeader/B.h4
-rw-r--r--test/Modules/Inputs/SameHeader/C.h12
-rw-r--r--test/Modules/Inputs/SameHeader/module.modulemap11
-rw-r--r--test/Modules/Inputs/check-for-sanitizer-feature/check.h5
-rw-r--r--test/Modules/Inputs/check-for-sanitizer-feature/map3
-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/foo.h28
-rw-r--r--test/Modules/Inputs/codegen/use.cpp8
-rw-r--r--test/Modules/Inputs/crash-typo-correction-visibility/module.h1
-rw-r--r--test/Modules/Inputs/crash-typo-correction-visibility/module.modulemap3
-rw-r--r--test/Modules/Inputs/diag_flags.h1
-rw-r--r--test/Modules/Inputs/diagnose-missing-import/a.h8
-rw-r--r--test/Modules/Inputs/diagnose-missing-import/module.modulemap3
-rw-r--r--test/Modules/Inputs/export_as_test.modulemap9
-rw-r--r--test/Modules/Inputs/header-attribs/bar.h1
-rw-r--r--test/Modules/Inputs/header-attribs/baz.h1
-rw-r--r--test/Modules/Inputs/header-attribs/foo.h1
-rw-r--r--test/Modules/Inputs/header-attribs/modular.modulemap5
-rw-r--r--test/Modules/Inputs/header-attribs/textual.modulemap5
-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/incomplete-umbrella/Foo.framework/Headers/Bar.h1
-rw-r--r--test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h1
-rw-r--r--test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap5
-rw-r--r--test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap5
-rw-r--r--test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h1
-rw-r--r--test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h1
-rw-r--r--test/Modules/Inputs/innerstructredef.h6
-rw-r--r--test/Modules/Inputs/lookup-assert-protocol/Base.h3
-rw-r--r--test/Modules/Inputs/lookup-assert-protocol/Derive.h4
-rw-r--r--test/Modules/Inputs/lookup-assert-protocol/H3.h1
-rw-r--r--test/Modules/Inputs/lookup-assert-protocol/module.map4
-rw-r--r--test/Modules/Inputs/malformed-overload/X.h2
-rw-r--r--test/Modules/Inputs/malformed-overload/module.modulemap4
-rw-r--r--test/Modules/Inputs/module.map28
-rw-r--r--test/Modules/Inputs/objc-desig-init/A.h1
-rw-r--r--test/Modules/Inputs/objc-desig-init/A2.h4
-rw-r--r--test/Modules/Inputs/objc-desig-init/Base.h4
-rw-r--r--test/Modules/Inputs/objc-desig-init/X.h4
-rw-r--r--test/Modules/Inputs/objc-desig-init/module.modulemap9
-rw-r--r--test/Modules/Inputs/objcAtKeywordMissingEnd.h3
-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/pragma_pack_set.h3
-rw-r--r--test/Modules/Inputs/preprocess-decluse/a.h1
-rw-r--r--test/Modules/Inputs/preprocess-decluse/a.modulemap1
-rw-r--r--test/Modules/Inputs/preprocess-decluse/b.h1
-rw-r--r--test/Modules/Inputs/preprocess-decluse/b.modulemap1
-rw-r--r--test/Modules/Inputs/preprocess-decluse/main.modulemap1
-rw-r--r--test/Modules/Inputs/preprocess/a.h2
-rw-r--r--test/Modules/Inputs/preprocess/b.h2
-rw-r--r--test/Modules/Inputs/preprocess/c.h4
-rw-r--r--test/Modules/Inputs/preprocess/file.h6
-rw-r--r--test/Modules/Inputs/preprocess/file2.h2
-rw-r--r--test/Modules/Inputs/preprocess/fwd.h1
-rw-r--r--test/Modules/Inputs/preprocess/module.modulemap7
-rw-r--r--test/Modules/Inputs/preprocess/other.h1
-rw-r--r--test/Modules/Inputs/submodule-visibility/b.h6
-rw-r--r--test/Modules/Inputs/submodule-visibility/other.h9
-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/template-default-args/a.h13
-rw-r--r--test/Modules/Inputs/template-default-args/d.h7
-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/ModuleDebugInfo.cpp11
-rw-r--r--test/Modules/ModuleDebugInfo.m6
-rw-r--r--test/Modules/adl.cpp40
-rw-r--r--test/Modules/anon-linkage.cpp12
-rw-r--r--test/Modules/autolink.m6
-rw-r--r--test/Modules/autolinkTBD.m6
-rw-r--r--test/Modules/builtin-import.mm4
-rw-r--r--test/Modules/builtins.m1
-rw-r--r--test/Modules/check-for-sanitizer-feature.cpp66
-rw-r--r--test/Modules/codegen-flags.test25
-rw-r--r--test/Modules/codegen-nodep.test13
-rw-r--r--test/Modules/codegen.test49
-rw-r--r--test/Modules/const-var-init-update.cpp30
-rw-r--r--test/Modules/crash-typo-correction-visibility.cpp11
-rw-r--r--test/Modules/crash-vfs-ivfsoverlay.m1
-rw-r--r--test/Modules/crash-vfs-path-emptydir-entries.m2
-rw-r--r--test/Modules/crash-vfs-path-symlink-component.m4
-rw-r--r--test/Modules/crash-vfs-path-symlink-topheader.m2
-rw-r--r--test/Modules/crash-vfs-path-traversal.m4
-rw-r--r--test/Modules/crash-vfs-relative-incdir.m2
-rw-r--r--test/Modules/crash-vfs-relative-overlay.m4
-rw-r--r--test/Modules/crash-vfs-run-reproducer.m2
-rw-r--r--test/Modules/cxx-templates.cpp24
-rw-r--r--test/Modules/cxx17-inline-variables.cpp30
-rw-r--r--test/Modules/debug-info-moduleimport-in-module.m21
-rw-r--r--test/Modules/debug-info-moduleimport.m5
-rw-r--r--test/Modules/diag-flags.cpp44
-rw-r--r--test/Modules/diagnose-missing-import.m14
-rw-r--r--test/Modules/diagnostics.modulemap14
-rw-r--r--test/Modules/elaborated-type-specifier-from-hidden-module.m7
-rw-r--r--test/Modules/export_as_test.c9
-rw-r--r--test/Modules/extern_cxx.cpp25
-rw-r--r--test/Modules/find-privateheaders.m13
-rw-r--r--test/Modules/header-attribs.cpp10
-rw-r--r--test/Modules/implicit-built-Werror-using-W.cpp42
-rw-r--r--test/Modules/import-syntax.c35
-rw-r--r--test/Modules/incomplete-umbrella.m15
-rw-r--r--test/Modules/inner-struct-redefines-invisible.m12
-rw-r--r--test/Modules/interface-visibility.m29
-rw-r--r--test/Modules/localsubmodulevis.m8
-rw-r--r--test/Modules/lookup-assert-protocol.m17
-rw-r--r--test/Modules/lookup.m4
-rw-r--r--test/Modules/macro-redefinition.cpp27
-rw-r--r--test/Modules/malformed-overload.m9
-rw-r--r--test/Modules/merge-anon-in-extern_c.cpp19
-rw-r--r--test/Modules/missing-flag.cpp4
-rw-r--r--test/Modules/module-impl-with-link.c5
-rw-r--r--test/Modules/modules-cache-path-canonicalization.m30
-rw-r--r--test/Modules/objc-at-keyword.m7
-rw-r--r--test/Modules/objc-designated-init-mod.m17
-rw-r--r--test/Modules/odr_hash.cpp1432
-rw-r--r--test/Modules/outofdate-rebuild.m15
-rw-r--r--test/Modules/path-resolution.modulemap70
-rw-r--r--test/Modules/pragma-pack.cpp25
-rw-r--r--test/Modules/preprocess-build-diamond.m26
-rw-r--r--test/Modules/preprocess-build.cpp35
-rw-r--r--test/Modules/preprocess-decluse.cpp18
-rw-r--r--test/Modules/preprocess-missing.modulemap7
-rw-r--r--test/Modules/preprocess-module.cpp159
-rw-r--r--test/Modules/preprocess-nested.cpp57
-rw-r--r--test/Modules/preprocess-unavailable.cpp12
-rw-r--r--test/Modules/preprocess.cpp32
-rw-r--r--test/Modules/preprocess.m8
-rw-r--r--test/Modules/redefinition-c-tagtypes.m48
-rw-r--r--test/Modules/redefinition-same-header.m12
-rw-r--r--test/Modules/relative-dep-gen.cpp21
-rw-r--r--test/Modules/requires-coroutines.mm13
-rw-r--r--test/Modules/requires-gnuinlineasm.m4
-rw-r--r--test/Modules/requires.m17
-rw-r--r--test/Modules/requires.mm8
-rw-r--r--test/Modules/string_names.cpp4
-rw-r--r--test/Modules/submodule-visibility.cpp9
-rw-r--r--test/Modules/system-out-of-date-test.m17
-rw-r--r--test/Modules/system_version.m31
-rw-r--r--test/Modules/template-default-args.cpp17
-rw-r--r--test/Modules/umbrella-header-include-builtin.mm12
-rw-r--r--test/Modules/using-decl-inheritance.cpp34
-rw-r--r--test/Modules/using-directive-redecl.cpp37
-rw-r--r--test/Modules/using-directive.cpp62
-rw-r--r--test/Modules/visibility-in-instantiation.cpp51
-rw-r--r--test/Modules/warning-mismatch.m13
-rw-r--r--test/OpenMP/atomic_capture_codegen.cpp50
-rw-r--r--test/OpenMP/atomic_read_codegen.c6
-rw-r--r--test/OpenMP/atomic_update_codegen.cpp48
-rw-r--r--test/OpenMP/atomic_write_codegen.c6
-rw-r--r--test/OpenMP/cancel_codegen_cleanup.cpp46
-rw-r--r--test/OpenMP/capturing_in_templates.cpp30
-rw-r--r--test/OpenMP/critical_codegen.cpp2
-rw-r--r--test/OpenMP/declare_reduction_codegen.cpp38
-rw-r--r--test/OpenMP/declare_reduction_messages.cpp18
-rw-r--r--test/OpenMP/declare_simd_messages.cpp2
-rw-r--r--test/OpenMP/declare_target_ast_print.cpp27
-rw-r--r--test/OpenMP/declare_target_messages.cpp12
-rw-r--r--test/OpenMP/distribute_codegen.cpp15
-rw-r--r--test/OpenMP/distribute_firstprivate_messages.cpp8
-rw-r--r--test/OpenMP/distribute_parallel_for_ast_print.cpp37
-rw-r--r--test/OpenMP/distribute_parallel_for_codegen.cpp2260
-rw-r--r--test/OpenMP/distribute_parallel_for_firstprivate_codegen.cpp619
-rw-r--r--test/OpenMP/distribute_parallel_for_if_codegen.cpp192
-rw-r--r--test/OpenMP/distribute_parallel_for_lastprivate_codegen.cpp653
-rw-r--r--test/OpenMP/distribute_parallel_for_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/distribute_parallel_for_messages.cpp118
-rw-r--r--test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp121
-rw-r--r--test/OpenMP/distribute_parallel_for_private_codegen.cpp297
-rw-r--r--test/OpenMP/distribute_parallel_for_proc_bind_codegen.cpp93
-rw-r--r--test/OpenMP/distribute_parallel_for_reduction_messages.cpp4
-rw-r--r--test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/distribute_parallel_for_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/distribute_parallel_for_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/distribute_parallel_for_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/distribute_private_messages.cpp2
-rw-r--r--test/OpenMP/distribute_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/distribute_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/distribute_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/distribute_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/dump.cpp8
-rw-r--r--test/OpenMP/for_codegen.cpp27
-rw-r--r--test/OpenMP/for_firstprivate_codegen.cpp30
-rw-r--r--test/OpenMP/for_lastprivate_codegen.cpp13
-rw-r--r--test/OpenMP/for_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/for_linear_codegen.cpp1
-rw-r--r--test/OpenMP/for_loop_messages.cpp2
-rw-r--r--test/OpenMP/for_private_codegen.cpp18
-rw-r--r--test/OpenMP/for_reduction_codegen.cpp331
-rw-r--r--test/OpenMP/for_reduction_codegen_UDR.cpp174
-rw-r--r--test/OpenMP/for_reduction_messages.cpp4
-rw-r--r--test/OpenMP/for_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/for_simd_codegen.cpp2
-rw-r--r--test/OpenMP/for_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/for_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/for_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/is_initial_device.c36
-rw-r--r--test/OpenMP/master_codegen.cpp2
-rw-r--r--test/OpenMP/nvptx_param_translate.c19
-rw-r--r--test/OpenMP/nvptx_target_codegen.cpp39
-rw-r--r--test/OpenMP/nvptx_target_firstprivate_codegen.cpp70
-rw-r--r--test/OpenMP/openmp_offload_codegen.cpp36
-rw-r--r--test/OpenMP/ordered_codegen.cpp4
-rw-r--r--test/OpenMP/ordered_messages.cpp8
-rw-r--r--test/OpenMP/parallel_codegen.cpp12
-rw-r--r--test/OpenMP/parallel_for_codegen.cpp43
-rw-r--r--test/OpenMP/parallel_for_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/parallel_for_loop_messages.cpp2
-rw-r--r--test/OpenMP/parallel_for_reduction_messages.cpp10
-rw-r--r--test/OpenMP/parallel_for_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/parallel_for_simd_codegen.cpp3
-rw-r--r--test/OpenMP/parallel_for_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/parallel_for_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/parallel_for_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/parallel_if_codegen.cpp2
-rw-r--r--test/OpenMP/parallel_reduction_codegen.cpp8
-rw-r--r--test/OpenMP/parallel_reduction_messages.cpp4
-rw-r--r--test/OpenMP/parallel_sections_codegen.cpp6
-rw-r--r--test/OpenMP/parallel_sections_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/parallel_sections_reduction_messages.cpp4
-rw-r--r--test/OpenMP/report_default_DSA.cpp18
-rw-r--r--test/OpenMP/sections_codegen.cpp9
-rw-r--r--test/OpenMP/sections_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/sections_reduction_messages.cpp4
-rw-r--r--test/OpenMP/simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/single_codegen.cpp2
-rw-r--r--test/OpenMP/target_ast_print.cpp63
-rw-r--r--test/OpenMP/target_codegen.cpp450
-rw-r--r--test/OpenMP/target_codegen_global_capture.cpp143
-rw-r--r--test/OpenMP/target_codegen_registration.cpp64
-rw-r--r--test/OpenMP/target_data_codegen.cpp51
-rw-r--r--test/OpenMP/target_data_messages.c2
-rw-r--r--test/OpenMP/target_data_use_device_ptr_codegen.cpp113
-rw-r--r--test/OpenMP/target_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_enter_data_codegen.cpp51
-rw-r--r--test/OpenMP/target_enter_data_depend_messages.cpp20
-rw-r--r--test/OpenMP/target_enter_data_map_messages.c2
-rw-r--r--test/OpenMP/target_enter_data_nowait_messages.cpp2
-rw-r--r--test/OpenMP/target_exit_data_codegen.cpp51
-rw-r--r--test/OpenMP/target_exit_data_depend_messages.cpp20
-rw-r--r--test/OpenMP/target_exit_data_map_messages.c2
-rw-r--r--test/OpenMP/target_exit_data_nowait_messages.cpp2
-rw-r--r--test/OpenMP/target_firstprivate_codegen.cpp165
-rw-r--r--test/OpenMP/target_is_device_ptr_codegen.cpp112
-rw-r--r--test/OpenMP/target_map_codegen.cpp1926
-rw-r--r--test/OpenMP/target_map_messages.cpp90
-rw-r--r--test/OpenMP/target_messages.cpp2
-rw-r--r--test/OpenMP/target_parallel_codegen.cpp279
-rw-r--r--test/OpenMP/target_parallel_codegen_registration.cpp64
-rw-r--r--test/OpenMP/target_parallel_debug_codegen.cpp113
-rw-r--r--test/OpenMP/target_parallel_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_parallel_for_codegen.cpp232
-rw-r--r--test/OpenMP/target_parallel_for_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_parallel_for_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/target_parallel_for_loop_messages.cpp2
-rw-r--r--test/OpenMP/target_parallel_for_map_messages.cpp12
-rw-r--r--test/OpenMP/target_parallel_for_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_parallel_for_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/target_parallel_for_simd_codegen.cpp232
-rw-r--r--test/OpenMP/target_parallel_for_simd_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_parallel_for_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/target_parallel_for_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/target_parallel_for_simd_map_messages.cpp12
-rw-r--r--test/OpenMP/target_parallel_for_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_parallel_if_codegen.cpp90
-rw-r--r--test/OpenMP/target_parallel_map_messages.cpp12
-rw-r--r--test/OpenMP/target_parallel_no_exceptions.cpp18
-rw-r--r--test/OpenMP/target_parallel_num_threads_codegen.cpp32
-rw-r--r--test/OpenMP/target_parallel_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/target_simd_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/target_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/target_simd_map_messages.cpp12
-rw-r--r--test/OpenMP/target_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_codegen.cpp294
-rw-r--r--test/OpenMP/target_teams_codegen_registration.cpp64
-rw-r--r--test/OpenMP/target_teams_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_teams_distribute_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_teams_distribute_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_distribute_loop_messages.cpp2
-rw-r--r--test/OpenMP/target_teams_distribute_map_messages.cpp12
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_loop_messages.cpp2
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_map_messages.cpp12
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_simd_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_simd_map_messages.cpp12
-rw-r--r--test/OpenMP/target_teams_distribute_parallel_for_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_distribute_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/target_teams_distribute_simd_depend_messages.cpp10
-rw-r--r--test/OpenMP/target_teams_distribute_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_distribute_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/target_teams_distribute_simd_map_messages.cpp12
-rw-r--r--test/OpenMP/target_teams_distribute_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_map_messages.cpp18
-rw-r--r--test/OpenMP/target_teams_num_teams_codegen.cpp32
-rw-r--r--test/OpenMP/target_teams_reduction_messages.cpp4
-rw-r--r--test/OpenMP/target_teams_thread_limit_codegen.cpp32
-rw-r--r--test/OpenMP/target_update_codegen.cpp53
-rw-r--r--test/OpenMP/target_update_depend_messages.cpp20
-rw-r--r--test/OpenMP/target_update_from_messages.cpp12
-rw-r--r--test/OpenMP/target_update_to_messages.cpp12
-rw-r--r--test/OpenMP/task_ast_print.cpp37
-rw-r--r--test/OpenMP/task_codegen.c30
-rw-r--r--test/OpenMP/task_depend_messages.cpp10
-rw-r--r--test/OpenMP/task_in_reduction_codegen.cpp81
-rw-r--r--test/OpenMP/task_in_reduction_message.cpp308
-rw-r--r--test/OpenMP/taskgroup_ast_print.cpp60
-rw-r--r--test/OpenMP/taskgroup_codegen.cpp2
-rw-r--r--test/OpenMP/taskgroup_messages.cpp2
-rw-r--r--test/OpenMP/taskgroup_task_reduction_codegen.cpp212
-rw-r--r--test/OpenMP/taskgroup_task_reduction_messages.cpp258
-rw-r--r--test/OpenMP/taskloop_ast_print.cpp16
-rw-r--r--test/OpenMP/taskloop_codegen.cpp18
-rw-r--r--test/OpenMP/taskloop_firstprivate_codegen.cpp8
-rw-r--r--test/OpenMP/taskloop_firstprivate_messages.cpp4
-rw-r--r--test/OpenMP/taskloop_in_reduction_codegen.cpp82
-rw-r--r--test/OpenMP/taskloop_in_reduction_messages.cpp376
-rw-r--r--test/OpenMP/taskloop_lastprivate_codegen.cpp8
-rw-r--r--test/OpenMP/taskloop_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/taskloop_loop_messages.cpp2
-rw-r--r--test/OpenMP/taskloop_private_codegen.cpp8
-rw-r--r--test/OpenMP/taskloop_reduction_codegen.cpp198
-rw-r--r--test/OpenMP/taskloop_reduction_messages.cpp331
-rw-r--r--test/OpenMP/taskloop_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/taskloop_simd_ast_print.cpp16
-rw-r--r--test/OpenMP/taskloop_simd_codegen.cpp14
-rw-r--r--test/OpenMP/taskloop_simd_firstprivate_codegen.cpp8
-rw-r--r--test/OpenMP/taskloop_simd_firstprivate_messages.cpp4
-rw-r--r--test/OpenMP/taskloop_simd_in_reduction_codegen.cpp82
-rw-r--r--test/OpenMP/taskloop_simd_in_reduction_messages.cpp376
-rw-r--r--test/OpenMP/taskloop_simd_lastprivate_codegen.cpp8
-rw-r--r--test/OpenMP/taskloop_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/taskloop_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/taskloop_simd_private_codegen.cpp8
-rw-r--r--test/OpenMP/taskloop_simd_reduction_codegen.cpp197
-rw-r--r--test/OpenMP/taskloop_simd_reduction_messages.cpp331
-rw-r--r--test/OpenMP/teams_distribute_codegen.cpp241
-rw-r--r--test/OpenMP/teams_distribute_collapse_codegen.cpp126
-rw-r--r--test/OpenMP/teams_distribute_dist_schedule_codegen.cpp206
-rw-r--r--test/OpenMP/teams_distribute_firstprivate_codegen.cpp336
-rw-r--r--test/OpenMP/teams_distribute_lastprivate_codegen.cpp366
-rw-r--r--test/OpenMP/teams_distribute_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_loop_messages.cpp2
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_loop_messages.cpp2
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_reduction_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_shared_messages.cpp2
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_parallel_for_simd_shared_messages.cpp2
-rw-r--r--test/OpenMP/teams_distribute_private_codegen.cpp236
-rw-r--r--test/OpenMP/teams_distribute_reduction_codegen.cpp217
-rw-r--r--test/OpenMP/teams_distribute_reduction_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_shared_messages.cpp2
-rw-r--r--test/OpenMP/teams_distribute_simd_aligned_messages.cpp5
-rw-r--r--test/OpenMP/teams_distribute_simd_lastprivate_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_simd_loop_messages.cpp2
-rw-r--r--test/OpenMP/teams_distribute_simd_reduction_messages.cpp4
-rw-r--r--test/OpenMP/teams_distribute_simd_shared_messages.cpp2
-rw-r--r--test/OpenMP/teams_reduction_messages.cpp4
-rw-r--r--test/OpenMP/teams_shared_messages.cpp2
-rw-r--r--test/OpenMP/varargs.cpp8
-rw-r--r--test/OpenMP/vla_crash.c42
-rw-r--r--test/PCH/attrs.c3
-rw-r--r--test/PCH/case-insensitive-include.c15
-rw-r--r--test/PCH/coroutines.cpp77
-rw-r--r--test/PCH/cxx-dependent-sized-ext-vector.cpp18
-rw-r--r--test/PCH/cxx-templates.cpp8
-rw-r--r--test/PCH/cxx-templates.h3
-rw-r--r--test/PCH/cxx-traits.cpp1
-rw-r--r--test/PCH/cxx-traits.h1
-rw-r--r--test/PCH/cxx11-lambdas.mm2
-rw-r--r--test/PCH/cxx2a-bitfield-init.cpp25
-rw-r--r--test/PCH/emit-dependencies.c9
-rw-r--r--test/PCH/include-timestamp.cpp20
-rw-r--r--test/PCH/pragma-pack.c90
-rw-r--r--test/PCH/suspicious-pragma-pack.c10
-rw-r--r--test/Parser/MicrosoftExtensions.cpp6
-rw-r--r--test/Parser/altivec-csk-bool.c4
-rw-r--r--test/Parser/altivec.c6
-rw-r--r--test/Parser/arm-windows-calling-convention-handling.c1
-rw-r--r--test/Parser/builtin_types_compatible.c17
-rw-r--r--test/Parser/c2x-attributes.c122
-rw-r--r--test/Parser/c2x-attributes.m21
-rw-r--r--test/Parser/cxx-altivec.cpp6
-rw-r--r--test/Parser/cxx-bool.cpp9
-rw-r--r--test/Parser/cxx-modules-import.cpp58
-rw-r--r--test/Parser/cxx-modules-interface.cppm7
-rw-r--r--test/Parser/cxx-template-argument.cpp2
-rw-r--r--test/Parser/cxx0x-ambig.cpp26
-rw-r--r--test/Parser/cxx0x-attributes.cpp8
-rw-r--r--test/Parser/cxx0x-condition.cpp4
-rw-r--r--test/Parser/cxx0x-decl.cpp19
-rw-r--r--test/Parser/cxx11-stmt-attributes.cpp1
-rw-r--r--test/Parser/cxx1z-class-template-argument-deduction.cpp1
-rw-r--r--test/Parser/cxx1z-constexpr-lambdas.cpp8
-rw-r--r--test/Parser/cxx1z-fold-expressions.cpp17
-rw-r--r--test/Parser/cxx1z-nested-namespace-definition.cpp6
-rw-r--r--test/Parser/cxx2a-bitfield-init.cpp22
-rw-r--r--test/Parser/editor-placeholder-recovery.cpp75
-rw-r--r--test/Parser/ms-square-bracket-attributes.mm2
-rw-r--r--test/Parser/objc-at-implementation-eof-crash.m24
-rw-r--r--test/Parser/objc-at-interface-eof-crash.m23
-rw-r--r--test/Parser/objc-available.m13
-rw-r--r--test/Parser/objc-cxx-keyword-identifiers.mm62
-rw-r--r--test/Parser/opencl-atomics-cl20.cl2
-rw-r--r--test/Parser/placeholder-recovery.m13
-rw-r--r--test/Parser/pragma-attribute-declspec.cpp13
-rw-r--r--test/Parser/pragma-attribute.cpp181
-rw-r--r--test/Parser/pragma-fp.cpp64
-rw-r--r--test/Parser/pragma-options.c2
-rw-r--r--test/Parser/pragma-options.cpp2
-rw-r--r--test/Parser/pragma-pack.c2
-rw-r--r--test/Parser/vector-cast-define.cl10
-rw-r--r--test/Parser/vsx.c4
-rw-r--r--test/Preprocessor/Inputs/nonportable-hmaps/foo.hmapbin0 -> 102 bytes
-rw-r--r--test/Preprocessor/Inputs/nonportable-hmaps/headers/foo/Foo.h0
-rw-r--r--test/Preprocessor/aarch64-target-features.c12
-rw-r--r--test/Preprocessor/arm-target-features.c1
-rw-r--r--test/Preprocessor/cuda-types.cu32
-rw-r--r--test/Preprocessor/cxx_oper_keyword.cpp12
-rw-r--r--test/Preprocessor/hexagon-predefines.c45
-rw-r--r--test/Preprocessor/init.c492
-rw-r--r--test/Preprocessor/line-directive-output.c7
-rw-r--r--test/Preprocessor/macro_paste_commaext.c21
-rw-r--r--test/Preprocessor/macro_vaopt_check.cpp64
-rw-r--r--test/Preprocessor/macro_vaopt_expand.cpp148
-rw-r--r--test/Preprocessor/nonportable-include-with-hmap.c16
-rw-r--r--test/Preprocessor/pp-modules.c6
-rw-r--r--test/Preprocessor/pr19649-unsigned-wchar_t.c2
-rw-r--r--test/Preprocessor/pragma_assume_nonnull.c16
-rw-r--r--test/Preprocessor/pragma_diagnostic.c7
-rw-r--r--test/Preprocessor/pragma_module.c52
-rw-r--r--test/Preprocessor/predefined-arch-macros.c271
-rw-r--r--test/Preprocessor/predefined-macros.c24
-rw-r--r--test/Preprocessor/print-assembler.s16
-rw-r--r--test/Preprocessor/stdint.c99
-rw-r--r--test/Preprocessor/stringize_space.c11
-rw-r--r--test/Preprocessor/wchar_t.c113
-rw-r--r--test/Preprocessor/woa-defaults.c5
-rw-r--r--test/Preprocessor/x86_target_features.c8
-rw-r--r--test/Profile/Inputs/cxx-missing-bodies.proftext9
-rw-r--r--test/Profile/c-outdated-data.c16
-rw-r--r--test/Profile/cxx-missing-bodies.cpp21
-rw-r--r--test/Profile/cxx-structors.cpp2
-rw-r--r--test/Refactor/Extract/ExtractExprIntoFunction.cpp56
-rw-r--r--test/Refactor/Extract/FromMethodToFunction.cpp42
-rw-r--r--test/Refactor/Extract/ObjCProperty.m41
-rw-r--r--test/Refactor/LocalRename/Field.cpp11
-rw-r--r--test/Refactor/LocalRename/NoSymbolSelectedError.cpp8
-rw-r--r--test/Refactor/tool-apply-replacements.cpp9
-rw-r--r--test/Refactor/tool-common-options.c3
-rw-r--r--test/Refactor/tool-selection-option.c15
-rw-r--r--test/Refactor/tool-test-support.c46
-rw-r--r--test/Sema/128bitfloat.cpp10
-rw-r--r--test/Sema/2010-05-31-palignr.c8
-rw-r--r--test/Sema/Inputs/pragma-pack1.h27
-rw-r--r--test/Sema/Inputs/pragma-pack2.h8
-rw-r--r--test/Sema/address-packed.c9
-rw-r--r--test/Sema/address_spaces.c2
-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.c22
-rw-r--r--test/Sema/asm.c35
-rw-r--r--test/Sema/assign.c43
-rw-r--r--test/Sema/atomic-ops.c10
-rw-r--r--test/Sema/attr-availability-app-extensions.c11
-rw-r--r--test/Sema/attr-availability-ios.c4
-rw-r--r--test/Sema/attr-availability-macosx.c4
-rw-r--r--test/Sema/attr-availability-tvos.c4
-rw-r--r--test/Sema/attr-availability-watchos.c4
-rw-r--r--test/Sema/attr-availability.c29
-rw-r--r--test/Sema/attr-capabilities.c3
-rw-r--r--test/Sema/attr-deprecated-c2x.c54
-rw-r--r--test/Sema/attr-deprecated.c27
-rw-r--r--test/Sema/attr-long-call.c26
-rw-r--r--test/Sema/attr-micromips.c17
-rw-r--r--test/Sema/attr-section.c13
-rw-r--r--test/Sema/attr-selectany.c5
-rw-r--r--test/Sema/attr-target.c10
-rw-r--r--test/Sema/attr-unavailable-message.c8
-rw-r--r--test/Sema/block-args.c2
-rw-r--r--test/Sema/builtin-cpu-supports.c6
-rw-r--r--test/Sema/builtins-ppc.c4
-rw-r--r--test/Sema/builtins-x86.c2
-rw-r--r--test/Sema/c2x-fallthrough.c75
-rw-r--r--test/Sema/c2x-maybe_unused-errors.c12
-rw-r--r--test/Sema/c2x-maybe_unused.c35
-rw-r--r--test/Sema/c2x-nodiscard.c49
-rw-r--r--test/Sema/compare.c59
-rw-r--r--test/Sema/declspec-naked.c11
-rw-r--r--test/Sema/designated-initializers.c17
-rw-r--r--test/Sema/diagnose_if.c4
-rw-r--r--test/Sema/dllimport.c8
-rw-r--r--test/Sema/enum-attr.c130
-rw-r--r--test/Sema/enum.c12
-rw-r--r--test/Sema/expr-address-of.c3
-rw-r--r--test/Sema/ext_vector_ops.c27
-rw-r--r--test/Sema/format-strings-fixit-ssize_t.c10
-rw-r--r--test/Sema/format-strings-scanf.c64
-rw-r--r--test/Sema/fp16vec-sema.c51
-rw-r--r--test/Sema/implicit-decl-c90.c50
-rw-r--r--test/Sema/implicit-decl.c5
-rw-r--r--test/Sema/inline-asm-validate-amdgpu.cl66
-rw-r--r--test/Sema/integer-overflow.c7
-rw-r--r--test/Sema/loop-control.c48
-rw-r--r--test/Sema/ms-annotation.c13
-rw-r--r--test/Sema/ms-inline-asm.c13
-rw-r--r--test/Sema/noescape.c25
-rw-r--r--test/Sema/outof-range-constant-compare.c36
-rw-r--r--test/Sema/outof-range-enum-constant-compare.c379
-rw-r--r--test/Sema/overloadable.c135
-rw-r--r--test/Sema/pointer-addition.c11
-rw-r--r--test/Sema/pragma-attribute-strict-subjects.c153
-rw-r--r--test/Sema/pragma-attribute.c47
-rw-r--r--test/Sema/pragma-clang-section.c17
-rw-r--r--test/Sema/pragma-pack.c5
-rw-r--r--test/Sema/preserve-call-conv.c3
-rw-r--r--test/Sema/redefinition-same-header.c14
-rw-r--r--test/Sema/sign-compare-enum.c24
-rw-r--r--test/Sema/sizeof-struct-non-zero-as-member.cl1
-rw-r--r--test/Sema/struct-packed-align.c14
-rw-r--r--test/Sema/suspicious-pragma-pack.c50
-rw-r--r--test/Sema/switch.c1
-rw-r--r--test/Sema/tautological-constant-compare.c514
-rw-r--r--test/Sema/tautological-constant-enum-compare.c419
-rw-r--r--test/Sema/tautological-unsigned-enum-zero-compare.c260
-rw-r--r--test/Sema/tautological-unsigned-enum-zero-compare.cpp347
-rw-r--r--test/Sema/tautological-unsigned-zero-compare.c370
-rw-r--r--test/Sema/tls.c10
-rw-r--r--test/Sema/transparent-union.c2
-rw-r--r--test/Sema/typo-correction.c7
-rw-r--r--test/Sema/varargs-aarch64.c11
-rw-r--r--test/Sema/varargs-x86-32.c2
-rw-r--r--test/Sema/varargs.c2
-rw-r--r--test/Sema/vector-cast.c13
-rw-r--r--test/Sema/vector-gcc-compat.c330
-rw-r--r--test/Sema/vector-gcc-compat.cpp328
-rw-r--r--test/Sema/vector-ops.c116
-rw-r--r--test/Sema/vector_swizzle_length.c10
-rw-r--r--test/Sema/warn-cast-qual.c31
-rw-r--r--test/Sema/warn-documentation.cpp96
-rw-r--r--test/Sema/warn-documentation.m81
-rw-r--r--test/Sema/warn-strict-prototypes.m11
-rw-r--r--test/Sema/warn-unreachable-ms.c55
-rw-r--r--test/Sema/warn-unreachable.c47
-rw-r--r--test/Sema/wchar.c2
-rw-r--r--test/Sema/xray-log-args-class.cpp7
-rw-r--r--test/Sema/zero-initializer.c41
-rw-r--r--test/Sema/zvector.c24
-rw-r--r--test/Sema/zvector2.c211
-rw-r--r--test/SemaCUDA/error-includes-mode.cu7
-rw-r--r--test/SemaCUDA/function-overload.cu2
-rw-r--r--test/SemaCUDA/no-destructor-overload.cu10
-rw-r--r--test/SemaCXX/Inputs/nullability-completeness.h4
-rw-r--r--test/SemaCXX/Inputs/std-coroutine.h37
-rw-r--r--test/SemaCXX/Inputs/warn-zero-nullptr.h3
-rw-r--r--test/SemaCXX/MicrosoftCompatibility-cxx98.cpp23
-rw-r--r--test/SemaCXX/MicrosoftCompatibility.cpp24
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp22
-rw-r--r--test/SemaCXX/P30636.cpp20
-rw-r--r--test/SemaCXX/PR16677.cpp5
-rw-r--r--test/SemaCXX/PR27037.cpp13
-rw-r--r--test/SemaCXX/accessible-base.cpp32
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp32
-rw-r--r--test/SemaCXX/alloc-align-attr.cpp40
-rw-r--r--test/SemaCXX/altivec.cpp2
-rw-r--r--test/SemaCXX/amdgpu-sizeof-alignof.cpp47
-rw-r--r--test/SemaCXX/anonymous-struct.cpp3
-rw-r--r--test/SemaCXX/attr-cxx-disabled.cpp12
-rw-r--r--test/SemaCXX/attr-deprecated.cpp20
-rw-r--r--test/SemaCXX/attr-flag-enum-reject.cpp4
-rw-r--r--test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp29
-rw-r--r--test/SemaCXX/attr-require-constant-initialization.cpp72
-rw-r--r--test/SemaCXX/attr-selectany.cpp5
-rw-r--r--test/SemaCXX/attr-x86-no_caller_saved_registers.cpp33
-rw-r--r--test/SemaCXX/co_await-range-for.cpp165
-rw-r--r--test/SemaCXX/compare.cpp6
-rw-r--r--test/SemaCXX/complex-conversion.cpp18
-rw-r--r--test/SemaCXX/complex-overload.cpp7
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp65
-rw-r--r--test/SemaCXX/constant-expression-cxx1y.cpp39
-rw-r--r--test/SemaCXX/constexpr-array-unknown-bound.cpp26
-rw-r--r--test/SemaCXX/constructor-initializer.cpp19
-rw-r--r--test/SemaCXX/coreturn.cpp128
-rw-r--r--test/SemaCXX/coroutine-seh.cpp37
-rw-r--r--test/SemaCXX/coroutine-unhandled_exception-warning.cpp41
-rw-r--r--test/SemaCXX/coroutine-uninitialized-warning-crash.cpp44
-rw-r--r--test/SemaCXX/coroutines.cpp583
-rw-r--r--test/SemaCXX/cxx-altivec.cpp2
-rw-r--r--test/SemaCXX/cxx0x-compat.cpp13
-rw-r--r--test/SemaCXX/cxx0x-cursory-default-delete.cpp6
-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/cxx0x-initializer-stdinitializerlist.cpp8
-rw-r--r--test/SemaCXX/cxx17-compat.cpp29
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp19
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp146
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp24
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas.cpp7
-rw-r--r--test/SemaCXX/cxx1y-init-captures.cpp8
-rw-r--r--test/SemaCXX/cxx1y-variable-templates_top_level.cpp7
-rw-r--r--test/SemaCXX/cxx1z-class-template-argument-deduction.cpp133
-rw-r--r--test/SemaCXX/cxx1z-copy-omission.cpp41
-rw-r--r--test/SemaCXX/cxx1z-decomposition.cpp6
-rw-r--r--test/SemaCXX/cxx1z-init-statement-template.cpp32
-rw-r--r--test/SemaCXX/cxx1z-init-statement.cpp1
-rw-r--r--test/SemaCXX/cxx1z-lambda-star-this.cpp531
-rw-r--r--test/SemaCXX/cxx1z-noexcept-function-type.cpp8
-rw-r--r--test/SemaCXX/cxx2a-destroying-delete.cpp103
-rw-r--r--test/SemaCXX/cxx2a-lambda-equals-this.cpp15
-rw-r--r--test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp14
-rw-r--r--test/SemaCXX/cxx98-compat-flags.cpp6
-rw-r--r--test/SemaCXX/decl-expr-ambiguity.cpp24
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp2
-rw-r--r--test/SemaCXX/deprecated.cpp34
-rw-r--r--test/SemaCXX/destructor.cpp67
-rw-r--r--test/SemaCXX/dllimport-memptr.cpp7
-rw-r--r--test/SemaCXX/enable_if.cpp41
-rw-r--r--test/SemaCXX/enum-attr.cpp108
-rw-r--r--test/SemaCXX/enum.cpp10
-rw-r--r--test/SemaCXX/eval-crashes.cpp56
-rw-r--r--test/SemaCXX/flexible-array-test.cpp5
-rw-r--r--test/SemaCXX/for-range-examples.cpp34
-rw-r--r--test/SemaCXX/friend2.cpp37
-rw-r--r--test/SemaCXX/imaginary-constants.cpp44
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp2
-rw-r--r--test/SemaCXX/init-expr-crash.cpp31
-rw-r--r--test/SemaCXX/inline.cpp6
-rw-r--r--test/SemaCXX/integer-overflow.cpp2
-rw-r--r--test/SemaCXX/invalid-member-expr.cpp4
-rw-r--r--test/SemaCXX/invalid-template-params.cpp23
-rw-r--r--test/SemaCXX/lambda-expressions.cpp14
-rw-r--r--test/SemaCXX/linkage2.cpp36
-rw-r--r--test/SemaCXX/local-classes.cpp12
-rw-r--r--test/SemaCXX/member-init.cpp2
-rw-r--r--test/SemaCXX/microsoft-varargs.cpp5
-rw-r--r--test/SemaCXX/missing-members.cpp14
-rw-r--r--test/SemaCXX/modules-ts.cppm33
-rw-r--r--test/SemaCXX/ms-interface.cpp29
-rw-r--r--test/SemaCXX/ms-iunknown-inline-def.cpp8
-rw-r--r--test/SemaCXX/ms-iunknown-outofline-def.cpp10
-rw-r--r--test/SemaCXX/ms-iunknown-template-function.cpp39
-rw-r--r--test/SemaCXX/ms-iunknown.cpp50
-rw-r--r--test/SemaCXX/ms-uuid.cpp2
-rw-r--r--test/SemaCXX/nested-name-spec.cpp7
-rw-r--r--test/SemaCXX/nothrow-as-noexcept-ctor.cpp26
-rw-r--r--test/SemaCXX/null-cast.cpp8
-rw-r--r--test/SemaCXX/nullability.cpp8
-rw-r--r--test/SemaCXX/nullptr-arithmetic.cpp30
-rw-r--r--test/SemaCXX/overloaded-operator.cpp54
-rw-r--r--test/SemaCXX/ptrtomember.cpp4
-rw-r--r--test/SemaCXX/short-wchar-sign.cpp2
-rw-r--r--test/SemaCXX/static-assert.cpp19
-rw-r--r--test/SemaCXX/suppress.cpp25
-rw-r--r--test/SemaCXX/template-default-param-through-using.cpp33
-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.cpp486
-rw-r--r--test/SemaCXX/typo-correction-crash.cpp4
-rw-r--r--test/SemaCXX/typo-correction.cpp38
-rw-r--r--test/SemaCXX/unavailable_aligned_allocation.cpp139
-rw-r--r--test/SemaCXX/undefined-internal.cpp8
-rw-r--r--test/SemaCXX/uninitialized.cpp2
-rw-r--r--test/SemaCXX/unused.cpp52
-rw-r--r--test/SemaCXX/varargs.cpp57
-rw-r--r--test/SemaCXX/vartemplate-lambda.cpp2
-rw-r--r--test/SemaCXX/vector-no-lax.cpp2
-rw-r--r--test/SemaCXX/virtual-base-used.cpp22
-rw-r--r--test/SemaCXX/warn-absolute-value.cpp155
-rw-r--r--test/SemaCXX/warn-bitfield-enum-conversion.cpp59
-rw-r--r--test/SemaCXX/warn-c++1z-extensions.cpp4
-rw-r--r--test/SemaCXX/warn-cast-qual.cpp140
-rw-r--r--test/SemaCXX/warn-enum-compare.cpp67
-rw-r--r--test/SemaCXX/warn-global-constructors.cpp19
-rw-r--r--test/SemaCXX/warn-loop-analysis.cpp12
-rw-r--r--test/SemaCXX/warn-shadow.cpp123
-rw-r--r--test/SemaCXX/warn-sign-conversion-cpp11.cpp21
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp56
-rw-r--r--test/SemaCXX/warn-thread-safety-parsing.cpp14
-rw-r--r--test/SemaCXX/warn-throw-out-noexcept-func.cpp327
-rw-r--r--test/SemaCXX/warn-unreachable.cpp16
-rw-r--r--test/SemaCXX/warn-unused-filescoped.cpp18
-rw-r--r--test/SemaCXX/warn-unused-lambda-capture.cpp5
-rw-r--r--test/SemaCXX/warn-unused-private-field.cpp17
-rw-r--r--test/SemaCXX/warn-unused-result.cpp46
-rw-r--r--test/SemaCXX/warn-unused-value.cpp6
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp43
-rw-r--r--test/SemaCXX/warn-zero-nullptr.cpp92
-rw-r--r--test/SemaObjC/Inputs/empty.h1
-rw-r--r--test/SemaObjC/arc-nsconsumed-errors.m13
-rw-r--r--test/SemaObjC/arc-peformselector.m11
-rw-r--r--test/SemaObjC/arc-property-decl-attrs.m131
-rw-r--r--test/SemaObjC/arc-repeated-weak.mm10
-rw-r--r--test/SemaObjC/arc-unavailable-for-weakref.m1
-rw-r--r--test/SemaObjC/attr-availability.m30
-rw-r--r--test/SemaObjC/attr-deprecated.m22
-rw-r--r--test/SemaObjC/attr-ns_returns_retained.m18
-rw-r--r--test/SemaObjC/category-attribute.m23
-rw-r--r--test/SemaObjC/class-message-protocol-lookup.m27
-rw-r--r--test/SemaObjC/class-unavail-warning.m4
-rw-r--r--test/SemaObjC/default-synthesize-1.m16
-rw-r--r--test/SemaObjC/default-synthesize-3.m8
-rw-r--r--test/SemaObjC/default-synthesize.m2
-rw-r--r--test/SemaObjC/diagnose_if.m16
-rw-r--r--test/SemaObjC/flexible-array-arc.m36
-rw-r--r--test/SemaObjC/flexible-array.m288
-rw-r--r--test/SemaObjC/foreach.m24
-rw-r--r--test/SemaObjC/forward-protocol-incomplete-impl-warn.m2
-rw-r--r--test/SemaObjC/illegal-nonarc-bridged-cast.m17
-rw-r--r--test/SemaObjC/ivar-sem-check-1.m5
-rw-r--r--test/SemaObjC/method-bad-param.m6
-rw-r--r--test/SemaObjC/objc-container-subscripting-1.m5
-rw-r--r--test/SemaObjC/objc-container-subscripting-2.m19
-rw-r--r--test/SemaObjC/property-ambiguous-synthesis.m2
-rw-r--r--test/SemaObjC/property-implement-readonly-with-custom-setter.m21
-rw-r--r--test/SemaObjC/property-typecheck-1.m5
-rw-r--r--test/SemaObjC/special-dep-unavail-warning.m4
-rw-r--r--test/SemaObjC/suspicious-pragma-pack.m6
-rw-r--r--test/SemaObjC/typo-correction.m20
-rw-r--r--test/SemaObjC/unguarded-availability-new.m160
-rw-r--r--test/SemaObjC/unguarded-availability.m150
-rw-r--r--test/SemaObjC/warn-deprecated-implementations.m29
-rw-r--r--test/SemaObjC/warn-messaging-id.mm21
-rw-r--r--test/SemaObjC/x86-method-vector-values.m125
-rw-r--r--test/SemaObjCXX/Inputs/nullability-completeness-cferror.h13
-rw-r--r--test/SemaObjCXX/Inputs/nullability-consistency-2.h2
-rw-r--r--test/SemaObjCXX/arc-bridged-cast.mm16
-rw-r--r--test/SemaObjCXX/arc-overloading.mm2
-rw-r--r--test/SemaObjCXX/arc-ptr-comparison.mm24
-rw-r--r--test/SemaObjCXX/arc-unavailable-for-weakref.mm1
-rw-r--r--test/SemaObjCXX/flexible-array.mm37
-rw-r--r--test/SemaObjCXX/interface-return-type.mm7
-rw-r--r--test/SemaObjCXX/is-base-of.mm25
-rw-r--r--test/SemaObjCXX/noescape.mm90
-rw-r--r--test/SemaObjCXX/nullability-completeness-cferror.mm5
-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/SemaObjCXX/pr32725.mm9
-rw-r--r--test/SemaObjCXX/typo-correction.mm53
-rw-r--r--test/SemaOpenCL/address-spaces.cl23
-rw-r--r--test/SemaOpenCL/arithmetic-conversions.cl23
-rw-r--r--test/SemaOpenCL/array-init.cl20
-rw-r--r--test/SemaOpenCL/as_type.cl9
-rw-r--r--test/SemaOpenCL/atomic-init.cl12
-rw-r--r--test/SemaOpenCL/atomic-ops.cl195
-rw-r--r--test/SemaOpenCL/cl20-device-side-enqueue.cl56
-rw-r--r--test/SemaOpenCL/clang-builtin-version.cl61
-rw-r--r--test/SemaOpenCL/cond.cl2
-rw-r--r--test/SemaOpenCL/extension-begin.cl2
-rw-r--r--test/SemaOpenCL/extern.cl9
-rw-r--r--test/SemaOpenCL/func.cl12
-rw-r--r--test/SemaOpenCL/images.cl33
-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.cl11
-rw-r--r--test/SemaOpenCL/invalid-kernel-attrs.cl4
-rw-r--r--test/SemaOpenCL/invalid-pipe-builtin-cl2.0.cl4
-rw-r--r--test/SemaOpenCL/invalid-pipes-cl2.0.cl5
-rw-r--r--test/SemaOpenCL/overload_addrspace_resolution.cl29
-rw-r--r--test/SemaOpenCL/sampler_t.cl13
-rw-r--r--test/SemaOpenCL/storageclass-cl20.cl38
-rw-r--r--test/SemaOpenCL/storageclass.cl61
-rw-r--r--test/SemaOpenCL/to_addr_builtin.cl2
-rw-r--r--test/SemaOpenCL/types.cl6
-rw-r--r--test/SemaOpenCL/vector_conv_invalid.cl10
-rw-r--r--test/SemaOpenCL/vector_literals_invalid.cl3
-rw-r--r--test/SemaOpenCL/vector_swizzle_length.cl10
-rw-r--r--test/SemaTemplate/address_space-dependent.cpp119
-rw-r--r--test/SemaTemplate/constexpr-instantiate.cpp2
-rw-r--r--test/SemaTemplate/crash-unparsed-exception.cpp5
-rw-r--r--test/SemaTemplate/cxx17-inline-variables.cpp7
-rw-r--r--test/SemaTemplate/deduction-crash.cpp53
-rw-r--r--test/SemaTemplate/deduction.cpp13
-rw-r--r--test/SemaTemplate/default-arguments-cxx0x.cpp27
-rw-r--r--test/SemaTemplate/default-arguments.cpp16
-rw-r--r--test/SemaTemplate/default-expr-arguments-3.cpp2
-rw-r--r--test/SemaTemplate/dependent-template-recover.cpp22
-rw-r--r--test/SemaTemplate/destructor-template.cpp6
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp2
-rw-r--r--test/SemaTemplate/explicit-specialization-member.cpp23
-rw-r--r--test/SemaTemplate/extern-templates.cpp7
-rw-r--r--test/SemaTemplate/instantiate-friend-function.cpp49
-rw-r--r--test/SemaTemplate/ms-lookup-template-base-classes.cpp3
-rw-r--r--test/SemaTemplate/overload-candidates.cpp34
-rw-r--r--test/SemaTemplate/temp_arg_nontype_cxx11.cpp2
-rw-r--r--test/SemaTemplate/temp_arg_nontype_cxx1z.cpp3
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp48
-rw-r--r--test/SemaTemplate/temp_arg_template_cxx1z.cpp18
-rw-r--r--test/SemaTemplate/temp_arg_type.cpp54
-rw-r--r--test/SemaTemplate/typo-template-name.cpp43
-rw-r--r--test/Tooling/Inputs/clang-diff-basic-src.cpp33
-rw-r--r--test/Tooling/clang-diff-args.test12
-rw-r--r--test/Tooling/clang-diff-ast.cpp92
-rw-r--r--test/Tooling/clang-diff-basic.cpp57
-rw-r--r--test/Tooling/clang-diff-bottomup.cpp39
-rw-r--r--test/Tooling/clang-diff-html.test36
-rw-r--r--test/Tooling/clang-diff-json.cpp27
-rw-r--r--test/Tooling/clang-diff-opt.cpp45
-rw-r--r--test/Tooling/clang-diff-topdown.cpp83
-rw-r--r--test/Unit/lit.cfg109
-rw-r--r--test/Unit/lit.cfg.py57
-rw-r--r--test/Unit/lit.site.cfg.py.in (renamed from test/Unit/lit.site.cfg.in)2
-rw-r--r--test/clang-rename/ClassAsTemplateArgument.cpp21
-rw-r--r--test/clang-rename/ClassFindByName.cpp10
-rw-r--r--test/clang-rename/ClassSimpleRenaming.cpp14
-rw-r--r--test/clang-rename/ClassTestMulti.cpp11
-rw-r--r--test/clang-rename/ClassTestMultiByName.cpp8
-rw-r--r--test/clang-rename/ComplexFunctionOverride.cpp47
-rw-r--r--test/clang-rename/ComplicatedClassType.cpp63
-rw-r--r--test/clang-rename/Ctor.cpp14
-rw-r--r--test/clang-rename/CtorInitializer.cpp17
-rw-r--r--test/clang-rename/DeclRefExpr.cpp24
-rw-r--r--test/clang-rename/ForceMulti.cpp8
-rw-r--r--test/clang-rename/FunctionMacro.cpp20
-rw-r--r--test/clang-rename/FunctionOverride.cpp13
-rw-r--r--test/clang-rename/FunctionWithClassFindByName.cpp12
-rw-r--r--test/clang-rename/IncludeHeaderWithSymbol.cpp10
-rw-r--r--test/clang-rename/Inputs/HeaderWithSymbol.h1
-rw-r--r--test/clang-rename/Inputs/OffsetToNewName.yaml6
-rw-r--r--test/clang-rename/Inputs/QualifiedNameToNewName.yaml6
-rw-r--r--test/clang-rename/InvalidNewName.cpp2
-rw-r--r--test/clang-rename/InvalidOffset.cpp9
-rw-r--r--test/clang-rename/InvalidQualifiedName.cpp4
-rw-r--r--test/clang-rename/MemberExprMacro.cpp22
-rw-r--r--test/clang-rename/Namespace.cpp13
-rw-r--r--test/clang-rename/NoNewName.cpp4
-rw-r--r--test/clang-rename/TemplateClassInstantiation.cpp42
-rw-r--r--test/clang-rename/TemplateTypename.cpp24
-rw-r--r--test/clang-rename/TemplatedClassFunction.cpp27
-rw-r--r--test/clang-rename/UserDefinedConversion.cpp26
-rw-r--r--test/clang-rename/Variable.cpp33
-rw-r--r--test/clang-rename/VariableMacro.cpp21
-rw-r--r--test/clang-rename/YAMLInput.cpp10
-rw-r--r--test/lit.cfg523
-rw-r--r--test/lit.cfg.py184
-rw-r--r--test/lit.site.cfg.py.in (renamed from test/lit.site.cfg.in)9
-rw-r--r--tools/CMakeLists.txt5
-rw-r--r--tools/c-index-test/c-index-test.c169
-rw-r--r--tools/c-index-test/core_main.cpp2
-rw-r--r--tools/clang-check/ClangCheck.cpp3
-rw-r--r--tools/clang-diff/CMakeLists.txt14
-rw-r--r--tools/clang-diff/ClangDiff.cpp537
-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.cs198
-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/CMakeLists.txt2
-rw-r--r--tools/clang-format/ClangFormat.cpp56
-rw-r--r--tools/clang-format/clang-format.py19
-rw-r--r--tools/clang-format/fuzzer/CMakeLists.txt6
-rw-r--r--tools/clang-format/fuzzer/ClangFormatFuzzer.cpp7
-rwxr-xr-xtools/clang-format/git-clang-format87
-rw-r--r--tools/clang-func-mapping/CMakeLists.txt22
-rw-r--r--tools/clang-func-mapping/ClangFnMapGen.cpp124
-rw-r--r--tools/clang-fuzzer/CMakeLists.txt81
-rw-r--r--tools/clang-fuzzer/ClangFuzzer.cpp32
-rw-r--r--tools/clang-fuzzer/Dockerfile37
-rw-r--r--tools/clang-fuzzer/DummyClangFuzzer.cpp21
-rw-r--r--tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp44
-rw-r--r--tools/clang-fuzzer/README.txt82
-rw-r--r--tools/clang-fuzzer/cxx_proto.proto93
-rw-r--r--tools/clang-fuzzer/handle-cxx/CMakeLists.txt12
-rw-r--r--tools/clang-fuzzer/handle-cxx/handle_cxx.cpp58
-rw-r--r--tools/clang-fuzzer/handle-cxx/handle_cxx.h25
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt14
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp102
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h22
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/proto_to_cxx_main.cpp30
-rw-r--r--tools/clang-import-test/CMakeLists.txt1
-rw-r--r--tools/clang-import-test/clang-import-test.cpp235
-rw-r--r--tools/clang-offload-bundler/ClangOffloadBundler.cpp9
-rw-r--r--tools/clang-refactor/CMakeLists.txt23
-rw-r--r--tools/clang-refactor/ClangRefactor.cpp577
-rw-r--r--tools/clang-refactor/TestSupport.cpp392
-rw-r--r--tools/clang-refactor/TestSupport.h107
-rw-r--r--tools/clang-refactor/ToolRefactoringResultConsumer.h48
-rw-r--r--tools/clang-rename/CMakeLists.txt22
-rw-r--r--tools/clang-rename/ClangRename.cpp233
-rw-r--r--tools/clang-rename/clang-rename.el79
-rw-r--r--tools/clang-rename/clang-rename.py61
-rw-r--r--tools/diagtool/CMakeLists.txt1
-rw-r--r--tools/diagtool/DiagnosticNames.cpp12
-rw-r--r--tools/diagtool/DiagnosticNames.h6
-rw-r--r--tools/diagtool/FindDiagnosticID.cpp74
-rw-r--r--tools/diagtool/ListWarnings.cpp56
-rw-r--r--tools/diagtool/ShowEnabledWarnings.cpp24
-rw-r--r--tools/diagtool/TreeView.cpp59
-rw-r--r--tools/driver/CMakeLists.txt2
-rw-r--r--tools/driver/cc1as_main.cpp36
-rw-r--r--tools/driver/driver.cpp104
-rw-r--r--tools/libclang/ARCMigrate.cpp5
-rw-r--r--tools/libclang/CIndex.cpp310
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp9
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp30
-rw-r--r--tools/libclang/CMakeLists.txt14
-rw-r--r--tools/libclang/CXCompilationDatabase.cpp31
-rw-r--r--tools/libclang/CXCursor.cpp26
-rw-r--r--tools/libclang/CXIndexDataConsumer.cpp6
-rw-r--r--tools/libclang/CXTranslationUnit.h4
-rw-r--r--tools/libclang/CXType.cpp74
-rw-r--r--tools/libclang/Indexing.cpp6
-rw-r--r--tools/libclang/libclang.exports14
-rw-r--r--tools/scan-build-py/libscanbuild/__init__.py6
-rw-r--r--tools/scan-build-py/libscanbuild/analyze.py313
-rw-r--r--tools/scan-build-py/libscanbuild/arguments.py5
-rw-r--r--tools/scan-build-py/libscanbuild/intercept.py4
-rw-r--r--tools/scan-build-py/libscanbuild/report.py37
-rw-r--r--tools/scan-build-py/libscanbuild/runner.py294
-rw-r--r--tools/scan-build-py/tests/unit/__init__.py2
-rw-r--r--tools/scan-build-py/tests/unit/test_analyze.py313
-rw-r--r--tools/scan-build-py/tests/unit/test_report.py2
-rw-r--r--tools/scan-build-py/tests/unit/test_runner.py321
-rw-r--r--tools/scan-build/CMakeLists.txt3
-rwxr-xr-xtools/scan-build/libexec/ccc-analyzer3
-rw-r--r--unittests/AST/ASTImporterTest.cpp53
-rw-r--r--unittests/AST/CMakeLists.txt1
-rw-r--r--unittests/AST/CommentLexer.cpp3
-rw-r--r--unittests/AST/DataCollectionTest.cpp173
-rw-r--r--unittests/AST/DeclPrinterTest.cpp2
-rw-r--r--unittests/AST/StmtPrinterTest.cpp74
-rw-r--r--unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp49
-rw-r--r--unittests/ASTMatchers/ASTMatchersNodeTest.cpp101
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h44
-rw-r--r--unittests/ASTMatchers/ASTMatchersTraversalTest.cpp43
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp28
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp43
-rw-r--r--unittests/ASTMatchers/Dynamic/VariantValueTest.cpp25
-rw-r--r--unittests/Analysis/CMakeLists.txt5
-rw-r--r--unittests/Analysis/CloneDetectionTest.cpp112
-rw-r--r--unittests/Basic/CMakeLists.txt1
-rw-r--r--unittests/Basic/DiagnosticTest.cpp59
-rw-r--r--unittests/Basic/FileManagerTest.cpp79
-rw-r--r--unittests/Basic/MemoryBufferCacheTest.cpp94
-rw-r--r--unittests/Basic/SourceManagerTest.cpp108
-rw-r--r--unittests/Basic/VirtualFileSystemTest.cpp42
-rw-r--r--unittests/CMakeLists.txt2
-rw-r--r--unittests/CodeGen/CMakeLists.txt4
-rw-r--r--unittests/CodeGen/CodeGenExternalTest.cpp302
-rw-r--r--unittests/CodeGen/IncrementalProcessingTest.cpp174
-rw-r--r--unittests/CrossTU/CMakeLists.txt16
-rw-r--r--unittests/CrossTU/CrossTranslationUnitTest.cpp158
-rw-r--r--unittests/Driver/CMakeLists.txt1
-rw-r--r--unittests/Driver/ToolChainTest.cpp126
-rw-r--r--unittests/Format/CMakeLists.txt3
-rw-r--r--unittests/Format/CleanupTest.cpp18
-rw-r--r--unittests/Format/FormatTest.cpp1706
-rw-r--r--unittests/Format/FormatTestComments.cpp532
-rw-r--r--unittests/Format/FormatTestJS.cpp507
-rw-r--r--unittests/Format/FormatTestJava.cpp32
-rw-r--r--unittests/Format/FormatTestObjC.cpp24
-rw-r--r--unittests/Format/FormatTestProto.cpp192
-rw-r--r--unittests/Format/FormatTestRawStrings.cpp733
-rw-r--r--unittests/Format/FormatTestSelective.cpp18
-rw-r--r--unittests/Format/FormatTestTextProto.cpp294
-rw-r--r--unittests/Format/FormatTestUtils.h3
-rw-r--r--unittests/Format/NamespaceEndCommentsFixerTest.cpp201
-rw-r--r--unittests/Format/SortImportsTestJS.cpp25
-rw-r--r--unittests/Format/SortIncludesTest.cpp34
-rw-r--r--unittests/Format/UsingDeclarationsSorterTest.cpp333
-rw-r--r--unittests/Frontend/ASTUnitTest.cpp87
-rw-r--r--unittests/Frontend/CMakeLists.txt4
-rw-r--r--unittests/Frontend/CodeGenActionTest.cpp2
-rw-r--r--unittests/Frontend/CompilerInstanceTest.cpp74
-rw-r--r--unittests/Frontend/FrontendActionTest.cpp21
-rw-r--r--unittests/Frontend/PCHPreambleTest.cpp200
-rw-r--r--unittests/Frontend/ParsedSourceLocationTest.cpp37
-rw-r--r--unittests/Lex/LexerTest.cpp150
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp30
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp24
-rw-r--r--unittests/Rename/CMakeLists.txt26
-rw-r--r--unittests/Rename/ClangRenameTest.h112
-rw-r--r--unittests/Rename/RenameAliasTest.cpp304
-rw-r--r--unittests/Rename/RenameClassTest.cpp799
-rw-r--r--unittests/Rename/RenameEnumTest.cpp189
-rw-r--r--unittests/Rename/RenameFunctionTest.cpp574
-rw-r--r--unittests/Rename/RenameMemberTest.cpp229
-rw-r--r--unittests/Tooling/ASTSelectionTest.cpp975
-rw-r--r--unittests/Tooling/CMakeLists.txt6
-rw-r--r--unittests/Tooling/CastExprTest.cpp38
-rw-r--r--unittests/Tooling/CommentHandlerTest.cpp3
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp53
-rw-r--r--unittests/Tooling/DiagnosticsYamlTest.cpp167
-rw-r--r--unittests/Tooling/ExecutionTest.cpp228
-rw-r--r--unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp227
-rw-r--r--unittests/Tooling/LookupTest.cpp6
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp152
-rw-r--r--unittests/Tooling/RefactoringActionRulesTest.cpp248
-rw-r--r--unittests/Tooling/RefactoringCallbacksTest.cpp91
-rw-r--r--unittests/Tooling/RefactoringTest.cpp457
-rw-r--r--unittests/Tooling/TestVisitor.h10
-rw-r--r--unittests/Tooling/ToolingTest.cpp2
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp829
-rw-r--r--utils/TableGen/ClangDataCollectorsEmitter.cpp18
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp4
-rw-r--r--utils/TableGen/ClangOptionDocEmitter.cpp13
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp3
-rw-r--r--utils/TableGen/TableGen.cpp37
-rw-r--r--utils/TableGen/TableGenBackends.h8
-rwxr-xr-xutils/analyzer/CmpRuns.py97
-rwxr-xr-xutils/analyzer/SATestAdd.py50
-rwxr-xr-xutils/analyzer/SATestBuild.py640
-rwxr-xr-xutils/analyzer/SATestUpdateDiffs.py73
-rw-r--r--utils/analyzer/SATestUtils.py100
-rw-r--r--utils/analyzer/SumTimerInfo.py78
-rwxr-xr-xutils/analyzer/ubiviz87
-rw-r--r--utils/bash-autocomplete.sh83
-rwxr-xr-xutils/clangdiag.py192
-rw-r--r--utils/perf-training/CMakeLists.txt12
-rw-r--r--utils/perf-training/lit.cfg3
-rw-r--r--utils/perf-training/order-files.lit.cfg3
-rw-r--r--www/analyzer/alpha_checks.html280
-rw-r--r--www/analyzer/available_checks.html323
-rw-r--r--www/analyzer/checker_dev_manual.html18
-rw-r--r--www/analyzer/implicit_checks.html4
-rw-r--r--www/analyzer/open_projects.html7
-rw-r--r--www/analyzer/scripts/expandcollapse.js2
-rw-r--r--www/cxx_dr_status.html740
-rw-r--r--www/cxx_status.html131
-rw-r--r--www/get_started.html4
-rw-r--r--www/hacking.html4
-rw-r--r--www/index.html44
-rwxr-xr-xwww/make_cxx_dr_status5
-rwxr-xr-x[-rw-r--r--]www/menu.html.incl4
3026 files changed, 180050 insertions, 53863 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a095d2b865..42d580077d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -181,9 +181,14 @@ endif()
# we can include cmake files from this directory.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
-find_package(LibXml2 2.5.3 QUIET)
-if (LIBXML2_FOUND)
- set(CLANG_HAVE_LIBXML 1)
+# Don't look for libxml if we're using MSan, since uninstrumented third party
+# code may call MSan interceptors like strlen, leading to false positives.
+if(NOT LLVM_USE_SANITIZER MATCHES "Memory.*")
+ set (LIBXML2_FOUND 0)
+ find_package(LibXml2 2.5.3 QUIET)
+ if (LIBXML2_FOUND)
+ set(CLANG_HAVE_LIBXML 1)
+ endif()
endif()
include(CheckIncludeFile)
@@ -230,6 +235,17 @@ endif()
set(CLANG_DEFAULT_OPENMP_RUNTIME "libomp" CACHE STRING
"Default OpenMP runtime used by -fopenmp.")
+# OpenMP offloading requires at least sm_30 because we use shuffle instructions
+# to generate efficient code for reductions.
+set(CLANG_OPENMP_NVPTX_DEFAULT_ARCH "sm_30" CACHE STRING
+ "Default architecture for OpenMP offloading to Nvidia GPUs.")
+string(REGEX MATCH "^sm_([0-9]+)$" MATCHED_ARCH "${CLANG_OPENMP_NVPTX_DEFAULT_ARCH}")
+if (NOT DEFINED MATCHED_ARCH OR "${CMAKE_MATCH_1}" LESS 30)
+ message(WARNING "Resetting default architecture for OpenMP offloading to Nvidia GPUs to sm_30")
+ set(CLANG_OPENMP_NVPTX_DEFAULT_ARCH "sm_30" CACHE STRING
+ "Default architecture for OpenMP offloading to Nvidia GPUs." FORCE)
+endif()
+
set(CLANG_VENDOR ${PACKAGE_VENDOR} CACHE STRING
"Vendor-specific text for showing with version information.")
@@ -330,10 +346,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)
@@ -361,6 +373,10 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
PATTERN "*.inc"
PATTERN "*.h"
)
+
+ install(PROGRAMS utils/bash-autocomplete.sh
+ DESTINATION share/clang
+ )
endif()
add_definitions( -D_GNU_SOURCE )
@@ -371,16 +387,26 @@ option(CLANG_BUILD_TOOLS
option(CLANG_ENABLE_ARCMT "Build ARCMT." ON)
option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
-if (NOT CLANG_ENABLE_STATIC_ANALYZER AND CLANG_ENABLE_ARCMT)
- message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT")
+option(CLANG_ANALYZER_BUILD_Z3
+ "Build the static analyzer with the Z3 constraint manager." OFF)
+
+option(CLANG_ENABLE_PROTO_FUZZER "Build Clang protobuf fuzzer." 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(CLANG_ENABLE_ARCMT)
- add_definitions(-DCLANG_ENABLE_ARCMT)
- add_definitions(-DCLANG_ENABLE_OBJC_REWRITER)
+if(CLANG_ANALYZER_BUILD_Z3)
+ find_package(Z3 4.5)
+ 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_STATIC_ANALYZER)
- add_definitions(-DCLANG_ENABLE_STATIC_ANALYZER)
+
+if(CLANG_ENABLE_ARCMT)
+ set(CLANG_ENABLE_OBJC_REWRITER ON)
endif()
# Clang version information
@@ -402,7 +428,15 @@ add_subdirectory(include)
# All targets below may depend on all tablegen'd files.
get_property(CLANG_TABLEGEN_TARGETS GLOBAL PROPERTY CLANG_TABLEGEN_TARGETS)
-list(APPEND LLVM_COMMON_DEPENDS ${CLANG_TABLEGEN_TARGETS})
+add_custom_target(clang-tablegen-targets DEPENDS ${CLANG_TABLEGEN_TARGETS})
+list(APPEND LLVM_COMMON_DEPENDS clang-tablegen-targets)
+
+# Force target to be built as soon as possible. Clang modules builds depend
+# header-wise on it as they ship all headers from the umbrella folders. Building
+# an entire module might include header, which depends on intrinsics_gen.
+if(LLVM_ENABLE_MODULES AND NOT CLANG_BUILT_STANDALONE)
+ list(APPEND LLVM_COMMON_DEPENDS intrinsics_gen)
+endif()
add_subdirectory(lib)
add_subdirectory(tools)
@@ -570,10 +604,17 @@ if (CLANG_ENABLE_BOOTSTRAP)
add_dependencies(clang-bootstrap-deps compiler-rt)
endif()
+ set(C_COMPILER "clang")
+ set(CXX_COMPILER "clang++")
+ if(WIN32)
+ set(C_COMPILER "clang-cl.exe")
+ set(CXX_COMPILER "clang-cl.exe")
+ endif()
+
set(COMPILER_OPTIONS
- -DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++
- -DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang
- -DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
+ -DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${CXX_COMPILER}
+ -DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${C_COMPILER}
+ -DCMAKE_ASM_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/${C_COMPILER})
if(BOOTSTRAP_LLVM_BUILD_INSTRUMENTED)
add_dependencies(clang-bootstrap-deps llvm-profdata)
@@ -687,3 +728,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/README.txt b/README.txt
index ada9ebc9e2..b5f33bb66d 100644
--- a/README.txt
+++ b/README.txt
@@ -13,10 +13,10 @@ different source-level tools. One example of this is the Clang Static Analyzer.
If you're interested in more (including how to build Clang) it is best to read
the relevant web sites. Here are some pointers:
-Information on Clang: http://clang.llvm.org/
-Building and using Clang: http://clang.llvm.org/get_started.html
-Clang Static Analyzer: http://clang-analyzer.llvm.org/
-Information on the LLVM project: http://llvm.org/
+Information on Clang: http://clang.llvm.org/
+Building and using Clang: http://clang.llvm.org/get_started.html
+Clang Static Analyzer: http://clang-analyzer.llvm.org/
+Information on the LLVM project: http://llvm.org/
If you have questions or comments about Clang, a great place to discuss them is
on the Clang development mailing list:
@@ -24,3 +24,4 @@ on the Clang development mailing list:
If you find a bug in Clang, please file it in the LLVM bug tracker:
http://llvm.org/bugs/
+
diff --git a/bindings/python/clang/__init__.py b/bindings/python/clang/__init__.py
index fba49e38c9..88f3081238 100644
--- a/bindings/python/clang/__init__.py
+++ b/bindings/python/clang/__init__.py
@@ -20,13 +20,5 @@ The available modules are:
Bindings for the Clang indexing library.
"""
-
-# Python 3 uses unicode for strings. The bindings, in particular the interaction
-# with ctypes, need modifying to handle conversions between unicode and
-# c-strings.
-import sys
-if sys.version_info[0] != 2:
- raise Exception("Only Python 2 is supported.")
-
__all__ = ['cindex']
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 48fc8b13a2..d72dd14ef9 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -67,6 +67,63 @@ import collections
import clang.enumerations
+import sys
+if sys.version_info[0] == 3:
+ # Python 3 strings are unicode, translate them to/from utf8 for C-interop.
+ class c_interop_string(c_char_p):
+
+ def __init__(self, p=None):
+ if p is None:
+ p = ""
+ if isinstance(p, str):
+ p = p.encode("utf8")
+ super(c_char_p, self).__init__(p)
+
+ def __str__(self):
+ return self.value
+
+ @property
+ def value(self):
+ if super(c_char_p, self).value is None:
+ return None
+ return super(c_char_p, self).value.decode("utf8")
+
+ @classmethod
+ def from_param(cls, param):
+ if isinstance(param, str):
+ return cls(param)
+ if isinstance(param, bytes):
+ return cls(param)
+ if param is None:
+ # Support passing null to C functions expecting char arrays
+ return None
+ raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__))
+
+ @staticmethod
+ def to_python_string(x, *args):
+ return x.value
+
+ def b(x):
+ if isinstance(x, bytes):
+ return x
+ return x.encode('utf8')
+
+ xrange = range
+
+elif sys.version_info[0] == 2:
+ # Python 2 strings are utf8 byte strings, no translation is needed for
+ # C-interop.
+ c_interop_string = c_char_p
+
+ def _to_python_string(x, *args):
+ return x
+
+ c_interop_string.to_python_string = staticmethod(_to_python_string)
+
+ def b(x):
+ return x
+
+
# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
# object. This is a problem, because it means that from_parameter will see an
# integer and pass the wrong value on platforms where int != void*. Work around
@@ -153,10 +210,11 @@ class _CXString(Structure):
conf.lib.clang_disposeString(self)
@staticmethod
- def from_result(res, fn, args):
+ def from_result(res, fn=None, args=None):
assert isinstance(res, _CXString)
return conf.lib.clang_getCString(res)
+
class SourceLocation(Structure):
"""
A SourceLocation represents a particular location within a source file.
@@ -404,8 +462,7 @@ class Diagnostic(object):
"""The command-line option that disables this diagnostic."""
disable = _CXString()
conf.lib.clang_getDiagnosticOption(self, byref(disable))
-
- return conf.lib.clang_getCString(disable)
+ return _CXString.from_result(disable)
def format(self, options=None):
"""
@@ -418,8 +475,7 @@ class Diagnostic(object):
options = conf.lib.clang_defaultDiagnosticDisplayOptions()
if options & ~Diagnostic._FormatOptionsMask:
raise ValueError('Invalid format options')
- formatted = conf.lib.clang_formatDiagnostic(self, options)
- return conf.lib.clang_getCString(formatted)
+ return conf.lib.clang_formatDiagnostic(self, options)
def __repr__(self):
return "<Diagnostic severity %r, location %r, spelling %r>" % (
@@ -596,7 +652,7 @@ class CursorKind(BaseEnumeration):
@staticmethod
def get_all_kinds():
"""Return all CursorKind enumeration instances."""
- return filter(None, CursorKind._kinds)
+ return [x for x in CursorKind._kinds if not x is None]
def is_declaration(self):
"""Test if this is a declaration kind."""
@@ -727,7 +783,7 @@ CursorKind.CONVERSION_FUNCTION = CursorKind(26)
# A C++ template type parameter
CursorKind.TEMPLATE_TYPE_PARAMETER = CursorKind(27)
-# A C++ non-type template paramater.
+# A C++ non-type template parameter.
CursorKind.TEMPLATE_NON_TYPE_PARAMETER = CursorKind(28)
# A C++ template template parameter.
@@ -1312,6 +1368,30 @@ TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2)
TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3)
TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4)
+### Exception Specification Kinds ###
+class ExceptionSpecificationKind(BaseEnumeration):
+ """
+ An ExceptionSpecificationKind describes the kind of exception specification
+ that a function has.
+ """
+
+ # The required BaseEnumeration declarations.
+ _kinds = []
+ _name_map = None
+
+ def __repr__(self):
+ return 'ExceptionSpecificationKind.{}'.format(self.name)
+
+ExceptionSpecificationKind.NONE = ExceptionSpecificationKind(0)
+ExceptionSpecificationKind.DYNAMIC_NONE = ExceptionSpecificationKind(1)
+ExceptionSpecificationKind.DYNAMIC = ExceptionSpecificationKind(2)
+ExceptionSpecificationKind.MS_ANY = ExceptionSpecificationKind(3)
+ExceptionSpecificationKind.BASIC_NOEXCEPT = ExceptionSpecificationKind(4)
+ExceptionSpecificationKind.COMPUTED_NOEXCEPT = ExceptionSpecificationKind(5)
+ExceptionSpecificationKind.UNEVALUATED = ExceptionSpecificationKind(6)
+ExceptionSpecificationKind.UNINSTANTIATED = ExceptionSpecificationKind(7)
+ExceptionSpecificationKind.UNPARSED = ExceptionSpecificationKind(8)
+
### Cursors ###
class Cursor(Structure):
@@ -1399,6 +1479,11 @@ class Cursor(Structure):
"""
return conf.lib.clang_CXXMethod_isVirtual(self)
+ def is_scoped_enum(self):
+ """Returns True if the cursor refers to a scoped enum declaration.
+ """
+ return conf.lib.clang_EnumDecl_isScoped(self)
+
def get_definition(self):
"""
If the cursor is a reference to a declaration or a declaration of
@@ -1467,6 +1552,22 @@ class Cursor(Structure):
return self._loc
@property
+ def linkage(self):
+ """Return the linkage of this cursor."""
+ if not hasattr(self, '_linkage'):
+ self._linkage = conf.lib.clang_getCursorLinkage(self)
+
+ return LinkageKind.from_id(self._linkage)
+
+ @property
+ def tls_kind(self):
+ """Return the thread-local storage (TLS) kind of this cursor."""
+ if not hasattr(self, '_tls_kind'):
+ self._tls_kind = conf.lib.clang_getCursorTLSKind(self)
+
+ return TLSKind.from_id(self._tls_kind)
+
+ @property
def extent(self):
"""
Return the source range (the range of text) occupied by the entity
@@ -1489,6 +1590,16 @@ class Cursor(Structure):
return StorageClass.from_id(self._storage_class)
@property
+ def availability(self):
+ """
+ Retrieves the availability of the entity pointed at by the cursor.
+ """
+ if not hasattr(self, '_availability'):
+ self._availability = conf.lib.clang_getCursorAvailability(self)
+
+ return AvailabilityKind.from_id(self._availability)
+
+ @property
def access_specifier(self):
"""
Retrieves the access specifier (if any) of the entity pointed at by the
@@ -1532,6 +1643,18 @@ class Cursor(Structure):
return self._result_type
@property
+ def exception_specification_kind(self):
+ '''
+ Retrieve the exception specification kind, which is one of the values
+ from the ExceptionSpecificationKind enumeration.
+ '''
+ if not hasattr(self, '_exception_specification_kind'):
+ exc_kind = conf.lib.clang_getCursorExceptionSpecificationType(self)
+ self._exception_specification_kind = ExceptionSpecificationKind.from_id(exc_kind)
+
+ return self._exception_specification_kind
+
+ @property
def underlying_typedef_type(self):
"""Return the underlying type of a typedef declaration.
@@ -1813,6 +1936,24 @@ StorageClass.OPENCLWORKGROUPLOCAL = StorageClass(5)
StorageClass.AUTO = StorageClass(6)
StorageClass.REGISTER = StorageClass(7)
+### Availability Kinds ###
+
+class AvailabilityKind(BaseEnumeration):
+ """
+ Describes the availability of an entity.
+ """
+
+ # The unique kind objects, indexed by id.
+ _kinds = []
+ _name_map = None
+
+ def __repr__(self):
+ return 'AvailabilityKind.%s' % (self.name,)
+
+AvailabilityKind.AVAILABLE = AvailabilityKind(0)
+AvailabilityKind.DEPRECATED = AvailabilityKind(1)
+AvailabilityKind.NOT_AVAILABLE = AvailabilityKind(2)
+AvailabilityKind.NOT_ACCESSIBLE = AvailabilityKind(3)
### C++ access specifiers ###
@@ -1908,6 +2049,47 @@ TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
TypeKind.MEMBERPOINTER = TypeKind(117)
TypeKind.AUTO = TypeKind(118)
TypeKind.ELABORATED = TypeKind(119)
+TypeKind.PIPE = TypeKind(120)
+TypeKind.OCLIMAGE1DRO = TypeKind(121)
+TypeKind.OCLIMAGE1DARRAYRO = TypeKind(122)
+TypeKind.OCLIMAGE1DBUFFERRO = TypeKind(123)
+TypeKind.OCLIMAGE2DRO = TypeKind(124)
+TypeKind.OCLIMAGE2DARRAYRO = TypeKind(125)
+TypeKind.OCLIMAGE2DDEPTHRO = TypeKind(126)
+TypeKind.OCLIMAGE2DARRAYDEPTHRO = TypeKind(127)
+TypeKind.OCLIMAGE2DMSAARO = TypeKind(128)
+TypeKind.OCLIMAGE2DARRAYMSAARO = TypeKind(129)
+TypeKind.OCLIMAGE2DMSAADEPTHRO = TypeKind(130)
+TypeKind.OCLIMAGE2DARRAYMSAADEPTHRO = TypeKind(131)
+TypeKind.OCLIMAGE3DRO = TypeKind(132)
+TypeKind.OCLIMAGE1DWO = TypeKind(133)
+TypeKind.OCLIMAGE1DARRAYWO = TypeKind(134)
+TypeKind.OCLIMAGE1DBUFFERWO = TypeKind(135)
+TypeKind.OCLIMAGE2DWO = TypeKind(136)
+TypeKind.OCLIMAGE2DARRAYWO = TypeKind(137)
+TypeKind.OCLIMAGE2DDEPTHWO = TypeKind(138)
+TypeKind.OCLIMAGE2DARRAYDEPTHWO = TypeKind(139)
+TypeKind.OCLIMAGE2DMSAAWO = TypeKind(140)
+TypeKind.OCLIMAGE2DARRAYMSAAWO = TypeKind(141)
+TypeKind.OCLIMAGE2DMSAADEPTHWO = TypeKind(142)
+TypeKind.OCLIMAGE2DARRAYMSAADEPTHWO = TypeKind(143)
+TypeKind.OCLIMAGE3DWO = TypeKind(144)
+TypeKind.OCLIMAGE1DRW = TypeKind(145)
+TypeKind.OCLIMAGE1DARRAYRW = TypeKind(146)
+TypeKind.OCLIMAGE1DBUFFERRW = TypeKind(147)
+TypeKind.OCLIMAGE2DRW = TypeKind(148)
+TypeKind.OCLIMAGE2DARRAYRW = TypeKind(149)
+TypeKind.OCLIMAGE2DDEPTHRW = TypeKind(150)
+TypeKind.OCLIMAGE2DARRAYDEPTHRW = TypeKind(151)
+TypeKind.OCLIMAGE2DMSAARW = TypeKind(152)
+TypeKind.OCLIMAGE2DARRAYMSAARW = TypeKind(153)
+TypeKind.OCLIMAGE2DMSAADEPTHRW = TypeKind(154)
+TypeKind.OCLIMAGE2DARRAYMSAADEPTHRW = TypeKind(155)
+TypeKind.OCLIMAGE3DRW = TypeKind(156)
+TypeKind.OCLSAMPLER = TypeKind(157)
+TypeKind.OCLEVENT = TypeKind(158)
+TypeKind.OCLQUEUE = TypeKind(159)
+TypeKind.OCLRESERVEID = TypeKind(160)
class RefQualifierKind(BaseEnumeration):
"""Describes a specific ref-qualifier of a type."""
@@ -1926,6 +2108,42 @@ RefQualifierKind.NONE = RefQualifierKind(0)
RefQualifierKind.LVALUE = RefQualifierKind(1)
RefQualifierKind.RVALUE = RefQualifierKind(2)
+class LinkageKind(BaseEnumeration):
+ """Describes the kind of linkage of a cursor."""
+
+ # The unique kind objects, indexed by id.
+ _kinds = []
+ _name_map = None
+
+ def from_param(self):
+ return self.value
+
+ def __repr__(self):
+ return 'LinkageKind.%s' % (self.name,)
+
+LinkageKind.INVALID = LinkageKind(0)
+LinkageKind.NO_LINKAGE = LinkageKind(1)
+LinkageKind.INTERNAL = LinkageKind(2)
+LinkageKind.UNIQUE_EXTERNAL = LinkageKind(3)
+LinkageKind.EXTERNAL = LinkageKind(4)
+
+class TLSKind(BaseEnumeration):
+ """Describes the kind of thread-local storage (TLS) of a cursor."""
+
+ # The unique kind objects, indexed by id.
+ _kinds = []
+ _name_map = None
+
+ def from_param(self):
+ return self.value
+
+ def __repr__(self):
+ return 'TLSKind.%s' % (self.name,)
+
+TLSKind.NONE = TLSKind(0)
+TLSKind.DYNAMIC = TLSKind(1)
+TLSKind.STATIC = TLSKind(2)
+
class Type(Structure):
"""
The type of an element in the abstract syntax tree.
@@ -2066,6 +2284,12 @@ class Type(Structure):
return conf.lib.clang_isFunctionTypeVariadic(self)
+ def get_address_space(self):
+ return conf.lib.clang_getAddressSpace(self)
+
+ def get_typedef_name(self):
+ return conf.lib.clang_getTypedefName(self)
+
def is_pod(self):
"""Determine whether this Type represents plain old data (POD)."""
return conf.lib.clang_isPODType(self)
@@ -2128,7 +2352,7 @@ class Type(Structure):
"""
Retrieve the offset of a field in the record.
"""
- return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname))
+ return conf.lib.clang_Type_getOffsetOf(self, fieldname)
def get_ref_qualifier(self):
"""
@@ -2152,6 +2376,14 @@ class Type(Structure):
callbacks['fields_visit'](visitor), fields)
return iter(fields)
+ def get_exception_specification_kind(self):
+ """
+ Return the kind of the exception specification; a value from
+ the ExceptionSpecificationKind enumeration.
+ """
+ return ExceptionSpecificationKind.from_id(
+ conf.lib.clang.getExceptionSpecificationType(self))
+
@property
def spelling(self):
"""Retrieve the spelling of this Type."""
@@ -2239,7 +2471,7 @@ class CompletionChunk:
def spelling(self):
if self.__kindNumber in SpellingCache:
return SpellingCache[self.__kindNumber]
- return conf.lib.clang_getCompletionChunkText(self.cs, self.key).spelling
+ return conf.lib.clang_getCompletionChunkText(self.cs, self.key)
# We do not use @CachedProperty here, as the manual implementation is
# apparently still significantly faster. Please profile carefully if you
@@ -2345,7 +2577,7 @@ class CompletionString(ClangObject):
return " | ".join([str(a) for a in self]) \
+ " || Priority: " + str(self.priority) \
+ " || Availability: " + str(self.availability) \
- + " || Brief comment: " + str(self.briefComment.spelling)
+ + " || Brief comment: " + str(self.briefComment)
availabilityKinds = {
0: CompletionChunk.Kind("Available"),
@@ -2542,7 +2774,7 @@ class TranslationUnit(ClangObject):
args_array = None
if len(args) > 0:
- args_array = (c_char_p * len(args))(* args)
+ args_array = (c_char_p * len(args))(*[b(x) for x in args])
unsaved_array = None
if len(unsaved_files) > 0:
@@ -2551,8 +2783,8 @@ class TranslationUnit(ClangObject):
if hasattr(contents, "read"):
contents = contents.read()
- unsaved_array[i].name = name
- unsaved_array[i].contents = contents
+ unsaved_array[i].name = b(name)
+ unsaved_array[i].contents = b(contents)
unsaved_array[i].length = len(contents)
ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array,
@@ -2797,8 +3029,8 @@ class TranslationUnit(ClangObject):
print(value)
if not isinstance(value, str):
raise TypeError('Unexpected unsaved file contents.')
- unsaved_files_array[i].name = name
- unsaved_files_array[i].contents = value
+ unsaved_files_array[i].name = b(name)
+ unsaved_files_array[i].contents = b(value)
unsaved_files_array[i].length = len(value)
ptr = conf.lib.clang_codeCompleteAt(self, path, line, column,
unsaved_files_array, len(unsaved_files), options)
@@ -2833,7 +3065,7 @@ class File(ClangObject):
@property
def name(self):
"""Return the complete file and path name of the file."""
- return conf.lib.clang_getCString(conf.lib.clang_getFileName(self))
+ return conf.lib.clang_getFileName(self)
@property
def time(self):
@@ -3042,6 +3274,7 @@ class Token(Structure):
def cursor(self):
"""The Cursor this Token corresponds to."""
cursor = Cursor()
+ cursor._tu = self._tu
conf.lib.clang_annotateTokens(self._tu, byref(self), 1, byref(cursor))
@@ -3064,7 +3297,7 @@ functionList = [
[c_object_p]),
("clang_CompilationDatabase_fromDirectory",
- [c_char_p, POINTER(c_uint)],
+ [c_interop_string, POINTER(c_uint)],
c_object_p,
CompilationDatabase.from_result),
@@ -3074,7 +3307,7 @@ functionList = [
CompileCommands.from_result),
("clang_CompilationDatabase_getCompileCommands",
- [c_object_p, c_char_p],
+ [c_object_p, c_interop_string],
c_object_p,
CompileCommands.from_result),
@@ -3109,7 +3342,7 @@ functionList = [
c_uint),
("clang_codeCompleteAt",
- [TranslationUnit, c_char_p, c_int, c_int, c_void_p, c_int, c_int],
+ [TranslationUnit, c_interop_string, c_int, c_int, c_void_p, c_int, c_int],
POINTER(CCRStructure)),
("clang_codeCompleteGetDiagnostic",
@@ -3125,7 +3358,7 @@ functionList = [
c_object_p),
("clang_createTranslationUnit",
- [Index, c_char_p],
+ [Index, c_interop_string],
c_object_p),
("clang_CXXConstructor_isConvertingConstructor",
@@ -3168,6 +3401,10 @@ functionList = [
[Cursor],
bool),
+ ("clang_EnumDecl_isScoped",
+ [Cursor],
+ bool),
+
("clang_defaultDiagnosticDisplayOptions",
[],
c_uint),
@@ -3215,7 +3452,8 @@ functionList = [
("clang_formatDiagnostic",
[Diagnostic, c_uint],
- _CXString),
+ _CXString,
+ _CXString.from_result),
("clang_getArgType",
[Type, c_uint],
@@ -3255,7 +3493,8 @@ functionList = [
("clang_getCompletionBriefComment",
[c_void_p],
- _CXString),
+ _CXString,
+ _CXString.from_result),
("clang_getCompletionChunkCompletionString",
[c_void_p, c_int],
@@ -3267,7 +3506,8 @@ functionList = [
("clang_getCompletionChunkText",
[c_void_p, c_int],
- _CXString),
+ _CXString,
+ _CXString.from_result),
("clang_getCompletionPriority",
[c_void_p],
@@ -3275,12 +3515,17 @@ functionList = [
("clang_getCString",
[_CXString],
- c_char_p),
+ c_interop_string,
+ c_interop_string.to_python_string),
("clang_getCursor",
[TranslationUnit, SourceLocation],
Cursor),
+ ("clang_getCursorAvailability",
+ [Cursor],
+ c_int),
+
("clang_getCursorDefinition",
[Cursor],
Cursor,
@@ -3422,12 +3667,13 @@ functionList = [
Type.from_result),
("clang_getFile",
- [TranslationUnit, c_char_p],
+ [TranslationUnit, c_interop_string],
c_object_p),
("clang_getFileName",
[File],
- _CXString), # TODO go through _CXString.from_result?
+ _CXString,
+ _CXString.from_result),
("clang_getFileTime",
[File],
@@ -3551,7 +3797,8 @@ functionList = [
("clang_getTUResourceUsageName",
[c_uint],
- c_char_p),
+ c_interop_string,
+ c_interop_string.to_python_string),
("clang_getTypeDeclaration",
[Type],
@@ -3563,6 +3810,11 @@ functionList = [
Type,
Type.from_result),
+ ("clang_getTypedefName",
+ [Type],
+ _CXString,
+ _CXString.from_result),
+
("clang_getTypeKindSpelling",
[c_uint],
_CXString,
@@ -3646,7 +3898,7 @@ functionList = [
bool),
("clang_parseTranslationUnit",
- [Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int],
+ [Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int],
c_object_p),
("clang_reparseTranslationUnit",
@@ -3654,7 +3906,7 @@ functionList = [
c_int),
("clang_saveTranslationUnit",
- [TranslationUnit, c_char_p, c_uint],
+ [TranslationUnit, c_interop_string, c_uint],
c_int),
("clang_tokenize",
@@ -3726,7 +3978,7 @@ functionList = [
Type.from_result),
("clang_Type_getOffsetOf",
- [Type, c_char_p],
+ [Type, c_interop_string],
c_longlong),
("clang_Type_getSizeOf",
@@ -3785,7 +4037,8 @@ def register_functions(lib, ignore_errors):
def register(item):
return register_function(lib, item, ignore_errors)
- map(register, functionList)
+ for f in functionList:
+ register(f)
class Config:
library_path = None
@@ -3888,6 +4141,7 @@ conf = Config()
register_enumerations()
__all__ = [
+ 'AvailabilityKind',
'Config',
'CodeCompletionResults',
'CompilationDatabase',
@@ -3899,8 +4153,10 @@ __all__ = [
'File',
'FixIt',
'Index',
+ 'LinkageKind',
'SourceLocation',
'SourceRange',
+ 'TLSKind',
'TokenKind',
'Token',
'TranslationUnitLoadError',
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index 8103e96df4..8ff0695154 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -1,6 +1,7 @@
import ctypes
import gc
+from clang.cindex import AvailabilityKind
from clang.cindex import CursorKind
from clang.cindex import TemplateArgumentKind
from clang.cindex import TranslationUnit
@@ -255,6 +256,22 @@ def test_is_virtual_method():
assert foo.is_virtual_method()
assert not bar.is_virtual_method()
+def test_is_scoped_enum():
+ """Ensure Cursor.is_scoped_enum works."""
+ source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
+ tu = get_tu(source, lang='cpp')
+
+ cls = get_cursor(tu, 'X')
+ regular_enum = get_cursor(tu, 'RegularEnum')
+ scoped_enum = get_cursor(tu, 'ScopedEnum')
+ assert cls is not None
+ assert regular_enum is not None
+ assert scoped_enum is not None
+
+ assert not cls.is_scoped_enum()
+ assert not regular_enum.is_scoped_enum()
+ assert scoped_enum.is_scoped_enum()
+
def test_underlying_type():
tu = get_tu('typedef int foo;')
typedef = get_cursor(tu, 'foo')
@@ -361,6 +378,26 @@ def test_annotation_attribute():
else:
assert False, "Couldn't find annotation"
+def test_annotation_template():
+ annotation = '__attribute__ ((annotate("annotation")))'
+ for source, kind in [
+ ('int foo (T value) %s;', CursorKind.FUNCTION_TEMPLATE),
+ ('class %s foo {};', CursorKind.CLASS_TEMPLATE),
+ ]:
+ source = 'template<typename T> ' + (source % annotation)
+ tu = get_tu(source, lang="cpp")
+
+ foo = get_cursor(tu, 'foo')
+ assert foo is not None
+ assert foo.kind == kind
+
+ for c in foo.get_children():
+ if c.kind == CursorKind.ANNOTATE_ATTR:
+ assert c.displayname == "annotation"
+ break
+ else:
+ assert False, "Couldn't find annotation for {}".format(kind)
+
def test_result_type():
tu = get_tu('int foo();')
foo = get_cursor(tu, 'foo')
@@ -369,6 +406,30 @@ def test_result_type():
t = foo.result_type
assert t.kind == TypeKind.INT
+def test_availability():
+ tu = get_tu('class A { A(A const&) = delete; };', lang='cpp')
+
+ # AvailabilityKind.AVAILABLE
+ cursor = get_cursor(tu, 'A')
+ assert cursor.kind == CursorKind.CLASS_DECL
+ assert cursor.availability == AvailabilityKind.AVAILABLE
+
+ # AvailabilityKind.NOT_AVAILABLE
+ cursors = get_cursors(tu, 'A')
+ for c in cursors:
+ if c.kind == CursorKind.CONSTRUCTOR:
+ assert c.availability == AvailabilityKind.NOT_AVAILABLE
+ break
+ else:
+ assert False, "Could not find cursor for deleted constructor"
+
+ # AvailabilityKind.DEPRECATED
+ tu = get_tu('void test() __attribute__((deprecated));', lang='cpp')
+ cursor = get_cursor(tu, 'test')
+ assert cursor.availability == AvailabilityKind.DEPRECATED
+
+ # AvailabilityKind.NOT_ACCESSIBLE is only used in the code completion results
+
def test_get_tokens():
"""Ensure we can map cursors back to tokens."""
tu = get_tu('int foo(int i);')
@@ -379,6 +440,28 @@ def test_get_tokens():
assert tokens[0].spelling == 'int'
assert tokens[1].spelling == 'foo'
+def test_get_token_cursor():
+ """Ensure we can map tokens to cursors."""
+ tu = get_tu('class A {}; int foo(A var = A());', lang='cpp')
+ foo = get_cursor(tu, 'foo')
+
+ for cursor in foo.walk_preorder():
+ if cursor.kind.is_expression() and not cursor.kind.is_statement():
+ break
+ else:
+ assert False, "Could not find default value expression"
+
+ tokens = list(cursor.get_tokens())
+ assert len(tokens) == 4, [t.spelling for t in tokens]
+ assert tokens[0].spelling == '='
+ assert tokens[1].spelling == 'A'
+ assert tokens[2].spelling == '('
+ assert tokens[3].spelling == ')'
+ t_cursor = tokens[1].cursor
+ assert t_cursor.kind == CursorKind.TYPE_REF
+ r_cursor = t_cursor.referenced # should not raise an exception
+ assert r_cursor.kind == CursorKind.CLASS_DECL
+
def test_get_arguments():
tu = get_tu('void foo(int i, int j);')
foo = get_cursor(tu, 'foo')
diff --git a/bindings/python/tests/cindex/test_diagnostics.py b/bindings/python/tests/cindex/test_diagnostics.py
index ba6e545e8b..23cbe89f65 100644
--- a/bindings/python/tests/cindex/test_diagnostics.py
+++ b/bindings/python/tests/cindex/test_diagnostics.py
@@ -92,3 +92,11 @@ def test_diagnostic_children():
assert children[0].spelling.endswith('declared here')
assert children[0].location.line == 1
assert children[0].location.column == 1
+
+def test_diagnostic_string_repr():
+ tu = get_tu('struct MissingSemicolon{}')
+ assert len(tu.diagnostics) == 1
+ d = tu.diagnostics[0]
+
+ assert repr(d) == '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">'
+
diff --git a/bindings/python/tests/cindex/test_exception_specification_kind.py b/bindings/python/tests/cindex/test_exception_specification_kind.py
new file mode 100644
index 0000000000..543d47f7db
--- /dev/null
+++ b/bindings/python/tests/cindex/test_exception_specification_kind.py
@@ -0,0 +1,27 @@
+import clang.cindex
+from clang.cindex import ExceptionSpecificationKind
+from .util import get_tu
+
+
+def find_function_declarations(node, declarations=[]):
+ if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
+ declarations.append((node.spelling, node.exception_specification_kind))
+ for child in node.get_children():
+ declarations = find_function_declarations(child, declarations)
+ return declarations
+
+
+def test_exception_specification_kind():
+ source = """int square1(int x);
+ int square2(int x) noexcept;
+ int square3(int x) noexcept(noexcept(x * x));"""
+
+ tu = get_tu(source, lang='cpp', flags=['-std=c++14'])
+
+ declarations = find_function_declarations(tu.cursor)
+ expected = [
+ ('square1', ExceptionSpecificationKind.NONE),
+ ('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT),
+ ('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT)
+ ]
+ assert declarations == expected
diff --git a/bindings/python/tests/cindex/test_index.py b/bindings/python/tests/cindex/test_index.py
index dc173f04d2..ef76692a52 100644
--- a/bindings/python/tests/cindex/test_index.py
+++ b/bindings/python/tests/cindex/test_index.py
@@ -13,3 +13,5 @@ def test_parse():
assert isinstance(index, Index)
tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
assert isinstance(tu, TranslationUnit)
+ tu = index.parse(None, ['-c', os.path.join(kInputsDir, 'hello.cpp')])
+ assert isinstance(tu, TranslationUnit)
diff --git a/bindings/python/tests/cindex/test_linkage.py b/bindings/python/tests/cindex/test_linkage.py
new file mode 100644
index 0000000000..2f056d5140
--- /dev/null
+++ b/bindings/python/tests/cindex/test_linkage.py
@@ -0,0 +1,30 @@
+
+from clang.cindex import LinkageKind
+from clang.cindex import Cursor
+from clang.cindex import TranslationUnit
+
+from .util import get_cursor
+from .util import get_tu
+
+def test_linkage():
+ """Ensure that linkage specifers are available on cursors"""
+
+ tu = get_tu("""
+void foo() { int no_linkage; }
+static int internal;
+namespace { extern int unique_external; }
+extern int external;
+""", lang = 'cpp')
+
+ no_linkage = get_cursor(tu.cursor, 'no_linkage')
+ assert no_linkage.linkage == LinkageKind.NO_LINKAGE;
+
+ internal = get_cursor(tu.cursor, 'internal')
+ assert internal.linkage == LinkageKind.INTERNAL
+
+ unique_external = get_cursor(tu.cursor, 'unique_external')
+ assert unique_external.linkage == LinkageKind.UNIQUE_EXTERNAL
+
+ external = get_cursor(tu.cursor, 'external')
+ assert external.linkage == LinkageKind.EXTERNAL
+
diff --git a/bindings/python/tests/cindex/test_tls_kind.py b/bindings/python/tests/cindex/test_tls_kind.py
new file mode 100644
index 0000000000..6a03c0d5ee
--- /dev/null
+++ b/bindings/python/tests/cindex/test_tls_kind.py
@@ -0,0 +1,37 @@
+
+from clang.cindex import TLSKind
+from clang.cindex import Cursor
+from clang.cindex import TranslationUnit
+
+from .util import get_cursor
+from .util import get_tu
+
+def test_tls_kind():
+ """Ensure that thread-local storage kinds are available on cursors."""
+
+ tu = get_tu("""
+int tls_none;
+thread_local int tls_dynamic;
+_Thread_local int tls_static;
+""", lang = 'cpp')
+
+ tls_none = get_cursor(tu.cursor, 'tls_none')
+ assert tls_none.tls_kind == TLSKind.NONE;
+
+ tls_dynamic = get_cursor(tu.cursor, 'tls_dynamic')
+ assert tls_dynamic.tls_kind == TLSKind.DYNAMIC
+
+ tls_static = get_cursor(tu.cursor, 'tls_static')
+ assert tls_static.tls_kind == TLSKind.STATIC
+
+ # The following case tests '__declspec(thread)'. Since it is a Microsoft
+ # specific extension, specific flags are required for the parser to pick
+ # these up.
+ flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32']
+ tu = get_tu("""
+__declspec(thread) int tls_declspec;
+""", lang = 'cpp', flags=flags)
+
+ tls_declspec = get_cursor(tu.cursor, 'tls_declspec')
+ assert tls_declspec.tls_kind == TLSKind.STATIC
+
diff --git a/bindings/python/tests/cindex/test_translation_unit.py b/bindings/python/tests/cindex/test_translation_unit.py
index be6cd671ae..65d1ee02ff 100644
--- a/bindings/python/tests/cindex/test_translation_unit.py
+++ b/bindings/python/tests/cindex/test_translation_unit.py
@@ -59,9 +59,12 @@ int SOME_DEFINE;
assert spellings[-1] == 'y'
def test_unsaved_files_2():
- import StringIO
+ try:
+ from StringIO import StringIO
+ except:
+ from io import StringIO
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
- ('fake.c', StringIO.StringIO('int x;'))])
+ ('fake.c', StringIO('int x;'))])
spellings = [c.spelling for c in tu.cursor.get_children()]
assert spellings[-1] == 'x'
diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py
index f2184338be..6ee0773828 100644
--- a/bindings/python/tests/cindex/test_type.py
+++ b/bindings/python/tests/cindex/test_type.py
@@ -37,37 +37,44 @@ def test_a_struct():
assert not fields[0].type.is_const_qualified()
assert fields[0].type.kind == TypeKind.INT
assert fields[0].type.get_canonical().kind == TypeKind.INT
+ assert fields[0].type.get_typedef_name() == ''
assert fields[1].spelling == 'b'
assert not fields[1].type.is_const_qualified()
assert fields[1].type.kind == TypeKind.TYPEDEF
assert fields[1].type.get_canonical().kind == TypeKind.INT
assert fields[1].type.get_declaration().spelling == 'I'
+ assert fields[1].type.get_typedef_name() == 'I'
assert fields[2].spelling == 'c'
assert not fields[2].type.is_const_qualified()
assert fields[2].type.kind == TypeKind.LONG
assert fields[2].type.get_canonical().kind == TypeKind.LONG
+ assert fields[2].type.get_typedef_name() == ''
assert fields[3].spelling == 'd'
assert not fields[3].type.is_const_qualified()
assert fields[3].type.kind == TypeKind.ULONG
assert fields[3].type.get_canonical().kind == TypeKind.ULONG
+ assert fields[3].type.get_typedef_name() == ''
assert fields[4].spelling == 'e'
assert not fields[4].type.is_const_qualified()
assert fields[4].type.kind == TypeKind.LONG
assert fields[4].type.get_canonical().kind == TypeKind.LONG
+ assert fields[4].type.get_typedef_name() == ''
assert fields[5].spelling == 'f'
assert fields[5].type.is_const_qualified()
assert fields[5].type.kind == TypeKind.INT
assert fields[5].type.get_canonical().kind == TypeKind.INT
+ assert fields[5].type.get_typedef_name() == ''
assert fields[6].spelling == 'g'
assert not fields[6].type.is_const_qualified()
assert fields[6].type.kind == TypeKind.POINTER
assert fields[6].type.get_pointee().kind == TypeKind.INT
+ assert fields[6].type.get_typedef_name() == ''
assert fields[7].spelling == 'h'
assert not fields[7].type.is_const_qualified()
@@ -75,6 +82,7 @@ def test_a_struct():
assert fields[7].type.get_pointee().kind == TypeKind.POINTER
assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
+ assert fields[7].type.get_typedef_name() == ''
def test_references():
"""Ensure that a Type maintains a reference to a TranslationUnit."""
@@ -404,3 +412,12 @@ def test_decay():
assert a.kind == TypeKind.INCOMPLETEARRAY
assert a.element_type.kind == TypeKind.INT
assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
+
+def test_addrspace():
+ """Ensure the address space can be queried"""
+ tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c')
+
+ testInteger = get_cursor(tu, 'testInteger')
+
+ assert testInteger is not None, "Could not find testInteger."
+ assert testInteger.type.get_address_space() == 2
diff --git a/cmake/caches/Android-stage2.cmake b/cmake/caches/Android-stage2.cmake
new file mode 100644
index 0000000000..6720517590
--- /dev/null
+++ b/cmake/caches/Android-stage2.cmake
@@ -0,0 +1,52 @@
+set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "")
+
+set(CLANG_VENDOR Android CACHE STRING "")
+set(CMAKE_BUILD_TYPE Release CACHE STRING "")
+set(LLVM_ENABLE_THREADS OFF CACHE BOOL "")
+set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
+set(LLVM_LIBDIR_SUFFIX 64 CACHE STRING "")
+set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
+
+set(ANDROID_RUNTIMES_ENABLE_ASSERTIONS ON CACHE BOOL "")
+set(ANDROID_RUNTIMES_BUILD_TYPE Release CACHE STRING "")
+set(ANDROID_BUILTINS_BUILD_TYPE Release CACHE STRING "")
+
+set(LLVM_BUILTIN_TARGETS "i686-linux-android;x86_64-linux-android;aarch64-linux-android;armv7-linux-android" CACHE STRING "")
+foreach(target i686;x86_64;aarch64;armv7)
+ set(BUILTINS_${target}-linux-android_ANDROID 1 CACHE STRING "")
+ set(BUILTINS_${target}-linux-android_CMAKE_BUILD_TYPE ${ANDROID_BUILTINS_BUILD_TYPE} CACHE STRING "")
+ set(BUILTINS_${target}-linux-android_CMAKE_ASM_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
+ set(BUILTINS_${target}-linux-android_CMAKE_C_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
+ set(BUILTINS_${target}-linux-android_CMAKE_SYSROOT ${ANDROID_${target}_SYSROOT} CACHE PATH "")
+ set(BUILTINS_${target}-linux-android_CMAKE_EXE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
+ set(BUILTINS_${target}-linux-android_CMAKE_SHARED_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
+ set(BUILTINS_${target}-linux-android_CMAKE_MOUDLE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
+endforeach()
+
+
+set(LLVM_RUNTIME_TARGETS "i686-linux-android;x86_64-linux-android;aarch64-linux-android;armv7-linux-android" CACHE STRING "")
+foreach(target i686;x86_64;aarch64;armv7)
+ set(RUNTIMES_${target}-linux-android_ANDROID 1 CACHE STRING "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_ASM_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_BUILD_TYPE ${ANDROID_RUNTIMES_BUILD_TYPE} CACHE STRING "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_C_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_CXX_FLAGS ${ANDROID_${target}_CXX_FLAGS} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_SYSROOT ${ANDROID_${target}_SYSROOT} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_EXE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_SHARED_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_CMAKE_MODULE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_COMPILER_RT_ENABLE_WERROR ON CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_COMPILER_RT_TEST_COMPILER_CFLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
+ set(RUNTIMES_${target}-linux-android_COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_ASSERTIONS ${ANDROID_RUNTIMES_ENABLE_ASSERTIONS} CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_THREADS OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LIBUNWIND_HAS_NO_EXCEPTIONS_FLAG ON CACHE BOOL "")
+ set(RUNTIMES_${target}-linux-android_LIBUNWIND_HAS_FUNWIND_TABLES ON CACHE BOOL "")
+endforeach()
+
+set(RUNTIMES_armv7-linux-android_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
+
diff --git a/cmake/caches/Android.cmake b/cmake/caches/Android.cmake
new file mode 100644
index 0000000000..6fbc4a5395
--- /dev/null
+++ b/cmake/caches/Android.cmake
@@ -0,0 +1,43 @@
+# This file sets up a CMakeCache for an Android toolchain build.
+
+set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
+
+set(CLANG_ENABLE_ARCMT OFF CACHE BOOL "")
+set(CLANG_ENABLE_STATIC_ANALYZER OFF CACHE BOOL "")
+set(CLANG_VENDOR Android CACHE STRING "")
+
+set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
+
+set(HAVE_LIBCXXABI ON CACHE BOOL "")
+set(LLVM_BUILD_TOOLS OFF CACHE BOOL "")
+set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
+set(LLVM_ENABLE_THREADS OFF CACHE BOOL "")
+set(LLVM_LIBDIR_SUFFIX 64 CACHE STRING "")
+set(LLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD OFF CACHE BOOL "")
+set(LLVM_TOOL_OPENMP_BUILD OFF CACHE BOOL "")
+set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
+
+if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
+ list(APPEND EXTRA_ARGS -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT=${LIBCXX_ENABLE_ABI_LINKER_SCRIPT})
+endif()
+
+if (LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
+ list(APPEND EXTRA_ARGS -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=${LIBCXX_ENABLE_STATIC_ABI_LIBRARY})
+endif()
+
+if (LLVM_BUILD_EXTERNAL_COMPILER_RT)
+ set(APPEND EXTRA_ARGS -DLLVM_BUILD_EXTERNAL_COMPILER_RT=${LLVM_BUILD_EXTERNAL_COMPILER_RT})
+endif()
+
+get_cmake_property(variableNames VARIABLES)
+foreach(variableName ${variableNames})
+ if(variableName MATCHES "^STAGE2_")
+ string(REPLACE "STAGE2_" "" new_name ${variableName})
+ list(APPEND EXTRA_ARGS "-D${new_name}=${${variableName}}")
+ endif()
+endforeach()
+
+set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
+set(CLANG_BOOTSTRAP_CMAKE_ARGS
+ ${EXTRA_ARGS}
+ -C${CMAKE_CURRENT_LIST_DIR}/Android-stage2.cmake CACHE STRING "")
diff --git a/cmake/caches/Apple-stage1.cmake b/cmake/caches/Apple-stage1.cmake
index 32159811a8..5180888013 100644
--- a/cmake/caches/Apple-stage1.cmake
+++ b/cmake/caches/Apple-stage1.cmake
@@ -24,6 +24,12 @@ set(CLANG_BOOTSTRAP_PASSTHROUGH
CMAKE_OSX_ARCHITECTURES
CACHE STRING "")
+# Disabling embedded darwin compiler-rt on stage1 builds is required because we
+# don't build stage1 to support arm code generation.
+set(COMPILER_RT_ENABLE_IOS OFF CACHE BOOL "")
+set(COMPILER_RT_ENABLE_WATCHOS OFF CACHE BOOL "")
+set(COMPILER_RT_ENABLE_TVOS OFF CACHE BOOL "")
+
set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
@@ -39,6 +45,8 @@ set(CLANG_BOOTSTRAP_TARGETS
clang-test-depends
distribution
install-distribution
+ install-xcode-toolchain
+ install-distribution-toolchain
clang CACHE STRING "")
#bootstrap
diff --git a/cmake/caches/Apple-stage2.cmake b/cmake/caches/Apple-stage2.cmake
index 11c595c153..8826fc12de 100644
--- a/cmake/caches/Apple-stage2.cmake
+++ b/cmake/caches/Apple-stage2.cmake
@@ -13,6 +13,7 @@ set(CLANG_LINKS_TO_CREATE clang++ cc c++ CACHE STRING "")
set(CMAKE_MACOSX_RPATH ON CACHE BOOL "")
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
+set(LLVM_ENABLE_MODULES ON CACHE BOOL "")
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(BUG_REPORT_URL "http://developer.apple.com/bugreporter/" CACHE STRING "")
@@ -28,8 +29,10 @@ set(LLVM_BUILD_TESTS ON CACHE BOOL "")
set(LLVM_ENABLE_LTO ON CACHE BOOL "")
set(CMAKE_C_FLAGS "-fno-stack-protector -fno-common -Wno-profile-instr-unprofiled" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-fno-stack-protector -fno-common -Wno-profile-instr-unprofiled" 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 "")
+if(LLVM_ENABLE_LTO AND NOT LLVM_ENABLE_LTO STREQUAL "THIN")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
+endif()
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(LIBCXX_INSTALL_LIBRARY OFF CACHE BOOL "")
@@ -37,6 +40,10 @@ set(LIBCXX_INSTALL_HEADERS ON CACHE BOOL "")
set(LIBCXX_INCLUDE_TESTS OFF CACHE BOOL "")
set(LLVM_LTO_VERSION_OFFSET 3000 CACHE STRING "")
+# Generating Xcode toolchains is useful for developers wanting to build and use
+# clang without installing over existing tools.
+set(LLVM_CREATE_XCODE_TOOLCHAIN ON CACHE BOOL "")
+
# setup toolchain
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
set(LLVM_TOOLCHAIN_TOOLS
diff --git a/cmake/caches/BaremetalARM.cmake b/cmake/caches/BaremetalARM.cmake
new file mode 100644
index 0000000000..73f797d9c4
--- /dev/null
+++ b/cmake/caches/BaremetalARM.cmake
@@ -0,0 +1,50 @@
+set(LLVM_TARGETS_TO_BUILD ARM;X86 CACHE STRING "")
+
+# Builtins
+set(LLVM_BUILTIN_TARGETS "armv7m-none-eabi;armv6m-none-eabi;armv7em-none-eabi" CACHE STRING "Builtin Targets")
+
+set(BUILTINS_armv6m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV6M_SYSROOT} CACHE STRING "armv6m-none-eabi Sysroot")
+set(BUILTINS_armv6m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv6m-none-eabi System Name")
+set(BUILTINS_armv6m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv6m-none-eabi Baremetal build")
+set(BUILTINS_armv6m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv6m-none-eabi os dir")
+
+set(BUILTINS_armv7m-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7M_SYSROOT} CACHE STRING "armv7m-none-eabi Sysroot")
+set(BUILTINS_armv7m-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7m-none-eabi System Name")
+set(BUILTINS_armv7m-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7m-none-eabi Baremetal build")
+set(BUILTINS_armv7m-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi C Flags")
+set(BUILTINS_armv7m-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7m-none-eabi ASM Flags")
+set(BUILTINS_armv7m-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7m-none-eabi os dir")
+
+set(BUILTINS_armv7em-none-eabi_CMAKE_SYSROOT ${BAREMETAL_ARMV7EM_SYSROOT} CACHE STRING "armv7em-none-eabi Sysroot")
+set(BUILTINS_armv7em-none-eabi_CMAKE_SYSTEM_NAME Generic CACHE STRING "armv7em-none-eabi System Name")
+set(BUILTINS_armv7em-none-eabi_COMPILER_RT_BAREMETAL_BUILD ON CACHE BOOL "armv7em-none-eabi Baremetal build")
+set(BUILTINS_armv7em-none-eabi_CMAKE_C_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi C Flags")
+set(BUILTINS_armv7em-none-eabi_CMAKE_ASM_FLAGS "-mfpu=fp-armv8" CACHE STRING "armv7em-none-eabi ASM Flags")
+set(BUILTINS_armv7em-none-eabi_COMPILER_RT_OS_DIR "baremetal" CACHE STRING "armv7em-none-eabi os dir")
+
+set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
+set(LLVM_TOOLCHAIN_TOOLS
+ llc
+ llvm-ar
+ llvm-cxxfilt
+ llvm-dwarfdump
+ llvm-dsymutil
+ llvm-nm
+ llvm-objdump
+ llvm-ranlib
+ llvm-readobj
+ llvm-size
+ llvm-symbolizer
+ opt
+ CACHE STRING "")
+
+set(LLVM_DISTRIBUTION_COMPONENTS
+ clang
+ lld
+ clang-headers
+ builtins-armv6m-none-eabi
+ builtins-armv7m-none-eabi
+ builtins-armv7em-none-eabi
+ runtimes
+ ${LLVM_TOOLCHAIN_TOOLS}
+ CACHE STRING "")
diff --git a/cmake/caches/DistributionExample.cmake b/cmake/caches/DistributionExample.cmake
index 862f547c16..551f4ee07e 100644
--- a/cmake/caches/DistributionExample.cmake
+++ b/cmake/caches/DistributionExample.cmake
@@ -29,6 +29,13 @@ set(CLANG_BOOTSTRAP_TARGETS
# Setup the bootstrap build.
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
-set(CLANG_BOOTSTRAP_CMAKE_ARGS
- -C ${CMAKE_CURRENT_LIST_DIR}/DistributionExample-stage2.cmake
- CACHE STRING "")
+
+if(STAGE2_CACHE_FILE)
+ set(CLANG_BOOTSTRAP_CMAKE_ARGS
+ -C ${STAGE2_CACHE_FILE}
+ CACHE STRING "")
+else()
+ set(CLANG_BOOTSTRAP_CMAKE_ARGS
+ -C ${CMAKE_CURRENT_LIST_DIR}/DistributionExample-stage2.cmake
+ CACHE STRING "")
+endif()
diff --git a/cmake/caches/Fuchsia-stage2.cmake b/cmake/caches/Fuchsia-stage2.cmake
index dcbeae82fa..d2f19fd6d0 100644
--- a/cmake/caches/Fuchsia-stage2.cmake
+++ b/cmake/caches/Fuchsia-stage2.cmake
@@ -1,13 +1,12 @@
# 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(LLVM_TARGETS_TO_BUILD X86;ARM;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 "")
@@ -19,19 +18,54 @@ if(NOT APPLE)
set(CLANG_DEFAULT_LINKER lld CACHE STRING "")
endif()
+# This is a "Does your linker support it?" option that only applies
+# to x86-64 ELF targets. All Fuchsia target linkers do support it.
+# For x86-64 Linux, it's supported by LLD and by GNU linkers since
+# binutils 2.27, so one can hope that all Linux hosts in use handle it.
+# Ideally this would be settable as a per-target option.
+set(ENABLE_X86_RELAX_RELOCATIONS ON CACHE BOOL "")
+
+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(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
+
+set(LLVM_BUILTIN_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "")
+foreach(target x86_64;aarch64)
+ set(BUILTINS_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
+ set(BUILTINS_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
+endforeach()
+
+set(LLVM_RUNTIME_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia;x86_64-fuchsia-asan:x86_64-fuchsia;aarch64-fuchsia-asan:aarch64-fuchsia" CACHE STRING "")
+foreach(target x86_64;aarch64)
+ set(RUNTIMES_${target}-fuchsia_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
+ set(RUNTIMES_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
+ set(RUNTIMES_${target}-fuchsia_UNIX 1 CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LIBUNWIND_ENABLE_STATIC OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_LIBCXX_ABI_VERSION 2 CACHE STRING "")
+ set(RUNTIMES_${target}-fuchsia_LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-fuchsia_SANITIZER_USE_COMPILER_RT ON CACHE BOOL "")
-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 "")
+ set(RUNTIMES_${target}-fuchsia-asan_LLVM_USE_SANITIZER Address CACHE STRING "")
+ set(RUNTIMES_${target}-fuchsia-asan_LLVM_RUNTIMES_PREFIX "${target}-fuchsia/" CACHE STRING "")
+ set(RUNTIMES_${target}-fuchsia-asan_LLVM_RUNTIMES_LIBDIR_SUFFIX "/asan" CACHE STRING "")
+ set(RUNTIMES_${target}-fuchsia-asan_LIBCXX_INSTALL_HEADERS OFF CACHE BOOL "")
+endforeach()
# Setup toolchain.
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
set(LLVM_TOOLCHAIN_TOOLS
+ llc
llvm-ar
llvm-cov
llvm-cxxfilt
@@ -39,12 +73,16 @@ set(LLVM_TOOLCHAIN_TOOLS
llvm-dsymutil
llvm-lib
llvm-nm
+ llvm-objcopy
llvm-objdump
llvm-profdata
llvm-ranlib
+ llvm-readelf
llvm-readobj
llvm-size
llvm-symbolizer
+ opt
+ sancov
CACHE STRING "")
set(LLVM_DISTRIBUTION_COMPONENTS
@@ -55,8 +93,10 @@ set(LLVM_DISTRIBUTION_COMPONENTS
LTO
clang-format
clang-headers
- builtins-x86_64-fuchsia-none
- builtins-aarch64-fuchsia-none
+ clang-refactor
+ clang-tidy
+ clangd
+ builtins
runtimes
${LLVM_TOOLCHAIN_TOOLS}
CACHE STRING "")
diff --git a/cmake/caches/Fuchsia.cmake b/cmake/caches/Fuchsia.cmake
index a90647e4ae..0932c046f6 100644
--- a/cmake/caches/Fuchsia.cmake
+++ b/cmake/caches/Fuchsia.cmake
@@ -19,6 +19,12 @@ 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
@@ -32,9 +38,11 @@ set(CLANG_BOOTSTRAP_TARGETS
install-distribution
clang CACHE STRING "")
-if(FUCHSIA_SYSROOT)
- set(EXTRA_ARGS -DFUCHSIA_SYSROOT=${FUCHSIA_SYSROOT})
-endif()
+foreach(target x86_64;aarch64)
+ if(FUCHSIA_${target}_SYSROOT)
+ list(APPEND EXTRA_ARGS -DFUCHSIA_${target}_SYSROOT=${FUCHSIA_${target}_SYSROOT})
+ endif()
+endforeach()
# Setup the bootstrap build.
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt
index 59176a2b80..be6d1d7257 100644
--- a/cmake/modules/CMakeLists.txt
+++ b/cmake/modules/CMakeLists.txt
@@ -42,7 +42,7 @@ 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"
+ "\${CLANG_INSTALL_PREFIX}/include"
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/ClangConfig.cmake.in
diff --git a/cmake/modules/ClangConfig.cmake.in b/cmake/modules/ClangConfig.cmake.in
index 03bca691c2..a5a7eae503 100644
--- a/cmake/modules/ClangConfig.cmake.in
+++ b/cmake/modules/ClangConfig.cmake.in
@@ -11,3 +11,10 @@ set(CLANG_INCLUDE_DIRS "@CLANG_CONFIG_INCLUDE_DIRS@")
# Provide all our library targets to users.
include("@CLANG_CONFIG_EXPORTS_FILE@")
+
+# By creating clang-tablegen-targets here, subprojects that depend on Clang's
+# tablegen-generated headers can always depend on this target whether building
+# in-tree with Clang or not.
+if(NOT TARGET clang-tablegen-targets)
+ add_custom_target(clang-tablegen-targets)
+endif()
diff --git a/cmake/modules/FindZ3.cmake b/cmake/modules/FindZ3.cmake
new file mode 100644
index 0000000000..779ef928da
--- /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/cmake/modules/ProtobufMutator.cmake b/cmake/modules/ProtobufMutator.cmake
new file mode 100644
index 0000000000..5f23f33f4c
--- /dev/null
+++ b/cmake/modules/ProtobufMutator.cmake
@@ -0,0 +1,19 @@
+set(PBM_PREFIX protobuf_mutator)
+set(PBM_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PBM_PREFIX}/src/${PBM_PREFIX})
+set(PBM_LIB_PATH ${PBM_PATH}-build/src/libprotobuf-mutator.a)
+set(PBM_FUZZ_LIB_PATH ${PBM_PATH}-build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a)
+
+ExternalProject_Add(${PBM_PREFIX}
+ PREFIX ${PBM_PREFIX}
+ GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git
+ GIT_TAG master
+ CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
+ -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
+ BUILD_BYPRODUCTS ${PBM_LIB_PATH} ${PBM_FUZZ_LIB_PATH}
+ UPDATE_COMMAND ""
+ INSTALL_COMMAND ""
+ )
+
+set(ProtobufMutator_INCLUDE_DIRS ${PBM_PATH})
+set(ProtobufMutator_LIBRARIES ${PBM_FUZZ_LIB_PATH} ${PBM_LIB_PATH})
diff --git a/docs/AddressSanitizer.rst b/docs/AddressSanitizer.rst
index ed28ad4de6..f58995576f 100644
--- a/docs/AddressSanitizer.rst
+++ b/docs/AddressSanitizer.rst
@@ -140,7 +140,8 @@ Memory leak detection
---------------------
For more information on leak detector in AddressSanitizer, see
-:doc:`LeakSanitizer`. The leak detection is turned on by default on Linux;
+:doc:`LeakSanitizer`. The leak detection is turned on by default on Linux,
+and can be enabled using ``ASAN_OPTIONS=detect_leaks=1`` on OS X;
however, it is not yet supported on other platforms.
Issue Suppression
diff --git a/docs/Block-ABI-Apple.rst b/docs/Block-ABI-Apple.rst
index 628e6f3d90..7f49bbd40d 100644
--- a/docs/Block-ABI-Apple.rst
+++ b/docs/Block-ABI-Apple.rst
@@ -856,15 +856,15 @@ mentioned above, call:
.. code-block:: c
- _Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
+ _Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<apropos>);
in the copy helper and:
.. code-block:: c
- _Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
+ _Block_object_dispose(->target, BLOCK_FIELD_<apropos>);
-in the dispose helper where ``<appropo>`` is:
+in the dispose helper where ``<apropos>`` is:
.. code-block:: c
@@ -888,7 +888,7 @@ and functions are generated in the same manner.
Under ObjC we allow ``__weak`` as an attribute on ``__block`` variables, and
this causes the addition of ``BLOCK_FIELD_IS_WEAK`` orred onto the
``BLOCK_FIELD_IS_BYREF`` flag when copying the ``block_byref`` structure in the
-``Block`` copy helper, and onto the ``BLOCK_FIELD_<appropo>`` field within the
+``Block`` copy helper, and onto the ``BLOCK_FIELD_<apropos>`` field within the
``block_byref`` copy/dispose helper calls.
The prototypes, and summary, of the helper functions are:
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index 13b79fdfa5..d2956c18f8 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -91,8 +91,8 @@ endif()
endif()
if (LLVM_ENABLE_SPHINX)
+ include(AddSphinxTarget)
if (SPHINX_FOUND)
- include(AddSphinxTarget)
if (${SPHINX_OUTPUT_HTML})
add_sphinx_target(html clang)
add_custom_command(TARGET docs-clang-html POST_BUILD
diff --git a/docs/ClangCommandLineReference.rst b/docs/ClangCommandLineReference.rst
index c7aead921a..0a0fce9190 100644
--- a/docs/ClangCommandLineReference.rst
+++ b/docs/ClangCommandLineReference.rst
@@ -56,6 +56,16 @@ Pass <arg> to fatbinary invocation
Pass <arg> to the ptxas assembler
+.. option:: -Xopenmp-target <arg>
+
+Pass <arg> to the target offloading toolchain.
+
+.. program:: clang1
+.. option:: -Xopenmp-target=<arg> <arg2>
+.. program:: clang
+
+Pass <arg> to the specified target offloading toolchain. The triple that identifies the toolchain must be provided after the equals sign.
+
.. option:: -Z<arg>
.. option:: -a<arg>, --profile-blocks
@@ -96,6 +106,8 @@ Emit ARC errors even if the migrator can fix them
Output path for the plist report
+.. option:: --autocomplete=<arg>
+
.. option:: -bind\_at\_load
.. option:: -bundle
@@ -198,6 +210,10 @@ Specify comma-separated list of triples OpenMP offloading targets to be supporte
.. 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
@@ -238,6 +254,8 @@ Make the next included directory (-I or -F) an indexer header map
Run the migrator
+.. option:: -mios-simulator-version-min=<arg>, -miphonesimulator-version-min=<arg>
+
.. option:: -mlinker-version=<arg>
.. option:: -mlittle-endian, -EL
@@ -250,6 +268,8 @@ Additional arguments to forward to LLVM's option processing
Directory to dump module dependencies to
+.. option:: -mtvos-simulator-version-min=<arg>, -mappletvsimulator-version-min=<arg>
+
.. option:: -multi\_module
.. option:: -multiply\_defined <arg>
@@ -258,6 +278,8 @@ Directory to dump module dependencies to
.. 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.
@@ -282,7 +304,7 @@ Disable builtin #include directories
.. option:: -nomultidefs
-.. option:: -nopie
+.. option:: -nopie, -no-pie
.. option:: -noprebind
@@ -300,6 +322,10 @@ Disable standard #include directories for the C++ standard library
.. option:: -nostdlib, --no-standard-libraries
+.. program:: clang1
+.. option:: -nostdlib++
+.. program:: clang
+
.. option:: -nostdlibinc
.. option:: -o<file>, --output <arg>, --output=<arg>
@@ -416,6 +442,10 @@ Print the library path for the currently used compiler runtime library ("libgcc.
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
@@ -640,6 +670,10 @@ Pass <arg> to the assembler
Pass <arg> to the clang compiler
+.. option:: -fclang-abi-compat=<version>
+
+Attempt to match the ABI of Clang <version>
+
.. option:: -fcomment-block-commands=<arg>,<arg2>...
Treat each comma separated argument in <arg> as a documentation comment block command
@@ -678,6 +712,8 @@ 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
@@ -688,6 +724,10 @@ Don't use blacklist file for sanitizers
Level of field padding for AddressSanitizer
+.. option:: -fsanitize-address-globals-dead-stripping
+
+Enable linker dead stripping of globals in AddressSanitizer
+
.. option:: -fsanitize-address-use-after-scope, -fno-sanitize-address-use-after-scope
Enable use-after-scope detection in AddressSanitizer
@@ -700,6 +740,10 @@ Path to blacklist file for sanitizers
Enable control flow integrity (CFI) checks for cross-DSO calls.
+.. option:: -fsanitize-cfi-icall-generalize-pointers
+
+Generalize pointers in function type signatures used for Control Flow Integrity (CFI) indirect call checking
+
.. option:: -fsanitize-coverage=<arg1>,<arg2>..., -fno-sanitize-coverage=<arg1>,<arg2>...
Specify the type of coverage instrumentation for Sanitizers
@@ -720,6 +764,8 @@ Enable origins tracking in MemorySanitizer
Enable use-after-destroy detection in MemorySanitizer
+.. option:: -fsanitize-minimal-runtime, -fno-sanitize-minimal-runtime
+
.. option:: -fsanitize-recover, -fno-sanitize-recover
.. program:: clang1
@@ -830,6 +876,10 @@ Use the last modification time of <file> as the build session timestamp
Time when the current build session started
+.. option:: -fmodule-file=\[<name>=\]<file>
+
+Specify the mapping of module name to precompiled module file, or load a module file if name is omitted.
+
.. option:: -fmodules-cache-path=<directory>
Specify the module cache path
@@ -872,6 +922,10 @@ Add directory to AFTER include search path
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
@@ -1051,11 +1105,13 @@ Target-independent compilation options
Enable C++17 aligned allocation functions
-.. option:: -fallow-unsupported
+.. option:: -fallow-editor-placeholders, -fno-allow-editor-placeholders
-.. option:: -faltivec, -fno-altivec, -maltivec
+Treat editor placeholders as valid source code
+
+.. option:: -fallow-unsupported
-Enable AltiVec vector initializer syntax
+.. option:: -faltivec, -fno-altivec
.. option:: -fansi-escape-codes
@@ -1155,6 +1211,10 @@ Place each data in its own section (ELF Only)
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
@@ -1183,6 +1243,10 @@ Print absolute paths in diagnostics
.. option:: -fdiagnostics-color=<arg>
.. program:: clang
+.. option:: -fdiagnostics-hotness-threshold=<number>
+
+Prevent optimization remarks from being output if they do not have at least this profile count
+
.. option:: -fdiagnostics-show-hotness, -fno-diagnostics-show-hotness
Enable profile hotness information in diagnostic line
@@ -1325,10 +1389,6 @@ Specify the maximum alignment to enforce on pointers lacking an explicit alignme
.. 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
@@ -1411,6 +1471,10 @@ Do not treat C++ operator name keywords as synonyms for operators
.. option:: -fno-working-directory
+.. option:: -fnoopenmp-relocatable-target
+
+Do not compile OpenMP target code as relocatable.
+
.. option:: -fnoopenmp-use-tls
.. option:: -fobjc-abi-version=<arg>
@@ -1453,6 +1517,10 @@ Enable ARC-style weak references in Objective-C
.. option:: -fopenmp-dump-offload-linker-script
+.. option:: -fopenmp-relocatable-target
+
+OpenMP target code is compiled as relocatable using the -c flag. For OpenMP targets the code is relocatable by default.
+
.. option:: -fopenmp-use-tls
.. option:: -fopenmp-version=<arg>
@@ -1531,7 +1599,18 @@ Generate instrumented code to collect execution counts into <file> (overridden b
Use instrumentation data for profile-guided optimization
+.. option:: -fprofile-sample-accurate, -fauto-profile-accurate, -fno-profile-sample-accurate
+
+Specifies that the sample profile is accurate. If the sample
+ profile is accurate, callsites without profile samples are marked
+ as cold. Otherwise, treat callsites without profile samples as if
+ we have no profile
+
+.. 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
@@ -1559,6 +1638,8 @@ Turn on loop reroller
.. option:: -fretain-comments-from-system-headers
+.. option:: -frewrite-imports, -fno-rewrite-imports
+
.. option:: -frewrite-includes, -fno-rewrite-includes
.. option:: -frewrite-map-file <arg>
@@ -1613,10 +1694,6 @@ Use SjLj style exceptions
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>
@@ -1653,7 +1730,7 @@ Enable optimizations based on the strict definition of an enum's value range
.. option:: -fstrict-return, -fno-strict-return
-Always treat control flow paths that fall off the end of a non-voidfunction as unreachable
+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
@@ -1765,6 +1842,10 @@ Treat signed integer overflow as two's complement
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
@@ -1777,6 +1858,10 @@ Sets the minimum function size to instrument with XRay
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
@@ -1855,6 +1940,8 @@ Put objects of at most <size> bytes into small data section (MIPS / Hexagon)
Enable SVR4-style position-independent code (Mips only)
+.. option:: -mabs=<arg>
+
.. option:: -malign-double
Align doubles to two words in structs (x86 only)
@@ -1875,7 +1962,9 @@ Link stack frames through backchain on System Z
.. 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)
+.. 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:: -mdefault-build-attributes<arg>, -mno-default-build-attributes<arg>
.. option:: -mdll<arg>
@@ -1891,6 +1980,18 @@ Link stack frames through backchain on System Z
Set EABI type, e.g. 4, 5 or gnu (default depends on triple)
+.. option:: -membedded-data, -mno-embedded-data
+
+Place constants in the .rodata section instead of the .sdata section even if they meet the -G <size> threshold (MIPS)
+
+.. option:: -mextern-sdata, -mno-extern-sdata
+
+Assume that externally defined data is in the small data if it meets the -G <size> threshold (MIPS)
+
+.. option:: -mfentry
+
+Insert calls to fentry at function entry (x86 only)
+
.. option:: -mfloat-abi=<arg>
.. option:: -mfp32
@@ -1909,6 +2010,10 @@ Use 64-bit floating point registers (MIPS only)
Enable merging of globals
+.. option:: -mgpopt, -mno-gpopt
+
+Use GP relative accesses for symbols known to be in a small data section (MIPS)
+
.. option:: -mhard-float
.. option:: -mhwdiv=<arg>, --mhwdiv <arg>, --mhwdiv=<arg>
@@ -1925,7 +2030,7 @@ Use Intel MCU ABI
(integrated-as) Emit an object file which can be used with an incremental linker
-.. option:: -miphoneos-version-min=<arg>, -mios-simulator-version-min=<arg>, -mios-version-min=<arg>, -miphonesimulator-version-min=<arg>
+.. option:: -miphoneos-version-min=<arg>, -mios-version-min=<arg>
.. option:: -mips16
@@ -1933,14 +2038,24 @@ Use Intel MCU ABI
.. option:: -mldc1-sdc1, -mno-ldc1-sdc1
+.. option:: -mlocal-sdata, -mno-local-sdata
+
+Extend the -G behaviour to object local data (MIPS)
+
.. option:: -mlong-calls, -mno-long-calls
Generate branches with extended addressability, usually via indirect jumps.
-.. option:: -mmacosx-version-min=<arg>
+.. option:: -mmacosx-version-min=<arg>, -mmacos-version-min=<arg>
Set Mac OS X deployment target
+.. option:: -mmadd4, -mno-madd4
+
+Enable the generation of 4-operand madd.s, madd.d and related instructions.
+
+.. option:: -mmcu=<arg>
+
.. option:: -mmicromips, -mno-micromips
.. option:: -mms-bitfields, -mno-ms-bitfields
@@ -1951,6 +2066,10 @@ Set the default structure layout to be compatible with the Microsoft compiler st
Enable MSA ASE (MIPS only)
+.. option:: -mmt, -mno-mt
+
+Enable MT ASE (MIPS only)
+
.. option:: -mnan=<arg>
.. option:: -mno-mips16
@@ -2015,7 +2134,7 @@ The thread model to use, e.g. posix, single (posix by default)
.. option:: -mtune=<arg>
-.. option:: -mtvos-version-min=<arg>, -mappletvos-version-min=<arg>, -mappletvsimulator-version-min=<arg>, -mtvos-simulator-version-min=<arg>
+.. option:: -mtvos-version-min=<arg>, -mappletvos-version-min=<arg>
.. option:: -municode<arg>
@@ -2023,7 +2142,7 @@ The thread model to use, e.g. posix, single (posix by default)
.. option:: -mwarn-nonportable-cfstrings, -mno-warn-nonportable-cfstrings
-.. option:: -mwatchos-version-min=<arg>, -mwatchos-simulator-version-min=<arg>, -mwatchsimulator-version-min=<arg>
+.. option:: -mwatchos-version-min=<arg>
.. option:: -mwindows<arg>
@@ -2065,6 +2184,10 @@ Disallow generation of data access to code sections (ARM only)
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)
@@ -2091,6 +2214,8 @@ Enable Hexagon Double Vector eXtensions
PowerPC
-------
+.. option:: -maltivec, -mno-altivec
+
.. option:: -mcmpb, -mno-cmpb
.. option:: -mcrbits, -mno-crbits
@@ -2159,6 +2284,8 @@ X86
.. option:: -mavx512vl, -mno-avx512vl
+.. option:: -mavx512vpopcntdq, -mno-avx512vpopcntdq
+
.. option:: -mbmi, -mno-bmi
.. option:: -mbmi2, -mno-bmi2
@@ -2167,6 +2294,8 @@ X86
.. option:: -mclwb, -mno-clwb
+.. option:: -mclzero, -mno-clzero
+
.. option:: -mcx16, -mno-cx16
.. option:: -mf16c, -mno-f16c
@@ -2179,6 +2308,8 @@ X86
.. option:: -mfxsr, -mno-fxsr
+.. option:: -mlwp, -mno-lwp
+
.. option:: -mlzcnt, -mno-lzcnt
.. option:: -mmmx, -mno-mmx
@@ -2326,6 +2457,16 @@ Debug information flags
.. option:: -gstrict-dwarf, -gno-strict-dwarf
+.. option:: -gz
+
+DWARF debug sections compression type
+
+.. program:: clang1
+.. option:: -gz=<arg>
+.. program:: clang
+
+DWARF debug sections compression type
+
Static analyzer flags
=====================
@@ -2491,15 +2632,15 @@ Add directory to library search path
Specify <script> as linker script
-.. option:: -Tbss<addr
+.. option:: -Tbss<addr>
Set starting address of BSS to <addr>
-.. option:: -Tdata<addr
+.. option:: -Tdata<addr>
Set starting address of BSS to <addr>
-.. option:: -Ttext<addr
+.. option:: -Ttext<addr>
Set starting address of BSS to <addr>
diff --git a/docs/ClangFormat.rst b/docs/ClangFormat.rst
index dc1e2b9a76..b4030eac6f 100644
--- a/docs/ClangFormat.rst
+++ b/docs/ClangFormat.rst
@@ -71,6 +71,7 @@ to format C/C++/Obj-C code.
Use -style="{key: value, ...}" to set specific
parameters, e.g.:
-style="{BasedOnStyle: llvm, IndentWidth: 8}"
+ -verbose - If set, shows the list of processed files
Generic Options:
@@ -120,6 +121,18 @@ entity.
It operates on the current, potentially unsaved buffer and does not create
or save any files. To revert a formatting, just undo.
+An alternative option is to format changes when saving a file and thus to
+have a zero-effort integration into the coding workflow. To do this, add this to
+your `.vimrc`:
+
+.. code-block:: vim
+
+ function! Formatonsave()
+ let l:formatdiff = 1
+ pyf ~/llvm/tools/clang/tools/clang-format/clang-format.py
+ endfunction
+ autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave()
+
Emacs Integration
=================
@@ -162,8 +175,9 @@ Download the latest Visual Studio extension from the `alpha build site
Script for patch reformatting
=============================
-The python script `clang/tools/clang-format-diff.py` parses the output of
-a unified diff and reformats all contained lines with :program:`clang-format`.
+The python script `clang/tools/clang-format/clang-format-diff.py` parses the
+output of a unified diff and reformats all contained lines with
+:program:`clang-format`.
.. code-block:: console
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
index 7b13a7d009..0c03c77656 100644
--- a/docs/ClangFormatStyleOptions.rst
+++ b/docs/ClangFormatStyleOptions.rst
@@ -209,23 +209,45 @@ the configuration (without a prefix: ``Auto``).
float b = 23;
std::string ccc = 23;
-**AlignEscapedNewlinesLeft** (``bool``)
- If ``true``, aligns escaped newlines as far left as possible.
- Otherwise puts them into the right-most column.
+**AlignEscapedNewlines** (``EscapedNewlineAlignmentStyle``)
+ Options for aligning backslashes in escaped newlines.
- .. code-block:: c++
+ Possible values:
+
+ * ``ENAS_DontAlign`` (in configuration: ``DontAlign``)
+ Don't align escaped newlines.
+
+ .. code-block:: c++
+
+ #define A \
+ int aaaa; \
+ int b; \
+ int dddddddddd;
+
+ * ``ENAS_Left`` (in configuration: ``Left``)
+ Align escaped newlines as far left as possible.
+
+ .. code-block:: c++
+
+ true:
+ #define A \
+ int aaaa; \
+ int b; \
+ int dddddddddd;
+
+ false:
+
+ * ``ENAS_Right`` (in configuration: ``Right``)
+ Align escaped newlines in the right-most column.
+
+ .. code-block:: c++
+
+ #define A \
+ int aaaa; \
+ int b; \
+ int dddddddddd;
- 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
@@ -244,20 +266,31 @@ the configuration (without a prefix: ``Auto``).
.. 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
+ true:
+ int a; // My comment a
+ int b = 2; // comment b
+
+ false:
+ int a; // My comment a
+ int b = 2; // comment about b
**AllowAllParametersOfDeclarationOnNextLine** (``bool``)
- Allow putting all parameters of a function declaration onto
+ If the function declaration doesn't fit on a line,
+ 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);
+ true:
+ void myFunction(
+ int a, int b, int c, int d, int e);
+
+ false:
+ void myFunction(int a,
+ int b,
+ int c,
+ int d,
+ int e);
**AllowShortBlocksOnASingleLine** (``bool``)
Allows contracting simple braced statements to a single line.
@@ -287,12 +320,28 @@ the configuration (without a prefix: ``Auto``).
* ``SFS_None`` (in configuration: ``None``)
Never merge functions into a single line.
+ * ``SFS_InlineOnly`` (in configuration: ``InlineOnly``)
+ Only merge functions defined inside a class. Same as "inline",
+ except it does not implies "empty": i.e. top level empty functions
+ are not merged either.
+
+ .. code-block:: c++
+
+ class Foo {
+ void f() { foo(); }
+ };
+ void f() {
+ foo();
+ }
+ void f() {
+ }
+
* ``SFS_Empty`` (in configuration: ``Empty``)
Only merge empty functions.
.. code-block:: c++
- void f() { bar(); }
+ void f() {}
void f2() {
bar2();
}
@@ -302,16 +351,20 @@ the configuration (without a prefix: ``Auto``).
.. code-block:: c++
- class {
+ class Foo {
void f() { foo(); }
};
+ void f() {
+ foo();
+ }
+ void f() {}
* ``SFS_All`` (in configuration: ``All``)
Merge all functions fitting on a single line.
.. code-block:: c++
- class {
+ class Foo {
void f() { foo(); }
};
void f() { bar(); }
@@ -327,7 +380,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:
@@ -455,166 +508,257 @@ the configuration (without a prefix: ``Auto``).
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.
If ``BreakBeforeBraces`` is set to ``BS_Custom``, use this to specify how
each individual brace case should be handled. Otherwise, this is ignored.
+ .. code-block:: yaml
+
+ # Example of usage:
+ BreakBeforeBraces: Custom
+ BraceWrapping:
+ AfterEnum: true
+ AfterStruct: false
+ SplitEmptyFunction: false
+
Nested configuration flags:
* ``bool AfterClass`` Wrap class definitions.
- .. code-block:: c++
+ .. code-block:: c++
- true:
- class foo {};
+ true:
+ class foo {};
- false:
- class foo
- {};
+ false:
+ class foo
+ {};
* ``bool AfterControlStatement`` Wrap control statements (``if``/``for``/``while``/``switch``/..).
- .. code-block:: c++
+ .. code-block:: c++
- true:
- if (foo())
- {
- } else
- {}
- for (int i = 0; i < 10; ++i)
- {}
+ true:
+ if (foo())
+ {
+ } else
+ {}
+ for (int i = 0; i < 10; ++i)
+ {}
- false:
- 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++
+ .. code-block:: c++
- true:
- enum X : int
- {
- B
- };
+ true:
+ enum X : int
+ {
+ B
+ };
- false:
- enum X : int { B };
+ false:
+ enum X : int { B };
* ``bool AfterFunction`` Wrap function definitions.
- .. code-block:: c++
+ .. code-block:: c++
- true:
- void foo()
- {
- bar();
- bar2();
- }
+ true:
+ void foo()
+ {
+ bar();
+ bar2();
+ }
- false:
- void foo() {
- bar();
- bar2();
- }
+ false:
+ void foo() {
+ bar();
+ bar2();
+ }
* ``bool AfterNamespace`` Wrap namespace definitions.
- .. code-block:: c++
+ .. code-block:: c++
- true:
- namespace
- {
- int foo();
- int bar();
- }
+ true:
+ namespace
+ {
+ int foo();
+ int bar();
+ }
- false:
- 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++
+ .. code-block:: c++
- true:
- struct foo
- {
- int x;
- }
+ true:
+ struct foo
+ {
+ int x;
+ };
- false:
- struct foo {
- int x;
- }
+ false:
+ struct foo {
+ int x;
+ };
* ``bool AfterUnion`` Wrap union definitions.
- .. code-block:: c++
+ .. code-block:: c++
- true:
- union foo
- {
- int x;
- }
+ true:
+ union foo
+ {
+ int x;
+ }
- false:
- union foo {
- int x;
- }
+ false:
+ union foo {
+ int x;
+ }
+
+ * ``bool AfterExternBlock`` Wrap extern blocks.
+
+ .. code-block:: c++
+
+ true:
+ extern "C"
+ {
+ int foo();
+ }
+
+ false:
+ extern "C" {
+ int foo();
+ }
* ``bool BeforeCatch`` Wrap before ``catch``.
- .. code-block:: c++
+ .. code-block:: c++
- true:
- try {
- foo();
- }
- catch () {
- }
+ true:
+ try {
+ foo();
+ }
+ catch () {
+ }
- false:
- try {
- foo();
- } catch () {
- }
+ false:
+ try {
+ foo();
+ } catch () {
+ }
* ``bool BeforeElse`` Wrap before ``else``.
- .. code-block:: c++
+ .. code-block:: c++
- true:
- if (foo()) {
- }
- else {
- }
+ true:
+ if (foo()) {
+ }
+ else {
+ }
- false:
- if (foo()) {
- } else {
- }
+ false:
+ if (foo()) {
+ } else {
+ }
* ``bool IndentBraces`` Indent the wrapped braces themselves.
+ * ``bool SplitEmptyFunction`` If ``false``, empty function body can be put on a single line.
+ This option is used only if the opening brace of the function has
+ already been wrapped, i.e. the `AfterFunction` brace wrapping mode is
+ set, and the function could/should not be put on a single line (as per
+ `AllowShortFunctionsOnASingleLine` and constructor formatting options).
+
+ .. code-block:: c++
+
+ int f() vs. inf f()
+ {} {
+ }
+
+ * ``bool SplitEmptyRecord`` If ``false``, empty record (e.g. class, struct or union) body
+ can be put on a single line. This option is used only if the opening
+ brace of the record has already been wrapped, i.e. the `AfterClass`
+ (for classes) brace wrapping mode is set.
+
+ .. code-block:: c++
+
+ class Foo vs. class Foo
+ {} {
+ }
+
+ * ``bool SplitEmptyNamespace`` If ``false``, empty namespace body can be put on a single line.
+ This option is used only if the opening brace of the namespace has
+ already been wrapped, i.e. the `AfterNamespace` brace wrapping mode is
+ set.
+
+ .. code-block:: c++
+
+ namespace Foo vs. namespace Foo
+ {} {
+ }
+
**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.
@@ -623,12 +767,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``)
@@ -806,22 +983,45 @@ the configuration (without a prefix: ``Auto``).
? firstValue
: SecondValueVeryVeryVeryVeryLong;
- true:
+ false:
veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ?
firstValue :
SecondValueVeryVeryVeryVeryLong;
-**BreakConstructorInitializersBeforeComma** (``bool``)
- Always break constructor initializers before commas and align
- the commas with the colon.
+**BreakConstructorInitializers** (``BreakConstructorInitializersStyle``)
+ The constructor initializers style to use.
+
+ Possible values:
+
+ * ``BCIS_BeforeColon`` (in configuration: ``BeforeColon``)
+ Break constructor initializers before the colon and after the commas.
+
+ .. code-block:: c++
+
+ Constructor()
+ : initializer1(),
+ initializer2()
+
+ * ``BCIS_BeforeComma`` (in configuration: ``BeforeComma``)
+ Break constructor initializers before the colon and commas, and align
+ the commas with the colon.
+
+ .. code-block:: c++
+
+ Constructor()
+ : initializer1()
+ , initializer2()
+
+ * ``BCIS_AfterColon`` (in configuration: ``AfterColon``)
+ Break constructor initializers after the colon and commas.
+
+ .. code-block:: c++
+
+ Constructor() :
+ initializer1(),
+ initializer2()
- .. 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.
@@ -837,6 +1037,37 @@ 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
+
+**CompactNamespaces** (``bool``)
+ If ``true``, consecutive namespace declarations will be on the same
+ line. If ``false``, each namespace is declared on a new line.
+
+ .. code-block:: c++
+
+ true:
+ namespace Foo { namespace Bar {
+ }}
+
+ false:
+ namespace Foo {
+ namespace Bar {
+ }
+ }
+
+ If it does not fit on a single line, the overflowing namespaces get
+ wrapped:
+
+ .. code-block:: c++
+
+ namespace Foo { namespace Bar {
+ namespace Extra {
+ }}}
+
**ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``)
If the constructor initializers don't fit on a line, put each
initializer on its own line.
@@ -863,6 +1094,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.
@@ -878,10 +1117,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.
@@ -952,7 +1201,7 @@ the configuration (without a prefix: ``Auto``).
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- - Regex: '^(<|"(gtest|isl|json)/)'
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
@@ -976,13 +1225,74 @@ 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();
+ } }
+
+**IndentPPDirectives** (``PPDirectiveIndentStyle``)
+ The preprocessor directive indenting style to use.
+
+ Possible values:
+
+ * ``PPDIS_None`` (in configuration: ``None``)
+ Does not indent any directives.
+
+ .. code-block:: c++
+
+ #if FOO
+ #if BAR
+ #include <foo>
+ #endif
+ #endif
+
+ * ``PPDIS_AfterHash`` (in configuration: ``AfterHash``)
+ Indents directives after the hash.
+
+ .. code-block:: c++
+
+ #if FOO
+ # if BAR
+ # include <foo>
+ # endif
+ #endif
+
+
+
**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.
@@ -991,19 +1301,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.
@@ -1032,17 +1377,58 @@ the configuration (without a prefix: ``Auto``).
* ``LK_TableGen`` (in configuration: ``TableGen``)
Should be used for TableGen code.
+ * ``LK_TextProto`` (in configuration: ``TextProto``)
+ Should be used for Protocol Buffer messages in text format
+ (https://developers.google.com/protocol-buffers/).
+
**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.
@@ -1051,17 +1437,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)``.
@@ -1070,6 +1491,9 @@ the configuration (without a prefix: ``Auto``).
Add a space in front of an Objective-C protocol list, i.e. use
``Foo <Protocol>`` instead of ``Foo<Protocol>``.
+**PenaltyBreakAssignment** (``unsigned``)
+ The penalty for breaking around an assignment operator.
+
**PenaltyBreakBeforeFirstCallParameter** (``unsigned``)
The penalty for breaking a function call after ``call(``.
@@ -1120,6 +1544,18 @@ the configuration (without a prefix: ``Auto``).
**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``.
@@ -1129,6 +1565,15 @@ the configuration (without a prefix: ``Auto``).
#include "b.h" vs. #include "a.h"
#include "a.h" #include "b.h"
+**SortUsingDeclarations** (``bool``)
+ If ``true``, clang-format will sort using declarations.
+
+ .. code-block:: c++
+
+ false: true:
+ using std::cout; vs. using std::cin;
+ using std::cin; using std::cout;
+
**SpaceAfterCStyleCast** (``bool``)
If ``true``, a space is inserted after C style casts.
@@ -1162,21 +1607,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).
@@ -1185,6 +1664,15 @@ 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.
@@ -1207,6 +1695,12 @@ the configuration (without a prefix: ``Auto``).
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 ``)``.
@@ -1235,7 +1729,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.
@@ -1376,4 +1871,3 @@ The result is:
r();
}
}
-
diff --git a/docs/ControlFlowIntegrity.rst b/docs/ControlFlowIntegrity.rst
index eed5ac5120..12b4610f8a 100644
--- a/docs/ControlFlowIntegrity.rst
+++ b/docs/ControlFlowIntegrity.rst
@@ -215,6 +215,23 @@ shared library boundaries are handled as if the callee was not compiled with
This scheme is currently only supported on the x86 and x86_64 architectures.
+``-fsanitize-cfi-icall-generalize-pointers``
+--------------------------------------------
+
+Mismatched pointer types are a common cause of cfi-icall check failures.
+Translation units compiled with the ``-fsanitize-cfi-icall-generalize-pointers``
+flag relax pointer type checking for call sites in that translation unit,
+applied across all functions compiled with ``-fsanitize=cfi-icall``.
+
+Specifically, pointers in return and argument types are treated as equivalent as
+long as the qualifiers for the type they point to match. For example, ``char*``
+``char**`, and ``int*`` are considered equivalent types. However, ``char*`` and
+``const char*`` are considered separate types.
+
+``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
+``-fsanitize-cfi-cross-dso``.
+
+
``-fsanitize=cfi-icall`` and ``-fsanitize=function``
----------------------------------------------------
@@ -243,17 +260,25 @@ Blacklist
A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
source files, functions and types using the ``src``, ``fun`` and ``type``
-entity types.
+entity types. Specific CFI modes can be be specified using ``[section]``
+headers.
.. code-block:: bash
- # Suppress checking for code in a file.
+ # Suppress all CFI checking for code in a file.
src:bad_file.cpp
src:bad_header.h
# Ignore all functions with names containing MyFooBar.
fun:*MyFooBar*
# Ignore all types in the standard library.
type:std::*
+ # Disable only unrelated cast checks for this function
+ [cfi-unrelated-cast]
+ fun:*UnrelatedCast*
+ # Disable CFI call checks for this function without affecting cast checks
+ [cfi-vcall|cfi-nvcall|cfi-icall]
+ fun:*BadCall*
+
.. _cfi-cross-dso:
diff --git a/docs/ControlFlowIntegrityDesign.rst b/docs/ControlFlowIntegrityDesign.rst
index 552e891979..15e20e1e1d 100644
--- a/docs/ControlFlowIntegrityDesign.rst
+++ b/docs/ControlFlowIntegrityDesign.rst
@@ -92,7 +92,7 @@ The compiler relies on co-operation from the linker in order to assemble
the bit vectors for the whole program. It currently does this using LLVM's
`type metadata`_ mechanism together with link-time optimization.
-.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general
+.. _address point: http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-general
.. _type metadata: http://llvm.org/docs/TypeMetadata.html
.. _ByteArrayBuilder: http://llvm.org/docs/doxygen/html/structllvm_1_1ByteArrayBuilder.html
@@ -437,12 +437,17 @@ export this information, every DSO implements
.. code-block:: none
- void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr)
+ void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData)
-This function provides external modules with access to CFI checks for the
-targets inside this DSO. For each known ``CallSiteTypeId``, this function
-performs an ``llvm.type.test`` with the corresponding type identifier. It
-aborts if the type is unknown, or if the check fails.
+This function provides external modules with access to CFI checks for
+the targets inside this DSO. For each known ``CallSiteTypeId``, this
+function performs an ``llvm.type.test`` with the corresponding type
+identifier. It reports an error if the type is unknown, or if the
+check fails. Depending on the values of compiler flags
+``-fsanitize-trap`` and ``-fsanitize-recover``, this function may
+print an error, abort and/or return to the caller. ``DiagData`` is an
+opaque pointer to the diagnostic information about the error, or
+``null`` if the caller does not provide this information.
The basic implementation is a large switch statement over all values
of CallSiteTypeId supported by this DSO, and each case is similar to
@@ -452,11 +457,10 @@ CFI Shadow
----------
To route CFI checks to the target DSO's __cfi_check function, a
-mapping from possible virtual / indirect call targets to
-the corresponding __cfi_check functions is maintained. This mapping is
+mapping from possible virtual / indirect call targets to the
+corresponding __cfi_check functions is maintained. This mapping is
implemented as a sparse array of 2 bytes for every possible page (4096
-bytes) of memory. The table is kept readonly (FIXME: not yet) most of
-the time.
+bytes) of memory. The table is kept readonly most of the time.
There are 3 types of shadow values:
@@ -481,14 +485,24 @@ them.
CFI_SlowPath
------------
-The slow path check is implemented in compiler-rt library as
+The slow path check is implemented in a runtime support library as
.. code-block:: none
void __cfi_slowpath(uint64 CallSiteTypeId, void *TargetAddr)
+ void __cfi_slowpath_diag(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData)
-This functions loads a shadow value for ``TargetAddr``, finds the
-address of __cfi_check as described above and calls that.
+These functions loads a shadow value for ``TargetAddr``, finds the
+address of ``__cfi_check`` as described above and calls
+that. ``DiagData`` is an opaque pointer to diagnostic data which is
+passed verbatim to ``__cfi_check``, and ``__cfi_slowpath`` passes
+``nullptr`` instead.
+
+Compiler-RT library contains reference implementations of slowpath
+functions, but they have unresolvable issues with correctness and
+performance in the handling of dlopen(). It is recommended that
+platforms provide their own implementations, usually as part of libc
+or libdl.
Position-independent executable requirement
-------------------------------------------
@@ -498,12 +512,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).
diff --git a/docs/DiagnosticsReference.rst b/docs/DiagnosticsReference.rst
index ce100cbc87..e2b0bd7dd5 100644
--- a/docs/DiagnosticsReference.rst
+++ b/docs/DiagnosticsReference.rst
@@ -244,6 +244,21 @@ This diagnostic is an error by default, but the flag ``-Wno-address-of-temporary
------------------
This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
+-Waligned-allocation-unavailable
+--------------------------------
+This diagnostic is an error by default, but the flag ``-Wno-aligned-allocation-unavailable`` can be used to disable the error.
+
+**Diagnostic text:**
+
++--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| :diagtext:`aligned` |nbsp| |+------------------------+| |nbsp| :diagtext:`function of type '`:placeholder:`B`:diagtext:`' is only available on` |nbsp| :placeholder:`C` |nbsp| :placeholder:`D` |nbsp| :diagtext:`or newer`|
+| ||:diagtext:`allocation` || |
+| |+------------------------+| |
+| ||:diagtext:`deallocation`|| |
+| |+------------------------+| |
++--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wall
-----
Some of the diagnostics controlled by this flag are enabled by default.
@@ -745,6 +760,11 @@ This diagnostic is enabled by default.
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-Wbinary-literal
+----------------
+Controls `-Wc++14-binary-literal`_, `-Wc++98-c++11-compat-binary-literal`_, `-Wgnu-binary-literal`_.
+
+
-Wbind-to-temporary-copy
------------------------
Also controls `-Wc++98-compat-bind-to-temporary-copy`_.
@@ -797,6 +817,23 @@ This diagnostic is enabled by default.
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-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
----------------
This diagnostic is enabled by default.
@@ -833,6 +870,8 @@ This diagnostic is enabled by default.
-Wblock-capture-autoreleasing
-----------------------------
+This diagnostic is enabled by default.
+
**Diagnostic text:**
+-----------------------------------------------------------------------------------------------------------------------------+
@@ -953,7 +992,7 @@ Synonym for `-Wc++11-narrowing`_.
--------------
Some of the diagnostics controlled by this flag are enabled by default.
-Also controls `-Wc++11-compat-deprecated-writable-strings`_, `-Wc++11-compat-reserved-user-defined-literal`_, `-Wc++11-narrowing`_, `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_.
+Also controls `-Wc++11-compat-deprecated-writable-strings`_, `-Wc++11-compat-reserved-user-defined-literal`_, `-Wc++11-narrowing`_, `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_.
**Diagnostic text:**
@@ -1019,7 +1058,9 @@ This diagnostic is enabled by default.
-Wc++11-compat-pedantic
-----------------------
-Controls `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_.
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Controls `-Wc++11-compat`_, `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_.
-Wc++11-compat-reserved-user-defined-literal
@@ -1269,12 +1310,12 @@ Some of the diagnostics controlled by this flag are enabled by default.
-Wc++14-compat
--------------
-Synonym for `-Wc++98-c++11-c++14-compat`_.
+Controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_.
-Wc++14-compat-pedantic
-----------------------
-Synonym for `-Wc++98-c++11-c++14-compat-pedantic`_.
+Controls `-Wc++14-compat`_, `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_.
-Wc++14-extensions
@@ -1330,16 +1371,16 @@ Also controls `-Wc++14-binary-literal`_.
+-------------------------------------------------------------------------------+
--Wc++1y-extensions
-------------------
-Synonym for `-Wc++14-extensions`_.
+-Wc++17-compat
+--------------
+Some of the diagnostics controlled by this flag are enabled by default.
+Controls `-Wc++17-compat-mangling`_, `-Wc++98-c++11-c++14-c++17-compat`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
--Wc++1z-compat
---------------
-This diagnostic is enabled by default.
-Also controls `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
+-Wc++17-compat-mangling
+-----------------------
+This diagnostic is enabled by default.
**Diagnostic text:**
@@ -1348,42 +1389,49 @@ Also controls `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
--Wc++1z-extensions
+-Wc++17-compat-pedantic
+-----------------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Controls `-Wc++17-compat`_, `-Wc++98-c++11-c++14-c++17-compat-pedantic`_.
+
+
+-Wc++17-extensions
------------------
Some of the diagnostics controlled by this flag are enabled by default.
**Diagnostic text:**
+------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`constexpr if is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`constexpr if is a C++17 extension`|
+------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'constexpr' on lambda expressions is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`'constexpr' on lambda expressions is a C++17 extension`|
+---------------------------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++17 extension`|
+---------------------------------------------------------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are a C++17 extension`|
+---------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is a C++17 extension`|
+--------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'begin' and 'end' returning different types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`'begin' and 'end' returning different types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) is a C++17 extension`|
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++1z feature`|
+|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++17 feature`|
+----------------------------------------------------------------------------------------+
+----------------------------------------+--------------------+-------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'`|+------------------+|:diagtext:`' initialization statements are a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`'`|+------------------+|:diagtext:`' initialization statements are a C++17 extension`|
| ||:diagtext:`if` || |
| |+------------------+| |
| ||:diagtext:`switch`|| |
@@ -1391,68 +1439,145 @@ Some of the diagnostics controlled by this flag are enabled by default.
+----------------------------------------+--------------------+-------------------------------------------------------------+
+-----------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`inline variables are a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`inline variables are a C++17 extension`|
+-----------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is a C++17 extension`|
+---------------------------------------------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is a C++1z extension; define each namespace separately`|
+|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is a C++17 extension; define each namespace separately`|
+-------------------------------------------------------------------------------------------------------------------------+
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are a C++17 extension`|
+| ||:diagtext:`a namespace` || |
+| |+-------------------------+| |
+| ||:diagtext:`an enumerator`|| |
+| |+-------------------------+| |
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+
+---------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`capture of '\*this' by copy is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`capture of '\*this' by copy is a C++17 extension`|
+---------------------------------------------------------------------------------------+
+------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is a C++17 extension`|
+------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is a C++17 extension`|
+--------------------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is a C++17 extension`|
+--------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack expansion of using declaration is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`pack expansion of using declaration is a C++17 extension`|
+-----------------------------------------------------------------------------------------------+
+-Wc++1y-extensions
+------------------
+Synonym for `-Wc++14-extensions`_.
+
+
+-Wc++1z-compat
+--------------
+Synonym for `-Wc++17-compat`_.
+
+
+-Wc++1z-compat-mangling
+-----------------------
+Synonym for `-Wc++17-compat-mangling`_.
+
+
+-Wc++1z-extensions
+------------------
+Synonym for `-Wc++17-extensions`_.
+
+
+-Wc++2a-compat
+--------------
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a keyword in C++2a`|
++-------------------------------------------------------------------------------------------+
+
+
+-Wc++2a-compat-pedantic
+-----------------------
+Synonym for `-Wc++2a-compat`_.
+
+
+-Wc++2a-extensions
+------------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is a C++2a extension`|
++----------------------------------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is a C++2a extension`|
++--------------------------------------------------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension`|
++--------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wc++98-c++11-c++14-c++17-compat
+--------------------------------
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is incompatible with C++ standards before C++2a`|
++-------------------------------------------------------------------------------------------------------------------------------+
+
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is incompatible with C++ standards before C++2a`|
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wc++98-c++11-c++14-c++17-compat-pedantic
+-----------------------------------------
+Also controls `-Wc++98-c++11-c++14-c++17-compat`_.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is incompatible with C++ standards before C++2a`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wc++98-c++11-c++14-compat
--------------------------
**Diagnostic text:**
-+------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are incompatible with C++ standards before C++1z`|
-| ||:diagtext:`a namespace` || |
-| |+-------------------------+| |
-| ||:diagtext:`an enumerator`|| |
-| |+-------------------------+| |
-+------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
-
+---------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`constexpr if is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`constexpr if is incompatible with C++ standards before C++17`|
+---------------------------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`constexpr on lambda expressions is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`constexpr on lambda expressions is incompatible with C++ standards before C++17`|
+----------------------------------------------------------------------------------------------------------------------+
+------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are incompatible with C++ standards before C++17`|
+------------------------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is incompatible with C++ standards before C++17`|
+-----------------------------------------------------------------------------------------------------------+
+---------------------------+--------------------+----------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| |+------------------+| |nbsp| :diagtext:`initialization statements are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| |+------------------+| |nbsp| :diagtext:`initialization statements are incompatible with C++ standards before C++17`|
| ||:diagtext:`if` || |
| |+------------------+| |
| ||:diagtext:`switch`|| |
@@ -1460,47 +1585,47 @@ Some of the diagnostics controlled by this flag are enabled by default.
+---------------------------+--------------------+----------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`inline variables are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`inline variables are incompatible with C++ standards before C++17`|
+--------------------------------------------------------------------------------------------------------+
+------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is incompatible with C++ standards before C++17`|
+------------------------------------------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`by value capture of '\*this' is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`by value capture of '\*this' is incompatible with C++ standards before C++17`|
+-------------------------------------------------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is incompatible with C++ standards before C++17`|
+---------------------------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|: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:`non-type template parameters declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`are incompatible with C++ standards before C++17`|
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is incompatible with C++ standards before C++17`|
+-----------------------------------------------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`unicode literals are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`unicode literals are incompatible with C++ standards before C++17`|
+--------------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is incompatible with C++ standards before C++17`|
+-----------------------------------------------------------------------------------------------------------------------------+
+------------------------------------------------------------------------------------------------------------------------------------------------+
-|: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:`use of multiple declarators in a single using declaration is incompatible with C++ standards before C++17`|
+------------------------------------------------------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack expansion 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++17`|
+-----------------------------------------------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|: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`|
+|: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++17`|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -1510,8 +1635,16 @@ Also controls `-Wc++98-c++11-c++14-compat`_.
**Diagnostic text:**
++------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are incompatible with C++ standards before C++17`|
+| ||:diagtext:`a namespace` || |
+| |+-------------------------+| |
+| ||:diagtext:`an enumerator`|| |
+| |+-------------------------+| |
++------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
+
+---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are incompatible with C++ standards before C++17`|
+---------------------------------------------------------------------------------------------------------------------+
@@ -1568,10 +1701,8 @@ Also controls `-Wc++98-c++11-c++14-compat`_.
+----------------------------------------------------------------------------------------------------------+
--Wc++98-c++11-compat-pedantic
------------------------------
-Also controls `-Wc++98-c++11-compat`_.
-
+-Wc++98-c++11-compat-binary-literal
+-----------------------------------
**Diagnostic text:**
+---------------------------------------------------------------------------------------------------------------+
@@ -1579,9 +1710,14 @@ Also controls `-Wc++98-c++11-compat`_.
+---------------------------------------------------------------------------------------------------------------+
+-Wc++98-c++11-compat-pedantic
+-----------------------------
+Controls `-Wc++98-c++11-compat`_, `-Wc++98-c++11-compat-binary-literal`_.
+
+
-Wc++98-compat
--------------
-Also controls `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_, `-Wc++98-compat-local-type-template-args`_, `-Wc++98-compat-unnamed-type-template-args`_.
+Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_, `-Wc++98-compat-local-type-template-args`_, `-Wc++98-compat-unnamed-type-template-args`_.
**Diagnostic text:**
@@ -1922,7 +2058,7 @@ Also controls `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_, `-Wc++98-c
-Wc++98-compat-pedantic
-----------------------
-Also controls `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_.
+Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_.
**Diagnostic text:**
@@ -2380,7 +2516,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:**
@@ -2414,6 +2550,22 @@ Also controls `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion
Synonym for `-Wnull-conversion`_.
+-Wcoroutine
+-----------
+Synonym for `-Wcoroutine-missing-unhandled-exception`_.
+
+
+-Wcoroutine-missing-unhandled-exception
+---------------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is required to declare the member 'unhandled\_exception()' when exceptions are enabled`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wcovered-switch-default
------------------------
**Diagnostic text:**
@@ -2423,6 +2575,11 @@ Synonym for `-Wnull-conversion`_.
+--------------------------------------------------------------------------------------------------+
+-Wcpp
+-----
+Synonym for `-W#warnings`_.
+
+
-Wcstring-format-directive
--------------------------
**Diagnostic text:**
@@ -2686,6 +2843,10 @@ This diagnostic is enabled by default.
**Diagnostic text:**
++--------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`specifying 'uuid' as an ATL attribute is deprecated; use \_\_declspec instead`|
++--------------------------------------------------------------------------------------------------------------------+
+
+-----------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`use of C-style parameters in Objective-C method declarations is deprecated`|
+-----------------------------------------------------------------------------------------------------------------+
@@ -2721,7 +2882,7 @@ This diagnostic is enabled by default.
**Diagnostic text:**
+----------------------------------------------------------------------+----------------------+
-|:warning:`warning:` |nbsp| :diagtext:`Implementing deprecated` |nbsp| |+--------------------+|
+|:warning:`warning:` |nbsp| :diagtext:`implementing deprecated` |nbsp| |+--------------------+|
| ||:diagtext:`method` ||
| |+--------------------+|
| ||:diagtext:`class` ||
@@ -2730,6 +2891,10 @@ This diagnostic is enabled by default.
| |+--------------------+|
+----------------------------------------------------------------------+----------------------+
++----------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`implementing unavailable method`|
++----------------------------------------------------------------------+
+
-Wdeprecated-increment-bool
---------------------------
@@ -2738,7 +2903,7 @@ This diagnostic is enabled by default.
**Diagnostic text:**
+---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`incrementing expression of type bool is deprecated and incompatible with C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`incrementing expression of type bool is deprecated and incompatible with C++17`|
+---------------------------------------------------------------------------------------------------------------------+
@@ -2788,7 +2953,7 @@ This diagnostic is enabled by default.
**Diagnostic text:**
+-------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'register' storage class specifier is deprecated and incompatible with C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`'register' storage class specifier is deprecated and incompatible with C++17`|
+-------------------------------------------------------------------------------------------------------------------+
@@ -3197,7 +3362,7 @@ Also controls `-Wdeprecated-dynamic-exception-spec`_.
**Diagnostic text:**
+--------------------------------------------------------------------------------------------+
-|:error:`error:` |nbsp| :diagtext:`ISO C++1z does not allow dynamic exception specifications`|
+|:error:`error:` |nbsp| :diagtext:`ISO C++17 does not allow dynamic exception specifications`|
+--------------------------------------------------------------------------------------------+
@@ -3249,7 +3414,7 @@ This diagnostic is enabled by default.
**Diagnostic text:**
+-------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`ISO C++1z does not allow a decomposition group to be empty`|
+|:warning:`warning:` |nbsp| :diagtext:`ISO C++17 does not allow a decomposition group to be empty`|
+-------------------------------------------------------------------------------------------------+
@@ -3282,6 +3447,8 @@ Synonym for `-Wextra-tokens`_.
--------------
This diagnostic is enabled by default.
+Also controls `-Wenum-compare-switch`_.
+
**Diagnostic text:**
+------------------------------------------------------------------------------------------------+
@@ -3289,6 +3456,17 @@ This diagnostic is enabled by default.
+------------------------------------------------------------------------------------------------+
+-Wenum-compare-switch
+---------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison of two values with different enumeration types in switch statement`|
++--------------------------------------------------------------------------------------------------------------------+
+
+
-Wenum-conversion
-----------------
This diagnostic is enabled by default.
@@ -3333,6 +3511,10 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`exception of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`will be caught by earlier handler`|
+-------------------------------------------------------------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has a non-throwing exception specification but can still throw`|
++-----------------------------------------------------------------------------------------------------------------------------+
+
-Wexit-time-destructors
-----------------------
@@ -3421,7 +3603,7 @@ This diagnostic is enabled by default.
-------
Some of the diagnostics controlled by this flag are enabled by default.
-Also 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`_, `-Wnull-pointer-arithmetic`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_.
**Diagnostic text:**
@@ -4287,6 +4469,10 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute ignored`|
+--------------------------------------------------------------------------------+
++--------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute ignored for field of type` |nbsp| :placeholder:`B`|
++--------------------------------------------------------------------------------------------------------------------------+
+
+---------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute ignored on inline function`|
+---------------------------------------------------------------------------------------------------+
@@ -4423,6 +4609,8 @@ This diagnostic is enabled by default.
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`methods and properties` ||
| |+----------------------------------------------------------------------------------------------------------------+|
+| ||:diagtext:`functions, methods, and properties` ||
+| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`struct or union` ||
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`struct, union or class` ||
@@ -4463,6 +4651,8 @@ This diagnostic is enabled by default.
| |+----------------------------------------------------------------------------------------------------------------+|
| ||:diagtext:`classes and enumerations` ||
| |+----------------------------------------------------------------------------------------------------------------+|
+| ||:diagtext:`named declarations` ||
+| |+----------------------------------------------------------------------------------------------------------------+|
+------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+
+--------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -4613,9 +4803,13 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`\_\_declspec attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not supported`|
+-------------------------------------------------------------------------------------------------------------------------+
-+-------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`Ignoring unsupported '`:placeholder:`A`:diagtext:`' in the target attribute string`|
-+-------------------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring` |nbsp| |+-----------------------+|+--------------------------------+| |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' in the target attribute string`|
+| ||:diagtext:`unsupported`||| || |
+| |+-----------------------+|+--------------------------------+| |
+| ||:diagtext:`duplicate` ||| |nbsp| :diagtext:`architecture`|| |
+| |+-----------------------+|+--------------------------------+| |
++-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+
-Wignored-optimization-argument
@@ -4938,9 +5132,13 @@ Some of the diagnostics controlled by this flag are enabled by default.
**Diagnostic text:**
-+------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in C99`|
-+------------------------------------------------------------------------------------------------------------------------------------+
++----------------------------------------------------------------------------------------------------------------------------------------+--------------------+
+|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in` |nbsp| |+------------------+|
+| ||:diagtext:`C99` ||
+| |+------------------+|
+| ||:diagtext:`OpenCL`||
+| |+------------------+|
++----------------------------------------------------------------------------------------------------------------------------------------+--------------------+
+---------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`implicitly declaring library function '`:placeholder:`A`:diagtext:`' with type` |nbsp| :placeholder:`B`|
@@ -5218,6 +5416,10 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`missing submodule '`:placeholder:`A`:diagtext:`'`|
+---------------------------------------------------------------------------------------+
++--------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`umbrella directory '`:placeholder:`A`:diagtext:`' not found`|
++--------------------------------------------------------------------------------------------------+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`umbrella header for module '`:placeholder:`A`:diagtext:`' does not include header '`:placeholder:`B`:diagtext:`'`|
+-------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -5238,6 +5440,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.
@@ -5258,7 +5469,7 @@ Also controls `-Wdeprecated-increment-bool`_.
**Diagnostic text:**
+------------------------------------------------------------------------------------------------+
-|:error:`error:` |nbsp| :diagtext:`ISO C++1z does not allow incrementing expression of type bool`|
+|:error:`error:` |nbsp| :diagtext:`ISO C++17 does not allow incrementing expression of type bool`|
+------------------------------------------------------------------------------------------------+
@@ -5431,6 +5642,10 @@ Also controls `-Wignored-optimization-argument`_.
**Diagnostic text:**
++-----------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`the object size sanitizer has no effect at -O0, but is explicitly enabled:` |nbsp| :placeholder:`A`|
++-----------------------------------------------------------------------------------------------------------------------------------------+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`optimization level '`:placeholder:`A`:diagtext:`' is not supported; using '`:placeholder:`B`:placeholder:`C`:diagtext:`' instead`|
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -5481,6 +5696,17 @@ This diagnostic is enabled by default.
+--------------------------------------------------------------------------------------------------------------+
+-Winvalid-ios-deployment-target
+-------------------------------
+This diagnostic is an error by default, but the flag ``-Wno-invalid-ios-deployment-target`` can be used to disable the error.
+
+**Diagnostic text:**
+
++------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| :diagtext:`invalid iOS deployment version '`:placeholder:`A`:diagtext:`', iOS 10 is the maximum deployment target for 32-bit targets`|
++------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Winvalid-noreturn
------------------
This diagnostic is enabled by default.
@@ -5972,6 +6198,8 @@ This diagnostic is enabled by default.
-Wmicrosoft-enum-forward-reference
----------------------------------
+This diagnostic is enabled by default.
+
**Diagnostic text:**
+---------------------------------------------------------------------------------------------------+
@@ -5981,8 +6209,6 @@ This diagnostic is enabled by default.
-Wmicrosoft-enum-value
----------------------
-This diagnostic is enabled by default.
-
**Diagnostic text:**
+---------------------------------------------------------------------------------------------------------------------------+
@@ -6392,6 +6618,17 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
+--------------------------------------------------------------------------------------------+
+-Wmissing-noescape
+------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`parameter of overriding method should be annotated with \_\_attribute\_\_((noescape))`|
++----------------------------------------------------------------------------------------------------------------------------+
+
+
-Wmissing-noreturn
------------------
**Diagnostic text:**
@@ -6472,6 +6709,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
-----------------
@@ -6483,6 +6728,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
-----------------------------
@@ -6543,7 +6792,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`_, `-Wuser-defined-warnings`_, `-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-flexible-array`_, `-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
@@ -6556,6 +6805,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.
@@ -6628,6 +6888,11 @@ This diagnostic is enabled by default.
+----------------------------------------------------------------+
+-Wnoexcept-type
+---------------
+Synonym for `-Wc++17-compat-mangling`_.
+
+
-Wnon-gcc
---------
Some of the diagnostics controlled by this flag are enabled by default.
@@ -6768,6 +7033,32 @@ This diagnostic is enabled by default.
+---------------------------------------------------------------------------------------------------------------------+
+-Wnsconsumed-mismatch
+---------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`overriding method has mismatched ns\_consumed attribute on its parameter`|
++---------------------------------------------------------------------------------------------------------------+
+
+
+-Wnsreturns-mismatch
+--------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------+---------------------------+------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`overriding method has mismatched ns\_returns\_`|+-------------------------+| |nbsp| :diagtext:`attributes`|
+| ||:diagtext:`not\_retained`|| |
+| |+-------------------------+| |
+| ||:diagtext:`retained` || |
+| |+-------------------------+| |
++-------------------------------------------------------------------------------------+---------------------------+------------------------------+
+
+
-Wnull-arithmetic
-----------------
This diagnostic is enabled by default.
@@ -6840,6 +7131,23 @@ This diagnostic is enabled by default.
+---------------------------------------------------------------------------------------------------------+
+-Wnull-pointer-arithmetic
+-------------------------
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension`|
++--------------------------------------------------------------------------------------------------------------------------------+
+
++-------------------------------------------------------------------------------------------------------------+----------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`performing pointer arithmetic on a null pointer has undefined behavior`|+--------------------------------------------+|
+| || ||
+| |+--------------------------------------------+|
+| || |nbsp| :diagtext:`if the offset is nonzero`||
+| |+--------------------------------------------+|
++-------------------------------------------------------------------------------------------------------------+----------------------------------------------+
+
+
-Wnullability
-------------
This diagnostic is enabled by default.
@@ -7013,6 +7321,21 @@ This diagnostic is enabled by default.
+----------------------------------------------------------------------------------------------------------+
+-Wobjc-flexible-array
+---------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`can overwrite instance variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`with variable sized type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`in superclass` |nbsp| :placeholder:`D`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with variable sized type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is not visible to subclasses and can conflict with their instance variables`|
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wobjc-forward-class-redefinition
---------------------------------
This diagnostic is enabled by default.
@@ -7088,6 +7411,15 @@ This diagnostic is enabled by default.
+-------------------------------------------------------------------------------------------+
+-Wobjc-messaging-id
+-------------------
+**Diagnostic text:**
+
++---------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`messaging unqualified id`|
++---------------------------------------------------------------+
+
+
-Wobjc-method-access
--------------------
This diagnostic is enabled by default.
@@ -7344,6 +7676,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.
@@ -7434,10 +7783,26 @@ This diagnostic is enabled by default.
**Diagnostic text:**
++------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored`|
++------------------------------------------------------------------------------------------------------------------------------------------+
+
+----------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`option '`:placeholder:`A`:diagtext:`' was ignored by the PS4 toolchain, using '-fPIC'`|
+----------------------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabicalls' option as it cannot be used with non position-independent code and the N64 ABI`|
++-------------------------------------------------------------------------------------------------------------------------------------------+
+
++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mlong-calls' option as it is not currently supported with` |nbsp| |+-----------------------------------------+|:diagtext:`-mabicalls`|
+| || || |
+| |+-----------------------------------------+| |
+| ||:diagtext:`the implicit usage of` |nbsp| || |
+| |+-----------------------------------------+| |
++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+
-Wout-of-line-declaration
-------------------------
@@ -7450,6 +7815,21 @@ This diagnostic is an error by default, but the flag ``-Wno-out-of-line-declarat
+-------------------------------------------------------------------------------------------+
+-Wout-of-scope-function
+-----------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`use of out-of-scope declaration of` |nbsp| :placeholder:`A`|+-------------------------------------------------------------------------------------+|
+| || ||
+| |+-------------------------------------------------------------------------------------+|
+| || |nbsp| :diagtext:`whose type is not compatible with that of an implicit declaration`||
+| |+-------------------------------------------------------------------------------------+|
++-------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------+
+
+
-Wover-aligned
--------------
**Diagnostic text:**
@@ -7695,7 +8075,7 @@ This diagnostic is enabled by default.
-Wpedantic
----------
-Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wextended-offsetof`_, `-Wflexible-array-extensions`_, `-Wformat-pedantic`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-forward-reference`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wvariadic-macros`_, `-Wvla-extension`_, `-Wzero-length-array`_.
+Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wextended-offsetof`_, `-Wflexible-array-extensions`_, `-Wformat-pedantic`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wundefined-internal-type`_, `-Wvla-extension`_, `-Wzero-length-array`_.
**Diagnostic text:**
@@ -7761,6 +8141,10 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
|:warning:`warning:` |nbsp| :diagtext:`parameter` |nbsp| :placeholder:`A` |nbsp| :diagtext:`was not declared, defaulting to type 'int'`|
+--------------------------------------------------------------------------------------------------------------------------------------+
++--------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension`|
++--------------------------------------------------------------------------------------------------------------------------+
+
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`qualifier in explicit instantiation of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`requires a template-id (a typedef is not permitted)`|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -7914,7 +8298,7 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
+---------------------------------------------------------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++17 extension`|
+---------------------------------------------------------------------------------------------------------------------------+
+-----------------------------------------------------------------------------+--------------------+---------------------------------------------+
@@ -7999,6 +8383,14 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
|:warning:`warning:` |nbsp| :diagtext:`exception specification of '...' is a Microsoft extension`|
+------------------------------------------------------------------------------------------------+
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are a C++17 extension`|
+| ||:diagtext:`a namespace` || |
+| |+-------------------------+| |
+| ||:diagtext:`an enumerator`|| |
+| |+-------------------------+| |
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+
+-----------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`extern templates are a C++11 extension`|
+-----------------------------------------------------------------------------+
@@ -8024,7 +8416,7 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
+---------------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++1z feature`|
+|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++17 feature`|
+----------------------------------------------------------------------------------------+
+---------------------------------------------------------------------+
@@ -8043,6 +8435,14 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
|:warning:`warning:` |nbsp| :diagtext:`\_\_VA\_ARGS\_\_ can only appear in the expansion of a C99 variadic macro`|
+----------------------------------------------------------------------------------------------------------------+
++------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`variadic macros are a C99 feature`|
++------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`named variadic macros are a GNU extension`|
++--------------------------------------------------------------------------------+
+
+------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`empty macro arguments are a C99 feature`|
+------------------------------------------------------------------------------+
@@ -8207,6 +8607,17 @@ This diagnostic is enabled by default.
+----------------------------------------------------------------------------------------------------------------------------------+
+-Wpragma-clang-attribute
+------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unused attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in '#pragma clang attribute push' region`|
++-------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wpragma-once-outside-header
----------------------------
This diagnostic is enabled by default.
@@ -8218,6 +8629,32 @@ This diagnostic is enabled by default.
+----------------------------------------------------------------+
+-Wpragma-pack
+-------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Also controls `-Wpragma-pack-suspicious-include`_.
+
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`the current #pragma pack aligment value is modified in the included file`|
++---------------------------------------------------------------------------------------------------------------+
+
++---------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unterminated '#pragma pack (push, ...)' at end of file`|
++---------------------------------------------------------------------------------------------+
+
+
+-Wpragma-pack-suspicious-include
+--------------------------------
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`non-default #pragma pack value changes the alignment of struct or union members in the included file`|
++-------------------------------------------------------------------------------------------------------------------------------------------+
+
+
-Wpragma-system-header-outside-header
-------------------------------------
This diagnostic is enabled by default.
@@ -8233,7 +8670,7 @@ This diagnostic is enabled by default.
---------
Some of the diagnostics controlled by this flag are enabled by default.
-Also controls `-Wignored-pragmas`_, `-Wunknown-pragmas`_.
+Also controls `-Wignored-pragmas`_, `-Wpragma-clang-attribute`_, `-Wpragma-pack`_, `-Wunknown-pragmas`_.
**Diagnostic text:**
@@ -8289,6 +8726,23 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`top-level module '`:placeholder:`A`:diagtext:`' in private module map, expected a submodule of '`:placeholder:`B`:diagtext:`'`|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
++----------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`module '`:placeholder:`A`:diagtext:`' already re-exported as '`:placeholder:`B`:diagtext:`'`|
++----------------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wprofile-instr-missing
+-----------------------
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`profile data may be incomplete: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`no data`|
+| || || ||:diagtext:`:has` || |
+| |+-------------+| |+-----------------+| |
+| ||:diagtext:`s`|| ||:diagtext:`:have`|| |
+| |+-------------+| |+-----------------+| |
++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+
+
-Wprofile-instr-out-of-date
---------------------------
@@ -8296,13 +8750,13 @@ This diagnostic is enabled by default.
**Diagnostic text:**
-+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------------------------------------------+-------------------+--------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`no data and` |nbsp| :placeholder:`C` |nbsp| |+-----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`|
-| || || ||:diagtext:`:has` || ||:diagtext:`:has` || |
-| |+-------------+| |+-----------------+| |+-----------------+| |
-| ||:diagtext:`s`|| ||:diagtext:`:have`|| ||:diagtext:`:have`|| |
-| |+-------------+| |+-----------------+| |+-----------------+| |
-+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------------------------------------------+-------------------+--------------------------------------------------------+
++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`|
+| || || ||:diagtext:`:has` || |
+| |+-------------+| |+-----------------+| |
+| ||:diagtext:`s`|| ||:diagtext:`:have`|| |
+| |+-------------+| |+-----------------+| |
++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+
-Wprofile-instr-unprofiled
@@ -8367,9 +8821,29 @@ This diagnostic is enabled by default.
**Diagnostic text:**
-+-----------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`property of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`was selected for synthesis`|
-+-----------------------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------+----------------------------------------------------------------+----------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| |+--------------------------------------------------------------+| |nbsp| :diagtext:`was selected for synthesis`|
+| ||+-------------------------------------------+ || |
+| |||:diagtext:`of type` |nbsp| :placeholder:`B`| || |
+| ||+-------------------------------------------+ || |
+| |+--------------------------------------------------------------+| |
+| ||+---------------------------------------------------------+ || |
+| |||:diagtext:`with attribute '`:placeholder:`B`:diagtext:`'`| || |
+| ||+---------------------------------------------------------+ || |
+| |+--------------------------------------------------------------+| |
+| ||+------------------------------------------------------------+|| |
+| |||:diagtext:`without attribute '`:placeholder:`B`:diagtext:`'`||| |
+| ||+------------------------------------------------------------+|| |
+| |+--------------------------------------------------------------+| |
+| ||+-----------------------------------------------+ || |
+| |||:diagtext:`with getter` |nbsp| :placeholder:`B`| || |
+| ||+-----------------------------------------------+ || |
+| |+--------------------------------------------------------------+| |
+| ||+-----------------------------------------------+ || |
+| |||:diagtext:`with setter` |nbsp| :placeholder:`B`| || |
+| ||+-----------------------------------------------+ || |
+| |+--------------------------------------------------------------+| |
++-------------------------------------------------------+----------------------------------------------------------------+----------------------------------------------+
-Wqualified-void-return-type
@@ -8461,6 +8935,15 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
+-------------------------------------------------------------------------+
+-Wredundant-parens
+------------------
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`redundant parentheses surrounding declarator`|
++-----------------------------------------------------------------------------------+
+
+
-Wregister
----------
This diagnostic is enabled by default.
@@ -8470,7 +8953,7 @@ Also controls `-Wdeprecated-register`_.
**Diagnostic text:**
+----------------------------------------------------------------------------------------------+
-|:error:`error:` |nbsp| :diagtext:`ISO C++1z does not allow 'register' storage class specifier`|
+|:error:`error:` |nbsp| :diagtext:`ISO C++17 does not allow 'register' storage class specifier`|
+----------------------------------------------------------------------------------------------+
@@ -8614,9 +9097,9 @@ 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 coroutine; which is undefined behavior because the promise type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not declare 'return\_void()'`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void function`|
@@ -8626,9 +9109,9 @@ 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 coroutine; which is undefined behavior because the promise type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not declare 'return\_void()'`|
++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+---------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`control may reach end of non-void function`|
@@ -8708,6 +9191,10 @@ This diagnostic is enabled by default.
**Diagnostic text:**
++--------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`section attribute is specified on redeclared variable`|
++--------------------------------------------------------------------------------------------+
+
+----------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`section does not match previous declaration`|
+----------------------------------------------------------------------------------+
@@ -8844,6 +9331,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`| ||
+| ||+-------------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+--------------------------------------------------------------------+-------------------------------------------------------------+
@@ -8851,7 +9346,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`_, `-Wshadow-uncaptured-local`_.
+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
@@ -8905,6 +9409,14 @@ This diagnostic is enabled by default.
| |||:diagtext:`field of` |nbsp| :placeholder:`C`| ||
| ||+--------------------------------------------+ ||
| |+-----------------------------------------------------------+|
+| ||+----------------------------------------------+ ||
+| |||:diagtext:`typedef in` |nbsp| :placeholder:`C`| ||
+| ||+----------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+| ||+-------------------------------------------------+ ||
+| |||:diagtext:`type alias in` |nbsp| :placeholder:`C`| ||
+| ||+-------------------------------------------------+ ||
+| |+-----------------------------------------------------------+|
+--------------------------------------------------------------------+-------------------------------------------------------------+
@@ -9057,6 +9569,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:**
@@ -9253,6 +9776,8 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
|:warning:`warning:` |nbsp| :diagtext:`this` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`a prototype`|
| ||:diagtext:`function declaration is not` || |
| |+------------------------------------------------------------+| |
+| ||:diagtext:`block declaration is not` || |
+| |+------------------------------------------------------------+| |
| ||:diagtext:`old-style function definition is not preceded by`|| |
| |+------------------------------------------------------------+| |
+---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
@@ -9266,6 +9791,8 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
|:warning:`warning:` |nbsp| :diagtext:`this` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`a prototype`|
| ||:diagtext:`function declaration is not` || |
| |+------------------------------------------------------------+| |
+| ||:diagtext:`block declaration is not` || |
+| |+------------------------------------------------------------+| |
| ||:diagtext:`old-style function definition is not preceded by`|| |
| |+------------------------------------------------------------+| |
+---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
@@ -9459,7 +9986,7 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
----------------------
Some of the diagnostics controlled by this flag are enabled by default.
-Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_.
+Also controls `-Wtautological-constant-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_.
**Diagnostic text:**
@@ -9481,21 +10008,22 @@ Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-o
| |+-----------------+|
+-------------------------------------------------------------------------------------+-------------------+
-+-------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`comparison of unsigned`|+------------------------+| |nbsp| :diagtext:`expression` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is always` |nbsp| :placeholder:`B`|
-| || || |
-| |+------------------------+| |
-| || |nbsp| :diagtext:`enum`|| |
-| |+------------------------+| |
-+-------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------------------------------------------+
-+--------------------------------------------------------------------------------------------------------+--------------------------+----------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`unsigned`|+------------------------+| |nbsp| :diagtext:`expression is always` |nbsp| :placeholder:`B`|
-| || || |
-| |+------------------------+| |
-| || |nbsp| :diagtext:`enum`|| |
-| |+------------------------+| |
-+--------------------------------------------------------------------------------------------------------+--------------------------+----------------------------------------------------------------+
+-Wtautological-constant-compare
+-------------------------------
+This diagnostic is enabled by default.
+
+Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-unsigned-enum-zero-compare`_, `-Wtautological-unsigned-zero-compare`_.
+
+**Diagnostic text:**
+
++---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison` |nbsp| |+----------------+| |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+|
+| ||:placeholder:`D`|| ||:placeholder:`B`|| ||:diagtext:`false`||
+| |+----------------+| |+----------------+| |+-----------------+|
+| ||:placeholder:`B`|| ||:placeholder:`D`|| ||:diagtext:`true` ||
+| |+----------------+| |+----------------+| |+-----------------+|
++---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+
-Wtautological-constant-out-of-range-compare
@@ -9578,6 +10106,36 @@ This diagnostic is enabled by default.
+------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+
+-Wtautological-unsigned-enum-zero-compare
+-----------------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+------------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+|
+| ||:placeholder:`D` || ||:diagtext:`unsigned enum expression`|| ||:diagtext:`false`||
+| |+------------------------------------+| |+------------------------------------+| |+-----------------+|
+| ||:diagtext:`unsigned enum expression`|| ||:placeholder:`D` || ||:diagtext:`true` ||
+| |+------------------------------------+| |+------------------------------------+| |+-----------------+|
++------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+
+
+
+-Wtautological-unsigned-zero-compare
+------------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+-------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+|
+| ||:placeholder:`D` || ||:diagtext:`unsigned expression`|| ||:diagtext:`false`||
+| |+-------------------------------+| |+-------------------------------+| |+-----------------+|
+| ||:diagtext:`unsigned expression`|| ||:placeholder:`D` || ||:diagtext:`true` ||
+| |+-------------------------------+| |+-------------------------------+| |+-----------------+|
++------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+
+
+
-Wtentative-definition-incomplete-type
--------------------------------------
This diagnostic is enabled by default.
@@ -9993,6 +10551,19 @@ This diagnostic is enabled by default.
+---------------------------+----------------------+-----------------------------------------------------------------------------------+
+-Wundefined-internal-type
+-------------------------
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------+----------------------+----------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ISO C++ requires a definition in this translation unit for` |nbsp| |+--------------------+| |nbsp| :placeholder:`B` |nbsp| :diagtext:`because its type does not have linkage`|
+| ||:diagtext:`function`|| |
+| |+--------------------+| |
+| ||:diagtext:`variable`|| |
+| |+--------------------+| |
++---------------------------------------------------------------------------------------------------------+----------------------+----------------------------------------------------------------------------------+
+
+
-Wundefined-reinterpret-cast
----------------------------
**Diagnostic text:**
@@ -10032,19 +10603,22 @@ Also controls `-Wpotentially-evaluated-expression`_.
-Wunguarded-availability
------------------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Also controls `-Wunguarded-availability-new`_.
+
**Diagnostic text:**
-+----------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is only available conditionally`|
-+----------------------------------------------------------------------------------------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is only available on` |nbsp| :placeholder:`B` |nbsp| :placeholder:`C` |nbsp| :diagtext:`or newer`|
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+
-+------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`may be partial because the receiver type is unknown`|
-+------------------------------------------------------------------------------------------------------------------+
-+--------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is partial:` |nbsp| :placeholder:`B`|
-+--------------------------------------------------------------------------------------------------+
+-Wunguarded-availability-new
+----------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+---------------------------------------------------------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is only available on` |nbsp| :placeholder:`B` |nbsp| :placeholder:`C` |nbsp| :diagtext:`or newer`|
@@ -10197,10 +10771,6 @@ Some of the diagnostics controlled by this flag are enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`unexpected token in pragma diagnostic`|
+----------------------------------------------------------------------------+
-+----------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`unknown warning group '`:placeholder:`A`:diagtext:`', ignored`|
-+----------------------------------------------------------------------------------------------------+
-
+-------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`unknown pragma ignored`|
+-------------------------------------------------------------+
@@ -10259,6 +10829,10 @@ This diagnostic is enabled by default.
**Diagnostic text:**
++----------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unknown warning group '`:placeholder:`A`:diagtext:`', ignored`|
++----------------------------------------------------------------------------------------------------+
+
+------------------------------------------------------+---------------------+---------------------------------------------------------+--------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`unknown` |nbsp| |+-------------------+| |nbsp| :diagtext:`option '`:placeholder:`B`:diagtext:`'`|+------------------------------------------------------------+|
| ||:diagtext:`warning`|| || ||
@@ -10371,6 +10945,36 @@ This diagnostic is enabled by default.
+-----------------------------------------------------------------------------------------------------+
+-Wunsupported-abs
+-----------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabs=2008' option because the '`:placeholder:`A`:diagtext:`' architecture does not support it`|
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+
++-------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabs=legacy' option because the '`:placeholder:`A`:diagtext:`' architecture does not support it`|
++-------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wunsupported-availability-guard
+--------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++---------------------------+------------------------------------+--------------------------------------------------------------+------------------------------------+---------------------+
+|:warning:`warning:` |nbsp| |+----------------------------------+| |nbsp| :diagtext:`does not guard availability here; use if (`|+----------------------------------+|:diagtext:`) instead`|
+| ||:diagtext:`@available` || ||:diagtext:`@available` || |
+| |+----------------------------------+| |+----------------------------------+| |
+| ||:diagtext:`\_\_builtin\_available`|| ||:diagtext:`\_\_builtin\_available`|| |
+| |+----------------------------------+| |+----------------------------------+| |
++---------------------------+------------------------------------+--------------------------------------------------------------+------------------------------------+---------------------+
+
+
-Wunsupported-cb
----------------
This diagnostic is enabled by default.
@@ -10410,6 +11014,21 @@ This diagnostic is enabled by default.
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-Wunsupported-gpopt
+-------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mgpopt' option as it cannot be used with` |nbsp| |+-----------------------------------------+|:diagtext:`-mabicalls`|
+| || || |
+| |+-----------------------------------------+| |
+| ||:diagtext:`the implicit usage of` |nbsp| || |
+| |+-----------------------------------------+| |
++--------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+
+
-Wunsupported-nan
-----------------
This diagnostic is enabled by default.
@@ -10468,14 +11087,14 @@ This diagnostic is enabled by default.
**Diagnostic text:**
++-------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`argument '`:placeholder:`A`:diagtext:`' requires profile-guided optimization information`|
++-------------------------------------------------------------------------------------------------------------------------------+
+
+---------------------------------------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`joined argument expects additional value: '`:placeholder:`A`:diagtext:`'`|
+---------------------------------------------------------------------------------------------------------------+
-+-----------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`argument '-fdiagnostics-show-hotness' requires profile-guided optimization information`|
-+-----------------------------------------------------------------------------------------------------------------------------+
-
+----------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :placeholder:`A`:diagtext:`: '`:placeholder:`B`:diagtext:`' input unused`|+--------------------------------------------------------------------+|
| ||+------------------------------------------------------------------+||
@@ -10504,6 +11123,10 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`argument unused during compilation: '`:placeholder:`A`:diagtext:`'`|
+---------------------------------------------------------------------------------------------------------+
++----------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`the flag '`:placeholder:`A`:diagtext:`' has been deprecated and will be ignored`|
++----------------------------------------------------------------------------------------------------------------------+
+
-Wunused-comparison
-------------------
@@ -10664,6 +11287,21 @@ This diagnostic is enabled by default.
+-------------------------------------------------------------------------------------------------------------------------------------------+
+-Wunused-template
+-----------------
+Also controls `-Wunneeded-internal-declaration`_.
+
+**Diagnostic text:**
+
++-----------------------------------------------------+----------------------+----------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unused` |nbsp| |+--------------------+| |nbsp| :diagtext:`template` |nbsp| :placeholder:`B`|
+| ||:diagtext:`function`|| |
+| |+--------------------+| |
+| ||:diagtext:`variable`|| |
+| |+--------------------+| |
++-----------------------------------------------------+----------------------+----------------------------------------------------+
+
+
-Wunused-value
--------------
This diagnostic is enabled by default.
@@ -10771,12 +11409,18 @@ This diagnostic is enabled by default.
-Wvariadic-macros
-----------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
**Diagnostic text:**
+--------------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`named variadic macros are a GNU extension`|
+--------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`\_\_VA\_OPT\_\_ can only appear in the expansion of a variadic macro`|
++-----------------------------------------------------------------------------------------------------------+
+
+------------------------------------------------------------------------+
|:warning:`warning:` |nbsp| :diagtext:`variadic macros are a C99 feature`|
+------------------------------------------------------------------------+
@@ -10835,6 +11479,10 @@ This diagnostic is enabled by default.
|:warning:`warning:` |nbsp| :diagtext:`parentheses were disambiguated as a function declaration`|
+-----------------------------------------------------------------------------------------------+
++-----------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`parentheses were disambiguated as redundant parentheses around declaration of variable named` |nbsp| :placeholder:`A`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------------+
+
-Wvisibility
------------
@@ -10920,6 +11568,15 @@ Also controls `-Wdeprecated-writable-strings`_.
Synonym for `-Wwritable-strings`_.
+-Wzero-as-null-pointer-constant
+-------------------------------
+**Diagnostic text:**
+
++--------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`zero as null pointer constant`|
++--------------------------------------------------------------------+
+
+
-Wzero-length-array
-------------------
**Diagnostic text:**
diff --git a/docs/ExternalClangExamples.rst b/docs/ExternalClangExamples.rst
index c9734ec5f2..b92fa3fcc0 100644
--- a/docs/ExternalClangExamples.rst
+++ b/docs/ExternalClangExamples.rst
@@ -90,3 +90,11 @@ List of projects and tools
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/InternalsManual.rst b/docs/InternalsManual.rst
index dc89d123c0..058c63f0af 100644
--- a/docs/InternalsManual.rst
+++ b/docs/InternalsManual.rst
@@ -49,7 +49,7 @@ when the code is incorrect or dubious. In Clang, each diagnostic produced has
(at the minimum) a unique ID, an English translation associated with it, a
:ref:`SourceLocation <SourceLocation>` to "put the caret", and a severity
(e.g., ``WARNING`` or ``ERROR``). They can also optionally include a number of
-arguments to the dianostic (which fill in "%0"'s in the string) as well as a
+arguments to the diagnostic (which fill in "%0"'s in the string) as well as a
number of source ranges that related to the diagnostic.
In this section, we'll be giving examples produced by the Clang command line
@@ -493,11 +493,11 @@ source code of the program. Important design points include:
In practice, the ``SourceLocation`` works together with the ``SourceManager``
class to encode two pieces of information about a location: its spelling
-location and its instantiation location. For most tokens, these will be the
+location and its expansion location. For most tokens, these will be the
same. However, for a macro expansion (or tokens that came from a ``_Pragma``
directive) these will describe the location of the characters corresponding to
the token and the location where the token was used (i.e., the macro
-instantiation point or the location of the ``_Pragma`` itself).
+expansion point or the location of the ``_Pragma`` itself).
The Clang front-end inherently depends on the location of a token being tracked
correctly. If it is ever incorrect, the front-end may get confused and die.
@@ -795,7 +795,7 @@ preprocessor and notifies a client of the parsing progress.
Historically, the parser used to talk to an abstract ``Action`` interface that
had virtual methods for parse events, for example ``ActOnBinOp()``. When Clang
grew C++ support, the parser stopped supporting general ``Action`` clients --
-it now always talks to the :ref:`Sema libray <Sema>`. However, the Parser
+it now always talks to the :ref:`Sema library <Sema>`. However, the Parser
still accesses AST objects only through opaque types like ``ExprResult`` and
``StmtResult``. Only :ref:`Sema <Sema>` looks at the AST node contents of these
wrappers.
@@ -1324,9 +1324,9 @@ range of iterators over declarations of "``f``".
function ``DeclContext::getPrimaryContext`` retrieves the "primary" context for
a given ``DeclContext`` instance, which is the ``DeclContext`` responsible for
maintaining the lookup table used for the semantics-centric view. Given a
-DeclContext, one can obtain the set of declaration contexts that are semanticaly
-connected to this declaration context, in source order, including this context
-(which will be the only result, for non-namespace contexts) via
+DeclContext, one can obtain the set of declaration contexts that are
+semantically connected to this declaration context, in source order, including
+this context (which will be the only result, for non-namespace contexts) via
``DeclContext::collectAllContexts``. Note that these functions are used
internally within the lookup and insertion methods of the ``DeclContext``, so
the vast majority of clients can ignore them.
@@ -1514,7 +1514,7 @@ use an i-c-e where one is required, but accepting the code unless running with
Things get a little bit more tricky when it comes to compatibility with
real-world source code. Specifically, GCC has historically accepted a huge
superset of expressions as i-c-e's, and a lot of real world code depends on
-this unfortuate accident of history (including, e.g., the glibc system
+this unfortunate accident of history (including, e.g., the glibc system
headers). GCC accepts anything its "fold" optimizer is capable of reducing to
an integer constant, which means that the definition of what it accepts changes
as its optimizer does. One example is that GCC accepts things like "``case
@@ -1540,7 +1540,7 @@ Implementation Approach
After trying several different approaches, we've finally converged on a design
(Note, at the time of this writing, not all of this has been implemented,
consider this a design goal!). Our basic approach is to define a single
-recursive method evaluation method (``Expr::Evaluate``), which is implemented
+recursive evaluation method (``Expr::Evaluate``), which is implemented
in ``AST/ExprConstant.cpp``. Given an expression with "scalar" type (integer,
fp, complex, or pointer) this method returns the following information:
@@ -2037,7 +2037,7 @@ are similar.
* ``CodeGenFunction`` contains functions ``ConvertType`` and
``ConvertTypeForMem`` that convert Clang's types (``clang::Type*`` or
``clang::QualType``) to LLVM types. Use the former for values, and the
- later for memory locations: test with the C++ "``bool``" type to check
+ latter for memory locations: test with the C++ "``bool``" type to check
this. If you find that you are having to use LLVM bitcasts to make the
subexpressions of your expression have the type that your expression
expects, STOP! Go fix semantic analysis and the AST so that you don't
diff --git a/docs/LTOVisibility.rst b/docs/LTOVisibility.rst
index 67367f3d63..e1372d667a 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 164dfc585e..652145f66f 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++
@@ -780,14 +780,14 @@ Use ``__has_feature(cxx_variadic_templates)`` or
``__has_extension(cxx_variadic_templates)`` to determine if support for
variadic templates is enabled.
-C++1y
+C++14
-----
-The features listed below are part of the committee draft for the C++1y
-standard. As a result, all these features are enabled with the ``-std=c++1y``
-or ``-std=gnu++1y`` option when compiling C++ code.
+The features listed below are part of the C++14 standard. As a result, all
+these features are enabled with the ``-std=C++14`` or ``-std=gnu++14`` option
+when compiling C++ code.
-C++1y binary literals
+C++14 binary literals
^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_binary_literals)`` or
@@ -795,37 +795,37 @@ Use ``__has_feature(cxx_binary_literals)`` or
binary literals (for instance, ``0b10010``) are recognized. Clang supports this
feature as an extension in all language modes.
-C++1y contextual conversions
+C++14 contextual conversions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_contextual_conversions)`` or
-``__has_extension(cxx_contextual_conversions)`` to determine if the C++1y rules
+``__has_extension(cxx_contextual_conversions)`` to determine if the C++14 rules
are used when performing an implicit conversion for an array bound in a
*new-expression*, the operand of a *delete-expression*, an integral constant
expression, or a condition in a ``switch`` statement.
-C++1y decltype(auto)
+C++14 decltype(auto)
^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_decltype_auto)`` or
``__has_extension(cxx_decltype_auto)`` to determine if support
for the ``decltype(auto)`` placeholder type is enabled.
-C++1y default initializers for aggregates
+C++14 default initializers for aggregates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_aggregate_nsdmi)`` or
``__has_extension(cxx_aggregate_nsdmi)`` to determine if support
for default initializers in aggregate members is enabled.
-C++1y digit separators
+C++14 digit separators
^^^^^^^^^^^^^^^^^^^^^^
Use ``__cpp_digit_separators`` to determine if support for digit separators
using single quotes (for instance, ``10'000``) is enabled. At this time, there
is no corresponding ``__has_feature`` name
-C++1y generalized lambda capture
+C++14 generalized lambda capture
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_init_captures)`` or
@@ -833,7 +833,7 @@ Use ``__has_feature(cxx_init_captures)`` or
lambda captures with explicit initializers is enabled
(for instance, ``[n(0)] { return ++n; }``).
-C++1y generic lambdas
+C++14 generic lambdas
^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_generic_lambdas)`` or
@@ -841,7 +841,7 @@ Use ``__has_feature(cxx_generic_lambdas)`` or
(polymorphic) lambdas is enabled
(for instance, ``[] (auto x) { return x + 1; }``).
-C++1y relaxed constexpr
+C++14 relaxed constexpr
^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_relaxed_constexpr)`` or
@@ -849,7 +849,7 @@ Use ``__has_feature(cxx_relaxed_constexpr)`` or
declarations, local variable modification, and control flow constructs
are permitted in ``constexpr`` functions.
-C++1y return type deduction
+C++14 return type deduction
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_return_type_deduction)`` or
@@ -857,7 +857,7 @@ Use ``__has_feature(cxx_return_type_deduction)`` or
for return type deduction for functions (using ``auto`` as a return type)
is enabled.
-C++1y runtime-sized arrays
+C++14 runtime-sized arrays
^^^^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_runtime_array)`` or
@@ -866,7 +866,7 @@ for arrays of runtime bound (a restricted form of variable-length arrays)
is enabled.
Clang's implementation of this feature is incomplete.
-C++1y variable templates
+C++14 variable templates
^^^^^^^^^^^^^^^^^^^^^^^^
Use ``__has_feature(cxx_variable_templates)`` or
@@ -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)
@@ -1270,6 +1271,87 @@ Further examples of these attributes are available in the static analyzer's `lis
Query for these features with ``__has_attribute(ns_consumed)``,
``__has_attribute(ns_returns_retained)``, etc.
+Objective-C @available
+----------------------
+
+It is possible to use the newest SDK but still build a program that can run on
+older versions of macOS and iOS by passing ``-mmacosx-version-min=`` /
+``-miphoneos-version-min=``.
+
+Before LLVM 5.0, when calling a function that exists only in the OS that's
+newer than the target OS (as determined by the minimum deployment version),
+programmers had to carefully check if the function exists at runtime, using
+null checks for weakly-linked C functions, ``+class`` for Objective-C classes,
+and ``-respondsToSelector:`` or ``+instancesRespondToSelector:`` for
+Objective-C methods. If such a check was missed, the program would compile
+fine, run fine on newer systems, but crash on older systems.
+
+As of LLVM 5.0, ``-Wunguarded-availability`` uses the `availability attributes
+<http://clang.llvm.org/docs/AttributeReference.html#availability>`_ together
+with the new ``@available()`` keyword to assist with this issue.
+When a method that's introduced in the OS newer than the target OS is called, a
+-Wunguarded-availability warning is emitted if that call is not guarded:
+
+.. code-block:: objc
+
+ void my_fun(NSSomeClass* var) {
+ // If fancyNewMethod was added in e.g. macOS 10.12, but the code is
+ // built with -mmacosx-version-min=10.11, then this unconditional call
+ // will emit a -Wunguarded-availability warning:
+ [var fancyNewMethod];
+ }
+
+To fix the warning and to avoid the crash on macOS 10.11, wrap it in
+``if(@available())``:
+
+.. code-block:: objc
+
+ void my_fun(NSSomeClass* var) {
+ if (@available(macOS 10.12, *)) {
+ [var fancyNewMethod];
+ } else {
+ // Put fallback behavior for old macOS versions (and for non-mac
+ // platforms) here.
+ }
+ }
+
+The ``*`` is required and means that platforms not explicitly listed will take
+the true branch, and the compiler will emit ``-Wunguarded-availability``
+warnings for unlisted platforms based on those platform's deployment target.
+More than one platform can be listed in ``@available()``:
+
+.. code-block:: objc
+
+ void my_fun(NSSomeClass* var) {
+ if (@available(macOS 10.12, iOS 10, *)) {
+ [var fancyNewMethod];
+ }
+ }
+
+If the caller of ``my_fun()`` already checks that ``my_fun()`` is only called
+on 10.12, then add an `availability attribute
+<http://clang.llvm.org/docs/AttributeReference.html#availability>`_ to it,
+which will also suppress the warning and require that calls to my_fun() are
+checked:
+
+.. code-block:: objc
+
+ API_AVAILABLE(macos(10.12)) void my_fun(NSSomeClass* var) {
+ [var fancyNewMethod]; // Now ok.
+ }
+
+``@available()`` is only available in Objective-C code. To use the feature
+in C and C++ code, use the ``__builtin_available()`` spelling instead.
+
+If existing code uses null checks or ``-respondsToSelector:``, it should
+be changed to use ``@available()`` (or ``__builtin_available``) instead.
+
+``-Wunguarded-availability`` is disabled by default, but
+``-Wunguarded-availability-new``, which only emits this warning for APIs
+that have been introduced in macOS >= 10.13, iOS >= 11, watchOS >= 4 and
+tvOS >= 11, is enabled by default.
+
+.. _langext-overloading:
Objective-C++ ABI: protocol-qualifier mangling of parameters
------------------------------------------------------------
@@ -1286,8 +1368,6 @@ parameters of protocol-qualified type.
Query the presence of this new mangling with
``__has_feature(objc_protocol_qualifier_mangling)``.
-.. _langext-overloading:
-
Initializer lists for complex numbers in C
==========================================
@@ -1849,7 +1929,13 @@ provided, with values corresponding to the enumerators of C11's
``memory_order`` enumeration.
(Note that Clang additionally provides GCC-compatible ``__atomic_*``
-builtins)
+builtins and OpenCL 2.0 ``__opencl_atomic_*`` builtins. The OpenCL 2.0
+atomic builtins are an explicit form of the corresponding OpenCL 2.0
+builtin function, and are named with a ``__opencl_`` prefix. The macros
+``__OPENCL_MEMORY_SCOPE_WORK_ITEM``, ``__OPENCL_MEMORY_SCOPE_WORK_GROUP``,
+``__OPENCL_MEMORY_SCOPE_DEVICE``, ``__OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES``,
+and ``__OPENCL_MEMORY_SCOPE_SUB_GROUP`` are provided, with values
+corresponding to the enumerators of OpenCL's ``memory_scope`` enumeration.)
Low-level ARM exclusive memory builtins
---------------------------------------
@@ -2312,3 +2398,253 @@ 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.
+
+Specifying an attribute for multiple declarations (#pragma clang attribute)
+===========================================================================
+
+The ``#pragma clang attribute`` directive can be used to apply an attribute to
+multiple declarations. The ``#pragma clang attribute push`` variation of the
+directive pushes a new attribute to the attribute stack. The declarations that
+follow the pragma receive the attributes that are on the attribute stack, until
+the stack is cleared using a ``#pragma clang attribute pop`` directive. Multiple
+push directives can be nested inside each other.
+
+The attributes that are used in the ``#pragma clang attribute`` directives
+can be written using the GNU-style syntax:
+
+.. code-block:: c++
+
+ #pragma clang attribute push(__attribute__((annotate("custom"))), apply_to = function)
+
+ void function(); // The function now has the annotate("custom") attribute
+
+ #pragma clang attribute pop
+
+The attributes can also be written using the C++11 style syntax:
+
+.. code-block:: c++
+
+ #pragma clang attribute push([[noreturn]], apply_to = function)
+
+ void function(); // The function now has the [[noreturn]] attribute
+
+ #pragma clang attribute pop
+
+The ``__declspec`` style syntax is also supported:
+
+.. code-block:: c++
+
+ #pragma clang attribute push(__declspec(dllexport), apply_to = function)
+
+ void function(); // The function now has the __declspec(dllexport) attribute
+
+ #pragma clang attribute pop
+
+A single push directive accepts only one attribute regardless of the syntax
+used.
+
+Subject Match Rules
+-------------------
+
+The set of declarations that receive a single attribute from the attribute stack
+depends on the subject match rules that were specified in the pragma. Subject
+match rules are specified after the attribute. The compiler expects an
+identifier that corresponds to the subject set specifier. The ``apply_to``
+specifier is currently the only supported subject set specifier. It allows you
+to specify match rules that form a subset of the attribute's allowed subject
+set, i.e. the compiler doesn't require all of the attribute's subjects. For
+example, an attribute like ``[[nodiscard]]`` whose subject set includes
+``enum``, ``record`` and ``hasType(functionType)``, requires the presence of at
+least one of these rules after ``apply_to``:
+
+.. code-block:: c++
+
+ #pragma clang attribute push([[nodiscard]], apply_to = enum)
+
+ enum Enum1 { A1, B1 }; // The enum will receive [[nodiscard]]
+
+ struct Record1 { }; // The struct will *not* receive [[nodiscard]]
+
+ #pragma clang attribute pop
+
+ #pragma clang attribute push([[nodiscard]], apply_to = any(record, enum))
+
+ enum Enum2 { A2, B2 }; // The enum will receive [[nodiscard]]
+
+ struct Record2 { }; // The struct *will* receive [[nodiscard]]
+
+ #pragma clang attribute pop
+
+ // This is an error, since [[nodiscard]] can't be applied to namespaces:
+ #pragma clang attribute push([[nodiscard]], apply_to = any(record, namespace))
+
+ #pragma clang attribute pop
+
+Multiple match rules can be specified using the ``any`` match rule, as shown
+in the example above. The ``any`` rule applies attributes to all declarations
+that are matched by at least one of the rules in the ``any``. It doesn't nest
+and can't be used inside the other match rules. Redundant match rules or rules
+that conflict with one another should not be used inside of ``any``.
+
+Clang supports the following match rules:
+
+- ``function``: Can be used to apply attributes to functions. This includes C++
+ member functions, static functions, operators, and constructors/destructors.
+
+- ``function(is_member)``: Can be used to apply attributes to C++ member
+ functions. This includes members like static functions, operators, and
+ constructors/destructors.
+
+- ``hasType(functionType)``: Can be used to apply attributes to functions, C++
+ member functions, and variables/fields whose type is a function pointer. It
+ does not apply attributes to Objective-C methods or blocks.
+
+- ``type_alias``: Can be used to apply attributes to ``typedef`` declarations
+ and C++11 type aliases.
+
+- ``record``: Can be used to apply attributes to ``struct``, ``class``, and
+ ``union`` declarations.
+
+- ``record(unless(is_union))``: Can be used to apply attributes only to
+ ``struct`` and ``class`` declarations.
+
+- ``enum``: Can be be used to apply attributes to enumeration declarations.
+
+- ``enum_constant``: Can be used to apply attributes to enumerators.
+
+- ``variable``: Can be used to apply attributes to variables, including
+ local variables, parameters, global variables, and static member variables.
+ It does not apply attributes to instance member variables or Objective-C
+ ivars.
+
+- ``variable(is_thread_local)``: Can be used to apply attributes to thread-local
+ variables only.
+
+- ``variable(is_global)``: Can be used to apply attributes to global variables
+ only.
+
+- ``variable(is_parameter)``: Can be used to apply attributes to parameters
+ only.
+
+- ``variable(unless(is_parameter))``: Can be used to apply attributes to all
+ the variables that are not parameters.
+
+- ``field``: Can be used to apply attributes to non-static member variables
+ in a record. This includes Objective-C ivars.
+
+- ``namespace``: Can be used to apply attributes to ``namespace`` declarations.
+
+- ``objc_interface``: Can be used to apply attributes to ``@interface``
+ declarations.
+
+- ``objc_protocol``: Can be used to apply attributes to ``@protocol``
+ declarations.
+
+- ``objc_category``: Can be used to apply attributes to category declarations,
+ including class extensions.
+
+- ``objc_method``: Can be used to apply attributes to Objective-C methods,
+ including instance and class methods. Implicit methods like implicit property
+ getters and setters do not receive the attribute.
+
+- ``objc_method(is_instance)``: Can be used to apply attributes to Objective-C
+ instance methods.
+
+- ``objc_property``: Can be used to apply attributes to ``@property``
+ declarations.
+
+- ``block``: Can be used to apply attributes to block declarations. This does
+ not include variables/fields of block pointer type.
+
+The use of ``unless`` in match rules is currently restricted to a strict set of
+sub-rules that are used by the supported attributes. That means that even though
+``variable(unless(is_parameter))`` is a valid match rule,
+``variable(unless(is_thread_local))`` is not.
+
+Supported Attributes
+--------------------
+
+Not all attributes can be used with the ``#pragma clang attribute`` directive.
+Notably, statement attributes like ``[[fallthrough]]`` or type attributes
+like ``address_space`` aren't supported by this directive. You can determine
+whether or not an attribute is supported by the pragma by referring to the
+:doc:`individual documentation for that attribute <AttributeReference>`.
+
+The attributes are applied to all matching declarations individually, even when
+the attribute is semantically incorrect. The attributes that aren't applied to
+any declaration are not verified semantically.
+
+Specifying section names for global objects (#pragma clang section)
+===================================================================
+
+The ``#pragma clang section`` directive provides a means to assign section-names
+to global variables, functions and static variables.
+
+The section names can be specified as:
+
+.. code-block:: c++
+
+ #pragma clang section bss="myBSS" data="myData" rodata="myRodata" text="myText"
+
+The section names can be reverted back to default name by supplying an empty
+string to the section kind, for example:
+
+.. code-block:: c++
+
+ #pragma clang section bss="" data="" text="" rodata=""
+
+The ``#pragma clang section`` directive obeys the following rules:
+
+* The pragma applies to all global variable, statics and function declarations
+ from the pragma to the end of the translation unit.
+
+* The pragma clang section is enabled automatically, without need of any flags.
+
+* This feature is only defined to work sensibly for ELF targets.
+
+* If section name is specified through _attribute_((section("myname"))), then
+ the attribute name gains precedence.
+
+* Global variables that are initialized to zero will be placed in the named
+ bss section, if one is present.
+
+* The ``#pragma clang section`` directive does not does try to infer section-kind
+ from the name. For example, naming a section "``.bss.mySec``" does NOT mean
+ it will be a bss section name.
+
+* The decision about which section-kind applies to each global is taken in the back-end.
+ Once the section-kind is known, appropriate section name, as specified by the user using
+ ``#pragma clang section`` directive, is applied to that global.
diff --git a/docs/LeakSanitizer.rst b/docs/LeakSanitizer.rst
index c3cceccd28..3601587c42 100644
--- a/docs/LeakSanitizer.rst
+++ b/docs/LeakSanitizer.rst
@@ -17,7 +17,7 @@ detection phase.
Usage
=====
-LeakSanitizer is only supported on x86\_64 Linux. In order to use it,
+LeakSanitizer is supported on x86\_64 Linux and OS X. In order to use it,
simply build your program with :doc:`AddressSanitizer`:
.. code-block:: console
@@ -30,7 +30,7 @@ simply build your program with :doc:`AddressSanitizer`:
p = 0; // The memory is leaked here.
return 0;
}
- % clang -fsanitize=address -g memory-leak.c ; ./a.out
+ % clang -fsanitize=address -g memory-leak.c ; ASAN_OPTIONS=detect_leaks=1 ./a.out
==23646==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 7 byte(s) in 1 object(s) allocated from:
#0 0x4af01b in __interceptor_malloc /projects/compiler-rt/lib/asan/asan_malloc_linux.cc:52:3
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index 0fd7a744b3..63ae085b0d 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -337,6 +337,33 @@ 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('objcCategoryImplDecl0')"><a name="objcCategoryImplDecl0Anchor">objcCategoryImplDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCCategoryImplDecl.html">ObjCCategoryImplDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="objcCategoryImplDecl0"><pre>Matches Objective-C category definitions.
+
+Example matches Foo (Additions)
+ @implementation 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('objcImplementationDecl0')"><a name="objcImplementationDecl0Anchor">objcImplementationDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCImplementationDecl.html">ObjCImplementationDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="objcImplementationDecl0"><pre>Matches Objective-C implementation declarations.
+
+Example matches Foo
+ @implementation Foo
+ @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 +373,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 +487,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.
@@ -862,6 +942,19 @@ in
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('cxxStdInitializerListExpr0')"><a name="cxxStdInitializerListExpr0Anchor">cxxStdInitializerListExpr</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStdInitializerListExpr.html">CXXStdInitializerListExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="cxxStdInitializerListExpr0"><pre>Matches C++ initializer list expressions.
+
+Given
+ std::vector&lt;int&gt; a({ 1, 2, 3 });
+ std::vector&lt;int&gt; b = { 4, 5 };
+ int c[] = { 6, 7 };
+ std::pair&lt;int, int&gt; d = { 8, 9 };
+cxxStdInitializerListExpr()
+ matches "{ 1, 2, 3 }" and "{ 4, 5 }"
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('cxxTemporaryObjectExpr0')"><a name="cxxTemporaryObjectExpr0Anchor">cxxTemporaryObjectExpr</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTemporaryObjectExpr.html">CXXTemporaryObjectExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="cxxTemporaryObjectExpr0"><pre>Matches functional cast expressions having N != 1 arguments
@@ -1098,7 +1191,7 @@ Example matches [&amp;](){return 5;}
<tr><td colspan="4" class="doc" id="materializeTemporaryExpr0"><pre>Matches nodes where temporaries are materialized.
Example: Given
- struct T {void func()};
+ struct T {void func();};
T f();
void g(T);
materializeTemporaryExpr() matches 'f()' in these statements
@@ -1654,6 +1747,21 @@ substTemplateTypeParmType() matches the type of 't' but not '1'
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('tagType0')"><a name="tagType0Anchor">tagType</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="tagType0"><pre>Matches tag types (record and enum types).
+
+Given
+ enum E {};
+ class C {};
+
+ E e;
+ C c;
+
+tagType() matches the type of the variable declarations of both e
+and c.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('templateSpecializationType0')"><a name="templateSpecializationType0Anchor">templateSpecializationType</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="templateSpecializationType0"><pre>Matches template specialization types.
@@ -1784,17 +1892,44 @@ Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
</pre></td></tr>
-<tr><td>Matcher&lt;CXXBoolLiteral&gt;</td><td class="name" onclick="toggle('equals2')"><a name="equals2Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value.
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;</td><td class="name" onclick="toggle('equals2')"><a name="equals2Anchor">equals</a></td><td>ValueT Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals2"><pre>Matches literals that are equal to the given value of type ValueT.
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
+Given
+ f('false, 3.14, 42);
+characterLiteral(equals(0))
+ matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
+ match false
+floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
+ match 3.14
+integerLiteral(equals(42))
+ matches 42
+
+Note that you cannot directly match a negative numeric literal because the
+minus sign is not part of the literal: It is a unary operator whose operand
+is the positive numeric literal. Instead, you must use a unaryOperator()
+matcher to match the minus sign:
-Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(13))))
+
+Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;</td><td class="name" onclick="toggle('equals5')"><a name="equals5Anchor">equals</a></td><td>bool Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals5"><pre></pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;</td><td class="name" onclick="toggle('equals11')"><a name="equals11Anchor">equals</a></td><td>double Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals11"><pre></pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;</td><td class="name" onclick="toggle('equals8')"><a name="equals8Anchor">equals</a></td><td>unsigned Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals8"><pre></pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>&gt;</td><td class="name" onclick="toggle('isCatchAll0')"><a name="isCatchAll0Anchor">isCatchAll</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isCatchAll0"><pre>Matches a C++ catch statement that has a catch-all handler.
@@ -2221,16 +2356,43 @@ Example: matches the implicit cast around 0
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;</td><td class="name" onclick="toggle('equals3')"><a name="equals3Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value.
+<tr><td colspan="4" class="doc" id="equals3"><pre>Matches literals that are equal to the given value of type ValueT.
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
+Given
+ f('false, 3.14, 42);
+characterLiteral(equals(0))
+ matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
+ match false
+floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
+ match 3.14
+integerLiteral(equals(42))
+ matches 42
+
+Note that you cannot directly match a negative numeric literal because the
+minus sign is not part of the literal: It is a unary operator whose operand
+is the positive numeric literal. Instead, you must use a unaryOperator()
+matcher to match the minus sign:
-Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(13))))
+
+Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;</td><td class="name" onclick="toggle('equals4')"><a name="equals4Anchor">equals</a></td><td>bool Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals4"><pre></pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;</td><td class="name" onclick="toggle('equals10')"><a name="equals10Anchor">equals</a></td><td>double Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals10"><pre></pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;</td><td class="name" onclick="toggle('equals7')"><a name="equals7Anchor">equals</a></td><td>unsigned Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals7"><pre></pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('templateArgumentCountIs0')"><a name="templateArgumentCountIs0Anchor">templateArgumentCountIs</a></td><td>unsigned N</td></tr>
<tr><td colspan="4" class="doc" id="templateArgumentCountIs0"><pre>Matches if the number of template arguments equals N.
@@ -2458,16 +2620,35 @@ fieldDecl(isBitField())
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;</td><td class="name" onclick="toggle('equals1')"><a name="equals1Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value.
+<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value of type ValueT.
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
+Given
+ f('false, 3.14, 42);
+characterLiteral(equals(0))
+ matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
+ match false
+floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
+ match 3.14
+integerLiteral(equals(42))
+ matches 42
+
+Note that you cannot directly match a negative numeric literal because the
+minus sign is not part of the literal: It is a unary operator whose operand
+is the positive numeric literal. Instead, you must use a unaryOperator()
+matcher to match the minus sign:
-Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(13))))
+
+Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;</td><td class="name" onclick="toggle('equals12')"><a name="equals12Anchor">equals</a></td><td>double Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals12"><pre></pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('hasDynamicExceptionSpec0')"><a name="hasDynamicExceptionSpec0Anchor">hasDynamicExceptionSpec</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasDynamicExceptionSpec0"><pre>Matches functions that have a dynamic exception specification.
@@ -2569,19 +2750,22 @@ functionDecl(isExplicitTemplateSpecialization())
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
</pre></td></tr>
-
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isExternC0')"><a name="isExternC0Anchor">isExternC</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function declarations.
+<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function or variable declarations.
Given:
extern "C" void f() {}
extern "C" { void g() {} }
void h() {}
+ extern "C" int x = 1;
+ extern "C" int y = 2;
+ int z = 3;
functionDecl(isExternC())
- matches the declaration of f and g, but not the declaration h
+ matches the declaration of f and g, but not the declaration of h.
+varDecl(isExternC())
+ matches the declaration of x and y, but not the declaration of z.
</pre></td></tr>
-
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isInline1')"><a name="isInline1Anchor">isInline</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isInline1"><pre>Matches function and namespace declarations that are marked with
the inline keyword.
@@ -2730,16 +2914,43 @@ functionProtoType(parameterCountIs(3))
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;</td><td class="name" onclick="toggle('equals0')"><a name="equals0Anchor">equals</a></td><td>ValueT Value</td></tr>
-<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value.
+<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value of type ValueT.
-Example matches true (matcher = cxxBoolLiteral(equals(true)))
- true
+Given
+ f('false, 3.14, 42);
+characterLiteral(equals(0))
+ matches 'cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
+ match false
+floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
+ match 3.14
+integerLiteral(equals(42))
+ matches 42
+
+Note that you cannot directly match a negative numeric literal because the
+minus sign is not part of the literal: It is a unary operator whose operand
+is the positive numeric literal. Instead, you must use a unaryOperator()
+matcher to match the minus sign:
+
+unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(13))))
-Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;CXXBoolLiteral&gt;,
+Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;</td><td class="name" onclick="toggle('equals6')"><a name="equals6Anchor">equals</a></td><td>bool Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals6"><pre></pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;</td><td class="name" onclick="toggle('equals13')"><a name="equals13Anchor">equals</a></td><td>double Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals13"><pre></pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;</td><td class="name" onclick="toggle('equals9')"><a name="equals9Anchor">equals</a></td><td>unsigned Value</td></tr>
+<tr><td colspan="4" class="doc" id="equals9"><pre></pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;</td><td class="name" onclick="toggle('isArrow0')"><a name="isArrow0Anchor">isArrow</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isArrow0"><pre>Matches member expressions that are called with '-&gt;' as opposed
to '.'.
@@ -3481,19 +3692,22 @@ functionDecl(isExplicitTemplateSpecialization())
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
</pre></td></tr>
-
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('isExternC1')"><a name="isExternC1Anchor">isExternC</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExternC1"><pre>Matches extern "C" function declarations.
+<tr><td colspan="4" class="doc" id="isExternC1"><pre>Matches extern "C" function or variable declarations.
Given:
extern "C" void f() {}
extern "C" { void g() {} }
void h() {}
+ extern "C" int x = 1;
+ extern "C" int y = 2;
+ int z = 3;
functionDecl(isExternC())
- matches the declaration of f and g, but not the declaration h
+ matches the declaration of f and g, but not the declaration of h.
+varDecl(isExternC())
+ matches the declaration of x and y, but not the declaration of z.
</pre></td></tr>
-
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('isStaticStorageClass1')"><a name="isStaticStorageClass1Anchor">isStaticStorageClass</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isStaticStorageClass1"><pre>Matches variablefunction declarations that have "static" storage
class specifier ("static" keyword) written in the source.
@@ -4371,6 +4585,18 @@ functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('hasSpecializedTemplate0')"><a name="hasSpecializedTemplate0Anchor">hasSpecializedTemplate</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasSpecializedTemplate0"><pre>Matches the specialized template of a specialization declaration.
+
+Given
+ tempalate&lt;typename T&gt; class A {};
+ typedef A&lt;int&gt; B;
+classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
+ matches 'B' with classTemplateDecl() matching the class template
+ declaration of 'A'.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('hasTemplateArgument0')"><a name="hasTemplateArgument0Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasTemplateArgument0"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
@@ -5171,7 +5397,7 @@ Example matches y in x(y)
<tr><td colspan="4" class="doc" id="hasReceiverType0"><pre>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.
NSString *webViewJavaScript = ...
UIWebView *webView = ...
diff --git a/docs/LibFormat.rst b/docs/LibFormat.rst
index eacdc16145..086a52827d 100644
--- a/docs/LibFormat.rst
+++ b/docs/LibFormat.rst
@@ -28,7 +28,9 @@ The core routine of LibFormat is ``reformat()``:
This reads a token stream out of the lexer ``Lex`` and reformats all the code
ranges in ``Ranges``. The ``FormatStyle`` controls basic decisions made during
-formatting. A list of options can be found under :ref:`style-options`.
+formatting. A list of options can be found under :ref:`style-options`.
+
+The style options are described in :doc:`ClangFormatStyleOptions`.
.. _style-options:
diff --git a/docs/MemorySanitizer.rst b/docs/MemorySanitizer.rst
index 8088ecdf56..5bb19ed8a5 100644
--- a/docs/MemorySanitizer.rst
+++ b/docs/MemorySanitizer.rst
@@ -27,7 +27,7 @@ executable, so make sure to use ``clang`` (not ``ld``) for the final
link step. When linking shared libraries, the MemorySanitizer run-time
is not linked, so ``-Wl,-z,defs`` may cause link errors (don't use it
with MemorySanitizer). To get a reasonable performance add ``-O1`` or
-higher. To get meaninful stack traces in error messages add
+higher. To get meaningful stack traces in error messages add
``-fno-omit-frame-pointer``. To get perfect stack traces you may need
to disable inlining (just use ``-O1``) and tail call elimination
(``-fno-optimize-sibling-calls``).
diff --git a/docs/Modules.rst b/docs/Modules.rst
index 141d3b8575..757be61913 100644
--- a/docs/Modules.rst
+++ b/docs/Modules.rst
@@ -213,8 +213,14 @@ Command-line parameters
``-fno-implicit-modules``
All modules used by the build must be specified with ``-fmodule-file``.
-``-fmodule-file=<file>``
- Load the given precompiled module file.
+``-fmodule-file=[<name>=]<file>``
+ Specify the mapping of module names to precompiled module files. If the
+ name is omitted, then the module file is loaded whether actually required
+ or not. If the name is specified, then the mapping is treated as another
+ prebuilt module search mechanism (in addition to ``-fprebuilt-module-path``)
+ and the module is only loaded if required. Note that in this case the
+ specified file also overrides this module's paths that might be embedded
+ in other precompiled module files.
``-fprebuilt-module-path=<directory>``
Specify the path to the prebuilt modules. If specified, we will look for modules in this directory for a given top-level module name. We don't need a module map for loading prebuilt modules in this directory and the compiler will not try to rebuild these modules. This can be specified multiple times.
@@ -317,11 +323,12 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
.. parsed-literal::
- ``config_macros`` ``export`` ``private``
+ ``config_macros`` ``export_as`` ``private``
``conflict`` ``framework`` ``requires``
``exclude`` ``header`` ``textual``
``explicit`` ``link`` ``umbrella``
``extern`` ``module`` ``use``
+ ``export``
Module map file
---------------
@@ -360,6 +367,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
@@ -380,6 +388,7 @@ Modules can have a number of different kinds of members, each of which is descri
*umbrella-dir-declaration*
*submodule-declaration*
*export-declaration*
+ *export-as-declaration*
*use-declaration*
*link-declaration*
*config-macros-declaration*
@@ -402,7 +411,7 @@ A *requires-declaration* specifies the requirements that an importing translatio
*feature*:
``!``:sub:`opt` *identifier*
-The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module. The optional ``!`` indicates that a feature is incompatible with the module.
+The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module. When building a module for use by a compilation, submodules requiring unavailable features are ignored. The optional ``!`` indicates that a feature is incompatible with the module.
The following features are defined:
@@ -412,6 +421,9 @@ altivec
blocks
The "blocks" language feature is available.
+coroutines
+ Support for the coroutines TS is available.
+
cplusplus
C++ support is available.
@@ -465,9 +477,16 @@ A header declaration specifies that a particular header is associated with the e
.. parsed-literal::
*header-declaration*:
- ``private``:sub:`opt` ``textual``:sub:`opt` ``header`` *string-literal*
- ``umbrella`` ``header`` *string-literal*
- ``exclude`` ``header`` *string-literal*
+ ``private``:sub:`opt` ``textual``:sub:`opt` ``header`` *string-literal* *header-attrs*:sub:`opt`
+ ``umbrella`` ``header`` *string-literal* *header-attrs*:sub:`opt`
+ ``exclude`` ``header`` *string-literal* *header-attrs*:sub:`opt`
+
+ *header-attrs*:
+ '{' *header-attr** '}'
+
+ *header-attr*:
+ ``size`` *integer-literal*
+ ``mtime`` *integer-literal*
A header declaration that does not contain ``exclude`` nor ``textual`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule.
@@ -500,6 +519,18 @@ A header with the ``exclude`` specifier is excluded from the module. It will not
A given header shall not be referenced by more than one *header-declaration*.
+Two *header-declaration*\s, or a *header-declaration* and a ``#include``, are
+considered to refer to the same file if the paths resolve to the same file
+and the specified *header-attr*\s (if any) match the attributes of that file,
+even if the file is named differently (for instance, by a relative path or
+via symlinks).
+
+.. note::
+ The use of *header-attr*\s avoids the need for Clang to speculatively
+ ``stat`` every header referenced by a module map. It is recommended that
+ *header-attr*\s only be used in machine-generated module maps, to avoid
+ mismatches between attribute values and the corresponding files.
+
Umbrella directory declaration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An umbrella directory declaration specifies that all of the headers in the specified directory should be included within the module.
@@ -637,6 +668,30 @@ Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard e
compatibility for programs that rely on transitive inclusion (i.e.,
all of them).
+Re-export Declaration
+~~~~~~~~~~~~~~~~~~~~~
+An *export-as-declaration* specifies that the current module will have
+its interface re-exported by the named module.
+
+.. parsed-literal::
+
+ *export-as-declaration*:
+ ``export_as`` *identifier*
+
+The *export-as-declaration* names the module that the current
+module will be re-exported through. Only top-level modules
+can be re-exported, and any given module may only be re-exported
+through a single module.
+
+**Example:** In the following example, the module ``MyFrameworkCore``
+will be re-exported via the module ``MyFramework``:
+
+.. parsed-literal::
+
+ module MyFrameworkCore {
+ export_as MyFramework
+ }
+
Use declaration
~~~~~~~~~~~~~~~
A *use-declaration* specifies another module that the current top-level module
@@ -842,6 +897,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).
@@ -912,4 +977,3 @@ PCHInternals_
.. [#] The preprocessing context in which the modules are parsed is actually dependent on the command-line options provided to the compiler, including the language dialect and any ``-D`` options. However, the compiled modules for different command-line options are kept distinct, and any preprocessor directives that occur within the translation unit are ignored. See the section on the `Configuration macros declaration`_ for more information.
.. _PCHInternals: PCHInternals.html
-
diff --git a/docs/RefactoringEngine.rst b/docs/RefactoringEngine.rst
new file mode 100644
index 0000000000..e0d16ef437
--- /dev/null
+++ b/docs/RefactoringEngine.rst
@@ -0,0 +1,253 @@
+==========================
+Clang's refactoring engine
+==========================
+
+This document describes the design of Clang's refactoring engine and provides
+a couple of examples that show how various primitives in the refactoring API
+can be used to implement different refactoring actions. The :doc:`LibTooling`
+library provides several other APIs that are used when developing a
+refactoring action.
+
+Refactoring engine can be used to implement local refactorings that are
+initiated using a selection in an editor or an IDE. You can combine
+:doc:`AST matchers<LibASTMatchers>` and the refactoring engine to implement
+refactorings that don't lend themselves well to source selection and/or have to
+query ASTs for some particular nodes.
+
+We assume basic knowledge about the Clang AST. See the :doc:`Introduction
+to the Clang AST <IntroductionToTheClangAST>` if you want to learn more
+about how the AST is structured.
+
+.. FIXME: create new refactoring action tutorial and link to the tutorial
+
+Introduction
+------------
+
+Clang's refactoring engine defines a set refactoring actions that implement
+a number of different source transformations. The ``clang-refactor``
+command-line tool can be used to perform these refactorings. Certain
+refactorings are also available in other clients like text editors and IDEs.
+
+A refactoring action is a class that defines a list of related refactoring
+operations (rules). These rules are grouped under a common umbrella - a single
+``clang-refactor`` command. In addition to rules, the refactoring action
+provides the action's command name and description to ``clang-refactor``.
+Each action must implement the ``RefactoringAction`` interface. Here's an
+outline of a ``local-rename`` action:
+
+.. code-block:: c++
+
+ class LocalRename final : public RefactoringAction {
+ public:
+ StringRef getCommand() const override { return "local-rename"; }
+
+ StringRef getDescription() const override {
+ return "Finds and renames symbols in code with no indexer support";
+ }
+
+ RefactoringActionRules createActionRules() const override {
+ ...
+ }
+ };
+
+Refactoring Action Rules
+------------------------
+
+An individual refactoring action is responsible for creating the set of
+grouped refactoring action rules that represent one refactoring operation.
+Although the rules in one action may have a number of different implementations,
+they should strive to produce a similar result. It should be easy for users to
+identify which refactoring action produced the result regardless of which
+refactoring action rule was used.
+
+The distinction between actions and rules enables the creation of actions
+that define a set of different rules that produce similar results. For example,
+the "add missing switch cases" refactoring operation typically adds missing
+cases to one switch at a time. However, it could be useful to have a
+refactoring that works on all switches that operate on a particular enum, as
+one could then automatically update all of them after adding a new enum
+constant. To achieve that, we can create two different rules that will use one
+``clang-refactor`` subcommand. The first rule will describe a local operation
+that's initiated when the user selects a single switch. The second rule will
+describe a global operation that works across translation units and is initiated
+when the user provides the name of the enum to clang-refactor (or the user could
+select the enum declaration instead). The clang-refactor tool will then analyze
+the selection and other options passed to the refactoring action, and will pick
+the most appropriate rule for the given selection and other options.
+
+Rule Types
+^^^^^^^^^^
+
+Clang's refactoring engine supports several different refactoring rules:
+
+- ``SourceChangeRefactoringRule`` produces source replacements that are applied
+ to the source files. Subclasses that choose to implement this rule have to
+ implement the ``createSourceReplacements`` member function. This type of
+ rule is typically used to implement local refactorings that transform the
+ source in one translation unit only.
+
+- ``FindSymbolOccurrencesRefactoringRule`` produces a "partial" refactoring
+ result: a set of occurrences that refer to a particular symbol. This type
+ of rule is typically used to implement an interactive renaming action that
+ allows users to specify which occurrences should be renamed during the
+ refactoring. Subclasses that choose to implement this rule have to implement
+ the ``findSymbolOccurrences`` member function.
+
+The following set of quick checks might help if you are unsure about the type
+of rule you should use:
+
+#. If you would like to transform the source in one translation unit and if
+ you don't need any cross-TU information, then the
+ ``SourceChangeRefactoringRule`` should work for you.
+
+#. If you would like to implement a rename-like operation with potential
+ interactive components, then ``FindSymbolOccurrencesRefactoringRule`` might
+ work for you.
+
+How to Create a Rule
+^^^^^^^^^^^^^^^^^^^^
+
+Once you determine which type of rule is suitable for your needs you can
+implement the refactoring by subclassing the rule and implementing its
+interface. The subclass should have a constructor that takes the inputs that
+are needed to perform the refactoring. For example, if you want to implement a
+rule that simply deletes a selection, you should create a subclass of
+``SourceChangeRefactoringRule`` with a constructor that accepts the selection
+range:
+
+.. code-block:: c++
+
+ class DeleteSelectedRange final : public SourceChangeRefactoringRule {
+ public:
+ DeleteSelection(SourceRange Selection) : Selection(Selection) {}
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) override {
+ AtomicChange Replacement(Context.getSources(), Selection.getBegin());
+ Replacement.replace(Context.getSource,
+ CharSourceRange::getCharRange(Selection), "");
+ return { Replacement };
+ }
+ private:
+ SourceRange Selection;
+ };
+
+The rule's subclass can then be added to the list of refactoring action's
+rules for a particular action using the ``createRefactoringActionRule``
+function. For example, the class that's shown above can be added to the
+list of action rules using the following code:
+
+.. code-block:: c++
+
+ RefactoringActionRules Rules;
+ Rules.push_back(
+ createRefactoringActionRule<DeleteSelectedRange>(
+ SourceRangeSelectionRequirement())
+ );
+
+The ``createRefactoringActionRule`` function takes in a list of refactoring
+action rule requirement values. These values describe the initiation
+requirements that have to be satisfied by the refactoring engine before the
+provided action rule can be constructed and invoked. The next section
+describes how these requirements are evaluated and lists all the possible
+requirements that can be used to construct a refactoring action rule.
+
+Refactoring Action Rule Requirements
+------------------------------------
+
+A refactoring action rule requirement is a value whose type derives from the
+``RefactoringActionRuleRequirement`` class. The type must define an
+``evaluate`` member function that returns a value of type ``Expected<...>``.
+When a requirement value is used as an argument to
+``createRefactoringActionRule``, that value is evaluated during the initiation
+of the action rule. The evaluated result is then passed to the rule's
+constructor unless the evaluation produced an error. For example, the
+``DeleteSelectedRange`` sample rule that's defined in the previous section
+will be evaluated using the following steps:
+
+#. ``SourceRangeSelectionRequirement``'s ``evaluate`` member function will be
+ called first. It will return an ``Expected<SourceRange>``.
+
+#. If the return value is an error the initiation will fail and the error
+ will be reported to the client. Note that the client may not report the
+ error to the user.
+
+#. Otherwise the source range return value will be used to construct the
+ ``DeleteSelectedRange`` rule. The rule will then be invoked as the initiation
+ succeeded (all requirements were evaluated successfully).
+
+The same series of steps applies to any refactoring rule. Firstly, the engine
+will evaluate all of the requirements. Then it will check if these requirements
+are satisfied (they should not produce an error). Then it will construct the
+rule and invoke it.
+
+The separation of requirements, their evaluation and the invocation of the
+refactoring action rule allows the refactoring clients to:
+
+- Disable refactoring action rules whose requirements are not supported.
+
+- Gather the set of options and define a command-line / visual interface
+ that allows users to input these options without ever invoking the
+ action.
+
+Selection Requirements
+^^^^^^^^^^^^^^^^^^^^^^
+
+The refactoring rule requirements that require some form of source selection
+are listed below:
+
+- ``SourceRangeSelectionRequirement`` evaluates to a source range when the
+ action is invoked with some sort of selection. This requirement should be
+ satisfied when a refactoring is initiated in an editor, even when the user
+ has not selected anything (the range will contain the cursor's location in
+ that case).
+
+.. FIXME: Future selection requirements
+
+.. FIXME: Maybe mention custom selection requirements?
+
+Other Requirements
+^^^^^^^^^^^^^^^^^^
+
+There are several other requirements types that can be used when creating
+a refactoring rule:
+
+- The ``RefactoringOptionsRequirement`` requirement is an abstract class that
+ should be subclassed by requirements working with options. The more
+ concrete ``OptionRequirement`` requirement is a simple implementation of the
+ aforementioned class that returns the value of the specified option when
+ it's evaluated. The next section talks more about refactoring options and
+ how they can be used when creating a rule.
+
+Refactoring Options
+-------------------
+
+Refactoring options are values that affect a refactoring operation and are
+specified either using command-line options or another client-specific
+mechanism. Options should be created using a class that derives either from
+the ``OptionalRequiredOption`` or ``RequiredRefactoringOption``. The following
+example shows how one can created a required string option that corresponds to
+the ``-new-name`` command-line option in clang-refactor:
+
+.. code-block:: c++
+
+ class NewNameOption : public RequiredRefactoringOption<std::string> {
+ public:
+ StringRef getName() const override { return "new-name"; }
+ StringRef getDescription() const override {
+ return "The new name to change the symbol to";
+ }
+ };
+
+The option that's shown in the example above can then be used to create
+a requirement for a refactoring rule using a requirement like
+``OptionRequirement``:
+
+.. code-block:: c++
+
+ createRefactoringActionRule<RenameOccurrences>(
+ ...,
+ OptionRequirement<NewNameOption>())
+ );
+
+.. FIXME: Editor Bindings section
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index d22857ed43..4c8099121e 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,5 +1,5 @@
=======================================
-Clang 5.0.0 (In-Progress) Release Notes
+Clang 6.0.0 (In-Progress) Release Notes
=======================================
.. contents::
@@ -10,7 +10,7 @@ Written by the `LLVM Team <http://llvm.org/>`_
.. warning::
- These are in-progress notes for the upcoming Clang 5 release.
+ These are in-progress notes for the upcoming Clang 6 release.
Release notes for previous releases can be found on
`the Download Page <http://releases.llvm.org/download.html>`_.
@@ -18,7 +18,7 @@ Introduction
============
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
+frontend, part of the LLVM Compiler Infrastructure, release 6.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
@@ -26,17 +26,16 @@ documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
releases may be downloaded from the `LLVM releases web
site <http://llvm.org/releases/>`_.
-For more information about Clang or LLVM, including information about
-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>`_.
+For more information about Clang or LLVM, including information about the
+latest release, please see the `Clang Web Site <http://clang.llvm.org>`_ or the
+`LLVM Web Site <http://llvm.org>`_.
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?
+What's New in Clang 6.0.0?
==========================
Some of the major new features and improvements to Clang are listed
@@ -52,13 +51,83 @@ Major New Features
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.
+- ``-Wpragma-pack`` is a new warning that warns in the following cases:
+
+ - When a translation unit is missing terminating ``#pragma pack (pop)``
+ directives.
+
+ - When leaving an included file that changes the current alignment value,
+ i.e. when the alignment before ``#include`` is different to the alignment
+ after ``#include``.
+
+ - ``-Wpragma-pack-suspicious-include`` (disabled by default) warns on an
+ ``#include`` when the included file contains structures or unions affected by
+ a non-default alignment that has been specified using a ``#pragma pack``
+ directive prior to the ``#include``.
+
+- ``-Wobjc-messaging-id`` is a new, non-default warning that warns about
+ message sends to unqualified ``id`` in Objective-C. This warning is useful
+ for projects that would like to avoid any potential future compiler
+ errors/warnings, as the system frameworks might add a method with the same
+ selector which could make the message send to ``id`` ambiguous.
+
+- ``-Wtautological-compare`` now warns when comparing an unsigned integer and 0
+ regardless of whether the constant is signed or unsigned."
+
+- ``-Wtautological-compare`` now warns about comparing a signed integer and 0
+ when the signed integer is coerced to an unsigned type for the comparison.
+ ``-Wsign-compare`` was adjusted not to warn in this case.
+
+- ``-Wtautological-constant-compare`` is a new warning that warns on
+ tautological comparisons between integer variable of the type ``T`` and the
+ largest/smallest possible integer constant of that same type.
+
+- For C code, ``-Wsign-compare``, ``-Wtautological-constant-compare`` and
+ ``-Wtautological-constant-out-of-range-compare`` were adjusted to use the
+ underlying datatype of ``enum``.
+
+- ``-Wnull-pointer-arithmetic`` now warns about performing pointer arithmetic
+ on a null pointer. Such pointer arithmetic has an undefined behavior if the
+ offset is nonzero. It also now warns about arithmetic on a null pointer
+ treated as a cast from integer to pointer (GNU extension).
+
+- ``-Wzero-as-null-pointer-constant`` was adjusted not to warn on null pointer
+ constants that originate from system macros, except ``NULL`` macro.
+
+Non-comprehensive list of changes in this release
+-------------------------------------------------
+
+- Bitrig OS was merged back into OpenBSD, so Bitrig support has been
+ removed from Clang/LLVM.
+
+- The default value of _MSC_VER was raised from 1800 to 1911, making it
+ compatible with the Visual Studio 2015 and 2017 C++ standard library headers.
+ Users should generally expect this to be regularly raised to match the most
+ recently released version of the Visual C++ compiler.
+
+- clang now defaults to ``.init_array`` if no gcc installation can be found.
+ If a gcc installation is found, it still prefers ``.ctors`` if the found
+ gcc is older than 4.7.0.
New Compiler Flags
------------------
-The option ....
+- --autocomplete was implemented to obtain a list of flags and its arguments. This is used for shell autocompletion.
+
+- The ``-fdouble-square-bracket-attributes`` and corresponding
+ ``-fno-double-square-bracket-attributes`` flags were added to enable or
+ disable [[]] attributes in any language mode. Currently, only a limited
+ number of attributes are supported outside of C++ mode. See the Clang
+ attribute documentation for more information about which attributes are
+ supported for each syntax.
+
+Deprecated Compiler Flags
+-------------------------
+
+The following options are deprecated and ignored. They will be removed in
+future versions of Clang.
+
+- ...
New Pragmas in Clang
-----------------------
@@ -69,7 +138,10 @@ Clang now supports the ...
Attribute Changes in Clang
--------------------------
-- ...
+- The presence of __attribute__((availability(...))) on a declaration no longer
+ implies default visibility for that declaration on macOS.
+
+- ...
Windows Support
---------------
@@ -126,7 +198,54 @@ this section should help get you past the largest hurdles of upgrading.
AST Matchers
------------
-...
+The hasDeclaration matcher now works the same for Type and QualType and only
+ever looks through one level of sugaring in a limited number of cases.
+
+There are two main patterns affected by this:
+
+- qualType(hasDeclaration(recordDecl(...))): previously, we would look through
+ sugar like TypedefType to get at the underlying recordDecl; now, we need
+ to explicitly remove the sugaring:
+ qualType(hasUnqualifiedDesugaredType(hasDeclaration(recordDecl(...))))
+
+- hasType(recordDecl(...)): hasType internally uses hasDeclaration; previously,
+ this matcher used to match for example TypedefTypes of the RecordType, but
+ after the change they don't; to fix, use:
+
+::
+ hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(recordDecl(...)))))
+
+- templateSpecializationType(hasDeclaration(classTemplateDecl(...))):
+ previously, we would directly match the underlying ClassTemplateDecl;
+ now, we can explicitly match the ClassTemplateSpecializationDecl, but that
+ requires to explicitly get the ClassTemplateDecl:
+
+::
+ templateSpecializationType(hasDeclaration(
+ classTemplateSpecializationDecl(
+ hasSpecializedTemplate(classTemplateDecl(...)))))
+
+clang-format
+------------
+
+* Option *IndentPPDirectives* added to indent preprocessor directives on
+ conditionals.
+
+ +----------------------+----------------------+
+ | Before | After |
+ +======================+======================+
+ | .. code-block:: c++ | .. code-block:: c++ |
+ | | |
+ | #if FOO | #if FOO |
+ | #if BAR | # if BAR |
+ | #include <foo> | # include <foo> |
+ | #endif | # endif |
+ | #endif | #endif |
+ +----------------------+----------------------+
+
+* Option -verbose added to the command line.
+ Shows the list of processed files.
libclang
--------
@@ -139,6 +258,14 @@ Static Analyzer
...
+Undefined Behavior Sanitizer (UBSan)
+------------------------------------
+
+* A minimal runtime is now available. It is suitable for use in production
+ environments, and has a small attack surface. It only provides very basic
+ issue logging and deduplication, and does not support ``-fsanitize=vptr``
+ checking.
+
Core Analysis Improvements
==========================
diff --git a/docs/SanitizerCoverage.rst b/docs/SanitizerCoverage.rst
index 8ff5bdf3a3..e1c3fc91d3 100644
--- a/docs/SanitizerCoverage.rst
+++ b/docs/SanitizerCoverage.rst
@@ -8,335 +8,12 @@ SanitizerCoverage
Introduction
============
-Sanitizer tools have a very simple code coverage tool built in. It allows to
-get function-level, basic-block-level, and edge-level coverage at a very low
-cost.
-
-How to build and run
-====================
-
-SanitizerCoverage can be used with :doc:`AddressSanitizer`,
-:doc:`LeakSanitizer`, :doc:`MemorySanitizer`,
-UndefinedBehaviorSanitizer, or without any sanitizer. Pass one of the
-following compile-time flags:
-
-* ``-fsanitize-coverage=func`` for function-level coverage (very fast).
-* ``-fsanitize-coverage=bb`` for basic-block-level coverage (may add up to 30%
- **extra** slowdown).
-* ``-fsanitize-coverage=edge`` for edge-level coverage (up to 40% slowdown).
-
-You may also specify ``-fsanitize-coverage=indirect-calls`` for
-additional `caller-callee coverage`_.
-
-At run time, pass ``coverage=1`` in ``ASAN_OPTIONS``,
-``LSAN_OPTIONS``, ``MSAN_OPTIONS`` or ``UBSAN_OPTIONS``, as
-appropriate. For the standalone coverage mode, use ``UBSAN_OPTIONS``.
-
-To get `Coverage counters`_, add ``-fsanitize-coverage=8bit-counters``
-to one of the above compile-time flags. At runtime, use
-``*SAN_OPTIONS=coverage=1:coverage_counters=1``.
-
-Example:
-
-.. code-block:: console
-
- % cat -n cov.cc
- 1 #include <stdio.h>
- 2 __attribute__((noinline))
- 3 void foo() { printf("foo\n"); }
- 4
- 5 int main(int argc, char **argv) {
- 6 if (argc == 2)
- 7 foo();
- 8 printf("main\n");
- 9 }
- % clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=func
- % ASAN_OPTIONS=coverage=1 ./a.out; ls -l *sancov
- main
- -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
- % ASAN_OPTIONS=coverage=1 ./a.out foo ; ls -l *sancov
- foo
- main
- -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
- -rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
-
-Every time you run an executable instrumented with SanitizerCoverage
-one ``*.sancov`` file is created during the process shutdown.
-If the executable is dynamically linked against instrumented DSOs,
-one ``*.sancov`` file will be also created for every DSO.
-
-Postprocessing
-==============
-
-The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic,
-one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the
-magic defines the size of the following offsets. The rest of the data is the
-offsets in the corresponding binary/DSO that were executed during the run.
-
-A simple script
-``$LLVM/projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py`` is
-provided to dump these offsets.
-
-.. code-block:: console
-
- % sancov.py print a.out.22679.sancov a.out.22673.sancov
- sancov.py: read 2 PCs from a.out.22679.sancov
- sancov.py: read 1 PCs from a.out.22673.sancov
- sancov.py: 2 files merged; 2 PCs total
- 0x465250
- 0x4652a0
-
-You can then filter the output of ``sancov.py`` through ``addr2line --exe
-ObjectFile`` or ``llvm-symbolizer --obj ObjectFile`` to get file names and line
-numbers:
-
-.. code-block:: console
-
- % sancov.py print a.out.22679.sancov a.out.22673.sancov 2> /dev/null | llvm-symbolizer --obj a.out
- cov.cc:3
- cov.cc:5
-
-Sancov Tool
-===========
-
-A new experimental ``sancov`` tool is developed to process coverage files.
-The tool is part of LLVM project and is currently supported only on Linux.
-It can handle symbolization tasks autonomously without any extra support
-from the environment. You need to pass .sancov files (named
-``<module_name>.<pid>.sancov`` and paths to all corresponding binary elf files.
-Sancov matches these files using module names and binaries file names.
-
-.. code-block:: console
-
- USAGE: sancov [options] <action> (<binary file>|<.sancov file>)...
-
- Action (required)
- -print - Print coverage addresses
- -covered-functions - Print all covered functions.
- -not-covered-functions - Print all not covered functions.
- -symbolize - Symbolizes the report.
-
- Options
- -blacklist=<string> - Blacklist file (sanitizer blacklist format).
- -demangle - Print demangled function name.
- -strip_path_prefix=<string> - Strip this prefix from file paths in reports
-
-
-Coverage Reports (Experimental)
-================================
-
-``.sancov`` files do not contain enough information to generate a source-level
-coverage report. The missing information is contained
-in debug info of the binary. Thus the ``.sancov`` has to be symbolized
-to produce a ``.symcov`` file first:
-
-.. code-block:: console
-
- sancov -symbolize my_program.123.sancov my_program > my_program.123.symcov
-
-The ``.symcov`` file can be browsed overlayed over the source code by
-running ``tools/sancov/coverage-report-server.py`` script that will start
-an HTTP server.
-
-
-How good is the coverage?
-=========================
-
-It is possible to find out which PCs are not covered, by subtracting the covered
-set from the set of all instrumented PCs. The latter can be obtained by listing
-all callsites of ``__sanitizer_cov()`` in the binary. On Linux, ``sancov.py``
-can do this for you. Just supply the path to binary and a list of covered PCs:
-
-.. code-block:: console
-
- % sancov.py print a.out.12345.sancov > covered.txt
- sancov.py: read 2 64-bit PCs from a.out.12345.sancov
- sancov.py: 1 file merged; 2 PCs total
- % sancov.py missing a.out < covered.txt
- sancov.py: found 3 instrumented PCs in a.out
- sancov.py: read 2 PCs from stdin
- sancov.py: 1 PCs missing from coverage
- 0x4cc61c
-
-Edge coverage
-=============
-
-Consider this code:
-
-.. code-block:: c++
-
- void foo(int *a) {
- if (a)
- *a = 0;
- }
-
-It contains 3 basic blocks, let's name them A, B, C:
-
-.. code-block:: none
-
- A
- |\
- | \
- | B
- | /
- |/
- C
-
-If blocks A, B, and C are all covered we know for certain that the edges A=>B
-and B=>C were executed, but we still don't know if the edge A=>C was executed.
-Such edges of control flow graph are called
-`critical <http://en.wikipedia.org/wiki/Control_flow_graph#Special_edges>`_. The
-edge-level coverage (``-fsanitize-coverage=edge``) simply splits all critical
-edges by introducing new dummy blocks and then instruments those blocks:
-
-.. code-block:: none
-
- A
- |\
- | \
- D B
- | /
- |/
- C
-
-Bitset
-======
-
-When ``coverage_bitset=1`` run-time flag is given, the coverage will also be
-dumped as a bitset (text file with 1 for blocks that have been executed and 0
-for blocks that were not).
-
-.. code-block:: console
-
- % clang++ -fsanitize=address -fsanitize-coverage=edge cov.cc
- % ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out
- main
- % ASAN_OPTIONS="coverage=1:coverage_bitset=1" ./a.out 1
- foo
- main
- % head *bitset*
- ==> a.out.38214.bitset-sancov <==
- 01101
- ==> a.out.6128.bitset-sancov <==
- 11011%
-
-For a given executable the length of the bitset is always the same (well,
-unless dlopen/dlclose come into play), so the bitset coverage can be
-easily used for bitset-based corpus distillation.
-
-Caller-callee coverage
-======================
-
-**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
-pairs of lines (odd lines are callers, even lines are callees)
-
-.. code-block:: console
-
- a.out 0x4a2e0c
- a.out 0x4a6510
- a.out 0x4a2e0c
- a.out 0x4a87f0
-
-Current limitations:
-
-* Only the first 14 callees for every caller are recorded, the rest are silently
- ignored.
-* The output format is not very compact since caller and callee may reside in
- different modules and we need to spell out the module names.
-* The routine that dumps the output is not optimized for speed
-* Only Linux x86_64 is tested so far.
-* Sandboxes are not supported.
-
-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
-more sensitive coverage information. In addition to boolean values assigned to
-every basic block (edge) the instrumentation will collect imprecise counters.
-On exit, every counter will be mapped to a 8-bit bitset representing counter
-ranges: ``1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+`` and those 8-bit bitsets will
-be dumped to disk.
-
-.. code-block:: console
-
- % clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=edge,8bit-counters
- % ASAN_OPTIONS="coverage=1:coverage_counters=1" ./a.out
- % ls -l *counters-sancov
- ... a.out.17110.counters-sancov
- % xxd *counters-sancov
- 0000000: 0001 0100 01
-
-These counters may also be used for in-process coverage-guided fuzzers. See
-``include/sanitizer/coverage_interface.h``:
-
-.. code-block:: c++
-
- // The coverage instrumentation may optionally provide imprecise counters.
- // Rather than exposing the counter values to the user we instead map
- // the counters to a bitset.
- // Every counter is associated with 8 bits in the bitset.
- // We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+
- // The i-th bit is set to 1 if the counter value is in the i-th range.
- // This counter-based coverage implementation is *not* thread-safe.
-
- // Returns the number of registered coverage counters.
- uintptr_t __sanitizer_get_number_of_counters();
- // Updates the counter 'bitset', clears the counters and returns the number of
- // new bits in 'bitset'.
- // If 'bitset' is nullptr, only clears the counters.
- // Otherwise 'bitset' should be at least
- // __sanitizer_get_number_of_counters bytes long and 8-aligned.
- uintptr_t
- __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
-
-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
-(depending on the value of ``-fsanitize-coverage=[func,bb,edge]``).
-Example:
-
-.. code-block:: console
-
- % clang -g -fsanitize=address -fsanitize-coverage=edge,trace-bb foo.cc
- % ASAN_OPTIONS=coverage=1 ./a.out
-
-This will produce two files after the process exit:
-`trace-points.PID.sancov` and `trace-events.PID.sancov`.
-The first file will contain a textual description of all the instrumented points in the program
-in the form that you can feed into llvm-symbolizer (e.g. `a.out 0x4dca89`), one per line.
-The second file will contain the actual execution trace as a sequence of 4-byte integers
--- these integers are the indices into the array of instrumented points (the first file).
-
-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.
-With an additional ``...=trace-pc,indirect-calls`` flag
-``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
-These callbacks are not implemented in the Sanitizer run-time and should be defined
-by the user. So, these flags do not require the other sanitizer to be used.
-This mechanism is used for fuzzing the Linux kernel (https://github.com/google/syzkaller)
-and can be used with `AFL <http://lcamtuf.coredump.cx/afl>`__.
+LLVM has a simple code coverage instrumentation built in (SanitizerCoverage).
+It inserts calls to user-defined functions on function-, basic-block-, and edge- levels.
+Default implementations of those callbacks are provided and implement
+simple coverage reporting and visualization,
+however if you need *just* coverage visualization you may want to use
+:doc:`SourceBasedCodeCoverage <SourceBasedCodeCoverage>` instead.
Tracing PCs with guards
=======================
@@ -350,7 +27,7 @@ on every edge:
Every edge will have its own `guard_variable` (uint32_t).
-The compler will also insert a module constructor that will call
+The compler will also insert calls to a module constructor:
.. code-block:: c++
@@ -359,7 +36,7 @@ The compler will also insert a module constructor that will call
// more than once with the same values of start/stop.
__sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop);
-With `trace-pc-guards,indirect-calls`
+With an additional ``...=trace-pc,indirect-calls`` flag
``__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.
@@ -442,6 +119,122 @@ Example:
guard: 0x71bcdc 4 PC 0x4ecdc7 in main trace-pc-guard-example.cc:4:17
guard: 0x71bcd0 1 PC 0x4ecd20 in foo() trace-pc-guard-example.cc:2:14
+Inline 8bit-counters
+====================
+
+**Experimental, may change or disappear in future**
+
+With ``-fsanitize-coverage=inline-8bit-counters`` the compiler will insert
+inline counter increments on every edge.
+This is similar to ``-fsanitize-coverage=trace-pc-guard`` but instead of a
+callback the instrumentation simply increments a counter.
+
+Users need to implement a single function to capture the counters at startup.
+
+.. code-block:: c++
+
+ extern "C"
+ void __sanitizer_cov_8bit_counters_init(char *start, char *end) {
+ // [start,end) is the array of 8-bit counters created for the current DSO.
+ // Capture this array in order to read/modify the counters.
+ }
+
+PC-Table
+========
+
+**Experimental, may change or disappear in future**
+
+With ``-fsanitize-coverage=pc-table`` the compiler will create a table of
+instrumented PCs. Requires either ``-fsanitize-coverage=inline-8bit-counters`` or
+``-fsanitize-coverage=trace-pc-guard``.
+
+Users need to implement a single function to capture the PC table at startup:
+
+.. code-block:: c++
+
+ extern "C"
+ void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
+ const uintptr_t *pcs_end) {
+ // [pcs_beg,pcs_end) is the array of ptr-sized integers representing
+ // pairs [PC,PCFlags] for every instrumented block in the current DSO.
+ // Capture this array in order to read the PCs and their Flags.
+ // The number of PCs and PCFlags for a given DSO is the same as the number
+ // of 8-bit counters (-fsanitize-coverage=inline-8bit-counters) or
+ // trace_pc_guard callbacks (-fsanitize-coverage=trace-pc-guard)
+ // A PCFlags describes the basic block:
+ // * bit0: 1 if the block is the function entry block, 0 otherwise.
+ }
+
+
+Tracing PCs
+===========
+
+With ``-fsanitize-coverage=trace-pc`` the compiler will insert
+``__sanitizer_cov_trace_pc()`` on every edge.
+With an additional ``...=trace-pc,indirect-calls`` flag
+``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
+These callbacks are not implemented in the Sanitizer run-time and should be defined
+by the user.
+This mechanism is used for fuzzing the Linux kernel
+(https://github.com/google/syzkaller).
+
+Instrumentation points
+======================
+Sanitizer Coverage offers different levels of instrumentation.
+
+* ``edge`` (default): edges are instrumented (see below).
+* ``bb``: basic blocks are instrumented.
+* ``func``: only the entry block of every function will be instrumented.
+
+Use these flags together with ``trace-pc-guard`` or ``trace-pc``,
+like this: ``-fsanitize-coverage=func,trace-pc-guard``.
+
+When ``edge`` or ``bb`` is used, some of the edges/blocks may still be left
+uninstrumented (pruned) if such instrumentation is considered redundant.
+Use ``no-prune`` (e.g. ``-fsanitize-coverage=bb,no-prune,trace-pc-guard``)
+to disable pruning. This could be useful for better coverage visualization.
+
+
+Edge coverage
+-------------
+
+Consider this code:
+
+.. code-block:: c++
+
+ void foo(int *a) {
+ if (a)
+ *a = 0;
+ }
+
+It contains 3 basic blocks, let's name them A, B, C:
+
+.. code-block:: none
+
+ A
+ |\
+ | \
+ | B
+ | /
+ |/
+ C
+
+If blocks A, B, and C are all covered we know for certain that the edges A=>B
+and B=>C were executed, but we still don't know if the edge A=>C was executed.
+Such edges of control flow graph are called
+`critical <http://en.wikipedia.org/wiki/Control_flow_graph#Special_edges>`_. The
+edge-level coverage simply splits all critical
+edges by introducing new dummy blocks and then instruments those blocks:
+
+.. code-block:: none
+
+ A
+ |\
+ | \
+ D B
+ | /
+ |/
+ C
Tracing data flow
=================
@@ -464,6 +257,14 @@ the `LLVM GEP instructions <http://llvm.org/docs/GetElementPtr.html>`_
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2);
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2);
+ // Called before a comparison instruction if exactly one of the arguments is constant.
+ // Arg1 and Arg2 are arguments of the comparison, Arg1 is a compile-time constant.
+ // These callbacks are emitted by -fsanitize-coverage=trace-cmp since 2017-08-11
+ void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2);
+ void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2);
+ void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2);
+ void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2);
+
// Called before a switch statement.
// Val is the switch operand.
// Cases[0] is the number of case constants.
@@ -480,111 +281,106 @@ the `LLVM GEP instructions <http://llvm.org/docs/GetElementPtr.html>`_
// for every non-constant array index.
void __sanitizer_cov_trace_gep(uintptr_t Idx);
+Default implementation
+======================
-This interface is a subject to change.
-The current implementation is not thread-safe and thus can be safely used only for single-threaded targets.
+The sanitizer run-time (AddressSanitizer, MemorySanitizer, etc) provide a
+default implementations of some of the coverage callbacks.
+You may use this implementation to dump the coverage on disk at the process
+exit.
-Output directory
-================
+Example:
-By default, .sancov files are created in the current working directory.
-This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``:
+.. code-block:: console
+
+ % cat -n cov.cc
+ 1 #include <stdio.h>
+ 2 __attribute__((noinline))
+ 3 void foo() { printf("foo\n"); }
+ 4
+ 5 int main(int argc, char **argv) {
+ 6 if (argc == 2)
+ 7 foo();
+ 8 printf("main\n");
+ 9 }
+ % clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=trace-pc-guard
+ % ASAN_OPTIONS=coverage=1 ./a.out; wc -c *.sancov
+ main
+ SanitizerCoverage: ./a.out.7312.sancov 2 PCs written
+ 24 a.out.7312.sancov
+ % ASAN_OPTIONS=coverage=1 ./a.out foo ; wc -c *.sancov
+ foo
+ main
+ SanitizerCoverage: ./a.out.7316.sancov 3 PCs written
+ 24 a.out.7312.sancov
+ 32 a.out.7316.sancov
+
+Every time you run an executable instrumented with SanitizerCoverage
+one ``*.sancov`` file is created during the process shutdown.
+If the executable is dynamically linked against instrumented DSOs,
+one ``*.sancov`` file will be also created for every DSO.
+
+Sancov data format
+------------------
+
+The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic,
+one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the
+magic defines the size of the following offsets. The rest of the data is the
+offsets in the corresponding binary/DSO that were executed during the run.
+
+Sancov Tool
+-----------
+
+An simple ``sancov`` tool is provided to process coverage files.
+The tool is part of LLVM project and is currently supported only on Linux.
+It can handle symbolization tasks autonomously without any extra support
+from the environment. You need to pass .sancov files (named
+``<module_name>.<pid>.sancov`` and paths to all corresponding binary elf files.
+Sancov matches these files using module names and binaries file names.
.. code-block:: console
- % ASAN_OPTIONS="coverage=1:coverage_dir=/tmp/cov" ./a.out foo
- % ls -l /tmp/cov/*sancov
- -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
- -rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
+ USAGE: sancov [options] <action> (<binary file>|<.sancov file>)...
-Sudden death
-============
+ Action (required)
+ -print - Print coverage addresses
+ -covered-functions - Print all covered functions.
+ -not-covered-functions - Print all not covered functions.
+ -symbolize - Symbolizes the report.
+
+ Options
+ -blacklist=<string> - Blacklist file (sanitizer blacklist format).
+ -demangle - Print demangled function name.
+ -strip_path_prefix=<string> - Strip this prefix from file paths in reports
-Normally, coverage data is collected in memory and saved to disk when the
-program exits (with an ``atexit()`` handler), when a SIGSEGV is caught, or when
-``__sanitizer_cov_dump()`` is called.
-If the program ends with a signal that ASan does not handle (or can not handle
-at all, like SIGKILL), coverage data will be lost. This is a big problem on
-Android, where SIGKILL is a normal way of evicting applications from memory.
+Coverage Reports
+----------------
-With ``ASAN_OPTIONS=coverage=1:coverage_direct=1`` coverage data is written to a
-memory-mapped file as soon as it collected.
+**Experimental**
+
+``.sancov`` files do not contain enough information to generate a source-level
+coverage report. The missing information is contained
+in debug info of the binary. Thus the ``.sancov`` has to be symbolized
+to produce a ``.symcov`` file first:
.. code-block:: console
- % ASAN_OPTIONS="coverage=1:coverage_direct=1" ./a.out
- main
- % ls
- 7036.sancov.map 7036.sancov.raw a.out
- % sancov.py rawunpack 7036.sancov.raw
- sancov.py: reading map 7036.sancov.map
- sancov.py: unpacking 7036.sancov.raw
- writing 1 PCs to a.out.7036.sancov
- % sancov.py print a.out.7036.sancov
- sancov.py: read 1 PCs from a.out.7036.sancov
- sancov.py: 1 files merged; 1 PCs total
- 0x4b2bae
-
-Note that on 64-bit platforms, this method writes 2x more data than the default,
-because it stores full PC values instead of 32-bit offsets.
-
-In-process fuzzing
-==================
-
-Coverage data could be useful for fuzzers and sometimes it is preferable to run
-a fuzzer in the same process as the code being fuzzed (in-process fuzzer).
-
-You can use ``__sanitizer_get_total_unique_coverage()`` from
-``<sanitizer/coverage_interface.h>`` which returns the number of currently
-covered entities in the program. This will tell the fuzzer if the coverage has
-increased after testing every new input.
-
-If a fuzzer finds a bug in the ASan run, you will need to save the reproducer
-before exiting the process. Use ``__asan_set_death_callback`` from
-``<sanitizer/asan_interface.h>`` to do that.
-
-An example of such fuzzer can be found in `the LLVM tree
-<http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/README.txt?view=markup>`_.
-
-Performance
-===========
+ sancov -symbolize my_program.123.sancov my_program > my_program.123.symcov
+
+The ``.symcov`` file can be browsed overlayed over the source code by
+running ``tools/sancov/coverage-report-server.py`` script that will start
+an HTTP server.
+
+Output directory
+----------------
+
+By default, .sancov files are created in the current working directory.
+This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``:
+
+.. code-block:: console
-This coverage implementation is **fast**. With function-level coverage
-(``-fsanitize-coverage=func``) the overhead is not measurable. With
-basic-block-level coverage (``-fsanitize-coverage=bb``) the overhead varies
-between 0 and 25%.
-
-============== ========= ========= ========= ========= ========= =========
- benchmark cov0 cov1 diff 0-1 cov2 diff 0-2 diff 1-2
-============== ========= ========= ========= ========= ========= =========
- 400.perlbench 1296.00 1307.00 1.01 1465.00 1.13 1.12
- 401.bzip2 858.00 854.00 1.00 1010.00 1.18 1.18
- 403.gcc 613.00 617.00 1.01 683.00 1.11 1.11
- 429.mcf 605.00 582.00 0.96 610.00 1.01 1.05
- 445.gobmk 896.00 880.00 0.98 1050.00 1.17 1.19
- 456.hmmer 892.00 892.00 1.00 918.00 1.03 1.03
- 458.sjeng 995.00 1009.00 1.01 1217.00 1.22 1.21
-462.libquantum 497.00 492.00 0.99 534.00 1.07 1.09
- 464.h264ref 1461.00 1467.00 1.00 1543.00 1.06 1.05
- 471.omnetpp 575.00 590.00 1.03 660.00 1.15 1.12
- 473.astar 658.00 652.00 0.99 715.00 1.09 1.10
- 483.xalancbmk 471.00 491.00 1.04 582.00 1.24 1.19
- 433.milc 616.00 627.00 1.02 627.00 1.02 1.00
- 444.namd 602.00 601.00 1.00 654.00 1.09 1.09
- 447.dealII 630.00 634.00 1.01 653.00 1.04 1.03
- 450.soplex 365.00 368.00 1.01 395.00 1.08 1.07
- 453.povray 427.00 434.00 1.02 495.00 1.16 1.14
- 470.lbm 357.00 375.00 1.05 370.00 1.04 0.99
- 482.sphinx3 927.00 928.00 1.00 1000.00 1.08 1.08
-============== ========= ========= ========= ========= ========= =========
-
-Why another coverage?
-=====================
-
-Why did we implement yet another code coverage?
- * We needed something that is lightning fast, plays well with
- AddressSanitizer, and does not significantly increase the binary size.
- * Traditional coverage implementations based in global counters
- `suffer from contention on counters
- <https://groups.google.com/forum/#!topic/llvm-dev/cDqYgnxNEhY>`_.
+ % ASAN_OPTIONS="coverage=1:coverage_dir=/tmp/cov" ./a.out foo
+ % ls -l /tmp/cov/*sancov
+ -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
+ -rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
diff --git a/docs/SanitizerSpecialCaseList.rst b/docs/SanitizerSpecialCaseList.rst
index a4165b2521..a636a02b01 100644
--- a/docs/SanitizerSpecialCaseList.rst
+++ b/docs/SanitizerSpecialCaseList.rst
@@ -51,14 +51,23 @@ Example
Format
======
-Each line contains an entity type, followed by a colon and a regular
-expression, specifying the names of the entities, optionally followed by
-an equals sign and a tool-specific category. Empty lines and lines starting
-with "#" are ignored. The meanining of ``*`` in regular expression for entity
-names is different - it is treated as in shell wildcarding. Two generic
-entity types are ``src`` and ``fun``, which allow user to add, respectively,
-source files and functions to special case list. Some sanitizer tools may
-introduce custom entity types - refer to tool-specific docs.
+Blacklists consist of entries, optionally grouped into sections. Empty lines and
+lines starting with "#" are ignored.
+
+Section names are regular expressions written in square brackets that denote
+which sanitizer the following entries apply to. For example, ``[address]``
+specifies AddressSanitizer while ``[cfi-vcall|cfi-icall]`` specifies Control
+Flow Integrity virtual and indirect call checking. Entries without a section
+will be placed under the ``[*]`` section applying to all enabled sanitizers.
+
+Entries contain an entity type, followed by a colon and a regular expression,
+specifying the names of the entities, optionally followed by an equals sign and
+a tool-specific category, e.g. ``fun:*ExampleFunc=example_category``. The
+meaning of ``*`` in regular expression for entity names is different - it is
+treated as in shell wildcarding. Two generic entity types are ``src`` and
+``fun``, which allow users to specify source files and functions, respectively.
+Some sanitizer tools may introduce custom entity types and categories - refer to
+tool-specific docs.
.. code-block:: bash
@@ -77,3 +86,10 @@ introduce custom entity types - refer to tool-specific docs.
fun:*BadFunction*
# Specific sanitizer tools may introduce categories.
src:/special/path/*=special_sources
+ # Sections can be used to limit blacklist entries to specific sanitizers
+ [address]
+ fun:*BadASanFunc*
+ # Section names are regular expressions
+ [cfi-vcall|cfi-icall]
+ fun:*BadCfiCall
+ # Entries without sections are placed into [*] and apply to all sanitizers
diff --git a/docs/SourceBasedCodeCoverage.rst b/docs/SourceBasedCodeCoverage.rst
index 474af30ae3..805c987948 100644
--- a/docs/SourceBasedCodeCoverage.rst
+++ b/docs/SourceBasedCodeCoverage.rst
@@ -274,6 +274,11 @@ To specify an alternate directory for raw profiles, use
Drawbacks and limitations
=========================
+* Prior to version 2.26, the GNU binutils BFD linker is not able link programs
+ compiled with ``-fcoverage-mapping`` in its ``--gc-sections`` mode. Possible
+ workarounds include disabling ``--gc-sections``, upgrading to a newer version
+ of BFD, or using the Gold linker.
+
* Code coverage does not handle unpredictable changes in control flow or stack
unwinding in the presence of exceptions precisely. Consider the following
function:
diff --git a/docs/ThinLTO.rst b/docs/ThinLTO.rst
index 7c7d951302..607121fd1e 100644
--- a/docs/ThinLTO.rst
+++ b/docs/ThinLTO.rst
@@ -63,7 +63,7 @@ ThinLTO is currently supported for the following linkers:
- **ld64**:
Starting with `Xcode 8 <https://developer.apple.com/xcode/>`_.
- **lld**:
- Starting with r284050 (ELF only).
+ Starting with r284050 for ELF, r298942 for COFF.
Usage
=====
@@ -78,6 +78,13 @@ To utilize ThinLTO, simply add the -flto=thin option to compile and link. E.g.
% clang -flto=thin -O2 file1.c file2.c -c
% clang -flto=thin -O2 file1.o file2.o -o a.out
+When using lld-link, the -flto option need only be added to the compile step:
+
+.. code-block:: console
+
+ % clang-cl -flto=thin -O2 -c file1.c file2.c
+ % lld-link /out:a.exe file1.obj file2.obj
+
As mentioned earlier, by default the linkers will launch the ThinLTO backend
threads in parallel, passing the resulting native object files back to the
linker for the final native link. As such, the usage model the same as
@@ -111,6 +118,8 @@ be reduced to ``N`` via:
``-Wl,-mllvm,-threads=N``
- lld:
``-Wl,--thinlto-jobs=N``
+- lld-link:
+ ``/opt:lldltojobs=N``
Incremental
-----------
@@ -119,10 +128,62 @@ Incremental
ThinLTO supports fast incremental builds through the use of a cache,
which currently must be enabled through a linker option.
-- gold (as of LLVM r279883):
+- gold (as of LLVM 4.0):
``-Wl,-plugin-opt,cache-dir=/path/to/cache``
- ld64 (support in clang 3.9 and Xcode 8):
``-Wl,-cache_path_lto,/path/to/cache``
+- ELF lld (as of LLVM 5.0):
+ ``-Wl,--thinlto-cache-dir=/path/to/cache``
+- COFF lld-link (as of LLVM 6.0):
+ ``/lldltocache:/path/to/cache``
+
+Cache Pruning
+-------------
+
+To help keep the size of the cache under control, ThinLTO supports cache
+pruning. Cache pruning is supported with gold, ld64 and ELF and COFF lld, but
+currently only gold, ELF and COFF lld allow you to control the policy with a
+policy string. The cache policy must be specified with a linker option.
+
+- gold (as of LLVM 6.0):
+ ``-Wl,-plugin-opt,cache-policy=POLICY``
+- ELF lld (as of LLVM 5.0):
+ ``-Wl,--thinlto-cache-policy,POLICY``
+- COFF lld-link (as of LLVM 6.0):
+ ``/lldltocachepolicy:POLICY``
+
+A policy string is a series of key-value pairs separated by ``:`` characters.
+Possible key-value pairs are:
+
+- ``cache_size=X%``: The maximum size for the cache directory is ``X`` percent
+ of the available space on the the disk. Set to 100 to indicate no limit,
+ 50 to indicate that the cache size will not be left over half the available
+ disk space. A value over 100 is invalid. A value of 0 disables the percentage
+ size-based pruning. The default is 75%.
+
+- ``cache_size_bytes=X``, ``cache_size_bytes=Xk``, ``cache_size_bytes=Xm``,
+ ``cache_size_bytes=Xg``:
+ Sets the maximum size for the cache directory to ``X`` bytes (or KB, MB,
+ GB respectively). A value over the amount of available space on the disk
+ will be reduced to the amount of available space. A value of 0 disables
+ the byte size-based pruning. The default is no byte size-based pruning.
+
+ Note that ThinLTO will apply both size-based pruning policies simultaneously,
+ and changing one does not affect the other. For example, a policy of
+ ``cache_size_bytes=1g`` on its own will cause both the 1GB and default 75%
+ policies to be applied unless the default ``cache_size`` is overridden.
+
+- ``prune_after=Xs``, ``prune_after=Xm``, ``prune_after=Xh``: Sets the
+ expiration time for cache files to ``X`` seconds (or minutes, hours
+ respectively). When a file hasn't been accessed for ``prune_after`` seconds,
+ it is removed from the cache. A value of 0 disables the expiration-based
+ pruning. The default is 1 week.
+
+- ``prune_interval=Xs``, ``prune_interval=Xm``, ``prune_interval=Xh``:
+ Sets the pruning interval to ``X`` seconds (or minutes, hours
+ respectively). This is intended to be used to avoid scanning the directory
+ too often. It does not impact the decision of which files to prune. A
+ value of 0 forces the scan to occur. The default is every 20 minutes.
Clang Bootstrap
---------------
@@ -137,13 +198,20 @@ To bootstrap clang/LLVM with ThinLTO, follow these steps:
when configuring the bootstrap compiler build:
* ``-DLLVM_ENABLE_LTO=Thin``
- * ``-DLLVM_PARALLEL_LINK_JOBS=1``
- (since the ThinLTO link invokes parallel backend jobs)
* ``-DCMAKE_C_COMPILER=/path/to/host/clang``
* ``-DCMAKE_CXX_COMPILER=/path/to/host/clang++``
* ``-DCMAKE_RANLIB=/path/to/host/llvm-ranlib``
* ``-DCMAKE_AR=/path/to/host/llvm-ar``
+ Or, on Windows:
+
+ * ``-DLLVM_ENABLE_LTO=Thin``
+ * ``-DCMAKE_C_COMPILER=/path/to/host/clang-cl.exe``
+ * ``-DCMAKE_CXX_COMPILER=/path/to/host/clang-cl.exe``
+ * ``-DCMAKE_LINKER=/path/to/host/lld-link.exe``
+ * ``-DCMAKE_RANLIB=/path/to/host/llvm-ranlib.exe``
+ * ``-DCMAKE_AR=/path/to/host/llvm-ar.exe``
+
#. To use additional linker arguments for controlling the backend
parallelism_ or enabling incremental_ builds of the bootstrap compiler,
after configuring the build, modify the resulting CMakeCache.txt file in the
diff --git a/docs/ThreadSafetyAnalysis.rst b/docs/ThreadSafetyAnalysis.rst
index 19ec2352ff..ea8e98a188 100644
--- a/docs/ThreadSafetyAnalysis.rst
+++ b/docs/ThreadSafetyAnalysis.rst
@@ -764,8 +764,6 @@ implementation.
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
- #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-
#define CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
@@ -886,11 +884,11 @@ implementation.
// Deprecated.
#define PT_GUARDED_VAR \
- THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded)
+ THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var)
// Deprecated.
#define GUARDED_VAR \
- THREAD_ANNOTATION_ATTRIBUTE__(guarded)
+ THREAD_ANNOTATION_ATTRIBUTE__(guarded_var)
// Replaced by REQUIRES
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
diff --git a/docs/Toolchain.rst b/docs/Toolchain.rst
index 6ae8888c69..e727ccdc7c 100644
--- a/docs/Toolchain.rst
+++ b/docs/Toolchain.rst
@@ -222,7 +222,7 @@ Unwind library
The unwind library provides a family of ``_Unwind_*`` functions implementing
the language-neutral stack unwinding portion of the Itanium C++ ABI
-(`Level I <http://mentorembedded.github.io/cxx-abi/abi-eh.html#base-abi>`_).
+(`Level I <http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-abi>`_).
It is a dependency of the C++ ABI library, and sometimes is a dependency
of other runtimes.
@@ -288,9 +288,9 @@ C++ ABI library
The C++ ABI library provides an implementation of the library portion of
the Itanium C++ ABI, covering both the
`support functionality in the main Itanium C++ ABI document
-<http://mentorembedded.github.io/cxx-abi/abi.html>`_ and
+<http://itanium-cxx-abi.github.io/cxx-abi/abi.html>`_ and
`Level II of the exception handling support
-<http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi>`_.
+<http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-abi>`_.
References to the functions and objects in this library are implicitly
generated by Clang when compiling C++ code.
diff --git a/docs/UndefinedBehaviorSanitizer.rst b/docs/UndefinedBehaviorSanitizer.rst
index f9111ee846..0a08a41e2d 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:
@@ -75,6 +75,7 @@ Available checks are:
of a misaligned reference.
- ``-fsanitize=bool``: Load of a ``bool`` value which is neither
``true`` nor ``false``.
+ - ``-fsanitize=builtin``: Passing invalid values to compiler builtins.
- ``-fsanitize=bounds``: Out of bounds array indexing, in cases
where the array bound can be statically determined.
- ``-fsanitize=enum``: Load of a value of an enumerated type which
@@ -86,7 +87,8 @@ Available checks are:
- ``-fsanitize=float-divide-by-zero``: Floating point division by
zero.
- ``-fsanitize=function``: Indirect call of a function through a
- function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
+ function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64
+ only).
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
parameter which is declared to never be null.
@@ -106,6 +108,8 @@ Available checks are:
invalid pointers. These checks are made in terms of
``__builtin_object_size``, and consequently may be able to detect more
problems at higher optimization levels.
+ - ``-fsanitize=pointer-overflow``: Performing pointer arithmetic which
+ overflows.
- ``-fsanitize=return``: In C++, reaching the end of a
value-returning function without returning a value.
- ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
@@ -128,11 +132,11 @@ Available checks are:
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
- it is of the wrong dynamic type, or that its lifetime has not
- begun or has ended. Incompatible with ``-fno-rtti``. Link must
- be performed by ``clang++``, not ``clang``, to make sure C++-specific
- parts of the runtime library and C++ standard libraries are present.
+ - ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of
+ the wrong dynamic type, or that its lifetime has not begun or has ended.
+ Incompatible with ``-fno-rtti``. Link must be performed by ``clang++``, not
+ ``clang``, to make sure C++-specific parts of the runtime library and C++
+ standard libraries are present.
You can also use the following check groups:
- ``-fsanitize=undefined``: All of the checks listed above other than
@@ -146,6 +150,25 @@ You can also use the following check groups:
nullability does not have undefined behavior, it is often unintentional,
so UBSan offers to catch it.
+Volatile
+--------
+
+The ``null``, ``alignment``, ``object-size``, and ``vptr`` checks do not apply
+to pointers to types with the ``volatile`` qualifier.
+
+Minimal Runtime
+===============
+
+There is a minimal UBSan runtime available suitable for use in production
+environments. This runtime has a small attack surface. It only provides very
+basic issue logging and deduplication, and does not support ``-fsanitize=vptr``
+checking.
+
+To use the minimal runtime, add ``-fsanitize-minimal-runtime`` to the clang
+command line options. For example, if you're used to compiling with
+``-fsanitize=undefined``, you could enable the minimal runtime with
+``-fsanitize=undefined -fsanitize-minimal-runtime``.
+
Stack traces and report symbolization
=====================================
If you want UBSan to print symbolized stack trace for each error report, you
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index beb55ca251..023f9f5528 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -107,7 +107,7 @@ Options to Control Error and Warning Messages
.. option:: -Wno-error=foo
- Turn warning "foo" into an warning even if :option:`-Werror` is specified.
+ Turn warning "foo" into a warning even if :option:`-Werror` is specified.
.. option:: -Wfoo
@@ -322,18 +322,40 @@ output format of the diagnostics that it generates.
by category, so it should be a high level category. We want dozens
of these, not hundreds or thousands of them.
+.. _opt_fsave-optimization-record:
+
+**-fsave-optimization-record**
+ Write optimization remarks to a YAML file.
+
+ This option, which defaults to off, controls whether Clang writes
+ optimization reports to a YAML file. By recording diagnostics in a file,
+ using a structured YAML format, users can parse or sort the remarks in a
+ convenient way.
+
+.. _opt_foptimization-record-file:
+
+**-foptimization-record-file**
+ Control the file to which optimization reports are written.
+
+ When optimization reports are being output (see
+ :ref:`-fsave-optimization-record <opt_fsave-optimization-record>`), this
+ option controls the file to which those reports are written.
+
+ If this option is not used, optimization records are output to a file named
+ after the primary file being compiled. If that's "foo.c", for example,
+ optimization records are output to "foo.opt.yaml".
+
.. _opt_fdiagnostics-show-hotness:
**-f[no-]diagnostics-show-hotness**
Enable profile hotness information in diagnostic line.
- This option, which defaults to off, controls whether Clang prints the
- profile hotness associated with a diagnostics in the presence of
- profile-guided optimization information. This is currently supported with
- optimization remarks (see :ref:`Options to Emit Optimization Reports
- <rpass>`). The hotness information allows users to focus on the hot
- optimization remarks that are likely to be more relevant for run-time
- performance.
+ This option controls whether Clang prints the profile hotness associated
+ with diagnostics in the presence of profile-guided optimization information.
+ This is currently supported with optimization remarks (see
+ :ref:`Options to Emit Optimization Reports <rpass>`). The hotness information
+ allows users to focus on the hot optimization remarks that are likely to be
+ more relevant for run-time performance.
For example, in this output, the block containing the callsite of `foo` was
executed 3000 times according to the profile data:
@@ -344,6 +366,23 @@ output format of the diagnostics that it generates.
sum += foo(x, x - 2);
^
+ This option is implied when
+ :ref:`-fsave-optimization-record <opt_fsave-optimization-record>` is used.
+ Otherwise, it defaults to off.
+
+.. _opt_fdiagnostics-hotness-threshold:
+
+**-fdiagnostics-hotness-threshold**
+ Prevent optimization remarks from being output if they do not have at least
+ this hotness value.
+
+ This option, which defaults to zero, controls the minimum hotness an
+ optimization remark would need in order to be output by Clang. This is
+ currently supported with optimization remarks (see :ref:`Options to Emit
+ Optimization Reports <rpass>`) when profile hotness information in
+ diagnostics is enabled (see
+ :ref:`-fdiagnostics-show-hotness <opt_fdiagnostics-show-hotness>`).
+
.. _opt_fdiagnostics-fixit-info:
**-f[no-]diagnostics-fixit-info**
@@ -562,6 +601,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
@@ -628,7 +677,7 @@ Current limitations
Other Options
-------------
-Clang options that that don't fit neatly into other categories.
+Clang options that don't fit neatly into other categories.
.. option:: -MV
@@ -1098,6 +1147,11 @@ are listed below.
the behavior of sanitizers in the ``cfi`` group to allow checking
of cross-DSO virtual and indirect calls.
+.. option:: -fsanitize-cfi-icall-generalize-pointers
+
+ Generalize pointers in return and argument types in function type signatures
+ checked by Control Flow Integrity indirect call checking. See
+ :doc:`ControlFlowIntegrity` for more details.
.. option:: -fstrict-vtable-pointers
@@ -1389,7 +1443,7 @@ Sample Profile Text Format
This section describes the ASCII text format for sampling profiles. It is,
arguably, the easiest one to generate. If you are interested in generating any
-of the other two, consult the ``ProfileData`` library in in LLVM's source tree
+of the other two, consult the ``ProfileData`` library in LLVM's source tree
(specifically, ``include/llvm/ProfileData/SampleProfReader.h``).
.. code-block:: console
@@ -1405,7 +1459,7 @@ of the other two, consult the ``ProfileData`` library in in LLVM's source tree
offsetB[.discriminator]: fnB:num_of_total_samples
offsetB1[.discriminator]: number_of_samples [fn11:num fn12:num ... ]
-This is a nested tree in which the identation represents the nesting level
+This is a nested tree in which the indentation represents the nesting level
of the inline stack. There are no blank lines in the file. And the spacing
within a single line is fixed. Additional spaces will result in an error
while reading the file.
@@ -2573,6 +2627,10 @@ Execute ``clang-cl /?`` to see a list of supported options:
/Brepro Emit an object file which can be reproduced over time
/C Don't discard comments when preprocessing
/c Compile only
+ /d1reportAllClassLayout Dump record layout information
+ /diagnostics:caret Enable caret and column diagnostics (on by default)
+ /diagnostics:classic Disable column and caret diagnostics
+ /diagnostics:column Disable caret diagnostics but keep column info
/D <macro[=value]> Define macro
/EH<value> Exception handling model
/EP Disable linemarker output and preprocess to stdout
@@ -2667,6 +2725,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
/Zc:threadSafeInit Enable thread-safe initialization of static variables
/Zc:trigraphs- Disable trigraphs (default)
/Zc:trigraphs Enable trigraphs
+ /Zc:twoPhase- Disable two-phase name lookup in templates
+ /Zc:twoPhase Enable two-phase name lookup in templates
/Zd Emit debug line number tables only
/Zi Alias for /Z7. Does not produce PDBs.
/Zl Don't mention any default libraries in the object file
@@ -2679,12 +2739,14 @@ Execute ``clang-cl /?`` to see a list of supported options:
--analyze Run the static analyzer
-fansi-escape-codes Use ANSI escape codes for diagnostics
-fcolor-diagnostics Use colors in diagnostics
+ -fdebug-macro Emit macro debug information
-fdelayed-template-parsing
Parse templated function definitions at the end of the translation unit
-fdiagnostics-absolute-paths
Print absolute paths in diagnostics
-fdiagnostics-parseable-fixits
Print fix-its in machine parseable form
+ -flto=<value> Set LTO mode to either 'full' or 'thin'
-flto Enable LTO in 'full' mode
-fms-compatibility-version=<value>
Dot-separated value representing the Microsoft compiler version
@@ -2693,12 +2755,27 @@ Execute ``clang-cl /?`` to see a list of supported options:
-fms-extensions Accept some non-standard constructs supported by the Microsoft compiler
-fmsc-version=<value> Microsoft compiler version number to report in _MSC_VER
(0 = don't define it (default))
+ -fno-debug-macro Do not emit macro debug information
-fno-delayed-template-parsing
Disable delayed template parsing
+ -fno-sanitize-address-use-after-scope
+ Disable use-after-scope detection in AddressSanitizer
+ -fno-sanitize-blacklist Don't use blacklist file for sanitizers
+ -fno-sanitize-cfi-cross-dso
+ Disable control flow integrity (CFI) checks for cross-DSO calls.
-fno-sanitize-coverage=<value>
Disable specified features of coverage instrumentation for Sanitizers
+ -fno-sanitize-memory-track-origins
+ Disable origins tracking in MemorySanitizer
-fno-sanitize-recover=<value>
Disable recovery for specified sanitizers
+ -fno-sanitize-stats Disable sanitizer statistics gathering.
+ -fno-sanitize-thread-atomics
+ Disable atomic operations instrumentation in ThreadSanitizer
+ -fno-sanitize-thread-func-entry-exit
+ Disable function entry/exit instrumentation in ThreadSanitizer
+ -fno-sanitize-thread-memory-access
+ Disable memory access instrumentation in ThreadSanitizer
-fno-sanitize-trap=<value>
Disable trapping for specified sanitizers
-fno-standalone-debug Limit debug information produced to reduce size of debug binary
@@ -2710,13 +2787,36 @@ Execute ``clang-cl /?`` to see a list of supported options:
(overridden by '=' form of option or LLVM_PROFILE_FILE env var)
-fprofile-instr-use=<value>
Use instrumentation data for profile-guided optimization
+ -fsanitize-address-field-padding=<value>
+ Level of field padding for AddressSanitizer
+ -fsanitize-address-globals-dead-stripping
+ Enable linker dead stripping of globals in AddressSanitizer
+ -fsanitize-address-use-after-scope
+ Enable use-after-scope detection in AddressSanitizer
-fsanitize-blacklist=<value>
Path to blacklist file for sanitizers
+ -fsanitize-cfi-cross-dso
+ Enable control flow integrity (CFI) checks for cross-DSO calls.
-fsanitize-coverage=<value>
Specify the type of coverage instrumentation for Sanitizers
+ -fsanitize-memory-track-origins=<value>
+ Enable origins tracking in MemorySanitizer
+ -fsanitize-memory-track-origins
+ Enable origins tracking in MemorySanitizer
+ -fsanitize-memory-use-after-dtor
+ Enable use-after-destroy detection in MemorySanitizer
-fsanitize-recover=<value>
Enable recovery for specified sanitizers
+ -fsanitize-stats Enable sanitizer statistics gathering.
+ -fsanitize-thread-atomics
+ Enable atomic operations instrumentation in ThreadSanitizer (default)
+ -fsanitize-thread-func-entry-exit
+ Enable function entry/exit instrumentation in ThreadSanitizer (default)
+ -fsanitize-thread-memory-access
+ Enable memory access instrumentation in ThreadSanitizer (default)
-fsanitize-trap=<value> Enable trapping for specified sanitizers
+ -fsanitize-undefined-strip-path-components=<number>
+ Strip (or keep only, if negative) a given number of path components when emitting check metadata.
-fsanitize=<check> Turn on runtime checks for various forms of undefined or suspicious
behavior. See user manual for available checks
-fstandalone-debug Emit full debug info for all types used by the program
@@ -2724,6 +2824,7 @@ Execute ``clang-cl /?`` to see a list of supported options:
-gline-tables-only Emit debug line number tables only
-miamcu Use Intel MCU ABI
-mllvm <value> Additional arguments to forward to LLVM's option processing
+ -nobuiltininc Disable builtin #include directories
-Qunused-arguments Don't emit warning for unused driver arguments
-R<remark> Enable the specified remark
--target=<value> Generate code for the given target
diff --git a/docs/analyzer/DebugChecks.rst b/docs/analyzer/DebugChecks.rst
index 880dcfc960..e2a8e05417 100644
--- a/docs/analyzer/DebugChecks.rst
+++ b/docs/analyzer/DebugChecks.rst
@@ -74,7 +74,7 @@ inspects expressions.)
ExprInspection checks
---------------------
-- void clang_analyzer_eval(bool);
+- ``void clang_analyzer_eval(bool);``
Prints TRUE if the argument is known to have a non-zero value, FALSE if the
argument is known to have a zero or null value, and UNKNOWN if the argument
@@ -93,7 +93,7 @@ ExprInspection checks
clang_analyzer_eval(x); // expected-warning{{TRUE}}
-- void clang_analyzer_checkInlined(bool);
+- ``void clang_analyzer_checkInlined(bool);``
If a call occurs within an inlined function, prints TRUE or FALSE according to
the value of its argument. If a call occurs outside an inlined function,
@@ -125,7 +125,7 @@ ExprInspection checks
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
}
-- void clang_analyzer_warnIfReached();
+- ``void clang_analyzer_warnIfReached();``
Generate a warning if this line of code gets reached by the analyzer.
@@ -138,7 +138,7 @@ ExprInspection checks
clang_analyzer_warnIfReached(); // no-warning
}
-- void clang_analyzer_numTimesReached();
+- ``void clang_analyzer_numTimesReached();``
Same as above, but include the number of times this call expression
gets reached by the analyzer during the current analysis.
@@ -149,7 +149,7 @@ ExprInspection checks
clang_analyzer_numTimesReached(); // expected-warning{{3}}
}
-- void clang_analyzer_warnOnDeadSymbol(int);
+- ``void clang_analyzer_warnOnDeadSymbol(int);``
Subscribe for a delayed warning when the symbol that represents the value of
the argument is garbage-collected by the analyzer.
@@ -173,7 +173,7 @@ ExprInspection checks
} while(0); // expected-warning{{SYMBOL DEAD}}
-- void clang_analyzer_explain(a single argument of any type);
+- ``void clang_analyzer_explain(a single argument of any type);``
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
@@ -197,7 +197,7 @@ ExprInspection checks
clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
}
-- void clang_analyzer_dump(a single argument of any type);
+- ``void clang_analyzer_dump( /* a single argument of any type */);``
Similar to clang_analyzer_explain, but produces a raw dump of the value,
same as SVal::dump().
@@ -209,7 +209,7 @@ ExprInspection checks
clang_analyzer_dump(x); // expected-warning{{reg_$0<x>}}
}
-- size_t clang_analyzer_getExtent(void *);
+- ``size_t clang_analyzer_getExtent(void *);``
This function returns the value that represents the extent of a memory region
pointed to by the argument. This value is often difficult to obtain otherwise,
@@ -226,7 +226,7 @@ ExprInspection checks
clang_analyzer_explain(ys); // expected-warning{{'8'}}
}
-- void clang_analyzer_printState();
+- ``void clang_analyzer_printState();``
Dumps the current ProgramState to the stderr. Quickly lookup the program state
at any execution point without ViewExplodedGraph or re-compiling the program.
diff --git a/docs/analyzer/DesignDiscussions/InitializerLists.rst b/docs/analyzer/DesignDiscussions/InitializerLists.rst
new file mode 100644
index 0000000000..b826547bf1
--- /dev/null
+++ b/docs/analyzer/DesignDiscussions/InitializerLists.rst
@@ -0,0 +1,321 @@
+This discussion took place in https://reviews.llvm.org/D35216
+"Escape symbols when creating std::initializer_list".
+
+It touches problems of modelling C++ standard library constructs in general,
+including modelling implementation-defined fields within C++ standard library
+objects, in particular constructing objects into pointers held by such fields,
+and separation of responsibilities between analyzer's core and checkers.
+
+**Artem:**
+
+I've seen a few false positives that appear because we construct
+C++11 std::initializer_list objects with brace initializers, and such
+construction is not properly modeled. For instance, if a new object is
+constructed on the heap only to be put into a brace-initialized STL container,
+the object is reported to be leaked.
+
+Approach (0): This can be trivially fixed by this patch, which causes pointers
+passed into initializer list expressions to immediately escape.
+
+This fix is overly conservative though. So i did a bit of investigation as to
+how model std::initializer_list better.
+
+According to the standard, std::initializer_list<T> is an object that has
+methods begin(), end(), and size(), where begin() returns a pointer to continous
+array of size() objects of type T, and end() is equal to begin() plus size().
+The standard does hint that it should be possible to implement
+std::initializer_list<T> as a pair of pointers, or as a pointer and a size
+integer, however specific fields that the object would contain are an
+implementation detail.
+
+Ideally, we should be able to model the initializer list's methods precisely.
+Or, at least, it should be possible to explain to the analyzer that the list
+somehow "takes hold" of the values put into it. Initializer lists can also be
+copied, which is a separate story that i'm not trying to address here.
+
+The obvious approach to modeling std::initializer_list in a checker would be to
+construct a SymbolMetadata for the memory region of the initializer list object,
+which would be of type T* and represent begin(), so we'd trivially model begin()
+as a function that returns this symbol. The array pointed to by that symbol
+would be bindLoc()ed to contain the list's contents (probably as a CompoundVal
+to produce less bindings in the store). Extent of this array would represent
+size() and would be equal to the length of the list as written.
+
+So this sounds good, however apparently it does nothing to address our false
+positives: when the list escapes, our RegionStoreManager is not magically
+guessing that the metadata symbol attached to it, together with its contents,
+should also escape. In fact, it's impossible to trigger a pointer escape from
+within the checker.
+
+Approach (1): If only we enabled ProgramState::bindLoc(..., notifyChanges=true)
+to cause pointer escapes (not only region changes) (which sounds like the right
+thing to do anyway) such checker would be able to solve the false positives by
+triggering escapes when binding list elements to the list. However, it'd be as
+conservative as the current patch's solution. Ideally, we do not want escapes to
+happen so early. Instead, we'd prefer them to be delayed until the list itself
+escapes.
+
+So i believe that escaping metadata symbols whenever their base regions escape
+would be the right thing to do. Currently we didn't think about that because we
+had neither pointer-type metadatas nor non-pointer escapes.
+
+Approach (2): We could teach the Store to scan itself for bindings to
+metadata-symbolic-based regions during scanReachableSymbols() whenever a region
+turns out to be reachable. This requires no work on checker side, but it sounds
+performance-heavy.
+
+Approach (3): We could let checkers maintain the set of active metadata symbols
+in the program state (ideally somewhere in the Store, which sounds weird but
+causes the smallest amount of layering violations), so that the core knew what
+to escape. This puts a stress on the checkers, but with a smart data map it
+wouldn't be a problem.
+
+Approach (4): We could allow checkers to trigger pointer escapes in arbitrary
+moments. If we allow doing this within checkPointerEscape callback itself, we
+would be able to express facts like "when this region escapes, that metadata
+symbol attached to it should also escape". This sounds like an ultimate freedom,
+with maximum stress on the checkers - still not too much stress when we have
+smart data maps.
+
+I'm personally liking the approach (2) - it should be possible to avoid
+performance overhead, and clarity seems nice.
+
+**Gabor:**
+
+At this point, I am a bit wondering about two questions.
+
+- When should something belong to a checker and when should something belong
+to the engine? Sometimes we model library aspects in the engine and model
+language constructs in checkers.
+- What is the checker programming model that we are aiming for? Maximum
+freedom or more easy checker development?
+
+I think if we aim for maximum freedom, we do not need to worry about the
+potential stress on checkers, and we can introduce abstractions to mitigate that
+later on.
+If we want to simplify the API, then maybe it makes more sense to move language
+construct modeling to the engine when the checker API is not sufficient instead
+of complicating the API.
+
+Right now I have no preference or objections between the alternatives but there
+are some random thoughts:
+
+- Maybe it would be great to have a guideline how to evolve the analyzer and
+follow it, so it can help us to decide in similar situations
+- I do care about performance in this case. The reason is that we have a
+limited performance budget. And I think we should not expect most of the checker
+writers to add modeling of language constructs. So, in my opinion, it is ok to
+have less nice/more verbose API for language modeling if we can have better
+performance this way, since it only needs to be done once, and is done by the
+framework developers.
+
+**Artem:** These are some great questions, i guess it'd be better to discuss
+them more openly. As a quick dump of my current mood:
+
+- To me it seems obvious that we need to aim for a checker API that is both
+simple and powerful. This can probably by keeping the API as powerful as
+necessary while providing a layer of simple ready-made solutions on top of it.
+Probably a few reusable components for assembling checkers. And this layer
+should ideally be pleasant enough to work with, so that people would prefer to
+extend it when something is lacking, instead of falling back to the complex
+omnipotent API. I'm thinking of AST matchers vs. AST visitors as a roughly
+similar situation: matchers are not omnipotent, but they're so nice.
+
+- Separation between core and checkers is usually quite strange. Once we have
+shared state traits, i generally wouldn't mind having region store or range
+constraint manager as checkers (though it's probably not worth it to transform
+them - just a mood). The main thing to avoid here would be the situation when
+the checker overwrites stuff written by the core because it thinks it has a
+better idea what's going on, so the core should provide a good default behavior.
+
+- Yeah, i totally care about performance as well, and if i try to implement
+approach, i'd make sure it's good.
+
+**Artem:**
+
+> Approach (2): We could teach the Store to scan itself for bindings to
+> metadata-symbolic-based regions during scanReachableSymbols() whenever
+> a region turns out to be reachable. This requires no work on checker side,
+> but it sounds performance-heavy.
+
+Nope, this approach is wrong. Metadata symbols may become out-of-date: when the
+object changes, metadata symbols attached to it aren't changing (because symbols
+simply don't change). The same metadata may have different symbols to denote its
+value in different moments of time, but at most one of them represents the
+actual metadata value. So we'd be escaping more stuff than necessary.
+
+If only we had "ghost fields"
+(http://lists.llvm.org/pipermail/cfe-dev/2016-May/049000.html), it would have
+been much easier, because the ghost field would only contain the actual
+metadata, and the Store would always know about it. This example adds to my
+belief that ghost fields are exactly what we need for most C++ checkers.
+
+**Devin:**
+
+In this case, I would be fine with some sort of
+AbstractStorageMemoryRegion that meant "here is a memory region and somewhere
+reachable from here exists another region of type T". Or even multiple regions
+with different identifiers. This wouldn't specify how the memory is reachable,
+but it would allow for transfer functions to get at those regions and it would
+allow for invalidation.
+
+For std::initializer_list this reachable region would the region for the backing
+array and the transfer functions for begin() and end() yield the beginning and
+end element regions for it.
+
+In my view this differs from ghost variables in that (1) this storage does
+actually exist (it is just a library implementation detail where that storage
+lives) and (2) it is perfectly valid for a pointer into that storage to be
+returned and for another part of the program to read or write from that storage.
+(Well, in this case just read since it is allowed to be read-only memory).
+
+What I'm not OK with is modeling abstract analysis state (for example, the count
+of a NSMutableArray or the typestate of a file handle) as a value stored in some
+ginned up region in the store. This takes an easy problem that the analyzer does
+well at (modeling typestate) and turns it into a hard one that the analyzer is
+bad at (reasoning about the contents of the heap).
+
+I think the key criterion here is: "is the region accessible from outside the
+library". That is, does the library expose the region as a pointer that can be
+read to or written from in the client program? If so, then it makes sense for
+this to be in the store: we are modeling reachable storage as storage. But if
+we're just modeling arbitrary analysis facts that need to be invalidated when a
+pointer escapes then we shouldn't try to gin up storage for them just to get
+invalidation for free.
+
+**Artem:**
+
+> In this case, I would be fine with some sort of AbstractStorageMemoryRegion
+> that meant "here is a memory region and somewhere reachable from here exists
+> another region of type T". Or even multiple regions with different
+> identifiers. This wouldn't specify how the memory is reachable, but it would
+> allow for transfer functions to get at those regions and it would allow for
+> invalidation.
+
+Yeah, this is what we can easily implement now as a
+symbolic-region-based-on-a-metadata-symbol (though we can make a new region
+class for that if we eg. want it typed). The problem is that the relation
+between such storage region and its parent object region is essentially
+immaterial, similarly to the relation between SymbolRegionValue and its parent
+region. Region contents are mutable: today the abstract storage is reachable
+from its parent object, tomorrow it's not, and maybe something else becomes
+reachable, something that isn't even abstract. So the parent region for the
+abstract storage is most of the time at best a "nice to know" thing - we cannot
+rely on it to do any actual work. We'd anyway need to rely on the checker to do
+the job.
+
+> For std::initializer_list this reachable region would the region for the
+> backing array and the transfer functions for begin() and end() yield the
+> beginning and end element regions for it.
+
+So maybe in fact for std::initializer_list it may work fine because you cannot
+change the data after the object is constructed - so this region's contents are
+essentially immutable. For the future, i feel as if it is a dead end.
+
+I'd like to consider another funny example. Suppose we're trying to model
+std::unique_ptr. Consider::
+
+ void bar(const std::unique_ptr<int> &x);
+
+ void foo(std::unique_ptr<int> &x) {
+ int *a = x.get(); // (a, 0, direct): &AbstractStorageRegion
+ *a = 1; // (AbstractStorageRegion, 0, direct): 1 S32b
+ int *b = new int;
+ *b = 2; // (SymRegion{conj_$0<int *>}, 0 ,direct): 2 S32b
+ x.reset(b); // Checker map: x -> SymRegion{conj_$0<int *>}
+ bar(x); // 'a' doesn't escape (the pointer was unique), 'b' does.
+ clang_analyzer_eval(*a == 1); // Making this true is up to the checker.
+ clang_analyzer_eval(*b == 2); // Making this unknown is up to the checker.
+ }
+
+The checker doesn't totally need to ensure that *a == 1 passes - even though the
+pointer was unique, it could theoretically have .get()-ed above and the code
+could of course break the uniqueness invariant (though we'd probably want it).
+The checker can say that "even if *a did escape, it was not because it was
+stuffed directly into bar()".
+
+The checker's direct responsibility, however, is to solve the *b == 2 thing
+(which is in fact the problem we're dealing with in this patch - escaping the
+storage region of the object).
+
+So we're talking about one more operation over the program state (scanning
+reachable symbols and regions) that cannot work without checker support.
+
+We can probably add a new callback "checkReachableSymbols" to solve this. This
+is in fact also related to the dead symbols problem (we're scanning for live
+symbols in the store and in the checkers separately, but we need to do so
+simultaneously with a single worklist). Hmm, in fact this sounds like a good
+idea; we can replace checkLiveSymbols with checkReachableSymbols.
+
+Or we could just have ghost member variables, and no checker support required at
+all. For ghost member variables, the relation with their parent region (which
+would be their superregion) is actually useful, the mutability of their contents
+is expressed naturally, and the store automagically sees reachable symbols, live
+symbols, escapes, invalidations, whatever.
+
+> In my view this differs from ghost variables in that (1) this storage does
+> actually exist (it is just a library implementation detail where that storage
+> lives) and (2) it is perfectly valid for a pointer into that storage to be
+> returned and for another part of the program to read or write from that
+> storage. (Well, in this case just read since it is allowed to be read-only
+> memory).
+
+> What I'm not OK with is modeling abstract analysis state (for example, the
+> count of a NSMutableArray or the typestate of a file handle) as a value stored
+> in some ginned up region in the store.This takes an easy problem that the
+> analyzer does well at (modeling typestate) and turns it into a hard one that
+> the analyzer is bad at (reasoning about the contents of the heap).
+
+Yeah, i tend to agree on that. For simple typestates, this is probably an
+overkill, so let's definitely put aside the idea of "ghost symbolic regions"
+that i had earlier.
+
+But, to summarize a bit, in our current case, however, the typestate we're
+looking for is the contents of the heap. And when we try to model such
+typestates (complex in this specific manner, i.e. heap-like) in any checker, we
+have a choice between re-doing this modeling in every such checker (which is
+something analyzer is indeed good at, but at a price of making checkers heavy)
+or instead relying on the Store to do exactly what it's designed to do.
+
+> I think the key criterion here is: "is the region accessible from outside
+> the library". That is, does the library expose the region as a pointer that
+> can be read to or written from in the client program? If so, then it makes
+> sense for this to be in the store: we are modeling reachable storage as
+> storage. But if we're just modeling arbitrary analysis facts that need to be
+> invalidated when a pointer escapes then we shouldn't try to gin up storage
+> for them just to get invalidation for free.
+
+As a metaphor, i'd probably compare it to body farms - the difference between
+ghost member variables and metadata symbols seems to me like the difference
+between body farms and evalCall. Both are nice to have, and body farms are very
+pleasant to work with, even if not omnipotent. I think it's fine for a
+FunctionDecl's body in a body farm to have a local variable, even if such
+variable doesn't actually exist, even if it cannot be seen from outside the
+function call. I'm not seeing immediate practical difference between "it does
+actually exist" and "it doesn't actually exist, just a handy abstraction".
+Similarly, i think it's fine if we have a CXXRecordDecl with
+implementation-defined contents, and try to farm up a member variable as a handy
+abstraction (we don't even need to know its name or offset, only that it's there
+somewhere).
+
+**Artem:**
+
+We've discussed it in person with Devin, and he provided more points to think
+about:
+
+- If the initializer list consists of non-POD data, constructors of list's
+objects need to take the sub-region of the list's region as this-region In the
+current (v2) version of this patch, these objects are constructed elsewhere and
+then trivial-copied into the list's metadata pointer region, which may be
+incorrect. This is our overall problem with C++ constructors, which manifests in
+this case as well. Additionally, objects would need to be constructed in the
+analyzer's core, which would not be able to predict that it needs to take a
+checker-specific region as this-region, which makes it harder, though it might
+be mitigated by sharing the checker state traits.
+
+- Because "ghost variables" are not material to the user, we need to somehow
+make super sure that they don't make it into the diagnostic messages.
+
+So, because this needs further digging into overall C++ support and rises too
+many questions, i'm delaying a better approach to this problem and will fall
+back to the original trivial patch.
diff --git a/docs/analyzer/conf.py b/docs/analyzer/conf.py
index c40af7a5e8..09967598ac 100644
--- a/docs/analyzer/conf.py
+++ b/docs/analyzer/conf.py
@@ -49,9 +49,9 @@ copyright = u'2013-%d, Analyzer Team' % date.today().year
# built documents.
#
# The short version.
-version = '5'
+version = '6'
# The full version, including alpha/beta/rc tags.
-release = '5'
+release = '6'
# 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 a9861cd517..a12f99ad6d 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -49,9 +49,9 @@ copyright = u'2007-%d, The Clang Team' % date.today().year
# built documents.
#
# The short version.
-version = '5'
+version = '6'
# The full version, including alpha/beta/rc tags.
-release = '5'
+release = '6'
# 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 ef96605ed1..13ed72222b 100644
--- a/docs/doxygen.cfg.in
+++ b/docs/doxygen.cfg.in
@@ -132,7 +132,7 @@ INLINE_INHERITED_MEMB = NO
# shortest path that makes the file name unique will be used
# The default value is: YES.
-FULL_PATH_NAMES = NO
+FULL_PATH_NAMES = YES
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
@@ -144,7 +144,7 @@ FULL_PATH_NAMES = NO
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-STRIP_FROM_PATH = ../..
+STRIP_FROM_PATH = @abs_srcdir@/..
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@@ -153,7 +153,7 @@ STRIP_FROM_PATH = ../..
# specify the list of include paths that are normally passed to the compiler
# using the -I flag.
-STRIP_FROM_INC_PATH =
+STRIP_FROM_INC_PATH = @abs_srcdir@/../include
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't
@@ -513,7 +513,7 @@ SHOW_GROUPED_MEMB_INC = NO
# files with double quotes in the documentation rather than with sharp brackets.
# The default value is: NO.
-FORCE_LOCAL_INCLUDES = NO
+FORCE_LOCAL_INCLUDES = YES
# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
# documentation for inline members.
diff --git a/docs/index.rst b/docs/index.rst
index 0097ebbf65..daf943a60b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -60,6 +60,7 @@ Using Clang as a Library
LibASTMatchers
HowToSetupToolingForLLVM
JSONCompilationDatabase
+ RefactoringEngine
Using Clang Tools
=================
diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py
index 81a5af6ef4..e2571f4644 100755
--- a/docs/tools/dump_format_style.py
+++ b/docs/tools/dump_format_style.py
@@ -24,10 +24,10 @@ def doxygen2rst(text):
text = re.sub(r'\\\w+ ', '', text)
return text
-def indent(text, columns):
+def indent(text, columns, indent_first_line=True):
indent = ' ' * columns
s = re.sub(r'\n([^\n])', '\n' + indent + '\\1', text, flags=re.S)
- if s.startswith('\n'):
+ if not indent_first_line or s.startswith('\n'):
return s
return indent + s
@@ -64,7 +64,9 @@ class NestedField:
self.comment = comment.strip()
def __str__(self):
- return '\n* ``%s`` %s' % (self.name, doxygen2rst(self.comment))
+ return '\n* ``%s`` %s' % (
+ self.name,
+ doxygen2rst(indent(self.comment, 2, indent_first_line=False)))
class Enum:
def __init__(self, name, comment):
@@ -179,7 +181,7 @@ def read_options(header):
if enums.has_key(option.type):
option.enum = enums[option.type]
elif nested_structs.has_key(option.type):
- option.nested_struct = nested_structs[option.type];
+ option.nested_struct = nested_structs[option.type]
else:
raise Exception('Unknown type: %s' % option.type)
return options
@@ -195,4 +197,3 @@ contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text)
with open(DOC_FILE, 'wb') as output:
output.write(contents)
-
diff --git a/include/clang-c/CXCompilationDatabase.h b/include/clang-c/CXCompilationDatabase.h
index 9359abfebf..29f89e52a6 100644
--- a/include/clang-c/CXCompilationDatabase.h
+++ b/include/clang-c/CXCompilationDatabase.h
@@ -7,7 +7,7 @@
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
-|* This header provides a public inferface to use CompilationDatabase without *|
+|* This header provides a public interface to use CompilationDatabase without *|
|* the full Clang C++ API. *|
|* *|
\*===----------------------------------------------------------------------===*/
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index d466fce851..c72be56fdc 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -7,7 +7,7 @@
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
-|* This header provides a public inferface to a Clang library for extracting *|
+|* This header provides a public interface to a Clang library for extracting *|
|* high-level symbol information from source files without exposing the full *|
|* Clang C++ API. *|
|* *|
@@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 37
+#define CINDEX_VERSION_MINOR 43
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -81,6 +81,12 @@ extern "C" {
typedef void *CXIndex;
/**
+ * \brief An opaque type representing target information for a given translation
+ * unit.
+ */
+typedef struct CXTargetInfoImpl *CXTargetInfo;
+
+/**
* \brief A single translation unit, which resides in an index.
*/
typedef struct CXTranslationUnitImpl *CXTranslationUnit;
@@ -165,7 +171,60 @@ typedef struct CXVersion {
*/
int Subminor;
} CXVersion;
-
+
+/**
+ * \brief Describes the exception specification of a cursor.
+ *
+ * A negative value indicates that the cursor is not a function declaration.
+ */
+enum CXCursor_ExceptionSpecificationKind {
+
+ /**
+ * \brief The cursor has no exception specification.
+ */
+ CXCursor_ExceptionSpecificationKind_None,
+
+ /**
+ * \brief The cursor has exception specification throw()
+ */
+ CXCursor_ExceptionSpecificationKind_DynamicNone,
+
+ /**
+ * \brief The cursor has exception specification throw(T1, T2)
+ */
+ CXCursor_ExceptionSpecificationKind_Dynamic,
+
+ /**
+ * \brief The cursor has exception specification throw(...).
+ */
+ CXCursor_ExceptionSpecificationKind_MSAny,
+
+ /**
+ * \brief The cursor has exception specification basic noexcept.
+ */
+ CXCursor_ExceptionSpecificationKind_BasicNoexcept,
+
+ /**
+ * \brief The cursor has exception specification computed noexcept.
+ */
+ CXCursor_ExceptionSpecificationKind_ComputedNoexcept,
+
+ /**
+ * \brief The exception specification has not yet been evaluated.
+ */
+ CXCursor_ExceptionSpecificationKind_Unevaluated,
+
+ /**
+ * \brief The exception specification has not yet been instantiated.
+ */
+ CXCursor_ExceptionSpecificationKind_Uninstantiated,
+
+ /**
+ * \brief The exception specification has not been parsed yet.
+ */
+ CXCursor_ExceptionSpecificationKind_Unparsed
+};
+
/**
* \brief Provides a shared context for creating translation units.
*
@@ -478,8 +537,8 @@ CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location,
unsigned *offset);
/**
- * \brief Retrieve the file, line, column, and offset represented by
- * the given source location, as specified in a # line directive.
+ * \brief Retrieve the file, line and column represented by the given source
+ * location, as specified in a # line directive.
*
* Example: given the following source code in a file somefile.c
*
@@ -1228,7 +1287,12 @@ enum CXTranslationUnit_Flags {
* purposes of an IDE, this is undesirable behavior and as much information
* as possible should be reported. Use this flag to enable this behavior.
*/
- CXTranslationUnit_KeepGoing = 0x200
+ CXTranslationUnit_KeepGoing = 0x200,
+
+ /**
+ * \brief Sets the preprocessor in a mode for parsing a single file only.
+ */
+ CXTranslationUnit_SingleFileParse = 0x400
};
/**
@@ -1413,6 +1477,15 @@ CINDEX_LINKAGE int clang_saveTranslationUnit(CXTranslationUnit TU,
unsigned options);
/**
+ * \brief Suspend a translation unit in order to free memory associated with it.
+ *
+ * A suspended translation unit uses significantly less memory but on the other
+ * side does not support any other calls than \c clang_reparseTranslationUnit
+ * to resume it or \c clang_disposeTranslationUnit to dispose it completely.
+ */
+CINDEX_LINKAGE unsigned clang_suspendTranslationUnit(CXTranslationUnit);
+
+/**
* \brief Destroy the specified CXTranslationUnit object.
*/
CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
@@ -1553,6 +1626,36 @@ CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU
CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage);
/**
+ * \brief Get target information for this translation unit.
+ *
+ * The CXTargetInfo object cannot outlive the CXTranslationUnit object.
+ */
+CINDEX_LINKAGE CXTargetInfo
+clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit);
+
+/**
+ * \brief Destroy the CXTargetInfo object.
+ */
+CINDEX_LINKAGE void
+clang_TargetInfo_dispose(CXTargetInfo Info);
+
+/**
+ * \brief Get the normalized target triple as a string.
+ *
+ * Returns the empty string in case of any error.
+ */
+CINDEX_LINKAGE CXString
+clang_TargetInfo_getTriple(CXTargetInfo Info);
+
+/**
+ * \brief Get the pointer width of the target in bits.
+ *
+ * Returns -1 in case of error.
+ */
+CINDEX_LINKAGE int
+clang_TargetInfo_getPointerWidth(CXTargetInfo Info);
+
+/**
* @}
*/
@@ -2734,6 +2837,22 @@ enum CXLanguageKind {
CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor);
/**
+ * \brief Describe the "thread-local storage (TLS) kind" of the declaration
+ * referred to by a cursor.
+ */
+enum CXTLSKind {
+ CXTLS_None = 0,
+ CXTLS_Dynamic,
+ CXTLS_Static
+};
+
+/**
+ * \brief Determine the "thread-local storage (TLS) kind" of the declaration
+ * referred to by a cursor.
+ */
+CINDEX_LINKAGE enum CXTLSKind clang_getCursorTLSKind(CXCursor cursor);
+
+/**
* \brief Returns the translation unit that a cursor originated from.
*/
CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor);
@@ -3012,8 +3131,9 @@ enum CXTypeKind {
CXType_ObjCSel = 29,
CXType_Float128 = 30,
CXType_Half = 31,
+ CXType_Float16 = 32,
CXType_FirstBuiltin = CXType_Void,
- CXType_LastBuiltin = CXType_Half,
+ CXType_LastBuiltin = CXType_Float16,
CXType_Complex = 100,
CXType_Pointer = 101,
@@ -3040,7 +3160,52 @@ enum CXTypeKind {
*
* E.g., struct S, or via a qualified name, e.g., N::M::type, or both.
*/
- CXType_Elaborated = 119
+ CXType_Elaborated = 119,
+
+ /* OpenCL PipeType. */
+ CXType_Pipe = 120,
+
+ /* OpenCL builtin types. */
+ CXType_OCLImage1dRO = 121,
+ CXType_OCLImage1dArrayRO = 122,
+ CXType_OCLImage1dBufferRO = 123,
+ CXType_OCLImage2dRO = 124,
+ CXType_OCLImage2dArrayRO = 125,
+ CXType_OCLImage2dDepthRO = 126,
+ CXType_OCLImage2dArrayDepthRO = 127,
+ CXType_OCLImage2dMSAARO = 128,
+ CXType_OCLImage2dArrayMSAARO = 129,
+ CXType_OCLImage2dMSAADepthRO = 130,
+ CXType_OCLImage2dArrayMSAADepthRO = 131,
+ CXType_OCLImage3dRO = 132,
+ CXType_OCLImage1dWO = 133,
+ CXType_OCLImage1dArrayWO = 134,
+ CXType_OCLImage1dBufferWO = 135,
+ CXType_OCLImage2dWO = 136,
+ CXType_OCLImage2dArrayWO = 137,
+ CXType_OCLImage2dDepthWO = 138,
+ CXType_OCLImage2dArrayDepthWO = 139,
+ CXType_OCLImage2dMSAAWO = 140,
+ CXType_OCLImage2dArrayMSAAWO = 141,
+ CXType_OCLImage2dMSAADepthWO = 142,
+ CXType_OCLImage2dArrayMSAADepthWO = 143,
+ CXType_OCLImage3dWO = 144,
+ CXType_OCLImage1dRW = 145,
+ CXType_OCLImage1dArrayRW = 146,
+ CXType_OCLImage1dBufferRW = 147,
+ CXType_OCLImage2dRW = 148,
+ CXType_OCLImage2dArrayRW = 149,
+ CXType_OCLImage2dDepthRW = 150,
+ CXType_OCLImage2dArrayDepthRW = 151,
+ CXType_OCLImage2dMSAARW = 152,
+ CXType_OCLImage2dArrayMSAARW = 153,
+ CXType_OCLImage2dMSAADepthRW = 154,
+ CXType_OCLImage2dArrayMSAADepthRW = 155,
+ CXType_OCLImage3dRW = 156,
+ CXType_OCLSampler = 157,
+ CXType_OCLEvent = 158,
+ CXType_OCLQueue = 159,
+ CXType_OCLReserveID = 160
};
/**
@@ -3057,7 +3222,9 @@ enum CXCallingConv {
CXCallingConv_AAPCS_VFP = 7,
CXCallingConv_X86RegCall = 8,
CXCallingConv_IntelOclBicc = 9,
- CXCallingConv_X86_64Win64 = 10,
+ CXCallingConv_Win64 = 10,
+ /* Alias for compatibility with older versions of API. */
+ CXCallingConv_X86_64Win64 = CXCallingConv_Win64,
CXCallingConv_X86_64SysV = 11,
CXCallingConv_X86VectorCall = 12,
CXCallingConv_Swift = 13,
@@ -3327,6 +3494,16 @@ CINDEX_LINKAGE unsigned clang_isVolatileQualifiedType(CXType T);
CINDEX_LINKAGE unsigned clang_isRestrictQualifiedType(CXType T);
/**
+ * \brief Returns the address space of the given type.
+ */
+CINDEX_LINKAGE unsigned clang_getAddressSpace(CXType T);
+
+/**
+ * \brief Returns the typedef name of the given type.
+ */
+CINDEX_LINKAGE CXString clang_getTypedefName(CXType CT);
+
+/**
* \brief For pointer types, returns the type of the pointee.
*/
CINDEX_LINKAGE CXType clang_getPointeeType(CXType T);
@@ -3366,6 +3543,13 @@ CINDEX_LINKAGE enum CXCallingConv clang_getFunctionTypeCallingConv(CXType T);
CINDEX_LINKAGE CXType clang_getResultType(CXType T);
/**
+ * \brief Retrieve the exception specification type associated with a function type.
+ *
+ * If a non-function type is passed in, an error code of -1 is returned.
+ */
+CINDEX_LINKAGE int clang_getExceptionSpecificationType(CXType T);
+
+/**
* \brief Retrieve the number of non-variadic parameters associated with a
* function type.
*
@@ -3394,6 +3578,13 @@ CINDEX_LINKAGE unsigned clang_isFunctionTypeVariadic(CXType T);
CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
/**
+ * \brief Retrieve the exception specification type associated with a given cursor.
+ *
+ * This only returns a valid result if the cursor refers to a function or method.
+ */
+CINDEX_LINKAGE int clang_getCursorExceptionSpecificationType(CXCursor C);
+
+/**
* \brief Return 1 if the CXType is a POD (plain old data) type, and 0
* otherwise.
*/
@@ -3437,6 +3628,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.
@@ -3965,8 +4166,8 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C);
/**
- * \brief Given a cursor pointing to an Objective-C message, returns the CXType
- * of the receiver.
+ * \brief Given a cursor pointing to an Objective-C message or property
+ * reference, or C++ method call, returns the CXType of the receiver.
*/
CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C);
@@ -4024,8 +4225,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);
@@ -4035,6 +4236,23 @@ CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C);
/**
+ * \brief Returns non-zero if the given cursor points to a symbol marked with
+ * external_source_symbol attribute.
+ *
+ * \param language If non-NULL, and the attribute is present, will be set to
+ * the 'language' string from the attribute.
+ *
+ * \param definedIn If non-NULL, and the attribute is present, will be set to
+ * the 'definedIn' string from the attribute.
+ *
+ * \param isGenerated If non-NULL, and the attribute is present, will be set to
+ * non-zero if the 'generated_declaration' is set in the attribute.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isExternalSymbol(CXCursor C,
+ CXString *language, CXString *definedIn,
+ unsigned *isGenerated);
+
+/**
* \brief Given a cursor that represents a declaration, return the associated
* comment's source range. The range may include multiple consecutive comments
* with whitespace in between.
@@ -4075,6 +4293,12 @@ CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor);
CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor);
/**
+ * \brief Retrieve the CXStrings representing the mangled symbols of the ObjC
+ * class interface or implementation at the cursor.
+ */
+CINDEX_LINKAGE CXStringSet *clang_Cursor_getObjCManglings(CXCursor);
+
+/**
* @}
*/
@@ -4218,6 +4442,11 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
/**
+ * \brief Determine if an enum declaration refers to a scoped enum.
+ */
+CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C);
+
+/**
* \brief Determine if a C++ member function or member function template is
* declared 'const'.
*/
@@ -4701,7 +4930,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
@@ -5590,7 +5819,8 @@ typedef enum {
CXIdxEntityLang_None = 0,
CXIdxEntityLang_C = 1,
CXIdxEntityLang_ObjC = 2,
- CXIdxEntityLang_CXX = 3
+ CXIdxEntityLang_CXX = 3,
+ CXIdxEntityLang_Swift = 4
} CXIdxEntityLanguage;
/**
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 5fa515d02d..1498c366d7 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -39,6 +39,8 @@
#include "clang/Basic/SanitizerBlacklist.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/XRayLists.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -88,7 +90,6 @@ class DiagnosticsEngine;
class Expr;
class MangleNumberingContext;
class MaterializeTemporaryExpr;
-class TargetInfo;
// Decls
class MangleContext;
class ObjCIvarDecl;
@@ -142,6 +143,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes;
mutable llvm::FoldingSet<DependentSizedExtVectorType>
DependentSizedExtVectorTypes;
+ mutable llvm::FoldingSet<DependentAddressSpaceType>
+ DependentAddressSpaceTypes;
mutable llvm::FoldingSet<VectorType> VectorTypes;
mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&>
@@ -176,12 +179,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
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.
@@ -203,17 +206,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*>
@@ -229,21 +232,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;
@@ -262,7 +265,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;
@@ -271,7 +274,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;
@@ -301,12 +304,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;
@@ -454,17 +457,17 @@ 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;
mutable BuiltinTemplateDecl *TypePackElementDecl;
- /// \brief The associated SourceManager object.a
+ /// \brief The associated SourceManager object.
SourceManager &SourceMgr;
/// \brief The language options used to create the AST associated with
@@ -475,6 +478,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
@@ -489,9 +496,9 @@ private:
CXXABI *createCXXABI(const TargetInfo &T);
/// \brief The logical -> physical address space map.
- const LangAS::Map *AddrSpaceMap;
+ const LangASMap *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;
@@ -503,7 +510,7 @@ private:
const TargetInfo *Target;
const TargetInfo *AuxTarget;
clang::PrintingPolicy PrintingPolicy;
-
+
public:
IdentifierTable &Idents;
SelectorTable &Selectors;
@@ -607,7 +614,7 @@ public:
void setPrintingPolicy(const clang::PrintingPolicy &Policy) {
PrintingPolicy = Policy;
}
-
+
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
@@ -622,7 +629,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 {
@@ -630,7 +637,7 @@ public:
}
/// Return the total memory used for various side tables.
size_t getSideTableAllocatedMemory() const;
-
+
PartialDiagnostic::StorageAllocator &getDiagAllocator() {
return DiagAllocator;
}
@@ -650,13 +657,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 {
@@ -865,7 +876,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
@@ -881,7 +892,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.
@@ -894,7 +905,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);
@@ -902,7 +913,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());
@@ -926,7 +937,7 @@ public:
/// \brief Get the additional modules in which the definition \p Def has
/// been merged.
- ArrayRef<Module*> getModulesWithMergedDefinition(NamedDecl *Def) {
+ ArrayRef<Module*> getModulesWithMergedDefinition(const NamedDecl *Def) {
auto MergedIt = MergedDefModules.find(Def);
if (MergedIt == MergedDefModules.end())
return None;
@@ -964,6 +975,7 @@ public:
CanQualType UnsignedLongLongTy, UnsignedInt128Ty;
CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty;
CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
+ CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType Float128ComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
@@ -1058,7 +1070,14 @@ public:
/// The resulting type has a union of the qualifiers from T and the address
/// space. If T already has an address space specifier, it is silently
/// replaced.
- QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const;
+ QualType getAddrSpaceQualType(QualType T, LangAS AddressSpace) const;
+
+ /// \brief Remove any existing address space on the type and returns the type
+ /// with qualifiers intact (or that's the idea anyway)
+ ///
+ /// The return type should be T with all prior qualifiers minus the address
+ /// space.
+ QualType removeAddrSpaceQualType(QualType T) const;
/// \brief Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol
@@ -1182,15 +1201,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)
@@ -1234,7 +1253,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;
@@ -1260,6 +1279,10 @@ public:
Expr *SizeExpr,
SourceLocation AttrLoc) const;
+ QualType getDependentAddressSpaceType(QualType PointeeType,
+ Expr *AddrSpaceExpr,
+ SourceLocation AttrLoc) const;
+
/// \brief Return a K&R style C function type like 'int()'.
QualType getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const;
@@ -1385,7 +1408,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
@@ -1432,6 +1455,10 @@ public:
/// The sizeof operator requires this (C99 6.5.3.4p4).
CanQualType getSizeType() const;
+ /// \brief Return the unique signed counterpart of
+ /// the integer type corresponding to size_t.
+ CanQualType getSignedSizeType() const;
+
/// \brief Return the unique type for "intmax_t" (C99 7.18.1.5), defined in
/// <stdint.h>.
CanQualType getIntMaxType() const;
@@ -1475,17 +1502,22 @@ public:
/// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;
+ /// \brief Return the unique unsigned counterpart of "ptrdiff_t"
+ /// integer type. The standard (C11 7.21.6.1p7) refers to this type
+ /// in the definition of %tu format specifier.
+ QualType getUnsignedPointerDiffType() const;
+
/// \brief Return the unique type for "pid_t" defined in
/// <sys/types.h>. We need this to compute the correct type for vfork().
QualType getProcessIDType() const;
/// \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 {
@@ -1506,11 +1538,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 {
@@ -1518,7 +1550,7 @@ public:
return getObjCIdType();
return ObjCIdRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines \c id.
void setObjCIdRedefinitionType(QualType RedefType) {
ObjCIdRedefinitionType = RedefType;
@@ -1531,7 +1563,7 @@ public:
return getObjCClassType();
return ObjCClassRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines 'SEL'.
void setObjCClassRedefinitionType(QualType RedefType) {
ObjCClassRedefinitionType = RedefType;
@@ -1544,7 +1576,7 @@ public:
return getObjCSelType();
return ObjCSelRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines 'SEL'.
void setObjCSelRedefinitionType(QualType RedefType) {
ObjCSelRedefinitionType = RedefType;
@@ -1568,6 +1600,24 @@ public:
return NSCopyingName;
}
+ CanQualType getNSUIntegerType() const {
+ assert(Target && "Expected target to be initialized");
+ const llvm::Triple &T = Target->getTriple();
+ // Windows is LLP64 rather than LP64
+ if (T.isOSWindows() && T.isArch64Bit())
+ return UnsignedLongLongTy;
+ return UnsignedLongTy;
+ }
+
+ CanQualType getNSIntegerType() const {
+ assert(Target && "Expected target to be initialized");
+ const llvm::Triple &T = Target->getTriple();
+ // Windows is LLP64 rather than LP64
+ if (T.isOSWindows() && T.isArch64Bit())
+ return LongLongTy;
+ return LongTy;
+ }
+
/// Retrieve the identifier 'bool'.
IdentifierInfo *getBoolName() const {
if (!BoolName)
@@ -1596,7 +1646,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; }
@@ -1681,7 +1731,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
@@ -1691,7 +1741,7 @@ public:
bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
ObjCProtocolDecl *rProto) const;
-
+
ObjCPropertyImplDecl *getObjCPropertyImplDeclForPropertyDecl(
const ObjCPropertyDecl *PD,
const Decl *Container) const;
@@ -1703,7 +1753,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)
@@ -1715,26 +1765,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;
@@ -1752,12 +1802,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;
@@ -1820,7 +1870,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 {
@@ -1831,7 +1881,7 @@ public:
Qs.removeObjCLifetime();
return getQualifiedType(type.getUnqualifiedType(), Qs);
}
-
+
DeclarationNameInfo getNameForTemplate(TemplateName Name,
SourceLocation NameLoc) const;
@@ -1850,7 +1900,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>
@@ -1915,7 +1965,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;
@@ -1937,11 +1987,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;
@@ -2041,15 +2091,20 @@ public:
/// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
uint64_t getFieldOffset(const ValueDecl *FD) const;
+ /// Get the offset of an ObjCIvarDecl in bits.
+ uint64_t lookupFieldBitOffset(const ObjCInterfaceDecl *OID,
+ const ObjCImplementationDecl *ID,
+ const ObjCIvarDecl *Ivar) const;
+
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
VTableContextBase *getVTableContext();
MangleContext *createMangleContext();
-
+
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
-
+
unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const;
void CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
@@ -2125,7 +2180,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"
@@ -2144,9 +2199,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.
///
@@ -2174,7 +2229,7 @@ public:
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
/// \brief Retrieves the default calling convention for the current target.
- CallingConv getDefaultCallingConvention(bool isVariadic,
+ CallingConv getDefaultCallingConvention(bool IsVariadic,
bool IsCXXMethod) const;
/// \brief Retrieves the "canonical" template name that refers to a
@@ -2200,7 +2255,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
@@ -2227,7 +2282,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]
@@ -2246,14 +2301,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.
///
@@ -2279,7 +2334,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.
@@ -2308,21 +2363,14 @@ public:
return getTargetAddressSpace(Q.getAddressSpace());
}
- unsigned getTargetAddressSpace(unsigned AS) const {
- if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count)
- return AS;
- else
- return (*AddrSpaceMap)[AS - LangAS::Offset];
- }
+ unsigned getTargetAddressSpace(LangAS AS) const;
/// Get target-dependent integer value for null pointer which is used for
/// constant folding.
uint64_t getTargetNullPointerValue(QualType QT) const;
- bool addressSpaceMapManglingFor(unsigned AS) const {
- return AddrSpaceMapMangling ||
- AS < LangAS::Offset ||
- AS >= LangAS::Offset + LangAS::Count;
+ bool addressSpaceMapManglingFor(LangAS AS) const {
+ return AddrSpaceMapMangling || isTargetAddressSpace(AS);
}
private:
@@ -2335,11 +2383,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();
@@ -2354,7 +2402,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);
@@ -2380,12 +2428,33 @@ public:
QualType mergeTransparentUnionType(QualType, QualType,
bool OfBlockPointer=false,
bool Unqualified = false);
-
+
QualType mergeObjCGCQualifiers(QualType, QualType);
-
- bool doFunctionTypesMatchOnExtParameterInfos(
- const FunctionProtoType *FromFunctionType,
- const FunctionProtoType *ToFunctionType);
+
+ /// This function merges the ExtParameterInfo lists of two functions. It
+ /// returns true if the lists are compatible. The merged list is returned in
+ /// NewParamInfos.
+ ///
+ /// \param FirstFnType The type of the first function.
+ ///
+ /// \param SecondFnType The type of the second function.
+ ///
+ /// \param CanUseFirst This flag is set to true if the first function's
+ /// ExtParameterInfo list can be used as the composite list of
+ /// ExtParameterInfo.
+ ///
+ /// \param CanUseSecond This flag is set to true if the second function's
+ /// ExtParameterInfo list can be used as the composite list of
+ /// ExtParameterInfo.
+ ///
+ /// \param NewParamInfos The composite list of ExtParameterInfo. The list is
+ /// empty if none of the flags are set.
+ ///
+ bool mergeExtParameterInfo(
+ const FunctionProtoType *FirstFnType,
+ const FunctionProtoType *SecondFnType,
+ bool &CanUseFirst, bool &CanUseSecond,
+ SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &NewParamInfos);
void ResetObjCLayout(const ObjCContainerDecl *CD);
@@ -2452,7 +2521,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
@@ -2476,10 +2545,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.
@@ -2507,7 +2576,7 @@ public:
///
/// \returns true if the function/var must be CodeGen'ed/deserialized even if
/// it is not used.
- bool DeclMustBeEmitted(const Decl *D, bool ForModularCodegen = false);
+ bool DeclMustBeEmitted(const Decl *D);
const CXXConstructorDecl *
getCopyConstructorForExceptionObject(CXXRecordDecl *RD);
@@ -2554,15 +2623,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;
@@ -2575,25 +2644,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.
///
@@ -2710,13 +2779,13 @@ public:
};
/// \brief Utility function for constructing a nullary selector.
-static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
+inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
/// \brief Utility function for constructing an unary selector.
-static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
+inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
}
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index a8eff1a2fc..ed82b32342 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -22,6 +22,7 @@ namespace clang {
class CXXRecordDecl;
class Decl;
class DeclContext;
+ class Expr;
class FieldDecl;
class FunctionDecl;
class FunctionTemplateDecl;
@@ -80,7 +81,8 @@ public:
/// \brief A virtual destructor's operator delete has been resolved.
virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
- const FunctionDecl *Delete) {}
+ const FunctionDecl *Delete,
+ Expr *ThisArg) {}
/// \brief An implicit member got a definition.
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
diff --git a/include/clang/AST/ASTStructuralEquivalence.h b/include/clang/AST/ASTStructuralEquivalence.h
new file mode 100644
index 0000000000..23674c65f3
--- /dev/null
+++ b/include/clang/AST/ASTStructuralEquivalence.h
@@ -0,0 +1,103 @@
+//===--- ASTStructuralEquivalence.h - ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the StructuralEquivalenceContext class which checks for
+// structural equivalence between types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
+#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include <deque>
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class DiagnosticBuilder;
+class QualType;
+class RecordDecl;
+class SourceLocation;
+
+struct StructuralEquivalenceContext {
+ /// AST contexts for which we are checking structural equivalence.
+ ASTContext &FromCtx, &ToCtx;
+
+ /// The set of "tentative" equivalences between two canonical
+ /// declarations, mapping from a declaration in the first context to the
+ /// declaration in the second context that we believe to be equivalent.
+ llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
+
+ /// Queue of declarations in the first context whose equivalence
+ /// with a declaration in the second context still needs to be verified.
+ std::deque<Decl *> DeclsToCheck;
+
+ /// Declaration (from, to) pairs that are known not to be equivalent
+ /// (which we have already complained about).
+ llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls;
+
+ /// Whether we're being strict about the spelling of types when
+ /// unifying two types.
+ bool StrictTypeSpelling;
+
+ /// Whether warn or error on tag type mismatches.
+ bool ErrorOnTagTypeMismatch;
+
+ /// Whether to complain about failures.
+ bool Complain;
+
+ /// \c true if the last diagnostic came from ToCtx.
+ bool LastDiagFromC2;
+
+ StructuralEquivalenceContext(
+ ASTContext &FromCtx, ASTContext &ToCtx,
+ llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls,
+ bool StrictTypeSpelling = false, bool Complain = true,
+ bool ErrorOnTagTypeMismatch = false)
+ : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
+ StrictTypeSpelling(StrictTypeSpelling),
+ ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
+ LastDiagFromC2(false) {}
+
+ DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
+ DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
+
+ /// Determine whether the two declarations are structurally
+ /// equivalent.
+ bool IsStructurallyEquivalent(Decl *D1, Decl *D2);
+
+ /// Determine whether the two types are structurally equivalent.
+ bool IsStructurallyEquivalent(QualType T1, QualType T2);
+
+ /// Find the index of the given anonymous struct/union within its
+ /// context.
+ ///
+ /// \returns Returns the index of this anonymous struct/union in its context,
+ /// including the next assigned index (if none of them match). Returns an
+ /// empty option if the context is not a record, i.e.. if the anonymous
+ /// struct/union is at namespace or block scope.
+ ///
+ /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
+ /// probably makes more sense in some other common place then here.
+ static llvm::Optional<unsigned>
+ findUntaggedStructOrUnionIndex(RecordDecl *Anon);
+
+private:
+ /// Finish checking all of the structural equivalences.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool Finish();
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index 181131aba0..e4f5f7db2f 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -133,6 +133,9 @@ FLOATING_TYPE(Double, DoubleTy)
// 'long double'
FLOATING_TYPE(LongDouble, LongDoubleTy)
+// '_Float16'
+FLOATING_TYPE(Float16, HalfTy)
+
// '__float128'
FLOATING_TYPE(Float128, Float128Ty)
diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt
index 260734f220..942d08d585 100644
--- a/include/clang/AST/CMakeLists.txt
+++ b/include/clang/AST/CMakeLists.txt
@@ -50,3 +50,6 @@ clang_tablegen(CommentCommandList.inc -gen-clang-comment-command-list
SOURCE CommentCommands.td
TARGET ClangCommentCommandList)
+clang_tablegen(StmtDataCollectors.inc -gen-clang-data-collectors
+ SOURCE StmtDataCollectors.td
+ TARGET StmtDataCollectors)
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index 3cf058f26b..980608570f 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -127,7 +127,11 @@ class CXXBasePaths {
/// class subobjects for that class type. The key of the map is
/// the cv-unqualified canonical type of the base class subobject.
llvm::SmallDenseMap<QualType, std::pair<bool, unsigned>, 8> ClassSubobjects;
-
+
+ /// VisitedDependentRecords - Records the dependent records that have been
+ /// already visited.
+ llvm::SmallDenseSet<const CXXRecordDecl *, 4> VisitedDependentRecords;
+
/// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
/// ambiguous paths while it is looking for a path from a derived
/// type to a base type.
@@ -161,7 +165,8 @@ class CXXBasePaths {
void ComputeDeclsFound();
bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record,
- CXXRecordDecl::BaseMatchesCallback BaseMatches);
+ CXXRecordDecl::BaseMatchesCallback BaseMatches,
+ bool LookupInDependent = false);
public:
typedef std::list<CXXBasePath>::iterator paths_iterator;
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 25f6172be9..023456e2e3 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -359,8 +359,7 @@ struct simplify_type< ::clang::CanQual<T> > {
// Teach SmallPtrSet that CanQual<T> is "basically a pointer".
template<typename T>
-class PointerLikeTypeTraits<clang::CanQual<T> > {
-public:
+struct PointerLikeTypeTraits<clang::CanQual<T> > {
static inline void *getAsVoidPointer(clang::CanQual<T> P) {
return P.getAsOpaquePtr();
}
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 564c8ec9b9..ddead6046a 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -40,14 +40,14 @@ namespace clang {
typedef int64_t QuantityType;
private:
- QuantityType Quantity;
+ QuantityType Quantity = 0;
explicit CharUnits(QuantityType C) : Quantity(C) {}
public:
/// CharUnits - A default constructor.
- CharUnits() : Quantity(0) {}
+ CharUnits() = default;
/// Zero - Construct a CharUnits quantity of zero.
static CharUnits Zero() {
diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h
index 6a803836e8..230e52739f 100644
--- a/include/clang/AST/CommentSema.h
+++ b/include/clang/AST/CommentSema.h
@@ -208,6 +208,10 @@ public:
/// \returns \c true if declaration that this comment is attached to declares
/// a function pointer.
bool isFunctionPointerVarDecl();
+ /// \returns \c true if the declaration that this comment is attached to
+ /// declares a variable or a field whose type is a function or a block
+ /// pointer.
+ bool isFunctionOrBlockPointerVarLikeDecl();
bool isFunctionOrMethodVariadic();
bool isObjCMethodDecl();
bool isObjCPropertyDecl();
diff --git a/include/clang/AST/DataCollection.h b/include/clang/AST/DataCollection.h
new file mode 100644
index 0000000000..229ac2bd0f
--- /dev/null
+++ b/include/clang/AST/DataCollection.h
@@ -0,0 +1,65 @@
+//===--- DatatCollection.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 helper methods for collecting data from AST nodes.
+///
+/// To collect data from Stmt nodes, subclass ConstStmtVisitor and include
+/// StmtDataCollectors.inc after defining the macros that you need. This
+/// provides data collection implementations for most Stmt kinds. Note
+/// that that code requires some conditions to be met:
+///
+/// - There must be a method addData(const T &Data) that accepts strings,
+/// integral types as well as QualType. All data is forwarded using
+/// to this method.
+/// - The ASTContext of the Stmt must be accessible by the name Context.
+///
+/// It is also possible to override individual visit methods. Have a look at
+/// the DataCollector in lib/Analysis/CloneDetection.cpp for a usage example.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DATACOLLECTION_H
+#define LLVM_CLANG_AST_DATACOLLECTION_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+namespace data_collection {
+
+/// Returns a string that represents all macro expansions that expanded into the
+/// given SourceLocation.
+///
+/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations
+/// A and B are expanded from the same macros in the same order.
+std::string getMacroStack(SourceLocation Loc, ASTContext &Context);
+
+/// Utility functions for implementing addData() for a consumer that has a
+/// method update(StringRef)
+template <class T>
+void addDataToConsumer(T &DataConsumer, llvm::StringRef Str) {
+ DataConsumer.update(Str);
+}
+
+template <class T> void addDataToConsumer(T &DataConsumer, const QualType &QT) {
+ addDataToConsumer(DataConsumer, QT.getAsString());
+}
+
+template <class T, class Type>
+typename std::enable_if<
+ std::is_integral<Type>::value || std::is_enum<Type>::value ||
+ std::is_convertible<Type, size_t>::value // for llvm::hash_code
+ >::type
+addDataToConsumer(T &DataConsumer, Type Data) {
+ DataConsumer.update(StringRef(reinterpret_cast<char *>(&Data), sizeof(Data)));
+}
+
+} // end namespace data_collection
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_DATACOLLECTION_H
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index d1c77f5e08..ef0f502a35 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -301,16 +301,6 @@ public:
using Decl::isModulePrivate;
using Decl::setModulePrivate;
- /// \brief Determine whether this declaration is hidden from name lookup.
- bool isHidden() const { return Hidden; }
-
- /// \brief Set whether this declaration is hidden from name lookup.
- void setHidden(bool Hide) {
- assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
- "declaration with no owning module can't be hidden");
- Hidden = Hide;
- }
-
/// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const {
const DeclContext *DC = getDeclContext();
@@ -349,6 +339,12 @@ public:
return clang::isExternallyVisible(getLinkageInternal());
}
+ /// Determine whether this declaration can be redeclared in a
+ /// different translation unit.
+ bool isExternallyDeclarable() const {
+ return isExternallyVisible() && !getOwningModuleForLinkage();
+ }
+
/// \brief Determines the visibility of this entity.
Visibility getVisibility() const {
return getLinkageAndVisibility().getVisibility();
@@ -359,7 +355,14 @@ public:
/// Kinds of explicit visibility.
enum ExplicitVisibilityKind {
+ /// Do an LV computation for, ultimately, a type.
+ /// Visibility may be restricted by type visibility settings and
+ /// the visibility of template arguments.
VisibilityForType,
+
+ /// Do an LV computation for, ultimately, a non-type declaration.
+ /// Visibility may be restricted by value visibility settings and
+ /// the visibility of template arguments.
VisibilityForValue
};
@@ -838,7 +841,7 @@ protected:
/// Describes the kind of default argument for this parameter. By default
/// this is none. If this is normal, then the default argument is stored in
- /// the \c VarDecl initalizer expression unless we were unble to parse
+ /// the \c VarDecl initializer expression unless we were unable to parse
/// (even an invalid) expression for the default argument.
unsigned DefaultArgKind : 2;
@@ -861,6 +864,7 @@ protected:
class NonParmVarDeclBitfields {
friend class VarDecl;
+ friend class ImplicitParamDecl;
friend class ASTDeclReader;
unsigned : NumVarDeclBits;
@@ -904,6 +908,10 @@ protected:
/// declared in the same block scope. This controls whether we should merge
/// the type of this declaration with its previous declaration.
unsigned PreviousDeclInSameBlockScope : 1;
+
+ /// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or
+ /// something else.
+ unsigned ImplicitParamKind : 3;
};
union {
@@ -966,9 +974,16 @@ public:
/// hasLocalStorage - Returns true if a variable with function scope
/// is a non-static local variable.
bool hasLocalStorage() const {
- if (getStorageClass() == SC_None)
+ if (getStorageClass() == SC_None) {
+ // OpenCL v1.2 s6.5.3: The __constant or constant address space name is
+ // used to describe variables allocated in global memory and which are
+ // accessed inside a kernel(s) as read-only variables. As such, variables
+ // in constant address space cannot have local storage.
+ if (getType().getAddressSpace() == LangAS::opencl_constant)
+ return false;
// Second check is for C++11 [dcl.stc]p4.
return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
+ }
// Global Named Register (GNU extension)
if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm())
@@ -1379,20 +1394,50 @@ public:
class ImplicitParamDecl : public VarDecl {
void anchor() override;
+
public:
+ /// Defines the kind of the implicit parameter: is this an implicit parameter
+ /// with pointer to 'this', 'self', '_cmd', virtual table pointers, captured
+ /// context or something else.
+ enum ImplicitParamKind : unsigned {
+ ObjCSelf, /// Parameter for Objective-C 'self' argument
+ ObjCCmd, /// Parameter for Objective-C '_cmd' argument
+ CXXThis, /// Parameter for C++ 'this' argument
+ CXXVTT, /// Parameter for C++ virtual table pointers
+ CapturedContext, /// Parameter for captured context
+ Other, /// Other implicit parameter
+ };
+
+ /// Create implicit parameter.
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T);
+ QualType T, ImplicitParamKind ParamKind);
+ static ImplicitParamDecl *Create(ASTContext &C, QualType T,
+ ImplicitParamKind ParamKind);
static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc,
- IdentifierInfo *Id, QualType Type)
- : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
- /*tinfo*/ nullptr, SC_None) {
+ IdentifierInfo *Id, QualType Type,
+ ImplicitParamKind ParamKind)
+ : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
+ /*TInfo=*/nullptr, SC_None) {
+ NonParmVarDeclBits.ImplicitParamKind = ParamKind;
setImplicit();
}
+ ImplicitParamDecl(ASTContext &C, QualType Type, ImplicitParamKind ParamKind)
+ : VarDecl(ImplicitParam, C, /*DC=*/nullptr, SourceLocation(),
+ SourceLocation(), /*Id=*/nullptr, Type,
+ /*TInfo=*/nullptr, SC_None) {
+ NonParmVarDeclBits.ImplicitParamKind = ParamKind;
+ setImplicit();
+ }
+
+ /// Returns the implicit parameter kind.
+ ImplicitParamKind getParameterKind() const {
+ return static_cast<ImplicitParamKind>(NonParmVarDeclBits.ImplicitParamKind);
+ }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ImplicitParam; }
@@ -1624,6 +1669,7 @@ private:
unsigned HasImplicitReturnZero : 1;
unsigned IsLateTemplateParsed : 1;
unsigned IsConstexpr : 1;
+ unsigned InstantiationIsPending:1;
/// \brief Indicates if the function uses __try.
unsigned UsesSEHTry : 1;
@@ -1632,11 +1678,18 @@ private:
/// skipped.
unsigned HasSkippedBody : 1;
- /// Indicates if the function declaration will have a body, once we're done
- /// parsing it. (We don't set it to false when we're done parsing, in the
- /// hopes this is simpler.)
- unsigned WillHaveBody : 1;
-
+protected:
+ // Since a Deduction Guide [C++17] will never have a body, we can share the
+ // storage, and use a different name.
+ union {
+ /// Indicates if the function declaration will have a body, once we're done
+ /// parsing it.
+ unsigned WillHaveBody : 1;
+ /// Indicates that the Deduction Guide is the implicitly generated 'copy
+ /// deduction candidate' (is used during overload resolution).
+ unsigned IsCopyDeductionCandidate : 1;
+ };
+private:
/// \brief End part of this FunctionDecl's source range.
///
/// We could compute the full range in getSourceRange(). However, when we're
@@ -1719,6 +1772,7 @@ protected:
IsDeleted(false), IsTrivial(false), IsDefaulted(false),
IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
+ InstantiationIsPending(false),
UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false),
EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(),
DNLoc(NameInfo.getInfo()) {}
@@ -1832,14 +1886,15 @@ public:
return getBody(Definition);
}
- /// isThisDeclarationADefinition - Returns whether this specific
- /// declaration of the function is also a definition. This does not
- /// determine whether the function has been defined (e.g., in a
- /// previous definition); for that information, use isDefined. Note
- /// that this returns false for a defaulted function unless that function
- /// has been implicitly defined (possibly as deleted).
+ /// Returns whether this specific declaration of the function is also a
+ /// definition that does not contain uninstantiated body.
+ ///
+ /// This does not determine whether the function has been defined (e.g., in a
+ /// previous definition); for that information, use isDefined.
+ ///
bool isThisDeclarationADefinition() const {
- return IsDeleted || Body || IsLateTemplateParsed;
+ return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
+ WillHaveBody || hasDefiningAttr();
}
/// doesThisDeclarationHaveABody - Returns whether this specific
@@ -1910,6 +1965,15 @@ public:
bool isConstexpr() const { return IsConstexpr; }
void setConstexpr(bool IC) { IsConstexpr = IC; }
+ /// \brief Whether the instantiation of this function is pending.
+ /// This bit is set when the decision to instantiate this function is made
+ /// and unset if and when the function body is created. That leaves out
+ /// cases where instantiation did not happen because the template definition
+ /// was not seen in this TU. This bit remains set in those cases, under the
+ /// assumption that the instantiation will happen in some other TU.
+ bool instantiationIsPending() const { return InstantiationIsPending; }
+ void setInstantiationIsPending(bool IC) { InstantiationIsPending = IC; }
+
/// \brief Indicates the function uses __try.
bool usesSEHTry() const { return UsesSEHTry; }
void setUsesSEHTry(bool UST) { UsesSEHTry = UST; }
@@ -1975,7 +2039,13 @@ public:
/// These functions have special behavior under C++1y [expr.new]:
/// An implementation is allowed to omit a call to a replaceable global
/// allocation function. [...]
- bool isReplaceableGlobalAllocationFunction() const;
+ ///
+ /// If this function is an aligned allocation/deallocation function, return
+ /// true through IsAligned.
+ bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const;
+
+ /// \brief Determine whether this is a destroying operator delete.
+ bool isDestroyingOperatorDelete() const;
/// Compute the language linkage.
LanguageLinkage getLanguageLinkage() const;
@@ -2082,10 +2152,7 @@ public:
const Attr *getUnusedResultAttr() const;
/// \brief Returns true if this function or its return type has the
- /// warn_unused_result attribute. If the return type has the attribute and
- /// this function is a method of the return type's class, then false will be
- /// returned to avoid spurious warnings on member methods such as assignment
- /// operators.
+ /// warn_unused_result attribute.
bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; }
/// \brief Returns the storage class as written in the source. For the
@@ -2321,9 +2388,9 @@ public:
/// FieldDecl - An instance of this class is created by Sema::ActOnField to
/// represent a member of a struct/union/class.
class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
- // FIXME: This can be packed into the bitfields in Decl.
+ unsigned BitField : 1;
unsigned Mutable : 1;
- mutable unsigned CachedFieldIndex : 31;
+ mutable unsigned CachedFieldIndex : 30;
/// The kinds of value we can store in InitializerOrBitWidth.
///
@@ -2333,7 +2400,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
/// If the pointer is null, there's nothing special. Otherwise,
/// this is a bitfield and the pointer is the Expr* storing the
/// bit-width.
- ISK_BitWidthOrNothing = (unsigned) ICIS_NoInit,
+ ISK_NoInit = (unsigned) ICIS_NoInit,
/// The pointer is an (optional due to delayed parsing) Expr*
/// holding the copy-initializer.
@@ -2348,27 +2415,34 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
ISK_CapturedVLAType,
};
- /// \brief Storage for either the bit-width, the in-class
- /// initializer, or the captured variable length array bound.
- ///
- /// We can safely combine these because in-class initializers are
- /// not permitted for bit-fields, and both are exclusive with VLA
- /// captures.
+ /// If this is a bitfield with a default member initializer, this
+ /// structure is used to represent the two expressions.
+ struct InitAndBitWidth {
+ Expr *Init;
+ Expr *BitWidth;
+ };
+
+ /// \brief Storage for either the bit-width, the in-class initializer, or
+ /// both (via InitAndBitWidth), or the captured variable length array bound.
///
/// If the storage kind is ISK_InClassCopyInit or
/// ISK_InClassListInit, but the initializer is null, then this
- /// field has an in-class initializer which has not yet been parsed
+ /// field has an in-class initializer that has not yet been parsed
/// and attached.
+ // FIXME: Tail-allocate this to reduce the size of FieldDecl in the
+ // overwhelmingly common case that we have none of these things.
llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage;
+
protected:
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
- Mutable(Mutable), CachedFieldIndex(0),
- InitStorage(BW, (InitStorageKind) InitStyle) {
- assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield");
+ BitField(false), Mutable(Mutable), CachedFieldIndex(0),
+ InitStorage(nullptr, (InitStorageKind) InitStyle) {
+ if (BW)
+ setBitWidth(BW);
}
public:
@@ -2388,10 +2462,7 @@ public:
bool isMutable() const { return Mutable; }
/// \brief Determines whether this field is a bitfield.
- bool isBitField() const {
- return InitStorage.getInt() == ISK_BitWidthOrNothing &&
- InitStorage.getPointer() != nullptr;
- }
+ bool isBitField() const { return BitField; }
/// @brief Determines whether this is an unnamed bitfield.
bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
@@ -2403,66 +2474,76 @@ public:
bool isAnonymousStructOrUnion() const;
Expr *getBitWidth() const {
- return isBitField()
- ? static_cast<Expr *>(InitStorage.getPointer())
- : nullptr;
+ if (!BitField)
+ return nullptr;
+ void *Ptr = InitStorage.getPointer();
+ if (getInClassInitStyle())
+ return static_cast<InitAndBitWidth*>(Ptr)->BitWidth;
+ return static_cast<Expr*>(Ptr);
}
unsigned getBitWidthValue(const ASTContext &Ctx) const;
/// setBitWidth - Set the bit-field width for this member.
// Note: used by some clients (i.e., do not remove it).
void setBitWidth(Expr *Width) {
- assert(InitStorage.getInt() == ISK_BitWidthOrNothing &&
- InitStorage.getPointer() == nullptr &&
- "bit width, initializer or captured type already set");
- InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing);
+ assert(!hasCapturedVLAType() && !BitField &&
+ "bit width or captured type already set");
+ assert(Width && "no bit width specified");
+ InitStorage.setPointer(
+ InitStorage.getInt()
+ ? new (getASTContext())
+ InitAndBitWidth{getInClassInitializer(), Width}
+ : static_cast<void*>(Width));
+ BitField = true;
}
/// removeBitWidth - Remove the bit-field width from this member.
// Note: used by some clients (i.e., do not remove it).
void removeBitWidth() {
assert(isBitField() && "no bitfield width to remove");
- InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing);
+ InitStorage.setPointer(getInClassInitializer());
+ BitField = false;
}
- /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which
- /// this field has.
+ /// Get the kind of (C++11) default member initializer that this field has.
InClassInitStyle getInClassInitStyle() const {
InitStorageKind storageKind = InitStorage.getInt();
return (storageKind == ISK_CapturedVLAType
? ICIS_NoInit : (InClassInitStyle) storageKind);
}
- /// hasInClassInitializer - Determine whether this member has a C++11 in-class
- /// initializer.
+ /// Determine whether this member has a C++11 default member initializer.
bool hasInClassInitializer() const {
return getInClassInitStyle() != ICIS_NoInit;
}
- /// getInClassInitializer - Get the C++11 in-class initializer for this
- /// member, or null if one has not been set. If a valid declaration has an
- /// in-class initializer, but this returns null, then we have not parsed and
- /// attached it yet.
+ /// Get the C++11 default member initializer for this member, or null if one
+ /// has not been set. If a valid declaration has a default member initializer,
+ /// but this returns null, then we have not parsed and attached it yet.
Expr *getInClassInitializer() const {
- return hasInClassInitializer()
- ? static_cast<Expr *>(InitStorage.getPointer())
- : nullptr;
+ if (!hasInClassInitializer())
+ return nullptr;
+ void *Ptr = InitStorage.getPointer();
+ if (BitField)
+ return static_cast<InitAndBitWidth*>(Ptr)->Init;
+ return static_cast<Expr*>(Ptr);
}
/// setInClassInitializer - Set the C++11 in-class initializer for this
/// member.
void setInClassInitializer(Expr *Init) {
- assert(hasInClassInitializer() &&
- InitStorage.getPointer() == nullptr &&
- "bit width, initializer or captured type already set");
- InitStorage.setPointer(Init);
+ assert(hasInClassInitializer() && !getInClassInitializer());
+ if (BitField)
+ static_cast<InitAndBitWidth*>(InitStorage.getPointer())->Init = Init;
+ else
+ InitStorage.setPointer(Init);
}
/// removeInClassInitializer - Remove the C++11 in-class initializer from this
/// member.
void removeInClassInitializer() {
assert(hasInClassInitializer() && "no initializer to remove");
- InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing);
+ InitStorage.setPointerAndInt(getBitWidth(), ISK_NoInit);
}
/// \brief Determine whether this member captures the variable length array
@@ -2481,7 +2562,7 @@ public:
void setCapturedVLAType(const VariableArrayType *VLAType);
/// getParent - Returns the parent of this field declaration, which
- /// is the struct in which this method is defined.
+ /// is the struct in which this field is defined.
const RecordDecl *getParent() const {
return cast<RecordDecl>(getDeclContext());
}
@@ -2641,12 +2722,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 {
@@ -2699,11 +2785,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'
@@ -3235,6 +3332,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;
@@ -3431,7 +3540,7 @@ public:
return K >= firstRecord && K <= lastRecord;
}
- /// isMsStrust - Get whether or not this is an ms_struct which can
+ /// \brief Get whether or not this is an ms_struct which can
/// be turned on with an attribute, pragma, or -mms-bitfields
/// commandline option.
bool isMsStruct(const ASTContext &C) const;
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index c88cb6a8fd..47515a848a 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -34,6 +34,7 @@ class DeclarationName;
class DependentDiagnostic;
class EnumDecl;
class ExportDecl;
+class ExternalSourceSymbolAttr;
class FunctionDecl;
class FunctionType;
enum Linkage : unsigned char;
@@ -201,26 +202,33 @@ public:
OBJC_TQ_CSNullability = 0x40
};
-protected:
- // Enumeration values used in the bits stored in NextInContextAndBits.
- enum {
- /// \brief Whether this declaration is a top-level declaration (function,
- /// global variable, etc.) that is lexically inside an objc container
- /// definition.
- TopLevelDeclInObjCContainerFlag = 0x01,
-
- /// \brief Whether this declaration is private to the module in which it was
- /// defined.
- ModulePrivateFlag = 0x02
+ /// The kind of ownership a declaration has, for visibility purposes.
+ /// This enumeration is designed such that higher values represent higher
+ /// levels of name hiding.
+ enum class ModuleOwnershipKind : unsigned {
+ /// This declaration is not owned by a module.
+ Unowned,
+ /// This declaration has an owning module, but is globally visible
+ /// (typically because its owning module is visible and we know that
+ /// modules cannot later become hidden in this compilation).
+ /// After serialization and deserialization, this will be converted
+ /// to VisibleWhenImported.
+ Visible,
+ /// This declaration has an owning module, and is visible when that
+ /// module is imported.
+ VisibleWhenImported,
+ /// This declaration has an owning module, but is only visible to
+ /// lookups that occur within that module.
+ ModulePrivate
};
-
+
+protected:
/// \brief The next declaration within the same lexical
/// DeclContext. These pointers form the linked list that is
/// traversed via DeclContext's decls_begin()/decls_end().
///
- /// The extra two bits are used for the TopLevelDeclInObjCContainer and
- /// ModulePrivate bits.
- llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits;
+ /// The extra two bits are used for the ModuleOwnershipKind.
+ llvm::PointerIntPair<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits;
private:
friend class DeclContext;
@@ -281,6 +289,11 @@ private:
/// are regarded as "referenced" but not "used".
unsigned Referenced : 1;
+ /// \brief Whether this declaration is a top-level declaration (function,
+ /// global variable, etc.) that is lexically inside an objc container
+ /// definition.
+ unsigned TopLevelDeclInObjCContainer : 1;
+
/// \brief Whether statistic collection is enabled.
static bool StatisticsEnabled;
@@ -293,11 +306,6 @@ protected:
/// \brief Whether this declaration was loaded from an AST file.
unsigned FromASTFile : 1;
- /// \brief Whether this declaration is hidden from normal name lookup, e.g.,
- /// because it is was loaded from an AST file is either module-private or
- /// because its submodule has not been made visible.
- unsigned Hidden : 1;
-
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 13;
@@ -331,26 +339,38 @@ protected:
private:
bool AccessDeclContextSanity() const;
-protected:
+ /// Get the module ownership kind to use for a local lexical child of \p DC,
+ /// which may be either a local or (rarely) an imported declaration.
+ static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) {
+ if (DC) {
+ auto *D = cast<Decl>(DC);
+ auto MOK = D->getModuleOwnershipKind();
+ if (MOK != ModuleOwnershipKind::Unowned &&
+ (!D->isFromASTFile() || D->hasLocalOwningModuleStorage()))
+ return MOK;
+ // If D is not local and we have no local module storage, then we don't
+ // need to track module ownership at all.
+ }
+ return ModuleOwnershipKind::Unowned;
+ }
+protected:
Decl(Kind DK, DeclContext *DC, SourceLocation L)
- : NextInContextAndBits(), DeclCtx(DC),
- Loc(L), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), FromASTFile(0), Hidden(DC && cast<Decl>(DC)->Hidden),
- IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
- CacheValidAndLinkage(0)
- {
+ : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
+ DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
+ Implicit(false), Used(false), Referenced(false),
+ TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
+ IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
+ CacheValidAndLinkage(0) {
if (StatisticsEnabled) add(DK);
}
Decl(Kind DK, EmptyShell Empty)
- : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), FromASTFile(0), Hidden(0),
- IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
- CacheValidAndLinkage(0)
- {
+ : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
+ Implicit(false), Used(false), Referenced(false),
+ TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
+ IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
+ CacheValidAndLinkage(0) {
if (StatisticsEnabled) add(DK);
}
@@ -550,22 +570,21 @@ public:
/// global variable, etc.) that is lexically inside an objc container
/// definition.
bool isTopLevelDeclInObjCContainer() const {
- return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag;
+ return TopLevelDeclInObjCContainer;
}
void setTopLevelDeclInObjCContainer(bool V = true) {
- unsigned Bits = NextInContextAndBits.getInt();
- if (V)
- Bits |= TopLevelDeclInObjCContainerFlag;
- else
- Bits &= ~TopLevelDeclInObjCContainerFlag;
- NextInContextAndBits.setInt(Bits);
+ TopLevelDeclInObjCContainer = V;
}
+ /// \brief Looks on this and related declarations for an applicable
+ /// external source symbol attribute.
+ ExternalSourceSymbolAttr *getExternalSourceSymbolAttr() const;
+
/// \brief Whether this declaration was marked as being private to the
/// module in which it was defined.
bool isModulePrivate() const {
- return NextInContextAndBits.getInt() & ModulePrivateFlag;
+ return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate;
}
/// \brief Whether this declaration is exported (by virtue of being lexically
@@ -580,15 +599,14 @@ public:
const Attr *getDefiningAttr() const;
protected:
- /// \brief Specify whether this declaration was marked as being private
+ /// \brief Specify that this declaration was marked as being private
/// to the module in which it was defined.
- void setModulePrivate(bool MP = true) {
- unsigned Bits = NextInContextAndBits.getInt();
- if (MP)
- Bits |= ModulePrivateFlag;
- else
- Bits &= ~ModulePrivateFlag;
- NextInContextAndBits.setInt(Bits);
+ void setModulePrivate() {
+ // The module-private specifier has no effect on unowned declarations.
+ // FIXME: We should track this in some way for source fidelity.
+ if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned)
+ return;
+ setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate);
}
/// \brief Set the owning module ID.
@@ -616,6 +634,14 @@ public:
getAvailability(std::string *Message = nullptr,
VersionTuple EnclosingVersion = VersionTuple()) const;
+ /// \brief Retrieve the version of the target platform in which this
+ /// declaration was introduced.
+ ///
+ /// \returns An empty version tuple if this declaration has no 'introduced'
+ /// availability attributes, or the version tuple that's specified in the
+ /// attribute otherwise.
+ VersionTuple getVersionIntroduced() const;
+
/// \brief Determine whether this declaration is marked 'deprecated'.
///
/// \param Message If non-NULL and the declaration is deprecated,
@@ -679,7 +705,7 @@ public:
/// \brief Get the imported owning module, if this decl is from an imported
/// (non-local) module.
Module *getImportedOwningModule() const {
- if (!isFromASTFile())
+ if (!isFromASTFile() || !hasOwningModule())
return nullptr;
return getOwningModuleSlow();
@@ -688,16 +714,66 @@ public:
/// \brief Get the local owning module, if known. Returns nullptr if owner is
/// not yet known or declaration is not from a module.
Module *getLocalOwningModule() const {
- if (isFromASTFile() || !Hidden)
+ if (isFromASTFile() || !hasOwningModule())
return nullptr;
+
+ assert(hasLocalOwningModuleStorage() &&
+ "owned local decl but no local module storage");
return reinterpret_cast<Module *const *>(this)[-1];
}
void setLocalOwningModule(Module *M) {
- assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() &&
+ assert(!isFromASTFile() && hasOwningModule() &&
+ hasLocalOwningModuleStorage() &&
"should not have a cached owning module");
reinterpret_cast<Module **>(this)[-1] = M;
}
+ /// Is this declaration owned by some module?
+ bool hasOwningModule() const {
+ return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned;
+ }
+
+ /// Get the module that owns this declaration (for visibility purposes).
+ Module *getOwningModule() const {
+ return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule();
+ }
+
+ /// Get the module that owns this declaration for linkage purposes.
+ /// There only ever is such a module under the C++ Modules TS.
+ ///
+ /// \param IgnoreLinkage Ignore the linkage of the entity; assume that
+ /// all declarations in a global module fragment are unowned.
+ Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const;
+
+ /// \brief Determine whether this declaration might be hidden from name
+ /// lookup. Note that the declaration might be visible even if this returns
+ /// \c false, if the owning module is visible within the query context.
+ // FIXME: Rename this to make it clearer what it does.
+ bool isHidden() const {
+ return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible;
+ }
+
+ /// Set that this declaration is globally visible, even if it came from a
+ /// module that is not visible.
+ void setVisibleDespiteOwningModule() {
+ if (isHidden())
+ setModuleOwnershipKind(ModuleOwnershipKind::Visible);
+ }
+
+ /// \brief Get the kind of module ownership for this declaration.
+ ModuleOwnershipKind getModuleOwnershipKind() const {
+ return NextInContextAndBits.getInt();
+ }
+
+ /// \brief Set whether this declaration is hidden from name lookup.
+ void setModuleOwnershipKind(ModuleOwnershipKind MOK) {
+ assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned &&
+ MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() &&
+ !hasLocalOwningModuleStorage()) &&
+ "no storage available for owning module for this declaration");
+ NextInContextAndBits.setInt(MOK);
+ }
+
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
@@ -933,13 +1009,15 @@ public:
/// declaration, but in the semantic context of the enclosing namespace
/// scope.
void setLocalExternDecl() {
- assert((IdentifierNamespace == IDNS_Ordinary ||
- IdentifierNamespace == IDNS_OrdinaryFriend) &&
- "namespace is not ordinary");
-
Decl *Prev = getPreviousDecl();
IdentifierNamespace &= ~IDNS_Ordinary;
+ // It's OK for the declaration to still have the "invisible friend" flag or
+ // the "conflicts with tag declarations in this scope" flag for the outer
+ // scope.
+ assert((IdentifierNamespace & ~(IDNS_OrdinaryFriend | IDNS_Tag)) == 0 &&
+ "namespace is not ordinary");
+
IdentifierNamespace |= IDNS_LocalExtern;
if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)
IdentifierNamespace |= IDNS_Ordinary;
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index d663dbeea8..d9b8ac274d 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -73,8 +73,7 @@ public:
namespace llvm {
// Provide PointerLikeTypeTraits for non-cvr pointers.
template<>
- class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> {
- public:
+ struct PointerLikeTypeTraits< ::clang::AnyFunctionDecl> {
static inline void *getAsVoidPointer(::clang::AnyFunctionDecl F) {
return F.get();
}
@@ -375,6 +374,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief These flags are \c true if a defaulted corresponding special
/// member can't be fully analyzed without performing overload resolution.
/// @{
+ unsigned NeedOverloadResolutionForCopyConstructor : 1;
unsigned NeedOverloadResolutionForMoveConstructor : 1;
unsigned NeedOverloadResolutionForMoveAssignment : 1;
unsigned NeedOverloadResolutionForDestructor : 1;
@@ -383,6 +383,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief These flags are \c true if an implicit defaulted corresponding
/// special member would be defined as deleted.
/// @{
+ unsigned DefaultedCopyConstructorIsDeleted : 1;
unsigned DefaultedMoveConstructorIsDeleted : 1;
unsigned DefaultedMoveAssignmentIsDeleted : 1;
unsigned DefaultedDestructorIsDeleted : 1;
@@ -415,6 +416,12 @@ class CXXRecordDecl : public RecordDecl {
/// constructor.
unsigned HasDefaultedDefaultConstructor : 1;
+ /// \brief True if this class can be passed in a non-address-preserving
+ /// fashion (such as in registers) according to the C++ language rules.
+ /// This does not imply anything about how the ABI in use will actually
+ /// pass an object of this class.
+ unsigned CanPassInRegisters : 1;
+
/// \brief True if a defaulted default constructor for this class would
/// be constexpr.
unsigned DefaultedDefaultConstructorIsConstexpr : 1;
@@ -464,6 +471,8 @@ 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;
@@ -712,8 +721,7 @@ public:
return data().IsParsingBaseSpecifiers;
}
- void computeODRHash();
- unsigned getODRHash() const { return data().ODRHash; }
+ unsigned getODRHash() const;
/// \brief Sets the base classes of this struct or class.
void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
@@ -810,18 +818,53 @@ public:
return data().FirstFriend.isValid();
}
+ /// \brief \c true if a defaulted copy constructor for this class would be
+ /// deleted.
+ bool defaultedCopyConstructorIsDeleted() const {
+ assert((!needsOverloadResolutionForCopyConstructor() ||
+ (data().DeclaredSpecialMembers & SMF_CopyConstructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedCopyConstructorIsDeleted;
+ }
+
+ /// \brief \c true if a defaulted move constructor for this class would be
+ /// deleted.
+ bool defaultedMoveConstructorIsDeleted() const {
+ assert((!needsOverloadResolutionForMoveConstructor() ||
+ (data().DeclaredSpecialMembers & SMF_MoveConstructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedMoveConstructorIsDeleted;
+ }
+
+ /// \brief \c true if a defaulted destructor for this class would be deleted.
+ bool defaultedDestructorIsDeleted() const {
+ assert((!needsOverloadResolutionForDestructor() ||
+ (data().DeclaredSpecialMembers & SMF_Destructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedDestructorIsDeleted;
+ }
+
+ /// \brief \c true if we know for sure that this class has a single,
+ /// accessible, unambiguous copy constructor that is not deleted.
+ bool hasSimpleCopyConstructor() const {
+ return !hasUserDeclaredCopyConstructor() &&
+ !data().DefaultedCopyConstructorIsDeleted;
+ }
+
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move constructor that is not deleted.
bool hasSimpleMoveConstructor() const {
return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() &&
!data().DefaultedMoveConstructorIsDeleted;
}
+
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move assignment operator that is not deleted.
bool hasSimpleMoveAssignment() const {
return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
!data().DefaultedMoveAssignmentIsDeleted;
}
+
/// \brief \c true if we know for sure that this class has an accessible
/// destructor that is not deleted.
bool hasSimpleDestructor() const {
@@ -877,7 +920,16 @@ public:
/// \brief Determine whether we need to eagerly declare a defaulted copy
/// constructor for this class.
bool needsOverloadResolutionForCopyConstructor() const {
- return data().HasMutableFields;
+ // C++17 [class.copy.ctor]p6:
+ // If the class definition declares a move constructor or move assignment
+ // operator, the implicitly declared copy constructor is defined as
+ // deleted.
+ // In MSVC mode, sometimes a declared move assignment does not delete an
+ // implicit copy constructor, so defer this choice to Sema.
+ if (data().UserDeclaredSpecialMembers &
+ (SMF_MoveConstructor | SMF_MoveAssignment))
+ return true;
+ return data().NeedOverloadResolutionForCopyConstructor;
}
/// \brief Determine whether an implicit copy constructor for this type
@@ -918,7 +970,16 @@ public:
needsImplicitMoveConstructor();
}
- /// \brief Set that we attempted to declare an implicitly move
+ /// \brief Set that we attempted to declare an implicit copy
+ /// constructor, but overload resolution failed so we deleted it.
+ void setImplicitCopyConstructorIsDeleted() {
+ assert((data().DefaultedCopyConstructorIsDeleted ||
+ needsOverloadResolutionForCopyConstructor()) &&
+ "Copy constructor should not be deleted");
+ data().DefaultedCopyConstructorIsDeleted = true;
+ }
+
+ /// \brief Set that we attempted to declare an implicit move
/// constructor, but overload resolution failed so we deleted it.
void setImplicitMoveConstructorIsDeleted() {
assert((data().DefaultedMoveConstructorIsDeleted ||
@@ -927,6 +988,15 @@ public:
data().DefaultedMoveConstructorIsDeleted = true;
}
+ /// \brief Set that we attempted to declare an implicit destructor,
+ /// but overload resolution failed so we deleted it.
+ void setImplicitDestructorIsDeleted() {
+ assert((data().DefaultedDestructorIsDeleted ||
+ needsOverloadResolutionForDestructor()) &&
+ "destructor should not be deleted");
+ data().DefaultedDestructorIsDeleted = true;
+ }
+
/// \brief Determine whether this class should get an implicit move
/// constructor or if any existing special member function inhibits this.
bool needsImplicitMoveConstructor() const {
@@ -1315,6 +1385,18 @@ public:
return data().HasIrrelevantDestructor;
}
+ /// \brief Determine whether this class has at least one trivial, non-deleted
+ /// copy or move constructor.
+ bool canPassInRegisters() const {
+ return data().CanPassInRegisters;
+ }
+
+ /// \brief Set that we can pass this RecordDecl in registers.
+ // FIXME: This should be set as part of completeDefinition.
+ void setCanPassInRegisters(bool CanPass) {
+ data().CanPassInRegisters = CanPass;
+ }
+
/// \brief Determine whether this class has a non-literal or/ volatile type
/// non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {
@@ -1562,10 +1644,13 @@ public:
/// \param Paths used to record the paths from this class to its base class
/// subobjects that match the search criteria.
///
+ /// \param LookupInDependent can be set to true to extend the search to
+ /// dependent base classes.
+ ///
/// \returns true if there exists any path from this class to a base class
/// subobject that matches the search criteria.
- bool lookupInBases(BaseMatchesCallback BaseMatches,
- CXXBasePaths &Paths) const;
+ bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths,
+ bool LookupInDependent = false) const;
/// \brief Base-class lookup callback that determines whether the given
/// base class specifier refers to a specific class declaration.
@@ -1607,6 +1692,16 @@ public:
CXXBasePath &Path, DeclarationName Name);
/// \brief Base-class lookup callback that determines whether there exists
+ /// a member with the given name.
+ ///
+ /// This callback can be used with \c lookupInBases() to find members
+ /// of the given name within a C++ class hierarchy, including dependent
+ /// classes.
+ static bool
+ FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path, DeclarationName Name);
+
+ /// \brief Base-class lookup callback that determines whether there exists
/// an OpenMP declare reduction member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
@@ -1632,6 +1727,14 @@ public:
/// \brief Get the indirect primary bases for this class.
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const;
+ /// Performs an imprecise lookup of a dependent name in this class.
+ ///
+ /// This function does not follow strict semantic rules and should be used
+ /// only when lookup rules can be relaxed, e.g. indexing.
+ std::vector<const NamedDecl *>
+ lookupDependentName(const DeclarationName &Name,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter);
+
/// Renders and displays an inheritance diagram
/// for this C++ class and all of its base classes (transitively) using
/// GraphViz.
@@ -1740,6 +1843,10 @@ public:
return getLambdaData().MethodTyInfo;
}
+ // \brief Determine whether this type is an Interface Like type for
+ // __interface inheritence purposes.
+ bool isInterfaceLike() const;
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstCXXRecord && K <= lastCXXRecord;
@@ -1774,6 +1881,10 @@ private:
if (EndLocation.isValid())
setRangeEnd(EndLocation);
IsExplicitSpecified = IsExplicit;
+
+ // IsCopyDeductionCandidate is a union variant member, so ensure it is the
+ // active member by storing to it.
+ IsCopyDeductionCandidate = false;
}
public:
@@ -1796,6 +1907,12 @@ public:
return getDeclName().getCXXDeductionGuideTemplate();
}
+ void setIsCopyDeductionCandidate() {
+ IsCopyDeductionCandidate = true;
+ }
+
+ bool isCopyDeductionCandidate() const { return IsCopyDeductionCandidate; }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == CXXDeductionGuide; }
@@ -1864,6 +1981,19 @@ public:
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
}
+ /// If it's possible to devirtualize a call to this method, return the called
+ /// function. Otherwise, return null.
+
+ /// \param Base The object on which this virtual function is called.
+ /// \param IsAppleKext True if we are compiling for Apple kext.
+ CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, bool IsAppleKext);
+
+ const CXXMethodDecl *getDevirtualizedMethod(const Expr *Base,
+ bool IsAppleKext) const {
+ return const_cast<CXXMethodDecl *>(this)->getDevirtualizedMethod(
+ Base, IsAppleKext);
+ }
+
/// \brief Determine whether this is a usual deallocation function
/// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
/// delete or delete[] operator with a particular signature.
@@ -1923,7 +2053,10 @@ public:
/// \brief Returns the type of the \c this pointer.
///
- /// Should only be called for instance (i.e., non-static) methods.
+ /// Should only be called for instance (i.e., non-static) methods. Note
+ /// that for the call operator of a lambda closure type, this returns the
+ /// desugared 'this' type (a pointer to the closure type), not the captured
+ /// 'this' type.
QualType getThisType(ASTContext &C) const;
unsigned getTypeQualifiers() const {
@@ -2443,7 +2576,10 @@ public:
class CXXDestructorDecl : public CXXMethodDecl {
void anchor() override;
+ // FIXME: Don't allocate storage for these except in the first declaration
+ // of a virtual destructor.
FunctionDecl *OperatorDelete;
+ Expr *OperatorDeleteThisArg;
CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
@@ -2451,7 +2587,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
bool isInline, bool isImplicitlyDeclared)
: CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, /*isConstexpr=*/false, SourceLocation()),
- OperatorDelete(nullptr) {
+ OperatorDelete(nullptr), OperatorDeleteThisArg(nullptr) {
setImplicit(isImplicitlyDeclared);
}
@@ -2464,10 +2600,13 @@ public:
bool isImplicitlyDeclared);
static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
- void setOperatorDelete(FunctionDecl *OD);
+ void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
const FunctionDecl *getOperatorDelete() const {
return getCanonicalDecl()->OperatorDelete;
}
+ Expr *getOperatorDeleteThisArg() const {
+ return getCanonicalDecl()->OperatorDeleteThisArg;
+ }
CXXDestructorDecl *getCanonicalDecl() override {
return cast<CXXDestructorDecl>(FunctionDecl::getCanonicalDecl());
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index ff37758c25..eb86526e8e 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/DeclGroup.h b/include/clang/AST/DeclGroup.h
index 6353b26f7b..628d7886aa 100644
--- a/include/clang/AST/DeclGroup.h
+++ b/include/clang/AST/DeclGroup.h
@@ -138,10 +138,9 @@ public:
namespace llvm {
// DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits.
template <typename T>
- class PointerLikeTypeTraits;
+ struct PointerLikeTypeTraits;
template <>
- class PointerLikeTypeTraits<clang::DeclGroupRef> {
- public:
+ struct PointerLikeTypeTraits<clang::DeclGroupRef> {
static inline void *getAsVoidPointer(clang::DeclGroupRef P) {
return P.getAsOpaquePtr();
}
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index a445042aec..1cd6e004f7 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; }
@@ -1027,10 +1039,9 @@ public:
typedef llvm::DenseMap<std::pair<IdentifierInfo*,
unsigned/*isClassProperty*/>,
ObjCPropertyDecl*> PropertyMap;
-
- typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
- ProtocolPropertyMap;
-
+
+ typedef llvm::SmallDenseSet<const ObjCProtocolDecl *, 8> ProtocolPropertySet;
+
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
/// This routine collects list of properties to be implemented in the class.
@@ -2147,7 +2158,8 @@ public:
PropertyDeclOrder &PO) const override;
void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
- ProtocolPropertyMap &PM) const;
+ ProtocolPropertySet &PS,
+ PropertyDeclOrder &PO) const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCProtocol; }
diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h
index 30ca79e9d0..2a329c3732 100644
--- a/include/clang/AST/DeclOpenMP.h
+++ b/include/clang/AST/DeclOpenMP.h
@@ -100,12 +100,22 @@ public:
///
/// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer.
class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext {
+public:
+ enum InitKind {
+ CallInit, // Initialized by function call.
+ DirectInit, // omp_priv(<expr>)
+ CopyInit // omp_priv = <expr>
+ };
+
private:
friend class ASTDeclReader;
/// \brief Combiner for declare reduction construct.
Expr *Combiner;
/// \brief Initializer for declare reduction construct.
Expr *Initializer;
+ /// Kind of initializer - function call or omp_priv<init_expr> initializtion.
+ InitKind InitializerKind = CallInit;
+
/// \brief Reference to the previous declare reduction construct in the same
/// scope with the same name. Required for proper templates instantiation if
/// the declare reduction construct is declared inside compound statement.
@@ -117,7 +127,8 @@ private:
DeclarationName Name, QualType Ty,
OMPDeclareReductionDecl *PrevDeclInScope)
: ValueDecl(DK, DC, L, Name, Ty), DeclContext(DK), Combiner(nullptr),
- Initializer(nullptr), PrevDeclInScope(PrevDeclInScope) {}
+ Initializer(nullptr), InitializerKind(CallInit),
+ PrevDeclInScope(PrevDeclInScope) {}
void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) {
PrevDeclInScope = Prev;
@@ -142,8 +153,13 @@ public:
/// construct.
Expr *getInitializer() { return Initializer; }
const Expr *getInitializer() const { return Initializer; }
+ /// Get initializer kind.
+ InitKind getInitializerKind() const { return InitializerKind; }
/// \brief Set initializer expression for the declare reduction construct.
- void setInitializer(Expr *E) { Initializer = E; }
+ void setInitializer(Expr *E, InitKind IK) {
+ Initializer = E;
+ InitializerKind = IK;
+ }
/// \brief Get reference to previous declare reduction construct in the same
/// scope with the same name.
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index a7ca03ff9e..bef2339e8e 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -24,6 +24,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SyncScope.h"
#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APSInt.h"
@@ -274,6 +275,7 @@ public:
MLV_LValueCast, // Specialized form of MLV_InvalidExpression.
MLV_IncompleteType,
MLV_ConstQualified,
+ MLV_ConstQualifiedField,
MLV_ConstAddrSpace,
MLV_ArrayType,
MLV_NoSetterProperty,
@@ -323,6 +325,7 @@ public:
CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext
CM_NoSetterProperty,// Implicit assignment to ObjC property without setter
CM_ConstQualified,
+ CM_ConstQualifiedField,
CM_ConstAddrSpace,
CM_ArrayType,
CM_IncompleteType
@@ -908,6 +911,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
@@ -1168,6 +1175,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;
@@ -1223,6 +1234,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;
};
@@ -1316,6 +1330,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 {
@@ -1366,6 +1383,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 {
@@ -1430,6 +1450,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,
@@ -1462,6 +1485,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"
@@ -1629,6 +1655,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
@@ -1670,6 +1699,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
@@ -1779,6 +1811,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.
@@ -1982,6 +2017,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;
};
@@ -2070,6 +2110,7 @@ public:
// Iterators
child_range children();
+ const_child_range children() const;
};
//===----------------------------------------------------------------------===//
@@ -2154,6 +2195,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]).
@@ -2304,6 +2348,12 @@ public:
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
+ bool isCallToStdMove() const {
+ const FunctionDecl* FD = getDirectCallee();
+ return getNumArgs() == 1 && FD && FD->isInStdNamespace() &&
+ FD->getIdentifier() && FD->getIdentifier()->isStr("move");
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstCallExprConstant &&
T->getStmtClass() <= lastCallExprConstant;
@@ -2314,6 +2364,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.
@@ -2568,6 +2623,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;
@@ -2640,6 +2698,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
@@ -2719,6 +2780,16 @@ public:
path_const_iterator path_begin() const { return path_buffer(); }
path_const_iterator path_end() const { return path_buffer() + path_size(); }
+ const FieldDecl *getTargetUnionField() const {
+ assert(getCastKind() == CK_ToUnion);
+ return getTargetFieldForToUnionCast(getType(), getSubExpr()->getType());
+ }
+
+ static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType,
+ QualType opType);
+ static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD,
+ QualType opType);
+
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstCastExprConstant &&
T->getStmtClass() <= lastCastExprConstant;
@@ -2726,6 +2797,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
@@ -2918,11 +2990,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 };
@@ -2931,7 +3001,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(),
@@ -2939,7 +3009,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() &&
@@ -3062,6 +3132,12 @@ public:
return isShiftAssignOp(getOpcode());
}
+ // Return true if a binary operator using the specified opcode and operands
+ // would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized
+ // integer to a pointer.
+ static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc,
+ Expr *LHS, Expr *RHS);
+
static bool classof(const Stmt *S) {
return S->getStmtClass() >= firstBinaryOperatorConstant &&
S->getStmtClass() <= lastBinaryOperatorConstant;
@@ -3071,19 +3147,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(),
@@ -3091,7 +3174,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;
}
@@ -3113,8 +3196,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) {
@@ -3247,6 +3330,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
@@ -3332,6 +3418,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 {
@@ -3386,6 +3475,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;}).
@@ -3428,6 +3520,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
@@ -3496,6 +3591,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
@@ -3550,6 +3648,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.
@@ -3630,6 +3731,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
@@ -3666,6 +3770,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.
@@ -3713,6 +3820,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.
@@ -3901,6 +4011,10 @@ public:
/// initializer)?
bool isTransparent() const;
+ /// Is this the zero initializer {0} in a language which considers it
+ /// idiomatic?
+ bool isIdiomaticZeroInitializer(const LangOptions &LangOpts) const;
+
SourceLocation getLBraceLoc() const { return LBraceLoc; }
void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
SourceLocation getRBraceLoc() const { return RBraceLoc; }
@@ -3910,6 +4024,9 @@ public:
InitListExpr *getSemanticForm() const {
return isSemanticForm() ? nullptr : AltForm.getPointer();
}
+ bool isSyntacticForm() const {
+ return !AltForm.getInt() || !AltForm.getPointer();
+ }
InitListExpr *getSyntacticForm() const {
return isSemanticForm() ? AltForm.getPointer() : nullptr;
}
@@ -3937,10 +4054,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;
@@ -4193,6 +4316,9 @@ public:
}
Designator *getDesignator(unsigned Idx) { return &designators()[Idx]; }
+ const Designator *getDesignator(unsigned Idx) const {
+ return &designators()[Idx];
+ }
void setDesignators(const ASTContext &C, const Designator *Desigs,
unsigned NumDesigs);
@@ -4255,6 +4381,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;
};
@@ -4288,6 +4418,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:
@@ -4333,6 +4466,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.
@@ -4394,6 +4531,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;
@@ -4422,6 +4562,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;
@@ -4456,6 +4599,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 {
@@ -4502,6 +4648,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;
@@ -4622,7 +4771,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;
};
@@ -4691,6 +4842,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.
@@ -4732,6 +4886,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]
@@ -4777,6 +4934,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
@@ -4915,8 +5075,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) {
@@ -4929,9 +5096,11 @@ public:
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
-/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>.
-/// All of these instructions take one primary pointer and at least one memory
-/// order.
+/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>,
+/// and corresponding __opencl_atomic_* for OpenCL 2.0.
+/// All of these instructions take one primary pointer, at least one memory
+/// order. The instructions for which getScopeModel returns non-null value
+/// take one synch scope.
class AtomicExpr : public Expr {
public:
enum AtomicOp {
@@ -4943,14 +5112,16 @@ public:
};
private:
+ /// \brief Location of sub-expressions.
+ /// The location of Scope sub-expression is NumSubExprs - 1, which is
+ /// not fixed, therefore is not defined in enum.
enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR };
- Stmt* SubExprs[END_EXPR];
+ Stmt *SubExprs[END_EXPR + 1];
unsigned NumSubExprs;
SourceLocation BuiltinLoc, RParenLoc;
AtomicOp Op;
friend class ASTStmtReader;
-
public:
AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t,
AtomicOp op, SourceLocation RP);
@@ -4968,8 +5139,12 @@ public:
Expr *getOrder() const {
return cast<Expr>(SubExprs[ORDER]);
}
+ Expr *getScope() const {
+ assert(getScopeModel() && "No scope");
+ return cast<Expr>(SubExprs[NumSubExprs - 1]);
+ }
Expr *getVal1() const {
- if (Op == AO__c11_atomic_init)
+ if (Op == AO__c11_atomic_init || Op == AO__opencl_atomic_init)
return cast<Expr>(SubExprs[ORDER]);
assert(NumSubExprs > VAL1);
return cast<Expr>(SubExprs[VAL1]);
@@ -4988,6 +5163,7 @@ public:
assert(NumSubExprs > WEAK);
return cast<Expr>(SubExprs[WEAK]);
}
+ QualType getValueType() const;
AtomicOp getOp() const { return Op; }
unsigned getNumSubExprs() const { return NumSubExprs; }
@@ -5004,10 +5180,17 @@ public:
bool isCmpXChg() const {
return getOp() == AO__c11_atomic_compare_exchange_strong ||
getOp() == AO__c11_atomic_compare_exchange_weak ||
+ getOp() == AO__opencl_atomic_compare_exchange_strong ||
+ getOp() == AO__opencl_atomic_compare_exchange_weak ||
getOp() == AO__atomic_compare_exchange ||
getOp() == AO__atomic_compare_exchange_n;
}
+ bool isOpenCL() const {
+ return getOp() >= AO__opencl_atomic_init &&
+ getOp() <= AO__opencl_atomic_fetch_max;
+ }
+
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
@@ -5022,6 +5205,27 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs+NumSubExprs);
}
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + NumSubExprs);
+ }
+
+ /// \brief Get atomic scope model for the atomic op code.
+ /// \return empty atomic scope model if the atomic op code does not have
+ /// scope operand.
+ static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) {
+ auto Kind =
+ (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max)
+ ? AtomicScopeModelKind::OpenCL
+ : AtomicScopeModelKind::None;
+ return AtomicScopeModel::create(Kind);
+ }
+
+ /// \brief Get atomic scope model.
+ /// \return empty atomic scope model if this atomic expression does not have
+ /// scope operand.
+ std::unique_ptr<AtomicScopeModel> getScopeModel() const {
+ return getScopeModel(getOp());
+ }
};
/// TypoExpr - Internal placeholder for expressions where typo correction
@@ -5040,6 +5244,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 f4ff5bb982..a2cf961269 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;
@@ -3054,6 +3056,11 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+ /// Determine whether this expression models list-initialization.
+ /// If so, there will be exactly one subexpression, which will be
+ /// an InitListExpr.
+ bool isListInitialization() const { return LParenLoc.isInvalid(); }
+
/// \brief Retrieve the number of arguments.
unsigned arg_size() const { return NumArgs; }
diff --git a/include/clang/AST/ExternalASTMerger.h b/include/clang/AST/ExternalASTMerger.h
new file mode 100644
index 0000000000..81492aec6e
--- /dev/null
+++ b/include/clang/AST/ExternalASTMerger.h
@@ -0,0 +1,176 @@
+//===--- 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"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+/// ExternalASTSource implementation that merges information from several
+/// ASTContexts.
+///
+/// ExtermalASTMerger maintains a vector of ASTImporters that it uses to import
+/// (potentially incomplete) Decls and DeclContexts from the source ASTContexts
+/// in response to ExternalASTSource API calls.
+///
+/// When lookup occurs in the resulting imported DeclContexts, the original
+/// DeclContexts need to be queried. Roughly, there are three cases here:
+///
+/// - The DeclContext of origin can be found by simple name lookup. In this
+/// case, no additional state is required.
+///
+/// - The DeclContext of origin is different from what would be found by name
+/// lookup. In this case, Origins contains an entry overriding lookup and
+/// specifying the correct pair of DeclContext/ASTContext.
+///
+/// - The DeclContext of origin was determined by another ExterenalASTMerger.
+/// (This is possible when the source ASTContext for one of the Importers has
+/// its own ExternalASTMerger). The origin must be properly forwarded in this
+/// case.
+///
+/// ExternalASTMerger's job is to maintain the data structures necessary to
+/// allow this. The data structures themselves can be extracted (read-only) and
+/// copied for re-use.
+class ExternalASTMerger : public ExternalASTSource {
+public:
+ /// A single origin for a DeclContext. Unlike Decls, DeclContexts do
+ /// not allow their containing ASTContext to be determined in all cases.
+ struct DCOrigin {
+ DeclContext *DC;
+ ASTContext *AST;
+ };
+
+ typedef std::map<const DeclContext *, DCOrigin> OriginMap;
+ typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector;
+private:
+ /// One importer exists for each source.
+ ImporterVector Importers;
+ /// Overrides in case name lookup would return nothing or would return
+ /// the wrong thing.
+ OriginMap Origins;
+ /// The installed log stream.
+ llvm::raw_ostream *LogStream;
+
+public:
+ /// The target for an ExternalASTMerger.
+ ///
+ /// ASTImporters require both ASTContext and FileManager to be able to
+ /// import SourceLocations properly.
+ struct ImporterTarget {
+ ASTContext &AST;
+ FileManager &FM;
+ };
+ /// A source for an ExternalASTMerger.
+ ///
+ /// ASTImporters require both ASTContext and FileManager to be able to
+ /// import SourceLocations properly. Additionally, when import occurs for
+ /// a DeclContext whose origin has been overridden, then this
+ /// ExternalASTMerger must be able to determine that.
+ struct ImporterSource {
+ ASTContext &AST;
+ FileManager &FM;
+ const OriginMap &OM;
+ };
+
+private:
+ /// The target for this ExtenralASTMerger.
+ ImporterTarget Target;
+
+public:
+ ExternalASTMerger(const ImporterTarget &Target,
+ llvm::ArrayRef<ImporterSource> Sources);
+
+ /// Add a set of ASTContexts as possible origins.
+ ///
+ /// Usually the set will be initialized in the constructor, but long-lived
+ /// ExternalASTMergers may neeed to import from new sources (for example,
+ /// newly-parsed source files).
+ ///
+ /// Ensures that Importers does not gain duplicate entries as a result.
+ void AddSources(llvm::ArrayRef<ImporterSource> Sources);
+
+ /// Remove a set of ASTContexts as possible origins.
+ ///
+ /// Sometimes an origin goes away (for example, if a source file gets
+ /// superseded by a newer version).
+ ///
+ /// The caller is responsible for ensuring that this doesn't leave
+ /// DeclContexts that can't be completed.
+ void RemoveSources(llvm::ArrayRef<ImporterSource> Sources);
+
+ /// Implementation of the ExternalASTSource API.
+ bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) override;
+
+ /// Implementation of the ExternalASTSource API.
+ void
+ FindExternalLexicalDecls(const DeclContext *DC,
+ llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
+ SmallVectorImpl<Decl *> &Result) override;
+
+ /// Implementation of the ExternalASTSource API.
+ void CompleteType(TagDecl *Tag) override;
+
+ /// Implementation of the ExternalASTSource API.
+ void CompleteType(ObjCInterfaceDecl *Interface) override;
+
+ /// Returns true if DC can be found in any source AST context.
+ bool CanComplete(DeclContext *DC);
+
+ /// Records an origin in Origins only if name lookup would find
+ /// something different or nothing at all.
+ void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin);
+
+ /// Regardless of any checks, override the Origin for a DeclContext.
+ void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin);
+
+ /// Get a read-only view of the Origins map, for use in constructing
+ /// an ImporterSource for another ExternalASTMerger.
+ const OriginMap &GetOrigins() { return Origins; }
+
+ /// Returns true if Importers contains an ASTImporter whose source is
+ /// OriginContext.
+ bool HasImporterForOrigin(ASTContext &OriginContext);
+
+ /// Returns a reference to the ASTRImporter from Importers whose origin
+ /// is OriginContext. This allows manual import of ASTs while preserving the
+ /// OriginMap correctly.
+ ASTImporter &ImporterForOrigin(ASTContext &OriginContext);
+
+ /// Sets the current log stream.
+ void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; }
+private:
+ /// Records and origin in Origins.
+ void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
+ ASTImporter &importer);
+
+ /// Performs an action for every DeclContext that is identified as
+ /// corresponding (either by forced origin or by name lookup) to DC.
+ template <typename CallbackType>
+ void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback);
+
+public:
+ /// Log something if there is a logging callback installed.
+ llvm::raw_ostream &logs() { return *LogStream; }
+
+ /// True if the log stream is not llvm::nulls();
+ bool LoggingEnabled() { return LogStream != &llvm::nulls(); }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 40c54b2e8d..d8dd18ecb8 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -172,7 +172,7 @@ public:
enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
- virtual ExtKind hasExternalDefinitions(unsigned ID);
+ 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/LexicallyOrderedRecursiveASTVisitor.h b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
new file mode 100644
index 0000000000..264f20f19a
--- /dev/null
+++ b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
@@ -0,0 +1,164 @@
+//===--- LexicallyOrderedRecursiveASTVisitor.h - ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the LexicallyOrderedRecursiveASTVisitor interface, which
+// recursively traverses the entire AST in a lexical order.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H
+#define LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/SaveAndRestore.h"
+
+namespace clang {
+
+/// A RecursiveASTVisitor subclass that guarantees that AST traversal is
+/// performed in a lexical order (i.e. the order in which declarations are
+/// written in the source).
+///
+/// RecursiveASTVisitor doesn't guarantee lexical ordering because there are
+/// some declarations, like Objective-C @implementation declarations
+/// that might be represented in the AST differently to how they were written
+/// in the source.
+/// In particular, Objective-C @implementation declarations may contain
+/// non-Objective-C declarations, like functions:
+///
+/// @implementation MyClass
+///
+/// - (void) method { }
+/// void normalFunction() { }
+///
+/// @end
+///
+/// Clang's AST stores these declarations outside of the @implementation
+/// declaration, so the example above would be represented using the following
+/// AST:
+/// |-ObjCImplementationDecl ... MyClass
+/// | `-ObjCMethodDecl ... method
+/// | ...
+/// `-FunctionDecl ... normalFunction
+/// ...
+///
+/// This class ensures that these declarations are traversed before the
+/// corresponding TraverseDecl for the @implementation returns. This ensures
+/// that the lexical parent relationship between these declarations and the
+/// @implementation is preserved while traversing the AST. Note that the
+/// current implementation doesn't mix these declarations with the declarations
+/// contained in the @implementation, so the traversal of all of the
+/// declarations in the @implementation still doesn't follow the lexical order.
+template <typename Derived>
+class LexicallyOrderedRecursiveASTVisitor
+ : public RecursiveASTVisitor<Derived> {
+ using BaseType = RecursiveASTVisitor<Derived>;
+
+public:
+ LexicallyOrderedRecursiveASTVisitor(const SourceManager &SM) : SM(SM) {}
+
+ bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
+ // Objective-C @implementation declarations should not trigger early exit
+ // until the additional decls are traversed as their children are not
+ // lexically ordered.
+ bool Result = BaseType::TraverseObjCImplementationDecl(D);
+ return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false;
+ }
+
+ bool TraverseObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ bool Result = BaseType::TraverseObjCCategoryImplDecl(D);
+ return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false;
+ }
+
+ bool TraverseDeclContextHelper(DeclContext *DC) {
+ if (!DC)
+ return true;
+
+ for (auto I = DC->decls_begin(), E = DC->decls_end(); I != E;) {
+ Decl *Child = *I;
+ if (BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Child)) {
+ ++I;
+ continue;
+ }
+ if (!isa<ObjCImplementationDecl>(Child) &&
+ !isa<ObjCCategoryImplDecl>(Child)) {
+ if (!BaseType::getDerived().TraverseDecl(Child))
+ return false;
+ ++I;
+ continue;
+ }
+ // Gather declarations that follow the Objective-C implementation
+ // declarations but are lexically contained in the implementation.
+ LexicallyNestedDeclarations.clear();
+ for (++I; I != E; ++I) {
+ Decl *Sibling = *I;
+ if (!SM.isBeforeInTranslationUnit(Sibling->getLocStart(),
+ Child->getLocEnd()))
+ break;
+ if (!BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Sibling))
+ LexicallyNestedDeclarations.push_back(Sibling);
+ }
+ if (!BaseType::getDerived().TraverseDecl(Child))
+ return false;
+ }
+ return true;
+ }
+
+ Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
+
+ SmallVector<Stmt *, 8> getStmtChildren(CXXOperatorCallExpr *CE) {
+ SmallVector<Stmt *, 8> Children(CE->children());
+ bool Swap;
+ // Switch the operator and the first operand for all infix and postfix
+ // operations.
+ switch (CE->getOperator()) {
+ case OO_Arrow:
+ case OO_Call:
+ case OO_Subscript:
+ Swap = true;
+ break;
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ // These are postfix unless there is exactly one argument.
+ Swap = Children.size() != 2;
+ break;
+ default:
+ Swap = CE->isInfixBinaryOp();
+ break;
+ }
+ if (Swap && Children.size() > 1)
+ std::swap(Children[0], Children[1]);
+ return Children;
+ }
+
+private:
+ bool TraverseAdditionalLexicallyNestedDeclarations() {
+ // FIXME: Ideally the gathered declarations and the declarations in the
+ // @implementation should be mixed and sorted to get a true lexical order,
+ // but right now we only care about getting the correct lexical parent, so
+ // we can traverse the gathered nested declarations after the declarations
+ // in the decl context.
+ assert(!BaseType::getDerived().shouldTraversePostOrder() &&
+ "post-order traversal is not supported for lexically ordered "
+ "recursive ast visitor");
+ for (Decl *D : LexicallyNestedDeclarations) {
+ if (!BaseType::getDerived().TraverseDecl(D))
+ return false;
+ }
+ return true;
+ }
+
+ const SourceManager &SM;
+ llvm::SmallVector<Decl *, 8> LexicallyNestedDeclarations;
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H
diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
index 583f9d9f1d..3757116e7c 100644
--- a/include/clang/AST/NSAPI.h
+++ b/include/clang/AST/NSAPI.h
@@ -49,7 +49,7 @@ public:
NSStr_initWithString,
NSStr_initWithUTF8String
};
- static const unsigned NumNSStringMethods = 5;
+ static const unsigned NumNSStringMethods = 6;
IdentifierInfo *getNSClassId(NSClassIdKindKind K) const;
@@ -112,7 +112,7 @@ public:
NSMutableDict_setObjectForKeyedSubscript,
NSMutableDict_setValueForKey
};
- static const unsigned NumNSDictionaryMethods = 14;
+ static const unsigned NumNSDictionaryMethods = 13;
/// \brief The Objective-C NSDictionary selectors.
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index b1ff9bdff5..29862ba416 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -35,7 +35,7 @@ class LangOptions;
/// "\::std::vector<int>::".
///
/// C++ nested name specifiers are the prefixes to qualified
-/// namespaces. For example, "foo::" in "foo::x" is a nested name
+/// names. For example, "foo::" in "foo::x" is a nested name
/// specifier. Nested name specifiers are made up of a sequence of
/// specifiers, each of which can be a namespace, type, identifier
/// (for dependent names), decltype specifier, or the global specifier ('::').
diff --git a/include/clang/AST/ODRHash.h b/include/clang/AST/ODRHash.h
index 9af8488fca..e4cc12d358 100644
--- a/include/clang/AST/ODRHash.h
+++ b/include/clang/AST/ODRHash.h
@@ -25,7 +25,7 @@ namespace clang {
class Decl;
class IdentifierInfo;
-class NestedNameSpecifer;
+class NestedNameSpecifier;
class Stmt;
class TemplateParameterList;
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index f977e63e04..7c24e34251 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -20,6 +20,7 @@
#include "clang/AST/Stmt.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/MapVector.h"
namespace clang {
@@ -1889,6 +1890,449 @@ public:
}
};
+/// This represents clause 'task_reduction' in the '#pragma omp taskgroup'
+/// directives.
+///
+/// \code
+/// #pragma omp taskgroup task_reduction(+:a,b)
+/// \endcode
+/// In this example directive '#pragma omp taskgroup' has clause
+/// 'task_reduction' with operator '+' and the variables 'a' and 'b'.
+///
+class OMPTaskReductionClause final
+ : public OMPVarListClause<OMPTaskReductionClause>,
+ public OMPClauseWithPostUpdate,
+ private llvm::TrailingObjects<OMPTaskReductionClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
+ friend class OMPClauseReader;
+ /// Location of ':'.
+ SourceLocation ColonLoc;
+ /// Nested name specifier for C++.
+ NestedNameSpecifierLoc QualifierLoc;
+ /// Name of custom operator.
+ DeclarationNameInfo NameInfo;
+
+ /// Build clause with number of variables \a N.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param ColonLoc Location of ':'.
+ /// \param N Number of the variables in the clause.
+ /// \param QualifierLoc The nested-name qualifier with location information
+ /// \param NameInfo The full name info for reduction identifier.
+ ///
+ OMPTaskReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ unsigned N, NestedNameSpecifierLoc QualifierLoc,
+ const DeclarationNameInfo &NameInfo)
+ : OMPVarListClause<OMPTaskReductionClause>(OMPC_task_reduction, StartLoc,
+ LParenLoc, EndLoc, N),
+ OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc),
+ QualifierLoc(QualifierLoc), NameInfo(NameInfo) {}
+
+ /// Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPTaskReductionClause(unsigned N)
+ : OMPVarListClause<OMPTaskReductionClause>(
+ OMPC_task_reduction, SourceLocation(), SourceLocation(),
+ SourceLocation(), N),
+ OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {}
+
+ /// Sets location of ':' symbol in clause.
+ void setColonLoc(SourceLocation CL) { ColonLoc = CL; }
+ /// Sets the name info for specified reduction identifier.
+ void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; }
+ /// Sets the nested name specifier.
+ void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent private copy of the reduction variable.
+ void setPrivates(ArrayRef<Expr *> Privates);
+
+ /// Get the list of helper privates.
+ MutableArrayRef<Expr *> getPrivates() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getPrivates() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent LHS expression in the final reduction
+ /// expression performed by the reduction clause.
+ void setLHSExprs(ArrayRef<Expr *> LHSExprs);
+
+ /// Get the list of helper LHS expressions.
+ MutableArrayRef<Expr *> getLHSExprs() {
+ return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getLHSExprs() const {
+ return llvm::makeArrayRef(getPrivates().end(), varlist_size());
+ }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent RHS expression in the final reduction
+ /// expression performed by the reduction clause. Also, variables in these
+ /// expressions are used for proper initialization of reduction copies.
+ void setRHSExprs(ArrayRef<Expr *> RHSExprs);
+
+ /// Get the list of helper destination expressions.
+ MutableArrayRef<Expr *> getRHSExprs() {
+ return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getRHSExprs() const {
+ return llvm::makeArrayRef(getLHSExprs().end(), varlist_size());
+ }
+
+ /// Set list of helper reduction expressions, required for proper
+ /// codegen of the clause. These expressions are binary expressions or
+ /// operator/custom reduction call that calculates new value from source
+ /// helper expressions to destination helper expressions.
+ void setReductionOps(ArrayRef<Expr *> ReductionOps);
+
+ /// Get the list of helper reduction expressions.
+ MutableArrayRef<Expr *> getReductionOps() {
+ return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getReductionOps() const {
+ return llvm::makeArrayRef(getRHSExprs().end(), varlist_size());
+ }
+
+public:
+ /// Creates clause with a list of variables \a VL.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param ColonLoc Location of ':'.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL The variables in the clause.
+ /// \param QualifierLoc The nested-name qualifier with location information
+ /// \param NameInfo The full name info for reduction identifier.
+ /// \param Privates List of helper expressions for proper generation of
+ /// private copies.
+ /// \param LHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// LHSs of the reduction expressions.
+ /// \param RHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// RHSs of the reduction expressions.
+ /// Also, variables in these expressions are used for proper initialization of
+ /// reduction copies.
+ /// \param ReductionOps List of helper expressions that represents reduction
+ /// expressions:
+ /// \code
+ /// LHSExprs binop RHSExprs;
+ /// operator binop(LHSExpr, RHSExpr);
+ /// <CutomReduction>(LHSExpr, RHSExpr);
+ /// \endcode
+ /// Required for proper codegen of final reduction operation performed by the
+ /// reduction clause.
+ /// \param PreInit Statement that must be executed before entering the OpenMP
+ /// region with this clause.
+ /// \param PostUpdate Expression that must be executed after exit from the
+ /// OpenMP region with this clause.
+ ///
+ static OMPTaskReductionClause *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ NestedNameSpecifierLoc QualifierLoc,
+ const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates,
+ ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs,
+ ArrayRef<Expr *> ReductionOps, Stmt *PreInit, Expr *PostUpdate);
+
+ /// Creates an empty clause with the place for \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPTaskReductionClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ /// Gets location of ':' symbol in clause.
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ /// Gets the name info for specified reduction identifier.
+ const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
+ /// Gets the nested name specifier.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+
+ typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
+ typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
+ typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
+ typedef llvm::iterator_range<helper_expr_const_iterator>
+ helper_expr_const_range;
+
+ helper_expr_const_range privates() const {
+ return helper_expr_const_range(getPrivates().begin(), getPrivates().end());
+ }
+ helper_expr_range privates() {
+ return helper_expr_range(getPrivates().begin(), getPrivates().end());
+ }
+ helper_expr_const_range lhs_exprs() const {
+ return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_range lhs_exprs() {
+ return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_const_range rhs_exprs() const {
+ return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_range rhs_exprs() {
+ return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_const_range reduction_ops() const {
+ return helper_expr_const_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+ helper_expr_range reduction_ops() {
+ return helper_expr_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+
+ child_range children() {
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_task_reduction;
+ }
+};
+
+/// This represents clause 'in_reduction' in the '#pragma omp task' directives.
+///
+/// \code
+/// #pragma omp task in_reduction(+:a,b)
+/// \endcode
+/// In this example directive '#pragma omp task' has clause 'in_reduction' with
+/// operator '+' and the variables 'a' and 'b'.
+///
+class OMPInReductionClause final
+ : public OMPVarListClause<OMPInReductionClause>,
+ public OMPClauseWithPostUpdate,
+ private llvm::TrailingObjects<OMPInReductionClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
+ friend class OMPClauseReader;
+ /// Location of ':'.
+ SourceLocation ColonLoc;
+ /// Nested name specifier for C++.
+ NestedNameSpecifierLoc QualifierLoc;
+ /// Name of custom operator.
+ DeclarationNameInfo NameInfo;
+
+ /// Build clause with number of variables \a N.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param ColonLoc Location of ':'.
+ /// \param N Number of the variables in the clause.
+ /// \param QualifierLoc The nested-name qualifier with location information
+ /// \param NameInfo The full name info for reduction identifier.
+ ///
+ OMPInReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ unsigned N, NestedNameSpecifierLoc QualifierLoc,
+ const DeclarationNameInfo &NameInfo)
+ : OMPVarListClause<OMPInReductionClause>(OMPC_in_reduction, StartLoc,
+ LParenLoc, EndLoc, N),
+ OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc),
+ QualifierLoc(QualifierLoc), NameInfo(NameInfo) {}
+
+ /// Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPInReductionClause(unsigned N)
+ : OMPVarListClause<OMPInReductionClause>(
+ OMPC_in_reduction, SourceLocation(), SourceLocation(),
+ SourceLocation(), N),
+ OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {}
+
+ /// Sets location of ':' symbol in clause.
+ void setColonLoc(SourceLocation CL) { ColonLoc = CL; }
+ /// Sets the name info for specified reduction identifier.
+ void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; }
+ /// Sets the nested name specifier.
+ void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent private copy of the reduction variable.
+ void setPrivates(ArrayRef<Expr *> Privates);
+
+ /// Get the list of helper privates.
+ MutableArrayRef<Expr *> getPrivates() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getPrivates() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent LHS expression in the final reduction
+ /// expression performed by the reduction clause.
+ void setLHSExprs(ArrayRef<Expr *> LHSExprs);
+
+ /// Get the list of helper LHS expressions.
+ MutableArrayRef<Expr *> getLHSExprs() {
+ return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getLHSExprs() const {
+ return llvm::makeArrayRef(getPrivates().end(), varlist_size());
+ }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent RHS expression in the final reduction
+ /// expression performed by the reduction clause. Also, variables in these
+ /// expressions are used for proper initialization of reduction copies.
+ void setRHSExprs(ArrayRef<Expr *> RHSExprs);
+
+ /// Get the list of helper destination expressions.
+ MutableArrayRef<Expr *> getRHSExprs() {
+ return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getRHSExprs() const {
+ return llvm::makeArrayRef(getLHSExprs().end(), varlist_size());
+ }
+
+ /// Set list of helper reduction expressions, required for proper
+ /// codegen of the clause. These expressions are binary expressions or
+ /// operator/custom reduction call that calculates new value from source
+ /// helper expressions to destination helper expressions.
+ void setReductionOps(ArrayRef<Expr *> ReductionOps);
+
+ /// Get the list of helper reduction expressions.
+ MutableArrayRef<Expr *> getReductionOps() {
+ return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getReductionOps() const {
+ return llvm::makeArrayRef(getRHSExprs().end(), varlist_size());
+ }
+
+ /// Set list of helper reduction taskgroup descriptors.
+ void setTaskgroupDescriptors(ArrayRef<Expr *> ReductionOps);
+
+ /// Get the list of helper reduction taskgroup descriptors.
+ MutableArrayRef<Expr *> getTaskgroupDescriptors() {
+ return MutableArrayRef<Expr *>(getReductionOps().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getTaskgroupDescriptors() const {
+ return llvm::makeArrayRef(getReductionOps().end(), varlist_size());
+ }
+
+public:
+ /// Creates clause with a list of variables \a VL.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param ColonLoc Location of ':'.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL The variables in the clause.
+ /// \param QualifierLoc The nested-name qualifier with location information
+ /// \param NameInfo The full name info for reduction identifier.
+ /// \param Privates List of helper expressions for proper generation of
+ /// private copies.
+ /// \param LHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// LHSs of the reduction expressions.
+ /// \param RHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// RHSs of the reduction expressions.
+ /// Also, variables in these expressions are used for proper initialization of
+ /// reduction copies.
+ /// \param ReductionOps List of helper expressions that represents reduction
+ /// expressions:
+ /// \code
+ /// LHSExprs binop RHSExprs;
+ /// operator binop(LHSExpr, RHSExpr);
+ /// <CutomReduction>(LHSExpr, RHSExpr);
+ /// \endcode
+ /// Required for proper codegen of final reduction operation performed by the
+ /// reduction clause.
+ /// \param TaskgroupDescriptors List of helper taskgroup descriptors for
+ /// corresponding items in parent taskgroup task_reduction clause.
+ /// \param PreInit Statement that must be executed before entering the OpenMP
+ /// region with this clause.
+ /// \param PostUpdate Expression that must be executed after exit from the
+ /// OpenMP region with this clause.
+ ///
+ static OMPInReductionClause *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ NestedNameSpecifierLoc QualifierLoc,
+ const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates,
+ ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs,
+ ArrayRef<Expr *> ReductionOps, ArrayRef<Expr *> TaskgroupDescriptors,
+ Stmt *PreInit, Expr *PostUpdate);
+
+ /// Creates an empty clause with the place for \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPInReductionClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ /// Gets location of ':' symbol in clause.
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ /// Gets the name info for specified reduction identifier.
+ const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
+ /// Gets the nested name specifier.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+
+ typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
+ typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
+ typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
+ typedef llvm::iterator_range<helper_expr_const_iterator>
+ helper_expr_const_range;
+
+ helper_expr_const_range privates() const {
+ return helper_expr_const_range(getPrivates().begin(), getPrivates().end());
+ }
+ helper_expr_range privates() {
+ return helper_expr_range(getPrivates().begin(), getPrivates().end());
+ }
+ helper_expr_const_range lhs_exprs() const {
+ return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_range lhs_exprs() {
+ return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_const_range rhs_exprs() const {
+ return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_range rhs_exprs() {
+ return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_const_range reduction_ops() const {
+ return helper_expr_const_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+ helper_expr_range reduction_ops() {
+ return helper_expr_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+ helper_expr_const_range taskgroup_descriptors() const {
+ return helper_expr_const_range(getTaskgroupDescriptors().begin(),
+ getTaskgroupDescriptors().end());
+ }
+ helper_expr_range taskgroup_descriptors() {
+ return helper_expr_range(getTaskgroupDescriptors().begin(),
+ getTaskgroupDescriptors().end());
+ }
+
+ child_range children() {
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_in_reduction;
+ }
+};
+
/// \brief This represents clause 'linear' in the '#pragma omp ...'
/// directives.
///
@@ -2697,7 +3141,7 @@ public:
/// In this example directive '#pragma omp target' has clause 'device'
/// with single expression 'a'.
///
-class OMPDeviceClause : public OMPClause {
+class OMPDeviceClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -2717,16 +3161,19 @@ public:
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
///
- OMPDeviceClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc)
- : OMPClause(OMPC_device, StartLoc, EndLoc), LParenLoc(LParenLoc),
- Device(E) {}
+ OMPDeviceClause(Expr *E, Stmt *HelperE, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_device, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), Device(E) {
+ setPreInitStmt(HelperE);
+ }
/// \brief Build an empty clause.
///
OMPDeviceClause()
- : OMPClause(OMPC_device, SourceLocation(), SourceLocation()),
- LParenLoc(SourceLocation()), Device(nullptr) {}
+ : OMPClause(OMPC_device, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
+ Device(nullptr) {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
/// \brief Returns the location of '('.
@@ -3001,7 +3448,7 @@ protected:
// Organize the components by declaration and retrieve the original
// expression. Original expressions are always the first component of the
// mappable component list.
- llvm::DenseMap<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>>
+ llvm::MapVector<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>>
ComponentListMap;
{
auto CI = ComponentLists.begin();
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index 274df220e1..953ecada6c 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -50,7 +50,8 @@ struct PrintingPolicy {
UseVoidForZeroParams(!LO.CPlusPlus),
TerseOutput(false), PolishForDeclaration(false),
Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
- IncludeNewlines(true), MSVCFormatting(false) { }
+ IncludeNewlines(true), MSVCFormatting(false),
+ ConstantsAsWritten(false), SuppressImplicitBase(false) { }
/// \brief Adjust this printing policy for cases where it's known that
/// we're printing C++ code (for instance, if AST dumping reaches a
@@ -200,6 +201,27 @@ struct PrintingPolicy {
/// prints anonymous namespaces as `anonymous namespace' and does not insert
/// spaces after template arguments.
bool MSVCFormatting : 1;
+
+ /// \brief Whether we should print the constant expressions as written in the
+ /// sources.
+ ///
+ /// This flag determines whether constants expressions like
+ ///
+ /// \code
+ /// 0x10
+ /// 2.5e3
+ /// \endcode
+ ///
+ /// will be printed as written or as follows:
+ ///
+ /// \code
+ /// 0x10
+ /// 2.5e3
+ /// \endcode
+ bool ConstantsAsWritten : 1;
+
+ /// \brief When true, don't print the implicit 'self' or 'this' expressions.
+ bool SuppressImplicitBase : 1;
};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 1b5850a05b..7fb5221b7d 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -83,7 +83,7 @@ namespace clang {
return false; \
} while (false)
-/// \brief A class that does preordor or postorder
+/// \brief A class that does preorder or postorder
/// depth-first traversal on the entire Clang AST and visits each node.
///
/// This class performs three distinct tasks:
@@ -267,6 +267,12 @@ public:
bool TraverseTemplateArguments(const TemplateArgument *Args,
unsigned NumArgs);
+ /// \brief Recursively visit a base specifier. This can be overridden by a
+ /// subclass.
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base);
+
/// \brief Recursively visit a constructor initializer. This
/// automatically dispatches to another visitor for the initializer
/// expression, but not for the name of the initializer, so may
@@ -309,6 +315,8 @@ public:
// ---- Methods on Stmts ----
+ Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
+
private:
template<typename T, typename U>
struct has_same_member_pointer_type : std::false_type {};
@@ -491,6 +499,8 @@ public:
bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; }
#include "clang/AST/DeclNodes.inc"
+ bool canIgnoreChildDeclWhileTraversingDeclContext(const Decl *Child);
+
private:
// These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
@@ -593,6 +603,16 @@ bool RecursiveASTVisitor<Derived>::PostVisitStmt(Stmt *S) {
#define STMT(CLASS, PARENT) \
case Stmt::CLASS##Class: \
TRY_TO(WalkUpFrom##CLASS(static_cast<CLASS *>(S))); break;
+#define INITLISTEXPR(CLASS, PARENT) \
+ case Stmt::CLASS##Class: \
+ { \
+ auto ILE = static_cast<CLASS *>(S); \
+ if (auto Syn = ILE->isSemanticForm() ? ILE->getSyntacticForm() : ILE) \
+ TRY_TO(WalkUpFrom##CLASS(Syn)); \
+ if (auto Sem = ILE->isSemanticForm() ? ILE : ILE->getSemanticForm()) \
+ TRY_TO(WalkUpFrom##CLASS(Sem)); \
+ break; \
+ }
#include "clang/AST/StmtNodes.inc"
}
@@ -968,6 +988,11 @@ DEF_TRAVERSE_TYPE(DependentSizedArrayType, {
TRY_TO(TraverseStmt(T->getSizeExpr()));
})
+DEF_TRAVERSE_TYPE(DependentAddressSpaceType, {
+ TRY_TO(TraverseStmt(T->getAddrSpaceExpr()));
+ TRY_TO(TraverseType(T->getPointeeType()));
+})
+
DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, {
if (T->getSizeExpr())
TRY_TO(TraverseStmt(T->getSizeExpr()));
@@ -1021,8 +1046,12 @@ DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
DEF_TRAVERSE_TYPE(RecordType, {})
DEF_TRAVERSE_TYPE(EnumType, {})
DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {})
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {})
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
+ TRY_TO(TraverseType(T->getReplacementType()));
+})
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
+ TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
+})
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
TRY_TO(TraverseTemplateName(T->getTemplateName()));
@@ -1174,6 +1203,11 @@ DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, {
return TraverseArrayTypeLocHelper(TL);
})
+DEF_TRAVERSE_TYPELOC(DependentAddressSpaceType, {
+ TRY_TO(TraverseStmt(TL.getTypePtr()->getAddrSpaceExpr()));
+ TRY_TO(TraverseType(TL.getTypePtr()->getPointeeType()));
+})
+
// FIXME: order? why not size expr first?
// FIXME: base VectorTypeLoc is unfinished
DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, {
@@ -1249,8 +1283,12 @@ DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
DEF_TRAVERSE_TYPELOC(RecordType, {})
DEF_TRAVERSE_TYPELOC(EnumType, {})
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {})
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {})
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
+ TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
+})
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
+ TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
+})
// FIXME: use the loc for the template name?
DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
@@ -1321,14 +1359,20 @@ DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
// than those.
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::canIgnoreChildDeclWhileTraversingDeclContext(
+ const Decl *Child) {
+ // BlockDecls and CapturedDecls are traversed through BlockExprs and
+ // CapturedStmts respectively.
+ return isa<BlockDecl>(Child) || isa<CapturedDecl>(Child);
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) {
if (!DC)
return true;
for (auto *Child : DC->decls()) {
- // BlockDecls and CapturedDecls are traversed through BlockExprs and
- // CapturedStmts respectively.
- if (!isa<BlockDecl>(Child) && !isa<CapturedDecl>(Child))
+ if (!canIgnoreChildDeclWhileTraversingDeclContext(Child))
TRY_TO(TraverseDecl(Child));
}
@@ -1656,8 +1700,8 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
// template declarations.
#define DEF_TRAVERSE_TMPL_DECL(TMPLDECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateDecl, { \
- TRY_TO(TraverseDecl(D->getTemplatedDecl())); \
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
+ TRY_TO(TraverseDecl(D->getTemplatedDecl())); \
\
/* By default, we do not traverse the instantiations of \
class templates since they do not appear in the user code. The \
@@ -1751,12 +1795,19 @@ bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(RecordDecl *D) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseCXXBaseSpecifier(
+ const CXXBaseSpecifier &Base) {
+ TRY_TO(TraverseTypeLoc(Base.getTypeSourceInfo()->getTypeLoc()));
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(CXXRecordDecl *D) {
if (!TraverseRecordHelper(D))
return false;
if (D->isCompleteDefinition()) {
for (const auto &I : D->bases()) {
- TRY_TO(TraverseTypeLoc(I.getTypeSourceInfo()->getTypeLoc()));
+ TRY_TO(TraverseCXXBaseSpecifier(I));
}
// We don't traverse the friends or the conversions, as they are
// already in decls_begin()/decls_end().
@@ -1781,6 +1832,7 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
\
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); \
if (!getDerived().shouldVisitTemplateInstantiations() && \
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \
/* Returning from here skips traversing the \
@@ -2038,7 +2090,7 @@ DEF_TRAVERSE_DECL(ParmVarDecl, {
TRY_TO(WalkUpFrom##STMT(S)); \
{ CODE; } \
if (ShouldVisitChildren) { \
- for (Stmt *SubStmt : S->children()) { \
+ for (Stmt * SubStmt : getDerived().getStmtChildren(S)) { \
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); \
} \
} \
@@ -2212,13 +2264,15 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
// the syntactic and the semantic form.
//
// There is no guarantee about which form \p S takes when this method is called.
-DEF_TRAVERSE_STMT(InitListExpr, {
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
+ InitListExpr *S, DataRecursionQueue *Queue) {
TRY_TO(TraverseSynOrSemInitListExpr(
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
TRY_TO(TraverseSynOrSemInitListExpr(
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
- ShouldVisitChildren = false;
-})
+ return true;
+}
// GenericSelectionExpr is a special case because the types and expressions
// are interleaved. We also need to watch out for null types (default
@@ -2326,7 +2380,7 @@ DEF_TRAVERSE_STMT(LambdaExpr, {
}
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
- FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
+ FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
// Visit the whole type.
@@ -2996,6 +3050,52 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPTaskReductionClause(
+ OMPTaskReductionClause *C) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
+ TRY_TO(VisitOMPClauseList(C));
+ TRY_TO(VisitOMPClauseWithPostUpdate(C));
+ for (auto *E : C->privates()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->lhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->rhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->reduction_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ return true;
+}
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPInReductionClause(
+ OMPInReductionClause *C) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
+ TRY_TO(VisitOMPClauseList(C));
+ TRY_TO(VisitOMPClauseWithPostUpdate(C));
+ for (auto *E : C->privates()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->lhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->rhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->reduction_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->taskgroup_descriptors())
+ TRY_TO(TraverseStmt(E));
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) {
TRY_TO(VisitOMPClauseList(C));
return true;
@@ -3009,6 +3109,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPDeviceClause(OMPDeviceClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getDevice()));
return true;
}
diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h
index cd5f186a20..89a9d3c4cc 100644
--- a/include/clang/AST/Redeclarable.h
+++ b/include/clang/AST/Redeclarable.h
@@ -21,6 +21,60 @@
namespace clang {
class ASTContext;
+// Some notes on redeclarables:
+//
+// - Every redeclarable is on a circular linked list.
+//
+// - Every decl has a pointer to the first element of the chain _and_ a
+// DeclLink that may point to one of 3 possible states:
+// - the "previous" (temporal) element in the chain
+// - the "latest" (temporal) element in the chain
+// - the an "uninitialized-latest" value (when newly-constructed)
+//
+// - The first element is also often called the canonical element. Every
+// element has a pointer to it so that "getCanonical" can be fast.
+//
+// - Most links in the chain point to previous, except the link out of
+// the first; it points to latest.
+//
+// - Elements are called "first", "previous", "latest" or
+// "most-recent" when referring to temporal order: order of addition
+// to the chain.
+//
+// - To make matters confusing, the DeclLink type uses the term "next"
+// for its pointer-storage internally (thus functions like
+// NextIsPrevious). It's easiest to just ignore the implementation of
+// DeclLink when making sense of the redeclaration chain.
+//
+// - There's also a "definition" link for several types of
+// redeclarable, where only one definition should exist at any given
+// time (and the defn pointer is stored in the decl's "data" which
+// is copied to every element on the chain when it's changed).
+//
+// Here is some ASCII art:
+//
+// "first" "latest"
+// "canonical" "most recent"
+// +------------+ first +--------------+
+// | | <--------------------------- | |
+// | | | |
+// | | | |
+// | | +--------------+ | |
+// | | first | | | |
+// | | <---- | | | |
+// | | | | | |
+// | @class A | link | @interface A | link | @class A |
+// | seen first | <---- | seen second | <---- | seen third |
+// | | | | | |
+// +------------+ +--------------+ +--------------+
+// | data | defn | data | defn | data |
+// | | ----> | | <---- | |
+// +------------+ +--------------+ +--------------+
+// | | ^ ^
+// | |defn | |
+// | link +-----+ |
+// +-->-------------------------------------------+
+
/// \brief Provides common interface for the Decls that can be redeclared.
template<typename decl_type>
class Redeclarable {
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index c210bd1cec..795f4d6e71 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -389,8 +389,8 @@ public:
/// back to its original source language syntax.
void dumpPretty(const ASTContext &Context) const;
void printPretty(raw_ostream &OS, PrinterHelper *Helper,
- const PrintingPolicy &Policy,
- unsigned Indentation = 0) const;
+ const PrintingPolicy &Policy, unsigned Indentation = 0,
+ const ASTContext *Context = nullptr) const;
/// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only
/// works on systems with GraphViz (Mac OS X) or dot+gv installed.
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index ac440a9f0c..77f81838e5 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -308,12 +308,16 @@ class CoroutineBodyStmt final
OnFallthrough, ///< Handler for control flow falling off the body.
Allocate, ///< Coroutine frame memory allocation.
Deallocate, ///< Coroutine frame memory deallocation.
- ReturnValue, ///< Return value for thunk function.
+ ReturnValue, ///< Return value for thunk function: p.get_return_object().
+ ResultDecl, ///< Declaration holding the result of get_return_object.
+ ReturnStmt, ///< Return statement for the thunk function.
+ ReturnStmtOnAllocFailure, ///< Return statement if allocation failed.
FirstParamMove ///< First offset for move construction of parameter copies.
};
unsigned NumParams;
friend class ASTStmtReader;
+ friend class ASTReader;
friend TrailingObjects;
Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); }
@@ -331,7 +335,10 @@ public:
Stmt *OnFallthrough = nullptr;
Expr *Allocate = nullptr;
Expr *Deallocate = nullptr;
- Stmt *ReturnValue = nullptr;
+ Expr *ReturnValue = nullptr;
+ Stmt *ResultDecl = nullptr;
+ Stmt *ReturnStmt = nullptr;
+ Stmt *ReturnStmtOnAllocFailure = nullptr;
ArrayRef<Stmt *> ParamMoves;
};
@@ -341,6 +348,12 @@ private:
public:
static CoroutineBodyStmt *Create(const ASTContext &C, CtorArgs const &Args);
+ static CoroutineBodyStmt *Create(const ASTContext &C, EmptyShell,
+ unsigned NumParams);
+
+ bool hasDependentPromiseType() const {
+ return getPromiseDecl()->getType()->isDependentType();
+ }
/// \brief Retrieve the body of the coroutine as written. This will be either
/// a CompoundStmt or a TryStmt.
@@ -375,9 +388,13 @@ public:
Expr *getDeallocate() const {
return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]);
}
-
Expr *getReturnValueInit() const {
- return cast_or_null<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
+ return cast<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
+ }
+ Stmt *getResultDecl() const { return getStoredStmts()[SubStmt::ResultDecl]; }
+ Stmt *getReturnStmt() const { return getStoredStmts()[SubStmt::ReturnStmt]; }
+ Stmt *getReturnStmtOnAllocFailure() const {
+ return getStoredStmts()[SubStmt::ReturnStmtOnAllocFailure];
}
ArrayRef<Stmt const *> getParamMoves() const {
return {getStoredStmts() + SubStmt::FirstParamMove, NumParams};
@@ -430,6 +447,8 @@ public:
SubStmts[SubStmt::PromiseCall] = PromiseCall;
}
+ CoreturnStmt(EmptyShell) : CoreturnStmt({}, {}, {}) {}
+
SourceLocation getKeywordLoc() const { return CoreturnLoc; }
/// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr
diff --git a/include/clang/AST/StmtDataCollectors.td b/include/clang/AST/StmtDataCollectors.td
new file mode 100644
index 0000000000..bf5f8c2170
--- /dev/null
+++ b/include/clang/AST/StmtDataCollectors.td
@@ -0,0 +1,242 @@
+class Stmt {
+ code Code = [{
+ addData(S->getStmtClass());
+ // This ensures that non-macro-generated code isn't identical to
+ // macro-generated code.
+ addData(data_collection::getMacroStack(S->getLocStart(), Context));
+ addData(data_collection::getMacroStack(S->getLocEnd(), Context));
+ }];
+}
+
+class Expr {
+ code Code = [{
+ addData(S->getType());
+ }];
+}
+
+//--- Builtin functionality ----------------------------------------------//
+class ArrayTypeTraitExpr {
+ code Code = [{
+ addData(S->getTrait());
+ }];
+}
+class ExpressionTraitExpr {
+ code Code = [{
+ addData(S->getTrait());
+ }];
+}
+class PredefinedExpr {
+ code Code = [{
+ addData(S->getIdentType());
+ }];
+}
+class TypeTraitExpr {
+ code Code = [{
+ addData(S->getTrait());
+ for (unsigned i = 0; i < S->getNumArgs(); ++i)
+ addData(S->getArg(i)->getType());
+ }];
+}
+
+//--- Calls --------------------------------------------------------------//
+class CallExpr {
+ code Code = [{
+ // Function pointers don't have a callee and we just skip hashing it.
+ if (const FunctionDecl *D = S->getDirectCallee()) {
+ // If the function is a template specialization, we also need to handle
+ // the template arguments as they are not included in the qualified name.
+ if (auto Args = D->getTemplateSpecializationArgs()) {
+ std::string ArgString;
+
+ // Print all template arguments into ArgString
+ llvm::raw_string_ostream OS(ArgString);
+ for (unsigned i = 0; i < Args->size(); ++i) {
+ Args->get(i).print(Context.getLangOpts(), OS);
+ // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
+ OS << '\n';
+ }
+ OS.flush();
+
+ addData(ArgString);
+ }
+ addData(D->getQualifiedNameAsString());
+ }
+ }];
+}
+
+//--- Value references ---------------------------------------------------//
+class DeclRefExpr {
+ code Code = [{
+ addData(S->getDecl()->getQualifiedNameAsString());
+ }];
+}
+class MemberExpr {
+ code Code = [{
+ addData(S->getMemberDecl()->getName());
+ }];
+}
+
+//--- Literals -----------------------------------------------------------//
+class IntegerLiteral {
+ code Code = [{
+ addData(llvm::hash_value(S->getValue()));
+ }];
+}
+class FloatingLiteral {
+ code Code = [{
+ addData(llvm::hash_value(S->getValue()));
+ }];
+}
+class StringLiteral {
+ code Code = [{
+ addData(S->getString());
+}];
+}
+class CXXBoolLiteralExpr {
+ code Code = [{
+ addData(S->getValue());
+ }];
+}
+class CharacterLiteral {
+ code Code = [{
+ addData(S->getValue());
+ }];
+}
+
+//--- Exceptions ---------------------------------------------------------//
+class CXXCatchStmt {
+ code Code = [{
+ addData(S->getCaughtType());
+ }];
+}
+
+//--- C++ OOP Stmts ------------------------------------------------------//
+class CXXDeleteExpr {
+ code Code = [{
+ addData(S->isArrayFormAsWritten()); addData(S->isGlobalDelete());
+ }];
+}
+
+//--- Casts --------------------------------------------------------------//
+class ObjCBridgedCastExpr {
+ code Code = [{
+ addData(S->getBridgeKind());
+ }];
+}
+
+//--- Miscellaneous Exprs ------------------------------------------------//
+class BinaryOperator {
+ code Code = [{
+ addData(S->getOpcode());
+ }];
+}
+class UnaryOperator {
+ code Code = [{
+ addData(S->getOpcode());
+ }];
+}
+
+//--- Control flow -------------------------------------------------------//
+class GotoStmt {
+ code Code = [{
+ addData(S->getLabel()->getName());
+ }];
+}
+class IndirectGotoStmt {
+ code Code = [{
+ if (S->getConstantTarget())
+ addData(S->getConstantTarget()->getName());
+ }];
+}
+class LabelStmt {
+ code Code = [{
+ addData(S->getDecl()->getName());
+ }];
+}
+class MSDependentExistsStmt {
+ code Code = [{
+ addData(S->isIfExists());
+ }];
+}
+class AddrLabelExpr {
+ code Code = [{
+ addData(S->getLabel()->getName());
+ }];
+}
+
+//--- Objective-C --------------------------------------------------------//
+class ObjCIndirectCopyRestoreExpr {
+ code Code = [{
+ addData(S->shouldCopy());
+ }];
+}
+class ObjCPropertyRefExpr {
+ code Code = [{
+ addData(S->isSuperReceiver()); addData(S->isImplicitProperty());
+ }];
+}
+class ObjCAtCatchStmt {
+ code Code = [{
+ addData(S->hasEllipsis());
+ }];
+}
+
+//--- Miscellaneous Stmts ------------------------------------------------//
+class CXXFoldExpr {
+ code Code = [{
+ addData(S->isRightFold()); addData(S->getOperator());
+ }];
+}
+class GenericSelectionExpr {
+ code Code = [{
+ for (unsigned i = 0; i < S->getNumAssocs(); ++i) {
+ addData(S->getAssocType(i));
+ }
+ }];
+}
+class LambdaExpr {
+ code Code = [{
+ for (const LambdaCapture &C : S->captures()) {
+ addData(C.isPackExpansion());
+ addData(C.getCaptureKind());
+ if (C.capturesVariable())
+ addData(C.getCapturedVar()->getType());
+ }
+ addData(S->isGenericLambda());
+ addData(S->isMutable());
+ }];
+}
+class DeclStmt {
+ code Code = [{
+ auto numDecls = std::distance(S->decl_begin(), S->decl_end());
+ addData(static_cast<unsigned>(numDecls));
+ for (const Decl *D : S->decls()) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ addData(VD->getType());
+ }
+ }
+ }];
+}
+class AsmStmt {
+ code Code = [{
+ addData(S->isSimple());
+ addData(S->isVolatile());
+ addData(S->generateAsmString(Context));
+ for (unsigned i = 0; i < S->getNumInputs(); ++i) {
+ addData(S->getInputConstraint(i));
+ }
+ for (unsigned i = 0; i < S->getNumOutputs(); ++i) {
+ addData(S->getOutputConstraint(i));
+ }
+ for (unsigned i = 0; i < S->getNumClobbers(); ++i) {
+ addData(S->getClobber(i));
+ }
+ }];
+}
+class AttributedStmt {
+ code Code = [{
+ for (const Attr *A : S->getAttrs()) {
+ addData(std::string(A->getSpelling()));
+ }
+ }];
+}
diff --git a/include/clang/AST/StmtIterator.h b/include/clang/AST/StmtIterator.h
index 81f8ad4344..5d3bce8d83 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 13af142ca3..5ad118ca40 100644
--- a/include/clang/AST/StmtOpenMP.h
+++ b/include/clang/AST/StmtOpenMP.h
@@ -318,8 +318,9 @@ class OMPLoopDirective : public OMPExecutableDirective {
/// \brief Offsets to the stored exprs.
/// This enumeration contains offsets to all the pointers to children
/// expressions stored in OMPLoopDirective.
- /// The first 9 children are nesessary for all the loop directives, and
- /// the next 10 are specific to the worksharing ones.
+ /// The first 9 children are necessary for all the loop directives,
+ /// the next 8 are specific to the worksharing ones, and the next 11 are
+ /// used for combined constructs containing two pragmas associated to loops.
/// After the fixed children, three arrays of length CollapsedNum are
/// allocated: loop counters, their updates and final values.
/// PrevLowerBound and PrevUpperBound are used to communicate blocking
@@ -344,7 +345,7 @@ class OMPLoopDirective : public OMPExecutableDirective {
// specify the offset to the end (and start of the following counters/
// updates/finals arrays).
DefaultEnd = 9,
- // The following 12 exprs are used by worksharing and distribute loops only.
+ // The following 8 exprs are used by worksharing and distribute loops only.
IsLastIterVariableOffset = 9,
LowerBoundVariableOffset = 10,
UpperBoundVariableOffset = 11,
@@ -353,13 +354,22 @@ class OMPLoopDirective : public OMPExecutableDirective {
NextLowerBoundOffset = 14,
NextUpperBoundOffset = 15,
NumIterationsOffset = 16,
+ // Offset to the end for worksharing loop directives.
+ WorksharingEnd = 17,
PrevLowerBoundVariableOffset = 17,
PrevUpperBoundVariableOffset = 18,
DistIncOffset = 19,
PrevEnsureUpperBoundOffset = 20,
+ CombinedLowerBoundVariableOffset = 21,
+ CombinedUpperBoundVariableOffset = 22,
+ CombinedEnsureUpperBoundOffset = 23,
+ CombinedInitOffset = 24,
+ CombinedConditionOffset = 25,
+ CombinedNextLowerBoundOffset = 26,
+ CombinedNextUpperBoundOffset = 27,
// Offset to the end (and start of the following counters/updates/finals
- // arrays) for worksharing loop directives.
- WorksharingEnd = 21,
+ // arrays) for combined distribute loop directives.
+ CombinedDistributeEnd = 28,
};
/// \brief Get the counters storage.
@@ -423,11 +433,12 @@ protected:
/// \brief Offset to the start of children expression arrays.
static unsigned getArraysOffset(OpenMPDirectiveKind Kind) {
- return (isOpenMPWorksharingDirective(Kind) ||
- isOpenMPTaskLoopDirective(Kind) ||
- isOpenMPDistributeDirective(Kind))
- ? WorksharingEnd
- : DefaultEnd;
+ if (isOpenMPLoopBoundSharingDirective(Kind))
+ return CombinedDistributeEnd;
+ if (isOpenMPWorksharingDirective(Kind) || isOpenMPTaskLoopDirective(Kind) ||
+ isOpenMPDistributeDirective(Kind))
+ return WorksharingEnd;
+ return DefaultEnd;
}
/// \brief Children number.
@@ -515,33 +526,60 @@ protected:
*std::next(child_begin(), NumIterationsOffset) = NI;
}
void setPrevLowerBoundVariable(Expr *PrevLB) {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
*std::next(child_begin(), PrevLowerBoundVariableOffset) = PrevLB;
}
void setPrevUpperBoundVariable(Expr *PrevUB) {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
*std::next(child_begin(), PrevUpperBoundVariableOffset) = PrevUB;
}
void setDistInc(Expr *DistInc) {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
*std::next(child_begin(), DistIncOffset) = DistInc;
}
void setPrevEnsureUpperBound(Expr *PrevEUB) {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
*std::next(child_begin(), PrevEnsureUpperBoundOffset) = PrevEUB;
}
+ void setCombinedLowerBoundVariable(Expr *CombLB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedLowerBoundVariableOffset) = CombLB;
+ }
+ void setCombinedUpperBoundVariable(Expr *CombUB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedUpperBoundVariableOffset) = CombUB;
+ }
+ void setCombinedEnsureUpperBound(Expr *CombEUB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedEnsureUpperBoundOffset) = CombEUB;
+ }
+ void setCombinedInit(Expr *CombInit) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedInitOffset) = CombInit;
+ }
+ void setCombinedCond(Expr *CombCond) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedConditionOffset) = CombCond;
+ }
+ void setCombinedNextLowerBound(Expr *CombNLB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedNextLowerBoundOffset) = CombNLB;
+ }
+ void setCombinedNextUpperBound(Expr *CombNUB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB;
+ }
void setCounters(ArrayRef<Expr *> A);
void setPrivateCounters(ArrayRef<Expr *> A);
void setInits(ArrayRef<Expr *> A);
@@ -549,6 +587,33 @@ protected:
void setFinals(ArrayRef<Expr *> A);
public:
+ /// The expressions built to support OpenMP loops in combined/composite
+ /// pragmas (e.g. pragma omp distribute parallel for)
+ struct DistCombinedHelperExprs {
+ /// DistributeLowerBound - used when composing 'omp distribute' with
+ /// 'omp for' in a same construct.
+ Expr *LB;
+ /// DistributeUpperBound - used when composing 'omp distribute' with
+ /// 'omp for' in a same construct.
+ Expr *UB;
+ /// DistributeEnsureUpperBound - used when composing 'omp distribute'
+ /// with 'omp for' in a same construct, EUB depends on DistUB
+ Expr *EUB;
+ /// Distribute loop iteration variable init used when composing 'omp
+ /// distribute'
+ /// with 'omp for' in a same construct
+ Expr *Init;
+ /// Distribute Loop condition used when composing 'omp distribute'
+ /// with 'omp for' in a same construct
+ Expr *Cond;
+ /// Update of LowerBound for statically sheduled omp loops for
+ /// outer loop in combined constructs (e.g. 'distribute parallel for')
+ Expr *NLB;
+ /// Update of UpperBound for statically sheduled omp loops for
+ /// outer loop in combined constructs (e.g. 'distribute parallel for')
+ Expr *NUB;
+ };
+
/// \brief The expressions built for the OpenMP loop CodeGen for the
/// whole collapsed loop nest.
struct HelperExprs {
@@ -611,6 +676,9 @@ public:
/// Init statement for all captured expressions.
Stmt *PreInits;
+ /// Expressions used when combining OpenMP loop pragmas
+ DistCombinedHelperExprs DistCombinedFields;
+
/// \brief Check if all the expressions are built (does not check the
/// worksharing ones).
bool builtAll() {
@@ -654,6 +722,13 @@ public:
Finals[i] = nullptr;
}
PreInits = nullptr;
+ DistCombinedFields.LB = nullptr;
+ DistCombinedFields.UB = nullptr;
+ DistCombinedFields.EUB = nullptr;
+ DistCombinedFields.Init = nullptr;
+ DistCombinedFields.Cond = nullptr;
+ DistCombinedFields.NLB = nullptr;
+ DistCombinedFields.NUB = nullptr;
}
};
@@ -757,37 +832,71 @@ public:
*std::next(child_begin(), NumIterationsOffset)));
}
Expr *getPrevLowerBoundVariable() const {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), PrevLowerBoundVariableOffset)));
}
Expr *getPrevUpperBoundVariable() const {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), PrevUpperBoundVariableOffset)));
}
Expr *getDistInc() const {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), DistIncOffset)));
}
Expr *getPrevEnsureUpperBound() const {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), PrevEnsureUpperBoundOffset)));
}
+ Expr *getCombinedLowerBoundVariable() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedLowerBoundVariableOffset)));
+ }
+ Expr *getCombinedUpperBoundVariable() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedUpperBoundVariableOffset)));
+ }
+ Expr *getCombinedEnsureUpperBound() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedEnsureUpperBoundOffset)));
+ }
+ Expr *getCombinedInit() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedInitOffset)));
+ }
+ Expr *getCombinedCond() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedConditionOffset)));
+ }
+ Expr *getCombinedNextLowerBound() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedNextLowerBoundOffset)));
+ }
+ Expr *getCombinedNextUpperBound() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedNextUpperBoundOffset)));
+ }
const Stmt *getBody() const {
// This relies on the loop form is already checked by Sema.
Stmt *Body = getAssociatedStmt()->IgnoreContainers(true);
@@ -1786,7 +1895,7 @@ public:
}
};
-/// \brief This represents '#pragma omp taskgroup' directive.
+/// This represents '#pragma omp taskgroup' directive.
///
/// \code
/// #pragma omp taskgroup
@@ -1794,39 +1903,61 @@ public:
///
class OMPTaskgroupDirective : public OMPExecutableDirective {
friend class ASTStmtReader;
- /// \brief Build directive with the given start and end location.
+ /// Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending location of the directive.
+ /// \param NumClauses Number of clauses.
///
- OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+ OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned NumClauses)
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
- StartLoc, EndLoc, 0, 1) {}
+ StartLoc, EndLoc, NumClauses, 2) {}
- /// \brief Build an empty directive.
+ /// Build an empty directive.
+ /// \param NumClauses Number of clauses.
///
- explicit OMPTaskgroupDirective()
+ explicit OMPTaskgroupDirective(unsigned NumClauses)
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
- SourceLocation(), SourceLocation(), 0, 1) {}
+ SourceLocation(), SourceLocation(), NumClauses,
+ 2) {}
+
+ /// Sets the task_reduction return variable.
+ void setReductionRef(Expr *RR) {
+ *std::next(child_begin(), 1) = RR;
+ }
public:
- /// \brief Creates directive.
+ /// Creates directive.
///
/// \param C AST context.
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending Location of the directive.
+ /// \param Clauses List of clauses.
/// \param AssociatedStmt Statement, associated with the directive.
+ /// \param ReductionRef Reference to the task_reduction return variable.
///
- static OMPTaskgroupDirective *Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation EndLoc,
- Stmt *AssociatedStmt);
+ static OMPTaskgroupDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ Expr *ReductionRef);
- /// \brief Creates an empty directive.
+ /// Creates an empty directive.
///
/// \param C AST context.
+ /// \param NumClauses Number of clauses.
///
- static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, EmptyShell);
+ static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
+
+
+ /// Returns reference to the task_reduction return variable.
+ const Expr *getReductionRef() const {
+ return static_cast<const Expr *>(*std::next(child_begin(), 1));
+ }
+ Expr *getReductionRef() {
+ return static_cast<Expr *>(*std::next(child_begin(), 1));
+ }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTaskgroupDirectiveClass;
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index df4a2d8bc3..470788e8bb 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -29,15 +29,17 @@ template <typename T> struct make_const_ptr { typedef const T *type; };
/// StmtVisitorBase - This class implements a simple visitor for Stmt
/// subclasses. Since Expr derives from Stmt, this also includes support for
/// visiting Exprs.
-template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
+template<template <typename> class Ptr, typename ImplClass, typename RetTy=void,
+ class... ParamTys>
class StmtVisitorBase {
public:
#define PTR(CLASS) typename Ptr<CLASS>::type
#define DISPATCH(NAME, CLASS) \
- return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<PTR(CLASS)>(S))
+ return static_cast<ImplClass*>(this)->Visit ## NAME( \
+ static_cast<PTR(CLASS)>(S), std::forward<ParamTys>(P)...)
- RetTy Visit(PTR(Stmt) S) {
+ RetTy Visit(PTR(Stmt) S, ParamTys... P) {
// If we have a binary expr, dispatch to the subcode of the binop. A smart
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
@@ -111,13 +113,13 @@ public:
// If the implementation chooses not to implement a certain visit method, fall
// back on VisitExpr or whatever else is the superclass.
#define STMT(CLASS, PARENT) \
- RetTy Visit ## CLASS(PTR(CLASS) S) { DISPATCH(PARENT, PARENT); }
+ RetTy Visit ## CLASS(PTR(CLASS) S, ParamTys... P) { DISPATCH(PARENT, PARENT); }
#include "clang/AST/StmtNodes.inc"
// If the implementation doesn't implement binary operator methods, fall back
// on VisitBinaryOperator.
#define BINOP_FALLBACK(NAME) \
- RetTy VisitBin ## NAME(PTR(BinaryOperator) S) { \
+ RetTy VisitBin ## NAME(PTR(BinaryOperator) S, ParamTys... P) { \
DISPATCH(BinaryOperator, BinaryOperator); \
}
BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI)
@@ -137,7 +139,7 @@ public:
// If the implementation doesn't implement compound assignment operator
// methods, fall back on VisitCompoundAssignOperator.
#define CAO_FALLBACK(NAME) \
- RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S) { \
+ RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S, ParamTys... P) { \
DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \
}
CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
@@ -149,7 +151,7 @@ public:
// If the implementation doesn't implement unary operator methods, fall back
// on VisitUnaryOperator.
#define UNARYOP_FALLBACK(NAME) \
- RetTy VisitUnary ## NAME(PTR(UnaryOperator) S) { \
+ RetTy VisitUnary ## NAME(PTR(UnaryOperator) S, ParamTys... P) { \
DISPATCH(UnaryOperator, UnaryOperator); \
}
UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
@@ -163,7 +165,7 @@ public:
#undef UNARYOP_FALLBACK
// Base case, ignore it. :)
- RetTy VisitStmt(PTR(Stmt) Node) { return RetTy(); }
+ RetTy VisitStmt(PTR(Stmt) Node, ParamTys... P) { return RetTy(); }
#undef PTR
#undef DISPATCH
@@ -174,18 +176,18 @@ public:
///
/// This class does not preserve constness of Stmt pointers (see also
/// ConstStmtVisitor).
-template<typename ImplClass, typename RetTy=void>
+template<typename ImplClass, typename RetTy=void, typename... ParamTys>
class StmtVisitor
- : public StmtVisitorBase<make_ptr, ImplClass, RetTy> {};
+ : public StmtVisitorBase<make_ptr, ImplClass, RetTy, ParamTys...> {};
/// ConstStmtVisitor - This class implements a simple visitor for Stmt
/// subclasses. Since Expr derives from Stmt, this also includes support for
/// visiting Exprs.
///
/// This class preserves constness of Stmt pointers (see also StmtVisitor).
-template<typename ImplClass, typename RetTy=void>
+template<typename ImplClass, typename RetTy=void, typename... ParamTys>
class ConstStmtVisitor
- : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy> {};
+ : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy, ParamTys...> {};
/// \brief This class implements a simple visitor for OMPClause
/// subclasses.
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index bf4d008ee8..45a610e638 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -262,6 +262,11 @@ public:
TemplateName getUnderlying() const;
+ /// Get the template name to substitute when this template name is used as a
+ /// template template argument. This refers to the most recent declaration of
+ /// the template, including any default template arguments.
+ TemplateName getNameToSubstitute() const;
+
/// \brief Determines whether this is a dependent template name.
bool isDependent() const;
@@ -515,8 +520,7 @@ namespace llvm {
/// \brief The clang::TemplateName class is effectively a pointer.
template<>
-class PointerLikeTypeTraits<clang::TemplateName> {
-public:
+struct PointerLikeTypeTraits<clang::TemplateName> {
static inline void *getAsVoidPointer(clang::TemplateName TN) {
return TN.getAsVoidPointer();
}
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 9c1d110067..e1956473ac 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -48,10 +48,9 @@ namespace clang {
namespace llvm {
template <typename T>
- class PointerLikeTypeTraits;
+ struct PointerLikeTypeTraits;
template<>
- class PointerLikeTypeTraits< ::clang::Type*> {
- public:
+ struct PointerLikeTypeTraits< ::clang::Type*> {
static inline void *getAsVoidPointer(::clang::Type *P) { return P; }
static inline ::clang::Type *getFromVoidPointer(void *P) {
return static_cast< ::clang::Type*>(P);
@@ -59,8 +58,7 @@ namespace llvm {
enum { NumLowBitsAvailable = clang::TypeAlignmentInBits };
};
template<>
- class PointerLikeTypeTraits< ::clang::ExtQuals*> {
- public:
+ struct PointerLikeTypeTraits< ::clang::ExtQuals*> {
static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; }
static inline ::clang::ExtQuals *getFromVoidPointer(void *P) {
return static_cast< ::clang::ExtQuals*>(P);
@@ -164,8 +162,6 @@ public:
FastMask = (1 << FastWidth) - 1
};
- Qualifiers() : Mask(0) {}
-
/// Returns the common set of qualifiers while removing them from
/// the given sets.
static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) {
@@ -332,15 +328,34 @@ public:
}
bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
- unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
- void setAddressSpace(unsigned space) {
- assert(space <= MaxAddressSpace);
+ LangAS getAddressSpace() const {
+ return static_cast<LangAS>(Mask >> AddressSpaceShift);
+ }
+ bool hasTargetSpecificAddressSpace() const {
+ return isTargetAddressSpace(getAddressSpace());
+ }
+ /// 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 == LangAS::Default || hasTargetSpecificAddressSpace());
+ if (Addr != LangAS::Default)
+ return toTargetAddressSpace(Addr);
+ // 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(LangAS space) {
+ assert((unsigned)space <= MaxAddressSpace);
Mask = (Mask & ~AddressSpaceMask)
| (((uint32_t) space) << AddressSpaceShift);
}
- void removeAddressSpace() { setAddressSpace(0); }
- void addAddressSpace(unsigned space) {
- assert(space);
+ void removeAddressSpace() { setAddressSpace(LangAS::Default); }
+ void addAddressSpace(LangAS space) {
+ assert(space != LangAS::Default);
setAddressSpace(space);
}
@@ -524,7 +539,7 @@ private:
// bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31|
// |C R V|U|GCAttr|Lifetime|AddressSpace|
- uint32_t Mask;
+ uint32_t Mask = 0;
static const uint32_t UMask = 0x8;
static const uint32_t UShift = 3;
@@ -619,7 +634,7 @@ class QualType {
friend class QualifierCollector;
public:
- QualType() {}
+ QualType() = default;
QualType(const Type *Ptr, unsigned Quals)
: Value(Ptr, Quals) {}
@@ -755,6 +770,10 @@ public:
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
bool isTriviallyCopyableType(const ASTContext &Context) const;
+ /// Return true if this has unique object representations according to (C++17
+ /// [meta.unary.prop]p9)
+ bool hasUniqueObjectRepresentations(const ASTContext &Context) const;
+
// Don't promise in the API that anything besides 'const' can be
// easily added.
@@ -992,7 +1011,7 @@ public:
}
/// Return the address space of this type.
- inline unsigned getAddressSpace() const;
+ inline LangAS getAddressSpace() const;
/// Returns gc attribute of this type.
inline Qualifiers::GC getObjCGCAttr() const;
@@ -1020,6 +1039,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,
@@ -1096,6 +1118,8 @@ public:
QualType getAtomicUnqualifiedType() const;
private:
+ bool unionHasUniqueObjectRepresentations(const ASTContext& Context) const;
+ bool structHasUniqueObjectRepresentations(const ASTContext& Context) const;
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
// caller.
@@ -1123,8 +1147,7 @@ template<> struct simplify_type< ::clang::QualType> {
// Teach SmallPtrSet that QualType is "basically a pointer".
template<>
-class PointerLikeTypeTraits<clang::QualType> {
-public:
+struct PointerLikeTypeTraits<clang::QualType> {
static inline void *getAsVoidPointer(clang::QualType P) {
return P.getAsOpaquePtr();
}
@@ -1215,7 +1238,7 @@ public:
}
bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
- unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
+ LangAS getAddressSpace() const { return Quals.getAddressSpace(); }
const Type *getBaseType() const { return BaseType; }
@@ -1379,7 +1402,7 @@ protected:
/// Extra information which affects how the function is called, like
/// regparm and the calling convention.
- unsigned ExtInfo : 10;
+ unsigned ExtInfo : 11;
/// Used only by FunctionProtoType, put here to pack with the
/// other bitfields.
@@ -1688,6 +1711,7 @@ public:
bool isComplexIntegerType() const; // GCC _Complex integer type.
bool isVectorType() const; // GCC vector type.
bool isExtVectorType() const; // Extended vector type.
+ bool isDependentAddressSpaceType() const; // value-dependent address space qualifier
bool isObjCObjectPointerType() const; // pointer to ObjC object
bool isObjCRetainableType() const; // ObjC object or block pointer
bool isObjCLifetimeType() const; // (array of)* retainable type
@@ -1732,6 +1756,7 @@ public:
bool isTemplateTypeParmType() const; // C++ template type parameter
bool isNullPtrType() const; // C++11 std::nullptr_t
bool isAlignValT() const; // C++17 std::align_val_t
+ bool isStdByteType() const; // C++17 std::byte
bool isAtomicType() const; // C11 _Atomic()
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
@@ -1991,10 +2016,11 @@ public:
Optional<NullabilityKind> getNullability(const ASTContext &context) const;
/// Determine whether the given type can have a nullability
- /// specifier applied to it, i.e., if it is any kind of pointer type
- /// or a dependent type that could instantiate to any kind of
- /// pointer type.
- bool canHaveNullability() const;
+ /// specifier applied to it, i.e., if it is any kind of pointer type.
+ ///
+ /// \param ResultIfUnknown The value to return if we don't yet know whether
+ /// this type can have nullability because it is dependent.
+ bool canHaveNullability(bool ResultIfUnknown = true) const;
/// Retrieve the set of substitutions required when accessing a member
/// of the Objective-C receiver type that is declared in the given context.
@@ -2076,7 +2102,7 @@ public:
: Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
/*InstantiationDependent=*/(K == Dependent),
/*VariablyModified=*/false,
- /*Unexpanded paramter pack=*/false) {
+ /*Unexpanded parameter pack=*/false) {
BuiltinTypeBits.Kind = K;
}
@@ -2724,6 +2750,49 @@ public:
unsigned TypeQuals, Expr *E);
};
+/// Represents an extended address space qualifier where the input address space
+/// value is dependent. Non-dependent address spaces are not represented with a
+/// special Type subclass; they are stored on an ExtQuals node as part of a QualType.
+///
+/// For example:
+/// \code
+/// template<typename T, int AddrSpace>
+/// class AddressSpace {
+/// typedef T __attribute__((address_space(AddrSpace))) type;
+/// }
+/// \endcode
+class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode {
+ const ASTContext &Context;
+ Expr *AddrSpaceExpr;
+ QualType PointeeType;
+ SourceLocation loc;
+
+ DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType,
+ QualType can, Expr *AddrSpaceExpr,
+ SourceLocation loc);
+
+ friend class ASTContext;
+
+public:
+ Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; }
+ QualType getPointeeType() const { return PointeeType; }
+ SourceLocation getAttributeLoc() const { return loc; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentAddressSpace;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Context, getPointeeType(), getAddrSpaceExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType PointeeType, Expr *AddrSpaceExpr);
+};
+
/// Represents an extended vector type where either the type or size is
/// dependent.
///
@@ -2924,19 +2993,23 @@ class FunctionType : public Type {
// * AST read and write
// * Codegen
class ExtInfo {
- // Feel free to rearrange or add bits, but if you go over 10,
+ // Feel free to rearrange or add bits, but if you go over 11,
// you'll need to adjust both the Bits field below and
// Type::FunctionTypeBitfields.
- // | CC |noreturn|produces|regparm|
- // |0 .. 4| 5 | 6 | 7 .. 9|
+ // | CC |noreturn|produces|nocallersavedregs|regparm|
+ // |0 .. 4| 5 | 6 | 7 |8 .. 10|
//
// regparm is either 0 (no regparm attribute) or the regparm value+1.
enum { CallConvMask = 0x1F };
enum { NoReturnMask = 0x20 };
enum { ProducesResultMask = 0x40 };
- enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
- RegParmOffset = 7 }; // Assumed to be the last field
+ enum { NoCallerSavedRegsMask = 0x80 };
+ enum {
+ RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask |
+ NoCallerSavedRegsMask),
+ RegParmOffset = 8
+ }; // Assumed to be the last field
uint16_t Bits;
@@ -2947,13 +3020,13 @@ class FunctionType : public Type {
public:
// Constructor with no defaults. Use this when you know that you
// have all the elements (when reading an AST file for example).
- ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
- bool producesResult) {
- assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
- Bits = ((unsigned) cc) |
- (noReturn ? NoReturnMask : 0) |
- (producesResult ? ProducesResultMask : 0) |
- (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0);
+ ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
+ bool producesResult, bool noCallerSavedRegs) {
+ assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
+ Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) |
+ (producesResult ? ProducesResultMask : 0) |
+ (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) |
+ (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0);
}
// Constructor with all defaults. Use when for example creating a
@@ -2966,6 +3039,7 @@ class FunctionType : public Type {
bool getNoReturn() const { return Bits & NoReturnMask; }
bool getProducesResult() const { return Bits & ProducesResultMask; }
+ bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; }
bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; }
unsigned getRegParm() const {
unsigned RegParm = Bits >> RegParmOffset;
@@ -2999,6 +3073,13 @@ class FunctionType : public Type {
return ExtInfo(Bits & ~ProducesResultMask);
}
+ ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const {
+ if (noCallerSavedRegs)
+ return ExtInfo(Bits | NoCallerSavedRegsMask);
+ else
+ return ExtInfo(Bits & ~NoCallerSavedRegsMask);
+ }
+
ExtInfo withRegParm(unsigned RegParm) const {
assert(RegParm < 7 && "Invalid regparm value");
return ExtInfo((Bits & ~RegParmMask) |
@@ -3118,6 +3199,7 @@ public:
ABIMask = 0x0F,
IsConsumed = 0x10,
HasPassObjSize = 0x20,
+ IsNoEscape = 0x40,
};
unsigned char Data;
@@ -3158,6 +3240,19 @@ public:
return Copy;
}
+ bool isNoEscape() const {
+ return Data & IsNoEscape;
+ }
+
+ ExtParameterInfo withIsNoEscape(bool NoEscape) const {
+ ExtParameterInfo Copy = *this;
+ if (NoEscape)
+ Copy.Data |= IsNoEscape;
+ else
+ Copy.Data &= ~IsNoEscape;
+ return Copy;
+ }
+
unsigned char getOpaqueValue() const { return Data; }
static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
ExtParameterInfo result;
@@ -3760,10 +3855,9 @@ public:
return reinterpret_cast<RecordDecl*>(TagType::getDecl());
}
- // FIXME: This predicate is a helper to QualType/Type. It needs to
- // recursively check all fields for const-ness. If any field is declared
- // const, it needs to return false.
- bool hasConstFields() const { return false; }
+ /// Recursively check all fields in the record for const-ness. If any field
+ /// is declared const, return true. Otherwise, return false.
+ bool hasConstFields() const;
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -3845,6 +3939,7 @@ public:
attr_sptr,
attr_uptr,
attr_nonnull,
+ attr_ns_returns_retained,
attr_nullable,
attr_null_unspecified,
attr_objc_kindof,
@@ -5567,7 +5662,7 @@ inline void QualType::removeLocalCVRQualifiers(unsigned Mask) {
}
/// Return the address space of this type.
-inline unsigned QualType::getAddressSpace() const {
+inline LangAS QualType::getAddressSpace() const {
return getQualifiers().getAddressSpace();
}
@@ -5746,6 +5841,9 @@ inline bool Type::isVectorType() const {
inline bool Type::isExtVectorType() const {
return isa<ExtVectorType>(CanonicalType);
}
+inline bool Type::isDependentAddressSpaceType() const {
+ return isa<DependentAddressSpaceType>(CanonicalType);
+}
inline bool Type::isObjCObjectPointerType() const {
return isa<ObjCObjectPointerType>(CanonicalType);
}
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 525f848a9f..283c421425 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1544,7 +1544,11 @@ class DependentSizedArrayTypeLoc :
public InheritingConcreteTypeLoc<ArrayTypeLoc,
DependentSizedArrayTypeLoc,
DependentSizedArrayType> {
-
+public:
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ ArrayTypeLoc::initializeLocal(Context, Loc);
+ setSizeExpr(getTypePtr()->getSizeExpr());
+ }
};
class VariableArrayTypeLoc :
@@ -1660,6 +1664,76 @@ private:
}
};
+struct DependentAddressSpaceLocInfo {
+ Expr *ExprOperand;
+ SourceRange OperandParens;
+ SourceLocation AttrLoc;
+};
+
+class DependentAddressSpaceTypeLoc
+ : public ConcreteTypeLoc<UnqualTypeLoc,
+ DependentAddressSpaceTypeLoc,
+ DependentAddressSpaceType,
+ DependentAddressSpaceLocInfo> {
+
+ public:
+
+ /// The location of the attribute name, i.e.
+ /// int * __attribute__((address_space(11)))
+ /// ^~~~~~~~~~~~~
+ SourceLocation getAttrNameLoc() const {
+ return getLocalData()->AttrLoc;
+ }
+ void setAttrNameLoc(SourceLocation loc) {
+ getLocalData()->AttrLoc = loc;
+ }
+
+ /// The attribute's expression operand, if it has one.
+ /// int * __attribute__((address_space(11)))
+ /// ^~
+ Expr *getAttrExprOperand() const {
+ return getLocalData()->ExprOperand;
+ }
+ void setAttrExprOperand(Expr *e) {
+ getLocalData()->ExprOperand = e;
+ }
+
+ /// The location of the parentheses around the operand, if there is
+ /// an operand.
+ /// int * __attribute__((address_space(11)))
+ /// ^ ^
+ SourceRange getAttrOperandParensRange() const {
+ return getLocalData()->OperandParens;
+ }
+ void setAttrOperandParensRange(SourceRange range) {
+ getLocalData()->OperandParens = range;
+ }
+
+ SourceRange getLocalSourceRange() const {
+ SourceRange range(getAttrNameLoc());
+ range.setEnd(getAttrOperandParensRange().getEnd());
+ return range;
+ }
+
+ /// Returns the type before the address space attribute application
+ /// area.
+ /// int * __attribute__((address_space(11))) *
+ /// ^ ^
+ QualType getInnerType() const {
+ return this->getTypePtr()->getPointeeType();
+ }
+
+ TypeLoc getPointeeTypeLoc() const {
+ return this->getInnerTypeLoc();
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation loc) {
+ setAttrNameLoc(loc);
+ setAttrOperandParensRange(SourceRange(loc));
+ setAttrExprOperand(getTypePtr()->getAddrSpaceExpr());
+ }
+};
+
//===----------------------------------------------------------------------===//
//
// All of these need proper implementations.
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 9d1d09e2cc..66697fa0d0 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -23,7 +23,7 @@
// NON_CANONICAL_TYPE(Class, Base) - A type that can show up
// anywhere in the AST but will never be a part of a canonical
// type. Clients that only need to deal with canonical types
-// (ignoring, e.g., typedefs and other type alises used for
+// (ignoring, e.g., typedefs and other type aliases used for
// pretty-printing) can ignore these types.
//
// DEPENDENT_TYPE(Class, Base) - A type that will only show up
@@ -73,6 +73,7 @@ TYPE(IncompleteArray, ArrayType)
TYPE(VariableArray, ArrayType)
DEPENDENT_TYPE(DependentSizedArray, ArrayType)
DEPENDENT_TYPE(DependentSizedExtVector, Type)
+DEPENDENT_TYPE(DependentAddressSpace, Type)
TYPE(Vector, Type)
TYPE(ExtVector, VectorType)
ABSTRACT_TYPE(Function, Type)
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
index 392e544d90..fa64fae882 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/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h
index 5cbcf51dd6..b0b71e4735 100644
--- a/include/clang/AST/VTableBuilder.h
+++ b/include/clang/AST/VTableBuilder.h
@@ -154,6 +154,28 @@ public:
bool isRTTIKind() const { return isRTTIKind(getKind()); }
+ GlobalDecl getGlobalDecl() const {
+ assert(isUsedFunctionPointerKind() &&
+ "GlobalDecl can be created only from virtual function");
+
+ auto *DtorDecl = dyn_cast<CXXDestructorDecl>(getFunctionDecl());
+ switch (getKind()) {
+ case CK_FunctionPointer:
+ return GlobalDecl(getFunctionDecl());
+ case CK_CompleteDtorPointer:
+ return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete);
+ case CK_DeletingDtorPointer:
+ return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting);
+ case CK_VCallOffset:
+ case CK_VBaseOffset:
+ case CK_OffsetToTop:
+ case CK_RTTI:
+ case CK_UnusedFunctionPointer:
+ llvm_unreachable("Only function pointers kinds");
+ }
+ llvm_unreachable("Should already return");
+ }
+
private:
static bool isFunctionPointerKind(Kind ComponentKind) {
return isUsedFunctionPointerKind(ComponentKind) ||
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 6c1c8e4428..d1a582508a 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1,4 +1,4 @@
-//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===//
+//===- ASTMatchers.h - Structural query framework ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -25,7 +25,7 @@
//
// For example, when we're interested in child classes of a certain class, we
// would write:
-// cxxRecordDecl(hasName("MyClass"), hasChild(id("child", recordDecl())))
+// cxxRecordDecl(hasName("MyClass"), has(id("child", recordDecl())))
// When the match is found via the MatchFinder, a user provided callback will
// be called with a BoundNodes instance that contains a mapping from the
// strings that we provided for the id(...) calls to the nodes that were
@@ -46,13 +46,48 @@
#define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TypeTraits.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Regex.h"
+#include <cassert>
+#include <cstddef>
#include <iterator>
+#include <limits>
+#include <string>
+#include <utility>
+#include <vector>
namespace clang {
namespace ast_matchers {
@@ -78,7 +113,7 @@ public:
/// \brief Type of mapping from binding identifiers to bound nodes. This type
/// is an associative container with a key type of \c std::string and a value
/// type of \c clang::ast_type_traits::DynTypedNode
- typedef internal::BoundNodesMap::IDToNodeMap IDToNodeMap;
+ using IDToNodeMap = internal::BoundNodesMap::IDToNodeMap;
/// \brief Retrieve mapping from binding identifiers to bound nodes.
const IDToNodeMap &getMap() const {
@@ -86,13 +121,13 @@ public:
}
private:
+ friend class internal::BoundNodesTreeBuilder;
+
/// \brief Create BoundNodes from a pre-filled map of bindings.
BoundNodes(internal::BoundNodesMap &MyBoundNodes)
: MyBoundNodes(MyBoundNodes) {}
internal::BoundNodesMap MyBoundNodes;
-
- friend class internal::BoundNodesTreeBuilder;
};
/// \brief If the provided matcher matches a node, binds the node to \c ID.
@@ -107,13 +142,13 @@ internal::Matcher<T> id(StringRef ID,
/// \brief Types of matchers for the top-level classes in the AST class
/// hierarchy.
/// @{
-typedef internal::Matcher<Decl> DeclarationMatcher;
-typedef internal::Matcher<Stmt> StatementMatcher;
-typedef internal::Matcher<QualType> TypeMatcher;
-typedef internal::Matcher<TypeLoc> TypeLocMatcher;
-typedef internal::Matcher<NestedNameSpecifier> NestedNameSpecifierMatcher;
-typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher;
-typedef internal::Matcher<CXXCtorInitializer> CXXCtorInitializerMatcher;
+using DeclarationMatcher = internal::Matcher<Decl>;
+using StatementMatcher = internal::Matcher<Stmt>;
+using TypeMatcher = internal::Matcher<QualType>;
+using TypeLocMatcher = internal::Matcher<TypeLoc>;
+using NestedNameSpecifierMatcher = internal::Matcher<NestedNameSpecifier>;
+using NestedNameSpecifierLocMatcher = internal::Matcher<NestedNameSpecifierLoc>;
+using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>;
/// @}
/// \brief Matches any node.
@@ -180,6 +215,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
@@ -572,6 +617,23 @@ AST_MATCHER_P(FieldDecl, hasInClassInitializer, internal::Matcher<Expr>,
InnerMatcher.matches(*Initializer, Finder, Builder));
}
+/// \brief Matches the specialized template of a specialization declaration.
+///
+/// Given
+/// \code
+/// tempalate<typename T> class A {};
+/// typedef A<int> B;
+/// \endcode
+/// classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
+/// matches 'B' with classTemplateDecl() matching the class template
+/// declaration of 'A'.
+AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate,
+ internal::Matcher<ClassTemplateDecl>, InnerMatcher) {
+ const ClassTemplateDecl* Decl = Node.getSpecializedTemplate();
+ return (Decl != nullptr &&
+ InnerMatcher.matches(*Decl, Finder, Builder));
+}
+
/// \brief Matches a declaration that has been implicitly added
/// by the compiler (eg. implicit default/copy constructors).
AST_MATCHER(Decl, isImplicit) {
@@ -1118,6 +1180,91 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
ObjCInterfaceDecl> objcInterfaceDecl;
+/// \brief Matches Objective-C implementation declarations.
+///
+/// Example matches Foo
+/// \code
+/// @implementation Foo
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCImplementationDecl> objcImplementationDecl;
+
+/// \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 category definitions.
+///
+/// Example matches Foo (Additions)
+/// \code
+/// @implementation Foo (Additions)
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCCategoryImplDecl> objcCategoryImplDecl;
+
+/// \brief Matches Objective-C method declarations.
+///
+/// Example matches both declaration and definition of -[Foo method]
+/// \code
+/// @interface Foo
+/// - (void)method;
+/// @end
+///
+/// @implementation Foo
+/// - (void)method {}
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCMethodDecl> objcMethodDecl;
+
+/// \brief Matches Objective-C instance variable declarations.
+///
+/// Example matches _enabled
+/// \code
+/// @implementation Foo {
+/// BOOL _enabled;
+/// }
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCIvarDecl> objcIvarDecl;
+
+/// \brief Matches Objective-C property declarations.
+///
+/// Example matches enabled
+/// \code
+/// @interface Foo
+/// @property BOOL enabled;
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCPropertyDecl> objcPropertyDecl;
+
/// \brief Matches expressions that introduce cleanups to be run at the end
/// of the sub-expression's evaluation.
///
@@ -1150,6 +1297,20 @@ AST_MATCHER_P(InitListExpr, hasSyntacticForm,
InnerMatcher.matches(*SyntForm, Finder, Builder));
}
+/// \brief Matches C++ initializer list expressions.
+///
+/// Given
+/// \code
+/// std::vector<int> a({ 1, 2, 3 });
+/// std::vector<int> b = { 4, 5 };
+/// int c[] = { 6, 7 };
+/// std::pair<int, int> d = { 8, 9 };
+/// \endcode
+/// cxxStdInitializerListExpr()
+/// matches "{ 1, 2, 3 }" and "{ 4, 5 }"
+const internal::VariadicDynCastAllOfMatcher<Stmt,
+ CXXStdInitializerListExpr> cxxStdInitializerListExpr;
+
/// \brief Matches implicit initializers of init list expressions.
///
/// Given
@@ -1333,7 +1494,7 @@ const internal::VariadicDynCastAllOfMatcher<
///
/// Example: Given
/// \code
-/// struct T {void func()};
+/// struct T {void func();};
/// T f();
/// void g(T);
/// \endcode
@@ -2060,23 +2221,23 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
/// \c b.
///
/// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = {
- internal::DynTypedMatcher::VO_EachOf
-};
+const internal::VariadicOperatorMatcherFunc<
+ 2, std::numeric_limits<unsigned>::max()>
+ eachOf = {internal::DynTypedMatcher::VO_EachOf};
/// \brief Matches if any of the given matchers matches.
///
/// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = {
- internal::DynTypedMatcher::VO_AnyOf
-};
+const internal::VariadicOperatorMatcherFunc<
+ 2, std::numeric_limits<unsigned>::max()>
+ anyOf = {internal::DynTypedMatcher::VO_AnyOf};
/// \brief Matches if all given matchers match.
///
/// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = {
- internal::DynTypedMatcher::VO_AllOf
-};
+const internal::VariadicOperatorMatcherFunc<
+ 2, std::numeric_limits<unsigned>::max()>
+ allOf = {internal::DynTypedMatcher::VO_AllOf};
/// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
///
@@ -2462,8 +2623,21 @@ const internal::VariadicOperatorMatcherFunc<1, 1> unless = {
/// - for CXXConstructExpr, the declaration of the constructor
/// - for CXXNewExpr, the declaration of the operator new
///
-/// Also usable as Matcher<T> for any T supporting the getDecl() member
-/// function. e.g. various subtypes of clang::Type and various expressions.
+/// For type nodes, hasDeclaration will generally match the declaration of the
+/// sugared type. Given
+/// \code
+/// class X {};
+/// typedef X Y;
+/// Y y;
+/// \endcode
+/// in varDecl(hasType(hasDeclaration(decl()))) the decl will match the
+/// typedefDecl. A common use case is to match the underlying, desugared type.
+/// This can be achieved by using the hasUnqualifiedDesugaredType matcher:
+/// \code
+/// varDecl(hasType(hasUnqualifiedDesugaredType(
+/// recordType(hasDeclaration(decl())))))
+/// \endcode
+/// In this matcher, the decl will match the CXXRecordDecl of class X.
///
/// Usable as: Matcher<AddrLabelExpr>, Matcher<CallExpr>,
/// Matcher<CXXConstructExpr>, Matcher<CXXNewExpr>, Matcher<DeclRefExpr>,
@@ -2522,7 +2696,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 = ...
@@ -2756,7 +2930,7 @@ AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
/// class A {};
/// using B = A;
/// \endcode
-/// The matcher type(hasUniqualifeidDesugaredType(recordType())) matches
+/// The matcher type(hasUnqualifeidDesugaredType(recordType())) matches
/// both B and A.
AST_MATCHER_P(Type, hasUnqualifiedDesugaredType, internal::Matcher<Type>,
InnerMatcher) {
@@ -3150,7 +3324,7 @@ AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
/// with forField matching foo_
AST_MATCHER_P(CXXCtorInitializer, forField,
internal::Matcher<FieldDecl>, InnerMatcher) {
- const FieldDecl *NodeAsDecl = Node.getMember();
+ const FieldDecl *NodeAsDecl = Node.getAnyMember();
return (NodeAsDecl != nullptr &&
InnerMatcher.matches(*NodeAsDecl, Finder, Builder));
}
@@ -3405,16 +3579,21 @@ AST_MATCHER_P(FunctionDecl, returns,
return InnerMatcher.matches(Node.getReturnType(), Finder, Builder);
}
-/// \brief Matches extern "C" function declarations.
+/// \brief Matches extern "C" function or variable declarations.
///
/// Given:
/// \code
/// extern "C" void f() {}
/// extern "C" { void g() {} }
/// void h() {}
+/// extern "C" int x = 1;
+/// extern "C" int y = 2;
+/// int z = 3;
/// \endcode
/// functionDecl(isExternC())
-/// matches the declaration of f and g, but not the declaration h
+/// matches the declaration of f and g, but not the declaration of h.
+/// varDecl(isExternC())
+/// matches the declaration of x and y, but not the declaration of z.
AST_POLYMORPHIC_MATCHER(isExternC, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
VarDecl)) {
return Node.isExternC();
@@ -3719,14 +3898,30 @@ AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) {
return Node.size() == N;
}
-/// \brief Matches literals that are equal to the given value.
+/// \brief Matches literals that are equal to the given value of type ValueT.
///
-/// Example matches true (matcher = cxxBoolLiteral(equals(true)))
+/// Given
/// \code
-/// true
+/// f('\0', false, 3.14, 42);
/// \endcode
+/// characterLiteral(equals(0))
+/// matches '\0'
+/// cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
+/// match false
+/// floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
+/// match 3.14
+/// integerLiteral(equals(42))
+/// matches 42
+///
+/// Note that you cannot directly match a negative numeric literal because the
+/// minus sign is not part of the literal: It is a unary operator whose operand
+/// is the positive numeric literal. Instead, you must use a unaryOperator()
+/// matcher to match the minus sign:
///
-/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
+/// unaryOperator(hasOperatorName("-"),
+/// hasUnaryOperand(integerLiteral(equals(13))))
+///
+/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
/// Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
template <typename ValueT>
internal::PolymorphicMatcherWithParam1<internal::ValueEqualsMatcher, ValueT>
@@ -3736,6 +3931,34 @@ equals(const ValueT &Value) {
ValueT>(Value);
}
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
+ CXXBoolLiteralExpr,
+ IntegerLiteral),
+ bool, Value, 0) {
+ return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
+ .matchesNode(Node);
+}
+
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
+ CXXBoolLiteralExpr,
+ IntegerLiteral),
+ unsigned, Value, 1) {
+ return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
+ .matchesNode(Node);
+}
+
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
+ CXXBoolLiteralExpr,
+ FloatingLiteral,
+ IntegerLiteral),
+ double, Value, 2) {
+ return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
+ .matchesNode(Node);
+}
+
/// \brief Matches the operator Name of operator expressions (binary or
/// unary).
///
@@ -3816,7 +4039,6 @@ AST_MATCHER_P(UnaryOperator, hasUnaryOperand,
/// \code
/// int a = b ?: 1;
/// \endcode
-
AST_POLYMORPHIC_MATCHER_P(hasSourceExpression,
AST_POLYMORPHIC_SUPPORTED_TYPES(CastExpr,
OpaqueValueExpr),
@@ -4952,6 +5174,21 @@ AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType);
/// and \c s.
AST_TYPE_MATCHER(RecordType, recordType);
+/// \brief Matches tag types (record and enum types).
+///
+/// Given
+/// \code
+/// enum E {};
+/// class C {};
+///
+/// E e;
+/// C c;
+/// \endcode
+///
+/// \c tagType() matches the type of the variable declarations of both \c e
+/// and \c c.
+AST_TYPE_MATCHER(TagType, tagType);
+
/// \brief Matches types specified with an elaborated type keyword or with a
/// qualified name.
///
@@ -5474,7 +5711,6 @@ AST_MATCHER_P(ReturnStmt, hasReturnValue, internal::Matcher<Expr>,
return false;
}
-
/// \brief Matches CUDA kernel call expression.
///
/// Example matches,
@@ -5485,7 +5721,6 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CUDAKernelCallExpr> cudaKernelCallExpr;
-
/// \brief Matches expressions that resolve to a null pointer constant, such as
/// GNU's __null, C++11's nullptr, or C's NULL macro.
///
@@ -5569,7 +5804,7 @@ AST_MATCHER(NamedDecl, hasExternalFormalLinkage) {
return Node.hasExternalFormalLinkage();
}
-} // end namespace ast_matchers
-} // end namespace clang
+} // namespace ast_matchers
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index bc75e807ce..203575e689 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1,4 +1,4 @@
-//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===//
+//===- ASTMatchersInternal.h - Structural query framework -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -38,23 +38,42 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Stmt.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
+#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ManagedStatic.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
#include <map>
#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
#include <vector>
namespace clang {
+
+class ASTContext;
+
namespace ast_matchers {
class BoundNodes;
@@ -158,7 +177,7 @@ public:
/// Note that we're using std::map here, as for memoization:
/// - we need a comparison operator
/// - we need an assignment operator
- typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap;
+ using IDToNodeMap = std::map<std::string, ast_type_traits::DynTypedNode>;
const IDToNodeMap &getMap() const {
return NodeMap;
@@ -188,7 +207,7 @@ public:
/// BoundNodesTree.
class Visitor {
public:
- virtual ~Visitor() {}
+ virtual ~Visitor() = default;
/// \brief Called multiple times during a single call to VisitMatches(...).
///
@@ -248,7 +267,7 @@ class ASTMatchFinder;
class DynMatcherInterface
: public llvm::ThreadSafeRefCountedBase<DynMatcherInterface> {
public:
- virtual ~DynMatcherInterface() {}
+ virtual ~DynMatcherInterface() = default;
/// \brief Returns true if \p DynNode can be matched.
///
@@ -317,26 +336,29 @@ public:
/// \brief Takes ownership of the provided implementation pointer.
template <typename T>
DynTypedMatcher(MatcherInterface<T> *Implementation)
- : AllowBind(false),
- SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()),
+ : SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>()),
RestrictKind(SupportedKind), Implementation(Implementation) {}
/// \brief Construct from a variadic function.
enum VariadicOperator {
/// \brief Matches nodes for which all provided matchers match.
VO_AllOf,
+
/// \brief Matches nodes for which at least one of the provided matchers
/// matches.
VO_AnyOf,
+
/// \brief Matches nodes for which at least one of the provided matchers
/// matches, but doesn't stop at the first match.
VO_EachOf,
+
/// \brief Matches nodes that do not match the provided matcher.
///
/// Uses the variadic matcher interface, but fails if
/// InnerMatchers.size() != 1.
VO_UnaryNot
};
+
static DynTypedMatcher
constructVariadic(VariadicOperator Op,
ast_type_traits::ASTNodeKind SupportedKind,
@@ -382,7 +404,7 @@ public:
/// include both in the ID to make it unique.
///
/// \c MatcherIDType supports operator< and provides strict weak ordering.
- typedef std::pair<ast_type_traits::ASTNodeKind, uint64_t> MatcherIDType;
+ using MatcherIDType = std::pair<ast_type_traits::ASTNodeKind, uint64_t>;
MatcherIDType getID() const {
/// FIXME: Document the requirements this imposes on matcher
/// implementations (no new() implementation_ during a Matches()).
@@ -428,13 +450,12 @@ private:
DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind,
ast_type_traits::ASTNodeKind RestrictKind,
IntrusiveRefCntPtr<DynMatcherInterface> Implementation)
- : AllowBind(false),
- SupportedKind(SupportedKind),
- RestrictKind(RestrictKind),
+ : SupportedKind(SupportedKind), RestrictKind(RestrictKind),
Implementation(std::move(Implementation)) {}
- bool AllowBind;
+ bool AllowBind = false;
ast_type_traits::ASTNodeKind SupportedKind;
+
/// \brief A potentially stricter node kind.
///
/// It allows to perform implicit and dynamic cast of matchers without
@@ -545,6 +566,7 @@ public:
private:
// For Matcher<T> <=> Matcher<U> conversions.
template <typename U> friend class Matcher;
+
// For DynTypedMatcher::unconditionalConvertTo<T>.
friend class DynTypedMatcher;
@@ -618,8 +640,8 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start,
// Metafunction to determine if type T has a member called getDecl.
template <typename Ty>
class has_getDecl {
- typedef char yes[1];
- typedef char no[2];
+ using yes = char[1];
+ using no = char[2];
template <typename Inner>
static yes& test(Inner *I, decltype(I->getDecl()) * = nullptr);
@@ -728,48 +750,94 @@ public:
}
private:
- /// \brief If getDecl exists as a member of U, returns whether the inner
- /// matcher matches Node.getDecl().
- template <typename U>
- bool matchesSpecialized(
- const U &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
- typename std::enable_if<has_getDecl<U>::value, int>::type = 0) const {
- return matchesDecl(Node.getDecl(), Finder, Builder);
- }
-
- /// \brief Extracts the TagDecl of a QualType and returns whether the inner
- /// matcher matches on it.
+ /// \brief Forwards to matching on the underlying type of the QualType.
bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
if (Node.isNull())
return false;
- if (auto *TD = Node->getAsTagDecl())
- return matchesDecl(TD, Finder, Builder);
- else if (auto *TT = Node->getAs<TypedefType>())
- return matchesDecl(TT->getDecl(), Finder, Builder);
- // Do not use getAs<TemplateTypeParmType> instead of the direct dyn_cast.
- // Calling getAs will return the canonical type, but that type does not
- // store a TemplateTypeParmDecl. We *need* the uncanonical type, if it is
- // available, and using dyn_cast ensures that.
- else if (auto *TTP = dyn_cast<TemplateTypeParmType>(Node.getTypePtr()))
- return matchesDecl(TTP->getDecl(), Finder, Builder);
- else if (auto *OCIT = Node->getAs<ObjCInterfaceType>())
- return matchesDecl(OCIT->getDecl(), Finder, Builder);
- else if (auto *UUT = Node->getAs<UnresolvedUsingType>())
- return matchesDecl(UUT->getDecl(), Finder, Builder);
- else if (auto *ICNT = Node->getAs<InjectedClassNameType>())
- return matchesDecl(ICNT->getDecl(), Finder, Builder);
+ return matchesSpecialized(*Node, Finder, Builder);
+ }
+
+ /// \brief Finds the best declaration for a type and returns whether the inner
+ /// matcher matches on it.
+ bool matchesSpecialized(const Type &Node, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ // DeducedType does not have declarations of its own, so
+ // match the deduced type instead.
+ const Type *EffectiveType = &Node;
+ if (const auto *S = dyn_cast<DeducedType>(&Node)) {
+ EffectiveType = S->getDeducedType().getTypePtrOrNull();
+ if (!EffectiveType)
+ return false;
+ }
+
+ // First, for any types that have a declaration, extract the declaration and
+ // match on it.
+ if (const auto *S = dyn_cast<TagType>(EffectiveType)) {
+ return matchesDecl(S->getDecl(), Finder, Builder);
+ }
+ if (const auto *S = dyn_cast<InjectedClassNameType>(EffectiveType)) {
+ return matchesDecl(S->getDecl(), Finder, Builder);
+ }
+ if (const auto *S = dyn_cast<TemplateTypeParmType>(EffectiveType)) {
+ return matchesDecl(S->getDecl(), Finder, Builder);
+ }
+ if (const auto *S = dyn_cast<TypedefType>(EffectiveType)) {
+ return matchesDecl(S->getDecl(), Finder, Builder);
+ }
+ if (const auto *S = dyn_cast<UnresolvedUsingType>(EffectiveType)) {
+ return matchesDecl(S->getDecl(), Finder, Builder);
+ }
+ if (const auto *S = dyn_cast<ObjCObjectType>(EffectiveType)) {
+ return matchesDecl(S->getInterface(), Finder, Builder);
+ }
+
+ // A SubstTemplateTypeParmType exists solely to mark a type substitution
+ // on the instantiated template. As users usually want to match the
+ // template parameter on the uninitialized template, we can always desugar
+ // one level without loss of expressivness.
+ // For example, given:
+ // template<typename T> struct X { T t; } class A {}; X<A> a;
+ // The following matcher will match, which otherwise would not:
+ // fieldDecl(hasType(pointerType())).
+ if (const auto *S = dyn_cast<SubstTemplateTypeParmType>(EffectiveType)) {
+ return matchesSpecialized(S->getReplacementType(), Finder, Builder);
+ }
+
+ // For template specialization types, we want to match the template
+ // declaration, as long as the type is still dependent, and otherwise the
+ // declaration of the instantiated tag type.
+ if (const auto *S = dyn_cast<TemplateSpecializationType>(EffectiveType)) {
+ if (!S->isTypeAlias() && S->isSugared()) {
+ // If the template is non-dependent, we want to match the instantiated
+ // tag type.
+ // For example, given:
+ // template<typename T> struct X {}; X<int> a;
+ // The following matcher will match, which otherwise would not:
+ // templateSpecializationType(hasDeclaration(cxxRecordDecl())).
+ return matchesSpecialized(*S->desugar(), Finder, Builder);
+ }
+ // If the template is dependent or an alias, match the template
+ // declaration.
+ return matchesDecl(S->getTemplateName().getAsTemplateDecl(), Finder,
+ Builder);
+ }
+
+ // FIXME: We desugar elaborated types. This makes the assumption that users
+ // do never want to match on whether a type is elaborated - there are
+ // arguments for both sides; for now, continue desugaring.
+ if (const auto *S = dyn_cast<ElaboratedType>(EffectiveType)) {
+ return matchesSpecialized(S->desugar(), Finder, Builder);
+ }
return false;
}
- /// \brief Gets the TemplateDecl from a TemplateSpecializationType
- /// and returns whether the inner matches on it.
- bool matchesSpecialized(const TemplateSpecializationType &Node,
- ASTMatchFinder *Finder,
+ /// \brief Extracts the Decl the DeclRefExpr references and returns whether
+ /// the inner matcher matches on it.
+ bool matchesSpecialized(const DeclRefExpr &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- return matchesDecl(Node.getTemplateName().getAsTemplateDecl(),
- Finder, Builder);
+ return matchesDecl(Node.getDecl(), Finder, Builder);
}
/// \brief Extracts the Decl of the callee of a CallExpr and returns whether
@@ -811,6 +879,13 @@ private:
return matchesDecl(Node.getLabel(), Finder, Builder);
}
+ /// \brief Extracts the declaration of a LabelStmt and returns whether the
+ /// inner matcher matches on it.
+ bool matchesSpecialized(const LabelStmt &Node, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return matchesDecl(Node.getDecl(), Finder, Builder);
+ }
+
/// \brief Returns whether the inner matcher \c Node. Returns false if \c Node
/// is \c NULL.
bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder,
@@ -863,6 +938,7 @@ public:
enum TraversalKind {
/// Will traverse any child nodes.
TK_AsIs,
+
/// Will not traverse implicit casts and parentheses.
TK_IgnoreImplicitCastsAndParentheses
};
@@ -871,6 +947,7 @@ public:
enum BindKind {
/// Stop at the first match and only bind the first match.
BK_First,
+
/// Create results for all combinations of bindings that match.
BK_All
};
@@ -879,11 +956,12 @@ public:
enum AncestorMatchMode {
/// All ancestors.
AMM_All,
+
/// Direct parent only.
AMM_ParentOnly
};
- virtual ~ASTMatchFinder() {}
+ virtual ~ASTMatchFinder() = default;
/// \brief Returns true if the given class is directly or indirectly derived
/// from a base type matching \c base.
@@ -906,7 +984,7 @@ public:
std::is_base_of<TypeLoc, T>::value ||
std::is_base_of<QualType, T>::value,
"unsupported type for recursive matching");
- return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
+ return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
Matcher, Builder, Traverse, Bind);
}
@@ -969,17 +1047,17 @@ template <typename... Ts> struct TypeList {}; // Empty sentinel type list.
template <typename T1, typename... Ts> struct TypeList<T1, Ts...> {
/// \brief The first type on the list.
- typedef T1 head;
+ using head = T1;
/// \brief A sublist with the tail. ie everything but the head.
///
/// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the
/// end of the list.
- typedef TypeList<Ts...> tail;
+ using tail = TypeList<Ts...>;
};
/// \brief The empty type list.
-typedef TypeList<> EmptyTypeList;
+using EmptyTypeList = TypeList<>;
/// \brief Helper meta-function to determine if some type \c T is present or
/// a parent type in the list.
@@ -997,8 +1075,9 @@ struct TypeListContainsSuperOf<EmptyTypeList, T> {
/// \brief A "type list" that contains all types.
///
/// Useful for matchers like \c anything and \c unless.
-typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc,
- QualType, Type, TypeLoc, CXXCtorInitializer> AllNodeBaseTypes;
+using AllNodeBaseTypes =
+ TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, QualType,
+ Type, TypeLoc, CXXCtorInitializer>;
/// \brief Helper meta-function to extract the argument out of a function of
/// type void(Arg).
@@ -1006,20 +1085,22 @@ typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc,
/// See AST_POLYMORPHIC_SUPPORTED_TYPES for details.
template <class T> struct ExtractFunctionArgMeta;
template <class T> struct ExtractFunctionArgMeta<void(T)> {
- typedef T type;
+ using type = T;
};
/// \brief Default type lists for ArgumentAdaptingMatcher matchers.
-typedef AllNodeBaseTypes AdaptativeDefaultFromTypes;
-typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc,
- TypeLoc, QualType> AdaptativeDefaultToTypes;
+using AdaptativeDefaultFromTypes = AllNodeBaseTypes;
+using AdaptativeDefaultToTypes =
+ TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, TypeLoc,
+ QualType>;
/// \brief All types that are supported by HasDeclarationMatcher above.
-typedef TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType,
- InjectedClassNameType, LabelStmt, AddrLabelExpr, MemberExpr,
- QualType, RecordType, TagType, TemplateSpecializationType,
- TemplateTypeParmType, TypedefType, UnresolvedUsingType>
- HasDeclarationSupportedTypes;
+using HasDeclarationSupportedTypes =
+ TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType,
+ ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr,
+ MemberExpr, QualType, RecordType, TagType,
+ TemplateSpecializationType, TemplateTypeParmType, TypedefType,
+ UnresolvedUsingType>;
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
/// "adapting" a \c To into a \c T.
@@ -1043,7 +1124,7 @@ struct ArgumentAdaptingMatcherFunc {
explicit Adaptor(const Matcher<T> &InnerMatcher)
: InnerMatcher(InnerMatcher) {}
- typedef ToTypes ReturnTypes;
+ using ReturnTypes = ToTypes;
template <typename To> operator Matcher<To>() const {
return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher));
@@ -1080,7 +1161,8 @@ template <template <typename T> class MatcherT,
typename ReturnTypesF = void(AllNodeBaseTypes)>
class PolymorphicMatcherWithParam0 {
public:
- typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
+ using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type;
+
template <typename T>
operator Matcher<T>() const {
static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value,
@@ -1097,7 +1179,7 @@ public:
explicit PolymorphicMatcherWithParam1(const P1 &Param1)
: Param1(Param1) {}
- typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
+ using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type;
template <typename T>
operator Matcher<T>() const {
@@ -1118,7 +1200,7 @@ public:
PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2)
: Param1(Param1), Param2(Param2) {}
- typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
+ using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type;
template <typename T>
operator Matcher<T>() const {
@@ -1137,8 +1219,8 @@ private:
/// This is useful when a matcher syntactically requires a child matcher,
/// but the context doesn't care. See for example: anything().
class TrueMatcher {
- public:
- typedef AllNodeBaseTypes ReturnTypes;
+public:
+ using ReturnTypes = AllNodeBaseTypes;
template <typename T>
operator Matcher<T>() const {
@@ -1184,7 +1266,6 @@ public:
/// ChildT must be an AST base type.
template <typename T, typename ChildT>
class HasMatcher : public WrapperMatcherInterface<T> {
-
public:
explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
: HasMatcher::WrapperMatcherInterface(ChildMatcher) {}
@@ -1278,7 +1359,7 @@ template<typename T>
BindableMatcher<T> makeAllOfComposite(
ArrayRef<const Matcher<T> *> InnerMatchers) {
// For the size() == 0 case, we return a "true" matcher.
- if (InnerMatchers.size() == 0) {
+ if (InnerMatchers.empty()) {
return BindableMatcher<T>(TrueMatcher());
}
// For the size() == 1 case, we simply return that one matcher.
@@ -1287,7 +1368,8 @@ BindableMatcher<T> makeAllOfComposite(
return BindableMatcher<T>(*InnerMatchers[0]);
}
- typedef llvm::pointee_iterator<const Matcher<T> *const *> PI;
+ using PI = llvm::pointee_iterator<const Matcher<T> *const *>;
+
std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()),
PI(InnerMatchers.end()));
return BindableMatcher<T>(
@@ -1580,12 +1662,13 @@ template <typename InnerTBase,
typename ReturnTypesF>
class TypeTraversePolymorphicMatcher {
private:
- typedef TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl,
- ReturnTypesF> Self;
+ using Self = TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl,
+ ReturnTypesF>;
+
static Self create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers);
public:
- typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes;
+ using ReturnTypes = typename ExtractFunctionArgMeta<ReturnTypesF>::type;
explicit TypeTraversePolymorphicMatcher(
ArrayRef<const Matcher<InnerTBase> *> InnerMatchers)
@@ -1612,6 +1695,7 @@ private:
template <typename Matcher, Matcher (*Func)()> class MemoizedMatcher {
struct Wrapper {
Wrapper() : M(Func()) {}
+
Matcher M;
};
@@ -1657,6 +1741,7 @@ struct NotEqualsBoundNodePredicate {
bool operator()(const internal::BoundNodesMap &Nodes) const {
return Nodes.getNode(ID) != Node;
}
+
std::string ID;
ast_type_traits::DynTypedNode Node;
};
@@ -1712,9 +1797,10 @@ CompoundStmtMatcher<StmtExpr>::get(const StmtExpr &Node) {
return Node.getSubStmt();
}
+} // namespace internal
+
+} // namespace ast_matchers
-} // end namespace internal
-} // end namespace ast_matchers
-} // end namespace clang
+} // namespace clang
#endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H
diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
index 2c76ddaa07..908fa0db62 100644
--- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h
+++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
@@ -76,7 +76,7 @@ public:
ET_ParserInvalidToken = 106,
ET_ParserMalformedBindExpr = 107,
ET_ParserTrailingCode = 108,
- ET_ParserUnsignedError = 109,
+ ET_ParserNumberError = 109,
ET_ParserOverloadedType = 110
};
diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h
index 76926f09db..e8fcf0a9d6 100644
--- a/include/clang/ASTMatchers/Dynamic/Parser.h
+++ b/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -1,4 +1,4 @@
-//===--- Parser.h - Matcher expression parser -----*- C++ -*-===//
+//===- Parser.h - Matcher expression parser ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -6,7 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-///
+//
/// \file
/// \brief Simple matcher expression parser.
///
@@ -19,8 +19,10 @@
/// \code
/// Grammar for the expressions supported:
/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression>
-/// <Literal> := <StringLiteral> | <Unsigned>
+/// <Literal> := <StringLiteral> | <Boolean> | <Double> | <Unsigned>
/// <StringLiteral> := "quoted string"
+/// <Boolean> := true | false
+/// <Double> := [0-9]+.[0-9]* | [0-9]+.[0-9]*[eE][-+]?[0-9]+
/// <Unsigned> := [0-9]+
/// <NamedValue> := <Identifier>
/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
@@ -28,24 +30,28 @@
/// <Identifier> := [a-zA-Z]+
/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList>
/// \endcode
-///
+//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H
#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_PARSER_H
-#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
-#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include <utility>
+#include <vector>
namespace clang {
namespace ast_matchers {
namespace dynamic {
+class Diagnostics;
+
/// \brief Matcher expression parser.
class Parser {
public:
@@ -122,8 +128,8 @@ public:
/// \brief Sema implementation that uses the matcher registry to process the
/// tokens.
class RegistrySema : public Parser::Sema {
- public:
- ~RegistrySema() override;
+ public:
+ ~RegistrySema() override;
llvm::Optional<MatcherCtor>
lookupMatcherCtor(StringRef MatcherName) override;
@@ -141,7 +147,7 @@ public:
getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) override;
};
- typedef llvm::StringMap<VariantValue> NamedValueMap;
+ using NamedValueMap = llvm::StringMap<VariantValue>;
/// \brief Parse a matcher expression.
///
@@ -245,13 +251,14 @@ private:
const NamedValueMap *const NamedValues;
Diagnostics *const Error;
- typedef std::vector<std::pair<MatcherCtor, unsigned> > ContextStackTy;
+ using ContextStackTy = std::vector<std::pair<MatcherCtor, unsigned>>;
+
ContextStackTy ContextStack;
std::vector<MatcherCompletion> Completions;
};
-} // namespace dynamic
-} // namespace ast_matchers
-} // namespace clang
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
-#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
+#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_PARSER_H
diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h
index 7bba95dbff..277491250d 100644
--- a/include/clang/ASTMatchers/Dynamic/Registry.h
+++ b/include/clang/ASTMatchers/Dynamic/Registry.h
@@ -1,4 +1,4 @@
-//===--- Registry.h - Matcher registry --------------------------*- C++ -*-===//
+//===- Registry.h - Matcher registry ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -6,12 +6,12 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-///
+//
/// \file
/// \brief Registry of all known matchers.
///
/// The registry provides a generic interface to construct any matcher by name.
-///
+//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_REGISTRY_H
@@ -34,9 +34,9 @@ namespace internal {
class MatcherDescriptor;
-} // end namespace internal
+} // namespace internal
-typedef const internal::MatcherDescriptor *MatcherCtor;
+using MatcherCtor = const internal::MatcherDescriptor *;
struct MatcherCompletion {
MatcherCompletion() = default;
@@ -129,8 +129,8 @@ public:
Diagnostics *Error);
};
-} // end namespace dynamic
-} // end namespace ast_matchers
-} // end namespace clang
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_REGISTRY_H
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index 2c80b51373..f9efe0f16f 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -35,6 +35,8 @@ class ArgKind {
public:
enum Kind {
AK_Matcher,
+ AK_Boolean,
+ AK_Double,
AK_Unsigned,
AK_String
};
@@ -56,7 +58,7 @@ class ArgKind {
/// \param To the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
bool operator<(const ArgKind &Other) const {
@@ -182,7 +184,7 @@ public:
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
unsigned *Specificity) const {
if (Value)
@@ -241,6 +243,8 @@ struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
/// copy/assignment.
///
/// Supported types:
+/// - \c bool
+// - \c double
/// - \c unsigned
/// - \c llvm::StringRef
/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
@@ -253,14 +257,29 @@ public:
VariantValue &operator=(const VariantValue &Other);
/// \brief Specific constructors for each supported type.
+ VariantValue(bool Boolean);
+ VariantValue(double Double);
VariantValue(unsigned Unsigned);
VariantValue(StringRef String);
VariantValue(const VariantMatcher &Matchers);
+ /// \brief Constructs an \c unsigned value (disambiguation from bool).
+ VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {}
+
/// \brief Returns true iff this is not an empty value.
explicit operator bool() const { return hasValue(); }
bool hasValue() const { return Type != VT_Nothing; }
+ /// \brief Boolean value functions.
+ bool isBoolean() const;
+ bool getBoolean() const;
+ void setBoolean(bool Boolean);
+
+ /// \brief Double value functions.
+ bool isDouble() const;
+ double getDouble() const;
+ void setDouble(double Double);
+
/// \brief Unsigned value functions.
bool isUnsigned() const;
unsigned getUnsigned() const;
@@ -281,7 +300,7 @@ public:
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
/// \brief Determines if the contained value can be converted to any kind
@@ -290,7 +309,7 @@ public:
/// \param Kinds the requested destination types.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion. It is the maximum specificity of all the possible
+ /// conversion. It is the maximum specificity of all the possible
/// conversions.
bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
@@ -303,6 +322,8 @@ private:
/// \brief All supported value types.
enum ValueType {
VT_Nothing,
+ VT_Boolean,
+ VT_Double,
VT_Unsigned,
VT_String,
VT_Matcher
@@ -311,6 +332,8 @@ private:
/// \brief All supported value types.
union AllValues {
unsigned Unsigned;
+ double Double;
+ bool Boolean;
std::string *String;
VariantMatcher *Matcher;
};
diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h
index c0fc02724f..5ba42b475c 100644
--- a/include/clang/Analysis/Analyses/Consumed.h
+++ b/include/clang/Analysis/Analyses/Consumed.h
@@ -19,7 +19,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/SourceLocation.h"
namespace clang {
diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h
index 1229f8a8ef..6cb161ab37 100644
--- a/include/clang/Analysis/Analyses/Dominators.h
+++ b/include/clang/Analysis/Analyses/Dominators.h
@@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/Support/GenericDomTree.h"
@@ -38,15 +38,15 @@ typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode;
class DominatorTree : public ManagedAnalysis {
virtual void anchor();
public:
- llvm::DominatorTreeBase<CFGBlock>* DT;
+ llvm::DomTreeBase<CFGBlock>* DT;
DominatorTree() {
- DT = new llvm::DominatorTreeBase<CFGBlock>(false);
+ DT = new llvm::DomTreeBase<CFGBlock>();
}
~DominatorTree() override { delete DT; }
- llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; }
+ llvm::DomTreeBase<CFGBlock>& getBase() { return *DT; }
/// \brief This method returns the root CFGBlock of the dominators tree.
///
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index 8db4b0a58f..6a1222386b 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -15,7 +15,7 @@
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H
#include "clang/AST/Decl.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "llvm/ADT/ImmutableSet.h"
namespace clang {
diff --git a/include/clang/Analysis/Analyses/PostOrderCFGView.h b/include/clang/Analysis/Analyses/PostOrderCFGView.h
index a1c6504275..c0a9352837 100644
--- a/include/clang/Analysis/Analyses/PostOrderCFGView.h
+++ b/include/clang/Analysis/Analyses/PostOrderCFGView.h
@@ -21,7 +21,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/BitVector.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
namespace clang {
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
index 22694a7a22..7e403b1f40 100644
--- a/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -19,7 +19,7 @@
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/StringRef.h"
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
index 8c1d1da554..414645b723 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
+++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
@@ -25,7 +25,7 @@
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/OperatorKinds.h"
#include <memory>
#include <ostream>
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
index be8a7105d7..17351622fb 100644
--- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
+++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
@@ -909,15 +909,10 @@ class Project : public SExpr {
public:
static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
- Project(SExpr *R, StringRef SName)
- : SExpr(COP_Project), Rec(R), SlotName(SName), Cvdecl(nullptr)
- { }
Project(SExpr *R, const clang::ValueDecl *Cvd)
- : SExpr(COP_Project), Rec(R), SlotName(Cvd->getName()), Cvdecl(Cvd)
- { }
- Project(const Project &P, SExpr *R)
- : SExpr(P), Rec(R), SlotName(P.SlotName), Cvdecl(P.Cvdecl)
- { }
+ : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) {
+ assert(Cvd && "ValueDecl must not be null");
+ }
SExpr *record() { return Rec; }
const SExpr *record() const { return Rec; }
@@ -931,10 +926,14 @@ public:
}
StringRef slotName() const {
- if (Cvdecl)
+ if (Cvdecl->getDeclName().isIdentifier())
return Cvdecl->getName();
- else
- return SlotName;
+ if (!SlotName) {
+ SlotName = "";
+ llvm::raw_string_ostream OS(*SlotName);
+ Cvdecl->printName(OS);
+ }
+ return *SlotName;
}
template <class V>
@@ -953,7 +952,7 @@ public:
private:
SExpr* Rec;
- StringRef SlotName;
+ mutable llvm::Optional<std::string> SlotName;
const clang::ValueDecl *Cvdecl;
};
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisDeclContext.h
index f6a47d646d..03ff4a9516 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisDeclContext.h
@@ -1,4 +1,4 @@
-//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-//
+//=== AnalysisDeclContext.h - Analysis context for Path Sens analysis --*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
@@ -12,10 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
-#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H
+#define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H
#include "clang/AST/Decl.h"
+#include "clang/Analysis/BodyFarm.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CodeInjector.h"
#include "llvm/ADT/DenseMap.h"
@@ -416,22 +417,25 @@ class AnalysisDeclContextManager {
/// Pointer to an interface that can provide function bodies for
/// declarations from external source.
std::unique_ptr<CodeInjector> Injector;
-
+
+ /// A factory for creating and caching implementations for common
+ /// methods during the analysis.
+ BodyFarm FunctionBodyFarm;
+
/// Flag to indicate whether or not bodies should be synthesized
/// for well-known functions.
bool SynthesizeBodies;
public:
- AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
+ AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false,
bool addImplicitDtors = false,
bool addInitializers = false,
bool addTemporaryDtors = false,
+ bool addLifetime = false, bool addLoopExit = false,
bool synthesizeBodies = false,
bool addStaticInitBranches = false,
bool addCXXNewAllocator = true,
- CodeInjector* injector = nullptr);
-
- ~AnalysisDeclContextManager();
+ CodeInjector *injector = nullptr);
AnalysisDeclContext *getContext(const Decl *D);
@@ -470,6 +474,9 @@ public:
return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
}
+ /// Get a reference to {@code BodyFarm} instance.
+ BodyFarm &getBodyFarm();
+
/// Discard all previously created AnalysisDeclContexts.
void clear();
diff --git a/lib/Analysis/BodyFarm.h b/include/clang/Analysis/BodyFarm.h
index edbe996246..ff0859bc66 100644
--- a/lib/Analysis/BodyFarm.h
+++ b/include/clang/Analysis/BodyFarm.h
@@ -28,24 +28,27 @@ class ObjCMethodDecl;
class ObjCPropertyDecl;
class Stmt;
class CodeInjector;
-
+
class BodyFarm {
public:
BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {}
-
+
/// Factory method for creating bodies for ordinary functions.
Stmt *getBody(const FunctionDecl *D);
/// Factory method for creating bodies for Objective-C properties.
Stmt *getBody(const ObjCMethodDecl *D);
+ /// Remove copy constructor to avoid accidental copying.
+ BodyFarm(const BodyFarm &other) = delete;
+
private:
- typedef llvm::DenseMap<const Decl *, Optional<Stmt *> > BodyMap;
+ typedef llvm::DenseMap<const Decl *, Optional<Stmt *>> BodyMap;
ASTContext &C;
BodyMap Bodies;
CodeInjector *Injector;
};
-}
+} // namespace clang
#endif
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index d23ed77ded..8cdd782671 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -58,6 +58,8 @@ public:
Statement,
Initializer,
NewAllocator,
+ LifetimeEnds,
+ LoopExit,
// dtor kind
AutomaticObjectDtor,
DeleteDtor,
@@ -167,6 +169,51 @@ private:
}
};
+/// Represents the point where a loop ends.
+/// This element is is only produced when building the CFG for the static
+/// analyzer and hidden behind the 'cfg-loopexit' analyzer config flag.
+///
+/// Note: a loop exit element can be reached even when the loop body was never
+/// entered.
+class CFGLoopExit : public CFGElement {
+public:
+ explicit CFGLoopExit(const Stmt *stmt)
+ : CFGElement(LoopExit, stmt) {}
+
+ const Stmt *getLoopStmt() const {
+ return static_cast<Stmt *>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+ CFGLoopExit() {}
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == LoopExit;
+ }
+};
+
+/// Represents the point where the lifetime of an automatic object ends
+class CFGLifetimeEnds : public CFGElement {
+public:
+ explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt)
+ : CFGElement(LifetimeEnds, var, stmt) {}
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+ const Stmt *getTriggerStmt() const {
+ return static_cast<Stmt *>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+ CFGLifetimeEnds() {}
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == LifetimeEnds;
+ }
+};
+
/// CFGImplicitDtor - Represents C++ object destructor implicitly generated
/// by compiler on various occasions.
class CFGImplicitDtor : public CFGElement {
@@ -701,6 +748,14 @@ public:
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
}
+ void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
+ Elements.push_back(CFGLifetimeEnds(VD, S), C);
+ }
+
+ void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) {
+ Elements.push_back(CFGLoopExit(LoopStmt), C);
+ }
+
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
Elements.push_back(CFGDeleteDtor(RD, DE), C);
}
@@ -717,6 +772,19 @@ public:
*I = CFGAutomaticObjDtor(VD, S);
return ++I;
}
+
+ // Scope leaving must be performed in reversed order. So insertion is in two
+ // steps. First we prepare space for some number of elements, then we insert
+ // the elements beginning at the last position in prepared space.
+ iterator beginLifetimeEndsInsert(iterator I, size_t Cnt,
+ BumpVectorContext &C) {
+ return iterator(
+ Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C));
+ }
+ iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) {
+ *I = CFGLifetimeEnds(VD, S);
+ return ++I;
+ }
};
/// \brief CFGCallback defines methods that should be called when a logical
@@ -753,6 +821,8 @@ public:
bool AddEHEdges;
bool AddInitializers;
bool AddImplicitDtors;
+ bool AddLifetime;
+ bool AddLoopExit;
bool AddTemporaryDtors;
bool AddStaticInitBranches;
bool AddCXXNewAllocator;
@@ -774,8 +844,10 @@ public:
BuildOptions()
: forcedBlkExprs(nullptr), Observer(nullptr),
- PruneTriviallyFalseEdges(true), AddEHEdges(false),
+ PruneTriviallyFalseEdges(true),
+ AddEHEdges(false),
AddInitializers(false), AddImplicitDtors(false),
+ AddLifetime(false), AddLoopExit(false),
AddTemporaryDtors(false), AddStaticInitBranches(false),
AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {}
};
diff --git a/include/clang/Analysis/CloneDetection.h b/include/clang/Analysis/CloneDetection.h
index 51cad7a96d..051b923665 100644
--- a/include/clang/Analysis/CloneDetection.h
+++ b/include/clang/Analysis/CloneDetection.h
@@ -7,18 +7,16 @@
//
//===----------------------------------------------------------------------===//
///
-/// /file
-/// This file defines classes for searching and anlyzing source code clones.
+/// \file
+/// This file defines classes for searching and analyzing source code clones.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_CLONEDETECTION_H
#define LLVM_CLANG_AST_CLONEDETECTION_H
-#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/StringMap.h"
-
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/Regex.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,244 @@ public:
bool contains(const StmtSequence &Other) const;
};
-/// \brief Searches for clones in source code.
+/// Searches for similar subtrees in the AST.
+///
+/// First, this class needs several declarations with statement bodies which
+/// can be passed via analyzeCodeBody. Afterwards all statements can be
+/// searched for clones by calling findClones with a given list of constraints
+/// that should specify the wanted properties of the clones.
///
-/// First, this class needs a translation unit which is passed via
-/// \p analyzeTranslationUnit . It will then generate and store search data
-/// for all statements inside the given translation unit.
-/// Afterwards the generated data can be used to find code clones by calling
-/// \p findClones .
+/// The result of findClones can be further constrained with the constrainClones
+/// method.
///
/// This class only searches for clones in exectuable source code
/// (e.g. function bodies). Other clones (e.g. cloned comments or declarations)
/// are not supported.
class CloneDetector {
+
public:
- typedef unsigned DataPiece;
-
- /// 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);
}
+
+ Result.push_back(AllClones);
+
+ constrainClones(Result, ConstraintList...);
+ }
+
+private:
+ CloneGroup Sequences;
+};
+
+/// This class is a utility class that contains utility functions for building
+/// custom constraints.
+class CloneConstraint {
+public:
+ /// Removes all groups by using a filter function.
+ /// \param CloneGroups The list of CloneGroups that is supposed to be
+ /// filtered.
+ /// \param Filter The filter function that should return true for all groups
+ /// that should be removed from the list.
+ static void filterGroups(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ llvm::function_ref<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,
+ llvm::function_ref<bool(const StmtSequence &, const StmtSequence &)>
+ Compare);
+};
+
+/// This constraint moves clones into clone groups of type II via hashing.
+///
+/// Clones with different hash values are moved into separate clone groups.
+/// Collisions are possible, and this constraint does nothing to address this
+/// them. Add the slower RecursiveCloneTypeIIVerifyConstraint later in the
+/// constraint chain, not necessarily immediately, to eliminate hash collisions
+/// through a more detailed analysis.
+class RecursiveCloneTypeIIHashConstraint {
+public:
+ void constrain(std::vector<CloneDetector::CloneGroup> &Sequences);
+};
+
+/// This constraint moves clones into clone groups of type II by comparing them.
+///
+/// Clones that aren't type II clones are moved into separate clone groups.
+/// In contrast to the RecursiveCloneTypeIIHashConstraint, all clones in a clone
+/// group are guaranteed to be be type II clones of each other, but it is too
+/// slow to efficiently handle large amounts of clones.
+class RecursiveCloneTypeIIVerifyConstraint {
+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) {}
+
+ /// Calculates the complexity of the given StmtSequence.
+ /// \param Limit The limit of complexity we probe for. After reaching
+ /// this limit during calculation, this method is exiting
+ /// early to improve performance and returns this limit.
+ size_t calculateStmtComplexity(const StmtSequence &Seq, std::size_t Limit,
+ 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) <
+ MinComplexity;
+ else
+ return false;
+ });
+ }
+};
+
+/// Ensures that all clone groups contain at least the given amount of clones.
+class MinGroupSizeConstraint {
+ unsigned MinGroupSize;
+
+public:
+ MinGroupSizeConstraint(unsigned MinGroupSize = 2)
+ : MinGroupSize(MinGroupSize) {}
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(CloneGroups,
+ [this](const CloneDetector::CloneGroup &A) {
+ return A.size() < MinGroupSize;
+ });
+ }
+};
+
+/// Ensures that no clone group fully contains another clone group.
+struct OnlyLargestCloneConstraint {
+ void constrain(std::vector<CloneDetector::CloneGroup> &Result);
+};
+
+struct FilenamePatternConstraint {
+ StringRef IgnoredFilesPattern;
+ std::shared_ptr<llvm::Regex> IgnoredFilesRegex;
+
+ FilenamePatternConstraint(StringRef IgnoredFilesPattern)
+ : IgnoredFilesPattern(IgnoredFilesPattern) {
+ IgnoredFilesRegex = std::make_shared<llvm::Regex>("^(" +
+ IgnoredFilesPattern.str() + "$)");
+ }
+
+ bool isAutoGenerated(const CloneDetector::CloneGroup &Group);
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(
+ CloneGroups, [this](const CloneDetector::CloneGroup &Group) {
+ return isAutoGenerated(Group);
+ });
+ }
+};
+
+/// Analyzes the pattern of the referenced variables in a statement.
+class VariablePattern {
+
+ /// Describes an occurence of a variable reference in a statement.
+ struct VariableOccurence {
+ /// The index of the associated VarDecl in the Variables vector.
+ size_t KindID;
+ /// The statement in the code where the variable was referenced.
+ const Stmt *Mention;
+
+ VariableOccurence(size_t KindID, const Stmt *Mention)
+ : KindID(KindID), Mention(Mention) {}
};
- /// \brief Generates and stores search data for all statements in the body of
- /// the given Decl.
- void analyzeCodeBody(const Decl *D);
+ /// 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 Stores the CloneSignature to allow future querying.
- void add(const StmtSequence &S, const CloneSignature &Signature);
+ /// 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);
- /// \brief Searches the provided statements for clones.
- ///
- /// \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.
+ /// 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 +409,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/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index be5adfb294..2d59dec48a 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
#define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
@@ -83,6 +83,7 @@ public:
PostImplicitCallKind,
MinImplicitCallKind = PreImplicitCallKind,
MaxImplicitCallKind = PostImplicitCallKind,
+ LoopExitKind,
EpsilonKind};
private:
@@ -654,6 +655,29 @@ private:
}
};
+/// Represents a point when we exit a loop.
+/// When this ProgramPoint is encountered we can be sure that the symbolic
+/// execution of the corresponding LoopStmt is finished on the given path.
+/// Note: It is possible to encounter a LoopExit element when we haven't even
+/// encountered the loop itself. At the current state not all loop exits will
+/// result in a LoopExit program point.
+class LoopExit : public ProgramPoint {
+public:
+ LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
+ : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
+
+ const Stmt *getLoopStmt() const {
+ return static_cast<const Stmt *>(getData1());
+ }
+
+private:
+ friend class ProgramPoint;
+ LoopExit() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == LoopExitKind;
+ }
+};
+
/// This is a meta program point, which should be skipped by all the diagnostic
/// reasoning etc.
class EpsilonPoint : public ProgramPoint {
diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h
index 63df61bedb..6b0090813e 100644
--- a/include/clang/Basic/AddressSpaces.h
+++ b/include/clang/Basic/AddressSpaces.h
@@ -16,36 +16,59 @@
#ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H
#define LLVM_CLANG_BASIC_ADDRESSSPACES_H
-namespace clang {
+#include <assert.h>
-namespace LangAS {
+namespace clang {
-/// \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,
+enum class LangAS : unsigned {
+ // The default value 0 is the value used in QualType for the the situation
+ // where there is no address space qualifier.
+ Default = 0,
- opencl_global = Offset,
+ // OpenCL specific address spaces.
+ // In OpenCL each l-value must have certain non-default address space, each
+ // r-value must have no address space (i.e. the default address space). The
+ // pointee of a pointer must have non-default address space.
+ opencl_global,
opencl_local,
opencl_constant,
+ opencl_private,
opencl_generic,
+ // CUDA specific address spaces.
cuda_device,
cuda_constant,
cuda_shared,
- Last,
- Count = Last-Offset
+ // This denotes the count of language-specific address spaces and also
+ // the offset added to the target-specific address spaces, which are usually
+ // specified by address space attributes __attribute__(address_space(n))).
+ FirstTargetAddressSpace
};
/// The type of a lookup table which maps from language-specific address spaces
/// to target-specific ones.
-typedef unsigned Map[Count];
+typedef unsigned LangASMap[(unsigned)LangAS::FirstTargetAddressSpace];
+/// \return whether \p AS is a target-specific address space rather than a
+/// clang AST address space
+inline bool isTargetAddressSpace(LangAS AS) {
+ return (unsigned)AS >= (unsigned)LangAS::FirstTargetAddressSpace;
}
+inline unsigned toTargetAddressSpace(LangAS AS) {
+ assert(isTargetAddressSpace(AS));
+ return (unsigned)AS - (unsigned)LangAS::FirstTargetAddressSpace;
}
+inline LangAS getLangASFromTargetAS(unsigned TargetAS) {
+ return static_cast<LangAS>((TargetAS) +
+ (unsigned)LangAS::FirstTargetAddressSpace);
+}
+
+} // namespace clang
+
#endif
diff --git a/include/clang/Basic/AlignedAllocation.h b/include/clang/Basic/AlignedAllocation.h
new file mode 100644
index 0000000000..b3496949f3
--- /dev/null
+++ b/include/clang/Basic/AlignedAllocation.h
@@ -0,0 +1,44 @@
+//===--- AlignedAllocation.h - Aligned Allocation ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines a function that returns the minimum OS versions supporting
+/// C++17's aligned allocation functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H
+#define LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H
+
+#include "clang/Basic/VersionTuple.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace clang {
+
+inline VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) {
+ switch (OS) {
+ default:
+ break;
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX: // Earliest supporting version is 10.13.
+ return VersionTuple(10U, 13U);
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0.
+ return VersionTuple(11U);
+ case llvm::Triple::WatchOS: // Earliest supporting version is 4.0.0.
+ return VersionTuple(4U);
+ }
+
+ llvm_unreachable("Unexpected OS");
+}
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H
diff --git a/include/clang/Basic/AllDiagnostics.h b/include/clang/Basic/AllDiagnostics.h
index 18a2b8a318..1c83e2d0f8 100644
--- a/include/clang/Basic/AllDiagnostics.h
+++ b/include/clang/Basic/AllDiagnostics.h
@@ -18,17 +18,19 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CommentDiagnostic.h"
#include "clang/Analysis/AnalysisDiagnostic.h"
+#include "clang/CrossTU/CrossTUDiagnostic.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Serialization/SerializationDiagnostic.h"
+#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
namespace clang {
template <size_t SizeOfStr, typename FieldType>
class StringSizerHelper {
- char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
+ static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
public:
enum { Size = SizeOfStr };
};
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 5960cca1e7..0090b99526 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -149,6 +149,9 @@ class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
class FunctionArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
opt,
fake>;
+class NamedArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
+ opt,
+ fake>;
class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
@@ -207,18 +210,26 @@ class CXX11<string namespace, string name, int version = 1>
string Namespace = namespace;
int Version = version;
}
+class C2x<string namespace, string name> : Spelling<name, "C2x"> {
+ string Namespace = namespace;
+}
+
class Keyword<string name> : Spelling<name, "Keyword">;
class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
string Namespace = namespace;
}
-// The GCC spelling implies GNU<name, "GNU"> and CXX11<"gnu", name> and also
-// sets KnownToGCC to 1. This spelling should be used for any GCC-compatible
+// The GCC spelling implies GNU<name> and CXX11<"gnu", name> and also sets
+// KnownToGCC to 1. This spelling should be used for any GCC-compatible
// attributes.
class GCC<string name> : Spelling<name, "GCC"> {
let KnownToGCC = 1;
}
+// The Clang spelling implies GNU<name> and CXX11<"clang", name>. This spelling
+// should be used for any Clang-specific attributes.
+class Clang<string name> : Spelling<name, "Clang">;
+
class Accessor<string name, list<Spelling> spellings> {
string Name = name;
list<Spelling> Spellings = spellings;
@@ -248,6 +259,8 @@ def COnly : LangOpt<"CPlusPlus", 1>;
def CPlusPlus : LangOpt<"CPlusPlus">;
def OpenCL : LangOpt<"OpenCL">;
def RenderScript : LangOpt<"RenderScript">;
+def ObjC : LangOpt<"ObjC1">;
+def BlocksSupported : LangOpt<"Blocks">;
// Defines targets for target-specific attributes. The list of strings should
// specify architectures for which the target applies, based off the ArchType
@@ -259,17 +272,124 @@ class TargetArch<list<string> arches> {
}
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
def TargetAVR : TargetArch<["avr"]>;
-def TargetMips : TargetArch<["mips", "mipsel"]>;
+def TargetMips32 : TargetArch<["mips", "mipsel"]>;
+def TargetAnyMips : TargetArch<["mips", "mipsel", "mips64", "mips64el"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
def TargetX86 : TargetArch<["x86"]>;
def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
-def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
+def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> {
let OSes = ["Win32"];
}
-def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
+def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch64"]> {
let CXXABIs = ["Microsoft"];
}
+// Attribute subject match rules that are used for #pragma clang attribute.
+//
+// A instance of AttrSubjectMatcherRule represents an individual match rule.
+// An individual match rule can correspond to a number of different attribute
+// subjects, e.g. "record" matching rule corresponds to the Record and
+// CXXRecord attribute subjects.
+//
+// Match rules are used in the subject list of the #pragma clang attribute.
+// Match rules can have sub-match rules that are instances of
+// AttrSubjectMatcherSubRule. A sub-match rule can correspond to a number
+// of different attribute subjects, and it can have a negated spelling as well.
+// For example, "variable(unless(is_parameter))" matching rule corresponds to
+// the NonParmVar attribute subject.
+class AttrSubjectMatcherSubRule<string name, list<AttrSubject> subjects,
+ bit negated = 0> {
+ string Name = name;
+ list<AttrSubject> Subjects = subjects;
+ bit Negated = negated;
+ // Lists language options, one of which is required to be true for the
+ // attribute to be applicable. If empty, the language options are taken
+ // from the parent matcher rule.
+ list<LangOpt> LangOpts = [];
+}
+class AttrSubjectMatcherRule<string name, list<AttrSubject> subjects,
+ list<AttrSubjectMatcherSubRule> subrules = []> {
+ string Name = name;
+ list<AttrSubject> Subjects = subjects;
+ list<AttrSubjectMatcherSubRule> Constraints = subrules;
+ // Lists language options, one of which is required to be true for the
+ // attribute to be applicable. If empty, no language options are required.
+ list<LangOpt> LangOpts = [];
+}
+
+// function(is_member)
+def SubRuleForCXXMethod : AttrSubjectMatcherSubRule<"is_member", [CXXMethod]> {
+ let LangOpts = [CPlusPlus];
+}
+def SubjectMatcherForFunction : AttrSubjectMatcherRule<"function", [Function], [
+ SubRuleForCXXMethod
+]>;
+// hasType is abstract, it should be used with one of the sub-rules.
+def SubjectMatcherForType : AttrSubjectMatcherRule<"hasType", [], [
+ AttrSubjectMatcherSubRule<"functionType", [FunctionLike]>
+
+ // FIXME: There's a matcher ambiguity with objc methods and blocks since
+ // functionType excludes them but functionProtoType includes them.
+ // AttrSubjectMatcherSubRule<"functionProtoType", [HasFunctionProto]>
+]>;
+def SubjectMatcherForTypedef : AttrSubjectMatcherRule<"type_alias",
+ [TypedefName]>;
+def SubjectMatcherForRecord : AttrSubjectMatcherRule<"record", [Record,
+ CXXRecord], [
+ // unless(is_union)
+ AttrSubjectMatcherSubRule<"is_union", [Struct], 1>
+]>;
+def SubjectMatcherForEnum : AttrSubjectMatcherRule<"enum", [Enum]>;
+def SubjectMatcherForEnumConstant : AttrSubjectMatcherRule<"enum_constant",
+ [EnumConstant]>;
+def SubjectMatcherForVar : AttrSubjectMatcherRule<"variable", [Var], [
+ AttrSubjectMatcherSubRule<"is_thread_local", [TLSVar]>,
+ AttrSubjectMatcherSubRule<"is_global", [GlobalVar]>,
+ AttrSubjectMatcherSubRule<"is_parameter", [ParmVar]>,
+ // unless(is_parameter)
+ AttrSubjectMatcherSubRule<"is_parameter", [NonParmVar], 1>
+]>;
+def SubjectMatcherForField : AttrSubjectMatcherRule<"field", [Field]>;
+def SubjectMatcherForNamespace : AttrSubjectMatcherRule<"namespace",
+ [Namespace]> {
+ let LangOpts = [CPlusPlus];
+}
+def SubjectMatcherForObjCInterface : AttrSubjectMatcherRule<"objc_interface",
+ [ObjCInterface]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCProtocol : AttrSubjectMatcherRule<"objc_protocol",
+ [ObjCProtocol]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCCategory : AttrSubjectMatcherRule<"objc_category",
+ [ObjCCategory]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method",
+ [ObjCMethod], [
+ AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]>
+]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCProperty : AttrSubjectMatcherRule<"objc_property",
+ [ObjCProperty]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForBlock : AttrSubjectMatcherRule<"block", [Block]> {
+ let LangOpts = [BlocksSupported];
+}
+
+// Aggregate attribute subject match rules are abstract match rules that can't
+// be used directly in #pragma clang attribute. Instead, users have to use
+// subject match rules that correspond to attribute subjects that derive from
+// the specified subject.
+class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
+ AttrSubject Subject = subject;
+}
+
+def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
+
class Attr {
// The various ways in which an attribute can be spelled in source
list<Spelling> Spellings;
@@ -302,6 +422,17 @@ class Attr {
// Set to true if this attribute can be duplicated on a subject when merging
// attributes. By default, attributes are not merged.
bit DuplicatesAllowedWhileMerging = 0;
+ // Set to true if this attribute meaningful when applied to or inherited
+ // in a class template definition.
+ bit MeaningfulToClassTemplateDefinition = 0;
+ // Set to true if this attribute can be used with '#pragma clang attribute'.
+ // By default, when this value is false, an attribute is supported by the
+ // '#pragma clang attribute' only when:
+ // - It has documentation.
+ // - It has a subject list whose subjects can be represented using subject
+ // match rules.
+ // - It has GNU/CXX11 spelling and doesn't require delayed parsing.
+ bit ForcePragmaAttributeSupport = 0;
// Lists language options, one of which is required to be true for the
// attribute to be applicable. If empty, no language options are required.
list<LangOpt> LangOpts = [];
@@ -373,6 +504,7 @@ def AbiTag : Attr {
let Args = [VariadicStringArgument<"Tags">];
let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag,
"ExpectedStructClassVariableFunctionOrInlineNamespace">;
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [AbiTagsDocs];
}
@@ -435,23 +567,19 @@ def AlwaysInline : InheritableAttr {
}
def XRayInstrument : InheritableAttr {
- let Spellings = [GNU<"xray_always_instrument">,
- CXX11<"clang", "xray_always_instrument">,
- GNU<"xray_never_instrument">,
- CXX11<"clang", "xray_never_instrument">];
+ let Spellings = [Clang<"xray_always_instrument">,
+ Clang<"xray_never_instrument">];
let Subjects = SubjectList<[CXXMethod, ObjCMethod, Function], WarnDiag,
"ExpectedFunctionOrMethod">;
let Accessors = [Accessor<"alwaysXRayInstrument",
- [GNU<"xray_always_instrument">,
- CXX11<"clang", "xray_always_instrument">]>,
+ [Clang<"xray_always_instrument">]>,
Accessor<"neverXRayInstrument",
- [GNU<"xray_never_instrument">,
- CXX11<"clang", "xray_never_instrument">]>];
+ [Clang<"xray_never_instrument">]>];
let Documentation = [XRayDocs];
}
def XRayLogArgs : InheritableAttr {
- let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">];
+ let Spellings = [Clang<"xray_log_args">];
let Subjects = SubjectList<
[CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod"
>;
@@ -474,13 +602,16 @@ def AnalyzerNoReturn : InheritableAttr {
def Annotate : InheritableParamAttr {
let Spellings = [GNU<"annotate">];
let Args = [StringArgument<"Annotation">];
+ // Ensure that the annotate attribute can be used with
+ // '#pragma clang attribute' even though it has no subject list.
+ let ForcePragmaAttributeSupport = 1;
let Documentation = [Undocumented];
}
def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
// NOTE: If you add any additional spellings, MSP430Interrupt's,
// MipsInterrupt's and AnyX86Interrupt's spellings must match.
- let Spellings = [GNU<"interrupt">];
+ let Spellings = [GCC<"interrupt">];
let Args = [EnumArgument<"Interrupt", "InterruptType",
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"],
@@ -491,14 +622,14 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
}
def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> {
- let Spellings = [GNU<"interrupt">];
+ let Spellings = [GCC<"interrupt">];
let Subjects = SubjectList<[Function]>;
let ParseKind = "Interrupt";
let Documentation = [AVRInterruptDocs];
}
def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
- let Spellings = [GNU<"signal">];
+ let Spellings = [GCC<"signal">];
let Subjects = SubjectList<[Function]>;
let Documentation = [AVRSignalDocs];
}
@@ -529,21 +660,44 @@ def Availability : InheritableAttr {
.Case("tvos_app_extension", "tvOS (App Extension)")
.Case("watchos_app_extension", "watchOS (App Extension)")
.Default(llvm::StringRef());
+}
+static llvm::StringRef getPlatformNameSourceSpelling(llvm::StringRef Platform) {
+ return llvm::StringSwitch<llvm::StringRef>(Platform)
+ .Case("ios", "iOS")
+ .Case("macos", "macOS")
+ .Case("tvos", "tvOS")
+ .Case("watchos", "watchOS")
+ .Case("ios_app_extension", "iOSApplicationExtension")
+ .Case("macos_app_extension", "macOSApplicationExtension")
+ .Case("tvos_app_extension", "tvOSApplicationExtension")
+ .Case("watchos_app_extension", "watchOSApplicationExtension")
+ .Default(Platform);
+}
+static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
+ return llvm::StringSwitch<llvm::StringRef>(Platform)
+ .Case("iOS", "ios")
+ .Case("macOS", "macos")
+ .Case("tvOS", "tvos")
+ .Case("watchOS", "watchos")
+ .Case("iOSApplicationExtension", "ios_app_extension")
+ .Case("macOSApplicationExtension", "macos_app_extension")
+ .Case("tvOSApplicationExtension", "tvos_app_extension")
+ .Case("watchOSApplicationExtension", "watchos_app_extension")
+ .Default(Platform);
} }];
let HasCustomParsing = 1;
let DuplicatesAllowedWhileMerging = 1;
-// let Subjects = SubjectList<[Named]>;
+ let Subjects = SubjectList<[Named]>;
let Documentation = [AvailabilityDocs];
}
def ExternalSourceSymbol : InheritableAttr {
- let Spellings = [GNU<"external_source_symbol">,
- CXX11<"clang", "external_source_symbol">];
+ let Spellings = [Clang<"external_source_symbol">];
let Args = [StringArgument<"language", 1>,
StringArgument<"definedIn", 1>,
BoolArgument<"generatedDeclaration", 1>];
let HasCustomParsing = 1;
-// let Subjects = SubjectList<[Named]>;
+ let Subjects = SubjectList<[Named]>;
let Documentation = [ExternalSourceSymbolDocs];
}
@@ -741,6 +895,13 @@ def OpenCLUnrollHint : InheritableAttr {
let Documentation = [OpenCLUnrollHintDocs];
}
+def OpenCLIntelReqdSubGroupSize: InheritableAttr {
+ let Spellings = [GNU<"intel_reqd_sub_group_size">];
+ let Args = [UnsignedArgument<"SubGroupSize">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [OpenCLIntelReqdSubGroupSizeDocs];
+}
+
// This attribute is both a type attribute, and a declaration attribute (for
// parameter variables).
def OpenCLAccess : Attr {
@@ -800,11 +961,12 @@ def RenderScriptKernel : Attr {
def Deprecated : InheritableAttr {
let Spellings = [GCC<"deprecated">, Declspec<"deprecated">,
- CXX11<"","deprecated", 201309>];
+ CXX11<"","deprecated", 201309>, C2x<"", "deprecated">];
let Args = [StringArgument<"Message", 1>,
// An optional string argument that enables us to provide a
// Fix-It.
StringArgument<"Replacement", 1>];
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [DeprecatedDocs];
}
@@ -846,7 +1008,7 @@ def ExtVectorType : Attr {
}
def FallThrough : StmtAttr {
- let Spellings = [CXX11<"", "fallthrough", 201603>,
+ let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">,
CXX11<"clang", "fallthrough">];
// let Subjects = [NullStmt];
let Documentation = [FallthroughDocs];
@@ -881,7 +1043,14 @@ def FlagEnum : InheritableAttr {
let Spellings = [GNU<"flag_enum">];
let Subjects = SubjectList<[Enum]>;
let Documentation = [FlagEnumDocs];
- let LangOpts = [COnly];
+}
+
+def EnumExtensibility : InheritableAttr {
+ let Spellings = [Clang<"enum_extensibility">];
+ let Subjects = SubjectList<[Enum]>;
+ let Args = [EnumArgument<"Extensibility", "Kind",
+ ["closed", "open"], ["Closed", "Open"]>];
+ let Documentation = [EnumExtensibilityDocs];
}
def Flatten : InheritableAttr {
@@ -987,23 +1156,23 @@ def MSABI : InheritableAttr {
def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
// NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's
// and AnyX86Interrupt's spellings must match.
- let Spellings = [GNU<"interrupt">];
+ let Spellings = [GCC<"interrupt">];
let Args = [UnsignedArgument<"Number">];
let ParseKind = "Interrupt";
let HasCustomParsing = 1;
let Documentation = [Undocumented];
}
-def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
+def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips32> {
let Spellings = [GCC<"mips16">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [Undocumented];
}
-def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
+def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips32> {
// NOTE: If you add any additional spellings, ARMInterrupt's,
// MSP430Interrupt's and AnyX86Interrupt's spellings must match.
- let Spellings = [GNU<"interrupt">];
+ let Spellings = [GCC<"interrupt">];
let Subjects = SubjectList<[Function]>;
let Args = [EnumArgument<"Interrupt", "InterruptType",
["vector=sw0", "vector=sw1", "vector=hw0",
@@ -1016,6 +1185,24 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
let Documentation = [MipsInterruptDocs];
}
+def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> {
+ let Spellings = [GCC<"micromips">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [MicroMipsDocs];
+}
+
+def MipsLongCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> {
+ let Spellings = [GCC<"long_call">, GCC<"far">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [MipsLongCallStyleDocs];
+}
+
+def MipsShortCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> {
+ let Spellings = [GCC<"short_call">, GCC<"near">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [MipsShortCallStyleDocs];
+}
+
def Mode : Attr {
let Spellings = [GCC<"mode">];
let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag,
@@ -1049,8 +1236,7 @@ def ReturnsTwice : InheritableAttr {
}
def DisableTailCalls : InheritableAttr {
- let Spellings = [GNU<"disable_tail_calls">,
- CXX11<"clang", "disable_tail_calls">];
+ let Spellings = [Clang<"disable_tail_calls">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let Documentation = [DisableTailCallsDocs];
}
@@ -1075,13 +1261,13 @@ def NoDebug : InheritableAttr {
}
def NoDuplicate : InheritableAttr {
- let Spellings = [GNU<"noduplicate">, CXX11<"clang", "noduplicate">];
+ let Spellings = [Clang<"noduplicate">];
let Subjects = SubjectList<[Function]>;
let Documentation = [NoDuplicateDocs];
}
def Convergent : InheritableAttr {
- let Spellings = [GNU<"convergent">, CXX11<"clang", "convergent">];
+ let Spellings = [Clang<"convergent">];
let Subjects = SubjectList<[Function]>;
let Documentation = [ConvergentDocs];
}
@@ -1092,12 +1278,18 @@ def NoInline : InheritableAttr {
let Documentation = [Undocumented];
}
-def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
+def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips32> {
let Spellings = [GCC<"nomips16">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [Undocumented];
}
+def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> {
+ let Spellings = [GCC<"nomicromips">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [MicroMipsDocs];
+}
+
// This is not a TargetSpecificAttr so that is silently accepted and
// ignored on other targets as encouraged by the OpenCL spec.
//
@@ -1205,6 +1397,12 @@ def ObjCKindOf : TypeAttr {
let Documentation = [Undocumented];
}
+def NoEscape : Attr {
+ let Spellings = [Clang<"noescape">];
+ let Subjects = SubjectList<[ParmVar]>;
+ let Documentation = [NoEscapeDocs];
+}
+
def AssumeAligned : InheritableAttr {
let Spellings = [GCC<"assume_aligned">];
let Subjects = SubjectList<[ObjCMethod, Function]>;
@@ -1212,6 +1410,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?
@@ -1225,14 +1431,15 @@ def NoInstrumentFunction : InheritableAttr {
}
def NotTailCalled : InheritableAttr {
- let Spellings = [GNU<"not_tail_called">, CXX11<"clang", "not_tail_called">];
+ let Spellings = [Clang<"not_tail_called">];
let Subjects = SubjectList<[Function]>;
let Documentation = [NotTailCalledDocs];
}
def NoThrow : InheritableAttr {
let Spellings = [GCC<"nothrow">, Declspec<"nothrow">];
- let Documentation = [Undocumented];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [NoThrowDocs];
}
def NvWeak : IgnoredAttr {
@@ -1386,7 +1593,7 @@ def ObjCBoxable : Attr {
}
def OptimizeNone : InheritableAttr {
- let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">];
+ let Spellings = [Clang<"optnone">];
let Subjects = SubjectList<[Function, ObjCMethod]>;
let Documentation = [OptnoneDocs];
}
@@ -1464,8 +1671,7 @@ def ReqdWorkGroupSize : InheritableAttr {
}
def RequireConstantInit : InheritableAttr {
- let Spellings = [GNU<"require_constant_initialization">,
- CXX11<"clang", "require_constant_initialization">];
+ let Spellings = [Clang<"require_constant_initialization">];
let Subjects = SubjectList<[GlobalVar], ErrorDiag,
"ExpectedStaticOrTLSVar">;
let Documentation = [RequireConstantInitDocs];
@@ -1482,7 +1688,7 @@ def WorkGroupSizeHint : InheritableAttr {
}
def InitPriority : InheritableAttr {
- let Spellings = [GNU<"init_priority">];
+ let Spellings = [GCC<"init_priority">];
let Args = [UnsignedArgument<"Priority">];
let Subjects = SubjectList<[Var], ErrorDiag>;
let Documentation = [Undocumented];
@@ -1497,6 +1703,42 @@ def Section : InheritableAttr {
let Documentation = [SectionDocs];
}
+def PragmaClangBSSSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
+def PragmaClangDataSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
+def PragmaClangRodataSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
+def PragmaClangTextSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[Function], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
def Sentinel : InheritableAttr {
let Spellings = [GCC<"sentinel">];
let Args = [DefaultIntArgument<"Sentinel", 0>,
@@ -1512,26 +1754,32 @@ def StdCall : InheritableAttr {
}
def SwiftCall : InheritableAttr {
- let Spellings = [GCC<"swiftcall">];
+ let Spellings = [GNU<"swiftcall">];
// let Subjects = SubjectList<[Function]>;
let Documentation = [SwiftCallDocs];
}
def SwiftContext : ParameterABIAttr {
- let Spellings = [GCC<"swift_context">];
+ let Spellings = [GNU<"swift_context">];
let Documentation = [SwiftContextDocs];
}
def SwiftErrorResult : ParameterABIAttr {
- let Spellings = [GCC<"swift_error_result">];
+ let Spellings = [GNU<"swift_error_result">];
let Documentation = [SwiftErrorResultDocs];
}
def SwiftIndirectResult : ParameterABIAttr {
- let Spellings = [GCC<"swift_indirect_result">];
+ let Spellings = [GNU<"swift_indirect_result">];
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];
@@ -1574,11 +1822,18 @@ def Target : InheritableAttr {
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [TargetDocs];
let AdditionalMembers = [{
- typedef std::pair<std::vector<std::string>, StringRef> ParsedTargetAttr;
+ struct ParsedTargetAttr {
+ std::vector<std::string> Features;
+ StringRef Architecture;
+ bool DuplicateArchitecture = false;
+ };
ParsedTargetAttr parse() const {
+ return parse(getFeaturesStr());
+ }
+ static ParsedTargetAttr parse(StringRef Features) {
ParsedTargetAttr Ret;
SmallVector<StringRef, 1> AttrFeatures;
- getFeaturesStr().split(AttrFeatures, ",");
+ Features.split(AttrFeatures, ",");
// Grab the various features and prepend a "+" to turn on the feature to
// the backend and add them to our existing set of features.
@@ -1595,12 +1850,15 @@ def Target : InheritableAttr {
continue;
// While we're here iterating check for a different target cpu.
- if (Feature.startswith("arch="))
- Ret.second = Feature.split("=").second.trim();
- else if (Feature.startswith("no-"))
- Ret.first.push_back("-" + Feature.split("-").second.str());
+ if (Feature.startswith("arch=")) {
+ if (!Ret.Architecture.empty())
+ Ret.DuplicateArchitecture = true;
+ else
+ Ret.Architecture = Feature.split("=").second.trim();
+ } else if (Feature.startswith("no-"))
+ Ret.Features.push_back("-" + Feature.split("-").second.str());
else
- Ret.first.push_back("+" + Feature.str());
+ Ret.Features.push_back("+" + Feature.str());
}
return Ret;
}
@@ -1630,14 +1888,14 @@ def Unavailable : InheritableAttr {
def DiagnoseIf : InheritableAttr {
let Spellings = [GNU<"diagnose_if">];
- let Subjects = SubjectList<[Function]>;
+ let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>;
let Args = [ExprArgument<"Cond">, StringArgument<"Message">,
EnumArgument<"DiagnosticType",
"DiagnosticType",
["error", "warning"],
["DT_Error", "DT_Warning"]>,
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
- FunctionArgument<"Parent", 0, /*fake*/ 1>];
+ NamedArgument<"Parent", 0, /*fake*/ 1>];
let DuplicatesAllowedWhileMerging = 1;
let LateParsed = 1;
let AdditionalMembers = [{
@@ -1674,7 +1932,8 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
}
def Unused : InheritableAttr {
- let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">];
+ let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">,
+ C2x<"", "maybe_unused">];
let Subjects = SubjectList<[Var, ObjCIvar, Type, Enum, EnumConstant, Label,
Field, ObjCMethod, FunctionLike], WarnDiag,
"ExpectedForMaybeUnused">;
@@ -1715,12 +1974,13 @@ def Visibility : InheritableAttr {
let Args = [EnumArgument<"Visibility", "VisibilityType",
["default", "hidden", "internal", "protected"],
["Default", "Hidden", "Hidden", "Protected"]>];
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [Undocumented];
}
def TypeVisibility : InheritableAttr {
let Clone = 0;
- let Spellings = [GNU<"type_visibility">, CXX11<"clang", "type_visibility">];
+ let Spellings = [Clang<"type_visibility">];
let Args = [EnumArgument<"Visibility", "VisibilityType",
["default", "hidden", "internal", "protected"],
["Default", "Hidden", "Hidden", "Protected"]>];
@@ -1735,16 +1995,16 @@ def VecReturn : InheritableAttr {
}
def WarnUnused : InheritableAttr {
- let Spellings = [GNU<"warn_unused">];
+ let Spellings = [GCC<"warn_unused">];
let Subjects = SubjectList<[Record]>;
let Documentation = [Undocumented];
}
def WarnUnusedResult : InheritableAttr {
- let Spellings = [CXX11<"", "nodiscard", 201603>,
+ let Spellings = [CXX11<"", "nodiscard", 201603>, C2x<"", "nodiscard">,
CXX11<"clang", "warn_unused_result">,
GCC<"warn_unused_result">];
- let Subjects = SubjectList<[ObjCMethod, Enum, CXXRecord, FunctionLike],
+ let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike],
WarnDiag, "ExpectedFunctionMethodEnumOrClass">;
let Documentation = [WarnUnusedResultsDocs];
}
@@ -1777,23 +2037,29 @@ def LTOVisibilityPublic : InheritableAttr {
def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
// NOTE: If you add any additional spellings, ARMInterrupt's,
// MSP430Interrupt's and MipsInterrupt's spellings must match.
- let Spellings = [GNU<"interrupt">];
+ let Spellings = [GCC<"interrupt">];
let Subjects = SubjectList<[HasFunctionProto]>;
let ParseKind = "Interrupt";
let HasCustomParsing = 1;
- let Documentation = [AnyX86InterruptDocs];
+ let Documentation = [Undocumented];
+}
+
+def AnyX86NoCallerSavedRegisters : InheritableAttr,
+ TargetSpecificAttr<TargetAnyX86> {
+ let Spellings = [GCC<"no_caller_saved_registers">];
+ let Documentation = [AnyX86NoCallerSavedRegistersDocs];
}
-def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
- let Spellings = [GNU<"force_align_arg_pointer">];
+def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
+ let Spellings = [GCC<"force_align_arg_pointer">];
// Technically, this appertains to a FunctionDecl, but the target-specific
// code silently allows anything function-like (such as typedefs or function
// pointers), but does not apply the attribute to them.
- let Documentation = [Undocumented];
+ let Documentation = [X86ForceAlignArgPointerDocs];
}
def NoSanitize : InheritableAttr {
- let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">];
+ let Spellings = [Clang<"no_sanitize">];
let Args = [VariadicStringArgument<"Sanitizers">];
let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar], ErrorDiag,
"ExpectedFunctionMethodOrGlobalVar">;
@@ -1855,15 +2121,12 @@ def ScopedLockable : InheritableAttr {
}
def Capability : InheritableAttr {
- let Spellings = [GNU<"capability">, CXX11<"clang", "capability">,
- GNU<"shared_capability">,
- CXX11<"clang", "shared_capability">];
+ let Spellings = [Clang<"capability">, Clang<"shared_capability">];
let Subjects = SubjectList<[Record, TypedefName], ErrorDiag,
"ExpectedStructOrUnionOrTypedef">;
let Args = [StringArgument<"Name">];
let Accessors = [Accessor<"isShared",
- [GNU<"shared_capability">,
- CXX11<"clang","shared_capability">]>];
+ [Clang<"shared_capability">]>];
let Documentation = [Undocumented];
let AdditionalMembers = [{
bool isMutex() const { return getName().equals_lower("mutex"); }
@@ -1872,27 +2135,22 @@ def Capability : InheritableAttr {
}
def AssertCapability : InheritableAttr {
- let Spellings = [GNU<"assert_capability">,
- CXX11<"clang", "assert_capability">,
- GNU<"assert_shared_capability">,
- CXX11<"clang", "assert_shared_capability">];
+ let Spellings = [Clang<"assert_capability">,
+ Clang<"assert_shared_capability">];
let Subjects = SubjectList<[Function]>;
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
- let Args = [ExprArgument<"Expr">];
+ let Args = [VariadicExprArgument<"Args">];
let Accessors = [Accessor<"isShared",
- [GNU<"assert_shared_capability">,
- CXX11<"clang", "assert_shared_capability">]>];
+ [Clang<"assert_shared_capability">]>];
let Documentation = [AssertCapabilityDocs];
}
def AcquireCapability : InheritableAttr {
- let Spellings = [GNU<"acquire_capability">,
- CXX11<"clang", "acquire_capability">,
- GNU<"acquire_shared_capability">,
- CXX11<"clang", "acquire_shared_capability">,
+ let Spellings = [Clang<"acquire_capability">,
+ Clang<"acquire_shared_capability">,
GNU<"exclusive_lock_function">,
GNU<"shared_lock_function">];
let Subjects = SubjectList<[Function]>;
@@ -1902,17 +2160,14 @@ def AcquireCapability : InheritableAttr {
let DuplicatesAllowedWhileMerging = 1;
let Args = [VariadicExprArgument<"Args">];
let Accessors = [Accessor<"isShared",
- [GNU<"acquire_shared_capability">,
- CXX11<"clang", "acquire_shared_capability">,
+ [Clang<"acquire_shared_capability">,
GNU<"shared_lock_function">]>];
let Documentation = [AcquireCapabilityDocs];
}
def TryAcquireCapability : InheritableAttr {
- let Spellings = [GNU<"try_acquire_capability">,
- CXX11<"clang", "try_acquire_capability">,
- GNU<"try_acquire_shared_capability">,
- CXX11<"clang", "try_acquire_shared_capability">];
+ let Spellings = [Clang<"try_acquire_capability">,
+ Clang<"try_acquire_shared_capability">];
let Subjects = SubjectList<[Function],
ErrorDiag>;
let LateParsed = 1;
@@ -1921,18 +2176,14 @@ def TryAcquireCapability : InheritableAttr {
let DuplicatesAllowedWhileMerging = 1;
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
let Accessors = [Accessor<"isShared",
- [GNU<"try_acquire_shared_capability">,
- CXX11<"clang", "try_acquire_shared_capability">]>];
+ [Clang<"try_acquire_shared_capability">]>];
let Documentation = [TryAcquireCapabilityDocs];
}
def ReleaseCapability : InheritableAttr {
- let Spellings = [GNU<"release_capability">,
- CXX11<"clang", "release_capability">,
- GNU<"release_shared_capability">,
- CXX11<"clang", "release_shared_capability">,
- GNU<"release_generic_capability">,
- CXX11<"clang", "release_generic_capability">,
+ let Spellings = [Clang<"release_capability">,
+ Clang<"release_shared_capability">,
+ Clang<"release_generic_capability">,
GNU<"unlock_function">];
let Subjects = SubjectList<[Function]>;
let LateParsed = 1;
@@ -1941,21 +2192,17 @@ def ReleaseCapability : InheritableAttr {
let DuplicatesAllowedWhileMerging = 1;
let Args = [VariadicExprArgument<"Args">];
let Accessors = [Accessor<"isShared",
- [GNU<"release_shared_capability">,
- CXX11<"clang", "release_shared_capability">]>,
+ [Clang<"release_shared_capability">]>,
Accessor<"isGeneric",
- [GNU<"release_generic_capability">,
- CXX11<"clang", "release_generic_capability">,
+ [Clang<"release_generic_capability">,
GNU<"unlock_function">]>];
let Documentation = [ReleaseCapabilityDocs];
}
def RequiresCapability : InheritableAttr {
- let Spellings = [GNU<"requires_capability">,
- CXX11<"clang", "requires_capability">,
+ let Spellings = [Clang<"requires_capability">,
GNU<"exclusive_locks_required">,
- GNU<"requires_shared_capability">,
- CXX11<"clang", "requires_shared_capability">,
+ Clang<"requires_shared_capability">,
GNU<"shared_locks_required">];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = 1;
@@ -1963,9 +2210,8 @@ def RequiresCapability : InheritableAttr {
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[Function]>;
- let Accessors = [Accessor<"isShared", [GNU<"requires_shared_capability">,
- GNU<"shared_locks_required">,
- CXX11<"clang","requires_shared_capability">]>];
+ let Accessors = [Accessor<"isShared", [Clang<"requires_shared_capability">,
+ GNU<"shared_locks_required">]>];
let Documentation = [Undocumented];
}
@@ -2215,9 +2461,8 @@ def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
}
def SelectAny : InheritableAttr {
- let Spellings = [Declspec<"selectany">];
- let LangOpts = [MicrosoftExt];
- let Documentation = [Undocumented];
+ let Spellings = [Declspec<"selectany">, GCC<"selectany">];
+ let Documentation = [SelectAnyDocs];
}
def Thread : Attr {
@@ -2429,6 +2674,14 @@ def OMPCaptureNoInit : InheritableAttr {
let Documentation = [Undocumented];
}
+def OMPCaptureKind : Attr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let SemaHandler = 0;
+ let Args = [UnsignedArgument<"CaptureKind">];
+ let Documentation = [Undocumented];
+}
+
def OMPDeclareSimdDecl : Attr {
let Spellings = [Pragma<"omp", "declare simd">];
let Subjects = SubjectList<[Function]>;
@@ -2515,7 +2768,7 @@ def OMPDeclareTargetDecl : Attr {
}
def InternalLinkage : InheritableAttr {
- let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
+ let Spellings = [Clang<"internal_linkage">];
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
let Documentation = [InternalLinkageDocs];
}
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index df299e07c6..ecff329c4c 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -7,6 +7,24 @@
//
//===---------------------------------------------------------------------===//
+// To test that the documentation builds cleanly, you must run clang-tblgen to
+// convert the .td file into a .rst file, and then run sphinx to convert the
+// .rst file into an HTML file. After completing testing, you should revert the
+// generated .rst file so that the modified version does not get checked in to
+// version control.
+//
+// To run clang-tblgen to generate the .rst file:
+// clang-tblgen -gen-attr-docs -I <root>/llvm/tools/clang/include
+// <root>/llvm/tools/clang/include/clang/Basic/Attr.td -o
+// <root>/llvm/tools/clang/docs/AttributeReference.rst
+//
+// To run sphinx to generate the .html files (note that sphinx-build must be
+// available on the PATH):
+// Windows (from within the clang\docs directory):
+// make.bat html
+// Non-Windows (from within the clang\docs directory):
+// make -f Makefile.sphinx html
+
def GlobalDocumentation {
code Intro =[{..
-------------------------------------------------------------------
@@ -112,6 +130,50 @@ members, and static locals.
}];
}
+def NoEscapeDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+``noescape`` placed on a function parameter of a pointer type is used to inform
+the compiler that the pointer cannot escape: that is, no reference to the object
+the pointer points to that is derived from the parameter value will survive
+after the function returns. Users are responsible for making sure parameters
+annotated with ``noescape`` do not actuallly escape.
+
+For example:
+
+.. code-block:: c
+
+ int *gp;
+
+ void nonescapingFunc(__attribute__((noescape)) int *p) {
+ *p += 100; // OK.
+ }
+
+ void escapingFunc(__attribute__((noescape)) int *p) {
+ gp = p; // Not OK.
+ }
+
+Additionally, when the parameter is a `block pointer
+<https://clang.llvm.org/docs/BlockLanguageSpec.html>`, the same restriction
+applies to copies of the block. For example:
+
+.. code-block:: c
+
+ typedef void (^BlockTy)();
+ BlockTy g0, g1;
+
+ void nonescapingFunc(__attribute__((noescape)) BlockTy block) {
+ block(); // OK.
+ }
+
+ void escapingFunc(__attribute__((noescape)) BlockTy block) {
+ g0 = block; // Not OK.
+ g1 = Block_copy(block); // Not OK either.
+ }
+
+ }];
+}
+
def CarriesDependencyDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -244,6 +306,36 @@ An example of how to use ``alloc_size``
}];
}
+def AllocAlignDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Use ``__attribute__((alloc_align(<alignment>))`` on a function
+declaration to specify that the return value of the function (which must be a
+pointer type) is at least as aligned as the value of the indicated parameter. The
+parameter is given by its index in the list of formal parameters; the first
+parameter has index 1 unless the function is a C++ non-static member function,
+in which case the first parameter has index 2 to account for the implicit ``this``
+parameter.
+
+.. code-block:: c++
+
+ // The returned pointer has the alignment specified by the first parameter.
+ void *a(size_t align) __attribute__((alloc_align(1)));
+
+ // The returned pointer has the alignment specified by the second parameter.
+ void *b(void *v, size_t align) __attribute__((alloc_align(2)));
+
+ // The returned pointer has the alignment specified by the second visible
+ // parameter, however it must be adjusted for the implicit 'this' parameter.
+ void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3)));
+
+Note that this attribute merely informs the compiler that a function always
+returns a sufficiently aligned pointer. It does not cause the compiler to
+emit code to enforce that alignment. The behavior is undefined if the returned
+poitner is not sufficiently aligned.
+ }];
+}
+
def EnableIfDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -575,20 +667,27 @@ semantics:
for ``T`` and ``U`` to be incompatible.
The declaration of ``overloadable`` functions is restricted to function
-declarations and definitions. Most importantly, if any function with a given
-name is given the ``overloadable`` attribute, then all function declarations
-and definitions with that name (and in that scope) must have the
-``overloadable`` attribute. This rule even applies to redeclarations of
-functions whose original declaration had the ``overloadable`` attribute, e.g.,
+declarations and definitions. If a function is marked with the ``overloadable``
+attribute, then all declarations and definitions of functions with that name,
+except for at most one (see the note below about unmarked overloads), must have
+the ``overloadable`` attribute. In addition, redeclarations of a function with
+the ``overloadable`` attribute must have the ``overloadable`` attribute, and
+redeclarations of a function without the ``overloadable`` attribute must *not*
+have the ``overloadable`` attribute. e.g.,
.. code-block:: c
int f(int) __attribute__((overloadable));
float f(float); // error: declaration of "f" must have the "overloadable" attribute
+ int f(int); // error: redeclaration of "f" must have the "overloadable" attribute
int g(int) __attribute__((overloadable));
int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute
+ int h(int);
+ int h(int) __attribute__((overloadable)); // error: declaration of "h" must not
+ // have the "overloadable" attribute
+
Functions marked ``overloadable`` must have prototypes. Therefore, the
following code is ill-formed:
@@ -621,7 +720,28 @@ caveats to this use of name mangling:
linkage specification, it's name *will* be mangled in the same way as it
would in C.
-Query for this feature with ``__has_extension(attribute_overloadable)``.
+For the purpose of backwards compatibility, at most one function with the same
+name as other ``overloadable`` functions may omit the ``overloadable``
+attribute. In this case, the function without the ``overloadable`` attribute
+will not have its name mangled.
+
+For example:
+
+.. code-block:: c
+
+ // Notes with mangled names assume Itanium mangling.
+ int f(int);
+ int f(double) __attribute__((overloadable));
+ void foo() {
+ f(5); // Emits a call to f (not _Z1fi, as it would with an overload that
+ // was marked with overloadable).
+ f(1.0); // Emits a call to _Z1fd.
+ }
+
+Support for unmarked overloads is not present in some versions of clang. You may
+query for it using ``__has_extension(overloadable_unmarked)``.
+
+Query for this attribute with ``__has_attribute(overloadable)``.
}];
}
@@ -852,13 +972,13 @@ the function declaration for a hypothetical function ``f``:
void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
-The availability attribute states that ``f`` was introduced in Mac OS X 10.4,
-deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information
+The availability attribute states that ``f`` was introduced in macOS 10.4,
+deprecated in macOS 10.6, and obsoleted in macOS 10.7. This information
is used by Clang to determine when it is safe to use ``f``: for example, if
-Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()``
-succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call
+Clang is instructed to compile code for macOS 10.5, a call to ``f()``
+succeeds. If Clang is instructed to compile code for macOS 10.6, the call
succeeds but Clang emits a warning specifying that the function is deprecated.
-Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call
+Finally, if Clang is instructed to compile code for macOS 10.7, the call
fails because ``f()`` is no longer available.
The availability attribute is a comma-separated list starting with the
@@ -903,7 +1023,7 @@ are:
command-line arguments.
``macos``
- Apple's Mac OS X operating system. The minimum deployment target is
+ Apple's macOS operating system. The minimum deployment target is
specified by the ``-mmacosx-version-min=*version*`` command-line argument.
``macosx`` is supported for backward-compatibility reasons, but it is
deprecated.
@@ -957,6 +1077,19 @@ When one method overrides another, the overriding method can be more widely avai
- (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later
- (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4
@end
+
+Starting with the macOS 10.12 SDK, the ``API_AVAILABLE`` macro from
+``<os/availability.h>`` can simplify the spelling:
+
+.. code-block:: objc
+
+ @interface A
+ - (id)method API_AVAILABLE(macos(10.11)));
+ - (id)otherMethod API_AVAILABLE(macos(10.11), ios(11.0));
+ @end
+
+Also see the documentation for `@available
+<http://clang.llvm.org/docs/LanguageExtensions.html#objective-c-available>`_
}];
}
@@ -1160,6 +1293,7 @@ Here is an example:
def ARMInterruptDocs : Documentation {
let Category = DocCatFunction;
+ let Heading = "interrupt (ARM)";
let Content = [{
Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on
ARM targets. This attribute may be attached to a function definition and
@@ -1201,6 +1335,7 @@ The semantics are as follows:
def MipsInterruptDocs : Documentation {
let Category = DocCatFunction;
+ let Heading = "interrupt (MIPS)";
let Content = [{
Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on
MIPS targets. This attribute may be attached to a function definition and instructs
@@ -1239,8 +1374,65 @@ The semantics are as follows:
}];
}
+def MicroMipsDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((micromips))`` and
+``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes
+may be attached to a function definition and instructs the backend to generate
+or not to generate microMIPS code for that function.
+
+These attributes override the `-mmicromips` and `-mno-micromips` options
+on the command line.
+ }];
+}
+
+def MipsLongCallStyleDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "long_call (gnu::long_call, gnu::far)";
+ let Content = [{
+Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``,
+and ``__attribute__((near))`` attributes on MIPS targets. These attributes may
+only be added to function declarations and change the code generated
+by the compiler when directly calling the function. The ``near`` attribute
+allows calls to the function to be made using the ``jal`` instruction, which
+requires the function to be located in the same naturally aligned 256MB
+segment as the caller. The ``long_call`` and ``far`` attributes are synonyms
+and require the use of a different call sequence that works regardless
+of the distance between the functions.
+
+These attributes have no effect for position-independent code.
+
+These attributes take priority over command line switches such
+as ``-mlong-calls`` and ``-mno-long-calls``.
+ }];
+}
+
+def MipsShortCallStyleDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "short_call (gnu::short_call, gnu::near)";
+ let Content = [{
+Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``,
+``__attribute__((short__call))``, and ``__attribute__((near))`` attributes
+on MIPS targets. These attributes may only be added to function declarations
+and change the code generated by the compiler when directly calling
+the function. The ``short_call`` and ``near`` attributes are synonyms and
+allow calls to the function to be made using the ``jal`` instruction, which
+requires the function to be located in the same naturally aligned 256MB segment
+as the caller. The ``long_call`` and ``far`` attributes are synonyms and
+require the use of a different call sequence that works regardless
+of the distance between the functions.
+
+These attributes have no effect for position-independent code.
+
+These attributes take priority over command line switches such
+as ``-mlong-calls`` and ``-mno-long-calls``.
+ }];
+}
+
def AVRInterruptDocs : Documentation {
let Category = DocCatFunction;
+ let Heading = "interrupt (AVR)";
let Content = [{
Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
AVR targets. This attribute may be attached to a function definition and instructs
@@ -1963,6 +2155,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 = [{
@@ -2137,6 +2378,21 @@ s6.11.5 for details.
}];
}
+def OpenCLIntelReqdSubGroupSizeDocs : Documentation {
+ let Category = DocCatStmt;
+ let Heading = "__attribute__((intel_reqd_sub_group_size))";
+ let Content = [{
+The optional attribute intel_reqd_sub_group_size can be used to indicate that
+the kernel must be compiled and executed with the specified subgroup size. When
+this attribute is present, get_max_sub_group_size() is guaranteed to return the
+specified integer value. This is important for the correctness of many subgroup
+algorithms, and in some cases may be used by the compiler to generate more optimal
+code. See `cl_intel_required_subgroup_size
+<https://www.khronos.org/registry/OpenCL/extensions/intel/cl_intel_required_subgroup_size.txt>`
+for details.
+ }];
+}
+
def OpenCLAccessDocs : Documentation {
let Category = DocCatStmt;
let Heading = "__read_only, __write_only, __read_write (read_only, write_only, read_write)";
@@ -2477,6 +2733,18 @@ Marking virtual functions as ``not_tail_called`` is an error:
}];
}
+def NoThrowDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((nothrow))`` and Microsoft style
+``__declspec(nothrow)`` attribute as an equivilent of `noexcept` on function
+declarations. This attribute informs the compiler that the annotated function
+does not throw an exception. This prevents exception-unwinding. This attribute
+is particularly useful on functions in the C Standard Library that are
+guaranteed to not throw an exception.
+ }];
+}
+
def InternalLinkageDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -2525,56 +2793,62 @@ Marking virtual functions as ``disable_tail_calls`` is legal.
}];
}
-def AnyX86InterruptDocs : Documentation {
+def AnyX86NoCallerSavedRegistersDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
-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.
+Use this attribute to indicate that the specified function has no
+caller-saved registers. That is, all registers are callee-saved except for
+registers used for passing parameters to the function or returning parameters
+from the function.
+The compiler saves and restores any modified registers that were not used for
+passing or returning arguments to the function.
-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.
+The user can call functions specified with the 'no_caller_saved_registers'
+attribute from an interrupt handler without saving and restoring all
+call-clobbered registers.
-1. interrupt handler must be declared with a mandatory pointer argument:
+Note that 'no_caller_saved_registers' attribute is not a calling convention.
+In fact, it only overrides the decision of which registers should be saved by
+the caller, but not how the parameters are passed from the caller to the callee.
- .. code-block:: c
+For example:
- struct interrupt_frame
- {
- uword_t ip;
- uword_t cs;
- uword_t flags;
- uword_t sp;
- uword_t ss;
- };
+ .. code-block:: c
- __attribute__ ((interrupt))
- void f (struct interrupt_frame *frame) {
+ __attribute__ ((no_caller_saved_registers, fastcall))
+ void f (int arg1, int arg2) {
...
}
-2. exception handler:
+ In this case parameters 'arg1' and 'arg2' will be passed in registers.
+ In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as
+ register parameters. However, it will not assume any scratch registers and
+ should save and restore any modified registers except for ECX and EDX.
+ }];
+}
- The exception handler is very similar to the interrupt handler with
- a different mandatory function signature:
+def X86ForceAlignArgPointerDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Use this attribute to force stack alignment.
+
+Legacy x86 code uses 4-byte stack alignment. Newer aligned SSE instructions
+(like 'movaps') that work with the stack require operands to be 16-byte aligned.
+This attribute realigns the stack in the function prologue to make sure the
+stack can be used with SSE instructions.
+
+Note that the x86_64 ABI forces 16-byte stack alignment at the call site.
+Because of this, 'force_align_arg_pointer' is not needed on x86_64, except in
+rare cases where the caller does not align the stack properly (e.g. flow
+jumps from i386 arch code).
.. code-block:: c
- __attribute__ ((interrupt))
- void f (struct interrupt_frame *frame, uword_t error_code) {
+ __attribute__ ((force_align_arg_pointer))
+ void f () {
...
}
- 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.
}];
}
@@ -2722,6 +2996,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 = [{
@@ -2898,3 +3198,18 @@ This attribute can be added to an Objective-C ``@interface`` declaration to
ensure that this class cannot be subclassed.
}];
}
+
+
+def SelectAnyDocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+This attribute appertains to a global symbol, causing it to have a weak
+definition (
+`linkonce <https://llvm.org/docs/LangRef.html#linkage-types>`_
+), allowing the linker to select any definition.
+
+For more information see
+`gcc documentation <https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Microsoft-Windows-Variable-Attributes.html>`_
+or `msvc documentation <https://docs.microsoft.com/pl-pl/cpp/cpp/selectany>`_.
+}];
+}
diff --git a/include/clang/Basic/AttrSubjectMatchRules.h b/include/clang/Basic/AttrSubjectMatchRules.h
new file mode 100644
index 0000000000..4c88adf57f
--- /dev/null
+++ b/include/clang/Basic/AttrSubjectMatchRules.h
@@ -0,0 +1,32 @@
+//===-- AttrSubjectMatchRules.h - Attribute subject match rules -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
+#define LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+namespace attr {
+
+/// \brief A list of all the recognized kinds of attributes.
+enum SubjectMatchRule {
+#define ATTR_MATCH_RULE(X, Spelling, IsAbstract) X,
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+};
+
+const char *getSubjectMatchRuleSpelling(SubjectMatchRule Rule);
+
+using ParsedSubjectMatchRuleSet = llvm::DenseMap<int, SourceRange>;
+
+} // end namespace attr
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/Attributes.h b/include/clang/Basic/Attributes.h
index ea9e28ae68..c651abacd4 100644
--- a/include/clang/Basic/Attributes.h
+++ b/include/clang/Basic/Attributes.h
@@ -26,6 +26,8 @@ enum class AttrSyntax {
Microsoft,
// Is the identifier known as a C++-style attribute?
CXX,
+ // Is the identifier known as a C-style attribute?
+ C,
// Is the identifier known as a pragma attribute?
Pragma
};
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index e7084de9ce..8e276e8445 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -52,6 +52,7 @@
// LL -> long long
// LLL -> __int128_t (e.g. LLLi)
// W -> int64_t
+// N -> 'int' size if target is LP64, 'L' otherwise.
// S -> signed
// U -> unsigned
// I -> Required to constant fold to an integer constant expression.
@@ -699,6 +700,21 @@ BUILTIN(__atomic_signal_fence, "vi", "n")
BUILTIN(__atomic_always_lock_free, "izvCD*", "n")
BUILTIN(__atomic_is_lock_free, "izvCD*", "n")
+// OpenCL 2.0 atomic builtins.
+ATOMIC_BUILTIN(__opencl_atomic_init, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_load, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_store, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_exchange, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_strong, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_compare_exchange_weak, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_fetch_add, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_fetch_sub, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_fetch_and, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_fetch_or, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_fetch_xor, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_fetch_min, "v.", "t")
+ATOMIC_BUILTIN(__opencl_atomic_fetch_max, "v.", "t")
+
#undef ATOMIC_BUILTIN
// Non-overloaded atomic builtins.
@@ -716,13 +732,14 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
// Microsoft builtins. These are only active with -fms-extensions.
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__annotation, "wC*.","n", ALL_MS_LANGUAGES)
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
-LIBBUILTIN(_byteswap_ulong, "ULiULi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
+LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
LIBBUILTIN(_byteswap_uint64, "ULLiULLi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__exception_code, "UNi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_exception_code, "UNi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
@@ -730,47 +747,47 @@ LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedAnd8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedAnd16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedAnd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedAnd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange8, "ccD*cc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedExchange, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchange8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchange16, "ssD*s", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeAdd8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeAdd16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedExchangeAdd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeSub8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeSub16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedExchangeSub, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedExchangeSub, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedIncrement16, "ssD*", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedIncrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedOr8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedOr16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedOr, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedOr, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedXor, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedXor, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt64, "ULLiULLi", "nc", ALL_MS_LANGUAGES)
-LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl, "UiUii", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_lrotl, "ULiULii", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_lrotl, "UNiUNii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr8, "UcUcUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr16, "UsUsUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_lrotr, "UNiUNii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES)
@@ -991,9 +1008,9 @@ LIBBUILTIN(modf, "ddd*", "fn", "math.h", ALL_LANGUAGES)
LIBBUILTIN(modff, "fff*", "fn", "math.h", ALL_LANGUAGES)
LIBBUILTIN(modfl, "LdLdLd*", "fn", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(nan, "dcC*", "fnc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(nanf, "fcC*", "fnc", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(nanl, "LdcC*", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nan, "dcC*", "fUn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nanf, "fcC*", "fUn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(nanl, "LdcC*", "fUn", "math.h", ALL_LANGUAGES)
LIBBUILTIN(pow, "ddd", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(powf, "fff", "fne", "math.h", ALL_LANGUAGES)
@@ -1397,18 +1414,37 @@ LANGBUILTIN(get_pipe_max_packets, "Ui.", "tn", OCLC20_LANG)
// OpenCL v2.0 s6.13.17 - Enqueue kernel functions.
// Custom builtin check allows to perform special check of passed block arguments.
LANGBUILTIN(enqueue_kernel, "i.", "tn", OCLC20_LANG)
-LANGBUILTIN(get_kernel_work_group_size, "i.", "tn", OCLC20_LANG)
-LANGBUILTIN(get_kernel_preferred_work_group_size_multiple, "i.", "tn", OCLC20_LANG)
+LANGBUILTIN(get_kernel_work_group_size, "Ui.", "tn", OCLC20_LANG)
+LANGBUILTIN(get_kernel_preferred_work_group_size_multiple, "Ui.", "tn", OCLC20_LANG)
+LANGBUILTIN(get_kernel_max_sub_group_size_for_ndrange, "Ui.", "tn", OCLC20_LANG)
+LANGBUILTIN(get_kernel_sub_group_count_for_ndrange, "Ui.", "tn", OCLC20_LANG)
// OpenCL v2.0 s6.13.9 - Address space qualifier functions.
LANGBUILTIN(to_global, "v*v*", "tn", OCLC20_LANG)
LANGBUILTIN(to_local, "v*v*", "tn", OCLC20_LANG)
LANGBUILTIN(to_private, "v*v*", "tn", OCLC20_LANG)
+// OpenCL half load/store builtin
+LANGBUILTIN(__builtin_store_half, "vdh*", "n", ALL_OCLC_LANGUAGES)
+LANGBUILTIN(__builtin_store_halff, "vfh*", "n", ALL_OCLC_LANGUAGES)
+LANGBUILTIN(__builtin_load_half, "dhC*", "nc", ALL_OCLC_LANGUAGES)
+LANGBUILTIN(__builtin_load_halff, "fhC*", "nc", ALL_OCLC_LANGUAGES)
+
// Builtins for os_log/os_trace
BUILTIN(__builtin_os_log_format_buffer_size, "zcC*.", "p:0:nut")
BUILTIN(__builtin_os_log_format, "v*v*cC*.", "p:0:nt")
+// OpenMP 4.0
+LANGBUILTIN(omp_is_initial_device, "i", "nc", OMP_LANG)
+
+// Builtins for XRay
+BUILTIN(__xray_customevent, "vcC*z", "")
+
+// Win64-compatible va_list functions
+BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
+BUILTIN(__builtin_ms_va_end, "vc*&", "n")
+BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n")
+
#undef BUILTIN
#undef LIBBUILTIN
#undef LANGBUILTIN
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index 87c1f93eed..963c72ea82 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -36,10 +36,13 @@ enum LanguageID {
CXX_LANG = 0x4, // builtin for cplusplus only.
OBJC_LANG = 0x8, // builtin for objective-c and objective-c++
MS_LANG = 0x10, // builtin requires MS mode.
- OCLC20_LANG = 0x20, // builtin for OpenCL C only.
+ OCLC20_LANG = 0x20, // builtin for OpenCL C 2.0 only.
+ OCLC1X_LANG = 0x40, // builtin for OpenCL C 1.x only.
+ OMP_LANG = 0x80, // builtin requires OpenMP.
ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages.
ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode.
- ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode.
+ ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG, // builtin requires MS mode.
+ ALL_OCLC_LANGUAGES = OCLC1X_LANG | OCLC20_LANG // builtin for OCLC languages.
};
namespace Builtin {
diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def
index 1db4c14710..55a4f70176 100644
--- a/include/clang/Basic/BuiltinsAArch64.def
+++ b/include/clang/Basic/BuiltinsAArch64.def
@@ -14,6 +14,10 @@
// The format of this database matches clang/Basic/Builtins.def.
+#if defined(BUILTIN) && !defined(LANGBUILTIN)
+# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
// In libgcc
BUILTIN(__clear_cache, "vv*v*", "i")
@@ -61,4 +65,9 @@ BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc")
BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc")
BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
+LANGBUILTIN(__dmb, "vUi", "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__dsb, "vUi", "nc", ALL_MS_LANGUAGES)
+LANGBUILTIN(__isb, "vUi", "nc", ALL_MS_LANGUAGES)
+
#undef BUILTIN
+#undef LANGBUILTIN
diff --git a/include/clang/Basic/BuiltinsAMDGPU.def b/include/clang/Basic/BuiltinsAMDGPU.def
index a8ab657c37..ec6a0fb917 100644
--- a/include/clang/Basic/BuiltinsAMDGPU.def
+++ b/include/clang/Basic/BuiltinsAMDGPU.def
@@ -21,6 +21,7 @@
// SI+ only builtins.
//===----------------------------------------------------------------------===//
+BUILTIN(__builtin_amdgcn_dispatch_ptr, "Uc*2", "nc")
BUILTIN(__builtin_amdgcn_kernarg_segment_ptr, "Uc*2", "nc")
BUILTIN(__builtin_amdgcn_implicitarg_ptr, "Uc*2", "nc")
@@ -36,6 +37,7 @@ BUILTIN(__builtin_amdgcn_workitem_id_z, "Ui", "nc")
// Instruction builtins.
//===----------------------------------------------------------------------===//
BUILTIN(__builtin_amdgcn_s_getreg, "UiIi", "n")
+BUILTIN(__builtin_amdgcn_s_getpc, "LUi", "n")
BUILTIN(__builtin_amdgcn_s_waitcnt, "vIi", "n")
BUILTIN(__builtin_amdgcn_s_sendmsg, "vIiUi", "n")
BUILTIN(__builtin_amdgcn_s_sendmsghalt, "vIiUi", "n")
@@ -119,6 +121,8 @@ TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts")
// Special builtins.
//===----------------------------------------------------------------------===//
BUILTIN(__builtin_amdgcn_read_exec, "LUi", "nc")
+BUILTIN(__builtin_amdgcn_read_exec_lo, "Ui", "nc")
+BUILTIN(__builtin_amdgcn_read_exec_hi, "Ui", "nc")
//===----------------------------------------------------------------------===//
// R600-NI only builtins.
diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def
index 6cc7308d4c..4e277f8a5a 100644
--- a/include/clang/Basic/BuiltinsARM.def
+++ b/include/clang/Basic/BuiltinsARM.def
@@ -25,11 +25,93 @@
// In libgcc
BUILTIN(__clear_cache, "vv*v*", "i")
+// 16-bit multiplications
+BUILTIN(__builtin_arm_smulbb, "iii", "nc")
+BUILTIN(__builtin_arm_smulbt, "iii", "nc")
+BUILTIN(__builtin_arm_smultb, "iii", "nc")
+BUILTIN(__builtin_arm_smultt, "iii", "nc")
+BUILTIN(__builtin_arm_smulwb, "iii", "nc")
+BUILTIN(__builtin_arm_smulwt, "iii", "nc")
+
// Saturating arithmetic
BUILTIN(__builtin_arm_qadd, "iii", "nc")
BUILTIN(__builtin_arm_qsub, "iii", "nc")
BUILTIN(__builtin_arm_ssat, "iiUi", "nc")
-BUILTIN(__builtin_arm_usat, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usat, "UiiUi", "nc")
+
+BUILTIN(__builtin_arm_smlabb, "iiii", "nc")
+BUILTIN(__builtin_arm_smlabt, "iiii", "nc")
+BUILTIN(__builtin_arm_smlatb, "iiii", "nc")
+BUILTIN(__builtin_arm_smlatt, "iiii", "nc")
+BUILTIN(__builtin_arm_smlawb, "iiii", "nc")
+BUILTIN(__builtin_arm_smlawt, "iiii", "nc")
+
+BUILTIN(__builtin_arm_ssat16, "iii", "nc")
+BUILTIN(__builtin_arm_usat16, "iii", "nc")
+
+BUILTIN(__builtin_arm_sxtab16, "iii", "nc")
+BUILTIN(__builtin_arm_sxtb16, "ii", "nc")
+BUILTIN(__builtin_arm_uxtab16, "iii", "nc")
+BUILTIN(__builtin_arm_uxtb16, "ii", "nc")
+
+BUILTIN(__builtin_arm_sel, "iii", "nc")
+
+BUILTIN(__builtin_arm_qadd8, "iii", "nc")
+BUILTIN(__builtin_arm_qsub8, "iii", "nc")
+BUILTIN(__builtin_arm_sadd8, "iii", "nc")
+BUILTIN(__builtin_arm_shadd8, "iii", "nc")
+BUILTIN(__builtin_arm_shsub8, "iii", "nc")
+BUILTIN(__builtin_arm_ssub8, "iii", "nc")
+BUILTIN(__builtin_arm_uadd8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhadd8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhsub8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqadd8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqsub8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usub8, "UiUiUi", "nc")
+
+// Sum of 8-bit absolute differences
+BUILTIN(__builtin_arm_usad8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usada8, "UiUiUiUi", "nc")
+
+// Parallel 16-bit addition and subtraction
+BUILTIN(__builtin_arm_qadd16, "iii", "nc")
+BUILTIN(__builtin_arm_qasx, "iii", "nc")
+BUILTIN(__builtin_arm_qsax, "iii", "nc")
+BUILTIN(__builtin_arm_qsub16, "iii", "nc")
+BUILTIN(__builtin_arm_sadd16, "iii", "nc")
+BUILTIN(__builtin_arm_sasx, "iii", "nc")
+BUILTIN(__builtin_arm_shadd16, "iii", "nc")
+BUILTIN(__builtin_arm_shasx, "iii", "nc")
+BUILTIN(__builtin_arm_shsax, "iii", "nc")
+BUILTIN(__builtin_arm_shsub16, "iii", "nc")
+BUILTIN(__builtin_arm_ssax, "iii", "nc")
+BUILTIN(__builtin_arm_ssub16, "iii", "nc")
+BUILTIN(__builtin_arm_uadd16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uasx, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhadd16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhasx, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhsax, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhsub16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqadd16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqasx, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqsax, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqsub16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usax, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usub16, "UiUiUi", "nc")
+
+// Parallel 16-bit multiplication
+BUILTIN(__builtin_arm_smlad, "iiii", "nc")
+BUILTIN(__builtin_arm_smladx, "iiii", "nc")
+BUILTIN(__builtin_arm_smlald, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smlaldx, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smlsd, "iiii", "nc")
+BUILTIN(__builtin_arm_smlsdx, "iiii", "nc")
+BUILTIN(__builtin_arm_smlsld, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smlsldx, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smuad, "iii", "nc")
+BUILTIN(__builtin_arm_smuadx, "iii", "nc")
+BUILTIN(__builtin_arm_smusd, "iii", "nc")
+BUILTIN(__builtin_arm_smusdx, "iii", "nc")
// Bit manipulation
BUILTIN(__builtin_arm_rbit, "UiUi", "nc")
@@ -133,10 +215,10 @@ LANGBUILTIN(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
-TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
diff --git a/include/clang/Basic/BuiltinsHexagon.def b/include/clang/Basic/BuiltinsHexagon.def
index 85936cbfc0..14fc4adc25 100644
--- a/include/clang/Basic/BuiltinsHexagon.def
+++ b/include/clang/Basic/BuiltinsHexagon.def
@@ -882,6 +882,12 @@ BUILTIN(__builtin_HEXAGON_S2_ct0p,"iLLi","")
BUILTIN(__builtin_HEXAGON_S2_ct1p,"iLLi","")
BUILTIN(__builtin_HEXAGON_S2_interleave,"LLiLLi","")
BUILTIN(__builtin_HEXAGON_S2_deinterleave,"LLiLLi","")
+BUILTIN(__builtin_HEXAGON_Y2_dccleana,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y2_dccleaninva,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y2_dcinva,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y2_dczeroa,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y4_l2fetch,"vv*Ui","")
+BUILTIN(__builtin_HEXAGON_Y5_l2fetch,"vv*LLUi","")
BUILTIN(__builtin_HEXAGON_S6_rol_i_r,"iii","v:60:")
BUILTIN(__builtin_HEXAGON_S6_rol_i_p,"LLiLLii","v:60:")
diff --git a/include/clang/Basic/BuiltinsNVPTX.def b/include/clang/Basic/BuiltinsNVPTX.def
index afea6cb0f1..caa860480f 100644
--- a/include/clang/Basic/BuiltinsNVPTX.def
+++ b/include/clang/Basic/BuiltinsNVPTX.def
@@ -378,6 +378,9 @@ BUILTIN(__nvvm_bar0_popc, "ii", "")
BUILTIN(__nvvm_bar0_and, "ii", "")
BUILTIN(__nvvm_bar0_or, "ii", "")
BUILTIN(__nvvm_bar_sync, "vi", "n")
+TARGET_BUILTIN(__nvvm_bar_warp_sync, "vUi", "n", "ptx60")
+TARGET_BUILTIN(__nvvm_barrier_sync, "vUi", "n", "ptx60")
+TARGET_BUILTIN(__nvvm_barrier_sync_cnt, "vUiUi", "n", "ptx60")
// Shuffle
@@ -390,6 +393,33 @@ BUILTIN(__nvvm_shfl_bfly_f32, "ffii", "")
BUILTIN(__nvvm_shfl_idx_i32, "iiii", "")
BUILTIN(__nvvm_shfl_idx_f32, "ffii", "")
+TARGET_BUILTIN(__nvvm_shfl_sync_down_i32, "iUiiii", "", "ptx60")
+TARGET_BUILTIN(__nvvm_shfl_sync_down_f32, "fUifii", "", "ptx60")
+TARGET_BUILTIN(__nvvm_shfl_sync_up_i32, "iUiiii", "", "ptx60")
+TARGET_BUILTIN(__nvvm_shfl_sync_up_f32, "fUifii", "", "ptx60")
+TARGET_BUILTIN(__nvvm_shfl_sync_bfly_i32, "iUiiii", "", "ptx60")
+TARGET_BUILTIN(__nvvm_shfl_sync_bfly_f32, "fUifii", "", "ptx60")
+TARGET_BUILTIN(__nvvm_shfl_sync_idx_i32, "iUiiii", "", "ptx60")
+TARGET_BUILTIN(__nvvm_shfl_sync_idx_f32, "fUifii", "", "ptx60")
+
+// Vote
+BUILTIN(__nvvm_vote_all, "bb", "")
+BUILTIN(__nvvm_vote_any, "bb", "")
+BUILTIN(__nvvm_vote_uni, "bb", "")
+BUILTIN(__nvvm_vote_ballot, "Uib", "")
+
+TARGET_BUILTIN(__nvvm_vote_all_sync, "bUib", "", "ptx60")
+TARGET_BUILTIN(__nvvm_vote_any_sync, "bUib", "", "ptx60")
+TARGET_BUILTIN(__nvvm_vote_uni_sync, "bUib", "", "ptx60")
+TARGET_BUILTIN(__nvvm_vote_ballot_sync, "UiUib", "", "ptx60")
+
+// Match
+TARGET_BUILTIN(__nvvm_match_any_sync_i32, "UiUiUi", "", "ptx60")
+TARGET_BUILTIN(__nvvm_match_any_sync_i64, "WiUiWi", "", "ptx60")
+// These return a pair {value, predicate}, which requires custom lowering.
+TARGET_BUILTIN(__nvvm_match_all_sync_i32p, "UiUiUii*", "", "ptx60")
+TARGET_BUILTIN(__nvvm_match_all_sync_i64p, "WiUiWii*", "", "ptx60")
+
// Membar
BUILTIN(__nvvm_membar_cta, "v", "")
@@ -658,5 +688,18 @@ BUILTIN(__nvvm_ldg_f2, "E2fE2fC*", "")
BUILTIN(__nvvm_ldg_f4, "E4fE4fC*", "")
BUILTIN(__nvvm_ldg_d2, "E2dE2dC*", "")
+// Builtins to support WMMA instructions on sm_70
+TARGET_BUILTIN(__hmma_m16n16k16_ld_a, "vi*iC*UiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_ld_b, "vi*iC*UiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_ld_c_f16, "vi*iC*UiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_ld_c_f32, "vf*fC*UiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_st_c_f16, "vi*i*UiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_st_c_f32, "vf*f*UiIi", "", "ptx60")
+
+TARGET_BUILTIN(__hmma_m16n16k16_mma_f16f16, "vi*iC*iC*iC*IiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_mma_f32f16, "vf*iC*iC*iC*IiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_mma_f32f32, "vf*iC*iC*fC*IiIi", "", "ptx60")
+TARGET_BUILTIN(__hmma_m16n16k16_mma_f16f32, "vi*iC*iC*fC*IiIi", "", "ptx60")
+
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/include/clang/Basic/BuiltinsNios2.def b/include/clang/Basic/BuiltinsNios2.def
new file mode 100644
index 0000000000..d9697e795c
--- /dev/null
+++ b/include/clang/Basic/BuiltinsNios2.def
@@ -0,0 +1,70 @@
+//===-- BuiltinsNios2.def - Nios2 Builtin function database --------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Nios2-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
+# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+// Nios2 R1 builtins:
+
+//int __builtin_ldbio(volatile const void *);
+BUILTIN(__builtin_ldbio, "ivDC*", "")
+//int __builtin_ldbuio(volatile const void *);
+BUILTIN(__builtin_ldbuio, "ivDC*", "")
+//int __builtin_ldhio(volatile const void *);
+BUILTIN(__builtin_ldhio, "ivDC*", "")
+//int __builtin_ldhuio(volatile const void *);
+BUILTIN(__builtin_ldhuio, "ivDC*", "")
+//int __builtin_ldwio(volatile const void *);
+BUILTIN(__builtin_ldwio, "ivDC*", "")
+//int __builtin_ldwuio(int);
+BUILTIN(__builtin_ldwuio, "ii", "")
+// int __builtin_rdctl(int);
+BUILTIN(__builtin_rdctl, "iIi", "")
+// void __builtin_wrctl(int, int);
+BUILTIN(__builtin_wrctl, "vIii", "")
+// int __builtin_rdprs(int, int);
+BUILTIN(__builtin_rdprs, "iii", "")
+//void __builtin_stbio(volatile void *, int);
+BUILTIN(__builtin_stbio, "vvD*i", "")
+//void __builtin_sthio(volatile void *, int);
+BUILTIN(__builtin_sthio, "vvD*i", "")
+//void __builtin_stwio(volatile void *, int);
+BUILTIN(__builtin_stwio, "vvD*i", "")
+//void __builtin_sync(void);
+BUILTIN(__builtin_sync, "v", "")
+// void __builtin_flushd(volatile void *);
+BUILTIN(__builtin_flushd, "vvD*", "")
+// void __builtin_flushda(volatile void *);
+BUILTIN(__builtin_flushda, "vvD*", "")
+
+// Nios2 R2 builtins:
+
+// int __builtin_wrpie(int);
+TARGET_BUILTIN(__builtin_wrpie, "ii", "", "nios2r2mandatory")
+// void __builtin_eni(int);
+TARGET_BUILTIN(__builtin_eni, "vi", "", "nios2r2mandatory")
+// int __builtin_ldex(volatile const void *);
+TARGET_BUILTIN(__builtin_ldex, "ivDC*", "", "nios2r2mandatory")
+// int __builtin_stex(volatile void *, int);
+TARGET_BUILTIN(__builtin_stex, "ivD*i", "", "nios2r2mandatory")
+// int __builtin_ldsex(volatile const void *);
+TARGET_BUILTIN(__builtin_ldsex, "ivDC*", "", "nios2r2mpx")
+// int __builtin_stsex(volatile void *, int);
+TARGET_BUILTIN(__builtin_stsex, "ivDC*i", "", "nios2r2mpx")
+
+#undef BUILTIN
+#undef TARGET_BUILTIN
diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def
index f7cddc0313..faa70a48ed 100644
--- a/include/clang/Basic/BuiltinsPPC.def
+++ b/include/clang/Basic/BuiltinsPPC.def
@@ -51,10 +51,10 @@ BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "")
BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "")
-BUILTIN(__builtin_altivec_vcfsx, "V4fV4ii", "")
-BUILTIN(__builtin_altivec_vcfux, "V4fV4ii", "")
-BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fi", "")
-BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "")
+BUILTIN(__builtin_altivec_vcfsx, "V4fV4iIi", "")
+BUILTIN(__builtin_altivec_vcfux, "V4fV4iIi", "")
+BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "")
+BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "")
BUILTIN(__builtin_altivec_dss, "vUi", "")
BUILTIN(__builtin_altivec_dssall, "v", "")
@@ -420,6 +420,9 @@ BUILTIN(__builtin_vsx_xvtstdcsp, "V4UiV4fIi", "")
BUILTIN(__builtin_vsx_insertword, "V16UcV4UiV16UcIi", "")
BUILTIN(__builtin_vsx_extractuword, "V2ULLiV16UcIi", "")
+BUILTIN(__builtin_vsx_xxpermdi, "v.", "t")
+BUILTIN(__builtin_vsx_xxsldwi, "v.", "t")
+
// HTM builtins
BUILTIN(__builtin_tbegin, "UiUIi", "")
BUILTIN(__builtin_tend, "UiUIi", "")
diff --git a/include/clang/Basic/BuiltinsSystemZ.def b/include/clang/Basic/BuiltinsSystemZ.def
index fa96e10b39..ac92286af0 100644
--- a/include/clang/Basic/BuiltinsSystemZ.def
+++ b/include/clang/Basic/BuiltinsSystemZ.def
@@ -253,5 +253,29 @@ TARGET_BUILTIN(__builtin_s390_vfmsdb, "V2dV2dV2dV2d", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vfsqdb, "V2dV2d", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vftcidb, "V2SLLiV2dIii*", "nc", "vector")
+// Vector-enhancements facility 1 intrinsics.
+TARGET_BUILTIN(__builtin_s390_vlrl, "V16ScUivC*", "", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vstrl, "vV16ScUiv*", "", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vbperm, "V2ULLiV16UcV16Uc", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vmslg, "V16UcV2ULLiV2ULLiV16UcIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmaxdb, "V2dV2dV2dIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmindb, "V2dV2dV2dIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmadb, "V2dV2dV2dV2d", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmsdb, "V2dV2dV2dV2d", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfcesbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfchsbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfchesbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfisb, "V4fV4fIiIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmaxsb, "V4fV4fV4fIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfminsb, "V4fV4fV4fIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vflnsb, "V4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vflpsb, "V4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmasb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmssb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmasb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmssb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfsqsb, "V4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vftcisb, "V4SiV4fIii*", "nc", "vector-enhancements-1")
+
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/include/clang/Basic/BuiltinsWebAssembly.def b/include/clang/Basic/BuiltinsWebAssembly.def
index de56908be8..19318dcebb 100644
--- a/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/include/clang/Basic/BuiltinsWebAssembly.def
@@ -21,4 +21,8 @@
BUILTIN(__builtin_wasm_current_memory, "z", "n")
BUILTIN(__builtin_wasm_grow_memory, "zz", "n")
+// Exception handling builtins.
+BUILTIN(__builtin_wasm_throw, "vUiv*", "r")
+BUILTIN(__builtin_wasm_rethrow, "v", "r")
+
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 2400b4458c..d57ea8f119 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -32,12 +32,9 @@
// Miscellaneous builtin for checking x86 cpu features.
// TODO: Make this somewhat generic so that other backends
// can use it?
+BUILTIN(__builtin_cpu_init, "v", "n")
BUILTIN(__builtin_cpu_supports, "bcC*", "nc")
-
-// Win64-compatible va_list functions
-BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
-BUILTIN(__builtin_ms_va_end, "vc*&", "n")
-BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n")
+BUILTIN(__builtin_cpu_is, "bcC*", "nc")
// Undefined Values
//
@@ -269,8 +266,6 @@ TARGET_BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "", "sse2")
-TARGET_BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "", "sse2")
-TARGET_BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "", "sse2")
@@ -343,8 +338,8 @@ TARGET_BUILTIN(__builtin_ia32_lfence, "v", "", "sse2")
TARGET_HEADER_BUILTIN(_mm_lfence, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2")
TARGET_BUILTIN(__builtin_ia32_mfence, "v", "", "sse2")
TARGET_HEADER_BUILTIN(_mm_mfence, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2")
-TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "sse2")
-TARGET_HEADER_BUILTIN(_mm_pause, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2")
+TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "")
+TARGET_HEADER_BUILTIN(_mm_pause, "v", "h", "emmintrin.h", ALL_LANGUAGES, "")
TARGET_BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "", "sse2")
@@ -391,7 +386,6 @@ TARGET_BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2dIi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_roundpd, "V2dV2dIi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fIc", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_dppd, "V2dV2dV2dIc", "", "sse4.1")
-TARGET_BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLiC*", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "", "sse4.1")
@@ -526,8 +520,6 @@ TARGET_BUILTIN(__builtin_ia32_paddusw256, "V16sV16sV16s", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psubusb256, "V32cV32cV32c", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psubusw256, "V16sV16sV16s", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIi", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "", "avx2")
@@ -576,7 +568,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")
@@ -648,7 +639,10 @@ TARGET_BUILTIN(__builtin_ia32_xsavec, "vv*ULLi", "", "xsavec")
TARGET_BUILTIN(__builtin_ia32_xsaves, "vv*ULLi", "", "xsaves")
//CLFLUSHOPT
-TARGET_BUILTIN(__builtin_ia32_clflushopt, "vc*", "", "clflushopt")
+TARGET_BUILTIN(__builtin_ia32_clflushopt, "vvC*", "", "clflushopt")
+
+//CLWB
+TARGET_BUILTIN(__builtin_ia32_clwb, "vvC*", "", "clwb")
// ADX
TARGET_BUILTIN(__builtin_ia32_addcarryx_u32, "UcUcUiUiUi*", "", "adx")
@@ -670,6 +664,12 @@ TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "", "bmi2")
// TBM
TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "", "tbm")
+// LWP
+TARGET_BUILTIN(__builtin_ia32_llwpcb, "vv*", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_slwpcb, "v*", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpins32, "UcUiUiUi", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpval32, "vUiUiUi", "", "lwp")
+
// SHA
TARGET_BUILTIN(__builtin_ia32_sha1rnds4, "V4iV4iV4iIc", "", "sha")
TARGET_BUILTIN(__builtin_ia32_sha1nexte, "V4iV4iV4i", "", "sha")
@@ -976,8 +976,6 @@ TARGET_BUILTIN(__builtin_ia32_pmuldq512, "V8LLiV16iV16i", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_pmuludq512, "V8LLiV16iV16i", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_ptestmd512, "UsV16iV16iUs", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_ptestmq512, "UcV8LLiV8LLiUc", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastd512_gpr_mask, "V16iiV16iUs", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_mem_mask, "V8LLiLLiV8LLiUc", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_loaddqusi512_mask, "V16iiC*V16iUs", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_loaddqudi512_mask, "V8LLiLLiC*V8LLiUc", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_loadups512_mask, "V16ffC*V16fUs", "", "avx512f")
@@ -1074,8 +1072,6 @@ TARGET_BUILTIN(__builtin_ia32_paddsb512_mask, "V64cV64cV64cV64cULLi", "", "avx51
TARGET_BUILTIN(__builtin_ia32_paddsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddusb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddusw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_pavgb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_pavgw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pmaxsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pmaxsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pmaxub512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
@@ -1103,6 +1099,9 @@ TARGET_BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "", "avx5
TARGET_BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "", "avx512cd")
TARGET_BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512cd")
+TARGET_BUILTIN(__builtin_ia32_vpopcntd_512, "V16iV16i", "", "avx512vpopcntdq")
+TARGET_BUILTIN(__builtin_ia32_vpopcntq_512, "V8LLiV8LLi", "", "avx512vpopcntdq")
+
TARGET_BUILTIN(__builtin_ia32_vpermi2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw")
TARGET_BUILTIN(__builtin_ia32_vpermi2varhi256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw")
TARGET_BUILTIN(__builtin_ia32_vpermt2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw")
@@ -1377,11 +1376,6 @@ TARGET_BUILTIN(__builtin_ia32_movdqa64load128_mask, "V2LLiV2LLiC*V2LLiUc","","av
TARGET_BUILTIN(__builtin_ia32_movdqa64load256_mask, "V4LLiV4LLiC*V4LLiUc","","avx512vl")
TARGET_BUILTIN(__builtin_ia32_movdqa64store128_mask, "vV2LLi*V2LLiUc","","avx512f")
TARGET_BUILTIN(__builtin_ia32_movdqa64store256_mask, "vV4LLi*V4LLiUc","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastb512_gpr_mask, "V64ccV64cULLi","","avx512bw")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastb128_gpr_mask, "V16ccV16cUs","","avx512bw,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastb256_gpr_mask, "V32ccV32cUi","","avx512bw,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastd128_gpr_mask, "V4iiV4iUc","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastd256_gpr_mask, "V8iiV8iUc","","avx512vl")
TARGET_BUILTIN(__builtin_ia32_vpmadd52huq512_mask, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma")
TARGET_BUILTIN(__builtin_ia32_vpmadd52huq512_maskz, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma")
TARGET_BUILTIN(__builtin_ia32_vpmadd52luq512_mask, "V8LLiV8LLiV8LLiV8LLiUc","","avx512ifma")
@@ -1592,14 +1586,6 @@ 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_broadcasti32x2_512_mask, "V16iV4iV16iUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_256_mask, "V8fV4fV8fUc","","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_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")
TARGET_BUILTIN(__builtin_ia32_pmovsdb512_mask, "V16cV16iV16cUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_pmovsdb512mem_mask, "vV16c*V16iUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_pmovswb512mem_mask, "vV32c*V32sUi","","avx512bw")
@@ -1747,7 +1733,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")
@@ -1816,8 +1801,8 @@ TARGET_BUILTIN(__builtin_ia32_mwaitx, "vUiUiUi", "", "mwaitx")
TARGET_BUILTIN(__builtin_ia32_clzero, "vv*", "", "clzero")
// MSVC
-TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_ReadBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -1832,6 +1817,16 @@ TARGET_HEADER_BUILTIN(__stosb, "vUc*Ucz", "nh", "intrin.h", ALL_MS_LANGUAGES, ""
TARGET_HEADER_BUILTIN(__int2c, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__ud2, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+
+TARGET_HEADER_BUILTIN(__readgsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+
#undef BUILTIN
#undef TARGET_BUILTIN
#undef TARGET_HEADER_BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86_64.def b/include/clang/Basic/BuiltinsX86_64.def
index d38f522c38..6e120672ff 100644
--- a/include/clang/Basic/BuiltinsX86_64.def
+++ b/include/clang/Basic/BuiltinsX86_64.def
@@ -22,8 +22,8 @@
# define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
#endif
-TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__mulh, "LLiLLiLLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -69,9 +69,8 @@ TARGET_BUILTIN(__builtin_ia32_bzhi_di, "ULLiULLiULLi", "", "bmi2")
TARGET_BUILTIN(__builtin_ia32_pdep_di, "ULLiULLiULLi", "", "bmi2")
TARGET_BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "", "bmi2")
TARGET_BUILTIN(__builtin_ia32_bextri_u64, "ULLiULLiIULLi", "", "tbm")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_gpr_mask, "V8LLiLLiV8LLiUc", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastq128_gpr_mask, "V2LLiULLiV2LLiUc","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_pbroadcastq256_gpr_mask, "V4LLiULLiV4LLiUc","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcULLiUiUi", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpval64, "vULLiUiUi", "", "lwp")
TARGET_BUILTIN(__builtin_ia32_vcvtsd2si64, "LLiV2dIi","","avx512f")
TARGET_BUILTIN(__builtin_ia32_vcvtsd2usi64, "ULLiV2dIi","","avx512f")
TARGET_BUILTIN(__builtin_ia32_vcvtss2si64, "LLiV4fIi","","avx512f")
diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt
index e4929b5b52..821c405913 100644
--- a/include/clang/Basic/CMakeLists.txt
+++ b/include/clang/Basic/CMakeLists.txt
@@ -9,10 +9,12 @@ clang_diag_gen(Analysis)
clang_diag_gen(AST)
clang_diag_gen(Comment)
clang_diag_gen(Common)
+clang_diag_gen(CrossTU)
clang_diag_gen(Driver)
clang_diag_gen(Frontend)
clang_diag_gen(Lex)
clang_diag_gen(Parse)
+clang_diag_gen(Refactoring)
clang_diag_gen(Sema)
clang_diag_gen(Serialization)
clang_tablegen(DiagnosticGroups.inc -gen-clang-diag-groups
@@ -28,6 +30,11 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list
SOURCE Attr.td
TARGET ClangAttrList)
+clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE Attr.td
+ TARGET ClangAttrSubjectMatchRuleList)
+
clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
diff --git a/include/clang/Basic/CharInfo.h b/include/clang/Basic/CharInfo.h
index dd9c55431e..cc27bbb48e 100644
--- a/include/clang/Basic/CharInfo.h
+++ b/include/clang/Basic/CharInfo.h
@@ -40,14 +40,14 @@ namespace charinfo {
} // end namespace charinfo
/// Returns true if this is an ASCII character.
-LLVM_READNONE static inline bool isASCII(char c) {
+LLVM_READNONE inline bool isASCII(char c) {
return static_cast<unsigned char>(c) <= 127;
}
/// Returns true if this is a valid first character of a C identifier,
/// which is [a-zA-Z_].
-LLVM_READONLY static inline bool isIdentifierHead(unsigned char c,
- bool AllowDollar = false) {
+LLVM_READONLY inline bool isIdentifierHead(unsigned char c,
+ bool AllowDollar = false) {
using namespace charinfo;
if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_UNDER))
return true;
@@ -56,8 +56,8 @@ LLVM_READONLY static inline bool isIdentifierHead(unsigned char c,
/// Returns true if this is a body character of a C identifier,
/// which is [a-zA-Z0-9_].
-LLVM_READONLY static inline bool isIdentifierBody(unsigned char c,
- bool AllowDollar = false) {
+LLVM_READONLY inline bool isIdentifierBody(unsigned char c,
+ bool AllowDollar = false) {
using namespace charinfo;
if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER))
return true;
@@ -68,7 +68,7 @@ LLVM_READONLY static inline bool isIdentifierBody(unsigned char c,
/// ' ', '\\t', '\\f', '\\v'.
///
/// Note that this returns false for '\\0'.
-LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) {
+LLVM_READONLY inline bool isHorizontalWhitespace(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_SPACE)) != 0;
}
@@ -76,7 +76,7 @@ LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) {
/// Returns true if this character is vertical ASCII whitespace: '\\n', '\\r'.
///
/// Note that this returns false for '\\0'.
-LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) {
+LLVM_READONLY inline bool isVerticalWhitespace(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & CHAR_VERT_WS) != 0;
}
@@ -85,43 +85,43 @@ LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) {
/// ' ', '\\t', '\\f', '\\v', '\\n', '\\r'.
///
/// Note that this returns false for '\\0'.
-LLVM_READONLY static inline bool isWhitespace(unsigned char c) {
+LLVM_READONLY inline bool isWhitespace(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_VERT_WS|CHAR_SPACE)) != 0;
}
/// Return true if this character is an ASCII digit: [0-9]
-LLVM_READONLY static inline bool isDigit(unsigned char c) {
+LLVM_READONLY inline bool isDigit(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & CHAR_DIGIT) != 0;
}
/// Return true if this character is a lowercase ASCII letter: [a-z]
-LLVM_READONLY static inline bool isLowercase(unsigned char c) {
+LLVM_READONLY inline bool isLowercase(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & CHAR_LOWER) != 0;
}
/// Return true if this character is an uppercase ASCII letter: [A-Z]
-LLVM_READONLY static inline bool isUppercase(unsigned char c) {
+LLVM_READONLY inline bool isUppercase(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & CHAR_UPPER) != 0;
}
/// Return true if this character is an ASCII letter: [a-zA-Z]
-LLVM_READONLY static inline bool isLetter(unsigned char c) {
+LLVM_READONLY inline bool isLetter(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER)) != 0;
}
/// Return true if this character is an ASCII letter or digit: [a-zA-Z0-9]
-LLVM_READONLY static inline bool isAlphanumeric(unsigned char c) {
+LLVM_READONLY inline bool isAlphanumeric(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_DIGIT|CHAR_UPPER|CHAR_LOWER)) != 0;
}
/// Return true if this character is an ASCII hex digit: [0-9a-fA-F]
-LLVM_READONLY static inline bool isHexDigit(unsigned char c) {
+LLVM_READONLY inline bool isHexDigit(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_DIGIT|CHAR_XLETTER)) != 0;
}
@@ -129,7 +129,7 @@ LLVM_READONLY static inline bool isHexDigit(unsigned char c) {
/// Return true if this character is an ASCII punctuation character.
///
/// Note that '_' is both a punctuation character and an identifier character!
-LLVM_READONLY static inline bool isPunctuation(unsigned char c) {
+LLVM_READONLY inline bool isPunctuation(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0;
}
@@ -137,7 +137,7 @@ LLVM_READONLY static inline bool isPunctuation(unsigned char c) {
/// Return true if this character is an ASCII printable character; that is, a
/// character that should take exactly one column to print in a fixed-width
/// terminal.
-LLVM_READONLY static inline bool isPrintable(unsigned char c) {
+LLVM_READONLY inline bool isPrintable(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT|
CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0;
@@ -145,14 +145,14 @@ LLVM_READONLY static inline bool isPrintable(unsigned char c) {
/// Return true if this is the body character of a C preprocessing number,
/// which is [a-zA-Z0-9_.].
-LLVM_READONLY static inline bool isPreprocessingNumberBody(unsigned char c) {
+LLVM_READONLY inline bool isPreprocessingNumberBody(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] &
(CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER|CHAR_PERIOD)) != 0;
}
/// Return true if this is the body character of a C++ raw string delimiter.
-LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) {
+LLVM_READONLY inline bool isRawStringDelimBody(unsigned char c) {
using namespace charinfo;
return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|
CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0;
@@ -162,7 +162,7 @@ LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) {
/// Converts the given ASCII character to its lowercase equivalent.
///
/// If the character is not an uppercase character, it is returned as is.
-LLVM_READONLY static inline char toLowercase(char c) {
+LLVM_READONLY inline char toLowercase(char c) {
if (isUppercase(c))
return c + 'a' - 'A';
return c;
@@ -171,7 +171,7 @@ LLVM_READONLY static inline char toLowercase(char c) {
/// Converts the given ASCII character to its uppercase equivalent.
///
/// If the character is not a lowercase character, it is returned as is.
-LLVM_READONLY static inline char toUppercase(char c) {
+LLVM_READONLY inline char toUppercase(char c) {
if (isLowercase(c))
return c + 'A' - 'a';
return c;
@@ -182,7 +182,7 @@ LLVM_READONLY static inline char toUppercase(char c) {
///
/// Note that this is a very simple check; it does not accept '$' or UCNs as
/// valid identifier characters.
-LLVM_READONLY static inline bool isValidIdentifier(StringRef S) {
+LLVM_READONLY inline bool isValidIdentifier(StringRef S) {
if (S.empty() || !isIdentifierHead(S[0]))
return false;
diff --git a/include/clang/Basic/Cuda.h b/include/clang/Basic/Cuda.h
index ad1139b8c1..1a0731c37a 100644
--- a/include/clang/Basic/Cuda.h
+++ b/include/clang/Basic/Cuda.h
@@ -21,6 +21,8 @@ enum class CudaVersion {
CUDA_70,
CUDA_75,
CUDA_80,
+ CUDA_90,
+ LATEST = CUDA_90,
};
const char *CudaVersionToString(CudaVersion V);
@@ -41,6 +43,7 @@ enum class CudaArch {
SM_60,
SM_61,
SM_62,
+ SM_70,
};
const char *CudaArchToString(CudaArch A);
@@ -60,6 +63,7 @@ enum class CudaVirtualArch {
COMPUTE_60,
COMPUTE_61,
COMPUTE_62,
+ COMPUTE_70,
};
const char *CudaVirtualArchToString(CudaVirtualArch A);
@@ -72,6 +76,9 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A);
/// Get the earliest CudaVersion that supports the given CudaArch.
CudaVersion MinVersionForCudaArch(CudaArch A);
+/// Get the latest CudaVersion that supports the given CudaArch.
+CudaVersion MaxVersionForCudaArch(CudaArch A);
+
} // namespace clang
#endif
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index ffce99bf9f..22cded21c1 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -178,12 +178,7 @@ public:
private:
unsigned char AllExtensionsSilenced; // Used by __extension__
- bool IgnoreAllWarnings; // Ignore all warnings: -w
- bool WarningsAsErrors; // Treat warnings like errors.
- bool EnableAllWarnings; // Enable all warnings.
- bool ErrorsAsFatal; // Treat errors like fatal errors.
- bool FatalsAsError; // Treat fatal errors like errors.
- bool SuppressSystemWarnings; // Suppress warnings in system headers.
+ bool SuppressAfterFatalError; // Suppress diagnostics after a fatal error?
bool SuppressAllDiagnostics; // Suppress all diagnostics.
bool ElideType; // Elide common types of templates.
bool PrintTemplateTree; // Print a tree when comparing templates.
@@ -194,7 +189,6 @@ private:
// 0 -> no limit.
unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation
// backtrace stack, 0 -> no limit.
- diag::Severity ExtBehavior; // Map extensions to warnings or errors?
IntrusiveRefCntPtr<DiagnosticIDs> Diags;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticConsumer *Client;
@@ -216,6 +210,19 @@ private:
llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap;
public:
+ // "Global" configuration state that can actually vary between modules.
+ unsigned IgnoreAllWarnings : 1; // Ignore all warnings: -w
+ unsigned EnableAllWarnings : 1; // Enable all warnings.
+ unsigned WarningsAsErrors : 1; // Treat warnings like errors.
+ unsigned ErrorsAsFatal : 1; // Treat errors like fatal errors.
+ unsigned SuppressSystemWarnings : 1; // Suppress warnings in system headers.
+ diag::Severity ExtBehavior; // Map extensions to warnings or errors?
+
+ DiagState()
+ : IgnoreAllWarnings(false), EnableAllWarnings(false),
+ WarningsAsErrors(false), ErrorsAsFatal(false),
+ SuppressSystemWarnings(false), ExtBehavior(diag::Severity::Ignored) {}
+
typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator;
typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator
const_iterator;
@@ -223,6 +230,9 @@ private:
void setMapping(diag::kind Diag, DiagnosticMapping Info) {
DiagMap[Diag] = Info;
}
+ DiagnosticMapping lookupMapping(diag::kind Diag) const {
+ return DiagMap.lookup(Diag);
+ }
DiagnosticMapping &getOrAddMapping(diag::kind Diag);
@@ -490,33 +500,47 @@ public:
/// \brief When set to true, any unmapped warnings are ignored.
///
/// If this and WarningsAsErrors are both set, then this one wins.
- void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
- bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
+ void setIgnoreAllWarnings(bool Val) {
+ GetCurDiagState()->IgnoreAllWarnings = Val;
+ }
+ bool getIgnoreAllWarnings() const {
+ return GetCurDiagState()->IgnoreAllWarnings;
+ }
/// \brief When set to true, any unmapped ignored warnings are no longer
/// ignored.
///
/// If this and IgnoreAllWarnings are both set, then that one wins.
- void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }
- bool getEnableAllWarnings() const { return EnableAllWarnings; }
+ void setEnableAllWarnings(bool Val) {
+ GetCurDiagState()->EnableAllWarnings = Val;
+ }
+ bool getEnableAllWarnings() const {
+ return GetCurDiagState()->EnableAllWarnings;
+ }
/// \brief When set to true, any warnings reported are issued as errors.
- void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
- bool getWarningsAsErrors() const { return WarningsAsErrors; }
+ void setWarningsAsErrors(bool Val) {
+ GetCurDiagState()->WarningsAsErrors = Val;
+ }
+ bool getWarningsAsErrors() const {
+ return GetCurDiagState()->WarningsAsErrors;
+ }
/// \brief When set to true, any error reported is made a fatal error.
- void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; }
- bool getErrorsAsFatal() const { return ErrorsAsFatal; }
+ void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; }
+ bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; }
- /// \brief When set to true, any fatal error reported is made an error.
- ///
- /// This setting takes precedence over the setErrorsAsFatal setting above.
- void setFatalsAsError(bool Val) { FatalsAsError = Val; }
- bool getFatalsAsError() const { return FatalsAsError; }
+ /// \brief When set to true (the default), suppress further diagnostics after
+ /// a fatal error.
+ void setSuppressAfterFatalError(bool Val) { SuppressAfterFatalError = Val; }
/// \brief When set to true mask warnings that come from system headers.
- void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
- bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
+ void setSuppressSystemWarnings(bool Val) {
+ GetCurDiagState()->SuppressSystemWarnings = Val;
+ }
+ bool getSuppressSystemWarnings() const {
+ return GetCurDiagState()->SuppressSystemWarnings;
+ }
/// \brief Suppress all diagnostics, to silence the front end when we
/// know that we don't want any more diagnostics to be passed along to the
@@ -568,11 +592,15 @@ public:
}
/// \brief Controls whether otherwise-unmapped extension diagnostics are
- /// mapped onto ignore/warning/error.
+ /// mapped onto ignore/warning/error.
///
/// This corresponds to the GCC -pedantic and -pedantic-errors option.
- void setExtensionHandlingBehavior(diag::Severity H) { ExtBehavior = H; }
- diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; }
+ void setExtensionHandlingBehavior(diag::Severity H) {
+ GetCurDiagState()->ExtBehavior = H;
+ }
+ diag::Severity getExtensionHandlingBehavior() const {
+ return GetCurDiagState()->ExtBehavior;
+ }
/// \brief Counter bumped when an __extension__ block is/ encountered.
///
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index 39da0060dd..52ccf350e6 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
+// See the Internals Manual, section The Diagnostics Subsystem for an overview.
+
// Define the diagnostic severities.
class Severity<string N> {
string Name = N;
@@ -100,10 +102,20 @@ class SuppressInSystemHeader {
class Error<string str> : Diagnostic<str, CLASS_ERROR, SEV_Error>, SFINAEFailure {
bit ShowInSystemHeader = 1;
}
+// Warnings default to on (but can be default-off'd with DefaultIgnore).
+// This is used for warnings about questionable code; warnings about
+// accepted language extensions should use Extension or ExtWarn below instead.
class Warning<string str> : Diagnostic<str, CLASS_WARNING, SEV_Warning>;
+// Remarks can be turned on with -R flags and provide commentary, e.g. on
+// optimizer decisions.
class Remark<string str> : Diagnostic<str, CLASS_REMARK, SEV_Ignored>;
+// Extensions are warnings about accepted language extensions.
+// Extension warnings are default-off but enabled by -pedantic.
class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>;
+// ExtWarns are warnings about accepted language extensions.
+// ExtWarn warnings are default-on.
class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>;
+// Notes can provide supplementary information on errors, warnings, and remarks.
class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>;
@@ -121,10 +133,12 @@ include "DiagnosticASTKinds.td"
include "DiagnosticAnalysisKinds.td"
include "DiagnosticCommentKinds.td"
include "DiagnosticCommonKinds.td"
+include "DiagnosticCrossTUKinds.td"
include "DiagnosticDriverKinds.td"
include "DiagnosticFrontendKinds.td"
include "DiagnosticLexKinds.td"
include "DiagnosticParseKinds.td"
+include "DiagnosticRefactoringKinds.td"
include "DiagnosticSemaKinds.td"
include "DiagnosticSerializationKinds.td"
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 652d062785..215580b2e9 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -127,6 +127,10 @@ def note_constexpr_access_null : Note<
def note_constexpr_access_past_end : Note<
"%select{read of|assignment to|increment of|decrement of}0 "
"dereferenced one-past-the-end pointer is not allowed in a constant expression">;
+def note_constexpr_access_unsized_array : Note<
+ "%select{read of|assignment to|increment of|decrement of}0 "
+ "pointer to element of array without known bound "
+ "is not allowed in a constant expression">;
def note_constexpr_access_inactive_union_member : Note<
"%select{read of|assignment to|increment of|decrement of}0 "
"member %1 of union with %select{active member %3|no active member}2 "
@@ -154,6 +158,11 @@ def note_constexpr_baa_insufficient_alignment : Note<
def note_constexpr_baa_value_insufficient_alignment : Note<
"value of the aligned pointer (%0) is not a multiple of the asserted %1 "
"%plural{1:byte|:bytes}1">;
+def note_constexpr_unsupported_unsized_array : Note<
+ "array-to-pointer decay of array member without known bound is not supported">;
+def note_constexpr_unsized_array_indexed : Note<
+ "indexing of array without known bound is not allowed "
+ "in a constant expression">;
def warn_integer_constant_overflow : Warning<
"overflow in expression; result is %0 with type %1">,
@@ -200,12 +209,17 @@ def note_odr_defined_here : Note<"also defined here">;
def err_odr_function_type_inconsistent : Error<
"external function %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
-def warn_odr_tag_type_inconsistent : Warning<
- "type %0 has incompatible definitions in different translation units">,
- InGroup<DiagGroup<"odr">>;
+def warn_odr_tag_type_inconsistent
+ : Warning<"type %0 has incompatible definitions in different translation "
+ "units">,
+ InGroup<DiagGroup<"odr">>;
+def err_odr_tag_type_inconsistent
+ : Error<"type %0 has incompatible definitions in different translation "
+ "units">;
def note_odr_tag_kind_here: Note<
"%0 is a %select{struct|interface|union|class|enum}1 here">;
def note_odr_field : Note<"field %0 has type %1 here">;
+def note_odr_field_name : Note<"field has name %0 here">;
def note_odr_missing_field : Note<"no corresponding field here">;
def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;
def note_odr_not_bit_field : Note<"field %0 is not a bit-field">;
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index b8293f08c5..98fd3c4d57 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -90,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/DiagnosticCrossTUKinds.td b/include/clang/Basic/DiagnosticCrossTUKinds.td
new file mode 100644
index 0000000000..8b6d8b6814
--- /dev/null
+++ b/include/clang/Basic/DiagnosticCrossTUKinds.td
@@ -0,0 +1,18 @@
+//==--- DiagnosticCrossTUKinds.td - Cross Translation Unit diagnostics ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+let Component = "CrossTU" in {
+
+def err_fnmap_parsing : Error<
+ "error parsing index file: '%0' line: %1 'UniqueID filename' format "
+ "expected">;
+
+def err_multiple_def_index : Error<
+ "multiple definitions are found for the same key in index ">;
+}
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index b02599c8ae..dd72c958d1 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -29,9 +29,10 @@ def err_drv_no_cuda_installation : Error<
def err_drv_no_cuda_libdevice : Error<
"cannot find libdevice for %0. Provide path to different CUDA installation "
"via --cuda-path, or pass -nocudalib to build without linking with libdevice.">;
-def err_drv_cuda_version_too_low : Error<
- "GPU arch %1 requires CUDA version at least %3, but installation at %0 is %2. "
- "Use --cuda-path to specify a different CUDA install, or pass "
+def err_drv_cuda_version_unsupported : Error<
+ "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), "
+ "but installation at %3 is %4. Use --cuda-path to specify a different CUDA "
+ "install, pass a different GPU arch with --cuda-gpu-arch, or pass "
"--no-cuda-version-check.">;
def err_drv_cuda_nvptx_host : Error<"unsupported use of NVPTX for host compilation.">;
def err_drv_invalid_thread_model_for_target : Error<
@@ -69,6 +70,10 @@ def err_drv_invalid_Xarch_argument_with_args : Error<
"invalid Xarch argument: '%0', options requiring arguments are unsupported">;
def err_drv_invalid_Xarch_argument_isdriver : Error<
"invalid Xarch argument: '%0', cannot change driver behavior inside Xarch argument">;
+def err_drv_Xopenmp_target_missing_triple : Error<
+ "cannot deduce implicit triple value for -Xopenmp-target, specify triple using -Xopenmp-target=<triple>">;
+def err_drv_invalid_Xopenmp_target_with_args : Error<
+ "invalid -Xopenmp-target argument: '%0', options requiring arguments are unsupported">;
def err_drv_argument_only_allowed_with : Error<
"invalid argument '%0' only allowed with '%1'">;
def err_drv_argument_not_allowed_with : Error<
@@ -85,6 +90,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,9 +99,13 @@ 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_mtp : Error<
+ "invalid thread pointer reading mode '%0'">;
+def err_drv_missing_arg_mtp : Error<
+ "missing argument to '%0'">;
def err_drv_invalid_libcxx_deployment : Error<
"invalid deployment target for -stdlib=libc++ (requires %0 or later)">;
def err_drv_invalid_argument_to_fdebug_prefix_map : Error<
@@ -104,6 +115,10 @@ def err_drv_malformed_sanitizer_blacklist : Error<
def err_target_unsupported_arch
: Error<"the target architecture '%0' is not supported by the target '%1'">;
+def err_cpu_unsupported_isa
+ : Error<"CPU '%0' does not support '%1' execution mode">;
+def err_arch_unsupported_isa
+ : Error<"Architecture '%0' does not support '%1' execution mode">;
def err_drv_I_dash_not_supported : Error<
"'%0' not supported, please use -iquote instead">;
@@ -136,6 +151,10 @@ def err_drv_cc_print_options_failure : Error<
def err_drv_lto_without_lld : Error<"LTO requires -fuse-ld=lld">;
def err_drv_preamble_format : Error<
"incorrect format for -preamble-bytes=N,END">;
+def warn_invalid_ios_deployment_target : Warning<
+ "invalid iOS deployment version '%0', iOS 10 is the maximum deployment "
+ "target for 32-bit targets">, InGroup<InvalidIOSDeploymentTarget>,
+ DefaultError;
def err_drv_conflicting_deployment_targets : Error<
"conflicting deployment targets, both '%0' and '%1' are present in environment">;
def err_arc_unsupported_on_runtime : Error<
@@ -173,6 +192,8 @@ def warn_drv_optimization_value : Warning<"optimization level '%0' is not suppor
InGroup<InvalidCommandLineArgument>;
def warn_ignored_gcc_optimization : Warning<"optimization flag '%0' is not supported">,
InGroup<IgnoredOptimizationArgument>;
+def warn_ignored_clang_option : Warning<"the flag '%0' has been deprecated and will be ignored">,
+ InGroup<UnusedCommandLineArgument>;
def warn_drv_unsupported_opt_for_target : Warning<
"optimization flag '%0' is not supported for target '%1'">,
InGroup<IgnoredOptimizationArgument>;
@@ -193,8 +214,8 @@ def warn_drv_unused_argument : Warning<
def warn_drv_empty_joined_argument : Warning<
"joined argument expects additional value: '%0'">,
InGroup<UnusedCommandLineArgument>;
-def warn_drv_fdiagnostics_show_hotness_requires_pgo : Warning<
- "argument '-fdiagnostics-show-hotness' requires profile-guided optimization information">,
+def warn_drv_diagnostics_hotness_requires_pgo : Warning<
+ "argument '%0' requires profile-guided optimization information">,
InGroup<UnusedCommandLineArgument>;
def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
@@ -223,7 +244,10 @@ def warn_drv_enabling_rtti_with_exceptions : Warning<
InGroup<DiagGroup<"rtti-for-exceptions">>;
def warn_drv_disabling_vptr_no_rtti_default : Warning<
"implicitly disabling vptr sanitizer because rtti wasn't enabled">,
- InGroup<DiagGroup<"auto-disable-vptr-sanitizer">>;
+ InGroup<AutoDisableVptrSanitizer>;
+def warn_drv_object_size_disabled_O0 : Warning<
+ "the object size sanitizer has no effect at -O0, but is explicitly enabled: %0">,
+ InGroup<InvalidCommandLineArgument>;
def note_drv_command_failed_diag_msg : Note<
"diagnostic msg: %0">;
@@ -231,13 +255,18 @@ 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 note_drv_use_standard : Note<"use '%0'"
+ "%select{| or '%3'|, '%3', or '%4'|, '%3', '%4', or '%5'}2 "
+ "for '%1' standard">;
def err_analyzer_config_no_value : Error<
"analyzer-config option '%0' has a key but no value">;
def err_analyzer_config_multiple_values : Error<
"analyzer-config option '%0' should contain only one '='">;
+def err_drv_invalid_hvx_length : Error<
+ "-mhvx-length is not supported without a -mhvx/-mhvx= flag">;
+
def err_drv_modules_validate_once_requires_timestamp : Error<
"option '-fmodules-validate-once-per-build-session' requires "
"'-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'">;
@@ -264,9 +293,27 @@ def warn_target_unsupported_nan2008 : Warning<
def warn_target_unsupported_nanlegacy : Warning<
"ignoring '-mnan=legacy' option because the '%0' architecture does not support it">,
InGroup<UnsupportedNan>;
+def warn_target_unsupported_abslegacy : Warning<
+ "ignoring '-mabs=legacy' option because the '%0' architecture does not support it">,
+ InGroup<UnsupportedAbs>;
+def warn_target_unsupported_abs2008 : Warning<
+ "ignoring '-mabs=2008' option because the '%0' architecture does not support it">,
+ InGroup<UnsupportedAbs>;
def warn_target_unsupported_compact_branches : Warning<
"ignoring '-mcompact-branches=' option because the '%0' architecture does not"
" support it">, InGroup<UnsupportedCB>;
+def warn_drv_unsupported_gpopt : Warning<
+ "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit"
+ " usage of }0-mabicalls">,
+ InGroup<UnsupportedGPOpt>;
+def warn_drv_unsupported_longcalls : Warning<
+ "ignoring '-mlong-calls' option as it is not currently supported with "
+ "%select{|the implicit usage of }0-mabicalls">,
+ InGroup<OptionIgnored>;
+def warn_drv_unsupported_abicalls : Warning<
+ "ignoring '-mabicalls' option as it cannot be used with "
+ "non position-independent code and the N64 ABI">,
+ InGroup<OptionIgnored>;
def warn_drv_unable_to_find_directory_expected : Warning<
"unable to find %0 directory, expected to be in '%1'">,
@@ -283,4 +330,12 @@ 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">>;
+
+def warn_drv_fine_grained_bitfield_accesses_ignored : Warning<
+ "option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored">,
+ InGroup<OptionIgnored>;
}
diff --git a/include/clang/Basic/DiagnosticError.h b/include/clang/Basic/DiagnosticError.h
new file mode 100644
index 0000000000..6b4b073736
--- /dev/null
+++ b/include/clang/Basic/DiagnosticError.h
@@ -0,0 +1,61 @@
+//===--- DiagnosticError.h - Diagnostic payload for llvm::Error -*- 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_DIAGNOSTIC_ERROR_H
+#define LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H
+
+#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+
+/// \brief Carries a Clang diagnostic in an llvm::Error.
+///
+/// Users should emit the stored diagnostic using the DiagnosticsEngine.
+class DiagnosticError : public llvm::ErrorInfo<DiagnosticError> {
+public:
+ DiagnosticError(PartialDiagnosticAt Diag) : Diag(std::move(Diag)) {}
+
+ void log(raw_ostream &OS) const override { OS << "clang diagnostic"; }
+
+ PartialDiagnosticAt &getDiagnostic() { return Diag; }
+ const PartialDiagnosticAt &getDiagnostic() const { return Diag; }
+
+ /// Creates a new \c DiagnosticError that contains the given diagnostic at
+ /// the given location.
+ static llvm::Error create(SourceLocation Loc, PartialDiagnostic Diag) {
+ return llvm::make_error<DiagnosticError>(
+ PartialDiagnosticAt(Loc, std::move(Diag)));
+ }
+
+ /// Extracts and returns the diagnostic payload from the given \c Error if
+ /// the error is a \c DiagnosticError. Returns none if the given error is not
+ /// a \c DiagnosticError.
+ static Optional<PartialDiagnosticAt> take(llvm::Error &Err) {
+ Optional<PartialDiagnosticAt> Result;
+ Err = llvm::handleErrors(std::move(Err), [&](DiagnosticError &E) {
+ Result = std::move(E.getDiagnostic());
+ });
+ return Result;
+ }
+
+ static char ID;
+
+private:
+ // Users are not expected to use error_code.
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+
+ PartialDiagnosticAt Diag;
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 1267f8d09f..392a340a3b 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -116,6 +116,8 @@ def err_fe_action_not_available : Error<
"action %0 not compiled in">;
def err_fe_invalid_alignment : Error<
"invalid value '%1' in '%0'; alignment must be a power of 2">;
+def err_fe_invalid_wchar_type
+ : Error<"invalid wchar_t type '%0'; must be one of 'char', 'short', 'int'">;
def warn_fe_serialized_diag_merge_failure : Warning<
"unable to merge a subprocess's serialized diagnostics">,
@@ -179,6 +181,8 @@ def warn_incompatible_analyzer_plugin_api : Warning<
def note_incompatible_analyzer_plugin_api : Note<
"current API version is '%0', but plugin was compiled with version '%1'">;
+def err_module_build_requires_fmodules : Error<
+ "module compilation requires '-fmodules'">;
def err_module_interface_requires_modules_ts : Error<
"module interface compilation requires '-fmodules-ts'">;
def warn_module_config_mismatch : Warning<
@@ -196,6 +200,7 @@ def err_no_submodule_suggest : Error<
"no submodule named %0 in module '%1'; did you mean '%2'?">;
def warn_missing_submodule : Warning<"missing submodule '%0'">,
InGroup<IncompleteUmbrella>;
+def note_module_import_here : Note<"module imported here">;
def err_module_cannot_create_includes : Error<
"cannot create includes file for module %0: %1">;
def warn_module_config_macro_undef : Warning<
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 6153b8e7ed..c23183c81a 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -27,14 +27,23 @@ def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">;
def GNUAutoType : DiagGroup<"gnu-auto-type">;
def ArrayBounds : DiagGroup<"array-bounds">;
def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">;
+def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">;
def Availability : DiagGroup<"availability">;
def Section : DiagGroup<"section">;
def AutoImport : DiagGroup<"auto-import">;
def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">;
+def CXXPre14CompatBinaryLiteral : DiagGroup<"c++98-c++11-compat-binary-literal">;
def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;
+def BinaryLiteral : DiagGroup<"binary-literal", [CXX14BinaryLiteral,
+ CXXPre14CompatBinaryLiteral,
+ GNUBinaryLiteral]>;
def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">;
def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">;
+def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">;
def BitFieldWidth : DiagGroup<"bitfield-width">;
+def CoroutineMissingUnhandledException :
+ DiagGroup<"coroutine-missing-unhandled-exception">;
+def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException]>;
def ConstantConversion :
DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >;
def LiteralConversion : DiagGroup<"literal-conversion">;
@@ -56,7 +65,9 @@ def FloatConversion :
def DoublePromotion : DiagGroup<"double-promotion">;
def EnumTooLarge : DiagGroup<"enum-too-large">;
def UnsupportedNan : DiagGroup<"unsupported-nan">;
+def UnsupportedAbs : DiagGroup<"unsupported-abs">;
def UnsupportedCB : DiagGroup<"unsupported-cb">;
+def UnsupportedGPOpt : DiagGroup<"unsupported-gpopt">;
def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">;
def NullConversion : DiagGroup<"null-conversion">;
def ImplicitConversionFloatingPointToBool :
@@ -83,6 +94,7 @@ def GNUStringLiteralOperatorTemplate :
DiagGroup<"gnu-string-literal-operator-template">;
def UndefinedVarTemplate : DiagGroup<"undefined-var-template">;
def UndefinedFuncTemplate : DiagGroup<"undefined-func-template">;
+def MissingNoEscape : DiagGroup<"missing-noescape">;
def DeleteIncomplete : DiagGroup<"delete-incomplete">;
def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
@@ -94,7 +106,9 @@ def CXX11CompatDeprecatedWritableStr :
def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
-def UnguardedAvailability : DiagGroup<"unguarded-availability">;
+def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">;
+def UnguardedAvailability : DiagGroup<"unguarded-availability",
+ [UnguardedAvailabilityNew]>;
// partial-availability is an alias of unguarded-availability.
def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
def DeprecatedDynamicExceptionSpec
@@ -146,13 +160,24 @@ def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">;
def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
+def InvalidIOSDeploymentTarget : DiagGroup<"invalid-ios-deployment-target">;
+
+def CXX17CompatMangling : DiagGroup<"c++17-compat-mangling">;
+def : DiagGroup<"c++1z-compat-mangling", [CXX17CompatMangling]>;
+// Name of this warning in GCC.
+def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>;
+
// Warnings for C++1y code which is not compatible with prior C++ standards.
def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">;
def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic",
- [CXXPre14Compat]>;
-def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">;
-def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic",
- [CXXPre1zCompat]>;
+ [CXXPre14Compat,
+ CXXPre14CompatBinaryLiteral]>;
+def CXXPre17Compat : DiagGroup<"c++98-c++11-c++14-compat">;
+def CXXPre17CompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic",
+ [CXXPre17Compat]>;
+def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++17-compat">;
+def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic",
+ [CXXPre2aCompat]>;
def CXX98CompatBindToTemporaryCopy :
DiagGroup<"c++98-compat-bind-to-temporary-copy">;
@@ -165,13 +190,15 @@ def CXX98Compat : DiagGroup<"c++98-compat",
[CXX98CompatLocalTypeTemplateArgs,
CXX98CompatUnnamedTypeTemplateArgs,
CXXPre14Compat,
- CXXPre1zCompat]>;
+ CXXPre17Compat,
+ CXXPre2aCompat]>;
// Warnings for C++11 features which are Extensions in C++98 mode.
def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
[CXX98Compat,
CXX98CompatBindToTemporaryCopy,
CXXPre14CompatPedantic,
- CXXPre1zCompatPedantic]>;
+ CXXPre17CompatPedantic,
+ CXXPre2aCompatPedantic]>;
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
@@ -196,18 +223,34 @@ def CXX11Compat : DiagGroup<"c++11-compat",
CXX11CompatReservedUserDefinedLiteral,
CXX11CompatDeprecatedWritableStr,
CXXPre14Compat,
- CXXPre1zCompat]>;
+ CXXPre17Compat,
+ CXXPre2aCompat]>;
def : DiagGroup<"c++0x-compat", [CXX11Compat]>;
def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic",
- [CXXPre14CompatPedantic,
- CXXPre1zCompatPedantic]>;
+ [CXX11Compat,
+ CXXPre14CompatPedantic,
+ CXXPre17CompatPedantic,
+ CXXPre2aCompatPedantic]>;
-def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>;
+def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre17Compat,
+ CXXPre2aCompat]>;
def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic",
- [CXXPre1zCompatPedantic]>;
-
-def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister,
- DeprecatedIncrementBool]>;
+ [CXX14Compat,
+ CXXPre17CompatPedantic,
+ CXXPre2aCompatPedantic]>;
+
+def CXX17Compat : DiagGroup<"c++17-compat", [DeprecatedRegister,
+ DeprecatedIncrementBool,
+ CXX17CompatMangling,
+ CXXPre2aCompat]>;
+def CXX17CompatPedantic : DiagGroup<"c++17-compat-pedantic",
+ [CXX17Compat,
+ CXXPre2aCompatPedantic]>;
+def : DiagGroup<"c++1z-compat", [CXX17Compat]>;
+
+def CXX2aCompat : DiagGroup<"c++2a-compat">;
+def CXX2aCompatPedantic : DiagGroup<"c++2a-compat-pedantic",
+ [CXX2aCompat]>;
def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">;
@@ -301,8 +344,10 @@ def NonPODVarargs : DiagGroup<"non-pod-varargs">;
def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>;
def : DiagGroup<"nonportable-cfstrings">;
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
+def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic">;
def : DiagGroup<"effc++", [NonVirtualDtor]>;
def OveralignedType : DiagGroup<"over-aligned">;
+def AlignedAllocationUnavailable : DiagGroup<"aligned-allocation-unavailable">;
def OldStyleCast : DiagGroup<"old-style-cast">;
def : DiagGroup<"old-style-definition">;
def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">;
@@ -329,6 +374,7 @@ def ObjCRootClass : DiagGroup<"objc-root-class">;
def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">;
def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>;
def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">;
+def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">;
def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">;
def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">;
def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">;
@@ -389,12 +435,18 @@ def StringCompare : DiagGroup<"string-compare">;
def StringPlusInt : DiagGroup<"string-plus-int">;
def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
+def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;
+def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">;
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
+def TautologicalConstantCompare : DiagGroup<"tautological-constant-compare",
+ [TautologicalUnsignedZeroCompare,
+ TautologicalUnsignedEnumZeroCompare,
+ TautologicalOutOfRangeCompare]>;
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">;
def TautologicalCompare : DiagGroup<"tautological-compare",
- [TautologicalOutOfRangeCompare,
+ [TautologicalConstantCompare,
TautologicalPointerCompare,
TautologicalOverlapCompare,
TautologicalUndefinedCompare]>;
@@ -438,6 +490,8 @@ def CoveredSwitchDefault : DiagGroup<"covered-switch-default">;
def SwitchBool : DiagGroup<"switch-bool">;
def SwitchEnum : DiagGroup<"switch-enum">;
def Switch : DiagGroup<"switch">;
+def EnumCompareSwitch : DiagGroup<"enum-compare-switch">;
+def EnumCompare : DiagGroup<"enum-compare", [EnumCompareSwitch]>;
def ImplicitFallthroughPerFunction :
DiagGroup<"implicit-fallthrough-per-function">;
def ImplicitFallthrough : DiagGroup<"implicit-fallthrough",
@@ -457,9 +511,16 @@ def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes,
def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>;
-def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>;
+def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">;
+def PragmaPackSuspiciousInclude : DiagGroup<"pragma-pack-suspicious-include">;
+def PragmaPack : DiagGroup<"pragma-pack", [PragmaPackSuspiciousInclude]>;
+def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas,
+ PragmaClangAttribute, PragmaPack]>;
def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
+def NSConsumedMismatch : DiagGroup<"nsconsumed-mismatch">;
+def NSReturnsMismatch : DiagGroup<"nsreturns-mismatch">;
+
def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
def UnknownAttributes : DiagGroup<"unknown-attributes">;
def IgnoredAttributes : DiagGroup<"ignored-attributes">;
@@ -480,6 +541,7 @@ def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
def UnneededMemberFunction : DiagGroup<"unneeded-member-function">;
def UnusedPrivateField : DiagGroup<"unused-private-field">;
def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>;
+def UnusedTemplate : DiagGroup<"unused-template", [UnneededInternalDecl]>;
def UnusedMemberFunction : DiagGroup<"unused-member-function",
[UnneededMemberFunction]>;
def UnusedLabel : DiagGroup<"unused-label">;
@@ -606,6 +668,7 @@ def Conversion : DiagGroup<"conversion",
[BoolConversion,
ConstantConversion,
EnumConversion,
+ BitFieldEnumConversion,
FloatConversion,
Shorten64To32,
IntConversion,
@@ -620,6 +683,7 @@ def Conversion : DiagGroup<"conversion",
def Unused : DiagGroup<"unused",
[UnusedArgument, UnusedFunction, UnusedLabel,
// UnusedParameter, (matches GCC's behavior)
+ // UnusedTemplate, (clean-up libc++ before enabling)
// UnusedMemberFunction, (clean-up llvm before enabling)
UnusedPrivateField, UnusedLambdaCapture,
UnusedLocalTypedef, UnusedValue, UnusedVariable,
@@ -657,7 +721,8 @@ def Extra : DiagGroup<"extra", [
SemiBeforeMethodBody,
MissingMethodReturnType,
SignCompare,
- UnusedParameter
+ UnusedParameter,
+ NullPointerArithmetic
]>;
def Most : DiagGroup<"most", [
@@ -686,6 +751,7 @@ def Most : DiagGroup<"most", [
VolatileRegisterVar,
ObjCMissingSuperCalls,
ObjCDesignatedInit,
+ ObjCFlexibleArray,
OverloadedVirtual,
PrivateExtern,
SelTypeCast,
@@ -724,6 +790,7 @@ def Pedantic : DiagGroup<"pedantic">;
// Aliases.
def : DiagGroup<"", [Extra]>; // -W = -Wextra
def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wextra-tokens
+def : DiagGroup<"cpp", [PoundWarning]>; // -Wcpp = -W#warnings
def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
def : DiagGroup<"conversion-null",
[NullConversion]>; // -Wconversion-null = -Wnull-conversion
@@ -750,12 +817,17 @@ def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11InlineNamespace,
// earlier C++ versions.
def CXX14 : DiagGroup<"c++14-extensions", [CXX14BinaryLiteral]>;
-// A warning group for warnings about using C++1z features as extensions in
+// A warning group for warnings about using C++17 features as extensions in
+// earlier C++ versions.
+def CXX17 : DiagGroup<"c++17-extensions">;
+
+// A warning group for warnings about using C++2a features as extensions in
// earlier C++ versions.
-def CXX1z : DiagGroup<"c++1z-extensions">;
+def CXX2a : DiagGroup<"c++2a-extensions">;
def : DiagGroup<"c++0x-extensions", [CXX11]>;
def : DiagGroup<"c++1y-extensions", [CXX14]>;
+def : DiagGroup<"c++1z-extensions", [CXX17]>;
def DelegatingCtorCycles :
DiagGroup<"delegating-ctor-cycles">;
@@ -818,6 +890,7 @@ def MicrosoftVoidPseudoDtor : DiagGroup<"microsoft-void-pseudo-dtor">;
def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">;
def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">;
def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">;
+def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">;
// Aliases.
def : DiagGroup<"msvc-include", [MicrosoftInclude]>;
// -Wmsvc-include = -Wmicrosoft-include
@@ -883,6 +956,7 @@ def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">;
def BackendOptimizationFailure : DiagGroup<"pass-failed">;
// Instrumentation based profiling warnings.
+def ProfileInstrMissing : DiagGroup<"profile-instr-missing">;
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index fcd04a0be1..a62d6af744 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -18,6 +18,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
+#include <vector>
namespace clang {
class DiagnosticsEngine;
@@ -25,19 +26,36 @@ namespace clang {
// Import the diagnostic enums themselves.
namespace diag {
+ // Size of each of the diagnostic categories.
+ enum {
+ DIAG_SIZE_COMMON = 300,
+ DIAG_SIZE_DRIVER = 200,
+ DIAG_SIZE_FRONTEND = 100,
+ DIAG_SIZE_SERIALIZATION = 120,
+ DIAG_SIZE_LEX = 400,
+ DIAG_SIZE_PARSE = 500,
+ DIAG_SIZE_AST = 150,
+ DIAG_SIZE_COMMENT = 100,
+ DIAG_SIZE_CROSSTU = 100,
+ DIAG_SIZE_SEMA = 3500,
+ DIAG_SIZE_ANALYSIS = 100,
+ DIAG_SIZE_REFACTORING = 1000,
+ };
// Start position for diagnostics.
enum {
- DIAG_START_COMMON = 0,
- DIAG_START_DRIVER = DIAG_START_COMMON + 300,
- DIAG_START_FRONTEND = DIAG_START_DRIVER + 200,
- DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100,
- DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
- DIAG_START_PARSE = DIAG_START_LEX + 300,
- DIAG_START_AST = DIAG_START_PARSE + 500,
- DIAG_START_COMMENT = DIAG_START_AST + 110,
- DIAG_START_SEMA = DIAG_START_COMMENT + 100,
- DIAG_START_ANALYSIS = DIAG_START_SEMA + 3500,
- DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
+ DIAG_START_COMMON = 0,
+ DIAG_START_DRIVER = DIAG_START_COMMON + DIAG_SIZE_COMMON,
+ DIAG_START_FRONTEND = DIAG_START_DRIVER + DIAG_SIZE_DRIVER,
+ DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + DIAG_SIZE_FRONTEND,
+ DIAG_START_LEX = DIAG_START_SERIALIZATION + DIAG_SIZE_SERIALIZATION,
+ DIAG_START_PARSE = DIAG_START_LEX + DIAG_SIZE_LEX,
+ DIAG_START_AST = DIAG_START_PARSE + DIAG_SIZE_PARSE,
+ DIAG_START_COMMENT = DIAG_START_AST + DIAG_SIZE_AST,
+ DIAG_START_CROSSTU = DIAG_START_COMMENT + DIAG_SIZE_CROSSTU,
+ DIAG_START_SEMA = DIAG_START_CROSSTU + DIAG_SIZE_COMMENT,
+ DIAG_START_ANALYSIS = DIAG_START_SEMA + DIAG_SIZE_SEMA,
+ DIAG_START_REFACTORING = DIAG_START_ANALYSIS + DIAG_SIZE_ANALYSIS,
+ DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + DIAG_SIZE_REFACTORING
};
class CustomDiagInfo;
@@ -84,6 +102,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 +113,7 @@ public:
Result.IsPragma = IsPragma;
Result.HasNoWarningAsError = 0;
Result.HasNoErrorAsFatal = 0;
+ Result.WasUpgradedFromWarning = 0;
return Result;
}
@@ -103,11 +123,39 @@ public:
bool isUser() const { return IsUser; }
bool isPragma() const { return IsPragma; }
+ bool isErrorOrFatal() const {
+ return getSeverity() == diag::Severity::Error ||
+ getSeverity() == diag::Severity::Fatal;
+ }
+
bool hasNoWarningAsError() const { return HasNoWarningAsError; }
void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; }
bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; }
void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; }
+
+ /// Whether this mapping attempted to map the diagnostic to a warning, but
+ /// was overruled because the diagnostic was already mapped to an error or
+ /// fatal error.
+ bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; }
+ void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; }
+
+ /// Serialize this mapping as a raw integer.
+ unsigned serialize() const {
+ return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) |
+ (HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity;
+ }
+ /// Deserialize a mapping.
+ static DiagnosticMapping deserialize(unsigned Bits) {
+ DiagnosticMapping Result;
+ Result.IsUser = (Bits >> 7) & 1;
+ Result.IsPragma = (Bits >> 6) & 1;
+ Result.HasNoWarningAsError = (Bits >> 5) & 1;
+ Result.HasNoErrorAsFatal = (Bits >> 4) & 1;
+ Result.WasUpgradedFromWarning = (Bits >> 3) & 1;
+ Result.Severity = Bits & 0x7;
+ return Result;
+ }
};
/// \brief Used for handling and querying diagnostic IDs.
@@ -233,6 +281,13 @@ public:
/// are not SFINAE errors.
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
+ /// \brief Get the string of all diagnostic flags.
+ ///
+ /// \returns A list of all diagnostics flags as they would be written in a
+ /// command line invocation including their `no-` variants. For example:
+ /// `{"-Wempty-body", "-Wno-empty-body", ...}`
+ static std::vector<std::string> getDiagnosticFlags();
+
/// \brief Get the set of all diagnostic IDs in the group with the given name.
///
/// \param[out] Diags - On return, the diagnostics in the group.
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 7f7022b49e..8bc6d77c92 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -71,6 +71,8 @@ def ext_token_used : Extension<"extension used">,
def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">,
InGroup<CXX11Compat>, DefaultIgnore;
+def warn_cxx2a_keyword : Warning<"'%0' is a keyword in C++2a">,
+ InGroup<CXX2aCompat>, DefaultIgnore;
def ext_unterminated_char_or_string : ExtWarn<
"missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>;
@@ -173,26 +175,24 @@ def warn_char_constant_too_large : Warning<
def err_multichar_utf_character_literal : Error<
"Unicode character literals may not contain multiple characters">;
def err_exponent_has_no_digits : Error<"exponent has no digits">;
-def ext_imaginary_constant : Extension<
- "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>;
def err_hex_constant_requires : Error<
"hexadecimal floating %select{constant|literal}0 requires "
"%select{an exponent|a significand}1">;
def ext_hex_constant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">, InGroup<C99>;
def ext_hex_literal_invalid : Extension<
- "hexadecimal floating literals are a C++1z feature">, InGroup<CXX1z>;
-def warn_cxx1z_hex_literal : Warning<
+ "hexadecimal floating literals are a C++17 feature">, InGroup<CXX17>;
+def warn_cxx17_hex_literal : Warning<
"hexadecimal floating literals are incompatible with "
- "C++ standards before C++1z">,
- InGroup<CXXPre1zCompatPedantic>, DefaultIgnore;
+ "C++ standards before C++17">,
+ InGroup<CXXPre17CompatPedantic>, DefaultIgnore;
def ext_binary_literal : Extension<
"binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>;
def ext_binary_literal_cxx14 : Extension<
"binary integer literals are a C++14 extension">, InGroup<CXX14BinaryLiteral>;
def warn_cxx11_compat_binary_literal : Warning<
"binary integer literals are incompatible with C++ standards before C++14">,
- InGroup<CXXPre14CompatPedantic>, DefaultIgnore;
+ InGroup<CXXPre14CompatBinaryLiteral>, DefaultIgnore;
def err_pascal_string_too_long : Error<"Pascal string is too long">;
def err_escape_too_large : Error<
"%select{hex|octal}0 escape sequence out of range">;
@@ -208,8 +208,8 @@ def warn_cxx98_compat_unicode_literal : Warning<
"unicode literals are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx14_compat_u8_character_literal : Warning<
- "unicode literals are incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "unicode literals are incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17Compat>, DefaultIgnore;
def warn_cxx11_compat_user_defined_literal : Warning<
"identifier after literal will be treated as a user-defined literal suffix "
"in C++11">, InGroup<CXX11Compat>, DefaultIgnore;
@@ -242,6 +242,7 @@ def warn_bad_character_encoding : ExtWarn<
"illegal character encoding in character literal">,
InGroup<InvalidSourceEncoding>;
def err_lexing_string : Error<"failure when lexing a string">;
+def err_placeholder_in_source : Error<"editor placeholder in source file">;
//===----------------------------------------------------------------------===//
@@ -345,6 +346,23 @@ def ext_pp_extra_tokens_at_eol : ExtWarn<
def ext_pp_comma_expr : Extension<"comma operator in operand of #if">;
def ext_pp_bad_vaargs_use : Extension<
"__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">;
+
+def ext_pp_bad_vaopt_use
+ : ExtWarn<
+ "__VA_OPT__ can only appear in the expansion of a variadic macro">,
+ InGroup<VariadicMacros>;
+
+def err_pp_missing_lparen_in_vaopt_use : Error<
+ "missing '(' following __VA_OPT__">;
+def err_pp_vaopt_nested_use : Error<
+ "__VA_OPT__ cannot be nested within its own replacement tokens">;
+
+def err_vaopt_paste_at_start : Error<
+ "'##' cannot appear at start of __VA_OPT__ argument">;
+
+def err_vaopt_paste_at_end
+ : Error<"'##' cannot appear at end of __VA_OPT__ argument">;
+
def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">, InGroup<MacroRedefined>;
def ext_variadic_macro : Extension<"variadic macros are a C99 feature">,
InGroup<VariadicMacros>;
@@ -502,12 +520,34 @@ def warn_pragma_diagnostic_invalid_token :
InGroup<UnknownPragmas>;
def warn_pragma_diagnostic_unknown_warning :
ExtWarn<"unknown warning group '%0', ignored">,
- InGroup<UnknownPragmas>;
+ InGroup<UnknownWarningOption>;
// - #pragma __debug
def warn_pragma_debug_unexpected_command : Warning<
"unexpected debug command '%0'">, InGroup<IgnoredPragmas>;
def warn_pragma_debug_missing_argument : Warning<
"missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
+// #pragma module
+def err_pp_expected_module_name : Error<
+ "expected %select{identifier after '.' in |}0module name">;
+def err_pp_module_begin_wrong_module : Error<
+ "must specify '-fmodule-name=%0' to enter %select{|submodule of }1"
+ "this module%select{ (current module is %3)|}2">;
+def err_pp_module_begin_no_module_map : Error<
+ "no module map available for module %0">;
+def err_pp_module_begin_no_submodule : Error<
+ "submodule %0.%1 not declared in module map">;
+def err_pp_module_begin_without_module_end : Error<
+ "no matching '#pragma clang module end' for this "
+ "'#pragma clang module begin'">;
+def err_pp_module_end_without_module_begin : Error<
+ "no matching '#pragma clang module begin' for this "
+ "'#pragma clang module end'">;
+def note_pp_module_begin_here : Note<
+ "entering module '%0' due to this pragma">;
+def err_pp_module_build_pth : Error<
+ "'#pragma clang module build' not supported in pretokenized header">;
+def err_pp_module_build_missing_end : Error<
+ "no matching '#pragma clang module endbuild' for this '#pragma clang module build'">;
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
def err_paste_at_start : Error<
@@ -594,8 +634,6 @@ def err_mmap_expected_mmap_file : Error<"expected a module map file name">;
def err_mmap_module_redefinition : Error<
"redefinition of module '%0'">;
def note_mmap_prev_definition : Note<"previously defined here">;
-def err_mmap_umbrella_dir_not_found : Error<
- "umbrella directory '%0' not found">;
def err_mmap_umbrella_clash : Error<
"umbrella for module '%0' already covers this directory">;
def err_mmap_module_id : Error<
@@ -647,6 +685,19 @@ def warn_mmap_mismatched_top_level_private : Warning<
InGroup<PrivateModule>;
def note_mmap_rename_top_level_private_as_submodule : Note<
"make '%0' a submodule of '%1' to ensure it can be found by name">;
+def err_mmap_duplicate_header_attribute : Error<
+ "header attribute '%0' specified multiple times">;
+def err_mmap_invalid_header_attribute_value : Error<
+ "expected integer literal as value for header attribute '%0'">;
+def err_mmap_expected_header_attribute : Error<
+ "expected a header attribute name ('size' or 'mtime')">;
+def err_mmap_conflicting_export_as : Error<
+ "conflicting re-export of module '%0' as '%1' or '%2'">;
+def warn_mmap_redundant_export_as : Warning<
+ "module '%0' already re-exported as '%1'">,
+ InGroup<PrivateModule>;
+def err_mmap_submodule_export_as : Error<
+ "only top-level modules can be re-exported as public">;
def warn_auto_module_import : Warning<
"treating #%select{include|import|include_next|__include_macros}0 as an "
@@ -656,6 +707,9 @@ def note_implicit_top_level_module_import_here : Note<
def warn_uncovered_module_header : Warning<
"umbrella header for module '%0' does not include header '%1'">,
InGroup<IncompleteUmbrella>;
+def warn_mmap_umbrella_dir_not_found : Warning<
+ "umbrella directory '%0' not found">,
+ InGroup<IncompleteUmbrella>;
def err_expected_id_building_module : Error<
"expected a module name in '__building_module' expression">;
def warn_use_of_private_header_outside_module : Warning<
diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def
index 0ab6724ed9..2467b24fd9 100644
--- a/include/clang/Basic/DiagnosticOptions.def
+++ b/include/clang/Basic/DiagnosticOptions.def
@@ -87,6 +87,8 @@ VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit)
VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit)
/// Limit number of times to perform spell checking.
VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit)
+/// Limit number of lines shown in a snippet.
+VALUE_DIAGOPT(SnippetLineLimit, 32, DefaultSnippetLineLimit)
VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops.
/// Column limit for formatting message diagnostics, or 0 if unused.
diff --git a/include/clang/Basic/DiagnosticOptions.h b/include/clang/Basic/DiagnosticOptions.h
index c9b0c5def9..c195003de5 100644
--- a/include/clang/Basic/DiagnosticOptions.h
+++ b/include/clang/Basic/DiagnosticOptions.h
@@ -63,11 +63,15 @@ public:
enum TextDiagnosticFormat { Clang, MSVC, Vi };
// Default values.
- enum { DefaultTabStop = 8, MaxTabStop = 100,
+ enum {
+ DefaultTabStop = 8,
+ MaxTabStop = 100,
DefaultMacroBacktraceLimit = 6,
DefaultTemplateBacktraceLimit = 10,
DefaultConstexprBacktraceLimit = 10,
- DefaultSpellCheckingLimit = 50 };
+ DefaultSpellCheckingLimit = 50,
+ DefaultSnippetLineLimit = 1,
+ };
// Define simple diagnostic options (with no accessors).
#define DIAGOPT(Name, Bits, Default) unsigned Name : Bits;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index b486e62c35..a8d6955da3 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -211,11 +211,11 @@ def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
def err_namespace_nonnamespace_scope : Error<
"namespaces can only be defined in global or namespace scope">;
def ext_nested_namespace_definition : ExtWarn<
- "nested namespace definition is a C++1z extension; "
- "define each namespace separately">, InGroup<CXX1z>;
+ "nested namespace definition is a C++17 extension; "
+ "define each namespace separately">, InGroup<CXX17>;
def warn_cxx14_compat_nested_namespace_definition : Warning<
- "nested namespace definition is incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "nested namespace definition is incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17Compat>, DefaultIgnore;
def err_inline_nested_namespace_definition : Error<
"nested namespace definition cannot be 'inline'">;
def err_expected_semi_after_attribute_list : Error<
@@ -358,14 +358,12 @@ def err_expected_coloncolon_after_super : Error<
"expected '::' after '__super'">;
def ext_decomp_decl_empty : ExtWarn<
- "ISO C++1z does not allow a decomposition group to be empty">,
+ "ISO C++17 does not allow a decomposition group to be empty">,
InGroup<DiagGroup<"empty-decomposition">>;
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
"method type specifier must start with '-' or '+'">;
-def err_objc_no_attributes_on_category : Error<
- "attributes may not be specified on a category">;
def err_objc_missing_end : Error<"missing '@end'">;
def note_objc_container_start : Note<
"%select{class|protocol|category|class extension|implementation"
@@ -438,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">;
@@ -517,16 +522,16 @@ def err_function_is_not_record : Error<
def err_super_in_using_declaration : Error<
"'__super' cannot be used with a using declaration">;
def ext_constexpr_if : ExtWarn<
- "constexpr if is a C++1z extension">, InGroup<CXX1z>;
+ "constexpr if is a C++17 extension">, InGroup<CXX17>;
def warn_cxx14_compat_constexpr_if : Warning<
- "constexpr if is incompatible with C++ standards before C++1z">,
- DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "constexpr if is incompatible with C++ standards before C++17">,
+ DefaultIgnore, InGroup<CXXPre17Compat>;
def ext_init_statement : ExtWarn<
- "'%select{if|switch}0' initialization statements are a C++1z extension">,
- InGroup<CXX1z>;
+ "'%select{if|switch}0' initialization statements are a C++17 extension">,
+ InGroup<CXX17>;
def warn_cxx14_compat_init_statement : Warning<
"%select{if|switch}0 initialization statements are incompatible with "
- "C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
@@ -553,10 +558,13 @@ def warn_cxx98_compat_noexcept_expr : Warning<
def warn_cxx98_compat_nullptr : Warning<
"'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
-def warn_cxx14_compat_attribute : Warning<
+def ext_ns_enum_attribute : Extension<
+ "attributes on %select{a namespace|an enumerator}0 declaration are "
+ "a C++17 extension">, InGroup<CXX17>;
+def warn_cxx14_compat_ns_enum_attribute : Warning<
"attributes on %select{a namespace|an enumerator}0 declaration are "
- "incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17CompatPedantic>, DefaultIgnore;
def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_attribute : Warning<
@@ -572,10 +580,10 @@ def err_cxx11_attribute_repeated : Error<
"attribute %0 cannot appear multiple times in an attribute specifier">;
def warn_cxx14_compat_using_attribute_ns : Warning<
"default scope specifier for attributes is incompatible with C++ standards "
- "before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore;
def ext_using_attribute_ns : ExtWarn<
- "default scope specifier for attributes is a C++1z extension">,
- InGroup<CXX1z>;
+ "default scope specifier for attributes is a C++17 extension">,
+ InGroup<CXX17>;
def err_using_attribute_ns_conflict : Error<
"attribute with scope specifier cannot follow default scope specifier">;
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
@@ -612,12 +620,12 @@ def err_expected_comma_greater : Error<
def err_class_on_template_template_param : Error<
"template template parameter requires 'class' after the parameter list">;
def ext_template_template_param_typename : ExtWarn<
- "template template parameter using 'typename' is a C++1z extension">,
- InGroup<CXX1z>;
+ "template template parameter using 'typename' is a C++17 extension">,
+ InGroup<CXX17>;
def warn_cxx14_compat_template_template_param_typename : Warning<
"template template parameter using 'typename' is "
- "incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17Compat>, DefaultIgnore;
def err_template_spec_syntax_non_template : Error<
"identifier followed by '<' indicates a class template specialization but "
"%0 %select{does not refer to a template|refers to a function template|"
@@ -690,11 +698,11 @@ def err_default_template_template_parameter_not_template : Error<
"template">;
def ext_fold_expression : ExtWarn<
- "pack fold expression is a C++1z extension">,
- InGroup<CXX1z>;
+ "pack fold expression is a C++17 extension">,
+ InGroup<CXX17>;
def warn_cxx14_compat_fold_expression : Warning<
- "pack fold expression is incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "pack fold expression is incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17Compat>, DefaultIgnore;
def err_expected_fold_operator : Error<
"expected a foldable binary operator in fold expression">;
def err_fold_operator_mismatch : Error<
@@ -725,8 +733,12 @@ def ext_nonstatic_member_init : ExtWarn<
def warn_cxx98_compat_nonstatic_member_init : Warning<
"in-class initialization of non-static data members is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
-def err_bitfield_member_init: Error<
- "bit-field member cannot have an in-class initializer">;
+def ext_bitfield_member_init: ExtWarn<
+ "default member initializer for bit-field is a C++2a extension">,
+ InGroup<CXX2a>;
+def warn_cxx17_compat_bitfield_member_init: Warning<
+ "default member initializer for bit-field is incompatible with "
+ "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
def err_incomplete_array_member_init: Error<
"array bound cannot be deduced from an in-class initializer">;
@@ -743,19 +755,19 @@ def err_alias_declaration_specialization : Error<
def err_alias_declaration_pack_expansion : Error<
"alias declaration cannot be a pack expansion">;
-// C++1z using-declaration pack expansions
+// C++17 using-declaration pack expansions
def ext_multi_using_declaration : ExtWarn<
"use of multiple declarators in a single using declaration is "
- "a C++1z extension">, InGroup<CXX1z>;
-def warn_cxx1z_compat_multi_using_declaration : Warning<
+ "a C++17 extension">, InGroup<CXX17>;
+def warn_cxx17_compat_multi_using_declaration : Warning<
"use of multiple declarators in a single using declaration is "
- "incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17Compat>, DefaultIgnore;
def ext_using_declaration_pack : ExtWarn<
- "pack expansion of using declaration is a C++1z extension">, InGroup<CXX1z>;
-def warn_cxx1z_compat_using_declaration_pack : Warning<
+ "pack expansion of using declaration is a C++17 extension">, InGroup<CXX17>;
+def warn_cxx17_compat_using_declaration_pack : Warning<
"pack expansion using declaration is incompatible with C++ standards "
- "before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore;
// C++11 override control
def ext_override_control_keyword : ExtWarn<
@@ -806,16 +818,16 @@ def err_lambda_missing_parens : Error<
"attribute specifier|'constexpr'}0">;
def err_lambda_decl_specifier_repeated : Error<
"%select{'mutable'|'constexpr'}0 cannot appear multiple times in a lambda declarator">;
-// C++1z lambda expressions
+// C++17 lambda expressions
def err_expected_star_this_capture : Error<
"expected 'this' following '*' in lambda capture list">;
-// C++1z constexpr lambda expressions
+// C++17 constexpr lambda expressions
def warn_cxx14_compat_constexpr_on_lambda : Warning<
- "constexpr on lambda expressions is incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
-def ext_constexpr_on_lambda_cxx1z : ExtWarn<
- "'constexpr' on lambda expressions is a C++1z extension">, InGroup<CXX1z>;
+ "constexpr on lambda expressions is incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17Compat>, DefaultIgnore;
+def ext_constexpr_on_lambda_cxx17 : ExtWarn<
+ "'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
// Availability attribute
def err_expected_version : Error<
@@ -882,9 +894,16 @@ def warn_pragma_expected_rparen : Warning<
"missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>;
+
+// '#pragma clang section' related errors
+def err_pragma_expected_clang_section_name : Error<
+ "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">;
+def err_pragma_clang_section_expected_equal : Error<
+ "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">;
def warn_pragma_expected_section_name : Warning<
"expected a string literal for the section name in '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
+
def warn_pragma_expected_section_push_pop_or_name : Warning<
"expected push, pop or a string literal for the section name in '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
@@ -974,6 +993,43 @@ def err_pragma_optimize_invalid_argument : Error<
"expected 'on' or 'off'">;
def err_pragma_optimize_extra_argument : Error<
"unexpected extra argument '%0' to '#pragma clang optimize'">;
+// - #pragma clang attribute
+def err_pragma_attribute_expected_push_pop : Error<
+ "expected 'push' or 'pop' after '#pragma clang attribute'">;
+def err_pragma_attribute_invalid_argument : Error<
+ "unexpected argument '%0' to '#pragma clang attribute'; "
+ "expected 'push' or 'pop'">;
+def err_pragma_attribute_expected_attribute : Error<
+ "expected an attribute after '('">;
+def err_pragma_attribute_expected_attribute_name : Error<
+ "expected identifier that represents an attribute name">;
+def err_pragma_attribute_extra_tokens_after_attribute : Error<
+ "extra tokens after attribute in a '#pragma clang attribute push'">;
+def err_pragma_attribute_unsupported_attribute : Error<
+ "attribute %0 is not supported by '#pragma clang attribute'">;
+def err_pragma_attribute_multiple_attributes : Error<
+ "more than one attribute specified in '#pragma clang attribute push'">;
+def err_pragma_attribute_expected_attribute_syntax : Error<
+ "expected an attribute that is specified using the GNU, C++11 or '__declspec'"
+ " syntax">;
+def note_pragma_attribute_use_attribute_kw : Note<"use the GNU '__attribute__' "
+ "syntax">;
+def err_pragma_attribute_invalid_subject_set_specifier : Error<
+ "expected attribute subject set specifier 'apply_to'">;
+def err_pragma_attribute_expected_subject_identifier : Error<
+ "expected an identifier that corresponds to an attribute subject rule">;
+def err_pragma_attribute_unknown_subject_rule : Error<
+ "unknown attribute subject rule '%0'">;
+def err_pragma_attribute_expected_subject_sub_identifier : Error<
+ "expected an identifier that corresponds to an attribute subject matcher "
+ "sub-rule; '%0' matcher %select{does not support sub-rules|supports the "
+ "following sub-rules: %2|}1">;
+def err_pragma_attribute_unknown_subject_sub_rule : Error<
+ "%select{invalid use of|unknown}2 attribute subject matcher sub-rule '%0'; "
+ "'%1' matcher %select{does not support sub-rules|supports the following "
+ "sub-rules: %3}2">;
+def err_pragma_attribute_duplicate_subject : Error<
+ "duplicate attribute subject matcher '%0'">;
def err_opencl_unroll_hint_on_non_loop : Error<
"OpenCL only supports 'opencl_unroll_hint' attribute on for, while, and do statements">;
@@ -1042,6 +1098,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'">;
@@ -1062,14 +1128,12 @@ def err_pragma_cannot_end_force_cuda_host_device : Error<
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {
-def err_expected_module_interface_decl : Error<
- "expected module declaration at start of module interface">;
def err_unexpected_module_decl : Error<
- "module declaration must be the first declaration in the translation unit">;
+ "module declaration can only appear at the top level">;
def err_module_expected_ident : Error<
- "expected a module name after module%select{| import}0">;
-def err_unexpected_module_kind : Error<
- "unexpected module kind %0; expected 'implementation' or 'partition'">;
+ "expected a module name after '%select{module|import}0'">;
+def err_module_implementation_partition : Error<
+ "module partition must be declared 'export'">;
def err_attribute_not_module_attr : Error<
"%0 attribute cannot be applied to a module">;
def err_attribute_not_import_attr : Error<
diff --git a/include/clang/Basic/DiagnosticRefactoringKinds.td b/include/clang/Basic/DiagnosticRefactoringKinds.td
new file mode 100644
index 0000000000..ee396b9307
--- /dev/null
+++ b/include/clang/Basic/DiagnosticRefactoringKinds.td
@@ -0,0 +1,34 @@
+//==--- DiagnosticRefactoringKinds.td - refactoring diagnostics -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Refactoring Diagnostics
+//===----------------------------------------------------------------------===//
+
+let Component = "Refactoring" in {
+
+let CategoryName = "Refactoring Invocation Issue" in {
+
+def err_refactor_no_selection : Error<"refactoring action can't be initiated "
+ "without a selection">;
+def err_refactor_selection_no_symbol : Error<"there is no symbol at the given "
+ "location">;
+def err_refactor_selection_invalid_ast : Error<"the provided selection does "
+ "not overlap with the AST nodes of interest">;
+
+def err_refactor_code_outside_of_function : Error<"the selected code is not a "
+ "part of a function's / method's body">;
+def err_refactor_extract_simple_expression : Error<"the selected expression "
+ "is too simple to extract">;
+def err_refactor_extract_prohibited_expression : Error<"the selected "
+ "expression can't be extracted">;
+
+}
+
+} // end of Refactoring diagnostics
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 9764c9ee34..b8538f92cb 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -194,6 +194,8 @@ def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">,
InGroup<DuplicateDeclSpecifier>;
def ext_plain_complex : ExtWarn<
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
+def ext_imaginary_constant : Extension<
+ "imaginary constants are a GNU extension">, InGroup<GNUImaginaryConstant>;
def ext_integer_complex : Extension<
"complex integer types are a GNU extension">, InGroup<GNUComplexInteger>;
@@ -211,9 +213,9 @@ def warn_auto_storage_class : Warning<
def warn_deprecated_register : Warning<
"'register' storage class specifier is deprecated "
- "and incompatible with C++1z">, InGroup<DeprecatedRegister>;
+ "and incompatible with C++17">, InGroup<DeprecatedRegister>;
def ext_register_storage_class : ExtWarn<
- "ISO C++1z does not allow 'register' storage class specifier">,
+ "ISO C++17 does not allow 'register' storage class specifier">,
DefaultError, InGroup<Register>;
def err_invalid_decl_spec_combination : Error<
@@ -293,8 +295,20 @@ def warn_empty_parens_are_function_decl : Warning<
def warn_parens_disambiguated_as_function_declaration : Warning<
"parentheses were disambiguated as a function declaration">,
InGroup<VexingParse>;
+def warn_parens_disambiguated_as_variable_declaration : Warning<
+ "parentheses were disambiguated as redundant parentheses around declaration "
+ "of variable named %0">, InGroup<VexingParse>;
+def warn_redundant_parens_around_declarator : Warning<
+ "redundant parentheses surrounding declarator">,
+ InGroup<DiagGroup<"redundant-parens">>, DefaultIgnore;
def note_additional_parens_for_variable_declaration : Note<
"add a pair of parentheses to declare a variable">;
+def note_raii_guard_add_name : Note<
+ "add a variable name to declare a %0 initialized with %1">;
+def note_function_style_cast_add_parentheses : Note<
+ "add enclosing parentheses to perform a function-style cast">;
+def note_remove_parens_for_variable_declaration : Note<
+ "remove parentheses to silence this warning">;
def note_empty_parens_function_call : Note<
"change this ',' to a ';' to call %0">;
def note_empty_parens_default_ctor : Note<
@@ -303,6 +317,8 @@ def note_empty_parens_zero_initialize : Note<
"replace parentheses with an initializer to declare a variable">;
def warn_unused_function : Warning<"unused function %0">,
InGroup<UnusedFunction>, DefaultIgnore;
+def warn_unused_template : Warning<"unused %select{function|variable}0 template %1">,
+ InGroup<UnusedTemplate>, DefaultIgnore;
def warn_unused_member_function : Warning<"unused member function %0">,
InGroup<UnusedMemberFunction>, DefaultIgnore;
def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">,
@@ -339,7 +355,7 @@ def warn_implicit_function_decl : Warning<
"implicit declaration of function %0">,
InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
def ext_implicit_function_decl : ExtWarn<
- "implicit declaration of function %0 is invalid in C99">,
+ "implicit declaration of function %0 is invalid in %select{C99|OpenCL}1">,
InGroup<ImplicitFunctionDeclare>;
def note_function_suggestion : Note<"did you mean %0?">;
@@ -350,8 +366,10 @@ def err_language_linkage_spec_unknown : Error<"unknown linkage language">;
def err_language_linkage_spec_not_ascii : Error<
"string literal in language linkage specifier cannot have an "
"encoding-prefix">;
-def warn_use_out_of_scope_declaration : Warning<
- "use of out-of-scope declaration of %0">;
+def ext_use_out_of_scope_declaration : ExtWarn<
+ "use of out-of-scope declaration of %0%select{| whose type is not "
+ "compatible with that of an implicit declaration}1">,
+ InGroup<DiagGroup<"out-of-scope-function">>;
def err_inline_non_function : Error<
"'inline' can only appear on functions%select{| and non-local variables}0">;
def err_noreturn_non_function : Error<
@@ -369,7 +387,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>,
@@ -387,9 +407,9 @@ def err_decomp_decl_context : Error<
"decomposition declaration not permitted in this context">;
def warn_cxx14_compat_decomp_decl : Warning<
"decomposition declarations are incompatible with "
- "C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre17Compat>;
def ext_decomp_decl : ExtWarn<
- "decomposition declarations are a C++1z extension">, InGroup<CXX1z>;
+ "decomposition declarations are a C++17 extension">, InGroup<CXX17>;
def err_decomp_decl_spec : Error<
"decomposition declaration cannot be declared "
"%plural{1:'%1'|:with '%1' specifiers}0">;
@@ -490,7 +510,7 @@ def err_access_decl : Error<
"ISO C++11 does not allow access declarations; "
"use using declarations instead">;
def ext_dynamic_exception_spec : ExtWarn<
- "ISO C++1z does not allow dynamic exception specifications">,
+ "ISO C++17 does not allow dynamic exception specifications">,
InGroup<DynamicExceptionSpec>, DefaultError;
def warn_exception_spec_deprecated : Warning<
"dynamic exception specifications are deprecated">,
@@ -501,9 +521,9 @@ def warn_deprecated_copy_operation : Warning<
"for %0 is deprecated because it has a user-declared "
"%select{copy %select{assignment operator|constructor}1|destructor}2">,
InGroup<Deprecated>, DefaultIgnore;
-def warn_cxx1z_compat_exception_spec_in_signature : Warning<
+def warn_cxx17_compat_exception_spec_in_signature : Warning<
"mangled name of %0 will change in C++17 due to non-throwing exception "
- "specification in function signature">, InGroup<CXX1zCompat>;
+ "specification in function signature">, InGroup<CXX17CompatMangling>;
def warn_global_constructor : Warning<
"declaration requires a global constructor">,
@@ -533,10 +553,10 @@ def err_maybe_falloff_nonvoid_block : Error<
def err_falloff_nonvoid_block : Error<
"control reaches end of non-void block">;
def warn_maybe_falloff_nonvoid_coroutine : Warning<
- "control may reach end of non-void coroutine">,
+ "control may reach end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">,
InGroup<ReturnType>;
def warn_falloff_nonvoid_coroutine : Warning<
- "control reaches end of non-void coroutine">,
+ "control reaches end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">,
InGroup<ReturnType>;
def warn_suggest_noreturn_function : Warning<
"%select{function|method}0 %1 could be declared with attribute 'noreturn'">,
@@ -577,6 +597,7 @@ def warn_redecl_library_builtin : Warning<
def err_builtin_definition : Error<"definition of builtin function %0">;
def err_arm_invalid_specialreg : Error<"invalid special register for builtin">;
def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">;
+def err_invalid_cpu_is : Error<"invalid cpu name for builtin">;
def err_builtin_needs_feature : Error<"%0 needs target feature %1">;
def err_function_needs_feature
: Error<"always_inline function %1 requires target feature '%2', but would "
@@ -708,6 +729,19 @@ def err_pragma_options_align_mac68k_target_unsupported : Error<
def warn_pragma_pack_invalid_alignment : Warning<
"expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">,
InGroup<IgnoredPragmas>;
+def warn_pragma_pack_non_default_at_include : Warning<
+ "non-default #pragma pack value changes the alignment of struct or union "
+ "members in the included file">, InGroup<PragmaPackSuspiciousInclude>,
+ DefaultIgnore;
+def warn_pragma_pack_modified_after_include : Warning<
+ "the current #pragma pack aligment value is modified in the included "
+ "file">, InGroup<PragmaPack>;
+def warn_pragma_pack_no_pop_eof : Warning<"unterminated "
+ "'#pragma pack (push, ...)' at end of file">, InGroup<PragmaPack>;
+def note_pragma_pack_here : Note<
+ "previous '#pragma pack' directive that modifies alignment is here">;
+def note_pragma_pack_pop_instead_reset : Note<
+ "did you intend to use '#pragma pack (pop)' instead of '#pragma pack()'?">;
// Follow the Microsoft implementation.
def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">;
def warn_pragma_pack_pop_identifer_and_alignment : Warning<
@@ -728,6 +762,9 @@ def err_super_in_lambda_unsupported : Error<
def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">,
InGroup<IgnoredPragmas>;
+def warn_atl_uuid_deprecated : Warning<
+ "specifying 'uuid' as an ATL attribute is deprecated; use __declspec instead">,
+ InGroup<DeprecatedDeclarations>;
def warn_pragma_unused_expected_var_arg : Warning<
"only variables can be arguments to '#pragma unused'">,
InGroup<IgnoredPragmas>;
@@ -748,6 +785,25 @@ def err_pragma_loop_compatibility : Error<
def err_pragma_loop_precedes_nonloop : Error<
"expected a for, while, or do-while loop to follow '%0'">;
+def err_pragma_attribute_matcher_subrule_contradicts_rule : Error<
+ "redundant attribute subject matcher sub-rule '%0'; '%1' already matches "
+ "those declarations">;
+def err_pragma_attribute_matcher_negated_subrule_contradicts_subrule : Error<
+ "negated attribute subject matcher sub-rule '%0' contradicts sub-rule '%1'">;
+def err_pragma_attribute_invalid_matchers : Error<
+ "attribute %0 can't be applied to %1">;
+def err_pragma_attribute_stack_mismatch : Error<
+ "'#pragma clang attribute pop' with no matching '#pragma clang attribute push'">;
+def warn_pragma_attribute_unused : Warning<
+ "unused attribute %0 in '#pragma clang attribute push' region">,
+ InGroup<PragmaClangAttribute>;
+def note_pragma_attribute_region_ends_here : Note<
+ "'#pragma clang attribute push' regions ends here">;
+def err_pragma_attribute_no_pop_eof : Error<"unterminated "
+ "'#pragma clang attribute push' at end of file">;
+def note_pragma_attribute_applied_decl_here : Note<
+ "when applied to this declaration">;
+
/// Objective-C parser diagnostics
def err_duplicate_class_def : Error<
"duplicate interface definition for class %0">;
@@ -782,8 +838,10 @@ def warn_property_types_are_incompatible : Warning<
"property type %0 is incompatible with type %1 inherited from %2">,
InGroup<DiagGroup<"incompatible-property-type">>;
def warn_protocol_property_mismatch : Warning<
- "property of type %0 was selected for synthesis">,
+ "property %select{of type %1|with attribute '%1'|without attribute '%1'|with "
+ "getter %1|with setter %1}0 was selected for synthesis">,
InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>;
+def err_protocol_property_mismatch: Error<warn_protocol_property_mismatch.Text>;
def err_undef_interface : Error<"cannot find interface declaration for %0">;
def err_category_forward_interface : Error<
"cannot define %select{category|class extension}0 for undefined class %1">;
@@ -1003,6 +1061,8 @@ def warn_auto_synthesizing_protocol_property :Warning<
"auto property synthesis will not synthesize property %0"
" declared in protocol %1">,
InGroup<DiagGroup<"objc-protocol-property-synthesis">>;
+def note_add_synthesize_directive : Note<
+ "add a '@synthesize' directive">;
def warn_no_autosynthesis_shared_ivar_property : Warning <
"auto property synthesis will not synthesize property "
"%0 because it cannot share an ivar with another synthesized property">,
@@ -1060,7 +1120,9 @@ def err_category_property : Error<
def note_property_declare : Note<
"property declared here">;
def note_protocol_property_declare : Note<
- "it could also be property of type %0 declared here">;
+ "it could also be property "
+ "%select{of type %1|without attribute '%1'|with attribute '%1'|with getter "
+ "%1|with setter %1}0 declared here">;
def note_property_synthesize : Note<
"property synthesized here">;
def err_synthesize_category_decl : Error<
@@ -1159,21 +1221,31 @@ def err_objc_kindof_nonobject : Error<
def err_objc_kindof_wrong_position : Error<
"'__kindof' type specifier must precede the declarator">;
+def err_objc_method_unsupported_param_ret_type : Error<
+ "%0 %select{parameter|return}1 type is unsupported; "
+ "support for vector types for this target is introduced in %2">;
+
+def warn_messaging_unqualified_id : Warning<
+ "messaging unqualified id">, DefaultIgnore,
+ InGroup<DiagGroup<"objc-messaging-id">>;
+
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">;
def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">;
+def err_static_assert_requirement_failed : Error<
+ "static_assert failed due to requirement '%0'%select{ %2|}1">;
def ext_static_assert_no_message : ExtWarn<
- "static_assert with no message is a C++1z extension">, InGroup<CXX1z>;
+ "static_assert with no message is a C++17 extension">, InGroup<CXX17>;
def warn_cxx14_compat_static_assert_no_message : Warning<
- "static_assert with no message is incompatible with C++ standards before C++1z">,
- DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "static_assert with no message is incompatible with C++ standards before C++17">,
+ DefaultIgnore, InGroup<CXXPre17Compat>;
def ext_inline_variable : ExtWarn<
- "inline variables are a C++1z extension">, InGroup<CXX1z>;
+ "inline variables are a C++17 extension">, InGroup<CXX17>;
def warn_cxx14_compat_inline_variable : Warning<
- "inline variables are incompatible with C++ standards before C++1z">,
- DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "inline variables are incompatible with C++ standards before C++17">,
+ DefaultIgnore, InGroup<CXXPre17Compat>;
def warn_inline_namespace_reopened_noninline : Warning<
"inline namespace reopened as a non-inline namespace">;
@@ -1277,6 +1349,8 @@ def err_type_defined_in_alias_template : Error<
"%0 cannot be defined in a type alias template">;
def err_type_defined_in_condition : Error<
"%0 cannot be defined in a condition">;
+def err_type_defined_in_enum : Error<
+ "%0 cannot be defined in an enumeration">;
def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">;
@@ -1524,11 +1598,9 @@ def note_ivar_decl : Note<"instance variable is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
def note_member_synthesized_at : Note<
- "implicit %select{default constructor|copy constructor|move constructor|copy "
- "assignment operator|move assignment operator|destructor}0 for %1 first "
- "required here">;
-def note_inhctor_synthesized_at : Note<
- "inherited constructor for %0 first required here">;
+ "in implicit %select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}0 for %1 "
+ "first required here">;
def err_missing_default_ctor : Error<
"%select{constructor for %1 must explicitly initialize the|"
"implicit default constructor for %1 must explicitly initialize the|"
@@ -1603,6 +1675,11 @@ def err_conflicting_overriding_cc_attributes : Error<
"virtual function %0 has different calling convention attributes "
"%diff{($) than the function it overrides (which has calling convention $)|"
"than the function it overrides}1,2">;
+def warn_overriding_method_missing_noescape : Warning<
+ "parameter of overriding method should be annotated with "
+ "__attribute__((noescape))">, InGroup<MissingNoEscape>;
+def note_overridden_marked_noescape : Note<
+ "parameter of overridden method is annotated with __attribute__((noescape))">;
def err_covariant_return_inaccessible_base : Error<
"invalid covariant return for virtual function: %1 is a "
@@ -1687,8 +1764,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"
@@ -1814,8 +1891,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>;
@@ -1887,7 +1965,7 @@ def err_auto_not_allowed : Error<
"|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 until C++1z|in block literal"
+ "|in exception declaration|in template parameter until C++17|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
"|in conversion function type|here|in lambda parameter"
"|in type allocated by 'new'|in K&R-style function parameter"
@@ -1929,6 +2007,9 @@ def err_auto_var_deduction_failure_from_init_list : Error<
"cannot deduce actual type for variable %0 with type %1 from initializer list">;
def err_auto_new_deduction_failure : Error<
"new expression for type %0 has incompatible constructor argument of type %1">;
+def err_auto_inconsistent_deduction : Error<
+ "deduced conflicting types %diff{($ vs $) |}0,1"
+ "for initializer list element type">;
def err_auto_different_deductions : Error<
"%select{'auto'|'decltype(auto)'|'__auto_type'|template arguments}0 "
"deduced as %1 in declaration of %2 and "
@@ -1964,7 +2045,7 @@ 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
+// C++17 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 "
@@ -2062,7 +2143,7 @@ def err_enum_invalid_underlying : Error<
"non-integral type %0 is an invalid underlying type">;
def err_enumerator_too_large : Error<
"enumerator value is not representable in the underlying type %0">;
-def ext_enumerator_too_large : ExtWarn<
+def ext_enumerator_too_large : Extension<
"enumerator value is not representable in the underlying type %0">,
InGroup<MicrosoftEnumValue>;
def err_enumerator_wrapped : Error<
@@ -2112,11 +2193,11 @@ def err_for_range_iter_deduction_failure : Error<
def err_for_range_member_begin_end_mismatch : Error<
"range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">;
def ext_for_range_begin_end_types_differ : ExtWarn<
- "'begin' and 'end' returning different types (%0 and %1) is a C++1z extension">,
- InGroup<CXX1z>;
+ "'begin' and 'end' returning different types (%0 and %1) is a C++17 extension">,
+ InGroup<CXX17>;
def warn_for_range_begin_end_types_differ : Warning<
"'begin' and 'end' returning different types (%0 and %1) is incompatible "
- "with C++ standards before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "with C++ standards before C++17">, InGroup<CXXPre17Compat>, DefaultIgnore;
def note_in_for_range: Note<
"when looking up '%select{begin|end}0' function for range expression "
"of type %1">;
@@ -2352,8 +2433,9 @@ def err_attribute_requires_positive_integer : Error<
def err_attribute_requires_opencl_version : Error<
"%0 attribute requires OpenCL version %1%select{| or above}2">;
def warn_unsupported_target_attribute
- : Warning<"Ignoring unsupported '%0' in the target attribute string">,
- InGroup<IgnoredAttributes>;
+ : Warning<"ignoring %select{unsupported|duplicate}0"
+ "%select{| architecture}1 '%2' in the target attribute string">,
+ InGroup<IgnoredAttributes>;
def err_attribute_unsupported
: Error<"%0 attribute is not supported for this target">;
// The err_*_attribute_argument_not_int are separate because they're used by
@@ -2434,6 +2516,9 @@ def err_attribute_invalid_size : Error<
"vector size not an integral multiple of component size">;
def err_attribute_zero_size : Error<"zero vector size">;
def err_attribute_size_too_large : Error<"vector size too large">;
+def err_typecheck_vector_not_convertable_implict_truncation : Error<
+ "cannot convert between %select{scalar|vector}0 type %1 and vector type"
+ " %2 as implicit conversion would cause truncation">;
def err_typecheck_vector_not_convertable : Error<
"cannot convert between vector values of different size (%0 and %1)">;
def err_typecheck_vector_not_convertable_non_scalar : Error<
@@ -2456,7 +2541,7 @@ def err_attribute_address_multiple_qualifiers : Error<
def err_attribute_address_function_type : Error<
"function type may not be qualified with an address space">;
def err_as_qualified_auto_decl : Error<
- "automatic variable qualified with an address space">;
+ "automatic variable qualified with an%select{| invalid}0 address space">;
def err_arg_with_address_space : Error<
"parameter may not be qualified with an address space">;
def err_field_with_address_space : Error<
@@ -2549,6 +2634,8 @@ def err_attribute_section_invalid_for_target : Error<
"argument to 'section' attribute is not valid for this target: %0">;
def warn_mismatched_section : Warning<
"section does not match previous declaration">, InGroup<Section>;
+def warn_attribute_section_on_redeclaration : Warning<
+ "section attribute is specified on redeclared variable">, InGroup<Section>;
def err_anonymous_property: Error<
"anonymous property is not supported">;
@@ -2735,6 +2822,7 @@ def warn_attribute_wrong_decl_type : Warning<
"|types and namespaces"
"|Objective-C interfaces"
"|methods and properties"
+ "|functions, methods, and properties"
"|struct or union"
"|struct, union or class"
"|types"
@@ -2794,9 +2882,9 @@ def warn_cconv_structors : Warning<
def err_regparm_mismatch : Error<"function declared with regparm(%0) "
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
-def err_returns_retained_mismatch : Error<
- "function declared with the ns_returns_retained attribute "
- "was previously declared without the ns_returns_retained attribute">;
+def err_function_attribute_mismatch : Error<
+ "function declared with %0 attribute "
+ "was previously declared without the %0 attribute">;
def err_objc_precise_lifetime_bad_type : Error<
"objc_precise_lifetime only applies to retainable types; type here is %0">;
def warn_objc_precise_lifetime_meaningless : Error<
@@ -2837,17 +2925,18 @@ def note_protocol_method : Note<
def warn_unguarded_availability :
Warning<"%0 is only available on %1 %2 or newer">,
InGroup<UnguardedAvailability>, DefaultIgnore;
-def warn_partial_availability : Warning<"%0 is only available conditionally">,
- InGroup<UnguardedAvailability>, DefaultIgnore;
-def note_partial_availability_silence : Note<
- "explicitly redeclare %0 to silence this warning">;
+def warn_unguarded_availability_new :
+ Warning<warn_unguarded_availability.Text>,
+ InGroup<UnguardedAvailabilityNew>;
+def note_decl_unguarded_availability_silence : Note<
+ "annotate %select{%1|anonymous %1}0 with an availability attribute to silence this warning">;
def note_unguarded_available_silence : Note<
- "enclose %0 in an @available check to silence this warning">;
-def warn_partial_message : Warning<"%0 is partial: %1">,
- InGroup<UnguardedAvailability>, DefaultIgnore;
-def warn_partial_fwdclass_message : Warning<
- "%0 may be partial because the receiver type is unknown">,
- InGroup<UnguardedAvailability>, DefaultIgnore;
+ "enclose %0 in %select{an @available|a __builtin_available}1 check to silence"
+ " this warning">;
+def warn_at_available_unchecked_use : Warning<
+ "%select{@available|__builtin_available}0 does not guard availability here; "
+ "use if (%select{@available|__builtin_available}0) instead">,
+ InGroup<DiagGroup<"unsupported-availability-guard">>;
// Thread Safety Attributes
def warn_invalid_capability_name : Warning<
@@ -3009,6 +3098,8 @@ def warn_impcast_vector_scalar : Warning<
def warn_impcast_complex_scalar : Warning<
"implicit conversion discards imaginary component: %0 to %1">,
InGroup<Conversion>, DefaultIgnore;
+def err_impcast_complex_scalar : Error<
+ "implicit conversion from %0 to %1 is not permitted in C++">;
def warn_impcast_float_precision : Warning<
"implicit conversion loses floating-point precision: %0 to %1">,
InGroup<Conversion>, DefaultIgnore;
@@ -3134,6 +3225,9 @@ def warn_int_to_void_pointer_cast : Warning<
"cast to %1 from smaller integer type %0">,
InGroup<IntToVoidPointerCast>;
+def warn_attribute_ignored_for_field_of_type : Warning<
+ "%0 attribute ignored for field of type %1">,
+ InGroup<IgnoredAttributes>;
def warn_no_underlying_type_specified_for_enum_bitfield : Warning<
"enums in the Microsoft ABI are signed integers by default; consider giving "
"the enum %0 an unsigned underlying type to make this code portable">,
@@ -3228,7 +3322,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<
@@ -3245,13 +3340,15 @@ def warn_iboutletcollection_property_assign : Warning<
"IBOutletCollection properties should be copy/strong and not assign">,
InGroup<ObjCInvalidIBOutletProperty>;
-def err_attribute_overloadable_missing : Error<
- "%select{overloaded function|redeclaration of}0 %1 must have the "
- "'overloadable' attribute">;
+def err_attribute_overloadable_mismatch : Error<
+ "redeclaration of %0 must %select{not |}1have the 'overloadable' attribute">;
def note_attribute_overloadable_prev_overload : Note<
- "previous overload of function is here">;
+ "previous %select{unmarked |}0overload of function is here">;
def err_attribute_overloadable_no_prototype : Error<
"'overloadable' function %0 must have a prototype">;
+def err_attribute_overloadable_multiple_unmarked_overloads : Error<
+ "at most one overload for a given name may lack the 'overloadable' "
+ "attribute">;
def warn_ns_attribute_wrong_return_type : Warning<
"%0 attribute only applies to %select{functions|methods|properties}1 that "
"return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,
@@ -3465,6 +3562,8 @@ def note_ovl_candidate_substitution_failure : Note<
"candidate template ignored: substitution failure%0%1">;
def note_ovl_candidate_disabled_by_enable_if : Note<
"candidate template ignored: disabled by %0%1">;
+def note_ovl_candidate_disabled_by_requirement : Note<
+ "candidate template ignored: requirement '%0' was not satisfied%1">;
def note_ovl_candidate_has_pass_object_size_params: Note<
"candidate address cannot be taken because parameter %0 has "
"pass_object_size attribute">;
@@ -3846,8 +3945,8 @@ def err_template_nontype_parm_bad_type : Error<
"a non-type template parameter cannot have type %0">;
def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
"non-type template parameters declared with %0 are incompatible with C++ "
- "standards before C++1z">,
- DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "standards before C++17">,
+ DefaultIgnore, InGroup<CXXPre17Compat>;
def err_template_param_default_arg_redefinition : Error<
"template parameter redefines default argument">;
def note_template_param_prev_default_arg : Note<
@@ -4021,6 +4120,13 @@ def err_pointer_to_member_call_drops_quals : Error<
def err_pointer_to_member_oper_value_classify: Error<
"pointer-to-member function type %0 can only be called on an "
"%select{rvalue|lvalue}1">;
+def ext_pointer_to_const_ref_member_on_rvalue : Extension<
+ "invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension">,
+ InGroup<CXX2a>, SFINAEFailure;
+def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning<
+ "invoking a pointer to a 'const &' member function on an rvalue is "
+ "incompatible with C++ standards before C++2a">,
+ InGroup<CXXPre2aCompatPedantic>, DefaultIgnore;
def ext_ms_deref_template_argument: ExtWarn<
"non-type template argument containing a dereference operation is a "
"Microsoft extension">, InGroup<MicrosoftTemplate>;
@@ -4378,6 +4484,9 @@ def err_typename_nested_not_found : Error<"no type named %0 in %1">;
def err_typename_nested_not_found_enable_if : Error<
"no type named 'type' in %0; 'enable_if' cannot be used to disable "
"this declaration">;
+def err_typename_nested_not_found_requirement : Error<
+ "failed requirement '%0'; 'enable_if' cannot be used to disable this "
+ "declaration">;
def err_typename_nested_not_type : Error<
"typename specifier refers to non-type member %0 in %1">;
def note_typename_refers_here : Note<
@@ -4517,8 +4626,11 @@ def warn_deprecated_fwdclass_message : Warning<
"%0 may be deprecated because the receiver type is unknown">,
InGroup<DeprecatedDeclarations>;
def warn_deprecated_def : Warning<
- "Implementing deprecated %select{method|class|category}0">,
- InGroup<DeprecatedImplementations>, DefaultIgnore;
+ "implementing deprecated %select{method|class|category}0">,
+ InGroup<DeprecatedImplementations>, DefaultIgnore;
+def warn_unavailable_def : Warning<
+ "implementing unavailable method">,
+ InGroup<DeprecatedImplementations>, DefaultIgnore;
def err_unavailable : Error<"%0 is unavailable">;
def err_property_method_unavailable :
Error<"property access is using %0 method which is unavailable">;
@@ -4545,7 +4657,7 @@ def warn_missing_prototype : Warning<
def note_declaration_not_a_prototype : Note<
"this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">;
def warn_strict_prototypes : Warning<
- "this %select{function declaration is not|"
+ "this %select{function declaration is not|block declaration is not|"
"old-style function definition is not preceded by}0 a prototype">,
InGroup<DiagGroup<"strict-prototypes">>, DefaultIgnore;
def warn_missing_variable_declarations : Warning<
@@ -4576,6 +4688,8 @@ def err_abi_tag_on_redeclaration : Error<
"cannot add 'abi_tag' attribute in a redeclaration">;
def err_new_abi_tag_on_redeclaration : Error<
"'abi_tag' %0 missing in original declaration">;
+def note_use_ifdef_guards : Note<
+ "unguarded header; consider using #ifdef guards or #pragma once">;
def note_deleted_dtor_no_operator_delete : Note<
"virtual destructor requires an unambiguous, accessible 'operator delete'">;
@@ -4614,6 +4728,14 @@ def note_deleted_assign_field : Note<
def warn_undefined_internal : Warning<
"%select{function|variable}0 %q1 has internal linkage but is not defined">,
InGroup<DiagGroup<"undefined-internal">>;
+def err_undefined_internal_type : Error<
+ "%select{function|variable}0 %q1 is used but not defined in this "
+ "translation unit, and cannot be defined in any other translation unit "
+ "because its type does not have linkage">;
+def ext_undefined_internal_type : Extension<
+ "ISO C++ requires a definition in this translation unit for "
+ "%select{function|variable}0 %q1 because its type does not have linkage">,
+ InGroup<DiagGroup<"undefined-internal-type">>;
def warn_undefined_inline : Warning<"inline function %q0 is not defined">,
InGroup<DiagGroup<"undefined-inline">>;
def err_undefined_inline_var : Error<"inline variable %q0 is not defined">;
@@ -4679,6 +4801,9 @@ def err_thread_non_thread : Error<
def err_thread_thread_different_kind : Error<
"thread-local declaration of %0 with %select{static|dynamic}1 initialization "
"follows declaration with %select{dynamic|static}1 initialization">;
+def err_mismatched_owning_module : Error<
+ "declaration of %0 in %select{the global module|module %2}1 follows "
+ "declaration in %select{the global module|module %4}3">;
def err_redefinition_different_type : Error<
"redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
def err_redefinition_different_kind : Error<
@@ -4732,7 +4857,7 @@ def ext_forward_ref_enum : Extension<
"ISO C forbids forward references to 'enum' types">;
def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
-def ext_ms_forward_ref_enum : Extension<
+def ext_ms_forward_ref_enum : ExtWarn<
"forward references to 'enum' types are a Microsoft extension">,
InGroup<MicrosoftEnumForwardReference>;
def ext_forward_ref_enum_def : Extension<
@@ -4908,6 +5033,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">,
@@ -4962,6 +5102,8 @@ def note_protected_by_if_available : Note<
"jump enters controlled statement of if available">;
def note_protected_by_vla : Note<
"jump bypasses initialization of variable length array">;
+def note_protected_by_objc_fast_enumeration : Note<
+ "jump enters Objective-C fast enumeration loop">;
def note_protected_by_objc_try : Note<
"jump bypasses initialization of @try block">;
def note_protected_by_objc_catch : Note<
@@ -5080,6 +5222,28 @@ def ext_flexible_array_empty_aggregate_gnu : Extension<
def ext_flexible_array_union_gnu : Extension<
"flexible array member %0 in a union is a GNU extension">, InGroup<GNUFlexibleArrayUnionMember>;
+def err_flexible_array_not_at_end : Error<
+ "flexible array member %0 with type %1 is not at the end of"
+ " %select{struct|interface|union|class|enum}2">;
+def err_objc_variable_sized_type_not_at_end : Error<
+ "field %0 with variable sized type %1 is not at the end of class">;
+def note_next_field_declaration : Note<
+ "next field declaration is here">;
+def note_next_ivar_declaration : Note<
+ "next %select{instance variable declaration|synthesized instance variable}0"
+ " is here">;
+def err_synthesize_variable_sized_ivar : Error<
+ "synthesized property with variable size type %0"
+ " requires an existing instance variable">;
+def err_flexible_array_arc_retainable : Error<
+ "ARC forbids flexible array members with retainable object type">;
+def warn_variable_sized_ivar_visibility : Warning<
+ "field %0 with variable sized type %1 is not visible to subclasses and"
+ " can conflict with their instance variables">, InGroup<ObjCFlexibleArray>;
+def warn_superclass_variable_sized_type_not_at_end : Warning<
+ "field %0 can overwrite instance variable %1 with variable sized type %2"
+ " in superclass %3">, InGroup<ObjCFlexibleArray>;
+
let CategoryName = "ARC Semantic Issue" in {
// ARC-mode diagnostics.
@@ -5391,6 +5555,12 @@ def err_offsetof_field_of_virtual_base : Error<
def warn_sub_ptr_zero_size_types : Warning<
"subtraction of pointers to type %0 of zero size has undefined behavior">,
InGroup<PointerArith>;
+def warn_pointer_arith_null_ptr : Warning<
+ "performing pointer arithmetic on a null pointer has undefined behavior%select{| if the offset is nonzero}0">,
+ InGroup<NullPointerArithmetic>, DefaultIgnore;
+def warn_gnu_null_ptr_arith : Warning<
+ "arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">,
+ InGroup<NullPointerArithmetic>, DefaultIgnore;
def warn_floatingpoint_eq : Warning<
"comparing floating point with == or != is unsafe">,
@@ -5555,6 +5725,11 @@ def err_enumerator_does_not_exist : Error<
def note_enum_specialized_here : Note<
"enum %0 was explicitly specialized here">;
+def err_specialization_not_primary_template : Error<
+ "cannot reference member of primary template because deduced class "
+ "template specialization %0 is %select{instantiated from a partial|"
+ "an explicit}1 specialization">;
+
def err_member_redeclared : Error<"class member cannot be redeclared">;
def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">,
InGroup<RedeclaredClassMember>;
@@ -5727,6 +5902,9 @@ def err_objc_object_assignment : Error<
"cannot assign to class object (%0 invalid)">;
def err_typecheck_invalid_operands : Error<
"invalid operands to binary expression (%0 and %1)">;
+def err_typecheck_logical_vector_expr_gnu_cpp_restrict : Error<
+ "logical expression with vector %select{type %1 and non-vector type %2|types"
+ " %1 and %2}0 is only supported in C++">;
def err_typecheck_sub_ptr_compatible : Error<
"%diff{$ and $ are not pointers to compatible types|"
"pointers to incompatible types}0,1">;
@@ -5770,6 +5948,8 @@ def err_typecheck_assign_const : Error<
"cannot assign to %select{non-|}1static data member %2 "
"with const-qualified type %3|"
"cannot assign to non-static data member within const member function %1|"
+ "cannot assign to %select{variable %2|non-static data member %2|lvalue}1 "
+ "with %select{|nested }3const-qualified data member %4|"
"read-only variable is not assignable}0">;
def note_typecheck_assign_const : Note<
@@ -5777,25 +5957,37 @@ def note_typecheck_assign_const : Note<
"function %1 which returns const-qualified type %2 declared here|"
"variable %1 declared const here|"
"%select{non-|}1static data member %2 declared const here|"
- "member function %q1 is declared const here}0">;
+ "member function %q1 is declared const here|"
+ "%select{|nested }1data member %2 declared const here}0">;
+
+def warn_unsigned_always_true_comparison : Warning<
+ "comparison of %select{%3|unsigned expression}0 %2 "
+ "%select{unsigned expression|%3}0 is always %select{false|true}4">,
+ InGroup<TautologicalUnsignedZeroCompare>;
+def warn_unsigned_enum_always_true_comparison : Warning<
+ "comparison of %select{%3|unsigned enum expression}0 %2 "
+ "%select{unsigned enum expression|%3}0 is always %select{false|true}4">,
+ InGroup<TautologicalUnsignedEnumZeroCompare>;
+def warn_tautological_constant_compare : Warning<
+ "comparison %select{%3|%1}0 %2 "
+ "%select{%1|%3}0 is always %select{false|true}4">,
+ InGroup<TautologicalConstantCompare>;
def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
InGroup<SignCompare>, DefaultIgnore;
-def warn_lunsigned_always_true_comparison : Warning<
- "comparison of unsigned%select{| enum}2 expression %0 is always %1">,
- InGroup<TautologicalCompare>;
def warn_out_of_range_compare : Warning<
"comparison of %select{constant %0|true|false}1 with "
"%select{expression of type %2|boolean expression}3 is always "
"%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>;
-def warn_runsigned_always_true_comparison : Warning<
- "comparison of %0 unsigned%select{| enum}2 expression is always %1">,
- InGroup<TautologicalCompare>;
def warn_comparison_of_mixed_enum_types : Warning<
"comparison of two values with different enumeration types"
"%diff{ ($ and $)|}0,1">,
- InGroup<DiagGroup<"enum-compare">>;
+ InGroup<EnumCompare>;
+def warn_comparison_of_mixed_enum_types_switch : Warning<
+ "comparison of two values with different enumeration types in switch statement"
+ "%diff{ ($ and $)|}0,1">,
+ InGroup<EnumCompareSwitch>;
def warn_null_in_arithmetic_operation : Warning<
"use of NULL in arithmetic operation">,
InGroup<NullArithmetic>;
@@ -5850,8 +6042,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>;
@@ -6240,12 +6432,14 @@ def warn_ambiguous_suitable_delete_function_found : Warning<
InGroup<DiagGroup<"ambiguous-delete">>;
def note_member_declared_here : Note<
"member %0 declared here">;
+def note_member_first_declared_here : Note<
+ "member %0 first declared here">;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
"incrementing expression of type bool is deprecated and "
- "incompatible with C++1z">, InGroup<DeprecatedIncrementBool>;
+ "incompatible with C++17">, InGroup<DeprecatedIncrementBool>;
def ext_increment_bool : ExtWarn<
- "ISO C++1z does not allow incrementing expression of type bool">,
+ "ISO C++17 does not allow incrementing expression of type bool">,
DefaultError, InGroup<IncrementBool>;
def err_increment_decrement_enum : Error<
"cannot %select{decrement|increment}0 expression of enum type %1">;
@@ -6273,6 +6467,13 @@ def err_exceptions_disabled : Error<
"cannot use '%0' with exceptions disabled">;
def err_objc_exceptions_disabled : Error<
"cannot use '%0' with Objective-C exceptions disabled">;
+def warn_throw_in_noexcept_func : Warning<
+ "%0 has a non-throwing exception specification but can still throw">,
+ InGroup<Exceptions>;
+def note_throw_in_dtor : Note<
+ "%select{destructor|deallocator}0 has a %select{non-throwing|implicit "
+ "non-throwing}1 exception specification">;
+def note_throw_in_function : Note<"function declared non-throwing here">;
def err_seh_try_outside_functions : Error<
"cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">;
def err_mixing_cxx_try_seh_try : Error<
@@ -6290,12 +6491,12 @@ def warn_non_virtual_dtor : Warning<
def warn_delete_non_virtual_dtor : Warning<
"%select{delete|destructor}0 called on non-final %1 that has "
"virtual functions but non-virtual destructor">,
- InGroup<DeleteNonVirtualDtor>, DefaultIgnore;
+ InGroup<DeleteNonVirtualDtor>, DefaultIgnore, ShowInSystemHeader;
def note_delete_non_virtual : Note<
"qualify call to silence this warning">;
def warn_delete_abstract_non_virtual_dtor : Warning<
"%select{delete|destructor}0 called on %1 that is abstract but has "
- "non-virtual destructor">, InGroup<DeleteNonVirtualDtor>;
+ "non-virtual destructor">, InGroup<DeleteNonVirtualDtor>, ShowInSystemHeader;
def warn_overloaded_virtual : Warning<
"%q0 hides overloaded virtual %select{function|functions}1">,
InGroup<OverloadedVirtual>, DefaultIgnore;
@@ -6318,6 +6519,12 @@ def warn_overaligned_type : Warning<
"type %0 requires %1 bytes of alignment and the default allocator only "
"guarantees %2 bytes">,
InGroup<OveralignedType>, DefaultIgnore;
+def warn_aligned_allocation_unavailable :Warning<
+ "aligned %select{allocation|deallocation}0 function of type '%1' is only "
+ "available on %2 %3 or newer">, InGroup<AlignedAllocationUnavailable>, DefaultError;
+def note_silence_unligned_allocation_unavailable : Note<
+ "if you supply your own aligned allocation functions, use "
+ "-Wno-aligned-allocation-unavailable to silence this diagnostic">;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
@@ -6351,8 +6558,6 @@ let CategoryName = "Lambda Issue" in {
"%0 can appear only once in a capture list">;
def err_reference_capture_with_reference_default : Error<
"'&' cannot precede a capture when the capture default is '&'">;
- def err_this_capture_with_copy_default : Error<
- "'this' cannot be explicitly captured when the capture default is '='">;
def err_copy_capture_with_copy_default : Error<
"'&' must precede a capture when the capture default is '='">;
def err_capture_does_not_name_variable : Error<
@@ -6419,12 +6624,20 @@ let CategoryName = "Lambda Issue" in {
def err_init_capture_deduction_failure_from_init_list : Error<
"cannot deduce type for lambda capture %0 from initializer list">;
- // C++1z '*this' captures.
+ // C++17 '*this' captures.
def warn_cxx14_compat_star_this_lambda_capture : Warning<
- "by value capture of '*this' is incompatible with C++ standards before C++1z">,
- InGroup<CXXPre1zCompat>, DefaultIgnore;
- def ext_star_this_lambda_capture_cxx1z : ExtWarn<
- "capture of '*this' by copy is a C++1z extension">, InGroup<CXX1z>;
+ "by value capture of '*this' is incompatible with C++ standards before C++17">,
+ InGroup<CXXPre17Compat>, DefaultIgnore;
+ def ext_star_this_lambda_capture_cxx17 : ExtWarn<
+ "capture of '*this' by copy is a C++17 extension">, InGroup<CXX17>;
+
+ // C++2a [=, this] captures.
+ def warn_cxx17_compat_equals_this_lambda_capture : Warning<
+ "explicit capture of 'this' with a capture default of '=' is incompatible "
+ "with C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
+ def ext_equals_this_lambda_capture_cxx2a : ExtWarn<
+ "explicit capture of 'this' with a capture default of '=' "
+ "is a C++2a extension">, InGroup<CXX2a>;
}
def err_return_in_captured_stmt : Error<
@@ -6874,8 +7087,8 @@ def err_atomic_op_needs_atomic : Error<
"address argument to atomic operation must be a pointer to _Atomic "
"type (%0 invalid)">;
def err_atomic_op_needs_non_const_atomic : Error<
- "address argument to atomic operation must be a pointer to non-const _Atomic "
- "type (%0 invalid)">;
+ "address argument to atomic operation must be a pointer to non-%select{const|constant}0 _Atomic "
+ "type (%1 invalid)">;
def err_atomic_op_needs_non_const_pointer : Error<
"address argument to atomic operation must be a pointer to non-const "
"type (%0 invalid)">;
@@ -6891,6 +7104,8 @@ def err_atomic_op_bitwise_needs_atomic_int : Error<
def warn_atomic_op_has_invalid_memory_order : Warning<
"memory order argument to atomic operation is invalid">,
InGroup<DiagGroup<"atomic-memory-ordering">>;
+def err_atomic_op_has_invalid_synch_scope : Error<
+ "synchronization scope argument to atomic operation is invalid">;
def err_overflow_builtin_must_be_int : Error<
"operand argument to overflow builtin must be an integer (%0 invalid)">;
@@ -7092,8 +7307,8 @@ def warn_unused_volatile : Warning<
def ext_cxx14_attr : Extension<
"use of the %0 attribute is a C++14 extension">, InGroup<CXX14>;
-def ext_cxx1z_attr : Extension<
- "use of the %0 attribute is a C++1z extension">, InGroup<CXX1z>;
+def ext_cxx17_attr : Extension<
+ "use of the %0 attribute is a C++17 extension">, InGroup<CXX17>;
def warn_unused_comparison : Warning<
"%select{%select{|in}1equality|relational}0 comparison result unused">,
@@ -7205,11 +7420,11 @@ def err_invalid_conversion_between_vector_and_integer : Error<
"invalid conversion between vector type %0 and integer type %1 "
"of different size">;
-def err_opencl_function_pointer_variable : Error<
+def err_opencl_function_pointer : Error<
"pointers to functions are not allowed">;
-def err_opencl_taking_function_address : Error<
- "taking address of function is not allowed">;
+def err_opencl_taking_address_capture : Error<
+ "taking address of a capture is not allowed">;
def err_invalid_conversion_between_vector_and_scalar : Error<
"invalid conversion between vector type %0 and scalar type %1">;
@@ -7350,6 +7565,9 @@ def err_ambiguous_derived_to_base_conv : Error<
def err_ambiguous_memptr_conv : Error<
"ambiguous conversion from pointer to member of %select{base|derived}0 "
"class %1 to pointer to member of %select{derived|base}0 class %2:%3">;
+def ext_ms_ambiguous_direct_base : ExtWarn<
+ "accessing inaccessible direct base %0 of %1 is a Microsoft extension">,
+ InGroup<MicrosoftInaccessibleBase>;
def err_memptr_conv_via_virtual : Error<
"conversion from pointer to member of class %0 to pointer to member "
@@ -7419,6 +7637,11 @@ def err_operator_delete_dependent_param_type : Error<
"%0 cannot take a dependent type as first parameter; use %1 instead">;
def err_operator_delete_param_type : Error<
"first parameter of %0 must have type %1">;
+def err_destroying_operator_delete_not_usual : Error<
+ "destroying operator delete can have only an optional size and optional "
+ "alignment parameter">;
+def note_implicit_delete_this_in_destructor_here : Note<
+ "while checking implicit 'delete this' for virtual destructor">;
// C++ literal operators
def err_literal_operator_outside_namespace : Error<
@@ -7761,6 +7984,8 @@ def err_builtin_annotation_first_arg : Error<
"first argument to __builtin_annotation must be an integer">;
def err_builtin_annotation_second_arg : Error<
"second argument to __builtin_annotation must be a non-wide string constant">;
+def err_msvc_annotation_wide_str : Error<
+ "arguments to __annotation must be wide string constants">;
// CFString checking
def err_cfstring_literal_not_string_constant : Error<
@@ -7876,7 +8101,11 @@ def warn_empty_switch_body : Warning<
def note_empty_body_on_separate_line : Note<
"put the semicolon on a separate line to silence this warning">;
-def err_va_start_used_in_non_variadic_function : Error<
+def err_va_start_captured_stmt : Error<
+ "'va_start' cannot be used in a captured statement">;
+def err_va_start_outside_function : Error<
+ "'va_start' cannot be used outside a function">;
+def err_va_start_fixed_function : Error<
"'va_start' used in function with fixed args">;
def err_va_start_used_in_wrong_abi_function : Error<
"'va_start' used in %select{System V|Win64}0 ABI function">;
@@ -7947,10 +8176,13 @@ def err_block_on_nonlocal : Error<
def err_block_on_vm : Error<
"__block attribute not allowed on declaration with a variably modified type">;
-def err_shufflevector_non_vector : Error<
- "first two arguments to __builtin_shufflevector must be vectors">;
-def err_shufflevector_incompatible_vector : Error<
- "first two arguments to __builtin_shufflevector must have the same type">;
+def err_vec_builtin_non_vector : Error<
+ "first two arguments to %0 must be vectors">;
+def err_vec_builtin_incompatible_vector : Error<
+ "first two arguments to %0 must have the same type">;
+def err_vsx_builtin_nonconstant_argument : Error<
+ "argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
+
def err_shufflevector_nonconstant_argument : Error<
"index for __builtin_shufflevector must be a constant integer">;
def err_shufflevector_argument_too_large : Error<
@@ -7999,10 +8231,10 @@ def err_systemz_invalid_tabort_code : Error<
"invalid transaction abort code">;
def err_64_bit_builtin_32_bit_tgt : Error<
"this builtin is only available on 64-bit targets">;
+def err_builtin_x64_aarch64_only : Error<
+ "this builtin is only available on x86-64 and aarch64 targets">;
def err_ppc_builtin_only_on_pwr7 : Error<
"this builtin is only valid on POWER7 or later CPUs">;
-def err_x86_builtin_32_bit_tgt : Error<
- "this builtin is only available on x86-64 targets">;
def err_x86_builtin_invalid_rounding : Error<
"invalid rounding argument">;
def err_x86_builtin_invalid_scale : Error<
@@ -8081,12 +8313,12 @@ def err_c99_array_usage_cxx : Error<
"feature, not permitted in C++">;
def err_type_unsupported : Error<
"%0 is not supported on this target">;
-def err_nsconsumed_attribute_mismatch : Error<
+def warn_nsconsumed_attribute_mismatch : Warning<
"overriding method has mismatched ns_consumed attribute on its"
- " parameter">;
-def err_nsreturns_retained_attribute_mismatch : Error<
+ " parameter">, InGroup<NSConsumedMismatch>;
+def warn_nsreturns_retained_attribute_mismatch : Warning<
"overriding method has mismatched ns_returns_%select{not_retained|retained}0"
- " attributes">;
+ " attributes">, InGroup<NSReturnsMismatch>;
def note_getter_unavailable : Note<
"or because setter is declared here, but no getter method %0 is found">;
@@ -8134,9 +8366,20 @@ def err_undeclared_use_suggest : Error<
"use of undeclared %0; did you mean %1?">;
def err_undeclared_var_use_suggest : Error<
"use of undeclared identifier %0; did you mean %1?">;
+def err_no_template : Error<"no template named %0">;
def err_no_template_suggest : Error<"no template named %0; did you mean %1?">;
+def err_no_member_template : Error<"no template named %0 in %1">;
def err_no_member_template_suggest : Error<
"no template named %0 in %1; did you mean %select{|simply }2%3?">;
+def err_non_template_in_template_id : Error<
+ "%0 does not name a template but is followed by template arguments">;
+def err_non_template_in_template_id_suggest : Error<
+ "%0 does not name a template but is followed by template arguments; "
+ "did you mean %1?">;
+def err_non_template_in_member_template_id_suggest : Error<
+ "member %0 of %1 is not a template; did you mean %select{|simply }2%3?">;
+def note_non_template_in_template_id_found : Note<
+ "non-template declaration found by name lookup">;
def err_mem_init_not_member_or_class_suggest : Error<
"initializer %0 does not name a non-static data member or base "
"class; did you mean the %select{base class|member}1 %2?">;
@@ -8221,14 +8464,22 @@ def err_opencl_ptrptr_kernel_param : Error<
def err_kernel_arg_address_space : Error<
"pointer arguments to kernel functions must reside in '__global', "
"'__constant' or '__local' address space">;
+def err_opencl_ext_vector_component_invalid_length : Error<
+ "vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">;
def err_opencl_function_variable : Error<
"%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">;
+def err_opencl_addrspace_scope : Error<
+ "variables in the %0 address space can only be declared in the outermost "
+ "scope of a kernel function">;
def err_static_function_scope : Error<
"variables in function scope cannot be declared static">;
def err_opencl_bitfields : Error<
"bit-fields are not supported in OpenCL">;
def err_opencl_vla : Error<
"variable length arrays are not supported in OpenCL">;
+def err_opencl_scalar_type_rank_greater_than_vector_type : Error<
+ "scalar operand type has greater rank than the type of the vector "
+ "element. (%0 and %1)">;
def err_bad_kernel_param_type : Error<
"%0 cannot be used as the type of a kernel parameter">;
def err_record_with_pointers_kernel_param : Error<
@@ -8251,6 +8502,8 @@ def err_sampler_argument_required : Error<
"sampler_t variable required - got %0">;
def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
+def err_opencl_nonconst_global_sampler : Error<
+ "global sampler requires a const or constant address space qualifier">;
def err_opencl_cast_non_zero_to_event_t : Error<
"cannot cast non-zero value '%0' to 'event_t'">;
def err_opencl_global_invalid_addr_space : Error<
@@ -8266,9 +8519,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<
@@ -8285,7 +8538,7 @@ def warn_opencl_attr_deprecated_ignored : Warning <
def err_opencl_variadic_function : Error<
"invalid prototype, variadic arguments are not allowed in OpenCL">;
def err_opencl_requires_extension : Error<
- "use of %select{type |declaration}0%1 requires %2 extension to be enabled">;
+ "use of %select{type|declaration}0 %1 requires %2 extension to be enabled">;
// OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions
def err_opencl_builtin_pipe_first_arg : Error<
@@ -8330,8 +8583,6 @@ def err_opencl_builtin_to_addr_invalid_arg : Error<
// OpenCL v2.0 s6.13.17 Enqueue kernel restrictions.
def err_opencl_enqueue_kernel_incorrect_args : Error<
"illegal call to enqueue_kernel, incorrect argument types">;
-def err_opencl_enqueue_kernel_expected_type : Error<
- "illegal call to enqueue_kernel, expected %0 argument type">;
def err_opencl_enqueue_kernel_local_size_args : Error<
"mismatch in number of block parameters and local size arguments passed">;
def err_opencl_enqueue_kernel_invalid_local_size_type : Error<
@@ -8341,6 +8592,9 @@ def err_opencl_enqueue_kernel_blocks_non_local_void_args : Error<
def err_opencl_enqueue_kernel_blocks_no_args : Error<
"blocks with parameters are not accepted in this prototype of enqueue_kernel call">;
+def err_opencl_builtin_expected_type : Error<
+ "illegal call to %0, expected %1 argument type">;
+
// OpenCL v2.2 s2.1.2.3 - Vector Component Access
def ext_opencl_ext_vector_type_rgba_selector: ExtWarn<
"vector component name '%0' is an OpenCL version 2.2 feature">,
@@ -8380,6 +8634,8 @@ def err_omp_expected_var_name_member_expr : Error<
"expected variable name%select{| or data member of current class}0">;
def err_omp_expected_var_name_member_expr_or_array_item : Error<
"expected variable name%select{|, data member of current class}0, array element or array section">;
+def err_omp_expected_addressable_lvalue_or_array_item : Error<
+ "expected addressable lvalue expression, array element or array section">;
def err_omp_expected_named_var_member_or_array_expression: Error<
"expected expression containing only member accesses and/or array sections based on named variables">;
def err_omp_bit_fields_forbidden_in_clause : Error<
@@ -8517,11 +8773,11 @@ def err_omp_unknown_reduction_identifier : Error<
def err_omp_not_resolved_reduction_identifier : Error<
"unable to resolve declare reduction construct for type %0">;
def err_omp_reduction_ref_type_arg : Error<
- "argument of OpenMP clause 'reduction' must reference the same object in all threads">;
+ "argument of OpenMP clause '%0' must reference the same object in all threads">;
def err_omp_clause_not_arithmetic_type_arg : Error<
- "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 type">;
+ "arguments of OpenMP clause '%0' for 'min' or 'max' must be of %select{scalar|arithmetic}1 type">;
def err_omp_clause_floating_type_arg : Error<
- "arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">;
+ "arguments of OpenMP clause '%0' with bitwise operators cannot be of floating type">;
def err_omp_once_referenced : Error<
"variable can appear only once in OpenMP '%0' clause">;
def err_omp_once_referenced_in_target_update : Error<
@@ -8532,6 +8788,12 @@ def err_omp_reduction_in_task : Error<
"reduction variables may not be accessed in an explicit task">;
def err_omp_reduction_id_not_compatible : Error<
"list item of type %0 is not valid for specified reduction operation: unable to provide default initialization value">;
+def err_omp_in_reduction_not_task_reduction : Error<
+ "in_reduction variable must appear in a task_reduction clause">;
+def err_omp_reduction_identifier_mismatch : Error<
+ "in_reduction variable must have the same reduction operation as in a task_reduction clause">;
+def note_omp_previous_reduction_identifier : Note<
+ "previously marked as task_reduction with different reduction operation">;
def err_omp_prohibited_region : Error<
"region cannot be%select{| closely}0 nested inside '%1' region"
"%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|"
@@ -8655,16 +8917,10 @@ def err_omp_expected_base_var_name : Error<
"expected variable name as a base of the array %select{subscript|section}0">;
def err_omp_map_shared_storage : Error<
"variable already marked as mapped in current construct">;
-def err_omp_not_mappable_type : Error<
- "type %0 is not mappable to target">;
def err_omp_invalid_map_type_for_directive : Error<
"%select{map type '%1' is not allowed|map type must be specified}0 for '#pragma omp %2'">;
-def err_omp_no_map_for_directive : Error<
- "expected at least one map clause for '#pragma omp %0'">;
-def note_omp_polymorphic_in_target : Note<
- "mappable type cannot be polymorphic">;
-def note_omp_static_member_in_target : Note<
- "mappable type cannot contain static members">;
+def err_omp_no_clause_for_directive : Error<
+ "expected at least one %0 clause for '#pragma omp %1'">;
def err_omp_threadprivate_in_clause : Error<
"threadprivate variables are not allowed in '%0' clause">;
def err_omp_wrong_ordered_loop_count : Error<
@@ -8683,16 +8939,10 @@ def note_omp_critical_hint_here : Note<
"%select{|previous }0'hint' clause with value '%1'">;
def note_omp_critical_no_hint : Note<
"%select{|previous }0directive with no 'hint' clause specified">;
-def err_omp_firstprivate_distribute_private_teams : Error<
- "private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">;
-def err_omp_firstprivate_and_lastprivate_in_distribute : Error<
- "lastprivate variable cannot be firstprivate in '#pragma omp distribute'">;
-def err_omp_firstprivate_distribute_in_teams_reduction : Error<
- "reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">;
def err_omp_depend_clause_thread_simd : Error<
"'depend' clauses cannot be mixed with '%0' clause">;
def err_omp_depend_sink_expected_loop_iteration : Error<
- "expected %0 loop iteration variable">;
+ "expected%select{| %1}0 loop iteration variable">;
def err_omp_depend_sink_unexpected_expr : Error<
"unexpected expression: number of expressions is larger than the number of associated loops">;
def err_omp_depend_sink_expected_plus_minus : Error<
@@ -8729,6 +8979,10 @@ def warn_omp_nesting_simd : Warning<
def err_omp_orphaned_device_directive : Error<
"orphaned 'omp %0' directives are prohibited"
"; perhaps you forget to enclose the directive into a %select{|||target |teams }1region?">;
+def err_omp_reduction_non_addressable_expression : Error<
+ "expected addressable reduction item for the task-based directives">;
+def err_omp_reduction_with_nogroup : Error<
+ "'reduction' clause cannot be used with 'nogroup' clause">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
@@ -8759,15 +9013,25 @@ def err_invalid_type_for_program_scope_var : Error<
}
let CategoryName = "Modules Issue" in {
+def err_module_decl_in_module_map_module : Error<
+ "'module' declaration found while building module from module map">;
def err_module_interface_implementation_mismatch : Error<
- "%select{'module'|'module partition'|'module implementation'}0 declaration "
- "found while %select{not |not |}0building module interface">;
+ "missing 'export' specifier in module declaration while "
+ "building module interface">;
def err_current_module_name_mismatch : Error<
"module name '%0' specified on command line does not match name of module">;
def err_module_redefinition : Error<
"redefinition of module '%0'">;
def note_prev_module_definition : Note<"previously defined here">;
def note_prev_module_definition_from_ast_file : Note<"module loaded from '%0'">;
+def err_module_not_defined : Error<
+ "definition of module '%0' is not available; use -fmodule-file= to specify "
+ "path to precompiled module interface">;
+def err_module_redeclaration : Error<
+ "translation unit contains multiple module declarations">;
+def note_prev_module_declaration : Note<"previous module declaration is here">;
+def err_module_declaration_missing : Error<
+ "missing 'export module' declaration in module interface unit">;
def err_module_private_specialization : Error<
"%select{template|partial|member}0 specialization cannot be "
"declared __module_private__">;
@@ -8804,14 +9068,24 @@ def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
def err_module_import_in_implementation : Error<
"@import of module '%0' in implementation of '%1'; use #import">;
+
+// C++ Modules TS
def err_export_within_export : Error<
"export declaration appears within another export declaration">;
+def err_export_not_in_module_interface : Error<
+ "export declaration can only be used within a module interface unit after "
+ "the module declaration">;
def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn<
"ambiguous use of internal linkage declaration %0 defined in multiple modules">,
InGroup<DiagGroup<"modules-ambiguous-internal-linkage">>;
def note_equivalent_internal_linkage_decl : Note<
"declared here%select{ in module '%1'|}0">;
+
+def note_redefinition_modules_same_file : Note<
+ "'%0' included multiple times, additional include site in header from module '%1'">;
+def note_redefinition_include_same_file : Note<
+ "'%0' included multiple times, additional include site here">;
}
let CategoryName = "Coroutines Issue" in {
@@ -8833,6 +9107,11 @@ def err_coroutine_invalid_func_context : Error<
def err_implied_coroutine_type_not_found : Error<
"%0 type was not found; include <experimental/coroutine> before defining "
"a coroutine">;
+def err_implicit_coroutine_std_nothrow_type_not_found : Error<
+ "std::nothrow was not found; include <new> before defining a coroutine which "
+ "uses get_return_object_on_allocation_failure()">;
+def err_malformed_std_nothrow : Error<
+ "std::nothrow must be a valid variable declaration">;
def err_malformed_std_coroutine_handle : Error<
"std::experimental::coroutine_handle must be a class template">;
def err_coroutine_handle_missing_member : Error<
@@ -8848,18 +9127,35 @@ def err_coroutine_promise_type_incomplete : Error<
def err_coroutine_type_missing_specialization : Error<
"this function cannot be a coroutine: missing definition of "
"specialization %q0">;
-def err_implied_std_current_exception_not_found : Error<
- "you need to include <exception> before defining a coroutine that implicitly "
- "uses 'set_exception'">;
-def err_malformed_std_current_exception : Error<
- "'std::current_exception' must be a function">;
-def err_coroutine_promise_return_ill_formed : Error<
- "%0 declares both 'return_value' and 'return_void'">;
+def err_coroutine_promise_incompatible_return_functions : Error<
+ "the coroutine promise type %0 declares both 'return_value' and 'return_void'">;
+def err_coroutine_promise_requires_return_function : Error<
+ "the coroutine promise type %0 must declare either 'return_value' or 'return_void'">;
def note_coroutine_promise_implicit_await_transform_required_here : Note<
"call to 'await_transform' implicitly required by 'co_await' here">;
-def note_coroutine_promise_call_implicitly_required : Note<
+def note_coroutine_promise_suspend_implicitly_required : Note<
"call to '%select{initial_suspend|final_suspend}0' implicitly "
"required by the %select{initial suspend point|final suspend point}0">;
+def err_coroutine_promise_unhandled_exception_required : Error<
+ "%0 is required to declare the member 'unhandled_exception()'">;
+def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warning<
+ "%0 is required to declare the member 'unhandled_exception()' when exceptions are enabled">,
+ InGroup<CoroutineMissingUnhandledException>;
+def err_coroutine_promise_get_return_object_on_allocation_failure : Error<
+ "%0: 'get_return_object_on_allocation_failure()' must be a static member function">;
+def err_seh_in_a_coroutine_with_cxx_exceptions : Error<
+ "cannot use SEH '__try' in a coroutine when C++ exceptions are enabled">;
+def err_coroutine_promise_new_requires_nothrow : Error<
+ "%0 is required to have a non-throwing noexcept specification when the promise "
+ "type declares 'get_return_object_on_allocation_failure()'">;
+def note_coroutine_promise_call_implicitly_required : Note<
+ "call to %0 implicitly required by coroutine function here">;
+def err_await_suspend_invalid_return_type : Error<
+ "return type of 'await_suspend' is required to be 'void' or 'bool' (have %0)"
+>;
+def note_await_ready_no_bool_conversion : Note<
+ "return type of 'await_ready' is required to be contextually convertible to 'bool'"
+>;
}
let CategoryName = "Documentation Issue" in {
@@ -8870,8 +9166,13 @@ def warn_not_a_doxygen_trailing_member_comment : Warning<
let CategoryName = "Instrumentation Issue" in {
def warn_profile_data_out_of_date : Warning<
"profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1"
- " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">,
+ " mismatched data that will be ignored">,
InGroup<ProfileInstrOutOfDate>;
+def warn_profile_data_missing : Warning<
+ "profile data may be incomplete: of %0 function%s0, %1 %plural{1:has|:have}1"
+ " no data">,
+ InGroup<ProfileInstrMissing>,
+ DefaultIgnore;
def warn_profile_data_unprofiled : Warning<
"no profile data available for file \"%0\"">,
InGroup<ProfileInstrUnprofiled>;
@@ -8901,6 +9202,9 @@ def warn_nullability_lost : Warning<
"implicit conversion from nullable pointer %0 to non-nullable pointer "
"type %1">,
InGroup<NullableToNonNullConversion>, DefaultIgnore;
+def warn_zero_as_null_pointer_constant : Warning<
+ "zero as null pointer constant">,
+ InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore;
def err_nullability_cs_multilevel : Error<
"nullability keyword %0 cannot be applied to multi-level pointer type %1">;
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index d6e040a442..3f0a14c59f 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -112,19 +112,65 @@ def note_module_odr_violation_possible_decl : Note<
def err_module_odr_violation_different_definitions : Error<
"%q0 has different definitions in different modules; "
"%select{definition in module '%2' is here|defined here}1">;
+def note_first_module_difference : Note<
+ "in first definition, possible difference is here">;
def note_module_odr_violation_different_definitions : Note<
"definition in module '%0' is here">;
+def note_second_module_difference : Note<
+ "in second definition, possible difference is here">;
+
def err_module_odr_violation_different_instantiations : Error<
"instantiation of %q0 is different in different modules">;
+def err_module_odr_violation_definition_data : Error <
+ "%q0 has different definitions in different modules; first difference is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "%4 base %plural{1:class|:classes}4|"
+ "%4 virtual base %plural{1:class|:classes}4|"
+ "%ordinal4 base class with type %5|"
+ "%ordinal4 %select{non-virtual|virtual}5 base class %6|"
+ "%ordinal4 base class %5 with "
+ "%select{public|protected|private|no}6 access specifier}3">;
+
+def note_module_odr_violation_definition_data : Note <
+ "but in '%0' found "
+ "%select{"
+ "%2 base %plural{1:class|:classes}2|"
+ "%2 virtual base %plural{1:class|:classes}2|"
+ "%ordinal2 base class with different type %3|"
+ "%ordinal2 %select{non-virtual|virtual}3 base class %4|"
+ "%ordinal2 base class %3 with "
+ "%select{public|protected|private|no}4 access specifier}1">;
+
+def err_module_odr_violation_template_parameter : Error <
+ "%q0 has different definitions in different modules; first difference is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "unnamed template parameter|"
+ "template parameter %4|"
+ "template parameter with %select{no |}4default argument|"
+ "template parameter with default argument}3">;
+
+
+def note_module_odr_violation_template_parameter : Note <
+ "but in '%0' found "
+ "%select{"
+ "unnamed template parameter %2|"
+ "template parameter %2|"
+ "template parameter with %select{no |}2default argument|"
+ "template parameter with different default argument}1">;
+
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">;
+ "protected access specifier|static assert|field|method|type alias|typedef|"
+ "data member|friend declaration}3">;
def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
"%select{end of class|public access specifier|private access specifier|"
- "protected access specifier|static assert|field|method}1">;
+ "protected access specifier|static assert|field|method|type alias|typedef|"
+ "data member|friend declaration}1">;
def err_module_odr_violation_mismatch_decl_diff : Error<
"%q0 has different definitions in different modules; first difference is "
@@ -140,13 +186,40 @@ def err_module_odr_violation_mismatch_decl_diff : Error<
"%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">;
+ "%select{method %5|constructor|destructor}4|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not deleted|deleted}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{|pure }6%select{not virtual|virtual}7|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not static|static}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not volatile|volatile}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not const|const}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not inline|inline}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "that has %6 parameter%s6|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter of type %7%select{| decayed from %9}8|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter named %7|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter with%select{out|}7 a default argument|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter with a default argument|"
+ "%select{typedef|type alias}4 name %5|"
+ "%select{typedef|type alias}4 %5 with underlying type %6|"
+ "data member with name %4|"
+ "data member %4 with type %5|"
+ "data member %4 with%select{out|}5 an initializer|"
+ "data member %4 with an initializer|"
+ "data member %4 %select{is constexpr|is not constexpr}5|"
+ "friend %select{class|function}4|"
+ "friend %4|"
+ "friend function %4|"
+ "}3">;
def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
"%select{"
@@ -160,22 +233,69 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
"%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">;
+ "%select{method %3|constructor|destructor}2|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not deleted|deleted}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{|pure }4%select{not virtual|virtual}5|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not static|static}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not volatile|volatile}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not const|const}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not inline|inline}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "that has %4 parameter%s4|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter of type %5%select{| decayed from %7}6|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter named %5|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter with%select{out|}5 a default argument|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter with a different default argument|"
+ "%select{typedef|type alias}2 name %3|"
+ "%select{typedef|type alias}2 %3 with different underlying type %4|"
+ "data member with name %2|"
+ "data member %2 with different type %3|"
+ "data member %2 with%select{out|}3 an initializer|"
+ "data member %2 with a different initializer|"
+ "data member %2 %select{is constexpr|is not constexpr}3|"
+ "friend %select{class|function}2|"
+ "friend %2|"
+ "friend function %2|"
+ "}1">;
-def warn_module_uses_date_time : Warning<
- "%select{precompiled header|module}0 uses __DATE__ or __TIME__">,
- InGroup<DiagGroup<"pch-date-time">>;
+def err_module_odr_violation_mismatch_decl_unknown : Error<
+ "%q0 %select{with definition in module '%2'|defined here}1 has different "
+ "definitions in different modules; first difference is this "
+ "%select{||||static assert|field|method|type alias|typedef|data member|"
+ "friend declaration|unexpected decl}3">;
+def note_module_odr_violation_mismatch_decl_unknown : Note<
+ "but in '%0' found "
+ "%select{||||different static assert|different field|different method|"
+ "different type alias|different typedef|different data member|"
+ "different friend declaration|another unexpected decl}1">;
def warn_duplicate_module_file_extension : Warning<
"duplicate module file extension block name '%0'">,
InGroup<ModuleFileExtension>;
+def warn_module_system_bit_conflict : Warning<
+ "module file '%0' was validated as a system module and is now being imported "
+ "as a non-system module; any difference in diagnostic options will be ignored">,
+ InGroup<ModuleConflict>;
+} // let CategoryName
+
+let CategoryName = "AST Serialization Issue" in {
+def warn_module_uses_date_time : Warning<
+ "%select{precompiled header|module}0 uses __DATE__ or __TIME__">,
+ InGroup<DiagGroup<"pch-date-time">>;
+def err_module_no_size_mtime_for_header : Error<
+ "cannot emit module %0: %select{size|mtime}1 must be explicitly specified "
+ "for missing header file \"%2\"">;
} // let CategoryName
} // let Component
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index aaed481906..3938e09890 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -272,15 +272,15 @@ public:
/// this identifier is a C++ alternate representation of an operator.
void setIsCPlusPlusOperatorKeyword(bool Val = true) {
IsCPPOperatorKeyword = Val;
- if (Val)
- NeedsHandleIdentifier = true;
- else
- RecomputeNeedsHandleIdentifier();
}
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
/// \brief Return true if this token is a keyword in the specified language.
- bool isKeyword(const LangOptions &LangOpts);
+ bool isKeyword(const LangOptions &LangOpts) const;
+
+ /// \brief Return true if this token is a C++ keyword in the specified
+ /// language.
+ bool isCPlusPlusKeyword(const LangOptions &LangOpts) const;
/// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
/// associate arbitrary metadata with this token.
@@ -351,6 +351,19 @@ public:
RecomputeNeedsHandleIdentifier();
}
+ /// Return true if this identifier is an editor placeholder.
+ ///
+ /// Editor placeholders are produced by the code-completion engine and are
+ /// represented as characters between '<#' and '#>' in the source code. An
+ /// example of auto-completed call with a placeholder parameter is shown
+ /// below:
+ /// \code
+ /// function(<#int x#>);
+ /// \endcode
+ bool isEditorPlaceholder() const {
+ return getName().startswith("<#") && getName().endswith("#>");
+ }
+
/// \brief Provide less than operator for lexicographical sorting.
bool operator<(const IdentifierInfo &RHS) const {
return getName() < RHS.getName();
@@ -364,10 +377,9 @@ private:
/// This method is very tied to the definition of HandleIdentifier. Any
/// change to it should be reflected here.
void RecomputeNeedsHandleIdentifier() {
- NeedsHandleIdentifier =
- (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
- isExtensionToken() | isFutureCompatKeyword() || isOutOfDate() ||
- isModulesImport());
+ NeedsHandleIdentifier = isPoisoned() || hasMacroDefinition() ||
+ isExtensionToken() || isFutureCompatKeyword() ||
+ isOutOfDate() || isModulesImport();
}
};
@@ -862,11 +874,10 @@ struct DenseMapInfo<clang::Selector> {
template <>
struct isPodLike<clang::Selector> { static const bool value = true; };
-template <typename T> class PointerLikeTypeTraits;
+template <typename T> struct PointerLikeTypeTraits;
template<>
-class PointerLikeTypeTraits<clang::Selector> {
-public:
+struct PointerLikeTypeTraits<clang::Selector> {
static inline const void *getAsVoidPointer(clang::Selector P) {
return P.getAsOpaquePtr();
}
@@ -881,8 +892,7 @@ public:
// Provide PointerLikeTypeTraits for IdentifierInfo pointers, which
// are not guaranteed to be 8-byte aligned.
template<>
-class PointerLikeTypeTraits<clang::IdentifierInfo*> {
-public:
+struct PointerLikeTypeTraits<clang::IdentifierInfo*> {
static inline void *getAsVoidPointer(clang::IdentifierInfo* P) {
return P;
}
@@ -895,8 +905,7 @@ public:
};
template<>
-class PointerLikeTypeTraits<const clang::IdentifierInfo*> {
-public:
+struct PointerLikeTypeTraits<const clang::IdentifierInfo*> {
static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) {
return P;
}
diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h
index f32ab5e11b..e60284d1b4 100644
--- a/include/clang/Basic/LLVM.h
+++ b/include/clang/Basic/LLVM.h
@@ -35,6 +35,7 @@ namespace llvm {
template<typename T, unsigned N> class SmallVector;
template<typename T> class SmallVectorImpl;
template<typename T> class Optional;
+ template <class T> class Expected;
template<typename T>
struct SaveAndRestore;
@@ -71,6 +72,9 @@ namespace clang {
using llvm::SmallVectorImpl;
using llvm::SaveAndRestore;
+ // Error handling.
+ using llvm::Expected;
+
// Reference counting.
using llvm::IntrusiveRefCntPtr;
using llvm::IntrusiveRefCntPtrInfo;
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 7126275503..78a743750e 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -89,7 +89,8 @@ LANGOPT(Borland , 1, 0, "Borland extensions")
LANGOPT(CPlusPlus , 1, 0, "C++")
LANGOPT(CPlusPlus11 , 1, 0, "C++11")
LANGOPT(CPlusPlus14 , 1, 0, "C++14")
-LANGOPT(CPlusPlus1z , 1, 0, "C++1z")
+LANGOPT(CPlusPlus1z , 1, 0, "C++17")
+LANGOPT(CPlusPlus2a , 1, 0, "C++2a")
LANGOPT(ObjC1 , 1, 0, "Objective-C 1")
LANGOPT(ObjC2 , 1, 0, "Objective-C 2")
BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0,
@@ -136,6 +137,8 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly")
LANGOPT(CoroutinesTS , 1, 0, "C++ coroutines TS")
LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments")
+LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
+
BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers")
LANGOPT(POSIXThreads , 1, 0, "POSIX thread support")
LANGOPT(Blocks , 1, 0, "blocks extension to C")
@@ -174,7 +177,8 @@ BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __w
BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control")
LANGOPT(CharIsSigned , 1, 1, "signed char")
-LANGOPT(ShortWChar , 1, 0, "unsigned short wchar_t")
+LANGOPT(WCharSize , 4, 0, "width of wchar_t")
+LANGOPT(WCharIsSigned , 1, 0, "signed or unsigned wchar_t")
ENUM_LANGOPT(MSPointerToMemberRepresentationMethod, PragmaMSPointersToMembersKind, 2, PPTMK_BestCase, "member-pointer representation method")
ENUM_LANGOPT(DefaultCallingConv, DefaultCallingConvention, 3, DCC_None, "default calling convention")
@@ -199,9 +203,11 @@ LANGOPT(CUDADeviceApproxTranscendentals, 1, 0, "using approximate transcendental
LANGOPT(SizedDeallocation , 1, 0, "sized deallocation")
LANGOPT(AlignedAllocation , 1, 0, "aligned allocation")
+LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable")
LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'")
LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts")
-BENIGN_LANGOPT(ModularCodegen , 1, 0, "Modular codegen")
+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")
@@ -216,7 +222,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")
@@ -262,6 +269,11 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
"field padding (0: none, 1:least "
"aggressive, 2: more aggressive)")
+LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation")
+
+BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0,
+ "allow editor placeholders in source")
+
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 10635b1122..51fb5ad661 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -58,6 +58,7 @@ public:
SOB_Trapping // -ftrapv
};
+ // FIXME: Unify with TUKind.
enum CompilingModuleKind {
CMK_None, ///< Not compiling a module interface at all.
CMK_ModuleMap, ///< Compiling a module from a module map.
@@ -88,6 +89,12 @@ public:
MSVC2015 = 19
};
+ enum FPContractModeKind {
+ FPC_Off, // Form fused FP ops only where result will not be affected.
+ FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
+ FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
+ };
+
public:
/// \brief Set of enabled sanitizers.
SanitizerSet Sanitize;
@@ -96,6 +103,16 @@ public:
/// (files, functions, variables) should not be instrumented.
std::vector<std::string> SanitizerBlacklistFiles;
+ /// \brief Paths to the XRay "always instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "always instrument" attribute.
+ std::vector<std::string> XRayAlwaysInstrumentFiles;
+
+ /// \brief Paths to the XRay "never instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "never instrument" attribute.
+ std::vector<std::string> XRayNeverInstrumentFiles;
+
clang::ObjCRuntime ObjCRuntime;
std::string ObjCConstantStringClass;
@@ -150,6 +167,11 @@ public:
return getCompilingModule() != CMK_None;
}
+ /// Do we need to track the owning module for a local declaration?
+ bool trackLocalOwningModule() const {
+ return isCompilingModule() || ModulesLocalVisibility || ModulesTS;
+ }
+
bool isSignedOverflowDefined() const {
return getSignedOverflowBehavior() == SOB_Defined;
}
@@ -170,17 +192,49 @@ 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;
+ }
+
+ bool assumeFunctionsAreConvergent() const {
+ return (CUDA && CUDAIsDevice) || OpenCL;
+ }
};
/// \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/Linkage.h b/include/clang/Basic/Linkage.h
index e96fb568c0..6ec8763f24 100644
--- a/include/clang/Basic/Linkage.h
+++ b/include/clang/Basic/Linkage.h
@@ -45,6 +45,17 @@ enum Linkage : unsigned char {
/// translation units because of types defined in a inline function.
VisibleNoLinkage,
+ /// \brief Internal linkage according to the Modules TS, but can be referred
+ /// to from other translation units indirectly through inline functions and
+ /// templates in the module interface.
+ ModuleInternalLinkage,
+
+ /// \brief Module linkage, which indicates that the entity can be referred
+ /// to from other translation units within the same module, and indirectly
+ /// from arbitrary other translation units through inline functions and
+ /// templates in the module interface.
+ ModuleLinkage,
+
/// \brief External linkage, which indicates that the entity can
/// be referred to from other translation units.
ExternalLinkage
@@ -74,15 +85,20 @@ inline bool isDiscardableGVALinkage(GVALinkage L) {
}
inline bool isExternallyVisible(Linkage L) {
- return L == ExternalLinkage || L == VisibleNoLinkage;
+ return L >= VisibleNoLinkage;
}
inline Linkage getFormalLinkage(Linkage L) {
- if (L == UniqueExternalLinkage)
+ switch (L) {
+ case UniqueExternalLinkage:
return ExternalLinkage;
- if (L == VisibleNoLinkage)
+ case VisibleNoLinkage:
return NoLinkage;
- return L;
+ case ModuleInternalLinkage:
+ return InternalLinkage;
+ default:
+ return L;
+ }
}
inline bool isExternalFormalLinkage(Linkage L) {
diff --git a/include/clang/Basic/MemoryBufferCache.h b/include/clang/Basic/MemoryBufferCache.h
new file mode 100644
index 0000000000..c79c3c40e4
--- /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 51ad109088..0b2a665f05 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -62,6 +62,22 @@ public:
/// \brief The location of the module definition.
SourceLocation DefinitionLoc;
+ enum ModuleKind {
+ /// \brief This is a module that was defined by a module map and built out
+ /// of header files.
+ ModuleMapModule,
+
+ /// \brief This is a C++ Modules TS module interface unit.
+ ModuleInterfaceUnit,
+
+ /// \brief This is a fragment of the global module within some C++ Modules
+ /// TS module.
+ GlobalModuleFragment,
+ };
+
+ /// \brief The kind of this module.
+ ModuleKind Kind = ModuleMapModule;
+
/// \brief The parent of this module. This will be NULL for the top-level
/// module.
Module *Parent;
@@ -71,6 +87,10 @@ public:
/// are found.
const DirectoryEntry *Directory;
+ /// \brief The presumed file name for the module map defining this module.
+ /// Only non-empty when building from preprocessed source.
+ std::string PresumedModuleMapFile;
+
/// \brief The umbrella header or directory.
llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella;
@@ -79,6 +99,10 @@ public:
/// \brief The name of the umbrella entry, as written in the module map.
std::string UmbrellaAsWritten;
+
+ /// \brief The module through which entities defined in this module will
+ /// eventually be exposed, for use in "private" modules.
+ std::string ExportAsModule;
private:
/// \brief The submodules of this module, indexed by name.
@@ -138,11 +162,19 @@ public:
/// \brief Stored information about a header directive that was found in the
/// module map file but has not been resolved to a file.
struct UnresolvedHeaderDirective {
+ HeaderKind Kind = HK_Normal;
SourceLocation FileNameLoc;
std::string FileName;
- bool IsUmbrella;
+ bool IsUmbrella = false;
+ bool HasBuiltinHeader = false;
+ Optional<off_t> Size;
+ Optional<time_t> ModTime;
};
+ /// Headers that are mentioned in the module map file but that we have not
+ /// yet attempted to resolve to a file on the file system.
+ SmallVector<UnresolvedHeaderDirective, 1> UnresolvedHeaders;
+
/// \brief Headers that are mentioned in the module map file but could not be
/// found on the file system.
SmallVector<UnresolvedHeaderDirective, 1> MissingHeaders;
@@ -215,8 +247,6 @@ public:
/// and headers from used modules.
unsigned NoUndeclaredIncludes : 1;
- unsigned WithCodegen : 1;
-
/// \brief Describes the visibility of the various names within a
/// particular module.
enum NameVisibilityKind {
@@ -369,9 +399,20 @@ public:
return IsFramework && Parent && Parent->isPartOfFramework();
}
+ /// Set the parent of this module. This should only be used if the parent
+ /// could not be set during module creation.
+ void setParent(Module *M) {
+ assert(!Parent);
+ Parent = M;
+ Parent->SubModuleIndex[Name] = Parent->SubModules.size();
+ Parent->SubModules.push_back(this);
+ }
+
/// \brief Retrieve the full name of this module, including the path from
/// its top-level module.
- std::string getFullModuleName() const;
+ /// \param AllowStringLiterals If \c true, components that might not be
+ /// lexically valid as identifiers will be emitted as string literals.
+ std::string getFullModuleName(bool AllowStringLiterals = false) const;
/// \brief Whether the full name of this module is equal to joining
/// \p nameParts with "."s.
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index 78fc899882..8dc259c7ab 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/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index 74ec26f19a..3fedaf71dc 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -168,6 +168,9 @@
#ifndef OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE
#define OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(Name)
#endif
+#ifndef OPENMP_TASKGROUP_CLAUSE
+#define OPENMP_TASKGROUP_CLAUSE(Name)
+#endif
// OpenMP directives.
OPENMP_DIRECTIVE(threadprivate)
@@ -270,6 +273,8 @@ OPENMP_CLAUSE(to, OMPToClause)
OPENMP_CLAUSE(from, OMPFromClause)
OPENMP_CLAUSE(use_device_ptr, OMPUseDevicePtrClause)
OPENMP_CLAUSE(is_device_ptr, OMPIsDevicePtrClause)
+OPENMP_CLAUSE(task_reduction, OMPTaskReductionClause)
+OPENMP_CLAUSE(in_reduction, OMPInReductionClause)
// Clauses allowed for OpenMP directive 'parallel'.
OPENMP_PARALLEL_CLAUSE(if)
@@ -430,6 +435,7 @@ OPENMP_TASK_CLAUSE(untied)
OPENMP_TASK_CLAUSE(mergeable)
OPENMP_TASK_CLAUSE(depend)
OPENMP_TASK_CLAUSE(priority)
+OPENMP_TASK_CLAUSE(in_reduction)
// Clauses allowed for OpenMP directive 'atomic'.
OPENMP_ATOMIC_CLAUSE(read)
@@ -552,6 +558,8 @@ OPENMP_TASKLOOP_CLAUSE(priority)
OPENMP_TASKLOOP_CLAUSE(grainsize)
OPENMP_TASKLOOP_CLAUSE(nogroup)
OPENMP_TASKLOOP_CLAUSE(num_tasks)
+OPENMP_TASKLOOP_CLAUSE(reduction)
+OPENMP_TASKLOOP_CLAUSE(in_reduction)
// Clauses allowed for OpenMP directive 'taskloop simd'.
OPENMP_TASKLOOP_SIMD_CLAUSE(if)
@@ -572,6 +580,8 @@ OPENMP_TASKLOOP_SIMD_CLAUSE(simdlen)
OPENMP_TASKLOOP_SIMD_CLAUSE(grainsize)
OPENMP_TASKLOOP_SIMD_CLAUSE(nogroup)
OPENMP_TASKLOOP_SIMD_CLAUSE(num_tasks)
+OPENMP_TASKLOOP_SIMD_CLAUSE(reduction)
+OPENMP_TASKLOOP_SIMD_CLAUSE(in_reduction)
// Clauses allowed for OpenMP directive 'critical'.
OPENMP_CRITICAL_CLAUSE(hint)
@@ -846,6 +856,10 @@ OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(aligned)
OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(safelen)
OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(simdlen)
+// Clauses allowed for OpenMP directive 'taskgroup'.
+OPENMP_TASKGROUP_CLAUSE(task_reduction)
+
+#undef OPENMP_TASKGROUP_CLAUSE
#undef OPENMP_TASKLOOP_SIMD_CLAUSE
#undef OPENMP_TASKLOOP_CLAUSE
#undef OPENMP_LINEAR_KIND
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index 53ce95cab1..b2f14afe56 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -329,6 +329,15 @@ public:
bool hasStorage() const { return DiagStorage != nullptr; }
+ /// Retrieve the string argument at the given index.
+ StringRef getStringArg(unsigned I) {
+ assert(DiagStorage && "No diagnostic storage?");
+ assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args");
+ assert(DiagStorage->DiagArgumentsKind[I]
+ == DiagnosticsEngine::ak_std_string && "Not a string arg");
+ return DiagStorage->DiagArgumentsStr[I];
+ }
+
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
unsigned I) {
PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
diff --git a/include/clang/Basic/SanitizerBlacklist.h b/include/clang/Basic/SanitizerBlacklist.h
index e651e18316..1ae5c36eea 100644
--- a/include/clang/Basic/SanitizerBlacklist.h
+++ b/include/clang/Basic/SanitizerBlacklist.h
@@ -15,29 +15,30 @@
#define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SanitizerSpecialCaseList.h"
+#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/SpecialCaseList.h"
#include <memory>
namespace clang {
class SanitizerBlacklist {
- std::unique_ptr<llvm::SpecialCaseList> SCL;
+ std::unique_ptr<SanitizerSpecialCaseList> SSCL;
SourceManager &SM;
public:
SanitizerBlacklist(const std::vector<std::string> &BlacklistPaths,
SourceManager &SM);
- bool isBlacklistedGlobal(StringRef GlobalName,
+ bool isBlacklistedGlobal(SanitizerMask Mask, StringRef GlobalName,
StringRef Category = StringRef()) const;
- bool isBlacklistedType(StringRef MangledTypeName,
+ bool isBlacklistedType(SanitizerMask Mask, StringRef MangledTypeName,
StringRef Category = StringRef()) const;
- bool isBlacklistedFunction(StringRef FunctionName) const;
- bool isBlacklistedFile(StringRef FileName,
+ bool isBlacklistedFunction(SanitizerMask Mask, StringRef FunctionName) const;
+ bool isBlacklistedFile(SanitizerMask Mask, StringRef FileName,
StringRef Category = StringRef()) const;
- bool isBlacklistedLocation(SourceLocation Loc,
+ bool isBlacklistedLocation(SanitizerMask Mask, SourceLocation Loc,
StringRef Category = StringRef()) const;
};
diff --git a/include/clang/Basic/SanitizerSpecialCaseList.h b/include/clang/Basic/SanitizerSpecialCaseList.h
new file mode 100644
index 0000000000..e3252022a4
--- /dev/null
+++ b/include/clang/Basic/SanitizerSpecialCaseList.h
@@ -0,0 +1,54 @@
+//===--- SanitizerSpecialCaseList.h - SCL for sanitizers --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// An extension of SpecialCaseList to allowing querying sections by
+// SanitizerMask.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H
+#define LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Sanitizers.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace clang {
+
+class SanitizerSpecialCaseList : public llvm::SpecialCaseList {
+public:
+ static std::unique_ptr<SanitizerSpecialCaseList>
+ create(const std::vector<std::string> &Paths, std::string &Error);
+
+ static std::unique_ptr<SanitizerSpecialCaseList>
+ createOrDie(const std::vector<std::string> &Paths);
+
+ // Query blacklisted entries if any bit in Mask matches the entry's section.
+ bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query,
+ StringRef Category = StringRef()) const;
+
+protected:
+ // Initialize SanitizerSections.
+ void createSanitizerSections();
+
+ struct SanitizerSection {
+ SanitizerSection(SanitizerMask SM, SectionEntries &E)
+ : Mask(SM), Entries(E){};
+
+ SanitizerMask Mask;
+ SectionEntries &Entries;
+ };
+
+ std::vector<SanitizerSection> SanitizerSections;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
index c574045e13..d6df617172 100644
--- a/include/clang/Basic/Sanitizers.def
+++ b/include/clang/Basic/Sanitizers.def
@@ -47,6 +47,12 @@ SANITIZER("kernel-address", KernelAddress)
// MemorySanitizer
SANITIZER("memory", Memory)
+// libFuzzer
+SANITIZER("fuzzer", Fuzzer)
+
+// libFuzzer-required instrumentation, no linking.
+SANITIZER("fuzzer-no-link", FuzzerNoLink)
+
// ThreadSanitizer
SANITIZER("thread", Thread)
@@ -57,6 +63,7 @@ SANITIZER("leak", Leak)
SANITIZER("alignment", Alignment)
SANITIZER("array-bounds", ArrayBounds)
SANITIZER("bool", Bool)
+SANITIZER("builtin", Builtin)
SANITIZER("enum", Enum)
SANITIZER("float-cast-overflow", FloatCastOverflow)
SANITIZER("float-divide-by-zero", FloatDivideByZero)
@@ -70,6 +77,7 @@ SANITIZER("nullability-return", NullabilityReturn)
SANITIZER_GROUP("nullability", Nullability,
NullabilityArg | NullabilityAssign | NullabilityReturn)
SANITIZER("object-size", ObjectSize)
+SANITIZER("pointer-overflow", PointerOverflow)
SANITIZER("return", Return)
SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute)
SANITIZER("shift-base", ShiftBase)
@@ -103,11 +111,12 @@ SANITIZER("safe-stack", SafeStack)
// -fsanitize=undefined includes all the sanitizers which have low overhead, no
// ABI or address space layout implications, and only catch undefined behavior.
SANITIZER_GROUP("undefined", Undefined,
- Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
- FloatDivideByZero | IntegerDivideByZero | NonnullAttribute |
- Null | ObjectSize | Return | ReturnsNonnullAttribute |
- Shift | SignedIntegerOverflow | Unreachable | VLABound |
- Function | Vptr)
+ Alignment | Bool | Builtin | ArrayBounds | Enum |
+ FloatCastOverflow | FloatDivideByZero |
+ IntegerDivideByZero | NonnullAttribute | Null | ObjectSize |
+ PointerOverflow | Return | ReturnsNonnullAttribute | Shift |
+ SignedIntegerOverflow | Unreachable | VLABound | Function |
+ Vptr)
// -fsanitize=undefined-trap is an alias for -fsanitize=undefined.
SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined)
diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h
index bfa8e516ed..1b936c7d11 100644
--- a/include/clang/Basic/Sanitizers.h
+++ b/include/clang/Basic/Sanitizers.h
@@ -61,8 +61,8 @@ struct SanitizerSet {
Mask = Value ? (Mask | K) : (Mask & ~K);
}
- /// \brief Disable all sanitizers.
- void clear() { Mask = 0; }
+ /// Disable the sanitizers specified in \p K.
+ void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
/// \brief Returns true if at least one sanitizer is enabled.
bool empty() const { return Mask == 0; }
@@ -79,6 +79,12 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
/// this group enables.
SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
+/// Return the sanitizers which do not affect preprocessing.
+inline SanitizerMask getPPTransparentSanitizers() {
+ return SanitizerKind::CFI | SanitizerKind::Integer |
+ SanitizerKind::Nullability | SanitizerKind::Undefined;
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 006cf3dc95..7418b50f9d 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -39,10 +39,9 @@ class SourceManager;
class FileID {
/// \brief A mostly-opaque identifier, where 0 is "invalid", >0 is
/// this module, and <-1 is something loaded from another module.
- int ID;
-public:
- FileID() : ID(0) {}
+ int ID = 0;
+public:
bool isValid() const { return ID != 0; }
bool isInvalid() const { return ID == 0; }
@@ -86,17 +85,15 @@ private:
///
/// It is important that this type remains small. It is currently 32 bits wide.
class SourceLocation {
- unsigned ID;
+ unsigned ID = 0;
friend class SourceManager;
friend class ASTReader;
friend class ASTWriter;
enum : unsigned {
MacroIDBit = 1U << 31
};
-public:
-
- SourceLocation() : ID(0) {}
+public:
bool isFileID() const { return (ID & MacroIDBit) == 0; }
bool isMacroID() const { return (ID & MacroIDBit) != 0; }
@@ -172,6 +169,11 @@ public:
return getFromRawEncoding((unsigned)(uintptr_t)Encoding);
}
+ static bool isPairOfFileLocations(SourceLocation Start, SourceLocation End) {
+ return Start.isValid() && Start.isFileID() && End.isValid() &&
+ End.isFileID();
+ }
+
void print(raw_ostream &OS, const SourceManager &SM) const;
std::string printToString(const SourceManager &SM) const;
void dump(const SourceManager &SM) const;
@@ -193,8 +195,9 @@ inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) {
class SourceRange {
SourceLocation B;
SourceLocation E;
+
public:
- SourceRange(): B(SourceLocation()), E(SourceLocation()) {}
+ SourceRange() = default;
SourceRange(SourceLocation loc) : B(loc), E(loc) {}
SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {}
@@ -225,9 +228,10 @@ public:
/// range.
class CharSourceRange {
SourceRange Range;
- bool IsTokenRange;
+ bool IsTokenRange = false;
+
public:
- CharSourceRange() : IsTokenRange(false) {}
+ CharSourceRange() = default;
CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {}
static CharSourceRange getTokenRange(SourceRange R) {
@@ -262,18 +266,84 @@ public:
bool isInvalid() const { return !isValid(); }
};
+/// \brief Represents an unpacked "presumed" location which can be presented
+/// to the user.
+///
+/// A 'presumed' location can be modified by \#line and GNU line marker
+/// directives and is always the expansion point of a normal location.
+///
+/// You can get a PresumedLoc from a SourceLocation with SourceManager.
+class PresumedLoc {
+ const char *Filename;
+ unsigned Line, Col;
+ SourceLocation IncludeLoc;
+
+public:
+ PresumedLoc() : Filename(nullptr) {}
+ PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL)
+ : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) {}
+
+ /// \brief Return true if this object is invalid or uninitialized.
+ ///
+ /// This occurs when created with invalid source locations or when walking
+ /// off the top of a \#include stack.
+ bool isInvalid() const { return Filename == nullptr; }
+ bool isValid() const { return Filename != nullptr; }
+
+ /// \brief Return the presumed filename of this location.
+ ///
+ /// This can be affected by \#line etc.
+ const char *getFilename() const {
+ assert(isValid());
+ return Filename;
+ }
+
+ /// \brief Return the presumed line number of this location.
+ ///
+ /// This can be affected by \#line etc.
+ unsigned getLine() const {
+ assert(isValid());
+ return Line;
+ }
+
+ /// \brief Return the presumed column number of this location.
+ ///
+ /// This cannot be affected by \#line, but is packaged here for convenience.
+ unsigned getColumn() const {
+ assert(isValid());
+ return Col;
+ }
+
+ /// \brief Return the presumed include location of this location.
+ ///
+ /// This can be affected by GNU linemarker directives.
+ SourceLocation getIncludeLoc() const {
+ assert(isValid());
+ return IncludeLoc;
+ }
+};
+
+class FileEntry;
+
/// \brief A SourceLocation and its associated SourceManager.
///
/// This is useful for argument passing to functions that expect both objects.
class FullSourceLoc : public SourceLocation {
- const SourceManager *SrcMgr;
+ const SourceManager *SrcMgr = nullptr;
+
public:
/// \brief Creates a FullSourceLoc where isValid() returns \c false.
- explicit FullSourceLoc() : SrcMgr(nullptr) {}
+ FullSourceLoc() = default;
explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM)
: SourceLocation(Loc), SrcMgr(&SM) {}
+ bool hasManager() const {
+ bool hasSrcMgr = SrcMgr != nullptr;
+ assert(hasSrcMgr == isValid() && "FullSourceLoc has location but no manager");
+ return hasSrcMgr;
+ }
+
/// \pre This FullSourceLoc has an associated SourceManager.
const SourceManager &getManager() const {
assert(SrcMgr && "SourceManager is NULL.");
@@ -284,6 +354,13 @@ public:
FullSourceLoc getExpansionLoc() const;
FullSourceLoc getSpellingLoc() const;
+ FullSourceLoc getFileLoc() const;
+ std::pair<FullSourceLoc, FullSourceLoc> getImmediateExpansionRange() const;
+ PresumedLoc getPresumedLoc(bool UseLineDirectives = true) const;
+ bool isMacroArgExpansion(FullSourceLoc *StartLoc = nullptr) const;
+ FullSourceLoc getImmediateMacroCallerLoc() const;
+ std::pair<FullSourceLoc, StringRef> getModuleImportLoc() const;
+ unsigned getFileOffset() const;
unsigned getExpansionLineNumber(bool *Invalid = nullptr) const;
unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const;
@@ -293,6 +370,12 @@ public:
const char *getCharacterData(bool *Invalid = nullptr) const;
+ unsigned getLineNumber(bool *Invalid = nullptr) const;
+ unsigned getColumnNumber(bool *Invalid = nullptr) const;
+
+ std::pair<FullSourceLoc, FullSourceLoc> getExpansionRange() const;
+
+ const FileEntry *getFileEntry() const;
/// \brief Return a StringRef to the source buffer data for the
/// specified FileID.
@@ -321,8 +404,7 @@ public:
}
/// \brief Comparison function class, useful for sorting FullSourceLocs.
- struct BeforeThanCompare : public std::binary_function<FullSourceLoc,
- FullSourceLoc, bool> {
+ struct BeforeThanCompare {
bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const {
return lhs.isBeforeInTranslationUnitThan(rhs);
}
@@ -346,50 +428,6 @@ public:
};
-/// \brief Represents an unpacked "presumed" location which can be presented
-/// to the user.
-///
-/// A 'presumed' location can be modified by \#line and GNU line marker
-/// directives and is always the expansion point of a normal location.
-///
-/// You can get a PresumedLoc from a SourceLocation with SourceManager.
-class PresumedLoc {
- const char *Filename;
- unsigned Line, Col;
- SourceLocation IncludeLoc;
-public:
- PresumedLoc() : Filename(nullptr) {}
- PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL)
- : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) {
- }
-
- /// \brief Return true if this object is invalid or uninitialized.
- ///
- /// This occurs when created with invalid source locations or when walking
- /// off the top of a \#include stack.
- bool isInvalid() const { return Filename == nullptr; }
- bool isValid() const { return Filename != nullptr; }
-
- /// \brief Return the presumed filename of this location.
- ///
- /// This can be affected by \#line etc.
- const char *getFilename() const { assert(isValid()); return Filename; }
-
- /// \brief Return the presumed line number of this location.
- ///
- /// This can be affected by \#line etc.
- unsigned getLine() const { assert(isValid()); return Line; }
-
- /// \brief Return the presumed column number of this location.
- ///
- /// This cannot be affected by \#line, but is packaged here for convenience.
- unsigned getColumn() const { assert(isValid()); return Col; }
-
- /// \brief Return the presumed include location of this location.
- ///
- /// This can be affected by GNU linemarker directives.
- SourceLocation getIncludeLoc() const { assert(isValid()); return IncludeLoc; }
-};
} // end namespace clang
@@ -422,8 +460,7 @@ namespace llvm {
// Teach SmallPtrSet how to handle SourceLocation.
template<>
- class PointerLikeTypeTraits<clang::SourceLocation> {
- public:
+ struct PointerLikeTypeTraits<clang::SourceLocation> {
static inline void *getAsVoidPointer(clang::SourceLocation L) {
return L.getPtrEncoding();
}
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index c8fe2ab90c..16bd5616a6 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -80,9 +80,19 @@ namespace SrcMgr {
/// system_header is seen or in various other cases.
///
enum CharacteristicKind {
- C_User, C_System, C_ExternCSystem
+ C_User, C_System, C_ExternCSystem, C_User_ModuleMap, C_System_ModuleMap
};
+ /// Determine whether a file / directory characteristic is for system code.
+ inline bool isSystem(CharacteristicKind CK) {
+ return CK != C_User && CK != C_User_ModuleMap;
+ }
+
+ /// Determine whether a file characteristic is for a module map.
+ inline bool isModuleMap(CharacteristicKind CK) {
+ return CK == C_User_ModuleMap || CK == C_System_ModuleMap;
+ }
+
/// \brief One instance of this struct is kept for every file loaded or used.
///
/// This object owns the MemoryBuffer object.
@@ -202,12 +212,6 @@ namespace SrcMgr {
/// this content cache. This is used for performance analysis.
llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const;
- void setBuffer(std::unique_ptr<llvm::MemoryBuffer> B) {
- assert(!Buffer.getPointer() && "MemoryBuffer already set.");
- Buffer.setPointer(B.release());
- Buffer.setInt(0);
- }
-
/// \brief Get the underlying buffer, returning NULL if the buffer is not
/// yet available.
llvm::MemoryBuffer *getRawBuffer() const { return Buffer.getPointer(); }
@@ -251,12 +255,14 @@ namespace SrcMgr {
/// preprocessing of this \#include, including this SLocEntry.
///
/// Zero means the preprocessor didn't provide such info for this SLocEntry.
- unsigned NumCreatedFIDs;
+ unsigned NumCreatedFIDs : 31;
- /// \brief Contains the ContentCache* and the bits indicating the
- /// characteristic of the file and whether it has \#line info, all
- /// bitmangled together.
- uintptr_t Data;
+ /// \brief Whether this FileInfo has any \#line directives.
+ unsigned HasLineDirectives : 1;
+
+ /// \brief The content cache and the characteristic of the file.
+ llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind>
+ ContentAndKind;
friend class clang::SourceManager;
friend class clang::ASTWriter;
@@ -269,10 +275,9 @@ namespace SrcMgr {
FileInfo X;
X.IncludeLoc = IL.getRawEncoding();
X.NumCreatedFIDs = 0;
- X.Data = (uintptr_t)Con;
- assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned");
- assert((unsigned)FileCharacter < 4 && "invalid file character");
- X.Data |= (unsigned)FileCharacter;
+ X.HasLineDirectives = false;
+ X.ContentAndKind.setPointer(Con);
+ X.ContentAndKind.setInt(FileCharacter);
return X;
}
@@ -280,22 +285,22 @@ namespace SrcMgr {
return SourceLocation::getFromRawEncoding(IncludeLoc);
}
- const ContentCache* getContentCache() const {
- return reinterpret_cast<const ContentCache*>(Data & ~uintptr_t(7));
+ const ContentCache *getContentCache() const {
+ return ContentAndKind.getPointer();
}
/// \brief Return whether this is a system header or not.
CharacteristicKind getFileCharacteristic() const {
- return (CharacteristicKind)(Data & 3);
+ return ContentAndKind.getInt();
}
/// \brief Return true if this FileID has \#line directives in it.
- bool hasLineDirectives() const { return (Data & 4) != 0; }
+ bool hasLineDirectives() const { return HasLineDirectives; }
/// \brief Set the flag that indicates that this FileID has
/// line table entries associated with it.
void setHasLineDirectives() {
- Data |= 4;
+ HasLineDirectives = true;
}
};
@@ -407,6 +412,8 @@ namespace SrcMgr {
};
public:
+ SLocEntry() : Offset(), IsExpansion(), File() {}
+
unsigned getOffset() const { return Offset; }
bool isExpansion() const { return IsExpansion; }
@@ -722,6 +729,10 @@ public:
void clearIDTables();
+ /// Initialize this source manager suitably to replay the compilation
+ /// described by \p Old. Requires that \p Old outlive \p *this.
+ void initializeForReplay(const SourceManager &Old);
+
DiagnosticsEngine &getDiagnostics() const { return Diag; }
FileManager &getFileManager() const { return FileMgr; }
@@ -785,9 +796,8 @@ public:
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
int LoadedID = 0, unsigned LoadedOffset = 0) {
- const SrcMgr::ContentCache *
- IR = getOrCreateContentCache(SourceFile,
- /*isSystemFile=*/FileCharacter != SrcMgr::C_User);
+ const SrcMgr::ContentCache *IR =
+ getOrCreateContentCache(SourceFile, isSystem(FileCharacter));
assert(IR && "getOrCreateContentCache() cannot return NULL");
return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
}
@@ -800,7 +810,22 @@ public:
SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
int LoadedID = 0, unsigned LoadedOffset = 0,
SourceLocation IncludeLoc = SourceLocation()) {
- return createFileID(createMemBufferContentCache(std::move(Buffer)),
+ return createFileID(
+ createMemBufferContentCache(Buffer.release(), /*DoNotFree*/ false),
+ IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
+ }
+
+ enum UnownedTag { Unowned };
+
+ /// \brief Create a new FileID that represents the specified memory buffer.
+ ///
+ /// This does no caching of the buffer and takes ownership of the
+ /// MemoryBuffer, so only pass a MemoryBuffer to this once.
+ FileID createFileID(UnownedTag, llvm::MemoryBuffer *Buffer,
+ SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
+ int LoadedID = 0, unsigned LoadedOffset = 0,
+ SourceLocation IncludeLoc = SourceLocation()) {
+ return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/true),
IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
}
@@ -865,7 +890,7 @@ public:
const FileEntry *NewFile);
/// \brief Returns true if the file contents have been overridden.
- bool isFileOverridden(const FileEntry *File) {
+ bool isFileOverridden(const FileEntry *File) const {
if (OverriddenFilesInfo) {
if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File))
return true;
@@ -1356,7 +1381,7 @@ public:
/// \brief Returns if a SourceLocation is in a system header.
bool isInSystemHeader(SourceLocation Loc) const {
- return getFileCharacteristic(Loc) != SrcMgr::C_User;
+ return isSystem(getFileCharacteristic(Loc));
}
/// \brief Returns if a SourceLocation is in an "extern C" system header.
@@ -1399,10 +1424,9 @@ public:
/// specified by Loc.
///
/// If FilenameID is -1, it is considered to be unspecified.
- void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID);
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID,
bool IsFileEntry, bool IsFileExit,
- bool IsSystemHeader, bool IsExternCHeader);
+ SrcMgr::CharacteristicKind FileKind);
/// \brief Determine if the source manager has a line table.
bool hasLineTable() const { return LineTable != nullptr; }
@@ -1474,6 +1498,17 @@ public:
/// \returns true if LHS source location comes before RHS, false otherwise.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
+ /// \brief Determines whether the two decomposed source location is in the
+ /// same translation unit. As a byproduct, it also calculates the order
+ /// of the source locations in case they are in the same TU.
+ ///
+ /// \returns Pair of bools the first component is true if the two locations
+ /// are in the same TU. The second bool is true if the first is true
+ /// and \p LOffs is before \p ROffs.
+ std::pair<bool, bool>
+ isInTheSameTranslationUnit(std::pair<FileID, unsigned> &LOffs,
+ std::pair<FileID, unsigned> &ROffs) const;
+
/// \brief Determines the order of 2 source locations in the "source location
/// address space".
bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const {
@@ -1494,6 +1529,14 @@ public:
return LHSLoaded;
}
+ /// Return true if the Point is within Start and End.
+ bool isPointWithin(SourceLocation Location, SourceLocation Start,
+ SourceLocation End) const {
+ return Location == Start || Location == End ||
+ (isBeforeInTranslationUnit(Start, Location) &&
+ isBeforeInTranslationUnit(Location, End));
+ }
+
// Iterators over FileInfos.
typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>
::const_iterator fileinfo_iterator;
@@ -1665,7 +1708,7 @@ private:
/// \brief Create a new ContentCache for the specified memory buffer.
const SrcMgr::ContentCache *
- createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buf);
+ createMemBufferContentCache(llvm::MemoryBuffer *Buf, bool DoNotFree);
FileID getFileIDSlow(unsigned SLocOffset) const;
FileID getFileIDLocal(unsigned SLocOffset) const;
diff --git a/include/clang/Basic/SourceManagerInternals.h b/include/clang/Basic/SourceManagerInternals.h
index e65c97b003..9403dea888 100644
--- a/include/clang/Basic/SourceManagerInternals.h
+++ b/include/clang/Basic/SourceManagerInternals.h
@@ -102,8 +102,6 @@ public:
unsigned getNumFilenames() const { return FilenamesByID.size(); }
void AddLineNote(FileID FID, unsigned Offset,
- unsigned LineNo, int FilenameID);
- void AddLineNote(FileID FID, unsigned Offset,
unsigned LineNo, int FilenameID,
unsigned EntryExit, SrcMgr::CharacteristicKind FileKind);
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 33952f83ff..377534baab 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -52,6 +52,7 @@ namespace clang {
TST_int,
TST_int128,
TST_half, // OpenCL half, ARM NEON __fp16
+ TST_Float16, // C11 extension ISO/IEC TS 18661-3
TST_float,
TST_double,
TST_float128,
@@ -236,7 +237,7 @@ namespace clang {
CC_X86ThisCall, // __attribute__((thiscall))
CC_X86VectorCall, // __attribute__((vectorcall))
CC_X86Pascal, // __attribute__((pascal))
- CC_X86_64Win64, // __attribute__((ms_abi))
+ CC_Win64, // __attribute__((ms_abi))
CC_X86_64SysV, // __attribute__((sysv_abi))
CC_X86RegCall, // __attribute__((regcall))
CC_AAPCS, // __attribute__((pcs("aapcs")))
diff --git a/include/clang/Basic/SyncScope.h b/include/clang/Basic/SyncScope.h
new file mode 100644
index 0000000000..09ac005218
--- /dev/null
+++ b/include/clang/Basic/SyncScope.h
@@ -0,0 +1,154 @@
+//===--- SyncScope.h - Atomic synchronization scopes ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides definitions for the atomic synchronization scopes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_SYNCSCOPE_H
+#define LLVM_CLANG_BASIC_SYNCSCOPE_H
+
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <memory>
+
+namespace clang {
+
+/// \brief Defines synch scope values used internally by clang.
+///
+/// The enum values start from 0 and are contiguous. They are mainly used for
+/// enumerating all supported synch scope values and mapping them to LLVM
+/// synch scopes. Their numerical values may be different from the corresponding
+/// synch scope enums used in source languages.
+///
+/// In atomic builtin and expressions, language-specific synch scope enums are
+/// used. Currently only OpenCL memory scope enums are supported and assumed
+/// to be used by all languages. However, in the future, other languages may
+/// define their own set of synch scope enums. The language-specific synch scope
+/// values are represented by class AtomicScopeModel and its derived classes.
+///
+/// To add a new enum value:
+/// Add the enum value to enum class SyncScope.
+/// Update enum value Last if necessary.
+/// Update getAsString.
+///
+enum class SyncScope {
+ OpenCLWorkGroup,
+ OpenCLDevice,
+ OpenCLAllSVMDevices,
+ OpenCLSubGroup,
+ Last = OpenCLSubGroup
+};
+
+inline llvm::StringRef getAsString(SyncScope S) {
+ switch (S) {
+ case SyncScope::OpenCLWorkGroup:
+ return "opencl_workgroup";
+ case SyncScope::OpenCLDevice:
+ return "opencl_device";
+ case SyncScope::OpenCLAllSVMDevices:
+ return "opencl_allsvmdevices";
+ case SyncScope::OpenCLSubGroup:
+ return "opencl_subgroup";
+ }
+ llvm_unreachable("Invalid synch scope");
+}
+
+/// \brief Defines the kind of atomic scope models.
+enum class AtomicScopeModelKind { None, OpenCL };
+
+/// \brief Defines the interface for synch scope model.
+class AtomicScopeModel {
+public:
+ virtual ~AtomicScopeModel() {}
+ /// \brief Maps language specific synch scope values to internal
+ /// SyncScope enum.
+ virtual SyncScope map(unsigned S) const = 0;
+
+ /// \brief Check if the compile-time constant synch scope value
+ /// is valid.
+ virtual bool isValid(unsigned S) const = 0;
+
+ /// \brief Get all possible synch scope values that might be
+ /// encountered at runtime for the current language.
+ virtual ArrayRef<unsigned> getRuntimeValues() const = 0;
+
+ /// \brief If atomic builtin function is called with invalid
+ /// synch scope value at runtime, it will fall back to a valid
+ /// synch scope value returned by this function.
+ virtual unsigned getFallBackValue() const = 0;
+
+ /// \brief Create an atomic scope model by AtomicScopeModelKind.
+ /// \return an empty std::unique_ptr for AtomicScopeModelKind::None.
+ static std::unique_ptr<AtomicScopeModel> create(AtomicScopeModelKind K);
+};
+
+/// \brief Defines the synch scope model for OpenCL.
+class AtomicScopeOpenCLModel : public AtomicScopeModel {
+public:
+ /// The enum values match the pre-defined macros
+ /// __OPENCL_MEMORY_SCOPE_*, which are used to define memory_scope_*
+ /// enums in opencl-c.h.
+ enum ID {
+ WorkGroup = 1,
+ Device = 2,
+ AllSVMDevices = 3,
+ SubGroup = 4,
+ Last = SubGroup
+ };
+
+ AtomicScopeOpenCLModel() {}
+
+ SyncScope map(unsigned S) const override {
+ switch (static_cast<ID>(S)) {
+ case WorkGroup:
+ return SyncScope::OpenCLWorkGroup;
+ case Device:
+ return SyncScope::OpenCLDevice;
+ case AllSVMDevices:
+ return SyncScope::OpenCLAllSVMDevices;
+ case SubGroup:
+ return SyncScope::OpenCLSubGroup;
+ }
+ llvm_unreachable("Invalid language synch scope value");
+ }
+
+ bool isValid(unsigned S) const override {
+ return S >= static_cast<unsigned>(WorkGroup) &&
+ S <= static_cast<unsigned>(Last);
+ }
+
+ ArrayRef<unsigned> getRuntimeValues() const override {
+ static_assert(Last == SubGroup, "Does not include all synch scopes");
+ static const unsigned Scopes[] = {
+ static_cast<unsigned>(WorkGroup), static_cast<unsigned>(Device),
+ static_cast<unsigned>(AllSVMDevices), static_cast<unsigned>(SubGroup)};
+ return llvm::makeArrayRef(Scopes);
+ }
+
+ unsigned getFallBackValue() const override {
+ return static_cast<unsigned>(AllSVMDevices);
+ }
+};
+
+inline std::unique_ptr<AtomicScopeModel>
+AtomicScopeModel::create(AtomicScopeModelKind K) {
+ switch (K) {
+ case AtomicScopeModelKind::None:
+ return std::unique_ptr<AtomicScopeModel>{};
+ case AtomicScopeModelKind::OpenCL:
+ return llvm::make_unique<AtomicScopeOpenCLModel>();
+ }
+ llvm_unreachable("Invalid atomic scope model kind");
+}
+}
+
+#endif
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index 5d45e162d9..8f4f5e9a74 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -150,6 +150,16 @@ namespace clang {
};
}
+ /// \brief Nios2 builtins
+ namespace Nios2 {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsNios2.def"
+ LastTSBuiltin
+ };
+ }
+
/// \brief MIPS builtins
namespace Mips {
enum {
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 46db895489..f80f6b7a6b 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -23,6 +23,7 @@
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -45,6 +46,7 @@ class MacroBuilder;
class QualType;
class SourceLocation;
class SourceManager;
+class Type;
namespace Builtin { struct Info; }
@@ -84,7 +86,7 @@ protected:
*LongDoubleFormat, *Float128Format;
unsigned char RegParmMax, SSERegParmMax;
TargetCXXABI TheCXXABI;
- const LangAS::Map *AddrSpaceMap;
+ const LangASMap *AddrSpaceMap;
mutable StringRef PlatformName;
mutable VersionTuple PlatformMinVersion;
@@ -154,7 +156,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 +170,7 @@ public:
PowerABIBuiltinVaList,
/// __builtin_va_list as defined by the x86-64 ABI:
- /// http://www.x86-64.org/documentation/abi.pdf
+ /// http://refspecs.linuxbase.org/elf/x86_64-abi-0.21.pdf
X86_64ABIBuiltinVaList,
/// __builtin_va_list as defined by ARM AAPCS ABI
@@ -225,6 +227,20 @@ protected:
public:
IntType getSizeType() const { return SizeType; }
+ IntType getSignedSizeType() const {
+ switch (SizeType) {
+ case UnsignedShort:
+ return SignedShort;
+ case UnsignedInt:
+ return SignedInt;
+ case UnsignedLong:
+ return SignedLong;
+ case UnsignedLongLong:
+ return SignedLongLong;
+ default:
+ llvm_unreachable("Invalid SizeType");
+ }
+ }
IntType getIntMaxType() const { return IntMaxType; }
IntType getUIntMaxType() const {
return getCorrespondingUnsignedType(IntMaxType);
@@ -232,6 +248,9 @@ public:
IntType getPtrDiffType(unsigned AddrSpace) const {
return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace);
}
+ IntType getUnsignedPtrDiffType(unsigned AddrSpace) const {
+ return getCorrespondingUnsignedType(getPtrDiffType(AddrSpace));
+ }
IntType getIntPtrType() const { return IntPtrType; }
IntType getUIntPtrType() const {
return getCorrespondingUnsignedType(IntPtrType);
@@ -303,9 +322,7 @@ public:
/// \brief Get integer value for null pointer.
/// \param AddrSpace address space of pointee in source language.
- virtual uint64_t getNullPointerValue(unsigned AddrSpace) const {
- return 0;
- }
+ virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; }
/// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits.
unsigned getBoolWidth() const { return BoolWidth; }
@@ -432,6 +449,9 @@ public:
/// \brief Return the maximum width lock-free atomic operation which can be
/// inlined given the supported features of the given target.
unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; }
+ /// \brief Set the maximum inline or promote width lock-free atomic operation
+ /// for the given target.
+ virtual void setMaxAtomicWidth() {}
/// \brief Returns true if the given target supports lock-free atomic
/// operations at the specified width and alignment.
virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits,
@@ -449,21 +469,6 @@ public:
/// types for the given target.
unsigned getSimdDefaultAlign() const { return SimdDefaultAlign; }
- /// Return the alignment (in bits) of the thrown exception object. This is
- /// only meaningful for targets that allocate C++ exceptions in a system
- /// runtime, such as those using the Itanium C++ ABI.
- virtual unsigned getExnObjectAlignment() const {
- // Itanium says that an _Unwind_Exception has to be "double-word"
- // aligned (and thus the end of it is also so-aligned), meaning 16
- // bytes. Of course, that was written for the actual Itanium,
- // which is a 64-bit platform. Classically, the ABI doesn't really
- // specify the alignment on other platforms, but in practice
- // libUnwind declares the struct with __attribute__((aligned)), so
- // we assume that alignment here. (It's generally 16 bytes, but
- // some targets overwrite it.)
- return getDefaultAlignForAttributeAligned();
- }
-
/// \brief Return the size of intmax_t and uintmax_t for this target, in bits.
unsigned getIntMaxTWidth() const {
return getTypeWidth(IntMaxType);
@@ -823,8 +828,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,
@@ -853,6 +859,11 @@ public:
return false;
}
+ /// brief Determine whether this TargetInfo supports the given CPU name.
+ virtual bool isValidCPUName(StringRef Name) const {
+ return true;
+ }
+
/// \brief Use the specified ABI.
///
/// \return False on error (invalid ABI name).
@@ -875,6 +886,11 @@ public:
Features[Name] = Enabled;
}
+ /// \brief Determine whether this TargetInfo supports the given feature.
+ virtual bool isValidFeatureName(StringRef Feature) const {
+ return true;
+ }
+
/// \brief Perform initialization based on the user configured
/// set of features (e.g., +sse4).
///
@@ -900,6 +916,10 @@ public:
// argument.
virtual bool validateCpuSupports(StringRef Name) const { return false; }
+ // \brief Validate the contents of the __builtin_cpu_is(const char*)
+ // argument.
+ virtual bool validateCpuIs(StringRef Name) const { return false; }
+
// \brief Returns maximal number of args passed in registers.
unsigned getRegParmMax() const {
assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle");
@@ -949,8 +969,14 @@ public:
return nullptr;
}
- const LangAS::Map &getAddressSpaceMap() const {
- return *AddrSpaceMap;
+ const LangASMap &getAddressSpaceMap() const { return *AddrSpaceMap; }
+
+ /// \brief Return an AST address space which can be used opportunistically
+ /// for constant global memory. It must be possible to convert pointers into
+ /// this address space to LangAS::Default. If no such address space exists,
+ /// this may return None, and such optimizations will be disabled.
+ virtual llvm::Optional<LangAS> getConstantAddressSpace() const {
+ return LangAS::Default;
}
/// \brief Retrieve the name of the platform as it is used in the
@@ -1027,10 +1053,8 @@ public:
return getTargetOpts().SupportedOpenCLOptions;
}
- /// \brief Get OpenCL image type address space.
- virtual LangAS::ID getOpenCLImageAddrSpace() const {
- return LangAS::opencl_global;
- }
+ /// \brief Get address space for OpenCL type.
+ virtual LangAS getOpenCLTypeAddrSpace(const Type *T) const;
/// \returns Target specific vtbl ptr address space.
virtual unsigned getVtblPtrAddressSpace() const {
diff --git a/include/clang/Basic/TargetOptions.h b/include/clang/Basic/TargetOptions.h
index 2889cce596..9bb19c7b79 100644
--- a/include/clang/Basic/TargetOptions.h
+++ b/include/clang/Basic/TargetOptions.h
@@ -18,14 +18,14 @@
#include <string>
#include <vector>
#include "clang/Basic/OpenCLOptions.h"
+#include "llvm/Target/TargetOptions.h"
namespace clang {
/// \brief Options for controlling the target.
class TargetOptions {
public:
- /// If given, the name of the target triple to compile for. If not given the
- /// target will be selected to match the host.
+ /// The name of the target triple to compile for.
std::string Triple;
/// When compiling for the device side, contains the triple used to compile
@@ -42,7 +42,7 @@ public:
std::string ABI;
/// The EABI version to use
- std::string EABIVersion;
+ llvm::EABI EABIVersion;
/// If given, the version string of the linker in use.
std::string LinkerVersion;
diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h
index aed287b462..ac99ad185f 100644
--- a/include/clang/Basic/TemplateKinds.h
+++ b/include/clang/Basic/TemplateKinds.h
@@ -26,13 +26,21 @@ enum TemplateNameKind {
TNK_Function_template,
/// The name refers to a template whose specialization produces a
/// type. The template itself could be a class template, template
- /// template parameter, or C++0x template alias.
+ /// template parameter, or template alias.
TNK_Type_template,
/// The name refers to a variable template whose specialization produces a
/// variable.
TNK_Var_template,
- /// The name refers to a dependent template name. Whether the
- /// template name is assumed to refer to a type template or a
+ /// The name refers to a dependent template name:
+ /// \code
+ /// template<typename MetaFun, typename T1, typename T2> struct apply2 {
+ /// typedef typename MetaFun::template apply<T1, T2>::type type;
+ /// };
+ /// \endcode
+ ///
+ /// Here, "apply" is a dependent template name within the typename
+ /// specifier in the typedef. "apply" is a nested template, and
+ /// whether the template name is assumed to refer to a type template or a
/// function template depends on the context in which the template
/// name occurs.
TNK_Dependent_template_name
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 104b053a14..9bb7b6a7d6 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -27,8 +27,11 @@
#ifndef CXX11_KEYWORD
#define CXX11_KEYWORD(X,Y) KEYWORD(X,KEYCXX11|(Y))
#endif
+#ifndef CXX2A_KEYWORD
+#define CXX2A_KEYWORD(X,Y) KEYWORD(X,KEYCXX2A|(Y))
+#endif
#ifndef CONCEPTS_KEYWORD
-#define CONCEPTS_KEYWORD(X) KEYWORD(X,KEYCONCEPTS)
+#define CONCEPTS_KEYWORD(X) CXX2A_KEYWORD(X,KEYCONCEPTS)
#endif
#ifndef MODULES_KEYWORD
#define MODULES_KEYWORD(X) KEYWORD(X,KEYMODULES)
@@ -142,7 +145,7 @@ TOK(numeric_constant) // 0x123
TOK(char_constant) // 'a'
TOK(wide_char_constant) // L'b'
-// C++1z Character Constants
+// C++17 Character Constants
TOK(utf8_char_constant) // u8'a'
// C++11 Character Constants
@@ -236,6 +239,7 @@ PUNCTUATOR(caretcaret, "^^")
// implementation namespace
// KEYNOCXX - This is a keyword in every non-C++ dialect.
// KEYCXX11 - This is a C++ keyword introduced to C++ in C++11
+// KEYCXX2A - This is a C++ keyword introduced to C++ in C++2a
// KEYCONCEPTS - This is a keyword if the C++ extensions for concepts
// are enabled.
// KEYMODULES - This is a keyword if the C++ extensions for modules
@@ -362,7 +366,7 @@ CXX11_KEYWORD(nullptr , 0)
CXX11_KEYWORD(static_assert , 0)
CXX11_KEYWORD(thread_local , 0)
-// C++ concepts TS keywords
+// C++2a / concepts TS keywords
CONCEPTS_KEYWORD(concept)
CONCEPTS_KEYWORD(requires)
@@ -375,6 +379,9 @@ KEYWORD(co_yield , KEYCOROUTINES)
MODULES_KEYWORD(module)
MODULES_KEYWORD(import)
+// C11 Extension
+KEYWORD(_Float16 , KEYALL)
+
// GNU Extensions (in impl-reserved namespace)
KEYWORD(_Decimal32 , KEYALL)
KEYWORD(_Decimal64 , KEYALL)
@@ -411,6 +418,7 @@ TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS)
// MSVC12.0 / VS2013 Type Traits
TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS)
+TYPE_TRAIT_1(__is_trivially_destructible, IsTriviallyDestructible, KEYCXX)
TYPE_TRAIT_1(__is_nothrow_destructible, IsNothrowDestructible, KEYMS)
TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX)
TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX)
@@ -432,13 +440,13 @@ TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX)
TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX)
TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX)
+TYPE_TRAIT_1(__is_aggregate, IsAggregate, KEYCXX)
TYPE_TRAIT_2(__is_base_of, IsBaseOf, KEYCXX)
TYPE_TRAIT_1(__is_class, IsClass, KEYCXX)
TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX)
TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX)
TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX)
TYPE_TRAIT_1(__is_final, IsFinal, KEYCXX)
-// Tentative name - there's no implementation of std::is_literal_type yet.
TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX)
// Name for GCC 4.6 compatibility - people have already written libraries using
// this name unfortunately.
@@ -447,6 +455,8 @@ TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX)
TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX)
TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX)
TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
+TYPE_TRAIT_1(__has_unique_object_representations,
+ HasUniqueObjectRepresentations, KEYCXX)
// Clang-only C++ Type Traits
TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)
@@ -787,6 +797,11 @@ ANNOTATION(pragma_openmp_end)
// handles #pragma loop ... directives.
ANNOTATION(pragma_loop_hint)
+ANNOTATION(pragma_fp)
+
+// Annotation for the attribute pragma directives - #pragma clang attribute ...
+ANNOTATION(pragma_attribute)
+
// Annotations for module import translated from #include etc.
ANNOTATION(module_include)
ANNOTATION(module_begin)
@@ -804,6 +819,7 @@ ANNOTATION(module_end)
#undef TYPE_TRAIT_1
#undef TYPE_TRAIT
#undef CONCEPTS_KEYWORD
+#undef CXX2A_KEYWORD
#undef CXX11_KEYWORD
#undef KEYWORD
#undef PUNCTUATOR
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 730ecba3d4..8ecd63f9c3 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,
@@ -64,11 +65,13 @@ namespace clang {
UTT_IsStandardLayout,
UTT_IsTrivial,
UTT_IsTriviallyCopyable,
+ UTT_IsTriviallyDestructible,
UTT_IsUnion,
UTT_IsUnsigned,
UTT_IsVoid,
UTT_IsVolatile,
- UTT_Last = UTT_IsVolatile,
+ UTT_HasUniqueObjectRepresentations,
+ UTT_Last = UTT_HasUniqueObjectRepresentations,
BTT_IsBaseOf,
BTT_IsConvertible,
BTT_IsConvertibleTo,
diff --git a/include/clang/Basic/Visibility.h b/include/clang/Basic/Visibility.h
index 6ac52ed6b5..cc839d789e 100644
--- a/include/clang/Basic/Visibility.h
+++ b/include/clang/Basic/Visibility.h
@@ -75,6 +75,9 @@ public:
static LinkageInfo none() {
return LinkageInfo(NoLinkage, DefaultVisibility, false);
}
+ static LinkageInfo visible_none() {
+ return LinkageInfo(VisibleNoLinkage, DefaultVisibility, false);
+ }
Linkage getLinkage() const { return (Linkage)linkage_; }
Visibility getVisibility() const { return (Visibility)visibility_; }
diff --git a/include/clang/Basic/XRayLists.h b/include/clang/Basic/XRayLists.h
new file mode 100644
index 0000000000..8cfea70e28
--- /dev/null
+++ b/include/clang/Basic/XRayLists.h
@@ -0,0 +1,55 @@
+//===--- XRayLists.h - XRay automatic attribution ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters for always/never XRay instrumenting certain functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_XRAYLISTS_H
+#define LLVM_CLANG_BASIC_XRAYLISTS_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace clang {
+
+class XRayFunctionFilter {
+ std::unique_ptr<llvm::SpecialCaseList> AlwaysInstrument;
+ std::unique_ptr<llvm::SpecialCaseList> NeverInstrument;
+ SourceManager &SM;
+
+public:
+ XRayFunctionFilter(ArrayRef<std::string> AlwaysInstrumentPaths,
+ ArrayRef<std::string> NeverInstrumentPaths,
+ SourceManager &SM);
+
+ enum class ImbueAttribute {
+ NONE,
+ ALWAYS,
+ NEVER,
+ ALWAYS_ARG1,
+ };
+
+ ImbueAttribute shouldImbueFunction(StringRef FunctionName) const;
+
+ ImbueAttribute
+ shouldImbueFunctionsInFile(StringRef Filename,
+ StringRef Category = StringRef()) const;
+
+ ImbueAttribute shouldImbueLocation(SourceLocation Loc,
+ StringRef Category = StringRef()) const;
+};
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h
index 2703f299d2..d1f05124d5 100644
--- a/include/clang/CodeGen/CGFunctionInfo.h
+++ b/include/clang/CodeGen/CGFunctionInfo.h
@@ -461,7 +461,7 @@ class CGFunctionInfo final
unsigned EffectiveCallingConvention : 8;
/// The clang::CallingConv that this was originally created with.
- unsigned ASTCallingConvention : 8;
+ unsigned ASTCallingConvention : 7;
/// Whether this is an instance method.
unsigned InstanceMethod : 1;
@@ -475,6 +475,9 @@ class CGFunctionInfo final
/// Whether this function is returns-retained.
unsigned ReturnsRetained : 1;
+ /// Whether this function saved caller registers.
+ unsigned NoCallerSavedRegs : 1;
+
/// How many arguments to pass inreg.
unsigned HasRegParm : 1;
unsigned RegParm : 3;
@@ -560,6 +563,9 @@ public:
/// is not always reliable for call sites.
bool isReturnsRetained() const { return ReturnsRetained; }
+ /// Whether this function no longer saves caller registers.
+ bool isNoCallerSavedRegs() const { return NoCallerSavedRegs; }
+
/// getASTCallingConvention() - Return the AST-specified calling
/// convention.
CallingConv getASTCallingConvention() const {
@@ -583,10 +589,9 @@ public:
unsigned getRegParm() const { return RegParm; }
FunctionType::ExtInfo getExtInfo() const {
- return FunctionType::ExtInfo(isNoReturn(),
- getHasRegParm(), getRegParm(),
- getASTCallingConvention(),
- isReturnsRetained());
+ return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(),
+ getASTCallingConvention(), isReturnsRetained(),
+ isNoCallerSavedRegs());
}
CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
@@ -623,6 +628,7 @@ public:
ID.AddBoolean(ChainCall);
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
+ ID.AddBoolean(NoCallerSavedRegs);
ID.AddBoolean(HasRegParm);
ID.AddInteger(RegParm);
ID.AddInteger(Required.getOpaqueData());
@@ -648,6 +654,7 @@ public:
ID.AddBoolean(ChainCall);
ID.AddBoolean(info.getNoReturn());
ID.AddBoolean(info.getProducesResult());
+ ID.AddBoolean(info.getNoCallerSavedRegs());
ID.AddBoolean(info.getHasRegParm());
ID.AddInteger(info.getRegParm());
ID.AddInteger(required.getOpaqueData());
diff --git a/include/clang/CodeGen/CodeGenABITypes.h b/include/clang/CodeGen/CodeGenABITypes.h
index e7b7435968..53619fa8ef 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.
//
//===----------------------------------------------------------------------===//
@@ -31,6 +31,8 @@
namespace llvm {
class DataLayout;
class Module;
+ class FunctionType;
+ class Type;
}
namespace clang {
@@ -70,6 +72,19 @@ const CGFunctionInfo &arrangeFreeFunctionCall(CodeGenModule &CGM,
FunctionType::ExtInfo info,
RequiredArgs args);
+/// Returns null if the function type is incomplete and can't be lowered.
+llvm::FunctionType *convertFreeFunctionType(CodeGenModule &CGM,
+ const FunctionDecl *FD);
+
+llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T);
+
+/// Given a non-bitfield struct field, return its index within the elements of
+/// the struct's converted type. The returned index refers to a field number in
+/// the complete object type which is returned by convertTypeForMemory. FD must
+/// be a field in RD directly (i.e. not an inherited field).
+unsigned getLLVMFieldNumber(CodeGenModule &CGM,
+ const RecordDecl *RD, const FieldDecl *FD);
+
} // end namespace CodeGen
} // end namespace clang
diff --git a/include/clang/CodeGen/ConstantInitFuture.h b/include/clang/CodeGen/ConstantInitFuture.h
index ef1a5d2f49..f1a7e2264f 100644
--- a/include/clang/CodeGen/ConstantInitFuture.h
+++ b/include/clang/CodeGen/ConstantInitFuture.h
@@ -31,8 +31,7 @@ class ConstantInitBuilderBase;
}
namespace llvm {
template <>
-class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> {
-public:
+struct PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> {
using T = ::clang::CodeGen::ConstantInitBuilderBase*;
static inline void *getAsVoidPointer(T p) { return p; }
@@ -93,8 +92,7 @@ public:
namespace llvm {
template <>
-class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> {
-public:
+struct PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> {
using T = ::clang::CodeGen::ConstantInitFuture;
static inline void *getAsVoidPointer(T future) {
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
index 6f81ea9d63..e110f6fd30 100644
--- a/include/clang/CodeGen/ModuleBuilder.h
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -84,6 +84,10 @@ public:
/// code generator will schedule the entity for emission if a
/// definition has been registered with this code generator.
llvm::Constant *GetAddrOfGlobal(GlobalDecl decl, bool isForDefinition);
+
+ /// Create a new \c llvm::Module after calling HandleTranslationUnit. This
+ /// enable codegen in interactive processing environments.
+ llvm::Module* StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C);
};
/// CreateLLVMCodeGen - Create a CodeGenerator instance.
diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake
index 55f0ca94de..10074aafd8 100644
--- a/include/clang/Config/config.h.cmake
+++ b/include/clang/Config/config.h.cmake
@@ -20,6 +20,9 @@
/* Default OpenMP runtime used by -fopenmp. */
#define CLANG_DEFAULT_OPENMP_RUNTIME "${CLANG_DEFAULT_OPENMP_RUNTIME}"
+/* Default architecture for OpenMP offloading to Nvidia GPUs. */
+#define CLANG_OPENMP_NVPTX_DEFAULT_ARCH "${CLANG_OPENMP_NVPTX_DEFAULT_ARCH}"
+
/* Multilib suffix for libdir. */
#define CLANG_LIBDIR_SUFFIX "${CLANG_LIBDIR_SUFFIX}"
@@ -38,6 +41,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}
@@ -53,4 +59,9 @@
/* enable x86 relax relocations by default */
#cmakedefine01 ENABLE_X86_RELAX_RELOCATIONS
+/* Enable each functionality of modules */
+#cmakedefine01 CLANG_ENABLE_ARCMT
+#cmakedefine01 CLANG_ENABLE_OBJC_REWRITER
+#cmakedefine01 CLANG_ENABLE_STATIC_ANALYZER
+
#endif
diff --git a/include/clang/CrossTU/CrossTUDiagnostic.h b/include/clang/CrossTU/CrossTUDiagnostic.h
new file mode 100644
index 0000000000..dad38309fd
--- /dev/null
+++ b/include/clang/CrossTU/CrossTUDiagnostic.h
@@ -0,0 +1,29 @@
+//===--- CrossTUDiagnostic.h - Diagnostics for Cross TU ---------*- 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_CROSSTU_CROSSTUDIAGNOSTIC_H
+#define LLVM_CLANG_CROSSTU_CROSSTUDIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+namespace diag {
+enum {
+#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \
+ SHOWINSYSHEADER, CATEGORY) \
+ ENUM,
+#define CROSSTUSTART
+#include "clang/Basic/DiagnosticCrossTUKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_CROSSTU_DIAGNOSTICS
+};
+} // end namespace diag
+} // end namespace clang
+
+#endif // LLVM_CLANG_FRONTEND_FRONTENDDIAGNOSTIC_H
diff --git a/include/clang/CrossTU/CrossTranslationUnit.h b/include/clang/CrossTU/CrossTranslationUnit.h
new file mode 100644
index 0000000000..f2a1690250
--- /dev/null
+++ b/include/clang/CrossTU/CrossTranslationUnit.h
@@ -0,0 +1,159 @@
+//===--- CrossTranslationUnit.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 provides an interface to load binary AST dumps on demand. This
+// feature can be utilized for tools that require cross translation unit
+// support.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H
+#define LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+class CompilerInstance;
+class ASTContext;
+class ASTImporter;
+class ASTUnit;
+class DeclContext;
+class FunctionDecl;
+class NamedDecl;
+class TranslationUnitDecl;
+
+namespace cross_tu {
+
+enum class index_error_code {
+ unspecified = 1,
+ missing_index_file,
+ invalid_index_format,
+ multiple_definitions,
+ missing_definition,
+ failed_import,
+ failed_to_get_external_ast,
+ failed_to_generate_usr
+};
+
+class IndexError : public llvm::ErrorInfo<IndexError> {
+public:
+ static char ID;
+ IndexError(index_error_code C) : Code(C), LineNo(0) {}
+ IndexError(index_error_code C, std::string FileName, int LineNo = 0)
+ : Code(C), FileName(std::move(FileName)), LineNo(LineNo) {}
+ void log(raw_ostream &OS) const override;
+ std::error_code convertToErrorCode() const override;
+ index_error_code getCode() const { return Code; }
+ int getLineNum() const { return LineNo; }
+ std::string getFileName() const { return FileName; }
+
+private:
+ index_error_code Code;
+ std::string FileName;
+ int LineNo;
+};
+
+/// \brief This function parses an index file that determines which
+/// translation unit contains which definition.
+///
+/// The index file format is the following:
+/// each line consists of an USR and a filepath separated by a space.
+///
+/// \return Returns a map where the USR is the key and the filepath is the value
+/// or an error.
+llvm::Expected<llvm::StringMap<std::string>>
+parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir);
+
+std::string createCrossTUIndexString(const llvm::StringMap<std::string> &Index);
+
+/// \brief This class is used for tools that requires cross translation
+/// unit capability.
+///
+/// This class can load function definitions from external AST files.
+/// The loaded definition will be merged back to the original AST using the
+/// AST Importer.
+/// In order to use this class, an index file is required that describes
+/// the locations of the AST files for each function definition.
+///
+/// Note that this class also implements caching.
+class CrossTranslationUnitContext {
+public:
+ CrossTranslationUnitContext(CompilerInstance &CI);
+ ~CrossTranslationUnitContext();
+
+ /// \brief This function loads a function definition from an external AST
+ /// file and merge it into the original AST.
+ ///
+ /// This method should only be used on functions that have no definitions in
+ /// the current translation unit. A function definition with the same
+ /// declaration will be looked up in the index file which should be in the
+ /// \p CrossTUDir directory, called \p IndexName. In case the declaration is
+ /// found in the index the corresponding AST file will be loaded and the
+ /// definition of the function will be merged into the original AST using
+ /// the AST Importer.
+ ///
+ /// \return The declaration with the definition will be returned.
+ /// If no suitable definition is found in the index file or multiple
+ /// definitions found error will be returned.
+ ///
+ /// Note that the AST files should also be in the \p CrossTUDir.
+ llvm::Expected<const FunctionDecl *>
+ getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir,
+ StringRef IndexName);
+
+ /// \brief This function loads a function definition from an external AST
+ /// file.
+ ///
+ /// A function definition with the same declaration will be looked up in the
+ /// index file which should be in the \p CrossTUDir directory, called
+ /// \p IndexName. In case the declaration is found in the index the
+ /// corresponding AST file will be loaded.
+ ///
+ /// \return Returns an ASTUnit that contains the definition of the looked up
+ /// function.
+ ///
+ /// Note that the AST files should also be in the \p CrossTUDir.
+ llvm::Expected<ASTUnit *> loadExternalAST(StringRef LookupName,
+ StringRef CrossTUDir,
+ StringRef IndexName);
+
+ /// \brief This function merges a definition from a separate AST Unit into
+ /// the current one which was created by the compiler instance that
+ /// was passed to the constructor.
+ ///
+ /// \return Returns the resulting definition or an error.
+ llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD);
+
+ /// \brief Get a name to identify a function.
+ static std::string getLookupName(const NamedDecl *ND);
+
+ /// \brief Emit diagnostics for the user for potential configuration errors.
+ void emitCrossTUDiagnostics(const IndexError &IE);
+
+private:
+ ASTImporter &getOrCreateASTImporter(ASTContext &From);
+ const FunctionDecl *findFunctionInDeclContext(const DeclContext *DC,
+ StringRef LookupFnName);
+
+ llvm::StringMap<std::unique_ptr<clang::ASTUnit>> FileASTUnitMap;
+ llvm::StringMap<clang::ASTUnit *> FunctionASTUnitMap;
+ llvm::StringMap<std::string> FunctionFileMap;
+ llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>>
+ ASTUnitImporterMap;
+ CompilerInstance &CI;
+ ASTContext &Context;
+};
+
+} // namespace cross_tu
+} // namespace clang
+
+#endif // LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index acc76f6aa6..bca51b593a 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -70,7 +70,7 @@ def analyzer_opt_analyze_nested_blocks : Flag<["-"], "analyzer-opt-analyze-neste
def analyzer_display_progress : Flag<["-"], "analyzer-display-progress">,
HelpText<"Emit verbose output about the analyzer's progress">;
def analyze_function : Separate<["-"], "analyze-function">,
- HelpText<"Run analysis on specific function">;
+ HelpText<"Run analysis on specific function (for C++ include parameters in name)">;
def analyze_function_EQ : Joined<["-"], "analyze-function=">, Alias<analyze_function>;
def analyzer_eagerly_assume : Flag<["-"], "analyzer-eagerly-assume">,
HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">;
@@ -99,7 +99,19 @@ def analyzer_stats : Flag<["-"], "analyzer-stats">,
HelpText<"Print internal analyzer statistics.">;
def analyzer_checker : Separate<["-"], "analyzer-checker">,
- HelpText<"Choose analyzer checkers to enable">;
+ HelpText<"Choose analyzer checkers to enable">,
+ ValuesCode<[{
+ const char *Values =
+ #define GET_CHECKERS
+ #define CHECKER(FULLNAME, CLASS, DESCFILE, HT, G, H) FULLNAME ","
+ #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
+ #undef GET_CHECKERS
+ #define GET_PACKAGES
+ #define PACKAGE(FULLNAME, G, D) FULLNAME ","
+ #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
+ #undef GET_PACKAGES
+ ;
+ }]>;
def analyzer_checker_EQ : Joined<["-"], "analyzer-checker=">,
Alias<analyzer_checker>;
@@ -134,7 +146,6 @@ 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">;
@@ -144,20 +155,22 @@ def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
HelpText<"The compilation directory to embed in the debug info.">;
def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
+def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">,
+ HelpText<"DWARF debug sections compression">;
+def compress_debug_sections_EQ : Joined<["-"], "compress-debug-sections=">,
+ HelpText<"DWARF debug sections compression type">;
def mno_exec_stack : Flag<["-"], "mnoexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">,
HelpText<"Make assembler warnings fatal">;
def mrelax_relocations : Flag<["--"], "mrelax-relocations">,
HelpText<"Use relaxable elf relocations">;
-def compress_debug_sections : Flag<["-"], "compress-debug-sections">,
- HelpText<"Compress DWARF debug sections using zlib">;
def msave_temp_labels : Flag<["-"], "msave-temp-labels">,
HelpText<"Save temporary labels in the symbol table. "
"Note this may change .s semantics and shouldn't generally be used "
"on compiler-generated code.">;
def mrelocation_model : Separate<["-"], "mrelocation-model">,
- HelpText<"The relocation model to use">;
+ HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">;
def fno_math_builtin : Flag<["-"], "fno-math-builtin">,
HelpText<"Disable implicit builtin knowledge of math functions">;
}
@@ -172,6 +185,8 @@ def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">,
def disable_lifetimemarkers : Flag<["-"], "disable-lifetime-markers">,
HelpText<"Disable lifetime-markers emission even when optimizations are "
"enabled">;
+def disable_O0_optnone : Flag<["-"], "disable-O0-optnone">,
+ HelpText<"Disable adding the optnone attribute to functions at O0">;
def disable_red_zone : Flag<["-"], "disable-red-zone">,
HelpText<"Do not emit code that uses the red zone.">;
def dwarf_column_info : Flag<["-"], "dwarf-column-info">,
@@ -185,6 +200,12 @@ def arange_sections : Flag<["-"], "arange_sections">,
def dwarf_ext_refs : Flag<["-"], "dwarf-ext-refs">,
HelpText<"Generate debug info with external references to clang modules"
" or precompiled headers">;
+def dwarf_explicit_import : Flag<["-"], "dwarf-explicit-import">,
+ HelpText<"Generate explicit import from anonymous namespace to containing"
+ " scope">;
+def debug_forward_template_params : Flag<["-"], "debug-forward-template-params">,
+ HelpText<"Emit complete descriptions of template parameters in forward"
+ " declarations">;
def fforbid_guard_variables : Flag<["-"], "fforbid-guard-variables">,
HelpText<"Emit an error if a C++ static local initializer would need a guard variable">;
def no_implicit_float : Flag<["-"], "no-implicit-float">,
@@ -226,7 +247,7 @@ def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">,
def masm_verbose : Flag<["-"], "masm-verbose">,
HelpText<"Generate verbose assembly output">;
def mcode_model : Separate<["-"], "mcode-model">,
- HelpText<"The code model to use">;
+ HelpText<"The code model to use">, Values<"small,kernel,medium,large">;
def mdebug_pass : Separate<["-"], "mdebug-pass">,
HelpText<"Enable additional debug output">;
def mdisable_fp_elim : Flag<["-"], "mdisable-fp-elim">,
@@ -242,6 +263,8 @@ def menable_unsafe_fp_math : Flag<["-"], "menable-unsafe-fp-math">,
"precision">;
def mfloat_abi : Separate<["-"], "mfloat-abi">,
HelpText<"The float ABI to use">;
+def mtp : Separate<["-"], "mtp">,
+ HelpText<"Mode for reading thread pointer">;
def mlimit_float_precision : Separate<["-"], "mlimit-float-precision">,
HelpText<"Limit float precision to the given value">;
def split_stacks : Flag<["-"], "split-stacks">,
@@ -265,8 +288,6 @@ def vectorize_loops : Flag<["-"], "vectorize-loops">,
HelpText<"Run the Loop vectorization passes">;
def vectorize_slp : Flag<["-"], "vectorize-slp">,
HelpText<"Run the SLP vectorization passes">;
-def vectorize_slp_aggressive : Flag<["-"], "vectorize-slp-aggressive">,
- HelpText<"Run the BB vectorization passes">;
def dependent_lib : Joined<["--"], "dependent-lib=">,
HelpText<"Add dependent library">;
def linker_option : Joined<["--"], "linker-option=">,
@@ -291,15 +312,27 @@ def fsanitize_coverage_trace_gep
def fsanitize_coverage_8bit_counters
: Flag<["-"], "fsanitize-coverage-8bit-counters">,
HelpText<"Enable frequency counters in sanitizer coverage">;
+def fsanitize_coverage_inline_8bit_counters
+ : Flag<["-"], "fsanitize-coverage-inline-8bit-counters">,
+ HelpText<"Enable inline 8-bit counters in sanitizer coverage">;
+def fsanitize_coverage_pc_table
+ : Flag<["-"], "fsanitize-coverage-pc-table">,
+ HelpText<"Create a table of coverage-instrumented PCs">;
def fsanitize_coverage_trace_pc
: Flag<["-"], "fsanitize-coverage-trace-pc">,
HelpText<"Enable PC tracing in sanitizer coverage">;
def fsanitize_coverage_trace_pc_guard
: Flag<["-"], "fsanitize-coverage-trace-pc-guard">,
HelpText<"Enable PC tracing with guard in sanitizer coverage">;
+def fsanitize_coverage_no_prune
+ : Flag<["-"], "fsanitize-coverage-no-prune">,
+ HelpText<"Disable coverage pruning (i.e. instrument all blocks/edges)">;
+def fsanitize_coverage_stack_depth
+ : Flag<["-"], "fsanitize-coverage-stack-depth">,
+ HelpText<"Enable max stack depth tracing">;
def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">,
HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, "
- "or none">;
+ "or none">, Values<"none,clang,llvm">;
def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">,
HelpText<"Generate instrumented code to collect execution counts into "
"<file> (overridden by LLVM_PROFILE_FILE env var)">;
@@ -312,6 +345,12 @@ def flto_visibility_public_std:
def flto_unit: Flag<["-"], "flto-unit">,
HelpText<"Emit IR to support LTO unit features (CFI, whole program vtable opt)">;
def fno_lto_unit: Flag<["-"], "fno-lto-unit">;
+def fthin_link_bitcode_EQ : Joined<["-"], "fthin-link-bitcode=">,
+ HelpText<"Write minimized bitcode to <file> for the ThinLTO thin link only">;
+def fdebug_pass_manager : Flag<["-"], "fdebug-pass-manager">,
+ HelpText<"Prints debug information for the new pass manager">;
+def fno_debug_pass_manager : Flag<["-"], "fno-debug-pass-manager">,
+ HelpText<"Disables debug printing for the new pass manager">;
//===----------------------------------------------------------------------===//
// Dependency Output Options
@@ -337,9 +376,9 @@ def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">,
HelpText<"File for serializing diagnostics in a binary format">;
def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">,
- HelpText<"Change diagnostic formatting to match IDE and command line tools">;
+ HelpText<"Change diagnostic formatting to match IDE and command line tools">, Values<"clang,msvc,msvc-fallback,vi">;
def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">,
- HelpText<"Print diagnostic category">;
+ HelpText<"Print diagnostic category">, Values<"none,id,name">;
def fno_diagnostics_use_presumed_location : Flag<["-"], "fno-diagnostics-use-presumed-location">,
HelpText<"Ignore #line directives when displaying diagnostic locations">;
def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"<N>">,
@@ -354,6 +393,9 @@ def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">,
HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">;
def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of times to perform spell checking on unrecognized identifiers (0 = no limit).">;
+def fcaret_diagnostics_max_lines :
+ Separate<["-"], "fcaret-diagnostics-max-lines">, MetaVarName<"<N>">,
+ HelpText<"Set the maximum number of source lines to show in a caret diagnostic">;
def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
def verify : Flag<["-"], "verify">,
@@ -434,10 +476,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 fmodule_codegen :
+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'.">;
@@ -550,6 +596,9 @@ def find_pch_source_EQ : Joined<["-"], "find-pch-source=">,
def fno_pch_timestamp : Flag<["-"], "fno-pch-timestamp">,
HelpText<"Disable inclusion of timestamp in precompiled headers">;
+def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">,
+ HelpText<"Aligned allocation/deallocation functions are unavailable">;
+
//===----------------------------------------------------------------------===//
// Language Options
//===----------------------------------------------------------------------===//
@@ -567,6 +616,8 @@ def fblocks_runtime_optional : Flag<["-"], "fblocks-runtime-optional">,
HelpText<"Weakly link in the blocks runtime">;
def fexternc_nounwind : Flag<["-"], "fexternc-nounwind">,
HelpText<"Assume all functions with C linkage do not unwind">;
+def enable_split_dwarf : Flag<["-"], "enable-split-dwarf">,
+ HelpText<"Use split dwarf/Fission">;
def split_dwarf_file : Separate<["-"], "split-dwarf-file">,
HelpText<"File name to use for split dwarf debug info output">;
def fno_wchar : Flag<["-"], "fno-wchar">,
@@ -575,11 +626,11 @@ def fconstant_string_class : Separate<["-"], "fconstant-string-class">,
MetaVarName<"<class name>">,
HelpText<"Specify the class to use for constant Objective-C string objects.">;
def fobjc_arc_cxxlib_EQ : Joined<["-"], "fobjc-arc-cxxlib=">,
- HelpText<"Objective-C++ Automatic Reference Counting standard library kind">;
+ HelpText<"Objective-C++ Automatic Reference Counting standard library kind">, Values<"libc++,libstdc++,none">;
def fobjc_runtime_has_weak : Flag<["-"], "fobjc-runtime-has-weak">,
HelpText<"The target Objective-C runtime supports ARC weak operations">;
def fobjc_dispatch_method_EQ : Joined<["-"], "fobjc-dispatch-method=">,
- HelpText<"Objective-C dispatch method to use">;
+ HelpText<"Objective-C dispatch method to use">, Values<"legacy,non-legacy,mixed">;
def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-default-synthesize-properties">,
HelpText<"disable the default synthesis of Objective-C properties">;
def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">,
@@ -653,9 +704,17 @@ def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and
def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">,
HelpText<"Allow function arguments and returns of type half">;
def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">,
- HelpText<"Set default MS calling convention">;
+ HelpText<"Set default MS calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall">;
def finclude_default_header : Flag<["-"], "finclude-default-header">,
HelpText<"Include the default header file for OpenCL">;
+def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">,
+ HelpText<"Preserve 3-component vector type">;
+def fwchar_type_EQ : Joined<["-"], "fwchar-type=">,
+ HelpText<"Select underlying type for wchar_t">, Values<"char,short,int">;
+def fsigned_wchar : Flag<["-"], "fsigned-wchar">,
+ HelpText<"Use a signed type for wchar_t">;
+def fno_signed_wchar : Flag<["-"], "fno-signed-wchar">,
+ HelpText<"Use an unsigned type for wchar_t">;
// FIXME: Remove these entirely once functionality/tests have been excised.
def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>,
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index 9b6ab3a5ef..aebb36ed0e 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -61,6 +61,14 @@ def _SLASH_Brepro_ : CLFlag<"Brepro-">,
def _SLASH_C : CLFlag<"C">,
HelpText<"Don't discard comments when preprocessing">, Alias<C>;
def _SLASH_c : CLFlag<"c">, HelpText<"Compile only">, Alias<c>;
+def _SLASH_d1reportAllClassLayout : CLFlag<"d1reportAllClassLayout">,
+ HelpText<"Dump record layout information">, Alias<fdump_record_layouts>;
+def _SLASH_diagnostics_caret : CLFlag<"diagnostics:caret">,
+ HelpText<"Enable caret and column diagnostics (on by default)">;
+def _SLASH_diagnostics_column : CLFlag<"diagnostics:column">,
+ HelpText<"Disable caret diagnostics but keep column info">;
+def _SLASH_diagnostics_classic : CLFlag<"diagnostics:classic">,
+ HelpText<"Disable column and caret diagnostics">;
def _SLASH_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">,
MetaVarName<"<macro[=value]>">, Alias<D>;
def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>;
@@ -172,6 +180,12 @@ def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">,
HelpText<"Enable trigraphs">, Alias<ftrigraphs>;
def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">,
HelpText<"Disable trigraphs (default)">, Alias<fno_trigraphs>;
+def _SLASH_Zc_twoPhase : CLFlag<"Zc:twoPhase">,
+ HelpText<"Enable two-phase name lookup in templates">,
+ Alias<fno_delayed_template_parsing>;
+def _SLASH_Zc_twoPhase_ : CLFlag<"Zc:twoPhase-">,
+ HelpText<"Disable two-phase name lookup in templates">,
+ Alias<fdelayed_template_parsing>;
def _SLASH_Z7 : CLFlag<"Z7">,
HelpText<"Enable CodeView debug information in object files">;
def _SLASH_Zd : CLFlag<"Zd">,
@@ -316,6 +330,7 @@ def _SLASH_Zc_forScope : CLIgnoredFlag<"Zc:forScope">;
def _SLASH_Zc_inline : CLIgnoredFlag<"Zc:inline">;
def _SLASH_Zc_rvalueCast : CLIgnoredFlag<"Zc:rvalueCast">;
def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">;
+def _SLASH_Zc_ternary : CLIgnoredFlag<"Zc:ternary">;
def _SLASH_Zm : CLIgnoredJoined<"Zm">;
def _SLASH_Zo : CLIgnoredFlag<"Zo">;
def _SLASH_Zo_ : CLIgnoredFlag<"Zo-">;
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 114e0b33c7..89c0def6c5 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -99,16 +99,19 @@ class Compilation {
/// only be removed if we crash.
ArgStringMap FailureResultFiles;
- /// Redirection for stdout, stderr, etc.
- const StringRef **Redirects;
+ /// Optional redirection for stdin, stdout, stderr.
+ std::vector<Optional<StringRef>> Redirects;
/// Whether we're compiling for diagnostic purposes.
bool ForDiagnostics;
+ /// Whether an error during the parsing of the input args.
+ bool ContainsError;
+
public:
Compilation(const Driver &D, const ToolChain &DefaultToolChain,
llvm::opt::InputArgList *Args,
- llvm::opt::DerivedArgList *TranslatedArgs);
+ llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError);
~Compilation();
const Driver &getDriver() const { return TheDriver; }
@@ -275,14 +278,15 @@ public:
/// Return true if we're compiling for diagnostics.
bool isForDiagnostics() const { return ForDiagnostics; }
+ /// Return whether an error during the parsing of the input args.
+ bool containsError() const { return ContainsError; }
+
/// Redirect - Redirect output of this compilation. Can only be done once.
///
- /// \param Redirects - array of pointers to paths. The array
- /// should have a size of three. The inferior process's
- /// stdin(0), stdout(1), and stderr(2) will be redirected to the
- /// corresponding paths. This compilation instance becomes
- /// the owner of Redirects and will delete the array and StringRef's.
- void Redirect(const StringRef** Redirects);
+ /// \param Redirects - array of optional paths. The array should have a size
+ /// of three. The inferior process's stdin(0), stdout(1), and stderr(2) will
+ /// be redirected to the corresponding paths, if provided (not llvm::None).
+ void Redirect(ArrayRef<Optional<StringRef>> Redirects);
};
} // end namespace driver
diff --git a/include/clang/Driver/Distro.h b/include/clang/Driver/Distro.h
index e2fb8b6433..eeb4f25f34 100644
--- a/include/clang/Driver/Distro.h
+++ b/include/clang/Driver/Distro.h
@@ -32,6 +32,7 @@ public:
DebianWheezy,
DebianJessie,
DebianStretch,
+ DebianBuster,
Exherbo,
RHEL5,
RHEL6,
@@ -57,6 +58,8 @@ public:
UbuntuXenial,
UbuntuYakkety,
UbuntuZesty,
+ UbuntuArtful,
+ UbuntuBionic,
UnknownDistro
};
@@ -106,13 +109,13 @@ public:
}
bool IsDebian() const {
- return DistroVal >= DebianLenny && DistroVal <= DebianStretch;
+ return DistroVal >= DebianLenny && DistroVal <= DebianBuster;
}
bool IsUbuntu() const {
- return DistroVal >= UbuntuHardy && DistroVal <= UbuntuZesty;
+ return DistroVal >= UbuntuHardy && DistroVal <= UbuntuBionic;
}
-
+
/// @}
};
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index e653c7ca95..a3662872a9 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -129,6 +129,9 @@ public:
/// The original path to the clang executable.
std::string ClangExecutable;
+ /// Target and driver mode components extracted from clang executable name.
+ ParsedClangName ClangNameParts;
+
/// The path to the installed clang directory, if any.
std::string InstalledDir;
@@ -148,9 +151,6 @@ public:
/// Dynamic loader prefix, if present
std::string DyldPrefix;
- /// If the standard library is used
- bool UseStdLib;
-
/// Driver title to use with help.
std::string DriverTitle;
@@ -216,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;
@@ -282,6 +287,8 @@ public:
void setCheckInputsExist(bool Value) { CheckInputsExist = Value; }
+ void setTargetAndMode(const ParsedClangName &TM) { ClangNameParts = TM; }
+
const std::string &getTitle() { return DriverTitle; }
void setTitle(std::string Value) { DriverTitle = std::move(Value); }
@@ -336,7 +343,8 @@ public:
/// ParseArgStrings - Parse the given list of strings into an
/// ArgList.
- llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args);
+ llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args,
+ bool &ContainsError);
/// BuildInputs - Construct the list of inputs and their types from
/// the given arguments.
@@ -417,6 +425,10 @@ public:
// FIXME: This should be in CompilationInfo.
std::string GetProgramPath(StringRef Name, const ToolChain &TC) const;
+ /// handleAutocompletions - Handle --autocomplete by searching and printing
+ /// possible flags, descriptions, and its arguments.
+ void handleAutocompletions(StringRef PassedFlags) const;
+
/// HandleImmediateArgs - Handle any arguments which should be
/// treated before building actions or binding tools.
///
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 54bed09e0a..b74b3b4b35 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,
@@ -93,8 +97,8 @@ public:
virtual void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
CrashReportInfo *CrashInfo = nullptr) const;
- virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
- bool *ExecutionFailed) const;
+ virtual int Execute(ArrayRef<Optional<StringRef>> Redirects,
+ std::string *ErrMsg, bool *ExecutionFailed) const;
/// getSource - Return the Action which caused the creation of this job.
const Action &getSource() const { return Source; }
@@ -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; }
@@ -131,7 +141,7 @@ public:
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
CrashReportInfo *CrashInfo = nullptr) const override;
- int Execute(const StringRef **Redirects, std::string *ErrMsg,
+ int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const override;
private:
@@ -148,7 +158,7 @@ public:
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
CrashReportInfo *CrashInfo = nullptr) const override;
- int Execute(const StringRef **Redirects, std::string *ErrMsg,
+ int Execute(ArrayRef<Optional<StringRef>> Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const override;
};
diff --git a/include/clang/Driver/Multilib.h b/include/clang/Driver/Multilib.h
index 0419186b74..36d2493b1a 100644
--- a/include/clang/Driver/Multilib.h
+++ b/include/clang/Driver/Multilib.h
@@ -70,13 +70,21 @@ public:
/// All elements begin with either '+' or '-'
const flags_list &flags() const { return Flags; }
flags_list &flags() { return Flags; }
+
/// Add a flag to the flags list
+ /// \p Flag must be a flag accepted by the driver with its leading '-' removed,
+ /// and replaced with either:
+ /// '-' which contraindicates using this multilib with that flag
+ /// or:
+ /// '+' which promotes using this multilib in the presence of that flag
+ /// otherwise '-print-multi-lib' will not emit them correctly.
Multilib &flag(StringRef F) {
assert(F.front() == '+' || F.front() == '-');
Flags.push_back(F);
return *this;
}
+ LLVM_DUMP_METHOD void dump() const;
/// \brief print summary of the Multilib
void print(raw_ostream &OS) const;
@@ -150,6 +158,7 @@ public:
unsigned size() const { return Multilibs.size(); }
+ LLVM_DUMP_METHOD void dump() const;
void print(raw_ostream &OS) const;
MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) {
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index 57e4452f3e..2da3cb4828 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -39,8 +39,9 @@ enum ClangFlags {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) OPT_##ID,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
#include "clang/Driver/Options.inc"
LastOption
#undef OPTION
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 7952b33fd5..e3476c721a 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -139,6 +139,10 @@ 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">;
+// The features added by this group will not be added to target features.
+// These are explicitly handled.
+def m_hexagon_Features_HVX_Group : OptionGroup<"<hexagon features group>">,
+ Group<m_Group>, DocName<"Hexagon">;
def m_ppc_Features_Group : OptionGroup<"<ppc features group>">,
Group<m_Group>, DocName<"PowerPC">;
def m_wasm_Features_Group : OptionGroup<"<wasm features group>">,
@@ -194,6 +198,16 @@ def clang_ignored_f_Group : OptionGroup<"<clang ignored f group>">,
def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">,
Group<m_Group>, Flags<[Ignored]>;
+// Group for clang options in the process of deprecation.
+// Please include the version that deprecated the flag as comment to allow
+// easier garbage collection.
+def clang_ignored_legacy_options_Group : OptionGroup<"<clang legacy flags>">,
+ Group<f_Group>, Flags<[Ignored]>;
+
+// Retired with clang-5.0
+def : Flag<["-"], "fslp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>;
+def : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>;
+
// Group that ignores all gcc optimizations that won't be implemented
def clang_ignored_gcc_optimization_f_Group : OptionGroup<
"<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>, Flags<[Ignored]>;
@@ -265,6 +279,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">;
@@ -400,11 +416,11 @@ def R_Joined : Joined<["-"], "R">, Group<R_Group>, Flags<[CC1Option, CoreOption]
def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
HelpText<"Only run preprocess and compilation steps">;
def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>,
- MetaVarName<"<addr">, HelpText<"Set starting address of BSS to <addr>">;
+ 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>">;
+ 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>">;
+ 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>,
@@ -447,6 +463,10 @@ def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">,
HelpText<"Pass <arg> to fatbinary invocation">, MetaVarName<"<arg>">;
def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">,
HelpText<"Pass <arg> to the ptxas assembler">, MetaVarName<"<arg>">;
+def Xopenmp_target : Separate<["-"], "Xopenmp-target">,
+ HelpText<"Pass <arg> to the target offloading toolchain.">, MetaVarName<"<arg>">;
+def Xopenmp_target_EQ : JoinedAndSeparate<["-"], "Xopenmp-target=">,
+ HelpText<"Pass <arg> to the specified target offloading toolchain. The triple that identifies the toolchain must be provided after the equals sign.">, MetaVarName<"<arg>">;
def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">,
Group<Link_Group>;
@@ -467,6 +487,7 @@ def arch__errors__fatal : Flag<["-"], "arch_errors_fatal">;
def arch : Separate<["-"], "arch">, Flags<[DriverOption]>;
def arch__only : Separate<["-"], "arch_only">;
def a : Joined<["-"], "a">;
+def autocomplete : Joined<["--"], "autocomplete=">;
def bind__at__load : Flag<["-"], "bind_at_load">;
def bundle__loader : Separate<["-"], "bundle_loader">;
def bundle : Flag<["-"], "bundle">;
@@ -490,7 +511,7 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group<opencl_Group>, Flags<[CC
def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group<opencl_Group>, Flags<[CC1Option]>,
HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">;
def cl_std_EQ : Joined<["-"], "cl-std=">, Group<opencl_Group>, Flags<[CC1Option]>,
- HelpText<"OpenCL language standard to compile for.">;
+ HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0">;
def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group<opencl_Group>, Flags<[CC1Option]>,
HelpText<"OpenCL only. Allow denormals to be flushed to zero.">;
def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group<opencl_Group>, Flags<[CC1Option]>,
@@ -575,7 +596,9 @@ def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]>
HelpText<"Use Apple's kernel extensions ABI">;
def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable Apple gcc-compatible #pragma pack handling">;
-def shared_libasan : Flag<["-"], "shared-libasan">;
+def shared_libsan : Flag<["-"], "shared-libsan">;
+def static_libsan : Flag<["-"], "static-libsan">;
+def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>;
def fasm : Flag<["-"], "fasm">, Group<f_Group>;
def fasm_blocks : Flag<["-"], "fasm-blocks">, Group<f_Group>, Flags<[CC1Option]>;
@@ -587,6 +610,13 @@ def fastf : Flag<["-"], "fastf">, Group<f_Group>;
def fast : Flag<["-"], "fast">, Group<f_Group>;
def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Group<f_Group>;
+def fdouble_square_bracket_attributes : Flag<[ "-" ], "fdouble-square-bracket-attributes">,
+ Group<f_Group>, Flags<[DriverOption, CC1Option]>,
+ HelpText<"Enable '[[]]' attributes in all C and C++ language modes">;
+def fno_double_square_bracket_attributes : Flag<[ "-" ], "fno-double-square-bracket-attributes">,
+ Group<f_Group>, Flags<[DriverOption, CC1Option]>,
+ HelpText<"Disable '[[]]' attributes in all C and C++ language modes">;
+
def fautolink : Flag <["-"], "fautolink">, Group<f_Group>;
def fno_autolink : Flag <["-"], "fno-autolink">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>,
@@ -613,11 +643,32 @@ 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 fprofile_sample_accurate : Flag<["-"], "fprofile-sample-accurate">,
+ Group<f_Group>, Flags<[DriverOption, CC1Option]>,
+ HelpText<"Specifies that the sample profile is accurate">,
+ DocBrief<[{Specifies that the sample profile is accurate. If the sample
+ profile is accurate, callsites without profile samples are marked
+ as cold. Otherwise, treat callsites without profile samples as if
+ we have no profile}]>;
+def fno_profile_sample_accurate : Flag<["-"], "fno-profile-sample-accurate">,
+ Group<f_Group>, Flags<[DriverOption]>;
+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 fauto_profile_accurate : Flag<["-"], "fauto-profile-accurate">,
+ Group<f_Group>, Alias<fprofile_sample_accurate>;
+def fno_auto_profile_accurate : Flag<["-"], "fno-auto-profile-accurate">,
+ Group<f_Group>, Alias<fno_profile_sample_accurate>;
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.">;
@@ -673,6 +724,9 @@ def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>;
def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>,
Flags<[DriverOption]>, HelpText<"Load the clang builtins module map file.">;
def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>;
+def fclang_abi_compat_EQ : Joined<["-"], "fclang-abi-compat=">, Group<f_clang_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<version>">, Values<"<major>.<minor>,latest">,
+ HelpText<"Attempt to match the ABI of Clang <version>">;
def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>,
Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">;
@@ -693,7 +747,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]>;
@@ -711,6 +766,9 @@ def fdiagnostics_print_source_range_info : Flag<["-"], "fdiagnostics-print-sourc
HelpText<"Print source range spans in numeric form">;
def fdiagnostics_show_hotness : Flag<["-"], "fdiagnostics-show-hotness">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Enable profile hotness information in diagnostic line">;
+def fdiagnostics_hotness_threshold_EQ : Joined<["-"], "fdiagnostics-hotness-threshold=">,
+ Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">,
+ HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count">;
def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Print option name with mappable diagnostics">;
def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">,
@@ -767,106 +825,133 @@ def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
def fjump_tables : Flag<["-"], "fjump-tables">, Group<f_Group>;
def fno_jump_tables : Flag<["-"], "fno-jump-tables">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Do not use jump tables for lowering switches">;
+
+// Begin sanitizer flags. These should all be core options exposed in all driver
+// modes.
+let Flags = [CC1Option, CoreOption] in {
+
def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">,
+ MetaVarName<"<check>">,
HelpText<"Turn on runtime checks for various forms of undefined "
"or suspicious behavior. See user manual for available checks">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
- Flags<[CoreOption]>;
+ Flags<[CoreOption, DriverOption]>;
def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
- Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>,
+ Group<f_clang_Group>,
HelpText<"Path to blacklist file for sanitizers">;
def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">,
Group<f_clang_Group>,
HelpText<"Don't use blacklist file for sanitizers">;
def fsanitize_coverage
: CommaJoined<["-"], "fsanitize-coverage=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>,
HelpText<"Specify the type of coverage instrumentation for Sanitizers">;
def fno_sanitize_coverage
: CommaJoined<["-"], "fno-sanitize-coverage=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>,
HelpText<"Disable specified features of coverage instrumentation for "
- "Sanitizers">;
+ "Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters">;
def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable origins tracking in MemorySanitizer">;
def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable origins tracking in MemorySanitizer">;
def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable origins tracking in MemorySanitizer">;
def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable use-after-destroy detection in MemorySanitizer">;
+def fno_sanitize_memory_use_after_dtor : Flag<["-"], "fno-sanitize-memory-use-after-dtor">,
+ Group<f_clang_Group>,
+ HelpText<"Disable use-after-destroy detection in MemorySanitizer">;
def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Level of field padding for AddressSanitizer">;
def fsanitize_address_use_after_scope : Flag<["-"], "fsanitize-address-use-after-scope">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable use-after-scope detection in AddressSanitizer">;
def fno_sanitize_address_use_after_scope : Flag<["-"], "fno-sanitize-address-use-after-scope">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable use-after-scope detection in AddressSanitizer">;
-def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>,
- Flags<[CoreOption]>;
+def fsanitize_address_globals_dead_stripping : Flag<["-"], "fsanitize-address-globals-dead-stripping">,
+ Group<f_clang_Group>,
+ HelpText<"Enable linker dead stripping of globals in AddressSanitizer">;
+def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>;
def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">,
- Group<f_clang_Group>, Flags<[CoreOption]>;
+ Flags<[CoreOption, DriverOption]>,
+ Group<f_clang_Group>;
def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">,
Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>,
HelpText<"Enable recovery for specified sanitizers">;
def fno_sanitize_recover_EQ
: CommaJoined<["-"], "fno-sanitize-recover=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable recovery for specified sanitizers">;
def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>,
HelpText<"Enable trapping for specified sanitizers">;
def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
- Flags<[CoreOption]>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable trapping for specified sanitizers">;
def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">,
Group<f_clang_Group>;
def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">,
Group<f_clang_Group>;
+def fsanitize_minimal_runtime : Flag<["-"], "fsanitize-minimal-runtime">,
+ Group<f_clang_Group>;
+def fno_sanitize_minimal_runtime : Flag<["-"], "fno-sanitize-minimal-runtime">,
+ Group<f_clang_Group>;
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_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-generalize-pointers">,
+ Group<f_clang_Group>,
+ HelpText<"Generalize pointers in CFI indirect call type signature checks">;
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">,
@@ -894,7 +979,7 @@ def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>, Flags<[CC1Op
def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group<f_Group>, Flags<[CC1Option]>;
def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)"
- " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">;
+ " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">, Values<"fast,on,off">;
def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>;
def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>;
@@ -903,6 +988,10 @@ def frewrite_includes : Flag<["-"], "frewrite-includes">, Group<f_Group>,
Flags<[CC1Option]>;
def fno_rewrite_includes : Flag<["-"], "fno-rewrite-includes">, Group<f_Group>;
+def frewrite_imports : Flag<["-"], "frewrite-imports">, Group<f_Group>,
+ Flags<[CC1Option]>;
+def fno_rewrite_imports : Flag<["-"], "fno-rewrite-imports">, Group<f_Group>;
+
def frewrite_map_file : Separate<["-"], "frewrite-map-file">,
Group<f_Group>,
Flags<[ DriverOption, CC1Option ]>;
@@ -954,11 +1043,27 @@ 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 ffine_grained_bitfield_accesses : Flag<["-"],
+ "ffine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Use separate accesses for bitfields with legal widths and alignments.">;
+def fno_fine_grained_bitfield_accesses : Flag<["-"],
+ "fno-fine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Use large-integer access for consecutive bitfield runs.">;
+
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<[CoreOption, CC1Option]>, Group<f_Group>,
- HelpText<"Set LTO mode to either 'full' or 'thin'">;
+ HelpText<"Set LTO mode to either 'full' or 'thin'">, Values<"thin,full">;
def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group<f_Group>,
HelpText<"Enable LTO in 'full' mode">;
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>,
@@ -1046,8 +1151,8 @@ def fmodule_map_file : Joined<["-"], "fmodule-map-file=">,
Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">,
HelpText<"Load this module map file">;
def fmodule_file : Joined<["-"], "fmodule-file=">,
- Group<f_Group>, Flags<[DriverOption,CC1Option]>,
- HelpText<"Load this precompiled module file">, MetaVarName<"<file>">;
+ Group<i_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"[<name>=]<file>">,
+ HelpText<"Specify the mapping of module name to precompiled module file, or load a module file if name is omitted.">;
def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Ignore the definition of the given macro when building and loading modules">;
def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>,
@@ -1116,7 +1221,7 @@ def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-m
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Disables an experimental new pass manager in LLVM.">;
def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Use the given vector functions library">;
+ HelpText<"Use the given vector functions library">, Values<"Accelerate,SVML,none">;
def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>;
def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>,
@@ -1252,6 +1357,10 @@ def fopenmp_targets_EQ : CommaJoined<["-"], "fopenmp-targets=">, Flags<[DriverOp
HelpText<"Specify comma-separated list of triples OpenMP offloading targets to be supported">;
def fopenmp_dump_offload_linker_script : Flag<["-"], "fopenmp-dump-offload-linker-script">, Group<f_Group>,
Flags<[NoArgumentUnused]>;
+def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>,
+ HelpText<"OpenMP target code is compiled as relocatable using the -c flag. For OpenMP targets the code is relocatable by default.">;
+def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>,
+ HelpText<"Do not compile OpenMP target code as relocatable.">;
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
@@ -1294,13 +1403,13 @@ def frtti : Flag<["-"], "frtti">, Group<f_Group>;
def : Flag<["-"], "fsched-interblock">, Group<clang_ignored_f_Group>;
def fshort_enums : Flag<["-"], "fshort-enums">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">;
-def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, Flags<[CC1Option]>,
+def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>,
HelpText<"Force wchar_t to be a short unsigned int">;
-def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, Flags<[CC1Option]>,
+def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>,
HelpText<"Force wchar_t to be an unsigned int">;
def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Which overload candidates to show when overload resolution fails: "
- "best|all; defaults to all">;
+ "best|all; defaults to all">, Values<"best,all">;
def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>;
def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
@@ -1363,9 +1472,6 @@ def : Flag<["-"], "fno-tree-vectorize">, Alias<fno_vectorize>;
def fslp_vectorize : Flag<["-"], "fslp-vectorize">, Group<f_Group>,
HelpText<"Enable the superword-level parallelism vectorization passes">;
def fno_slp_vectorize : Flag<["-"], "fno-slp-vectorize">, Group<f_Group>;
-def fslp_vectorize_aggressive : Flag<["-"], "fslp-vectorize-aggressive">, Group<f_Group>,
- HelpText<"Enable the BB vectorization passes">;
-def fno_slp_vectorize_aggressive : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<f_Group>;
def : Flag<["-"], "ftree-slp-vectorize">, Alias<fslp_vectorize>;
def : Flag<["-"], "fno-tree-slp-vectorize">, Alias<fno_slp_vectorize>;
def Wlarge_by_value_copy_def : Flag<["-"], "Wlarge-by-value-copy">,
@@ -1414,7 +1520,7 @@ def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1
def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>;
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
- HelpText<"Set the default symbol visibility for all global declarations">;
+ HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">;
def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,
HelpText<"Give inline C++ member functions default visibility by default">,
Flags<[CC1Option]>;
@@ -1422,9 +1528,10 @@ def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group>
HelpText<"Give global types 'default' visibility and global functions and "
"variables 'hidden' visibility by default">;
def fwhole_program_vtables : Flag<["-"], "fwhole-program-vtables">, Group<f_Group>,
- Flags<[CC1Option]>,
+ Flags<[CoreOption, CC1Option]>,
HelpText<"Enables whole-program vtable optimization. Requires -flto">;
-def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>;
+def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>,
+ Flags<[CoreOption]>;
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,
@@ -1453,6 +1560,12 @@ def fstrict_return : Flag<["-"], "fstrict-return">, Group<f_Group>,
def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>,
Flags<[CC1Option]>;
+def fallow_editor_placeholders : Flag<["-"], "fallow-editor-placeholders">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Treat editor placeholders as valid source code">;
+def fno_allow_editor_placeholders : Flag<["-"],
+ "fno-allow-editor-placeholders">, Group<f_Group>;
+
def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">;
def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>,
@@ -1510,11 +1623,15 @@ def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>;
def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>, Flags<[CoreOption]>;
def gno_column_info : Flag<["-"], "gno-column-info">, Group<g_flags_Group>, Flags<[CoreOption]>;
def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>;
-def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>;
+def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>, Flags<[CC1Option]>;
def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>;
def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>,
HelpText<"Generate debug info with external references to clang modules"
" or precompiled headers">;
+def gz : Flag<["-"], "gz">, Group<g_flags_Group>,
+ HelpText<"DWARF debug sections compression type">;
+def gz_EQ : Joined<["-"], "gz=">, Group<g_flags_Group>,
+ HelpText<"DWARF debug sections compression type">;
def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>,
HelpText<"Display available options">;
@@ -1579,8 +1696,6 @@ def m16 : Flag<["-"], "m16">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def mqdsp6_compat : Flag<["-"], "mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,CC1Option]>,
HelpText<"Enable hexagon-qdsp6 backward compatibility">;
-def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>;
-def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>;
def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def mx32 : Flag<["-"], "mx32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>;
@@ -1599,19 +1714,23 @@ def mexecute_only : Flag<["-"], "mexecute-only">, Group<m_arm_Features_Group>,
HelpText<"Disallow generation of data access to code sections (ARM only)">;
def mno_execute_only : Flag<["-"], "mno-execute-only">, Group<m_arm_Features_Group>,
HelpText<"Allow generation of data access to code sections (ARM only)">;
+def mtp_mode_EQ : Joined<["-"], "mtp=">, Group<m_arm_Features_Group>, Values<"soft, cp15">,
+ HelpText<"Read thread pointer from coprocessor register (ARM only)">;
def mpure_code : Flag<["-"], "mpure-code">, Alias<mexecute_only>; // Alias for GCC compatibility
def mno_pure_code : Flag<["-"], "mno-pure-code">, Alias<mno_execute_only>;
def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>;
def mappletvos_version_min_EQ : Joined<["-"], "mappletvos-version-min=">, Alias<mtvos_version_min_EQ>;
-def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">, Alias<mtvos_version_min_EQ>;
-def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_version_min_EQ>;
+def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">;
+def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_simulator_version_min_EQ>;
def mwatchos_version_min_EQ : Joined<["-"], "mwatchos-version-min=">, Group<m_Group>;
-def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">, Alias<mwatchos_version_min_EQ>;
-def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_version_min_EQ>;
+def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">;
+def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_simulator_version_min_EQ>;
def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>;
def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
def mimplicit_it_EQ : Joined<["-"], "mimplicit-it=">, Group<m_Group>;
+def mdefault_build_attributes : Joined<["-"], "mdefault-build-attributes">, Group<m_Group>;
+def mno_default_build_attributes : Joined<["-"], "mno-default-build-attributes">, Group<m_Group>;
def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>;
def mconsole : Joined<["-"], "mconsole">, Group<m_Group>, Flags<[DriverOption]>;
def mwindows : Joined<["-"], "mwindows">, Group<m_Group>, Flags<[DriverOption]>;
@@ -1619,6 +1738,7 @@ def mdll : Joined<["-"], "mdll">, Group<m_Group>, Flags<[DriverOption]>;
def municode : Joined<["-"], "municode">, Group<m_Group>, Flags<[DriverOption]>;
def mthreads : Joined<["-"], "mthreads">, Group<m_Group>, Flags<[DriverOption]>;
def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>;
+def mmcu_EQ : Joined<["-"], "mmcu=">, Group<m_Group>;
def mdynamic_no_pic : Joined<["-"], "mdynamic-no-pic">, Group<m_Group>;
def mfix_and_continue : Flag<["-"], "mfix-and-continue">, Group<clang_ignored_m_Group>;
def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>;
@@ -1626,7 +1746,7 @@ def minline_all_stringops : Flag<["-"], "minline-all-stringops">, Group<clang_ig
def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group<clang_ignored_m_Group>;
def malign_double : Flag<["-"], "malign-double">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Align doubles to two words in structs (x86 only)">;
-def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>;
+def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>, Values<"soft,softfp,hard">;
def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>;
def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>;
def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>;
@@ -1636,8 +1756,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]>;
@@ -1645,6 +1765,8 @@ def mllvm : Separate<["-"], "mllvm">, Flags<[CC1Option,CC1AsOption,CoreOption]>,
HelpText<"Additional arguments to forward to LLVM's option processing">;
def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">,
Group<m_Group>, HelpText<"Set Mac OS X deployment target">;
+def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
+ Group<m_Group>, Alias<mmacosx_version_min_EQ>;
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">;
def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>,
@@ -1656,17 +1778,13 @@ def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags
def mstack_probe_size : Joined<["-"], "mstack-probe-size=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the stack probe size">;
def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>,
- HelpText<"The thread model to use, e.g. posix, single (posix by default)">;
+ HelpText<"The thread model to use, e.g. posix, single (posix by default)">, Values<"posix,single">;
def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>,
- HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">;
+ HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">, Values<"default,4,5,gnu">;
-def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>;
-def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>;
-def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>;
def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>;
def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Disable merging of globals">;
-def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>;
def mno_pascal_strings : Flag<["-"], "mno-pascal-strings">,
Alias<fno_pascal_strings>;
def mno_red_zone : Flag<["-"], "mno-red-zone">, Group<m_Group>;
@@ -1674,63 +1792,6 @@ def mno_relax_all : Flag<["-"], "mno-relax-all">, Group<m_Group>;
def mno_rtd: Flag<["-"], "mno-rtd">, Group<m_Group>;
def mno_soft_float : Flag<["-"], "mno-soft-float">, Group<m_Group>;
def mno_stackrealign : Flag<["-"], "mno-stackrealign">, Group<m_Group>;
-def mno_x87 : Flag<["-"], "mno-x87">, Group<m_x86_Features_Group>;
-def mno_80387 : Flag<["-"], "mno-80387">, Alias<mno_x87>;
-def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>;
-def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>;
-def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>;
-def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>;
-def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>;
-// -mno-sse4 turns off sse4.1 which has the effect of turning off everything
-// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on
-// everything earlier than 4.2.
-def mno_sse4 : Flag<["-"], "mno-sse4">, Alias<mno_sse4_1>;
-def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>;
-def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>;
-def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>;
-def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>;
-def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>;
-def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>;
-def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>;
-def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>;
-def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>;
-def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>;
-def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>;
-def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>;
-def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group<m_x86_Features_Group>;
-def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group<m_x86_Features_Group>;
-def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>;
-def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>;
-def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>;
-def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>;
-def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>;
-def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>;
-def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>;
-def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>;
-def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>;
-def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>;
-def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>;
-def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>;
-def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>;
-def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>;
-def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>;
-def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>;
-def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>;
-def mno_cx16 : Flag<["-"], "mno-cx16">, Group<m_x86_Features_Group>;
-def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>;
-def mno_xsave : Flag<["-"], "mno-xsave">, Group<m_x86_Features_Group>;
-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)">;
@@ -1752,6 +1813,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)">;
@@ -1774,6 +1837,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">,
@@ -1824,12 +1891,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>;
@@ -1874,62 +1935,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)">,
+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>;
-def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>;
-def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>;
-def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>;
-def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>;
-def msse4 : Flag<["-"], "msse4">, Alias<msse4_2>;
-def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>;
-def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>;
-def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>;
-def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>;
-def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>;
-def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>;
-def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>;
-def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>;
-def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>;
-def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>;
-def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>;
-def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>;
-def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group<m_x86_Features_Group>;
-def mavx512ifma : Flag<["-"], "mavx512ifma">, Group<m_x86_Features_Group>;
-def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>;
-def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>;
-def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>;
-def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>;
-def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>;
-def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>;
-def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>;
-def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>;
-def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>;
-def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>;
-def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>;
-def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>;
-def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
-def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>;
-def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>;
-def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>;
-def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>;
-def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>;
-def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>;
-def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>;
-def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>;
-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>;
@@ -1942,21 +1949,56 @@ def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, Group<m_Group>;
def mno_check_zero_division : Flag<["-"], "mno-check-zero-division">,
Group<m_Group>;
def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">, Group<m_Group>;
+def mbranch_likely : Flag<["-"], "mbranch-likely">, Group<m_Group>,
+ IgnoredGCCCompat;
+def mno_branch_likely : Flag<["-"], "mno-branch-likely">, Group<m_Group>,
+ IgnoredGCCCompat;
def mdsp : Flag<["-"], "mdsp">, Group<m_Group>;
def mno_dsp : Flag<["-"], "mno-dsp">, Group<m_Group>;
def mdspr2 : Flag<["-"], "mdspr2">, Group<m_Group>;
def mno_dspr2 : Flag<["-"], "mno-dspr2">, Group<m_Group>;
def msingle_float : Flag<["-"], "msingle-float">, Group<m_Group>;
def mdouble_float : Flag<["-"], "mdouble-float">, Group<m_Group>;
+def mmadd4 : Flag<["-"], "mmadd4">, Group<m_Group>,
+ HelpText<"Enable the generation of 4-operand madd.s, madd.d and related instructions.">;
+def mno_madd4 : Flag<["-"], "mno-madd4">, Group<m_Group>,
+ HelpText<"Disable the generation of 4-operand madd.s, madd.d and related instructions.">;
def mmsa : Flag<["-"], "mmsa">, Group<m_Group>,
HelpText<"Enable MSA ASE (MIPS only)">;
def mno_msa : Flag<["-"], "mno-msa">, Group<m_Group>,
HelpText<"Disable MSA ASE (MIPS only)">;
+def mmt : Flag<["-"], "mmt">, Group<m_Group>,
+ HelpText<"Enable MT ASE (MIPS only)">;
+def mno_mt : Flag<["-"], "mno-mt">, Group<m_Group>,
+ HelpText<"Disable MT ASE (MIPS only)">;
def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>,
HelpText<"Use 64-bit floating point registers (MIPS only)">;
def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>,
HelpText<"Use 32-bit floating point registers (MIPS only)">;
+def mgpopt : Flag<["-"], "mgpopt">, Group<m_Group>,
+ HelpText<"Use GP relative accesses for symbols known to be in a small"
+ " data section (MIPS)">;
+def mno_gpopt : Flag<["-"], "mno-gpopt">, Group<m_Group>,
+ HelpText<"Do not use GP relative accesses for symbols known to be in a small"
+ " data section (MIPS)">;
+def mlocal_sdata : Flag<["-"], "mlocal-sdata">, Group<m_Group>,
+ HelpText<"Extend the -G behaviour to object local data (MIPS)">;
+def mno_local_sdata : Flag<["-"], "mno-local-sdata">, Group<m_Group>,
+ HelpText<"Do not extend the -G behaviour to object local data (MIPS)">;
+def mextern_sdata : Flag<["-"], "mextern-sdata">, Group<m_Group>,
+ HelpText<"Assume that externally defined data is in the small data if it"
+ " meets the -G <size> threshold (MIPS)">;
+def mno_extern_sdata : Flag<["-"], "mno-extern-sdata">, Group<m_Group>,
+ HelpText<"Do not assume that externally defined data is in the small data if"
+ " it meets the -G <size> threshold (MIPS)">;
+def membedded_data : Flag<["-"], "membedded-data">, Group<m_Group>,
+ HelpText<"Place constants in the .rodata section instead of the .sdata "
+ "section even if they meet the -G <size> threshold (MIPS)">;
+def mno_embedded_data : Flag<["-"], "mno-embedded-data">, Group<m_Group>,
+ HelpText<"Do not place constants in the .rodata section instead of the "
+ ".sdata if they meet the -G <size> threshold (MIPS)">;
def mnan_EQ : Joined<["-"], "mnan=">, Group<m_Group>;
+def mabs_EQ : Joined<["-"], "mabs=">, Group<m_Group>;
def mabicalls : Flag<["-"], "mabicalls">, Group<m_Group>,
HelpText<"Enable SVR4-style position-independent code (Mips only)">;
def mno_abicalls : Flag<["-"], "mno-abicalls">, Group<m_Group>,
@@ -2031,7 +2073,7 @@ def no_cpp_precomp : Flag<["-"], "no-cpp-precomp">, Group<clang_ignored_f_Group>
def no_integrated_cpp : Flag<["-", "--"], "no-integrated-cpp">, Flags<[DriverOption]>;
def no_pedantic : Flag<["-", "--"], "no-pedantic">, Group<pedantic_Group>;
def no__dead__strip__inits__and__terms : Flag<["-"], "no_dead_strip_inits_and_terms">;
-def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option]>,
+def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option, CoreOption]>,
HelpText<"Disable builtin #include directories">;
def nocudainc : Flag<["-"], "nocudainc">;
def nocudalib : Flag<["-"], "nocudalib">;
@@ -2040,14 +2082,16 @@ def nofixprebinding : Flag<["-"], "nofixprebinding">;
def nolibc : Flag<["-"], "nolibc">;
def nomultidefs : Flag<["-"], "nomultidefs">;
def nopie : Flag<["-"], "nopie">;
+def no_pie : Flag<["-"], "no-pie">, Alias<nopie>;
def noprebind : Flag<["-"], "noprebind">;
def noseglinkedit : Flag<["-"], "noseglinkedit">;
def nostartfiles : Flag<["-"], "nostartfiles">;
-def nostdinc : Flag<["-"], "nostdinc">;
+def nostdinc : Flag<["-"], "nostdinc">, Flags<[CoreOption]>;
def nostdlibinc : Flag<["-"], "nostdlibinc">;
def nostdincxx : Flag<["-"], "nostdinc++">, Flags<[CC1Option]>,
HelpText<"Disable standard #include directories for the C++ standard library">;
def nostdlib : Flag<["-"], "nostdlib">;
+def nostdlibxx : Flag<["-"], "nostdlib++">;
def object : Flag<["-"], "object">;
def o : JoinedOrSeparate<["-"], "o">, Flags<[DriverOption, RenderAsInput, CC1Option, CC1AsOption]>,
HelpText<"Write output to <file>">, MetaVarName<"<file>">;
@@ -2074,6 +2118,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">;
@@ -2098,6 +2144,10 @@ def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[DriverOption, CoreO
def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>, Group<Link_Group>;
def rtlib_EQ : Joined<["-", "--"], "rtlib=">,
HelpText<"Compiler runtime library to use">;
+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]>,
@@ -2136,9 +2186,16 @@ def static_libstdcxx : Flag<["-"], "static-libstdc++">;
def static : Flag<["-", "--"], "static">, Flags<[NoArgumentUnused]>;
def std_default_EQ : Joined<["-"], "std-default=">;
def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>,
- Group<CompileOnly_Group>, HelpText<"Language standard to compile for">;
+ Group<CompileOnly_Group>, HelpText<"Language standard to compile for">,
+ ValuesCode<[{
+ const char *Values =
+ #define LANGSTANDARD(id, name, lang, desc, features) name ","
+ #define LANGSTANDARD_ALIAS(id, alias) alias ","
+ #include "clang/Frontend/LangStandards.def"
+ ;
+ }]>;
def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>,
- HelpText<"C++ standard library to use">;
+ HelpText<"C++ standard library to use">, Values<"libc++,libstdc++,platform">;
def sub__library : JoinedOrSeparate<["-"], "sub_library">;
def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">;
def system_header_prefix : Joined<["--"], "system-header-prefix=">,
@@ -2294,7 +2351,8 @@ def _rtlib : Separate<["--"], "rtlib">, Alias<rtlib_EQ>;
def _serialize_diags : Separate<["-", "--"], "serialize-diagnostics">, Flags<[DriverOption]>,
HelpText<"Serialize compiler diagnostics to a file">;
// We give --version different semantics from -version.
-def _version : Flag<["--"], "version">, Flags<[CC1Option]>;
+def _version : Flag<["--"], "version">, Flags<[CoreOption, CC1Option]>,
+ HelpText<"Print version information">;
def _signed_char : Flag<["--"], "signed-char">, Alias<fsigned_char>;
def _std : Separate<["--"], "std">, Alias<std_EQ>;
def _stdlib : Separate<["--"], "stdlib">, Alias<stdlib_EQ>;
@@ -2322,14 +2380,153 @@ 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 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>,
- Flags<[CC1Option]>, HelpText<"Disable Hexagon Vector eXtensions">;
-def mhexagon_hvx_double : Flag<["-"], "mhvx-double">, Group<m_hexagon_Features_Group>,
- Flags<[CC1Option]>, HelpText<"Enable Hexagon Double Vector eXtensions">;
-def mno_hexagon_hvx_double : Flag<["-"], "mno-hvx-double">, Group<m_hexagon_Features_Group>,
- Flags<[CC1Option]>, HelpText<"Disable Hexagon Double Vector eXtensions">;
+def mv62 : Flag<["-"], "mv62">, Group<m_hexagon_Features_Group>,
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv62"]>;
+def mhexagon_hvx : Flag<[ "-" ], "mhvx">,
+ Group<m_hexagon_Features_HVX_Group>,
+ HelpText<"Enable Hexagon Vector eXtensions">;
+def mhexagon_hvx_EQ : Joined<[ "-" ], "mhvx=">,
+ Group<m_hexagon_Features_HVX_Group>,
+ HelpText<"Enable Hexagon Vector eXtensions">;
+def mno_hexagon_hvx : Flag<[ "-" ], "mno-hvx">,
+ Group<m_hexagon_Features_HVX_Group>,
+ HelpText<"Disable Hexagon Vector eXtensions">;
+def mhexagon_hvx_length_EQ : Joined<[ "-" ], "mhvx-length=">,
+ Group<m_hexagon_Features_HVX_Group>,
+ HelpText<"Set Hexagon Vector Length">, Values<"64B,128B">;
+// hvx-double deprecrated flag.
+def mhexagon_hvx_double : Flag<[ "-" ], "mhvx-double">,
+ Group<m_hexagon_Features_HVX_Group>,
+ HelpText<"Enable Hexagon Double Vector eXtensions">;
+def mno_hexagon_hvx_double
+ : Flag<[ "-" ], "mno-hvx-double">,
+ Group<m_hexagon_Features_HVX_Group>,
+ HelpText<"Disable Hexagon Double Vector eXtensions">;
+
+
+// X86 feature flags
+def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>;
+def mno_x87 : Flag<["-"], "mno-x87">, Group<m_x86_Features_Group>;
+def m80387 : Flag<["-"], "m80387">, Alias<mx87>;
+def mno_80387 : Flag<["-"], "mno-80387">, Alias<mno_x87>;
+def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>;
+def mno_mmx : Flag<["-"], "mno-mmx">, Group<m_x86_Features_Group>;
+def m3dnow : Flag<["-"], "m3dnow">, Group<m_x86_Features_Group>;
+def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>;
+def m3dnowa : Flag<["-"], "m3dnowa">, Group<m_x86_Features_Group>;
+def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>;
+def msse : Flag<["-"], "msse">, Group<m_x86_Features_Group>;
+def mno_sse : Flag<["-"], "mno-sse">, Group<m_x86_Features_Group>;
+def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>;
+def mno_sse2 : Flag<["-"], "mno-sse2">, Group<m_x86_Features_Group>;
+def msse3 : Flag<["-"], "msse3">, Group<m_x86_Features_Group>;
+def mno_sse3 : Flag<["-"], "mno-sse3">, Group<m_x86_Features_Group>;
+def mssse3 : Flag<["-"], "mssse3">, Group<m_x86_Features_Group>;
+def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group<m_x86_Features_Group>;
+def msse4_1 : Flag<["-"], "msse4.1">, Group<m_x86_Features_Group>;
+def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group<m_x86_Features_Group>;
+def msse4_2 : Flag<["-"], "msse4.2">, Group<m_x86_Features_Group>;
+def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group<m_x86_Features_Group>;
+def msse4 : Flag<["-"], "msse4">, Alias<msse4_2>;
+// -mno-sse4 turns off sse4.1 which has the effect of turning off everything
+// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on
+// everything earlier than 4.2.
+def mno_sse4 : Flag<["-"], "mno-sse4">, Alias<mno_sse4_1>;
+def msse4a : Flag<["-"], "msse4a">, Group<m_x86_Features_Group>;
+def mno_sse4a : Flag<["-"], "mno-sse4a">, Group<m_x86_Features_Group>;
+def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>;
+def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>;
+def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>;
+def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>;
+def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>;
+def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>;
+def mavx512bw : Flag<["-"], "mavx512bw">, Group<m_x86_Features_Group>;
+def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group<m_x86_Features_Group>;
+def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>;
+def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>;
+def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>;
+def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>;
+def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>;
+def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>;
+def mavx512ifma : Flag<["-"], "mavx512ifma">, Group<m_x86_Features_Group>;
+def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group<m_x86_Features_Group>;
+def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>;
+def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>;
+def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group<m_x86_Features_Group>;
+def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group<m_x86_Features_Group>;
+def mavx512vl : Flag<["-"], "mavx512vl">, Group<m_x86_Features_Group>;
+def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group<m_x86_Features_Group>;
+def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group<m_x86_Features_Group>;
+def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group<m_x86_Features_Group>;
+def madx : Flag<["-"], "madx">, Group<m_x86_Features_Group>;
+def mno_adx : Flag<["-"], "mno-adx">, Group<m_x86_Features_Group>;
+def maes : Flag<["-"], "maes">, Group<m_x86_Features_Group>;
+def mno_aes : Flag<["-"], "mno-aes">, Group<m_x86_Features_Group>;
+def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>;
+def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>;
+def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>;
+def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>;
+def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>;
+def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>;
+def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>;
+def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>;
+def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>;
+def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>;
+def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>;
+def mno_cx16 : Flag<["-"], "mno-cx16">, Group<m_x86_Features_Group>;
+def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>;
+def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>;
+def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>;
+def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>;
+def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>;
+def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>;
+def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>;
+def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>;
+def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>;
+def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>;
+def mlwp : Flag<["-"], "mlwp">, Group<m_x86_Features_Group>;
+def mno_lwp : Flag<["-"], "mno-lwp">, Group<m_x86_Features_Group>;
+def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>;
+def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>;
+def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>;
+def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>;
+def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>;
+def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>;
+def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>;
+def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>;
+def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>;
+def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>;
+def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>;
+def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>;
+def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>;
+def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>;
+def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>;
+def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>;
+def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>;
+def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>;
+def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>;
+def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>;
+def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
+def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>;
+def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>;
+def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>;
+def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>;
+def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>;
+def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>;
+def mno_sha : Flag<["-"], "mno-sha">, Group<m_x86_Features_Group>;
+def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>;
+def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>;
+def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>;
+def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>;
+def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>;
+def mno_xsave : Flag<["-"], "mno-xsave">, Group<m_x86_Features_Group>;
+def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>;
+def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>;
+def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>;
+def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>;
+def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>;
+def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>;
+
// These are legacy user-facing driver-level option spellings. They are always
// aliases for options that are spelled using the more common Unix / GNU flag
diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h
index 6206680118..19309c3f3b 100644
--- a/include/clang/Driver/SanitizerArgs.h
+++ b/include/clang/Driver/SanitizerArgs.h
@@ -32,33 +32,40 @@ class SanitizerArgs {
int MsanTrackOrigins = 0;
bool MsanUseAfterDtor = false;
bool CfiCrossDso = false;
+ bool CfiICallGeneralizePointers = false;
int AsanFieldPadding = 0;
- bool AsanSharedRuntime = false;
- bool AsanUseAfterScope = false;
+ bool SharedRuntime = false;
+ bool AsanUseAfterScope = true;
+ bool AsanGlobalsDeadStripping = false;
bool LinkCXXRuntimes = false;
bool NeedPIE = false;
+ bool SafeStackRuntime = false;
bool Stats = false;
bool TsanMemoryAccess = true;
bool TsanFuncEntryExit = true;
bool TsanAtomics = true;
+ bool MinimalRuntime = false;
+ // True if cross-dso CFI support if provided by the system (i.e. Android).
+ bool ImplicitCfiRuntime = false;
public:
/// Parses the sanitizer arguments from an argument list.
SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
+ bool needsSharedRt() const { return SharedRuntime; }
+
bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); }
- bool needsSharedAsanRt() const { return AsanSharedRuntime; }
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
+ bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
bool needsLsanRt() const {
return Sanitizers.has(SanitizerKind::Leak) &&
!Sanitizers.has(SanitizerKind::Address);
}
bool needsUbsanRt() const;
+ bool requiresMinimalRuntime() const { return MinimalRuntime; }
bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); }
- bool needsSafeStackRt() const {
- return Sanitizers.has(SanitizerKind::SafeStack);
- }
+ bool needsSafeStackRt() const { return SafeStackRuntime; }
bool needsCfiRt() const;
bool needsCfiDiagRt() const;
bool needsStatsRt() const { return Stats; }
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 5012cc8966..8f76e17c48 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 7dbe7a96dd..51ff2b2827 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -44,6 +44,29 @@ namespace driver {
class RegisterEffectiveTriple;
class SanitizerArgs;
class Tool;
+ class XRayArgs;
+
+/// Helper structure used to pass information extracted from clang executable
+/// name such as `i686-linux-android-g++`.
+///
+struct ParsedClangName {
+ /// Target part of the executable name, as `i686-linux-android`.
+ std::string TargetPrefix;
+ /// Driver mode part of the executable name, as `g++`.
+ std::string ModeSuffix;
+ /// Corresponding driver mode argument, as '--driver-mode=g++'
+ const char *DriverMode;
+ /// True if TargetPrefix is recognized as a registered target name.
+ bool TargetIsValid;
+
+ ParsedClangName() : DriverMode(nullptr), TargetIsValid(false) {}
+ ParsedClangName(std::string Suffix, const char *Mode)
+ : ModeSuffix(Suffix), DriverMode(Mode), TargetIsValid(false) {}
+ ParsedClangName(std::string Target, std::string Suffix, const char *Mode,
+ bool IsRegistered)
+ : TargetPrefix(Target), ModeSuffix(Suffix), DriverMode(Mode),
+ TargetIsValid(IsRegistered) {}
+};
/// ToolChain - Access to tools for a single platform.
class ToolChain {
@@ -94,12 +117,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 +201,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; }
@@ -187,13 +215,16 @@ public:
/// For example, when called with i686-linux-android-g++, the first element
/// of the return value will be set to `"i686-linux-android"` and the second
/// will be set to "--driver-mode=g++"`.
+ /// It is OK if the target name is not registered. In this case the return
+ /// value contains false in the field TargetIsValid.
///
/// \pre `llvm::InitializeAllTargets()` has been called.
/// \param ProgName The name the Clang driver was invoked with (from,
- /// e.g., argv[0])
- /// \return A pair of (`target`, `mode-flag`), where one or both may be empty.
- static std::pair<std::string, std::string>
- getTargetAndModeFromProgramName(StringRef ProgName);
+ /// e.g., argv[0]).
+ /// \return A structure of type ParsedClangName that contains the executable
+ /// name parts.
+ ///
+ static ParsedClangName getTargetAndModeFromProgramName(StringRef ProgName);
// Tool access.
@@ -211,6 +242,13 @@ public:
return nullptr;
}
+ /// TranslateOpenMPTargetArgs - Create a new derived argument list for
+ /// that contains the OpenMP target specific flags passed via
+ /// -Xopenmp-target -opt=val OR -Xopenmp-target=<triple> -opt=val
+ virtual llvm::opt::DerivedArgList *TranslateOpenMPTargetArgs(
+ const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost,
+ SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const;
+
/// Choose a tool to use to handle the action \p JA.
///
/// This can be overridden when a particular ToolChain needs to use
@@ -292,6 +330,8 @@ public:
return ToolChain::CST_Libstdcxx;
}
+ virtual std::string getCompilerRTPath() const;
+
virtual std::string getCompilerRT(const llvm::opt::ArgList &Args,
StringRef Component,
bool Shared = false) const;
@@ -309,7 +349,7 @@ public:
/// IsUnwindTablesDefault - Does this tool chain use -funwind-tables
/// by default.
- virtual bool IsUnwindTablesDefault() const;
+ virtual bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const;
/// \brief Test whether this toolchain defaults to PIC.
virtual bool isPICDefault() const = 0;
@@ -405,7 +445,8 @@ public:
/// \brief Add options that need to be passed to cc1 for this target.
virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const;
/// \brief Add warning options that need to be passed to cc1 for this target.
virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const;
@@ -425,6 +466,10 @@ public:
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;
+ /// Returns if the C++ standard library should be linked in.
+ /// Note that e.g. -lm should still be linked even if this returns false.
+ bool ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const;
+
/// AddCXXStdlibLibArgs - Add the system specific linker arguments to use
/// for the given C++ standard library type.
virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
@@ -476,7 +521,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 0000000000..83210d100a
--- /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/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h
index b6ec8b8f06..d95a0c2be8 100644
--- a/include/clang/Edit/EditedSource.h
+++ b/include/clang/Edit/EditedSource.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/Allocator.h"
#include <map>
+#include <tuple>
namespace clang {
class LangOptions;
@@ -41,9 +42,21 @@ class EditedSource {
typedef std::map<FileOffset, FileEdit> FileEditsTy;
FileEditsTy FileEdits;
- llvm::DenseMap<unsigned, llvm::TinyPtrVector<IdentifierInfo*>>
- ExpansionToArgMap;
- SmallVector<std::pair<SourceLocation, IdentifierInfo*>, 2>
+ struct MacroArgUse {
+ IdentifierInfo *Identifier;
+ SourceLocation ImmediateExpansionLoc;
+ // Location of argument use inside the top-level macro
+ SourceLocation UseLoc;
+
+ bool operator==(const MacroArgUse &Other) const {
+ return std::tie(Identifier, ImmediateExpansionLoc, UseLoc) ==
+ std::tie(Other.Identifier, Other.ImmediateExpansionLoc,
+ Other.UseLoc);
+ }
+ };
+
+ llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>> ExpansionToArgMap;
+ SmallVector<std::pair<SourceLocation, MacroArgUse>, 2>
CurrCommitMacroArgExps;
IdentifierTable IdentTable;
@@ -65,7 +78,7 @@ public:
bool commit(const Commit &commit);
- void applyRewrites(EditsReceiver &receiver);
+ void applyRewrites(EditsReceiver &receiver, bool adjustRemovals = true);
void clearRewrites();
StringRef copyString(StringRef str) { return str.copy(StrAlloc); }
@@ -84,7 +97,7 @@ private:
FileEditsTy::iterator getActionForOffset(FileOffset Offs);
void deconstructMacroArgLoc(SourceLocation Loc,
SourceLocation &ExpansionLoc,
- IdentifierInfo *&II);
+ MacroArgUse &ArgUse);
void startingCommit();
void finishedCommit();
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index b856bfd31a..a0e42f4e30 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -98,22 +98,39 @@ struct FormatStyle {
/// \endcode
bool AlignConsecutiveDeclarations;
- /// \brief If ``true``, aligns escaped newlines as far left as possible.
- /// Otherwise puts them into the right-most column.
- /// \code
- /// true:
- /// #define A \
- /// int aaaa; \
- /// int b; \
- /// int dddddddddd;
- ///
- /// false:
- /// #define A \
- /// int aaaa; \
- /// int b; \
- /// int dddddddddd;
- /// \endcode
- bool AlignEscapedNewlinesLeft;
+ /// \brief Different styles for aligning escaped newlines.
+ enum EscapedNewlineAlignmentStyle {
+ /// \brief Don't align escaped newlines.
+ /// \code
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ /// \endcode
+ ENAS_DontAlign,
+ /// \brief Align escaped newlines as far left as possible.
+ /// \code
+ /// true:
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ ///
+ /// false:
+ /// \endcode
+ ENAS_Left,
+ /// \brief Align escaped newlines in the right-most column.
+ /// \code
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ /// \endcode
+ ENAS_Right,
+ };
+
+ /// \brief Options for aligning backslashes in escaped newlines.
+ EscapedNewlineAlignmentStyle AlignEscapedNewlines;
/// \brief If ``true``, horizontally align operands of binary and ternary
/// expressions.
@@ -134,13 +151,20 @@ struct FormatStyle {
/// \endcode
bool AlignTrailingComments;
- /// \brief Allow putting all parameters of a function declaration onto
+ /// \brief If the function declaration doesn't fit on a line,
+ /// 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);
+ /// true:
+ /// void myFunction(
+ /// int a, int b, int c, int d, int e);
+ ///
+ /// false:
+ /// void myFunction(int a,
+ /// int b,
+ /// int c,
+ /// int d,
+ /// int e);
/// \endcode
bool AllowAllParametersOfDeclarationOnNextLine;
@@ -167,9 +191,23 @@ struct FormatStyle {
enum ShortFunctionStyle {
/// \brief Never merge functions into a single line.
SFS_None,
+ /// \brief Only merge functions defined inside a class. Same as "inline",
+ /// except it does not implies "empty": i.e. top level empty functions
+ /// are not merged either.
+ /// \code
+ /// class Foo {
+ /// void f() { foo(); }
+ /// };
+ /// void f() {
+ /// foo();
+ /// }
+ /// void f() {
+ /// }
+ /// \endcode
+ SFS_InlineOnly,
/// \brief Only merge empty functions.
/// \code
- /// void f() { bar(); }
+ /// void f() {}
/// void f2() {
/// bar2();
/// }
@@ -177,14 +215,18 @@ struct FormatStyle {
SFS_Empty,
/// \brief Only merge functions defined inside a class. Implies "empty".
/// \code
- /// class {
+ /// class Foo {
/// void f() { foo(); }
/// };
+ /// void f() {
+ /// foo();
+ /// }
+ /// void f() {}
/// \endcode
SFS_Inline,
/// \brief Merge all functions fitting on a single line.
/// \code
- /// class {
+ /// class Foo {
/// void f() { foo(); }
/// };
/// void f() { bar(); }
@@ -204,7 +246,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.
+ /// This option is **deprecated** and is retained for backwards compatibility.
enum DefinitionReturnTypeBreakingStyle {
/// Break after return type automatically.
/// ``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
@@ -287,7 +329,7 @@ struct FormatStyle {
};
/// \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.
@@ -318,19 +360,73 @@ struct FormatStyle {
/// \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,
};
@@ -563,12 +659,12 @@ struct FormatStyle {
/// struct foo
/// {
/// int x;
- /// }
+ /// };
///
/// false:
/// struct foo {
/// int x;
- /// }
+ /// };
/// \endcode
bool AfterStruct;
/// \brief Wrap union definitions.
@@ -585,6 +681,20 @@ struct FormatStyle {
/// }
/// \endcode
bool AfterUnion;
+ /// \brief Wrap extern blocks.
+ /// \code
+ /// true:
+ /// extern "C"
+ /// {
+ /// int foo();
+ /// }
+ ///
+ /// false:
+ /// extern "C" {
+ /// int foo();
+ /// }
+ /// \endcode
+ bool AfterExternBlock;
/// \brief Wrap before ``catch``.
/// \code
/// true:
@@ -617,12 +727,54 @@ struct FormatStyle {
bool BeforeElse;
/// \brief Indent the wrapped braces themselves.
bool IndentBraces;
+ /// \brief If ``false``, empty function body can be put on a single line.
+ /// This option is used only if the opening brace of the function has
+ /// already been wrapped, i.e. the `AfterFunction` brace wrapping mode is
+ /// set, and the function could/should not be put on a single line (as per
+ /// `AllowShortFunctionsOnASingleLine` and constructor formatting options).
+ /// \code
+ /// int f() vs. inf f()
+ /// {} {
+ /// }
+ /// \endcode
+ ///
+ bool SplitEmptyFunction;
+ /// \brief If ``false``, empty record (e.g. class, struct or union) body
+ /// can be put on a single line. This option is used only if the opening
+ /// brace of the record has already been wrapped, i.e. the `AfterClass`
+ /// (for classes) brace wrapping mode is set.
+ /// \code
+ /// class Foo vs. class Foo
+ /// {} {
+ /// }
+ /// \endcode
+ ///
+ bool SplitEmptyRecord;
+ /// \brief If ``false``, empty namespace body can be put on a single line.
+ /// This option is used only if the opening brace of the namespace has
+ /// already been wrapped, i.e. the `AfterNamespace` brace wrapping mode is
+ /// set.
+ /// \code
+ /// namespace Foo vs. namespace Foo
+ /// {} {
+ /// }
+ /// \endcode
+ ///
+ bool SplitEmptyNamespace;
};
/// \brief Control of individual brace wrapping cases.
///
/// If ``BreakBeforeBraces`` is set to ``BS_Custom``, use this to specify how
/// each individual brace case should be handled. Otherwise, this is ignored.
+ /// \code{.yaml}
+ /// # Example of usage:
+ /// BreakBeforeBraces: Custom
+ /// BraceWrapping:
+ /// AfterEnum: true
+ /// AfterStruct: false
+ /// SplitEmptyFunction: false
+ /// \endcode
BraceWrappingFlags BraceWrapping;
/// \brief If ``true``, ternary operators will be placed after line breaks.
@@ -632,25 +784,49 @@ struct FormatStyle {
/// ? firstValue
/// : SecondValueVeryVeryVeryVeryLong;
///
- /// true:
+ /// false:
/// 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 Different ways to break initializers.
+ enum BreakConstructorInitializersStyle {
+ /// Break constructor initializers before the colon and after the commas.
+ /// \code
+ /// Constructor()
+ /// : initializer1(),
+ /// initializer2()
+ /// \endcode
+ BCIS_BeforeColon,
+ /// Break constructor initializers before the colon and commas, and align
+ /// the commas with the colon.
+ /// \code
+ /// Constructor()
+ /// : initializer1()
+ /// , initializer2()
+ /// \endcode
+ BCIS_BeforeComma,
+ /// Break constructor initializers after the colon and commas.
+ /// \code
+ /// Constructor() :
+ /// initializer1(),
+ /// initializer2()
+ /// \endcode
+ BCIS_AfterColon
+ };
+
+ /// \brief The constructor initializers style to use.
+ BreakConstructorInitializersStyle BreakConstructorInitializers;
/// \brief Break after each annotation on a field in Java files.
+ /// \code{.java}
+ /// true: false:
+ /// @Partial vs. @Partial @Mock DataLoad loader;
+ /// @Mock
+ /// DataLoad loader;
+ /// \endcode
bool BreakAfterJavaFieldAnnotations;
/// \brief Allow breaking string literals when formatting.
@@ -665,6 +841,11 @@ 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
@@ -678,6 +859,29 @@ struct FormatStyle {
/// \endcode
bool BreakBeforeInheritanceComma;
+ /// \brief If ``true``, consecutive namespace declarations will be on the same
+ /// line. If ``false``, each namespace is declared on a new line.
+ /// \code
+ /// true:
+ /// namespace Foo { namespace Bar {
+ /// }}
+ ///
+ /// false:
+ /// namespace Foo {
+ /// namespace Bar {
+ /// }
+ /// }
+ /// \endcode
+ ///
+ /// If it does not fit on a single line, the overflowing namespaces get
+ /// wrapped:
+ /// \code
+ /// namespace Foo { namespace Bar {
+ /// namespace Extra {
+ /// }}}
+ /// \endcode
+ bool CompactNamespaces;
+
/// \brief If the constructor initializers don't fit on a line, put each
/// initializer on its own line.
/// \code
@@ -701,6 +905,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
@@ -716,11 +927,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.
@@ -797,7 +1017,7 @@ struct FormatStyle {
/// IncludeCategories:
/// - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
/// Priority: 2
- /// - Regex: '^(<|"(gtest|isl|json)/)'
+ /// - Regex: '^(<|"(gtest|gmock|isl|json)/)'
/// Priority: 3
/// - Regex: '.*'
/// Priority: 1
@@ -821,23 +1041,89 @@ 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 Options for indenting preprocessor directives.
+ enum PPDirectiveIndentStyle {
+ /// Does not indent any directives.
+ /// \code
+ /// #if FOO
+ /// #if BAR
+ /// #include <foo>
+ /// #endif
+ /// #endif
+ /// \endcode
+ PPDIS_None,
+ /// Indents directives after the hash.
+ /// \code
+ /// #if FOO
+ /// # if BAR
+ /// # include <foo>
+ /// # endif
+ /// #endif
+ /// \endcode
+ PPDIS_AfterHash
+ };
+
+ /// \brief The preprocessor directive indenting style to use.
+ PPDirectiveIndentStyle IndentPPDirectives;
+
/// \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
};
@@ -845,9 +1131,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.
@@ -870,29 +1174,91 @@ struct FormatStyle {
/// (https://developers.google.com/protocol-buffers/).
LK_Proto,
/// Should be used for TableGen code.
- LK_TableGen
+ LK_TableGen,
+ /// Should be used for Protocol Buffer messages in text format
+ /// (https://developers.google.com/protocol-buffers/).
+ LK_TextProto
};
- bool IsCpp() const { return Language == LK_Cpp || Language == LK_ObjC; }
+ 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
};
@@ -900,6 +1266,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
@@ -910,6 +1283,9 @@ struct FormatStyle {
/// ``Foo <Protocol>`` instead of ``Foo<Protocol>``.
bool ObjCSpaceBeforeProtocolList;
+ /// \brief The penalty for breaking around an assignment operator.
+ unsigned PenaltyBreakAssignment;
+
/// \brief The penalty for breaking a function call after ``call(``.
unsigned PenaltyBreakBeforeFirstCallParameter;
@@ -951,7 +1327,53 @@ struct FormatStyle {
/// \brief Pointer and reference alignment style.
PointerAlignmentStyle PointerAlignment;
+ /// See documentation of ``RawStringFormats``.
+ struct RawStringFormat {
+ /// \brief The delimiter that this raw string format matches.
+ std::string Delimiter;
+ /// \brief The language of this raw string.
+ LanguageKind Language;
+ /// \brief The style name on which this raw string format is based on.
+ /// If not specified, the raw string format is based on the style that this
+ /// format is based on.
+ std::string BasedOnStyle;
+ bool operator==(const RawStringFormat &Other) const {
+ return Delimiter == Other.Delimiter && Language == Other.Language &&
+ BasedOnStyle == Other.BasedOnStyle;
+ }
+ };
+
+ /// \brief Raw string delimiters denoting that the raw string contents are
+ /// code in a particular language and can be reformatted.
+ ///
+ /// A raw string with a matching delimiter will be reformatted assuming the
+ /// specified language based on a predefined style given by 'BasedOnStyle'.
+ /// If 'BasedOnStyle' is not found, the formatting is based on llvm style.
+ ///
+ /// To configure this in the .clang-format file, use:
+ /// \code{.yaml}
+ /// RawStringFormats:
+ /// - Delimiter: 'pb'
+ /// Language: TextProto
+ /// BasedOnStyle: llvm
+ /// - Delimiter: 'proto'
+ /// Language: TextProto
+ /// BasedOnStyle: google
+ /// \endcode
+ std::vector<RawStringFormat> RawStringFormats;
+
/// \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``.
@@ -962,6 +1384,14 @@ struct FormatStyle {
/// \endcode
bool SortIncludes;
+ /// \brief If ``true``, clang-format will sort using declarations.
+ /// \code
+ /// false: true:
+ /// using std::cout; vs. using std::cin;
+ /// using std::cin; using std::cout;
+ /// \endcode
+ bool SortUsingDeclarations;
+
/// \brief If ``true``, a space is inserted after C style casts.
/// \code
/// true: false:
@@ -987,14 +1417,35 @@ struct FormatStyle {
/// \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
};
@@ -1002,6 +1453,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
@@ -1010,6 +1470,14 @@ 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 ``>``
@@ -1023,6 +1491,11 @@ struct FormatStyle {
/// \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.
@@ -1052,7 +1525,8 @@ struct FormatStyle {
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
@@ -1086,7 +1560,7 @@ struct FormatStyle {
AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
AlignConsecutiveAssignments == R.AlignConsecutiveAssignments &&
AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations &&
- AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
+ AlignEscapedNewlines == R.AlignEscapedNewlines &&
AlignOperands == R.AlignOperands &&
AlignTrailingComments == R.AlignTrailingComments &&
AllowAllParametersOfDeclarationOnNextLine ==
@@ -1109,8 +1583,8 @@ struct FormatStyle {
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
BreakBeforeBraces == R.BreakBeforeBraces &&
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
- BreakConstructorInitializersBeforeComma ==
- R.BreakConstructorInitializersBeforeComma &&
+ BreakConstructorInitializers == R.BreakConstructorInitializers &&
+ CompactNamespaces == R.CompactNamespaces &&
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
BreakStringLiterals == R.BreakStringLiterals &&
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
@@ -1129,6 +1603,7 @@ struct FormatStyle {
ForEachMacros == R.ForEachMacros &&
IncludeCategories == R.IncludeCategories &&
IndentCaseLabels == R.IndentCaseLabels &&
+ IndentPPDirectives == R.IndentPPDirectives &&
IndentWidth == R.IndentWidth && Language == R.Language &&
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
JavaScriptQuotes == R.JavaScriptQuotes &&
@@ -1142,6 +1617,8 @@ struct FormatStyle {
ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty &&
ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
+ PenaltyBreakAssignment ==
+ R.PenaltyBreakAssignment &&
PenaltyBreakBeforeFirstCallParameter ==
R.PenaltyBreakBeforeFirstCallParameter &&
PenaltyBreakComment == R.PenaltyBreakComment &&
@@ -1150,6 +1627,7 @@ struct FormatStyle {
PenaltyExcessCharacter == R.PenaltyExcessCharacter &&
PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine &&
PointerAlignment == R.PointerAlignment &&
+ RawStringFormats == R.RawStringFormats &&
SpaceAfterCStyleCast == R.SpaceAfterCStyleCast &&
SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword &&
SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators &&
@@ -1251,6 +1729,18 @@ llvm::Expected<tooling::Replacements>
cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
const FormatStyle &Style);
+/// \brief Represents the status of a formatting attempt.
+struct FormattingAttemptStatus {
+ /// \brief A value of ``false`` means that any of the affected ranges were not
+ /// formatted due to a non-recoverable syntax error.
+ bool FormatComplete = true;
+
+ /// \brief If ``FormatComplete`` is false, ``Line`` records a one-based
+ /// original line number at which a syntax error might have occurred. This is
+ /// based on a best-effort analysis and could be imprecise.
+ unsigned Line = 0;
+};
+
/// \brief Reformats the given \p Ranges in \p Code.
///
/// Each range is extended on either end to its next bigger logic unit, i.e.
@@ -1260,13 +1750,20 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
/// Returns the ``Replacements`` necessary to make all \p Ranges comply with
/// \p Style.
///
-/// If ``IncompleteFormat`` is non-null, its value will be set to true if any
-/// of the affected ranges were not formatted due to a non-recoverable syntax
-/// error.
+/// If ``Status`` is non-null, its value will be populated with the status of
+/// this formatting attempt. See \c FormattingAttemptStatus.
tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName = "<stdin>",
- bool *IncompleteFormat = nullptr);
+ FormattingAttemptStatus *Status = nullptr);
+
+/// \brief Same as above, except if ``IncompleteFormat`` is non-null, its value
+/// will be set to true if any of the affected ranges were not formatted due to
+/// a non-recoverable syntax error.
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName,
+ bool *IncompleteFormat);
/// \brief Clean up any erroneous/redundant code in the given \p Ranges in \p
/// Code.
@@ -1285,6 +1782,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
ArrayRef<tooling::Range> Ranges,
StringRef FileName = "<stdin>");
+/// \brief Sort consecutive using declarations in the given \p Ranges in
+/// \p Code.
+///
+/// Returns the ``Replacements`` that sort the using declarations in all
+/// \p Ranges in \p Code.
+tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName = "<stdin>");
+
/// \brief Returns the ``LangOpts`` that the formatter expects you to set.
///
/// \param Style determines specific settings for lexing mode.
@@ -1337,6 +1844,8 @@ inline StringRef getLanguageName(FormatStyle::LanguageKind Language) {
return "JavaScript";
case FormatStyle::LK_Proto:
return "Proto";
+ case FormatStyle::LK_TextProto:
+ return "TextProto";
default:
return "Unknown";
}
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 03961f1a3c..5d04dcd191 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -25,6 +25,7 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Frontend/PrecompiledPreamble.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -51,16 +52,23 @@ class DiagnosticsEngine;
class FileEntry;
class FileManager;
class HeaderSearch;
+class InputKind;
+class MemoryBufferCache;
class Preprocessor;
+class PreprocessorOptions;
class PCHContainerOperations;
class PCHContainerReader;
class TargetInfo;
class FrontendAction;
class ASTDeserializationListener;
+namespace vfs {
+class FileSystem;
+}
+
/// \brief Utility class for loading a ASTContext from an AST file.
///
-class ASTUnit : public ModuleLoader {
+class ASTUnit {
public:
struct StandaloneFixIt {
std::pair<unsigned, unsigned> RemoveRange;
@@ -84,12 +92,14 @@ private:
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
IntrusiveRefCntPtr<FileManager> FileMgr;
IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
std::unique_ptr<HeaderSearch> HeaderInfo;
IntrusiveRefCntPtr<TargetInfo> Target;
std::shared_ptr<Preprocessor> PP;
IntrusiveRefCntPtr<ASTContext> Ctx;
std::shared_ptr<TargetOptions> TargetOpts;
std::shared_ptr<HeaderSearchOptions> HSOpts;
+ std::shared_ptr<PreprocessorOptions> PPOpts;
IntrusiveRefCntPtr<ASTReader> Reader;
bool HadModuleLoaderFatalFailure;
@@ -110,10 +120,13 @@ private:
/// LoadFromCommandLine available.
std::shared_ptr<CompilerInvocation> Invocation;
+ /// Fake module loader: the AST unit doesn't need to load any modules.
+ TrivialModuleLoader ModuleLoader;
+
// OnlyLocalDecls - when true, walking this AST should only visit declarations
// that come from the AST itself, not from included precompiled headers.
// FIXME: This is temporary; eventually, CIndex will always do this.
- bool OnlyLocalDecls;
+ bool OnlyLocalDecls;
/// \brief Whether to capture any diagnostics produced.
bool CaptureDiagnostics;
@@ -179,103 +192,23 @@ private:
/// some number of calls.
unsigned PreambleRebuildCounter;
-public:
- class PreambleData {
- const FileEntry *File;
- std::vector<char> Buffer;
- mutable unsigned NumLines;
-
- public:
- PreambleData() : File(nullptr), NumLines(0) { }
-
- void assign(const FileEntry *F, const char *begin, const char *end) {
- File = F;
- Buffer.assign(begin, end);
- NumLines = 0;
- }
-
- void clear() { Buffer.clear(); File = nullptr; NumLines = 0; }
-
- size_t size() const { return Buffer.size(); }
- bool empty() const { return Buffer.empty(); }
-
- const char *getBufferStart() const { return &Buffer[0]; }
-
- unsigned getNumLines() const {
- if (NumLines)
- return NumLines;
- countLines();
- return NumLines;
- }
-
- SourceRange getSourceRange(const SourceManager &SM) const {
- SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID());
- return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1));
- }
-
- private:
- void countLines() const;
- };
-
- const PreambleData &getPreambleData() const {
- return Preamble;
- }
-
- /// Data used to determine if a file used in the preamble has been changed.
- struct PreambleFileHash {
- /// All files have size set.
- off_t Size;
-
- /// Modification time is set for files that are on disk. For memory
- /// buffers it is zero.
- time_t ModTime;
-
- /// Memory buffers have MD5 instead of modification time. We don't
- /// compute MD5 for on-disk files because we hope that modification time is
- /// enough to tell if the file was changed.
- llvm::MD5::MD5Result MD5;
-
- static PreambleFileHash createForFile(off_t Size, time_t ModTime);
- static PreambleFileHash
- createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
-
- friend bool operator==(const PreambleFileHash &LHS,
- const PreambleFileHash &RHS);
-
- friend bool operator!=(const PreambleFileHash &LHS,
- const PreambleFileHash &RHS) {
- return !(LHS == RHS);
- }
- };
+ /// \brief Cache pairs "filename - source location"
+ ///
+ /// Cache contains only source locations from preamble so it is
+ /// guaranteed that they stay valid when the SourceManager is recreated.
+ /// This cache is used when loading preambule to increase performance
+ /// of that loading. It must be cleared when preamble is recreated.
+ llvm::StringMap<SourceLocation> PreambleSrcLocCache;
private:
- /// \brief The contents of the preamble that has been precompiled to
- /// \c PreambleFile.
- PreambleData Preamble;
-
- /// \brief Whether the preamble ends at the start of a new line.
- ///
- /// Used to inform the lexer as to whether it's starting at the beginning of
- /// a line after skipping the preamble.
- bool PreambleEndsAtStartOfLine;
-
- /// \brief Keeps track of the files that were used when computing the
- /// preamble, with both their buffer size and their modification time.
- ///
- /// If any of the files have changed from one compile to the next,
- /// the preamble must be thrown away.
- llvm::StringMap<PreambleFileHash> FilesInPreamble;
+ /// The contents of the preamble.
+ llvm::Optional<PrecompiledPreamble> Preamble;
/// \brief When non-NULL, this is the buffer used to store the contents of
/// the main file when it has been padded for use with the precompiled
/// preamble.
std::unique_ptr<llvm::MemoryBuffer> SavedMainFileBuffer;
- /// \brief When non-NULL, this is the buffer used to store the
- /// contents of the preamble when it has been padded to build the
- /// precompiled preamble.
- std::unique_ptr<llvm::MemoryBuffer> PreambleBuffer;
-
/// \brief The number of warnings that occurred while parsing the preamble.
///
/// This value will be used to restore the state of the \c DiagnosticsEngine
@@ -299,9 +232,6 @@ private:
/// (likely to change while trying to use them).
bool UserFilesAreVolatile : 1;
- /// \brief The language options used when we load an AST file.
- LangOptions ASTFileLangOpts;
-
static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics);
@@ -417,27 +347,14 @@ private:
explicit ASTUnit(bool MainFileIsAST);
- void CleanTemporaryFiles();
bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
-
- struct ComputedPreamble {
- llvm::MemoryBuffer *Buffer;
- std::unique_ptr<llvm::MemoryBuffer> Owner;
- unsigned Size;
- bool PreambleEndsAtStartOfLine;
- ComputedPreamble(llvm::MemoryBuffer *Buffer,
- std::unique_ptr<llvm::MemoryBuffer> Owner, unsigned Size,
- bool PreambleEndsAtStartOfLine)
- : Buffer(Buffer), Owner(std::move(Owner)), Size(Size),
- PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
- };
- ComputedPreamble ComputePreamble(CompilerInvocation &Invocation,
- unsigned MaxLines);
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS);
std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true,
+ const CompilerInvocation &PreambleInvocationIn,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild = true,
unsigned MaxLines = 0);
void RealizeTopLevelDeclsFromPreamble();
@@ -480,7 +397,7 @@ public:
};
friend class ConcurrencyCheck;
- ~ASTUnit() override;
+ ~ASTUnit();
bool isMainFileAST() const { return MainFileIsAST; }
@@ -510,9 +427,19 @@ public:
}
const LangOptions &getLangOpts() const {
- assert(LangOpts && " ASTUnit does not have language options");
+ assert(LangOpts && "ASTUnit does not have language options");
return *LangOpts;
}
+
+ const HeaderSearchOptions &getHeaderSearchOpts() const {
+ assert(HSOpts && "ASTUnit does not have header search options");
+ return *HSOpts;
+ }
+
+ const PreprocessorOptions &getPreprocessorOpts() const {
+ assert(PPOpts && "ASTUnit does not have preprocessor options");
+ return *PPOpts;
+ }
const FileManager &getFileManager() const { return *FileMgr; }
FileManager &getFileManager() { return *FileMgr; }
@@ -521,18 +448,13 @@ public:
IntrusiveRefCntPtr<ASTReader> getASTReader() const;
- StringRef getOriginalSourceFileName() {
+ StringRef getOriginalSourceFileName() const {
return OriginalSourceFile;
}
ASTMutationListener *getASTMutationListener();
ASTDeserializationListener *getDeserializationListener();
- /// \brief Add a temporary file that the ASTUnit depends on.
- ///
- /// This file will be erased when the ASTUnit is destroyed.
- void addTemporaryFile(StringRef TempFile);
-
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; }
@@ -583,12 +505,6 @@ public:
void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
SmallVectorImpl<Decl *> &Decls);
- /// \brief Add a new top-level declaration, identified by its ID in
- /// the precompiled preamble.
- void addTopLevelDeclFromPreamble(serialization::DeclID D) {
- TopLevelDeclsInPreamble.push_back(D);
- }
-
/// \brief Retrieve a reference to the current top-level name hash value.
///
/// Note: This is used internally by the top-level tracking action
@@ -608,26 +524,26 @@ public:
/// \brief If \p Loc is a loaded location from the preamble, returns
/// the corresponding local location of the main file, otherwise it returns
/// \p Loc.
- SourceLocation mapLocationFromPreamble(SourceLocation Loc);
+ SourceLocation mapLocationFromPreamble(SourceLocation Loc) const;
/// \brief If \p Loc is a local location of the main file but inside the
/// preamble chunk, returns the corresponding loaded location from the
/// preamble, otherwise it returns \p Loc.
- SourceLocation mapLocationToPreamble(SourceLocation Loc);
+ SourceLocation mapLocationToPreamble(SourceLocation Loc) const;
- bool isInPreambleFileID(SourceLocation Loc);
- bool isInMainFileID(SourceLocation Loc);
- SourceLocation getStartOfMainFileID();
- SourceLocation getEndOfPreambleFileID();
+ bool isInPreambleFileID(SourceLocation Loc) const;
+ bool isInMainFileID(SourceLocation Loc) const;
+ SourceLocation getStartOfMainFileID() const;
+ SourceLocation getEndOfPreambleFileID() const;
/// \see mapLocationFromPreamble.
- SourceRange mapRangeFromPreamble(SourceRange R) {
+ SourceRange mapRangeFromPreamble(SourceRange R) const {
return SourceRange(mapLocationFromPreamble(R.getBegin()),
mapLocationFromPreamble(R.getEnd()));
}
/// \see mapLocationToPreamble.
- SourceRange mapRangeToPreamble(SourceRange R) {
+ SourceRange mapRangeToPreamble(SourceRange R) const {
return SourceRange(mapLocationToPreamble(R.getBegin()),
mapLocationToPreamble(R.getEnd()));
}
@@ -691,7 +607,7 @@ public:
/// \brief Returns true if the ASTUnit was constructed from a serialized
/// module file.
- bool isModuleFile();
+ bool isModuleFile() const;
std::unique_ptr<llvm::MemoryBuffer>
getBufferForFile(StringRef Filename, std::string *ErrorStr = nullptr);
@@ -699,6 +615,9 @@ public:
/// \brief Determine what kind of translation unit this AST represents.
TranslationUnitKind getTranslationUnitKind() const { return TUKind; }
+ /// \brief Determine the input kind this AST unit represents.
+ InputKind getInputKind() const;
+
/// \brief A mapping from a file name to the memory buffer that stores the
/// remapped contents of that file.
typedef std::pair<std::string, llvm::MemoryBuffer *> RemappedFile;
@@ -709,6 +628,15 @@ public:
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, bool CaptureDiagnostics,
bool UserFilesAreVolatile);
+ enum WhatToLoad {
+ /// Load options and the preprocessor state.
+ LoadPreprocessorOnly,
+ /// Load the AST, but do not restore Sema state.
+ LoadASTOnly,
+ /// Load everything, including Sema.
+ LoadEverything
+ };
+
/// \brief Create a ASTUnit from an AST file.
///
/// \param Filename - The AST file to load.
@@ -721,7 +649,7 @@ public:
/// \returns - The initialized ASTUnit or null if the AST failed to load.
static std::unique_ptr<ASTUnit> LoadFromASTFile(
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false,
bool OnlyLocalDecls = false, ArrayRef<RemappedFile> RemappedFiles = None,
bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false,
@@ -735,11 +663,17 @@ private:
/// of this translation unit should be precompiled, to improve the performance
/// of reparsing. Set to zero to disable preambles.
///
+ /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
+ /// preamble is saved to a temporary directory on a RealFileSystem, so in order
+ /// for it to be loaded correctly, VFS should have access to it(i.e., be an
+ /// overlay over RealFileSystem).
+ ///
/// \returns \c true if a catastrophic failure occurred (which means that the
/// \c ASTUnit itself is invalid), or \c false otherwise.
bool LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- unsigned PrecompilePreambleAfterNParses);
+ unsigned PrecompilePreambleAfterNParses,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS);
public:
@@ -830,6 +764,11 @@ public:
/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
/// mainly to allow the caller to see the diagnostics.
///
+ /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
+ /// preamble is saved to a temporary directory on a RealFileSystem, so in order
+ /// for it to be loaded correctly, VFS should have access to it(i.e., be an
+ /// overlay over RealFileSystem). RealFileSystem will be used if \p VFS is nullptr.
+ ///
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCommandLine(
@@ -844,17 +783,31 @@ public:
bool CacheCodeCompletionResults = false,
bool IncludeBriefCommentsInCodeCompletion = false,
bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false,
+ bool SingleFileParse = false,
bool UserFilesAreVolatile = false, bool ForSerialization = false,
llvm::Optional<StringRef> ModuleFormat = llvm::None,
- std::unique_ptr<ASTUnit> *ErrAST = nullptr);
+ std::unique_ptr<ASTUnit> *ErrAST = nullptr,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
/// \brief Reparse the source files using the same command-line options that
/// were originally used to produce this translation unit.
///
+ /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
+ /// preamble is saved to a temporary directory on a RealFileSystem, so in order
+ /// for it to be loaded correctly, VFS should give an access to this(i.e. be an
+ /// overlay over RealFileSystem). FileMgr->getVirtualFileSystem() will be used if
+ /// \p VFS is nullptr.
+ ///
/// \returns True if a failure occurred that causes the ASTUnit not to
/// contain any translation-unit information, false otherwise.
bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- ArrayRef<RemappedFile> RemappedFiles = None);
+ ArrayRef<RemappedFile> RemappedFiles = None,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
+
+ /// \brief Free data that will be re-generated on the next parse.
+ ///
+ /// Preamble-related data is not affected.
+ void ResetForParse();
/// \brief Perform code completion at the given file, line, and
/// column within this translation unit.
@@ -896,21 +849,6 @@ public:
///
/// \returns True if an error occurred, false otherwise.
bool serialize(raw_ostream &OS);
-
- ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- // ASTUnit doesn't know how to load modules (not that this matters).
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override {}
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
};
} // namespace clang
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 172380c00e..8f2aae2f14 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -29,7 +29,8 @@ CODEGENOPT(Name, Bits, Default)
#endif
CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as
-CODEGENOPT(CompressDebugSections, 1, 0) ///< -Wa,-compress-debug-sections
+ENUM_CODEGENOPT(CompressDebugSections, llvm::DebugCompressionType, 2,
+ llvm::DebugCompressionType::None)
CODEGENOPT(RelaxELFRelocations, 1, 0) ///< -Wa,--mrelax-relocations
CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm.
CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments.
@@ -53,8 +54,11 @@ CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get
///< the pristine IR generated by the
///< frontend.
CODEGENOPT(DisableLifetimeMarkers, 1, 0) ///< Don't emit any lifetime markers
+CODEGENOPT(DisableO0ImplyOptNone , 1, 0) ///< Don't annonate function with optnone at O0
CODEGENOPT(ExperimentalNewPassManager, 1, 0) ///< Enables the new, experimental
///< pass manager.
+CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new
+ ///< pass manager.
CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled.
CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls.
CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what
@@ -65,8 +69,6 @@ CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA.
CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
CODEGENOPT(EmulatedTLS , 1, 0) ///< Set when -femulated-tls is enabled.
-/// \brief FP_CONTRACT mode (on/off/fast).
-ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On)
/// \brief Embed Bitcode mode (off/all/bitcode/marker).
ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
@@ -118,6 +120,10 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
///< enabled.
+
+/// A version of Clang that we should attempt to be ABI-compatible with.
+ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest)
+
VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
@@ -139,11 +145,17 @@ CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA
CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels.
CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection
///< in AddressSanitizer
+CODEGENOPT(SanitizeAddressGlobalsDeadStripping, 1, 0) ///< Enable linker dead stripping
+ ///< of globals in AddressSanitizer
CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in
///< MemorySanitizer
CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection
///< in MemorySanitizer
CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI.
+CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime for
+ ///< diagnostics.
+CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
+ ///< CFI icall function signatures
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
///< instrumentation.
CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage
@@ -162,9 +174,14 @@ CODEGENOPT(SanitizeCoverageTracePC, 1, 0) ///< Enable PC tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageTracePCGuard, 1, 0) ///< Enable PC tracing with guard
///< in sanitizer coverage.
+CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters.
+CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table.
+CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning.
+CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing
CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
+CODEGENOPT(FineGrainedBitfieldAccesses, 1, 0) ///< Enable fine-grained bitfield accesses.
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers
CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled.
@@ -173,9 +190,9 @@ CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled.
CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled.
CODEGENOPT(UnsafeFPMath , 1, 0) ///< Allow unsafe floating point optzns.
CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables.
-CODEGENOPT(VectorizeBB , 1, 0) ///< Run basic block vectorizer.
CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer.
CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer.
+CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate.
/// Attempt to use register sized accesses to bit-fields in structures, when
/// possible.
@@ -201,9 +218,14 @@ CODEGENOPT(DebugTypeExtRefs, 1, 0) ///< Whether or not debug info should contain
CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should
///< contain explicit imports for
///< anonymous namespaces
+CODEGENOPT(EnableSplitDwarf, 1, 0) ///< Whether to enable split DWARF
CODEGENOPT(SplitDwarfInlining, 1, 1) ///< Whether to include inlining info in the
///< skeleton CU to allow for symbolication
///< of inline stack frames without .dwo files.
+CODEGENOPT(DebugFwdTemplateParams, 1, 0) ///< Whether to emit complete
+ ///< template parameter descriptions in
+ ///< forward declarations (versus just
+ ///< including them in the name).
CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
@@ -255,6 +277,10 @@ VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0)
/// Whether to report the hotness of the code region for optimization remarks.
CODEGENOPT(DiagnosticsWithHotness, 1, 0)
+/// The minimum hotness value a diagnostic needs in order to be included in
+/// optimization diagnostics.
+VALUE_CODEGENOPT(DiagnosticsHotnessThreshold, 32, 0)
+
/// Whether copy relocations support is available when building as PIE.
CODEGENOPT(PIECopyRelocations, 1, 0)
@@ -265,6 +291,12 @@ 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)
+
+/// Whether to emit .debug_gnu_pubnames section instead of .debug_pubnames.
+CODEGENOPT(GnuPubnames, 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 f8f32666c5..71730a21db 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -69,10 +69,21 @@ public:
LocalExecTLSModel
};
- enum FPContractModeKind {
- FPC_Off, // Form fused FP ops only where result will not be affected.
- FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
- FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
+ /// Clang versions with different platform ABI conformance.
+ enum class ClangABI {
+ /// Attempt to be ABI-compatible with code generated by Clang 3.8.x
+ /// (SVN r257626). This causes <1 x long long> to be passed in an
+ /// integer register instead of an SSE register on x64_64.
+ Ver3_8,
+
+ /// Attempt to be ABI-compatible with code generated by Clang 4.0.x
+ /// (SVN r291814). This causes move operations to be ignored when
+ /// determining whether a class type can be passed or returned directly.
+ Ver4,
+
+ /// Conform to the underlying platform's C and C++ ABIs as closely
+ /// as we can.
+ Latest
};
enum StructReturnConventionKind {
@@ -188,6 +199,11 @@ public:
/// importing.
std::string ThinLTOIndexFile;
+ /// Name of a file that can optionally be written with minimized bitcode
+ /// to be used as input for the ThinLTO thin link step, which only needs
+ /// the summary and module symbol table (and not, e.g. any debug metadata).
+ std::string ThinLinkBitcodeFile;
+
/// A list of file names passed with -fcuda-include-gpubinary options to
/// forward to CUDA runtime back-end for incorporating them into host-side
/// object file.
@@ -219,7 +235,7 @@ public:
/// flag.
std::shared_ptr<llvm::Regex> OptimizationRemarkAnalysisPattern;
- /// Set of files definining the rules for the symbol rewriting.
+ /// Set of files defining the rules for the symbol rewriting.
std::vector<std::string> RewriteMapFiles;
/// Set of sanitizer checks that are non-fatal (i.e. execution should be
diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h
index a78c96d23a..f5c1e1a8a6 100644
--- a/include/clang/Frontend/CommandLineSourceLoc.h
+++ b/include/clang/Frontend/CommandLineSourceLoc.h
@@ -51,6 +51,52 @@ public:
}
};
+/// A source range that has been parsed on the command line.
+struct ParsedSourceRange {
+ std::string FileName;
+ /// The starting location of the range. The first element is the line and
+ /// the second element is the column.
+ std::pair<unsigned, unsigned> Begin;
+ /// The ending location of the range. The first element is the line and the
+ /// second element is the column.
+ std::pair<unsigned, unsigned> End;
+
+ /// Returns a parsed source range from a string or None if the string is
+ /// invalid.
+ ///
+ /// These source string has the following format:
+ ///
+ /// file:start_line:start_column[-end_line:end_column]
+ ///
+ /// If the end line and column are omitted, the starting line and columns
+ /// are used as the end values.
+ static Optional<ParsedSourceRange> fromString(StringRef Str) {
+ std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-');
+ unsigned EndLine, EndColumn;
+ bool HasEndLoc = false;
+ if (!RangeSplit.second.empty()) {
+ std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':');
+ if (Split.first.getAsInteger(10, EndLine) ||
+ Split.second.getAsInteger(10, EndColumn)) {
+ // The string does not end in end_line:end_column, so the '-'
+ // probably belongs to the filename which menas the whole
+ // string should be parsed.
+ RangeSplit.first = Str;
+ } else
+ HasEndLoc = true;
+ }
+ auto Begin = ParsedSourceLocation::FromString(RangeSplit.first);
+ if (Begin.FileName.empty())
+ return None;
+ if (!HasEndLoc) {
+ EndLine = Begin.Line;
+ EndColumn = Begin.Column;
+ }
+ return ParsedSourceRange{std::move(Begin.FileName),
+ {Begin.Line, Begin.Column},
+ {EndLine, EndColumn}};
+ }
+};
}
namespace llvm {
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 91d9198ddf..90a9501475 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;
@@ -132,6 +136,13 @@ class CompilerInstance : public ModuleLoader {
/// along with the module map
llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
+ /// \brief The set of top-level modules that has already been built on the
+ /// fly as part of this overall compilation action.
+ std::map<std::string, std::string> BuiltModules;
+
+ /// Should we delete the BuiltModules when we're done?
+ bool DeleteBuiltModules = true;
+
/// \brief The location of the module-import keyword for the last module
/// import.
SourceLocation LastModuleImportLoc;
@@ -178,7 +189,7 @@ public:
explicit CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>(),
- bool BuildingModule = false);
+ MemoryBufferCache *SharedPCMCache = nullptr);
~CompilerInstance() override;
/// @name High-Level Operations
@@ -629,7 +640,9 @@ public:
const CodeGenOptions *CodeGenOpts = nullptr);
/// Create the file manager and replace any existing one with it.
- void createFileManager();
+ ///
+ /// \return The new file manager on success, or null on failure.
+ FileManager *createFileManager();
/// Create the source manager and replace any existing one with it.
void createSourceManager(FileManager &FileMgr);
@@ -658,6 +671,8 @@ public:
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
+ DependencyFileGenerator *DependencyFile,
+ ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors,
void *DeserializationListener, bool OwnDeserializationListener,
bool Preamble, bool UseGlobalModuleIndex);
@@ -767,6 +782,9 @@ public:
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
+ void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName,
+ StringRef Source) override;
+
void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) override;
@@ -783,6 +801,8 @@ public:
}
void setExternalSemaSource(IntrusiveRefCntPtr<ExternalSemaSource> ESS);
+
+ MemoryBufferCache &getPCMCache() const { return *PCMCache; }
};
} // end namespace clang
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index cef7f73eca..8c4c932190 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -225,6 +225,11 @@ IntrusiveRefCntPtr<vfs::FileSystem>
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
DiagnosticsEngine &Diags);
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> BaseFS);
+
} // end namespace clang
#endif
diff --git a/include/clang/Frontend/DiagnosticRenderer.h b/include/clang/Frontend/DiagnosticRenderer.h
index 2588feb2b8..e453d7db62 100644
--- a/include/clang/Frontend/DiagnosticRenderer.h
+++ b/include/clang/Frontend/DiagnosticRenderer.h
@@ -70,33 +70,27 @@ protected:
DiagnosticOptions *DiagOpts);
virtual ~DiagnosticRenderer();
-
- virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
+
+ virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag Info) = 0;
-
- virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+
+ virtual void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) = 0;
+ ArrayRef<CharSourceRange> Ranges) = 0;
- virtual void emitCodeContext(SourceLocation Loc,
+ virtual void emitCodeContext(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) = 0;
-
- virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
- const SourceManager &SM) = 0;
- virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) = 0;
- virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) = 0;
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) = 0;
+
+ virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) = 0;
+ virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) = 0;
+ virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) = 0;
virtual void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {}
@@ -106,25 +100,21 @@ protected:
private:
void emitBasicNote(StringRef Message);
- void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc,
- DiagnosticsEngine::Level Level, const SourceManager &SM);
- void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM);
- void emitImportStack(SourceLocation Loc, const SourceManager &SM);
- void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName,
- const SourceManager &SM);
+ void emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level);
+ void emitIncludeStackRecursively(FullSourceLoc Loc);
+ void emitImportStack(FullSourceLoc Loc);
+ void emitImportStackRecursively(FullSourceLoc Loc, StringRef ModuleName);
void emitModuleBuildStack(const SourceManager &SM);
- void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
- void emitSingleMacroExpansion(SourceLocation Loc,
+ void emitCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints);
+ void emitSingleMacroExpansion(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM);
- void emitMacroExpansions(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges);
+ void emitMacroExpansions(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
+ ArrayRef<FixItHint> Hints);
+
public:
/// \brief Emit a diagnostic.
///
@@ -138,12 +128,9 @@ public:
/// \param Message The diagnostic message to emit.
/// \param Ranges The underlined ranges for this code snippet.
/// \param FixItHints The FixIt hints active for this diagnostic.
- /// \param SM The SourceManager; will be null if the diagnostic came from the
- /// frontend, thus \p Loc will be invalid.
- void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
+ void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
StringRef Message, ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixItHints,
- const SourceManager *SM,
DiagOrStoredDiag D = (Diagnostic *)nullptr);
void emitStoredDiagnostic(StoredDiagnostic &Diag);
@@ -159,19 +146,15 @@ public:
~DiagnosticNoteRenderer() override;
- void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
- const SourceManager &SM) override;
+ void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override;
- void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
- void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
- virtual void emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) = 0;
+ virtual void emitNote(FullSourceLoc Loc, StringRef Message) = 0;
};
} // end clang namespace
#endif
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index 384499a3d8..7ae6173512 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -76,8 +76,7 @@ protected:
///
/// \return True on success; on failure ExecutionAction() and
/// EndSourceFileAction() will not be called.
- virtual bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+ virtual bool BeginSourceFileAction(CompilerInstance &CI) {
return true;
}
@@ -146,6 +145,8 @@ public:
return *CurrentASTUnit;
}
+ Module *getCurrentModule() const;
+
std::unique_ptr<ASTUnit> takeCurrentASTUnit() {
return std::move(CurrentASTUnit);
}
@@ -174,10 +175,10 @@ public:
virtual TranslationUnitKind getTranslationUnitKind() { return TU_Complete; }
/// \brief Does this action support use with PCH?
- virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); }
+ virtual bool hasPCHSupport() const { return true; }
/// \brief Does this action support use with AST files?
- virtual bool hasASTFileSupport() const { return !usesPreprocessorOnly(); }
+ virtual bool hasASTFileSupport() const { return true; }
/// \brief Does this action support use with IR files?
virtual bool hasIRSupport() const { return false; }
@@ -289,7 +290,7 @@ protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
bool BeginInvocation(CompilerInstance &CI) override;
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void ExecuteAction() override;
void EndSourceFileAction() override;
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 778b40b15d..c45aeaa208 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -91,7 +91,7 @@ public:
ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile,
std::string &Sysroot, std::string &OutputFile);
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
};
class GenerateModuleAction : public ASTFrontendAction {
@@ -99,8 +99,6 @@ class GenerateModuleAction : public ASTFrontendAction {
CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0;
protected:
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
-
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
@@ -112,25 +110,16 @@ protected:
};
class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
- clang::Module *Module = nullptr;
- const FileEntry *ModuleMapForUniquing = nullptr;
- bool IsSystem = false;
-
private:
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
-
-public:
- GenerateModuleFromModuleMapAction() {}
- GenerateModuleFromModuleMapAction(const FileEntry *ModuleMap, bool IsSystem)
- : ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) {}
};
class GenerateModuleInterfaceAction : public GenerateModuleAction {
private:
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
@@ -192,8 +181,7 @@ protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
- bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void ExecuteAction() override;
void EndSourceFileAction() override;
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 4fd0f82a3a..5192a3774c 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -23,6 +23,7 @@ class MemoryBuffer;
}
namespace clang {
+class FileEntry;
namespace frontend {
enum ActionKind {
@@ -62,46 +63,89 @@ namespace frontend {
};
}
-enum InputKind {
- IK_None,
- IK_Asm,
- IK_C,
- IK_CXX,
- IK_ObjC,
- IK_ObjCXX,
- IK_PreprocessedC,
- IK_PreprocessedCXX,
- IK_PreprocessedObjC,
- IK_PreprocessedObjCXX,
- IK_OpenCL,
- IK_CUDA,
- IK_PreprocessedCuda,
- IK_RenderScript,
- IK_AST,
- IK_LLVM_IR
-};
+/// The kind of a file that we've been handed as an input.
+class InputKind {
+private:
+ unsigned Lang : 4;
+ unsigned Fmt : 3;
+ unsigned Preprocessed : 1;
+
+public:
+ /// The language for the input, used to select and validate the language
+ /// standard and possible actions.
+ enum Language {
+ Unknown,
+
+ /// Assembly: we accept this only so that we can preprocess it.
+ Asm,
+
+ /// LLVM IR: we accept this so that we can run the optimizer on it,
+ /// and compile it to assembly or object code.
+ LLVM_IR,
+
+ ///@{ Languages that the frontend can parse and compile.
+ C,
+ CXX,
+ ObjC,
+ ObjCXX,
+ OpenCL,
+ CUDA,
+ RenderScript,
+ ///@}
+ };
+
+ /// The input file format.
+ enum Format {
+ Source,
+ ModuleMap,
+ Precompiled
+ };
+
+ constexpr InputKind(Language L = Unknown, Format F = Source,
+ bool PP = false)
+ : Lang(L), Fmt(F), Preprocessed(PP) {}
+
+ Language getLanguage() const { return static_cast<Language>(Lang); }
+ Format getFormat() const { return static_cast<Format>(Fmt); }
+ bool isPreprocessed() const { return Preprocessed; }
+ /// Is the input kind fully-unknown?
+ bool isUnknown() const { return Lang == Unknown && Fmt == Source; }
+
+ /// Is the language of the input some dialect of Objective-C?
+ bool isObjectiveC() const { return Lang == ObjC || Lang == ObjCXX; }
+
+ InputKind getPreprocessed() const {
+ return InputKind(getLanguage(), getFormat(), true);
+ }
+ InputKind withFormat(Format F) const {
+ return InputKind(getLanguage(), F, isPreprocessed());
+ }
+};
/// \brief An input file for the front end.
class FrontendInputFile {
/// \brief The file name, or "-" to read from standard input.
std::string File;
- llvm::MemoryBuffer *Buffer;
+ /// The input, if it comes from a buffer rather than a file. This object
+ /// does not own the buffer, and the caller is responsible for ensuring
+ /// that it outlives any users.
+ llvm::MemoryBuffer *Buffer = nullptr;
/// \brief The kind of input, e.g., C source, AST file, LLVM IR.
InputKind Kind;
/// \brief Whether we're dealing with a 'system' input (vs. a 'user' input).
- bool IsSystem;
+ bool IsSystem = false;
public:
- FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { }
+ FrontendInputFile() { }
FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false)
- : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { }
- FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind,
+ : File(File.str()), Kind(Kind), IsSystem(IsSystem) { }
+ FrontendInputFile(llvm::MemoryBuffer *Buffer, InputKind Kind,
bool IsSystem = false)
- : Buffer(buffer), Kind(Kind), IsSystem(IsSystem) { }
+ : Buffer(Buffer), Kind(Kind), IsSystem(IsSystem) { }
InputKind getKind() const { return Kind; }
bool isSystem() const { return IsSystem; }
@@ -109,13 +153,7 @@ public:
bool isEmpty() const { return File.empty() && Buffer == nullptr; }
bool isFile() const { return !isBuffer(); }
bool isBuffer() const { return Buffer != nullptr; }
- bool isPreprocessed() const {
- return Kind == IK_PreprocessedC ||
- Kind == IK_PreprocessedCXX ||
- Kind == IK_PreprocessedObjC ||
- Kind == IK_PreprocessedObjCXX ||
- Kind == IK_PreprocessedCuda;
- }
+ bool isPreprocessed() const { return Kind.isPreprocessed(); }
StringRef getFile() const {
assert(isFile());
@@ -224,6 +262,10 @@ public:
/// The input files and their types.
std::vector<FrontendInputFile> Inputs;
+ /// When the input is a module map, the original module map file from which
+ /// that map was inferred, if any (for umbrella modules).
+ std::string OriginalModuleMap;
+
/// The output file, if any.
std::string OutputFile;
@@ -278,8 +320,8 @@ public:
/// \brief Auxiliary triple for CUDA compilation.
std::string AuxTriple;
- /// \brief If non-empty, search the pch input file as it was a header
- // included by this file.
+ /// \brief If non-empty, search the pch input file as if it was a header
+ /// included by this file.
std::string FindPchSource;
/// Filename to write statistics to.
@@ -299,10 +341,10 @@ public:
{}
/// getInputKindForExtension - Return the appropriate input kind for a file
- /// extension. For example, "c" would return IK_C.
+ /// extension. For example, "c" would return InputKind::C.
///
- /// \return The input kind for the extension, or IK_None if the extension is
- /// not recognized.
+ /// \return The input kind for the extension, or InputKind::Unknown if the
+ /// extension is not recognized.
static InputKind getInputKindForExtension(StringRef Extension);
};
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index 5ead90f007..6731e08bca 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H
#include "clang/Basic/LLVM.h"
+#include "clang/Frontend/FrontendOptions.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
@@ -19,13 +20,13 @@ namespace frontend {
enum LangFeatures {
LineComment = (1 << 0),
- C89 = (1 << 1),
- C99 = (1 << 2),
- C11 = (1 << 3),
- CPlusPlus = (1 << 4),
- CPlusPlus11 = (1 << 5),
- CPlusPlus14 = (1 << 6),
- CPlusPlus1z = (1 << 7),
+ C99 = (1 << 1),
+ C11 = (1 << 2),
+ CPlusPlus = (1 << 3),
+ CPlusPlus11 = (1 << 4),
+ CPlusPlus14 = (1 << 5),
+ CPlusPlus1z = (1 << 6),
+ CPlusPlus2a = (1 << 7),
Digraphs = (1 << 8),
GNUMode = (1 << 9),
HexFloat = (1 << 10),
@@ -39,7 +40,7 @@ enum LangFeatures {
/// standard.
struct LangStandard {
enum Kind {
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
lang_##id,
#include "clang/Frontend/LangStandards.def"
lang_unspecified
@@ -48,6 +49,7 @@ struct LangStandard {
const char *ShortName;
const char *Description;
unsigned Flags;
+ InputKind::Language Language;
public:
/// getName - Get the name of this standard.
@@ -56,12 +58,12 @@ public:
/// getDescription - Get the description of this standard.
const char *getDescription() const { return Description; }
+ /// Get the language that this standard describes.
+ InputKind::Language getLanguage() const { return Language; }
+
/// Language supports '//' comments.
bool hasLineComments() const { return Flags & frontend::LineComment; }
- /// isC89 - Language is a superset of C89.
- bool isC89() const { return Flags & frontend::C89; }
-
/// isC99 - Language is a superset of C99.
bool isC99() const { return Flags & frontend::C99; }
@@ -80,6 +82,10 @@ public:
/// isCPlusPlus1z - Language is a C++17 variant (or later).
bool isCPlusPlus1z() const { return Flags & frontend::CPlusPlus1z; }
+ /// isCPlusPlus2a - Language is a post-C++17 variant (or later).
+ bool isCPlusPlus2a() const { return Flags & frontend::CPlusPlus2a; }
+
+
/// hasDigraphs - Language supports digraphs.
bool hasDigraphs() const { return Flags & frontend::Digraphs; }
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index 425ac84bf6..a019d63922 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -11,10 +11,11 @@
#error "LANGSTANDARD must be defined before including this file"
#endif
-/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES)
+/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES)
///
/// \param IDENT - The name of the standard as a C++ identifier.
/// \param NAME - The name of the standard.
+/// \param LANG - The InputKind::Language for which this is a standard.
/// \param DESC - A short description of the standard.
/// \param FEATURES - The standard features as flags, these are enums from the
/// clang::frontend namespace, which is assumed to be be available.
@@ -23,146 +24,138 @@
/// \param IDENT - The name of the standard as a C++ identifier.
/// \param ALIAS - The alias of the standard.
+/// LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS)
+/// Same as LANGSTANDARD_ALIAS, but for a deprecated alias.
+
#ifndef LANGSTANDARD_ALIAS
#define LANGSTANDARD_ALIAS(IDENT, ALIAS)
#endif
+#ifndef LANGSTANDARD_ALIAS_DEPR
+#define LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) LANGSTANDARD_ALIAS(IDENT, ALIAS)
+#endif
+
// C89-ish modes.
LANGSTANDARD(c89, "c89",
- "ISO C 1990",
- C89 | ImplicitInt)
-LANGSTANDARD(c90, "c90",
- "ISO C 1990",
- C89 | ImplicitInt)
-LANGSTANDARD(iso9899_1990, "iso9899:1990",
- "ISO C 1990",
- C89 | ImplicitInt)
+ C, "ISO C 1990",
+ ImplicitInt)
+LANGSTANDARD_ALIAS(c89, "c90")
+LANGSTANDARD_ALIAS(c89, "iso9899:1990")
LANGSTANDARD(c94, "iso9899:199409",
- "ISO C 1990 with amendment 1",
- C89 | Digraphs | ImplicitInt)
+ C, "ISO C 1990 with amendment 1",
+ Digraphs | ImplicitInt)
LANGSTANDARD(gnu89, "gnu89",
- "ISO C 1990 with GNU extensions",
- LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
-LANGSTANDARD(gnu90, "gnu90",
- "ISO C 1990 with GNU extensions",
- LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
+ C, "ISO C 1990 with GNU extensions",
+ LineComment | Digraphs | GNUMode | ImplicitInt)
+LANGSTANDARD_ALIAS(gnu89, "gnu90")
// C99-ish modes
LANGSTANDARD(c99, "c99",
- "ISO C 1999",
- LineComment | C99 | Digraphs | HexFloat)
-LANGSTANDARD(c9x, "c9x",
- "ISO C 1999",
- LineComment | C99 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_1999,
- "iso9899:1999", "ISO C 1999",
- LineComment | C99 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_199x,
- "iso9899:199x", "ISO C 1999",
+ C, "ISO C 1999",
LineComment | C99 | Digraphs | HexFloat)
+LANGSTANDARD_ALIAS(c99, "iso9899:1999")
+LANGSTANDARD_ALIAS_DEPR(c99, "c9x")
+LANGSTANDARD_ALIAS_DEPR(c99, "iso9899:199x")
LANGSTANDARD(gnu99, "gnu99",
- "ISO C 1999 with GNU extensions",
- LineComment | C99 | Digraphs | GNUMode | HexFloat)
-LANGSTANDARD(gnu9x, "gnu9x",
- "ISO C 1999 with GNU extensions",
+ C, "ISO C 1999 with GNU extensions",
LineComment | C99 | Digraphs | GNUMode | HexFloat)
+LANGSTANDARD_ALIAS_DEPR(gnu99, "gnu9x")
// C11 modes
LANGSTANDARD(c11, "c11",
- "ISO C 2011",
- LineComment | C99 | C11 | Digraphs | HexFloat)
-LANGSTANDARD(c1x, "c1x",
- "ISO C 2011",
- LineComment | C99 | C11 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_2011,
- "iso9899:2011", "ISO C 2011",
- LineComment | C99 | C11 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_201x,
- "iso9899:201x", "ISO C 2011",
+ C, "ISO C 2011",
LineComment | C99 | C11 | Digraphs | HexFloat)
+LANGSTANDARD_ALIAS(c11, "iso9899:2011")
+LANGSTANDARD_ALIAS_DEPR(c11, "c1x")
+LANGSTANDARD_ALIAS_DEPR(c11, "iso9899:201x")
LANGSTANDARD(gnu11, "gnu11",
- "ISO C 2011 with GNU extensions",
- LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
-LANGSTANDARD(gnu1x, "gnu1x",
- "ISO C 2011 with GNU extensions",
+ C, "ISO C 2011 with GNU extensions",
LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
+LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x")
// C++ modes
LANGSTANDARD(cxx98, "c++98",
- "ISO C++ 1998 with amendments",
- LineComment | CPlusPlus | Digraphs)
-LANGSTANDARD(cxx03, "c++03",
- "ISO C++ 1998 with amendments",
+ CXX, "ISO C++ 1998 with amendments",
LineComment | CPlusPlus | Digraphs)
+LANGSTANDARD_ALIAS(cxx98, "c++03")
+
LANGSTANDARD(gnucxx98, "gnu++98",
- "ISO C++ 1998 with amendments and GNU extensions",
+ CXX, "ISO C++ 1998 with amendments and GNU extensions",
LineComment | CPlusPlus | Digraphs | GNUMode)
+LANGSTANDARD_ALIAS(gnucxx98, "gnu++03")
-LANGSTANDARD(cxx0x, "c++0x",
- "ISO C++ 2011 with amendments",
- LineComment | CPlusPlus | CPlusPlus11 | Digraphs)
LANGSTANDARD(cxx11, "c++11",
- "ISO C++ 2011 with amendments",
+ CXX, "ISO C++ 2011 with amendments",
LineComment | CPlusPlus | CPlusPlus11 | Digraphs)
-LANGSTANDARD(gnucxx0x, "gnu++0x",
- "ISO C++ 2011 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode)
-LANGSTANDARD(gnucxx11, "gnu++11",
+LANGSTANDARD_ALIAS_DEPR(cxx11, "c++0x")
+
+LANGSTANDARD(gnucxx11, "gnu++11", CXX,
"ISO C++ 2011 with amendments and GNU extensions",
LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode)
+LANGSTANDARD_ALIAS_DEPR(gnucxx11, "gnu++0x")
-LANGSTANDARD(cxx1y, "c++1y",
- "ISO C++ 2014 with amendments",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs)
LANGSTANDARD(cxx14, "c++14",
- "ISO C++ 2014 with amendments",
+ CXX, "ISO C++ 2014 with amendments",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs)
-LANGSTANDARD(gnucxx1y, "gnu++1y",
- "ISO C++ 2014 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs |
- GNUMode)
+LANGSTANDARD_ALIAS_DEPR(cxx14, "c++1y")
+
LANGSTANDARD(gnucxx14, "gnu++14",
- "ISO C++ 2014 with amendments and GNU extensions",
+ CXX, "ISO C++ 2014 with amendments and GNU extensions",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs |
GNUMode)
+LANGSTANDARD_ALIAS_DEPR(gnucxx14, "gnu++1y")
-LANGSTANDARD(cxx1z, "c++1z",
- "Working draft for ISO C++ 2017",
+LANGSTANDARD(cxx17, "c++17",
+ CXX, "ISO C++ 2017 with amendments",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
Digraphs | HexFloat)
-LANGSTANDARD(gnucxx1z, "gnu++1z",
- "Working draft for ISO C++ 2017 with GNU extensions",
+LANGSTANDARD_ALIAS_DEPR(cxx17, "c++1z")
+
+LANGSTANDARD(gnucxx17, "gnu++17",
+ CXX, "ISO C++ 2017 with amendments and GNU extensions",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
Digraphs | HexFloat | GNUMode)
+LANGSTANDARD_ALIAS_DEPR(gnucxx17, "gnu++1z")
+
+LANGSTANDARD(cxx2a, "c++2a",
+ CXX, "Working draft for ISO C++ 2020",
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
+ CPlusPlus2a | Digraphs | HexFloat)
+
+LANGSTANDARD(gnucxx2a, "gnu++2a",
+ CXX, "Working draft for ISO C++ 2020 with GNU extensions",
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
+ CPlusPlus2a | Digraphs | HexFloat | GNUMode)
// OpenCL
-LANGSTANDARD(opencl, "cl",
- "OpenCL 1.0",
+LANGSTANDARD(opencl10, "cl1.0",
+ OpenCL, "OpenCL 1.0",
LineComment | C99 | Digraphs | HexFloat | OpenCL)
+LANGSTANDARD_ALIAS_DEPR(opencl10, "cl")
+
LANGSTANDARD(opencl11, "cl1.1",
- "OpenCL 1.1",
+ OpenCL, "OpenCL 1.1",
LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD(opencl12, "cl1.2",
- "OpenCL 1.2",
+ OpenCL, "OpenCL 1.2",
LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD(opencl20, "cl2.0",
- "OpenCL 2.0",
+ OpenCL, "OpenCL 2.0",
LineComment | C99 | Digraphs | HexFloat | OpenCL)
-LANGSTANDARD_ALIAS(opencl, "CL")
-LANGSTANDARD_ALIAS(opencl11, "CL1.1")
-LANGSTANDARD_ALIAS(opencl12, "CL1.2")
-LANGSTANDARD_ALIAS(opencl20, "CL2.0")
+LANGSTANDARD_ALIAS_DEPR(opencl10, "CL")
+LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1")
+LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2")
+LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0")
// CUDA
-LANGSTANDARD(cuda, "cuda",
- "NVIDIA CUDA(tm)",
+LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)",
LineComment | CPlusPlus | Digraphs)
#undef LANGSTANDARD
#undef LANGSTANDARD_ALIAS
-
+#undef LANGSTANDARD_ALIAS_DEPR
diff --git a/include/clang/Frontend/PrecompiledPreamble.h b/include/clang/Frontend/PrecompiledPreamble.h
new file mode 100644
index 0000000000..6b0b6261e4
--- /dev/null
+++ b/include/clang/Frontend/PrecompiledPreamble.h
@@ -0,0 +1,236 @@
+//===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper class to build precompiled preamble.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
+#define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
+
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/MD5.h"
+#include <memory>
+#include <system_error>
+#include <type_traits>
+
+namespace llvm {
+class MemoryBuffer;
+}
+
+namespace clang {
+namespace vfs {
+class FileSystem;
+}
+
+class CompilerInstance;
+class CompilerInvocation;
+class DeclGroupRef;
+class PCHContainerOperations;
+
+/// \brief Runs lexer to compute suggested preamble bounds.
+PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
+ llvm::MemoryBuffer *Buffer,
+ unsigned MaxLines);
+
+class PreambleCallbacks;
+
+/// A class holding a PCH and all information to check whether it is valid to
+/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
+/// CanReusePreamble + AddImplicitPreamble to make use of it.
+class PrecompiledPreamble {
+ class TempPCHFile;
+ struct PreambleFileHash;
+
+public:
+ /// \brief Try to build PrecompiledPreamble for \p Invocation. See
+ /// BuildPreambleError for possible error codes.
+ ///
+ /// \param Invocation Original CompilerInvocation with options to compile the
+ /// file.
+ ///
+ /// \param MainFileBuffer Buffer with the contents of the main file.
+ ///
+ /// \param Bounds Bounds of the preamble, result of calling
+ /// ComputePreambleBounds.
+ ///
+ /// \param Diagnostics Diagnostics engine to be used while building the
+ /// preamble.
+ ///
+ /// \param VFS An instance of vfs::FileSystem to be used for file
+ /// accesses.
+ ///
+ /// \param PCHContainerOps An instance of PCHContainerOperations.
+ ///
+ /// \param Callbacks A set of callbacks to be executed when building
+ /// the preamble.
+ static llvm::ErrorOr<PrecompiledPreamble>
+ Build(const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+ DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ PreambleCallbacks &Callbacks);
+
+ PrecompiledPreamble(PrecompiledPreamble &&) = default;
+ PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default;
+
+ /// PreambleBounds used to build the preamble.
+ PreambleBounds getBounds() const;
+
+ /// The temporary file path at which the preamble PCH was placed.
+ StringRef GetPCHPath() const { return PCHFile.getFilePath(); }
+
+ /// Check whether PrecompiledPreamble can be reused for the new contents(\p
+ /// MainFileBuffer) of the main file.
+ bool CanReuse(const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+ vfs::FileSystem *VFS) const;
+
+ /// Changes options inside \p CI to use PCH from this preamble. Also remaps
+ /// main file to \p MainFileBuffer.
+ void AddImplicitPreamble(CompilerInvocation &CI,
+ llvm::MemoryBuffer *MainFileBuffer) const;
+
+private:
+ PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes,
+ bool PreambleEndsAtStartOfLine,
+ llvm::StringMap<PreambleFileHash> FilesInPreamble);
+
+ /// A temp file that would be deleted on destructor call. If destructor is not
+ /// called for any reason, the file will be deleted at static objects'
+ /// destruction.
+ /// An assertion will fire if two TempPCHFiles are created with the same name,
+ /// so it's not intended to be used outside preamble-handling.
+ class TempPCHFile {
+ public:
+ // A main method used to construct TempPCHFile.
+ static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
+
+ /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file.
+ static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix,
+ StringRef Suffix);
+ /// Create a new instance of TemporaryFile for file at \p Path. Use with
+ /// extreme caution, there's an assertion checking that there's only a
+ /// single instance of TempPCHFile alive for each path.
+ static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path);
+
+ private:
+ TempPCHFile(std::string FilePath);
+
+ public:
+ TempPCHFile(TempPCHFile &&Other);
+ TempPCHFile &operator=(TempPCHFile &&Other);
+
+ TempPCHFile(const TempPCHFile &) = delete;
+ ~TempPCHFile();
+
+ /// A path where temporary file is stored.
+ llvm::StringRef getFilePath() const;
+
+ private:
+ void RemoveFileIfPresent();
+
+ private:
+ llvm::Optional<std::string> FilePath;
+ };
+
+ /// Data used to determine if a file used in the preamble has been changed.
+ struct PreambleFileHash {
+ /// All files have size set.
+ off_t Size = 0;
+
+ /// Modification time is set for files that are on disk. For memory
+ /// buffers it is zero.
+ time_t ModTime = 0;
+
+ /// Memory buffers have MD5 instead of modification time. We don't
+ /// compute MD5 for on-disk files because we hope that modification time is
+ /// enough to tell if the file was changed.
+ llvm::MD5::MD5Result MD5 = {};
+
+ static PreambleFileHash createForFile(off_t Size, time_t ModTime);
+ static PreambleFileHash
+ createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
+
+ friend bool operator==(const PreambleFileHash &LHS,
+ const PreambleFileHash &RHS) {
+ return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
+ LHS.MD5 == RHS.MD5;
+ }
+ friend bool operator!=(const PreambleFileHash &LHS,
+ const PreambleFileHash &RHS) {
+ return !(LHS == RHS);
+ }
+ };
+
+ /// Manages the lifetime of temporary file that stores a PCH.
+ TempPCHFile PCHFile;
+ /// Keeps track of the files that were used when computing the
+ /// preamble, with both their buffer size and their modification time.
+ ///
+ /// If any of the files have changed from one compile to the next,
+ /// the preamble must be thrown away.
+ llvm::StringMap<PreambleFileHash> FilesInPreamble;
+ /// The contents of the file that was used to precompile the preamble. Only
+ /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
+ /// part of the file has not changed, so that preamble can be reused.
+ std::vector<char> PreambleBytes;
+ /// See PreambleBounds::PreambleEndsAtStartOfLine
+ bool PreambleEndsAtStartOfLine;
+};
+
+/// A set of callbacks to gather useful information while building a preamble.
+class PreambleCallbacks {
+public:
+ virtual ~PreambleCallbacks() = default;
+
+ /// Called after FrontendAction::Execute(), but before
+ /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
+ /// various CompilerInstance fields before they are destroyed.
+ virtual void AfterExecute(CompilerInstance &CI);
+ /// Called after PCH has been emitted. \p Writer may be used to retrieve
+ /// information about AST, serialized in PCH.
+ virtual void AfterPCHEmitted(ASTWriter &Writer);
+ /// Called for each TopLevelDecl.
+ /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
+ /// used instead, but having only this method allows a simpler API.
+ virtual void HandleTopLevelDecl(DeclGroupRef DG);
+ /// Called for each macro defined in the Preamble.
+ /// NOTE: To allow more flexibility a custom PPCallbacks could probably be
+ /// used instead, but having only this method allows a simpler API.
+ virtual void HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD);
+};
+
+enum class BuildPreambleError {
+ PreambleIsEmpty = 1,
+ CouldntCreateTempFile,
+ CouldntCreateTargetInfo,
+ CouldntCreateVFSOverlay,
+ BeginSourceFileFailed,
+ CouldntEmitPCH
+};
+
+class BuildPreambleErrorCategory final : public std::error_category {
+public:
+ const char *name() const noexcept override;
+ std::string message(int condition) const override;
+};
+
+std::error_code make_error_code(BuildPreambleError Error);
+} // namespace clang
+
+namespace std {
+template <>
+struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
+} // namespace std
+
+#endif
diff --git a/include/clang/Frontend/PreprocessorOutputOptions.h b/include/clang/Frontend/PreprocessorOutputOptions.h
index 3261b66538..94afcd06a3 100644
--- a/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -24,6 +24,7 @@ public:
unsigned ShowMacros : 1; ///< Print macro definitions.
unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output.
unsigned RewriteIncludes : 1; ///< Preprocess include directives only.
+ unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules.
public:
PreprocessorOutputOptions() {
@@ -35,6 +36,7 @@ public:
ShowMacros = 0;
ShowIncludeDirectives = 0;
RewriteIncludes = 0;
+ RewriteImports = 0;
}
};
diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h
index 9b108c28bd..1bbfe9fa02 100644
--- a/include/clang/Frontend/TextDiagnostic.h
+++ b/include/clang/Frontend/TextDiagnostic.h
@@ -75,44 +75,35 @@ public:
unsigned Columns, bool ShowColors);
protected:
- void emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
+ void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag D) override;
- void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) override;
-
- void emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) override {
- emitSnippetAndCaret(Loc, Level, Ranges, Hints, SM);
+ ArrayRef<CharSourceRange> Ranges) override;
+
+ void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) override {
+ emitSnippetAndCaret(Loc, Level, Ranges, Hints);
}
- void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
- const SourceManager &SM) override;
+ void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override;
- void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
- void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
private:
void emitFilename(StringRef Filename, const SourceManager &SM);
- void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
+ void emitSnippetAndCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints);
void emitSnippet(StringRef SourceLine);
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 0ee46846c8..8ccc31982d 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -184,10 +184,11 @@ createChainedIncludesSource(CompilerInstance &CI,
///
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
-std::unique_ptr<CompilerInvocation>
-createInvocationFromCommandLine(ArrayRef<const char *> Args,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
- IntrusiveRefCntPtr<DiagnosticsEngine>());
+std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine(
+ ArrayRef<const char *> Args,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ IntrusiveRefCntPtr<DiagnosticsEngine>(),
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
/// Return the value of the last argument as an integer, or a default. If Diags
/// is non-null, emits an error if the argument is given, but non-integral.
diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 475f07f9dc..8d71fb98b0 100644
--- a/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -176,7 +176,8 @@ public:
: DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) {
assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
- assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!");
+ assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
+ "DiagnosticLoc is invalid!");
}
private:
diff --git a/include/clang/Index/IndexSymbol.h b/include/clang/Index/IndexSymbol.h
index eb718d782d..ae591364f2 100644
--- a/include/clang/Index/IndexSymbol.h
+++ b/include/clang/Index/IndexSymbol.h
@@ -53,12 +53,14 @@ enum class SymbolKind : uint8_t {
ConversionFunction,
Parameter,
+ Using,
};
enum class SymbolLanguage {
C,
ObjC,
CXX,
+ Swift,
};
/// Language specific sub-kinds.
@@ -68,6 +70,8 @@ enum class SymbolSubKind {
CXXMoveConstructor,
AccessorGetter,
AccessorSetter,
+ UsingTypename,
+ UsingValue,
};
/// Set of properties that provide additional info about a symbol.
@@ -106,8 +110,9 @@ enum class SymbolRole : uint32_t {
RelationAccessorOf = 1 << 15,
RelationContainedBy = 1 << 16,
RelationIBTypeOf = 1 << 17,
+ RelationSpecializationOf = 1 << 18,
};
-static const unsigned SymbolRoleBitNum = 18;
+static const unsigned SymbolRoleBitNum = 19;
typedef unsigned SymbolRoleSet;
/// Represents a relation to another symbol for a symbol occurrence.
@@ -132,6 +137,8 @@ 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 8eed33c612..fb703be4e5 100644
--- a/include/clang/Index/IndexingAction.h
+++ b/include/clang/Index/IndexingAction.h
@@ -11,11 +11,14 @@
#define LLVM_CLANG_INDEX_INDEXINGACTION_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
#include <memory>
namespace clang {
+ class ASTContext;
class ASTReader;
class ASTUnit;
+ class Decl;
class FrontendAction;
namespace serialization {
@@ -47,8 +50,11 @@ void indexASTUnit(ASTUnit &Unit,
std::shared_ptr<IndexDataConsumer> DataConsumer,
IndexingOptions Opts);
-void indexModuleFile(serialization::ModuleFile &Mod,
- ASTReader &Reader,
+void indexTopLevelDecls(ASTContext &Ctx, ArrayRef<const Decl *> Decls,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts);
+
+void indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader,
std::shared_ptr<IndexDataConsumer> DataConsumer,
IndexingOptions Opts);
diff --git a/include/clang/Index/USRGeneration.h b/include/clang/Index/USRGeneration.h
index 61f2c9d1ff..8c661bd63c 100644
--- a/include/clang/Index/USRGeneration.h
+++ b/include/clang/Index/USRGeneration.h
@@ -30,10 +30,14 @@ static inline StringRef getUSRSpacePrefix() {
bool generateUSRForDecl(const Decl *D, SmallVectorImpl<char> &Buf);
/// \brief Generate a USR fragment for an Objective-C class.
-void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS);
+void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS,
+ StringRef ExtSymbolDefinedIn = "",
+ StringRef CategoryContextExtSymbolDefinedIn = "");
/// \brief Generate a USR fragment for an Objective-C class category.
-void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS);
+void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS,
+ StringRef ClsExtSymbolDefinedIn = "",
+ StringRef CatExtSymbolDefinedIn = "");
/// \brief Generate a USR fragment for an Objective-C instance variable. The
/// complete USR can be created by concatenating the USR for the
@@ -48,7 +52,15 @@ void generateUSRForObjCMethod(StringRef Sel, bool IsInstanceMethod,
void generateUSRForObjCProperty(StringRef Prop, bool isClassProp, raw_ostream &OS);
/// \brief Generate a USR fragment for an Objective-C protocol.
-void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS);
+void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS,
+ StringRef ExtSymbolDefinedIn = "");
+
+/// Generate USR fragment for a global (non-nested) enum.
+void generateUSRForGlobalEnum(StringRef EnumName, raw_ostream &OS,
+ StringRef ExtSymbolDefinedIn = "");
+
+/// Generate a USR fragment for an enum constant.
+void generateUSRForEnumConstant(StringRef EnumConstantName, raw_ostream &OS);
/// \brief Generate a USR for a macro, including the USR prefix.
///
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 51983b9ab5..126bbdfc13 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -47,7 +47,7 @@ struct HeaderFileInfo {
/// whether it is C++ clean or not. This can be set by the include paths or
/// by \#pragma gcc system_header. This is an instance of
/// SrcMgr::CharacteristicKind.
- unsigned DirInfo : 2;
+ unsigned DirInfo : 3;
/// \brief Whether this header file info was supplied by an external source,
/// and has not changed since.
@@ -375,13 +375,16 @@ public:
/// \param SuggestedModule If non-null, and the file found is semantically
/// part of a known module, this will be set to the module that should
/// be imported instead of preprocessing/parsing the file found.
+ ///
+ /// \param IsMapped If non-null, and the search involved header maps, set to
+ /// true.
const FileEntry *LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache = false, bool BuildSystemModule = false);
+ bool *IsMapped, bool SkipCache = false, bool BuildSystemModule = false);
/// \brief Look up a subframework for the specified \#include file.
///
@@ -468,29 +471,41 @@ public:
/// \brief Get filenames for all registered header maps.
void getHeaderMapFileNames(SmallVectorImpl<std::string> &Names) const;
- /// \brief Retrieve the name of the module file that should be used to
- /// load the given module.
+ /// \brief Retrieve the name of the cached module file that should be used
+ /// to load the given module.
///
/// \param Module The module whose module file name will be returned.
///
/// \returns The name of the module file that corresponds to this module,
/// or an empty string if this module does not correspond to any module file.
- std::string getModuleFileName(Module *Module);
+ std::string getCachedModuleFileName(Module *Module);
- /// \brief Retrieve the name of the module file that should be used to
- /// load a module with the given name.
+ /// \brief Retrieve the name of the prebuilt module file that should be used
+ /// to load a module with the given name.
+ ///
+ /// \param ModuleName The module whose module file name will be returned.
+ ///
+ /// \param FileMapOnly If true, then only look in the explicit module name
+ // to file name map and skip the directory search.
+ ///
+ /// \returns The name of the module file that corresponds to this module,
+ /// or an empty string if this module does not correspond to any module file.
+ std::string getPrebuiltModuleFileName(StringRef ModuleName,
+ bool FileMapOnly = false);
+
+
+ /// \brief Retrieve the name of the (to-be-)cached module file that should
+ /// be used to load a module with the given name.
///
/// \param ModuleName The module whose module file name will be returned.
///
/// \param ModuleMapPath A path that when combined with \c ModuleName
/// uniquely identifies this module. See Module::ModuleMap.
///
- /// \param UsePrebuiltPath Whether we should use the prebuilt module path.
- ///
/// \returns The name of the module file that corresponds to this module,
/// or an empty string if this module does not correspond to any module file.
- std::string getModuleFileName(StringRef ModuleName, StringRef ModuleMapPath,
- bool UsePrebuiltPath);
+ std::string getCachedModuleFileName(StringRef ModuleName,
+ StringRef ModuleMapPath);
/// \brief Lookup a module Search for a module with the given name.
///
@@ -535,9 +550,18 @@ public:
///
/// \param File The module map file.
/// \param IsSystem Whether this file is in a system header directory.
- ///
+ /// \param ID If the module map file is already mapped (perhaps as part of
+ /// processing a preprocessed module), the ID of the file.
+ /// \param Offset [inout] An offset within ID to start parsing. On exit,
+ /// filled by the end of the parsed contents (either EOF or the
+ /// location of an end-of-module-map pragma).
+ /// \param OriginalModuleMapFile The original path to the module map file,
+ /// used to resolve paths within the module (this is required when
+ /// building the module from preprocessed source).
/// \returns true if an error occurred, false otherwise.
- bool loadModuleMapFile(const FileEntry *File, bool IsSystem);
+ bool loadModuleMapFile(const FileEntry *File, bool IsSystem,
+ FileID ID = FileID(), unsigned *Offset = nullptr,
+ StringRef OriginalModuleMapFile = StringRef());
/// \brief Collect the set of all known, top-level modules.
///
@@ -683,7 +707,9 @@ private:
LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File,
bool IsSystem,
- const DirectoryEntry *Dir);
+ const DirectoryEntry *Dir,
+ FileID ID = FileID(),
+ unsigned *Offset = nullptr);
/// \brief Try to load the module map file in the given directory.
///
diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index ca3a84e75e..356f500335 100644
--- a/include/clang/Lex/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/StringRef.h"
#include <string>
#include <vector>
+#include <map>
namespace clang {
@@ -94,6 +95,9 @@ public:
/// \brief The directory used for a user build.
std::string ModuleUserBuildPath;
+ /// \brief The mapping of module names to prebuilt module files.
+ std::map<std::string, std::string> PrebuiltModuleFiles;
+
/// \brief The directories used to load prebuilt module files.
std::vector<std::string> PrebuiltModulePaths;
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 830c25a2e4..603ce10f64 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -39,6 +39,23 @@ enum ConflictMarkerKind {
CMK_Perforce
};
+/// Describes the bounds (start, size) of the preamble and a flag required by
+/// PreprocessorOptions::PrecompiledPreambleBytes.
+/// The preamble includes the BOM, if any.
+struct PreambleBounds {
+ PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine)
+ : Size(Size),
+ PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
+
+ /// \brief Size of the preamble in bytes.
+ unsigned Size;
+ /// \brief Whether the preamble ends at the start of a new line.
+ ///
+ /// Used to inform the lexer as to whether it's starting at the beginning of
+ /// a line after skipping the preamble.
+ bool PreambleEndsAtStartOfLine;
+};
+
/// Lexer - This provides a simple interface that turns a text buffer into a
/// stream of tokens. This provides no support for file reading or buffering,
/// or buffering/seeking of tokens, only forward lexing is supported. It relies
@@ -443,11 +460,11 @@ public:
/// to fewer than this number of lines.
///
/// \returns The offset into the file where the preamble ends and the rest
- /// of the file begins along with a boolean value indicating whether
+ /// of the file begins along with a boolean value indicating whether
/// the preamble ends at the beginning of a new line.
- static std::pair<unsigned, bool> ComputePreamble(StringRef Buffer,
- const LangOptions &LangOpts,
- unsigned MaxLines = 0);
+ static PreambleBounds ComputePreamble(StringRef Buffer,
+ const LangOptions &LangOpts,
+ unsigned MaxLines = 0);
/// \brief Checks that the given token is the first token that occurs after
/// the given location (this excludes comments and whitespace). Returns the
@@ -463,6 +480,10 @@ public:
/// \brief Returns true if the given character could appear in an identifier.
static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts);
+ /// \brief Checks whether new line pointed by Str is preceded by escape
+ /// sequence.
+ static bool isNewLineEscaped(const char *BufferStart, const char *Str);
+
/// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever
/// emit a warning.
static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size,
@@ -478,6 +499,11 @@ public:
return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
+ /// Returns the leading whitespace for line that corresponds to the given
+ /// location \p Loc.
+ static StringRef getIndentationForLine(SourceLocation Loc,
+ const SourceManager &SM);
+
//===--------------------------------------------------------------------===//
// Internal implementation interfaces.
private:
@@ -609,7 +635,7 @@ private:
//===--------------------------------------------------------------------===//
// Other lexer functions.
- void SkipBytes(unsigned Bytes, bool StartOfLine);
+ void SetByteOffset(unsigned Offset, bool StartOfLine);
void PropagateLineStartLeadingSpaceInfo(Token &Result);
@@ -638,6 +664,8 @@ private:
bool IsStartOfConflictMarker(const char *CurPtr);
bool HandleEndOfConflictMarker(const char *CurPtr);
+ bool lexEditorPlaceholder(Token &Result, const char *CurPtr);
+
bool isCodeCompletionPoint(const char *CurPtr) const;
void cutOffLexing() { BufferPtr = BufferEnd; }
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index b66581b428..cc9223eb7d 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -65,6 +65,7 @@ public:
bool isHalf : 1; // 1.0h
bool isFloat : 1; // 1.0f
bool isImaginary : 1; // 1.0i
+ bool isFloat16 : 1; // 1.0f16
bool isFloat128 : 1; // 1.0q
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
diff --git a/include/clang/Lex/MacroArgs.h b/include/clang/Lex/MacroArgs.h
index 7b2a48561f..a202550da3 100644
--- a/include/clang/Lex/MacroArgs.h
+++ b/include/clang/Lex/MacroArgs.h
@@ -17,6 +17,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/TrailingObjects.h"
#include <vector>
namespace clang {
@@ -26,7 +27,10 @@ namespace clang {
/// MacroArgs - An instance of this class captures information about
/// the formal arguments specified to a function-like macro invocation.
-class MacroArgs {
+class MacroArgs final
+ : private llvm::TrailingObjects<MacroArgs, Token> {
+
+ friend TrailingObjects;
/// NumUnexpArgTokens - The number of raw, unexpanded tokens for the
/// arguments. All of the actual argument tokens are allocated immediately
/// after the MacroArgs object in memory. This is all of the arguments
@@ -53,9 +57,12 @@ class MacroArgs {
/// Preprocessor owns which we use to avoid thrashing malloc/free.
MacroArgs *ArgCache;
- MacroArgs(unsigned NumToks, bool varargsElided)
- : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided),
- ArgCache(nullptr) {}
+ /// MacroArgs - The number of arguments the invoked macro expects.
+ unsigned NumMacroArgs;
+
+ MacroArgs(unsigned NumToks, bool varargsElided, unsigned MacroArgs)
+ : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided),
+ ArgCache(nullptr), NumMacroArgs(MacroArgs) {}
~MacroArgs() = default;
public:
@@ -86,7 +93,7 @@ public:
/// getPreExpArgument - Return the pre-expanded form of the specified
/// argument.
const std::vector<Token> &
- getPreExpArgument(unsigned Arg, const MacroInfo *MI, Preprocessor &PP);
+ getPreExpArgument(unsigned Arg, Preprocessor &PP);
/// getStringifiedArgument - Compute, cache, and return the specified argument
/// that has been 'stringified' as required by the # operator.
@@ -94,10 +101,9 @@ public:
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd);
- /// getNumArguments - Return the number of arguments passed into this macro
- /// invocation.
- unsigned getNumArguments() const { return NumUnexpArgTokens; }
-
+ /// getNumMacroArguments - Return the number of arguments the invoked macro
+ /// expects.
+ unsigned getNumMacroArguments() const { return NumMacroArgs; }
/// isVarargsElidedUse - Return true if this is a C99 style varargs macro
/// invocation and there was no argument specified for the "..." argument. If
@@ -106,6 +112,20 @@ public:
/// argument, this returns false.
bool isVarargsElidedUse() const { return VarargsElided; }
+ /// Returns true if the macro was defined with a variadic (ellipsis) parameter
+ /// AND was invoked with at least one token supplied as a variadic argument.
+ ///
+ /// \code
+ /// #define F(a) a
+ /// #define V(a, ...) __VA_OPT__(a)
+ /// F() <-- returns false on this invocation.
+ /// V(,a) <-- returns true on this invocation.
+ /// V(,) <-- returns false on this invocation.
+ /// \endcode
+ ///
+
+ bool invokedWithVariadicArgument(const MacroInfo *const MI) const;
+
/// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of
/// tokens into the literal string token that should be produced by the C #
/// preprocessor operator. If Charify is true, then it should be turned into
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index 6cc3b0bb26..47f10d6e76 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -42,14 +42,14 @@ class MacroInfo {
/// \brief The list of arguments for a function-like macro.
///
- /// ArgumentList points to the first of NumArguments pointers.
+ /// ParameterList points to the first of NumParameters pointers.
///
/// This can be empty, for, e.g. "#define X()". In a C99-style variadic
/// macro, this includes the \c __VA_ARGS__ identifier on the list.
- IdentifierInfo **ArgumentList;
+ IdentifierInfo **ParameterList;
- /// \see ArgumentList
- unsigned NumArguments;
+ /// \see ParameterList
+ unsigned NumParameters;
/// \brief This is the list of tokens that the macro is defined to.
SmallVector<Token, 8> ReplacementTokens;
@@ -105,9 +105,6 @@ class MacroInfo {
/// \brief Must warn if the macro is unused at the end of translation unit.
bool IsWarnIfUnused : 1;
- /// \brief Whether this macro info was loaded from an AST file.
- bool FromASTFile : 1;
-
/// \brief Whether this macro was used as header guard.
bool UsedForHeaderGuard : 1;
@@ -126,7 +123,7 @@ public:
SourceLocation getDefinitionEndLoc() const { return EndLocation; }
/// \brief Get length in characters of the macro definition.
- unsigned getDefinitionLength(SourceManager &SM) const {
+ unsigned getDefinitionLength(const SourceManager &SM) const {
if (IsDefinitionLengthCached)
return DefinitionLength;
return getDefinitionLengthSlow(SM);
@@ -156,37 +153,37 @@ public:
/// \brief Set the value of the IsWarnIfUnused flag.
void setIsWarnIfUnused(bool val) { IsWarnIfUnused = val; }
- /// \brief Set the specified list of identifiers as the argument list for
+ /// \brief Set the specified list of identifiers as the parameter list for
/// this macro.
- void setArgumentList(ArrayRef<IdentifierInfo *> List,
+ void setParameterList(ArrayRef<IdentifierInfo *> List,
llvm::BumpPtrAllocator &PPAllocator) {
- assert(ArgumentList == nullptr && NumArguments == 0 &&
- "Argument list already set!");
+ assert(ParameterList == nullptr && NumParameters == 0 &&
+ "Parameter list already set!");
if (List.empty())
return;
- NumArguments = List.size();
- ArgumentList = PPAllocator.Allocate<IdentifierInfo *>(List.size());
- std::copy(List.begin(), List.end(), ArgumentList);
+ NumParameters = List.size();
+ ParameterList = PPAllocator.Allocate<IdentifierInfo *>(List.size());
+ std::copy(List.begin(), List.end(), ParameterList);
}
- /// Arguments - The list of arguments for a function-like macro. This can be
- /// empty, for, e.g. "#define X()".
- typedef IdentifierInfo *const *arg_iterator;
- bool arg_empty() const { return NumArguments == 0; }
- arg_iterator arg_begin() const { return ArgumentList; }
- arg_iterator arg_end() const { return ArgumentList + NumArguments; }
- unsigned getNumArgs() const { return NumArguments; }
- ArrayRef<const IdentifierInfo *> args() const {
- return ArrayRef<const IdentifierInfo *>(ArgumentList, NumArguments);
+ /// Parameters - The list of parameters for a function-like macro. This can
+ /// be empty, for, e.g. "#define X()".
+ typedef IdentifierInfo *const *param_iterator;
+ bool param_empty() const { return NumParameters == 0; }
+ param_iterator param_begin() const { return ParameterList; }
+ param_iterator param_end() const { return ParameterList + NumParameters; }
+ unsigned getNumParams() const { return NumParameters; }
+ ArrayRef<const IdentifierInfo *> params() const {
+ return ArrayRef<const IdentifierInfo *>(ParameterList, NumParameters);
}
- /// \brief Return the argument number of the specified identifier,
- /// or -1 if the identifier is not a formal argument identifier.
- int getArgumentNum(const IdentifierInfo *Arg) const {
- for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I)
+ /// \brief Return the parameter number of the specified identifier,
+ /// or -1 if the identifier is not a formal parameter identifier.
+ int getParameterNum(const IdentifierInfo *Arg) const {
+ for (param_iterator I = param_begin(), E = param_end(); I != E; ++I)
if (*I == Arg)
- return I - arg_begin();
+ return I - param_begin();
return -1;
}
@@ -264,33 +261,15 @@ public:
IsDisabled = true;
}
- /// \brief Determine whether this macro info came from an AST file (such as
- /// a precompiled header or module) rather than having been parsed.
- bool isFromASTFile() const { return FromASTFile; }
-
/// \brief Determine whether this macro was used for a header guard.
bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; }
void setUsedForHeaderGuard(bool Val) { UsedForHeaderGuard = Val; }
- /// \brief Retrieve the global ID of the module that owns this particular
- /// macro info.
- unsigned getOwningModuleID() const {
- if (isFromASTFile())
- return *(const unsigned *)(this + 1);
-
- return 0;
- }
-
void dump() const;
private:
- unsigned getDefinitionLengthSlow(SourceManager &SM) const;
-
- void setOwningModuleID(unsigned ID) {
- assert(isFromASTFile());
- *(unsigned *)(this + 1) = ID;
- }
+ unsigned getDefinitionLengthSlow(const SourceManager &SM) const;
friend class Preprocessor;
};
@@ -531,6 +510,9 @@ public:
ID.AddPointer(II);
}
+ /// Get the name of the macro.
+ IdentifierInfo *getName() const { return II; }
+
/// Get the ID of the module that exports this macro.
Module *getOwningModule() const { return OwningModule; }
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index 70770d17e9..ee0638b57f 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -109,6 +109,16 @@ public:
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) = 0;
+ /// Attempt to load the given module from the specified source buffer. Does
+ /// not make any submodule visible; for that, use loadModule or
+ /// makeModuleVisible.
+ ///
+ /// \param Loc The location at which the module was loaded.
+ /// \param ModuleName The name of the module to build.
+ /// \param Source The source of the module: a (preprocessed) module map.
+ virtual void loadModuleFromSource(SourceLocation Loc, StringRef ModuleName,
+ StringRef Source) = 0;
+
/// \brief Make the given module visible.
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
@@ -136,6 +146,30 @@ public:
bool HadFatalFailure;
};
+
+/// A module loader that doesn't know how to load modules.
+class TrivialModuleLoader : public ModuleLoader {
+public:
+ ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) override {
+ return ModuleLoadResult();
+ }
+
+ void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName,
+ StringRef Source) override {}
+
+ void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc) override {}
+
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override {
+ return nullptr;
+ }
+ bool lookupMissingImports(StringRef Name,
+ SourceLocation TriggerLoc) override {
+ return 0;
+ }
+};
}
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index 46136725d8..4e600ce855 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -26,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/Twine.h"
#include <algorithm>
#include <memory>
@@ -81,22 +82,26 @@ class ModuleMap {
/// \brief The directory used for Clang-supplied, builtin include headers,
/// such as "stdint.h".
- const DirectoryEntry *BuiltinIncludeDir;
+ const DirectoryEntry *BuiltinIncludeDir = nullptr;
/// \brief Language options used to parse the module map itself.
///
/// These are always simple C language options.
LangOptions MMapLangOpts;
- // The module that the main source file is associated with (the module
- // named LangOpts::CurrentModule, if we've loaded it).
- Module *SourceModule;
+ /// The module that the main source file is associated with (the module
+ /// named LangOpts::CurrentModule, if we've loaded it).
+ Module *SourceModule = nullptr;
+
+ /// The global module for the current TU, if we still own it. (Ownership is
+ /// transferred if/when we create an enclosing module.
+ std::unique_ptr<Module> PendingGlobalModule;
/// \brief The top-level modules that are known.
llvm::StringMap<Module *> Modules;
/// \brief The number of modules we have created in total.
- unsigned NumCreatedModules;
+ unsigned NumCreatedModules = 0;
public:
/// \brief Flags describing the role of a module header.
@@ -116,6 +121,11 @@ public:
// Adjust ModuleMap::addHeader.
};
+ /// Convert a header kind to a role. Requires Kind to not be HK_Excluded.
+ static ModuleHeaderRole headerKindToRole(Module::HeaderKind Kind);
+ /// Convert a header role to a kind.
+ static Module::HeaderKind headerRoleToKind(ModuleHeaderRole Role);
+
/// \brief A header that is known to reside within a given module,
/// whether it was included or excluded.
class KnownHeader {
@@ -165,7 +175,13 @@ private:
/// \brief Mapping from each header to the module that owns the contents of
/// that header.
HeadersMap Headers;
-
+
+ /// Map from file sizes to modules with lazy header directives of that size.
+ mutable llvm::DenseMap<off_t, llvm::TinyPtrVector<Module*>> LazyHeadersBySize;
+ /// Map from mtimes to modules with lazy header directives with those mtimes.
+ mutable llvm::DenseMap<time_t, llvm::TinyPtrVector<Module*>>
+ LazyHeadersByModTime;
+
/// \brief Mapping from directories with umbrella headers to the module
/// that is generated from the umbrella header.
///
@@ -257,6 +273,31 @@ private:
/// resolved.
Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const;
+ /// Add an unresolved header to a module.
+ void addUnresolvedHeader(Module *Mod,
+ Module::UnresolvedHeaderDirective Header);
+
+ /// Look up the given header directive to find an actual header file.
+ ///
+ /// \param M The module in which we're resolving the header directive.
+ /// \param Header The header directive to resolve.
+ /// \param RelativePathName Filled in with the relative path name from the
+ /// module to the resolved header.
+ /// \return The resolved file, if any.
+ const FileEntry *findHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header,
+ SmallVectorImpl<char> &RelativePathName);
+
+ /// Resolve the given header directive.
+ void resolveHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header);
+
+ /// Attempt to resolve the specified header directive as naming a builtin
+ /// header.
+ /// \return \c true if a corresponding builtin header was found.
+ bool resolveAsBuiltinHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header);
+
/// \brief Looks up the modules that \p File corresponds to.
///
/// If \p File represents a builtin header within Clang's builtin include
@@ -351,6 +392,15 @@ public:
/// the preferred module for the header.
ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File) const;
+ /// Resolve all lazy header directives for the specified file.
+ ///
+ /// This ensures that the HeaderFileInfo on HeaderSearch is up to date. This
+ /// is effectively internal, but is exposed so HeaderSearch can call it.
+ void resolveHeaderDirectives(const FileEntry *File) const;
+
+ /// Resolve all lazy header directives for the specified module.
+ void resolveHeaderDirectives(Module *Mod) const;
+
/// \brief Reports errors if a module must not include a specific file.
///
/// \param RequestingModule The module including a file.
@@ -426,6 +476,14 @@ public:
bool IsFramework,
bool IsExplicit);
+ /// \brief Create a 'global module' for a C++ Modules TS module interface
+ /// unit.
+ ///
+ /// We model the global module as a submodule of the module interface unit.
+ /// Unfortunately, we can't create the module interface unit's Module until
+ /// later, because we don't know what it will be called.
+ Module *createGlobalModuleForInterfaceUnit(SourceLocation Loc);
+
/// \brief Create a new module for a C++ Modules TS module interface unit.
/// The module must not already exist, and will be configured for the current
/// compilation.
@@ -433,7 +491,8 @@ public:
/// Note that this also sets the current module to the newly-created module.
///
/// \returns The newly-created module.
- Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name);
+ Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name,
+ Module *GlobalModule);
/// \brief Infer the contents of a framework module map from the given
/// framework directory.
@@ -507,16 +566,6 @@ public:
/// false otherwise.
bool resolveConflicts(Module *Mod, bool Complain);
- /// \brief Infers the (sub)module based on the given source location and
- /// source manager.
- ///
- /// \param Loc The location within the source that we are querying, along
- /// with its source manager.
- ///
- /// \returns The module that owns this source location, or null if no
- /// module owns this source location.
- Module *inferModuleFromLocation(FullSourceLoc Loc);
-
/// \brief Sets the umbrella header of the given module to the given
/// header.
void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader,
@@ -546,14 +595,20 @@ public:
/// \param HomeDir The directory in which relative paths within this module
/// map file will be resolved.
///
+ /// \param ID The FileID of the file to process, if we've already entered it.
+ ///
+ /// \param Offset [inout] On input the offset at which to start parsing. On
+ /// output, the offset at which the module map terminated.
+ ///
/// \param ExternModuleLoc The location of the "extern module" declaration
/// that caused us to load this module map file, if any.
///
/// \returns true if an error occurred, false otherwise.
bool parseModuleMapFile(const FileEntry *File, bool IsSystem,
- const DirectoryEntry *HomeDir,
+ const DirectoryEntry *HomeDir, FileID ID = FileID(),
+ unsigned *Offset = nullptr,
SourceLocation ExternModuleLoc = SourceLocation());
-
+
/// \brief Dump the contents of the module map, for debugging purposes.
void dump();
diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h
index 83e6f99078..3967f86889 100644
--- a/include/clang/Lex/MultipleIncludeOpt.h
+++ b/include/clang/Lex/MultipleIncludeOpt.h
@@ -92,7 +92,7 @@ public:
TheMacro = nullptr;
}
- /// getHasReadAnyTokensVal - This is used for the \#ifndef hande-shake at the
+ /// getHasReadAnyTokensVal - This is used for the \#ifndef handshake at the
/// top of the file when reading preprocessor directives. Otherwise, reading
/// the "ifndef x" would count as reading tokens.
bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index 2d027f314b..19bce4dd32 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -235,6 +235,14 @@ public:
virtual void PragmaWarningPop(SourceLocation Loc) {
}
+ /// \brief Callback invoked when a \#pragma clang assume_nonnull begin directive
+ /// is read.
+ virtual void PragmaAssumeNonNullBegin(SourceLocation Loc) {}
+
+ /// \brief Callback invoked when a \#pragma clang assume_nonnull end directive
+ /// is read.
+ virtual void PragmaAssumeNonNullEnd(SourceLocation Loc) {}
+
/// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a
/// macro invocation is found.
virtual void MacroExpands(const Token &MacroNameTok,
@@ -247,10 +255,14 @@ public:
}
/// \brief Hook called whenever a macro \#undef is seen.
+ /// \param MacroNameTok The active Token
+ /// \param MD A MacroDefinition for the named macro.
+ /// \param Undef New MacroDirective if the macro was defined, null otherwise.
///
/// MD is released immediately following this callback.
virtual void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
}
/// \brief Hook called whenever the 'defined' operator is seen.
@@ -262,7 +274,10 @@ public:
/// \brief Hook called when a source range is skipped.
/// \param Range The SourceRange that was skipped. The range begins at the
/// \#if/\#else directive and ends after the \#endif/\#else directive.
- virtual void SourceRangeSkipped(SourceRange Range) {
+ /// \param EndifLoc The end location of the 'endif' token, which may precede
+ /// the range skipped by the directive (e.g excluding comments after an
+ /// 'endif').
+ virtual void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) {
}
enum ConditionValueKind {
@@ -377,6 +392,12 @@ public:
Second->Ident(Loc, str);
}
+ void PragmaDirective(SourceLocation Loc,
+ PragmaIntroducerKind Introducer) override {
+ First->PragmaDirective(Loc, Introducer);
+ Second->PragmaDirective(Loc, Introducer);
+ }
+
void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
StringRef Str) override {
First->PragmaComment(Loc, Kind, Str);
@@ -389,6 +410,11 @@ public:
Second->PragmaDetectMismatch(Loc, Name, Value);
}
+ void PragmaDebug(SourceLocation Loc, StringRef DebugType) override {
+ First->PragmaDebug(Loc, DebugType);
+ Second->PragmaDebug(Loc, DebugType);
+ }
+
void PragmaMessage(SourceLocation Loc, StringRef Namespace,
PragmaMessageKind Kind, StringRef Str) override {
First->PragmaMessage(Loc, Namespace, Kind, Str);
@@ -433,21 +459,33 @@ public:
Second->PragmaWarningPop(Loc);
}
+ void PragmaAssumeNonNullBegin(SourceLocation Loc) override {
+ First->PragmaAssumeNonNullBegin(Loc);
+ Second->PragmaAssumeNonNullBegin(Loc);
+ }
+
+ void PragmaAssumeNonNullEnd(SourceLocation Loc) override {
+ First->PragmaAssumeNonNullEnd(Loc);
+ Second->PragmaAssumeNonNullEnd(Loc);
+ }
+
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
SourceRange Range, const MacroArgs *Args) override {
First->MacroExpands(MacroNameTok, MD, Range, Args);
Second->MacroExpands(MacroNameTok, MD, Range, Args);
}
- void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override {
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
First->MacroDefined(MacroNameTok, MD);
Second->MacroDefined(MacroNameTok, MD);
}
void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) override {
- First->MacroUndefined(MacroNameTok, MD);
- Second->MacroUndefined(MacroNameTok, MD);
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) override {
+ First->MacroUndefined(MacroNameTok, MD, Undef);
+ Second->MacroUndefined(MacroNameTok, MD, Undef);
}
void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
@@ -456,9 +494,9 @@ public:
Second->Defined(MacroNameTok, MD, Range);
}
- void SourceRangeSkipped(SourceRange Range) override {
- First->SourceRangeSkipped(Range);
- Second->SourceRangeSkipped(Range);
+ void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override {
+ First->SourceRangeSkipped(Range, EndifLoc);
+ Second->SourceRangeSkipped(Range, EndifLoc);
}
/// \brief Hook called whenever an \#if is seen.
diff --git a/include/clang/Lex/PTHLexer.h b/include/clang/Lex/PTHLexer.h
index 904be792b2..f96af665b1 100644
--- a/include/clang/Lex/PTHLexer.h
+++ b/include/clang/Lex/PTHLexer.h
@@ -36,7 +36,7 @@ class PTHLexer : public PreprocessorLexer {
const unsigned char* LastHashTokPtr;
/// PPCond - Pointer to a side table in the PTH file that provides a
- /// a consise summary of the preproccessor conditional block structure.
+ /// a concise summary of the preprocessor conditional block structure.
/// This is used to perform quick skipping of conditional blocks.
const unsigned char* PPCond;
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index 826ba33fbb..882b8aedf7 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -488,7 +488,8 @@ namespace clang {
void MacroExpands(const Token &Id, const MacroDefinition &MD,
SourceRange Range, const MacroArgs *Args) override;
void MacroDefined(const Token &Id, const MacroDirective *MD) override;
- void MacroUndefined(const Token &Id, const MacroDefinition &MD) override;
+ void MacroUndefined(const Token &Id, const MacroDefinition &MD,
+ const MacroDirective *Undef) override;
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
@@ -503,7 +504,8 @@ namespace clang {
void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
SourceRange Range) override;
- void SourceRangeSkipped(SourceRange Range) override;
+ void SourceRangeSkipped(SourceRange Range,
+ SourceLocation EndifLoc) override;
void addMacroExpansion(const Token &Id, const MacroInfo *MI,
SourceRange Range);
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 26efa8b8a1..4f211a3eb6 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;
@@ -95,6 +96,8 @@ enum MacroUse {
/// know anything about preprocessor-level issues like the \#include stack,
/// token expansion, etc.
class Preprocessor {
+ friend class VariadicMacroScopeGuard;
+ friend class VAOptDefinitionContext;
std::shared_ptr<PreprocessorOptions> PPOpts;
DiagnosticsEngine *Diags;
LangOptions &LangOpts;
@@ -102,6 +105,7 @@ class Preprocessor {
const TargetInfo *AuxTarget;
FileManager &FileMgr;
SourceManager &SourceMgr;
+ MemoryBufferCache &PCMCache;
std::unique_ptr<ScratchBuffer> ScratchBuf;
HeaderSearch &HeaderInfo;
ModuleLoader &TheModuleLoader;
@@ -128,6 +132,7 @@ class Preprocessor {
IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma
IdentifierInfo *Ident__identifier; // __identifier
IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__
+ IdentifierInfo *Ident__VA_OPT__; // __VA_OPT__
IdentifierInfo *Ident__has_feature; // __has_feature
IdentifierInfo *Ident__has_extension; // __has_extension
IdentifierInfo *Ident__has_builtin; // __has_builtin
@@ -281,6 +286,44 @@ class Preprocessor {
/// This is used when loading a precompiled preamble.
std::pair<int, bool> SkipMainFilePreamble;
+ class PreambleConditionalStackStore {
+ enum State {
+ Off = 0,
+ Recording = 1,
+ Replaying = 2,
+ };
+
+ public:
+ PreambleConditionalStackStore() : ConditionalStackState(Off) {}
+
+ void startRecording() { ConditionalStackState = Recording; }
+ void startReplaying() { ConditionalStackState = Replaying; }
+ bool isRecording() const { return ConditionalStackState == Recording; }
+ bool isReplaying() const { return ConditionalStackState == Replaying; }
+
+ ArrayRef<PPConditionalInfo> getStack() const {
+ return ConditionalStack;
+ }
+
+ void doneReplaying() {
+ ConditionalStack.clear();
+ ConditionalStackState = Off;
+ }
+
+ void setStack(ArrayRef<PPConditionalInfo> s) {
+ if (!isRecording() && !isReplaying())
+ return;
+ ConditionalStack.clear();
+ ConditionalStack.append(s.begin(), s.end());
+ }
+
+ bool hasRecordedPreamble() const { return !ConditionalStack.empty(); }
+
+ private:
+ SmallVector<PPConditionalInfo, 4> ConditionalStack;
+ State ConditionalStackState;
+ } PreambleConditionalStack;
+
/// \brief The current top of the stack that we're lexing from if
/// not expanding a macro and we are lexing directly from source code.
///
@@ -322,7 +365,7 @@ class Preprocessor {
/// \brief If the current lexer is for a submodule that is being built, this
/// is that submodule.
- Module *CurSubmodule;
+ Module *CurLexerSubmodule;
/// \brief Keeps track of the stack of files currently
/// \#included, and macros currently being expanded from, not counting
@@ -505,16 +548,19 @@ class Preprocessor {
/// \brief Information about a submodule that we're currently building.
struct BuildingSubmoduleInfo {
- BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc,
+ BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma,
SubmoduleState *OuterSubmoduleState,
unsigned OuterPendingModuleMacroNames)
- : M(M), ImportLoc(ImportLoc), OuterSubmoduleState(OuterSubmoduleState),
+ : M(M), ImportLoc(ImportLoc), IsPragma(IsPragma),
+ OuterSubmoduleState(OuterSubmoduleState),
OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {}
/// The module that we are building.
Module *M;
/// The location at which the module was included.
SourceLocation ImportLoc;
+ /// Whether we entered this submodule via a pragma.
+ bool IsPragma;
/// The previous SubmoduleState.
SubmoduleState *OuterSubmoduleState;
/// The number of pending module macro names when we started building this.
@@ -639,19 +685,12 @@ class Preprocessor {
/// of that list.
MacroInfoChain *MIChainHead;
- struct DeserializedMacroInfoChain {
- MacroInfo MI;
- unsigned OwningModuleID; // MUST be immediately after the MacroInfo object
- // so it can be accessed by MacroInfo::getOwningModuleID().
- DeserializedMacroInfoChain *Next;
- };
- DeserializedMacroInfoChain *DeserialMIChainHead;
-
void updateOutOfDateIdentifier(IdentifierInfo &II) const;
public:
Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM,
+ MemoryBufferCache &PCMCache,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup = nullptr,
bool OwnsHeaderSearch = false,
@@ -691,6 +730,7 @@ public:
const TargetInfo *getAuxTargetInfo() const { return AuxTarget; }
FileManager &getFileManager() const { return FileMgr; }
SourceManager &getSourceManager() const { return SourceMgr; }
+ MemoryBufferCache &getPCMCache() const { return PCMCache; }
HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
IdentifierTable &getIdentifierTable() { return Identifiers; }
@@ -769,8 +809,9 @@ public:
/// expansions going on at the time.
PreprocessorLexer *getCurrentFileLexer() const;
- /// \brief Return the submodule owning the file being lexed.
- Module *getCurrentSubmodule() const { return CurSubmodule; }
+ /// \brief Return the submodule owning the file being lexed. This may not be
+ /// the current module if we have changed modules since entering the file.
+ Module *getCurrentLexerSubmodule() const { return CurLexerSubmodule; }
/// \brief Returns the FileID for the preprocessor predefines.
FileID getPredefinesFileID() const { return PredefinesFileID; }
@@ -1259,6 +1300,10 @@ public:
CachedTokens[CachedLexPos-1] = Tok;
}
+ /// Enter an annotation token into the token stream.
+ void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind,
+ void *AnnotationVal);
+
/// Update the current token to represent the provided
/// identifier, in order to cache an action performed by typo correction.
void TypoCorrectToken(const Token &Tok) {
@@ -1598,6 +1643,7 @@ private:
*Ident_AbnormalTermination;
const char *getCurLexerEndPos();
+ void diagnoseMissingHeaderInUmbrellaDir(const Module &Mod);
public:
void PoisonSEHIdentifiers(bool Poison = true); // Borland
@@ -1656,10 +1702,6 @@ public:
/// \brief Allocate a new MacroInfo object with the provided SourceLocation.
MacroInfo *AllocateMacroInfo(SourceLocation L);
- /// \brief Allocate a new MacroInfo object loaded from an AST file.
- MacroInfo *AllocateDeserializedMacroInfo(SourceLocation L,
- unsigned SubModuleID);
-
/// \brief Turn the specified lexer token into a fully checked and spelled
/// filename, e.g. as an operand of \#include.
///
@@ -1682,7 +1724,7 @@ public:
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache = false);
+ bool *IsMapped, bool SkipCache = false);
/// \brief Get the DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable.
@@ -1717,13 +1759,16 @@ public:
bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
bool *ShadowFlag = nullptr);
-private:
+ void EnterSubmodule(Module *M, SourceLocation ImportLoc, bool ForPragma);
+ Module *LeaveSubmodule(bool ForPragma);
+private:
void PushIncludeMacroStack() {
assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer");
- IncludeMacroStack.emplace_back(
- CurLexerKind, CurSubmodule, std::move(CurLexer), std::move(CurPTHLexer),
- CurPPLexer, std::move(CurTokenLexer), CurDirLookup);
+ IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule,
+ std::move(CurLexer), std::move(CurPTHLexer),
+ CurPPLexer, std::move(CurTokenLexer),
+ CurDirLookup);
CurPPLexer = nullptr;
}
@@ -1733,16 +1778,13 @@ private:
CurPPLexer = IncludeMacroStack.back().ThePPLexer;
CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer);
CurDirLookup = IncludeMacroStack.back().TheDirLookup;
- CurSubmodule = IncludeMacroStack.back().TheSubmodule;
+ CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule;
CurLexerKind = IncludeMacroStack.back().CurLexerKind;
IncludeMacroStack.pop_back();
}
void PropagateLineStartLeadingSpaceInfo(Token &Result);
- void EnterSubmodule(Module *M, SourceLocation ImportLoc);
- void LeaveSubmodule();
-
/// Determine whether we need to create module macros for #defines in the
/// current context.
bool needModuleMacros() const;
@@ -1751,9 +1793,6 @@ private:
/// macro name.
void updateModuleMacroInfo(const IdentifierInfo *II, ModuleMacroInfo &Info);
- /// \brief Allocate a new MacroInfo object.
- MacroInfo *AllocateMacroInfo();
-
DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI,
SourceLocation Loc);
UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc);
@@ -1773,11 +1812,24 @@ private:
void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other,
bool *ShadowFlag = nullptr);
+ /// ReadOptionalMacroParameterListAndBody - This consumes all (i.e. the
+ /// entire line) of the macro's tokens and adds them to MacroInfo, and while
+ /// doing so performs certain validity checks including (but not limited to):
+ /// - # (stringization) is followed by a macro parameter
+ /// \param MacroNameTok - Token that represents the macro name
+ /// \param ImmediatelyAfterHeaderGuard - Macro follows an #ifdef header guard
+ ///
+ /// Either returns a pointer to a MacroInfo object OR emits a diagnostic and
+ /// returns a nullptr if an invalid sequence of tokens is encountered.
+
+ MacroInfo *ReadOptionalMacroParameterListAndBody(
+ const Token &MacroNameTok, bool ImmediatelyAfterHeaderGuard);
+
/// The ( starting an argument list of a macro definition has just been read.
- /// Lex the rest of the arguments and the closing ), updating \p MI with
+ /// Lex the rest of the parameters and the closing ), updating \p MI with
/// what we learn and saving in \p LastTok the last token read.
/// Return true if an error occurs parsing the arg list.
- bool ReadMacroDefinitionArgList(MacroInfo *MI, Token& LastTok);
+ bool ReadMacroParameterList(MacroInfo *MI, Token& LastTok);
/// We just read a \#if or related directive and decided that the
/// subsequent tokens are in the \#if'd out portion of the
@@ -1787,18 +1839,28 @@ private:
/// \p FoundElse is false, then \#else directives are ok, if not, then we have
/// already seen one so a \#else directive is a duplicate. When this returns,
/// the caller can lex the first valid token.
- void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
+ void SkipExcludedConditionalBlock(const Token &HashToken,
+ SourceLocation IfTokenLoc,
bool FoundNonSkipPortion, bool FoundElse,
SourceLocation ElseLoc = SourceLocation());
/// \brief A fast PTH version of SkipExcludedConditionalBlock.
void PTHSkipExcludedConditionalBlock();
+ /// Information about the result for evaluating an expression for a
+ /// preprocessor directive.
+ struct DirectiveEvalResult {
+ /// Whether the expression was evaluated as true or not.
+ bool Conditional;
+ /// True if the expression contained identifiers that were undefined.
+ bool IncludedUndefinedIds;
+ };
+
/// \brief Evaluate an integer constant expression that may occur after a
- /// \#if or \#elif directive and return it as a bool.
+ /// \#if or \#elif directive and return a \p DirectiveEvalResult object.
///
/// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro.
- bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro);
+ DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro);
/// \brief Install the standard preprocessor pragmas:
/// \#pragma GCC poison/system_header/dependency and \#pragma once.
@@ -1829,7 +1891,7 @@ private:
/// After reading "MACRO(", this method is invoked to read all of the formal
/// arguments specified for the macro invocation. Returns null on error.
- MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI,
+ MacroArgs *ReadMacroCallArgumentList(Token &MacroName, MacroInfo *MI,
SourceLocation &ExpansionEnd);
/// \brief If an identifier token is read that is to be expanded
@@ -1913,20 +1975,24 @@ private:
void HandleMicrosoftImportDirective(Token &Tok);
public:
+ /// Check that the given module is available, producing a diagnostic if not.
+ /// \return \c true if the check failed (because the module is not available).
+ /// \c false if the module appears to be usable.
+ static bool checkModuleIsAvailable(const LangOptions &LangOpts,
+ const TargetInfo &TargetInfo,
+ DiagnosticsEngine &Diags, Module *M);
+
// Module inclusion testing.
/// \brief Find the module that owns the source or header file that
/// \p Loc points to. If the location is in a file that was included
/// into a module, or is outside any module, returns nullptr.
Module *getModuleForLocation(SourceLocation Loc);
- /// \brief Find the module that contains the specified location, either
- /// directly or indirectly.
- Module *getModuleContainingLocation(SourceLocation Loc);
-
/// \brief We want to produce a diagnostic at location IncLoc concerning a
/// missing module import.
///
/// \param IncLoc The location at which the missing import was detected.
+ /// \param M The desired module.
/// \param MLoc A location within the desired module at which some desired
/// effect occurred (eg, where a desired entity was declared).
///
@@ -1934,20 +2000,47 @@ public:
/// Null if no such file could be determined or if a #include is not
/// appropriate.
const FileEntry *getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+ Module *M,
SourceLocation MLoc);
+ bool isRecordingPreamble() const {
+ return PreambleConditionalStack.isRecording();
+ }
+
+ bool hasRecordedPreamble() const {
+ return PreambleConditionalStack.hasRecordedPreamble();
+ }
+
+ ArrayRef<PPConditionalInfo> getPreambleConditionalStack() const {
+ return PreambleConditionalStack.getStack();
+ }
+
+ void setRecordedPreambleConditionalStack(ArrayRef<PPConditionalInfo> s) {
+ PreambleConditionalStack.setStack(s);
+ }
+
+ void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s) {
+ PreambleConditionalStack.startReplaying();
+ PreambleConditionalStack.setStack(s);
+ }
+
private:
+ /// \brief After processing predefined file, initialize the conditional stack from
+ /// the preamble.
+ void replayPreambleConditionalStack();
+
// Macro handling.
void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
void HandleUndefDirective();
// Conditional Inclusion.
- void HandleIfdefDirective(Token &Tok, bool isIfndef,
- bool ReadAnyTokensBeforeDirective);
- void HandleIfDirective(Token &Tok, bool ReadAnyTokensBeforeDirective);
+ void HandleIfdefDirective(Token &Tok, const Token &HashToken,
+ bool isIfndef, bool ReadAnyTokensBeforeDirective);
+ void HandleIfDirective(Token &Tok, const Token &HashToken,
+ bool ReadAnyTokensBeforeDirective);
void HandleEndifDirective(Token &Tok);
- void HandleElseDirective(Token &Tok);
- void HandleElifDirective(Token &Tok);
+ void HandleElseDirective(Token &Tok, const Token &HashToken);
+ void HandleElifDirective(Token &Tok, const Token &HashToken);
// Pragmas.
void HandlePragmaDirective(SourceLocation IntroducerLoc,
@@ -1961,6 +2054,7 @@ public:
void HandlePragmaPushMacro(Token &Tok);
void HandlePragmaPopMacro(Token &Tok);
void HandlePragmaIncludeAlias(Token &Tok);
+ void HandlePragmaModuleBuild(Token &Tok);
IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
// Return true and store the first token only if any CommentHandler
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index 6d6cf05a96..65021fc2d3 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -17,6 +17,7 @@
#include "clang/Lex/MultipleIncludeOpt.h"
#include "clang/Lex/Token.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -76,7 +77,7 @@ protected:
PreprocessorLexer(Preprocessor *pp, FileID fid);
PreprocessorLexer()
- : PP(nullptr), InitialNumSLocEntries(0),
+ : PP(nullptr), FID(), InitialNumSLocEntries(0),
ParsingPreprocessorDirective(false),
ParsingFilename(false),
LexingRawMode(false) {}
@@ -176,6 +177,11 @@ public:
conditional_iterator conditional_end() const {
return ConditionalStack.end();
}
+
+ void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) {
+ ConditionalStack.clear();
+ ConditionalStack.append(CL.begin(), CL.end());
+ }
};
} // end namespace clang
diff --git a/include/clang/Lex/PreprocessorOptions.h b/include/clang/Lex/PreprocessorOptions.h
index 58d79f7ff8..760b308f92 100644
--- a/include/clang/Lex/PreprocessorOptions.h
+++ b/include/clang/Lex/PreprocessorOptions.h
@@ -80,7 +80,14 @@ public:
/// The boolean indicates whether the preamble ends at the start of a new
/// line.
std::pair<unsigned, bool> PrecompiledPreambleBytes;
-
+
+ /// \brief True indicates that a preamble is being generated.
+ ///
+ /// When the lexer is done, one of the things that need to be preserved is the
+ /// conditional #if stack, so the ASTWriter/ASTReader can save/restore it when
+ /// processing the rest of the file.
+ bool GeneratePreamble;
+
/// The implicit PTH input included at the start of the translation unit, or
/// empty.
std::string ImplicitPTHInclude;
@@ -88,6 +95,16 @@ public:
/// If given, a PTH cache file to use for speeding up header parsing.
std::string TokenCache;
+ /// When enabled, preprocessor is in a mode for parsing a single file only.
+ ///
+ /// Disables #includes of other files and if there are unresolved identifiers
+ /// in preprocessor directive conditions it causes all blocks to be parsed so
+ /// that the client can get the maximum amount of information from the parser.
+ bool SingleFileParseMode = false;
+
+ /// When enabled, the preprocessor will construct editor placeholder tokens.
+ bool LexEditorPlaceholders = true;
+
/// \brief True if the SourceManager should report the original file name for
/// contents of files that were remapped to other files. Defaults to true.
bool RemappedFilesKeepOriginalName;
@@ -143,7 +160,8 @@ public:
DisablePCHValidation(false),
AllowPCHWithCompilerErrors(false),
DumpDeserializedPCHDecls(false),
- PrecompiledPreambleBytes(0, true),
+ PrecompiledPreambleBytes(0, false),
+ GeneratePreamble(false),
RemappedFilesKeepOriginalName(true),
RetainRemappedFileBuffers(false),
ObjCXXARCStandardLibrary(ARCXX_nolib) { }
@@ -173,9 +191,11 @@ public:
ImplicitPCHInclude.clear();
ImplicitPTHInclude.clear();
TokenCache.clear();
+ SingleFileParseMode = false;
+ LexEditorPlaceholders = true;
RetainRemappedFileBuffers = true;
PrecompiledPreambleBytes.first = 0;
- PrecompiledPreambleBytes.second = 0;
+ PrecompiledPreambleBytes.second = false;
}
};
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index 4393e205ff..02a1fef70f 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -84,6 +84,7 @@ public:
StringifiedInMacro = 0x100, // This string or character literal is formed by
// macro stringizing or charizing operator.
CommaAfterElided = 0x200, // The comma following this token was elided (MS).
+ IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
};
tok::TokenKind getKind() const { return Kind; }
@@ -298,6 +299,13 @@ public:
/// Returns true if the comma after this token was elided.
bool commaAfterElided() const { return getFlag(CommaAfterElided); }
+
+ /// Returns true if this token is an editor placeholder.
+ ///
+ /// Editor placeholders are produced by the code-completion engine and are
+ /// represented as characters between '<#' and '#>' in the source code. The
+ /// lexer uses identifier tokens to represent placeholders.
+ bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
};
/// \brief Information about the conditional stack (\#if directives)
diff --git a/include/clang/Lex/TokenLexer.h b/include/clang/Lex/TokenLexer.h
index fdeed44d8f..17305107ca 100644
--- a/include/clang/Lex/TokenLexer.h
+++ b/include/clang/Lex/TokenLexer.h
@@ -15,12 +15,14 @@
#define LLVM_CLANG_LEX_TOKENLEXER_H
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
namespace clang {
class MacroInfo;
class Preprocessor;
class Token;
class MacroArgs;
+ class VAOptExpansionContext;
/// TokenLexer - This implements a lexer that returns tokens from a macro body
/// or token stream instead of lexing from a character buffer. This is used for
@@ -55,9 +57,9 @@ class TokenLexer {
///
unsigned NumTokens;
- /// CurToken - This is the next token that Lex will return.
+ /// This is the index of the next token that Lex will return.
///
- unsigned CurToken;
+ unsigned CurTokenIdx;
/// ExpandLocStart/End - The source location range where this macro was
/// expanded.
@@ -156,15 +158,56 @@ private:
/// isAtEnd - Return true if the next lex call will pop this macro off the
/// include stack.
bool isAtEnd() const {
- return CurToken == NumTokens;
+ return CurTokenIdx == NumTokens;
}
- /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
- /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there
- /// are is another ## after it, chomp it iteratively. Return the result as
- /// Tok. If this returns true, the caller should immediately return the
+ /// Concatenates the next (sub-)sequence of \p Tokens separated by '##'
+ /// starting with LHSTok - stopping when we encounter a token that is neither
+ /// '##' nor preceded by '##'. Places the result back into \p LHSTok and sets
+ /// \p CurIdx to point to the token following the last one that was pasted.
+ ///
+ /// Also performs the MSVC extension wide-literal token pasting involved with:
+ /// \code L #macro-arg. \endcode
+ ///
+ /// \param[in,out] LHSTok - Contains the token to the left of '##' in \p
+ /// Tokens upon entry and will contain the resulting concatenated Token upon
+ /// exit.
+ ///
+ /// \param[in] TokenStream - The stream of Tokens we are lexing from.
+ ///
+ /// \param[in,out] CurIdx - Upon entry, \pTokens[\pCurIdx] must equal '##'
+ /// (with the exception of the MSVC extension mentioned above). Upon exit, it
+ /// is set to the index of the token following the last token that was
+ /// concatenated together.
+ ///
+ /// \returns If this returns true, the caller should immediately return the
/// token.
- bool PasteTokens(Token &Tok);
+
+ bool pasteTokens(Token &LHSTok, ArrayRef<Token> TokenStream,
+ unsigned int &CurIdx);
+
+ /// Calls pasteTokens above, passing in the '*this' object's Tokens and
+ /// CurTokenIdx data members.
+ bool pasteTokens(Token &Tok);
+
+
+ /// Takes the tail sequence of tokens within ReplacementToks that represent
+ /// the just expanded __VA_OPT__ tokens (possibly zero tokens) and transforms
+ /// them into a string. \p VCtx is used to determine which token represents
+ /// the first __VA_OPT__ replacement token.
+ ///
+ /// \param[in,out] ReplacementToks - Contains the current Replacement Tokens
+ /// (prior to rescanning and token pasting), the tail end of which represents
+ /// the tokens just expanded through __VA_OPT__ processing. These (sub)
+ /// sequence of tokens are folded into one stringified token.
+ ///
+ /// \param[in] VCtx - contains relevent contextual information about the
+ /// state of the tokens around and including the __VA_OPT__ token, necessary
+ /// for stringification.
+
+ void stringifyVAOPTContents(SmallVectorImpl<Token> &ReplacementToks,
+ const VAOptExpansionContext &VCtx,
+ SourceLocation VAOPTClosingParenLoc);
/// Expand the arguments of a function-like macro so that we can quickly
/// return preexpanded tokens from Tokens.
diff --git a/include/clang/Lex/VariadicMacroSupport.h b/include/clang/Lex/VariadicMacroSupport.h
new file mode 100644
index 0000000000..cebaf15187
--- /dev/null
+++ b/include/clang/Lex/VariadicMacroSupport.h
@@ -0,0 +1,226 @@
+//===- VariadicMacroSupport.h - state machines and scope guards -*- 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 support types to help with preprocessing variadic macro
+// (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and
+// expansions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
+#define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
+
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+ class Preprocessor;
+
+ /// An RAII class that tracks when the Preprocessor starts and stops lexing
+ /// the definition of a (ISO C/C++) variadic macro. As an example, this is
+ /// useful for unpoisoning and repoisoning certain identifiers (such as
+ /// __VA_ARGS__) that are only allowed in this context. Also, being a friend
+ /// of the Preprocessor class allows it to access PP's cached identifiers
+ /// directly (as opposed to performing a lookup each time).
+ class VariadicMacroScopeGuard {
+ const Preprocessor &PP;
+ IdentifierInfo *const Ident__VA_ARGS__;
+ IdentifierInfo *const Ident__VA_OPT__;
+
+ public:
+ VariadicMacroScopeGuard(const Preprocessor &P)
+ : PP(P), Ident__VA_ARGS__(PP.Ident__VA_ARGS__),
+ Ident__VA_OPT__(PP.Ident__VA_OPT__) {
+ assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned "
+ "outside an ISO C/C++ variadic "
+ "macro definition!");
+ assert(
+ !Ident__VA_OPT__ ||
+ (Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!"));
+ }
+
+ /// Client code should call this function just before the Preprocessor is
+ /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.
+ void enterScope() {
+ Ident__VA_ARGS__->setIsPoisoned(false);
+ if (Ident__VA_OPT__)
+ Ident__VA_OPT__->setIsPoisoned(false);
+ }
+
+ /// Client code should call this function as soon as the Preprocessor has
+ /// either completed lexing the macro's definition tokens, or an error
+ /// occured and the context is being exited. This function is idempotent
+ /// (might be explicitly called, and then reinvoked via the destructor).
+ void exitScope() {
+ Ident__VA_ARGS__->setIsPoisoned(true);
+ if (Ident__VA_OPT__)
+ Ident__VA_OPT__->setIsPoisoned(true);
+ }
+
+ ~VariadicMacroScopeGuard() { exitScope(); }
+ };
+
+ /// \brief A class for tracking whether we're inside a VA_OPT during a
+ /// traversal of the tokens of a variadic macro definition.
+ class VAOptDefinitionContext {
+ /// Contains all the locations of so far unmatched lparens.
+ SmallVector<SourceLocation, 8> UnmatchedOpeningParens;
+
+ const IdentifierInfo *const Ident__VA_OPT__;
+
+
+ public:
+ VAOptDefinitionContext(Preprocessor &PP)
+ : Ident__VA_OPT__(PP.Ident__VA_OPT__) {}
+
+ bool isVAOptToken(const Token &T) const {
+ return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__;
+ }
+
+ /// Returns true if we have seen the __VA_OPT__ and '(' but before having
+ /// seen the matching ')'.
+ bool isInVAOpt() const { return UnmatchedOpeningParens.size(); }
+
+ /// Call this function as soon as you see __VA_OPT__ and '('.
+ void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) {
+ assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
+ UnmatchedOpeningParens.push_back(LParenLoc);
+
+ }
+
+ SourceLocation getUnmatchedOpeningParenLoc() const {
+ assert(isInVAOpt() && "Must be within VAOPT context to call this");
+ return UnmatchedOpeningParens.back();
+ }
+
+ /// Call this function each time an rparen is seen. It returns true only if
+ /// the rparen that was just seen was the eventual (non-nested) closing
+ /// paren for VAOPT, and ejects us out of the VAOPT context.
+ bool sawClosingParen() {
+ assert(isInVAOpt() && "Must be within VAOPT context to call this");
+ UnmatchedOpeningParens.pop_back();
+ return !UnmatchedOpeningParens.size();
+ }
+
+ /// Call this function each time an lparen is seen.
+ void sawOpeningParen(SourceLocation LParenLoc) {
+ assert(isInVAOpt() && "Must be within VAOPT context to call this");
+ UnmatchedOpeningParens.push_back(LParenLoc);
+ }
+
+ };
+
+ /// \brief A class for tracking whether we're inside a VA_OPT during a
+ /// traversal of the tokens of a macro during macro expansion.
+ class VAOptExpansionContext : VAOptDefinitionContext {
+
+ Token SyntheticEOFToken;
+
+ // The (spelling) location of the current __VA_OPT__ in the replacement list
+ // of the function-like macro being expanded.
+ SourceLocation VAOptLoc;
+
+ // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first
+ // token of the current VAOPT contents (so we know where to start eager
+ // token-pasting and stringification) *within* the substituted tokens of
+ // the function-like macro's new replacement list.
+ int NumOfTokensPriorToVAOpt = -1;
+
+ unsigned LeadingSpaceForStringifiedToken : 1;
+
+ unsigned StringifyBefore : 1;
+ unsigned CharifyBefore : 1;
+
+
+ bool hasStringifyBefore() const {
+ assert(!isReset() &&
+ "Must only be called if the state has not been reset");
+ return StringifyBefore;
+ }
+
+ bool isReset() const {
+ return NumOfTokensPriorToVAOpt == -1 ||
+ VAOptLoc.isInvalid();
+ }
+
+ public:
+ VAOptExpansionContext(Preprocessor &PP)
+ : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
+ StringifyBefore(false), CharifyBefore(false) {
+ SyntheticEOFToken.startToken();
+ SyntheticEOFToken.setKind(tok::eof);
+ }
+
+ void reset() {
+ VAOptLoc = SourceLocation();
+ NumOfTokensPriorToVAOpt = -1;
+ LeadingSpaceForStringifiedToken = false;
+ StringifyBefore = false;
+ CharifyBefore = false;
+ }
+
+ const Token &getEOFTok() const { return SyntheticEOFToken; }
+
+ void sawHashOrHashAtBefore(const bool HasLeadingSpace,
+ const bool IsHashAt) {
+
+ StringifyBefore = !IsHashAt;
+ CharifyBefore = IsHashAt;
+ LeadingSpaceForStringifiedToken = HasLeadingSpace;
+ }
+
+
+
+ bool hasCharifyBefore() const {
+ assert(!isReset() &&
+ "Must only be called if the state has not been reset");
+ return CharifyBefore;
+ }
+ bool hasStringifyOrCharifyBefore() const {
+ return hasStringifyBefore() || hasCharifyBefore();
+ }
+
+ unsigned int getNumberOfTokensPriorToVAOpt() const {
+ assert(!isReset() &&
+ "Must only be called if the state has not been reset");
+ return NumOfTokensPriorToVAOpt;
+ }
+
+ bool getLeadingSpaceForStringifiedToken() const {
+ assert(hasStringifyBefore() &&
+ "Must only be called if this has been marked for stringification");
+ return LeadingSpaceForStringifiedToken;
+ }
+
+ void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc,
+ const unsigned int NumPriorTokens) {
+ assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
+ assert(isReset() && "Must only be called if the state has been reset");
+ VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation());
+ this->VAOptLoc = VAOptLoc;
+ NumOfTokensPriorToVAOpt = NumPriorTokens;
+ assert(NumOfTokensPriorToVAOpt > -1 &&
+ "Too many prior tokens");
+ }
+
+ SourceLocation getVAOptLoc() const {
+ assert(!isReset() &&
+ "Must only be called if the state has not been reset");
+ assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
+ return VAOptLoc;
+ }
+ using VAOptDefinitionContext::isVAOptToken;
+ using VAOptDefinitionContext::isInVAOpt;
+ using VAOptDefinitionContext::sawClosingParen;
+ using VAOptDefinitionContext::sawOpeningParen;
+
+ };
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Parse/CMakeLists.txt b/include/clang/Parse/CMakeLists.txt
index ec75f7b96b..2cc7e54b3b 100644
--- a/include/clang/Parse/CMakeLists.txt
+++ b/include/clang/Parse/CMakeLists.txt
@@ -2,3 +2,9 @@ clang_tablegen(AttrParserStringSwitches.inc -gen-clang-attr-parser-string-switch
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
TARGET ClangAttrParserStringSwitches)
+
+clang_tablegen(AttrSubMatchRulesParserStringSwitches.inc
+ -gen-clang-attr-subject-match-rules-parser-string-switches
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrSubMatchRulesParserStringSwitches)
diff --git a/include/clang/Parse/ParseAST.h b/include/clang/Parse/ParseAST.h
index 21f9701c3e..34c96816eb 100644
--- a/include/clang/Parse/ParseAST.h
+++ b/include/clang/Parse/ParseAST.h
@@ -29,10 +29,13 @@ namespace clang {
/// This operation inserts the parsed decls into the translation
/// unit held by Ctx.
///
+ /// \param PrintStats Whether to print LLVM statistics related to parsing.
/// \param TUKind The kind of translation unit being parsed.
- ///
/// \param CompletionConsumer If given, an object to consume code completion
/// results.
+ /// \param SkipFunctionBodies Whether to skip parsing of function bodies.
+ /// This option can be used, for example, to speed up searches for
+ /// declarations/definitions when indexing.
void ParseAST(Preprocessor &pp, ASTConsumer *C,
ASTContext &Ctx, bool PrintStats = false,
TranslationUnitKind TUKind = TU_Complete,
@@ -43,7 +46,7 @@ namespace clang {
/// abstract syntax tree.
void ParseAST(Sema &S, bool PrintStats = false,
bool SkipFunctionBodies = false);
-
+
} // end namespace clang
#endif
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 70381e507e..ce60cbb431 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -166,6 +166,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> FPContractHandler;
std::unique_ptr<PragmaHandler> OpenCLExtensionHandler;
std::unique_ptr<PragmaHandler> OpenMPHandler;
+ std::unique_ptr<PragmaHandler> PCSectionHandler;
std::unique_ptr<PragmaHandler> MSCommentHandler;
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
std::unique_ptr<PragmaHandler> MSPointersToMembers;
@@ -183,6 +184,8 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> LoopHintHandler;
std::unique_ptr<PragmaHandler> UnrollHintHandler;
std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
+ std::unique_ptr<PragmaHandler> FPHandler;
+ std::unique_ptr<PragmaHandler> AttributePragmaHandler;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@@ -250,6 +253,10 @@ class Parser : public CodeCompletionHandler {
/// be NULL.
bool ParsingInObjCContainer;
+ /// Whether to skip parsing of function bodies.
+ ///
+ /// This option can be used, for example, to speed up searches for
+ /// declarations/definitions when indexing.
bool SkipFunctionBodies;
/// The location of the expression statement that is being parsed right now.
@@ -302,8 +309,9 @@ public:
}
/// ConsumeToken - Consume the current 'peek token' and lex the next one.
- /// This does not work with special tokens: string literals, code completion
- /// and balanced tokens must be handled using the specific consume methods.
+ /// This does not work with special tokens: string literals, code completion,
+ /// annotation tokens and balanced tokens must be handled using the specific
+ /// consume methods.
/// Returns the location of the consumed token.
SourceLocation ConsumeToken() {
assert(!isTokenSpecial() &&
@@ -330,6 +338,27 @@ public:
return true;
}
+ /// ConsumeAnyToken - Dispatch to the right Consume* method based on the
+ /// current token type. This should only be used in cases where the type of
+ /// the token really isn't known, e.g. in error recovery.
+ SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) {
+ if (isTokenParen())
+ return ConsumeParen();
+ if (isTokenBracket())
+ return ConsumeBracket();
+ if (isTokenBrace())
+ return ConsumeBrace();
+ if (isTokenStringLiteral())
+ return ConsumeStringToken();
+ if (Tok.is(tok::code_completion))
+ return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken()
+ : handleUnexpectedCodeCompletionToken();
+ if (Tok.isAnnotation())
+ return ConsumeAnnotationToken();
+ return ConsumeToken();
+ }
+
+
SourceLocation getEndOfPreviousToken() {
return PP.getLocForEndOfToken(PrevTokLocation);
}
@@ -364,7 +393,7 @@ private:
/// isTokenSpecial - True if this token requires special consumption methods.
bool isTokenSpecial() const {
return isTokenStringLiteral() || isTokenParen() || isTokenBracket() ||
- isTokenBrace() || Tok.is(tok::code_completion);
+ isTokenBrace() || Tok.is(tok::code_completion) || Tok.isAnnotation();
}
/// \brief Returns true if the current token is '=' or is a type of '='.
@@ -380,22 +409,12 @@ private:
PP.EnterToken(Next);
}
- /// ConsumeAnyToken - Dispatch to the right Consume* method based on the
- /// current token type. This should only be used in cases where the type of
- /// the token really isn't known, e.g. in error recovery.
- SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) {
- if (isTokenParen())
- return ConsumeParen();
- if (isTokenBracket())
- return ConsumeBracket();
- if (isTokenBrace())
- return ConsumeBrace();
- if (isTokenStringLiteral())
- return ConsumeStringToken();
- if (Tok.is(tok::code_completion))
- return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken()
- : handleUnexpectedCodeCompletionToken();
- return ConsumeToken();
+ SourceLocation ConsumeAnnotationToken() {
+ assert(Tok.isAnnotation() && "wrong consume method");
+ SourceLocation Loc = Tok.getLocation();
+ PrevTokLocation = Tok.getAnnotationEndLoc();
+ PP.Lex(Tok);
+ return Loc;
}
/// ConsumeParen - This consume method keeps the paren count up-to-date.
@@ -487,6 +506,12 @@ private:
Kind == tok::annot_module_end || Kind == tok::annot_module_include;
}
+ /// \brief Checks if the \p Level is valid for use in a fold expression.
+ bool isFoldOperator(prec::Level Level) const;
+
+ /// \brief Checks if the \p Kind is a valid operator for fold expressions.
+ bool isFoldOperator(tok::TokenKind Kind) const;
+
/// \brief Initialize all pragma handlers.
void initializePragmaHandlers();
@@ -549,6 +574,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();
@@ -560,6 +589,12 @@ private:
/// #pragma clang loop and #pragma unroll.
bool HandlePragmaLoopHint(LoopHint &Hint);
+ bool ParsePragmaAttributeSubjectMatchRuleSet(
+ attr::ParsedSubjectMatchRuleSet &SubjectMatchRules,
+ SourceLocation &AnyLoc, SourceLocation &LastMatchRuleEndLoc);
+
+ void HandlePragmaAttribute();
+
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
/// returns the token after Tok, etc.
@@ -580,7 +615,7 @@ public:
}
/// getTypeAnnotation - Read a parsed type out of an annotation token.
- static ParsedType getTypeAnnotation(Token &Tok) {
+ static ParsedType getTypeAnnotation(const Token &Tok) {
return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue());
}
@@ -591,7 +626,7 @@ private:
/// \brief Read an already-translated primary expression out of an annotation
/// token.
- static ExprResult getExprAnnotation(Token &Tok) {
+ static ExprResult getExprAnnotation(const Token &Tok) {
return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue());
}
@@ -795,6 +830,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
@@ -1429,6 +1472,8 @@ public:
};
ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
+ ExprResult ParseConstantExpressionInExprEvalContext(
+ TypeCastState isTypeCast = NotTypeCast);
ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast);
ExprResult ParseConstraintExpression();
// Expr that doesn't include commas.
@@ -1436,7 +1481,6 @@ public:
ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
unsigned &NumLineToksConsumed,
- void *Info,
bool IsUnevaluated);
private:
@@ -1449,10 +1493,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();
@@ -1466,6 +1512,8 @@ private:
K == tok::plusplus || K == tok::minusminus);
}
+ bool diagnoseUnknownTemplateId(ExprResult TemplateName, SourceLocation Less);
+
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
@@ -1479,9 +1527,10 @@ private:
typedef SmallVector<SourceLocation, 20> CommaLocsTy;
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
- bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
- SmallVectorImpl<SourceLocation> &CommaLocs,
- std::function<void()> Completer = nullptr);
+ bool ParseExpressionList(
+ SmallVectorImpl<Expr *> &Exprs,
+ SmallVectorImpl<SourceLocation> &CommaLocs,
+ llvm::function_ref<void()> Completer = llvm::function_ref<void()>());
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
/// used for misc language extensions.
@@ -1534,7 +1583,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
@@ -1686,7 +1736,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.
@@ -1695,11 +1745,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();
@@ -1728,7 +1778,7 @@ private:
StmtResult ParseAsmStatement(bool &msAsm);
StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
StmtResult ParsePragmaLoopHint(StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
@@ -1813,6 +1863,7 @@ private:
DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
DSC_top_level, // top-level/namespace declaration context
+ DSC_template_param, // template parameter context
DSC_template_type_arg, // template type argument context
DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
DSC_condition // condition declaration context
@@ -1823,6 +1874,7 @@ private:
static bool isTypeSpecifier(DeclSpecContext DSC) {
switch (DSC) {
case DSC_normal:
+ case DSC_template_param:
case DSC_class:
case DSC_top_level:
case DSC_objc_method_result:
@@ -1843,6 +1895,7 @@ private:
static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
switch (DSC) {
case DSC_normal:
+ case DSC_template_param:
case DSC_class:
case DSC_top_level:
case DSC_condition:
@@ -2117,18 +2170,25 @@ public:
private:
void ParseBlockId(SourceLocation CaretLoc);
- // Check for the start of a C++11 attribute-specifier-seq in a context where
- // an attribute is not allowed.
+ /// Are [[]] attributes enabled?
+ bool standardAttributesAllowed() const {
+ const LangOptions &LO = getLangOpts();
+ return LO.DoubleSquareBracketAttributes;
+ }
+
+ // Check for the start of an attribute-specifier-seq in a context where an
+ // attribute is not allowed.
bool CheckProhibitedCXX11Attribute() {
assert(Tok.is(tok::l_square));
- if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))
+ if (!standardAttributesAllowed() || NextToken().isNot(tok::l_square))
return false;
return DiagnoseProhibitedCXX11Attribute();
}
+
bool DiagnoseProhibitedCXX11Attribute();
void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
SourceLocation CorrectLocation) {
- if (!getLangOpts().CPlusPlus11)
+ if (!standardAttributesAllowed())
return;
if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
Tok.isNot(tok::kw_alignas))
@@ -2148,17 +2208,18 @@ private:
}
void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs);
- // Forbid C++11 attributes that appear on certain syntactic
- // locations which standard permits but we don't supported yet,
- // for example, attributes appertain to decl specifiers.
+ // Forbid C++11 and C2x attributes that appear on certain syntactic locations
+ // which standard permits but we don't supported yet, for example, attributes
+ // appertain to decl specifiers.
void ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
unsigned DiagID);
- /// \brief Skip C++11 attributes and return the end location of the last one.
+ /// \brief Skip C++11 and C2x attributes and return the end location of the
+ /// last one.
/// \returns SourceLocation() if there are no attributes.
SourceLocation SkipCXX11Attributes();
- /// \brief Diagnose and skip C++11 attributes that appear in syntactic
+ /// \brief Diagnose and skip C++11 and C2x attributes that appear in syntactic
/// locations where attributes are not allowed.
void DiagnoseAndSkipCXX11Attributes();
@@ -2208,7 +2269,7 @@ private:
AttributeList::Syntax Syntax);
void MaybeParseCXX11Attributes(Declarator &D) {
- if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
SourceLocation endLoc;
ParseCXX11Attributes(attrs, &endLoc);
@@ -2217,7 +2278,7 @@ private:
}
void MaybeParseCXX11Attributes(ParsedAttributes &attrs,
SourceLocation *endLoc = nullptr) {
- if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
+ if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrsWithRange(AttrFactory);
ParseCXX11Attributes(attrsWithRange, endLoc);
attrs.takeAllFrom(attrsWithRange);
@@ -2226,8 +2287,8 @@ private:
void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc = nullptr,
bool OuterMightBeMessageSend = false) {
- if (getLangOpts().CPlusPlus11 &&
- isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
+ if (standardAttributesAllowed() &&
+ isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
ParseCXX11Attributes(attrs, endLoc);
}
@@ -2235,8 +2296,8 @@ private:
SourceLocation *EndLoc = nullptr);
void ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *EndLoc = nullptr);
- /// \brief Parses a C++-style attribute argument list. Returns true if this
- /// results in adding an attribute to the ParsedAttributes list.
+ /// \brief Parses a C++11 (or C2x)-style attribute argument list. Returns true
+ /// if this results in adding an attribute to the ParsedAttributes list.
bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc,
@@ -2566,6 +2627,9 @@ private:
Decl *TagDecl = nullptr);
/// \brief Parse 'omp declare reduction' construct.
DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS);
+ /// Parses initializer for provided omp_priv declaration inside the reduction
+ /// initializer.
+ void ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm);
/// \brief Parses simple list of variables.
///
@@ -2587,7 +2651,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.
@@ -2678,11 +2742,11 @@ private:
AccessSpecifier AS=AS_none,
AttributeList *AccessAttrs = nullptr);
bool ParseTemplateParameters(unsigned Depth,
- SmallVectorImpl<Decl*> &TemplateParams,
+ SmallVectorImpl<NamedDecl *> &TemplateParams,
SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc);
bool ParseTemplateParameterList(unsigned Depth,
- SmallVectorImpl<Decl*> &TemplateParams);
+ SmallVectorImpl<NamedDecl*> &TemplateParams);
bool isStartOfTemplateTypeParameter();
Decl *ParseTemplateParameter(unsigned Depth, unsigned Position);
Decl *ParseTypeParameter(unsigned Depth, unsigned Position);
@@ -2700,10 +2764,7 @@ private:
bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
bool ConsumeLastToken,
bool ObjCGenericList);
- bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
- const CXXScopeSpec &SS,
- bool ConsumeLastToken,
+ bool ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
SourceLocation &RAngleLoc);
diff --git a/lib/Parse/RAIIObjectsForParser.h b/include/clang/Parse/RAIIObjectsForParser.h
index 36d87ebd8a..0422b038da 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/Rewrite/Frontend/FrontendActions.h b/include/clang/Rewrite/Frontend/FrontendActions.h
index 27976eac4e..5f83ac16fe 100644
--- a/include/clang/Rewrite/Frontend/FrontendActions.h
+++ b/include/clang/Rewrite/Frontend/FrontendActions.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_REWRITE_FRONTEND_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
class FixItRewriter;
@@ -34,8 +35,7 @@ protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
- bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void EndSourceFileAction() override;
@@ -74,7 +74,10 @@ protected:
};
class RewriteIncludesAction : public PreprocessorFrontendAction {
+ std::shared_ptr<raw_ostream> OutputStream;
+ class RewriteImportsListener;
protected:
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void ExecuteAction() override;
};
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 7c1678086c..0580ff8850 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_SEMA_ATTRIBUTELIST_H
#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/VersionTuple.h"
@@ -99,16 +100,20 @@ public:
AS_GNU,
/// [[...]]
AS_CXX11,
+ /// [[...]]
+ AS_C2x,
/// __declspec(...)
AS_Declspec,
/// [uuid("...")] class Foo
AS_Microsoft,
/// __ptr16, alignas(...), etc.
AS_Keyword,
- /// Context-sensitive version of a keyword attribute.
- AS_ContextSensitiveKeyword,
/// #pragma ...
AS_Pragma,
+ // Note TableGen depends on the order above. Do not add or change the order
+ // without adding related code to TableGen/ClangAttrEmitter.cpp.
+ /// Context-sensitive version of a keyword attribute.
+ AS_ContextSensitiveKeyword,
};
private:
@@ -375,6 +380,9 @@ public:
bool isCXX11Attribute() const {
return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
}
+ bool isC2xAttribute() const {
+ return SyntaxUsed == AS_C2x;
+ }
bool isKeywordAttribute() const {
return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
}
@@ -509,9 +517,14 @@ public:
unsigned getMaxArgs() const;
bool hasVariadicArg() const;
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
+ bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const;
+ void getMatchRules(const LangOptions &LangOpts,
+ SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>>
+ &MatchRules) const;
bool diagnoseLangOpts(class Sema &S) const;
bool existsInTarget(const TargetInfo &Target) const;
bool isKnownToGCC() const;
+ bool isSupportedByPragmaAttribute() const;
/// \brief If the parsed attribute has a semantic equivalent, and it would
/// have a semantic Spelling enumeration (due to having semantically-distinct
@@ -774,6 +787,8 @@ public:
void clear() { list = nullptr; pool.clear(); }
AttributeList *getList() const { return list; }
+ void clearListOnly() { list = nullptr; }
+
/// Returns a reference to the attribute list. Try not to introduce
/// dependencies on this method, it may not be long-lived.
AttributeList *&getListRef() { return list; }
@@ -907,6 +922,7 @@ enum AttributeDeclKind {
ExpectedTypeOrNamespace,
ExpectedObjectiveCInterface,
ExpectedMethodOrProperty,
+ ExpectedFunctionOrMethodOrProperty,
ExpectedStructOrUnion,
ExpectedStructOrUnionOrClass,
ExpectedType,
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 82f04a584b..4fc55a1dac 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -280,6 +280,7 @@ public:
static const TST TST_half = clang::TST_half;
static const TST TST_float = clang::TST_float;
static const TST TST_double = clang::TST_double;
+ static const TST TST_float16 = clang::TST_Float16;
static const TST TST_float128 = clang::TST_float128;
static const TST TST_bool = clang::TST_bool;
static const TST TST_decimal32 = clang::TST_decimal32;
@@ -861,11 +862,19 @@ 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
@@ -882,6 +891,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.
@@ -1988,41 +2000,6 @@ public:
llvm_unreachable("unknown context kind!");
}
- /// diagnoseIdentifier - Return true if the identifier is prohibited and
- /// should be diagnosed (because it cannot be anything else).
- bool diagnoseIdentifier() const {
- switch (Context) {
- case FileContext:
- case KNRTypeListContext:
- case MemberContext:
- case BlockContext:
- case ForContext:
- case InitStmtContext:
- case ConditionContext:
- case PrototypeContext:
- case LambdaExprParameterContext:
- case TemplateParamContext:
- case CXXCatchContext:
- case ObjCCatchContext:
- case TypeNameContext:
- case FunctionalCastContext:
- case ConversionIdContext:
- case ObjCParameterContext:
- case ObjCResultContext:
- case BlockLiteralContext:
- case CXXNewContext:
- case LambdaExprContext:
- return false;
-
- case AliasDeclContext:
- case AliasTemplateContext:
- case TemplateTypeArgContext:
- case TrailingReturnContext:
- return true;
- }
- llvm_unreachable("unknown context kind!");
- }
-
/// Return true if the context permits a C++17 decomposition declarator.
bool mayHaveDecompositionDeclarator() const {
switch (Context) {
@@ -2324,6 +2301,42 @@ public:
}
llvm_unreachable("unknown context kind!");
}
+
+ /// Determine whether this declaration appears in a context where an
+ /// expression could appear.
+ bool isExpressionContext() const {
+ switch (Context) {
+ case FileContext:
+ case KNRTypeListContext:
+ case MemberContext:
+ case TypeNameContext: // FIXME: sizeof(...) permits an expression.
+ case FunctionalCastContext:
+ case AliasDeclContext:
+ case AliasTemplateContext:
+ case PrototypeContext:
+ case LambdaExprParameterContext:
+ case ObjCParameterContext:
+ case ObjCResultContext:
+ case TemplateParamContext:
+ case CXXNewContext:
+ case CXXCatchContext:
+ case ObjCCatchContext:
+ case BlockLiteralContext:
+ case LambdaExprContext:
+ case ConversionIdContext:
+ case TrailingReturnContext:
+ return false;
+
+ case BlockContext:
+ case ForContext:
+ case InitStmtContext:
+ case ConditionContext:
+ case TemplateTypeArgContext:
+ return true;
+ }
+
+ llvm_unreachable("unknown context kind!");
+ }
/// \brief Return true if a function declarator at this position would be a
/// function declaration.
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index b73ec0868f..d65dbf0cd3 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -124,7 +124,8 @@ public:
static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
SourceLocation Loc,
- const NamedDecl *D,
+ const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
StringRef Msg,
@@ -164,9 +165,13 @@ public:
return *reinterpret_cast<const AccessedEntity*>(AccessData);
}
- const NamedDecl *getAvailabilityDecl() const {
+ const NamedDecl *getAvailabilityReferringDecl() const {
assert(Kind == Availability && "Not an availability diagnostic.");
- return AvailabilityData.Decl;
+ return AvailabilityData.ReferringDecl;
+ }
+
+ const NamedDecl *getAvailabilityOffendingDecl() const {
+ return AvailabilityData.OffendingDecl;
}
StringRef getAvailabilityMessage() const {
@@ -213,7 +218,8 @@ public:
private:
struct AD {
- const NamedDecl *Decl;
+ const NamedDecl *ReferringDecl;
+ const NamedDecl *OffendingDecl;
const ObjCInterfaceDecl *UnknownObjCClass;
const ObjCPropertyDecl *ObjCProperty;
const char *Message;
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index a07834f956..382fe80bea 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 7b13867cdf..bd07b9ea9a 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) {
@@ -822,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
@@ -866,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
@@ -892,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 2ed9548b59..546df8842a 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -18,6 +18,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/Sema/Sema.h"
+#include "llvm/ADT/Optional.h"
+
namespace clang {
/// @brief Represents the results of name lookup.
@@ -137,6 +139,7 @@ public:
LookupKind(LookupKind),
IDNS(0),
Redecl(Redecl != Sema::NotForRedeclaration),
+ ExternalRedecl(Redecl == Sema::ForExternalRedeclaration),
HideTags(true),
Diagnose(Redecl == Sema::NotForRedeclaration),
AllowHidden(false),
@@ -146,7 +149,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,
@@ -159,6 +162,7 @@ public:
LookupKind(LookupKind),
IDNS(0),
Redecl(Redecl != Sema::NotForRedeclaration),
+ ExternalRedecl(Redecl == Sema::ForExternalRedeclaration),
HideTags(true),
Diagnose(Redecl == Sema::NotForRedeclaration),
AllowHidden(false),
@@ -179,6 +183,7 @@ public:
LookupKind(Other.LookupKind),
IDNS(Other.IDNS),
Redecl(Other.Redecl),
+ ExternalRedecl(Other.ExternalRedecl),
HideTags(Other.HideTags),
Diagnose(false),
AllowHidden(Other.AllowHidden),
@@ -199,7 +204,9 @@ public:
SemaPtr(std::move(Other.SemaPtr)), NameInfo(std::move(Other.NameInfo)),
NameContextRange(std::move(Other.NameContextRange)),
LookupKind(std::move(Other.LookupKind)), IDNS(std::move(Other.IDNS)),
- Redecl(std::move(Other.Redecl)), HideTags(std::move(Other.HideTags)),
+ Redecl(std::move(Other.Redecl)),
+ ExternalRedecl(std::move(Other.ExternalRedecl)),
+ HideTags(std::move(Other.HideTags)),
Diagnose(std::move(Other.Diagnose)),
AllowHidden(std::move(Other.AllowHidden)),
Shadowed(std::move(Other.Shadowed)) {
@@ -219,6 +226,7 @@ public:
LookupKind = std::move(Other.LookupKind);
IDNS = std::move(Other.IDNS);
Redecl = std::move(Other.Redecl);
+ ExternalRedecl = std::move(Other.ExternalRedecl);
HideTags = std::move(Other.HideTags);
Diagnose = std::move(Other.Diagnose);
AllowHidden = std::move(Other.AllowHidden);
@@ -263,6 +271,17 @@ public:
return Redecl;
}
+ /// True if this lookup is just looking for an existing declaration to link
+ /// against a declaration with external linkage.
+ bool isForExternalRedeclaration() const {
+ return ExternalRedecl;
+ }
+
+ Sema::RedeclarationKind redeclarationKind() const {
+ return ExternalRedecl ? Sema::ForExternalRedeclaration :
+ Redecl ? Sema::ForVisibleRedeclaration : Sema::NotForRedeclaration;
+ }
+
/// \brief Specify whether hidden declarations are visible, e.g.,
/// for recovery reasons.
void setAllowHidden(bool AH) {
@@ -273,7 +292,7 @@ public:
/// declarations, such as those in modules that have not yet been imported.
bool isHiddenDeclarationVisible(NamedDecl *ND) const {
return AllowHidden ||
- (isForRedeclaration() && ND->isExternallyVisible());
+ (isForExternalRedeclaration() && ND->isExternallyDeclarable());
}
/// Sets whether tag declarations should be hidden by non-tag
@@ -465,7 +484,7 @@ public:
Paths = nullptr;
}
} else {
- AmbiguityKind SavedAK;
+ llvm::Optional<AmbiguityKind> SavedAK;
bool WasAmbiguous = false;
if (ResultKind == Ambiguous) {
SavedAK = Ambiguity;
@@ -479,7 +498,7 @@ public:
if (ResultKind == Ambiguous) {
(void)WasAmbiguous;
assert(WasAmbiguous);
- Ambiguity = SavedAK;
+ Ambiguity = SavedAK.getValue();
} else if (Paths) {
deletePaths(Paths);
Paths = nullptr;
@@ -554,7 +573,8 @@ public:
/// \brief Change this lookup's redeclaration kind.
void setRedeclarationKind(Sema::RedeclarationKind RK) {
- Redecl = RK;
+ Redecl = (RK != Sema::NotForRedeclaration);
+ ExternalRedecl = (RK == Sema::ForExternalRedeclaration);
configure();
}
@@ -717,6 +737,7 @@ private:
unsigned IDNS; // set by configure()
bool Redecl;
+ bool ExternalRedecl;
/// \brief True if tag declarations should be hidden if non-tags
/// are present
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
index 93e83dc026..1d681a0055 100644
--- a/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -90,7 +90,7 @@ public:
/// initializers themselves.
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
- ExtKind hasExternalDefinitions(unsigned ID) override;
+ ExtKind hasExternalDefinitions(const Decl *D) override;
/// \brief Find all declarations with the given name in the
/// given context.
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 5220d98730..05cfe53666 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.
@@ -632,12 +633,9 @@ namespace clang {
/// Might be a UsingShadowDecl or a FunctionTemplateDecl.
DeclAccessPair FoundDecl;
- // BuiltinTypes - Provides the return and parameter types of a
- // built-in overload candidate. Only valid when Function is NULL.
- struct {
- QualType ResultTy;
- QualType ParamTypes[3];
- } BuiltinTypes;
+ /// BuiltinParamTypes - Provides the parameter types of a built-in overload
+ /// candidate. Only valid when Function is NULL.
+ QualType BuiltinParamTypes[3];
/// Surrogate - The conversion function for which this candidate
/// is a surrogate, but only if IsSurrogate is true.
@@ -728,11 +726,20 @@ namespace clang {
enum CandidateSetKind {
/// Normal lookup.
CSK_Normal,
- /// Lookup for candidates for a call using operator syntax. Candidates
- /// that have no parameters of class type will be skipped unless there
- /// is a parameter of (reference to) enum type and the corresponding
- /// argument is of the same enum type.
- CSK_Operator
+ /// C++ [over.match.oper]:
+ /// Lookup of operator function candidates in a call using operator
+ /// syntax. Candidates that have no parameters of class type will be
+ /// skipped unless there is a parameter of (reference to) enum type and
+ /// the corresponding argument is of the same enum type.
+ CSK_Operator,
+ /// C++ [over.match.copy]:
+ /// Copy-initialization of an object of class type by user-defined
+ /// conversion.
+ CSK_InitByUserDefinedConversion,
+ /// C++ [over.match.ctor], [over.match.list]
+ /// Initialization of an object of class type by constructor,
+ /// using either a parenthesized or braced list of arguments.
+ CSK_InitByConstructor,
};
private:
@@ -797,7 +804,7 @@ namespace clang {
}
/// \brief Clear out all of the candidates.
- void clear();
+ void clear(CandidateSetKind CSK);
typedef SmallVectorImpl<OverloadCandidate>::iterator iterator;
iterator begin() { return Candidates.begin(); }
@@ -837,8 +844,7 @@ namespace clang {
/// Find the best viable function on this overload set, if it exists.
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
- OverloadCandidateSet::iterator& Best,
- bool UserDefinedConversion = false);
+ OverloadCandidateSet::iterator& Best);
void NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
@@ -850,10 +856,10 @@ namespace clang {
};
bool isBetterOverloadCandidate(Sema &S,
- const OverloadCandidate& Cand1,
- const OverloadCandidate& Cand2,
+ const OverloadCandidate &Cand1,
+ const OverloadCandidate &Cand2,
SourceLocation Loc,
- bool UserDefinedConversion = false);
+ OverloadCandidateSet::CandidateSetKind Kind);
struct ConstructorInfo {
DeclAccessPair FoundDecl;
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index 848837a1de..1e35316fd5 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -107,8 +107,7 @@ namespace clang {
namespace llvm {
template <class T>
- class PointerLikeTypeTraits<clang::OpaquePtr<T> > {
- public:
+ struct PointerLikeTypeTraits<clang::OpaquePtr<T> > {
static inline void *getAsVoidPointer(clang::OpaquePtr<T> P) {
// FIXME: Doesn't work? return P.getAs< void >();
return P.getAsOpaquePtr();
diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h
index 03de9ff6ae..01a4ab3f37 100644
--- a/include/clang/Sema/ParsedTemplate.h
+++ b/include/clang/Sema/ParsedTemplate.h
@@ -145,12 +145,15 @@ namespace clang {
/// expressions, or template names, and the source locations for important
/// tokens. All of the information about template arguments is allocated
/// directly after this structure.
- struct TemplateIdAnnotation {
+ struct TemplateIdAnnotation final
+ : private llvm::TrailingObjects<TemplateIdAnnotation,
+ ParsedTemplateArgument> {
+ friend TrailingObjects;
/// \brief The nested-name-specifier that precedes the template name.
CXXScopeSpec SS;
- /// TemplateKWLoc - The location of the template keyword within the
- /// source.
+ /// TemplateKWLoc - The location of the template keyword.
+ /// For e.g. typename T::template Y<U>
SourceLocation TemplateKWLoc;
/// TemplateNameLoc - The location of the template name within the
@@ -183,34 +186,56 @@ namespace clang {
/// \brief Retrieves a pointer to the template arguments
ParsedTemplateArgument *getTemplateArgs() {
- return reinterpret_cast<ParsedTemplateArgument *>(this + 1);
+ return getTrailingObjects<ParsedTemplateArgument>();
}
/// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and
/// appends it to List.
static TemplateIdAnnotation *
- Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) {
- TemplateIdAnnotation *TemplateId
- = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
- sizeof(ParsedTemplateArgument) * NumArgs);
- TemplateId->NumArgs = NumArgs;
-
- // Default-construct nested-name-specifier.
- new (&TemplateId->SS) CXXScopeSpec();
-
- // Default-construct parsed template arguments.
- ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs();
- for (unsigned I = 0; I != NumArgs; ++I)
- new (TemplateArgs + I) ParsedTemplateArgument();
-
- List.push_back(TemplateId);
+ Create(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
+ SourceLocation TemplateNameLoc, IdentifierInfo *Name,
+ OverloadedOperatorKind OperatorKind,
+ ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind,
+ SourceLocation LAngleLoc, SourceLocation RAngleLoc,
+ ArrayRef<ParsedTemplateArgument> TemplateArgs,
+ SmallVectorImpl<TemplateIdAnnotation *> &CleanupList) {
+
+ TemplateIdAnnotation *TemplateId = new (std::malloc(
+ totalSizeToAlloc<ParsedTemplateArgument>(TemplateArgs.size())))
+ TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name,
+ OperatorKind, OpaqueTemplateName, TemplateKind,
+ LAngleLoc, RAngleLoc, TemplateArgs);
+ CleanupList.push_back(TemplateId);
return TemplateId;
}
-
- void Destroy() {
- SS.~CXXScopeSpec();
+
+ void Destroy() {
+ std::for_each(
+ getTemplateArgs(), getTemplateArgs() + NumArgs,
+ [](ParsedTemplateArgument &A) { A.~ParsedTemplateArgument(); });
+ this->~TemplateIdAnnotation();
free(this);
}
+ private:
+ TemplateIdAnnotation(const TemplateIdAnnotation &) = delete;
+
+ TemplateIdAnnotation(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
+ SourceLocation TemplateNameLoc, IdentifierInfo *Name,
+ OverloadedOperatorKind OperatorKind,
+ ParsedTemplateTy OpaqueTemplateName,
+ TemplateNameKind TemplateKind,
+ SourceLocation LAngleLoc, SourceLocation RAngleLoc,
+ ArrayRef<ParsedTemplateArgument> TemplateArgs) noexcept
+ : SS(SS), TemplateKWLoc(TemplateKWLoc),
+ TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind),
+ Template(OpaqueTemplateName), Kind(TemplateKind),
+ LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
+ NumArgs(TemplateArgs.size()) {
+
+ std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(),
+ getTemplateArgs());
+ }
+ ~TemplateIdAnnotation() = default;
};
/// Retrieves the range of the given template parameter lists.
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index d0b006b82e..cd58a9910f 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -124,6 +124,12 @@ public:
/// We are currently in the filter expression of an SEH except block.
SEHFilterScope = 0x200000,
+
+ /// This is a compound statement scope.
+ CompoundStmtScope = 0x400000,
+
+ /// We are between inheritance colon and the real class/struct definition scope.
+ ClassInheritanceScope = 0x800000,
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -429,6 +435,11 @@ public:
/// \brief Determine whether this scope is a SEH '__except' block.
bool isSEHExceptScope() const { return getFlags() & Scope::SEHExceptScope; }
+ /// \brief Determine whether this scope is a compound statement scope.
+ bool isCompoundStmtScope() const {
+ return getFlags() & Scope::CompoundStmtScope;
+ }
+
/// \brief Returns if rhs has a higher scope depth than this.
///
/// The caller is responsible for calling this only if one of the two scopes
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 4487c7c2cc..6bb667deb2 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -388,6 +388,8 @@ public:
(HasBranchProtectedScope && HasBranchIntoScope));
}
+ bool isCoroutine() const { return !FirstCoroutineStmtLoc.isInvalid(); }
+
void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) {
assert(FirstCoroutineStmtLoc.isInvalid() &&
"first coroutine statement location already set");
@@ -831,6 +833,12 @@ public:
return FSI->Kind == SK_Lambda;
}
+ /// Is this scope known to be for a generic lambda? (This will be false until
+ /// we parse the first 'auto'-typed parameter.
+ bool isGenericLambda() const {
+ return !AutoTemplateParams.empty() || GLTemplateParameterList;
+ }
+
///
/// \brief Add a variable that might potentially be captured by the
/// lambda and therefore the enclosing lambdas.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 6995740635..66328adad6 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -64,7 +64,7 @@ namespace llvm {
template <typename ValueT> struct DenseMapInfo;
template <typename ValueT, typename ValueInfoT> class DenseSet;
class SmallBitVector;
- class InlineAsmIdentifierInfo;
+ struct InlineAsmIdentifierInfo;
}
namespace clang {
@@ -208,6 +208,7 @@ namespace sema {
class FunctionScopeInfo;
class LambdaScopeInfo;
class PossiblyUnreachableDiag;
+ class SemaPPCallbacks;
class TemplateDeductionInfo;
}
@@ -228,6 +229,10 @@ struct FileNullability {
/// not have a corresponding nullability annotation.
SourceLocation PointerLoc;
+ /// The end location for the first pointer declarator in the file. Used for
+ /// placing fix-its.
+ SourceLocation PointerEndLoc;
+
/// Which kind of pointer declarator we saw.
uint8_t PointerKind;
@@ -280,15 +285,21 @@ class Sema {
bool isVisibleSlow(const NamedDecl *D);
+ /// Determine whether two declarations should be linked together, given that
+ /// the old declaration might not be visible and the new declaration might
+ /// not have external linkage.
bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old,
const NamedDecl *New) {
- // We are about to link these. It is now safe to compute the linkage of
- // the new decl. If the new decl has external linkage, we will
- // link it with the hidden decl (which also has external linkage) and
- // it will keep having external linkage. If it has internal linkage, we
- // will not link it. Since it has no previous decls, it will remain
- // with internal linkage.
- return isVisible(Old) || New->isExternallyVisible();
+ if (isVisible(Old))
+ return true;
+ // See comment in below overload for why it's safe to compute the linkage
+ // of the new declaration here.
+ if (New->isExternallyDeclarable()) {
+ assert(Old->isExternallyDeclarable() &&
+ "should not have found a non-externally-declarable previous decl");
+ return true;
+ }
+ return false;
}
bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New);
@@ -336,6 +347,35 @@ public:
/// \brief Source location for newly created implicit MSInheritanceAttrs
SourceLocation ImplicitMSInheritanceAttrLoc;
+ /// \brief pragma clang section kind
+ enum PragmaClangSectionKind {
+ PCSK_Invalid = 0,
+ PCSK_BSS = 1,
+ PCSK_Data = 2,
+ PCSK_Rodata = 3,
+ PCSK_Text = 4
+ };
+
+ enum PragmaClangSectionAction {
+ PCSA_Set = 0,
+ PCSA_Clear = 1
+ };
+
+ struct PragmaClangSection {
+ std::string SectionName;
+ bool Valid = false;
+ SourceLocation PragmaLocation;
+
+ void Act(SourceLocation PragmaLocation,
+ PragmaClangSectionAction Action,
+ StringLiteral* Name);
+ };
+
+ PragmaClangSection PragmaClangBSSSection;
+ PragmaClangSection PragmaClangDataSection;
+ PragmaClangSection PragmaClangRodataSection;
+ PragmaClangSection PragmaClangTextSection;
+
enum PragmaMsStackAction {
PSK_Reset = 0x0, // #pragma ()
PSK_Set = 0x1, // #pragma (value)
@@ -352,11 +392,12 @@ public:
llvm::StringRef StackSlotLabel;
ValueType Value;
SourceLocation PragmaLocation;
- Slot(llvm::StringRef StackSlotLabel,
- ValueType Value,
- SourceLocation PragmaLocation)
- : StackSlotLabel(StackSlotLabel), Value(Value),
- PragmaLocation(PragmaLocation) {}
+ SourceLocation PragmaPushLocation;
+ Slot(llvm::StringRef StackSlotLabel, ValueType Value,
+ SourceLocation PragmaLocation, SourceLocation PragmaPushLocation)
+ : StackSlotLabel(StackSlotLabel), Value(Value),
+ PragmaLocation(PragmaLocation),
+ PragmaPushLocation(PragmaPushLocation) {}
};
void Act(SourceLocation PragmaLocation,
PragmaMsStackAction Action,
@@ -387,6 +428,8 @@ public:
explicit PragmaStack(const ValueType &Default)
: DefaultValue(Default), CurrentValue(Default) {}
+ bool hasValue() const { return CurrentValue != DefaultValue; }
+
SmallVector<Slot, 2> Stack;
ValueType DefaultValue; // Value used for PSK_Reset action.
ValueType CurrentValue;
@@ -408,6 +451,13 @@ public:
// Sentinel to represent when the stack is set to mac68k alignment.
static const unsigned kMac68kAlignmentSentinel = ~0U;
PragmaStack<unsigned> PackStack;
+ // The current #pragma pack values and locations at each #include.
+ struct PackIncludeState {
+ unsigned CurrentValue;
+ SourceLocation CurrentPragmaLocation;
+ bool HasNonDefaultValue, ShouldWarnOnInclude;
+ };
+ SmallVector<PackIncludeState, 8> PackIncludeStack;
// Segment #pragmas.
PragmaStack<StringLiteral *> DataSegStack;
PragmaStack<StringLiteral *> BSSSegStack;
@@ -437,6 +487,20 @@ public:
/// VisContext - Manages the stack for \#pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
+ /// \brief This represents the stack of attributes that were pushed by
+ /// \#pragma clang attribute.
+ struct PragmaAttributeEntry {
+ SourceLocation Loc;
+ AttributeList *Attribute;
+ SmallVector<attr::SubjectMatchRule, 4> MatchRules;
+ bool IsUsed;
+ };
+ SmallVector<PragmaAttributeEntry, 2> PragmaAttributeStack;
+
+ /// \brief The declaration that is currently receiving an attribute from the
+ /// #pragma attribute stack.
+ const Decl *PragmaAttributeCurrentTargetDecl;
+
/// \brief This represents the last location of a "#pragma clang optimize off"
/// directive if such a directive has not been closed by an "on" yet. If
/// optimizations are currently "on", this is set to an invalid location.
@@ -675,16 +739,37 @@ public:
class SynthesizedFunctionScope {
Sema &S;
Sema::ContextRAII SavedContext;
+ bool PushedCodeSynthesisContext = false;
public:
SynthesizedFunctionScope(Sema &S, DeclContext *DC)
- : S(S), SavedContext(S, DC)
- {
+ : S(S), SavedContext(S, DC) {
S.PushFunctionScope();
- S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ S.PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ if (auto *FD = dyn_cast<FunctionDecl>(DC))
+ FD->setWillHaveBody(true);
+ else
+ assert(isa<ObjCMethodDecl>(DC));
+ }
+
+ void addContextNote(SourceLocation UseLoc) {
+ assert(!PushedCodeSynthesisContext);
+
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::DefiningSynthesizedFunction;
+ Ctx.PointOfInstantiation = UseLoc;
+ Ctx.Entity = cast<Decl>(S.CurContext);
+ S.pushCodeSynthesisContext(Ctx);
+
+ PushedCodeSynthesisContext = true;
}
~SynthesizedFunctionScope() {
+ if (PushedCodeSynthesisContext)
+ S.popCodeSynthesisContext();
+ if (auto *FD = dyn_cast<FunctionDecl>(S.CurContext))
+ FD->setWillHaveBody(false);
S.PopExpressionEvaluationContext();
S.PopFunctionScopeInfo();
}
@@ -802,7 +887,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
@@ -908,8 +993,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;
}
};
@@ -1007,6 +1096,11 @@ public:
/// definition in this translation unit.
llvm::MapVector<NamedDecl *, SourceLocation> UndefinedButUsed;
+ /// Determine if VD, which must be a variable or function, is an external
+ /// symbol that nonetheless can't be referenced from outside this translation
+ /// unit because its type has no linkage and it's not extern "C".
+ bool isExternalWithNoLinkageType(ValueDecl *VD);
+
/// Obtain a sorted list of functions that are undefined but ODR-used.
void getUndefinedButUsed(
SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined);
@@ -1042,12 +1136,23 @@ public:
CXXInvalid
};
- typedef std::pair<CXXRecordDecl*, CXXSpecialMember> SpecialMemberDecl;
+ typedef llvm::PointerIntPair<CXXRecordDecl *, 3, CXXSpecialMember>
+ SpecialMemberDecl;
/// The C++ special members which we are currently in the process of
/// declaring. If this process recursively triggers the declaration of the
/// same special member, we should act as if it is not yet declared.
- llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared;
+ llvm::SmallPtrSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared;
+
+ /// The function definitions which were renamed as part of typo-correction
+ /// to match their respective declarations. We want to keep track of them
+ /// to ensure that we don't emit a "redefinition" error if we encounter a
+ /// correctly named definition after the renamed definition.
+ llvm::SmallPtrSet<const NamedDecl *, 4> TypoCorrectedFunctionDefinitions;
+
+ /// Stack of types that correspond to the parameter entities that are
+ /// currently being copy-initialized. Can be empty.
+ llvm::SmallVector<QualType, 4> CurrentParameterCopyTypes;
void ReadMethodPool(Selector Sel);
void updateOutOfDateSelector(Selector Sel);
@@ -1065,14 +1170,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);
@@ -1190,6 +1293,7 @@ public:
void emitAndClearUnusedLocalTypedefWarnings();
+ void ActOnStartOfTranslationUnit();
void ActOnEndOfTranslationUnit();
void CheckDelegatingCtorCycles();
@@ -1280,6 +1384,8 @@ public:
SourceRange Brackets, DeclarationName Entity);
QualType BuildExtVectorType(QualType T, Expr *ArraySize,
SourceLocation AttrLoc);
+ QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
+ SourceLocation AttrLoc);
bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
@@ -1427,23 +1533,27 @@ private:
TypeDiagnoser *Diagnoser);
struct ModuleScope {
- clang::Module *Module;
+ clang::Module *Module = nullptr;
+ bool ModuleInterface = false;
VisibleModuleSet OuterVisibleModules;
};
/// The modules we're currently parsing.
llvm::SmallVector<ModuleScope, 16> ModuleScopes;
- VisibleModuleSet VisibleModules;
+ /// Get the module whose scope we are currently within.
+ Module *getCurrentModule() const {
+ return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module;
+ }
- Module *CachedFakeTopLevelModule;
+ VisibleModuleSet VisibleModules;
public:
/// \brief Get the module owning an entity.
- Module *getOwningModule(Decl *Entity);
+ Module *getOwningModule(Decl *Entity) { return Entity->getOwningModule(); }
/// \brief Make a merged definition of an existing hidden definition \p ND
/// visible at the specified location.
- void makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc);
+ void makeMergedDefinitionVisible(NamedDecl *ND);
bool isModuleVisible(Module *M) { return VisibleModules.isVisible(M); }
@@ -1462,6 +1572,11 @@ public:
llvm::SmallVectorImpl<Module *> *Modules);
bool hasVisibleMergedDefinition(NamedDecl *Def);
+ bool hasMergedDefinitionInCurrentModule(NamedDecl *Def);
+
+ /// Determine if \p D and \p Suggested have a structurally compatible
+ /// layout as described in C11 6.2.7/1.
+ bool hasStructuralCompatLayout(Decl *D, Decl *Suggested);
/// Determine if \p D has a visible definition. If not, suggest a declaration
/// that should be made visible to expose the definition.
@@ -1477,6 +1592,12 @@ public:
hasVisibleDefaultArgument(const NamedDecl *D,
llvm::SmallVectorImpl<Module *> *Modules = nullptr);
+ /// Determine if there is a visible declaration of \p D that is an explicit
+ /// specialization declaration for a specialization of a template. (For a
+ /// member specialization, use hasVisibleMemberSpecialization.)
+ bool hasVisibleExplicitSpecialization(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr);
+
/// Determine if there is a visible declaration of \p D that is a member
/// specialization declaration (as opposed to an instantiated declaration).
bool hasVisibleMemberSpecialization(
@@ -1544,9 +1665,13 @@ public:
//
struct SkipBodyInfo {
- SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {}
+ SkipBodyInfo()
+ : ShouldSkip(false), CheckSameAsPrevious(false), Previous(nullptr),
+ New(nullptr) {}
bool ShouldSkip;
+ bool CheckSameAsPrevious;
NamedDecl *Previous;
+ NamedDecl *New;
};
DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr);
@@ -1570,7 +1695,7 @@ public:
Scope *S,
CXXScopeSpec *SS,
ParsedType &SuggestedType,
- bool AllowClassTemplates = false);
+ bool IsTemplateName = false);
/// Attempt to behave like MSVC in situations where lookup of an unqualified
/// type name has failed in a dependent context. In these situations, we
@@ -1599,7 +1724,6 @@ public:
ExprResult Expr;
TemplateName Template;
ParsedType Type;
- const IdentifierInfo *Keyword;
explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
@@ -1608,8 +1732,7 @@ public:
NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
- NameClassification(const IdentifierInfo *Keyword)
- : Kind(NC_Keyword), Keyword(Keyword) { }
+ NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {}
static NameClassification Error() {
return NameClassification(NC_Error);
@@ -1715,6 +1838,23 @@ public:
TemplateNameKindForDiagnostics
getTemplateNameKindForDiagnostics(TemplateName Name);
+ /// Determine whether it's plausible that E was intended to be a
+ /// template-name.
+ bool mightBeIntendedToBeTemplateName(ExprResult E) {
+ if (!getLangOpts().CPlusPlus || E.isInvalid())
+ return false;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E.get()))
+ return !DRE->hasExplicitTemplateArgs();
+ if (auto *ME = dyn_cast<MemberExpr>(E.get()))
+ return !ME->hasExplicitTemplateArgs();
+ // Any additional cases recognized here should also be handled by
+ // diagnoseExprIntendedAsTemplateName.
+ return false;
+ }
+ void diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
+ SourceLocation Less,
+ SourceLocation Greater);
+
Decl *ActOnDeclarator(Scope *S, Declarator &D);
NamedDecl *HandleDeclarator(Scope *S, Declarator &D,
@@ -1735,8 +1875,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
@@ -1822,7 +1965,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);
@@ -1908,14 +2050,15 @@ public:
SourceLocation SemiLoc);
enum class ModuleDeclKind {
- Module, ///< 'module X;'
+ Interface, ///< 'export module X;'
+ Implementation, ///< 'module X;'
Partition, ///< 'module partition X;'
- Implementation, ///< 'module implementation X;'
};
/// The parser has processed a module-declaration that begins the definition
/// of a module interface or implementation.
- DeclGroupPtrTy ActOnModuleDecl(SourceLocation ModuleLoc, ModuleDeclKind MDK,
+ DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc,
+ SourceLocation ModuleLoc, ModuleDeclKind MDK,
ModuleIdPath Path);
/// \brief The parser has processed a module import declaration.
@@ -2040,15 +2183,14 @@ public:
};
Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, CXXScopeSpec &SS,
- IdentifierInfo *Name, SourceLocation NameLoc,
- AttributeList *Attr, AccessSpecifier AS,
- SourceLocation ModulePrivateLoc,
- MultiTemplateParamsArg TemplateParameterLists,
- bool &OwnedDecl, bool &IsDependent,
- SourceLocation ScopedEnumKWLoc,
+ SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name,
+ SourceLocation NameLoc, AttributeList *Attr,
+ AccessSpecifier AS, SourceLocation ModulePrivateLoc,
+ MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl,
+ bool &IsDependent, SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
- bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr);
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ SkipBodyInfo *SkipBody = nullptr);
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
@@ -2113,6 +2255,12 @@ public:
/// struct, or union).
void ActOnTagStartDefinition(Scope *S, Decl *TagDecl);
+ /// Perform ODR-like check for C/ObjC when merging tag types from modules.
+ /// Differently from C++, actually parse the body and reject / error out
+ /// in case of a structural mismatch.
+ bool ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev,
+ SkipBodyInfo &SkipBody);
+
typedef void *SkippedDefinitionContext;
/// \brief Invoked when we enter a tag definition that we're skipping.
@@ -2166,8 +2314,8 @@ public:
Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id,
- AttributeList *Attrs,
- SourceLocation EqualLoc, Expr *Val);
+ AttributeList *Attrs, SourceLocation EqualLoc,
+ Expr *Val);
void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
Decl *EnumDecl,
ArrayRef<Decl *> Elements,
@@ -2310,6 +2458,7 @@ public:
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn);
+ void notePreviousDefinition(const NamedDecl *Old, SourceLocation New);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
// AssignmentAction - This is used by all the assignment diagnostic functions
@@ -2556,7 +2705,8 @@ public:
OverloadCandidateSet &CandidateSet,
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
bool SuppressUserConversions = false,
- bool PartialOverloading = false);
+ bool PartialOverloading = false,
+ bool FirstArgumentIsBase = false);
void AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr::Classification ObjectClassification,
@@ -2604,13 +2754,15 @@ public:
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet,
- bool AllowObjCConversionOnExplicit);
+ bool AllowObjCConversionOnExplicit,
+ bool AllowResultConversion = true);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet,
- bool AllowObjCConversionOnExplicit);
+ bool AllowObjCConversionOnExplicit,
+ bool AllowResultConversion = true);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -2621,8 +2773,7 @@ public:
SourceLocation OpLoc, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange = SourceRange());
- void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
- ArrayRef<Expr *> Args,
+ void AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator = false,
unsigned NumContextualBoolArguments = 0);
@@ -2651,6 +2802,14 @@ public:
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
bool MissingImplicitThis = false);
+ /// Find the failed Boolean condition within a given Boolean
+ /// constant expression, and describe it with a string.
+ ///
+ /// \param AllowTopLevelCond Whether to allow the result to be the
+ /// complete top-level condition.
+ std::pair<Expr *, std::string>
+ findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond);
+
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
/// non-ArgDependent DiagnoseIfAttrs.
///
@@ -2670,7 +2829,7 @@ public:
/// of a function.
///
/// Returns true if any errors were emitted.
- bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
+ bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
SourceLocation Loc);
/// Returns whether the given function's address can be taken or not,
@@ -2700,7 +2859,8 @@ public:
resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
DeclAccessPair &FoundResult);
- bool resolveAndFixAddressOfOnlyViableOverloadCandidate(ExprResult &SrcExpr);
+ bool resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ ExprResult &SrcExpr, bool DoFunctionPointerConversion = false);
FunctionDecl *
ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
@@ -2760,12 +2920,13 @@ public:
ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *input);
+ Expr *input, bool RequiresADL = true);
ExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *LHS, Expr *RHS);
+ Expr *LHS, Expr *RHS,
+ bool RequiresADL = true);
ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
SourceLocation RLoc,
@@ -2880,14 +3041,31 @@ public:
/// purpose of redeclaring the name.
NotForRedeclaration = 0,
/// \brief The lookup results will be used for redeclaration of a name,
- /// if an entity by that name already exists.
- ForRedeclaration
+ /// if an entity by that name already exists and is visible.
+ ForVisibleRedeclaration,
+ /// \brief The lookup results will be used for redeclaration of a name
+ /// with external linkage; non-visible lookup results with external linkage
+ /// may also be found.
+ ForExternalRedeclaration
};
+ RedeclarationKind forRedeclarationInCurContext() {
+ // A declaration with an owning module for linkage can never link against
+ // anything that is not visible. We don't need to check linkage here; if
+ // the context has internal linkage, redeclaration lookup won't find things
+ // from other TUs, and we can't safely compute linkage yet in general.
+ if (cast<Decl>(CurContext)
+ ->getOwningModuleForLinkage(/*IgnoreLinkage*/true))
+ return ForVisibleRedeclaration;
+ return ForExternalRedeclaration;
+ }
+
/// \brief The possible outcomes of name lookup for a literal operator.
enum LiteralOperatorLookupResult {
/// \brief The lookup resulted in an error.
LOLR_Error,
+ /// \brief The lookup found no match but no diagnostic was issued.
+ LOLR_ErrorNoDiagnostic,
/// \brief The lookup found a single 'cooked' literal operator, which
/// expects a normal literal to be built and passed to it.
LOLR_Cooked,
@@ -2991,9 +3169,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());
@@ -3015,7 +3190,8 @@ public:
ArrayRef<QualType> ArgTys,
bool AllowRaw,
bool AllowTemplate,
- bool AllowStringTemplate);
+ bool AllowStringTemplate,
+ bool DiagnoseMissing);
bool isKnownName(StringRef name);
void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
@@ -3026,7 +3202,8 @@ public:
bool IncludeGlobalScope = true);
void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
- bool IncludeGlobalScope = true);
+ bool IncludeGlobalScope = true,
+ bool IncludeDependentBases = false);
enum CorrectTypoKind {
CTK_NonError, // CorrectTypo used in a non error recovery situation.
@@ -3100,6 +3277,8 @@ public:
const PartialDiagnostic &PrevNote,
bool ErrorRecovery = true);
+ void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F);
+
void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
@@ -3108,6 +3287,8 @@ public:
void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
bool ConsiderLinkage, bool AllowInlineNamespace);
+ bool CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old);
+
void DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
@@ -3126,7 +3307,7 @@ 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.
+ // Helper for delayed processing of attributes.
void ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL,
bool IncludeCXX11Attributes = true);
@@ -3145,11 +3326,12 @@ public:
bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
const FunctionDecl *FD = nullptr);
bool CheckNoReturnAttr(const AttributeList &attr);
+ bool CheckNoCallerSavedRegsAttr(const AttributeList &attr);
bool checkStringLiteralArgumentAttr(const AttributeList &Attr,
unsigned ArgNum, StringRef &Str,
SourceLocation *ArgLocation = nullptr);
bool checkSectionName(SourceLocation LiteralLoc, StringRef Str);
- void checkTargetAttr(SourceLocation LiteralLoc, StringRef Str);
+ bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str);
bool checkMSInheritanceAttrOnDefinition(
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
MSInheritanceAttr::Spelling SemanticSpelling);
@@ -3238,9 +3420,10 @@ public:
/// DefaultSynthesizeProperties - This routine default synthesizes all
/// properties which must be synthesized in the class's \@implementation.
- void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
- ObjCInterfaceDecl *IDecl);
- void DefaultSynthesizeProperties(Scope *S, Decl *D);
+ void DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
+ ObjCInterfaceDecl *IDecl,
+ SourceLocation AtEnd);
+ void DefaultSynthesizeProperties(Scope *S, Decl *D, SourceLocation AtEnd);
/// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
/// an ivar synthesized for 'Method' and 'Method' is a property accessor
@@ -3266,7 +3449,9 @@ public:
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
+ SourceLocation GetterNameLoc,
Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
unsigned &Attributes,
const unsigned AttributesAsWritten,
@@ -3282,7 +3467,9 @@ public:
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
+ SourceLocation GetterNameLoc,
Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
const unsigned Attributes,
const unsigned AttributesAsWritten,
@@ -3627,15 +3814,15 @@ public:
Expr *AsmString, MultiExprArg Clobbers,
SourceLocation RParenLoc);
+ void FillInlineAsmIdentifierInfo(Expr *Res,
+ llvm::InlineAsmIdentifierInfo &Info);
ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
- llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext);
bool LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset, SourceLocation AsmLoc);
ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member,
- llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc);
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
ArrayRef<Token> AsmToks,
@@ -3736,6 +3923,9 @@ public:
void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType,
SourceLocation Loc);
+ /// Warn when implicitly casting 0 to nullptr.
+ void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E);
+
ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) {
return DelayedDiagnostics.push(pool);
}
@@ -3751,11 +3941,10 @@ public:
void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
- void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D,
- StringRef Message, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess);
+ void DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess,
+ bool AvoidPartialAvailabilityChecks = false);
bool makeUnavailableInSystemHeader(SourceLocation loc,
UnavailableAttr::ImplicitReason reason);
@@ -3768,8 +3957,9 @@ public:
bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid);
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass=nullptr,
- bool ObjCPropertyAccess=false);
+ const ObjCInterfaceDecl *UnknownObjCClass = nullptr,
+ bool ObjCPropertyAccess = false,
+ bool AvoidPartialAvailabilityChecks = false);
void NoteDeletedFunction(FunctionDecl *FD);
void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD);
std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD);
@@ -3811,7 +4001,7 @@ public:
void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
bool MightBeOdrUse = true);
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
- void MarkDeclRefReferenced(DeclRefExpr *E);
+ void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr);
void MarkMemberReferenced(MemberExpr *E);
void UpdateMarkingForLValueToRValue(Expr *E);
@@ -4983,7 +5173,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,
@@ -5136,7 +5326,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::'.
///
@@ -5160,13 +5351,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);
@@ -5904,7 +6098,7 @@ public:
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- ArrayRef<Decl *> Params,
+ ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc,
Expr *RequiresClause);
@@ -6047,6 +6241,7 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
+ void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
DeclResult
ActOnExplicitInstantiation(Scope *S,
@@ -6903,6 +7098,10 @@ public:
/// We are declaring an implicit special member function.
DeclaringSpecialMember,
+
+ /// We are defining a synthesized function (such as a defaulted special
+ /// member).
+ DefiningSynthesizedFunction,
} Kind;
/// \brief Was the enclosing context a non-instantiation SFINAE context?
@@ -7196,9 +7395,13 @@ public:
PrintInstantiationStack();
LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size();
}
+ if (PragmaAttributeCurrentTargetDecl)
+ PrintPragmaAttributeInstantiationPoint();
}
void PrintInstantiationStack();
+ void PrintPragmaAttributeInstantiationPoint();
+
/// \brief Determines whether we are currently in a context where
/// template argument substitution failures are not considered
/// errors.
@@ -7308,9 +7511,9 @@ public:
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingInstantiations;
- class SavePendingInstantiationsAndVTableUsesRAII {
+ class GlobalEagerInstantiationScope {
public:
- SavePendingInstantiationsAndVTableUsesRAII(Sema &S, bool Enabled)
+ GlobalEagerInstantiationScope(Sema &S, bool Enabled)
: S(S), Enabled(Enabled) {
if (!Enabled) return;
@@ -7318,7 +7521,14 @@ public:
SavedVTableUses.swap(S.VTableUses);
}
- ~SavePendingInstantiationsAndVTableUsesRAII() {
+ void perform() {
+ if (Enabled) {
+ S.DefineUsedVTables();
+ S.PerformPendingInstantiations();
+ }
+ }
+
+ ~GlobalEagerInstantiationScope() {
if (!Enabled) return;
// Restore the set of pending vtables.
@@ -7348,14 +7558,16 @@ public:
/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
- class SavePendingLocalImplicitInstantiationsRAII {
+ class LocalEagerInstantiationScope {
public:
- SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) {
+ LocalEagerInstantiationScope(Sema &S) : S(S) {
SavedPendingLocalImplicitInstantiations.swap(
S.PendingLocalImplicitInstantiations);
}
- ~SavePendingLocalImplicitInstantiationsRAII() {
+ void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); }
+
+ ~LocalEagerInstantiationScope() {
assert(S.PendingLocalImplicitInstantiations.empty() &&
"there shouldn't be any pending local implicit instantiations");
SavedPendingLocalImplicitInstantiations.swap(
@@ -7365,7 +7577,7 @@ public:
private:
Sema &S;
std::deque<PendingImplicitInstantiation>
- SavedPendingLocalImplicitInstantiations;
+ SavedPendingLocalImplicitInstantiations;
};
/// A helper class for building up ExtParameterInfos.
@@ -7418,6 +7630,10 @@ public:
unsigned ThisTypeQuals);
void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
const MultiLevelTemplateArgumentList &Args);
+ bool SubstExceptionSpec(SourceLocation Loc,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
+ SmallVectorImpl<QualType> &ExceptionStorage,
+ const MultiLevelTemplateArgumentList &Args);
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
@@ -7497,6 +7713,15 @@ public:
LateInstantiatedAttrVec *LateAttrs = nullptr,
LocalInstantiationScope *OuterMostScope = nullptr);
+ void
+ InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs,
+ const Decl *Pattern, Decl *Inst,
+ LateInstantiatedAttrVec *LateAttrs = nullptr,
+ LocalInstantiationScope *OuterMostScope = nullptr);
+
+ bool usesPartialOrExplicitSpecialization(
+ SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec);
+
bool
InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
@@ -7571,7 +7796,8 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs);
NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
- const MultiLevelTemplateArgumentList &TemplateArgs);
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool FindingInstantiatedContext = false);
DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -7658,7 +7884,8 @@ public:
Decl * const *ProtoRefs,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
- SourceLocation EndProtoLoc);
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList);
Decl *ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
@@ -8002,6 +8229,11 @@ public:
POAK_Reset // #pragma options align=reset
};
+ /// ActOnPragmaClangSection - Called on well formed \#pragma clang section
+ void ActOnPragmaClangSection(SourceLocation PragmaLoc,
+ PragmaClangSectionAction Action,
+ PragmaClangSectionKind SecKind, StringRef SecName);
+
/// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align.
void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc);
@@ -8010,6 +8242,15 @@ public:
void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
StringRef SlotLabel, Expr *Alignment);
+ enum class PragmaPackDiagnoseKind {
+ NonDefaultStateAtInclude,
+ ChangedStateAtExit
+ };
+
+ void DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
+ SourceLocation IncludeLoc);
+ void DiagnoseUnterminatedPragmaPack();
+
/// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off].
void ActOnPragmaMSStruct(PragmaMSStructKind Kind);
@@ -8100,8 +8341,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'.
@@ -8134,6 +8376,20 @@ public:
/// the appropriate attribute.
void AddCFAuditedAttribute(Decl *D);
+ /// \brief Called on well-formed '\#pragma clang attribute push'.
+ void ActOnPragmaAttributePush(AttributeList &Attribute,
+ SourceLocation PragmaLoc,
+ attr::ParsedSubjectMatchRuleSet Rules);
+
+ /// \brief Called on well-formed '\#pragma clang attribute pop'.
+ void ActOnPragmaAttributePop(SourceLocation PragmaLoc);
+
+ /// \brief Adds the attributes that have been specified using the
+ /// '\#pragma clang attribute push' directives to the given declaration.
+ void AddPragmaAttributes(Scope *S, Decl *D);
+
+ void DiagnoseUnterminatedPragmaAttribute();
+
/// \brief Called on well formed \#pragma clang optimize.
void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc);
@@ -8164,6 +8420,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,
@@ -8185,9 +8446,13 @@ public:
unsigned SpellingListIndex, bool isNSConsumed,
bool isTemplateInstantiation);
+ bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
+
//===--------------------------------------------------------------------===//
// C++ Coroutines TS
//
+ bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc,
+ StringRef Keyword);
ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E);
ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E);
StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E);
@@ -8253,7 +8518,7 @@ public:
/// is disabled due to required OpenCL extensions being disabled. If so,
/// emit diagnostics.
/// \return true if type is disabled.
- bool checkOpenCLDisabledDecl(const Decl &D, const Expr &E);
+ bool checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E);
//===--------------------------------------------------------------------===//
// OpenMP directives and clauses.
@@ -8271,6 +8536,12 @@ private:
/// Returns OpenMP nesting level for current directive.
unsigned getOpenMPNestingLevel() const;
+ /// Push new OpenMP function region for non-capturing function.
+ void pushOpenMPFunctionRegion();
+
+ /// Pop OpenMP function region for non-capturing function.
+ void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI);
+
/// Checks if a type or a declaration is disabled due to the owning extension
/// being disabled, and emits diagnostic messages if it is disabled.
/// \param D type or declaration to be checked.
@@ -8305,6 +8576,11 @@ public:
/// is performed.
bool isOpenMPPrivateDecl(ValueDecl *D, unsigned Level);
+ /// Sets OpenMP capture kind (OMPC_private, OMPC_firstprivate, OMPC_map etc.)
+ /// for \p FD based on DSA for the provided corresponding captured declaration
+ /// \p D.
+ void setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level);
+
/// \brief Check if the specified variable is captured by 'target' directive.
/// \param Level Relative level of nested OpenMP construct for that the check
/// is performed.
@@ -8357,9 +8633,11 @@ public:
/// \brief Finish current declare reduction construct initializer.
void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner);
/// \brief Initialize declare reduction construct initializer.
- void ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D);
+ /// \return omp_priv variable.
+ VarDecl *ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D);
/// \brief Finish current declare reduction construct initializer.
- void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer);
+ void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer,
+ VarDecl *OmpPrivParm);
/// \brief Called at the end of '#pragma omp declare reduction'.
DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd(
Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid);
@@ -8477,7 +8755,8 @@ public:
StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed '\#pragma omp taskgroup'.
- StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc,
+ StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed '\#pragma omp flush'.
StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
@@ -8819,6 +9098,20 @@ public:
CXXScopeSpec &ReductionIdScopeSpec,
const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions = llvm::None);
+ /// Called on well-formed 'task_reduction' clause.
+ OMPClause *ActOnOpenMPTaskReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions = llvm::None);
+ /// Called on well-formed 'in_reduction' clause.
+ OMPClause *ActOnOpenMPInReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions = llvm::None);
/// \brief Called on well-formed 'linear' clause.
OMPClause *
ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
@@ -9185,6 +9478,8 @@ public:
/// type checking binary operators (subroutines of CreateBuiltinBinOp).
QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS,
ExprResult &RHS);
+ QualType InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS,
+ ExprResult &RHS);
QualType CheckPointerToMemberOperands( // C++ 5.5
ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK,
SourceLocation OpLoc, bool isIndirect);
@@ -9334,14 +9629,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);
@@ -9914,8 +10209,7 @@ public:
void CodeCompleteObjCPropertyDefinition(Scope *S);
void CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
IdentifierInfo *PropertyName);
- void CodeCompleteObjCMethodDecl(Scope *S,
- bool IsInstanceMethod,
+ void CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
ParsedType ReturnType);
void CodeCompleteObjCMethodDeclSelector(Scope *S,
bool IsInstanceMethod,
@@ -9934,6 +10228,7 @@ public:
MacroInfo *MacroInfo,
unsigned Argument);
void CodeCompleteNaturalLanguage();
+ void CodeCompleteAvailabilityPlatformName();
void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
SmallVectorImpl<CodeCompletionResult> &Results);
@@ -9997,12 +10292,11 @@ private:
bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
- bool SemaBuiltinVAStartImpl(CallExpr *TheCall);
- bool SemaBuiltinVAStart(CallExpr *TheCall);
- bool SemaBuiltinMSVAStart(CallExpr *TheCall);
- bool SemaBuiltinVAStartARM(CallExpr *Call);
+ bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall);
+ bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
+ bool SemaBuiltinVSX(CallExpr *TheCall);
bool SemaBuiltinOSLogFormat(CallExpr *TheCall);
public:
@@ -10171,6 +10465,12 @@ private:
IdentifierInfo *Ident_NSError = nullptr;
+ /// \brief The handler for the FileChanged preprocessor events.
+ ///
+ /// Used for diagnostics that implement custom semantic analysis for #include
+ /// directives, like -Wpragma-pack.
+ sema::SemaPPCallbacks *SemaPPCallbackHandler;
+
protected:
friend class Parser;
friend class InitializationSequence;
@@ -10211,17 +10511,6 @@ public:
return OriginalLexicalContext ? OriginalLexicalContext : CurContext;
}
- /// \brief The diagnostic we should emit for \c D, or \c AR_Available.
- ///
- /// \param D The declaration to check. Note that this may be altered to point
- /// to another declaration that \c D gets it's availability from. i.e., we
- /// walk the list of typedefs to find an availability attribute.
- ///
- /// \param Message If non-null, this will be populated with the message from
- /// the availability attribute that is selected.
- AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D,
- std::string *Message);
-
const DeclContext *getCurObjCLexicalContext() const {
const DeclContext *DC = getCurLexicalContext();
// A category implicitly has the attribute of the interface.
@@ -10245,6 +10534,36 @@ public:
SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses;
private:
+ class SavePendingParsedClassStateRAII {
+ public:
+ SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); }
+
+ ~SavePendingParsedClassStateRAII() {
+ assert(S.DelayedExceptionSpecChecks.empty() &&
+ "there shouldn't be any pending delayed exception spec checks");
+ assert(S.DelayedDefaultedMemberExceptionSpecs.empty() &&
+ "there shouldn't be any pending delayed defaulted member "
+ "exception specs");
+ assert(S.DelayedDllExportClasses.empty() &&
+ "there shouldn't be any pending delayed DLL export classes");
+ swapSavedState();
+ }
+
+ private:
+ Sema &S;
+ decltype(DelayedExceptionSpecChecks) SavedExceptionSpecChecks;
+ decltype(DelayedDefaultedMemberExceptionSpecs)
+ SavedDefaultedMemberExceptionSpecs;
+ decltype(DelayedDllExportClasses) SavedDllExportClasses;
+
+ void swapSavedState() {
+ SavedExceptionSpecChecks.swap(S.DelayedExceptionSpecChecks);
+ SavedDefaultedMemberExceptionSpecs.swap(
+ S.DelayedDefaultedMemberExceptionSpecs);
+ SavedDllExportClasses.swap(S.DelayedDllExportClasses);
+ }
+ };
+
/// \brief Helper class that collects misaligned member designations and
/// their location info for delayed diagnostics.
struct MisalignedMember {
@@ -10298,6 +10617,7 @@ class EnterExpressionEvaluationContext {
bool Entered = true;
public:
+
EnterExpressionEvaluationContext(Sema &Actions,
Sema::ExpressionEvaluationContext NewContext,
Decl *LambdaContextDecl = nullptr,
@@ -10328,8 +10648,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/SemaInternal.h b/include/clang/Sema/SemaInternal.h
index a01e8d639f..4dc215ba21 100644
--- a/include/clang/Sema/SemaInternal.h
+++ b/include/clang/Sema/SemaInternal.h
@@ -73,7 +73,8 @@ inline void MarkVarDeclODRUsed(VarDecl *Var,
// Keep track of used but undefined variables.
// FIXME: We shouldn't suppress this warning for static data members.
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
- (!Var->isExternallyVisible() || Var->isInline()) &&
+ (!Var->isExternallyVisible() || Var->isInline() ||
+ SemaRef.isExternalWithNoLinkageType(Var)) &&
!(Var->isStaticDataMember() && Var->hasInit())) {
SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
if (old.isInvalid())
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index d92cbab4fb..cd9ed6abfa 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -88,6 +88,12 @@ public:
HasSFINAEDiagnostic = false;
}
+ /// Peek at the SFINAE diagnostic.
+ const PartialDiagnosticAt &peekSFINAEDiagnostic() const {
+ assert(HasSFINAEDiagnostic);
+ return SuppressedDiagnostics.front();
+ }
+
/// \brief Provide a new template argument list that contains the
/// results of template argument deduction.
void reset(TemplateArgumentList *NewDeduced) {
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index de8e2a8183..42c62257ad 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -604,6 +604,12 @@ namespace clang {
OPENCL_EXTENSION_DECLS = 59,
MODULAR_CODEGEN_DECLS = 60,
+
+ /// \brief Record code for \#pragma pack options.
+ PACK_PRAGMA_OPTIONS = 61,
+
+ /// \brief The stack of open #ifs/#ifdefs recorded in a preamble.
+ PP_CONDITIONAL_STACK = 62,
};
/// \brief Record types used within a source manager block.
@@ -710,6 +716,9 @@ namespace clang {
/// \brief Specifies some declarations with initializers that must be
/// emitted to initialize the module.
SUBMODULE_INITIALIZERS = 16,
+ /// \brief Specifies the name of the module that will eventually
+ /// re-export the entities in this module.
+ SUBMODULE_EXPORT_AS = 17,
};
/// \brief Record types used within a comments block.
@@ -820,6 +829,8 @@ namespace clang {
PREDEF_TYPE_OMP_ARRAY_SECTION = 42,
/// \brief The '__float128' type
PREDEF_TYPE_FLOAT128_ID = 43,
+ /// \brief The '_Float16' type
+ PREDEF_TYPE_FLOAT16_ID = 44,
/// \brief OpenCL image types with auto numeration
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
PREDEF_TYPE_##Id##_ID,
@@ -927,7 +938,11 @@ namespace clang {
/// \brief An ObjCTypeParamType record.
TYPE_OBJC_TYPE_PARAM = 44,
/// \brief A DeducedTemplateSpecializationType record.
- TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45
+ TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45,
+ /// \brief A DependentSizedExtVectorType record.
+ TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46,
+ /// \brief A DependentAddressSpaceType record.
+ TYPE_DEPENDENT_ADDRESS_SPACE = 47
};
/// \brief The type IDs for special types constructed by semantic
@@ -1537,9 +1552,14 @@ namespace clang {
// ARC
EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
-
+
STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt
- EXPR_LAMBDA // LambdaExpr
+ EXPR_LAMBDA, // LambdaExpr
+ STMT_COROUTINE_BODY,
+ STMT_CORETURN,
+ EXPR_COAWAIT,
+ EXPR_COYIELD,
+ EXPR_DEPENDENT_COAWAIT,
};
/// \brief The kinds of designators that can occur in a
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 5a1514ad80..9c5ad00691 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -400,7 +400,7 @@ private:
Preprocessor &PP;
/// \brief The AST context into which we'll read the AST files.
- ASTContext &Context;
+ ASTContext *ContextObj = nullptr;
/// \brief The AST consumer.
ASTConsumer *Consumer = nullptr;
@@ -408,6 +408,9 @@ private:
/// \brief The module manager which manages modules and their dependencies
ModuleManager ModuleMgr;
+ /// The cache that manages memory buffers for PCM files.
+ MemoryBufferCache &PCMCache;
+
/// \brief A dummy identifier resolver used to merge TU-scope declarations in
/// C, for the cases where we don't have a Sema object to provide a real
/// identifier resolver.
@@ -475,10 +478,18 @@ private:
/// in the chain.
DeclUpdateOffsetsMap DeclUpdateOffsets;
+ struct PendingUpdateRecord {
+ Decl *D;
+ serialization::GlobalDeclID ID;
+ // Whether the declaration was just deserialized.
+ bool JustLoaded;
+ PendingUpdateRecord(serialization::GlobalDeclID ID, Decl *D,
+ bool JustLoaded)
+ : D(D), ID(ID), JustLoaded(JustLoaded) {}
+ };
/// \brief Declaration updates for already-loaded declarations that we need
/// to apply once we finish processing an import.
- llvm::SmallVector<std::pair<serialization::GlobalDeclID, Decl*>, 16>
- PendingUpdateRecords;
+ llvm::SmallVector<PendingUpdateRecord, 16> PendingUpdateRecords;
enum class PendingFakeDefinitionKind { NotFake, Fake, FakeLoaded };
@@ -700,7 +711,7 @@ private:
/// \brief Mapping from global preprocessing entity IDs to the module in
/// which the preprocessed entity resides along with the offset that should be
- /// added to the global preprocessing entitiy ID to produce a local ID.
+ /// added to the global preprocessing entity ID to produce a local ID.
GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap;
/// \name CodeGen-relevant special data
@@ -808,6 +819,18 @@ private:
int PragmaMSPointersToMembersState = -1;
SourceLocation PointersToMembersPragmaLocation;
+ /// \brief The pragma pack state.
+ Optional<unsigned> PragmaPackCurrentValue;
+ SourceLocation PragmaPackCurrentLocation;
+ struct PragmaPackStackEntry {
+ unsigned Value;
+ SourceLocation Location;
+ SourceLocation PushLocation;
+ StringRef SlotLabel;
+ };
+ llvm::SmallVector<PragmaPackStackEntry, 2> PragmaPackStack;
+ llvm::SmallVector<std::string, 2> PragmaPackStrings;
+
/// \brief The OpenCL extension settings.
OpenCLOptions OpenCLExtensions;
@@ -845,9 +868,6 @@ private:
SmallVector<ImportedSubmodule, 2> ImportedModules;
//@}
- /// \brief The directory that the PCH we are reading is stored in.
- std::string CurrentDir;
-
/// \brief The system include root to be used when loading the
/// precompiled header.
std::string isysroot;
@@ -970,14 +990,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
@@ -1011,8 +1043,11 @@ private:
/// once recursing loading has been completed.
llvm::SmallVector<NamedDecl *, 16> PendingOdrMergeChecks;
+ using DataPointers =
+ std::pair<CXXRecordDecl *, struct CXXRecordDecl::DefinitionData *>;
+
/// \brief Record definitions in which we found an ODR violation.
- llvm::SmallDenseMap<CXXRecordDecl *, llvm::TinyPtrVector<CXXRecordDecl *>, 2>
+ llvm::SmallDenseMap<CXXRecordDecl *, llvm::SmallVector<DataPointers, 2>, 2>
PendingOdrMergeFailures;
/// \brief DeclContexts in which we have diagnosed an ODR violation.
@@ -1101,6 +1136,8 @@ private:
/// predefines buffer may contain additional definitions.
std::string SuggestedPredefines;
+ llvm::DenseMap<const Decl *, bool> DefinitionSource;
+
/// \brief Reads a statement from the specified cursor.
Stmt *ReadStmtFromStream(ModuleFile &F);
@@ -1110,6 +1147,7 @@ private:
time_t StoredTime;
bool Overridden;
bool Transient;
+ bool TopLevelModuleMap;
};
/// \brief Reads the stored information about an input file.
@@ -1251,7 +1289,7 @@ private:
RecordLocation DeclCursorForID(serialization::DeclID ID,
SourceLocation &Location);
- void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
+ void loadDeclUpdateRecords(PendingUpdateRecord &Record);
void loadPendingDeclChain(Decl *D, uint64_t LocalOffset);
void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D,
unsigned PreviousGeneration = 0);
@@ -1350,7 +1388,7 @@ public:
/// precompiled header will be loaded.
///
/// \param Context the AST context that this precompiled header will be
- /// loaded into.
+ /// loaded into, if any.
///
/// \param PCHContainerRdr the PCHContainerOperations to use for loading and
/// creating modules.
@@ -1382,7 +1420,7 @@ public:
///
/// \param ReadTimer If non-null, a timer used to track the time spent
/// deserializing.
- ASTReader(Preprocessor &PP, ASTContext &Context,
+ ASTReader(Preprocessor &PP, ASTContext *Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
StringRef isysroot = "", bool DisableValidation = false,
@@ -1582,7 +1620,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
@@ -1983,7 +2021,7 @@ public:
/// \brief Return a descriptor for the corresponding module.
llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
- ExtKind hasExternalDefinitions(unsigned ID) override;
+ ExtKind hasExternalDefinitions(const Decl *D) override;
/// \brief Retrieve a selector from the given module with its local ID
/// number.
@@ -2107,9 +2145,19 @@ public:
// \brief Read a string
static std::string ReadString(const RecordData &Record, unsigned &Idx);
+ // \brief Skip a string
+ static void SkipString(const RecordData &Record, unsigned &Idx) {
+ Idx += Record[Idx] + 1;
+ }
+
// \brief Read a path
std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx);
+ // \brief Skip a path
+ static void SkipPath(const RecordData &Record, unsigned &Idx) {
+ SkipString(Record, Idx);
+ }
+
/// \brief Read a version tuple.
static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
@@ -2171,7 +2219,10 @@ public:
void completeVisibleDeclsMap(const DeclContext *DC) override;
/// \brief Retrieve the AST context that this AST reader supplements.
- ASTContext &getContext() { return Context; }
+ ASTContext &getContext() {
+ assert(ContextObj && "requested AST context when not loading AST");
+ return *ContextObj;
+ }
// \brief Contains the IDs for declarations that were requested before we have
// access to a Sema object.
@@ -2213,6 +2264,12 @@ public:
llvm::function_ref<void(const serialization::InputFile &IF,
bool isSystem)> Visitor);
+ /// Visit all the top-level module maps loaded when building the given module
+ /// file.
+ void visitTopLevelModuleMaps(serialization::ModuleFile &MF,
+ llvm::function_ref<
+ void(const FileEntry *)> Visitor);
+
bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; }
};
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index f3c644b9e2..392a4652d6 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;
@@ -109,6 +110,9 @@ private:
/// 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;
@@ -481,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);
@@ -512,6 +517,7 @@ public:
/// \brief Create a new precompiled header writer that outputs to
/// the given bitstream.
ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer,
+ MemoryBufferCache &PCMCache,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool IncludeTimestamps = true);
~ASTWriter() override;
@@ -621,10 +627,6 @@ public:
/// \brief Add a version tuple to the given record
void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);
- /// \brief Infer the submodule ID that contains an entity at the given
- /// source location.
- serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc);
-
/// \brief Retrieve or create a submodule ID for this module, or return 0 if
/// the submodule is neither local (a submodle of the currently-written module)
/// nor from an imported module.
@@ -696,7 +698,8 @@ private:
void ResolvedExceptionSpec(const FunctionDecl *FD) override;
void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
- const FunctionDecl *Delete) override;
+ const FunctionDecl *Delete,
+ Expr *ThisArg) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
void DefaultArgumentInstantiated(const ParmVarDecl *D) override;
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index c1d4a9fd2d..4e4bf44f34 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -163,9 +163,9 @@ public:
/// \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 = 0;
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index 70c9d9e540..ffc42ce604 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -24,8 +24,10 @@
namespace clang {
class GlobalModuleIndex;
+class MemoryBufferCache;
class ModuleMap;
class PCHContainerReader;
+class HeaderSearch;
namespace serialization {
@@ -51,9 +53,15 @@ class ModuleManager {
/// FileEntry *.
FileManager &FileMgr;
+ /// Cache of PCM files.
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
+
/// \brief Knows how to unwrap module containers.
const PCHContainerReader &PCHContainerRdr;
+ /// \brief Preprocessor's HeaderSearchInfo containing the module map.
+ const HeaderSearch &HeaderSearchInfo;
+
/// \brief A lookup of in-memory (virtual file) buffers
llvm::DenseMap<const FileEntry *, std::unique_ptr<llvm::MemoryBuffer>>
InMemoryBuffers;
@@ -123,8 +131,9 @@ public:
ModuleReverseIterator;
typedef std::pair<uint32_t, StringRef> ModuleOffset;
- explicit ModuleManager(FileManager &FileMgr,
- const PCHContainerReader &PCHContainerRdr);
+ explicit ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache,
+ const PCHContainerReader &PCHContainerRdr,
+ const HeaderSearch &HeaderSearchInfo);
~ModuleManager();
/// \brief Forward iterator to traverse all loaded modules.
@@ -159,8 +168,11 @@ public:
/// \brief Returns the module associated with the given index
ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; }
- /// \brief Returns the module associated with the given name
- ModuleFile *lookup(StringRef Name) const;
+ /// \brief Returns the module associated with the given file name.
+ ModuleFile *lookupByFileName(StringRef FileName) const;
+
+ /// \brief Returns the module associated with the given module name.
+ ModuleFile *lookupByModuleName(StringRef ModName) const;
/// \brief Returns the module associated with the given module file.
ModuleFile *lookup(const FileEntry *File) const;
@@ -290,6 +302,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 ab33c76767..be8b1494c8 100644
--- a/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -38,6 +38,11 @@ def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden;
// default. Such checkers belong in the alpha package.
def OptIn : Package<"optin">;
+// In the Portability package reside checkers for finding code that relies on
+// implementation-defined behavior. Such checks are wanted for cross-platform
+// development, but unwanted for developers who target only a single platform.
+def PortabilityOptIn : Package<"portability">, InPackage<OptIn>;
+
def Nullability : Package<"nullability">;
def Cplusplus : Package<"cplusplus">;
@@ -127,6 +132,10 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
HelpText<"Generate dynamic type information">,
DescFile<"DynamicTypePropagation.cpp">;
+def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">,
+ HelpText<"Assume that const string-like globals are non-null">,
+ DescFile<"NonilStringConstantsChecker.cpp">;
+
} // end "core"
let ParentPackage = CoreAlpha in {
@@ -279,9 +288,19 @@ def VirtualCallChecker : Checker<"VirtualCall">,
let ParentPackage = CplusplusAlpha in {
-def IteratorPastEndChecker : Checker<"IteratorPastEnd">,
- HelpText<"Check iterators used past end">,
- DescFile<"IteratorPastEndChecker.cpp">;
+def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">,
+ HelpText<"Reports destructions of polymorphic objects with a non-virtual "
+ "destructor in their base class">,
+ DescFile<"DeleteWithNonVirtualDtorChecker.cpp">;
+
+def IteratorRangeChecker : Checker<"IteratorRange">,
+ HelpText<"Check for iterators used outside their valid ranges">,
+ DescFile<"IteratorChecker.cpp">;
+
+def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
+ HelpText<"Method calls on a moved-from object and copying a moved-from "
+ "object will be reported">,
+ DescFile<"MisusedMovedObjectChecker.cpp">;
} // end: "alpha.cplusplus"
@@ -411,7 +430,7 @@ def GenericTaintChecker : Checker<"TaintPropagation">,
let ParentPackage = Unix in {
-def UnixAPIChecker : Checker<"API">,
+def UnixAPIMisuseChecker : Checker<"API">,
HelpText<"Check calls to various UNIX/Posix functions">,
DescFile<"UnixAPIChecker.cpp">;
@@ -730,10 +749,6 @@ def ExplodedGraphViewer : Checker<"ViewExplodedGraph">,
HelpText<"View Exploded Graphs using GraphViz">,
DescFile<"DebugCheckers.cpp">;
-def BugHashDumper : Checker<"DumpBugHash">,
- HelpText<"Dump the bug hash for all statements.">,
- DescFile<"DebugCheckers.cpp">;
-
} // end "debug"
@@ -749,3 +764,14 @@ def CloneChecker : Checker<"CloneChecker">,
} // end "clone"
+//===----------------------------------------------------------------------===//
+// Portability checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = PortabilityOptIn in {
+
+def UnixAPIPortabilityChecker : Checker<"UnixAPI">,
+ HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">,
+ DescFile<"UnixAPIChecker.cpp">;
+
+} // end optin.portability
diff --git a/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
index 25886545e2..e5e857e970 100644
--- a/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
+++ b/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
@@ -145,9 +145,11 @@ public:
/// Indicates that the tracked object is an Objective-C object.
ObjC,
/// Indicates that the tracked object could be a CF or Objective-C object.
- AnyObj
+ AnyObj,
+ /// Indicates that the tracked object is a generalized object.
+ Generalized
};
-
+
private:
Kind K;
ObjKind O;
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
index 3355f4b694..281a2ac3a6 100644
--- a/include/clang/StaticAnalyzer/Core/Analyses.def
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -22,14 +22,16 @@ 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)
#endif
-ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer)
+ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer)
+ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis results using HTML (not allowing for multi-file bugs)", createHTMLSingleFileDiagnosticConsumer)
ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer)
-ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer)
+ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer)
ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer)
ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer)
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 4fb50deb0f..ce50cc582d 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -205,9 +205,18 @@ private:
/// Controls which C++ member functions will be considered for inlining.
CXXInlineableMemberKind CXXMemberInliningMode;
+ /// \sa includeImplicitDtorsInCFG
+ Optional<bool> IncludeImplicitDtorsInCFG;
+
/// \sa includeTemporaryDtorsInCFG
Optional<bool> IncludeTemporaryDtorsInCFG;
-
+
+ /// \sa IncludeLifetimeInCFG
+ Optional<bool> IncludeLifetimeInCFG;
+
+ /// \sa IncludeLoopExitInCFG
+ Optional<bool> IncludeLoopExitInCFG;
+
/// \sa mayInlineCXXStandardLibrary
Optional<bool> InlineCXXStandardLibrary;
@@ -269,6 +278,9 @@ private:
/// \sa shouldWidenLoops
Optional<bool> WidenLoops;
+ /// \sa shouldUnrollLoops
+ Optional<bool> UnrollLoops;
+
/// \sa shouldDisplayNotesAsEvents
Optional<bool> DisplayNotesAsEvents;
@@ -395,6 +407,27 @@ public:
/// accepts the values "true" and "false".
bool includeTemporaryDtorsInCFG();
+ /// Returns whether or not implicit destructors for C++ objects should
+ /// be included in the CFG.
+ ///
+ /// This is controlled by the 'cfg-implicit-dtors' config option, which
+ /// accepts the values "true" and "false".
+ bool includeImplicitDtorsInCFG();
+
+ /// Returns whether or not end-of-lifetime information should be included in
+ /// the CFG.
+ ///
+ /// This is controlled by the 'cfg-lifetime' config option, which accepts
+ /// the values "true" and "false".
+ bool includeLifetimeInCFG();
+
+ /// Returns whether or not the end of the loop information should be included
+ /// in the CFG.
+ ///
+ /// This is controlled by the 'cfg-loopexit' config option, which accepts
+ /// the values "true" and "false".
+ bool includeLoopExitInCFG();
+
/// Returns whether or not C++ standard library functions may be considered
/// for inlining.
///
@@ -540,6 +573,10 @@ public:
/// This is controlled by the 'widen-loops' config option.
bool shouldWidenLoops();
+ /// Returns true if the analysis should try to unroll loops with known bounds.
+ /// This is controlled by the 'unroll-loops' config option.
+ bool shouldUnrollLoops();
+
/// Returns true if the bug reporter should transparently treat extra note
/// diagnostic pieces as event diagnostic pieces. Useful when the diagnostic
/// consumer doesn't support the extra note pieces.
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 0f1eb096c4..cd1355d03b 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -17,7 +17,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index b72bce5fc9..2043896fd2 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -1,4 +1,4 @@
-//===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===//
+//===--- BugReporterVisitors.h - Generate PathDiagnostics -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
-#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/FoldingSet.h"
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
index 8df2bc331b..0e80e7bc19 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
@@ -17,6 +17,7 @@ namespace clang {
extern const char * const CoreFoundationObjectiveC;
extern const char * const LogicError;
extern const char * const MemoryCoreFoundationObjectiveC;
+ extern const char * const MemoryError;
extern const char * const UnixAPI;
}
}
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index dc6e54a332..a07cd88950 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -550,13 +550,15 @@ public:
class PathDiagnosticCallPiece : public PathDiagnosticPiece {
PathDiagnosticCallPiece(const Decl *callerD,
const PathDiagnosticLocation &callReturnPos)
- : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr),
- NoExit(false), callReturn(callReturnPos) {}
+ : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr),
+ NoExit(false), IsCalleeAnAutosynthesizedPropertyAccessor(false),
+ callReturn(callReturnPos) {}
PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
- : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr),
- NoExit(true), path(oldPath) {}
-
+ : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr),
+ NoExit(true), IsCalleeAnAutosynthesizedPropertyAccessor(false),
+ path(oldPath) {}
+
const Decl *Caller;
const Decl *Callee;
@@ -564,6 +566,10 @@ class PathDiagnosticCallPiece : public PathDiagnosticPiece {
// call exit.
bool NoExit;
+ // Flag signifying that the callee function is an Objective-C autosynthesized
+ // property getter or setter.
+ bool IsCalleeAnAutosynthesizedPropertyAccessor;
+
// The custom string, which should appear after the call Return Diagnostic.
// TODO: Should we allow multiple diagnostics?
std::string CallStackMessage;
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 52ed260346..88cb08a4b6 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -286,7 +286,7 @@ public:
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
- /// \brief Run checkers on begining of function.
+ /// \brief Run checkers on beginning of function.
void runCheckersForBeginFunction(ExplodedNodeSet &Dst,
const BlockEdge &L,
ExplodedNode *Pred,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 3e0913ec4e..15b930bc3f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 0d1a120c9d..4aa87443e4 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; }
@@ -120,7 +124,7 @@ public:
/// Returns the type of the APSInt used to store values of the given QualType.
APSIntType getAPSIntType(QualType T) const {
assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T));
- return APSIntType(Ctx.getTypeSize(T),
+ return APSIntType(Ctx.getIntWidth(T),
!T->isSignedIntegerOrEnumerationType());
}
@@ -176,6 +180,11 @@ public:
return getValue(X);
}
+ inline const llvm::APSInt& getZeroWithTypeSize(QualType T) {
+ assert(T->isScalarType());
+ return getValue(0, Ctx.getTypeSize(T), true);
+ }
+
inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index aaecf38f33..9fec217aca 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -19,7 +19,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -383,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.
@@ -393,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.
@@ -402,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
@@ -436,20 +436,7 @@ public:
return cast<FunctionDecl>(CallEvent::getDecl());
}
- RuntimeDefinition getRuntimeDefinition() const override {
- const FunctionDecl *FD = getDecl();
- // Note that the AnalysisDeclContext will have the FunctionDecl with
- // the definition (if one exists).
- if (FD) {
- AnalysisDeclContext *AD =
- getLocationContext()->getAnalysisDeclContext()->
- getManager()->getContext(FD);
- if (AD->getBody())
- return RuntimeDefinition(AD->getDecl());
- }
-
- return RuntimeDefinition();
- }
+ RuntimeDefinition getRuntimeDefinition() const override;
bool argumentsMayEscape() const override;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index e380982d43..78d38a3d59 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -196,6 +196,13 @@ public:
return getState()->getSVal(S, getLocationContext());
}
+ /// \brief Returns true if the value of \p E is greater than or equal to \p
+ /// Val under unsigned comparison
+ bool isGreaterOrEqual(const Expr *E, unsigned long long Val);
+
+ /// Returns true if the value of \p E is negative.
+ bool isNegative(const Expr *E);
+
/// \brief Generates a new transition in the program state graph
/// (ExplodedGraph). Uses the default CheckerContext predecessor node.
///
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index fa12d7727d..c01600d5c9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -184,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/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 12ec5b6c64..7472a7147f 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -16,7 +16,7 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
#include "clang/AST/Expr.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index a66e1a1aed..c63ed4a013 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ImmutableMap.h"
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index a710ae68be..dcea5e461d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -20,14 +20,14 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
#include "clang/AST/Decl.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include <memory>
@@ -404,7 +404,7 @@ private:
};
class ExplodedNodeSet {
- typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy;
+ typedef llvm::SmallSetVector<ExplodedNode*, 4> ImplTy;
ImplTy Impl;
public:
@@ -424,7 +424,7 @@ public:
unsigned size() const { return Impl.size(); }
bool empty() const { return Impl.empty(); }
- bool erase(ExplodedNode *N) { return Impl.erase(N); }
+ bool erase(ExplodedNode *N) { return Impl.remove(N); }
void clear() { Impl.clear(); }
void insert(const ExplodedNodeSet &S) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index fa7769bcfc..ecff5c6623 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,8 @@ public:
void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
+ void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
+
void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
@@ -237,7 +239,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,
@@ -621,16 +623,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/LoopUnrolling.h b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
new file mode 100644
index 0000000000..a4c505ce5f
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
@@ -0,0 +1,50 @@
+//===--- LoopUnrolling.h - Unroll loops -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// This header contains the declarations of functions which are used to decide
+/// which loops should be completely unrolled and mark their corresponding
+/// CFGBlocks. It is done by tracking a stack of loops in the ProgramState. This
+/// way specific loops can be marked as completely unrolled. For considering a
+/// loop to be completely unrolled it has to fulfill the following requirements:
+/// - Currently only forStmts can be considered.
+/// - The bound has to be known.
+/// - The counter variable has not escaped before/in the body of the loop and
+/// changed only in the increment statement corresponding to the loop. It also
+/// has to be initialized by a literal in the corresponding initStmt.
+/// - Does not contain goto, switch and returnStmt.
+///
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H
+
+#include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+namespace clang {
+namespace ento {
+class AnalysisManager;
+
+/// Returns if the given State indicates that is inside a completely unrolled
+/// loop.
+bool isUnrolledState(ProgramStateRef State);
+
+/// Updates the stack of loops contained by the ProgramState.
+ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
+ ExplodedNode* Pred, unsigned maxVisitOnPath);
+
+/// Updates the given ProgramState. In current implementation it removes the top
+/// element of the stack of loops.
+ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State);
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index da4b964424..8ab6656230 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -21,7 +21,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/FoldingSet.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 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>
- RegionTy* getSubRegion(const A1 a1, const A2 a2,
- const MemRegion* 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);
@@ -1339,21 +1412,18 @@ public:
bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const;
bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const;
};
-
-} // end GR namespace
-
-} // end clang namespace
//===----------------------------------------------------------------------===//
// Pretty-printing regions.
//===----------------------------------------------------------------------===//
-
-namespace llvm {
-static inline raw_ostream &operator<<(raw_ostream &os,
- const clang::ento::MemRegion* R) {
+inline raw_ostream &operator<<(raw_ostream &os,
+ const clang::ento::MemRegion *R) {
R->dumpToStream(os);
return os;
}
-} // end llvm namespace
+
+} // namespace ento
+
+} // namespace clang
#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 2910ef4212..e3a2164b11 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -43,6 +43,7 @@ typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)(
ProgramStateManager &, SubEngine *);
typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)(
ProgramStateManager &);
+typedef llvm::ImmutableMap<const SubRegion*, TaintTagType> TaintedSubRegions;
//===----------------------------------------------------------------------===//
// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState.
@@ -343,6 +344,9 @@ public:
ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx,
TaintTagType Kind = TaintTagGeneric) const;
+ /// Create a new state in which the value is marked as tainted.
+ ProgramStateRef addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const;
+
/// Create a new state in which the symbol is marked as tainted.
ProgramStateRef addTaint(SymbolRef S,
TaintTagType Kind = TaintTagGeneric) const;
@@ -351,6 +355,14 @@ public:
ProgramStateRef addTaint(const MemRegion *R,
TaintTagType Kind = TaintTagGeneric) const;
+ /// Create a new state in a which a sub-region of a given symbol is tainted.
+ /// This might be necessary when referring to regions that can not have an
+ /// individual symbol, e.g. if they are represented by the default binding of
+ /// a LazyCompoundVal.
+ ProgramStateRef addPartialTaint(SymbolRef ParentSym,
+ const SubRegion *SubRegion,
+ TaintTagType Kind = TaintTagGeneric) const;
+
/// Check if the statement is tainted in the current state.
bool isTainted(const Stmt *S, const LocationContext *LCtx,
TaintTagType Kind = TaintTagGeneric) const;
@@ -453,6 +465,7 @@ private:
std::unique_ptr<ConstraintManager> ConstraintMgr;
ProgramState::GenericDataMap::Factory GDMFactory;
+ TaintedSubRegions::Factory TSRFactory;
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
GDMContextsTy GDMContexts;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index a4c01fc453..d58d0a690c 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,
@@ -310,6 +315,13 @@ public:
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
}
+ /// Create NULL pointer, with proper pointer bit-width for given address
+ /// space.
+ /// \param type pointer type.
+ Loc makeNullWithType(QualType type) {
+ return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type));
+ }
+
Loc makeNull() {
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index cc3c02a02c..af1af4590d 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.
@@ -188,6 +198,10 @@ public:
}
};
+inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
+ V.dumpToStream(os);
+ return os;
+}
class UndefinedVal : public SVal {
public:
@@ -273,6 +287,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 +326,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 +342,6 @@ public:
private:
friend class SVal;
- SymbolVal() {}
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == SymbolValKind;
@@ -373,7 +387,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 +531,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 +556,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 {
@@ -609,11 +626,6 @@ private:
} // end clang namespace
namespace llvm {
-static inline raw_ostream &operator<<(raw_ostream &os,
- clang::ento::SVal V) {
- V.dumpToStream(os);
- return os;
-}
template <typename T> struct isPodLike;
template <> struct isPodLike<clang::ento::SVal> {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 7fa7515bf2..25d20a17af 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -51,7 +51,7 @@ public:
virtual ~StoreManager() {}
/// Return the value bound to specified location in a given state.
- /// \param[in] store The analysis state.
+ /// \param[in] store The store in which to make the lookup.
/// \param[in] loc The symbolic memory location.
/// \param[in] T An optional type that provides a hint indicating the
/// expected type of the returned value. This is used if the value is
@@ -83,12 +83,12 @@ public:
return getDefaultBinding(lcv.getStore(), lcv.getRegion());
}
- /// Return a state with the specified value bound to the given location.
- /// \param[in] store The analysis state.
+ /// Return a store with the specified value bound to the given location.
+ /// \param[in] store The store in which to make the binding.
/// \param[in] loc The symbolic memory location.
/// \param[in] val The value to bind to location \c loc.
- /// \return A pointer to a ProgramState object that contains the same
- /// bindings as \c state with the addition of having the value specified
+ /// \return A StoreRef object that contains the same
+ /// bindings as \c store with the addition of having the value specified
/// by \c val bound to the location given for \c loc.
virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0;
@@ -160,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
@@ -259,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 e16df136ca..8ccd34751b 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,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
index 18bc60754b..9780d01447 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() {}
@@ -92,6 +98,12 @@ public:
virtual const MemRegion *getOriginRegion() const { return nullptr; }
};
+inline raw_ostream &operator<<(raw_ostream &os,
+ const clang::ento::SymExpr *SE) {
+ SE->dumpToStream(os);
+ return os;
+}
+
typedef const SymExpr *SymbolRef;
typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
@@ -103,7 +115,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 f00dce568e..7d2e5ad8ba 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -17,7 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.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; }
@@ -595,11 +633,4 @@ public:
} // end clang namespace
-namespace llvm {
-static inline raw_ostream &operator<<(raw_ostream &os,
- const clang::ento::SymExpr *SE) {
- SE->dumpToStream(os);
- return os;
-}
-} // end llvm namespace
#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index d39b5017d3..7b76263f04 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -35,6 +35,16 @@ template<> struct ProgramStateTrait<TaintMap>
static void *GDMIndex() { static int index = 0; return &index; }
};
+/// The GDM component mapping derived symbols' parent symbols to their
+/// underlying regions. This is used to efficiently check whether a symbol is
+/// tainted when it represents a sub-region of a tainted symbol.
+struct DerivedSymTaint {};
+typedef llvm::ImmutableMap<SymbolRef, TaintedSubRegions> DerivedSymTaintImpl;
+template<> struct ProgramStateTrait<DerivedSymTaint>
+ : public ProgramStatePartialTrait<DerivedSymTaintImpl> {
+ static void *GDMIndex() { static int index; return &index; }
+};
+
class TaintManager {
TaintManager() {}
diff --git a/include/clang/Tooling/ASTDiff/ASTDiff.h b/include/clang/Tooling/ASTDiff/ASTDiff.h
new file mode 100644
index 0000000000..dd11c91ac0
--- /dev/null
+++ b/include/clang/Tooling/ASTDiff/ASTDiff.h
@@ -0,0 +1,127 @@
+//===- ASTDiff.h - AST differencing API -----------------------*- C++ -*- -===//
+//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file specifies an interface that can be used to compare C++ syntax
+// trees.
+//
+// We use the gumtree algorithm which combines a heuristic top-down search that
+// is able to match large subtrees that are equivalent, with an optimal
+// algorithm to match small subtrees.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H
+#define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H
+
+#include "clang/Tooling/ASTDiff/ASTDiffInternal.h"
+
+namespace clang {
+namespace diff {
+
+enum ChangeKind {
+ None,
+ Delete, // (Src): delete node Src.
+ Update, // (Src, Dst): update the value of node Src to match Dst.
+ Insert, // (Src, Dst, Pos): insert Src as child of Dst at offset Pos.
+ Move, // (Src, Dst, Pos): move Src to be a child of Dst at offset Pos.
+ UpdateMove // Same as Move plus Update.
+};
+
+/// Represents a Clang AST node, alongside some additional information.
+struct Node {
+ NodeId Parent, LeftMostDescendant, RightMostDescendant;
+ int Depth, Height, Shift = 0;
+ ast_type_traits::DynTypedNode ASTNode;
+ SmallVector<NodeId, 4> Children;
+ ChangeKind Change = None;
+
+ ast_type_traits::ASTNodeKind getType() const;
+ StringRef getTypeLabel() const;
+ bool isLeaf() const { return Children.empty(); }
+ llvm::Optional<StringRef> getIdentifier() const;
+ llvm::Optional<std::string> getQualifiedIdentifier() const;
+};
+
+class ASTDiff {
+public:
+ ASTDiff(SyntaxTree &Src, SyntaxTree &Dst, const ComparisonOptions &Options);
+ ~ASTDiff();
+
+ // Returns the ID of the node that is mapped to the given node in SourceTree.
+ NodeId getMapped(const SyntaxTree &SourceTree, NodeId Id) const;
+
+ class Impl;
+
+private:
+ std::unique_ptr<Impl> DiffImpl;
+};
+
+/// SyntaxTree objects represent subtrees of the AST.
+/// They can be constructed from any Decl or Stmt.
+class SyntaxTree {
+public:
+ /// Constructs a tree from a translation unit.
+ SyntaxTree(ASTContext &AST);
+ /// Constructs a tree from any AST node.
+ template <class T>
+ SyntaxTree(T *Node, ASTContext &AST)
+ : TreeImpl(llvm::make_unique<Impl>(this, Node, AST)) {}
+ SyntaxTree(SyntaxTree &&Other) = default;
+ ~SyntaxTree();
+
+ const ASTContext &getASTContext() const;
+ StringRef getFilename() const;
+
+ int getSize() const;
+ NodeId getRootId() const;
+ using PreorderIterator = NodeId;
+ PreorderIterator begin() const;
+ PreorderIterator end() const;
+
+ const Node &getNode(NodeId Id) const;
+ int findPositionInParent(NodeId Id) const;
+
+ // Returns the starting and ending offset of the node in its source file.
+ std::pair<unsigned, unsigned> getSourceRangeOffsets(const Node &N) const;
+
+ /// Serialize the node attributes to a string representation. This should
+ /// uniquely distinguish nodes of the same kind. Note that this function just
+ /// returns a representation of the node value, not considering descendants.
+ std::string getNodeValue(NodeId Id) const;
+ std::string getNodeValue(const Node &Node) const;
+
+ class Impl;
+ std::unique_ptr<Impl> TreeImpl;
+};
+
+struct ComparisonOptions {
+ /// During top-down matching, only consider nodes of at least this height.
+ int MinHeight = 2;
+
+ /// During bottom-up matching, match only nodes with at least this value as
+ /// the ratio of their common descendants.
+ double MinSimilarity = 0.5;
+
+ /// Whenever two subtrees are matched in the bottom-up phase, the optimal
+ /// mapping is computed, unless the size of either subtrees exceeds this.
+ int MaxSize = 100;
+
+ bool StopAfterTopDown = false;
+
+ /// Returns false if the nodes should never be matched.
+ bool isMatchingAllowed(const Node &N1, const Node &N2) const {
+ return N1.getType().isSame(N2.getType());
+ }
+};
+
+} // end namespace diff
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Tooling/ASTDiff/ASTDiffInternal.h b/include/clang/Tooling/ASTDiff/ASTDiffInternal.h
new file mode 100644
index 0000000000..a76ad37336
--- /dev/null
+++ b/include/clang/Tooling/ASTDiff/ASTDiffInternal.h
@@ -0,0 +1,48 @@
+//===- ASTDiffInternal.h --------------------------------------*- C++ -*- -===//
+//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFFINTERNAL_H
+#define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFFINTERNAL_H
+
+#include "clang/AST/ASTTypeTraits.h"
+
+namespace clang {
+namespace diff {
+
+using DynTypedNode = ast_type_traits::DynTypedNode;
+
+class SyntaxTree;
+class SyntaxTreeImpl;
+struct ComparisonOptions;
+
+/// Within a tree, this identifies a node by its preorder offset.
+struct NodeId {
+private:
+ static constexpr int InvalidNodeId = -1;
+
+public:
+ int Id;
+
+ NodeId() : Id(InvalidNodeId) {}
+ NodeId(int Id) : Id(Id) {}
+
+ operator int() const { return Id; }
+ NodeId &operator++() { return ++Id, *this; }
+ NodeId &operator--() { return --Id, *this; }
+ // Support defining iterators on NodeId.
+ NodeId &operator*() { return *this; }
+
+ bool isValid() const { return Id != InvalidNodeId; }
+ bool isInvalid() const { return Id == InvalidNodeId; }
+};
+
+} // end namespace diff
+} // end namespace clang
+#endif
diff --git a/include/clang/Tooling/ArgumentsAdjusters.h b/include/clang/Tooling/ArgumentsAdjusters.h
index 1fd7be6887..4eb02251a7 100644
--- a/include/clang/Tooling/ArgumentsAdjusters.h
+++ b/include/clang/Tooling/ArgumentsAdjusters.h
@@ -44,6 +44,10 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster();
/// arguments.
ArgumentsAdjuster getClangStripOutputAdjuster();
+/// \brief Gets an argument adjuster which removes dependency-file
+/// related command line arguments.
+ArgumentsAdjuster getClangStripDependencyFileAdjuster();
+
enum class ArgumentInsertPosition { BEGIN, END };
/// \brief Gets an argument adjuster which inserts \p Extra arguments in the
diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h
index 3d630c5f76..15e8161dd7 100644
--- a/include/clang/Tooling/CommonOptionsParser.h
+++ b/include/clang/Tooling/CommonOptionsParser.h
@@ -27,8 +27,10 @@
#ifndef LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H
#define LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H
+#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
namespace clang {
namespace tooling {
@@ -84,14 +86,19 @@ public:
///
/// All options not belonging to \p Category become hidden.
///
- /// I also allows calls to set the required number of positional parameters.
- ///
- /// This constructor exits program in case of error.
+ /// It also allows calls to set the required number of positional parameters.
CommonOptionsParser(int &argc, const char **argv,
llvm::cl::OptionCategory &Category,
llvm::cl::NumOccurrencesFlag OccurrencesFlag,
const char *Overview = nullptr);
+ /// \brief A factory method that is similar to the above constructor, except
+ /// this returns an error instead exiting the program on error.
+ static llvm::Expected<CommonOptionsParser>
+ create(int &argc, const char **argv, llvm::cl::OptionCategory &Category,
+ llvm::cl::NumOccurrencesFlag OccurrencesFlag,
+ const char *Overview = nullptr);
+
/// Returns a reference to the loaded compilations database.
CompilationDatabase &getCompilations() {
return *Compilations;
@@ -102,13 +109,46 @@ public:
return SourcePathList;
}
+ /// Returns the argument adjuster calculated from "--extra-arg" and
+ //"--extra-arg-before" options.
+ ArgumentsAdjuster getArgumentsAdjuster() { return Adjuster; }
+
static const char *const HelpMessage;
private:
+ CommonOptionsParser() = default;
+
+ llvm::Error init(int &argc, const char **argv,
+ llvm::cl::OptionCategory &Category,
+ llvm::cl::NumOccurrencesFlag OccurrencesFlag,
+ const char *Overview);
+
std::unique_ptr<CompilationDatabase> Compilations;
std::vector<std::string> SourcePathList;
- std::vector<std::string> ExtraArgsBefore;
- std::vector<std::string> ExtraArgsAfter;
+ ArgumentsAdjuster Adjuster;
+};
+
+class ArgumentsAdjustingCompilations : public CompilationDatabase {
+public:
+ ArgumentsAdjustingCompilations(
+ std::unique_ptr<CompilationDatabase> Compilations)
+ : Compilations(std::move(Compilations)) {}
+
+ void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster);
+
+ std::vector<CompileCommand>
+ getCompileCommands(StringRef FilePath) const override;
+
+ std::vector<std::string> getAllFiles() const override;
+
+ std::vector<CompileCommand> getAllCompileCommands() const override;
+
+private:
+ std::unique_ptr<CompilationDatabase> Compilations;
+ std::vector<ArgumentsAdjuster> Adjusters;
+
+ std::vector<CompileCommand>
+ adjustCommands(std::vector<CompileCommand> Commands) const;
};
} // namespace tooling
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index 4611d3cdae..28af33a407 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -60,16 +60,6 @@ struct CompileCommand {
/// The output file associated with the command.
std::string Output;
-
- /// \brief An optional mapping from each file's path to its content for all
- /// files needed for the compilation that are not available via the file
- /// system.
- ///
- /// Note that a tool implementation is required to fall back to the file
- /// system if a source file is not provided in the mapped sources, as
- /// compilation databases will usually not provide all files in mapped sources
- /// for performance reasons.
- std::vector<std::pair<std::string, std::string> > MappedSources;
};
/// \brief Interface for compilation databases.
@@ -114,7 +104,7 @@ public:
/// \brief Returns all compile commands in which the specified file was
/// compiled.
///
- /// This includes compile comamnds that span multiple source files.
+ /// This includes compile commands that span multiple source files.
/// For example, consider a project with the following compilations:
/// $ clang++ -o test a.cc b.cc t.cc
/// $ clang++ -o production a.cc b.cc -DPRODUCTION
@@ -186,10 +176,11 @@ public:
/// the number of arguments before "--", if "--" was found in the argument
/// list.
/// \param Argv Points to the command line arguments.
+ /// \param ErrorMsg Contains error text if the function returns null pointer.
/// \param Directory The base directory used in the FixedCompilationDatabase.
- static FixedCompilationDatabase *loadFromCommandLine(int &Argc,
- const char *const *Argv,
- Twine Directory = ".");
+ static std::unique_ptr<FixedCompilationDatabase> loadFromCommandLine(
+ int &Argc, const char *const *Argv, std::string &ErrorMsg,
+ Twine Directory = ".");
/// \brief Constructs a compilation data base from a specified directory
/// and command line.
diff --git a/include/clang/Tooling/Core/Diagnostic.h b/include/clang/Tooling/Core/Diagnostic.h
index d657f16df1..b4920d4fe4 100644
--- a/include/clang/Tooling/Core/Diagnostic.h
+++ b/include/clang/Tooling/Core/Diagnostic.h
@@ -58,9 +58,9 @@ struct Diagnostic {
Diagnostic(llvm::StringRef DiagnosticName, Level DiagLevel,
StringRef BuildDirectory);
- Diagnostic(llvm::StringRef DiagnosticName, DiagnosticMessage &Message,
- llvm::StringMap<Replacements> &Fix,
- SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel,
+ Diagnostic(llvm::StringRef DiagnosticName, const DiagnosticMessage &Message,
+ const llvm::StringMap<Replacements> &Fix,
+ const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel,
llvm::StringRef BuildDirectory);
/// \brief Name identifying the Diagnostic.
diff --git a/include/clang/Tooling/Core/Replacement.h b/include/clang/Tooling/Core/Replacement.h
index 8d4a22adf3..3fea9aee60 100644
--- a/include/clang/Tooling/Core/Replacement.h
+++ b/include/clang/Tooling/Core/Replacement.h
@@ -255,7 +255,7 @@ class Replacements {
/// \brief Merges \p Replaces into the current replacements. \p Replaces
/// refers to code after applying the current replacements.
- Replacements merge(const Replacements &Replaces) const;
+ LLVM_NODISCARD Replacements merge(const Replacements &Replaces) const;
// Returns the affected ranges in the changed code.
std::vector<Range> getAffectedRanges() const;
diff --git a/include/clang/Tooling/DiagnosticsYaml.h b/include/clang/Tooling/DiagnosticsYaml.h
index f32b9fa9c9..4d6ff06364 100644
--- a/include/clang/Tooling/DiagnosticsYaml.h
+++ b/include/clang/Tooling/DiagnosticsYaml.h
@@ -56,6 +56,9 @@ template <> struct MappingTraits<clang::tooling::Diagnostic> {
MappingNormalization<NormalizedDiagnostic, clang::tooling::Diagnostic> Keys(
Io, D);
Io.mapRequired("DiagnosticName", Keys->DiagnosticName);
+ Io.mapRequired("Message", Keys->Message.Message);
+ Io.mapRequired("FileOffset", Keys->Message.FileOffset);
+ Io.mapRequired("FilePath", Keys->Message.FilePath);
// FIXME: Export properly all the different fields.
@@ -82,17 +85,7 @@ template <> struct MappingTraits<clang::tooling::Diagnostic> {
template <> struct MappingTraits<clang::tooling::TranslationUnitDiagnostics> {
static void mapping(IO &Io, clang::tooling::TranslationUnitDiagnostics &Doc) {
Io.mapRequired("MainSourceFile", Doc.MainSourceFile);
-
- std::vector<clang::tooling::Diagnostic> Diagnostics;
- for (auto &Diagnostic : Doc.Diagnostics) {
- // FIXME: Export all diagnostics, not just the ones with fixes.
- // Update MappingTraits<clang::tooling::Diagnostic>::mapping.
- if (Diagnostic.Fix.size() > 0) {
- Diagnostics.push_back(Diagnostic);
- }
- }
- Io.mapRequired("Diagnostics", Diagnostics);
- Doc.Diagnostics = Diagnostics;
+ Io.mapRequired("Diagnostics", Doc.Diagnostics);
}
};
} // end namespace yaml
diff --git a/include/clang/Tooling/Execution.h b/include/clang/Tooling/Execution.h
new file mode 100644
index 0000000000..9d07c5659e
--- /dev/null
+++ b/include/clang/Tooling/Execution.h
@@ -0,0 +1,168 @@
+//===--- Execution.h - Executing clang frontend actions -*- 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 framework for executing clang frontend actions.
+//
+// The framework can be extended to support different execution plans including
+// standalone execution on the given TUs or parallel execution on all TUs in
+// the codebase.
+//
+// In order to enable multiprocessing execution, tool actions are expected to
+// output result into the ToolResults provided by the executor. The
+// `ToolResults` is an interface that abstracts how results are stored e.g.
+// in-memory for standalone execution or on-disk for large-scale execution.
+//
+// New executors can be registered as ToolExecutorPlugins via the
+// `ToolExecutorPluginRegistry`. CLI tools can use
+// `createExecutorFromCommandLineArgs` to create a specific registered executor
+// according to the command-line arguments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_EXECUTION_H
+#define LLVM_CLANG_TOOLING_EXECUTION_H
+
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace tooling {
+
+/// \brief An abstraction for the result of a tool execution. For example, the
+/// underlying result can be in-memory or on-disk.
+///
+/// Results should be string key-value pairs. For example, a refactoring tool
+/// can use source location as key and a replacement in YAML format as value.
+class ToolResults {
+public:
+ virtual ~ToolResults() = default;
+ virtual void addResult(StringRef Key, StringRef Value) = 0;
+ virtual std::vector<std::pair<std::string, std::string>> AllKVResults() = 0;
+ virtual void forEachResult(
+ llvm::function_ref<void(StringRef Key, StringRef Value)> Callback) = 0;
+};
+
+class InMemoryToolResults : public ToolResults {
+public:
+ void addResult(StringRef Key, StringRef Value) override;
+ std::vector<std::pair<std::string, std::string>> AllKVResults() override;
+ void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
+ Callback) override;
+
+private:
+ std::vector<std::pair<std::string, std::string>> KVResults;
+};
+
+/// \brief The context of an execution, including the information about
+/// compilation and results.
+class ExecutionContext {
+public:
+ virtual ~ExecutionContext() {}
+
+ /// \brief Initializes a context. This does not take ownership of `Results`.
+ explicit ExecutionContext(ToolResults *Results) : Results(Results) {}
+
+ /// \brief Adds a KV pair to the result container of this execution.
+ void reportResult(StringRef Key, StringRef Value);
+
+ // Returns the source control system's revision number if applicable.
+ // Otherwise returns an empty string.
+ virtual std::string getRevision() { return ""; }
+
+ // Returns the corpus being analyzed, e.g. "llvm" for the LLVM codebase, if
+ // applicable.
+ virtual std::string getCorpus() { return ""; }
+
+ // Returns the currently processed compilation unit if available.
+ virtual std::string getCurrentCompilationUnit() { return ""; }
+
+private:
+ ToolResults *Results;
+};
+
+/// \brief Interface for executing clang frontend actions.
+///
+/// This can be extended to support running tool actions in different
+/// execution mode, e.g. on a specific set of TUs or many TUs in parallel.
+///
+/// New executors can be registered as ToolExecutorPlugins via the
+/// `ToolExecutorPluginRegistry`. CLI tools can use
+/// `createExecutorFromCommandLineArgs` to create a specific registered
+/// executor according to the command-line arguments.
+class ToolExecutor {
+public:
+ virtual ~ToolExecutor() {}
+
+ /// \brief Returns the name of a specific executor.
+ virtual StringRef getExecutorName() const = 0;
+
+ /// \brief Executes each action with a corresponding arguments adjuster.
+ virtual llvm::Error
+ execute(llvm::ArrayRef<
+ std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
+ Actions) = 0;
+
+ /// \brief Convenient functions for the above `execute`.
+ llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action);
+ /// Executes an action with an argument adjuster.
+ llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action,
+ ArgumentsAdjuster Adjuster);
+
+ /// \brief Returns a reference to the execution context.
+ ///
+ /// This should be passed to tool callbacks, and tool callbacks should report
+ /// results via the returned context.
+ virtual ExecutionContext *getExecutionContext() = 0;
+
+ /// \brief Returns a reference to the result container.
+ ///
+ /// NOTE: This should only be used after the execution finishes. Tool
+ /// callbacks should report results via `ExecutionContext` instead.
+ virtual ToolResults *getToolResults() = 0;
+
+ /// \brief Map a virtual file to be used while running the tool.
+ ///
+ /// \param FilePath The path at which the content will be mapped.
+ /// \param Content A buffer of the file's content.
+ virtual void mapVirtualFile(StringRef FilePath, StringRef Content) = 0;
+};
+
+/// \brief Interface for factories that create specific executors. This is also
+/// used as a plugin to be registered into ToolExecutorPluginRegistry.
+class ToolExecutorPlugin {
+public:
+ virtual ~ToolExecutorPlugin() {}
+
+ /// \brief Create an `ToolExecutor`.
+ ///
+ /// `OptionsParser` can be consumed (e.g. moved) if the creation succeeds.
+ virtual llvm::Expected<std::unique_ptr<ToolExecutor>>
+ create(CommonOptionsParser &OptionsParser) = 0;
+};
+
+/// \brief This creates a ToolExecutor that is in the global registry based on
+/// commandline arguments.
+///
+/// This picks the right executor based on the `--executor` option. This parses
+/// the commandline arguments with `CommonOptionsParser`, so caller does not
+/// need to parse again.
+///
+/// By default, this creates a `StandaloneToolExecutor` ("standalone") if
+/// `--executor` is not provided.
+llvm::Expected<std::unique_ptr<ToolExecutor>>
+createExecutorFromCommandLineArgs(int &argc, const char **argv,
+ llvm::cl::OptionCategory &Category,
+ const char *Overview = nullptr);
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_EXECUTION_H
diff --git a/include/clang/Tooling/FixIt.h b/include/clang/Tooling/FixIt.h
index e2259d4357..c1e5088492 100644
--- a/include/clang/Tooling/FixIt.h
+++ b/include/clang/Tooling/FixIt.h
@@ -65,6 +65,13 @@ FixItHint createReplacement(const D &Destination, const S &Source,
getText(Source, Context));
}
+// \brief Returns a FixItHint to replace \p Destination by \p Source.
+template <typename D>
+FixItHint createReplacement(const D &Destination, StringRef Source) {
+ return FixItHint::CreateReplacement(internal::getSourceRange(Destination),
+ Source);
+}
+
} // end namespace fixit
} // end namespace tooling
} // end namespace clang
diff --git a/include/clang/Tooling/Refactoring/ASTSelection.h b/include/clang/Tooling/Refactoring/ASTSelection.h
new file mode 100644
index 0000000000..aa02a6899e
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/ASTSelection.h
@@ -0,0 +1,155 @@
+//===--- ASTSelection.h - Clang refactoring library -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include <vector>
+
+namespace clang {
+
+class ASTContext;
+
+namespace tooling {
+
+enum class SourceSelectionKind {
+ /// A node that's not selected.
+ None,
+
+ /// A node that's considered to be selected because the whole selection range
+ /// is inside of its source range.
+ ContainsSelection,
+ /// A node that's considered to be selected because the start of the selection
+ /// range is inside its source range.
+ ContainsSelectionStart,
+ /// A node that's considered to be selected because the end of the selection
+ /// range is inside its source range.
+ ContainsSelectionEnd,
+
+ /// A node that's considered to be selected because the node is entirely in
+ /// the selection range.
+ InsideSelection,
+};
+
+/// Represents a selected AST node.
+///
+/// AST selection is represented using a tree of \c SelectedASTNode. The tree
+/// follows the top-down shape of the actual AST. Each selected node has
+/// a selection kind. The kind might be none as the node itself might not
+/// actually be selected, e.g. a statement in macro whose child is in a macro
+/// argument.
+struct SelectedASTNode {
+ ast_type_traits::DynTypedNode Node;
+ SourceSelectionKind SelectionKind;
+ std::vector<SelectedASTNode> Children;
+
+ SelectedASTNode(const ast_type_traits::DynTypedNode &Node,
+ SourceSelectionKind SelectionKind)
+ : Node(Node), SelectionKind(SelectionKind) {}
+ SelectedASTNode(SelectedASTNode &&) = default;
+ SelectedASTNode &operator=(SelectedASTNode &&) = default;
+
+ void dump(llvm::raw_ostream &OS = llvm::errs()) const;
+
+ using ReferenceType = std::reference_wrapper<const SelectedASTNode>;
+};
+
+/// Traverses the given ASTContext and creates a tree of selected AST nodes.
+///
+/// \returns None if no nodes are selected in the AST, or a selected AST node
+/// that corresponds to the TranslationUnitDecl otherwise.
+Optional<SelectedASTNode> findSelectedASTNodes(const ASTContext &Context,
+ SourceRange SelectionRange);
+
+/// An AST selection value that corresponds to a selection of a set of
+/// statements that belong to one body of code (like one function).
+///
+/// For example, the following selection in the source.
+///
+/// \code
+/// void function() {
+/// // selection begin:
+/// int x = 0;
+/// {
+/// // selection end
+/// x = 1;
+/// }
+/// x = 2;
+/// }
+/// \endcode
+///
+/// Would correspond to a code range selection of statements "int x = 0"
+/// and the entire compound statement that follows it.
+///
+/// A \c CodeRangeASTSelection value stores references to the full
+/// \c SelectedASTNode tree and should not outlive it.
+class CodeRangeASTSelection {
+public:
+ CodeRangeASTSelection(CodeRangeASTSelection &&) = default;
+ CodeRangeASTSelection &operator=(CodeRangeASTSelection &&) = default;
+
+ /// Returns the parent hierarchy (top to bottom) for the selected nodes.
+ ArrayRef<SelectedASTNode::ReferenceType> getParents() { return Parents; }
+
+ /// Returns the number of selected statements.
+ size_t size() const {
+ if (!AreChildrenSelected)
+ return 1;
+ return SelectedNode.get().Children.size();
+ }
+
+ const Stmt *operator[](size_t I) const {
+ if (!AreChildrenSelected) {
+ assert(I == 0 && "Invalid index");
+ return SelectedNode.get().Node.get<Stmt>();
+ }
+ return SelectedNode.get().Children[I].Node.get<Stmt>();
+ }
+
+ /// Returns true when a selected code range is in a function-like body
+ /// of code, like a function, method or a block.
+ ///
+ /// This function can be used to test against selected expressions that are
+ /// located outside of a function, e.g. global variable initializers, default
+ /// argument values, or even template arguments.
+ ///
+ /// Use the \c getFunctionLikeNearestParent to get the function-like parent
+ /// declaration.
+ bool isInFunctionLikeBodyOfCode() const;
+
+ /// Returns the nearest function-like parent declaration or null if such
+ /// declaration doesn't exist.
+ const Decl *getFunctionLikeNearestParent() const;
+
+ static Optional<CodeRangeASTSelection>
+ create(SourceRange SelectionRange, const SelectedASTNode &ASTSelection);
+
+private:
+ CodeRangeASTSelection(SelectedASTNode::ReferenceType SelectedNode,
+ ArrayRef<SelectedASTNode::ReferenceType> Parents,
+ bool AreChildrenSelected)
+ : SelectedNode(SelectedNode), Parents(Parents.begin(), Parents.end()),
+ AreChildrenSelected(AreChildrenSelected) {}
+
+ /// The reference to the selected node (or reference to the selected
+ /// child nodes).
+ SelectedASTNode::ReferenceType SelectedNode;
+ /// The parent hierarchy (top to bottom) for the selected noe.
+ llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents;
+ /// True only when the children of the selected node are actually selected.
+ bool AreChildrenSelected;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_AST_SELECTION_H
diff --git a/include/clang/Tooling/Refactoring/AtomicChange.h b/include/clang/Tooling/Refactoring/AtomicChange.h
index f437c4ba41..8a468a6de8 100644
--- a/include/clang/Tooling/Refactoring/AtomicChange.h
+++ b/include/clang/Tooling/Refactoring/AtomicChange.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
@@ -45,6 +46,14 @@ public:
AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key)
: Key(Key), FilePath(FilePath) {}
+ AtomicChange(AtomicChange &&) = default;
+ AtomicChange(const AtomicChange &) = default;
+
+ AtomicChange &operator=(AtomicChange &&) = default;
+ AtomicChange &operator=(const AtomicChange &) = default;
+
+ bool operator==(const AtomicChange &Other) const;
+
/// \brief Returns the atomic change as a YAML string.
std::string toYAMLString();
@@ -70,6 +79,12 @@ public:
/// \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.
@@ -123,6 +138,41 @@ private:
tooling::Replacements Replaces;
};
+using AtomicChanges = std::vector<AtomicChange>;
+
+// Defines specs for applying changes.
+struct ApplyChangesSpec {
+ // If true, cleans up redundant/erroneous code around changed code with
+ // clang-format's cleanup functionality, e.g. redundant commas around deleted
+ // parameter or empty namespaces introduced by deletions.
+ bool Cleanup = true;
+
+ format::FormatStyle Style = format::getNoStyle();
+
+ // Options for selectively formatting changes with clang-format:
+ // kAll: Format all changed lines.
+ // kNone: Don't format anything.
+ // kViolations: Format lines exceeding the `ColumnLimit` in `Style`.
+ enum FormatOption { kAll, kNone, kViolations };
+
+ FormatOption Format = kNone;
+};
+
+/// \brief Applies all AtomicChanges in \p Changes to the \p Code.
+///
+/// This completely ignores the file path in each change and replaces them with
+/// \p FilePath, i.e. callers are responsible for ensuring all changes are for
+/// the same file.
+///
+/// \returns The changed code if all changes are applied successfully;
+/// otherwise, an llvm::Error carrying llvm::StringError is returned (the Error
+/// message can be converted to string with `llvm::toString()` and the
+/// error_code should be ignored).
+llvm::Expected<std::string>
+applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code,
+ llvm::ArrayRef<AtomicChange> Changes,
+ const ApplyChangesSpec &Spec);
+
} // end namespace tooling
} // end namespace clang
diff --git a/include/clang/Tooling/Refactoring/Extract/Extract.h b/include/clang/Tooling/Refactoring/Extract/Extract.h
new file mode 100644
index 0000000000..2fd76d252c
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Extract/Extract.h
@@ -0,0 +1,53 @@
+//===--- Extract.h - Clang refactoring library ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H
+#define LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H
+
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+
+namespace clang {
+namespace tooling {
+
+/// An "Extract Function" refactoring moves code into a new function that's
+/// then called from the place where the original code was.
+class ExtractFunction final : public SourceChangeRefactoringRule {
+public:
+ /// Initiates the extract function refactoring operation.
+ ///
+ /// \param Code The selected set of statements.
+ /// \param DeclName The name name of the extract function. If None,
+ /// "extracted" is used.
+ static Expected<ExtractFunction> initiate(RefactoringRuleContext &Context,
+ CodeRangeASTSelection Code,
+ Optional<std::string> DeclName);
+
+ static const RefactoringDescriptor &describe();
+
+private:
+ ExtractFunction(CodeRangeASTSelection Code, Optional<std::string> DeclName)
+ : Code(std::move(Code)),
+ DeclName(DeclName ? std::move(*DeclName) : "extracted") {}
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) override;
+
+ CodeRangeASTSelection Code;
+
+ // FIXME: Account for naming collisions:
+ // - error when name is specified by user.
+ // - rename to "extractedN" when name is implicit.
+ std::string DeclName;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H
diff --git a/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
new file mode 100644
index 0000000000..8b01a61256
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
@@ -0,0 +1,122 @@
+//===--- RecursiveSymbolVisitor.h - Clang refactoring library -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief A wrapper class around \c RecursiveASTVisitor that visits each
+/// occurrences of a named symbol.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
+
+#include "clang/AST/AST.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tooling {
+
+/// Traverses the AST and visits the occurrence of each named symbol in the
+/// given nodes.
+template <typename T>
+class RecursiveSymbolVisitor
+ : public RecursiveASTVisitor<RecursiveSymbolVisitor<T>> {
+ using BaseType = RecursiveASTVisitor<RecursiveSymbolVisitor<T>>;
+
+public:
+ RecursiveSymbolVisitor(const SourceManager &SM, const LangOptions &LangOpts)
+ : SM(SM), LangOpts(LangOpts) {}
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ return true;
+ }
+
+ // Declaration visitors:
+
+ bool VisitNamedDecl(const NamedDecl *D) {
+ return isa<CXXConversionDecl>(D) ? true : visit(D, D->getLocation());
+ }
+
+ bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
+ for (const auto *Initializer : CD->inits()) {
+ // Ignore implicit initializers.
+ if (!Initializer->isWritten())
+ continue;
+ if (const FieldDecl *FD = Initializer->getMember()) {
+ if (!visit(FD, Initializer->getSourceLocation(),
+ Lexer::getLocForEndOfToken(Initializer->getSourceLocation(),
+ 0, SM, LangOpts)))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Expression visitors:
+
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+ return visit(Expr->getFoundDecl(), Expr->getLocation());
+ }
+
+ bool VisitMemberExpr(const MemberExpr *Expr) {
+ return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc());
+ }
+
+ // Other visitors:
+
+ bool VisitTypeLoc(const TypeLoc Loc) {
+ const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
+ const SourceLocation TypeEndLoc =
+ Lexer::getLocForEndOfToken(TypeBeginLoc, 0, SM, LangOpts);
+ if (const auto *TemplateTypeParm =
+ dyn_cast<TemplateTypeParmType>(Loc.getType())) {
+ if (!visit(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc))
+ return false;
+ }
+ if (const auto *TemplateSpecType =
+ dyn_cast<TemplateSpecializationType>(Loc.getType())) {
+ if (!visit(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
+ TypeBeginLoc, TypeEndLoc))
+ return false;
+ }
+ return visit(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc);
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ // The base visitor will visit NNSL prefixes, so we should only look at
+ // the current NNS.
+ if (NNS) {
+ const NamespaceDecl *ND = NNS.getNestedNameSpecifier()->getAsNamespace();
+ if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc()))
+ return false;
+ }
+ return BaseType::TraverseNestedNameSpecifierLoc(NNS);
+ }
+
+private:
+ const SourceManager &SM;
+ const LangOptions &LangOpts;
+
+ bool visit(const NamedDecl *ND, SourceLocation BeginLoc,
+ SourceLocation EndLoc) {
+ return static_cast<T *>(this)->visitSymbolOccurrence(
+ ND, SourceRange(BeginLoc, EndLoc));
+ }
+ bool visit(const NamedDecl *ND, SourceLocation Loc) {
+ return visit(ND, Loc,
+ Loc.getLocWithOffset(ND->getNameAsString().length() - 1));
+ }
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringAction.h b/include/clang/Tooling/Refactoring/RefactoringAction.h
new file mode 100644
index 0000000000..c4080237f1
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringAction.h
@@ -0,0 +1,64 @@
+//===--- RefactoringAction.h - Clang refactoring library ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// A refactoring action is a class that defines a set of related refactoring
+/// action rules. These rules get grouped under a common umbrella - a single
+/// clang-refactor subcommand.
+///
+/// A subclass of \c RefactoringAction is responsible for creating the set of
+/// grouped refactoring action rules that represent one refactoring operation.
+/// Although the rules in one action may have a number of different
+/// implementations, they should strive to produce a similar result. It should
+/// be easy for users to identify which refactoring action produced the result
+/// regardless of which refactoring action rule was used.
+///
+/// The distinction between actions and rules enables the creation of action
+/// that uses very different rules, for example:
+/// - local vs global: a refactoring operation like
+/// "add missing switch cases" can be applied to one switch when it's
+/// selected in an editor, or to all switches in a project when an enum
+/// constant is added to an enum.
+/// - tool vs editor: some refactoring operation can be initiated in the
+/// editor when a declaration is selected, or in a tool when the name of
+/// the declaration is passed using a command-line argument.
+class RefactoringAction {
+public:
+ virtual ~RefactoringAction() {}
+
+ /// Returns the name of the subcommand that's used by clang-refactor for this
+ /// action.
+ virtual StringRef getCommand() const = 0;
+
+ virtual StringRef getDescription() const = 0;
+
+ RefactoringActionRules createActiveActionRules();
+
+protected:
+ /// Returns a set of refactoring actions rules that are defined by this
+ /// action.
+ virtual RefactoringActionRules createActionRules() const = 0;
+};
+
+/// Returns the list of all the available refactoring actions.
+std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions();
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRule.h b/include/clang/Tooling/Refactoring/RefactoringActionRule.h
new file mode 100644
index 0000000000..4130e29d8d
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringActionRule.h
@@ -0,0 +1,74 @@
+//===--- RefactoringActionRule.h - Clang refactoring library -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+class RefactoringOptionVisitor;
+class RefactoringResultConsumer;
+class RefactoringRuleContext;
+
+struct RefactoringDescriptor {
+ /// A unique identifier for the specific refactoring.
+ StringRef Name;
+ /// A human readable title for the refactoring.
+ StringRef Title;
+ /// A human readable description of what the refactoring does.
+ StringRef Description;
+};
+
+/// A common refactoring action rule interface that defines the 'invoke'
+/// function that performs the refactoring operation (either fully or
+/// partially).
+class RefactoringActionRuleBase {
+public:
+ virtual ~RefactoringActionRuleBase() {}
+
+ /// Initiates and performs a specific refactoring action.
+ ///
+ /// The specific rule will invoke an appropriate \c handle method on a
+ /// consumer to propagate the result of the refactoring action.
+ virtual void invoke(RefactoringResultConsumer &Consumer,
+ RefactoringRuleContext &Context) = 0;
+
+ /// Returns the structure that describes the refactoring.
+ // static const RefactoringDescriptor &describe() = 0;
+};
+
+/// A refactoring action rule is a wrapper class around a specific refactoring
+/// action rule (SourceChangeRefactoringRule, etc) that, in addition to invoking
+/// the action, describes the requirements that determine when the action can be
+/// initiated.
+class RefactoringActionRule : public RefactoringActionRuleBase {
+public:
+ /// Returns true when the rule has a source selection requirement that has
+ /// to be fullfilled before refactoring can be performed.
+ virtual bool hasSelectionRequirement() = 0;
+
+ /// Traverses each refactoring option used by the rule and invokes the
+ /// \c visit callback in the consumer for each option.
+ ///
+ /// Options are visited in the order of use, e.g. if a rule has two
+ /// requirements that use options, the options from the first requirement
+ /// are visited before the options in the second requirement.
+ virtual void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) = 0;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
new file mode 100644
index 0000000000..355a6a55f2
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h
@@ -0,0 +1,123 @@
+//===--- RefactoringActionRuleRequirements.h - Clang refactoring library --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
+#include "clang/Tooling/Refactoring/RefactoringOption.h"
+#include "clang/Tooling/Refactoring/RefactoringRuleContext.h"
+#include "llvm/Support/Error.h"
+#include <type_traits>
+
+namespace clang {
+namespace tooling {
+
+/// A refactoring action rule requirement determines when a refactoring action
+/// rule can be invoked. The rule can be invoked only when all of the
+/// requirements are satisfied.
+///
+/// Subclasses must implement the
+/// 'Expected<T> evaluate(RefactoringRuleContext &) const' member function.
+/// \c T is used to determine the return type that is passed to the
+/// refactoring rule's constructor.
+/// For example, the \c SourceRangeSelectionRequirement subclass defines
+/// 'Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const'
+/// function. When this function returns a non-error value, the resulting
+/// source range is passed to the specific refactoring action rule
+/// constructor (provided all other requirements are satisfied).
+class RefactoringActionRuleRequirement {
+ // Expected<T> evaluate(RefactoringRuleContext &Context) const;
+};
+
+/// A base class for any requirement that expects some part of the source to be
+/// selected in an editor (or the refactoring tool with the -selection option).
+class SourceSelectionRequirement : public RefactoringActionRuleRequirement {};
+
+/// A selection requirement that is satisfied when any portion of the source
+/// text is selected.
+class SourceRangeSelectionRequirement : public SourceSelectionRequirement {
+public:
+ Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const {
+ if (Context.getSelectionRange().isValid())
+ return Context.getSelectionRange();
+ return Context.createDiagnosticError(diag::err_refactor_no_selection);
+ }
+};
+
+/// An AST selection requirement is satisfied when any portion of the AST
+/// overlaps with the selection range.
+///
+/// The requirement will be evaluated only once during the initiation and
+/// search of matching refactoring action rules.
+class ASTSelectionRequirement : public SourceRangeSelectionRequirement {
+public:
+ Expected<SelectedASTNode> evaluate(RefactoringRuleContext &Context) const;
+};
+
+/// A selection requirement that is satisfied when the selection range overlaps
+/// with a number of neighbouring statements in the AST. The statemenst must be
+/// contained in declaration like a function. The selection range must be a
+/// non-empty source selection (i.e. cursors won't be accepted).
+///
+/// The requirement will be evaluated only once during the initiation and search
+/// of matching refactoring action rules.
+///
+/// \see CodeRangeASTSelection
+class CodeRangeASTSelectionRequirement : public ASTSelectionRequirement {
+public:
+ Expected<CodeRangeASTSelection>
+ evaluate(RefactoringRuleContext &Context) const;
+};
+
+/// A base class for any requirement that requires some refactoring options.
+class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement {
+public:
+ virtual ~RefactoringOptionsRequirement() {}
+
+ /// Returns the set of refactoring options that are used when evaluating this
+ /// requirement.
+ virtual ArrayRef<std::shared_ptr<RefactoringOption>>
+ getRefactoringOptions() const = 0;
+};
+
+/// A requirement that evaluates to the value of the given \c OptionType when
+/// the \c OptionType is a required option. When the \c OptionType is an
+/// optional option, the requirement will evaluate to \c None if the option is
+/// not specified or to an appropriate value otherwise.
+template <typename OptionType>
+class OptionRequirement : public RefactoringOptionsRequirement {
+public:
+ OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {}
+
+ ArrayRef<std::shared_ptr<RefactoringOption>>
+ getRefactoringOptions() const final override {
+ return Opt;
+ }
+
+ Expected<typename OptionType::ValueType>
+ evaluate(RefactoringRuleContext &) const {
+ return static_cast<OptionType *>(Opt.get())->getValue();
+ }
+
+private:
+ /// The partially-owned option.
+ ///
+ /// The ownership of the option is shared among the different requirements
+ /// because the same option can be used by multiple rules in one refactoring
+ /// action.
+ std::shared_ptr<RefactoringOption> Opt;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRules.h b/include/clang/Tooling/Refactoring/RefactoringActionRules.h
new file mode 100644
index 0000000000..33206d9a5d
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringActionRules.h
@@ -0,0 +1,94 @@
+//===--- RefactoringActionRules.h - Clang refactoring library -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H
+
+#include "clang/Tooling/Refactoring/RefactoringActionRule.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRulesInternal.h"
+
+namespace clang {
+namespace tooling {
+
+/// Creates a new refactoring action rule that constructs and invokes the
+/// \c RuleType rule when all of the requirements are satisfied.
+///
+/// This function takes in a list of values whose type derives from
+/// \c RefactoringActionRuleRequirement. These values describe the initiation
+/// requirements that have to be satisfied by the refactoring engine before
+/// the provided action rule can be constructed and invoked. The engine
+/// verifies that the requirements are satisfied by evaluating them (using the
+/// 'evaluate' member function) and checking that the results don't contain
+/// any errors. Once all requirements are satisfied, the provided refactoring
+/// rule is constructed by passing in the values returned by the requirements'
+/// evaluate functions as arguments to the constructor. The rule is then invoked
+/// immediately after construction.
+///
+/// The separation of requirements, their evaluation and the invocation of the
+/// refactoring action rule allows the refactoring clients to:
+/// - Disable refactoring action rules whose requirements are not supported.
+/// - Gather the set of options and define a command-line / visual interface
+/// that allows users to input these options without ever invoking the
+/// action.
+template <typename RuleType, typename... RequirementTypes>
+std::unique_ptr<RefactoringActionRule>
+createRefactoringActionRule(const RequirementTypes &... Requirements);
+
+/// A set of refactoring action rules that should have unique initiation
+/// requirements.
+using RefactoringActionRules =
+ std::vector<std::unique_ptr<RefactoringActionRule>>;
+
+/// A type of refactoring action rule that produces source replacements in the
+/// form of atomic changes.
+///
+/// This action rule is typically used for local refactorings that replace
+/// source in a single AST unit.
+class SourceChangeRefactoringRule : public RefactoringActionRuleBase {
+public:
+ void invoke(RefactoringResultConsumer &Consumer,
+ RefactoringRuleContext &Context) final override {
+ Expected<AtomicChanges> Changes = createSourceReplacements(Context);
+ if (!Changes)
+ Consumer.handleError(Changes.takeError());
+ else
+ Consumer.handle(std::move(*Changes));
+ }
+
+private:
+ virtual Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) = 0;
+};
+
+/// A type of refactoring action rule that finds a set of symbol occurrences
+/// that reference a particular symbol.
+///
+/// This action rule is typically used for an interactive rename that allows
+/// users to specify the new name and the set of selected occurrences during
+/// the refactoring.
+class FindSymbolOccurrencesRefactoringRule : public RefactoringActionRuleBase {
+public:
+ void invoke(RefactoringResultConsumer &Consumer,
+ RefactoringRuleContext &Context) final override {
+ Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(Context);
+ if (!Occurrences)
+ Consumer.handleError(Occurrences.takeError());
+ else
+ Consumer.handle(std::move(*Occurrences));
+ }
+
+private:
+ virtual Expected<SymbolOccurrences>
+ findSymbolOccurrences(RefactoringRuleContext &Context) = 0;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
new file mode 100644
index 0000000000..75b6c8f70d
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
@@ -0,0 +1,158 @@
+//===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRule.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
+#include "clang/Tooling/Refactoring/RefactoringResultConsumer.h"
+#include "clang/Tooling/Refactoring/RefactoringRuleContext.h"
+#include "llvm/Support/Error.h"
+#include <type_traits>
+
+namespace clang {
+namespace tooling {
+namespace internal {
+
+inline llvm::Error findError() { return llvm::Error::success(); }
+
+inline void ignoreError() {}
+
+template <typename FirstT, typename... RestT>
+void ignoreError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
+ if (!First)
+ llvm::consumeError(First.takeError());
+ ignoreError(Rest...);
+}
+
+/// Scans the tuple and returns a valid \c Error if any of the values are
+/// invalid.
+template <typename FirstT, typename... RestT>
+llvm::Error findError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
+ if (!First) {
+ ignoreError(Rest...);
+ return First.takeError();
+ }
+ return findError(Rest...);
+}
+
+template <typename RuleType, typename... RequirementTypes, size_t... Is>
+void invokeRuleAfterValidatingRequirements(
+ RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context,
+ const std::tuple<RequirementTypes...> &Requirements,
+ llvm::index_sequence<Is...>) {
+ // Check if the requirements we're interested in can be evaluated.
+ auto Values =
+ std::make_tuple(std::get<Is>(Requirements).evaluate(Context)...);
+ auto Err = findError(std::get<Is>(Values)...);
+ if (Err)
+ return Consumer.handleError(std::move(Err));
+ // Construct the target action rule by extracting the evaluated
+ // requirements from Expected<> wrappers and then run it.
+ auto Rule =
+ RuleType::initiate(Context, std::move((*std::get<Is>(Values)))...);
+ if (!Rule)
+ return Consumer.handleError(Rule.takeError());
+ Rule->invoke(Consumer, Context);
+}
+
+inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {}
+
+/// Scans the list of requirements in a rule and visits all the refactoring
+/// options that are used by all the requirements.
+template <typename FirstT, typename... RestT>
+void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor,
+ const FirstT &First, const RestT &... Rest) {
+ struct OptionGatherer {
+ RefactoringOptionVisitor &Visitor;
+
+ void operator()(const RefactoringOptionsRequirement &Requirement) {
+ for (const auto &Option : Requirement.getRefactoringOptions())
+ Option->passToVisitor(Visitor);
+ }
+ void operator()(const RefactoringActionRuleRequirement &) {}
+ };
+ (OptionGatherer{Visitor})(First);
+ return visitRefactoringOptionsImpl(Visitor, Rest...);
+}
+
+template <typename... RequirementTypes, size_t... Is>
+void visitRefactoringOptions(
+ RefactoringOptionVisitor &Visitor,
+ const std::tuple<RequirementTypes...> &Requirements,
+ llvm::index_sequence<Is...>) {
+ visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...);
+}
+
+/// A type trait that returns true when the given type list has at least one
+/// type whose base is the given base type.
+template <typename Base, typename First, typename... Rest>
+struct HasBaseOf : std::conditional<HasBaseOf<Base, First>::value ||
+ HasBaseOf<Base, Rest...>::value,
+ std::true_type, std::false_type>::type {};
+
+template <typename Base, typename T>
+struct HasBaseOf<Base, T> : std::is_base_of<Base, T> {};
+
+/// A type trait that returns true when the given type list contains types that
+/// derive from Base.
+template <typename Base, typename First, typename... Rest>
+struct AreBaseOf : std::conditional<AreBaseOf<Base, First>::value &&
+ AreBaseOf<Base, Rest...>::value,
+ std::true_type, std::false_type>::type {};
+
+template <typename Base, typename T>
+struct AreBaseOf<Base, T> : std::is_base_of<Base, T> {};
+
+} // end namespace internal
+
+template <typename RuleType, typename... RequirementTypes>
+std::unique_ptr<RefactoringActionRule>
+createRefactoringActionRule(const RequirementTypes &... Requirements) {
+ static_assert(std::is_base_of<RefactoringActionRuleBase, RuleType>::value,
+ "Expected a refactoring action rule type");
+ static_assert(internal::AreBaseOf<RefactoringActionRuleRequirement,
+ RequirementTypes...>::value,
+ "Expected a list of refactoring action rules");
+
+ class Rule final : public RefactoringActionRule {
+ public:
+ Rule(std::tuple<RequirementTypes...> Requirements)
+ : Requirements(Requirements) {}
+
+ void invoke(RefactoringResultConsumer &Consumer,
+ RefactoringRuleContext &Context) override {
+ internal::invokeRuleAfterValidatingRequirements<RuleType>(
+ Consumer, Context, Requirements,
+ llvm::index_sequence_for<RequirementTypes...>());
+ }
+
+ bool hasSelectionRequirement() override {
+ return internal::HasBaseOf<SourceSelectionRequirement,
+ RequirementTypes...>::value;
+ }
+
+ void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override {
+ internal::visitRefactoringOptions(
+ Visitor, Requirements,
+ llvm::index_sequence_for<RequirementTypes...>());
+ }
+ private:
+ std::tuple<RequirementTypes...> Requirements;
+ };
+
+ return llvm::make_unique<Rule>(std::make_tuple(Requirements...));
+}
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h b/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h
new file mode 100644
index 0000000000..6767dc708e
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringDiagnostic.h
@@ -0,0 +1,30 @@
+//===--- RefactoringDiagnostic.h - ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H
+#define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/PartialDiagnostic.h"
+
+namespace clang {
+namespace diag {
+enum {
+#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \
+ SHOWINSYSHEADER, CATEGORY) \
+ ENUM,
+#define REFACTORINGSTART
+#include "clang/Basic/DiagnosticRefactoringKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_REFACTORING_DIAGNOSTICS
+};
+} // end namespace diag
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGDIAGNOSTIC_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringOption.h b/include/clang/Tooling/Refactoring/RefactoringOption.h
new file mode 100644
index 0000000000..5011223cce
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringOption.h
@@ -0,0 +1,64 @@
+//===--- RefactoringOption.h - Clang refactoring library ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H
+
+#include "clang/Basic/LLVM.h"
+#include <memory>
+#include <type_traits>
+
+namespace clang {
+namespace tooling {
+
+class RefactoringOptionVisitor;
+
+/// A refactoring option is an interface that describes a value that
+/// has an impact on the outcome of a refactoring.
+///
+/// Refactoring options can be specified using command-line arguments when
+/// the clang-refactor tool is used.
+class RefactoringOption {
+public:
+ virtual ~RefactoringOption() {}
+
+ /// Returns the name of the refactoring option.
+ ///
+ /// Each refactoring option must have a unique name.
+ virtual StringRef getName() const = 0;
+
+ virtual StringRef getDescription() const = 0;
+
+ /// True when this option must be specified before invoking the refactoring
+ /// action.
+ virtual bool isRequired() const = 0;
+
+ /// Invokes the \c visit method in the option consumer that's appropriate
+ /// for the option's value type.
+ ///
+ /// For example, if the option stores a string value, this method will
+ /// invoke the \c visit method with a reference to an std::string value.
+ virtual void passToVisitor(RefactoringOptionVisitor &Visitor) = 0;
+};
+
+/// Constructs a refactoring option of the given type.
+///
+/// The ownership of options is shared among requirements that use it because
+/// one option can be used by multiple rules in a refactoring action.
+template <typename OptionType>
+std::shared_ptr<OptionType> createRefactoringOption() {
+ static_assert(std::is_base_of<RefactoringOption, OptionType>::value,
+ "invalid option type");
+ return std::make_shared<OptionType>();
+}
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h b/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h
new file mode 100644
index 0000000000..aea8fa5493
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringOptionVisitor.h
@@ -0,0 +1,62 @@
+//===--- RefactoringOptionVisitor.h - Clang refactoring library -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H
+
+#include "clang/Basic/LLVM.h"
+#include <type_traits>
+
+namespace clang {
+namespace tooling {
+
+class RefactoringOption;
+
+/// An interface that declares functions that handle different refactoring
+/// option types.
+///
+/// A valid refactoring option type must have a corresponding \c visit
+/// declaration in this interface.
+class RefactoringOptionVisitor {
+public:
+ virtual ~RefactoringOptionVisitor() {}
+
+ virtual void visit(const RefactoringOption &Opt,
+ Optional<std::string> &Value) = 0;
+};
+
+namespace traits {
+namespace internal {
+
+template <typename T> struct HasHandle {
+private:
+ template <typename ClassT>
+ static auto check(ClassT *) -> typename std::is_same<
+ decltype(std::declval<RefactoringOptionVisitor>().visit(
+ std::declval<RefactoringOption>(), *std::declval<Optional<T> *>())),
+ void>::type;
+
+ template <typename> static std::false_type check(...);
+
+public:
+ using Type = decltype(check<RefactoringOptionVisitor>(nullptr));
+};
+
+} // end namespace internal
+
+/// A type trait that returns true iff the given type is a type that can be
+/// stored in a refactoring option.
+template <typename T>
+struct IsValidOptionType : internal::HasHandle<T>::Type {};
+
+} // end namespace traits
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringOptions.h b/include/clang/Tooling/Refactoring/RefactoringOptions.h
new file mode 100644
index 0000000000..e45c0a09fd
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringOptions.h
@@ -0,0 +1,58 @@
+//===--- RefactoringOptions.h - Clang refactoring library -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
+#include "clang/Tooling/Refactoring/RefactoringOption.h"
+#include "clang/Tooling/Refactoring/RefactoringOptionVisitor.h"
+#include "llvm/Support/Error.h"
+#include <type_traits>
+
+namespace clang {
+namespace tooling {
+
+/// A refactoring option that stores a value of type \c T.
+template <typename T, typename = typename std::enable_if<
+ traits::IsValidOptionType<T>::value>::type>
+class OptionalRefactoringOption : public RefactoringOption {
+public:
+ void passToVisitor(RefactoringOptionVisitor &Visitor) final override {
+ Visitor.visit(*this, Value);
+ }
+
+ bool isRequired() const override { return false; }
+
+ using ValueType = Optional<T>;
+
+ const ValueType &getValue() const { return Value; }
+
+protected:
+ Optional<T> Value;
+};
+
+/// A required refactoring option that stores a value of type \c T.
+template <typename T, typename = typename std::enable_if<
+ traits::IsValidOptionType<T>::value>::type>
+class RequiredRefactoringOption : public OptionalRefactoringOption<T> {
+public:
+ using ValueType = T;
+
+ const ValueType &getValue() const {
+ return *OptionalRefactoringOption<T>::Value;
+ }
+ bool isRequired() const final override { return true; }
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h b/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h
new file mode 100644
index 0000000000..fe7738e734
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringResultConsumer.h
@@ -0,0 +1,52 @@
+//===--- RefactoringResultConsumer.h - Clang refactoring library ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace tooling {
+
+/// An abstract interface that consumes the various refactoring results that can
+/// be produced by refactoring actions.
+///
+/// A valid refactoring result must be handled by a \c handle method.
+class RefactoringResultConsumer {
+public:
+ virtual ~RefactoringResultConsumer() {}
+
+ /// Handles an initation or an invication error. An initiation error typically
+ /// has a \c DiagnosticError payload that describes why initation failed.
+ virtual void handleError(llvm::Error Err) = 0;
+
+ /// Handles the source replacements that are produced by a refactoring action.
+ virtual void handle(AtomicChanges SourceReplacements) {
+ defaultResultHandler();
+ }
+
+ /// Handles the symbol occurrences that are found by an interactive
+ /// refactoring action.
+ virtual void handle(SymbolOccurrences Occurrences) { defaultResultHandler(); }
+
+private:
+ void defaultResultHandler() {
+ handleError(llvm::make_error<llvm::StringError>(
+ "unsupported refactoring result", llvm::inconvertibleErrorCode()));
+ }
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_CONSUMER_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringRuleContext.h b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
new file mode 100644
index 0000000000..882ab824b6
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
@@ -0,0 +1,90 @@
+//===--- RefactoringRuleContext.h - Clang refactoring library -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H
+
+#include "clang/Basic/DiagnosticError.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+
+namespace clang {
+
+class ASTContext;
+
+namespace tooling {
+
+/// The refactoring rule context stores all of the inputs that might be needed
+/// by a refactoring action rule. It can create the specialized
+/// \c ASTRefactoringOperation or \c PreprocessorRefactoringOperation values
+/// that can be used by the refactoring action rules.
+///
+/// The following inputs are stored by the operation:
+///
+/// - SourceManager: a reference to a valid source manager.
+///
+/// - SelectionRange: an optional source selection ranges that can be used
+/// to represent a selection in an editor.
+class RefactoringRuleContext {
+public:
+ RefactoringRuleContext(const SourceManager &SM) : SM(SM) {}
+
+ const SourceManager &getSources() const { return SM; }
+
+ /// Returns the current source selection range as set by the
+ /// refactoring engine. Can be invalid.
+ SourceRange getSelectionRange() const { return SelectionRange; }
+
+ void setSelectionRange(SourceRange R) { SelectionRange = R; }
+
+ bool hasASTContext() const { return AST; }
+
+ ASTContext &getASTContext() const {
+ assert(AST && "no AST!");
+ return *AST;
+ }
+
+ void setASTContext(ASTContext &Context) { AST = &Context; }
+
+ /// Creates an llvm::Error value that contains a diagnostic.
+ ///
+ /// The errors should not outlive the context.
+ llvm::Error createDiagnosticError(SourceLocation Loc, unsigned DiagID) {
+ return DiagnosticError::create(Loc, PartialDiagnostic(DiagID, DiagStorage));
+ }
+
+ llvm::Error createDiagnosticError(unsigned DiagID) {
+ return createDiagnosticError(SourceLocation(), DiagID);
+ }
+
+ void setASTSelection(std::unique_ptr<SelectedASTNode> Node) {
+ ASTNodeSelection = std::move(Node);
+ }
+
+private:
+ /// The source manager for the translation unit / file on which a refactoring
+ /// action might operate on.
+ const SourceManager &SM;
+ /// An optional source selection range that's commonly used to represent
+ /// a selection in an editor.
+ SourceRange SelectionRange;
+ /// An optional AST for the translation unit on which a refactoring action
+ /// might operate on.
+ ASTContext *AST = nullptr;
+ /// The allocator for diagnostics.
+ PartialDiagnostic::StorageAllocator DiagStorage;
+
+ // FIXME: Remove when memoized.
+ std::unique_ptr<SelectedASTNode> ASTNodeSelection;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RULE_CONTEXT_H
diff --git a/include/clang/Tooling/Refactoring/Rename/RenamingAction.h b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
new file mode 100644
index 0000000000..d9ed7d3a1f
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
@@ -0,0 +1,100 @@
+//===--- RenamingAction.h - Clang refactoring library ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to rename every symbol at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
+
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+class ASTConsumer;
+class CompilerInstance;
+
+namespace tooling {
+
+class RenamingAction {
+public:
+ RenamingAction(const std::vector<std::string> &NewNames,
+ const std::vector<std::string> &PrevNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces,
+ bool PrintLocations = false)
+ : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
+ FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
+
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+ const std::vector<std::string> &NewNames, &PrevNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+ bool PrintLocations;
+};
+
+class RenameOccurrences final : public SourceChangeRefactoringRule {
+public:
+ static Expected<RenameOccurrences> initiate(RefactoringRuleContext &Context,
+ SourceRange SelectionRange,
+ std::string NewName);
+
+ static const RefactoringDescriptor &describe();
+
+private:
+ RenameOccurrences(const NamedDecl *ND, std::string NewName)
+ : ND(ND), NewName(std::move(NewName)) {}
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) override;
+
+ const NamedDecl *ND;
+ std::string NewName;
+};
+
+/// Returns source replacements that correspond to the rename of the given
+/// symbol occurrences.
+llvm::Expected<std::vector<AtomicChange>>
+createRenameReplacements(const SymbolOccurrences &Occurrences,
+ const SourceManager &SM, const SymbolName &NewName);
+
+/// Rename all symbols identified by the given USRs.
+class QualifiedRenamingAction {
+public:
+ QualifiedRenamingAction(
+ const std::vector<std::string> &NewNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces)
+ : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {}
+
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+ /// New symbol names.
+ const std::vector<std::string> &NewNames;
+
+ /// A list of USRs. Each element represents USRs of a symbol being renamed.
+ const std::vector<std::vector<std::string>> &USRList;
+
+ /// A file path to replacements map.
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
diff --git a/include/clang/Tooling/Refactoring/Rename/SymbolName.h b/include/clang/Tooling/Refactoring/Rename/SymbolName.h
new file mode 100644
index 0000000000..e69d2908b5
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Rename/SymbolName.h
@@ -0,0 +1,49 @@
+//===--- SymbolName.h - Clang refactoring library -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace tooling {
+
+/// A name of a symbol.
+///
+/// Symbol's name can be composed of multiple strings. For example, Objective-C
+/// methods can contain multiple argument lables:
+///
+/// \code
+/// - (void) myMethodNamePiece: (int)x anotherNamePieces:(int)y;
+/// // ^~ string 0 ~~~~~ ^~ string 1 ~~~~~
+/// \endcode
+class SymbolName {
+public:
+ explicit SymbolName(StringRef Name) {
+ // While empty symbol names are valid (Objective-C selectors can have empty
+ // name pieces), occurrences Objective-C selectors are created using an
+ // array of strings instead of just one string.
+ assert(!Name.empty() && "Invalid symbol name!");
+ this->Name.push_back(Name.str());
+ }
+
+ ArrayRef<std::string> getNamePieces() const { return Name; }
+
+private:
+ llvm::SmallVector<std::string, 1> Name;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H
diff --git a/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h b/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h
new file mode 100644
index 0000000000..0f85301197
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h
@@ -0,0 +1,91 @@
+//===--- SymbolOccurrences.h - Clang refactoring library ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+class SymbolName;
+
+/// An occurrence of a symbol in the source.
+///
+/// Occurrences can have difference kinds, that describe whether this occurrence
+/// is an exact semantic match, or whether this is a weaker textual match that's
+/// not guaranteed to represent the exact declaration.
+///
+/// A single occurrence of a symbol can span more than one source range. For
+/// example, Objective-C selectors can contain multiple argument labels:
+///
+/// \code
+/// [object selectorPiece1: ... selectorPiece2: ...];
+/// // ^~~ range 0 ~~ ^~~ range 1 ~~
+/// \endcode
+///
+/// We have to replace the text in both range 0 and range 1 when renaming the
+/// Objective-C method 'selectorPiece1:selectorPiece2'.
+class SymbolOccurrence {
+public:
+ enum OccurrenceKind {
+ /// This occurrence is an exact match and can be renamed automatically.
+ ///
+ /// Note:
+ /// Symbol occurrences in macro arguments that expand to different
+ /// declarations get marked as exact matches, and thus the renaming engine
+ /// will rename them e.g.:
+ ///
+ /// \code
+ /// #define MACRO(x) x + ns::x
+ /// int foo(int var) {
+ /// return MACRO(var); // var is renamed automatically here when
+ /// // either var or ns::var is renamed.
+ /// };
+ /// \endcode
+ ///
+ /// The user will have to fix their code manually after performing such a
+ /// rename.
+ /// FIXME: The rename verifier should notify user about this issue.
+ MatchingSymbol
+ };
+
+ SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind,
+ ArrayRef<SourceLocation> Locations);
+
+ SymbolOccurrence(SymbolOccurrence &&) = default;
+ SymbolOccurrence &operator=(SymbolOccurrence &&) = default;
+
+ OccurrenceKind getKind() const { return Kind; }
+
+ ArrayRef<SourceRange> getNameRanges() const {
+ if (MultipleRanges) {
+ return llvm::makeArrayRef(MultipleRanges.get(),
+ RangeOrNumRanges.getBegin().getRawEncoding());
+ }
+ return RangeOrNumRanges;
+ }
+
+private:
+ OccurrenceKind Kind;
+ std::unique_ptr<SourceRange[]> MultipleRanges;
+ SourceRange RangeOrNumRanges;
+};
+
+using SymbolOccurrences = std::vector<SymbolOccurrence>;
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H
diff --git a/include/clang/Tooling/Refactoring/Rename/USRFinder.h b/include/clang/Tooling/Refactoring/Rename/USRFinder.h
new file mode 100644
index 0000000000..b74a5d7f70
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Rename/USRFinder.h
@@ -0,0 +1,50 @@
+//===--- USRFinder.h - Clang refactoring library --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Methods for determining the USR of a symbol at a location in source
+/// code.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
+
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTContext.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class SourceLocation;
+class NamedDecl;
+
+namespace tooling {
+
+// Given an AST context and a point, returns a NamedDecl identifying the symbol
+// at the point. Returns null if nothing is found at the point.
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,
+ const SourceLocation Point);
+
+// Given an AST context and a fully qualified name, returns a NamedDecl
+// identifying the symbol with a matching name. Returns null if nothing is
+// found for the name.
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,
+ const std::string &Name);
+
+// Converts a Decl into a USR.
+std::string getUSRForDecl(const Decl *Decl);
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
diff --git a/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h b/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
new file mode 100644
index 0000000000..f1c5ae60f8
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
@@ -0,0 +1,68 @@
+//===--- USRFindingAction.h - Clang refactoring library -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to find all relevant USRs at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+
+#include <string>
+#include <vector>
+
+namespace clang {
+class ASTConsumer;
+class ASTContext;
+class CompilerInstance;
+class NamedDecl;
+
+namespace tooling {
+
+/// Returns the canonical declaration that best represents a symbol that can be
+/// renamed.
+///
+/// The following canonicalization rules are currently used:
+///
+/// - A constructor is canonicalized to its class.
+/// - A destructor is canonicalized to its class.
+const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl);
+
+/// Returns the set of USRs that correspond to the given declaration.
+std::vector<std::string> getUSRsForDeclaration(const NamedDecl *ND,
+ ASTContext &Context);
+
+struct USRFindingAction {
+ USRFindingAction(ArrayRef<unsigned> SymbolOffsets,
+ ArrayRef<std::string> QualifiedNames, bool Force)
+ : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
+ ErrorOccurred(false), Force(Force) {}
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+ ArrayRef<std::string> getUSRSpellings() { return SpellingNames; }
+ ArrayRef<std::vector<std::string>> getUSRList() { return USRList; }
+ bool errorOccurred() { return ErrorOccurred; }
+
+private:
+ std::vector<unsigned> SymbolOffsets;
+ std::vector<std::string> QualifiedNames;
+ std::vector<std::string> SpellingNames;
+ std::vector<std::vector<std::string>> USRList;
+ bool ErrorOccurred;
+ bool Force;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
diff --git a/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h b/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
new file mode 100644
index 0000000000..801a8ad9e9
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
@@ -0,0 +1,53 @@
+//===--- USRLocFinder.h - Clang refactoring library -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides functionality for finding all instances of a USR in a given
+/// AST.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
+
+#include "clang/AST/AST.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// Create atomic changes for renaming all symbol references which are
+/// identified by the USRs set to a given new name.
+///
+/// \param USRs The set containing USRs of a particular old symbol.
+/// \param NewName The new name to replace old symbol name.
+/// \param TranslationUnitDecl The translation unit declaration.
+///
+/// \return Atomic changes for renaming.
+std::vector<tooling::AtomicChange>
+createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
+ llvm::StringRef NewName, Decl *TranslationUnitDecl);
+
+/// Finds the symbol occurrences for the symbol that's identified by the given
+/// USR set.
+///
+/// \return SymbolOccurrences that can be converted to AtomicChanges when
+/// renaming.
+SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs,
+ StringRef PrevName, Decl *Decl);
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
diff --git a/include/clang/Tooling/RefactoringCallbacks.h b/include/clang/Tooling/RefactoringCallbacks.h
index 6ef9ea11f0..9862951149 100644
--- a/include/clang/Tooling/RefactoringCallbacks.h
+++ b/include/clang/Tooling/RefactoringCallbacks.h
@@ -47,6 +47,33 @@ protected:
Replacements Replace;
};
+/// \brief Adaptor between \c ast_matchers::MatchFinder and \c
+/// tooling::RefactoringTool.
+///
+/// Runs AST matchers and stores the \c tooling::Replacements in a map.
+class ASTMatchRefactorer {
+public:
+ explicit ASTMatchRefactorer(
+ std::map<std::string, Replacements> &FileToReplaces);
+
+ template <typename T>
+ void addMatcher(const T &Matcher, RefactoringCallback *Callback) {
+ MatchFinder.addMatcher(Matcher, Callback);
+ Callbacks.push_back(Callback);
+ }
+
+ void addDynamicMatcher(const ast_matchers::internal::DynTypedMatcher &Matcher,
+ RefactoringCallback *Callback);
+
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+ friend class RefactoringASTConsumer;
+ std::vector<RefactoringCallback *> Callbacks;
+ ast_matchers::MatchFinder MatchFinder;
+ std::map<std::string, Replacements> &FileToReplaces;
+};
+
/// \brief Replace the text of the statement bound to \c FromId with the text in
/// \c ToText.
class ReplaceStmtWithText : public RefactoringCallback {
@@ -59,6 +86,29 @@ private:
std::string ToText;
};
+/// \brief Replace the text of an AST node bound to \c FromId with the result of
+/// evaluating the template in \c ToTemplate.
+///
+/// Expressions of the form ${NodeName} in \c ToTemplate will be
+/// replaced by the text of the node bound to ${NodeName}. The string
+/// "$$" will be replaced by "$".
+class ReplaceNodeWithTemplate : public RefactoringCallback {
+public:
+ static llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>>
+ create(StringRef FromId, StringRef ToTemplate);
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ struct TemplateElement {
+ enum { Literal, Identifier } Type;
+ std::string Value;
+ };
+ ReplaceNodeWithTemplate(llvm::StringRef FromId,
+ std::vector<TemplateElement> Template);
+ std::string FromId;
+ std::vector<TemplateElement> Template;
+};
+
/// \brief Replace the text of the statement bound to \c FromId with the text of
/// the statement bound to \c ToId.
class ReplaceStmtWithStmt : public RefactoringCallback {
diff --git a/include/clang/Tooling/StandaloneExecution.h b/include/clang/Tooling/StandaloneExecution.h
new file mode 100644
index 0000000000..f5f32d737a
--- /dev/null
+++ b/include/clang/Tooling/StandaloneExecution.h
@@ -0,0 +1,97 @@
+//===--- StandaloneExecution.h - Standalone execution. -*- 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 standalone execution of clang tools.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H
+#define LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H
+
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/Execution.h"
+
+namespace clang {
+namespace tooling {
+
+/// \brief A standalone executor that runs FrontendActions on a given set of
+/// TUs in sequence.
+///
+/// By default, this executor uses the following arguments adjusters (as defined
+/// in `clang/Tooling/ArgumentsAdjusters.h`):
+/// - `getClangStripOutputAdjuster()`
+/// - `getClangSyntaxOnlyAdjuster()`
+/// - `getClangStripDependencyFileAdjuster()`
+class StandaloneToolExecutor : public ToolExecutor {
+public:
+ static const char *ExecutorName;
+
+ /// \brief Init with \p CompilationDatabase and the paths of all files to be
+ /// proccessed.
+ StandaloneToolExecutor(
+ const CompilationDatabase &Compilations,
+ llvm::ArrayRef<std::string> SourcePaths,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps =
+ std::make_shared<PCHContainerOperations>());
+
+ /// \brief Init with \p CommonOptionsParser. This is expected to be used by
+ /// `createExecutorFromCommandLineArgs` based on commandline options.
+ ///
+ /// The executor takes ownership of \p Options.
+ StandaloneToolExecutor(
+ CommonOptionsParser Options,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps =
+ std::make_shared<PCHContainerOperations>());
+
+ StringRef getExecutorName() const override { return ExecutorName; }
+
+ using ToolExecutor::execute;
+
+ llvm::Error
+ execute(llvm::ArrayRef<
+ std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
+ Actions) override;
+
+ /// \brief Set a \c DiagnosticConsumer to use during parsing.
+ void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) {
+ Tool.setDiagnosticConsumer(DiagConsumer);
+ }
+
+ ExecutionContext *getExecutionContext() override { return &Context; };
+
+ ToolResults *getToolResults() override { return &Results; }
+
+ llvm::ArrayRef<std::string> getSourcePaths() const {
+ return Tool.getSourcePaths();
+ }
+
+ void mapVirtualFile(StringRef FilePath, StringRef Content) override {
+ Tool.mapVirtualFile(FilePath, Content);
+ }
+
+ /// \brief Returns the file manager used in the tool.
+ ///
+ /// The file manager is shared between all translation units.
+ FileManager &getFiles() { return Tool.getFiles(); }
+
+private:
+ // Used to store the parser when the executor is initialized with parser.
+ llvm::Optional<CommonOptionsParser> OptionsParser;
+ // FIXME: The standalone executor is currently just a wrapper of `ClangTool`.
+ // Merge `ClangTool` implementation into the this.
+ ClangTool Tool;
+ ExecutionContext Context;
+ InMemoryToolResults Results;
+ ArgumentsAdjuster ArgsAdjuster;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H
diff --git a/include/clang/Tooling/ToolExecutorPluginRegistry.h b/include/clang/Tooling/ToolExecutorPluginRegistry.h
new file mode 100644
index 0000000000..11ba89546e
--- /dev/null
+++ b/include/clang/Tooling/ToolExecutorPluginRegistry.h
@@ -0,0 +1,24 @@
+//===--- ToolExecutorPluginRegistry.h - -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
+#define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
+
+#include "clang/Tooling/Execution.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace tooling {
+
+typedef llvm::Registry<ToolExecutorPlugin> ToolExecutorPluginRegistry;
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index 10e26ac25d..e64be07d9a 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -31,12 +31,12 @@
#define LLVM_CLANG_TOOLING_TOOLING_H
#include "clang/AST/ASTConsumer.h"
-#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
#include "clang/Driver/Util.h"
#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CompilationDatabase.h"
@@ -116,7 +116,7 @@ public:
/// \brief Called before a source file is processed by a FrontEndAction.
/// \see clang::FrontendAction::BeginSourceFileAction
- virtual bool handleBeginSource(CompilerInstance &CI, StringRef Filename) {
+ virtual bool handleBeginSource(CompilerInstance &CI) {
return true;
}
@@ -202,12 +202,15 @@ buildASTFromCode(const Twine &Code, const Twine &FileName = "input.cc",
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
/// clang modules.
///
+/// \param Adjuster A function to filter the command line arguments as specified.
+///
/// \return The resulting AST or null if an error occurred.
std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
const Twine &Code, const std::vector<std::string> &Args,
const Twine &FileName = "input.cc", const Twine &ToolName = "clang-tool",
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
- std::make_shared<PCHContainerOperations>());
+ std::make_shared<PCHContainerOperations>(),
+ ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster());
/// \brief Utility to run a FrontendAction in a single clang invocation.
class ToolInvocation {
@@ -334,7 +337,9 @@ class ClangTool {
/// The file manager is shared between all translation units.
FileManager &getFiles() { return *Files; }
- private:
+ llvm::ArrayRef<std::string> getSourcePaths() const { return SourcePaths; }
+
+private:
const CompilationDatabase &Compilations;
std::vector<std::string> SourcePaths;
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
@@ -388,12 +393,11 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
}
protected:
- bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) override {
- if (!clang::ASTFrontendAction::BeginSourceFileAction(CI, Filename))
+ bool BeginSourceFileAction(CompilerInstance &CI) override {
+ if (!clang::ASTFrontendAction::BeginSourceFileAction(CI))
return false;
if (Callbacks)
- return Callbacks->handleBeginSource(CI, Filename);
+ return Callbacks->handleBeginSource(CI);
return true;
}
void EndSourceFileAction() override {
diff --git a/include/clang/module.modulemap b/include/clang/module.modulemap
index 3b42381100..41cf73d910 100644
--- a/include/clang/module.modulemap
+++ b/include/clang/module.modulemap
@@ -33,6 +33,7 @@ module Clang_Basic {
textual header "Basic/BuiltinsLe64.def"
textual header "Basic/BuiltinsMips.def"
textual header "Basic/BuiltinsNEON.def"
+ textual header "Basic/BuiltinsNios2.def"
textual header "Basic/BuiltinsNVPTX.def"
textual header "Basic/BuiltinsPPC.def"
textual header "Basic/BuiltinsSystemZ.def"
@@ -68,9 +69,9 @@ module Clang_Diagnostics {
module Frontend { header "Frontend/FrontendDiagnostic.h" export * }
module Lex { header "Lex/LexDiagnostic.h" export * }
module Parse { header "Parse/ParseDiagnostic.h" export * }
- // FIXME: This breaks the build of Clang_Sema, for unknown reasons.
- //module Sema { header "Sema/SemaDiagnostic.h" export * }
+ module Sema { header "Sema/SemaDiagnostic.h" export * }
module Serialization { header "Serialization/SerializationDiagnostic.h" export * }
+ module Refactoring { header "Tooling/Refactoring/RefactoringDiagnostic.h" export * }
}
module Clang_Driver {
@@ -89,7 +90,6 @@ module Clang_Frontend {
requires cplusplus
umbrella "Frontend"
- textual header "Frontend/CodeGenOptions.def"
textual header "Frontend/LangStandards.def"
module * { export * }
@@ -98,11 +98,20 @@ module Clang_Frontend {
exclude header "Frontend/PCHContainerOperations.h"
}
+// Used in clangBasic
+module Clang_Frontend_CodeGenOptions {
+ requires cplusplus
+ header "Frontend/CodeGenOptions.h"
+ textual header "Frontend/CodeGenOptions.def"
+ export *
+}
+
module Clang_FrontendTool { requires cplusplus umbrella "FrontendTool" module * { export * } }
module Clang_Index { requires cplusplus umbrella "Index" module * { export * } }
module Clang_Lex { requires cplusplus umbrella "Lex" module * { export * } }
module Clang_Parse { requires cplusplus umbrella "Parse" module * { export * } }
-module Clang_Rewrite { requires cplusplus umbrella "Rewrite" module * { export * } }
+module Clang_Rewrite { requires cplusplus umbrella "Rewrite/Core" module * { export * } }
+module Clang_RewriteFrontend { requires cplusplus umbrella "Rewrite/Frontend" module * { export * } }
module Clang_Sema { requires cplusplus umbrella "Sema" module * { export * } }
module Clang_Serialization { requires cplusplus umbrella "Serialization" module * { export * } }
@@ -132,9 +141,14 @@ module Clang_StaticAnalyzer_Frontend {
module Clang_Tooling {
requires cplusplus umbrella "Tooling" module * { export * }
- // FIXME: Exclude this header to avoid pulling all of the AST matchers
+ // FIXME: Exclude these headers to avoid pulling all of the AST matchers
// library into clang-format. Due to inline key functions in the headers,
// importing the AST matchers library gives a link dependency on the AST
// matchers (and thus the AST), which clang-format should not have.
exclude header "Tooling/RefactoringCallbacks.h"
}
+
+module Clang_ToolingCore {
+ requires cplusplus
+ umbrella "Tooling/Core" module * { export * }
+}
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 241a7246b6..fcc67da1f7 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -2189,7 +2189,7 @@ static std::string applyEditsToTemp(const FileEntry *FE,
Rewriter rewriter(SM, LangOpts);
RewritesReceiver Rec(rewriter);
- Editor.applyRewrites(Rec);
+ Editor.applyRewrites(Rec, /*adjustRemovals=*/false);
const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
SmallString<512> NewText;
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index f81133f3aa..389f3655aa 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -78,6 +78,7 @@ public:
}
}
// Pass through.
+ LLVM_FALLTHROUGH;
case OMF_retain:
case OMF_release:
if (E->getReceiverKind() == ObjCMessageExpr::Instance)
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index c628b54ed4..4f3fb58459 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -539,6 +539,7 @@ void TransformActionsImpl::addRemoval(CharSourceRange range) {
return;
case Range_Contains:
RI->End = newRange.End;
+ LLVM_FALLTHROUGH;
case Range_ExtendsBegin:
newRange.End = RI->End;
Removals.erase(RI);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index e8f98929de..87d096dab0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -57,7 +57,7 @@ unsigned ASTContext::NumImplicitDestructors;
unsigned ASTContext::NumImplicitDestructorsDeclared;
enum FloatingRank {
- HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
+ Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
};
RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
@@ -697,15 +697,17 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
llvm_unreachable("Invalid CXXABI type!");
}
-static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
- const LangOptions &LOpts) {
+static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
+ const LangOptions &LOpts) {
if (LOpts.FakeAddressSpaceMap) {
// 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
+ 0, // opencl_private
4, // opencl_generic
5, // cuda_device
6, // cuda_constant
@@ -748,6 +750,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr),
TypePackElementDecl(nullptr), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
+ XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
+ LangOpts.XRayNeverInstrumentFiles, SM)),
AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr),
PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(nullptr),
@@ -891,7 +895,7 @@ void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M,
if (getLangOpts().ModulesLocalVisibility)
MergedDefModules[ND].push_back(M);
else
- ND->setHidden(false);
+ ND->setVisibleDespiteOwningModule();
}
void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) {
@@ -1090,6 +1094,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
// GNU extension, __float128 for IEEE quadruple precision
InitBuiltinType(Float128Ty, BuiltinType::Float128);
+ // C11 extension ISO/IEC TS 18661-3
+ InitBuiltinType(Float16Ty, BuiltinType::Float16);
+
// GNU extension, 128-bit integers.
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
@@ -1179,7 +1186,14 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
ObjCSuperType = QualType();
// void * type
- VoidPtrTy = getPointerType(VoidTy);
+ if (LangOpts.OpenCLVersion >= 200) {
+ auto Q = VoidTy.getQualifiers();
+ Q.setAddressSpace(LangAS::opencl_generic);
+ VoidPtrTy = getPointerType(getCanonicalType(
+ getQualifiedType(VoidTy.getUnqualifiedType(), Q)));
+ } else {
+ VoidPtrTy = getPointerType(VoidTy);
+ }
// nullptr type (C++0x 2.14.7)
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
@@ -1410,7 +1424,9 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
assert(BT && "Not a floating point type!");
switch (BT->getKind()) {
default: llvm_unreachable("Not a floating point type!");
- case BuiltinType::Half: return Target->getHalfFormat();
+ case BuiltinType::Float16:
+ case BuiltinType::Half:
+ return Target->getHalfFormat();
case BuiltinType::Float: return Target->getFloatFormat();
case BuiltinType::Double: return Target->getDoubleFormat();
case BuiltinType::LongDouble: return Target->getLongDoubleFormat();
@@ -1621,6 +1637,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
uint64_t Width = 0;
unsigned Align = 8;
bool AlignIsRequired = false;
+ unsigned AS = 0;
switch (T->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1737,6 +1754,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Width = 128;
Align = 128; // int128_t is 128-bit aligned on all targets.
break;
+ case BuiltinType::Float16:
case BuiltinType::Half:
Width = Target->getHalfWidth();
Align = Target->getHalfAlign();
@@ -1767,28 +1785,18 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(0);
Align = Target->getPointerAlign(0);
break;
- case BuiltinType::OCLSampler: {
- auto AS = getTargetAddressSpace(LangAS::opencl_constant);
- Width = Target->getPointerWidth(AS);
- Align = Target->getPointerAlign(AS);
- break;
- }
+ case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
- // Currently these types are pointers to opaque types.
- Width = Target->getPointerWidth(0);
- Align = Target->getPointerAlign(0);
- break;
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLImageTypes.def"
- {
- auto AS = getTargetAddressSpace(Target->getOpenCLImageAddrSpace());
- Width = Target->getPointerWidth(AS);
- Align = Target->getPointerAlign(AS);
- }
+ AS = getTargetAddressSpace(Target->getOpenCLTypeAddrSpace(T));
+ Width = Target->getPointerWidth(AS);
+ Align = Target->getPointerAlign(AS);
+ break;
}
break;
case Type::ObjCObjectPointer:
@@ -1796,8 +1804,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Align = Target->getPointerAlign(0);
break;
case Type::BlockPointer: {
- unsigned AS = getTargetAddressSpace(
- cast<BlockPointerType>(T)->getPointeeType());
+ AS = getTargetAddressSpace(cast<BlockPointerType>(T)->getPointeeType());
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -1806,14 +1813,13 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::RValueReference: {
// alignof and sizeof should never enter this code path here, so we go
// the pointer route.
- unsigned AS = getTargetAddressSpace(
- cast<ReferenceType>(T)->getPointeeType());
+ AS = getTargetAddressSpace(cast<ReferenceType>(T)->getPointeeType());
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
}
case Type::Pointer: {
- unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
+ AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -1936,9 +1942,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
break;
case Type::Pipe: {
- TypeInfo Info = getTypeInfo(cast<PipeType>(T)->getElementType());
- Width = Info.Width;
- Align = Info.Align;
+ Width = Target->getPointerWidth(getTargetAddressSpace(LangAS::opencl_global));
+ Align = Target->getPointerAlign(getTargetAddressSpace(LangAS::opencl_global));
}
}
@@ -2278,8 +2283,8 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
return QualType(eq, fastQuals);
}
-QualType
-ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const {
+QualType ASTContext::getAddrSpaceQualType(QualType T,
+ LangAS AddressSpace) const {
QualType CanT = getCanonicalType(T);
if (CanT.getAddressSpace() == AddressSpace)
return T;
@@ -2298,6 +2303,27 @@ ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const {
return getExtQualType(TypeNode, Quals);
}
+QualType ASTContext::removeAddrSpaceQualType(QualType T) const {
+ // If we are composing extended qualifiers together, merge together
+ // into one ExtQuals node.
+ QualifierCollector Quals;
+ const Type *TypeNode = Quals.strip(T);
+
+ // If the qualifier doesn't have an address space just return it.
+ if (!Quals.hasAddressSpace())
+ return T;
+
+ Quals.removeAddressSpace();
+
+ // Removal of the address space can mean there are no longer any
+ // non-fast qualifiers, so creating an ExtQualType isn't possible (asserts)
+ // or required.
+ if (Quals.hasNonFastQualifiers())
+ return getExtQualType(TypeNode, Quals);
+ else
+ return QualType(TypeNode, Quals.getFastQualifiers());
+}
+
QualType ASTContext::getObjCGCQualType(QualType T,
Qualifiers::GC GCAttr) const {
QualType CanT = getCanonicalType(T);
@@ -2692,8 +2718,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);
@@ -2749,6 +2774,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::Vector:
case Type::ExtVector:
case Type::DependentSizedExtVector:
+ case Type::DependentAddressSpace:
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
@@ -3097,6 +3123,41 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
return QualType(New, 0);
}
+QualType ASTContext::getDependentAddressSpaceType(QualType PointeeType,
+ Expr *AddrSpaceExpr,
+ SourceLocation AttrLoc) const {
+ assert(AddrSpaceExpr->isInstantiationDependent());
+
+ QualType canonPointeeType = getCanonicalType(PointeeType);
+
+ void *insertPos = nullptr;
+ llvm::FoldingSetNodeID ID;
+ DependentAddressSpaceType::Profile(ID, *this, canonPointeeType,
+ AddrSpaceExpr);
+
+ DependentAddressSpaceType *canonTy =
+ DependentAddressSpaceTypes.FindNodeOrInsertPos(ID, insertPos);
+
+ if (!canonTy) {
+ canonTy = new (*this, TypeAlignment)
+ DependentAddressSpaceType(*this, canonPointeeType,
+ QualType(), AddrSpaceExpr, AttrLoc);
+ DependentAddressSpaceTypes.InsertNode(canonTy, insertPos);
+ Types.push_back(canonTy);
+ }
+
+ if (canonPointeeType == PointeeType &&
+ canonTy->getAddrSpaceExpr() == AddrSpaceExpr)
+ return QualType(canonTy, 0);
+
+ DependentAddressSpaceType *sugaredType
+ = new (*this, TypeAlignment)
+ DependentAddressSpaceType(*this, PointeeType, QualType(canonTy, 0),
+ AddrSpaceExpr, AttrLoc);
+ Types.push_back(sugaredType);
+ return QualType(sugaredType, 0);
+}
+
/// \brief Determine whether \p T is canonical as the result type of a function.
static bool isCanonicalResultType(QualType T) {
return T.isCanonical() &&
@@ -3564,7 +3625,7 @@ QualType ASTContext::getSubstTemplateTypeParmPackType(
= new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
ArgPack);
Types.push_back(SubstParm);
- SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
+ SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos);
return QualType(SubstParm, 0);
}
@@ -4524,6 +4585,12 @@ CanQualType ASTContext::getSizeType() const {
return getFromTargetType(Target->getSizeType());
}
+/// Return the unique signed counterpart of the integer type
+/// corresponding to size_t.
+CanQualType ASTContext::getSignedSizeType() const {
+ return getFromTargetType(Target->getSignedSizeType());
+}
+
/// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5).
CanQualType ASTContext::getIntMaxType() const {
return getFromTargetType(Target->getIntMaxType());
@@ -4562,6 +4629,13 @@ QualType ASTContext::getPointerDiffType() const {
return getFromTargetType(Target->getPtrDiffType(0));
}
+/// \brief Return the unique unsigned counterpart of "ptrdiff_t"
+/// integer type. The standard (C11 7.21.6.1p7) refers to this type
+/// in the definition of %tu format specifier.
+QualType ASTContext::getUnsignedPointerDiffType() const {
+ return getFromTargetType(Target->getUnsignedPtrDiffType(0));
+}
+
/// \brief Return the unique type for "pid_t" defined in
/// <sys/types.h>. We need this to compute the correct type for vfork().
QualType ASTContext::getProcessIDType() const {
@@ -5044,6 +5118,7 @@ static FloatingRank getFloatingRank(QualType T) {
assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type");
switch (T->getAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("getFloatingRank(): not a floating type");
+ case BuiltinType::Float16: return Float16Rank;
case BuiltinType::Half: return HalfRank;
case BuiltinType::Float: return FloatRank;
case BuiltinType::Double: return DoubleRank;
@@ -5061,6 +5136,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
FloatingRank EltRank = getFloatingRank(Size);
if (Domain->isComplexType()) {
switch (EltRank) {
+ case Float16Rank:
case HalfRank: llvm_unreachable("Complex half is not supported");
case FloatRank: return FloatComplexTy;
case DoubleRank: return DoubleComplexTy;
@@ -5071,6 +5147,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
assert(Domain->isRealFloatingType() && "Unknown domain!");
switch (EltRank) {
+ case Float16Rank: return HalfTy;
case HalfRank: return HalfTy;
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
@@ -5558,14 +5635,14 @@ ASTContext::getInlineVariableDefinitionKind(const VarDecl *VD) const {
// In almost all cases, it's a weak definition.
auto *First = VD->getFirstDecl();
- if (!First->isConstexpr() || First->isInlineSpecified() ||
- !VD->isStaticDataMember())
+ if (First->isInlineSpecified() || !First->isStaticDataMember())
return InlineVariableDefinitionKind::Weak;
// If there's a file-context declaration in this translation unit, it's a
// non-discardable definition.
for (auto *D : VD->redecls())
- if (D->getLexicalDeclContext()->isFileContext())
+ if (D->getLexicalDeclContext()->isFileContext() &&
+ !D->isInlineSpecified() && (D->isConstexpr() || First->isConstexpr()))
return InlineVariableDefinitionKind::Strong;
// If we've not seen one yet, we don't know.
@@ -5595,7 +5672,6 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
- SourceLocation Loc;
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
CharUnits ParmOffset = PtrSize;
for (auto PI : Decl->parameters()) {
@@ -5703,7 +5779,6 @@ std::string ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
- SourceLocation Loc;
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
// The first two arguments (self and _cmd) are pointers; account for
// their size.
@@ -5928,6 +6003,7 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
case BuiltinType::LongDouble: return 'D';
case BuiltinType::NullPtr: return '*'; // like char*
+ case BuiltinType::Float16:
case BuiltinType::Float128:
case BuiltinType::Half:
// FIXME: potentially need @encodes for these!
@@ -5989,9 +6065,19 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
// compatibility with GCC, although providing it breaks anything that
// actually uses runtime introspection and wants to work on both runtimes...
if (Ctx->getLangOpts().ObjCRuntime.isGNUFamily()) {
- const RecordDecl *RD = FD->getParent();
- const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD);
- S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
+ uint64_t Offset;
+
+ if (const auto *IVD = dyn_cast<ObjCIvarDecl>(FD)) {
+ Offset = Ctx->lookupFieldBitOffset(IVD->getContainingInterface(), nullptr,
+ IVD);
+ } else {
+ const RecordDecl *RD = FD->getParent();
+ const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD);
+ Offset = RL.getFieldOffset(FD->getFieldIndex());
+ }
+
+ S += llvm::utostr(Offset);
+
if (const EnumType *ET = T->getAs<EnumType>())
S += ObjCEncodingForEnumType(Ctx, ET);
else {
@@ -6238,6 +6324,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += "{objc_class=}";
return;
}
+ // TODO: Double check to make sure this intentially falls through.
+ LLVM_FALLTHROUGH;
}
case Type::ObjCInterface: {
@@ -7916,6 +8004,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
return QualType();
+ if (lbaseInfo.getNoCallerSavedRegs() != rbaseInfo.getNoCallerSavedRegs())
+ return QualType();
// FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
@@ -7941,9 +8031,17 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lproto->getTypeQuals() != rproto->getTypeQuals())
return QualType();
- if (!doFunctionTypesMatchOnExtParameterInfos(rproto, lproto))
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> newParamInfos;
+ bool canUseLeft, canUseRight;
+ if (!mergeExtParameterInfo(lproto, rproto, canUseLeft, canUseRight,
+ newParamInfos))
return QualType();
+ if (!canUseLeft)
+ allLTypes = false;
+ if (!canUseRight)
+ allRTypes = false;
+
// Check parameter type compatibility
SmallVector<QualType, 10> types;
for (unsigned i = 0, n = lproto->getNumParams(); i < n; i++) {
@@ -7974,6 +8072,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo();
EPI.ExtInfo = einfo;
+ EPI.ExtParameterInfos =
+ newParamInfos.empty() ? nullptr : newParamInfos.data();
return getFunctionType(retType, types, EPI);
}
@@ -8333,26 +8433,50 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
llvm_unreachable("Invalid Type::Class!");
}
-bool ASTContext::doFunctionTypesMatchOnExtParameterInfos(
- const FunctionProtoType *firstFnType,
- const FunctionProtoType *secondFnType) {
+bool ASTContext::mergeExtParameterInfo(
+ const FunctionProtoType *FirstFnType, const FunctionProtoType *SecondFnType,
+ bool &CanUseFirst, bool &CanUseSecond,
+ SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &NewParamInfos) {
+ assert(NewParamInfos.empty() && "param info list not empty");
+ CanUseFirst = CanUseSecond = true;
+ bool FirstHasInfo = FirstFnType->hasExtParameterInfos();
+ bool SecondHasInfo = SecondFnType->hasExtParameterInfos();
+
// Fast path: if the first type doesn't have ext parameter infos,
- // we match if and only if they second type also doesn't have them.
- if (!firstFnType->hasExtParameterInfos())
- return !secondFnType->hasExtParameterInfos();
+ // we match if and only if the second type also doesn't have them.
+ if (!FirstHasInfo && !SecondHasInfo)
+ return true;
- // Otherwise, we can only match if the second type has them.
- if (!secondFnType->hasExtParameterInfos())
- return false;
+ bool NeedParamInfo = false;
+ size_t E = FirstHasInfo ? FirstFnType->getExtParameterInfos().size()
+ : SecondFnType->getExtParameterInfos().size();
- auto firstEPI = firstFnType->getExtParameterInfos();
- auto secondEPI = secondFnType->getExtParameterInfos();
- assert(firstEPI.size() == secondEPI.size());
+ for (size_t I = 0; I < E; ++I) {
+ FunctionProtoType::ExtParameterInfo FirstParam, SecondParam;
+ if (FirstHasInfo)
+ FirstParam = FirstFnType->getExtParameterInfo(I);
+ if (SecondHasInfo)
+ SecondParam = SecondFnType->getExtParameterInfo(I);
- for (size_t i = 0, n = firstEPI.size(); i != n; ++i) {
- if (firstEPI[i] != secondEPI[i])
+ // Cannot merge unless everything except the noescape flag matches.
+ if (FirstParam.withIsNoEscape(false) != SecondParam.withIsNoEscape(false))
return false;
+
+ bool FirstNoEscape = FirstParam.isNoEscape();
+ bool SecondNoEscape = SecondParam.isNoEscape();
+ bool IsNoEscape = FirstNoEscape && SecondNoEscape;
+ NewParamInfos.push_back(FirstParam.withIsNoEscape(IsNoEscape));
+ if (NewParamInfos.back().getOpaqueValue())
+ NeedParamInfo = true;
+ if (FirstNoEscape != IsNoEscape)
+ CanUseFirst = false;
+ if (SecondNoEscape != IsNoEscape)
+ CanUseSecond = false;
}
+
+ if (!NeedParamInfo)
+ NewParamInfos.clear();
+
return true;
}
@@ -8509,6 +8633,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
// Read the prefixed modifiers first.
bool Done = false;
+ #ifndef NDEBUG
+ bool IsSpecialLong = false;
+ #endif
while (!Done) {
switch (*Str++) {
default: Done = true; --Str; break;
@@ -8526,12 +8653,28 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
Unsigned = true;
break;
case 'L':
+ assert(!IsSpecialLong && "Can't use 'L' with 'W' or 'N' modifiers");
assert(HowLong <= 2 && "Can't have LLLL modifier");
++HowLong;
break;
+ case 'N': {
+ // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise.
+ assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
+ assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!");
+ #ifndef NDEBUG
+ IsSpecialLong = true;
+ #endif
+ if (Context.getTargetInfo().getLongWidth() == 32)
+ ++HowLong;
+ break;
+ }
case 'W':
// This modifier represents int64 type.
+ assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!");
+ #ifndef NDEBUG
+ IsSpecialLong = true;
+ #endif
switch (Context.getTargetInfo().getInt64Type()) {
default:
llvm_unreachable("Unexpected integer type");
@@ -8542,6 +8685,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
HowLong = 2;
break;
}
+ break;
}
}
@@ -8726,7 +8870,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,
+ getLangASFromTargetAS(AddrSpace));
Str = End;
}
if (c == '*')
@@ -8870,7 +9015,7 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
}
static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context,
- GVALinkage L, const Decl *D) {
+ const Decl *D, GVALinkage L) {
// See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx
// dllexport/dllimport on inline functions.
if (D->hasAttr<DLLImportAttr>()) {
@@ -8889,25 +9034,37 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context,
return L;
}
-GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
- auto L = adjustGVALinkageForAttributes(
- *this, basicGVALinkageForFunction(*this, FD), FD);
- auto EK = ExternalASTSource::EK_ReplyHazy;
- if (auto *Ext = getExternalSource())
- EK = Ext->hasExternalDefinitions(FD->getOwningModuleID());
- switch (EK) {
+/// Adjust the GVALinkage for a declaration based on what an external AST source
+/// knows about whether there can be other definitions of this declaration.
+static GVALinkage
+adjustGVALinkageForExternalDefinitionKind(const ASTContext &Ctx, const Decl *D,
+ GVALinkage L) {
+ ExternalASTSource *Source = Ctx.getExternalSource();
+ if (!Source)
+ return L;
+
+ switch (Source->hasExternalDefinitions(D)) {
case ExternalASTSource::EK_Never:
+ // Other translation units rely on us to provide the definition.
if (L == GVA_DiscardableODR)
return GVA_StrongODR;
break;
+
case ExternalASTSource::EK_Always:
return GVA_AvailableExternally;
+
case ExternalASTSource::EK_ReplyHazy:
break;
}
return L;
}
+GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
+ return adjustGVALinkageForExternalDefinitionKind(*this, FD,
+ adjustGVALinkageForAttributes(*this, FD,
+ basicGVALinkageForFunction(*this, FD)));
+}
+
static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
const VarDecl *VD) {
if (!VD->isExternallyVisible())
@@ -8986,11 +9143,12 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
}
GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
- return adjustGVALinkageForAttributes(
- *this, basicGVALinkageForVariable(*this, VD), VD);
+ return adjustGVALinkageForExternalDefinitionKind(*this, VD,
+ adjustGVALinkageForAttributes(*this, VD,
+ basicGVALinkageForVariable(*this, VD)));
}
-bool ASTContext::DeclMustBeEmitted(const Decl *D, bool ForModularCodegen) {
+bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
@@ -9056,9 +9214,6 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D, bool ForModularCodegen) {
GVALinkage Linkage = GetGVALinkageForFunction(FD);
- if (Linkage == GVA_DiscardableODR && ForModularCodegen)
- return true;
-
// 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++.
@@ -9073,9 +9228,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D, bool ForModularCodegen) {
return false;
// Variables that can be needed in other TUs are required.
- if (!isDiscardableGVALinkage(GetGVALinkageForVariable(VD)))
+ auto Linkage = GetGVALinkageForVariable(VD);
+ if (!isDiscardableGVALinkage(Linkage))
return true;
+ // We never need to emit a variable that is available in another TU.
+ if (Linkage == GVA_AvailableExternally)
+ return false;
+
// Variables that have destruction with side-effects are required.
if (VD->getType().isDestructedType())
return true;
@@ -9109,7 +9269,7 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
case LangOptions::DCC_CDecl:
return CC_C;
case LangOptions::DCC_FastCall:
- if (getTargetInfo().hasFeature("sse2"))
+ if (getTargetInfo().hasFeature("sse2") && !IsVariadic)
return CC_X86FastCall;
break;
case LangOptions::DCC_StdCall:
@@ -9414,10 +9574,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) {
if (!NodeOrVector.template is<ASTContext::ParentVector *>()) {
auto *Vector = new ASTContext::ParentVector(
1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
- if (auto *Node =
- NodeOrVector
- .template dyn_cast<ast_type_traits::DynTypedNode *>())
- delete Node;
+ delete NodeOrVector
+ .template dyn_cast<ast_type_traits::DynTypedNode *>();
NodeOrVector = Vector;
}
@@ -9536,15 +9694,22 @@ ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
}
uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
- unsigned AS;
+ LangAS AS;
if (QT->getUnqualifiedDesugaredType()->isNullPtrType())
- AS = 0;
+ AS = LangAS::Default;
else
AS = QT->getPointeeType().getAddressSpace();
return getTargetInfo().getNullPointerValue(AS);
}
+unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
+ if (isTargetAddressSpace(AS))
+ return toTargetAddressSpace(AS);
+ else
+ return (*AddrSpaceMap)[(unsigned)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/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 03e6115a0d..b43c28deb3 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -360,6 +360,7 @@ void clang::FormatASTNodeDiagnosticArgument(
Modifier = StringRef();
Argument = StringRef();
// Fall through
+ LLVM_FALLTHROUGH;
}
case DiagnosticsEngine::ak_qualtype: {
assert(Modifier.empty() && Argument.empty() &&
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index ef491ab06f..e74aee0aaa 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -537,6 +537,7 @@ namespace {
void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node);
void VisitCXXThisExpr(const CXXThisExpr *Node);
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
+ void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *Node);
void VisitCXXConstructExpr(const CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
void VisitCXXNewExpr(const CXXNewExpr *Node);
@@ -1038,10 +1039,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
dumpSourceRange(D->getSourceRange());
OS << ' ';
dumpLocation(D->getLocation());
- if (Module *M = D->getImportedOwningModule())
+ if (D->isFromASTFile())
+ OS << " imported";
+ if (Module *M = D->getOwningModule())
OS << " in " << M->getFullModuleName();
- else if (Module *M = D->getLocalOwningModule())
- OS << " in (local) " << M->getFullModuleName();
if (auto *ND = dyn_cast<NamedDecl>(D))
for (Module *M : D->getASTContext().getModulesWithMergedDefinition(
const_cast<NamedDecl *>(ND)))
@@ -1184,6 +1185,30 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
I != E; ++I)
dumpCXXCtorInitializer(*I);
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (MD->size_overridden_methods() != 0) {
+ auto dumpOverride =
+ [=](const CXXMethodDecl *D) {
+ SplitQualType T_split = D->getType().split();
+ OS << D << " " << D->getParent()->getName() << "::"
+ << D->getNameAsString() << " '" << QualType::getAsString(T_split) << "'";
+ };
+
+ dumpChild([=] {
+ auto FirstOverrideItr = MD->begin_overridden_methods();
+ OS << "Overrides: [ ";
+ dumpOverride(*FirstOverrideItr);
+ for (const auto *Override :
+ llvm::make_range(FirstOverrideItr + 1,
+ MD->end_overridden_methods())) {
+ OS << ", ";
+ dumpOverride(Override);
+ }
+ OS << " ]";
+ });
+ }
+ }
+
if (D->doesThisDeclarationHaveABody())
dumpStmt(D->getBody());
}
@@ -1292,6 +1317,16 @@ void ASTDumper::VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) {
dumpStmt(D->getCombiner());
if (auto *Initializer = D->getInitializer()) {
OS << " initializer";
+ switch (D->getInitializerKind()) {
+ case OMPDeclareReductionDecl::DirectInit:
+ OS << " omp_priv = ";
+ break;
+ case OMPDeclareReductionDecl::CopyInit:
+ OS << " omp_priv ()";
+ break;
+ case OMPDeclareReductionDecl::CallInit:
+ break;
+ }
dumpStmt(Initializer);
}
}
@@ -1341,6 +1376,128 @@ void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
if (!D->isCompleteDefinition())
return;
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << "DefinitionData";
+ }
+#define FLAG(fn, name) if (D->fn()) OS << " " #name;
+ FLAG(isParsingBaseSpecifiers, parsing_base_specifiers);
+
+ FLAG(isGenericLambda, generic);
+ FLAG(isLambda, lambda);
+
+ FLAG(canPassInRegisters, pass_in_registers);
+ FLAG(isEmpty, empty);
+ FLAG(isAggregate, aggregate);
+ FLAG(isStandardLayout, standard_layout);
+ FLAG(isTriviallyCopyable, trivially_copyable);
+ FLAG(isPOD, pod);
+ FLAG(isTrivial, trivial);
+ FLAG(isPolymorphic, polymorphic);
+ FLAG(isAbstract, abstract);
+ FLAG(isLiteral, literal);
+
+ FLAG(hasUserDeclaredConstructor, has_user_declared_ctor);
+ FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor);
+ FLAG(hasMutableFields, has_mutable_fields);
+ FLAG(hasVariantMembers, has_variant_members);
+ FLAG(allowConstDefaultInit, can_const_default_init);
+
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << "DefaultConstructor";
+ }
+ FLAG(hasDefaultConstructor, exists);
+ FLAG(hasTrivialDefaultConstructor, trivial);
+ FLAG(hasNonTrivialDefaultConstructor, non_trivial);
+ FLAG(hasUserProvidedDefaultConstructor, user_provided);
+ FLAG(hasConstexprDefaultConstructor, constexpr);
+ FLAG(needsImplicitDefaultConstructor, needs_implicit);
+ FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr);
+ });
+
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << "CopyConstructor";
+ }
+ FLAG(hasSimpleCopyConstructor, simple);
+ FLAG(hasTrivialCopyConstructor, trivial);
+ FLAG(hasNonTrivialCopyConstructor, non_trivial);
+ FLAG(hasUserDeclaredCopyConstructor, user_declared);
+ FLAG(hasCopyConstructorWithConstParam, has_const_param);
+ FLAG(needsImplicitCopyConstructor, needs_implicit);
+ FLAG(needsOverloadResolutionForCopyConstructor,
+ needs_overload_resolution);
+ if (!D->needsOverloadResolutionForCopyConstructor())
+ FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted);
+ FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param);
+ });
+
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << "MoveConstructor";
+ }
+ FLAG(hasMoveConstructor, exists);
+ FLAG(hasSimpleMoveConstructor, simple);
+ FLAG(hasTrivialMoveConstructor, trivial);
+ FLAG(hasNonTrivialMoveConstructor, non_trivial);
+ FLAG(hasUserDeclaredMoveConstructor, user_declared);
+ FLAG(needsImplicitMoveConstructor, needs_implicit);
+ FLAG(needsOverloadResolutionForMoveConstructor,
+ needs_overload_resolution);
+ if (!D->needsOverloadResolutionForMoveConstructor())
+ FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted);
+ });
+
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << "CopyAssignment";
+ }
+ FLAG(hasTrivialCopyAssignment, trivial);
+ FLAG(hasNonTrivialCopyAssignment, non_trivial);
+ FLAG(hasCopyAssignmentWithConstParam, has_const_param);
+ FLAG(hasUserDeclaredCopyAssignment, user_declared);
+ FLAG(needsImplicitCopyAssignment, needs_implicit);
+ FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution);
+ FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param);
+ });
+
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << "MoveAssignment";
+ }
+ FLAG(hasMoveAssignment, exists);
+ FLAG(hasSimpleMoveAssignment, simple);
+ FLAG(hasTrivialMoveAssignment, trivial);
+ FLAG(hasNonTrivialMoveAssignment, non_trivial);
+ FLAG(hasUserDeclaredMoveAssignment, user_declared);
+ FLAG(needsImplicitMoveAssignment, needs_implicit);
+ FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution);
+ });
+
+ dumpChild([=] {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << "Destructor";
+ }
+ FLAG(hasSimpleDestructor, simple);
+ FLAG(hasIrrelevantDestructor, irrelevant);
+ FLAG(hasTrivialDestructor, trivial);
+ FLAG(hasNonTrivialDestructor, non_trivial);
+ FLAG(hasUserDeclaredDestructor, user_declared);
+ FLAG(needsImplicitDestructor, needs_implicit);
+ FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
+ if (!D->needsOverloadResolutionForDestructor())
+ FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted);
+ });
+ });
+
for (const auto &I : D->bases()) {
dumpChild([=] {
if (I.isVirtual())
@@ -2145,12 +2302,24 @@ void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) {
<< " <" << Node->getCastKindName() << ">";
}
+void ASTDumper::VisitCXXUnresolvedConstructExpr(
+ const CXXUnresolvedConstructExpr *Node) {
+ VisitExpr(Node);
+ dumpType(Node->getTypeAsWritten());
+ if (Node->isListInitialization())
+ OS << " list";
+}
+
void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) {
VisitExpr(Node);
CXXConstructorDecl *Ctor = Node->getConstructor();
dumpType(Ctor->getType());
if (Node->isElidable())
OS << " elidable";
+ if (Node->isListInitialization())
+ OS << " list";
+ if (Node->isStdInitListInitialization())
+ OS << " std::initializer_list";
if (Node->requiresZeroInitialization())
OS << " zeroing";
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 2a7768a424..c92647770e 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTImporter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
@@ -318,1399 +319,18 @@ namespace clang {
bool ImportArrayChecked(const InContainerTy &InContainer, OIter Obegin) {
return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin);
}
- };
-}
-
-using namespace clang;
-
-//----------------------------------------------------------------------------
-// Structural Equivalence
-//----------------------------------------------------------------------------
-namespace {
- struct StructuralEquivalenceContext {
- /// \brief AST contexts for which we are checking structural equivalence.
- ASTContext &C1, &C2;
-
- /// \brief The set of "tentative" equivalences between two canonical
- /// declarations, mapping from a declaration in the first context to the
- /// declaration in the second context that we believe to be equivalent.
- llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
-
- /// \brief Queue of declarations in the first context whose equivalence
- /// with a declaration in the second context still needs to be verified.
- std::deque<Decl *> DeclsToCheck;
-
- /// \brief Declaration (from, to) pairs that are known not to be equivalent
- /// (which we have already complained about).
- llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls;
-
- /// \brief Whether we're being strict about the spelling of types when
- /// unifying two types.
- bool StrictTypeSpelling;
-
- /// \brief Whether to complain about failures.
- bool Complain;
-
- /// \brief \c true if the last diagnostic came from C2.
- bool LastDiagFromC2;
-
- StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
- llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
- bool StrictTypeSpelling = false,
- bool Complain = true)
- : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls),
- StrictTypeSpelling(StrictTypeSpelling), Complain(Complain),
- LastDiagFromC2(false) {}
-
- /// \brief Determine whether the two declarations are structurally
- /// equivalent.
- bool IsStructurallyEquivalent(Decl *D1, Decl *D2);
-
- /// \brief Determine whether the two types are structurally equivalent.
- bool IsStructurallyEquivalent(QualType T1, QualType T2);
-
- private:
- /// \brief Finish checking all of the structural equivalences.
- ///
- /// \returns true if an error occurred, false otherwise.
- bool Finish();
-
- public:
- DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
- assert(Complain && "Not allowed to complain");
- if (LastDiagFromC2)
- C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics());
- LastDiagFromC2 = false;
- return C1.getDiagnostics().Report(Loc, DiagID);
- }
-
- DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
- assert(Complain && "Not allowed to complain");
- if (!LastDiagFromC2)
- C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics());
- LastDiagFromC2 = true;
- return C2.getDiagnostics().Report(Loc, DiagID);
- }
+ // Importing overrides.
+ void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
};
}
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- QualType T1, QualType T2);
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Decl *D1, Decl *D2);
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const TemplateArgument &Arg1,
- const TemplateArgument &Arg2);
-
-/// \brief Determine structural equivalence of two expressions.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Expr *E1, Expr *E2) {
- if (!E1 || !E2)
- return E1 == E2;
-
- // FIXME: Actually perform a structural comparison!
- return true;
-}
-
-/// \brief Determine whether two identifiers are equivalent.
-static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
- const IdentifierInfo *Name2) {
- if (!Name1 || !Name2)
- return Name1 == Name2;
-
- return Name1->getName() == Name2->getName();
-}
-
-/// \brief Determine whether two nested-name-specifiers are equivalent.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NestedNameSpecifier *NNS1,
- NestedNameSpecifier *NNS2) {
- 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.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const TemplateArgument &Arg1,
- const TemplateArgument &Arg2) {
- if (Arg1.getKind() != Arg2.getKind())
- return false;
-
- switch (Arg1.getKind()) {
- case TemplateArgument::Null:
- return true;
-
- case TemplateArgument::Type:
- return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType());
-
- case TemplateArgument::Integral:
- if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(),
- Arg2.getIntegralType()))
- return false;
-
- return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral());
-
- case TemplateArgument::Declaration:
- return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
-
- case TemplateArgument::NullPtr:
- return true; // FIXME: Is this correct?
-
- case TemplateArgument::Template:
- return IsStructurallyEquivalent(Context,
- Arg1.getAsTemplate(),
- Arg2.getAsTemplate());
-
- case TemplateArgument::TemplateExpansion:
- return IsStructurallyEquivalent(Context,
- Arg1.getAsTemplateOrTemplatePattern(),
- Arg2.getAsTemplateOrTemplatePattern());
-
- case TemplateArgument::Expression:
- return IsStructurallyEquivalent(Context,
- Arg1.getAsExpr(), Arg2.getAsExpr());
-
- case TemplateArgument::Pack:
- if (Arg1.pack_size() != Arg2.pack_size())
- return false;
-
- for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context,
- Arg1.pack_begin()[I],
- Arg2.pack_begin()[I]))
- return false;
-
- return true;
- }
-
- llvm_unreachable("Invalid template argument kind");
-}
-
-/// \brief Determine structural equivalence for the common part of array
-/// types.
-static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const ArrayType *Array1,
- const ArrayType *Array2) {
- if (!IsStructurallyEquivalent(Context,
- Array1->getElementType(),
- Array2->getElementType()))
- return false;
- if (Array1->getSizeModifier() != Array2->getSizeModifier())
- return false;
- if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
- return false;
-
- return true;
-}
-
-/// \brief Determine structural equivalence of two types.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- QualType T1, QualType T2) {
- if (T1.isNull() || T2.isNull())
- return T1.isNull() && T2.isNull();
-
- if (!Context.StrictTypeSpelling) {
- // We aren't being strict about token-to-token equivalence of types,
- // so map down to the canonical type.
- T1 = Context.C1.getCanonicalType(T1);
- T2 = Context.C2.getCanonicalType(T2);
- }
-
- if (T1.getQualifiers() != T2.getQualifiers())
- return false;
-
- Type::TypeClass TC = T1->getTypeClass();
-
- if (T1->getTypeClass() != T2->getTypeClass()) {
- // Compare function types with prototypes vs. without prototypes as if
- // both did not have prototypes.
- if (T1->getTypeClass() == Type::FunctionProto &&
- T2->getTypeClass() == Type::FunctionNoProto)
- TC = Type::FunctionNoProto;
- else if (T1->getTypeClass() == Type::FunctionNoProto &&
- T2->getTypeClass() == Type::FunctionProto)
- TC = Type::FunctionNoProto;
- else
- return false;
- }
-
- switch (TC) {
- case Type::Builtin:
- // FIXME: Deal with Char_S/Char_U.
- if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
- return false;
- break;
-
- case Type::Complex:
- if (!IsStructurallyEquivalent(Context,
- cast<ComplexType>(T1)->getElementType(),
- cast<ComplexType>(T2)->getElementType()))
- return false;
- break;
-
- case Type::Adjusted:
- case Type::Decayed:
- if (!IsStructurallyEquivalent(Context,
- cast<AdjustedType>(T1)->getOriginalType(),
- cast<AdjustedType>(T2)->getOriginalType()))
- return false;
- break;
-
- case Type::Pointer:
- if (!IsStructurallyEquivalent(Context,
- cast<PointerType>(T1)->getPointeeType(),
- cast<PointerType>(T2)->getPointeeType()))
- return false;
- break;
-
- case Type::BlockPointer:
- if (!IsStructurallyEquivalent(Context,
- cast<BlockPointerType>(T1)->getPointeeType(),
- cast<BlockPointerType>(T2)->getPointeeType()))
- return false;
- break;
-
- case Type::LValueReference:
- case Type::RValueReference: {
- const ReferenceType *Ref1 = cast<ReferenceType>(T1);
- const ReferenceType *Ref2 = cast<ReferenceType>(T2);
- if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
- return false;
- if (Ref1->isInnerRef() != Ref2->isInnerRef())
- return false;
- if (!IsStructurallyEquivalent(Context,
- Ref1->getPointeeTypeAsWritten(),
- Ref2->getPointeeTypeAsWritten()))
- return false;
- break;
- }
-
- case Type::MemberPointer: {
- const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1);
- const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2);
- if (!IsStructurallyEquivalent(Context,
- MemPtr1->getPointeeType(),
- MemPtr2->getPointeeType()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- QualType(MemPtr1->getClass(), 0),
- QualType(MemPtr2->getClass(), 0)))
- return false;
- break;
- }
-
- case Type::ConstantArray: {
- const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1);
- const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2);
- if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
- return false;
-
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
- break;
- }
-
- case Type::IncompleteArray:
- if (!IsArrayStructurallyEquivalent(Context,
- cast<ArrayType>(T1),
- cast<ArrayType>(T2)))
- return false;
- break;
-
- case Type::VariableArray: {
- const VariableArrayType *Array1 = cast<VariableArrayType>(T1);
- const VariableArrayType *Array2 = cast<VariableArrayType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Array1->getSizeExpr(), Array2->getSizeExpr()))
- return false;
-
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
-
- break;
- }
-
- case Type::DependentSizedArray: {
- const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1);
- const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Array1->getSizeExpr(), Array2->getSizeExpr()))
- return false;
-
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
-
- break;
- }
-
- case Type::DependentSizedExtVector: {
- const DependentSizedExtVectorType *Vec1
- = cast<DependentSizedExtVectorType>(T1);
- const DependentSizedExtVectorType *Vec2
- = cast<DependentSizedExtVectorType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Vec1->getSizeExpr(), Vec2->getSizeExpr()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Vec1->getElementType(),
- Vec2->getElementType()))
- return false;
- break;
- }
-
- case Type::Vector:
- case Type::ExtVector: {
- const VectorType *Vec1 = cast<VectorType>(T1);
- const VectorType *Vec2 = cast<VectorType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Vec1->getElementType(),
- Vec2->getElementType()))
- return false;
- if (Vec1->getNumElements() != Vec2->getNumElements())
- return false;
- if (Vec1->getVectorKind() != Vec2->getVectorKind())
- return false;
- break;
- }
-
- case Type::FunctionProto: {
- const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1);
- const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2);
- if (Proto1->getNumParams() != Proto2->getNumParams())
- return false;
- for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
- Proto2->getParamType(I)))
- return false;
- }
- if (Proto1->isVariadic() != Proto2->isVariadic())
- return false;
- if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())
- return false;
- if (Proto1->getExceptionSpecType() == EST_Dynamic) {
- if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
- return false;
- for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Proto1->getExceptionType(I),
- Proto2->getExceptionType(I)))
- return false;
- }
- } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
- if (!IsStructurallyEquivalent(Context,
- Proto1->getNoexceptExpr(),
- Proto2->getNoexceptExpr()))
- return false;
- }
- if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
- return false;
-
- // Fall through to check the bits common with FunctionNoProtoType.
- }
-
- case Type::FunctionNoProto: {
- const FunctionType *Function1 = cast<FunctionType>(T1);
- const FunctionType *Function2 = cast<FunctionType>(T2);
- if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
- Function2->getReturnType()))
- return false;
- if (Function1->getExtInfo() != Function2->getExtInfo())
- return false;
- break;
- }
-
- case Type::UnresolvedUsing:
- if (!IsStructurallyEquivalent(Context,
- cast<UnresolvedUsingType>(T1)->getDecl(),
- cast<UnresolvedUsingType>(T2)->getDecl()))
- return false;
-
- break;
-
- case Type::Attributed:
- if (!IsStructurallyEquivalent(Context,
- cast<AttributedType>(T1)->getModifiedType(),
- cast<AttributedType>(T2)->getModifiedType()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- cast<AttributedType>(T1)->getEquivalentType(),
- cast<AttributedType>(T2)->getEquivalentType()))
- return false;
- break;
-
- case Type::Paren:
- if (!IsStructurallyEquivalent(Context,
- cast<ParenType>(T1)->getInnerType(),
- cast<ParenType>(T2)->getInnerType()))
- return false;
- break;
-
- case Type::Typedef:
- if (!IsStructurallyEquivalent(Context,
- cast<TypedefType>(T1)->getDecl(),
- cast<TypedefType>(T2)->getDecl()))
- return false;
- break;
-
- case Type::TypeOfExpr:
- if (!IsStructurallyEquivalent(Context,
- cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
- cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
- return false;
- break;
-
- case Type::TypeOf:
- if (!IsStructurallyEquivalent(Context,
- cast<TypeOfType>(T1)->getUnderlyingType(),
- cast<TypeOfType>(T2)->getUnderlyingType()))
- return false;
- break;
-
- case Type::UnaryTransform:
- if (!IsStructurallyEquivalent(Context,
- cast<UnaryTransformType>(T1)->getUnderlyingType(),
- cast<UnaryTransformType>(T1)->getUnderlyingType()))
- return false;
- break;
-
- case Type::Decltype:
- if (!IsStructurallyEquivalent(Context,
- cast<DecltypeType>(T1)->getUnderlyingExpr(),
- cast<DecltypeType>(T2)->getUnderlyingExpr()))
- return false;
- break;
-
- case Type::Auto:
- if (!IsStructurallyEquivalent(Context,
- cast<AutoType>(T1)->getDeducedType(),
- cast<AutoType>(T2)->getDeducedType()))
- return false;
- break;
-
- case Type::DeducedTemplateSpecialization: {
- auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
- auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context,
- DT1->getTemplateName(),
- DT2->getTemplateName()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- DT1->getDeducedType(),
- DT2->getDeducedType()))
- return false;
- break;
- }
-
- case Type::Record:
- case Type::Enum:
- if (!IsStructurallyEquivalent(Context,
- cast<TagType>(T1)->getDecl(),
- cast<TagType>(T2)->getDecl()))
- return false;
- break;
-
- case Type::TemplateTypeParm: {
- const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
- const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
- if (Parm1->getDepth() != Parm2->getDepth())
- return false;
- if (Parm1->getIndex() != Parm2->getIndex())
- return false;
- if (Parm1->isParameterPack() != Parm2->isParameterPack())
- return false;
-
- // Names of template type parameters are never significant.
- break;
- }
-
- case Type::SubstTemplateTypeParm: {
- const SubstTemplateTypeParmType *Subst1
- = cast<SubstTemplateTypeParmType>(T1);
- const SubstTemplateTypeParmType *Subst2
- = cast<SubstTemplateTypeParmType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Subst1->getReplacementType(),
- Subst2->getReplacementType()))
- return false;
- break;
- }
-
- case Type::SubstTemplateTypeParmPack: {
- const SubstTemplateTypeParmPackType *Subst1
- = cast<SubstTemplateTypeParmPackType>(T1);
- const SubstTemplateTypeParmPackType *Subst2
- = cast<SubstTemplateTypeParmPackType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Subst1->getArgumentPack(),
- Subst2->getArgumentPack()))
- return false;
- break;
- }
- case Type::TemplateSpecialization: {
- const TemplateSpecializationType *Spec1
- = cast<TemplateSpecializationType>(T1);
- const TemplateSpecializationType *Spec2
- = cast<TemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Spec1->getTemplateName(),
- Spec2->getTemplateName()))
- return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
- return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Spec1->getArg(I), Spec2->getArg(I)))
- return false;
- }
- break;
- }
-
- case Type::Elaborated: {
- const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
- const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
- // CHECKME: what if a keyword is ETK_None or ETK_typename ?
- if (Elab1->getKeyword() != Elab2->getKeyword())
- return false;
- if (!IsStructurallyEquivalent(Context,
- Elab1->getQualifier(),
- Elab2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Elab1->getNamedType(),
- Elab2->getNamedType()))
- return false;
- break;
- }
-
- case Type::InjectedClassName: {
- const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
- const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Inj1->getInjectedSpecializationType(),
- Inj2->getInjectedSpecializationType()))
- return false;
- break;
- }
-
- case Type::DependentName: {
- const DependentNameType *Typename1 = cast<DependentNameType>(T1);
- const DependentNameType *Typename2 = cast<DependentNameType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Typename1->getQualifier(),
- Typename2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
- Typename2->getIdentifier()))
- return false;
-
- break;
- }
-
- case Type::DependentTemplateSpecialization: {
- const DependentTemplateSpecializationType *Spec1 =
- cast<DependentTemplateSpecializationType>(T1);
- const DependentTemplateSpecializationType *Spec2 =
- cast<DependentTemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Spec1->getQualifier(),
- Spec2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
- Spec2->getIdentifier()))
- return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
- return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Spec1->getArg(I), Spec2->getArg(I)))
- return false;
- }
- break;
- }
-
- case Type::PackExpansion:
- if (!IsStructurallyEquivalent(Context,
- cast<PackExpansionType>(T1)->getPattern(),
- cast<PackExpansionType>(T2)->getPattern()))
- return false;
- break;
-
- case Type::ObjCInterface: {
- const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
- const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Iface1->getDecl(), Iface2->getDecl()))
- return false;
- break;
- }
-
- case Type::ObjCTypeParam: {
- const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1);
- const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2);
- if (!IsStructurallyEquivalent(Context, Obj1->getDecl(),
- Obj2->getDecl()))
- return false;
-
- if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
- return false;
- for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Obj1->getProtocol(I),
- Obj2->getProtocol(I)))
- return false;
- }
- break;
- }
- case Type::ObjCObject: {
- const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1);
- const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Obj1->getBaseType(),
- Obj2->getBaseType()))
- return false;
- if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
- return false;
- for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Obj1->getProtocol(I),
- Obj2->getProtocol(I)))
- return false;
- }
- break;
- }
-
- case Type::ObjCObjectPointer: {
- const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1);
- const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Ptr1->getPointeeType(),
- Ptr2->getPointeeType()))
- return false;
- break;
- }
-
- case Type::Atomic: {
- if (!IsStructurallyEquivalent(Context,
- cast<AtomicType>(T1)->getValueType(),
- cast<AtomicType>(T2)->getValueType()))
- return false;
- break;
- }
-
- case Type::Pipe: {
- if (!IsStructurallyEquivalent(Context,
- cast<PipeType>(T1)->getElementType(),
- cast<PipeType>(T2)->getElementType()))
- return false;
- break;
- }
-
- } // end switch
-
- return true;
-}
-
-/// \brief Determine structural equivalence of two fields.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FieldDecl *Field1, FieldDecl *Field2) {
- RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
-
- // For anonymous structs/unions, match up the anonymous struct/union type
- // declarations directly, so that we don't go off searching for anonymous
- // types
- if (Field1->isAnonymousStructOrUnion() &&
- Field2->isAnonymousStructOrUnion()) {
- RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
- RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
- return IsStructurallyEquivalent(Context, D1, D2);
- }
-
- // Check for equivalent field names.
- IdentifierInfo *Name1 = Field1->getIdentifier();
- IdentifierInfo *Name2 = Field2->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2))
- return false;
-
- if (!IsStructurallyEquivalent(Context,
- Field1->getType(), Field2->getType())) {
- if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- }
- return false;
- }
-
- if (Field1->isBitField() != Field2->isBitField()) {
- if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- if (Field1->isBitField()) {
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType()
- << Field1->getBitWidthValue(Context.C1);
- Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
- << Field2->getDeclName();
- } else {
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType()
- << Field2->getBitWidthValue(Context.C2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
- << Field1->getDeclName();
- }
- }
- return false;
- }
-
- if (Field1->isBitField()) {
- // Make sure that the bit-fields are the same length.
- unsigned Bits1 = Field1->getBitWidthValue(Context.C1);
- unsigned Bits2 = Field2->getBitWidthValue(Context.C2);
-
- if (Bits1 != Bits2) {
- if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType() << Bits2;
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType() << Bits1;
- }
- return false;
- }
- }
-
- return true;
-}
-
-/// \brief Find the index of the given anonymous struct/union within its
-/// context.
-///
-/// \returns Returns the index of this anonymous struct/union in its context,
-/// including the next assigned index (if none of them match). Returns an
-/// empty option if the context is not a record, i.e.. if the anonymous
-/// struct/union is at namespace or block scope.
-static Optional<unsigned> findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
- ASTContext &Context = Anon->getASTContext();
- QualType AnonTy = Context.getRecordType(Anon);
-
- RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
- if (!Owner)
- return None;
-
- unsigned Index = 0;
- for (const auto *D : Owner->noload_decls()) {
- const auto *F = dyn_cast<FieldDecl>(D);
- if (!F)
- continue;
-
- if (F->isAnonymousStructOrUnion()) {
- if (Context.hasSameType(F->getType(), AnonTy))
- break;
- ++Index;
- continue;
- }
-
- // If the field looks like this:
- // struct { ... } A;
- QualType FieldType = F->getType();
- if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
- const RecordDecl *RecDecl = RecType->getDecl();
- if (RecDecl->getDeclContext() == Owner &&
- !RecDecl->getIdentifier()) {
- if (Context.hasSameType(FieldType, AnonTy))
- break;
- ++Index;
- continue;
- }
- }
- }
-
- return Index;
-}
-
-/// \brief Determine structural equivalence of two records.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- RecordDecl *D1, RecordDecl *D2) {
- if (D1->isUnion() != D2->isUnion()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
- << D1->getDeclName() << (unsigned)D1->getTagKind();
- }
- return false;
- }
-
- if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
- // If both anonymous structs/unions are in a record context, make sure
- // they occur in the same location in the context records.
- if (Optional<unsigned> Index1 = findUntaggedStructOrUnionIndex(D1)) {
- if (Optional<unsigned> Index2 = findUntaggedStructOrUnionIndex(D2)) {
- if (*Index1 != *Index2)
- return false;
- }
- }
- }
-
- // If both declarations are class template specializations, we know
- // the ODR applies, so check the template and template arguments.
- ClassTemplateSpecializationDecl *Spec1
- = dyn_cast<ClassTemplateSpecializationDecl>(D1);
- ClassTemplateSpecializationDecl *Spec2
- = dyn_cast<ClassTemplateSpecializationDecl>(D2);
- if (Spec1 && Spec2) {
- // Check that the specialized templates are the same.
- if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
- Spec2->getSpecializedTemplate()))
- return false;
-
- // Check that the template arguments are the same.
- if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
- return false;
-
- for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context,
- Spec1->getTemplateArgs().get(I),
- Spec2->getTemplateArgs().get(I)))
- return false;
- }
- // If one is a class template specialization and the other is not, these
- // structures are different.
- else if (Spec1 || Spec2)
- return false;
-
- // Compare the definitions of these two records. If either or both are
- // incomplete, we assume that they are equivalent.
- D1 = D1->getDefinition();
- D2 = D2->getDefinition();
- if (!D1 || !D2)
- return true;
-
- if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
- if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
- if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
- << D2CXX->getNumBases();
- Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
- << D1CXX->getNumBases();
- }
- return false;
- }
-
- // Check the base classes.
- for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
- BaseEnd1 = D1CXX->bases_end(),
- Base2 = D2CXX->bases_begin();
- Base1 != BaseEnd1;
- ++Base1, ++Base2) {
- if (!IsStructurallyEquivalent(Context,
- Base1->getType(), Base2->getType())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
- << Base2->getType()
- << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
- }
- return false;
- }
-
- // Check virtual vs. non-virtual inheritance mismatch.
- if (Base1->isVirtual() != Base2->isVirtual()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(),
- diag::note_odr_virtual_base)
- << Base2->isVirtual() << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->isVirtual()
- << Base1->getSourceRange();
- }
- return false;
- }
- }
- } else if (D1CXX->getNumBases() > 0) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
- }
- return false;
- }
- }
-
- // Check the fields for consistency.
- RecordDecl::field_iterator Field2 = D2->field_begin(),
- Field2End = D2->field_end();
- for (RecordDecl::field_iterator Field1 = D1->field_begin(),
- Field1End = D1->field_end();
- Field1 != Field1End;
- ++Field1, ++Field2) {
- if (Field2 == Field2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
- }
- return false;
- }
-
- if (!IsStructurallyEquivalent(Context, *Field1, *Field2))
- return false;
- }
-
- if (Field2 != Field2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
- }
- return false;
- }
-
- return true;
-}
-
-/// \brief Determine structural equivalence of two enums.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- EnumDecl *D1, EnumDecl *D2) {
- EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
- EC2End = D2->enumerator_end();
- for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
- EC1End = D1->enumerator_end();
- EC1 != EC1End; ++EC1, ++EC2) {
- if (EC2 == EC2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
- }
- return false;
- }
-
- llvm::APSInt Val1 = EC1->getInitVal();
- llvm::APSInt Val2 = EC2->getInitVal();
- if (!llvm::APSInt::isSameValue(Val1, Val2) ||
- !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName()
- << EC2->getInitVal().toString(10);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- }
- return false;
- }
- }
-
- if (EC2 != EC2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName()
- << EC2->getInitVal().toString(10);
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
- }
- return false;
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateParameterList *Params1,
- TemplateParameterList *Params2) {
- if (Params1->size() != Params2->size()) {
- if (Context.Complain) {
- Context.Diag2(Params2->getTemplateLoc(),
- diag::err_odr_different_num_template_parameters)
- << Params1->size() << Params2->size();
- Context.Diag1(Params1->getTemplateLoc(),
- diag::note_odr_template_parameter_list);
- }
- return false;
- }
-
- for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
- if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
- if (Context.Complain) {
- Context.Diag2(Params2->getParam(I)->getLocation(),
- diag::err_odr_different_template_parameter_kind);
- Context.Diag1(Params1->getParam(I)->getLocation(),
- diag::note_odr_template_parameter_here);
- }
- return false;
- }
-
- if (!Context.IsStructurallyEquivalent(Params1->getParam(I),
- Params2->getParam(I))) {
-
- return false;
- }
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateTypeParmDecl *D1,
- TemplateTypeParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NonTypeTemplateParmDecl *D1,
- NonTypeTemplateParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
-
- // Check types.
- if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- diag::err_odr_non_type_parameter_type_inconsistent)
- << D2->getType() << D1->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
- << D1->getType();
- }
- return false;
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateTemplateParmDecl *D1,
- TemplateTemplateParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
-
- // Check template parameter lists.
- return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
- D2->getTemplateParameters());
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- ClassTemplateDecl *D1,
- ClassTemplateDecl *D2) {
- // Check template parameters.
- if (!IsStructurallyEquivalent(Context,
- D1->getTemplateParameters(),
- D2->getTemplateParameters()))
- return false;
-
- // Check the templated declaration.
- return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(),
- D2->getTemplatedDecl());
-}
-
-/// \brief Determine structural equivalence of two declarations.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Decl *D1, Decl *D2) {
- // FIXME: Check for known structural equivalences via a callback of some sort.
-
- // Check whether we already know that these two declarations are not
- // structurally equivalent.
- if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(),
- D2->getCanonicalDecl())))
- return false;
-
- // Determine whether we've already produced a tentative equivalence for D1.
- Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
- if (EquivToD1)
- return EquivToD1 == D2->getCanonicalDecl();
-
- // Produce a tentative equivalence D1 <-> D2, which will be checked later.
- EquivToD1 = D2->getCanonicalDecl();
- Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
- return true;
-}
-
-bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1,
- Decl *D2) {
- if (!::IsStructurallyEquivalent(*this, D1, D2))
- return false;
-
- return !Finish();
-}
-
-bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1,
- QualType T2) {
- if (!::IsStructurallyEquivalent(*this, T1, T2))
- return false;
-
- return !Finish();
-}
-
-bool StructuralEquivalenceContext::Finish() {
- while (!DeclsToCheck.empty()) {
- // Check the next declaration.
- Decl *D1 = DeclsToCheck.front();
- DeclsToCheck.pop_front();
-
- Decl *D2 = TentativeEquivalences[D1];
- assert(D2 && "Unrecorded tentative equivalence?");
-
- bool Equivalent = true;
-
- // FIXME: Switch on all declaration kinds. For now, we're just going to
- // check the obvious ones.
- if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) {
- if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
- // Check for equivalent structure names.
- IdentifierInfo *Name1 = Record1->getIdentifier();
- if (!Name1 && Record1->getTypedefNameForAnonDecl())
- Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier();
- IdentifierInfo *Name2 = Record2->getIdentifier();
- if (!Name2 && Record2->getTypedefNameForAnonDecl())
- Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2) ||
- !::IsStructurallyEquivalent(*this, Record1, Record2))
- Equivalent = false;
- } else {
- // Record/non-record mismatch.
- Equivalent = false;
- }
- } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
- if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
- // Check for equivalent enum names.
- IdentifierInfo *Name1 = Enum1->getIdentifier();
- if (!Name1 && Enum1->getTypedefNameForAnonDecl())
- Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier();
- IdentifierInfo *Name2 = Enum2->getIdentifier();
- if (!Name2 && Enum2->getTypedefNameForAnonDecl())
- Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2) ||
- !::IsStructurallyEquivalent(*this, Enum1, Enum2))
- Equivalent = false;
- } else {
- // Enum/non-enum mismatch
- Equivalent = false;
- }
- } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
- if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
- if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
- Typedef2->getIdentifier()) ||
- !::IsStructurallyEquivalent(*this,
- Typedef1->getUnderlyingType(),
- Typedef2->getUnderlyingType()))
- Equivalent = false;
- } else {
- // Typedef/non-typedef mismatch.
- Equivalent = false;
- }
- } else if (ClassTemplateDecl *ClassTemplate1
- = dyn_cast<ClassTemplateDecl>(D1)) {
- if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) {
- if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(),
- ClassTemplate2->getIdentifier()) ||
- !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2))
- Equivalent = false;
- } else {
- // Class template/non-class-template mismatch.
- Equivalent = false;
- }
- } else if (TemplateTypeParmDecl *TTP1= dyn_cast<TemplateTypeParmDecl>(D1)) {
- if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
- Equivalent = false;
- } else {
- // Kind mismatch.
- Equivalent = false;
- }
- } else if (NonTypeTemplateParmDecl *NTTP1
- = dyn_cast<NonTypeTemplateParmDecl>(D1)) {
- if (NonTypeTemplateParmDecl *NTTP2
- = dyn_cast<NonTypeTemplateParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2))
- Equivalent = false;
- } else {
- // Kind mismatch.
- Equivalent = false;
- }
- } else if (TemplateTemplateParmDecl *TTP1
- = dyn_cast<TemplateTemplateParmDecl>(D1)) {
- if (TemplateTemplateParmDecl *TTP2
- = dyn_cast<TemplateTemplateParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
- Equivalent = false;
- } else {
- // Kind mismatch.
- Equivalent = false;
- }
- }
-
- if (!Equivalent) {
- // Note that these two declarations are not equivalent (and we already
- // know about it).
- NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(),
- D2->getCanonicalDecl()));
- return true;
- }
- // FIXME: Check other declaration kinds!
- }
-
- return false;
-}
-
//----------------------------------------------------------------------------
// Import Types
//----------------------------------------------------------------------------
+using namespace clang;
+
QualType ASTNodeImporter::VisitType(const Type *T) {
Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node)
<< T->getTypeClassName();
@@ -2336,12 +956,16 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.HasUninitializedFields = FromData.HasUninitializedFields;
ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;
ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;
+ ToData.NeedOverloadResolutionForCopyConstructor
+ = FromData.NeedOverloadResolutionForCopyConstructor;
ToData.NeedOverloadResolutionForMoveConstructor
= FromData.NeedOverloadResolutionForMoveConstructor;
ToData.NeedOverloadResolutionForMoveAssignment
= FromData.NeedOverloadResolutionForMoveAssignment;
ToData.NeedOverloadResolutionForDestructor
= FromData.NeedOverloadResolutionForDestructor;
+ ToData.DefaultedCopyConstructorIsDeleted
+ = FromData.DefaultedCopyConstructorIsDeleted;
ToData.DefaultedMoveConstructorIsDeleted
= FromData.DefaultedMoveConstructorIsDeleted;
ToData.DefaultedMoveAssignmentIsDeleted
@@ -2353,6 +977,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
= FromData.HasConstexprNonCopyMoveConstructor;
ToData.HasDefaultedDefaultConstructor
= FromData.HasDefaultedDefaultConstructor;
+ ToData.CanPassInRegisters = FromData.CanPassInRegisters;
ToData.DefaultedDefaultConstructorIsConstexpr
= FromData.DefaultedDefaultConstructorIsConstexpr;
ToData.HasConstexprDefaultConstructor
@@ -2634,7 +1259,7 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
Importer.getNonEquivalentDecls());
- return Ctx.IsStructurallyEquivalent(From, To);
+ return Ctx.IsStructurallyEquivalent(From, To);
}
bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From,
@@ -2813,10 +1438,10 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
FoundTypedef->getUnderlyingType()))
return Importer.Imported(D, FoundTypedef);
}
-
+
ConflictingDecls.push_back(FoundDecls[I]);
}
-
+
if (!ConflictingDecls.empty()) {
Name = Importer.HandleNameConflict(Name, DC, IDNS,
ConflictingDecls.data(),
@@ -2825,7 +1450,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
return nullptr;
}
}
-
+
// Import the underlying type of this typedef;
QualType T = Importer.Import(D->getUnderlyingType());
if (T.isNull())
@@ -2845,12 +1470,12 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
StartL, Loc,
Name.getAsIdentifierInfo(),
TInfo);
-
+
ToTypedef->setAccess(D->getAccess());
ToTypedef->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToTypedef);
LexicalDC->addDeclInternal(ToTypedef);
-
+
return ToTypedef;
}
@@ -2919,7 +1544,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
if (!DC->isFunctionOrMethod() && SearchName) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -3005,10 +1630,18 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// We may already have a record of the same name; try to find and match it.
RecordDecl *AdoptDecl = nullptr;
+ RecordDecl *PrevDecl = nullptr;
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(SearchName, FoundDecls);
+
+ if (!FoundDecls.empty()) {
+ // We're going to have to compare D against potentially conflicting Decls, so complete it.
+ if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition())
+ D->getASTContext().getExternalSource()->CompleteType(D);
+ }
+
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -3024,9 +1657,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
FoundRecord->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (Optional<unsigned> Index1
- = findUntaggedStructOrUnionIndex(D)) {
- if (Optional<unsigned> Index2 =
+ if (Optional<unsigned> Index1 =
+ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
+ D)) {
+ if (Optional<unsigned> Index2 = StructuralEquivalenceContext::
findUntaggedStructOrUnionIndex(FoundRecord)) {
if (*Index1 != *Index2)
continue;
@@ -3034,6 +1668,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
}
}
+ PrevDecl = FoundRecord;
+
if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
if ((SearchName && !D->isCompleteDefinition())
|| (D->isCompleteDefinition() &&
@@ -3126,6 +1762,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
LexicalDC->addDeclInternal(D2);
if (D->isAnonymousStructOrUnion())
D2->setAnonymousStructOrUnion(true);
+ if (PrevDecl) {
+ // FIXME: do this for all Redeclarables, not just RecordDecls.
+ D2->setPreviousDecl(PrevDecl);
+ }
}
Importer.Imported(D, D2);
@@ -3206,6 +1846,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (ToD)
return ToD;
+ const FunctionDecl *FoundWithoutBody = nullptr;
+
// Try to find a function in our own ("to") context with the same name, same
// type, and in the same context as the function we're importing.
if (!LexicalDC->isFunctionOrMethod()) {
@@ -3216,23 +1858,30 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
-
+
if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) {
if (FoundFunction->hasExternalFormalLinkage() &&
D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundFunction->getType())) {
// FIXME: Actually try to merge the body and other attributes.
+ const FunctionDecl *FromBodyDecl = nullptr;
+ D->hasBody(FromBodyDecl);
+ if (D == FromBodyDecl && !FoundFunction->hasBody()) {
+ // This function is needed to merge completely.
+ FoundWithoutBody = FoundFunction;
+ break;
+ }
return Importer.Imported(D, FoundFunction);
}
-
+
// FIXME: Check for overloading more carefully, e.g., by boosting
// Sema::IsOverload out to the AST library.
-
+
// Function overloading is okay in C++.
if (Importer.getToContext().getLangOpts().CPlusPlus)
continue;
-
+
// Complain about inconsistent function types.
Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent)
<< Name << D->getType() << FoundFunction->getType();
@@ -3241,10 +1890,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
<< FoundFunction->getType();
}
}
-
+
ConflictingDecls.push_back(FoundDecls[I]);
}
-
+
if (!ConflictingDecls.empty()) {
Name = Importer.HandleNameConflict(Name, DC, IDNS,
ConflictingDecls.data(),
@@ -3373,6 +2022,12 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
ToFunction->setParams(Parameters);
+ if (FoundWithoutBody) {
+ auto *Recent = const_cast<FunctionDecl *>(
+ FoundWithoutBody->getMostRecentDecl());
+ ToFunction->setPreviousDecl(Recent);
+ }
+
if (usedDifferentExceptionSpec) {
// Update FunctionProtoType::ExtProtoInfo.
QualType T = Importer.Import(D->getType());
@@ -3393,6 +2048,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Add this function to the lexical context.
LexicalDC->addDeclInternal(ToFunction);
+ if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
+ ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
+
return ToFunction;
}
@@ -3449,12 +2107,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
continue;
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType())) {
Importer.Imported(D, FoundField);
return FoundField;
}
-
+
Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent)
<< Name << D->getType() << FoundField->getType();
Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
@@ -3514,7 +2172,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
continue;
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType(),
!Name.isEmpty())) {
Importer.Imported(D, FoundField);
@@ -3638,12 +2296,12 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
if (ToD)
return ToD;
- // Determine whether we've already imported this ivar
+ // Determine whether we've already imported this ivar
SmallVector<NamedDecl *, 2> FoundDecls;
DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) {
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundIvar->getType())) {
Importer.Imported(D, FoundIvar);
return FoundIvar;
@@ -3702,12 +2360,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
-
+
if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) {
// We have found a variable that we may need to merge with. Check it.
if (FoundVar->hasExternalFormalLinkage() &&
D->hasExternalFormalLinkage()) {
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundVar->getType())) {
MergeWithVar = FoundVar;
break;
@@ -3830,10 +2488,9 @@ Decl *ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
return nullptr;
// Create the imported parameter.
- ImplicitParamDecl *ToParm
- = ImplicitParamDecl::Create(Importer.getToContext(), DC,
- Loc, Name.getAsIdentifierInfo(),
- T);
+ auto *ToParm = ImplicitParamDecl::Create(Importer.getToContext(), DC, Loc,
+ Name.getAsIdentifierInfo(), T,
+ D->getParameterKind());
return Importer.Imported(D, ToParm);
}
@@ -3931,12 +2588,12 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
}
// Check parameter types.
- for (ObjCMethodDecl::param_iterator P = D->param_begin(),
+ for (ObjCMethodDecl::param_iterator P = D->param_begin(),
PEnd = D->param_end(), FoundP = FoundMethod->param_begin();
P != PEnd; ++P, ++FoundP) {
- if (!Importer.IsStructurallyEquivalent((*P)->getType(),
+ if (!Importer.IsStructurallyEquivalent((*P)->getType(),
(*FoundP)->getType())) {
- Importer.FromDiag((*P)->getLocation(),
+ Importer.FromDiag((*P)->getLocation(),
diag::err_odr_objc_method_param_type_inconsistent)
<< D->isInstanceMethod() << Name
<< (*P)->getType() << (*FoundP)->getType();
@@ -4542,7 +3199,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
if (ObjCPropertyDecl *FoundProp
= dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) {
// Check property types.
- if (!Importer.IsStructurallyEquivalent(D->getType(),
+ if (!Importer.IsStructurallyEquivalent(D->getType(),
FoundProp->getType())) {
Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent)
<< Name << D->getType() << FoundProp->getType();
@@ -4580,8 +3237,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(
@@ -5324,12 +3983,16 @@ Stmt *ASTNodeImporter::VisitCaseStmt(CaseStmt *S) {
Expr *ToRHS = Importer.Import(S->getRHS());
if (!ToRHS && S->getRHS())
return nullptr;
+ Stmt *ToSubStmt = Importer.Import(S->getSubStmt());
+ if (!ToSubStmt && S->getSubStmt())
+ return nullptr;
SourceLocation ToCaseLoc = Importer.Import(S->getCaseLoc());
SourceLocation ToEllipsisLoc = Importer.Import(S->getEllipsisLoc());
SourceLocation ToColonLoc = Importer.Import(S->getColonLoc());
- return new (Importer.getToContext()) CaseStmt(ToLHS, ToRHS,
- ToCaseLoc, ToEllipsisLoc,
- ToColonLoc);
+ CaseStmt *ToStmt = new (Importer.getToContext())
+ CaseStmt(ToLHS, ToRHS, ToCaseLoc, ToEllipsisLoc, ToColonLoc);
+ ToStmt->setSubStmt(ToSubStmt);
+ return ToStmt;
}
Stmt *ASTNodeImporter::VisitDefaultStmt(DefaultStmt *S) {
@@ -6072,7 +4735,7 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
T, E->getValueKind(),
E->getObjectKind(),
Importer.Import(E->getOperatorLoc()),
- E->isFPContractable());
+ E->getFPFeatures());
}
Expr *ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
@@ -6222,7 +4885,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) {
@@ -6866,6 +5529,14 @@ Expr *ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr(
Replacement);
}
+void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod,
+ CXXMethodDecl *FromMethod) {
+ for (auto *FromOverriddenMethod : FromMethod->overridden_methods())
+ ToMethod->addOverriddenMethod(
+ cast<CXXMethodDecl>(Importer.Import(const_cast<CXXMethodDecl*>(
+ FromOverriddenMethod))));
+}
+
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager,
bool MinimalImport)
@@ -7595,7 +6266,7 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To,
= ImportedTypes.find(From.getTypePtr());
if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To))
return true;
-
+
StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls,
false, Complain);
return Ctx.IsStructurallyEquivalent(From, To);
diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp
new file mode 100644
index 0000000000..0df8e5653f
--- /dev/null
+++ b/lib/AST/ASTStructuralEquivalence.cpp
@@ -0,0 +1,1377 @@
+//===--- ASTStructuralEquivalence.cpp - -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implement StructuralEquivalenceContext class and helper functions
+// for layout matching.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTStructuralEquivalence.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace {
+
+using namespace clang;
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgument &Arg1,
+ const TemplateArgument &Arg2);
+
+/// Determine structural equivalence of two expressions.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Expr *E1, Expr *E2) {
+ if (!E1 || !E2)
+ return E1 == E2;
+
+ // FIXME: Actually perform a structural comparison!
+ return true;
+}
+
+/// Determine whether two identifiers are equivalent.
+static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
+ const IdentifierInfo *Name2) {
+ if (!Name1 || !Name2)
+ return Name1 == Name2;
+
+ return Name1->getName() == Name2->getName();
+}
+
+/// Determine whether two nested-name-specifiers are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NestedNameSpecifier *NNS1,
+ NestedNameSpecifier *NNS2) {
+ if (NNS1->getKind() != NNS2->getKind())
+ return false;
+
+ NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
+ *Prefix2 = NNS2->getPrefix();
+ if ((bool)Prefix1 != (bool)Prefix2)
+ return false;
+
+ if (Prefix1)
+ if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
+ return false;
+
+ switch (NNS1->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
+ NNS2->getAsIdentifier());
+ case NestedNameSpecifier::Namespace:
+ return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
+ NNS2->getAsNamespace());
+ case NestedNameSpecifier::NamespaceAlias:
+ return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
+ NNS2->getAsNamespaceAlias());
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
+ QualType(NNS2->getAsType(), 0));
+ case NestedNameSpecifier::Global:
+ return true;
+ case NestedNameSpecifier::Super:
+ return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),
+ NNS2->getAsRecordDecl());
+ }
+ return false;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateName &N1,
+ const TemplateName &N2) {
+ if (N1.getKind() != N2.getKind())
+ return false;
+ switch (N1.getKind()) {
+ case TemplateName::Template:
+ return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(),
+ N2.getAsTemplateDecl());
+
+ case TemplateName::OverloadedTemplate: {
+ OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
+ *OS2 = N2.getAsOverloadedTemplate();
+ OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(),
+ E1 = OS1->end(), E2 = OS2->end();
+ for (; I1 != E1 && I2 != E2; ++I1, ++I2)
+ if (!IsStructurallyEquivalent(Context, *I1, *I2))
+ return false;
+ return I1 == E1 && I2 == E2;
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),
+ *QN2 = N2.getAsQualifiedTemplateName();
+ return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) &&
+ IsStructurallyEquivalent(Context, QN1->getQualifier(),
+ QN2->getQualifier());
+ }
+
+ case TemplateName::DependentTemplate: {
+ DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
+ *DN2 = N2.getAsDependentTemplateName();
+ if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),
+ DN2->getQualifier()))
+ return false;
+ if (DN1->isIdentifier() && DN2->isIdentifier())
+ return IsStructurallyEquivalent(DN1->getIdentifier(),
+ DN2->getIdentifier());
+ else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())
+ return DN1->getOperator() == DN2->getOperator();
+ return false;
+ }
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(),
+ *TS2 = N2.getAsSubstTemplateTemplateParm();
+ return IsStructurallyEquivalent(Context, TS1->getParameter(),
+ TS2->getParameter()) &&
+ IsStructurallyEquivalent(Context, TS1->getReplacement(),
+ TS2->getReplacement());
+ }
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ SubstTemplateTemplateParmPackStorage
+ *P1 = N1.getAsSubstTemplateTemplateParmPack(),
+ *P2 = N2.getAsSubstTemplateTemplateParmPack();
+ return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
+ P2->getArgumentPack()) &&
+ IsStructurallyEquivalent(Context, P1->getParameterPack(),
+ P2->getParameterPack());
+ }
+ }
+ return false;
+}
+
+/// Determine whether two template arguments are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgument &Arg1,
+ const TemplateArgument &Arg2) {
+ if (Arg1.getKind() != Arg2.getKind())
+ return false;
+
+ switch (Arg1.getKind()) {
+ case TemplateArgument::Null:
+ return true;
+
+ case TemplateArgument::Type:
+ return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType());
+
+ case TemplateArgument::Integral:
+ if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(),
+ Arg2.getIntegralType()))
+ return false;
+
+ return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
+ Arg2.getAsIntegral());
+
+ case TemplateArgument::Declaration:
+ return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
+
+ case TemplateArgument::NullPtr:
+ return true; // FIXME: Is this correct?
+
+ case TemplateArgument::Template:
+ return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(),
+ Arg2.getAsTemplate());
+
+ case TemplateArgument::TemplateExpansion:
+ return IsStructurallyEquivalent(Context,
+ Arg1.getAsTemplateOrTemplatePattern(),
+ Arg2.getAsTemplateOrTemplatePattern());
+
+ case TemplateArgument::Expression:
+ return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
+ Arg2.getAsExpr());
+
+ case TemplateArgument::Pack:
+ if (Arg1.pack_size() != Arg2.pack_size())
+ return false;
+
+ for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
+ if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I],
+ Arg2.pack_begin()[I]))
+ return false;
+
+ return true;
+ }
+
+ llvm_unreachable("Invalid template argument kind");
+}
+
+/// Determine structural equivalence for the common part of array
+/// types.
+static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const ArrayType *Array1,
+ const ArrayType *Array2) {
+ if (!IsStructurallyEquivalent(Context, Array1->getElementType(),
+ Array2->getElementType()))
+ return false;
+ if (Array1->getSizeModifier() != Array2->getSizeModifier())
+ return false;
+ if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
+ return false;
+
+ return true;
+}
+
+/// Determine structural equivalence of two types.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2) {
+ if (T1.isNull() || T2.isNull())
+ return T1.isNull() && T2.isNull();
+
+ if (!Context.StrictTypeSpelling) {
+ // We aren't being strict about token-to-token equivalence of types,
+ // so map down to the canonical type.
+ T1 = Context.FromCtx.getCanonicalType(T1);
+ T2 = Context.ToCtx.getCanonicalType(T2);
+ }
+
+ if (T1.getQualifiers() != T2.getQualifiers())
+ return false;
+
+ Type::TypeClass TC = T1->getTypeClass();
+
+ if (T1->getTypeClass() != T2->getTypeClass()) {
+ // Compare function types with prototypes vs. without prototypes as if
+ // both did not have prototypes.
+ if (T1->getTypeClass() == Type::FunctionProto &&
+ T2->getTypeClass() == Type::FunctionNoProto)
+ TC = Type::FunctionNoProto;
+ else if (T1->getTypeClass() == Type::FunctionNoProto &&
+ T2->getTypeClass() == Type::FunctionProto)
+ TC = Type::FunctionNoProto;
+ else
+ return false;
+ }
+
+ switch (TC) {
+ case Type::Builtin:
+ // FIXME: Deal with Char_S/Char_U.
+ if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
+ return false;
+ break;
+
+ case Type::Complex:
+ if (!IsStructurallyEquivalent(Context,
+ cast<ComplexType>(T1)->getElementType(),
+ cast<ComplexType>(T2)->getElementType()))
+ return false;
+ break;
+
+ case Type::Adjusted:
+ case Type::Decayed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<AdjustedType>(T1)->getOriginalType(),
+ cast<AdjustedType>(T2)->getOriginalType()))
+ return false;
+ break;
+
+ case Type::Pointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PointerType>(T1)->getPointeeType(),
+ cast<PointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::BlockPointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<BlockPointerType>(T1)->getPointeeType(),
+ cast<BlockPointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ const ReferenceType *Ref1 = cast<ReferenceType>(T1);
+ const ReferenceType *Ref2 = cast<ReferenceType>(T2);
+ if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
+ return false;
+ if (Ref1->isInnerRef() != Ref2->isInnerRef())
+ return false;
+ if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(),
+ Ref2->getPointeeTypeAsWritten()))
+ return false;
+ break;
+ }
+
+ case Type::MemberPointer: {
+ const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1);
+ const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(),
+ MemPtr2->getPointeeType()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0),
+ QualType(MemPtr2->getClass(), 0)))
+ return false;
+ break;
+ }
+
+ case Type::ConstantArray: {
+ const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1);
+ const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2);
+ if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+ break;
+ }
+
+ case Type::IncompleteArray:
+ if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1),
+ cast<ArrayType>(T2)))
+ return false;
+ break;
+
+ case Type::VariableArray: {
+ const VariableArrayType *Array1 = cast<VariableArrayType>(T1);
+ const VariableArrayType *Array2 = cast<VariableArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
+ Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedArray: {
+ const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1);
+ const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
+ Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentAddressSpace: {
+ const DependentAddressSpaceType *DepAddressSpace1 =
+ cast<DependentAddressSpaceType>(T1);
+ const DependentAddressSpaceType *DepAddressSpace2 =
+ cast<DependentAddressSpaceType>(T2);
+ if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(),
+ DepAddressSpace2->getAddrSpaceExpr()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getPointeeType(),
+ DepAddressSpace2->getPointeeType()))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedExtVector: {
+ const DependentSizedExtVectorType *Vec1 =
+ cast<DependentSizedExtVectorType>(T1);
+ const DependentSizedExtVectorType *Vec2 =
+ cast<DependentSizedExtVectorType>(T2);
+ if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
+ Vec2->getSizeExpr()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ break;
+ }
+
+ case Type::Vector:
+ case Type::ExtVector: {
+ const VectorType *Vec1 = cast<VectorType>(T1);
+ const VectorType *Vec2 = cast<VectorType>(T2);
+ if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ if (Vec1->getNumElements() != Vec2->getNumElements())
+ return false;
+ if (Vec1->getVectorKind() != Vec2->getVectorKind())
+ return false;
+ break;
+ }
+
+ case Type::FunctionProto: {
+ const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1);
+ const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2);
+ if (Proto1->getNumParams() != Proto2->getNumParams())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
+ Proto2->getParamType(I)))
+ return false;
+ }
+ if (Proto1->isVariadic() != Proto2->isVariadic())
+ return false;
+ if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())
+ return false;
+ if (Proto1->getExceptionSpecType() == EST_Dynamic) {
+ if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
+ Proto2->getExceptionType(I)))
+ return false;
+ }
+ } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
+ Proto2->getNoexceptExpr()))
+ return false;
+ }
+ if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
+ return false;
+
+ // Fall through to check the bits common with FunctionNoProtoType.
+ LLVM_FALLTHROUGH;
+ }
+
+ case Type::FunctionNoProto: {
+ const FunctionType *Function1 = cast<FunctionType>(T1);
+ const FunctionType *Function2 = cast<FunctionType>(T2);
+ if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
+ Function2->getReturnType()))
+ return false;
+ if (Function1->getExtInfo() != Function2->getExtInfo())
+ return false;
+ break;
+ }
+
+ case Type::UnresolvedUsing:
+ if (!IsStructurallyEquivalent(Context,
+ cast<UnresolvedUsingType>(T1)->getDecl(),
+ cast<UnresolvedUsingType>(T2)->getDecl()))
+ return false;
+
+ break;
+
+ case Type::Attributed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<AttributedType>(T1)->getModifiedType(),
+ cast<AttributedType>(T2)->getModifiedType()))
+ return false;
+ if (!IsStructurallyEquivalent(
+ Context, cast<AttributedType>(T1)->getEquivalentType(),
+ cast<AttributedType>(T2)->getEquivalentType()))
+ return false;
+ break;
+
+ case Type::Paren:
+ if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(),
+ cast<ParenType>(T2)->getInnerType()))
+ return false;
+ break;
+
+ case Type::Typedef:
+ if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
+ cast<TypedefType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::TypeOfExpr:
+ if (!IsStructurallyEquivalent(
+ Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
+ cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::TypeOf:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypeOfType>(T1)->getUnderlyingType(),
+ cast<TypeOfType>(T2)->getUnderlyingType()))
+ return false;
+ break;
+
+ case Type::UnaryTransform:
+ if (!IsStructurallyEquivalent(
+ Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
+ cast<UnaryTransformType>(T1)->getUnderlyingType()))
+ return false;
+ break;
+
+ case Type::Decltype:
+ if (!IsStructurallyEquivalent(Context,
+ cast<DecltypeType>(T1)->getUnderlyingExpr(),
+ cast<DecltypeType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::Auto:
+ if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
+ cast<AutoType>(T2)->getDeducedType()))
+ return false;
+ break;
+
+ case Type::DeducedTemplateSpecialization: {
+ auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
+ auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(),
+ DT2->getTemplateName()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(),
+ DT2->getDeducedType()))
+ return false;
+ break;
+ }
+
+ case Type::Record:
+ case Type::Enum:
+ if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),
+ cast<TagType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::TemplateTypeParm: {
+ const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
+ const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
+ if (Parm1->getDepth() != Parm2->getDepth())
+ return false;
+ if (Parm1->getIndex() != Parm2->getIndex())
+ return false;
+ if (Parm1->isParameterPack() != Parm2->isParameterPack())
+ return false;
+
+ // Names of template type parameters are never significant.
+ break;
+ }
+
+ case Type::SubstTemplateTypeParm: {
+ const SubstTemplateTypeParmType *Subst1 =
+ cast<SubstTemplateTypeParmType>(T1);
+ const SubstTemplateTypeParmType *Subst2 =
+ cast<SubstTemplateTypeParmType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Subst1->getReplacedParameter(), 0),
+ QualType(Subst2->getReplacedParameter(), 0)))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
+ Subst2->getReplacementType()))
+ return false;
+ break;
+ }
+
+ case Type::SubstTemplateTypeParmPack: {
+ const SubstTemplateTypeParmPackType *Subst1 =
+ cast<SubstTemplateTypeParmPackType>(T1);
+ const SubstTemplateTypeParmPackType *Subst2 =
+ cast<SubstTemplateTypeParmPackType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Subst1->getReplacedParameter(), 0),
+ QualType(Subst2->getReplacedParameter(), 0)))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
+ Subst2->getArgumentPack()))
+ return false;
+ break;
+ }
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *Spec1 =
+ cast<TemplateSpecializationType>(T1);
+ const TemplateSpecializationType *Spec2 =
+ cast<TemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
+ Spec2->getTemplateName()))
+ return false;
+ if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
+ Spec2->getArg(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::Elaborated: {
+ const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
+ const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
+ // CHECKME: what if a keyword is ETK_None or ETK_typename ?
+ if (Elab1->getKeyword() != Elab2->getKeyword())
+ return false;
+ if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),
+ Elab2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),
+ Elab2->getNamedType()))
+ return false;
+ break;
+ }
+
+ case Type::InjectedClassName: {
+ const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
+ const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Inj1->getInjectedSpecializationType(),
+ Inj2->getInjectedSpecializationType()))
+ return false;
+ break;
+ }
+
+ case Type::DependentName: {
+ const DependentNameType *Typename1 = cast<DependentNameType>(T1);
+ const DependentNameType *Typename2 = cast<DependentNameType>(T2);
+ if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(),
+ Typename2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
+ Typename2->getIdentifier()))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentTemplateSpecialization: {
+ const DependentTemplateSpecializationType *Spec1 =
+ cast<DependentTemplateSpecializationType>(T1);
+ const DependentTemplateSpecializationType *Spec2 =
+ cast<DependentTemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),
+ Spec2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
+ Spec2->getIdentifier()))
+ return false;
+ if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
+ Spec2->getArg(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::PackExpansion:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PackExpansionType>(T1)->getPattern(),
+ cast<PackExpansionType>(T2)->getPattern()))
+ return false;
+ break;
+
+ case Type::ObjCInterface: {
+ const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
+ const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
+ if (!IsStructurallyEquivalent(Context, Iface1->getDecl(),
+ Iface2->getDecl()))
+ return false;
+ break;
+ }
+
+ case Type::ObjCTypeParam: {
+ const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1);
+ const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2);
+ if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl()))
+ return false;
+
+ if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
+ Obj2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+ case Type::ObjCObject: {
+ const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1);
+ const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2);
+ if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(),
+ Obj2->getBaseType()))
+ return false;
+ if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
+ Obj2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1);
+ const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(),
+ Ptr2->getPointeeType()))
+ return false;
+ break;
+ }
+
+ case Type::Atomic: {
+ if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(),
+ cast<AtomicType>(T2)->getValueType()))
+ return false;
+ break;
+ }
+
+ case Type::Pipe: {
+ if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(),
+ cast<PipeType>(T2)->getElementType()))
+ return false;
+ break;
+ }
+
+ } // end switch
+
+ return true;
+}
+
+/// Determine structural equivalence of two fields.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ FieldDecl *Field1, FieldDecl *Field2) {
+ RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
+
+ // For anonymous structs/unions, match up the anonymous struct/union type
+ // declarations directly, so that we don't go off searching for anonymous
+ // types
+ if (Field1->isAnonymousStructOrUnion() &&
+ Field2->isAnonymousStructOrUnion()) {
+ RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
+ return IsStructurallyEquivalent(Context, D1, D2);
+ }
+
+ // Check for equivalent field names.
+ IdentifierInfo *Name1 = Field1->getIdentifier();
+ IdentifierInfo *Name2 = Field2->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2)) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
+ << Field2->getDeclName();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)
+ << Field1->getDeclName();
+ }
+ return false;
+ }
+
+ if (!IsStructurallyEquivalent(Context, Field1->getType(),
+ Field2->getType())) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ }
+ return false;
+ }
+
+ if (Field1->isBitField() != Field2->isBitField()) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ if (Field1->isBitField()) {
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Field1->getBitWidthValue(Context.FromCtx);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
+ << Field2->getDeclName();
+ } else {
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Field2->getBitWidthValue(Context.ToCtx);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
+ << Field1->getDeclName();
+ }
+ }
+ return false;
+ }
+
+ if (Field1->isBitField()) {
+ // Make sure that the bit-fields are the same length.
+ unsigned Bits1 = Field1->getBitWidthValue(Context.FromCtx);
+ unsigned Bits2 = Field2->getBitWidthValue(Context.ToCtx);
+
+ if (Bits1 != Bits2) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType() << Bits2;
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType() << Bits1;
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/// Determine structural equivalence of two records.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ RecordDecl *D1, RecordDecl *D2) {
+ if (D1->isUnion() != D2->isUnion()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
+ << D1->getDeclName() << (unsigned)D1->getTagKind();
+ }
+ return false;
+ }
+
+ if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
+ // If both anonymous structs/unions are in a record context, make sure
+ // they occur in the same location in the context records.
+ if (Optional<unsigned> Index1 =
+ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
+ if (Optional<unsigned> Index2 =
+ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
+ D2)) {
+ if (*Index1 != *Index2)
+ return false;
+ }
+ }
+ }
+
+ // If both declarations are class template specializations, we know
+ // the ODR applies, so check the template and template arguments.
+ ClassTemplateSpecializationDecl *Spec1 =
+ dyn_cast<ClassTemplateSpecializationDecl>(D1);
+ ClassTemplateSpecializationDecl *Spec2 =
+ dyn_cast<ClassTemplateSpecializationDecl>(D2);
+ if (Spec1 && Spec2) {
+ // Check that the specialized templates are the same.
+ if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
+ Spec2->getSpecializedTemplate()))
+ return false;
+
+ // Check that the template arguments are the same.
+ if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
+ return false;
+
+ for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
+ if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I),
+ Spec2->getTemplateArgs().get(I)))
+ return false;
+ }
+ // If one is a class template specialization and the other is not, these
+ // structures are different.
+ else if (Spec1 || Spec2)
+ return false;
+
+ // Compare the definitions of these two records. If either or both are
+ // incomplete, we assume that they are equivalent.
+ D1 = D1->getDefinition();
+ D2 = D2->getDefinition();
+ if (!D1 || !D2)
+ return true;
+
+ if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
+ if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
+ if (D1CXX->hasExternalLexicalStorage() &&
+ !D1CXX->isCompleteDefinition()) {
+ D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
+ }
+
+ if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+ << D2CXX->getNumBases();
+ Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
+ << D1CXX->getNumBases();
+ }
+ return false;
+ }
+
+ // Check the base classes.
+ for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
+ BaseEnd1 = D1CXX->bases_end(),
+ Base2 = D2CXX->bases_begin();
+ Base1 != BaseEnd1; ++Base1, ++Base2) {
+ if (!IsStructurallyEquivalent(Context, Base1->getType(),
+ Base2->getType())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
+ << Base2->getType() << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType() << Base1->getSourceRange();
+ }
+ return false;
+ }
+
+ // Check virtual vs. non-virtual inheritance mismatch.
+ if (Base1->isVirtual() != Base2->isVirtual()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(), diag::note_odr_virtual_base)
+ << Base2->isVirtual() << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->isVirtual() << Base1->getSourceRange();
+ }
+ return false;
+ }
+ }
+ } else if (D1CXX->getNumBases() > 0) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType() << Base1->getSourceRange();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ }
+ return false;
+ }
+ }
+
+ // Check the fields for consistency.
+ RecordDecl::field_iterator Field2 = D2->field_begin(),
+ Field2End = D2->field_end();
+ for (RecordDecl::field_iterator Field1 = D1->field_begin(),
+ Field1End = D1->field_end();
+ Field1 != Field1End; ++Field1, ++Field2) {
+ if (Field2 == Field2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ }
+ return false;
+ }
+
+ if (!IsStructurallyEquivalent(Context, *Field1, *Field2))
+ return false;
+ }
+
+ if (Field2 != Field2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/// Determine structural equivalence of two enums.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ EnumDecl *D1, EnumDecl *D2) {
+ EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
+ EC2End = D2->enumerator_end();
+ for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
+ EC1End = D1->enumerator_end();
+ EC1 != EC1End; ++EC1, ++EC2) {
+ if (EC2 == EC2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName() << EC1->getInitVal().toString(10);
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ }
+ return false;
+ }
+
+ llvm::APSInt Val1 = EC1->getInitVal();
+ llvm::APSInt Val2 = EC2->getInitVal();
+ if (!llvm::APSInt::isSameValue(Val1, Val2) ||
+ !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName() << EC2->getInitVal().toString(10);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName() << EC1->getInitVal().toString(10);
+ }
+ return false;
+ }
+ }
+
+ if (EC2 != EC2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName() << EC2->getInitVal().toString(10);
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateParameterList *Params1,
+ TemplateParameterList *Params2) {
+ if (Params1->size() != Params2->size()) {
+ if (Context.Complain) {
+ Context.Diag2(Params2->getTemplateLoc(),
+ diag::err_odr_different_num_template_parameters)
+ << Params1->size() << Params2->size();
+ Context.Diag1(Params1->getTemplateLoc(),
+ diag::note_odr_template_parameter_list);
+ }
+ return false;
+ }
+
+ for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
+ if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
+ if (Context.Complain) {
+ Context.Diag2(Params2->getParam(I)->getLocation(),
+ diag::err_odr_different_template_parameter_kind);
+ Context.Diag1(Params1->getParam(I)->getLocation(),
+ diag::note_odr_template_parameter_here);
+ }
+ return false;
+ }
+
+ if (!Context.IsStructurallyEquivalent(Params1->getParam(I),
+ Params2->getParam(I))) {
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateTypeParmDecl *D1,
+ TemplateTypeParmDecl *D2) {
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NonTypeTemplateParmDecl *D1,
+ NonTypeTemplateParmDecl *D2) {
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
+ return false;
+ }
+
+ // Check types.
+ if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::err_odr_non_type_parameter_type_inconsistent)
+ << D2->getType() << D1->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
+ << D1->getType();
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateTemplateParmDecl *D1,
+ TemplateTemplateParmDecl *D2) {
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
+ return false;
+ }
+
+ // Check template parameter lists.
+ return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
+ D2->getTemplateParameters());
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ClassTemplateDecl *D1,
+ ClassTemplateDecl *D2) {
+ // Check template parameters.
+ if (!IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
+ D2->getTemplateParameters()))
+ return false;
+
+ // Check the templated declaration.
+ return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(),
+ D2->getTemplatedDecl());
+}
+
+/// Determine structural equivalence of two declarations.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2) {
+ // FIXME: Check for known structural equivalences via a callback of some sort.
+
+ // Check whether we already know that these two declarations are not
+ // structurally equivalent.
+ if (Context.NonEquivalentDecls.count(
+ std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())))
+ return false;
+
+ // Determine whether we've already produced a tentative equivalence for D1.
+ Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
+ if (EquivToD1)
+ return EquivToD1 == D2->getCanonicalDecl();
+
+ // Produce a tentative equivalence D1 <-> D2, which will be checked later.
+ EquivToD1 = D2->getCanonicalDecl();
+ Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
+ return true;
+}
+} // namespace
+
+namespace clang {
+
+DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(Complain && "Not allowed to complain");
+ if (LastDiagFromC2)
+ FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());
+ LastDiagFromC2 = false;
+ return FromCtx.getDiagnostics().Report(Loc, DiagID);
+}
+
+DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(Complain && "Not allowed to complain");
+ if (!LastDiagFromC2)
+ ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());
+ LastDiagFromC2 = true;
+ return ToCtx.getDiagnostics().Report(Loc, DiagID);
+}
+
+Optional<unsigned>
+StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
+ ASTContext &Context = Anon->getASTContext();
+ QualType AnonTy = Context.getRecordType(Anon);
+
+ RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
+ if (!Owner)
+ return None;
+
+ unsigned Index = 0;
+ for (const auto *D : Owner->noload_decls()) {
+ const auto *F = dyn_cast<FieldDecl>(D);
+ if (!F)
+ continue;
+
+ if (F->isAnonymousStructOrUnion()) {
+ if (Context.hasSameType(F->getType(), AnonTy))
+ break;
+ ++Index;
+ continue;
+ }
+
+ // If the field looks like this:
+ // struct { ... } A;
+ QualType FieldType = F->getType();
+ if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
+ const RecordDecl *RecDecl = RecType->getDecl();
+ if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {
+ if (Context.hasSameType(FieldType, AnonTy))
+ break;
+ ++Index;
+ continue;
+ }
+ }
+ }
+
+ return Index;
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1,
+ Decl *D2) {
+ if (!::IsStructurallyEquivalent(*this, D1, D2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1,
+ QualType T2) {
+ if (!::IsStructurallyEquivalent(*this, T1, T2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::Finish() {
+ while (!DeclsToCheck.empty()) {
+ // Check the next declaration.
+ Decl *D1 = DeclsToCheck.front();
+ DeclsToCheck.pop_front();
+
+ Decl *D2 = TentativeEquivalences[D1];
+ assert(D2 && "Unrecorded tentative equivalence?");
+
+ bool Equivalent = true;
+
+ // FIXME: Switch on all declaration kinds. For now, we're just going to
+ // check the obvious ones.
+ if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) {
+ if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
+ // Check for equivalent structure names.
+ IdentifierInfo *Name1 = Record1->getIdentifier();
+ if (!Name1 && Record1->getTypedefNameForAnonDecl())
+ Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Record2->getIdentifier();
+ if (!Name2 && Record2->getTypedefNameForAnonDecl())
+ Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Record1, Record2))
+ Equivalent = false;
+ } else {
+ // Record/non-record mismatch.
+ Equivalent = false;
+ }
+ } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
+ if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
+ // Check for equivalent enum names.
+ IdentifierInfo *Name1 = Enum1->getIdentifier();
+ if (!Name1 && Enum1->getTypedefNameForAnonDecl())
+ Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Enum2->getIdentifier();
+ if (!Name2 && Enum2->getTypedefNameForAnonDecl())
+ Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Enum1, Enum2))
+ Equivalent = false;
+ } else {
+ // Enum/non-enum mismatch
+ Equivalent = false;
+ }
+ } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
+ if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
+ Typedef2->getIdentifier()) ||
+ !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(),
+ Typedef2->getUnderlyingType()))
+ Equivalent = false;
+ } else {
+ // Typedef/non-typedef mismatch.
+ Equivalent = false;
+ }
+ } else if (ClassTemplateDecl *ClassTemplate1 =
+ dyn_cast<ClassTemplateDecl>(D1)) {
+ if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(),
+ ClassTemplate2->getIdentifier()) ||
+ !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2))
+ Equivalent = false;
+ } else {
+ // Class template/non-class-template mismatch.
+ Equivalent = false;
+ }
+ } else if (TemplateTypeParmDecl *TTP1 =
+ dyn_cast<TemplateTypeParmDecl>(D1)) {
+ if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ } else if (NonTypeTemplateParmDecl *NTTP1 =
+ dyn_cast<NonTypeTemplateParmDecl>(D1)) {
+ if (NonTypeTemplateParmDecl *NTTP2 =
+ dyn_cast<NonTypeTemplateParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ } else if (TemplateTemplateParmDecl *TTP1 =
+ dyn_cast<TemplateTemplateParmDecl>(D1)) {
+ if (TemplateTemplateParmDecl *TTP2 =
+ dyn_cast<TemplateTemplateParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ }
+
+ if (!Equivalent) {
+ // Note that these two declarations are not equivalent (and we already
+ // know about it).
+ NonEquivalentDecls.insert(
+ std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()));
+ return true;
+ }
+ // FIXME: Check other declaration kinds!
+ }
+
+ return false;
+}
+} // namespace clang
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 2e98f524da..db771b5eb7 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -1,4 +1,7 @@
-set(LLVM_LINK_COMPONENTS support)
+set(LLVM_LINK_COMPONENTS
+ BinaryFormat
+ Support
+ )
add_clang_library(clangAST
APValue.cpp
@@ -7,6 +10,7 @@ add_clang_library(clangAST
ASTDiagnostic.cpp
ASTDumper.cpp
ASTImporter.cpp
+ ASTStructuralEquivalence.cpp
ASTTypeTraits.cpp
AttrImpl.cpp
CXXInheritance.cpp
@@ -16,6 +20,7 @@ add_clang_library(clangAST
CommentLexer.cpp
CommentParser.cpp
CommentSema.cpp
+ DataCollection.cpp
Decl.cpp
DeclarationName.cpp
DeclBase.cpp
@@ -31,6 +36,7 @@ add_clang_library(clangAST
ExprConstant.cpp
ExprCXX.cpp
ExprObjC.cpp
+ ExternalASTMerger.cpp
ExternalASTSource.cpp
InheritViz.cpp
ItaniumCXXABI.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 56fb046407..fc4d8b1373 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SetVector.h"
#include <algorithm>
@@ -56,6 +57,7 @@ bool CXXBasePaths::isAmbiguous(CanQualType BaseType) {
void CXXBasePaths::clear() {
Paths.clear();
ClassSubobjects.clear();
+ VisitedDependentRecords.clear();
ScratchPath.clear();
DetectedVirtual = nullptr;
}
@@ -66,6 +68,7 @@ void CXXBasePaths::swap(CXXBasePaths &Other) {
std::swap(Origin, Other.Origin);
Paths.swap(Other.Paths);
ClassSubobjects.swap(Other.ClassSubobjects);
+ VisitedDependentRecords.swap(Other.VisitedDependentRecords);
std::swap(FindAmbiguities, Other.FindAmbiguities);
std::swap(RecordPaths, Other.RecordPaths);
std::swap(DetectVirtual, Other.DetectVirtual);
@@ -174,9 +177,10 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches,
return AllMatches;
}
-bool CXXBasePaths::lookupInBases(
- ASTContext &Context, const CXXRecordDecl *Record,
- CXXRecordDecl::BaseMatchesCallback BaseMatches) {
+bool CXXBasePaths::lookupInBases(ASTContext &Context,
+ const CXXRecordDecl *Record,
+ CXXRecordDecl::BaseMatchesCallback BaseMatches,
+ bool LookupInDependent) {
bool FoundPath = false;
// The access of the path down to this record.
@@ -194,7 +198,7 @@ bool CXXBasePaths::lookupInBases(
// the base class scope is not examined during unqualified name lookup
// either at the point of definition of the class template or member or
// during an instantiation of the class tem- plate or member.
- if (BaseType->isDependentType())
+ if (!LookupInDependent && BaseType->isDependentType())
continue;
// Determine whether we need to visit this base class at all,
@@ -262,10 +266,34 @@ bool CXXBasePaths::lookupInBases(
return FoundPath;
}
} else if (VisitBase) {
- CXXRecordDecl *BaseRecord
- = cast<CXXRecordDecl>(BaseSpec.getType()->castAs<RecordType>()
- ->getDecl());
- if (lookupInBases(Context, BaseRecord, BaseMatches)) {
+ CXXRecordDecl *BaseRecord;
+ if (LookupInDependent) {
+ BaseRecord = nullptr;
+ const TemplateSpecializationType *TST =
+ BaseSpec.getType()->getAs<TemplateSpecializationType>();
+ if (!TST) {
+ if (auto *RT = BaseSpec.getType()->getAs<RecordType>())
+ BaseRecord = cast<CXXRecordDecl>(RT->getDecl());
+ } else {
+ TemplateName TN = TST->getTemplateName();
+ if (auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()))
+ BaseRecord = TD->getTemplatedDecl();
+ }
+ if (BaseRecord) {
+ if (!BaseRecord->hasDefinition() ||
+ VisitedDependentRecords.count(BaseRecord)) {
+ BaseRecord = nullptr;
+ } else {
+ VisitedDependentRecords.insert(BaseRecord);
+ }
+ }
+ } else {
+ BaseRecord = cast<CXXRecordDecl>(
+ BaseSpec.getType()->castAs<RecordType>()->getDecl());
+ }
+ if (BaseRecord &&
+ lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
// C++ [class.member.lookup]p2:
// A member name f in one sub-object B hides a member name f in
// a sub-object A if A is a base class sub-object of B. Any
@@ -299,9 +327,11 @@ bool CXXBasePaths::lookupInBases(
}
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches,
- CXXBasePaths &Paths) const {
+ CXXBasePaths &Paths,
+ bool LookupInDependent) const {
// If we didn't find anything, report that.
- if (!Paths.lookupInBases(getASTContext(), this, BaseMatches))
+ if (!Paths.lookupInBases(getASTContext(), this, BaseMatches,
+ LookupInDependent))
return false;
// If we're not recording paths or we won't ever find ambiguities,
@@ -387,23 +417,49 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
return false;
}
-bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
- CXXBasePath &Path,
- DeclarationName Name) {
- RecordDecl *BaseRecord =
- Specifier->getType()->castAs<RecordType>()->getDecl();
-
- const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
+static bool findOrdinaryMember(RecordDecl *BaseRecord, CXXBasePath &Path,
+ DeclarationName Name) {
+ const unsigned IDNS = clang::Decl::IDNS_Ordinary | clang::Decl::IDNS_Tag |
+ clang::Decl::IDNS_Member;
for (Path.Decls = BaseRecord->lookup(Name);
!Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS))
return true;
}
-
+
return false;
}
+bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ DeclarationName Name) {
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
+ return findOrdinaryMember(BaseRecord, Path, Name);
+}
+
+bool CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
+ const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
+ DeclarationName Name) {
+ const TemplateSpecializationType *TST =
+ Specifier->getType()->getAs<TemplateSpecializationType>();
+ if (!TST) {
+ auto *RT = Specifier->getType()->getAs<RecordType>();
+ if (!RT)
+ return false;
+ return findOrdinaryMember(RT->getDecl(), Path, Name);
+ }
+ TemplateName TN = TST->getTemplateName();
+ const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return false;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ if (!RD)
+ return false;
+ return findOrdinaryMember(RD, Path, Name);
+}
+
bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
@@ -438,6 +494,36 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
return false;
}
+std::vector<const NamedDecl *> CXXRecordDecl::lookupDependentName(
+ const DeclarationName &Name,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
+ std::vector<const NamedDecl *> Results;
+ // Lookup in the class.
+ DeclContext::lookup_result DirectResult = lookup(Name);
+ if (!DirectResult.empty()) {
+ for (const NamedDecl *ND : DirectResult) {
+ if (Filter(ND))
+ Results.push_back(ND);
+ }
+ return Results;
+ }
+ // Perform lookup into our base classes.
+ CXXBasePaths Paths;
+ Paths.setOrigin(this);
+ if (!lookupInBases(
+ [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
+ return CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
+ Specifier, Path, Name);
+ },
+ Paths, /*LookupInDependent=*/true))
+ return Results;
+ for (const NamedDecl *ND : Paths.front().Decls) {
+ if (Filter(ND))
+ Results.push_back(ND);
+ }
+ return Results;
+}
+
void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 7a7d3dd830..dfa2a1665d 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -116,6 +116,9 @@ bool ParagraphComment::isWhitespaceNoCache() const {
static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {
TypeLoc TL = SrcTL.IgnoreParens();
+ // Look through attribute types.
+ if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>())
+ return AttributeTL.getModifiedLoc();
// Look through qualified types.
if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>())
return QualifiedTL.getUnqualifiedLoc();
@@ -280,8 +283,25 @@ void DeclInfo::fill() {
case Decl::EnumConstant:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField:
+ case Decl::ObjCProperty: {
+ const TypeSourceInfo *TSI;
+ if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))
+ TSI = VD->getTypeSourceInfo();
+ else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))
+ TSI = PD->getTypeSourceInfo();
+ else
+ TSI = nullptr;
+ if (TSI) {
+ TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
+ FunctionTypeLoc FTL;
+ if (getFunctionTypeLoc(TL, FTL)) {
+ ParamVars = FTL.getParams();
+ ReturnType = FTL.getReturnLoc().getType();
+ }
+ }
Kind = VariableKind;
break;
+ }
case Decl::Namespace:
Kind = NamespaceKind;
break;
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index d39a9b26b2..6c2019e1a7 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -86,7 +86,7 @@ ParamCommandComment *Sema::actOnParamCommandStart(
new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
CommandMarker);
- if (!isFunctionDecl())
+ if (!isFunctionDecl() && !isFunctionOrBlockPointerVarLikeDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
<< CommandMarker
@@ -584,7 +584,11 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
assert(ThisDeclInfo && "should not call this check on a bare comment");
- if (isFunctionDecl()) {
+ // We allow the return command for all @properties because it can be used
+ // to document the value that the property getter returns.
+ if (isObjCPropertyDecl())
+ return;
+ if (isFunctionDecl() || isFunctionOrBlockPointerVarLikeDecl()) {
if (ThisDeclInfo->ReturnType->isVoidType()) {
unsigned DiagKind;
switch (ThisDeclInfo->CommentDecl->getKind()) {
@@ -610,8 +614,6 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
return;
}
- else if (isObjCPropertyDecl())
- return;
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
@@ -811,7 +813,7 @@ bool Sema::isAnyFunctionDecl() {
}
bool Sema::isFunctionOrMethodVariadic() {
- if (!isAnyFunctionDecl() && !isObjCMethodDecl() && !isFunctionTemplateDecl())
+ if (!isFunctionDecl() || !ThisDeclInfo->CurrentDecl)
return false;
if (const FunctionDecl *FD =
dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
@@ -822,6 +824,14 @@ bool Sema::isFunctionOrMethodVariadic() {
if (const ObjCMethodDecl *MD =
dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
return MD->isVariadic();
+ if (const TypedefNameDecl *TD =
+ dyn_cast<TypedefNameDecl>(ThisDeclInfo->CurrentDecl)) {
+ QualType Type = TD->getUnderlyingType();
+ if (Type->isFunctionPointerType() || Type->isBlockPointerType())
+ Type = Type->getPointeeType();
+ if (const auto *FT = Type->getAs<FunctionProtoType>())
+ return FT->isVariadic();
+ }
return false;
}
@@ -844,6 +854,30 @@ bool Sema::isFunctionPointerVarDecl() {
return false;
}
+bool Sema::isFunctionOrBlockPointerVarLikeDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (ThisDeclInfo->getKind() != DeclInfo::VariableKind ||
+ !ThisDeclInfo->CurrentDecl)
+ return false;
+ QualType QT;
+ if (const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->CurrentDecl))
+ QT = VD->getType();
+ else if (const auto *PD =
+ dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->CurrentDecl))
+ QT = PD->getType();
+ else
+ return false;
+ // We would like to warn about the 'returns'/'param' commands for
+ // variables that don't directly specify the function type, so type aliases
+ // can be ignored.
+ if (QT->getAs<TypedefType>())
+ return false;
+ return QT->isFunctionPointerType() || QT->isBlockPointerType();
+}
+
bool Sema::isObjCPropertyDecl() {
if (!ThisDeclInfo)
return false;
diff --git a/lib/AST/DataCollection.cpp b/lib/AST/DataCollection.cpp
new file mode 100644
index 0000000000..c2ecabe8e6
--- /dev/null
+++ b/lib/AST/DataCollection.cpp
@@ -0,0 +1,50 @@
+//===-- DataCollection.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/AST/DataCollection.h"
+
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace data_collection {
+
+/// 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(),
+ Context.getLangOpts());
+
+ // Add an empty space at the end as a padding to prevent
+ // that macro names concatenate to the names of other macros.
+ MacroStack << " ";
+}
+
+/// Returns a string that represents all macro expansions that expanded into the
+/// given SourceLocation.
+///
+/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations
+/// A and B are expanded from the same macros in the same order.
+std::string getMacroStack(SourceLocation Loc, ASTContext &Context) {
+ std::string MacroStack;
+ llvm::raw_string_ostream MacroStackStream(MacroStack);
+ SourceManager &SM = Context.getSourceManager();
+
+ // Iterate over all macros that expanded into the given SourceLocation.
+ while (Loc.isMacroID()) {
+ // Add the macro name to the stream.
+ printMacroName(MacroStackStream, Context, Loc);
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+ }
+ MacroStackStream.flush();
+ return MacroStack;
+}
+
+} // end namespace data_collection
+} // end namespace clang
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index cc6f2fa705..32a4907251 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Decl.h"
+#include "Linkage.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
@@ -47,9 +48,7 @@ bool Decl::isOutOfLine() const {
TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx)
: Decl(TranslationUnit, nullptr, SourceLocation()),
- DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {
- Hidden = Ctx.getLangOpts().ModulesLocalVisibility;
-}
+ DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {}
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
@@ -101,63 +100,25 @@ TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx)
// and 'matcher' is a type only matters when looking for attributes
// and settings from the immediate context.
-const unsigned IgnoreExplicitVisibilityBit = 2;
-const unsigned IgnoreAllVisibilityBit = 4;
-
-/// Kinds of LV computation. The linkage side of the computation is
-/// always the same, but different things can change how visibility is
-/// computed.
-enum LVComputationKind {
- /// Do an LV computation for, ultimately, a type.
- /// Visibility may be restricted by type visibility settings and
- /// the visibility of template arguments.
- LVForType = NamedDecl::VisibilityForType,
-
- /// Do an LV computation for, ultimately, a non-type declaration.
- /// Visibility may be restricted by value visibility settings and
- /// the visibility of template arguments.
- LVForValue = NamedDecl::VisibilityForValue,
-
- /// Do an LV computation for, ultimately, a type that already has
- /// some sort of explicit visibility. Visibility may only be
- /// restricted by the visibility of template arguments.
- LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit),
-
- /// Do an LV computation for, ultimately, a non-type declaration
- /// that already has some sort of explicit visibility. Visibility
- /// may only be restricted by the visibility of template arguments.
- LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit),
-
- /// Do an LV computation when we only care about the linkage.
- LVForLinkageOnly =
- LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit
-};
-
/// Does this computation kind permit us to consider additional
/// visibility settings from attributes and the like?
static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
- return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0);
+ return computation.IgnoreExplicitVisibility;
}
/// Given an LVComputationKind, return one of the same type/value sort
/// that records that it already has explicit visibility.
static LVComputationKind
-withExplicitVisibilityAlready(LVComputationKind oldKind) {
- LVComputationKind newKind =
- static_cast<LVComputationKind>(unsigned(oldKind) |
- IgnoreExplicitVisibilityBit);
- assert(oldKind != LVForType || newKind == LVForExplicitType);
- assert(oldKind != LVForValue || newKind == LVForExplicitValue);
- assert(oldKind != LVForExplicitType || newKind == LVForExplicitType);
- assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue);
- return newKind;
+withExplicitVisibilityAlready(LVComputationKind Kind) {
+ Kind.IgnoreExplicitVisibility = true;
+ return Kind;
}
static Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
LVComputationKind kind) {
- assert(!hasExplicitVisibilityAlready(kind) &&
+ assert(!kind.IgnoreExplicitVisibility &&
"asking for explicit visibility when we shouldn't be");
- return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind);
+ return D->getExplicitVisibility(kind.getExplicitVisibilityKind());
}
/// Is the given declaration a "type" or a "value" for the purposes of
@@ -218,30 +179,21 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
return getVisibilityFromAttr(A);
}
- // If we're on Mac OS X, an 'availability' for Mac OS X attribute
- // implies visibility(default).
- if (D->getASTContext().getTargetInfo().getTriple().isOSDarwin()) {
- for (const auto *A : D->specific_attrs<AvailabilityAttr>())
- if (A->getPlatform()->getName().equals("macos"))
- return DefaultVisibility;
- }
-
return None;
}
-static LinkageInfo
-getLVForType(const Type &T, LVComputationKind computation) {
- if (computation == LVForLinkageOnly)
+LinkageInfo LinkageComputer::getLVForType(const Type &T,
+ LVComputationKind computation) {
+ if (computation.IgnoreAllVisibility)
return LinkageInfo(T.getLinkage(), DefaultVisibility, true);
- return T.getLinkageAndVisibility();
+ return getTypeLinkageAndVisibility(&T);
}
/// \brief Get the most restrictive linkage for the types in the given
/// template parameter list. For visibility purposes, template
/// parameters are part of the signature of a template.
-static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *Params,
- LVComputationKind computation) {
+LinkageInfo LinkageComputer::getLVForTemplateParameterList(
+ const TemplateParameterList *Params, LVComputationKind computation) {
LinkageInfo LV;
for (const NamedDecl *P : *Params) {
// Template type parameters are the most common and never
@@ -266,7 +218,7 @@ getLVForTemplateParameterList(const TemplateParameterList *Params,
for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) {
QualType type = NTTP->getExpansionType(i);
if (!type->isDependentType())
- LV.merge(type->getLinkageAndVisibility());
+ LV.merge(getTypeLinkageAndVisibility(type));
}
continue;
}
@@ -293,10 +245,6 @@ getLVForTemplateParameterList(const TemplateParameterList *Params,
return LV;
}
-/// getLVForDecl - Get the linkage and visibility for the given declaration.
-static LinkageInfo getLVForDecl(const NamedDecl *D,
- LVComputationKind computation);
-
static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
const Decl *Ret = nullptr;
const DeclContext *DC = D->getDeclContext();
@@ -313,8 +261,9 @@ static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
///
/// Note that we don't take an LVComputationKind because we always
/// want to honor the visibility of template arguments in the same way.
-static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
- LVComputationKind computation) {
+LinkageInfo
+LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
+ LVComputationKind computation) {
LinkageInfo LV;
for (const TemplateArgument &Arg : Args) {
@@ -336,7 +285,7 @@ static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
continue;
case TemplateArgument::NullPtr:
- LV.merge(Arg.getNullPtrType()->getLinkageAndVisibility());
+ LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType()));
continue;
case TemplateArgument::Template:
@@ -356,9 +305,9 @@ static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
return LV;
}
-static LinkageInfo
-getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
- LVComputationKind computation) {
+LinkageInfo
+LinkageComputer::getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
+ LVComputationKind computation) {
return getLVForTemplateArgumentList(TArgs.asArray(), computation);
}
@@ -381,10 +330,10 @@ static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
/// LVForValue.
///
/// \param[out] LV the computation to use for the parent
-static void
-mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
- const FunctionTemplateSpecializationInfo *specInfo,
- LVComputationKind computation) {
+void LinkageComputer::mergeTemplateLV(
+ LinkageInfo &LV, const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo,
+ LVComputationKind computation) {
bool considerVisibility =
shouldConsiderTemplateVisibility(fn, specInfo);
@@ -404,21 +353,11 @@ mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
/// that would match the given rules?
static bool hasDirectVisibilityAttribute(const NamedDecl *D,
LVComputationKind computation) {
- switch (computation) {
- case LVForType:
- case LVForExplicitType:
- if (D->hasAttr<TypeVisibilityAttr>())
- return true;
- // fallthrough
- case LVForValue:
- case LVForExplicitValue:
- if (D->hasAttr<VisibilityAttr>())
- return true;
- return false;
- case LVForLinkageOnly:
+ if (computation.IgnoreAllVisibility)
return false;
- }
- llvm_unreachable("bad visibility computation kind");
+
+ return (computation.isTypeVisibility() && D->hasAttr<TypeVisibilityAttr>()) ||
+ D->hasAttr<VisibilityAttr>();
}
/// Should we consider visibility associated with the template
@@ -459,9 +398,9 @@ static bool shouldConsiderTemplateVisibility(
/// Merge in template-related linkage and visibility for the given
/// class template specialization.
-static void mergeTemplateLV(LinkageInfo &LV,
- const ClassTemplateSpecializationDecl *spec,
- LVComputationKind computation) {
+void LinkageComputer::mergeTemplateLV(
+ LinkageInfo &LV, const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
// Merge information from the template parameters, but ignore
@@ -511,9 +450,9 @@ static bool shouldConsiderTemplateVisibility(
/// Merge in template-related linkage and visibility for the given
/// variable template specialization. As usual, follow class template
/// specialization logic up to initialization.
-static void mergeTemplateLV(LinkageInfo &LV,
- const VarTemplateSpecializationDecl *spec,
- LVComputationKind computation) {
+void LinkageComputer::mergeTemplateLV(LinkageInfo &LV,
+ const VarTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
// Merge information from the template parameters, but ignore
@@ -575,8 +514,50 @@ static bool isSingleLineLanguageLinkage(const Decl &D) {
return false;
}
-static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
- LVComputationKind computation) {
+static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) {
+ // FIXME: Handle isModulePrivate.
+ switch (D->getModuleOwnershipKind()) {
+ case Decl::ModuleOwnershipKind::Unowned:
+ case Decl::ModuleOwnershipKind::ModulePrivate:
+ return false;
+ case Decl::ModuleOwnershipKind::Visible:
+ case Decl::ModuleOwnershipKind::VisibleWhenImported:
+ if (auto *M = D->getOwningModule())
+ return M->Kind == Module::ModuleInterfaceUnit;
+ }
+ llvm_unreachable("unexpected module ownership kind");
+}
+
+static LinkageInfo getInternalLinkageFor(const NamedDecl *D) {
+ // Internal linkage declarations within a module interface unit are modeled
+ // as "module-internal linkage", which means that they have internal linkage
+ // formally but can be indirectly accessed from outside the module via inline
+ // functions and templates defined within the module.
+ if (auto *M = D->getOwningModule())
+ if (M->Kind == Module::ModuleInterfaceUnit)
+ return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false);
+
+ return LinkageInfo::internal();
+}
+
+static LinkageInfo getExternalLinkageFor(const NamedDecl *D) {
+ // C++ Modules TS [basic.link]/6.8:
+ // - A name declared at namespace scope that does not have internal linkage
+ // by the previous rules and that is introduced by a non-exported
+ // declaration has module linkage.
+ if (auto *M = D->getOwningModule())
+ if (M->Kind == Module::ModuleInterfaceUnit)
+ if (!isExportedFromModuleIntefaceUnit(
+ cast<NamedDecl>(D->getCanonicalDecl())))
+ return LinkageInfo(ModuleLinkage, DefaultVisibility, false);
+
+ return LinkageInfo::external();
+}
+
+LinkageInfo
+LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
+ LVComputationKind computation,
+ bool IgnoreVarTypeLinkage) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -590,16 +571,18 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (const auto *Var = dyn_cast<VarDecl>(D)) {
// Explicitly declared static.
if (Var->getStorageClass() == SC_Static)
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Var);
// - a non-inline, non-volatile object or reference that is explicitly
// declared const or constexpr and neither explicitly declared extern
// nor previously declared to have external linkage; or (there is no
// equivalent in C99)
+ // The C++ modules TS adds "non-exported" to this list.
if (Context.getLangOpts().CPlusPlus &&
Var->getType().isConstQualified() &&
!Var->getType().isVolatileQualified() &&
- !Var->isInline()) {
+ !Var->isInline() &&
+ !isExportedFromModuleIntefaceUnit(Var)) {
const VarDecl *PrevVar = Var->getPreviousDecl();
if (PrevVar)
return getLVForDecl(PrevVar, computation);
@@ -607,17 +590,17 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern &&
!isSingleLineLanguageLinkage(*Var))
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Var);
}
for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar;
PrevVar = PrevVar->getPreviousDecl()) {
if (PrevVar->getStorageClass() == SC_PrivateExtern &&
Var->getStorageClass() == SC_None)
- return PrevVar->getLinkageAndVisibility();
+ return getDeclLinkageAndVisibility(PrevVar);
// Explicitly declared static.
if (PrevVar->getStorageClass() == SC_Static)
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Var);
}
} else if (const FunctionDecl *Function = D->getAsFunction()) {
// C++ [temp]p4:
@@ -626,23 +609,28 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Explicitly declared static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
- return LinkageInfo(InternalLinkage, DefaultVisibility, false);
+ return getInternalLinkageFor(Function);
} else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) {
// - a data member of an anonymous union.
const VarDecl *VD = IFD->getVarDecl();
assert(VD && "Expected a VarDecl in this IndirectFieldDecl!");
- return getLVForNamespaceScopeDecl(VD, computation);
+ return getLVForNamespaceScopeDecl(VD, computation, IgnoreVarTypeLinkage);
}
assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
if (D->isInAnonymousNamespace()) {
const auto *Var = dyn_cast<VarDecl>(D);
const auto *Func = dyn_cast<FunctionDecl>(D);
- // FIXME: In C++11 onwards, anonymous namespaces should give decls
- // within them internal linkage, not unique external linkage.
+ // FIXME: The check for extern "C" here is not justified by the standard
+ // wording, but we retain it from the pre-DR1113 model to avoid breaking
+ // code.
+ //
+ // C++11 [basic.link]p4:
+ // An unnamed namespace or a namespace declared directly or indirectly
+ // within an unnamed namespace has internal linkage.
if ((!Var || !isFirstInExternCContext(Var)) &&
(!Func || !isFirstInExternCContext(Func)))
- return LinkageInfo::uniqueExternal();
+ return getInternalLinkageFor(D);
}
// Set up the defaults.
@@ -651,7 +639,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// If the declaration of an identifier for an object has file
// scope and no storage-class specifier, its linkage is
// external.
- LinkageInfo LV;
+ LinkageInfo LV = getExternalLinkageFor(D);
if (!hasExplicitVisibilityAlready(computation)) {
if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
@@ -674,13 +662,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Add in global settings if the above didn't give us direct visibility.
if (!LV.isVisibilityExplicit()) {
// Use global type/value visibility as appropriate.
- Visibility globalVisibility;
- if (computation == LVForValue) {
- globalVisibility = Context.getLangOpts().getValueVisibilityMode();
- } else {
- assert(computation == LVForType);
- globalVisibility = Context.getLangOpts().getTypeVisibilityMode();
- }
+ Visibility globalVisibility =
+ computation.isValueVisibility()
+ ? Context.getLangOpts().getValueVisibilityMode()
+ : Context.getLangOpts().getTypeVisibilityMode();
LV.mergeVisibility(globalVisibility, /*explicit*/ false);
// If we're paying attention to global visibility, apply
@@ -718,9 +703,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
- if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) {
+ if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var) &&
+ !IgnoreVarTypeLinkage) {
LinkageInfo TypeLV = getLVForType(*Var->getType(), computation);
- if (TypeLV.getLinkage() != ExternalLinkage)
+ if (!isExternallyVisible(TypeLV.getLinkage()))
return LinkageInfo::uniqueExternal();
if (!LV.isVisibilityExplicit())
LV.mergeVisibility(TypeLV);
@@ -758,19 +744,13 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// unique-external linkage, it's not legally usable from outside
// this translation unit. However, we should use the C linkage
// rules instead for extern "C" declarations.
- if (Context.getLangOpts().CPlusPlus &&
- !Function->isInExternCContext()) {
- // Only look at the type-as-written. If this function has an auto-deduced
- // return type, we can't compute the linkage of that type because it could
- // require looking at the linkage of this function, and we don't need this
- // for correctness because the type is not part of the function's
- // signature.
- // FIXME: This is a hack. We should be able to solve this circularity and
- // the one in getLVForClassMember for Functions some other way.
+ if (Context.getLangOpts().CPlusPlus && !Function->isInExternCContext()) {
+ // Only look at the type-as-written. Otherwise, deducing the return type
+ // of a function could change its linkage.
QualType TypeAsWritten = Function->getType();
if (TypeSourceInfo *TSI = Function->getTypeSourceInfo())
TypeAsWritten = TSI->getType();
- if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
+ if (!isExternallyVisible(TypeAsWritten->getLinkage()))
return LinkageInfo::uniqueExternal();
}
@@ -818,7 +798,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
- } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
+ //
+ // We handled names in anonymous namespaces above.
+ } else if (isa<NamespaceDecl>(D)) {
return LV;
// By extension, we assign external linkage to Objective-C
@@ -837,16 +819,18 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
return LinkageInfo::none();
}
- // If we ended up with non-external linkage, visibility should
+ // If we ended up with non-externally-visible linkage, visibility should
// always be default.
- if (LV.getLinkage() != ExternalLinkage)
+ if (!isExternallyVisible(LV.getLinkage()))
return LinkageInfo(LV.getLinkage(), DefaultVisibility, false);
return LV;
}
-static LinkageInfo getLVForClassMember(const NamedDecl *D,
- LVComputationKind computation) {
+LinkageInfo
+LinkageComputer::getLVForClassMember(const NamedDecl *D,
+ LVComputationKind computation,
+ bool IgnoreVarTypeLinkage) {
// Only certain class members have linkage. Note that fields don't
// really have linkage, but it's convenient to say they do for the
// purposes of calculating linkage of pointer-to-data-member
@@ -889,12 +873,11 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
LinkageInfo classLV =
getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
- // If the class already has unique-external linkage, we can't improve.
- if (classLV.getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
-
+ // The member has the same linkage as the class. If that's not externally
+ // visible, we don't need to compute anything about the linkage.
+ // FIXME: If we're only computing linkage, can we bail out here?
if (!isExternallyVisible(classLV.getLinkage()))
- return LinkageInfo::none();
+ return classLV;
// Otherwise, don't merge in classLV yet, because in certain cases
@@ -904,22 +887,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
const NamedDecl *explicitSpecSuppressor = nullptr;
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
- // If the type of the function uses a type with unique-external
- // linkage, it's not legally usable from outside this translation unit.
- // But only look at the type-as-written. If this function has an
- // auto-deduced return type, we can't compute the linkage of that type
- // because it could require looking at the linkage of this function, and we
- // don't need this for correctness because the type is not part of the
- // function's signature.
- // FIXME: This is a hack. We should be able to solve this circularity and
- // the one in getLVForNamespaceScopeDecl for Functions some other way.
- {
- QualType TypeAsWritten = MD->getType();
- if (TypeSourceInfo *TSI = MD->getTypeSourceInfo())
- TypeAsWritten = TSI->getType();
- if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
- }
+ // Only look at the type-as-written. Otherwise, deducing the return type
+ // of a function could change its linkage.
+ QualType TypeAsWritten = MD->getType();
+ if (TypeSourceInfo *TSI = MD->getTypeSourceInfo())
+ TypeAsWritten = TSI->getType();
+ if (!isExternallyVisible(TypeAsWritten->getLinkage()))
+ return LinkageInfo::uniqueExternal();
+
// If this is a method template specialization, use the linkage for
// the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *spec
@@ -956,10 +931,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
- LinkageInfo typeLV = getLVForType(*VD->getType(), computation);
- if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit())
- LV.mergeVisibility(typeLV);
- LV.mergeExternalVisibility(typeLV);
+ if (!IgnoreVarTypeLinkage) {
+ LinkageInfo typeLV = getLVForType(*VD->getType(), computation);
+ // FIXME: If the type's linkage is not externally visible, we can
+ // give this static data member UniqueExternalLinkage.
+ if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit())
+ LV.mergeVisibility(typeLV);
+ LV.mergeExternalVisibility(typeLV);
+ }
if (isExplicitMemberSpecialization(VD)) {
explicitSpecSuppressor = VD;
@@ -1003,15 +982,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
void NamedDecl::anchor() { }
-static LinkageInfo computeLVForDecl(const NamedDecl *D,
- LVComputationKind computation);
-
bool NamedDecl::isLinkageValid() const {
if (!hasCachedLinkage())
return true;
- return computeLVForDecl(this, LVForLinkageOnly).getLinkage() ==
- getCachedLinkage();
+ Linkage L = LinkageComputer{}
+ .computeLVForDecl(this, LVComputationKind::forLinkageOnly())
+ .getLinkage();
+ return L == getCachedLinkage();
}
ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const {
@@ -1030,13 +1008,13 @@ ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const {
Linkage NamedDecl::getLinkageInternal() const {
// We don't care about visibility here, so ask for the cheapest
// possible visibility analysis.
- return getLVForDecl(this, LVForLinkageOnly).getLinkage();
+ return LinkageComputer{}
+ .getLVForDecl(this, LVComputationKind::forLinkageOnly())
+ .getLinkage();
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
- LVComputationKind computation =
- (usesTypeVisibility(this) ? LVForType : LVForValue);
- return getLVForDecl(this, computation);
+ return LinkageComputer{}.getDeclLinkageAndVisibility(this);
}
static Optional<Visibility>
@@ -1114,32 +1092,50 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return getExplicitVisibilityAux(this, kind, false);
}
-static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
- LVComputationKind computation) {
+LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC,
+ Decl *ContextDecl,
+ LVComputationKind computation) {
// This lambda has its linkage/visibility determined by its owner.
- if (ContextDecl) {
- if (isa<ParmVarDecl>(ContextDecl))
- DC = ContextDecl->getDeclContext()->getRedeclContext();
- else
- return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
- }
+ const NamedDecl *Owner;
+ if (!ContextDecl)
+ Owner = dyn_cast<NamedDecl>(DC);
+ else if (isa<ParmVarDecl>(ContextDecl))
+ Owner =
+ dyn_cast<NamedDecl>(ContextDecl->getDeclContext()->getRedeclContext());
+ else
+ Owner = cast<NamedDecl>(ContextDecl);
- if (const auto *ND = dyn_cast<NamedDecl>(DC))
- return getLVForDecl(ND, computation);
+ if (!Owner)
+ return LinkageInfo::none();
- return LinkageInfo::external();
+ // If the owner has a deduced type, we need to skip querying the linkage and
+ // visibility of that type, because it might involve this closure type. The
+ // only effect of this is that we might give a lambda VisibleNoLinkage rather
+ // than NoLinkage when we don't strictly need to, which is benign.
+ auto *VD = dyn_cast<VarDecl>(Owner);
+ LinkageInfo OwnerLV =
+ VD && VD->getType()->getContainedDeducedType()
+ ? computeLVForDecl(Owner, computation, /*IgnoreVarTypeLinkage*/true)
+ : getLVForDecl(Owner, computation);
+
+ // A lambda never formally has linkage. But if the owner is externally
+ // visible, then the lambda is too. We apply the same rules to blocks.
+ if (!isExternallyVisible(OwnerLV.getLinkage()))
+ return LinkageInfo::none();
+ return LinkageInfo(VisibleNoLinkage, OwnerLV.getVisibility(),
+ OwnerLV.isVisibilityExplicit());
}
-static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
- LVComputationKind computation) {
+LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
+ LVComputationKind computation) {
if (const auto *Function = dyn_cast<FunctionDecl>(D)) {
if (Function->isInAnonymousNamespace() &&
!Function->isInExternCContext())
- return LinkageInfo::uniqueExternal();
+ return getInternalLinkageFor(Function);
// This is a "void f();" which got merged with a file static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Function);
LinkageInfo LV;
if (!hasExplicitVisibilityAlready(computation)) {
@@ -1158,7 +1154,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
if (const auto *Var = dyn_cast<VarDecl>(D)) {
if (Var->hasExternalStorage()) {
if (Var->isInAnonymousNamespace() && !Var->isInExternCContext())
- return LinkageInfo::uniqueExternal();
+ return getInternalLinkageFor(Var);
LinkageInfo LV;
if (Var->getStorageClass() == SC_PrivateExtern)
@@ -1224,11 +1220,12 @@ getOutermostEnclosingLambda(const CXXRecordDecl *Record) {
return Ret;
}
-static LinkageInfo computeLVForDecl(const NamedDecl *D,
- LVComputationKind computation) {
+LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation,
+ bool IgnoreVarTypeLinkage) {
// Internal_linkage attribute overrides other considerations.
if (D->hasAttr<InternalLinkageAttr>())
- return LinkageInfo::internal();
+ return getInternalLinkageFor(D);
// Objective-C: treat all Objective-C declarations as having external
// linkage.
@@ -1253,14 +1250,15 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
case Decl::EnumConstant:
// C++ [basic.link]p4: an enumerator has the linkage of its enumeration.
- return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation);
+ if (D->getASTContext().getLangOpts().CPlusPlus)
+ return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation);
+ return LinkageInfo::visible_none();
case Decl::Typedef:
case Decl::TypeAlias:
// A typedef declaration has linkage if it gives a type a name for
// linkage purposes.
- if (!D->getASTContext().getLangOpts().CPlusPlus ||
- !cast<TypedefNameDecl>(D)
+ if (!cast<TypedefNameDecl>(D)
->getAnonDeclWithTypedefName(/*AnyRedecl*/true))
return LinkageInfo::none();
break;
@@ -1276,14 +1274,14 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
case Decl::ObjCProperty:
case Decl::ObjCPropertyImpl:
case Decl::ObjCProtocol:
- return LinkageInfo::external();
+ return getExternalLinkageFor(D);
case Decl::CXXRecord: {
const auto *Record = cast<CXXRecordDecl>(D);
if (Record->isLambda()) {
if (!Record->getLambdaManglingNumber()) {
// This lambda has no mangling number, so it's internal.
- return LinkageInfo::internal();
+ return getInternalLinkageFor(D);
}
// This lambda has its linkage/visibility determined:
@@ -1299,7 +1297,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
const CXXRecordDecl *OuterMostLambda =
getOutermostEnclosingLambda(Record);
if (!OuterMostLambda->getLambdaManglingNumber())
- return LinkageInfo::internal();
+ return getInternalLinkageFor(D);
return getLVForClosure(
OuterMostLambda->getDeclContext()->getRedeclContext(),
@@ -1312,7 +1310,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
// Handle linkage for namespace-scope names.
if (D->getDeclContext()->getRedeclContext()->isFileContext())
- return getLVForNamespaceScopeDecl(D, computation);
+ return getLVForNamespaceScopeDecl(D, computation, IgnoreVarTypeLinkage);
// C++ [basic.link]p5:
// In addition, a member function, static data member, a named
@@ -1322,7 +1320,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
// purposes (7.1.3), has external linkage if the name of the class
// has external linkage.
if (D->getDeclContext()->isRecord())
- return getLVForClassMember(D, computation);
+ return getLVForClassMember(D, computation, IgnoreVarTypeLinkage);
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
@@ -1343,56 +1341,92 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
return LinkageInfo::none();
}
-namespace clang {
-class LinkageComputer {
-public:
- static LinkageInfo getLVForDecl(const NamedDecl *D,
- LVComputationKind computation) {
- // Internal_linkage attribute overrides other considerations.
- if (D->hasAttr<InternalLinkageAttr>())
- return LinkageInfo::internal();
+/// getLVForDecl - Get the linkage and visibility for the given declaration.
+LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ // Internal_linkage attribute overrides other considerations.
+ if (D->hasAttr<InternalLinkageAttr>())
+ return getInternalLinkageFor(D);
- if (computation == LVForLinkageOnly && D->hasCachedLinkage())
- return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
+ if (computation.IgnoreAllVisibility && D->hasCachedLinkage())
+ return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
- LinkageInfo LV = computeLVForDecl(D, computation);
- if (D->hasCachedLinkage())
- assert(D->getCachedLinkage() == LV.getLinkage());
+ if (llvm::Optional<LinkageInfo> LI = lookup(D, computation))
+ return *LI;
- D->setCachedLinkage(LV.getLinkage());
+ LinkageInfo LV = computeLVForDecl(D, computation);
+ if (D->hasCachedLinkage())
+ assert(D->getCachedLinkage() == LV.getLinkage());
+
+ D->setCachedLinkage(LV.getLinkage());
+ cache(D, computation, LV);
#ifndef NDEBUG
- // In C (because of gnu inline) and in c++ with microsoft extensions an
- // static can follow an extern, so we can have two decls with different
- // linkages.
- const LangOptions &Opts = D->getASTContext().getLangOpts();
- if (!Opts.CPlusPlus || Opts.MicrosoftExt)
- return LV;
+ // In C (because of gnu inline) and in c++ with microsoft extensions an
+ // static can follow an extern, so we can have two decls with different
+ // linkages.
+ const LangOptions &Opts = D->getASTContext().getLangOpts();
+ if (!Opts.CPlusPlus || Opts.MicrosoftExt)
+ return LV;
- // We have just computed the linkage for this decl. By induction we know
- // that all other computed linkages match, check that the one we just
- // computed also does.
- NamedDecl *Old = nullptr;
- for (auto I : D->redecls()) {
- auto *T = cast<NamedDecl>(I);
- if (T == D)
- continue;
- if (!T->isInvalidDecl() && T->hasCachedLinkage()) {
- Old = T;
- break;
- }
+ // We have just computed the linkage for this decl. By induction we know
+ // that all other computed linkages match, check that the one we just
+ // computed also does.
+ NamedDecl *Old = nullptr;
+ for (auto I : D->redecls()) {
+ auto *T = cast<NamedDecl>(I);
+ if (T == D)
+ continue;
+ if (!T->isInvalidDecl() && T->hasCachedLinkage()) {
+ Old = T;
+ break;
}
- assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage());
+ }
+ assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage());
#endif
- return LV;
- }
-};
+ return LV;
}
-static LinkageInfo getLVForDecl(const NamedDecl *D,
- LVComputationKind computation) {
- return clang::LinkageComputer::getLVForDecl(D, computation);
+LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) {
+ return getLVForDecl(D,
+ LVComputationKind(usesTypeVisibility(D)
+ ? NamedDecl::VisibilityForType
+ : NamedDecl::VisibilityForValue));
+}
+
+Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
+ Module *M = getOwningModule();
+ if (!M)
+ return nullptr;
+
+ switch (M->Kind) {
+ case Module::ModuleMapModule:
+ // Module map modules have no special linkage semantics.
+ return nullptr;
+
+ case Module::ModuleInterfaceUnit:
+ return M;
+
+ case Module::GlobalModuleFragment:
+ // External linkage declarations in the global module have no owning module
+ // for linkage purposes. But internal linkage declarations in the global
+ // module fragment of a particular module are owned by that module for
+ // linkage purposes.
+ if (IgnoreLinkage)
+ return nullptr;
+ bool InternalLinkage;
+ if (auto *ND = dyn_cast<NamedDecl>(this))
+ InternalLinkage = !ND->hasExternalFormalLinkage();
+ else {
+ auto *NSD = dyn_cast<NamespaceDecl>(this);
+ InternalLinkage = (NSD && NSD->isAnonymousNamespace()) ||
+ isInAnonymousNamespace();
+ }
+ return InternalLinkage ? M->Parent : nullptr;
+ }
+
+ llvm_unreachable("unknown module kind");
}
void NamedDecl::printName(raw_ostream &os) const {
@@ -1563,14 +1597,6 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
cast<UnresolvedUsingValueDecl>(OldD)->getQualifier());
}
- // UsingDirectiveDecl's are not really NamedDecl's, and all have same name.
- // They can be replaced if they nominate the same namespace.
- // FIXME: Is this true even if they have different module visibility?
- if (auto *UD = dyn_cast<UsingDirectiveDecl>(this))
- return UD->getNominatedNamespace()->getOriginalNamespace() ==
- cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace()
- ->getOriginalNamespace();
-
if (isRedeclarable(getKind())) {
if (getCanonicalDecl() != OldD->getCanonicalDecl())
return false;
@@ -2251,6 +2277,14 @@ bool VarDecl::checkInitIsICE() const {
return Eval->IsICE;
}
+template<typename DeclT>
+static DeclT *getDefinitionOrSelf(DeclT *D) {
+ assert(D);
+ if (auto *Def = D->getDefinition())
+ return Def;
+ return D;
+}
+
VarDecl *VarDecl::getTemplateInstantiationPattern() const {
// If it's a variable template specialization, find the template or partial
// specialization from which it was instantiated.
@@ -2262,7 +2296,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
break;
VTD = NewVTD;
}
- return VTD->getTemplatedDecl()->getDefinition();
+ return getDefinitionOrSelf(VTD->getTemplatedDecl());
}
if (auto *VTPSD =
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
@@ -2271,7 +2305,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
break;
VTPSD = NewVTPSD;
}
- return VTPSD->getDefinition();
+ return getDefinitionOrSelf<VarDecl>(VTPSD);
}
}
@@ -2280,23 +2314,18 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
VarDecl *VD = getInstantiatedFromStaticDataMember();
while (auto *NewVD = VD->getInstantiatedFromStaticDataMember())
VD = NewVD;
- return VD->getDefinition();
+ return getDefinitionOrSelf(VD);
}
}
if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) {
-
while (VarTemplate->getInstantiatedFromMemberTemplate()) {
if (VarTemplate->isMemberSpecialization())
break;
VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate();
}
- assert((!VarTemplate->getTemplatedDecl() ||
- !isTemplateInstantiation(getTemplateSpecializationKind())) &&
- "couldn't find pattern for variable instantiation");
-
- return VarTemplate->getTemplatedDecl();
+ return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
}
return nullptr;
}
@@ -2533,9 +2562,8 @@ bool FunctionDecl::hasTrivialBody() const
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
for (auto I : redecls()) {
- if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
- I->hasDefiningAttr()) {
- Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
+ if (I->isThisDeclarationADefinition()) {
+ Definition = I;
return true;
}
}
@@ -2630,7 +2658,7 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy);
}
-bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
+bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const {
if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
return false;
if (getDeclName().getCXXOverloadedOperator() != OO_New &&
@@ -2676,8 +2704,11 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
// In C++17, the next parameter can be a 'std::align_val_t' for aligned
// new/delete.
- if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT())
+ if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) {
+ if (IsAligned)
+ *IsAligned = true;
Consume();
+ }
// Finally, if this is not a sized delete, the final parameter can
// be a 'const std::nothrow_t&'.
@@ -2693,6 +2724,20 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
return Params == FPT->getNumParams();
}
+bool FunctionDecl::isDestroyingOperatorDelete() const {
+ // C++ P0722:
+ // Within a class C, a single object deallocation function with signature
+ // (T, std::destroying_delete_t, <more params>)
+ // is a destroying operator delete.
+ if (!isa<CXXMethodDecl>(this) || getOverloadedOperator() != OO_Delete ||
+ getNumParams() < 2)
+ return false;
+
+ auto *RD = getParamDecl(1)->getType()->getAsCXXRecordDecl();
+ return RD && RD->isInStdNamespace() && RD->getIdentifier() &&
+ RD->getIdentifier()->isStr("destroying_delete_t");
+}
+
LanguageLinkage FunctionDecl::getLanguageLinkage() const {
return getDeclLanguageLinkage(*this);
}
@@ -3003,9 +3048,8 @@ SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
const Attr *FunctionDecl::getUnusedResultAttr() const {
QualType RetType = getReturnType();
if (RetType->isRecordType()) {
- const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl();
- const auto *MD = dyn_cast<CXXMethodDecl>(this);
- if (Ret && !(MD && MD->getCorrespondingMethodInClass(Ret, true))) {
+ if (const auto *Ret =
+ dyn_cast_or_null<RecordDecl>(RetType->getAsTagDecl())) {
if (const auto *R = Ret->getAttr<WarnUnusedResultAttr>())
return R;
}
@@ -3200,9 +3244,12 @@ bool FunctionDecl::isTemplateInstantiation() const {
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
// Handle class scope explicit specialization special case.
- if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return getClassScopeSpecializationPattern();
-
+ if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ if (auto *Spec = getClassScopeSpecializationPattern())
+ return getDefinitionOrSelf(Spec);
+ return nullptr;
+ }
+
// If this is a generic lambda call operator specialization, its
// instantiation pattern is always its primary template's pattern
// even if its primary template was instantiated from another
@@ -3214,16 +3261,10 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
if (isGenericLambdaCallOperatorSpecialization(
dyn_cast<CXXMethodDecl>(this))) {
- assert(getPrimaryTemplate() && "A generic lambda specialization must be "
- "generated from a primary call operator "
- "template");
- assert(getPrimaryTemplate()->getTemplatedDecl()->getBody() &&
- "A generic lambda call operator template must always have a body - "
- "even if instantiated from a prototype (i.e. as written) member "
- "template");
- return getPrimaryTemplate()->getTemplatedDecl();
+ assert(getPrimaryTemplate() && "not a generic lambda call operator?");
+ return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl());
}
-
+
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
while (Primary->getInstantiatedFromMemberTemplate()) {
// If we have hit a point where the user provided a specialization of
@@ -3232,11 +3273,14 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
break;
Primary = Primary->getInstantiatedFromMemberTemplate();
}
-
- return Primary->getTemplatedDecl();
+
+ return getDefinitionOrSelf(Primary->getTemplatedDecl());
}
-
- return getInstantiatedFromMemberFunction();
+
+ if (auto *MFD = getInstantiatedFromMemberFunction())
+ return getDefinitionOrSelf(MFD);
+
+ return nullptr;
}
FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
@@ -3546,8 +3590,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
assert(isBitField() && "not a bitfield");
- auto *BitWidth = static_cast<Expr *>(InitStorage.getPointer());
- return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue();
+ return getBitWidth()->EvaluateKnownConstInt(Ctx).getZExtValue();
}
unsigned FieldDecl::getFieldIndex() const {
@@ -3570,25 +3613,18 @@ unsigned FieldDecl::getFieldIndex() const {
}
SourceRange FieldDecl::getSourceRange() const {
- switch (InitStorage.getInt()) {
- // All three of these cases store an optional Expr*.
- case ISK_BitWidthOrNothing:
- case ISK_InClassCopyInit:
- case ISK_InClassListInit:
- if (const auto *E = static_cast<const Expr *>(InitStorage.getPointer()))
- return SourceRange(getInnerLocStart(), E->getLocEnd());
- // FALLTHROUGH
-
- case ISK_CapturedVLAType:
- return DeclaratorDecl::getSourceRange();
- }
- llvm_unreachable("bad init storage kind");
+ const Expr *FinalExpr = getInClassInitializer();
+ if (!FinalExpr)
+ FinalExpr = getBitWidth();
+ if (FinalExpr)
+ return SourceRange(getInnerLocStart(), FinalExpr->getLocEnd());
+ return DeclaratorDecl::getSourceRange();
}
void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) {
assert((getParent()->isLambda() || getParent()->isCapturedRecord()) &&
"capturing type in non-lambda or captured record.");
- assert(InitStorage.getInt() == ISK_BitWidthOrNothing &&
+ assert(InitStorage.getInt() == ISK_NoInit &&
InitStorage.getPointer() == nullptr &&
"bit width, initializer or captured type already set");
InitStorage.setPointerAndInt(const_cast<VariableArrayType *>(VLAType),
@@ -3742,6 +3778,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();
@@ -3766,7 +3816,7 @@ EnumDecl *EnumDecl::getTemplateInstantiationPattern() const {
EnumDecl *ED = getInstantiatedFromMemberEnum();
while (auto *NewED = ED->getInstantiatedFromMemberEnum())
ED = NewED;
- return ED;
+ return getDefinitionOrSelf(ED);
}
}
@@ -3892,9 +3942,9 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().Sanitize.hasOneOf(
- SanitizerKind::Address | SanitizerKind::KernelAddress) ||
- !Context.getLangOpts().SanitizeAddressFieldPadding)
+ const SanitizerMask EnabledAsanMask = Context.getLangOpts().Sanitize.Mask &
+ (SanitizerKind::Address | SanitizerKind::KernelAddress);
+ if (!EnabledAsanMask || !Context.getLangOpts().SanitizeAddressFieldPadding)
return false;
const auto &Blacklist = Context.getSanitizerBlacklist();
const auto *CXXRD = dyn_cast<CXXRecordDecl>(this);
@@ -3912,9 +3962,11 @@ bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
ReasonToReject = 4; // has trivial destructor.
else if (CXXRD->isStandardLayout())
ReasonToReject = 5; // is standard layout.
- else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding"))
+ else if (Blacklist.isBlacklistedLocation(EnabledAsanMask, getLocation(),
+ "field-padding"))
ReasonToReject = 6; // is in a blacklisted file.
- else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(),
+ else if (Blacklist.isBlacklistedType(EnabledAsanMask,
+ getQualifiedNameAsString(),
"field-padding"))
ReasonToReject = 7; // is blacklisted.
@@ -4094,15 +4146,19 @@ void ImplicitParamDecl::anchor() { }
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc,
- IdentifierInfo *Id,
- QualType Type) {
- return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type);
+ IdentifierInfo *Id, QualType Type,
+ ImplicitParamKind ParamKind) {
+ return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type, ParamKind);
+}
+
+ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, QualType Type,
+ ImplicitParamKind ParamKind) {
+ return new (C, nullptr) ImplicitParamDecl(C, Type, ParamKind);
}
ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- return new (C, ID) ImplicitParamDecl(C, nullptr, SourceLocation(), nullptr,
- QualType());
+ return new (C, ID) ImplicitParamDecl(C, QualType(), ImplicitParamKind::Other);
}
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
@@ -4228,6 +4284,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 cda70c5edc..1e15ee98bb 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -74,8 +74,9 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
DeclContext *Parent, std::size_t Extra) {
assert(!Parent || &Parent->getParentASTContext() == &Ctx);
// With local visibility enabled, we track the owning module even for local
- // declarations.
- if (Ctx.getLangOpts().ModulesLocalVisibility) {
+ // declarations. We create the TU decl early and may not yet know what the
+ // LangOpts are, so conservatively allocate the storage.
+ if (Ctx.getLangOpts().trackLocalOwningModule() || !Parent) {
// Ensure required alignment of the resulting object by adding extra
// padding at the start if required.
size_t ExtraAlign =
@@ -83,7 +84,9 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
char *Buffer = reinterpret_cast<char *>(
::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx));
Buffer += ExtraAlign;
- return new (Buffer) Module*(nullptr) + 1;
+ auto *ParentModule =
+ Parent ? cast<Decl>(Parent)->getOwningModule() : nullptr;
+ return new (Buffer) Module*(ParentModule) + 1;
}
return ::operator new(Size + Extra, Ctx);
}
@@ -94,7 +97,7 @@ Module *Decl::getOwningModuleSlow() const {
}
bool Decl::hasLocalOwningModuleStorage() const {
- return getASTContext().getLangOpts().ModulesLocalVisibility;
+ return getASTContext().getLangOpts().trackLocalOwningModule();
}
const char *Decl::getDeclKindName() const {
@@ -272,7 +275,19 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
} else {
getMultipleDC()->LexicalDC = DC;
}
- Hidden = cast<Decl>(DC)->Hidden;
+
+ // FIXME: We shouldn't be changing the lexical context of declarations
+ // imported from AST files.
+ if (!isFromASTFile()) {
+ setModuleOwnershipKind(getModuleOwnershipKindForChildOf(DC));
+ if (hasOwningModule())
+ setLocalOwningModule(cast<Decl>(DC)->getOwningModule());
+ }
+
+ assert(
+ (getModuleOwnershipKind() != ModuleOwnershipKind::VisibleWhenImported ||
+ getOwningModule()) &&
+ "hidden declaration has no owning module");
}
void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
@@ -300,12 +315,11 @@ bool Decl::isLexicallyWithinFunctionOrMethod() const {
}
bool Decl::isInAnonymousNamespace() const {
- const DeclContext *DC = getDeclContext();
- do {
+ for (const DeclContext *DC = getDeclContext(); DC; DC = DC->getParent()) {
if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
if (ND->isAnonymousNamespace())
return true;
- } while ((DC = DC->getParent()));
+ }
return false;
}
@@ -403,6 +417,27 @@ bool Decl::isExported() const {
return false;
}
+ExternalSourceSymbolAttr *Decl::getExternalSourceSymbolAttr() const {
+ const Decl *Definition = nullptr;
+ if (auto ID = dyn_cast<ObjCInterfaceDecl>(this)) {
+ Definition = ID->getDefinition();
+ } else if (auto PD = dyn_cast<ObjCProtocolDecl>(this)) {
+ Definition = PD->getDefinition();
+ } else if (auto TD = dyn_cast<TagDecl>(this)) {
+ Definition = TD->getDefinition();
+ }
+ if (!Definition)
+ Definition = this;
+
+ if (auto *attr = Definition->getAttr<ExternalSourceSymbolAttr>())
+ return attr;
+ if (auto *dcd = dyn_cast<Decl>(getDeclContext())) {
+ return dcd->getAttr<ExternalSourceSymbolAttr>();
+ }
+
+ return nullptr;
+}
+
bool Decl::hasDefiningAttr() const {
return hasAttr<AliasAttr>() || hasAttr<IFuncAttr>();
}
@@ -415,6 +450,19 @@ const Attr *Decl::getDefiningAttr() const {
return nullptr;
}
+static StringRef getRealizedPlatform(const AvailabilityAttr *A,
+ const ASTContext &Context) {
+ // Check if this is an App Extension "platform", and if so chop off
+ // the suffix for matching with the actual platform.
+ StringRef RealizedPlatform = A->getPlatform()->getName();
+ if (!Context.getLangOpts().AppExt)
+ return RealizedPlatform;
+ size_t suffix = RealizedPlatform.rfind("_app_extension");
+ if (suffix != StringRef::npos)
+ return RealizedPlatform.slice(0, suffix);
+ return RealizedPlatform;
+}
+
/// \brief Determine the availability of the given declaration based on
/// the target platform.
///
@@ -434,20 +482,11 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
if (EnclosingVersion.empty())
return AR_Available;
- // Check if this is an App Extension "platform", and if so chop off
- // the suffix for matching with the actual platform.
StringRef ActualPlatform = A->getPlatform()->getName();
- StringRef RealizedPlatform = ActualPlatform;
- if (Context.getLangOpts().AppExt) {
- size_t suffix = RealizedPlatform.rfind("_app_extension");
- if (suffix != StringRef::npos)
- RealizedPlatform = RealizedPlatform.slice(0, suffix);
- }
-
StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
// Match the platform name.
- if (RealizedPlatform != TargetPlatform)
+ if (getRealizedPlatform(A, Context) != TargetPlatform)
return AR_Available;
StringRef PrettyPlatformName
@@ -567,6 +606,20 @@ AvailabilityResult Decl::getAvailability(std::string *Message,
return Result;
}
+VersionTuple Decl::getVersionIntroduced() const {
+ const ASTContext &Context = getASTContext();
+ StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
+ for (const auto *A : attrs()) {
+ if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
+ if (getRealizedPlatform(Availability, Context) != TargetPlatform)
+ continue;
+ if (!Availability->getIntroduced().empty())
+ return Availability->getIntroduced();
+ }
+ }
+ return VersionTuple();
+}
+
bool Decl::canBeWeakImported(bool &IsDefinition) const {
IsDefinition = false;
@@ -627,7 +680,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case CXXConversion:
case EnumConstant:
case Var:
- case Binding:
case ImplicitParam:
case ParmVar:
case ObjCMethod:
@@ -639,10 +691,11 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case IndirectField:
return IDNS_Ordinary | IDNS_Member;
+ case Binding:
case NonTypeTemplateParm:
- // Non-type template parameters are not found by lookups that ignore
- // non-types, but they are found by redeclaration lookups for tag types,
- // so we include them in the tag namespace.
+ case VarTemplate:
+ // These (C++-only) declarations are found by redeclaration lookup for
+ // tag types, so we include them in the tag namespace.
return IDNS_Ordinary | IDNS_Tag;
case ObjCCompatibleAlias:
@@ -651,7 +704,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Typedef:
case TypeAlias:
- case TypeAliasTemplate:
case TemplateTypeParm:
case ObjCTypeParam:
return IDNS_Ordinary | IDNS_Type;
@@ -687,11 +739,11 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Namespace;
case FunctionTemplate:
- case VarTemplate:
return IDNS_Ordinary;
case ClassTemplate:
case TemplateTemplateParm:
+ case TypeAliasTemplate:
return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
case OMPDeclareReduction:
@@ -1301,7 +1353,7 @@ void DeclContext::removeDecl(Decl *D) {
// Remove only decls that have a name
if (!ND->getDeclName()) return;
- auto *DC = this;
+ auto *DC = D->getDeclContext();
do {
StoredDeclsMap *Map = DC->getPrimaryContext()->LookupPtr;
if (Map) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 74183701de..bd8a150cf1 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -55,15 +55,18 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasOnlyCMembers(true), HasInClassInitializer(false),
HasUninitializedReferenceMember(false), HasUninitializedFields(false),
HasInheritedConstructor(false), HasInheritedAssignment(false),
+ NeedOverloadResolutionForCopyConstructor(false),
NeedOverloadResolutionForMoveConstructor(false),
NeedOverloadResolutionForMoveAssignment(false),
NeedOverloadResolutionForDestructor(false),
+ DefaultedCopyConstructorIsDeleted(false),
DefaultedMoveConstructorIsDeleted(false),
DefaultedMoveAssignmentIsDeleted(false),
DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All),
DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true),
HasConstexprNonCopyMoveConstructor(false),
HasDefaultedDefaultConstructor(false),
+ CanPassInRegisters(true),
DefaultedDefaultConstructorIsConstexpr(true),
HasConstexprDefaultConstructor(false),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
@@ -73,8 +76,9 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
- IsParsingBaseSpecifiers(false), ODRHash(0), 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());
@@ -96,7 +100,7 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C,
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
- CXXRecordDecl* PrevDecl,
+ CXXRecordDecl *PrevDecl,
bool DelayTypeCreation) {
CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc,
IdLoc, Id, PrevDecl);
@@ -351,8 +355,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
setHasVolatileMember(true);
// Keep track of the presence of mutable fields.
- if (BaseClassDecl->hasMutableFields())
+ if (BaseClassDecl->hasMutableFields()) {
data().HasMutableFields = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ }
if (BaseClassDecl->hasUninitializedReferenceMember())
data().HasUninitializedReferenceMember = true;
@@ -381,16 +387,23 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().IsParsingBaseSpecifiers = false;
}
-void CXXRecordDecl::computeODRHash() {
- if (!DefinitionData)
- return;
+unsigned CXXRecordDecl::getODRHash() const {
+ assert(hasDefinition() && "ODRHash only for records with definitions");
- ODRHash Hash;
- Hash.AddCXXRecordDecl(this);
+ // 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
@@ -398,6 +411,8 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
// -- a direct or virtual base class B that cannot be copied/moved [...]
// -- a non-static data member of class type M (or array thereof)
// that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleCopyConstructor())
+ data().NeedOverloadResolutionForCopyConstructor = true;
if (!Subobj->hasSimpleMoveConstructor())
data().NeedOverloadResolutionForMoveConstructor = true;
@@ -418,6 +433,7 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
// -- any non-static data member has a type with a destructor
// that is deleted or inaccessible from the defaulted [ctor or dtor].
if (!Subobj->hasSimpleDestructor()) {
+ data().NeedOverloadResolutionForCopyConstructor = true;
data().NeedOverloadResolutionForMoveConstructor = true;
data().NeedOverloadResolutionForDestructor = true;
}
@@ -703,8 +719,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().IsStandardLayout = false;
// Keep track of the presence of mutable fields.
- if (Field->isMutable())
+ if (Field->isMutable()) {
data().HasMutableFields = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ }
// C++11 [class.union]p8, DR1460:
// If X is a union, a non-static data member of X that is not an anonymous
@@ -722,9 +740,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
ASTContext &Context = getASTContext();
QualType T = Context.getBaseElementType(Field->getType());
if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
- if (!Context.getLangOpts().ObjCAutoRefCount) {
- setHasObjectMember(true);
- } else if (T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+ if (T.hasNonTrivialObjCLifetime()) {
// Objective-C Automatic Reference Counting:
// If a class has a non-static data member of Objective-C pointer
// type (or array thereof), it is a non-POD type and its
@@ -736,6 +752,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
Data.PlainOldData = false;
Data.HasTrivialSpecialMembers = 0;
Data.HasIrrelevantDestructor = false;
+ } else if (!Context.getLangOpts().ObjCAutoRefCount) {
+ setHasObjectMember(true);
}
} else if (!T.isCXX98PODType(Context))
data().PlainOldData = false;
@@ -748,6 +766,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
// A standard-layout class is a class that:
// -- has no non-static data members of type [...] reference,
data().IsStandardLayout = false;
+
+ // C++1z [class.copy.ctor]p10:
+ // A defaulted copy constructor for a class X is defined as deleted if X has:
+ // -- a non-static data member of rvalue reference type
+ if (T->isRValueReferenceType())
+ data().DefaultedCopyConstructorIsDeleted = true;
}
if (!Field->hasInClassInitializer() && !Field->isMutable()) {
@@ -801,6 +825,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
// We may need to perform overload resolution to determine whether a
// field can be moved if it's const or volatile qualified.
if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) {
+ // We need to care about 'const' for the copy constructor because an
+ // implicit copy constructor might be declared with a non-const
+ // parameter.
+ data().NeedOverloadResolutionForCopyConstructor = true;
data().NeedOverloadResolutionForMoveConstructor = true;
data().NeedOverloadResolutionForMoveAssignment = true;
}
@@ -811,6 +839,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
// -- X is a union-like class that has a variant member with a
// non-trivial [corresponding special member]
if (isUnion()) {
+ if (FieldRec->hasNonTrivialCopyConstructor())
+ data().DefaultedCopyConstructorIsDeleted = true;
if (FieldRec->hasNonTrivialMoveConstructor())
data().DefaultedMoveConstructorIsDeleted = true;
if (FieldRec->hasNonTrivialMoveAssignment())
@@ -822,6 +852,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
// For an anonymous union member, our overload resolution will perform
// overload resolution for its members.
if (Field->isAnonymousStructOrUnion()) {
+ data().NeedOverloadResolutionForCopyConstructor |=
+ FieldRec->data().NeedOverloadResolutionForCopyConstructor;
data().NeedOverloadResolutionForMoveConstructor |=
FieldRec->data().NeedOverloadResolutionForMoveConstructor;
data().NeedOverloadResolutionForMoveAssignment |=
@@ -907,8 +939,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
// Keep track of the presence of mutable fields.
- if (FieldRec->hasMutableFields())
+ if (FieldRec->hasMutableFields()) {
data().HasMutableFields = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ }
// C++11 [class.copy]p13:
// If the implicitly-defined constructor would satisfy the
@@ -1356,6 +1390,13 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
}
const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
+ auto GetDefinitionOrSelf =
+ [](const CXXRecordDecl *D) -> const CXXRecordDecl * {
+ if (auto *Def = D->getDefinition())
+ return Def;
+ return D;
+ };
+
// If it's a class template specialization, find the template or partial
// specialization from which it was instantiated.
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
@@ -1366,7 +1407,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
break;
CTD = NewCTD;
}
- return CTD->getTemplatedDecl()->getDefinition();
+ return GetDefinitionOrSelf(CTD->getTemplatedDecl());
}
if (auto *CTPSD =
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
@@ -1375,7 +1416,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
break;
CTPSD = NewCTPSD;
}
- return CTPSD->getDefinition();
+ return GetDefinitionOrSelf(CTPSD);
}
}
@@ -1384,7 +1425,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
const CXXRecordDecl *RD = this;
while (auto *NewRD = RD->getInstantiatedFromMemberClass())
RD = NewRD;
- return RD->getDefinition();
+ return GetDefinitionOrSelf(RD);
}
}
@@ -1402,11 +1443,8 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
Context.getCanonicalType(ClassType));
DeclContext::lookup_result R = lookup(Name);
- if (R.empty())
- return nullptr;
- CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front());
- return Dtor;
+ return R.empty() ? nullptr : dyn_cast<CXXDestructorDecl>(R.front());
}
bool CXXRecordDecl::isAnyDestructorNoReturn() const {
@@ -1417,8 +1455,9 @@ bool CXXRecordDecl::isAnyDestructorNoReturn() const {
// Check base classes destructor for noreturn.
for (const auto &Base : bases())
- if (Base.getType()->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
- return true;
+ if (const CXXRecordDecl *RD = Base.getType()->getAsCXXRecordDecl())
+ if (RD->isAnyDestructorNoReturn())
+ return true;
// Check fields for noreturn.
for (const auto *Field : fields())
@@ -1431,13 +1470,73 @@ bool CXXRecordDecl::isAnyDestructorNoReturn() const {
return false;
}
+static bool isDeclContextInNamespace(const DeclContext *DC) {
+ while (!DC->isTranslationUnit()) {
+ if (DC->isNamespace())
+ return true;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
+bool CXXRecordDecl::isInterfaceLike() const {
+ assert(hasDefinition() && "checking for interface-like without a definition");
+ // All __interfaces are inheritently interface-like.
+ if (isInterface())
+ return true;
+
+ // Interface-like types cannot have a user declared constructor, destructor,
+ // friends, VBases, conversion functions, or fields. Additionally, lambdas
+ // cannot be interface types.
+ if (isLambda() || hasUserDeclaredConstructor() ||
+ hasUserDeclaredDestructor() || !field_empty() || hasFriends() ||
+ getNumVBases() > 0 || conversion_end() - conversion_begin() > 0)
+ return false;
+
+ // No interface-like type can have a method with a definition.
+ for (const auto *const Method : methods())
+ if (Method->isDefined() && !Method->isImplicit())
+ return false;
+
+ // Check "Special" types.
+ const auto *Uuid = getAttr<UuidAttr>();
+ // MS SDK declares IUnknown/IDispatch both in the root of a TU, or in an
+ // extern C++ block directly in the TU. These are only valid if in one
+ // of these two situations.
+ if (Uuid && isStruct() && !getDeclContext()->isExternCContext() &&
+ !isDeclContextInNamespace(getDeclContext()) &&
+ ((getName() == "IUnknown" &&
+ Uuid->getGuid() == "00000000-0000-0000-C000-000000000046") ||
+ (getName() == "IDispatch" &&
+ Uuid->getGuid() == "00020400-0000-0000-C000-000000000046"))) {
+ if (getNumBases() > 0)
+ return false;
+ return true;
+ }
+
+ // FIXME: Any access specifiers is supposed to make this no longer interface
+ // like.
+
+ // If this isn't a 'special' type, it must have a single interface-like base.
+ if (getNumBases() != 1)
+ return false;
+
+ const auto BaseSpec = *bases_begin();
+ if (BaseSpec.isVirtual() || BaseSpec.getAccessSpecifier() != AS_public)
+ return false;
+ const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+ if (Base->isInterface() || !Base->isInterfaceLike())
+ return false;
+ return true;
+}
+
void CXXRecordDecl::completeDefinition() {
completeDefinition(nullptr);
}
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
RecordDecl::completeDefinition();
-
+
// If the class may be abstract (but hasn't been marked as such), check for
// any pure final overriders.
if (mayBeAbstract()) {
@@ -1592,6 +1691,84 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
SC_None, false, false, SourceLocation());
}
+CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
+ bool IsAppleKext) {
+ assert(isVirtual() && "this method is expected to be virtual");
+
+ // When building with -fapple-kext, all calls must go through the vtable since
+ // the kernel linker can do runtime patching of vtables.
+ if (IsAppleKext)
+ return nullptr;
+
+ // If the member function is marked 'final', we know that it can't be
+ // overridden and can therefore devirtualize it unless it's pure virtual.
+ if (hasAttr<FinalAttr>())
+ return isPure() ? nullptr : this;
+
+ // If Base is unknown, we cannot devirtualize.
+ if (!Base)
+ return nullptr;
+
+ // If the base expression (after skipping derived-to-base conversions) is a
+ // class prvalue, then we can devirtualize.
+ Base = Base->getBestDynamicClassTypeExpr();
+ if (Base->isRValue() && Base->getType()->isRecordType())
+ return this;
+
+ // If we don't even know what we would call, we can't devirtualize.
+ const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
+ if (!BestDynamicDecl)
+ return nullptr;
+
+ // There may be a method corresponding to MD in a derived class.
+ CXXMethodDecl *DevirtualizedMethod =
+ getCorrespondingMethodInClass(BestDynamicDecl);
+
+ // If that method is pure virtual, we can't devirtualize. If this code is
+ // reached, the result would be UB, not a direct call to the derived class
+ // function, and we can't assume the derived class function is defined.
+ if (DevirtualizedMethod->isPure())
+ return nullptr;
+
+ // If that method is marked final, we can devirtualize it.
+ if (DevirtualizedMethod->hasAttr<FinalAttr>())
+ return DevirtualizedMethod;
+
+ // Similarly, if the class itself is marked 'final' it can't be overridden
+ // and we can therefore devirtualize the member function call.
+ if (BestDynamicDecl->hasAttr<FinalAttr>())
+ return DevirtualizedMethod;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VD->getType()->isRecordType())
+ // This is a record decl. We know the type and can devirtualize it.
+ return DevirtualizedMethod;
+
+ return nullptr;
+ }
+
+ // We can devirtualize calls on an object accessed by a class member access
+ // expression, since by C++11 [basic.life]p6 we know that it can't refer to
+ // a derived class object constructed in the same location.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl()))
+ return VD->getType()->isRecordType() ? DevirtualizedMethod : nullptr;
+
+ // Likewise for calls on an object accessed by a (non-reference) pointer to
+ // member access.
+ if (auto *BO = dyn_cast<BinaryOperator>(Base)) {
+ if (BO->isPtrMemOp()) {
+ auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>();
+ if (MPT->getPointeeType()->isRecordType())
+ return DevirtualizedMethod;
+ }
+ }
+
+ // We can't devirtualize the call.
+ return nullptr;
+}
+
bool CXXMethodDecl::isUsualDeallocationFunction() const {
if (getOverloadedOperator() != OO_Delete &&
getOverloadedOperator() != OO_Array_Delete)
@@ -1611,6 +1788,14 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
return true;
unsigned UsualParams = 1;
+ // C++ P0722:
+ // A destroying operator delete is a usual deallocation function if
+ // removing the std::destroying_delete_t parameter and changing the
+ // first parameter type from T* to void* results in the signature of
+ // a usual deallocation function.
+ if (isDestroyingOperatorDelete())
+ ++UsualParams;
+
// C++ <=14 [basic.stc.dynamic.deallocation]p2:
// [...] If class T does not declare such an operator delete but does
// declare a member deallocation function named operator delete with
@@ -1746,9 +1931,10 @@ bool CXXMethodDecl::hasInlineBody() const {
const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
if (!CheckFn)
CheckFn = this;
-
+
const FunctionDecl *fn;
- return CheckFn->hasBody(fn) && !fn->isOutOfLine();
+ return CheckFn->isDefined(fn) && !fn->isOutOfLine() &&
+ (fn->doesThisDeclarationHaveABody() || fn->willHaveBody());
}
bool CXXMethodDecl::isLambdaStaticInvoker() const {
@@ -2009,12 +2195,13 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
isInline, isImplicitlyDeclared);
}
-void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD) {
+void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) {
auto *First = cast<CXXDestructorDecl>(getFirstDecl());
if (OD && !First->OperatorDelete) {
First->OperatorDelete = OD;
+ First->OperatorDeleteThisArg = ThisArg;
if (auto *L = getASTMutationListener())
- L->ResolvedOperatorDelete(First, OD);
+ L->ResolvedOperatorDelete(First, OD, ThisArg);
}
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index a1ef58a454..d8bdb6369e 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -539,9 +539,18 @@ void ObjCInterfaceDecl::getDesignatedInitializers(
bool ObjCInterfaceDecl::isDesignatedInitializer(Selector Sel,
const ObjCMethodDecl **InitMethod) const {
+ bool HasCompleteDef = isThisDeclarationADefinition();
+ // During deserialization the data record for the ObjCInterfaceDecl could
+ // be made invariant by reusing the canonical decl. Take this into account
+ // when checking for the complete definition.
+ if (!HasCompleteDef && getCanonicalDecl()->hasDefinition() &&
+ getCanonicalDecl()->getDefinition() == getDefinition())
+ HasCompleteDef = true;
+
// Check for a complete definition and recover if not so.
- if (!isThisDeclarationADefinition())
+ if (!HasCompleteDef)
return false;
+
if (data().ExternallyCompleted)
LoadExternalDefinition();
@@ -979,12 +988,11 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
break;
case OMF_performSelector:
- if (!isInstanceMethod() ||
- !(getReturnType()->isObjCIdType() || getReturnType()->isVoidType()))
+ if (!isInstanceMethod() || !getReturnType()->isObjCIdType())
family = OMF_None;
else {
unsigned noParams = param_size();
- if (noParams < 1 || noParams > 5)
+ if (noParams < 1 || noParams > 3)
family = OMF_None;
else {
ObjCMethodDecl::param_type_iterator it = param_type_begin();
@@ -993,11 +1001,10 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
family = OMF_None;
break;
}
- // The first type should generally always be 'id' or 'Thread *', the
- // other types can vary.
- if (noParams > 1) {
- ArgT = *(it + 1);
- if (!ArgT->isObjCObjectPointerType()) {
+ while (--noParams) {
+ it++;
+ ArgT = (*it);
+ if (!ArgT->isObjCIdType()) {
family = OMF_None;
break;
}
@@ -1063,20 +1070,20 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
bool selfIsPseudoStrong, selfIsConsumed;
QualType selfTy =
getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed);
- ImplicitParamDecl *self
- = ImplicitParamDecl::Create(Context, this, SourceLocation(),
- &Context.Idents.get("self"), selfTy);
- setSelfDecl(self);
+ auto *Self = ImplicitParamDecl::Create(Context, this, SourceLocation(),
+ &Context.Idents.get("self"), selfTy,
+ ImplicitParamDecl::ObjCSelf);
+ setSelfDecl(Self);
if (selfIsConsumed)
- self->addAttr(NSConsumedAttr::CreateImplicit(Context));
+ Self->addAttr(NSConsumedAttr::CreateImplicit(Context));
if (selfIsPseudoStrong)
- self->setARCPseudoStrong(true);
+ Self->setARCPseudoStrong(true);
- setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
- &Context.Idents.get("_cmd"),
- Context.getObjCSelType()));
+ setCmdDecl(ImplicitParamDecl::Create(
+ Context, this, SourceLocation(), &Context.Idents.get("_cmd"),
+ Context.getObjCSelType(), ImplicitParamDecl::ObjCCmd));
}
ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
@@ -1882,25 +1889,23 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
}
}
-
void ObjCProtocolDecl::collectInheritedProtocolProperties(
- const ObjCPropertyDecl *Property,
- ProtocolPropertyMap &PM) const {
+ const ObjCPropertyDecl *Property, ProtocolPropertySet &PS,
+ PropertyDeclOrder &PO) const {
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
- bool MatchFound = false;
+ if (!PS.insert(PDecl).second)
+ return;
for (auto *Prop : PDecl->properties()) {
if (Prop == Property)
continue;
if (Prop->getIdentifier() == Property->getIdentifier()) {
- PM[PDecl] = Prop;
- MatchFound = true;
- break;
+ PO.push_back(Prop);
+ return;
}
}
// Scan through protocol's protocols which did not have a matching property.
- if (!MatchFound)
- for (const auto *PI : PDecl->protocols())
- PI->collectInheritedProtocolProperties(Property, PM);
+ for (const auto *PI : PDecl->protocols())
+ PI->collectInheritedProtocolProperties(Property, PS, PO);
}
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index aedc35b0f8..68adfc7c56 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -28,6 +28,7 @@ namespace {
class DeclPrinter : public DeclVisitor<DeclPrinter> {
raw_ostream &Out;
PrintingPolicy Policy;
+ const ASTContext &Context;
unsigned Indentation;
bool PrintInstantiation;
@@ -48,9 +49,10 @@ namespace {
public:
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
- unsigned Indentation = 0, bool PrintInstantiation = false)
- : Out(Out), Policy(Policy), Indentation(Indentation),
- PrintInstantiation(PrintInstantiation) { }
+ const ASTContext &Context, unsigned Indentation = 0,
+ bool PrintInstantiation = false)
+ : Out(Out), Policy(Policy), Context(Context), Indentation(Indentation),
+ PrintInstantiation(PrintInstantiation) {}
void VisitDeclContext(DeclContext *DC, bool Indent = true);
@@ -115,7 +117,8 @@ void Decl::print(raw_ostream &Out, unsigned Indentation,
void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation, bool PrintInstantiation) const {
- DeclPrinter Printer(Out, Policy, Indentation, PrintInstantiation);
+ DeclPrinter Printer(Out, Policy, getASTContext(), Indentation,
+ PrintInstantiation);
Printer.Visit(const_cast<Decl*>(this));
}
@@ -192,7 +195,7 @@ LLVM_DUMP_METHOD void DeclContext::dumpDeclContext() const {
DC = DC->getParent();
ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
- DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), 0);
+ DeclPrinter Printer(llvm::errs(), Ctx.getPrintingPolicy(), Ctx, 0);
Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
}
@@ -467,7 +470,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
prettyPrintAttributes(D);
if (Expr *Init = D->getInitExpr()) {
Out << " = ";
- Init->printPretty(Out, nullptr, Policy, Indentation);
+ Init->printPretty(Out, nullptr, Policy, Indentation, &Context);
}
}
@@ -478,6 +481,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isFunctionTemplateSpecialization())
Out << "template<> ";
+ else if (!D->getDescribedFunctionTemplate()) {
+ for (unsigned I = 0, NumTemplateParams = D->getNumTemplateParameterLists();
+ I < NumTemplateParams; ++I)
+ printTemplateParameters(D->getTemplateParameterList(I));
+ }
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
@@ -504,12 +512,19 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
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);
+ DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation);
TArgPrinter.printTemplateArguments(*TArgs);
}
@@ -527,7 +542,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Proto += "(";
if (FT) {
llvm::raw_string_ostream POut(Proto);
- DeclPrinter ParamPrinter(POut, SubPolicy, Indentation);
+ DeclPrinter ParamPrinter(POut, SubPolicy, Context, Indentation);
for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
if (i) POut << ", ";
ParamPrinter.VisitParmVarDecl(D->getParamDecl(i));
@@ -683,7 +698,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
// This is a K&R function definition, so we need to print the
// parameters.
Out << '\n';
- DeclPrinter ParamPrinter(Out, SubPolicy, Indentation);
+ DeclPrinter ParamPrinter(Out, SubPolicy, Context, Indentation);
Indentation += Policy.Indentation;
for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
Indent();
@@ -1048,6 +1063,12 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
prettyPrintPragmas(D->getTemplatedDecl());
+ // Print any leading template parameter lists.
+ if (const FunctionDecl *FD = D->getTemplatedDecl()) {
+ for (unsigned I = 0, NumTemplateParams = FD->getNumTemplateParameterLists();
+ I < NumTemplateParams; ++I)
+ printTemplateParameters(FD->getTemplateParameterList(I));
+ }
VisitRedeclarableTemplateDecl(D);
// Never print "instantiations" for deduction guides (they don't really
@@ -1171,7 +1192,9 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
for (const auto *PI : OMD->parameters()) {
// FIXME: selector is missing here!
pos = name.find_first_of(':', lastPos);
- Out << " " << name.substr(lastPos, pos - lastPos) << ':';
+ if (lastPos != 0)
+ Out << " ";
+ Out << name.substr(lastPos, pos - lastPos) << ':';
PrintObjCMethodType(OMD->getASTContext(),
PI->getObjCDeclQualifier(),
PI->getType());
@@ -1180,7 +1203,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
}
if (OMD->param_begin() == OMD->param_end())
- Out << " " << name;
+ Out << name;
if (OMD->isVariadic())
Out << ", ...";
@@ -1521,7 +1544,19 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
Out << ")";
if (auto *Init = D->getInitializer()) {
Out << " initializer(";
+ switch (D->getInitializerKind()) {
+ case OMPDeclareReductionDecl::DirectInit:
+ Out << "omp_priv(";
+ break;
+ case OMPDeclareReductionDecl::CopyInit:
+ Out << "omp_priv = ";
+ break;
+ case OMPDeclareReductionDecl::CallInit:
+ break;
+ }
Init->printPretty(Out, nullptr, Policy, 0);
+ if (D->getInitializerKind() == OMPDeclareReductionDecl::DirectInit)
+ Out << ")";
Out << ")";
}
}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 6053bd7e39..1f8e26deda 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -660,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;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 224dec17f1..6cda82b2b0 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;
@@ -1576,6 +1576,7 @@ bool CastExpr::CastConsistency() const {
getSubExpr()->getType()->isBlockPointerType());
assert(getType()->getPointeeType().getAddressSpace() !=
getSubExpr()->getType()->getPointeeType().getAddressSpace());
+ LLVM_FALLTHROUGH;
// These should not have an inheritance path.
case CK_Dynamic:
case CK_ToUnion:
@@ -1640,25 +1641,32 @@ const char *CastExpr::getCastKindName() const {
llvm_unreachable("Unhandled cast kind!");
}
+namespace {
+ Expr *skipImplicitTemporary(Expr *expr) {
+ // Skip through reference binding to temporary.
+ if (MaterializeTemporaryExpr *Materialize
+ = dyn_cast<MaterializeTemporaryExpr>(expr))
+ expr = Materialize->GetTemporaryExpr();
+
+ // Skip any temporary bindings; they're implicit.
+ if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(expr))
+ expr = Binder->getSubExpr();
+
+ return expr;
+ }
+}
+
Expr *CastExpr::getSubExprAsWritten() {
Expr *SubExpr = nullptr;
CastExpr *E = this;
do {
- SubExpr = E->getSubExpr();
+ SubExpr = skipImplicitTemporary(E->getSubExpr());
- // Skip through reference binding to temporary.
- if (MaterializeTemporaryExpr *Materialize
- = dyn_cast<MaterializeTemporaryExpr>(SubExpr))
- SubExpr = Materialize->GetTemporaryExpr();
-
- // Skip any temporary bindings; they're implicit.
- if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
- SubExpr = Binder->getSubExpr();
-
// Conversions by constructor and conversion functions have a
// subexpression describing the call; strip it off.
if (E->getCastKind() == CK_ConstructorConversion)
- SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0);
+ SubExpr =
+ skipImplicitTemporary(cast<CXXConstructExpr>(SubExpr)->getArg(0));
else if (E->getCastKind() == CK_UserDefinedConversion) {
assert((isa<CXXMemberCallExpr>(SubExpr) ||
isa<BlockExpr>(SubExpr)) &&
@@ -1687,6 +1695,26 @@ CXXBaseSpecifier **CastExpr::path_buffer() {
}
}
+const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType,
+ QualType opType) {
+ auto RD = unionType->castAs<RecordType>()->getDecl();
+ return getTargetFieldForToUnionCast(RD, opType);
+}
+
+const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD,
+ QualType OpType) {
+ auto &Ctx = RD->getASTContext();
+ RecordDecl::field_iterator Field, FieldEnd;
+ for (Field = RD->field_begin(), FieldEnd = RD->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Ctx.hasSameUnqualifiedType(Field->getType(), OpType) &&
+ !Field->isUnnamedBitfield()) {
+ return *Field;
+ }
+ }
+ return nullptr;
+}
+
ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath,
@@ -1801,6 +1829,38 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
return OverOps[Opc];
}
+bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx,
+ Opcode Opc,
+ Expr *LHS, Expr *RHS) {
+ if (Opc != BO_Add)
+ return false;
+
+ // Check that we have one pointer and one integer operand.
+ Expr *PExp;
+ if (LHS->getType()->isPointerType()) {
+ if (!RHS->getType()->isIntegerType())
+ return false;
+ PExp = LHS;
+ } else if (RHS->getType()->isPointerType()) {
+ if (!LHS->getType()->isIntegerType())
+ return false;
+ PExp = RHS;
+ } else {
+ return false;
+ }
+
+ // Check that the pointer is a nullptr.
+ if (!PExp->IgnoreParenCasts()
+ ->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+ return false;
+
+ // Check that the pointee type is char-sized.
+ const PointerType *PTy = PExp->getType()->getAs<PointerType>();
+ if (!PTy || !PTy->getPointeeType()->isCharType())
+ return false;
+
+ return true;
+}
InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
@@ -1891,6 +1951,17 @@ bool InitListExpr::isTransparent() const {
getInit(0)->getType().getCanonicalType();
}
+bool InitListExpr::isIdiomaticZeroInitializer(const LangOptions &LangOpts) const {
+ assert(isSyntacticForm() && "only test syntactic form as zero initializer");
+
+ if (LangOpts.CPlusPlus || getNumInits() != 1) {
+ return false;
+ }
+
+ const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(getInit(0));
+ return Lit && Lit->getValue() == 0;
+}
+
SourceLocation InitListExpr::getLocStart() const {
if (InitListExpr *SyntacticForm = getSyntacticForm())
return SyntacticForm->getLocStart();
@@ -2102,6 +2173,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
}
// Fallthrough for generic call handling.
+ LLVM_FALLTHROUGH;
}
case CallExprClass:
case CXXMemberCallExprClass:
@@ -2226,7 +2298,8 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
const DeclRefExpr *DRE =
dyn_cast<DeclRefExpr>(CE->getSubExpr()->IgnoreParens());
if (!(DRE && isa<VarDecl>(DRE->getDecl()) &&
- cast<VarDecl>(DRE->getDecl())->hasLocalStorage())) {
+ cast<VarDecl>(DRE->getDecl())->hasLocalStorage()) &&
+ !isa<CallExpr>(CE->getSubExpr()->IgnoreParens())) {
return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc,
R1, R2, Ctx);
}
@@ -3221,20 +3294,20 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// Check that it is a cast to void*.
if (const PointerType *PT = CE->getType()->getAs<PointerType>()) {
QualType Pointee = PT->getPointeeType();
- Qualifiers Q = Pointee.getQualifiers();
- // In OpenCL v2.0 generic address space acts as a placeholder
- // and should be ignored.
- bool IsASValid = true;
- if (Ctx.getLangOpts().OpenCLVersion >= 200) {
- if (Pointee.getAddressSpace() == LangAS::opencl_generic)
- Q.removeAddressSpace();
- else
- IsASValid = false;
- }
-
- if (IsASValid && !Q.hasQualifiers() &&
- Pointee->isVoidType() && // to void*
- CE->getSubExpr()->getType()->isIntegerType()) // from int.
+ // Only (void*)0 or equivalent are treated as nullptr. If pointee type
+ // has non-default address space it is not treated as nullptr.
+ // (__generic void*)0 in OpenCL 2.0 should not be treated as nullptr
+ // since it cannot be assigned to a pointer to constant address space.
+ bool PointeeHasDefaultAS =
+ Pointee.getAddressSpace() == LangAS::Default ||
+ (Ctx.getLangOpts().OpenCLVersion >= 200 &&
+ Pointee.getAddressSpace() == LangAS::opencl_generic) ||
+ (Ctx.getLangOpts().OpenCL &&
+ Ctx.getLangOpts().OpenCLVersion < 200 &&
+ Pointee.getAddressSpace() == LangAS::opencl_private);
+
+ if (PointeeHasDefaultAS && Pointee->isVoidType() && // to void*
+ CE->getSubExpr()->getType()->isIntegerType()) // from int.
return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
}
}
@@ -3887,16 +3960,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,
@@ -3923,10 +4002,12 @@ AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args,
unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
switch (Op) {
case AO__c11_atomic_init:
+ case AO__opencl_atomic_init:
case AO__c11_atomic_load:
case AO__atomic_load_n:
return 2;
+ case AO__opencl_atomic_load:
case AO__c11_atomic_store:
case AO__c11_atomic_exchange:
case AO__atomic_load:
@@ -3952,6 +4033,15 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
case AO__atomic_nand_fetch:
return 3;
+ case AO__opencl_atomic_store:
+ case AO__opencl_atomic_exchange:
+ case AO__opencl_atomic_fetch_add:
+ case AO__opencl_atomic_fetch_sub:
+ case AO__opencl_atomic_fetch_and:
+ case AO__opencl_atomic_fetch_or:
+ case AO__opencl_atomic_fetch_xor:
+ case AO__opencl_atomic_fetch_min:
+ case AO__opencl_atomic_fetch_max:
case AO__atomic_exchange:
return 4;
@@ -3959,6 +4049,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
case AO__c11_atomic_compare_exchange_weak:
return 5;
+ case AO__opencl_atomic_compare_exchange_strong:
+ case AO__opencl_atomic_compare_exchange_weak:
case AO__atomic_compare_exchange:
case AO__atomic_compare_exchange_n:
return 6;
@@ -3966,6 +4058,13 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) {
llvm_unreachable("unknown atomic op");
}
+QualType AtomicExpr::getValueType() const {
+ auto T = getPtr()->getType()->castAs<PointerType>()->getPointeeType();
+ if (auto AT = T->getAs<AtomicType>())
+ return AT->getValueType();
+ return T;
+}
+
QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) {
unsigned ArraySectionCount = 0;
while (auto *OASE = dyn_cast<OMPArraySectionExpr>(Base->IgnoreParens())) {
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 6713fca045..182a8b415a 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -160,6 +160,22 @@ bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const {
// CXXDeleteExpr
QualType CXXDeleteExpr::getDestroyedType() const {
const Expr *Arg = getArgument();
+
+ // For a destroying operator delete, we may have implicitly converted the
+ // pointer type to the type of the parameter of the 'operator delete'
+ // function.
+ while (auto *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ if (ICE->getCastKind() == CK_DerivedToBase ||
+ ICE->getCastKind() == CK_UncheckedDerivedToBase ||
+ ICE->getCastKind() == CK_NoOp) {
+ assert((ICE->getCastKind() == CK_NoOp ||
+ getOperatorDelete()->isDestroyingOperatorDelete()) &&
+ "only a destroying operator delete can have a converted arg");
+ Arg = ICE->getSubExpr();
+ } else
+ break;
+ }
+
// The type-to-delete may not be a pointer if it's a dependent type.
const QualType ArgType = Arg->getType();
@@ -1052,7 +1068,9 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
:Type->getType()->isRValueReferenceType()? VK_XValue
:VK_RValue),
OK_Ordinary,
- Type->getType()->isDependentType(), true, true,
+ Type->getType()->isDependentType() ||
+ Type->getType()->getContainedDeducedType(),
+ true, true,
Type->getType()->containsUnexpandedParameterPack()),
Type(Type),
LParenLoc(LParenLoc),
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 76c548f82a..3bb2b4eb5f 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -190,7 +190,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
- case Expr::CoyieldExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -414,7 +413,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
case Expr::CoawaitExprClass:
- return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr());
+ case Expr::CoyieldExprClass:
+ return ClassifyInternal(Ctx, cast<CoroutineSuspendExpr>(E)->getResumeExpr());
}
llvm_unreachable("unhandled expression kind in classification");
@@ -627,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.
@@ -640,7 +641,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Records with any const fields (recursively) are not modifiable.
if (const RecordType *R = CT->getAs<RecordType>())
if (R->hasConstFields())
- return Cl::CM_ConstQualified;
+ return Cl::CM_ConstQualifiedField;
return Cl::CM_Modifiable;
}
@@ -694,6 +695,7 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
llvm_unreachable("CM_LValueCast and CL_LValue don't match");
case Cl::CM_NoSetterProperty: return MLV_NoSetterProperty;
case Cl::CM_ConstQualified: return MLV_ConstQualified;
+ case Cl::CM_ConstQualifiedField: return MLV_ConstQualifiedField;
case Cl::CM_ConstAddrSpace: return MLV_ConstAddrSpace;
case Cl::CM_ArrayType: return MLV_ArrayType;
case Cl::CM_IncompleteType: return MLV_IncompleteType;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index a1b508f78c..c09c99386c 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -62,7 +62,13 @@ namespace {
static QualType getType(APValue::LValueBase B) {
if (!B) return QualType();
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
- return D->getType();
+ // FIXME: It's unclear where we're supposed to take the type from, and
+ // this actually matters for arrays of unknown bound. Using the type of
+ // the most recent declaration isn't clearly correct in general. Eg:
+ //
+ // extern int arr[]; void f() { extern int arr[3]; };
+ // constexpr int *p = &arr[1]; // valid?
+ return cast<ValueDecl>(D->getMostRecentDecl())->getType();
const Expr *Base = B.get<const Expr*>();
@@ -141,6 +147,12 @@ namespace {
return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
}
+ /// The bound to claim that an array of unknown bound has.
+ /// The value in MostDerivedArraySize is undefined in this case. So, set it
+ /// to an arbitrary value that's likely to loudly break things if it's used.
+ static const uint64_t AssumedSizeForUnsizedArray =
+ std::numeric_limits<uint64_t>::max() / 2;
+
/// Determines if an LValue with the given LValueBase will have an unsized
/// array in its designator.
/// Find the path length and type of the most-derived subobject in the given
@@ -148,7 +160,8 @@ namespace {
static unsigned
findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base,
ArrayRef<APValue::LValuePathEntry> Path,
- uint64_t &ArraySize, QualType &Type, bool &IsArray) {
+ uint64_t &ArraySize, QualType &Type, bool &IsArray,
+ bool &FirstEntryIsUnsizedArray) {
// This only accepts LValueBases from APValues, and APValues don't support
// arrays that lack size info.
assert(!isBaseAnAllocSizeCall(Base) &&
@@ -158,12 +171,18 @@ namespace {
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
if (Type->isArrayType()) {
- const ConstantArrayType *CAT =
- cast<ConstantArrayType>(Ctx.getAsArrayType(Type));
- Type = CAT->getElementType();
- ArraySize = CAT->getSize().getZExtValue();
+ const ArrayType *AT = Ctx.getAsArrayType(Type);
+ Type = AT->getElementType();
MostDerivedLength = I + 1;
IsArray = true;
+
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ ArraySize = CAT->getSize().getZExtValue();
+ } else {
+ assert(I == 0 && "unexpected unsized array designator");
+ FirstEntryIsUnsizedArray = true;
+ ArraySize = AssumedSizeForUnsizedArray;
+ }
} else if (Type->isAnyComplexType()) {
const ComplexType *CT = Type->castAs<ComplexType>();
Type = CT->getElementType();
@@ -246,10 +265,12 @@ namespace {
Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
if (V.getLValueBase()) {
bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
MostDerivedPathLength = findMostDerivedSubobject(
Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
- MostDerivedType, IsArray);
+ MostDerivedType, IsArray, FirstIsUnsizedArray);
MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
}
}
}
@@ -318,7 +339,7 @@ namespace {
// The value in MostDerivedArraySize is undefined in this case. So, set it
// to an arbitrary value that's likely to loudly break things if it's
// used.
- MostDerivedArraySize = std::numeric_limits<uint64_t>::max() / 2;
+ MostDerivedArraySize = AssumedSizeForUnsizedArray;
MostDerivedPathLength = Entries.size();
}
/// Update this designator to refer to the given base or member of this
@@ -350,12 +371,15 @@ namespace {
MostDerivedArraySize = 2;
MostDerivedPathLength = Entries.size();
}
- void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, APSInt N);
+ void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
+ 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, APSInt N) {
if (Invalid || !N) return;
uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue();
if (isMostDerivedAnUnsizedArray()) {
+ diagnoseUnsizedArrayPointerArithmetic(Info, E);
// Can't verify -- trust that the user is doing the right thing (or if
// not, trust that the caller will catch the bad behavior).
// FIXME: Should we reject if this overflows, at least?
@@ -536,7 +560,7 @@ namespace {
/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
/// evaluate the expression regardless of what the RHS is, but C only allows
/// certain things in certain situations.
- struct LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) EvalInfo {
+ struct EvalInfo {
ASTContext &Ctx;
/// EvalStatus - Contains information about the evaluation.
@@ -572,6 +596,31 @@ namespace {
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
+ /// EvaluatingObject - Pair of the AST node that an lvalue represents and
+ /// the call index that that lvalue was allocated in.
+ typedef std::pair<APValue::LValueBase, unsigned> EvaluatingObject;
+
+ /// EvaluatingConstructors - Set of objects that are currently being
+ /// constructed.
+ llvm::DenseSet<EvaluatingObject> EvaluatingConstructors;
+
+ struct EvaluatingConstructorRAII {
+ EvalInfo &EI;
+ EvaluatingObject Object;
+ bool DidInsert;
+ EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object)
+ : EI(EI), Object(Object) {
+ DidInsert = EI.EvaluatingConstructors.insert(Object).second;
+ }
+ ~EvaluatingConstructorRAII() {
+ if (DidInsert) EI.EvaluatingConstructors.erase(Object);
+ }
+ };
+
+ bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) {
+ return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex));
+ }
+
/// The current array initialization index, if we're performing array
/// initialization.
uint64_t ArrayInitIndex = -1;
@@ -665,6 +714,7 @@ namespace {
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
EvaluatingDeclValue = &Value;
+ EvaluatingConstructors.insert({Base, 0});
}
const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
@@ -735,6 +785,7 @@ namespace {
if (!HasFoldFailureDiagnostic)
break;
// We've already failed to fold something. Keep that diagnostic.
+ LLVM_FALLTHROUGH;
case EM_ConstantExpression:
case EM_PotentialConstantExpression:
case EM_ConstantExpressionUnevaluated:
@@ -975,24 +1026,23 @@ namespace {
/// RAII object used to optionally suppress diagnostics and side-effects from
/// a speculative evaluation.
class SpeculativeEvaluationRAII {
- /// Pair of EvalInfo, and a bit that stores whether or not we were
- /// speculatively evaluating when we created this RAII.
- llvm::PointerIntPair<EvalInfo *, 1, bool> InfoAndOldSpecEval;
- Expr::EvalStatus Old;
+ EvalInfo *Info = nullptr;
+ Expr::EvalStatus OldStatus;
+ bool OldIsSpeculativelyEvaluating;
void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
- InfoAndOldSpecEval = Other.InfoAndOldSpecEval;
- Old = Other.Old;
- Other.InfoAndOldSpecEval.setPointer(nullptr);
+ Info = Other.Info;
+ OldStatus = Other.OldStatus;
+ OldIsSpeculativelyEvaluating = Other.OldIsSpeculativelyEvaluating;
+ Other.Info = nullptr;
}
void maybeRestoreState() {
- EvalInfo *Info = InfoAndOldSpecEval.getPointer();
if (!Info)
return;
- Info->EvalStatus = Old;
- Info->IsSpeculativelyEvaluating = InfoAndOldSpecEval.getInt();
+ Info->EvalStatus = OldStatus;
+ Info->IsSpeculativelyEvaluating = OldIsSpeculativelyEvaluating;
}
public:
@@ -1000,8 +1050,8 @@ namespace {
SpeculativeEvaluationRAII(
EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
- : InfoAndOldSpecEval(&Info, Info.IsSpeculativelyEvaluating),
- Old(Info.EvalStatus) {
+ : Info(&Info), OldStatus(Info.EvalStatus),
+ OldIsSpeculativelyEvaluating(Info.IsSpeculativelyEvaluating) {
Info.EvalStatus.Diag = NewDiag;
Info.IsSpeculativelyEvaluating = true;
}
@@ -1067,11 +1117,22 @@ bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
setInvalid();
return false;
}
+ // Note, we do not diagnose if isMostDerivedAnUnsizedArray(), because there
+ // must actually be at least one array element; even a VLA cannot have a
+ // bound of zero. And if our index is nonzero, we already had a CCEDiag.
return true;
}
+void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info,
+ const Expr *E) {
+ Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed);
+ // Do not set the designator as invalid: we can represent this situation,
+ // and correct handling of __builtin_object_size requires us to do so.
+}
+
void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
- const Expr *E, APSInt 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)
@@ -1212,8 +1273,6 @@ namespace {
IsNullPtr);
else {
assert(!InvalidBase && "APValues can't handle invalid LValue bases");
- assert(!Designator.FirstEntryIsAnUnsizedArray &&
- "Unsized array with a valid base?");
V = APValue(Base, Offset, Designator.Entries,
Designator.IsOnePastTheEnd, CallIndex, IsNullPtr);
}
@@ -1228,8 +1287,7 @@ namespace {
IsNullPtr = V.isNullPointer();
}
- void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false,
- bool IsNullPtr_ = false, uint64_t Offset_ = 0) {
+ void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) {
#ifndef NDEBUG
// We only allow a few types of invalid bases. Enforce that here.
if (BInvalid) {
@@ -1240,11 +1298,20 @@ namespace {
#endif
Base = B;
- Offset = CharUnits::fromQuantity(Offset_);
+ Offset = CharUnits::fromQuantity(0);
InvalidBase = BInvalid;
CallIndex = I;
Designator = SubobjectDesignator(getType(B));
- IsNullPtr = IsNullPtr_;
+ IsNullPtr = false;
+ }
+
+ void setNull(QualType PointerTy, uint64_t TargetVal) {
+ Base = (Expr *)nullptr;
+ Offset = CharUnits::fromQuantity(TargetVal);
+ InvalidBase = false;
+ CallIndex = 0;
+ Designator = SubobjectDesignator(PointerTy->getPointeeType());
+ IsNullPtr = true;
}
void setInvalid(APValue::LValueBase B, unsigned I = 0) {
@@ -1278,10 +1345,14 @@ namespace {
if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
Designator.addDeclUnchecked(D, Virtual);
}
- void addUnsizedArray(EvalInfo &Info, QualType ElemTy) {
- assert(Designator.Entries.empty() && getType(Base)->isPointerType());
- assert(isBaseAnAllocSizeCall(Base) &&
- "Only alloc_size bases can have unsized arrays");
+ void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
+ if (!Designator.Entries.empty()) {
+ Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
+ Designator.setInvalid();
+ return;
+ }
+
+ assert(getType(Base)->isPointerType() || getType(Base)->isArrayType());
Designator.FirstEntryIsAnUnsizedArray = true;
Designator.addUnsizedArrayUnchecked(ElemTy);
}
@@ -1296,8 +1367,8 @@ namespace {
void clearIsNullPointer() {
IsNullPtr = false;
}
- void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, APSInt Index,
- CharUnits ElementSize) {
+ 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)
@@ -1654,6 +1725,19 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
return true;
}
+/// Member pointers are constant expressions unless they point to a
+/// non-virtual dllimport member function.
+static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
+ SourceLocation Loc,
+ QualType Type,
+ const APValue &Value) {
+ const ValueDecl *Member = Value.getMemberPointerDecl();
+ const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member);
+ if (!FD)
+ return true;
+ return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>();
+}
+
/// Check that this core constant expression is of literal type, and if not,
/// produce an appropriate diagnostic.
static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
@@ -1734,6 +1818,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
}
}
for (const auto *I : RD->fields()) {
+ if (I->isUnnamedBitfield())
+ continue;
+
if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
Value.getStructField(I->getFieldIndex())))
return false;
@@ -1746,6 +1833,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal);
}
+ if (Value.isMemberPointer())
+ return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value);
+
// Everything else is fine.
return true;
}
@@ -2572,10 +2662,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Sub.Invalid)
// A diagnostic will have already been produced.
return handler.failed();
- if (Sub.isOnePastTheEnd()) {
+ if (Sub.isOnePastTheEnd() || Sub.isMostDerivedAnUnsizedArray()) {
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ Info.FFDiag(E, Sub.isOnePastTheEnd()
+ ? diag::note_constexpr_access_past_end
+ : diag::note_constexpr_access_unsized_array)
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -3072,10 +3164,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
// During the construction of an object, it is not yet 'const'.
- // FIXME: We don't set up EvaluatingDecl for local variables or temporaries,
- // and this doesn't do quite the right thing for const subobjects of the
+ // FIXME: This doesn't do quite the right thing for const subobjects of the
// object under construction.
- if (LVal.getLValueBase() == Info.EvaluatingDecl) {
+ if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) {
BaseType = Info.Ctx.getCanonicalType(BaseType);
BaseType.removeLocalConst();
}
@@ -4228,6 +4319,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
return false;
}
+ EvalInfo::EvaluatingConstructorRAII EvalObj(
+ Info, {This.getLValueBase(), This.CallIndex});
CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
// FIXME: Creating an APValue just to hold a nonexistent return value is
@@ -4416,8 +4509,14 @@ private:
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
- if (Info.checkingPotentialConstantExpression() && Info.noteFailure())
+ if (Info.checkingPotentialConstantExpression() && Info.noteFailure()) {
CheckPotentialConstantConditional(E);
+ return false;
+ }
+ if (Info.noteFailure()) {
+ StmtVisitorTy::Visit(E->getTrueExpr());
+ StmtVisitorTy::Visit(E->getFalseExpr());
+ }
return false;
}
@@ -5238,14 +5337,19 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
if (E->getBase()->getType()->isVectorType())
return Error(E);
- if (!evaluatePointer(E->getBase(), Result))
- return false;
+ bool Success = true;
+ if (!evaluatePointer(E->getBase(), Result)) {
+ if (!Info.noteFailure())
+ return false;
+ Success = false;
+ }
APSInt Index;
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
- return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index);
+ return Success &&
+ HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index);
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
@@ -5423,7 +5527,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
Result.setInvalid(E);
QualType Pointee = E->getType()->castAs<PointerType>()->getPointeeType();
- Result.addUnsizedArray(Info, Pointee);
+ Result.addUnsizedArray(Info, E, Pointee);
return true;
}
@@ -5458,8 +5562,8 @@ public:
return true;
}
bool ZeroInitialization(const Expr *E) {
- auto Offset = Info.Ctx.getTargetNullPointerValue(E->getType());
- Result.set((Expr*)nullptr, 0, false, true, Offset);
+ auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType());
+ Result.setNull(E->getType(), TargetVal);
return true;
}
@@ -5468,8 +5572,11 @@ public:
bool VisitUnaryAddrOf(const UnaryOperator *E);
bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
{ return Success(E); }
- bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E)
- { return Success(E); }
+ bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
+ if (Info.noteFailure())
+ EvaluateIgnoredValue(Info, E->getSubExpr());
+ return Error(E);
+ }
bool VisitAddrLabelExpr(const AddrLabelExpr *E)
{ return Success(E); }
bool VisitCallExpr(const CallExpr *E);
@@ -5630,7 +5737,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return true;
}
}
- case CK_ArrayToPointerDecay:
+
+ case CK_ArrayToPointerDecay: {
if (SubExpr->isGLValue()) {
if (!evaluateLValue(SubExpr, Result))
return false;
@@ -5641,12 +5749,13 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return false;
}
// The result is a pointer to the first element of the array.
- if (const ConstantArrayType *CAT
- = Info.Ctx.getAsConstantArrayType(SubExpr->getType()))
+ auto *AT = Info.Ctx.getAsArrayType(SubExpr->getType());
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AT))
Result.addArray(Info, E, CAT);
else
- Result.Designator.setInvalid();
+ Result.addUnsizedArray(Info, E, AT->getElementType());
return true;
+ }
case CK_FunctionToPointerDecay:
return evaluateLValue(SubExpr, Result);
@@ -5713,7 +5822,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
Result.setInvalid(E);
QualType PointeeTy = E->getType()->castAs<PointerType>()->getPointeeType();
- Result.addUnsizedArray(Info, PointeeTy);
+ Result.addUnsizedArray(Info, E, PointeeTy);
return true;
}
@@ -7274,7 +7383,8 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
/// Please note: this function is specialized for how __builtin_object_size
/// views "objects".
///
-/// If this encounters an invalid RecordDecl, it will always return true.
+/// If this encounters an invalid RecordDecl or otherwise cannot determine the
+/// correct result, it will always return true.
static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
assert(!LVal.Designator.Invalid);
@@ -7305,9 +7415,8 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
unsigned I = 0;
QualType BaseType = getType(Base);
if (LVal.Designator.FirstEntryIsAnUnsizedArray) {
- assert(isBaseAnAllocSizeCall(Base) &&
- "Unsized array in non-alloc_size call?");
- // If this is an alloc_size base, we should ignore the initial array index
+ // If we don't know the array bound, conservatively assume we're looking at
+ // the final array element.
++I;
BaseType = BaseType->castAs<PointerType>()->getPointeeType();
}
@@ -7862,6 +7971,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return BuiltinOp == Builtin::BI__atomic_always_lock_free ?
Success(0, E) : Error(E);
}
+ case Builtin::BIomp_is_initial_device:
+ // We can decide statically which value the runtime would return if called.
+ return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E);
}
}
@@ -8072,7 +8184,8 @@ bool DataRecursiveIntBinOpEvaluator::
return true;
}
-static void addOrSubLValueAsInteger(APValue &LVal, APSInt Index, bool IsSub) {
+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.
@@ -9482,7 +9595,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
case BO_Mul:
if (Result.isComplexFloat()) {
// This is an implementation of complex multiplication according to the
- // constraints laid out in C11 Annex G. The implemantion uses the
+ // constraints laid out in C11 Annex G. The implemention uses the
// following naming scheme:
// (a + ib) * (c + id)
ComplexValue LHS = Result;
@@ -9563,7 +9676,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
case BO_Div:
if (Result.isComplexFloat()) {
// This is an implementation of complex division according to the
- // constraints laid out in C11 Annex G. The implemantion uses the
+ // constraints laid out in C11 Annex G. The implemention uses the
// following naming scheme:
// (a + ib) / (c + id)
ComplexValue LHS = Result;
@@ -9746,6 +9859,8 @@ public:
bool Success(const APValue &V, const Expr *e) { return true; }
+ bool ZeroInitialization(const Expr *E) { return true; }
+
bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
@@ -10321,6 +10436,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
}
// OffsetOf falls through here.
+ LLVM_FALLTHROUGH;
}
case Expr::OffsetOfExprClass: {
// Note that per C99, offsetof must be an ICE. And AFAIK, using
@@ -10423,6 +10539,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
return Worst(LHSResult, RHSResult);
}
}
+ LLVM_FALLTHROUGH;
}
case Expr::ImplicitCastExprClass:
case Expr::CStyleCastExprClass:
diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp
new file mode 100644
index 0000000000..6b75c51c64
--- /dev/null
+++ b/lib/AST/ExternalASTMerger.cpp
@@ -0,0 +1,402 @@
+//===- 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/DeclCXX.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;
+
+/// For the given DC, return the DC that is safe to perform lookups on. This is
+/// the DC we actually want to work with most of the time.
+const DeclContext *CanonicalizeDC(const DeclContext *DC) {
+ if (isa<LinkageSpecDecl>(DC))
+ return DC->getRedeclContext();
+ return DC;
+}
+
+Source<const DeclContext *>
+LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
+ ASTImporter &ReverseImporter) {
+ DC = CanonicalizeDC(DC);
+ 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();
+ if (SearchResultSize == 0 || SearchResultSize > 1) {
+ // There are two cases here. First, we might not find the name.
+ // We might also find multiple copies, in which case we have no
+ // guarantee that the one we wanted is the one we pick. (E.g.,
+ // if we have two specializations of the same template it is
+ // very hard to determine which is the one you want.)
+ //
+ // The Origins map fixes this problem by allowing the origin to be
+ // explicitly recorded, so we trigger that recording by returning
+ // nothing (rather than a possibly-inaccurate guess) here.
+ return nullptr;
+ } else {
+ NamedDecl *SearchResultDecl = SearchResult[0];
+ if (isa<DeclContext>(SearchResultDecl) &&
+ SearchResultDecl->getKind() == DC->getDeclKind())
+ return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();
+ return nullptr; // This type of lookup is unsupported
+ }
+}
+
+/// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.
+///
+/// There are several modifications:
+///
+/// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few
+/// others), which instructs Clang to refer to ExternalASTMerger. Also, it
+/// forces MinimalImport to true, which is necessary to make this work.
+/// - It maintains a reverse importer for use with names. This allows lookup of
+/// arbitrary names in the source context.
+/// - It updates the ExternalASTMerger's origin map as needed whenever a
+/// it sees a DeclContext.
+class LazyASTImporter : public ASTImporter {
+private:
+ ExternalASTMerger &Parent;
+ ASTImporter Reverse;
+ const ExternalASTMerger::OriginMap &FromOrigins;
+
+ llvm::raw_ostream &logs() { return Parent.logs(); }
+public:
+ LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,
+ FileManager &ToFileManager, ASTContext &FromContext,
+ FileManager &FromFileManager,
+ const ExternalASTMerger::OriginMap &_FromOrigins)
+ : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
+ /*MinimalImport=*/true),
+ Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext,
+ ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {}
+
+ /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
+ /// map is kept up to date. Also set the appropriate flags.
+ Decl *Imported(Decl *From, Decl *To) override {
+ if (auto *ToDC = dyn_cast<DeclContext>(To)) {
+ const bool LoggingEnabled = Parent.LoggingEnabled();
+ if (LoggingEnabled)
+ logs() << "(ExternalASTMerger*)" << (void*)&Parent
+ << " imported (DeclContext*)" << (void*)ToDC
+ << ", (ASTContext*)" << (void*)&getToContext()
+ << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)
+ << ", (ASTContext*)" << (void*)&getFromContext()
+ << "\n";
+ Source<DeclContext *> FromDC(
+ cast<DeclContext>(From)->getPrimaryContext());
+ if (FromOrigins.count(FromDC) &&
+ Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) {
+ if (LoggingEnabled)
+ logs() << "(ExternalASTMerger*)" << (void*)&Parent
+ << " forced origin (DeclContext*)"
+ << (void*)FromOrigins.at(FromDC).DC
+ << ", (ASTContext*)"
+ << (void*)FromOrigins.at(FromDC).AST
+ << "\n";
+ Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC));
+ } else {
+ if (LoggingEnabled)
+ logs() << "(ExternalASTMerger*)" << (void*)&Parent
+ << " maybe recording origin (DeclContext*)" << (void*)FromDC
+ << ", (ASTContext*)" << (void*)&getFromContext()
+ << "\n";
+ Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});
+ }
+ }
+ if (auto *ToTag = dyn_cast<TagDecl>(To)) {
+ ToTag->setHasExternalLexicalStorage();
+ ToTag->setMustBuildLookupTable();
+ assert(Parent.CanComplete(ToTag));
+ } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {
+ ToNamespace->setHasExternalVisibleStorage();
+ assert(Parent.CanComplete(ToNamespace));
+ } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {
+ ToContainer->setHasExternalLexicalStorage();
+ ToContainer->setMustBuildLookupTable();
+ assert(Parent.CanComplete(ToContainer));
+ }
+ return ASTImporter::Imported(From, To);
+ }
+ ASTImporter &GetReverse() { return Reverse; }
+};
+
+bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
+ if (isa<FunctionDecl>(C.first.get()))
+ return false;
+ return llvm::any_of(Decls, [&](const Candidate &D) {
+ return C.first.get()->getKind() == D.first.get()->getKind();
+ });
+}
+
+} // end namespace
+
+ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) {
+ for (const std::unique_ptr<ASTImporter> &I : Importers)
+ if (&I->getFromContext() == &OriginContext)
+ return *I;
+ llvm_unreachable("We should have an importer for this origin!");
+}
+
+namespace {
+LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,
+ ASTContext &OriginContext) {
+ return static_cast<LazyASTImporter &>(
+ Merger.ImporterForOrigin(OriginContext));
+}
+}
+
+bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) {
+ for (const std::unique_ptr<ASTImporter> &I : Importers)
+ if (&I->getFromContext() == &OriginContext)
+ return true;
+ return false;
+}
+
+template <typename CallbackType>
+void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,
+ CallbackType Callback) {
+ if (Origins.count(DC)) {
+ ExternalASTMerger::DCOrigin Origin = Origins[DC];
+ LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
+ Callback(Importer, Importer.GetReverse(), Origin.DC);
+ } else {
+ bool DidCallback = false;
+ for (const std::unique_ptr<ASTImporter> &Importer : Importers) {
+ Source<TranslationUnitDecl *> SourceTU =
+ Importer->getFromContext().getTranslationUnitDecl();
+ ASTImporter &Reverse =
+ static_cast<LazyASTImporter *>(Importer.get())->GetReverse();
+ if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {
+ DidCallback = true;
+ if (Callback(*Importer, Reverse, SourceDC))
+ break;
+ }
+ }
+ if (!DidCallback && LoggingEnabled())
+ logs() << "(ExternalASTMerger*)" << (void*)this
+ << " asserting for (DeclContext*)" << (const void*)DC
+ << ", (ASTContext*)" << (void*)&Target.AST
+ << "\n";
+ assert(DidCallback && "Couldn't find a source context matching our DC");
+ }
+}
+
+void ExternalASTMerger::CompleteType(TagDecl *Tag) {
+ assert(Tag->hasExternalLexicalStorage());
+ ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,
+ Source<const DeclContext *> SourceDC) -> bool {
+ auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));
+ if (SourceTag->hasExternalLexicalStorage())
+ SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);
+ if (!SourceTag->getDefinition())
+ return false;
+ Forward.Imported(SourceTag, Tag);
+ Forward.ImportDefinition(SourceTag);
+ Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());
+ return true;
+ });
+}
+
+void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) {
+ assert(Interface->hasExternalLexicalStorage());
+ ForEachMatchingDC(
+ Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,
+ Source<const DeclContext *> SourceDC) -> bool {
+ auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(
+ cast<ObjCInterfaceDecl>(SourceDC.get()));
+ if (SourceInterface->hasExternalLexicalStorage())
+ SourceInterface->getASTContext().getExternalSource()->CompleteType(
+ SourceInterface);
+ if (!SourceInterface->getDefinition())
+ return false;
+ Forward.Imported(SourceInterface, Interface);
+ Forward.ImportDefinition(SourceInterface);
+ return true;
+ });
+}
+
+bool ExternalASTMerger::CanComplete(DeclContext *Interface) {
+ assert(Interface->hasExternalLexicalStorage() ||
+ Interface->hasExternalVisibleStorage());
+ bool FoundMatchingDC = false;
+ ForEachMatchingDC(Interface,
+ [&](ASTImporter &Forward, ASTImporter &Reverse,
+ Source<const DeclContext *> SourceDC) -> bool {
+ FoundMatchingDC = true;
+ return true;
+ });
+ return FoundMatchingDC;
+}
+
+namespace {
+bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {
+ if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))
+ return true; // There are many cases where Objective-C is ambiguous.
+ if (auto *T1 = dyn_cast<TagDecl>(D1))
+ if (auto *T2 = dyn_cast<TagDecl>(D2))
+ if (T1->getFirstDecl() == T2->getFirstDecl())
+ return true;
+ return D1 == D2 || D1 == CanonicalizeDC(D2);
+}
+}
+
+void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC,
+ DCOrigin Origin) {
+ LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
+ ASTImporter &Reverse = Importer.GetReverse();
+ Source<const DeclContext *> FoundFromDC =
+ LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);
+ const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);
+ if (DoRecord)
+ RecordOriginImpl(ToDC, Origin, Importer);
+ if (LoggingEnabled())
+ logs() << "(ExternalASTMerger*)" << (void*)this
+ << (DoRecord ? " decided " : " decided NOT")
+ << " to record origin (DeclContext*)" << (void*)Origin.DC
+ << ", (ASTContext*)" << (void*)&Origin.AST
+ << "\n";
+}
+
+void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC,
+ DCOrigin Origin) {
+ RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));
+}
+
+void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
+ ASTImporter &Importer) {
+ Origins[ToDC] = Origin;
+ Importer.ASTImporter::Imported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));
+}
+
+ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,
+ llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {
+ AddSources(Sources);
+}
+
+void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) {
+ for (const ImporterSource &S : Sources) {
+ assert(&S.AST != &Target.AST);
+ Importers.push_back(llvm::make_unique<LazyASTImporter>(
+ *this, Target.AST, Target.FM, S.AST, S.FM, S.OM));
+ }
+}
+
+void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
+ if (LoggingEnabled())
+ for (const ImporterSource &S : Sources)
+ logs() << "(ExternalASTMerger*)" << (void*)this
+ << " removing source (ASTContext*)" << (void*)&S.AST
+ << "\n";
+ Importers.erase(
+ std::remove_if(Importers.begin(), Importers.end(),
+ [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {
+ for (const ImporterSource &S : Sources) {
+ if (&Importer->getFromContext() == &S.AST)
+ return true;
+ }
+ return false;
+ }),
+ Importers.end());
+ for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {
+ std::pair<const DeclContext *, DCOrigin> Origin = *OI;
+ bool Erase = false;
+ for (const ImporterSource &S : Sources) {
+ if (&S.AST == Origin.second.AST) {
+ Erase = true;
+ break;
+ }
+ }
+ if (Erase)
+ OI = Origins.erase(OI);
+ else
+ ++OI;
+ }
+}
+
+bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ llvm::SmallVector<NamedDecl *, 1> Decls;
+ llvm::SmallVector<Candidate, 4> Candidates;
+
+ auto FilterFoundDecl = [&Candidates](const Candidate &C) {
+ if (!HasDeclOfSameType(Candidates, C))
+ Candidates.push_back(C);
+ };
+
+ ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
+ Source<const DeclContext *> SourceDC) -> bool {
+ DeclarationName FromName = Reverse.Import(Name);
+ DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
+ for (NamedDecl *FromD : Result) {
+ FilterFoundDecl(std::make_pair(FromD, &Forward));
+ }
+ return false;
+ });
+
+ if (Candidates.empty())
+ return false;
+
+ Decls.reserve(Candidates.size());
+ for (const Candidate &C : Candidates) {
+ 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, [&](ASTImporter &Forward, ASTImporter &Reverse,
+ Source<const DeclContext *> SourceDC) -> bool {
+ for (const Decl *SourceDecl : SourceDC.get()->decls()) {
+ if (IsKindWeWant(SourceDecl->getKind())) {
+ Decl *ImportedDecl = Forward.Import(const_cast<Decl *>(SourceDecl));
+ assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC));
+ (void)ImportedDecl;
+ }
+ }
+ return false;
+ });
+}
+
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 26b1aef0a8..182d38242f 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -29,7 +29,7 @@ ExternalASTSource::getSourceDescriptor(unsigned ID) {
}
ExternalASTSource::ExtKind
-ExternalASTSource::hasExternalDefinitions(unsigned ID) {
+ExternalASTSource::hasExternalDefinitions(const Decl *D) {
return EK_ReplyHazy;
}
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index dd99f2087f..58e2bc8a39 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -11,7 +11,7 @@
// which is used in GCC 3.2 and newer (and many compilers that are
// ABI-compatible with GCC):
//
-// http://mentorembedded.github.io/cxx-abi/abi.html#mangling
+// http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Mangle.h"
@@ -381,6 +381,7 @@ class CXXNameMangler {
AbiTagState AbiTagsRoot;
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+ llvm::DenseMap<StringRef, unsigned> ModuleSubstitutions;
ASTContext &getASTContext() const { return Context.getASTContext(); }
@@ -475,6 +476,8 @@ private:
void mangleNameWithAbiTags(const NamedDecl *ND,
const AbiTagList *AdditionalAbiTags);
+ void mangleModuleName(const Module *M);
+ void mangleModuleNamePrefix(StringRef Name);
void mangleTemplateName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -517,7 +520,7 @@ private:
void mangleOperatorName(DeclarationName Name, unsigned Arity);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleVendorQualifier(StringRef qualifier);
- void mangleQualifiers(Qualifiers Quals);
+ void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr);
void mangleRefQualifier(RefQualifierKind RefQualifier);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
@@ -845,9 +848,9 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND,
const AbiTagList *AdditionalAbiTags) {
- // <name> ::= <nested-name>
- // ::= <unscoped-name>
- // ::= <unscoped-template-name> <template-args>
+ // <name> ::= [<module-name>] <nested-name>
+ // ::= [<module-name>] <unscoped-name>
+ // ::= [<module-name>] <unscoped-template-name> <template-args>
// ::= <local-name>
//
const DeclContext *DC = getEffectiveDeclContext(ND);
@@ -866,6 +869,19 @@ void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND,
DC = IgnoreLinkageSpecDecls(DC);
+ if (isLocalContainerContext(DC)) {
+ mangleLocalName(ND, AdditionalAbiTags);
+ return;
+ }
+
+ // Do not mangle the owning module for an external linkage declaration.
+ // This enables backwards-compatibility with non-modular code, and is
+ // a valid choice since conflicts are not permitted by C++ Modules TS
+ // [basic.def.odr]/6.2.
+ if (!ND->hasExternalFormalLinkage())
+ if (Module *M = ND->getOwningModuleForLinkage())
+ mangleModuleName(M);
+
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
@@ -879,12 +895,42 @@ void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND,
return;
}
- if (isLocalContainerContext(DC)) {
- mangleLocalName(ND, AdditionalAbiTags);
+ mangleNestedName(ND, DC, AdditionalAbiTags);
+}
+
+void CXXNameMangler::mangleModuleName(const Module *M) {
+ // Implement the C++ Modules TS name mangling proposal; see
+ // https://gcc.gnu.org/wiki/cxx-modules?action=AttachFile
+ //
+ // <module-name> ::= W <unscoped-name>+ E
+ // ::= W <module-subst> <unscoped-name>* E
+ Out << 'W';
+ mangleModuleNamePrefix(M->Name);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleModuleNamePrefix(StringRef Name) {
+ // <module-subst> ::= _ <seq-id> # 0 < seq-id < 10
+ // ::= W <seq-id - 10> _ # otherwise
+ auto It = ModuleSubstitutions.find(Name);
+ if (It != ModuleSubstitutions.end()) {
+ if (It->second < 10)
+ Out << '_' << static_cast<char>('0' + It->second);
+ else
+ Out << 'W' << (It->second - 10) << '_';
return;
}
- mangleNestedName(ND, DC, AdditionalAbiTags);
+ // FIXME: Preserve hierarchy in module names rather than flattening
+ // them to strings; use Module*s as substitution keys.
+ auto Parts = Name.rsplit('.');
+ if (Parts.second.empty())
+ Parts.second = Parts.first;
+ else
+ mangleModuleNamePrefix(Parts.first);
+
+ Out << Parts.second.size() << Parts.second;
+ ModuleSubstitutions.insert({Name, ModuleSubstitutions.size()});
}
void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
@@ -982,9 +1028,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.
@@ -1234,14 +1279,23 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
}
if (II) {
- // We must avoid conflicts between internally- and externally-
- // linked variable and function declaration names in the same TU:
+ // Match GCC's naming convention for internal linkage symbols, for
+ // symbols that are not actually visible outside of this TU. GCC
+ // distinguishes between internal and external linkage symbols in
+ // its mangling, to support cases like this that were valid C++ prior
+ // to DR426:
+ //
// void test() { extern void foo(); }
// static void foo();
- // This naming convention is the same as that followed by GCC,
- // though it shouldn't actually matter.
+ //
+ // Don't bother with the L marker for names in anonymous namespaces; the
+ // 12_GLOBAL__N_1 mangling is quite sufficient there, and this better
+ // matches GCC anyway, because GCC does not treat anonymous namespaces as
+ // implying internal linkage.
if (ND && ND->getFormalLinkage() == InternalLinkage &&
- getEffectiveDeclContext(ND)->isFileContext())
+ !ND->isExternallyVisible() &&
+ getEffectiveDeclContext(ND)->isFileContext() &&
+ !ND->isInAnonymousNamespace())
Out << 'L';
auto *FD = dyn_cast<FunctionDecl>(ND);
@@ -1456,7 +1510,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
Qualifiers MethodQuals =
- Qualifiers::fromCVRMask(Method->getTypeQualifiers());
+ Qualifiers::fromCVRUMask(Method->getTypeQualifiers());
// We do not consider restrict a distinguishing attribute for overloading
// purposes so we must not mangle it.
MethodQuals.removeRestrict();
@@ -1621,6 +1675,10 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
// the symbol in question isn't externally visible.
if (!Number)
Number = Context.getBlockId(Block, false);
+ else {
+ // Stored mangling numbers are 1-based.
+ --Number;
+ }
Out << "Ub";
if (Number > 0)
Out << Number - 1;
@@ -1639,10 +1697,15 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// to emit that last part of the prefix here.
if (Decl *Context = Lambda->getLambdaContextDecl()) {
if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
- Context->getDeclContext()->isRecord()) {
+ !isa<ParmVarDecl>(Context)) {
+ // FIXME: 'inline auto [a, b] = []{ return ... };' does not get a
+ // reasonable mangling here.
if (const IdentifierInfo *Name
= cast<NamedDecl>(Context)->getIdentifier()) {
mangleSourceName(Name);
+ const TemplateArgumentList *TemplateArgs = nullptr;
+ if (isTemplate(cast<NamedDecl>(Context), TemplateArgs))
+ mangleTemplateArgs(*TemplateArgs);
Out << 'M';
}
}
@@ -1867,6 +1930,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::IncompleteArray:
case Type::VariableArray:
case Type::DependentSizedArray:
+ case Type::DependentAddressSpace:
case Type::DependentSizedExtVector:
case Type::Vector:
case Type::ExtVector:
@@ -2138,8 +2202,16 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
}
}
-void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
- // Vendor qualifiers come first.
+void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST) {
+ // Vendor qualifiers come first and if they are order-insensitive they must
+ // be emitted in reversed alphabetical order, see Itanium ABI 5.1.5.
+
+ // <type> ::= U <addrspace-expr>
+ if (DAST) {
+ Out << "U2ASI";
+ mangleExpression(DAST->getAddrSpaceExpr());
+ Out << "E";
+ }
// Address space qualifiers start with an ordinary letter.
if (Quals.hasAddressSpace()) {
@@ -2150,20 +2222,22 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
// <type> ::= U <CUDA-addrspace>
SmallString<64> ASString;
- unsigned AS = Quals.getAddressSpace();
+ LangAS AS = Quals.getAddressSpace();
if (Context.getASTContext().addressSpaceMapManglingFor(AS)) {
// <target-addrspace> ::= "AS" <address-space-number>
unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS);
- ASString = "AS" + llvm::utostr(TargetAS);
+ if (TargetAS != 0)
+ ASString = "AS" + llvm::utostr(TargetAS);
} else {
switch (AS) {
default: llvm_unreachable("Not a language specific address space");
- // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant |
- // "generic" ]
+ // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" |
+ // "private"| "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_private: ASString = "CLprivate"; break;
case LangAS::opencl_generic: ASString = "CLgeneric"; break;
// <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ]
case LangAS::cuda_device: ASString = "CUdevice"; break;
@@ -2171,21 +2245,33 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
case LangAS::cuda_shared: ASString = "CUshared"; break;
}
}
- mangleVendorQualifier(ASString);
+ if (!ASString.empty())
+ mangleVendorQualifier(ASString);
}
// The ARC ownership qualifiers start with underscores.
- switch (Quals.getObjCLifetime()) {
// Objective-C ARC Extension:
//
// <type> ::= U "__strong"
// <type> ::= U "__weak"
// <type> ::= U "__autoreleasing"
+ //
+ // Note: we emit __weak first to preserve the order as
+ // required by the Itanium ABI.
+ if (Quals.getObjCLifetime() == Qualifiers::OCL_Weak)
+ mangleVendorQualifier("__weak");
+
+ // __unaligned (from -fms-extensions)
+ if (Quals.hasUnaligned())
+ mangleVendorQualifier("__unaligned");
+
+ // Remaining ARC ownership qualifiers.
+ switch (Quals.getObjCLifetime()) {
case Qualifiers::OCL_None:
break;
case Qualifiers::OCL_Weak:
- mangleVendorQualifier("__weak");
+ // Do nothing as we already handled this case above.
break;
case Qualifiers::OCL_Strong:
@@ -2325,11 +2411,19 @@ void CXXNameMangler::mangleType(QualType T) {
// substitution at the original type.
}
- if (quals) {
- mangleQualifiers(quals);
- // Recurse: even if the qualified type isn't yet substitutable,
- // the unqualified type might be.
- mangleType(QualType(ty, 0));
+ if (quals || ty->isDependentAddressSpaceType()) {
+ if (const DependentAddressSpaceType *DAST =
+ dyn_cast<DependentAddressSpaceType>(ty)) {
+ SplitQualType splitDAST = DAST->getPointeeType().split();
+ mangleQualifiers(splitDAST.Quals, DAST);
+ mangleType(QualType(splitDAST.Ty, 0));
+ } else {
+ mangleQualifiers(quals);
+
+ // Recurse: even if the qualified type isn't yet substitutable,
+ // the unqualified type might be.
+ mangleType(QualType(ty, 0));
+ }
} else {
switch (ty->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
@@ -2381,6 +2475,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits)
// UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits)
// ::= Dh # IEEE 754r half-precision floating point (16 bits)
+ // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits);
// ::= Di # char32_t
// ::= Ds # char16_t
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
@@ -2443,6 +2538,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::Int128:
Out << 'n';
break;
+ case BuiltinType::Float16:
+ Out << "DF16_";
+ break;
case BuiltinType::Half:
Out << "Dh";
break;
@@ -2518,7 +2616,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
case CC_X86ThisCall:
case CC_X86VectorCall:
case CC_X86Pascal:
- case CC_X86_64Win64:
+ case CC_Win64:
case CC_X86_64SysV:
case CC_X86RegCall:
case CC_AAPCS:
@@ -2575,6 +2673,9 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
if (PI.isConsumed())
mangleVendorQualifier("ns_consumed");
+
+ if (PI.isNoEscape())
+ mangleVendorQualifier("noescape");
}
// <type> ::= <function-type>
@@ -2970,6 +3071,12 @@ void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
mangleType(T->getElementType());
}
+void CXXNameMangler::mangleType(const DependentAddressSpaceType *T) {
+ SplitQualType split = T->getPointeeType().split();
+ mangleQualifiers(split.Quals, T);
+ mangleType(QualType(split.Ty, 0));
+}
+
void CXXNameMangler::mangleType(const PackExpansionType *T) {
// <type> ::= Dp <type> # pack expansion (C++0x)
Out << "Dp";
@@ -3332,7 +3439,6 @@ recurse:
case Expr::BlockExprClass:
case Expr::ChooseExprClass:
case Expr::CompoundLiteralExprClass:
- case Expr::DesignatedInitExprClass:
case Expr::ExtVectorElementExprClass:
case Expr::GenericSelectionExprClass:
case Expr::ObjCEncodeExprClass:
@@ -3410,6 +3516,27 @@ recurse:
break;
}
+ case Expr::DesignatedInitExprClass: {
+ auto *DIE = cast<DesignatedInitExpr>(E);
+ for (const auto &Designator : DIE->designators()) {
+ if (Designator.isFieldDesignator()) {
+ Out << "di";
+ mangleSourceName(Designator.getFieldName());
+ } else if (Designator.isArrayDesignator()) {
+ Out << "dx";
+ mangleExpression(DIE->getArrayIndex(Designator));
+ } else {
+ assert(Designator.isArrayRangeDesignator() &&
+ "unknown designator kind");
+ Out << "dX";
+ mangleExpression(DIE->getArrayRangeStart(Designator));
+ mangleExpression(DIE->getArrayRangeEnd(Designator));
+ }
+ }
+ mangleExpression(DIE->getInit());
+ break;
+ }
+
case Expr::CXXDefaultArgExprClass:
mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
break;
@@ -3501,7 +3628,6 @@ recurse:
if (const Expr *Base = PDE->getBase())
mangleMemberExprBase(Base, PDE->isArrow());
NestedNameSpecifier *Qualifier = PDE->getQualifier();
- QualType ScopeType;
if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) {
if (Qualifier) {
mangleUnresolvedPrefix(Qualifier,
@@ -3567,6 +3693,16 @@ recurse:
const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
unsigned N = CE->arg_size();
+ if (CE->isListInitialization()) {
+ assert(N == 1 && "unexpected form for list initialization");
+ auto *IL = cast<InitListExpr>(CE->getArg(0));
+ Out << "tl";
+ mangleType(CE->getType());
+ mangleInitListElements(IL);
+ Out << "E";
+ return;
+ }
+
Out << "cv";
mangleType(CE->getType());
if (N != 1) Out << '_';
@@ -3774,6 +3910,7 @@ recurse:
Out << "v1U" << Kind.size() << Kind;
}
// Fall through to mangle the cast itself.
+ LLVM_FALLTHROUGH;
case Expr::CStyleCastExprClass:
mangleCastExpression(E, "cv");
@@ -4102,7 +4239,13 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) {
// get mangled if used as an rvalue of a known non-class type?
assert(!parm->getType()->isArrayType()
&& "parameter's type is still an array type?");
- mangleQualifiers(parm->getType().getQualifiers());
+
+ if (const DependentAddressSpaceType *DAST =
+ dyn_cast<DependentAddressSpaceType>(parm->getType())) {
+ mangleQualifiers(DAST->getPointeeType().getQualifiers(), DAST);
+ } else {
+ mangleQualifiers(parm->getType().getQualifiers());
+ }
// Parameter index.
if (parmIndex != 0) {
@@ -4326,7 +4469,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
/// substitutions.
static bool hasMangledSubstitutionQualifiers(QualType T) {
Qualifiers Qs = T.getQualifiers();
- return Qs.getCVRQualifiers() || Qs.hasAddressSpace();
+ return Qs.getCVRQualifiers() || Qs.hasAddressSpace() || Qs.hasUnaligned();
}
bool CXXNameMangler::mangleSubstitution(QualType T) {
@@ -4538,9 +4681,11 @@ CXXNameMangler::makeFunctionReturnTypeTags(const FunctionDecl *FD) {
const FunctionProtoType *Proto =
cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
+ FunctionTypeDepthState saved = TrackReturnTypeTags.FunctionTypeDepth.push();
TrackReturnTypeTags.FunctionTypeDepth.enterResultType();
TrackReturnTypeTags.mangleType(Proto->getReturnType());
TrackReturnTypeTags.FunctionTypeDepth.leaveResultType();
+ TrackReturnTypeTags.FunctionTypeDepth.pop(saved);
return TrackReturnTypeTags.AbiTagsRoot.getSortedUniqueUsedAbiTags();
}
diff --git a/lib/AST/Linkage.h b/lib/AST/Linkage.h
new file mode 100644
index 0000000000..e6489c7ef2
--- /dev/null
+++ b/lib/AST/Linkage.h
@@ -0,0 +1,159 @@
+//===----- Linkage.h - Linkage calculation-related utilities ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides AST-internal utilities for linkage and visibility
+// calculation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_AST_LINKAGE_H
+#define LLVM_CLANG_LIB_AST_LINKAGE_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+/// Kinds of LV computation. The linkage side of the computation is
+/// always the same, but different things can change how visibility is
+/// computed.
+struct LVComputationKind {
+ /// The kind of entity whose visibility is ultimately being computed;
+ /// visibility computations for types and non-types follow different rules.
+ unsigned ExplicitKind : 1;
+ /// Whether explicit visibility attributes should be ignored. When set,
+ /// visibility may only be restricted by the visibility of template arguments.
+ unsigned IgnoreExplicitVisibility : 1;
+ /// Whether all visibility should be ignored. When set, we're only interested
+ /// in computing linkage.
+ unsigned IgnoreAllVisibility : 1;
+
+ explicit LVComputationKind(NamedDecl::ExplicitVisibilityKind EK)
+ : ExplicitKind(EK), IgnoreExplicitVisibility(false),
+ IgnoreAllVisibility(false) {}
+
+ NamedDecl::ExplicitVisibilityKind getExplicitVisibilityKind() const {
+ return static_cast<NamedDecl::ExplicitVisibilityKind>(ExplicitKind);
+ }
+
+ bool isTypeVisibility() const {
+ return getExplicitVisibilityKind() == NamedDecl::VisibilityForType;
+ }
+ bool isValueVisibility() const {
+ return getExplicitVisibilityKind() == NamedDecl::VisibilityForValue;
+ }
+
+ /// Do an LV computation when we only care about the linkage.
+ static LVComputationKind forLinkageOnly() {
+ LVComputationKind Result(NamedDecl::VisibilityForValue);
+ Result.IgnoreExplicitVisibility = true;
+ Result.IgnoreAllVisibility = true;
+ return Result;
+ }
+
+ unsigned toBits() {
+ unsigned Bits = 0;
+ Bits = (Bits << 1) | ExplicitKind;
+ Bits = (Bits << 1) | IgnoreExplicitVisibility;
+ Bits = (Bits << 1) | IgnoreAllVisibility;
+ return Bits;
+ }
+};
+
+class LinkageComputer {
+ // We have a cache for repeated linkage/visibility computations. This saves us
+ // from exponential behavior in heavily templated code, such as:
+ //
+ // template <typename T, typename V> struct {};
+ // using A = int;
+ // using B = Foo<A, A>;
+ // using C = Foo<B, B>;
+ // using D = Foo<C, C>;
+ //
+ // The unsigned represents an LVComputationKind.
+ using QueryType = std::pair<const NamedDecl *, unsigned>;
+ llvm::SmallDenseMap<QueryType, LinkageInfo, 8> CachedLinkageInfo;
+
+ static QueryType makeCacheKey(const NamedDecl *ND, LVComputationKind Kind) {
+ return std::make_pair(ND, Kind.toBits());
+ }
+
+ llvm::Optional<LinkageInfo> lookup(const NamedDecl *ND,
+ LVComputationKind Kind) const {
+ auto Iter = CachedLinkageInfo.find(makeCacheKey(ND, Kind));
+ if (Iter == CachedLinkageInfo.end())
+ return None;
+ return Iter->second;
+ }
+
+ void cache(const NamedDecl *ND, LVComputationKind Kind, LinkageInfo Info) {
+ CachedLinkageInfo[makeCacheKey(ND, Kind)] = Info;
+ }
+
+ LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
+ LVComputationKind computation);
+
+ LinkageInfo getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
+ LVComputationKind computation);
+
+ void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo,
+ LVComputationKind computation);
+
+ void mergeTemplateLV(LinkageInfo &LV,
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation);
+
+ void mergeTemplateLV(LinkageInfo &LV,
+ const VarTemplateSpecializationDecl *spec,
+ LVComputationKind computation);
+
+ LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
+ LVComputationKind computation,
+ bool IgnoreVarTypeLinkage);
+
+ LinkageInfo getLVForClassMember(const NamedDecl *D,
+ LVComputationKind computation,
+ bool IgnoreVarTypeLinkage);
+
+ LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
+ LVComputationKind computation);
+
+ LinkageInfo getLVForLocalDecl(const NamedDecl *D,
+ LVComputationKind computation);
+
+ LinkageInfo getLVForType(const Type &T, LVComputationKind computation);
+
+ LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params,
+ LVComputationKind computation);
+
+public:
+ LinkageInfo computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation,
+ bool IgnoreVarTypeLinkage = false);
+
+ LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation);
+
+ LinkageInfo computeTypeLinkageInfo(const Type *T);
+ LinkageInfo computeTypeLinkageInfo(QualType T) {
+ return computeTypeLinkageInfo(T.getTypePtr());
+ }
+
+ LinkageInfo getDeclLinkageAndVisibility(const NamedDecl *D);
+
+ LinkageInfo getTypeLinkageAndVisibility(const Type *T);
+ LinkageInfo getTypeLinkageAndVisibility(QualType T) {
+ return getTypeLinkageAndVisibility(T.getTypePtr());
+ }
+};
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 00d50c0e3b..56a2500274 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -103,6 +103,11 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
if (CC != CCM_Other)
return true;
+ // If the declaration has an owning module for linkage purposes that needs to
+ // be mangled, we must mangle its name.
+ if (!D->hasExternalFormalLinkage() && D->getOwningModuleForLinkage())
+ return true;
+
// In C, functions with no attributes never need to be mangled. Fastpath them.
if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
return false;
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 6e14dd055c..c8048544ab 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -966,16 +966,71 @@ void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) {
}
if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID =
- Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle a local inside this block yet");
- Diags.Report(BD->getLocation(), DiagID);
-
- // FIXME: This is completely, utterly, wrong; see ItaniumMangle
- // for how this should be done.
- Out << "__block_invoke" << Context.getBlockId(BD, false);
- Out << '@';
+ auto Discriminate =
+ [](StringRef Name, const unsigned Discriminator,
+ const unsigned ParameterDiscriminator) -> std::string {
+ std::string Buffer;
+ llvm::raw_string_ostream Stream(Buffer);
+ Stream << Name;
+ if (Discriminator)
+ Stream << '_' << Discriminator;
+ if (ParameterDiscriminator)
+ Stream << '_' << ParameterDiscriminator;
+ return Stream.str();
+ };
+
+ unsigned Discriminator = BD->getBlockManglingNumber();
+ if (!Discriminator)
+ Discriminator = Context.getBlockId(BD, /*Local=*/false);
+
+ // Mangle the parameter position as a discriminator to deal with unnamed
+ // parameters. Rather than mangling the unqualified parameter name,
+ // always use the position to give a uniform mangling.
+ unsigned ParameterDiscriminator = 0;
+ if (const auto *MC = BD->getBlockManglingContextDecl())
+ if (const auto *P = dyn_cast<ParmVarDecl>(MC))
+ if (const auto *F = dyn_cast<FunctionDecl>(P->getDeclContext()))
+ ParameterDiscriminator =
+ F->getNumParams() - P->getFunctionScopeIndex();
+
+ DC = getEffectiveDeclContext(BD);
+
+ Out << '?';
+ mangleSourceName(Discriminate("_block_invoke", Discriminator,
+ ParameterDiscriminator));
+ // If we have a block mangling context, encode that now. This allows us
+ // to discriminate between named static data initializers in the same
+ // scope. This is handled differently from parameters, which use
+ // positions to discriminate between multiple instances.
+ if (const auto *MC = BD->getBlockManglingContextDecl())
+ if (!isa<ParmVarDecl>(MC))
+ if (const auto *ND = dyn_cast<NamedDecl>(MC))
+ mangleUnqualifiedName(ND);
+ // MS ABI and Itanium manglings are in inverted scopes. In the case of a
+ // RecordDecl, mangle the entire scope hierachy at this point rather than
+ // just the unqualified name to get the ordering correct.
+ if (const auto *RD = dyn_cast<RecordDecl>(DC))
+ mangleName(RD);
+ else
+ Out << '@';
+ // void __cdecl
+ Out << "YAX";
+ // struct __block_literal *
+ Out << 'P';
+ // __ptr64
+ if (PointersAre64Bit)
+ Out << 'E';
+ Out << 'A';
+ mangleArtificalTagType(TTK_Struct,
+ Discriminate("__block_literal", Discriminator,
+ ParameterDiscriminator));
+ Out << "@Z";
+
+ // If the effective context was a Record, we have fully mangled the
+ // qualified name and do not need to continue.
+ if (isa<RecordDecl>(DC))
+ break;
+ continue;
} else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(Method);
} else if (isa<NamedDecl>(DC)) {
@@ -1689,6 +1744,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
// ::= _N # bool
// _O # <array in parameter>
// ::= _T # __float80 (Intel)
+ // ::= _S # char16_t
+ // ::= _U # char32_t
// ::= _W # wchar_t
// ::= _Z # __float80 (Digital Mars)
switch (T->getKind()) {
@@ -1809,6 +1866,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
Out << "$$T";
break;
+ case BuiltinType::Float16:
case BuiltinType::Float128:
case BuiltinType::Half: {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -2065,7 +2123,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
switch (CC) {
default:
llvm_unreachable("Unsupported CC for mangling");
- case CC_X86_64Win64:
+ case CC_Win64:
case CC_X86_64SysV:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
@@ -2267,13 +2325,15 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals,
manglePointerExtQualifiers(Quals, PointeeType);
mangleType(PointeeType, Range);
}
+
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
Qualifiers Quals, SourceRange Range) {
+ if (T->isObjCIdType() || T->isObjCClassType())
+ return mangleType(T->getPointeeType(), Range, QMM_Drop);
+
QualType PointeeType = T->getPointeeType();
manglePointerCVQualifiers(Quals);
manglePointerExtQualifiers(Quals, PointeeType);
- // Object pointers never have qualifiers.
- Out << 'A';
mangleType(PointeeType, Range);
}
@@ -2370,6 +2430,15 @@ void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T,
<< Range;
}
+void MicrosoftCXXNameMangler::mangleType(const DependentAddressSpaceType *T,
+ Qualifiers, SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "cannot mangle this dependent address space type yet");
+ Diags.Report(Range.getBegin(), DiagID) << Range;
+}
+
void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers,
SourceRange) {
// ObjC interfaces have structs underlying them.
@@ -2381,7 +2450,7 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Qualifiers,
SourceRange Range) {
// We don't allow overloading by different protocol qualification,
// so mangling them isn't necessary.
- mangleType(T->getBaseType(), Range);
+ mangleType(T->getBaseType(), Range, QMM_Drop);
}
void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index e7c8c16b01..8adaef1fb6 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -441,6 +441,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::Int128:
case BuiltinType::LongDouble:
case BuiltinType::UInt128:
+ case BuiltinType::Float16:
case BuiltinType::Float128:
case BuiltinType::NullPtr:
case BuiltinType::ObjCClass:
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 514c7c9f5b..e2e0dbeec0 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -290,6 +290,7 @@ NestedNameSpecifier::print(raw_ostream &OS,
case TypeSpecWithTemplate:
OS << "template ";
// Fall through to print the type.
+ LLVM_FALLTHROUGH;
case TypeSpec: {
const Type *T = getAsType();
diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp
index d72eebbe8e..17c95f2a0a 100644
--- a/lib/AST/ODRHash.cpp
+++ b/lib/AST/ODRHash.cpp
@@ -81,10 +81,91 @@ void ODRHash::AddDeclarationName(DeclarationName Name) {
}
}
-void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {}
-void ODRHash::AddTemplateName(TemplateName Name) {}
-void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
-void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
+void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
+ assert(NNS && "Expecting non-null pointer.");
+ const auto *Prefix = NNS->getPrefix();
+ AddBoolean(Prefix);
+ if (Prefix) {
+ AddNestedNameSpecifier(Prefix);
+ }
+ auto Kind = NNS->getKind();
+ ID.AddInteger(Kind);
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ AddIdentifierInfo(NNS->getAsIdentifier());
+ break;
+ case NestedNameSpecifier::Namespace:
+ AddDecl(NNS->getAsNamespace());
+ break;
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDecl(NNS->getAsNamespaceAlias());
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ AddType(NNS->getAsType());
+ break;
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
+ break;
+ }
+}
+
+void ODRHash::AddTemplateName(TemplateName Name) {
+ auto Kind = Name.getKind();
+ ID.AddInteger(Kind);
+
+ switch (Kind) {
+ case TemplateName::Template:
+ AddDecl(Name.getAsTemplateDecl());
+ break;
+ // TODO: Support these cases.
+ case TemplateName::OverloadedTemplate:
+ case TemplateName::QualifiedTemplate:
+ case TemplateName::DependentTemplate:
+ case TemplateName::SubstTemplateTemplateParm:
+ case TemplateName::SubstTemplateTemplateParmPack:
+ break;
+ }
+}
+
+void ODRHash::AddTemplateArgument(TemplateArgument TA) {
+ const auto Kind = TA.getKind();
+ ID.AddInteger(Kind);
+
+ switch (Kind) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Expected valid TemplateArgument");
+ case TemplateArgument::Type:
+ AddQualType(TA.getAsType());
+ break;
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Integral:
+ break;
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ AddTemplateName(TA.getAsTemplateOrTemplatePattern());
+ break;
+ case TemplateArgument::Expression:
+ AddStmt(TA.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ ID.AddInteger(TA.pack_size());
+ for (auto SubTA : TA.pack_elements()) {
+ AddTemplateArgument(SubTA);
+ }
+ break;
+ }
+}
+
+void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {
+ assert(TPL && "Expecting non-null pointer.");
+
+ ID.AddInteger(TPL->size());
+ for (auto *ND : TPL->asArray()) {
+ AddSubDecl(ND);
+ }
+}
void ODRHash::clear() {
DeclMap.clear();
@@ -125,6 +206,7 @@ unsigned ODRHash::CalculateHash() {
return ID.ComputeHash();
}
+namespace {
// 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> {
@@ -154,6 +236,17 @@ public:
Hash.AddQualType(T);
}
+ void AddDecl(const Decl *D) {
+ Hash.AddBoolean(D);
+ if (D) {
+ Hash.AddDecl(D);
+ }
+ }
+
+ void AddTemplateArgument(TemplateArgument TA) {
+ Hash.AddTemplateArgument(TA);
+ }
+
void Visit(const Decl *D) {
ID.AddInteger(D->getKind());
Inherited::Visit(D);
@@ -165,10 +258,28 @@ public:
}
void VisitValueDecl(const ValueDecl *D) {
- AddQualType(D->getType());
+ if (!isa<FunctionDecl>(D)) {
+ AddQualType(D->getType());
+ }
Inherited::VisitValueDecl(D);
}
+ void VisitVarDecl(const VarDecl *D) {
+ Hash.AddBoolean(D->isStaticLocal());
+ Hash.AddBoolean(D->isConstexpr());
+ const bool HasInit = D->hasInit();
+ Hash.AddBoolean(HasInit);
+ if (HasInit) {
+ AddStmt(D->getInit());
+ }
+ Inherited::VisitVarDecl(D);
+ }
+
+ void VisitParmVarDecl(const ParmVarDecl *D) {
+ // TODO: Handle default arguments.
+ Inherited::VisitParmVarDecl(D);
+ }
+
void VisitAccessSpecDecl(const AccessSpecDecl *D) {
ID.AddInteger(D->getAccess());
Inherited::VisitAccessSpecDecl(D);
@@ -202,6 +313,14 @@ public:
Hash.AddBoolean(D->isPure());
Hash.AddBoolean(D->isDeletedAsWritten());
+ ID.AddInteger(D->param_size());
+
+ for (auto *Param : D->parameters()) {
+ Hash.AddSubDecl(Param);
+ }
+
+ AddQualType(D->getReturnType());
+
Inherited::VisitFunctionDecl(D);
}
@@ -225,7 +344,54 @@ public:
void VisitTypeAliasDecl(const TypeAliasDecl *D) {
Inherited::VisitTypeAliasDecl(D);
}
+
+ void VisitFriendDecl(const FriendDecl *D) {
+ TypeSourceInfo *TSI = D->getFriendType();
+ Hash.AddBoolean(TSI);
+ if (TSI) {
+ AddQualType(TSI->getType());
+ } else {
+ AddDecl(D->getFriendDecl());
+ }
+ }
+
+ void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+ // Only care about default arguments as part of the definition.
+ const bool hasDefaultArgument =
+ D->hasDefaultArgument() && !D->defaultArgumentWasInherited();
+ Hash.AddBoolean(hasDefaultArgument);
+ if (hasDefaultArgument) {
+ AddTemplateArgument(D->getDefaultArgument());
+ }
+
+ Inherited::VisitTemplateTypeParmDecl(D);
+ }
+
+ void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
+ // Only care about default arguments as part of the definition.
+ const bool hasDefaultArgument =
+ D->hasDefaultArgument() && !D->defaultArgumentWasInherited();
+ Hash.AddBoolean(hasDefaultArgument);
+ if (hasDefaultArgument) {
+ AddStmt(D->getDefaultArgument());
+ }
+
+ Inherited::VisitNonTypeTemplateParmDecl(D);
+ }
+
+ void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
+ // Only care about default arguments as part of the definition.
+ const bool hasDefaultArgument =
+ D->hasDefaultArgument() && !D->defaultArgumentWasInherited();
+ Hash.AddBoolean(hasDefaultArgument);
+ if (hasDefaultArgument) {
+ AddTemplateArgument(D->getDefaultArgument().getArgument());
+ }
+
+ Inherited::VisitTemplateTemplateParmDecl(D);
+ }
};
+} // namespace
// Only allow a small portion of Decl's to be processed. Remove this once
// all Decl's can be handled.
@@ -237,11 +403,15 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
default:
return false;
case Decl::AccessSpec:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
case Decl::CXXMethod:
case Decl::Field:
+ case Decl::Friend:
case Decl::StaticAssert:
case Decl::TypeAlias:
case Decl::Typedef:
+ case Decl::Var:
return true;
}
}
@@ -256,6 +426,15 @@ void ODRHash::AddSubDecl(const Decl *D) {
void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
assert(Record && Record->hasDefinition() &&
"Expected non-null record to be a definition.");
+
+ const DeclContext *DC = Record;
+ while (DC) {
+ if (isa<ClassTemplateSpecializationDecl>(DC)) {
+ return;
+ }
+ DC = DC->getParent();
+ }
+
AddDecl(Record);
// Filter out sub-Decls which will not be processed in order to get an
@@ -271,6 +450,20 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
for (auto SubDecl : Decls) {
AddSubDecl(SubDecl);
}
+
+ const ClassTemplateDecl *TD = Record->getDescribedClassTemplate();
+ AddBoolean(TD);
+ if (TD) {
+ AddTemplateParameterList(TD->getTemplateParameters());
+ }
+
+ ID.AddInteger(Record->getNumBases());
+ auto Bases = Record->bases();
+ for (auto Base : Bases) {
+ AddQualType(Base.getType());
+ ID.AddInteger(Base.isVirtual());
+ ID.AddInteger(Base.getAccessSpecifierAsWritten());
+ }
}
void ODRHash::AddDecl(const Decl *D) {
@@ -290,6 +483,7 @@ void ODRHash::AddDecl(const Decl *D) {
}
}
+namespace {
// 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> {
@@ -315,6 +509,35 @@ public:
}
}
+ void AddQualType(QualType T) {
+ Hash.AddQualType(T);
+ }
+
+ void AddType(const Type *T) {
+ Hash.AddBoolean(T);
+ if (T) {
+ Hash.AddType(T);
+ }
+ }
+
+ void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
+ Hash.AddBoolean(NNS);
+ if (NNS) {
+ Hash.AddNestedNameSpecifier(NNS);
+ }
+ }
+
+ void AddIdentifierInfo(const IdentifierInfo *II) {
+ Hash.AddBoolean(II);
+ if (II) {
+ Hash.AddIdentifierInfo(II);
+ }
+ }
+
+ void VisitQualifiers(Qualifiers Quals) {
+ ID.AddInteger(Quals.getAsOpaqueValue());
+ }
+
void Visit(const Type *T) {
ID.AddInteger(T->getTypeClass());
Inherited::Visit(T);
@@ -322,17 +545,134 @@ public:
void VisitType(const Type *T) {}
+ void VisitAdjustedType(const AdjustedType *T) {
+ AddQualType(T->getOriginalType());
+ AddQualType(T->getAdjustedType());
+ VisitType(T);
+ }
+
+ void VisitDecayedType(const DecayedType *T) {
+ AddQualType(T->getDecayedType());
+ AddQualType(T->getPointeeType());
+ VisitAdjustedType(T);
+ }
+
+ void VisitArrayType(const ArrayType *T) {
+ AddQualType(T->getElementType());
+ ID.AddInteger(T->getSizeModifier());
+ VisitQualifiers(T->getIndexTypeQualifiers());
+ VisitType(T);
+ }
+ void VisitConstantArrayType(const ConstantArrayType *T) {
+ T->getSize().Profile(ID);
+ VisitArrayType(T);
+ }
+
+ void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
+ AddStmt(T->getSizeExpr());
+ VisitArrayType(T);
+ }
+
+ void VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ VisitArrayType(T);
+ }
+
+ void VisitVariableArrayType(const VariableArrayType *T) {
+ AddStmt(T->getSizeExpr());
+ VisitArrayType(T);
+ }
+
void VisitBuiltinType(const BuiltinType *T) {
ID.AddInteger(T->getKind());
VisitType(T);
}
+ void VisitFunctionType(const FunctionType *T) {
+ AddQualType(T->getReturnType());
+ T->getExtInfo().Profile(ID);
+ Hash.AddBoolean(T->isConst());
+ Hash.AddBoolean(T->isVolatile());
+ Hash.AddBoolean(T->isRestrict());
+ VisitType(T);
+ }
+
+ void VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+ VisitFunctionType(T);
+ }
+
+ void VisitFunctionProtoType(const FunctionProtoType *T) {
+ ID.AddInteger(T->getNumParams());
+ for (auto ParamType : T->getParamTypes())
+ AddQualType(ParamType);
+
+ VisitFunctionType(T);
+ }
+
void VisitTypedefType(const TypedefType *T) {
AddDecl(T->getDecl());
- Hash.AddQualType(T->getDecl()->getUnderlyingType());
+ QualType UnderlyingType = T->getDecl()->getUnderlyingType();
+ VisitQualifiers(UnderlyingType.getQualifiers());
+ while (const TypedefType *Underlying =
+ dyn_cast<TypedefType>(UnderlyingType.getTypePtr())) {
+ UnderlyingType = Underlying->getDecl()->getUnderlyingType();
+ }
+ AddType(UnderlyingType.getTypePtr());
+ VisitType(T);
+ }
+
+ void VisitTagType(const TagType *T) {
+ AddDecl(T->getDecl());
VisitType(T);
}
+
+ void VisitRecordType(const RecordType *T) { VisitTagType(T); }
+ void VisitEnumType(const EnumType *T) { VisitTagType(T); }
+
+ void VisitTypeWithKeyword(const TypeWithKeyword *T) {
+ ID.AddInteger(T->getKeyword());
+ VisitType(T);
+ };
+
+ void VisitDependentNameType(const DependentNameType *T) {
+ AddNestedNameSpecifier(T->getQualifier());
+ AddIdentifierInfo(T->getIdentifier());
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitDependentTemplateSpecializationType(
+ const DependentTemplateSpecializationType *T) {
+ AddIdentifierInfo(T->getIdentifier());
+ AddNestedNameSpecifier(T->getQualifier());
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->template_arguments()) {
+ Hash.AddTemplateArgument(TA);
+ }
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitElaboratedType(const ElaboratedType *T) {
+ AddNestedNameSpecifier(T->getQualifier());
+ AddQualType(T->getNamedType());
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->template_arguments()) {
+ Hash.AddTemplateArgument(TA);
+ }
+ Hash.AddTemplateName(T->getTemplateName());
+ VisitType(T);
+ }
+
+ void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+ ID.AddInteger(T->getDepth());
+ ID.AddInteger(T->getIndex());
+ Hash.AddBoolean(T->isParameterPack());
+ AddDecl(T->getDecl());
+ }
};
+} // namespace
void ODRHash::AddType(const Type *T) {
assert(T && "Expecting non-null pointer.");
diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp
index 77470a9b76..a4fa4b07a1 100644
--- a/lib/AST/OpenMPClause.cpp
+++ b/lib/AST/OpenMPClause.cpp
@@ -46,6 +46,10 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPLastprivateClause *>(C);
case OMPC_reduction:
return static_cast<const OMPReductionClause *>(C);
+ case OMPC_task_reduction:
+ return static_cast<const OMPTaskReductionClause *>(C);
+ case OMPC_in_reduction:
+ return static_cast<const OMPInReductionClause *>(C);
case OMPC_linear:
return static_cast<const OMPLinearClause *>(C);
case OMPC_if:
@@ -56,6 +60,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPNumTeamsClause *>(C);
case OMPC_thread_limit:
return static_cast<const OMPThreadLimitClause *>(C);
+ case OMPC_device:
+ return static_cast<const OMPDeviceClause *>(C);
case OMPC_default:
case OMPC_proc_bind:
case OMPC_final:
@@ -79,7 +85,6 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_depend:
- case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
@@ -112,6 +117,10 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
return static_cast<const OMPLastprivateClause *>(C);
case OMPC_reduction:
return static_cast<const OMPReductionClause *>(C);
+ case OMPC_task_reduction:
+ return static_cast<const OMPTaskReductionClause *>(C);
+ case OMPC_in_reduction:
+ return static_cast<const OMPInReductionClause *>(C);
case OMPC_linear:
return static_cast<const OMPLinearClause *>(C);
case OMPC_schedule:
@@ -505,6 +514,122 @@ OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPReductionClause(N);
}
+void OMPTaskReductionClause::setPrivates(ArrayRef<Expr *> Privates) {
+ assert(Privates.size() == varlist_size() &&
+ "Number of private copies is not the same as the preallocated buffer");
+ std::copy(Privates.begin(), Privates.end(), varlist_end());
+}
+
+void OMPTaskReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
+ assert(
+ LHSExprs.size() == varlist_size() &&
+ "Number of LHS expressions is not the same as the preallocated buffer");
+ std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end());
+}
+
+void OMPTaskReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
+ assert(
+ RHSExprs.size() == varlist_size() &&
+ "Number of RHS expressions is not the same as the preallocated buffer");
+ std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end());
+}
+
+void OMPTaskReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) {
+ assert(ReductionOps.size() == varlist_size() && "Number of task reduction "
+ "expressions is not the same "
+ "as the preallocated buffer");
+ std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end());
+}
+
+OMPTaskReductionClause *OMPTaskReductionClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
+ NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
+ ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs,
+ ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps, Stmt *PreInit,
+ Expr *PostUpdate) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
+ OMPTaskReductionClause *Clause = new (Mem) OMPTaskReductionClause(
+ StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
+ Clause->setVarRefs(VL);
+ Clause->setPrivates(Privates);
+ Clause->setLHSExprs(LHSExprs);
+ Clause->setRHSExprs(RHSExprs);
+ Clause->setReductionOps(ReductionOps);
+ Clause->setPreInitStmt(PreInit);
+ Clause->setPostUpdateExpr(PostUpdate);
+ return Clause;
+}
+
+OMPTaskReductionClause *OMPTaskReductionClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * N));
+ return new (Mem) OMPTaskReductionClause(N);
+}
+
+void OMPInReductionClause::setPrivates(ArrayRef<Expr *> Privates) {
+ assert(Privates.size() == varlist_size() &&
+ "Number of private copies is not the same as the preallocated buffer");
+ std::copy(Privates.begin(), Privates.end(), varlist_end());
+}
+
+void OMPInReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
+ assert(
+ LHSExprs.size() == varlist_size() &&
+ "Number of LHS expressions is not the same as the preallocated buffer");
+ std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end());
+}
+
+void OMPInReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
+ assert(
+ RHSExprs.size() == varlist_size() &&
+ "Number of RHS expressions is not the same as the preallocated buffer");
+ std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end());
+}
+
+void OMPInReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) {
+ assert(ReductionOps.size() == varlist_size() && "Number of in reduction "
+ "expressions is not the same "
+ "as the preallocated buffer");
+ std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end());
+}
+
+void OMPInReductionClause::setTaskgroupDescriptors(
+ ArrayRef<Expr *> TaskgroupDescriptors) {
+ assert(TaskgroupDescriptors.size() == varlist_size() &&
+ "Number of in reduction descriptors is not the same as the "
+ "preallocated buffer");
+ std::copy(TaskgroupDescriptors.begin(), TaskgroupDescriptors.end(),
+ getReductionOps().end());
+}
+
+OMPInReductionClause *OMPInReductionClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
+ NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
+ ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs,
+ ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps,
+ ArrayRef<Expr *> TaskgroupDescriptors, Stmt *PreInit, Expr *PostUpdate) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(6 * VL.size()));
+ OMPInReductionClause *Clause = new (Mem) OMPInReductionClause(
+ StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
+ Clause->setVarRefs(VL);
+ Clause->setPrivates(Privates);
+ Clause->setLHSExprs(LHSExprs);
+ Clause->setRHSExprs(RHSExprs);
+ Clause->setReductionOps(ReductionOps);
+ Clause->setTaskgroupDescriptors(TaskgroupDescriptors);
+ Clause->setPreInitStmt(PreInit);
+ Clause->setPostUpdateExpr(PostUpdate);
+ return Clause;
+}
+
+OMPInReductionClause *OMPInReductionClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(6 * N));
+ return new (Mem) OMPInReductionClause(N);
+}
+
OMPFlushClause *OMPFlushClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index cf981be0a4..0083e390cb 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -632,6 +632,9 @@ protected:
/// pointer, as opposed to inheriting one from a primary base class.
bool HasOwnVFPtr;
+ /// \brief the flag of field offset changing due to packed attribute.
+ bool HasPackedField;
+
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
@@ -666,7 +669,7 @@ protected:
NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()), PrimaryBase(nullptr),
PrimaryBaseIsVirtual(false), HasOwnVFPtr(false),
- FirstNearlyEmptyVBase(nullptr) {}
+ HasPackedField(false), FirstNearlyEmptyVBase(nullptr) {}
void Layout(const RecordDecl *D);
void Layout(const CXXRecordDecl *D);
@@ -1166,7 +1169,6 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
// Query the external layout to see if it provides an offset.
bool HasExternalLayout = false;
if (UseExternalLayout) {
- llvm::DenseMap<const CXXRecordDecl *, CharUnits>::iterator Known;
if (Base->IsVirtual)
HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset);
else
@@ -1729,7 +1731,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
const ArrayType* ATy = Context.getAsArrayType(D->getType());
FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
- unsigned AS = RT->getPointeeType().getAddressSpace();
+ unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType());
FieldSize =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
FieldAlign =
@@ -1847,7 +1849,6 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
uint64_t UnpackedSizeInBits =
llvm::alignTo(getSizeInBits(), Context.toBits(UnpackedAlignment));
- CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits);
uint64_t RoundedSize =
llvm::alignTo(getSizeInBits(), Context.toBits(Alignment));
@@ -1882,10 +1883,11 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
<< (InBits ? 1 : 0); // (byte|bit)
}
- // Warn if we packed it unnecessarily. If the alignment is 1 byte don't
- // bother since there won't be alignment issues.
- if (Packed && UnpackedAlignment > CharUnits::One() &&
- getSize() == UnpackedSize)
+ // Warn if we packed it unnecessarily, when the unpacked alignment is not
+ // greater than the one after packing, the size in bits doesn't change and
+ // the offset of each field is identical.
+ if (Packed && UnpackedAlignment <= Alignment &&
+ UnpackedSizeInBits == getSizeInBits() && !HasPackedField)
Diag(D->getLocation(), diag::warn_unnecessary_packed)
<< Context.getTypeDeclType(RD);
}
@@ -1977,13 +1979,10 @@ void ItaniumRecordLayoutBuilder::CheckFieldPadding(
<< Context.getTypeDeclType(D->getParent())
<< PadSize
<< (InBits ? 1 : 0); // (byte|bit)
- }
-
- // Warn if we packed it unnecessarily. If the alignment is 1 byte don't
- // bother since there won't be alignment issues.
- if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset)
- Diag(D->getLocation(), diag::warn_unnecessary_packed)
- << D->getIdentifier();
+ }
+ if (isPacked && Offset != UnpackedOffset) {
+ HasPackedField = true;
+ }
}
static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
@@ -2084,7 +2083,7 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
// rules, we should implement the restrictions about over-sized
// bitfields:
//
- // http://mentorembedded.github.com/cxx-abi/abi.html#POD :
+ // http://itanium-cxx-abi.github.io/cxx-abi/abi.html#POD :
// In general, a type is considered a POD for the purposes of
// layout if it is a POD type (in the sense of ISO C++
// [basic.types]). However, a POD-struct or POD-union (in the
@@ -3073,6 +3072,41 @@ uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const {
return OffsetInBits;
}
+uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID,
+ const ObjCImplementationDecl *ID,
+ const ObjCIvarDecl *Ivar) const {
+ const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
+
+ // FIXME: We should eliminate the need to have ObjCImplementationDecl passed
+ // in here; it should never be necessary because that should be the lexical
+ // decl context for the ivar.
+
+ // If we know have an implementation (and the ivar is in it) then
+ // look up in the implementation layout.
+ const ASTRecordLayout *RL;
+ if (ID && declaresSameEntity(ID->getClassInterface(), Container))
+ RL = &getASTObjCImplementationLayout(ID);
+ else
+ RL = &getASTObjCInterfaceLayout(Container);
+
+ // Compute field index.
+ //
+ // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is
+ // implemented. This should be fixed to get the information from the layout
+ // directly.
+ unsigned Index = 0;
+
+ for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
+ if (Ivar == IVD)
+ break;
+ ++Index;
+ }
+ assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
+
+ return RL->getFieldOffset(Index);
+}
+
/// getObjCLayout - Get or compute information about the layout of the
/// given interface.
///
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 697cdc3fb3..922ff1f8de 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);
}
@@ -1112,13 +1112,9 @@ void CapturedStmt::setCapturedRegionKind(CapturedRegionKind Kind) {
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
for (const auto &I : captures()) {
- if (!I.capturesVariable())
+ if (!I.capturesVariable() && !I.capturesVariableByCopy())
continue;
-
- // This does not handle variable redeclarations. This should be
- // extended to capture variables with redeclarations, for example
- // a thread-private variable in OpenMP.
- if (I.getCapturedVar() == Var)
+ if (I.getCapturedVar()->getCanonicalDecl() == Var->getCanonicalDecl())
return true;
}
diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp
index 5c7686c8cb..666f5dcc9d 100644
--- a/lib/AST/StmtCXX.cpp
+++ b/lib/AST/StmtCXX.cpp
@@ -88,7 +88,7 @@ const VarDecl *CXXForRangeStmt::getLoopVariable() const {
}
CoroutineBodyStmt *CoroutineBodyStmt::Create(
- const ASTContext &C, CoroutineBodyStmt::CtorArgs const& Args) {
+ const ASTContext &C, CoroutineBodyStmt::CtorArgs const &Args) {
std::size_t Size = totalSizeToAlloc<Stmt *>(
CoroutineBodyStmt::FirstParamMove + Args.ParamMoves.size());
@@ -96,6 +96,20 @@ CoroutineBodyStmt *CoroutineBodyStmt::Create(
return new (Mem) CoroutineBodyStmt(Args);
}
+CoroutineBodyStmt *CoroutineBodyStmt::Create(const ASTContext &C, EmptyShell,
+ unsigned NumParams) {
+ std::size_t Size = totalSizeToAlloc<Stmt *>(
+ CoroutineBodyStmt::FirstParamMove + NumParams);
+
+ void *Mem = C.Allocate(Size, alignof(CoroutineBodyStmt));
+ auto *Result = new (Mem) CoroutineBodyStmt(CtorArgs());
+ Result->NumParams = NumParams;
+ auto *ParamBegin = Result->getStoredStmts() + SubStmt::FirstParamMove;
+ std::uninitialized_fill(ParamBegin, ParamBegin + NumParams,
+ static_cast<Stmt *>(nullptr));
+ return Result;
+}
+
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
: Stmt(CoroutineBodyStmtClass), NumParams(Args.ParamMoves.size()) {
Stmt **SubStmts = getStoredStmts();
@@ -108,6 +122,10 @@ CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
SubStmts[CoroutineBodyStmt::Allocate] = Args.Allocate;
SubStmts[CoroutineBodyStmt::Deallocate] = Args.Deallocate;
SubStmts[CoroutineBodyStmt::ReturnValue] = Args.ReturnValue;
+ SubStmts[CoroutineBodyStmt::ResultDecl] = Args.ResultDecl;
+ SubStmts[CoroutineBodyStmt::ReturnStmt] = Args.ReturnStmt;
+ SubStmts[CoroutineBodyStmt::ReturnStmtOnAllocFailure] =
+ Args.ReturnStmtOnAllocFailure;
std::copy(Args.ParamMoves.begin(), Args.ParamMoves.end(),
const_cast<Stmt **>(getParamMoves().data()));
-} \ No newline at end of file
+}
diff --git a/lib/AST/StmtOpenMP.cpp b/lib/AST/StmtOpenMP.cpp
index a812884cd9..b4e5795211 100644
--- a/lib/AST/StmtOpenMP.cpp
+++ b/lib/AST/StmtOpenMP.cpp
@@ -147,10 +147,6 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -201,10 +197,6 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -368,10 +360,6 @@ OMPParallelForDirective *OMPParallelForDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -421,10 +409,6 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -538,23 +522,29 @@ OMPTaskwaitDirective *OMPTaskwaitDirective::CreateEmpty(const ASTContext &C,
return new (Mem) OMPTaskwaitDirective();
}
-OMPTaskgroupDirective *OMPTaskgroupDirective::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation EndLoc,
- Stmt *AssociatedStmt) {
- unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective), alignof(Stmt *));
- void *Mem = C.Allocate(Size + sizeof(Stmt *));
+OMPTaskgroupDirective *OMPTaskgroupDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *ReductionRef) {
+ unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective) +
+ sizeof(OMPClause *) * Clauses.size(),
+ alignof(Stmt *));
+ void *Mem = C.Allocate(Size + sizeof(Stmt *) + sizeof(Expr *));
OMPTaskgroupDirective *Dir =
- new (Mem) OMPTaskgroupDirective(StartLoc, EndLoc);
+ new (Mem) OMPTaskgroupDirective(StartLoc, EndLoc, Clauses.size());
Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setReductionRef(ReductionRef);
+ Dir->setClauses(Clauses);
return Dir;
}
OMPTaskgroupDirective *OMPTaskgroupDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective), alignof(Stmt *));
- void *Mem = C.Allocate(Size + sizeof(Stmt *));
- return new (Mem) OMPTaskgroupDirective();
+ unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective) +
+ sizeof(OMPClause *) * NumClauses,
+ alignof(Stmt *));
+ void *Mem = C.Allocate(Size + sizeof(Stmt *) + sizeof(Expr *));
+ return new (Mem) OMPTaskgroupDirective(NumClauses);
}
OMPCancellationPointDirective *OMPCancellationPointDirective::Create(
@@ -759,10 +749,6 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -904,10 +890,6 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -957,10 +939,6 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1009,10 +987,6 @@ OMPDistributeDirective *OMPDistributeDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1095,6 +1069,13 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create(
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1153,6 +1134,13 @@ OMPDistributeParallelForSimdDirective::Create(
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1200,10 +1188,6 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1256,10 +1240,6 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1352,10 +1332,6 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1407,10 +1383,6 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1474,6 +1446,13 @@ OMPTeamsDistributeParallelForSimdDirective::Create(
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1534,6 +1513,13 @@ OMPTeamsDistributeParallelForDirective::Create(
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1606,10 +1592,6 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
- Dir->setDistInc(Exprs.DistInc);
- Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1676,6 +1658,13 @@ OMPTargetTeamsDistributeParallelForDirective::Create(
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1739,6 +1728,13 @@ OMPTargetTeamsDistributeParallelForSimdDirective::Create(
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1789,10 +1785,6 @@ OMPTargetTeamsDistributeSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
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 21f5259c3c..371d3e181d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Format.h"
using namespace clang;
@@ -38,12 +39,14 @@ namespace {
unsigned IndentLevel;
clang::PrinterHelper* Helper;
PrintingPolicy Policy;
+ const ASTContext *Context;
public:
- StmtPrinter(raw_ostream &os, PrinterHelper* helper,
- const PrintingPolicy &Policy,
- unsigned Indentation = 0)
- : OS(os), IndentLevel(Indentation), Helper(helper), Policy(Policy) {}
+ StmtPrinter(raw_ostream &os, PrinterHelper *helper,
+ const PrintingPolicy &Policy, unsigned Indentation = 0,
+ const ASTContext *Context = nullptr)
+ : OS(os), IndentLevel(Indentation), Helper(helper), Policy(Policy),
+ Context(Context) {}
void PrintStmt(Stmt *S) {
PrintStmt(S, Policy.Indentation);
@@ -836,6 +839,51 @@ void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPTaskReductionClause(
+ OMPTaskReductionClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "task_reduction(";
+ NestedNameSpecifier *QualifierLoc =
+ Node->getQualifierLoc().getNestedNameSpecifier();
+ OverloadedOperatorKind OOK =
+ Node->getNameInfo().getName().getCXXOverloadedOperator();
+ if (QualifierLoc == nullptr && OOK != OO_None) {
+ // Print reduction identifier in C format
+ OS << getOperatorSpelling(OOK);
+ } else {
+ // Use C++ format
+ if (QualifierLoc != nullptr)
+ QualifierLoc->print(OS, Policy);
+ OS << Node->getNameInfo();
+ }
+ OS << ":";
+ VisitOMPClauseList(Node, ' ');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPInReductionClause(OMPInReductionClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "in_reduction(";
+ NestedNameSpecifier *QualifierLoc =
+ Node->getQualifierLoc().getNestedNameSpecifier();
+ OverloadedOperatorKind OOK =
+ Node->getNameInfo().getName().getCXXOverloadedOperator();
+ if (QualifierLoc == nullptr && OOK != OO_None) {
+ // Print reduction identifier in C format
+ OS << getOperatorSpelling(OOK);
+ } else {
+ // Use C++ format
+ if (QualifierLoc != nullptr)
+ QualifierLoc->print(OS, Policy);
+ OS << Node->getNameInfo();
+ }
+ OS << ":";
+ VisitOMPClauseList(Node, ' ');
+ OS << ")";
+ }
+}
+
void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
if (!Node->varlist_empty()) {
OS << "linear";
@@ -1081,7 +1129,7 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
}
void StmtPrinter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *Node) {
- Indent() << "#pragma omp taskgroup";
+ Indent() << "#pragma omp taskgroup ";
PrintOMPExecutableDirective(Node);
}
@@ -1298,10 +1346,25 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
OS, Node->template_arguments(), Policy);
}
+static bool isImplicitSelf(const Expr *E) {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (const ImplicitParamDecl *PD =
+ dyn_cast<ImplicitParamDecl>(DRE->getDecl())) {
+ if (PD->getParameterKind() == ImplicitParamDecl::ObjCSelf &&
+ DRE->getLocStart().isInvalid())
+ return true;
+ }
+ }
+ return false;
+}
+
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
if (Node->getBase()) {
- PrintExpr(Node->getBase());
- OS << (Node->isArrow() ? "->" : ".");
+ if (!Policy.SuppressImplicitBase ||
+ !isImplicitSelf(Node->getBase()->IgnoreImpCasts())) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ }
}
OS << *Node->getDecl();
}
@@ -1396,7 +1459,26 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
}
}
+/// Prints the given expression using the original source text. Returns true on
+/// success, false otherwise.
+static bool printExprAsWritten(raw_ostream &OS, Expr *E,
+ const ASTContext *Context) {
+ if (!Context)
+ return false;
+ bool Invalid = false;
+ StringRef Source = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(E->getSourceRange()),
+ Context->getSourceManager(), Context->getLangOpts(), &Invalid);
+ if (!Invalid) {
+ OS << Source;
+ return true;
+ }
+ return false;
+}
+
void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
+ if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context))
+ return;
bool isSigned = Node->getType()->isSignedIntegerType();
OS << Node->getValue().toString(10, isSigned);
@@ -1433,6 +1515,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
default: llvm_unreachable("Unexpected type for float literal!");
case BuiltinType::Half: break; // FIXME: suffix?
case BuiltinType::Double: break; // no suffix.
+ case BuiltinType::Float16: OS << "F16"; break;
case BuiltinType::Float: OS << 'F'; break;
case BuiltinType::LongDouble: OS << 'L'; break;
case BuiltinType::Float128: OS << 'Q'; break;
@@ -1440,6 +1523,8 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
}
void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) {
+ if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context))
+ return;
PrintFloatingLiteral(OS, Node, /*PrintSuffix=*/true);
}
@@ -1600,16 +1685,25 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
PrintCallArgs(Call);
OS << ")";
}
+
+static bool isImplicitThis(const Expr *E) {
+ if (const auto *TE = dyn_cast<CXXThisExpr>(E))
+ return TE->isImplicit();
+ return false;
+}
+
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
- // FIXME: Suppress printing implicit bases (like "this")
- PrintExpr(Node->getBase());
+ if (!Policy.SuppressImplicitBase || !isImplicitThis(Node->getBase())) {
+ PrintExpr(Node->getBase());
- MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
- FieldDecl *ParentDecl = ParentMember
- ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : nullptr;
+ MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
+ FieldDecl *ParentDecl =
+ ParentMember ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl())
+ : nullptr;
- if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
- OS << (Node->isArrow() ? "->" : ".");
+ if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
+ OS << (Node->isArrow() ? "->" : ".");
+ }
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
if (FD->isAnonymousStructOrUnion())
@@ -1846,7 +1940,8 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
// AtomicExpr stores its subexpressions in a permuted order.
PrintExpr(Node->getPtr());
if (Node->getOp() != AtomicExpr::AO__c11_atomic_load &&
- Node->getOp() != AtomicExpr::AO__atomic_load_n) {
+ Node->getOp() != AtomicExpr::AO__atomic_load_n &&
+ Node->getOp() != AtomicExpr::AO__opencl_atomic_load) {
OS << ", ";
PrintExpr(Node->getVal1());
}
@@ -1860,7 +1955,8 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
OS << ", ";
PrintExpr(Node->getWeak());
}
- if (Node->getOp() != AtomicExpr::AO__c11_atomic_init) {
+ if (Node->getOp() != AtomicExpr::AO__c11_atomic_init &&
+ Node->getOp() != AtomicExpr::AO__opencl_atomic_init) {
OS << ", ";
PrintExpr(Node->getOrder());
}
@@ -2649,11 +2745,10 @@ void Stmt::dumpPretty(const ASTContext &Context) const {
printPretty(llvm::errs(), nullptr, PrintingPolicy(Context.getLangOpts()));
}
-void Stmt::printPretty(raw_ostream &OS,
- PrinterHelper *Helper,
- const PrintingPolicy &Policy,
- unsigned Indentation) const {
- StmtPrinter P(OS, Helper, Policy, Indentation);
+void Stmt::printPretty(raw_ostream &OS, PrinterHelper *Helper,
+ const PrintingPolicy &Policy, unsigned Indentation,
+ const ASTContext *Context) const {
+ StmtPrinter P(OS, Helper, Policy, Indentation, Context);
P.Visit(const_cast<Stmt*>(this));
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index f1fbe2806b..9acd79bc2c 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -549,6 +549,58 @@ void OMPClauseProfiler::VisitOMPReductionClause(
Profiler->VisitStmt(E);
}
}
+void OMPClauseProfiler::VisitOMPTaskReductionClause(
+ const OMPTaskReductionClause *C) {
+ Profiler->VisitNestedNameSpecifier(
+ C->getQualifierLoc().getNestedNameSpecifier());
+ Profiler->VisitName(C->getNameInfo().getName());
+ VisitOMPClauseList(C);
+ VistOMPClauseWithPostUpdate(C);
+ for (auto *E : C->privates()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->lhs_exprs()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->rhs_exprs()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->reduction_ops()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+}
+void OMPClauseProfiler::VisitOMPInReductionClause(
+ const OMPInReductionClause *C) {
+ Profiler->VisitNestedNameSpecifier(
+ C->getQualifierLoc().getNestedNameSpecifier());
+ Profiler->VisitName(C->getNameInfo().getName());
+ VisitOMPClauseList(C);
+ VistOMPClauseWithPostUpdate(C);
+ for (auto *E : C->privates()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->lhs_exprs()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->rhs_exprs()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->reduction_ops()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->taskgroup_descriptors()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+}
void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
VistOMPClauseWithPostUpdate(C);
@@ -750,6 +802,8 @@ void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) {
void StmtProfiler::VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *S) {
VisitOMPExecutableDirective(S);
+ if (const Expr *E = S->getReductionRef())
+ VisitStmt(E);
}
void StmtProfiler::VisitOMPFlushDirective(const OMPFlushDirective *S) {
@@ -1364,6 +1418,15 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
llvm_unreachable("Invalid overloaded operator expression");
}
+#if defined(_MSC_VER) && !defined(__clang__)
+#if _MSC_VER == 1911
+// Work around https://developercommunity.visualstudio.com/content/problem/84002/clang-cl-when-built-with-vc-2017-crashes-cause-vc.html
+// MSVC 2017 update 3 miscompiles this function, and a clang built with it
+// will crash in stage 2 of a bootstrap build.
+#pragma optimize("", off)
+#endif
+#endif
+
void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
if (S->isTypeDependent()) {
// Type-dependent operator calls are profiled like their underlying
@@ -1396,6 +1459,12 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
ID.AddInteger(S->getOperator());
}
+#if defined(_MSC_VER) && !defined(__clang__)
+#if _MSC_VER == 1911
+#pragma optimize("", on)
+#endif
+#endif
+
void StmtProfiler::VisitCXXMemberCallExpr(const CXXMemberCallExpr *S) {
VisitCallExpr(S);
}
@@ -1632,6 +1701,7 @@ void StmtProfiler::VisitCXXUnresolvedConstructExpr(
const CXXUnresolvedConstructExpr *S) {
VisitExpr(S);
VisitType(S->getTypeAsWritten());
+ ID.AddInteger(S->isListInitialization());
}
void StmtProfiler::VisitCXXDependentScopeMemberExpr(
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 47a7d47e7a..9dbe827df5 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -131,6 +131,23 @@ DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
return Storage.dyn_cast<DependentTemplateName *>();
}
+TemplateName TemplateName::getNameToSubstitute() const {
+ TemplateDecl *Decl = getAsTemplateDecl();
+
+ // Substituting a dependent template name: preserve it as written.
+ if (!Decl)
+ return *this;
+
+ // If we have a template declaration, use the most recent non-friend
+ // declaration of that template.
+ Decl = cast<TemplateDecl>(Decl->getMostRecentDecl());
+ while (Decl->getFriendObjectKind()) {
+ Decl = cast<TemplateDecl>(Decl->getPreviousDecl());
+ assert(Decl && "all declarations of template are friends");
+ }
+ return TemplateName(Decl);
+}
+
bool TemplateName::isDependent() const {
if (TemplateDecl *Template = getAsTemplateDecl()) {
if (isa<TemplateTemplateParmDecl>(Template))
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 50bebd5f91..d0707a4a73 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Type.h"
+#include "Linkage.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
@@ -168,6 +169,26 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID,
SizeExpr->Profile(ID, Context, true);
}
+DependentAddressSpaceType::DependentAddressSpaceType(
+ const ASTContext &Context, QualType PointeeType, QualType can,
+ Expr *AddrSpaceExpr, SourceLocation loc)
+ : Type(DependentAddressSpace, can, /*Dependent=*/true,
+ /*InstantiationDependent=*/true,
+ PointeeType->isVariablyModifiedType(),
+ (PointeeType->containsUnexpandedParameterPack() ||
+ (AddrSpaceExpr &&
+ AddrSpaceExpr->containsUnexpandedParameterPack()))),
+ Context(Context), AddrSpaceExpr(AddrSpaceExpr), PointeeType(PointeeType),
+ loc(loc) {}
+
+void DependentAddressSpaceType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Context,
+ QualType PointeeType,
+ Expr *AddrSpaceExpr) {
+ ID.AddPointer(PointeeType.getAsOpaquePtr());
+ AddrSpaceExpr->Profile(ID, Context, true);
+}
+
VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType,
VectorKind vecKind)
: VectorType(Vector, vecType, nElements, canonType, vecKind) {}
@@ -1344,7 +1365,7 @@ Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
} else if (getAs<BlockPointerType>()) {
ASTContext &ctx = dc->getParentASTContext();
objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { })
- ->castAs<ObjCObjectType>();;
+ ->castAs<ObjCObjectType>();
} else {
objectType = getAs<ObjCObjectType>();
}
@@ -2023,20 +2044,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()) {
@@ -2085,22 +2094,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())
@@ -2137,35 +2132,18 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
if ((*this)->isArrayType())
return Context.getBaseElementType(*this).isTriviallyCopyableType(Context);
- if (Context.getLangOpts().ObjCAutoRefCount) {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Autoreleasing:
- return false;
-
- case Qualifiers::OCL_None:
- if ((*this)->isObjCLifetimeType())
- return false;
- break;
- }
- }
+ if (hasNonTrivialObjCLifetime())
+ return false;
- // C++11 [basic.types]p9
+ // C++11 [basic.types]p9 - See Core 2094
// Scalar types, trivially copyable class types, arrays of such types, and
- // non-volatile const-qualified versions of these types are collectively
+ // cv-qualified versions of these types are collectively
// called trivially copyable types.
QualType CanonicalType = getCanonicalType();
if (CanonicalType->isDependentType())
return false;
- if (CanonicalType.isVolatileQualified())
- return false;
-
// Return false for incomplete types after skipping any incomplete array types
// which are expressly allowed by the standard and thus our API.
if (CanonicalType->isIncompleteType())
@@ -2188,7 +2166,156 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
return false;
}
+bool QualType::unionHasUniqueObjectRepresentations(
+ const ASTContext &Context) const {
+ assert((*this)->isUnionType() && "must be union type");
+ CharUnits UnionSize = Context.getTypeSizeInChars(*this);
+ const RecordDecl *Union = getTypePtr()->getAs<RecordType>()->getDecl();
+ for (const auto *Field : Union->fields()) {
+ if (!Field->getType().hasUniqueObjectRepresentations(Context))
+ return false;
+ CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
+ if (FieldSize != UnionSize)
+ return false;
+ }
+ return true;
+}
+
+static bool isStructEmpty(QualType Ty) {
+ assert(Ty.getTypePtr()->isStructureOrClassType() &&
+ "Must be struct or class");
+ const RecordDecl *RD = Ty.getTypePtr()->getAs<RecordType>()->getDecl();
+
+ if (!RD->field_empty())
+ return false;
+
+ if (const CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
+ return ClassDecl->isEmpty();
+ }
+
+ return true;
+}
+
+bool QualType::structHasUniqueObjectRepresentations(
+ const ASTContext &Context) const {
+ assert((*this)->isStructureOrClassType() && "Must be struct or class");
+ const RecordDecl *RD = getTypePtr()->getAs<RecordType>()->getDecl();
+
+ if (isStructEmpty(*this))
+ return false;
+
+ // Check base types.
+ CharUnits BaseSize{};
+ if (const CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const auto Base : ClassDecl->bases()) {
+ if (Base.isVirtual())
+ return false;
+
+ // Empty bases are permitted, otherwise ensure base has unique
+ // representation. Also, Empty Base Optimization means that an
+ // Empty base takes up 0 size.
+ if (!isStructEmpty(Base.getType())) {
+ if (!Base.getType().structHasUniqueObjectRepresentations(Context))
+ return false;
+ BaseSize += Context.getTypeSizeInChars(Base.getType());
+ }
+ }
+ }
+
+ CharUnits StructSize = Context.getTypeSizeInChars(*this);
+
+ // This struct obviously has bases that keep it from being 'empty', so
+ // checking fields is no longer required. Ensure that the struct size
+ // is the sum of the bases.
+ if (RD->field_empty())
+ return StructSize == BaseSize;
+ ;
+
+ CharUnits CurOffset =
+ Context.toCharUnitsFromBits(Context.getFieldOffset(*RD->field_begin()));
+
+ // If the first field isn't at the sum of the size of the bases, there
+ // is padding somewhere.
+ if (BaseSize != CurOffset)
+ return false;
+
+ for (const auto *Field : RD->fields()) {
+ if (!Field->getType().hasUniqueObjectRepresentations(Context))
+ return false;
+ CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
+ CharUnits FieldOffset =
+ Context.toCharUnitsFromBits(Context.getFieldOffset(Field));
+ // Has padding between fields.
+ if (FieldOffset != CurOffset)
+ return false;
+ CurOffset += FieldSize;
+ }
+ // Check for tail padding.
+ return CurOffset == StructSize;
+}
+
+bool QualType::hasUniqueObjectRepresentations(const ASTContext &Context) const {
+ // C++17 [meta.unary.prop]:
+ // The predicate condition for a template specialization
+ // has_unique_object_representations<T> shall be
+ // satisfied if and only if:
+ // (9.1) - T is trivially copyable, and
+ // (9.2) - any two objects of type T with the same value have the same
+ // object representation, where two objects
+ // of array or non-union class type are considered to have the same value
+ // if their respective sequences of
+ // direct subobjects have the same values, and two objects of union type
+ // are considered to have the same
+ // value if they have the same active member and the corresponding members
+ // have the same value.
+ // The set of scalar types for which this condition holds is
+ // implementation-defined. [ Note: If a type has padding
+ // bits, the condition does not hold; otherwise, the condition holds true
+ // for unsigned integral types. -- end note ]
+ if (isNull())
+ return false;
+
+ // Arrays are unique only if their element type is unique.
+ if ((*this)->isArrayType())
+ return Context.getBaseElementType(*this).hasUniqueObjectRepresentations(
+ Context);
+
+ // (9.1) - T is trivially copyable, and
+ if (!isTriviallyCopyableType(Context))
+ return false;
+
+ // Functions are not unique.
+ if ((*this)->isFunctionType())
+ return false;
+
+ // All integrals and enums are unique!
+ if ((*this)->isIntegralOrEnumerationType())
+ return true;
+
+ // All pointers are unique, since they're just integrals.
+ if ((*this)->isPointerType() || (*this)->isMemberPointerType())
+ return true;
+
+ if ((*this)->isRecordType()) {
+ const RecordDecl *Record = getTypePtr()->getAs<RecordType>()->getDecl();
+
+ // Lambda types are not unique, so exclude them immediately.
+ if (Record->isLambda())
+ return false;
+
+ if (Record->isUnion())
+ return unionHasUniqueObjectRepresentations(Context);
+ return structHasUniqueObjectRepresentations(Context);
+ }
+ 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())
@@ -2298,20 +2425,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
@@ -2364,6 +2479,15 @@ bool Type::isAlignValT() const {
return false;
}
+bool Type::isStdByteType() const {
+ if (auto *ET = getAs<EnumType>()) {
+ auto *II = ET->getDecl()->getIdentifier();
+ if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace())
+ return true;
+ }
+ return false;
+}
+
bool Type::isPromotableIntegerType() const {
if (const BuiltinType *BT = getAs<BuiltinType>())
switch (BT->getKind()) {
@@ -2605,6 +2729,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
return "double";
case LongDouble:
return "long double";
+ case Float16:
+ return "_Float16";
case Float128:
return "__float128";
case WChar_S:
@@ -2681,7 +2807,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
case CC_X86VectorCall: return "vectorcall";
- case CC_X86_64Win64: return "ms_abi";
+ case CC_Win64: return "ms_abi";
case CC_X86_64SysV: return "sysv_abi";
case CC_X86RegCall : return "regcall";
case CC_AAPCS: return "aapcs";
@@ -3033,6 +3159,19 @@ bool TagType::isBeingDefined() const {
return getDecl()->isBeingDefined();
}
+bool RecordType::hasConstFields() const {
+ for (FieldDecl *FD : getDecl()->fields()) {
+ QualType FieldTy = FD->getType();
+ if (FieldTy.isConstQualified())
+ return true;
+ FieldTy = FieldTy.getCanonicalType();
+ if (const RecordType *FieldRecTy = FieldTy->getAs<RecordType>())
+ if (FieldRecTy->hasConstFields())
+ return true;
+ }
+ return false;
+}
+
bool AttributedType::isQualifier() const {
switch (getAttrKind()) {
// These are type qualifiers in the traditional C sense: they annotate
@@ -3074,6 +3213,7 @@ bool AttributedType::isQualifier() const {
case AttributedType::attr_sptr:
case AttributedType::attr_uptr:
case AttributedType::attr_objc_kindof:
+ case AttributedType::attr_ns_returns_retained:
return false;
}
llvm_unreachable("bad attributed type kind");
@@ -3107,6 +3247,7 @@ bool AttributedType::isCallingConv() const {
case attr_objc_inert_unsafe_unretained:
case attr_noreturn:
case attr_nonnull:
+ case attr_ns_returns_retained:
case attr_nullable:
case attr_null_unspecified:
case attr_objc_kindof:
@@ -3468,9 +3609,7 @@ bool Type::hasUnnamedOrLocalType() const {
return TypeBits.hasLocalOrUnnamedType();
}
-static LinkageInfo computeLinkageInfo(QualType T);
-
-static LinkageInfo computeLinkageInfo(const Type *T) {
+LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
switch (T->getTypeClass()) {
#define TYPE(Class,Base)
#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
@@ -3494,75 +3633,78 @@ static LinkageInfo computeLinkageInfo(const Type *T) {
case Type::Record:
case Type::Enum:
- return cast<TagType>(T)->getDecl()->getLinkageAndVisibility();
+ return getDeclLinkageAndVisibility(cast<TagType>(T)->getDecl());
case Type::Complex:
- return computeLinkageInfo(cast<ComplexType>(T)->getElementType());
+ return computeTypeLinkageInfo(cast<ComplexType>(T)->getElementType());
case Type::Pointer:
- return computeLinkageInfo(cast<PointerType>(T)->getPointeeType());
+ return computeTypeLinkageInfo(cast<PointerType>(T)->getPointeeType());
case Type::BlockPointer:
- return computeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType());
+ return computeTypeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType());
case Type::LValueReference:
case Type::RValueReference:
- return computeLinkageInfo(cast<ReferenceType>(T)->getPointeeType());
+ return computeTypeLinkageInfo(cast<ReferenceType>(T)->getPointeeType());
case Type::MemberPointer: {
const MemberPointerType *MPT = cast<MemberPointerType>(T);
- LinkageInfo LV = computeLinkageInfo(MPT->getClass());
- LV.merge(computeLinkageInfo(MPT->getPointeeType()));
+ LinkageInfo LV = computeTypeLinkageInfo(MPT->getClass());
+ LV.merge(computeTypeLinkageInfo(MPT->getPointeeType()));
return LV;
}
case Type::ConstantArray:
case Type::IncompleteArray:
case Type::VariableArray:
- return computeLinkageInfo(cast<ArrayType>(T)->getElementType());
+ return computeTypeLinkageInfo(cast<ArrayType>(T)->getElementType());
case Type::Vector:
case Type::ExtVector:
- return computeLinkageInfo(cast<VectorType>(T)->getElementType());
+ return computeTypeLinkageInfo(cast<VectorType>(T)->getElementType());
case Type::FunctionNoProto:
- return computeLinkageInfo(cast<FunctionType>(T)->getReturnType());
+ return computeTypeLinkageInfo(cast<FunctionType>(T)->getReturnType());
case Type::FunctionProto: {
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
- LinkageInfo LV = computeLinkageInfo(FPT->getReturnType());
+ LinkageInfo LV = computeTypeLinkageInfo(FPT->getReturnType());
for (const auto &ai : FPT->param_types())
- LV.merge(computeLinkageInfo(ai));
+ LV.merge(computeTypeLinkageInfo(ai));
return LV;
}
case Type::ObjCInterface:
- return cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
+ return getDeclLinkageAndVisibility(cast<ObjCInterfaceType>(T)->getDecl());
case Type::ObjCObject:
- return computeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType());
+ return computeTypeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType());
case Type::ObjCObjectPointer:
- return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType());
+ return computeTypeLinkageInfo(
+ cast<ObjCObjectPointerType>(T)->getPointeeType());
case Type::Atomic:
- return computeLinkageInfo(cast<AtomicType>(T)->getValueType());
+ return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType());
case Type::Pipe:
- return computeLinkageInfo(cast<PipeType>(T)->getElementType());
+ return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
}
llvm_unreachable("unhandled type class");
}
-static LinkageInfo computeLinkageInfo(QualType T) {
- return computeLinkageInfo(T.getTypePtr());
-}
-
bool Type::isLinkageValid() const {
if (!TypeBits.isCacheValid())
return true;
- return computeLinkageInfo(getCanonicalTypeInternal()).getLinkage() ==
- TypeBits.getLinkage();
+ Linkage L = LinkageComputer{}
+ .computeTypeLinkageInfo(getCanonicalTypeInternal())
+ .getLinkage();
+ return L == TypeBits.getLinkage();
}
-LinkageInfo Type::getLinkageAndVisibility() const {
- if (!isCanonicalUnqualified())
- return computeLinkageInfo(getCanonicalTypeInternal());
+LinkageInfo LinkageComputer::getTypeLinkageAndVisibility(const Type *T) {
+ if (!T->isCanonicalUnqualified())
+ return computeTypeLinkageInfo(T->getCanonicalTypeInternal());
- LinkageInfo LV = computeLinkageInfo(this);
- assert(LV.getLinkage() == getLinkage());
+ LinkageInfo LV = computeTypeLinkageInfo(T);
+ assert(LV.getLinkage() == T->getLinkage());
return LV;
}
+LinkageInfo Type::getLinkageAndVisibility() const {
+ return LinkageComputer{}.getTypeLinkageAndVisibility(this);
+}
+
Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const {
QualType type(this, 0);
do {
@@ -3582,7 +3724,7 @@ Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const
} while (true);
}
-bool Type::canHaveNullability() const {
+bool Type::canHaveNullability(bool ResultIfUnknown) const {
QualType type = getCanonicalTypeInternal();
switch (type->getTypeClass()) {
@@ -3610,7 +3752,8 @@ bool Type::canHaveNullability() const {
case Type::SubstTemplateTypeParmPack:
case Type::DependentName:
case Type::DependentTemplateSpecialization:
- return true;
+ case Type::Auto:
+ return ResultIfUnknown;
// Dependent template specializations can instantiate to pointer
// types unless they're known to be specializations of a class
@@ -3622,12 +3765,7 @@ bool Type::canHaveNullability() const {
if (isa<ClassTemplateDecl>(templateDecl))
return false;
}
- return true;
-
- // auto is considered dependent when it isn't deduced.
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- return !cast<DeducedType>(type.getTypePtr())->isDeduced();
+ return ResultIfUnknown;
case Type::Builtin:
switch (cast<BuiltinType>(type.getTypePtr())->getKind()) {
@@ -3646,7 +3784,7 @@ bool Type::canHaveNullability() const {
case BuiltinType::PseudoObject:
case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast:
- return true;
+ return ResultIfUnknown;
case BuiltinType::Void:
case BuiltinType::ObjCId:
@@ -3665,6 +3803,7 @@ bool Type::canHaveNullability() const {
case BuiltinType::OMPArraySection:
return false;
}
+ llvm_unreachable("unknown builtin type");
// Non-pointer types.
case Type::Complex:
@@ -3677,9 +3816,11 @@ bool Type::canHaveNullability() const {
case Type::DependentSizedExtVector:
case Type::Vector:
case Type::ExtVector:
+ case Type::DependentAddressSpace:
case Type::FunctionProto:
case Type::FunctionNoProto:
case Type::Record:
+ case Type::DeducedTemplateSpecialization:
case Type::Enum:
case Type::InjectedClassName:
case Type::PackExpansion:
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index c9a2686557..9ff437b4cc 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -319,6 +319,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
+ case BuiltinType::Float16:
case BuiltinType::Float128:
llvm_unreachable("Builtin type needs extra local data!");
// Fall through, if the impossible happens.
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 84aa7dc845..7351d972b1 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -104,6 +104,7 @@ namespace {
void printAfter(QualType T, raw_ostream &OS);
void AppendScope(DeclContext *DC, raw_ostream &OS);
void printTag(TagDecl *T, raw_ostream &OS);
+ void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) \
void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
@@ -221,6 +222,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::LValueReference:
case Type::RValueReference:
case Type::MemberPointer:
+ case Type::DependentAddressSpace:
case Type::DependentSizedExtVector:
case Type::Vector:
case Type::ExtVector:
@@ -526,6 +528,19 @@ void TypePrinter::printDependentSizedArrayAfter(
printAfter(T->getElementType(), OS);
}
+void TypePrinter::printDependentAddressSpaceBefore(
+ const DependentAddressSpaceType *T, raw_ostream &OS) {
+ printBefore(T->getPointeeType(), OS);
+}
+void TypePrinter::printDependentAddressSpaceAfter(
+ const DependentAddressSpaceType *T, raw_ostream &OS) {
+ OS << " __attribute__((address_space(";
+ if (T->getAddrSpaceExpr())
+ T->getAddrSpaceExpr()->printPretty(OS, nullptr, Policy);
+ OS << ")))";
+ printAfter(T->getPointeeType(), OS);
+}
+
void TypePrinter::printDependentSizedExtVectorBefore(
const DependentSizedExtVectorType *T,
raw_ostream &OS) {
@@ -664,6 +679,8 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
auto EPI = T->getExtParameterInfo(i);
if (EPI.isConsumed()) OS << "__attribute__((ns_consumed)) ";
+ if (EPI.isNoEscape())
+ OS << "__attribute__((noescape)) ";
auto ABI = EPI.getABI();
if (ABI != ParameterABI::Ordinary)
OS << "__attribute__((" << getParameterABISpelling(ABI) << ")) ";
@@ -685,6 +702,36 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
FunctionType::ExtInfo Info = T->getExtInfo();
+ printFunctionAfter(Info, OS);
+
+ if (unsigned quals = T->getTypeQuals()) {
+ OS << ' ';
+ AppendTypeQualList(OS, quals, Policy.Restrict);
+ }
+
+ switch (T->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ OS << " &";
+ break;
+
+ case RQ_RValue:
+ OS << " &&";
+ break;
+ }
+ T->printExceptionSpecification(OS, Policy);
+
+ if (T->hasTrailingReturn()) {
+ OS << " -> ";
+ print(T->getReturnType(), OS, StringRef());
+ } else
+ printAfter(T->getReturnType(), OS);
+}
+
+void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
+ raw_ostream &OS) {
if (!InsideCCAttribute) {
switch (Info.getCC()) {
case CC_C:
@@ -720,7 +767,7 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_IntelOclBicc:
OS << " __attribute__((intel_ocl_bicc))";
break;
- case CC_X86_64Win64:
+ case CC_Win64:
OS << " __attribute__((ms_abi))";
break;
case CC_X86_64SysV:
@@ -747,34 +794,13 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
+ if (Info.getProducesResult())
+ OS << " __attribute__((ns_returns_retained))";
if (Info.getRegParm())
OS << " __attribute__((regparm ("
<< Info.getRegParm() << ")))";
-
- if (unsigned quals = T->getTypeQuals()) {
- OS << ' ';
- AppendTypeQualList(OS, quals, Policy.Restrict);
- }
-
- switch (T->getRefQualifier()) {
- case RQ_None:
- break;
-
- case RQ_LValue:
- OS << " &";
- break;
-
- case RQ_RValue:
- OS << " &&";
- break;
- }
- T->printExceptionSpecification(OS, Policy);
-
- if (T->hasTrailingReturn()) {
- OS << " -> ";
- print(T->getReturnType(), OS, StringRef());
- } else
- printAfter(T->getReturnType(), OS);
+ if (Info.getNoCallerSavedRegs())
+ OS << " __attribute__((no_caller_saved_registers))";
}
void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
@@ -793,8 +819,7 @@ void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T,
SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
OS << "()";
- if (T->getNoReturnAttr())
- OS << " __attribute__((noreturn))";
+ printFunctionAfter(T->getExtInfo(), OS);
printAfter(T->getReturnType(), OS);
}
@@ -1268,6 +1293,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained)
return;
+ // Don't print ns_returns_retained unless it had an effect.
+ if (T->getAttrKind() == AttributedType::attr_ns_returns_retained &&
+ !T->getEquivalentType()->castAs<FunctionType>()
+ ->getExtInfo().getProducesResult())
+ return;
+
// Print nullability type specifiers that occur after
if (T->getAttrKind() == AttributedType::attr_nonnull ||
T->getAttrKind() == AttributedType::attr_nullable ||
@@ -1289,7 +1320,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
default: llvm_unreachable("This attribute should have been handled already");
case AttributedType::attr_address_space:
OS << "address_space(";
- OS << T->getEquivalentType().getAddressSpace();
+ // FIXME: printing the raw LangAS value is wrong. This should probably
+ // use the same code as Qualifiers::print()
+ OS << (unsigned)T->getEquivalentType().getAddressSpace();
OS << ')';
break;
@@ -1359,6 +1392,10 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
+ case AttributedType::attr_ns_returns_retained:
+ OS << "ns_returns_retained";
+ break;
+
// FIXME: When Sema learns to form this AttributedType, avoid printing the
// attribute again in printFunctionProtoAfter.
case AttributedType::attr_noreturn: OS << "noreturn"; break;
@@ -1610,7 +1647,7 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const {
if (getCVRQualifiers())
return false;
- if (getAddressSpace())
+ if (getAddressSpace() != LangAS::Default)
return false;
if (getObjCGCAttr())
@@ -1641,27 +1678,39 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__unaligned";
addSpace = true;
}
- if (unsigned addrspace = getAddressSpace()) {
- if (addSpace)
- OS << ' ';
- addSpace = true;
- switch (addrspace) {
+ LangAS addrspace = getAddressSpace();
+ if (addrspace != LangAS::Default) {
+ if (addrspace != LangAS::opencl_private) {
+ if (addSpace)
+ OS << ' ';
+ addSpace = true;
+ switch (addrspace) {
case LangAS::opencl_global:
OS << "__global";
break;
case LangAS::opencl_local:
OS << "__local";
break;
+ case LangAS::opencl_private:
+ 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:
OS << "__attribute__((address_space(";
- OS << addrspace;
+ OS << toTargetAddressSpace(addrspace);
OS << ")))";
+ }
}
}
if (Qualifiers::GC gc = getObjCGCAttr()) {
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index e60ae33f2e..ae8f6309fc 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -2963,6 +2963,9 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
ThisAdjustmentOffset);
+ unsigned VBIndex =
+ LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
+
if (OverriddenMD) {
// If MD overrides anything in this vftable, we need to update the
// entries.
@@ -2975,6 +2978,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
+ VBIndex = OverriddenMethodInfo.VBTableIndex;
+
// Let's check if the overrider requires any return adjustments.
// We must create a new slot if the MD's return type is not trivially
// convertible to the OverriddenMD's one.
@@ -2987,8 +2992,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
if (!ReturnAdjustingThunk) {
// No return adjustment needed - just replace the overridden method info
// with the current info.
- MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
- OverriddenMethodInfo.VFTableIndex);
+ MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex);
MethodInfoMap.erase(OverriddenMDIterator);
assert(!MethodInfoMap.count(MD) &&
@@ -3015,8 +3019,6 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
// If we got here, MD is a method not seen in any of the sub-bases or
// it requires return adjustment. Insert the method info for this method.
- unsigned VBIndex =
- LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
MethodInfo MI(VBIndex,
HasRTTIComponent ? Components.size() - 1 : Components.size(),
ReturnAdjustingThunk);
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 49b15ee685..02aee4b46d 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -734,7 +734,10 @@ private:
BoundNodesTreeBuilder *Builder) {
const Type *const CanonicalType =
ActiveASTContext->getCanonicalType(TypeNode);
- for (const TypedefNameDecl *Alias : TypeAliases.lookup(CanonicalType)) {
+ auto Aliases = TypeAliases.find(CanonicalType);
+ if (Aliases == TypeAliases.end())
+ return false;
+ for (const TypedefNameDecl *Alias : Aliases->second) {
BoundNodesTreeBuilder Result(*Builder);
if (Matcher.matches(*Alias, this, &Result)) {
*Builder = std::move(Result);
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index f0bfbf9e32..491c7fc7b6 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1,4 +1,4 @@
-//===--- ASTMatchersInternal.cpp - Structural query framework -------------===//
+//===- ASTMatchersInternal.cpp - Structural query framework ---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,11 +11,30 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <string>
+#include <utility>
+#include <vector>
namespace clang {
namespace ast_matchers {
@@ -40,7 +59,6 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
-
void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
if (Bindings.empty())
Bindings.push_back(BoundNodesMap());
@@ -51,7 +69,7 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
namespace {
-typedef bool (*VariadicOperatorFunction)(
+using VariadicOperatorFunction = bool (*)(
const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
@@ -100,20 +118,22 @@ public:
TrueMatcherImpl() {
Retain(); // Reference count will never become zero.
}
+
bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *,
BoundNodesTreeBuilder *) const override {
return true;
}
};
-static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
-} // namespace
+} // namespace
+
+static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
DynTypedMatcher DynTypedMatcher::constructVariadic(
DynTypedMatcher::VariadicOperator Op,
ast_type_traits::ASTNodeKind SupportedKind,
std::vector<DynTypedMatcher> InnerMatchers) {
- assert(InnerMatchers.size() > 0 && "Array must not be empty.");
+ assert(!InnerMatchers.empty() && "Array must not be empty.");
assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(),
[SupportedKind](const DynTypedMatcher &M) {
return M.canConvertTo(SupportedKind);
@@ -314,9 +334,7 @@ HasNameMatcher::HasNameMatcher(std::vector<std::string> N)
#endif
}
-namespace {
-
-bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) {
+static bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) {
StringRef Name = FullName;
if (!Name.endswith(Suffix))
return false;
@@ -330,7 +348,8 @@ bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) {
return true;
}
-StringRef getNodeName(const NamedDecl &Node, llvm::SmallString<128> &Scratch) {
+static StringRef getNodeName(const NamedDecl &Node,
+ llvm::SmallString<128> &Scratch) {
// Simple name.
if (Node.getIdentifier())
return Node.getName();
@@ -346,7 +365,8 @@ StringRef getNodeName(const NamedDecl &Node, llvm::SmallString<128> &Scratch) {
return "(anonymous)";
}
-StringRef getNodeName(const RecordDecl &Node, llvm::SmallString<128> &Scratch) {
+static StringRef getNodeName(const RecordDecl &Node,
+ llvm::SmallString<128> &Scratch) {
if (Node.getIdentifier()) {
return Node.getName();
}
@@ -354,11 +374,12 @@ StringRef getNodeName(const RecordDecl &Node, llvm::SmallString<128> &Scratch) {
return ("(anonymous " + Node.getKindName() + ")").toStringRef(Scratch);
}
-StringRef getNodeName(const NamespaceDecl &Node,
- llvm::SmallString<128> &Scratch) {
+static StringRef getNodeName(const NamespaceDecl &Node,
+ llvm::SmallString<128> &Scratch) {
return Node.isAnonymousNamespace() ? "(anonymous namespace)" : Node.getName();
}
+namespace {
class PatternSet {
public:
@@ -397,10 +418,11 @@ private:
StringRef P;
bool IsFullyQualified;
};
+
llvm::SmallVector<Pattern, 8> Patterns;
};
-} // namespace
+} // namespace
bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const {
assert(UseUnqualifiedMatch);
diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index 787b780c42..9cddcf93ca 100644
--- a/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -118,8 +118,8 @@ static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
return "Malformed bind() expression.";
case Diagnostics::ET_ParserTrailingCode:
return "Expected end of code.";
- case Diagnostics::ET_ParserUnsignedError:
- return "Error parsing unsigned token: <$0>";
+ case Diagnostics::ET_ParserNumberError:
+ return "Error parsing numeric literal: <$0>";
case Diagnostics::ET_ParserOverloadedType:
return "Input value has unresolved overloaded type: $0";
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
index fb6b349a81..d5626b2218 100644
--- a/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -1,4 +1,4 @@
-//===--- Marshallers.h - Generic matcher function marshallers ---*- C++ -*-===//
+//===- Marshallers.h - Generic matcher function marshallers -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -6,7 +6,7 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-///
+//
/// \file
/// \brief Functions templates and classes to wrap matcher construct functions.
///
@@ -14,18 +14,33 @@
/// marshalling layer on top of matcher construct functions.
/// These are used by the registry to export all marshaller constructors with
/// the same generic interface.
-///
+//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H
#define LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <limits>
+#include <memory>
#include <string>
+#include <utility>
+#include <vector>
namespace clang {
namespace ast_matchers {
@@ -41,9 +56,11 @@ template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> {
template <> struct ArgTypeTraits<std::string> {
static bool is(const VariantValue &Value) { return Value.isString(); }
+
static const std::string &get(const VariantValue &Value) {
return Value.getString();
}
+
static ArgKind getKind() {
return ArgKind(ArgKind::AK_String);
}
@@ -53,23 +70,51 @@ template <>
struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> {
};
-template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
+template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T>> {
static bool is(const VariantValue &Value) {
return Value.isMatcher() && Value.getMatcher().hasTypedMatcher<T>();
}
+
static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) {
return Value.getMatcher().getTypedMatcher<T>();
}
+
static ArgKind getKind() {
return ArgKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
}
};
+template <> struct ArgTypeTraits<bool> {
+ static bool is(const VariantValue &Value) { return Value.isBoolean(); }
+
+ static bool get(const VariantValue &Value) {
+ return Value.getBoolean();
+ }
+
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_Boolean);
+ }
+};
+
+template <> struct ArgTypeTraits<double> {
+ static bool is(const VariantValue &Value) { return Value.isDouble(); }
+
+ static double get(const VariantValue &Value) {
+ return Value.getDouble();
+ }
+
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_Double);
+ }
+};
+
template <> struct ArgTypeTraits<unsigned> {
static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
+
static unsigned get(const VariantValue &Value) {
return Value.getUnsigned();
}
+
static ArgKind getKind() {
return ArgKind(ArgKind::AK_Unsigned);
}
@@ -83,23 +128,26 @@ private:
#include "clang/Basic/AttrList.inc"
.Default(attr::Kind(-1));
}
+
public:
static bool is(const VariantValue &Value) {
return Value.isString() &&
getAttrKind(Value.getString()) != attr::Kind(-1);
}
+
static attr::Kind get(const VariantValue &Value) {
return getAttrKind(Value.getString());
}
+
static ArgKind getKind() {
return ArgKind(ArgKind::AK_String);
}
};
-template <> struct ArgTypeTraits<clang::CastKind> {
+template <> struct ArgTypeTraits<CastKind> {
private:
- static clang::CastKind getCastKind(llvm::StringRef AttrKind) {
- return llvm::StringSwitch<clang::CastKind>(AttrKind)
+ static CastKind getCastKind(llvm::StringRef AttrKind) {
+ return llvm::StringSwitch<CastKind>(AttrKind)
#define CAST_OPERATION(Name) .Case( #Name, CK_##Name)
#include "clang/AST/OperationKinds.def"
.Default(CK_Invalid);
@@ -110,9 +158,11 @@ public:
return Value.isString() &&
getCastKind(Value.getString()) != CK_Invalid;
}
- static clang::CastKind get(const VariantValue &Value) {
+
+ static CastKind get(const VariantValue &Value) {
return getCastKind(Value.getString());
}
+
static ArgKind getKind() {
return ArgKind(ArgKind::AK_String);
}
@@ -124,7 +174,8 @@ public:
/// arguments, and various other methods for type introspection.
class MatcherDescriptor {
public:
- virtual ~MatcherDescriptor() {}
+ virtual ~MatcherDescriptor() = default;
+
virtual VariantMatcher create(SourceRange NameRange,
ArrayRef<ParserValue> Args,
Diagnostics *Error) const = 0;
@@ -181,11 +232,11 @@ inline bool isRetKindConvertibleTo(
/// their types, unpacking them and calling the underlying function.
class FixedArgCountMatcherDescriptor : public MatcherDescriptor {
public:
- typedef VariantMatcher (*MarshallerType)(void (*Func)(),
- StringRef MatcherName,
- SourceRange NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error);
+ using MarshallerType = VariantMatcher (*)(void (*Func)(),
+ StringRef MatcherName,
+ SourceRange NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error);
/// \param Marshaller Function to unpack the arguments and call \c Func
/// \param Func Matcher construct function. This is the function that
@@ -209,10 +260,12 @@ public:
bool isVariadic() const override { return false; }
unsigned getNumArgs() const override { return ArgKinds.size(); }
+
void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ArgKinds[ArgNo]);
}
+
bool isConvertibleTo(
ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
@@ -283,14 +336,14 @@ struct BuildReturnTypeVector {
};
template <typename T>
-struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T> > {
+struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T>> {
static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
}
};
template <typename T>
-struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T> > {
+struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T>> {
static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
}
@@ -306,7 +359,8 @@ variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange,
bool HasError = false;
for (size_t i = 0, e = Args.size(); i != e; ++i) {
- typedef ArgTypeTraits<ArgT> ArgTraits;
+ using ArgTraits = ArgTypeTraits<ArgT>;
+
const ParserValue &Arg = Args[i];
const VariantValue &Value = Arg.Value;
if (!ArgTraits::is(Value)) {
@@ -340,10 +394,10 @@ variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange,
/// object file.
class VariadicFuncMatcherDescriptor : public MatcherDescriptor {
public:
- typedef VariantMatcher (*RunFunc)(StringRef MatcherName,
- SourceRange NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error);
+ using RunFunc = VariantMatcher (*)(StringRef MatcherName,
+ SourceRange NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error);
template <typename ResultT, typename ArgT,
ResultT (*F)(ArrayRef<const ArgT *>)>
@@ -364,10 +418,12 @@ public:
bool isVariadic() const override { return true; }
unsigned getNumArgs() const override { return 0; }
+
void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ArgsKind);
}
+
bool isConvertibleTo(
ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
@@ -438,7 +494,7 @@ static VariantMatcher matcherMarshall0(void (*Func)(), StringRef MatcherName,
SourceRange NameRange,
ArrayRef<ParserValue> Args,
Diagnostics *Error) {
- typedef ReturnType (*FuncType)();
+ using FuncType = ReturnType (*)();
CHECK_ARG_COUNT(0);
return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)());
}
@@ -449,7 +505,7 @@ static VariantMatcher matcherMarshall1(void (*Func)(), StringRef MatcherName,
SourceRange NameRange,
ArrayRef<ParserValue> Args,
Diagnostics *Error) {
- typedef ReturnType (*FuncType)(ArgType1);
+ using FuncType = ReturnType (*)(ArgType1);
CHECK_ARG_COUNT(1);
CHECK_ARG_TYPE(0, ArgType1);
return outvalueToVariantMatcher(reinterpret_cast<FuncType>(Func)(
@@ -462,7 +518,7 @@ static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName,
SourceRange NameRange,
ArrayRef<ParserValue> Args,
Diagnostics *Error) {
- typedef ReturnType (*FuncType)(ArgType1, ArgType2);
+ using FuncType = ReturnType (*)(ArgType1, ArgType2);
CHECK_ARG_COUNT(2);
CHECK_ARG_TYPE(0, ArgType1);
CHECK_ARG_TYPE(1, ArgType2);
@@ -487,8 +543,8 @@ public:
}
private:
- typedef ast_matchers::internal::ArgumentAdaptingMatcherFunc<
- ArgumentAdapterT, FromTypes, ToTypes> AdaptativeFunc;
+ using AdaptativeFunc = ast_matchers::internal::ArgumentAdaptingMatcherFunc<
+ ArgumentAdapterT, FromTypes, ToTypes>;
/// \brief End case for the recursion
static void collect(ast_matchers::internal::EmptyTypeList) {}
@@ -514,7 +570,7 @@ public:
: Overloads(std::make_move_iterator(Callbacks.begin()),
std::make_move_iterator(Callbacks.end())) {}
- ~OverloadedMatcherDescriptor() override {}
+ ~OverloadedMatcherDescriptor() override = default;
VariantMatcher create(SourceRange NameRange,
ArrayRef<ParserValue> Args,
@@ -584,7 +640,8 @@ private:
/// \brief Variadic operator marshaller function.
class VariadicOperatorMatcherDescriptor : public MatcherDescriptor {
public:
- typedef DynTypedMatcher::VariadicOperator VarOp;
+ using VarOp = DynTypedMatcher::VariadicOperator;
+
VariadicOperatorMatcherDescriptor(unsigned MinCount, unsigned MaxCount,
VarOp Op, StringRef MatcherName)
: MinCount(MinCount), MaxCount(MaxCount), Op(Op),
@@ -595,7 +652,9 @@ public:
Diagnostics *Error) const override {
if (Args.size() < MinCount || MaxCount < Args.size()) {
const std::string MaxStr =
- (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str();
+ (MaxCount == std::numeric_limits<unsigned>::max() ? ""
+ : Twine(MaxCount))
+ .str();
Error->addError(NameRange, Error->ET_RegistryWrongArgCount)
<< ("(" + Twine(MinCount) + ", " + MaxStr + ")") << Args.size();
return VariantMatcher();
@@ -617,10 +676,12 @@ public:
bool isVariadic() const override { return true; }
unsigned getNumArgs() const override { return 0; }
+
void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
std::vector<ArgKind> &Kinds) const override {
Kinds.push_back(ThisKind);
}
+
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
if (Specificity)
@@ -629,6 +690,7 @@ public:
*LeastDerivedKind = Kind;
return true;
}
+
bool isPolymorphic() const override { return true; }
private:
diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp
index ce8d0a9a02..89e1a26958 100644
--- a/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -1,4 +1,4 @@
-//===--- Parser.cpp - Matcher expression parser -----*- C++ -*-===//
+//===- Parser.cpp - Matcher expression parser -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -13,11 +13,21 @@
//===----------------------------------------------------------------------===//
#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cstddef>
+#include <cstdlib>
#include <string>
+#include <utility>
#include <vector>
namespace clang {
@@ -43,10 +53,10 @@ struct Parser::TokenInfo {
/// \brief Some known identifiers.
static const char* const ID_Bind;
- TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {}
+ TokenInfo() = default;
StringRef Text;
- TokenKind Kind;
+ TokenKind Kind = TK_Eof;
SourceRange Range;
VariantValue Value;
};
@@ -57,14 +67,13 @@ const char* const Parser::TokenInfo::ID_Bind = "bind";
class Parser::CodeTokenizer {
public:
explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error)
- : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
- CodeCompletionLocation(nullptr) {
+ : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {
NextToken = getNextToken();
}
CodeTokenizer(StringRef MatcherCode, Diagnostics *Error,
unsigned CodeCompletionOffset)
- : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
+ : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),
CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
NextToken = getNextToken();
}
@@ -130,15 +139,15 @@ private:
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- // Parse an unsigned literal.
- consumeUnsignedLiteral(&Result);
+ // Parse an unsigned and float literal.
+ consumeNumberLiteral(&Result);
break;
default:
if (isAlphanumeric(Code[0])) {
// Parse an identifier
size_t TokenLength = 1;
- while (1) {
+ while (true) {
// A code completion location in/immediately after an identifier will
// cause the portion of the identifier before the code completion
// location to become a code completion token.
@@ -153,8 +162,16 @@ private:
break;
++TokenLength;
}
- Result.Kind = TokenInfo::TK_Ident;
- Result.Text = Code.substr(0, TokenLength);
+ if (TokenLength == 4 && Code.startswith("true")) {
+ Result.Kind = TokenInfo::TK_Literal;
+ Result.Value = true;
+ } else if (TokenLength == 5 && Code.startswith("false")) {
+ Result.Kind = TokenInfo::TK_Literal;
+ Result.Value = false;
+ } else {
+ Result.Kind = TokenInfo::TK_Ident;
+ Result.Text = Code.substr(0, TokenLength);
+ }
Code = Code.drop_front(TokenLength);
} else {
Result.Kind = TokenInfo::TK_InvalidChar;
@@ -168,8 +185,9 @@ private:
return Result;
}
- /// \brief Consume an unsigned literal.
- void consumeUnsignedLiteral(TokenInfo *Result) {
+ /// \brief Consume an unsigned and float literal.
+ void consumeNumberLiteral(TokenInfo *Result) {
+ bool isFloatingLiteral = false;
unsigned Length = 1;
if (Code.size() > 1) {
// Consume the 'x' or 'b' radix modifier, if present.
@@ -180,20 +198,44 @@ private:
while (Length < Code.size() && isHexDigit(Code[Length]))
++Length;
+ // Try to recognize a floating point literal.
+ while (Length < Code.size()) {
+ char c = Code[Length];
+ if (c == '-' || c == '+' || c == '.' || isHexDigit(c)) {
+ isFloatingLiteral = true;
+ Length++;
+ } else {
+ break;
+ }
+ }
+
Result->Text = Code.substr(0, Length);
Code = Code.drop_front(Length);
- unsigned Value;
- if (!Result->Text.getAsInteger(0, Value)) {
- Result->Kind = TokenInfo::TK_Literal;
- Result->Value = Value;
+ if (isFloatingLiteral) {
+ char *end;
+ errno = 0;
+ std::string Text = Result->Text.str();
+ double doubleValue = strtod(Text.c_str(), &end);
+ if (*end == 0 && errno == 0) {
+ Result->Kind = TokenInfo::TK_Literal;
+ Result->Value = doubleValue;
+ return;
+ }
} else {
- SourceRange Range;
- Range.Start = Result->Range.Start;
- Range.End = currentLocation();
- Error->addError(Range, Error->ET_ParserUnsignedError) << Result->Text;
- Result->Kind = TokenInfo::TK_Error;
+ unsigned Value;
+ if (!Result->Text.getAsInteger(0, Value)) {
+ Result->Kind = TokenInfo::TK_Literal;
+ Result->Value = Value;
+ return;
+ }
}
+
+ SourceRange Range;
+ Range.Start = Result->Range.Start;
+ Range.End = currentLocation();
+ Error->addError(Range, Error->ET_ParserNumberError) << Result->Text;
+ Result->Kind = TokenInfo::TK_Error;
}
/// \brief Consume a string literal.
@@ -250,22 +292,22 @@ private:
StringRef Code;
StringRef StartOfLine;
- unsigned Line;
+ unsigned Line = 1;
Diagnostics *Error;
TokenInfo NextToken;
- const char *CodeCompletionLocation;
+ const char *CodeCompletionLocation = nullptr;
};
-Parser::Sema::~Sema() {}
+Parser::Sema::~Sema() = default;
std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes(
llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
- return std::vector<ArgKind>();
+ return {};
}
std::vector<MatcherCompletion>
Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) {
- return std::vector<MatcherCompletion>();
+ return {};
}
struct Parser::ScopedContextEntry {
@@ -351,7 +393,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
EndToken = Tokenizer->consumeNextToken();
break;
}
- if (Args.size() > 0) {
+ if (!Args.empty()) {
// We must find a , token to continue.
const TokenInfo CommaToken = Tokenizer->consumeNextToken();
if (CommaToken.Kind != TokenInfo::TK_Comma) {
@@ -525,7 +567,7 @@ Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
: Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),
NamedValues(NamedValues), Error(Error) {}
-Parser::RegistrySema::~RegistrySema() {}
+Parser::RegistrySema::~RegistrySema() = default;
llvm::Optional<MatcherCtor>
Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
@@ -607,6 +649,6 @@ Parser::parseMatcherExpression(StringRef Code, Sema *S,
return Result;
}
-} // namespace dynamic
-} // namespace ast_matchers
-} // namespace clang
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index d1cab80c1a..f171900501 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -1,37 +1,49 @@
-//===--- Registry.cpp - Matcher registry -------------------------===//
+//===- Registry.cpp - Matcher registry ------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
-//===------------------------------------------------------------===//
-///
+//===----------------------------------------------------------------------===//
+//
/// \file
/// \brief Registry map populated at static initialization time.
-///
-//===------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
#include "clang/ASTMatchers/Dynamic/Registry.h"
#include "Marshallers.h"
+#include "clang/AST/ASTTypeTraits.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <iterator>
+#include <memory>
#include <set>
+#include <string>
#include <utility>
+#include <vector>
using namespace clang::ast_type_traits;
namespace clang {
namespace ast_matchers {
namespace dynamic {
+
namespace {
using internal::MatcherDescriptor;
-typedef llvm::StringMap<std::unique_ptr<const MatcherDescriptor>> ConstructorMap;
+using ConstructorMap = llvm::StringMap<std::unique_ptr<const MatcherDescriptor>>;
+
class RegistryMaps {
public:
RegistryMaps();
@@ -46,6 +58,8 @@ private:
ConstructorMap Constructors;
};
+} // namespace
+
void RegistryMaps::registerMatcher(
StringRef MatcherName, std::unique_ptr<MatcherDescriptor> Callback) {
assert(Constructors.find(MatcherName) == Constructors.end());
@@ -56,21 +70,25 @@ void RegistryMaps::registerMatcher(
registerMatcher(#name, internal::makeMatcherAutoMarshall( \
::clang::ast_matchers::name, #name));
+#define REGISTER_MATCHER_OVERLOAD(name) \
+ registerMatcher(#name, \
+ llvm::make_unique<internal::OverloadedMatcherDescriptor>(name##Callbacks))
+
#define SPECIFIC_MATCHER_OVERLOAD(name, Id) \
static_cast<::clang::ast_matchers::name##_Type##Id>( \
::clang::ast_matchers::name)
+#define MATCHER_OVERLOAD_ENTRY(name, Id) \
+ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, Id), \
+ #name)
+
#define REGISTER_OVERLOADED_2(name) \
do { \
- std::unique_ptr<MatcherDescriptor> Callbacks[] = { \
- internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0), \
- #name), \
- internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1), \
- #name)}; \
- registerMatcher( \
- #name, \
- llvm::make_unique<internal::OverloadedMatcherDescriptor>(Callbacks)); \
- } while (0)
+ std::unique_ptr<MatcherDescriptor> name##Callbacks[] = { \
+ MATCHER_OVERLOAD_ENTRY(name, 0), \
+ MATCHER_OVERLOAD_ENTRY(name, 1)}; \
+ REGISTER_MATCHER_OVERLOAD(name); \
+ } while (false)
/// \brief Generate a registry map with all the known matchers.
RegistryMaps::RegistryMaps() {
@@ -83,7 +101,6 @@ RegistryMaps::RegistryMaps() {
// findAll
//
// Other:
- // equals
// equalsNode
REGISTER_OVERLOADED_2(callee);
@@ -96,6 +113,13 @@ RegistryMaps::RegistryMaps() {
REGISTER_OVERLOADED_2(references);
REGISTER_OVERLOADED_2(thisPointerType);
+ std::unique_ptr<MatcherDescriptor> equalsCallbacks[] = {
+ MATCHER_OVERLOAD_ENTRY(equals, 0),
+ MATCHER_OVERLOAD_ENTRY(equals, 1),
+ MATCHER_OVERLOAD_ENTRY(equals, 2),
+ };
+ REGISTER_MATCHER_OVERLOAD(equals);
+
REGISTER_MATCHER(accessSpecDecl);
REGISTER_MATCHER(addrLabelExpr);
REGISTER_MATCHER(alignOfExpr);
@@ -153,6 +177,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(cxxRecordDecl);
REGISTER_MATCHER(cxxReinterpretCastExpr);
REGISTER_MATCHER(cxxStaticCastExpr);
+ REGISTER_MATCHER(cxxStdInitializerListExpr);
REGISTER_MATCHER(cxxTemporaryObjectExpr);
REGISTER_MATCHER(cxxThisExpr);
REGISTER_MATCHER(cxxThrowExpr);
@@ -185,6 +210,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(forEachArgumentWithParam);
REGISTER_MATCHER(forEachConstructorInitializer);
REGISTER_MATCHER(forEachDescendant);
+ REGISTER_MATCHER(forEachOverridden);
REGISTER_MATCHER(forEachSwitchCase);
REGISTER_MATCHER(forField);
REGISTER_MATCHER(forFunction);
@@ -296,6 +322,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isCatchAll);
REGISTER_MATCHER(isClass);
REGISTER_MATCHER(isConst);
+ REGISTER_MATCHER(isConstexpr);
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isCopyAssignmentOperator);
REGISTER_MATCHER(isCopyConstructor);
@@ -330,6 +357,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isPublic);
REGISTER_MATCHER(isPure);
REGISTER_MATCHER(isSignedInteger);
+ REGISTER_MATCHER(isStaticStorageClass);
REGISTER_MATCHER(isStruct);
REGISTER_MATCHER(isTemplateInstantiation);
REGISTER_MATCHER(isUnion);
@@ -342,6 +370,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(labelDecl);
REGISTER_MATCHER(labelStmt);
REGISTER_MATCHER(lambdaExpr);
+ REGISTER_MATCHER(linkageSpecDecl);
REGISTER_MATCHER(lValueReferenceType);
REGISTER_MATCHER(matchesName);
REGISTER_MATCHER(matchesSelector);
@@ -359,9 +388,16 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(nullStmt);
REGISTER_MATCHER(numSelectorArgs);
REGISTER_MATCHER(ofClass);
+ REGISTER_MATCHER(objcCategoryDecl);
+ REGISTER_MATCHER(objcCategoryImplDecl);
+ REGISTER_MATCHER(objcImplementationDecl);
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 +448,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(typedefNameDecl);
REGISTER_MATCHER(typedefType);
REGISTER_MATCHER(typeAliasDecl);
+ REGISTER_MATCHER(typeAliasTemplateDecl);
REGISTER_MATCHER(typeLoc);
REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
REGISTER_MATCHER(unaryOperator);
@@ -431,12 +468,10 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(withInitializer);
}
-RegistryMaps::~RegistryMaps() {}
+RegistryMaps::~RegistryMaps() = default;
static llvm::ManagedStatic<RegistryMaps> RegistryData;
-} // anonymous namespace
-
// static
llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
auto it = RegistryData->constructors().find(MatcherName);
@@ -445,10 +480,8 @@ llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
: it->second.get();
}
-namespace {
-
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
- const std::set<ASTNodeKind> &KS) {
+static llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const std::set<ASTNodeKind> &KS) {
unsigned Count = 0;
for (std::set<ASTNodeKind>::const_iterator I = KS.begin(), E = KS.end();
I != E; ++I) {
@@ -463,8 +496,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
return OS;
}
-} // namespace
-
std::vector<ArgKind> Registry::getAcceptedCompletionTypes(
ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {
ASTNodeKind InitialTypes[] = {
@@ -574,7 +605,6 @@ Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) {
return Completions;
}
-// static
VariantMatcher Registry::constructMatcher(MatcherCtor Ctor,
SourceRange NameRange,
ArrayRef<ParserValue> Args,
@@ -582,7 +612,6 @@ VariantMatcher Registry::constructMatcher(MatcherCtor Ctor,
return Ctor->create(NameRange, Args, Error);
}
-// static
VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor,
SourceRange NameRange,
StringRef BindID,
@@ -602,6 +631,6 @@ VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor,
return VariantMatcher();
}
-} // namespace dynamic
-} // namespace ast_matchers
-} // namespace clang
+} // namespace dynamic
+} // namespace ast_matchers
+} // namespace clang
diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp
index f0339ed479..57858d00ac 100644
--- a/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -24,6 +24,10 @@ std::string ArgKind::asString() const {
switch (getArgKind()) {
case AK_Matcher:
return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
+ case AK_Boolean:
+ return "boolean";
+ case AK_Double:
+ return "double";
case AK_Unsigned:
return "unsigned";
case AK_String:
@@ -247,6 +251,14 @@ VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
*this = Other;
}
+VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {
+ setBoolean(Boolean);
+}
+
+VariantValue::VariantValue(double Double) : Type(VT_Nothing) {
+ setDouble(Double);
+}
+
VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
setUnsigned(Unsigned);
}
@@ -265,6 +277,12 @@ VariantValue &VariantValue::operator=(const VariantValue &Other) {
if (this == &Other) return *this;
reset();
switch (Other.Type) {
+ case VT_Boolean:
+ setBoolean(Other.getBoolean());
+ break;
+ case VT_Double:
+ setDouble(Other.getDouble());
+ break;
case VT_Unsigned:
setUnsigned(Other.getUnsigned());
break;
@@ -290,6 +308,8 @@ void VariantValue::reset() {
delete Value.Matcher;
break;
// Cases that do nothing.
+ case VT_Boolean:
+ case VT_Double:
case VT_Unsigned:
case VT_Nothing:
break;
@@ -297,6 +317,36 @@ void VariantValue::reset() {
Type = VT_Nothing;
}
+bool VariantValue::isBoolean() const {
+ return Type == VT_Boolean;
+}
+
+bool VariantValue::getBoolean() const {
+ assert(isBoolean());
+ return Value.Boolean;
+}
+
+void VariantValue::setBoolean(bool NewValue) {
+ reset();
+ Type = VT_Boolean;
+ Value.Boolean = NewValue;
+}
+
+bool VariantValue::isDouble() const {
+ return Type == VT_Double;
+}
+
+double VariantValue::getDouble() const {
+ assert(isDouble());
+ return Value.Double;
+}
+
+void VariantValue::setDouble(double NewValue) {
+ reset();
+ Type = VT_Double;
+ Value.Double = NewValue;
+}
+
bool VariantValue::isUnsigned() const {
return Type == VT_Unsigned;
}
@@ -344,6 +394,18 @@ void VariantValue::setMatcher(const VariantMatcher &NewValue) {
bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
switch (Kind.getArgKind()) {
+ case ArgKind::AK_Boolean:
+ if (!isBoolean())
+ return false;
+ *Specificity = 1;
+ return true;
+
+ case ArgKind::AK_Double:
+ if (!isDouble())
+ return false;
+ *Specificity = 1;
+ return true;
+
case ArgKind::AK_Unsigned:
if (!isUnsigned())
return false;
@@ -383,6 +445,8 @@ std::string VariantValue::getTypeAsString() const {
switch (Type) {
case VT_String: return "String";
case VT_Matcher: return getMatcher().getTypeAsString();
+ case VT_Boolean: return "Boolean";
+ case VT_Double: return "Double";
case VT_Unsigned: return "Unsigned";
case VT_Nothing: return "Nothing";
}
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 6b58916162..181edff0a0 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -12,8 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/AnalysisContext.h"
-#include "BodyFarm.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -23,6 +22,7 @@
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
+#include "clang/Analysis/BodyFarm.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Support/BumpVector.h"
@@ -63,38 +63,33 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
-AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool addInitializers,
- bool addTemporaryDtors,
- bool synthesizeBodies,
- bool addStaticInitBranch,
- bool addCXXNewAllocator,
- CodeInjector *injector)
- : Injector(injector), SynthesizeBodies(synthesizeBodies)
-{
+AnalysisDeclContextManager::AnalysisDeclContextManager(
+ ASTContext &ASTCtx, bool useUnoptimizedCFG, bool addImplicitDtors,
+ bool addInitializers, bool addTemporaryDtors, bool addLifetime,
+ bool addLoopExit, bool synthesizeBodies, bool addStaticInitBranch,
+ bool addCXXNewAllocator, CodeInjector *injector)
+ : Injector(injector), FunctionBodyFarm(ASTCtx, injector),
+ SynthesizeBodies(synthesizeBodies) {
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
+ cfgBuildOptions.AddLifetime = addLifetime;
+ cfgBuildOptions.AddLoopExit = addLoopExit;
cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
}
void AnalysisDeclContextManager::clear() { Contexts.clear(); }
-static BodyFarm &getBodyFarm(ASTContext &C, CodeInjector *injector = nullptr) {
- static BodyFarm *BF = new BodyFarm(C, injector);
- return *BF;
-}
-
Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
IsAutosynthesized = false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
+ if (auto *CoroBody = dyn_cast_or_null<CoroutineBodyStmt>(Body))
+ Body = CoroBody->getBody();
if (Manager && Manager->synthesizeBodies()) {
- Stmt *SynthesizedBody =
- getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD);
+ Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(FD);
if (SynthesizedBody) {
Body = SynthesizedBody;
IsAutosynthesized = true;
@@ -105,8 +100,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
Stmt *Body = MD->getBody();
if (Manager && Manager->synthesizeBodies()) {
- Stmt *SynthesizedBody =
- getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(MD);
+ Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(MD);
if (SynthesizedBody) {
Body = SynthesizedBody;
IsAutosynthesized = true;
@@ -311,6 +305,8 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
return AC.get();
}
+BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; }
+
const StackFrameContext *
AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S,
const CFGBlock *Blk, unsigned Idx) {
@@ -604,8 +600,6 @@ AnalysisDeclContext::~AnalysisDeclContext() {
}
}
-AnalysisDeclContextManager::~AnalysisDeclContextManager() {}
-
LocationContext::~LocationContext() {}
LocationContextManager::~LocationContextManager() {
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 56c812c34c..58a129c411 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -12,13 +12,20 @@
//
//===----------------------------------------------------------------------===//
-#include "BodyFarm.h"
+#include "clang/Analysis/BodyFarm.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Analysis/CodeInjector.h"
+#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "body-farm"
using namespace clang;
@@ -55,7 +62,8 @@ public:
CompoundStmt *makeCompound(ArrayRef<Stmt*>);
/// Create a new DeclRefExpr for the referenced variable.
- DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
+ DeclRefExpr *makeDeclRefExpr(const VarDecl *D,
+ bool RefersToEnclosingVariableOrCapture = false);
/// Create a new UnaryOperator representing a dereference.
UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
@@ -66,9 +74,19 @@ public:
/// Create an implicit cast to a builtin boolean type.
ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
- // Create an implicit cast for lvalue-to-rvaluate conversions.
+ /// Create an implicit cast for lvalue-to-rvaluate conversions.
ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
+ /// Make RValue out of variable declaration, creating a temporary
+ /// DeclRefExpr in the process.
+ ImplicitCastExpr *
+ makeLvalueToRvalue(const VarDecl *Decl,
+ bool RefersToEnclosingVariableOrCapture = false);
+
+ /// Create an implicit cast of the given type.
+ ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty,
+ CastKind CK = CK_LValueToRValue);
+
/// Create an Objective-C bool literal.
ObjCBoolLiteralExpr *makeObjCBool(bool Val);
@@ -78,6 +96,18 @@ public:
/// Create a Return statement.
ReturnStmt *makeReturn(const Expr *RetVal);
+ /// Create an integer literal.
+ IntegerLiteral *makeIntegerLiteral(uint64_t value);
+
+ /// Create a member expression.
+ MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
+ bool IsArrow = false,
+ ExprValueKind ValueKind = VK_LValue);
+
+ /// Returns a *first* member field of a record declaration with a given name.
+ /// \return an nullptr if no member with such a name exists.
+ ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name);
+
private:
ASTContext &C;
};
@@ -87,7 +117,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,23 +129,21 @@ 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) {
return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation());
}
-DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
- DeclRefExpr *DR =
- DeclRefExpr::Create(/* Ctx = */ C,
- /* QualifierLoc = */ NestedNameSpecifierLoc(),
- /* TemplateKWLoc = */ SourceLocation(),
- /* D = */ const_cast<VarDecl*>(D),
- /* RefersToEnclosingVariableOrCapture = */ false,
- /* NameLoc = */ SourceLocation(),
- /* T = */ D->getType(),
- /* VK = */ VK_LValue);
+DeclRefExpr *ASTMaker::makeDeclRefExpr(
+ const VarDecl *D,
+ bool RefersToEnclosingVariableOrCapture) {
+ QualType Type = D->getType().getNonReferenceType();
+
+ DeclRefExpr *DR = DeclRefExpr::Create(
+ C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D),
+ RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue);
return DR;
}
@@ -125,8 +153,25 @@ UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
}
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
- return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
- const_cast<Expr*>(Arg), nullptr, VK_RValue);
+ return makeImplicitCast(Arg, Ty, CK_LValueToRValue);
+}
+
+ImplicitCastExpr *
+ASTMaker::makeLvalueToRvalue(const VarDecl *Arg,
+ bool RefersToEnclosingVariableOrCapture) {
+ QualType Type = Arg->getType().getNonReferenceType();
+ return makeLvalueToRvalue(makeDeclRefExpr(Arg,
+ RefersToEnclosingVariableOrCapture),
+ Type);
+}
+
+ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty,
+ CastKind CK) {
+ return ImplicitCastExpr::Create(C, Ty,
+ /* CastKind=*/ CK,
+ /* Expr=*/ const_cast<Expr *>(Arg),
+ /* CXXCastPath=*/ nullptr,
+ /* ExprValueKind=*/ VK_RValue);
}
Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
@@ -161,12 +206,252 @@ ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
nullptr);
}
+IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t value) {
+ return IntegerLiteral::Create(C,
+ llvm::APInt(
+ /*numBits=*/C.getTypeSize(C.IntTy), value),
+ /*QualType=*/C.IntTy, SourceLocation());
+}
+
+MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
+ bool IsArrow,
+ ExprValueKind ValueKind) {
+
+ DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public);
+ return MemberExpr::Create(
+ C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
+ SourceLocation(), MemberDecl, FoundDecl,
+ DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
+ /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
+ OK_Ordinary);
+}
+
+ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
+
+ CXXBasePaths Paths(
+ /* FindAmbiguities=*/false,
+ /* RecordPaths=*/false,
+ /* DetectVirtual=*/ false);
+ const IdentifierInfo &II = C.Idents.get(Name);
+ DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II);
+
+ DeclContextLookupResult Decls = RD->lookup(DeclName);
+ for (NamedDecl *FoundDecl : Decls)
+ if (!FoundDecl->getDeclContext()->isFunctionOrMethod())
+ return cast<ValueDecl>(FoundDecl);
+
+ return nullptr;
+}
+
//===----------------------------------------------------------------------===//
// Creation functions for faux ASTs.
//===----------------------------------------------------------------------===//
typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
+static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M,
+ const ParmVarDecl *Callback,
+ ArrayRef<Expr *> CallArgs) {
+
+ QualType Ty = Callback->getType();
+ DeclRefExpr *Call = M.makeDeclRefExpr(Callback);
+ CastKind CK;
+ if (Ty->isRValueReferenceType()) {
+ CK = CK_LValueToRValue;
+ } else {
+ assert(Ty->isLValueReferenceType());
+ CK = CK_FunctionToPointerDecay;
+ Ty = C.getPointerType(Ty.getNonReferenceType());
+ }
+
+ return new (C)
+ CallExpr(C, M.makeImplicitCast(Call, Ty.getNonReferenceType(), CK),
+ /*args=*/CallArgs,
+ /*QualType=*/C.VoidTy,
+ /*ExprValueType=*/VK_RValue,
+ /*SourceLocation=*/SourceLocation());
+}
+
+static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
+ const ParmVarDecl *Callback,
+ CXXRecordDecl *CallbackDecl,
+ ArrayRef<Expr *> CallArgs) {
+ assert(CallbackDecl != nullptr);
+ assert(CallbackDecl->isLambda());
+ FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator();
+ assert(callOperatorDecl != nullptr);
+
+ DeclRefExpr *callOperatorDeclRef =
+ DeclRefExpr::Create(/* Ctx =*/ C,
+ /* QualifierLoc =*/ NestedNameSpecifierLoc(),
+ /* TemplateKWLoc =*/ SourceLocation(),
+ const_cast<FunctionDecl *>(callOperatorDecl),
+ /* RefersToEnclosingVariableOrCapture=*/ false,
+ /* NameLoc =*/ SourceLocation(),
+ /* T =*/ callOperatorDecl->getType(),
+ /* VK =*/ VK_LValue);
+
+ return new (C)
+ CXXOperatorCallExpr(/*AstContext=*/C, OO_Call, callOperatorDeclRef,
+ /*args=*/CallArgs,
+ /*QualType=*/C.VoidTy,
+ /*ExprValueType=*/VK_RValue,
+ /*SourceLocation=*/SourceLocation(), FPOptions());
+}
+
+/// Create a fake body for std::call_once.
+/// Emulates the following function body:
+///
+/// \code
+/// typedef struct once_flag_s {
+/// unsigned long __state = 0;
+/// } once_flag;
+/// template<class Callable>
+/// void call_once(once_flag& o, Callable func) {
+/// if (!o.__state) {
+/// func();
+/// }
+/// o.__state = 1;
+/// }
+/// \endcode
+static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
+ DEBUG(llvm::dbgs() << "Generating body for call_once\n");
+
+ // We need at least two parameters.
+ if (D->param_size() < 2)
+ return nullptr;
+
+ ASTMaker M(C);
+
+ const ParmVarDecl *Flag = D->getParamDecl(0);
+ const ParmVarDecl *Callback = D->getParamDecl(1);
+ QualType CallbackType = Callback->getType().getNonReferenceType();
+
+ // Nullable pointer, non-null iff function is a CXXRecordDecl.
+ CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl();
+ QualType FlagType = Flag->getType().getNonReferenceType();
+ auto *FlagRecordDecl = dyn_cast_or_null<RecordDecl>(FlagType->getAsTagDecl());
+
+ if (!FlagRecordDecl) {
+ DEBUG(llvm::dbgs() << "Flag field is not a record: "
+ << "unknown std::call_once implementation, "
+ << "ignoring the call.\n");
+ return nullptr;
+ }
+
+ // We initially assume libc++ implementation of call_once,
+ // where the once_flag struct has a field `__state_`.
+ ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_");
+
+ // Otherwise, try libstdc++ implementation, with a field
+ // `_M_once`
+ if (!FlagFieldDecl) {
+ DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, "
+ << "assuming libstdc++ implementation\n");
+ FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once");
+ }
+
+ if (!FlagFieldDecl) {
+ DEBUG(llvm::dbgs() << "No field _M_once found on std::once flag struct: "
+ << "unknown std::call_once implementation, "
+ << "ignoring the call");
+ return nullptr;
+ }
+
+ bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda();
+ if (CallbackRecordDecl && !isLambdaCall) {
+ DEBUG(llvm::dbgs() << "Not supported: synthesizing body for functors when "
+ << "body farming std::call_once, ignoring the call.");
+ return nullptr;
+ }
+
+ SmallVector<Expr *, 5> CallArgs;
+ const FunctionProtoType *CallbackFunctionType;
+ if (isLambdaCall) {
+
+ // Lambda requires callback itself inserted as a first parameter.
+ CallArgs.push_back(
+ M.makeDeclRefExpr(Callback,
+ /* RefersToEnclosingVariableOrCapture=*/ true));
+ CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator()
+ ->getType()
+ ->getAs<FunctionProtoType>();
+ } else if (!CallbackType->getPointeeType().isNull()) {
+ CallbackFunctionType =
+ CallbackType->getPointeeType()->getAs<FunctionProtoType>();
+ } else {
+ CallbackFunctionType = CallbackType->getAs<FunctionProtoType>();
+ }
+
+ if (!CallbackFunctionType)
+ return nullptr;
+
+ // First two arguments are used for the flag and for the callback.
+ if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) {
+ DEBUG(llvm::dbgs() << "Number of params of the callback does not match "
+ << "the number of params passed to std::call_once, "
+ << "ignoring the call");
+ return nullptr;
+ }
+
+ // All arguments past first two ones are passed to the callback,
+ // and we turn lvalues into rvalues if the argument is not passed by
+ // reference.
+ for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
+ const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
+ Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
+ if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
+ QualType PTy = PDecl->getType().getNonReferenceType();
+ ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy);
+ }
+ CallArgs.push_back(ParamExpr);
+ }
+
+ CallExpr *CallbackCall;
+ if (isLambdaCall) {
+
+ CallbackCall = create_call_once_lambda_call(C, M, Callback,
+ CallbackRecordDecl, CallArgs);
+ } else {
+
+ // Function pointer case.
+ CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs);
+ }
+
+ DeclRefExpr *FlagDecl =
+ M.makeDeclRefExpr(Flag,
+ /* RefersToEnclosingVariableOrCapture=*/true);
+
+
+ MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
+ assert(Deref->isLValue());
+ QualType DerefType = Deref->getType();
+
+ // Negation predicate.
+ UnaryOperator *FlagCheck = new (C) UnaryOperator(
+ /* input=*/
+ M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
+ CK_IntegralToBoolean),
+ /* opc=*/ UO_LNot,
+ /* QualType=*/ C.IntTy,
+ /* ExprValueKind=*/ VK_RValue,
+ /* ExprObjectKind=*/ OK_Ordinary, SourceLocation());
+
+ // Create assignment.
+ BinaryOperator *FlagAssignment = M.makeAssignment(
+ Deref, M.makeIntegralCast(M.makeIntegerLiteral(1), DerefType), DerefType);
+
+ IfStmt *Out = new (C)
+ IfStmt(C, SourceLocation(),
+ /* IsConstexpr=*/ false,
+ /* init=*/ nullptr,
+ /* var=*/ nullptr,
+ /* cond=*/ FlagCheck,
+ /* then=*/ M.makeCompound({CallbackCall, FlagAssignment}));
+
+ return Out;
+}
+
/// Create a fake body for dispatch_once.
static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
// Check if we have at least two parameters.
@@ -202,15 +487,17 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
ASTMaker M(C);
// (1) Create the call.
- DeclRefExpr *DR = M.makeDeclRefExpr(Block);
- ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
- CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,
- SourceLocation());
+ CallExpr *CE = new (C) CallExpr(
+ /*ASTContext=*/C,
+ /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block),
+ /*args=*/None,
+ /*QualType=*/C.VoidTy,
+ /*ExprValueType=*/VK_RValue,
+ /*SourceLocation=*/SourceLocation());
// (2) Create the assignment to the predicate.
- IntegerLiteral *IL =
- IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
- C.IntTy, SourceLocation());
+ IntegerLiteral *IL = M.makeIntegerLiteral(1);
+
BinaryOperator *B =
M.makeAssignment(
M.makeDereference(
@@ -234,13 +521,20 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
PredicateTy),
PredicateTy);
- UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
- VK_RValue, OK_Ordinary,
- SourceLocation());
+ UnaryOperator *UO = new (C) UnaryOperator(
+ /* input=*/ LValToRval,
+ /* opc=*/ UO_LNot,
+ /* QualType=*/ C.IntTy,
+ /* ExprValueKind=*/ VK_RValue,
+ /* ExprObjectKind=*/ OK_Ordinary, SourceLocation());
// (5) Create the 'if' statement.
- IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr,
- UO, CS);
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(),
+ /* IsConstexpr=*/ false,
+ /* init=*/ nullptr,
+ /* var=*/ nullptr,
+ /* cond=*/ UO,
+ /* then=*/ CS);
return If;
}
@@ -370,8 +664,9 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
if (Name.startswith("OSAtomicCompareAndSwap") ||
Name.startswith("objc_atomicCompareAndSwap")) {
FF = create_OSAtomicCompareAndSwap;
- }
- else {
+ } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {
+ FF = create_call_once;
+ } else {
FF = llvm::StringSwitch<FunctionFarmer>(Name)
.Case("dispatch_sync", create_dispatch_sync)
.Case("dispatch_once", create_dispatch_once)
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 2a2b3d73b5..164d9640af 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -233,6 +233,7 @@ public:
}
int distance(const_iterator L);
+ const_iterator shared_parent(const_iterator L);
};
friend class const_iterator;
@@ -275,6 +276,30 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
return D;
}
+/// Calculates the closest parent of this iterator
+/// that is in a scope reachable through the parents of L.
+/// I.e. when using 'goto' from this to L, the lifetime of all variables
+/// between this and shared_parent(L) end.
+LocalScope::const_iterator
+LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
+ llvm::SmallPtrSet<const LocalScope *, 4> ScopesOfL;
+ while (true) {
+ ScopesOfL.insert(L.Scope);
+ if (L == const_iterator())
+ break;
+ L = L.Scope->Prev;
+ }
+
+ const_iterator F = *this;
+ while (true) {
+ if (ScopesOfL.count(F.Scope))
+ return F;
+ assert(F != const_iterator() &&
+ "L iterator is not reachable from F iterator.");
+ F = F.Scope->Prev;
+ }
+}
+
/// Structure for specifying position in CFG during its build process. It
/// consists of CFGBlock that specifies position in CFG and
/// LocalScope::const_iterator that specifies position in LocalScope graph.
@@ -370,12 +395,16 @@ class CFGBuilder {
ASTContext *Context;
std::unique_ptr<CFG> cfg;
- CFGBlock *Block;
- CFGBlock *Succ;
+ CFGBlock *Block; // Current block.
+ CFGBlock *Succ; // Block after the current block.
JumpTarget ContinueJumpTarget;
JumpTarget BreakJumpTarget;
+ JumpTarget SEHLeaveJumpTarget;
CFGBlock *SwitchTerminatedBlock;
CFGBlock *DefaultCaseBlock;
+
+ // This can point either to a try or a __try block. The frontend forbids
+ // mixing both kinds in one function, so having one for both is enough.
CFGBlock *TryTerminatedBlock;
// Current position in local scope.
@@ -411,13 +440,12 @@ class CFGBuilder {
public:
explicit CFGBuilder(ASTContext *astContext,
- const CFG::BuildOptions &buildOpts)
- : Context(astContext), cfg(new CFG()), // crew a new CFG
- Block(nullptr), Succ(nullptr),
- SwitchTerminatedBlock(nullptr), DefaultCaseBlock(nullptr),
- TryTerminatedBlock(nullptr), badCFG(false), BuildOpts(buildOpts),
- switchExclusivelyCovered(false), switchCond(nullptr),
- cachedEntry(nullptr), lastLookup(nullptr) {}
+ const CFG::BuildOptions &buildOpts)
+ : Context(astContext), cfg(new CFG()), // crew a new CFG
+ Block(nullptr), Succ(nullptr), SwitchTerminatedBlock(nullptr),
+ DefaultCaseBlock(nullptr), TryTerminatedBlock(nullptr), badCFG(false),
+ BuildOpts(buildOpts), switchExclusivelyCovered(false),
+ switchCond(nullptr), cachedEntry(nullptr), lastLookup(nullptr) {}
// buildCFG - Used by external clients to construct the CFG.
std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *Statement);
@@ -476,6 +504,10 @@ private:
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
CFGBlock *VisitReturnStmt(ReturnStmt *R);
+ CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S);
+ CFGBlock *VisitSEHFinallyStmt(SEHFinallyStmt *S);
+ CFGBlock *VisitSEHLeaveStmt(SEHLeaveStmt *S);
+ CFGBlock *VisitSEHTryStmt(SEHTryStmt *S);
CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
CFGBlock *VisitSwitchStmt(SwitchStmt *S);
CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
@@ -577,8 +609,13 @@ private:
return Visit(S, AddStmtChoice::AlwaysAdd);
}
CFGBlock *addInitializer(CXXCtorInitializer *I);
+ void addLoopExit(const Stmt *LoopStmt);
void addAutomaticObjDtors(LocalScope::const_iterator B,
LocalScope::const_iterator E, Stmt *S);
+ void addLifetimeEnds(LocalScope::const_iterator B,
+ LocalScope::const_iterator E, Stmt *S);
+ void addAutomaticObjHandling(LocalScope::const_iterator B,
+ LocalScope::const_iterator E, Stmt *S);
void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD);
// Local scopes creation.
@@ -619,6 +656,14 @@ private:
B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
}
+ void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
+ B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext());
+ }
+
+ void appendLoopExit(CFGBlock *B, const Stmt *LoopStmt) {
+ B->appendLoopExit(LoopStmt, cfg->getBumpVectorContext());
+ }
+
void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
}
@@ -626,6 +671,10 @@ private:
void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E);
+ void prependAutomaticObjLifetimeWithTerminator(CFGBlock *Blk,
+ LocalScope::const_iterator B,
+ LocalScope::const_iterator E);
+
void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) {
B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
cfg->getBumpVectorContext());
@@ -957,7 +1006,8 @@ private:
return TryResult();
}
-
+
+ bool hasTrivialDestructor(VarDecl *VD);
};
inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
@@ -1031,6 +1081,9 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
assert(Succ == &cfg->getExit());
Block = nullptr; // the EXIT block is empty. Create all other blocks lazily.
+ assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) &&
+ "AddImplicitDtors and AddLifetime cannot be used at the same time");
+
if (BuildOpts.AddImplicitDtors)
if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
addImplicitDtorsForDestructor(DD);
@@ -1067,6 +1120,8 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
if (LI == LabelMap.end()) continue;
JumpTarget JT = LI->second;
+ prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
+ JT.scopePosition);
prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
JT.scopePosition);
addSuccessor(B, JT.block);
@@ -1209,7 +1264,71 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context,
return Init->getType();
}
-
+
+
+// TODO: Support adding LoopExit element to the CFG in case where the loop is
+// ended by ReturnStmt, GotoStmt or ThrowExpr.
+void CFGBuilder::addLoopExit(const Stmt *LoopStmt){
+ if(!BuildOpts.AddLoopExit)
+ return;
+ autoCreateBlock();
+ appendLoopExit(Block, LoopStmt);
+}
+
+void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
+ LocalScope::const_iterator E,
+ Stmt *S) {
+ if (BuildOpts.AddImplicitDtors)
+ addAutomaticObjDtors(B, E, S);
+ if (BuildOpts.AddLifetime)
+ addLifetimeEnds(B, E, S);
+}
+
+/// Add to current block automatic objects that leave the scope.
+void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B,
+ LocalScope::const_iterator E, Stmt *S) {
+ if (!BuildOpts.AddLifetime)
+ return;
+
+ if (B == E)
+ return;
+
+ // To go from B to E, one first goes up the scopes from B to P
+ // then sideways in one scope from P to P' and then down
+ // the scopes from P' to E.
+ // The lifetime of all objects between B and P end.
+ LocalScope::const_iterator P = B.shared_parent(E);
+ int dist = B.distance(P);
+ if (dist <= 0)
+ return;
+
+ // We need to perform the scope leaving in reverse order
+ SmallVector<VarDecl *, 10> DeclsTrivial;
+ SmallVector<VarDecl *, 10> DeclsNonTrivial;
+ DeclsTrivial.reserve(dist);
+ DeclsNonTrivial.reserve(dist);
+
+ for (LocalScope::const_iterator I = B; I != P; ++I)
+ if (hasTrivialDestructor(*I))
+ DeclsTrivial.push_back(*I);
+ else
+ DeclsNonTrivial.push_back(*I);
+
+ autoCreateBlock();
+ // object with trivial destructor end their lifetime last (when storage
+ // duration ends)
+ for (SmallVectorImpl<VarDecl *>::reverse_iterator I = DeclsTrivial.rbegin(),
+ E = DeclsTrivial.rend();
+ I != E; ++I)
+ appendLifetimeEnds(Block, *I, S);
+
+ for (SmallVectorImpl<VarDecl *>::reverse_iterator
+ I = DeclsNonTrivial.rbegin(),
+ E = DeclsNonTrivial.rend();
+ I != E; ++I)
+ appendLifetimeEnds(Block, *I, S);
+}
+
/// addAutomaticObjDtors - Add to current block automatic objects destructors
/// for objects in range of local scope positions. Use S as trigger statement
/// for destructors.
@@ -1309,7 +1428,7 @@ LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
/// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement
/// that should create implicit scope (e.g. if/else substatements).
void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
- if (!BuildOpts.AddImplicitDtors)
+ if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
return;
LocalScope *Scope = nullptr;
@@ -1334,7 +1453,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
/// reuse Scope if not NULL.
LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
LocalScope* Scope) {
- if (!BuildOpts.AddImplicitDtors)
+ if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
return Scope;
for (auto *DI : DS->decls())
@@ -1343,23 +1462,7 @@ LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
return Scope;
}
-/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will
-/// create add scope for automatic objects and temporary objects bound to
-/// const reference. Will reuse Scope if not NULL.
-LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
- LocalScope* Scope) {
- if (!BuildOpts.AddImplicitDtors)
- return Scope;
-
- // Check if variable is local.
- switch (VD->getStorageClass()) {
- case SC_None:
- case SC_Auto:
- case SC_Register:
- break;
- default: return Scope;
- }
-
+bool CFGBuilder::hasTrivialDestructor(VarDecl *VD) {
// Check for const references bound to temporary. Set type to pointee.
QualType QT = VD->getType();
if (QT.getTypePtr()->isReferenceType()) {
@@ -1370,44 +1473,74 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
// temporaries, and a single declaration can extend multiple temporaries.
// We should look at the storage duration on each nested
// MaterializeTemporaryExpr instead.
+
const Expr *Init = VD->getInit();
if (!Init)
- return Scope;
+ return true;
// Lifetime-extending a temporary.
bool FoundMTE = false;
QT = getReferenceInitTemporaryType(*Context, Init, &FoundMTE);
if (!FoundMTE)
- return Scope;
+ return true;
}
// Check for constant size array. Set type to array element type.
while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
if (AT->getSize() == 0)
- return Scope;
+ return true;
QT = AT->getElementType();
}
// Check if type is a C++ class with non-trivial destructor.
if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
- if (CD->hasDefinition() && !CD->hasTrivialDestructor()) {
+ return !CD->hasDefinition() || CD->hasTrivialDestructor();
+ return true;
+}
+
+/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will
+/// create add scope for automatic objects and temporary objects bound to
+/// const reference. Will reuse Scope if not NULL.
+LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
+ LocalScope* Scope) {
+ assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) &&
+ "AddImplicitDtors and AddLifetime cannot be used at the same time");
+ if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
+ return Scope;
+
+ // Check if variable is local.
+ switch (VD->getStorageClass()) {
+ case SC_None:
+ case SC_Auto:
+ case SC_Register:
+ break;
+ default: return Scope;
+ }
+
+ if (BuildOpts.AddImplicitDtors) {
+ if (!hasTrivialDestructor(VD)) {
// Add the variable to scope
Scope = createOrReuseLocalScope(Scope);
Scope->addVar(VD);
ScopePos = Scope->begin();
}
+ return Scope;
+ }
+
+ assert(BuildOpts.AddLifetime);
+ // Add the variable to scope
+ Scope = createOrReuseLocalScope(Scope);
+ Scope->addVar(VD);
+ ScopePos = Scope->begin();
return Scope;
}
/// addLocalScopeAndDtors - For given statement add local scope for it and
/// add destructors that will cleanup the scope. Will reuse Scope if not NULL.
void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
- if (!BuildOpts.AddImplicitDtors)
- return;
-
LocalScope::const_iterator scopeBeginPos = ScopePos;
addLocalScopeForStmt(S);
- addAutomaticObjDtors(ScopePos, scopeBeginPos, S);
+ addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
}
/// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for
@@ -1419,6 +1552,8 @@ void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
/// no-return destructors properly.
void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E) {
+ if (!BuildOpts.AddImplicitDtors)
+ return;
BumpVectorContext &C = cfg->getBumpVectorContext();
CFGBlock::iterator InsertPos
= Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C);
@@ -1427,6 +1562,21 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
Blk->getTerminator());
}
+/// prependAutomaticObjLifetimeWithTerminator - Prepend lifetime CFGElements for
+/// variables with automatic storage duration to CFGBlock's elements vector.
+/// Elements will be prepended to physical beginning of the vector which
+/// happens to be logical end. Use blocks terminator as statement that specifies
+/// where lifetime ends.
+void CFGBuilder::prependAutomaticObjLifetimeWithTerminator(
+ CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) {
+ if (!BuildOpts.AddLifetime)
+ return;
+ BumpVectorContext &C = cfg->getBumpVectorContext();
+ CFGBlock::iterator InsertPos =
+ Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C);
+ for (LocalScope::const_iterator I = B; I != E; ++I)
+ InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator());
+}
/// Visit - Walk the subtree of a statement and add extra
/// blocks for ternary operators, &&, and ||. We also process "," and
/// DeclStmts (which may contain nested control-flow).
@@ -1588,6 +1738,18 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::ReturnStmtClass:
return VisitReturnStmt(cast<ReturnStmt>(S));
+ case Stmt::SEHExceptStmtClass:
+ return VisitSEHExceptStmt(cast<SEHExceptStmt>(S));
+
+ case Stmt::SEHFinallyStmtClass:
+ return VisitSEHFinallyStmt(cast<SEHFinallyStmt>(S));
+
+ case Stmt::SEHLeaveStmtClass:
+ return VisitSEHLeaveStmt(cast<SEHLeaveStmt>(S));
+
+ case Stmt::SEHTryStmtClass:
+ return VisitSEHTryStmt(cast<SEHTryStmt>(S));
+
case Stmt::UnaryExprOrTypeTraitExprClass:
return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
asc);
@@ -1815,7 +1977,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
// If there is no target for the break, then we are looking at an incomplete
// AST. This means that the CFG cannot be constructed.
if (BreakJumpTarget.block) {
- addAutomaticObjDtors(ScopePos, BreakJumpTarget.scopePosition, B);
+ addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
addSuccessor(Block, BreakJumpTarget.block);
} else
badCFG = true;
@@ -1947,13 +2109,12 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
LocalScope::const_iterator scopeBeginPos = ScopePos;
- if (BuildOpts.AddImplicitDtors) {
- addLocalScopeForStmt(C);
- }
+ addLocalScopeForStmt(C);
+
if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) {
// If the body ends with a ReturnStmt, the dtors will be added in
// VisitReturnStmt.
- addAutomaticObjDtors(ScopePos, scopeBeginPos, C);
+ addAutomaticObjHandling(ScopePos, scopeBeginPos, C);
}
CFGBlock *LastBlock = Block;
@@ -2183,7 +2344,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
if (VarDecl *VD = I->getConditionVariable())
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), I);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
// The block we were processing is now finished. Make it the successor
// block.
@@ -2308,7 +2469,7 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
// Create the new block.
Block = createBlock(false);
- addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
+ addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R);
// If the one of the destructors does not return, we already have the Exit
// block as a successor.
@@ -2320,6 +2481,117 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
return VisitStmt(R, AddStmtChoice::AlwaysAdd);
}
+CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
+ // SEHExceptStmt are treated like labels, so they are the first statement in a
+ // block.
+
+ // Save local scope position because in case of exception variable ScopePos
+ // won't be restored when traversing AST.
+ SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+
+ addStmt(ES->getBlock());
+ CFGBlock *SEHExceptBlock = Block;
+ if (!SEHExceptBlock)
+ SEHExceptBlock = createBlock();
+
+ appendStmt(SEHExceptBlock, ES);
+
+ // Also add the SEHExceptBlock as a label, like with regular labels.
+ SEHExceptBlock->setLabel(ES);
+
+ // Bail out if the CFG is bad.
+ if (badCFG)
+ return nullptr;
+
+ // We set Block to NULL to allow lazy creation of a new block (if necessary).
+ Block = nullptr;
+
+ return SEHExceptBlock;
+}
+
+CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {
+ return VisitCompoundStmt(FS->getBlock());
+}
+
+CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {
+ // "__leave" is a control-flow statement. Thus we stop processing the current
+ // block.
+ if (badCFG)
+ return nullptr;
+
+ // Now create a new block that ends with the __leave statement.
+ Block = createBlock(false);
+ Block->setTerminator(LS);
+
+ // If there is no target for the __leave, then we are looking at an incomplete
+ // AST. This means that the CFG cannot be constructed.
+ if (SEHLeaveJumpTarget.block) {
+ addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
+ addSuccessor(Block, SEHLeaveJumpTarget.block);
+ } else
+ badCFG = true;
+
+ return Block;
+}
+
+CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
+ // "__try"/"__except"/"__finally" is a control-flow statement. Thus we stop
+ // processing the current block.
+ CFGBlock *SEHTrySuccessor = nullptr;
+
+ if (Block) {
+ if (badCFG)
+ return nullptr;
+ SEHTrySuccessor = Block;
+ } else SEHTrySuccessor = Succ;
+
+ // FIXME: Implement __finally support.
+ if (Terminator->getFinallyHandler())
+ return NYS();
+
+ CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
+
+ // Create a new block that will contain the __try statement.
+ CFGBlock *NewTryTerminatedBlock = createBlock(false);
+
+ // Add the terminator in the __try block.
+ NewTryTerminatedBlock->setTerminator(Terminator);
+
+ if (SEHExceptStmt *Except = Terminator->getExceptHandler()) {
+ // The code after the try is the implicit successor if there's an __except.
+ Succ = SEHTrySuccessor;
+ Block = nullptr;
+ CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
+ if (!ExceptBlock)
+ return nullptr;
+ // Add this block to the list of successors for the block with the try
+ // statement.
+ addSuccessor(NewTryTerminatedBlock, ExceptBlock);
+ }
+ if (PrevSEHTryTerminatedBlock)
+ addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
+ else
+ addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
+
+ // The code after the try is the implicit successor.
+ Succ = SEHTrySuccessor;
+
+ // Save the current "__try" context.
+ SaveAndRestore<CFGBlock *> save_try(TryTerminatedBlock,
+ NewTryTerminatedBlock);
+ cfg->addTryDispatchBlock(TryTerminatedBlock);
+
+ // Save the current value for the __leave target.
+ // All __leaves should go to the code following the __try
+ // (FIXME: or if the __try has a __finally, to the __finally.)
+ SaveAndRestore<JumpTarget> save_break(SEHLeaveJumpTarget);
+ SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
+
+ assert(Terminator->getTryBlock() && "__try must contain a non-NULL body");
+ Block = nullptr;
+ return addStmt(Terminator->getTryBlock());
+}
+
CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
// Get the block of the labeled statement. Add it to our map.
addStmt(L->getSubStmt());
@@ -2389,7 +2661,7 @@ CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
else {
JumpTarget JT = I->second;
- addAutomaticObjDtors(ScopePos, JT.scopePosition, G);
+ addAutomaticObjHandling(ScopePos, JT.scopePosition, G);
addSuccessor(Block, JT.block);
}
@@ -2414,7 +2686,9 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
addLocalScopeForVarDecl(VD);
LocalScope::const_iterator ContinueScopePos = ScopePos;
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), F);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
+
+ addLoopExit(F);
// "for" is a control-flow statement. Thus we stop processing the current
// block.
@@ -2466,7 +2740,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
ContinueJumpTarget.block->setLoopTarget(F);
// Loop body should end with destructor of Condition variable (if any).
- addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F);
+ addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -2753,8 +3027,9 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
if (VarDecl *VD = W->getConditionVariable()) {
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
+ addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
}
+ addLoopExit(W);
// "while" is a control-flow statement. Thus we stop processing the current
// block.
@@ -2788,7 +3063,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// Loop body should end with destructor of Condition variable (if any).
- addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
+ addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -2918,6 +3193,8 @@ CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
CFGBlock *LoopSuccessor = nullptr;
+ addLoopExit(D);
+
// "do...while" is a control-flow statement. Thus we stop processing the
// current block.
if (Block) {
@@ -3030,7 +3307,7 @@ CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) {
// If there is no target for the continue, then we are looking at an
// incomplete AST. This means the CFG cannot be constructed.
if (ContinueJumpTarget.block) {
- addAutomaticObjDtors(ScopePos, ContinueJumpTarget.scopePosition, C);
+ addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition, C);
addSuccessor(Block, ContinueJumpTarget.block);
} else
badCFG = true;
@@ -3085,7 +3362,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
if (VarDecl *VD = Terminator->getConditionVariable())
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), Terminator);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
if (Block) {
if (badCFG)
@@ -3373,7 +3650,7 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
if (VarDecl *VD = CS->getExceptionDecl()) {
LocalScope::const_iterator BeginScopePos = ScopePos;
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, BeginScopePos, CS);
+ addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
}
if (CS->getHandlerBlock())
@@ -3427,7 +3704,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
addLocalScopeForStmt(Begin);
if (Stmt *End = S->getEndStmt())
addLocalScopeForStmt(End);
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
LocalScope::const_iterator ContinueScopePos = ScopePos;
@@ -3898,6 +4175,8 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
case CFGElement::Statement:
case CFGElement::Initializer:
case CFGElement::NewAllocator:
+ case CFGElement::LoopExit:
+ case CFGElement::LifetimeEnds:
llvm_unreachable("getDestructorDecl should only be used with "
"ImplicitDtors");
case CFGElement::AutomaticObjectDtor: {
@@ -4174,6 +4453,10 @@ public:
OS << "try ...";
}
+ void VisitSEHTryStmt(SEHTryStmt *CS) {
+ OS << "__try ...";
+ }
+
void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
if (Stmt *Cond = C->getCond())
Cond->printPretty(OS, Helper, Policy);
@@ -4308,6 +4591,15 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
+ } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) {
+ const VarDecl *VD = DE->getVarDecl();
+ Helper.handleDecl(VD, OS);
+
+ OS << " (Lifetime ends)\n";
+
+ } else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) {
+ const Stmt *LoopStmt = LE->getLoopStmt();
+ OS << LoopStmt->getStmtClassName() << " (LoopExit)\n";
} else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
OS << "CFGNewAllocator(";
if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
@@ -4397,7 +4689,11 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
else
OS << "...";
OS << ")";
-
+ } else if (SEHExceptStmt *ES = dyn_cast<SEHExceptStmt>(Label)) {
+ OS << "__except (";
+ ES->getFilterExpr()->printPretty(OS, &Helper,
+ PrintingPolicy(Helper.getLangOpts()), 0);
+ OS << ")";
} else
llvm_unreachable("Invalid label statement in CFGBlock.");
diff --git a/lib/Analysis/CloneDetection.cpp b/lib/Analysis/CloneDetection.cpp
index e761738214..098803f9a4 100644
--- a/lib/Analysis/CloneDetection.cpp
+++ b/lib/Analysis/CloneDetection.cpp
@@ -13,38 +13,34 @@
#include "clang/Analysis/CloneDetection.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/StringRef.h"
+#include "clang/AST/DataCollection.h"
+#include "clang/AST/DeclTemplate.h"
#include "llvm/Support/MD5.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
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 +72,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,567 +87,222 @@ 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);
- }
+void CloneDetector::analyzeCodeBody(const Decl *D) {
+ assert(D);
+ assert(D->hasBody());
- // Recursively check all children of the given statement.
- for (const Stmt *Child : S->children()) {
- addVariables(Child);
- }
- }
+ Sequences.push_back(StmtSequence(D->getBody(), D));
+}
-public:
- /// \brief Creates an VariablePattern object with information about the given
- /// StmtSequence.
- VariablePattern(const StmtSequence &Sequence) {
- for (const Stmt *S : Sequence)
- addVariables(S);
+/// Returns true if and only if \p Stmt contains at least one other
+/// sequence in the \p Group.
+static bool containsAnyInGroup(StmtSequence &Seq,
+ CloneDetector::CloneGroup &Group) {
+ for (StmtSequence &GroupSeq : Group) {
+ if (Seq.contains(GroupSeq))
+ return true;
}
+ return false;
+}
- /// \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;
+/// 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;
- ++NumberOfDifferences;
+ for (StmtSequence &Stmt : Group) {
+ if (!containsAnyInGroup(Stmt, OtherGroup))
+ return false;
+ }
+ return true;
+}
- // If FirstMismatch is not a nullptr, we need to store information about
- // the first difference between the two patterns.
- if (FirstMismatch == nullptr)
- continue;
+void OnlyLargestCloneConstraint::constrain(
+ std::vector<CloneDetector::CloneGroup> &Result) {
+ std::vector<unsigned> IndexesToRemove;
- // Only proceed if we just found the first difference as we only store
- // information about the first difference.
- if (NumberOfDifferences != 1)
+ // 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;
- 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);
+ if (containsGroup(Result[j], Result[i])) {
+ IndexesToRemove.push_back(i);
+ break;
+ }
}
+ }
- return NumberOfDifferences;
+ // 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);
}
-};
}
-/// \brief 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(),
- Context.getLangOpts());
-
- // Add an empty space at the end as a padding to prevent
- // that macro names concatenate to the names of other macros.
- MacroStack << " ";
-}
+bool FilenamePatternConstraint::isAutoGenerated(
+ const CloneDetector::CloneGroup &Group) {
+ std::string Error;
+ if (IgnoredFilesPattern.empty() || Group.empty() ||
+ !IgnoredFilesRegex->isValid(Error))
+ return false;
-/// \brief Returns a string that represents all macro expansions that
-/// expanded into the given SourceLocation.
-///
-/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations
-/// A and B are expanded from the same macros in the same order.
-static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) {
- std::string MacroStack;
- llvm::raw_string_ostream MacroStackStream(MacroStack);
- SourceManager &SM = Context.getSourceManager();
-
- // Iterate over all macros that expanded into the given SourceLocation.
- while (Loc.isMacroID()) {
- // Add the macro name to the stream.
- printMacroName(MacroStackStream, Context, Loc);
- Loc = SM.getImmediateMacroCallerLoc(Loc);
+ for (const StmtSequence &S : Group) {
+ const SourceManager &SM = S.getASTContext().getSourceManager();
+ StringRef Filename = llvm::sys::path::filename(
+ SM.getFilename(S.getContainingDecl()->getLocation()));
+ if (IgnoredFilesRegex->match(Filename))
+ return true;
}
- MacroStackStream.flush();
- return MacroStack;
+
+ return false;
}
-namespace {
-/// \brief Collects the data of a single Stmt.
-///
-/// This class defines what a code clone is: If it collects for two statements
-/// the same data, then those two statements are considered to be clones of each
-/// other.
+/// This class defines what a type II code clone is: If it collects for two
+/// statements the same data, then those two statements are considered to be
+/// clones of each other.
///
/// All collected data is forwarded to the given data consumer of the type T.
/// The data consumer class needs to provide a member method with the signature:
/// update(StringRef Str)
-template <typename T>
-class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> {
-
+namespace {
+template <class T>
+class CloneTypeIIStmtDataCollector
+ : public ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>> {
ASTContext &Context;
- /// \brief The data sink to which all data is forwarded.
+ /// The data sink to which all data is forwarded.
T &DataConsumer;
+ template <class Ty> void addData(const Ty &Data) {
+ data_collection::addDataToConsumer(DataConsumer, Data);
+ }
+
public:
- /// \brief Collects data of the given Stmt.
- /// \param S The given statement.
- /// \param Context The ASTContext of S.
- /// \param DataConsumer The data sink to which all data is forwarded.
- StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer)
+ CloneTypeIIStmtDataCollector(const Stmt *S, ASTContext &Context,
+ T &DataConsumer)
: Context(Context), DataConsumer(DataConsumer) {
this->Visit(S);
}
- // Below are utility methods for appending different data to the vector.
-
- void addData(CloneDetector::DataPiece Integer) {
- DataConsumer.update(
- StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer)));
- }
-
- void addData(llvm::StringRef Str) { DataConsumer.update(Str); }
-
- void addData(const QualType &QT) { addData(QT.getAsString()); }
-
-// The functions below collect the class specific data of each Stmt subclass.
-
-// Utility macro for defining a visit method for a given class. This method
-// calls back to the ConstStmtVisitor to visit all parent classes.
+// Define a visit method for each class to collect data and subsequently visit
+// all parent classes. This uses a template so that custom visit methods by us
+// take precedence.
#define DEF_ADD_DATA(CLASS, CODE) \
- void Visit##CLASS(const CLASS *S) { \
+ template <class = void> void Visit##CLASS(const CLASS *S) { \
CODE; \
- ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
+ ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>>::Visit##CLASS(S); \
}
- DEF_ADD_DATA(Stmt, {
- addData(S->getStmtClass());
- // This ensures that macro generated code isn't identical to macro-generated
- // code.
- addData(getMacroStack(S->getLocStart(), Context));
- addData(getMacroStack(S->getLocEnd(), Context));
- })
- DEF_ADD_DATA(Expr, { addData(S->getType()); })
-
- //--- Builtin functionality ----------------------------------------------//
- DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); })
- DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); })
- DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); })
- DEF_ADD_DATA(TypeTraitExpr, {
- addData(S->getTrait());
- for (unsigned i = 0; i < S->getNumArgs(); ++i)
- addData(S->getArg(i)->getType());
- })
-
- //--- Calls --------------------------------------------------------------//
- DEF_ADD_DATA(CallExpr, {
- // Function pointers don't have a callee and we just skip hashing it.
- if (const FunctionDecl *D = S->getDirectCallee()) {
- // If the function is a template specialization, we also need to handle
- // the template arguments as they are not included in the qualified name.
- if (auto Args = D->getTemplateSpecializationArgs()) {
- std::string ArgString;
-
- // Print all template arguments into ArgString
- llvm::raw_string_ostream OS(ArgString);
- for (unsigned i = 0; i < Args->size(); ++i) {
- Args->get(i).print(Context.getLangOpts(), OS);
- // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
- OS << '\n';
- }
- OS.flush();
+#include "clang/AST/StmtDataCollectors.inc"
- addData(ArgString);
- }
- addData(D->getQualifiedNameAsString());
- }
- })
-
- //--- Exceptions ---------------------------------------------------------//
- DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); })
-
- //--- C++ OOP Stmts ------------------------------------------------------//
- DEF_ADD_DATA(CXXDeleteExpr, {
- addData(S->isArrayFormAsWritten());
- addData(S->isGlobalDelete());
- })
-
- //--- Casts --------------------------------------------------------------//
- DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); })
-
- //--- Miscellaneous Exprs ------------------------------------------------//
- DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); })
- DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); })
-
- //--- Control flow -------------------------------------------------------//
- DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); })
- DEF_ADD_DATA(IndirectGotoStmt, {
- if (S->getConstantTarget())
- addData(S->getConstantTarget()->getName());
- })
- DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); })
- DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); })
- DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); })
-
- //--- Objective-C --------------------------------------------------------//
- DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); })
- DEF_ADD_DATA(ObjCPropertyRefExpr, {
- addData(S->isSuperReceiver());
- addData(S->isImplicitProperty());
- })
- DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); })
-
- //--- Miscellaneous Stmts ------------------------------------------------//
- DEF_ADD_DATA(CXXFoldExpr, {
- addData(S->isRightFold());
- addData(S->getOperator());
- })
- DEF_ADD_DATA(GenericSelectionExpr, {
- for (unsigned i = 0; i < S->getNumAssocs(); ++i) {
- addData(S->getAssocType(i));
- }
- })
- DEF_ADD_DATA(LambdaExpr, {
- for (const LambdaCapture &C : S->captures()) {
- addData(C.isPackExpansion());
- addData(C.getCaptureKind());
- if (C.capturesVariable())
- addData(C.getCapturedVar()->getType());
- }
- addData(S->isGenericLambda());
- addData(S->isMutable());
- })
- DEF_ADD_DATA(DeclStmt, {
- auto numDecls = std::distance(S->decl_begin(), S->decl_end());
- addData(static_cast<CloneDetector::DataPiece>(numDecls));
- for (const Decl *D : S->decls()) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- addData(VD->getType());
- }
- }
- })
- DEF_ADD_DATA(AsmStmt, {
- addData(S->isSimple());
- addData(S->isVolatile());
- addData(S->generateAsmString(Context));
- for (unsigned i = 0; i < S->getNumInputs(); ++i) {
- addData(S->getInputConstraint(i));
- }
- for (unsigned i = 0; i < S->getNumOutputs(); ++i) {
- addData(S->getOutputConstraint(i));
- }
- for (unsigned i = 0; i < S->getNumClobbers(); ++i) {
- addData(S->getClobber(i));
- }
- })
- DEF_ADD_DATA(AttributedStmt, {
- for (const Attr *A : S->getAttrs()) {
- addData(std::string(A->getSpelling()));
- }
- })
+// Type II clones ignore variable names and literals, so let's skip them.
+#define SKIP(CLASS) \
+ void Visit##CLASS(const CLASS *S) { \
+ ConstStmtVisitor<CloneTypeIIStmtDataCollector<T>>::Visit##CLASS(S); \
+ }
+ SKIP(DeclRefExpr)
+ SKIP(MemberExpr)
+ SKIP(IntegerLiteral)
+ SKIP(FloatingLiteral)
+ SKIP(StringLiteral)
+ SKIP(CXXBoolLiteralExpr)
+ SKIP(CharacterLiteral)
+#undef SKIP
};
} // end anonymous namespace
-namespace {
-/// Generates CloneSignatures for a set of statements and stores the results in
-/// a CloneDetector object.
-class CloneSignatureGenerator {
-
- CloneDetector &CD;
- ASTContext &Context;
-
- /// \brief Generates CloneSignatures for all statements in the given statement
- /// tree and stores them in the CloneDetector.
- ///
- /// \param S The root of the given statement tree.
- /// \param ParentMacroStack A string representing the macros that generated
- /// the parent statement or an empty string if no
- /// macros generated the parent statement.
- /// See getMacroStack() for generating such a string.
- /// \return The CloneSignature of the root statement.
- CloneDetector::CloneSignature
- generateSignatures(const Stmt *S, const std::string &ParentMacroStack) {
- // Create an empty signature that will be filled in this method.
- CloneDetector::CloneSignature Signature;
-
- llvm::MD5 Hash;
-
- // Collect all relevant data from S and hash it.
- StmtDataCollector<llvm::MD5>(S, Context, Hash);
-
- // Look up what macros expanded into the current statement.
- std::string StartMacroStack = getMacroStack(S->getLocStart(), Context);
- std::string EndMacroStack = getMacroStack(S->getLocEnd(), Context);
-
- // First, check if ParentMacroStack is not empty which means we are currently
- // dealing with a parent statement which was expanded from a macro.
- // If this parent statement was expanded from the same macros as this
- // statement, we reduce the initial complexity of this statement to zero.
- // This causes that a group of statements that were generated by a single
- // macro expansion will only increase the total complexity by one.
- // Note: This is not the final complexity of this statement as we still
- // add the complexity of the child statements to the complexity value.
- if (!ParentMacroStack.empty() && (StartMacroStack == ParentMacroStack &&
- EndMacroStack == ParentMacroStack)) {
- Signature.Complexity = 0;
- }
+static size_t createHash(llvm::MD5 &Hash) {
+ size_t HashCode;
- // 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);
+ // Create the final hash code for the current Stmt.
+ llvm::MD5::MD5Result HashResult;
+ Hash.final(HashResult);
- // 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;
+ // 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)));
- // 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);
-
- // 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)));
+ return HashCode;
+}
- // If the current statement is a CompoundStatement, we need to store the
- // signature for the generation of the sub-sequences.
- if (CS)
- ChildSignatures.push_back(ChildSignature);
+/// 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.
+///
+/// If the given Stmt is a CompoundStmt, this method will also generate
+/// hashes for all possible StmtSequences in the children of this Stmt.
+static size_t
+saveHash(const Stmt *S, const Decl *D,
+ std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash) {
+ llvm::MD5 Hash;
+ ASTContext &Context = D->getASTContext();
+
+ CloneTypeIIStmtDataCollector<llvm::MD5>(S, Context, Hash);
+
+ 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;
}
-
- // 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);
-
- // Create the final hash code for the current signature.
- llvm::MD5::MD5Result HashResult;
- Hash.final(HashResult);
-
- // 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)));
-
- // Save the signature for the current statement in the CloneDetector object.
- CD.add(StmtSequence(S, Context), Signature);
-
- return Signature;
+ size_t ChildHash = saveHash(Child, D, StmtsByHash);
+ Hash.update(
+ StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash)));
+ ChildHashes.push_back(ChildHash);
}
- /// \brief Adds all possible sub-sequences in the child array of the given
- /// CompoundStmt to the CloneDetector.
- /// \param CS The given CompoundStmt.
- /// \param ChildSignatures A list of calculated signatures for each child in
- /// the given CompoundStmt.
- void handleSubSequences(
- const CompoundStmt *CS,
- const std::vector<CloneDetector::CloneSignature> &ChildSignatures) {
-
- // FIXME: This function has quadratic runtime right now. Check if skipping
- // this function for too long CompoundStmts is an option.
-
- // The length of the sub-sequence. We don't need to handle sequences with
- // the length 1 as they are already handled in CollectData().
- for (unsigned Length = 2; Length <= CS->size(); ++Length) {
- // The start index in the body of the CompoundStmt. We increase the
- // position until the end of the sub-sequence reaches the end of the
- // CompoundStmt body.
- for (unsigned Pos = 0; Pos <= CS->size() - Length; ++Pos) {
- // Create an empty signature and add the signatures of all selected
- // child statements to it.
- CloneDetector::CloneSignature SubSignature;
- llvm::MD5 SubHash;
-
- for (unsigned i = Pos; i < Pos + Length; ++i) {
- SubSignature.Complexity += ChildSignatures[i].Complexity;
- size_t ChildHash = ChildSignatures[i].Hash;
-
- SubHash.update(StringRef(reinterpret_cast<char *>(&ChildHash),
- sizeof(ChildHash)));
+ if (CS) {
+ // If we're in a CompoundStmt, we hash all possible combinations of child
+ // statements to find clones in those subsequences.
+ // We first go through every possible starting position of a subsequence.
+ for (unsigned Pos = 0; Pos < CS->size(); ++Pos) {
+ // Then we try all possible lengths this subsequence could have and
+ // reuse the same hash object to make sure we only hash every child
+ // hash exactly once.
+ llvm::MD5 Hash;
+ for (unsigned Length = 1; Length <= CS->size() - Pos; ++Length) {
+ // Grab the current child hash and put it into our hash. We do
+ // -1 on the index because we start counting the length at 1.
+ size_t ChildHash = ChildHashes[Pos + Length - 1];
+ Hash.update(
+ StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash)));
+ // If we have at least two elements in our subsequence, we can start
+ // saving it.
+ if (Length > 1) {
+ llvm::MD5 SubHash = Hash;
+ StmtsByHash.push_back(std::make_pair(
+ createHash(SubHash), StmtSequence(CS, D, Pos, Pos + Length)));
}
-
- // Create the final hash code for the current signature.
- llvm::MD5::MD5Result HashResult;
- SubHash.final(HashResult);
-
- // Copy as much of the generated hash code to the signature's hash code.
- std::memcpy(&SubSignature.Hash, &HashResult,
- std::min(sizeof(SubSignature.Hash), sizeof(HashResult)));
-
- // Save the signature together with the information about what children
- // sequence we selected.
- CD.add(StmtSequence(CS, Context, Pos, Pos + Length), SubSignature);
}
}
}
-public:
- explicit CloneSignatureGenerator(CloneDetector &CD, ASTContext &Context)
- : CD(CD), Context(Context) {}
-
- /// \brief Generates signatures for all statements in the given function body.
- void consumeCodeBody(const Stmt *S) { generateSignatures(S, ""); }
-};
-} // end anonymous namespace
-
-void CloneDetector::analyzeCodeBody(const Decl *D) {
- assert(D);
- assert(D->hasBody());
- CloneSignatureGenerator Generator(*this, D->getASTContext());
- Generator.consumeCodeBody(D->getBody());
-}
-
-void CloneDetector::add(const StmtSequence &S,
- const CloneSignature &Signature) {
- Sequences.push_back(std::make_pair(Signature, S));
-}
-
-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;
+ size_t HashCode = createHash(Hash);
+ StmtsByHash.push_back(std::make_pair(HashCode, StmtSequence(S, D)));
+ return HashCode;
}
-} // 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,25 +314,25 @@ 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) {
- StmtDataCollector<FoldingSetNodeIDWrapper>(S, Sequence.getASTContext(),
- OutputData);
+ CloneTypeIIStmtDataCollector<FoldingSetNodeIDWrapper>(
+ S, Sequence.getASTContext(), OutputData);
for (const Stmt *Child : S->children()) {
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 +349,283 @@ 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 RecursiveCloneTypeIIHashConstraint::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) {
+ // 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;
+void RecursiveCloneTypeIIVerifyConstraint::constrain(
+ std::vector<CloneDetector::CloneGroup> &Sequences) {
+ CloneConstraint::splitCloneGroups(
+ Sequences, [](const StmtSequence &A, const StmtSequence &B) {
+ return areSequencesClones(A, B);
+ });
+}
- // 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;
+size_t MinComplexityConstraint::calculateStmtComplexity(
+ const StmtSequence &Seq, std::size_t Limit,
+ 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 MacroStack =
+ data_collection::getMacroStack(Seq.getStartLoc(), 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() && MacroStack == ParentMacroStack) {
+ Complexity = 0;
+ }
- // 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;
- }
+ // 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()), Limit, MacroStack);
+ if (Complexity >= Limit)
+ return Limit;
+ }
+ } else {
+ for (const Stmt *S : Seq.front()->children()) {
+ Complexity += calculateStmtComplexity(
+ StmtSequence(S, Seq.getContainingDecl()), Limit, MacroStack);
+ if (Complexity >= Limit)
+ return Limit;
+ }
+ }
+ return Complexity;
+}
- // Skip CloneSignatures that won't pass the complexity requirement.
- if (Signature.first.Complexity < MinGroupComplexity)
+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;
+ });
+}
+
+void CloneConstraint::splitCloneGroups(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ llvm::function_ref<bool(const StmtSequence &, const StmtSequence &)>
+ Compare) {
+ std::vector<CloneDetector::CloneGroup> Result;
+ for (auto &HashGroup : CloneGroups) {
+ // Contains all indexes in HashGroup that were already added to a
+ // CloneGroup.
+ std::vector<char> Indexes;
+ Indexes.resize(HashGroup.size());
+
+ for (unsigned i = 0; i < HashGroup.size(); ++i) {
+ // Skip indexes that are already part of a CloneGroup.
+ if (Indexes[i])
continue;
- Group.Sequences.push_back(Signature.second);
- }
+ // Pick the first unhandled StmtSequence and consider it as the
+ // beginning
+ // of a new CloneGroup for now.
+ // We don't add i to Indexes because we never iterate back.
+ StmtSequence Prototype = HashGroup[i];
+ CloneDetector::CloneGroup PotentialGroup = {Prototype};
+ ++Indexes[i];
+
+ // Check all following StmtSequences for clones.
+ for (unsigned j = i + 1; j < HashGroup.size(); ++j) {
+ // Skip indexes that are already part of a CloneGroup.
+ if (Indexes[j])
+ continue;
+
+ // If a following StmtSequence belongs to our CloneGroup, we add it.
+ const StmtSequence &Candidate = HashGroup[j];
+
+ if (!Compare(Prototype, Candidate))
+ continue;
+
+ PotentialGroup.push_back(Candidate);
+ // Make sure we never visit this StmtSequence again.
+ ++Indexes[j];
+ }
- // There is a chance that we haven't found more than two fitting
- // CloneSignature because not enough CloneSignatures passed the complexity
- // requirement. As a CloneGroup with less than two members makes no sense,
- // we ignore this CloneGroup and won't add it to the result.
- if (!Group.isValid())
- continue;
+ // Otherwise, add it to the result and continue searching for more
+ // groups.
+ Result.push_back(PotentialGroup);
+ }
- CloneGroups.push_back(Group);
+ assert(std::all_of(Indexes.begin(), Indexes.end(),
+ [](char c) { return c == 1; }));
}
+ CloneGroups = Result;
+}
- // Add every valid clone group that fulfills the complexity requirement.
- for (const CloneGroup &Group : CloneGroups) {
- createCloneGroups(Result, Group, CheckPatterns);
+void VariablePattern::addVariableOccurence(const VarDecl *VarDecl,
+ const Stmt *Mention) {
+ // First check if we already reference this variable
+ for (size_t KindIndex = 0; KindIndex < Variables.size(); ++KindIndex) {
+ if (Variables[KindIndex] == VarDecl) {
+ // If yes, add a new occurence that points to the existing entry in
+ // the Variables vector.
+ Occurences.emplace_back(KindIndex, Mention);
+ return;
+ }
}
+ // If this variable wasn't already referenced, add it to the list of
+ // referenced variables and add a occurence that points to this new entry.
+ Occurences.emplace_back(Variables.size(), Mention);
+ Variables.push_back(VarDecl);
+}
- std::vector<unsigned> IndexesToRemove;
-
- // Compare every group in the result with the rest. If one groups contains
- // another group, we only need to return the bigger group.
- // Note: This doesn't scale well, so if possible avoid calling any heavy
- // function from this loop to minimize the performance impact.
- for (unsigned i = 0; i < Result.size(); ++i) {
- for (unsigned j = 0; j < Result.size(); ++j) {
- // Don't compare a group with itself.
- if (i == j)
- continue;
+void VariablePattern::addVariables(const Stmt *S) {
+ // Sometimes we get a nullptr (such as from IfStmts which often have nullptr
+ // children). We skip such statements as they don't reference any
+ // variables.
+ if (!S)
+ return;
- if (containsGroup(Result[j], Result[i])) {
- IndexesToRemove.push_back(i);
- break;
- }
- }
+ // Check if S is a reference to a variable. If yes, add it to the pattern.
+ if (auto D = dyn_cast<DeclRefExpr>(S)) {
+ if (auto VD = dyn_cast<VarDecl>(D->getDecl()->getCanonicalDecl()))
+ addVariableOccurence(VD, D);
}
- // Erasing a list of indexes from the vector should be done with decreasing
- // indexes. As IndexesToRemove is constructed with increasing values, we just
- // reverse iterate over it to get the desired order.
- for (auto I = IndexesToRemove.rbegin(); I != IndexesToRemove.rend(); ++I) {
- Result.erase(Result.begin() + *I);
+ // Recursively check all children of the given statement.
+ for (const Stmt *Child : S->children()) {
+ addVariables(Child);
}
}
-void CloneDetector::findSuspiciousClones(
- std::vector<CloneDetector::SuspiciousClonePair> &Result,
- unsigned MinGroupComplexity) {
- std::vector<CloneGroup> Clones;
- // Reuse the normal search for clones but specify that the clone groups don't
- // need to have a common referenced variable pattern so that we can manually
- // search for the kind of pattern errors this function is supposed to find.
- findClones(Clones, MinGroupComplexity, false);
-
- for (const CloneGroup &Group : Clones) {
- for (unsigned i = 0; i < Group.Sequences.size(); ++i) {
- VariablePattern PatternA(Group.Sequences[i]);
-
- for (unsigned j = i + 1; j < Group.Sequences.size(); ++j) {
- VariablePattern PatternB(Group.Sequences[j]);
-
- CloneDetector::SuspiciousClonePair ClonePair;
- // For now, we only report clones which break the variable pattern just
- // once because multiple differences in a pattern are an indicator that
- // those differences are maybe intended (e.g. because it's actually
- // a different algorithm).
- // TODO: In very big clones even multiple variables can be unintended,
- // so replacing this number with a percentage could better handle such
- // cases. On the other hand it could increase the false-positive rate
- // for all clones if the percentage is too high.
- if (PatternA.countPatternDifferences(PatternB, &ClonePair) == 1) {
- Result.push_back(ClonePair);
- break;
- }
- }
- }
+unsigned VariablePattern::countPatternDifferences(
+ const VariablePattern &Other,
+ VariablePattern::SuspiciousClonePair *FirstMismatch) {
+ unsigned NumberOfDifferences = 0;
+
+ assert(Other.Occurences.size() == Occurences.size());
+ for (unsigned i = 0; i < Occurences.size(); ++i) {
+ auto ThisOccurence = Occurences[i];
+ auto OtherOccurence = Other.Occurences[i];
+ if (ThisOccurence.KindID == OtherOccurence.KindID)
+ continue;
+
+ ++NumberOfDifferences;
+
+ // If FirstMismatch is not a nullptr, we need to store information about
+ // the first difference between the two patterns.
+ if (FirstMismatch == nullptr)
+ continue;
+
+ // Only proceed if we just found the first difference as we only store
+ // information about the first difference.
+ if (NumberOfDifferences != 1)
+ continue;
+
+ const VarDecl *FirstSuggestion = nullptr;
+ // If there is a variable available in the list of referenced variables
+ // which wouldn't break the pattern if it is used in place of the
+ // current variable, we provide this variable as the suggested fix.
+ if (OtherOccurence.KindID < Variables.size())
+ FirstSuggestion = Variables[OtherOccurence.KindID];
+
+ // Store information about the first clone.
+ FirstMismatch->FirstCloneInfo =
+ VariablePattern::SuspiciousClonePair::SuspiciousCloneInfo(
+ Variables[ThisOccurence.KindID], ThisOccurence.Mention,
+ FirstSuggestion);
+
+ // Same as above but with the other clone. We do this for both clones as
+ // we don't know which clone is the one containing the unintended
+ // pattern error.
+ const VarDecl *SecondSuggestion = nullptr;
+ if (ThisOccurence.KindID < Other.Variables.size())
+ SecondSuggestion = Other.Variables[ThisOccurence.KindID];
+
+ // Store information about the second clone.
+ FirstMismatch->SecondCloneInfo =
+ VariablePattern::SuspiciousClonePair::SuspiciousCloneInfo(
+ Other.Variables[OtherOccurence.KindID], OtherOccurence.Mention,
+ SecondSuggestion);
+
+ // SuspiciousClonePair guarantees that the first clone always has a
+ // suggested variable associated with it. As we know that one of the two
+ // clones in the pair always has suggestion, we swap the two clones
+ // in case the first clone has no suggested variable which means that
+ // the second clone has a suggested variable and should be first.
+ if (!FirstMismatch->FirstCloneInfo.Suggestion)
+ std::swap(FirstMismatch->FirstCloneInfo, FirstMismatch->SecondCloneInfo);
+
+ // This ensures that we always have at least one suggestion in a pair.
+ assert(FirstMismatch->FirstCloneInfo.Suggestion);
}
+
+ return NumberOfDifferences;
}
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index f6fe78ac46..96edad0c30 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -22,7 +22,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
@@ -749,8 +749,7 @@ void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
// Special case for the std::move function.
// TODO: Make this more specific. (Deferred)
- if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" &&
- FunDecl->isInStdNamespace()) {
+ if (Call->isCallToStdMove()) {
copyInfo(Call->getArg(0), Call, CS_Consumed);
return;
}
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index cd73a62e69..4752c2b020 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -15,7 +15,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PostOrderIterator.h"
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index ed7193ecb4..dfaed26564 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -441,6 +441,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return Ctx.IntTy;
+ LLVM_FALLTHROUGH;
default:
return ArgType::Invalid();
}
@@ -465,8 +466,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsIntMax:
return ArgType(Ctx.getIntMaxType(), "intmax_t");
case LengthModifier::AsSizeT:
- // FIXME: How to get the corresponding signed version of size_t?
- return ArgType();
+ return ArgType(Ctx.getSignedSizeType(), "ssize_t");
case LengthModifier::AsInt3264:
return Ctx.getTargetInfo().getTriple().isArch64Bit()
? ArgType(Ctx.LongLongTy, "__int64")
@@ -505,9 +505,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
: ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
case LengthModifier::AsPtrDiff:
- // FIXME: How to get the corresponding unsigned
- // version of ptrdiff_t?
- return ArgType();
+ return ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t");
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
case LengthModifier::AsWide:
@@ -536,7 +534,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
- return ArgType(); // FIXME: ssize_t
+ return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
case LengthModifier::AsLongDouble:
@@ -654,6 +652,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
case BuiltinType::UInt128:
case BuiltinType::Int128:
case BuiltinType::Half:
+ case BuiltinType::Float16:
case BuiltinType::Float128:
// Various types which are non-trivial to correct.
return false;
diff --git a/lib/Analysis/PseudoConstantAnalysis.cpp b/lib/Analysis/PseudoConstantAnalysis.cpp
index 614f676fb1..83b545a7be 100644
--- a/lib/Analysis/PseudoConstantAnalysis.cpp
+++ b/lib/Analysis/PseudoConstantAnalysis.cpp
@@ -109,6 +109,7 @@ void PseudoConstantAnalysis::RunAnalysis() {
// Do not visit the children
continue;
+ LLVM_FALLTHROUGH;
}
case BO_AddAssign:
case BO_SubAssign:
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index a2f3203762..7e72795a47 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
@@ -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/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 3b93f1a57f..8398a4b82d 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -251,8 +251,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
- // FIXME: ssize_t.
- return ArgType();
+ return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
case LengthModifier::AsLongDouble:
@@ -292,8 +291,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsSizeT:
return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
case LengthModifier::AsPtrDiff:
- // FIXME: Unsigned version of ptrdiff_t?
- return ArgType();
+ return ArgType::PtrTo(
+ ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
case LengthModifier::AsLongDouble:
// GNU extension.
return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
@@ -341,6 +340,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
+ LLVM_FALLTHROUGH;
default:
return ArgType::Invalid();
}
@@ -357,6 +357,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
+ LLVM_FALLTHROUGH;
default:
return ArgType::Invalid();
}
@@ -384,7 +385,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
- return ArgType(); // FIXME: ssize_t
+ return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
case LengthModifier::AsLongDouble:
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 879a15c9c2..6a9c9a04c5 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -26,7 +26,7 @@
#include "clang/Analysis/Analyses/ThreadSafetyLogical.h"
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Basic/OperatorKinds.h"
@@ -1735,8 +1735,23 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
CapExprSet AssertLocks;
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
for (const auto &AssertLock : AssertLocks)
- Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
- AssertLock, LK_Shared, Loc, false, true),
+ Analyzer->addLock(FSet,
+ llvm::make_unique<LockableFactEntry>(
+ AssertLock, LK_Shared, Loc, false, true),
+ ClassifyDiagnostic(A));
+ break;
+ }
+
+ case attr::AssertCapability: {
+ AssertCapabilityAttr *A = cast<AssertCapabilityAttr>(At);
+ CapExprSet AssertLocks;
+ Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
+ for (const auto &AssertLock : AssertLocks)
+ Analyzer->addLock(FSet,
+ llvm::make_unique<LockableFactEntry>(
+ AssertLock,
+ A->isShared() ? LK_Shared : LK_Exclusive, Loc,
+ false, true),
ClassifyDiagnostic(A));
break;
}
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
index cbd5464c34..875f28c6e9 100644
--- a/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -19,7 +19,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
diff --git a/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp
index 2923f7e66a..83aa90435e 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/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index d5289fb9d4..5f11d8a2a3 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
#include "llvm/ADT/DenseMap.h"
@@ -440,16 +440,11 @@ static bool isPointerToConst(const QualType &QT) {
void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
// Classify arguments to std::move as used.
- if (CE->getNumArgs() == 1) {
- if (FunctionDecl *FD = CE->getDirectCallee()) {
- if (FD->isInStdNamespace() && FD->getIdentifier() &&
- FD->getIdentifier()->isStr("move")) {
- // RecordTypes are handled in SemaDeclCXX.cpp.
- if (!CE->getArg(0)->getType()->isRecordType())
- classify(CE->getArg(0), Use);
- return;
- }
- }
+ if (CE->isCallToStdMove()) {
+ // RecordTypes are handled in SemaDeclCXX.cpp.
+ if (!CE->getArg(0)->getType()->isRecordType())
+ classify(CE->getArg(0), Use);
+ return;
}
// If a value is passed by const pointer or by const reference to a function,
diff --git a/lib/Basic/Attributes.cpp b/lib/Basic/Attributes.cpp
index c215366fc3..b7570d03c8 100644
--- a/lib/Basic/Attributes.cpp
+++ b/lib/Basic/Attributes.cpp
@@ -1,4 +1,5 @@
#include "clang/Basic/Attributes.h"
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -15,3 +16,13 @@ int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
return 0;
}
+
+const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
+ switch (Rule) {
+#define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \
+ case attr::NAME: \
+ return SPELLING;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+ llvm_unreachable("Invalid subject match rule");
+}
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 28695d649a..ed7f87c9b9 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -69,9 +69,15 @@ bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo,
bool MSModeUnsupported =
!LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG);
bool ObjCUnsupported = !LangOpts.ObjC1 && BuiltinInfo.Langs == OBJC_LANG;
- bool OclCUnsupported = LangOpts.OpenCLVersion != 200 &&
- BuiltinInfo.Langs == OCLC20_LANG;
+ bool OclC1Unsupported = (LangOpts.OpenCLVersion / 100) != 1 &&
+ (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES ) == OCLC1X_LANG;
+ bool OclC2Unsupported = LangOpts.OpenCLVersion != 200 &&
+ (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES) == OCLC20_LANG;
+ bool OclCUnsupported = !LangOpts.OpenCL &&
+ (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES);
+ bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG;
return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported &&
+ !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported &&
!GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported;
}
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 8929ec30ff..d0c9b902f6 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -4,24 +4,6 @@ set(LLVM_LINK_COMPONENTS
Support
)
-# Figure out if we can track VC revisions.
-function(find_first_existing_file out_var)
- foreach(file ${ARGN})
- if(EXISTS "${file}")
- set(${out_var} "${file}" PARENT_SCOPE)
- return()
- endif()
- endforeach()
-endfunction()
-
-macro(find_first_existing_vc_file out_var path)
- find_first_existing_file(${out_var}
- "${path}/.git/logs/HEAD" # Git
- "${path}/.svn/wc.db" # SVN 1.7
- "${path}/.svn/entries" # SVN 1.6
- )
-endmacro()
-
find_first_existing_vc_file(llvm_vc "${LLVM_MAIN_SRC_DIR}")
find_first_existing_vc_file(clang_vc "${CLANG_SOURCE_DIR}")
@@ -74,21 +56,46 @@ add_clang_library(clangBasic
FileSystemStatCache.cpp
IdentifierTable.cpp
LangOptions.cpp
+ MemoryBufferCache.cpp
Module.cpp
ObjCRuntime.cpp
OpenMPKinds.cpp
OperatorPrecedence.cpp
SanitizerBlacklist.cpp
+ SanitizerSpecialCaseList.cpp
Sanitizers.cpp
SourceLocation.cpp
SourceManager.cpp
TargetInfo.cpp
Targets.cpp
+ Targets/AArch64.cpp
+ Targets/AMDGPU.cpp
+ Targets/ARM.cpp
+ Targets/AVR.cpp
+ Targets/BPF.cpp
+ Targets/Hexagon.cpp
+ Targets/Lanai.cpp
+ Targets/Le64.cpp
+ Targets/MSP430.cpp
+ Targets/Mips.cpp
+ Targets/NVPTX.cpp
+ Targets/Nios2.cpp
+ Targets/OSTargets.cpp
+ Targets/PNaCl.cpp
+ Targets/PPC.cpp
+ Targets/SPIR.cpp
+ Targets/Sparc.cpp
+ Targets/SystemZ.cpp
+ Targets/TCE.cpp
+ Targets/WebAssembly.cpp
+ Targets/X86.cpp
+ Targets/XCore.cpp
TokenKinds.cpp
Version.cpp
VersionTuple.cpp
VirtualFileSystem.cpp
Warnings.cpp
+ XRayLists.cpp
${version_inc}
)
diff --git a/lib/Basic/Cuda.cpp b/lib/Basic/Cuda.cpp
index 3264078b98..58b99a3b58 100644
--- a/lib/Basic/Cuda.cpp
+++ b/lib/Basic/Cuda.cpp
@@ -16,6 +16,8 @@ const char *CudaVersionToString(CudaVersion V) {
return "7.5";
case CudaVersion::CUDA_80:
return "8.0";
+ case CudaVersion::CUDA_90:
+ return "9.0";
}
llvm_unreachable("invalid enum");
}
@@ -48,6 +50,8 @@ const char *CudaArchToString(CudaArch A) {
return "sm_61";
case CudaArch::SM_62:
return "sm_62";
+ case CudaArch::SM_70:
+ return "sm_70";
}
llvm_unreachable("invalid enum");
}
@@ -66,6 +70,7 @@ CudaArch StringToCudaArch(llvm::StringRef S) {
.Case("sm_60", CudaArch::SM_60)
.Case("sm_61", CudaArch::SM_61)
.Case("sm_62", CudaArch::SM_62)
+ .Case("sm_70", CudaArch::SM_70)
.Default(CudaArch::UNKNOWN);
}
@@ -95,6 +100,8 @@ const char *CudaVirtualArchToString(CudaVirtualArch A) {
return "compute_61";
case CudaVirtualArch::COMPUTE_62:
return "compute_62";
+ case CudaVirtualArch::COMPUTE_70:
+ return "compute_70";
}
llvm_unreachable("invalid enum");
}
@@ -112,6 +119,7 @@ CudaVirtualArch StringToCudaVirtualArch(llvm::StringRef S) {
.Case("compute_60", CudaVirtualArch::COMPUTE_60)
.Case("compute_61", CudaVirtualArch::COMPUTE_61)
.Case("compute_62", CudaVirtualArch::COMPUTE_62)
+ .Case("compute_70", CudaVirtualArch::COMPUTE_70)
.Default(CudaVirtualArch::UNKNOWN);
}
@@ -142,6 +150,8 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A) {
return CudaVirtualArch::COMPUTE_61;
case CudaArch::SM_62:
return CudaVirtualArch::COMPUTE_62;
+ case CudaArch::SM_70:
+ return CudaVirtualArch::COMPUTE_70;
}
llvm_unreachable("invalid enum");
}
@@ -164,8 +174,22 @@ CudaVersion MinVersionForCudaArch(CudaArch A) {
case CudaArch::SM_61:
case CudaArch::SM_62:
return CudaVersion::CUDA_80;
+ case CudaArch::SM_70:
+ return CudaVersion::CUDA_90;
}
llvm_unreachable("invalid enum");
}
+CudaVersion MaxVersionForCudaArch(CudaArch A) {
+ switch (A) {
+ case CudaArch::UNKNOWN:
+ return CudaVersion::UNKNOWN;
+ case CudaArch::SM_20:
+ case CudaArch::SM_21:
+ return CudaVersion::CUDA_80;
+ default:
+ return CudaVersion::LATEST;
+ }
+}
+
} // namespace clang
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 0c27ae4638..47f6a139b1 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -11,8 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/DiagnosticError.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -67,18 +68,12 @@ DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,
ArgToStringCookie = nullptr;
AllExtensionsSilenced = 0;
- IgnoreAllWarnings = false;
- WarningsAsErrors = false;
- EnableAllWarnings = false;
- ErrorsAsFatal = false;
- FatalsAsError = false;
- SuppressSystemWarnings = false;
+ SuppressAfterFatalError = true;
SuppressAllDiagnostics = false;
ElideType = true;
PrintTemplateTree = false;
ShowColors = false;
ShowOverloads = Ovl_All;
- ExtBehavior = diag::Severity::Ignored;
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
@@ -152,10 +147,9 @@ void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
}
void DiagnosticsEngine::ReportDelayed() {
- Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
+ unsigned ID = DelayedDiagID;
DelayedDiagID = 0;
- DelayedDiagArg1.clear();
- DelayedDiagArg2.clear();
+ Report(ID) << DelayedDiagArg1 << DelayedDiagArg2;
}
void DiagnosticsEngine::DiagStateMap::appendFirst(
@@ -258,13 +252,17 @@ void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
// 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 ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&
@@ -339,8 +337,8 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
diag::Severity::Fatal);
- // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
- // potentially downgrade anything already mapped to be an error.
+ // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
+ // and potentially downgrade anything already mapped to be a fatal error.
// Get the diagnostics in this group.
SmallVector<diag::kind, 8> GroupDiags;
@@ -422,11 +420,10 @@ bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) {
}
// Clear out the current diagnostic object.
- unsigned DiagID = CurDiagID;
Clear();
// If there was a delayed diagnostic, emit it now.
- if (!Force && DelayedDiagID && DelayedDiagID != DiagID)
+ if (!Force && DelayedDiagID)
ReportDelayed();
return Emitted;
@@ -1054,3 +1051,5 @@ PartialDiagnostic::StorageAllocator::~StorageAllocator() {
llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
"A partial is on the lam");
}
+
+char DiagnosticError::ID;
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index e0580af45b..4f59e550ba 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -43,7 +43,7 @@ struct StaticDiagInfoRec {
unsigned SFINAE : 2;
unsigned WarnNoWerror : 1;
unsigned WarnShowInSystemHeader : 1;
- unsigned Category : 5;
+ unsigned Category : 6;
uint16_t OptionGroupIndex;
@@ -68,6 +68,30 @@ struct StaticDiagInfoRec {
}
};
+#define STRINGIFY_NAME(NAME) #NAME
+#define VALIDATE_DIAG_SIZE(NAME) \
+ static_assert( \
+ static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
+ static_cast<unsigned>(diag::DIAG_START_##NAME) + \
+ static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
+ STRINGIFY_NAME( \
+ DIAG_SIZE_##NAME) " is insufficient to contain all " \
+ "diagnostics, it may need to be made larger in " \
+ "DiagnosticIDs.h.");
+VALIDATE_DIAG_SIZE(COMMON)
+VALIDATE_DIAG_SIZE(DRIVER)
+VALIDATE_DIAG_SIZE(FRONTEND)
+VALIDATE_DIAG_SIZE(SERIALIZATION)
+VALIDATE_DIAG_SIZE(LEX)
+VALIDATE_DIAG_SIZE(PARSE)
+VALIDATE_DIAG_SIZE(AST)
+VALIDATE_DIAG_SIZE(COMMENT)
+VALIDATE_DIAG_SIZE(SEMA)
+VALIDATE_DIAG_SIZE(ANALYSIS)
+VALIDATE_DIAG_SIZE(REFACTORING)
+#undef VALIDATE_DIAG_SIZE
+#undef STRINGIFY_NAME
+
} // namespace anonymous
static const StaticDiagInfoRec StaticDiagInfo[] = {
@@ -86,8 +110,10 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticCommentKinds.inc"
+#include "clang/Basic/DiagnosticCrossTUKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
+#include "clang/Basic/DiagnosticRefactoringKinds.inc"
#undef DIAG
};
@@ -96,18 +122,6 @@ static const unsigned StaticDiagInfoSize = llvm::array_lengthof(StaticDiagInfo);
/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
/// or null if the ID is invalid.
static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
- // If assertions are enabled, verify that the StaticDiagInfo array is sorted.
-#ifndef NDEBUG
- static bool IsFirst = true; // So the check is only performed on first call.
- if (IsFirst) {
- assert(std::is_sorted(std::begin(StaticDiagInfo),
- std::end(StaticDiagInfo)) &&
- "Diag ID conflict, the enums at the start of clang::diag (in "
- "DiagnosticIDs.h) probably need to be increased");
- IsFirst = false;
- }
-#endif
-
// Out of bounds diag. Can't be in the table.
using namespace diag;
if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
@@ -135,8 +149,10 @@ CATEGORY(LEX, SERIALIZATION)
CATEGORY(PARSE, LEX)
CATEGORY(AST, PARSE)
CATEGORY(COMMENT, AST)
-CATEGORY(SEMA, COMMENT)
+CATEGORY(CROSSTU, COMMENT)
+CATEGORY(SEMA, CROSSTU)
CATEGORY(ANALYSIS, SEMA)
+CATEGORY(REFACTORING, ANALYSIS)
#undef CATEGORY
// Avoid out of bounds reads.
@@ -420,7 +436,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
Result = Mapping.getSeverity();
// Upgrade ignored diagnostics if -Weverything is enabled.
- if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored &&
+ if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
!Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
Result = diag::Severity::Warning;
@@ -435,7 +451,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// For extension diagnostics that haven't been explicitly mapped, check if we
// should upgrade the diagnostic.
if (IsExtensionDiag && !Mapping.isUser())
- Result = std::max(Result, Diag.ExtBehavior);
+ Result = std::max(Result, State->ExtBehavior);
// At this point, ignored errors can no longer be upgraded.
if (Result == diag::Severity::Ignored)
@@ -443,28 +459,24 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// Honor -w, which is lower in priority than pedantic-errors, but higher than
// -Werror.
- if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings)
+ // FIXME: Under GCC, this also suppresses warnings that have been mapped to
+ // errors by -W flags and #pragma diagnostic.
+ if (Result == diag::Severity::Warning && State->IgnoreAllWarnings)
return diag::Severity::Ignored;
// If -Werror is enabled, map warnings to errors unless explicitly disabled.
if (Result == diag::Severity::Warning) {
- if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError())
+ if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
Result = diag::Severity::Error;
}
// If -Wfatal-errors is enabled, map errors to fatal unless explicity
// disabled.
if (Result == diag::Severity::Error) {
- if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
+ if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
Result = diag::Severity::Fatal;
}
- // If explicitly requested, map fatal errors to errors.
- if (Result == diag::Severity::Fatal) {
- if (Diag.FatalsAsError)
- Result = diag::Severity::Error;
- }
-
// Custom diagnostics always are emitted in system headers.
bool ShowInSystemHeader =
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
@@ -472,7 +484,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// If we are in a system header, we ignore it. We look at the diagnostic class
// because we also want to ignore extensions and warnings in -Werror and
// -pedantic-errors modes, which *map* warnings/extensions to errors.
- if (Diag.SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
+ if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
Diag.getSourceManager().isInSystemHeader(
Diag.getSourceManager().getExpansionLoc(Loc)))
return diag::Severity::Ignored;
@@ -514,6 +526,18 @@ StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
return StringRef();
}
+std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
+ std::vector<std::string> Res;
+ for (size_t I = 1; DiagGroupNames[I] != '\0';) {
+ std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
+ I += DiagGroupNames[I] + 1;
+ Res.push_back("-W" + Diag);
+ Res.push_back("-Wno-" + Diag);
+ }
+
+ return Res;
+}
+
/// Return \c true if any diagnostics were found in this group, even if they
/// were filtered out due to having the wrong flavor.
static bool getDiagnosticsInGroup(diag::Flavor Flavor,
@@ -632,7 +656,7 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
// If a fatal error has already been emitted, silence all subsequent
// diagnostics.
- if (Diag.FatalErrorOccurred) {
+ if (Diag.FatalErrorOccurred && Diag.SuppressAfterFatalError) {
if (DiagLevel >= DiagnosticIDs::Error &&
Diag.Client->IncludeInDiagnosticCounts()) {
++Diag.NumErrors;
@@ -670,6 +694,10 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
}
}
+ // Make sure we set FatalErrorOccurred to ensure that the notes from the
+ // diagnostic that caused `fatal_too_many_errors` won't be emitted.
+ if (Diag.CurDiagID == diag::fatal_too_many_errors)
+ Diag.FatalErrorOccurred = true;
// Finally, report it.
EmitDiag(Diag, DiagLevel);
return true;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 50050d0a51..a3e226d6cc 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;
}
@@ -407,7 +408,7 @@ bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const {
bool Changed = FixupRelativePath(Path);
if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
- llvm::sys::fs::make_absolute(Path);
+ FS->makeAbsolute(Path);
Changed = true;
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 5caa8a6fb2..fe7829ec50 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -114,7 +114,9 @@ namespace {
KEYZVECTOR = 0x40000,
KEYCOROUTINES = 0x80000,
KEYMODULES = 0x100000,
- KEYALL = (0x1fffff & ~KEYNOMS18 &
+ KEYCXX2A = 0x200000,
+ KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX2A,
+ KEYALL = (0x3fffff & ~KEYNOMS18 &
~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude.
};
@@ -134,6 +136,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
if (Flags == KEYALL) return KS_Enabled;
if (LangOpts.CPlusPlus && (Flags & KEYCXX)) return KS_Enabled;
if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled;
+ if (LangOpts.CPlusPlus2a && (Flags & KEYCXX2A)) return KS_Enabled;
if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled;
if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension;
if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension;
@@ -152,7 +155,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled;
if (LangOpts.CoroutinesTS && (Flags & KEYCOROUTINES)) return KS_Enabled;
if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled;
- if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future;
+ if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future;
return KS_Disabled;
}
@@ -244,7 +247,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 +257,20 @@ 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;
+ LangOptsNoCPP.CPlusPlus2a = 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
@@ -538,6 +555,7 @@ ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
case 's':
if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
if (startsWithWord(name, "standard")) return OIT_Singleton;
+ break;
case 'i':
if (startsWithWord(name, "init")) return OIT_Init;
default:
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index ff10a773a9..db81507aa2 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -29,10 +29,10 @@ void LangOptions::resetNonModularOptions() {
Name = Default;
#include "clang/Basic/LangOptions.def"
- // FIXME: This should not be reset; modules can be different with different
- // sanitizer options (this affects __has_feature(address_sanitizer) etc).
- Sanitize.clear();
+ // These options do not affect AST generation.
SanitizerBlacklistFiles.clear();
+ XRayAlwaysInstrumentFiles.clear();
+ XRayNeverInstrumentFiles.clear();
CurrentModule.clear();
IsHeaderFile = false;
diff --git a/lib/Basic/MemoryBufferCache.cpp b/lib/Basic/MemoryBufferCache.cpp
new file mode 100644
index 0000000000..c1fc571ec9
--- /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 ad814fda9a..621b1b23d7 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Module.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
@@ -33,7 +34,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false), ConfigMacrosExhaustive(false),
- NoUndeclaredIncludes(false), WithCodegen(false), NameVisibility(Hidden) {
+ NoUndeclaredIncludes(false), NameVisibility(Hidden) {
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
@@ -64,6 +65,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
bool HasFeature = llvm::StringSwitch<bool>(Feature)
.Case("altivec", LangOpts.AltiVec)
.Case("blocks", LangOpts.Blocks)
+ .Case("coroutines", LangOpts.CoroutinesTS)
.Case("cplusplus", LangOpts.CPlusPlus)
.Case("cplusplus11", LangOpts.CPlusPlus11)
.Case("freestanding", LangOpts.Freestanding)
@@ -124,7 +126,36 @@ const Module *Module::getTopLevelModule() const {
return Result;
}
-std::string Module::getFullModuleName() const {
+static StringRef getModuleNameFromComponent(
+ const std::pair<std::string, SourceLocation> &IdComponent) {
+ return IdComponent.first;
+}
+static StringRef getModuleNameFromComponent(StringRef R) { return R; }
+
+template<typename InputIter>
+static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End,
+ bool AllowStringLiterals = true) {
+ for (InputIter It = Begin; It != End; ++It) {
+ if (It != Begin)
+ OS << ".";
+
+ StringRef Name = getModuleNameFromComponent(*It);
+ if (!AllowStringLiterals || isValidIdentifier(Name))
+ OS << Name;
+ else {
+ OS << '"';
+ OS.write_escaped(Name);
+ OS << '"';
+ }
+ }
+}
+
+template<typename Container>
+static void printModuleId(raw_ostream &OS, const Container &C) {
+ return printModuleId(OS, C.begin(), C.end());
+}
+
+std::string Module::getFullModuleName(bool AllowStringLiterals) const {
SmallVector<StringRef, 2> Names;
// Build up the set of module names (from innermost to outermost).
@@ -132,15 +163,11 @@ std::string Module::getFullModuleName() const {
Names.push_back(M->Name);
std::string Result;
- for (SmallVectorImpl<StringRef>::reverse_iterator I = Names.rbegin(),
- IEnd = Names.rend();
- I != IEnd; ++I) {
- if (!Result.empty())
- Result += '.';
-
- Result += *I;
- }
-
+
+ llvm::raw_string_ostream Out(Result);
+ printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals);
+ Out.flush();
+
return Result;
}
@@ -239,14 +266,6 @@ Module *Module::findSubmodule(StringRef Name) const {
return SubModules[Pos->getValue()];
}
-static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
- for (unsigned I = 0, N = Id.size(); I != N; ++I) {
- if (I)
- OS << ".";
- OS << Id[I].first;
- }
-}
-
void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
// All non-explicit submodules are exported.
for (std::vector<Module *>::const_iterator I = SubModules.begin(),
@@ -333,7 +352,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "framework ";
if (IsExplicit)
OS << "explicit ";
- OS << "module " << Name;
+ OS << "module ";
+ printModuleId(OS, &Name, &Name + 1);
if (IsSystem || IsExternC) {
OS.indent(Indent + 2);
@@ -393,14 +413,38 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
{"exclude ", HK_Excluded}};
for (auto &K : Kinds) {
+ assert(&K == &Kinds[K.Kind] && "kinds in wrong order");
for (auto &H : Headers[K.Kind]) {
OS.indent(Indent + 2);
OS << K.Prefix << "header \"";
OS.write_escaped(H.NameAsWritten);
- OS << "\"\n";
+ OS << "\" { size " << H.Entry->getSize()
+ << " mtime " << H.Entry->getModificationTime() << " }\n";
+ }
+ }
+ for (auto *Unresolved : {&UnresolvedHeaders, &MissingHeaders}) {
+ for (auto &U : *Unresolved) {
+ OS.indent(Indent + 2);
+ OS << Kinds[U.Kind].Prefix << "header \"";
+ OS.write_escaped(U.FileName);
+ OS << "\"";
+ if (U.Size || U.ModTime) {
+ OS << " {";
+ if (U.Size)
+ OS << " size " << *U.Size;
+ if (U.ModTime)
+ OS << " mtime " << *U.ModTime;
+ OS << " }";
+ }
+ OS << "\n";
}
}
+ if (!ExportAsModule.empty()) {
+ OS.indent(Indent + 2);
+ OS << "export_as" << ExportAsModule << "\n";
+ }
+
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI)
// Print inferred subframework modules so that we don't need to re-infer
@@ -414,7 +458,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.indent(Indent + 2);
OS << "export ";
if (Module *Restriction = Exports[I].getPointer()) {
- OS << Restriction->getFullModuleName();
+ OS << Restriction->getFullModuleName(true);
if (Exports[I].getInt())
OS << ".*";
} else {
@@ -435,7 +479,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "use ";
- OS << DirectUses[I]->getFullModuleName();
+ OS << DirectUses[I]->getFullModuleName(true);
OS << "\n";
}
@@ -468,7 +512,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "conflict ";
- OS << Conflicts[I].Other->getFullModuleName();
+ OS << Conflicts[I].Other->getFullModuleName(true);
OS << ", \"";
OS.write_escaped(Conflicts[I].Message);
OS << "\"\n";
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 5a8bb61eaa..b5f66e038b 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -138,6 +138,8 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
@@ -277,6 +279,8 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
@@ -710,6 +714,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_taskgroup:
+ switch (CKind) {
+#define OPENMP_TASKGROUP_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_unknown:
@@ -719,7 +733,6 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
- case OMPD_taskgroup:
case OMPD_cancellation_point:
case OMPD_declare_reduction:
break;
@@ -840,7 +853,8 @@ bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) {
bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) {
return Kind == OMPC_private || Kind == OMPC_firstprivate ||
Kind == OMPC_lastprivate || Kind == OMPC_linear ||
- Kind == OMPC_reduction; // TODO add next clauses like 'reduction'.
+ Kind == OMPC_reduction || Kind == OMPC_task_reduction ||
+ Kind == OMPC_in_reduction; // TODO add next clauses like 'reduction'.
}
bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) {
@@ -854,14 +868,10 @@ bool clang::isOpenMPTaskingDirective(OpenMPDirectiveKind Kind) {
bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) {
return Kind == OMPD_distribute_parallel_for ||
Kind == OMPD_distribute_parallel_for_simd ||
- Kind == OMPD_distribute_simd || Kind == OMPD_teams_distribute ||
- Kind == OMPD_teams_distribute_simd ||
Kind == OMPD_teams_distribute_parallel_for_simd ||
Kind == OMPD_teams_distribute_parallel_for ||
- Kind == OMPD_target_teams_distribute ||
Kind == OMPD_target_teams_distribute_parallel_for ||
- Kind == OMPD_target_teams_distribute_parallel_for_simd ||
- Kind == OMPD_target_teams_distribute_simd;
+ Kind == OMPD_target_teams_distribute_parallel_for_simd;
}
void clang::getOpenMPCaptureRegions(
@@ -880,6 +890,9 @@ void clang::getOpenMPCaptureRegions(
CaptureRegions.push_back(OMPD_target);
CaptureRegions.push_back(OMPD_teams);
break;
+ case OMPD_teams_distribute:
+ CaptureRegions.push_back(OMPD_teams);
+ break;
case OMPD_teams:
case OMPD_simd:
case OMPD_for:
@@ -903,7 +916,6 @@ void clang::getOpenMPCaptureRegions(
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:
diff --git a/lib/Basic/SanitizerBlacklist.cpp b/lib/Basic/SanitizerBlacklist.cpp
index de78c94bc1..199ded1f31 100644
--- a/lib/Basic/SanitizerBlacklist.cpp
+++ b/lib/Basic/SanitizerBlacklist.cpp
@@ -17,30 +17,35 @@ using namespace clang;
SanitizerBlacklist::SanitizerBlacklist(
const std::vector<std::string> &BlacklistPaths, SourceManager &SM)
- : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}
+ : SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}
-bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName,
+bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask,
+ StringRef GlobalName,
StringRef Category) const {
- return SCL->inSection("global", GlobalName, Category);
+ return SSCL->inSection(Mask, "global", GlobalName, Category);
}
-bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName,
+bool SanitizerBlacklist::isBlacklistedType(SanitizerMask Mask,
+ StringRef MangledTypeName,
StringRef Category) const {
- return SCL->inSection("type", MangledTypeName, Category);
+ return SSCL->inSection(Mask, "type", MangledTypeName, Category);
}
-bool SanitizerBlacklist::isBlacklistedFunction(StringRef FunctionName) const {
- return SCL->inSection("fun", FunctionName);
+bool SanitizerBlacklist::isBlacklistedFunction(SanitizerMask Mask,
+ StringRef FunctionName) const {
+ return SSCL->inSection(Mask, "fun", FunctionName);
}
-bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName,
+bool SanitizerBlacklist::isBlacklistedFile(SanitizerMask Mask,
+ StringRef FileName,
StringRef Category) const {
- return SCL->inSection("src", FileName, Category);
+ return SSCL->inSection(Mask, "src", FileName, Category);
}
-bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc,
+bool SanitizerBlacklist::isBlacklistedLocation(SanitizerMask Mask,
+ SourceLocation Loc,
StringRef Category) const {
return Loc.isValid() &&
- isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category);
+ isBlacklistedFile(Mask, SM.getFilename(SM.getFileLoc(Loc)), Category);
}
diff --git a/lib/Basic/SanitizerSpecialCaseList.cpp b/lib/Basic/SanitizerSpecialCaseList.cpp
new file mode 100644
index 0000000000..4dd52ee870
--- /dev/null
+++ b/lib/Basic/SanitizerSpecialCaseList.cpp
@@ -0,0 +1,64 @@
+//===--- SanitizerSpecialCaseList.cpp - SCL for sanitizers ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// An extension of SpecialCaseList to allowing querying sections by
+// SanitizerMask.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/SanitizerSpecialCaseList.h"
+
+using namespace clang;
+
+std::unique_ptr<SanitizerSpecialCaseList>
+SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths,
+ std::string &Error) {
+ std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL(
+ new SanitizerSpecialCaseList());
+ if (SSCL->createInternal(Paths, Error)) {
+ SSCL->createSanitizerSections();
+ return SSCL;
+ }
+ return nullptr;
+}
+
+std::unique_ptr<SanitizerSpecialCaseList>
+SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
+ std::string Error;
+ if (auto SSCL = create(Paths, Error))
+ return SSCL;
+ llvm::report_fatal_error(Error);
+}
+
+void SanitizerSpecialCaseList::createSanitizerSections() {
+ for (auto &S : Sections) {
+ SanitizerMask Mask = 0;
+
+#define SANITIZER(NAME, ID) \
+ if (S.SectionMatcher->match(NAME)) \
+ Mask |= SanitizerKind::ID;
+#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID)
+
+#include "clang/Basic/Sanitizers.def"
+#undef SANITIZER
+#undef SANITIZER_GROUP
+
+ SanitizerSections.emplace_back(Mask, S.Entries);
+ }
+}
+
+bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix,
+ StringRef Query,
+ StringRef Category) const {
+ for (auto &S : SanitizerSections)
+ if ((S.Mask & Mask) &&
+ SpecialCaseList::inSection(S.Entries, Prefix, Query, Category))
+ return true;
+
+ return false;
+}
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index a58d0465a6..89ddbc946a 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -92,6 +92,76 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const {
return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
}
+FullSourceLoc FullSourceLoc::getFileLoc() const {
+ assert(isValid());
+ return FullSourceLoc(SrcMgr->getFileLoc(*this), *SrcMgr);
+}
+
+std::pair<FullSourceLoc, FullSourceLoc>
+FullSourceLoc::getImmediateExpansionRange() const {
+ assert(isValid());
+ std::pair<SourceLocation, SourceLocation> Range =
+ SrcMgr->getImmediateExpansionRange(*this);
+ return std::make_pair(FullSourceLoc(Range.first, *SrcMgr),
+ FullSourceLoc(Range.second, *SrcMgr));
+}
+
+PresumedLoc FullSourceLoc::getPresumedLoc(bool UseLineDirectives) const {
+ if (!isValid())
+ return PresumedLoc();
+
+ return SrcMgr->getPresumedLoc(*this, UseLineDirectives);
+}
+
+bool FullSourceLoc::isMacroArgExpansion(FullSourceLoc *StartLoc) const {
+ assert(isValid());
+ return SrcMgr->isMacroArgExpansion(*this, StartLoc);
+}
+
+FullSourceLoc FullSourceLoc::getImmediateMacroCallerLoc() const {
+ assert(isValid());
+ return FullSourceLoc(SrcMgr->getImmediateMacroCallerLoc(*this), *SrcMgr);
+}
+
+std::pair<FullSourceLoc, StringRef> FullSourceLoc::getModuleImportLoc() const {
+ if (!isValid())
+ return std::make_pair(FullSourceLoc(), StringRef());
+
+ std::pair<SourceLocation, StringRef> ImportLoc =
+ SrcMgr->getModuleImportLoc(*this);
+ return std::make_pair(FullSourceLoc(ImportLoc.first, *SrcMgr),
+ ImportLoc.second);
+}
+
+unsigned FullSourceLoc::getFileOffset() const {
+ assert(isValid());
+ return SrcMgr->getFileOffset(*this);
+}
+
+unsigned FullSourceLoc::getLineNumber(bool *Invalid) const {
+ assert(isValid());
+ return SrcMgr->getLineNumber(getFileID(), getFileOffset(), Invalid);
+}
+
+unsigned FullSourceLoc::getColumnNumber(bool *Invalid) const {
+ assert(isValid());
+ return SrcMgr->getColumnNumber(getFileID(), getFileOffset(), Invalid);
+}
+
+std::pair<FullSourceLoc, FullSourceLoc>
+FullSourceLoc::getExpansionRange() const {
+ assert(isValid());
+ std::pair<SourceLocation, SourceLocation> Range =
+ SrcMgr->getExpansionRange(*this);
+ return std::make_pair(FullSourceLoc(Range.first, *SrcMgr),
+ FullSourceLoc(Range.second, *SrcMgr));
+}
+
+const FileEntry *FullSourceLoc::getFileEntry() const {
+ assert(isValid());
+ return SrcMgr->getFileEntryForID(getFileID());
+}
+
unsigned FullSourceLoc::getExpansionLineNumber(bool *Invalid) const {
assert(isValid());
return SrcMgr->getExpansionLineNumber(*this, Invalid);
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 380ca373e6..620f05c637 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -73,11 +73,11 @@ void ContentCache::replaceBuffer(llvm::MemoryBuffer *B, bool DoNotFree) {
Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
return;
}
-
+
if (shouldFreeBuffer())
delete Buffer.getPointer();
Buffer.setPointer(B);
- Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
+ Buffer.setInt((B && DoNotFree) ? DoNotFreeFlag : 0);
}
llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
@@ -183,48 +183,22 @@ unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
return IterBool.first->second;
}
-/// AddLineNote - Add a line note to the line table that indicates that there
-/// is a \#line at the specified FID/Offset location which changes the presumed
-/// location to LineNo/FilenameID.
-void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
- unsigned LineNo, int FilenameID) {
- std::vector<LineEntry> &Entries = LineEntries[FID];
-
- assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
- "Adding line entries out of order!");
-
- SrcMgr::CharacteristicKind Kind = SrcMgr::C_User;
- unsigned IncludeOffset = 0;
-
- if (!Entries.empty()) {
- // If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember
- // that we are still in "foo.h".
- if (FilenameID == -1)
- FilenameID = Entries.back().FilenameID;
-
- // If we are after a line marker that switched us to system header mode, or
- // that set #include information, preserve it.
- Kind = Entries.back().FileKind;
- IncludeOffset = Entries.back().IncludeOffset;
- }
-
- Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind,
- IncludeOffset));
-}
-
-/// AddLineNote This is the same as the previous version of AddLineNote, but is
-/// used for GNU line markers. If EntryExit is 0, then this doesn't change the
-/// presumed \#include stack. If it is 1, this is a file entry, if it is 2 then
-/// this is a file exit. FileKind specifies whether this is a system header or
-/// extern C system header.
-void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
- unsigned LineNo, int FilenameID,
- unsigned EntryExit,
+/// Add a line note to the line table that indicates that there is a \#line or
+/// GNU line marker at the specified FID/Offset location which changes the
+/// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't
+/// change the presumed \#include stack. If it is 1, this is a file entry, if
+/// it is 2 then this is a file exit. FileKind specifies whether this is a
+/// system header or extern C system header.
+void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo,
+ int FilenameID, unsigned EntryExit,
SrcMgr::CharacteristicKind FileKind) {
- assert(FilenameID != -1 && "Unspecified filename should use other accessor");
-
std::vector<LineEntry> &Entries = LineEntries[FID];
+ // An unspecified FilenameID means use the last filename if available, or the
+ // main source file otherwise.
+ if (FilenameID == -1 && !Entries.empty())
+ FilenameID = Entries.back().FilenameID;
+
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
"Adding line entries out of order!");
@@ -281,47 +255,20 @@ unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
return getLineTable().getLineTableFilenameID(Name);
}
-
/// AddLineNote - Add a line note to the line table for the FileID and offset
/// specified by Loc. If FilenameID is -1, it is considered to be
/// unspecified.
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
- int FilenameID) {
- std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
-
- bool Invalid = false;
- const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
- if (!Entry.isFile() || Invalid)
- return;
-
- const SrcMgr::FileInfo &FileInfo = Entry.getFile();
-
- // Remember that this file has #line directives now if it doesn't already.
- const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
-
- getLineTable().AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID);
-}
-
-/// AddLineNote - Add a GNU line marker to the line table.
-void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
int FilenameID, bool IsFileEntry,
- bool IsFileExit, bool IsSystemHeader,
- bool IsExternCHeader) {
- // If there is no filename and no flags, this is treated just like a #line,
- // which does not change the flags of the previous line marker.
- if (FilenameID == -1) {
- assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader &&
- "Can't set flags without setting the filename!");
- return AddLineNote(Loc, LineNo, FilenameID);
- }
-
+ bool IsFileExit,
+ SrcMgr::CharacteristicKind FileKind) {
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
if (!Entry.isFile() || Invalid)
return;
-
+
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
// Remember that this file has #line directives now if it doesn't already.
@@ -329,14 +276,6 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
(void) getLineTable();
- SrcMgr::CharacteristicKind FileKind;
- if (IsExternCHeader)
- FileKind = SrcMgr::C_ExternCSystem;
- else if (IsSystemHeader)
- FileKind = SrcMgr::C_System;
- else
- FileKind = SrcMgr::C_User;
-
unsigned EntryExit = 0;
if (IsFileEntry)
EntryExit = 1;
@@ -406,6 +345,34 @@ void SourceManager::clearIDTables() {
createExpansionLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1);
}
+void SourceManager::initializeForReplay(const SourceManager &Old) {
+ assert(MainFileID.isInvalid() && "expected uninitialized SourceManager");
+
+ auto CloneContentCache = [&](const ContentCache *Cache) -> ContentCache * {
+ auto *Clone = new (ContentCacheAlloc.Allocate<ContentCache>()) ContentCache;
+ Clone->OrigEntry = Cache->OrigEntry;
+ Clone->ContentsEntry = Cache->ContentsEntry;
+ Clone->BufferOverridden = Cache->BufferOverridden;
+ Clone->IsSystemFile = Cache->IsSystemFile;
+ Clone->IsTransient = Cache->IsTransient;
+ Clone->replaceBuffer(Cache->getRawBuffer(), /*DoNotFree*/true);
+ return Clone;
+ };
+
+ // Ensure all SLocEntries are loaded from the external source.
+ for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I)
+ if (!Old.SLocEntryLoaded[I])
+ Old.loadSLocEntry(I, nullptr);
+
+ // Inherit any content cache data from the old source manager.
+ for (auto &FileInfo : Old.FileInfos) {
+ SrcMgr::ContentCache *&Slot = FileInfos[FileInfo.first];
+ if (Slot)
+ continue;
+ Slot = CloneContentCache(FileInfo.second);
+ }
+}
+
/// getOrCreateContentCache - Create or return a cached ContentCache for the
/// specified file.
const ContentCache *
@@ -442,15 +409,16 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
}
-/// createMemBufferContentCache - Create a new ContentCache for the specified
-/// memory buffer. This does no caching.
-const ContentCache *SourceManager::createMemBufferContentCache(
- std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+/// Create a new ContentCache for the specified memory buffer.
+/// This does no caching.
+const ContentCache *
+SourceManager::createMemBufferContentCache(llvm::MemoryBuffer *Buffer,
+ bool DoNotFree) {
// Add a new ContentCache to the MemBufferInfos list and return it.
ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>();
new (Entry) ContentCache();
MemBufferInfos.push_back(Entry);
- Entry->setBuffer(std::move(Buffer));
+ Entry->replaceBuffer(Buffer, DoNotFree);
return Entry;
}
@@ -1136,6 +1104,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 +1113,19 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache;
unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
unsigned LineEnd = SourceLineCache[LastLineNoResult];
- if (FilePos >= LineStart && FilePos < LineEnd)
+ if (FilePos >= LineStart && FilePos < LineEnd) {
+ // LineEnd is the LineStart of the next line.
+ // A line ends with separator LF or CR+LF on Windows.
+ // FilePos might point to the last separator,
+ // but we need a column number at most 1 + the last column.
+ if (FilePos + 1 == LineEnd && FilePos > LineStart) {
+ if (Buf[FilePos - 1] == '\r' || Buf[FilePos - 1] == '\n')
+ --FilePos;
+ }
return FilePos - LineStart + 1;
+ }
}
- const char *Buf = MemBuf->getBufferStart();
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
--LineStart;
@@ -2042,9 +2019,51 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
if (LOffs.first.isInvalid() || ROffs.first.isInvalid())
return LOffs.first.isInvalid() && !ROffs.first.isInvalid();
+ std::pair<bool, bool> InSameTU = isInTheSameTranslationUnit(LOffs, ROffs);
+ if (InSameTU.first)
+ return InSameTU.second;
+
+ // If we arrived here, the location is either in a built-ins buffer or
+ // associated with global inline asm. PR5662 and PR22576 are examples.
+
+ StringRef LB = getBuffer(LOffs.first)->getBufferIdentifier();
+ StringRef RB = getBuffer(ROffs.first)->getBufferIdentifier();
+ bool LIsBuiltins = LB == "<built-in>";
+ bool RIsBuiltins = RB == "<built-in>";
+ // Sort built-in before non-built-in.
+ if (LIsBuiltins || RIsBuiltins) {
+ if (LIsBuiltins != RIsBuiltins)
+ return LIsBuiltins;
+ // Both are in built-in buffers, but from different files. We just claim that
+ // lower IDs come first.
+ return LOffs.first < ROffs.first;
+ }
+ bool LIsAsm = LB == "<inline asm>";
+ bool RIsAsm = RB == "<inline asm>";
+ // Sort assembler after built-ins, but before the rest.
+ if (LIsAsm || RIsAsm) {
+ if (LIsAsm != RIsAsm)
+ return RIsAsm;
+ assert(LOffs.first == ROffs.first);
+ return false;
+ }
+ bool LIsScratch = LB == "<scratch space>";
+ bool RIsScratch = RB == "<scratch space>";
+ // Sort scratch after inline asm, but before the rest.
+ if (LIsScratch || RIsScratch) {
+ if (LIsScratch != RIsScratch)
+ return LIsScratch;
+ return LOffs.second < ROffs.second;
+ }
+ llvm_unreachable("Unsortable locations found");
+}
+
+std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit(
+ std::pair<FileID, unsigned> &LOffs,
+ std::pair<FileID, unsigned> &ROffs) const {
// If the source locations are in the same file, just compare offsets.
if (LOffs.first == ROffs.first)
- return LOffs.second < ROffs.second;
+ return std::make_pair(true, LOffs.second < ROffs.second);
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
@@ -2054,7 +2073,8 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
- return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
+ return std::make_pair(
+ true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
// Okay, we missed in the cache, start updating the cache for this query.
IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first,
@@ -2084,44 +2104,12 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// locations within the common file and cache them.
if (LOffs.first == ROffs.first) {
IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second);
- return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
+ return std::make_pair(
+ true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
}
-
- // If we arrived here, the location is either in a built-ins buffer or
- // associated with global inline asm. PR5662 and PR22576 are examples.
-
// Clear the lookup cache, it depends on a common location.
IsBeforeInTUCache.clear();
- StringRef LB = getBuffer(LOffs.first)->getBufferIdentifier();
- StringRef RB = getBuffer(ROffs.first)->getBufferIdentifier();
- bool LIsBuiltins = LB == "<built-in>";
- bool RIsBuiltins = RB == "<built-in>";
- // Sort built-in before non-built-in.
- if (LIsBuiltins || RIsBuiltins) {
- if (LIsBuiltins != RIsBuiltins)
- return LIsBuiltins;
- // Both are in built-in buffers, but from different files. We just claim that
- // lower IDs come first.
- return LOffs.first < ROffs.first;
- }
- bool LIsAsm = LB == "<inline asm>";
- bool RIsAsm = RB == "<inline asm>";
- // Sort assembler after built-ins, but before the rest.
- if (LIsAsm || RIsAsm) {
- if (LIsAsm != RIsAsm)
- return RIsAsm;
- assert(LOffs.first == ROffs.first);
- return false;
- }
- bool LIsScratch = LB == "<scratch space>";
- bool RIsScratch = RB == "<scratch space>";
- // Sort scratch after inline asm, but before the rest.
- if (LIsScratch || RIsScratch) {
- if (LIsScratch != RIsScratch)
- return LIsScratch;
- return LOffs.second < ROffs.second;
- }
- llvm_unreachable("Unsortable locations found");
+ return std::make_pair(false, false);
}
void SourceManager::PrintStats() const {
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index b1b01e5f58..9ae466b786 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -12,16 +12,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetParser.h"
#include <cstdlib>
using namespace clang;
-static const LangAS::Map DefaultAddrSpaceMap = { 0 };
+static const LangASMap DefaultAddrSpaceMap = {0};
// TargetInfo Constructor.
TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
@@ -143,9 +145,11 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) const {
case UnsignedChar:
if (getCharWidth() < getIntWidth())
return "";
+ LLVM_FALLTHROUGH;
case UnsignedShort:
if (getShortWidth() < getIntWidth())
return "";
+ LLVM_FALLTHROUGH;
case UnsignedInt: return "U";
case UnsignedLong: return "UL";
case UnsignedLongLong: return "ULL";
@@ -282,12 +286,20 @@ 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)
- WCharType = UnsignedShort;
+
+ switch (Opts.WCharSize) {
+ default: llvm_unreachable("invalid wchar_t width");
+ case 0: break;
+ case 1: WCharType = Opts.WCharIsSigned ? SignedChar : UnsignedChar; break;
+ case 2: WCharType = Opts.WCharIsSigned ? SignedShort : UnsignedShort; break;
+ case 4: WCharType = Opts.WCharIsSigned ? SignedInt : UnsignedInt; break;
+ }
+
if (Opts.AlignDouble) {
DoubleAlign = LongLongAlign = 64;
LongDoubleAlign = 64;
@@ -344,6 +356,30 @@ bool TargetInfo::initFeatureMap(
return true;
}
+LangAS TargetInfo::getOpenCLTypeAddrSpace(const Type *T) const {
+ auto BT = dyn_cast<BuiltinType>(T);
+
+ if (!BT) {
+ if (isa<PipeType>(T))
+ return LangAS::opencl_global;
+
+ return LangAS::Default;
+ }
+
+ switch (BT->getKind()) {
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id: \
+ return LangAS::opencl_global;
+#include "clang/Basic/OpenCLImageTypes.def"
+
+ case BuiltinType::OCLSampler:
+ return LangAS::opencl_constant;
+
+ default:
+ return LangAS::Default;
+ }
+}
+
//===----------------------------------------------------------------------===//
@@ -504,6 +540,11 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
case '?': // Disparage slightly code.
case '!': // Disparage severely.
case '*': // Ignore for choosing register preferences.
+ case 'i': // Ignore i,n,E,F as output constraints (match from the other
+ // chars)
+ case 'n':
+ case 'E':
+ case 'F':
break; // Pass them.
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 21d9ea13ea..a9a5f4ddcf 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -12,30 +12,37 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/Cuda.h"
+#include "Targets.h"
+
+#include "Targets/AArch64.h"
+#include "Targets/AMDGPU.h"
+#include "Targets/ARM.h"
+#include "Targets/AVR.h"
+#include "Targets/BPF.h"
+#include "Targets/Hexagon.h"
+#include "Targets/Lanai.h"
+#include "Targets/Le64.h"
+#include "Targets/MSP430.h"
+#include "Targets/Mips.h"
+#include "Targets/NVPTX.h"
+#include "Targets/Nios2.h"
+#include "Targets/OSTargets.h"
+#include "Targets/PNaCl.h"
+#include "Targets/PPC.h"
+#include "Targets/SPIR.h"
+#include "Targets/Sparc.h"
+#include "Targets/SystemZ.h"
+#include "Targets/TCE.h"
+#include "Targets/WebAssembly.h"
+#include "Targets/X86.h"
+#include "Targets/XCore.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/MacroBuilder.h"
-#include "clang/Basic/TargetBuiltins.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/TargetOptions.h"
-#include "clang/Basic/Version.h"
-#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/MC/MCSectionMachO.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/TargetParser.h"
-#include <algorithm>
-#include <memory>
using namespace clang;
+namespace clang {
+namespace targets {
//===----------------------------------------------------------------------===//
// Common code shared among targets.
//===----------------------------------------------------------------------===//
@@ -43,8 +50,8 @@ using namespace clang;
/// DefineStd - Define a macro name and standard variants. For example if
/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix"
/// when in GNU mode.
-static void DefineStd(MacroBuilder &Builder, StringRef MacroName,
- const LangOptions &Opts) {
+void DefineStd(MacroBuilder &Builder, StringRef MacroName,
+ const LangOptions &Opts) {
assert(MacroName[0] != '_' && "Identifier should be in the user's namespace");
// If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier
@@ -59,4389 +66,14 @@ static void DefineStd(MacroBuilder &Builder, StringRef MacroName,
Builder.defineMacro("__" + MacroName + "__");
}
-static void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName,
- bool Tuning = true) {
+void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, bool Tuning) {
Builder.defineMacro("__" + CPUName);
Builder.defineMacro("__" + CPUName + "__");
if (Tuning)
Builder.defineMacro("__tune_" + CPUName + "__");
}
-static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
- const TargetOptions &Opts);
-
-//===----------------------------------------------------------------------===//
-// Defines specific to certain operating systems.
-//===----------------------------------------------------------------------===//
-
-namespace {
-template<typename TgtInfo>
-class OSTargetInfo : public TgtInfo {
-protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const=0;
-public:
- OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : TgtInfo(Triple, Opts) {}
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- TgtInfo::getTargetDefines(Opts, Builder);
- getOSDefines(Opts, TgtInfo::getTriple(), Builder);
- }
-
-};
-
-// CloudABI Target
-template <typename Target>
-class CloudABITargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__CloudABI__");
- Builder.defineMacro("__ELF__");
-
- // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t.
- Builder.defineMacro("__STDC_ISO_10646__", "201206L");
- Builder.defineMacro("__STDC_UTF_16__");
- Builder.defineMacro("__STDC_UTF_32__");
- }
-
-public:
- CloudABITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
-};
-
-static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
- const llvm::Triple &Triple,
- StringRef &PlatformName,
- VersionTuple &PlatformMinVersion) {
- Builder.defineMacro("__APPLE_CC__", "6000");
- Builder.defineMacro("__APPLE__");
- Builder.defineMacro("OBJC_NEW_PROPERTIES");
- // AddressSanitizer doesn't play well with source fortification, which is on
- // by default on Darwin.
- if (Opts.Sanitize.has(SanitizerKind::Address))
- Builder.defineMacro("_FORTIFY_SOURCE", "0");
-
- // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode.
- if (!Opts.ObjC1) {
- // __weak is always defined, for use in blocks and with objc pointers.
- Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
- Builder.defineMacro("__strong", "");
- Builder.defineMacro("__unsafe_unretained", "");
- }
-
- if (Opts.Static)
- Builder.defineMacro("__STATIC__");
- else
- Builder.defineMacro("__DYNAMIC__");
-
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
-
- // Get the platform type and version number from the triple.
- unsigned Maj, Min, Rev;
- if (Triple.isMacOSX()) {
- Triple.getMacOSXVersion(Maj, Min, Rev);
- PlatformName = "macos";
- } else {
- Triple.getOSVersion(Maj, Min, Rev);
- PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
- }
-
- // If -target arch-pc-win32-macho option specified, we're
- // generating code for Win32 ABI. No need to emit
- // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__.
- if (PlatformName == "win32") {
- PlatformMinVersion = VersionTuple(Maj, Min, Rev);
- return;
- }
-
- // Set the appropriate OS version define.
- if (Triple.isiOS()) {
- assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
- char Str[7];
- if (Maj < 10) {
- Str[0] = '0' + Maj;
- Str[1] = '0' + (Min / 10);
- Str[2] = '0' + (Min % 10);
- Str[3] = '0' + (Rev / 10);
- Str[4] = '0' + (Rev % 10);
- Str[5] = '\0';
- } else {
- // Handle versions >= 10.
- Str[0] = '0' + (Maj / 10);
- Str[1] = '0' + (Maj % 10);
- Str[2] = '0' + (Min / 10);
- Str[3] = '0' + (Min % 10);
- Str[4] = '0' + (Rev / 10);
- Str[5] = '0' + (Rev % 10);
- Str[6] = '\0';
- }
- if (Triple.isTvOS())
- Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str);
- else
- Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
- Str);
-
- } else if (Triple.isWatchOS()) {
- assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
- char Str[6];
- Str[0] = '0' + Maj;
- Str[1] = '0' + (Min / 10);
- Str[2] = '0' + (Min % 10);
- Str[3] = '0' + (Rev / 10);
- Str[4] = '0' + (Rev % 10);
- Str[5] = '\0';
- Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str);
- } else if (Triple.isMacOSX()) {
- // Note that the Driver allows versions which aren't representable in the
- // define (because we only get a single digit for the minor and micro
- // revision numbers). So, we limit them to the maximum representable
- // version.
- assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
- char Str[7];
- if (Maj < 10 || (Maj == 10 && Min < 10)) {
- Str[0] = '0' + (Maj / 10);
- Str[1] = '0' + (Maj % 10);
- Str[2] = '0' + std::min(Min, 9U);
- Str[3] = '0' + std::min(Rev, 9U);
- Str[4] = '\0';
- } else {
- // Handle versions > 10.9.
- Str[0] = '0' + (Maj / 10);
- Str[1] = '0' + (Maj % 10);
- Str[2] = '0' + (Min / 10);
- Str[3] = '0' + (Min % 10);
- Str[4] = '0' + (Rev / 10);
- Str[5] = '0' + (Rev % 10);
- Str[6] = '\0';
- }
- Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
- }
-
- // Tell users about the kernel if there is one.
- if (Triple.isOSDarwin())
- Builder.defineMacro("__MACH__");
-
- // The Watch ABI uses Dwarf EH.
- if(Triple.isWatchABI())
- Builder.defineMacro("__ARM_DWARF_EH__");
-
- PlatformMinVersion = VersionTuple(Maj, Min, Rev);
-}
-
-template<typename Target>
-class DarwinTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- getDarwinDefines(Builder, Opts, Triple, this->PlatformName,
- this->PlatformMinVersion);
- }
-
-public:
- DarwinTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- // By default, no TLS, and we whitelist permitted architecture/OS
- // combinations.
- this->TLSSupported = false;
-
- if (Triple.isMacOSX())
- this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7);
- else if (Triple.isiOS()) {
- // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards.
- if (Triple.getArch() == llvm::Triple::x86_64 ||
- Triple.getArch() == llvm::Triple::aarch64)
- this->TLSSupported = !Triple.isOSVersionLT(8);
- else if (Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb)
- this->TLSSupported = !Triple.isOSVersionLT(9);
- } else if (Triple.isWatchOS())
- this->TLSSupported = !Triple.isOSVersionLT(2);
-
- this->MCountName = "\01mcount";
- }
-
- std::string isValidSectionSpecifier(StringRef SR) const override {
- // Let MCSectionMachO validate this.
- StringRef Segment, Section;
- unsigned TAA, StubSize;
- bool HasTAA;
- return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section,
- TAA, HasTAA, StubSize);
- }
-
- const char *getStaticInitSectionSpecifier() const override {
- // FIXME: We should return 0 when building kexts.
- return "__TEXT,__StaticInit,regular,pure_instructions";
- }
-
- /// Darwin does not support protected visibility. Darwin's "default"
- /// is very similar to ELF's "protected"; Darwin requires a "weak"
- /// attribute on declarations that can be dynamically replaced.
- bool hasProtectedVisibility() const override {
- return false;
- }
-
- unsigned getExnObjectAlignment() const override {
- // The alignment of an exception object is 8-bytes for darwin since
- // libc++abi doesn't declare _Unwind_Exception with __attribute__((aligned))
- // and therefore doesn't guarantee 16-byte alignment.
- return 64;
- }
-};
-
-
-// DragonFlyBSD Target
-template<typename Target>
-class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // DragonFly defines; list based off of gcc output
- Builder.defineMacro("__DragonFly__");
- Builder.defineMacro("__DragonFly_cc_version", "100001");
- Builder.defineMacro("__ELF__");
- Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
- Builder.defineMacro("__tune_i386__");
- DefineStd(Builder, "unix", Opts);
- }
-public:
- DragonFlyBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- switch (Triple.getArch()) {
- default:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- this->MCountName = ".mcount";
- break;
- }
- }
-};
-
-#ifndef FREEBSD_CC_VERSION
-#define FREEBSD_CC_VERSION 0U
-#endif
-
-// FreeBSD Target
-template<typename Target>
-class FreeBSDTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // FreeBSD defines; list based off of gcc output
-
- unsigned Release = Triple.getOSMajorVersion();
- if (Release == 0U)
- Release = 8U;
- unsigned CCVersion = FREEBSD_CC_VERSION;
- if (CCVersion == 0U)
- CCVersion = Release * 100000U + 1U;
-
- Builder.defineMacro("__FreeBSD__", Twine(Release));
- Builder.defineMacro("__FreeBSD_cc_version", Twine(CCVersion));
- Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
-
- // On FreeBSD, wchar_t contains the number of the code point as
- // used by the character set of the locale. These character sets are
- // not necessarily a superset of ASCII.
- //
- // FIXME: This is wrong; the macro refers to the numerical values
- // of wchar_t *literals*, which are not locale-dependent. However,
- // FreeBSD systems apparently depend on us getting this wrong, and
- // setting this to 1 is conforming even if all the basic source
- // character literals have the same encoding as char and wchar_t.
- Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1");
- }
-public:
- FreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- switch (Triple.getArch()) {
- default:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- this->MCountName = ".mcount";
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- this->MCountName = "_mcount";
- break;
- case llvm::Triple::arm:
- this->MCountName = "__mcount";
- break;
- }
- }
-};
-
-// GNU/kFreeBSD Target
-template<typename Target>
-class KFreeBSDTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // GNU/kFreeBSD defines; list based off of gcc output
-
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__FreeBSD_kernel__");
- Builder.defineMacro("__GLIBC__");
- Builder.defineMacro("__ELF__");
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
- }
-public:
- KFreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
-};
-
-// Haiku Target
-template<typename Target>
-class HaikuTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // Haiku defines; list based off of gcc output
- Builder.defineMacro("__HAIKU__");
- Builder.defineMacro("__ELF__");
- DefineStd(Builder, "unix", Opts);
- }
-public:
- HaikuTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->SizeType = TargetInfo::UnsignedLong;
- this->IntPtrType = TargetInfo::SignedLong;
- this->PtrDiffType = TargetInfo::SignedLong;
- this->ProcessIDType = TargetInfo::SignedLong;
- this->TLSSupported = false;
-
- }
-};
-
-// Minix Target
-template<typename Target>
-class MinixTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // Minix defines
-
- Builder.defineMacro("__minix", "3");
- Builder.defineMacro("_EM_WSIZE", "4");
- Builder.defineMacro("_EM_PSIZE", "4");
- Builder.defineMacro("_EM_SSIZE", "2");
- Builder.defineMacro("_EM_LSIZE", "4");
- Builder.defineMacro("_EM_FSIZE", "4");
- Builder.defineMacro("_EM_DSIZE", "8");
- Builder.defineMacro("__ELF__");
- DefineStd(Builder, "unix", Opts);
- }
-public:
- MinixTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
-};
-
-// Linux target
-template<typename Target>
-class LinuxTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // Linux defines; list based off of gcc output
- DefineStd(Builder, "unix", Opts);
- DefineStd(Builder, "linux", Opts);
- Builder.defineMacro("__gnu_linux__");
- Builder.defineMacro("__ELF__");
- if (Triple.isAndroid()) {
- Builder.defineMacro("__ANDROID__", "1");
- unsigned Maj, Min, Rev;
- Triple.getEnvironmentVersion(Maj, Min, Rev);
- this->PlatformName = "android";
- this->PlatformMinVersion = VersionTuple(Maj, Min, Rev);
- if (Maj)
- Builder.defineMacro("__ANDROID_API__", Twine(Maj));
- }
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
- if (this->HasFloat128)
- Builder.defineMacro("__FLOAT128__");
- }
-public:
- LinuxTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->WIntType = TargetInfo::UnsignedInt;
-
- switch (Triple.getArch()) {
- default:
- break;
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- this->MCountName = "_mcount";
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- case llvm::Triple::systemz:
- this->HasFloat128 = true;
- break;
- }
- }
-
- const char *getStaticInitSectionSpecifier() const override {
- return ".text.startup";
- }
-};
-
-// NetBSD Target
-template<typename Target>
-class NetBSDTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // NetBSD defines; list based off of gcc output
- Builder.defineMacro("__NetBSD__");
- Builder.defineMacro("__unix__");
- Builder.defineMacro("__ELF__");
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
-
- switch (Triple.getArch()) {
- default:
- break;
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- Builder.defineMacro("__ARM_DWARF_EH__");
- break;
- }
- }
-public:
- NetBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->MCountName = "_mcount";
- }
-};
-
-// OpenBSD Target
-template<typename Target>
-class OpenBSDTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // OpenBSD defines; list based off of gcc output
-
- Builder.defineMacro("__OpenBSD__");
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- if (this->HasFloat128)
- Builder.defineMacro("__FLOAT128__");
- }
-public:
- OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->TLSSupported = false;
-
- switch (Triple.getArch()) {
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- this->HasFloat128 = true;
- // FALLTHROUGH
- default:
- this->MCountName = "__mcount";
- break;
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::ppc:
- case llvm::Triple::sparcv9:
- this->MCountName = "_mcount";
- break;
- }
- }
-};
-
-// Bitrig Target
-template<typename Target>
-class BitrigTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // Bitrig defines; list based off of gcc output
-
- Builder.defineMacro("__Bitrig__");
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
-
- switch (Triple.getArch()) {
- default:
- break;
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- Builder.defineMacro("__ARM_DWARF_EH__");
- break;
- }
- }
-public:
- BitrigTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->MCountName = "__mcount";
- }
-};
-
-// PSP Target
-template<typename Target>
-class PSPTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // PSP defines; list based on the output of the pspdev gcc toolchain.
- Builder.defineMacro("PSP");
- Builder.defineMacro("_PSP");
- Builder.defineMacro("__psp__");
- Builder.defineMacro("__ELF__");
- }
-public:
- PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {}
-};
-
-// PS3 PPU Target
-template<typename Target>
-class PS3PPUTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // PS3 PPU defines.
- Builder.defineMacro("__PPC__");
- Builder.defineMacro("__PPU__");
- Builder.defineMacro("__CELLOS_LV2__");
- Builder.defineMacro("__ELF__");
- Builder.defineMacro("__LP32__");
- Builder.defineMacro("_ARCH_PPC64");
- Builder.defineMacro("__powerpc64__");
- }
-public:
- PS3PPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->LongWidth = this->LongAlign = 32;
- this->PointerWidth = this->PointerAlign = 32;
- this->IntMaxType = TargetInfo::SignedLongLong;
- this->Int64Type = TargetInfo::SignedLongLong;
- this->SizeType = TargetInfo::UnsignedInt;
- this->resetDataLayout("E-m:e-p:32:32-i64:64-n32:64");
- }
-};
-
-template <typename Target>
-class PS4OSTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__FreeBSD__", "9");
- Builder.defineMacro("__FreeBSD_cc_version", "900001");
- Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- Builder.defineMacro("__ORBIS__");
- }
-public:
- PS4OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->WCharType = this->UnsignedShort;
-
- // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits).
- this->MaxTLSAlign = 256;
-
- // On PS4, do not honor explicit bit field alignment,
- // as in "__attribute__((aligned(2))) int b : 1;".
- this->UseExplicitBitFieldAlignment = false;
-
- switch (Triple.getArch()) {
- default:
- case llvm::Triple::x86_64:
- this->MCountName = ".mcount";
- break;
- }
- }
-};
-
-// Solaris target
-template<typename Target>
-class SolarisTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "sun", Opts);
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- Builder.defineMacro("__svr4__");
- Builder.defineMacro("__SVR4");
- // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and
- // newer, but to 500 for everything else. feature_test.h has a check to
- // ensure that you are not using C99 with an old version of X/Open or C89
- // with a new version.
- if (Opts.C99)
- Builder.defineMacro("_XOPEN_SOURCE", "600");
- else
- Builder.defineMacro("_XOPEN_SOURCE", "500");
- if (Opts.CPlusPlus)
- Builder.defineMacro("__C99FEATURES__");
- Builder.defineMacro("_LARGEFILE_SOURCE");
- Builder.defineMacro("_LARGEFILE64_SOURCE");
- Builder.defineMacro("__EXTENSIONS__");
- Builder.defineMacro("_REENTRANT");
- }
-public:
- SolarisTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->WCharType = this->SignedInt;
- // FIXME: WIntType should be SignedLong
- }
-};
-
-// Windows target
-template<typename Target>
-class WindowsTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("_WIN32");
- }
- void getVisualStudioDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- if (Opts.CPlusPlus) {
- if (Opts.RTTIData)
- Builder.defineMacro("_CPPRTTI");
-
- if (Opts.CXXExceptions)
- Builder.defineMacro("_CPPUNWIND");
- }
-
- if (Opts.Bool)
- Builder.defineMacro("__BOOL_DEFINED");
-
- if (!Opts.CharIsSigned)
- Builder.defineMacro("_CHAR_UNSIGNED");
-
- // FIXME: POSIXThreads isn't exactly the option this should be defined for,
- // but it works for now.
- if (Opts.POSIXThreads)
- Builder.defineMacro("_MT");
-
- if (Opts.MSCompatibilityVersion) {
- Builder.defineMacro("_MSC_VER",
- Twine(Opts.MSCompatibilityVersion / 100000));
- Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion));
- // FIXME We cannot encode the revision information into 32-bits
- Builder.defineMacro("_MSC_BUILD", Twine(1));
-
- if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015))
- Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1));
-
- if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) {
- if (Opts.CPlusPlus1z)
- Builder.defineMacro("_MSVC_LANG", "201403L");
- else if (Opts.CPlusPlus14)
- Builder.defineMacro("_MSVC_LANG", "201402L");
- }
- }
-
- if (Opts.MicrosoftExt) {
- Builder.defineMacro("_MSC_EXTENSIONS");
-
- if (Opts.CPlusPlus11) {
- Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED");
- Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED");
- Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED");
- }
- }
-
- Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
- }
-
-public:
- WindowsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
-};
-
-template <typename Target>
-class NaClTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
-
- DefineStd(Builder, "unix", Opts);
- Builder.defineMacro("__ELF__");
- Builder.defineMacro("__native_client__");
- }
-
-public:
- NaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->LongAlign = 32;
- this->LongWidth = 32;
- this->PointerAlign = 32;
- this->PointerWidth = 32;
- this->IntMaxType = TargetInfo::SignedLongLong;
- this->Int64Type = TargetInfo::SignedLongLong;
- this->DoubleAlign = 64;
- this->LongDoubleWidth = 64;
- this->LongDoubleAlign = 64;
- this->LongLongWidth = 64;
- this->LongLongAlign = 64;
- this->SizeType = TargetInfo::UnsignedInt;
- this->PtrDiffType = TargetInfo::SignedInt;
- this->IntPtrType = TargetInfo::SignedInt;
- // RegParmMax is inherited from the underlying architecture.
- this->LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- if (Triple.getArch() == llvm::Triple::arm) {
- // Handled in ARM's setABI().
- } else if (Triple.getArch() == llvm::Triple::x86) {
- this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32-S128");
- } else if (Triple.getArch() == llvm::Triple::x86_64) {
- this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32:64-S128");
- } else if (Triple.getArch() == llvm::Triple::mipsel) {
- // Handled on mips' setDataLayout.
- } else {
- assert(Triple.getArch() == llvm::Triple::le32);
- this->resetDataLayout("e-p:32:32-i64:64");
- }
- }
-};
-
-// Fuchsia Target
-template<typename Target>
-class FuchsiaTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__Fuchsia__");
- Builder.defineMacro("__ELF__");
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- // Required by the libc++ locale support.
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
- }
-public:
- FuchsiaTargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->MCountName = "__mcount";
- }
-};
-
-// WebAssembly target
-template <typename Target>
-class WebAssemblyOSTargetInfo : public OSTargetInfo<Target> {
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const final {
- // A common platform macro.
- if (Opts.POSIXThreads)
- Builder.defineMacro("_REENTRANT");
- // Follow g++ convention and predefine _GNU_SOURCE for C++.
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
- }
-
- // As an optimization, group static init code together in a section.
- const char *getStaticInitSectionSpecifier() const final {
- return ".text.__startup";
- }
-
-public:
- explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- this->MCountName = "__mcount";
- this->TheCXXABI.set(TargetCXXABI::WebAssembly);
- }
-};
-
-//===----------------------------------------------------------------------===//
-// Specific target implementations.
-//===----------------------------------------------------------------------===//
-
-// PPC abstract base class
-class PPCTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
- static const char * const GCCRegNames[];
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- std::string CPU;
-
- // Target cpu features.
- bool HasVSX;
- bool HasP8Vector;
- bool HasP8Crypto;
- bool HasDirectMove;
- bool HasQPX;
- bool HasHTM;
- bool HasBPERMD;
- bool HasExtDiv;
- bool HasP9Vector;
-
-protected:
- std::string ABI;
-
-public:
- PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple), HasVSX(false), HasP8Vector(false),
- HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false),
- HasBPERMD(false), HasExtDiv(false), HasP9Vector(false) {
- SimdDefaultAlign = 128;
- LongDoubleWidth = LongDoubleAlign = 128;
- LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble();
- }
-
- /// \brief Flags for architecture specific defines.
- typedef enum {
- ArchDefineNone = 0,
- ArchDefineName = 1 << 0, // <name> is substituted for arch name.
- ArchDefinePpcgr = 1 << 1,
- ArchDefinePpcsq = 1 << 2,
- ArchDefine440 = 1 << 3,
- ArchDefine603 = 1 << 4,
- ArchDefine604 = 1 << 5,
- ArchDefinePwr4 = 1 << 6,
- ArchDefinePwr5 = 1 << 7,
- ArchDefinePwr5x = 1 << 8,
- ArchDefinePwr6 = 1 << 9,
- ArchDefinePwr6x = 1 << 10,
- ArchDefinePwr7 = 1 << 11,
- ArchDefinePwr8 = 1 << 12,
- ArchDefinePwr9 = 1 << 13,
- ArchDefineA2 = 1 << 14,
- ArchDefineA2q = 1 << 15
- } ArchDefineTypes;
-
- // 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,
- // titan, rs64.
- bool setCPU(const std::string &Name) override {
- bool CPUKnown = llvm::StringSwitch<bool>(Name)
- .Case("generic", true)
- .Case("440", true)
- .Case("450", true)
- .Case("601", true)
- .Case("602", true)
- .Case("603", true)
- .Case("603e", true)
- .Case("603ev", true)
- .Case("604", true)
- .Case("604e", true)
- .Case("620", true)
- .Case("630", true)
- .Case("g3", true)
- .Case("7400", true)
- .Case("g4", true)
- .Case("7450", true)
- .Case("g4+", true)
- .Case("750", true)
- .Case("970", true)
- .Case("g5", true)
- .Case("a2", true)
- .Case("a2q", true)
- .Case("e500mc", true)
- .Case("e5500", true)
- .Case("power3", true)
- .Case("pwr3", true)
- .Case("power4", true)
- .Case("pwr4", true)
- .Case("power5", true)
- .Case("pwr5", true)
- .Case("power5x", true)
- .Case("pwr5x", true)
- .Case("power6", true)
- .Case("pwr6", true)
- .Case("power6x", true)
- .Case("pwr6x", true)
- .Case("power7", true)
- .Case("pwr7", true)
- .Case("power8", true)
- .Case("pwr8", true)
- .Case("power9", true)
- .Case("pwr9", true)
- .Case("powerpc", true)
- .Case("ppc", true)
- .Case("powerpc64", true)
- .Case("ppc64", true)
- .Case("powerpc64le", true)
- .Case("ppc64le", true)
- .Default(false);
-
- if (CPUKnown)
- CPU = Name;
-
- return CPUKnown;
- }
-
-
- StringRef getABI() const override { return ABI; }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin);
- }
-
- bool isCLZForZeroUndef() const override { return false; }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override;
-
- bool
- initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const override;
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override;
- bool hasFeature(StringRef Feature) const override;
- void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name,
- bool Enabled) const override;
-
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- switch (*Name) {
- default: return false;
- case 'O': // Zero
- break;
- case 'b': // Base register
- case 'f': // Floating point register
- Info.setAllowsRegister();
- break;
- // FIXME: The following are added to allow parsing.
- // I just took a guess at what the actions should be.
- // Also, is more specific checking needed? I.e. specific registers?
- case 'd': // Floating point register (containing 64-bit value)
- case 'v': // Altivec vector register
- Info.setAllowsRegister();
- break;
- case 'w':
- switch (Name[1]) {
- case 'd':// VSX vector register to hold vector double data
- case 'f':// VSX vector register to hold vector float data
- case 's':// VSX vector register to hold scalar float data
- case 'a':// Any VSX register
- case 'c':// An individual CR bit
- break;
- default:
- return false;
- }
- Info.setAllowsRegister();
- Name++; // Skip over 'w'.
- break;
- case 'h': // `MQ', `CTR', or `LINK' register
- case 'q': // `MQ' register
- case 'c': // `CTR' register
- case 'l': // `LINK' register
- case 'x': // `CR' register (condition register) number 0
- case 'y': // `CR' register (condition register)
- case 'z': // `XER[CA]' carry bit (part of the XER register)
- Info.setAllowsRegister();
- break;
- case 'I': // Signed 16-bit constant
- case 'J': // Unsigned 16-bit constant shifted left 16 bits
- // (use `L' instead for SImode constants)
- case 'K': // Unsigned 16-bit constant
- case 'L': // Signed 16-bit constant shifted left 16 bits
- case 'M': // Constant larger than 31
- case 'N': // Exact power of 2
- case 'P': // Constant whose negation is a signed 16-bit constant
- case 'G': // Floating point constant that can be loaded into a
- // register with one instruction per word
- case 'H': // Integer/Floating point constant that can be loaded
- // into a register using three instructions
- break;
- case 'm': // Memory operand. Note that on PowerPC targets, m can
- // include addresses that update the base register. It
- // is therefore only safe to use `m' in an asm statement
- // if that asm statement accesses the operand exactly once.
- // The asm statement must also use `%U<opno>' as a
- // placeholder for the "update" flag in the corresponding
- // load or store instruction. For example:
- // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val));
- // is correct but:
- // asm ("st %1,%0" : "=m" (mem) : "r" (val));
- // is not. Use es rather than m if you don't want the base
- // register to be updated.
- case 'e':
- if (Name[1] != 's')
- return false;
- // es: A "stable" memory operand; that is, one which does not
- // include any automodification of the base register. Unlike
- // `m', this constraint can be used in asm statements that
- // might access the operand several times, or that might not
- // access it at all.
- Info.setAllowsMemory();
- Name++; // Skip over 'e'.
- break;
- case 'Q': // Memory operand that is an offset from a register (it is
- // usually better to use `m' or `es' in asm statements)
- case 'Z': // Memory operand that is an indexed or indirect from a
- // register (it is usually better to use `m' or `es' in
- // asm statements)
- Info.setAllowsMemory();
- Info.setAllowsRegister();
- break;
- case 'R': // AIX TOC entry
- case 'a': // Address operand that is an indexed or indirect from a
- // register (`p' is preferable for asm statements)
- case 'S': // Constant suitable as a 64-bit mask operand
- case 'T': // Constant suitable as a 32-bit mask operand
- case 'U': // System V Release 4 small data area reference
- case 't': // AND masks that can be performed by two rldic{l, r}
- // instructions
- case 'W': // Vector constant that does not require memory
- case 'j': // Vector constant that is all zeros.
- break;
- // End FIXME.
- }
- return true;
- }
- std::string convertConstraint(const char *&Constraint) const override {
- std::string R;
- switch (*Constraint) {
- case 'e':
- case 'w':
- // Two-character constraint; add "^" hint for later parsing.
- R = std::string("^") + std::string(Constraint, 2);
- Constraint++;
- break;
- default:
- return TargetInfo::convertConstraint(Constraint);
- }
- return R;
- }
- const char *getClobbers() const override {
- return "";
- }
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- if (RegNo == 0) return 3;
- if (RegNo == 1) return 4;
- return -1;
- }
-
- bool hasSjLjLowering() const override {
- return true;
- }
-
- bool useFloat128ManglingForLongDouble() const override {
- return LongDoubleWidth == 128 &&
- LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble() &&
- getTriple().isOSBinFormatELF();
- }
-};
-
-const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsPPC.def"
-};
-
-/// handleTargetFeatures - Perform initialization based on the user
-/// configured set of features.
-bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
- for (const auto &Feature : Features) {
- if (Feature == "+vsx") {
- HasVSX = true;
- } else if (Feature == "+bpermd") {
- HasBPERMD = true;
- } else if (Feature == "+extdiv") {
- HasExtDiv = true;
- } else if (Feature == "+power8-vector") {
- HasP8Vector = true;
- } else if (Feature == "+crypto") {
- HasP8Crypto = true;
- } else if (Feature == "+direct-move") {
- HasDirectMove = true;
- } else if (Feature == "+qpx") {
- HasQPX = true;
- } else if (Feature == "+htm") {
- HasHTM = true;
- } else if (Feature == "+float128") {
- HasFloat128 = true;
- } else if (Feature == "+power9-vector") {
- HasP9Vector = true;
- }
- // TODO: Finish this list and add an assert that we've handled them
- // all.
- }
-
- return true;
-}
-
-/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
-/// #defines that are not tied to a specific subtarget.
-void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- // Target identification.
- Builder.defineMacro("__ppc__");
- Builder.defineMacro("__PPC__");
- Builder.defineMacro("_ARCH_PPC");
- Builder.defineMacro("__powerpc__");
- Builder.defineMacro("__POWERPC__");
- if (PointerWidth == 64) {
- Builder.defineMacro("_ARCH_PPC64");
- Builder.defineMacro("__powerpc64__");
- Builder.defineMacro("__ppc64__");
- Builder.defineMacro("__PPC64__");
- }
-
- // Target properties.
- if (getTriple().getArch() == llvm::Triple::ppc64le) {
- Builder.defineMacro("_LITTLE_ENDIAN");
- } else {
- if (getTriple().getOS() != llvm::Triple::NetBSD &&
- getTriple().getOS() != llvm::Triple::OpenBSD)
- Builder.defineMacro("_BIG_ENDIAN");
- }
-
- // ABI options.
- if (ABI == "elfv1" || ABI == "elfv1-qpx")
- Builder.defineMacro("_CALL_ELF", "1");
- if (ABI == "elfv2")
- Builder.defineMacro("_CALL_ELF", "2");
-
- // Subtarget options.
- Builder.defineMacro("__NATURAL_ALIGNMENT__");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
-
- // FIXME: Should be controlled by command line option.
- if (LongDoubleWidth == 128)
- Builder.defineMacro("__LONG_DOUBLE_128__");
-
- // 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");
-
- if (Opts.AltiVec) {
- Builder.defineMacro("__VEC__", "10206");
- Builder.defineMacro("__ALTIVEC__");
- }
-
- // 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);
-
- if (defs & ArchDefineName)
- Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper()));
- if (defs & ArchDefinePpcgr)
- Builder.defineMacro("_ARCH_PPCGR");
- if (defs & ArchDefinePpcsq)
- Builder.defineMacro("_ARCH_PPCSQ");
- if (defs & ArchDefine440)
- Builder.defineMacro("_ARCH_440");
- if (defs & ArchDefine603)
- Builder.defineMacro("_ARCH_603");
- if (defs & ArchDefine604)
- Builder.defineMacro("_ARCH_604");
- if (defs & ArchDefinePwr4)
- Builder.defineMacro("_ARCH_PWR4");
- if (defs & ArchDefinePwr5)
- Builder.defineMacro("_ARCH_PWR5");
- if (defs & ArchDefinePwr5x)
- Builder.defineMacro("_ARCH_PWR5X");
- if (defs & ArchDefinePwr6)
- Builder.defineMacro("_ARCH_PWR6");
- if (defs & ArchDefinePwr6x)
- Builder.defineMacro("_ARCH_PWR6X");
- if (defs & ArchDefinePwr7)
- Builder.defineMacro("_ARCH_PWR7");
- if (defs & ArchDefinePwr8)
- Builder.defineMacro("_ARCH_PWR8");
- if (defs & ArchDefinePwr9)
- Builder.defineMacro("_ARCH_PWR9");
- if (defs & ArchDefineA2)
- Builder.defineMacro("_ARCH_A2");
- if (defs & ArchDefineA2q) {
- Builder.defineMacro("_ARCH_A2Q");
- Builder.defineMacro("_ARCH_QP");
- }
-
- if (getTriple().getVendor() == llvm::Triple::BGQ) {
- Builder.defineMacro("__bg__");
- Builder.defineMacro("__THW_BLUEGENE__");
- Builder.defineMacro("__bgq__");
- Builder.defineMacro("__TOS_BGQ__");
- }
-
- if (HasVSX)
- Builder.defineMacro("__VSX__");
- if (HasP8Vector)
- Builder.defineMacro("__POWER8_VECTOR__");
- if (HasP8Crypto)
- Builder.defineMacro("__CRYPTO__");
- if (HasHTM)
- Builder.defineMacro("__HTM__");
- if (HasFloat128)
- Builder.defineMacro("__FLOAT128__");
- if (HasP9Vector)
- Builder.defineMacro("__POWER9_VECTOR__");
-
- 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");
- if (PointerWidth == 64)
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
-
- // FIXME: The following are not yet generated here by Clang, but are
- // generated by GCC:
- //
- // _SOFT_FLOAT_
- // __RECIP_PRECISION__
- // __APPLE_ALTIVEC__
- // __RECIP__
- // __RECIPF__
- // __RSQRTE__
- // __RSQRTEF__
- // _SOFT_DOUBLE_
- // __NO_LWSYNC__
- // __HAVE_BSWAP__
- // __LONGDOUBLE128
- // __CMODEL_MEDIUM__
- // __CMODEL_LARGE__
- // _CALL_SYSV
- // _CALL_DARWIN
- // __NO_FPRS__
-}
-
-// Handle explicit options being passed to the compiler here: if we've
-// explicitly turned off vsx and turned on any of:
-// - power8-vector
-// - direct-move
-// - float128
-// - power9-vector
-// then go ahead and error since the customer has expressed an incompatible
-// set of options.
-static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags,
- const std::vector<std::string> &FeaturesVec) {
-
- if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") !=
- FeaturesVec.end()) {
- if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") !=
- FeaturesVec.end()) {
- Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector"
- << "-mno-vsx";
- return false;
- }
-
- if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") !=
- FeaturesVec.end()) {
- Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move"
- << "-mno-vsx";
- return false;
- }
-
- if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") !=
- FeaturesVec.end()) {
- Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128"
- << "-mno-vsx";
- return false;
- }
-
- if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power9-vector") !=
- FeaturesVec.end()) {
- Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower9-vector"
- << "-mno-vsx";
- return false;
- }
- }
-
- return true;
-}
-
-bool PPCTargetInfo::initFeatureMap(
- llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const {
- Features["altivec"] = llvm::StringSwitch<bool>(CPU)
- .Case("7400", true)
- .Case("g4", true)
- .Case("7450", true)
- .Case("g4+", true)
- .Case("970", true)
- .Case("g5", true)
- .Case("pwr6", true)
- .Case("pwr7", true)
- .Case("pwr8", true)
- .Case("pwr9", true)
- .Case("ppc64", true)
- .Case("ppc64le", true)
- .Default(false);
-
- Features["qpx"] = (CPU == "a2q");
- Features["power9-vector"] = (CPU == "pwr9");
- Features["crypto"] = llvm::StringSwitch<bool>(CPU)
- .Case("ppc64le", true)
- .Case("pwr9", true)
- .Case("pwr8", true)
- .Default(false);
- Features["power8-vector"] = llvm::StringSwitch<bool>(CPU)
- .Case("ppc64le", true)
- .Case("pwr9", true)
- .Case("pwr8", true)
- .Default(false);
- Features["bpermd"] = llvm::StringSwitch<bool>(CPU)
- .Case("ppc64le", true)
- .Case("pwr9", true)
- .Case("pwr8", true)
- .Case("pwr7", true)
- .Default(false);
- Features["extdiv"] = llvm::StringSwitch<bool>(CPU)
- .Case("ppc64le", true)
- .Case("pwr9", true)
- .Case("pwr8", true)
- .Case("pwr7", true)
- .Default(false);
- Features["direct-move"] = llvm::StringSwitch<bool>(CPU)
- .Case("ppc64le", true)
- .Case("pwr9", true)
- .Case("pwr8", true)
- .Default(false);
- Features["vsx"] = llvm::StringSwitch<bool>(CPU)
- .Case("ppc64le", true)
- .Case("pwr9", true)
- .Case("pwr8", true)
- .Case("pwr7", true)
- .Default(false);
-
- if (!ppcUserFeaturesCheck(Diags, FeaturesVec))
- return false;
-
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
-}
-
-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);
-}
-
-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;
- }
- } else {
- if (Name == "vsx") {
- Features[Name] = Features["direct-move"] = Features["power8-vector"] =
- Features["float128"] = Features["power9-vector"] = false;
- } else {
- Features[Name] = false;
- }
- }
-}
-
-const char * const PPCTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
- "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
- "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
- "mq", "lr", "ctr", "ap",
- "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
- "xer",
- "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
- "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
- "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
- "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
- "vrsave", "vscr",
- "spe_acc", "spefscr",
- "sfp"
-};
-
-ArrayRef<const char*> PPCTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = {
- // While some of these aliases do map to different registers
- // they still share the same register name.
- { { "0" }, "r0" },
- { { "1"}, "r1" },
- { { "2" }, "r2" },
- { { "3" }, "r3" },
- { { "4" }, "r4" },
- { { "5" }, "r5" },
- { { "6" }, "r6" },
- { { "7" }, "r7" },
- { { "8" }, "r8" },
- { { "9" }, "r9" },
- { { "10" }, "r10" },
- { { "11" }, "r11" },
- { { "12" }, "r12" },
- { { "13" }, "r13" },
- { { "14" }, "r14" },
- { { "15" }, "r15" },
- { { "16" }, "r16" },
- { { "17" }, "r17" },
- { { "18" }, "r18" },
- { { "19" }, "r19" },
- { { "20" }, "r20" },
- { { "21" }, "r21" },
- { { "22" }, "r22" },
- { { "23" }, "r23" },
- { { "24" }, "r24" },
- { { "25" }, "r25" },
- { { "26" }, "r26" },
- { { "27" }, "r27" },
- { { "28" }, "r28" },
- { { "29" }, "r29" },
- { { "30" }, "r30" },
- { { "31" }, "r31" },
- { { "fr0" }, "f0" },
- { { "fr1" }, "f1" },
- { { "fr2" }, "f2" },
- { { "fr3" }, "f3" },
- { { "fr4" }, "f4" },
- { { "fr5" }, "f5" },
- { { "fr6" }, "f6" },
- { { "fr7" }, "f7" },
- { { "fr8" }, "f8" },
- { { "fr9" }, "f9" },
- { { "fr10" }, "f10" },
- { { "fr11" }, "f11" },
- { { "fr12" }, "f12" },
- { { "fr13" }, "f13" },
- { { "fr14" }, "f14" },
- { { "fr15" }, "f15" },
- { { "fr16" }, "f16" },
- { { "fr17" }, "f17" },
- { { "fr18" }, "f18" },
- { { "fr19" }, "f19" },
- { { "fr20" }, "f20" },
- { { "fr21" }, "f21" },
- { { "fr22" }, "f22" },
- { { "fr23" }, "f23" },
- { { "fr24" }, "f24" },
- { { "fr25" }, "f25" },
- { { "fr26" }, "f26" },
- { { "fr27" }, "f27" },
- { { "fr28" }, "f28" },
- { { "fr29" }, "f29" },
- { { "fr30" }, "f30" },
- { { "fr31" }, "f31" },
- { { "cc" }, "cr0" },
-};
-
-ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
-}
-
-class PPC32TargetInfo : public PPCTargetInfo {
-public:
- PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : PPCTargetInfo(Triple, Opts) {
- resetDataLayout("E-m:e-p:32:32-i64:64-n32");
-
- switch (getTriple().getOS()) {
- case llvm::Triple::Linux:
- case llvm::Triple::FreeBSD:
- case llvm::Triple::NetBSD:
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- IntPtrType = SignedInt;
- break;
- default:
- break;
- }
-
- if (getTriple().getOS() == llvm::Triple::FreeBSD) {
- LongDoubleWidth = LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- }
-
- // PPC32 supports atomics up to 4 bytes.
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
- }
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- // This is the ELF definition, and is overridden by the Darwin sub-target
- return TargetInfo::PowerABIBuiltinVaList;
- }
-};
-
-// Note: ABI differences may eventually require us to have a separate
-// TargetInfo for little endian.
-class PPC64TargetInfo : public PPCTargetInfo {
-public:
- PPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : PPCTargetInfo(Triple, Opts) {
- LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
- IntMaxType = SignedLong;
- Int64Type = SignedLong;
-
- if ((Triple.getArch() == llvm::Triple::ppc64le)) {
- resetDataLayout("e-m:e-i64:64-n32:64");
- ABI = "elfv2";
- } else {
- resetDataLayout("E-m:e-i64:64-n32:64");
- ABI = "elfv1";
- }
-
- switch (getTriple().getOS()) {
- case llvm::Triple::FreeBSD:
- LongDoubleWidth = LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- break;
- case llvm::Triple::NetBSD:
- IntMaxType = SignedLongLong;
- Int64Type = SignedLongLong;
- break;
- default:
- break;
- }
-
- // PPC64 supports atomics up to 8 bytes.
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::CharPtrBuiltinVaList;
- }
- // PPC64 Linux-specific ABI options.
- bool setABI(const std::string &Name) override {
- if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") {
- ABI = Name;
- return true;
- }
- return false;
- }
-};
-
-class DarwinPPC32TargetInfo : public DarwinTargetInfo<PPC32TargetInfo> {
-public:
- DarwinPPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : DarwinTargetInfo<PPC32TargetInfo>(Triple, Opts) {
- HasAlignMac68kSupport = true;
- 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 {
- return TargetInfo::CharPtrBuiltinVaList;
- }
-};
-
-class DarwinPPC64TargetInfo : public DarwinTargetInfo<PPC64TargetInfo> {
-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[] = {
- 1, // opencl_global
- 3, // opencl_local
- 4, // opencl_constant
- // FIXME: generic has to be added to the target
- 0, // opencl_generic
- 1, // cuda_device
- 4, // cuda_constant
- 3, // cuda_shared
-};
-
-class NVPTXTargetInfo : public TargetInfo {
- static const char *const GCCRegNames[];
- static const Builtin::Info BuiltinInfo[];
- CudaArch GPU;
- std::unique_ptr<TargetInfo> HostTarget;
-
-public:
- NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts,
- unsigned TargetPointerWidth)
- : TargetInfo(Triple) {
- assert((TargetPointerWidth == 32 || TargetPointerWidth == 64) &&
- "NVPTX only supports 32- and 64-bit modes.");
-
- TLSSupported = false;
- AddrSpaceMap = &NVPTXAddrSpaceMap;
- UseAddrSpaceMapMangling = true;
-
- // Define available target features
- // These must be defined in sorted order!
- NoAsmVariants = true;
- GPU = CudaArch::SM_20;
-
- if (TargetPointerWidth == 32)
- resetDataLayout("e-p:32:32-i64:64-v16:16-v32:32-n16:32:64");
- else
- resetDataLayout("e-i64:64-v16:16-v32:32-n16:32:64");
-
- // If possible, get a TargetInfo for our host triple, so we can match its
- // types.
- llvm::Triple HostTriple(Opts.HostTriple);
- if (!HostTriple.isNVPTX())
- HostTarget.reset(AllocateTarget(llvm::Triple(Opts.HostTriple), Opts));
-
- // If no host target, make some guesses about the data layout and return.
- if (!HostTarget) {
- LongWidth = LongAlign = TargetPointerWidth;
- PointerWidth = PointerAlign = TargetPointerWidth;
- switch (TargetPointerWidth) {
- case 32:
- SizeType = TargetInfo::UnsignedInt;
- PtrDiffType = TargetInfo::SignedInt;
- IntPtrType = TargetInfo::SignedInt;
- break;
- case 64:
- SizeType = TargetInfo::UnsignedLong;
- PtrDiffType = TargetInfo::SignedLong;
- IntPtrType = TargetInfo::SignedLong;
- break;
- default:
- llvm_unreachable("TargetPointerWidth must be 32 or 64");
- }
- return;
- }
-
- // Copy properties from host target.
- PointerWidth = HostTarget->getPointerWidth(/* AddrSpace = */ 0);
- PointerAlign = HostTarget->getPointerAlign(/* AddrSpace = */ 0);
- BoolWidth = HostTarget->getBoolWidth();
- BoolAlign = HostTarget->getBoolAlign();
- IntWidth = HostTarget->getIntWidth();
- IntAlign = HostTarget->getIntAlign();
- HalfWidth = HostTarget->getHalfWidth();
- HalfAlign = HostTarget->getHalfAlign();
- FloatWidth = HostTarget->getFloatWidth();
- FloatAlign = HostTarget->getFloatAlign();
- DoubleWidth = HostTarget->getDoubleWidth();
- DoubleAlign = HostTarget->getDoubleAlign();
- LongWidth = HostTarget->getLongWidth();
- LongAlign = HostTarget->getLongAlign();
- LongLongWidth = HostTarget->getLongLongWidth();
- LongLongAlign = HostTarget->getLongLongAlign();
- MinGlobalAlign = HostTarget->getMinGlobalAlign();
- NewAlign = HostTarget->getNewAlign();
- DefaultAlignForAttributeAligned =
- HostTarget->getDefaultAlignForAttributeAligned();
- SizeType = HostTarget->getSizeType();
- IntMaxType = HostTarget->getIntMaxType();
- PtrDiffType = HostTarget->getPtrDiffType(/* AddrSpace = */ 0);
- IntPtrType = HostTarget->getIntPtrType();
- WCharType = HostTarget->getWCharType();
- WIntType = HostTarget->getWIntType();
- Char16Type = HostTarget->getChar16Type();
- Char32Type = HostTarget->getChar32Type();
- Int64Type = HostTarget->getInt64Type();
- SigAtomicType = HostTarget->getSigAtomicType();
- ProcessIDType = HostTarget->getProcessIDType();
-
- UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment();
- UseZeroLengthBitfieldAlignment =
- HostTarget->useZeroLengthBitfieldAlignment();
- UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment();
- ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary();
-
- // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and
- // we need those macros to be identical on host and device, because (among
- // other things) they affect which standard library classes are defined, and
- // we need all classes to be defined on both the host and device.
- MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth();
-
- // Properties intentionally not copied from host:
- // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the
- // host/device boundary.
- // - SuitableAlign: Not visible across the host/device boundary, and may
- // correctly be different on host/device, e.g. if host has wider vector
- // types than device.
- // - LongDoubleWidth, LongDoubleAlign: nvptx's long double type is the same
- // as its double type, but that's not necessarily true on the host.
- // TODO: nvcc emits a warning when using long double on device; we should
- // do the same.
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__PTX__");
- Builder.defineMacro("__NVPTX__");
- if (Opts.CUDAIsDevice) {
- // Set __CUDA_ARCH__ for the GPU specified.
- std::string CUDAArchCode = [this] {
- switch (GPU) {
- case CudaArch::UNKNOWN:
- assert(false && "No GPU arch when compiling CUDA device code.");
- return "";
- case CudaArch::SM_20:
- return "200";
- case CudaArch::SM_21:
- return "210";
- case CudaArch::SM_30:
- return "300";
- case CudaArch::SM_32:
- return "320";
- case CudaArch::SM_35:
- return "350";
- case CudaArch::SM_37:
- return "370";
- case CudaArch::SM_50:
- return "500";
- case CudaArch::SM_52:
- return "520";
- case CudaArch::SM_53:
- return "530";
- case CudaArch::SM_60:
- return "600";
- case CudaArch::SM_61:
- return "610";
- case CudaArch::SM_62:
- return "620";
- }
- llvm_unreachable("unhandled CudaArch");
- }();
- Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode);
- }
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin);
- }
- bool
- initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const override {
- Features["satom"] = GPU >= CudaArch::SM_60;
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
- }
-
- bool hasFeature(StringRef Feature) const override {
- return llvm::StringSwitch<bool>(Feature)
- .Cases("ptx", "nvptx", true)
- .Case("satom", GPU >= CudaArch::SM_60) // Atomics w/ scope.
- .Default(false);
- }
-
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- // No aliases.
- return None;
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- switch (*Name) {
- default:
- return false;
- case 'c':
- case 'h':
- case 'r':
- case 'l':
- case 'f':
- case 'd':
- Info.setAllowsRegister();
- return true;
- }
- }
- const char *getClobbers() const override {
- // FIXME: Is this really right?
- return "";
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- // FIXME: implement
- return TargetInfo::CharPtrBuiltinVaList;
- }
- bool setCPU(const std::string &Name) override {
- GPU = StringToCudaArch(Name);
- return GPU != CudaArch::UNKNOWN;
- }
- void setSupportedOpenCLOpts() override {
- auto &Opts = getSupportedOpenCLOpts();
- Opts.support("cl_clang_storage_class_specifiers");
- Opts.support("cl_khr_gl_sharing");
- Opts.support("cl_khr_icd");
-
- Opts.support("cl_khr_fp64");
- Opts.support("cl_khr_byte_addressable_store");
- Opts.support("cl_khr_global_int32_base_atomics");
- Opts.support("cl_khr_global_int32_extended_atomics");
- Opts.support("cl_khr_local_int32_base_atomics");
- Opts.support("cl_khr_local_int32_extended_atomics");
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- // CUDA compilations support all of the host's calling conventions.
- //
- // TODO: We should warn if you apply a non-default CC to anything other than
- // a host function.
- if (HostTarget)
- return HostTarget->checkCallingConvention(CC);
- return CCCR_Warning;
- }
-};
-
-const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE },
-#include "clang/Basic/BuiltinsNVPTX.def"
-};
-
-const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"};
-
-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
-};
-
-// If you edit the description strings, make sure you update
-// getPointerWidthV().
-
-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 =
- "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";
-
-class AMDGPUTargetInfo final : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
- static const char * const GCCRegNames[];
-
- /// \brief The GPU profiles supported by the AMDGPU target.
- enum GPUKind {
- GK_NONE,
- GK_R600,
- GK_R600_DOUBLE_OPS,
- GK_R700,
- GK_R700_DOUBLE_OPS,
- GK_EVERGREEN,
- GK_EVERGREEN_DOUBLE_OPS,
- GK_NORTHERN_ISLANDS,
- GK_CAYMAN,
- GK_GFX6,
- GK_GFX7,
- GK_GFX8,
- GK_GFX9
- } GPU;
-
- bool hasFP64:1;
- bool hasFMAF:1;
- bool hasLDEXPF:1;
- bool hasFullSpeedFP32Denorms:1;
-
- static bool isAMDGCN(const llvm::Triple &TT) {
- return TT.getArch() == llvm::Triple::amdgcn;
- }
-
-public:
- AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : TargetInfo(Triple) ,
- GPU(isAMDGCN(Triple) ? GK_GFX6 : GK_R600),
- hasFP64(false),
- hasFMAF(false),
- hasLDEXPF(false),
- hasFullSpeedFP32Denorms(false){
- if (getTriple().getArch() == llvm::Triple::amdgcn) {
- hasFP64 = true;
- hasFMAF = true;
- hasLDEXPF = true;
- }
-
- resetDataLayout(getTriple().getArch() == llvm::Triple::amdgcn ?
- DataLayoutStringSI : DataLayoutStringR600);
-
- AddrSpaceMap = &AMDGPUAddrSpaceMap;
- UseAddrSpaceMapMangling = true;
- }
-
- uint64_t getPointerWidthV(unsigned AddrSpace) const override {
- if (GPU <= GK_CAYMAN)
- return 32;
-
- switch(AddrSpace) {
- default:
- return 64;
- case 0:
- case 3:
- case 5:
- return 32;
- }
- }
-
- uint64_t getMaxPointerWidth() const override {
- return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32;
- }
-
- const char * getClobbers() const override {
- return "";
- }
-
- ArrayRef<const char *> getGCCRegNames() const override;
-
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
-
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- switch (*Name) {
- default: break;
- case 'v': // vgpr
- case 's': // sgpr
- Info.setAllowsRegister();
- return true;
- }
- return false;
- }
-
- bool initFeatureMap(llvm::StringMap<bool> &Features,
- DiagnosticsEngine &Diags, StringRef CPU,
- const std::vector<std::string> &FeatureVec) const override;
-
- void adjustTargetOptions(const CodeGenOptions &CGOpts,
- TargetOptions &TargetOpts) const override {
- bool hasFP32Denormals = false;
- bool hasFP64Denormals = false;
- for (auto &I : TargetOpts.FeaturesAsWritten) {
- if (I == "+fp32-denormals" || I == "-fp32-denormals")
- hasFP32Denormals = true;
- if (I == "+fp64-fp16-denormals" || I == "-fp64-fp16-denormals")
- hasFP64Denormals = true;
- }
- if (!hasFP32Denormals)
- TargetOpts.Features.push_back((Twine(hasFullSpeedFP32Denorms &&
- !CGOpts.FlushDenorm ? '+' : '-') + Twine("fp32-denormals")).str());
- // Always do not flush fp64 or fp16 denorms.
- if (!hasFP64Denormals && hasFP64)
- TargetOpts.Features.push_back("+fp64-fp16-denormals");
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin);
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- if (getTriple().getArch() == llvm::Triple::amdgcn)
- Builder.defineMacro("__AMDGCN__");
- else
- Builder.defineMacro("__R600__");
-
- if (hasFMAF)
- Builder.defineMacro("__HAS_FMAF__");
- if (hasLDEXPF)
- Builder.defineMacro("__HAS_LDEXPF__");
- if (hasFP64)
- Builder.defineMacro("__HAS_FP64__");
- }
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::CharPtrBuiltinVaList;
- }
-
- static GPUKind parseR600Name(StringRef Name) {
- return llvm::StringSwitch<GPUKind>(Name)
- .Case("r600" , GK_R600)
- .Case("rv610", GK_R600)
- .Case("rv620", GK_R600)
- .Case("rv630", GK_R600)
- .Case("rv635", GK_R600)
- .Case("rs780", GK_R600)
- .Case("rs880", GK_R600)
- .Case("rv670", GK_R600_DOUBLE_OPS)
- .Case("rv710", GK_R700)
- .Case("rv730", GK_R700)
- .Case("rv740", GK_R700_DOUBLE_OPS)
- .Case("rv770", GK_R700_DOUBLE_OPS)
- .Case("palm", GK_EVERGREEN)
- .Case("cedar", GK_EVERGREEN)
- .Case("sumo", GK_EVERGREEN)
- .Case("sumo2", GK_EVERGREEN)
- .Case("redwood", GK_EVERGREEN)
- .Case("juniper", GK_EVERGREEN)
- .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS)
- .Case("cypress", GK_EVERGREEN_DOUBLE_OPS)
- .Case("barts", GK_NORTHERN_ISLANDS)
- .Case("turks", GK_NORTHERN_ISLANDS)
- .Case("caicos", GK_NORTHERN_ISLANDS)
- .Case("cayman", GK_CAYMAN)
- .Case("aruba", GK_CAYMAN)
- .Default(GK_NONE);
- }
-
- static GPUKind parseAMDGCNName(StringRef Name) {
- return llvm::StringSwitch<GPUKind>(Name)
- .Case("tahiti", GK_GFX6)
- .Case("pitcairn", GK_GFX6)
- .Case("verde", GK_GFX6)
- .Case("oland", GK_GFX6)
- .Case("hainan", GK_GFX6)
- .Case("bonaire", GK_GFX7)
- .Case("kabini", GK_GFX7)
- .Case("kaveri", GK_GFX7)
- .Case("hawaii", GK_GFX7)
- .Case("mullins", GK_GFX7)
- .Case("gfx700", GK_GFX7)
- .Case("gfx701", GK_GFX7)
- .Case("gfx702", GK_GFX7)
- .Case("tonga", GK_GFX8)
- .Case("iceland", GK_GFX8)
- .Case("carrizo", GK_GFX8)
- .Case("fiji", GK_GFX8)
- .Case("stoney", GK_GFX8)
- .Case("polaris10", GK_GFX8)
- .Case("polaris11", GK_GFX8)
- .Case("gfx800", GK_GFX8)
- .Case("gfx801", GK_GFX8)
- .Case("gfx802", GK_GFX8)
- .Case("gfx803", GK_GFX8)
- .Case("gfx804", GK_GFX8)
- .Case("gfx810", GK_GFX8)
- .Case("gfx900", GK_GFX9)
- .Case("gfx901", GK_GFX9)
- .Default(GK_NONE);
- }
-
- bool setCPU(const std::string &Name) override {
- if (getTriple().getArch() == llvm::Triple::amdgcn)
- GPU = parseAMDGCNName(Name);
- else
- GPU = parseR600Name(Name);
-
- return GPU != GK_NONE;
- }
-
- void setSupportedOpenCLOpts() override {
- auto &Opts = getSupportedOpenCLOpts();
- Opts.support("cl_clang_storage_class_specifiers");
- Opts.support("cl_khr_icd");
-
- if (hasFP64)
- Opts.support("cl_khr_fp64");
- if (GPU >= GK_EVERGREEN) {
- Opts.support("cl_khr_byte_addressable_store");
- Opts.support("cl_khr_global_int32_base_atomics");
- Opts.support("cl_khr_global_int32_extended_atomics");
- Opts.support("cl_khr_local_int32_base_atomics");
- Opts.support("cl_khr_local_int32_extended_atomics");
- }
- if (GPU >= GK_GFX6) {
- Opts.support("cl_khr_fp16");
- Opts.support("cl_khr_int64_base_atomics");
- Opts.support("cl_khr_int64_extended_atomics");
- Opts.support("cl_khr_mipmap_image");
- Opts.support("cl_khr_subgroups");
- Opts.support("cl_khr_3d_image_writes");
- Opts.support("cl_amd_media_ops");
- Opts.support("cl_amd_media_ops2");
- }
- }
-
- LangAS::ID getOpenCLImageAddrSpace() const override {
- 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 {
- switch (AddressSpace) {
- case 0: // LLVM Private.
- return 1; // DWARF Private.
- case 3: // LLVM Local.
- return 2; // DWARF Local.
- default:
- return None;
- }
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- switch (CC) {
- default:
- return CCCR_Warning;
- case CC_C:
- case CC_OpenCLKernel:
- return CCCR_OK;
- }
- }
-
- // In amdgcn target the null pointer in global, constant, and generic
- // 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 ? ~0 : 0;
- }
-};
-
-const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE },
-#include "clang/Basic/BuiltinsAMDGPU.def"
-};
-const char * const AMDGPUTargetInfo::GCCRegNames[] = {
- "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
- "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
- "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
- "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
- "v32", "v33", "v34", "v35", "v36", "v37", "v38", "v39",
- "v40", "v41", "v42", "v43", "v44", "v45", "v46", "v47",
- "v48", "v49", "v50", "v51", "v52", "v53", "v54", "v55",
- "v56", "v57", "v58", "v59", "v60", "v61", "v62", "v63",
- "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71",
- "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79",
- "v80", "v81", "v82", "v83", "v84", "v85", "v86", "v87",
- "v88", "v89", "v90", "v91", "v92", "v93", "v94", "v95",
- "v96", "v97", "v98", "v99", "v100", "v101", "v102", "v103",
- "v104", "v105", "v106", "v107", "v108", "v109", "v110", "v111",
- "v112", "v113", "v114", "v115", "v116", "v117", "v118", "v119",
- "v120", "v121", "v122", "v123", "v124", "v125", "v126", "v127",
- "v128", "v129", "v130", "v131", "v132", "v133", "v134", "v135",
- "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143",
- "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151",
- "v152", "v153", "v154", "v155", "v156", "v157", "v158", "v159",
- "v160", "v161", "v162", "v163", "v164", "v165", "v166", "v167",
- "v168", "v169", "v170", "v171", "v172", "v173", "v174", "v175",
- "v176", "v177", "v178", "v179", "v180", "v181", "v182", "v183",
- "v184", "v185", "v186", "v187", "v188", "v189", "v190", "v191",
- "v192", "v193", "v194", "v195", "v196", "v197", "v198", "v199",
- "v200", "v201", "v202", "v203", "v204", "v205", "v206", "v207",
- "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215",
- "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223",
- "v224", "v225", "v226", "v227", "v228", "v229", "v230", "v231",
- "v232", "v233", "v234", "v235", "v236", "v237", "v238", "v239",
- "v240", "v241", "v242", "v243", "v244", "v245", "v246", "v247",
- "v248", "v249", "v250", "v251", "v252", "v253", "v254", "v255",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
- "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
- "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
- "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39",
- "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47",
- "s48", "s49", "s50", "s51", "s52", "s53", "s54", "s55",
- "s56", "s57", "s58", "s59", "s60", "s61", "s62", "s63",
- "s64", "s65", "s66", "s67", "s68", "s69", "s70", "s71",
- "s72", "s73", "s74", "s75", "s76", "s77", "s78", "s79",
- "s80", "s81", "s82", "s83", "s84", "s85", "s86", "s87",
- "s88", "s89", "s90", "s91", "s92", "s93", "s94", "s95",
- "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103",
- "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111",
- "s112", "s113", "s114", "s115", "s116", "s117", "s118", "s119",
- "s120", "s121", "s122", "s123", "s124", "s125", "s126", "s127",
- "exec", "vcc", "scc", "m0", "flat_scratch", "exec_lo", "exec_hi",
- "vcc_lo", "vcc_hi", "flat_scratch_lo", "flat_scratch_hi"
-};
-
-ArrayRef<const char *> AMDGPUTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-bool AMDGPUTargetInfo::initFeatureMap(
- llvm::StringMap<bool> &Features,
- DiagnosticsEngine &Diags, StringRef CPU,
- const std::vector<std::string> &FeatureVec) const {
-
- // XXX - What does the member GPU mean if device name string passed here?
- if (getTriple().getArch() == llvm::Triple::amdgcn) {
- if (CPU.empty())
- CPU = "tahiti";
-
- switch (parseAMDGCNName(CPU)) {
- case GK_GFX6:
- 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:
- return false;
- default:
- llvm_unreachable("unhandled subtarget");
- }
- } else {
- if (CPU.empty())
- CPU = "r600";
-
- switch (parseR600Name(CPU)) {
- case GK_R600:
- case GK_R700:
- case GK_EVERGREEN:
- case GK_NORTHERN_ISLANDS:
- break;
- case GK_R600_DOUBLE_OPS:
- case GK_R700_DOUBLE_OPS:
- case GK_EVERGREEN_DOUBLE_OPS:
- case GK_CAYMAN:
- Features["fp64"] = true;
- break;
- case GK_NONE:
- return false;
- default:
- llvm_unreachable("unhandled subtarget");
- }
- }
-
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec);
-}
-
-const Builtin::Info BuiltinInfoX86[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE },
-#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- { #ID, TYPE, ATTRS, HEADER, LANGS, FEATURE },
-#include "clang/Basic/BuiltinsX86.def"
-
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE },
-#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- { #ID, TYPE, ATTRS, HEADER, LANGS, FEATURE },
-#include "clang/Basic/BuiltinsX86_64.def"
-};
-
-
-static const char* const GCCRegNames[] = {
- "ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
- "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
- "argp", "flags", "fpcr", "fpsr", "dirflag", "frame",
- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
- "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
- "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
- "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15",
- "xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23",
- "xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31",
- "ymm16", "ymm17", "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", "ymm23",
- "ymm24", "ymm25", "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31",
- "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7",
- "zmm8", "zmm9", "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15",
- "zmm16", "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23",
- "zmm24", "zmm25", "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31",
- "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7",
-};
-
-const TargetInfo::AddlRegName AddlRegNames[] = {
- { { "al", "ah", "eax", "rax" }, 0 },
- { { "bl", "bh", "ebx", "rbx" }, 3 },
- { { "cl", "ch", "ecx", "rcx" }, 2 },
- { { "dl", "dh", "edx", "rdx" }, 1 },
- { { "esi", "rsi" }, 4 },
- { { "edi", "rdi" }, 5 },
- { { "esp", "rsp" }, 7 },
- { { "ebp", "rbp" }, 6 },
- { { "r8d", "r8w", "r8b" }, 38 },
- { { "r9d", "r9w", "r9b" }, 39 },
- { { "r10d", "r10w", "r10b" }, 40 },
- { { "r11d", "r11w", "r11b" }, 41 },
- { { "r12d", "r12w", "r12b" }, 42 },
- { { "r13d", "r13w", "r13b" }, 43 },
- { { "r14d", "r14w", "r14b" }, 44 },
- { { "r15d", "r15w", "r15b" }, 45 },
-};
-
-// X86 target abstract base class; x86-32 and x86-64 are very close, so
-// most of the implementation can be shared.
-class X86TargetInfo : public TargetInfo {
- enum X86SSEEnum {
- NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512F
- } SSELevel = NoSSE;
- enum MMX3DNowEnum {
- NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon
- } MMX3DNowLevel = NoMMX3DNow;
- enum XOPEnum {
- NoXOP,
- SSE4A,
- FMA4,
- XOP
- } XOPLevel = NoXOP;
-
- bool HasAES = false;
- bool HasPCLMUL = false;
- bool HasLZCNT = false;
- bool HasRDRND = false;
- bool HasFSGSBASE = false;
- bool HasBMI = false;
- bool HasBMI2 = false;
- bool HasPOPCNT = false;
- bool HasRTM = false;
- bool HasPRFCHW = false;
- bool HasRDSEED = false;
- bool HasADX = false;
- bool HasTBM = false;
- bool HasFMA = false;
- bool HasF16C = false;
- bool HasAVX512CD = false;
- bool HasAVX512ER = false;
- bool HasAVX512PF = false;
- bool HasAVX512DQ = false;
- bool HasAVX512BW = false;
- bool HasAVX512VL = false;
- bool HasAVX512VBMI = false;
- bool HasAVX512IFMA = false;
- bool HasSHA = false;
- bool HasMPX = false;
- bool HasSGX = false;
- bool HasCX16 = false;
- bool HasFXSR = false;
- bool HasXSAVE = false;
- bool HasXSAVEOPT = false;
- bool HasXSAVEC = false;
- bool HasXSAVES = false;
- bool HasMWAITX = false;
- bool HasCLZERO = false;
- bool HasPKU = false;
- bool HasCLFLUSHOPT = false;
- bool HasCLWB = false;
- bool HasMOVBE = false;
- bool HasPREFETCHWT1 = false;
-
- /// \brief Enumeration of all of the X86 CPUs supported by Clang.
- ///
- /// Each enumeration represents a particular CPU supported by Clang. These
- /// loosely correspond to the options passed to '-march' or '-mtune' flags.
- enum CPUKind {
- CK_Generic,
-
- /// \name i386
- /// i386-generation processors.
- //@{
- CK_i386,
- //@}
-
- /// \name i486
- /// i486-generation processors.
- //@{
- CK_i486,
- CK_WinChipC6,
- CK_WinChip2,
- CK_C3,
- //@}
-
- /// \name i586
- /// i586-generation processors, P5 microarchitecture based.
- //@{
- CK_i586,
- CK_Pentium,
- CK_PentiumMMX,
- //@}
-
- /// \name i686
- /// i686-generation processors, P6 / Pentium M microarchitecture based.
- //@{
- CK_i686,
- CK_PentiumPro,
- CK_Pentium2,
- CK_Pentium3,
- CK_Pentium3M,
- CK_PentiumM,
- CK_C3_2,
-
- /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah.
- /// Clang however has some logic to suport this.
- // FIXME: Warn, deprecate, and potentially remove this.
- CK_Yonah,
- //@}
-
- /// \name Netburst
- /// Netburst microarchitecture based processors.
- //@{
- CK_Pentium4,
- CK_Pentium4M,
- CK_Prescott,
- CK_Nocona,
- //@}
-
- /// \name Core
- /// Core microarchitecture based processors.
- //@{
- CK_Core2,
-
- /// This enumerator, like \see CK_Yonah, is a bit odd. It is another
- /// codename which GCC no longer accepts as an option to -march, but Clang
- /// has some logic for recognizing it.
- // FIXME: Warn, deprecate, and potentially remove this.
- CK_Penryn,
- //@}
-
- /// \name Atom
- /// Atom processors
- //@{
- CK_Bonnell,
- CK_Silvermont,
- //@}
-
- /// \name Nehalem
- /// Nehalem microarchitecture based processors.
- CK_Nehalem,
-
- /// \name Westmere
- /// Westmere microarchitecture based processors.
- CK_Westmere,
-
- /// \name Sandy Bridge
- /// Sandy Bridge microarchitecture based processors.
- CK_SandyBridge,
-
- /// \name Ivy Bridge
- /// Ivy Bridge microarchitecture based processors.
- CK_IvyBridge,
-
- /// \name Haswell
- /// Haswell microarchitecture based processors.
- CK_Haswell,
-
- /// \name Broadwell
- /// Broadwell microarchitecture based processors.
- CK_Broadwell,
-
- /// \name Skylake Client
- /// Skylake client microarchitecture based processors.
- CK_SkylakeClient,
-
- /// \name Skylake Server
- /// Skylake server microarchitecture based processors.
- CK_SkylakeServer,
-
- /// \name Cannonlake Client
- /// Cannonlake client microarchitecture based processors.
- CK_Cannonlake,
-
- /// \name Knights Landing
- /// Knights Landing processor.
- CK_KNL,
-
- /// \name Lakemont
- /// Lakemont microarchitecture based processors.
- CK_Lakemont,
-
- /// \name K6
- /// K6 architecture processors.
- //@{
- CK_K6,
- CK_K6_2,
- CK_K6_3,
- //@}
-
- /// \name K7
- /// K7 architecture processors.
- //@{
- CK_Athlon,
- CK_AthlonThunderbird,
- CK_Athlon4,
- CK_AthlonXP,
- CK_AthlonMP,
- //@}
-
- /// \name K8
- /// K8 architecture processors.
- //@{
- CK_Athlon64,
- CK_Athlon64SSE3,
- CK_AthlonFX,
- CK_K8,
- CK_K8SSE3,
- CK_Opteron,
- CK_OpteronSSE3,
- CK_AMDFAM10,
- //@}
-
- /// \name Bobcat
- /// Bobcat architecture processors.
- //@{
- CK_BTVER1,
- CK_BTVER2,
- //@}
-
- /// \name Bulldozer
- /// Bulldozer architecture processors.
- //@{
- CK_BDVER1,
- CK_BDVER2,
- CK_BDVER3,
- CK_BDVER4,
- //@}
-
- /// \name zen
- /// Zen architecture processors.
- //@{
- CK_ZNVER1,
- //@}
-
- /// This specification is deprecated and will be removed in the future.
- /// Users should prefer \see CK_K8.
- // FIXME: Warn on this when the CPU is set to it.
- //@{
- CK_x86_64,
- //@}
-
- /// \name Geode
- /// Geode processors.
- //@{
- CK_Geode
- //@}
- } CPU = CK_Generic;
-
- CPUKind getCPUKind(StringRef CPU) const {
- return llvm::StringSwitch<CPUKind>(CPU)
- .Case("i386", CK_i386)
- .Case("i486", CK_i486)
- .Case("winchip-c6", CK_WinChipC6)
- .Case("winchip2", CK_WinChip2)
- .Case("c3", CK_C3)
- .Case("i586", CK_i586)
- .Case("pentium", CK_Pentium)
- .Case("pentium-mmx", CK_PentiumMMX)
- .Case("i686", CK_i686)
- .Case("pentiumpro", CK_PentiumPro)
- .Case("pentium2", CK_Pentium2)
- .Case("pentium3", CK_Pentium3)
- .Case("pentium3m", CK_Pentium3M)
- .Case("pentium-m", CK_PentiumM)
- .Case("c3-2", CK_C3_2)
- .Case("yonah", CK_Yonah)
- .Case("pentium4", CK_Pentium4)
- .Case("pentium4m", CK_Pentium4M)
- .Case("prescott", CK_Prescott)
- .Case("nocona", CK_Nocona)
- .Case("core2", CK_Core2)
- .Case("penryn", CK_Penryn)
- .Case("bonnell", CK_Bonnell)
- .Case("atom", CK_Bonnell) // Legacy name.
- .Case("silvermont", CK_Silvermont)
- .Case("slm", CK_Silvermont) // Legacy name.
- .Case("nehalem", CK_Nehalem)
- .Case("corei7", CK_Nehalem) // Legacy name.
- .Case("westmere", CK_Westmere)
- .Case("sandybridge", CK_SandyBridge)
- .Case("corei7-avx", CK_SandyBridge) // Legacy name.
- .Case("ivybridge", CK_IvyBridge)
- .Case("core-avx-i", CK_IvyBridge) // Legacy name.
- .Case("haswell", CK_Haswell)
- .Case("core-avx2", CK_Haswell) // Legacy name.
- .Case("broadwell", CK_Broadwell)
- .Case("skylake", CK_SkylakeClient)
- .Case("skylake-avx512", CK_SkylakeServer)
- .Case("skx", CK_SkylakeServer) // Legacy name.
- .Case("cannonlake", CK_Cannonlake)
- .Case("knl", CK_KNL)
- .Case("lakemont", CK_Lakemont)
- .Case("k6", CK_K6)
- .Case("k6-2", CK_K6_2)
- .Case("k6-3", CK_K6_3)
- .Case("athlon", CK_Athlon)
- .Case("athlon-tbird", CK_AthlonThunderbird)
- .Case("athlon-4", CK_Athlon4)
- .Case("athlon-xp", CK_AthlonXP)
- .Case("athlon-mp", CK_AthlonMP)
- .Case("athlon64", CK_Athlon64)
- .Case("athlon64-sse3", CK_Athlon64SSE3)
- .Case("athlon-fx", CK_AthlonFX)
- .Case("k8", CK_K8)
- .Case("k8-sse3", CK_K8SSE3)
- .Case("opteron", CK_Opteron)
- .Case("opteron-sse3", CK_OpteronSSE3)
- .Case("barcelona", CK_AMDFAM10)
- .Case("amdfam10", CK_AMDFAM10)
- .Case("btver1", CK_BTVER1)
- .Case("btver2", CK_BTVER2)
- .Case("bdver1", CK_BDVER1)
- .Case("bdver2", CK_BDVER2)
- .Case("bdver3", CK_BDVER3)
- .Case("bdver4", CK_BDVER4)
- .Case("znver1", CK_ZNVER1)
- .Case("x86-64", CK_x86_64)
- .Case("geode", CK_Geode)
- .Default(CK_Generic);
- }
-
- enum FPMathKind {
- FP_Default,
- FP_SSE,
- FP_387
- } FPMath = FP_Default;
-
-public:
- X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
- }
- unsigned getFloatEvalMethod() const override {
- // X87 evaluates with 80 bits "long double" precision.
- return SSELevel == NoSSE ? 2 : 0;
- }
- ArrayRef<const char *> getGCCRegNames() const override {
- return llvm::makeArrayRef(GCCRegNames);
- }
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
- ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override {
- return llvm::makeArrayRef(AddlRegNames);
- }
- bool validateCpuSupports(StringRef Name) const override;
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override;
-
- bool validateGlobalRegisterVariable(StringRef RegName,
- unsigned RegSize,
- bool &HasSizeMismatch) const override {
- // esp and ebp are the only 32-bit registers the x86 backend can currently
- // handle.
- if (RegName.equals("esp") || RegName.equals("ebp")) {
- // Check that the register size is 32-bit.
- HasSizeMismatch = RegSize != 32;
- return true;
- }
-
- return false;
- }
-
- bool validateOutputSize(StringRef Constraint, unsigned Size) const override;
-
- bool validateInputSize(StringRef Constraint, unsigned Size) const override;
-
- virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const;
-
- std::string convertConstraint(const char *&Constraint) const override;
- const char *getClobbers() const override {
- return "~{dirflag},~{fpsr},~{flags}";
- }
-
- StringRef getConstraintRegister(const StringRef &Constraint,
- const StringRef &Expression) const override {
- StringRef::iterator I, E;
- for (I = Constraint.begin(), E = Constraint.end(); I != E; ++I) {
- if (isalpha(*I))
- break;
- }
- if (I == E)
- return "";
- switch (*I) {
- // For the register constraints, return the matching register name
- case 'a':
- return "ax";
- case 'b':
- return "bx";
- case 'c':
- return "cx";
- case 'd':
- return "dx";
- case 'S':
- return "si";
- case 'D':
- return "di";
- // In case the constraint is 'r' we need to return Expression
- case 'r':
- return Expression;
- default:
- // Default value if there is no constraint for the register
- return "";
- }
- return "";
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override;
- static void setSSELevel(llvm::StringMap<bool> &Features, X86SSEEnum Level,
- bool Enabled);
- static void setMMXLevel(llvm::StringMap<bool> &Features, MMX3DNowEnum Level,
- bool Enabled);
- static void setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
- bool Enabled);
- void setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name, bool Enabled) const override {
- setFeatureEnabledImpl(Features, Name, Enabled);
- }
- // This exists purely to cut down on the number of virtual calls in
- // initFeatureMap which calls this repeatedly.
- static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
- StringRef Name, bool Enabled);
- bool
- initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const override;
- bool hasFeature(StringRef Feature) const override;
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override;
- StringRef getABI() const override {
- if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F)
- return "avx512";
- if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
- return "avx";
- if (getTriple().getArch() == llvm::Triple::x86 &&
- MMX3DNowLevel == NoMMX3DNow)
- return "no-mmx";
- return "";
- }
- bool setCPU(const std::string &Name) override {
- CPU = getCPUKind(Name);
-
- // Perform any per-CPU checks necessary to determine if this CPU is
- // acceptable.
- // FIXME: This results in terrible diagnostics. Clang just says the CPU is
- // invalid without explaining *why*.
- switch (CPU) {
- case CK_Generic:
- // No processor selected!
- return false;
-
- case CK_i386:
- case CK_i486:
- case CK_WinChipC6:
- case CK_WinChip2:
- case CK_C3:
- case CK_i586:
- case CK_Pentium:
- case CK_PentiumMMX:
- case CK_i686:
- case CK_PentiumPro:
- case CK_Pentium2:
- case CK_Pentium3:
- case CK_Pentium3M:
- case CK_PentiumM:
- case CK_Yonah:
- case CK_C3_2:
- case CK_Pentium4:
- case CK_Pentium4M:
- case CK_Lakemont:
- case CK_Prescott:
- case CK_K6:
- case CK_K6_2:
- case CK_K6_3:
- case CK_Athlon:
- case CK_AthlonThunderbird:
- case CK_Athlon4:
- case CK_AthlonXP:
- case CK_AthlonMP:
- case CK_Geode:
- // Only accept certain architectures when compiling in 32-bit mode.
- if (getTriple().getArch() != llvm::Triple::x86)
- return false;
-
- // Fallthrough
- case CK_Nocona:
- case CK_Core2:
- case CK_Penryn:
- case CK_Bonnell:
- case CK_Silvermont:
- case CK_Nehalem:
- case CK_Westmere:
- case CK_SandyBridge:
- case CK_IvyBridge:
- case CK_Haswell:
- case CK_Broadwell:
- case CK_SkylakeClient:
- case CK_SkylakeServer:
- case CK_Cannonlake:
- case CK_KNL:
- case CK_Athlon64:
- case CK_Athlon64SSE3:
- case CK_AthlonFX:
- case CK_K8:
- case CK_K8SSE3:
- case CK_Opteron:
- case CK_OpteronSSE3:
- case CK_AMDFAM10:
- case CK_BTVER1:
- case CK_BTVER2:
- case CK_BDVER1:
- case CK_BDVER2:
- case CK_BDVER3:
- case CK_BDVER4:
- case CK_ZNVER1:
- case CK_x86_64:
- return true;
- }
- llvm_unreachable("Unhandled CPU kind");
- }
-
- bool setFPMath(StringRef Name) override;
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- // Most of the non-ARM calling conventions are i386 conventions.
- switch (CC) {
- case CC_X86ThisCall:
- case CC_X86FastCall:
- case CC_X86StdCall:
- case CC_X86VectorCall:
- case CC_X86RegCall:
- case CC_C:
- case CC_Swift:
- case CC_X86Pascal:
- case CC_IntelOclBicc:
- return CCCR_OK;
- default:
- return CCCR_Warning;
- }
- }
-
- CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
- return MT == CCMT_Member ? CC_X86ThisCall : CC_C;
- }
-
- bool hasSjLjLowering() const override {
- return true;
- }
-
- void setSupportedOpenCLOpts() override {
- getSupportedOpenCLOpts().supportAll();
- }
-};
-
-bool X86TargetInfo::setFPMath(StringRef Name) {
- if (Name == "387") {
- FPMath = FP_387;
- return true;
- }
- if (Name == "sse") {
- FPMath = FP_SSE;
- return true;
- }
- return false;
-}
-
-bool X86TargetInfo::initFeatureMap(
- llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const {
- // FIXME: This *really* should not be here.
- // X86_64 always has SSE2.
- if (getTriple().getArch() == llvm::Triple::x86_64)
- setFeatureEnabledImpl(Features, "sse2", true);
-
- const CPUKind Kind = getCPUKind(CPU);
-
- // Enable X87 for all X86 processors but Lakemont.
- if (Kind != CK_Lakemont)
- setFeatureEnabledImpl(Features, "x87", true);
-
- switch (Kind) {
- case CK_Generic:
- case CK_i386:
- case CK_i486:
- case CK_i586:
- case CK_Pentium:
- case CK_i686:
- case CK_PentiumPro:
- case CK_Lakemont:
- break;
- case CK_PentiumMMX:
- case CK_Pentium2:
- case CK_K6:
- case CK_WinChipC6:
- setFeatureEnabledImpl(Features, "mmx", true);
- break;
- case CK_Pentium3:
- case CK_Pentium3M:
- case CK_C3_2:
- setFeatureEnabledImpl(Features, "sse", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- break;
- case CK_PentiumM:
- case CK_Pentium4:
- case CK_Pentium4M:
- case CK_x86_64:
- setFeatureEnabledImpl(Features, "sse2", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- break;
- case CK_Yonah:
- case CK_Prescott:
- case CK_Nocona:
- setFeatureEnabledImpl(Features, "sse3", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- break;
- case CK_Core2:
- case CK_Bonnell:
- setFeatureEnabledImpl(Features, "ssse3", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- break;
- case CK_Penryn:
- setFeatureEnabledImpl(Features, "sse4.1", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- break;
- case CK_Cannonlake:
- setFeatureEnabledImpl(Features, "avx512ifma", true);
- setFeatureEnabledImpl(Features, "avx512vbmi", true);
- setFeatureEnabledImpl(Features, "sha", true);
- LLVM_FALLTHROUGH;
- case CK_SkylakeServer:
- setFeatureEnabledImpl(Features, "avx512f", true);
- setFeatureEnabledImpl(Features, "avx512cd", true);
- setFeatureEnabledImpl(Features, "avx512dq", true);
- setFeatureEnabledImpl(Features, "avx512bw", true);
- setFeatureEnabledImpl(Features, "avx512vl", true);
- setFeatureEnabledImpl(Features, "pku", true);
- setFeatureEnabledImpl(Features, "clwb", true);
- 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);
- LLVM_FALLTHROUGH;
- case CK_Broadwell:
- setFeatureEnabledImpl(Features, "rdseed", true);
- setFeatureEnabledImpl(Features, "adx", true);
- 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);
- LLVM_FALLTHROUGH;
- case CK_IvyBridge:
- setFeatureEnabledImpl(Features, "rdrnd", true);
- setFeatureEnabledImpl(Features, "f16c", true);
- setFeatureEnabledImpl(Features, "fsgsbase", true);
- LLVM_FALLTHROUGH;
- case CK_SandyBridge:
- setFeatureEnabledImpl(Features, "avx", true);
- setFeatureEnabledImpl(Features, "xsave", true);
- setFeatureEnabledImpl(Features, "xsaveopt", true);
- LLVM_FALLTHROUGH;
- case CK_Westmere:
- case CK_Silvermont:
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- LLVM_FALLTHROUGH;
- case CK_Nehalem:
- setFeatureEnabledImpl(Features, "sse4.2", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- break;
- case CK_KNL:
- setFeatureEnabledImpl(Features, "avx512f", true);
- setFeatureEnabledImpl(Features, "avx512cd", true);
- setFeatureEnabledImpl(Features, "avx512er", true);
- setFeatureEnabledImpl(Features, "avx512pf", true);
- setFeatureEnabledImpl(Features, "prefetchwt1", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- setFeatureEnabledImpl(Features, "rdseed", true);
- setFeatureEnabledImpl(Features, "adx", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "bmi", true);
- setFeatureEnabledImpl(Features, "bmi2", true);
- setFeatureEnabledImpl(Features, "rtm", true);
- setFeatureEnabledImpl(Features, "fma", true);
- setFeatureEnabledImpl(Features, "rdrnd", true);
- setFeatureEnabledImpl(Features, "f16c", true);
- setFeatureEnabledImpl(Features, "fsgsbase", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- setFeatureEnabledImpl(Features, "xsaveopt", true);
- setFeatureEnabledImpl(Features, "xsave", true);
- setFeatureEnabledImpl(Features, "movbe", true);
- break;
- case CK_K6_2:
- case CK_K6_3:
- case CK_WinChip2:
- case CK_C3:
- setFeatureEnabledImpl(Features, "3dnow", true);
- break;
- case CK_Athlon:
- case CK_AthlonThunderbird:
- case CK_Geode:
- setFeatureEnabledImpl(Features, "3dnowa", true);
- break;
- case CK_Athlon4:
- case CK_AthlonXP:
- case CK_AthlonMP:
- setFeatureEnabledImpl(Features, "sse", true);
- setFeatureEnabledImpl(Features, "3dnowa", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- break;
- case CK_K8:
- case CK_Opteron:
- case CK_Athlon64:
- case CK_AthlonFX:
- setFeatureEnabledImpl(Features, "sse2", true);
- setFeatureEnabledImpl(Features, "3dnowa", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- break;
- case CK_AMDFAM10:
- setFeatureEnabledImpl(Features, "sse4a", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "popcnt", true);
- LLVM_FALLTHROUGH;
- case CK_K8SSE3:
- case CK_OpteronSSE3:
- case CK_Athlon64SSE3:
- setFeatureEnabledImpl(Features, "sse3", true);
- setFeatureEnabledImpl(Features, "3dnowa", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- break;
- case CK_BTVER2:
- setFeatureEnabledImpl(Features, "avx", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- setFeatureEnabledImpl(Features, "bmi", true);
- setFeatureEnabledImpl(Features, "f16c", true);
- setFeatureEnabledImpl(Features, "xsaveopt", true);
- LLVM_FALLTHROUGH;
- case CK_BTVER1:
- setFeatureEnabledImpl(Features, "ssse3", true);
- setFeatureEnabledImpl(Features, "sse4a", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "popcnt", true);
- setFeatureEnabledImpl(Features, "prfchw", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- break;
- case CK_ZNVER1:
- setFeatureEnabledImpl(Features, "adx", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "avx2", true);
- 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);
- setFeatureEnabledImpl(Features, "fsgsbase", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "mwaitx", true);
- setFeatureEnabledImpl(Features, "movbe", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- setFeatureEnabledImpl(Features, "popcnt", true);
- setFeatureEnabledImpl(Features, "prfchw", true);
- setFeatureEnabledImpl(Features, "rdrnd", true);
- setFeatureEnabledImpl(Features, "rdseed", true);
- setFeatureEnabledImpl(Features, "sha", true);
- setFeatureEnabledImpl(Features, "sse4a", true);
- setFeatureEnabledImpl(Features, "xsave", true);
- setFeatureEnabledImpl(Features, "xsavec", true);
- setFeatureEnabledImpl(Features, "xsaveopt", true);
- setFeatureEnabledImpl(Features, "xsaves", true);
- break;
- case CK_BDVER4:
- setFeatureEnabledImpl(Features, "avx2", true);
- setFeatureEnabledImpl(Features, "bmi2", true);
- setFeatureEnabledImpl(Features, "mwaitx", true);
- LLVM_FALLTHROUGH;
- case CK_BDVER3:
- setFeatureEnabledImpl(Features, "fsgsbase", true);
- setFeatureEnabledImpl(Features, "xsaveopt", true);
- LLVM_FALLTHROUGH;
- case CK_BDVER2:
- setFeatureEnabledImpl(Features, "bmi", true);
- setFeatureEnabledImpl(Features, "fma", true);
- setFeatureEnabledImpl(Features, "f16c", true);
- setFeatureEnabledImpl(Features, "tbm", true);
- LLVM_FALLTHROUGH;
- case CK_BDVER1:
- // xop implies avx, sse4a and fma4.
- setFeatureEnabledImpl(Features, "xop", true);
- setFeatureEnabledImpl(Features, "lzcnt", true);
- setFeatureEnabledImpl(Features, "aes", true);
- setFeatureEnabledImpl(Features, "pclmul", true);
- setFeatureEnabledImpl(Features, "prfchw", true);
- setFeatureEnabledImpl(Features, "cx16", true);
- setFeatureEnabledImpl(Features, "fxsr", true);
- setFeatureEnabledImpl(Features, "xsave", true);
- break;
- }
- if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec))
- return false;
-
- // Can't do this earlier because we need to be able to explicitly enable
- // or disable these features and the things that they depend upon.
-
- // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled.
- auto I = Features.find("sse4.2");
- if (I != Features.end() && I->getValue() &&
- std::find(FeaturesVec.begin(), FeaturesVec.end(), "-popcnt") ==
- FeaturesVec.end())
- Features["popcnt"] = true;
-
- // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled.
- I = Features.find("3dnow");
- if (I != Features.end() && I->getValue() &&
- std::find(FeaturesVec.begin(), FeaturesVec.end(), "-prfchw") ==
- FeaturesVec.end())
- Features["prfchw"] = true;
-
- // Additionally, if SSE is enabled and mmx is not explicitly disabled,
- // then enable MMX.
- I = Features.find("sse");
- if (I != Features.end() && I->getValue() &&
- std::find(FeaturesVec.begin(), FeaturesVec.end(), "-mmx") ==
- FeaturesVec.end())
- Features["mmx"] = true;
-
- return true;
-}
-
-void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features,
- X86SSEEnum Level, bool Enabled) {
- if (Enabled) {
- switch (Level) {
- case AVX512F:
- Features["avx512f"] = true;
- case AVX2:
- Features["avx2"] = true;
- case AVX:
- Features["avx"] = true;
- Features["xsave"] = true;
- case SSE42:
- Features["sse4.2"] = true;
- case SSE41:
- Features["sse4.1"] = true;
- case SSSE3:
- Features["ssse3"] = true;
- case SSE3:
- Features["sse3"] = true;
- case SSE2:
- Features["sse2"] = true;
- case SSE1:
- Features["sse"] = true;
- case NoSSE:
- break;
- }
- return;
- }
-
- switch (Level) {
- case NoSSE:
- case SSE1:
- Features["sse"] = false;
- case SSE2:
- Features["sse2"] = Features["pclmul"] = Features["aes"] =
- Features["sha"] = false;
- case SSE3:
- Features["sse3"] = false;
- setXOPLevel(Features, NoXOP, false);
- case SSSE3:
- Features["ssse3"] = false;
- case SSE41:
- Features["sse4.1"] = false;
- case SSE42:
- Features["sse4.2"] = false;
- case AVX:
- Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] =
- Features["xsaveopt"] = false;
- setXOPLevel(Features, FMA4, false);
- case AVX2:
- Features["avx2"] = false;
- case AVX512F:
- Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] =
- Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] =
- Features["avx512vl"] = Features["avx512vbmi"] =
- Features["avx512ifma"] = false;
- }
-}
-
-void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features,
- MMX3DNowEnum Level, bool Enabled) {
- if (Enabled) {
- switch (Level) {
- case AMD3DNowAthlon:
- Features["3dnowa"] = true;
- case AMD3DNow:
- Features["3dnow"] = true;
- case MMX:
- Features["mmx"] = true;
- case NoMMX3DNow:
- break;
- }
- return;
- }
-
- switch (Level) {
- case NoMMX3DNow:
- case MMX:
- Features["mmx"] = false;
- case AMD3DNow:
- Features["3dnow"] = false;
- case AMD3DNowAthlon:
- Features["3dnowa"] = false;
- }
-}
-
-void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
- bool Enabled) {
- if (Enabled) {
- switch (Level) {
- case XOP:
- Features["xop"] = true;
- case FMA4:
- Features["fma4"] = true;
- setSSELevel(Features, AVX, true);
- case SSE4A:
- Features["sse4a"] = true;
- setSSELevel(Features, SSE3, true);
- case NoXOP:
- break;
- }
- return;
- }
-
- switch (Level) {
- case NoXOP:
- case SSE4A:
- Features["sse4a"] = false;
- case FMA4:
- Features["fma4"] = false;
- case XOP:
- Features["xop"] = false;
- }
-}
-
-void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
- StringRef Name, bool Enabled) {
- // This is a bit of a hack to deal with the sse4 target feature when used
- // as part of the target attribute. We handle sse4 correctly everywhere
- // else. See below for more information on how we handle the sse4 options.
- if (Name != "sse4")
- Features[Name] = Enabled;
-
- if (Name == "mmx") {
- setMMXLevel(Features, MMX, Enabled);
- } else if (Name == "sse") {
- setSSELevel(Features, SSE1, Enabled);
- } else if (Name == "sse2") {
- setSSELevel(Features, SSE2, Enabled);
- } else if (Name == "sse3") {
- setSSELevel(Features, SSE3, Enabled);
- } else if (Name == "ssse3") {
- setSSELevel(Features, SSSE3, Enabled);
- } else if (Name == "sse4.2") {
- setSSELevel(Features, SSE42, Enabled);
- } else if (Name == "sse4.1") {
- setSSELevel(Features, SSE41, Enabled);
- } else if (Name == "3dnow") {
- setMMXLevel(Features, AMD3DNow, Enabled);
- } else if (Name == "3dnowa") {
- setMMXLevel(Features, AMD3DNowAthlon, Enabled);
- } else if (Name == "aes") {
- if (Enabled)
- setSSELevel(Features, SSE2, Enabled);
- } else if (Name == "pclmul") {
- if (Enabled)
- setSSELevel(Features, SSE2, Enabled);
- } else if (Name == "avx") {
- setSSELevel(Features, AVX, Enabled);
- } else if (Name == "avx2") {
- setSSELevel(Features, AVX2, Enabled);
- } else if (Name == "avx512f") {
- setSSELevel(Features, AVX512F, Enabled);
- } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" ||
- Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" ||
- Name == "avx512vbmi" || Name == "avx512ifma") {
- if (Enabled)
- setSSELevel(Features, AVX512F, Enabled);
- // Enable BWI instruction if VBMI is being enabled.
- if (Name == "avx512vbmi" && Enabled)
- Features["avx512bw"] = true;
- // Also disable VBMI if BWI is being disabled.
- if (Name == "avx512bw" && !Enabled)
- Features["avx512vbmi"] = false;
- } else if (Name == "fma") {
- if (Enabled)
- setSSELevel(Features, AVX, Enabled);
- } else if (Name == "fma4") {
- setXOPLevel(Features, FMA4, Enabled);
- } else if (Name == "xop") {
- setXOPLevel(Features, XOP, Enabled);
- } else if (Name == "sse4a") {
- setXOPLevel(Features, SSE4A, Enabled);
- } else if (Name == "f16c") {
- if (Enabled)
- setSSELevel(Features, AVX, Enabled);
- } else if (Name == "sha") {
- if (Enabled)
- setSSELevel(Features, SSE2, Enabled);
- } else if (Name == "sse4") {
- // We can get here via the __target__ attribute since that's not controlled
- // via the -msse4/-mno-sse4 command line alias. Handle this the same way
- // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if
- // disabled.
- if (Enabled)
- setSSELevel(Features, SSE42, Enabled);
- else
- setSSELevel(Features, SSE41, Enabled);
- } else if (Name == "xsave") {
- if (!Enabled)
- Features["xsaveopt"] = false;
- } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") {
- if (Enabled)
- Features["xsave"] = true;
- }
-}
-
-/// handleTargetFeatures - Perform initialization based on the user
-/// configured set of features.
-bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
- for (const auto &Feature : Features) {
- if (Feature[0] != '+')
- continue;
-
- if (Feature == "+aes") {
- HasAES = true;
- } else if (Feature == "+pclmul") {
- HasPCLMUL = true;
- } else if (Feature == "+lzcnt") {
- HasLZCNT = true;
- } else if (Feature == "+rdrnd") {
- HasRDRND = true;
- } else if (Feature == "+fsgsbase") {
- HasFSGSBASE = true;
- } else if (Feature == "+bmi") {
- HasBMI = true;
- } else if (Feature == "+bmi2") {
- HasBMI2 = true;
- } else if (Feature == "+popcnt") {
- HasPOPCNT = true;
- } else if (Feature == "+rtm") {
- HasRTM = true;
- } else if (Feature == "+prfchw") {
- HasPRFCHW = true;
- } else if (Feature == "+rdseed") {
- HasRDSEED = true;
- } else if (Feature == "+adx") {
- HasADX = true;
- } else if (Feature == "+tbm") {
- HasTBM = true;
- } else if (Feature == "+fma") {
- HasFMA = true;
- } else if (Feature == "+f16c") {
- HasF16C = true;
- } else if (Feature == "+avx512cd") {
- HasAVX512CD = true;
- } else if (Feature == "+avx512er") {
- HasAVX512ER = true;
- } else if (Feature == "+avx512pf") {
- HasAVX512PF = true;
- } else if (Feature == "+avx512dq") {
- HasAVX512DQ = true;
- } else if (Feature == "+avx512bw") {
- HasAVX512BW = true;
- } else if (Feature == "+avx512vl") {
- HasAVX512VL = true;
- } else if (Feature == "+avx512vbmi") {
- HasAVX512VBMI = true;
- } else if (Feature == "+avx512ifma") {
- HasAVX512IFMA = true;
- } else if (Feature == "+sha") {
- HasSHA = true;
- } else if (Feature == "+mpx") {
- HasMPX = true;
- } else if (Feature == "+movbe") {
- HasMOVBE = true;
- } else if (Feature == "+sgx") {
- HasSGX = true;
- } else if (Feature == "+cx16") {
- HasCX16 = true;
- } else if (Feature == "+fxsr") {
- HasFXSR = true;
- } else if (Feature == "+xsave") {
- HasXSAVE = true;
- } else if (Feature == "+xsaveopt") {
- HasXSAVEOPT = true;
- } else if (Feature == "+xsavec") {
- HasXSAVEC = true;
- } else if (Feature == "+xsaves") {
- HasXSAVES = true;
- } else if (Feature == "+mwaitx") {
- HasMWAITX = true;
- } else if (Feature == "+pku") {
- HasPKU = true;
- } else if (Feature == "+clflushopt") {
- HasCLFLUSHOPT = true;
- } else if (Feature == "+clwb") {
- HasCLWB = true;
- } else if (Feature == "+prefetchwt1") {
- HasPREFETCHWT1 = true;
- } else if (Feature == "+clzero") {
- HasCLZERO = true;
- }
-
- X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
- .Case("+avx512f", AVX512F)
- .Case("+avx2", AVX2)
- .Case("+avx", AVX)
- .Case("+sse4.2", SSE42)
- .Case("+sse4.1", SSE41)
- .Case("+ssse3", SSSE3)
- .Case("+sse3", SSE3)
- .Case("+sse2", SSE2)
- .Case("+sse", SSE1)
- .Default(NoSSE);
- SSELevel = std::max(SSELevel, Level);
-
- MMX3DNowEnum ThreeDNowLevel =
- llvm::StringSwitch<MMX3DNowEnum>(Feature)
- .Case("+3dnowa", AMD3DNowAthlon)
- .Case("+3dnow", AMD3DNow)
- .Case("+mmx", MMX)
- .Default(NoMMX3DNow);
- MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel);
-
- XOPEnum XLevel = llvm::StringSwitch<XOPEnum>(Feature)
- .Case("+xop", XOP)
- .Case("+fma4", FMA4)
- .Case("+sse4a", SSE4A)
- .Default(NoXOP);
- XOPLevel = std::max(XOPLevel, XLevel);
- }
-
- // LLVM doesn't have a separate switch for fpmath, so only accept it if it
- // matches the selected sse level.
- if ((FPMath == FP_SSE && SSELevel < SSE1) ||
- (FPMath == FP_387 && SSELevel >= SSE1)) {
- Diags.Report(diag::err_target_unsupported_fpmath) <<
- (FPMath == FP_SSE ? "sse" : "387");
- return false;
- }
-
- SimdDefaultAlign =
- hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
- return true;
-}
-
-/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro
-/// definitions for this particular subtarget.
-void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- // Target identification.
- if (getTriple().getArch() == llvm::Triple::x86_64) {
- Builder.defineMacro("__amd64__");
- Builder.defineMacro("__amd64");
- Builder.defineMacro("__x86_64");
- Builder.defineMacro("__x86_64__");
- if (getTriple().getArchName() == "x86_64h") {
- Builder.defineMacro("__x86_64h");
- Builder.defineMacro("__x86_64h__");
- }
- } else {
- DefineStd(Builder, "i386", Opts);
- }
-
- // Subtarget options.
- // FIXME: We are hard-coding the tune parameters based on the CPU, but they
- // truly should be based on -mtune options.
- switch (CPU) {
- case CK_Generic:
- break;
- case CK_i386:
- // The rest are coming from the i386 define above.
- Builder.defineMacro("__tune_i386__");
- break;
- case CK_i486:
- case CK_WinChipC6:
- case CK_WinChip2:
- case CK_C3:
- defineCPUMacros(Builder, "i486");
- break;
- case CK_PentiumMMX:
- Builder.defineMacro("__pentium_mmx__");
- Builder.defineMacro("__tune_pentium_mmx__");
- // Fallthrough
- case CK_i586:
- case CK_Pentium:
- defineCPUMacros(Builder, "i586");
- defineCPUMacros(Builder, "pentium");
- break;
- case CK_Pentium3:
- case CK_Pentium3M:
- case CK_PentiumM:
- Builder.defineMacro("__tune_pentium3__");
- // Fallthrough
- case CK_Pentium2:
- case CK_C3_2:
- Builder.defineMacro("__tune_pentium2__");
- // Fallthrough
- case CK_PentiumPro:
- Builder.defineMacro("__tune_i686__");
- Builder.defineMacro("__tune_pentiumpro__");
- // Fallthrough
- case CK_i686:
- Builder.defineMacro("__i686");
- Builder.defineMacro("__i686__");
- // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686.
- Builder.defineMacro("__pentiumpro");
- Builder.defineMacro("__pentiumpro__");
- break;
- case CK_Pentium4:
- case CK_Pentium4M:
- defineCPUMacros(Builder, "pentium4");
- break;
- case CK_Yonah:
- case CK_Prescott:
- case CK_Nocona:
- defineCPUMacros(Builder, "nocona");
- break;
- case CK_Core2:
- case CK_Penryn:
- defineCPUMacros(Builder, "core2");
- break;
- case CK_Bonnell:
- defineCPUMacros(Builder, "atom");
- break;
- case CK_Silvermont:
- defineCPUMacros(Builder, "slm");
- break;
- case CK_Nehalem:
- case CK_Westmere:
- case CK_SandyBridge:
- case CK_IvyBridge:
- case CK_Haswell:
- case CK_Broadwell:
- case CK_SkylakeClient:
- // FIXME: Historically, we defined this legacy name, it would be nice to
- // remove it at some point. We've never exposed fine-grained names for
- // recent primary x86 CPUs, and we should keep it that way.
- defineCPUMacros(Builder, "corei7");
- break;
- case CK_SkylakeServer:
- defineCPUMacros(Builder, "skx");
- break;
- case CK_Cannonlake:
- break;
- case CK_KNL:
- defineCPUMacros(Builder, "knl");
- break;
- case CK_Lakemont:
- Builder.defineMacro("__tune_lakemont__");
- break;
- case CK_K6_2:
- Builder.defineMacro("__k6_2__");
- Builder.defineMacro("__tune_k6_2__");
- // Fallthrough
- case CK_K6_3:
- if (CPU != CK_K6_2) { // In case of fallthrough
- // FIXME: GCC may be enabling these in cases where some other k6
- // architecture is specified but -m3dnow is explicitly provided. The
- // exact semantics need to be determined and emulated here.
- Builder.defineMacro("__k6_3__");
- Builder.defineMacro("__tune_k6_3__");
- }
- // Fallthrough
- case CK_K6:
- defineCPUMacros(Builder, "k6");
- break;
- case CK_Athlon:
- case CK_AthlonThunderbird:
- case CK_Athlon4:
- case CK_AthlonXP:
- case CK_AthlonMP:
- defineCPUMacros(Builder, "athlon");
- if (SSELevel != NoSSE) {
- Builder.defineMacro("__athlon_sse__");
- Builder.defineMacro("__tune_athlon_sse__");
- }
- break;
- case CK_K8:
- case CK_K8SSE3:
- case CK_x86_64:
- case CK_Opteron:
- case CK_OpteronSSE3:
- case CK_Athlon64:
- case CK_Athlon64SSE3:
- case CK_AthlonFX:
- defineCPUMacros(Builder, "k8");
- break;
- case CK_AMDFAM10:
- defineCPUMacros(Builder, "amdfam10");
- break;
- case CK_BTVER1:
- defineCPUMacros(Builder, "btver1");
- break;
- case CK_BTVER2:
- defineCPUMacros(Builder, "btver2");
- break;
- case CK_BDVER1:
- defineCPUMacros(Builder, "bdver1");
- break;
- case CK_BDVER2:
- defineCPUMacros(Builder, "bdver2");
- break;
- case CK_BDVER3:
- defineCPUMacros(Builder, "bdver3");
- break;
- case CK_BDVER4:
- defineCPUMacros(Builder, "bdver4");
- break;
- case CK_ZNVER1:
- defineCPUMacros(Builder, "znver1");
- break;
- case CK_Geode:
- defineCPUMacros(Builder, "geode");
- break;
- }
-
- // Target properties.
- Builder.defineMacro("__REGISTER_PREFIX__", "");
-
- // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
- // functions in glibc header files that use FP Stack inline asm which the
- // backend can't deal with (PR879).
- Builder.defineMacro("__NO_MATH_INLINES");
-
- if (HasAES)
- Builder.defineMacro("__AES__");
-
- if (HasPCLMUL)
- Builder.defineMacro("__PCLMUL__");
-
- if (HasLZCNT)
- Builder.defineMacro("__LZCNT__");
-
- if (HasRDRND)
- Builder.defineMacro("__RDRND__");
-
- if (HasFSGSBASE)
- Builder.defineMacro("__FSGSBASE__");
-
- if (HasBMI)
- Builder.defineMacro("__BMI__");
-
- if (HasBMI2)
- Builder.defineMacro("__BMI2__");
-
- if (HasPOPCNT)
- Builder.defineMacro("__POPCNT__");
-
- if (HasRTM)
- Builder.defineMacro("__RTM__");
-
- if (HasPRFCHW)
- Builder.defineMacro("__PRFCHW__");
-
- if (HasRDSEED)
- Builder.defineMacro("__RDSEED__");
-
- if (HasADX)
- Builder.defineMacro("__ADX__");
-
- if (HasTBM)
- Builder.defineMacro("__TBM__");
-
- if (HasMWAITX)
- Builder.defineMacro("__MWAITX__");
-
- switch (XOPLevel) {
- case XOP:
- Builder.defineMacro("__XOP__");
- case FMA4:
- Builder.defineMacro("__FMA4__");
- case SSE4A:
- Builder.defineMacro("__SSE4A__");
- case NoXOP:
- break;
- }
-
- if (HasFMA)
- Builder.defineMacro("__FMA__");
-
- if (HasF16C)
- Builder.defineMacro("__F16C__");
-
- if (HasAVX512CD)
- Builder.defineMacro("__AVX512CD__");
- if (HasAVX512ER)
- Builder.defineMacro("__AVX512ER__");
- if (HasAVX512PF)
- Builder.defineMacro("__AVX512PF__");
- if (HasAVX512DQ)
- Builder.defineMacro("__AVX512DQ__");
- if (HasAVX512BW)
- Builder.defineMacro("__AVX512BW__");
- if (HasAVX512VL)
- Builder.defineMacro("__AVX512VL__");
- if (HasAVX512VBMI)
- Builder.defineMacro("__AVX512VBMI__");
- if (HasAVX512IFMA)
- Builder.defineMacro("__AVX512IFMA__");
-
- if (HasSHA)
- Builder.defineMacro("__SHA__");
-
- if (HasFXSR)
- Builder.defineMacro("__FXSR__");
- if (HasXSAVE)
- Builder.defineMacro("__XSAVE__");
- if (HasXSAVEOPT)
- Builder.defineMacro("__XSAVEOPT__");
- if (HasXSAVEC)
- Builder.defineMacro("__XSAVEC__");
- if (HasXSAVES)
- Builder.defineMacro("__XSAVES__");
- if (HasPKU)
- Builder.defineMacro("__PKU__");
- if (HasCX16)
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16");
- if (HasCLFLUSHOPT)
- Builder.defineMacro("__CLFLUSHOPT__");
- if (HasCLWB)
- Builder.defineMacro("__CLWB__");
- if (HasMPX)
- Builder.defineMacro("__MPX__");
- if (HasSGX)
- Builder.defineMacro("__SGX__");
- if (HasPREFETCHWT1)
- Builder.defineMacro("__PREFETCHWT1__");
- if (HasCLZERO)
- Builder.defineMacro("__CLZERO__");
-
- // Each case falls through to the previous one here.
- switch (SSELevel) {
- case AVX512F:
- Builder.defineMacro("__AVX512F__");
- case AVX2:
- Builder.defineMacro("__AVX2__");
- case AVX:
- Builder.defineMacro("__AVX__");
- case SSE42:
- Builder.defineMacro("__SSE4_2__");
- case SSE41:
- Builder.defineMacro("__SSE4_1__");
- case SSSE3:
- Builder.defineMacro("__SSSE3__");
- case SSE3:
- Builder.defineMacro("__SSE3__");
- case SSE2:
- Builder.defineMacro("__SSE2__");
- Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
- case SSE1:
- Builder.defineMacro("__SSE__");
- Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
- case NoSSE:
- break;
- }
-
- if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) {
- switch (SSELevel) {
- case AVX512F:
- case AVX2:
- case AVX:
- case SSE42:
- case SSE41:
- case SSSE3:
- case SSE3:
- case SSE2:
- Builder.defineMacro("_M_IX86_FP", Twine(2));
- break;
- case SSE1:
- Builder.defineMacro("_M_IX86_FP", Twine(1));
- break;
- default:
- Builder.defineMacro("_M_IX86_FP", Twine(0));
- }
- }
-
- // Each case falls through to the previous one here.
- switch (MMX3DNowLevel) {
- case AMD3DNowAthlon:
- Builder.defineMacro("__3dNOW_A__");
- case AMD3DNow:
- Builder.defineMacro("__3dNOW__");
- case MMX:
- Builder.defineMacro("__MMX__");
- case NoMMX3DNow:
- break;
- }
-
- if (CPU >= CK_i486) {
- 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");
- }
- if (CPU >= CK_i586)
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
-}
-
-bool X86TargetInfo::hasFeature(StringRef Feature) const {
- return llvm::StringSwitch<bool>(Feature)
- .Case("aes", HasAES)
- .Case("avx", SSELevel >= AVX)
- .Case("avx2", SSELevel >= AVX2)
- .Case("avx512f", SSELevel >= AVX512F)
- .Case("avx512cd", HasAVX512CD)
- .Case("avx512er", HasAVX512ER)
- .Case("avx512pf", HasAVX512PF)
- .Case("avx512dq", HasAVX512DQ)
- .Case("avx512bw", HasAVX512BW)
- .Case("avx512vl", HasAVX512VL)
- .Case("avx512vbmi", HasAVX512VBMI)
- .Case("avx512ifma", HasAVX512IFMA)
- .Case("bmi", HasBMI)
- .Case("bmi2", HasBMI2)
- .Case("clflushopt", HasCLFLUSHOPT)
- .Case("clwb", HasCLWB)
- .Case("clzero", HasCLZERO)
- .Case("cx16", HasCX16)
- .Case("f16c", HasF16C)
- .Case("fma", HasFMA)
- .Case("fma4", XOPLevel >= FMA4)
- .Case("fsgsbase", HasFSGSBASE)
- .Case("fxsr", HasFXSR)
- .Case("lzcnt", HasLZCNT)
- .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow)
- .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon)
- .Case("mmx", MMX3DNowLevel >= MMX)
- .Case("movbe", HasMOVBE)
- .Case("mpx", HasMPX)
- .Case("pclmul", HasPCLMUL)
- .Case("pku", HasPKU)
- .Case("popcnt", HasPOPCNT)
- .Case("prefetchwt1", HasPREFETCHWT1)
- .Case("prfchw", HasPRFCHW)
- .Case("rdrnd", HasRDRND)
- .Case("rdseed", HasRDSEED)
- .Case("rtm", HasRTM)
- .Case("sgx", HasSGX)
- .Case("sha", HasSHA)
- .Case("sse", SSELevel >= SSE1)
- .Case("sse2", SSELevel >= SSE2)
- .Case("sse3", SSELevel >= SSE3)
- .Case("ssse3", SSELevel >= SSSE3)
- .Case("sse4.1", SSELevel >= SSE41)
- .Case("sse4.2", SSELevel >= SSE42)
- .Case("sse4a", XOPLevel >= SSE4A)
- .Case("tbm", HasTBM)
- .Case("x86", true)
- .Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
- .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
- .Case("xop", XOPLevel >= XOP)
- .Case("xsave", HasXSAVE)
- .Case("xsavec", HasXSAVEC)
- .Case("xsaves", HasXSAVES)
- .Case("xsaveopt", HasXSAVEOPT)
- .Default(false);
-}
-
-// We can't use a generic validation scheme for the features accepted here
-// versus subtarget features accepted in the target attribute because the
-// bitfield structure that's initialized in the runtime only supports the
-// below currently rather than the full range of subtarget features. (See
-// X86TargetInfo::hasFeature for a somewhat comprehensive list).
-bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
- return llvm::StringSwitch<bool>(FeatureStr)
- .Case("cmov", true)
- .Case("mmx", true)
- .Case("popcnt", true)
- .Case("sse", true)
- .Case("sse2", true)
- .Case("sse3", true)
- .Case("ssse3", true)
- .Case("sse4.1", true)
- .Case("sse4.2", true)
- .Case("avx", true)
- .Case("avx2", true)
- .Case("sse4a", true)
- .Case("fma4", true)
- .Case("xop", true)
- .Case("fma", true)
- .Case("avx512f", true)
- .Case("bmi", true)
- .Case("bmi2", true)
- .Case("aes", true)
- .Case("pclmul", true)
- .Case("avx512vl", true)
- .Case("avx512bw", true)
- .Case("avx512dq", true)
- .Case("avx512cd", true)
- .Case("avx512er", true)
- .Case("avx512pf", true)
- .Case("avx512vbmi", true)
- .Case("avx512ifma", true)
- .Default(false);
-}
-
-bool
-X86TargetInfo::validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
- switch (*Name) {
- default: return false;
- // Constant constraints.
- case 'e': // 32-bit signed integer constant for use with sign-extending x86_64
- // instructions.
- case 'Z': // 32-bit unsigned integer constant for use with zero-extending
- // x86_64 instructions.
- case 's':
- Info.setRequiresImmediate();
- return true;
- case 'I':
- Info.setRequiresImmediate(0, 31);
- return true;
- case 'J':
- Info.setRequiresImmediate(0, 63);
- return true;
- case 'K':
- Info.setRequiresImmediate(-128, 127);
- return true;
- case 'L':
- Info.setRequiresImmediate({ int(0xff), int(0xffff), int(0xffffffff) });
- return true;
- case 'M':
- Info.setRequiresImmediate(0, 3);
- return true;
- case 'N':
- Info.setRequiresImmediate(0, 255);
- return true;
- case 'O':
- Info.setRequiresImmediate(0, 127);
- return true;
- // Register constraints.
- case 'Y': // 'Y' is the first character for several 2-character constraints.
- // Shift the pointer to the second character of the constraint.
- Name++;
- switch (*Name) {
- default:
- return false;
- case '0': // First SSE register.
- case 't': // Any SSE register, when SSE2 is enabled.
- case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled.
- case 'm': // Any MMX register, when inter-unit moves enabled.
- case 'k': // AVX512 arch mask registers: k1-k7.
- Info.setAllowsRegister();
- return true;
- }
- case 'f': // Any x87 floating point stack register.
- // Constraint 'f' cannot be used for output operands.
- if (Info.ConstraintStr[0] == '=')
- return false;
- Info.setAllowsRegister();
- return true;
- case 'a': // eax.
- case 'b': // ebx.
- case 'c': // ecx.
- case 'd': // edx.
- case 'S': // esi.
- case 'D': // edi.
- case 'A': // edx:eax.
- case 't': // Top of floating point stack.
- case 'u': // Second from top of floating point stack.
- case 'q': // Any register accessible as [r]l: a, b, c, and d.
- case 'y': // Any MMX register.
- case 'v': // Any {X,Y,Z}MM register (Arch & context dependent)
- case 'x': // Any SSE register.
- case 'k': // Any AVX512 mask register (same as Yk, additionaly allows k0
- // for intermideate k reg operations).
- case 'Q': // Any register accessible as [r]h: a, b, c, and d.
- case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp.
- case 'l': // "Index" registers: any general register that can be used as an
- // index in a base+index memory access.
- Info.setAllowsRegister();
- return true;
- // Floating point constant constraints.
- case 'C': // SSE floating point constant.
- case 'G': // x87 floating point constant.
- return true;
- }
-}
-
-bool X86TargetInfo::validateOutputSize(StringRef Constraint,
- unsigned Size) const {
- // Strip off constraint modifiers.
- while (Constraint[0] == '=' ||
- Constraint[0] == '+' ||
- Constraint[0] == '&')
- Constraint = Constraint.substr(1);
-
- return validateOperandSize(Constraint, Size);
-}
-
-bool X86TargetInfo::validateInputSize(StringRef Constraint,
- unsigned Size) const {
- return validateOperandSize(Constraint, Size);
-}
-
-bool X86TargetInfo::validateOperandSize(StringRef Constraint,
- unsigned Size) const {
- switch (Constraint[0]) {
- default: break;
- case 'k':
- // Registers k0-k7 (AVX512) size limit is 64 bit.
- case 'y':
- return Size <= 64;
- case 'f':
- case 't':
- case 'u':
- return Size <= 128;
- case 'v':
- case 'x':
- if (SSELevel >= AVX512F)
- // 512-bit zmm registers can be used if target supports AVX512F.
- return Size <= 512U;
- else if (SSELevel >= AVX)
- // 256-bit ymm registers can be used if target supports AVX.
- return Size <= 256U;
- return Size <= 128U;
- case 'Y':
- // 'Y' is the first character for several 2-character constraints.
- switch (Constraint[1]) {
- default: break;
- case 'm':
- // 'Ym' is synonymous with 'y'.
- case 'k':
- return Size <= 64;
- case 'i':
- case 't':
- // 'Yi' and 'Yt' are synonymous with 'x' when SSE2 is enabled.
- if (SSELevel >= AVX512F)
- return Size <= 512U;
- else if (SSELevel >= AVX)
- return Size <= 256U;
- return SSELevel >= SSE2 && Size <= 128U;
- }
-
- }
-
- return true;
-}
-
-std::string
-X86TargetInfo::convertConstraint(const char *&Constraint) const {
- switch (*Constraint) {
- case 'a': return std::string("{ax}");
- case 'b': return std::string("{bx}");
- case 'c': return std::string("{cx}");
- case 'd': return std::string("{dx}");
- case 'S': return std::string("{si}");
- case 'D': return std::string("{di}");
- case 'p': // address
- return std::string("im");
- case 't': // top of floating point stack.
- return std::string("{st}");
- case 'u': // second from top of floating point stack.
- return std::string("{st(1)}"); // second from top of floating point stack.
- case 'Y':
- switch (Constraint[1]) {
- default:
- // Break from inner switch and fall through (copy single char),
- // continue parsing after copying the current constraint into
- // the return string.
- break;
- case 'k':
- // "^" hints llvm that this is a 2 letter constraint.
- // "Constraint++" is used to promote the string iterator
- // to the next constraint.
- return std::string("^") + std::string(Constraint++, 2);
- }
- LLVM_FALLTHROUGH;
- default:
- return std::string(1, *Constraint);
- }
-}
-
-// X86-32 generic target
-class X86_32TargetInfo : public X86TargetInfo {
-public:
- X86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : X86TargetInfo(Triple, Opts) {
- DoubleAlign = LongLongAlign = 32;
- LongDoubleWidth = 96;
- LongDoubleAlign = 32;
- SuitableAlign = 128;
- resetDataLayout("e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128");
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- IntPtrType = SignedInt;
- RegParmMax = 3;
-
- // Use fpret for all types.
- RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) |
- (1 << TargetInfo::Double) |
- (1 << TargetInfo::LongDouble));
-
- // x86-32 has atomics up to 8 bytes
- // FIXME: Check that we actually have cmpxchg8b before setting
- // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.)
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::CharPtrBuiltinVaList;
- }
-
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- if (RegNo == 0) return 0;
- if (RegNo == 1) return 2;
- return -1;
- }
- bool validateOperandSize(StringRef Constraint,
- unsigned Size) const override {
- switch (Constraint[0]) {
- default: break;
- case 'R':
- case 'q':
- case 'Q':
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'S':
- case 'D':
- return Size <= 32;
- case 'A':
- return Size <= 64;
- }
-
- return X86TargetInfo::validateOperandSize(Constraint, Size);
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin -
- Builtin::FirstTSBuiltin + 1);
- }
-};
-
-class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> {
-public:
- NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}
-
- unsigned getFloatEvalMethod() const override {
- unsigned Major, Minor, Micro;
- getTriple().getOSVersion(Major, Minor, Micro);
- // New NetBSD uses the default rounding mode.
- if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 0)
- return X86_32TargetInfo::getFloatEvalMethod();
- // NetBSD before 6.99.26 defaults to "double" rounding.
- return 1;
- }
-};
-
-class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> {
-public:
- OpenBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OpenBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {
- SizeType = UnsignedLong;
- IntPtrType = SignedLong;
- PtrDiffType = SignedLong;
- }
-};
-
-class BitrigI386TargetInfo : public BitrigTargetInfo<X86_32TargetInfo> {
-public:
- BitrigI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : BitrigTargetInfo<X86_32TargetInfo>(Triple, Opts) {
- SizeType = UnsignedLong;
- IntPtrType = SignedLong;
- PtrDiffType = SignedLong;
- }
-};
-
-class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> {
-public:
- DarwinI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : DarwinTargetInfo<X86_32TargetInfo>(Triple, Opts) {
- LongDoubleWidth = 128;
- LongDoubleAlign = 128;
- SuitableAlign = 128;
- MaxVectorAlign = 256;
- // The watchOS simulator uses the builtin bool type for Objective-C.
- llvm::Triple T = llvm::Triple(Triple);
- if (T.isWatchOS())
- UseSignedCharForObjCBool = false;
- SizeType = UnsignedLong;
- IntPtrType = SignedLong;
- resetDataLayout("e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128");
- HasAlignMac68kSupport = true;
- }
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override {
- if (!DarwinTargetInfo<X86_32TargetInfo>::handleTargetFeatures(Features,
- Diags))
- return false;
- // We now know the features we have: we can decide how to align vectors.
- MaxVectorAlign =
- hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
- return true;
- }
-};
-
-// x86-32 Windows target
-class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> {
-public:
- WindowsX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WindowsTargetInfo<X86_32TargetInfo>(Triple, Opts) {
- WCharType = UnsignedShort;
- DoubleAlign = LongLongAlign = 64;
- bool IsWinCOFF =
- getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
- resetDataLayout(IsWinCOFF
- ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
- : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder);
- }
-};
-
-// x86-32 Windows Visual Studio target
-class MicrosoftX86_32TargetInfo : public WindowsX86_32TargetInfo {
-public:
- MicrosoftX86_32TargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : WindowsX86_32TargetInfo(Triple, Opts) {
- LongDoubleWidth = LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
- WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder);
- // The value of the following reflects processor type.
- // 300=386, 400=486, 500=Pentium, 600=Blend (default)
- // We lost the original triple, so we use the default.
- Builder.defineMacro("_M_IX86", "600");
- }
-};
-
-static void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) {
+void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) {
// Mingw and cygwin define __declspec(a) to __attribute__((a)). Clang
// supports __declspec natively under -fms-extensions, but we define a no-op
// __declspec macro anyway for pre-processor compatibility.
@@ -4465,4511 +97,18 @@ static void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) {
}
}
-static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) {
+void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) {
Builder.defineMacro("__MSVCRT__");
Builder.defineMacro("__MINGW32__");
addCygMingDefines(Opts, Builder);
}
-// x86-32 MinGW target
-class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
-public:
- MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WindowsX86_32TargetInfo(Triple, Opts) {}
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
- DefineStd(Builder, "WIN32", Opts);
- DefineStd(Builder, "WINNT", Opts);
- Builder.defineMacro("_X86_");
- addMinGWDefines(Opts, Builder);
- }
-};
-
-// x86-32 Cygwin target
-class CygwinX86_32TargetInfo : public X86_32TargetInfo {
-public:
- CygwinX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : X86_32TargetInfo(Triple, Opts) {
- WCharType = UnsignedShort;
- DoubleAlign = LongLongAlign = 64;
- resetDataLayout("e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- X86_32TargetInfo::getTargetDefines(Opts, Builder);
- Builder.defineMacro("_X86_");
- Builder.defineMacro("__CYGWIN__");
- Builder.defineMacro("__CYGWIN32__");
- addCygMingDefines(Opts, Builder);
- DefineStd(Builder, "unix", Opts);
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
- }
-};
-
-// x86-32 Haiku target
-class HaikuX86_32TargetInfo : public HaikuTargetInfo<X86_32TargetInfo> {
-public:
- HaikuX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : HaikuTargetInfo<X86_32TargetInfo>(Triple, Opts) {
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- HaikuTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder);
- Builder.defineMacro("__INTEL__");
- }
-};
-
-// X86-32 MCU target
-class MCUX86_32TargetInfo : public X86_32TargetInfo {
-public:
- MCUX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : X86_32TargetInfo(Triple, Opts) {
- LongDoubleWidth = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- resetDataLayout("e-m:e-p:32:32-i64:32-f64:32-f128:32-n8:16:32-a:0:32-S32");
- WIntType = UnsignedInt;
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- // On MCU we support only C calling convention.
- return CC == CC_C ? CCCR_OK : CCCR_Warning;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- X86_32TargetInfo::getTargetDefines(Opts, Builder);
- Builder.defineMacro("__iamcu");
- Builder.defineMacro("__iamcu__");
- }
-
- bool allowsLargerPreferedTypeAlignment() const override {
- return false;
- }
-};
-
-// RTEMS Target
-template<typename Target>
-class RTEMSTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // RTEMS defines; list based off of gcc output
-
- Builder.defineMacro("__rtems__");
- Builder.defineMacro("__ELF__");
- }
-
-public:
- RTEMSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {
- switch (Triple.getArch()) {
- default:
- case llvm::Triple::x86:
- // this->MCountName = ".mcount";
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- // this->MCountName = "_mcount";
- break;
- case llvm::Triple::arm:
- // this->MCountName = "__mcount";
- break;
- }
- }
-};
-
-// x86-32 RTEMS target
-class RTEMSX86_32TargetInfo : public X86_32TargetInfo {
-public:
- RTEMSX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : X86_32TargetInfo(Triple, Opts) {
- SizeType = UnsignedLong;
- IntPtrType = SignedLong;
- PtrDiffType = SignedLong;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- X86_32TargetInfo::getTargetDefines(Opts, Builder);
- Builder.defineMacro("__INTEL__");
- Builder.defineMacro("__rtems__");
- }
-};
-
-// x86-64 generic target
-class X86_64TargetInfo : public X86TargetInfo {
-public:
- X86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : X86TargetInfo(Triple, Opts) {
- const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32;
- bool IsWinCOFF =
- getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
- LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64;
- LongDoubleWidth = 128;
- LongDoubleAlign = 128;
- LargeArrayMinWidth = 128;
- LargeArrayAlign = 128;
- SuitableAlign = 128;
- SizeType = IsX32 ? UnsignedInt : UnsignedLong;
- PtrDiffType = IsX32 ? SignedInt : SignedLong;
- IntPtrType = IsX32 ? SignedInt : SignedLong;
- IntMaxType = IsX32 ? SignedLongLong : SignedLong;
- Int64Type = IsX32 ? SignedLongLong : SignedLong;
- RegParmMax = 6;
-
- // Pointers are 32-bit in x32.
- resetDataLayout(IsX32
- ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128"
- : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
- : "e-m:e-i64:64-f80:128-n8:16:32:64-S128");
-
- // Use fpret only for long double.
- RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
-
- // Use fp2ret for _Complex long double.
- ComplexLongDoubleUsesFP2Ret = true;
-
- // Make __builtin_ms_va_list available.
- HasBuiltinMSVaList = true;
-
- // x86-64 has atomics up to 16 bytes.
- MaxAtomicPromoteWidth = 128;
- MaxAtomicInlineWidth = 128;
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::X86_64ABIBuiltinVaList;
- }
-
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- if (RegNo == 0) return 0;
- if (RegNo == 1) return 1;
- return -1;
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- switch (CC) {
- case CC_C:
- case CC_Swift:
- case CC_X86VectorCall:
- case CC_IntelOclBicc:
- case CC_X86_64Win64:
- case CC_PreserveMost:
- case CC_PreserveAll:
- case CC_X86RegCall:
- return CCCR_OK;
- default:
- return CCCR_Warning;
- }
- }
-
- CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
- return CC_C;
- }
-
- // for x32 we need it here explicitly
- bool hasInt128Type() const override { return true; }
- unsigned getUnwindWordWidth() const override { return 64; }
- unsigned getRegisterWidth() const override { return 64; }
-
- bool validateGlobalRegisterVariable(StringRef RegName,
- unsigned RegSize,
- bool &HasSizeMismatch) const override {
- // rsp and rbp are the only 64-bit registers the x86 backend can currently
- // handle.
- if (RegName.equals("rsp") || RegName.equals("rbp")) {
- // Check that the register size is 64-bit.
- HasSizeMismatch = RegSize != 64;
- return true;
- }
-
- // Check if the register is a 32-bit register the backend can handle.
- return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize,
- HasSizeMismatch);
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfoX86,
- X86::LastTSBuiltin - Builtin::FirstTSBuiltin);
- }
-};
-
-// x86-64 Windows target
-class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> {
-public:
- WindowsX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WindowsTargetInfo<X86_64TargetInfo>(Triple, Opts) {
- WCharType = UnsignedShort;
- LongWidth = LongAlign = 32;
- DoubleAlign = LongLongAlign = 64;
- IntMaxType = SignedLongLong;
- Int64Type = SignedLongLong;
- SizeType = UnsignedLongLong;
- PtrDiffType = SignedLongLong;
- IntPtrType = SignedLongLong;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder);
- Builder.defineMacro("_WIN64");
- }
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::CharPtrBuiltinVaList;
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- switch (CC) {
- case CC_X86StdCall:
- case CC_X86ThisCall:
- case CC_X86FastCall:
- return CCCR_Ignore;
- case CC_C:
- case CC_X86VectorCall:
- case CC_IntelOclBicc:
- case CC_X86_64SysV:
- case CC_Swift:
- case CC_X86RegCall:
- return CCCR_OK;
- default:
- return CCCR_Warning;
- }
- }
-};
-
-// x86-64 Windows Visual Studio target
-class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo {
-public:
- MicrosoftX86_64TargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : WindowsX86_64TargetInfo(Triple, Opts) {
- LongDoubleWidth = LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
- WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder);
- Builder.defineMacro("_M_X64", "100");
- Builder.defineMacro("_M_AMD64", "100");
- }
-};
-
-// x86-64 MinGW target
-class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo {
-public:
- MinGWX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WindowsX86_64TargetInfo(Triple, Opts) {
- // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks
- // with x86 FP ops. Weird.
- LongDoubleWidth = LongDoubleAlign = 128;
- LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
- DefineStd(Builder, "WIN64", Opts);
- Builder.defineMacro("__MINGW64__");
- addMinGWDefines(Opts, Builder);
-
- // GCC defines this macro when it is using __gxx_personality_seh0.
- if (!Opts.SjLjExceptions)
- Builder.defineMacro("__SEH__");
- }
-};
-
-// x86-64 Cygwin target
-class CygwinX86_64TargetInfo : public X86_64TargetInfo {
-public:
- CygwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : X86_64TargetInfo(Triple, Opts) {
- TLSSupported = false;
- WCharType = UnsignedShort;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- X86_64TargetInfo::getTargetDefines(Opts, Builder);
- Builder.defineMacro("__x86_64__");
- Builder.defineMacro("__CYGWIN__");
- Builder.defineMacro("__CYGWIN64__");
- addCygMingDefines(Opts, Builder);
- DefineStd(Builder, "unix", Opts);
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
-
- // GCC defines this macro when it is using __gxx_personality_seh0.
- if (!Opts.SjLjExceptions)
- Builder.defineMacro("__SEH__");
- }
-};
-
-class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> {
-public:
- DarwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : DarwinTargetInfo<X86_64TargetInfo>(Triple, Opts) {
- Int64Type = SignedLongLong;
- // The 64-bit iOS simulator uses the builtin bool type for Objective-C.
- llvm::Triple T = llvm::Triple(Triple);
- if (T.isiOS())
- UseSignedCharForObjCBool = false;
- resetDataLayout("e-m:o-i64:64-f80:128-n8:16:32:64-S128");
- }
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override {
- if (!DarwinTargetInfo<X86_64TargetInfo>::handleTargetFeatures(Features,
- Diags))
- return false;
- // We now know the features we have: we can decide how to align vectors.
- MaxVectorAlign =
- hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
- return true;
- }
-};
-
-class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> {
-public:
- OpenBSDX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OpenBSDTargetInfo<X86_64TargetInfo>(Triple, Opts) {
- IntMaxType = SignedLongLong;
- Int64Type = SignedLongLong;
- }
-};
-
-class BitrigX86_64TargetInfo : public BitrigTargetInfo<X86_64TargetInfo> {
-public:
- BitrigX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : BitrigTargetInfo<X86_64TargetInfo>(Triple, Opts) {
- IntMaxType = SignedLongLong;
- Int64Type = SignedLongLong;
- }
-};
-
-class ARMTargetInfo : public TargetInfo {
- // Possible FPU choices.
- enum FPUMode {
- VFP2FPU = (1 << 0),
- VFP3FPU = (1 << 1),
- VFP4FPU = (1 << 2),
- NeonFPU = (1 << 3),
- FPARMV8 = (1 << 4)
- };
-
- // Possible HWDiv features.
- enum HWDivMode {
- HWDivThumb = (1 << 0),
- HWDivARM = (1 << 1)
- };
-
- static bool FPUModeIsVFP(FPUMode Mode) {
- return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8);
- }
-
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- static const char * const GCCRegNames[];
-
- std::string ABI, CPU;
-
- StringRef CPUProfile;
- StringRef CPUAttr;
-
- enum {
- FP_Default,
- FP_VFP,
- FP_Neon
- } FPMath;
-
- unsigned ArchISA;
- unsigned ArchKind = llvm::ARM::AK_ARMV4T;
- unsigned ArchProfile;
- unsigned ArchVersion;
-
- unsigned FPU : 5;
-
- unsigned IsAAPCS : 1;
- unsigned HWDiv : 2;
-
- // Initialized via features.
- unsigned SoftFloat : 1;
- unsigned SoftFloatABI : 1;
-
- unsigned CRC : 1;
- unsigned Crypto : 1;
- unsigned DSP : 1;
- unsigned Unaligned : 1;
-
- enum {
- LDREX_B = (1 << 0), /// byte (8-bit)
- LDREX_H = (1 << 1), /// half (16-bit)
- LDREX_W = (1 << 2), /// word (32-bit)
- LDREX_D = (1 << 3), /// double (64-bit)
- };
-
- uint32_t LDREX;
-
- // ACLE 6.5.1 Hardware floating point
- enum {
- HW_FP_HP = (1 << 1), /// half (16-bit)
- HW_FP_SP = (1 << 2), /// single (32-bit)
- HW_FP_DP = (1 << 3), /// double (64-bit)
- };
- uint32_t HW_FP;
-
- static const Builtin::Info BuiltinInfo[];
-
- void setABIAAPCS() {
- IsAAPCS = true;
-
- DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
- const llvm::Triple &T = getTriple();
-
- // size_t is unsigned long on MachO-derived environments, NetBSD,
- // OpenBSD and Bitrig.
- if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD ||
- T.getOS() == llvm::Triple::OpenBSD ||
- T.getOS() == llvm::Triple::Bitrig)
- SizeType = UnsignedLong;
- else
- SizeType = UnsignedInt;
-
- switch (T.getOS()) {
- case llvm::Triple::NetBSD:
- case llvm::Triple::OpenBSD:
- WCharType = SignedInt;
- break;
- case llvm::Triple::Win32:
- WCharType = UnsignedShort;
- break;
- case llvm::Triple::Linux:
- default:
- // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int.
- WCharType = UnsignedInt;
- break;
- }
-
- UseBitFieldTypeAlignment = true;
-
- ZeroLengthBitfieldBoundary = 0;
-
- // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
- // so set preferred for small types to 32.
- if (T.isOSBinFormatMachO()) {
- resetDataLayout(BigEndian
- ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
- : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64");
- } else if (T.isOSWindows()) {
- assert(!BigEndian && "Windows on ARM does not support big endian");
- resetDataLayout("e"
- "-m:w"
- "-p:32:32"
- "-i64:64"
- "-v128:64:128"
- "-a:0:32"
- "-n32"
- "-S64");
- } else if (T.isOSNaCl()) {
- assert(!BigEndian && "NaCl on ARM does not support big endian");
- resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128");
- } else {
- resetDataLayout(BigEndian
- ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
- : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64");
- }
-
- // FIXME: Enumerated types are variable width in straight AAPCS.
- }
-
- void setABIAPCS(bool IsAAPCS16) {
- const llvm::Triple &T = getTriple();
-
- IsAAPCS = false;
-
- if (IsAAPCS16)
- DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
- else
- DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
-
- // size_t is unsigned int on FreeBSD.
- if (T.getOS() == llvm::Triple::FreeBSD)
- SizeType = UnsignedInt;
- else
- SizeType = UnsignedLong;
-
- // Revert to using SignedInt on apcs-gnu to comply with existing behaviour.
- WCharType = SignedInt;
-
- // Do not respect the alignment of bit-field types when laying out
- // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
- UseBitFieldTypeAlignment = false;
-
- /// gcc forces the alignment to 4 bytes, regardless of the type of the
- /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in
- /// gcc.
- ZeroLengthBitfieldBoundary = 32;
-
- if (T.isOSBinFormatMachO() && IsAAPCS16) {
- assert(!BigEndian && "AAPCS16 does not support big-endian");
- resetDataLayout("e-m:o-p:32:32-i64:64-a:0:32-n32-S128");
- } else if (T.isOSBinFormatMachO())
- resetDataLayout(
- BigEndian
- ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
- : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32");
- else
- resetDataLayout(
- BigEndian
- ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
- : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32");
-
- // FIXME: Override "preferred align" for double and long long.
- }
-
- void setArchInfo() {
- StringRef ArchName = getTriple().getArchName();
-
- ArchISA = llvm::ARM::parseArchISA(ArchName);
- CPU = llvm::ARM::getDefaultCPU(ArchName);
- unsigned AK = llvm::ARM::parseArch(ArchName);
- if (AK != llvm::ARM::AK_INVALID)
- ArchKind = AK;
- setArchInfo(ArchKind);
- }
-
- void setArchInfo(unsigned Kind) {
- StringRef SubArch;
-
- // cache TargetParser info
- ArchKind = Kind;
- SubArch = llvm::ARM::getSubArch(ArchKind);
- ArchProfile = llvm::ARM::parseArchProfile(SubArch);
- ArchVersion = llvm::ARM::parseArchVersion(SubArch);
-
- // cache CPU related strings
- CPUAttr = getCPUAttr();
- CPUProfile = getCPUProfile();
- }
-
- void setAtomic() {
- // when triple does not specify a sub arch,
- // then we are not using inline atomics
- bool ShouldUseInlineAtomic =
- (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) ||
- (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7);
- // Cortex M does not support 8 byte atomics, while general Thumb2 does.
- if (ArchProfile == llvm::ARM::PK_M) {
- MaxAtomicPromoteWidth = 32;
- if (ShouldUseInlineAtomic)
- MaxAtomicInlineWidth = 32;
- }
- else {
- MaxAtomicPromoteWidth = 64;
- if (ShouldUseInlineAtomic)
- MaxAtomicInlineWidth = 64;
- }
- }
-
- bool isThumb() const {
- return (ArchISA == llvm::ARM::IK_THUMB);
- }
-
- bool supportsThumb() const {
- return CPUAttr.count('T') || ArchVersion >= 6;
- }
-
- bool supportsThumb2() const {
- return CPUAttr.equals("6T2") ||
- (ArchVersion >= 7 && !CPUAttr.equals("8M_BASE"));
- }
-
- StringRef getCPUAttr() const {
- // For most sub-arches, the build attribute CPU name is enough.
- // For Cortex variants, it's slightly different.
- switch(ArchKind) {
- default:
- return llvm::ARM::getCPUAttr(ArchKind);
- case llvm::ARM::AK_ARMV6M:
- return "6M";
- case llvm::ARM::AK_ARMV7S:
- return "7S";
- case llvm::ARM::AK_ARMV7A:
- return "7A";
- case llvm::ARM::AK_ARMV7R:
- return "7R";
- case llvm::ARM::AK_ARMV7M:
- 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:
- return "8_1A";
- case llvm::ARM::AK_ARMV8_2A:
- return "8_2A";
- case llvm::ARM::AK_ARMV8MBaseline:
- return "8M_BASE";
- case llvm::ARM::AK_ARMV8MMainline:
- return "8M_MAIN";
- case llvm::ARM::AK_ARMV8R:
- return "8R";
- }
- }
-
- StringRef getCPUProfile() const {
- switch(ArchProfile) {
- case llvm::ARM::PK_A:
- return "A";
- case llvm::ARM::PK_R:
- return "R";
- case llvm::ARM::PK_M:
- return "M";
- default:
- return "";
- }
- }
-
-public:
- ARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0),
- HW_FP(0) {
-
- switch (getTriple().getOS()) {
- case llvm::Triple::NetBSD:
- case llvm::Triple::OpenBSD:
- PtrDiffType = SignedLong;
- break;
- default:
- PtrDiffType = SignedInt;
- break;
- }
-
- // Cache arch related info.
- setArchInfo();
-
- // {} in inline assembly are neon specifiers, not assembly variant
- // specifiers.
- NoAsmVariants = true;
-
- // FIXME: This duplicates code from the driver that sets the -target-abi
- // option - this code is used if -target-abi isn't passed and should
- // be unified in some way.
- if (Triple.isOSBinFormatMachO()) {
- // The backend is hardwired to assume AAPCS for M-class processors, ensure
- // the frontend matches that.
- if (Triple.getEnvironment() == llvm::Triple::EABI ||
- Triple.getOS() == llvm::Triple::UnknownOS ||
- ArchProfile == llvm::ARM::PK_M) {
- setABI("aapcs");
- } else if (Triple.isWatchABI()) {
- setABI("aapcs16");
- } else {
- setABI("apcs-gnu");
- }
- } else if (Triple.isOSWindows()) {
- // FIXME: this is invalid for WindowsCE
- setABI("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:
- setABI("aapcs-linux");
- break;
- case llvm::Triple::EABIHF:
- case llvm::Triple::EABI:
- setABI("aapcs");
- break;
- case llvm::Triple::GNU:
- setABI("apcs-gnu");
- break;
- default:
- if (Triple.getOS() == llvm::Triple::NetBSD)
- setABI("apcs-gnu");
- else if (Triple.getOS() == llvm::Triple::OpenBSD)
- setABI("aapcs-linux");
- else
- setABI("aapcs");
- break;
- }
- }
-
- // ARM targets default to using the ARM C++ ABI.
- TheCXXABI.set(TargetCXXABI::GenericARM);
-
- // ARM has atomics up to 8 bytes
- setAtomic();
-
- // Do force alignment of members that follow zero length bitfields. If
- // the alignment of the zero-length bitfield is greater than the member
- // that follows it, `bar', `bar' will be aligned as the type of the
- // zero length bitfield.
- UseZeroLengthBitfieldAlignment = true;
-
- if (Triple.getOS() == llvm::Triple::Linux ||
- Triple.getOS() == llvm::Triple::UnknownOS)
- this->MCountName =
- Opts.EABIVersion == "gnu" ? "\01__gnu_mcount_nc" : "\01mcount";
- }
-
- StringRef getABI() const override { return ABI; }
-
- bool setABI(const std::string &Name) override {
- ABI = Name;
-
- // The defaults (above) are for AAPCS, check if we need to change them.
- //
- // FIXME: We need support for -meabi... we could just mangle it into the
- // name.
- if (Name == "apcs-gnu" || Name == "aapcs16") {
- setABIAPCS(Name == "aapcs16");
- return true;
- }
- if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") {
- setABIAAPCS();
- return true;
- }
- return false;
- }
-
- // FIXME: This should be based on Arch attributes, not CPU names.
- bool
- initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const override {
-
- std::vector<StringRef> TargetFeatures;
- unsigned Arch = llvm::ARM::parseArch(getTriple().getArchName());
-
- // get default FPU features
- unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch);
- llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures);
-
- // get default Extension features
- unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch);
- llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures);
-
- for (auto Feature : TargetFeatures)
- if (Feature[0] == '+')
- Features[Feature.drop_front(1)] = true;
-
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
- }
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override {
- FPU = 0;
- CRC = 0;
- Crypto = 0;
- DSP = 0;
- Unaligned = 1;
- SoftFloat = SoftFloatABI = false;
- HWDiv = 0;
-
- // This does not diagnose illegal cases like having both
- // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp".
- uint32_t HW_FP_remove = 0;
- for (const auto &Feature : Features) {
- if (Feature == "+soft-float") {
- SoftFloat = true;
- } else if (Feature == "+soft-float-abi") {
- SoftFloatABI = true;
- } else if (Feature == "+vfp2") {
- FPU |= VFP2FPU;
- HW_FP |= HW_FP_SP | HW_FP_DP;
- } else if (Feature == "+vfp3") {
- FPU |= VFP3FPU;
- HW_FP |= HW_FP_SP | HW_FP_DP;
- } else if (Feature == "+vfp4") {
- FPU |= VFP4FPU;
- HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
- } else if (Feature == "+fp-armv8") {
- FPU |= FPARMV8;
- HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
- } else if (Feature == "+neon") {
- FPU |= NeonFPU;
- HW_FP |= HW_FP_SP | HW_FP_DP;
- } else if (Feature == "+hwdiv") {
- HWDiv |= HWDivThumb;
- } else if (Feature == "+hwdiv-arm") {
- HWDiv |= HWDivARM;
- } else if (Feature == "+crc") {
- CRC = 1;
- } else if (Feature == "+crypto") {
- Crypto = 1;
- } else if (Feature == "+dsp") {
- DSP = 1;
- } else if (Feature == "+fp-only-sp") {
- HW_FP_remove |= HW_FP_DP;
- } else if (Feature == "+strict-align") {
- Unaligned = 0;
- } else if (Feature == "+fp16") {
- HW_FP |= HW_FP_HP;
- }
- }
- HW_FP &= ~HW_FP_remove;
-
- switch (ArchVersion) {
- case 6:
- if (ArchProfile == llvm::ARM::PK_M)
- LDREX = 0;
- else if (ArchKind == llvm::ARM::AK_ARMV6K)
- LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ;
- else
- LDREX = LDREX_W;
- break;
- case 7:
- if (ArchProfile == llvm::ARM::PK_M)
- LDREX = LDREX_W | LDREX_H | LDREX_B ;
- else
- LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ;
- break;
- case 8:
- LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ;
- }
-
- if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
- Diags.Report(diag::err_target_unsupported_fpmath) << "neon";
- return false;
- }
-
- if (FPMath == FP_Neon)
- Features.push_back("+neonfp");
- else if (FPMath == FP_VFP)
- Features.push_back("-neonfp");
-
- // Remove front-end specific options which the backend handles differently.
- auto Feature =
- std::find(Features.begin(), Features.end(), "+soft-float-abi");
- if (Feature != Features.end())
- Features.erase(Feature);
-
- return true;
- }
-
- bool hasFeature(StringRef Feature) const override {
- return llvm::StringSwitch<bool>(Feature)
- .Case("arm", true)
- .Case("aarch32", true)
- .Case("softfloat", SoftFloat)
- .Case("thumb", isThumb())
- .Case("neon", (FPU & NeonFPU) && !SoftFloat)
- .Case("hwdiv", HWDiv & HWDivThumb)
- .Case("hwdiv-arm", HWDiv & HWDivARM)
- .Default(false);
- }
-
- bool setCPU(const std::string &Name) override {
- if (Name != "generic")
- setArchInfo(llvm::ARM::parseCPUArch(Name));
-
- if (ArchKind == llvm::ARM::AK_INVALID)
- return false;
- setAtomic();
- CPU = Name;
- return true;
- }
-
- bool setFPMath(StringRef Name) override;
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- // Target identification.
- Builder.defineMacro("__arm");
- Builder.defineMacro("__arm__");
- // For bare-metal none-eabi.
- if (getTriple().getOS() == llvm::Triple::UnknownOS &&
- getTriple().getEnvironment() == llvm::Triple::EABI)
- Builder.defineMacro("__ELF__");
-
- // Target properties.
- Builder.defineMacro("__REGISTER_PREFIX__", "");
-
- // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU
- // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__.
- if (getTriple().isWatchABI())
- Builder.defineMacro("__ARM_ARCH_7K__", "2");
-
- if (!CPUAttr.empty())
- Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__");
-
- // ACLE 6.4.1 ARM/Thumb instruction set architecture
- // __ARM_ARCH is defined as an integer value indicating the current ARM ISA
- Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));
-
- if (ArchVersion >= 8) {
- // ACLE 6.5.7 Crypto Extension
- if (Crypto)
- Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1");
- // ACLE 6.5.8 CRC32 Extension
- if (CRC)
- Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
- // ACLE 6.5.10 Numeric Maximum and Minimum
- Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1");
- // ACLE 6.5.9 Directed Rounding
- Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1");
- }
-
- // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It
- // is not defined for the M-profile.
- // NOTE that the default profile is assumed to be 'A'
- if (CPUProfile.empty() || ArchProfile != llvm::ARM::PK_M)
- Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1");
-
- // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supports the original
- // Thumb ISA (including v6-M and v8-M Baseline). It is set to 2 if the
- // core supports the Thumb-2 ISA as found in the v6T2 architecture and all
- // v7 and v8 architectures excluding v8-M Baseline.
- if (supportsThumb2())
- Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2");
- else if (supportsThumb())
- Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1");
-
- // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit
- // instruction set such as ARM or Thumb.
- Builder.defineMacro("__ARM_32BIT_STATE", "1");
-
- // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex)
-
- // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset.
- if (!CPUProfile.empty())
- Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'");
-
- // ACLE 6.4.3 Unaligned access supported in hardware
- if (Unaligned)
- Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
-
- // ACLE 6.4.4 LDREX/STREX
- if (LDREX)
- Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + llvm::utohexstr(LDREX));
-
- // ACLE 6.4.5 CLZ
- if (ArchVersion == 5 ||
- (ArchVersion == 6 && CPUProfile != "M") ||
- ArchVersion > 6)
- Builder.defineMacro("__ARM_FEATURE_CLZ", "1");
-
- // ACLE 6.5.1 Hardware Floating Point
- if (HW_FP)
- Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP));
-
- // ACLE predefines.
- Builder.defineMacro("__ARM_ACLE", "200");
-
- // FP16 support (we currently only support IEEE format).
- Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1");
- Builder.defineMacro("__ARM_FP16_ARGS", "1");
-
- // ACLE 6.5.3 Fused multiply-accumulate (FMA)
- if (ArchVersion >= 7 && (FPU & VFP4FPU))
- Builder.defineMacro("__ARM_FEATURE_FMA", "1");
-
- // Subtarget options.
-
- // FIXME: It's more complicated than this and we don't really support
- // interworking.
- // Windows on ARM does not "support" interworking
- if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows())
- Builder.defineMacro("__THUMB_INTERWORK__");
-
- if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
- // Embedded targets on Darwin follow AAPCS, but not EABI.
- // Windows on ARM follows AAPCS VFP, but does not conform to EABI.
- if (!getTriple().isOSBinFormatMachO() && !getTriple().isOSWindows())
- Builder.defineMacro("__ARM_EABI__");
- Builder.defineMacro("__ARM_PCS", "1");
- }
-
- if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" ||
- ABI == "aapcs16")
- Builder.defineMacro("__ARM_PCS_VFP", "1");
-
- if (SoftFloat)
- Builder.defineMacro("__SOFTFP__");
-
- if (ArchKind == llvm::ARM::AK_XSCALE)
- Builder.defineMacro("__XSCALE__");
-
- if (isThumb()) {
- Builder.defineMacro("__THUMBEL__");
- Builder.defineMacro("__thumb__");
- if (supportsThumb2())
- Builder.defineMacro("__thumb2__");
- }
-
- // ACLE 6.4.9 32-bit SIMD instructions
- if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM"))
- Builder.defineMacro("__ARM_FEATURE_SIMD32", "1");
-
- // ACLE 6.4.10 Hardware Integer Divide
- if (((HWDiv & HWDivThumb) && isThumb()) ||
- ((HWDiv & HWDivARM) && !isThumb())) {
- Builder.defineMacro("__ARM_FEATURE_IDIV", "1");
- Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1");
- }
-
- // Note, this is always on in gcc, even though it doesn't make sense.
- Builder.defineMacro("__APCS_32__");
-
- if (FPUModeIsVFP((FPUMode) FPU)) {
- Builder.defineMacro("__VFP_FP__");
- if (FPU & VFP2FPU)
- Builder.defineMacro("__ARM_VFPV2__");
- if (FPU & VFP3FPU)
- Builder.defineMacro("__ARM_VFPV3__");
- if (FPU & VFP4FPU)
- Builder.defineMacro("__ARM_VFPV4__");
- if (FPU & FPARMV8)
- Builder.defineMacro("__ARM_FPV5__");
- }
-
- // This only gets set when Neon instructions are actually available, unlike
- // the VFP define, hence the soft float and arch check. This is subtly
- // different from gcc, we follow the intent which was that it should be set
- // when Neon instructions are actually available.
- if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) {
- Builder.defineMacro("__ARM_NEON", "1");
- Builder.defineMacro("__ARM_NEON__");
- // current AArch32 NEON implementations do not support double-precision
- // floating-point even when it is present in VFP.
- Builder.defineMacro("__ARM_NEON_FP",
- "0x" + llvm::utohexstr(HW_FP & ~HW_FP_DP));
- }
-
- Builder.defineMacro("__ARM_SIZEOF_WCHAR_T",
- Opts.ShortWChar ? "2" : "4");
-
- Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM",
- Opts.ShortEnums ? "1" : "4");
-
- if (ArchVersion >= 6 && CPUAttr != "6M" && CPUAttr != "8M_BASE") {
- 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");
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
- }
-
- // ACLE 6.4.7 DSP instructions
- if (DSP) {
- Builder.defineMacro("__ARM_FEATURE_DSP", "1");
- }
-
- // ACLE 6.4.8 Saturation instructions
- bool SAT = false;
- if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6 ) {
- Builder.defineMacro("__ARM_FEATURE_SAT", "1");
- SAT = true;
- }
-
- // ACLE 6.4.6 Q (saturation) flag
- if (DSP || SAT)
- Builder.defineMacro("__ARM_FEATURE_QBIT", "1");
-
- if (Opts.UnsafeFPMath)
- Builder.defineMacro("__ARM_FP_FAST", "1");
-
- if (ArchKind == llvm::ARM::AK_ARMV8_1A)
- Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin);
- }
- bool isCLZForZeroUndef() const override { return false; }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return IsAAPCS
- ? AAPCSABIBuiltinVaList
- : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList
- : TargetInfo::VoidPtrBuiltinVaList);
- }
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- switch (*Name) {
- default: break;
- case 'l': // r0-r7
- case 'h': // r8-r15
- case 't': // VFP Floating point register single precision
- case 'w': // VFP Floating point register double precision
- Info.setAllowsRegister();
- return true;
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- // FIXME
- return true;
- case 'Q': // A memory address that is a single base register.
- Info.setAllowsMemory();
- return true;
- case 'U': // a memory reference...
- switch (Name[1]) {
- case 'q': // ...ARMV4 ldrsb
- case 'v': // ...VFP load/store (reg+constant offset)
- case 'y': // ...iWMMXt load/store
- case 't': // address valid for load/store opaque types wider
- // than 128-bits
- case 'n': // valid address for Neon doubleword vector load/store
- case 'm': // valid address for Neon element and structure load/store
- case 's': // valid address for non-offset loads/stores of quad-word
- // values in four ARM registers
- Info.setAllowsMemory();
- Name++;
- return true;
- }
- }
- return false;
- }
- std::string convertConstraint(const char *&Constraint) const override {
- std::string R;
- switch (*Constraint) {
- case 'U': // Two-character constraint; add "^" hint for later parsing.
- R = std::string("^") + std::string(Constraint, 2);
- Constraint++;
- break;
- case 'p': // 'p' should be translated to 'r' by default.
- R = std::string("r");
- break;
- default:
- return std::string(1, *Constraint);
- }
- return R;
- }
- bool
- validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size,
- std::string &SuggestedModifier) const override {
- bool isOutput = (Constraint[0] == '=');
- bool isInOut = (Constraint[0] == '+');
-
- // Strip off constraint modifiers.
- while (Constraint[0] == '=' ||
- Constraint[0] == '+' ||
- Constraint[0] == '&')
- Constraint = Constraint.substr(1);
-
- switch (Constraint[0]) {
- default: break;
- case 'r': {
- switch (Modifier) {
- default:
- return (isInOut || isOutput || Size <= 64);
- case 'q':
- // A register of size 32 cannot fit a vector type.
- return false;
- }
- }
- }
-
- return true;
- }
- const char *getClobbers() const override {
- // FIXME: Is this really right?
- return "";
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- switch (CC) {
- case CC_AAPCS:
- case CC_AAPCS_VFP:
- case CC_Swift:
- return CCCR_OK;
- default:
- return CCCR_Warning;
- }
- }
-
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- if (RegNo == 0) return 0;
- if (RegNo == 1) return 1;
- return -1;
- }
-
- bool hasSjLjLowering() const override {
- return true;
- }
-};
-
-bool ARMTargetInfo::setFPMath(StringRef Name) {
- if (Name == "neon") {
- FPMath = FP_Neon;
- return true;
- } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" ||
- Name == "vfp4") {
- FPMath = FP_VFP;
- return true;
- }
- return false;
-}
-
-const char * const ARMTargetInfo::GCCRegNames[] = {
- // Integer registers
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
-
- // Float registers
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
- "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
- "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
-
- // Double registers
- "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",
-
- // Quad registers
- "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
-};
-
-ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = {
- { { "a1" }, "r0" },
- { { "a2" }, "r1" },
- { { "a3" }, "r2" },
- { { "a4" }, "r3" },
- { { "v1" }, "r4" },
- { { "v2" }, "r5" },
- { { "v3" }, "r6" },
- { { "v4" }, "r7" },
- { { "v5" }, "r8" },
- { { "v6", "rfp" }, "r9" },
- { { "sl" }, "r10" },
- { { "fp" }, "r11" },
- { { "ip" }, "r12" },
- { { "r13" }, "sp" },
- { { "r14" }, "lr" },
- { { "r15" }, "pc" },
- // The S, D and Q registers overlap, but aren't really aliases; we
- // don't want to substitute one of these for a different-sized one.
-};
-
-ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
-}
-
-const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsNEON.def"
-
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \
- { #ID, TYPE, ATTRS, nullptr, LANG, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- { #ID, TYPE, ATTRS, HEADER, LANGS, FEATURE },
-#include "clang/Basic/BuiltinsARM.def"
-};
-
-class ARMleTargetInfo : public ARMTargetInfo {
-public:
- ARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : ARMTargetInfo(Triple, Opts) {}
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__ARMEL__");
- ARMTargetInfo::getTargetDefines(Opts, Builder);
- }
-};
-
-class ARMbeTargetInfo : public ARMTargetInfo {
-public:
- ARMbeTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : ARMTargetInfo(Triple, Opts) {}
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__ARMEB__");
- Builder.defineMacro("__ARM_BIG_ENDIAN");
- ARMTargetInfo::getTargetDefines(Opts, Builder);
- }
-};
-
-class WindowsARMTargetInfo : public WindowsTargetInfo<ARMleTargetInfo> {
- const llvm::Triple Triple;
-public:
- WindowsARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WindowsTargetInfo<ARMleTargetInfo>(Triple, Opts), Triple(Triple) {
- WCharType = UnsignedShort;
- SizeType = UnsignedInt;
- }
- void getVisualStudioDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder);
-
- // FIXME: this is invalid for WindowsCE
- Builder.defineMacro("_M_ARM_NT", "1");
- Builder.defineMacro("_M_ARMT", "_M_ARM");
- Builder.defineMacro("_M_THUMB", "_M_ARM");
-
- assert((Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb) &&
- "invalid architecture for Windows ARM target info");
- unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
- Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset));
-
- // TODO map the complete set of values
- // 31: VFPv3 40: VFPv4
- Builder.defineMacro("_M_ARM_FP", "31");
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::CharPtrBuiltinVaList;
- }
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- switch (CC) {
- case CC_X86StdCall:
- case CC_X86ThisCall:
- case CC_X86FastCall:
- case CC_X86VectorCall:
- return CCCR_Ignore;
- case CC_C:
- return CCCR_OK;
- default:
- return CCCR_Warning;
- }
- }
-};
-
-// Windows ARM + Itanium C++ ABI Target
-class ItaniumWindowsARMleTargetInfo : public WindowsARMTargetInfo {
-public:
- ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : WindowsARMTargetInfo(Triple, Opts) {
- TheCXXABI.set(TargetCXXABI::GenericARM);
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
-
- if (Opts.MSVCCompat)
- WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
- }
-};
-
-// Windows ARM, MS (C++) ABI
-class MicrosoftARMleTargetInfo : public WindowsARMTargetInfo {
-public:
- MicrosoftARMleTargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : WindowsARMTargetInfo(Triple, Opts) {
- TheCXXABI.set(TargetCXXABI::Microsoft);
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
- WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
- }
-};
-
-// ARM MinGW target
-class MinGWARMTargetInfo : public WindowsARMTargetInfo {
-public:
- MinGWARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WindowsARMTargetInfo(Triple, Opts) {
- TheCXXABI.set(TargetCXXABI::GenericARM);
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
- DefineStd(Builder, "WIN32", Opts);
- DefineStd(Builder, "WINNT", Opts);
- Builder.defineMacro("_ARM_");
- addMinGWDefines(Opts, Builder);
- }
-};
-
-// ARM Cygwin target
-class CygwinARMTargetInfo : public ARMleTargetInfo {
-public:
- CygwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : ARMleTargetInfo(Triple, Opts) {
- TLSSupported = false;
- WCharType = UnsignedShort;
- DoubleAlign = LongLongAlign = 64;
- resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- ARMleTargetInfo::getTargetDefines(Opts, Builder);
- Builder.defineMacro("_ARM_");
- Builder.defineMacro("__CYGWIN__");
- Builder.defineMacro("__CYGWIN32__");
- DefineStd(Builder, "unix", Opts);
- if (Opts.CPlusPlus)
- Builder.defineMacro("_GNU_SOURCE");
- }
-};
-
-class DarwinARMTargetInfo : public DarwinTargetInfo<ARMleTargetInfo> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
- }
-
-public:
- DarwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : DarwinTargetInfo<ARMleTargetInfo>(Triple, Opts) {
- HasAlignMac68kSupport = true;
- // iOS always has 64-bit atomic instructions.
- // FIXME: This should be based off of the target features in
- // ARMleTargetInfo.
- MaxAtomicInlineWidth = 64;
-
- if (Triple.isWatchABI()) {
- // Darwin on iOS uses a variant of the ARM C++ ABI.
- TheCXXABI.set(TargetCXXABI::WatchOS);
-
- // The 32-bit ABI is silent on what ptrdiff_t should be, but given that
- // size_t is long, it's a bit weird for it to be int.
- PtrDiffType = SignedLong;
-
- // BOOL should be a real boolean on the new ABI
- UseSignedCharForObjCBool = false;
- } else
- TheCXXABI.set(TargetCXXABI::iOS);
- }
-};
-
-class AArch64TargetInfo : public TargetInfo {
- virtual void setDataLayout() = 0;
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- static const char *const GCCRegNames[];
-
- enum FPUModeEnum {
- FPUMode,
- NeonMode
- };
-
- unsigned FPU;
- unsigned CRC;
- unsigned Crypto;
- unsigned Unaligned;
- unsigned V8_1A;
-
- static const Builtin::Info BuiltinInfo[];
-
- std::string ABI;
-
-public:
- AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : TargetInfo(Triple), ABI("aapcs") {
- if (getTriple().getOS() == llvm::Triple::NetBSD ||
- getTriple().getOS() == llvm::Triple::OpenBSD) {
- WCharType = SignedInt;
-
- // NetBSD apparently prefers consistency across ARM targets to consistency
- // across 64-bit targets.
- Int64Type = SignedLongLong;
- IntMaxType = SignedLongLong;
- } else {
- WCharType = UnsignedInt;
- Int64Type = SignedLong;
- IntMaxType = SignedLong;
- }
-
- LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
- MaxVectorAlign = 128;
- MaxAtomicInlineWidth = 128;
- MaxAtomicPromoteWidth = 128;
-
- LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128;
- LongDoubleFormat = &llvm::APFloat::IEEEquad();
-
- // {} in inline assembly are neon specifiers, not assembly variant
- // specifiers.
- NoAsmVariants = true;
-
- // AAPCS gives rules for bitfields. 7.1.7 says: "The container type
- // contributes to the alignment of the containing aggregate in the same way
- // a plain (non bit-field) member of that type would, without exception for
- // zero-sized or anonymous bit-fields."
- assert(UseBitFieldTypeAlignment && "bitfields affect type alignment");
- UseZeroLengthBitfieldAlignment = true;
-
- // AArch64 targets default to using the ARM C++ ABI.
- TheCXXABI.set(TargetCXXABI::GenericAArch64);
-
- 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";
- }
-
- StringRef getABI() const override { return ABI; }
- bool setABI(const std::string &Name) override {
- if (Name != "aapcs" && Name != "darwinpcs")
- return false;
-
- ABI = Name;
- return true;
- }
-
- bool setCPU(const std::string &Name) override {
- return Name == "generic" ||
- llvm::AArch64::parseCPUArch(Name) !=
- static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID);
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- // Target identification.
- Builder.defineMacro("__aarch64__");
-
- // Target properties.
- Builder.defineMacro("_LP64");
- Builder.defineMacro("__LP64__");
-
- // ACLE predefines. Many can only have one possible value on v8 AArch64.
- Builder.defineMacro("__ARM_ACLE", "200");
- Builder.defineMacro("__ARM_ARCH", "8");
- Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'");
-
- Builder.defineMacro("__ARM_64BIT_STATE", "1");
- Builder.defineMacro("__ARM_PCS_AAPCS64", "1");
- Builder.defineMacro("__ARM_ARCH_ISA_A64", "1");
-
- Builder.defineMacro("__ARM_FEATURE_CLZ", "1");
- Builder.defineMacro("__ARM_FEATURE_FMA", "1");
- Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF");
- Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE
- Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility
- Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1");
- Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1");
-
- Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");
-
- // 0xe implies support for half, single and double precision operations.
- Builder.defineMacro("__ARM_FP", "0xE");
-
- // PCS specifies this for SysV variants, which is all we support. Other ABIs
- // may choose __ARM_FP16_FORMAT_ALTERNATIVE.
- Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1");
- Builder.defineMacro("__ARM_FP16_ARGS", "1");
-
- if (Opts.UnsafeFPMath)
- Builder.defineMacro("__ARM_FP_FAST", "1");
-
- Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4");
-
- Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM",
- Opts.ShortEnums ? "1" : "4");
-
- if (FPU == NeonMode) {
- Builder.defineMacro("__ARM_NEON", "1");
- // 64-bit NEON supports half, single and double precision operations.
- Builder.defineMacro("__ARM_NEON_FP", "0xE");
- }
-
- if (CRC)
- Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
-
- if (Crypto)
- Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1");
-
- if (Unaligned)
- Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
-
- if (V8_1A)
- Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
-
- // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
- 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");
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin);
- }
-
- bool hasFeature(StringRef Feature) const override {
- return Feature == "aarch64" ||
- Feature == "arm64" ||
- Feature == "arm" ||
- (Feature == "neon" && FPU == NeonMode);
- }
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override {
- FPU = FPUMode;
- CRC = 0;
- Crypto = 0;
- Unaligned = 1;
- V8_1A = 0;
-
- for (const auto &Feature : Features) {
- if (Feature == "+neon")
- FPU = NeonMode;
- if (Feature == "+crc")
- CRC = 1;
- if (Feature == "+crypto")
- Crypto = 1;
- if (Feature == "+strict-align")
- Unaligned = 0;
- if (Feature == "+v8.1a")
- V8_1A = 1;
- }
-
- setDataLayout();
-
- return true;
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- switch (CC) {
- case CC_C:
- case CC_Swift:
- case CC_PreserveMost:
- case CC_PreserveAll:
- return CCCR_OK;
- default:
- return CCCR_Warning;
- }
- }
-
- bool isCLZForZeroUndef() const override { return false; }
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::AArch64ABIBuiltinVaList;
- }
-
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
-
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- switch (*Name) {
- default:
- return false;
- case 'w': // Floating point and SIMD registers (V0-V31)
- Info.setAllowsRegister();
- return true;
- case 'I': // Constant that can be used with an ADD instruction
- case 'J': // Constant that can be used with a SUB instruction
- case 'K': // Constant that can be used with a 32-bit logical instruction
- case 'L': // Constant that can be used with a 64-bit logical instruction
- case 'M': // Constant that can be used as a 32-bit MOV immediate
- case 'N': // Constant that can be used as a 64-bit MOV immediate
- case 'Y': // Floating point constant zero
- case 'Z': // Integer constant zero
- return true;
- case 'Q': // A memory reference with base register and no offset
- Info.setAllowsMemory();
- return true;
- case 'S': // A symbolic address
- Info.setAllowsRegister();
- return true;
- case 'U':
- // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes.
- // Utf: A memory address suitable for ldp/stp in TF mode.
- // Usa: An absolute symbolic address.
- // Ush: The high part (bits 32:12) of a pc-relative symbolic address.
- llvm_unreachable("FIXME: Unimplemented support for U* constraints.");
- case 'z': // Zero register, wzr or xzr
- Info.setAllowsRegister();
- return true;
- case 'x': // Floating point and SIMD registers (V0-V15)
- Info.setAllowsRegister();
- return true;
- }
- return false;
- }
-
- bool
- validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size,
- std::string &SuggestedModifier) const override {
- // Strip off constraint modifiers.
- while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
- Constraint = Constraint.substr(1);
-
- switch (Constraint[0]) {
- default:
- return true;
- case 'z':
- case 'r': {
- switch (Modifier) {
- case 'x':
- case 'w':
- // For now assume that the person knows what they're
- // doing with the modifier.
- return true;
- default:
- // By default an 'r' constraint will be in the 'x'
- // registers.
- if (Size == 64)
- return true;
-
- SuggestedModifier = "w";
- return false;
- }
- }
- }
- }
-
- const char *getClobbers() const override { return ""; }
-
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- if (RegNo == 0)
- return 0;
- if (RegNo == 1)
- return 1;
- return -1;
- }
-};
-
-const char *const AArch64TargetInfo::GCCRegNames[] = {
- // 32-bit Integer registers
- "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10",
- "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21",
- "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp",
-
- // 64-bit Integer registers
- "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",
-
- // 32-bit floating point regsisters
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10",
- "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21",
- "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
-
- // 64-bit floating point regsisters
- "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",
-
- // Vector registers
- "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10",
- "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21",
- "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
-};
-
-ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
- { { "w31" }, "wsp" },
- { { "x29" }, "fp" },
- { { "x30" }, "lr" },
- { { "x31" }, "sp" },
- // The S/D/Q and W/X registers overlap, but aren't really aliases; we
- // don't want to substitute one of these for a different-sized one.
-};
-
-ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
-}
-
-const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsNEON.def"
-
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsAArch64.def"
-};
-
-class AArch64leTargetInfo : public AArch64TargetInfo {
- void setDataLayout() override {
- if (getTriple().isOSBinFormatMachO())
- resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128");
- else
- resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
- }
-
-public:
- AArch64leTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : AArch64TargetInfo(Triple, Opts) {
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__AARCH64EL__");
- AArch64TargetInfo::getTargetDefines(Opts, Builder);
- }
-};
-
-class AArch64beTargetInfo : public AArch64TargetInfo {
- void setDataLayout() override {
- assert(!getTriple().isOSBinFormatMachO());
- resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
- }
-
-public:
- AArch64beTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : AArch64TargetInfo(Triple, Opts) {}
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__AARCH64EB__");
- Builder.defineMacro("__AARCH_BIG_ENDIAN");
- Builder.defineMacro("__ARM_BIG_ENDIAN");
- AArch64TargetInfo::getTargetDefines(Opts, Builder);
- }
-};
-
-class DarwinAArch64TargetInfo : public DarwinTargetInfo<AArch64leTargetInfo> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__AARCH64_SIMD__");
- Builder.defineMacro("__ARM64_ARCH_8__");
- Builder.defineMacro("__ARM_NEON__");
- Builder.defineMacro("__LITTLE_ENDIAN__");
- Builder.defineMacro("__REGISTER_PREFIX__", "");
- Builder.defineMacro("__arm64", "1");
- Builder.defineMacro("__arm64__", "1");
-
- getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
- }
-
-public:
- DarwinAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) {
- Int64Type = SignedLongLong;
- WCharType = SignedInt;
- UseSignedCharForObjCBool = false;
-
- LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
-
- TheCXXABI.set(TargetCXXABI::iOS64);
- }
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::CharPtrBuiltinVaList;
- }
-};
-
-// Hexagon abstract base class
-class HexagonTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
- static const char * const GCCRegNames[];
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- std::string CPU;
- bool HasHVX, HasHVXDouble;
- bool UseLongCalls;
-
-public:
- HexagonTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- // Specify the vector alignment explicitly. For v512x1, the calculated
- // alignment would be 512*alignment(i1), which is 512 bytes, instead of
- // the required minimum of 64 bytes.
- resetDataLayout("e-m:e-p:32:32:32-a:0-n16:32-"
- "i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-"
- "v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048");
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- IntPtrType = SignedInt;
-
- // {} in inline assembly are packet specifiers, not assembly variant
- // specifiers.
- NoAsmVariants = true;
-
- LargeArrayMinWidth = 64;
- LargeArrayAlign = 64;
- UseBitFieldTypeAlignment = true;
- ZeroLengthBitfieldBoundary = 32;
- HasHVX = HasHVXDouble = false;
- UseLongCalls = false;
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin);
- }
-
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- switch (*Name) {
- case 'v':
- case 'q':
- if (HasHVX) {
- Info.setAllowsRegister();
- return true;
- }
- break;
- case 's':
- // Relocatable constant.
- return true;
- }
- return false;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override;
-
- bool isCLZForZeroUndef() const override { return false; }
-
- bool hasFeature(StringRef Feature) const override {
- return llvm::StringSwitch<bool>(Feature)
- .Case("hexagon", true)
- .Case("hvx", HasHVX)
- .Case("hvx-double", HasHVXDouble)
- .Case("long-calls", UseLongCalls)
- .Default(false);
- }
-
- bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU, const std::vector<std::string> &FeaturesVec)
- const override;
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override;
-
- void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name,
- bool Enabled) const override;
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::CharPtrBuiltinVaList;
- }
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
- const char *getClobbers() const override {
- return "";
- }
-
- static const char *getHexagonCPUSuffix(StringRef Name) {
- return llvm::StringSwitch<const char*>(Name)
- .Case("hexagonv4", "4")
- .Case("hexagonv5", "5")
- .Case("hexagonv55", "55")
- .Case("hexagonv60", "60")
- .Default(nullptr);
- }
-
- bool setCPU(const std::string &Name) override {
- if (!getHexagonCPUSuffix(Name))
- return false;
- CPU = Name;
- return true;
- }
-
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- return RegNo < 2 ? RegNo : -1;
- }
-};
-
-void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- Builder.defineMacro("__qdsp6__", "1");
- Builder.defineMacro("__hexagon__", "1");
-
- if (CPU == "hexagonv4") {
- Builder.defineMacro("__HEXAGON_V4__");
- Builder.defineMacro("__HEXAGON_ARCH__", "4");
- if (Opts.HexagonQdsp6Compat) {
- Builder.defineMacro("__QDSP6_V4__");
- Builder.defineMacro("__QDSP6_ARCH__", "4");
- }
- } else if (CPU == "hexagonv5") {
- Builder.defineMacro("__HEXAGON_V5__");
- Builder.defineMacro("__HEXAGON_ARCH__", "5");
- if(Opts.HexagonQdsp6Compat) {
- Builder.defineMacro("__QDSP6_V5__");
- Builder.defineMacro("__QDSP6_ARCH__", "5");
- }
- } else if (CPU == "hexagonv55") {
- Builder.defineMacro("__HEXAGON_V55__");
- Builder.defineMacro("__HEXAGON_ARCH__", "55");
- Builder.defineMacro("__QDSP6_V55__");
- Builder.defineMacro("__QDSP6_ARCH__", "55");
- } else if (CPU == "hexagonv60") {
- Builder.defineMacro("__HEXAGON_V60__");
- Builder.defineMacro("__HEXAGON_ARCH__", "60");
- Builder.defineMacro("__QDSP6_V60__");
- Builder.defineMacro("__QDSP6_ARCH__", "60");
- }
-
- if (hasFeature("hvx")) {
- Builder.defineMacro("__HVX__");
- if (hasFeature("hvx-double"))
- Builder.defineMacro("__HVXDBL__");
- }
-}
-
-bool HexagonTargetInfo::initFeatureMap(llvm::StringMap<bool> &Features,
- DiagnosticsEngine &Diags, StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const {
- // Default for v60: -hvx, -hvx-double.
- Features["hvx"] = false;
- Features["hvx-double"] = false;
- Features["long-calls"] = false;
-
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
-}
-
-bool HexagonTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
- for (auto &F : Features) {
- if (F == "+hvx")
- HasHVX = true;
- else if (F == "-hvx")
- HasHVX = HasHVXDouble = false;
- else if (F == "+hvx-double")
- HasHVX = HasHVXDouble = true;
- else if (F == "-hvx-double")
- HasHVXDouble = false;
-
- if (F == "+long-calls")
- UseLongCalls = true;
- else if (F == "-long-calls")
- UseLongCalls = false;
- }
- return true;
-}
-
-void HexagonTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name, bool Enabled) const {
- if (Enabled) {
- if (Name == "hvx-double")
- Features["hvx"] = true;
- } else {
- if (Name == "hvx")
- Features["hvx-double"] = false;
- }
- Features[Name] = Enabled;
-}
-
-const char *const HexagonTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
- "p0", "p1", "p2", "p3",
- "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp"
-};
-
-ArrayRef<const char*> HexagonTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = {
- { { "sp" }, "r29" },
- { { "fp" }, "r30" },
- { { "lr" }, "r31" },
-};
-
-ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
-}
-
-
-const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsHexagon.def"
-};
-
-class LanaiTargetInfo : public TargetInfo {
- // Class for Lanai (32-bit).
- // The CPU profiles supported by the Lanai backend
- enum CPUKind {
- CK_NONE,
- CK_V11,
- } CPU;
-
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- static const char *const GCCRegNames[];
-
-public:
- LanaiTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- // Description string has to be kept in sync with backend.
- resetDataLayout("E" // Big endian
- "-m:e" // ELF name manging
- "-p:32:32" // 32 bit pointers, 32 bit aligned
- "-i64:64" // 64 bit integers, 64 bit aligned
- "-a:0:32" // 32 bit alignment of objects of aggregate type
- "-n32" // 32 bit native integer width
- "-S64" // 64 bit natural stack alignment
- );
-
- // Setting RegParmMax equal to what mregparm was set to in the old
- // toolchain
- RegParmMax = 4;
-
- // Set the default CPU to V11
- CPU = CK_V11;
-
- // Temporary approach to make everything at least word-aligned and allow for
- // safely casting between pointers with different alignment requirements.
- // TODO: Remove this when there are no more cast align warnings on the
- // firmware.
- MinGlobalAlign = 32;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- // Define __lanai__ when building for target lanai.
- Builder.defineMacro("__lanai__");
-
- // Set define for the CPU specified.
- switch (CPU) {
- case CK_V11:
- Builder.defineMacro("__LANAI_V11__");
- break;
- case CK_NONE:
- llvm_unreachable("Unhandled target CPU");
- }
- }
-
- bool setCPU(const std::string &Name) override {
- CPU = llvm::StringSwitch<CPUKind>(Name)
- .Case("v11", CK_V11)
- .Default(CK_NONE);
-
- return CPU != CK_NONE;
- }
-
- bool hasFeature(StringRef Feature) const override {
- return llvm::StringSwitch<bool>(Feature).Case("lanai", true).Default(false);
- }
-
- ArrayRef<const char *> getGCCRegNames() const override;
-
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
-
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
- return false;
- }
-
- const char *getClobbers() const override { return ""; }
-};
-
-const char *const LanaiTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
- "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
- "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"};
-
-ArrayRef<const char *> LanaiTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = {
- {{"pc"}, "r2"},
- {{"sp"}, "r4"},
- {{"fp"}, "r5"},
- {{"rv"}, "r8"},
- {{"rr1"}, "r10"},
- {{"rr2"}, "r11"},
- {{"rca"}, "r15"},
-};
-
-ArrayRef<TargetInfo::GCCRegAlias> LanaiTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
-}
-
-// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit).
-class SparcTargetInfo : public TargetInfo {
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
- static const char * const GCCRegNames[];
- bool SoftFloat;
-public:
- SparcTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple), SoftFloat(false) {}
-
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- if (RegNo == 0) return 24;
- if (RegNo == 1) return 25;
- return -1;
- }
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override {
- // Check if software floating point is enabled
- auto Feature = std::find(Features.begin(), Features.end(), "+soft-float");
- if (Feature != Features.end()) {
- SoftFloat = true;
- }
- return true;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "sparc", Opts);
- Builder.defineMacro("__REGISTER_PREFIX__", "");
-
- if (SoftFloat)
- Builder.defineMacro("SOFT_FLOAT", "1");
- }
-
- bool hasFeature(StringRef Feature) const override {
- return llvm::StringSwitch<bool>(Feature)
- .Case("softfloat", SoftFloat)
- .Case("sparc", true)
- .Default(false);
- }
-
- bool hasSjLjLowering() const override {
- return true;
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- // FIXME: Implement!
- return None;
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
- // FIXME: Implement!
- switch (*Name) {
- case 'I': // Signed 13-bit constant
- case 'J': // Zero
- case 'K': // 32-bit constant with the low 12 bits clear
- case 'L': // A constant in the range supported by movcc (11-bit signed imm)
- case 'M': // A constant in the range supported by movrcc (19-bit signed imm)
- case 'N': // Same as 'K' but zext (required for SIMode)
- case 'O': // The constant 4096
- return true;
- }
- return false;
- }
- const char *getClobbers() const override {
- // FIXME: Implement!
- return "";
- }
-
- // No Sparc V7 for now, the backend doesn't support it anyway.
- enum CPUKind {
- CK_GENERIC,
- CK_V8,
- CK_SUPERSPARC,
- CK_SPARCLITE,
- CK_F934,
- CK_HYPERSPARC,
- CK_SPARCLITE86X,
- CK_SPARCLET,
- CK_TSC701,
- CK_V9,
- CK_ULTRASPARC,
- CK_ULTRASPARC3,
- CK_NIAGARA,
- CK_NIAGARA2,
- CK_NIAGARA3,
- CK_NIAGARA4,
- CK_MYRIAD2100,
- CK_MYRIAD2150,
- CK_MYRIAD2450,
- CK_LEON2,
- CK_LEON2_AT697E,
- CK_LEON2_AT697F,
- CK_LEON3,
- CK_LEON3_UT699,
- CK_LEON3_GR712RC,
- CK_LEON4,
- CK_LEON4_GR740
- } CPU = CK_GENERIC;
-
- enum CPUGeneration {
- CG_V8,
- CG_V9,
- };
-
- CPUGeneration getCPUGeneration(CPUKind Kind) const {
- switch (Kind) {
- case CK_GENERIC:
- case CK_V8:
- case CK_SUPERSPARC:
- case CK_SPARCLITE:
- case CK_F934:
- case CK_HYPERSPARC:
- case CK_SPARCLITE86X:
- case CK_SPARCLET:
- case CK_TSC701:
- case CK_MYRIAD2100:
- case CK_MYRIAD2150:
- case CK_MYRIAD2450:
- case CK_LEON2:
- case CK_LEON2_AT697E:
- case CK_LEON2_AT697F:
- case CK_LEON3:
- case CK_LEON3_UT699:
- case CK_LEON3_GR712RC:
- case CK_LEON4:
- case CK_LEON4_GR740:
- return CG_V8;
- case CK_V9:
- case CK_ULTRASPARC:
- case CK_ULTRASPARC3:
- case CK_NIAGARA:
- case CK_NIAGARA2:
- case CK_NIAGARA3:
- case CK_NIAGARA4:
- return CG_V9;
- }
- llvm_unreachable("Unexpected CPU kind");
- }
-
- CPUKind getCPUKind(StringRef Name) const {
- return llvm::StringSwitch<CPUKind>(Name)
- .Case("v8", CK_V8)
- .Case("supersparc", CK_SUPERSPARC)
- .Case("sparclite", CK_SPARCLITE)
- .Case("f934", CK_F934)
- .Case("hypersparc", CK_HYPERSPARC)
- .Case("sparclite86x", CK_SPARCLITE86X)
- .Case("sparclet", CK_SPARCLET)
- .Case("tsc701", CK_TSC701)
- .Case("v9", CK_V9)
- .Case("ultrasparc", CK_ULTRASPARC)
- .Case("ultrasparc3", CK_ULTRASPARC3)
- .Case("niagara", CK_NIAGARA)
- .Case("niagara2", CK_NIAGARA2)
- .Case("niagara3", CK_NIAGARA3)
- .Case("niagara4", CK_NIAGARA4)
- .Case("ma2100", CK_MYRIAD2100)
- .Case("ma2150", CK_MYRIAD2150)
- .Case("ma2450", CK_MYRIAD2450)
- // FIXME: the myriad2[.n] spellings are obsolete,
- // but a grace period is needed to allow updating dependent builds.
- .Case("myriad2", CK_MYRIAD2100)
- .Case("myriad2.1", CK_MYRIAD2100)
- .Case("myriad2.2", CK_MYRIAD2150)
- .Case("leon2", CK_LEON2)
- .Case("at697e", CK_LEON2_AT697E)
- .Case("at697f", CK_LEON2_AT697F)
- .Case("leon3", CK_LEON3)
- .Case("ut699", CK_LEON3_UT699)
- .Case("gr712rc", CK_LEON3_GR712RC)
- .Case("leon4", CK_LEON4)
- .Case("gr740", CK_LEON4_GR740)
- .Default(CK_GENERIC);
- }
-
- bool setCPU(const std::string &Name) override {
- CPU = getCPUKind(Name);
- return CPU != CK_GENERIC;
- }
-};
-
-const char * const SparcTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
-};
-
-ArrayRef<const char *> SparcTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = {
- { { "g0" }, "r0" },
- { { "g1" }, "r1" },
- { { "g2" }, "r2" },
- { { "g3" }, "r3" },
- { { "g4" }, "r4" },
- { { "g5" }, "r5" },
- { { "g6" }, "r6" },
- { { "g7" }, "r7" },
- { { "o0" }, "r8" },
- { { "o1" }, "r9" },
- { { "o2" }, "r10" },
- { { "o3" }, "r11" },
- { { "o4" }, "r12" },
- { { "o5" }, "r13" },
- { { "o6", "sp" }, "r14" },
- { { "o7" }, "r15" },
- { { "l0" }, "r16" },
- { { "l1" }, "r17" },
- { { "l2" }, "r18" },
- { { "l3" }, "r19" },
- { { "l4" }, "r20" },
- { { "l5" }, "r21" },
- { { "l6" }, "r22" },
- { { "l7" }, "r23" },
- { { "i0" }, "r24" },
- { { "i1" }, "r25" },
- { { "i2" }, "r26" },
- { { "i3" }, "r27" },
- { { "i4" }, "r28" },
- { { "i5" }, "r29" },
- { { "i6", "fp" }, "r30" },
- { { "i7" }, "r31" },
-};
-
-ArrayRef<TargetInfo::GCCRegAlias> SparcTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
-}
-
-// SPARC v8 is the 32-bit mode selected by Triple::sparc.
-class SparcV8TargetInfo : public SparcTargetInfo {
-public:
- SparcV8TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : SparcTargetInfo(Triple, Opts) {
- resetDataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64");
- // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int.
- switch (getTriple().getOS()) {
- default:
- SizeType = UnsignedInt;
- IntPtrType = SignedInt;
- PtrDiffType = SignedInt;
- break;
- case llvm::Triple::NetBSD:
- case llvm::Triple::OpenBSD:
- SizeType = UnsignedLong;
- IntPtrType = SignedLong;
- PtrDiffType = SignedLong;
- break;
- }
- // Up to 32 bits are lock-free atomic, but we're willing to do atomic ops
- // on up to 64 bits.
- MaxAtomicPromoteWidth = 64;
- MaxAtomicInlineWidth = 32;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- SparcTargetInfo::getTargetDefines(Opts, Builder);
- switch (getCPUGeneration(CPU)) {
- case CG_V8:
- Builder.defineMacro("__sparcv8");
- if (getTriple().getOS() != llvm::Triple::Solaris)
- Builder.defineMacro("__sparcv8__");
- break;
- case CG_V9:
- Builder.defineMacro("__sparcv9");
- if (getTriple().getOS() != llvm::Triple::Solaris) {
- Builder.defineMacro("__sparcv9__");
- Builder.defineMacro("__sparc_v9__");
- }
- break;
- }
- if (getTriple().getVendor() == llvm::Triple::Myriad) {
- std::string MyriadArchValue, Myriad2Value;
- Builder.defineMacro("__sparc_v8__");
- Builder.defineMacro("__leon__");
- switch (CPU) {
- case CK_MYRIAD2150:
- MyriadArchValue = "__ma2150";
- Myriad2Value = "2";
- break;
- case CK_MYRIAD2450:
- MyriadArchValue = "__ma2450";
- Myriad2Value = "2";
- break;
- default:
- MyriadArchValue = "__ma2100";
- Myriad2Value = "1";
- break;
- }
- Builder.defineMacro(MyriadArchValue, "1");
- Builder.defineMacro(MyriadArchValue+"__", "1");
- Builder.defineMacro("__myriad2__", Myriad2Value);
- Builder.defineMacro("__myriad2", Myriad2Value);
- }
- }
-
- bool hasSjLjLowering() const override {
- return true;
- }
-};
-
-// SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel.
-class SparcV8elTargetInfo : public SparcV8TargetInfo {
- public:
- SparcV8elTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : SparcV8TargetInfo(Triple, Opts) {
- resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32-S64");
- }
-};
-
-// SPARC v9 is the 64-bit mode selected by Triple::sparcv9.
-class SparcV9TargetInfo : public SparcTargetInfo {
-public:
- SparcV9TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : SparcTargetInfo(Triple, Opts) {
- // FIXME: Support Sparc quad-precision long double?
- resetDataLayout("E-m:e-i64:64-n32:64-S128");
- // This is an LP64 platform.
- LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
-
- // OpenBSD uses long long for int64_t and intmax_t.
- if (getTriple().getOS() == llvm::Triple::OpenBSD)
- IntMaxType = SignedLongLong;
- else
- IntMaxType = SignedLong;
- Int64Type = IntMaxType;
-
- // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit
- // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned.
- LongDoubleWidth = 128;
- LongDoubleAlign = 128;
- LongDoubleFormat = &llvm::APFloat::IEEEquad();
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- SparcTargetInfo::getTargetDefines(Opts, Builder);
- Builder.defineMacro("__sparcv9");
- Builder.defineMacro("__arch64__");
- // Solaris doesn't need these variants, but the BSDs do.
- if (getTriple().getOS() != llvm::Triple::Solaris) {
- Builder.defineMacro("__sparc64__");
- Builder.defineMacro("__sparc_v9__");
- Builder.defineMacro("__sparcv9__");
- }
- }
-
- bool setCPU(const std::string &Name) override {
- if (!SparcTargetInfo::setCPU(Name))
- return false;
- return getCPUGeneration(CPU) == CG_V9;
- }
-};
-
-class SystemZTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
- static const char *const GCCRegNames[];
- std::string CPU;
- bool HasTransactionalExecution;
- bool HasVector;
-
-public:
- SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false),
- HasVector(false) {
- IntMaxType = SignedLong;
- Int64Type = SignedLong;
- TLSSupported = true;
- IntWidth = IntAlign = 32;
- LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
- PointerWidth = PointerAlign = 64;
- LongDoubleWidth = 128;
- LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEquad();
- DefaultAlignForAttributeAligned = 64;
- MinGlobalAlign = 16;
- resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64");
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__s390__");
- Builder.defineMacro("__s390x__");
- 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");
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
-
- if (HasTransactionalExecution)
- Builder.defineMacro("__HTM__");
- if (HasVector)
- Builder.defineMacro("__VX__");
- if (Opts.ZVector)
- Builder.defineMacro("__VEC__", "10301");
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin);
- }
-
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- // No aliases.
- return None;
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override;
- const char *getClobbers() const override {
- // FIXME: Is this really right?
- return "";
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::SystemZBuiltinVaList;
- }
- bool setCPU(const std::string &Name) override {
- CPU = Name;
- bool CPUKnown = llvm::StringSwitch<bool>(Name)
- .Case("z10", true)
- .Case("arch8", true)
- .Case("z196", true)
- .Case("arch9", true)
- .Case("zEC12", true)
- .Case("arch10", true)
- .Case("z13", true)
- .Case("arch11", true)
- .Default(false);
-
- return CPUKnown;
- }
- bool
- initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const override {
- if (CPU == "zEC12" || CPU == "arch10")
- Features["transactional-execution"] = true;
- if (CPU == "z13" || CPU == "arch11") {
- Features["transactional-execution"] = true;
- Features["vector"] = true;
- }
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
- }
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override {
- HasTransactionalExecution = false;
- for (const auto &Feature : Features) {
- if (Feature == "+transactional-execution")
- HasTransactionalExecution = true;
- else if (Feature == "+vector")
- HasVector = true;
- }
- // If we use the vector ABI, vector types are 64-bit aligned.
- if (HasVector) {
- MaxVectorAlign = 64;
- resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64"
- "-v128:64-a:8:16-n32:64");
- }
- return true;
- }
-
- bool hasFeature(StringRef Feature) const override {
- return llvm::StringSwitch<bool>(Feature)
- .Case("systemz", true)
- .Case("htm", HasTransactionalExecution)
- .Case("vx", HasVector)
- .Default(false);
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- switch (CC) {
- case CC_C:
- case CC_Swift:
- return CCCR_OK;
- default:
- return CCCR_Warning;
- }
- }
-
- StringRef getABI() const override {
- if (HasVector)
- return "vector";
- return "";
- }
-
- bool useFloat128ManglingForLongDouble() const override {
- return true;
- }
-};
-
-const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE },
-#include "clang/Basic/BuiltinsSystemZ.def"
-};
-
-const char *const SystemZTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7",
- "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15"
-};
-
-ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-bool SystemZTargetInfo::
-validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
- switch (*Name) {
- default:
- return false;
-
- case 'a': // Address register
- case 'd': // Data register (equivalent to 'r')
- case 'f': // Floating-point register
- Info.setAllowsRegister();
- return true;
-
- case 'I': // Unsigned 8-bit constant
- case 'J': // Unsigned 12-bit constant
- case 'K': // Signed 16-bit constant
- case 'L': // Signed 20-bit displacement (on all targets we support)
- case 'M': // 0x7fffffff
- return true;
-
- case 'Q': // Memory with base and unsigned 12-bit displacement
- case 'R': // Likewise, plus an index
- case 'S': // Memory with base and signed 20-bit displacement
- case 'T': // Likewise, plus an index
- Info.setAllowsMemory();
- return true;
- }
-}
-
-class MSP430TargetInfo : public TargetInfo {
- static const char *const GCCRegNames[];
-
-public:
- MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- TLSSupported = false;
- IntWidth = 16;
- IntAlign = 16;
- LongWidth = 32;
- LongLongWidth = 64;
- LongAlign = LongLongAlign = 16;
- PointerWidth = 16;
- PointerAlign = 16;
- SuitableAlign = 16;
- SizeType = UnsignedInt;
- IntMaxType = SignedLongLong;
- IntPtrType = SignedInt;
- PtrDiffType = SignedInt;
- SigAtomicType = SignedLong;
- resetDataLayout("e-m:e-p:16:16-i32:16:32-a:16-n8:16");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("MSP430");
- Builder.defineMacro("__MSP430__");
- // FIXME: defines for different 'flavours' of MCU
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- // FIXME: Implement.
- return None;
- }
- bool hasFeature(StringRef Feature) const override {
- return Feature == "msp430";
- }
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- // No aliases.
- return None;
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
- // FIXME: implement
- switch (*Name) {
- case 'K': // the constant 1
- case 'L': // constant -1^20 .. 1^19
- case 'M': // constant 1-4:
- return true;
- }
- // No target constraints for now.
- return false;
- }
- const char *getClobbers() const override {
- // FIXME: Is this really right?
- return "";
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- // FIXME: implement
- return TargetInfo::CharPtrBuiltinVaList;
- }
-};
-
-const char *const MSP430TargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"};
-
-ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
-
-// LLVM and Clang cannot be used directly to output native binaries for
-// target, but is used to compile C code to llvm bitcode with correct
-// type and alignment information.
-//
-// TCE uses the llvm bitcode as input and uses it for generating customized
-// target processor and program binary. TCE co-design environment is
-// publicly available in http://tce.cs.tut.fi
-
-static const unsigned TCEOpenCLAddrSpaceMap[] = {
- 3, // opencl_global
- 4, // opencl_local
- 5, // opencl_constant
- // FIXME: generic has to be added to the target
- 0, // opencl_generic
- 0, // cuda_device
- 0, // cuda_constant
- 0 // cuda_shared
-};
-
-class TCETargetInfo : public TargetInfo {
-public:
- TCETargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- TLSSupported = false;
- IntWidth = 32;
- LongWidth = LongLongWidth = 32;
- PointerWidth = 32;
- IntAlign = 32;
- LongAlign = LongLongAlign = 32;
- PointerAlign = 32;
- SuitableAlign = 32;
- SizeType = UnsignedInt;
- IntMaxType = SignedLong;
- IntPtrType = SignedInt;
- PtrDiffType = SignedInt;
- FloatWidth = 32;
- FloatAlign = 32;
- DoubleWidth = 32;
- DoubleAlign = 32;
- LongDoubleWidth = 32;
- LongDoubleAlign = 32;
- FloatFormat = &llvm::APFloat::IEEEsingle();
- DoubleFormat = &llvm::APFloat::IEEEsingle();
- LongDoubleFormat = &llvm::APFloat::IEEEsingle();
- resetDataLayout("E-p:32:32:32-i1:8:8-i8:8:32-"
- "i16:16:32-i32:32:32-i64:32:32-"
- "f32:32:32-f64:32:32-v64:32:32-"
- "v128:32:32-v256:32:32-v512:32:32-"
- "v1024:32:32-a0:0:32-n32");
- AddrSpaceMap = &TCEOpenCLAddrSpaceMap;
- UseAddrSpaceMapMangling = true;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "tce", Opts);
- Builder.defineMacro("__TCE__");
- Builder.defineMacro("__TCE_V1__");
- }
- bool hasFeature(StringRef Feature) const override { return Feature == "tce"; }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
- const char *getClobbers() const override { return ""; }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
- ArrayRef<const char *> getGCCRegNames() const override { return None; }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
- return true;
- }
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
-};
-
-class TCELETargetInfo : public TCETargetInfo {
-public:
- TCELETargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : TCETargetInfo(Triple, Opts) {
- BigEndian = false;
-
- resetDataLayout("e-p:32:32:32-i1:8:8-i8:8:32-"
- "i16:16:32-i32:32:32-i64:32:32-"
- "f32:32:32-f64:32:32-v64:32:32-"
- "v128:32:32-v256:32:32-v512:32:32-"
- "v1024:32:32-a0:0:32-n32");
-
- }
-
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- DefineStd(Builder, "tcele", Opts);
- Builder.defineMacro("__TCE__");
- Builder.defineMacro("__TCE_V1__");
- Builder.defineMacro("__TCELE__");
- Builder.defineMacro("__TCELE_V1__");
- }
-
-};
-
-class BPFTargetInfo : public TargetInfo {
-public:
- BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
- SizeType = UnsignedLong;
- PtrDiffType = SignedLong;
- IntPtrType = SignedLong;
- IntMaxType = SignedLong;
- Int64Type = SignedLong;
- RegParmMax = 5;
- if (Triple.getArch() == llvm::Triple::bpfeb) {
- resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128");
- } else {
- resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
- }
- MaxAtomicPromoteWidth = 64;
- MaxAtomicInlineWidth = 64;
- TLSSupported = false;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "bpf", Opts);
- Builder.defineMacro("__BPF__");
- }
- bool hasFeature(StringRef Feature) const override {
- return Feature == "bpf";
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
- const char *getClobbers() const override {
- return "";
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
- ArrayRef<const char *> getGCCRegNames() const override {
- return None;
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
- return true;
- }
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
-};
-
-class MipsTargetInfo : public TargetInfo {
- void setDataLayout() {
- StringRef Layout;
-
- if (ABI == "o32")
- Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64";
- else if (ABI == "n32")
- Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128";
- else if (ABI == "n64")
- Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128";
- else
- llvm_unreachable("Invalid ABI");
-
- if (BigEndian)
- resetDataLayout(("E-" + Layout).str());
- else
- resetDataLayout(("e-" + Layout).str());
- }
-
-
- static const Builtin::Info BuiltinInfo[];
- std::string CPU;
- bool IsMips16;
- bool IsMicromips;
- bool IsNan2008;
- bool IsSingleFloat;
- bool IsNoABICalls;
- bool CanUseBSDABICalls;
- enum MipsFloatABI {
- HardFloat, SoftFloat
- } FloatABI;
- enum DspRevEnum {
- NoDSP, DSP1, DSP2
- } DspRev;
- bool HasMSA;
-
-protected:
- bool HasFP64;
- std::string ABI;
-
-public:
- MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple), IsMips16(false), IsMicromips(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 ||
- getTriple().getArch() == llvm::Triple::mipsel)
- ? "o32"
- : "n64");
-
- CPU = ABI == "o32" ? "mips32r2" : "mips64r2";
-
- CanUseBSDABICalls = Triple.getOS() == llvm::Triple::FreeBSD ||
- Triple.getOS() == llvm::Triple::OpenBSD;
- }
-
- bool isNaN2008Default() const {
- return CPU == "mips32r6" || CPU == "mips64r6";
- }
-
- bool isFP64Default() const {
- return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64";
- }
-
- bool isNan2008() const override {
- return IsNan2008;
- }
-
- bool processorSupportsGPR64() const {
- return llvm::StringSwitch<bool>(CPU)
- .Case("mips3", true)
- .Case("mips4", true)
- .Case("mips5", true)
- .Case("mips64", true)
- .Case("mips64r2", true)
- .Case("mips64r3", true)
- .Case("mips64r5", true)
- .Case("mips64r6", true)
- .Case("octeon", true)
- .Default(false);
- return false;
- }
-
- StringRef getABI() const override { return ABI; }
- bool setABI(const std::string &Name) override {
- if (Name == "o32") {
- setO32ABITypes();
- ABI = Name;
- return true;
- }
-
- if (Name == "n32") {
- setN32ABITypes();
- ABI = Name;
- return true;
- }
- if (Name == "n64") {
- setN64ABITypes();
- ABI = Name;
- return true;
- }
- return false;
- }
-
- void setO32ABITypes() {
- Int64Type = SignedLongLong;
- IntMaxType = Int64Type;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- LongDoubleWidth = LongDoubleAlign = 64;
- LongWidth = LongAlign = 32;
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
- PointerWidth = PointerAlign = 32;
- PtrDiffType = SignedInt;
- SizeType = UnsignedInt;
- SuitableAlign = 64;
- }
-
- void setN32N64ABITypes() {
- LongDoubleWidth = LongDoubleAlign = 128;
- LongDoubleFormat = &llvm::APFloat::IEEEquad();
- if (getTriple().getOS() == llvm::Triple::FreeBSD) {
- LongDoubleWidth = LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- }
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- SuitableAlign = 128;
- }
-
- void setN64ABITypes() {
- setN32N64ABITypes();
- if (getTriple().getOS() == llvm::Triple::OpenBSD) {
- Int64Type = SignedLongLong;
- } else {
- Int64Type = SignedLong;
- }
- IntMaxType = Int64Type;
- LongWidth = LongAlign = 64;
- PointerWidth = PointerAlign = 64;
- PtrDiffType = SignedLong;
- SizeType = UnsignedLong;
- }
-
- void setN32ABITypes() {
- setN32N64ABITypes();
- Int64Type = SignedLongLong;
- IntMaxType = Int64Type;
- LongWidth = LongAlign = 32;
- PointerWidth = PointerAlign = 32;
- PtrDiffType = SignedInt;
- SizeType = UnsignedInt;
- }
-
- bool setCPU(const std::string &Name) override {
- CPU = Name;
- return llvm::StringSwitch<bool>(Name)
- .Case("mips1", true)
- .Case("mips2", true)
- .Case("mips3", true)
- .Case("mips4", true)
- .Case("mips5", true)
- .Case("mips32", true)
- .Case("mips32r2", true)
- .Case("mips32r3", true)
- .Case("mips32r5", true)
- .Case("mips32r6", true)
- .Case("mips64", true)
- .Case("mips64r2", true)
- .Case("mips64r3", true)
- .Case("mips64r5", true)
- .Case("mips64r6", true)
- .Case("octeon", true)
- .Case("p5600", true)
- .Default(false);
- }
- const std::string& getCPU() const { return CPU; }
- bool
- initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const override {
- if (CPU.empty())
- CPU = getCPU();
- if (CPU == "octeon")
- Features["mips64r2"] = Features["cnmips"] = true;
- else
- Features[CPU] = true;
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- if (BigEndian) {
- DefineStd(Builder, "MIPSEB", Opts);
- Builder.defineMacro("_MIPSEB");
- } else {
- DefineStd(Builder, "MIPSEL", Opts);
- Builder.defineMacro("_MIPSEL");
- }
-
- Builder.defineMacro("__mips__");
- Builder.defineMacro("_mips");
- if (Opts.GNUMode)
- Builder.defineMacro("mips");
-
- if (ABI == "o32") {
- Builder.defineMacro("__mips", "32");
- Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32");
- } else {
- Builder.defineMacro("__mips", "64");
- Builder.defineMacro("__mips64");
- Builder.defineMacro("__mips64__");
- Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64");
- }
-
- const std::string ISARev = llvm::StringSwitch<std::string>(getCPU())
- .Cases("mips32", "mips64", "1")
- .Cases("mips32r2", "mips64r2", "2")
- .Cases("mips32r3", "mips64r3", "3")
- .Cases("mips32r5", "mips64r5", "5")
- .Cases("mips32r6", "mips64r6", "6")
- .Default("");
- if (!ISARev.empty())
- Builder.defineMacro("__mips_isa_rev", ISARev);
-
- if (ABI == "o32") {
- Builder.defineMacro("__mips_o32");
- Builder.defineMacro("_ABIO32", "1");
- Builder.defineMacro("_MIPS_SIM", "_ABIO32");
- } else if (ABI == "n32") {
- Builder.defineMacro("__mips_n32");
- Builder.defineMacro("_ABIN32", "2");
- Builder.defineMacro("_MIPS_SIM", "_ABIN32");
- } else if (ABI == "n64") {
- Builder.defineMacro("__mips_n64");
- Builder.defineMacro("_ABI64", "3");
- Builder.defineMacro("_MIPS_SIM", "_ABI64");
- } else
- llvm_unreachable("Invalid ABI.");
-
- if (!IsNoABICalls) {
- Builder.defineMacro("__mips_abicalls");
- if (CanUseBSDABICalls)
- Builder.defineMacro("__ABICALLS__");
- }
-
- Builder.defineMacro("__REGISTER_PREFIX__", "");
-
- switch (FloatABI) {
- case HardFloat:
- Builder.defineMacro("__mips_hard_float", Twine(1));
- break;
- case SoftFloat:
- Builder.defineMacro("__mips_soft_float", Twine(1));
- break;
- }
-
- if (IsSingleFloat)
- Builder.defineMacro("__mips_single_float", Twine(1));
-
- Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32));
- Builder.defineMacro("_MIPS_FPSET",
- Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2)));
-
- if (IsMips16)
- Builder.defineMacro("__mips16", Twine(1));
-
- if (IsMicromips)
- Builder.defineMacro("__mips_micromips", Twine(1));
-
- if (IsNan2008)
- Builder.defineMacro("__mips_nan2008", Twine(1));
-
- switch (DspRev) {
- default:
- break;
- case DSP1:
- Builder.defineMacro("__mips_dsp_rev", Twine(1));
- Builder.defineMacro("__mips_dsp", Twine(1));
- break;
- case DSP2:
- Builder.defineMacro("__mips_dsp_rev", Twine(2));
- Builder.defineMacro("__mips_dspr2", Twine(1));
- Builder.defineMacro("__mips_dsp", Twine(1));
- break;
- }
-
- if (HasMSA)
- Builder.defineMacro("__mips_msa", Twine(1));
-
- Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
- Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
- Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
-
- Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\"");
- Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
-
- // These shouldn't be defined for MIPS-I but there's no need to check
- // for that since MIPS-I isn't supported.
- 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");
-
- // 32-bit MIPS processors don't have the necessary lld/scd instructions
- // found in 64-bit processors. In the case of O32 on a 64-bit processor,
- // the instructions exist but using them violates the ABI since they
- // require 64-bit GPRs and O32 only supports 32-bit GPRs.
- if (ABI == "n32" || ABI == "n64")
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin);
- }
- bool hasFeature(StringRef Feature) const override {
- return llvm::StringSwitch<bool>(Feature)
- .Case("mips", true)
- .Case("fp64", HasFP64)
- .Default(false);
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
- ArrayRef<const char *> getGCCRegNames() const override {
- static const char *const GCCRegNames[] = {
- // CPU register names
- // Must match second column of GCCRegAliases
- "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
- "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
- // Floating point register names
- "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
- "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
- "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
- "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
- // Hi/lo and condition register names
- "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
- "$fcc5","$fcc6","$fcc7","$ac1hi","$ac1lo","$ac2hi","$ac2lo",
- "$ac3hi","$ac3lo",
- // MSA register names
- "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7",
- "$w8", "$w9", "$w10", "$w11", "$w12", "$w13", "$w14", "$w15",
- "$w16", "$w17", "$w18", "$w19", "$w20", "$w21", "$w22", "$w23",
- "$w24", "$w25", "$w26", "$w27", "$w28", "$w29", "$w30", "$w31",
- // MSA control register names
- "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify",
- "$msarequest", "$msamap", "$msaunmap"
- };
- return llvm::makeArrayRef(GCCRegNames);
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- switch (*Name) {
- default:
- return false;
- case 'r': // CPU registers.
- case 'd': // Equivalent to "r" unless generating MIPS16 code.
- case 'y': // Equivalent to "r", backward compatibility only.
- case 'f': // floating-point registers.
- case 'c': // $25 for indirect jumps
- case 'l': // lo register
- case 'x': // hilo register pair
- Info.setAllowsRegister();
- return true;
- case 'I': // Signed 16-bit constant
- case 'J': // Integer 0
- case 'K': // Unsigned 16-bit constant
- case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui)
- case 'M': // Constants not loadable via lui, addiu, or ori
- case 'N': // Constant -1 to -65535
- case 'O': // A signed 15-bit constant
- case 'P': // A constant between 1 go 65535
- return true;
- case 'R': // An address that can be used in a non-macro load or store
- Info.setAllowsMemory();
- return true;
- case 'Z':
- if (Name[1] == 'C') { // An address usable by ll, and sc.
- Info.setAllowsMemory();
- Name++; // Skip over 'Z'.
- return true;
- }
- return false;
- }
- }
-
- std::string convertConstraint(const char *&Constraint) const override {
- std::string R;
- switch (*Constraint) {
- case 'Z': // Two-character constraint; add "^" hint for later parsing.
- if (Constraint[1] == 'C') {
- R = std::string("^") + std::string(Constraint, 2);
- Constraint++;
- return R;
- }
- break;
- }
- return TargetInfo::convertConstraint(Constraint);
- }
-
- const char *getClobbers() const override {
- // In GCC, $1 is not widely used in generated code (it's used only in a few
- // specific situations), so there is no real need for users to add it to
- // the clobbers list if they want to use it in their inline assembly code.
- //
- // In LLVM, $1 is treated as a normal GPR and is always allocatable during
- // code generation, so using it in inline assembly without adding it to the
- // clobbers list can cause conflicts between the inline assembly code and
- // the surrounding generated code.
- //
- // Another problem is that LLVM is allowed to choose $1 for inline assembly
- // operands, which will conflict with the ".set at" assembler option (which
- // we use only for inline assembly, in order to maintain compatibility with
- // GCC) and will also conflict with the user's usage of $1.
- //
- // The easiest way to avoid these conflicts and keep $1 as an allocatable
- // register for generated code is to automatically clobber $1 for all inline
- // assembly code.
- //
- // FIXME: We should automatically clobber $1 only for inline assembly code
- // which actually uses it. This would allow LLVM to use $1 for inline
- // assembly operands if the user's assembly code doesn't use it.
- return "~{$1}";
- }
-
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) override {
- IsMips16 = false;
- IsMicromips = false;
- IsNan2008 = isNaN2008Default();
- IsSingleFloat = false;
- FloatABI = HardFloat;
- DspRev = NoDSP;
- HasFP64 = isFP64Default();
-
- for (const auto &Feature : Features) {
- if (Feature == "+single-float")
- IsSingleFloat = true;
- else if (Feature == "+soft-float")
- FloatABI = SoftFloat;
- else if (Feature == "+mips16")
- IsMips16 = true;
- else if (Feature == "+micromips")
- IsMicromips = true;
- else if (Feature == "+dsp")
- DspRev = std::max(DspRev, DSP1);
- else if (Feature == "+dspr2")
- DspRev = std::max(DspRev, DSP2);
- else if (Feature == "+msa")
- HasMSA = true;
- else if (Feature == "+fp64")
- HasFP64 = true;
- else if (Feature == "-fp64")
- HasFP64 = false;
- else if (Feature == "+nan2008")
- IsNan2008 = true;
- else if (Feature == "-nan2008")
- IsNan2008 = false;
- else if (Feature == "+noabicalls")
- IsNoABICalls = true;
- }
-
- setDataLayout();
-
- return true;
- }
-
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- if (RegNo == 0) return 4;
- if (RegNo == 1) return 5;
- return -1;
- }
-
- bool isCLZForZeroUndef() const override { return false; }
-
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- static const TargetInfo::GCCRegAlias O32RegAliases[] = {
- {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"},
- {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"},
- {{"a3"}, "$7"}, {{"t0"}, "$8"}, {{"t1"}, "$9"},
- {{"t2"}, "$10"}, {{"t3"}, "$11"}, {{"t4"}, "$12"},
- {{"t5"}, "$13"}, {{"t6"}, "$14"}, {{"t7"}, "$15"},
- {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"},
- {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"},
- {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"},
- {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"},
- {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"},
- {{"ra"}, "$31"}};
- static const TargetInfo::GCCRegAlias NewABIRegAliases[] = {
- {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"},
- {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"},
- {{"a3"}, "$7"}, {{"a4"}, "$8"}, {{"a5"}, "$9"},
- {{"a6"}, "$10"}, {{"a7"}, "$11"}, {{"t0"}, "$12"},
- {{"t1"}, "$13"}, {{"t2"}, "$14"}, {{"t3"}, "$15"},
- {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"},
- {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"},
- {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"},
- {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"},
- {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"},
- {{"ra"}, "$31"}};
- if (ABI == "o32")
- return llvm::makeArrayRef(O32RegAliases);
- return llvm::makeArrayRef(NewABIRegAliases);
- }
-
- bool hasInt128Type() const override {
- return ABI == "n32" || ABI == "n64";
- }
-
- bool validateTarget(DiagnosticsEngine &Diags) const override {
- // FIXME: It's valid to use O32 on a 64-bit CPU but the backend can't handle
- // this yet. It's better to fail here than on the backend assertion.
- if (processorSupportsGPR64() && ABI == "o32") {
- Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU;
- return false;
- }
-
- // 64-bit ABI's require 64-bit CPU's.
- if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) {
- Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU;
- return false;
- }
-
- // FIXME: It's valid to use O32 on a mips64/mips64el triple but the backend
- // can't handle this yet. It's better to fail here than on the
- // backend assertion.
- if ((getTriple().getArch() == llvm::Triple::mips64 ||
- getTriple().getArch() == llvm::Triple::mips64el) &&
- ABI == "o32") {
- Diags.Report(diag::err_target_unsupported_abi_for_triple)
- << ABI << getTriple().str();
- return false;
- }
-
- // FIXME: It's valid to use N32/N64 on a mips/mipsel triple but the backend
- // can't handle this yet. It's better to fail here than on the
- // backend assertion.
- if ((getTriple().getArch() == llvm::Triple::mips ||
- getTriple().getArch() == llvm::Triple::mipsel) &&
- (ABI == "n32" || ABI == "n64")) {
- Diags.Report(diag::err_target_unsupported_abi_for_triple)
- << ABI << getTriple().str();
- return false;
- }
-
- return true;
- }
-};
-
-const Builtin::Info MipsTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsMips.def"
-};
-
-class PNaClTargetInfo : public TargetInfo {
-public:
- PNaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : TargetInfo(Triple) {
- this->LongAlign = 32;
- this->LongWidth = 32;
- this->PointerAlign = 32;
- this->PointerWidth = 32;
- this->IntMaxType = TargetInfo::SignedLongLong;
- this->Int64Type = TargetInfo::SignedLongLong;
- this->DoubleAlign = 64;
- this->LongDoubleWidth = 64;
- this->LongDoubleAlign = 64;
- this->SizeType = TargetInfo::UnsignedInt;
- this->PtrDiffType = TargetInfo::SignedInt;
- this->IntPtrType = TargetInfo::SignedInt;
- this->RegParmMax = 0; // Disallow regparm
- }
-
- void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const {
- Builder.defineMacro("__le32__");
- Builder.defineMacro("__pnacl__");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- getArchDefines(Opts, Builder);
- }
- bool hasFeature(StringRef Feature) const override {
- return Feature == "pnacl";
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::PNaClABIBuiltinVaList;
- }
- ArrayRef<const char *> getGCCRegNames() const override;
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- return false;
- }
-
- const char *getClobbers() const override {
- return "";
- }
-};
-
-ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const {
- return None;
-}
-
-ArrayRef<TargetInfo::GCCRegAlias> PNaClTargetInfo::getGCCRegAliases() const {
- return None;
-}
-
-// We attempt to use PNaCl (le32) frontend and Mips32EL backend.
-class NaClMips32TargetInfo : public MipsTargetInfo {
-public:
- NaClMips32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : MipsTargetInfo(Triple, Opts) {}
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::PNaClABIBuiltinVaList;
- }
-};
-
-class Le64TargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
-
-public:
- Le64TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- NoAsmVariants = true;
- LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- resetDataLayout("e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128");
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "unix", Opts);
- defineCPUMacros(Builder, "le64", /*Tuning=*/false);
- Builder.defineMacro("__ELF__");
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::Le64::LastTSBuiltin - Builtin::FirstTSBuiltin);
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::PNaClABIBuiltinVaList;
- }
- const char *getClobbers() const override { return ""; }
- ArrayRef<const char *> getGCCRegNames() const override {
- return None;
- }
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- return false;
- }
-
- bool hasProtectedVisibility() const override { return false; }
-};
-
-class WebAssemblyTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
-
- enum SIMDEnum {
- NoSIMD,
- SIMD128,
- } SIMDLevel;
-
-public:
- explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &)
- : TargetInfo(T), SIMDLevel(NoSIMD) {
- NoAsmVariants = true;
- SuitableAlign = 128;
- LargeArrayMinWidth = 128;
- LargeArrayAlign = 128;
- SimdDefaultAlign = 128;
- SigAtomicType = SignedLong;
- LongDoubleWidth = LongDoubleAlign = 128;
- LongDoubleFormat = &llvm::APFloat::IEEEquad();
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- IntPtrType = SignedInt;
- }
-
-protected:
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- defineCPUMacros(Builder, "wasm", /*Tuning=*/false);
- if (SIMDLevel >= SIMD128)
- Builder.defineMacro("__wasm_simd128__");
- }
-
-private:
- bool
- initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
- StringRef CPU,
- const std::vector<std::string> &FeaturesVec) const override {
- if (CPU == "bleeding-edge")
- Features["simd128"] = true;
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
- }
- bool hasFeature(StringRef Feature) const final {
- return llvm::StringSwitch<bool>(Feature)
- .Case("simd128", SIMDLevel >= SIMD128)
- .Default(false);
- }
- bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) final {
- for (const auto &Feature : Features) {
- if (Feature == "+simd128") {
- SIMDLevel = std::max(SIMDLevel, SIMD128);
- continue;
- }
- if (Feature == "-simd128") {
- SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1));
- continue;
- }
-
- Diags.Report(diag::err_opt_not_valid_with_opt) << Feature
- << "-target-feature";
- return false;
- }
- return true;
- }
- bool setCPU(const std::string &Name) final {
- return llvm::StringSwitch<bool>(Name)
- .Case("mvp", true)
- .Case("bleeding-edge", true)
- .Case("generic", true)
- .Default(false);
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const final {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin);
- }
- BuiltinVaListKind getBuiltinVaListKind() const final {
- return VoidPtrBuiltinVaList;
- }
- ArrayRef<const char *> getGCCRegNames() const final {
- return None;
- }
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const final {
- return None;
- }
- bool
- validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const final {
- return false;
- }
- const char *getClobbers() const final { return ""; }
- bool isCLZForZeroUndef() const final { return false; }
- bool hasInt128Type() const final { return true; }
- IntType getIntTypeByWidth(unsigned BitWidth,
- bool IsSigned) const final {
- // WebAssembly prefers long long for explicitly 64-bit integers.
- return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong)
- : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned);
- }
- IntType getLeastIntTypeByWidth(unsigned BitWidth,
- bool IsSigned) const final {
- // WebAssembly uses long long for int_least64_t and int_fast64_t.
- return BitWidth == 64
- ? (IsSigned ? SignedLongLong : UnsignedLongLong)
- : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned);
- }
-};
-
-const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsWebAssembly.def"
-};
-
-class WebAssembly32TargetInfo : public WebAssemblyTargetInfo {
-public:
- explicit WebAssembly32TargetInfo(const llvm::Triple &T,
- const TargetOptions &Opts)
- : WebAssemblyTargetInfo(T, Opts) {
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
- resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128");
- }
-
-protected:
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
- defineCPUMacros(Builder, "wasm32", /*Tuning=*/false);
- }
-};
-
-class WebAssembly64TargetInfo : public WebAssemblyTargetInfo {
-public:
- explicit WebAssembly64TargetInfo(const llvm::Triple &T,
- const TargetOptions &Opts)
- : WebAssemblyTargetInfo(T, Opts) {
- LongAlign = LongWidth = 64;
- PointerAlign = PointerWidth = 64;
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- SizeType = UnsignedLong;
- PtrDiffType = SignedLong;
- IntPtrType = SignedLong;
- resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
- }
-
-protected:
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
- defineCPUMacros(Builder, "wasm64", /*Tuning=*/false);
- }
-};
-
-const Builtin::Info Le64TargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsLe64.def"
-};
-
-static const unsigned SPIRAddrSpaceMap[] = {
- 1, // opencl_global
- 3, // opencl_local
- 2, // opencl_constant
- 4, // opencl_generic
- 0, // cuda_device
- 0, // cuda_constant
- 0 // cuda_shared
-};
-class SPIRTargetInfo : public TargetInfo {
-public:
- SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
- "SPIR target must use unknown OS");
- assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
- "SPIR target must use unknown environment type");
- TLSSupported = false;
- LongWidth = LongAlign = 64;
- AddrSpaceMap = &SPIRAddrSpaceMap;
- UseAddrSpaceMapMangling = true;
- // Define available target features
- // These must be defined in sorted order!
- NoAsmVariants = true;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "SPIR", Opts);
- }
- bool hasFeature(StringRef Feature) const override {
- return Feature == "spir";
- }
-
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
- const char *getClobbers() const override { return ""; }
- ArrayRef<const char *> getGCCRegNames() const override { return None; }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override {
- return true;
- }
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
-
- CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK
- : CCCR_Warning;
- }
-
- CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
- return CC_SpirFunction;
- }
-
- void setSupportedOpenCLOpts() override {
- // Assume all OpenCL extensions and optional core features are supported
- // for SPIR since it is a generic target.
- getSupportedOpenCLOpts().supportAll();
- }
-};
-
-class SPIR32TargetInfo : public SPIRTargetInfo {
-public:
- SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : SPIRTargetInfo(Triple, Opts) {
- PointerWidth = PointerAlign = 32;
- SizeType = TargetInfo::UnsignedInt;
- PtrDiffType = IntPtrType = TargetInfo::SignedInt;
- resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
- "v96:128-v192:256-v256:256-v512:512-v1024:1024");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "SPIR32", Opts);
- }
-};
-
-class SPIR64TargetInfo : public SPIRTargetInfo {
-public:
- SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : SPIRTargetInfo(Triple, Opts) {
- PointerWidth = PointerAlign = 64;
- SizeType = TargetInfo::UnsignedLong;
- PtrDiffType = IntPtrType = TargetInfo::SignedLong;
- resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
- "v96:128-v192:256-v256:256-v512:512-v1024:1024");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- DefineStd(Builder, "SPIR64", Opts);
- }
-};
-
-class XCoreTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
-public:
- XCoreTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- NoAsmVariants = true;
- LongLongAlign = 32;
- SuitableAlign = 32;
- DoubleAlign = LongDoubleAlign = 32;
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- IntPtrType = SignedInt;
- WCharType = UnsignedChar;
- WIntType = UnsignedInt;
- UseZeroLengthBitfieldAlignment = true;
- resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32"
- "-f64:32-a:0:32-n32");
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__XS1B__");
- }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin);
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
- const char *getClobbers() const override {
- return "";
- }
- ArrayRef<const char *> getGCCRegNames() const override {
- static const char * const GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr"
- };
- return llvm::makeArrayRef(GCCRegNames);
- }
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const override {
- return false;
- }
- int getEHDataRegisterNumber(unsigned RegNo) const override {
- // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister
- return (RegNo < 2)? RegNo : -1;
- }
- bool allowsLargerPreferedTypeAlignment() const override {
- return false;
- }
-};
-
-const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr },
-#include "clang/Basic/BuiltinsXCore.def"
-};
-
-// x86_32 Android target
-class AndroidX86_32TargetInfo : public LinuxTargetInfo<X86_32TargetInfo> {
-public:
- AndroidX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : LinuxTargetInfo<X86_32TargetInfo>(Triple, Opts) {
- SuitableAlign = 32;
- LongDoubleWidth = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- }
-};
-
-// x86_64 Android target
-class AndroidX86_64TargetInfo : public LinuxTargetInfo<X86_64TargetInfo> {
-public:
- AndroidX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : LinuxTargetInfo<X86_64TargetInfo>(Triple, Opts) {
- LongDoubleFormat = &llvm::APFloat::IEEEquad();
- }
-
- bool useFloat128ManglingForLongDouble() const override {
- return true;
- }
-};
-
-// 32-bit RenderScript is armv7 with width and align of 'long' set to 8-bytes
-class RenderScript32TargetInfo : public ARMleTargetInfo {
-public:
- RenderScript32TargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(),
- Triple.getOSName(),
- Triple.getEnvironmentName()),
- Opts) {
- IsRenderScriptTarget = true;
- LongWidth = LongAlign = 64;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__RENDERSCRIPT__");
- ARMleTargetInfo::getTargetDefines(Opts, Builder);
- }
-};
-
-// 64-bit RenderScript is aarch64
-class RenderScript64TargetInfo : public AArch64leTargetInfo {
-public:
- RenderScript64TargetInfo(const llvm::Triple &Triple,
- const TargetOptions &Opts)
- : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(),
- Triple.getOSName(),
- Triple.getEnvironmentName()),
- Opts) {
- IsRenderScriptTarget = true;
- }
-
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__RENDERSCRIPT__");
- AArch64leTargetInfo::getTargetDefines(Opts, Builder);
- }
-};
-
-/// 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 {
-public:
- AVRTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple) {
- TLSSupported = false;
- PointerWidth = 16;
- PointerAlign = 8;
- IntWidth = 16;
- IntAlign = 8;
- LongWidth = 32;
- LongAlign = 8;
- LongLongWidth = 64;
- LongLongAlign = 8;
- SuitableAlign = 8;
- DefaultAlignForAttributeAligned = 8;
- HalfWidth = 16;
- HalfAlign = 8;
- FloatWidth = 32;
- FloatAlign = 8;
- DoubleWidth = 32;
- DoubleAlign = 8;
- DoubleFormat = &llvm::APFloat::IEEEsingle();
- LongDoubleWidth = 32;
- LongDoubleAlign = 8;
- LongDoubleFormat = &llvm::APFloat::IEEEsingle();
- SizeType = UnsignedInt;
- PtrDiffType = SignedInt;
- IntPtrType = SignedInt;
- Char16Type = UnsignedInt;
- WCharType = SignedInt;
- WIntType = SignedInt;
- Char32Type = UnsignedLong;
- SigAtomicType = SignedChar;
- resetDataLayout("e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64"
- "-f32:32:32-f64:64:64-n8");
- }
-
- 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 {
- return None;
- }
-
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::VoidPtrBuiltinVaList;
- }
-
- const char *getClobbers() const override {
- return "";
- }
-
- ArrayRef<const char *> getGCCRegNames() const override {
- static const char * const GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "X", "Y", "Z", "SP"
- };
- return llvm::makeArrayRef(GCCRegNames);
- }
-
- ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
- }
-
- ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override {
- static const TargetInfo::AddlRegName AddlRegNames[] = {
- { { "r26", "r27"}, 26 },
- { { "r28", "r29"}, 27 },
- { { "r30", "r31"}, 28 },
- { { "SPL", "SPH"}, 29 },
- };
- return llvm::makeArrayRef(AddlRegNames);
- }
-
- 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;
- }
-
- IntType getIntTypeByWidth(unsigned BitWidth,
- bool IsSigned) const final {
- // AVR prefers int for 16-bit integers.
- return BitWidth == 16 ? (IsSigned ? SignedInt : UnsignedInt)
- : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned);
- }
-
- IntType getLeastIntTypeByWidth(unsigned BitWidth,
- bool IsSigned) const final {
- // AVR uses int for int_least16_t and int_fast16_t.
- return BitWidth == 16
- ? (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
-
//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
-static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
- const TargetOptions &Opts) {
+TargetInfo *AllocateTarget(const llvm::Triple &Triple,
+ const TargetOptions &Opts) {
llvm::Triple::OSType os = Triple.getOS();
switch (Triple.getArch()) {
@@ -9002,6 +141,14 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new NetBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts);
case llvm::Triple::OpenBSD:
return new OpenBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts);
+ case llvm::Triple::Win32:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::GNU:
+ return new MinGWARM64TargetInfo(Triple, Opts);
+ case llvm::Triple::MSVC:
+ default: // Assume MSVC for unknown environments
+ return new MicrosoftARM64TargetInfo(Triple, Opts);
+ }
default:
return new AArch64leTargetInfo(Triple, Opts);
}
@@ -9036,8 +183,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new NetBSDTargetInfo<ARMleTargetInfo>(Triple, Opts);
case llvm::Triple::OpenBSD:
return new OpenBSDTargetInfo<ARMleTargetInfo>(Triple, Opts);
- case llvm::Triple::Bitrig:
- return new BitrigTargetInfo<ARMleTargetInfo>(Triple, Opts);
case llvm::Triple::RTEMS:
return new RTEMSTargetInfo<ARMleTargetInfo>(Triple, Opts);
case llvm::Triple::NaCl:
@@ -9072,8 +217,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new NetBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts);
case llvm::Triple::OpenBSD:
return new OpenBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts);
- case llvm::Triple::Bitrig:
- return new BitrigTargetInfo<ARMbeTargetInfo>(Triple, Opts);
case llvm::Triple::RTEMS:
return new RTEMSTargetInfo<ARMbeTargetInfo>(Triple, Opts);
case llvm::Triple::NaCl:
@@ -9091,6 +234,9 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
case llvm::Triple::msp430:
return new MSP430TargetInfo(Triple, Opts);
+ case llvm::Triple::nios2:
+ return new LinuxTargetInfo<Nios2TargetInfo>(Triple, Opts);
+
case llvm::Triple::mips:
switch (os) {
case llvm::Triple::Linux:
@@ -9283,6 +429,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new DarwinI386TargetInfo(Triple, Opts);
switch (os) {
+ case llvm::Triple::Ananas:
+ return new AnanasTargetInfo<X86_32TargetInfo>(Triple, Opts);
case llvm::Triple::CloudABI:
return new CloudABITargetInfo<X86_32TargetInfo>(Triple, Opts);
case llvm::Triple::Linux: {
@@ -9299,8 +447,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new NetBSDI386TargetInfo(Triple, Opts);
case llvm::Triple::OpenBSD:
return new OpenBSDI386TargetInfo(Triple, Opts);
- case llvm::Triple::Bitrig:
- return new BitrigI386TargetInfo(Triple, Opts);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<X86_32TargetInfo>(Triple, Opts);
case llvm::Triple::KFreeBSD:
@@ -9338,6 +484,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new DarwinX86_64TargetInfo(Triple, Opts);
switch (os) {
+ case llvm::Triple::Ananas:
+ return new AnanasTargetInfo<X86_64TargetInfo>(Triple, Opts);
case llvm::Triple::CloudABI:
return new CloudABITargetInfo<X86_64TargetInfo>(Triple, Opts);
case llvm::Triple::Linux: {
@@ -9354,8 +502,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new NetBSDTargetInfo<X86_64TargetInfo>(Triple, Opts);
case llvm::Triple::OpenBSD:
return new OpenBSDX86_64TargetInfo(Triple, Opts);
- case llvm::Triple::Bitrig:
- return new BitrigX86_64TargetInfo(Triple, Opts);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<X86_64TargetInfo>(Triple, Opts);
case llvm::Triple::Fuchsia:
@@ -9420,7 +566,10 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new LinuxTargetInfo<RenderScript64TargetInfo>(Triple, Opts);
}
}
+} // namespace targets
+} // namespace clang
+using namespace clang::targets;
/// CreateTargetInfo - Return the target info object for the specified target
/// options.
TargetInfo *
@@ -9459,7 +608,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
llvm::StringMap<bool> Features;
if (!Target->initFeatureMap(Features, Diags, Opts->CPU,
Opts->FeaturesAsWritten))
- return nullptr;
+ return nullptr;
// Add the features to the compile options.
Opts->Features.clear();
@@ -9471,6 +620,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Target->setSupportedOpenCLOpts();
Target->setOpenCLExtensionOpts();
+ Target->setMaxAtomicWidth();
if (!Target->validateTarget(Diags))
return nullptr;
diff --git a/lib/Basic/Targets.h b/lib/Basic/Targets.h
new file mode 100644
index 0000000000..12a23fa814
--- /dev/null
+++ b/lib/Basic/Targets.h
@@ -0,0 +1,51 @@
+//===------- Targets.h - Declare target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares things required for construction of a TargetInfo object
+// from a target triple. Typically individual targets will need to include from
+// here in order to get these functions if required.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_H
+
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace targets {
+
+LLVM_LIBRARY_VISIBILITY
+clang::TargetInfo *AllocateTarget(const llvm::Triple &Triple,
+ const clang::TargetOptions &Opts);
+
+/// DefineStd - Define a macro name and standard variants. For example if
+/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix"
+/// when in GNU mode.
+LLVM_LIBRARY_VISIBILITY
+void DefineStd(clang::MacroBuilder &Builder, llvm::StringRef MacroName,
+ const clang::LangOptions &Opts);
+
+LLVM_LIBRARY_VISIBILITY
+void defineCPUMacros(clang::MacroBuilder &Builder, llvm::StringRef CPUName,
+ bool Tuning = true);
+
+LLVM_LIBRARY_VISIBILITY
+void addMinGWDefines(const clang::LangOptions &Opts,
+ clang::MacroBuilder &Builder);
+
+LLVM_LIBRARY_VISIBILITY
+void addCygMingDefines(const clang::LangOptions &Opts,
+ clang::MacroBuilder &Builder);
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_H
diff --git a/lib/Basic/Targets/AArch64.cpp b/lib/Basic/Targets/AArch64.cpp
new file mode 100644
index 0000000000..f58bf9f277
--- /dev/null
+++ b/lib/Basic/Targets/AArch64.cpp
@@ -0,0 +1,550 @@
+//===--- AArch64.cpp - Implement AArch64 target feature support -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements AArch64 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsNEON.def"
+
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \
+ {#ID, TYPE, ATTRS, nullptr, LANG, nullptr},
+#include "clang/Basic/BuiltinsAArch64.def"
+};
+
+AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : TargetInfo(Triple), ABI("aapcs") {
+ if (getTriple().getOS() == llvm::Triple::NetBSD ||
+ getTriple().getOS() == llvm::Triple::OpenBSD) {
+ // NetBSD apparently prefers consistency across ARM targets to
+ // consistency across 64-bit targets.
+ Int64Type = SignedLongLong;
+ IntMaxType = SignedLongLong;
+ } else {
+ if (!getTriple().isOSDarwin())
+ WCharType = UnsignedInt;
+
+ Int64Type = SignedLong;
+ IntMaxType = SignedLong;
+ }
+
+
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ MaxVectorAlign = 128;
+ MaxAtomicInlineWidth = 128;
+ MaxAtomicPromoteWidth = 128;
+
+ LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad();
+
+ // Make __builtin_ms_va_list available.
+ HasBuiltinMSVaList = true;
+
+ // {} in inline assembly are neon specifiers, not assembly variant
+ // specifiers.
+ NoAsmVariants = true;
+
+ // AAPCS gives rules for bitfields. 7.1.7 says: "The container type
+ // contributes to the alignment of the containing aggregate in the same way
+ // a plain (non bit-field) member of that type would, without exception for
+ // zero-sized or anonymous bit-fields."
+ assert(UseBitFieldTypeAlignment && "bitfields affect type alignment");
+ UseZeroLengthBitfieldAlignment = true;
+
+ // AArch64 targets default to using the ARM C++ ABI.
+ TheCXXABI.set(TargetCXXABI::GenericAArch64);
+
+ if (Triple.getOS() == llvm::Triple::Linux)
+ this->MCountName = "\01_mcount";
+ else if (Triple.getOS() == llvm::Triple::UnknownOS)
+ this->MCountName =
+ Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount";
+}
+
+StringRef AArch64TargetInfo::getABI() const { return ABI; }
+
+bool AArch64TargetInfo::setABI(const std::string &Name) {
+ if (Name != "aapcs" && Name != "darwinpcs")
+ return false;
+
+ ABI = Name;
+ return true;
+}
+
+bool AArch64TargetInfo::isValidCPUName(StringRef Name) const {
+ return Name == "generic" ||
+ llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID;
+}
+
+bool AArch64TargetInfo::setCPU(const std::string &Name) {
+ return isValidCPUName(Name);
+}
+
+void AArch64TargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+}
+
+void AArch64TargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Also include the ARMv8.1 defines
+ getTargetDefinesARMV81A(Opts, Builder);
+}
+
+void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Target identification.
+ Builder.defineMacro("__aarch64__");
+ // For bare-metal none-eabi.
+ if (getTriple().getOS() == llvm::Triple::UnknownOS &&
+ (getTriple().getEnvironment() == llvm::Triple::EABI ||
+ getTriple().getEnvironment() == llvm::Triple::EABIHF))
+ Builder.defineMacro("__ELF__");
+
+ // Target properties.
+ if (!getTriple().isOSWindows()) {
+ Builder.defineMacro("_LP64");
+ Builder.defineMacro("__LP64__");
+ }
+
+ // ACLE predefines. Many can only have one possible value on v8 AArch64.
+ Builder.defineMacro("__ARM_ACLE", "200");
+ Builder.defineMacro("__ARM_ARCH", "8");
+ Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'");
+
+ Builder.defineMacro("__ARM_64BIT_STATE", "1");
+ Builder.defineMacro("__ARM_PCS_AAPCS64", "1");
+ Builder.defineMacro("__ARM_ARCH_ISA_A64", "1");
+
+ Builder.defineMacro("__ARM_FEATURE_CLZ", "1");
+ Builder.defineMacro("__ARM_FEATURE_FMA", "1");
+ Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF");
+ Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE
+ Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility
+ Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1");
+ Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1");
+
+ Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");
+
+ // 0xe implies support for half, single and double precision operations.
+ Builder.defineMacro("__ARM_FP", "0xE");
+
+ // PCS specifies this for SysV variants, which is all we support. Other ABIs
+ // may choose __ARM_FP16_FORMAT_ALTERNATIVE.
+ Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1");
+ Builder.defineMacro("__ARM_FP16_ARGS", "1");
+
+ if (Opts.UnsafeFPMath)
+ Builder.defineMacro("__ARM_FP_FAST", "1");
+
+ Builder.defineMacro("__ARM_SIZEOF_WCHAR_T",
+ llvm::utostr(Opts.WCharSize ? Opts.WCharSize : 4));
+
+ Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4");
+
+ if (FPU & NeonMode) {
+ Builder.defineMacro("__ARM_NEON", "1");
+ // 64-bit NEON supports half, single and double precision operations.
+ Builder.defineMacro("__ARM_NEON_FP", "0xE");
+ }
+
+ if (FPU & SveMode)
+ Builder.defineMacro("__ARM_FEATURE_SVE", "1");
+
+ if (CRC)
+ Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
+
+ if (Crypto)
+ Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1");
+
+ if (Unaligned)
+ Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
+
+ switch (ArchKind) {
+ default:
+ break;
+ case llvm::AArch64::ArchKind::ARMV8_1A:
+ getTargetDefinesARMV81A(Opts, Builder);
+ break;
+ case llvm::AArch64::ArchKind::ARMV8_2A:
+ getTargetDefinesARMV82A(Opts, Builder);
+ break;
+ }
+
+ // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+}
+
+ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
+ return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" ||
+ (Feature == "neon" && (FPU & NeonMode)) ||
+ (Feature == "sve" && (FPU & SveMode));
+}
+
+bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ FPU = FPUMode;
+ CRC = 0;
+ Crypto = 0;
+ Unaligned = 1;
+ HasFullFP16 = 0;
+ ArchKind = llvm::AArch64::ArchKind::ARMV8A;
+
+ for (const auto &Feature : Features) {
+ if (Feature == "+neon")
+ FPU |= NeonMode;
+ if (Feature == "+sve")
+ FPU |= SveMode;
+ if (Feature == "+crc")
+ CRC = 1;
+ if (Feature == "+crypto")
+ Crypto = 1;
+ if (Feature == "+strict-align")
+ Unaligned = 0;
+ if (Feature == "+v8.1a")
+ ArchKind = llvm::AArch64::ArchKind::ARMV8_1A;
+ if (Feature == "+v8.2a")
+ ArchKind = llvm::AArch64::ArchKind::ARMV8_2A;
+ if (Feature == "+fullfp16")
+ HasFullFP16 = 1;
+ }
+
+ setDataLayout();
+
+ return true;
+}
+
+TargetInfo::CallingConvCheckResult
+AArch64TargetInfo::checkCallingConvention(CallingConv CC) const {
+ switch (CC) {
+ case CC_C:
+ case CC_Swift:
+ case CC_PreserveMost:
+ case CC_PreserveAll:
+ case CC_OpenCLKernel:
+ case CC_Win64:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+}
+
+bool AArch64TargetInfo::isCLZForZeroUndef() const { return false; }
+
+TargetInfo::BuiltinVaListKind AArch64TargetInfo::getBuiltinVaListKind() const {
+ return TargetInfo::AArch64ABIBuiltinVaList;
+}
+
+const char *const AArch64TargetInfo::GCCRegNames[] = {
+ // 32-bit Integer registers
+ "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11",
+ "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22",
+ "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp",
+
+ // 64-bit Integer registers
+ "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",
+
+ // 32-bit floating point regsisters
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
+ "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22",
+ "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+
+ // 64-bit floating point regsisters
+ "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",
+
+ // Vector registers
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
+ "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22",
+ "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+};
+
+ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
+ {{"w31"}, "wsp"}, {{"x29"}, "fp"}, {{"x30"}, "lr"}, {{"x31"}, "sp"},
+ // The S/D/Q and W/X registers overlap, but aren't really aliases; we
+ // don't want to substitute one of these for a different-sized one.
+};
+
+ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const {
+ return llvm::makeArrayRef(GCCRegAliases);
+}
+
+bool AArch64TargetInfo::validateAsmConstraint(
+ const char *&Name, TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ return false;
+ case 'w': // Floating point and SIMD registers (V0-V31)
+ Info.setAllowsRegister();
+ return true;
+ case 'I': // Constant that can be used with an ADD instruction
+ case 'J': // Constant that can be used with a SUB instruction
+ case 'K': // Constant that can be used with a 32-bit logical instruction
+ case 'L': // Constant that can be used with a 64-bit logical instruction
+ case 'M': // Constant that can be used as a 32-bit MOV immediate
+ case 'N': // Constant that can be used as a 64-bit MOV immediate
+ case 'Y': // Floating point constant zero
+ case 'Z': // Integer constant zero
+ return true;
+ case 'Q': // A memory reference with base register and no offset
+ Info.setAllowsMemory();
+ return true;
+ case 'S': // A symbolic address
+ Info.setAllowsRegister();
+ return true;
+ case 'U':
+ // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes.
+ // Utf: A memory address suitable for ldp/stp in TF mode.
+ // Usa: An absolute symbolic address.
+ // Ush: The high part (bits 32:12) of a pc-relative symbolic address.
+ llvm_unreachable("FIXME: Unimplemented support for U* constraints.");
+ case 'z': // Zero register, wzr or xzr
+ Info.setAllowsRegister();
+ return true;
+ case 'x': // Floating point and SIMD registers (V0-V15)
+ Info.setAllowsRegister();
+ return true;
+ }
+ return false;
+}
+
+bool AArch64TargetInfo::validateConstraintModifier(
+ StringRef Constraint, char Modifier, unsigned Size,
+ std::string &SuggestedModifier) const {
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
+
+ switch (Constraint[0]) {
+ default:
+ return true;
+ case 'z':
+ case 'r': {
+ switch (Modifier) {
+ case 'x':
+ case 'w':
+ // For now assume that the person knows what they're
+ // doing with the modifier.
+ return true;
+ default:
+ // By default an 'r' constraint will be in the 'x'
+ // registers.
+ if (Size == 64)
+ return true;
+
+ SuggestedModifier = "w";
+ return false;
+ }
+ }
+ }
+}
+
+const char *AArch64TargetInfo::getClobbers() const { return ""; }
+
+int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0)
+ return 0;
+ if (RegNo == 1)
+ return 1;
+ return -1;
+}
+
+AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : AArch64TargetInfo(Triple, Opts) {}
+
+void AArch64leTargetInfo::setDataLayout() {
+ if (getTriple().isOSBinFormatMachO())
+ resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128");
+ else
+ resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
+}
+
+void AArch64leTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__AARCH64EL__");
+ AArch64TargetInfo::getTargetDefines(Opts, Builder);
+}
+
+AArch64beTargetInfo::AArch64beTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : AArch64TargetInfo(Triple, Opts) {}
+
+void AArch64beTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__AARCH64EB__");
+ Builder.defineMacro("__AARCH_BIG_ENDIAN");
+ Builder.defineMacro("__ARM_BIG_ENDIAN");
+ AArch64TargetInfo::getTargetDefines(Opts, Builder);
+}
+
+void AArch64beTargetInfo::setDataLayout() {
+ assert(!getTriple().isOSBinFormatMachO());
+ resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128");
+}
+
+WindowsARM64TargetInfo::WindowsARM64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) {
+
+ // This is an LLP64 platform.
+ // int:4, long:4, long long:8, long double:8.
+ IntWidth = IntAlign = 32;
+ LongWidth = LongAlign = 32;
+ DoubleAlign = LongLongAlign = 64;
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ IntMaxType = SignedLongLong;
+ Int64Type = SignedLongLong;
+ SizeType = UnsignedLongLong;
+ PtrDiffType = SignedLongLong;
+ IntPtrType = SignedLongLong;
+}
+
+void WindowsARM64TargetInfo::setDataLayout() {
+ resetDataLayout("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128");
+}
+
+TargetInfo::BuiltinVaListKind
+WindowsARM64TargetInfo::getBuiltinVaListKind() const {
+ return TargetInfo::CharPtrBuiltinVaList;
+}
+
+TargetInfo::CallingConvCheckResult
+WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const {
+ switch (CC) {
+ case CC_X86StdCall:
+ case CC_X86ThisCall:
+ case CC_X86FastCall:
+ case CC_X86VectorCall:
+ return CCCR_Ignore;
+ case CC_C:
+ case CC_OpenCLKernel:
+ case CC_PreserveMost:
+ case CC_PreserveAll:
+ case CC_Win64:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+}
+
+MicrosoftARM64TargetInfo::MicrosoftARM64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsARM64TargetInfo(Triple, Opts) {
+ TheCXXABI.set(TargetCXXABI::Microsoft);
+}
+
+void MicrosoftARM64TargetInfo::getVisualStudioDefines(
+ const LangOptions &Opts, MacroBuilder &Builder) const {
+ WindowsTargetInfo<AArch64leTargetInfo>::getVisualStudioDefines(Opts, Builder);
+ Builder.defineMacro("_WIN32", "1");
+ Builder.defineMacro("_WIN64", "1");
+ Builder.defineMacro("_M_ARM64", "1");
+}
+
+void MicrosoftARM64TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsTargetInfo::getTargetDefines(Opts, Builder);
+ getVisualStudioDefines(Opts, Builder);
+}
+
+MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsARM64TargetInfo(Triple, Opts) {
+ TheCXXABI.set(TargetCXXABI::GenericAArch64);
+}
+
+void MinGWARM64TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsTargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_WIN32", "1");
+ Builder.defineMacro("_WIN64", "1");
+ Builder.defineMacro("WIN32", "1");
+ Builder.defineMacro("WIN64", "1");
+ addMinGWDefines(Opts, Builder);
+}
+
+
+DarwinAArch64TargetInfo::DarwinAArch64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) {
+ Int64Type = SignedLongLong;
+ UseSignedCharForObjCBool = false;
+
+ LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+
+ TheCXXABI.set(TargetCXXABI::iOS64);
+}
+
+void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts,
+ const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__AARCH64_SIMD__");
+ Builder.defineMacro("__ARM64_ARCH_8__");
+ Builder.defineMacro("__ARM_NEON__");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__arm64", "1");
+ Builder.defineMacro("__arm64__", "1");
+
+ getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
+}
+
+TargetInfo::BuiltinVaListKind
+DarwinAArch64TargetInfo::getBuiltinVaListKind() const {
+ return TargetInfo::CharPtrBuiltinVaList;
+}
+
+// 64-bit RenderScript is aarch64
+RenderScript64TargetInfo::RenderScript64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(),
+ Triple.getOSName(),
+ Triple.getEnvironmentName()),
+ Opts) {
+ IsRenderScriptTarget = true;
+}
+
+void RenderScript64TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__RENDERSCRIPT__");
+ AArch64leTargetInfo::getTargetDefines(Opts, Builder);
+}
diff --git a/lib/Basic/Targets/AArch64.h b/lib/Basic/Targets/AArch64.h
new file mode 100644
index 0000000000..8391b7367a
--- /dev/null
+++ b/lib/Basic/Targets/AArch64.h
@@ -0,0 +1,166 @@
+//===--- AArch64.h - Declare AArch64 target feature support -----*- 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 AArch64 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H
+
+#include "OSTargets.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/Support/TargetParser.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
+ virtual void setDataLayout() = 0;
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char *const GCCRegNames[];
+
+ enum FPUModeEnum { FPUMode, NeonMode = (1 << 0), SveMode = (1 << 1) };
+
+ unsigned FPU;
+ unsigned CRC;
+ unsigned Crypto;
+ unsigned Unaligned;
+ unsigned HasFullFP16;
+ llvm::AArch64::ArchKind ArchKind;
+
+ static const Builtin::Info BuiltinInfo[];
+
+ std::string ABI;
+
+public:
+ AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ StringRef getABI() const override;
+ bool setABI(const std::string &Name) override;
+
+ bool isValidCPUName(StringRef Name) const override;
+ bool setCPU(const std::string &Name) override;
+
+ void getTargetDefinesARMV81A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
+ void getTargetDefinesARMV82A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ bool hasFeature(StringRef Feature) const override;
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;
+
+ bool isCLZForZeroUndef() const override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override;
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override;
+ bool
+ validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size,
+ std::string &SuggestedModifier) const override;
+ const char *getClobbers() const override;
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo {
+public:
+ AArch64leTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+private:
+ void setDataLayout() override;
+};
+
+class LLVM_LIBRARY_VISIBILITY WindowsARM64TargetInfo
+ : public WindowsTargetInfo<AArch64leTargetInfo> {
+ const llvm::Triple Triple;
+
+public:
+ WindowsARM64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts);
+
+ void setDataLayout() override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override;
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;
+};
+
+// Windows ARM, MS (C++) ABI
+class LLVM_LIBRARY_VISIBILITY MicrosoftARM64TargetInfo
+ : public WindowsARM64TargetInfo {
+public:
+ MicrosoftARM64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts);
+
+ void getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+// ARM64 MinGW target
+class LLVM_LIBRARY_VISIBILITY MinGWARM64TargetInfo
+ : public WindowsARM64TargetInfo {
+public:
+ MinGWARM64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY AArch64beTargetInfo : public AArch64TargetInfo {
+public:
+ AArch64beTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+private:
+ void setDataLayout() override;
+};
+
+class LLVM_LIBRARY_VISIBILITY DarwinAArch64TargetInfo
+ : public DarwinTargetInfo<AArch64leTargetInfo> {
+public:
+ DarwinAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ BuiltinVaListKind getBuiltinVaListKind() const override;
+
+ protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override;
+};
+
+// 64-bit RenderScript is aarch64
+class LLVM_LIBRARY_VISIBILITY RenderScript64TargetInfo
+ : public AArch64leTargetInfo {
+public:
+ RenderScript64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+} // namespace targets
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H
diff --git a/lib/Basic/Targets/AMDGPU.cpp b/lib/Basic/Targets/AMDGPU.cpp
new file mode 100644
index 0000000000..b8740ca4b4
--- /dev/null
+++ b/lib/Basic/Targets/AMDGPU.cpp
@@ -0,0 +1,373 @@
+//===--- AMDGPU.cpp - Implement AMDGPU target feature support -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements AMDGPU TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+namespace clang {
+namespace targets {
+
+// If you edit the description strings, make sure you update
+// getPointerWidthV().
+
+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 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";
+
+static const LangASMap AMDGPUPrivIsZeroDefIsGenMap = {
+ 4, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_private
+ 4, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+
+static const LangASMap AMDGPUGenIsZeroDefIsGenMap = {
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 5, // opencl_private
+ 0, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+
+static const LangASMap AMDGPUPrivIsZeroDefIsPrivMap = {
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_private
+ 4, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+
+static const LangASMap AMDGPUGenIsZeroDefIsPrivMap = {
+ 5, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 5, // opencl_private
+ 0, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+} // namespace targets
+} // namespace clang
+
+const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#include "clang/Basic/BuiltinsAMDGPU.def"
+};
+
+const char *const AMDGPUTargetInfo::GCCRegNames[] = {
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8",
+ "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17",
+ "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26",
+ "v27", "v28", "v29", "v30", "v31", "v32", "v33", "v34", "v35",
+ "v36", "v37", "v38", "v39", "v40", "v41", "v42", "v43", "v44",
+ "v45", "v46", "v47", "v48", "v49", "v50", "v51", "v52", "v53",
+ "v54", "v55", "v56", "v57", "v58", "v59", "v60", "v61", "v62",
+ "v63", "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71",
+ "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79", "v80",
+ "v81", "v82", "v83", "v84", "v85", "v86", "v87", "v88", "v89",
+ "v90", "v91", "v92", "v93", "v94", "v95", "v96", "v97", "v98",
+ "v99", "v100", "v101", "v102", "v103", "v104", "v105", "v106", "v107",
+ "v108", "v109", "v110", "v111", "v112", "v113", "v114", "v115", "v116",
+ "v117", "v118", "v119", "v120", "v121", "v122", "v123", "v124", "v125",
+ "v126", "v127", "v128", "v129", "v130", "v131", "v132", "v133", "v134",
+ "v135", "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143",
+ "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151", "v152",
+ "v153", "v154", "v155", "v156", "v157", "v158", "v159", "v160", "v161",
+ "v162", "v163", "v164", "v165", "v166", "v167", "v168", "v169", "v170",
+ "v171", "v172", "v173", "v174", "v175", "v176", "v177", "v178", "v179",
+ "v180", "v181", "v182", "v183", "v184", "v185", "v186", "v187", "v188",
+ "v189", "v190", "v191", "v192", "v193", "v194", "v195", "v196", "v197",
+ "v198", "v199", "v200", "v201", "v202", "v203", "v204", "v205", "v206",
+ "v207", "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215",
+ "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223", "v224",
+ "v225", "v226", "v227", "v228", "v229", "v230", "v231", "v232", "v233",
+ "v234", "v235", "v236", "v237", "v238", "v239", "v240", "v241", "v242",
+ "v243", "v244", "v245", "v246", "v247", "v248", "v249", "v250", "v251",
+ "v252", "v253", "v254", "v255", "s0", "s1", "s2", "s3", "s4",
+ "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13",
+ "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22",
+ "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+ "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", "s40",
+ "s41", "s42", "s43", "s44", "s45", "s46", "s47", "s48", "s49",
+ "s50", "s51", "s52", "s53", "s54", "s55", "s56", "s57", "s58",
+ "s59", "s60", "s61", "s62", "s63", "s64", "s65", "s66", "s67",
+ "s68", "s69", "s70", "s71", "s72", "s73", "s74", "s75", "s76",
+ "s77", "s78", "s79", "s80", "s81", "s82", "s83", "s84", "s85",
+ "s86", "s87", "s88", "s89", "s90", "s91", "s92", "s93", "s94",
+ "s95", "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103",
+ "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111", "s112",
+ "s113", "s114", "s115", "s116", "s117", "s118", "s119", "s120", "s121",
+ "s122", "s123", "s124", "s125", "s126", "s127", "exec", "vcc", "scc",
+ "m0", "flat_scratch", "exec_lo", "exec_hi", "vcc_lo", "vcc_hi",
+ "flat_scratch_lo", "flat_scratch_hi"
+};
+
+ArrayRef<const char *> AMDGPUTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+bool AMDGPUTargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeatureVec) const {
+
+ // XXX - What does the member GPU mean if device name string passed here?
+ if (getTriple().getArch() == llvm::Triple::amdgcn) {
+ if (CPU.empty())
+ CPU = "tahiti";
+
+ switch (parseAMDGCNName(CPU)) {
+ case GK_GFX6:
+ 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:
+ return false;
+ default:
+ llvm_unreachable("unhandled subtarget");
+ }
+ } else {
+ if (CPU.empty())
+ CPU = "r600";
+
+ switch (parseR600Name(CPU)) {
+ case GK_R600:
+ case GK_R700:
+ case GK_EVERGREEN:
+ case GK_NORTHERN_ISLANDS:
+ break;
+ case GK_R600_DOUBLE_OPS:
+ case GK_R700_DOUBLE_OPS:
+ case GK_EVERGREEN_DOUBLE_OPS:
+ case GK_CAYMAN:
+ Features["fp64"] = true;
+ break;
+ case GK_NONE:
+ return false;
+ default:
+ llvm_unreachable("unhandled subtarget");
+ }
+ }
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec);
+}
+
+void AMDGPUTargetInfo::adjustTargetOptions(const CodeGenOptions &CGOpts,
+ TargetOptions &TargetOpts) const {
+ bool hasFP32Denormals = false;
+ bool hasFP64Denormals = false;
+ for (auto &I : TargetOpts.FeaturesAsWritten) {
+ if (I == "+fp32-denormals" || I == "-fp32-denormals")
+ hasFP32Denormals = true;
+ if (I == "+fp64-fp16-denormals" || I == "-fp64-fp16-denormals")
+ hasFP64Denormals = true;
+ }
+ if (!hasFP32Denormals)
+ TargetOpts.Features.push_back(
+ (Twine(hasFullSpeedFMAF32(TargetOpts.CPU) && !CGOpts.FlushDenorm
+ ? '+'
+ : '-') +
+ Twine("fp32-denormals"))
+ .str());
+ // Always do not flush fp64 or fp16 denorms.
+ if (!hasFP64Denormals && hasFP64)
+ TargetOpts.Features.push_back("+fp64-fp16-denormals");
+}
+
+AMDGPUTargetInfo::GPUKind AMDGPUTargetInfo::parseR600Name(StringRef Name) {
+ return llvm::StringSwitch<GPUKind>(Name)
+ .Case("r600", GK_R600)
+ .Case("rv610", GK_R600)
+ .Case("rv620", GK_R600)
+ .Case("rv630", GK_R600)
+ .Case("rv635", GK_R600)
+ .Case("rs780", GK_R600)
+ .Case("rs880", GK_R600)
+ .Case("rv670", GK_R600_DOUBLE_OPS)
+ .Case("rv710", GK_R700)
+ .Case("rv730", GK_R700)
+ .Case("rv740", GK_R700_DOUBLE_OPS)
+ .Case("rv770", GK_R700_DOUBLE_OPS)
+ .Case("palm", GK_EVERGREEN)
+ .Case("cedar", GK_EVERGREEN)
+ .Case("sumo", GK_EVERGREEN)
+ .Case("sumo2", GK_EVERGREEN)
+ .Case("redwood", GK_EVERGREEN)
+ .Case("juniper", GK_EVERGREEN)
+ .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("cypress", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("barts", GK_NORTHERN_ISLANDS)
+ .Case("turks", GK_NORTHERN_ISLANDS)
+ .Case("caicos", GK_NORTHERN_ISLANDS)
+ .Case("cayman", GK_CAYMAN)
+ .Case("aruba", GK_CAYMAN)
+ .Default(GK_NONE);
+}
+
+AMDGPUTargetInfo::GPUKind AMDGPUTargetInfo::parseAMDGCNName(StringRef Name) {
+ return llvm::StringSwitch<GPUKind>(Name)
+ .Case("gfx600", GK_GFX6)
+ .Case("tahiti", GK_GFX6)
+ .Case("gfx601", GK_GFX6)
+ .Case("pitcairn", GK_GFX6)
+ .Case("verde", GK_GFX6)
+ .Case("oland", GK_GFX6)
+ .Case("hainan", GK_GFX6)
+ .Case("gfx700", GK_GFX7)
+ .Case("bonaire", GK_GFX7)
+ .Case("kaveri", GK_GFX7)
+ .Case("gfx701", GK_GFX7)
+ .Case("hawaii", GK_GFX7)
+ .Case("gfx702", GK_GFX7)
+ .Case("gfx703", GK_GFX7)
+ .Case("kabini", GK_GFX7)
+ .Case("mullins", GK_GFX7)
+ .Case("gfx800", GK_GFX8)
+ .Case("iceland", GK_GFX8)
+ .Case("gfx801", GK_GFX8)
+ .Case("carrizo", GK_GFX8)
+ .Case("gfx802", GK_GFX8)
+ .Case("tonga", GK_GFX8)
+ .Case("gfx803", GK_GFX8)
+ .Case("fiji", GK_GFX8)
+ .Case("polaris10", GK_GFX8)
+ .Case("polaris11", GK_GFX8)
+ .Case("gfx804", GK_GFX8)
+ .Case("gfx810", GK_GFX8)
+ .Case("stoney", GK_GFX8)
+ .Case("gfx900", GK_GFX9)
+ .Case("gfx901", GK_GFX9)
+ .Case("gfx902", GK_GFX9)
+ .Case("gfx903", GK_GFX9)
+ .Default(GK_NONE);
+}
+
+void AMDGPUTargetInfo::setAddressSpaceMap(bool DefaultIsPrivate) {
+ if (isGenericZero(getTriple())) {
+ AddrSpaceMap = DefaultIsPrivate ? &AMDGPUGenIsZeroDefIsPrivMap
+ : &AMDGPUGenIsZeroDefIsGenMap;
+ } else {
+ AddrSpaceMap = DefaultIsPrivate ? &AMDGPUPrivIsZeroDefIsPrivMap
+ : &AMDGPUPrivIsZeroDefIsGenMap;
+ }
+}
+
+AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : TargetInfo(Triple),
+ GPU(isAMDGCN(Triple) ? GK_GFX6 : parseR600Name(Opts.CPU)),
+ hasFP64(false), hasFMAF(false), hasLDEXPF(false),
+ AS(isGenericZero(Triple)) {
+ if (getTriple().getArch() == llvm::Triple::amdgcn) {
+ hasFP64 = true;
+ hasFMAF = true;
+ hasLDEXPF = true;
+ }
+ if (getTriple().getArch() == llvm::Triple::r600) {
+ if (GPU == GK_EVERGREEN_DOUBLE_OPS || GPU == GK_CAYMAN) {
+ hasFMAF = true;
+ }
+ }
+ auto IsGenericZero = isGenericZero(Triple);
+ resetDataLayout(getTriple().getArch() == llvm::Triple::amdgcn
+ ? (IsGenericZero ? DataLayoutStringSIGenericIsZero
+ : DataLayoutStringSIPrivateIsZero)
+ : DataLayoutStringR600);
+ assert(DataLayout->getAllocaAddrSpace() == AS.Private);
+
+ setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D ||
+ Triple.getEnvironment() == llvm::Triple::OpenCL ||
+ Triple.getEnvironmentName() == "amdgizcl" ||
+ !isAMDGCN(Triple));
+ UseAddrSpaceMapMangling = true;
+
+ // Set pointer width and alignment for target address space 0.
+ PointerWidth = PointerAlign = DataLayout->getPointerSizeInBits();
+ if (getMaxPointerWidth() == 64) {
+ LongWidth = LongAlign = 64;
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ IntPtrType = SignedLong;
+ }
+
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+}
+
+void AMDGPUTargetInfo::adjust(LangOptions &Opts) {
+ TargetInfo::adjust(Opts);
+ setAddressSpaceMap(Opts.OpenCL || !isAMDGCN(getTriple()));
+}
+
+ArrayRef<Builtin::Info> AMDGPUTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::AMDGPU::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ if (getTriple().getArch() == llvm::Triple::amdgcn)
+ Builder.defineMacro("__AMDGCN__");
+ else
+ Builder.defineMacro("__R600__");
+
+ if (hasFMAF)
+ Builder.defineMacro("__HAS_FMAF__");
+ if (hasLDEXPF)
+ Builder.defineMacro("__HAS_LDEXPF__");
+ if (hasFP64)
+ Builder.defineMacro("__HAS_FP64__");
+}
diff --git a/lib/Basic/Targets/AMDGPU.h b/lib/Basic/Targets/AMDGPU.h
new file mode 100644
index 0000000000..4cbf0f202e
--- /dev/null
+++ b/lib/Basic/Targets/AMDGPU.h
@@ -0,0 +1,329 @@
+//===--- AMDGPU.h - Declare AMDGPU target feature support -------*- 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 AMDGPU TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
+
+ static const Builtin::Info BuiltinInfo[];
+ static const char *const GCCRegNames[];
+
+ struct LLVM_LIBRARY_VISIBILITY 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,
+ GK_R600,
+ GK_R600_DOUBLE_OPS,
+ GK_R700,
+ GK_R700_DOUBLE_OPS,
+ GK_EVERGREEN,
+ GK_EVERGREEN_DOUBLE_OPS,
+ GK_NORTHERN_ISLANDS,
+ GK_CAYMAN,
+ GK_GFX6,
+ GK_GFX7,
+ GK_GFX8,
+ GK_GFX9
+ } GPU;
+
+ bool hasFP64 : 1;
+ bool hasFMAF : 1;
+ bool hasLDEXPF : 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);
+
+ void setAddressSpaceMap(bool DefaultIsPrivate);
+
+ void adjust(LangOptions &Opts) override;
+
+ uint64_t getPointerWidthV(unsigned AddrSpace) const override {
+ if (GPU <= GK_CAYMAN)
+ return 32;
+
+ if (AddrSpace == AS.Private || AddrSpace == AS.Local) {
+ return 32;
+ }
+ return 64;
+ }
+
+ uint64_t getPointerAlignV(unsigned AddrSpace) const override {
+ return getPointerWidthV(AddrSpace);
+ }
+
+ uint64_t getMaxPointerWidth() const override {
+ return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32;
+ }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+
+ /// Accepted register names: (n, m is unsigned integer, n < m)
+ /// v
+ /// s
+ /// {vn}, {v[n]}
+ /// {sn}, {s[n]}
+ /// {S} , where S is a special register name
+ ////{v[n:m]}
+ /// {s[n:m]}
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ static const ::llvm::StringSet<> SpecialRegs({
+ "exec", "vcc", "flat_scratch", "m0", "scc", "tba", "tma",
+ "flat_scratch_lo", "flat_scratch_hi", "vcc_lo", "vcc_hi", "exec_lo",
+ "exec_hi", "tma_lo", "tma_hi", "tba_lo", "tba_hi",
+ });
+
+ StringRef S(Name);
+ bool HasLeftParen = false;
+ if (S.front() == '{') {
+ HasLeftParen = true;
+ S = S.drop_front();
+ }
+ if (S.empty())
+ return false;
+ if (S.front() != 'v' && S.front() != 's') {
+ if (!HasLeftParen)
+ return false;
+ auto E = S.find('}');
+ if (!SpecialRegs.count(S.substr(0, E)))
+ return false;
+ S = S.drop_front(E + 1);
+ if (!S.empty())
+ return false;
+ // Found {S} where S is a special register.
+ Info.setAllowsRegister();
+ Name = S.data() - 1;
+ return true;
+ }
+ S = S.drop_front();
+ if (!HasLeftParen) {
+ if (!S.empty())
+ return false;
+ // Found s or v.
+ Info.setAllowsRegister();
+ Name = S.data() - 1;
+ return true;
+ }
+ bool HasLeftBracket = false;
+ if (!S.empty() && S.front() == '[') {
+ HasLeftBracket = true;
+ S = S.drop_front();
+ }
+ unsigned long long N;
+ if (S.empty() || consumeUnsignedInteger(S, 10, N))
+ return false;
+ if (!S.empty() && S.front() == ':') {
+ if (!HasLeftBracket)
+ return false;
+ S = S.drop_front();
+ unsigned long long M;
+ if (consumeUnsignedInteger(S, 10, M) || N >= M)
+ return false;
+ }
+ if (HasLeftBracket) {
+ if (S.empty() || S.front() != ']')
+ return false;
+ S = S.drop_front();
+ }
+ if (S.empty() || S.front() != '}')
+ return false;
+ S = S.drop_front();
+ if (!S.empty())
+ return false;
+ // Found {vn}, {sn}, {v[n]}, {s[n]}, {v[n:m]}, or {s[n:m]}.
+ Info.setAllowsRegister();
+ Name = S.data() - 1;
+ return true;
+ }
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeatureVec) const override;
+
+ void adjustTargetOptions(const CodeGenOptions &CGOpts,
+ TargetOptions &TargetOpts) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+ static GPUKind parseR600Name(StringRef Name);
+
+ static GPUKind parseAMDGCNName(StringRef Name);
+
+ bool isValidCPUName(StringRef Name) const override {
+ if (getTriple().getArch() == llvm::Triple::amdgcn)
+ return GK_NONE != parseAMDGCNName(Name);
+ else
+ return GK_NONE != parseR600Name(Name);
+ }
+
+ bool setCPU(const std::string &Name) override {
+ if (getTriple().getArch() == llvm::Triple::amdgcn)
+ GPU = parseAMDGCNName(Name);
+ else
+ GPU = parseR600Name(Name);
+
+ return GPU != GK_NONE;
+ }
+
+ void setSupportedOpenCLOpts() override {
+ auto &Opts = getSupportedOpenCLOpts();
+ Opts.support("cl_clang_storage_class_specifiers");
+ Opts.support("cl_khr_icd");
+
+ if (hasFP64)
+ Opts.support("cl_khr_fp64");
+ if (GPU >= GK_EVERGREEN) {
+ Opts.support("cl_khr_byte_addressable_store");
+ Opts.support("cl_khr_global_int32_base_atomics");
+ Opts.support("cl_khr_global_int32_extended_atomics");
+ Opts.support("cl_khr_local_int32_base_atomics");
+ Opts.support("cl_khr_local_int32_extended_atomics");
+ }
+ if (GPU >= GK_GFX6) {
+ Opts.support("cl_khr_fp16");
+ Opts.support("cl_khr_int64_base_atomics");
+ Opts.support("cl_khr_int64_extended_atomics");
+ Opts.support("cl_khr_mipmap_image");
+ Opts.support("cl_khr_subgroups");
+ Opts.support("cl_khr_3d_image_writes");
+ Opts.support("cl_amd_media_ops");
+ Opts.support("cl_amd_media_ops2");
+ }
+ }
+
+ LangAS getOpenCLTypeAddrSpace(const Type *T) const override {
+ auto BT = dyn_cast<BuiltinType>(T);
+
+ if (!BT)
+ return TargetInfo::getOpenCLTypeAddrSpace(T);
+
+ switch (BT->getKind()) {
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id: \
+ return LangAS::opencl_constant;
+#include "clang/Basic/OpenCLImageTypes.def"
+ case BuiltinType::OCLClkEvent:
+ case BuiltinType::OCLQueue:
+ case BuiltinType::OCLReserveID:
+ return LangAS::opencl_global;
+
+ default:
+ return TargetInfo::getOpenCLTypeAddrSpace(T);
+ }
+ }
+
+ llvm::Optional<LangAS> getConstantAddressSpace() const override {
+ return getLangASFromTargetAS(AS.Constant);
+ }
+
+ /// \returns Target specific vtbl ptr address space.
+ unsigned getVtblPtrAddressSpace() const override { return AS.Constant; }
+
+ /// \returns If a target requires an address within a target specific address
+ /// space \p AddressSpace to be converted in order to be used, then return the
+ /// corresponding target specific DWARF address space.
+ ///
+ /// \returns Otherwise return None and no conversion will be emitted in the
+ /// DWARF.
+ Optional<unsigned>
+ getDWARFAddressSpace(unsigned AddressSpace) const override {
+ const unsigned DWARF_Private = 1;
+ const unsigned DWARF_Local = 2;
+ if (AddressSpace == AS.Private) {
+ return DWARF_Private;
+ } else if (AddressSpace == AS.Local) {
+ return DWARF_Local;
+ } else {
+ return None;
+ }
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ default:
+ return CCCR_Warning;
+ case CC_C:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ }
+ }
+
+ // In amdgcn target the null pointer in global, constant, and generic
+ // address space has value 0 but in private and local address space has
+ // value ~0.
+ uint64_t getNullPointerValue(LangAS AS) const override {
+ return AS == LangAS::opencl_local ? ~0 : 0;
+ }
+};
+
+} // namespace targets
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H
diff --git a/lib/Basic/Targets/ARM.cpp b/lib/Basic/Targets/ARM.cpp
new file mode 100644
index 0000000000..def490b99f
--- /dev/null
+++ b/lib/Basic/Targets/ARM.cpp
@@ -0,0 +1,1067 @@
+//===--- ARM.cpp - Implement ARM target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements ARM TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARM.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+void ARMTargetInfo::setABIAAPCS() {
+ IsAAPCS = true;
+
+ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
+ const llvm::Triple &T = getTriple();
+
+ bool IsNetBSD = T.getOS() == llvm::Triple::NetBSD;
+ bool IsOpenBSD = T.getOS() == llvm::Triple::OpenBSD;
+ if (!T.isOSWindows() && !IsNetBSD && !IsOpenBSD)
+ WCharType = UnsignedInt;
+
+ UseBitFieldTypeAlignment = true;
+
+ ZeroLengthBitfieldBoundary = 0;
+
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
+ if (T.isOSBinFormatMachO()) {
+ resetDataLayout(BigEndian
+ ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+ : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64");
+ } else if (T.isOSWindows()) {
+ assert(!BigEndian && "Windows on ARM does not support big endian");
+ resetDataLayout("e"
+ "-m:w"
+ "-p:32:32"
+ "-i64:64"
+ "-v128:64:128"
+ "-a:0:32"
+ "-n32"
+ "-S64");
+ } else if (T.isOSNaCl()) {
+ assert(!BigEndian && "NaCl on ARM does not support big endian");
+ resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128");
+ } else {
+ resetDataLayout(BigEndian
+ ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+ : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64");
+ }
+
+ // FIXME: Enumerated types are variable width in straight AAPCS.
+}
+
+void ARMTargetInfo::setABIAPCS(bool IsAAPCS16) {
+ const llvm::Triple &T = getTriple();
+
+ IsAAPCS = false;
+
+ if (IsAAPCS16)
+ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
+ else
+ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
+
+ WCharType = SignedInt;
+
+ // Do not respect the alignment of bit-field types when laying out
+ // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
+ UseBitFieldTypeAlignment = false;
+
+ /// gcc forces the alignment to 4 bytes, regardless of the type of the
+ /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in
+ /// gcc.
+ ZeroLengthBitfieldBoundary = 32;
+
+ if (T.isOSBinFormatMachO() && IsAAPCS16) {
+ assert(!BigEndian && "AAPCS16 does not support big-endian");
+ resetDataLayout("e-m:o-p:32:32-i64:64-a:0:32-n32-S128");
+ } else if (T.isOSBinFormatMachO())
+ resetDataLayout(
+ BigEndian
+ ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+ : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32");
+ else
+ resetDataLayout(
+ BigEndian
+ ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+ : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32");
+
+ // FIXME: Override "preferred align" for double and long long.
+}
+
+void ARMTargetInfo::setArchInfo() {
+ StringRef ArchName = getTriple().getArchName();
+
+ ArchISA = llvm::ARM::parseArchISA(ArchName);
+ CPU = llvm::ARM::getDefaultCPU(ArchName);
+ llvm::ARM::ArchKind AK = llvm::ARM::parseArch(ArchName);
+ if (AK != llvm::ARM::ArchKind::INVALID)
+ ArchKind = AK;
+ setArchInfo(ArchKind);
+}
+
+void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) {
+ StringRef SubArch;
+
+ // cache TargetParser info
+ ArchKind = Kind;
+ SubArch = llvm::ARM::getSubArch(ArchKind);
+ ArchProfile = llvm::ARM::parseArchProfile(SubArch);
+ ArchVersion = llvm::ARM::parseArchVersion(SubArch);
+
+ // cache CPU related strings
+ CPUAttr = getCPUAttr();
+ CPUProfile = getCPUProfile();
+}
+
+void ARMTargetInfo::setAtomic() {
+ // when triple does not specify a sub arch,
+ // then we are not using inline atomics
+ bool ShouldUseInlineAtomic =
+ (ArchISA == llvm::ARM::ISAKind::ARM && ArchVersion >= 6) ||
+ (ArchISA == llvm::ARM::ISAKind::THUMB && ArchVersion >= 7);
+ // Cortex M does not support 8 byte atomics, while general Thumb2 does.
+ if (ArchProfile == llvm::ARM::ProfileKind::M) {
+ MaxAtomicPromoteWidth = 32;
+ if (ShouldUseInlineAtomic)
+ MaxAtomicInlineWidth = 32;
+ } else {
+ MaxAtomicPromoteWidth = 64;
+ if (ShouldUseInlineAtomic)
+ MaxAtomicInlineWidth = 64;
+ }
+}
+
+bool ARMTargetInfo::isThumb() const {
+ return ArchISA == llvm::ARM::ISAKind::THUMB;
+}
+
+bool ARMTargetInfo::supportsThumb() const {
+ return CPUAttr.count('T') || ArchVersion >= 6;
+}
+
+bool ARMTargetInfo::supportsThumb2() const {
+ return CPUAttr.equals("6T2") ||
+ (ArchVersion >= 7 && !CPUAttr.equals("8M_BASE"));
+}
+
+StringRef ARMTargetInfo::getCPUAttr() const {
+ // For most sub-arches, the build attribute CPU name is enough.
+ // For Cortex variants, it's slightly different.
+ switch (ArchKind) {
+ default:
+ return llvm::ARM::getCPUAttr(ArchKind);
+ case llvm::ARM::ArchKind::ARMV6M:
+ return "6M";
+ case llvm::ARM::ArchKind::ARMV7S:
+ return "7S";
+ case llvm::ARM::ArchKind::ARMV7A:
+ return "7A";
+ case llvm::ARM::ArchKind::ARMV7R:
+ return "7R";
+ case llvm::ARM::ArchKind::ARMV7M:
+ return "7M";
+ case llvm::ARM::ArchKind::ARMV7EM:
+ return "7EM";
+ case llvm::ARM::ArchKind::ARMV7VE:
+ return "7VE";
+ case llvm::ARM::ArchKind::ARMV8A:
+ return "8A";
+ case llvm::ARM::ArchKind::ARMV8_1A:
+ return "8_1A";
+ case llvm::ARM::ArchKind::ARMV8_2A:
+ return "8_2A";
+ case llvm::ARM::ArchKind::ARMV8MBaseline:
+ return "8M_BASE";
+ case llvm::ARM::ArchKind::ARMV8MMainline:
+ return "8M_MAIN";
+ case llvm::ARM::ArchKind::ARMV8R:
+ return "8R";
+ }
+}
+
+StringRef ARMTargetInfo::getCPUProfile() const {
+ switch (ArchProfile) {
+ case llvm::ARM::ProfileKind::A:
+ return "A";
+ case llvm::ARM::ProfileKind::R:
+ return "R";
+ case llvm::ARM::ProfileKind::M:
+ return "M";
+ default:
+ return "";
+ }
+}
+
+ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0),
+ HW_FP(0) {
+ bool IsOpenBSD = Triple.getOS() == llvm::Triple::OpenBSD;
+ bool IsNetBSD = Triple.getOS() == llvm::Triple::NetBSD;
+
+ // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like
+ // environment where size_t is `unsigned long` rather than `unsigned int`
+
+ PtrDiffType = IntPtrType =
+ (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD ||
+ IsNetBSD)
+ ? SignedLong
+ : SignedInt;
+
+ SizeType = (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD ||
+ IsNetBSD)
+ ? UnsignedLong
+ : UnsignedInt;
+
+ // ptrdiff_t is inconsistent on Darwin
+ if ((Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) &&
+ !Triple.isWatchABI())
+ PtrDiffType = SignedInt;
+
+ // Cache arch related info.
+ setArchInfo();
+
+ // {} in inline assembly are neon specifiers, not assembly variant
+ // specifiers.
+ NoAsmVariants = true;
+
+ // FIXME: This duplicates code from the driver that sets the -target-abi
+ // option - this code is used if -target-abi isn't passed and should
+ // be unified in some way.
+ if (Triple.isOSBinFormatMachO()) {
+ // The backend is hardwired to assume AAPCS for M-class processors, ensure
+ // the frontend matches that.
+ if (Triple.getEnvironment() == llvm::Triple::EABI ||
+ Triple.getOS() == llvm::Triple::UnknownOS ||
+ ArchProfile == llvm::ARM::ProfileKind::M) {
+ setABI("aapcs");
+ } else if (Triple.isWatchABI()) {
+ setABI("aapcs16");
+ } else {
+ setABI("apcs-gnu");
+ }
+ } else if (Triple.isOSWindows()) {
+ // FIXME: this is invalid for WindowsCE
+ setABI("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:
+ setABI("aapcs-linux");
+ break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::EABI:
+ setABI("aapcs");
+ break;
+ case llvm::Triple::GNU:
+ setABI("apcs-gnu");
+ break;
+ default:
+ if (Triple.getOS() == llvm::Triple::NetBSD)
+ setABI("apcs-gnu");
+ else if (Triple.getOS() == llvm::Triple::OpenBSD)
+ setABI("aapcs-linux");
+ else
+ setABI("aapcs");
+ break;
+ }
+ }
+
+ // ARM targets default to using the ARM C++ ABI.
+ TheCXXABI.set(TargetCXXABI::GenericARM);
+
+ // ARM has atomics up to 8 bytes
+ setAtomic();
+
+ // Maximum alignment for ARM NEON data types should be 64-bits (AAPCS)
+ if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android))
+ MaxVectorAlign = 64;
+
+ // Do force alignment of members that follow zero length bitfields. If
+ // the alignment of the zero-length bitfield is greater than the member
+ // that follows it, `bar', `bar' will be aligned as the type of the
+ // zero length bitfield.
+ UseZeroLengthBitfieldAlignment = true;
+
+ if (Triple.getOS() == llvm::Triple::Linux ||
+ Triple.getOS() == llvm::Triple::UnknownOS)
+ this->MCountName = Opts.EABIVersion == llvm::EABI::GNU
+ ? "\01__gnu_mcount_nc"
+ : "\01mcount";
+}
+
+StringRef ARMTargetInfo::getABI() const { return ABI; }
+
+bool ARMTargetInfo::setABI(const std::string &Name) {
+ ABI = Name;
+
+ // The defaults (above) are for AAPCS, check if we need to change them.
+ //
+ // FIXME: We need support for -meabi... we could just mangle it into the
+ // name.
+ if (Name == "apcs-gnu" || Name == "aapcs16") {
+ setABIAPCS(Name == "aapcs16");
+ return true;
+ }
+ if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") {
+ setABIAAPCS();
+ return true;
+ }
+ return false;
+}
+
+// FIXME: This should be based on Arch attributes, not CPU names.
+bool ARMTargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+
+ std::vector<StringRef> TargetFeatures;
+ llvm::ARM::ArchKind Arch = llvm::ARM::parseArch(getTriple().getArchName());
+
+ // get default FPU features
+ unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch);
+ llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures);
+
+ // get default Extension features
+ unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch);
+ llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures);
+
+ for (auto Feature : TargetFeatures)
+ if (Feature[0] == '+')
+ Features[Feature.drop_front(1)] = true;
+
+ // Enable or disable thumb-mode explicitly per function to enable mixed
+ // ARM and Thumb code generation.
+ if (isThumb())
+ Features["thumb-mode"] = true;
+ else
+ Features["thumb-mode"] = false;
+
+ // Convert user-provided arm and thumb GNU target attributes to
+ // [-|+]thumb-mode target features respectively.
+ std::vector<std::string> UpdatedFeaturesVec(FeaturesVec);
+ for (auto &Feature : UpdatedFeaturesVec) {
+ if (Feature.compare("+arm") == 0)
+ Feature = "-thumb-mode";
+ else if (Feature.compare("+thumb") == 0)
+ Feature = "+thumb-mode";
+ }
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec);
+}
+
+
+bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ FPU = 0;
+ CRC = 0;
+ Crypto = 0;
+ DSP = 0;
+ Unaligned = 1;
+ SoftFloat = SoftFloatABI = false;
+ HWDiv = 0;
+
+ // This does not diagnose illegal cases like having both
+ // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp".
+ uint32_t HW_FP_remove = 0;
+ for (const auto &Feature : Features) {
+ if (Feature == "+soft-float") {
+ SoftFloat = true;
+ } else if (Feature == "+soft-float-abi") {
+ SoftFloatABI = true;
+ } else if (Feature == "+vfp2") {
+ FPU |= VFP2FPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+vfp3") {
+ FPU |= VFP3FPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+vfp4") {
+ FPU |= VFP4FPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
+ } else if (Feature == "+fp-armv8") {
+ FPU |= FPARMV8;
+ HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
+ } else if (Feature == "+neon") {
+ FPU |= NeonFPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+hwdiv") {
+ HWDiv |= HWDivThumb;
+ } else if (Feature == "+hwdiv-arm") {
+ HWDiv |= HWDivARM;
+ } else if (Feature == "+crc") {
+ CRC = 1;
+ } else if (Feature == "+crypto") {
+ Crypto = 1;
+ } else if (Feature == "+dsp") {
+ DSP = 1;
+ } else if (Feature == "+fp-only-sp") {
+ HW_FP_remove |= HW_FP_DP;
+ } else if (Feature == "+strict-align") {
+ Unaligned = 0;
+ } else if (Feature == "+fp16") {
+ HW_FP |= HW_FP_HP;
+ }
+ }
+ HW_FP &= ~HW_FP_remove;
+
+ switch (ArchVersion) {
+ case 6:
+ if (ArchProfile == llvm::ARM::ProfileKind::M)
+ LDREX = 0;
+ else if (ArchKind == llvm::ARM::ArchKind::ARMV6K)
+ LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B;
+ else
+ LDREX = LDREX_W;
+ break;
+ case 7:
+ if (ArchProfile == llvm::ARM::ProfileKind::M)
+ LDREX = LDREX_W | LDREX_H | LDREX_B;
+ else
+ LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B;
+ break;
+ case 8:
+ LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B;
+ }
+
+ if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
+ Diags.Report(diag::err_target_unsupported_fpmath) << "neon";
+ return false;
+ }
+
+ if (FPMath == FP_Neon)
+ Features.push_back("+neonfp");
+ else if (FPMath == FP_VFP)
+ Features.push_back("-neonfp");
+
+ // Remove front-end specific options which the backend handles differently.
+ auto Feature = std::find(Features.begin(), Features.end(), "+soft-float-abi");
+ if (Feature != Features.end())
+ Features.erase(Feature);
+
+ return true;
+}
+
+bool ARMTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("arm", true)
+ .Case("aarch32", true)
+ .Case("softfloat", SoftFloat)
+ .Case("thumb", isThumb())
+ .Case("neon", (FPU & NeonFPU) && !SoftFloat)
+ .Case("vfp", FPU && !SoftFloat)
+ .Case("hwdiv", HWDiv & HWDivThumb)
+ .Case("hwdiv-arm", HWDiv & HWDivARM)
+ .Default(false);
+}
+
+bool ARMTargetInfo::isValidCPUName(StringRef Name) const {
+ return Name == "generic" ||
+ llvm::ARM::parseCPUArch(Name) != llvm::ARM::ArchKind::INVALID;
+}
+
+bool ARMTargetInfo::setCPU(const std::string &Name) {
+ if (Name != "generic")
+ setArchInfo(llvm::ARM::parseCPUArch(Name));
+
+ if (ArchKind == llvm::ARM::ArchKind::INVALID)
+ return false;
+ setAtomic();
+ CPU = Name;
+ return true;
+}
+
+bool ARMTargetInfo::setFPMath(StringRef Name) {
+ if (Name == "neon") {
+ FPMath = FP_Neon;
+ return true;
+ } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" ||
+ Name == "vfp4") {
+ FPMath = FP_VFP;
+ return true;
+ }
+ return false;
+}
+
+void ARMTargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+}
+
+void ARMTargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Also include the ARMv8.1-A defines
+ getTargetDefinesARMV81A(Opts, Builder);
+}
+
+void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Target identification.
+ Builder.defineMacro("__arm");
+ Builder.defineMacro("__arm__");
+ // For bare-metal none-eabi.
+ if (getTriple().getOS() == llvm::Triple::UnknownOS &&
+ (getTriple().getEnvironment() == llvm::Triple::EABI ||
+ getTriple().getEnvironment() == llvm::Triple::EABIHF))
+ Builder.defineMacro("__ELF__");
+
+ // Target properties.
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+
+ // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU
+ // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__.
+ if (getTriple().isWatchABI())
+ Builder.defineMacro("__ARM_ARCH_7K__", "2");
+
+ if (!CPUAttr.empty())
+ Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__");
+
+ // ACLE 6.4.1 ARM/Thumb instruction set architecture
+ // __ARM_ARCH is defined as an integer value indicating the current ARM ISA
+ Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));
+
+ if (ArchVersion >= 8) {
+ // ACLE 6.5.7 Crypto Extension
+ if (Crypto)
+ Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1");
+ // ACLE 6.5.8 CRC32 Extension
+ if (CRC)
+ Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
+ // ACLE 6.5.10 Numeric Maximum and Minimum
+ Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1");
+ // ACLE 6.5.9 Directed Rounding
+ Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1");
+ }
+
+ // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It
+ // is not defined for the M-profile.
+ // NOTE that the default profile is assumed to be 'A'
+ if (CPUProfile.empty() || ArchProfile != llvm::ARM::ProfileKind::M)
+ Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1");
+
+ // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supports the original
+ // Thumb ISA (including v6-M and v8-M Baseline). It is set to 2 if the
+ // core supports the Thumb-2 ISA as found in the v6T2 architecture and all
+ // v7 and v8 architectures excluding v8-M Baseline.
+ if (supportsThumb2())
+ Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2");
+ else if (supportsThumb())
+ Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1");
+
+ // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit
+ // instruction set such as ARM or Thumb.
+ Builder.defineMacro("__ARM_32BIT_STATE", "1");
+
+ // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex)
+
+ // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset.
+ if (!CPUProfile.empty())
+ Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'");
+
+ // ACLE 6.4.3 Unaligned access supported in hardware
+ if (Unaligned)
+ Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
+
+ // ACLE 6.4.4 LDREX/STREX
+ if (LDREX)
+ Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + llvm::utohexstr(LDREX));
+
+ // ACLE 6.4.5 CLZ
+ if (ArchVersion == 5 || (ArchVersion == 6 && CPUProfile != "M") ||
+ ArchVersion > 6)
+ Builder.defineMacro("__ARM_FEATURE_CLZ", "1");
+
+ // ACLE 6.5.1 Hardware Floating Point
+ if (HW_FP)
+ Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP));
+
+ // ACLE predefines.
+ Builder.defineMacro("__ARM_ACLE", "200");
+
+ // FP16 support (we currently only support IEEE format).
+ Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1");
+ Builder.defineMacro("__ARM_FP16_ARGS", "1");
+
+ // ACLE 6.5.3 Fused multiply-accumulate (FMA)
+ if (ArchVersion >= 7 && (FPU & VFP4FPU))
+ Builder.defineMacro("__ARM_FEATURE_FMA", "1");
+
+ // Subtarget options.
+
+ // FIXME: It's more complicated than this and we don't really support
+ // interworking.
+ // Windows on ARM does not "support" interworking
+ if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows())
+ Builder.defineMacro("__THUMB_INTERWORK__");
+
+ if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
+ // Embedded targets on Darwin follow AAPCS, but not EABI.
+ // Windows on ARM follows AAPCS VFP, but does not conform to EABI.
+ if (!getTriple().isOSBinFormatMachO() && !getTriple().isOSWindows())
+ Builder.defineMacro("__ARM_EABI__");
+ Builder.defineMacro("__ARM_PCS", "1");
+ }
+
+ if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" || ABI == "aapcs16")
+ Builder.defineMacro("__ARM_PCS_VFP", "1");
+
+ if (SoftFloat)
+ Builder.defineMacro("__SOFTFP__");
+
+ if (ArchKind == llvm::ARM::ArchKind::XSCALE)
+ Builder.defineMacro("__XSCALE__");
+
+ if (isThumb()) {
+ Builder.defineMacro("__THUMBEL__");
+ Builder.defineMacro("__thumb__");
+ if (supportsThumb2())
+ Builder.defineMacro("__thumb2__");
+ }
+
+ // ACLE 6.4.9 32-bit SIMD instructions
+ if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM"))
+ Builder.defineMacro("__ARM_FEATURE_SIMD32", "1");
+
+ // ACLE 6.4.10 Hardware Integer Divide
+ if (((HWDiv & HWDivThumb) && isThumb()) ||
+ ((HWDiv & HWDivARM) && !isThumb())) {
+ Builder.defineMacro("__ARM_FEATURE_IDIV", "1");
+ Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1");
+ }
+
+ // Note, this is always on in gcc, even though it doesn't make sense.
+ Builder.defineMacro("__APCS_32__");
+
+ if (FPUModeIsVFP((FPUMode)FPU)) {
+ Builder.defineMacro("__VFP_FP__");
+ if (FPU & VFP2FPU)
+ Builder.defineMacro("__ARM_VFPV2__");
+ if (FPU & VFP3FPU)
+ Builder.defineMacro("__ARM_VFPV3__");
+ if (FPU & VFP4FPU)
+ Builder.defineMacro("__ARM_VFPV4__");
+ if (FPU & FPARMV8)
+ Builder.defineMacro("__ARM_FPV5__");
+ }
+
+ // This only gets set when Neon instructions are actually available, unlike
+ // the VFP define, hence the soft float and arch check. This is subtly
+ // different from gcc, we follow the intent which was that it should be set
+ // when Neon instructions are actually available.
+ if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) {
+ Builder.defineMacro("__ARM_NEON", "1");
+ Builder.defineMacro("__ARM_NEON__");
+ // current AArch32 NEON implementations do not support double-precision
+ // floating-point even when it is present in VFP.
+ Builder.defineMacro("__ARM_NEON_FP",
+ "0x" + llvm::utohexstr(HW_FP & ~HW_FP_DP));
+ }
+
+ Builder.defineMacro("__ARM_SIZEOF_WCHAR_T",
+ llvm::utostr(Opts.WCharSize ? Opts.WCharSize : 4));
+
+ Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4");
+
+ if (ArchVersion >= 6 && CPUAttr != "6M" && CPUAttr != "8M_BASE") {
+ 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");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+ }
+
+ // ACLE 6.4.7 DSP instructions
+ if (DSP) {
+ Builder.defineMacro("__ARM_FEATURE_DSP", "1");
+ }
+
+ // ACLE 6.4.8 Saturation instructions
+ bool SAT = false;
+ if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6) {
+ Builder.defineMacro("__ARM_FEATURE_SAT", "1");
+ SAT = true;
+ }
+
+ // ACLE 6.4.6 Q (saturation) flag
+ if (DSP || SAT)
+ Builder.defineMacro("__ARM_FEATURE_QBIT", "1");
+
+ if (Opts.UnsafeFPMath)
+ Builder.defineMacro("__ARM_FP_FAST", "1");
+
+ switch (ArchKind) {
+ default:
+ break;
+ case llvm::ARM::ArchKind::ARMV8_1A:
+ getTargetDefinesARMV81A(Opts, Builder);
+ break;
+ case llvm::ARM::ArchKind::ARMV8_2A:
+ getTargetDefinesARMV82A(Opts, Builder);
+ break;
+ }
+}
+
+const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsNEON.def"
+
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \
+ {#ID, TYPE, ATTRS, nullptr, LANG, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
+ {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE},
+#include "clang/Basic/BuiltinsARM.def"
+};
+
+ArrayRef<Builtin::Info> ARMTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+bool ARMTargetInfo::isCLZForZeroUndef() const { return false; }
+TargetInfo::BuiltinVaListKind ARMTargetInfo::getBuiltinVaListKind() const {
+ return IsAAPCS
+ ? AAPCSABIBuiltinVaList
+ : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList
+ : TargetInfo::VoidPtrBuiltinVaList);
+}
+
+const char *const ARMTargetInfo::GCCRegNames[] = {
+ // Integer registers
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
+ "r12", "sp", "lr", "pc",
+
+ // Float registers
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
+ "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22",
+ "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+
+ // Double registers
+ "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",
+
+ // Quad registers
+ "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11",
+ "q12", "q13", "q14", "q15"};
+
+ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = {
+ {{"a1"}, "r0"}, {{"a2"}, "r1"}, {{"a3"}, "r2"}, {{"a4"}, "r3"},
+ {{"v1"}, "r4"}, {{"v2"}, "r5"}, {{"v3"}, "r6"}, {{"v4"}, "r7"},
+ {{"v5"}, "r8"}, {{"v6", "rfp"}, "r9"}, {{"sl"}, "r10"}, {{"fp"}, "r11"},
+ {{"ip"}, "r12"}, {{"r13"}, "sp"}, {{"r14"}, "lr"}, {{"r15"}, "pc"},
+ // The S, D and Q registers overlap, but aren't really aliases; we
+ // don't want to substitute one of these for a different-sized one.
+};
+
+ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const {
+ return llvm::makeArrayRef(GCCRegAliases);
+}
+
+bool ARMTargetInfo::validateAsmConstraint(
+ const char *&Name, TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ break;
+ case 'l': // r0-r7
+ case 'h': // r8-r15
+ case 't': // VFP Floating point register single precision
+ case 'w': // VFP Floating point register double precision
+ Info.setAllowsRegister();
+ return true;
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ // FIXME
+ return true;
+ case 'Q': // A memory address that is a single base register.
+ Info.setAllowsMemory();
+ return true;
+ case 'U': // a memory reference...
+ switch (Name[1]) {
+ case 'q': // ...ARMV4 ldrsb
+ case 'v': // ...VFP load/store (reg+constant offset)
+ case 'y': // ...iWMMXt load/store
+ case 't': // address valid for load/store opaque types wider
+ // than 128-bits
+ case 'n': // valid address for Neon doubleword vector load/store
+ case 'm': // valid address for Neon element and structure load/store
+ case 's': // valid address for non-offset loads/stores of quad-word
+ // values in four ARM registers
+ Info.setAllowsMemory();
+ Name++;
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string ARMTargetInfo::convertConstraint(const char *&Constraint) const {
+ std::string R;
+ switch (*Constraint) {
+ case 'U': // Two-character constraint; add "^" hint for later parsing.
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
+ break;
+ case 'p': // 'p' should be translated to 'r' by default.
+ R = std::string("r");
+ break;
+ default:
+ return std::string(1, *Constraint);
+ }
+ return R;
+}
+
+bool ARMTargetInfo::validateConstraintModifier(
+ StringRef Constraint, char Modifier, unsigned Size,
+ std::string &SuggestedModifier) const {
+ bool isOutput = (Constraint[0] == '=');
+ bool isInOut = (Constraint[0] == '+');
+
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
+
+ switch (Constraint[0]) {
+ default:
+ break;
+ case 'r': {
+ switch (Modifier) {
+ default:
+ return (isInOut || isOutput || Size <= 64);
+ case 'q':
+ // A register of size 32 cannot fit a vector type.
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+const char *ARMTargetInfo::getClobbers() const {
+ // FIXME: Is this really right?
+ return "";
+}
+
+TargetInfo::CallingConvCheckResult
+ARMTargetInfo::checkCallingConvention(CallingConv CC) const {
+ switch (CC) {
+ case CC_AAPCS:
+ case CC_AAPCS_VFP:
+ case CC_Swift:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+}
+
+int ARMTargetInfo::getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0)
+ return 0;
+ if (RegNo == 1)
+ return 1;
+ return -1;
+}
+
+bool ARMTargetInfo::hasSjLjLowering() const { return true; }
+
+ARMleTargetInfo::ARMleTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : ARMTargetInfo(Triple, Opts) {}
+
+void ARMleTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARMEL__");
+ ARMTargetInfo::getTargetDefines(Opts, Builder);
+}
+
+ARMbeTargetInfo::ARMbeTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : ARMTargetInfo(Triple, Opts) {}
+
+void ARMbeTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARMEB__");
+ Builder.defineMacro("__ARM_BIG_ENDIAN");
+ ARMTargetInfo::getTargetDefines(Opts, Builder);
+}
+
+WindowsARMTargetInfo::WindowsARMTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsTargetInfo<ARMleTargetInfo>(Triple, Opts), Triple(Triple) {
+}
+
+void WindowsARMTargetInfo::getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder);
+
+ // FIXME: this is invalid for WindowsCE
+ Builder.defineMacro("_M_ARM_NT", "1");
+ Builder.defineMacro("_M_ARMT", "_M_ARM");
+ Builder.defineMacro("_M_THUMB", "_M_ARM");
+
+ assert((Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb) &&
+ "invalid architecture for Windows ARM target info");
+ unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
+ Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset));
+
+ // TODO map the complete set of values
+ // 31: VFPv3 40: VFPv4
+ Builder.defineMacro("_M_ARM_FP", "31");
+}
+
+TargetInfo::BuiltinVaListKind
+WindowsARMTargetInfo::getBuiltinVaListKind() const {
+ return TargetInfo::CharPtrBuiltinVaList;
+}
+
+TargetInfo::CallingConvCheckResult
+WindowsARMTargetInfo::checkCallingConvention(CallingConv CC) const {
+ switch (CC) {
+ case CC_X86StdCall:
+ case CC_X86ThisCall:
+ case CC_X86FastCall:
+ case CC_X86VectorCall:
+ return CCCR_Ignore;
+ case CC_C:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+}
+
+// Windows ARM + Itanium C++ ABI Target
+ItaniumWindowsARMleTargetInfo::ItaniumWindowsARMleTargetInfo(
+ const llvm::Triple &Triple, const TargetOptions &Opts)
+ : WindowsARMTargetInfo(Triple, Opts) {
+ TheCXXABI.set(TargetCXXABI::GenericARM);
+}
+
+void ItaniumWindowsARMleTargetInfo::getTargetDefines(
+ const LangOptions &Opts, MacroBuilder &Builder) const {
+ WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
+
+ if (Opts.MSVCCompat)
+ WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
+}
+
+// Windows ARM, MS (C++) ABI
+MicrosoftARMleTargetInfo::MicrosoftARMleTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsARMTargetInfo(Triple, Opts) {
+ TheCXXABI.set(TargetCXXABI::Microsoft);
+}
+
+void MicrosoftARMleTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
+ WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
+}
+
+MinGWARMTargetInfo::MinGWARMTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsARMTargetInfo(Triple, Opts) {
+ TheCXXABI.set(TargetCXXABI::GenericARM);
+}
+
+void MinGWARMTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
+ DefineStd(Builder, "WIN32", Opts);
+ DefineStd(Builder, "WINNT", Opts);
+ Builder.defineMacro("_ARM_");
+ addMinGWDefines(Opts, Builder);
+}
+
+CygwinARMTargetInfo::CygwinARMTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : ARMleTargetInfo(Triple, Opts) {
+ this->WCharType = TargetInfo::UnsignedShort;
+ TLSSupported = false;
+ DoubleAlign = LongLongAlign = 64;
+ resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64");
+}
+
+void CygwinARMTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ ARMleTargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_ARM_");
+ Builder.defineMacro("__CYGWIN__");
+ Builder.defineMacro("__CYGWIN32__");
+ DefineStd(Builder, "unix", Opts);
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+}
+
+DarwinARMTargetInfo::DarwinARMTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : DarwinTargetInfo<ARMleTargetInfo>(Triple, Opts) {
+ HasAlignMac68kSupport = true;
+ // iOS always has 64-bit atomic instructions.
+ // FIXME: This should be based off of the target features in
+ // ARMleTargetInfo.
+ MaxAtomicInlineWidth = 64;
+
+ if (Triple.isWatchABI()) {
+ // Darwin on iOS uses a variant of the ARM C++ ABI.
+ TheCXXABI.set(TargetCXXABI::WatchOS);
+
+ // BOOL should be a real boolean on the new ABI
+ UseSignedCharForObjCBool = false;
+ } else
+ TheCXXABI.set(TargetCXXABI::iOS);
+}
+
+void DarwinARMTargetInfo::getOSDefines(const LangOptions &Opts,
+ const llvm::Triple &Triple,
+ MacroBuilder &Builder) const {
+ getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
+}
+
+RenderScript32TargetInfo::RenderScript32TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(),
+ Triple.getOSName(),
+ Triple.getEnvironmentName()),
+ Opts) {
+ IsRenderScriptTarget = true;
+ LongWidth = LongAlign = 64;
+}
+
+void RenderScript32TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__RENDERSCRIPT__");
+ ARMleTargetInfo::getTargetDefines(Opts, Builder);
+}
diff --git a/lib/Basic/Targets/ARM.h b/lib/Basic/Targets/ARM.h
new file mode 100644
index 0000000000..232b23cd2a
--- /dev/null
+++ b/lib/Basic/Targets/ARM.h
@@ -0,0 +1,252 @@
+//===--- ARM.h - Declare ARM target feature support -------------*- 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 ARM TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H
+
+#include "OSTargets.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/TargetParser.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
+ // Possible FPU choices.
+ enum FPUMode {
+ VFP2FPU = (1 << 0),
+ VFP3FPU = (1 << 1),
+ VFP4FPU = (1 << 2),
+ NeonFPU = (1 << 3),
+ FPARMV8 = (1 << 4)
+ };
+
+ // Possible HWDiv features.
+ enum HWDivMode { HWDivThumb = (1 << 0), HWDivARM = (1 << 1) };
+
+ static bool FPUModeIsVFP(FPUMode Mode) {
+ return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8);
+ }
+
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char *const GCCRegNames[];
+
+ std::string ABI, CPU;
+
+ StringRef CPUProfile;
+ StringRef CPUAttr;
+
+ enum { FP_Default, FP_VFP, FP_Neon } FPMath;
+
+ llvm::ARM::ISAKind ArchISA;
+ llvm::ARM::ArchKind ArchKind = llvm::ARM::ArchKind::ARMV4T;
+ llvm::ARM::ProfileKind ArchProfile;
+ unsigned ArchVersion;
+
+ unsigned FPU : 5;
+
+ unsigned IsAAPCS : 1;
+ unsigned HWDiv : 2;
+
+ // Initialized via features.
+ unsigned SoftFloat : 1;
+ unsigned SoftFloatABI : 1;
+
+ unsigned CRC : 1;
+ unsigned Crypto : 1;
+ unsigned DSP : 1;
+ unsigned Unaligned : 1;
+
+ enum {
+ LDREX_B = (1 << 0), /// byte (8-bit)
+ LDREX_H = (1 << 1), /// half (16-bit)
+ LDREX_W = (1 << 2), /// word (32-bit)
+ LDREX_D = (1 << 3), /// double (64-bit)
+ };
+
+ uint32_t LDREX;
+
+ // ACLE 6.5.1 Hardware floating point
+ enum {
+ HW_FP_HP = (1 << 1), /// half (16-bit)
+ HW_FP_SP = (1 << 2), /// single (32-bit)
+ HW_FP_DP = (1 << 3), /// double (64-bit)
+ };
+ uint32_t HW_FP;
+
+ static const Builtin::Info BuiltinInfo[];
+
+ void setABIAAPCS();
+ void setABIAPCS(bool IsAAPCS16);
+
+ void setArchInfo();
+ void setArchInfo(llvm::ARM::ArchKind Kind);
+
+ void setAtomic();
+
+ bool isThumb() const;
+ bool supportsThumb() const;
+ bool supportsThumb2() const;
+
+ StringRef getCPUAttr() const;
+ StringRef getCPUProfile() const;
+
+public:
+ ARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ StringRef getABI() const override;
+ bool setABI(const std::string &Name) override;
+
+ // FIXME: This should be based on Arch attributes, not CPU names.
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override;
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+
+ bool hasFeature(StringRef Feature) const override;
+
+ bool isValidCPUName(StringRef Name) const override;
+ bool setCPU(const std::string &Name) override;
+
+ bool setFPMath(StringRef Name) override;
+
+ void getTargetDefinesARMV81A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
+
+ void getTargetDefinesARMV82A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ bool isCLZForZeroUndef() const override;
+ BuiltinVaListKind getBuiltinVaListKind() const override;
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override;
+ std::string convertConstraint(const char *&Constraint) const override;
+ bool
+ validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size,
+ std::string &SuggestedModifier) const override;
+ const char *getClobbers() const override;
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override;
+
+ bool hasSjLjLowering() const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo {
+public:
+ ARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY ARMbeTargetInfo : public ARMTargetInfo {
+public:
+ ARMbeTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY WindowsARMTargetInfo
+ : public WindowsTargetInfo<ARMleTargetInfo> {
+ const llvm::Triple Triple;
+
+public:
+ WindowsARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ void getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override;
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;
+};
+
+// Windows ARM + Itanium C++ ABI Target
+class LLVM_LIBRARY_VISIBILITY ItaniumWindowsARMleTargetInfo
+ : public WindowsARMTargetInfo {
+public:
+ ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+// Windows ARM, MS (C++) ABI
+class LLVM_LIBRARY_VISIBILITY MicrosoftARMleTargetInfo
+ : public WindowsARMTargetInfo {
+public:
+ MicrosoftARMleTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+// ARM MinGW target
+class LLVM_LIBRARY_VISIBILITY MinGWARMTargetInfo : public WindowsARMTargetInfo {
+public:
+ MinGWARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+// ARM Cygwin target
+class LLVM_LIBRARY_VISIBILITY CygwinARMTargetInfo : public ARMleTargetInfo {
+public:
+ CygwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY DarwinARMTargetInfo
+ : public DarwinTargetInfo<ARMleTargetInfo> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override;
+
+public:
+ DarwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
+};
+
+// 32-bit RenderScript is armv7 with width and align of 'long' set to 8-bytes
+class LLVM_LIBRARY_VISIBILITY RenderScript32TargetInfo
+ : public ARMleTargetInfo {
+public:
+ RenderScript32TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+} // namespace targets
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H
diff --git a/lib/Basic/Targets/AVR.cpp b/lib/Basic/Targets/AVR.cpp
new file mode 100644
index 0000000000..3022fe33d7
--- /dev/null
+++ b/lib/Basic/Targets/AVR.cpp
@@ -0,0 +1,320 @@
+//===--- AVR.cpp - Implement AVR target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements AVR TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+namespace clang {
+namespace targets {
+
+/// Information about a specific microcontroller.
+struct LLVM_LIBRARY_VISIBILITY 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__"},
+};
+
+} // namespace targets
+} // namespace clang
+
+bool AVRTargetInfo::isValidCPUName(StringRef Name) const {
+ 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);
+
+ bool IsMCU =
+ std::find_if(AVRMcus.begin(), AVRMcus.end(), [&](const MCUInfo &Info) {
+ return Info.Name == Name;
+ }) != AVRMcus.end();
+ return IsFamily || IsMCU;
+}
+
+void AVRTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ 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);
+ }
+}
diff --git a/lib/Basic/Targets/AVR.h b/lib/Basic/Targets/AVR.h
new file mode 100644
index 0000000000..3dfb84f756
--- /dev/null
+++ b/lib/Basic/Targets/AVR.h
@@ -0,0 +1,184 @@
+//===--- AVR.h - Declare AVR target feature support -------------*- 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 AVR TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+// AVR Target
+class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo {
+public:
+ AVRTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ TLSSupported = false;
+ PointerWidth = 16;
+ PointerAlign = 8;
+ IntWidth = 16;
+ IntAlign = 8;
+ LongWidth = 32;
+ LongAlign = 8;
+ LongLongWidth = 64;
+ LongLongAlign = 8;
+ SuitableAlign = 8;
+ DefaultAlignForAttributeAligned = 8;
+ HalfWidth = 16;
+ HalfAlign = 8;
+ FloatWidth = 32;
+ FloatAlign = 8;
+ DoubleWidth = 32;
+ DoubleAlign = 8;
+ DoubleFormat = &llvm::APFloat::IEEEsingle();
+ LongDoubleWidth = 32;
+ LongDoubleAlign = 8;
+ LongDoubleFormat = &llvm::APFloat::IEEEsingle();
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+ Char16Type = UnsignedInt;
+ WIntType = SignedInt;
+ Char32Type = UnsignedLong;
+ SigAtomicType = SignedChar;
+ resetDataLayout("e-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<const char *> getGCCRegNames() const override {
+ static const char *const GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+ "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
+ "r20", "r21", "r22", "r23", "r24", "r25", "X", "Y", "Z", "SP"
+ };
+ return llvm::makeArrayRef(GCCRegNames);
+ }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+
+ ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override {
+ static const TargetInfo::AddlRegName AddlRegNames[] = {
+ {{"r26", "r27"}, 26},
+ {{"r28", "r29"}, 27},
+ {{"r30", "r31"}, 28},
+ {{"SPL", "SPH"}, 29},
+ };
+ return llvm::makeArrayRef(AddlRegNames);
+ }
+
+ 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;
+ }
+
+ IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final {
+ // AVR prefers int for 16-bit integers.
+ return BitWidth == 16 ? (IsSigned ? SignedInt : UnsignedInt)
+ : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned);
+ }
+
+ IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final {
+ // AVR uses int for int_least16_t and int_fast16_t.
+ return BitWidth == 16
+ ? (IsSigned ? SignedInt : UnsignedInt)
+ : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned);
+ }
+
+ bool isValidCPUName(StringRef Name) const override;
+ bool setCPU(const std::string &Name) override {
+ bool isValid = isValidCPUName(Name);
+ if (isValid)
+ CPU = Name;
+ return isValid;
+ }
+
+protected:
+ std::string CPU;
+};
+
+} // namespace targets
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H
diff --git a/lib/Basic/Targets/BPF.cpp b/lib/Basic/Targets/BPF.cpp
new file mode 100644
index 0000000000..54e34f1553
--- /dev/null
+++ b/lib/Basic/Targets/BPF.cpp
@@ -0,0 +1,25 @@
+//===--- BPF.cpp - Implement BPF target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements BPF TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BPF.h"
+#include "Targets.h"
+#include "clang/Basic/MacroBuilder.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "bpf", Opts);
+ Builder.defineMacro("__BPF__");
+}
diff --git a/lib/Basic/Targets/BPF.h b/lib/Basic/Targets/BPF.h
new file mode 100644
index 0000000000..4dd9cbd9d2
--- /dev/null
+++ b/lib/Basic/Targets/BPF.h
@@ -0,0 +1,94 @@
+//===--- BPF.h - Declare BPF target feature support -------------*- 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 BPF TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
+public:
+ BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ IntPtrType = SignedLong;
+ IntMaxType = SignedLong;
+ Int64Type = SignedLong;
+ RegParmMax = 5;
+ if (Triple.getArch() == llvm::Triple::bpfeb) {
+ resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128");
+ } else {
+ resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
+ }
+ MaxAtomicPromoteWidth = 64;
+ MaxAtomicInlineWidth = 64;
+ TLSSupported = false;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool hasFeature(StringRef Feature) const override { return Feature == "bpf"; }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+
+ const char *getClobbers() const override { return ""; }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override { return None; }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
+ return true;
+ }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ default:
+ return CCCR_Warning;
+ case CC_C:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ }
+ }
+
+ bool isValidCPUName(StringRef Name) const override {
+ if (Name == "generic" || Name == "v1" ||
+ Name == "v2" || Name == "probe")
+ return true;
+ return false;
+ }
+
+ bool setCPU(const std::string &Name) override {
+ StringRef CPUName(Name);
+ return isValidCPUName(CPUName);
+ }
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H
diff --git a/lib/Basic/Targets/Hexagon.cpp b/lib/Basic/Targets/Hexagon.cpp
new file mode 100644
index 0000000000..a43f579bc1
--- /dev/null
+++ b/lib/Basic/Targets/Hexagon.cpp
@@ -0,0 +1,154 @@
+//===--- Hexagon.cpp - Implement Hexagon target feature support -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Hexagon TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Hexagon.h"
+#include "Targets.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__qdsp6__", "1");
+ Builder.defineMacro("__hexagon__", "1");
+
+ if (CPU == "hexagonv4") {
+ Builder.defineMacro("__HEXAGON_V4__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "4");
+ if (Opts.HexagonQdsp6Compat) {
+ Builder.defineMacro("__QDSP6_V4__");
+ Builder.defineMacro("__QDSP6_ARCH__", "4");
+ }
+ } else if (CPU == "hexagonv5") {
+ Builder.defineMacro("__HEXAGON_V5__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "5");
+ if (Opts.HexagonQdsp6Compat) {
+ Builder.defineMacro("__QDSP6_V5__");
+ Builder.defineMacro("__QDSP6_ARCH__", "5");
+ }
+ } else if (CPU == "hexagonv55") {
+ Builder.defineMacro("__HEXAGON_V55__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "55");
+ Builder.defineMacro("__QDSP6_V55__");
+ Builder.defineMacro("__QDSP6_ARCH__", "55");
+ } else if (CPU == "hexagonv60") {
+ Builder.defineMacro("__HEXAGON_V60__");
+ 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-length64b")) {
+ Builder.defineMacro("__HVX__");
+ Builder.defineMacro("__HVX_ARCH__", HVXVersion);
+ Builder.defineMacro("__HVX_LENGTH__", "64");
+ }
+
+ if (hasFeature("hvx-length128b")) {
+ Builder.defineMacro("__HVX__");
+ Builder.defineMacro("__HVX_ARCH__", HVXVersion);
+ Builder.defineMacro("__HVX_LENGTH__", "128");
+ // FIXME: This macro is deprecated.
+ Builder.defineMacro("__HVXDBL__");
+ }
+}
+
+bool HexagonTargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+ Features["hvx-double"] = false;
+ Features["long-calls"] = false;
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+}
+
+bool HexagonTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ for (auto &F : Features) {
+ if (F == "+hvx-length64b")
+ HasHVX = HasHVX64B = true;
+ else if (F == "+hvx-length128b")
+ HasHVX = HasHVX128B = true;
+ else if (F.find("+hvxv") != std::string::npos) {
+ HasHVX = true;
+ HVXVersion = F.substr(std::string("+hvxv").length());
+ } else if (F == "-hvx")
+ HasHVX = HasHVX64B = HasHVX128B = false;
+ else if (F == "+long-calls")
+ UseLongCalls = true;
+ else if (F == "-long-calls")
+ UseLongCalls = false;
+ }
+ return true;
+}
+
+const char *const HexagonTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
+ "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17",
+ "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26",
+ "r27", "r28", "r29", "r30", "r31", "p0", "p1", "p2", "p3",
+ "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp"
+};
+
+ArrayRef<const char *> HexagonTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = {
+ {{"sp"}, "r29"},
+ {{"fp"}, "r30"},
+ {{"lr"}, "r31"},
+};
+
+ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const {
+ return llvm::makeArrayRef(GCCRegAliases);
+}
+
+const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsHexagon.def"
+};
+
+bool HexagonTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("hexagon", true)
+ .Case("hvx", HasHVX)
+ .Case("hvx-length64b", HasHVX64B)
+ .Case("hvx-length128b", HasHVX128B)
+ .Case("long-calls", UseLongCalls)
+ .Default(false);
+}
+
+const char *HexagonTargetInfo::getHexagonCPUSuffix(StringRef Name) {
+ return llvm::StringSwitch<const char *>(Name)
+ .Case("hexagonv4", "4")
+ .Case("hexagonv5", "5")
+ .Case("hexagonv55", "55")
+ .Case("hexagonv60", "60")
+ .Case("hexagonv62", "62")
+ .Default(nullptr);
+}
+
+ArrayRef<Builtin::Info> HexagonTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/Hexagon.h b/lib/Basic/Targets/Hexagon.h
new file mode 100644
index 0000000000..7b0966457c
--- /dev/null
+++ b/lib/Basic/Targets/Hexagon.h
@@ -0,0 +1,128 @@
+//===--- Hexagon.h - Declare Hexagon target feature support -----*- 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 Hexagon TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+// Hexagon abstract base class
+class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo {
+
+ static const Builtin::Info BuiltinInfo[];
+ static const char *const GCCRegNames[];
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ std::string CPU;
+ std::string HVXVersion;
+ bool HasHVX = false;
+ bool HasHVX64B = false;
+ bool HasHVX128B = false;
+ bool UseLongCalls = false;
+
+public:
+ HexagonTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ // Specify the vector alignment explicitly. For v512x1, the calculated
+ // alignment would be 512*alignment(i1), which is 512 bytes, instead of
+ // the required minimum of 64 bytes.
+ resetDataLayout(
+ "e-m:e-p:32:32:32-a:0-n16:32-"
+ "i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-"
+ "v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048");
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+
+ // {} in inline assembly are packet specifiers, not assembly variant
+ // specifiers.
+ NoAsmVariants = true;
+
+ LargeArrayMinWidth = 64;
+ LargeArrayAlign = 64;
+ UseBitFieldTypeAlignment = true;
+ ZeroLengthBitfieldBoundary = 32;
+ }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ switch (*Name) {
+ case 'v':
+ case 'q':
+ if (HasHVX) {
+ Info.setAllowsRegister();
+ return true;
+ }
+ break;
+ case 'a': // Modifier register m0-m1.
+ Info.setAllowsRegister();
+ return true;
+ case 's':
+ // Relocatable constant.
+ return true;
+ }
+ return false;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool isCLZForZeroUndef() const override { return false; }
+
+ bool hasFeature(StringRef Feature) const override;
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override;
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+
+ const char *getClobbers() const override { return ""; }
+
+ static const char *getHexagonCPUSuffix(StringRef Name);
+
+ bool isValidCPUName(StringRef Name) const override {
+ return getHexagonCPUSuffix(Name);
+ }
+
+ bool setCPU(const std::string &Name) override {
+ if (!isValidCPUName(Name))
+ return false;
+ CPU = Name;
+ return true;
+ }
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ return RegNo < 2 ? RegNo : -1;
+ }
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H
diff --git a/lib/Basic/Targets/Lanai.cpp b/lib/Basic/Targets/Lanai.cpp
new file mode 100644
index 0000000000..1d8314af99
--- /dev/null
+++ b/lib/Basic/Targets/Lanai.cpp
@@ -0,0 +1,67 @@
+//===--- Lanai.cpp - Implement Lanai target feature support ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Lanai TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lanai.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const char *const LanaiTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
+ "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+ArrayRef<const char *> LanaiTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = {
+ {{"pc"}, "r2"}, {{"sp"}, "r4"}, {{"fp"}, "r5"}, {{"rv"}, "r8"},
+ {{"rr1"}, "r10"}, {{"rr2"}, "r11"}, {{"rca"}, "r15"},
+};
+
+ArrayRef<TargetInfo::GCCRegAlias> LanaiTargetInfo::getGCCRegAliases() const {
+ return llvm::makeArrayRef(GCCRegAliases);
+}
+
+bool LanaiTargetInfo::isValidCPUName(StringRef Name) const {
+ return llvm::StringSwitch<bool>(Name).Case("v11", true).Default(false);
+}
+
+bool LanaiTargetInfo::setCPU(const std::string &Name) {
+ CPU = llvm::StringSwitch<CPUKind>(Name).Case("v11", CK_V11).Default(CK_NONE);
+
+ return CPU != CK_NONE;
+}
+
+bool LanaiTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature).Case("lanai", true).Default(false);
+}
+
+void LanaiTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Define __lanai__ when building for target lanai.
+ Builder.defineMacro("__lanai__");
+
+ // Set define for the CPU specified.
+ switch (CPU) {
+ case CK_V11:
+ Builder.defineMacro("__LANAI_V11__");
+ break;
+ case CK_NONE:
+ llvm_unreachable("Unhandled target CPU");
+ }
+}
diff --git a/lib/Basic/Targets/Lanai.h b/lib/Basic/Targets/Lanai.h
new file mode 100644
index 0000000000..5f99c17a53
--- /dev/null
+++ b/lib/Basic/Targets/Lanai.h
@@ -0,0 +1,92 @@
+//===--- Lanai.h - Declare Lanai target feature support ---------*- 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 Lanai TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY LanaiTargetInfo : public TargetInfo {
+ // Class for Lanai (32-bit).
+ // The CPU profiles supported by the Lanai backend
+ enum CPUKind {
+ CK_NONE,
+ CK_V11,
+ } CPU;
+
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char *const GCCRegNames[];
+
+public:
+ LanaiTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ // Description string has to be kept in sync with backend.
+ resetDataLayout("E" // Big endian
+ "-m:e" // ELF name manging
+ "-p:32:32" // 32 bit pointers, 32 bit aligned
+ "-i64:64" // 64 bit integers, 64 bit aligned
+ "-a:0:32" // 32 bit alignment of objects of aggregate type
+ "-n32" // 32 bit native integer width
+ "-S64" // 64 bit natural stack alignment
+ );
+
+ // Setting RegParmMax equal to what mregparm was set to in the old
+ // toolchain
+ RegParmMax = 4;
+
+ // Set the default CPU to V11
+ CPU = CK_V11;
+
+ // Temporary approach to make everything at least word-aligned and allow for
+ // safely casting between pointers with different alignment requirements.
+ // TODO: Remove this when there are no more cast align warnings on the
+ // firmware.
+ MinGlobalAlign = 32;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool isValidCPUName(StringRef Name) const override;
+
+ bool setCPU(const std::string &Name) override;
+
+ bool hasFeature(StringRef Feature) const override;
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
+ return false;
+ }
+
+ const char *getClobbers() const override { return ""; }
+};
+} // namespace targets
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H
diff --git a/lib/Basic/Targets/Le64.cpp b/lib/Basic/Targets/Le64.cpp
new file mode 100644
index 0000000000..5a1c1c88e7
--- /dev/null
+++ b/lib/Basic/Targets/Le64.cpp
@@ -0,0 +1,39 @@
+//===--- Le64.cpp - Implement Le64 target feature support -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Le64 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Le64.h"
+#include "Targets.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info Le64TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsLe64.def"
+};
+
+ArrayRef<Builtin::Info> Le64TargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::Le64::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+void Le64TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "unix", Opts);
+ defineCPUMacros(Builder, "le64", /*Tuning=*/false);
+ Builder.defineMacro("__ELF__");
+}
diff --git a/lib/Basic/Targets/Le64.h b/lib/Basic/Targets/Le64.h
new file mode 100644
index 0000000000..5e18d04986
--- /dev/null
+++ b/lib/Basic/Targets/Le64.h
@@ -0,0 +1,64 @@
+//===--- Le64.h - Declare Le64 target feature support -----------*- 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 Le64 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY Le64TargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+
+public:
+ Le64TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ NoAsmVariants = true;
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ resetDataLayout("e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::PNaClABIBuiltinVaList;
+ }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<const char *> getGCCRegNames() const override { return None; }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ return false;
+ }
+
+ bool hasProtectedVisibility() const override { return false; }
+};
+
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H
diff --git a/lib/Basic/Targets/MSP430.cpp b/lib/Basic/Targets/MSP430.cpp
new file mode 100644
index 0000000000..86f85a398f
--- /dev/null
+++ b/lib/Basic/Targets/MSP430.cpp
@@ -0,0 +1,34 @@
+//===--- MSP430.cpp - Implement MSP430 target feature support -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements MSP430 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MSP430.h"
+#include "clang/Basic/MacroBuilder.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const char *const MSP430TargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+};
+
+ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+void MSP430TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("MSP430");
+ Builder.defineMacro("__MSP430__");
+ // FIXME: defines for different 'flavours' of MCU
+}
diff --git a/lib/Basic/Targets/MSP430.h b/lib/Basic/Targets/MSP430.h
new file mode 100644
index 0000000000..72aafb9459
--- /dev/null
+++ b/lib/Basic/Targets/MSP430.h
@@ -0,0 +1,92 @@
+//===--- MSP430.h - Declare MSP430 target feature support -------*- 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 MSP430 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo {
+ static const char *const GCCRegNames[];
+
+public:
+ MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ TLSSupported = false;
+ IntWidth = 16;
+ IntAlign = 16;
+ LongWidth = 32;
+ LongLongWidth = 64;
+ LongAlign = LongLongAlign = 16;
+ PointerWidth = 16;
+ PointerAlign = 16;
+ SuitableAlign = 16;
+ SizeType = UnsignedInt;
+ IntMaxType = SignedLongLong;
+ IntPtrType = SignedInt;
+ PtrDiffType = SignedInt;
+ SigAtomicType = SignedLong;
+ resetDataLayout("e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16");
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ // FIXME: Implement.
+ return None;
+ }
+
+ bool hasFeature(StringRef Feature) const override {
+ return Feature == "msp430";
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ // No aliases.
+ return None;
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
+ // FIXME: implement
+ switch (*Name) {
+ case 'K': // the constant 1
+ case 'L': // constant -1^20 .. 1^19
+ case 'M': // constant 1-4:
+ return true;
+ }
+ // No target constraints for now.
+ return false;
+ }
+
+ const char *getClobbers() const override {
+ // FIXME: Is this really right?
+ return "";
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ // FIXME: implement
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+};
+
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H
diff --git a/lib/Basic/Targets/Mips.cpp b/lib/Basic/Targets/Mips.cpp
new file mode 100644
index 0000000000..3eb39b377b
--- /dev/null
+++ b/lib/Basic/Targets/Mips.cpp
@@ -0,0 +1,245 @@
+//===--- Mips.cpp - Implement Mips target feature support -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Mips TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Mips.h"
+#include "Targets.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info MipsTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsMips.def"
+};
+
+bool MipsTargetInfo::processorSupportsGPR64() const {
+ return llvm::StringSwitch<bool>(CPU)
+ .Case("mips3", true)
+ .Case("mips4", true)
+ .Case("mips5", true)
+ .Case("mips64", true)
+ .Case("mips64r2", true)
+ .Case("mips64r3", true)
+ .Case("mips64r5", true)
+ .Case("mips64r6", true)
+ .Case("octeon", true)
+ .Default(false);
+ return false;
+}
+
+bool MipsTargetInfo::isValidCPUName(StringRef Name) const {
+ return llvm::StringSwitch<bool>(Name)
+ .Case("mips1", true)
+ .Case("mips2", true)
+ .Case("mips3", true)
+ .Case("mips4", true)
+ .Case("mips5", true)
+ .Case("mips32", true)
+ .Case("mips32r2", true)
+ .Case("mips32r3", true)
+ .Case("mips32r5", true)
+ .Case("mips32r6", true)
+ .Case("mips64", true)
+ .Case("mips64r2", true)
+ .Case("mips64r3", true)
+ .Case("mips64r5", true)
+ .Case("mips64r6", true)
+ .Case("octeon", true)
+ .Case("p5600", true)
+ .Default(false);
+}
+
+void MipsTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ if (BigEndian) {
+ DefineStd(Builder, "MIPSEB", Opts);
+ Builder.defineMacro("_MIPSEB");
+ } else {
+ DefineStd(Builder, "MIPSEL", Opts);
+ Builder.defineMacro("_MIPSEL");
+ }
+
+ Builder.defineMacro("__mips__");
+ Builder.defineMacro("_mips");
+ if (Opts.GNUMode)
+ Builder.defineMacro("mips");
+
+ if (ABI == "o32") {
+ Builder.defineMacro("__mips", "32");
+ Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32");
+ } else {
+ Builder.defineMacro("__mips", "64");
+ Builder.defineMacro("__mips64");
+ Builder.defineMacro("__mips64__");
+ Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64");
+ }
+
+ const std::string ISARev = llvm::StringSwitch<std::string>(getCPU())
+ .Cases("mips32", "mips64", "1")
+ .Cases("mips32r2", "mips64r2", "2")
+ .Cases("mips32r3", "mips64r3", "3")
+ .Cases("mips32r5", "mips64r5", "5")
+ .Cases("mips32r6", "mips64r6", "6")
+ .Default("");
+ if (!ISARev.empty())
+ Builder.defineMacro("__mips_isa_rev", ISARev);
+
+ if (ABI == "o32") {
+ Builder.defineMacro("__mips_o32");
+ Builder.defineMacro("_ABIO32", "1");
+ Builder.defineMacro("_MIPS_SIM", "_ABIO32");
+ } else if (ABI == "n32") {
+ Builder.defineMacro("__mips_n32");
+ Builder.defineMacro("_ABIN32", "2");
+ Builder.defineMacro("_MIPS_SIM", "_ABIN32");
+ } else if (ABI == "n64") {
+ Builder.defineMacro("__mips_n64");
+ Builder.defineMacro("_ABI64", "3");
+ Builder.defineMacro("_MIPS_SIM", "_ABI64");
+ } else
+ llvm_unreachable("Invalid ABI.");
+
+ if (!IsNoABICalls) {
+ Builder.defineMacro("__mips_abicalls");
+ if (CanUseBSDABICalls)
+ Builder.defineMacro("__ABICALLS__");
+ }
+
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+
+ switch (FloatABI) {
+ case HardFloat:
+ Builder.defineMacro("__mips_hard_float", Twine(1));
+ break;
+ case SoftFloat:
+ Builder.defineMacro("__mips_soft_float", Twine(1));
+ break;
+ }
+
+ if (IsSingleFloat)
+ Builder.defineMacro("__mips_single_float", Twine(1));
+
+ Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32));
+ Builder.defineMacro("_MIPS_FPSET",
+ Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2)));
+
+ if (IsMips16)
+ Builder.defineMacro("__mips16", Twine(1));
+
+ if (IsMicromips)
+ Builder.defineMacro("__mips_micromips", Twine(1));
+
+ if (IsNan2008)
+ Builder.defineMacro("__mips_nan2008", Twine(1));
+
+ if (IsAbs2008)
+ Builder.defineMacro("__mips_abs2008", Twine(1));
+
+ switch (DspRev) {
+ default:
+ break;
+ case DSP1:
+ Builder.defineMacro("__mips_dsp_rev", Twine(1));
+ Builder.defineMacro("__mips_dsp", Twine(1));
+ break;
+ case DSP2:
+ Builder.defineMacro("__mips_dsp_rev", Twine(2));
+ Builder.defineMacro("__mips_dspr2", Twine(1));
+ Builder.defineMacro("__mips_dsp", Twine(1));
+ break;
+ }
+
+ if (HasMSA)
+ Builder.defineMacro("__mips_msa", Twine(1));
+
+ if (DisableMadd4)
+ Builder.defineMacro("__mips_no_madd4", Twine(1));
+
+ Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
+ Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
+ Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
+
+ Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\"");
+ Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
+
+ // These shouldn't be defined for MIPS-I but there's no need to check
+ // for that since MIPS-I isn't supported.
+ 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");
+
+ // 32-bit MIPS processors don't have the necessary lld/scd instructions
+ // found in 64-bit processors. In the case of O32 on a 64-bit processor,
+ // the instructions exist but using them violates the ABI since they
+ // require 64-bit GPRs and O32 only supports 32-bit GPRs.
+ if (ABI == "n32" || ABI == "n64")
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+}
+
+bool MipsTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("mips", true)
+ .Case("fp64", HasFP64)
+ .Default(false);
+}
+
+ArrayRef<Builtin::Info> MipsTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::Mips::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
+ // FIXME: It's valid to use O32 on a 64-bit CPU but the backend can't handle
+ // this yet. It's better to fail here than on the backend assertion.
+ if (processorSupportsGPR64() && ABI == "o32") {
+ Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU;
+ return false;
+ }
+
+ // 64-bit ABI's require 64-bit CPU's.
+ if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) {
+ Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU;
+ return false;
+ }
+
+ // FIXME: It's valid to use O32 on a mips64/mips64el triple but the backend
+ // can't handle this yet. It's better to fail here than on the
+ // backend assertion.
+ if ((getTriple().getArch() == llvm::Triple::mips64 ||
+ getTriple().getArch() == llvm::Triple::mips64el) &&
+ ABI == "o32") {
+ Diags.Report(diag::err_target_unsupported_abi_for_triple)
+ << ABI << getTriple().str();
+ return false;
+ }
+
+ // FIXME: It's valid to use N32/N64 on a mips/mipsel triple but the backend
+ // can't handle this yet. It's better to fail here than on the
+ // backend assertion.
+ if ((getTriple().getArch() == llvm::Triple::mips ||
+ getTriple().getArch() == llvm::Triple::mipsel) &&
+ (ABI == "n32" || ABI == "n64")) {
+ Diags.Report(diag::err_target_unsupported_abi_for_triple)
+ << ABI << getTriple().str();
+ return false;
+ }
+
+ return true;
+}
diff --git a/lib/Basic/Targets/Mips.h b/lib/Basic/Targets/Mips.h
new file mode 100644
index 0000000000..28900f21f8
--- /dev/null
+++ b/lib/Basic/Targets/Mips.h
@@ -0,0 +1,397 @@
+//===--- Mips.h - Declare Mips target feature support -----------*- 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 Mips TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo {
+ void setDataLayout() {
+ StringRef Layout;
+
+ if (ABI == "o32")
+ Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64";
+ else if (ABI == "n32")
+ Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128";
+ else if (ABI == "n64")
+ Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128";
+ else
+ llvm_unreachable("Invalid ABI");
+
+ if (BigEndian)
+ resetDataLayout(("E-" + Layout).str());
+ else
+ resetDataLayout(("e-" + Layout).str());
+ }
+
+ static const Builtin::Info BuiltinInfo[];
+ std::string CPU;
+ bool IsMips16;
+ bool IsMicromips;
+ bool IsNan2008;
+ bool IsAbs2008;
+ bool IsSingleFloat;
+ bool IsNoABICalls;
+ bool CanUseBSDABICalls;
+ enum MipsFloatABI { HardFloat, SoftFloat } FloatABI;
+ enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev;
+ bool HasMSA;
+ bool DisableMadd4;
+
+protected:
+ bool HasFP64;
+ std::string ABI;
+
+public:
+ MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple), IsMips16(false), IsMicromips(false),
+ IsNan2008(false), IsAbs2008(false), IsSingleFloat(false),
+ IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat),
+ DspRev(NoDSP), HasMSA(false), DisableMadd4(false), HasFP64(false) {
+ TheCXXABI.set(TargetCXXABI::GenericMIPS);
+
+ setABI((getTriple().getArch() == llvm::Triple::mips ||
+ getTriple().getArch() == llvm::Triple::mipsel)
+ ? "o32"
+ : "n64");
+
+ CPU = ABI == "o32" ? "mips32r2" : "mips64r2";
+
+ CanUseBSDABICalls = Triple.getOS() == llvm::Triple::FreeBSD ||
+ Triple.getOS() == llvm::Triple::OpenBSD;
+ }
+
+ bool isIEEE754_2008Default() const {
+ return CPU == "mips32r6" || CPU == "mips64r6";
+ }
+
+ bool isFP64Default() const {
+ return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64";
+ }
+
+ bool isNan2008() const override { return IsNan2008; }
+
+ bool processorSupportsGPR64() const;
+
+ StringRef getABI() const override { return ABI; }
+
+ bool setABI(const std::string &Name) override {
+ if (Name == "o32") {
+ setO32ABITypes();
+ ABI = Name;
+ return true;
+ }
+
+ if (Name == "n32") {
+ setN32ABITypes();
+ ABI = Name;
+ return true;
+ }
+ if (Name == "n64") {
+ setN64ABITypes();
+ ABI = Name;
+ return true;
+ }
+ return false;
+ }
+
+ void setO32ABITypes() {
+ Int64Type = SignedLongLong;
+ IntMaxType = Int64Type;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongWidth = LongAlign = 32;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
+ PointerWidth = PointerAlign = 32;
+ PtrDiffType = SignedInt;
+ SizeType = UnsignedInt;
+ SuitableAlign = 64;
+ }
+
+ void setN32N64ABITypes() {
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad();
+ if (getTriple().getOS() == llvm::Triple::FreeBSD) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ }
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ SuitableAlign = 128;
+ }
+
+ void setN64ABITypes() {
+ setN32N64ABITypes();
+ if (getTriple().getOS() == llvm::Triple::OpenBSD) {
+ Int64Type = SignedLongLong;
+ } else {
+ Int64Type = SignedLong;
+ }
+ IntMaxType = Int64Type;
+ LongWidth = LongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ PtrDiffType = SignedLong;
+ SizeType = UnsignedLong;
+ }
+
+ void setN32ABITypes() {
+ setN32N64ABITypes();
+ Int64Type = SignedLongLong;
+ IntMaxType = Int64Type;
+ LongWidth = LongAlign = 32;
+ PointerWidth = PointerAlign = 32;
+ PtrDiffType = SignedInt;
+ SizeType = UnsignedInt;
+ }
+
+ bool isValidCPUName(StringRef Name) const override;
+
+ bool setCPU(const std::string &Name) override {
+ CPU = Name;
+ return isValidCPUName(Name);
+ }
+
+ const std::string &getCPU() const { return CPU; }
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override {
+ if (CPU.empty())
+ CPU = getCPU();
+ if (CPU == "octeon")
+ Features["mips64r2"] = Features["cnmips"] = true;
+ else
+ Features[CPU] = true;
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ bool hasFeature(StringRef Feature) const override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override {
+ static const char *const GCCRegNames[] = {
+ // CPU register names
+ // Must match second column of GCCRegAliases
+ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10",
+ "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20",
+ "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30",
+ "$31",
+ // Floating point register names
+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9",
+ "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18",
+ "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27",
+ "$f28", "$f29", "$f30", "$f31",
+ // Hi/lo and condition register names
+ "hi", "lo", "", "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5",
+ "$fcc6", "$fcc7", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo", "$ac3hi",
+ "$ac3lo",
+ // MSA register names
+ "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7", "$w8", "$w9",
+ "$w10", "$w11", "$w12", "$w13", "$w14", "$w15", "$w16", "$w17", "$w18",
+ "$w19", "$w20", "$w21", "$w22", "$w23", "$w24", "$w25", "$w26", "$w27",
+ "$w28", "$w29", "$w30", "$w31",
+ // MSA control register names
+ "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify",
+ "$msarequest", "$msamap", "$msaunmap"
+ };
+ return llvm::makeArrayRef(GCCRegNames);
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ switch (*Name) {
+ default:
+ return false;
+ case 'r': // CPU registers.
+ case 'd': // Equivalent to "r" unless generating MIPS16 code.
+ case 'y': // Equivalent to "r", backward compatibility only.
+ case 'f': // floating-point registers.
+ case 'c': // $25 for indirect jumps
+ case 'l': // lo register
+ case 'x': // hilo register pair
+ Info.setAllowsRegister();
+ return true;
+ case 'I': // Signed 16-bit constant
+ case 'J': // Integer 0
+ case 'K': // Unsigned 16-bit constant
+ case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui)
+ case 'M': // Constants not loadable via lui, addiu, or ori
+ case 'N': // Constant -1 to -65535
+ case 'O': // A signed 15-bit constant
+ case 'P': // A constant between 1 go 65535
+ return true;
+ case 'R': // An address that can be used in a non-macro load or store
+ Info.setAllowsMemory();
+ return true;
+ case 'Z':
+ if (Name[1] == 'C') { // An address usable by ll, and sc.
+ Info.setAllowsMemory();
+ Name++; // Skip over 'Z'.
+ return true;
+ }
+ return false;
+ }
+ }
+
+ std::string convertConstraint(const char *&Constraint) const override {
+ std::string R;
+ switch (*Constraint) {
+ case 'Z': // Two-character constraint; add "^" hint for later parsing.
+ if (Constraint[1] == 'C') {
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
+ return R;
+ }
+ break;
+ }
+ return TargetInfo::convertConstraint(Constraint);
+ }
+
+ const char *getClobbers() const override {
+ // In GCC, $1 is not widely used in generated code (it's used only in a few
+ // specific situations), so there is no real need for users to add it to
+ // the clobbers list if they want to use it in their inline assembly code.
+ //
+ // In LLVM, $1 is treated as a normal GPR and is always allocatable during
+ // code generation, so using it in inline assembly without adding it to the
+ // clobbers list can cause conflicts between the inline assembly code and
+ // the surrounding generated code.
+ //
+ // Another problem is that LLVM is allowed to choose $1 for inline assembly
+ // operands, which will conflict with the ".set at" assembler option (which
+ // we use only for inline assembly, in order to maintain compatibility with
+ // GCC) and will also conflict with the user's usage of $1.
+ //
+ // The easiest way to avoid these conflicts and keep $1 as an allocatable
+ // register for generated code is to automatically clobber $1 for all inline
+ // assembly code.
+ //
+ // FIXME: We should automatically clobber $1 only for inline assembly code
+ // which actually uses it. This would allow LLVM to use $1 for inline
+ // assembly operands if the user's assembly code doesn't use it.
+ return "~{$1}";
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ IsMips16 = false;
+ IsMicromips = false;
+ IsNan2008 = isIEEE754_2008Default();
+ IsAbs2008 = isIEEE754_2008Default();
+ IsSingleFloat = false;
+ FloatABI = HardFloat;
+ DspRev = NoDSP;
+ HasFP64 = isFP64Default();
+
+ for (const auto &Feature : Features) {
+ if (Feature == "+single-float")
+ IsSingleFloat = true;
+ else if (Feature == "+soft-float")
+ FloatABI = SoftFloat;
+ else if (Feature == "+mips16")
+ IsMips16 = true;
+ else if (Feature == "+micromips")
+ IsMicromips = true;
+ else if (Feature == "+dsp")
+ DspRev = std::max(DspRev, DSP1);
+ else if (Feature == "+dspr2")
+ DspRev = std::max(DspRev, DSP2);
+ else if (Feature == "+msa")
+ HasMSA = true;
+ else if (Feature == "+nomadd4")
+ DisableMadd4 = true;
+ else if (Feature == "+fp64")
+ HasFP64 = true;
+ else if (Feature == "-fp64")
+ HasFP64 = false;
+ else if (Feature == "+nan2008")
+ IsNan2008 = true;
+ else if (Feature == "-nan2008")
+ IsNan2008 = false;
+ else if (Feature == "+abs2008")
+ IsAbs2008 = true;
+ else if (Feature == "-abs2008")
+ IsAbs2008 = false;
+ else if (Feature == "+noabicalls")
+ IsNoABICalls = true;
+ }
+
+ setDataLayout();
+
+ return true;
+ }
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ if (RegNo == 0)
+ return 4;
+ if (RegNo == 1)
+ return 5;
+ return -1;
+ }
+
+ bool isCLZForZeroUndef() const override { return false; }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ static const TargetInfo::GCCRegAlias O32RegAliases[] = {
+ {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"},
+ {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"},
+ {{"a3"}, "$7"}, {{"t0"}, "$8"}, {{"t1"}, "$9"},
+ {{"t2"}, "$10"}, {{"t3"}, "$11"}, {{"t4"}, "$12"},
+ {{"t5"}, "$13"}, {{"t6"}, "$14"}, {{"t7"}, "$15"},
+ {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"},
+ {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"},
+ {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"},
+ {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"},
+ {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"},
+ {{"ra"}, "$31"}
+ };
+ static const TargetInfo::GCCRegAlias NewABIRegAliases[] = {
+ {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"},
+ {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"},
+ {{"a3"}, "$7"}, {{"a4"}, "$8"}, {{"a5"}, "$9"},
+ {{"a6"}, "$10"}, {{"a7"}, "$11"}, {{"t0"}, "$12"},
+ {{"t1"}, "$13"}, {{"t2"}, "$14"}, {{"t3"}, "$15"},
+ {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"},
+ {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"},
+ {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"},
+ {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"},
+ {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"},
+ {{"ra"}, "$31"}
+ };
+ if (ABI == "o32")
+ return llvm::makeArrayRef(O32RegAliases);
+ return llvm::makeArrayRef(NewABIRegAliases);
+ }
+
+ bool hasInt128Type() const override { return ABI == "n32" || ABI == "n64"; }
+
+ bool validateTarget(DiagnosticsEngine &Diags) const override;
+};
+} // namespace targets
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H
diff --git a/lib/Basic/Targets/NVPTX.cpp b/lib/Basic/Targets/NVPTX.cpp
new file mode 100644
index 0000000000..3889f09735
--- /dev/null
+++ b/lib/Basic/Targets/NVPTX.cpp
@@ -0,0 +1,198 @@
+//===--- NVPTX.cpp - Implement NVPTX target feature support ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements NVPTX TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NVPTX.h"
+#include "Targets.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#include "clang/Basic/BuiltinsNVPTX.def"
+};
+
+const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"};
+
+NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts,
+ unsigned TargetPointerWidth)
+ : TargetInfo(Triple) {
+ assert((TargetPointerWidth == 32 || TargetPointerWidth == 64) &&
+ "NVPTX only supports 32- and 64-bit modes.");
+
+ TLSSupported = false;
+ AddrSpaceMap = &NVPTXAddrSpaceMap;
+ UseAddrSpaceMapMangling = true;
+
+ // Define available target features
+ // These must be defined in sorted order!
+ NoAsmVariants = true;
+ GPU = CudaArch::SM_20;
+
+ if (TargetPointerWidth == 32)
+ resetDataLayout("e-p:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64");
+ else
+ resetDataLayout("e-i64:64-i128:128-v16:16-v32:32-n16:32:64");
+
+ // If possible, get a TargetInfo for our host triple, so we can match its
+ // types.
+ llvm::Triple HostTriple(Opts.HostTriple);
+ if (!HostTriple.isNVPTX())
+ HostTarget.reset(AllocateTarget(llvm::Triple(Opts.HostTriple), Opts));
+
+ // If no host target, make some guesses about the data layout and return.
+ if (!HostTarget) {
+ LongWidth = LongAlign = TargetPointerWidth;
+ PointerWidth = PointerAlign = TargetPointerWidth;
+ switch (TargetPointerWidth) {
+ case 32:
+ SizeType = TargetInfo::UnsignedInt;
+ PtrDiffType = TargetInfo::SignedInt;
+ IntPtrType = TargetInfo::SignedInt;
+ break;
+ case 64:
+ SizeType = TargetInfo::UnsignedLong;
+ PtrDiffType = TargetInfo::SignedLong;
+ IntPtrType = TargetInfo::SignedLong;
+ break;
+ default:
+ llvm_unreachable("TargetPointerWidth must be 32 or 64");
+ }
+ return;
+ }
+
+ // Copy properties from host target.
+ PointerWidth = HostTarget->getPointerWidth(/* AddrSpace = */ 0);
+ PointerAlign = HostTarget->getPointerAlign(/* AddrSpace = */ 0);
+ BoolWidth = HostTarget->getBoolWidth();
+ BoolAlign = HostTarget->getBoolAlign();
+ IntWidth = HostTarget->getIntWidth();
+ IntAlign = HostTarget->getIntAlign();
+ HalfWidth = HostTarget->getHalfWidth();
+ HalfAlign = HostTarget->getHalfAlign();
+ FloatWidth = HostTarget->getFloatWidth();
+ FloatAlign = HostTarget->getFloatAlign();
+ DoubleWidth = HostTarget->getDoubleWidth();
+ DoubleAlign = HostTarget->getDoubleAlign();
+ LongWidth = HostTarget->getLongWidth();
+ LongAlign = HostTarget->getLongAlign();
+ LongLongWidth = HostTarget->getLongLongWidth();
+ LongLongAlign = HostTarget->getLongLongAlign();
+ MinGlobalAlign = HostTarget->getMinGlobalAlign();
+ NewAlign = HostTarget->getNewAlign();
+ DefaultAlignForAttributeAligned =
+ HostTarget->getDefaultAlignForAttributeAligned();
+ SizeType = HostTarget->getSizeType();
+ IntMaxType = HostTarget->getIntMaxType();
+ PtrDiffType = HostTarget->getPtrDiffType(/* AddrSpace = */ 0);
+ IntPtrType = HostTarget->getIntPtrType();
+ WCharType = HostTarget->getWCharType();
+ WIntType = HostTarget->getWIntType();
+ Char16Type = HostTarget->getChar16Type();
+ Char32Type = HostTarget->getChar32Type();
+ Int64Type = HostTarget->getInt64Type();
+ SigAtomicType = HostTarget->getSigAtomicType();
+ ProcessIDType = HostTarget->getProcessIDType();
+
+ UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment();
+ UseZeroLengthBitfieldAlignment = HostTarget->useZeroLengthBitfieldAlignment();
+ UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment();
+ ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary();
+
+ // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and
+ // we need those macros to be identical on host and device, because (among
+ // other things) they affect which standard library classes are defined, and
+ // we need all classes to be defined on both the host and device.
+ MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth();
+
+ // Properties intentionally not copied from host:
+ // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the
+ // host/device boundary.
+ // - SuitableAlign: Not visible across the host/device boundary, and may
+ // correctly be different on host/device, e.g. if host has wider vector
+ // types than device.
+ // - LongDoubleWidth, LongDoubleAlign: nvptx's long double type is the same
+ // as its double type, but that's not necessarily true on the host.
+ // TODO: nvcc emits a warning when using long double on device; we should
+ // do the same.
+}
+
+ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+bool NVPTXTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Cases("ptx", "nvptx", true)
+ .Case("satom", GPU >= CudaArch::SM_60) // Atomics w/ scope.
+ .Default(false);
+}
+
+void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__PTX__");
+ Builder.defineMacro("__NVPTX__");
+ if (Opts.CUDAIsDevice) {
+ // Set __CUDA_ARCH__ for the GPU specified.
+ std::string CUDAArchCode = [this] {
+ switch (GPU) {
+ case CudaArch::UNKNOWN:
+ assert(false && "No GPU arch when compiling CUDA device code.");
+ return "";
+ case CudaArch::SM_20:
+ return "200";
+ case CudaArch::SM_21:
+ return "210";
+ case CudaArch::SM_30:
+ return "300";
+ case CudaArch::SM_32:
+ return "320";
+ case CudaArch::SM_35:
+ return "350";
+ case CudaArch::SM_37:
+ return "370";
+ case CudaArch::SM_50:
+ return "500";
+ case CudaArch::SM_52:
+ return "520";
+ case CudaArch::SM_53:
+ return "530";
+ case CudaArch::SM_60:
+ return "600";
+ case CudaArch::SM_61:
+ return "610";
+ case CudaArch::SM_62:
+ return "620";
+ case CudaArch::SM_70:
+ return "700";
+ }
+ llvm_unreachable("unhandled CudaArch");
+ }();
+ Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode);
+ }
+}
+
+ArrayRef<Builtin::Info> NVPTXTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::NVPTX::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/NVPTX.h b/lib/Basic/Targets/NVPTX.h
new file mode 100644
index 0000000000..a84870763f
--- /dev/null
+++ b/lib/Basic/Targets/NVPTX.h
@@ -0,0 +1,132 @@
+//===--- NVPTX.h - Declare NVPTX target feature support ---------*- 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 NVPTX TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
+
+#include "clang/Basic/Cuda.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+static const unsigned NVPTXAddrSpaceMap[] = {
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 4, // opencl_constant
+ 0, // opencl_private
+ // FIXME: generic has to be added to the target
+ 0, // opencl_generic
+ 1, // cuda_device
+ 4, // cuda_constant
+ 3, // cuda_shared
+};
+
+class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
+ static const char *const GCCRegNames[];
+ static const Builtin::Info BuiltinInfo[];
+ CudaArch GPU;
+ std::unique_ptr<TargetInfo> HostTarget;
+
+public:
+ NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts,
+ unsigned TargetPointerWidth);
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override {
+ Features["satom"] = GPU >= CudaArch::SM_60;
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+ }
+
+ bool hasFeature(StringRef Feature) const override;
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ // No aliases.
+ return None;
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ switch (*Name) {
+ default:
+ return false;
+ case 'c':
+ case 'h':
+ case 'r':
+ case 'l':
+ case 'f':
+ case 'd':
+ Info.setAllowsRegister();
+ return true;
+ }
+ }
+
+ const char *getClobbers() const override {
+ // FIXME: Is this really right?
+ return "";
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ // FIXME: implement
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+ bool isValidCPUName(StringRef Name) const override {
+ return StringToCudaArch(Name) != CudaArch::UNKNOWN;
+ }
+
+ bool setCPU(const std::string &Name) override {
+ GPU = StringToCudaArch(Name);
+ return GPU != CudaArch::UNKNOWN;
+ }
+
+ void setSupportedOpenCLOpts() override {
+ auto &Opts = getSupportedOpenCLOpts();
+ Opts.support("cl_clang_storage_class_specifiers");
+ Opts.support("cl_khr_gl_sharing");
+ Opts.support("cl_khr_icd");
+
+ Opts.support("cl_khr_fp64");
+ Opts.support("cl_khr_byte_addressable_store");
+ Opts.support("cl_khr_global_int32_base_atomics");
+ Opts.support("cl_khr_global_int32_extended_atomics");
+ Opts.support("cl_khr_local_int32_base_atomics");
+ Opts.support("cl_khr_local_int32_extended_atomics");
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ // CUDA compilations support all of the host's calling conventions.
+ //
+ // TODO: We should warn if you apply a non-default CC to anything other than
+ // a host function.
+ if (HostTarget)
+ return HostTarget->checkCallingConvention(CC);
+ return CCCR_Warning;
+ }
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H
diff --git a/lib/Basic/Targets/Nios2.cpp b/lib/Basic/Targets/Nios2.cpp
new file mode 100644
index 0000000000..48f662dd98
--- /dev/null
+++ b/lib/Basic/Targets/Nios2.cpp
@@ -0,0 +1,56 @@
+//===--- Nios2.cpp - Implement Nios2 target feature support ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Nios2 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Nios2.h"
+#include "Targets.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info Nios2TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#include "clang/Basic/BuiltinsNios2.def"
+};
+
+bool Nios2TargetInfo::isFeatureSupportedByCPU(StringRef Feature,
+ StringRef CPU) const {
+ const bool isR2 = CPU == "nios2r2";
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("nios2r2mandatory", isR2)
+ .Case("nios2r2bmx", isR2)
+ .Case("nios2r2mpx", isR2)
+ .Case("nios2r2cdx", isR2)
+ .Default(false);
+}
+
+void Nios2TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "nios2", Opts);
+ DefineStd(Builder, "NIOS2", Opts);
+
+ Builder.defineMacro("__nios2");
+ Builder.defineMacro("__NIOS2");
+ Builder.defineMacro("__nios2__");
+ Builder.defineMacro("__NIOS2__");
+}
+
+ArrayRef<Builtin::Info> Nios2TargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::Nios2::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/Nios2.h b/lib/Basic/Targets/Nios2.h
new file mode 100644
index 0000000000..aa02f8f626
--- /dev/null
+++ b/lib/Basic/Targets/Nios2.h
@@ -0,0 +1,147 @@
+//===--- Nios2.h - Declare Nios2 target feature support ---------*- 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 Nios2 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY Nios2TargetInfo : public TargetInfo {
+ void setDataLayout() {
+ if (BigEndian)
+ resetDataLayout("E-p:32:32:32-i8:8:32-i16:16:32-n32");
+ else
+ resetDataLayout("e-p:32:32:32-i8:8:32-i16:16:32-n32");
+ }
+
+ static const Builtin::Info BuiltinInfo[];
+ std::string CPU;
+ std::string ABI;
+
+public:
+ Nios2TargetInfo(const llvm::Triple &triple, const TargetOptions &opts)
+ : TargetInfo(triple), CPU(opts.CPU), ABI(opts.ABI) {
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
+ setDataLayout();
+ }
+
+ StringRef getABI() const override { return ABI; }
+ bool setABI(const std::string &Name) override {
+ if (Name == "o32" || Name == "eabi") {
+ ABI = Name;
+ return true;
+ }
+ return false;
+ }
+
+ bool isValidCPUName(StringRef Name) const override {
+ return Name == "nios2r1" || Name == "nios2r2";
+ }
+
+ bool setCPU(const std::string &Name) override {
+ if (isValidCPUName(Name)) {
+ CPU = Name;
+ return true;
+ }
+ return false;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ bool isFeatureSupportedByCPU(StringRef Feature, StringRef CPU) const;
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeatureVec) const override {
+ static const char *allFeatures[] = {"nios2r2mandatory", "nios2r2bmx",
+ "nios2r2mpx", "nios2r2cdx"
+ };
+ for (const char *feature : allFeatures) {
+ Features[feature] = isFeatureSupportedByCPU(feature, CPU);
+ }
+ return true;
+ }
+
+ bool hasFeature(StringRef Feature) const override {
+ return isFeatureSupportedByCPU(Feature, CPU);
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override {
+ static const char *const GCCRegNames[] = {
+ // CPU register names
+ // Must match second column of GCCRegAliases
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20",
+ "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30",
+ "r31",
+ // Floating point register names
+ "ctl0", "ctl1", "ctl2", "ctl3", "ctl4", "ctl5", "ctl6", "ctl7", "ctl8",
+ "ctl9", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15"
+ };
+ return llvm::makeArrayRef(GCCRegNames);
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ switch (*Name) {
+ default:
+ return false;
+
+ case 'r': // CPU registers.
+ case 'd': // Equivalent to "r" unless generating MIPS16 code.
+ case 'y': // Equivalent to "r", backwards compatibility only.
+ case 'f': // floating-point registers.
+ case 'c': // $25 for indirect jumps
+ case 'l': // lo register
+ case 'x': // hilo register pair
+ Info.setAllowsRegister();
+ return true;
+ }
+ }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ static const TargetInfo::GCCRegAlias aliases[] = {
+ {{"zero"}, "r0"}, {{"at"}, "r1"}, {{"et"}, "r24"},
+ {{"bt"}, "r25"}, {{"gp"}, "r26"}, {{"sp"}, "r27"},
+ {{"fp"}, "r28"}, {{"ea"}, "r29"}, {{"ba"}, "r30"},
+ {{"ra"}, "r31"}, {{"status"}, "ctl0"}, {{"estatus"}, "ctl1"},
+ {{"bstatus"}, "ctl2"}, {{"ienable"}, "ctl3"}, {{"ipending"}, "ctl4"},
+ {{"cpuid"}, "ctl5"}, {{"exception"}, "ctl7"}, {{"pteaddr"}, "ctl8"},
+ {{"tlbacc"}, "ctl9"}, {{"tlbmisc"}, "ctl10"}, {{"badaddr"}, "ctl12"},
+ {{"config"}, "ctl13"}, {{"mpubase"}, "ctl14"}, {{"mpuacc"}, "ctl15"},
+ };
+ return llvm::makeArrayRef(aliases);
+ }
+};
+
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H
diff --git a/lib/Basic/Targets/OSTargets.cpp b/lib/Basic/Targets/OSTargets.cpp
new file mode 100644
index 0000000000..b01e682e64
--- /dev/null
+++ b/lib/Basic/Targets/OSTargets.cpp
@@ -0,0 +1,143 @@
+//===--- OSTargets.cpp - Implement OS target feature support --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements OS specific TargetInfo types.
+//===----------------------------------------------------------------------===//
+
+#include "OSTargets.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+namespace clang {
+namespace targets {
+
+void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
+ const llvm::Triple &Triple, StringRef &PlatformName,
+ VersionTuple &PlatformMinVersion) {
+ Builder.defineMacro("__APPLE_CC__", "6000");
+ Builder.defineMacro("__APPLE__");
+ Builder.defineMacro("__STDC_NO_THREADS__");
+ Builder.defineMacro("OBJC_NEW_PROPERTIES");
+ // AddressSanitizer doesn't play well with source fortification, which is on
+ // by default on Darwin.
+ if (Opts.Sanitize.has(SanitizerKind::Address))
+ Builder.defineMacro("_FORTIFY_SOURCE", "0");
+
+ // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode.
+ if (!Opts.ObjC1) {
+ // __weak is always defined, for use in blocks and with objc pointers.
+ Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
+ Builder.defineMacro("__strong", "");
+ Builder.defineMacro("__unsafe_unretained", "");
+ }
+
+ if (Opts.Static)
+ Builder.defineMacro("__STATIC__");
+ else
+ Builder.defineMacro("__DYNAMIC__");
+
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+
+ // Get the platform type and version number from the triple.
+ unsigned Maj, Min, Rev;
+ if (Triple.isMacOSX()) {
+ Triple.getMacOSXVersion(Maj, Min, Rev);
+ PlatformName = "macos";
+ } else {
+ Triple.getOSVersion(Maj, Min, Rev);
+ PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
+ }
+
+ // If -target arch-pc-win32-macho option specified, we're
+ // generating code for Win32 ABI. No need to emit
+ // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__.
+ if (PlatformName == "win32") {
+ PlatformMinVersion = VersionTuple(Maj, Min, Rev);
+ return;
+ }
+
+ // Set the appropriate OS version define.
+ if (Triple.isiOS()) {
+ assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
+ char Str[7];
+ if (Maj < 10) {
+ Str[0] = '0' + Maj;
+ Str[1] = '0' + (Min / 10);
+ Str[2] = '0' + (Min % 10);
+ Str[3] = '0' + (Rev / 10);
+ Str[4] = '0' + (Rev % 10);
+ Str[5] = '\0';
+ } else {
+ // Handle versions >= 10.
+ Str[0] = '0' + (Maj / 10);
+ Str[1] = '0' + (Maj % 10);
+ Str[2] = '0' + (Min / 10);
+ Str[3] = '0' + (Min % 10);
+ Str[4] = '0' + (Rev / 10);
+ Str[5] = '0' + (Rev % 10);
+ Str[6] = '\0';
+ }
+ if (Triple.isTvOS())
+ Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str);
+ else
+ Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
+ Str);
+
+ } else if (Triple.isWatchOS()) {
+ assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
+ char Str[6];
+ Str[0] = '0' + Maj;
+ Str[1] = '0' + (Min / 10);
+ Str[2] = '0' + (Min % 10);
+ Str[3] = '0' + (Rev / 10);
+ Str[4] = '0' + (Rev % 10);
+ Str[5] = '\0';
+ Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str);
+ } else if (Triple.isMacOSX()) {
+ // Note that the Driver allows versions which aren't representable in the
+ // define (because we only get a single digit for the minor and micro
+ // revision numbers). So, we limit them to the maximum representable
+ // version.
+ assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
+ char Str[7];
+ if (Maj < 10 || (Maj == 10 && Min < 10)) {
+ Str[0] = '0' + (Maj / 10);
+ Str[1] = '0' + (Maj % 10);
+ Str[2] = '0' + std::min(Min, 9U);
+ Str[3] = '0' + std::min(Rev, 9U);
+ Str[4] = '\0';
+ } else {
+ // Handle versions > 10.9.
+ Str[0] = '0' + (Maj / 10);
+ Str[1] = '0' + (Maj % 10);
+ Str[2] = '0' + (Min / 10);
+ Str[3] = '0' + (Min % 10);
+ Str[4] = '0' + (Rev / 10);
+ Str[5] = '0' + (Rev % 10);
+ Str[6] = '\0';
+ }
+ Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
+ }
+
+ // Tell users about the kernel if there is one.
+ if (Triple.isOSDarwin())
+ Builder.defineMacro("__MACH__");
+
+ // The Watch ABI uses Dwarf EH.
+ if (Triple.isWatchABI())
+ Builder.defineMacro("__ARM_DWARF_EH__");
+
+ PlatformMinVersion = VersionTuple(Maj, Min, Rev);
+}
+} // namespace targets
+} // namespace clang
diff --git a/lib/Basic/Targets/OSTargets.h b/lib/Basic/Targets/OSTargets.h
new file mode 100644
index 0000000000..c775fe32ee
--- /dev/null
+++ b/lib/Basic/Targets/OSTargets.h
@@ -0,0 +1,736 @@
+//===--- OSTargets.h - Declare OS target feature support --------*- 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 OS specific TargetInfo types.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H
+
+#include "Targets.h"
+#include "llvm/MC/MCSectionMachO.h"
+
+namespace clang {
+namespace targets {
+
+template <typename TgtInfo>
+class LLVM_LIBRARY_VISIBILITY OSTargetInfo : public TgtInfo {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const = 0;
+
+public:
+ OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : TgtInfo(Triple, Opts) {}
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ TgtInfo::getTargetDefines(Opts, Builder);
+ getOSDefines(Opts, TgtInfo::getTriple(), Builder);
+ }
+};
+
+// CloudABI Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY CloudABITargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__CloudABI__");
+ Builder.defineMacro("__ELF__");
+
+ // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t.
+ Builder.defineMacro("__STDC_ISO_10646__", "201206L");
+ Builder.defineMacro("__STDC_UTF_16__");
+ Builder.defineMacro("__STDC_UTF_32__");
+ }
+
+public:
+ CloudABITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {}
+};
+
+// Ananas target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY AnanasTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // Ananas defines
+ Builder.defineMacro("__Ananas__");
+ Builder.defineMacro("__ELF__");
+ }
+
+public:
+ AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {}
+};
+
+void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
+ const llvm::Triple &Triple, StringRef &PlatformName,
+ VersionTuple &PlatformMinVersion);
+
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY DarwinTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ getDarwinDefines(Builder, Opts, Triple, this->PlatformName,
+ this->PlatformMinVersion);
+ }
+
+public:
+ DarwinTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ // By default, no TLS, and we whitelist permitted architecture/OS
+ // combinations.
+ this->TLSSupported = false;
+
+ if (Triple.isMacOSX())
+ this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7);
+ else if (Triple.isiOS()) {
+ // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards.
+ if (Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::aarch64)
+ this->TLSSupported = !Triple.isOSVersionLT(8);
+ else if (Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb)
+ this->TLSSupported = !Triple.isOSVersionLT(9);
+ } else if (Triple.isWatchOS())
+ this->TLSSupported = !Triple.isOSVersionLT(2);
+
+ this->MCountName = "\01mcount";
+ }
+
+ std::string isValidSectionSpecifier(StringRef SR) const override {
+ // Let MCSectionMachO validate this.
+ StringRef Segment, Section;
+ unsigned TAA, StubSize;
+ bool HasTAA;
+ return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section,
+ TAA, HasTAA, StubSize);
+ }
+
+ const char *getStaticInitSectionSpecifier() const override {
+ // FIXME: We should return 0 when building kexts.
+ return "__TEXT,__StaticInit,regular,pure_instructions";
+ }
+
+ /// Darwin does not support protected visibility. Darwin's "default"
+ /// is very similar to ELF's "protected"; Darwin requires a "weak"
+ /// attribute on declarations that can be dynamically replaced.
+ bool hasProtectedVisibility() const override { return false; }
+};
+
+// DragonFlyBSD Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY DragonFlyBSDTargetInfo
+ : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // DragonFly defines; list based off of gcc output
+ Builder.defineMacro("__DragonFly__");
+ Builder.defineMacro("__DragonFly_cc_version", "100001");
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
+ Builder.defineMacro("__tune_i386__");
+ DefineStd(Builder, "unix", Opts);
+ }
+
+public:
+ DragonFlyBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ this->MCountName = ".mcount";
+ break;
+ }
+ }
+};
+
+#ifndef FREEBSD_CC_VERSION
+#define FREEBSD_CC_VERSION 0U
+#endif
+
+// FreeBSD Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY FreeBSDTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // FreeBSD defines; list based off of gcc output
+
+ unsigned Release = Triple.getOSMajorVersion();
+ if (Release == 0U)
+ Release = 8U;
+ unsigned CCVersion = FREEBSD_CC_VERSION;
+ if (CCVersion == 0U)
+ CCVersion = Release * 100000U + 1U;
+
+ Builder.defineMacro("__FreeBSD__", Twine(Release));
+ Builder.defineMacro("__FreeBSD_cc_version", Twine(CCVersion));
+ Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+
+ // On FreeBSD, wchar_t contains the number of the code point as
+ // used by the character set of the locale. These character sets are
+ // not necessarily a superset of ASCII.
+ //
+ // FIXME: This is wrong; the macro refers to the numerical values
+ // of wchar_t *literals*, which are not locale-dependent. However,
+ // FreeBSD systems apparently depend on us getting this wrong, and
+ // setting this to 1 is conforming even if all the basic source
+ // character literals have the same encoding as char and wchar_t.
+ Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1");
+ }
+
+public:
+ FreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ this->MCountName = ".mcount";
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ this->MCountName = "_mcount";
+ break;
+ case llvm::Triple::arm:
+ this->MCountName = "__mcount";
+ break;
+ }
+ }
+};
+
+// GNU/kFreeBSD Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY KFreeBSDTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // GNU/kFreeBSD defines; list based off of gcc output
+
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__FreeBSD_kernel__");
+ Builder.defineMacro("__GLIBC__");
+ Builder.defineMacro("__ELF__");
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
+
+public:
+ KFreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {}
+};
+
+// Haiku Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY HaikuTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // Haiku defines; list based off of gcc output
+ Builder.defineMacro("__HAIKU__");
+ Builder.defineMacro("__ELF__");
+ DefineStd(Builder, "unix", Opts);
+ }
+
+public:
+ HaikuTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->SizeType = TargetInfo::UnsignedLong;
+ this->IntPtrType = TargetInfo::SignedLong;
+ this->PtrDiffType = TargetInfo::SignedLong;
+ this->ProcessIDType = TargetInfo::SignedLong;
+ this->TLSSupported = false;
+ }
+};
+
+// Minix Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY MinixTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // Minix defines
+
+ Builder.defineMacro("__minix", "3");
+ Builder.defineMacro("_EM_WSIZE", "4");
+ Builder.defineMacro("_EM_PSIZE", "4");
+ Builder.defineMacro("_EM_SSIZE", "2");
+ Builder.defineMacro("_EM_LSIZE", "4");
+ Builder.defineMacro("_EM_FSIZE", "4");
+ Builder.defineMacro("_EM_DSIZE", "8");
+ Builder.defineMacro("__ELF__");
+ DefineStd(Builder, "unix", Opts);
+ }
+
+public:
+ MinixTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {}
+};
+
+// Linux target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY LinuxTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // Linux defines; list based off of gcc output
+ DefineStd(Builder, "unix", Opts);
+ DefineStd(Builder, "linux", Opts);
+ Builder.defineMacro("__gnu_linux__");
+ Builder.defineMacro("__ELF__");
+ if (Triple.isAndroid()) {
+ Builder.defineMacro("__ANDROID__", "1");
+ unsigned Maj, Min, Rev;
+ Triple.getEnvironmentVersion(Maj, Min, Rev);
+ this->PlatformName = "android";
+ this->PlatformMinVersion = VersionTuple(Maj, Min, Rev);
+ if (Maj)
+ Builder.defineMacro("__ANDROID_API__", Twine(Maj));
+ }
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ if (this->HasFloat128)
+ Builder.defineMacro("__FLOAT128__");
+ }
+
+public:
+ LinuxTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->WIntType = TargetInfo::UnsignedInt;
+
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ this->MCountName = "_mcount";
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ case llvm::Triple::systemz:
+ this->HasFloat128 = true;
+ break;
+ }
+ }
+
+ const char *getStaticInitSectionSpecifier() const override {
+ return ".text.startup";
+ }
+};
+
+// NetBSD Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY NetBSDTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // NetBSD defines; list based off of gcc output
+ Builder.defineMacro("__NetBSD__");
+ Builder.defineMacro("__unix__");
+ Builder.defineMacro("__ELF__");
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ Builder.defineMacro("__ARM_DWARF_EH__");
+ break;
+ }
+ }
+
+public:
+ NetBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->MCountName = "_mcount";
+ }
+};
+
+// OpenBSD Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY OpenBSDTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // OpenBSD defines; list based off of gcc output
+
+ Builder.defineMacro("__OpenBSD__");
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ if (this->HasFloat128)
+ Builder.defineMacro("__FLOAT128__");
+ }
+
+public:
+ OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ this->HasFloat128 = true;
+ // FALLTHROUGH
+ default:
+ this->MCountName = "__mcount";
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::ppc:
+ case llvm::Triple::sparcv9:
+ this->MCountName = "_mcount";
+ break;
+ }
+ }
+};
+
+// PSP Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY PSPTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // PSP defines; list based on the output of the pspdev gcc toolchain.
+ Builder.defineMacro("PSP");
+ Builder.defineMacro("_PSP");
+ Builder.defineMacro("__psp__");
+ Builder.defineMacro("__ELF__");
+ }
+
+public:
+ PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {}
+};
+
+// PS3 PPU Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY PS3PPUTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // PS3 PPU defines.
+ Builder.defineMacro("__PPC__");
+ Builder.defineMacro("__PPU__");
+ Builder.defineMacro("__CELLOS_LV2__");
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__LP32__");
+ Builder.defineMacro("_ARCH_PPC64");
+ Builder.defineMacro("__powerpc64__");
+ }
+
+public:
+ PS3PPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->LongWidth = this->LongAlign = 32;
+ this->PointerWidth = this->PointerAlign = 32;
+ this->IntMaxType = TargetInfo::SignedLongLong;
+ this->Int64Type = TargetInfo::SignedLongLong;
+ this->SizeType = TargetInfo::UnsignedInt;
+ this->resetDataLayout("E-m:e-p:32:32-i64:64-n32:64");
+ }
+};
+
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY PS4OSTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__FreeBSD__", "9");
+ Builder.defineMacro("__FreeBSD_cc_version", "900001");
+ Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__ORBIS__");
+ }
+
+public:
+ PS4OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->WCharType = TargetInfo::UnsignedShort;
+
+ // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits).
+ this->MaxTLSAlign = 256;
+
+ // On PS4, do not honor explicit bit field alignment,
+ // as in "__attribute__((aligned(2))) int b : 1;".
+ this->UseExplicitBitFieldAlignment = false;
+
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86_64:
+ this->MCountName = ".mcount";
+ break;
+ }
+ }
+};
+
+// RTEMS Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY RTEMSTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // RTEMS defines; list based off of gcc output
+
+ Builder.defineMacro("__rtems__");
+ Builder.defineMacro("__ELF__");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
+
+public:
+ RTEMSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ switch (Triple.getArch()) {
+ default:
+ case llvm::Triple::x86:
+ // this->MCountName = ".mcount";
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ // this->MCountName = "_mcount";
+ break;
+ case llvm::Triple::arm:
+ // this->MCountName = "__mcount";
+ break;
+ }
+ }
+};
+
+// Solaris target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY SolarisTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ DefineStd(Builder, "sun", Opts);
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__svr4__");
+ Builder.defineMacro("__SVR4");
+ // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and
+ // newer, but to 500 for everything else. feature_test.h has a check to
+ // ensure that you are not using C99 with an old version of X/Open or C89
+ // with a new version.
+ if (Opts.C99)
+ Builder.defineMacro("_XOPEN_SOURCE", "600");
+ else
+ Builder.defineMacro("_XOPEN_SOURCE", "500");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("__C99FEATURES__");
+ Builder.defineMacro("_LARGEFILE_SOURCE");
+ Builder.defineMacro("_LARGEFILE64_SOURCE");
+ Builder.defineMacro("__EXTENSIONS__");
+ Builder.defineMacro("_REENTRANT");
+ }
+
+public:
+ SolarisTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ // FIXME: WIntType should be SignedLong
+ }
+};
+
+// Windows target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY WindowsTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("_WIN32");
+ }
+ void getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ if (Opts.CPlusPlus) {
+ if (Opts.RTTIData)
+ Builder.defineMacro("_CPPRTTI");
+
+ if (Opts.CXXExceptions)
+ Builder.defineMacro("_CPPUNWIND");
+ }
+
+ if (Opts.Bool)
+ Builder.defineMacro("__BOOL_DEFINED");
+
+ if (!Opts.CharIsSigned)
+ Builder.defineMacro("_CHAR_UNSIGNED");
+
+ // FIXME: POSIXThreads isn't exactly the option this should be defined for,
+ // but it works for now.
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_MT");
+
+ if (Opts.MSCompatibilityVersion) {
+ Builder.defineMacro("_MSC_VER",
+ Twine(Opts.MSCompatibilityVersion / 100000));
+ Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion));
+ // FIXME We cannot encode the revision information into 32-bits
+ Builder.defineMacro("_MSC_BUILD", Twine(1));
+
+ if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015))
+ Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1));
+
+ if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) {
+ if (Opts.CPlusPlus1z)
+ Builder.defineMacro("_MSVC_LANG", "201403L");
+ else if (Opts.CPlusPlus14)
+ Builder.defineMacro("_MSVC_LANG", "201402L");
+ }
+ }
+
+ if (Opts.MicrosoftExt) {
+ Builder.defineMacro("_MSC_EXTENSIONS");
+
+ if (Opts.CPlusPlus11) {
+ Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED");
+ Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED");
+ Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED");
+ }
+ }
+
+ Builder.defineMacro("_INTEGRAL_MAX_BITS", "64");
+ }
+
+public:
+ WindowsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->WCharType = TargetInfo::UnsignedShort;
+ }
+};
+
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY NaClTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__native_client__");
+ }
+
+public:
+ NaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->LongAlign = 32;
+ this->LongWidth = 32;
+ this->PointerAlign = 32;
+ this->PointerWidth = 32;
+ this->IntMaxType = TargetInfo::SignedLongLong;
+ this->Int64Type = TargetInfo::SignedLongLong;
+ this->DoubleAlign = 64;
+ this->LongDoubleWidth = 64;
+ this->LongDoubleAlign = 64;
+ this->LongLongWidth = 64;
+ this->LongLongAlign = 64;
+ this->SizeType = TargetInfo::UnsignedInt;
+ this->PtrDiffType = TargetInfo::SignedInt;
+ this->IntPtrType = TargetInfo::SignedInt;
+ // RegParmMax is inherited from the underlying architecture.
+ this->LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ if (Triple.getArch() == llvm::Triple::arm) {
+ // Handled in ARM's setABI().
+ } else if (Triple.getArch() == llvm::Triple::x86) {
+ this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32-S128");
+ } else if (Triple.getArch() == llvm::Triple::x86_64) {
+ this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32:64-S128");
+ } else if (Triple.getArch() == llvm::Triple::mipsel) {
+ // Handled on mips' setDataLayout.
+ } else {
+ assert(Triple.getArch() == llvm::Triple::le32);
+ this->resetDataLayout("e-p:32:32-i64:64");
+ }
+ }
+};
+
+// Fuchsia Target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY FuchsiaTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__Fuchsia__");
+ Builder.defineMacro("__ELF__");
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ // Required by the libc++ locale support.
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
+
+public:
+ FuchsiaTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->MCountName = "__mcount";
+ }
+};
+
+// WebAssembly target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo
+ : public OSTargetInfo<Target> {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const final {
+ // A common platform macro.
+ if (Opts.POSIXThreads)
+ Builder.defineMacro("_REENTRANT");
+ // Follow g++ convention and predefine _GNU_SOURCE for C++.
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
+
+ // As an optimization, group static init code together in a section.
+ const char *getStaticInitSectionSpecifier() const final {
+ return ".text.__startup";
+ }
+
+public:
+ explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {
+ this->MCountName = "__mcount";
+ this->TheCXXABI.set(TargetCXXABI::WebAssembly);
+ }
+};
+
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H
diff --git a/lib/Basic/Targets/PNaCl.cpp b/lib/Basic/Targets/PNaCl.cpp
new file mode 100644
index 0000000000..b9128c2716
--- /dev/null
+++ b/lib/Basic/Targets/PNaCl.cpp
@@ -0,0 +1,30 @@
+//===--- PNaCl.cpp - Implement PNaCl target feature support ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements PNaCl TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PNaCl.h"
+#include "clang/Basic/MacroBuilder.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const { return None; }
+
+ArrayRef<TargetInfo::GCCRegAlias> PNaClTargetInfo::getGCCRegAliases() const {
+ return None;
+}
+
+void PNaClTargetInfo::getArchDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__le32__");
+ Builder.defineMacro("__pnacl__");
+}
diff --git a/lib/Basic/Targets/PNaCl.h b/lib/Basic/Targets/PNaCl.h
new file mode 100644
index 0000000000..922944e85c
--- /dev/null
+++ b/lib/Basic/Targets/PNaCl.h
@@ -0,0 +1,87 @@
+//===--- PNaCl.h - Declare PNaCl target feature support ---------*- 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 PNaCl TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H
+
+#include "Mips.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY PNaClTargetInfo : public TargetInfo {
+public:
+ PNaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : TargetInfo(Triple) {
+ this->LongAlign = 32;
+ this->LongWidth = 32;
+ this->PointerAlign = 32;
+ this->PointerWidth = 32;
+ this->IntMaxType = TargetInfo::SignedLongLong;
+ this->Int64Type = TargetInfo::SignedLongLong;
+ this->DoubleAlign = 64;
+ this->LongDoubleWidth = 64;
+ this->LongDoubleAlign = 64;
+ this->SizeType = TargetInfo::UnsignedInt;
+ this->PtrDiffType = TargetInfo::SignedInt;
+ this->IntPtrType = TargetInfo::SignedInt;
+ this->RegParmMax = 0; // Disallow regparm
+ }
+
+ void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const;
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ getArchDefines(Opts, Builder);
+ }
+
+ bool hasFeature(StringRef Feature) const override {
+ return Feature == "pnacl";
+ }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::PNaClABIBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ return false;
+ }
+
+ const char *getClobbers() const override { return ""; }
+};
+
+// We attempt to use PNaCl (le32) frontend and Mips32EL backend.
+class LLVM_LIBRARY_VISIBILITY NaClMips32TargetInfo : public MipsTargetInfo {
+public:
+ NaClMips32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : MipsTargetInfo(Triple, Opts) {}
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::PNaClABIBuiltinVaList;
+ }
+};
+} // namespace targets
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H
diff --git a/lib/Basic/Targets/PPC.cpp b/lib/Basic/Targets/PPC.cpp
new file mode 100644
index 0000000000..a44aa0cd96
--- /dev/null
+++ b/lib/Basic/Targets/PPC.cpp
@@ -0,0 +1,544 @@
+//===--- PPC.cpp - Implement PPC target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements PPC TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PPC.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsPPC.def"
+};
+
+/// handleTargetFeatures - Perform initialization based on the user
+/// configured set of features.
+bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ for (const auto &Feature : Features) {
+ if (Feature == "+altivec") {
+ HasAltivec = true;
+ } else if (Feature == "+vsx") {
+ HasVSX = true;
+ } else if (Feature == "+bpermd") {
+ HasBPERMD = true;
+ } else if (Feature == "+extdiv") {
+ HasExtDiv = true;
+ } else if (Feature == "+power8-vector") {
+ HasP8Vector = true;
+ } else if (Feature == "+crypto") {
+ HasP8Crypto = true;
+ } else if (Feature == "+direct-move") {
+ HasDirectMove = true;
+ } else if (Feature == "+qpx") {
+ HasQPX = true;
+ } else if (Feature == "+htm") {
+ HasHTM = true;
+ } else if (Feature == "+float128") {
+ HasFloat128 = true;
+ } else if (Feature == "+power9-vector") {
+ HasP9Vector = true;
+ }
+ // TODO: Finish this list and add an assert that we've handled them
+ // all.
+ }
+
+ return true;
+}
+
+/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
+/// #defines that are not tied to a specific subtarget.
+void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Target identification.
+ Builder.defineMacro("__ppc__");
+ Builder.defineMacro("__PPC__");
+ Builder.defineMacro("_ARCH_PPC");
+ Builder.defineMacro("__powerpc__");
+ Builder.defineMacro("__POWERPC__");
+ if (PointerWidth == 64) {
+ Builder.defineMacro("_ARCH_PPC64");
+ Builder.defineMacro("__powerpc64__");
+ Builder.defineMacro("__ppc64__");
+ Builder.defineMacro("__PPC64__");
+ }
+
+ // Target properties.
+ if (getTriple().getArch() == llvm::Triple::ppc64le) {
+ Builder.defineMacro("_LITTLE_ENDIAN");
+ } else {
+ if (getTriple().getOS() != llvm::Triple::NetBSD &&
+ getTriple().getOS() != llvm::Triple::OpenBSD)
+ Builder.defineMacro("_BIG_ENDIAN");
+ }
+
+ // ABI options.
+ if (ABI == "elfv1" || ABI == "elfv1-qpx")
+ Builder.defineMacro("_CALL_ELF", "1");
+ 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) {
+ Builder.defineMacro("__LONG_DOUBLE_128__");
+ 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)
+ // 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()));
+ if (defs & ArchDefinePpcgr)
+ Builder.defineMacro("_ARCH_PPCGR");
+ if (defs & ArchDefinePpcsq)
+ Builder.defineMacro("_ARCH_PPCSQ");
+ if (defs & ArchDefine440)
+ Builder.defineMacro("_ARCH_440");
+ if (defs & ArchDefine603)
+ Builder.defineMacro("_ARCH_603");
+ if (defs & ArchDefine604)
+ Builder.defineMacro("_ARCH_604");
+ if (defs & ArchDefinePwr4)
+ Builder.defineMacro("_ARCH_PWR4");
+ if (defs & ArchDefinePwr5)
+ Builder.defineMacro("_ARCH_PWR5");
+ if (defs & ArchDefinePwr5x)
+ Builder.defineMacro("_ARCH_PWR5X");
+ if (defs & ArchDefinePwr6)
+ Builder.defineMacro("_ARCH_PWR6");
+ if (defs & ArchDefinePwr6x)
+ Builder.defineMacro("_ARCH_PWR6X");
+ if (defs & ArchDefinePwr7)
+ Builder.defineMacro("_ARCH_PWR7");
+ if (defs & ArchDefinePwr8)
+ Builder.defineMacro("_ARCH_PWR8");
+ if (defs & ArchDefinePwr9)
+ Builder.defineMacro("_ARCH_PWR9");
+ if (defs & ArchDefineA2)
+ Builder.defineMacro("_ARCH_A2");
+ if (defs & ArchDefineA2q) {
+ Builder.defineMacro("_ARCH_A2Q");
+ Builder.defineMacro("_ARCH_QP");
+ }
+
+ if (getTriple().getVendor() == llvm::Triple::BGQ) {
+ Builder.defineMacro("__bg__");
+ Builder.defineMacro("__THW_BLUEGENE__");
+ Builder.defineMacro("__bgq__");
+ Builder.defineMacro("__TOS_BGQ__");
+ }
+
+ if (HasAltivec) {
+ Builder.defineMacro("__VEC__", "10206");
+ Builder.defineMacro("__ALTIVEC__");
+ }
+ if (HasVSX)
+ Builder.defineMacro("__VSX__");
+ if (HasP8Vector)
+ Builder.defineMacro("__POWER8_VECTOR__");
+ if (HasP8Crypto)
+ Builder.defineMacro("__CRYPTO__");
+ if (HasHTM)
+ Builder.defineMacro("__HTM__");
+ if (HasFloat128)
+ Builder.defineMacro("__FLOAT128__");
+ if (HasP9Vector)
+ Builder.defineMacro("__POWER9_VECTOR__");
+
+ 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");
+ 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:
+ //
+ // _SOFT_FLOAT_
+ // __RECIP_PRECISION__
+ // __APPLE_ALTIVEC__
+ // __RECIP__
+ // __RECIPF__
+ // __RSQRTE__
+ // __RSQRTEF__
+ // _SOFT_DOUBLE_
+ // __NO_LWSYNC__
+ // __CMODEL_MEDIUM__
+ // __CMODEL_LARGE__
+ // _CALL_SYSV
+ // _CALL_DARWIN
+ // __NO_FPRS__
+}
+
+// Handle explicit options being passed to the compiler here: if we've
+// explicitly turned off vsx and turned on any of:
+// - power8-vector
+// - direct-move
+// - float128
+// - power9-vector
+// then go ahead and error since the customer has expressed an incompatible
+// set of options.
+static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags,
+ const std::vector<std::string> &FeaturesVec) {
+
+ if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") !=
+ FeaturesVec.end()) {
+ if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") !=
+ FeaturesVec.end()) {
+ Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector"
+ << "-mno-vsx";
+ return false;
+ }
+
+ if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") !=
+ FeaturesVec.end()) {
+ Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move"
+ << "-mno-vsx";
+ return false;
+ }
+
+ if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") !=
+ FeaturesVec.end()) {
+ Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128"
+ << "-mno-vsx";
+ return false;
+ }
+
+ if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power9-vector") !=
+ FeaturesVec.end()) {
+ Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower9-vector"
+ << "-mno-vsx";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PPCTargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+ Features["altivec"] = llvm::StringSwitch<bool>(CPU)
+ .Case("7400", true)
+ .Case("g4", true)
+ .Case("7450", true)
+ .Case("g4+", true)
+ .Case("970", true)
+ .Case("g5", true)
+ .Case("pwr6", true)
+ .Case("pwr7", true)
+ .Case("pwr8", true)
+ .Case("pwr9", true)
+ .Case("ppc64", true)
+ .Case("ppc64le", true)
+ .Default(false);
+
+ Features["qpx"] = (CPU == "a2q");
+ Features["power9-vector"] = (CPU == "pwr9");
+ Features["crypto"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr9", true)
+ .Case("pwr8", true)
+ .Default(false);
+ Features["power8-vector"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr9", true)
+ .Case("pwr8", true)
+ .Default(false);
+ Features["bpermd"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr9", true)
+ .Case("pwr8", true)
+ .Case("pwr7", true)
+ .Default(false);
+ Features["extdiv"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr9", true)
+ .Case("pwr8", true)
+ .Case("pwr7", true)
+ .Default(false);
+ Features["direct-move"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr9", true)
+ .Case("pwr8", true)
+ .Default(false);
+ Features["vsx"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr9", true)
+ .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;
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+}
+
+bool PPCTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .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 (Enabled) {
+ // 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 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;
+ if (Name == "power8-vector")
+ Features["power9-vector"] = false;
+ Features[Name] = false;
+ }
+}
+
+const char *const PPCTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
+ "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17",
+ "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26",
+ "r27", "r28", "r29", "r30", "r31", "f0", "f1", "f2", "f3",
+ "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12",
+ "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21",
+ "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30",
+ "f31", "mq", "lr", "ctr", "ap", "cr0", "cr1", "cr2", "cr3",
+ "cr4", "cr5", "cr6", "cr7", "xer", "v0", "v1", "v2", "v3",
+ "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12",
+ "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21",
+ "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30",
+ "v31", "vrsave", "vscr", "spe_acc", "spefscr", "sfp"
+};
+
+ArrayRef<const char *> PPCTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = {
+ // While some of these aliases do map to different registers
+ // they still share the same register name.
+ {{"0"}, "r0"}, {{"1"}, "r1"}, {{"2"}, "r2"}, {{"3"}, "r3"},
+ {{"4"}, "r4"}, {{"5"}, "r5"}, {{"6"}, "r6"}, {{"7"}, "r7"},
+ {{"8"}, "r8"}, {{"9"}, "r9"}, {{"10"}, "r10"}, {{"11"}, "r11"},
+ {{"12"}, "r12"}, {{"13"}, "r13"}, {{"14"}, "r14"}, {{"15"}, "r15"},
+ {{"16"}, "r16"}, {{"17"}, "r17"}, {{"18"}, "r18"}, {{"19"}, "r19"},
+ {{"20"}, "r20"}, {{"21"}, "r21"}, {{"22"}, "r22"}, {{"23"}, "r23"},
+ {{"24"}, "r24"}, {{"25"}, "r25"}, {{"26"}, "r26"}, {{"27"}, "r27"},
+ {{"28"}, "r28"}, {{"29"}, "r29"}, {{"30"}, "r30"}, {{"31"}, "r31"},
+ {{"fr0"}, "f0"}, {{"fr1"}, "f1"}, {{"fr2"}, "f2"}, {{"fr3"}, "f3"},
+ {{"fr4"}, "f4"}, {{"fr5"}, "f5"}, {{"fr6"}, "f6"}, {{"fr7"}, "f7"},
+ {{"fr8"}, "f8"}, {{"fr9"}, "f9"}, {{"fr10"}, "f10"}, {{"fr11"}, "f11"},
+ {{"fr12"}, "f12"}, {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"},
+ {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"}, {{"fr19"}, "f19"},
+ {{"fr20"}, "f20"}, {{"fr21"}, "f21"}, {{"fr22"}, "f22"}, {{"fr23"}, "f23"},
+ {{"fr24"}, "f24"}, {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"},
+ {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"}, {{"fr31"}, "f31"},
+ {{"cc"}, "cr0"},
+};
+
+ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const {
+ return llvm::makeArrayRef(GCCRegAliases);
+}
+
+bool PPCTargetInfo::isValidCPUName(StringRef Name) const {
+ return llvm::StringSwitch<bool>(Name)
+ .Case("generic", true)
+ .Case("440", true)
+ .Case("450", true)
+ .Case("601", true)
+ .Case("602", true)
+ .Case("603", true)
+ .Case("603e", true)
+ .Case("603ev", true)
+ .Case("604", true)
+ .Case("604e", true)
+ .Case("620", true)
+ .Case("630", true)
+ .Case("g3", true)
+ .Case("7400", true)
+ .Case("g4", true)
+ .Case("7450", true)
+ .Case("g4+", true)
+ .Case("750", true)
+ .Case("970", true)
+ .Case("g5", true)
+ .Case("a2", true)
+ .Case("a2q", true)
+ .Case("e500mc", true)
+ .Case("e5500", true)
+ .Case("power3", true)
+ .Case("pwr3", true)
+ .Case("power4", true)
+ .Case("pwr4", true)
+ .Case("power5", true)
+ .Case("pwr5", true)
+ .Case("power5x", true)
+ .Case("pwr5x", true)
+ .Case("power6", true)
+ .Case("pwr6", true)
+ .Case("power6x", true)
+ .Case("pwr6x", true)
+ .Case("power7", true)
+ .Case("pwr7", true)
+ .Case("power8", true)
+ .Case("pwr8", true)
+ .Case("power9", true)
+ .Case("pwr9", true)
+ .Case("powerpc", true)
+ .Case("ppc", true)
+ .Case("powerpc64", true)
+ .Case("ppc64", true)
+ .Case("powerpc64le", true)
+ .Case("ppc64le", true)
+ .Default(false);
+}
+
+void PPCTargetInfo::adjust(LangOptions &Opts) {
+ if (HasAltivec)
+ Opts.AltiVec = 1;
+ TargetInfo::adjust(Opts);
+}
+
+ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::PPC::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/PPC.h b/lib/Basic/Targets/PPC.h
new file mode 100644
index 0000000000..04bef258e3
--- /dev/null
+++ b/lib/Basic/Targets/PPC.h
@@ -0,0 +1,368 @@
+//===--- PPC.h - Declare PPC target feature support -------------*- 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 PPC TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H
+
+#include "OSTargets.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+// PPC abstract base class
+class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+ static const char *const GCCRegNames[];
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ std::string CPU;
+
+ // Target cpu features.
+ bool HasAltivec;
+ bool HasVSX;
+ bool HasP8Vector;
+ bool HasP8Crypto;
+ bool HasDirectMove;
+ bool HasQPX;
+ bool HasHTM;
+ bool HasBPERMD;
+ bool HasExtDiv;
+ bool HasP9Vector;
+
+protected:
+ std::string ABI;
+
+public:
+ PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : 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();
+ }
+
+ /// \brief Flags for architecture specific defines.
+ typedef enum {
+ ArchDefineNone = 0,
+ ArchDefineName = 1 << 0, // <name> is substituted for arch name.
+ ArchDefinePpcgr = 1 << 1,
+ ArchDefinePpcsq = 1 << 2,
+ ArchDefine440 = 1 << 3,
+ ArchDefine603 = 1 << 4,
+ ArchDefine604 = 1 << 5,
+ ArchDefinePwr4 = 1 << 6,
+ ArchDefinePwr5 = 1 << 7,
+ ArchDefinePwr5x = 1 << 8,
+ ArchDefinePwr6 = 1 << 9,
+ ArchDefinePwr6x = 1 << 10,
+ ArchDefinePwr7 = 1 << 11,
+ ArchDefinePwr8 = 1 << 12,
+ ArchDefinePwr9 = 1 << 13,
+ ArchDefineA2 = 1 << 14,
+ ArchDefineA2q = 1 << 15
+ } ArchDefineTypes;
+
+ // Set the language option for altivec based on our value.
+ void adjust(LangOptions &Opts) override;
+
+ // 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,
+ // titan, rs64.
+ bool isValidCPUName(StringRef Name) const override;
+
+ bool setCPU(const std::string &Name) override {
+ bool CPUKnown = isValidCPUName(Name);
+ if (CPUKnown)
+ CPU = Name;
+ return CPUKnown;
+ }
+
+ StringRef getABI() const override { return ABI; }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ bool isCLZForZeroUndef() const override { return false; }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override;
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+
+ bool hasFeature(StringRef Feature) const override;
+
+ void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name,
+ bool Enabled) const override;
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ switch (*Name) {
+ default:
+ return false;
+ case 'O': // Zero
+ break;
+ case 'b': // Base register
+ case 'f': // Floating point register
+ Info.setAllowsRegister();
+ break;
+ // FIXME: The following are added to allow parsing.
+ // I just took a guess at what the actions should be.
+ // Also, is more specific checking needed? I.e. specific registers?
+ case 'd': // Floating point register (containing 64-bit value)
+ case 'v': // Altivec vector register
+ Info.setAllowsRegister();
+ break;
+ case 'w':
+ switch (Name[1]) {
+ case 'd': // VSX vector register to hold vector double data
+ case 'f': // VSX vector register to hold vector float data
+ case 's': // VSX vector register to hold scalar float data
+ case 'a': // Any VSX register
+ case 'c': // An individual CR bit
+ break;
+ default:
+ return false;
+ }
+ Info.setAllowsRegister();
+ Name++; // Skip over 'w'.
+ break;
+ case 'h': // `MQ', `CTR', or `LINK' register
+ case 'q': // `MQ' register
+ case 'c': // `CTR' register
+ case 'l': // `LINK' register
+ case 'x': // `CR' register (condition register) number 0
+ case 'y': // `CR' register (condition register)
+ case 'z': // `XER[CA]' carry bit (part of the XER register)
+ Info.setAllowsRegister();
+ break;
+ case 'I': // Signed 16-bit constant
+ case 'J': // Unsigned 16-bit constant shifted left 16 bits
+ // (use `L' instead for SImode constants)
+ case 'K': // Unsigned 16-bit constant
+ case 'L': // Signed 16-bit constant shifted left 16 bits
+ case 'M': // Constant larger than 31
+ case 'N': // Exact power of 2
+ case 'P': // Constant whose negation is a signed 16-bit constant
+ case 'G': // Floating point constant that can be loaded into a
+ // register with one instruction per word
+ case 'H': // Integer/Floating point constant that can be loaded
+ // into a register using three instructions
+ break;
+ case 'm': // Memory operand. Note that on PowerPC targets, m can
+ // include addresses that update the base register. It
+ // is therefore only safe to use `m' in an asm statement
+ // if that asm statement accesses the operand exactly once.
+ // The asm statement must also use `%U<opno>' as a
+ // placeholder for the "update" flag in the corresponding
+ // load or store instruction. For example:
+ // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val));
+ // is correct but:
+ // asm ("st %1,%0" : "=m" (mem) : "r" (val));
+ // is not. Use es rather than m if you don't want the base
+ // register to be updated.
+ case 'e':
+ if (Name[1] != 's')
+ return false;
+ // es: A "stable" memory operand; that is, one which does not
+ // include any automodification of the base register. Unlike
+ // `m', this constraint can be used in asm statements that
+ // might access the operand several times, or that might not
+ // access it at all.
+ Info.setAllowsMemory();
+ Name++; // Skip over 'e'.
+ break;
+ case 'Q': // Memory operand that is an offset from a register (it is
+ // usually better to use `m' or `es' in asm statements)
+ case 'Z': // Memory operand that is an indexed or indirect from a
+ // register (it is usually better to use `m' or `es' in
+ // asm statements)
+ Info.setAllowsMemory();
+ Info.setAllowsRegister();
+ break;
+ case 'R': // AIX TOC entry
+ case 'a': // Address operand that is an indexed or indirect from a
+ // register (`p' is preferable for asm statements)
+ case 'S': // Constant suitable as a 64-bit mask operand
+ case 'T': // Constant suitable as a 32-bit mask operand
+ case 'U': // System V Release 4 small data area reference
+ case 't': // AND masks that can be performed by two rldic{l, r}
+ // instructions
+ case 'W': // Vector constant that does not require memory
+ case 'j': // Vector constant that is all zeros.
+ break;
+ // End FIXME.
+ }
+ return true;
+ }
+
+ std::string convertConstraint(const char *&Constraint) const override {
+ std::string R;
+ switch (*Constraint) {
+ case 'e':
+ case 'w':
+ // Two-character constraint; add "^" hint for later parsing.
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
+ break;
+ default:
+ return TargetInfo::convertConstraint(Constraint);
+ }
+ return R;
+ }
+
+ const char *getClobbers() const override { return ""; }
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ if (RegNo == 0)
+ return 3;
+ if (RegNo == 1)
+ return 4;
+ return -1;
+ }
+
+ bool hasSjLjLowering() const override { return true; }
+
+ bool useFloat128ManglingForLongDouble() const override {
+ return LongDoubleWidth == 128 &&
+ LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble() &&
+ getTriple().isOSBinFormatELF();
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo {
+public:
+ PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : PPCTargetInfo(Triple, Opts) {
+ resetDataLayout("E-m:e-p:32:32-i64:64-n32");
+
+ switch (getTriple().getOS()) {
+ case llvm::Triple::Linux:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+ break;
+ default:
+ break;
+ }
+
+ if (getTriple().getOS() == llvm::Triple::FreeBSD) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ }
+
+ // PPC32 supports atomics up to 4 bytes.
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ // This is the ELF definition, and is overridden by the Darwin sub-target
+ return TargetInfo::PowerABIBuiltinVaList;
+ }
+};
+
+// Note: ABI differences may eventually require us to have a separate
+// TargetInfo for little endian.
+class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
+public:
+ PPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : PPCTargetInfo(Triple, Opts) {
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ IntMaxType = SignedLong;
+ Int64Type = SignedLong;
+
+ if ((Triple.getArch() == llvm::Triple::ppc64le)) {
+ resetDataLayout("e-m:e-i64:64-n32:64");
+ ABI = "elfv2";
+ } else {
+ resetDataLayout("E-m:e-i64:64-n32:64");
+ ABI = "elfv1";
+ }
+
+ switch (getTriple().getOS()) {
+ case llvm::Triple::FreeBSD:
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ break;
+ case llvm::Triple::NetBSD:
+ IntMaxType = SignedLongLong;
+ Int64Type = SignedLongLong;
+ break;
+ default:
+ break;
+ }
+
+ // PPC64 supports atomics up to 8 bytes.
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+ // PPC64 Linux-specific ABI options.
+ bool setABI(const std::string &Name) override {
+ if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") {
+ ABI = Name;
+ return true;
+ }
+ return false;
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY DarwinPPC32TargetInfo
+ : public DarwinTargetInfo<PPC32TargetInfo> {
+public:
+ DarwinPPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : DarwinTargetInfo<PPC32TargetInfo>(Triple, Opts) {
+ HasAlignMac68kSupport = true;
+ BoolWidth = BoolAlign = 32; // XXX support -mone-byte-bool?
+ PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726
+ LongLongAlign = 32;
+ resetDataLayout("E-m:o-p:32:32-f64:32:64-n32");
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY DarwinPPC64TargetInfo
+ : public DarwinTargetInfo<PPC64TargetInfo> {
+public:
+ DarwinPPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : DarwinTargetInfo<PPC64TargetInfo>(Triple, Opts) {
+ HasAlignMac68kSupport = true;
+ resetDataLayout("E-m:o-i64:64-n32:64");
+ }
+};
+
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H
diff --git a/lib/Basic/Targets/SPIR.cpp b/lib/Basic/Targets/SPIR.cpp
new file mode 100644
index 0000000000..304d904368
--- /dev/null
+++ b/lib/Basic/Targets/SPIR.cpp
@@ -0,0 +1,33 @@
+//===--- SPIR.cpp - Implement SPIR target feature support -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements SPIR TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SPIR.h"
+#include "Targets.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR", Opts);
+}
+
+void SPIR32TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR32", Opts);
+}
+
+void SPIR64TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR64", Opts);
+}
diff --git a/lib/Basic/Targets/SPIR.h b/lib/Basic/Targets/SPIR.h
new file mode 100644
index 0000000000..e64ad54829
--- /dev/null
+++ b/lib/Basic/Targets/SPIR.h
@@ -0,0 +1,126 @@
+//===--- SPIR.h - Declare SPIR target feature support -----------*- 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 SPIR TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+static const unsigned SPIRAddrSpaceMap[] = {
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_private
+ 4, // opencl_generic
+ 0, // cuda_device
+ 0, // cuda_constant
+ 0 // cuda_shared
+};
+
+class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo {
+public:
+ SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
+ "SPIR target must use unknown OS");
+ assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
+ "SPIR target must use unknown environment type");
+ TLSSupported = false;
+ LongWidth = LongAlign = 64;
+ AddrSpaceMap = &SPIRAddrSpaceMap;
+ UseAddrSpaceMapMangling = true;
+ // Define available target features
+ // These must be defined in sorted order!
+ NoAsmVariants = true;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool hasFeature(StringRef Feature) const override {
+ return Feature == "spir";
+ }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<const char *> getGCCRegNames() const override { return None; }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
+ return true;
+ }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK
+ : CCCR_Warning;
+ }
+
+ CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
+ return CC_SpirFunction;
+ }
+
+ void setSupportedOpenCLOpts() override {
+ // Assume all OpenCL extensions and optional core features are supported
+ // for SPIR since it is a generic target.
+ getSupportedOpenCLOpts().supportAll();
+ }
+};
+class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
+public:
+ SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : SPIRTargetInfo(Triple, Opts) {
+ PointerWidth = PointerAlign = 32;
+ SizeType = TargetInfo::UnsignedInt;
+ PtrDiffType = IntPtrType = TargetInfo::SignedInt;
+ resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
+ "v96:128-v192:256-v256:256-v512:512-v1024:1024");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
+public:
+ SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : SPIRTargetInfo(Triple, Opts) {
+ PointerWidth = PointerAlign = 64;
+ SizeType = TargetInfo::UnsignedLong;
+ PtrDiffType = IntPtrType = TargetInfo::SignedLong;
+ resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
+ "v96:128-v192:256-v256:256-v512:512-v1024:1024");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H
diff --git a/lib/Basic/Targets/Sparc.cpp b/lib/Basic/Targets/Sparc.cpp
new file mode 100644
index 0000000000..429c1ee3a2
--- /dev/null
+++ b/lib/Basic/Targets/Sparc.cpp
@@ -0,0 +1,197 @@
+//===--- Sparc.cpp - Implement Sparc target feature support ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Sparc TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sparc.h"
+#include "Targets.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const char *const SparcTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
+ "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+ArrayRef<const char *> SparcTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = {
+ {{"g0"}, "r0"}, {{"g1"}, "r1"}, {{"g2"}, "r2"}, {{"g3"}, "r3"},
+ {{"g4"}, "r4"}, {{"g5"}, "r5"}, {{"g6"}, "r6"}, {{"g7"}, "r7"},
+ {{"o0"}, "r8"}, {{"o1"}, "r9"}, {{"o2"}, "r10"}, {{"o3"}, "r11"},
+ {{"o4"}, "r12"}, {{"o5"}, "r13"}, {{"o6", "sp"}, "r14"}, {{"o7"}, "r15"},
+ {{"l0"}, "r16"}, {{"l1"}, "r17"}, {{"l2"}, "r18"}, {{"l3"}, "r19"},
+ {{"l4"}, "r20"}, {{"l5"}, "r21"}, {{"l6"}, "r22"}, {{"l7"}, "r23"},
+ {{"i0"}, "r24"}, {{"i1"}, "r25"}, {{"i2"}, "r26"}, {{"i3"}, "r27"},
+ {{"i4"}, "r28"}, {{"i5"}, "r29"}, {{"i6", "fp"}, "r30"}, {{"i7"}, "r31"},
+};
+
+ArrayRef<TargetInfo::GCCRegAlias> SparcTargetInfo::getGCCRegAliases() const {
+ return llvm::makeArrayRef(GCCRegAliases);
+}
+
+bool SparcTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("softfloat", SoftFloat)
+ .Case("sparc", true)
+ .Default(false);
+}
+
+SparcTargetInfo::CPUKind SparcTargetInfo::getCPUKind(StringRef Name) const {
+ return llvm::StringSwitch<CPUKind>(Name)
+ .Case("v8", CK_V8)
+ .Case("supersparc", CK_SUPERSPARC)
+ .Case("sparclite", CK_SPARCLITE)
+ .Case("f934", CK_F934)
+ .Case("hypersparc", CK_HYPERSPARC)
+ .Case("sparclite86x", CK_SPARCLITE86X)
+ .Case("sparclet", CK_SPARCLET)
+ .Case("tsc701", CK_TSC701)
+ .Case("v9", CK_V9)
+ .Case("ultrasparc", CK_ULTRASPARC)
+ .Case("ultrasparc3", CK_ULTRASPARC3)
+ .Case("niagara", CK_NIAGARA)
+ .Case("niagara2", CK_NIAGARA2)
+ .Case("niagara3", CK_NIAGARA3)
+ .Case("niagara4", CK_NIAGARA4)
+ .Case("ma2100", CK_MYRIAD2100)
+ .Case("ma2150", CK_MYRIAD2150)
+ .Case("ma2155", CK_MYRIAD2155)
+ .Case("ma2450", CK_MYRIAD2450)
+ .Case("ma2455", CK_MYRIAD2455)
+ .Case("ma2x5x", CK_MYRIAD2x5x)
+ .Case("ma2080", CK_MYRIAD2080)
+ .Case("ma2085", CK_MYRIAD2085)
+ .Case("ma2480", CK_MYRIAD2480)
+ .Case("ma2485", CK_MYRIAD2485)
+ .Case("ma2x8x", CK_MYRIAD2x8x)
+ // FIXME: the myriad2[.n] spellings are obsolete,
+ // but a grace period is needed to allow updating dependent builds.
+ .Case("myriad2", CK_MYRIAD2x5x)
+ .Case("myriad2.1", CK_MYRIAD2100)
+ .Case("myriad2.2", CK_MYRIAD2x5x)
+ .Case("myriad2.3", CK_MYRIAD2x8x)
+ .Case("leon2", CK_LEON2)
+ .Case("at697e", CK_LEON2_AT697E)
+ .Case("at697f", CK_LEON2_AT697F)
+ .Case("leon3", CK_LEON3)
+ .Case("ut699", CK_LEON3_UT699)
+ .Case("gr712rc", CK_LEON3_GR712RC)
+ .Case("leon4", CK_LEON4)
+ .Case("gr740", CK_LEON4_GR740)
+ .Default(CK_GENERIC);
+}
+
+void SparcTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "sparc", Opts);
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+
+ if (SoftFloat)
+ Builder.defineMacro("SOFT_FLOAT", "1");
+}
+
+void SparcV8TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ SparcTargetInfo::getTargetDefines(Opts, Builder);
+ switch (getCPUGeneration(CPU)) {
+ case CG_V8:
+ Builder.defineMacro("__sparcv8");
+ if (getTriple().getOS() != llvm::Triple::Solaris)
+ Builder.defineMacro("__sparcv8__");
+ break;
+ case CG_V9:
+ Builder.defineMacro("__sparcv9");
+ if (getTriple().getOS() != llvm::Triple::Solaris) {
+ Builder.defineMacro("__sparcv9__");
+ Builder.defineMacro("__sparc_v9__");
+ }
+ break;
+ }
+ if (getTriple().getVendor() == llvm::Triple::Myriad) {
+ std::string MyriadArchValue, Myriad2Value;
+ Builder.defineMacro("__sparc_v8__");
+ Builder.defineMacro("__leon__");
+ switch (CPU) {
+ case CK_MYRIAD2100:
+ MyriadArchValue = "__ma2100";
+ Myriad2Value = "1";
+ break;
+ case CK_MYRIAD2150:
+ MyriadArchValue = "__ma2150";
+ Myriad2Value = "2";
+ break;
+ case CK_MYRIAD2155:
+ MyriadArchValue = "__ma2155";
+ Myriad2Value = "2";
+ break;
+ case CK_MYRIAD2450:
+ MyriadArchValue = "__ma2450";
+ Myriad2Value = "2";
+ break;
+ case CK_MYRIAD2455:
+ MyriadArchValue = "__ma2455";
+ Myriad2Value = "2";
+ break;
+ case CK_MYRIAD2x5x:
+ Myriad2Value = "2";
+ break;
+ case CK_MYRIAD2080:
+ MyriadArchValue = "__ma2080";
+ Myriad2Value = "3";
+ break;
+ case CK_MYRIAD2085:
+ MyriadArchValue = "__ma2085";
+ Myriad2Value = "3";
+ break;
+ case CK_MYRIAD2480:
+ MyriadArchValue = "__ma2480";
+ Myriad2Value = "3";
+ break;
+ case CK_MYRIAD2485:
+ MyriadArchValue = "__ma2485";
+ Myriad2Value = "3";
+ break;
+ case CK_MYRIAD2x8x:
+ Myriad2Value = "3";
+ break;
+ default:
+ MyriadArchValue = "__ma2100";
+ Myriad2Value = "1";
+ break;
+ }
+ if (!MyriadArchValue.empty()) {
+ Builder.defineMacro(MyriadArchValue, "1");
+ Builder.defineMacro(MyriadArchValue + "__", "1");
+ }
+ Builder.defineMacro("__myriad2__", Myriad2Value);
+ Builder.defineMacro("__myriad2", Myriad2Value);
+ }
+}
+
+void SparcV9TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ SparcTargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__sparcv9");
+ Builder.defineMacro("__arch64__");
+ // Solaris doesn't need these variants, but the BSDs do.
+ if (getTriple().getOS() != llvm::Triple::Solaris) {
+ Builder.defineMacro("__sparc64__");
+ Builder.defineMacro("__sparc_v9__");
+ Builder.defineMacro("__sparcv9__");
+ }
+}
diff --git a/lib/Basic/Targets/Sparc.h b/lib/Basic/Targets/Sparc.h
new file mode 100644
index 0000000000..aacc26119d
--- /dev/null
+++ b/lib/Basic/Targets/Sparc.h
@@ -0,0 +1,270 @@
+//===--- Sparc.h - Declare Sparc target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares Sparc TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+namespace clang {
+namespace targets {
+// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit).
+class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char *const GCCRegNames[];
+ bool SoftFloat;
+
+public:
+ SparcTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple), SoftFloat(false) {}
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ if (RegNo == 0)
+ return 24;
+ if (RegNo == 1)
+ return 25;
+ return -1;
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ // Check if software floating point is enabled
+ auto Feature = std::find(Features.begin(), Features.end(), "+soft-float");
+ if (Feature != Features.end()) {
+ SoftFloat = true;
+ }
+ return true;
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool hasFeature(StringRef Feature) const override;
+
+ bool hasSjLjLowering() const override { return true; }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ // FIXME: Implement!
+ return None;
+ }
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+ ArrayRef<const char *> getGCCRegNames() const override;
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
+ // FIXME: Implement!
+ switch (*Name) {
+ case 'I': // Signed 13-bit constant
+ case 'J': // Zero
+ case 'K': // 32-bit constant with the low 12 bits clear
+ case 'L': // A constant in the range supported by movcc (11-bit signed imm)
+ case 'M': // A constant in the range supported by movrcc (19-bit signed imm)
+ case 'N': // Same as 'K' but zext (required for SIMode)
+ case 'O': // The constant 4096
+ return true;
+
+ case 'f':
+ case 'e':
+ info.setAllowsRegister();
+ return true;
+ }
+ return false;
+ }
+ const char *getClobbers() const override {
+ // FIXME: Implement!
+ return "";
+ }
+
+ // No Sparc V7 for now, the backend doesn't support it anyway.
+ enum CPUKind {
+ CK_GENERIC,
+ CK_V8,
+ CK_SUPERSPARC,
+ CK_SPARCLITE,
+ CK_F934,
+ CK_HYPERSPARC,
+ CK_SPARCLITE86X,
+ CK_SPARCLET,
+ CK_TSC701,
+ CK_V9,
+ CK_ULTRASPARC,
+ CK_ULTRASPARC3,
+ CK_NIAGARA,
+ CK_NIAGARA2,
+ CK_NIAGARA3,
+ CK_NIAGARA4,
+ CK_MYRIAD2100,
+ CK_MYRIAD2150,
+ CK_MYRIAD2155,
+ CK_MYRIAD2450,
+ CK_MYRIAD2455,
+ CK_MYRIAD2x5x,
+ CK_MYRIAD2080,
+ CK_MYRIAD2085,
+ CK_MYRIAD2480,
+ CK_MYRIAD2485,
+ CK_MYRIAD2x8x,
+ CK_LEON2,
+ CK_LEON2_AT697E,
+ CK_LEON2_AT697F,
+ CK_LEON3,
+ CK_LEON3_UT699,
+ CK_LEON3_GR712RC,
+ CK_LEON4,
+ CK_LEON4_GR740
+ } CPU = CK_GENERIC;
+
+ enum CPUGeneration {
+ CG_V8,
+ CG_V9,
+ };
+
+ CPUGeneration getCPUGeneration(CPUKind Kind) const {
+ switch (Kind) {
+ case CK_GENERIC:
+ case CK_V8:
+ case CK_SUPERSPARC:
+ case CK_SPARCLITE:
+ case CK_F934:
+ case CK_HYPERSPARC:
+ case CK_SPARCLITE86X:
+ case CK_SPARCLET:
+ case CK_TSC701:
+ case CK_MYRIAD2100:
+ case CK_MYRIAD2150:
+ case CK_MYRIAD2155:
+ case CK_MYRIAD2450:
+ case CK_MYRIAD2455:
+ case CK_MYRIAD2x5x:
+ case CK_MYRIAD2080:
+ case CK_MYRIAD2085:
+ case CK_MYRIAD2480:
+ case CK_MYRIAD2485:
+ case CK_MYRIAD2x8x:
+ case CK_LEON2:
+ case CK_LEON2_AT697E:
+ case CK_LEON2_AT697F:
+ case CK_LEON3:
+ case CK_LEON3_UT699:
+ case CK_LEON3_GR712RC:
+ case CK_LEON4:
+ case CK_LEON4_GR740:
+ return CG_V8;
+ case CK_V9:
+ case CK_ULTRASPARC:
+ case CK_ULTRASPARC3:
+ case CK_NIAGARA:
+ case CK_NIAGARA2:
+ case CK_NIAGARA3:
+ case CK_NIAGARA4:
+ return CG_V9;
+ }
+ llvm_unreachable("Unexpected CPU kind");
+ }
+
+ CPUKind getCPUKind(StringRef Name) const;
+
+ bool isValidCPUName(StringRef Name) const override {
+ return getCPUKind(Name) != CK_GENERIC;
+ }
+
+ bool setCPU(const std::string &Name) override {
+ CPU = getCPUKind(Name);
+ return CPU != CK_GENERIC;
+ }
+};
+
+// SPARC v8 is the 32-bit mode selected by Triple::sparc.
+class LLVM_LIBRARY_VISIBILITY SparcV8TargetInfo : public SparcTargetInfo {
+public:
+ SparcV8TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : SparcTargetInfo(Triple, Opts) {
+ resetDataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64");
+ // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int.
+ switch (getTriple().getOS()) {
+ default:
+ SizeType = UnsignedInt;
+ IntPtrType = SignedInt;
+ PtrDiffType = SignedInt;
+ break;
+ case llvm::Triple::NetBSD:
+ case llvm::Triple::OpenBSD:
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ PtrDiffType = SignedLong;
+ break;
+ }
+ // Up to 32 bits are lock-free atomic, but we're willing to do atomic ops
+ // on up to 64 bits.
+ MaxAtomicPromoteWidth = 64;
+ MaxAtomicInlineWidth = 32;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool hasSjLjLowering() const override { return true; }
+};
+
+// SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel.
+class LLVM_LIBRARY_VISIBILITY SparcV8elTargetInfo : public SparcV8TargetInfo {
+public:
+ SparcV8elTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : SparcV8TargetInfo(Triple, Opts) {
+ resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32-S64");
+ }
+};
+
+// SPARC v9 is the 64-bit mode selected by Triple::sparcv9.
+class LLVM_LIBRARY_VISIBILITY SparcV9TargetInfo : public SparcTargetInfo {
+public:
+ SparcV9TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : SparcTargetInfo(Triple, Opts) {
+ // FIXME: Support Sparc quad-precision long double?
+ resetDataLayout("E-m:e-i64:64-n32:64-S128");
+ // This is an LP64 platform.
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+
+ // OpenBSD uses long long for int64_t and intmax_t.
+ if (getTriple().getOS() == llvm::Triple::OpenBSD)
+ IntMaxType = SignedLongLong;
+ else
+ IntMaxType = SignedLong;
+ Int64Type = IntMaxType;
+
+ // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit
+ // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned.
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad();
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool isValidCPUName(StringRef Name) const override {
+ return getCPUGeneration(SparcTargetInfo::getCPUKind(Name)) == CG_V9;
+ }
+
+ bool setCPU(const std::string &Name) override {
+ if (!SparcTargetInfo::setCPU(Name))
+ return false;
+ return getCPUGeneration(CPU) == CG_V9;
+ }
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H
diff --git a/lib/Basic/Targets/SystemZ.cpp b/lib/Basic/Targets/SystemZ.cpp
new file mode 100644
index 0000000000..98f3ae2f72
--- /dev/null
+++ b/lib/Basic/Targets/SystemZ.cpp
@@ -0,0 +1,118 @@
+//===--- SystemZ.cpp - Implement SystemZ target feature support -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements SystemZ TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemZ.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#include "clang/Basic/BuiltinsSystemZ.def"
+};
+
+const char *const SystemZTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "f0", "f2", "f4", "f6", "f1", "f3",
+ "f5", "f7", "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15"
+};
+
+ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+bool SystemZTargetInfo::validateAsmConstraint(
+ const char *&Name, TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ return false;
+
+ case 'a': // Address register
+ case 'd': // Data register (equivalent to 'r')
+ case 'f': // Floating-point register
+ Info.setAllowsRegister();
+ return true;
+
+ case 'I': // Unsigned 8-bit constant
+ case 'J': // Unsigned 12-bit constant
+ case 'K': // Signed 16-bit constant
+ case 'L': // Signed 20-bit displacement (on all targets we support)
+ case 'M': // 0x7fffffff
+ return true;
+
+ case 'Q': // Memory with base and unsigned 12-bit displacement
+ case 'R': // Likewise, plus an index
+ case 'S': // Memory with base and signed 20-bit displacement
+ case 'T': // Likewise, plus an index
+ Info.setAllowsMemory();
+ return true;
+ }
+}
+
+int SystemZTargetInfo::getISARevision(const StringRef &Name) const {
+ return llvm::StringSwitch<int>(Name)
+ .Cases("arch8", "z10", 8)
+ .Cases("arch9", "z196", 9)
+ .Cases("arch10", "zEC12", 10)
+ .Cases("arch11", "z13", 11)
+ .Cases("arch12", "z14", 12)
+ .Default(-1);
+}
+
+bool SystemZTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("systemz", true)
+ .Case("arch8", ISARevision >= 8)
+ .Case("arch9", ISARevision >= 9)
+ .Case("arch10", ISARevision >= 10)
+ .Case("arch11", ISARevision >= 11)
+ .Case("arch12", ISARevision >= 12)
+ .Case("htm", HasTransactionalExecution)
+ .Case("vx", HasVector)
+ .Default(false);
+}
+
+void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__s390__");
+ Builder.defineMacro("__s390x__");
+ Builder.defineMacro("__zarch__");
+ Builder.defineMacro("__LONG_DOUBLE_128__");
+
+ Builder.defineMacro("__ARCH__", Twine(ISARevision));
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+
+ if (HasTransactionalExecution)
+ Builder.defineMacro("__HTM__");
+ if (HasVector)
+ Builder.defineMacro("__VX__");
+ if (Opts.ZVector)
+ Builder.defineMacro("__VEC__", "10302");
+}
+
+ArrayRef<Builtin::Info> SystemZTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/SystemZ.h b/lib/Basic/Targets/SystemZ.h
new file mode 100644
index 0000000000..3023c1d2ea
--- /dev/null
+++ b/lib/Basic/Targets/SystemZ.h
@@ -0,0 +1,145 @@
+//===--- SystemZ.h - Declare SystemZ target feature support -----*- 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 SystemZ TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
+
+ static const Builtin::Info BuiltinInfo[];
+ static const char *const GCCRegNames[];
+ std::string CPU;
+ int ISARevision;
+ bool HasTransactionalExecution;
+ bool HasVector;
+
+public:
+ SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple), CPU("z10"), ISARevision(8),
+ HasTransactionalExecution(false), HasVector(false) {
+ IntMaxType = SignedLong;
+ Int64Type = SignedLong;
+ TLSSupported = true;
+ IntWidth = IntAlign = 32;
+ LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad();
+ DefaultAlignForAttributeAligned = 64;
+ MinGlobalAlign = 16;
+ resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64");
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ // No aliases.
+ return None;
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override;
+
+ const char *getClobbers() const override {
+ // FIXME: Is this really right?
+ return "";
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::SystemZBuiltinVaList;
+ }
+
+ int getISARevision(const StringRef &Name) const;
+
+ bool isValidCPUName(StringRef Name) const override {
+ return getISARevision(Name) != -1;
+ }
+
+ bool setCPU(const std::string &Name) override {
+ CPU = Name;
+ ISARevision = getISARevision(CPU);
+ return ISARevision != -1;
+ }
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override {
+ int ISARevision = getISARevision(CPU);
+ if (ISARevision >= 10)
+ Features["transactional-execution"] = true;
+ if (ISARevision >= 11)
+ Features["vector"] = true;
+ if (ISARevision >= 12)
+ Features["vector-enhancements-1"] = true;
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ HasTransactionalExecution = false;
+ HasVector = false;
+ for (const auto &Feature : Features) {
+ if (Feature == "+transactional-execution")
+ HasTransactionalExecution = true;
+ else if (Feature == "+vector")
+ HasVector = true;
+ }
+ // If we use the vector ABI, vector types are 64-bit aligned.
+ if (HasVector) {
+ MaxVectorAlign = 64;
+ resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64"
+ "-v128:64-a:8:16-n32:64");
+ }
+ return true;
+ }
+
+ bool hasFeature(StringRef Feature) const override;
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ case CC_C:
+ case CC_Swift:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+ }
+
+ StringRef getABI() const override {
+ if (HasVector)
+ return "vector";
+ return "";
+ }
+
+ bool useFloat128ManglingForLongDouble() const override { return true; }
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H
diff --git a/lib/Basic/Targets/TCE.cpp b/lib/Basic/Targets/TCE.cpp
new file mode 100644
index 0000000000..bf89c1dc54
--- /dev/null
+++ b/lib/Basic/Targets/TCE.cpp
@@ -0,0 +1,35 @@
+//===--- TCE.cpp - Implement TCE target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements TCE TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TCE.h"
+#include "Targets.h"
+#include "clang/Basic/MacroBuilder.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+void TCETargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "tce", Opts);
+ Builder.defineMacro("__TCE__");
+ Builder.defineMacro("__TCE_V1__");
+}
+
+void TCELETargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "tcele", Opts);
+ Builder.defineMacro("__TCE__");
+ Builder.defineMacro("__TCE_V1__");
+ Builder.defineMacro("__TCELE__");
+ Builder.defineMacro("__TCELE_V1__");
+}
diff --git a/lib/Basic/Targets/TCE.h b/lib/Basic/Targets/TCE.h
new file mode 100644
index 0000000000..be43bed98d
--- /dev/null
+++ b/lib/Basic/Targets/TCE.h
@@ -0,0 +1,123 @@
+//===--- TCE.h - Declare TCE target feature support -------------*- 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 TCE TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+// llvm and clang cannot be used directly to output native binaries for
+// target, but is used to compile C code to llvm bitcode with correct
+// type and alignment information.
+//
+// TCE uses the llvm bitcode as input and uses it for generating customized
+// target processor and program binary. TCE co-design environment is
+// publicly available in http://tce.cs.tut.fi
+
+static const unsigned TCEOpenCLAddrSpaceMap[] = {
+ 0, // Default
+ 3, // opencl_global
+ 4, // opencl_local
+ 5, // opencl_constant
+ 0, // opencl_private
+ // FIXME: generic has to be added to the target
+ 0, // opencl_generic
+ 0, // cuda_device
+ 0, // cuda_constant
+ 0 // cuda_shared
+};
+
+class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
+public:
+ TCETargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ TLSSupported = false;
+ IntWidth = 32;
+ LongWidth = LongLongWidth = 32;
+ PointerWidth = 32;
+ IntAlign = 32;
+ LongAlign = LongLongAlign = 32;
+ PointerAlign = 32;
+ SuitableAlign = 32;
+ SizeType = UnsignedInt;
+ IntMaxType = SignedLong;
+ IntPtrType = SignedInt;
+ PtrDiffType = SignedInt;
+ FloatWidth = 32;
+ FloatAlign = 32;
+ DoubleWidth = 32;
+ DoubleAlign = 32;
+ LongDoubleWidth = 32;
+ LongDoubleAlign = 32;
+ FloatFormat = &llvm::APFloat::IEEEsingle();
+ DoubleFormat = &llvm::APFloat::IEEEsingle();
+ LongDoubleFormat = &llvm::APFloat::IEEEsingle();
+ resetDataLayout("E-p:32:32:32-i1:8:8-i8:8:32-"
+ "i16:16:32-i32:32:32-i64:32:32-"
+ "f32:32:32-f64:32:32-v64:32:32-"
+ "v128:32:32-v256:32:32-v512:32:32-"
+ "v1024:32:32-a0:0:32-n32");
+ AddrSpaceMap = &TCEOpenCLAddrSpaceMap;
+ UseAddrSpaceMapMangling = true;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ bool hasFeature(StringRef Feature) const override { return Feature == "tce"; }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+
+ const char *getClobbers() const override { return ""; }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override { return None; }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
+ return true;
+ }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY TCELETargetInfo : public TCETargetInfo {
+public:
+ TCELETargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : TCETargetInfo(Triple, Opts) {
+ BigEndian = false;
+
+ resetDataLayout("e-p:32:32:32-i1:8:8-i8:8:32-"
+ "i16:16:32-i32:32:32-i64:32:32-"
+ "f32:32:32-f64:32:32-v64:32:32-"
+ "v128:32:32-v256:32:32-v512:32:32-"
+ "v1024:32:32-a0:0:32-n32");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H
diff --git a/lib/Basic/Targets/WebAssembly.cpp b/lib/Basic/Targets/WebAssembly.cpp
new file mode 100644
index 0000000000..9eaaf8d4fd
--- /dev/null
+++ b/lib/Basic/Targets/WebAssembly.cpp
@@ -0,0 +1,87 @@
+//===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements WebAssembly TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "WebAssembly.h"
+#include "Targets.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsWebAssembly.def"
+};
+
+bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("simd128", SIMDLevel >= SIMD128)
+ .Default(false);
+}
+
+bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const {
+ return llvm::StringSwitch<bool>(Name)
+ .Case("mvp", true)
+ .Case("bleeding-edge", true)
+ .Case("generic", true)
+ .Default(false);
+}
+
+void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ defineCPUMacros(Builder, "wasm", /*Tuning=*/false);
+ if (SIMDLevel >= SIMD128)
+ Builder.defineMacro("__wasm_simd128__");
+}
+
+bool WebAssemblyTargetInfo::handleTargetFeatures(
+ std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
+ for (const auto &Feature : Features) {
+ if (Feature == "+simd128") {
+ SIMDLevel = std::max(SIMDLevel, SIMD128);
+ continue;
+ }
+ if (Feature == "-simd128") {
+ SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1));
+ continue;
+ }
+
+ Diags.Report(diag::err_opt_not_valid_with_opt)
+ << Feature << "-target-feature";
+ return false;
+ }
+ return true;
+}
+
+ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
+ defineCPUMacros(Builder, "wasm32", /*Tuning=*/false);
+}
+
+void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WebAssemblyTargetInfo::getTargetDefines(Opts, Builder);
+ defineCPUMacros(Builder, "wasm64", /*Tuning=*/false);
+}
diff --git a/lib/Basic/Targets/WebAssembly.h b/lib/Basic/Targets/WebAssembly.h
new file mode 100644
index 0000000000..20f57506d9
--- /dev/null
+++ b/lib/Basic/Targets/WebAssembly.h
@@ -0,0 +1,144 @@
+//=== WebAssembly.h - Declare WebAssembly target feature support *- 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 WebAssembly TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+
+ enum SIMDEnum {
+ NoSIMD,
+ SIMD128,
+ } SIMDLevel;
+
+public:
+ explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &)
+ : TargetInfo(T), SIMDLevel(NoSIMD) {
+ NoAsmVariants = true;
+ SuitableAlign = 128;
+ LargeArrayMinWidth = 128;
+ LargeArrayAlign = 128;
+ SimdDefaultAlign = 128;
+ SigAtomicType = SignedLong;
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad();
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+ }
+
+protected:
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+private:
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override {
+ if (CPU == "bleeding-edge")
+ Features["simd128"] = true;
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+ }
+
+ bool hasFeature(StringRef Feature) const final;
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) final;
+
+ bool isValidCPUName(StringRef Name) const final;
+
+ bool setCPU(const std::string &Name) final { return isValidCPUName(Name); }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const final;
+
+ BuiltinVaListKind getBuiltinVaListKind() const final {
+ return VoidPtrBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const final { return None; }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const final {
+ return None;
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const final {
+ return false;
+ }
+
+ const char *getClobbers() const final { return ""; }
+
+ bool isCLZForZeroUndef() const final { return false; }
+
+ bool hasInt128Type() const final { return true; }
+
+ IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final {
+ // WebAssembly prefers long long for explicitly 64-bit integers.
+ return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong)
+ : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned);
+ }
+
+ IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final {
+ // WebAssembly uses long long for int_least64_t and int_fast64_t.
+ return BitWidth == 64
+ ? (IsSigned ? SignedLongLong : UnsignedLongLong)
+ : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned);
+ }
+};
+class LLVM_LIBRARY_VISIBILITY WebAssembly32TargetInfo
+ : public WebAssemblyTargetInfo {
+public:
+ explicit WebAssembly32TargetInfo(const llvm::Triple &T,
+ const TargetOptions &Opts)
+ : WebAssemblyTargetInfo(T, Opts) {
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128");
+ }
+
+protected:
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY WebAssembly64TargetInfo
+ : public WebAssemblyTargetInfo {
+public:
+ explicit WebAssembly64TargetInfo(const llvm::Triple &T,
+ const TargetOptions &Opts)
+ : WebAssemblyTargetInfo(T, Opts) {
+ LongAlign = LongWidth = 64;
+ PointerAlign = PointerWidth = 64;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ IntPtrType = SignedLong;
+ resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
+ }
+
+protected:
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H
diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp
new file mode 100644
index 0000000000..ee70c14e1d
--- /dev/null
+++ b/lib/Basic/Targets/X86.cpp
@@ -0,0 +1,1663 @@
+//===--- X86.cpp - Implement X86 target feature support -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements X86 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+
+namespace clang {
+namespace targets {
+
+const Builtin::Info BuiltinInfoX86[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
+ {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE},
+#include "clang/Basic/BuiltinsX86.def"
+
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
+ {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE},
+#include "clang/Basic/BuiltinsX86_64.def"
+};
+
+static const char *const GCCRegNames[] = {
+ "ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
+ "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
+ "argp", "flags", "fpcr", "fpsr", "dirflag", "frame", "xmm0", "xmm1",
+ "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "mm0", "mm1",
+ "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "r8", "r9",
+ "r10", "r11", "r12", "r13", "r14", "r15", "xmm8", "xmm9",
+ "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", "ymm0", "ymm1",
+ "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9",
+ "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "xmm16", "xmm17",
+ "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", "xmm24", "xmm25",
+ "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", "ymm16", "ymm17",
+ "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", "ymm23", "ymm24", "ymm25",
+ "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31", "zmm0", "zmm1",
+ "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9",
+ "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17",
+ "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm24", "zmm25",
+ "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", "k0", "k1",
+ "k2", "k3", "k4", "k5", "k6", "k7",
+ "cr0", "cr2", "cr3", "cr4", "cr8",
+ "dr0", "dr1", "dr2", "dr3", "dr6", "dr7",
+};
+
+const TargetInfo::AddlRegName AddlRegNames[] = {
+ {{"al", "ah", "eax", "rax"}, 0},
+ {{"bl", "bh", "ebx", "rbx"}, 3},
+ {{"cl", "ch", "ecx", "rcx"}, 2},
+ {{"dl", "dh", "edx", "rdx"}, 1},
+ {{"esi", "rsi"}, 4},
+ {{"edi", "rdi"}, 5},
+ {{"esp", "rsp"}, 7},
+ {{"ebp", "rbp"}, 6},
+ {{"r8d", "r8w", "r8b"}, 38},
+ {{"r9d", "r9w", "r9b"}, 39},
+ {{"r10d", "r10w", "r10b"}, 40},
+ {{"r11d", "r11w", "r11b"}, 41},
+ {{"r12d", "r12w", "r12b"}, 42},
+ {{"r13d", "r13w", "r13b"}, 43},
+ {{"r14d", "r14w", "r14b"}, 44},
+ {{"r15d", "r15w", "r15b"}, 45},
+};
+
+} // namespace targets
+} // namespace clang
+
+using namespace clang;
+using namespace clang::targets;
+
+bool X86TargetInfo::setFPMath(StringRef Name) {
+ if (Name == "387") {
+ FPMath = FP_387;
+ return true;
+ }
+ if (Name == "sse") {
+ FPMath = FP_SSE;
+ return true;
+ }
+ return false;
+}
+
+bool X86TargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+ // FIXME: This *really* should not be here.
+ // X86_64 always has SSE2.
+ if (getTriple().getArch() == llvm::Triple::x86_64)
+ setFeatureEnabledImpl(Features, "sse2", true);
+
+ const CPUKind Kind = getCPUKind(CPU);
+
+ // Enable X87 for all X86 processors but Lakemont.
+ if (Kind != CK_Lakemont)
+ setFeatureEnabledImpl(Features, "x87", true);
+
+ switch (Kind) {
+ case CK_Generic:
+ case CK_i386:
+ case CK_i486:
+ case CK_i586:
+ case CK_Pentium:
+ case CK_PentiumPro:
+ case CK_Lakemont:
+ break;
+
+ case CK_PentiumMMX:
+ case CK_Pentium2:
+ case CK_K6:
+ case CK_WinChipC6:
+ setFeatureEnabledImpl(Features, "mmx", true);
+ break;
+
+ case CK_Cannonlake:
+ setFeatureEnabledImpl(Features, "avx512ifma", true);
+ setFeatureEnabledImpl(Features, "avx512vbmi", true);
+ setFeatureEnabledImpl(Features, "sha", true);
+ LLVM_FALLTHROUGH;
+ case CK_SkylakeServer:
+ setFeatureEnabledImpl(Features, "avx512f", true);
+ setFeatureEnabledImpl(Features, "avx512cd", true);
+ setFeatureEnabledImpl(Features, "avx512dq", true);
+ setFeatureEnabledImpl(Features, "avx512bw", true);
+ setFeatureEnabledImpl(Features, "avx512vl", true);
+ setFeatureEnabledImpl(Features, "pku", true);
+ setFeatureEnabledImpl(Features, "clwb", true);
+ 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);
+ setFeatureEnabledImpl(Features, "rtm", true);
+ LLVM_FALLTHROUGH;
+ case CK_Broadwell:
+ setFeatureEnabledImpl(Features, "rdseed", true);
+ setFeatureEnabledImpl(Features, "adx", true);
+ LLVM_FALLTHROUGH;
+ case CK_Haswell:
+ setFeatureEnabledImpl(Features, "avx2", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "bmi2", true);
+ setFeatureEnabledImpl(Features, "fma", true);
+ setFeatureEnabledImpl(Features, "movbe", true);
+ LLVM_FALLTHROUGH;
+ case CK_IvyBridge:
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ LLVM_FALLTHROUGH;
+ case CK_SandyBridge:
+ setFeatureEnabledImpl(Features, "avx", true);
+ setFeatureEnabledImpl(Features, "xsave", true);
+ setFeatureEnabledImpl(Features, "xsaveopt", true);
+ LLVM_FALLTHROUGH;
+ case CK_Westmere:
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ LLVM_FALLTHROUGH;
+ case CK_Nehalem:
+ setFeatureEnabledImpl(Features, "sse4.2", true);
+ LLVM_FALLTHROUGH;
+ case CK_Penryn:
+ setFeatureEnabledImpl(Features, "sse4.1", true);
+ LLVM_FALLTHROUGH;
+ case CK_Core2:
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ LLVM_FALLTHROUGH;
+ case CK_Yonah:
+ case CK_Prescott:
+ case CK_Nocona:
+ setFeatureEnabledImpl(Features, "sse3", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ LLVM_FALLTHROUGH;
+ case CK_PentiumM:
+ case CK_Pentium4:
+ case CK_x86_64:
+ setFeatureEnabledImpl(Features, "sse2", true);
+ LLVM_FALLTHROUGH;
+ case CK_Pentium3:
+ case CK_C3_2:
+ setFeatureEnabledImpl(Features, "sse", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ break;
+
+ case CK_Goldmont:
+ setFeatureEnabledImpl(Features, "sha", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "rdseed", true);
+ setFeatureEnabledImpl(Features, "xsave", true);
+ setFeatureEnabledImpl(Features, "xsaveopt", true);
+ setFeatureEnabledImpl(Features, "xsavec", true);
+ setFeatureEnabledImpl(Features, "xsaves", true);
+ setFeatureEnabledImpl(Features, "clflushopt", true);
+ setFeatureEnabledImpl(Features, "mpx", true);
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ LLVM_FALLTHROUGH;
+ case CK_Silvermont:
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "sse4.2", true);
+ LLVM_FALLTHROUGH;
+ case CK_Bonnell:
+ setFeatureEnabledImpl(Features, "movbe", true);
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ break;
+
+ case CK_KNM:
+ // TODO: Add avx5124fmaps/avx5124vnniw.
+ setFeatureEnabledImpl(Features, "avx512vpopcntdq", true);
+ LLVM_FALLTHROUGH;
+ case CK_KNL:
+ setFeatureEnabledImpl(Features, "avx512f", true);
+ setFeatureEnabledImpl(Features, "avx512cd", true);
+ setFeatureEnabledImpl(Features, "avx512er", true);
+ setFeatureEnabledImpl(Features, "avx512pf", true);
+ setFeatureEnabledImpl(Features, "prefetchwt1", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ setFeatureEnabledImpl(Features, "rdseed", true);
+ setFeatureEnabledImpl(Features, "adx", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "bmi2", true);
+ setFeatureEnabledImpl(Features, "rtm", true);
+ setFeatureEnabledImpl(Features, "fma", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ setFeatureEnabledImpl(Features, "xsaveopt", true);
+ setFeatureEnabledImpl(Features, "xsave", true);
+ setFeatureEnabledImpl(Features, "movbe", true);
+ break;
+
+ case CK_K6_2:
+ case CK_K6_3:
+ case CK_WinChip2:
+ case CK_C3:
+ setFeatureEnabledImpl(Features, "3dnow", true);
+ break;
+
+ case CK_AMDFAM10:
+ setFeatureEnabledImpl(Features, "sse4a", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "popcnt", true);
+ LLVM_FALLTHROUGH;
+ case CK_K8SSE3:
+ setFeatureEnabledImpl(Features, "sse3", true);
+ LLVM_FALLTHROUGH;
+ case CK_K8:
+ setFeatureEnabledImpl(Features, "sse2", true);
+ LLVM_FALLTHROUGH;
+ case CK_AthlonXP:
+ setFeatureEnabledImpl(Features, "sse", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ LLVM_FALLTHROUGH;
+ case CK_Athlon:
+ case CK_Geode:
+ setFeatureEnabledImpl(Features, "3dnowa", true);
+ break;
+
+ case CK_BTVER2:
+ setFeatureEnabledImpl(Features, "avx", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "xsaveopt", true);
+ setFeatureEnabledImpl(Features, "movbe", true);
+ LLVM_FALLTHROUGH;
+ case CK_BTVER1:
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "sse4a", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "popcnt", true);
+ setFeatureEnabledImpl(Features, "prfchw", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ break;
+
+ case CK_ZNVER1:
+ setFeatureEnabledImpl(Features, "adx", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "avx2", true);
+ 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);
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "mwaitx", true);
+ setFeatureEnabledImpl(Features, "movbe", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "popcnt", true);
+ setFeatureEnabledImpl(Features, "prfchw", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "rdseed", true);
+ setFeatureEnabledImpl(Features, "sha", true);
+ setFeatureEnabledImpl(Features, "sse4a", true);
+ setFeatureEnabledImpl(Features, "xsave", true);
+ setFeatureEnabledImpl(Features, "xsavec", true);
+ setFeatureEnabledImpl(Features, "xsaveopt", true);
+ setFeatureEnabledImpl(Features, "xsaves", true);
+ break;
+
+ case CK_BDVER4:
+ setFeatureEnabledImpl(Features, "avx2", true);
+ setFeatureEnabledImpl(Features, "bmi2", true);
+ setFeatureEnabledImpl(Features, "mwaitx", true);
+ LLVM_FALLTHROUGH;
+ case CK_BDVER3:
+ setFeatureEnabledImpl(Features, "fsgsbase", true);
+ setFeatureEnabledImpl(Features, "xsaveopt", true);
+ LLVM_FALLTHROUGH;
+ case CK_BDVER2:
+ setFeatureEnabledImpl(Features, "bmi", true);
+ setFeatureEnabledImpl(Features, "fma", true);
+ setFeatureEnabledImpl(Features, "f16c", true);
+ setFeatureEnabledImpl(Features, "tbm", true);
+ LLVM_FALLTHROUGH;
+ case CK_BDVER1:
+ // xop implies avx, sse4a and fma4.
+ setFeatureEnabledImpl(Features, "xop", true);
+ setFeatureEnabledImpl(Features, "lwp", true);
+ setFeatureEnabledImpl(Features, "lzcnt", true);
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "prfchw", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ setFeatureEnabledImpl(Features, "xsave", true);
+ break;
+ }
+ if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec))
+ return false;
+
+ // Can't do this earlier because we need to be able to explicitly enable
+ // or disable these features and the things that they depend upon.
+
+ // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled.
+ auto I = Features.find("sse4.2");
+ if (I != Features.end() && I->getValue() &&
+ std::find(FeaturesVec.begin(), FeaturesVec.end(), "-popcnt") ==
+ FeaturesVec.end())
+ Features["popcnt"] = true;
+
+ // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled.
+ I = Features.find("3dnow");
+ if (I != Features.end() && I->getValue() &&
+ std::find(FeaturesVec.begin(), FeaturesVec.end(), "-prfchw") ==
+ FeaturesVec.end())
+ Features["prfchw"] = true;
+
+ // Additionally, if SSE is enabled and mmx is not explicitly disabled,
+ // then enable MMX.
+ I = Features.find("sse");
+ if (I != Features.end() && I->getValue() &&
+ std::find(FeaturesVec.begin(), FeaturesVec.end(), "-mmx") ==
+ FeaturesVec.end())
+ Features["mmx"] = true;
+
+ return true;
+}
+
+void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features,
+ X86SSEEnum Level, bool Enabled) {
+ if (Enabled) {
+ switch (Level) {
+ case AVX512F:
+ Features["avx512f"] = true;
+ LLVM_FALLTHROUGH;
+ case AVX2:
+ Features["avx2"] = true;
+ LLVM_FALLTHROUGH;
+ case AVX:
+ Features["avx"] = true;
+ Features["xsave"] = true;
+ LLVM_FALLTHROUGH;
+ case SSE42:
+ Features["sse4.2"] = true;
+ LLVM_FALLTHROUGH;
+ case SSE41:
+ Features["sse4.1"] = true;
+ LLVM_FALLTHROUGH;
+ case SSSE3:
+ Features["ssse3"] = true;
+ LLVM_FALLTHROUGH;
+ case SSE3:
+ Features["sse3"] = true;
+ LLVM_FALLTHROUGH;
+ case SSE2:
+ Features["sse2"] = true;
+ LLVM_FALLTHROUGH;
+ case SSE1:
+ Features["sse"] = true;
+ LLVM_FALLTHROUGH;
+ case NoSSE:
+ break;
+ }
+ return;
+ }
+
+ switch (Level) {
+ case NoSSE:
+ case SSE1:
+ Features["sse"] = false;
+ LLVM_FALLTHROUGH;
+ case SSE2:
+ Features["sse2"] = Features["pclmul"] = Features["aes"] = Features["sha"] =
+ false;
+ LLVM_FALLTHROUGH;
+ case SSE3:
+ Features["sse3"] = false;
+ setXOPLevel(Features, NoXOP, false);
+ LLVM_FALLTHROUGH;
+ case SSSE3:
+ Features["ssse3"] = false;
+ LLVM_FALLTHROUGH;
+ case SSE41:
+ Features["sse4.1"] = false;
+ LLVM_FALLTHROUGH;
+ case SSE42:
+ Features["sse4.2"] = false;
+ LLVM_FALLTHROUGH;
+ case AVX:
+ Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] =
+ Features["xsaveopt"] = false;
+ setXOPLevel(Features, FMA4, false);
+ LLVM_FALLTHROUGH;
+ case AVX2:
+ Features["avx2"] = false;
+ LLVM_FALLTHROUGH;
+ case AVX512F:
+ Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] =
+ Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] =
+ Features["avx512vl"] = Features["avx512vbmi"] =
+ Features["avx512ifma"] = Features["avx512vpopcntdq"] = false;
+ break;
+ }
+}
+
+void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features,
+ MMX3DNowEnum Level, bool Enabled) {
+ if (Enabled) {
+ switch (Level) {
+ case AMD3DNowAthlon:
+ Features["3dnowa"] = true;
+ LLVM_FALLTHROUGH;
+ case AMD3DNow:
+ Features["3dnow"] = true;
+ LLVM_FALLTHROUGH;
+ case MMX:
+ Features["mmx"] = true;
+ LLVM_FALLTHROUGH;
+ case NoMMX3DNow:
+ break;
+ }
+ return;
+ }
+
+ switch (Level) {
+ case NoMMX3DNow:
+ case MMX:
+ Features["mmx"] = false;
+ LLVM_FALLTHROUGH;
+ case AMD3DNow:
+ Features["3dnow"] = false;
+ LLVM_FALLTHROUGH;
+ case AMD3DNowAthlon:
+ Features["3dnowa"] = false;
+ break;
+ }
+}
+
+void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
+ bool Enabled) {
+ if (Enabled) {
+ switch (Level) {
+ case XOP:
+ Features["xop"] = true;
+ LLVM_FALLTHROUGH;
+ case FMA4:
+ Features["fma4"] = true;
+ setSSELevel(Features, AVX, true);
+ LLVM_FALLTHROUGH;
+ case SSE4A:
+ Features["sse4a"] = true;
+ setSSELevel(Features, SSE3, true);
+ LLVM_FALLTHROUGH;
+ case NoXOP:
+ break;
+ }
+ return;
+ }
+
+ switch (Level) {
+ case NoXOP:
+ case SSE4A:
+ Features["sse4a"] = false;
+ LLVM_FALLTHROUGH;
+ case FMA4:
+ Features["fma4"] = false;
+ LLVM_FALLTHROUGH;
+ case XOP:
+ Features["xop"] = false;
+ break;
+ }
+}
+
+void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
+ StringRef Name, bool Enabled) {
+ // This is a bit of a hack to deal with the sse4 target feature when used
+ // as part of the target attribute. We handle sse4 correctly everywhere
+ // else. See below for more information on how we handle the sse4 options.
+ if (Name != "sse4")
+ Features[Name] = Enabled;
+
+ if (Name == "mmx") {
+ setMMXLevel(Features, MMX, Enabled);
+ } else if (Name == "sse") {
+ setSSELevel(Features, SSE1, Enabled);
+ } else if (Name == "sse2") {
+ setSSELevel(Features, SSE2, Enabled);
+ } else if (Name == "sse3") {
+ setSSELevel(Features, SSE3, Enabled);
+ } else if (Name == "ssse3") {
+ setSSELevel(Features, SSSE3, Enabled);
+ } else if (Name == "sse4.2") {
+ setSSELevel(Features, SSE42, Enabled);
+ } else if (Name == "sse4.1") {
+ setSSELevel(Features, SSE41, Enabled);
+ } else if (Name == "3dnow") {
+ setMMXLevel(Features, AMD3DNow, Enabled);
+ } else if (Name == "3dnowa") {
+ setMMXLevel(Features, AMD3DNowAthlon, Enabled);
+ } else if (Name == "aes") {
+ if (Enabled)
+ setSSELevel(Features, SSE2, Enabled);
+ } else if (Name == "pclmul") {
+ if (Enabled)
+ setSSELevel(Features, SSE2, Enabled);
+ } else if (Name == "avx") {
+ setSSELevel(Features, AVX, Enabled);
+ } else if (Name == "avx2") {
+ setSSELevel(Features, AVX2, Enabled);
+ } else if (Name == "avx512f") {
+ setSSELevel(Features, AVX512F, Enabled);
+ } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" ||
+ Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" ||
+ Name == "avx512vbmi" || Name == "avx512ifma" ||
+ Name == "avx512vpopcntdq") {
+ if (Enabled)
+ setSSELevel(Features, AVX512F, Enabled);
+ // Enable BWI instruction if VBMI is being enabled.
+ if (Name == "avx512vbmi" && Enabled)
+ Features["avx512bw"] = true;
+ // Also disable VBMI if BWI is being disabled.
+ if (Name == "avx512bw" && !Enabled)
+ Features["avx512vbmi"] = false;
+ } else if (Name == "fma") {
+ if (Enabled)
+ setSSELevel(Features, AVX, Enabled);
+ } else if (Name == "fma4") {
+ setXOPLevel(Features, FMA4, Enabled);
+ } else if (Name == "xop") {
+ setXOPLevel(Features, XOP, Enabled);
+ } else if (Name == "sse4a") {
+ setXOPLevel(Features, SSE4A, Enabled);
+ } else if (Name == "f16c") {
+ if (Enabled)
+ setSSELevel(Features, AVX, Enabled);
+ } else if (Name == "sha") {
+ if (Enabled)
+ setSSELevel(Features, SSE2, Enabled);
+ } else if (Name == "sse4") {
+ // We can get here via the __target__ attribute since that's not controlled
+ // via the -msse4/-mno-sse4 command line alias. Handle this the same way
+ // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if
+ // disabled.
+ if (Enabled)
+ setSSELevel(Features, SSE42, Enabled);
+ else
+ setSSELevel(Features, SSE41, Enabled);
+ } else if (Name == "xsave") {
+ if (!Enabled)
+ Features["xsaveopt"] = false;
+ } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") {
+ if (Enabled)
+ Features["xsave"] = true;
+ }
+}
+
+/// handleTargetFeatures - Perform initialization based on the user
+/// configured set of features.
+bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ for (const auto &Feature : Features) {
+ if (Feature[0] != '+')
+ continue;
+
+ if (Feature == "+aes") {
+ HasAES = true;
+ } else if (Feature == "+pclmul") {
+ HasPCLMUL = true;
+ } else if (Feature == "+lzcnt") {
+ HasLZCNT = true;
+ } else if (Feature == "+rdrnd") {
+ HasRDRND = true;
+ } else if (Feature == "+fsgsbase") {
+ HasFSGSBASE = true;
+ } else if (Feature == "+bmi") {
+ HasBMI = true;
+ } else if (Feature == "+bmi2") {
+ HasBMI2 = true;
+ } else if (Feature == "+popcnt") {
+ HasPOPCNT = true;
+ } else if (Feature == "+rtm") {
+ HasRTM = true;
+ } else if (Feature == "+prfchw") {
+ HasPRFCHW = true;
+ } else if (Feature == "+rdseed") {
+ HasRDSEED = true;
+ } else if (Feature == "+adx") {
+ HasADX = true;
+ } else if (Feature == "+tbm") {
+ HasTBM = true;
+ } else if (Feature == "+lwp") {
+ HasLWP = true;
+ } else if (Feature == "+fma") {
+ HasFMA = true;
+ } else if (Feature == "+f16c") {
+ HasF16C = true;
+ } else if (Feature == "+avx512cd") {
+ HasAVX512CD = true;
+ } else if (Feature == "+avx512vpopcntdq") {
+ HasAVX512VPOPCNTDQ = true;
+ } else if (Feature == "+avx512er") {
+ HasAVX512ER = true;
+ } else if (Feature == "+avx512pf") {
+ HasAVX512PF = true;
+ } else if (Feature == "+avx512dq") {
+ HasAVX512DQ = true;
+ } else if (Feature == "+avx512bw") {
+ HasAVX512BW = true;
+ } else if (Feature == "+avx512vl") {
+ HasAVX512VL = true;
+ } else if (Feature == "+avx512vbmi") {
+ HasAVX512VBMI = true;
+ } else if (Feature == "+avx512ifma") {
+ HasAVX512IFMA = true;
+ } else if (Feature == "+sha") {
+ HasSHA = true;
+ } else if (Feature == "+mpx") {
+ HasMPX = true;
+ } else if (Feature == "+movbe") {
+ HasMOVBE = true;
+ } else if (Feature == "+sgx") {
+ HasSGX = true;
+ } else if (Feature == "+cx16") {
+ HasCX16 = true;
+ } else if (Feature == "+fxsr") {
+ HasFXSR = true;
+ } else if (Feature == "+xsave") {
+ HasXSAVE = true;
+ } else if (Feature == "+xsaveopt") {
+ HasXSAVEOPT = true;
+ } else if (Feature == "+xsavec") {
+ HasXSAVEC = true;
+ } else if (Feature == "+xsaves") {
+ HasXSAVES = true;
+ } else if (Feature == "+mwaitx") {
+ HasMWAITX = true;
+ } else if (Feature == "+pku") {
+ HasPKU = true;
+ } else if (Feature == "+clflushopt") {
+ HasCLFLUSHOPT = true;
+ } else if (Feature == "+clwb") {
+ HasCLWB = true;
+ } else if (Feature == "+prefetchwt1") {
+ HasPREFETCHWT1 = true;
+ } else if (Feature == "+clzero") {
+ HasCLZERO = true;
+ }
+
+ X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
+ .Case("+avx512f", AVX512F)
+ .Case("+avx2", AVX2)
+ .Case("+avx", AVX)
+ .Case("+sse4.2", SSE42)
+ .Case("+sse4.1", SSE41)
+ .Case("+ssse3", SSSE3)
+ .Case("+sse3", SSE3)
+ .Case("+sse2", SSE2)
+ .Case("+sse", SSE1)
+ .Default(NoSSE);
+ SSELevel = std::max(SSELevel, Level);
+
+ MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch<MMX3DNowEnum>(Feature)
+ .Case("+3dnowa", AMD3DNowAthlon)
+ .Case("+3dnow", AMD3DNow)
+ .Case("+mmx", MMX)
+ .Default(NoMMX3DNow);
+ MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel);
+
+ XOPEnum XLevel = llvm::StringSwitch<XOPEnum>(Feature)
+ .Case("+xop", XOP)
+ .Case("+fma4", FMA4)
+ .Case("+sse4a", SSE4A)
+ .Default(NoXOP);
+ XOPLevel = std::max(XOPLevel, XLevel);
+ }
+
+ // LLVM doesn't have a separate switch for fpmath, so only accept it if it
+ // matches the selected sse level.
+ if ((FPMath == FP_SSE && SSELevel < SSE1) ||
+ (FPMath == FP_387 && SSELevel >= SSE1)) {
+ Diags.Report(diag::err_target_unsupported_fpmath)
+ << (FPMath == FP_SSE ? "sse" : "387");
+ return false;
+ }
+
+ SimdDefaultAlign =
+ hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
+ return true;
+}
+
+/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro
+/// definitions for this particular subtarget.
+void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Target identification.
+ if (getTriple().getArch() == llvm::Triple::x86_64) {
+ Builder.defineMacro("__amd64__");
+ Builder.defineMacro("__amd64");
+ Builder.defineMacro("__x86_64");
+ Builder.defineMacro("__x86_64__");
+ if (getTriple().getArchName() == "x86_64h") {
+ Builder.defineMacro("__x86_64h");
+ Builder.defineMacro("__x86_64h__");
+ }
+ } else {
+ DefineStd(Builder, "i386", Opts);
+ }
+
+ // Subtarget options.
+ // FIXME: We are hard-coding the tune parameters based on the CPU, but they
+ // truly should be based on -mtune options.
+ switch (CPU) {
+ case CK_Generic:
+ break;
+ case CK_i386:
+ // The rest are coming from the i386 define above.
+ Builder.defineMacro("__tune_i386__");
+ break;
+ case CK_i486:
+ case CK_WinChipC6:
+ case CK_WinChip2:
+ case CK_C3:
+ defineCPUMacros(Builder, "i486");
+ break;
+ case CK_PentiumMMX:
+ Builder.defineMacro("__pentium_mmx__");
+ Builder.defineMacro("__tune_pentium_mmx__");
+ LLVM_FALLTHROUGH;
+ case CK_i586:
+ case CK_Pentium:
+ defineCPUMacros(Builder, "i586");
+ defineCPUMacros(Builder, "pentium");
+ break;
+ case CK_Pentium3:
+ case CK_PentiumM:
+ Builder.defineMacro("__tune_pentium3__");
+ LLVM_FALLTHROUGH;
+ case CK_Pentium2:
+ case CK_C3_2:
+ Builder.defineMacro("__tune_pentium2__");
+ LLVM_FALLTHROUGH;
+ case CK_PentiumPro:
+ defineCPUMacros(Builder, "i686");
+ defineCPUMacros(Builder, "pentiumpro");
+ break;
+ case CK_Pentium4:
+ defineCPUMacros(Builder, "pentium4");
+ break;
+ case CK_Yonah:
+ case CK_Prescott:
+ case CK_Nocona:
+ defineCPUMacros(Builder, "nocona");
+ break;
+ case CK_Core2:
+ case CK_Penryn:
+ defineCPUMacros(Builder, "core2");
+ break;
+ case CK_Bonnell:
+ defineCPUMacros(Builder, "atom");
+ break;
+ case CK_Silvermont:
+ defineCPUMacros(Builder, "slm");
+ break;
+ case CK_Goldmont:
+ defineCPUMacros(Builder, "goldmont");
+ break;
+ case CK_Nehalem:
+ case CK_Westmere:
+ case CK_SandyBridge:
+ case CK_IvyBridge:
+ case CK_Haswell:
+ case CK_Broadwell:
+ case CK_SkylakeClient:
+ // FIXME: Historically, we defined this legacy name, it would be nice to
+ // remove it at some point. We've never exposed fine-grained names for
+ // recent primary x86 CPUs, and we should keep it that way.
+ defineCPUMacros(Builder, "corei7");
+ break;
+ case CK_SkylakeServer:
+ defineCPUMacros(Builder, "skx");
+ break;
+ case CK_Cannonlake:
+ break;
+ case CK_KNL:
+ defineCPUMacros(Builder, "knl");
+ break;
+ case CK_KNM:
+ break;
+ case CK_Lakemont:
+ defineCPUMacros(Builder, "i586", /*Tuning*/false);
+ defineCPUMacros(Builder, "pentium", /*Tuning*/false);
+ Builder.defineMacro("__tune_lakemont__");
+ break;
+ case CK_K6_2:
+ Builder.defineMacro("__k6_2__");
+ Builder.defineMacro("__tune_k6_2__");
+ LLVM_FALLTHROUGH;
+ case CK_K6_3:
+ if (CPU != CK_K6_2) { // In case of fallthrough
+ // FIXME: GCC may be enabling these in cases where some other k6
+ // architecture is specified but -m3dnow is explicitly provided. The
+ // exact semantics need to be determined and emulated here.
+ Builder.defineMacro("__k6_3__");
+ Builder.defineMacro("__tune_k6_3__");
+ }
+ LLVM_FALLTHROUGH;
+ case CK_K6:
+ defineCPUMacros(Builder, "k6");
+ break;
+ case CK_Athlon:
+ case CK_AthlonXP:
+ defineCPUMacros(Builder, "athlon");
+ if (SSELevel != NoSSE) {
+ Builder.defineMacro("__athlon_sse__");
+ Builder.defineMacro("__tune_athlon_sse__");
+ }
+ break;
+ case CK_K8:
+ case CK_K8SSE3:
+ case CK_x86_64:
+ defineCPUMacros(Builder, "k8");
+ break;
+ case CK_AMDFAM10:
+ defineCPUMacros(Builder, "amdfam10");
+ break;
+ case CK_BTVER1:
+ defineCPUMacros(Builder, "btver1");
+ break;
+ case CK_BTVER2:
+ defineCPUMacros(Builder, "btver2");
+ break;
+ case CK_BDVER1:
+ defineCPUMacros(Builder, "bdver1");
+ break;
+ case CK_BDVER2:
+ defineCPUMacros(Builder, "bdver2");
+ break;
+ case CK_BDVER3:
+ defineCPUMacros(Builder, "bdver3");
+ break;
+ case CK_BDVER4:
+ defineCPUMacros(Builder, "bdver4");
+ break;
+ case CK_ZNVER1:
+ defineCPUMacros(Builder, "znver1");
+ break;
+ case CK_Geode:
+ defineCPUMacros(Builder, "geode");
+ break;
+ }
+
+ // Target properties.
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+
+ // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
+ // functions in glibc header files that use FP Stack inline asm which the
+ // backend can't deal with (PR879).
+ Builder.defineMacro("__NO_MATH_INLINES");
+
+ if (HasAES)
+ Builder.defineMacro("__AES__");
+
+ if (HasPCLMUL)
+ Builder.defineMacro("__PCLMUL__");
+
+ if (HasLZCNT)
+ Builder.defineMacro("__LZCNT__");
+
+ if (HasRDRND)
+ Builder.defineMacro("__RDRND__");
+
+ if (HasFSGSBASE)
+ Builder.defineMacro("__FSGSBASE__");
+
+ if (HasBMI)
+ Builder.defineMacro("__BMI__");
+
+ if (HasBMI2)
+ Builder.defineMacro("__BMI2__");
+
+ if (HasPOPCNT)
+ Builder.defineMacro("__POPCNT__");
+
+ if (HasRTM)
+ Builder.defineMacro("__RTM__");
+
+ if (HasPRFCHW)
+ Builder.defineMacro("__PRFCHW__");
+
+ if (HasRDSEED)
+ Builder.defineMacro("__RDSEED__");
+
+ if (HasADX)
+ Builder.defineMacro("__ADX__");
+
+ if (HasTBM)
+ Builder.defineMacro("__TBM__");
+
+ if (HasLWP)
+ Builder.defineMacro("__LWP__");
+
+ if (HasMWAITX)
+ Builder.defineMacro("__MWAITX__");
+
+ switch (XOPLevel) {
+ case XOP:
+ Builder.defineMacro("__XOP__");
+ LLVM_FALLTHROUGH;
+ case FMA4:
+ Builder.defineMacro("__FMA4__");
+ LLVM_FALLTHROUGH;
+ case SSE4A:
+ Builder.defineMacro("__SSE4A__");
+ LLVM_FALLTHROUGH;
+ case NoXOP:
+ break;
+ }
+
+ if (HasFMA)
+ Builder.defineMacro("__FMA__");
+
+ if (HasF16C)
+ Builder.defineMacro("__F16C__");
+
+ if (HasAVX512CD)
+ Builder.defineMacro("__AVX512CD__");
+ if (HasAVX512VPOPCNTDQ)
+ Builder.defineMacro("__AVX512VPOPCNTDQ__");
+ if (HasAVX512ER)
+ Builder.defineMacro("__AVX512ER__");
+ if (HasAVX512PF)
+ Builder.defineMacro("__AVX512PF__");
+ if (HasAVX512DQ)
+ Builder.defineMacro("__AVX512DQ__");
+ if (HasAVX512BW)
+ Builder.defineMacro("__AVX512BW__");
+ if (HasAVX512VL)
+ Builder.defineMacro("__AVX512VL__");
+ if (HasAVX512VBMI)
+ Builder.defineMacro("__AVX512VBMI__");
+ if (HasAVX512IFMA)
+ Builder.defineMacro("__AVX512IFMA__");
+
+ if (HasSHA)
+ Builder.defineMacro("__SHA__");
+
+ if (HasFXSR)
+ Builder.defineMacro("__FXSR__");
+ if (HasXSAVE)
+ Builder.defineMacro("__XSAVE__");
+ if (HasXSAVEOPT)
+ Builder.defineMacro("__XSAVEOPT__");
+ if (HasXSAVEC)
+ Builder.defineMacro("__XSAVEC__");
+ if (HasXSAVES)
+ Builder.defineMacro("__XSAVES__");
+ if (HasPKU)
+ Builder.defineMacro("__PKU__");
+ if (HasCX16)
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16");
+ if (HasCLFLUSHOPT)
+ Builder.defineMacro("__CLFLUSHOPT__");
+ if (HasCLWB)
+ Builder.defineMacro("__CLWB__");
+ if (HasMPX)
+ Builder.defineMacro("__MPX__");
+ if (HasSGX)
+ Builder.defineMacro("__SGX__");
+ if (HasPREFETCHWT1)
+ Builder.defineMacro("__PREFETCHWT1__");
+ if (HasCLZERO)
+ Builder.defineMacro("__CLZERO__");
+
+ // Each case falls through to the previous one here.
+ switch (SSELevel) {
+ case AVX512F:
+ Builder.defineMacro("__AVX512F__");
+ LLVM_FALLTHROUGH;
+ case AVX2:
+ Builder.defineMacro("__AVX2__");
+ LLVM_FALLTHROUGH;
+ case AVX:
+ Builder.defineMacro("__AVX__");
+ LLVM_FALLTHROUGH;
+ case SSE42:
+ Builder.defineMacro("__SSE4_2__");
+ LLVM_FALLTHROUGH;
+ case SSE41:
+ Builder.defineMacro("__SSE4_1__");
+ LLVM_FALLTHROUGH;
+ case SSSE3:
+ Builder.defineMacro("__SSSE3__");
+ LLVM_FALLTHROUGH;
+ case SSE3:
+ Builder.defineMacro("__SSE3__");
+ LLVM_FALLTHROUGH;
+ case SSE2:
+ Builder.defineMacro("__SSE2__");
+ Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
+ LLVM_FALLTHROUGH;
+ case SSE1:
+ Builder.defineMacro("__SSE__");
+ Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
+ LLVM_FALLTHROUGH;
+ case NoSSE:
+ break;
+ }
+
+ if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) {
+ switch (SSELevel) {
+ case AVX512F:
+ case AVX2:
+ case AVX:
+ case SSE42:
+ case SSE41:
+ case SSSE3:
+ case SSE3:
+ case SSE2:
+ Builder.defineMacro("_M_IX86_FP", Twine(2));
+ break;
+ case SSE1:
+ Builder.defineMacro("_M_IX86_FP", Twine(1));
+ break;
+ default:
+ Builder.defineMacro("_M_IX86_FP", Twine(0));
+ break;
+ }
+ }
+
+ // Each case falls through to the previous one here.
+ switch (MMX3DNowLevel) {
+ case AMD3DNowAthlon:
+ Builder.defineMacro("__3dNOW_A__");
+ LLVM_FALLTHROUGH;
+ case AMD3DNow:
+ Builder.defineMacro("__3dNOW__");
+ LLVM_FALLTHROUGH;
+ case MMX:
+ Builder.defineMacro("__MMX__");
+ LLVM_FALLTHROUGH;
+ case NoMMX3DNow:
+ break;
+ }
+
+ if (CPU >= CK_i486) {
+ 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");
+ }
+ if (CPU >= CK_i586)
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+
+ if (HasFloat128)
+ Builder.defineMacro("__SIZEOF_FLOAT128__", "16");
+}
+
+bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
+ return llvm::StringSwitch<bool>(Name)
+ .Case("aes", true)
+ .Case("avx", true)
+ .Case("avx2", true)
+ .Case("avx512f", true)
+ .Case("avx512cd", true)
+ .Case("avx512vpopcntdq", true)
+ .Case("avx512er", true)
+ .Case("avx512pf", true)
+ .Case("avx512dq", true)
+ .Case("avx512bw", true)
+ .Case("avx512vl", true)
+ .Case("avx512vbmi", true)
+ .Case("avx512ifma", true)
+ .Case("bmi", true)
+ .Case("bmi2", true)
+ .Case("clflushopt", true)
+ .Case("clwb", true)
+ .Case("clzero", true)
+ .Case("cx16", true)
+ .Case("f16c", true)
+ .Case("fma", true)
+ .Case("fma4", true)
+ .Case("fsgsbase", true)
+ .Case("fxsr", true)
+ .Case("lwp", true)
+ .Case("lzcnt", true)
+ .Case("mm3dnow", true)
+ .Case("mm3dnowa", true)
+ .Case("mmx", true)
+ .Case("movbe", true)
+ .Case("mpx", true)
+ .Case("pclmul", true)
+ .Case("pku", true)
+ .Case("popcnt", true)
+ .Case("prefetchwt1", true)
+ .Case("prfchw", true)
+ .Case("rdrnd", true)
+ .Case("rdseed", true)
+ .Case("rtm", true)
+ .Case("sgx", true)
+ .Case("sha", true)
+ .Case("sse", true)
+ .Case("sse2", true)
+ .Case("sse3", true)
+ .Case("ssse3", true)
+ .Case("sse4", true)
+ .Case("sse4.1", true)
+ .Case("sse4.2", true)
+ .Case("sse4a", true)
+ .Case("tbm", true)
+ .Case("x87", true)
+ .Case("xop", true)
+ .Case("xsave", true)
+ .Case("xsavec", true)
+ .Case("xsaves", true)
+ .Case("xsaveopt", true)
+ .Default(false);
+}
+
+bool X86TargetInfo::hasFeature(StringRef Feature) const {
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("aes", HasAES)
+ .Case("avx", SSELevel >= AVX)
+ .Case("avx2", SSELevel >= AVX2)
+ .Case("avx512f", SSELevel >= AVX512F)
+ .Case("avx512cd", HasAVX512CD)
+ .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ)
+ .Case("avx512er", HasAVX512ER)
+ .Case("avx512pf", HasAVX512PF)
+ .Case("avx512dq", HasAVX512DQ)
+ .Case("avx512bw", HasAVX512BW)
+ .Case("avx512vl", HasAVX512VL)
+ .Case("avx512vbmi", HasAVX512VBMI)
+ .Case("avx512ifma", HasAVX512IFMA)
+ .Case("bmi", HasBMI)
+ .Case("bmi2", HasBMI2)
+ .Case("clflushopt", HasCLFLUSHOPT)
+ .Case("clwb", HasCLWB)
+ .Case("clzero", HasCLZERO)
+ .Case("cx16", HasCX16)
+ .Case("f16c", HasF16C)
+ .Case("fma", HasFMA)
+ .Case("fma4", XOPLevel >= FMA4)
+ .Case("fsgsbase", HasFSGSBASE)
+ .Case("fxsr", HasFXSR)
+ .Case("lwp", HasLWP)
+ .Case("lzcnt", HasLZCNT)
+ .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow)
+ .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon)
+ .Case("mmx", MMX3DNowLevel >= MMX)
+ .Case("movbe", HasMOVBE)
+ .Case("mpx", HasMPX)
+ .Case("pclmul", HasPCLMUL)
+ .Case("pku", HasPKU)
+ .Case("popcnt", HasPOPCNT)
+ .Case("prefetchwt1", HasPREFETCHWT1)
+ .Case("prfchw", HasPRFCHW)
+ .Case("rdrnd", HasRDRND)
+ .Case("rdseed", HasRDSEED)
+ .Case("rtm", HasRTM)
+ .Case("sgx", HasSGX)
+ .Case("sha", HasSHA)
+ .Case("sse", SSELevel >= SSE1)
+ .Case("sse2", SSELevel >= SSE2)
+ .Case("sse3", SSELevel >= SSE3)
+ .Case("ssse3", SSELevel >= SSSE3)
+ .Case("sse4.1", SSELevel >= SSE41)
+ .Case("sse4.2", SSELevel >= SSE42)
+ .Case("sse4a", XOPLevel >= SSE4A)
+ .Case("tbm", HasTBM)
+ .Case("x86", true)
+ .Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
+ .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
+ .Case("xop", XOPLevel >= XOP)
+ .Case("xsave", HasXSAVE)
+ .Case("xsavec", HasXSAVEC)
+ .Case("xsaves", HasXSAVES)
+ .Case("xsaveopt", HasXSAVEOPT)
+ .Default(false);
+}
+
+// We can't use a generic validation scheme for the features accepted here
+// versus subtarget features accepted in the target attribute because the
+// bitfield structure that's initialized in the runtime only supports the
+// below currently rather than the full range of subtarget features. (See
+// X86TargetInfo::hasFeature for a somewhat comprehensive list).
+bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
+ return llvm::StringSwitch<bool>(FeatureStr)
+ .Case("cmov", true)
+ .Case("mmx", true)
+ .Case("popcnt", true)
+ .Case("sse", true)
+ .Case("sse2", true)
+ .Case("sse3", true)
+ .Case("ssse3", true)
+ .Case("sse4.1", true)
+ .Case("sse4.2", true)
+ .Case("avx", true)
+ .Case("avx2", true)
+ .Case("sse4a", true)
+ .Case("fma4", true)
+ .Case("xop", true)
+ .Case("fma", true)
+ .Case("avx512f", true)
+ .Case("bmi", true)
+ .Case("bmi2", true)
+ .Case("aes", true)
+ .Case("pclmul", true)
+ .Case("avx512vl", true)
+ .Case("avx512bw", true)
+ .Case("avx512dq", true)
+ .Case("avx512cd", true)
+ .Case("avx512er", true)
+ .Case("avx512pf", true)
+ .Case("avx512vbmi", true)
+ .Case("avx512ifma", true)
+ .Case("avx5124vnniw", true)
+ .Case("avx5124fmaps", true)
+ .Case("avx512vpopcntdq", true)
+ .Default(false);
+}
+
+// We can't use a generic validation scheme for the cpus accepted here
+// versus subtarget cpus accepted in the target attribute because the
+// variables intitialized by the runtime only support the below currently
+// rather than the full range of cpus.
+bool X86TargetInfo::validateCpuIs(StringRef FeatureStr) const {
+ return llvm::StringSwitch<bool>(FeatureStr)
+ .Case("amd", true)
+ .Case("amdfam10h", true)
+ .Case("amdfam15h", true)
+ .Case("amdfam17h", true)
+ .Case("atom", true)
+ .Case("barcelona", true)
+ .Case("bdver1", true)
+ .Case("bdver2", true)
+ .Case("bdver3", true)
+ .Case("bdver4", true)
+ .Case("bonnell", true)
+ .Case("broadwell", true)
+ .Case("btver1", true)
+ .Case("btver2", true)
+ .Case("core2", true)
+ .Case("corei7", true)
+ .Case("haswell", true)
+ .Case("intel", true)
+ .Case("istanbul", true)
+ .Case("ivybridge", true)
+ .Case("knl", true)
+ .Case("nehalem", true)
+ .Case("sandybridge", true)
+ .Case("shanghai", true)
+ .Case("silvermont", true)
+ .Case("skylake", true)
+ .Case("skylake-avx512", true)
+ .Case("slm", true)
+ .Case("westmere", true)
+ .Case("znver1", true)
+ .Default(false);
+}
+
+bool X86TargetInfo::validateAsmConstraint(
+ const char *&Name, TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ return false;
+ // Constant constraints.
+ case 'e': // 32-bit signed integer constant for use with sign-extending x86_64
+ // instructions.
+ case 'Z': // 32-bit unsigned integer constant for use with zero-extending
+ // x86_64 instructions.
+ case 's':
+ Info.setRequiresImmediate();
+ return true;
+ case 'I':
+ Info.setRequiresImmediate(0, 31);
+ return true;
+ case 'J':
+ Info.setRequiresImmediate(0, 63);
+ return true;
+ case 'K':
+ Info.setRequiresImmediate(-128, 127);
+ return true;
+ case 'L':
+ Info.setRequiresImmediate({int(0xff), int(0xffff), int(0xffffffff)});
+ return true;
+ case 'M':
+ Info.setRequiresImmediate(0, 3);
+ return true;
+ case 'N':
+ Info.setRequiresImmediate(0, 255);
+ return true;
+ case 'O':
+ Info.setRequiresImmediate(0, 127);
+ return true;
+ // Register constraints.
+ case 'Y': // 'Y' is the first character for several 2-character constraints.
+ // Shift the pointer to the second character of the constraint.
+ Name++;
+ switch (*Name) {
+ default:
+ return false;
+ case 'z':
+ case '0': // First SSE register.
+ case '2':
+ case 't': // Any SSE register, when SSE2 is enabled.
+ case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled.
+ case 'm': // Any MMX register, when inter-unit moves enabled.
+ case 'k': // AVX512 arch mask registers: k1-k7.
+ Info.setAllowsRegister();
+ return true;
+ }
+ case 'f': // Any x87 floating point stack register.
+ // Constraint 'f' cannot be used for output operands.
+ if (Info.ConstraintStr[0] == '=')
+ return false;
+ Info.setAllowsRegister();
+ return true;
+ case 'a': // eax.
+ case 'b': // ebx.
+ case 'c': // ecx.
+ case 'd': // edx.
+ case 'S': // esi.
+ case 'D': // edi.
+ case 'A': // edx:eax.
+ case 't': // Top of floating point stack.
+ case 'u': // Second from top of floating point stack.
+ case 'q': // Any register accessible as [r]l: a, b, c, and d.
+ case 'y': // Any MMX register.
+ case 'v': // Any {X,Y,Z}MM register (Arch & context dependent)
+ case 'x': // Any SSE register.
+ case 'k': // Any AVX512 mask register (same as Yk, additionaly allows k0
+ // for intermideate k reg operations).
+ case 'Q': // Any register accessible as [r]h: a, b, c, and d.
+ case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp.
+ case 'l': // "Index" registers: any general register that can be used as an
+ // index in a base+index memory access.
+ Info.setAllowsRegister();
+ return true;
+ // Floating point constant constraints.
+ case 'C': // SSE floating point constant.
+ case 'G': // x87 floating point constant.
+ return true;
+ }
+}
+
+bool X86TargetInfo::validateOutputSize(StringRef Constraint,
+ unsigned Size) const {
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
+
+ return validateOperandSize(Constraint, Size);
+}
+
+bool X86TargetInfo::validateInputSize(StringRef Constraint,
+ unsigned Size) const {
+ return validateOperandSize(Constraint, Size);
+}
+
+bool X86TargetInfo::validateOperandSize(StringRef Constraint,
+ unsigned Size) const {
+ switch (Constraint[0]) {
+ default:
+ break;
+ case 'k':
+ // Registers k0-k7 (AVX512) size limit is 64 bit.
+ case 'y':
+ return Size <= 64;
+ case 'f':
+ case 't':
+ case 'u':
+ return Size <= 128;
+ case 'Y':
+ // 'Y' is the first character for several 2-character constraints.
+ switch (Constraint[1]) {
+ default:
+ return false;
+ case 'm':
+ // 'Ym' is synonymous with 'y'.
+ case 'k':
+ return Size <= 64;
+ case 'z':
+ case '0':
+ // XMM0
+ if (SSELevel >= SSE1)
+ return Size <= 128U;
+ return false;
+ case 'i':
+ case 't':
+ case '2':
+ // 'Yi','Yt','Y2' are synonymous with 'x' when SSE2 is enabled.
+ if (SSELevel < SSE2)
+ return false;
+ break;
+ }
+ case 'v':
+ case 'x':
+ if (SSELevel >= AVX512F)
+ // 512-bit zmm registers can be used if target supports AVX512F.
+ return Size <= 512U;
+ else if (SSELevel >= AVX)
+ // 256-bit ymm registers can be used if target supports AVX.
+ return Size <= 256U;
+ return Size <= 128U;
+
+ }
+
+ return true;
+}
+
+std::string X86TargetInfo::convertConstraint(const char *&Constraint) const {
+ switch (*Constraint) {
+ case 'a':
+ return std::string("{ax}");
+ case 'b':
+ return std::string("{bx}");
+ case 'c':
+ return std::string("{cx}");
+ case 'd':
+ return std::string("{dx}");
+ case 'S':
+ return std::string("{si}");
+ case 'D':
+ return std::string("{di}");
+ case 'p': // address
+ return std::string("im");
+ case 't': // top of floating point stack.
+ return std::string("{st}");
+ case 'u': // second from top of floating point stack.
+ return std::string("{st(1)}"); // second from top of floating point stack.
+ case 'Y':
+ switch (Constraint[1]) {
+ default:
+ // Break from inner switch and fall through (copy single char),
+ // continue parsing after copying the current constraint into
+ // the return string.
+ break;
+ case 'k':
+ case 'm':
+ case 'i':
+ case 't':
+ case 'z':
+ case '0':
+ case '2':
+ // "^" hints llvm that this is a 2 letter constraint.
+ // "Constraint++" is used to promote the string iterator
+ // to the next constraint.
+ return std::string("^") + std::string(Constraint++, 2);
+ }
+ LLVM_FALLTHROUGH;
+ default:
+ return std::string(1, *Constraint);
+ }
+}
+
+bool X86TargetInfo::checkCPUKind(CPUKind Kind) const {
+ // Perform any per-CPU checks necessary to determine if this CPU is
+ // acceptable.
+ // FIXME: This results in terrible diagnostics. Clang just says the CPU is
+ // invalid without explaining *why*.
+ switch (Kind) {
+ case CK_Generic:
+ // No processor selected!
+ return false;
+
+ case CK_i386:
+ case CK_i486:
+ case CK_WinChipC6:
+ case CK_WinChip2:
+ case CK_C3:
+ case CK_i586:
+ case CK_Pentium:
+ case CK_PentiumMMX:
+ case CK_PentiumPro:
+ case CK_Pentium2:
+ case CK_Pentium3:
+ case CK_PentiumM:
+ case CK_Yonah:
+ case CK_C3_2:
+ case CK_Pentium4:
+ case CK_Lakemont:
+ case CK_Prescott:
+ case CK_K6:
+ case CK_K6_2:
+ case CK_K6_3:
+ case CK_Athlon:
+ case CK_AthlonXP:
+ case CK_Geode:
+ // Only accept certain architectures when compiling in 32-bit mode.
+ if (getTriple().getArch() != llvm::Triple::x86)
+ return false;
+
+ LLVM_FALLTHROUGH;
+ case CK_Nocona:
+ case CK_Core2:
+ case CK_Penryn:
+ case CK_Bonnell:
+ case CK_Silvermont:
+ case CK_Goldmont:
+ case CK_Nehalem:
+ case CK_Westmere:
+ case CK_SandyBridge:
+ case CK_IvyBridge:
+ case CK_Haswell:
+ case CK_Broadwell:
+ case CK_SkylakeClient:
+ case CK_SkylakeServer:
+ case CK_Cannonlake:
+ case CK_KNL:
+ case CK_KNM:
+ case CK_K8:
+ case CK_K8SSE3:
+ case CK_AMDFAM10:
+ case CK_BTVER1:
+ case CK_BTVER2:
+ case CK_BDVER1:
+ case CK_BDVER2:
+ case CK_BDVER3:
+ case CK_BDVER4:
+ case CK_ZNVER1:
+ case CK_x86_64:
+ return true;
+ }
+ llvm_unreachable("Unhandled CPU kind");
+}
+
+X86TargetInfo::CPUKind X86TargetInfo::getCPUKind(StringRef CPU) const {
+ return llvm::StringSwitch<CPUKind>(CPU)
+ .Case("i386", CK_i386)
+ .Case("i486", CK_i486)
+ .Case("winchip-c6", CK_WinChipC6)
+ .Case("winchip2", CK_WinChip2)
+ .Case("c3", CK_C3)
+ .Case("i586", CK_i586)
+ .Case("pentium", CK_Pentium)
+ .Case("pentium-mmx", CK_PentiumMMX)
+ .Cases("i686", "pentiumpro", CK_PentiumPro)
+ .Case("pentium2", CK_Pentium2)
+ .Cases("pentium3", "pentium3m", CK_Pentium3)
+ .Case("pentium-m", CK_PentiumM)
+ .Case("c3-2", CK_C3_2)
+ .Case("yonah", CK_Yonah)
+ .Cases("pentium4", "pentium4m", CK_Pentium4)
+ .Case("prescott", CK_Prescott)
+ .Case("nocona", CK_Nocona)
+ .Case("core2", CK_Core2)
+ .Case("penryn", CK_Penryn)
+ .Cases("bonnell", "atom", CK_Bonnell)
+ .Cases("silvermont", "slm", CK_Silvermont)
+ .Case("goldmont", CK_Goldmont)
+ .Cases("nehalem", "corei7", CK_Nehalem)
+ .Case("westmere", CK_Westmere)
+ .Cases("sandybridge", "corei7-avx", CK_SandyBridge)
+ .Cases("ivybridge", "core-avx-i", CK_IvyBridge)
+ .Cases("haswell", "core-avx2", CK_Haswell)
+ .Case("broadwell", CK_Broadwell)
+ .Case("skylake", CK_SkylakeClient)
+ .Cases("skylake-avx512", "skx", CK_SkylakeServer)
+ .Case("cannonlake", CK_Cannonlake)
+ .Case("knl", CK_KNL)
+ .Case("knm", CK_KNM)
+ .Case("lakemont", CK_Lakemont)
+ .Case("k6", CK_K6)
+ .Case("k6-2", CK_K6_2)
+ .Case("k6-3", CK_K6_3)
+ .Cases("athlon", "athlon-tbird", CK_Athlon)
+ .Cases("athlon-xp", "athlon-mp", "athlon-4", CK_AthlonXP)
+ .Cases("k8", "athlon64", "athlon-fx", "opteron", CK_K8)
+ .Cases("k8-sse3", "athlon64-sse3", "opteron-sse3", CK_K8SSE3)
+ .Cases("amdfam10", "barcelona", CK_AMDFAM10)
+ .Case("btver1", CK_BTVER1)
+ .Case("btver2", CK_BTVER2)
+ .Case("bdver1", CK_BDVER1)
+ .Case("bdver2", CK_BDVER2)
+ .Case("bdver3", CK_BDVER3)
+ .Case("bdver4", CK_BDVER4)
+ .Case("znver1", CK_ZNVER1)
+ .Case("x86-64", CK_x86_64)
+ .Case("geode", CK_Geode)
+ .Default(CK_Generic);
+}
+
+ArrayRef<const char *> X86TargetInfo::getGCCRegNames() const {
+ return llvm::makeArrayRef(GCCRegNames);
+}
+
+ArrayRef<TargetInfo::AddlRegName> X86TargetInfo::getGCCAddlRegNames() const {
+ return llvm::makeArrayRef(AddlRegNames);
+}
+
+ArrayRef<Builtin::Info> X86_32TargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin -
+ Builtin::FirstTSBuiltin + 1);
+}
+
+ArrayRef<Builtin::Info> X86_64TargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfoX86,
+ X86::LastTSBuiltin - Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/X86.h b/lib/Basic/Targets/X86.h
new file mode 100644
index 0000000000..b86497f17b
--- /dev/null
+++ b/lib/Basic/Targets/X86.h
@@ -0,0 +1,995 @@
+//===--- X86.h - Declare X86 target feature support -------------*- 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 X86 TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_X86_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_X86_H
+
+#include "OSTargets.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+// X86 target abstract base class; x86-32 and x86-64 are very close, so
+// most of the implementation can be shared.
+class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
+
+ enum X86SSEEnum {
+ NoSSE,
+ SSE1,
+ SSE2,
+ SSE3,
+ SSSE3,
+ SSE41,
+ SSE42,
+ AVX,
+ AVX2,
+ AVX512F
+ } SSELevel = NoSSE;
+ enum MMX3DNowEnum {
+ NoMMX3DNow,
+ MMX,
+ AMD3DNow,
+ AMD3DNowAthlon
+ } MMX3DNowLevel = NoMMX3DNow;
+ enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP;
+
+ bool HasAES = false;
+ bool HasPCLMUL = false;
+ bool HasLZCNT = false;
+ bool HasRDRND = false;
+ bool HasFSGSBASE = false;
+ bool HasBMI = false;
+ bool HasBMI2 = false;
+ bool HasPOPCNT = false;
+ bool HasRTM = false;
+ bool HasPRFCHW = false;
+ bool HasRDSEED = false;
+ bool HasADX = false;
+ bool HasTBM = false;
+ bool HasLWP = false;
+ bool HasFMA = false;
+ bool HasF16C = false;
+ bool HasAVX512CD = false;
+ bool HasAVX512VPOPCNTDQ = false;
+ bool HasAVX512ER = false;
+ bool HasAVX512PF = false;
+ bool HasAVX512DQ = false;
+ bool HasAVX512BW = false;
+ bool HasAVX512VL = false;
+ bool HasAVX512VBMI = false;
+ bool HasAVX512IFMA = false;
+ bool HasSHA = false;
+ bool HasMPX = false;
+ bool HasSGX = false;
+ bool HasCX16 = false;
+ bool HasFXSR = false;
+ bool HasXSAVE = false;
+ bool HasXSAVEOPT = false;
+ bool HasXSAVEC = false;
+ bool HasXSAVES = false;
+ bool HasMWAITX = false;
+ bool HasCLZERO = false;
+ bool HasPKU = false;
+ bool HasCLFLUSHOPT = false;
+ bool HasCLWB = false;
+ bool HasMOVBE = false;
+ bool HasPREFETCHWT1 = false;
+
+ /// \brief Enumeration of all of the X86 CPUs supported by Clang.
+ ///
+ /// Each enumeration represents a particular CPU supported by Clang. These
+ /// loosely correspond to the options passed to '-march' or '-mtune' flags.
+ enum CPUKind {
+ CK_Generic,
+
+ /// \name i386
+ /// i386-generation processors.
+ //@{
+ CK_i386,
+ //@}
+
+ /// \name i486
+ /// i486-generation processors.
+ //@{
+ CK_i486,
+ CK_WinChipC6,
+ CK_WinChip2,
+ CK_C3,
+ //@}
+
+ /// \name i586
+ /// i586-generation processors, P5 microarchitecture based.
+ //@{
+ CK_i586,
+ CK_Pentium,
+ CK_PentiumMMX,
+ //@}
+
+ /// \name i686
+ /// i686-generation processors, P6 / Pentium M microarchitecture based.
+ //@{
+ CK_PentiumPro,
+ CK_Pentium2,
+ CK_Pentium3,
+ CK_PentiumM,
+ CK_C3_2,
+
+ /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah.
+ /// Clang however has some logic to support this.
+ // FIXME: Warn, deprecate, and potentially remove this.
+ CK_Yonah,
+ //@}
+
+ /// \name Netburst
+ /// Netburst microarchitecture based processors.
+ //@{
+ CK_Pentium4,
+ CK_Prescott,
+ CK_Nocona,
+ //@}
+
+ /// \name Core
+ /// Core microarchitecture based processors.
+ //@{
+ CK_Core2,
+
+ /// This enumerator, like \see CK_Yonah, is a bit odd. It is another
+ /// codename which GCC no longer accepts as an option to -march, but Clang
+ /// has some logic for recognizing it.
+ // FIXME: Warn, deprecate, and potentially remove this.
+ CK_Penryn,
+ //@}
+
+ /// \name Atom
+ /// Atom processors
+ //@{
+ CK_Bonnell,
+ CK_Silvermont,
+ CK_Goldmont,
+ //@}
+
+ /// \name Nehalem
+ /// Nehalem microarchitecture based processors.
+ CK_Nehalem,
+
+ /// \name Westmere
+ /// Westmere microarchitecture based processors.
+ CK_Westmere,
+
+ /// \name Sandy Bridge
+ /// Sandy Bridge microarchitecture based processors.
+ CK_SandyBridge,
+
+ /// \name Ivy Bridge
+ /// Ivy Bridge microarchitecture based processors.
+ CK_IvyBridge,
+
+ /// \name Haswell
+ /// Haswell microarchitecture based processors.
+ CK_Haswell,
+
+ /// \name Broadwell
+ /// Broadwell microarchitecture based processors.
+ CK_Broadwell,
+
+ /// \name Skylake Client
+ /// Skylake client microarchitecture based processors.
+ CK_SkylakeClient,
+
+ /// \name Skylake Server
+ /// Skylake server microarchitecture based processors.
+ CK_SkylakeServer,
+
+ /// \name Cannonlake Client
+ /// Cannonlake client microarchitecture based processors.
+ CK_Cannonlake,
+
+ /// \name Knights Landing
+ /// Knights Landing processor.
+ CK_KNL,
+
+ /// \name Knights Mill
+ /// Knights Mill processor.
+ CK_KNM,
+
+ /// \name Lakemont
+ /// Lakemont microarchitecture based processors.
+ CK_Lakemont,
+
+ /// \name K6
+ /// K6 architecture processors.
+ //@{
+ CK_K6,
+ CK_K6_2,
+ CK_K6_3,
+ //@}
+
+ /// \name K7
+ /// K7 architecture processors.
+ //@{
+ CK_Athlon,
+ CK_AthlonXP,
+ //@}
+
+ /// \name K8
+ /// K8 architecture processors.
+ //@{
+ CK_K8,
+ CK_K8SSE3,
+ CK_AMDFAM10,
+ //@}
+
+ /// \name Bobcat
+ /// Bobcat architecture processors.
+ //@{
+ CK_BTVER1,
+ CK_BTVER2,
+ //@}
+
+ /// \name Bulldozer
+ /// Bulldozer architecture processors.
+ //@{
+ CK_BDVER1,
+ CK_BDVER2,
+ CK_BDVER3,
+ CK_BDVER4,
+ //@}
+
+ /// \name zen
+ /// Zen architecture processors.
+ //@{
+ CK_ZNVER1,
+ //@}
+
+ /// This specification is deprecated and will be removed in the future.
+ /// Users should prefer \see CK_K8.
+ // FIXME: Warn on this when the CPU is set to it.
+ //@{
+ CK_x86_64,
+ //@}
+
+ /// \name Geode
+ /// Geode processors.
+ //@{
+ CK_Geode
+ //@}
+ } CPU = CK_Generic;
+
+ bool checkCPUKind(CPUKind Kind) const;
+
+ CPUKind getCPUKind(StringRef CPU) const;
+
+ enum FPMathKind { FP_Default, FP_SSE, FP_387 } FPMath = FP_Default;
+
+public:
+ X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
+ }
+
+ unsigned getFloatEvalMethod() const override {
+ // X87 evaluates with 80 bits "long double" precision.
+ return SSELevel == NoSSE ? 2 : 0;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+
+ ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override;
+
+ bool validateCpuSupports(StringRef Name) const override;
+
+ bool validateCpuIs(StringRef Name) const override;
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override;
+
+ bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
+ bool &HasSizeMismatch) const override {
+ // esp and ebp are the only 32-bit registers the x86 backend can currently
+ // handle.
+ if (RegName.equals("esp") || RegName.equals("ebp")) {
+ // Check that the register size is 32-bit.
+ HasSizeMismatch = RegSize != 32;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool validateOutputSize(StringRef Constraint, unsigned Size) const override;
+
+ bool validateInputSize(StringRef Constraint, unsigned Size) const override;
+
+ virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const;
+
+ std::string convertConstraint(const char *&Constraint) const override;
+ const char *getClobbers() const override {
+ return "~{dirflag},~{fpsr},~{flags}";
+ }
+
+ StringRef getConstraintRegister(const StringRef &Constraint,
+ const StringRef &Expression) const override {
+ StringRef::iterator I, E;
+ for (I = Constraint.begin(), E = Constraint.end(); I != E; ++I) {
+ if (isalpha(*I))
+ break;
+ }
+ if (I == E)
+ return "";
+ switch (*I) {
+ // For the register constraints, return the matching register name
+ case 'a':
+ return "ax";
+ case 'b':
+ return "bx";
+ case 'c':
+ return "cx";
+ case 'd':
+ return "dx";
+ case 'S':
+ return "si";
+ case 'D':
+ return "di";
+ // In case the constraint is 'r' we need to return Expression
+ case 'r':
+ return Expression;
+ // Double letters Y<x> constraints
+ case 'Y':
+ if ((++I != E) && ((*I == '0') || (*I == 'z')))
+ return "xmm0";
+ default:
+ break;
+ }
+ return "";
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ static void setSSELevel(llvm::StringMap<bool> &Features, X86SSEEnum Level,
+ bool Enabled);
+
+ static void setMMXLevel(llvm::StringMap<bool> &Features, MMX3DNowEnum Level,
+ bool Enabled);
+
+ static void setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
+ bool Enabled);
+
+ void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name,
+ bool Enabled) const override {
+ setFeatureEnabledImpl(Features, Name, Enabled);
+ }
+
+ // This exists purely to cut down on the number of virtual calls in
+ // initFeatureMap which calls this repeatedly.
+ static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
+ StringRef Name, bool Enabled);
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override;
+
+ bool isValidFeatureName(StringRef Name) const override;
+
+ bool hasFeature(StringRef Feature) const override;
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+
+ StringRef getABI() const override {
+ if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F)
+ return "avx512";
+ if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
+ return "avx";
+ if (getTriple().getArch() == llvm::Triple::x86 &&
+ MMX3DNowLevel == NoMMX3DNow)
+ return "no-mmx";
+ return "";
+ }
+
+ bool isValidCPUName(StringRef Name) const override {
+ return checkCPUKind(getCPUKind(Name));
+ }
+
+ bool setCPU(const std::string &Name) override {
+ return checkCPUKind(CPU = getCPUKind(Name));
+ }
+
+ bool setFPMath(StringRef Name) override;
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ // Most of the non-ARM calling conventions are i386 conventions.
+ switch (CC) {
+ case CC_X86ThisCall:
+ case CC_X86FastCall:
+ case CC_X86StdCall:
+ case CC_X86VectorCall:
+ case CC_X86RegCall:
+ case CC_C:
+ case CC_Swift:
+ case CC_X86Pascal:
+ case CC_IntelOclBicc:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+ }
+
+ CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
+ return MT == CCMT_Member ? CC_X86ThisCall : CC_C;
+ }
+
+ bool hasSjLjLowering() const override { return true; }
+
+ void setSupportedOpenCLOpts() override {
+ getSupportedOpenCLOpts().supportAll();
+ }
+};
+
+// X86-32 generic target
+class LLVM_LIBRARY_VISIBILITY X86_32TargetInfo : public X86TargetInfo {
+public:
+ X86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : X86TargetInfo(Triple, Opts) {
+ DoubleAlign = LongLongAlign = 32;
+ LongDoubleWidth = 96;
+ LongDoubleAlign = 32;
+ SuitableAlign = 128;
+ resetDataLayout("e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128");
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+ RegParmMax = 3;
+
+ // Use fpret for all types.
+ RealTypeUsesObjCFPRet =
+ ((1 << TargetInfo::Float) | (1 << TargetInfo::Double) |
+ (1 << TargetInfo::LongDouble));
+
+ // x86-32 has atomics up to 8 bytes
+ // FIXME: Check that we actually have cmpxchg8b before setting
+ // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.)
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ if (RegNo == 0)
+ return 0;
+ if (RegNo == 1)
+ return 2;
+ return -1;
+ }
+
+ bool validateOperandSize(StringRef Constraint, unsigned Size) const override {
+ switch (Constraint[0]) {
+ default:
+ break;
+ case 'R':
+ case 'q':
+ case 'Q':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'S':
+ case 'D':
+ return Size <= 32;
+ case 'A':
+ return Size <= 64;
+ }
+
+ return X86TargetInfo::validateOperandSize(Constraint, Size);
+ }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
+ : public NetBSDTargetInfo<X86_32TargetInfo> {
+public:
+ NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}
+
+ unsigned getFloatEvalMethod() const override {
+ unsigned Major, Minor, Micro;
+ getTriple().getOSVersion(Major, Minor, Micro);
+ // New NetBSD uses the default rounding mode.
+ if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 0)
+ return X86_32TargetInfo::getFloatEvalMethod();
+ // NetBSD before 6.99.26 defaults to "double" rounding.
+ return 1;
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY OpenBSDI386TargetInfo
+ : public OpenBSDTargetInfo<X86_32TargetInfo> {
+public:
+ OpenBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OpenBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ PtrDiffType = SignedLong;
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY DarwinI386TargetInfo
+ : public DarwinTargetInfo<X86_32TargetInfo> {
+public:
+ DarwinI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : DarwinTargetInfo<X86_32TargetInfo>(Triple, Opts) {
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ SuitableAlign = 128;
+ MaxVectorAlign = 256;
+ // The watchOS simulator uses the builtin bool type for Objective-C.
+ llvm::Triple T = llvm::Triple(Triple);
+ if (T.isWatchOS())
+ UseSignedCharForObjCBool = false;
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ resetDataLayout("e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128");
+ HasAlignMac68kSupport = true;
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ if (!DarwinTargetInfo<X86_32TargetInfo>::handleTargetFeatures(Features,
+ Diags))
+ return false;
+ // We now know the features we have: we can decide how to align vectors.
+ MaxVectorAlign =
+ hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
+ return true;
+ }
+};
+
+// x86-32 Windows target
+class LLVM_LIBRARY_VISIBILITY WindowsX86_32TargetInfo
+ : public WindowsTargetInfo<X86_32TargetInfo> {
+public:
+ WindowsX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : WindowsTargetInfo<X86_32TargetInfo>(Triple, Opts) {
+ DoubleAlign = LongLongAlign = 64;
+ bool IsWinCOFF =
+ getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
+ resetDataLayout(IsWinCOFF
+ ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+ : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder);
+ }
+};
+
+// x86-32 Windows Visual Studio target
+class LLVM_LIBRARY_VISIBILITY MicrosoftX86_32TargetInfo
+ : public WindowsX86_32TargetInfo {
+public:
+ MicrosoftX86_32TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsX86_32TargetInfo(Triple, Opts) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
+ WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder);
+ // The value of the following reflects processor type.
+ // 300=386, 400=486, 500=Pentium, 600=Blend (default)
+ // We lost the original triple, so we use the default.
+ Builder.defineMacro("_M_IX86", "600");
+ }
+};
+
+// x86-32 MinGW target
+class LLVM_LIBRARY_VISIBILITY MinGWX86_32TargetInfo
+ : public WindowsX86_32TargetInfo {
+public:
+ MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : WindowsX86_32TargetInfo(Triple, Opts) {
+ HasFloat128 = true;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
+ DefineStd(Builder, "WIN32", Opts);
+ DefineStd(Builder, "WINNT", Opts);
+ Builder.defineMacro("_X86_");
+ addMinGWDefines(Opts, Builder);
+ }
+};
+
+// x86-32 Cygwin target
+class LLVM_LIBRARY_VISIBILITY CygwinX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ CygwinX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : X86_32TargetInfo(Triple, Opts) {
+ this->WCharType = TargetInfo::UnsignedShort;
+ DoubleAlign = LongLongAlign = 64;
+ resetDataLayout("e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_X86_");
+ Builder.defineMacro("__CYGWIN__");
+ Builder.defineMacro("__CYGWIN32__");
+ addCygMingDefines(Opts, Builder);
+ DefineStd(Builder, "unix", Opts);
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
+};
+
+// x86-32 Haiku target
+class LLVM_LIBRARY_VISIBILITY HaikuX86_32TargetInfo
+ : public HaikuTargetInfo<X86_32TargetInfo> {
+public:
+ HaikuX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : HaikuTargetInfo<X86_32TargetInfo>(Triple, Opts) {}
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ HaikuTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__INTEL__");
+ }
+};
+
+// X86-32 MCU target
+class LLVM_LIBRARY_VISIBILITY MCUX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ MCUX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : X86_32TargetInfo(Triple, Opts) {
+ LongDoubleWidth = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ resetDataLayout("e-m:e-p:32:32-i64:32-f64:32-f128:32-n8:16:32-a:0:32-S32");
+ WIntType = UnsignedInt;
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ // On MCU we support only C calling convention.
+ return CC == CC_C ? CCCR_OK : CCCR_Warning;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__iamcu");
+ Builder.defineMacro("__iamcu__");
+ }
+
+ bool allowsLargerPreferedTypeAlignment() const override { return false; }
+};
+
+// x86-32 RTEMS target
+class LLVM_LIBRARY_VISIBILITY RTEMSX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ RTEMSX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : X86_32TargetInfo(Triple, Opts) {
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ PtrDiffType = SignedLong;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__INTEL__");
+ Builder.defineMacro("__rtems__");
+ }
+};
+
+// x86-64 generic target
+class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
+public:
+ X86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : X86TargetInfo(Triple, Opts) {
+ const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32;
+ bool IsWinCOFF =
+ getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
+ LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64;
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ LargeArrayMinWidth = 128;
+ LargeArrayAlign = 128;
+ SuitableAlign = 128;
+ SizeType = IsX32 ? UnsignedInt : UnsignedLong;
+ PtrDiffType = IsX32 ? SignedInt : SignedLong;
+ IntPtrType = IsX32 ? SignedInt : SignedLong;
+ IntMaxType = IsX32 ? SignedLongLong : SignedLong;
+ Int64Type = IsX32 ? SignedLongLong : SignedLong;
+ RegParmMax = 6;
+
+ // Pointers are 32-bit in x32.
+ resetDataLayout(IsX32
+ ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128"
+ : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+ : "e-m:e-i64:64-f80:128-n8:16:32:64-S128");
+
+ // Use fpret only for long double.
+ RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
+
+ // Use fp2ret for _Complex long double.
+ ComplexLongDoubleUsesFP2Ret = true;
+
+ // Make __builtin_ms_va_list available.
+ HasBuiltinMSVaList = true;
+
+ // x86-64 has atomics up to 16 bytes.
+ MaxAtomicPromoteWidth = 128;
+ MaxAtomicInlineWidth = 64;
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::X86_64ABIBuiltinVaList;
+ }
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ if (RegNo == 0)
+ return 0;
+ if (RegNo == 1)
+ return 1;
+ return -1;
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ case CC_C:
+ case CC_Swift:
+ case CC_X86VectorCall:
+ case CC_IntelOclBicc:
+ case CC_Win64:
+ case CC_PreserveMost:
+ case CC_PreserveAll:
+ case CC_X86RegCall:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+ }
+
+ CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
+ return CC_C;
+ }
+
+ // for x32 we need it here explicitly
+ bool hasInt128Type() const override { return true; }
+
+ unsigned getUnwindWordWidth() const override { return 64; }
+
+ unsigned getRegisterWidth() const override { return 64; }
+
+ bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
+ bool &HasSizeMismatch) const override {
+ // rsp and rbp are the only 64-bit registers the x86 backend can currently
+ // handle.
+ if (RegName.equals("rsp") || RegName.equals("rbp")) {
+ // Check that the register size is 64-bit.
+ HasSizeMismatch = RegSize != 64;
+ return true;
+ }
+
+ // Check if the register is a 32-bit register the backend can handle.
+ return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize,
+ HasSizeMismatch);
+ }
+
+ void setMaxAtomicWidth() override {
+ if (hasFeature("cx16"))
+ MaxAtomicInlineWidth = 128;
+ }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+};
+
+// x86-64 Windows target
+class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
+ : public WindowsTargetInfo<X86_64TargetInfo> {
+public:
+ WindowsX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : WindowsTargetInfo<X86_64TargetInfo>(Triple, Opts) {
+ LongWidth = LongAlign = 32;
+ DoubleAlign = LongLongAlign = 64;
+ IntMaxType = SignedLongLong;
+ Int64Type = SignedLongLong;
+ SizeType = UnsignedLongLong;
+ PtrDiffType = SignedLongLong;
+ IntPtrType = SignedLongLong;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_WIN64");
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ case CC_X86StdCall:
+ case CC_X86ThisCall:
+ case CC_X86FastCall:
+ return CCCR_Ignore;
+ case CC_C:
+ case CC_X86VectorCall:
+ case CC_IntelOclBicc:
+ case CC_PreserveMost:
+ case CC_PreserveAll:
+ case CC_X86_64SysV:
+ case CC_Swift:
+ case CC_X86RegCall:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ default:
+ return CCCR_Warning;
+ }
+ }
+};
+
+// x86-64 Windows Visual Studio target
+class LLVM_LIBRARY_VISIBILITY MicrosoftX86_64TargetInfo
+ : public WindowsX86_64TargetInfo {
+public:
+ MicrosoftX86_64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsX86_64TargetInfo(Triple, Opts) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder);
+ Builder.defineMacro("_M_X64", "100");
+ Builder.defineMacro("_M_AMD64", "100");
+ }
+};
+
+// x86-64 MinGW target
+class LLVM_LIBRARY_VISIBILITY MinGWX86_64TargetInfo
+ : public WindowsX86_64TargetInfo {
+public:
+ MinGWX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : WindowsX86_64TargetInfo(Triple, Opts) {
+ // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks
+ // with x86 FP ops. Weird.
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
+ HasFloat128 = true;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ DefineStd(Builder, "WIN64", Opts);
+ Builder.defineMacro("__MINGW64__");
+ addMinGWDefines(Opts, Builder);
+
+ // GCC defines this macro when it is using __gxx_personality_seh0.
+ if (!Opts.SjLjExceptions)
+ Builder.defineMacro("__SEH__");
+ }
+};
+
+// x86-64 Cygwin target
+class LLVM_LIBRARY_VISIBILITY CygwinX86_64TargetInfo : public X86_64TargetInfo {
+public:
+ CygwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : X86_64TargetInfo(Triple, Opts) {
+ this->WCharType = TargetInfo::UnsignedShort;
+ TLSSupported = false;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ X86_64TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__x86_64__");
+ Builder.defineMacro("__CYGWIN__");
+ Builder.defineMacro("__CYGWIN64__");
+ addCygMingDefines(Opts, Builder);
+ DefineStd(Builder, "unix", Opts);
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+
+ // GCC defines this macro when it is using __gxx_personality_seh0.
+ if (!Opts.SjLjExceptions)
+ Builder.defineMacro("__SEH__");
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY DarwinX86_64TargetInfo
+ : public DarwinTargetInfo<X86_64TargetInfo> {
+public:
+ DarwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : DarwinTargetInfo<X86_64TargetInfo>(Triple, Opts) {
+ Int64Type = SignedLongLong;
+ // The 64-bit iOS simulator uses the builtin bool type for Objective-C.
+ llvm::Triple T = llvm::Triple(Triple);
+ if (T.isiOS())
+ UseSignedCharForObjCBool = false;
+ resetDataLayout("e-m:o-i64:64-f80:128-n8:16:32:64-S128");
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ if (!DarwinTargetInfo<X86_64TargetInfo>::handleTargetFeatures(Features,
+ Diags))
+ return false;
+ // We now know the features we have: we can decide how to align vectors.
+ MaxVectorAlign =
+ hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
+ return true;
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY OpenBSDX86_64TargetInfo
+ : public OpenBSDTargetInfo<X86_64TargetInfo> {
+public:
+ OpenBSDX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OpenBSDTargetInfo<X86_64TargetInfo>(Triple, Opts) {
+ IntMaxType = SignedLongLong;
+ Int64Type = SignedLongLong;
+ }
+};
+
+// x86_32 Android target
+class LLVM_LIBRARY_VISIBILITY AndroidX86_32TargetInfo
+ : public LinuxTargetInfo<X86_32TargetInfo> {
+public:
+ AndroidX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : LinuxTargetInfo<X86_32TargetInfo>(Triple, Opts) {
+ SuitableAlign = 32;
+ LongDoubleWidth = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ }
+};
+
+// x86_64 Android target
+class LLVM_LIBRARY_VISIBILITY AndroidX86_64TargetInfo
+ : public LinuxTargetInfo<X86_64TargetInfo> {
+public:
+ AndroidX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : LinuxTargetInfo<X86_64TargetInfo>(Triple, Opts) {
+ LongDoubleFormat = &llvm::APFloat::IEEEquad();
+ }
+
+ bool useFloat128ManglingForLongDouble() const override { return true; }
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_X86_H
diff --git a/lib/Basic/Targets/XCore.cpp b/lib/Basic/Targets/XCore.cpp
new file mode 100644
index 0000000000..793dca702d
--- /dev/null
+++ b/lib/Basic/Targets/XCore.cpp
@@ -0,0 +1,38 @@
+//===--- XCore.cpp - Implement XCore target feature support ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements XCore TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "XCore.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
+ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsXCore.def"
+};
+
+void XCoreTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__XS1B__");
+}
+
+ArrayRef<Builtin::Info> XCoreTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::XCore::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/XCore.h b/lib/Basic/Targets/XCore.h
new file mode 100644
index 0000000000..346e0eee15
--- /dev/null
+++ b/lib/Basic/Targets/XCore.h
@@ -0,0 +1,82 @@
+//===--- XCore.h - Declare XCore target feature support ---------*- 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 XCore TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY XCoreTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+
+public:
+ XCoreTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ NoAsmVariants = true;
+ LongLongAlign = 32;
+ SuitableAlign = 32;
+ DoubleAlign = LongDoubleAlign = 32;
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ IntPtrType = SignedInt;
+ WCharType = UnsignedChar;
+ WIntType = UnsignedInt;
+ UseZeroLengthBitfieldAlignment = true;
+ resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32"
+ "-f64:32-a:0:32-n32");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<const char *> getGCCRegNames() const override {
+ static const char *const GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr"
+ };
+ return llvm::makeArrayRef(GCCRegNames);
+ }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ return None;
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ return false;
+ }
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister
+ return (RegNo < 2) ? RegNo : -1;
+ }
+
+ bool allowsLargerPreferedTypeAlignment() const override { return false; }
+};
+} // namespace targets
+} // namespace clang
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
index f5db717866..debe5d9ad6 100644
--- a/lib/Basic/VirtualFileSystem.cpp
+++ b/lib/Basic/VirtualFileSystem.cpp
@@ -59,6 +59,7 @@ Status Status::copyWithNewName(const file_status &In, StringRef NewName) {
}
bool Status::equivalent(const Status &Other) const {
+ assert(isStatusKnown() && Other.isStatusKnown());
return getUniqueID() == Other.getUniqueID();
}
bool Status::isDirectory() const {
@@ -243,7 +244,7 @@ public:
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);
+ EC = llvm::sys::fs::status(Iter->path(), S, true);
CurrentEntry = Status::copyWithNewName(S, Iter->path());
}
}
@@ -257,7 +258,7 @@ public:
CurrentEntry = Status();
} else {
llvm::sys::fs::file_status S;
- EC = Iter->status(S);
+ EC = llvm::sys::fs::status(Iter->path(), S, true);
CurrentEntry = Status::copyWithNewName(S, Iter->path());
}
return EC;
diff --git a/lib/Basic/XRayLists.cpp b/lib/Basic/XRayLists.cpp
new file mode 100644
index 0000000000..462777d534
--- /dev/null
+++ b/lib/Basic/XRayLists.cpp
@@ -0,0 +1,59 @@
+//===--- 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("xray_always_instrument", "fun", FunctionName,
+ "arg1"))
+ return ImbueAttribute::ALWAYS_ARG1;
+ if (AlwaysInstrument->inSection("xray_always_instrument", "fun",
+ FunctionName))
+ return ImbueAttribute::ALWAYS;
+ if (NeverInstrument->inSection("xray_never_instrument", "fun", FunctionName))
+ return ImbueAttribute::NEVER;
+ return ImbueAttribute::NONE;
+}
+
+XRayFunctionFilter::ImbueAttribute
+XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename,
+ StringRef Category) const {
+ if (AlwaysInstrument->inSection("xray_always_instrument", "src", Filename,
+ Category))
+ return ImbueAttribute::ALWAYS;
+ if (NeverInstrument->inSection("xray_never_instrument", "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/CMakeLists.txt b/lib/CMakeLists.txt
index dfd819a407..b3fa93555b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -4,6 +4,7 @@ add_subdirectory(Lex)
add_subdirectory(Parse)
add_subdirectory(AST)
add_subdirectory(ASTMatchers)
+add_subdirectory(CrossTU)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index c0be60ef53..575506da84 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -24,6 +24,7 @@ namespace llvm {
namespace clang {
class ASTContext;
+ class CodeGenOptions;
class TargetInfo;
namespace CodeGen {
@@ -68,6 +69,7 @@ namespace swiftcall {
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
const TargetInfo &getTarget() const;
+ const CodeGenOptions &getCodeGenOpts() const;
/// Return the calling convention to use for system runtime
/// functions.
@@ -149,7 +151,6 @@ namespace swiftcall {
return info->supportsSwift();
}
};
-
} // end namespace CodeGen
} // end namespace clang
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index f0e0b71ddf..893967a9d6 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -35,7 +35,6 @@
#include "llvm/LTO/LTOBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -50,10 +49,12 @@
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
+#include "llvm/Transforms/Utils/NameAnonGlobals.h"
#include "llvm/Transforms/Utils/SymbolRewriter.h"
#include <memory>
using namespace clang;
@@ -83,9 +84,6 @@ class EmitAssemblyHelper {
return TargetIRAnalysis();
}
- /// Set LLVM command line options passed through -backend-option.
- void setCommandLineOpts();
-
void CreatePasses(legacy::PassManager &MPM, legacy::FunctionPassManager &FPM);
/// Generates the TargetMachine.
@@ -132,16 +130,20 @@ public:
// that we add to the PassManagerBuilder.
class PassManagerBuilderWrapper : public PassManagerBuilder {
public:
- PassManagerBuilderWrapper(const CodeGenOptions &CGOpts,
+ PassManagerBuilderWrapper(const Triple &TargetTriple,
+ const CodeGenOptions &CGOpts,
const LangOptions &LangOpts)
- : PassManagerBuilder(), CGOpts(CGOpts), LangOpts(LangOpts) {}
+ : PassManagerBuilder(), TargetTriple(TargetTriple), CGOpts(CGOpts),
+ LangOpts(LangOpts) {}
+ const Triple &getTargetTriple() const { return TargetTriple; }
const CodeGenOptions &getCGOpts() const { return CGOpts; }
const LangOptions &getLangOpts() const { return LangOpts; }
+
private:
+ const Triple &TargetTriple;
const CodeGenOptions &CGOpts;
const LangOptions &LangOpts;
};
-
}
static void addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
@@ -185,19 +187,44 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
Opts.Use8bitCounters = CGOpts.SanitizeCoverage8bitCounters;
Opts.TracePC = CGOpts.SanitizeCoverageTracePC;
Opts.TracePCGuard = CGOpts.SanitizeCoverageTracePCGuard;
+ Opts.NoPrune = CGOpts.SanitizeCoverageNoPrune;
+ Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters;
+ Opts.PCTable = CGOpts.SanitizeCoveragePCTable;
+ Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth;
PM.add(createSanitizerCoverageModulePass(Opts));
}
+// Check if ASan should use GC-friendly instrumentation for globals.
+// First of all, there is no point if -fdata-sections is off (expect for MachO,
+// where this is not a factor). Also, on ELF this feature requires an assembler
+// extension that only works with -integrated-as at the moment.
+static bool asanUseGlobalsGC(const Triple &T, const CodeGenOptions &CGOpts) {
+ if (!CGOpts.SanitizeAddressGlobalsDeadStripping)
+ return false;
+ switch (T.getObjectFormat()) {
+ case Triple::MachO:
+ case Triple::COFF:
+ return true;
+ case Triple::ELF:
+ return CGOpts.DataSections && !CGOpts.DisableIntegratedAS;
+ default:
+ return false;
+ }
+}
+
static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
const PassManagerBuilderWrapper &BuilderWrapper =
static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const Triple &T = BuilderWrapper.getTargetTriple();
const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Address);
bool UseAfterScope = CGOpts.SanitizeAddressUseAfterScope;
+ bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts);
PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover,
UseAfterScope));
- PM.add(createAddressSanitizerModulePass(/*CompileKernel*/false, Recover));
+ PM.add(createAddressSanitizerModulePass(/*CompileKernel*/ false, Recover,
+ UseGlobalsGC));
}
static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
@@ -294,6 +321,142 @@ 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 Optional<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", ~1u)
+ .Default(~0u);
+ assert(CodeModel != ~0u && "invalid code model!");
+ if (CodeModel == ~1u)
+ return None;
+ return static_cast<llvm::CodeModel::Model>(CodeModel);
+}
+
+static llvm::Reloc::Model getRelocModel(const CodeGenOptions &CodeGenOpts) {
+ // Keep this synced with the equivalent code in
+ // lib/Frontend/CompilerInvocation.cpp
+ llvm::Optional<llvm::Reloc::Model> RM;
+ RM = llvm::StringSwitch<llvm::Reloc::Model>(CodeGenOpts.RelocationModel)
+ .Case("static", llvm::Reloc::Static)
+ .Case("pic", llvm::Reloc::PIC_)
+ .Case("ropi", llvm::Reloc::ROPI)
+ .Case("rwpi", llvm::Reloc::RWPI)
+ .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI)
+ .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC);
+ assert(RM.hasValue() && "invalid PIC model!");
+ return *RM;
+}
+
+static TargetMachine::CodeGenFileType getCodeGenFileType(BackendAction Action) {
+ if (Action == Backend_EmitObj)
+ return TargetMachine::CGFT_ObjectFile;
+ else if (Action == Backend_EmitMCNull)
+ return TargetMachine::CGFT_Null;
+ else {
+ assert(Action == Backend_EmitAssembly && "Invalid action!");
+ return TargetMachine::CGFT_AssemblyFile;
+ }
+}
+
+static void initTargetOptions(llvm::TargetOptions &Options,
+ const CodeGenOptions &CodeGenOpts,
+ const clang::TargetOptions &TargetOpts,
+ const LangOptions &LangOpts,
+ const HeaderSearchOptions &HSOpts) {
+ Options.ThreadModel =
+ llvm::StringSwitch<llvm::ThreadModel::Model>(CodeGenOpts.ThreadModel)
+ .Case("posix", llvm::ThreadModel::POSIX)
+ .Case("single", llvm::ThreadModel::Single);
+
+ // Set float ABI type.
+ assert((CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp" ||
+ CodeGenOpts.FloatABI == "hard" || CodeGenOpts.FloatABI.empty()) &&
+ "Invalid Floating Point ABI!");
+ Options.FloatABIType =
+ llvm::StringSwitch<llvm::FloatABI::ABIType>(CodeGenOpts.FloatABI)
+ .Case("soft", llvm::FloatABI::Soft)
+ .Case("softfp", llvm::FloatABI::Soft)
+ .Case("hard", llvm::FloatABI::Hard)
+ .Default(llvm::FloatABI::Default);
+
+ // Set FP fusion mode.
+ switch (LangOpts.getDefaultFPContractMode()) {
+ case LangOptions::FPC_Off:
+ // Preserve any contraction performed by the front-end. (Strict performs
+ // splitting of the muladd instrinsic in the backend.)
+ Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
+ break;
+ case LangOptions::FPC_On:
+ Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
+ break;
+ case LangOptions::FPC_Fast:
+ Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
+ break;
+ }
+
+ Options.UseInitArray = CodeGenOpts.UseInitArray;
+ Options.DisableIntegratedAS = CodeGenOpts.DisableIntegratedAS;
+ Options.CompressDebugSections = CodeGenOpts.getCompressDebugSections();
+ Options.RelaxELFRelocations = CodeGenOpts.RelaxELFRelocations;
+
+ // Set EABI version.
+ Options.EABIVersion = TargetOpts.EABIVersion;
+
+ if (LangOpts.SjLjExceptions)
+ Options.ExceptionModel = llvm::ExceptionHandling::SjLj;
+
+ Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath;
+ Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath;
+ Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
+ Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
+ Options.StackAlignmentOverride = CodeGenOpts.StackAlignment;
+ Options.FunctionSections = CodeGenOpts.FunctionSections;
+ Options.DataSections = CodeGenOpts.DataSections;
+ Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames;
+ Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
+ Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning();
+
+ if (CodeGenOpts.EnableSplitDwarf)
+ Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile;
+ Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
+ Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
+ Options.MCOptions.MCUseDwarfDirectory = !CodeGenOpts.NoDwarfDirectoryAsm;
+ Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
+ Options.MCOptions.MCIncrementalLinkerCompatible =
+ CodeGenOpts.IncrementalLinkerCompatible;
+ Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations;
+ Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
+ Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
+ Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
+ Options.MCOptions.ABIName = TargetOpts.ABI;
+ for (const auto &Entry : HSOpts.UserEntries)
+ if (!Entry.IsFramework &&
+ (Entry.Group == frontend::IncludeDirGroup::Quoted ||
+ Entry.Group == frontend::IncludeDirGroup::Angled ||
+ Entry.Group == frontend::IncludeDirGroup::System))
+ Options.MCOptions.IASSearchPaths.push_back(
+ Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path);
+}
+
void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
legacy::FunctionPassManager &FPM) {
// Handle disabling of all LLVM passes, where we want to preserve the
@@ -301,8 +464,6 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
if (CodeGenOpts.DisableLLVMPasses)
return;
- PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts);
-
// Figure out TargetLibraryInfo. This needs to be added to MPM and FPM
// manually (and not via PMBuilder), since some passes (eg. InstrProfiling)
// are inserted before PMBuilder ones - they'd get the default-constructed
@@ -311,6 +472,8 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
std::unique_ptr<TargetLibraryInfoImpl> TLII(
createTLII(TargetTriple, CodeGenOpts));
+ PassManagerBuilderWrapper PMBuilder(TargetTriple, CodeGenOpts, LangOpts);
+
// At O0 and O1 we only run the always inliner which is more efficient. At
// higher optimization levels we run the normal inliner.
if (CodeGenOpts.OptimizationLevel <= 1) {
@@ -318,13 +481,17 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
!CodeGenOpts.DisableLifetimeMarkers);
PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
} else {
+ // We do not want to inline hot callsites for SamplePGO module-summary build
+ // because profile annotation will happen again in ThinLTO backend, and we
+ // want the IR of the hot path to match the profile.
PMBuilder.Inliner = createFunctionInliningPass(
- CodeGenOpts.OptimizationLevel, CodeGenOpts.OptimizeSize);
+ CodeGenOpts.OptimizationLevel, CodeGenOpts.OptimizeSize,
+ (!CodeGenOpts.SampleProfileFile.empty() &&
+ CodeGenOpts.EmitSummaryIndex));
}
PMBuilder.OptLevel = CodeGenOpts.OptimizationLevel;
PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
- PMBuilder.BBVectorize = CodeGenOpts.VectorizeBB;
PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;
PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
@@ -465,7 +632,7 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
PMBuilder.populateModulePassManager(MPM);
}
-void EmitAssemblyHelper::setCommandLineOpts() {
+static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) {
SmallVector<const char *, 16> BackendArgs;
BackendArgs.push_back("clang"); // Fake program name.
if (!CodeGenOpts.DebugPass.empty()) {
@@ -494,126 +661,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);
-
+ Optional<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));
}
@@ -629,13 +684,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
@@ -656,7 +705,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
std::unique_ptr<raw_pwrite_stream> OS) {
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
- setCommandLineOpts();
+ setCommandLineOpts(CodeGenOpts);
bool UsesCodeGen = (Action != Backend_EmitNothing &&
Action != Backend_EmitBC &&
@@ -682,13 +731,28 @@ 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:
- if (CodeGenOpts.EmitSummaryIndex)
- PerModulePasses.add(createWriteThinLTOBitcodePass(*OS));
+ 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));
@@ -770,7 +834,7 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) {
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
- setCommandLineOpts();
+ setCommandLineOpts(CodeGenOpts);
// The new pass manager always makes a target machine available to passes
// during construction.
@@ -780,24 +844,27 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
return;
TheModule->setDataLayout(TM->createDataLayout());
- 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);
+ Optional<PGOOptions> PGOOpt;
+
+ if (CodeGenOpts.hasProfileIRInstr())
+ // -fprofile-generate.
+ PGOOpt = PGOOptions(CodeGenOpts.InstrProfileOutput.empty()
+ ? DefaultProfileGenName
+ : CodeGenOpts.InstrProfileOutput,
+ "", "", true, CodeGenOpts.DebugInfoForProfiling);
+ else if (CodeGenOpts.hasProfileIRUse())
+ // -fprofile-use.
+ PGOOpt = PGOOptions("", CodeGenOpts.ProfileInstrumentUsePath, "", false,
+ CodeGenOpts.DebugInfoForProfiling);
+ else if (!CodeGenOpts.SampleProfileFile.empty())
+ // -fprofile-sample-use
+ PGOOpt = PGOOptions("", "", CodeGenOpts.SampleProfileFile, false,
+ CodeGenOpts.DebugInfoForProfiling);
+ else if (CodeGenOpts.DebugInfoForProfiling)
+ // -fdebug-info-for-profiling
+ PGOOpt = PGOOptions("", "", "", false, true);
+
+ PassBuilder PB(TM.get(), PGOOpt);
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
@@ -807,6 +874,14 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
// Register the AA manager first so that our version is the one used.
FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
+ // Register the target library analysis directly and give it a customized
+ // preset TLI.
+ Triple TargetTriple(TheModule->getTargetTriple());
+ std::unique_ptr<TargetLibraryInfoImpl> TLII(
+ createTLII(TargetTriple, CodeGenOpts));
+ FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
+ MAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
+
// Register all the basic analyses with the managers.
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
@@ -814,20 +889,34 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
- ModulePassManager MPM;
+ ModulePassManager MPM(CodeGenOpts.DebugPassManager);
if (!CodeGenOpts.DisableLLVMPasses) {
+ bool IsThinLTO = CodeGenOpts.EmitSummaryIndex;
+ bool IsLTO = CodeGenOpts.PrepareForLTO;
+
if (CodeGenOpts.OptimizationLevel == 0) {
// Build a minimal pipeline based on the semantics required by Clang,
// which is just that always inlining occurs.
MPM.addPass(AlwaysInlinerPass());
+ if (IsThinLTO)
+ MPM.addPass(NameAnonGlobalPass());
} else {
- // Otherwise, use the default pass pipeline. We also have to map our
- // optimization levels into one of the distinct levels used to configure
- // the pipeline.
+ // Map our optimization levels into one of the distinct levels used to
+ // configure the pipeline.
PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts);
- MPM = PB.buildPerModuleDefaultPipeline(Level);
+ if (IsThinLTO) {
+ MPM = PB.buildThinLTOPreLinkDefaultPipeline(
+ Level, CodeGenOpts.DebugPassManager);
+ MPM.addPass(NameAnonGlobalPass());
+ } else if (IsLTO) {
+ MPM = PB.buildLTOPreLinkDefaultPipeline(Level,
+ CodeGenOpts.DebugPassManager);
+ } else {
+ MPM = PB.buildPerModuleDefaultPipeline(Level,
+ CodeGenOpts.DebugPassManager);
+ }
}
}
@@ -835,6 +924,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
// create that pass manager here and use it as needed below.
legacy::PassManager CodeGenPasses;
bool NeedCodeGen = false;
+ Optional<raw_fd_ostream> ThinLinkOS;
// Append any output we need to the pass manager.
switch (Action) {
@@ -842,9 +932,24 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
break;
case Backend_EmitBC:
- MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists,
- CodeGenOpts.EmitSummaryIndex,
- CodeGenOpts.EmitSummaryIndex));
+ if (CodeGenOpts.EmitSummaryIndex) {
+ if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) {
+ std::error_code EC;
+ ThinLinkOS.emplace(CodeGenOpts.ThinLinkBitcodeFile, EC,
+ llvm::sys::fs::F_None);
+ if (EC) {
+ Diags.Report(diag::err_fe_unable_to_open_output)
+ << CodeGenOpts.ThinLinkBitcodeFile << EC.message();
+ return;
+ }
+ }
+ MPM.addPass(
+ ThinLTOBitcodeWriterPass(*OS, ThinLinkOS ? &*ThinLinkOS : nullptr));
+ } else {
+ MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists,
+ CodeGenOpts.EmitSummaryIndex,
+ CodeGenOpts.EmitSummaryIndex));
+ }
break;
case Backend_EmitLL:
@@ -884,11 +989,11 @@ Expected<BitcodeModule> clang::FindThinLTOModule(MemoryBufferRef MBRef) {
if (!BMsOrErr)
return BMsOrErr.takeError();
- // The bitcode file may contain multiple modules, we want the one with a
- // summary.
+ // The bitcode file may contain multiple modules, we want the one that is
+ // marked as being the ThinLTO module.
for (BitcodeModule &BM : *BMsOrErr) {
- Expected<bool> HasSummary = BM.hasSummary();
- if (HasSummary && *HasSummary)
+ Expected<BitcodeLTOInfo> LTOInfo = BM.getLTOInfo();
+ if (LTOInfo && LTOInfo->IsThinLTO)
return BM;
}
@@ -897,21 +1002,32 @@ Expected<BitcodeModule> clang::FindThinLTOModule(MemoryBufferRef MBRef) {
}
static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
+ const HeaderSearchOptions &HeaderOpts,
+ const CodeGenOptions &CGOpts,
+ const clang::TargetOptions &TOpts,
+ const LangOptions &LOpts,
std::unique_ptr<raw_pwrite_stream> OS,
- std::string SampleProfile) {
- StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
+ std::string SampleProfile,
+ BackendAction Action) {
+ StringMap<DenseMap<GlobalValue::GUID, GlobalValueSummary *>>
ModuleToDefinedGVSummaries;
CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
+ setCommandLineOpts(CGOpts);
+
// We can simply import the values mentioned in the combined index, since
// we should only invoke this using the individual indexes written out
// via a WriteIndexesThinBackend.
FunctionImporter::ImportMapTy ImportList;
for (auto &GlobalList : *CombinedIndex) {
+ // Ignore entries for undefined references.
+ if (GlobalList.second.SummaryList.empty())
+ continue;
+
auto GUID = GlobalList.first;
- assert(GlobalList.second.size() == 1 &&
+ assert(GlobalList.second.SummaryList.size() == 1 &&
"Expected individual combined index to have one summary per GUID");
- auto &Summary = GlobalList.second[0];
+ auto &Summary = GlobalList.second.SummaryList[0];
// Skip the summaries for the importing module. These are included to
// e.g. record required linkage changes.
if (Summary->modulePath() == M->getModuleIdentifier())
@@ -949,7 +1065,36 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
return llvm::make_unique<lto::NativeObjectStream>(std::move(OS));
};
lto::Config Conf;
- Conf.SampleProfile = SampleProfile;
+ Conf.CPU = TOpts.CPU;
+ Conf.CodeModel = getCodeModel(CGOpts);
+ Conf.MAttrs = TOpts.Features;
+ Conf.RelocModel = getRelocModel(CGOpts);
+ Conf.CGOptLevel = getCGOptLevel(CGOpts);
+ initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts);
+ Conf.SampleProfile = std::move(SampleProfile);
+ Conf.UseNewPM = CGOpts.ExperimentalNewPassManager;
+ switch (Action) {
+ case Backend_EmitNothing:
+ Conf.PreCodeGenModuleHook = [](size_t Task, const Module &Mod) {
+ return false;
+ };
+ break;
+ case Backend_EmitLL:
+ Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) {
+ M->print(*OS, nullptr, CGOpts.EmitLLVMUseLists);
+ return false;
+ };
+ break;
+ case Backend_EmitBC:
+ Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) {
+ WriteBitcodeToFile(M, *OS, CGOpts.EmitLLVMUseLists);
+ return false;
+ };
+ break;
+ default:
+ Conf.CGFileType = getCodeGenFileType(Action);
+ break;
+ }
if (Error E = thinBackend(
Conf, 0, AddStream, *M, *CombinedIndex, ImportList,
ModuleToDefinedGVSummaries[M->getModuleIdentifier()], ModuleMap)) {
@@ -972,7 +1117,8 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
// into memory and pass it into runThinLTOBackend, which will run the
// function importer and invoke LTO passes.
Expected<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr =
- llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile);
+ llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile,
+ /*IgnoreEmptyThinLTOIndexFile*/true);
if (!IndexOrErr) {
logAllUnhandledErrors(IndexOrErr.takeError(), errs(),
"Error loading index file '" +
@@ -985,8 +1131,8 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
// of an error).
bool DoThinLTOBackend = CombinedIndex != nullptr;
if (DoThinLTOBackend) {
- runThinLTOBackend(CombinedIndex.get(), M, std::move(OS),
- CGOpts.SampleProfileFile);
+ runThinLTOBackend(CombinedIndex.get(), M, HeaderOpts, CGOpts, TOpts,
+ LOpts, std::move(OS), CGOpts.SampleProfileFile, Action);
return;
}
}
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 28e20b53d6..d90c3a53a6 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -15,8 +15,10 @@
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
@@ -94,9 +96,8 @@ namespace {
BFI.StorageSize = AtomicSizeInBits;
BFI.StorageOffset += OffsetInChars;
LVal = LValue::MakeBitfield(Address(Addr, lvalue.getAlignment()),
- BFI, lvalue.getType(),
- lvalue.getAlignmentSource());
- LVal.setTBAAInfo(lvalue.getTBAAInfo());
+ BFI, lvalue.getType(), lvalue.getBaseInfo(),
+ lvalue.getTBAAInfo());
AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned);
if (AtomicTy.isNull()) {
llvm::APInt Size(
@@ -203,7 +204,7 @@ namespace {
addr = CGF.Builder.CreateStructGEP(addr, 0, CharUnits());
return LValue::MakeAddr(addr, getValueType(), CGF.getContext(),
- LVal.getAlignmentSource(), LVal.getTBAAInfo());
+ LVal.getBaseInfo(), LVal.getTBAAInfo());
}
/// \brief Emits atomic load.
@@ -359,13 +360,15 @@ static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
Address Val1, Address Val2,
uint64_t Size,
llvm::AtomicOrdering SuccessOrder,
- llvm::AtomicOrdering FailureOrder) {
+ llvm::AtomicOrdering FailureOrder,
+ llvm::SyncScope::ID Scope) {
// Note that cmpxchg doesn't support weak cmpxchg, at least at the moment.
llvm::Value *Expected = CGF.Builder.CreateLoad(Val1);
llvm::Value *Desired = CGF.Builder.CreateLoad(Val2);
llvm::AtomicCmpXchgInst *Pair = CGF.Builder.CreateAtomicCmpXchg(
- Ptr.getPointer(), Expected, Desired, SuccessOrder, FailureOrder);
+ Ptr.getPointer(), Expected, Desired, SuccessOrder, FailureOrder,
+ Scope);
Pair->setVolatile(E->isVolatile());
Pair->setWeak(IsWeak);
@@ -407,7 +410,8 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
Address Val1, Address Val2,
llvm::Value *FailureOrderVal,
uint64_t Size,
- llvm::AtomicOrdering SuccessOrder) {
+ llvm::AtomicOrdering SuccessOrder,
+ llvm::SyncScope::ID Scope) {
llvm::AtomicOrdering FailureOrder;
if (llvm::ConstantInt *FO = dyn_cast<llvm::ConstantInt>(FailureOrderVal)) {
auto FOS = FO->getSExtValue();
@@ -435,7 +439,7 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrder);
}
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
- FailureOrder);
+ FailureOrder, Scope);
return;
}
@@ -460,13 +464,13 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
// doesn't fold to a constant for the ordering.
CGF.Builder.SetInsertPoint(MonotonicBB);
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
- Size, SuccessOrder, llvm::AtomicOrdering::Monotonic);
+ Size, SuccessOrder, llvm::AtomicOrdering::Monotonic, Scope);
CGF.Builder.CreateBr(ContBB);
if (AcquireBB) {
CGF.Builder.SetInsertPoint(AcquireBB);
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
- Size, SuccessOrder, llvm::AtomicOrdering::Acquire);
+ Size, SuccessOrder, llvm::AtomicOrdering::Acquire, Scope);
CGF.Builder.CreateBr(ContBB);
SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
AcquireBB);
@@ -476,7 +480,7 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
if (SeqCstBB) {
CGF.Builder.SetInsertPoint(SeqCstBB);
emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
- llvm::AtomicOrdering::SequentiallyConsistent);
+ llvm::AtomicOrdering::SequentiallyConsistent, Scope);
CGF.Builder.CreateBr(ContBB);
SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
SeqCstBB);
@@ -488,27 +492,31 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
Address Ptr, Address Val1, Address Val2,
llvm::Value *IsWeak, llvm::Value *FailureOrder,
- uint64_t Size, llvm::AtomicOrdering Order) {
+ uint64_t Size, llvm::AtomicOrdering Order,
+ llvm::SyncScope::ID Scope) {
llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
llvm_unreachable("Already handled!");
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order);
+ FailureOrder, Size, Order, Scope);
return;
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order);
+ FailureOrder, Size, Order, Scope);
return;
case AtomicExpr::AO__atomic_compare_exchange:
case AtomicExpr::AO__atomic_compare_exchange_n: {
if (llvm::ConstantInt *IsWeakC = dyn_cast<llvm::ConstantInt>(IsWeak)) {
emitAtomicCmpXchgFailureSet(CGF, E, IsWeakC->getZExtValue(), Dest, Ptr,
- Val1, Val2, FailureOrder, Size, Order);
+ Val1, Val2, FailureOrder, Size, Order, Scope);
} else {
// Create all the relevant BB's
llvm::BasicBlock *StrongBB =
@@ -522,12 +530,12 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
CGF.Builder.SetInsertPoint(StrongBB);
emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order);
+ FailureOrder, Size, Order, Scope);
CGF.Builder.CreateBr(ContBB);
CGF.Builder.SetInsertPoint(WeakBB);
emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
- FailureOrder, Size, Order);
+ FailureOrder, Size, Order, Scope);
CGF.Builder.CreateBr(ContBB);
CGF.Builder.SetInsertPoint(ContBB);
@@ -535,26 +543,29 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
return;
}
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_load:
case AtomicExpr::AO__atomic_load_n:
case AtomicExpr::AO__atomic_load: {
llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
- Load->setAtomic(Order);
+ Load->setAtomic(Order, Scope);
Load->setVolatile(E->isVolatile());
CGF.Builder.CreateStore(Load, Dest);
return;
}
case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n: {
llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
- Store->setAtomic(Order);
+ Store->setAtomic(Order, Scope);
Store->setVolatile(E->isVolatile());
return;
}
case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__opencl_atomic_exchange:
case AtomicExpr::AO__atomic_exchange_n:
case AtomicExpr::AO__atomic_exchange:
Op = llvm::AtomicRMWInst::Xchg;
@@ -564,6 +575,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
PostOp = llvm::Instruction::Add;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__opencl_atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_add:
Op = llvm::AtomicRMWInst::Add;
break;
@@ -572,14 +584,26 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
PostOp = llvm::Instruction::Sub;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
Op = llvm::AtomicRMWInst::Sub;
break;
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min
+ : llvm::AtomicRMWInst::UMin;
+ break;
+
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
+ Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max
+ : llvm::AtomicRMWInst::UMax;
+ break;
+
case AtomicExpr::AO__atomic_and_fetch:
PostOp = llvm::Instruction::And;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__opencl_atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_and:
Op = llvm::AtomicRMWInst::And;
break;
@@ -588,6 +612,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
PostOp = llvm::Instruction::Or;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__opencl_atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_or:
Op = llvm::AtomicRMWInst::Or;
break;
@@ -596,6 +621,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
PostOp = llvm::Instruction::Xor;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_xor:
case AtomicExpr::AO__atomic_fetch_xor:
Op = llvm::AtomicRMWInst::Xor;
break;
@@ -610,7 +636,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
llvm::AtomicRMWInst *RMWI =
- CGF.Builder.CreateAtomicRMW(Op, Ptr.getPointer(), LoadVal1, Order);
+ CGF.Builder.CreateAtomicRMW(Op, Ptr.getPointer(), LoadVal1, Order, Scope);
RMWI->setVolatile(E->isVolatile());
// For __atomic_*_fetch operations, perform the operation again to
@@ -633,6 +659,61 @@ EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
return DeclPtr;
}
+static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
+ Address Ptr, Address Val1, Address Val2,
+ llvm::Value *IsWeak, llvm::Value *FailureOrder,
+ uint64_t Size, llvm::AtomicOrdering Order,
+ llvm::Value *Scope) {
+ auto ScopeModel = Expr->getScopeModel();
+
+ // LLVM atomic instructions always have synch scope. If clang atomic
+ // expression has no scope operand, use default LLVM synch scope.
+ if (!ScopeModel) {
+ EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
+ Order, CGF.CGM.getLLVMContext().getOrInsertSyncScopeID(""));
+ return;
+ }
+
+ // Handle constant scope.
+ if (auto SC = dyn_cast<llvm::ConstantInt>(Scope)) {
+ auto SCID = CGF.getTargetHooks().getLLVMSyncScopeID(
+ ScopeModel->map(SC->getZExtValue()), CGF.CGM.getLLVMContext());
+ EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
+ Order, SCID);
+ return;
+ }
+
+ // Handle non-constant scope.
+ auto &Builder = CGF.Builder;
+ auto Scopes = ScopeModel->getRuntimeValues();
+ llvm::DenseMap<unsigned, llvm::BasicBlock *> BB;
+ for (auto S : Scopes)
+ BB[S] = CGF.createBasicBlock(getAsString(ScopeModel->map(S)), CGF.CurFn);
+
+ llvm::BasicBlock *ContBB =
+ CGF.createBasicBlock("atomic.scope.continue", CGF.CurFn);
+
+ auto *SC = Builder.CreateIntCast(Scope, Builder.getInt32Ty(), false);
+ // If unsupported synch scope is encountered at run time, assume a fallback
+ // synch scope value.
+ auto FallBack = ScopeModel->getFallBackValue();
+ llvm::SwitchInst *SI = Builder.CreateSwitch(SC, BB[FallBack]);
+ for (auto S : Scopes) {
+ auto *B = BB[S];
+ if (S != FallBack)
+ SI->addCase(Builder.getInt32(S), B);
+
+ Builder.SetInsertPoint(B);
+ EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
+ Order,
+ CGF.getTargetHooks().getLLVMSyncScopeID(ScopeModel->map(S),
+ CGF.getLLVMContext()));
+ Builder.CreateBr(ContBB);
+ }
+
+ Builder.SetInsertPoint(ContBB);
+}
+
static void
AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,
@@ -663,33 +744,38 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
QualType MemTy = AtomicTy;
if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
MemTy = AT->getValueType();
- CharUnits sizeChars, alignChars;
- std::tie(sizeChars, alignChars) = getContext().getTypeInfoInChars(AtomicTy);
- uint64_t Size = sizeChars.getQuantity();
- unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth();
- bool UseLibcall = (sizeChars != alignChars ||
- getContext().toBits(sizeChars) > MaxInlineWidthInBits);
-
llvm::Value *IsWeak = nullptr, *OrderFail = nullptr;
Address Val1 = Address::invalid();
Address Val2 = Address::invalid();
Address Dest = Address::invalid();
- Address Ptr(EmitScalarExpr(E->getPtr()), alignChars);
+ Address Ptr = EmitPointerWithAlignment(E->getPtr());
+
+ CharUnits sizeChars, alignChars;
+ std::tie(sizeChars, alignChars) = getContext().getTypeInfoInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth();
+ bool UseLibcall = ((Ptr.getAlignment() % sizeChars) != 0 ||
+ getContext().toBits(sizeChars) > MaxInlineWidthInBits);
- if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
+ if (E->getOp() == AtomicExpr::AO__c11_atomic_init ||
+ E->getOp() == AtomicExpr::AO__opencl_atomic_init) {
LValue lvalue = MakeAddrLValue(Ptr, AtomicTy);
EmitAtomicInit(E->getVal1(), lvalue);
return RValue::get(nullptr);
}
llvm::Value *Order = EmitScalarExpr(E->getOrder());
+ llvm::Value *Scope =
+ E->getScopeModel() ? EmitScalarExpr(E->getScope()) : nullptr;
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
llvm_unreachable("Already handled above with EmitAtomicInit!");
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_load:
case AtomicExpr::AO__atomic_load_n:
break;
@@ -708,6 +794,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
case AtomicExpr::AO__atomic_compare_exchange_n:
case AtomicExpr::AO__atomic_compare_exchange:
Val1 = EmitPointerWithAlignment(E->getVal1());
@@ -716,12 +804,15 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
else
Val2 = EmitValToTemp(*this, E->getVal2());
OrderFail = EmitScalarExpr(E->getOrderFail());
- if (E->getNumSubExprs() == 6)
+ if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
+ E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
IsWeak = EmitScalarExpr(E->getWeak());
break;
case AtomicExpr::AO__c11_atomic_fetch_add:
case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_add:
+ case AtomicExpr::AO__opencl_atomic_fetch_sub:
if (MemTy->isPointerType()) {
// For pointer arithmetic, we're required to do a bit of math:
// adding 1 to an int* is not the same as adding 1 to a uintptr_t.
@@ -744,11 +835,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
case AtomicExpr::AO__atomic_sub_fetch:
case AtomicExpr::AO__c11_atomic_store:
case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__opencl_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_exchange:
case AtomicExpr::AO__atomic_store_n:
case AtomicExpr::AO__atomic_exchange_n:
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_and:
+ case AtomicExpr::AO__opencl_atomic_fetch_or:
+ case AtomicExpr::AO__opencl_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_xor:
@@ -784,18 +882,26 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
bool UseOptimizedLibcall = false;
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
llvm_unreachable("Already handled above with EmitAtomicInit!");
case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__opencl_atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_add:
case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__opencl_atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_and:
case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__opencl_atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_nand:
case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_xor:
case AtomicExpr::AO__atomic_add_fetch:
case AtomicExpr::AO__atomic_and_fetch:
@@ -812,6 +918,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
case AtomicExpr::AO__c11_atomic_exchange:
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__opencl_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_exchange:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
case AtomicExpr::AO__atomic_load_n:
case AtomicExpr::AO__atomic_load:
case AtomicExpr::AO__atomic_store_n:
@@ -833,7 +944,24 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
getContext().getSizeType());
}
// Atomic address is the first or second parameter
- Args.add(RValue::get(EmitCastToVoidPtr(Ptr.getPointer())),
+ // The OpenCL atomic library functions only accept pointer arguments to
+ // generic address space.
+ auto CastToGenericAddrSpace = [&](llvm::Value *V, QualType PT) {
+ if (!E->isOpenCL())
+ return V;
+ auto AS = PT->getAs<PointerType>()->getPointeeType().getAddressSpace();
+ if (AS == LangAS::opencl_generic)
+ return V;
+ auto DestAS = getContext().getTargetAddressSpace(LangAS::opencl_generic);
+ auto T = V->getType();
+ auto *DestType = T->getPointerElementType()->getPointerTo(DestAS);
+
+ return getTargetHooks().performAddrSpaceCast(
+ *this, V, AS, LangAS::opencl_generic, DestType, false);
+ };
+
+ Args.add(RValue::get(CastToGenericAddrSpace(
+ EmitCastToVoidPtr(Ptr.getPointer()), E->getPtr()->getType())),
getContext().VoidPtrTy);
std::string LibCallName;
@@ -844,6 +972,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
llvm_unreachable("Already handled!");
// There is only one libcall for compare an exchange, because there is no
@@ -855,13 +984,17 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// int success, int failure)
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
case AtomicExpr::AO__atomic_compare_exchange:
case AtomicExpr::AO__atomic_compare_exchange_n:
LibCallName = "__atomic_compare_exchange";
RetTy = getContext().BoolTy;
HaveRetTy = true;
- Args.add(RValue::get(EmitCastToVoidPtr(Val1.getPointer())),
- getContext().VoidPtrTy);
+ Args.add(
+ RValue::get(CastToGenericAddrSpace(
+ EmitCastToVoidPtr(Val1.getPointer()), E->getVal1()->getType())),
+ getContext().VoidPtrTy);
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val2.getPointer(),
MemTy, E->getExprLoc(), sizeChars);
Args.add(RValue::get(Order), getContext().IntTy);
@@ -871,6 +1004,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// int order)
// T __atomic_exchange_N(T *mem, T val, int order)
case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__opencl_atomic_exchange:
case AtomicExpr::AO__atomic_exchange_n:
case AtomicExpr::AO__atomic_exchange:
LibCallName = "__atomic_exchange";
@@ -880,6 +1014,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// void __atomic_store(size_t size, void *mem, void *val, int order)
// void __atomic_store_N(T *mem, T val, int order)
case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n:
LibCallName = "__atomic_store";
@@ -891,6 +1026,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// void __atomic_load(size_t size, void *mem, void *return, int order)
// T __atomic_load_N(T *mem, int order)
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_load:
case AtomicExpr::AO__atomic_load:
case AtomicExpr::AO__atomic_load_n:
LibCallName = "__atomic_load";
@@ -901,6 +1037,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
PostOp = llvm::Instruction::Add;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__opencl_atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_add:
LibCallName = "__atomic_fetch_add";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
@@ -912,6 +1049,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
PostOp = llvm::Instruction::And;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__opencl_atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_and:
LibCallName = "__atomic_fetch_and";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
@@ -923,6 +1061,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
PostOp = llvm::Instruction::Or;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__opencl_atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_or:
LibCallName = "__atomic_fetch_or";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
@@ -934,6 +1073,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
PostOp = llvm::Instruction::Sub;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
LibCallName = "__atomic_fetch_sub";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
@@ -945,11 +1085,26 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
PostOp = llvm::Instruction::Xor;
// Fall through.
case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_xor:
case AtomicExpr::AO__atomic_fetch_xor:
LibCallName = "__atomic_fetch_xor";
AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
MemTy, E->getExprLoc(), sizeChars);
break;
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ LibCallName = E->getValueType()->isSignedIntegerType()
+ ? "__atomic_fetch_min"
+ : "__atomic_fetch_umin";
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
+ LoweredMemTy, E->getExprLoc(), sizeChars);
+ break;
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
+ LibCallName = E->getValueType()->isSignedIntegerType()
+ ? "__atomic_fetch_max"
+ : "__atomic_fetch_umax";
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
+ LoweredMemTy, E->getExprLoc(), sizeChars);
+ break;
// T __atomic_nand_fetch_N(T *mem, T val, int order)
// T __atomic_fetch_nand_N(T *mem, T val, int order)
case AtomicExpr::AO__atomic_nand_fetch:
@@ -962,6 +1117,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
break;
}
+ if (E->isOpenCL()) {
+ LibCallName = std::string("__opencl") +
+ StringRef(LibCallName).drop_front(1).str();
+
+ }
// Optimized functions have the size in their name.
if (UseOptimizedLibcall)
LibCallName += "_" + llvm::utostr(Size);
@@ -982,6 +1142,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// order is always the last parameter
Args.add(RValue::get(Order),
getContext().IntTy);
+ if (E->isOpenCL())
+ Args.add(RValue::get(Scope), getContext().IntTy);
// PostOp is only needed for the atomic_*_fetch operations, and
// thus is only needed for and implemented in the
@@ -1018,9 +1180,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
}
bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
+ E->getOp() == AtomicExpr::AO__opencl_atomic_store ||
E->getOp() == AtomicExpr::AO__atomic_store ||
E->getOp() == AtomicExpr::AO__atomic_store_n;
bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
+ E->getOp() == AtomicExpr::AO__opencl_atomic_load ||
E->getOp() == AtomicExpr::AO__atomic_load ||
E->getOp() == AtomicExpr::AO__atomic_load_n;
@@ -1032,37 +1196,38 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
switch ((llvm::AtomicOrderingCABI)ord) {
case llvm::AtomicOrderingCABI::relaxed:
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Monotonic);
+ llvm::AtomicOrdering::Monotonic, Scope);
break;
case llvm::AtomicOrderingCABI::consume:
case llvm::AtomicOrderingCABI::acquire:
if (IsStore)
break; // Avoid crashing on code with undefined behavior
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Acquire);
+ llvm::AtomicOrdering::Acquire, Scope);
break;
case llvm::AtomicOrderingCABI::release:
if (IsLoad)
break; // Avoid crashing on code with undefined behavior
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::Release);
+ llvm::AtomicOrdering::Release, Scope);
break;
case llvm::AtomicOrderingCABI::acq_rel:
if (IsLoad || IsStore)
break; // Avoid crashing on code with undefined behavior
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::AcquireRelease);
+ llvm::AtomicOrdering::AcquireRelease, Scope);
break;
case llvm::AtomicOrderingCABI::seq_cst:
EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
- llvm::AtomicOrdering::SequentiallyConsistent);
+ llvm::AtomicOrdering::SequentiallyConsistent, Scope);
break;
}
if (RValTy->isVoidType())
return RValue::get(nullptr);
return convertTempToRValue(
- Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo()),
+ Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo(
+ Dest.getAddressSpace())),
RValTy, E->getExprLoc());
}
@@ -1091,13 +1256,13 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// Emit all the different atomics
Builder.SetInsertPoint(MonotonicBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
- Size, llvm::AtomicOrdering::Monotonic);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
+ llvm::AtomicOrdering::Monotonic, Scope);
Builder.CreateBr(ContBB);
if (!IsStore) {
Builder.SetInsertPoint(AcquireBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
- Size, llvm::AtomicOrdering::Acquire);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
+ llvm::AtomicOrdering::Acquire, Scope);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
AcquireBB);
@@ -1106,23 +1271,23 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
}
if (!IsLoad) {
Builder.SetInsertPoint(ReleaseBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
- Size, llvm::AtomicOrdering::Release);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
+ llvm::AtomicOrdering::Release, Scope);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::release),
ReleaseBB);
}
if (!IsLoad && !IsStore) {
Builder.SetInsertPoint(AcqRelBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
- Size, llvm::AtomicOrdering::AcquireRelease);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
+ llvm::AtomicOrdering::AcquireRelease, Scope);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acq_rel),
AcqRelBB);
}
Builder.SetInsertPoint(SeqCstBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
- Size, llvm::AtomicOrdering::SequentiallyConsistent);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
+ llvm::AtomicOrdering::SequentiallyConsistent, Scope);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
SeqCstBB);
@@ -1134,7 +1299,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
assert(Atomics.getValueSizeInBits() <= Atomics.getAtomicSizeInBits());
return convertTempToRValue(
- Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo()),
+ Builder.CreateBitCast(Dest, ConvertTypeForMem(RValTy)->getPointerTo(
+ Dest.getAddressSpace())),
RValTy, E->getExprLoc());
}
@@ -1181,15 +1347,15 @@ RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
if (LVal.isBitField())
return CGF.EmitLoadOfBitfieldLValue(
LValue::MakeBitfield(addr, LVal.getBitFieldInfo(), LVal.getType(),
- LVal.getAlignmentSource()), loc);
+ LVal.getBaseInfo(), TBAAAccessInfo()), loc);
if (LVal.isVectorElt())
return CGF.EmitLoadOfLValue(
LValue::MakeVectorElt(addr, LVal.getVectorIdx(), LVal.getType(),
- LVal.getAlignmentSource()), loc);
+ LVal.getBaseInfo(), TBAAAccessInfo()), loc);
assert(LVal.isExtVectorElt());
return CGF.EmitLoadOfExtVectorElementLValue(LValue::MakeExtVectorElt(
addr, LVal.getExtVectorElts(), LVal.getType(),
- LVal.getAlignmentSource()));
+ LVal.getBaseInfo(), TBAAAccessInfo()));
}
RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
@@ -1260,8 +1426,7 @@ llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO,
// Other decoration.
if (IsVolatile)
Load->setVolatile(true);
- if (LVal.getTBAAInfo())
- CGF.CGM.DecorateInstructionWithTBAA(Load, LVal.getTBAAInfo());
+ CGF.CGM.DecorateInstructionWithTBAA(Load, LVal.getTBAAInfo());
return Load;
}
@@ -1506,29 +1671,30 @@ EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, RValue OldRVal,
UpdateLVal =
LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo(),
+ AtomicLVal.getTBAAInfo());
DesiredLVal =
LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
- AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
+ AtomicLVal.getTBAAInfo());
} else if (AtomicLVal.isVectorElt()) {
UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo(),
+ AtomicLVal.getTBAAInfo());
DesiredLVal = LValue::MakeVectorElt(
DesiredAddr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
} else {
assert(AtomicLVal.isExtVectorElt());
UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo(),
+ AtomicLVal.getTBAAInfo());
DesiredLVal = LValue::MakeExtVectorElt(
DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
}
- UpdateLVal.setTBAAInfo(AtomicLVal.getTBAAInfo());
- DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo());
UpRVal = CGF.EmitLoadOfLValue(UpdateLVal, SourceLocation());
}
// Store new value in the corresponding memory area
@@ -1611,20 +1777,19 @@ static void EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics,
if (AtomicLVal.isBitField()) {
DesiredLVal =
LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
- AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
+ AtomicLVal.getTBAAInfo());
} else if (AtomicLVal.isVectorElt()) {
DesiredLVal =
LValue::MakeVectorElt(DesiredAddr, AtomicLVal.getVectorIdx(),
- AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
+ AtomicLVal.getTBAAInfo());
} else {
assert(AtomicLVal.isExtVectorElt());
DesiredLVal = LValue::MakeExtVectorElt(
DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
}
- DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo());
// Store new value in the corresponding memory area
assert(UpdateRVal.isScalar());
CGF.EmitStoreThroughLValue(UpdateRVal, DesiredLVal);
@@ -1777,8 +1942,7 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
// Other decoration.
if (IsVolatile)
store->setVolatile(true);
- if (dest.getTBAAInfo())
- CGM.DecorateInstructionWithTBAA(store, dest.getTBAAInfo());
+ CGM.DecorateInstructionWithTBAA(store, dest.getTBAAInfo());
return;
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 31632ab6de..850681471d 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -14,10 +14,13 @@
#include "CGBlocks.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
+#include "CGOpenCLRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "ConstantEmitter.h"
+#include "TargetInfo.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
@@ -266,7 +269,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;
@@ -290,7 +293,7 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
const Expr *init = var->getInit();
if (!init) return nullptr;
- return CGM.EmitConstantInit(*var, CGF);
+ return ConstantEmitter(CGM, CGF).tryEmitAbstractForInitializer(*var);
}
/// Get the low bit of a nonzero character count. This is the
@@ -301,21 +304,57 @@ static CharUnits getLowBit(CharUnits v) {
static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
SmallVectorImpl<llvm::Type*> &elementTypes) {
- // The header is basically 'struct { void *; int; int; void *; void *; }'.
- // Assert that that struct is packed.
- assert(CGM.getIntSize() <= CGM.getPointerSize());
- assert(CGM.getIntAlign() <= CGM.getPointerAlign());
- assert((2 * CGM.getIntSize()).isMultipleOf(CGM.getPointerAlign()));
-
- info.BlockAlign = CGM.getPointerAlign();
- info.BlockSize = 3 * CGM.getPointerSize() + 2 * CGM.getIntSize();
assert(elementTypes.empty());
- elementTypes.push_back(CGM.VoidPtrTy);
- elementTypes.push_back(CGM.IntTy);
- elementTypes.push_back(CGM.IntTy);
- elementTypes.push_back(CGM.VoidPtrTy);
- elementTypes.push_back(CGM.getBlockDescriptorType());
+ if (CGM.getLangOpts().OpenCL) {
+ // The header is basically 'struct { int; int; generic void *;
+ // custom_fields; }'. Assert that struct is packed.
+ auto GenericAS =
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic);
+ auto GenPtrAlign =
+ CharUnits::fromQuantity(CGM.getTarget().getPointerAlign(GenericAS) / 8);
+ auto GenPtrSize =
+ CharUnits::fromQuantity(CGM.getTarget().getPointerWidth(GenericAS) / 8);
+ assert(CGM.getIntSize() <= GenPtrSize);
+ assert(CGM.getIntAlign() <= GenPtrAlign);
+ assert((2 * CGM.getIntSize()).isMultipleOf(GenPtrAlign));
+ elementTypes.push_back(CGM.IntTy); /* total size */
+ elementTypes.push_back(CGM.IntTy); /* align */
+ elementTypes.push_back(
+ CGM.getOpenCLRuntime()
+ .getGenericVoidPointerType()); /* invoke function */
+ unsigned Offset =
+ 2 * CGM.getIntSize().getQuantity() + GenPtrSize.getQuantity();
+ unsigned BlockAlign = GenPtrAlign.getQuantity();
+ if (auto *Helper =
+ CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
+ for (auto I : Helper->getCustomFieldTypes()) /* custom fields */ {
+ // TargetOpenCLBlockHelp needs to make sure the struct is packed.
+ // If necessary, add padding fields to the custom fields.
+ unsigned Align = CGM.getDataLayout().getABITypeAlignment(I);
+ if (BlockAlign < Align)
+ BlockAlign = Align;
+ assert(Offset % Align == 0);
+ Offset += CGM.getDataLayout().getTypeAllocSize(I);
+ elementTypes.push_back(I);
+ }
+ }
+ info.BlockAlign = CharUnits::fromQuantity(BlockAlign);
+ info.BlockSize = CharUnits::fromQuantity(Offset);
+ } else {
+ // The header is basically 'struct { void *; int; int; void *; void *; }'.
+ // Assert that that struct is packed.
+ assert(CGM.getIntSize() <= CGM.getPointerSize());
+ assert(CGM.getIntAlign() <= CGM.getPointerAlign());
+ assert((2 * CGM.getIntSize()).isMultipleOf(CGM.getPointerAlign()));
+ info.BlockAlign = CGM.getPointerAlign();
+ info.BlockSize = 3 * CGM.getPointerSize() + 2 * CGM.getIntSize();
+ elementTypes.push_back(CGM.VoidPtrTy);
+ elementTypes.push_back(CGM.IntTy);
+ elementTypes.push_back(CGM.IntTy);
+ elementTypes.push_back(CGM.VoidPtrTy);
+ elementTypes.push_back(CGM.getBlockDescriptorType());
+ }
}
static QualType getCaptureFieldType(const CodeGenFunction &CGF,
@@ -340,8 +379,12 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
SmallVector<llvm::Type*, 8> elementTypes;
initializeForBlockHeader(CGM, info, elementTypes);
-
- if (!block->hasCaptures()) {
+ bool hasNonConstantCustomFields = false;
+ if (auto *OpenCLHelper =
+ CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper())
+ hasNonConstantCustomFields =
+ !OpenCLHelper->areAllCustomFieldValuesConstant(info);
+ if (!block->hasCaptures() && !hasNonConstantCustomFields) {
info.StructureType =
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
info.CanBeGlobal = true;
@@ -619,7 +662,17 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
// Block captures count as local values and have imprecise semantics.
// They also can't be arrays, so need to worry about that.
- if (dtorKind == QualType::DK_objc_strong_lifetime) {
+ //
+ // For const-qualified captures, emit clang.arc.use to ensure the captured
+ // object doesn't get released while we are still depending on its validity
+ // within the block.
+ if (VT.isConstQualified() &&
+ VT.getObjCLifetime() == Qualifiers::OCL_Strong &&
+ CGF.CGM.getCodeGenOpts().OptimizationLevel != 0) {
+ assert(CGF.CGM.getLangOpts().ObjCAutoRefCount &&
+ "expected ObjC ARC to be enabled");
+ destroyer = CodeGenFunction::emitARCIntrinsicUse;
+ } else if (dtorKind == QualType::DK_objc_strong_lifetime) {
destroyer = CodeGenFunction::destroyARCStrongImprecise;
} else {
destroyer = CGF.getDestroyer(dtorKind);
@@ -687,16 +740,27 @@ void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) {
}
/// Emit a block literal expression in the current function.
-llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
+llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr,
+ llvm::Function **InvokeF) {
// If the block has no captures, we won't have a pre-computed
// layout for it.
if (!blockExpr->getBlockDecl()->hasCaptures()) {
- if (llvm::Constant *Block = CGM.getAddrOfGlobalBlockIfEmitted(blockExpr))
+ // The block literal is emitted as a global variable, and the block invoke
+ // function has to be extracted from its initializer.
+ if (llvm::Constant *Block = CGM.getAddrOfGlobalBlockIfEmitted(blockExpr)) {
+ if (InvokeF) {
+ auto *GV = cast<llvm::GlobalVariable>(
+ cast<llvm::Constant>(Block)->stripPointerCasts());
+ auto *BlockInit = cast<llvm::ConstantStruct>(GV->getInitializer());
+ *InvokeF = cast<llvm::Function>(
+ BlockInit->getAggregateElement(2)->stripPointerCasts());
+ }
return Block;
+ }
CGBlockInfo blockInfo(blockExpr->getBlockDecl(), CurFn->getName());
computeBlockInfo(CGM, this, blockInfo);
blockInfo.BlockExpression = blockExpr;
- return EmitBlockLiteral(blockInfo);
+ return EmitBlockLiteral(blockInfo, InvokeF);
}
// Find the block info for this block and take ownership of it.
@@ -705,44 +769,57 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
blockExpr->getBlockDecl()));
blockInfo->BlockExpression = blockExpr;
- return EmitBlockLiteral(*blockInfo);
+ return EmitBlockLiteral(*blockInfo, InvokeF);
}
-llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
+llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo,
+ llvm::Function **InvokeF) {
+ bool IsOpenCL = CGM.getContext().getLangOpts().OpenCL;
+ auto GenVoidPtrTy =
+ IsOpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy;
+ LangAS GenVoidPtrAddr = IsOpenCL ? LangAS::opencl_generic : LangAS::Default;
+ auto GenVoidPtrSize = CharUnits::fromQuantity(
+ CGM.getTarget().getPointerWidth(
+ CGM.getContext().getTargetAddressSpace(GenVoidPtrAddr)) /
+ 8);
// Using the computed layout, generate the actual block function.
bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
- llvm::Constant *blockFn
- = CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo,
- LocalDeclMap,
- isLambdaConv);
- blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
+ auto *InvokeFn = CodeGenFunction(CGM, true).GenerateBlockFunction(
+ CurGD, blockInfo, LocalDeclMap, isLambdaConv, blockInfo.CanBeGlobal);
+ if (InvokeF)
+ *InvokeF = InvokeFn;
+ auto *blockFn = llvm::ConstantExpr::getPointerCast(InvokeFn, GenVoidPtrTy);
// If there is nothing to capture, we can emit this as a global block.
if (blockInfo.CanBeGlobal)
- return buildGlobalBlock(CGM, blockInfo, blockFn);
+ return CGM.getAddrOfGlobalBlockIfEmitted(blockInfo.BlockExpression);
// Otherwise, we have to emit this as a local block.
- 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.
- llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo);
-
Address blockAddr = blockInfo.LocalAddress;
assert(blockAddr.isValid() && "block has no address!");
- // Compute the initial on-stack block flags.
- BlockFlags flags = BLOCK_HAS_SIGNATURE;
- if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT;
- if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
- if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ;
- if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
+ llvm::Constant *isa;
+ llvm::Constant *descriptor;
+ BlockFlags flags;
+ if (!IsOpenCL) {
+ isa = llvm::ConstantExpr::getBitCast(CGM.getNSConcreteStackBlock(),
+ VoidPtrTy);
+
+ // Build the block descriptor.
+ descriptor = buildBlockDescriptor(CGM, blockInfo);
+
+ // Compute the initial on-stack block flags.
+ flags = BLOCK_HAS_SIGNATURE;
+ if (blockInfo.HasCapturedVariableLayout)
+ flags |= BLOCK_HAS_EXTENDED_LAYOUT;
+ if (blockInfo.NeedsCopyDispose)
+ flags |= BLOCK_HAS_COPY_DISPOSE;
+ if (blockInfo.HasCXXObject)
+ flags |= BLOCK_HAS_CXX_OBJ;
+ if (blockInfo.UsesStret)
+ flags |= BLOCK_USE_STRET;
+ }
auto projectField =
[&](unsigned index, CharUnits offset, const Twine &name) -> Address {
@@ -766,13 +843,33 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
index++;
};
- addHeaderField(isa, getPointerSize(), "block.isa");
- addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
- getIntSize(), "block.flags");
- addHeaderField(llvm::ConstantInt::get(IntTy, 0),
- getIntSize(), "block.reserved");
- addHeaderField(blockFn, getPointerSize(), "block.invoke");
- addHeaderField(descriptor, getPointerSize(), "block.descriptor");
+ if (!IsOpenCL) {
+ addHeaderField(isa, getPointerSize(), "block.isa");
+ addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
+ getIntSize(), "block.flags");
+ addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(),
+ "block.reserved");
+ } else {
+ addHeaderField(
+ llvm::ConstantInt::get(IntTy, blockInfo.BlockSize.getQuantity()),
+ getIntSize(), "block.size");
+ addHeaderField(
+ llvm::ConstantInt::get(IntTy, blockInfo.BlockAlign.getQuantity()),
+ getIntSize(), "block.align");
+ }
+ addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
+ if (!IsOpenCL)
+ addHeaderField(descriptor, getPointerSize(), "block.descriptor");
+ else if (auto *Helper =
+ CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
+ for (auto I : Helper->getCustomFieldValues(*this, blockInfo)) {
+ addHeaderField(
+ I.first,
+ CharUnits::fromQuantity(
+ CGM.getDataLayout().getTypeAllocSize(I.first->getType())),
+ I.second);
+ }
+ }
}
// Finally, capture all the values into the block.
@@ -866,6 +963,13 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
} else if (type->isReferenceType()) {
Builder.CreateStore(src.getPointer(), blockField);
+ // If type is const-qualified, copy the value into the block field.
+ } else if (type.isConstQualified() &&
+ type.getObjCLifetime() == Qualifiers::OCL_Strong &&
+ CGM.getCodeGenOpts().OptimizationLevel != 0) {
+ llvm::Value *value = Builder.CreateLoad(src, "captured");
+ Builder.CreateStore(value, blockField);
+
// If this is an ARC __strong block-pointer variable, don't do a
// block copy.
//
@@ -886,9 +990,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
} else {
// Fake up a new variable so that EmitScalarInit doesn't think
// we're referring to the variable in its own initializer.
- ImplicitParamDecl blockFieldPseudoVar(getContext(), /*DC*/ nullptr,
- SourceLocation(), /*name*/ nullptr,
- type);
+ ImplicitParamDecl BlockFieldPseudoVar(getContext(), type,
+ ImplicitParamDecl::Other);
// We use one of these or the other depending on whether the
// reference is nested.
@@ -901,7 +1004,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// FIXME: Pass a specific location for the expr init so that the store is
// attributed to a reasonable location - otherwise it may be attributed to
// locations of subexpressions in the initialization.
- EmitExprAsInit(&l2r, &blockFieldPseudoVar,
+ EmitExprAsInit(&l2r, &BlockFieldPseudoVar,
MakeAddrLValue(blockField, type, AlignmentSource::Decl),
/*captured by init*/ false);
}
@@ -944,9 +1047,8 @@ llvm::Type *CodeGenModule::getBlockDescriptorType() {
// const char *signature; // the block signature
// const char *layout; // reserved
// };
- BlockDescriptorType =
- llvm::StructType::create("struct.__block_descriptor",
- UnsignedLongTy, UnsignedLongTy, nullptr);
+ BlockDescriptorType = llvm::StructType::create(
+ "struct.__block_descriptor", UnsignedLongTy, UnsignedLongTy);
// Now form a pointer to that.
unsigned AddrSpace = 0;
@@ -962,22 +1064,38 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
llvm::Type *BlockDescPtrTy = getBlockDescriptorType();
- // struct __block_literal_generic {
- // void *__isa;
- // int __flags;
- // int __reserved;
- // void (*__invoke)(void *);
- // struct __block_descriptor *__descriptor;
- // };
- GenericBlockLiteralType =
- llvm::StructType::create("struct.__block_literal_generic",
- VoidPtrTy, IntTy, IntTy, VoidPtrTy,
- BlockDescPtrTy, nullptr);
+ if (getLangOpts().OpenCL) {
+ // struct __opencl_block_literal_generic {
+ // int __size;
+ // int __align;
+ // __generic void *__invoke;
+ // /* custom fields */
+ // };
+ SmallVector<llvm::Type *, 8> StructFields(
+ {IntTy, IntTy, getOpenCLRuntime().getGenericVoidPointerType()});
+ if (auto *Helper = getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
+ for (auto I : Helper->getCustomFieldTypes())
+ StructFields.push_back(I);
+ }
+ GenericBlockLiteralType = llvm::StructType::create(
+ StructFields, "struct.__opencl_block_literal_generic");
+ } else {
+ // struct __block_literal_generic {
+ // void *__isa;
+ // int __flags;
+ // int __reserved;
+ // void (*__invoke)(void *);
+ // struct __block_descriptor *__descriptor;
+ // };
+ GenericBlockLiteralType =
+ llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy,
+ IntTy, IntTy, VoidPtrTy, BlockDescPtrTy);
+ }
return GenericBlockLiteralType;
}
-RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
+RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
const BlockPointerType *BPT =
E->getCallee()->getType()->getAs<BlockPointerType>();
@@ -1002,8 +1120,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
// Get the function pointer from the literal.
llvm::Value *FuncPtr =
- Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr, 3);
-
+ Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr,
+ CGM.getLangOpts().OpenCL ? 2 : 3);
// Add the block literal.
CallArgList Args;
@@ -1011,8 +1129,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
QualType VoidPtrQualTy = getContext().VoidPtrTy;
llvm::Type *GenericVoidPtrTy = VoidPtrTy;
if (getLangOpts().OpenCL) {
- GenericVoidPtrTy = Builder.getInt8PtrTy(
- getContext().getTargetAddressSpace(LangAS::opencl_generic));
+ GenericVoidPtrTy = CGM.getOpenCLRuntime().getGenericVoidPointerType();
VoidPtrQualTy =
getContext().getPointerType(getContext().getAddrSpaceQualType(
getContext().VoidTy, LangAS::opencl_generic));
@@ -1037,7 +1154,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
- Func = Builder.CreateBitCast(Func, BlockFTyPtr);
+ Func = Builder.CreatePointerCast(Func, BlockFTyPtr);
// Prepare the callee.
CGCallee Callee(CGCalleeInfo(), Func);
@@ -1072,8 +1189,8 @@ Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable,
variable->getName());
}
- if (auto refType = capture.fieldType()->getAs<ReferenceType>())
- addr = EmitLoadOfReference(addr, refType);
+ if (capture.fieldType()->isReferenceType())
+ addr = EmitLoadOfReference(MakeAddrLValue(addr, capture.fieldType()));
return addr;
}
@@ -1098,17 +1215,14 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *BE,
computeBlockInfo(*this, nullptr, blockInfo);
// Using that metadata, generate the actual block function.
- llvm::Constant *blockFn;
{
CodeGenFunction::DeclMapTy LocalDeclMap;
- blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(),
- blockInfo,
- LocalDeclMap,
- false);
+ CodeGenFunction(*this).GenerateBlockFunction(
+ GlobalDecl(), blockInfo, LocalDeclMap,
+ /*IsLambdaConversionToBlock*/ false, /*BuildGlobalBlock*/ true);
}
- blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
- return buildGlobalBlock(*this, blockInfo, blockFn);
+ return getAddrOfGlobalBlockIfEmitted(BE);
}
static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
@@ -1125,28 +1239,37 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
ConstantInitBuilder builder(CGM);
auto fields = builder.beginStruct();
- // isa
- fields.add(
- (!CGM.getContext().getLangOpts().OpenCL)
- ? CGM.getNSConcreteGlobalBlock()
- : CGM.getNullPointer(cast<llvm::PointerType>(
- CGM.getNSConcreteGlobalBlock()->getType()),
- QualType(CGM.getContext().VoidPtrTy)));
+ bool IsOpenCL = CGM.getLangOpts().OpenCL;
+ if (!IsOpenCL) {
+ // isa
+ fields.add(CGM.getNSConcreteGlobalBlock());
+
+ // __flags
+ BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
+ if (blockInfo.UsesStret)
+ flags |= BLOCK_USE_STRET;
- // __flags
- BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
- if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
-
- fields.addInt(CGM.IntTy, flags.getBitMask());
+ fields.addInt(CGM.IntTy, flags.getBitMask());
- // Reserved
- fields.addInt(CGM.IntTy, 0);
+ // Reserved
+ fields.addInt(CGM.IntTy, 0);
+ } else {
+ fields.addInt(CGM.IntTy, blockInfo.BlockSize.getQuantity());
+ fields.addInt(CGM.IntTy, blockInfo.BlockAlign.getQuantity());
+ }
// Function
fields.add(blockFn);
- // Descriptor
- fields.add(buildBlockDescriptor(CGM, blockInfo));
+ if (!IsOpenCL) {
+ // Descriptor
+ fields.add(buildBlockDescriptor(CGM, blockInfo));
+ } else if (auto *Helper =
+ CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
+ for (auto I : Helper->getCustomFieldValues(CGM, blockInfo)) {
+ fields.add(I);
+ }
+ }
unsigned AddrSpace = 0;
if (CGM.getContext().getLangOpts().OpenCL)
@@ -1170,20 +1293,17 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D,
llvm::Value *arg) {
assert(BlockInfo && "not emitting prologue of block invocation function?!");
- llvm::Value *localAddr = nullptr;
- if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
- // Allocate a stack slot to let the debug info survive the RA.
- Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
- Builder.CreateStore(arg, alloc);
- localAddr = Builder.CreateLoad(alloc);
- }
-
+ // Allocate a stack slot like for any local variable to guarantee optimal
+ // debug info at -O0. The mem2reg pass will eliminate it when optimizing.
+ Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
+ Builder.CreateStore(arg, alloc);
if (CGDebugInfo *DI = getDebugInfo()) {
if (CGM.getCodeGenOpts().getDebugInfo() >=
codegenoptions::LimitedDebugInfo) {
DI->setLocation(D->getLocation());
- DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, arg, argNum,
- localAddr, Builder);
+ DI->EmitDeclareOfBlockLiteralArgVariable(
+ *BlockInfo, D->getName(), argNum,
+ cast<llvm::AllocaInst>(alloc.getPointer()), Builder);
}
}
@@ -1211,7 +1331,8 @@ llvm::Function *
CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const CGBlockInfo &blockInfo,
const DeclMapTy &ldm,
- bool IsLambdaConversionToBlock) {
+ bool IsLambdaConversionToBlock,
+ bool BuildGlobalBlock) {
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
CurGD = GD;
@@ -1240,7 +1361,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// 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 is used therefore to be able to accommodate both private and
// generic AS in one implementation.
if (getLangOpts().OpenCL)
selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType(
@@ -1248,9 +1369,10 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
- ImplicitParamDecl selfDecl(getContext(), const_cast<BlockDecl*>(blockDecl),
- SourceLocation(), II, selfTy);
- args.push_back(&selfDecl);
+ ImplicitParamDecl SelfDecl(getContext(), const_cast<BlockDecl *>(blockDecl),
+ SourceLocation(), II, selfTy,
+ ImplicitParamDecl::ObjCSelf);
+ args.push_back(&SelfDecl);
// Now add the rest of the parameters.
args.append(blockDecl->param_begin(), blockDecl->param_end());
@@ -1269,6 +1391,14 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
fnLLVMType, llvm::GlobalValue::InternalLinkage, name, &CGM.getModule());
CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo);
+ if (BuildGlobalBlock) {
+ auto GenVoidPtrTy = getContext().getLangOpts().OpenCL
+ ? CGM.getOpenCLRuntime().getGenericVoidPointerType()
+ : VoidPtrTy;
+ buildGlobalBlock(CGM, blockInfo,
+ llvm::ConstantExpr::getPointerCast(fn, GenVoidPtrTy));
+ }
+
// Begin generating the function.
StartFunction(blockDecl, fnType->getReturnType(), fn, fnInfo, args,
blockDecl->getLocation(),
@@ -1483,12 +1613,12 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- ImplicitParamDecl dstDecl(getContext(), nullptr, SourceLocation(), nullptr,
- C.VoidPtrTy);
- args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(getContext(), nullptr, SourceLocation(), nullptr,
- C.VoidPtrTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl DstDecl(getContext(), C.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&DstDecl);
+ ImplicitParamDecl SrcDecl(getContext(), C.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -1514,17 +1644,15 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
CGM.SetInternalFunctionAttributes(nullptr, Fn, FI);
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(FD, C.VoidTy, Fn, FI, args);
- // Create a scope with an artificial location for the body of this function.
- auto AL = ApplyDebugLocation::CreateArtificial(*this);
+ ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()};
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- Address src = GetAddrOfLocalVar(&srcDecl);
+ Address src = GetAddrOfLocalVar(&SrcDecl);
src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign);
src = Builder.CreateBitCast(src, structPtrTy, "block.source");
- Address dst = GetAddrOfLocalVar(&dstDecl);
+ Address dst = GetAddrOfLocalVar(&DstDecl);
dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
@@ -1660,9 +1788,9 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- ImplicitParamDecl srcDecl(getContext(), nullptr, SourceLocation(), nullptr,
- C.VoidPtrTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl SrcDecl(getContext(), C.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -1686,14 +1814,12 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
CGM.SetInternalFunctionAttributes(nullptr, Fn, FI);
- // Create a scope with an artificial location for the body of this function.
- auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(FD, C.VoidTy, Fn, FI, args);
- auto AL = ApplyDebugLocation::CreateArtificial(*this);
+ ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()};
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- Address src = GetAddrOfLocalVar(&srcDecl);
+ Address src = GetAddrOfLocalVar(&SrcDecl);
src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign);
src = Builder.CreateBitCast(src, structPtrTy, "block");
@@ -1902,13 +2028,13 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo,
QualType R = Context.VoidTy;
FunctionArgList args;
- ImplicitParamDecl dst(CGF.getContext(), nullptr, SourceLocation(), nullptr,
- Context.VoidPtrTy);
- args.push_back(&dst);
+ ImplicitParamDecl Dst(CGF.getContext(), Context.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Dst);
- ImplicitParamDecl src(CGF.getContext(), nullptr, SourceLocation(), nullptr,
- Context.VoidPtrTy);
- args.push_back(&src);
+ ImplicitParamDecl Src(CGF.getContext(), Context.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Src);
const CGFunctionInfo &FI =
CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(R, args);
@@ -1939,7 +2065,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo,
llvm::Type *byrefPtrType = byrefInfo.Type->getPointerTo(0);
// dst->x
- Address destField = CGF.GetAddrOfLocalVar(&dst);
+ Address destField = CGF.GetAddrOfLocalVar(&Dst);
destField = Address(CGF.Builder.CreateLoad(destField),
byrefInfo.ByrefAlignment);
destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
@@ -1947,7 +2073,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo,
"dest-object");
// src->x
- Address srcField = CGF.GetAddrOfLocalVar(&src);
+ Address srcField = CGF.GetAddrOfLocalVar(&Src);
srcField = Address(CGF.Builder.CreateLoad(srcField),
byrefInfo.ByrefAlignment);
srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
@@ -1979,9 +2105,9 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
QualType R = Context.VoidTy;
FunctionArgList args;
- ImplicitParamDecl src(CGF.getContext(), nullptr, SourceLocation(), nullptr,
- Context.VoidPtrTy);
- args.push_back(&src);
+ ImplicitParamDecl Src(CGF.getContext(), Context.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Src);
const CGFunctionInfo &FI =
CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(R, args);
@@ -2010,7 +2136,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
CGF.StartFunction(FD, R, Fn, FI, args);
if (generator.needsDispose()) {
- Address addr = CGF.GetAddrOfLocalVar(&src);
+ Address addr = CGF.GetAddrOfLocalVar(&Src);
addr = Address(CGF.Builder.CreateLoad(addr), byrefInfo.ByrefAlignment);
auto byrefPtrType = byrefInfo.Type->getPointerTo(0);
addr = CGF.Builder.CreateBitCast(addr, byrefPtrType);
diff --git a/lib/CodeGen/CGBuilder.h b/lib/CodeGen/CGBuilder.h
index 42f9a428bb..61fe4aac3a 100644
--- a/lib/CodeGen/CGBuilder.h
+++ b/lib/CodeGen/CGBuilder.h
@@ -145,6 +145,13 @@ public:
Addr.getAlignment());
}
+ using CGBuilderBaseTy::CreateAddrSpaceCast;
+ Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty,
+ const llvm::Twine &Name = "") {
+ return Address(CreateAddrSpaceCast(Addr.getPointer(), Ty, Name),
+ Addr.getAlignment());
+ }
+
/// Cast the element type of the given address to a different type,
/// preserving information like the alignment and address space.
Address CreateElementBitCast(Address Addr, llvm::Type *Ty,
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 23b3a80180..bc37afa284 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -16,6 +16,7 @@
#include "CGOpenCLRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -29,6 +30,8 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/ConvertUTF.h"
#include <sstream>
using namespace clang;
@@ -470,10 +473,13 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
assert(Ptr->getType()->isPointerTy() &&
"Non-pointer passed to __builtin_object_size?");
- // 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);
Value *F = CGM.getIntrinsic(Intrinsic::objectsize, {ResType, Ptr->getType()});
- return Builder.CreateCall(F, {Ptr, CI});
+
+ // 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
@@ -489,6 +495,7 @@ enum class CodeGenFunction::MSVCIntrin {
_InterlockedIncrement,
_InterlockedOr,
_InterlockedXor,
+ _interlockedbittestandset,
__fastfail,
};
@@ -556,6 +563,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(
@@ -598,9 +621,9 @@ Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID,
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, {Int32Ty}, false);
llvm::InlineAsm *IA =
llvm::InlineAsm::get(FTy, Asm, Constraints, /*SideEffects=*/true);
- llvm::AttributeSet NoReturnAttr =
- AttributeSet::get(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoReturn);
+ 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();
@@ -621,6 +644,200 @@ struct CallObjCArcUse final : EHScopeStack::Cleanup {
};
}
+Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
+ BuiltinCheckKind Kind) {
+ assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero)
+ && "Unsupported builtin check kind");
+
+ Value *ArgValue = EmitScalarExpr(E);
+ if (!SanOpts.has(SanitizerKind::Builtin) || !getTarget().isCLZForZeroUndef())
+ return ArgValue;
+
+ SanitizerScope SanScope(this);
+ Value *Cond = Builder.CreateICmpNE(
+ ArgValue, llvm::Constant::getNullValue(ArgValue->getType()));
+ EmitCheck(std::make_pair(Cond, SanitizerKind::Builtin),
+ SanitizerHandler::InvalidBuiltin,
+ {EmitCheckSourceLocation(E->getExprLoc()),
+ llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)},
+ None);
+ return ArgValue;
+}
+
+/// Get the argument type for arguments to os_log_helper.
+static CanQualType getOSLogArgType(ASTContext &C, int Size) {
+ QualType UnsignedTy = C.getIntTypeForBitwidth(Size * 8, /*Signed=*/false);
+ return C.getCanonicalType(UnsignedTy);
+}
+
+llvm::Function *CodeGenFunction::generateBuiltinOSLogHelperFunction(
+ const analyze_os_log::OSLogBufferLayout &Layout,
+ CharUnits BufferAlignment) {
+ ASTContext &Ctx = getContext();
+
+ llvm::SmallString<64> Name;
+ {
+ raw_svector_ostream OS(Name);
+ OS << "__os_log_helper";
+ OS << "_" << BufferAlignment.getQuantity();
+ OS << "_" << int(Layout.getSummaryByte());
+ OS << "_" << int(Layout.getNumArgsByte());
+ for (const auto &Item : Layout.Items)
+ OS << "_" << int(Item.getSizeByte()) << "_"
+ << int(Item.getDescriptorByte());
+ }
+
+ if (llvm::Function *F = CGM.getModule().getFunction(Name))
+ return F;
+
+ llvm::SmallVector<ImplicitParamDecl, 4> Params;
+ Params.emplace_back(Ctx, nullptr, SourceLocation(), &Ctx.Idents.get("buffer"),
+ Ctx.VoidPtrTy, ImplicitParamDecl::Other);
+
+ for (unsigned int I = 0, E = Layout.Items.size(); I < E; ++I) {
+ char Size = Layout.Items[I].getSizeByte();
+ if (!Size)
+ continue;
+
+ Params.emplace_back(
+ Ctx, nullptr, SourceLocation(),
+ &Ctx.Idents.get(std::string("arg") + llvm::to_string(I)),
+ getOSLogArgType(Ctx, Size), ImplicitParamDecl::Other);
+ }
+
+ FunctionArgList Args;
+ for (auto &P : Params)
+ Args.push_back(&P);
+
+ // The helper function has linkonce_odr linkage to enable the linker to merge
+ // identical functions. To ensure the merging always happens, 'noinline' is
+ // attached to the function when compiling with -Oz.
+ const CGFunctionInfo &FI =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
+ llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI);
+ llvm::Function *Fn = llvm::Function::Create(
+ FuncTy, llvm::GlobalValue::LinkOnceODRLinkage, Name, &CGM.getModule());
+ Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ CGM.SetLLVMFunctionAttributes(nullptr, FI, Fn);
+ CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Fn);
+
+ // Attach 'noinline' at -Oz.
+ if (CGM.getCodeGenOpts().OptimizeSize == 2)
+ Fn->addFnAttr(llvm::Attribute::NoInline);
+
+ auto NL = ApplyDebugLocation::CreateEmpty(*this);
+ IdentifierInfo *II = &Ctx.Idents.get(Name);
+ FunctionDecl *FD = FunctionDecl::Create(
+ Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
+ Ctx.VoidTy, nullptr, SC_PrivateExtern, false, false);
+
+ StartFunction(FD, Ctx.VoidTy, Fn, FI, Args);
+
+ // Create a scope with an artificial location for the body of this function.
+ auto AL = ApplyDebugLocation::CreateArtificial(*this);
+
+ CharUnits Offset;
+ Address BufAddr(Builder.CreateLoad(GetAddrOfLocalVar(&Params[0]), "buf"),
+ BufferAlignment);
+ Builder.CreateStore(Builder.getInt8(Layout.getSummaryByte()),
+ Builder.CreateConstByteGEP(BufAddr, Offset++, "summary"));
+ Builder.CreateStore(Builder.getInt8(Layout.getNumArgsByte()),
+ Builder.CreateConstByteGEP(BufAddr, Offset++, "numArgs"));
+
+ unsigned I = 1;
+ for (const auto &Item : Layout.Items) {
+ Builder.CreateStore(
+ Builder.getInt8(Item.getDescriptorByte()),
+ Builder.CreateConstByteGEP(BufAddr, Offset++, "argDescriptor"));
+ Builder.CreateStore(
+ Builder.getInt8(Item.getSizeByte()),
+ Builder.CreateConstByteGEP(BufAddr, Offset++, "argSize"));
+
+ CharUnits Size = Item.size();
+ if (!Size.getQuantity())
+ continue;
+
+ Address Arg = GetAddrOfLocalVar(&Params[I]);
+ Address Addr = Builder.CreateConstByteGEP(BufAddr, Offset, "argData");
+ Addr = Builder.CreateBitCast(Addr, Arg.getPointer()->getType(),
+ "argDataCast");
+ Builder.CreateStore(Builder.CreateLoad(Arg), Addr);
+ Offset += Size;
+ ++I;
+ }
+
+ FinishFunction();
+
+ return Fn;
+}
+
+RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) {
+ assert(E.getNumArgs() >= 2 &&
+ "__builtin_os_log_format takes at least 2 arguments");
+ ASTContext &Ctx = getContext();
+ analyze_os_log::OSLogBufferLayout Layout;
+ analyze_os_log::computeOSLogBufferLayout(Ctx, &E, Layout);
+ Address BufAddr = EmitPointerWithAlignment(E.getArg(0));
+ llvm::SmallVector<llvm::Value *, 4> RetainableOperands;
+
+ // Ignore argument 1, the format string. It is not currently used.
+ CallArgList Args;
+ Args.add(RValue::get(BufAddr.getPointer()), Ctx.VoidPtrTy);
+
+ for (const auto &Item : Layout.Items) {
+ int Size = Item.getSizeByte();
+ if (!Size)
+ continue;
+
+ llvm::Value *ArgVal;
+
+ if (const Expr *TheExpr = Item.getExpr()) {
+ ArgVal = EmitScalarExpr(TheExpr, /*Ignore*/ false);
+
+ // Check if this is a retainable type.
+ if (TheExpr->getType()->isObjCRetainableType()) {
+ assert(getEvaluationKind(TheExpr->getType()) == TEK_Scalar &&
+ "Only scalar can be a ObjC retainable type");
+ // Check if the object is constant, if not, save it in
+ // RetainableOperands.
+ if (!isa<Constant>(ArgVal))
+ RetainableOperands.push_back(ArgVal);
+ }
+ } else {
+ ArgVal = Builder.getInt32(Item.getConstValue().getQuantity());
+ }
+
+ unsigned ArgValSize =
+ CGM.getDataLayout().getTypeSizeInBits(ArgVal->getType());
+ llvm::IntegerType *IntTy = llvm::Type::getIntNTy(getLLVMContext(),
+ ArgValSize);
+ ArgVal = Builder.CreateBitOrPointerCast(ArgVal, IntTy);
+ CanQualType ArgTy = getOSLogArgType(Ctx, Size);
+ // If ArgVal has type x86_fp80, zero-extend ArgVal.
+ ArgVal = Builder.CreateZExtOrBitCast(ArgVal, ConvertType(ArgTy));
+ Args.add(RValue::get(ArgVal), ArgTy);
+ }
+
+ const CGFunctionInfo &FI =
+ CGM.getTypes().arrangeBuiltinFunctionCall(Ctx.VoidTy, Args);
+ llvm::Function *F = CodeGenFunction(CGM).generateBuiltinOSLogHelperFunction(
+ Layout, BufAddr.getAlignment());
+ EmitCall(FI, CGCallee::forDirect(F), ReturnValueSlot(), Args);
+
+ // Push a clang.arc.use cleanup for each object in RetainableOperands. The
+ // cleanup will cause the use to appear after the final log call, keeping
+ // the object valid while it’s held in the log buffer. Note that if there’s
+ // a release cleanup on the object, it will already be active; since
+ // cleanups are emitted in reverse order, the use will occur before the
+ // object is released.
+ if (!RetainableOperands.empty() && getLangOpts().ObjCAutoRefCount &&
+ CGM.getCodeGenOpts().OptimizationLevel != 0)
+ for (llvm::Value *Object : RetainableOperands)
+ pushFullExprCleanup<CallObjCArcUse>(getARCCleanupKind(), Object);
+
+ return RValue::get(BufAddr.getPointer());
+}
+
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -640,7 +857,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
default: break; // Handle intrinsics and libm functions below.
case Builtin::BI__builtin___CFStringMakeConstantString:
case Builtin::BI__builtin___NSStringMakeConstantString:
- return RValue::get(CGM.EmitConstantExpr(E, E->getType(), nullptr));
+ return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
case Builtin::BI__va_start:
@@ -772,7 +989,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ Value *ArgValue = EmitCheckedArgForBuiltin(E->getArg(0), BCK_CTZPassedZero);
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
@@ -789,7 +1006,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__builtin_clz:
case Builtin::BI__builtin_clzl:
case Builtin::BI__builtin_clzll: {
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ Value *ArgValue = EmitCheckedArgForBuiltin(E->getArg(0), BCK_CLZPassedZero);
llvm::Type *ArgType = ArgValue->getType();
Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
@@ -1326,8 +1543,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::ConstantInt::get(Int32Ty, Offset)));
}
case Builtin::BI__builtin_return_address: {
- Value *Depth =
- CGM.EmitConstantExpr(E->getArg(0), getContext().UnsignedIntTy, this);
+ Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0),
+ getContext().UnsignedIntTy);
Value *F = CGM.getIntrinsic(Intrinsic::returnaddress);
return RValue::get(Builder.CreateCall(F, Depth));
}
@@ -1336,8 +1553,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F, Builder.getInt32(0)));
}
case Builtin::BI__builtin_frame_address: {
- Value *Depth =
- CGM.EmitConstantExpr(E->getArg(0), getContext().UnsignedIntTy, this);
+ Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0),
+ getContext().UnsignedIntTy);
Value *F = CGM.getIntrinsic(Intrinsic::frameaddress);
return RValue::get(Builder.CreateCall(F, Depth));
}
@@ -1790,12 +2007,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__atomic_signal_fence:
case Builtin::BI__c11_atomic_thread_fence:
case Builtin::BI__c11_atomic_signal_fence: {
- llvm::SynchronizationScope Scope;
+ llvm::SyncScope::ID SSID;
if (BuiltinID == Builtin::BI__atomic_signal_fence ||
BuiltinID == Builtin::BI__c11_atomic_signal_fence)
- Scope = llvm::SingleThread;
+ SSID = llvm::SyncScope::SingleThread;
else
- Scope = llvm::CrossThread;
+ SSID = llvm::SyncScope::System;
Value *Order = EmitScalarExpr(E->getArg(0));
if (isa<llvm::ConstantInt>(Order)) {
int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
@@ -1805,17 +2022,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
case 1: // memory_order_consume
case 2: // memory_order_acquire
- Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID);
break;
case 3: // memory_order_release
- Builder.CreateFence(llvm::AtomicOrdering::Release, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Release, SSID);
break;
case 4: // memory_order_acq_rel
- Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID);
break;
case 5: // memory_order_seq_cst
- Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID);
break;
}
return RValue::get(nullptr);
@@ -1832,23 +2048,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB);
Builder.SetInsertPoint(AcquireBB);
- Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(1), AcquireBB);
SI->addCase(Builder.getInt32(2), AcquireBB);
Builder.SetInsertPoint(ReleaseBB);
- Builder.CreateFence(llvm::AtomicOrdering::Release, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Release, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(3), ReleaseBB);
Builder.SetInsertPoint(AcqRelBB);
- Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(4), AcqRelBB);
Builder.SetInsertPoint(SeqCstBB);
- Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(5), SeqCstBB);
@@ -1856,24 +2072,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(nullptr);
}
- // Library functions with special handling.
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
- case Builtin::BIsqrtl: {
- // Transform a call to sqrt* into a @llvm.sqrt.* intrinsic call, but only
- // in finite- or unsafe-math mode (the intrinsic has different semantics
- // for handling negative numbers compared to the library function, so
- // -fmath-errno=0 is not enough).
- if (!FD->hasAttr<ConstAttr>())
- break;
- if (!(CGM.getCodeGenOpts().UnsafeFPMath ||
- CGM.getCodeGenOpts().NoNaNsFPMath))
- break;
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = Arg0->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::sqrt, ArgType);
- return RValue::get(Builder.CreateCall(F, Arg0));
- }
+ case Builtin::BIsqrtl:
+ // Builtins have the same semantics as library functions. The LLVM intrinsic
+ // has the same semantics as the library function except it does not set
+ // errno. Thus, we can transform either sqrt or __builtin_sqrt to @llvm.sqrt
+ // if the call is 'const' (the call must not set errno).
+ //
+ // FIXME: The builtin cases are not here because they are marked 'const' in
+ // Builtins.def. So that means they are wrongly defined to have different
+ // semantics than the library functions. If we included them here, we would
+ // turn them into LLVM intrinsics regardless of whether -fmath-errno was on.
+ if (FD->hasAttr<ConstAttr>())
+ return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt));
+ break;
case Builtin::BI__builtin_pow:
case Builtin::BI__builtin_powf:
@@ -1913,6 +2126,28 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateZExt(EmitSignBit(*this, EmitScalarExpr(E->getArg(0))),
ConvertType(E->getType())));
}
+ case Builtin::BI__annotation: {
+ // Re-encode each wide string to UTF8 and make an MDString.
+ SmallVector<Metadata *, 1> Strings;
+ for (const Expr *Arg : E->arguments()) {
+ const auto *Str = cast<StringLiteral>(Arg->IgnoreParenCasts());
+ assert(Str->getCharByteWidth() == 2);
+ StringRef WideBytes = Str->getBytes();
+ std::string StrUtf8;
+ if (!convertUTF16ToUTF8String(
+ makeArrayRef(WideBytes.data(), WideBytes.size()), StrUtf8)) {
+ CGM.ErrorUnsupported(E, "non-UTF16 __annotation argument");
+ continue;
+ }
+ Strings.push_back(llvm::MDString::get(getLLVMContext(), StrUtf8));
+ }
+
+ // Build and MDTuple of MDStrings and emit the intrinsic call.
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::codeview_annotation, {});
+ MDTuple *StrTuple = MDTuple::get(getLLVMContext(), Strings);
+ Builder.CreateCall(F, MetadataAsValue::get(getLLVMContext(), StrTuple));
+ return RValue::getIgnored();
+ }
case Builtin::BI__builtin_annotation: {
llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0));
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::annotation,
@@ -2235,16 +2470,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:
@@ -2258,9 +2486,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);
@@ -2278,9 +2506,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;
@@ -2316,10 +2544,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
}
- case Builtin::BI__fastfail: {
+ case Builtin::BI__fastfail:
return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::__fastfail, E));
- break;
- }
case Builtin::BI__builtin_coro_size: {
auto & Context = getContext();
@@ -2550,47 +2776,77 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// 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, GenericVoidPtrTy};
+ llvm::Type *ArgTys[] = {QueueTy, Int32Ty, RangeTy, GenericVoidPtrTy,
+ GenericVoidPtrTy};
llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys, 4), false);
+ Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
- llvm::Value *Block = Builder.CreatePointerCast(
- EmitScalarExpr(E->getArg(3)), GenericVoidPtrTy);
+ auto Info =
+ CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(3));
+ llvm::Value *Kernel =
+ Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
+ llvm::Value *Block =
+ Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
AttrBuilder B;
B.addAttribute(Attribute::ByVal);
- AttributeSet ByValAttrSet =
- AttributeSet::get(CGM.getModule().getContext(), 3U, B);
+ llvm::AttributeList ByValAttrSet =
+ llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B);
auto RTCall =
Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name, ByValAttrSet),
- {Queue, Flags, Range, Block});
+ {Queue, Flags, Range, Kernel, Block});
RTCall->setAttributes(ByValAttrSet);
return RValue::get(RTCall);
}
assert(NumArgs >= 5 && "Invalid enqueue_kernel signature");
+ // Create a temporary array to hold the sizes of local pointer arguments
+ // for the block. \p First is the position of the first size argument.
+ auto CreateArrayForSizeVar = [=](unsigned First) {
+ auto *AT = llvm::ArrayType::get(SizeTy, NumArgs - First);
+ auto *Arr = Builder.CreateAlloca(AT);
+ llvm::Value *Ptr;
+ // Each of the following arguments specifies the size of the corresponding
+ // argument passed to the enqueued block.
+ auto *Zero = llvm::ConstantInt::get(IntTy, 0);
+ for (unsigned I = First; I < NumArgs; ++I) {
+ auto *Index = llvm::ConstantInt::get(IntTy, I - First);
+ auto *GEP = Builder.CreateGEP(Arr, {Zero, Index});
+ if (I == First)
+ Ptr = GEP;
+ auto *V =
+ Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(I)), SizeTy);
+ Builder.CreateAlignedStore(
+ V, GEP, CGM.getDataLayout().getPrefTypeAlignment(SizeTy));
+ }
+ return Ptr;
+ };
+
// Could have events and/or vaargs.
if (E->getArg(3)->getType()->isBlockPointerType()) {
// No events passed, but has variadic arguments.
Name = "__enqueue_kernel_vaargs";
- llvm::Value *Block = Builder.CreatePointerCast(
- EmitScalarExpr(E->getArg(3)), GenericVoidPtrTy);
+ auto Info =
+ CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(3));
+ llvm::Value *Kernel =
+ Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
+ auto *Block = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
+ auto *PtrToSizeArray = CreateArrayForSizeVar(4);
+
// 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,
- GenericVoidPtrTy, IntTy};
-
- // Each of the following arguments specifies the size of the corresponding
- // argument passed to the enqueued block.
- for (unsigned I = 4/*Position of the first size arg*/; I < NumArgs; ++I)
- Args.push_back(
- Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(I)), SizeTy));
+ std::vector<llvm::Value *> Args = {
+ Queue, Flags, Range,
+ Kernel, Block, ConstantInt::get(IntTy, NumArgs - 4),
+ PtrToSizeArray};
+ std::vector<llvm::Type *> ArgTys = {
+ QueueTy, IntTy, RangeTy,
+ GenericVoidPtrTy, GenericVoidPtrTy, IntTy,
+ PtrToSizeArray->getType()};
llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), true);
+ Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
return RValue::get(
Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
llvm::ArrayRef<llvm::Value *>(Args)));
@@ -2611,15 +2867,19 @@ 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.CreatePointerCast(
- EmitScalarExpr(E->getArg(6)), GenericVoidPtrTy);
+ auto Info =
+ CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(6));
+ llvm::Value *Kernel =
+ Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
+ llvm::Value *Block =
+ Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
std::vector<llvm::Type *> ArgTys = {
- QueueTy, Int32Ty, RangeTy, Int32Ty,
- EventPtrTy, EventPtrTy, GenericVoidPtrTy};
+ QueueTy, Int32Ty, RangeTy, Int32Ty,
+ EventPtrTy, EventPtrTy, GenericVoidPtrTy, GenericVoidPtrTy};
- std::vector<llvm::Value *> Args = {Queue, Flags, Range, NumEvents,
- EventList, ClkEvent, Block};
+ std::vector<llvm::Value *> Args = {Queue, Flags, Range, NumEvents,
+ EventList, ClkEvent, Kernel, Block};
if (NumArgs == 7) {
// Has events but no variadics.
@@ -2636,42 +2896,87 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
ArgTys.push_back(Int32Ty);
Name = "__enqueue_kernel_events_vaargs";
- // Each of the following arguments specifies the size of the corresponding
- // argument passed to the enqueued block.
- for (unsigned I = 7/*Position of the first size arg*/; I < NumArgs; ++I)
- Args.push_back(
- Builder.CreateZExtOrTrunc(EmitScalarExpr(E->getArg(I)), SizeTy));
+ auto *PtrToSizeArray = CreateArrayForSizeVar(7);
+ Args.push_back(PtrToSizeArray);
+ ArgTys.push_back(PtrToSizeArray->getType());
llvm::FunctionType *FTy = llvm::FunctionType::get(
- Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), true);
+ Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
return RValue::get(
Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
llvm::ArrayRef<llvm::Value *>(Args)));
}
+ LLVM_FALLTHROUGH;
}
// OpenCL v2.0 s6.13.17.6 - Kernel query functions need bitcast of block
// parameter.
case Builtin::BIget_kernel_work_group_size: {
llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
getContext().getTargetAddressSpace(LangAS::opencl_generic));
- Value *Arg = EmitScalarExpr(E->getArg(0));
- Arg = Builder.CreatePointerCast(Arg, GenericVoidPtrTy);
+ auto Info =
+ CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(0));
+ Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
+ Value *Arg = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
return RValue::get(Builder.CreateCall(
CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, GenericVoidPtrTy, false),
+ llvm::FunctionType::get(IntTy, {GenericVoidPtrTy, GenericVoidPtrTy},
+ false),
"__get_kernel_work_group_size_impl"),
- Arg));
+ {Kernel, 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.CreatePointerCast(Arg, GenericVoidPtrTy);
+ auto Info =
+ CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(0));
+ Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
+ Value *Arg = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
return RValue::get(Builder.CreateCall(
CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, GenericVoidPtrTy, false),
+ llvm::FunctionType::get(IntTy, {GenericVoidPtrTy, GenericVoidPtrTy},
+ false),
"__get_kernel_preferred_work_group_multiple_impl"),
- Arg));
+ {Kernel, Arg}));
+ }
+ case Builtin::BIget_kernel_max_sub_group_size_for_ndrange:
+ case Builtin::BIget_kernel_sub_group_count_for_ndrange: {
+ llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
+ getContext().getTargetAddressSpace(LangAS::opencl_generic));
+ LValue NDRangeL = EmitAggExprToLValue(E->getArg(0));
+ llvm::Value *NDRange = NDRangeL.getAddress().getPointer();
+ auto Info =
+ CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(1));
+ Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy);
+ Value *Block = Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy);
+ const char *Name =
+ BuiltinID == Builtin::BIget_kernel_max_sub_group_size_for_ndrange
+ ? "__get_kernel_max_sub_group_size_for_ndrange_impl"
+ : "__get_kernel_sub_group_count_for_ndrange_impl";
+ return RValue::get(Builder.CreateCall(
+ CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(
+ IntTy, {NDRange->getType(), GenericVoidPtrTy, GenericVoidPtrTy},
+ false),
+ Name),
+ {NDRange, Kernel, Block}));
+ }
+
+ case Builtin::BI__builtin_store_half:
+ case Builtin::BI__builtin_store_halff: {
+ Value *Val = EmitScalarExpr(E->getArg(0));
+ Address Address = EmitPointerWithAlignment(E->getArg(1));
+ Value *HalfVal = Builder.CreateFPTrunc(Val, Builder.getHalfTy());
+ return RValue::get(Builder.CreateStore(HalfVal, Address));
+ }
+ case Builtin::BI__builtin_load_half: {
+ Address Address = EmitPointerWithAlignment(E->getArg(0));
+ Value *HalfVal = Builder.CreateLoad(Address);
+ return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getDoubleTy()));
+ }
+ case Builtin::BI__builtin_load_halff: {
+ Address Address = EmitPointerWithAlignment(E->getArg(0));
+ Value *HalfVal = Builder.CreateLoad(Address);
+ return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getFloatTy()));
}
case Builtin::BIprintf:
if (getTarget().getTriple().isNVPTX())
@@ -2688,69 +2993,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// Fall through - it's already mapped to the intrinsic by GCCBuiltin.
break;
}
- case Builtin::BI__builtin_os_log_format: {
- assert(E->getNumArgs() >= 2 &&
- "__builtin_os_log_format takes at least 2 arguments");
- analyze_os_log::OSLogBufferLayout Layout;
- analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout);
- Address BufAddr = EmitPointerWithAlignment(E->getArg(0));
- // Ignore argument 1, the format string. It is not currently used.
- CharUnits Offset;
- Builder.CreateStore(
- Builder.getInt8(Layout.getSummaryByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "summary"));
- Builder.CreateStore(
- Builder.getInt8(Layout.getNumArgsByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "numArgs"));
-
- llvm::SmallVector<llvm::Value *, 4> RetainableOperands;
- for (const auto &Item : Layout.Items) {
- Builder.CreateStore(
- Builder.getInt8(Item.getDescriptorByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "argDescriptor"));
- Builder.CreateStore(
- Builder.getInt8(Item.getSizeByte()),
- Builder.CreateConstByteGEP(BufAddr, Offset++, "argSize"));
- Address Addr = Builder.CreateConstByteGEP(BufAddr, Offset);
- if (const Expr *TheExpr = Item.getExpr()) {
- Addr = Builder.CreateElementBitCast(
- Addr, ConvertTypeForMem(TheExpr->getType()));
- // Check if this is a retainable type.
- if (TheExpr->getType()->isObjCRetainableType()) {
- assert(getEvaluationKind(TheExpr->getType()) == TEK_Scalar &&
- "Only scalar can be a ObjC retainable type");
- llvm::Value *SV = EmitScalarExpr(TheExpr, /*Ignore*/ false);
- RValue RV = RValue::get(SV);
- LValue LV = MakeAddrLValue(Addr, TheExpr->getType());
- EmitStoreThroughLValue(RV, LV);
- // Check if the object is constant, if not, save it in
- // RetainableOperands.
- if (!isa<Constant>(SV))
- RetainableOperands.push_back(SV);
- } else {
- EmitAnyExprToMem(TheExpr, Addr, Qualifiers(), /*isInit*/ true);
- }
- } else {
- Addr = Builder.CreateElementBitCast(Addr, Int32Ty);
- Builder.CreateStore(
- Builder.getInt32(Item.getConstValue().getQuantity()), Addr);
- }
- Offset += Item.size();
- }
-
- // Push a clang.arc.use cleanup for each object in RetainableOperands. The
- // cleanup will cause the use to appear after the final log call, keeping
- // the object valid while it’s held in the log buffer. Note that if there’s
- // a release cleanup on the object, it will already be active; since
- // cleanups are emitted in reverse order, the use will occur before the
- // object is released.
- if (!RetainableOperands.empty() && getLangOpts().ObjCAutoRefCount &&
- CGM.getCodeGenOpts().OptimizationLevel != 0)
- for (llvm::Value *object : RetainableOperands)
- pushFullExprCleanup<CallObjCArcUse>(getARCCleanupKind(), object);
-
- return RValue::get(BufAddr.getPointer());
- }
+ case Builtin::BI__builtin_os_log_format:
+ return emitBuiltinOSLogFormat(*E);
case Builtin::BI__builtin_os_log_format_buffer_size: {
analyze_os_log::OSLogBufferLayout Layout;
@@ -2758,6 +3002,59 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(ConstantInt::get(ConvertType(E->getType()),
Layout.size().getQuantity()));
}
+
+ case Builtin::BI__xray_customevent: {
+ if (!ShouldXRayInstrumentFunction())
+ return RValue::getIgnored();
+ if (const auto *XRayAttr = CurFuncDecl->getAttr<XRayInstrumentAttr>()) {
+ if (XRayAttr->neverXRayInstrument())
+ return RValue::getIgnored();
+ }
+ Function *F = CGM.getIntrinsic(Intrinsic::xray_customevent);
+ auto FTy = F->getFunctionType();
+ auto Arg0 = E->getArg(0);
+ auto Arg0Val = EmitScalarExpr(Arg0);
+ auto Arg0Ty = Arg0->getType();
+ auto PTy0 = FTy->getParamType(0);
+ if (PTy0 != Arg0Val->getType()) {
+ if (Arg0Ty->isArrayType())
+ Arg0Val = EmitArrayToPointerDecay(Arg0).getPointer();
+ else
+ Arg0Val = Builder.CreatePointerCast(Arg0Val, PTy0);
+ }
+ auto Arg1 = EmitScalarExpr(E->getArg(1));
+ auto PTy1 = FTy->getParamType(1);
+ if (PTy1 != Arg1->getType())
+ Arg1 = Builder.CreateTruncOrBitCast(Arg1, PTy1);
+ return RValue::get(Builder.CreateCall(F, {Arg0Val, Arg1}));
+ }
+
+ case Builtin::BI__builtin_ms_va_start:
+ case Builtin::BI__builtin_ms_va_end:
+ return RValue::get(
+ EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(),
+ BuiltinID == Builtin::BI__builtin_ms_va_start));
+
+ case Builtin::BI__builtin_ms_va_copy: {
+ // Lower this manually. We can't reliably determine whether or not any
+ // given va_copy() is for a Win64 va_list from the calling convention
+ // alone, because it's legal to do this from a System V ABI function.
+ // With opaque pointer types, we won't have enough information in LLVM
+ // IR to determine this from the argument types, either. Best to do it
+ // now, while we have enough information.
+ Address DestAddr = EmitMSVAListRef(E->getArg(0));
+ Address SrcAddr = EmitMSVAListRef(E->getArg(1));
+
+ llvm::Type *BPP = Int8PtrPtrTy;
+
+ DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), BPP, "cp"),
+ DestAddr.getAlignment());
+ SrcAddr = Address(Builder.CreateBitCast(SrcAddr.getPointer(), BPP, "ap"),
+ SrcAddr.getAlignment());
+
+ Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val");
+ return RValue::get(Builder.CreateStore(ArgPtr, DestAddr));
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
@@ -3776,6 +4073,7 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
case NEON::BI__builtin_neon_vcalt_v:
case NEON::BI__builtin_neon_vcaltq_v:
std::swap(Ops[0], Ops[1]);
+ LLVM_FALLTHROUGH;
case NEON::BI__builtin_neon_vcage_v:
case NEON::BI__builtin_neon_vcageq_v:
case NEON::BI__builtin_neon_vcagt_v:
@@ -4534,7 +4832,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
? Intrinsic::arm_stlexd
: Intrinsic::arm_strexd);
- llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, nullptr);
+ llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty);
Address Tmp = CreateMemTemp(E->getArg(0)->getType());
Value *Val = EmitScalarExpr(E->getArg(0));
@@ -5019,6 +5317,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vsri_n_v:
case NEON::BI__builtin_neon_vsriq_n_v:
rightShift = true;
+ LLVM_FALLTHROUGH;
case NEON::BI__builtin_neon_vsli_n_v:
case NEON::BI__builtin_neon_vsliq_n_v:
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, rightShift);
@@ -5364,7 +5663,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
? Intrinsic::aarch64_stlxp
: Intrinsic::aarch64_stxp);
- llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty, nullptr);
+ llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty);
Address Tmp = CreateMemTemp(E->getArg(0)->getType());
EmitAnyExprToMem(E->getArg(0), Tmp, Qualifiers(), /*init*/ true);
@@ -7163,6 +7462,18 @@ static Value *EmitX86MaskedCompare(CodeGenFunction &CGF, unsigned CC,
std::max(NumElts, 8U)));
}
+static Value *EmitX86Abs(CodeGenFunction &CGF, ArrayRef<Value *> Ops) {
+
+ llvm::Type *Ty = Ops[0]->getType();
+ Value *Zero = llvm::Constant::getNullValue(Ty);
+ Value *Sub = CGF.Builder.CreateSub(Zero, Ops[0]);
+ Value *Cmp = CGF.Builder.CreateICmp(ICmpInst::ICMP_SGT, Ops[0], Zero);
+ Value *Res = CGF.Builder.CreateSelect(Cmp, Ops[0], Sub);
+ if (Ops.size() == 1)
+ return Res;
+ return EmitX86Select(CGF, Ops[2], Res, Ops[1]);
+}
+
static Value *EmitX86MinMax(CodeGenFunction &CGF, ICmpInst::Predicate Pred,
ArrayRef<Value *> Ops) {
Value *Cmp = CGF.Builder.CreateICmp(Pred, Ops[0], Ops[1]);
@@ -7175,33 +7486,263 @@ static Value *EmitX86MinMax(CodeGenFunction &CGF, ICmpInst::Predicate Pred,
return EmitX86Select(CGF, Ops[3], Res, Ops[2]);
}
-Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- if (BuiltinID == X86::BI__builtin_ms_va_start ||
- BuiltinID == X86::BI__builtin_ms_va_end)
- return EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(),
- BuiltinID == X86::BI__builtin_ms_va_start);
- if (BuiltinID == X86::BI__builtin_ms_va_copy) {
- // Lower this manually. We can't reliably determine whether or not any
- // given va_copy() is for a Win64 va_list from the calling convention
- // alone, because it's legal to do this from a System V ABI function.
- // With opaque pointer types, we won't have enough information in LLVM
- // IR to determine this from the argument types, either. Best to do it
- // now, while we have enough information.
- Address DestAddr = EmitMSVAListRef(E->getArg(0));
- Address SrcAddr = EmitMSVAListRef(E->getArg(1));
+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");
+}
- llvm::Type *BPP = Int8PtrPtrTy;
+Value *CodeGenFunction::EmitX86CpuIs(const CallExpr *E) {
+ const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
+ StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
+ return EmitX86CpuIs(CPUStr);
+}
- DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), BPP, "cp"),
- DestAddr.getAlignment());
- SrcAddr = Address(Builder.CreateBitCast(SrcAddr.getPointer(), BPP, "ap"),
- SrcAddr.getAlignment());
+Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) {
+
+ // This enum contains the vendor, type, and subtype enums from the
+ // runtime library concatenated together. The _START labels mark
+ // the start and are used to adjust the value into the correct
+ // encoding space.
+ enum X86CPUs {
+ INTEL = 1,
+ AMD,
+ CPU_TYPE_START,
+ INTEL_BONNELL,
+ INTEL_CORE2,
+ INTEL_COREI7,
+ AMDFAM10H,
+ AMDFAM15H,
+ INTEL_SILVERMONT,
+ INTEL_KNL,
+ AMD_BTVER1,
+ AMD_BTVER2,
+ AMDFAM17H,
+ CPU_SUBTYPE_START,
+ INTEL_COREI7_NEHALEM,
+ INTEL_COREI7_WESTMERE,
+ INTEL_COREI7_SANDYBRIDGE,
+ AMDFAM10H_BARCELONA,
+ AMDFAM10H_SHANGHAI,
+ AMDFAM10H_ISTANBUL,
+ AMDFAM15H_BDVER1,
+ AMDFAM15H_BDVER2,
+ AMDFAM15H_BDVER3,
+ AMDFAM15H_BDVER4,
+ AMDFAM17H_ZNVER1,
+ INTEL_COREI7_IVYBRIDGE,
+ INTEL_COREI7_HASWELL,
+ INTEL_COREI7_BROADWELL,
+ INTEL_COREI7_SKYLAKE,
+ INTEL_COREI7_SKYLAKE_AVX512,
+ };
- Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val");
- return Builder.CreateStore(ArgPtr, DestAddr);
+ X86CPUs CPU =
+ StringSwitch<X86CPUs>(CPUStr)
+ .Case("amd", AMD)
+ .Case("amdfam10h", AMDFAM10H)
+ .Case("amdfam10", AMDFAM10H)
+ .Case("amdfam15h", AMDFAM15H)
+ .Case("amdfam15", AMDFAM15H)
+ .Case("amdfam17h", AMDFAM17H)
+ .Case("atom", INTEL_BONNELL)
+ .Case("barcelona", AMDFAM10H_BARCELONA)
+ .Case("bdver1", AMDFAM15H_BDVER1)
+ .Case("bdver2", AMDFAM15H_BDVER2)
+ .Case("bdver3", AMDFAM15H_BDVER3)
+ .Case("bdver4", AMDFAM15H_BDVER4)
+ .Case("bonnell", INTEL_BONNELL)
+ .Case("broadwell", INTEL_COREI7_BROADWELL)
+ .Case("btver1", AMD_BTVER1)
+ .Case("btver2", AMD_BTVER2)
+ .Case("core2", INTEL_CORE2)
+ .Case("corei7", INTEL_COREI7)
+ .Case("haswell", INTEL_COREI7_HASWELL)
+ .Case("intel", INTEL)
+ .Case("istanbul", AMDFAM10H_ISTANBUL)
+ .Case("ivybridge", INTEL_COREI7_IVYBRIDGE)
+ .Case("knl", INTEL_KNL)
+ .Case("nehalem", INTEL_COREI7_NEHALEM)
+ .Case("sandybridge", INTEL_COREI7_SANDYBRIDGE)
+ .Case("shanghai", AMDFAM10H_SHANGHAI)
+ .Case("silvermont", INTEL_SILVERMONT)
+ .Case("skylake", INTEL_COREI7_SKYLAKE)
+ .Case("skylake-avx512", INTEL_COREI7_SKYLAKE_AVX512)
+ .Case("slm", INTEL_SILVERMONT)
+ .Case("westmere", INTEL_COREI7_WESTMERE)
+ .Case("znver1", AMDFAM17H_ZNVER1);
+
+ llvm::Type *Int32Ty = Builder.getInt32Ty();
+
+ // Matching the struct layout from the compiler-rt/libgcc structure that is
+ // filled in:
+ // unsigned int __cpu_vendor;
+ // unsigned int __cpu_type;
+ // unsigned int __cpu_subtype;
+ // unsigned int __cpu_features[1];
+ llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty,
+ llvm::ArrayType::get(Int32Ty, 1));
+
+ // Grab the global __cpu_model.
+ llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model");
+
+ // Calculate the index needed to access the correct field based on the
+ // range. Also adjust the expected value.
+ unsigned Index;
+ unsigned Value;
+ if (CPU > CPU_SUBTYPE_START) {
+ Index = 2;
+ Value = CPU - CPU_SUBTYPE_START;
+ } else if (CPU > CPU_TYPE_START) {
+ Index = 1;
+ Value = CPU - CPU_TYPE_START;
+ } else {
+ Index = 0;
+ Value = CPU;
}
+ // Grab the appropriate field from __cpu_model.
+ llvm::Value *Idxs[] = {
+ ConstantInt::get(Int32Ty, 0),
+ ConstantInt::get(Int32Ty, Index)
+ };
+ llvm::Value *CpuValue = Builder.CreateGEP(STy, CpuModel, Idxs);
+ CpuValue = Builder.CreateAlignedLoad(CpuValue, CharUnits::fromQuantity(4));
+
+ // Check the value of the field against the requested value.
+ return Builder.CreateICmpEQ(CpuValue,
+ llvm::ConstantInt::get(Int32Ty, Value));
+}
+
+Value *CodeGenFunction::EmitX86CpuSupports(const CallExpr *E) {
+ const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
+ StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
+ return EmitX86CpuSupports(FeatureStr);
+}
+
+Value *CodeGenFunction::EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs) {
+ // TODO: When/if this becomes more than x86 specific then use a TargetInfo
+ // based mapping.
+ // Processor features and mapping to processor feature value.
+ enum X86Features {
+ CMOV = 0,
+ MMX,
+ POPCNT,
+ SSE,
+ SSE2,
+ SSE3,
+ SSSE3,
+ SSE4_1,
+ SSE4_2,
+ AVX,
+ AVX2,
+ SSE4_A,
+ FMA4,
+ XOP,
+ FMA,
+ AVX512F,
+ BMI,
+ BMI2,
+ AES,
+ PCLMUL,
+ AVX512VL,
+ AVX512BW,
+ AVX512DQ,
+ AVX512CD,
+ AVX512ER,
+ AVX512PF,
+ AVX512VBMI,
+ AVX512IFMA,
+ AVX5124VNNIW,
+ AVX5124FMAPS,
+ AVX512VPOPCNTDQ,
+ MAX
+ };
+
+ uint32_t FeaturesMask = 0;
+
+ for (const StringRef &FeatureStr : FeatureStrs) {
+ X86Features Feature =
+ StringSwitch<X86Features>(FeatureStr)
+ .Case("cmov", X86Features::CMOV)
+ .Case("mmx", X86Features::MMX)
+ .Case("popcnt", X86Features::POPCNT)
+ .Case("sse", X86Features::SSE)
+ .Case("sse2", X86Features::SSE2)
+ .Case("sse3", X86Features::SSE3)
+ .Case("ssse3", X86Features::SSSE3)
+ .Case("sse4.1", X86Features::SSE4_1)
+ .Case("sse4.2", X86Features::SSE4_2)
+ .Case("avx", X86Features::AVX)
+ .Case("avx2", X86Features::AVX2)
+ .Case("sse4a", X86Features::SSE4_A)
+ .Case("fma4", X86Features::FMA4)
+ .Case("xop", X86Features::XOP)
+ .Case("fma", X86Features::FMA)
+ .Case("avx512f", X86Features::AVX512F)
+ .Case("bmi", X86Features::BMI)
+ .Case("bmi2", X86Features::BMI2)
+ .Case("aes", X86Features::AES)
+ .Case("pclmul", X86Features::PCLMUL)
+ .Case("avx512vl", X86Features::AVX512VL)
+ .Case("avx512bw", X86Features::AVX512BW)
+ .Case("avx512dq", X86Features::AVX512DQ)
+ .Case("avx512cd", X86Features::AVX512CD)
+ .Case("avx512er", X86Features::AVX512ER)
+ .Case("avx512pf", X86Features::AVX512PF)
+ .Case("avx512vbmi", X86Features::AVX512VBMI)
+ .Case("avx512ifma", X86Features::AVX512IFMA)
+ .Case("avx5124vnniw", X86Features::AVX5124VNNIW)
+ .Case("avx5124fmaps", X86Features::AVX5124FMAPS)
+ .Case("avx512vpopcntdq", X86Features::AVX512VPOPCNTDQ)
+ .Default(X86Features::MAX);
+ assert(Feature != X86Features::MAX && "Invalid feature!");
+ FeaturesMask |= (1U << Feature);
+ }
+
+ // Matching the struct layout from the compiler-rt/libgcc structure that is
+ // filled in:
+ // unsigned int __cpu_vendor;
+ // unsigned int __cpu_type;
+ // unsigned int __cpu_subtype;
+ // unsigned int __cpu_features[1];
+ llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty,
+ llvm::ArrayType::get(Int32Ty, 1));
+
+ // Grab the global __cpu_model.
+ llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model");
+
+ // Grab the first (0th) element from the field __cpu_features off of the
+ // global in the struct STy.
+ Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 3),
+ ConstantInt::get(Int32Ty, 0)};
+ Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs);
+ Value *Features =
+ Builder.CreateAlignedLoad(CpuFeatures, CharUnits::fromQuantity(4));
+
+ // Check the value of the bit corresponding to the feature requested.
+ Value *Bitset = Builder.CreateAnd(
+ Features, llvm::ConstantInt::get(Int32Ty, FeaturesMask));
+ return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0));
+}
+
+Value *CodeGenFunction::EmitX86CpuInit() {
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
+ /*Variadic*/ false);
+ llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, "__cpu_indicator_init");
+ return Builder.CreateCall(Func);
+}
+
+Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ if (BuiltinID == X86::BI__builtin_cpu_is)
+ return EmitX86CpuIs(E);
+ if (BuiltinID == X86::BI__builtin_cpu_supports)
+ return EmitX86CpuSupports(E);
+ if (BuiltinID == X86::BI__builtin_cpu_init)
+ return EmitX86CpuInit();
+
SmallVector<Value*, 4> Ops;
// Find out if any arguments are required to be integer constant expressions.
@@ -7252,105 +7793,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
switch (BuiltinID) {
default: return nullptr;
- case X86::BI__builtin_cpu_supports: {
- const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
- StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
-
- // TODO: When/if this becomes more than x86 specific then use a TargetInfo
- // based mapping.
- // Processor features and mapping to processor feature value.
- enum X86Features {
- CMOV = 0,
- MMX,
- POPCNT,
- SSE,
- SSE2,
- SSE3,
- SSSE3,
- SSE4_1,
- SSE4_2,
- AVX,
- AVX2,
- SSE4_A,
- FMA4,
- XOP,
- FMA,
- AVX512F,
- BMI,
- BMI2,
- AES,
- PCLMUL,
- AVX512VL,
- AVX512BW,
- AVX512DQ,
- AVX512CD,
- AVX512ER,
- AVX512PF,
- AVX512VBMI,
- AVX512IFMA,
- MAX
- };
-
- X86Features Feature = StringSwitch<X86Features>(FeatureStr)
- .Case("cmov", X86Features::CMOV)
- .Case("mmx", X86Features::MMX)
- .Case("popcnt", X86Features::POPCNT)
- .Case("sse", X86Features::SSE)
- .Case("sse2", X86Features::SSE2)
- .Case("sse3", X86Features::SSE3)
- .Case("ssse3", X86Features::SSSE3)
- .Case("sse4.1", X86Features::SSE4_1)
- .Case("sse4.2", X86Features::SSE4_2)
- .Case("avx", X86Features::AVX)
- .Case("avx2", X86Features::AVX2)
- .Case("sse4a", X86Features::SSE4_A)
- .Case("fma4", X86Features::FMA4)
- .Case("xop", X86Features::XOP)
- .Case("fma", X86Features::FMA)
- .Case("avx512f", X86Features::AVX512F)
- .Case("bmi", X86Features::BMI)
- .Case("bmi2", X86Features::BMI2)
- .Case("aes", X86Features::AES)
- .Case("pclmul", X86Features::PCLMUL)
- .Case("avx512vl", X86Features::AVX512VL)
- .Case("avx512bw", X86Features::AVX512BW)
- .Case("avx512dq", X86Features::AVX512DQ)
- .Case("avx512cd", X86Features::AVX512CD)
- .Case("avx512er", X86Features::AVX512ER)
- .Case("avx512pf", X86Features::AVX512PF)
- .Case("avx512vbmi", X86Features::AVX512VBMI)
- .Case("avx512ifma", X86Features::AVX512IFMA)
- .Default(X86Features::MAX);
- assert(Feature != X86Features::MAX && "Invalid feature!");
-
- // Matching the struct layout from the compiler-rt/libgcc structure that is
- // filled in:
- // unsigned int __cpu_vendor;
- // unsigned int __cpu_type;
- // unsigned int __cpu_subtype;
- // unsigned int __cpu_features[1];
- llvm::Type *STy = llvm::StructType::get(
- Int32Ty, Int32Ty, Int32Ty, llvm::ArrayType::get(Int32Ty, 1), nullptr);
-
- // Grab the global __cpu_model.
- llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model");
-
- // Grab the first (0th) element from the field __cpu_features off of the
- // global in the struct STy.
- Value *Idxs[] = {
- ConstantInt::get(Int32Ty, 0),
- ConstantInt::get(Int32Ty, 3),
- ConstantInt::get(Int32Ty, 0)
- };
- Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs);
- Value *Features = Builder.CreateAlignedLoad(CpuFeatures,
- CharUnits::fromQuantity(4));
-
- // Check the value of the bit corresponding to the feature requested.
- Value *Bitset = Builder.CreateAnd(
- Features, llvm::ConstantInt::get(Int32Ty, 1ULL << Feature));
- return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0));
- }
case X86::BI_mm_prefetch: {
Value *Address = Ops[0];
Value *RW = ConstantInt::get(Int32Ty, 0);
@@ -7473,6 +7915,26 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_storesd128_mask: {
return EmitX86MaskedStore(*this, Ops, 16);
}
+ case X86::BI__builtin_ia32_vpopcntd_512:
+ case X86::BI__builtin_ia32_vpopcntq_512: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ResultType);
+ return Builder.CreateCall(F, Ops);
+ }
+ case X86::BI__builtin_ia32_cvtmask2b128:
+ case X86::BI__builtin_ia32_cvtmask2b256:
+ case X86::BI__builtin_ia32_cvtmask2b512:
+ case X86::BI__builtin_ia32_cvtmask2w128:
+ case X86::BI__builtin_ia32_cvtmask2w256:
+ case X86::BI__builtin_ia32_cvtmask2w512:
+ case X86::BI__builtin_ia32_cvtmask2d128:
+ case X86::BI__builtin_ia32_cvtmask2d256:
+ case X86::BI__builtin_ia32_cvtmask2d512:
+ case X86::BI__builtin_ia32_cvtmask2q128:
+ case X86::BI__builtin_ia32_cvtmask2q256:
+ case X86::BI__builtin_ia32_cvtmask2q512:
+ return EmitX86SExtMask(*this, Ops[0], ConvertType(E->getType()));
+
case X86::BI__builtin_ia32_movdqa32store128_mask:
case X86::BI__builtin_ia32_movdqa64store128_mask:
case X86::BI__builtin_ia32_storeaps128_mask:
@@ -7596,6 +8058,45 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return EmitX86Select(*this, Ops[4], Align, Ops[3]);
}
+ case X86::BI__builtin_ia32_vperm2f128_pd256:
+ case X86::BI__builtin_ia32_vperm2f128_ps256:
+ case X86::BI__builtin_ia32_vperm2f128_si256:
+ case X86::BI__builtin_ia32_permti256: {
+ unsigned Imm = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
+ unsigned NumElts = Ops[0]->getType()->getVectorNumElements();
+
+ // This takes a very simple approach since there are two lanes and a
+ // shuffle can have 2 inputs. So we reserve the first input for the first
+ // lane and the second input for the second lane. This may result in
+ // duplicate sources, but this can be dealt with in the backend.
+
+ Value *OutOps[2];
+ uint32_t Indices[8];
+ for (unsigned l = 0; l != 2; ++l) {
+ // Determine the source for this lane.
+ if (Imm & (1 << ((l * 4) + 3)))
+ OutOps[l] = llvm::ConstantAggregateZero::get(Ops[0]->getType());
+ else if (Imm & (1 << ((l * 4) + 1)))
+ OutOps[l] = Ops[1];
+ else
+ OutOps[l] = Ops[0];
+
+ for (unsigned i = 0; i != NumElts/2; ++i) {
+ // Start with ith element of the source for this lane.
+ unsigned Idx = (l * NumElts) + i;
+ // If bit 0 of the immediate half is set, switch to the high half of
+ // the source.
+ if (Imm & (1 << (l * 4)))
+ Idx += NumElts/2;
+ Indices[(l * (NumElts/2)) + i] = Idx;
+ }
+ }
+
+ return Builder.CreateShuffleVector(OutOps[0], OutOps[1],
+ makeArrayRef(Indices, NumElts),
+ "vperm");
+ }
+
case X86::BI__builtin_ia32_movnti:
case X86::BI__builtin_ia32_movnti64:
case X86::BI__builtin_ia32_movntsd:
@@ -7710,6 +8211,20 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Ops[1]);
}
+ case X86::BI__builtin_ia32_pabsb128:
+ case X86::BI__builtin_ia32_pabsw128:
+ case X86::BI__builtin_ia32_pabsd128:
+ case X86::BI__builtin_ia32_pabsb256:
+ case X86::BI__builtin_ia32_pabsw256:
+ case X86::BI__builtin_ia32_pabsd256:
+ case X86::BI__builtin_ia32_pabsq128_mask:
+ case X86::BI__builtin_ia32_pabsq256_mask:
+ case X86::BI__builtin_ia32_pabsb512_mask:
+ case X86::BI__builtin_ia32_pabsw512_mask:
+ case X86::BI__builtin_ia32_pabsd512_mask:
+ case X86::BI__builtin_ia32_pabsq512_mask:
+ return EmitX86Abs(*this, Ops);
+
case X86::BI__builtin_ia32_pmaxsb128:
case X86::BI__builtin_ia32_pmaxsw128:
case X86::BI__builtin_ia32_pmaxsd128:
@@ -7853,6 +8368,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
// We can't handle 8-31 immediates with native IR, use the intrinsic.
+ // Except for predicates that create constants.
Intrinsic::ID ID;
switch (BuiltinID) {
default: llvm_unreachable("Unsupported intrinsic!");
@@ -7860,12 +8376,32 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
ID = Intrinsic::x86_sse_cmp_ps;
break;
case X86::BI__builtin_ia32_cmpps256:
+ // _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector
+ // on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0...
+ if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) {
+ Value *Constant = (CC == 0xf || CC == 0x1f) ?
+ llvm::Constant::getAllOnesValue(Builder.getInt32Ty()) :
+ llvm::Constant::getNullValue(Builder.getInt32Ty());
+ Value *Vec = Builder.CreateVectorSplat(
+ Ops[0]->getType()->getVectorNumElements(), Constant);
+ return Builder.CreateBitCast(Vec, Ops[0]->getType());
+ }
ID = Intrinsic::x86_avx_cmp_ps_256;
break;
case X86::BI__builtin_ia32_cmppd:
ID = Intrinsic::x86_sse2_cmp_pd;
break;
case X86::BI__builtin_ia32_cmppd256:
+ // _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector
+ // on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0...
+ if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) {
+ Value *Constant = (CC == 0xf || CC == 0x1f) ?
+ llvm::Constant::getAllOnesValue(Builder.getInt64Ty()) :
+ llvm::Constant::getNullValue(Builder.getInt64Ty());
+ Value *Vec = Builder.CreateVectorSplat(
+ Ops[0]->getType()->getVectorNumElements(), Constant);
+ return Builder.CreateBitCast(Vec, Ops[0]->getType());
+ }
ID = Intrinsic::x86_avx_cmp_pd_256;
break;
}
@@ -7946,13 +8482,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__faststorefence: {
return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::CrossThread);
+ llvm::SyncScope::System);
}
case X86::BI_ReadWriteBarrier:
case X86::BI_ReadBarrier:
case X86::BI_WriteBarrier: {
return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::SingleThread);
+ llvm::SyncScope::SingleThread);
}
case X86::BI_BitScanForward:
case X86::BI_BitScanForward64:
@@ -7995,13 +8531,37 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
llvm::InlineAsm *IA =
llvm::InlineAsm::get(FTy, "int $$0x2c", "", /*SideEffects=*/true);
- llvm::AttributeSet NoReturnAttr =
- AttributeSet::get(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoReturn);
+ 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;
+ }
}
}
@@ -8359,6 +8919,80 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, Ops);
}
}
+
+ case PPC::BI__builtin_vsx_xxpermdi: {
+ ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
+ assert(ArgCI && "Third arg must be constant integer!");
+
+ unsigned Index = ArgCI->getZExtValue();
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2));
+ Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int64Ty, 2));
+
+ // Element zero comes from the first input vector and element one comes from
+ // the second. The element indices within each vector are numbered in big
+ // endian order so the shuffle mask must be adjusted for this on little
+ // endian platforms (i.e. index is complemented and source vector reversed).
+ unsigned ElemIdx0;
+ unsigned ElemIdx1;
+ if (getTarget().isLittleEndian()) {
+ ElemIdx0 = (~Index & 1) + 2;
+ ElemIdx1 = (~Index & 2) >> 1;
+ } else { // BigEndian
+ ElemIdx0 = (Index & 2) >> 1;
+ ElemIdx1 = 2 + (Index & 1);
+ }
+
+ Constant *ShuffleElts[2] = {ConstantInt::get(Int32Ty, ElemIdx0),
+ ConstantInt::get(Int32Ty, ElemIdx1)};
+ Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
+
+ Value *ShuffleCall =
+ Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
+ QualType BIRetType = E->getType();
+ auto RetTy = ConvertType(BIRetType);
+ return Builder.CreateBitCast(ShuffleCall, RetTy);
+ }
+
+ case PPC::BI__builtin_vsx_xxsldwi: {
+ ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
+ assert(ArgCI && "Third argument must be a compile time constant");
+ unsigned Index = ArgCI->getZExtValue() & 0x3;
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 4));
+ Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int32Ty, 4));
+
+ // Create a shuffle mask
+ unsigned ElemIdx0;
+ unsigned ElemIdx1;
+ unsigned ElemIdx2;
+ unsigned ElemIdx3;
+ if (getTarget().isLittleEndian()) {
+ // Little endian element N comes from element 8+N-Index of the
+ // concatenated wide vector (of course, using modulo arithmetic on
+ // the total number of elements).
+ ElemIdx0 = (8 - Index) % 8;
+ ElemIdx1 = (9 - Index) % 8;
+ ElemIdx2 = (10 - Index) % 8;
+ ElemIdx3 = (11 - Index) % 8;
+ } else {
+ // Big endian ElemIdx<N> = Index + N
+ ElemIdx0 = Index;
+ ElemIdx1 = Index + 1;
+ ElemIdx2 = Index + 2;
+ ElemIdx3 = Index + 3;
+ }
+
+ Constant *ShuffleElts[4] = {ConstantInt::get(Int32Ty, ElemIdx0),
+ ConstantInt::get(Int32Ty, ElemIdx1),
+ ConstantInt::get(Int32Ty, ElemIdx2),
+ ConstantInt::get(Int32Ty, ElemIdx3)};
+
+ Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
+ Value *ShuffleCall =
+ Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
+ QualType BIRetType = E->getType();
+ auto RetTy = ConvertType(BIRetType);
+ return Builder.CreateBitCast(ShuffleCall, RetTy);
+ }
}
}
@@ -8488,6 +9122,15 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
CI->setConvergent();
return CI;
}
+ case AMDGPU::BI__builtin_amdgcn_read_exec_lo:
+ case AMDGPU::BI__builtin_amdgcn_read_exec_hi: {
+ StringRef RegName = BuiltinID == AMDGPU::BI__builtin_amdgcn_read_exec_lo ?
+ "exec_lo" : "exec_hi";
+ CallInst *CI = cast<CallInst>(
+ EmitSpecialRegisterBuiltin(*this, E, Int32Ty, Int32Ty, true, RegName));
+ CI->setConvergent();
+ return CI;
+ }
// amdgcn workitem
case AMDGPU::BI__builtin_amdgcn_workitem_id_x:
@@ -8600,12 +9243,14 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, {X, Undef});
}
+ case SystemZ::BI__builtin_s390_vfsqsb:
case SystemZ::BI__builtin_s390_vfsqdb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
Function *F = CGM.getIntrinsic(Intrinsic::sqrt, ResultType);
return Builder.CreateCall(F, X);
}
+ case SystemZ::BI__builtin_s390_vfmasb:
case SystemZ::BI__builtin_s390_vfmadb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8614,6 +9259,7 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
return Builder.CreateCall(F, {X, Y, Z});
}
+ case SystemZ::BI__builtin_s390_vfmssb:
case SystemZ::BI__builtin_s390_vfmsdb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8623,12 +9269,35 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
return Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")});
}
+ case SystemZ::BI__builtin_s390_vfnmasb:
+ case SystemZ::BI__builtin_s390_vfnmadb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ Value *Z = EmitScalarExpr(E->getArg(2));
+ Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
+ Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
+ return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, Z}), "sub");
+ }
+ case SystemZ::BI__builtin_s390_vfnmssb:
+ case SystemZ::BI__builtin_s390_vfnmsdb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ Value *Z = EmitScalarExpr(E->getArg(2));
+ Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
+ Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
+ Value *NegZ = Builder.CreateFSub(Zero, Z, "sub");
+ return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, NegZ}));
+ }
+ case SystemZ::BI__builtin_s390_vflpsb:
case SystemZ::BI__builtin_s390_vflpdb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
return Builder.CreateCall(F, X);
}
+ case SystemZ::BI__builtin_s390_vflnsb:
case SystemZ::BI__builtin_s390_vflndb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8636,6 +9305,7 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
return Builder.CreateFSub(Zero, Builder.CreateCall(F, X), "sub");
}
+ case SystemZ::BI__builtin_s390_vfisb:
case SystemZ::BI__builtin_s390_vfidb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8645,8 +9315,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
bool IsConstM5 = E->getArg(2)->isIntegerConstantExpr(M5, getContext());
assert(IsConstM4 && IsConstM5 && "Constant arg isn't actually constant?");
(void)IsConstM4; (void)IsConstM5;
- // Check whether this instance of vfidb can be represented via a LLVM
- // standard intrinsic. We only support some combinations of M4 and M5.
+ // Check whether this instance can be represented via a LLVM standard
+ // intrinsic. We only support some combinations of M4 and M5.
Intrinsic::ID ID = Intrinsic::not_intrinsic;
switch (M4.getZExtValue()) {
default: break;
@@ -8671,11 +9341,76 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(ID, ResultType);
return Builder.CreateCall(F, X);
}
- Function *F = CGM.getIntrinsic(Intrinsic::s390_vfidb);
+ switch (BuiltinID) {
+ case SystemZ::BI__builtin_s390_vfisb: ID = Intrinsic::s390_vfisb; break;
+ case SystemZ::BI__builtin_s390_vfidb: ID = Intrinsic::s390_vfidb; break;
+ default: llvm_unreachable("Unknown BuiltinID");
+ }
+ Function *F = CGM.getIntrinsic(ID);
Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
Value *M5Value = llvm::ConstantInt::get(getLLVMContext(), M5);
return Builder.CreateCall(F, {X, M4Value, M5Value});
}
+ case SystemZ::BI__builtin_s390_vfmaxsb:
+ case SystemZ::BI__builtin_s390_vfmaxdb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ // Constant-fold the M4 mask argument.
+ llvm::APSInt M4;
+ bool IsConstM4 = E->getArg(2)->isIntegerConstantExpr(M4, getContext());
+ assert(IsConstM4 && "Constant arg isn't actually constant?");
+ (void)IsConstM4;
+ // Check whether this instance can be represented via a LLVM standard
+ // intrinsic. We only support some values of M4.
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+ switch (M4.getZExtValue()) {
+ default: break;
+ case 4: ID = Intrinsic::maxnum; break;
+ }
+ if (ID != Intrinsic::not_intrinsic) {
+ Function *F = CGM.getIntrinsic(ID, ResultType);
+ return Builder.CreateCall(F, {X, Y});
+ }
+ switch (BuiltinID) {
+ case SystemZ::BI__builtin_s390_vfmaxsb: ID = Intrinsic::s390_vfmaxsb; break;
+ case SystemZ::BI__builtin_s390_vfmaxdb: ID = Intrinsic::s390_vfmaxdb; break;
+ default: llvm_unreachable("Unknown BuiltinID");
+ }
+ Function *F = CGM.getIntrinsic(ID);
+ Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
+ return Builder.CreateCall(F, {X, Y, M4Value});
+ }
+ case SystemZ::BI__builtin_s390_vfminsb:
+ case SystemZ::BI__builtin_s390_vfmindb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ // Constant-fold the M4 mask argument.
+ llvm::APSInt M4;
+ bool IsConstM4 = E->getArg(2)->isIntegerConstantExpr(M4, getContext());
+ assert(IsConstM4 && "Constant arg isn't actually constant?");
+ (void)IsConstM4;
+ // Check whether this instance can be represented via a LLVM standard
+ // intrinsic. We only support some values of M4.
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+ switch (M4.getZExtValue()) {
+ default: break;
+ case 4: ID = Intrinsic::minnum; break;
+ }
+ if (ID != Intrinsic::not_intrinsic) {
+ Function *F = CGM.getIntrinsic(ID, ResultType);
+ return Builder.CreateCall(F, {X, Y});
+ }
+ switch (BuiltinID) {
+ case SystemZ::BI__builtin_s390_vfminsb: ID = Intrinsic::s390_vfminsb; break;
+ case SystemZ::BI__builtin_s390_vfmindb: ID = Intrinsic::s390_vfmindb; break;
+ default: llvm_unreachable("Unknown BuiltinID");
+ }
+ Function *F = CGM.getIntrinsic(ID);
+ Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
+ return Builder.CreateCall(F, {X, Y, M4Value});
+ }
// Vector intrisincs that output the post-instruction CC value.
@@ -8742,10 +9477,14 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
INTRINSIC_WITH_CC(s390_vstrczhs);
INTRINSIC_WITH_CC(s390_vstrczfs);
+ INTRINSIC_WITH_CC(s390_vfcesbs);
INTRINSIC_WITH_CC(s390_vfcedbs);
+ INTRINSIC_WITH_CC(s390_vfchsbs);
INTRINSIC_WITH_CC(s390_vfchdbs);
+ INTRINSIC_WITH_CC(s390_vfchesbs);
INTRINSIC_WITH_CC(s390_vfchedbs);
+ INTRINSIC_WITH_CC(s390_vftcisb);
INTRINSIC_WITH_CC(s390_vftcidb);
#undef INTRINSIC_WITH_CC
@@ -8759,9 +9498,8 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
auto MakeLdg = [&](unsigned IntrinsicID) {
Value *Ptr = EmitScalarExpr(E->getArg(0));
- AlignmentSource AlignSource;
clang::CharUnits Align =
- getNaturalPointeeTypeAlignment(E->getArg(0)->getType(), &AlignSource);
+ getNaturalPointeeTypeAlignment(E->getArg(0)->getType());
return Builder.CreateCall(
CGM.getIntrinsic(IntrinsicID, {Ptr->getType()->getPointerElementType(),
Ptr->getType()}),
@@ -8995,6 +9733,219 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
{Ptr->getType()->getPointerElementType(), Ptr->getType()}),
{Ptr, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2))});
}
+ case NVPTX::BI__nvvm_match_all_sync_i32p:
+ case NVPTX::BI__nvvm_match_all_sync_i64p: {
+ Value *Mask = EmitScalarExpr(E->getArg(0));
+ Value *Val = EmitScalarExpr(E->getArg(1));
+ Address PredOutPtr = EmitPointerWithAlignment(E->getArg(2));
+ Value *ResultPair = Builder.CreateCall(
+ CGM.getIntrinsic(BuiltinID == NVPTX::BI__nvvm_match_all_sync_i32p
+ ? Intrinsic::nvvm_match_all_sync_i32p
+ : Intrinsic::nvvm_match_all_sync_i64p),
+ {Mask, Val});
+ Value *Pred = Builder.CreateZExt(Builder.CreateExtractValue(ResultPair, 1),
+ PredOutPtr.getElementType());
+ Builder.CreateStore(Pred, PredOutPtr);
+ return Builder.CreateExtractValue(ResultPair, 0);
+ }
+ case NVPTX::BI__hmma_m16n16k16_ld_a:
+ case NVPTX::BI__hmma_m16n16k16_ld_b:
+ case NVPTX::BI__hmma_m16n16k16_ld_c_f16:
+ case NVPTX::BI__hmma_m16n16k16_ld_c_f32: {
+ Address Dst = EmitPointerWithAlignment(E->getArg(0));
+ Value *Src = EmitScalarExpr(E->getArg(1));
+ Value *Ldm = EmitScalarExpr(E->getArg(2));
+ llvm::APSInt isColMajorArg;
+ if (!E->getArg(3)->isIntegerConstantExpr(isColMajorArg, getContext()))
+ return nullptr;
+ bool isColMajor = isColMajorArg.getSExtValue();
+ unsigned IID;
+ unsigned NumResults;
+ switch (BuiltinID) {
+ case NVPTX::BI__hmma_m16n16k16_ld_a:
+ IID = isColMajor ? Intrinsic::nvvm_wmma_load_a_f16_col_stride
+ : Intrinsic::nvvm_wmma_load_a_f16_row_stride;
+ NumResults = 8;
+ break;
+ case NVPTX::BI__hmma_m16n16k16_ld_b:
+ IID = isColMajor ? Intrinsic::nvvm_wmma_load_b_f16_col_stride
+ : Intrinsic::nvvm_wmma_load_b_f16_row_stride;
+ NumResults = 8;
+ break;
+ case NVPTX::BI__hmma_m16n16k16_ld_c_f16:
+ IID = isColMajor ? Intrinsic::nvvm_wmma_load_c_f16_col_stride
+ : Intrinsic::nvvm_wmma_load_c_f16_row_stride;
+ NumResults = 4;
+ break;
+ case NVPTX::BI__hmma_m16n16k16_ld_c_f32:
+ IID = isColMajor ? Intrinsic::nvvm_wmma_load_c_f32_col_stride
+ : Intrinsic::nvvm_wmma_load_c_f32_row_stride;
+ NumResults = 8;
+ break;
+ default:
+ llvm_unreachable("Unexpected builtin ID.");
+ }
+ Value *Result =
+ Builder.CreateCall(CGM.getIntrinsic(IID),
+ {Builder.CreatePointerCast(Src, VoidPtrTy), Ldm});
+
+ // Save returned values.
+ for (unsigned i = 0; i < NumResults; ++i) {
+ Builder.CreateAlignedStore(
+ Builder.CreateBitCast(Builder.CreateExtractValue(Result, i),
+ Dst.getElementType()),
+ Builder.CreateGEP(Dst.getPointer(), llvm::ConstantInt::get(IntTy, i)),
+ CharUnits::fromQuantity(4));
+ }
+ return Result;
+ }
+
+ case NVPTX::BI__hmma_m16n16k16_st_c_f16:
+ case NVPTX::BI__hmma_m16n16k16_st_c_f32: {
+ Value *Dst = EmitScalarExpr(E->getArg(0));
+ Address Src = EmitPointerWithAlignment(E->getArg(1));
+ Value *Ldm = EmitScalarExpr(E->getArg(2));
+ llvm::APSInt isColMajorArg;
+ if (!E->getArg(3)->isIntegerConstantExpr(isColMajorArg, getContext()))
+ return nullptr;
+ bool isColMajor = isColMajorArg.getSExtValue();
+ unsigned IID;
+ unsigned NumResults = 8;
+ // PTX Instructions (and LLVM instrinsics) are defined for slice _d_, yet
+ // for some reason nvcc builtins use _c_.
+ switch (BuiltinID) {
+ case NVPTX::BI__hmma_m16n16k16_st_c_f16:
+ IID = isColMajor ? Intrinsic::nvvm_wmma_store_d_f16_col_stride
+ : Intrinsic::nvvm_wmma_store_d_f16_row_stride;
+ NumResults = 4;
+ break;
+ case NVPTX::BI__hmma_m16n16k16_st_c_f32:
+ IID = isColMajor ? Intrinsic::nvvm_wmma_store_d_f32_col_stride
+ : Intrinsic::nvvm_wmma_store_d_f32_row_stride;
+ break;
+ default:
+ llvm_unreachable("Unexpected builtin ID.");
+ }
+ Function *Intrinsic = CGM.getIntrinsic(IID);
+ llvm::Type *ParamType = Intrinsic->getFunctionType()->getParamType(1);
+ SmallVector<Value *, 10> Values;
+ Values.push_back(Builder.CreatePointerCast(Dst, VoidPtrTy));
+ for (unsigned i = 0; i < NumResults; ++i) {
+ Value *V = Builder.CreateAlignedLoad(
+ Builder.CreateGEP(Src.getPointer(), llvm::ConstantInt::get(IntTy, i)),
+ CharUnits::fromQuantity(4));
+ Values.push_back(Builder.CreateBitCast(V, ParamType));
+ }
+ Values.push_back(Ldm);
+ Value *Result = Builder.CreateCall(Intrinsic, Values);
+ return Result;
+ }
+
+ // BI__hmma_m16n16k16_mma_<Dtype><CType>(d, a, b, c, layout, satf)
+ // --> Intrinsic::nvvm_wmma_mma_sync<layout A,B><DType><CType><Satf>
+ case NVPTX::BI__hmma_m16n16k16_mma_f16f16:
+ case NVPTX::BI__hmma_m16n16k16_mma_f32f16:
+ case NVPTX::BI__hmma_m16n16k16_mma_f32f32:
+ case NVPTX::BI__hmma_m16n16k16_mma_f16f32: {
+ Address Dst = EmitPointerWithAlignment(E->getArg(0));
+ Address SrcA = EmitPointerWithAlignment(E->getArg(1));
+ Address SrcB = EmitPointerWithAlignment(E->getArg(2));
+ Address SrcC = EmitPointerWithAlignment(E->getArg(3));
+ llvm::APSInt LayoutArg;
+ if (!E->getArg(4)->isIntegerConstantExpr(LayoutArg, getContext()))
+ return nullptr;
+ int Layout = LayoutArg.getSExtValue();
+ if (Layout < 0 || Layout > 3)
+ return nullptr;
+ llvm::APSInt SatfArg;
+ if (!E->getArg(5)->isIntegerConstantExpr(SatfArg, getContext()))
+ return nullptr;
+ bool Satf = SatfArg.getSExtValue();
+
+ // clang-format off
+#define MMA_VARIANTS(type) {{ \
+ Intrinsic::nvvm_wmma_mma_sync_row_row_##type, \
+ Intrinsic::nvvm_wmma_mma_sync_row_row_##type##_satfinite, \
+ Intrinsic::nvvm_wmma_mma_sync_row_col_##type, \
+ Intrinsic::nvvm_wmma_mma_sync_row_col_##type##_satfinite, \
+ Intrinsic::nvvm_wmma_mma_sync_col_row_##type, \
+ Intrinsic::nvvm_wmma_mma_sync_col_row_##type##_satfinite, \
+ Intrinsic::nvvm_wmma_mma_sync_col_col_##type, \
+ Intrinsic::nvvm_wmma_mma_sync_col_col_##type##_satfinite \
+ }}
+ // clang-format on
+
+ auto getMMAIntrinsic = [Layout, Satf](std::array<unsigned, 8> Variants) {
+ unsigned Index = Layout * 2 + Satf;
+ assert(Index < 8);
+ return Variants[Index];
+ };
+ unsigned IID;
+ unsigned NumEltsC;
+ unsigned NumEltsD;
+ switch (BuiltinID) {
+ case NVPTX::BI__hmma_m16n16k16_mma_f16f16:
+ IID = getMMAIntrinsic(MMA_VARIANTS(f16_f16));
+ NumEltsC = 4;
+ NumEltsD = 4;
+ break;
+ case NVPTX::BI__hmma_m16n16k16_mma_f32f16:
+ IID = getMMAIntrinsic(MMA_VARIANTS(f32_f16));
+ NumEltsC = 4;
+ NumEltsD = 8;
+ break;
+ case NVPTX::BI__hmma_m16n16k16_mma_f16f32:
+ IID = getMMAIntrinsic(MMA_VARIANTS(f16_f32));
+ NumEltsC = 8;
+ NumEltsD = 4;
+ break;
+ case NVPTX::BI__hmma_m16n16k16_mma_f32f32:
+ IID = getMMAIntrinsic(MMA_VARIANTS(f32_f32));
+ NumEltsC = 8;
+ NumEltsD = 8;
+ break;
+ default:
+ llvm_unreachable("Unexpected builtin ID.");
+ }
+#undef MMA_VARIANTS
+
+ SmallVector<Value *, 24> Values;
+ Function *Intrinsic = CGM.getIntrinsic(IID);
+ llvm::Type *ABType = Intrinsic->getFunctionType()->getParamType(0);
+ // Load A
+ for (unsigned i = 0; i < 8; ++i) {
+ Value *V = Builder.CreateAlignedLoad(
+ Builder.CreateGEP(SrcA.getPointer(),
+ llvm::ConstantInt::get(IntTy, i)),
+ CharUnits::fromQuantity(4));
+ Values.push_back(Builder.CreateBitCast(V, ABType));
+ }
+ // Load B
+ for (unsigned i = 0; i < 8; ++i) {
+ Value *V = Builder.CreateAlignedLoad(
+ Builder.CreateGEP(SrcB.getPointer(),
+ llvm::ConstantInt::get(IntTy, i)),
+ CharUnits::fromQuantity(4));
+ Values.push_back(Builder.CreateBitCast(V, ABType));
+ }
+ // Load C
+ llvm::Type *CType = Intrinsic->getFunctionType()->getParamType(16);
+ for (unsigned i = 0; i < NumEltsC; ++i) {
+ Value *V = Builder.CreateAlignedLoad(
+ Builder.CreateGEP(SrcC.getPointer(),
+ llvm::ConstantInt::get(IntTy, i)),
+ CharUnits::fromQuantity(4));
+ Values.push_back(Builder.CreateBitCast(V, CType));
+ }
+ Value *Result = Builder.CreateCall(Intrinsic, Values);
+ llvm::Type *DType = Dst.getElementType();
+ for (unsigned i = 0; i < NumEltsD; ++i)
+ Builder.CreateAlignedStore(
+ Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), DType),
+ Builder.CreateGEP(Dst.getPointer(), llvm::ConstantInt::get(IntTy, i)),
+ CharUnits::fromQuantity(4));
+ return Result;
+ }
default:
return nullptr;
}
@@ -9013,6 +9964,16 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_grow_memory, X->getType());
return Builder.CreateCall(Callee, X);
}
+ case WebAssembly::BI__builtin_wasm_throw: {
+ Value *Tag = EmitScalarExpr(E->getArg(0));
+ Value *Obj = EmitScalarExpr(E->getArg(1));
+ Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw);
+ return Builder.CreateCall(Callee, {Tag, Obj});
+ }
+ case WebAssembly::BI__builtin_wasm_rethrow: {
+ Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow);
+ return Builder.CreateCall(Callee);
+ }
default:
return nullptr;
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index 813cd74001..d24ef0a8a9 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -265,7 +265,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
"__cudaRegisterFatBinary");
// struct { int magic, int version, void * gpu_binary, void * dont_care };
llvm::StructType *FatbinWrapperTy =
- llvm::StructType::get(IntTy, IntTy, VoidPtrTy, VoidPtrTy, nullptr);
+ llvm::StructType::get(IntTy, IntTy, VoidPtrTy, VoidPtrTy);
llvm::Function *ModuleCtorFunc = llvm::Function::Create(
llvm::FunctionType::get(VoidTy, VoidPtrTy, false),
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 59010f4407..5ef4dc45fb 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -110,16 +110,14 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
return true;
return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
- GlobalDecl(BaseD, Dtor_Base),
- false);
+ GlobalDecl(BaseD, Dtor_Base));
}
/// Try to emit a definition as a global alias for another definition.
/// If \p InEveryTU is true, we know that an equivalent alias can be produced
/// in every translation unit.
bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
- GlobalDecl TargetDecl,
- bool InEveryTU) {
+ GlobalDecl TargetDecl) {
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
@@ -134,11 +132,6 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
llvm::GlobalValue::LinkageTypes TargetLinkage =
getFunctionLinkage(TargetDecl);
- // available_externally definitions aren't real definitions, so we cannot
- // create an alias to one.
- if (TargetLinkage == llvm::GlobalValue::AvailableExternallyLinkage)
- return true;
-
// Check if we have it already.
StringRef MangledName = getMangledName(AliasDecl);
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
@@ -161,7 +154,14 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
// Instead of creating as alias to a linkonce_odr, replace all of the uses
// of the aliasee.
- if (llvm::GlobalValue::isDiscardableIfUnused(Linkage)) {
+ if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
+ !(TargetLinkage == llvm::GlobalValue::AvailableExternallyLinkage &&
+ TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
+ // FIXME: An extern template instantiation will create functions with
+ // linkage "AvailableExternally". In libc++, some classes also define
+ // members with attribute "AlwaysInline" and expect no reference to
+ // be generated. It is desirable to reenable this optimisation after
+ // corresponding LLVM changes.
addReplacement(MangledName, Aliasee);
return false;
}
@@ -176,13 +176,11 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
return true;
}
- if (!InEveryTU) {
- // If we don't have a definition for the destructor yet, don't
- // emit. We can't emit aliases to declarations; that's just not
- // how aliases work.
- if (Ref->isDeclaration())
- return true;
- }
+ // If we don't have a definition for the destructor yet or the definition is
+ // avaialable_externally, don't emit an alias. We can't emit aliases to
+ // declarations; that's just not how aliases work.
+ if (Ref->isDeclarationForLinker())
+ return true;
// Don't create an alias to a linker weak symbol. This avoids producing
// different COMDATs in different TUs. Another option would be to
@@ -256,7 +254,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.cpp b/lib/CodeGen/CGCXXABI.cpp
index df75a7d7ff..033258643d 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -30,38 +30,9 @@ void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
}
bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
- // If RD has a non-trivial move or copy constructor, we cannot copy the
- // argument.
- if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor())
- return false;
-
- // If RD has a non-trivial destructor, we cannot copy the argument.
- if (RD->hasNonTrivialDestructor())
- return false;
-
// We can only copy the argument if there exists at least one trivial,
// non-deleted copy or move constructor.
- // FIXME: This assumes that all lazily declared copy and move constructors are
- // not deleted. This assumption might not be true in some corner cases.
- bool CopyDeleted = false;
- bool MoveDeleted = false;
- for (const CXXConstructorDecl *CD : RD->ctors()) {
- if (CD->isCopyConstructor() || CD->isMoveConstructor()) {
- assert(CD->isTrivial());
- // We had at least one undeleted trivial copy or move ctor. Return
- // directly.
- if (!CD->isDeleted())
- return true;
- if (CD->isCopyConstructor())
- CopyDeleted = true;
- else
- MoveDeleted = true;
- }
- }
-
- // If all trivial copy and move constructors are deleted, we cannot copy the
- // argument.
- return !(CopyDeleted && MoveDeleted);
+ return RD->canPassInRegisters();
}
llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
@@ -159,10 +130,10 @@ void CGCXXABI::buildThisParam(CodeGenFunction &CGF, FunctionArgList &params) {
// FIXME: I'm not entirely sure I like using a fake decl just for code
// generation. Maybe we can come up with a better way?
- ImplicitParamDecl *ThisDecl
- = ImplicitParamDecl::Create(CGM.getContext(), nullptr, MD->getLocation(),
- &CGM.getContext().Idents.get("this"),
- MD->getThisType(CGM.getContext()));
+ auto *ThisDecl = ImplicitParamDecl::Create(
+ CGM.getContext(), nullptr, MD->getLocation(),
+ &CGM.getContext().Idents.get("this"), MD->getThisType(CGM.getContext()),
+ ImplicitParamDecl::CXXThis);
params.push_back(ThisDecl);
CGF.CXXABIThisDecl = ThisDecl;
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 186abc3c6d..7b912e3aca 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -392,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 5f069bfe46..971455a873 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -50,7 +50,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
case CC_X86RegCall: return llvm::CallingConv::X86_RegCall;
case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
- case CC_X86_64Win64: return llvm::CallingConv::X86_64_Win64;
+ case CC_Win64: return llvm::CallingConv::Win64;
case CC_X86_64SysV: return llvm::CallingConv::X86_64_SysV;
case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
@@ -129,7 +129,7 @@ static void addExtParameterInfosForCall(
paramInfos.resize(totalArgs);
}
-/// Adds the formal paramaters in FPT to the given prefix. If any parameter in
+/// Adds the formal parameters in FPT to the given prefix. If any parameter in
/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
static void appendParameterTypes(const CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
@@ -218,7 +218,7 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
return CC_IntelOclBicc;
if (D->hasAttr<MSABIAttr>())
- return IsWindows ? CC_C : CC_X86_64Win64;
+ return IsWindows ? CC_C : CC_Win64;
if (D->hasAttr<SysVABIAttr>())
return IsWindows ? CC_X86_64SysV : CC_C;
@@ -455,11 +455,15 @@ const CGFunctionInfo &
CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
QualType receiverType) {
SmallVector<CanQualType, 16> argTys;
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(2);
argTys.push_back(Context.getCanonicalParamType(receiverType));
argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
// FIXME: Kill copy?
for (const auto *I : MD->parameters()) {
argTys.push_back(Context.getCanonicalParamType(I->getType()));
+ auto extParamInfo = FunctionProtoType::ExtParameterInfo().withIsNoEscape(
+ I->hasAttr<NoEscapeAttr>());
+ extParamInfos.push_back(extParamInfo);
}
FunctionType::ExtInfo einfo;
@@ -475,7 +479,7 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
return arrangeLLVMFunctionInfo(
GetReturnType(MD->getReturnType()), /*instanceMethod=*/false,
- /*chainCall=*/false, argTys, einfo, {}, required);
+ /*chainCall=*/false, argTys, einfo, extParamInfos, required);
}
const CGFunctionInfo &
@@ -707,6 +711,12 @@ CodeGenTypes::arrangeCall(const CGFunctionInfo &signature,
signature.getRequiredArgs());
}
+namespace clang {
+namespace CodeGen {
+void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
+}
+}
+
/// Arrange the argument and result information for an abstract value
/// of a given function type. This is the method which all of the
/// above functions ultimately defer to.
@@ -719,7 +729,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;
@@ -741,12 +751,16 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
bool inserted = FunctionsBeingProcessed.insert(FI).second;
(void)inserted;
assert(inserted && "Recursively being processed?");
-
+
// Compute ABI information.
- if (info.getCC() != CC_Swift) {
- getABIInfo().computeInfo(*FI);
- } else {
+ if (CC == llvm::CallingConv::SPIR_KERNEL) {
+ // Force target independent argument handling for the host visible
+ // kernel functions.
+ computeSPIRKernelABIInfo(CGM, *FI);
+ } else if (info.getCC() == CC_Swift) {
swiftcall::computeABIInfo(CGM, *FI);
+ } else {
+ getABIInfo().computeInfo(*FI);
}
// Loop over all of the computed argument and return value info. If any of
@@ -788,6 +802,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
FI->ChainCall = chainCall;
FI->NoReturn = info.getNoReturn();
FI->ReturnsRetained = info.getProducesResult();
+ FI->NoCallerSavedRegs = info.getNoCallerSavedRegs();
FI->Required = required;
FI->HasRegParm = info.getHasRegParm();
FI->RegParm = info.getRegParm();
@@ -1212,7 +1227,8 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
//
// FIXME: Assert that we aren't truncating non-padding bits when have access
// to that information.
- Src = CGF.Builder.CreateBitCast(Src, llvm::PointerType::getUnqual(Ty));
+ Src = CGF.Builder.CreateBitCast(Src,
+ Ty->getPointerTo(Src.getAddressSpace()));
return CGF.Builder.CreateLoad(Src);
}
@@ -1286,7 +1302,7 @@ static void CreateCoercedStore(llvm::Value *Src,
// If store is legal, just bitcast the src pointer.
if (SrcSize <= DstSize) {
- Dst = CGF.Builder.CreateBitCast(Dst, llvm::PointerType::getUnqual(SrcTy));
+ Dst = CGF.Builder.CreateElementBitCast(Dst, SrcTy);
BuildAggStore(CGF, Src, Dst, DstIsVolatile);
} else {
// Otherwise do coercion through memory. This is stupid, but
@@ -1586,9 +1602,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
case ABIArgInfo::Indirect: {
assert(NumIRArgs == 1);
- // indirect arguments are always on the stack, which is addr space #0.
+ // indirect arguments are always on the stack, which is alloca addr space.
llvm::Type *LTy = ConvertTypeForMem(it->type);
- ArgTypes[FirstIRArg] = LTy->getPointerTo();
+ ArgTypes[FirstIRArg] = LTy->getPointerTo(
+ CGM.getDataLayout().getAllocaAddrSpace());
break;
}
@@ -1725,7 +1742,7 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
std::vector<std::string> &Recips = getTarget().getTargetOpts().Reciprocals;
if (!Recips.empty())
FuncAttrs.addAttribute("reciprocal-estimates",
- llvm::join(Recips.begin(), Recips.end(), ","));
+ llvm::join(Recips, ","));
if (CodeGenOpts.StackRealignment)
FuncAttrs.addAttribute("stackrealign");
@@ -1733,13 +1750,16 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
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.
+ if (getLangOpts().assumeFunctionsAreConvergent()) {
+ // Conservatively, mark all functions and calls in CUDA and OpenCL as
+ // convergent (meaning, they may call an intrinsically convergent op, such
+ // as __syncthreads() / barrier(), and so can't have certain optimizations
+ // applied around them). LLVM will remove this attribute where it safely
+ // can.
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
+ }
+ if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
// Exceptions aren't supported in CUDA device code.
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
@@ -1754,14 +1774,12 @@ void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) {
ConstructDefaultFnAttrList(F.getName(),
F.hasFnAttribute(llvm::Attribute::OptimizeNone),
/* AttrOnCallsite = */ false, FuncAttrs);
- llvm::AttributeSet AS = llvm::AttributeSet::get(
- getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
- F.addAttributes(llvm::AttributeSet::FunctionIndex, AS);
+ F.addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs);
}
void CodeGenModule::ConstructAttributeList(
StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
- AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) {
+ llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite) {
llvm::AttrBuilder FuncAttrs;
llvm::AttrBuilder RetAttrs;
@@ -1785,6 +1803,8 @@ void CodeGenModule::ConstructAttributeList(
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
if (TargetDecl->hasAttr<NoReturnAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+ if (TargetDecl->hasAttr<ColdAttr>())
+ FuncAttrs.addAttribute(llvm::Attribute::Cold);
if (TargetDecl->hasAttr<NoDuplicateAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (TargetDecl->hasAttr<ConvergentAttr>())
@@ -1815,6 +1835,8 @@ void CodeGenModule::ConstructAttributeList(
RetAttrs.addAttribute(llvm::Attribute::NoAlias);
if (TargetDecl->hasAttr<ReturnsNonNullAttr>())
RetAttrs.addAttribute(llvm::Attribute::NonNull);
+ if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())
+ FuncAttrs.addAttribute("no_caller_saved_registers");
HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
@@ -1863,15 +1885,16 @@ void CodeGenModule::ConstructAttributeList(
// the function.
const auto *TD = FD->getAttr<TargetAttr>();
TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
- if (ParsedAttr.second != "")
- TargetCPU = ParsedAttr.second;
+ if (ParsedAttr.Architecture != "" &&
+ getTarget().isValidCPUName(ParsedAttr.Architecture))
+ TargetCPU = ParsedAttr.Architecture;
if (TargetCPU != "")
- FuncAttrs.addAttribute("target-cpu", TargetCPU);
+ FuncAttrs.addAttribute("target-cpu", TargetCPU);
if (!Features.empty()) {
std::sort(Features.begin(), Features.end());
FuncAttrs.addAttribute(
"target-features",
- llvm::join(Features.begin(), Features.end(), ","));
+ llvm::join(Features, ","));
}
} else {
// Otherwise just add the existing target cpu and target features to the
@@ -1883,7 +1906,7 @@ void CodeGenModule::ConstructAttributeList(
std::sort(Features.begin(), Features.end());
FuncAttrs.addAttribute(
"target-features",
- llvm::join(Features.begin(), Features.end(), ","));
+ llvm::join(Features, ","));
}
}
}
@@ -1930,13 +1953,8 @@ void CodeGenModule::ConstructAttributeList(
RetAttrs.addAttribute(llvm::Attribute::NonNull);
}
- // Attach return attributes.
- if (RetAttrs.hasAttributes()) {
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), llvm::AttributeSet::ReturnIndex, RetAttrs));
- }
-
bool hasUsedSRet = false;
+ SmallVector<llvm::AttributeSet, 4> ArgAttrs(IRFunctionArgs.totalIRArgs());
// Attach attributes to sret.
if (IRFunctionArgs.hasSRetArg()) {
@@ -1945,16 +1963,16 @@ void CodeGenModule::ConstructAttributeList(
hasUsedSRet = true;
if (RetAI.getInReg())
SRETAttrs.addAttribute(llvm::Attribute::InReg);
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), IRFunctionArgs.getSRetArgNo() + 1, SRETAttrs));
+ ArgAttrs[IRFunctionArgs.getSRetArgNo()] =
+ llvm::AttributeSet::get(getLLVMContext(), SRETAttrs);
}
// Attach attributes to inalloca argument.
if (IRFunctionArgs.hasInallocaArg()) {
llvm::AttrBuilder Attrs;
Attrs.addAttribute(llvm::Attribute::InAlloca);
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs));
+ ArgAttrs[IRFunctionArgs.getInallocaArgNo()] =
+ llvm::AttributeSet::get(getLLVMContext(), Attrs);
}
unsigned ArgNo = 0;
@@ -1967,10 +1985,12 @@ void CodeGenModule::ConstructAttributeList(
// Add attribute for padding argument, if necessary.
if (IRFunctionArgs.hasPaddingArg(ArgNo)) {
- if (AI.getPaddingInReg())
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), IRFunctionArgs.getPaddingArgNo(ArgNo) + 1,
- llvm::Attribute::InReg));
+ if (AI.getPaddingInReg()) {
+ ArgAttrs[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
+ llvm::AttributeSet::get(
+ getLLVMContext(),
+ llvm::AttrBuilder().addAttribute(llvm::Attribute::InReg));
+ }
}
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
@@ -2081,21 +2101,22 @@ void CodeGenModule::ConstructAttributeList(
break;
}
+ if (FI.getExtParameterInfo(ArgNo).isNoEscape())
+ Attrs.addAttribute(llvm::Attribute::NoCapture);
+
if (Attrs.hasAttributes()) {
unsigned FirstIRArg, NumIRArgs;
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
for (unsigned i = 0; i < NumIRArgs; i++)
- PAL.push_back(llvm::AttributeSet::get(getLLVMContext(),
- FirstIRArg + i + 1, Attrs));
+ ArgAttrs[FirstIRArg + i] =
+ llvm::AttributeSet::get(getLLVMContext(), Attrs);
}
}
assert(ArgNo == FI.arg_size());
- if (FuncAttrs.hasAttributes())
- PAL.push_back(llvm::
- AttributeSet::get(getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- FuncAttrs));
+ AttrList = llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs),
+ llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs);
}
/// An argument came in as a promoted argument; demote it back to its
@@ -2206,8 +2227,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (IRFunctionArgs.hasSRetArg()) {
auto AI = cast<llvm::Argument>(FnArgs[IRFunctionArgs.getSRetArgNo()]);
AI->setName("agg.result");
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(), AI->getArgNo() + 1,
- llvm::Attribute::NoAlias));
+ AI->addAttr(llvm::Attribute::NoAlias);
}
// Track if we received the parameter as a pointer (indirect, byval, or
@@ -2298,9 +2318,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(),
PVD->getFunctionScopeIndex()))
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NonNull));
+ AI->addAttr(llvm::Attribute::NonNull);
QualType OTy = PVD->getOriginalType();
if (const auto *ArrTy =
@@ -2317,12 +2335,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::AttrBuilder Attrs;
Attrs.addDereferenceableAttr(
getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize);
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1, Attrs));
+ AI->addAttrs(Attrs);
} else if (getContext().getTargetAddressSpace(ETy) == 0) {
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NonNull));
+ AI->addAttr(llvm::Attribute::NonNull);
}
}
} else if (const auto *ArrTy =
@@ -2332,35 +2347,26 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// we know that it must be nonnull.
if (ArrTy->getSizeModifier() == VariableArrayType::Static &&
!getContext().getTargetAddressSpace(ArrTy->getElementType()))
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NonNull));
+ AI->addAttr(llvm::Attribute::NonNull);
}
const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
if (!AVAttr)
if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
- if (AVAttr) {
+ if (AVAttr) {
llvm::Value *AlignmentValue =
EmitScalarExpr(AVAttr->getAlignment());
llvm::ConstantInt *AlignmentCI =
cast<llvm::ConstantInt>(AlignmentValue);
- unsigned Alignment =
- std::min((unsigned) AlignmentCI->getZExtValue(),
- +llvm::Value::MaximumAlignment);
-
- llvm::AttrBuilder Attrs;
- Attrs.addAlignmentAttr(Alignment);
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1, Attrs));
+ unsigned Alignment = std::min((unsigned)AlignmentCI->getZExtValue(),
+ +llvm::Value::MaximumAlignment);
+ AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment));
}
}
if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NoAlias));
+ AI->addAttr(llvm::Attribute::NoAlias);
// LLVM expects swifterror parameters to be used in very restricted
// ways. Copy the value into a less-restricted temporary.
@@ -2418,8 +2424,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
Address AddrToStoreInto = Address::invalid();
if (SrcSize <= DstSize) {
- AddrToStoreInto =
- Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
+ AddrToStoreInto = Builder.CreateElementBitCast(Ptr, STy);
} else {
AddrToStoreInto =
CreateTempAlloca(STy, Alloca.getAlignment(), "coerce");
@@ -2912,7 +2917,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
llvm::Instruction *Ret;
if (RV) {
- EmitReturnValueCheck(RV, EndLoc);
+ EmitReturnValueCheck(RV);
Ret = Builder.CreateRet(RV);
} else {
Ret = Builder.CreateRetVoid();
@@ -2922,8 +2927,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
Ret->setDebugLoc(std::move(RetDbgLoc));
}
-void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV,
- SourceLocation EndLoc) {
+void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) {
// A current decl may not be available when emitting vtable thunks.
if (!CurCodeDecl)
return;
@@ -2938,44 +2942,48 @@ void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV,
// 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 {
- // FIXME: The runtime shouldn't refer to the 'returns_nonnull' attribute.
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);
- }
+ // Make sure the "return" source location is valid. If we're checking a
+ // nullability annotation, make sure the preconditions for the check are met.
+ llvm::BasicBlock *Check = createBasicBlock("nullcheck");
+ llvm::BasicBlock *NoCheck = createBasicBlock("no.nullcheck");
+ llvm::Value *SLocPtr = Builder.CreateLoad(ReturnLocation, "return.sloc.load");
+ llvm::Value *CanNullCheck = Builder.CreateIsNotNull(SLocPtr);
+ if (requiresReturnValueNullabilityCheck())
+ CanNullCheck =
+ Builder.CreateAnd(CanNullCheck, RetValNullabilityPrecondition);
+ Builder.CreateCondBr(CanNullCheck, Check, NoCheck);
+ EmitBlock(Check);
- // Now do the null check. If the returns_nonnull attribute is present, this
- // is done unconditionally.
+ // Now do the null check.
llvm::Value *Cond = Builder.CreateIsNotNull(RV);
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(EndLoc), EmitCheckSourceLocation(AttrLoc),
- };
- EmitCheck(std::make_pair(Cond, CheckKind), SanitizerHandler::NonnullReturn,
- StaticData, None);
+ llvm::Constant *StaticData[] = {EmitCheckSourceLocation(AttrLoc)};
+ llvm::Value *DynamicData[] = {SLocPtr};
+ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, DynamicData);
- if (requiresReturnValueNullabilityCheck())
- EmitBlock(NoCheck);
+ EmitBlock(NoCheck);
+
+#ifndef NDEBUG
+ // The return location should not be used after the check has been emitted.
+ ReturnLocation = Address::invalid();
+#endif
}
static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) {
@@ -3058,7 +3066,8 @@ static void emitWriteback(CodeGenFunction &CGF,
// If the argument wasn't provably non-null, we need to null check
// before doing the store.
- bool provablyNonNull = llvm::isKnownNonNull(srcAddr.getPointer());
+ bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(),
+ CGF.CGM.getDataLayout());
if (!provablyNonNull) {
llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback");
contBB = CGF.createBasicBlock("icr.done");
@@ -3198,7 +3207,8 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// If the address is *not* known to be non-null, we need to switch.
llvm::Value *finalArgument;
- bool provablyNonNull = llvm::isKnownNonNull(srcAddr.getPointer());
+ bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(),
+ CGF.CGM.getDataLayout());
if (provablyNonNull) {
finalArgument = temp.getPointer();
} else {
@@ -3314,12 +3324,15 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
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);
@@ -3331,8 +3344,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
EmitCheckSourceLocation(ArgLoc), EmitCheckSourceLocation(AttrLoc),
llvm::ConstantInt::get(Int32Ty, ArgNo + 1),
};
- EmitCheck(std::make_pair(Cond, CheckKind), SanitizerHandler::NonnullArg,
- StaticData, None);
+ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
}
void CodeGenFunction::EmitCallArgs(
@@ -3390,6 +3402,14 @@ void CodeGenFunction::EmitCallArgs(
unsigned Idx = LeftToRight ? I : E - I - 1;
CallExpr::const_arg_iterator Arg = ArgRange.begin() + Idx;
unsigned InitialArgSize = Args.size();
+ // If *Arg is an ObjCIndirectCopyRestoreExpr, check that either the types of
+ // the argument and parameter match or the objc method is parameterized.
+ assert((!isa<ObjCIndirectCopyRestoreExpr>(*Arg) ||
+ getContext().hasSameUnqualifiedType((*Arg)->getType(),
+ ArgTypes[Idx]) ||
+ (isa<ObjCMethodDecl>(AC.getDecl()) &&
+ isObjCMethodWithTypeParams(cast<ObjCMethodDecl>(AC.getDecl())))) &&
+ "Argument and parameter types don't match");
EmitCallArg(Args, *Arg, ArgTypes[Idx]);
// 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.
@@ -3450,7 +3470,6 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
if (const ObjCIndirectCopyRestoreExpr *CRE
= dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
assert(getLangOpts().ObjCAutoRefCount);
- assert(getContext().hasSameUnqualifiedType(E->getType(), type));
return emitWritebackArg(*this, args, CRE);
}
@@ -3710,12 +3729,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");
}
@@ -3814,7 +3835,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
assert(NumIRArgs == 1);
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
- Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign());
+ Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(),
+ "indirect-arg-temp", false);
IRCallArgs[FirstIRArg] = Addr.getPointer();
LValue argLV = MakeAddrLValue(Addr, I->Ty);
@@ -3843,7 +3865,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
< Align.getQuantity()) ||
(ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
// Create an aligned temporary, and copy to it.
- Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign());
+ Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(),
+ "byval-temp", false);
IRCallArgs[FirstIRArg] = AI.getPointer();
EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified());
} else {
@@ -3937,7 +3960,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Builder.CreateMemCpy(TempAlloca, Src, SrcSize);
Src = TempAlloca;
} else {
- Src = Builder.CreateBitCast(Src, llvm::PointerType::getUnqual(STy));
+ Src = Builder.CreateBitCast(Src,
+ STy->getPointerTo(Src.getAddressSpace()));
}
auto SrcLayout = CGM.getDataLayout().getStructLayout(STy);
@@ -4111,13 +4135,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Compute the calling convention and attributes.
unsigned CallingConv;
- CodeGen::AttributeListType AttributeList;
+ llvm::AttributeList Attrs;
CGM.ConstructAttributeList(CalleePtr->getName(), CallInfo,
- Callee.getAbstractInfo(),
- AttributeList, CallingConv,
+ Callee.getAbstractInfo(), Attrs, CallingConv,
/*AttrOnCallSite=*/true);
- llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
- AttributeList);
// Apply some call-site-specific attributes.
// TODO: work this into building the attribute set.
@@ -4128,15 +4149,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);
}
@@ -4153,7 +4173,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();
@@ -4266,6 +4286,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Builder.CreateStore(elt, eltAddr);
}
// FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
case ABIArgInfo::InAlloca:
@@ -4349,6 +4370,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 031ce831cb..7e10407fc3 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,27 @@ namespace clang {
class VarDecl;
namespace CodeGen {
- typedef SmallVector<llvm::AttributeSet, 8> AttributeListType;
- /// Abstract information about a function or function prototype.
- class CGCalleeInfo {
- /// \brief The function prototype of the callee.
- const FunctionProtoType *CalleeProtoTy;
- /// \brief The function declaration of the callee.
- const Decl *CalleeDecl;
-
- public:
- explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {}
- CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl)
- : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
- CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
- : CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {}
- CGCalleeInfo(const Decl *calleeDecl)
- : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
-
- const FunctionProtoType *getCalleeFunctionProtoType() const {
- return CalleeProtoTy;
- }
- const Decl *getCalleeDecl() const { return CalleeDecl; }
+/// Abstract information about a function or function prototype.
+class CGCalleeInfo {
+ /// \brief The function prototype of the callee.
+ const FunctionProtoType *CalleeProtoTy;
+ /// \brief The function declaration of the callee.
+ const Decl *CalleeDecl;
+
+public:
+ explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {}
+ CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl)
+ : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
+ CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
+ : CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {}
+ CGCalleeInfo(const Decl *calleeDecl)
+ : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
+
+ const FunctionProtoType *getCalleeFunctionProtoType() const {
+ return CalleeProtoTy;
+ }
+ const Decl *getCalleeDecl() const { return CalleeDecl; }
};
/// All available information about a concrete callee.
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 7ba03a0d42..1cd59d1442 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -129,14 +129,16 @@ Address
CodeGenFunction::EmitCXXMemberDataPointerAddress(const Expr *E, Address base,
llvm::Value *memberPtr,
const MemberPointerType *memberPtrType,
- AlignmentSource *alignSource) {
+ LValueBaseInfo *BaseInfo,
+ TBAAAccessInfo *TBAAInfo) {
// Ask the ABI to compute the actual address.
llvm::Value *ptr =
CGM.getCXXABI().EmitMemberDataPointerAddress(*this, E, base,
memberPtr, memberPtrType);
QualType memberType = memberPtrType->getPointeeType();
- CharUnits memberAlign = getNaturalTypeAlignment(memberType, alignSource);
+ CharUnits memberAlign = getNaturalTypeAlignment(memberType, BaseInfo,
+ TBAAInfo);
memberAlign =
CGM.getDynamicOffsetAlignment(base.getAlignment(),
memberPtrType->getClass()->getAsCXXRecordDecl(),
@@ -1413,10 +1415,11 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// possible to delegate the destructor body to the complete
// destructor. Do so.
if (DtorType == Dtor_Deleting) {
+ RunCleanupsScope DtorEpilogue(*this);
EnterDtorCleanups(Dtor, Dtor_Deleting);
- EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- /*Delegating=*/false, LoadCXXThisAddress());
- PopCleanupBlock();
+ if (HaveInsertPoint())
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
+ /*Delegating=*/false, LoadCXXThisAddress());
return;
}
@@ -1512,6 +1515,13 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args)
}
namespace {
+ llvm::Value *LoadThisForDtorDelete(CodeGenFunction &CGF,
+ const CXXDestructorDecl *DD) {
+ if (Expr *ThisArg = DD->getOperatorDeleteThisArg())
+ return CGF.EmitScalarExpr(ThisArg);
+ return CGF.LoadCXXThis();
+ }
+
/// Call the operator delete associated with the current destructor.
struct CallDtorDelete final : EHScopeStack::Cleanup {
CallDtorDelete() {}
@@ -1519,11 +1529,38 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) override {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
const CXXRecordDecl *ClassDecl = Dtor->getParent();
- CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
+ CGF.EmitDeleteCall(Dtor->getOperatorDelete(),
+ LoadThisForDtorDelete(CGF, Dtor),
CGF.getContext().getTagDeclType(ClassDecl));
}
};
+ void EmitConditionalDtorDeleteCall(CodeGenFunction &CGF,
+ llvm::Value *ShouldDeleteCondition,
+ bool ReturnAfterDelete) {
+ llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
+ llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
+ llvm::Value *ShouldCallDelete
+ = CGF.Builder.CreateIsNull(ShouldDeleteCondition);
+ CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);
+
+ CGF.EmitBlock(callDeleteBB);
+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
+ const CXXRecordDecl *ClassDecl = Dtor->getParent();
+ CGF.EmitDeleteCall(Dtor->getOperatorDelete(),
+ LoadThisForDtorDelete(CGF, Dtor),
+ CGF.getContext().getTagDeclType(ClassDecl));
+ assert(Dtor->getOperatorDelete()->isDestroyingOperatorDelete() ==
+ ReturnAfterDelete &&
+ "unexpected value for ReturnAfterDelete");
+ if (ReturnAfterDelete)
+ CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
+ else
+ CGF.Builder.CreateBr(continueBB);
+
+ CGF.EmitBlock(continueBB);
+ }
+
struct CallDtorDeleteConditional final : EHScopeStack::Cleanup {
llvm::Value *ShouldDeleteCondition;
@@ -1534,20 +1571,8 @@ namespace {
}
void Emit(CodeGenFunction &CGF, Flags flags) override {
- llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
- llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
- llvm::Value *ShouldCallDelete
- = CGF.Builder.CreateIsNull(ShouldDeleteCondition);
- CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);
-
- CGF.EmitBlock(callDeleteBB);
- const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
- CGF.getContext().getTagDeclType(ClassDecl));
- CGF.Builder.CreateBr(continueBB);
-
- CGF.EmitBlock(continueBB);
+ EmitConditionalDtorDeleteCall(CGF, ShouldDeleteCondition,
+ /*ReturnAfterDelete*/false);
}
};
@@ -1577,6 +1602,7 @@ namespace {
static void EmitSanitizerDtorCallback(CodeGenFunction &CGF, llvm::Value *Ptr,
CharUnits::QuantityType PoisonSize) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
// Pass in void pointer and size of region as arguments to runtime
// function
llvm::Value *Args[] = {CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy),
@@ -1705,6 +1731,9 @@ namespace {
/// \brief Emit all code that comes at the end of class's
/// destructor. This is to call destructors on members and base classes
/// in reverse order of their construction.
+///
+/// For a deleting destructor, this also handles the case where a destroying
+/// operator delete completely overrides the definition.
void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
CXXDtorType DtorType) {
assert((!DD->isTrivial() || DD->hasAttr<DLLExportAttr>()) &&
@@ -1717,11 +1746,23 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
"operator delete missing - EnterDtorCleanups");
if (CXXStructorImplicitParamValue) {
// If there is an implicit param to the deleting dtor, it's a boolean
- // telling whether we should call delete at the end of the dtor.
- EHStack.pushCleanup<CallDtorDeleteConditional>(
- NormalAndEHCleanup, CXXStructorImplicitParamValue);
+ // telling whether this is a deleting destructor.
+ if (DD->getOperatorDelete()->isDestroyingOperatorDelete())
+ EmitConditionalDtorDeleteCall(*this, CXXStructorImplicitParamValue,
+ /*ReturnAfterDelete*/true);
+ else
+ EHStack.pushCleanup<CallDtorDeleteConditional>(
+ NormalAndEHCleanup, CXXStructorImplicitParamValue);
} else {
- EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+ if (DD->getOperatorDelete()->isDestroyingOperatorDelete()) {
+ const CXXRecordDecl *ClassDecl = DD->getParent();
+ EmitDeleteCall(DD->getOperatorDelete(),
+ LoadThisForDtorDelete(*this, DD),
+ getContext().getTagDeclType(ClassDecl));
+ EmitBranchThroughCleanup(ReturnBlock);
+ } else {
+ EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+ }
}
return;
}
@@ -2382,7 +2423,7 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy);
llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField);
- CGM.DecorateInstructionWithTBAA(Store, CGM.getTBAAInfoForVTablePtr());
+ CGM.DecorateInstructionWithTBAA(Store, CGM.getTBAAVTablePtrAccessInfo());
if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
CGM.getCodeGenOpts().StrictVTablePointers)
CGM.DecorateInstructionWithInvariantGroup(Store, Vptr.VTableClass);
@@ -2476,7 +2517,7 @@ llvm::Value *CodeGenFunction::GetVTablePtr(Address This,
const CXXRecordDecl *RD) {
Address VTablePtrSrc = Builder.CreateElementBitCast(This, VTableTy);
llvm::Instruction *VTable = Builder.CreateLoad(VTablePtrSrc, "vtable");
- CGM.DecorateInstructionWithTBAA(VTable, CGM.getTBAAInfoForVTablePtr());
+ CGM.DecorateInstructionWithTBAA(VTable, CGM.getTBAAVTablePtrAccessInfo());
if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
CGM.getCodeGenOpts().StrictVTablePointers)
@@ -2523,8 +2564,10 @@ LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) {
void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
llvm::Value *VTable,
SourceLocation Loc) {
- if (CGM.getCodeGenOpts().WholeProgramVTables &&
- CGM.HasHiddenLTOVisibility(RD)) {
+ if (SanOpts.has(SanitizerKind::CFIVCall))
+ EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc);
+ else if (CGM.getCodeGenOpts().WholeProgramVTables &&
+ CGM.HasHiddenLTOVisibility(RD)) {
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
llvm::Value *TypeId =
@@ -2536,9 +2579,6 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
{CastedVTable, TypeId});
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
}
-
- if (SanOpts.has(SanitizerKind::CFIVCall))
- EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc);
}
void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
@@ -2604,28 +2644,34 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
!CGM.HasHiddenLTOVisibility(RD))
return;
- std::string TypeName = RD->getQualifiedNameAsString();
- if (getContext().getSanitizerBlacklist().isBlacklistedType(TypeName))
- return;
-
- SanitizerScope SanScope(this);
+ SanitizerMask M;
llvm::SanitizerStatKind SSK;
switch (TCK) {
case CFITCK_VCall:
+ M = SanitizerKind::CFIVCall;
SSK = llvm::SanStat_CFI_VCall;
break;
case CFITCK_NVCall:
+ M = SanitizerKind::CFINVCall;
SSK = llvm::SanStat_CFI_NVCall;
break;
case CFITCK_DerivedCast:
+ M = SanitizerKind::CFIDerivedCast;
SSK = llvm::SanStat_CFI_DerivedCast;
break;
case CFITCK_UnrelatedCast:
+ M = SanitizerKind::CFIUnrelatedCast;
SSK = llvm::SanStat_CFI_UnrelatedCast;
break;
case CFITCK_ICall:
llvm_unreachable("not expecting CFITCK_ICall");
}
+
+ std::string TypeName = RD->getQualifiedNameAsString();
+ if (getContext().getSanitizerBlacklist().isBlacklistedType(M, TypeName))
+ return;
+
+ SanitizerScope SanScope(this);
EmitSanitizerStatReport(SSK);
llvm::Metadata *MD =
@@ -2636,24 +2682,6 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
llvm::Value *TypeTest = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId});
- SanitizerMask M;
- switch (TCK) {
- case CFITCK_VCall:
- M = SanitizerKind::CFIVCall;
- break;
- case CFITCK_NVCall:
- M = SanitizerKind::CFINVCall;
- break;
- case CFITCK_DerivedCast:
- M = SanitizerKind::CFIDerivedCast;
- break;
- case CFITCK_UnrelatedCast:
- M = SanitizerKind::CFIUnrelatedCast;
- break;
- case CFITCK_ICall:
- llvm_unreachable("not expecting CFITCK_ICall");
- }
-
llvm::Constant *StaticData[] = {
llvm::ConstantInt::get(Int8Ty, TCK),
EmitCheckSourceLocation(Loc),
@@ -2688,7 +2716,8 @@ bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
return false;
std::string TypeName = RD->getQualifiedNameAsString();
- return !getContext().getSanitizerBlacklist().isBlacklistedType(TypeName);
+ return !getContext().getSanitizerBlacklist().isBlacklistedType(
+ SanitizerKind::CFIVCall, TypeName);
}
llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
@@ -2716,79 +2745,6 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
cast<llvm::PointerType>(VTable->getType())->getElementType());
}
-bool
-CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base,
- const CXXMethodDecl *MD) {
- // When building with -fapple-kext, all calls must go through the vtable since
- // the kernel linker can do runtime patching of vtables.
- if (getLangOpts().AppleKext)
- return false;
-
- // If the member function is marked 'final', we know that it can't be
- // overridden and can therefore devirtualize it unless it's pure virtual.
- if (MD->hasAttr<FinalAttr>())
- return !MD->isPure();
-
- // If the base expression (after skipping derived-to-base conversions) is a
- // class prvalue, then we can devirtualize.
- Base = Base->getBestDynamicClassTypeExpr();
- if (Base->isRValue() && Base->getType()->isRecordType())
- return true;
-
- // If we don't even know what we would call, we can't devirtualize.
- const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
- if (!BestDynamicDecl)
- return false;
-
- // There may be a method corresponding to MD in a derived class.
- const CXXMethodDecl *DevirtualizedMethod =
- MD->getCorrespondingMethodInClass(BestDynamicDecl);
-
- // If that method is pure virtual, we can't devirtualize. If this code is
- // reached, the result would be UB, not a direct call to the derived class
- // function, and we can't assume the derived class function is defined.
- if (DevirtualizedMethod->isPure())
- return false;
-
- // If that method is marked final, we can devirtualize it.
- if (DevirtualizedMethod->hasAttr<FinalAttr>())
- return true;
-
- // Similarly, if the class itself is marked 'final' it can't be overridden
- // and we can therefore devirtualize the member function call.
- if (BestDynamicDecl->hasAttr<FinalAttr>())
- return true;
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- // This is a record decl. We know the type and can devirtualize it.
- return VD->getType()->isRecordType();
- }
-
- return false;
- }
-
- // We can devirtualize calls on an object accessed by a class member access
- // expression, since by C++11 [basic.life]p6 we know that it can't refer to
- // a derived class object constructed in the same location.
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base))
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl()))
- return VD->getType()->isRecordType();
-
- // Likewise for calls on an object accessed by a (non-reference) pointer to
- // member access.
- if (auto *BO = dyn_cast<BinaryOperator>(Base)) {
- if (BO->isPtrMemOp()) {
- auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>();
- if (MPT->getPointeeType()->isRecordType())
- return true;
- }
- }
-
- // We can't devirtualize the call.
- return false;
-}
-
void CodeGenFunction::EmitForwardingCallToLambda(
const CXXMethodDecl *callOperator,
CallArgList &callArgs) {
@@ -2828,6 +2784,15 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
const BlockDecl *BD = BlockInfo->getBlockDecl();
const VarDecl *variable = BD->capture_begin()->getVariable();
const CXXRecordDecl *Lambda = variable->getType()->getAsCXXRecordDecl();
+ const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
+
+ if (CallOp->isVariadic()) {
+ // FIXME: Making this work correctly is nasty because it requires either
+ // cloning the body of the call operator or making the call operator
+ // forward.
+ CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function");
+ return;
+ }
// Start building arguments for forwarding call
CallArgList CallArgs;
@@ -2842,18 +2807,7 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
assert(!Lambda->isGenericLambda() &&
"generic lambda interconversion to block not implemented");
- EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs);
-}
-
-void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
- if (cast<CXXMethodDecl>(CurCodeDecl)->isVariadic()) {
- // FIXME: Making this work correctly is nasty because it requires either
- // cloning the body of the call operator or making the call operator forward.
- CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function");
- return;
- }
-
- EmitFunctionBody(Args, cast<FunctionDecl>(CurGD.getDecl())->getBody());
+ EmitForwardingCallToLambda(CallOp, CallArgs);
}
void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
@@ -2886,7 +2840,7 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
EmitForwardingCallToLambda(CallOp, CallArgs);
}
-void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) {
+void CodeGenFunction::EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD) {
if (MD->isVariadic()) {
// FIXME: Making this work correctly is nasty because it requires either
// cloning the body of the call operator or making the call operator forward.
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index df6741da4a..22055b2cb9 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -51,8 +51,7 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
if (rv.isComplex()) {
CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
llvm::Type *ComplexTy =
- llvm::StructType::get(V.first->getType(), V.second->getType(),
- (void*) nullptr);
+ llvm::StructType::get(V.first->getType(), V.second->getType());
Address addr = CGF.CreateDefaultAlignTempAlloca(ComplexTy, "saved-complex");
CGF.Builder.CreateStore(V.first,
CGF.Builder.CreateStructGEP(addr, 0, CharUnits()));
@@ -449,6 +448,13 @@ void CodeGenFunction::PopCleanupBlocks(
auto *Inst = dyn_cast_or_null<llvm::Instruction>(*ReloadedValue);
if (!Inst)
continue;
+
+ // Don't spill static allocas, they dominate all cleanups. These are created
+ // by binding a reference to a local variable or temporary.
+ auto *AI = dyn_cast<llvm::AllocaInst>(Inst);
+ if (AI && AI->isStaticAlloca())
+ continue;
+
Address Tmp =
CreateDefaultAlignTempAlloca(Inst->getType(), "tmp.exprcleanup");
@@ -609,7 +615,7 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
llvm::SwitchInst *si = cast<llvm::SwitchInst>(use.getUser());
if (si->getNumCases() == 1 && si->getDefaultDest() == unreachableBB) {
// Replace the switch with a branch.
- llvm::BranchInst::Create(si->case_begin().getCaseSuccessor(), si);
+ llvm::BranchInst::Create(si->case_begin()->getCaseSuccessor(), si);
// The switch operand is a load from the cleanup-dest alloca.
llvm::LoadInst *condition = cast<llvm::LoadInst>(si->getCondition());
@@ -1090,7 +1096,7 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
break;
}
- // Otherwise, tell the scope that there's a jump propoagating
+ // Otherwise, tell the scope that there's a jump propagating
// through it. If this isn't new information, all the rest of
// the work has been done before.
if (!Scope.addBranchThrough(Dest.getBlock()))
diff --git a/lib/CodeGen/CGCoroutine.cpp b/lib/CodeGen/CGCoroutine.cpp
index 77497f3275..5842e7b3ff 100644
--- a/lib/CodeGen/CGCoroutine.cpp
+++ b/lib/CodeGen/CGCoroutine.cpp
@@ -11,36 +11,70 @@
//
//===----------------------------------------------------------------------===//
+#include "CGCleanup.h"
#include "CodeGenFunction.h"
+#include "llvm/ADT/ScopeExit.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtVisitor.h"
using namespace clang;
using namespace CodeGen;
-namespace clang {
-namespace CodeGen {
+using llvm::Value;
+using llvm::BasicBlock;
-struct CGCoroData {
+namespace {
+enum class AwaitKind { Init, Normal, Yield, Final };
+static constexpr llvm::StringLiteral AwaitKindStr[] = {"init", "await", "yield",
+ "final"};
+}
- // Stores the jump destination just before the final suspend. Coreturn
- // statements jumps to this point after calling return_xxx promise member.
- CodeGenFunction::JumpDest FinalJD;
+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;
+
// Stores the llvm.coro.id emitted in the function so that we can supply it
// as the first argument to coro.begin, coro.alloc and coro.free intrinsics.
// Note: llvm.coro.id returns a token that cannot be directly expressed in a
// builtin.
llvm::CallInst *CoroId = nullptr;
+
+ // Stores the llvm.coro.begin emitted in the function so that we can replace
+ // all coro.frame intrinsics with direct SSA value of coro.begin that returns
+ // the address of the coroutine frame of the current coroutine.
+ llvm::CallInst *CoroBegin = nullptr;
+
+ // Stores the last emitted coro.free for the deallocate expressions, we use it
+ // to wrap dealloc code with if(auto mem = coro.free) dealloc(mem).
+ llvm::CallInst *LastCoroFree = nullptr;
+
// If coro.id came from the builtin, remember the expression to give better
// diagnostic. If CoroIdExpr is nullptr, the coro.id was created by
// EmitCoroutineBody.
CallExpr const *CoroIdExpr = nullptr;
};
-}
-}
+// Defining these here allows to keep CGCoroData private to this file.
clang::CodeGen::CodeGenFunction::CGCoroInfo::CGCoroInfo() {}
CodeGenFunction::CGCoroInfo::~CGCoroInfo() {}
@@ -66,46 +100,533 @@ static void createCoroData(CodeGenFunction &CGF,
CurCoro.Data->CoroIdExpr = CoroIdExpr;
}
+// Synthesize a pretty name for a suspend point.
+static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) {
+ unsigned No = 0;
+ switch (Kind) {
+ case AwaitKind::Init:
+ case AwaitKind::Final:
+ break;
+ case AwaitKind::Normal:
+ No = ++Coro.AwaitNum;
+ break;
+ case AwaitKind::Yield:
+ No = ++Coro.YieldNum;
+ break;
+ }
+ SmallString<32> Prefix(AwaitKindStr[static_cast<unsigned>(Kind)]);
+ if (No > 1) {
+ Twine(No).toVector(Prefix);
+ }
+ return Prefix;
+}
+
+// Emit suspend expression which roughly looks like:
+//
+// auto && x = CommonExpr();
+// if (!x.await_ready()) {
+// llvm_coro_save();
+// x.await_suspend(...); (*)
+// llvm_coro_suspend(); (**)
+// }
+// x.await_resume();
+//
+// where the result of the entire expression is the result of x.await_resume()
+//
+// (*) If x.await_suspend return type is bool, it allows to veto a suspend:
+// if (x.await_suspend(...))
+// llvm_coro_suspend();
+//
+// (**) llvm_coro_suspend() encodes three possible continuations as
+// a switch instruction:
+//
+// %where-to = call i8 @llvm.coro.suspend(...)
+// switch i8 %where-to, label %coro.ret [ ; jump to epilogue to suspend
+// i8 0, label %yield.ready ; go here when resumed
+// i8 1, label %yield.cleanup ; go here when destroyed
+// ]
+//
+// See llvm's docs/Coroutines.rst for more details.
+//
+namespace {
+ struct LValueOrRValue {
+ LValue LV;
+ RValue RV;
+ };
+}
+static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
+ CoroutineSuspendExpr const &S,
+ AwaitKind Kind, AggValueSlot aggSlot,
+ bool ignoreResult, bool forLValue) {
+ auto *E = S.getCommonExpr();
+
+ auto Binder =
+ CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E);
+ auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); });
+
+ auto Prefix = buildSuspendPrefixStr(Coro, Kind);
+ BasicBlock *ReadyBlock = CGF.createBasicBlock(Prefix + Twine(".ready"));
+ BasicBlock *SuspendBlock = CGF.createBasicBlock(Prefix + Twine(".suspend"));
+ BasicBlock *CleanupBlock = CGF.createBasicBlock(Prefix + Twine(".cleanup"));
+
+ // If expression is ready, no need to suspend.
+ CGF.EmitBranchOnBoolExpr(S.getReadyExpr(), ReadyBlock, SuspendBlock, 0);
+
+ // Otherwise, emit suspend logic.
+ CGF.EmitBlock(SuspendBlock);
+
+ auto &Builder = CGF.Builder;
+ llvm::Function *CoroSave = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_save);
+ auto *NullPtr = llvm::ConstantPointerNull::get(CGF.CGM.Int8PtrTy);
+ auto *SaveCall = Builder.CreateCall(CoroSave, {NullPtr});
+
+ auto *SuspendRet = CGF.EmitScalarExpr(S.getSuspendExpr());
+ if (SuspendRet != nullptr && SuspendRet->getType()->isIntegerTy(1)) {
+ // Veto suspension if requested by bool returning await_suspend.
+ BasicBlock *RealSuspendBlock =
+ CGF.createBasicBlock(Prefix + Twine(".suspend.bool"));
+ CGF.Builder.CreateCondBr(SuspendRet, RealSuspendBlock, ReadyBlock);
+ SuspendBlock = RealSuspendBlock;
+ CGF.EmitBlock(RealSuspendBlock);
+ }
+
+ // Emit the suspend point.
+ const bool IsFinalSuspend = (Kind == AwaitKind::Final);
+ llvm::Function *CoroSuspend =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_suspend);
+ auto *SuspendResult = Builder.CreateCall(
+ CoroSuspend, {SaveCall, Builder.getInt1(IsFinalSuspend)});
+
+ // Create a switch capturing three possible continuations.
+ auto *Switch = Builder.CreateSwitch(SuspendResult, Coro.SuspendBB, 2);
+ Switch->addCase(Builder.getInt8(0), ReadyBlock);
+ Switch->addCase(Builder.getInt8(1), CleanupBlock);
+
+ // Emit cleanup for this suspend point.
+ CGF.EmitBlock(CleanupBlock);
+ CGF.EmitBranchThroughCleanup(Coro.CleanupJD);
+
+ // Emit await_resume expression.
+ CGF.EmitBlock(ReadyBlock);
+ LValueOrRValue Res;
+ if (forLValue)
+ Res.LV = CGF.EmitLValue(S.getResumeExpr());
+ else
+ Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
+ return Res;
+}
+
+RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E,
+ AggValueSlot aggSlot,
+ bool ignoreResult) {
+ return emitSuspendExpression(*this, *CurCoro.Data, E,
+ CurCoro.Data->CurrentAwaitKind, aggSlot,
+ ignoreResult, /*forLValue*/false).RV;
+}
+RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E,
+ AggValueSlot aggSlot,
+ bool ignoreResult) {
+ return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield,
+ aggSlot, ignoreResult, /*forLValue*/false).RV;
+}
+
void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
++CurCoro.Data->CoreturnCount;
+ const Expr *RV = S.getOperand();
+ if (RV && RV->getType()->isVoidType()) {
+ // Make sure to evaluate the expression of a co_return with a void
+ // expression for side effects.
+ RunCleanupsScope cleanupScope(*this);
+ EmitIgnoredExpr(RV);
+ }
EmitStmt(S.getPromiseCall());
EmitBranchThroughCleanup(CurCoro.Data->FinalJD);
}
+
+#ifndef NDEBUG
+static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx,
+ const CoroutineSuspendExpr *E) {
+ const auto *RE = E->getResumeExpr();
+ // Is it possible for RE to be a CXXBindTemporaryExpr wrapping
+ // a MemberCallExpr?
+ assert(isa<CallExpr>(RE) && "unexpected suspend expression type");
+ return cast<CallExpr>(RE)->getCallReturnType(Ctx);
+}
+#endif
+
+LValue
+CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) {
+ assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
+ "Can't have a scalar return unless the return type is a "
+ "reference type!");
+ return emitSuspendExpression(*this, *CurCoro.Data, *E,
+ CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(),
+ /*ignoreResult*/false, /*forLValue*/true).LV;
+}
+
+LValue
+CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) {
+ assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
+ "Can't have a scalar return unless the return type is a "
+ "reference type!");
+ return emitSuspendExpression(*this, *CurCoro.Data, *E,
+ AwaitKind::Yield, AggValueSlot::ignored(),
+ /*ignoreResult*/false, /*forLValue*/true).LV;
+}
+
+// Hunts for the parameter reference in the parameter copy/move declaration.
+namespace {
+struct GetParamRef : public StmtVisitor<GetParamRef> {
+public:
+ DeclRefExpr *Expr = nullptr;
+ GetParamRef() {}
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ assert(Expr == nullptr && "multilple declref in param move");
+ Expr = E;
+ }
+ void VisitStmt(Stmt *S) {
+ for (auto *C : S->children()) {
+ if (C)
+ Visit(C);
+ }
+ }
+};
+}
+
+// This class replaces references to parameters to their copies by changing
+// the addresses in CGF.LocalDeclMap and restoring back the original values in
+// its destructor.
+
+namespace {
+ struct ParamReferenceReplacerRAII {
+ CodeGenFunction::DeclMapTy SavedLocals;
+ CodeGenFunction::DeclMapTy& LocalDeclMap;
+
+ ParamReferenceReplacerRAII(CodeGenFunction::DeclMapTy &LocalDeclMap)
+ : LocalDeclMap(LocalDeclMap) {}
+
+ void addCopy(DeclStmt const *PM) {
+ // Figure out what param it refers to.
+
+ assert(PM->isSingleDecl());
+ VarDecl const*VD = static_cast<VarDecl const*>(PM->getSingleDecl());
+ Expr const *InitExpr = VD->getInit();
+ GetParamRef Visitor;
+ Visitor.Visit(const_cast<Expr*>(InitExpr));
+ assert(Visitor.Expr);
+ auto *DREOrig = cast<DeclRefExpr>(Visitor.Expr);
+ auto *PD = DREOrig->getDecl();
+
+ auto it = LocalDeclMap.find(PD);
+ assert(it != LocalDeclMap.end() && "parameter is not found");
+ SavedLocals.insert({ PD, it->second });
+
+ auto copyIt = LocalDeclMap.find(VD);
+ assert(copyIt != LocalDeclMap.end() && "parameter copy is not found");
+ it->second = copyIt->getSecond();
+ }
+
+ ~ParamReferenceReplacerRAII() {
+ for (auto&& SavedLocal : SavedLocals) {
+ LocalDeclMap.insert({SavedLocal.first, SavedLocal.second});
+ }
+ }
+ };
+}
+
+// For WinEH exception representation backend needs to know what funclet coro.end
+// belongs to. That information is passed in a funclet bundle.
+static SmallVector<llvm::OperandBundleDef, 1>
+getBundlesForCoroEnd(CodeGenFunction &CGF) {
+ SmallVector<llvm::OperandBundleDef, 1> BundleList;
+
+ if (llvm::Instruction *EHPad = CGF.CurrentFuncletPad)
+ BundleList.emplace_back("funclet", EHPad);
+
+ return BundleList;
+}
+
+namespace {
+// We will insert coro.end to cut any of the destructors for objects that
+// do not need to be destroyed once the coroutine is resumed.
+// See llvm/docs/Coroutines.rst for more details about coro.end.
+struct CallCoroEnd final : public EHScopeStack::Cleanup {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ auto &CGM = CGF.CGM;
+ auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
+ llvm::Function *CoroEndFn = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
+ // See if we have a funclet bundle to associate coro.end with. (WinEH)
+ auto Bundles = getBundlesForCoroEnd(CGF);
+ auto *CoroEnd = CGF.Builder.CreateCall(
+ CoroEndFn, {NullPtr, CGF.Builder.getTrue()}, Bundles);
+ if (Bundles.empty()) {
+ // Otherwise, (landingpad model), create a conditional branch that leads
+ // either to a cleanup block or a block with EH resume instruction.
+ auto *ResumeBB = CGF.getEHResumeBlock(/*cleanup=*/true);
+ auto *CleanupContBB = CGF.createBasicBlock("cleanup.cont");
+ CGF.Builder.CreateCondBr(CoroEnd, ResumeBB, CleanupContBB);
+ CGF.EmitBlock(CleanupContBB);
+ }
+ }
+};
+}
+
+namespace {
+// Make sure to call coro.delete on scope exit.
+struct CallCoroDelete final : public EHScopeStack::Cleanup {
+ Stmt *Deallocate;
+
+ // Emit "if (coro.free(CoroId, CoroBegin)) Deallocate;"
+
+ // Note: That deallocation will be emitted twice: once for a normal exit and
+ // once for exceptional exit. This usage is safe because Deallocate does not
+ // contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr()
+ // builds a single call to a deallocation function which is safe to emit
+ // multiple times.
+ void Emit(CodeGenFunction &CGF, Flags) override {
+ // Remember the current point, as we are going to emit deallocation code
+ // first to get to coro.free instruction that is an argument to a delete
+ // call.
+ BasicBlock *SaveInsertBlock = CGF.Builder.GetInsertBlock();
+
+ auto *FreeBB = CGF.createBasicBlock("coro.free");
+ CGF.EmitBlock(FreeBB);
+ CGF.EmitStmt(Deallocate);
+
+ auto *AfterFreeBB = CGF.createBasicBlock("after.coro.free");
+ CGF.EmitBlock(AfterFreeBB);
+
+ // We should have captured coro.free from the emission of deallocate.
+ auto *CoroFree = CGF.CurCoro.Data->LastCoroFree;
+ if (!CoroFree) {
+ CGF.CGM.Error(Deallocate->getLocStart(),
+ "Deallocation expressoin does not refer to coro.free");
+ return;
+ }
+
+ // Get back to the block we were originally and move coro.free there.
+ auto *InsertPt = SaveInsertBlock->getTerminator();
+ CoroFree->moveBefore(InsertPt);
+ CGF.Builder.SetInsertPoint(InsertPt);
+
+ // Add if (auto *mem = coro.free) Deallocate;
+ auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
+ auto *Cond = CGF.Builder.CreateICmpNE(CoroFree, NullPtr);
+ CGF.Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB);
+
+ // No longer need old terminator.
+ InsertPt->eraseFromParent();
+ CGF.Builder.SetInsertPoint(AfterFreeBB);
+ }
+ explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
+};
+}
+
+namespace {
+struct GetReturnObjectManager {
+ CodeGenFunction &CGF;
+ CGBuilderTy &Builder;
+ const CoroutineBodyStmt &S;
+
+ Address GroActiveFlag;
+ CodeGenFunction::AutoVarEmission GroEmission;
+
+ GetReturnObjectManager(CodeGenFunction &CGF, const CoroutineBodyStmt &S)
+ : CGF(CGF), Builder(CGF.Builder), S(S), GroActiveFlag(Address::invalid()),
+ GroEmission(CodeGenFunction::AutoVarEmission::invalid()) {}
+
+ // The gro variable has to outlive coroutine frame and coroutine promise, but,
+ // it can only be initialized after coroutine promise was created, thus, we
+ // split its emission in two parts. EmitGroAlloca emits an alloca and sets up
+ // cleanups. Later when coroutine promise is available we initialize the gro
+ // and sets the flag that the cleanup is now active.
+
+ void EmitGroAlloca() {
+ auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl());
+ if (!GroDeclStmt) {
+ // If get_return_object returns void, no need to do an alloca.
+ return;
+ }
+
+ auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl());
+
+ // Set GRO flag that it is not initialized yet
+ GroActiveFlag =
+ CGF.CreateTempAlloca(Builder.getInt1Ty(), CharUnits::One(), "gro.active");
+ Builder.CreateStore(Builder.getFalse(), GroActiveFlag);
+
+ GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl);
+
+ // Remember the top of EHStack before emitting the cleanup.
+ auto old_top = CGF.EHStack.stable_begin();
+ CGF.EmitAutoVarCleanups(GroEmission);
+ auto top = CGF.EHStack.stable_begin();
+
+ // Make the cleanup conditional on gro.active
+ for (auto b = CGF.EHStack.find(top), e = CGF.EHStack.find(old_top);
+ b != e; b++) {
+ if (auto *Cleanup = dyn_cast<EHCleanupScope>(&*b)) {
+ assert(!Cleanup->hasActiveFlag() && "cleanup already has active flag?");
+ Cleanup->setActiveFlag(GroActiveFlag);
+ Cleanup->setTestFlagInEHCleanup();
+ Cleanup->setTestFlagInNormalCleanup();
+ }
+ }
+ }
+
+ void EmitGroInit() {
+ if (!GroActiveFlag.isValid()) {
+ // No Gro variable was allocated. Simply emit the call to
+ // get_return_object.
+ CGF.EmitStmt(S.getResultDecl());
+ return;
+ }
+
+ CGF.EmitAutoVarInit(GroEmission);
+ Builder.CreateStore(Builder.getTrue(), GroActiveFlag);
+ }
+};
+}
+
+static void emitBodyAndFallthrough(CodeGenFunction &CGF,
+ const CoroutineBodyStmt &S, Stmt *Body) {
+ CGF.EmitStmt(Body);
+ const bool CanFallthrough = CGF.Builder.GetInsertBlock();
+ if (CanFallthrough)
+ if (Stmt *OnFallthrough = S.getFallthroughHandler())
+ CGF.EmitStmt(OnFallthrough);
+}
+
void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
auto &TI = CGM.getContext().getTargetInfo();
unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth();
+ auto *EntryBB = Builder.GetInsertBlock();
+ auto *AllocBB = createBasicBlock("coro.alloc");
+ auto *InitBB = createBasicBlock("coro.init");
auto *FinalBB = createBasicBlock("coro.final");
+ auto *RetBB = createBasicBlock("coro.ret");
auto *CoroId = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::coro_id),
{Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr});
createCoroData(*this, CurCoro, CoroId);
+ CurCoro.Data->SuspendBB = RetBB;
+
+ // Backend is allowed to elide memory allocations, to help it, emit
+ // auto mem = coro.alloc() ? 0 : ... allocation code ...;
+ auto *CoroAlloc = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId});
+
+ Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
+
+ EmitBlock(AllocBB);
+ auto *AllocateCall = EmitScalarExpr(S.getAllocate());
+ auto *AllocOrInvokeContBB = Builder.GetInsertBlock();
+
+ // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
+ if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
+ auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure");
+
+ // See if allocation was successful.
+ auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy);
+ auto *Cond = Builder.CreateICmpNE(AllocateCall, NullPtr);
+ Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB);
+
+ // If not, return OnAllocFailure object.
+ EmitBlock(RetOnFailureBB);
+ EmitStmt(RetOnAllocFailure);
+ }
+ else {
+ Builder.CreateBr(InitBB);
+ }
+
+ EmitBlock(InitBB);
+
+ // Pass the result of the allocation to coro.begin.
+ auto *Phi = Builder.CreatePHI(VoidPtrTy, 2);
+ Phi->addIncoming(NullPtr, EntryBB);
+ Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
+ auto *CoroBegin = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi});
+ CurCoro.Data->CoroBegin = CoroBegin;
- EmitScalarExpr(S.getAllocate());
+ GetReturnObjectManager GroManager(*this, S);
+ GroManager.EmitGroAlloca();
- // FIXME: Setup cleanup scopes.
+ CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB);
+ {
+ ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap);
+ CodeGenFunction::RunCleanupsScope ResumeScope(*this);
+ EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate());
+
+ // Create parameter copies. We do it before creating a promise, since an
+ // evolution of coroutine TS may allow promise constructor to observe
+ // parameter copies.
+ for (auto *PM : S.getParamMoves()) {
+ EmitStmt(PM);
+ ParamReplacer.addCopy(cast<DeclStmt>(PM));
+ // TODO: if(CoroParam(...)) need to surround ctor and dtor
+ // for the copy, so that llvm can elide it if the copy is
+ // not needed.
+ }
- EmitStmt(S.getPromiseDeclStmt());
+ EmitStmt(S.getPromiseDeclStmt());
- CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
+ Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl());
+ auto *PromiseAddrVoidPtr =
+ new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId);
+ // Update CoroId to refer to the promise. We could not do it earlier because
+ // promise local variable was not emitted yet.
+ CoroId->setArgOperand(1, PromiseAddrVoidPtr);
- // FIXME: Emit initial suspend and more before the body.
+ // Now we have the promise, initialize the GRO
+ GroManager.EmitGroInit();
- EmitStmt(S.getBody());
+ EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
- // See if we need to generate final suspend.
- const bool CanFallthrough = Builder.GetInsertBlock();
- const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
- if (CanFallthrough || HasCoreturns) {
- EmitBlock(FinalBB);
- // FIXME: Emit final suspend.
+ CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
+ EmitStmt(S.getInitSuspendStmt());
+ CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
+
+ CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
+
+ if (auto *OnException = S.getExceptionHandler()) {
+ auto Loc = S.getLocStart();
+ CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr, OnException);
+ auto *TryStmt = CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch);
+
+ EnterCXXTryStmt(*TryStmt);
+ emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
+ ExitCXXTryStmt(*TryStmt);
+ }
+ else {
+ emitBodyAndFallthrough(*this, S, S.getBody());
+ }
+
+ // See if we need to generate final suspend.
+ const bool CanFallthrough = Builder.GetInsertBlock();
+ const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
+ if (CanFallthrough || HasCoreturns) {
+ EmitBlock(FinalBB);
+ CurCoro.Data->CurrentAwaitKind = AwaitKind::Final;
+ EmitStmt(S.getFinalSuspendStmt());
+ } else {
+ // We don't need FinalBB. Emit it to make sure the block is deleted.
+ EmitBlock(FinalBB, /*IsFinished=*/true);
+ }
}
- EmitStmt(S.getDeallocate());
- // FIXME: Emit return for the coroutine return object.
+ EmitBlock(RetBB);
+ // Emit coro.end before getReturnStmt (and parameter destructors), since
+ // resume and destroy parts of the coroutine should not include them.
+ llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
+ Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()});
+
+ if (Stmt *Ret = S.getReturnStmt())
+ EmitStmt(Ret);
}
// Emit coroutine intrinsic and patch up arguments of the token type.
@@ -115,6 +636,17 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
switch (IID) {
default:
break;
+ // The coro.frame builtin is replaced with an SSA value of the coro.begin
+ // intrinsic.
+ case llvm::Intrinsic::coro_frame: {
+ if (CurCoro.Data && CurCoro.Data->CoroBegin) {
+ return RValue::get(CurCoro.Data->CoroBegin);
+ }
+ CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_begin "
+ "has been used earlier in this function");
+ auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
+ return RValue::get(NullPtr);
+ }
// The following three intrinsics take a token parameter referring to a token
// returned by earlier call to @llvm.coro.id. Since we cannot represent it in
// builtins, we patch it up here.
@@ -128,6 +660,7 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_id has"
" been used earlier in this function");
// Fallthrough to the next case to add TokenNone as the first argument.
+ LLVM_FALLTHROUGH;
}
// @llvm.coro.suspend takes a token parameter. Add token 'none' as the first
// argument.
@@ -141,10 +674,22 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
llvm::Value *F = CGM.getIntrinsic(IID);
llvm::CallInst *Call = Builder.CreateCall(F, Args);
+ // Note: The following code is to enable to emit coro.id and coro.begin by
+ // hand to experiment with coroutines in C.
// If we see @llvm.coro.id remember it in the CoroData. We will update
// coro.alloc, coro.begin and coro.free intrinsics to refer to it.
if (IID == llvm::Intrinsic::coro_id) {
createCoroData(*this, CurCoro, Call, E);
}
+ else if (IID == llvm::Intrinsic::coro_begin) {
+ if (CurCoro.Data)
+ CurCoro.Data->CoroBegin = Call;
+ }
+ else if (IID == llvm::Intrinsic::coro_free) {
+ // Remember the last coro_free as we need it to build the conditional
+ // deletion of the coroutine frame.
+ if (CurCoro.Data)
+ CurCoro.Data->LastCoroFree = Call;
+ }
return RValue::get(Call);
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 05987be845..3e4acd208f 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -18,6 +18,7 @@
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "ConstantEmitter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
@@ -28,6 +29,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Frontend/FrontendOptions.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PreprocessorOptions.h"
@@ -95,6 +97,10 @@ void ApplyDebugLocation::init(SourceLocation TemporaryLocation,
}
OriginalLocation = CGF->Builder.getCurrentDebugLocation();
+
+ if (OriginalLocation && !DI->CGM.getExpressionLocationsEnabled())
+ return;
+
if (TemporaryLocation.isValid()) {
DI->EmitLocation(CGF->Builder, TemporaryLocation);
return;
@@ -209,7 +215,7 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context,
// Check namespace.
if (const auto *NSDecl = dyn_cast<NamespaceDecl>(Context))
- return getOrCreateNameSpace(NSDecl);
+ return getOrCreateNamespace(NSDecl);
if (const auto *RDecl = dyn_cast<RecordDecl>(Context))
if (!RDecl->isDependentType())
@@ -218,6 +224,19 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context,
return Default;
}
+PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
+ PrintingPolicy PP = CGM.getContext().getPrintingPolicy();
+
+ // If we're emitting codeview, it's important to try to match MSVC's naming so
+ // that visualizers written for MSVC will trigger for our class names. In
+ // particular, we can't have spaces between arguments of standard templates
+ // like basic_string and vector.
+ if (CGM.getCodeGenOpts().EmitCodeView)
+ PP.MSVCFormatting = true;
+
+ return PP;
+}
+
StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
assert(FD && "Invalid FunctionDecl!");
IdentifierInfo *FII = FD->getIdentifier();
@@ -238,18 +257,16 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
SmallString<128> NS;
llvm::raw_svector_ostream OS(NS);
- PrintingPolicy Policy(CGM.getLangOpts());
- Policy.MSVCFormatting = CGM.getCodeGenOpts().EmitCodeView;
if (!UseQualifiedName)
FD->printName(OS);
else
- FD->printQualifiedName(OS, Policy);
+ FD->printQualifiedName(OS, getPrintingPolicy());
// Add any template specialization args.
if (Info) {
const TemplateArgumentList *TArgs = Info->TemplateArguments;
TemplateSpecializationType::PrintTemplateArgumentList(OS, TArgs->asArray(),
- Policy);
+ getPrintingPolicy());
}
// Copy this name on the side and use its reference.
@@ -296,7 +313,7 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
if (isa<ClassTemplateSpecializationDecl>(RD)) {
SmallString<128> Name;
llvm::raw_svector_ostream OS(Name);
- RD->getNameForDiagnostic(OS, CGM.getContext().getPrintingPolicy(),
+ RD->getNameForDiagnostic(OS, getPrintingPolicy(),
/*Qualified*/ false);
// Copy this name on the side and use its reference.
@@ -483,6 +500,16 @@ void CGDebugInfo::CreateCompileUnit() {
llvm::sys::path::append(MainFileDirSS, MainFileName);
MainFileName = MainFileDirSS.str();
}
+ // If the main file name provided is identical to the input file name, and
+ // if the input file is a preprocessed source, use the module name for
+ // debug info. The module name comes from the name specified in the first
+ // linemarker if the input is a preprocessed source.
+ if (MainFile->getName() == MainFileName &&
+ FrontendOptions::getInputKindForExtension(
+ MainFile->getName().rsplit('.').second)
+ .isPreprocessed())
+ MainFileName = CGM.getModule().getName().str();
+
CSKind = computeChecksum(SM.getMainFileID(), Checksum);
}
@@ -527,14 +554,16 @@ void CGDebugInfo::CreateCompileUnit() {
// Create new compile unit.
// FIXME - Eliminate TheCU.
+ auto &CGOpts = CGM.getCodeGenOpts();
TheCU = DBuilder.createCompileUnit(
- LangTag, DBuilder.createFile(remapDIPath(MainFileName),
- remapDIPath(getCurrentDirname()), CSKind,
- Checksum),
- Producer, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers,
- CGM.getCodeGenOpts().SplitDwarfFile, EmissionKind, 0 /* DWOid */,
- CGM.getCodeGenOpts().SplitDwarfInlining,
- CGM.getCodeGenOpts().DebugInfoForProfiling);
+ LangTag,
+ DBuilder.createFile(remapDIPath(MainFileName),
+ remapDIPath(getCurrentDirname()), CSKind, Checksum),
+ Producer, LO.Optimize || CGOpts.PrepareForLTO || CGOpts.EmitSummaryIndex,
+ CGOpts.DwarfDebugFlags, RuntimeVers,
+ CGOpts.EnableSplitDwarf ? "" : CGOpts.SplitDwarfFile, EmissionKind,
+ 0 /* DWOid */, CGOpts.SplitDwarfInlining, CGOpts.DebugInfoForProfiling,
+ CGOpts.GnuPubnames);
}
llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
@@ -643,6 +672,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Half:
case BuiltinType::Float:
case BuiltinType::LongDouble:
+ case BuiltinType::Float16:
case BuiltinType::Float128:
case BuiltinType::Double:
// FIXME: For targets where long double and __float128 have the same size,
@@ -803,6 +833,10 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType(
getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align,
llvm::DINode::FlagFwdDecl, FullName);
+ if (CGM.getCodeGenOpts().DebugFwdTemplateParams)
+ if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ DBuilder.replaceArrays(RetTy, llvm::DINodeArray(),
+ CollectCXXTemplateParams(TSpecial, DefUnit));
ReplaceMap.emplace_back(
std::piecewise_construct, std::make_tuple(Ty),
std::make_tuple(static_cast<llvm::Metadata *>(RetTy)));
@@ -907,12 +941,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
SmallString<128> NS;
llvm::raw_svector_ostream OS(NS);
- Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(),
+ Ty->getTemplateName().print(OS, getPrintingPolicy(),
/*qualified*/ false);
TemplateSpecializationType::PrintTemplateArgumentList(
- OS, Ty->template_arguments(),
- CGM.getContext().getPrintingPolicy());
+ OS, Ty->template_arguments(), getPrintingPolicy());
auto *AliasDecl = cast<TypeAliasTemplateDecl>(
Ty->getTemplateName().getAsTemplateDecl())->getTemplatedDecl();
@@ -954,7 +987,7 @@ static unsigned getDwarfCC(CallingConv CC) {
return llvm::dwarf::DW_CC_BORLAND_pascal;
// FIXME: Create new DW_CC_ codes for these calling conventions.
- case CC_X86_64Win64:
+ case CC_Win64:
case CC_X86_64SysV:
case CC_AAPCS:
case CC_AAPCS_VFP:
@@ -1039,7 +1072,13 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
assert(SizeInBits > 0 && "found named 0-width bitfield");
uint64_t StorageOffsetInBits =
CGM.getContext().toBits(BitFieldInfo.StorageOffset);
- uint64_t OffsetInBits = StorageOffsetInBits + BitFieldInfo.Offset;
+ uint64_t Offset = BitFieldInfo.Offset;
+ // The bit offsets for big endian machines are reversed for big
+ // endian target, compensate for that as the DIDerivedType requires
+ // un-reversed offsets.
+ if (CGM.getDataLayout().isBigEndian())
+ Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset;
+ uint64_t OffsetInBits = StorageOffsetInBits + Offset;
llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD);
return DBuilder.createBitFieldMemberType(
RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits,
@@ -1166,13 +1205,13 @@ void CGDebugInfo::CollectRecordNormalField(
elements.push_back(FieldType);
}
-void CGDebugInfo::CollectRecordNestedRecord(
- const RecordDecl *RD, SmallVectorImpl<llvm::Metadata *> &elements) {
- QualType Ty = CGM.getContext().getTypeDeclType(RD);
+void CGDebugInfo::CollectRecordNestedType(
+ const TypeDecl *TD, SmallVectorImpl<llvm::Metadata *> &elements) {
+ QualType Ty = CGM.getContext().getTypeDeclType(TD);
// Injected class names are not considered nested records.
if (isa<InjectedClassNameType>(Ty))
return;
- SourceLocation Loc = RD->getLocation();
+ SourceLocation Loc = TD->getLocation();
llvm::DIType *nestedType = getOrCreateType(Ty, getOrCreateFile(Loc));
elements.push_back(nestedType);
}
@@ -1188,9 +1227,9 @@ void CGDebugInfo::CollectRecordFields(
else {
const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
- // Debug info for nested records is included in the member list only for
+ // Debug info for nested types is included in the member list only for
// CodeView.
- bool IncludeNestedRecords = CGM.getCodeGenOpts().EmitCodeView;
+ bool IncludeNestedTypes = CGM.getCodeGenOpts().EmitCodeView;
// Field number for non-static fields.
unsigned fieldNo = 0;
@@ -1217,10 +1256,12 @@ void CGDebugInfo::CollectRecordFields(
// Bump field number for next field.
++fieldNo;
- } else if (const auto *nestedRec = dyn_cast<CXXRecordDecl>(I))
- if (IncludeNestedRecords && !nestedRec->isImplicit() &&
- nestedRec->getDeclContext() == record)
- CollectRecordNestedRecord(nestedRec, elements);
+ } else if (IncludeNestedTypes) {
+ if (const auto *nestedType = dyn_cast<TypeDecl>(I))
+ if (!nestedType->isImplicit() &&
+ nestedType->getDeclContext() == record)
+ CollectRecordNestedType(nestedType, elements);
+ }
}
}
@@ -1371,6 +1412,8 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
ContainingType = RecordTy;
}
+ if (Method->isStatic())
+ Flags |= llvm::DINode::FlagStaticMember;
if (Method->isImplicit())
Flags |= llvm::DINode::FlagArtificial;
Flags |= getAccessFlag(Method->getAccess(), Method->getParent());
@@ -1582,7 +1625,7 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
QualType T = E->getType();
if (E->isGLValue())
T = CGM.getContext().getLValueReferenceType(T);
- llvm::Constant *V = CGM.EmitConstantExpr(E, T);
+ llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(E, T);
assert(V && "Expression in template argument isn't constant");
llvm::DIType *TTy = getOrCreateType(T, Unit);
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
@@ -1758,6 +1801,29 @@ static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) {
return false;
}
+/// Does a type definition exist in an imported clang module?
+static bool isDefinedInClangModule(const RecordDecl *RD) {
+ // Only definitions that where imported from an AST file come from a module.
+ if (!RD || !RD->isFromASTFile())
+ return false;
+ // Anonymous entities cannot be addressed. Treat them as not from module.
+ if (!RD->isExternallyVisible() && RD->getName().empty())
+ return false;
+ if (auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) {
+ if (!CXXDecl->isCompleteDefinition())
+ return false;
+ auto TemplateKind = CXXDecl->getTemplateSpecializationKind();
+ if (TemplateKind != TSK_Undeclared) {
+ // This is a template, check the origin of the first member.
+ if (CXXDecl->field_begin() == CXXDecl->field_end())
+ return TemplateKind == TSK_ExplicitInstantiationDeclaration;
+ if (!CXXDecl->field_begin()->isFromASTFile())
+ return false;
+ }
+ }
+ return true;
+}
+
void CGDebugInfo::completeClassData(const RecordDecl *RD) {
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
if (CXXRD->isDynamicClass() &&
@@ -1765,6 +1831,10 @@ void CGDebugInfo::completeClassData(const RecordDecl *RD) {
llvm::GlobalValue::AvailableExternallyLinkage &&
!isClassOrMethodDLLImport(CXXRD))
return;
+
+ if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
+ return;
+
completeClass(RD);
}
@@ -1791,35 +1861,16 @@ static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I,
return false;
}
-/// Does a type definition exist in an imported clang module?
-static bool isDefinedInClangModule(const RecordDecl *RD) {
- // Only definitions that where imported from an AST file come from a module.
- if (!RD || !RD->isFromASTFile())
- return false;
- // Anonymous entities cannot be addressed. Treat them as not from module.
- if (!RD->isExternallyVisible() && RD->getName().empty())
- return false;
- if (auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) {
- if (!CXXDecl->isCompleteDefinition())
- return false;
- auto TemplateKind = CXXDecl->getTemplateSpecializationKind();
- if (TemplateKind != TSK_Undeclared) {
- // This is a template, check the origin of the first member.
- if (CXXDecl->field_begin() == CXXDecl->field_end())
- return TemplateKind == TSK_ExplicitInstantiationDeclaration;
- if (!CXXDecl->field_begin()->isFromASTFile())
- return false;
- }
- }
- return true;
-}
-
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;
@@ -2552,11 +2603,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) {
@@ -2601,7 +2658,7 @@ llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) {
// best to make this behavior a command line or debugger tuning
// option.
FullSourceLoc Loc(D->getLocation(), CGM.getContext().getSourceManager());
- if (Module *M = ClangModuleMap->inferModuleFromLocation(Loc)) {
+ if (Module *M = D->getOwningModule()) {
// This is a (sub-)module.
auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
return getOrCreateModuleRef(Info, /*SkeletonCU=*/false);
@@ -2769,6 +2826,7 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// them distinct if they are ODR-uniqued.
if (FullName.empty())
break;
+ LLVM_FALLTHROUGH;
case llvm::dwarf::DW_TAG_structure_type:
case llvm::dwarf::DW_TAG_union_type:
@@ -2849,7 +2907,7 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
if (DebugKind >= codegenoptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
- FDContext = getOrCreateNameSpace(NSDecl);
+ FDContext = getOrCreateNamespace(NSDecl);
else if (const RecordDecl *RDecl =
dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) {
llvm::DIScope *Mod = getParentModuleOrNull(RDecl);
@@ -3241,7 +3299,7 @@ void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
llvm::DISubprogram *SP = nullptr;
if (FI != SPCache.end())
SP = dyn_cast_or_null<llvm::DISubprogram>(FI->second);
- if (!SP)
+ if (!SP || !SP->isDefinition())
SP = getFunctionStub(GD);
FnBeginRegionCount.push_back(LexicalBlockStack.size());
LexicalBlockStack.emplace_back(SP);
@@ -3251,7 +3309,7 @@ void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy &Builder) {
assert(CurInlinedAt && "unbalanced inline scope stack");
- EmitFunctionEnd(Builder);
+ EmitFunctionEnd(Builder, nullptr);
setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt());
}
@@ -3320,7 +3378,7 @@ void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
LexicalBlockStack.pop_back();
}
-void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
+void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) {
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
unsigned RCount = FnBeginRegionCount.back();
assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
@@ -3332,6 +3390,9 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
LexicalBlockStack.pop_back();
}
FnBeginRegionCount.pop_back();
+
+ if (Fn && Fn->getSubprogram())
+ DBuilder.finalizeSubprogram(Fn->getSubprogram());
}
llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
@@ -3450,50 +3511,35 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
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
- // functions there won't be an implicit param at arg1 and
- // otherwise it is 'self' or 'this'.
- if (isa<ImplicitParamDecl>(VD) && ArgNo && *ArgNo == 1)
- Flags |= llvm::DINode::FlagObjectPointer;
- if (auto *Arg = dyn_cast<llvm::Argument>(Storage))
- if (Arg->getType()->isPointerTy() && !Arg->hasByValAttr() &&
- !VD->getType()->isPointerType())
- Expr.push_back(llvm::dwarf::DW_OP_deref);
+ // If this is implicit parameter of CXXThis or ObjCSelf kind, then give it an
+ // object pointer flag.
+ if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD)) {
+ if (IPD->getParameterKind() == ImplicitParamDecl::CXXThis ||
+ IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
+ Flags |= llvm::DINode::FlagObjectPointer;
+ }
+ // Note: Older versions of clang used to emit byval references with an extra
+ // DW_OP_deref, because they referenced the IR arg directly instead of
+ // referencing an alloca. Newer versions of LLVM don't treat allocas
+ // differently from other function arguments when used in a dbg.declare.
auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
-
StringRef Name = VD->getName();
if (!Name.empty()) {
if (VD->hasAttr<BlocksAttr>()) {
+ // Here, we need an offset *into* the alloca.
CharUnits offset = CharUnits::fromQuantity(32);
- Expr.push_back(llvm::dwarf::DW_OP_plus);
+ Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
CGM.getTarget().getPointerWidth(0));
Expr.push_back(offset.getQuantity());
Expr.push_back(llvm::dwarf::DW_OP_deref);
- Expr.push_back(llvm::dwarf::DW_OP_plus);
+ Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
Expr.push_back(offset.getQuantity());
-
- // Create the descriptor for the variable.
- auto *D = ArgNo
- ? DBuilder.createParameterVariable(Scope, VD->getName(),
- *ArgNo, Unit, Line, Ty)
- : DBuilder.createAutoVariable(Scope, VD->getName(), Unit,
- Line, Ty, Align);
-
- // Insert an llvm.dbg.declare into the current block.
- DBuilder.insertDeclare(
- Storage, D, DBuilder.createExpression(Expr),
- llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
- Builder.GetInsertBlock());
- return;
- } else if (isa<VariableArrayType>(VD->getType()))
- Expr.push_back(llvm::dwarf::DW_OP_deref);
+ }
} else if (const auto *RT = dyn_cast<RecordType>(VD->getType())) {
// If VD is an anonymous union then Storage represents value for
// all union fields.
@@ -3582,8 +3628,9 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
// Self is passed along as an implicit non-arg variable in a
// block. Mark it as the object pointer.
- if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self")
- Ty = CreateSelfType(VD->getType(), Ty);
+ if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD))
+ if (IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
+ Ty = CreateSelfType(VD->getType(), Ty);
// Get location information.
unsigned Line = getLineNumber(VD->getLocation());
@@ -3596,19 +3643,18 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
SmallVector<int64_t, 9> addr;
- if (isa<llvm::AllocaInst>(Storage))
- addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus);
+ addr.push_back(llvm::dwarf::DW_OP_deref);
+ addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
addr.push_back(offset.getQuantity());
if (isByRef) {
addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus);
+ addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of __forwarding field
offset =
CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0));
addr.push_back(offset.getQuantity());
addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus);
+ addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
addr.push_back(offset.getQuantity());
@@ -3623,12 +3669,11 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
// Insert an llvm.dbg.declare into the current block.
auto DL =
llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt);
+ auto *Expr = DBuilder.createExpression(addr);
if (InsertPoint)
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
- InsertPoint);
+ DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint);
else
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
- Builder.GetInsertBlock());
+ DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock());
}
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
@@ -3649,9 +3694,9 @@ bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
}
void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *Arg,
+ StringRef Name,
unsigned ArgNo,
- llvm::Value *LocalAddr,
+ llvm::AllocaInst *Alloca,
CGBuilderTy &Builder) {
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
ASTContext &C = CGM.getContext();
@@ -3783,19 +3828,11 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
// Create the descriptor for the parameter.
auto *debugVar = DBuilder.createParameterVariable(
- scope, Arg->getName(), ArgNo, tunit, line, type,
+ scope, Name, ArgNo, tunit, line, type,
CGM.getLangOpts().Optimize, flags);
- if (LocalAddr) {
- // Insert an llvm.dbg.value into the current block.
- DBuilder.insertDbgValueIntrinsic(
- LocalAddr, 0, debugVar, DBuilder.createExpression(),
- llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
- Builder.GetInsertBlock());
- }
-
// Insert an llvm.dbg.declare into the current block.
- DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(),
+ DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(),
llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
Builder.GetInsertBlock());
}
@@ -3964,10 +4001,10 @@ void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
const NamespaceDecl *NSDecl = UD.getNominatedNamespace();
if (!NSDecl->isAnonymousNamespace() ||
CGM.getCodeGenOpts().DebugExplicitImport) {
+ auto Loc = UD.getLocation();
DBuilder.createImportedModule(
getCurrentContextDescriptor(cast<Decl>(UD.getDeclContext())),
- getOrCreateNameSpace(NSDecl),
- getLineNumber(UD.getLocation()));
+ getOrCreateNamespace(NSDecl), getOrCreateFile(Loc), getLineNumber(Loc));
}
}
@@ -3990,10 +4027,12 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
if (AT->getDeducedType().isNull())
return;
if (llvm::DINode *Target =
- getDeclarationOrDefinition(USD.getUnderlyingDecl()))
+ getDeclarationOrDefinition(USD.getUnderlyingDecl())) {
+ auto Loc = USD.getLocation();
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
- getLineNumber(USD.getLocation()));
+ getOrCreateFile(Loc), getLineNumber(Loc));
+ }
}
void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
@@ -4001,10 +4040,11 @@ void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
return;
if (Module *M = ID.getImportedModule()) {
auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
+ auto Loc = ID.getLocation();
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(ID.getDeclContext())),
- getOrCreateModuleRef(Info, DebugTypeExtRefs),
- getLineNumber(ID.getLocation()));
+ getOrCreateModuleRef(Info, DebugTypeExtRefs), getOrCreateFile(Loc),
+ getLineNumber(Loc));
}
}
@@ -4016,35 +4056,37 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
if (VH)
return cast<llvm::DIImportedEntity>(VH);
llvm::DIImportedEntity *R;
+ auto Loc = NA.getLocation();
if (const auto *Underlying =
dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
// This could cache & dedup here rather than relying on metadata deduping.
R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
- EmitNamespaceAlias(*Underlying), getLineNumber(NA.getLocation()),
- NA.getName());
+ EmitNamespaceAlias(*Underlying), getOrCreateFile(Loc),
+ getLineNumber(Loc), NA.getName());
else
R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
- getOrCreateNameSpace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
- getLineNumber(NA.getLocation()), NA.getName());
+ getOrCreateNamespace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
+ getOrCreateFile(Loc), getLineNumber(Loc), NA.getName());
VH.reset(R);
return R;
}
llvm::DINamespace *
-CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
- NSDecl = NSDecl->getCanonicalDecl();
- auto I = NameSpaceCache.find(NSDecl);
- if (I != NameSpaceCache.end())
+CGDebugInfo::getOrCreateNamespace(const NamespaceDecl *NSDecl) {
+ // Don't canonicalize the NamespaceDecl here: The DINamespace will be uniqued
+ // if necessary, and this way multiple declarations of the same namespace in
+ // different parent modules stay distinct.
+ auto I = NamespaceCache.find(NSDecl);
+ if (I != NamespaceCache.end())
return cast<llvm::DINamespace>(I->second);
- unsigned LineNo = getLineNumber(NSDecl->getLocation());
- llvm::DIFile *FileD = getOrCreateFile(NSDecl->getLocation());
llvm::DIScope *Context = getDeclContextDescriptor(NSDecl);
- llvm::DINamespace *NS = DBuilder.createNameSpace(
- Context, NSDecl->getName(), FileD, LineNo, NSDecl->isInline());
- NameSpaceCache[NSDecl].reset(NS);
+ // Don't trust the context if it is a DIModule (see comment above).
+ llvm::DINamespace *NS =
+ DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline());
+ NamespaceCache[NSDecl].reset(NS);
return NS;
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index c6d1c66e13..4f7b7f2a0d 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -125,7 +125,7 @@ class CGDebugInfo {
/// Cache declarations relevant to DW_TAG_imported_declarations (C++
/// using declarations) that aren't covered by other more specific caches.
llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache;
- llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NameSpaceCache;
+ llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NamespaceCache;
llvm::DenseMap<const NamespaceAliasDecl *, llvm::TrackingMDRef>
NamespaceAliasCache;
llvm::DenseMap<const Decl *, llvm::TypedTrackingMDRef<llvm::DIDerivedType>>
@@ -194,8 +194,9 @@ class CGDebugInfo {
getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F);
/// \return debug info descriptor for vtable.
llvm::DIType *getOrCreateVTablePtrType(llvm::DIFile *F);
+
/// \return namespace descriptor for the given namespace decl.
- llvm::DINamespace *getOrCreateNameSpace(const NamespaceDecl *N);
+ llvm::DINamespace *getOrCreateNamespace(const NamespaceDecl *N);
llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty,
QualType PointeeTy, llvm::DIFile *F);
llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache);
@@ -277,8 +278,8 @@ class CGDebugInfo {
llvm::DIFile *F,
SmallVectorImpl<llvm::Metadata *> &E,
llvm::DIType *RecordTy, const RecordDecl *RD);
- void CollectRecordNestedRecord(const RecordDecl *RD,
- SmallVectorImpl<llvm::Metadata *> &E);
+ void CollectRecordNestedType(const TypeDecl *RD,
+ SmallVectorImpl<llvm::Metadata *> &E);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile *F,
SmallVectorImpl<llvm::Metadata *> &E,
llvm::DICompositeType *RecordTy);
@@ -366,7 +367,7 @@ public:
void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType);
/// Constructs the debug code for exiting a function.
- void EmitFunctionEnd(CGBuilderTy &Builder);
+ void EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn);
/// Emit metadata to indicate the beginning of a new lexical block
/// and push the block onto the stack.
@@ -397,8 +398,8 @@ public:
/// Emit call to \c llvm.dbg.declare for the block-literal argument
/// to a block invocation function.
void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *Arg, unsigned ArgNo,
- llvm::Value *LocalAddr,
+ StringRef Name, unsigned ArgNo,
+ llvm::AllocaInst *LocalAddr,
CGBuilderTy &Builder);
/// Emit information about a global variable.
@@ -438,6 +439,7 @@ public:
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.
@@ -556,6 +558,9 @@ private:
unsigned LineNo, StringRef LinkageName,
llvm::GlobalVariable *Var, llvm::DIScope *DContext);
+ /// Get the printing policy for producing names for debug info.
+ PrintingPolicy getPrintingPolicy() const;
+
/// Get function name for the given FunctionDecl. If the name is
/// constructed on demand (e.g., C++ destructor) then the name is
/// stored on the side.
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index cfadce5c22..44a6db4750 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -11,14 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGBlocks.h"
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGOpenCLRuntime.h"
#include "CGOpenMPRuntime.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "ConstantEmitter.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
@@ -152,7 +154,14 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
/// EmitVarDecl - This method handles emission of any variable declaration
/// inside a function, including static vars etc.
void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
- if (D.isStaticLocal()) {
+ if (D.hasExternalStorage())
+ // Don't emit it now, allow it to be emitted lazily on its first use.
+ return;
+
+ // Some function-scope variable does not have static storage but still
+ // needs to be emitted like a static variable, e.g. a function-scope
+ // variable in constant address space in OpenCL.
+ if (D.getStorageDuration() != SD_Automatic) {
llvm::GlobalValue::LinkageTypes Linkage =
CGM.getLLVMLinkageVarDefinition(&D, /*isConstant=*/false);
@@ -163,10 +172,6 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
return EmitStaticVarDecl(D, Linkage);
}
- if (D.hasExternalStorage())
- // Don't emit it now, allow it to be emitted lazily on its first use.
- return;
-
if (D.getType().getAddressSpace() == LangAS::opencl_local)
return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D);
@@ -217,8 +222,8 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
Name = getStaticDeclName(*this, D);
llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty);
- unsigned AddrSpace =
- GetGlobalVarAddressSpace(&D, getContext().getTargetAddressSpace(Ty));
+ LangAS AS = GetGlobalVarAddressSpace(&D);
+ unsigned TargetAS = getContext().getTargetAddressSpace(AS);
// Local address space cannot have an initializer.
llvm::Constant *Init = nullptr;
@@ -227,12 +232,9 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
else
Init = llvm::UndefValue::get(LTy);
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), LTy,
- Ty.isConstant(getContext()), Linkage,
- Init, Name, nullptr,
- llvm::GlobalVariable::NotThreadLocal,
- AddrSpace);
+ llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+ getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name,
+ nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
setGlobalVisibility(GV, &D);
@@ -250,11 +252,12 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
}
// Make sure the result is of the correct type.
- unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(Ty);
+ LangAS ExpectedAS = Ty.getAddressSpace();
llvm::Constant *Addr = GV;
- if (AddrSpace != ExpectedAddrSpace) {
- llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace);
- Addr = llvm::ConstantExpr::getAddrSpaceCast(GV, PTy);
+ if (AS != ExpectedAS) {
+ Addr = getTargetCodeGenInfo().performAddrSpaceCast(
+ *this, GV, AS, ExpectedAS,
+ LTy->getPointerTo(getContext().getTargetAddressSpace(ExpectedAS)));
}
setStaticLocalDeclAddress(&D, Addr);
@@ -305,7 +308,8 @@ static bool hasNontrivialDestruction(QualType T) {
llvm::GlobalVariable *
CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
llvm::GlobalVariable *GV) {
- llvm::Constant *Init = CGM.EmitConstantInit(D, this);
+ ConstantEmitter emitter(*this);
+ llvm::Constant *Init = emitter.tryEmitForInitializer(D);
// If constant emission failed, then this should be a C++ static
// initializer.
@@ -353,6 +357,8 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
GV->setConstant(CGM.isTypeConstant(D.getType(), true));
GV->setInitializer(Init);
+ emitter.finalize(GV);
+
if (hasNontrivialDestruction(D.getType()) && HaveInsertPoint()) {
// We have a constant initializer, but a nontrivial destructor. We still
// need to perform a guarded "initialization" in order to register the
@@ -402,6 +408,13 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
if (D.hasAttr<AnnotateAttr>())
CGM.AddGlobalAnnotations(&D, var);
+ if (auto *SA = D.getAttr<PragmaClangBSSSectionAttr>())
+ var->addAttribute("bss-section", SA->getName());
+ if (auto *SA = D.getAttr<PragmaClangDataSectionAttr>())
+ var->addAttribute("data-section", SA->getName());
+ if (auto *SA = D.getAttr<PragmaClangRodataSectionAttr>())
+ var->addAttribute("rodata-section", SA->getName());
+
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
var->setSection(SA->getName());
@@ -685,11 +698,10 @@ void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS,
// hand side must be nonnull.
SanitizerScope SanScope(this);
llvm::Value *IsNotNull = Builder.CreateIsNotNull(RHS);
- // FIXME: The runtime shouldn't refer to a 'reference'.
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(LHS.getType()),
- llvm::ConstantInt::get(Int8Ty, 1),
- llvm::ConstantInt::get(Int8Ty, TCK_ReferenceBinding)};
+ llvm::ConstantInt::get(Int8Ty, 0), // The LogAlignment info is unused.
+ llvm::ConstantInt::get(Int8Ty, TCK_NonnullAssign)};
EmitCheck({{IsNotNull, SanitizerKind::NullabilityAssign}},
SanitizerHandler::TypeMismatch, StaticData, RHS);
}
@@ -925,7 +937,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
return nullptr;
llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size);
- Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+ Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
llvm::CallInst *C =
Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr});
C->setDoesNotThrow();
@@ -933,7 +945,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
}
void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
- Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+ Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
llvm::CallInst *C =
Builder.CreateCall(CGM.getLLVMLifetimeEndFn(), {Size, Addr});
C->setDoesNotThrow();
@@ -944,6 +956,9 @@ void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
CodeGenFunction::AutoVarEmission
CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
QualType Ty = D.getType();
+ assert(
+ Ty.getAddressSpace() == LangAS::Default ||
+ (Ty.getAddressSpace() == LangAS::opencl_private && getLangOpts().OpenCL));
AutoVarEmission emission(D);
@@ -1036,8 +1051,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Create the alloca. Note that we set the name separately from
// building the instruction so that it's there even in no-asserts
// builds.
- address = CreateTempAlloca(allocaTy, allocaAlignment);
- address.getPointer()->setName(D.getName());
+ address = CreateTempAlloca(allocaTy, allocaAlignment, D.getName());
// Don't emit lifetime markers for MSVC catch parameters. The lifetime of
// the catch parameter starts in the catchpad instruction, and we can't
@@ -1097,10 +1111,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Type *llvmTy = ConvertTypeForMem(elementType);
// Allocate memory for the array.
- llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla");
- vla->setAlignment(alignment.getQuantity());
-
- address = Address(vla, alignment);
+ address = CreateTempAlloca(llvmTy, alignment, "vla", elementCount);
}
setAddrOfLocalVar(&D, address);
@@ -1119,6 +1130,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;
}
@@ -1225,7 +1242,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::Constant *constant = nullptr;
if (emission.IsConstantAggregate || D.isConstexpr()) {
assert(!capturedByInit && "constant init contains a capturing block?");
- constant = CGM.EmitConstantInit(D, this);
+ constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(D);
}
if (!constant) {
@@ -1249,7 +1266,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::ConstantInt::get(IntPtrTy,
getContext().getTypeSizeInChars(type).getQuantity());
- llvm::Type *BP = Int8PtrTy;
+ llvm::Type *BP = AllocaInt8PtrTy;
if (Loc.getType() != BP)
Loc = Builder.CreateBitCast(Loc, BP);
@@ -1409,13 +1426,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);
@@ -1727,17 +1737,19 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
/// Lazily declare the @llvm.lifetime.start intrinsic.
llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() {
- if (LifetimeStartFn) return LifetimeStartFn;
+ if (LifetimeStartFn)
+ return LifetimeStartFn;
LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(),
- llvm::Intrinsic::lifetime_start);
+ llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy);
return LifetimeStartFn;
}
/// Lazily declare the @llvm.lifetime.end intrinsic.
llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() {
- if (LifetimeEndFn) return LifetimeEndFn;
+ if (LifetimeEndFn)
+ return LifetimeEndFn;
LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(),
- llvm::Intrinsic::lifetime_end);
+ llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy);
return LifetimeEndFn;
}
@@ -1852,6 +1864,10 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
lt = Qualifiers::OCL_ExplicitNone;
}
+ // Load objects passed indirectly.
+ if (Arg.isIndirect() && !ArgVal)
+ ArgVal = Builder.CreateLoad(DeclPtr);
+
if (lt == Qualifiers::OCL_Strong) {
if (!isConsumed) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index f56e182169..e3437eb936 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -18,6 +18,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/Path.h"
using namespace clang;
@@ -237,7 +238,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();
@@ -259,6 +260,43 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
}
+void CodeGenFunction::EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
+ llvm::BasicBlock *InitBlock,
+ llvm::BasicBlock *NoInitBlock,
+ GuardKind Kind,
+ const VarDecl *D) {
+ assert((Kind == GuardKind::TlsGuard || D) && "no guarded variable");
+
+ // A guess at how many times we will enter the initialization of a
+ // variable, depending on the kind of variable.
+ static const uint64_t InitsPerTLSVar = 1024;
+ static const uint64_t InitsPerLocalVar = 1024 * 1024;
+
+ llvm::MDNode *Weights;
+ if (Kind == GuardKind::VariableGuard && !D->isLocalVarDecl()) {
+ // For non-local variables, don't apply any weighting for now. Due to our
+ // use of COMDATs, we expect there to be at most one initialization of the
+ // variable per DSO, but we have no way to know how many DSOs will try to
+ // initialize the variable.
+ Weights = nullptr;
+ } else {
+ uint64_t NumInits;
+ // FIXME: For the TLS case, collect and use profiling information to
+ // determine a more accurate brach weight.
+ if (Kind == GuardKind::TlsGuard || D->getTLSKind())
+ NumInits = InitsPerTLSVar;
+ else
+ NumInits = InitsPerLocalVar;
+
+ // The probability of us entering the initializer is
+ // 1 / (total number of times we attempt to initialize the variable).
+ llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+ Weights = MDHelper.createBranchWeights(1, NumInits - 1);
+ }
+
+ Builder.CreateCondBr(NeedsInit, InitBlock, NoInitBlock, Weights);
+}
+
llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
llvm::FunctionType *FTy, const Twine &Name, const CGFunctionInfo &FI,
SourceLocation Loc, bool TLS) {
@@ -278,17 +316,25 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
if (!getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (!isInSanitizerBlacklist(Fn, Loc)) {
- if (getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
- SanitizerKind::KernelAddress))
- Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
- if (getLangOpts().Sanitize.has(SanitizerKind::Thread))
- Fn->addFnAttr(llvm::Attribute::SanitizeThread);
- if (getLangOpts().Sanitize.has(SanitizerKind::Memory))
- Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
- if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack))
- Fn->addFnAttr(llvm::Attribute::SafeStack);
- }
+ if (getLangOpts().Sanitize.has(SanitizerKind::Address) &&
+ !isInSanitizerBlacklist(SanitizerKind::Address, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::KernelAddress) &&
+ !isInSanitizerBlacklist(SanitizerKind::KernelAddress, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
+ !isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
+ !isInSanitizerBlacklist(SanitizerKind::Memory, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
+
+ if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack) &&
+ !isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc))
+ Fn->addFnAttr(llvm::Attribute::SafeStack);
return Fn;
}
@@ -449,16 +495,12 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
PrioritizedCXXGlobalInits.clear();
}
- SmallString<128> FileName;
- SourceManager &SM = Context.getSourceManager();
- if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- // Include the filename in the symbol name. Including "sub_" matches gcc and
- // makes sure these symbols appear lexicographically behind the symbols with
- // priority emitted above.
- FileName = llvm::sys::path::filename(MainFile->getName());
- } else {
+ // Include the filename in the symbol name. Including "sub_" matches gcc and
+ // makes sure these symbols appear lexicographically behind the symbols with
+ // priority emitted above.
+ SmallString<128> FileName = llvm::sys::path::filename(getModule().getName());
+ if (FileName.empty())
FileName = "<null>";
- }
for (size_t i = 0; i < FileName.size(); ++i) {
// Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
@@ -539,7 +581,8 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
"guard.uninitialized");
llvm::BasicBlock *InitBlock = createBasicBlock("init");
ExitBlock = createBasicBlock("exit");
- Builder.CreateCondBr(Uninit, InitBlock, ExitBlock);
+ EmitCXXGuardedInitBranch(Uninit, InitBlock, ExitBlock,
+ GuardKind::TlsGuard, nullptr);
EmitBlock(InitBlock);
// Mark as initialized before initializing anything else. If the
// initializers use previously-initialized thread_local vars, that's
@@ -571,9 +614,10 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
-void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
- const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
- &DtorsAndObjects) {
+void CodeGenFunction::GenerateCXXGlobalDtorsFunc(
+ llvm::Function *Fn,
+ const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>>
+ &DtorsAndObjects) {
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
@@ -602,9 +646,9 @@ llvm::Function *CodeGenFunction::generateDestroyHelper(
Address addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray, const VarDecl *VD) {
FunctionArgList args;
- ImplicitParamDecl dst(getContext(), nullptr, SourceLocation(), nullptr,
- getContext().VoidPtrTy);
- args.push_back(&dst);
+ ImplicitParamDecl Dst(getContext(), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Dst);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(getContext().VoidTy, args);
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 8f999d175c..6a421e81df 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -15,6 +15,7 @@
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGObjCRuntime.h"
+#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/StmtCXX.h"
@@ -164,26 +165,27 @@ static const EHPersonality &getCXXPersonality(const llvm::Triple &T,
static const EHPersonality &getObjCXXPersonality(const llvm::Triple &T,
const LangOptions &L) {
switch (L.ObjCRuntime.getKind()) {
+ // In the fragile ABI, just use C++ exception handling and hope
+ // they're not doing crazy exception mixing.
+ case ObjCRuntime::FragileMacOSX:
+ return getCXXPersonality(T, L);
+
// The ObjC personality defers to the C++ personality for non-ObjC
// handlers. Unlike the C++ case, we use the same personality
// function on targets using (backend-driven) SJLJ EH.
case ObjCRuntime::MacOSX:
case ObjCRuntime::iOS:
case ObjCRuntime::WatchOS:
- return EHPersonality::NeXT_ObjC;
+ return getObjCPersonality(T, L);
- // In the fragile ABI, just use C++ exception handling and hope
- // they're not doing crazy exception mixing.
- case ObjCRuntime::FragileMacOSX:
- return getCXXPersonality(T, L);
+ case ObjCRuntime::GNUstep:
+ return EHPersonality::GNU_ObjCXX;
// The GCC runtime's personality function inherently doesn't support
- // mixed EH. Use the C++ personality just to avoid returning null.
+ // mixed EH. Use the ObjC personality just to avoid returning null.
case ObjCRuntime::GCC:
- case ObjCRuntime::ObjFW: // XXX: this will change soon
- return EHPersonality::GNU_ObjC;
- case ObjCRuntime::GNUstep:
- return EHPersonality::GNU_ObjCXX;
+ case ObjCRuntime::ObjFW:
+ return getObjCPersonality(T, L);
}
llvm_unreachable("bad runtime kind");
}
@@ -224,14 +226,19 @@ const EHPersonality &EHPersonality::get(CodeGenModule &CGM,
}
const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) {
- return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(CGF.CurCodeDecl));
+ const auto *FD = CGF.CurCodeDecl;
+ // For outlined finallys and filters, use the SEH personality in case they
+ // contain more SEH. This mostly only affects finallys. Filters could
+ // hypothetically use gnu statement expressions to sneak in nested SEH.
+ FD = FD ? FD : CGF.CurSEHParent;
+ return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(FD));
}
static llvm::Constant *getPersonalityFn(CodeGenModule &CGM,
const EHPersonality &Personality) {
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true),
Personality.PersonalityFn,
- llvm::AttributeSet(), /*Local=*/true);
+ llvm::AttributeList(), /*Local=*/true);
}
static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM,
@@ -765,8 +772,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
llvm::BasicBlock *lpad = createBasicBlock("lpad");
EmitBlock(lpad);
- llvm::LandingPadInst *LPadInst = Builder.CreateLandingPad(
- llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr), 0);
+ llvm::LandingPadInst *LPadInst =
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);
llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0);
Builder.CreateStore(LPadExn, getExceptionSlot());
@@ -1310,8 +1317,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
if (!CurFn->hasPersonalityFn())
CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality));
- llvm::LandingPadInst *LPadInst = Builder.CreateLandingPad(
- llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr), 0);
+ llvm::LandingPadInst *LPadInst =
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);
LPadInst->addClause(getCatchAllValue(*this));
llvm::Value *Exn = nullptr;
@@ -1387,8 +1394,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
llvm::Value *Exn = getExceptionFromSlot();
llvm::Value *Sel = getSelectorFromSlot();
- llvm::Type *LPadType = llvm::StructType::get(Exn->getType(),
- Sel->getType(), nullptr);
+ llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), Sel->getType());
llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
@@ -1650,18 +1656,19 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
// parameters. Win32 filters take no parameters.
if (IsFilter) {
Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, StartLoc,
+ getContext(), /*DC=*/nullptr, StartLoc,
&getContext().Idents.get("exception_pointers"),
- getContext().VoidPtrTy));
+ getContext().VoidPtrTy, ImplicitParamDecl::Other));
} else {
Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, StartLoc,
+ getContext(), /*DC=*/nullptr, StartLoc,
&getContext().Idents.get("abnormal_termination"),
- getContext().UnsignedCharTy));
+ getContext().UnsignedCharTy, ImplicitParamDecl::Other));
}
Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, StartLoc,
- &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+ getContext(), /*DC=*/nullptr, StartLoc,
+ &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other));
}
QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy;
@@ -1747,7 +1754,7 @@ void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,
// };
// int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode;
llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
- llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
+ llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy);
llvm::Value *Ptrs = Builder.CreateBitCast(SEHInfo, PtrsTy->getPointerTo());
llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0);
Rec = Builder.CreateAlignedLoad(Rec, getPointerAlign());
@@ -1800,7 +1807,8 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
// "catch i8* null". We can't do this on x86 because the filter has to save
// the exception code.
llvm::Constant *C =
- CGM.EmitConstantExpr(Except->getFilterExpr(), getContext().IntTy, this);
+ ConstantEmitter(*this).tryEmitAbstract(Except->getFilterExpr(),
+ getContext().IntTy);
if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C &&
C->isOneValue()) {
CatchScope->setCatchAllHandler(0, createBasicBlock("__except"));
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index ab4448bf3c..88116f7d81 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -20,6 +20,7 @@
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
@@ -48,7 +49,7 @@ using namespace CodeGen;
llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
unsigned addressSpace =
- cast<llvm::PointerType>(value->getType())->getAddressSpace();
+ cast<llvm::PointerType>(value->getType())->getAddressSpace();
llvm::PointerType *destType = Int8PtrTy;
if (addressSpace)
@@ -61,17 +62,42 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
/// block.
Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
- const Twine &Name) {
- auto Alloca = CreateTempAlloca(Ty, Name);
+ const Twine &Name,
+ llvm::Value *ArraySize,
+ bool CastToDefaultAddrSpace) {
+ auto Alloca = CreateTempAlloca(Ty, Name, ArraySize);
Alloca->setAlignment(Align.getQuantity());
- return Address(Alloca, Align);
-}
-
-/// CreateTempAlloca - This creates a alloca and inserts it into the entry
-/// block.
+ llvm::Value *V = Alloca;
+ // Alloca always returns a pointer in alloca address space, which may
+ // be different from the type defined by the language. For example,
+ // in C++ the auto variables are in the default address space. Therefore
+ // cast alloca to the default address space when necessary.
+ if (CastToDefaultAddrSpace && getASTAllocaAddressSpace() != LangAS::Default) {
+ auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default);
+ llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
+ // When ArraySize is nullptr, alloca is inserted at AllocaInsertPt,
+ // otherwise alloca is inserted at the current insertion point of the
+ // builder.
+ if (!ArraySize)
+ Builder.SetInsertPoint(AllocaInsertPt);
+ V = getTargetHooks().performAddrSpaceCast(
+ *this, V, getASTAllocaAddressSpace(), LangAS::Default,
+ Ty->getPointerTo(DestAddrSpace), /*non-null*/ true);
+ }
+
+ return Address(V, Align);
+}
+
+/// CreateTempAlloca - This creates an alloca and inserts it into the entry
+/// block if \p ArraySize is nullptr, otherwise inserts it at the current
+/// insertion point of the builder.
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
- const Twine &Name) {
- return new llvm::AllocaInst(Ty, nullptr, Name, AllocaInsertPt);
+ const Twine &Name,
+ llvm::Value *ArraySize) {
+ if (ArraySize)
+ return Builder.CreateAlloca(Ty, ArraySize, Name);
+ return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
+ ArraySize, Name, AllocaInsertPt);
}
/// CreateDefaultAlignTempAlloca - This creates an alloca with the
@@ -98,14 +124,18 @@ Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) {
return CreateTempAlloca(ConvertType(Ty), Align, Name);
}
-Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name) {
+Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name,
+ bool CastToDefaultAddrSpace) {
// FIXME: Should we prefer the preferred type alignment here?
- return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name);
+ return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name,
+ CastToDefaultAddrSpace);
}
Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align,
- const Twine &Name) {
- return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name);
+ const Twine &Name,
+ bool CastToDefaultAddrSpace) {
+ return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, nullptr,
+ CastToDefaultAddrSpace);
}
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
@@ -315,9 +345,10 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
}
}
-static Address
-createReferenceTemporary(CodeGenFunction &CGF,
- const MaterializeTemporaryExpr *M, const Expr *Inner) {
+static Address createReferenceTemporary(CodeGenFunction &CGF,
+ const MaterializeTemporaryExpr *M,
+ const Expr *Inner) {
+ auto &TCG = CGF.getTargetHooks();
switch (M->getStorageDuration()) {
case SD_FullExpression:
case SD_Automatic: {
@@ -329,14 +360,25 @@ createReferenceTemporary(CodeGenFunction &CGF,
if (CGF.CGM.getCodeGenOpts().MergeAllConstants &&
(Ty->isArrayType() || Ty->isRecordType()) &&
CGF.CGM.isTypeConstant(Ty, true))
- if (llvm::Constant *Init = CGF.CGM.EmitConstantExpr(Inner, Ty, &CGF)) {
- auto *GV = new llvm::GlobalVariable(
- CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp");
- CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
- GV->setAlignment(alignment.getQuantity());
- // FIXME: Should we put the new global into a COMDAT?
- return Address(GV, alignment);
+ if (auto Init = ConstantEmitter(CGF).tryEmitAbstract(Inner, Ty)) {
+ if (auto AddrSpace = CGF.getTarget().getConstantAddressSpace()) {
+ auto AS = AddrSpace.getValue();
+ auto *GV = new llvm::GlobalVariable(
+ CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp", nullptr,
+ llvm::GlobalValue::NotThreadLocal,
+ CGF.getContext().getTargetAddressSpace(AS));
+ CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
+ GV->setAlignment(alignment.getQuantity());
+ llvm::Constant *C = GV;
+ if (AS != LangAS::Default)
+ C = TCG.performAddrSpaceCast(
+ CGF.CGM, GV, AS, LangAS::Default,
+ GV->getValueType()->getPointerTo(
+ CGF.getContext().getTargetAddressSpace(LangAS::Default)));
+ // FIXME: Should we put the new global into a COMDAT?
+ return Address(C, alignment);
+ }
}
return CGF.CreateMemTemp(Ty, "ref.tmp");
}
@@ -415,9 +457,11 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
// Create and initialize the reference temporary.
Address Object = createReferenceTemporary(*this, M, E);
- if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object.getPointer())) {
+ if (auto *Var = dyn_cast<llvm::GlobalVariable>(
+ Object.getPointer()->stripPointerCasts())) {
Object = Address(llvm::ConstantExpr::getBitCast(
- Var, ConvertTypeForMem(E->getType())->getPointerTo()),
+ cast<llvm::Constant>(Object.getPointer()),
+ ConvertTypeForMem(E->getType())->getPointerTo()),
Object.getAlignment());
// If the temporary is a global and has a constant initializer or is a
// constant temporary that we promoted to a global, we may have already
@@ -463,8 +507,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
break;
case SubobjectAdjustment::FieldAdjustment: {
- LValue LV = MakeAddrLValue(Object, E->getType(),
- AlignmentSource::Decl);
+ LValue LV = MakeAddrLValue(Object, E->getType(), AlignmentSource::Decl);
LV = EmitLValueForField(LV, Adjustment.Field);
assert(LV.isSimple() &&
"materialized temporary field is not a simple lvalue");
@@ -525,6 +568,19 @@ static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
return Builder.CreateMul(B1, KMul);
}
+bool CodeGenFunction::isNullPointerAllowed(TypeCheckKind TCK) {
+ return TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
+ TCK == TCK_UpcastToVirtualBase;
+}
+
+bool CodeGenFunction::isVptrCheckRequired(TypeCheckKind TCK, QualType Ty) {
+ CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ return (RD && RD->hasDefinition() && RD->isDynamicClass()) &&
+ (TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
+ TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference ||
+ TCK == TCK_UpcastToVirtualBase);
+}
+
bool CodeGenFunction::sanitizePerformTypeCheck() const {
return SanOpts.has(SanitizerKind::Null) |
SanOpts.has(SanitizerKind::Alignment) |
@@ -545,27 +601,48 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
if (Ptr->getType()->getPointerAddressSpace())
return;
+ // Don't check pointers to volatile data. The behavior here is implementation-
+ // defined.
+ if (Ty.isVolatileQualified())
+ return;
+
SanitizerScope SanScope(this);
SmallVector<std::pair<llvm::Value *, SanitizerMask>, 3> Checks;
llvm::BasicBlock *Done = nullptr;
- bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
- TCK == TCK_UpcastToVirtualBase;
+ // Quickly determine whether we have a pointer to an alloca. It's possible
+ // to skip null checks, and some alignment checks, for these pointers. This
+ // can reduce compile-time significantly.
+ auto PtrToAlloca =
+ dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCastsNoFollowAliases());
+
+ llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext());
+ llvm::Value *IsNonNull = nullptr;
+ bool IsGuaranteedNonNull =
+ SkippedChecks.has(SanitizerKind::Null) || PtrToAlloca;
+ bool AllowNullPointers = isNullPointerAllowed(TCK);
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
- !SkippedChecks.has(SanitizerKind::Null)) {
+ !IsGuaranteedNonNull) {
// The glvalue must not be an empty glvalue.
- llvm::Value *IsNonNull = Builder.CreateIsNotNull(Ptr);
-
- if (AllowNullPointers) {
- // When performing pointer casts, it's OK if the value is null.
- // Skip the remaining checks in that case.
- Done = createBasicBlock("null");
- llvm::BasicBlock *Rest = createBasicBlock("not.null");
- Builder.CreateCondBr(IsNonNull, Rest, Done);
- EmitBlock(Rest);
- } else {
- Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
+ IsNonNull = Builder.CreateIsNotNull(Ptr);
+
+ // The IR builder can constant-fold the null check if the pointer points to
+ // a constant.
+ IsGuaranteedNonNull = IsNonNull == True;
+
+ // Skip the null check if the pointer is known to be non-null.
+ if (!IsGuaranteedNonNull) {
+ if (AllowNullPointers) {
+ // When performing pointer casts, it's OK if the value is null.
+ // Skip the remaining checks in that case.
+ Done = createBasicBlock("null");
+ llvm::BasicBlock *Rest = createBasicBlock("not.null");
+ Builder.CreateCondBr(IsNonNull, Rest, Done);
+ EmitBlock(Rest);
+ } else {
+ Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
+ }
}
}
@@ -581,14 +658,16 @@ 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;
+ llvm::Value *PtrAsInt = nullptr;
if (SanOpts.has(SanitizerKind::Alignment) &&
!SkippedChecks.has(SanitizerKind::Alignment)) {
@@ -597,13 +676,15 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
// The glvalue must be suitably aligned.
- if (AlignVal) {
- llvm::Value *Align =
- Builder.CreateAnd(Builder.CreatePtrToInt(Ptr, IntPtrTy),
- llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
+ if (AlignVal > 1 &&
+ (!PtrToAlloca || PtrToAlloca->getAlignment() < AlignVal)) {
+ PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy);
+ llvm::Value *Align = Builder.CreateAnd(
+ PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
llvm::Value *Aligned =
- Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
- Checks.push_back(std::make_pair(Aligned, SanitizerKind::Alignment));
+ Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
+ if (Aligned != True)
+ Checks.push_back(std::make_pair(Aligned, SanitizerKind::Alignment));
}
}
@@ -615,7 +696,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty),
llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2_64(AlignVal) : 1),
llvm::ConstantInt::get(Int8Ty, TCK)};
- EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData, Ptr);
+ EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData,
+ PtrAsInt ? PtrAsInt : Ptr);
}
// If possible, check that the vptr indicates that there is a subobject of
@@ -626,13 +708,20 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// The program has undefined behavior if:
// -- the [pointer or glvalue] is used to access a non-static data member
// 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) &&
- RD && RD->hasDefinition() && RD->isDynamicClass()) {
+ !SkippedChecks.has(SanitizerKind::Vptr) && isVptrCheckRequired(TCK, Ty)) {
+ // Ensure that the pointer is non-null before loading it. If there is no
+ // compile-time guarantee, reuse the run-time null check or emit a new one.
+ if (!IsGuaranteedNonNull) {
+ if (!IsNonNull)
+ IsNonNull = Builder.CreateIsNotNull(Ptr);
+ if (!Done)
+ Done = createBasicBlock("vptr.null");
+ llvm::BasicBlock *VptrNotNull = createBasicBlock("vptr.not.null");
+ Builder.CreateCondBr(IsNonNull, VptrNotNull, Done);
+ EmitBlock(VptrNotNull);
+ }
+
// Compute a hash of the mangled name of the type.
//
// FIXME: This is not guaranteed to be deterministic! Move to a
@@ -645,7 +734,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// Blacklist based on the mangled type.
if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType(
- Out.str())) {
+ SanitizerKind::Vptr, Out.str())) {
llvm::hash_code TypeHash = hash_value(Out.str());
// Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
@@ -830,7 +919,8 @@ void CodeGenModule::EmitExplicitCastExprType(const ExplicitCastExpr *E,
/// EmitPointerWithAlignment - Given an expression of pointer type, try to
/// derive a more accurate bound on the alignment of the pointer.
Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
- AlignmentSource *Source) {
+ LValueBaseInfo *BaseInfo,
+ TBAAAccessInfo *TBAAInfo) {
// We allow this with ObjC object pointers because of fragile ABIs.
assert(E->getType()->isPointerType() ||
E->getType()->isObjCObjectPointerType());
@@ -845,20 +935,35 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
// Non-converting casts (but not C's implicit conversion from void*).
case CK_BitCast:
case CK_NoOp:
+ case CK_AddressSpaceConversion:
if (auto PtrTy = CE->getSubExpr()->getType()->getAs<PointerType>()) {
if (PtrTy->getPointeeType()->isVoidType())
break;
- AlignmentSource InnerSource;
- Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), &InnerSource);
- if (Source) *Source = InnerSource;
-
- // If this is an explicit bitcast, and the source l-value is
- // opaque, honor the alignment of the casted-to type.
- if (isa<ExplicitCastExpr>(CE) &&
- InnerSource != AlignmentSource::Decl) {
- Addr = Address(Addr.getPointer(),
- getNaturalPointeeTypeAlignment(E->getType(), Source));
+ LValueBaseInfo InnerBaseInfo;
+ TBAAAccessInfo InnerTBAAInfo;
+ Address Addr = EmitPointerWithAlignment(CE->getSubExpr(),
+ &InnerBaseInfo,
+ &InnerTBAAInfo);
+ if (BaseInfo) *BaseInfo = InnerBaseInfo;
+ if (TBAAInfo) *TBAAInfo = InnerTBAAInfo;
+
+ if (isa<ExplicitCastExpr>(CE)) {
+ LValueBaseInfo TargetTypeBaseInfo;
+ TBAAAccessInfo TargetTypeTBAAInfo;
+ CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(),
+ &TargetTypeBaseInfo,
+ &TargetTypeTBAAInfo);
+ if (TBAAInfo)
+ *TBAAInfo = CGM.mergeTBAAInfoForCast(*TBAAInfo,
+ TargetTypeTBAAInfo);
+ // If the source l-value is opaque, honor the alignment of the
+ // casted-to type.
+ if (InnerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) {
+ if (BaseInfo)
+ BaseInfo->mergeForCast(TargetTypeBaseInfo);
+ Addr = Address(Addr.getPointer(), Align);
+ }
}
if (SanOpts.has(SanitizerKind::CFIUnrelatedCast) &&
@@ -869,19 +974,22 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
CodeGenFunction::CFITCK_UnrelatedCast,
CE->getLocStart());
}
-
- return Builder.CreateBitCast(Addr, ConvertType(E->getType()));
+ return CE->getCastKind() != CK_AddressSpaceConversion
+ ? Builder.CreateBitCast(Addr, ConvertType(E->getType()))
+ : Builder.CreateAddrSpaceCast(Addr,
+ ConvertType(E->getType()));
}
break;
// Array-to-pointer decay.
case CK_ArrayToPointerDecay:
- return EmitArrayToPointerDecay(CE->getSubExpr(), Source);
+ return EmitArrayToPointerDecay(CE->getSubExpr(), BaseInfo, TBAAInfo);
// Derived-to-base conversions.
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
- Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), Source);
+ Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), BaseInfo,
+ TBAAInfo);
auto Derived = CE->getSubExpr()->getType()->getPointeeCXXRecordDecl();
return GetAddressOfBaseClass(Addr, Derived,
CE->path_begin(), CE->path_end(),
@@ -900,7 +1008,8 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
if (UO->getOpcode() == UO_AddrOf) {
LValue LV = EmitLValue(UO->getSubExpr());
- if (Source) *Source = LV.getAlignmentSource();
+ if (BaseInfo) *BaseInfo = LV.getBaseInfo();
+ if (TBAAInfo) *TBAAInfo = LV.getTBAAInfo();
return LV.getAddress();
}
}
@@ -908,7 +1017,8 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
// TODO: conditional operators, comma.
// Otherwise, use the alignment of the type.
- CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), Source);
+ CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), BaseInfo,
+ TBAAInfo);
return Address(EmitScalarExpr(E), Align);
}
@@ -952,10 +1062,7 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
E->getType());
}
-bool CodeGenFunction::IsDeclRefOrWrappedCXXThis(const Expr *Obj) {
- if (isa<DeclRefExpr>(Obj))
- return true;
-
+bool CodeGenFunction::IsWrappedCXXThis(const Expr *Obj) {
const Expr *Base = Obj;
while (!isa<CXXThisExpr>(Base)) {
// The result of a dynamic_cast can be null.
@@ -986,9 +1093,13 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
LV = EmitLValue(E);
if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple()) {
SanitizerSet SkippedChecks;
- if (const auto *ME = dyn_cast<MemberExpr>(E))
- if (IsDeclRefOrWrappedCXXThis(ME->getBase()))
+ 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(), SkippedChecks);
}
@@ -1076,8 +1187,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
llvm::Value *V = LV.getPointer();
Scope.ForceCleanup({&V});
return LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(),
- getContext(), LV.getAlignmentSource(),
- LV.getTBAAInfo());
+ getContext(), LV.getBaseInfo(), LV.getTBAAInfo());
}
// FIXME: Is it possible to create an ExprWithCleanups that produces a
// bitfield lvalue or some other non-simple lvalue?
@@ -1133,6 +1243,11 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::MaterializeTemporaryExprClass:
return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
+
+ case Expr::CoawaitExprClass:
+ return EmitCoawaitLValue(cast<CoawaitExpr>(E));
+ case Expr::CoyieldExprClass:
+ return EmitCoyieldLValue(cast<CoyieldExpr>(E));
}
}
@@ -1229,7 +1344,8 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
return ConstantEmission();
// Emit as a constant.
- llvm::Constant *C = CGM.EmitConstantValue(result.Val, resultType, this);
+ auto C = ConstantEmitter(*this).emitAbstract(refExpr->getLocation(),
+ result.Val, resultType);
// Make sure we emit a debug reference to the global variable.
// This should probably fire even for
@@ -1248,13 +1364,30 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
return ConstantEmission::forValue(C);
}
+static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
+ const MemberExpr *ME) {
+ if (auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
+ // Try to emit static variable member expressions as DREs.
+ return DeclRefExpr::Create(
+ CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
+ /*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
+ ME->getType(), ME->getValueKind());
+ }
+ return nullptr;
+}
+
+CodeGenFunction::ConstantEmission
+CodeGenFunction::tryEmitAsConstant(const MemberExpr *ME) {
+ if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, ME))
+ return tryEmitAsConstant(DRE);
+ return ConstantEmission();
+}
+
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue,
SourceLocation Loc) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getType(), Loc, lvalue.getAlignmentSource(),
- lvalue.getTBAAInfo(),
- lvalue.getTBAABaseType(), lvalue.getTBAAOffset(),
- lvalue.isNontemporal());
+ lvalue.getType(), Loc, lvalue.getBaseInfo(),
+ lvalue.getTBAAInfo(), lvalue.isNontemporal());
}
static bool hasBooleanRepresentation(QualType Ty) {
@@ -1338,17 +1471,17 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool))
return true;
+ auto &Ctx = getLLVMContext();
SanitizerScope SanScope(this);
llvm::Value *Check;
--End;
if (!Min) {
- Check = Builder.CreateICmpULE(
- Value, llvm::ConstantInt::get(getLLVMContext(), End));
+ Check = Builder.CreateICmpULE(Value, llvm::ConstantInt::get(Ctx, End));
} else {
- llvm::Value *Upper = Builder.CreateICmpSLE(
- Value, llvm::ConstantInt::get(getLLVMContext(), End));
- llvm::Value *Lower = Builder.CreateICmpSGE(
- Value, llvm::ConstantInt::get(getLLVMContext(), Min));
+ llvm::Value *Upper =
+ Builder.CreateICmpSLE(Value, llvm::ConstantInt::get(Ctx, End));
+ llvm::Value *Lower =
+ Builder.CreateICmpSGE(Value, llvm::ConstantInt::get(Ctx, Min));
Check = Builder.CreateAnd(Upper, Lower);
}
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc),
@@ -1363,37 +1496,37 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
QualType Ty,
SourceLocation Loc,
- AlignmentSource AlignSource,
- llvm::MDNode *TBAAInfo,
- QualType TBAABaseType,
- uint64_t TBAAOffset,
+ LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo,
bool isNontemporal) {
- // For better performance, handle vector loads differently.
- if (Ty->isVectorType()) {
- const llvm::Type *EltTy = Addr.getElementType();
-
- const auto *VTy = cast<llvm::VectorType>(EltTy);
-
- // Handle vectors of size 3 like size 4 for better performance.
- if (VTy->getNumElements() == 3) {
-
- // Bitcast to vec4 type.
- llvm::VectorType *vec4Ty = llvm::VectorType::get(VTy->getElementType(),
- 4);
- Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4");
- // Now load value.
- llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4");
-
- // Shuffle vector to get vec3.
- V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
- {0, 1, 2}, "extractVec");
- return EmitFromMemory(V, Ty);
+ if (!CGM.getCodeGenOpts().PreserveVec3Type) {
+ // For better performance, handle vector loads differently.
+ if (Ty->isVectorType()) {
+ const llvm::Type *EltTy = Addr.getElementType();
+
+ const auto *VTy = cast<llvm::VectorType>(EltTy);
+
+ // Handle vectors of size 3 like size 4 for better performance.
+ if (VTy->getNumElements() == 3) {
+
+ // Bitcast to vec4 type.
+ llvm::VectorType *vec4Ty =
+ llvm::VectorType::get(VTy->getElementType(), 4);
+ Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4");
+ // Now load value.
+ llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4");
+
+ // Shuffle vector to get vec3.
+ V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
+ {0, 1, 2}, "extractVec");
+ return EmitFromMemory(V, Ty);
+ }
}
}
// Atomic operations have to be done on integral types.
LValue AtomicLValue =
- LValue::MakeAddr(Addr, Ty, getContext(), AlignSource, TBAAInfo);
+ LValue::MakeAddr(Addr, Ty, getContext(), BaseInfo, TBAAInfo);
if (Ty->isAtomicType() || LValueIsSuitableForInlineAtomic(AtomicLValue)) {
return EmitAtomicLoad(AtomicLValue, Loc).getScalarVal();
}
@@ -1404,13 +1537,8 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
Load->getContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
Load->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
}
- if (TBAAInfo) {
- llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
- TBAAOffset);
- if (TBAAPath)
- CGM.DecorateInstructionWithTBAA(Load, TBAAPath,
- false /*ConvertTypeToTag*/);
- }
+
+ CGM.DecorateInstructionWithTBAA(Load, TBAAInfo);
if (EmitScalarRangeCheck(Load, Ty, Loc)) {
// In order to prevent the optimizer from throwing away the check, don't
@@ -1449,37 +1577,35 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
bool Volatile, QualType Ty,
- AlignmentSource AlignSource,
- llvm::MDNode *TBAAInfo,
- bool isInit, QualType TBAABaseType,
- uint64_t TBAAOffset,
- bool isNontemporal) {
-
- // Handle vectors differently to get better performance.
- if (Ty->isVectorType()) {
- llvm::Type *SrcTy = Value->getType();
- auto *VecTy = cast<llvm::VectorType>(SrcTy);
- // Handle vec3 special.
- if (VecTy->getNumElements() == 3) {
- // Our source is a vec3, do a shuffle vector to make it a vec4.
- llvm::Constant *Mask[] = {Builder.getInt32(0), Builder.getInt32(1),
- Builder.getInt32(2),
- llvm::UndefValue::get(Builder.getInt32Ty())};
- llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
- Value = Builder.CreateShuffleVector(Value,
- llvm::UndefValue::get(VecTy),
- MaskV, "extractVec");
- SrcTy = llvm::VectorType::get(VecTy->getElementType(), 4);
- }
- if (Addr.getElementType() != SrcTy) {
- Addr = Builder.CreateElementBitCast(Addr, SrcTy, "storetmp");
+ LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo,
+ bool isInit, bool isNontemporal) {
+ if (!CGM.getCodeGenOpts().PreserveVec3Type) {
+ // Handle vectors differently to get better performance.
+ if (Ty->isVectorType()) {
+ llvm::Type *SrcTy = Value->getType();
+ auto *VecTy = dyn_cast<llvm::VectorType>(SrcTy);
+ // Handle vec3 special.
+ if (VecTy && VecTy->getNumElements() == 3) {
+ // Our source is a vec3, do a shuffle vector to make it a vec4.
+ llvm::Constant *Mask[] = {Builder.getInt32(0), Builder.getInt32(1),
+ Builder.getInt32(2),
+ llvm::UndefValue::get(Builder.getInt32Ty())};
+ llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
+ Value = Builder.CreateShuffleVector(Value, llvm::UndefValue::get(VecTy),
+ MaskV, "extractVec");
+ SrcTy = llvm::VectorType::get(VecTy->getElementType(), 4);
+ }
+ if (Addr.getElementType() != SrcTy) {
+ Addr = Builder.CreateElementBitCast(Addr, SrcTy, "storetmp");
+ }
}
}
Value = EmitToMemory(Value, Ty);
LValue AtomicLValue =
- LValue::MakeAddr(Addr, Ty, getContext(), AlignSource, TBAAInfo);
+ LValue::MakeAddr(Addr, Ty, getContext(), BaseInfo, TBAAInfo);
if (Ty->isAtomicType() ||
(!isInit && LValueIsSuitableForInlineAtomic(AtomicLValue))) {
EmitAtomicStore(RValue::get(Value), AtomicLValue, isInit);
@@ -1493,21 +1619,15 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
Store->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
}
- if (TBAAInfo) {
- llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
- TBAAOffset);
- if (TBAAPath)
- CGM.DecorateInstructionWithTBAA(Store, TBAAPath,
- false /*ConvertTypeToTag*/);
- }
+
+ CGM.DecorateInstructionWithTBAA(Store, TBAAInfo);
}
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
bool isInit) {
EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getType(), lvalue.getAlignmentSource(),
- lvalue.getTBAAInfo(), isInit, lvalue.getTBAABaseType(),
- lvalue.getTBAAOffset(), lvalue.isNontemporal());
+ lvalue.getType(), lvalue.getBaseInfo(),
+ lvalue.getTBAAInfo(), isInit, lvalue.isNontemporal());
}
/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
@@ -2040,35 +2160,45 @@ static LValue EmitThreadPrivateVarDeclLValue(
return CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
}
-Address CodeGenFunction::EmitLoadOfReference(Address Addr,
- const ReferenceType *RefTy,
- AlignmentSource *Source) {
- llvm::Value *Ptr = Builder.CreateLoad(Addr);
- return Address(Ptr, getNaturalTypeAlignment(RefTy->getPointeeType(),
- Source, /*forPointee*/ true));
-
+Address
+CodeGenFunction::EmitLoadOfReference(LValue RefLVal,
+ LValueBaseInfo *PointeeBaseInfo,
+ TBAAAccessInfo *PointeeTBAAInfo) {
+ llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(),
+ RefLVal.isVolatile());
+ CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo());
+
+ CharUnits Align = getNaturalTypeAlignment(RefLVal.getType()->getPointeeType(),
+ PointeeBaseInfo, PointeeTBAAInfo,
+ /* forPointeeType= */ true);
+ return Address(Load, Align);
}
-LValue CodeGenFunction::EmitLoadOfReferenceLValue(Address RefAddr,
- const ReferenceType *RefTy) {
- AlignmentSource Source;
- Address Addr = EmitLoadOfReference(RefAddr, RefTy, &Source);
- return MakeAddrLValue(Addr, RefTy->getPointeeType(), Source);
+LValue CodeGenFunction::EmitLoadOfReferenceLValue(LValue RefLVal) {
+ LValueBaseInfo PointeeBaseInfo;
+ TBAAAccessInfo PointeeTBAAInfo;
+ Address PointeeAddr = EmitLoadOfReference(RefLVal, &PointeeBaseInfo,
+ &PointeeTBAAInfo);
+ return MakeAddrLValue(PointeeAddr, RefLVal.getType()->getPointeeType(),
+ PointeeBaseInfo, PointeeTBAAInfo);
}
Address CodeGenFunction::EmitLoadOfPointer(Address Ptr,
const PointerType *PtrTy,
- AlignmentSource *Source) {
+ LValueBaseInfo *BaseInfo,
+ TBAAAccessInfo *TBAAInfo) {
llvm::Value *Addr = Builder.CreateLoad(Ptr);
- return Address(Addr, getNaturalTypeAlignment(PtrTy->getPointeeType(), Source,
+ return Address(Addr, getNaturalTypeAlignment(PtrTy->getPointeeType(),
+ BaseInfo, TBAAInfo,
/*forPointeeType=*/true));
}
LValue CodeGenFunction::EmitLoadOfPointerLValue(Address PtrAddr,
const PointerType *PtrTy) {
- AlignmentSource Source;
- Address Addr = EmitLoadOfPointer(PtrAddr, PtrTy, &Source);
- return MakeAddrLValue(Addr, PtrTy->getPointeeType(), Source);
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
+ Address Addr = EmitLoadOfPointer(PtrAddr, PtrTy, &BaseInfo, &TBAAInfo);
+ return MakeAddrLValue(Addr, PtrTy->getPointeeType(), BaseInfo, TBAAInfo);
}
static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
@@ -2085,17 +2215,15 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
Address Addr(V, Alignment);
- LValue LV;
// Emit reference to the private copy of the variable if it is an OpenMP
// threadprivate variable.
if (CGF.getLangOpts().OpenMP && VD->hasAttr<OMPThreadPrivateDeclAttr>())
return EmitThreadPrivateVarDeclLValue(CGF, VD, T, Addr, RealVarTy,
E->getExprLoc());
- if (auto RefTy = VD->getType()->getAs<ReferenceType>()) {
- LV = CGF.EmitLoadOfReferenceLValue(Addr, RefTy);
- } else {
- LV = CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
- }
+ LValue LV = VD->getType()->isReferenceType() ?
+ CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
+ AlignmentSource::Decl) :
+ CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
setObjCGCLValueClass(CGF.getContext(), E, LV);
return LV;
}
@@ -2128,7 +2256,8 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
const Expr *E, const FunctionDecl *FD) {
llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, FD);
CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
- return CGF.MakeAddrLValue(V, E->getType(), Alignment, AlignmentSource::Decl);
+ return CGF.MakeAddrLValue(V, E->getType(), Alignment,
+ AlignmentSource::Decl);
}
static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
@@ -2183,29 +2312,38 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
VD->isUsableInConstantExpressions(getContext()) &&
VD->checkInitIsICE() &&
// Do not emit if it is private OpenMP variable.
- !(E->refersToEnclosingVariableOrCapture() && CapturedStmtInfo &&
- LocalDeclMap.count(VD))) {
+ !(E->refersToEnclosingVariableOrCapture() &&
+ ((CapturedStmtInfo &&
+ (LocalDeclMap.count(VD->getCanonicalDecl()) ||
+ CapturedStmtInfo->lookup(VD->getCanonicalDecl()))) ||
+ LambdaCaptureFields.lookup(VD->getCanonicalDecl()) ||
+ isa<BlockDecl>(CurCodeDecl)))) {
llvm::Constant *Val =
- CGM.EmitConstantValue(*VD->evaluateValue(), VD->getType(), this);
+ ConstantEmitter(*this).emitAbstract(E->getLocation(),
+ *VD->evaluateValue(),
+ VD->getType());
assert(Val && "failed to emit reference constant expression");
// FIXME: Eventually we will want to emit vector element references.
// Should we be using the alignment of the constant pointer we emitted?
- CharUnits Alignment = getNaturalTypeAlignment(E->getType(), nullptr,
- /*pointee*/ true);
-
+ CharUnits Alignment = getNaturalTypeAlignment(E->getType(),
+ /* BaseInfo= */ nullptr,
+ /* TBAAInfo= */ nullptr,
+ /* forPointeeType= */ true);
return MakeAddrLValue(Address(Val, Alignment), T, AlignmentSource::Decl);
}
// Check for captured variables.
if (E->refersToEnclosingVariableOrCapture()) {
+ VD = VD->getCanonicalDecl();
if (auto *FD = LambdaCaptureFields.lookup(VD))
return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
else if (CapturedStmtInfo) {
auto I = LocalDeclMap.find(VD);
if (I != LocalDeclMap.end()) {
- if (auto RefTy = VD->getType()->getAs<ReferenceType>())
- return EmitLoadOfReferenceLValue(I->second, RefTy);
+ if (VD->getType()->isReferenceType())
+ return EmitLoadOfReferenceLValue(I->second, VD->getType(),
+ AlignmentSource::Decl);
return MakeAddrLValue(I->second, T);
}
LValue CapLVal =
@@ -2213,7 +2351,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
CapturedStmtInfo->getContextValue());
return MakeAddrLValue(
Address(CapLVal.getPointer(), getContext().getDeclAlign(VD)),
- CapLVal.getType(), AlignmentSource::Decl);
+ CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl),
+ CapLVal.getTBAAInfo());
}
assert(isa<BlockDecl>(CurCodeDecl));
@@ -2274,12 +2413,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
}
// Drill into reference types.
- LValue LV;
- if (auto RefTy = VD->getType()->getAs<ReferenceType>()) {
- LV = EmitLoadOfReferenceLValue(addr, RefTy);
- } else {
- LV = MakeAddrLValue(addr, T, AlignmentSource::Decl);
- }
+ LValue LV = VD->getType()->isReferenceType() ?
+ EmitLoadOfReferenceLValue(addr, VD->getType(), AlignmentSource::Decl) :
+ MakeAddrLValue(addr, T, AlignmentSource::Decl);
bool isLocalStorage = VD->hasLocalStorage();
@@ -2323,9 +2459,11 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
QualType T = E->getSubExpr()->getType()->getPointeeType();
assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
- AlignmentSource AlignSource;
- Address Addr = EmitPointerWithAlignment(E->getSubExpr(), &AlignSource);
- LValue LV = MakeAddrLValue(Addr, T, AlignSource);
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
+ Address Addr = EmitPointerWithAlignment(E->getSubExpr(), &BaseInfo,
+ &TBAAInfo);
+ LValue LV = MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo);
LV.getQuals().setAddressSpace(ExprTy.getAddressSpace());
// We should not generate __weak write barrier on indirect reference
@@ -2357,7 +2495,8 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
(E->getOpcode() == UO_Real
? emitAddrOfRealComponent(LV.getAddress(), LV.getType())
: emitAddrOfImagComponent(LV.getAddress(), LV.getType()));
- LValue ElemLV = MakeAddrLValue(Component, T, LV.getAlignmentSource());
+ LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo(),
+ CGM.getTBAAInfoForSubobject(LV, T));
ElemLV.getQuals().addQualifiers(LV.getQuals());
return ElemLV;
}
@@ -2467,6 +2606,9 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
llvm::Type *TargetTy = IntPtrTy;
+ if (V->getType() == TargetTy)
+ return V;
+
// Floating-point types which fit into intptr_t are bitcast to integers
// and then passed directly (after zero-extension, if necessary).
if (V->getType()->isFloatingPointTy()) {
@@ -2596,13 +2738,16 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
bool NeedsAbortSuffix =
IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable;
+ bool MinimalRuntime = CGF.CGM.getCodeGenOpts().SanitizeMinimalRuntime;
const SanitizerHandlerInfo &CheckInfo = SanitizerHandlers[CheckHandler];
const StringRef CheckName = CheckInfo.Name;
- std::string FnName =
- ("__ubsan_handle_" + CheckName +
- (CheckInfo.Version ? "_v" + llvm::utostr(CheckInfo.Version) : "") +
- (NeedsAbortSuffix ? "_abort" : ""))
- .str();
+ std::string FnName = "__ubsan_handle_" + CheckName.str();
+ if (CheckInfo.Version && !MinimalRuntime)
+ FnName += "_v" + llvm::utostr(CheckInfo.Version);
+ if (MinimalRuntime)
+ FnName += "_minimal";
+ if (NeedsAbortSuffix)
+ FnName += "_abort";
bool MayReturn =
!IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable;
@@ -2615,8 +2760,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) {
@@ -2689,24 +2834,26 @@ void CodeGenFunction::EmitCheck(
// representing operand values.
SmallVector<llvm::Value *, 4> Args;
SmallVector<llvm::Type *, 4> ArgTypes;
- Args.reserve(DynamicArgs.size() + 1);
- ArgTypes.reserve(DynamicArgs.size() + 1);
-
- // Emit handler arguments and create handler function type.
- if (!StaticArgs.empty()) {
- llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
- auto *InfoPtr =
- new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
- llvm::GlobalVariable::PrivateLinkage, Info);
- InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
- Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy));
- ArgTypes.push_back(Int8PtrTy);
- }
+ if (!CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
+ Args.reserve(DynamicArgs.size() + 1);
+ ArgTypes.reserve(DynamicArgs.size() + 1);
+
+ // Emit handler arguments and create handler function type.
+ if (!StaticArgs.empty()) {
+ llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
+ auto *InfoPtr =
+ new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
+ llvm::GlobalVariable::PrivateLinkage, Info);
+ InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
+ CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
+ Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy));
+ ArgTypes.push_back(Int8PtrTy);
+ }
- for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) {
- Args.push_back(EmitCheckValue(DynamicArgs[i]));
- ArgTypes.push_back(IntPtrTy);
+ for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) {
+ Args.push_back(EmitCheckValue(DynamicArgs[i]));
+ ArgTypes.push_back(IntPtrTy);
+ }
}
llvm::FunctionType *FnType =
@@ -2779,6 +2926,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
@@ -2789,10 +2954,10 @@ void CodeGenFunction::EmitCfiSlowPathCheck(
void CodeGenFunction::EmitCfiCheckFail() {
SanitizerScope SanScope(this);
FunctionArgList Args;
- ImplicitParamDecl ArgData(getContext(), nullptr, SourceLocation(), nullptr,
- getContext().VoidPtrTy);
- ImplicitParamDecl ArgAddr(getContext(), nullptr, SourceLocation(), nullptr,
- getContext().VoidPtrTy);
+ ImplicitParamDecl ArgData(getContext(), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl ArgAddr(getContext(), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
Args.push_back(&ArgData);
Args.push_back(&ArgAddr);
@@ -2820,9 +2985,9 @@ void CodeGenFunction::EmitCfiCheckFail() {
EmitTrapCheck(DataIsNotNullPtr);
llvm::StructType *SourceLocationTy =
- llvm::StructType::get(VoidPtrTy, Int32Ty, Int32Ty, nullptr);
+ llvm::StructType::get(VoidPtrTy, Int32Ty, Int32Ty);
llvm::StructType *CfiCheckFailDataTy =
- llvm::StructType::get(Int8Ty, SourceLocationTy, VoidPtrTy, nullptr);
+ llvm::StructType::get(Int8Ty, SourceLocationTy, VoidPtrTy);
llvm::Value *V = Builder.CreateConstGEP2_32(
CfiCheckFailDataTy,
@@ -2891,21 +3056,21 @@ llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) {
if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
CGM.getCodeGenOpts().TrapFuncName);
- TrapCall->addAttribute(llvm::AttributeSet::FunctionIndex, A);
+ TrapCall->addAttribute(llvm::AttributeList::FunctionIndex, A);
}
return TrapCall;
}
Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E,
- AlignmentSource *AlignSource) {
+ LValueBaseInfo *BaseInfo,
+ TBAAAccessInfo *TBAAInfo) {
assert(E->getType()->isArrayType() &&
"Array to pointer decay must have array source type!");
// Expressions of array type can't be bitfields or vector elements.
LValue LV = EmitLValue(E);
Address Addr = LV.getAddress();
- if (AlignSource) *AlignSource = LV.getAlignmentSource();
// If the array type was an incomplete type, we need to make sure
// the decay ends up being the right type.
@@ -2920,7 +3085,15 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E,
Addr = Builder.CreateStructGEP(Addr, 0, CharUnits::Zero(), "arraydecay");
}
+ // The result of this decay conversion points to an array element within the
+ // base lvalue. However, since TBAA currently does not support representing
+ // accesses to elements of member arrays, we conservatively represent accesses
+ // to the pointee object as if it had no any base lvalue specified.
+ // TODO: Support TBAA for member arrays.
QualType EltType = E->getType()->castAsArrayTypeUnsafe()->getElementType();
+ if (BaseInfo) *BaseInfo = LV.getBaseInfo();
+ if (TBAAInfo) *TBAAInfo = CGM.getTBAAAccessInfo(EltType);
+
return Builder.CreateElementBitCast(Addr, ConvertTypeForMem(EltType));
}
@@ -2944,9 +3117,13 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
llvm::Value *ptr,
ArrayRef<llvm::Value*> indices,
bool inbounds,
+ bool signedIndices,
+ SourceLocation loc,
const llvm::Twine &name = "arrayidx") {
if (inbounds) {
- return CGF.Builder.CreateInBoundsGEP(ptr, indices, name);
+ return CGF.EmitCheckedInBoundsGEP(ptr, indices, signedIndices,
+ CodeGenFunction::NotSubtraction, loc,
+ name);
} else {
return CGF.Builder.CreateGEP(ptr, indices, name);
}
@@ -2977,8 +3154,9 @@ static QualType getFixedSizeElementType(const ASTContext &ctx,
}
static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
- ArrayRef<llvm::Value*> indices,
+ ArrayRef<llvm::Value *> indices,
QualType eltType, bool inbounds,
+ bool signedIndices, SourceLocation loc,
const llvm::Twine &name = "arrayidx") {
// All the indices except that last must be zero.
#ifndef NDEBUG
@@ -2998,8 +3176,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
CharUnits eltAlign =
getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
- llvm::Value *eltPtr =
- emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds, name);
+ llvm::Value *eltPtr = emitArraySubscriptGEP(
+ CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name);
return Address(eltPtr, eltAlign);
}
@@ -3009,6 +3187,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// in lexical order (this complexity is, sadly, required by C++17).
llvm::Value *IdxPre =
(E->getLHS() == E->getIdx()) ? EmitScalarExpr(E->getIdx()) : nullptr;
+ bool SignedIndices = false;
auto EmitIdxAfterBase = [&, IdxPre](bool Promote) -> llvm::Value * {
auto *Idx = IdxPre;
if (E->getLHS() != E->getIdx()) {
@@ -3018,6 +3197,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
QualType IdxTy = E->getIdx()->getType();
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
+ SignedIndices |= IdxSigned;
if (SanOpts.has(SanitizerKind::ArrayBounds))
EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
@@ -3038,9 +3218,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
LValue LHS = EmitLValue(E->getBase());
auto *Idx = EmitIdxAfterBase(/*Promote*/false);
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
- return LValue::MakeVectorElt(LHS.getAddress(), Idx,
- E->getBase()->getType(),
- LHS.getAlignmentSource());
+ return LValue::MakeVectorElt(LHS.getAddress(), Idx, E->getBase()->getType(),
+ LHS.getBaseInfo(), TBAAAccessInfo());
}
// All the other cases basically behave like simple offsetting.
@@ -3052,18 +3231,21 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
Address Addr = EmitExtVectorElementLValue(LV);
QualType EltType = LV.getType()->castAs<VectorType>()->getElementType();
- Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true);
- return MakeAddrLValue(Addr, EltType, LV.getAlignmentSource());
+ Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true,
+ SignedIndices, E->getExprLoc());
+ return MakeAddrLValue(Addr, EltType, LV.getBaseInfo(),
+ CGM.getTBAAInfoForSubobject(LV, EltType));
}
- AlignmentSource AlignSource;
+ LValueBaseInfo EltBaseInfo;
+ TBAAAccessInfo EltTBAAInfo;
Address Addr = Address::invalid();
if (const VariableArrayType *vla =
getContext().getAsVariableArrayType(E->getType())) {
// The base must be a pointer, which is not an aggregate. Emit
// it. It needs to be emitted first in case it's what captures
// the VLA bounds.
- Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
// The element count here is the total number of non-VLA elements.
@@ -3080,13 +3262,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
}
Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ SignedIndices, E->getExprLoc());
} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
// Indexing over an interface, as in "NSString *P; P[4];"
// Emit the base pointer.
- Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
CharUnits InterfaceSize = getContext().getTypeSizeInChars(OIT);
@@ -3106,7 +3289,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
CharUnits EltAlign =
getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize);
llvm::Value *EltPtr =
- emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false);
+ emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false,
+ SignedIndices, E->getExprLoc());
Addr = Address(EltPtr, EltAlign);
// Cast back.
@@ -3128,22 +3312,22 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
// Propagate the alignment from the array itself to the result.
- Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(),
- {CGM.getSize(CharUnits::Zero()), Idx},
- E->getType(),
- !getLangOpts().isSignedOverflowDefined());
- AlignSource = ArrayLV.getAlignmentSource();
+ Addr = emitArraySubscriptGEP(
+ *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
+ E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
+ E->getExprLoc());
+ EltBaseInfo = ArrayLV.getBaseInfo();
+ EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
} else {
// The base must be a pointer; emit it with an estimate of its alignment.
- Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ SignedIndices, E->getExprLoc());
}
- LValue LV = MakeAddrLValue(Addr, E->getType(), AlignSource);
-
- // TODO: Preserve/extend path TBAA metadata?
+ LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
if (getLangOpts().ObjC1 &&
getLangOpts().getGC() != LangOptions::NonGC) {
@@ -3154,7 +3338,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
}
static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
- AlignmentSource &AlignSource,
+ LValueBaseInfo &BaseInfo,
+ TBAAAccessInfo &TBAAInfo,
QualType BaseTy, QualType ElTy,
bool IsLowerBound) {
LValue BaseLVal;
@@ -3162,7 +3347,7 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
BaseLVal = CGF.EmitOMPArraySectionExpr(ASE, IsLowerBound);
if (BaseTy->isArrayType()) {
Address Addr = BaseLVal.getAddress();
- AlignSource = BaseLVal.getAlignmentSource();
+ BaseInfo = BaseLVal.getBaseInfo();
// If the array type was an incomplete type, we need to make sure
// the decay ends up being the right type.
@@ -3181,20 +3366,20 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
return CGF.Builder.CreateElementBitCast(Addr,
CGF.ConvertTypeForMem(ElTy));
}
- CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &AlignSource);
+ LValueBaseInfo TypeBaseInfo;
+ TBAAAccessInfo TypeTBAAInfo;
+ CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &TypeBaseInfo,
+ &TypeTBAAInfo);
+ BaseInfo.mergeForCast(TypeBaseInfo);
+ TBAAInfo = CGF.CGM.mergeTBAAInfoForCast(TBAAInfo, TypeTBAAInfo);
return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress()), Align);
}
- return CGF.EmitPointerWithAlignment(Base, &AlignSource);
+ return CGF.EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo);
}
LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
bool IsLowerBound) {
- QualType BaseTy;
- if (auto *ASE =
- dyn_cast<OMPArraySectionExpr>(E->getBase()->IgnoreParenImpCasts()))
- BaseTy = OMPArraySectionExpr::getBaseOriginalType(ASE);
- else
- BaseTy = E->getBase()->getType();
+ QualType BaseTy = OMPArraySectionExpr::getBaseOriginalType(E->getBase());
QualType ResultExprTy;
if (auto *AT = getContext().getAsArrayType(BaseTy))
ResultExprTy = AT->getElementType();
@@ -3288,14 +3473,15 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
assert(Idx);
Address EltPtr = Address::invalid();
- AlignmentSource AlignSource;
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
if (auto *VLA = getContext().getAsVariableArrayType(ResultExprTy)) {
// The base must be a pointer, which is not an aggregate. Emit
// it. It needs to be emitted first in case it's what captures
// the VLA bounds.
Address Base =
- emitOMPArraySectionBase(*this, E->getBase(), AlignSource, BaseTy,
- VLA->getElementType(), IsLowerBound);
+ emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, TBAAInfo,
+ BaseTy, VLA->getElementType(), IsLowerBound);
// The element count here is the total number of non-VLA elements.
llvm::Value *NumElements = getVLASize(VLA).first;
@@ -3308,7 +3494,8 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
else
Idx = Builder.CreateNSWMul(Idx, NumElements);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ /*SignedIndices=*/false, E->getExprLoc());
} else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
// If this is A[i] where A is an array, the frontend will have decayed the
// base to be a ArrayToPointerDecay implicit cast. While correct, it is
@@ -3327,16 +3514,20 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
// Propagate the alignment from the array itself to the result.
EltPtr = emitArraySubscriptGEP(
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
- ResultExprTy, !getLangOpts().isSignedOverflowDefined());
- AlignSource = ArrayLV.getAlignmentSource();
+ ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
+ /*SignedIndices=*/false, E->getExprLoc());
+ BaseInfo = ArrayLV.getBaseInfo();
+ TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy);
} else {
- Address Base = emitOMPArraySectionBase(*this, E->getBase(), AlignSource,
- BaseTy, ResultExprTy, IsLowerBound);
+ Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo,
+ TBAAInfo, BaseTy, ResultExprTy,
+ IsLowerBound);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ /*SignedIndices=*/false, E->getExprLoc());
}
- return MakeAddrLValue(EltPtr, ResultExprTy, AlignSource);
+ return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo, TBAAInfo);
}
LValue CodeGenFunction::
@@ -3348,10 +3539,11 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
if (E->isArrow()) {
// If it is a pointer to a vector, emit the address and form an lvalue with
// it.
- AlignmentSource AlignSource;
- Address Ptr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
+ Address Ptr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo);
const PointerType *PT = E->getBase()->getType()->getAs<PointerType>();
- Base = MakeAddrLValue(Ptr, PT->getPointeeType(), AlignSource);
+ Base = MakeAddrLValue(Ptr, PT->getPointeeType(), BaseInfo, TBAAInfo);
Base.getQuals().removeObjCGCAttr();
} else if (E->getBase()->isGLValue()) {
// Otherwise, if the base is an lvalue ( as in the case of foo.x.x),
@@ -3382,7 +3574,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
llvm::Constant *CV =
llvm::ConstantDataVector::get(getLLVMContext(), Indices);
return LValue::MakeExtVectorElt(Base.getAddress(), CV, type,
- Base.getAlignmentSource());
+ Base.getBaseInfo(), TBAAAccessInfo());
}
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
@@ -3393,24 +3585,32 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
CElts.push_back(BaseElts->getAggregateElement(Indices[i]));
llvm::Constant *CV = llvm::ConstantVector::get(CElts);
return LValue::MakeExtVectorElt(Base.getExtVectorAddress(), CV, type,
- Base.getAlignmentSource());
+ Base.getBaseInfo(), TBAAAccessInfo());
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
- Expr *BaseExpr = E->getBase();
+ if (DeclRefExpr *DRE = tryToConvertMemberExprToDeclRefExpr(*this, E)) {
+ EmitIgnoredExpr(E->getBase());
+ return EmitDeclRefLValue(DRE);
+ }
+ Expr *BaseExpr = E->getBase();
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
LValue BaseLV;
if (E->isArrow()) {
- AlignmentSource AlignSource;
- Address Addr = EmitPointerWithAlignment(BaseExpr, &AlignSource);
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
+ Address Addr = EmitPointerWithAlignment(BaseExpr, &BaseInfo, &TBAAInfo);
QualType PtrTy = BaseExpr->getType()->getPointeeType();
SanitizerSet SkippedChecks;
- if (IsDeclRefOrWrappedCXXThis(BaseExpr))
+ 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);
+ BaseLV = MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo);
} else
BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
@@ -3421,9 +3621,6 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
return LV;
}
- if (auto *VD = dyn_cast<VarDecl>(ND))
- return EmitGlobalVarDeclLValue(*this, E, VD);
-
if (const auto *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);
@@ -3468,10 +3665,28 @@ static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
return CGF.Builder.CreateStructGEP(base, idx, offset, field->getName());
}
+static bool hasAnyVptr(const QualType Type, const ASTContext &Context) {
+ const auto *RD = Type.getTypePtr()->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+
+ if (RD->isDynamicClass())
+ return true;
+
+ for (const auto &Base : RD->bases())
+ if (hasAnyVptr(Base.getType(), Context))
+ return true;
+
+ for (const FieldDecl *Field : RD->fields())
+ if (hasAnyVptr(Field->getType(), Context))
+ return true;
+
+ return false;
+}
+
LValue CodeGenFunction::EmitLValueForField(LValue base,
const FieldDecl *field) {
- AlignmentSource fieldAlignSource =
- getFieldAlignmentSource(base.getAlignmentSource());
+ LValueBaseInfo BaseInfo = base.getBaseInfo();
if (field->isBitField()) {
const CGRecordLayout &RL =
@@ -3491,54 +3706,74 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
QualType fieldType =
field->getType().withCVRQualifiers(base.getVRQualifiers());
- return LValue::MakeBitfield(Addr, Info, fieldType, fieldAlignSource);
+ // TODO: Support TBAA for bit fields.
+ LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource());
+ return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo,
+ TBAAAccessInfo());
}
+ // Fields of may-alias structures are may-alias themselves.
+ // FIXME: this should get propagated down through anonymous structs
+ // and unions.
+ QualType FieldType = field->getType();
const RecordDecl *rec = field->getParent();
- QualType type = field->getType();
+ AlignmentSource BaseAlignSource = BaseInfo.getAlignmentSource();
+ LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(BaseAlignSource));
+ TBAAAccessInfo FieldTBAAInfo;
+ if (base.getTBAAInfo().isMayAlias() ||
+ rec->hasAttr<MayAliasAttr>() || FieldType->isVectorType()) {
+ FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
+ } else if (rec->isUnion()) {
+ // TODO: Support TBAA for unions.
+ FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
+ } else {
+ // If no base type been assigned for the base access, then try to generate
+ // one for this base lvalue.
+ FieldTBAAInfo = base.getTBAAInfo();
+ if (!FieldTBAAInfo.BaseType) {
+ FieldTBAAInfo.BaseType = CGM.getTBAABaseTypeInfo(base.getType());
+ assert(!FieldTBAAInfo.Offset &&
+ "Nonzero offset for an access with no base type!");
+ }
- bool mayAlias = rec->hasAttr<MayAliasAttr>();
+ // Adjust offset to be relative to the base type.
+ const ASTRecordLayout &Layout =
+ getContext().getASTRecordLayout(field->getParent());
+ unsigned CharWidth = getContext().getCharWidth();
+ if (FieldTBAAInfo.BaseType)
+ FieldTBAAInfo.Offset +=
+ Layout.getFieldOffset(field->getFieldIndex()) / CharWidth;
+
+ // Update the final access type.
+ FieldTBAAInfo.AccessType = CGM.getTBAATypeInfo(FieldType);
+ }
Address addr = base.getAddress();
- unsigned cvr = base.getVRQualifiers();
- bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA;
+ unsigned RecordCVR = base.getVRQualifiers();
if (rec->isUnion()) {
// For unions, there is no pointer adjustment.
- assert(!type->isReferenceType() && "union has reference member");
- // TODO: handle path-aware TBAA for union.
- TBAAPath = false;
+ assert(!FieldType->isReferenceType() && "union has reference member");
+ if (CGM.getCodeGenOpts().StrictVTablePointers &&
+ hasAnyVptr(FieldType, getContext()))
+ // Because unions can easily skip invariant.barriers, we need to add
+ // a barrier every time CXXRecord field with vptr is referenced.
+ addr = Address(Builder.CreateInvariantGroupBarrier(addr.getPointer()),
+ addr.getAlignment());
} else {
// For structs, we GEP to the field that the record layout suggests.
addr = emitAddrOfFieldStorage(*this, addr, field);
// If this is a reference field, load the reference right now.
- if (const ReferenceType *refType = type->getAs<ReferenceType>()) {
- llvm::LoadInst *load = Builder.CreateLoad(addr, "ref");
- if (cvr & Qualifiers::Volatile) load->setVolatile(true);
-
- // Loading the reference will disable path-aware TBAA.
- TBAAPath = false;
- if (CGM.shouldUseTBAA()) {
- llvm::MDNode *tbaa;
- if (mayAlias)
- tbaa = CGM.getTBAAInfo(getContext().CharTy);
- else
- tbaa = CGM.getTBAAInfo(type);
- if (tbaa)
- CGM.DecorateInstructionWithTBAA(load, tbaa);
- }
-
- mayAlias = false;
- type = refType->getPointeeType();
-
- CharUnits alignment =
- getNaturalTypeAlignment(type, &fieldAlignSource, /*pointee*/ true);
- addr = Address(load, alignment);
-
- // Qualifiers on the struct don't apply to the referencee, and
- // we'll pick up CVR from the actual type later, so reset these
- // additional qualifiers now.
- cvr = 0;
+ if (FieldType->isReferenceType()) {
+ LValue RefLVal = MakeAddrLValue(addr, FieldType, FieldBaseInfo,
+ FieldTBAAInfo);
+ if (RecordCVR & Qualifiers::Volatile)
+ RefLVal.getQuals().setVolatile(true);
+ addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo);
+
+ // Qualifiers on the struct don't apply to the referencee.
+ RecordCVR = 0;
+ FieldType = FieldType->getPointeeType();
}
}
@@ -3546,36 +3781,19 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
// for both unions and structs. A union needs a bitcast, a struct element
// will need a bitcast if the LLVM type laid out doesn't match the desired
// type.
- addr = Builder.CreateElementBitCast(addr,
- CGM.getTypes().ConvertTypeForMem(type),
- field->getName());
+ addr = Builder.CreateElementBitCast(
+ addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName());
if (field->hasAttr<AnnotateAttr>())
addr = EmitFieldAnnotations(field, addr);
- LValue LV = MakeAddrLValue(addr, type, fieldAlignSource);
- LV.getQuals().addCVRQualifiers(cvr);
- if (TBAAPath) {
- const ASTRecordLayout &Layout =
- getContext().getASTRecordLayout(field->getParent());
- // Set the base type to be the base type of the base LValue and
- // update offset to be relative to the base type.
- LV.setTBAABaseType(mayAlias ? getContext().CharTy : base.getTBAABaseType());
- LV.setTBAAOffset(mayAlias ? 0 : base.getTBAAOffset() +
- Layout.getFieldOffset(field->getFieldIndex()) /
- getContext().getCharWidth());
- }
+ LValue LV = MakeAddrLValue(addr, FieldType, FieldBaseInfo, FieldTBAAInfo);
+ LV.getQuals().addCVRQualifiers(RecordCVR);
// __weak attribute on a field is ignored.
if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak)
LV.getQuals().removeObjCGCAttr();
- // Fields of may_alias structs act like 'char' for TBAA purposes.
- // FIXME: this should get propagated down through anonymous structs
- // and unions.
- if (mayAlias && LV.getTBAAInfo())
- LV.setTBAAInfo(CGM.getTBAAInfo(getContext().CharTy));
-
return LV;
}
@@ -3593,9 +3811,14 @@ CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
llvm::Type *llvmType = ConvertTypeForMem(FieldType);
V = Builder.CreateElementBitCast(V, llvmType, Field->getName());
- // TODO: access-path TBAA?
- auto FieldAlignSource = getFieldAlignmentSource(Base.getAlignmentSource());
- return MakeAddrLValue(V, FieldType, FieldAlignSource);
+ // TODO: Generate TBAA information that describes this access as a structure
+ // member access and not just an access to an object of the field's type. This
+ // should be similar to what we do in EmitLValueForField().
+ LValueBaseInfo BaseInfo = Base.getBaseInfo();
+ AlignmentSource FieldAlignSource = BaseInfo.getAlignmentSource();
+ LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(FieldAlignSource));
+ return MakeAddrLValue(V, FieldType, FieldBaseInfo,
+ CGM.getTBAAInfoForSubobject(Base, FieldType));
}
LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
@@ -3706,8 +3929,12 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
phi->addIncoming(rhs->getPointer(), rhsBlock);
Address result(phi, std::min(lhs->getAlignment(), rhs->getAlignment()));
AlignmentSource alignSource =
- std::max(lhs->getAlignmentSource(), rhs->getAlignmentSource());
- return MakeAddrLValue(result, expr->getType(), alignSource);
+ std::max(lhs->getBaseInfo().getAlignmentSource(),
+ rhs->getBaseInfo().getAlignmentSource());
+ TBAAAccessInfo TBAAInfo = CGM.mergeTBAAInfoForConditionalOperator(
+ lhs->getTBAAInfo(), rhs->getTBAAInfo());
+ return MakeAddrLValue(result, expr->getType(), LValueBaseInfo(alignSource),
+ TBAAInfo);
} else {
assert((lhs || rhs) &&
"both operands of glvalue conditional are throw-expressions?");
@@ -3805,7 +4032,11 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
This, DerivedClassDecl, E->path_begin(), E->path_end(),
/*NullCheckValue=*/false, E->getExprLoc());
- return MakeAddrLValue(Base, E->getType(), LV.getAlignmentSource());
+ // TODO: Support accesses to members of base classes in TBAA. For now, we
+ // conservatively pretend that the complete object is of the base class
+ // type.
+ return MakeAddrLValue(Base, E->getType(), LV.getBaseInfo(),
+ CGM.getTBAAInfoForSubobject(LV, E->getType()));
}
case CK_ToUnion:
return EmitAggExprToLValue(E);
@@ -3832,7 +4063,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
/*MayBeNull=*/false,
CFITCK_DerivedCast, E->getLocStart());
- return MakeAddrLValue(Derived, E->getType(), LV.getAlignmentSource());
+ return MakeAddrLValue(Derived, E->getType(), LV.getBaseInfo(),
+ CGM.getTBAAInfoForSubobject(LV, E->getType()));
}
case CK_LValueBitCast: {
// This must be a reinterpret_cast (or c-style equivalent).
@@ -3848,13 +4080,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
/*MayBeNull=*/false,
CFITCK_UnrelatedCast, E->getLocStart());
- return MakeAddrLValue(V, E->getType(), LV.getAlignmentSource());
+ return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
+ CGM.getTBAAInfoForSubobject(LV, E->getType()));
}
case CK_ObjCObjectLValueCast: {
LValue LV = EmitLValue(E->getSubExpr());
Address V = Builder.CreateElementBitCast(LV.getAddress(),
ConvertType(E->getType()));
- return MakeAddrLValue(V, E->getType(), LV.getAlignmentSource());
+ return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
+ CGM.getTBAAInfoForSubobject(LV, E->getType()));
}
case CK_ZeroToOCLQueue:
llvm_unreachable("NULL to OpenCL queue lvalue cast is not valid");
@@ -4023,6 +4257,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
RValue RV = EmitAnyExpr(E->getRHS());
LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
+ if (RV.isScalar())
+ EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
EmitStoreThroughLValue(RV, LV);
return LV;
}
@@ -4060,8 +4296,7 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
&& "binding l-value to type which needs a temporary");
AggValueSlot Slot = CreateAggTemp(E->getType());
EmitCXXConstructExpr(E, Slot);
- return MakeAddrLValue(Slot.getAddress(), E->getType(),
- AlignmentSource::Decl);
+ return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl);
}
LValue
@@ -4085,16 +4320,14 @@ CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
Slot.setExternallyDestructed();
EmitAggExpr(E->getSubExpr(), Slot);
EmitCXXTemporary(E->getTemporary(), E->getType(), Slot.getAddress());
- return MakeAddrLValue(Slot.getAddress(), E->getType(),
- AlignmentSource::Decl);
+ return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl);
}
LValue
CodeGenFunction::EmitLambdaLValue(const LambdaExpr *E) {
AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
EmitLambdaExpr(E, Slot);
- return MakeAddrLValue(Slot.getAddress(), E->getType(),
- AlignmentSource::Decl);
+ return MakeAddrLValue(Slot.getAddress(), E->getType(), AlignmentSource::Decl);
}
LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
@@ -4196,10 +4429,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
SanitizerScope SanScope(this);
llvm::Constant *FTRTTIConst =
CGM.GetAddrOfRTTIDescriptor(QualType(FnType, 0), /*ForEH=*/true);
- llvm::Type *PrefixStructTyElems[] = {
- PrefixSig->getType(),
- FTRTTIConst->getType()
- };
+ llvm::Type *PrefixStructTyElems[] = {PrefixSig->getType(), Int32Ty};
llvm::StructType *PrefixStructTy = llvm::StructType::get(
CGM.getLLVMContext(), PrefixStructTyElems, /*isPacked=*/true);
@@ -4220,8 +4450,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
EmitBlock(TypeCheck);
llvm::Value *CalleeRTTIPtr =
Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, 0, 1);
- llvm::Value *CalleeRTTI =
+ llvm::Value *CalleeRTTIEncoded =
Builder.CreateAlignedLoad(CalleeRTTIPtr, getPointerAlign());
+ llvm::Value *CalleeRTTI =
+ DecodeAddrUsedInPrologue(CalleePtr, CalleeRTTIEncoded);
llvm::Value *CalleeRTTIMatch =
Builder.CreateICmpEQ(CalleeRTTI, FTRTTIConst);
llvm::Constant *StaticData[] = {
@@ -4243,7 +4475,12 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
SanitizerScope SanScope(this);
EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
- llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
+ llvm::Metadata *MD;
+ if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
+ MD = CGM.CreateMetadataIdentifierGeneralized(QualType(FnType, 0));
+ else
+ MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
+
llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
llvm::Value *CalleePtr = Callee.getFunctionPointer();
@@ -4350,12 +4587,13 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
const MemberPointerType *MPT
= E->getRHS()->getType()->getAs<MemberPointerType>();
- AlignmentSource AlignSource;
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
Address MemberAddr =
- EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT,
- &AlignSource);
+ EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT, &BaseInfo,
+ &TBAAInfo);
- return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), AlignSource);
+ return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), BaseInfo, TBAAInfo);
}
/// Given the address of a temporary variable, produce an r-value of
@@ -4418,7 +4656,6 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
if (ov == resultExpr && ov->isRValue() && !forLValue &&
CodeGenFunction::hasAggregateEvaluationKind(ov->getType())) {
CGF.EmitAggExpr(ov->getSourceExpr(), slot);
-
LValue LV = CGF.MakeAddrLValue(slot.getAddress(), ov->getType(),
AlignmentSource::Decl);
opaqueData = OVMA::bind(CGF, ov, LV);
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 009244784e..1ab8433864 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -111,30 +111,20 @@ 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());
}
// l-values.
- void VisitDeclRefExpr(DeclRefExpr *E) {
- // For aggregates, we should always be able to emit the variable
- // as an l-value unless it's a reference. This is due to the fact
- // that we can't actually ever see a normal l2r conversion on an
- // aggregate in C++, and in C there's no language standard
- // actively preventing us from listing variables in the captures
- // list of a block.
- if (E->getDecl()->getType()->isReferenceType()) {
- if (CodeGenFunction::ConstantEmission result
- = CGF.tryEmitAsConstant(E)) {
- EmitFinalDestCopy(E->getType(), result.getReferenceLValue(CGF, E));
- return;
- }
- }
-
- EmitAggLoadOfLValue(E);
- }
-
+ void VisitDeclRefExpr(DeclRefExpr *E) { EmitAggLoadOfLValue(E); }
void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); }
void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); }
void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); }
@@ -505,12 +495,20 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
currentElement->addIncoming(element, entryBB);
// Emit the actual filler expression.
- LValue elementLV =
- CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
- if (filler)
- EmitInitializationToLValue(filler, elementLV);
- else
- EmitNullInitializationToLValue(elementLV);
+ {
+ // C++1z [class.temporary]p5:
+ // when a default constructor is called to initialize an element of
+ // an array with no corresponding initializer [...] the destruction of
+ // every temporary created in a default argument is sequenced before
+ // the construction of the next array element, if any
+ CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
+ LValue elementLV =
+ CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
+ if (filler)
+ EmitInitializationToLValue(filler, elementLV);
+ else
+ EmitNullInitializationToLValue(elementLV);
+ }
// Move on to the next element.
llvm::Value *nextElement =
@@ -1267,7 +1265,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 04826916f7..3eb4bd6b90 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -16,6 +16,7 @@
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
+#include "ConstantEmitter.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/CallSite.h"
@@ -199,7 +200,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
bool CanUseVirtualCall = MD->isVirtual() && !HasQualifier;
const CXXMethodDecl *DevirtualizedMethod = nullptr;
- if (CanUseVirtualCall && CanDevirtualizeMemberFunctionCall(Base, MD)) {
+ if (CanUseVirtualCall &&
+ MD->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) {
const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl);
assert(DevirtualizedMethod);
@@ -301,9 +303,14 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
CallLoc = CE->getExprLoc();
SanitizerSet SkippedChecks;
- if (const auto *CMCE = dyn_cast<CXXMemberCallExpr>(CE))
- if (IsDeclRefOrWrappedCXXThis(CMCE->getImplicitObjectArgument()))
+ 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,
@@ -675,8 +682,8 @@ 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.CGM.EmitConstantExpr(e->getArraySize(),
- CGF.getContext().getSizeType(), &CGF);
+ numElements =
+ ConstantEmitter(CGF).tryEmitAbstract(e->getArraySize(), e->getType());
if (!numElements)
numElements = CGF.EmitScalarExpr(e->getArraySize());
assert(isa<llvm::IntegerType>(numElements->getType()));
@@ -1275,10 +1282,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");
@@ -1304,29 +1311,44 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
llvm_unreachable("predeclared global operator new/delete is missing");
}
-static std::pair<bool, bool>
-shouldPassSizeAndAlignToUsualDelete(const FunctionProtoType *FPT) {
+namespace {
+/// The parameters to pass to a usual operator delete.
+struct UsualDeleteParams {
+ bool DestroyingDelete = false;
+ bool Size = false;
+ bool Alignment = false;
+};
+}
+
+static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *FD) {
+ UsualDeleteParams Params;
+
+ const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
auto AI = FPT->param_type_begin(), AE = FPT->param_type_end();
// The first argument is always a void*.
++AI;
- // Figure out what other parameters we should be implicitly passing.
- bool PassSize = false;
- bool PassAlignment = false;
+ // The next parameter may be a std::destroying_delete_t.
+ if (FD->isDestroyingOperatorDelete()) {
+ Params.DestroyingDelete = true;
+ assert(AI != AE);
+ ++AI;
+ }
+ // Figure out what other parameters we should be implicitly passing.
if (AI != AE && (*AI)->isIntegerType()) {
- PassSize = true;
+ Params.Size = true;
++AI;
}
if (AI != AE && (*AI)->isAlignValT()) {
- PassAlignment = true;
+ Params.Alignment = true;
++AI;
}
assert(AI == AE && "unexpected usual deallocation function parameter");
- return {PassSize, PassAlignment};
+ return Params;
}
namespace {
@@ -1379,25 +1401,27 @@ namespace {
OperatorDelete->getType()->getAs<FunctionProtoType>();
CallArgList DeleteArgs;
- // The first argument is always a void*.
+ // The first argument is always a void* (or C* for a destroying operator
+ // delete for class type C).
DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(0));
// Figure out what other parameters we should be implicitly passing.
- bool PassSize = false;
- bool PassAlignment = false;
+ UsualDeleteParams Params;
if (NumPlacementArgs) {
// A placement deallocation function is implicitly passed an alignment
// if the placement allocation function was, but is never passed a size.
- PassAlignment = PassAlignmentToPlacementDelete;
+ Params.Alignment = PassAlignmentToPlacementDelete;
} else {
// For a non-placement new-expression, 'operator delete' can take a
// size and/or an alignment if it has the right parameters.
- std::tie(PassSize, PassAlignment) =
- shouldPassSizeAndAlignToUsualDelete(FPT);
+ Params = getUsualDeleteParams(OperatorDelete);
}
+ assert(!Params.DestroyingDelete &&
+ "should not call destroying delete in a new-expression");
+
// The second argument can be a std::size_t (for non-placement delete).
- if (PassSize)
+ if (Params.Size)
DeleteArgs.add(Traits::get(CGF, AllocSize),
CGF.getContext().getSizeType());
@@ -1405,7 +1429,7 @@ namespace {
// is an enum whose underlying type is std::size_t.
// FIXME: Use the right type as the parameter type. Note that in a call
// to operator delete(size_t, ...), we may not have it available.
- if (PassAlignment)
+ if (Params.Alignment)
DeleteArgs.add(RValue::get(llvm::ConstantInt::get(
CGF.SizeTy, AllocAlign.getQuantity())),
CGF.getContext().getSizeType());
@@ -1526,13 +1550,13 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
assert(E->getNumPlacementArgs() == 1);
const Expr *arg = *E->placement_arguments().begin();
- AlignmentSource alignSource;
- allocation = EmitPointerWithAlignment(arg, &alignSource);
+ LValueBaseInfo BaseInfo;
+ allocation = EmitPointerWithAlignment(arg, &BaseInfo);
// The pointer expression will, in many cases, be an opaque void*.
// In these cases, discard the computed alignment and use the
// formal alignment of the allocated type.
- if (alignSource != AlignmentSource::Decl)
+ if (BaseInfo.getAlignmentSource() != AlignmentSource::Decl)
allocation = Address(allocation.getPointer(), allocAlign);
// Set up allocatorArgs for the call to operator delete if it's not
@@ -1653,8 +1677,9 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Passing pointer through invariant.group.barrier to avoid propagation of
// vptrs information which may be included in previous type.
+ // To not break LTO with different optimizations levels, we do it regardless
+ // of optimization level.
if (CGM.getCodeGenOpts().StrictVTablePointers &&
- CGM.getCodeGenOpts().OptimizationLevel > 0 &&
allocator->isReservedGlobalPlacementOperator())
result = Address(Builder.CreateInvariantGroupBarrier(result.getPointer()),
result.getAlignment());
@@ -1707,9 +1732,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
CallArgList DeleteArgs;
- std::pair<bool, bool> PassSizeAndAlign =
- shouldPassSizeAndAlignToUsualDelete(DeleteFTy);
-
+ auto Params = getUsualDeleteParams(DeleteFD);
auto ParamTypeIt = DeleteFTy->param_type_begin();
// Pass the pointer itself.
@@ -1717,8 +1740,16 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
DeleteArgs.add(RValue::get(DeletePtr), ArgTy);
+ // Pass the std::destroying_delete tag if present.
+ if (Params.DestroyingDelete) {
+ QualType DDTag = *ParamTypeIt++;
+ // Just pass an 'undef'. We expect the tag type to be an empty struct.
+ auto *V = llvm::UndefValue::get(getTypes().ConvertType(DDTag));
+ DeleteArgs.add(RValue::get(V), DDTag);
+ }
+
// Pass the size if the delete function has a size_t parameter.
- if (PassSizeAndAlign.first) {
+ if (Params.Size) {
QualType SizeType = *ParamTypeIt++;
CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
llvm::Value *Size = llvm::ConstantInt::get(ConvertType(SizeType),
@@ -1737,7 +1768,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
}
// Pass the alignment if the delete function has an align_val_t parameter.
- if (PassSizeAndAlign.second) {
+ if (Params.Alignment) {
QualType AlignValType = *ParamTypeIt++;
CharUnits DeleteTypeAlign = getContext().toCharUnitsFromBits(
getContext().getTypeAlignIfKnown(DeleteTy));
@@ -1779,6 +1810,21 @@ CodeGenFunction::pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete,
OperatorDelete, ElementType);
}
+/// Emit the code for deleting a single object with a destroying operator
+/// delete. If the element type has a non-virtual destructor, Ptr has already
+/// been converted to the type of the parameter of 'operator delete'. Otherwise
+/// Ptr points to an object of the static type.
+static void EmitDestroyingObjectDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE, Address Ptr,
+ QualType ElementType) {
+ auto *Dtor = ElementType->getAsCXXRecordDecl()->getDestructor();
+ if (Dtor && Dtor->isVirtual())
+ CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType,
+ Dtor);
+ else
+ CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.getPointer(), ElementType);
+}
+
/// Emit the code for deleting a single object.
static void EmitObjectDelete(CodeGenFunction &CGF,
const CXXDeleteExpr *DE,
@@ -1793,6 +1839,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
DE->getExprLoc(), Ptr.getPointer(),
ElementType);
+ const FunctionDecl *OperatorDelete = DE->getOperatorDelete();
+ assert(!OperatorDelete->isDestroyingOperatorDelete());
+
// Find the destructor for the type, if applicable. If the
// destructor is virtual, we'll just emit the vcall and return.
const CXXDestructorDecl *Dtor = nullptr;
@@ -1812,7 +1861,6 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
// Make sure that we call delete even if the dtor throws.
// This doesn't have to a conditional cleanup because we're going
// to pop it off in a second.
- const FunctionDecl *OperatorDelete = DE->getOperatorDelete();
CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
Ptr.getPointer(),
OperatorDelete, ElementType);
@@ -1924,10 +1972,19 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
EmitBlock(DeleteNotNull);
+ QualType DeleteTy = E->getDestroyedType();
+
+ // A destroying operator delete overrides the entire operation of the
+ // delete expression.
+ if (E->getOperatorDelete()->isDestroyingOperatorDelete()) {
+ EmitDestroyingObjectDelete(*this, E, Ptr, DeleteTy);
+ EmitBlock(DeleteEnd);
+ return;
+ }
+
// We might be deleting a pointer to array. If so, GEP down to the
// first non-array element.
// (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*)
- QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType();
if (DeleteTy->isConstantArrayType()) {
llvm::Value *Zero = Builder.getInt32(0);
SmallVector<llvm::Value*,8> GEP;
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 22e7fa64db..e860b3045f 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -110,18 +110,32 @@ 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());
+ }
+
+ ComplexPairTy emitConstant(const CodeGenFunction::ConstantEmission &Constant,
+ Expr *E) {
+ assert(Constant && "not a constant");
+ if (Constant.isReference())
+ return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E),
+ E->getExprLoc());
+
+ llvm::Constant *pair = Constant.getValue();
+ return ComplexPairTy(pair->getAggregateElement(0U),
+ pair->getAggregateElement(1U));
+ }
// l-values.
ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) {
- if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
- if (result.isReference())
- return EmitLoadOfLValue(result.getReferenceLValue(CGF, E),
- E->getExprLoc());
-
- llvm::Constant *pair = result.getValue();
- return ComplexPairTy(pair->getAggregateElement(0U),
- pair->getAggregateElement(1U));
- }
+ if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E))
+ return emitConstant(Constant, E);
return EmitLoadOfLValue(E);
}
ComplexPairTy VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
@@ -131,7 +145,14 @@ public:
return CGF.EmitObjCMessageExpr(E).getComplexVal();
}
ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
+ ComplexPairTy VisitMemberExpr(MemberExpr *ME) {
+ if (CodeGenFunction::ConstantEmission Constant =
+ CGF.tryEmitAsConstant(ME)) {
+ CGF.EmitIgnoredExpr(ME->getBase());
+ return emitConstant(Constant, ME);
+ }
+ return EmitLoadOfLValue(ME);
+ }
ComplexPairTy VisitOpaqueValueExpr(OpaqueValueExpr *E) {
if (E->isGLValue())
return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getExprLoc());
@@ -754,7 +775,6 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
if (!LHSi)
LibCallOp.LHS.second = llvm::Constant::getNullValue(LHSr->getType());
- StringRef LibCallName;
switch (LHSr->getType()->getTypeID()) {
default:
llvm_unreachable("Unsupported floating point type!");
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 3db15c646f..3e35d4cb9c 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -16,6 +16,7 @@
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
#include "CodeGenModule.h"
+#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
@@ -37,25 +38,26 @@ namespace {
class ConstExprEmitter;
class ConstStructBuilder {
CodeGenModule &CGM;
- CodeGenFunction *CGF;
+ ConstantEmitter &Emitter;
bool Packed;
CharUnits NextFieldOffsetInChars;
CharUnits LLVMStructAlignment;
SmallVector<llvm::Constant *, 32> Elements;
public:
- static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CFG,
- ConstExprEmitter *Emitter,
+ static llvm::Constant *BuildStruct(ConstantEmitter &Emitter,
+ ConstExprEmitter *ExprEmitter,
llvm::ConstantStruct *Base,
- InitListExpr *Updater);
- static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
- InitListExpr *ILE);
- static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
+ InitListExpr *Updater,
+ QualType ValTy);
+ static llvm::Constant *BuildStruct(ConstantEmitter &Emitter,
+ InitListExpr *ILE, QualType StructTy);
+ static llvm::Constant *BuildStruct(ConstantEmitter &Emitter,
const APValue &Value, QualType ValTy);
private:
- ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
- : CGM(CGM), CGF(CGF), Packed(false),
+ ConstStructBuilder(ConstantEmitter &emitter)
+ : CGM(emitter.CGM), Emitter(emitter), Packed(false),
NextFieldOffsetInChars(CharUnits::Zero()),
LLVMStructAlignment(CharUnits::One()) { }
@@ -76,7 +78,7 @@ private:
bool Build(InitListExpr *ILE);
bool Build(ConstExprEmitter *Emitter, llvm::ConstantStruct *Base,
InitListExpr *Updater);
- void Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
+ bool Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
const CXXRecordDecl *VTableClass, CharUnits BaseOffset);
llvm::Constant *Finalize(QualType Ty);
@@ -201,7 +203,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
if (CGM.getDataLayout().isBigEndian()) {
- Tmp = Tmp.lshr(NewFieldWidth);
+ Tmp.lshrInPlace(NewFieldWidth);
Tmp = Tmp.trunc(BitsInPreviousByte);
// We want the remaining high bits.
@@ -210,7 +212,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
Tmp = Tmp.trunc(BitsInPreviousByte);
// We want the remaining low bits.
- FieldValue = FieldValue.lshr(BitsInPreviousByte);
+ FieldValue.lshrInPlace(BitsInPreviousByte);
FieldValue = FieldValue.trunc(NewFieldWidth);
}
}
@@ -273,7 +275,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
// We want the low bits.
Tmp = FieldValue.trunc(CharWidth);
- FieldValue = FieldValue.lshr(CharWidth);
+ FieldValue.lshrInPlace(CharWidth);
}
Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
@@ -391,10 +393,10 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
// we just use explicit null values for them.
llvm::Constant *EltInit;
if (ElementNo < ILE->getNumInits())
- EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++),
- Field->getType(), CGF);
+ EltInit = Emitter.tryEmitPrivateForMemory(ILE->getInit(ElementNo++),
+ Field->getType());
else
- EltInit = CGM.EmitNullConstant(Field->getType());
+ EltInit = Emitter.emitNullForMemory(Field->getType());
if (!EltInit)
return false;
@@ -431,7 +433,7 @@ struct BaseInfo {
};
}
-void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
+bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
bool IsPrimaryBase,
const CXXRecordDecl *VTableClass,
CharUnits Offset) {
@@ -486,8 +488,9 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
const APValue &FieldValue =
RD->isUnion() ? Val.getUnionValue() : Val.getStructField(FieldNo);
llvm::Constant *EltInit =
- CGM.EmitConstantValueForMemory(FieldValue, Field->getType(), CGF);
- assert(EltInit && "EmitConstantValue can't fail");
+ Emitter.tryEmitPrivateForMemory(FieldValue, Field->getType());
+ if (!EltInit)
+ return false;
if (!Field->isBitField()) {
// Handle non-bitfield members.
@@ -498,6 +501,8 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
cast<llvm::ConstantInt>(EltInit));
}
}
+
+ return true;
}
llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) {
@@ -559,37 +564,37 @@ llvm::Constant *ConstStructBuilder::Finalize(QualType Ty) {
return Result;
}
-llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
- CodeGenFunction *CGF,
- ConstExprEmitter *Emitter,
+llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter,
+ ConstExprEmitter *ExprEmitter,
llvm::ConstantStruct *Base,
- InitListExpr *Updater) {
- ConstStructBuilder Builder(CGM, CGF);
- if (!Builder.Build(Emitter, Base, Updater))
+ InitListExpr *Updater,
+ QualType ValTy) {
+ ConstStructBuilder Builder(Emitter);
+ if (!Builder.Build(ExprEmitter, Base, Updater))
return nullptr;
- return Builder.Finalize(Updater->getType());
+ return Builder.Finalize(ValTy);
}
-llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
- CodeGenFunction *CGF,
- InitListExpr *ILE) {
- ConstStructBuilder Builder(CGM, CGF);
+llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter,
+ InitListExpr *ILE,
+ QualType ValTy) {
+ ConstStructBuilder Builder(Emitter);
if (!Builder.Build(ILE))
return nullptr;
- return Builder.Finalize(ILE->getType());
+ return Builder.Finalize(ValTy);
}
-llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
- CodeGenFunction *CGF,
+llvm::Constant *ConstStructBuilder::BuildStruct(ConstantEmitter &Emitter,
const APValue &Val,
QualType ValTy) {
- ConstStructBuilder Builder(CGM, CGF);
+ ConstStructBuilder Builder(Emitter);
const RecordDecl *RD = ValTy->castAs<RecordType>()->getDecl();
const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
- Builder.Build(Val, RD, false, CD, CharUnits::Zero());
+ if (!Builder.Build(Val, RD, false, CD, CharUnits::Zero()))
+ return nullptr;
return Builder.Finalize(ValTy);
}
@@ -599,57 +604,86 @@ llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
// ConstExprEmitter
//===----------------------------------------------------------------------===//
+static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM,
+ CodeGenFunction *CGF,
+ const CompoundLiteralExpr *E) {
+ CharUnits Align = CGM.getContext().getTypeAlignInChars(E->getType());
+ if (llvm::GlobalVariable *Addr =
+ CGM.getAddrOfConstantCompoundLiteralIfEmitted(E))
+ return ConstantAddress(Addr, Align);
+
+ LangAS addressSpace = E->getType().getAddressSpace();
+
+ ConstantEmitter emitter(CGM, CGF);
+ llvm::Constant *C = emitter.tryEmitForInitializer(E->getInitializer(),
+ addressSpace, E->getType());
+ if (!C) {
+ assert(!E->isFileScope() &&
+ "file-scope compound literal did not have constant initializer!");
+ return ConstantAddress::invalid();
+ }
+
+ auto GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
+ CGM.isTypeConstant(E->getType(), true),
+ llvm::GlobalValue::InternalLinkage,
+ C, ".compoundliteral", nullptr,
+ llvm::GlobalVariable::NotThreadLocal,
+ CGM.getContext().getTargetAddressSpace(addressSpace));
+ emitter.finalize(GV);
+ GV->setAlignment(Align.getQuantity());
+ CGM.setAddrOfConstantCompoundLiteral(E, GV);
+ return ConstantAddress(GV, Align);
+}
+
/// This class only needs to handle two cases:
/// 1) Literals (this is used by APValue emission to emit literals).
/// 2) Arrays, structs and unions (outside C++11 mode, we don't currently
/// constant fold these types).
class ConstExprEmitter :
- public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
+ public StmtVisitor<ConstExprEmitter, llvm::Constant*, QualType> {
CodeGenModule &CGM;
- CodeGenFunction *CGF;
+ ConstantEmitter &Emitter;
llvm::LLVMContext &VMContext;
public:
- ConstExprEmitter(CodeGenModule &cgm, CodeGenFunction *cgf)
- : CGM(cgm), CGF(cgf), VMContext(cgm.getLLVMContext()) {
+ ConstExprEmitter(ConstantEmitter &emitter)
+ : CGM(emitter.CGM), Emitter(emitter), VMContext(CGM.getLLVMContext()) {
}
//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
- llvm::Constant *VisitStmt(Stmt *S) {
+ llvm::Constant *VisitStmt(Stmt *S, QualType T) {
return nullptr;
}
- llvm::Constant *VisitParenExpr(ParenExpr *PE) {
- return Visit(PE->getSubExpr());
+ llvm::Constant *VisitParenExpr(ParenExpr *PE, QualType T) {
+ return Visit(PE->getSubExpr(), T);
}
llvm::Constant *
- VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) {
- return Visit(PE->getReplacement());
+ VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE,
+ QualType T) {
+ return Visit(PE->getReplacement(), T);
}
- llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
- return Visit(GE->getResultExpr());
+ llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE,
+ QualType T) {
+ return Visit(GE->getResultExpr(), T);
}
- llvm::Constant *VisitChooseExpr(ChooseExpr *CE) {
- return Visit(CE->getChosenSubExpr());
+ llvm::Constant *VisitChooseExpr(ChooseExpr *CE, QualType T) {
+ return Visit(CE->getChosenSubExpr(), T);
}
- llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- return Visit(E->getInitializer());
+ llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E, QualType T) {
+ return Visit(E->getInitializer(), T);
}
- llvm::Constant *VisitCastExpr(CastExpr* E) {
+ llvm::Constant *VisitCastExpr(CastExpr *E, QualType destType) {
if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
- CGM.EmitExplicitCastExprType(ECE, CGF);
+ CGM.EmitExplicitCastExprType(ECE, Emitter.CGF);
Expr *subExpr = E->getSubExpr();
- llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF);
- if (!C) return nullptr;
-
- llvm::Type *destType = ConvertType(E->getType());
switch (E->getCastKind()) {
case CK_ToUnion: {
@@ -657,14 +691,22 @@ public:
assert(E->getType()->isUnionType() &&
"Destination type is not union type!");
+ auto field = E->getTargetUnionField();
+
+ auto C = Emitter.tryEmitPrivateForMemory(subExpr, field->getType());
+ if (!C) return nullptr;
+
+ auto destTy = ConvertType(destType);
+ if (C->getType() == destTy) return C;
+
// Build a struct with the union sub-element as the first member,
- // and padded to the appropriate size
+ // and padded to the appropriate size.
SmallVector<llvm::Constant*, 2> Elts;
SmallVector<llvm::Type*, 2> Types;
Elts.push_back(C);
Types.push_back(C->getType());
unsigned CurSize = CGM.getDataLayout().getTypeAllocSize(C->getType());
- unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destType);
+ unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destTy);
assert(CurSize <= TotalSize && "Union size mismatch!");
if (unsigned NumPadBytes = TotalSize - CurSize) {
@@ -676,20 +718,26 @@ public:
Types.push_back(Ty);
}
- llvm::StructType* STy =
- llvm::StructType::get(C->getType()->getContext(), Types, false);
+ llvm::StructType *STy = llvm::StructType::get(VMContext, Types, false);
return llvm::ConstantStruct::get(STy, Elts);
}
- case CK_AddressSpaceConversion:
- return llvm::ConstantExpr::getAddrSpaceCast(C, destType);
+ case CK_AddressSpaceConversion: {
+ auto C = Emitter.tryEmitPrivate(subExpr, subExpr->getType());
+ if (!C) return nullptr;
+ LangAS destAS = E->getType()->getPointeeType().getAddressSpace();
+ LangAS srcAS = subExpr->getType()->getPointeeType().getAddressSpace();
+ llvm::Type *destTy = ConvertType(E->getType());
+ return CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGM, C, srcAS,
+ destAS, destTy);
+ }
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_ConstructorConversion:
- return C;
+ return Visit(subExpr, destType);
case CK_IntToOCLSampler:
llvm_unreachable("global sampler variables are not generated");
@@ -701,8 +749,11 @@ public:
case CK_ReinterpretMemberPointer:
case CK_DerivedToBaseMemberPointer:
- case CK_BaseToDerivedMemberPointer:
+ case CK_BaseToDerivedMemberPointer: {
+ auto C = Emitter.tryEmitPrivate(subExpr, subExpr->getType());
+ if (!C) return nullptr;
return CGM.getCXXABI().EmitMemberPointerConversion(E, C);
+ }
// These will never be supported.
case CK_ObjCObjectLValueCast:
@@ -759,27 +810,28 @@ public:
llvm_unreachable("Invalid CastKind");
}
- llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
- return Visit(DAE->getExpr());
+ llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE, QualType T) {
+ return Visit(DAE->getExpr(), T);
}
- llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
+ llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE, QualType T) {
// No need for a DefaultInitExprScope: we don't handle 'this' in a
// constant expression.
- return Visit(DIE->getExpr());
+ return Visit(DIE->getExpr(), T);
}
- llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E) {
+ llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E, QualType T) {
if (!E->cleanupsHaveSideEffects())
- return Visit(E->getSubExpr());
+ return Visit(E->getSubExpr(), T);
return nullptr;
}
- llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
- return Visit(E->GetTemporaryExpr());
+ llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E,
+ QualType T) {
+ return Visit(E->GetTemporaryExpr(), T);
}
- llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
+ llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) {
llvm::ArrayType *AType =
cast<llvm::ArrayType>(ConvertType(ILE->getType()));
llvm::Type *ElemTy = AType->getElementType();
@@ -790,13 +842,14 @@ public:
// initialise any elements that have not been initialised explicitly
unsigned NumInitableElts = std::min(NumInitElements, NumElements);
+ QualType EltType = CGM.getContext().getAsArrayType(T)->getElementType();
+
// Initialize remaining array elements.
- // FIXME: This doesn't handle member pointers correctly!
llvm::Constant *fillC;
if (Expr *filler = ILE->getArrayFiller())
- fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
+ fillC = Emitter.tryEmitAbstractForMemory(filler, EltType);
else
- fillC = llvm::Constant::getNullValue(ElemTy);
+ fillC = Emitter.emitNullForMemory(EltType);
if (!fillC)
return nullptr;
@@ -805,13 +858,13 @@ public:
return llvm::ConstantAggregateZero::get(AType);
// Copy initializer elements.
- std::vector<llvm::Constant*> Elts;
+ SmallVector<llvm::Constant*, 16> Elts;
Elts.reserve(NumInitableElts + NumElements);
bool RewriteType = false;
for (unsigned i = 0; i < NumInitableElts; ++i) {
Expr *Init = ILE->getInit(i);
- llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+ llvm::Constant *C = Emitter.tryEmitPrivateForMemory(Init, EltType);
if (!C)
return nullptr;
RewriteType |= (C->getType() != ElemTy);
@@ -835,33 +888,33 @@ public:
return llvm::ConstantArray::get(AType, Elts);
}
- llvm::Constant *EmitRecordInitialization(InitListExpr *ILE) {
- return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
+ llvm::Constant *EmitRecordInitialization(InitListExpr *ILE, QualType T) {
+ return ConstStructBuilder::BuildStruct(Emitter, ILE, T);
}
- llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) {
- return CGM.EmitNullConstant(E->getType());
+ llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E,
+ QualType T) {
+ return CGM.EmitNullConstant(T);
}
- llvm::Constant *VisitInitListExpr(InitListExpr *ILE) {
+ llvm::Constant *VisitInitListExpr(InitListExpr *ILE, QualType T) {
if (ILE->isTransparent())
- return Visit(ILE->getInit(0));
+ return Visit(ILE->getInit(0), T);
if (ILE->getType()->isArrayType())
- return EmitArrayInitialization(ILE);
+ return EmitArrayInitialization(ILE, T);
if (ILE->getType()->isRecordType())
- return EmitRecordInitialization(ILE);
+ return EmitRecordInitialization(ILE, T);
return nullptr;
}
llvm::Constant *EmitDesignatedInitUpdater(llvm::Constant *Base,
- InitListExpr *Updater) {
- QualType ExprType = Updater->getType();
-
- if (ExprType->isArrayType()) {
- llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(ExprType));
+ InitListExpr *Updater,
+ QualType destType) {
+ if (auto destAT = CGM.getContext().getAsArrayType(destType)) {
+ llvm::ArrayType *AType = cast<llvm::ArrayType>(ConvertType(destType));
llvm::Type *ElemType = AType->getElementType();
unsigned NumInitElements = Updater->getNumInits();
@@ -870,12 +923,12 @@ public:
std::vector<llvm::Constant *> Elts;
Elts.reserve(NumElements);
- if (llvm::ConstantDataArray *DataArray =
- dyn_cast<llvm::ConstantDataArray>(Base))
+ QualType destElemType = destAT->getElementType();
+
+ if (auto DataArray = dyn_cast<llvm::ConstantDataArray>(Base))
for (unsigned i = 0; i != NumElements; ++i)
Elts.push_back(DataArray->getElementAsConstant(i));
- else if (llvm::ConstantArray *Array =
- dyn_cast<llvm::ConstantArray>(Base))
+ else if (auto Array = dyn_cast<llvm::ConstantArray>(Base))
for (unsigned i = 0; i != NumElements; ++i)
Elts.push_back(Array->getOperand(i));
else
@@ -884,7 +937,7 @@ public:
llvm::Constant *fillC = nullptr;
if (Expr *filler = Updater->getArrayFiller())
if (!isa<NoInitExpr>(filler))
- fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
+ fillC = Emitter.tryEmitAbstractForMemory(filler, destElemType);
bool RewriteType = (fillC && fillC->getType() != ElemType);
for (unsigned i = 0; i != NumElements; ++i) {
@@ -897,9 +950,9 @@ public:
else if (!Init || isa<NoInitExpr>(Init))
; // Do nothing.
else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init))
- Elts[i] = EmitDesignatedInitUpdater(Elts[i], ChildILE);
+ Elts[i] = EmitDesignatedInitUpdater(Elts[i], ChildILE, destElemType);
else
- Elts[i] = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
+ Elts[i] = Emitter.tryEmitPrivateForMemory(Init, destElemType);
if (!Elts[i])
return nullptr;
@@ -919,25 +972,24 @@ public:
return llvm::ConstantArray::get(AType, Elts);
}
- if (ExprType->isRecordType())
- return ConstStructBuilder::BuildStruct(CGM, CGF, this,
- dyn_cast<llvm::ConstantStruct>(Base), Updater);
+ if (destType->isRecordType())
+ return ConstStructBuilder::BuildStruct(Emitter, this,
+ dyn_cast<llvm::ConstantStruct>(Base), Updater, destType);
return nullptr;
}
- llvm::Constant *VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E) {
- return EmitDesignatedInitUpdater(
- CGM.EmitConstantExpr(E->getBase(), E->getType(), CGF),
- E->getUpdater());
+ llvm::Constant *VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E,
+ QualType destType) {
+ auto C = Visit(E->getBase(), destType);
+ if (!C) return nullptr;
+ return EmitDesignatedInitUpdater(C, E->getUpdater(), destType);
}
- llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) {
+ llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E, QualType Ty) {
if (!E->getConstructor()->isTrivial())
return nullptr;
- QualType Ty = E->getType();
-
// FIXME: We should not have to call getBaseElementType here.
const RecordType *RT =
CGM.getContext().getBaseElementType(Ty)->getAs<RecordType>();
@@ -960,26 +1012,23 @@ public:
assert(CGM.getContext().hasSameUnqualifiedType(Ty, Arg->getType()) &&
"argument to copy ctor is of wrong type");
- return Visit(Arg);
+ return Visit(Arg, Ty);
}
return CGM.EmitNullConstant(Ty);
}
- llvm::Constant *VisitStringLiteral(StringLiteral *E) {
+ llvm::Constant *VisitStringLiteral(StringLiteral *E, QualType T) {
return CGM.GetConstantArrayFromStringLiteral(E);
}
- llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E, QualType T) {
// This must be an @encode initializing an array in a static initializer.
// Don't emit it as the address of the string, emit the string data itself
// as an inline array.
std::string Str;
CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str);
- QualType T = E->getType();
- if (T->getTypeClass() == Type::TypeOfExpr)
- T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
- const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
+ const ConstantArrayType *CAT = CGM.getContext().getAsConstantArrayType(T);
// Resize the string to the right size, adding zeros at the end, or
// truncating as needed.
@@ -987,151 +1036,19 @@ public:
return llvm::ConstantDataArray::getString(VMContext, Str, false);
}
- llvm::Constant *VisitUnaryExtension(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
+ llvm::Constant *VisitUnaryExtension(const UnaryOperator *E, QualType T) {
+ return Visit(E->getSubExpr(), T);
}
// Utility methods
llvm::Type *ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
-
-public:
- ConstantAddress EmitLValue(APValue::LValueBase LVBase) {
- if (const ValueDecl *Decl = LVBase.dyn_cast<const ValueDecl*>()) {
- if (Decl->hasAttr<WeakRefAttr>())
- return CGM.GetWeakRefReference(Decl);
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
- return ConstantAddress(CGM.GetAddrOfFunction(FD), CharUnits::One());
- if (const VarDecl* VD = dyn_cast<VarDecl>(Decl)) {
- // We can never refer to a variable with local storage.
- if (!VD->hasLocalStorage()) {
- CharUnits Align = CGM.getContext().getDeclAlign(VD);
- if (VD->isFileVarDecl() || VD->hasExternalStorage())
- return ConstantAddress(CGM.GetAddrOfGlobalVar(VD), Align);
- else if (VD->isLocalVarDecl()) {
- auto Ptr = CGM.getOrCreateStaticVarDecl(
- *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false));
- return ConstantAddress(Ptr, Align);
- }
- }
- }
- return ConstantAddress::invalid();
- }
-
- Expr *E = const_cast<Expr*>(LVBase.get<const Expr*>());
- switch (E->getStmtClass()) {
- default: break;
- case Expr::CompoundLiteralExprClass: {
- CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
- CharUnits Align = CGM.getContext().getTypeAlignInChars(E->getType());
- if (llvm::GlobalVariable *Addr =
- CGM.getAddrOfConstantCompoundLiteralIfEmitted(CLE))
- return ConstantAddress(Addr, Align);
-
- llvm::Constant* C = CGM.EmitConstantExpr(CLE->getInitializer(),
- CLE->getType(), CGF);
- // FIXME: "Leaked" on failure.
- if (!C) return ConstantAddress::invalid();
-
- auto GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
- E->getType().isConstant(CGM.getContext()),
- llvm::GlobalValue::InternalLinkage,
- C, ".compoundliteral", nullptr,
- llvm::GlobalVariable::NotThreadLocal,
- CGM.getContext().getTargetAddressSpace(E->getType()));
- GV->setAlignment(Align.getQuantity());
- CGM.setAddrOfConstantCompoundLiteral(CLE, GV);
- return ConstantAddress(GV, Align);
- }
- case Expr::StringLiteralClass:
- return CGM.GetAddrOfConstantStringFromLiteral(cast<StringLiteral>(E));
- case Expr::ObjCEncodeExprClass:
- return CGM.GetAddrOfConstantStringFromObjCEncode(cast<ObjCEncodeExpr>(E));
- case Expr::ObjCStringLiteralClass: {
- ObjCStringLiteral* SL = cast<ObjCStringLiteral>(E);
- ConstantAddress C =
- CGM.getObjCRuntime().GenerateConstantString(SL->getString());
- return C.getElementBitCast(ConvertType(E->getType()));
- }
- case Expr::PredefinedExprClass: {
- unsigned Type = cast<PredefinedExpr>(E)->getIdentType();
- if (CGF) {
- LValue Res = CGF->EmitPredefinedLValue(cast<PredefinedExpr>(E));
- return cast<ConstantAddress>(Res.getAddress());
- } else if (Type == PredefinedExpr::PrettyFunction) {
- return CGM.GetAddrOfConstantCString("top level", ".tmp");
- }
-
- return CGM.GetAddrOfConstantCString("", ".tmp");
- }
- case Expr::AddrLabelExprClass: {
- assert(CGF && "Invalid address of label expression outside function.");
- llvm::Constant *Ptr =
- CGF->GetAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel());
- Ptr = llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType()));
- return ConstantAddress(Ptr, CharUnits::One());
- }
- case Expr::CallExprClass: {
- CallExpr* CE = cast<CallExpr>(E);
- unsigned builtin = CE->getBuiltinCallee();
- if (builtin !=
- Builtin::BI__builtin___CFStringMakeConstantString &&
- builtin !=
- Builtin::BI__builtin___NSStringMakeConstantString)
- break;
- const Expr *Arg = CE->getArg(0)->IgnoreParenCasts();
- const StringLiteral *Literal = cast<StringLiteral>(Arg);
- if (builtin ==
- Builtin::BI__builtin___NSStringMakeConstantString) {
- return CGM.getObjCRuntime().GenerateConstantString(Literal);
- }
- // FIXME: need to deal with UCN conversion issues.
- return CGM.GetAddrOfConstantCFString(Literal);
- }
- case Expr::BlockExprClass: {
- StringRef FunctionName;
- if (CGF)
- FunctionName = CGF->CurFn->getName();
- else
- FunctionName = "global";
-
- // This is not really an l-value.
- llvm::Constant *Ptr =
- CGM.GetAddrOfGlobalBlock(cast<BlockExpr>(E), FunctionName);
- return ConstantAddress(Ptr, CGM.getPointerAlign());
- }
- case Expr::CXXTypeidExprClass: {
- CXXTypeidExpr *Typeid = cast<CXXTypeidExpr>(E);
- QualType T;
- if (Typeid->isTypeOperand())
- T = Typeid->getTypeOperand(CGM.getContext());
- else
- T = Typeid->getExprOperand()->getType();
- return ConstantAddress(CGM.GetAddrOfRTTIDescriptor(T),
- CGM.getPointerAlign());
- }
- case Expr::CXXUuidofExprClass: {
- return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E));
- }
- case Expr::MaterializeTemporaryExprClass: {
- MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);
- assert(MTE->getStorageDuration() == SD_Static);
- SmallVector<const Expr *, 2> CommaLHSs;
- SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Inner = MTE->GetTemporaryExpr()
- ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
- return CGM.GetAddrOfGlobalTemporary(MTE, Inner);
- }
- }
-
- return ConstantAddress::invalid();
- }
};
} // end anonymous namespace.
-bool ConstStructBuilder::Build(ConstExprEmitter *Emitter,
+bool ConstStructBuilder::Build(ConstExprEmitter *ExprEmitter,
llvm::ConstantStruct *Base,
InitListExpr *Updater) {
assert(Base && "base expression should not be empty");
@@ -1179,9 +1096,10 @@ bool ConstStructBuilder::Build(ConstExprEmitter *Emitter,
if (!Init || isa<NoInitExpr>(Init))
; // Do nothing.
else if (InitListExpr *ChildILE = dyn_cast<InitListExpr>(Init))
- EltInit = Emitter->EmitDesignatedInitUpdater(EltInit, ChildILE);
+ EltInit = ExprEmitter->EmitDesignatedInitUpdater(EltInit, ChildILE,
+ Field->getType());
else
- EltInit = CGM.EmitConstantExpr(Init, Field->getType(), CGF);
+ EltInit = Emitter.tryEmitPrivateForMemory(Init, Field->getType());
++ElementNo;
@@ -1200,26 +1118,294 @@ bool ConstStructBuilder::Build(ConstExprEmitter *Emitter,
return true;
}
-llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
- CodeGenFunction *CGF) {
+llvm::Constant *ConstantEmitter::validateAndPopAbstract(llvm::Constant *C,
+ AbstractState saved) {
+ Abstract = saved.OldValue;
+
+ assert(saved.OldPlaceholdersSize == PlaceholderAddresses.size() &&
+ "created a placeholder while doing an abstract emission?");
+
+ // No validation necessary for now.
+ // No cleanup to do for now.
+ return C;
+}
+
+llvm::Constant *
+ConstantEmitter::tryEmitAbstractForInitializer(const VarDecl &D) {
+ auto state = pushAbstract();
+ auto C = tryEmitPrivateForVarInit(D);
+ return validateAndPopAbstract(C, state);
+}
+
+llvm::Constant *
+ConstantEmitter::tryEmitAbstract(const Expr *E, QualType destType) {
+ auto state = pushAbstract();
+ auto C = tryEmitPrivate(E, destType);
+ return validateAndPopAbstract(C, state);
+}
+
+llvm::Constant *
+ConstantEmitter::tryEmitAbstract(const APValue &value, QualType destType) {
+ auto state = pushAbstract();
+ auto C = tryEmitPrivate(value, destType);
+ return validateAndPopAbstract(C, state);
+}
+
+llvm::Constant *
+ConstantEmitter::emitAbstract(const Expr *E, QualType destType) {
+ auto state = pushAbstract();
+ auto C = tryEmitPrivate(E, destType);
+ C = validateAndPopAbstract(C, state);
+ if (!C) {
+ CGM.Error(E->getExprLoc(),
+ "internal error: could not emit constant value \"abstractly\"");
+ C = CGM.EmitNullConstant(destType);
+ }
+ return C;
+}
+
+llvm::Constant *
+ConstantEmitter::emitAbstract(SourceLocation loc, const APValue &value,
+ QualType destType) {
+ auto state = pushAbstract();
+ auto C = tryEmitPrivate(value, destType);
+ C = validateAndPopAbstract(C, state);
+ if (!C) {
+ CGM.Error(loc,
+ "internal error: could not emit constant value \"abstractly\"");
+ C = CGM.EmitNullConstant(destType);
+ }
+ return C;
+}
+
+llvm::Constant *ConstantEmitter::tryEmitForInitializer(const VarDecl &D) {
+ initializeNonAbstract(D.getType().getAddressSpace());
+ return markIfFailed(tryEmitPrivateForVarInit(D));
+}
+
+llvm::Constant *ConstantEmitter::tryEmitForInitializer(const Expr *E,
+ LangAS destAddrSpace,
+ QualType destType) {
+ initializeNonAbstract(destAddrSpace);
+ return markIfFailed(tryEmitPrivateForMemory(E, destType));
+}
+
+llvm::Constant *ConstantEmitter::emitForInitializer(const APValue &value,
+ LangAS destAddrSpace,
+ QualType destType) {
+ initializeNonAbstract(destAddrSpace);
+ auto C = tryEmitPrivateForMemory(value, destType);
+ assert(C && "couldn't emit constant value non-abstractly?");
+ return C;
+}
+
+llvm::GlobalValue *ConstantEmitter::getCurrentAddrPrivate() {
+ assert(!Abstract && "cannot get current address for abstract constant");
+
+
+
+ // Make an obviously ill-formed global that should blow up compilation
+ // if it survives.
+ auto global = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty, true,
+ llvm::GlobalValue::PrivateLinkage,
+ /*init*/ nullptr,
+ /*name*/ "",
+ /*before*/ nullptr,
+ llvm::GlobalVariable::NotThreadLocal,
+ CGM.getContext().getTargetAddressSpace(DestAddressSpace));
+
+ PlaceholderAddresses.push_back(std::make_pair(nullptr, global));
+
+ return global;
+}
+
+void ConstantEmitter::registerCurrentAddrPrivate(llvm::Constant *signal,
+ llvm::GlobalValue *placeholder) {
+ assert(!PlaceholderAddresses.empty());
+ assert(PlaceholderAddresses.back().first == nullptr);
+ assert(PlaceholderAddresses.back().second == placeholder);
+ PlaceholderAddresses.back().first = signal;
+}
+
+namespace {
+ struct ReplacePlaceholders {
+ CodeGenModule &CGM;
+
+ /// The base address of the global.
+ llvm::Constant *Base;
+ llvm::Type *BaseValueTy = nullptr;
+
+ /// The placeholder addresses that were registered during emission.
+ llvm::DenseMap<llvm::Constant*, llvm::GlobalVariable*> PlaceholderAddresses;
+
+ /// The locations of the placeholder signals.
+ llvm::DenseMap<llvm::GlobalVariable*, llvm::Constant*> Locations;
+
+ /// The current index stack. We use a simple unsigned stack because
+ /// we assume that placeholders will be relatively sparse in the
+ /// initializer, but we cache the index values we find just in case.
+ llvm::SmallVector<unsigned, 8> Indices;
+ llvm::SmallVector<llvm::Constant*, 8> IndexValues;
+
+ ReplacePlaceholders(CodeGenModule &CGM, llvm::Constant *base,
+ ArrayRef<std::pair<llvm::Constant*,
+ llvm::GlobalVariable*>> addresses)
+ : CGM(CGM), Base(base),
+ PlaceholderAddresses(addresses.begin(), addresses.end()) {
+ }
+
+ void replaceInInitializer(llvm::Constant *init) {
+ // Remember the type of the top-most initializer.
+ BaseValueTy = init->getType();
+
+ // Initialize the stack.
+ Indices.push_back(0);
+ IndexValues.push_back(nullptr);
+
+ // Recurse into the initializer.
+ findLocations(init);
+
+ // Check invariants.
+ assert(IndexValues.size() == Indices.size() && "mismatch");
+ assert(Indices.size() == 1 && "didn't pop all indices");
+
+ // Do the replacement; this basically invalidates 'init'.
+ assert(Locations.size() == PlaceholderAddresses.size() &&
+ "missed a placeholder?");
+
+ // We're iterating over a hashtable, so this would be a source of
+ // non-determinism in compiler output *except* that we're just
+ // messing around with llvm::Constant structures, which never itself
+ // does anything that should be visible in compiler output.
+ for (auto &entry : Locations) {
+ assert(entry.first->getParent() == nullptr && "not a placeholder!");
+ entry.first->replaceAllUsesWith(entry.second);
+ entry.first->eraseFromParent();
+ }
+ }
+
+ private:
+ void findLocations(llvm::Constant *init) {
+ // Recurse into aggregates.
+ if (auto agg = dyn_cast<llvm::ConstantAggregate>(init)) {
+ for (unsigned i = 0, e = agg->getNumOperands(); i != e; ++i) {
+ Indices.push_back(i);
+ IndexValues.push_back(nullptr);
+
+ findLocations(agg->getOperand(i));
+
+ IndexValues.pop_back();
+ Indices.pop_back();
+ }
+ return;
+ }
+
+ // Otherwise, check for registered constants.
+ while (true) {
+ auto it = PlaceholderAddresses.find(init);
+ if (it != PlaceholderAddresses.end()) {
+ setLocation(it->second);
+ break;
+ }
+
+ // Look through bitcasts or other expressions.
+ if (auto expr = dyn_cast<llvm::ConstantExpr>(init)) {
+ init = expr->getOperand(0);
+ } else {
+ break;
+ }
+ }
+ }
+
+ void setLocation(llvm::GlobalVariable *placeholder) {
+ assert(Locations.find(placeholder) == Locations.end() &&
+ "already found location for placeholder!");
+
+ // Lazily fill in IndexValues with the values from Indices.
+ // We do this in reverse because we should always have a strict
+ // prefix of indices from the start.
+ assert(Indices.size() == IndexValues.size());
+ for (size_t i = Indices.size() - 1; i != size_t(-1); --i) {
+ if (IndexValues[i]) {
+#ifndef NDEBUG
+ for (size_t j = 0; j != i + 1; ++j) {
+ assert(IndexValues[j] &&
+ isa<llvm::ConstantInt>(IndexValues[j]) &&
+ cast<llvm::ConstantInt>(IndexValues[j])->getZExtValue()
+ == Indices[j]);
+ }
+#endif
+ break;
+ }
+
+ IndexValues[i] = llvm::ConstantInt::get(CGM.Int32Ty, Indices[i]);
+ }
+
+ // Form a GEP and then bitcast to the placeholder type so that the
+ // replacement will succeed.
+ llvm::Constant *location =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(BaseValueTy,
+ Base, IndexValues);
+ location = llvm::ConstantExpr::getBitCast(location,
+ placeholder->getType());
+
+ Locations.insert({placeholder, location});
+ }
+ };
+}
+
+void ConstantEmitter::finalize(llvm::GlobalVariable *global) {
+ assert(InitializedNonAbstract &&
+ "finalizing emitter that was used for abstract emission?");
+ assert(!Finalized && "finalizing emitter multiple times");
+ assert(global->getInitializer());
+
+ // Note that we might also be Failed.
+ Finalized = true;
+
+ if (!PlaceholderAddresses.empty()) {
+ ReplacePlaceholders(CGM, global, PlaceholderAddresses)
+ .replaceInInitializer(global->getInitializer());
+ PlaceholderAddresses.clear(); // satisfy
+ }
+}
+
+ConstantEmitter::~ConstantEmitter() {
+ assert((!InitializedNonAbstract || Finalized || Failed) &&
+ "not finalized after being initialized for non-abstract emission");
+ assert(PlaceholderAddresses.empty() && "unhandled placeholders");
+}
+
+static QualType getNonMemoryType(CodeGenModule &CGM, QualType type) {
+ if (auto AT = type->getAs<AtomicType>()) {
+ return CGM.getContext().getQualifiedType(AT->getValueType(),
+ type.getQualifiers());
+ }
+ return type;
+}
+
+llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
// Make a quick check if variable can be default NULL initialized
// and avoid going through rest of code which may do, for c++11,
// initialization of memory to all NULLs.
if (!D.hasLocalStorage()) {
- QualType Ty = D.getType();
- if (Ty->isArrayType())
- Ty = Context.getBaseElementType(Ty);
+ QualType Ty = CGM.getContext().getBaseElementType(D.getType());
if (Ty->isRecordType())
if (const CXXConstructExpr *E =
dyn_cast_or_null<CXXConstructExpr>(D.getInit())) {
const CXXConstructorDecl *CD = E->getConstructor();
if (CD->isTrivial() && CD->isDefaultConstructor())
- return EmitNullConstant(D.getType());
+ return CGM.EmitNullConstant(D.getType());
}
}
-
- if (const APValue *Value = D.evaluateValue())
- return EmitConstantValueForMemory(*Value, D.getType(), CGF);
+
+ QualType destType = D.getType();
+
+ // Try to emit the initializer. Note that this can allow some things that
+ // are not allowed by tryEmitPrivateForMemory alone.
+ if (auto value = D.evaluateValue()) {
+ return tryEmitPrivateForMemory(*value, destType);
+ }
// FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a
// reference is a constant expression, and the reference binds to a temporary,
@@ -1227,42 +1413,95 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
// incorrectly emit a prvalue constant in this case, and the calling code
// interprets that as the (pointer) value of the reference, rather than the
// desired value of the referee.
- if (D.getType()->isReferenceType())
+ if (destType->isReferenceType())
return nullptr;
const Expr *E = D.getInit();
assert(E && "No initializer to emit");
- llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
- if (C && C->getType()->isIntegerTy(1)) {
- llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
- C = llvm::ConstantExpr::getZExt(C, BoolTy);
+ auto nonMemoryDestType = getNonMemoryType(CGM, destType);
+ auto C =
+ ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), nonMemoryDestType);
+ return (C ? emitForMemory(C, destType) : nullptr);
+}
+
+llvm::Constant *
+ConstantEmitter::tryEmitAbstractForMemory(const Expr *E, QualType destType) {
+ auto nonMemoryDestType = getNonMemoryType(CGM, destType);
+ auto C = tryEmitAbstract(E, nonMemoryDestType);
+ return (C ? emitForMemory(C, destType) : nullptr);
+}
+
+llvm::Constant *
+ConstantEmitter::tryEmitAbstractForMemory(const APValue &value,
+ QualType destType) {
+ auto nonMemoryDestType = getNonMemoryType(CGM, destType);
+ auto C = tryEmitAbstract(value, nonMemoryDestType);
+ return (C ? emitForMemory(C, destType) : nullptr);
+}
+
+llvm::Constant *ConstantEmitter::tryEmitPrivateForMemory(const Expr *E,
+ QualType destType) {
+ auto nonMemoryDestType = getNonMemoryType(CGM, destType);
+ llvm::Constant *C = tryEmitPrivate(E, nonMemoryDestType);
+ return (C ? emitForMemory(C, destType) : nullptr);
+}
+
+llvm::Constant *ConstantEmitter::tryEmitPrivateForMemory(const APValue &value,
+ QualType destType) {
+ auto nonMemoryDestType = getNonMemoryType(CGM, destType);
+ auto C = tryEmitPrivate(value, nonMemoryDestType);
+ return (C ? emitForMemory(C, destType) : nullptr);
+}
+
+llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM,
+ llvm::Constant *C,
+ QualType destType) {
+ // For an _Atomic-qualified constant, we may need to add tail padding.
+ if (auto AT = destType->getAs<AtomicType>()) {
+ QualType destValueType = AT->getValueType();
+ C = emitForMemory(CGM, C, destValueType);
+
+ uint64_t innerSize = CGM.getContext().getTypeSize(destValueType);
+ uint64_t outerSize = CGM.getContext().getTypeSize(destType);
+ if (innerSize == outerSize)
+ return C;
+
+ assert(innerSize < outerSize && "emitted over-large constant for atomic");
+ llvm::Constant *elts[] = {
+ C,
+ llvm::ConstantAggregateZero::get(
+ llvm::ArrayType::get(CGM.Int8Ty, (outerSize - innerSize) / 8))
+ };
+ return llvm::ConstantStruct::getAnon(elts);
+ }
+
+ // Zero-extend bool.
+ if (C->getType()->isIntegerTy(1)) {
+ llvm::Type *boolTy = CGM.getTypes().ConvertTypeForMem(destType);
+ return llvm::ConstantExpr::getZExt(C, boolTy);
}
+
return C;
}
-llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
- QualType DestType,
- CodeGenFunction *CGF) {
+llvm::Constant *ConstantEmitter::tryEmitPrivate(const Expr *E,
+ QualType destType) {
Expr::EvalResult Result;
bool Success = false;
- if (DestType->isReferenceType())
- Success = E->EvaluateAsLValue(Result, Context);
+ if (destType->isReferenceType())
+ Success = E->EvaluateAsLValue(Result, CGM.getContext());
else
- Success = E->EvaluateAsRValue(Result, Context);
+ Success = E->EvaluateAsRValue(Result, CGM.getContext());
- llvm::Constant *C = nullptr;
+ llvm::Constant *C;
if (Success && !Result.HasSideEffects)
- C = EmitConstantValue(Result.Val, DestType, CGF);
+ C = tryEmitPrivate(Result.Val, destType);
else
- C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
+ C = ConstExprEmitter(*this).Visit(const_cast<Expr*>(E), destType);
- if (C && C->getType()->isIntegerTy(1)) {
- llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
- C = llvm::ConstantExpr::getZExt(C, BoolTy);
- }
return C;
}
@@ -1270,123 +1509,339 @@ llvm::Constant *CodeGenModule::getNullPointer(llvm::PointerType *T, QualType QT)
return getTargetCodeGenInfo().getNullPointer(*this, T, QT);
}
-llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
- QualType DestType,
- CodeGenFunction *CGF) {
- // For an _Atomic-qualified constant, we may need to add tail padding.
- if (auto *AT = DestType->getAs<AtomicType>()) {
- QualType InnerType = AT->getValueType();
- auto *Inner = EmitConstantValue(Value, InnerType, CGF);
-
- uint64_t InnerSize = Context.getTypeSize(InnerType);
- uint64_t OuterSize = Context.getTypeSize(DestType);
- if (InnerSize == OuterSize)
- return Inner;
-
- assert(InnerSize < OuterSize && "emitted over-large constant for atomic");
- llvm::Constant *Elts[] = {
- Inner,
- llvm::ConstantAggregateZero::get(
- llvm::ArrayType::get(Int8Ty, (OuterSize - InnerSize) / 8))
- };
- return llvm::ConstantStruct::getAnon(Elts);
- }
+namespace {
+/// A struct which can be used to peephole certain kinds of finalization
+/// that normally happen during l-value emission.
+struct ConstantLValue {
+ llvm::Constant *Value;
+ bool HasOffsetApplied;
+
+ /*implicit*/ ConstantLValue(llvm::Constant *value,
+ bool hasOffsetApplied = false)
+ : Value(value), HasOffsetApplied(false) {}
+
+ /*implicit*/ ConstantLValue(ConstantAddress address)
+ : ConstantLValue(address.getPointer()) {}
+};
- switch (Value.getKind()) {
- case APValue::Uninitialized:
- llvm_unreachable("Constant expressions should be initialized.");
- case APValue::LValue: {
- llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
- llvm::Constant *Offset =
- llvm::ConstantInt::get(Int64Ty, Value.getLValueOffset().getQuantity());
-
- llvm::Constant *C = nullptr;
-
- if (APValue::LValueBase LVBase = Value.getLValueBase()) {
- // An array can be represented as an lvalue referring to the base.
- if (isa<llvm::ArrayType>(DestTy)) {
- assert(Offset->isNullValue() && "offset on array initializer");
- return ConstExprEmitter(*this, CGF).Visit(
- const_cast<Expr*>(LVBase.get<const Expr*>()));
- }
+/// A helper class for emitting constant l-values.
+class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
+ ConstantLValue> {
+ CodeGenModule &CGM;
+ ConstantEmitter &Emitter;
+ const APValue &Value;
+ QualType DestType;
- C = ConstExprEmitter(*this, CGF).EmitLValue(LVBase).getPointer();
+ // Befriend StmtVisitorBase so that we don't have to expose Visit*.
+ friend StmtVisitorBase;
- // Apply offset if necessary.
- if (!Offset->isNullValue()) {
- unsigned AS = C->getType()->getPointerAddressSpace();
- llvm::Type *CharPtrTy = Int8Ty->getPointerTo(AS);
- llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, CharPtrTy);
- Casted = llvm::ConstantExpr::getGetElementPtr(Int8Ty, Casted, Offset);
- C = llvm::ConstantExpr::getPointerCast(Casted, C->getType());
- }
+public:
+ ConstantLValueEmitter(ConstantEmitter &emitter, const APValue &value,
+ QualType destType)
+ : CGM(emitter.CGM), Emitter(emitter), Value(value), DestType(destType) {}
- // Convert to the appropriate type; this could be an lvalue for
- // an integer.
- if (isa<llvm::PointerType>(DestTy))
- return llvm::ConstantExpr::getPointerCast(C, DestTy);
+ llvm::Constant *tryEmit();
- return llvm::ConstantExpr::getPtrToInt(C, DestTy);
- } else {
- C = Offset;
-
- // Convert to the appropriate type; this could be an lvalue for
- // an integer.
- if (auto PT = dyn_cast<llvm::PointerType>(DestTy)) {
- if (Value.isNullPointer())
- return getNullPointer(PT, DestType);
- // Convert the integer to a pointer-sized integer before converting it
- // to a pointer.
- C = llvm::ConstantExpr::getIntegerCast(
- C, getDataLayout().getIntPtrType(DestTy),
- /*isSigned=*/false);
- return llvm::ConstantExpr::getIntToPtr(C, DestTy);
- }
+private:
+ llvm::Constant *tryEmitAbsolute(llvm::Type *destTy);
+ ConstantLValue tryEmitBase(const APValue::LValueBase &base);
+
+ ConstantLValue VisitStmt(const Stmt *S) { return nullptr; }
+ ConstantLValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
+ ConstantLValue VisitStringLiteral(const StringLiteral *E);
+ ConstantLValue VisitObjCEncodeExpr(const ObjCEncodeExpr *E);
+ ConstantLValue VisitObjCStringLiteral(const ObjCStringLiteral *E);
+ ConstantLValue VisitPredefinedExpr(const PredefinedExpr *E);
+ ConstantLValue VisitAddrLabelExpr(const AddrLabelExpr *E);
+ ConstantLValue VisitCallExpr(const CallExpr *E);
+ ConstantLValue VisitBlockExpr(const BlockExpr *E);
+ ConstantLValue VisitCXXTypeidExpr(const CXXTypeidExpr *E);
+ ConstantLValue VisitCXXUuidofExpr(const CXXUuidofExpr *E);
+ ConstantLValue VisitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *E);
+
+ bool hasNonZeroOffset() const {
+ return !Value.getLValueOffset().isZero();
+ }
- // If the types don't match this should only be a truncate.
- if (C->getType() != DestTy)
- return llvm::ConstantExpr::getTrunc(C, DestTy);
+ /// Return the value offset.
+ llvm::Constant *getOffset() {
+ return llvm::ConstantInt::get(CGM.Int64Ty,
+ Value.getLValueOffset().getQuantity());
+ }
+ /// Apply the value offset to the given constant.
+ llvm::Constant *applyOffset(llvm::Constant *C) {
+ if (!hasNonZeroOffset())
return C;
+
+ llvm::Type *origPtrTy = C->getType();
+ unsigned AS = origPtrTy->getPointerAddressSpace();
+ llvm::Type *charPtrTy = CGM.Int8Ty->getPointerTo(AS);
+ C = llvm::ConstantExpr::getBitCast(C, charPtrTy);
+ C = llvm::ConstantExpr::getGetElementPtr(CGM.Int8Ty, C, getOffset());
+ C = llvm::ConstantExpr::getPointerCast(C, origPtrTy);
+ return C;
+ }
+};
+
+}
+
+llvm::Constant *ConstantLValueEmitter::tryEmit() {
+ const APValue::LValueBase &base = Value.getLValueBase();
+
+ // Certain special array initializers are represented in APValue
+ // as l-values referring to the base expression which generates the
+ // array. This happens with e.g. string literals. These should
+ // probably just get their own representation kind in APValue.
+ if (DestType->isArrayType()) {
+ assert(!hasNonZeroOffset() && "offset on array initializer");
+ auto expr = const_cast<Expr*>(base.get<const Expr*>());
+ return ConstExprEmitter(Emitter).Visit(expr, DestType);
+ }
+
+ // Otherwise, the destination type should be a pointer or reference
+ // type, but it might also be a cast thereof.
+ //
+ // FIXME: the chain of casts required should be reflected in the APValue.
+ // We need this in order to correctly handle things like a ptrtoint of a
+ // non-zero null pointer and addrspace casts that aren't trivially
+ // represented in LLVM IR.
+ auto destTy = CGM.getTypes().ConvertTypeForMem(DestType);
+ assert(isa<llvm::IntegerType>(destTy) || isa<llvm::PointerType>(destTy));
+
+ // If there's no base at all, this is a null or absolute pointer,
+ // possibly cast back to an integer type.
+ if (!base) {
+ return tryEmitAbsolute(destTy);
+ }
+
+ // Otherwise, try to emit the base.
+ ConstantLValue result = tryEmitBase(base);
+
+ // If that failed, we're done.
+ llvm::Constant *value = result.Value;
+ if (!value) return nullptr;
+
+ // Apply the offset if necessary and not already done.
+ if (!result.HasOffsetApplied) {
+ value = applyOffset(value);
+ }
+
+ // Convert to the appropriate type; this could be an lvalue for
+ // an integer. FIXME: performAddrSpaceCast
+ if (isa<llvm::PointerType>(destTy))
+ return llvm::ConstantExpr::getPointerCast(value, destTy);
+
+ return llvm::ConstantExpr::getPtrToInt(value, destTy);
+}
+
+/// Try to emit an absolute l-value, such as a null pointer or an integer
+/// bitcast to pointer type.
+llvm::Constant *
+ConstantLValueEmitter::tryEmitAbsolute(llvm::Type *destTy) {
+ auto offset = getOffset();
+
+ // If we're producing a pointer, this is easy.
+ if (auto destPtrTy = cast<llvm::PointerType>(destTy)) {
+ if (Value.isNullPointer()) {
+ // FIXME: integer offsets from non-zero null pointers.
+ return CGM.getNullPointer(destPtrTy, DestType);
}
+
+ // Convert the integer to a pointer-sized integer before converting it
+ // to a pointer.
+ // FIXME: signedness depends on the original integer type.
+ auto intptrTy = CGM.getDataLayout().getIntPtrType(destPtrTy);
+ llvm::Constant *C = offset;
+ C = llvm::ConstantExpr::getIntegerCast(getOffset(), intptrTy,
+ /*isSigned*/ false);
+ C = llvm::ConstantExpr::getIntToPtr(C, destPtrTy);
+ return C;
+ }
+
+ // Otherwise, we're basically returning an integer constant.
+
+ // FIXME: this does the wrong thing with ptrtoint of a null pointer,
+ // but since we don't know the original pointer type, there's not much
+ // we can do about it.
+
+ auto C = getOffset();
+ C = llvm::ConstantExpr::getIntegerCast(C, destTy, /*isSigned*/ false);
+ return C;
+}
+
+ConstantLValue
+ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
+ // Handle values.
+ if (const ValueDecl *D = base.dyn_cast<const ValueDecl*>()) {
+ if (D->hasAttr<WeakRefAttr>())
+ return CGM.GetWeakRefReference(D).getPointer();
+
+ if (auto FD = dyn_cast<FunctionDecl>(D))
+ return CGM.GetAddrOfFunction(FD);
+
+ if (auto VD = dyn_cast<VarDecl>(D)) {
+ // We can never refer to a variable with local storage.
+ if (!VD->hasLocalStorage()) {
+ if (VD->isFileVarDecl() || VD->hasExternalStorage())
+ return CGM.GetAddrOfGlobalVar(VD);
+
+ if (VD->isLocalVarDecl()) {
+ return CGM.getOrCreateStaticVarDecl(
+ *VD, CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false));
+ }
+ }
+ }
+
+ return nullptr;
+ }
+
+ // Otherwise, it must be an expression.
+ return Visit(base.get<const Expr*>());
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+ return tryEmitGlobalCompoundLiteral(CGM, Emitter.CGF, E);
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitStringLiteral(const StringLiteral *E) {
+ return CGM.GetAddrOfConstantStringFromLiteral(E);
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
+ return CGM.GetAddrOfConstantStringFromObjCEncode(E);
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitObjCStringLiteral(const ObjCStringLiteral *E) {
+ auto C = CGM.getObjCRuntime().GenerateConstantString(E->getString());
+ return C.getElementBitCast(CGM.getTypes().ConvertTypeForMem(E->getType()));
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitPredefinedExpr(const PredefinedExpr *E) {
+ if (auto CGF = Emitter.CGF) {
+ LValue Res = CGF->EmitPredefinedLValue(E);
+ return cast<ConstantAddress>(Res.getAddress());
+ }
+
+ auto kind = E->getIdentType();
+ if (kind == PredefinedExpr::PrettyFunction) {
+ return CGM.GetAddrOfConstantCString("top level", ".tmp");
+ }
+
+ return CGM.GetAddrOfConstantCString("", ".tmp");
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitAddrLabelExpr(const AddrLabelExpr *E) {
+ assert(Emitter.CGF && "Invalid address of label expression outside function");
+ llvm::Constant *Ptr = Emitter.CGF->GetAddrOfLabel(E->getLabel());
+ Ptr = llvm::ConstantExpr::getBitCast(Ptr,
+ CGM.getTypes().ConvertType(E->getType()));
+ return Ptr;
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
+ unsigned builtin = E->getBuiltinCallee();
+ if (builtin != Builtin::BI__builtin___CFStringMakeConstantString &&
+ builtin != Builtin::BI__builtin___NSStringMakeConstantString)
+ return nullptr;
+
+ auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts());
+ if (builtin == Builtin::BI__builtin___NSStringMakeConstantString) {
+ return CGM.getObjCRuntime().GenerateConstantString(literal);
+ } else {
+ // FIXME: need to deal with UCN conversion issues.
+ return CGM.GetAddrOfConstantCFString(literal);
}
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *E) {
+ StringRef functionName;
+ if (auto CGF = Emitter.CGF)
+ functionName = CGF->CurFn->getName();
+ else
+ functionName = "global";
+
+ return CGM.GetAddrOfGlobalBlock(E, functionName);
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
+ QualType T;
+ if (E->isTypeOperand())
+ T = E->getTypeOperand(CGM.getContext());
+ else
+ T = E->getExprOperand()->getType();
+ return CGM.GetAddrOfRTTIDescriptor(T);
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
+ return CGM.GetAddrOfUuidDescriptor(E);
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *E) {
+ assert(E->getStorageDuration() == SD_Static);
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Inner = E->GetTemporaryExpr()
+ ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+ return CGM.GetAddrOfGlobalTemporary(E, Inner);
+}
+
+llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value,
+ QualType DestType) {
+ switch (Value.getKind()) {
+ case APValue::Uninitialized:
+ llvm_unreachable("Constant expressions should be initialized.");
+ case APValue::LValue:
+ return ConstantLValueEmitter(*this, Value, DestType).tryEmit();
case APValue::Int:
- return llvm::ConstantInt::get(VMContext, Value.getInt());
+ return llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getInt());
case APValue::ComplexInt: {
llvm::Constant *Complex[2];
- Complex[0] = llvm::ConstantInt::get(VMContext,
+ Complex[0] = llvm::ConstantInt::get(CGM.getLLVMContext(),
Value.getComplexIntReal());
- Complex[1] = llvm::ConstantInt::get(VMContext,
+ Complex[1] = llvm::ConstantInt::get(CGM.getLLVMContext(),
Value.getComplexIntImag());
// FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
- Complex[1]->getType(),
- nullptr);
+ llvm::StructType *STy =
+ llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType());
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Float: {
const llvm::APFloat &Init = Value.getFloat();
if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf() &&
- !Context.getLangOpts().NativeHalfType &&
- !Context.getLangOpts().HalfArgsAndReturns)
- return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt());
+ !CGM.getContext().getLangOpts().NativeHalfType &&
+ !CGM.getContext().getLangOpts().HalfArgsAndReturns)
+ return llvm::ConstantInt::get(CGM.getLLVMContext(),
+ Init.bitcastToAPInt());
else
- return llvm::ConstantFP::get(VMContext, Init);
+ return llvm::ConstantFP::get(CGM.getLLVMContext(), Init);
}
case APValue::ComplexFloat: {
llvm::Constant *Complex[2];
- Complex[0] = llvm::ConstantFP::get(VMContext,
+ Complex[0] = llvm::ConstantFP::get(CGM.getLLVMContext(),
Value.getComplexFloatReal());
- Complex[1] = llvm::ConstantFP::get(VMContext,
+ Complex[1] = llvm::ConstantFP::get(CGM.getLLVMContext(),
Value.getComplexFloatImag());
// FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
- Complex[1]->getType(),
- nullptr);
+ llvm::StructType *STy =
+ llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType());
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Vector: {
@@ -1396,9 +1851,9 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
for (unsigned I = 0; I != NumElts; ++I) {
const APValue &Elt = Value.getVectorElt(I);
if (Elt.isInt())
- Inits[I] = llvm::ConstantInt::get(VMContext, Elt.getInt());
+ Inits[I] = llvm::ConstantInt::get(CGM.getLLVMContext(), Elt.getInt());
else if (Elt.isFloat())
- Inits[I] = llvm::ConstantFP::get(VMContext, Elt.getFloat());
+ Inits[I] = llvm::ConstantFP::get(CGM.getLLVMContext(), Elt.getFloat());
else
llvm_unreachable("unsupported vector element type");
}
@@ -1407,13 +1862,14 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
case APValue::AddrLabelDiff: {
const AddrLabelExpr *LHSExpr = Value.getAddrLabelDiffLHS();
const AddrLabelExpr *RHSExpr = Value.getAddrLabelDiffRHS();
- llvm::Constant *LHS = EmitConstantExpr(LHSExpr, LHSExpr->getType(), CGF);
- llvm::Constant *RHS = EmitConstantExpr(RHSExpr, RHSExpr->getType(), CGF);
+ llvm::Constant *LHS = tryEmitPrivate(LHSExpr, LHSExpr->getType());
+ llvm::Constant *RHS = tryEmitPrivate(RHSExpr, RHSExpr->getType());
+ if (!LHS || !RHS) return nullptr;
// Compute difference
- llvm::Type *ResultType = getTypes().ConvertType(DestType);
- LHS = llvm::ConstantExpr::getPtrToInt(LHS, IntPtrTy);
- RHS = llvm::ConstantExpr::getPtrToInt(RHS, IntPtrTy);
+ llvm::Type *ResultType = CGM.getTypes().ConvertType(DestType);
+ LHS = llvm::ConstantExpr::getPtrToInt(LHS, CGM.IntPtrTy);
+ RHS = llvm::ConstantExpr::getPtrToInt(RHS, CGM.IntPtrTy);
llvm::Constant *AddrLabelDiff = llvm::ConstantExpr::getSub(LHS, RHS);
// LLVM is a bit sensitive about the exact format of the
@@ -1423,21 +1879,21 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
}
case APValue::Struct:
case APValue::Union:
- return ConstStructBuilder::BuildStruct(*this, CGF, Value, DestType);
+ return ConstStructBuilder::BuildStruct(*this, Value, DestType);
case APValue::Array: {
- const ArrayType *CAT = Context.getAsArrayType(DestType);
+ const ArrayType *CAT = CGM.getContext().getAsArrayType(DestType);
unsigned NumElements = Value.getArraySize();
unsigned NumInitElts = Value.getArrayInitializedElts();
// Emit array filler, if there is one.
llvm::Constant *Filler = nullptr;
if (Value.hasArrayFiller())
- Filler = EmitConstantValueForMemory(Value.getArrayFiller(),
- CAT->getElementType(), CGF);
+ Filler = tryEmitAbstractForMemory(Value.getArrayFiller(),
+ CAT->getElementType());
// Emit initializer elements.
llvm::Type *CommonElementType =
- getTypes().ConvertType(CAT->getElementType());
+ CGM.getTypes().ConvertType(CAT->getElementType());
// Try to use a ConstantAggregateZero if we can.
if (Filler && Filler->isNullValue() && !NumInitElts) {
@@ -1446,15 +1902,21 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
return llvm::ConstantAggregateZero::get(AType);
}
- std::vector<llvm::Constant*> Elts;
+ SmallVector<llvm::Constant*, 16> Elts;
Elts.reserve(NumElements);
for (unsigned I = 0; I < NumElements; ++I) {
llvm::Constant *C = Filler;
- if (I < NumInitElts)
- C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I),
- CAT->getElementType(), CGF);
- else
- assert(Filler && "Missing filler for implicit elements of initializer");
+ if (I < NumInitElts) {
+ C = tryEmitPrivateForMemory(Value.getArrayInitializedElt(I),
+ CAT->getElementType());
+ } else if (!Filler) {
+ assert(Value.hasArrayFiller() &&
+ "Missing filler for implicit elements of initializer");
+ C = tryEmitPrivateForMemory(Value.getArrayFiller(),
+ CAT->getElementType());
+ }
+ if (!C) return nullptr;
+
if (I == 0)
CommonElementType = C->getType();
else if (C->getType() != CommonElementType)
@@ -1468,7 +1930,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
Types.reserve(NumElements);
for (unsigned i = 0, e = Elts.size(); i < e; ++i)
Types.push_back(Elts[i]->getType());
- llvm::StructType *SType = llvm::StructType::get(VMContext, Types, true);
+ llvm::StructType *SType =
+ llvm::StructType::get(CGM.getLLVMContext(), Types, true);
return llvm::ConstantStruct::get(SType, Elts);
}
@@ -1477,23 +1940,11 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
return llvm::ConstantArray::get(AType, Elts);
}
case APValue::MemberPointer:
- return getCXXABI().EmitMemberPointer(Value, DestType);
+ return CGM.getCXXABI().EmitMemberPointer(Value, DestType);
}
llvm_unreachable("Unknown APValue kind");
}
-llvm::Constant *
-CodeGenModule::EmitConstantValueForMemory(const APValue &Value,
- QualType DestType,
- CodeGenFunction *CGF) {
- llvm::Constant *C = EmitConstantValue(Value, DestType, CGF);
- if (C->getType()->isIntegerTy(1)) {
- llvm::Type *BoolTy = getTypes().ConvertTypeForMem(DestType);
- C = llvm::ConstantExpr::getZExt(C, BoolTy);
- }
- return C;
-}
-
llvm::GlobalVariable *CodeGenModule::getAddrOfConstantCompoundLiteralIfEmitted(
const CompoundLiteralExpr *E) {
return EmittedCompoundLiterals.lookup(E);
@@ -1509,7 +1960,7 @@ void CodeGenModule::setAddrOfConstantCompoundLiteral(
ConstantAddress
CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) {
assert(E->isFileScope() && "not a file-scope compound literal expr");
- return ConstExprEmitter(*this, nullptr).EmitLValue(E);
+ return tryEmitGlobalCompoundLiteral(*this, nullptr, E);
}
llvm::Constant *
@@ -1631,6 +2082,11 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
return EmitNullConstant(CGM, base, /*asCompleteObject=*/false);
}
+llvm::Constant *ConstantEmitter::emitNullForMemory(CodeGenModule &CGM,
+ QualType T) {
+ return emitForMemory(CGM, CGM.EmitNullConstant(T), T);
+}
+
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
if (T->getAs<PointerType>())
return getNullPointer(
@@ -1645,7 +2101,8 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
QualType ElementTy = CAT->getElementType();
- llvm::Constant *Element = EmitNullConstant(ElementTy);
+ llvm::Constant *Element =
+ ConstantEmitter::emitNullForMemory(*this, ElementTy);
unsigned NumElements = CAT->getSize().getZExtValue();
SmallVector<llvm::Constant *, 8> Array(NumElements, Element);
return llvm::ConstantArray::get(ATy, Array);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 67f821f2f0..7c11103617 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -30,6 +30,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
@@ -44,13 +45,85 @@ using llvm::Value;
//===----------------------------------------------------------------------===//
namespace {
+
+/// Determine whether the given binary operation may overflow.
+/// Sets \p Result to the value of the operation for BO_Add, BO_Sub, BO_Mul,
+/// and signed BO_{Div,Rem}. For these opcodes, and for unsigned BO_{Div,Rem},
+/// the returned overflow check is precise. The returned value is 'true' for
+/// all other opcodes, to be conservative.
+bool mayHaveIntegerOverflow(llvm::ConstantInt *LHS, llvm::ConstantInt *RHS,
+ BinaryOperator::Opcode Opcode, bool Signed,
+ llvm::APInt &Result) {
+ // Assume overflow is possible, unless we can prove otherwise.
+ bool Overflow = true;
+ const auto &LHSAP = LHS->getValue();
+ const auto &RHSAP = RHS->getValue();
+ if (Opcode == BO_Add) {
+ if (Signed)
+ Result = LHSAP.sadd_ov(RHSAP, Overflow);
+ else
+ Result = LHSAP.uadd_ov(RHSAP, Overflow);
+ } else if (Opcode == BO_Sub) {
+ if (Signed)
+ Result = LHSAP.ssub_ov(RHSAP, Overflow);
+ else
+ Result = LHSAP.usub_ov(RHSAP, Overflow);
+ } else if (Opcode == BO_Mul) {
+ if (Signed)
+ Result = LHSAP.smul_ov(RHSAP, Overflow);
+ else
+ Result = LHSAP.umul_ov(RHSAP, Overflow);
+ } else if (Opcode == BO_Div || Opcode == BO_Rem) {
+ if (Signed && !RHS->isZero())
+ Result = LHSAP.sdiv_ov(RHSAP, Overflow);
+ else
+ return false;
+ }
+ return Overflow;
+}
+
struct BinOpInfo {
Value *LHS;
Value *RHS;
QualType Ty; // Computation Type.
BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
- bool FPContractable;
+ FPOptions FPFeatures;
const Expr *E; // Entire expr, for error unsupported. May not be binop.
+
+ /// Check if the binop can result in integer overflow.
+ bool mayHaveIntegerOverflow() const {
+ // Without constant input, we can't rule out overflow.
+ auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS);
+ auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS);
+ if (!LHSCI || !RHSCI)
+ return true;
+
+ llvm::APInt Result;
+ return ::mayHaveIntegerOverflow(
+ LHSCI, RHSCI, Opcode, Ty->hasSignedIntegerRepresentation(), Result);
+ }
+
+ /// Check if the binop computes a division or a remainder.
+ bool isDivremOp() const {
+ return Opcode == BO_Div || Opcode == BO_Rem || Opcode == BO_DivAssign ||
+ Opcode == BO_RemAssign;
+ }
+
+ /// Check if the binop can result in an integer division by zero.
+ bool mayHaveIntegerDivisionByZero() const {
+ if (isDivremOp())
+ if (auto *CI = dyn_cast<llvm::ConstantInt>(RHS))
+ return CI->isZero();
+ return true;
+ }
+
+ /// Check if the binop can result in a float division by zero.
+ bool mayHaveFloatDivisionByZero() const {
+ if (isDivremOp())
+ if (auto *CFP = dyn_cast<llvm::ConstantFP>(RHS))
+ return CFP->isZero();
+ return true;
+ }
};
static bool MustVisitNullValue(const Expr *E) {
@@ -85,9 +158,17 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
assert((isa<UnaryOperator>(Op.E) || isa<BinaryOperator>(Op.E)) &&
"Expected a unary or binary operator");
+ // If the binop has constant inputs and we can prove there is no overflow,
+ // we can elide the overflow check.
+ if (!Op.mayHaveIntegerOverflow())
+ return true;
+
+ // If a unary op has a widened operand, the op cannot overflow.
if (const auto *UO = dyn_cast<UnaryOperator>(Op.E))
return IsWidenedIntegerOp(Ctx, UO->getSubExpr());
+ // We usually don't need overflow checks for binops with widened operands.
+ // Multiplication with promoted unsigned operands is a special case.
const auto *BO = cast<BinaryOperator>(Op.E);
auto OptionalLHSTy = getUnwidenedIntegerType(Ctx, BO->getLHS());
if (!OptionalLHSTy)
@@ -100,19 +181,35 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
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.
+ // This is the simple case: binops without unsigned multiplication, and with
+ // widened operands. No overflow check is needed here.
if ((Op.Opcode != BO_Mul && Op.Opcode != BO_MulAssign) ||
!LHSTy->isUnsignedIntegerType() || !RHSTy->isUnsignedIntegerType())
return true;
- // The overflow check can be skipped if either one of the unpromoted types
- // are less than half the size of the promoted type.
+ // For unsigned multiplication the overflow check can be elided if either one
+ // of the unpromoted types are less than half the size of the promoted type.
unsigned PromotedSize = Ctx.getTypeSize(Op.E->getType());
return (2 * Ctx.getTypeSize(LHSTy)) < PromotedSize ||
(2 * Ctx.getTypeSize(RHSTy)) < PromotedSize;
}
+/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
+static void updateFastMathFlags(llvm::FastMathFlags &FMF,
+ FPOptions FPFeatures) {
+ FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement());
+}
+
+/// Propagate fast-math flags from \p Op to the instruction in \p V.
+static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) {
+ if (auto *I = dyn_cast<llvm::Instruction>(V)) {
+ llvm::FastMathFlags FMF = I->getFastMathFlags();
+ updateFastMathFlags(FMF, Op.FPFeatures);
+ I->setFastMathFlags(FMF);
+ }
+ return V;
+}
+
class ScalarExprEmitter
: public StmtVisitor<ScalarExprEmitter, Value*> {
CodeGenFunction &CGF;
@@ -276,6 +373,15 @@ public:
Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}
+ Value *VisitCoawaitExpr(CoawaitExpr *S) {
+ return CGF.EmitCoawaitExpr(*S).getScalarVal();
+ }
+ Value *VisitCoyieldExpr(CoyieldExpr *S) {
+ return CGF.EmitCoyieldExpr(*S).getScalarVal();
+ }
+ Value *VisitUnaryCoawait(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
// Leaves.
Value *VisitIntegerLiteral(const IntegerLiteral *E) {
@@ -322,14 +428,19 @@ public:
return CGF.getOpaqueRValueMapping(E).getScalarVal();
}
+ Value *emitConstant(const CodeGenFunction::ConstantEmission &Constant,
+ Expr *E) {
+ assert(Constant && "not a constant");
+ if (Constant.isReference())
+ return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E),
+ E->getExprLoc());
+ return Constant.getValue();
+ }
+
// l-values.
Value *VisitDeclRefExpr(DeclRefExpr *E) {
- if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) {
- if (result.isReference())
- return EmitLoadOfLValue(result.getReferenceLValue(CGF, E),
- E->getExprLoc());
- return result.getValue();
- }
+ if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E))
+ return emitConstant(Constant, E);
return EmitLoadOfLValue(E);
}
@@ -544,8 +655,10 @@ public:
!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.
@@ -901,10 +1014,42 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateVectorSplat(NumElements, Src, "splat");
}
- // Allow bitcast from vector to integer/fp of the same size.
- if (isa<llvm::VectorType>(SrcTy) ||
- isa<llvm::VectorType>(DstTy))
- return Builder.CreateBitCast(Src, DstTy, "conv");
+ if (isa<llvm::VectorType>(SrcTy) || isa<llvm::VectorType>(DstTy)) {
+ // Allow bitcast from vector to integer/fp of the same size.
+ unsigned SrcSize = SrcTy->getPrimitiveSizeInBits();
+ unsigned DstSize = DstTy->getPrimitiveSizeInBits();
+ if (SrcSize == DstSize)
+ return Builder.CreateBitCast(Src, DstTy, "conv");
+
+ // Conversions between vectors of different sizes are not allowed except
+ // when vectors of half are involved. Operations on storage-only half
+ // vectors require promoting half vector operands to float vectors and
+ // truncating the result, which is either an int or float vector, to a
+ // short or half vector.
+
+ // Source and destination are both expected to be vectors.
+ llvm::Type *SrcElementTy = SrcTy->getVectorElementType();
+ llvm::Type *DstElementTy = DstTy->getVectorElementType();
+ (void)DstElementTy;
+
+ assert(((SrcElementTy->isIntegerTy() &&
+ DstElementTy->isIntegerTy()) ||
+ (SrcElementTy->isFloatingPointTy() &&
+ DstElementTy->isFloatingPointTy())) &&
+ "unexpected conversion between a floating-point vector and an "
+ "integer vector");
+
+ // Truncate an i32 vector to an i16 vector.
+ if (SrcElementTy->isIntegerTy())
+ return Builder.CreateIntCast(Src, DstTy, false, "conv");
+
+ // Truncate a float vector to a half vector.
+ if (SrcSize > DstSize)
+ return Builder.CreateFPTrunc(Src, DstTy, "conv");
+
+ // Promote a half vector to a float vector.
+ return Builder.CreateFPExt(Src, DstTy, "conv");
+ }
// Finally, we have the arithmetic types: real int/float.
Value *Res = nullptr;
@@ -1191,13 +1336,15 @@ Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
}
Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
- llvm::APSInt Value;
- if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
- if (E->isArrow())
- CGF.EmitScalarExpr(E->getBase());
- else
- EmitLValue(E->getBase());
- return Builder.getInt(Value);
+ if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) {
+ CGF.EmitIgnoredExpr(E->getBase());
+ return emitConstant(Constant, E);
+ } else {
+ llvm::APSInt Value;
+ if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) {
+ CGF.EmitIgnoredExpr(E->getBase());
+ return Builder.getInt(Value);
+ }
}
return EmitLoadOfLValue(E);
@@ -1486,10 +1633,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
- auto *Src = Visit(E);
- return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGF, Src,
- E->getType(),
- DestTy);
+ return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(
+ CGF, Visit(E), E->getType()->getPointeeType().getAddressSpace(),
+ DestTy->getPointeeType().getAddressSpace(), ConvertType(DestTy));
}
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
@@ -1671,7 +1817,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
case CK_IntToOCLSampler:
- return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
+ return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
} // end of switch
@@ -1709,7 +1855,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;
}
@@ -1744,6 +1890,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *input;
int amount = (isInc ? 1 : -1);
+ bool isSubtraction = !isInc;
if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
type = atomicTy->getValueType();
@@ -1833,7 +1980,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, numElts, "vla.inc");
else
- value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
+ value = CGF.EmitCheckedInBoundsGEP(
+ value, numElts, /*SignedIndices=*/false, isSubtraction,
+ E->getExprLoc(), "vla.inc");
// Arithmetic on function pointers (!) is just +-1.
} else if (type->isFunctionType()) {
@@ -1843,7 +1992,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.funcptr");
else
- value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
+ value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false,
+ isSubtraction, E->getExprLoc(),
+ "incdec.funcptr");
value = Builder.CreateBitCast(value, input->getType());
// For everything else, we can just do a simple increment.
@@ -1852,7 +2003,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.ptr");
else
- value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
+ value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false,
+ isSubtraction, E->getExprLoc(),
+ "incdec.ptr");
}
// Vector increment/decrement.
@@ -1933,7 +2086,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
else
- value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
+ value = CGF.EmitCheckedInBoundsGEP(value, sizeValue,
+ /*SignedIndices=*/false, isSubtraction,
+ E->getExprLoc(), "incdec.objptr");
value = Builder.CreateBitCast(value, input->getType());
}
@@ -1975,7 +2130,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);
}
@@ -2196,7 +2351,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;
}
@@ -2216,7 +2371,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);
@@ -2350,7 +2505,8 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const auto *BO = cast<BinaryOperator>(Ops.E);
if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) &&
Ops.Ty->hasSignedIntegerRepresentation() &&
- !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS())) {
+ !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS()) &&
+ Ops.mayHaveIntegerOverflow()) {
llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
llvm::Value *IntMin =
@@ -2373,11 +2529,13 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) ||
CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
- Ops.Ty->isIntegerType()) {
+ Ops.Ty->isIntegerType() &&
+ (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
} else if (CGF.SanOpts.has(SanitizerKind::FloatDivideByZero) &&
- Ops.Ty->isRealFloatingType()) {
+ Ops.Ty->isRealFloatingType() &&
+ Ops.mayHaveFloatDivisionByZero()) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
llvm::Value *NonZero = Builder.CreateFCmpUNE(Ops.RHS, Zero);
EmitBinOpCheck(std::make_pair(NonZero, SanitizerKind::FloatDivideByZero),
@@ -2412,7 +2570,8 @@ 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) ||
CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
- Ops.Ty->isIntegerType()) {
+ Ops.Ty->isIntegerType() &&
+ (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
@@ -2455,6 +2614,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
if (isSigned)
OpID |= 1;
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, opTy);
@@ -2470,7 +2630,6 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// If the signed-integer-overflow sanitizer is enabled, emit a call to its
// runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *NotOverflow = Builder.CreateNot(overflow);
SanitizerMask Kind = isSigned ? SanitizerKind::SignedIntegerOverflow
: SanitizerKind::UnsignedIntegerOverflow;
@@ -2546,13 +2705,38 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
std::swap(pointerOperand, indexOperand);
}
+ bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
+
unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
auto &DL = CGF.CGM.getDataLayout();
auto PtrTy = cast<llvm::PointerType>(pointer->getType());
+
+ // Some versions of glibc and gcc use idioms (particularly in their malloc
+ // routines) that add a pointer-sized integer (known to be a pointer value)
+ // to a null pointer in order to cast the value back to an integer or as
+ // part of a pointer alignment algorithm. This is undefined behavior, but
+ // we'd like to be able to compile programs that use it.
+ //
+ // Normally, we'd generate a GEP with a null-pointer base here in response
+ // to that code, but it's also UB to dereference a pointer created that
+ // way. Instead (as an acknowledged hack to tolerate the idiom) we will
+ // generate a direct cast of the integer value to a pointer.
+ //
+ // The idiom (p = nullptr + N) is not met if any of the following are true:
+ //
+ // The operation is subtraction.
+ // The index is not pointer-sized.
+ // The pointer type is not byte-sized.
+ //
+ if (BinaryOperator::isNullPointerArithmeticExtension(CGF.getContext(),
+ op.Opcode,
+ expr->getLHS(),
+ expr->getRHS()))
+ return CGF.Builder.CreateIntToPtr(index, pointer->getType());
+
if (width != DL.getTypeSizeInBits(PtrTy)) {
// Zero-extend or sign-extend the pointer value according to
// whether the index is signed or not.
- bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned,
"idx.ext");
}
@@ -2596,7 +2780,9 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");
} else {
index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
- pointer = CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
+ pointer =
+ CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction,
+ op.E->getExprLoc(), "add.ptr");
}
return pointer;
}
@@ -2613,7 +2799,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
if (CGF.getLangOpts().isSignedOverflowDefined())
return CGF.Builder.CreateGEP(pointer, index, "add.ptr");
- return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
+ return CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction,
+ op.E->getExprLoc(), "add.ptr");
}
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and
@@ -2663,12 +2850,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.
@@ -2691,7 +2873,7 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
if (op.LHS->getType()->isPointerTy() ||
op.RHS->getType()->isPointerTy())
- return emitPointerArithmetic(CGF, op, /*subtraction*/ false);
+ return emitPointerArithmetic(CGF, op, CodeGenFunction::NotSubtraction);
if (op.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
@@ -2718,7 +2900,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");
@@ -2751,7 +2934,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// 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");
@@ -2760,7 +2944,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// If the RHS is not a pointer, then we have normal pointer
// arithmetic.
if (!op.RHS->getType()->isPointerTy())
- return emitPointerArithmetic(CGF, op, /*subtraction*/ true);
+ return emitPointerArithmetic(CGF, op, CodeGenFunction::IsSubtraction);
// Otherwise, this is a pointer subtraction.
@@ -2936,16 +3120,25 @@ static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT,
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p :
llvm::Intrinsic::ppc_altivec_vcmpgtsh_p;
case BuiltinType::UInt:
- case BuiltinType::ULong:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p :
llvm::Intrinsic::ppc_altivec_vcmpgtuw_p;
case BuiltinType::Int:
- case BuiltinType::Long:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p :
llvm::Intrinsic::ppc_altivec_vcmpgtsw_p;
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequd_p :
+ llvm::Intrinsic::ppc_altivec_vcmpgtud_p;
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequd_p :
+ llvm::Intrinsic::ppc_altivec_vcmpgtsd_p;
case BuiltinType::Float:
return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpeqfp_p :
llvm::Intrinsic::ppc_altivec_vcmpgtfp_p;
+ case BuiltinType::Double:
+ return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_vsx_xvcmpeqdp_p :
+ llvm::Intrinsic::ppc_vsx_xvcmpgtdp_p;
}
}
@@ -3030,6 +3223,16 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
Value *CR6Param = Builder.getInt32(CR6);
llvm::Function *F = CGF.CGM.getIntrinsic(ID);
Result = Builder.CreateCall(F, {CR6Param, FirstVecArg, SecondVecArg});
+
+ // The result type of intrinsic may not be same as E->getType().
+ // If E->getType() is not BoolTy, EmitScalarConversion will do the
+ // conversion work. If E->getType() is BoolTy, EmitScalarConversion will
+ // do nothing, if ResultTy is not i1 at the same time, it will cause
+ // crash later.
+ llvm::IntegerType *ResultTy = cast<llvm::IntegerType>(Result->getType());
+ if (ResultTy->getBitWidth() > 1 &&
+ E->getType() == CGF.getContext().BoolTy)
+ Result = Builder.CreateTrunc(Result, Builder.getInt1Ty());
return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType(),
E->getExprLoc());
}
@@ -3589,8 +3792,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;
}
@@ -3599,9 +3806,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;
@@ -3724,3 +3934,136 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
llvm_unreachable("Unhandled compound assignment operator");
}
+
+Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
+ ArrayRef<Value *> IdxList,
+ bool SignedIndices,
+ bool IsSubtraction,
+ SourceLocation Loc,
+ const Twine &Name) {
+ Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
+
+ // If the pointer overflow sanitizer isn't enabled, do nothing.
+ if (!SanOpts.has(SanitizerKind::PointerOverflow))
+ return GEPVal;
+
+ // If the GEP has already been reduced to a constant, leave it be.
+ if (isa<llvm::Constant>(GEPVal))
+ return GEPVal;
+
+ // Only check for overflows in the default address space.
+ if (GEPVal->getType()->getPointerAddressSpace())
+ return GEPVal;
+
+ auto *GEP = cast<llvm::GEPOperator>(GEPVal);
+ assert(GEP->isInBounds() && "Expected inbounds GEP");
+
+ SanitizerScope SanScope(this);
+ auto &VMContext = getLLVMContext();
+ const auto &DL = CGM.getDataLayout();
+ auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType());
+
+ // Grab references to the signed add/mul overflow intrinsics for intptr_t.
+ auto *Zero = llvm::ConstantInt::getNullValue(IntPtrTy);
+ auto *SAddIntrinsic =
+ CGM.getIntrinsic(llvm::Intrinsic::sadd_with_overflow, IntPtrTy);
+ auto *SMulIntrinsic =
+ CGM.getIntrinsic(llvm::Intrinsic::smul_with_overflow, IntPtrTy);
+
+ // The total (signed) byte offset for the GEP.
+ llvm::Value *TotalOffset = nullptr;
+ // The offset overflow flag - true if the total offset overflows.
+ llvm::Value *OffsetOverflows = Builder.getFalse();
+
+ /// Return the result of the given binary operation.
+ auto eval = [&](BinaryOperator::Opcode Opcode, llvm::Value *LHS,
+ llvm::Value *RHS) -> llvm::Value * {
+ assert((Opcode == BO_Add || Opcode == BO_Mul) && "Can't eval binop");
+
+ // If the operands are constants, return a constant result.
+ if (auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS)) {
+ if (auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS)) {
+ llvm::APInt N;
+ bool HasOverflow = mayHaveIntegerOverflow(LHSCI, RHSCI, Opcode,
+ /*Signed=*/true, N);
+ if (HasOverflow)
+ OffsetOverflows = Builder.getTrue();
+ return llvm::ConstantInt::get(VMContext, N);
+ }
+ }
+
+ // Otherwise, compute the result with checked arithmetic.
+ auto *ResultAndOverflow = Builder.CreateCall(
+ (Opcode == BO_Add) ? SAddIntrinsic : SMulIntrinsic, {LHS, RHS});
+ OffsetOverflows = Builder.CreateOr(
+ Builder.CreateExtractValue(ResultAndOverflow, 1), OffsetOverflows);
+ return Builder.CreateExtractValue(ResultAndOverflow, 0);
+ };
+
+ // Determine the total byte offset by looking at each GEP operand.
+ for (auto GTI = llvm::gep_type_begin(GEP), GTE = llvm::gep_type_end(GEP);
+ GTI != GTE; ++GTI) {
+ llvm::Value *LocalOffset;
+ auto *Index = GTI.getOperand();
+ // Compute the local offset contributed by this indexing step:
+ if (auto *STy = GTI.getStructTypeOrNull()) {
+ // For struct indexing, the local offset is the byte position of the
+ // specified field.
+ unsigned FieldNo = cast<llvm::ConstantInt>(Index)->getZExtValue();
+ LocalOffset = llvm::ConstantInt::get(
+ IntPtrTy, DL.getStructLayout(STy)->getElementOffset(FieldNo));
+ } else {
+ // Otherwise this is array-like indexing. The local offset is the index
+ // multiplied by the element size.
+ auto *ElementSize = llvm::ConstantInt::get(
+ IntPtrTy, DL.getTypeAllocSize(GTI.getIndexedType()));
+ auto *IndexS = Builder.CreateIntCast(Index, IntPtrTy, /*isSigned=*/true);
+ LocalOffset = eval(BO_Mul, ElementSize, IndexS);
+ }
+
+ // If this is the first offset, set it as the total offset. Otherwise, add
+ // the local offset into the running total.
+ if (!TotalOffset || TotalOffset == Zero)
+ TotalOffset = LocalOffset;
+ else
+ TotalOffset = eval(BO_Add, TotalOffset, LocalOffset);
+ }
+
+ // Common case: if the total offset is zero, don't emit a check.
+ if (TotalOffset == Zero)
+ return GEPVal;
+
+ // Now that we've computed the total offset, add it to the base pointer (with
+ // wrapping semantics).
+ auto *IntPtr = Builder.CreatePtrToInt(GEP->getPointerOperand(), IntPtrTy);
+ auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset);
+
+ // The GEP is valid if:
+ // 1) The total offset doesn't overflow, and
+ // 2) The sign of the difference between the computed address and the base
+ // pointer matches the sign of the total offset.
+ llvm::Value *ValidGEP;
+ auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows);
+ if (SignedIndices) {
+ auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
+ auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
+ llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
+ ValidGEP = Builder.CreateAnd(
+ Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid),
+ NoOffsetOverflow);
+ } else if (!SignedIndices && !IsSubtraction) {
+ auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
+ ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow);
+ } else {
+ auto *NegOrZeroValid = Builder.CreateICmpULE(ComputedGEP, IntPtr);
+ ValidGEP = Builder.CreateAnd(NegOrZeroValid, NoOffsetOverflow);
+ }
+
+ llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)};
+ // Pass the computed GEP to the runtime to avoid emitting poisoned arguments.
+ llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
+ EmitCheck(std::make_pair(ValidGEP, SanitizerKind::PointerOverflow),
+ SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
+
+ return GEPVal;
+}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index a67131af5d..f26263d947 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -117,10 +117,24 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
const ObjCArrayLiteral *ALE = dyn_cast<ObjCArrayLiteral>(E);
if (!ALE)
DLE = cast<ObjCDictionaryLiteral>(E);
-
- // Compute the type of the array we're initializing.
+
+ // Optimize empty collections by referencing constants, when available.
uint64_t NumElements =
ALE ? ALE->getNumElements() : DLE->getNumElements();
+ if (NumElements == 0 && CGM.getLangOpts().ObjCRuntime.hasEmptyCollections()) {
+ StringRef ConstantName = ALE ? "__NSArray0__" : "__NSDictionary0__";
+ QualType IdTy(CGM.getContext().getObjCIdType());
+ llvm::Constant *Constant =
+ CGM.CreateRuntimeVariable(ConvertType(IdTy), ConstantName);
+ LValue LV = MakeNaturalAlignAddrLValue(Constant, IdTy);
+ llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getLocStart());
+ cast<llvm::LoadInst>(Ptr)->setMetadata(
+ CGM.getModule().getMDKindID("invariant.load"),
+ llvm::MDNode::get(getLLVMContext(), None));
+ return Builder.CreateBitCast(Ptr, ConvertType(E->getType()));
+ }
+
+ // Compute the type of the array we're initializing.
llvm::APInt APNumElements(Context.getTypeSize(Context.getSizeType()),
NumElements);
QualType ElementType = Context.getObjCIdType().withConst();
@@ -1316,7 +1330,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
ivarRef.getType(), VK_RValue, OK_Ordinary,
- SourceLocation(), false);
+ SourceLocation(), FPOptions());
EmitStmt(&assign);
}
@@ -1469,6 +1483,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
if (DI)
DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+ RunCleanupsScope ForScope(*this);
+
// The local variable comes into scope immediately.
AutoVarEmission variable = AutoVarEmission::invalid();
if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
@@ -1499,8 +1515,6 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
ArrayType::Normal, 0);
Address ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
- RunCleanupsScope ForScope(*this);
-
// Emit the collection pointer. In ARC, we do a retain.
llvm::Value *Collection;
if (getLangOpts().ObjCAutoRefCount) {
@@ -1532,16 +1546,15 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
getContext().getPointerType(ItemsTy));
// The third argument is the capacity of that temporary array.
- llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy);
- llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems);
- Args.add(RValue::get(Count), getContext().UnsignedLongTy);
+ llvm::Type *NSUIntegerTy = ConvertType(getContext().getNSUIntegerType());
+ llvm::Constant *Count = llvm::ConstantInt::get(NSUIntegerTy, NumItems);
+ Args.add(RValue::get(Count), getContext().getNSUIntegerType());
// Start the enumeration.
RValue CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
- getContext().UnsignedLongTy,
- FastEnumSel,
- Collection, Args);
+ CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
+ getContext().getNSUIntegerType(),
+ FastEnumSel, Collection, Args);
// The initial number of objects that were returned in the buffer.
llvm::Value *initialBufferLimit = CountRV.getScalarVal();
@@ -1549,7 +1562,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::BasicBlock *EmptyBB = createBasicBlock("forcoll.empty");
llvm::BasicBlock *LoopInitBB = createBasicBlock("forcoll.loopinit");
- llvm::Value *zero = llvm::Constant::getNullValue(UnsignedLongLTy);
+ llvm::Value *zero = llvm::Constant::getNullValue(NSUIntegerTy);
// If the limit pointer was zero to begin with, the collection is
// empty; skip all this. Set the branch weight assuming this has the same
@@ -1581,11 +1594,11 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(LoopBodyBB);
// The current index into the buffer.
- llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.index");
+ llvm::PHINode *index = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.index");
index->addIncoming(zero, LoopInitBB);
// The current buffer size.
- llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.count");
+ llvm::PHINode *count = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.count");
count->addIncoming(initialBufferLimit, LoopInitBB);
incrementProfileCounter(&S);
@@ -1695,8 +1708,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::BasicBlock *FetchMoreBB = createBasicBlock("forcoll.refetch");
// First we check in the local buffer.
- llvm::Value *indexPlusOne
- = Builder.CreateAdd(index, llvm::ConstantInt::get(UnsignedLongLTy, 1));
+ llvm::Value *indexPlusOne =
+ Builder.CreateAdd(index, llvm::ConstantInt::get(NSUIntegerTy, 1));
// If we haven't overrun the buffer yet, we can continue.
// Set the branch weights based on the simplifying assumption that this is
@@ -1713,10 +1726,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(FetchMoreBB);
CountRV =
- CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
- getContext().UnsignedLongTy,
- FastEnumSel,
- Collection, Args);
+ CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
+ getContext().getNSUIntegerType(),
+ FastEnumSel, Collection, Args);
// If we got a zero count, we're done.
llvm::Value *refetchCount = CountRV.getScalarVal();
@@ -1836,12 +1848,8 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
F->addFnAttr(llvm::Attribute::NonLazyBind);
}
- if (IsForwarding(Name)) {
- llvm::AttrBuilder B;
- B.addAttribute(llvm::Attribute::Returned);
-
- F->arg_begin()->addAttr(llvm::AttributeSet::get(F->getContext(), 1, B));
- }
+ if (IsForwarding(Name))
+ F->arg_begin()->addAttr(llvm::Attribute::Returned);
}
return RTF;
@@ -2405,6 +2413,12 @@ void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
CGF.EmitARCDestroyWeak(addr);
}
+void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
+ QualType type) {
+ llvm::Value *value = CGF.Builder.CreateLoad(addr);
+ CGF.EmitARCIntrinsicUse(value);
+}
+
namespace {
struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup {
llvm::Value *Token;
@@ -3230,10 +3244,12 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
SrcTy = C.getPointerType(SrcTy);
FunctionArgList args;
- ImplicitParamDecl dstDecl(getContext(), FD, SourceLocation(), nullptr,DestTy);
- args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(getContext(), FD, SourceLocation(), nullptr, SrcTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl DstDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ DestTy, ImplicitParamDecl::Other);
+ args.push_back(&DstDecl);
+ ImplicitParamDecl SrcDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ SrcTy, ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -3249,12 +3265,12 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
StartFunction(FD, C.VoidTy, Fn, FI, args);
- DeclRefExpr DstExpr(&dstDecl, false, DestTy,
+ DeclRefExpr DstExpr(&DstDecl, false, DestTy,
VK_RValue, SourceLocation());
UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation());
- DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
+ DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
VK_RValue, SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation());
@@ -3263,7 +3279,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);
@@ -3311,10 +3327,12 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
SrcTy = C.getPointerType(SrcTy);
FunctionArgList args;
- ImplicitParamDecl dstDecl(getContext(), FD, SourceLocation(), nullptr,DestTy);
- args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(getContext(), FD, SourceLocation(), nullptr, SrcTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl DstDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ DestTy, ImplicitParamDecl::Other);
+ args.push_back(&DstDecl);
+ ImplicitParamDecl SrcDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ SrcTy, ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -3329,7 +3347,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
StartFunction(FD, C.VoidTy, Fn, FI, args);
- DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
+ DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
VK_RValue, SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
@@ -3355,7 +3373,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
CXXConstExpr->getConstructionKind(),
SourceRange());
- DeclRefExpr DstExpr(&dstDecl, false, DestTy,
+ DeclRefExpr DstExpr(&DstDecl, false, DestTy,
VK_RValue, SourceLocation());
RValue DV = EmitAnyExpr(&DstExpr);
@@ -3416,4 +3434,37 @@ CodeGenFunction::EmitBuiltinAvailable(ArrayRef<llvm::Value *> 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 9f6ccb4b5d..c8b8be7f45 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -34,7 +34,6 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Compiler.h"
-#include <cstdarg>
using namespace clang;
using namespace CodeGen;
@@ -58,18 +57,19 @@ public:
/// Initialises the lazy function with the name, return type, and the types
/// of the arguments.
- LLVM_END_WITH_NULL
- void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy, ...) {
+ template <typename... Tys>
+ void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy,
+ Tys *... Types) {
CGM = Mod;
FunctionName = name;
Function = nullptr;
- std::vector<llvm::Type *> ArgTys;
- va_list Args;
- va_start(Args, RetTy);
- while (llvm::Type *ArgTy = va_arg(Args, llvm::Type *))
- ArgTys.push_back(ArgTy);
- va_end(Args);
- FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
+ if(sizeof...(Tys)) {
+ SmallVector<llvm::Type *, 8> ArgTys({Types...});
+ FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
+ }
+ else {
+ FTy = llvm::FunctionType::get(RetTy, None, false);
+ }
}
llvm::FunctionType *getType() { return FTy; }
@@ -603,11 +603,10 @@ protected:
public:
CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
// IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy,
- nullptr);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy);
// IMP objc_msg_lookup_super(struct objc_super*, SEL);
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
}
};
@@ -663,7 +662,7 @@ class CGObjCGNUstep : public CGObjCGNU {
}
// The lookup function is guaranteed not to capture the receiver pointer.
- LookupFn->setDoesNotCapture(1);
+ LookupFn->addParamAttr(0, llvm::Attribute::NoCapture);
llvm::Value *args[] = {
EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy),
@@ -702,52 +701,51 @@ class CGObjCGNUstep : public CGObjCGNU {
CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
- llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy,
- PtrTy, PtrTy, IntTy, IMPTy, nullptr);
+ llvm::StructType *SlotStructTy =
+ llvm::StructType::get(PtrTy, PtrTy, PtrTy, IntTy, IMPTy);
SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
// Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy,
- SelectorTy, IdTy, nullptr);
+ SelectorTy, IdTy);
// Slot_t objc_msg_lookup_super(struct objc_super*, SEL);
SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
// If we're in ObjC++ mode, then we want to make
if (CGM.getLangOpts().CPlusPlus) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, nullptr);
+ EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
// void __cxa_end_catch(void)
- ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, nullptr);
+ ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy);
// void _Unwind_Resume_or_Rethrow(void*)
ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
- PtrTy, nullptr);
+ PtrTy);
} else if (R.getVersion() >= VersionTuple(1, 7)) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// id objc_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy, nullptr);
+ EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy);
// void objc_end_catch(void)
- ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy, nullptr);
+ ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy);
// void _Unwind_Resume_or_Rethrow(void*)
- ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy,
- PtrTy, nullptr);
+ ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy);
}
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
- SelectorTy, IdTy, PtrDiffTy, nullptr);
+ SelectorTy, IdTy, PtrDiffTy);
SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
+ IdTy, SelectorTy, IdTy, PtrDiffTy);
SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
+ IdTy, SelectorTy, IdTy, PtrDiffTy);
SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy",
- VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
+ VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy);
// void objc_setCppObjectAtomic(void *dest, const void *src, void
// *helper);
CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy, nullptr);
+ PtrTy, PtrTy);
// void objc_getCppObjectAtomic(void *dest, const void *src, void
// *helper);
CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy, nullptr);
+ PtrTy, PtrTy);
}
llvm::Constant *GetCppAtomicObjectGetFunction() override {
@@ -849,14 +847,14 @@ protected:
public:
CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
// IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, nullptr);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy);
MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy,
- SelectorTy, nullptr);
+ SelectorTy);
// IMP objc_msg_lookup_super(struct objc_super*, SEL);
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
}
};
} // end anonymous namespace
@@ -945,35 +943,34 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
- ObjCSuperTy = llvm::StructType::get(IdTy, IdTy, nullptr);
+ ObjCSuperTy = llvm::StructType::get(IdTy, IdTy);
PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy);
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void objc_exception_throw(id);
- ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, nullptr);
- ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, nullptr);
+ ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
+ ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
// int objc_sync_enter(id);
- SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy, nullptr);
+ SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy);
// int objc_sync_exit(id);
- SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy, nullptr);
+ SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy);
// void objc_enumerationMutation (id)
- EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy,
- IdTy, nullptr);
+ EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy, IdTy);
// id objc_getProperty(id, SEL, ptrdiff_t, BOOL)
GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy,
- PtrDiffTy, BoolTy, nullptr);
+ PtrDiffTy, BoolTy);
// void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL)
SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy,
- PtrDiffTy, IdTy, BoolTy, BoolTy, nullptr);
+ PtrDiffTy, IdTy, BoolTy, BoolTy);
// void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
- GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy, nullptr);
+ GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy,
+ PtrDiffTy, BoolTy, BoolTy);
// void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
- SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy, nullptr);
+ SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy,
+ PtrDiffTy, BoolTy, BoolTy);
// IMP type
llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
@@ -997,21 +994,19 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
// Get functions needed in GC mode
// id objc_assign_ivar(id, id, ptrdiff_t);
- IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy,
- nullptr);
+ IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy);
// id objc_assign_strongCast (id, id*)
StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy,
- PtrToIdTy, nullptr);
+ PtrToIdTy);
// id objc_assign_global(id, id*);
- GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy,
- nullptr);
+ GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy);
// id objc_assign_weak(id, id*);
- WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy, nullptr);
+ WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy);
// id objc_read_weak(id*);
- WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy, nullptr);
+ WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy);
// void *objc_memmove_collectable(void*, void *, size_t);
MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy,
- SizeTy, nullptr);
+ SizeTy);
}
}
@@ -1317,7 +1312,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
}
}
// Cast the pointer to a simplified version of the class structure
- llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy, nullptr);
+ llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy);
ReceiverClass = Builder.CreateBitCast(ReceiverClass,
llvm::PointerType::getUnqual(CastTy));
// Get the superclass pointer
@@ -1326,8 +1321,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ReceiverClass =
Builder.CreateAlignedLoad(ReceiverClass, CGF.getPointerAlign());
// Construct the structure used to look up the IMP
- llvm::StructType *ObjCSuperTy = llvm::StructType::get(
- Receiver->getType(), IdTy, nullptr);
+ llvm::StructType *ObjCSuperTy =
+ llvm::StructType::get(Receiver->getType(), IdTy);
// FIXME: Is this really supposed to be a dynamic alloca?
Address ObjCSuper = Address(Builder.CreateAlloca(ObjCSuperTy),
@@ -1565,11 +1560,8 @@ GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
IvarList.addInt(IntTy, (int)IvarNames.size());
// Get the ivar structure type.
- llvm::StructType *ObjCIvarTy = llvm::StructType::get(
- PtrToInt8Ty,
- PtrToInt8Ty,
- IntTy,
- nullptr);
+ llvm::StructType *ObjCIvarTy =
+ llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy);
// Array of ivar structures.
auto Ivars = IvarList.beginArray(ObjCIvarTy);
@@ -1611,7 +1603,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
// anyway; the classes will still work with the GNU runtime, they will just
// be ignored.
llvm::StructType *ClassTy = llvm::StructType::get(
- PtrToInt8Ty, // isa
+ PtrToInt8Ty, // isa
PtrToInt8Ty, // super_class
PtrToInt8Ty, // name
LongTy, // version
@@ -1620,18 +1612,18 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
IVars->getType(), // ivars
Methods->getType(), // methods
// These are all filled in by the runtime, so we pretend
- PtrTy, // dtable
- PtrTy, // subclass_list
- PtrTy, // sibling_class
- PtrTy, // protocols
- PtrTy, // gc_object_type
+ PtrTy, // dtable
+ PtrTy, // subclass_list
+ PtrTy, // sibling_class
+ PtrTy, // protocols
+ PtrTy, // gc_object_type
// New ABI:
LongTy, // abi_version
IvarOffsets->getType(), // ivar_offsets
Properties->getType(), // properties
IntPtrTy, // strong_pointers
- IntPtrTy, // weak_pointers
- nullptr);
+ IntPtrTy // weak_pointers
+ );
ConstantInitBuilder Builder(CGM);
auto Elements = Builder.beginStruct(ClassTy);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 29b45e325b..992da81409 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -64,13 +64,11 @@ private:
// Add the non-lazy-bind attribute, since objc_msgSend is likely to
// be called a lot.
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSend",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NonLazyBind));
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(ObjectPtrTy, params, true), "objc_msgSend",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -107,8 +105,8 @@ private:
llvm::Constant *getMessageSendFp2retFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
- llvm::Type *resultType =
- llvm::StructType::get(longDoubleType, longDoubleType, nullptr);
+ llvm::Type *resultType =
+ llvm::StructType::get(longDoubleType, longDoubleType);
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
params, true),
@@ -310,7 +308,7 @@ public:
SmallVector<CanQualType,5> Params;
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
- Params.push_back(Ctx.LongTy);
+ Params.push_back(Ctx.getSizeType());
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
@@ -589,13 +587,11 @@ public:
llvm::Constant *getSetJmpFn() {
// This is specifically the prototype for x86.
llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
- params, false),
- "_setjmp",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NonLazyBind));
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(CGM.Int32Ty, params, false), "_setjmp",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
public:
@@ -890,7 +886,7 @@ protected:
/// Cached reference to the class for constant strings. This value has type
/// int * but is actually an Obj-C class pointer.
- llvm::WeakVH ConstantStringClassRef;
+ llvm::WeakTrackingVH ConstantStringClassRef;
/// \brief The LLVM type corresponding to NSConstantString.
llvm::StructType *NSConstantStringType = nullptr;
@@ -1008,6 +1004,8 @@ protected:
const ObjCInterfaceDecl *ID,
ObjCCommonTypesHelper &ObjCTypes);
+ std::string GetSectionName(StringRef Section, StringRef MachOAttributes);
+
public:
/// CreateMetadataVar - Create a global variable with internal
/// linkage for use by the Objective-C runtime.
@@ -1680,7 +1678,10 @@ struct NullReturnState {
/// Complete the null-return operation. It is valid to call this
/// regardless of whether 'init' has been called.
- RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType,
+ RValue complete(CodeGenFunction &CGF,
+ ReturnValueSlot returnSlot,
+ RValue result,
+ QualType resultType,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
// If we never had to do a null-check, just use the raw result.
@@ -1747,7 +1748,8 @@ struct NullReturnState {
// memory or (2) agg values in registers.
if (result.isAggregate()) {
assert(result.isAggregate() && "null init of non-aggregate result?");
- CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
+ if (!returnSlot.isUnused())
+ CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
if (contBB) CGF.EmitBlock(contBB);
return result;
}
@@ -2119,11 +2121,11 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
}
}
- NullReturnState nullReturn;
+ bool RequiresNullCheck = false;
llvm::Constant *Fn = nullptr;
if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
- if (ReceiverCanBeNull) nullReturn.init(CGF, Arg0);
+ if (ReceiverCanBeNull) RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
@@ -2136,23 +2138,30 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
// arm64 uses objc_msgSend for stret methods and yet null receiver check
// must be made for it.
if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
- nullReturn.init(CGF, Arg0);
+ RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
+ // We don't need to emit a null check to zero out an indirect result if the
+ // result is ignored.
+ if (Return.isUnused())
+ RequiresNullCheck = false;
+
// Emit a null-check if there's a consumed argument other than the receiver.
- bool RequiresNullCheck = false;
- if (ReceiverCanBeNull && CGM.getLangOpts().ObjCAutoRefCount && Method) {
+ if (!RequiresNullCheck && CGM.getLangOpts().ObjCAutoRefCount && Method) {
for (const auto *ParamDecl : Method->parameters()) {
if (ParamDecl->hasAttr<NSConsumedAttr>()) {
- if (!nullReturn.NullBB)
- nullReturn.init(CGF, Arg0);
RequiresNullCheck = true;
break;
}
}
}
+
+ NullReturnState nullReturn;
+ if (RequiresNullCheck) {
+ nullReturn.init(CGF, Arg0);
+ }
llvm::Instruction *CallSite;
Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
@@ -2166,7 +2175,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
llvm::CallSite(CallSite).setDoesNotReturn();
}
- return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
+ return nullReturn.complete(CGF, Return, rvalue, ResultType, CallArgs,
RequiresNullCheck ? Method : nullptr);
}
@@ -4790,6 +4799,27 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
/* *** Private Interface *** */
+std::string CGObjCCommonMac::GetSectionName(StringRef Section,
+ StringRef MachOAttributes) {
+ switch (CGM.getTriple().getObjectFormat()) {
+ default:
+ llvm_unreachable("unexpected object file format");
+ case llvm::Triple::MachO: {
+ if (MachOAttributes.empty())
+ return ("__DATA," + Section).str();
+ return ("__DATA," + Section + "," + MachOAttributes).str();
+ }
+ case llvm::Triple::ELF:
+ assert(Section.substr(0, 2) == "__" &&
+ "expected the name to begin with __");
+ return Section.substr(2).str();
+ case llvm::Triple::COFF:
+ assert(Section.substr(0, 2) == "__" &&
+ "expected the name to begin with __");
+ return ("." + Section.substr(2) + "$B").str();
+ }
+}
+
/// EmitImageInfo - Emit the image info marker used to encode some module
/// level information.
///
@@ -4813,9 +4843,10 @@ enum ImageInfoFlags {
void CGObjCCommonMac::EmitImageInfo() {
unsigned version = 0; // Version is unused?
- const char *Section = (ObjCABI == 1) ?
- "__OBJC, __image_info,regular" :
- "__DATA, __objc_imageinfo, regular, no_dead_strip";
+ std::string Section =
+ (ObjCABI == 1)
+ ? "__OBJC,__image_info,regular"
+ : GetSectionName("__objc_imageinfo", "regular,no_dead_strip");
// Generate module-level named metadata to convey this information to the
// linker and code-gen.
@@ -4826,7 +4857,7 @@ void CGObjCCommonMac::EmitImageInfo() {
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
version);
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
- llvm::MDString::get(VMContext,Section));
+ llvm::MDString::get(VMContext, Section));
if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
// Non-GC overrides those files which specify GC.
@@ -5053,6 +5084,11 @@ void IvarLayoutBuilder::visitField(const FieldDecl *field,
// Drill down into arrays.
uint64_t numElts = 1;
+ if (auto arrayType = CGM.getContext().getAsIncompleteArrayType(fieldType)) {
+ numElts = 0;
+ fieldType = arrayType->getElementType();
+ }
+ // Unlike incomplete arrays, constant arrays can be nested.
while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) {
numElts *= arrayType->getSize().getZExtValue();
fieldType = arrayType->getElementType();
@@ -5510,17 +5546,15 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *name;
// char *attributes;
// }
- PropertyTy = llvm::StructType::create("struct._prop_t",
- Int8PtrTy, Int8PtrTy, nullptr);
+ PropertyTy = llvm::StructType::create("struct._prop_t", Int8PtrTy, Int8PtrTy);
// struct _prop_list_t {
// uint32_t entsize; // sizeof(struct _prop_t)
// uint32_t count_of_properties;
// struct _prop_t prop_list[count_of_properties];
// }
- PropertyListTy =
- llvm::StructType::create("struct._prop_list_t", IntTy, IntTy,
- llvm::ArrayType::get(PropertyTy, 0), nullptr);
+ PropertyListTy = llvm::StructType::create(
+ "struct._prop_list_t", IntTy, IntTy, llvm::ArrayType::get(PropertyTy, 0));
// struct _prop_list_t *
PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
@@ -5529,9 +5563,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *method_type;
// char *_imp;
// }
- MethodTy = llvm::StructType::create("struct._objc_method",
- SelectorPtrTy, Int8PtrTy, Int8PtrTy,
- nullptr);
+ MethodTy = llvm::StructType::create("struct._objc_method", SelectorPtrTy,
+ Int8PtrTy, Int8PtrTy);
// struct _objc_cache *
CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
@@ -5544,17 +5577,16 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// SEL name;
// char *types;
// }
- MethodDescriptionTy =
- llvm::StructType::create("struct._objc_method_description",
- SelectorPtrTy, Int8PtrTy, nullptr);
+ MethodDescriptionTy = llvm::StructType::create(
+ "struct._objc_method_description", SelectorPtrTy, Int8PtrTy);
// struct _objc_method_description_list {
// int count;
// struct _objc_method_description[1];
// }
- MethodDescriptionListTy = llvm::StructType::create(
- "struct._objc_method_description_list", IntTy,
- llvm::ArrayType::get(MethodDescriptionTy, 0), nullptr);
+ MethodDescriptionListTy =
+ llvm::StructType::create("struct._objc_method_description_list", IntTy,
+ llvm::ArrayType::get(MethodDescriptionTy, 0));
// struct _objc_method_description_list *
MethodDescriptionListPtrTy =
@@ -5570,11 +5602,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// const char ** extendedMethodTypes;
// struct _objc_property_list *class_properties;
// }
- ProtocolExtensionTy =
- llvm::StructType::create("struct._objc_protocol_extension",
- IntTy, MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy, PropertyListPtrTy,
- Int8PtrPtrTy, PropertyListPtrTy, nullptr);
+ ProtocolExtensionTy = llvm::StructType::create(
+ "struct._objc_protocol_extension", IntTy, MethodDescriptionListPtrTy,
+ MethodDescriptionListPtrTy, PropertyListPtrTy, Int8PtrPtrTy,
+ PropertyListPtrTy);
// struct _objc_protocol_extension *
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
@@ -5586,10 +5617,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
ProtocolListTy =
llvm::StructType::create(VMContext, "struct._objc_protocol_list");
- ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy),
- LongTy,
- llvm::ArrayType::get(ProtocolTy, 0),
- nullptr);
+ ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy), LongTy,
+ llvm::ArrayType::get(ProtocolTy, 0));
// struct _objc_protocol {
// struct _objc_protocol_extension *isa;
@@ -5600,9 +5629,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// }
ProtocolTy->setBody(ProtocolExtensionPtrTy, Int8PtrTy,
llvm::PointerType::getUnqual(ProtocolListTy),
- MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy,
- nullptr);
+ MethodDescriptionListPtrTy, MethodDescriptionListPtrTy);
// struct _objc_protocol_list *
ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
@@ -5616,8 +5643,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *ivar_type;
// int ivar_offset;
// }
- IvarTy = llvm::StructType::create("struct._objc_ivar",
- Int8PtrTy, Int8PtrTy, IntTy, nullptr);
+ IvarTy = llvm::StructType::create("struct._objc_ivar", Int8PtrTy, Int8PtrTy,
+ IntTy);
// struct _objc_ivar_list *
IvarListTy =
@@ -5630,9 +5657,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
// struct _objc_class_extension *
- ClassExtensionTy =
- llvm::StructType::create("struct._objc_class_extension",
- IntTy, Int8PtrTy, PropertyListPtrTy, nullptr);
+ ClassExtensionTy = llvm::StructType::create(
+ "struct._objc_class_extension", IntTy, Int8PtrTy, PropertyListPtrTy);
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
@@ -5652,18 +5678,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_class_ext *ext;
// };
ClassTy->setBody(llvm::PointerType::getUnqual(ClassTy),
- llvm::PointerType::getUnqual(ClassTy),
- Int8PtrTy,
- LongTy,
- LongTy,
- LongTy,
- IvarListPtrTy,
- MethodListPtrTy,
- CachePtrTy,
- ProtocolListPtrTy,
- Int8PtrTy,
- ClassExtensionPtrTy,
- nullptr);
+ llvm::PointerType::getUnqual(ClassTy), Int8PtrTy, LongTy,
+ LongTy, LongTy, IvarListPtrTy, MethodListPtrTy, CachePtrTy,
+ ProtocolListPtrTy, Int8PtrTy, ClassExtensionPtrTy);
ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
@@ -5677,12 +5694,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_property_list *instance_properties;// category's @property
// struct _objc_property_list *class_properties;
// }
- CategoryTy =
- llvm::StructType::create("struct._objc_category",
- Int8PtrTy, Int8PtrTy, MethodListPtrTy,
- MethodListPtrTy, ProtocolListPtrTy,
- IntTy, PropertyListPtrTy, PropertyListPtrTy,
- nullptr);
+ CategoryTy = llvm::StructType::create(
+ "struct._objc_category", Int8PtrTy, Int8PtrTy, MethodListPtrTy,
+ MethodListPtrTy, ProtocolListPtrTy, IntTy, PropertyListPtrTy,
+ PropertyListPtrTy);
// Global metadata structures
@@ -5693,10 +5708,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// short cat_def_cnt;
// char *defs[cls_def_cnt + cat_def_cnt];
// }
- SymtabTy =
- llvm::StructType::create("struct._objc_symtab",
- LongTy, SelectorPtrTy, ShortTy, ShortTy,
- llvm::ArrayType::get(Int8PtrTy, 0), nullptr);
+ SymtabTy = llvm::StructType::create("struct._objc_symtab", LongTy,
+ SelectorPtrTy, ShortTy, ShortTy,
+ llvm::ArrayType::get(Int8PtrTy, 0));
SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
// struct _objc_module {
@@ -5705,10 +5719,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *name;
// struct _objc_symtab* symtab;
// }
- ModuleTy =
- llvm::StructType::create("struct._objc_module",
- LongTy, LongTy, Int8PtrTy, SymtabPtrTy, nullptr);
-
+ ModuleTy = llvm::StructType::create("struct._objc_module", LongTy, LongTy,
+ Int8PtrTy, SymtabPtrTy);
// FIXME: This is the size of the setjmp buffer and should be target
// specific. 18 is what's used on 32-bit X86.
@@ -5717,10 +5729,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// Exceptions
llvm::Type *StackPtrTy = llvm::ArrayType::get(CGM.Int8PtrTy, 4);
- ExceptionDataTy =
- llvm::StructType::create("struct._objc_exception_data",
- llvm::ArrayType::get(CGM.Int32Ty,SetJmpBufferSize),
- StackPtrTy, nullptr);
+ ExceptionDataTy = llvm::StructType::create(
+ "struct._objc_exception_data",
+ llvm::ArrayType::get(CGM.Int32Ty, SetJmpBufferSize), StackPtrTy);
}
ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
@@ -5731,8 +5742,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _objc_method method_list[method_count];
// }
MethodListnfABITy =
- llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
- llvm::ArrayType::get(MethodTy, 0), nullptr);
+ llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
+ llvm::ArrayType::get(MethodTy, 0));
// struct method_list_t *
MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
@@ -5756,14 +5767,12 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
ProtocolListnfABITy =
llvm::StructType::create(VMContext, "struct._objc_protocol_list");
- ProtocolnfABITy =
- llvm::StructType::create("struct._protocol_t", ObjectPtrTy, Int8PtrTy,
- llvm::PointerType::getUnqual(ProtocolListnfABITy),
- MethodListnfABIPtrTy, MethodListnfABIPtrTy,
- MethodListnfABIPtrTy, MethodListnfABIPtrTy,
- PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy,
- Int8PtrTy, PropertyListPtrTy,
- nullptr);
+ ProtocolnfABITy = llvm::StructType::create(
+ "struct._protocol_t", ObjectPtrTy, Int8PtrTy,
+ llvm::PointerType::getUnqual(ProtocolListnfABITy), MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy,
+ PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy, Int8PtrTy,
+ PropertyListPtrTy);
// struct _protocol_t*
ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
@@ -5773,8 +5782,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _protocol_t *[protocol_count];
// }
ProtocolListnfABITy->setBody(LongTy,
- llvm::ArrayType::get(ProtocolnfABIPtrTy, 0),
- nullptr);
+ llvm::ArrayType::get(ProtocolnfABIPtrTy, 0));
// struct _objc_protocol_list*
ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
@@ -5788,7 +5796,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
IvarnfABITy = llvm::StructType::create(
"struct._ivar_t", llvm::PointerType::getUnqual(IvarOffsetVarTy),
- Int8PtrTy, Int8PtrTy, IntTy, IntTy, nullptr);
+ Int8PtrTy, Int8PtrTy, IntTy, IntTy);
// struct _ivar_list_t {
// uint32 entsize; // sizeof(struct _ivar_t)
@@ -5796,8 +5804,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _iver_t list[count];
// }
IvarListnfABITy =
- llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
- llvm::ArrayType::get(IvarnfABITy, 0), nullptr);
+ llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
+ llvm::ArrayType::get(IvarnfABITy, 0));
IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
@@ -5816,13 +5824,10 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
// FIXME. Add 'reserved' field in 64bit abi mode!
- ClassRonfABITy = llvm::StructType::create("struct._class_ro_t",
- IntTy, IntTy, IntTy, Int8PtrTy,
- Int8PtrTy, MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- IvarListnfABIPtrTy,
- Int8PtrTy, PropertyListPtrTy,
- nullptr);
+ ClassRonfABITy = llvm::StructType::create(
+ "struct._class_ro_t", IntTy, IntTy, IntTy, Int8PtrTy, Int8PtrTy,
+ MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, IvarListnfABIPtrTy,
+ Int8PtrTy, PropertyListPtrTy);
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
@@ -5839,11 +5844,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t");
ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
- llvm::PointerType::getUnqual(ClassnfABITy),
- CachePtrTy,
+ llvm::PointerType::getUnqual(ClassnfABITy), CachePtrTy,
llvm::PointerType::getUnqual(ImpnfABITy),
- llvm::PointerType::getUnqual(ClassRonfABITy),
- nullptr);
+ llvm::PointerType::getUnqual(ClassRonfABITy));
// LLVM for struct _class_t *
ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
@@ -5858,15 +5861,10 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const struct _prop_list_t * const class_properties;
// const uint32_t size;
// }
- CategorynfABITy = llvm::StructType::create("struct._category_t",
- Int8PtrTy, ClassnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- PropertyListPtrTy,
- PropertyListPtrTy,
- IntTy,
- nullptr);
+ CategorynfABITy = llvm::StructType::create(
+ "struct._category_t", Int8PtrTy, ClassnfABIPtrTy, MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, PropertyListPtrTy,
+ PropertyListPtrTy, IntTy);
// New types for nonfragile abi messaging.
CodeGen::CodeGenTypes &Types = CGM.getTypes();
@@ -5903,9 +5901,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// SUPER_IMP messenger;
// SEL name;
// };
- SuperMessageRefTy =
- llvm::StructType::create("struct._super_message_ref_t",
- ImpnfABITy, SelectorPtrTy, nullptr);
+ SuperMessageRefTy = llvm::StructType::create("struct._super_message_ref_t",
+ ImpnfABITy, SelectorPtrTy);
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
@@ -5916,10 +5913,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const char* name; // c++ typeinfo string
// Class cls;
// };
- EHTypeTy =
- llvm::StructType::create("struct._objc_typeinfo",
- llvm::PointerType::getUnqual(Int8PtrTy),
- Int8PtrTy, ClassnfABIPtrTy, nullptr);
+ EHTypeTy = llvm::StructType::create("struct._objc_typeinfo",
+ llvm::PointerType::getUnqual(Int8PtrTy),
+ Int8PtrTy, ClassnfABIPtrTy);
EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
}
@@ -5974,17 +5970,21 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
}
AddModuleClassList(DefinedClasses, "OBJC_LABEL_CLASS_$",
- "__DATA, __objc_classlist, regular, no_dead_strip");
+ GetSectionName("__objc_classlist",
+ "regular,no_dead_strip"));
AddModuleClassList(DefinedNonLazyClasses, "OBJC_LABEL_NONLAZY_CLASS_$",
- "__DATA, __objc_nlclslist, regular, no_dead_strip");
+ GetSectionName("__objc_nlclslist",
+ "regular,no_dead_strip"));
// Build list of all implemented category addresses in array
// L_OBJC_LABEL_CATEGORY_$.
AddModuleClassList(DefinedCategories, "OBJC_LABEL_CATEGORY_$",
- "__DATA, __objc_catlist, regular, no_dead_strip");
+ GetSectionName("__objc_catlist",
+ "regular,no_dead_strip"));
AddModuleClassList(DefinedNonLazyCategories, "OBJC_LABEL_NONLAZY_CATEGORY_$",
- "__DATA, __objc_nlcatlist, regular, no_dead_strip");
+ GetSectionName("__objc_nlcatlist",
+ "regular,no_dead_strip"));
EmitImageInfo();
}
@@ -6397,15 +6397,15 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
return CGF.Builder.CreateAlignedLoad(PTGV, Align);
- PTGV = new llvm::GlobalVariable(
- CGM.getModule(),
- Init->getType(), false,
- llvm::GlobalValue::WeakAnyLinkage,
- Init,
- ProtocolName);
- PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
+ PTGV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
+ llvm::GlobalValue::WeakAnyLinkage, Init,
+ ProtocolName);
+ PTGV->setSection(GetSectionName("__objc_protorefs",
+ "coalesced,no_dead_strip"));
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
PTGV->setAlignment(Align.getQuantity());
+ if (!CGM.getTriple().isOSBinFormatMachO())
+ PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName));
CGM.addCompilerUsedGlobal(PTGV);
return CGF.Builder.CreateAlignedLoad(PTGV, Align);
}
@@ -6620,10 +6620,14 @@ CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
Ivar->getAccessControl() == ObjCIvarDecl::Private ||
Ivar->getAccessControl() == ObjCIvarDecl::Package;
- if (ID->hasAttr<DLLExportAttr>() && !IsPrivateOrPackage)
- IvarOffsetGV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- else if (ID->hasAttr<DLLImportAttr>())
- IvarOffsetGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ const ObjCInterfaceDecl *ContainingID = Ivar->getContainingInterface();
+
+ if (ContainingID->hasAttr<DLLImportAttr>())
+ IvarOffsetGV
+ ->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (ContainingID->hasAttr<DLLExportAttr>() && !IsPrivateOrPackage)
+ IvarOffsetGV
+ ->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
}
}
return IvarOffsetGV;
@@ -6862,8 +6866,8 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef));
PTGV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
- if (CGM.getTriple().isOSBinFormatMachO())
- PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
+ PTGV->setSection(GetSectionName("__objc_protolist",
+ "coalesced,no_dead_strip"));
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.addCompilerUsedGlobal(PTGV);
return Entry;
@@ -7059,7 +7063,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
/*constant*/ false,
llvm::GlobalValue::WeakAnyLinkage);
messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
- messageRef->setSection("__DATA, __objc_msgrefs, coalesced");
+ messageRef->setSection(GetSectionName("__objc_msgrefs", "coalesced"));
}
bool requiresnullCheck = false;
@@ -7089,7 +7093,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
CGCallee callee(CGCalleeInfo(), calleePtr);
RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
- return nullReturn.complete(CGF, result, resultType, formalArgs,
+ return nullReturn.complete(CGF, returnSlot, result, resultType, formalArgs,
requiresnullCheck ? method : nullptr);
}
@@ -7170,7 +7174,8 @@ CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
false, llvm::GlobalValue::PrivateLinkage,
ClassGV, "OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(Align.getQuantity());
- Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_classrefs",
+ "regular,no_dead_strip"));
CGM.addCompilerUsedGlobal(Entry);
}
return CGF.Builder.CreateAlignedLoad(Entry, Align);
@@ -7204,7 +7209,8 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
false, llvm::GlobalValue::PrivateLinkage,
ClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(Align.getQuantity());
- Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_superrefs",
+ "regular,no_dead_strip"));
CGM.addCompilerUsedGlobal(Entry);
}
return CGF.Builder.CreateAlignedLoad(Entry, Align);
@@ -7226,7 +7232,8 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(Align.getQuantity());
- Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_superrefs",
+ "regular,no_dead_strip"));
CGM.addCompilerUsedGlobal(Entry);
}
@@ -7322,7 +7329,8 @@ Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF,
false, llvm::GlobalValue::PrivateLinkage,
Casted, "OBJC_SELECTOR_REFERENCES_");
Entry->setExternallyInitialized(true);
- Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_selrefs",
+ "literal_pointers,no_dead_strip"));
Entry->setAlignment(Align.getQuantity());
CGM.addCompilerUsedGlobal(Entry);
}
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 3da7ed230e..2f886fd82c 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -26,61 +26,27 @@
using namespace clang;
using namespace CodeGen;
-static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *OID,
- const ObjCImplementationDecl *ID,
- const ObjCIvarDecl *Ivar) {
- const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
-
- // FIXME: We should eliminate the need to have ObjCImplementationDecl passed
- // in here; it should never be necessary because that should be the lexical
- // decl context for the ivar.
-
- // If we know have an implementation (and the ivar is in it) then
- // look up in the implementation layout.
- const ASTRecordLayout *RL;
- if (ID && declaresSameEntity(ID->getClassInterface(), Container))
- RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
- else
- RL = &CGM.getContext().getASTObjCInterfaceLayout(Container);
-
- // Compute field index.
- //
- // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is
- // implemented. This should be fixed to get the information from the layout
- // directly.
- unsigned Index = 0;
-
- for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin();
- IVD; IVD = IVD->getNextIvar()) {
- if (Ivar == IVD)
- break;
- ++Index;
- }
- assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
-
- return RL->getFieldOffset(Index);
-}
-
uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *OID,
const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, OID, nullptr, Ivar) /
- CGM.getContext().getCharWidth();
+ return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) /
+ CGM.getContext().getCharWidth();
}
uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
const ObjCImplementationDecl *OID,
const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) /
- CGM.getContext().getCharWidth();
+ return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID,
+ Ivar) /
+ CGM.getContext().getCharWidth();
}
unsigned CGObjCRuntime::ComputeBitfieldBitOffset(
CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, ID, ID->getImplementation(), Ivar);
+ return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(),
+ Ivar);
}
LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
@@ -90,7 +56,11 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
unsigned CVRQualifiers,
llvm::Value *Offset) {
// Compute (type*) ( (char *) BaseValue + Offset)
- QualType IvarTy = Ivar->getType().withCVRQualifiers(CVRQualifiers);
+ QualType InterfaceTy{OID->getTypeForDecl(), 0};
+ QualType ObjectPtrTy =
+ CGF.CGM.getContext().getObjCObjectPointerType(InterfaceTy);
+ QualType IvarTy =
+ Ivar->getUsageType(ObjectPtrTy).withCVRQualifiers(CVRQualifiers);
llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy);
V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
@@ -115,7 +85,8 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// Note, there is a subtle invariant here: we can only call this routine on
// non-synthesized ivars but we may be called for synthesized ivars. However,
// a synthesized ivar can never be a bit-field, so this is safe.
- uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, nullptr, Ivar);
+ uint64_t FieldBitOffset =
+ CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar);
uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign();
uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
@@ -138,7 +109,9 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
Addr = CGF.Builder.CreateElementBitCast(Addr,
llvm::Type::getIntNTy(CGF.getLLVMContext(),
Info->StorageSize));
- return LValue::MakeBitfield(Addr, *Info, IvarTy, AlignmentSource::Decl);
+ return LValue::MakeBitfield(Addr, *Info, IvarTy,
+ LValueBaseInfo(AlignmentSource::Decl),
+ TBAAAccessInfo());
}
namespace {
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index db02c631c9..4d637615d2 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -16,6 +16,7 @@
#include "CGOpenCLRuntime.h"
#include "CodeGenFunction.h"
#include "TargetInfo.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
#include <assert.h>
@@ -35,8 +36,8 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
"Not an OpenCL specific type!");
llvm::LLVMContext& Ctx = CGM.getLLVMContext();
- uint32_t ImgAddrSpc = CGM.getContext().getTargetAddressSpace(
- CGM.getTarget().getOpenCLImageAddrSpace());
+ uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
+ CGM.getTarget().getOpenCLTypeAddrSpace(T));
switch (cast<BuiltinType>(T)->getKind()) {
default:
llvm_unreachable("Unexpected opencl builtin type!");
@@ -45,29 +46,29 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
case BuiltinType::Id: \
return llvm::PointerType::get( \
llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \
- ImgAddrSpc);
+ AddrSpc);
#include "clang/Basic/OpenCLImageTypes.def"
case BuiltinType::OCLSampler:
- return getSamplerType();
+ return getSamplerType(T);
case BuiltinType::OCLEvent:
- return llvm::PointerType::get(llvm::StructType::create(
- Ctx, "opencl.event_t"), 0);
+ return llvm::PointerType::get(
+ llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc);
case BuiltinType::OCLClkEvent:
return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.clk_event_t"), 0);
+ llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc);
case BuiltinType::OCLQueue:
return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.queue_t"), 0);
+ llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc);
case BuiltinType::OCLReserveID:
return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.reserve_id_t"), 0);
+ llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc);
}
}
-llvm::Type *CGOpenCLRuntime::getPipeType() {
+llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
if (!PipeTy){
- uint32_t PipeAddrSpc =
- CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
+ uint32_t PipeAddrSpc = CGM.getContext().getTargetAddressSpace(
+ CGM.getTarget().getOpenCLTypeAddrSpace(T));
PipeTy = llvm::PointerType::get(llvm::StructType::create(
CGM.getLLVMContext(), "opencl.pipe_t"), PipeAddrSpc);
}
@@ -75,12 +76,12 @@ llvm::Type *CGOpenCLRuntime::getPipeType() {
return PipeTy;
}
-llvm::PointerType *CGOpenCLRuntime::getSamplerType() {
+llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
if (!SamplerTy)
SamplerTy = llvm::PointerType::get(llvm::StructType::create(
CGM.getLLVMContext(), "opencl.sampler_t"),
CGM.getContext().getTargetAddressSpace(
- LangAS::opencl_constant));
+ CGM.getTarget().getOpenCLTypeAddrSpace(T)));
return SamplerTy;
}
@@ -103,3 +104,45 @@ llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
.getQuantity();
return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
}
+
+llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
+ assert(CGM.getLangOpts().OpenCL);
+ return llvm::IntegerType::getInt8PtrTy(
+ CGM.getLLVMContext(),
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
+}
+
+CGOpenCLRuntime::EnqueuedBlockInfo
+CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
+ // The block literal may be assigned to a const variable. Chasing down
+ // to get the block literal.
+ if (auto DR = dyn_cast<DeclRefExpr>(E)) {
+ E = cast<VarDecl>(DR->getDecl())->getInit();
+ }
+ if (auto Cast = dyn_cast<CastExpr>(E)) {
+ E = Cast->getSubExpr();
+ }
+ auto *Block = cast<BlockExpr>(E);
+
+ // The same block literal may be enqueued multiple times. Cache it if
+ // possible.
+ auto Loc = EnqueuedBlockMap.find(Block);
+ if (Loc != EnqueuedBlockMap.end()) {
+ return Loc->second;
+ }
+
+ // Emit block literal as a common block expression and get the block invoke
+ // function.
+ llvm::Function *Invoke;
+ auto *V = CGF.EmitBlockLiteral(cast<BlockExpr>(Block), &Invoke);
+ auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
+ CGF, Invoke, V->stripPointerCasts());
+
+ // The common part of the post-processing of the kernel goes here.
+ F->addFnAttr(llvm::Attribute::NoUnwind);
+ F->setCallingConv(
+ CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
+ EnqueuedBlockInfo Info{F, V};
+ EnqueuedBlockMap[Block] = Info;
+ return Info;
+}
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index ee3cb3dda0..ead303d1d0 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -17,11 +17,13 @@
#define LLVM_CLANG_LIB_CODEGEN_CGOPENCLRUNTIME_H
#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
namespace clang {
+class Expr;
class VarDecl;
namespace CodeGen {
@@ -35,6 +37,14 @@ protected:
llvm::Type *PipeTy;
llvm::PointerType *SamplerTy;
+ /// Structure for enqueued block information.
+ struct EnqueuedBlockInfo {
+ llvm::Function *Kernel; /// Enqueued block kernel.
+ llvm::Value *BlockArg; /// The first argument to enqueued block kernel.
+ };
+ /// Maps block expression to block information.
+ llvm::DenseMap<const Expr *, EnqueuedBlockInfo> EnqueuedBlockMap;
+
public:
CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM), PipeTy(nullptr),
SamplerTy(nullptr) {}
@@ -48,9 +58,9 @@ public:
virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
- virtual llvm::Type *getPipeType();
+ virtual llvm::Type *getPipeType(const PipeType *T);
- llvm::PointerType *getSamplerType();
+ llvm::PointerType *getSamplerType(const Type *T);
// \brief Returnes a value which indicates the size in bytes of the pipe
// element.
@@ -59,6 +69,13 @@ public:
// \brief Returnes a value which indicates the alignment in bytes of the pipe
// element.
virtual llvm::Value *getPipeElemAlign(const Expr *PipeArg);
+
+ /// \return __generic void* type.
+ llvm::PointerType *getGenericVoidPointerType();
+
+ /// \return enqueued block information for enqueued block.
+ EnqueuedBlockInfo emitOpenCLEnqueuedBlock(CodeGenFunction &CGF,
+ const Expr *E);
};
}
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index ae9cf9dc59..35929af95e 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/StmtOpenMP.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DerivedTypes.h"
@@ -264,6 +265,13 @@ public:
return nullptr;
}
+ /// \brief Get an LValue for the current ThreadID variable.
+ LValue getThreadIDVariableLValue(CodeGenFunction &CGF) override {
+ if (OuterRegionInfo)
+ return OuterRegionInfo->getThreadIDVariableLValue(CGF);
+ llvm_unreachable("No LValue for inlined OpenMP construct");
+ }
+
/// \brief Get the name of the capture helper.
StringRef getHelperName() const override {
if (auto *OuterRegionInfo = getOldCSI())
@@ -420,7 +428,7 @@ public:
/// \brief Values for bit flags used in the ident_t to describe the fields.
/// All enumeric elements are named and described in accordance with the code
/// from http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h
-enum OpenMPLocationFlags {
+enum OpenMPLocationFlags : unsigned {
/// \brief Use trampoline for internal microtask.
OMP_IDENT_IMD = 0x01,
/// \brief Use c-style ident structure.
@@ -436,7 +444,14 @@ enum OpenMPLocationFlags {
/// \brief Implicit barrier in 'sections' directive.
OMP_IDENT_BARRIER_IMPL_SECTIONS = 0xC0,
/// \brief Implicit barrier in 'single' directive.
- OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140
+ OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140,
+ /// Call of __kmp_for_static_init for static loop.
+ OMP_IDENT_WORK_LOOP = 0x200,
+ /// Call of __kmp_for_static_init for sections.
+ OMP_IDENT_WORK_SECTIONS = 0x400,
+ /// Call of __kmp_for_static_init for distribute.
+ OMP_IDENT_WORK_DISTRIBUTE = 0x800,
+ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_IDENT_WORK_DISTRIBUTE)
};
/// \brief Describes ident structure that describes a source location.
@@ -643,6 +658,12 @@ enum OpenMPRTLFunction {
// Call to void __kmpc_doacross_wait(ident_t *loc, kmp_int32 gtid, kmp_int64
// *vec);
OMPRTL__kmpc_doacross_wait,
+ // Call to void *__kmpc_task_reduction_init(int gtid, int num_data, void
+ // *data);
+ OMPRTL__kmpc_task_reduction_init,
+ // Call to void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
+ // *d);
+ OMPRTL__kmpc_task_reduction_get_th_data,
//
// Offloading related calls
@@ -697,6 +718,409 @@ void RegionCodeGenTy::operator()(CodeGenFunction &CGF) const {
}
}
+/// Check if the combiner is a call to UDR combiner and if it is so return the
+/// UDR decl used for reduction.
+static const OMPDeclareReductionDecl *
+getReductionInit(const Expr *ReductionOp) {
+ if (auto *CE = dyn_cast<CallExpr>(ReductionOp))
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
+ if (auto *DRE =
+ dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
+ if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
+ return DRD;
+ return nullptr;
+}
+
+static void emitInitWithReductionInitializer(CodeGenFunction &CGF,
+ const OMPDeclareReductionDecl *DRD,
+ const Expr *InitOp,
+ Address Private, Address Original,
+ QualType Ty) {
+ if (DRD->getInitializer()) {
+ std::pair<llvm::Function *, llvm::Function *> Reduction =
+ CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
+ auto *CE = cast<CallExpr>(InitOp);
+ auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
+ const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
+ const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
+ auto *LHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
+ auto *RHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()),
+ [=]() -> Address { return Private; });
+ PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()),
+ [=]() -> Address { return Original; });
+ (void)PrivateScope.Privatize();
+ RValue Func = RValue::get(Reduction.second);
+ CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
+ CGF.EmitIgnoredExpr(InitOp);
+ } else {
+ llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
+ auto *GV = new llvm::GlobalVariable(
+ CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Init, ".init");
+ LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty);
+ RValue InitRVal;
+ switch (CGF.getEvaluationKind(Ty)) {
+ case TEK_Scalar:
+ InitRVal = CGF.EmitLoadOfLValue(LV, SourceLocation());
+ break;
+ case TEK_Complex:
+ InitRVal =
+ RValue::getComplex(CGF.EmitLoadOfComplex(LV, SourceLocation()));
+ break;
+ case TEK_Aggregate:
+ InitRVal = RValue::getAggregate(LV.getAddress());
+ break;
+ }
+ OpaqueValueExpr OVE(SourceLocation(), Ty, VK_RValue);
+ CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
+ CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+}
+
+/// \brief Emit initialization of arrays of complex types.
+/// \param DestAddr Address of the array.
+/// \param Type Type of array.
+/// \param Init Initial expression of array.
+/// \param SrcAddr Address of the original array.
+static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
+ QualType Type, bool EmitDeclareReductionInit,
+ const Expr *Init,
+ const OMPDeclareReductionDecl *DRD,
+ Address SrcAddr = Address::invalid()) {
+ // Perform element-by-element initialization.
+ QualType ElementTy;
+
+ // Drill down to the base element type on both arrays.
+ auto ArrayTy = Type->getAsArrayTypeUnsafe();
+ auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
+ DestAddr =
+ CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType());
+ if (DRD)
+ SrcAddr =
+ CGF.Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
+
+ llvm::Value *SrcBegin = nullptr;
+ if (DRD)
+ SrcBegin = SrcAddr.getPointer();
+ auto DestBegin = DestAddr.getPointer();
+ // Cast from pointer to array type to pointer to single element.
+ auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements);
+ // The basic structure here is a while-do loop.
+ auto BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
+ auto DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
+ auto IsEmpty =
+ CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
+ CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
+
+ // Enter the loop body, making that address the current address.
+ auto EntryBB = CGF.Builder.GetInsertBlock();
+ CGF.EmitBlock(BodyBB);
+
+ CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
+
+ llvm::PHINode *SrcElementPHI = nullptr;
+ Address SrcElementCurrent = Address::invalid();
+ if (DRD) {
+ SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
+ "omp.arraycpy.srcElementPast");
+ SrcElementPHI->addIncoming(SrcBegin, EntryBB);
+ SrcElementCurrent =
+ Address(SrcElementPHI,
+ SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
+ }
+ llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
+ DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
+ DestElementPHI->addIncoming(DestBegin, EntryBB);
+ Address DestElementCurrent =
+ Address(DestElementPHI,
+ DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
+
+ // Emit copy.
+ {
+ CodeGenFunction::RunCleanupsScope InitScope(CGF);
+ if (EmitDeclareReductionInit) {
+ emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
+ SrcElementCurrent, ElementTy);
+ } else
+ CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+
+ if (DRD) {
+ // Shift the address forward by one element.
+ auto SrcElementNext = CGF.Builder.CreateConstGEP1_32(
+ SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
+ SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
+ }
+
+ // Shift the address forward by one element.
+ auto DestElementNext = CGF.Builder.CreateConstGEP1_32(
+ DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
+ // Check whether we've reached the end.
+ auto Done =
+ CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
+ CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
+ DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
+
+ // Done.
+ CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
+}
+
+LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) {
+ return CGF.EmitOMPSharedLValue(E);
+}
+
+LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF,
+ const Expr *E) {
+ if (const auto *OASE = dyn_cast<OMPArraySectionExpr>(E))
+ return CGF.EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false);
+ return LValue();
+}
+
+void ReductionCodeGen::emitAggregateInitialization(
+ CodeGenFunction &CGF, unsigned N, Address PrivateAddr, LValue SharedLVal,
+ const OMPDeclareReductionDecl *DRD) {
+ // Emit VarDecl with copy init for arrays.
+ // Get the address of the original variable captured in current
+ // captured region.
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ bool EmitDeclareReductionInit =
+ DRD && (DRD->getInitializer() || !PrivateVD->hasInit());
+ EmitOMPAggregateInit(CGF, PrivateAddr, PrivateVD->getType(),
+ EmitDeclareReductionInit,
+ EmitDeclareReductionInit ? ClausesData[N].ReductionOp
+ : PrivateVD->getInit(),
+ DRD, SharedLVal.getAddress());
+}
+
+ReductionCodeGen::ReductionCodeGen(ArrayRef<const Expr *> Shareds,
+ ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> ReductionOps) {
+ ClausesData.reserve(Shareds.size());
+ SharedAddresses.reserve(Shareds.size());
+ Sizes.reserve(Shareds.size());
+ BaseDecls.reserve(Shareds.size());
+ auto IPriv = Privates.begin();
+ auto IRed = ReductionOps.begin();
+ for (const auto *Ref : Shareds) {
+ ClausesData.emplace_back(Ref, *IPriv, *IRed);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ }
+}
+
+void ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, unsigned N) {
+ assert(SharedAddresses.size() == N &&
+ "Number of generated lvalues must be exactly N.");
+ LValue First = emitSharedLValue(CGF, ClausesData[N].Ref);
+ LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Ref);
+ SharedAddresses.emplace_back(First, Second);
+}
+
+void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ bool AsArraySection = isa<OMPArraySectionExpr>(ClausesData[N].Ref);
+ if (!PrivateType->isVariablyModifiedType()) {
+ Sizes.emplace_back(
+ CGF.getTypeSize(
+ SharedAddresses[N].first.getType().getNonReferenceType()),
+ nullptr);
+ return;
+ }
+ llvm::Value *Size;
+ llvm::Value *SizeInChars;
+ llvm::Type *ElemType =
+ cast<llvm::PointerType>(SharedAddresses[N].first.getPointer()->getType())
+ ->getElementType();
+ auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType);
+ if (AsArraySection) {
+ Size = CGF.Builder.CreatePtrDiff(SharedAddresses[N].second.getPointer(),
+ SharedAddresses[N].first.getPointer());
+ Size = CGF.Builder.CreateNUWAdd(
+ Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
+ SizeInChars = CGF.Builder.CreateNUWMul(Size, ElemSizeOf);
+ } else {
+ SizeInChars = CGF.getTypeSize(
+ SharedAddresses[N].first.getType().getNonReferenceType());
+ Size = CGF.Builder.CreateExactUDiv(SizeInChars, ElemSizeOf);
+ }
+ Sizes.emplace_back(SizeInChars, Size);
+ CodeGenFunction::OpaqueValueMapping OpaqueMap(
+ CGF,
+ cast<OpaqueValueExpr>(
+ CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
+ RValue::get(Size));
+ CGF.EmitVariablyModifiedType(PrivateType);
+}
+
+void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N,
+ llvm::Value *Size) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ if (!PrivateType->isVariablyModifiedType()) {
+ assert(!Size && !Sizes[N].second &&
+ "Size should be nullptr for non-variably modified reduction "
+ "items.");
+ return;
+ }
+ CodeGenFunction::OpaqueValueMapping OpaqueMap(
+ CGF,
+ cast<OpaqueValueExpr>(
+ CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
+ RValue::get(Size));
+ CGF.EmitVariablyModifiedType(PrivateType);
+}
+
+void ReductionCodeGen::emitInitialization(
+ CodeGenFunction &CGF, unsigned N, Address PrivateAddr, LValue SharedLVal,
+ llvm::function_ref<bool(CodeGenFunction &)> DefaultInit) {
+ assert(SharedAddresses.size() > N && "No variable was generated");
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ auto *DRD = getReductionInit(ClausesData[N].ReductionOp);
+ QualType PrivateType = PrivateVD->getType();
+ PrivateAddr = CGF.Builder.CreateElementBitCast(
+ PrivateAddr, CGF.ConvertTypeForMem(PrivateType));
+ QualType SharedType = SharedAddresses[N].first.getType();
+ SharedLVal = CGF.MakeAddrLValue(
+ CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(),
+ CGF.ConvertTypeForMem(SharedType)),
+ SharedType, SharedAddresses[N].first.getBaseInfo(),
+ CGF.CGM.getTBAAInfoForSubobject(SharedAddresses[N].first, SharedType));
+ if (CGF.getContext().getAsArrayType(PrivateVD->getType())) {
+ emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD);
+ } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
+ emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
+ PrivateAddr, SharedLVal.getAddress(),
+ SharedLVal.getType());
+ } else if (!DefaultInit(CGF) && PrivateVD->hasInit() &&
+ !CGF.isTrivialInitializer(PrivateVD->getInit())) {
+ CGF.EmitAnyExprToMem(PrivateVD->getInit(), PrivateAddr,
+ PrivateVD->getType().getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+}
+
+bool ReductionCodeGen::needCleanups(unsigned N) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
+ return DTorKind != QualType::DK_none;
+}
+
+void ReductionCodeGen::emitCleanups(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
+ if (needCleanups(N)) {
+ PrivateAddr = CGF.Builder.CreateElementBitCast(
+ PrivateAddr, CGF.ConvertTypeForMem(PrivateType));
+ CGF.pushDestroy(DTorKind, PrivateAddr, PrivateType);
+ }
+}
+
+static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
+ LValue BaseLV) {
+ BaseTy = BaseTy.getNonReferenceType();
+ while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
+ !CGF.getContext().hasSameType(BaseTy, ElTy)) {
+ if (auto *PtrTy = BaseTy->getAs<PointerType>())
+ BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
+ else {
+ LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy);
+ BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal);
+ }
+ BaseTy = BaseTy->getPointeeType();
+ }
+ return CGF.MakeAddrLValue(
+ CGF.Builder.CreateElementBitCast(BaseLV.getAddress(),
+ CGF.ConvertTypeForMem(ElTy)),
+ BaseLV.getType(), BaseLV.getBaseInfo(),
+ CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType()));
+}
+
+static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
+ llvm::Type *BaseLVType, CharUnits BaseLVAlignment,
+ llvm::Value *Addr) {
+ Address Tmp = Address::invalid();
+ Address TopTmp = Address::invalid();
+ Address MostTopTmp = Address::invalid();
+ BaseTy = BaseTy.getNonReferenceType();
+ while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
+ !CGF.getContext().hasSameType(BaseTy, ElTy)) {
+ Tmp = CGF.CreateMemTemp(BaseTy);
+ if (TopTmp.isValid())
+ CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
+ else
+ MostTopTmp = Tmp;
+ TopTmp = Tmp;
+ BaseTy = BaseTy->getPointeeType();
+ }
+ llvm::Type *Ty = BaseLVType;
+ if (Tmp.isValid())
+ Ty = Tmp.getElementType();
+ Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Ty);
+ if (Tmp.isValid()) {
+ CGF.Builder.CreateStore(Addr, Tmp);
+ return MostTopTmp;
+ }
+ return Address(Addr, BaseLVAlignment);
+}
+
+Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr) {
+ const DeclRefExpr *DE;
+ const VarDecl *OrigVD = nullptr;
+ if (auto *OASE = dyn_cast<OMPArraySectionExpr>(ClausesData[N].Ref)) {
+ auto *Base = OASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
+ Base = TempOASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ DE = cast<DeclRefExpr>(Base);
+ OrigVD = cast<VarDecl>(DE->getDecl());
+ } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(ClausesData[N].Ref)) {
+ auto *Base = ASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ DE = cast<DeclRefExpr>(Base);
+ OrigVD = cast<VarDecl>(DE->getDecl());
+ }
+ if (OrigVD) {
+ BaseDecls.emplace_back(OrigVD);
+ auto OriginalBaseLValue = CGF.EmitLValue(DE);
+ LValue BaseLValue =
+ loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(),
+ OriginalBaseLValue);
+ llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
+ BaseLValue.getPointer(), SharedAddresses[N].first.getPointer());
+ llvm::Value *Ptr =
+ CGF.Builder.CreateGEP(PrivateAddr.getPointer(), Adjustment);
+ return castToBase(CGF, OrigVD->getType(),
+ SharedAddresses[N].first.getType(),
+ OriginalBaseLValue.getPointer()->getType(),
+ OriginalBaseLValue.getAlignment(), Ptr);
+ }
+ BaseDecls.emplace_back(
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Ref)->getDecl()));
+ return PrivateAddr;
+}
+
+bool ReductionCodeGen::usesReductionInitializer(unsigned N) const {
+ auto *DRD = getReductionInit(ClausesData[N].ReductionOp);
+ return DRD && DRD->getInitializer();
+}
+
LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
return CGF.EmitLoadOfPointerLValue(
CGF.GetAddrOfLocalVar(getThreadIDVariable()),
@@ -728,7 +1152,7 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
IdentTy = llvm::StructType::create(
"ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
- CGM.Int8PtrTy /* psource */, nullptr);
+ CGM.Int8PtrTy /* psource */);
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
loadOffloadInfoMetadata();
@@ -747,9 +1171,9 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
QualType PtrTy = C.getPointerType(Ty).withRestrict();
FunctionArgList Args;
ImplicitParamDecl OmpOutParm(C, /*DC=*/nullptr, Out->getLocation(),
- /*Id=*/nullptr, PtrTy);
+ /*Id=*/nullptr, PtrTy, ImplicitParamDecl::Other);
ImplicitParamDecl OmpInParm(C, /*DC=*/nullptr, In->getLocation(),
- /*Id=*/nullptr, PtrTy);
+ /*Id=*/nullptr, PtrTy, ImplicitParamDecl::Other);
Args.push_back(&OmpOutParm);
Args.push_back(&OmpInParm);
auto &FnInfo =
@@ -760,6 +1184,7 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
IsCombiner ? ".omp_combiner." : ".omp_initializer.", &CGM.getModule());
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
Fn->removeFnAttr(llvm::Attribute::NoInline);
+ Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
Fn->addFnAttr(llvm::Attribute::AlwaysInline);
CodeGenFunction CGF(CGM);
// Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
@@ -777,7 +1202,14 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
.getAddress();
});
(void)Scope.Privatize();
- CGF.EmitIgnoredExpr(CombinerInitializer);
+ if (!IsCombiner && Out->hasInit() &&
+ !CGF.isTrivialInitializer(Out->getInit())) {
+ CGF.EmitAnyExprToMem(Out->getInit(), CGF.GetAddrOfLocalVar(Out),
+ Out->getType().getQualifiers(),
+ /*IsInitializer=*/true);
+ }
+ if (CombinerInitializer)
+ CGF.EmitIgnoredExpr(CombinerInitializer);
Scope.ForceCleanup();
CGF.FinishFunction();
return Fn;
@@ -803,7 +1235,10 @@ void CGOpenMPRuntime::emitUserDefinedReduction(
Orig = &C.Idents.get("omp_orig");
}
Initializer = emitCombinerOrInitializer(
- CGM, D->getType(), Init, cast<VarDecl>(D->lookup(Orig).front()),
+ CGM, D->getType(),
+ D->getInitializerKind() == OMPDeclareReductionDecl::CallInit ? Init
+ : nullptr,
+ cast<VarDecl>(D->lookup(Orig).front()),
cast<VarDecl>(D->lookup(Priv).front()),
/*IsCombiner=*/false);
}
@@ -1015,19 +1450,22 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
if (ThreadID != nullptr)
return ThreadID;
}
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- if (OMPRegionInfo->getThreadIDVariable()) {
- // Check if this an outlined function with thread id passed as argument.
- auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
- ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal();
- // If value loaded in entry block, cache it and use it everywhere in
- // function.
- if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
- auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
- Elem.second.ThreadID = ThreadID;
+ // If exceptions are enabled, do not use parameter to avoid possible crash.
+ if (!CGF.getInvokeDest()) {
+ if (auto *OMPRegionInfo =
+ dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
+ if (OMPRegionInfo->getThreadIDVariable()) {
+ // Check if this an outlined function with thread id passed as argument.
+ auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
+ ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal();
+ // If value loaded in entry block, cache it and use it everywhere in
+ // function.
+ if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
+ auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
+ Elem.second.ThreadID = ThreadID;
+ }
+ return ThreadID;
}
- return ThreadID;
}
}
@@ -1553,6 +1991,26 @@ CGOpenMPRuntime::createRuntimeFunction(unsigned Function) {
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_doacross_wait");
break;
}
+ case OMPRTL__kmpc_task_reduction_init: {
+ // Build void *__kmpc_task_reduction_init(int gtid, int num_data, void
+ // *data);
+ llvm::Type *TypeParams[] = {CGM.IntTy, CGM.IntTy, CGM.VoidPtrTy};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
+ RTLFn =
+ CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_task_reduction_init");
+ break;
+ }
+ case OMPRTL__kmpc_task_reduction_get_th_data: {
+ // Build void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
+ // *d);
+ llvm::Type *TypeParams[] = {CGM.IntTy, CGM.VoidPtrTy, CGM.VoidPtrTy};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(
+ FnTy, /*Name=*/"__kmpc_task_reduction_get_th_data");
+ break;
+ }
case OMPRTL__tgt_target: {
// Build int32_t __tgt_target(int32_t device_id, void *host_ptr, int32_t
// arg_num, void** args_base, void **args, size_t *arg_sizes, int32_t
@@ -1807,8 +2265,8 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
// threadprivate copy of the variable VD
CodeGenFunction CtorCGF(CGM);
FunctionArgList Args;
- ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, CGM.getContext().VoidPtrTy);
+ ImplicitParamDecl Dst(CGM.getContext(), CGM.getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
Args.push_back(&Dst);
auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
@@ -1838,8 +2296,8 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
// of the variable VD
CodeGenFunction DtorCGF(CGM);
FunctionArgList Args;
- ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, CGM.getContext().VoidPtrTy);
+ ImplicitParamDecl Dst(CGM.getContext(), CGM.getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
Args.push_back(&Dst);
auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
@@ -1903,6 +2361,27 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
return nullptr;
}
+Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
+ QualType VarType,
+ StringRef Name) {
+ llvm::Twine VarName(Name, ".artificial.");
+ llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
+ llvm::Value *GAddr = getOrCreateInternalVariable(VarLVType, VarName);
+ llvm::Value *Args[] = {
+ emitUpdateLocation(CGF, SourceLocation()),
+ getThreadID(CGF, SourceLocation()),
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(GAddr, CGM.VoidPtrTy),
+ CGF.Builder.CreateIntCast(CGF.getTypeSize(VarType), CGM.SizeTy,
+ /*IsSigned=*/false),
+ getOrCreateInternalVariable(CGM.VoidPtrPtrTy, VarName + ".cache.")};
+ return Address(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args),
+ VarLVType->getPointerTo(/*AddrSpace=*/0)),
+ CGM.getPointerAlign());
+}
+
/// \brief Emits code for OpenMP 'if' clause using specified \a CodeGen
/// function. Here is the logic:
/// if (Cond) {
@@ -1991,7 +2470,7 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
OutlinedFnArgs.push_back(ThreadIDAddr.getPointer());
OutlinedFnArgs.push_back(ZeroAddr.getPointer());
OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs);
+ RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
// __kmpc_end_serialized_parallel(&Loc, GTid);
llvm::Value *EndArgs[] = {RT.emitUpdateLocation(CGF, Loc), ThreadID};
@@ -2190,10 +2669,8 @@ static llvm::Value *emitCopyprivateCopyFunction(
auto &C = CGM.getContext();
// void copy_func(void *LHSArg, void *RHSArg);
FunctionArgList Args;
- ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
- ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
+ ImplicitParamDecl LHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl RHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
Args.push_back(&LHSArg);
Args.push_back(&RHSArg);
auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
@@ -2466,16 +2943,14 @@ static int addMonoNonMonoModifier(OpenMPSchedType Schedule,
return Schedule | Modifier;
}
-void CGOpenMPRuntime::emitForDispatchInit(CodeGenFunction &CGF,
- SourceLocation Loc,
- const OpenMPScheduleTy &ScheduleKind,
- unsigned IVSize, bool IVSigned,
- bool Ordered, llvm::Value *UB,
- llvm::Value *Chunk) {
+void CGOpenMPRuntime::emitForDispatchInit(
+ CodeGenFunction &CGF, SourceLocation Loc,
+ const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
+ bool Ordered, const DispatchRTInput &DispatchValues) {
if (!CGF.HaveInsertPoint())
return;
- OpenMPSchedType Schedule =
- getRuntimeSchedule(ScheduleKind.Schedule, Chunk != nullptr, Ordered);
+ OpenMPSchedType Schedule = getRuntimeSchedule(
+ ScheduleKind.Schedule, DispatchValues.Chunk != nullptr, Ordered);
assert(Ordered ||
(Schedule != OMP_sch_static && Schedule != OMP_sch_static_chunked &&
Schedule != OMP_ord_static && Schedule != OMP_ord_static_chunked &&
@@ -2486,14 +2961,14 @@ void CGOpenMPRuntime::emitForDispatchInit(CodeGenFunction &CGF,
// kmp_int[32|64] stride, kmp_int[32|64] chunk);
// If the Chunk was not specified in the clause - use default value 1.
- if (Chunk == nullptr)
- Chunk = CGF.Builder.getIntN(IVSize, 1);
+ llvm::Value *Chunk = DispatchValues.Chunk ? DispatchValues.Chunk
+ : CGF.Builder.getIntN(IVSize, 1);
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
CGF.Builder.getInt32(addMonoNonMonoModifier(
Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
- CGF.Builder.getIntN(IVSize, 0), // Lower
- UB, // Upper
+ DispatchValues.LB, // Lower
+ DispatchValues.UB, // Upper
CGF.Builder.getIntN(IVSize, 1), // Stride
Chunk // Chunk
};
@@ -2504,87 +2979,101 @@ static void emitForStaticInitCall(
CodeGenFunction &CGF, llvm::Value *UpdateLocation, llvm::Value *ThreadId,
llvm::Constant *ForStaticInitFunction, OpenMPSchedType Schedule,
OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2,
- unsigned IVSize, bool Ordered, Address IL, Address LB, Address UB,
- Address ST, llvm::Value *Chunk) {
+ const CGOpenMPRuntime::StaticRTInput &Values) {
if (!CGF.HaveInsertPoint())
- return;
-
- assert(!Ordered);
- assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked ||
- Schedule == OMP_sch_static_balanced_chunked ||
- Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked ||
- Schedule == OMP_dist_sch_static ||
- Schedule == OMP_dist_sch_static_chunked);
-
- // Call __kmpc_for_static_init(
- // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
- // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
- // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
- // kmp_int[32|64] incr, kmp_int[32|64] chunk);
- if (Chunk == nullptr) {
- assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static ||
- Schedule == OMP_dist_sch_static) &&
- "expected static non-chunked schedule");
- // If the Chunk was not specified in the clause - use default value 1.
- Chunk = CGF.Builder.getIntN(IVSize, 1);
- } else {
- assert((Schedule == OMP_sch_static_chunked ||
- Schedule == OMP_sch_static_balanced_chunked ||
- Schedule == OMP_ord_static_chunked ||
- Schedule == OMP_dist_sch_static_chunked) &&
- "expected static chunked schedule");
- }
- llvm::Value *Args[] = {
- UpdateLocation, ThreadId, CGF.Builder.getInt32(addMonoNonMonoModifier(
- Schedule, M1, M2)), // Schedule type
- IL.getPointer(), // &isLastIter
- LB.getPointer(), // &LB
- UB.getPointer(), // &UB
- ST.getPointer(), // &Stride
- CGF.Builder.getIntN(IVSize, 1), // Incr
- Chunk // Chunk
- };
- CGF.EmitRuntimeCall(ForStaticInitFunction, Args);
+ return;
+
+ assert(!Values.Ordered);
+ assert(Schedule == OMP_sch_static || Schedule == OMP_sch_static_chunked ||
+ Schedule == OMP_sch_static_balanced_chunked ||
+ Schedule == OMP_ord_static || Schedule == OMP_ord_static_chunked ||
+ Schedule == OMP_dist_sch_static ||
+ Schedule == OMP_dist_sch_static_chunked);
+
+ // Call __kmpc_for_static_init(
+ // ident_t *loc, kmp_int32 tid, kmp_int32 schedtype,
+ // kmp_int32 *p_lastiter, kmp_int[32|64] *p_lower,
+ // kmp_int[32|64] *p_upper, kmp_int[32|64] *p_stride,
+ // kmp_int[32|64] incr, kmp_int[32|64] chunk);
+ llvm::Value *Chunk = Values.Chunk;
+ if (Chunk == nullptr) {
+ assert((Schedule == OMP_sch_static || Schedule == OMP_ord_static ||
+ Schedule == OMP_dist_sch_static) &&
+ "expected static non-chunked schedule");
+ // If the Chunk was not specified in the clause - use default value 1.
+ Chunk = CGF.Builder.getIntN(Values.IVSize, 1);
+ } else {
+ assert((Schedule == OMP_sch_static_chunked ||
+ Schedule == OMP_sch_static_balanced_chunked ||
+ Schedule == OMP_ord_static_chunked ||
+ Schedule == OMP_dist_sch_static_chunked) &&
+ "expected static chunked schedule");
+ }
+ llvm::Value *Args[] = {
+ UpdateLocation,
+ ThreadId,
+ CGF.Builder.getInt32(addMonoNonMonoModifier(Schedule, M1,
+ M2)), // Schedule type
+ Values.IL.getPointer(), // &isLastIter
+ Values.LB.getPointer(), // &LB
+ Values.UB.getPointer(), // &UB
+ Values.ST.getPointer(), // &Stride
+ CGF.Builder.getIntN(Values.IVSize, 1), // Incr
+ Chunk // Chunk
+ };
+ CGF.EmitRuntimeCall(ForStaticInitFunction, Args);
}
void CGOpenMPRuntime::emitForStaticInit(CodeGenFunction &CGF,
SourceLocation Loc,
+ OpenMPDirectiveKind DKind,
const OpenMPScheduleTy &ScheduleKind,
- unsigned IVSize, bool IVSigned,
- bool Ordered, Address IL, Address LB,
- Address UB, Address ST,
- llvm::Value *Chunk) {
- OpenMPSchedType ScheduleNum =
- getRuntimeSchedule(ScheduleKind.Schedule, Chunk != nullptr, Ordered);
- auto *UpdatedLocation = emitUpdateLocation(CGF, Loc);
+ const StaticRTInput &Values) {
+ OpenMPSchedType ScheduleNum = getRuntimeSchedule(
+ ScheduleKind.Schedule, Values.Chunk != nullptr, Values.Ordered);
+ assert(isOpenMPWorksharingDirective(DKind) &&
+ "Expected loop-based or sections-based directive.");
+ auto *UpdatedLocation = emitUpdateLocation(CGF, Loc,
+ isOpenMPLoopDirective(DKind)
+ ? OMP_IDENT_WORK_LOOP
+ : OMP_IDENT_WORK_SECTIONS);
auto *ThreadId = getThreadID(CGF, Loc);
- auto *StaticInitFunction = createForStaticInitFunction(IVSize, IVSigned);
+ auto *StaticInitFunction =
+ createForStaticInitFunction(Values.IVSize, Values.IVSigned);
emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
- ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, IVSize,
- Ordered, IL, LB, UB, ST, Chunk);
+ ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, Values);
}
void CGOpenMPRuntime::emitDistributeStaticInit(
CodeGenFunction &CGF, SourceLocation Loc,
- OpenMPDistScheduleClauseKind SchedKind, unsigned IVSize, bool IVSigned,
- bool Ordered, Address IL, Address LB, Address UB, Address ST,
- llvm::Value *Chunk) {
- OpenMPSchedType ScheduleNum = getRuntimeSchedule(SchedKind, Chunk != nullptr);
- auto *UpdatedLocation = emitUpdateLocation(CGF, Loc);
+ OpenMPDistScheduleClauseKind SchedKind,
+ const CGOpenMPRuntime::StaticRTInput &Values) {
+ OpenMPSchedType ScheduleNum =
+ getRuntimeSchedule(SchedKind, Values.Chunk != nullptr);
+ auto *UpdatedLocation =
+ emitUpdateLocation(CGF, Loc, OMP_IDENT_WORK_DISTRIBUTE);
auto *ThreadId = getThreadID(CGF, Loc);
- auto *StaticInitFunction = createForStaticInitFunction(IVSize, IVSigned);
+ auto *StaticInitFunction =
+ createForStaticInitFunction(Values.IVSize, Values.IVSigned);
emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction,
ScheduleNum, OMPC_SCHEDULE_MODIFIER_unknown,
- OMPC_SCHEDULE_MODIFIER_unknown, IVSize, Ordered, IL, LB,
- UB, ST, Chunk);
+ OMPC_SCHEDULE_MODIFIER_unknown, Values);
}
void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF,
- SourceLocation Loc) {
+ SourceLocation Loc,
+ OpenMPDirectiveKind DKind) {
if (!CGF.HaveInsertPoint())
return;
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
- llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
+ llvm::Value *Args[] = {
+ emitUpdateLocation(CGF, Loc,
+ isOpenMPDistributeDirective(DKind)
+ ? OMP_IDENT_WORK_DISTRIBUTE
+ : isOpenMPLoopDirective(DKind)
+ ? OMP_IDENT_WORK_LOOP
+ : OMP_IDENT_WORK_SECTIONS),
+ getThreadID(CGF, Loc)};
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_for_static_fini),
Args);
}
@@ -2702,6 +3191,8 @@ enum KmpTaskTFields {
KmpTaskTStride,
/// (Taskloops only) Is last iteration flag.
KmpTaskTLastIter,
+ /// (Taskloops only) Reduction data.
+ KmpTaskTReductions,
};
} // anonymous namespace
@@ -2786,8 +3277,7 @@ createOffloadingBinaryDescriptorFunction(CodeGenModule &CGM, StringRef Name,
const RegionCodeGenTy &Codegen) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl DummyPtr(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.VoidPtrTy);
+ ImplicitParamDecl DummyPtr(C, C.VoidPtrTy, ImplicitParamDecl::Other);
Args.push_back(&DummyPtr);
CodeGenFunction CGF(CGM);
@@ -2890,21 +3380,34 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() {
// descriptor, so we can reuse the logic that emits Ctors and Dtors.
auto *IdentInfo = &C.Idents.get(".omp_offloading.reg_unreg_var");
ImplicitParamDecl RegUnregVar(C, C.getTranslationUnitDecl(), SourceLocation(),
- IdentInfo, C.CharTy);
+ IdentInfo, C.CharTy, ImplicitParamDecl::Other);
auto *UnRegFn = createOffloadingBinaryDescriptorFunction(
CGM, ".omp_offloading.descriptor_unreg",
[&](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitCallOrInvoke(createRuntimeFunction(OMPRTL__tgt_unregister_lib),
- Desc);
+ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_unregister_lib),
+ Desc);
});
auto *RegFn = createOffloadingBinaryDescriptorFunction(
CGM, ".omp_offloading.descriptor_reg",
[&](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitCallOrInvoke(createRuntimeFunction(OMPRTL__tgt_register_lib),
- Desc);
+ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_register_lib),
+ Desc);
CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc);
});
+ if (CGM.supportsCOMDAT()) {
+ // It is sufficient to call registration function only once, so create a
+ // COMDAT group for registration/unregistration functions and associated
+ // data. That would reduce startup time and code size. Registration
+ // function serves as a COMDAT group key.
+ auto ComdatKey = M.getOrInsertComdat(RegFn->getName());
+ RegFn->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+ RegFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ RegFn->setComdat(ComdatKey);
+ UnRegFn->setComdat(ComdatKey);
+ DeviceImages->setComdat(ComdatKey);
+ Desc->setComdat(ComdatKey);
+ }
return RegFn;
}
@@ -2974,7 +3477,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));
@@ -3241,6 +3744,7 @@ createKmpTaskTRecordDecl(CodeGenModule &CGM, OpenMPDirectiveKind Kind,
// kmp_uint64 ub;
// kmp_int64 st;
// kmp_int32 liter;
+ // void * reductions;
// };
auto *UD = C.buildImplicitRecord("kmp_cmplrdata_t", TTK_Union);
UD->startDefinition();
@@ -3264,6 +3768,7 @@ createKmpTaskTRecordDecl(CodeGenModule &CGM, OpenMPDirectiveKind Kind,
addFieldToRecordDecl(C, RD, KmpUInt64Ty);
addFieldToRecordDecl(C, RD, KmpInt64Ty);
addFieldToRecordDecl(C, RD, KmpInt32Ty);
+ addFieldToRecordDecl(C, RD, C.VoidPtrTy);
}
RD->completeDefinition();
return RD;
@@ -3294,7 +3799,7 @@ createKmpTaskTWithPrivatesRecordDecl(CodeGenModule &CGM, QualType KmpTaskTQTy,
/// TaskFunction(gtid, tt->part_id, &tt->privates, task_privates_map, tt,
/// For taskloops:
/// tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
-/// tt->shareds);
+/// tt->reductions, tt->shareds);
/// return 0;
/// }
/// \endcode
@@ -3307,10 +3812,11 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
llvm::Value *TaskPrivatesMap) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty);
- ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy.withRestrict());
+ ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy.withRestrict(),
+ ImplicitParamDecl::Other);
Args.push_back(&GtidArg);
Args.push_back(&TaskTypeArg);
auto &TaskEntryFnInfo =
@@ -3321,7 +3827,6 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
".omp_task_entry.", &CGM.getModule());
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskEntry, TaskEntryFnInfo);
CodeGenFunction CGF(CGM);
- CGF.disableDebugInfo();
CGF.StartFunction(GlobalDecl(), KmpInt32Ty, TaskEntry, TaskEntryFnInfo, Args);
// TaskFunction(gtid, tt->task_data.part_id, &tt->privates, task_privates_map,
@@ -3379,14 +3884,19 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
auto LILVal = CGF.EmitLValueForField(Base, *LIFI);
auto *LIParam = CGF.EmitLoadOfLValue(LILVal, Loc).getScalarVal();
+ auto RFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTReductions);
+ auto RLVal = CGF.EmitLValueForField(Base, *RFI);
+ auto *RParam = CGF.EmitLoadOfLValue(RLVal, Loc).getScalarVal();
CallArgs.push_back(LBParam);
CallArgs.push_back(UBParam);
CallArgs.push_back(StParam);
CallArgs.push_back(LIParam);
+ CallArgs.push_back(RParam);
}
CallArgs.push_back(SharedsParam);
- CGF.EmitCallOrInvoke(TaskFunction, CallArgs);
+ CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskFunction,
+ CallArgs);
CGF.EmitStoreThroughLValue(
RValue::get(CGF.Builder.getInt32(/*C=*/0)),
CGF.MakeAddrLValue(CGF.ReturnValue, KmpInt32Ty));
@@ -3401,10 +3911,11 @@ static llvm::Value *emitDestructorsFunction(CodeGenModule &CGM,
QualType KmpTaskTWithPrivatesQTy) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty);
- ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy.withRestrict());
+ ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy.withRestrict(),
+ ImplicitParamDecl::Other);
Args.push_back(&GtidArg);
Args.push_back(&TaskTypeArg);
FunctionType::ExtInfo Info;
@@ -3460,36 +3971,40 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
FunctionArgList Args;
ImplicitParamDecl TaskPrivatesArg(
C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.getPointerType(PrivatesQTy).withConst().withRestrict());
+ C.getPointerType(PrivatesQTy).withConst().withRestrict(),
+ ImplicitParamDecl::Other);
Args.push_back(&TaskPrivatesArg);
llvm::DenseMap<const VarDecl *, unsigned> PrivateVarsPos;
unsigned Counter = 1;
for (auto *E: PrivateVars) {
Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict()));
+ C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.getPointerType(C.getPointerType(E->getType()))
+ .withConst()
+ .withRestrict(),
+ ImplicitParamDecl::Other));
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
PrivateVarsPos[VD] = Counter;
++Counter;
}
for (auto *E : FirstprivateVars) {
Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict()));
+ C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.getPointerType(C.getPointerType(E->getType()))
+ .withConst()
+ .withRestrict(),
+ ImplicitParamDecl::Other));
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
PrivateVarsPos[VD] = Counter;
++Counter;
}
for (auto *E: LastprivateVars) {
Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict()));
+ C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.getPointerType(C.getPointerType(E->getType()))
+ .withConst()
+ .withRestrict(),
+ ImplicitParamDecl::Other));
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
PrivateVarsPos[VD] = Counter;
++Counter;
@@ -3504,6 +4019,7 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskPrivatesMap,
TaskPrivatesMapFnInfo);
TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
+ TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone);
TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
CodeGenFunction CGF(CGM);
CGF.disableDebugInfo();
@@ -3567,7 +4083,9 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
auto SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
SharedRefLValue = CGF.MakeAddrLValue(
Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)),
- SharedRefLValue.getType(), AlignmentSource::Decl);
+ SharedRefLValue.getType(),
+ LValueBaseInfo(AlignmentSource::Decl),
+ SharedRefLValue.getTBAAInfo());
QualType Type = OriginalVD->getType();
if (Type->isArrayType()) {
// Initialize firstprivate array.
@@ -3577,7 +4095,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,
@@ -3646,12 +4164,14 @@ emitTaskDupFunction(CodeGenModule &CGM, SourceLocation Loc,
ArrayRef<PrivateDataTy> Privates, bool WithLastIter) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl DstArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy);
- ImplicitParamDecl SrcArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy);
- ImplicitParamDecl LastprivArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.IntTy);
+ ImplicitParamDecl DstArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl SrcArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl LastprivArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy,
+ ImplicitParamDecl::Other);
Args.push_back(&DstArg);
Args.push_back(&SrcArg);
Args.push_back(&LastprivArg);
@@ -3761,9 +4281,20 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc,
// Build type kmp_routine_entry_t (if not built yet).
emitKmpRoutineEntryT(KmpInt32Ty);
// Build type kmp_task_t (if not built yet).
- if (KmpTaskTQTy.isNull()) {
- KmpTaskTQTy = C.getRecordType(createKmpTaskTRecordDecl(
- CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
+ if (isOpenMPTaskLoopDirective(D.getDirectiveKind())) {
+ if (SavedKmpTaskloopTQTy.isNull()) {
+ SavedKmpTaskloopTQTy = C.getRecordType(createKmpTaskTRecordDecl(
+ CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
+ }
+ KmpTaskTQTy = SavedKmpTaskloopTQTy;
+ } else {
+ assert(D.getDirectiveKind() == OMPD_task &&
+ "Expected taskloop or task directive");
+ if (SavedKmpTaskTQTy.isNull()) {
+ SavedKmpTaskTQTy = C.getRecordType(createKmpTaskTRecordDecl(
+ CGM, D.getDirectiveKind(), KmpInt32Ty, KmpRoutineEntryPtrQTy));
+ }
+ KmpTaskTQTy = SavedKmpTaskTQTy;
}
auto *KmpTaskTQTyRD = cast<RecordDecl>(KmpTaskTQTy->getAsTagDecl());
// Build particular struct kmp_task_t for the given task.
@@ -3780,9 +4311,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(
@@ -4053,8 +4582,8 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
}
auto &&ElseCodeGen = [&TaskArgs, ThreadID, NewTaskNewTaskTTy, TaskEntry,
- NumDependencies, &DepWaitTaskArgs](CodeGenFunction &CGF,
- PrePostActionTy &) {
+ NumDependencies, &DepWaitTaskArgs,
+ Loc](CodeGenFunction &CGF, PrePostActionTy &) {
auto &RT = CGF.CGM.getOpenMPRuntime();
CodeGenFunction::RunCleanupsScope LocalScope(CGF);
// Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid,
@@ -4065,11 +4594,12 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
CGF.EmitRuntimeCall(RT.createRuntimeFunction(OMPRTL__kmpc_omp_wait_deps),
DepWaitTaskArgs);
// Call proxy_task_entry(gtid, new_task);
- auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy](
- CodeGenFunction &CGF, PrePostActionTy &Action) {
+ auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy,
+ Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
llvm::Value *OutlinedFnArgs[] = {ThreadID, NewTaskNewTaskTTy};
- CGF.EmitCallOrInvoke(TaskEntry, OutlinedFnArgs);
+ CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, Loc, TaskEntry,
+ OutlinedFnArgs);
};
// Build void __kmpc_omp_task_begin_if0(ident_t *, kmp_int32 gtid,
@@ -4137,11 +4667,27 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
cast<VarDecl>(cast<DeclRefExpr>(D.getStrideVariable())->getDecl());
CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(),
/*IsInitializer=*/true);
+ // Store reductions address.
+ LValue RedLVal = CGF.EmitLValueForField(
+ Result.TDBase,
+ *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTReductions));
+ if (Data.Reductions)
+ CGF.EmitStoreOfScalar(Data.Reductions, RedLVal);
+ else {
+ CGF.EmitNullInitialization(RedLVal.getAddress(),
+ CGF.getContext().VoidPtrTy);
+ }
enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
llvm::Value *TaskArgs[] = {
- UpLoc, ThreadID, Result.NewTask, IfVal, LBLVal.getPointer(),
- UBLVal.getPointer(), CGF.EmitLoadOfScalar(StLVal, SourceLocation()),
- llvm::ConstantInt::getSigned(CGF.IntTy, Data.Nogroup ? 1 : 0),
+ UpLoc,
+ ThreadID,
+ Result.NewTask,
+ IfVal,
+ LBLVal.getPointer(),
+ UBLVal.getPointer(),
+ CGF.EmitLoadOfScalar(StLVal, SourceLocation()),
+ llvm::ConstantInt::getNullValue(
+ CGF.IntTy), // Always 0 because taskgroup emitted by the compiler
llvm::ConstantInt::getSigned(
CGF.IntTy, Data.Schedule.getPointer()
? Data.Schedule.getInt() ? NumTasks : Grainsize
@@ -4150,10 +4696,9 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty,
/*isSigned=*/false)
: llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0),
- Result.TaskDupFn
- ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Result.TaskDupFn,
- CGF.VoidPtrTy)
- : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)};
+ Result.TaskDupFn ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ Result.TaskDupFn, CGF.VoidPtrTy)
+ : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)};
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_taskloop), TaskArgs);
}
@@ -4265,10 +4810,8 @@ llvm::Value *CGOpenMPRuntime::emitReductionFunction(
// void reduction_func(void *LHSArg, void *RHSArg);
FunctionArgList Args;
- ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
- ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
+ ImplicitParamDecl LHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl RHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
Args.push_back(&LHSArg);
Args.push_back(&RHSArg);
auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
@@ -4659,6 +5202,353 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
}
+/// Generates unique name for artificial threadprivate variables.
+/// Format is: <Prefix> "." <Loc_raw_encoding> "_" <N>
+static std::string generateUniqueName(StringRef Prefix, SourceLocation Loc,
+ unsigned N) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ Out << Prefix << "." << Loc.getRawEncoding() << "_" << N;
+ return Out.str();
+}
+
+/// Emits reduction initializer function:
+/// \code
+/// void @.red_init(void* %arg) {
+/// %0 = bitcast void* %arg to <type>*
+/// store <type> <init>, <type>* %0
+/// ret void
+/// }
+/// \endcode
+static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N) {
+ auto &C = CGM.getContext();
+ FunctionArgList Args;
+ ImplicitParamDecl Param(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ Args.emplace_back(&Param);
+ auto &FnInfo =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
+ ".red_init.", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
+ CodeGenFunction CGF(CGM);
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args);
+ Address PrivateAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&Param),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ llvm::Value *Size = nullptr;
+ // If the size of the reduction item is non-constant, load it from global
+ // threadprivate variable.
+ if (RCG.getSizes(N).second) {
+ Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ Size =
+ CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
+ CGM.getContext().getSizeType(), SourceLocation());
+ }
+ RCG.emitAggregateType(CGF, N, Size);
+ LValue SharedLVal;
+ // If initializer uses initializer from declare reduction construct, emit a
+ // pointer to the address of the original reduction item (reuired by reduction
+ // initializer)
+ if (RCG.usesReductionInitializer(N)) {
+ Address SharedAddr =
+ CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().VoidPtrTy,
+ generateUniqueName("reduction", Loc, N));
+ SharedLVal = CGF.MakeAddrLValue(SharedAddr, CGM.getContext().VoidPtrTy);
+ } else {
+ SharedLVal = CGF.MakeNaturalAlignAddrLValue(
+ llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
+ CGM.getContext().VoidPtrTy);
+ }
+ // Emit the initializer:
+ // %0 = bitcast void* %arg to <type>*
+ // store <type> <init>, <type>* %0
+ RCG.emitInitialization(CGF, N, PrivateAddr, SharedLVal,
+ [](CodeGenFunction &) { return false; });
+ CGF.FinishFunction();
+ return Fn;
+}
+
+/// Emits reduction combiner function:
+/// \code
+/// void @.red_comb(void* %arg0, void* %arg1) {
+/// %lhs = bitcast void* %arg0 to <type>*
+/// %rhs = bitcast void* %arg1 to <type>*
+/// %2 = <ReductionOp>(<type>* %lhs, <type>* %rhs)
+/// store <type> %2, <type>* %lhs
+/// ret void
+/// }
+/// \endcode
+static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N,
+ const Expr *ReductionOp,
+ const Expr *LHS, const Expr *RHS,
+ const Expr *PrivateRef) {
+ auto &C = CGM.getContext();
+ auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(LHS)->getDecl());
+ auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(RHS)->getDecl());
+ FunctionArgList Args;
+ ImplicitParamDecl ParamInOut(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl ParamIn(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ Args.emplace_back(&ParamInOut);
+ Args.emplace_back(&ParamIn);
+ auto &FnInfo =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
+ ".red_comb.", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
+ CodeGenFunction CGF(CGM);
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args);
+ llvm::Value *Size = nullptr;
+ // If the size of the reduction item is non-constant, load it from global
+ // threadprivate variable.
+ if (RCG.getSizes(N).second) {
+ Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ Size =
+ CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
+ CGM.getContext().getSizeType(), SourceLocation());
+ }
+ RCG.emitAggregateType(CGF, N, Size);
+ // Remap lhs and rhs variables to the addresses of the function arguments.
+ // %lhs = bitcast void* %arg0 to <type>*
+ // %rhs = bitcast void* %arg1 to <type>*
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ PrivateScope.addPrivate(LHSVD, [&C, &CGF, &ParamInOut, LHSVD]() -> Address {
+ // Pull out the pointer to the variable.
+ Address PtrAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&ParamInOut),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ return CGF.Builder.CreateElementBitCast(
+ PtrAddr, CGF.ConvertTypeForMem(LHSVD->getType()));
+ });
+ PrivateScope.addPrivate(RHSVD, [&C, &CGF, &ParamIn, RHSVD]() -> Address {
+ // Pull out the pointer to the variable.
+ Address PtrAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&ParamIn),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ return CGF.Builder.CreateElementBitCast(
+ PtrAddr, CGF.ConvertTypeForMem(RHSVD->getType()));
+ });
+ PrivateScope.Privatize();
+ // Emit the combiner body:
+ // %2 = <ReductionOp>(<type> *%lhs, <type> *%rhs)
+ // store <type> %2, <type>* %lhs
+ CGM.getOpenMPRuntime().emitSingleReductionCombiner(
+ CGF, ReductionOp, PrivateRef, cast<DeclRefExpr>(LHS),
+ cast<DeclRefExpr>(RHS));
+ CGF.FinishFunction();
+ return Fn;
+}
+
+/// Emits reduction finalizer function:
+/// \code
+/// void @.red_fini(void* %arg) {
+/// %0 = bitcast void* %arg to <type>*
+/// <destroy>(<type>* %0)
+/// ret void
+/// }
+/// \endcode
+static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N) {
+ if (!RCG.needCleanups(N))
+ return nullptr;
+ auto &C = CGM.getContext();
+ FunctionArgList Args;
+ ImplicitParamDecl Param(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ Args.emplace_back(&Param);
+ auto &FnInfo =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
+ ".red_fini.", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
+ CodeGenFunction CGF(CGM);
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args);
+ Address PrivateAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&Param),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ llvm::Value *Size = nullptr;
+ // If the size of the reduction item is non-constant, load it from global
+ // threadprivate variable.
+ if (RCG.getSizes(N).second) {
+ Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ Size =
+ CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
+ CGM.getContext().getSizeType(), SourceLocation());
+ }
+ RCG.emitAggregateType(CGF, N, Size);
+ // Emit the finalizer body:
+ // <destroy>(<type>* %0)
+ RCG.emitCleanups(CGF, N, PrivateAddr);
+ CGF.FinishFunction();
+ return Fn;
+}
+
+llvm::Value *CGOpenMPRuntime::emitTaskReductionInit(
+ CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
+ if (!CGF.HaveInsertPoint() || Data.ReductionVars.empty())
+ return nullptr;
+
+ // Build typedef struct:
+ // kmp_task_red_input {
+ // void *reduce_shar; // shared reduction item
+ // size_t reduce_size; // size of data item
+ // void *reduce_init; // data initialization routine
+ // void *reduce_fini; // data finalization routine
+ // void *reduce_comb; // data combiner routine
+ // kmp_task_red_flags_t flags; // flags for additional info from compiler
+ // } kmp_task_red_input_t;
+ ASTContext &C = CGM.getContext();
+ auto *RD = C.buildImplicitRecord("kmp_task_red_input_t");
+ RD->startDefinition();
+ const FieldDecl *SharedFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *SizeFD = addFieldToRecordDecl(C, RD, C.getSizeType());
+ const FieldDecl *InitFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *FiniFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *CombFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *FlagsFD = addFieldToRecordDecl(
+ C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false));
+ RD->completeDefinition();
+ QualType RDType = C.getRecordType(RD);
+ unsigned Size = Data.ReductionVars.size();
+ llvm::APInt ArraySize(/*numBits=*/64, Size);
+ QualType ArrayRDType = C.getConstantArrayType(
+ RDType, ArraySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ // kmp_task_red_input_t .rd_input.[Size];
+ Address TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input.");
+ ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionCopies,
+ Data.ReductionOps);
+ for (unsigned Cnt = 0; Cnt < Size; ++Cnt) {
+ // kmp_task_red_input_t &ElemLVal = .rd_input.[Cnt];
+ llvm::Value *Idxs[] = {llvm::ConstantInt::get(CGM.SizeTy, /*V=*/0),
+ llvm::ConstantInt::get(CGM.SizeTy, Cnt)};
+ llvm::Value *GEP = CGF.EmitCheckedInBoundsGEP(
+ TaskRedInput.getPointer(), Idxs,
+ /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc,
+ ".rd_input.gep.");
+ LValue ElemLVal = CGF.MakeNaturalAlignAddrLValue(GEP, RDType);
+ // ElemLVal.reduce_shar = &Shareds[Cnt];
+ LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD);
+ RCG.emitSharedLValue(CGF, Cnt);
+ llvm::Value *CastedShared =
+ CGF.EmitCastToVoidPtr(RCG.getSharedLValue(Cnt).getPointer());
+ CGF.EmitStoreOfScalar(CastedShared, SharedLVal);
+ RCG.emitAggregateType(CGF, Cnt);
+ llvm::Value *SizeValInChars;
+ llvm::Value *SizeVal;
+ std::tie(SizeValInChars, SizeVal) = RCG.getSizes(Cnt);
+ // We use delayed creation/initialization for VLAs, array sections and
+ // custom reduction initializations. It is required because runtime does not
+ // provide the way to pass the sizes of VLAs/array sections to
+ // initializer/combiner/finalizer functions and does not pass the pointer to
+ // original reduction item to the initializer. Instead threadprivate global
+ // variables are used to store these values and use them in the functions.
+ bool DelayedCreation = !!SizeVal;
+ SizeValInChars = CGF.Builder.CreateIntCast(SizeValInChars, CGM.SizeTy,
+ /*isSigned=*/false);
+ LValue SizeLVal = CGF.EmitLValueForField(ElemLVal, SizeFD);
+ CGF.EmitStoreOfScalar(SizeValInChars, SizeLVal);
+ // ElemLVal.reduce_init = init;
+ LValue InitLVal = CGF.EmitLValueForField(ElemLVal, InitFD);
+ llvm::Value *InitAddr =
+ CGF.EmitCastToVoidPtr(emitReduceInitFunction(CGM, Loc, RCG, Cnt));
+ CGF.EmitStoreOfScalar(InitAddr, InitLVal);
+ DelayedCreation = DelayedCreation || RCG.usesReductionInitializer(Cnt);
+ // ElemLVal.reduce_fini = fini;
+ LValue FiniLVal = CGF.EmitLValueForField(ElemLVal, FiniFD);
+ llvm::Value *Fini = emitReduceFiniFunction(CGM, Loc, RCG, Cnt);
+ llvm::Value *FiniAddr = Fini
+ ? CGF.EmitCastToVoidPtr(Fini)
+ : llvm::ConstantPointerNull::get(CGM.VoidPtrTy);
+ CGF.EmitStoreOfScalar(FiniAddr, FiniLVal);
+ // ElemLVal.reduce_comb = comb;
+ LValue CombLVal = CGF.EmitLValueForField(ElemLVal, CombFD);
+ llvm::Value *CombAddr = CGF.EmitCastToVoidPtr(emitReduceCombFunction(
+ CGM, Loc, RCG, Cnt, Data.ReductionOps[Cnt], LHSExprs[Cnt],
+ RHSExprs[Cnt], Data.ReductionCopies[Cnt]));
+ CGF.EmitStoreOfScalar(CombAddr, CombLVal);
+ // ElemLVal.flags = 0;
+ LValue FlagsLVal = CGF.EmitLValueForField(ElemLVal, FlagsFD);
+ if (DelayedCreation) {
+ CGF.EmitStoreOfScalar(
+ llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*IsSigned=*/true),
+ FlagsLVal);
+ } else
+ CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType());
+ }
+ // Build call void *__kmpc_task_reduction_init(int gtid, int num_data, void
+ // *data);
+ llvm::Value *Args[] = {
+ CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
+ /*isSigned=*/true),
+ llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TaskRedInput.getPointer(),
+ CGM.VoidPtrTy)};
+ return CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_task_reduction_init), Args);
+}
+
+void CGOpenMPRuntime::emitTaskReductionFixups(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG,
+ unsigned N) {
+ auto Sizes = RCG.getSizes(N);
+ // Emit threadprivate global variable if the type is non-constant
+ // (Sizes.second = nullptr).
+ if (Sizes.second) {
+ llvm::Value *SizeVal = CGF.Builder.CreateIntCast(Sizes.second, CGM.SizeTy,
+ /*isSigned=*/false);
+ Address SizeAddr = getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ CGF.Builder.CreateStore(SizeVal, SizeAddr, /*IsVolatile=*/false);
+ }
+ // Store address of the original reduction item if custom initializer is used.
+ if (RCG.usesReductionInitializer(N)) {
+ Address SharedAddr = getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().VoidPtrTy,
+ generateUniqueName("reduction", Loc, N));
+ CGF.Builder.CreateStore(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ RCG.getSharedLValue(N).getPointer(), CGM.VoidPtrTy),
+ SharedAddr, /*IsVolatile=*/false);
+ }
+}
+
+Address CGOpenMPRuntime::getTaskReductionItem(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ llvm::Value *ReductionsPtr,
+ LValue SharedLVal) {
+ // Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
+ // *d);
+ llvm::Value *Args[] = {
+ CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
+ /*isSigned=*/true),
+ ReductionsPtr,
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(SharedLVal.getPointer(),
+ CGM.VoidPtrTy)};
+ return Address(
+ CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_task_reduction_get_th_data), Args),
+ SharedLVal.getAlignment());
+}
+
void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF,
SourceLocation Loc) {
if (!CGF.HaveInsertPoint())
@@ -5101,6 +5991,8 @@ public:
OMP_MAP_PRIVATE_PTR = 0x80,
/// \brief Pass the element to the device by value.
OMP_MAP_PRIVATE_VAL = 0x100,
+ /// Implicit map
+ OMP_MAP_IMPLICIT = 0x200,
};
/// Class that associates information with a base pointer to be passed to the
@@ -5271,7 +6163,7 @@ private:
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
MapBaseValuesArrayTy &BasePointers, MapValuesArrayTy &Pointers,
MapValuesArrayTy &Sizes, MapFlagsArrayTy &Types,
- bool IsFirstComponentList) const {
+ bool IsFirstComponentList, bool IsImplicit) const {
// The following summarizes what has to be generated for each map and the
// types bellow. The generated information is expressed in this order:
@@ -5406,8 +6298,7 @@ private:
} else {
// The base is the reference to the variable.
// BP = &Var.
- BP = CGF.EmitLValue(cast<DeclRefExpr>(I->getAssociatedExpression()))
- .getPointer();
+ BP = CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getPointer();
// If the variable is a pointer and is being dereferenced (i.e. is not
// the last component), the base has to be the pointer itself, not its
@@ -5426,6 +6317,7 @@ private:
}
}
+ unsigned DefaultFlags = IsImplicit ? OMP_MAP_IMPLICIT : 0;
for (; I != CE; ++I) {
auto Next = std::next(I);
@@ -5460,7 +6352,8 @@ private:
isa<OMPArraySectionExpr>(Next->getAssociatedExpression())) &&
"Unexpected expression");
- auto *LB = CGF.EmitLValue(I->getAssociatedExpression()).getPointer();
+ llvm::Value *LB =
+ CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getPointer();
auto *Size = getExprTypeSize(I->getAssociatedExpression());
// If we have a member expression and the current component is a
@@ -5475,9 +6368,11 @@ private:
BasePointers.push_back(BP);
Pointers.push_back(RefAddr);
Sizes.push_back(CGF.getTypeSize(CGF.getContext().VoidPtrTy));
- Types.push_back(getMapTypeBits(
- /*MapType*/ OMPC_MAP_alloc, /*MapTypeModifier=*/OMPC_MAP_unknown,
- !IsExpressionFirstInfo, IsCaptureFirstInfo));
+ Types.push_back(DefaultFlags |
+ getMapTypeBits(
+ /*MapType*/ OMPC_MAP_alloc,
+ /*MapTypeModifier=*/OMPC_MAP_unknown,
+ !IsExpressionFirstInfo, IsCaptureFirstInfo));
IsExpressionFirstInfo = false;
IsCaptureFirstInfo = false;
// The reference will be the next base address.
@@ -5492,9 +6387,9 @@ private:
// same expression except for the first one. We also need to signal
// this map is the first one that relates with the current capture
// (there is a set of entries for each capture).
- Types.push_back(getMapTypeBits(MapType, MapTypeModifier,
- !IsExpressionFirstInfo,
- IsCaptureFirstInfo));
+ Types.push_back(DefaultFlags | getMapTypeBits(MapType, MapTypeModifier,
+ !IsExpressionFirstInfo,
+ IsCaptureFirstInfo));
// If we have a final array section, we are done with this expression.
if (IsFinalArraySection)
@@ -5506,7 +6401,6 @@ private:
IsExpressionFirstInfo = false;
IsCaptureFirstInfo = false;
- continue;
}
}
}
@@ -5568,26 +6462,25 @@ public:
RPK_MemberReference,
};
OMPClauseMappableExprCommon::MappableExprComponentListRef Components;
- OpenMPMapClauseKind MapType;
- OpenMPMapClauseKind MapTypeModifier;
- ReturnPointerKind ReturnDevicePointer;
+ OpenMPMapClauseKind MapType = OMPC_MAP_unknown;
+ OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown;
+ ReturnPointerKind ReturnDevicePointer = RPK_None;
+ bool IsImplicit = false;
- MapInfo()
- : MapType(OMPC_MAP_unknown), MapTypeModifier(OMPC_MAP_unknown),
- ReturnDevicePointer(RPK_None) {}
+ MapInfo() = default;
MapInfo(
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapTypeModifier,
- ReturnPointerKind ReturnDevicePointer)
+ ReturnPointerKind ReturnDevicePointer, bool IsImplicit)
: Components(Components), MapType(MapType),
MapTypeModifier(MapTypeModifier),
- ReturnDevicePointer(ReturnDevicePointer) {}
+ ReturnDevicePointer(ReturnDevicePointer), IsImplicit(IsImplicit) {}
};
// We have to process the component lists that relate with the same
// declaration in a single chunk so that we can generate the map flags
// correctly. Therefore, we organize all lists in a map.
- llvm::DenseMap<const ValueDecl *, SmallVector<MapInfo, 8>> Info;
+ llvm::MapVector<const ValueDecl *, SmallVector<MapInfo, 8>> Info;
// Helper function to fill the information map for the different supported
// clauses.
@@ -5595,25 +6488,29 @@ public:
const ValueDecl *D,
OMPClauseMappableExprCommon::MappableExprComponentListRef L,
OpenMPMapClauseKind MapType, OpenMPMapClauseKind MapModifier,
- MapInfo::ReturnPointerKind ReturnDevicePointer) {
+ MapInfo::ReturnPointerKind ReturnDevicePointer, bool IsImplicit) {
const ValueDecl *VD =
D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
- Info[VD].push_back({L, MapType, MapModifier, ReturnDevicePointer});
+ Info[VD].emplace_back(L, MapType, MapModifier, ReturnDevicePointer,
+ IsImplicit);
};
// FIXME: MSVC 2013 seems to require this-> to find member CurDir.
for (auto *C : this->CurDir.getClausesOfKind<OMPMapClause>())
- for (auto L : C->component_lists())
+ for (auto L : C->component_lists()) {
InfoGen(L.first, L.second, C->getMapType(), C->getMapTypeModifier(),
- MapInfo::RPK_None);
+ MapInfo::RPK_None, C->isImplicit());
+ }
for (auto *C : this->CurDir.getClausesOfKind<OMPToClause>())
- for (auto L : C->component_lists())
+ for (auto L : C->component_lists()) {
InfoGen(L.first, L.second, OMPC_MAP_to, OMPC_MAP_unknown,
- MapInfo::RPK_None);
+ MapInfo::RPK_None, C->isImplicit());
+ }
for (auto *C : this->CurDir.getClausesOfKind<OMPFromClause>())
- for (auto L : C->component_lists())
+ for (auto L : C->component_lists()) {
InfoGen(L.first, L.second, OMPC_MAP_from, OMPC_MAP_unknown,
- MapInfo::RPK_None);
+ MapInfo::RPK_None, C->isImplicit());
+ }
// Look at the use_device_ptr clause information and mark the existing map
// entries as such. If there is no map information for an entry in the
@@ -5674,9 +6571,9 @@ public:
// Remember the current base pointer index.
unsigned CurrentBasePointersIdx = BasePointers.size();
// FIXME: MSVC 2013 seems to require this-> to find the member method.
- this->generateInfoForComponentList(L.MapType, L.MapTypeModifier,
- L.Components, BasePointers, Pointers,
- Sizes, Types, IsFirstComponentList);
+ this->generateInfoForComponentList(
+ L.MapType, L.MapTypeModifier, L.Components, BasePointers, Pointers,
+ Sizes, Types, IsFirstComponentList, L.IsImplicit);
// If this entry relates with a device pointer, set the relevant
// declaration and add the 'return pointer' flag.
@@ -5740,7 +6637,8 @@ public:
for (auto L : It->second) {
generateInfoForComponentList(
/*MapType=*/OMPC_MAP_to, /*MapTypeModifier=*/OMPC_MAP_unknown, L,
- BasePointers, Pointers, Sizes, Types, IsFirstComponentList);
+ BasePointers, Pointers, Sizes, Types, IsFirstComponentList,
+ /*IsImplicit=*/false);
IsFirstComponentList = false;
}
return;
@@ -5760,9 +6658,9 @@ public:
"We got information for the wrong declaration??");
assert(!L.second.empty() &&
"Not expecting declaration with no component lists.");
- generateInfoForComponentList(C->getMapType(), C->getMapTypeModifier(),
- L.second, BasePointers, Pointers, Sizes,
- Types, IsFirstComponentList);
+ generateInfoForComponentList(
+ C->getMapType(), C->getMapTypeModifier(), L.second, BasePointers,
+ Pointers, Sizes, Types, IsFirstComponentList, C->isImplicit());
IsFirstComponentList = false;
}
@@ -5911,16 +6809,11 @@ emitOffloadingArrays(CodeGenFunction &CGF,
for (unsigned i = 0; i < Info.NumberOfPtrs; ++i) {
llvm::Value *BPVal = *BasePointers[i];
- if (BPVal->getType()->isPointerTy())
- BPVal = CGF.Builder.CreateBitCast(BPVal, CGM.VoidPtrTy);
- else {
- assert(BPVal->getType()->isIntegerTy() &&
- "If not a pointer, the value type must be an integer.");
- BPVal = CGF.Builder.CreateIntToPtr(BPVal, CGM.VoidPtrTy);
- }
llvm::Value *BP = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
Info.BasePointersArray, 0, i);
+ BP = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ BP, BPVal->getType()->getPointerTo(/*AddrSpace=*/0));
Address BPAddr(BP, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
CGF.Builder.CreateStore(BPVal, BPAddr);
@@ -5929,16 +6822,11 @@ emitOffloadingArrays(CodeGenFunction &CGF,
Info.CaptureDeviceAddrMap.insert(std::make_pair(DevVD, BPAddr));
llvm::Value *PVal = Pointers[i];
- if (PVal->getType()->isPointerTy())
- PVal = CGF.Builder.CreateBitCast(PVal, CGM.VoidPtrTy);
- else {
- assert(PVal->getType()->isIntegerTy() &&
- "If not a pointer, the value type must be an integer.");
- PVal = CGF.Builder.CreateIntToPtr(PVal, CGM.VoidPtrTy);
- }
llvm::Value *P = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
Info.PointersArray, 0, i);
+ P = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ P, PVal->getType()->getPointerTo(/*AddrSpace=*/0));
Address PAddr(P, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
CGF.Builder.CreateStore(PVal, PAddr);
@@ -6001,8 +6889,6 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
assert(OutlinedFn && "Invalid outlined function!");
- auto &Ctx = CGF.getContext();
-
// Fill up the arrays with all the captured variables.
MappableExprsHandler::MapValuesArrayTy KernelArgs;
MappableExprsHandler::MapBaseValuesArrayTy BasePointers;
@@ -6024,9 +6910,6 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
for (CapturedStmt::const_capture_iterator CI = CS.capture_begin(),
CE = CS.capture_end();
CI != CE; ++CI, ++RI, ++CV) {
- StringRef Name;
- QualType Ty;
-
CurBasePointers.clear();
CurPointers.clear();
CurSizes.clear();
@@ -6067,19 +6950,10 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
MapTypes.append(CurMapTypes.begin(), CurMapTypes.end());
}
- // Keep track on whether the host function has to be executed.
- auto OffloadErrorQType =
- Ctx.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true);
- auto OffloadError = CGF.MakeAddrLValue(
- CGF.CreateMemTemp(OffloadErrorQType, ".run_host_version"),
- OffloadErrorQType);
- CGF.EmitStoreOfScalar(llvm::Constant::getNullValue(CGM.Int32Ty),
- OffloadError);
-
// Fill up the pointer arrays and transfer execution to the device.
- auto &&ThenGen = [&BasePointers, &Pointers, &Sizes, &MapTypes, Device,
- OutlinedFnID, OffloadError,
- &D](CodeGenFunction &CGF, PrePostActionTy &) {
+ auto &&ThenGen = [this, &BasePointers, &Pointers, &Sizes, &MapTypes, Device,
+ OutlinedFn, OutlinedFnID, &D,
+ &KernelArgs](CodeGenFunction &CGF, PrePostActionTy &) {
auto &RT = CGF.CGM.getOpenMPRuntime();
// Emit the offloading arrays.
TargetDataInfo Info;
@@ -6170,13 +7044,26 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
OffloadingArgs);
}
- CGF.EmitStoreOfScalar(Return, OffloadError);
+ // Check the error code and execute the host version if required.
+ llvm::BasicBlock *OffloadFailedBlock =
+ CGF.createBasicBlock("omp_offload.failed");
+ llvm::BasicBlock *OffloadContBlock =
+ CGF.createBasicBlock("omp_offload.cont");
+ llvm::Value *Failed = CGF.Builder.CreateIsNotNull(Return);
+ CGF.Builder.CreateCondBr(Failed, OffloadFailedBlock, OffloadContBlock);
+
+ CGF.EmitBlock(OffloadFailedBlock);
+ emitOutlinedFunctionCall(CGF, D.getLocStart(), OutlinedFn, KernelArgs);
+ CGF.EmitBranch(OffloadContBlock);
+
+ CGF.EmitBlock(OffloadContBlock, /*IsFinished=*/true);
};
// Notify that the host version must be executed.
- auto &&ElseGen = [OffloadError](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.Int32Ty, /*V=*/-1u),
- OffloadError);
+ auto &&ElseGen = [this, &D, OutlinedFn, &KernelArgs](CodeGenFunction &CGF,
+ PrePostActionTy &) {
+ emitOutlinedFunctionCall(CGF, D.getLocStart(), OutlinedFn,
+ KernelArgs);
};
// If we have a target function ID it means that we need to support
@@ -6194,19 +7081,6 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
RegionCodeGenTy ElseRCG(ElseGen);
ElseRCG(CGF);
}
-
- // Check the error code and execute the host version if required.
- auto OffloadFailedBlock = CGF.createBasicBlock("omp_offload.failed");
- auto OffloadContBlock = CGF.createBasicBlock("omp_offload.cont");
- auto OffloadErrorVal = CGF.EmitLoadOfScalar(OffloadError, SourceLocation());
- auto Failed = CGF.Builder.CreateIsNotNull(OffloadErrorVal);
- CGF.Builder.CreateCondBr(Failed, OffloadFailedBlock, OffloadContBlock);
-
- CGF.EmitBlock(OffloadFailedBlock);
- CGF.Builder.CreateCall(OutlinedFn, KernelArgs);
- CGF.EmitBranch(OffloadContBlock);
-
- CGF.EmitBlock(OffloadContBlock, /*IsFinished=*/true);
}
void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
@@ -6311,7 +7185,7 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
}
}
- // If we are in target mode we do not emit any global (declare target is not
+ // If we are in target mode, we do not emit any global (declare target is not
// implemented yet). Therefore we signal that GD was processed in this case.
return true;
}
@@ -6923,3 +7797,29 @@ void CGOpenMPRuntime::emitDoacrossOrdered(CodeGenFunction &CGF,
CGF.EmitRuntimeCall(RTLFn, Args);
}
+void CGOpenMPRuntime::emitCall(CodeGenFunction &CGF, llvm::Value *Callee,
+ ArrayRef<llvm::Value *> Args,
+ SourceLocation Loc) const {
+ auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc);
+
+ if (auto *Fn = dyn_cast<llvm::Function>(Callee)) {
+ if (Fn->doesNotThrow()) {
+ CGF.EmitNounwindRuntimeCall(Fn, Args);
+ return;
+ }
+ }
+ CGF.EmitRuntimeCall(Callee, Args);
+}
+
+void CGOpenMPRuntime::emitOutlinedFunctionCall(
+ CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
+ ArrayRef<llvm::Value *> Args) const {
+ assert(Loc.isValid() && "Outlined function call location must be valid.");
+ emitCall(CGF, OutlinedFn, Args, Loc);
+}
+
+Address CGOpenMPRuntime::getParameterAddress(CodeGenFunction &CGF,
+ const VarDecl *NativeParam,
+ const VarDecl *TargetParam) const {
+ return CGF.GetAddrOfLocalVar(NativeParam);
+}
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index dc62f2b6d5..94a1438413 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -96,15 +96,106 @@ struct OMPTaskDataTy final {
SmallVector<const Expr *, 4> FirstprivateInits;
SmallVector<const Expr *, 4> LastprivateVars;
SmallVector<const Expr *, 4> LastprivateCopies;
+ SmallVector<const Expr *, 4> ReductionVars;
+ SmallVector<const Expr *, 4> ReductionCopies;
+ SmallVector<const Expr *, 4> ReductionOps;
SmallVector<std::pair<OpenMPDependClauseKind, const Expr *>, 4> Dependences;
llvm::PointerIntPair<llvm::Value *, 1, bool> Final;
llvm::PointerIntPair<llvm::Value *, 1, bool> Schedule;
llvm::PointerIntPair<llvm::Value *, 1, bool> Priority;
+ llvm::Value *Reductions = nullptr;
unsigned NumberOfParts = 0;
bool Tied = true;
bool Nogroup = false;
};
+/// Class intended to support codegen of all kind of the reduction clauses.
+class ReductionCodeGen {
+private:
+ /// Data required for codegen of reduction clauses.
+ struct ReductionData {
+ /// Reference to the original shared item.
+ const Expr *Ref = nullptr;
+ /// Helper expression for generation of private copy.
+ const Expr *Private = nullptr;
+ /// Helper expression for generation reduction operation.
+ const Expr *ReductionOp = nullptr;
+ ReductionData(const Expr *Ref, const Expr *Private, const Expr *ReductionOp)
+ : Ref(Ref), Private(Private), ReductionOp(ReductionOp) {}
+ };
+ /// List of reduction-based clauses.
+ SmallVector<ReductionData, 4> ClausesData;
+
+ /// List of addresses of original shared variables/expressions.
+ SmallVector<std::pair<LValue, LValue>, 4> SharedAddresses;
+ /// Sizes of the reduction items in chars.
+ SmallVector<std::pair<llvm::Value *, llvm::Value *>, 4> Sizes;
+ /// Base declarations for the reduction items.
+ SmallVector<const VarDecl *, 4> BaseDecls;
+
+ /// Emits lvalue for shared expresion.
+ LValue emitSharedLValue(CodeGenFunction &CGF, const Expr *E);
+ /// Emits upper bound for shared expression (if array section).
+ LValue emitSharedLValueUB(CodeGenFunction &CGF, const Expr *E);
+ /// Performs aggregate initialization.
+ /// \param N Number of reduction item in the common list.
+ /// \param PrivateAddr Address of the corresponding private item.
+ /// \param SharedLVal Address of the original shared variable.
+ /// \param DRD Declare reduction construct used for reduction item.
+ void emitAggregateInitialization(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr, LValue SharedLVal,
+ const OMPDeclareReductionDecl *DRD);
+
+public:
+ ReductionCodeGen(ArrayRef<const Expr *> Shareds,
+ ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> ReductionOps);
+ /// Emits lvalue for a reduction item.
+ /// \param N Number of the reduction item.
+ void emitSharedLValue(CodeGenFunction &CGF, unsigned N);
+ /// Emits the code for the variable-modified type, if required.
+ /// \param N Number of the reduction item.
+ void emitAggregateType(CodeGenFunction &CGF, unsigned N);
+ /// Emits the code for the variable-modified type, if required.
+ /// \param N Number of the reduction item.
+ /// \param Size Size of the type in chars.
+ void emitAggregateType(CodeGenFunction &CGF, unsigned N, llvm::Value *Size);
+ /// Performs initialization of the private copy for the reduction item.
+ /// \param N Number of the reduction item.
+ /// \param PrivateAddr Address of the corresponding private item.
+ /// \param DefaultInit Default initialization sequence that should be
+ /// performed if no reduction specific initialization is found.
+ /// \param SharedLVal Address of the original shared variable.
+ void
+ emitInitialization(CodeGenFunction &CGF, unsigned N, Address PrivateAddr,
+ LValue SharedLVal,
+ llvm::function_ref<bool(CodeGenFunction &)> DefaultInit);
+ /// Returns true if the private copy requires cleanups.
+ bool needCleanups(unsigned N);
+ /// Emits cleanup code for the reduction item.
+ /// \param N Number of the reduction item.
+ /// \param PrivateAddr Address of the corresponding private item.
+ void emitCleanups(CodeGenFunction &CGF, unsigned N, Address PrivateAddr);
+ /// Adjusts \p PrivatedAddr for using instead of the original variable
+ /// address in normal operations.
+ /// \param N Number of the reduction item.
+ /// \param PrivateAddr Address of the corresponding private item.
+ Address adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr);
+ /// Returns LValue for the reduction item.
+ LValue getSharedLValue(unsigned N) const { return SharedAddresses[N].first; }
+ /// Returns the size of the reduction item (in chars and total number of
+ /// elements in the item), or nullptr, if the size is a constant.
+ std::pair<llvm::Value *, llvm::Value *> getSizes(unsigned N) const {
+ return Sizes[N];
+ }
+ /// Returns the base declaration of the reduction item.
+ const VarDecl *getBaseDecl(unsigned N) const { return BaseDecls[N]; }
+ /// Returns true if the initialization of the reduction item uses initializer
+ /// from declare reduction construct.
+ bool usesReductionInitializer(unsigned N) const;
+};
+
class CGOpenMPRuntime {
protected:
CodeGenModule &CGM;
@@ -121,7 +212,7 @@ protected:
/// \param OutlinedFnID Outlined function ID value to be defined by this call.
/// \param IsOffloadEntry True if the outlined function is an offload entry.
/// \param CodeGen Lambda codegen specific to an accelerator device.
- /// An oulined function may not be an entry if, e.g. the if clause always
+ /// An outlined function may not be an entry if, e.g. the if clause always
/// evaluates to false.
virtual void emitTargetOutlinedFunctionHelper(const OMPExecutableDirective &D,
StringRef ParentName,
@@ -159,6 +250,11 @@ protected:
//
virtual StringRef getOutlinedHelperName() const { return ".omp_outlined."; }
+ /// Emits \p Callee function call with arguments \p Args with location \p Loc.
+ void emitCall(CodeGenFunction &CGF, llvm::Value *Callee,
+ ArrayRef<llvm::Value *> Args = llvm::None,
+ SourceLocation Loc = SourceLocation()) const;
+
private:
/// \brief Default const ident_t object used for initialization of all other
/// ident_t objects.
@@ -222,6 +318,10 @@ private:
/// deconstructors of firstprivate C++ objects */
/// } kmp_task_t;
QualType KmpTaskTQTy;
+ /// Saved kmp_task_t for task directive.
+ QualType SavedKmpTaskTQTy;
+ /// Saved kmp_task_t for taskloop-based directive.
+ QualType SavedKmpTaskloopTQTy;
/// \brief Type typedef struct kmp_depend_info {
/// kmp_intptr_t base_addr;
/// size_t len;
@@ -672,16 +772,26 @@ public:
///
virtual bool isDynamic(OpenMPScheduleClauseKind ScheduleKind) const;
- virtual void emitForDispatchInit(CodeGenFunction &CGF, SourceLocation Loc,
- const OpenMPScheduleTy &ScheduleKind,
- unsigned IVSize, bool IVSigned, bool Ordered,
- llvm::Value *UB,
- llvm::Value *Chunk = nullptr);
+ /// struct with the values to be passed to the dispatch runtime function
+ struct DispatchRTInput {
+ /// Loop lower bound
+ llvm::Value *LB = nullptr;
+ /// Loop upper bound
+ llvm::Value *UB = nullptr;
+ /// Chunk size specified using 'schedule' clause (nullptr if chunk
+ /// was not specified)
+ llvm::Value *Chunk = nullptr;
+ DispatchRTInput() = default;
+ DispatchRTInput(llvm::Value *LB, llvm::Value *UB, llvm::Value *Chunk)
+ : LB(LB), UB(UB), Chunk(Chunk) {}
+ };
- /// \brief Call the appropriate runtime routine to initialize it before start
+ /// Call the appropriate runtime routine to initialize it before start
/// of loop.
- ///
- /// Depending on the loop schedule, it is nesessary to call some runtime
+
+ /// This is used for non static scheduled types and when the ordered
+ /// clause is present on the loop construct.
+ /// Depending on the loop schedule, it is necessary to call some runtime
/// routine before start of the OpenMP loop to get the loop upper / lower
/// bounds \a LB and \a UB and stride \a ST.
///
@@ -689,49 +799,76 @@ public:
/// \param Loc Clang source location.
/// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
/// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
+ /// \param IVSigned Sign of the iteration variable.
/// \param Ordered true if loop is ordered, false otherwise.
- /// \param IL Address of the output variable in which the flag of the
- /// last iteration is returned.
- /// \param LB Address of the output variable in which the lower iteration
- /// number is returned.
- /// \param UB Address of the output variable in which the upper iteration
- /// number is returned.
- /// \param ST Address of the output variable in which the stride value is
- /// returned nesessary to generated the static_chunked scheduled loop.
- /// \param Chunk Value of the chunk for the static_chunked scheduled loop.
+ /// \param DispatchValues struct containing llvm values for lower bound, upper
+ /// bound, and chunk expression.
/// For the default (nullptr) value, the chunk 1 will be used.
///
+ virtual void emitForDispatchInit(CodeGenFunction &CGF, SourceLocation Loc,
+ const OpenMPScheduleTy &ScheduleKind,
+ unsigned IVSize, bool IVSigned, bool Ordered,
+ const DispatchRTInput &DispatchValues);
+
+ /// Struct with the values to be passed to the static runtime function
+ struct StaticRTInput {
+ /// Size of the iteration variable in bits.
+ unsigned IVSize = 0;
+ /// Sign of the iteration variable.
+ bool IVSigned = false;
+ /// true if loop is ordered, false otherwise.
+ bool Ordered = false;
+ /// Address of the output variable in which the flag of the last iteration
+ /// is returned.
+ Address IL = Address::invalid();
+ /// Address of the output variable in which the lower iteration number is
+ /// returned.
+ Address LB = Address::invalid();
+ /// Address of the output variable in which the upper iteration number is
+ /// returned.
+ Address UB = Address::invalid();
+ /// Address of the output variable in which the stride value is returned
+ /// necessary to generated the static_chunked scheduled loop.
+ Address ST = Address::invalid();
+ /// Value of the chunk for the static_chunked scheduled loop. For the
+ /// default (nullptr) value, the chunk 1 will be used.
+ llvm::Value *Chunk = nullptr;
+ StaticRTInput(unsigned IVSize, bool IVSigned, bool Ordered, Address IL,
+ Address LB, Address UB, Address ST,
+ llvm::Value *Chunk = nullptr)
+ : IVSize(IVSize), IVSigned(IVSigned), Ordered(Ordered), IL(IL), LB(LB),
+ UB(UB), ST(ST), Chunk(Chunk) {}
+ };
+ /// \brief Call the appropriate runtime routine to initialize it before start
+ /// of loop.
+ ///
+ /// This is used only in case of static schedule, when the user did not
+ /// specify a ordered clause on the loop construct.
+ /// Depending on the loop schedule, it is necessary to call some runtime
+ /// routine before start of the OpenMP loop to get the loop upper / lower
+ /// bounds LB and UB and stride ST.
+ ///
+ /// \param CGF Reference to current CodeGenFunction.
+ /// \param Loc Clang source location.
+ /// \param DKind Kind of the directive.
+ /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
+ /// \param Values Input arguments for the construct.
+ ///
virtual void emitForStaticInit(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPDirectiveKind DKind,
const OpenMPScheduleTy &ScheduleKind,
- unsigned IVSize, bool IVSigned, bool Ordered,
- Address IL, Address LB, Address UB, Address ST,
- llvm::Value *Chunk = nullptr);
+ const StaticRTInput &Values);
///
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
/// \param SchedKind Schedule kind, specified by the 'dist_schedule' clause.
- /// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
- /// \param Ordered true if loop is ordered, false otherwise.
- /// \param IL Address of the output variable in which the flag of the
- /// last iteration is returned.
- /// \param LB Address of the output variable in which the lower iteration
- /// number is returned.
- /// \param UB Address of the output variable in which the upper iteration
- /// number is returned.
- /// \param ST Address of the output variable in which the stride value is
- /// returned nesessary to generated the static_chunked scheduled loop.
- /// \param Chunk Value of the chunk for the static_chunked scheduled loop.
- /// For the default (nullptr) value, the chunk 1 will be used.
+ /// \param Values Input arguments for the construct.
///
- virtual void emitDistributeStaticInit(CodeGenFunction &CGF, SourceLocation Loc,
+ virtual void emitDistributeStaticInit(CodeGenFunction &CGF,
+ SourceLocation Loc,
OpenMPDistScheduleClauseKind SchedKind,
- unsigned IVSize, bool IVSigned,
- bool Ordered, Address IL, Address LB,
- Address UB, Address ST,
- llvm::Value *Chunk = nullptr);
+ const StaticRTInput &Values);
/// \brief Call the appropriate runtime routine to notify that we finished
/// iteration of the ordered loop with the dynamic scheduling.
@@ -739,7 +876,7 @@ public:
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
/// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
+ /// \param IVSigned Sign of the iteration variable.
///
virtual void emitForOrderedIterationEnd(CodeGenFunction &CGF,
SourceLocation Loc, unsigned IVSize,
@@ -750,15 +887,17 @@ public:
///
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
+ /// \param DKind Kind of the directive for which the static finish is emitted.
///
- virtual void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc);
+ virtual void emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPDirectiveKind DKind);
/// Call __kmpc_dispatch_next(
/// ident_t *loc, kmp_int32 tid, kmp_int32 *p_lastiter,
/// kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
/// kmp_int[32|64] *p_stride);
/// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
+ /// \param IVSigned Sign of the iteration variable.
/// \param IL Address of the output variable in which the flag of the
/// last iteration is returned.
/// \param LB Address of the output variable in which the lower iteration
@@ -810,6 +949,14 @@ public:
SourceLocation Loc, bool PerformInit,
CodeGenFunction *CGF = nullptr);
+ /// Creates artificial threadprivate variable with name \p Name and type \p
+ /// VarType.
+ /// \param VarType Type of the artificial threadprivate variable.
+ /// \param Name Name of the artificial threadprivate variable.
+ virtual Address getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
+ QualType VarType,
+ StringRef Name);
+
/// \brief Emit flush of the variables specified in 'omp flush' directive.
/// \param Vars List of variables to flush.
virtual void emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *> Vars,
@@ -968,6 +1115,51 @@ public:
ArrayRef<const Expr *> ReductionOps,
ReductionOptionsTy Options);
+ /// Emit a code for initialization of task reduction clause. Next code
+ /// should be emitted for reduction:
+ /// \code
+ ///
+ /// _task_red_item_t red_data[n];
+ /// ...
+ /// red_data[i].shar = &origs[i];
+ /// red_data[i].size = sizeof(origs[i]);
+ /// red_data[i].f_init = (void*)RedInit<i>;
+ /// red_data[i].f_fini = (void*)RedDest<i>;
+ /// red_data[i].f_comb = (void*)RedOp<i>;
+ /// red_data[i].flags = <Flag_i>;
+ /// ...
+ /// void* tg1 = __kmpc_task_reduction_init(gtid, n, red_data);
+ /// \endcode
+ ///
+ /// \param LHSExprs List of LHS in \a Data.ReductionOps reduction operations.
+ /// \param RHSExprs List of RHS in \a Data.ReductionOps reduction operations.
+ /// \param Data Additional data for task generation like tiedness, final
+ /// state, list of privates, reductions etc.
+ virtual llvm::Value *emitTaskReductionInit(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ const OMPTaskDataTy &Data);
+
+ /// Required to resolve existing problems in the runtime. Emits threadprivate
+ /// variables to store the size of the VLAs/array sections for
+ /// initializer/combiner/finalizer functions + emits threadprivate variable to
+ /// store the pointer to the original reduction item for the custom
+ /// initializer defined by declare reduction construct.
+ /// \param RCG Allows to reuse an existing data for the reductions.
+ /// \param N Reduction item for which fixups must be emitted.
+ virtual void emitTaskReductionFixups(CodeGenFunction &CGF, SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N);
+
+ /// Get the address of `void *` type of the privatue copy of the reduction
+ /// item specified by the \p SharedLVal.
+ /// \param ReductionsPtr Pointer to the reduction data returned by the
+ /// emitTaskReductionInit function.
+ /// \param SharedLVal Address of the original reduction item.
+ virtual Address getTaskReductionItem(CodeGenFunction &CGF, SourceLocation Loc,
+ llvm::Value *ReductionsPtr,
+ LValue SharedLVal);
+
/// \brief Emit code for 'taskwait' directive.
virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc);
@@ -995,7 +1187,7 @@ public:
/// \param OutlinedFnID Outlined function ID value to be defined by this call.
/// \param IsOffloadEntry True if the outlined function is an offload entry.
/// \param CodeGen Code generation sequence for the \a D directive.
- /// An oulined function may not be an entry if, e.g. the if clause always
+ /// An outlined function may not be an entry if, e.g. the if clause always
/// evaluates to false.
virtual void emitTargetOutlinedFunction(const OMPExecutableDirective &D,
StringRef ParentName,
@@ -1034,7 +1226,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);
@@ -1146,6 +1338,30 @@ public:
/// \param C 'depend' clause with 'sink|source' dependency kind.
virtual void emitDoacrossOrdered(CodeGenFunction &CGF,
const OMPDependClause *C);
+
+ /// Translates the native parameter of outlined function if this is required
+ /// for target.
+ /// \param FD Field decl from captured record for the paramater.
+ /// \param NativeParam Parameter itself.
+ virtual const VarDecl *translateParameter(const FieldDecl *FD,
+ const VarDecl *NativeParam) const {
+ return NativeParam;
+ }
+
+ /// Gets the address of the native argument basing on the address of the
+ /// target-specific parameter.
+ /// \param NativeParam Parameter itself.
+ /// \param TargetParam Corresponding target-specific parameter.
+ virtual Address getParameterAddress(CodeGenFunction &CGF,
+ const VarDecl *NativeParam,
+ const VarDecl *TargetParam) const;
+
+ /// Emits call of the outlined function with the provided arguments,
+ /// translating these arguments to correct target-specific arguments.
+ virtual void
+ emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ ArrayRef<llvm::Value *> Args = llvm::None) const;
};
} // namespace CodeGen
diff --git a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
index c3391d087b..884bcc1c2d 100644
--- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
+++ b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
@@ -150,20 +150,18 @@ enum NamedBarrier : unsigned {
/// Get the GPU warp size.
static llvm::Value *getNVPTXWarpSize(CodeGenFunction &CGF) {
- CGBuilderTy &Bld = CGF.Builder;
- return Bld.CreateCall(
+ return CGF.EmitRuntimeCall(
llvm::Intrinsic::getDeclaration(
&CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_warpsize),
- llvm::None, "nvptx_warp_size");
+ "nvptx_warp_size");
}
/// Get the id of the current thread on the GPU.
static llvm::Value *getNVPTXThreadID(CodeGenFunction &CGF) {
- CGBuilderTy &Bld = CGF.Builder;
- return Bld.CreateCall(
+ return CGF.EmitRuntimeCall(
llvm::Intrinsic::getDeclaration(
&CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_tid_x),
- llvm::None, "nvptx_tid");
+ "nvptx_tid");
}
/// Get the id of the warp in the block.
@@ -185,17 +183,15 @@ static llvm::Value *getNVPTXLaneID(CodeGenFunction &CGF) {
/// Get the maximum number of threads in a block of the GPU.
static llvm::Value *getNVPTXNumThreads(CodeGenFunction &CGF) {
- CGBuilderTy &Bld = CGF.Builder;
- return Bld.CreateCall(
+ return CGF.EmitRuntimeCall(
llvm::Intrinsic::getDeclaration(
&CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_ntid_x),
- llvm::None, "nvptx_num_threads");
+ "nvptx_num_threads");
}
/// Get barrier to synchronize all threads in a block.
static void getNVPTXCTABarrier(CodeGenFunction &CGF) {
- CGBuilderTy &Bld = CGF.Builder;
- Bld.CreateCall(llvm::Intrinsic::getDeclaration(
+ CGF.EmitRuntimeCall(llvm::Intrinsic::getDeclaration(
&CGF.CGM.getModule(), llvm::Intrinsic::nvvm_barrier0));
}
@@ -205,9 +201,9 @@ 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);
+ CGF.EmitRuntimeCall(llvm::Intrinsic::getDeclaration(
+ &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_barrier),
+ Args);
}
/// Synchronize all GPU threads in a block.
@@ -345,7 +341,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericEntryHeader(CodeGenFunction &CGF,
Bld.CreateCondBr(IsWorker, WorkerBB, MasterCheckBB);
CGF.EmitBlock(WorkerBB);
- CGF.EmitCallOrInvoke(WST.WorkerFn, llvm::None);
+ emitCall(CGF, WST.WorkerFn);
CGF.EmitBranch(EST.ExitBB);
CGF.EmitBlock(MasterCheckBB);
@@ -555,7 +551,7 @@ void CGOpenMPRuntimeNVPTX::emitWorkerLoop(CodeGenFunction &CGF,
CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".zero.addr");
CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C=*/0));
llvm::Value *FnArgs[] = {ZeroAddr.getPointer(), ZeroAddr.getPointer()};
- CGF.EmitCallOrInvoke(Fn, FnArgs);
+ emitCall(CGF, Fn, FnArgs);
// Go to end of parallel region.
CGF.EmitBranch(TerminateBB);
@@ -861,6 +857,7 @@ llvm::Value *CGOpenMPRuntimeNVPTX::emitTeamsOutlinedFunction(
D, ThreadIDVar, InnermostKind, CodeGen);
llvm::Function *OutlinedFun = cast<llvm::Function>(OutlinedFunVal);
OutlinedFun->removeFnAttr(llvm::Attribute::NoInline);
+ OutlinedFun->removeFnAttr(llvm::Attribute::OptimizeNone);
OutlinedFun->addFnAttr(llvm::Attribute::AlwaysInline);
return OutlinedFun;
@@ -882,7 +879,7 @@ void CGOpenMPRuntimeNVPTX::emitTeamsCall(CodeGenFunction &CGF,
OutlinedFnArgs.push_back(ZeroAddr.getPointer());
OutlinedFnArgs.push_back(ZeroAddr.getPointer());
OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs);
+ emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
}
void CGOpenMPRuntimeNVPTX::emitParallelCall(
@@ -931,10 +928,10 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall(
auto *ThreadID = getThreadID(CGF, Loc);
llvm::Value *Args[] = {RTLoc, ThreadID};
- auto &&SeqGen = [this, Fn, &CapturedVars, &Args](CodeGenFunction &CGF,
- PrePostActionTy &) {
- auto &&CodeGen = [this, Fn, &CapturedVars](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
+ auto &&SeqGen = [this, Fn, &CapturedVars, &Args, Loc](CodeGenFunction &CGF,
+ PrePostActionTy &) {
+ auto &&CodeGen = [this, Fn, &CapturedVars, Loc](CodeGenFunction &CGF,
+ PrePostActionTy &Action) {
Action.Enter(CGF);
llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
@@ -943,7 +940,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall(
OutlinedFnArgs.push_back(
llvm::ConstantPointerNull::get(CGM.Int32Ty->getPointerTo()));
OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- CGF.EmitCallOrInvoke(Fn, OutlinedFnArgs);
+ emitOutlinedFunctionCall(CGF, Loc, Fn, OutlinedFnArgs);
};
RegionCodeGenTy RCG(CodeGen);
@@ -979,7 +976,7 @@ void CGOpenMPRuntimeNVPTX::emitSpmdParallelCall(
OutlinedFnArgs.push_back(
llvm::ConstantPointerNull::get(CGM.Int32Ty->getPointerTo()));
OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
- CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs);
+ emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
}
/// This function creates calls to one of two shuffle functions to copy
@@ -1243,32 +1240,27 @@ static void emitReductionListCopy(
/// local = local @ remote
/// else
/// local = remote
-llvm::Value *emitReduceScratchpadFunction(CodeGenModule &CGM,
- ArrayRef<const Expr *> Privates,
- QualType ReductionArrayTy,
- llvm::Value *ReduceFn) {
+static llvm::Value *
+emitReduceScratchpadFunction(CodeGenModule &CGM,
+ ArrayRef<const Expr *> Privates,
+ QualType ReductionArrayTy, llvm::Value *ReduceFn) {
auto &C = CGM.getContext();
auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true);
// Destination of the copy.
- ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.VoidPtrTy);
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
// Base address of the scratchpad array, with each element storing a
// Reduce list per team.
- ImplicitParamDecl ScratchPadArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.VoidPtrTy);
+ ImplicitParamDecl ScratchPadArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
// A source index into the scratchpad array.
- ImplicitParamDecl IndexArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, Int32Ty);
+ ImplicitParamDecl IndexArg(C, Int32Ty, ImplicitParamDecl::Other);
// Row width of an element in the scratchpad array, typically
// the number of teams.
- ImplicitParamDecl WidthArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, Int32Ty);
+ ImplicitParamDecl WidthArg(C, Int32Ty, ImplicitParamDecl::Other);
// If should_reduce == 1, then it's load AND reduce,
// If should_reduce == 0 (or otherwise), then it only loads (+ copy).
// The latter case is used for initialization.
- ImplicitParamDecl ShouldReduceArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, Int32Ty);
+ ImplicitParamDecl ShouldReduceArg(C, Int32Ty, ImplicitParamDecl::Other);
FunctionArgList Args;
Args.push_back(&ReduceListArg);
@@ -1372,28 +1364,24 @@ llvm::Value *emitReduceScratchpadFunction(CodeGenModule &CGM,
/// for elem in Reduce List:
/// scratchpad[elem_id][index] = elem
///
-llvm::Value *emitCopyToScratchpad(CodeGenModule &CGM,
- ArrayRef<const Expr *> Privates,
- QualType ReductionArrayTy) {
+static llvm::Value *emitCopyToScratchpad(CodeGenModule &CGM,
+ ArrayRef<const Expr *> Privates,
+ QualType ReductionArrayTy) {
auto &C = CGM.getContext();
auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true);
// Source of the copy.
- ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.VoidPtrTy);
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
// Base address of the scratchpad array, with each element storing a
// Reduce list per team.
- ImplicitParamDecl ScratchPadArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.VoidPtrTy);
+ ImplicitParamDecl ScratchPadArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
// A destination index into the scratchpad array, typically the team
// identifier.
- ImplicitParamDecl IndexArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, Int32Ty);
+ ImplicitParamDecl IndexArg(C, Int32Ty, ImplicitParamDecl::Other);
// Row width of an element in the scratchpad array, typically
// the number of teams.
- ImplicitParamDecl WidthArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, Int32Ty);
+ ImplicitParamDecl WidthArg(C, Int32Ty, ImplicitParamDecl::Other);
FunctionArgList Args;
Args.push_back(&ReduceListArg);
@@ -1474,13 +1462,12 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM,
// 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);
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
// NumWarps: number of warps active in the parallel region. This could
// be smaller than 32 (max warps in a CTA) for partial block reduction.
- ImplicitParamDecl NumWarpsArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr,
- C.getIntTypeForBitwidth(32, /* Signed */ true));
+ ImplicitParamDecl NumWarpsArg(C,
+ C.getIntTypeForBitwidth(32, /* Signed */ true),
+ ImplicitParamDecl::Other);
FunctionArgList Args;
Args.push_back(&ReduceListArg);
Args.push_back(&NumWarpsArg);
@@ -1722,17 +1709,14 @@ emitShuffleAndReduceFunction(CodeGenModule &CGM,
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);
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
// Current lane id; could be logical.
- ImplicitParamDecl LaneIDArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.ShortTy);
+ ImplicitParamDecl LaneIDArg(C, C.ShortTy, ImplicitParamDecl::Other);
// Offset of the remote source lane relative to the current lane.
- ImplicitParamDecl RemoteLaneOffsetArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.ShortTy);
+ ImplicitParamDecl RemoteLaneOffsetArg(C, C.ShortTy,
+ ImplicitParamDecl::Other);
// Algorithm version. This is expected to be known at compile time.
- ImplicitParamDecl AlgoVerArg(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.ShortTy);
+ ImplicitParamDecl AlgoVerArg(C, C.ShortTy, ImplicitParamDecl::Other);
FunctionArgList Args;
Args.push_back(&ReduceListArg);
Args.push_back(&LaneIDArg);
@@ -2250,3 +2234,86 @@ void CGOpenMPRuntimeNVPTX::emitReduction(
CGF.EmitBranch(DefaultBB);
CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
}
+
+const VarDecl *
+CGOpenMPRuntimeNVPTX::translateParameter(const FieldDecl *FD,
+ const VarDecl *NativeParam) const {
+ if (!NativeParam->getType()->isReferenceType())
+ return NativeParam;
+ QualType ArgType = NativeParam->getType();
+ QualifierCollector QC;
+ const Type *NonQualTy = QC.strip(ArgType);
+ QualType PointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType();
+ if (const auto *Attr = FD->getAttr<OMPCaptureKindAttr>()) {
+ if (Attr->getCaptureKind() == OMPC_map) {
+ PointeeTy = CGM.getContext().getAddrSpaceQualType(PointeeTy,
+ LangAS::opencl_global);
+ }
+ }
+ ArgType = CGM.getContext().getPointerType(PointeeTy);
+ QC.addRestrict();
+ enum { NVPTX_local_addr = 5 };
+ QC.addAddressSpace(getLangASFromTargetAS(NVPTX_local_addr));
+ ArgType = QC.apply(CGM.getContext(), ArgType);
+ return ImplicitParamDecl::Create(
+ CGM.getContext(), /*DC=*/nullptr, NativeParam->getLocation(),
+ NativeParam->getIdentifier(), ArgType, ImplicitParamDecl::Other);
+}
+
+Address
+CGOpenMPRuntimeNVPTX::getParameterAddress(CodeGenFunction &CGF,
+ const VarDecl *NativeParam,
+ const VarDecl *TargetParam) const {
+ assert(NativeParam != TargetParam &&
+ NativeParam->getType()->isReferenceType() &&
+ "Native arg must not be the same as target arg.");
+ Address LocalAddr = CGF.GetAddrOfLocalVar(TargetParam);
+ QualType NativeParamType = NativeParam->getType();
+ QualifierCollector QC;
+ const Type *NonQualTy = QC.strip(NativeParamType);
+ QualType NativePointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType();
+ unsigned NativePointeeAddrSpace =
+ CGF.getContext().getTargetAddressSpace(NativePointeeTy);
+ QualType TargetTy = TargetParam->getType();
+ llvm::Value *TargetAddr = CGF.EmitLoadOfScalar(
+ LocalAddr, /*Volatile=*/false, TargetTy, SourceLocation());
+ // First cast to generic.
+ TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo(
+ /*AddrSpace=*/0));
+ // Cast from generic to native address space.
+ TargetAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ TargetAddr, TargetAddr->getType()->getPointerElementType()->getPointerTo(
+ NativePointeeAddrSpace));
+ Address NativeParamAddr = CGF.CreateMemTemp(NativeParamType);
+ CGF.EmitStoreOfScalar(TargetAddr, NativeParamAddr, /*Volatile=*/false,
+ NativeParamType);
+ return NativeParamAddr;
+}
+
+void CGOpenMPRuntimeNVPTX::emitOutlinedFunctionCall(
+ CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
+ ArrayRef<llvm::Value *> Args) const {
+ SmallVector<llvm::Value *, 4> TargetArgs;
+ TargetArgs.reserve(Args.size());
+ auto *FnType =
+ cast<llvm::FunctionType>(OutlinedFn->getType()->getPointerElementType());
+ for (unsigned I = 0, E = Args.size(); I < E; ++I) {
+ if (FnType->isVarArg() && FnType->getNumParams() <= I) {
+ TargetArgs.append(std::next(Args.begin(), I), Args.end());
+ break;
+ }
+ llvm::Type *TargetType = FnType->getParamType(I);
+ llvm::Value *NativeArg = Args[I];
+ if (!TargetType->isPointerTy()) {
+ TargetArgs.emplace_back(NativeArg);
+ continue;
+ }
+ llvm::Value *TargetArg = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ NativeArg, NativeArg->getType()->getPointerElementType()->getPointerTo(
+ /*AddrSpace=*/0));
+ TargetArgs.emplace_back(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TargetArg, TargetType));
+ }
+ CGOpenMPRuntime::emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, TargetArgs);
+}
diff --git a/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
index ae25e94759..a9d6386e6b 100644
--- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
+++ b/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
@@ -268,6 +268,26 @@ public:
/// \return Specified function.
llvm::Constant *createNVPTXRuntimeFunction(unsigned Function);
+ /// Translates the native parameter of outlined function if this is required
+ /// for target.
+ /// \param FD Field decl from captured record for the paramater.
+ /// \param NativeParam Parameter itself.
+ const VarDecl *translateParameter(const FieldDecl *FD,
+ const VarDecl *NativeParam) const override;
+
+ /// Gets the address of the native argument basing on the address of the
+ /// target-specific parameter.
+ /// \param NativeParam Parameter itself.
+ /// \param TargetParam Corresponding target-specific parameter.
+ Address getParameterAddress(CodeGenFunction &CGF, const VarDecl *NativeParam,
+ const VarDecl *TargetParam) const override;
+
+ /// Emits call of the outlined function with the provided arguments,
+ /// translating these arguments to correct target-specific arguments.
+ void emitOutlinedFunctionCall(
+ CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
+ ArrayRef<llvm::Value *> Args = llvm::None) const override;
+
/// 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.
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 7d530a278f..1644ab4c07 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -403,6 +403,27 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
}
return;
}
+
+ // Check if current Field is better as a single field run. When current field
+ // has legal integer width, and its bitfield offset is naturally aligned, it
+ // is better to make the bitfield a separate storage component so as it can be
+ // accessed directly with lower cost.
+ auto IsBetterAsSingleFieldRun = [&](RecordDecl::field_iterator Field) {
+ if (!Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
+ return false;
+ unsigned Width = Field->getBitWidthValue(Context);
+ if (!DataLayout.isLegalInteger(Width))
+ return false;
+ // Make sure Field is natually aligned if it is treated as an IType integer.
+ if (getFieldBitOffset(*Field) %
+ Context.toBits(getAlignment(getIntNType(Width))) !=
+ 0)
+ return false;
+ return true;
+ };
+
+ // The start field is better as a single field run.
+ bool StartFieldAsSingleRun = false;
for (;;) {
// Check to see if we need to start a new run.
if (Run == FieldEnd) {
@@ -414,17 +435,28 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
Run = Field;
StartBitOffset = getFieldBitOffset(*Field);
Tail = StartBitOffset + Field->getBitWidthValue(Context);
+ StartFieldAsSingleRun = IsBetterAsSingleFieldRun(Run);
}
++Field;
continue;
}
- // Add bitfields to the run as long as they qualify.
- if (Field != FieldEnd && Field->getBitWidthValue(Context) != 0 &&
+
+ // If the start field of a new run is better as a single run, or
+ // if current field is better as a single run, or
+ // if current field has zero width bitfield, or
+ // if the offset of current field is inconsistent with the offset of
+ // previous field plus its offset,
+ // skip the block below and go ahead to emit the storage.
+ // Otherwise, try to add bitfields to the run.
+ if (!StartFieldAsSingleRun && Field != FieldEnd &&
+ !IsBetterAsSingleFieldRun(Field) &&
+ Field->getBitWidthValue(Context) != 0 &&
Tail == getFieldBitOffset(*Field)) {
Tail += Field->getBitWidthValue(Context);
++Field;
continue;
}
+
// We've hit a break-point in the run and need to emit a storage field.
llvm::Type *Type = getIntNType(Tail - StartBitOffset);
// Add the storage member to the record and set the bitfield info for all of
@@ -435,6 +467,7 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset),
MemberInfo::Field, nullptr, *Run));
Run = FieldEnd;
+ StartFieldAsSingleRun = false;
}
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 9c92367410..6a78865fc9 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -45,7 +45,7 @@ void CodeGenFunction::EmitStopPoint(const Stmt *S) {
}
}
-void CodeGenFunction::EmitStmt(const Stmt *S) {
+void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
assert(S && "Null statement?");
PGO.setCurrentStmt(S);
@@ -131,16 +131,16 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::IndirectGotoStmtClass:
EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break;
- case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
- case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S)); break;
- case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S)); break;
- case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S)); break;
+ case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
+ case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S), Attrs); break;
+ case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S), Attrs); break;
+ case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S), Attrs); break;
- case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
+ case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
- case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
- case Stmt::GCCAsmStmtClass: // Intentional fall-through.
- case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
+ case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
+ case Stmt::GCCAsmStmtClass: // Intentional fall-through.
+ case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
case Stmt::CoroutineBodyStmtClass:
EmitCoroutineBody(cast<CoroutineBodyStmt>(*S));
break;
@@ -178,7 +178,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
EmitCXXTryStmt(cast<CXXTryStmt>(*S));
break;
case Stmt::CXXForRangeStmtClass:
- EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S));
+ EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S), Attrs);
break;
case Stmt::SEHTryStmtClass:
EmitSEHTryStmt(cast<SEHTryStmt>(*S));
@@ -555,23 +555,7 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
}
void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
- const Stmt *SubStmt = S.getSubStmt();
- switch (SubStmt->getStmtClass()) {
- case Stmt::DoStmtClass:
- EmitDoStmt(cast<DoStmt>(*SubStmt), S.getAttrs());
- break;
- case Stmt::ForStmtClass:
- EmitForStmt(cast<ForStmt>(*SubStmt), S.getAttrs());
- break;
- case Stmt::WhileStmtClass:
- EmitWhileStmt(cast<WhileStmt>(*SubStmt), S.getAttrs());
- break;
- case Stmt::CXXForRangeStmtClass:
- EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*SubStmt), S.getAttrs());
- break;
- default:
- EmitStmt(SubStmt);
- }
+ EmitStmt(S.getSubStmt(), S.getAttrs());
}
void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
@@ -1024,6 +1008,18 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
/// if the function returns void, or may be missing one if the function returns
/// non-void. Fun stuff :).
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+ if (requiresReturnValueCheck()) {
+ llvm::Constant *SLoc = EmitCheckSourceLocation(S.getLocStart());
+ auto *SLocPtr =
+ new llvm::GlobalVariable(CGM.getModule(), SLoc->getType(), false,
+ llvm::GlobalVariable::PrivateLinkage, SLoc);
+ SLocPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
+ CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
+ assert(ReturnLocation.isValid() && "No valid return location");
+ Builder.CreateStore(Builder.CreateBitCast(SLocPtr, Int8PtrTy),
+ ReturnLocation);
+ }
+
// Returning from an outlined SEH helper is UB, and we already warn on it.
if (IsOutlinedSEHHelper) {
Builder.CreateUnreachable();
@@ -1166,7 +1162,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
if (Rem)
Rem--;
SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
- LHS++;
+ ++LHS;
}
return;
}
@@ -2127,16 +2123,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 +2153,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);
}
@@ -2198,7 +2194,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize));
Tmp = Builder.CreateTrunc(Tmp, TruncTy);
} else if (TruncTy->isIntegerTy()) {
- Tmp = Builder.CreateTrunc(Tmp, TruncTy);
+ Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
} else if (TruncTy->isVectorTy()) {
Tmp = Builder.CreateBitCast(Tmp, TruncTy);
}
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index 2f64da2912..df7f7802d3 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -65,6 +65,8 @@ public:
for (auto &C : CS->captures()) {
if (C.capturesVariable() || C.capturesVariableByCopy()) {
auto *VD = C.getCapturedVar();
+ assert(VD == VD->getCanonicalDecl() &&
+ "Canonical decl must be captured.");
DeclRefExpr DRE(const_cast<VarDecl *>(VD),
isCapturedVar(CGF, VD) ||
(CGF.CapturedStmtInfo &&
@@ -87,7 +89,8 @@ public:
class OMPParallelScope final : public OMPLexicalScope {
bool EmitPreInitStmt(const OMPExecutableDirective &S) {
OpenMPDirectiveKind Kind = S.getDirectiveKind();
- return !isOpenMPTargetExecutionDirective(Kind) &&
+ return !(isOpenMPTargetExecutionDirective(Kind) ||
+ isOpenMPLoopBoundSharingDirective(Kind)) &&
isOpenMPParallelDirective(Kind);
}
@@ -135,6 +138,22 @@ public:
} // namespace
+LValue CodeGenFunction::EmitOMPSharedLValue(const Expr *E) {
+ if (auto *OrigDRE = dyn_cast<DeclRefExpr>(E)) {
+ if (auto *OrigVD = dyn_cast<VarDecl>(OrigDRE->getDecl())) {
+ OrigVD = OrigVD->getCanonicalDecl();
+ bool IsCaptured =
+ LambdaCaptureFields.lookup(OrigVD) ||
+ (CapturedStmtInfo && CapturedStmtInfo->lookup(OrigVD)) ||
+ (CurCodeDecl && isa<BlockDecl>(CurCodeDecl));
+ DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD), IsCaptured,
+ OrigDRE->getType(), VK_LValue, OrigDRE->getExprLoc());
+ return EmitLValue(&DRE);
+ }
+ }
+ return EmitLValue(E);
+}
+
llvm::Value *CodeGenFunction::getTypeSize(QualType Ty) {
auto &C = getContext();
llvm::Value *Size = nullptr;
@@ -227,21 +246,67 @@ static Address castValueFromUintptr(CodeGenFunction &CGF, QualType DstType,
return TmpAddr;
}
-llvm::Function *
-CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
- assert(
- CapturedStmtInfo &&
- "CapturedStmtInfo should be set when generating the captured function");
- const CapturedDecl *CD = S.getCapturedDecl();
- const RecordDecl *RD = S.getCapturedRecordDecl();
+static QualType getCanonicalParamType(ASTContext &C, QualType T) {
+ if (T->isLValueReferenceType()) {
+ return C.getLValueReferenceType(
+ getCanonicalParamType(C, T.getNonReferenceType()),
+ /*SpelledAsLValue=*/false);
+ }
+ if (T->isPointerType())
+ return C.getPointerType(getCanonicalParamType(C, T->getPointeeType()));
+ if (auto *A = T->getAsArrayTypeUnsafe()) {
+ if (auto *VLA = dyn_cast<VariableArrayType>(A))
+ return getCanonicalParamType(C, VLA->getElementType());
+ else if (!A->isVariablyModifiedType())
+ return C.getCanonicalType(T);
+ }
+ return C.getCanonicalParamType(T);
+}
+
+namespace {
+ /// Contains required data for proper outlined function codegen.
+ struct FunctionOptions {
+ /// Captured statement for which the function is generated.
+ const CapturedStmt *S = nullptr;
+ /// true if cast to/from UIntPtr is required for variables captured by
+ /// value.
+ const bool UIntPtrCastRequired = true;
+ /// true if only casted arguments must be registered as local args or VLA
+ /// sizes.
+ const bool RegisterCastedArgsOnly = false;
+ /// Name of the generated function.
+ const StringRef FunctionName;
+ explicit FunctionOptions(const CapturedStmt *S, bool UIntPtrCastRequired,
+ bool RegisterCastedArgsOnly,
+ StringRef FunctionName)
+ : S(S), UIntPtrCastRequired(UIntPtrCastRequired),
+ RegisterCastedArgsOnly(UIntPtrCastRequired && RegisterCastedArgsOnly),
+ FunctionName(FunctionName) {}
+ };
+}
+
+static llvm::Function *emitOutlinedFunctionPrologue(
+ CodeGenFunction &CGF, FunctionArgList &Args,
+ llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>>
+ &LocalAddrs,
+ llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>>
+ &VLASizes,
+ llvm::Value *&CXXThisValue, const FunctionOptions &FO) {
+ const CapturedDecl *CD = FO.S->getCapturedDecl();
+ const RecordDecl *RD = FO.S->getCapturedRecordDecl();
assert(CD->hasBody() && "missing CapturedDecl body");
+ CXXThisValue = nullptr;
// Build the argument list.
+ CodeGenModule &CGM = CGF.CGM;
ASTContext &Ctx = CGM.getContext();
- FunctionArgList Args;
+ FunctionArgList TargetArgs;
Args.append(CD->param_begin(),
std::next(CD->param_begin(), CD->getContextParamPosition()));
- auto I = S.captures().begin();
+ TargetArgs.append(
+ CD->param_begin(),
+ std::next(CD->param_begin(), CD->getContextParamPosition()));
+ auto I = FO.S->captures().begin();
for (auto *FD : RD->fields()) {
QualType ArgType = FD->getType();
IdentifierInfo *II = nullptr;
@@ -253,124 +318,216 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
// deal with pointers. We can pass in the same way the VLA type sizes to the
// outlined function.
if ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) ||
- I->capturesVariableArrayType())
- ArgType = Ctx.getUIntPtrType();
+ I->capturesVariableArrayType()) {
+ if (FO.UIntPtrCastRequired)
+ ArgType = Ctx.getUIntPtrType();
+ }
if (I->capturesVariable() || I->capturesVariableByCopy()) {
CapVar = I->getCapturedVar();
II = CapVar->getIdentifier();
} else if (I->capturesThis())
- II = &getContext().Idents.get("this");
+ II = &Ctx.Idents.get("this");
else {
assert(I->capturesVariableArrayType());
- II = &getContext().Idents.get("vla");
- }
- if (ArgType->isVariablyModifiedType()) {
- bool IsReference = ArgType->isLValueReferenceType();
- ArgType =
- getContext().getCanonicalParamType(ArgType.getNonReferenceType());
- if (IsReference && !ArgType->isPointerType()) {
- ArgType = getContext().getLValueReferenceType(
- ArgType, /*SpelledAsLValue=*/false);
- }
+ II = &Ctx.Idents.get("vla");
}
- Args.push_back(ImplicitParamDecl::Create(getContext(), nullptr,
- FD->getLocation(), II, ArgType));
+ if (ArgType->isVariablyModifiedType())
+ ArgType = getCanonicalParamType(Ctx, ArgType);
+ auto *Arg =
+ ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(), II,
+ ArgType, ImplicitParamDecl::Other);
+ Args.emplace_back(Arg);
+ // Do not cast arguments if we emit function with non-original types.
+ TargetArgs.emplace_back(
+ FO.UIntPtrCastRequired
+ ? Arg
+ : CGM.getOpenMPRuntime().translateParameter(FD, Arg));
++I;
}
Args.append(
std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
CD->param_end());
+ TargetArgs.append(
+ std::next(CD->param_begin(), CD->getContextParamPosition() + 1),
+ CD->param_end());
// Create the function declaration.
FunctionType::ExtInfo ExtInfo;
const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, TargetArgs);
llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Function *F = llvm::Function::Create(
- FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
- CapturedStmtInfo->getHelperName(), &CGM.getModule());
+ llvm::Function *F =
+ llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
+ FO.FunctionName, &CGM.getModule());
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
if (CD->isNothrow())
- F->addFnAttr(llvm::Attribute::NoUnwind);
+ F->setDoesNotThrow();
// Generate the function.
- StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(),
- CD->getBody()->getLocStart());
+ CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, TargetArgs,
+ FO.S->getLocStart(), CD->getBody()->getLocStart());
unsigned Cnt = CD->getContextParamPosition();
- I = S.captures().begin();
+ I = FO.S->captures().begin();
for (auto *FD : RD->fields()) {
+ // Do not map arguments if we emit function with non-original types.
+ Address LocalAddr(Address::invalid());
+ if (!FO.UIntPtrCastRequired && Args[Cnt] != TargetArgs[Cnt]) {
+ LocalAddr = CGM.getOpenMPRuntime().getParameterAddress(CGF, Args[Cnt],
+ TargetArgs[Cnt]);
+ } else {
+ LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]);
+ }
// If we are capturing a pointer by copy we don't need to do anything, just
// use the value that we get from the arguments.
if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) {
const VarDecl *CurVD = I->getCapturedVar();
- Address LocalAddr = GetAddrOfLocalVar(Args[Cnt]);
// If the variable is a reference we need to materialize it here.
if (CurVD->getType()->isReferenceType()) {
- Address RefAddr = CreateMemTemp(CurVD->getType(), getPointerAlign(),
- ".materialized_ref");
- EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr, /*Volatile=*/false,
- CurVD->getType());
+ Address RefAddr = CGF.CreateMemTemp(
+ CurVD->getType(), CGM.getPointerAlign(), ".materialized_ref");
+ CGF.EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr,
+ /*Volatile=*/false, CurVD->getType());
LocalAddr = RefAddr;
}
- setAddrOfLocalVar(CurVD, LocalAddr);
+ if (!FO.RegisterCastedArgsOnly)
+ LocalAddrs.insert({Args[Cnt], {CurVD, LocalAddr}});
++Cnt;
++I;
continue;
}
- LValue ArgLVal =
- MakeAddrLValue(GetAddrOfLocalVar(Args[Cnt]), Args[Cnt]->getType(),
- AlignmentSource::Decl);
+ LValue ArgLVal = CGF.MakeAddrLValue(LocalAddr, Args[Cnt]->getType(),
+ AlignmentSource::Decl);
if (FD->hasCapturedVLAType()) {
- LValue CastedArgLVal =
- MakeAddrLValue(castValueFromUintptr(*this, FD->getType(),
- Args[Cnt]->getName(), ArgLVal),
- FD->getType(), AlignmentSource::Decl);
+ if (FO.UIntPtrCastRequired) {
+ ArgLVal = CGF.MakeAddrLValue(castValueFromUintptr(CGF, FD->getType(),
+ Args[Cnt]->getName(),
+ ArgLVal),
+ FD->getType(), AlignmentSource::Decl);
+ }
auto *ExprArg =
- EmitLoadOfLValue(CastedArgLVal, SourceLocation()).getScalarVal();
+ CGF.EmitLoadOfLValue(ArgLVal, SourceLocation()).getScalarVal();
auto VAT = FD->getCapturedVLAType();
- VLASizeMap[VAT->getSizeExpr()] = ExprArg;
+ VLASizes.insert({Args[Cnt], {VAT->getSizeExpr(), ExprArg}});
} else if (I->capturesVariable()) {
auto *Var = I->getCapturedVar();
QualType VarTy = Var->getType();
Address ArgAddr = ArgLVal.getAddress();
if (!VarTy->isReferenceType()) {
if (ArgLVal.getType()->isLValueReferenceType()) {
- ArgAddr = EmitLoadOfReference(
- ArgAddr, ArgLVal.getType()->castAs<ReferenceType>());
+ ArgAddr = CGF.EmitLoadOfReference(ArgLVal);
} else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) {
assert(ArgLVal.getType()->isPointerType());
- ArgAddr = EmitLoadOfPointer(
+ ArgAddr = CGF.EmitLoadOfPointer(
ArgAddr, ArgLVal.getType()->castAs<PointerType>());
}
}
- setAddrOfLocalVar(
- Var, Address(ArgAddr.getPointer(), getContext().getDeclAlign(Var)));
+ if (!FO.RegisterCastedArgsOnly) {
+ LocalAddrs.insert(
+ {Args[Cnt],
+ {Var, Address(ArgAddr.getPointer(), Ctx.getDeclAlign(Var))}});
+ }
} else if (I->capturesVariableByCopy()) {
assert(!FD->getType()->isAnyPointerType() &&
"Not expecting a captured pointer.");
auto *Var = I->getCapturedVar();
QualType VarTy = Var->getType();
- setAddrOfLocalVar(Var, castValueFromUintptr(*this, FD->getType(),
- Args[Cnt]->getName(), ArgLVal,
- VarTy->isReferenceType()));
+ LocalAddrs.insert(
+ {Args[Cnt],
+ {Var,
+ FO.UIntPtrCastRequired
+ ? castValueFromUintptr(CGF, FD->getType(), Args[Cnt]->getName(),
+ ArgLVal, VarTy->isReferenceType())
+ : ArgLVal.getAddress()}});
} else {
// If 'this' is captured, load it into CXXThisValue.
assert(I->capturesThis());
- CXXThisValue =
- EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation()).getScalarVal();
+ CXXThisValue = CGF.EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation())
+ .getScalarVal();
+ LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress()}});
}
++Cnt;
++I;
}
+ return F;
+}
+
+llvm::Function *
+CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
+ assert(
+ CapturedStmtInfo &&
+ "CapturedStmtInfo should be set when generating the captured function");
+ const CapturedDecl *CD = S.getCapturedDecl();
+ // Build the argument list.
+ bool NeedWrapperFunction =
+ getDebugInfo() &&
+ CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo;
+ FunctionArgList Args;
+ llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs;
+ llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes;
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ Out << CapturedStmtInfo->getHelperName();
+ if (NeedWrapperFunction)
+ Out << "_debug__";
+ FunctionOptions FO(&S, !NeedWrapperFunction, /*RegisterCastedArgsOnly=*/false,
+ Out.str());
+ llvm::Function *F = emitOutlinedFunctionPrologue(*this, Args, LocalAddrs,
+ VLASizes, CXXThisValue, FO);
+ for (const auto &LocalAddrPair : LocalAddrs) {
+ if (LocalAddrPair.second.first) {
+ setAddrOfLocalVar(LocalAddrPair.second.first,
+ LocalAddrPair.second.second);
+ }
+ }
+ for (const auto &VLASizePair : VLASizes)
+ VLASizeMap[VLASizePair.second.first] = VLASizePair.second.second;
PGO.assignRegionCounters(GlobalDecl(CD), F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
-
- return F;
+ if (!NeedWrapperFunction)
+ return F;
+
+ FunctionOptions WrapperFO(&S, /*UIntPtrCastRequired=*/true,
+ /*RegisterCastedArgsOnly=*/true,
+ CapturedStmtInfo->getHelperName());
+ CodeGenFunction WrapperCGF(CGM, /*suppressNewContext=*/true);
+ Args.clear();
+ LocalAddrs.clear();
+ VLASizes.clear();
+ llvm::Function *WrapperF =
+ emitOutlinedFunctionPrologue(WrapperCGF, Args, LocalAddrs, VLASizes,
+ WrapperCGF.CXXThisValue, WrapperFO);
+ llvm::SmallVector<llvm::Value *, 4> CallArgs;
+ for (const auto *Arg : Args) {
+ llvm::Value *CallArg;
+ auto I = LocalAddrs.find(Arg);
+ if (I != LocalAddrs.end()) {
+ LValue LV = WrapperCGF.MakeAddrLValue(
+ I->second.second,
+ I->second.first ? I->second.first->getType() : Arg->getType(),
+ AlignmentSource::Decl);
+ CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation());
+ } else {
+ auto EI = VLASizes.find(Arg);
+ if (EI != VLASizes.end())
+ CallArg = EI->second.second;
+ else {
+ LValue LV = WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg),
+ Arg->getType(),
+ AlignmentSource::Decl);
+ CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation());
+ }
+ }
+ CallArgs.emplace_back(WrapperCGF.EmitFromMemory(CallArg, Arg->getType()));
+ }
+ CGM.getOpenMPRuntime().emitOutlinedFunctionCall(WrapperCGF, S.getLocStart(),
+ F, CallArgs);
+ WrapperCGF.FinishFunction();
+ return WrapperF;
}
//===----------------------------------------------------------------------===//
@@ -437,156 +594,6 @@ void CodeGenFunction::EmitOMPAggregateAssign(
EmitBlock(DoneBB, /*IsFinished=*/true);
}
-/// Check if the combiner is a call to UDR combiner and if it is so return the
-/// UDR decl used for reduction.
-static const OMPDeclareReductionDecl *
-getReductionInit(const Expr *ReductionOp) {
- if (auto *CE = dyn_cast<CallExpr>(ReductionOp))
- if (auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
- if (auto *DRE =
- dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
- if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
- return DRD;
- return nullptr;
-}
-
-static void emitInitWithReductionInitializer(CodeGenFunction &CGF,
- const OMPDeclareReductionDecl *DRD,
- const Expr *InitOp,
- Address Private, Address Original,
- QualType Ty) {
- if (DRD->getInitializer()) {
- std::pair<llvm::Function *, llvm::Function *> Reduction =
- CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
- auto *CE = cast<CallExpr>(InitOp);
- auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
- const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
- const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
- auto *LHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
- auto *RHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()),
- [=]() -> Address { return Private; });
- PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()),
- [=]() -> Address { return Original; });
- (void)PrivateScope.Privatize();
- RValue Func = RValue::get(Reduction.second);
- CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
- CGF.EmitIgnoredExpr(InitOp);
- } else {
- llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
- auto *GV = new llvm::GlobalVariable(
- CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Init, ".init");
- LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty);
- RValue InitRVal;
- switch (CGF.getEvaluationKind(Ty)) {
- case TEK_Scalar:
- InitRVal = CGF.EmitLoadOfLValue(LV, SourceLocation());
- break;
- case TEK_Complex:
- InitRVal =
- RValue::getComplex(CGF.EmitLoadOfComplex(LV, SourceLocation()));
- break;
- case TEK_Aggregate:
- InitRVal = RValue::getAggregate(LV.getAddress());
- break;
- }
- OpaqueValueExpr OVE(SourceLocation(), Ty, VK_RValue);
- CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
- CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
- /*IsInitializer=*/false);
- }
-}
-
-/// \brief Emit initialization of arrays of complex types.
-/// \param DestAddr Address of the array.
-/// \param Type Type of array.
-/// \param Init Initial expression of array.
-/// \param SrcAddr Address of the original array.
-static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
- QualType Type, const Expr *Init,
- Address SrcAddr = Address::invalid()) {
- auto *DRD = getReductionInit(Init);
- // Perform element-by-element initialization.
- QualType ElementTy;
-
- // Drill down to the base element type on both arrays.
- auto ArrayTy = Type->getAsArrayTypeUnsafe();
- auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
- DestAddr =
- CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType());
- if (DRD)
- SrcAddr =
- CGF.Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
-
- llvm::Value *SrcBegin = nullptr;
- if (DRD)
- SrcBegin = SrcAddr.getPointer();
- auto DestBegin = DestAddr.getPointer();
- // Cast from pointer to array type to pointer to single element.
- auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements);
- // The basic structure here is a while-do loop.
- auto BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
- auto DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
- auto IsEmpty =
- CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
- CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
-
- // Enter the loop body, making that address the current address.
- auto EntryBB = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(BodyBB);
-
- CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
-
- llvm::PHINode *SrcElementPHI = nullptr;
- Address SrcElementCurrent = Address::invalid();
- if (DRD) {
- SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
- "omp.arraycpy.srcElementPast");
- SrcElementPHI->addIncoming(SrcBegin, EntryBB);
- SrcElementCurrent =
- Address(SrcElementPHI,
- SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
- }
- llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
- DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
- DestElementPHI->addIncoming(DestBegin, EntryBB);
- Address DestElementCurrent =
- Address(DestElementPHI,
- DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
-
- // Emit copy.
- {
- CodeGenFunction::RunCleanupsScope InitScope(CGF);
- if (DRD && (DRD->getInitializer() || !Init)) {
- emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
- SrcElementCurrent, ElementTy);
- } else
- CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
- /*IsInitializer=*/false);
- }
-
- if (DRD) {
- // Shift the address forward by one element.
- auto SrcElementNext = CGF.Builder.CreateConstGEP1_32(
- SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
- }
-
- // Shift the address forward by one element.
- auto DestElementNext = CGF.Builder.CreateConstGEP1_32(
- DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- // Check whether we've reached the end.
- auto Done =
- CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
- CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
- DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
-
- // Done.
- CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr,
Address SrcAddr, const VarDecl *DestVD,
const VarDecl *SrcVD, const Expr *Copy) {
@@ -939,253 +946,109 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal(
EmitBlock(DoneBB, /*IsFinished=*/true);
}
-static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
- LValue BaseLV, llvm::Value *Addr) {
- Address Tmp = Address::invalid();
- Address TopTmp = Address::invalid();
- Address MostTopTmp = Address::invalid();
- BaseTy = BaseTy.getNonReferenceType();
- while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
- !CGF.getContext().hasSameType(BaseTy, ElTy)) {
- Tmp = CGF.CreateMemTemp(BaseTy);
- if (TopTmp.isValid())
- CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
- else
- MostTopTmp = Tmp;
- TopTmp = Tmp;
- BaseTy = BaseTy->getPointeeType();
- }
- llvm::Type *Ty = BaseLV.getPointer()->getType();
- if (Tmp.isValid())
- Ty = Tmp.getElementType();
- Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Ty);
- if (Tmp.isValid()) {
- CGF.Builder.CreateStore(Addr, Tmp);
- return MostTopTmp;
- }
- return Address(Addr, BaseLV.getAlignment());
-}
-
-static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
- LValue BaseLV) {
- BaseTy = BaseTy.getNonReferenceType();
- while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
- !CGF.getContext().hasSameType(BaseTy, ElTy)) {
- if (auto *PtrTy = BaseTy->getAs<PointerType>())
- BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
- else {
- BaseLV = CGF.EmitLoadOfReferenceLValue(BaseLV.getAddress(),
- BaseTy->castAs<ReferenceType>());
- }
- BaseTy = BaseTy->getPointeeType();
- }
- return CGF.MakeAddrLValue(
- Address(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- BaseLV.getPointer(), CGF.ConvertTypeForMem(ElTy)->getPointerTo()),
- BaseLV.getAlignment()),
- BaseLV.getType(), BaseLV.getAlignmentSource());
-}
-
void CodeGenFunction::EmitOMPReductionClauseInit(
const OMPExecutableDirective &D,
CodeGenFunction::OMPPrivateScope &PrivateScope) {
if (!HaveInsertPoint())
return;
+ SmallVector<const Expr *, 4> Shareds;
+ SmallVector<const Expr *, 4> Privates;
+ SmallVector<const Expr *, 4> ReductionOps;
+ SmallVector<const Expr *, 4> LHSs;
+ SmallVector<const Expr *, 4> RHSs;
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
- auto ILHS = C->lhs_exprs().begin();
- auto IRHS = C->rhs_exprs().begin();
auto IPriv = C->privates().begin();
auto IRed = C->reduction_ops().begin();
- for (auto IRef : C->varlists()) {
- auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
- auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
- auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
- auto *DRD = getReductionInit(*IRed);
- if (auto *OASE = dyn_cast<OMPArraySectionExpr>(IRef)) {
- auto *Base = OASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
- Base = TempOASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- auto *DE = cast<DeclRefExpr>(Base);
- auto *OrigVD = cast<VarDecl>(DE->getDecl());
- auto OASELValueLB = EmitOMPArraySectionExpr(OASE);
- auto OASELValueUB =
- EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false);
- auto OriginalBaseLValue = EmitLValue(DE);
- LValue BaseLValue =
- loadToBegin(*this, OrigVD->getType(), OASELValueLB.getType(),
- OriginalBaseLValue);
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- PrivateScope.addPrivate(LHSVD, [OASELValueLB]() -> Address {
- return OASELValueLB.getAddress();
- });
- // Emit reduction copy.
- bool IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, OrigVD, PrivateVD, BaseLValue, OASELValueLB,
- OASELValueUB, OriginalBaseLValue, DRD, IRed]() -> Address {
- // Emit VarDecl with copy init for arrays.
- // Get the address of the original variable captured in current
- // captured region.
- auto *Size = Builder.CreatePtrDiff(OASELValueUB.getPointer(),
- OASELValueLB.getPointer());
- Size = Builder.CreateNUWAdd(
- Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
- CodeGenFunction::OpaqueValueMapping OpaqueMap(
- *this, cast<OpaqueValueExpr>(
- getContext()
- .getAsVariableArrayType(PrivateVD->getType())
- ->getSizeExpr()),
- RValue::get(Size));
- EmitVariablyModifiedType(PrivateVD->getType());
- auto Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- auto *Init = PrivateVD->getInit();
- EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(),
- DRD ? *IRed : Init,
- OASELValueLB.getAddress());
- EmitAutoVarCleanups(Emission);
- // Emit private VarDecl with reduction init.
- auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
- OASELValueLB.getPointer());
- auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset);
- return castToBase(*this, OrigVD->getType(),
- OASELValueLB.getType(), OriginalBaseLValue,
- Ptr);
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
- return GetAddrOfLocalVar(PrivateVD);
- });
- } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(IRef)) {
- auto *Base = ASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- auto *DE = cast<DeclRefExpr>(Base);
- auto *OrigVD = cast<VarDecl>(DE->getDecl());
- auto ASELValue = EmitLValue(ASE);
- auto OriginalBaseLValue = EmitLValue(DE);
- LValue BaseLValue = loadToBegin(
- *this, OrigVD->getType(), ASELValue.getType(), OriginalBaseLValue);
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- PrivateScope.addPrivate(
- LHSVD, [ASELValue]() -> Address { return ASELValue.getAddress(); });
- // Emit reduction copy.
- bool IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, OrigVD, PrivateVD, BaseLValue, ASELValue,
- OriginalBaseLValue, DRD, IRed]() -> Address {
- // Emit private VarDecl with reduction init.
- AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
- emitInitWithReductionInitializer(*this, DRD, *IRed, Addr,
- ASELValue.getAddress(),
- ASELValue.getType());
- } else
- EmitAutoVarInit(Emission);
- EmitAutoVarCleanups(Emission);
- auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
- ASELValue.getPointer());
- auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset);
- return castToBase(*this, OrigVD->getType(), ASELValue.getType(),
- OriginalBaseLValue, Ptr);
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address {
- return Builder.CreateElementBitCast(
- GetAddrOfLocalVar(PrivateVD), ConvertTypeForMem(RHSVD->getType()),
- "rhs.begin");
- });
- } else {
- auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
- QualType Type = PrivateVD->getType();
- if (getContext().getAsArrayType(Type)) {
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
- CapturedStmtInfo->lookup(OrigVD) != nullptr,
- IRef->getType(), VK_LValue, IRef->getExprLoc());
- Address OriginalAddr = EmitLValue(&DRE).getAddress();
- PrivateScope.addPrivate(LHSVD, [this, &OriginalAddr,
- LHSVD]() -> Address {
- OriginalAddr = Builder.CreateElementBitCast(
- OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
- return OriginalAddr;
- });
- bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address {
- if (Type->isVariablyModifiedType()) {
- CodeGenFunction::OpaqueValueMapping OpaqueMap(
- *this, cast<OpaqueValueExpr>(
- getContext()
- .getAsVariableArrayType(PrivateVD->getType())
- ->getSizeExpr()),
- RValue::get(
- getTypeSize(OrigVD->getType().getNonReferenceType())));
- EmitVariablyModifiedType(Type);
- }
- auto Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- auto *Init = PrivateVD->getInit();
- EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(),
- DRD ? *IRed : Init, OriginalAddr);
- EmitAutoVarCleanups(Emission);
- return Emission.getAllocatedAddress();
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address {
- return Builder.CreateElementBitCast(
- GetAddrOfLocalVar(PrivateVD),
- ConvertTypeForMem(RHSVD->getType()), "rhs.begin");
- });
- } else {
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- Address OriginalAddr = Address::invalid();
- PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef,
- &OriginalAddr]() -> Address {
- DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
- CapturedStmtInfo->lookup(OrigVD) != nullptr,
- IRef->getType(), VK_LValue, IRef->getExprLoc());
- OriginalAddr = EmitLValue(&DRE).getAddress();
- return OriginalAddr;
- });
- // Emit reduction copy.
- bool IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, PrivateVD, OriginalAddr, DRD, IRed]() -> Address {
- // Emit private VarDecl with reduction init.
- AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
- emitInitWithReductionInitializer(*this, DRD, *IRed, Addr,
- OriginalAddr,
- PrivateVD->getType());
- } else
- EmitAutoVarInit(Emission);
- EmitAutoVarCleanups(Emission);
- return Addr;
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
- return GetAddrOfLocalVar(PrivateVD);
- });
- }
+ auto ILHS = C->lhs_exprs().begin();
+ auto IRHS = C->rhs_exprs().begin();
+ for (const auto *Ref : C->varlists()) {
+ Shareds.emplace_back(Ref);
+ Privates.emplace_back(*IPriv);
+ ReductionOps.emplace_back(*IRed);
+ LHSs.emplace_back(*ILHS);
+ RHSs.emplace_back(*IRHS);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ std::advance(ILHS, 1);
+ std::advance(IRHS, 1);
+ }
+ }
+ ReductionCodeGen RedCG(Shareds, Privates, ReductionOps);
+ unsigned Count = 0;
+ auto ILHS = LHSs.begin();
+ auto IRHS = RHSs.begin();
+ auto IPriv = Privates.begin();
+ for (const auto *IRef : Shareds) {
+ auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
+ // Emit private VarDecl with reduction init.
+ RedCG.emitSharedLValue(*this, Count);
+ RedCG.emitAggregateType(*this, Count);
+ auto Emission = EmitAutoVarAlloca(*PrivateVD);
+ RedCG.emitInitialization(*this, Count, Emission.getAllocatedAddress(),
+ RedCG.getSharedLValue(Count),
+ [&Emission](CodeGenFunction &CGF) {
+ CGF.EmitAutoVarInit(Emission);
+ return true;
+ });
+ EmitAutoVarCleanups(Emission);
+ Address BaseAddr = RedCG.adjustPrivateAddress(
+ *this, Count, Emission.getAllocatedAddress());
+ bool IsRegistered = PrivateScope.addPrivate(
+ RedCG.getBaseDecl(Count), [BaseAddr]() -> Address { return BaseAddr; });
+ assert(IsRegistered && "private var already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+
+ auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
+ auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
+ QualType Type = PrivateVD->getType();
+ bool isaOMPArraySectionExpr = isa<OMPArraySectionExpr>(IRef);
+ if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) {
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address {
+ return RedCG.getSharedLValue(Count).getAddress();
+ });
+ PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
+ return GetAddrOfLocalVar(PrivateVD);
+ });
+ } else if ((isaOMPArraySectionExpr && Type->isScalarType()) ||
+ isa<ArraySubscriptExpr>(IRef)) {
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address {
+ return RedCG.getSharedLValue(Count).getAddress();
+ });
+ PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address {
+ return Builder.CreateElementBitCast(GetAddrOfLocalVar(PrivateVD),
+ ConvertTypeForMem(RHSVD->getType()),
+ "rhs.begin");
+ });
+ } else {
+ QualType Type = PrivateVD->getType();
+ bool IsArray = getContext().getAsArrayType(Type) != nullptr;
+ Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress();
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ if (IsArray) {
+ OriginalAddr = Builder.CreateElementBitCast(
+ OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
}
- ++ILHS;
- ++IRHS;
- ++IPriv;
- ++IRed;
+ PrivateScope.addPrivate(
+ LHSVD, [OriginalAddr]() -> Address { return OriginalAddr; });
+ PrivateScope.addPrivate(
+ RHSVD, [this, PrivateVD, RHSVD, IsArray]() -> Address {
+ return IsArray
+ ? Builder.CreateElementBitCast(
+ GetAddrOfLocalVar(PrivateVD),
+ ConvertTypeForMem(RHSVD->getType()), "rhs.begin")
+ : GetAddrOfLocalVar(PrivateVD);
+ });
}
+ ++ILHS;
+ ++IRHS;
+ ++IPriv;
+ ++Count;
}
}
@@ -1243,10 +1106,20 @@ static void emitPostUpdateForReductionClause(
CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
}
-static void emitCommonOMPParallelDirective(CodeGenFunction &CGF,
- const OMPExecutableDirective &S,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) {
+namespace {
+/// Codegen lambda for appending distribute lower and upper bounds to outlined
+/// parallel function. This is necessary for combined constructs such as
+/// 'distribute parallel for'
+typedef llvm::function_ref<void(CodeGenFunction &,
+ const OMPExecutableDirective &,
+ llvm::SmallVectorImpl<llvm::Value *> &)>
+ CodeGenBoundParametersTy;
+} // anonymous namespace
+
+static void emitCommonOMPParallelDirective(
+ CodeGenFunction &CGF, const OMPExecutableDirective &S,
+ OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
+ const CodeGenBoundParametersTy &CodeGenBoundParameters) {
const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
auto OutlinedFn = CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction(
S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
@@ -1273,11 +1146,20 @@ static void emitCommonOMPParallelDirective(CodeGenFunction &CGF,
OMPParallelScope Scope(CGF, S);
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
+ // Combining 'distribute' with 'for' requires sharing each 'distribute' chunk
+ // lower and upper bounds with the pragma 'for' chunking mechanism.
+ // The following lambda takes care of appending the lower and upper bound
+ // parameters when necessary
+ CodeGenBoundParameters(CGF, S, CapturedVars);
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getLocStart(), OutlinedFn,
CapturedVars, IfCond);
}
+static void emitEmptyBoundParameters(CodeGenFunction &,
+ const OMPExecutableDirective &,
+ llvm::SmallVectorImpl<llvm::Value *> &) {}
+
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
// Emit parallel region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
@@ -1298,7 +1180,8 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen,
+ emitEmptyBoundParameters);
emitPostUpdateForReductionClause(
*this, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; });
}
@@ -1375,12 +1258,14 @@ void CodeGenFunction::EmitOMPInnerLoop(
EmitBlock(LoopExit.getBlock());
}
-void CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) {
+bool CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) {
if (!HaveInsertPoint())
- return;
+ return false;
// Emit inits for the linear variables.
+ bool HasLinears = false;
for (const auto *C : D.getClausesOfKind<OMPLinearClause>()) {
for (auto *Init : C->inits()) {
+ HasLinears = true;
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(Init)->getDecl());
if (auto *Ref = dyn_cast<DeclRefExpr>(VD->getInit()->IgnoreImpCasts())) {
AutoVarEmission Emission = EmitAutoVarAlloca(*VD);
@@ -1405,6 +1290,7 @@ void CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) {
EmitIgnoredExpr(CS);
}
}
+ return HasLinears;
}
void CodeGenFunction::EmitOMPLinearClauseFinal(
@@ -1643,6 +1529,13 @@ void CodeGenFunction::EmitOMPSimdFinal(
EmitBlock(DoneBB, /*IsFinished=*/true);
}
+static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF,
+ const OMPLoopDirective &S,
+ CodeGenFunction::JumpDest LoopExit) {
+ CGF.EmitOMPLoopBody(S, LoopExit);
+ CGF.EmitStopPoint(&S);
+}
+
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
OMPLoopScope PreInitScope(CGF, S);
@@ -1687,7 +1580,7 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
CGF.EmitOMPSimdInit(S);
emitAlignedClause(CGF, S);
- CGF.EmitOMPLinearClauseInit(S);
+ (void)CGF.EmitOMPLinearClauseInit(S);
{
OMPPrivateScope LoopScope(CGF);
CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
@@ -1725,9 +1618,12 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
}
-void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
- const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) {
+void CodeGenFunction::EmitOMPOuterLoop(
+ bool DynamicOrOrdered, bool IsMonotonic, const OMPLoopDirective &S,
+ CodeGenFunction::OMPPrivateScope &LoopScope,
+ const CodeGenFunction::OMPLoopArguments &LoopArgs,
+ const CodeGenFunction::CodeGenLoopTy &CodeGenLoop,
+ const CodeGenFunction::CodeGenOrderedTy &CodeGenOrdered) {
auto &RT = CGM.getOpenMPRuntime();
const Expr *IVExpr = S.getIterationVariable();
@@ -1745,15 +1641,18 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
llvm::Value *BoolCondVal = nullptr;
if (!DynamicOrOrdered) {
- // UB = min(UB, GlobalUB)
- EmitIgnoredExpr(S.getEnsureUpperBound());
+ // UB = min(UB, GlobalUB) or
+ // UB = min(UB, PrevUB) for combined loop sharing constructs (e.g.
+ // 'distribute parallel for')
+ EmitIgnoredExpr(LoopArgs.EUB);
// IV = LB
- EmitIgnoredExpr(S.getInit());
+ EmitIgnoredExpr(LoopArgs.Init);
// IV < UB
- BoolCondVal = EvaluateExprAsBool(S.getCond());
+ BoolCondVal = EvaluateExprAsBool(LoopArgs.Cond);
} else {
- BoolCondVal = RT.emitForNext(*this, S.getLocStart(), IVSize, IVSigned, IL,
- LB, UB, ST);
+ BoolCondVal =
+ RT.emitForNext(*this, S.getLocStart(), IVSize, IVSigned, LoopArgs.IL,
+ LoopArgs.LB, LoopArgs.UB, LoopArgs.ST);
}
// If there are any cleanups between here and the loop-exit scope,
@@ -1773,7 +1672,7 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
// Emit "IV = LB" (in case of static schedule, we have already calculated new
// LB for loop condition and emitted it above).
if (DynamicOrOrdered)
- EmitIgnoredExpr(S.getInit());
+ EmitIgnoredExpr(LoopArgs.Init);
// Create a block for the increment.
auto Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
@@ -1787,24 +1686,27 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
EmitOMPSimdInit(S, IsMonotonic);
SourceLocation Loc = S.getLocStart();
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
- [&S, LoopExit](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, LoopExit);
- CGF.EmitStopPoint(&S);
- },
- [Ordered, IVSize, IVSigned, Loc](CodeGenFunction &CGF) {
- if (Ordered) {
- CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(
- CGF, Loc, IVSize, IVSigned);
- }
- });
+
+ // when 'distribute' is not combined with a 'for':
+ // while (idx <= UB) { BODY; ++idx; }
+ // when 'distribute' is combined with a 'for'
+ // (e.g. 'distribute parallel for')
+ // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
+ EmitOMPInnerLoop(
+ S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
+ [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
+ CodeGenLoop(CGF, S, LoopExit);
+ },
+ [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
+ CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
+ });
EmitBlock(Continue.getBlock());
BreakContinueStack.pop_back();
if (!DynamicOrOrdered) {
// Emit "LB = LB + Stride", "UB = UB + Stride".
- EmitIgnoredExpr(S.getNextLowerBound());
- EmitIgnoredExpr(S.getNextUpperBound());
+ EmitIgnoredExpr(LoopArgs.NextLB);
+ EmitIgnoredExpr(LoopArgs.NextUB);
}
EmitBranch(CondBlock);
@@ -1815,7 +1717,8 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
// Tell the runtime we are done.
auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) {
if (!DynamicOrOrdered)
- CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd());
+ CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd(),
+ S.getDirectiveKind());
};
OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
}
@@ -1823,7 +1726,8 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
void CodeGenFunction::EmitOMPForOuterLoop(
const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic,
const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) {
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds) {
auto &RT = CGM.getOpenMPRuntime();
// Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
@@ -1832,7 +1736,7 @@ void CodeGenFunction::EmitOMPForOuterLoop(
assert((Ordered ||
!RT.isStaticNonchunked(ScheduleKind.Schedule,
- /*Chunked=*/Chunk != nullptr)) &&
+ LoopArgs.Chunk != nullptr)) &&
"static non-chunked schedule does not need outer loop");
// Emit outer loop.
@@ -1890,22 +1794,48 @@ void CodeGenFunction::EmitOMPForOuterLoop(
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
if (DynamicOrOrdered) {
- llvm::Value *UBVal = EmitScalarExpr(S.getLastIteration());
+ auto DispatchBounds = CGDispatchBounds(*this, S, LoopArgs.LB, LoopArgs.UB);
+ llvm::Value *LBVal = DispatchBounds.first;
+ llvm::Value *UBVal = DispatchBounds.second;
+ CGOpenMPRuntime::DispatchRTInput DipatchRTInputValues = {LBVal, UBVal,
+ LoopArgs.Chunk};
RT.emitForDispatchInit(*this, S.getLocStart(), ScheduleKind, IVSize,
- IVSigned, Ordered, UBVal, Chunk);
+ IVSigned, Ordered, DipatchRTInputValues);
} else {
- RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned,
- Ordered, IL, LB, UB, ST, Chunk);
+ CGOpenMPRuntime::StaticRTInput StaticInit(
+ IVSize, IVSigned, Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB,
+ LoopArgs.ST, LoopArgs.Chunk);
+ RT.emitForStaticInit(*this, S.getLocStart(), S.getDirectiveKind(),
+ ScheduleKind, StaticInit);
}
- EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, Ordered, LB, UB,
- ST, IL, Chunk);
+ auto &&CodeGenOrdered = [Ordered](CodeGenFunction &CGF, SourceLocation Loc,
+ const unsigned IVSize,
+ const bool IVSigned) {
+ if (Ordered) {
+ CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(CGF, Loc, IVSize,
+ IVSigned);
+ }
+ };
+
+ OMPLoopArguments OuterLoopArgs(LoopArgs.LB, LoopArgs.UB, LoopArgs.ST,
+ LoopArgs.IL, LoopArgs.Chunk, LoopArgs.EUB);
+ OuterLoopArgs.IncExpr = S.getInc();
+ OuterLoopArgs.Init = S.getInit();
+ OuterLoopArgs.Cond = S.getCond();
+ OuterLoopArgs.NextLB = S.getNextLowerBound();
+ OuterLoopArgs.NextUB = S.getNextUpperBound();
+ EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, OuterLoopArgs,
+ emitOMPLoopBodyWithStopPoint, CodeGenOrdered);
}
+static void emitEmptyOrdered(CodeGenFunction &, SourceLocation Loc,
+ const unsigned IVSize, const bool IVSigned) {}
+
void CodeGenFunction::EmitOMPDistributeOuterLoop(
- OpenMPDistScheduleClauseKind ScheduleKind,
- const OMPDistributeDirective &S, OMPPrivateScope &LoopScope,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) {
+ OpenMPDistScheduleClauseKind ScheduleKind, const OMPLoopDirective &S,
+ OMPPrivateScope &LoopScope, const OMPLoopArguments &LoopArgs,
+ const CodeGenLoopTy &CodeGenLoopContent) {
auto &RT = CGM.getOpenMPRuntime();
@@ -1918,26 +1848,159 @@ void CodeGenFunction::EmitOMPDistributeOuterLoop(
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
- RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind,
- IVSize, IVSigned, /* Ordered = */ false,
- IL, LB, UB, ST, Chunk);
+ CGOpenMPRuntime::StaticRTInput StaticInit(
+ IVSize, IVSigned, /* Ordered = */ false, LoopArgs.IL, LoopArgs.LB,
+ LoopArgs.UB, LoopArgs.ST, LoopArgs.Chunk);
+ RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind, StaticInit);
+
+ // for combined 'distribute' and 'for' the increment expression of distribute
+ // is store in DistInc. For 'distribute' alone, it is in Inc.
+ Expr *IncExpr;
+ if (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind()))
+ IncExpr = S.getDistInc();
+ else
+ IncExpr = S.getInc();
+
+ // this routine is shared by 'omp distribute parallel for' and
+ // 'omp distribute': select the right EUB expression depending on the
+ // directive
+ OMPLoopArguments OuterLoopArgs;
+ OuterLoopArgs.LB = LoopArgs.LB;
+ OuterLoopArgs.UB = LoopArgs.UB;
+ OuterLoopArgs.ST = LoopArgs.ST;
+ OuterLoopArgs.IL = LoopArgs.IL;
+ OuterLoopArgs.Chunk = LoopArgs.Chunk;
+ OuterLoopArgs.EUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedEnsureUpperBound()
+ : S.getEnsureUpperBound();
+ OuterLoopArgs.IncExpr = IncExpr;
+ OuterLoopArgs.Init = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedInit()
+ : S.getInit();
+ OuterLoopArgs.Cond = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedCond()
+ : S.getCond();
+ OuterLoopArgs.NextLB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedNextLowerBound()
+ : S.getNextLowerBound();
+ OuterLoopArgs.NextUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedNextUpperBound()
+ : S.getNextUpperBound();
+
+ EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false, S,
+ LoopScope, OuterLoopArgs, CodeGenLoopContent,
+ emitEmptyOrdered);
+}
+
+/// Emit a helper variable and return corresponding lvalue.
+static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
+ const DeclRefExpr *Helper) {
+ auto VDecl = cast<VarDecl>(Helper->getDecl());
+ CGF.EmitVarDecl(*VDecl);
+ return CGF.EmitLValue(Helper);
+}
+
+static std::pair<LValue, LValue>
+emitDistributeParallelForInnerBounds(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ LValue LB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
+ LValue UB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
+
+ // When composing 'distribute' with 'for' (e.g. as in 'distribute
+ // parallel for') we need to use the 'distribute'
+ // chunk lower and upper bounds rather than the whole loop iteration
+ // space. These are parameters to the outlined function for 'parallel'
+ // and we copy the bounds of the previous schedule into the
+ // the current ones.
+ LValue PrevLB = CGF.EmitLValue(LS.getPrevLowerBoundVariable());
+ LValue PrevUB = CGF.EmitLValue(LS.getPrevUpperBoundVariable());
+ llvm::Value *PrevLBVal = CGF.EmitLoadOfScalar(PrevLB, SourceLocation());
+ PrevLBVal = CGF.EmitScalarConversion(
+ PrevLBVal, LS.getPrevLowerBoundVariable()->getType(),
+ LS.getIterationVariable()->getType(), SourceLocation());
+ llvm::Value *PrevUBVal = CGF.EmitLoadOfScalar(PrevUB, SourceLocation());
+ PrevUBVal = CGF.EmitScalarConversion(
+ PrevUBVal, LS.getPrevUpperBoundVariable()->getType(),
+ LS.getIterationVariable()->getType(), SourceLocation());
+
+ CGF.EmitStoreOfScalar(PrevLBVal, LB);
+ CGF.EmitStoreOfScalar(PrevUBVal, UB);
+
+ return {LB, UB};
+}
+
+/// if the 'for' loop has a dispatch schedule (e.g. dynamic, guided) then
+/// we need to use the LB and UB expressions generated by the worksharing
+/// code generation support, whereas in non combined situations we would
+/// just emit 0 and the LastIteration expression
+/// This function is necessary due to the difference of the LB and UB
+/// types for the RT emission routines for 'for_static_init' and
+/// 'for_dispatch_init'
+static std::pair<llvm::Value *, llvm::Value *>
+emitDistributeParallelForDispatchBounds(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S,
+ Address LB, Address UB) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ const Expr *IVExpr = LS.getIterationVariable();
+ // when implementing a dynamic schedule for a 'for' combined with a
+ // 'distribute' (e.g. 'distribute parallel for'), the 'for' loop
+ // is not normalized as each team only executes its own assigned
+ // distribute chunk
+ QualType IteratorTy = IVExpr->getType();
+ llvm::Value *LBVal = CGF.EmitLoadOfScalar(LB, /*Volatile=*/false, IteratorTy,
+ SourceLocation());
+ llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy,
+ SourceLocation());
+ return {LBVal, UBVal};
+}
+
+static void emitDistributeParallelForDistributeInnerBoundParams(
+ CodeGenFunction &CGF, const OMPExecutableDirective &S,
+ llvm::SmallVectorImpl<llvm::Value *> &CapturedVars) {
+ const auto &Dir = cast<OMPLoopDirective>(S);
+ LValue LB =
+ CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable()));
+ auto LBCast = CGF.Builder.CreateIntCast(
+ CGF.Builder.CreateLoad(LB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
+ CapturedVars.push_back(LBCast);
+ LValue UB =
+ CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable()));
+
+ auto UBCast = CGF.Builder.CreateIntCast(
+ CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
+ CapturedVars.push_back(UBCast);
+}
+
+static void
+emitInnerParallelForWhenCombined(CodeGenFunction &CGF,
+ const OMPLoopDirective &S,
+ CodeGenFunction::JumpDest LoopExit) {
+ auto &&CGInlinedWorksharingLoop = [&S](CodeGenFunction &CGF,
+ PrePostActionTy &) {
+ CGF.EmitOMPWorksharingLoop(S, S.getPrevEnsureUpperBound(),
+ emitDistributeParallelForInnerBounds,
+ emitDistributeParallelForDispatchBounds);
+ };
- EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false,
- S, LoopScope, /* Ordered = */ false, LB, UB, ST, IL, Chunk);
+ emitCommonOMPParallelDirective(
+ CGF, S, OMPD_for, CGInlinedWorksharingLoop,
+ emitDistributeParallelForDistributeInnerBoundParams);
}
void CodeGenFunction::EmitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective &S) {
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
+ S.getDistInc());
+ };
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
- CGM.getOpenMPRuntime().emitInlinedDirective(
- *this, OMPD_distribute_parallel_for,
- [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- OMPLoopScope PreInitScope(CGF, S);
- OMPCancelStackRAII CancelRegion(CGF, OMPD_distribute_parallel_for,
- /*HasCancel=*/false);
- CGF.EmitStmt(
- cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- });
+ OMPCancelStackRAII CancelRegion(*this, OMPD_distribute_parallel_for,
+ /*HasCancel=*/false);
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen,
+ /*HasCancel=*/false);
}
void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective(
@@ -1987,18 +2050,6 @@ void CodeGenFunction::EmitOMPTargetSimdDirective(
});
}
-void CodeGenFunction::EmitOMPTeamsDistributeDirective(
- const OMPTeamsDistributeDirective &S) {
- OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
- CGM.getOpenMPRuntime().emitInlinedDirective(
- *this, OMPD_teams_distribute,
- [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- OMPLoopScope PreInitScope(CGF, S);
- CGF.EmitStmt(
- cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- });
-}
-
void CodeGenFunction::EmitOMPTeamsDistributeSimdDirective(
const OMPTeamsDistributeSimdDirective &S) {
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
@@ -2037,6 +2088,7 @@ void CodeGenFunction::EmitOMPTeamsDistributeParallelForDirective(
void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective(
const OMPTargetTeamsDistributeDirective &S) {
+ OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
CGM.getOpenMPRuntime().emitInlinedDirective(
*this, OMPD_target_teams_distribute,
[&S](CodeGenFunction &CGF, PrePostActionTy &) {
@@ -2047,6 +2099,7 @@ void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective(
void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDirective(
const OMPTargetTeamsDistributeParallelForDirective &S) {
+ OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
CGM.getOpenMPRuntime().emitInlinedDirective(
*this, OMPD_target_teams_distribute_parallel_for,
[&S](CodeGenFunction &CGF, PrePostActionTy &) {
@@ -2057,6 +2110,7 @@ void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForDirective(
void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDirective(
const OMPTargetTeamsDistributeParallelForSimdDirective &S) {
+ OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
CGM.getOpenMPRuntime().emitInlinedDirective(
*this, OMPD_target_teams_distribute_parallel_for_simd,
[&S](CodeGenFunction &CGF, PrePostActionTy &) {
@@ -2067,6 +2121,7 @@ void CodeGenFunction::EmitOMPTargetTeamsDistributeParallelForSimdDirective(
void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective(
const OMPTargetTeamsDistributeSimdDirective &S) {
+ OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
CGM.getOpenMPRuntime().emitInlinedDirective(
*this, OMPD_target_teams_distribute_simd,
[&S](CodeGenFunction &CGF, PrePostActionTy &) {
@@ -2075,14 +2130,6 @@ void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective(
});
}
-/// \brief Emit a helper variable and return corresponding lvalue.
-static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
- const DeclRefExpr *Helper) {
- auto VDecl = cast<VarDecl>(Helper->getDecl());
- CGF.EmitVarDecl(*VDecl);
- return CGF.EmitLValue(Helper);
-}
-
namespace {
struct ScheduleKindModifiersTy {
OpenMPScheduleClauseKind Kind;
@@ -2095,7 +2142,10 @@ namespace {
};
} // namespace
-bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
+bool CodeGenFunction::EmitOMPWorksharingLoop(
+ const OMPLoopDirective &S, Expr *EUB,
+ const CodeGenLoopBoundsTy &CodeGenLoopBounds,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds) {
// Emit the loop iteration variable.
auto IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
auto IVDecl = cast<VarDecl>(IVExpr->getDecl());
@@ -2143,12 +2193,12 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
llvm::DenseSet<const Expr *> EmittedFinals;
emitAlignedClause(*this, S);
- EmitOMPLinearClauseInit(S);
+ bool HasLinears = EmitOMPLinearClauseInit(S);
// Emit helper vars inits.
- LValue LB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getLowerBoundVariable()));
- LValue UB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getUpperBoundVariable()));
+
+ std::pair<LValue, LValue> Bounds = CodeGenLoopBounds(*this, S);
+ LValue LB = Bounds.first;
+ LValue UB = Bounds.second;
LValue ST =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
LValue IL =
@@ -2157,7 +2207,7 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
// Emit 'then' code.
{
OMPPrivateScope LoopScope(*this);
- if (EmitOMPFirstprivateClause(S, LoopScope)) {
+ if (EmitOMPFirstprivateClause(S, LoopScope) || HasLinears) {
// Emit implicit barrier to synchronize threads and avoid data races on
// initialization of firstprivate variables and post-update of
// lastprivate variables.
@@ -2202,10 +2252,11 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
// chunks that are approximately equal in size, and at most one chunk is
// distributed to each thread. Note that the size of the chunks is
// unspecified in this case.
- RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind,
- IVSize, IVSigned, Ordered,
- IL.getAddress(), LB.getAddress(),
- UB.getAddress(), ST.getAddress());
+ CGOpenMPRuntime::StaticRTInput StaticInit(
+ IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(),
+ UB.getAddress(), ST.getAddress());
+ RT.emitForStaticInit(*this, S.getLocStart(), S.getDirectiveKind(),
+ ScheduleKind, StaticInit);
auto LoopExit =
getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
// UB = min(UB, GlobalUB);
@@ -2223,7 +2274,8 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
- CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd());
+ CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd(),
+ S.getDirectiveKind());
};
OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen);
} else {
@@ -2234,9 +2286,11 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
+ const OMPLoopArguments LoopArguments(LB.getAddress(), UB.getAddress(),
+ ST.getAddress(), IL.getAddress(),
+ Chunk, EUB);
EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
- LB.getAddress(), UB.getAddress(), ST.getAddress(),
- IL.getAddress(), Chunk);
+ LoopArguments, CGDispatchBounds);
}
if (isOpenMPSimdDirective(S.getDirectiveKind())) {
EmitOMPSimdFinal(S,
@@ -2274,12 +2328,42 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
return HasLastprivateClause;
}
+/// The following two functions generate expressions for the loop lower
+/// and upper bounds in case of static and dynamic (dispatch) schedule
+/// of the associated 'for' or 'distribute' loop.
+static std::pair<LValue, LValue>
+emitForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ LValue LB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
+ LValue UB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
+ return {LB, UB};
+}
+
+/// When dealing with dispatch schedules (e.g. dynamic, guided) we do not
+/// consider the lower and upper bound expressions generated by the
+/// worksharing loop support, but we use 0 and the iteration space size as
+/// constants
+static std::pair<llvm::Value *, llvm::Value *>
+emitDispatchForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S,
+ Address LB, Address UB) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ const Expr *IVExpr = LS.getIterationVariable();
+ const unsigned IVSize = CGF.getContext().getTypeSize(IVExpr->getType());
+ llvm::Value *LBVal = CGF.Builder.getIntN(IVSize, 0);
+ llvm::Value *UBVal = CGF.EmitScalarExpr(LS.getLastIteration());
+ return {LBVal, UBVal};
+}
+
void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
bool HasLastprivates = false;
auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
PrePostActionTy &) {
OMPCancelStackRAII CancelRegion(CGF, OMPD_for, S.hasCancel());
- HasLastprivates = CGF.EmitOMPWorksharingLoop(S);
+ HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
+ emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
{
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
@@ -2297,7 +2381,9 @@ void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) {
bool HasLastprivates = false;
auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
PrePostActionTy &) {
- HasLastprivates = CGF.EmitOMPWorksharingLoop(S);
+ HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
+ emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
{
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
@@ -2346,8 +2432,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());
@@ -2404,10 +2489,11 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
// Emit static non-chunked loop.
OpenMPScheduleTy ScheduleKind;
ScheduleKind.Schedule = OMPC_SCHEDULE_static;
+ CGOpenMPRuntime::StaticRTInput StaticInit(
+ /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(),
+ LB.getAddress(), UB.getAddress(), ST.getAddress());
CGF.CGM.getOpenMPRuntime().emitForStaticInit(
- CGF, S.getLocStart(), ScheduleKind, /*IVSize=*/32,
- /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(), LB.getAddress(),
- UB.getAddress(), ST.getAddress());
+ CGF, S.getLocStart(), S.getDirectiveKind(), ScheduleKind, StaticInit);
// UB = min(UB, GlobalUB);
auto *UBVal = CGF.EmitLoadOfScalar(UB, S.getLocStart());
auto *MinUBGlobalUB = CGF.Builder.CreateSelect(
@@ -2420,7 +2506,8 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
[](CodeGenFunction &) {});
// Tell the runtime we are done.
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
- CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd());
+ CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd(),
+ S.getDirectiveKind());
};
CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
@@ -2549,9 +2636,11 @@ void CodeGenFunction::EmitOMPParallelForDirective(
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
OMPCancelStackRAII CancelRegion(CGF, OMPD_parallel_for, S.hasCancel());
- CGF.EmitOMPWorksharingLoop(S);
+ CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen,
+ emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPParallelForSimdDirective(
@@ -2559,9 +2648,11 @@ void CodeGenFunction::EmitOMPParallelForSimdDirective(
// Emit directive as a combined directive that consists of two implicit
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPWorksharingLoop(S);
+ CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen,
+ emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPParallelSectionsDirective(
@@ -2571,7 +2662,8 @@ void CodeGenFunction::EmitOMPParallelSectionsDirective(
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitSections(S);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen,
+ emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
@@ -2655,16 +2747,38 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
++ID;
}
}
+ SmallVector<const Expr *, 4> LHSs;
+ SmallVector<const Expr *, 4> RHSs;
+ for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
+ auto IPriv = C->privates().begin();
+ auto IRed = C->reduction_ops().begin();
+ auto ILHS = C->lhs_exprs().begin();
+ auto IRHS = C->rhs_exprs().begin();
+ for (const auto *Ref : C->varlists()) {
+ Data.ReductionVars.emplace_back(Ref);
+ Data.ReductionCopies.emplace_back(*IPriv);
+ Data.ReductionOps.emplace_back(*IRed);
+ LHSs.emplace_back(*ILHS);
+ RHSs.emplace_back(*IRHS);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ std::advance(ILHS, 1);
+ std::advance(IRHS, 1);
+ }
+ }
+ Data.Reductions = CGM.getOpenMPRuntime().emitTaskReductionInit(
+ *this, S.getLocStart(), LHSs, RHSs, Data);
// Build list of dependences.
for (const auto *C : S.getClausesOfKind<OMPDependClause>())
for (auto *IRef : C->varlists())
Data.Dependences.push_back(std::make_pair(C->getDependencyKind(), IRef));
- auto &&CodeGen = [&Data, CS, &BodyGen, &LastprivateDstsOrigs](
+ auto &&CodeGen = [&Data, &S, CS, &BodyGen, &LastprivateDstsOrigs](
CodeGenFunction &CGF, PrePostActionTy &Action) {
// Set proper addresses for generated private copies.
OMPPrivateScope Scope(CGF);
if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() ||
!Data.LastprivateVars.empty()) {
+ enum { PrivatesParam = 2, CopyFnParam = 3 };
auto *CopyFn = CGF.Builder.CreateLoad(
CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(3)));
auto *PrivatesPtr = CGF.Builder.CreateLoad(
@@ -2696,7 +2810,8 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr));
CallArgs.push_back(PrivatePtr.getPointer());
}
- CGF.EmitRuntimeCall(CopyFn, CallArgs);
+ CGF.CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getLocStart(),
+ CopyFn, CallArgs);
for (auto &&Pair : LastprivateDstsOrigs) {
auto *OrigVD = cast<VarDecl>(Pair.second->getDecl());
DeclRefExpr DRE(
@@ -2714,7 +2829,85 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; });
}
}
+ if (Data.Reductions) {
+ OMPLexicalScope LexScope(CGF, S, /*AsInlined=*/true);
+ ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionCopies,
+ Data.ReductionOps);
+ llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(9)));
+ for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
+ RedCG.emitSharedLValue(CGF, Cnt);
+ RedCG.emitAggregateType(CGF, Cnt);
+ Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
+ CGF, S.getLocStart(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
+ Replacement =
+ Address(CGF.EmitScalarConversion(
+ Replacement.getPointer(), CGF.getContext().VoidPtrTy,
+ CGF.getContext().getPointerType(
+ Data.ReductionCopies[Cnt]->getType()),
+ SourceLocation()),
+ Replacement.getAlignment());
+ Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
+ Scope.addPrivate(RedCG.getBaseDecl(Cnt),
+ [Replacement]() { return Replacement; });
+ // FIXME: This must removed once the runtime library is fixed.
+ // Emit required threadprivate variables for
+ // initilizer/combiner/finalizer.
+ CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getLocStart(),
+ RedCG, Cnt);
+ }
+ }
+ // Privatize all private variables except for in_reduction items.
(void)Scope.Privatize();
+ SmallVector<const Expr *, 4> InRedVars;
+ SmallVector<const Expr *, 4> InRedPrivs;
+ SmallVector<const Expr *, 4> InRedOps;
+ SmallVector<const Expr *, 4> TaskgroupDescriptors;
+ for (const auto *C : S.getClausesOfKind<OMPInReductionClause>()) {
+ auto IPriv = C->privates().begin();
+ auto IRed = C->reduction_ops().begin();
+ auto ITD = C->taskgroup_descriptors().begin();
+ for (const auto *Ref : C->varlists()) {
+ InRedVars.emplace_back(Ref);
+ InRedPrivs.emplace_back(*IPriv);
+ InRedOps.emplace_back(*IRed);
+ TaskgroupDescriptors.emplace_back(*ITD);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ std::advance(ITD, 1);
+ }
+ }
+ // Privatize in_reduction items here, because taskgroup descriptors must be
+ // privatized earlier.
+ OMPPrivateScope InRedScope(CGF);
+ if (!InRedVars.empty()) {
+ ReductionCodeGen RedCG(InRedVars, InRedPrivs, InRedOps);
+ for (unsigned Cnt = 0, E = InRedVars.size(); Cnt < E; ++Cnt) {
+ RedCG.emitSharedLValue(CGF, Cnt);
+ RedCG.emitAggregateType(CGF, Cnt);
+ // The taskgroup descriptor variable is always implicit firstprivate and
+ // privatized already during procoessing of the firstprivates.
+ llvm::Value *ReductionsPtr = CGF.EmitLoadOfScalar(
+ CGF.EmitLValue(TaskgroupDescriptors[Cnt]), SourceLocation());
+ Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
+ CGF, S.getLocStart(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
+ Replacement = Address(
+ CGF.EmitScalarConversion(
+ Replacement.getPointer(), CGF.getContext().VoidPtrTy,
+ CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()),
+ SourceLocation()),
+ Replacement.getAlignment());
+ Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
+ InRedScope.addPrivate(RedCG.getBaseDecl(Cnt),
+ [Replacement]() { return Replacement; });
+ // FIXME: This must removed once the runtime library is fixed.
+ // Emit required threadprivate variables for
+ // initilizer/combiner/finalizer.
+ CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getLocStart(),
+ RedCG, Cnt);
+ }
+ }
+ (void)InRedScope.Privatize();
Action.Enter(CGF);
BodyGen(CGF);
@@ -2773,6 +2966,35 @@ void CodeGenFunction::EmitOMPTaskgroupDirective(
const OMPTaskgroupDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
+ if (const Expr *E = S.getReductionRef()) {
+ SmallVector<const Expr *, 4> LHSs;
+ SmallVector<const Expr *, 4> RHSs;
+ OMPTaskDataTy Data;
+ for (const auto *C : S.getClausesOfKind<OMPTaskReductionClause>()) {
+ auto IPriv = C->privates().begin();
+ auto IRed = C->reduction_ops().begin();
+ auto ILHS = C->lhs_exprs().begin();
+ auto IRHS = C->rhs_exprs().begin();
+ for (const auto *Ref : C->varlists()) {
+ Data.ReductionVars.emplace_back(Ref);
+ Data.ReductionCopies.emplace_back(*IPriv);
+ Data.ReductionOps.emplace_back(*IRed);
+ LHSs.emplace_back(*ILHS);
+ RHSs.emplace_back(*IRHS);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ std::advance(ILHS, 1);
+ std::advance(IRHS, 1);
+ }
+ }
+ llvm::Value *ReductionDesc =
+ CGF.CGM.getOpenMPRuntime().emitTaskReductionInit(CGF, S.getLocStart(),
+ LHSs, RHSs, Data);
+ const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+ CGF.EmitVarDecl(*VD);
+ CGF.EmitStoreOfScalar(ReductionDesc, CGF.GetAddrOfLocalVar(VD),
+ /*Volatile=*/false, E->getType());
+ }
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
};
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
@@ -2789,7 +3011,9 @@ void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
}(), S.getLocStart());
}
-void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
+void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
+ const CodeGenLoopTy &CodeGenLoop,
+ Expr *IncExpr) {
// Emit the loop iteration variable.
auto IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
auto IVDecl = cast<VarDecl>(IVExpr->getDecl());
@@ -2830,10 +3054,17 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
// Emit 'then' code.
{
// Emit helper vars inits.
- LValue LB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getLowerBoundVariable()));
- LValue UB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getUpperBoundVariable()));
+
+ LValue LB = EmitOMPHelperVar(
+ *this, cast<DeclRefExpr>(
+ (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedLowerBoundVariable()
+ : S.getLowerBoundVariable())));
+ LValue UB = EmitOMPHelperVar(
+ *this, cast<DeclRefExpr>(
+ (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedUpperBoundVariable()
+ : S.getUpperBoundVariable())));
LValue ST =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
LValue IL =
@@ -2878,33 +3109,46 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
// league. The size of the chunks is unspecified in this case.
if (RT.isStaticNonchunked(ScheduleKind,
/* Chunked */ Chunk != nullptr)) {
+ CGOpenMPRuntime::StaticRTInput StaticInit(
+ IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(),
+ LB.getAddress(), UB.getAddress(), ST.getAddress());
RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind,
- IVSize, IVSigned, /* Ordered = */ false,
- IL.getAddress(), LB.getAddress(),
- UB.getAddress(), ST.getAddress());
+ StaticInit);
auto LoopExit =
getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
// UB = min(UB, GlobalUB);
- EmitIgnoredExpr(S.getEnsureUpperBound());
+ EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedEnsureUpperBound()
+ : S.getEnsureUpperBound());
// IV = LB;
- EmitIgnoredExpr(S.getInit());
+ EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedInit()
+ : S.getInit());
+
+ Expr *Cond = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedCond()
+ : S.getCond();
+
+ // for distribute alone, codegen
// while (idx <= UB) { BODY; ++idx; }
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
- S.getInc(),
- [&S, LoopExit](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, LoopExit);
- CGF.EmitStopPoint(&S);
+ // when combined with 'for' (e.g. as in 'distribute parallel for')
+ // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
+ EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), Cond, IncExpr,
+ [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
+ CodeGenLoop(CGF, S, LoopExit);
},
[](CodeGenFunction &) {});
EmitBlock(LoopExit.getBlock());
// Tell the runtime we are done.
- RT.emitForStaticFinish(*this, S.getLocStart());
+ RT.emitForStaticFinish(*this, S.getLocStart(), S.getDirectiveKind());
} else {
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
- EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope,
- LB.getAddress(), UB.getAddress(), ST.getAddress(),
- IL.getAddress(), Chunk);
+ const OMPLoopArguments LoopArguments = {
+ LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(),
+ Chunk};
+ EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments,
+ CodeGenLoop);
}
// Emit final copy of the lastprivate variables if IsLastIter != 0.
@@ -2926,7 +3170,8 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
void CodeGenFunction::EmitOMPDistributeDirective(
const OMPDistributeDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S);
+
+ CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen,
@@ -2957,7 +3202,8 @@ void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) {
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
auto *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS);
- CGF.EmitNounwindRuntimeCall(OutlinedFn, CapturedVars);
+ CGM.getOpenMPRuntime().emitOutlinedFunctionCall(CGF, S.getLocStart(),
+ OutlinedFn, CapturedVars);
} else {
Action.Enter(CGF);
CGF.EmitStmt(
@@ -3353,6 +3599,8 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
@@ -3596,6 +3844,28 @@ void CodeGenFunction::EmitOMPTargetTeamsDirective(
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
+void CodeGenFunction::EmitOMPTeamsDistributeDirective(
+ const OMPTeamsDistributeDirective &S) {
+
+ auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
+ };
+
+ // Emit teams region as a standalone region.
+ auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
+ PrePostActionTy &) {
+ OMPPrivateScope PrivateScope(CGF);
+ CGF.EmitOMPReductionClauseInit(S, PrivateScope);
+ (void)PrivateScope.Privatize();
+ CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_distribute,
+ CodeGenDistribute);
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
+ };
+ emitCommonOMPTeamsDirective(*this, S, OMPD_teams, CodeGen);
+ emitPostUpdateForReductionClause(*this, S,
+ [](CodeGenFunction &) { return nullptr; });
+}
+
void CodeGenFunction::EmitOMPCancellationPointDirective(
const OMPCancellationPointDirective &S) {
CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getLocStart(),
@@ -3835,7 +4105,8 @@ static void emitTargetParallelRegion(CodeGenFunction &CGF,
CGF.EmitStmt(CS->getCapturedStmt());
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
};
- emitCommonOMPParallelDirective(CGF, S, OMPD_parallel, CodeGen);
+ emitCommonOMPParallelDirective(CGF, S, OMPD_parallel, CodeGen,
+ emitEmptyBoundParameters);
emitPostUpdateForReductionClause(
CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; });
}
@@ -3864,7 +4135,14 @@ void CodeGenFunction::EmitOMPTargetParallelDirective(
void CodeGenFunction::EmitOMPTargetParallelForDirective(
const OMPTargetParallelForDirective &S) {
- // TODO: codegen for target parallel for.
+ OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
+ CGM.getOpenMPRuntime().emitInlinedDirective(
+ *this, OMPD_target_parallel_for,
+ [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ OMPLoopScope PreInitScope(CGF, S);
+ CGF.EmitStmt(
+ cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ });
}
/// Emit a helper variable and return corresponding lvalue.
@@ -4001,7 +4279,18 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop,
CodeGen);
};
- EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data);
+ if (Data.Nogroup)
+ EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data);
+ else {
+ CGM.getOpenMPRuntime().emitTaskgroupRegion(
+ *this,
+ [&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF,
+ PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ CGF.EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data);
+ },
+ S.getLocStart());
+ }
}
void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) {
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 1907b8b402..67388ee208 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -14,11 +14,12 @@
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/Support/Format.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <algorithm>
@@ -122,6 +123,33 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
return RValue::get(ReturnValue);
}
+/// This function clones a function's DISubprogram node and enters it into
+/// a value map with the intent that the map can be utilized by the cloner
+/// to short-circuit Metadata node mapping.
+/// Furthermore, the function resolves any DILocalVariable nodes referenced
+/// by dbg.value intrinsics so they can be properly mapped during cloning.
+static void resolveTopLevelMetadata(llvm::Function *Fn,
+ llvm::ValueToValueMapTy &VMap) {
+ // Clone the DISubprogram node and put it into the Value map.
+ auto *DIS = Fn->getSubprogram();
+ if (!DIS)
+ return;
+ auto *NewDIS = DIS->replaceWithDistinct(DIS->clone());
+ VMap.MD()[DIS].reset(NewDIS);
+
+ // Find all llvm.dbg.declare intrinsics and resolve the DILocalVariable nodes
+ // they are referencing.
+ for (auto &BB : Fn->getBasicBlockList()) {
+ for (auto &I : BB) {
+ if (auto *DII = dyn_cast<llvm::DbgInfoIntrinsic>(&I)) {
+ auto *DILocal = DII->getVariable();
+ if (!DILocal->isResolved())
+ DILocal->resolve();
+ }
+ }
+ }
+}
+
// This function does roughly the same thing as GenerateThunk, but in a
// very different way, so that va_start and va_end work correctly.
// FIXME: This function assumes "this" is the first non-sret LLVM argument of
@@ -154,6 +182,10 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
// Clone to thunk.
llvm::ValueToValueMapTy VMap;
+
+ // We are cloning a function while some Metadata nodes are still unresolved.
+ // Ensure that the value mapper does not encounter any of them.
+ resolveTopLevelMetadata(BaseFn, VMap);
llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap);
Fn->replaceAllUsesWith(NewFn);
NewFn->takeName(Fn);
@@ -379,12 +411,9 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD,
// Apply the standard set of call attributes.
unsigned CallingConv;
- CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(CalleePtr->getName(),
- *CurFnInfo, MD, AttributeList,
+ llvm::AttributeList Attrs;
+ CGM.ConstructAttributeList(CalleePtr->getName(), *CurFnInfo, MD, Attrs,
CallingConv, /*AttrOnCallSite=*/true);
- llvm::AttributeSet Attrs =
- llvm::AttributeSet::get(getLLVMContext(), AttributeList);
Call->setAttributes(Attrs);
Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
@@ -904,6 +933,8 @@ void CodeGenModule::EmitDeferredVTables() {
for (const CXXRecordDecl *RD : DeferredVTables)
if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD))
VTables.GenerateClassData(RD);
+ else if (shouldOpportunisticallyEmitVTables())
+ OpportunisticVTables.push_back(RD);
assert(savedSize == DeferredVTables.size() &&
"deferred extra vtables during vtable emission?");
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 53a376df64..7d07ea4516 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -20,6 +20,7 @@
#include "llvm/IR/Value.h"
#include "llvm/IR/Type.h"
#include "Address.h"
+#include "CodeGenTBAA.h"
namespace llvm {
class Constant;
@@ -146,6 +147,20 @@ static inline AlignmentSource getFieldAlignmentSource(AlignmentSource Source) {
return AlignmentSource::Decl;
}
+class LValueBaseInfo {
+ AlignmentSource AlignSource;
+
+public:
+ explicit LValueBaseInfo(AlignmentSource Source = AlignmentSource::Type)
+ : AlignSource(Source) {}
+ AlignmentSource getAlignmentSource() const { return AlignSource; }
+ void setAlignmentSource(AlignmentSource Source) { AlignSource = Source; }
+
+ void mergeForCast(const LValueBaseInfo &Info) {
+ setAlignmentSource(Info.getAlignmentSource());
+ }
+};
+
/// LValue - This represents an lvalue references. Because C/C++ allow
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
/// bitrange.
@@ -200,7 +215,8 @@ class LValue {
// to make the default bitfield pattern all-zeroes.
bool ImpreciseLifetime : 1;
- unsigned AlignSource : 2;
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
// This flag shows if a nontemporal load/stores should be used when accessing
// this lvalue.
@@ -208,18 +224,9 @@ class LValue {
Expr *BaseIvarExp;
- /// Used by struct-path-aware TBAA.
- QualType TBAABaseType;
- /// Offset relative to the base type.
- uint64_t TBAAOffset;
-
- /// TBAAInfo - TBAA information to attach to dereferences of this LValue.
- llvm::MDNode *TBAAInfo;
-
private:
- void Initialize(QualType Type, Qualifiers Quals,
- CharUnits Alignment, AlignmentSource AlignSource,
- llvm::MDNode *TBAAInfo = nullptr) {
+ void Initialize(QualType Type, Qualifiers Quals, CharUnits Alignment,
+ LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) {
assert((!Alignment.isZero() || Type->isIncompleteType()) &&
"initializing l-value with zero alignment!");
this->Type = Type;
@@ -227,7 +234,8 @@ private:
this->Alignment = Alignment.getQuantity();
assert(this->Alignment == Alignment.getQuantity() &&
"Alignment exceeds allowed max!");
- this->AlignSource = unsigned(AlignSource);
+ this->BaseInfo = BaseInfo;
+ this->TBAAInfo = TBAAInfo;
// Initialize Objective-C flags.
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
@@ -235,11 +243,6 @@ private:
this->Nontemporal = false;
this->ThreadLocalRef = false;
this->BaseIvarExp = nullptr;
-
- // Initialize fields for TBAA.
- this->TBAABaseType = Type;
- this->TBAAOffset = 0;
- this->TBAAInfo = TBAAInfo;
}
public:
@@ -299,29 +302,19 @@ public:
Expr *getBaseIvarExp() const { return BaseIvarExp; }
void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
- QualType getTBAABaseType() const { return TBAABaseType; }
- void setTBAABaseType(QualType T) { TBAABaseType = T; }
-
- uint64_t getTBAAOffset() const { return TBAAOffset; }
- void setTBAAOffset(uint64_t O) { TBAAOffset = O; }
-
- llvm::MDNode *getTBAAInfo() const { return TBAAInfo; }
- void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; }
+ TBAAAccessInfo getTBAAInfo() const { return TBAAInfo; }
+ void setTBAAInfo(TBAAAccessInfo Info) { TBAAInfo = Info; }
const Qualifiers &getQuals() const { return Quals; }
Qualifiers &getQuals() { return Quals; }
- unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
+ LangAS getAddressSpace() const { return Quals.getAddressSpace(); }
CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); }
void setAlignment(CharUnits A) { Alignment = A.getQuantity(); }
- AlignmentSource getAlignmentSource() const {
- return AlignmentSource(AlignSource);
- }
- void setAlignmentSource(AlignmentSource Source) {
- AlignSource = unsigned(Source);
- }
+ LValueBaseInfo getBaseInfo() const { return BaseInfo; }
+ void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; }
// simple lvalue
llvm::Value *getPointer() const {
@@ -368,10 +361,8 @@ public:
// global register lvalue
llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; }
- static LValue MakeAddr(Address address, QualType type,
- ASTContext &Context,
- AlignmentSource alignSource,
- llvm::MDNode *TBAAInfo = nullptr) {
+ static LValue MakeAddr(Address address, QualType type, ASTContext &Context,
+ LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) {
Qualifiers qs = type.getQualifiers();
qs.setObjCGCAttr(Context.getObjCGCAttrKind(type));
@@ -379,29 +370,31 @@ public:
R.LVType = Simple;
assert(address.getPointer()->getType()->isPointerTy());
R.V = address.getPointer();
- R.Initialize(type, qs, address.getAlignment(), alignSource, TBAAInfo);
+ R.Initialize(type, qs, address.getAlignment(), BaseInfo, TBAAInfo);
return R;
}
static LValue MakeVectorElt(Address vecAddress, llvm::Value *Idx,
- QualType type, AlignmentSource alignSource) {
+ QualType type, LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo) {
LValue R;
R.LVType = VectorElt;
R.V = vecAddress.getPointer();
R.VectorIdx = Idx;
R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
- alignSource);
+ BaseInfo, TBAAInfo);
return R;
}
static LValue MakeExtVectorElt(Address vecAddress, llvm::Constant *Elts,
- QualType type, AlignmentSource alignSource) {
+ QualType type, LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo) {
LValue R;
R.LVType = ExtVectorElt;
R.V = vecAddress.getPointer();
R.VectorElts = Elts;
R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
- alignSource);
+ BaseInfo, TBAAInfo);
return R;
}
@@ -411,15 +404,15 @@ public:
/// bit-field refers to.
/// \param Info - The information describing how to perform the bit-field
/// access.
- static LValue MakeBitfield(Address Addr,
- const CGBitFieldInfo &Info,
- QualType type,
- AlignmentSource alignSource) {
+ static LValue MakeBitfield(Address Addr, const CGBitFieldInfo &Info,
+ QualType type, LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo) {
LValue R;
R.LVType = BitField;
R.V = Addr.getPointer();
R.BitFieldInfo = &Info;
- R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), alignSource);
+ R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), BaseInfo,
+ TBAAInfo);
return R;
}
@@ -428,7 +421,7 @@ public:
R.LVType = GlobalReg;
R.V = Reg.getPointer();
R.Initialize(type, type.getQualifiers(), Reg.getAlignment(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl), TBAAAccessInfo());
return R;
}
diff --git a/lib/CodeGen/CodeGenABITypes.cpp b/lib/CodeGen/CodeGenABITypes.cpp
index 166f44f816..c152291b15 100644
--- a/lib/CodeGen/CodeGenABITypes.cpp
+++ b/lib/CodeGen/CodeGenABITypes.cpp
@@ -17,6 +17,7 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/CodeGenABITypes.h"
+#include "CGRecordLayout.h"
#include "CodeGenModule.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
@@ -64,3 +65,25 @@ CodeGen::arrangeFreeFunctionCall(CodeGenModule &CGM,
returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes,
info, {}, args);
}
+
+llvm::FunctionType *
+CodeGen::convertFreeFunctionType(CodeGenModule &CGM, const FunctionDecl *FD) {
+ assert(FD != nullptr && "Expected a non-null function declaration!");
+ llvm::Type *T = CGM.getTypes().ConvertFunctionType(FD->getType(), FD);
+
+ if (auto FT = dyn_cast<llvm::FunctionType>(T))
+ return FT;
+
+ return nullptr;
+}
+
+llvm::Type *
+CodeGen::convertTypeForMemory(CodeGenModule &CGM, QualType T) {
+ return CGM.getTypes().ConvertTypeForMem(T);
+}
+
+unsigned CodeGen::getLLVMFieldNumber(CodeGenModule &CGM,
+ const RecordDecl *RD,
+ const FieldDecl *FD) {
+ return CGM.getTypes().getCGRecordLayout(RD).getLLVMFieldNo(FD);
+}
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index b864069dc6..6ca69d63cd 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -46,6 +46,38 @@ using namespace clang;
using namespace llvm;
namespace clang {
+ class BackendConsumer;
+ class ClangDiagnosticHandler final : public DiagnosticHandler {
+ public:
+ ClangDiagnosticHandler(const CodeGenOptions &CGOpts, BackendConsumer *BCon)
+ : CodeGenOpts(CGOpts), BackendCon(BCon) {}
+
+ bool handleDiagnostics(const DiagnosticInfo &DI) override;
+
+ bool isAnalysisRemarkEnabled(StringRef PassName) const override {
+ return (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
+ CodeGenOpts.OptimizationRemarkAnalysisPattern->match(PassName));
+ }
+ bool isMissedOptRemarkEnabled(StringRef PassName) const override {
+ return (CodeGenOpts.OptimizationRemarkMissedPattern &&
+ CodeGenOpts.OptimizationRemarkMissedPattern->match(PassName));
+ }
+ bool isPassedOptRemarkEnabled(StringRef PassName) const override {
+ return (CodeGenOpts.OptimizationRemarkPattern &&
+ CodeGenOpts.OptimizationRemarkPattern->match(PassName));
+ }
+
+ bool isAnyRemarkEnabled() const override {
+ return (CodeGenOpts.OptimizationRemarkAnalysisPattern ||
+ CodeGenOpts.OptimizationRemarkMissedPattern ||
+ CodeGenOpts.OptimizationRemarkPattern);
+ }
+
+ private:
+ const CodeGenOptions &CodeGenOpts;
+ BackendConsumer *BackendCon;
+ };
+
class BackendConsumer : public ASTConsumer {
using LinkModule = CodeGenAction::LinkModule;
@@ -224,18 +256,20 @@ namespace clang {
void *OldContext = Ctx.getInlineAsmDiagnosticContext();
Ctx.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, this);
- LLVMContext::DiagnosticHandlerTy OldDiagnosticHandler =
+ std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler =
Ctx.getDiagnosticHandler();
- void *OldDiagnosticContext = Ctx.getDiagnosticContext();
- Ctx.setDiagnosticHandler(DiagnosticHandler, this);
- Ctx.setDiagnosticHotnessRequested(CodeGenOpts.DiagnosticsWithHotness);
-
- std::unique_ptr<llvm::tool_output_file> OptRecordFile;
+ Ctx.setDiagnosticHandler(llvm::make_unique<ClangDiagnosticHandler>(
+ CodeGenOpts, this));
+ Ctx.setDiagnosticsHotnessRequested(CodeGenOpts.DiagnosticsWithHotness);
+ if (CodeGenOpts.DiagnosticsHotnessThreshold != 0)
+ Ctx.setDiagnosticsHotnessThreshold(
+ CodeGenOpts.DiagnosticsHotnessThreshold);
+
+ std::unique_ptr<llvm::ToolOutputFile> OptRecordFile;
if (!CodeGenOpts.OptRecordFile.empty()) {
std::error_code EC;
- OptRecordFile =
- llvm::make_unique<llvm::tool_output_file>(CodeGenOpts.OptRecordFile,
- EC, sys::fs::F_None);
+ OptRecordFile = llvm::make_unique<llvm::ToolOutputFile>(
+ CodeGenOpts.OptRecordFile, EC, sys::fs::F_None);
if (EC) {
Diags.Report(diag::err_cannot_open_file) <<
CodeGenOpts.OptRecordFile << EC.message();
@@ -246,7 +280,7 @@ namespace clang {
llvm::make_unique<yaml::Output>(OptRecordFile->os()));
if (CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone)
- Ctx.setDiagnosticHotnessRequested(true);
+ Ctx.setDiagnosticsHotnessRequested(true);
}
// Link each LinkModule into our module.
@@ -261,7 +295,7 @@ namespace clang {
Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext);
- Ctx.setDiagnosticHandler(OldDiagnosticHandler, OldDiagnosticContext);
+ Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler));
if (OptRecordFile)
OptRecordFile->keep();
@@ -296,11 +330,6 @@ namespace clang {
((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
}
- static void DiagnosticHandler(const llvm::DiagnosticInfo &DI,
- void *Context) {
- ((BackendConsumer *)Context)->DiagnosticHandlerImpl(DI);
- }
-
/// Get the best possible source location to represent a diagnostic that
/// may have associated debug info.
const FullSourceLoc
@@ -340,6 +369,11 @@ namespace clang {
void BackendConsumer::anchor() {}
}
+bool ClangDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) {
+ BackendCon->DiagnosticHandlerImpl(DI);
+ return true;
+}
+
/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr
/// buffer to be a valid FullSourceLoc.
static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
@@ -399,6 +433,8 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
case llvm::SourceMgr::DK_Note:
DiagID = diag::note_fe_inline_asm;
break;
+ case llvm::SourceMgr::DK_Remark:
+ llvm_unreachable("remarks unexpected");
}
// If this problem has clang-level source location information, report the
// issue in the source with a note showing the instantiated
@@ -548,9 +584,9 @@ void BackendConsumer::UnsupportedDiagHandler(
StringRef Filename;
unsigned Line, Column;
- bool BadDebugInfo;
- FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename,
- Line, Column);
+ bool BadDebugInfo = false;
+ FullSourceLoc Loc =
+ getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
Diags.Report(Loc, diag::err_fe_backend_unsupported) << D.getMessage().str();
@@ -572,8 +608,8 @@ void BackendConsumer::EmitOptimizationMessage(
StringRef Filename;
unsigned Line, Column;
bool BadDebugInfo = false;
- FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename,
- Line, Column);
+ FullSourceLoc Loc =
+ getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
std::string Msg;
raw_string_ostream MsgStream(Msg);
@@ -597,6 +633,10 @@ void BackendConsumer::EmitOptimizationMessage(
void BackendConsumer::OptimizationRemarkHandler(
const llvm::DiagnosticInfoOptimizationBase &D) {
+ // Without hotness information, don't show noisy remarks.
+ if (D.isVerbose() && !D.getHotness())
+ return;
+
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.
@@ -881,6 +921,8 @@ static void BitcodeInlineAsmDiagHandler(const llvm::SMDiagnostic &SM,
case llvm::SourceMgr::DK_Note:
DiagID = diag::note_fe_inline_asm;
break;
+ case llvm::SourceMgr::DK_Remark:
+ llvm_unreachable("remarks unexpected");
}
Diags->Report(DiagID).AddString("cannot compile inline asm");
@@ -944,7 +986,7 @@ std::unique_ptr<llvm::Module> CodeGenAction::loadModule(MemoryBufferRef MBRef) {
void CodeGenAction::ExecuteAction() {
// If this is an IR file, we have to treat it specially.
- if (getCurrentFileKind() == IK_LLVM_IR) {
+ if (getCurrentFileKind().getLanguage() == InputKind::LLVM_IR) {
BackendAction BA = static_cast<BackendAction>(Act);
CompilerInstance &CI = getCompilerInstance();
std::unique_ptr<raw_pwrite_stream> OS =
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 11660b4f41..234d1a2849 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -22,6 +22,7 @@
#include "CodeGenPGO.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
@@ -45,15 +46,15 @@ static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
if (CGOpts.DisableLifetimeMarkers)
return false;
- // Asan uses markers for use-after-scope checks.
- if (CGOpts.SanitizeAddressUseAfterScope)
- return true;
-
// Disable lifetime markers in msan builds.
// FIXME: Remove this when msan works with lifetime markers.
if (LangOpts.Sanitize.has(SanitizerKind::Memory))
return false;
+ // Asan uses markers for use-after-scope checks.
+ if (CGOpts.SanitizeAddressUseAfterScope)
+ return true;
+
// For now, only in optimized builds.
return CGOpts.OptimizationLevel != 0;
}
@@ -117,25 +118,32 @@ CodeGenFunction::~CodeGenFunction() {
}
CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
- AlignmentSource *Source) {
- return getNaturalTypeAlignment(T->getPointeeType(), Source,
- /*forPointee*/ true);
+ LValueBaseInfo *BaseInfo,
+ TBAAAccessInfo *TBAAInfo) {
+ return getNaturalTypeAlignment(T->getPointeeType(), BaseInfo, TBAAInfo,
+ /* forPointeeType= */ true);
}
CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T,
- AlignmentSource *Source,
+ LValueBaseInfo *BaseInfo,
+ TBAAAccessInfo *TBAAInfo,
bool forPointeeType) {
+ if (TBAAInfo)
+ *TBAAInfo = CGM.getTBAAAccessInfo(T);
+
// Honor alignment typedef attributes even on incomplete types.
// We also honor them straight for C++ class types, even as pointees;
// there's an expressivity gap here.
if (auto TT = T->getAs<TypedefType>()) {
if (auto Align = TT->getDecl()->getMaxAlignment()) {
- if (Source) *Source = AlignmentSource::AttributedType;
+ if (BaseInfo)
+ *BaseInfo = LValueBaseInfo(AlignmentSource::AttributedType);
return getContext().toCharUnitsFromBits(Align);
}
}
- if (Source) *Source = AlignmentSource::Type;
+ if (BaseInfo)
+ *BaseInfo = LValueBaseInfo(AlignmentSource::Type);
CharUnits Alignment;
if (T->isIncompleteType()) {
@@ -165,19 +173,22 @@ CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T,
}
LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
- AlignmentSource AlignSource;
- CharUnits Alignment = getNaturalTypeAlignment(T, &AlignSource);
- return LValue::MakeAddr(Address(V, Alignment), T, getContext(), AlignSource,
- CGM.getTBAAInfo(T));
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
+ CharUnits Alignment = getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo);
+ return LValue::MakeAddr(Address(V, Alignment), T, getContext(), BaseInfo,
+ TBAAInfo);
}
/// Given a value of type T* that may not be to a complete object,
/// construct an l-value with the natural pointee alignment of T.
LValue
CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) {
- AlignmentSource AlignSource;
- CharUnits Align = getNaturalTypeAlignment(T, &AlignSource, /*pointee*/ true);
- return MakeAddrLValue(Address(V, Align), T, AlignSource);
+ LValueBaseInfo BaseInfo;
+ TBAAAccessInfo TBAAInfo;
+ CharUnits Align = getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo,
+ /* forPointeeType= */ true);
+ return MakeAddrLValue(Address(V, Align), T, BaseInfo, TBAAInfo);
}
@@ -346,7 +357,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// Emit debug descriptor for function end.
if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitFunctionEnd(Builder);
+ DI->EmitFunctionEnd(Builder, CurFn);
// Reset the debug location to that of the simple 'return' expression, if any
// rather than that of the end of the function's scope '}'.
@@ -426,6 +437,43 @@ bool CodeGenFunction::ShouldXRayInstrumentFunction() const {
return CGM.getCodeGenOpts().XRayInstrumentFunctions;
}
+llvm::Constant *
+CodeGenFunction::EncodeAddrForUseInPrologue(llvm::Function *F,
+ llvm::Constant *Addr) {
+ // Addresses stored in prologue data can't require run-time fixups and must
+ // be PC-relative. Run-time fixups are undesirable because they necessitate
+ // writable text segments, which are unsafe. And absolute addresses are
+ // undesirable because they break PIE mode.
+
+ // Add a layer of indirection through a private global. Taking its address
+ // won't result in a run-time fixup, even if Addr has linkonce_odr linkage.
+ auto *GV = new llvm::GlobalVariable(CGM.getModule(), Addr->getType(),
+ /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Addr);
+
+ // Create a PC-relative address.
+ auto *GOTAsInt = llvm::ConstantExpr::getPtrToInt(GV, IntPtrTy);
+ auto *FuncAsInt = llvm::ConstantExpr::getPtrToInt(F, IntPtrTy);
+ auto *PCRelAsInt = llvm::ConstantExpr::getSub(GOTAsInt, FuncAsInt);
+ return (IntPtrTy == Int32Ty)
+ ? PCRelAsInt
+ : llvm::ConstantExpr::getTrunc(PCRelAsInt, Int32Ty);
+}
+
+llvm::Value *
+CodeGenFunction::DecodeAddrUsedInPrologue(llvm::Value *F,
+ llvm::Value *EncodedAddr) {
+ // Reconstruct the address of the global.
+ auto *PCRelAsInt = Builder.CreateSExt(EncodedAddr, IntPtrTy);
+ auto *FuncAsInt = Builder.CreatePtrToInt(F, IntPtrTy, "func_addr.int");
+ auto *GOTAsInt = Builder.CreateAdd(PCRelAsInt, FuncAsInt, "global_addr.int");
+ auto *GOTAddr = Builder.CreateIntToPtr(GOTAsInt, Int8PtrPtrTy, "global_addr");
+
+ // Load the original pointer through the global.
+ return Builder.CreateLoad(Address(GOTAddr, getPointerAlign()),
+ "decoded_addr");
+}
+
/// EmitFunctionInstrumentation - Emit LLVM code to call the specified
/// instrumentation function with the current function and the call site, if
/// function instrumentation is enabled.
@@ -477,8 +525,8 @@ static void removeImageAccessQualifier(std::string& TyName) {
// for example in clGetKernelArgInfo() implementation between the address
// spaces with targets without unique mapping to the OpenCL address spaces
// (basically all single AS CPUs).
-static unsigned ArgInfoAddressSpace(unsigned LangAS) {
- switch (LangAS) {
+static unsigned ArgInfoAddressSpace(LangAS AS) {
+ switch (AS) {
case LangAS::opencl_global: return 1;
case LangAS::opencl_constant: return 2;
case LangAS::opencl_local: return 3;
@@ -610,11 +658,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";
}
@@ -623,7 +666,10 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
// Get image and pipe access qualifier:
if (ty->isImageType()|| ty->isPipeType()) {
- const OpenCLAccessAttr *A = parm->getAttr<OpenCLAccessAttr>();
+ const Decl *PDecl = parm;
+ if (auto *TD = dyn_cast<TypedefType>(ty))
+ PDecl = TD->getDecl();
+ const OpenCLAccessAttr *A = PDecl->getAttr<OpenCLAccessAttr>();
if (A && A->isWriteOnly())
accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
else if (A && A->isReadWrite())
@@ -663,34 +709,42 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
GenOpenCLArgMetadata(FD, Fn, CGM, Context, Builder, getContext());
if (const VecTypeHintAttr *A = FD->getAttr<VecTypeHintAttr>()) {
- QualType hintQTy = A->getTypeHint();
- const ExtVectorType *hintEltQTy = hintQTy->getAs<ExtVectorType>();
- bool isSignedInteger =
- hintQTy->isSignedIntegerType() ||
- (hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType());
- llvm::Metadata *attrMDArgs[] = {
+ QualType HintQTy = A->getTypeHint();
+ const ExtVectorType *HintEltQTy = HintQTy->getAs<ExtVectorType>();
+ bool IsSignedInteger =
+ HintQTy->isSignedIntegerType() ||
+ (HintEltQTy && HintEltQTy->getElementType()->isSignedIntegerType());
+ llvm::Metadata *AttrMDArgs[] = {
llvm::ConstantAsMetadata::get(llvm::UndefValue::get(
CGM.getTypes().ConvertType(A->getTypeHint()))),
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
llvm::IntegerType::get(Context, 32),
- llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0))))};
- Fn->setMetadata("vec_type_hint", llvm::MDNode::get(Context, attrMDArgs));
+ llvm::APInt(32, (uint64_t)(IsSignedInteger ? 1 : 0))))};
+ Fn->setMetadata("vec_type_hint", llvm::MDNode::get(Context, AttrMDArgs));
}
if (const WorkGroupSizeHintAttr *A = FD->getAttr<WorkGroupSizeHintAttr>()) {
- llvm::Metadata *attrMDArgs[] = {
+ llvm::Metadata *AttrMDArgs[] = {
llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())),
llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())),
llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))};
- Fn->setMetadata("work_group_size_hint", llvm::MDNode::get(Context, attrMDArgs));
+ Fn->setMetadata("work_group_size_hint", llvm::MDNode::get(Context, AttrMDArgs));
}
if (const ReqdWorkGroupSizeAttr *A = FD->getAttr<ReqdWorkGroupSizeAttr>()) {
- llvm::Metadata *attrMDArgs[] = {
+ llvm::Metadata *AttrMDArgs[] = {
llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())),
llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())),
llvm::ConstantAsMetadata::get(Builder.getInt32(A->getZDim()))};
- Fn->setMetadata("reqd_work_group_size", llvm::MDNode::get(Context, attrMDArgs));
+ Fn->setMetadata("reqd_work_group_size", llvm::MDNode::get(Context, AttrMDArgs));
+ }
+
+ if (const OpenCLIntelReqdSubGroupSizeAttr *A =
+ FD->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) {
+ llvm::Metadata *AttrMDArgs[] = {
+ llvm::ConstantAsMetadata::get(Builder.getInt32(A->getSubGroupSize()))};
+ Fn->setMetadata("intel_reqd_sub_group_size",
+ llvm::MDNode::get(Context, AttrMDArgs));
}
}
@@ -715,6 +769,35 @@ static void markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) {
Fn->removeFnAttr(llvm::Attribute::SanitizeThread);
}
+static bool matchesStlAllocatorFn(const Decl *D, const ASTContext &Ctx) {
+ auto *MD = dyn_cast_or_null<CXXMethodDecl>(D);
+ if (!MD || !MD->getDeclName().getAsIdentifierInfo() ||
+ !MD->getDeclName().getAsIdentifierInfo()->isStr("allocate") ||
+ (MD->getNumParams() != 1 && MD->getNumParams() != 2))
+ return false;
+
+ if (MD->parameters()[0]->getType().getCanonicalType() != Ctx.getSizeType())
+ return false;
+
+ if (MD->getNumParams() == 2) {
+ auto *PT = MD->parameters()[1]->getType()->getAs<PointerType>();
+ if (!PT || !PT->isVoidPointerType() ||
+ !PT->getPointeeType().isConstQualified())
+ return false;
+ }
+
+ return true;
+}
+
+/// Return the UBSan prologue signature for \p FD if one is available.
+static llvm::Constant *getPrologueSignature(CodeGenModule &CGM,
+ const FunctionDecl *FD) {
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
+ if (!MD->isStatic())
+ return nullptr;
+ return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM);
+}
+
void CodeGenFunction::StartFunction(GlobalDecl GD,
QualType RetTy,
llvm::Function *Fn,
@@ -738,8 +821,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?");
- if (CGM.isInSanitizerBlacklist(Fn, Loc))
- SanOpts.clear();
+ // If this function has been blacklisted for any of the enabled sanitizers,
+ // disable the sanitizer for the function.
+ do {
+#define SANITIZER(NAME, ID) \
+ if (SanOpts.empty()) \
+ break; \
+ if (SanOpts.has(SanitizerKind::ID)) \
+ if (CGM.isInSanitizerBlacklist(SanitizerKind::ID, Fn, Loc)) \
+ SanOpts.set(SanitizerKind::ID, false);
+
+#include "clang/Basic/Sanitizers.def"
+#undef SANITIZER
+ } while (0);
if (D) {
// Apply the no_sanitize* attributes to SanOpts.
@@ -774,6 +868,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
}
}
+ // Ignore unrelated casts in STL allocate() since the allocator must cast
+ // from void* to T* before object initialization completes. Don't match on the
+ // namespace because not all allocators are in std::
+ if (D && SanOpts.has(SanitizerKind::CFIUnrelatedCast)) {
+ if (matchesStlAllocatorFn(D, getContext()))
+ SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast;
+ }
+
// Apply xray attributes to the function (as a string, for now)
if (D && ShouldXRayInstrumentFunction()) {
if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
@@ -786,9 +888,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
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));
}
}
@@ -800,6 +903,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
Fn->addFnAttr("no-jump-tables",
llvm::toStringRef(CGM.getCodeGenOpts().NoUseJumpTables));
+ // Add profile-sample-accurate value.
+ if (CGM.getCodeGenOpts().ProfileSampleAccurate)
+ Fn->addFnAttr("profile-sample-accurate");
+
if (getLangOpts().OpenCL) {
// Add metadata for a kernel function.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
@@ -810,11 +917,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
// prologue data.
if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function)) {
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
- if (llvm::Constant *PrologueSig =
- CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
+ if (llvm::Constant *PrologueSig = getPrologueSignature(CGM, FD)) {
llvm::Constant *FTRTTIConst =
CGM.GetAddrOfRTTIDescriptor(FD->getType(), /*ForEH=*/true);
- llvm::Constant *PrologueStructElems[] = { PrologueSig, FTRTTIConst };
+ llvm::Constant *FTRTTIConstEncoded =
+ EncodeAddrForUseInPrologue(Fn, FTRTTIConst);
+ llvm::Constant *PrologueStructElems[] = {PrologueSig,
+ FTRTTIConstEncoded};
llvm::Constant *PrologueStructConst =
llvm::ConstantStruct::getAnon(PrologueStructElems, /*Packed=*/true);
Fn->setPrologueData(PrologueStructConst);
@@ -854,6 +963,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
Builder.SetInsertPoint(EntryBB);
+ // If we're checking the return value, allocate space for a pointer to a
+ // precise source location of the checked return statement.
+ if (requiresReturnValueCheck()) {
+ ReturnLocation = CreateDefaultAlignTempAlloca(Int8PtrTy, "return.sloc.ptr");
+ InitTempAlloca(ReturnLocation, llvm::ConstantPointerNull::get(Int8PtrTy));
+ }
+
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
// Reconstruct the type from the argument list so that implicit parameters,
@@ -881,8 +997,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
if (CGM.getCodeGenOpts().InstrumentForProfiling) {
if (CGM.getCodeGenOpts().CallFEntry)
Fn->addFnAttr("fentry-call", "true");
- else
- Fn->addFnAttr("counting-function", getTarget().getMCountName());
+ else {
+ if (!CurFuncDecl || !CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
+ Fn->addFnAttr("counting-function", getTarget().getMCountName());
+ }
}
if (RetTy->isVoidType()) {
@@ -967,13 +1085,25 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
CXXThisValue = CXXABIThisValue;
}
- // Null-check the 'this' pointer once per function, if it's available.
- if (CXXThisValue) {
+ // Check the 'this' pointer once per function, if it's available.
+ if (CXXABIThisValue) {
SanitizerSet SkippedChecks;
- SkippedChecks.set(SanitizerKind::Alignment, true);
SkippedChecks.set(SanitizerKind::ObjectSize, true);
- EmitTypeCheck(TCK_Load, Loc, CXXThisValue, MD->getThisType(getContext()),
- /*Alignment=*/CharUnits::Zero(), SkippedChecks);
+ QualType ThisTy = MD->getThisType(getContext());
+
+ // If this is the call operator of a lambda with no capture-default, it
+ // may have a static invoker function, which may call this operator with
+ // a null 'this' pointer.
+ if (isLambdaCallOperator(MD) &&
+ cast<CXXRecordDecl>(MD->getParent())->getLambdaCaptureDefault() ==
+ LCD_None)
+ SkippedChecks.set(SanitizerKind::Null, true);
+
+ EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
+ : TCK_MemberCall,
+ Loc, CXXABIThisValue, ThisTy,
+ getContext().getTypeAlignInChars(ThisTy->getPointeeType()),
+ SkippedChecks);
}
}
@@ -1076,10 +1206,9 @@ QualType CodeGenFunction::BuildFunctionArgList(GlobalDecl GD,
if (!Param->hasAttr<PassObjectSizeAttr>())
continue;
- IdentifierInfo *NoID = nullptr;
auto *Implicit = ImplicitParamDecl::Create(
- getContext(), Param->getDeclContext(), Param->getLocation(), NoID,
- getContext().getSizeType());
+ getContext(), Param->getDeclContext(), Param->getLocation(),
+ /*Id=*/nullptr, getContext().getSizeType(), ImplicitParamDecl::Other);
SizeArguments[Param] = Implicit;
Args.push_back(Implicit);
}
@@ -1158,16 +1287,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
!getLangOpts().CUDAIsDevice &&
FD->hasAttr<CUDAGlobalAttr>())
CGM.getCUDARuntime().emitDeviceStub(*this, Args);
- else if (isa<CXXConversionDecl>(FD) &&
- cast<CXXConversionDecl>(FD)->isLambdaToBlockPointerConversion()) {
- // The lambda conversion to block pointer is special; the semantics can't be
- // expressed in the AST, so IRGen needs to special-case it.
- EmitLambdaToBlockPointerBody(Args);
- } else if (isa<CXXMethodDecl>(FD) &&
- cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
+ else if (isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
// The lambda static invoker function is special, because it forwards or
// clones the body of the function call operator (but is actually static).
- EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
+ EmitLambdaStaticInvokeBody(cast<CXXMethodDecl>(FD));
} else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
(cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator() ||
cast<CXXMethodDecl>(FD)->isMoveAssignmentOperator())) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 2db8a18cef..e1034c129d 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -76,6 +76,10 @@ class ObjCAtThrowStmt;
class ObjCAtSynchronizedStmt;
class ObjCAutoreleasePoolStmt;
+namespace analyze_os_log {
+class OSLogBufferLayout;
+}
+
namespace CodeGen {
class CodeGenTypes;
class CGCallee;
@@ -111,13 +115,17 @@ enum TypeEvaluationKind {
SANITIZER_CHECK(DynamicTypeCacheMiss, dynamic_type_cache_miss, 0) \
SANITIZER_CHECK(FloatCastOverflow, float_cast_overflow, 0) \
SANITIZER_CHECK(FunctionTypeMismatch, function_type_mismatch, 0) \
+ SANITIZER_CHECK(InvalidBuiltin, invalid_builtin, 0) \
SANITIZER_CHECK(LoadInvalidValue, load_invalid_value, 0) \
SANITIZER_CHECK(MissingReturn, missing_return, 0) \
SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \
SANITIZER_CHECK(NegateOverflow, negate_overflow, 0) \
+ SANITIZER_CHECK(NullabilityArg, nullability_arg, 0) \
+ SANITIZER_CHECK(NullabilityReturn, nullability_return, 1) \
SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \
- SANITIZER_CHECK(NonnullReturn, nonnull_return, 0) \
+ SANITIZER_CHECK(NonnullReturn, nonnull_return, 1) \
SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \
+ SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0) \
SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \
SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \
SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \
@@ -173,6 +181,25 @@ public:
// because of jumps.
VarBypassDetector Bypasses;
+ // CodeGen lambda for loops and support for ordered clause
+ typedef llvm::function_ref<void(CodeGenFunction &, const OMPLoopDirective &,
+ JumpDest)>
+ CodeGenLoopTy;
+ typedef llvm::function_ref<void(CodeGenFunction &, SourceLocation,
+ const unsigned, const bool)>
+ CodeGenOrderedTy;
+
+ // Codegen lambda for loop bounds in worksharing loop constructs
+ typedef llvm::function_ref<std::pair<LValue, LValue>(
+ CodeGenFunction &, const OMPExecutableDirective &S)>
+ CodeGenLoopBoundsTy;
+
+ // Codegen lambda for loop bounds in dispatch-based loop implementation
+ typedef llvm::function_ref<std::pair<llvm::Value *, llvm::Value *>(
+ CodeGenFunction &, const OMPExecutableDirective &S, Address LB,
+ Address UB)>
+ CodeGenDispatchBoundsTy;
+
/// \brief CGBuilder insert helper. This function is called after an
/// instruction is created using Builder.
void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
@@ -240,9 +267,9 @@ public:
if (I->capturesThis())
CXXThisFieldDecl = *Field;
else if (I->capturesVariable())
- CaptureFields[I->getCapturedVar()] = *Field;
+ CaptureFields[I->getCapturedVar()->getCanonicalDecl()] = *Field;
else if (I->capturesVariableByCopy())
- CaptureFields[I->getCapturedVar()] = *Field;
+ CaptureFields[I->getCapturedVar()->getCanonicalDecl()] = *Field;
}
}
@@ -256,7 +283,7 @@ public:
/// \brief Lookup the captured field decl for a variable.
virtual const FieldDecl *lookup(const VarDecl *VD) const {
- return CaptureFields.lookup(VD);
+ return CaptureFields.lookup(VD->getCanonicalDecl());
}
bool isCXXThisExprCaptured() const { return getThisFieldDecl() != nullptr; }
@@ -686,6 +713,7 @@ public:
llvm::function_ref<Address()> PrivateGen) {
assert(PerformCleanup && "adding private to dead scope");
+ LocalVD = LocalVD->getCanonicalDecl();
// Only save it once.
if (SavedLocals.count(LocalVD)) return false;
@@ -738,6 +766,7 @@ public:
/// Checks if the global variable is captured in current function.
bool isGlobalVarCaptured(const VarDecl *VD) const {
+ VD = VD->getCanonicalDecl();
return !VD->isLocalVarDeclOrParm() && CGF.LocalDeclMap.count(VD) > 0;
}
@@ -1094,7 +1123,7 @@ private:
auto IP = CGF.Builder.saveAndClearIP();
CGF.EmitBlock(Stack.back().ExitBlock.getBlock());
CodeGen(CGF);
- CGF.EmitBranchThroughCleanup(Stack.back().ContBlock);
+ CGF.EmitBranch(Stack.back().ContBlock.getBlock());
CGF.Builder.restoreIP(IP);
Stack.back().HasBeenEmitted = true;
}
@@ -1385,6 +1414,17 @@ private:
return RetValNullabilityPrecondition;
}
+ /// Used to store precise source locations for return statements by the
+ /// runtime return value checks.
+ Address ReturnLocation = Address::invalid();
+
+ /// Check if the return value of this function requires sanitization.
+ bool requiresReturnValueCheck() const {
+ return requiresReturnValueNullabilityCheck() ||
+ (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
+ CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>());
+ }
+
llvm::BasicBlock *TerminateLandingPad;
llvm::BasicBlock *TerminateHandler;
llvm::BasicBlock *TrapBB;
@@ -1392,16 +1432,8 @@ private:
/// True if we need emit the life-time markers.
const bool ShouldEmitLifetimeMarkers;
- /// Add a kernel metadata node to the named metadata node 'opencl.kernels'.
- /// In the kernel metadata node, reference the kernel function and metadata
- /// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2):
- /// - A node for the vec_type_hint(<type>) qualifier contains string
- /// "vec_type_hint", an undefined value of the <type> data type,
- /// and a Boolean that is true if the <type> is integer and signed.
- /// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string
- /// "work_group_size_hint", and three 32-bit integers X, Y and Z.
- /// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string
- /// "reqd_work_group_size", and three 32-bit integers X, Y and Z.
+ /// Add OpenCL kernel arg metadata and the kernel attribute meatadata to
+ /// the function metadata.
void EmitOpenCLKernelMetadata(const FunctionDecl *FD,
llvm::Function *Fn);
@@ -1454,6 +1486,9 @@ public:
const TargetInfo &getTarget() const { return Target; }
llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
+ const TargetCodeGenInfo &getTargetHooks() const {
+ return CGM.getTargetCodeGenInfo();
+ }
//===--------------------------------------------------------------------===//
// Cleanups
@@ -1549,13 +1584,21 @@ public:
// Block Bits
//===--------------------------------------------------------------------===//
- llvm::Value *EmitBlockLiteral(const BlockExpr *);
+ /// Emit block literal.
+ /// \return an LLVM value which is a pointer to a struct which contains
+ /// information about the block, including the block invoke function, the
+ /// captured variables, etc.
+ /// \param InvokeF will contain the block invoke function if it is not
+ /// nullptr.
+ llvm::Value *EmitBlockLiteral(const BlockExpr *,
+ llvm::Function **InvokeF = nullptr);
static void destroyBlockInfos(CGBlockInfo *info);
llvm::Function *GenerateBlockFunction(GlobalDecl GD,
const CGBlockInfo &Info,
const DeclMapTy &ldm,
- bool IsLambdaConversionToBlock);
+ bool IsLambdaConversionToBlock,
+ bool BuildGlobalBlock);
llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo);
llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo);
@@ -1614,10 +1657,9 @@ public:
void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
CallArgList &CallArgs);
- void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
void EmitLambdaBlockInvokeBody();
void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD);
- void EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD);
+ void EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD);
void EmitAsanPrologueOrEpilogue(bool Prologue);
/// \brief Emit the unified return block, trying to avoid its emission when
@@ -1724,11 +1766,6 @@ public:
llvm::Value *EmitVTableTypeCheckedLoad(const CXXRecordDecl *RD, llvm::Value *VTable,
uint64_t VTableByteOffset);
- /// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
- /// expr can be devirtualized.
- bool CanDevirtualizeMemberFunctionCall(const Expr *Base,
- const CXXMethodDecl *MD);
-
/// EnterDtorCleanups - Enter the cleanups necessary to complete the
/// given phase of destruction for a destructor. The end result
/// should call destructors on members and base classes in reverse
@@ -1751,6 +1788,15 @@ public:
/// EmitMCountInstrumentation - Emit call to .mcount.
void EmitMCountInstrumentation();
+ /// Encode an address into a form suitable for use in a function prologue.
+ llvm::Constant *EncodeAddrForUseInPrologue(llvm::Function *F,
+ llvm::Constant *Addr);
+
+ /// Decode an address used in a function prologue, encoded by \c
+ /// EncodeAddrForUseInPrologue.
+ llvm::Value *DecodeAddrUsedInPrologue(llvm::Value *F,
+ llvm::Value *EncodedAddr);
+
/// EmitFunctionProlog - Emit the target specific LLVM code to load the
/// arguments for the given function. This is also responsible for naming the
/// LLVM function arguments.
@@ -1764,7 +1810,7 @@ public:
SourceLocation EndLoc);
/// Emit a test that checks if the return value \p RV is nonnull.
- void EmitReturnValueCheck(llvm::Value *RV, SourceLocation EndLoc);
+ void EmitReturnValueCheck(llvm::Value *RV);
/// EmitStartEHSpec - Emit the start of the exception spec.
void EmitStartEHSpec(const Decl *D);
@@ -1793,8 +1839,7 @@ public:
/// TypeOfSelfObject - Return type of object that this self represents.
QualType TypeOfSelfObject();
- /// hasAggregateLLVMType - Return true if the specified AST type will map into
- /// an aggregate LLVM type or is void.
+ /// getEvaluationKind - Return the TypeEvaluationKind of QualType \c T.
static TypeEvaluationKind getEvaluationKind(QualType T);
static bool hasScalarEvaluationKind(QualType T) {
@@ -1873,40 +1918,85 @@ public:
//===--------------------------------------------------------------------===//
LValue MakeAddrLValue(Address Addr, QualType T,
- AlignmentSource AlignSource = AlignmentSource::Type) {
- return LValue::MakeAddr(Addr, T, getContext(), AlignSource,
- CGM.getTBAAInfo(T));
+ AlignmentSource Source = AlignmentSource::Type) {
+ return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source),
+ CGM.getTBAAAccessInfo(T));
+ }
+
+ LValue MakeAddrLValue(Address Addr, QualType T, LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo) {
+ return LValue::MakeAddr(Addr, T, getContext(), BaseInfo, TBAAInfo);
}
LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment,
- AlignmentSource AlignSource = AlignmentSource::Type) {
+ AlignmentSource Source = AlignmentSource::Type) {
return LValue::MakeAddr(Address(V, Alignment), T, getContext(),
- AlignSource, CGM.getTBAAInfo(T));
+ LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T));
+ }
+
+ LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment,
+ LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) {
+ return LValue::MakeAddr(Address(V, Alignment), T, getContext(),
+ BaseInfo, TBAAInfo);
}
LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T);
LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T);
CharUnits getNaturalTypeAlignment(QualType T,
- AlignmentSource *Source = nullptr,
+ LValueBaseInfo *BaseInfo = nullptr,
+ TBAAAccessInfo *TBAAInfo = nullptr,
bool forPointeeType = false);
CharUnits getNaturalPointeeTypeAlignment(QualType T,
- AlignmentSource *Source = nullptr);
-
- Address EmitLoadOfReference(Address Ref, const ReferenceType *RefTy,
- AlignmentSource *Source = nullptr);
- LValue EmitLoadOfReferenceLValue(Address Ref, const ReferenceType *RefTy);
+ LValueBaseInfo *BaseInfo = nullptr,
+ TBAAAccessInfo *TBAAInfo = nullptr);
+
+ Address EmitLoadOfReference(LValue RefLVal,
+ LValueBaseInfo *PointeeBaseInfo = nullptr,
+ TBAAAccessInfo *PointeeTBAAInfo = nullptr);
+ LValue EmitLoadOfReferenceLValue(LValue RefLVal);
+ LValue EmitLoadOfReferenceLValue(Address RefAddr, QualType RefTy,
+ AlignmentSource Source =
+ AlignmentSource::Type) {
+ LValue RefLVal = MakeAddrLValue(RefAddr, RefTy, LValueBaseInfo(Source),
+ CGM.getTBAAAccessInfo(RefTy));
+ return EmitLoadOfReferenceLValue(RefLVal);
+ }
Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy,
- AlignmentSource *Source = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr,
+ TBAAAccessInfo *TBAAInfo = nullptr);
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy);
- /// CreateTempAlloca - This creates a alloca and inserts it into the entry
- /// block. The caller is responsible for setting an appropriate alignment on
+ /// CreateTempAlloca - This creates an alloca and inserts it into the entry
+ /// block if \p ArraySize is nullptr, otherwise inserts it at the current
+ /// insertion point of the builder. The caller is responsible for setting an
+ /// appropriate alignment on
/// the alloca.
- llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty,
- const Twine &Name = "tmp");
+ ///
+ /// \p ArraySize is the number of array elements to be allocated if it
+ /// is not nullptr.
+ ///
+ /// LangAS::Default is the address space of pointers to local variables and
+ /// temporaries, as exposed in the source language. In certain
+ /// configurations, this is not the same as the alloca address space, and a
+ /// cast is needed to lift the pointer from the alloca AS into
+ /// LangAS::Default. This can happen when the target uses a restricted
+ /// address space for the stack but the source language requires
+ /// LangAS::Default to be a generic address space. The latter condition is
+ /// common for most programming languages; OpenCL is an exception in that
+ /// LangAS::Default is the private address space, which naturally maps
+ /// to the stack.
+ ///
+ /// Because the address of a temporary is often exposed to the program in
+ /// various ways, this function will perform the cast by default. The cast
+ /// may be avoided by passing false as \p CastToDefaultAddrSpace; this is
+ /// more efficient if the caller knows that the address will not be exposed.
+ llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp",
+ llvm::Value *ArraySize = nullptr);
Address CreateTempAlloca(llvm::Type *Ty, CharUnits align,
- const Twine &Name = "tmp");
+ const Twine &Name = "tmp",
+ llvm::Value *ArraySize = nullptr,
+ bool CastToDefaultAddrSpace = true);
/// CreateDefaultAlignedTempAlloca - This creates an alloca with the
/// default ABI alignment of the given LLVM type.
@@ -1941,9 +2031,12 @@ public:
Address CreateIRTemp(QualType T, const Twine &Name = "tmp");
/// CreateMemTemp - Create a temporary memory object of the given type, with
- /// appropriate alignment.
- Address CreateMemTemp(QualType T, const Twine &Name = "tmp");
- Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp");
+ /// appropriate alignment. Cast it to the default address space if
+ /// \p CastToDefaultAddrSpace is true.
+ Address CreateMemTemp(QualType T, const Twine &Name = "tmp",
+ bool CastToDefaultAddrSpace = true);
+ Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp",
+ bool CastToDefaultAddrSpace = true);
/// CreateAggTemp - Create a temporary memory object for the given
/// aggregate type.
@@ -1984,7 +2077,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);
@@ -2075,9 +2168,8 @@ public:
llvm::BlockAddress *GetAddrOfLabel(const LabelDecl *L);
llvm::BasicBlock *GetIndirectGotoBlock();
- /// Check if \p E is a reference, or a C++ "this" pointer wrapped in value-
- /// preserving casts.
- static bool IsDeclRefOrWrappedCXXThis(const Expr *E);
+ /// 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
@@ -2290,9 +2382,17 @@ 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
};
+ /// Determine whether the pointer type check \p TCK permits null pointers.
+ static bool isNullPointerAllowed(TypeCheckKind TCK);
+
+ /// Determine whether the pointer type check \p TCK requires a vptr check.
+ static bool isVptrCheckRequired(TypeCheckKind TCK, QualType Ty);
+
/// \brief Whether any type-checking sanitizers are enabled. If \c false,
/// calls to EmitTypeCheck can be skipped.
bool sanitizePerformTypeCheck() const;
@@ -2461,6 +2561,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
//===--------------------------------------------------------------------===//
@@ -2474,7 +2580,7 @@ public:
/// This function may clear the current insertion point; callers should use
/// EnsureInsertPoint if they wish to subsequently generate code without first
/// calling EmitBlock, EmitBranch, or EmitStmt.
- void EmitStmt(const Stmt *S);
+ void EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs = None);
/// EmitSimpleStmt - Try to emit a "simple" statement which does not
/// necessarily require an insertion point or debug information; typically
@@ -2524,6 +2630,14 @@ public:
void EmitCoroutineBody(const CoroutineBodyStmt &S);
void EmitCoreturnStmt(const CoreturnStmt &S);
+ RValue EmitCoawaitExpr(const CoawaitExpr &E,
+ AggValueSlot aggSlot = AggValueSlot::ignored(),
+ bool ignoreResult = false);
+ LValue EmitCoawaitLValue(const CoawaitExpr *E);
+ RValue EmitCoyieldExpr(const CoyieldExpr &E,
+ AggValueSlot aggSlot = AggValueSlot::ignored(),
+ bool ignoreResult = false);
+ LValue EmitCoyieldLValue(const CoyieldExpr *E);
RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID);
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
@@ -2695,7 +2809,9 @@ public:
/// and initializes them with the values according to OpenMP standard.
///
/// \param D Directive (possibly) with the 'linear' clause.
- void EmitOMPLinearClauseInit(const OMPLoopDirective &D);
+ /// \return true if at least one linear variable is found that should be
+ /// initialized with the value of the original variable, false otherwise.
+ bool EmitOMPLinearClauseInit(const OMPLoopDirective &D);
typedef const llvm::function_ref<void(CodeGenFunction & /*CGF*/,
llvm::Value * /*OutlinedFn*/,
@@ -2741,7 +2857,6 @@ public:
void EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S);
void EmitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective &S);
void EmitOMPDistributeDirective(const OMPDistributeDirective &S);
- void EmitOMPDistributeLoop(const OMPDistributeDirective &S);
void EmitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective &S);
void EmitOMPDistributeParallelForSimdDirective(
@@ -2798,32 +2913,84 @@ public:
void EmitOMPPrivateLoopCounters(const OMPLoopDirective &S,
OMPPrivateScope &LoopScope);
+ /// Helper for the OpenMP loop directives.
+ void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit);
+
+ /// \brief Emit code for the worksharing loop-based directive.
+ /// \return true, if this construct has any lastprivate clause, false -
+ /// otherwise.
+ bool EmitOMPWorksharingLoop(const OMPLoopDirective &S, Expr *EUB,
+ const CodeGenLoopBoundsTy &CodeGenLoopBounds,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds);
+
+ /// Emits the lvalue for the expression with possibly captured variable.
+ LValue EmitOMPSharedLValue(const Expr *E);
+
private:
- /// Helpers for blocks
- llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info);
+ /// Helpers for blocks. Returns invoke function by \p InvokeF if it is not
+ /// nullptr. It should be called without \p InvokeF if the caller does not
+ /// need invoke function to be returned.
+ llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info,
+ llvm::Function **InvokeF = nullptr);
/// Helpers for the OpenMP loop directives.
- void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit);
void EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic = false);
void EmitOMPSimdFinal(
const OMPLoopDirective &D,
const llvm::function_ref<llvm::Value *(CodeGenFunction &)> &CondGen);
- /// \brief Emit code for the worksharing loop-based directive.
- /// \return true, if this construct has any lastprivate clause, false -
- /// otherwise.
- bool EmitOMPWorksharingLoop(const OMPLoopDirective &S);
- void EmitOMPOuterLoop(bool IsMonotonic, bool DynamicOrOrdered,
- const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk);
+
+ void EmitOMPDistributeLoop(const OMPLoopDirective &S,
+ const CodeGenLoopTy &CodeGenLoop, Expr *IncExpr);
+
+ /// struct with the values to be passed to the OpenMP loop-related functions
+ struct OMPLoopArguments {
+ /// loop lower bound
+ Address LB = Address::invalid();
+ /// loop upper bound
+ Address UB = Address::invalid();
+ /// loop stride
+ Address ST = Address::invalid();
+ /// isLastIteration argument for runtime functions
+ Address IL = Address::invalid();
+ /// Chunk value generated by sema
+ llvm::Value *Chunk = nullptr;
+ /// EnsureUpperBound
+ Expr *EUB = nullptr;
+ /// IncrementExpression
+ Expr *IncExpr = nullptr;
+ /// Loop initialization
+ Expr *Init = nullptr;
+ /// Loop exit condition
+ Expr *Cond = nullptr;
+ /// Update of LB after a whole chunk has been executed
+ Expr *NextLB = nullptr;
+ /// Update of UB after a whole chunk has been executed
+ Expr *NextUB = nullptr;
+ OMPLoopArguments() = default;
+ OMPLoopArguments(Address LB, Address UB, Address ST, Address IL,
+ llvm::Value *Chunk = nullptr, Expr *EUB = nullptr,
+ Expr *IncExpr = nullptr, Expr *Init = nullptr,
+ Expr *Cond = nullptr, Expr *NextLB = nullptr,
+ Expr *NextUB = nullptr)
+ : LB(LB), UB(UB), ST(ST), IL(IL), Chunk(Chunk), EUB(EUB),
+ IncExpr(IncExpr), Init(Init), Cond(Cond), NextLB(NextLB),
+ NextUB(NextUB) {}
+ };
+ void EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
+ const OMPLoopDirective &S, OMPPrivateScope &LoopScope,
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenLoopTy &CodeGenLoop,
+ const CodeGenOrderedTy &CodeGenOrdered);
void EmitOMPForOuterLoop(const OpenMPScheduleTy &ScheduleKind,
bool IsMonotonic, const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope, bool Ordered, Address LB,
- Address UB, Address ST, Address IL,
- llvm::Value *Chunk);
- void EmitOMPDistributeOuterLoop(
- OpenMPDistScheduleClauseKind ScheduleKind,
- const OMPDistributeDirective &S, OMPPrivateScope &LoopScope,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk);
+ OMPPrivateScope &LoopScope, bool Ordered,
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds);
+ void EmitOMPDistributeOuterLoop(OpenMPDistScheduleClauseKind ScheduleKind,
+ const OMPLoopDirective &S,
+ OMPPrivateScope &LoopScope,
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenLoopTy &CodeGenLoopContent);
/// \brief Emit code for sections directive.
void EmitSections(const OMPExecutableDirective &S);
@@ -2921,11 +3088,15 @@ public:
/// the LLVM value representation.
llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty,
SourceLocation Loc,
- AlignmentSource AlignSource =
- AlignmentSource::Type,
- llvm::MDNode *TBAAInfo = nullptr,
- QualType TBAABaseTy = QualType(),
- uint64_t TBAAOffset = 0,
+ AlignmentSource Source = AlignmentSource::Type,
+ bool isNontemporal = false) {
+ return EmitLoadOfScalar(Addr, Volatile, Ty, Loc, LValueBaseInfo(Source),
+ CGM.getTBAAAccessInfo(Ty), isNontemporal);
+ }
+
+ llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty,
+ SourceLocation Loc, LValueBaseInfo BaseInfo,
+ TBAAAccessInfo TBAAInfo,
bool isNontemporal = false);
/// EmitLoadOfScalar - Load a scalar value from an address, taking
@@ -2939,10 +3110,16 @@ public:
/// the LLVM value representation.
void EmitStoreOfScalar(llvm::Value *Value, Address Addr,
bool Volatile, QualType Ty,
- AlignmentSource AlignSource = AlignmentSource::Type,
- llvm::MDNode *TBAAInfo = nullptr, bool isInit = false,
- QualType TBAABaseTy = QualType(),
- uint64_t TBAAOffset = 0, bool isNontemporal = false);
+ AlignmentSource Source = AlignmentSource::Type,
+ bool isInit = false, bool isNontemporal = false) {
+ EmitStoreOfScalar(Value, Addr, Volatile, Ty, LValueBaseInfo(Source),
+ CGM.getTBAAAccessInfo(Ty), isInit, isNontemporal);
+ }
+
+ void EmitStoreOfScalar(llvm::Value *Value, Address Addr,
+ bool Volatile, QualType Ty,
+ LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo,
+ bool isInit = false, bool isNontemporal = false);
/// EmitStoreOfScalar - Store a scalar value to an address, taking
/// care to appropriately convert from the memory representation to
@@ -3012,7 +3189,8 @@ public:
RValue EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc);
Address EmitArrayToPointerDecay(const Expr *Array,
- AlignmentSource *AlignSource = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr,
+ TBAAAccessInfo *TBAAInfo = nullptr);
class ConstantEmission {
llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference;
@@ -3045,6 +3223,7 @@ public:
};
ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr);
+ ConstantEmission tryEmitAsConstant(const MemberExpr *ME);
RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e,
AggValueSlot slot = AggValueSlot::ignored());
@@ -3153,7 +3332,8 @@ public:
Address EmitCXXMemberDataPointerAddress(const Expr *E, Address base,
llvm::Value *memberPtr,
const MemberPointerType *memberPtrType,
- AlignmentSource *AlignSource = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr,
+ TBAAAccessInfo *TBAAInfo = nullptr);
RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
ReturnValueSlot ReturnValue);
@@ -3172,6 +3352,13 @@ public:
unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue);
+ /// Emit IR for __builtin_os_log_format.
+ RValue emitBuiltinOSLogFormat(const CallExpr &E);
+
+ llvm::Function *generateBuiltinOSLogHelperFunction(
+ const analyze_os_log::OSLogBufferLayout &Layout,
+ CharUnits BufferAlignment);
+
RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue);
/// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call
@@ -3290,6 +3477,7 @@ public:
static Destroyer destroyARCStrongImprecise;
static Destroyer destroyARCStrongPrecise;
static Destroyer destroyARCWeak;
+ static Destroyer emitARCIntrinsicUse;
void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
llvm::Value *EmitObjCAutoreleasePoolPush();
@@ -3383,6 +3571,14 @@ public:
void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr,
bool PerformInit);
+ enum class GuardKind { VariableGuard, TlsGuard };
+
+ /// Emit a branch to select whether or not to perform guarded initialization.
+ void EmitCXXGuardedInitBranch(llvm::Value *NeedsInit,
+ llvm::BasicBlock *InitBlock,
+ llvm::BasicBlock *NoInitBlock,
+ GuardKind Kind, const VarDecl *D);
+
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
/// variables.
void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
@@ -3391,9 +3587,10 @@ public:
/// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
/// variables.
- void GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
- const std::vector<std::pair<llvm::WeakVH,
- llvm::Constant*> > &DtorsAndObjects);
+ void GenerateCXXGlobalDtorsFunc(
+ llvm::Function *Fn,
+ const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>>
+ &DtorsAndObjects);
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
@@ -3475,6 +3672,33 @@ public:
/// nonnull, if \p LHS is marked _Nonnull.
void EmitNullabilityCheck(LValue LHS, llvm::Value *RHS, SourceLocation Loc);
+ /// An enumeration which makes it easier to specify whether or not an
+ /// operation is a subtraction.
+ enum { NotSubtraction = false, IsSubtraction = true };
+
+ /// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
+ /// detect undefined behavior when the pointer overflow sanitizer is enabled.
+ /// \p SignedIndices indicates whether any of the GEP indices are signed.
+ /// \p IsSubtraction indicates whether the expression used to form the GEP
+ /// is a subtraction.
+ llvm::Value *EmitCheckedInBoundsGEP(llvm::Value *Ptr,
+ ArrayRef<llvm::Value *> IdxList,
+ bool SignedIndices,
+ bool IsSubtraction,
+ SourceLocation Loc,
+ const Twine &Name = "");
+
+ /// Specifies which type of sanitizer check to apply when handling a
+ /// particular builtin.
+ enum BuiltinCheckKind {
+ BCK_CTZPassedZero,
+ BCK_CLZPassedZero,
+ };
+
+ /// Emits an argument for a call to a builtin. If the builtin sanitizer is
+ /// enabled, a runtime check specified by \p Kind is also emitted.
+ llvm::Value *EmitCheckedArgForBuiltin(const Expr *E, BuiltinCheckKind Kind);
+
/// \brief Emit a description of a type in a format suitable for passing to
/// a runtime sanitizer handler.
llvm::Constant *EmitCheckTypeDescriptor(QualType T);
@@ -3508,6 +3732,9 @@ 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();
@@ -3667,39 +3894,32 @@ public:
unsigned ParamsToSkip = 0,
EvaluationOrder Order = EvaluationOrder::Default);
- /// EmitPointerWithAlignment - Given an expression with a pointer
- /// type, emit the value and compute our best estimate of the
- /// alignment of the pointee.
+ /// EmitPointerWithAlignment - Given an expression with a pointer type,
+ /// emit the value and compute our best estimate of the alignment of the
+ /// pointee.
///
- /// Note that this function will conservatively fall back on the type
- /// when it doesn't
+ /// \param BaseInfo - If non-null, this will be initialized with
+ /// information about the source of the alignment and the may-alias
+ /// attribute. Note that this function will conservatively fall back on
+ /// the type when it doesn't recognize the expression and may-alias will
+ /// be set to false.
///
- /// \param Source - If non-null, this will be initialized with
- /// information about the source of the alignment. Note that this
- /// function will conservatively fall back on the type when it
- /// doesn't recognize the expression, which means that sometimes
- ///
- /// a worst-case One
- /// reasonable way to use this information is when there's a
- /// language guarantee that the pointer must be aligned to some
- /// stricter value, and we're simply trying to ensure that
- /// sufficiently obvious uses of under-aligned objects don't get
- /// miscompiled; for example, a placement new into the address of
- /// a local variable. In such a case, it's quite reasonable to
- /// just ignore the returned alignment when it isn't from an
- /// explicit source.
+ /// One reasonable way to use this information is when there's a language
+ /// guarantee that the pointer must be aligned to some stricter value, and
+ /// we're simply trying to ensure that sufficiently obvious uses of under-
+ /// aligned objects don't get miscompiled; for example, a placement new
+ /// into the address of a local variable. In such a case, it's quite
+ /// reasonable to just ignore the returned alignment when it isn't from an
+ /// explicit source.
Address EmitPointerWithAlignment(const Expr *Addr,
- AlignmentSource *Source = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr,
+ TBAAAccessInfo *TBAAInfo = nullptr);
void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
private:
QualType getVarArgType(const Expr *Arg);
- const TargetCodeGenInfo &getTargetHooks() const {
- return CGM.getTargetCodeGenInfo();
- }
-
void EmitDeclMetadata();
BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType,
@@ -3708,6 +3928,11 @@ private:
void AddObjCARCExceptionMetadata(llvm::Instruction *Inst);
llvm::Value *GetValueForARMHint(unsigned BuiltinID);
+ llvm::Value *EmitX86CpuIs(const CallExpr *E);
+ llvm::Value *EmitX86CpuIs(StringRef CPUStr);
+ llvm::Value *EmitX86CpuSupports(const CallExpr *E);
+ llvm::Value *EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs);
+ llvm::Value *EmitX86CpuInit();
};
/// Helper class with most of the code for saving a value for a
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index a3920e1add..b2a18a03f2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -23,7 +23,7 @@
#include "CGOpenMPRuntimeNVPTX.h"
#include "CodeGenFunction.h"
#include "CodeGenPGO.h"
-#include "CodeGenTBAA.h"
+#include "ConstantEmitter.h"
#include "CoverageMappingGen.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
@@ -45,6 +45,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DataLayout.h"
@@ -59,6 +60,11 @@
using namespace clang;
using namespace CodeGen;
+static llvm::cl::opt<bool> LimitedCoverage(
+ "limited-coverage-experimental", llvm::cl::ZeroOrMore,
+ llvm::cl::desc("Emit limited coverage mapping information (experimental)"),
+ llvm::cl::init(false));
+
static const char AnnotationSection[] = "llvm.metadata";
static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
@@ -111,6 +117,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
C.getTargetInfo().getMaxPointerWidth());
Int8PtrTy = Int8Ty->getPointerTo(0);
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
+ AllocaInt8PtrTy = Int8Ty->getPointerTo(
+ M.getDataLayout().getAllocaAddrSpace());
+ ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace();
RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
BuiltinCC = getTargetCodeGenInfo().getABIInfo().getBuiltinCC();
@@ -367,13 +376,18 @@ void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags,
if (MainFile.empty())
MainFile = "<stdin>";
Diags.Report(diag::warn_profile_data_unprofiled) << MainFile;
- } else
- Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Missing
- << Mismatched;
+ } else {
+ if (Mismatched > 0)
+ Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Mismatched;
+
+ if (Missing > 0)
+ Diags.Report(diag::warn_profile_data_missing) << Visited << Missing;
+ }
}
void CodeGenModule::Release() {
EmitDeferred();
+ EmitVTablesOpportunistically();
applyGlobalValReplacements();
applyReplacements();
checkAliases();
@@ -392,8 +406,11 @@ void CodeGenModule::Release() {
}
if (OpenMPRuntime)
if (llvm::Function *OpenMPRegistrationFunction =
- OpenMPRuntime->emitRegistrationFunction())
- AddGlobalCtor(OpenMPRegistrationFunction, 0);
+ OpenMPRuntime->emitRegistrationFunction()) {
+ auto ComdatKey = OpenMPRegistrationFunction->hasComdat() ?
+ OpenMPRegistrationFunction : nullptr;
+ AddGlobalCtor(OpenMPRegistrationFunction, 0, ComdatKey);
+ }
if (PGOReader) {
getModule().setProfileSummary(PGOReader->getSummary().getMD(VMContext));
if (PGOStats.hasDiagnostics())
@@ -406,8 +423,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 +436,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.
@@ -450,17 +476,17 @@ void CodeGenModule::Release() {
llvm::DEBUG_METADATA_VERSION);
// We need to record the widths of enums and wchar_t, so that we can generate
- // the correct build attributes in the ARM backend.
+ // the correct build attributes in the ARM backend. wchar_size is also used by
+ // TargetLibraryInfo.
+ uint64_t WCharWidth =
+ Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity();
+ getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth);
+
llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
if ( Arch == llvm::Triple::arm
|| Arch == llvm::Triple::armeb
|| Arch == llvm::Triple::thumb
|| Arch == llvm::Triple::thumbeb) {
- // Width of wchar_t in bytes
- uint64_t WCharWidth =
- Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity();
- getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth);
-
// The minimum width of an enum in bytes
uint64_t EnumWidth = Context.getLangOpts().ShortEnums ? 1 : 4;
getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
@@ -479,6 +505,26 @@ void CodeGenModule::Release() {
LangOpts.CUDADeviceFlushDenormalsToZero ? 1 : 0);
}
+ // Emit OpenCL specific module metadata: OpenCL/SPIR version.
+ if (LangOpts.OpenCL) {
+ EmitOpenCLMetadata();
+ // Emit SPIR version.
+ if (getTriple().getArch() == llvm::Triple::spir ||
+ getTriple().getArch() == llvm::Triple::spir64) {
+ // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the
+ // opencl.spir.version named metadata.
+ llvm::Metadata *SPIRVerElts[] = {
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, LangOpts.OpenCLVersion / 100)),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, (LangOpts.OpenCLVersion / 100 > 1) ? 0 : 2))};
+ llvm::NamedMDNode *SPIRVerMD =
+ TheModule.getOrInsertNamedMetadata("opencl.spir.version");
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+ SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts));
+ }
+ }
+
if (uint32_t PLevel = Context.getLangOpts().PICLevel) {
assert(PLevel < 3 && "Invalid PIC Level");
getModule().setPICLevel(static_cast<llvm::PICLevel::Level>(PLevel));
@@ -502,6 +548,20 @@ void CodeGenModule::Release() {
EmitTargetMetadata();
}
+void CodeGenModule::EmitOpenCLMetadata() {
+ // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
+ // opencl.ocl.version named metadata node.
+ llvm::Metadata *OCLVerElts[] = {
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, LangOpts.OpenCLVersion / 100)),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, (LangOpts.OpenCLVersion % 100) / 10))};
+ llvm::NamedMDNode *OCLVerMD =
+ TheModule.getOrInsertNamedMetadata("opencl.ocl.version");
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+ OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
+}
+
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
// Make sure that this type is translated.
Types.UpdateCompletedType(TD);
@@ -512,16 +572,20 @@ void CodeGenModule::RefreshTypeCacheForClass(const CXXRecordDecl *RD) {
Types.RefreshTypeCacheForClass(RD);
}
-llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) {
+llvm::MDNode *CodeGenModule::getTBAATypeInfo(QualType QTy) {
if (!TBAA)
return nullptr;
- return TBAA->getTBAAInfo(QTy);
+ return TBAA->getTypeInfo(QTy);
}
-llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() {
+TBAAAccessInfo CodeGenModule::getTBAAAccessInfo(QualType AccessType) {
+ return TBAAAccessInfo(getTBAATypeInfo(AccessType));
+}
+
+TBAAAccessInfo CodeGenModule::getTBAAVTablePtrAccessInfo() {
if (!TBAA)
- return nullptr;
- return TBAA->getTBAAInfoForVTablePtr();
+ return TBAAAccessInfo();
+ return TBAA->getVTablePtrAccessInfo();
}
llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
@@ -530,36 +594,43 @@ llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
return TBAA->getTBAAStructInfo(QTy);
}
-llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy,
- llvm::MDNode *AccessN,
- uint64_t O) {
+llvm::MDNode *CodeGenModule::getTBAABaseTypeInfo(QualType QTy) {
if (!TBAA)
return nullptr;
- return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O);
+ return TBAA->getBaseTypeInfo(QTy);
+}
+
+llvm::MDNode *CodeGenModule::getTBAAAccessTagInfo(TBAAAccessInfo Info) {
+ if (!TBAA)
+ return nullptr;
+ return TBAA->getAccessTagInfo(Info);
+}
+
+TBAAAccessInfo CodeGenModule::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
+ TBAAAccessInfo TargetInfo) {
+ if (!TBAA)
+ return TBAAAccessInfo();
+ return TBAA->mergeTBAAInfoForCast(SourceInfo, TargetInfo);
+}
+
+TBAAAccessInfo
+CodeGenModule::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+ TBAAAccessInfo InfoB) {
+ if (!TBAA)
+ return TBAAAccessInfo();
+ return TBAA->mergeTBAAInfoForConditionalOperator(InfoA, InfoB);
}
-/// Decorate the instruction with a TBAA tag. For both scalar TBAA
-/// and struct-path aware TBAA, the tag has the same format:
-/// base type, access type and offset.
-/// When ConvertTypeToTag is true, we create a tag based on the scalar type.
void CodeGenModule::DecorateInstructionWithTBAA(llvm::Instruction *Inst,
- llvm::MDNode *TBAAInfo,
- bool ConvertTypeToTag) {
- if (ConvertTypeToTag && TBAA)
- Inst->setMetadata(llvm::LLVMContext::MD_tbaa,
- TBAA->getTBAAScalarTagInfo(TBAAInfo));
- else
- Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
+ TBAAAccessInfo TBAAInfo) {
+ if (llvm::MDNode *Tag = getTBAAAccessTagInfo(TBAAInfo))
+ Inst->setMetadata(llvm::LLVMContext::MD_tbaa, Tag);
}
void CodeGenModule::DecorateInstructionWithInvariantGroup(
llvm::Instruction *I, const CXXRecordDecl *RD) {
- llvm::Metadata *MD = CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
- auto *MetaDataNode = dyn_cast<llvm::MDNode>(MD);
- // Check if we have to wrap MDString in MDNode.
- if (!MetaDataNode)
- MetaDataNode = llvm::MDNode::get(getLLVMContext(), MD);
- I->setMetadata(llvm::LLVMContext::MD_invariant_group, MetaDataNode);
+ I->setMetadata(llvm::LLVMContext::MD_invariant_group,
+ llvm::MDNode::get(getLLVMContext(), {}));
}
void CodeGenModule::Error(SourceLocation loc, StringRef message) {
@@ -655,9 +726,9 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
}
}
- StringRef &FoundStr = MangledDeclNames[CanonicalGD];
- if (!FoundStr.empty())
- return FoundStr;
+ auto FoundName = MangledDeclNames.find(CanonicalGD);
+ if (FoundName != MangledDeclNames.end())
+ return FoundName->second;
const auto *ND = cast<NamedDecl>(GD.getDecl());
SmallString<256> Buffer;
@@ -688,7 +759,7 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
// Keep the first result in the case of a mangling collision.
auto Result = Manglings.insert(std::make_pair(Str, GD));
- return FoundStr = Result.first->first();
+ return MangledDeclNames[CanonicalGD] = Result.first->first();
}
StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD,
@@ -740,7 +811,7 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
// Get the type of a ctor entry, { i32, void ()*, i8* }.
llvm::StructType *CtorStructTy = llvm::StructType::get(
- Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, nullptr);
+ Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy);
// Construct the constructor and destructor arrays.
ConstantInitBuilder builder(*this);
@@ -830,10 +901,9 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
const CGFunctionInfo &Info,
llvm::Function *F) {
unsigned CallingConv;
- AttributeListType AttributeList;
- ConstructAttributeList(F->getName(), Info, D, AttributeList, CallingConv,
- false);
- F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList));
+ llvm::AttributeList PAL;
+ ConstructAttributeList(F->getName(), Info, D, PAL, CallingConv, false);
+ F->setAttributes(PAL);
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -882,14 +952,20 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining)
B.addAttribute(llvm::Attribute::NoInline);
- F->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(
- F->getContext(),
- llvm::AttributeSet::FunctionIndex, B));
+ F->addAttributes(llvm::AttributeList::FunctionIndex, B);
return;
}
- if (D->hasAttr<OptimizeNoneAttr>()) {
+ // Track whether we need to add the optnone LLVM attribute,
+ // starting with the default for this optimization level.
+ bool ShouldAddOptNone =
+ !CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0;
+ // We can't add optnone in the following cases, it won't pass the verifier.
+ ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
+ ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline);
+ ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();
+
+ if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) {
B.addAttribute(llvm::Attribute::OptimizeNone);
// OptimizeNone implies noinline; we should not be inlining such functions.
@@ -943,7 +1019,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// function.
if (!D->hasAttr<OptimizeNoneAttr>()) {
if (D->hasAttr<ColdAttr>()) {
- B.addAttribute(llvm::Attribute::OptimizeForSize);
+ if (!ShouldAddOptNone)
+ B.addAttribute(llvm::Attribute::OptimizeForSize);
B.addAttribute(llvm::Attribute::Cold);
}
@@ -951,9 +1028,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::MinSize);
}
- F->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(
- F->getContext(), llvm::AttributeSet::FunctionIndex, B));
+ F->addAttributes(llvm::AttributeList::FunctionIndex, B);
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
@@ -999,11 +1074,27 @@ void CodeGenModule::setNonAliasAttributes(const Decl *D,
llvm::GlobalObject *GO) {
SetCommonAttributes(D, GO);
- if (D)
+ if (D) {
+ if (auto *GV = dyn_cast<llvm::GlobalVariable>(GO)) {
+ if (auto *SA = D->getAttr<PragmaClangBSSSectionAttr>())
+ GV->addAttribute("bss-section", SA->getName());
+ if (auto *SA = D->getAttr<PragmaClangDataSectionAttr>())
+ GV->addAttribute("data-section", SA->getName());
+ if (auto *SA = D->getAttr<PragmaClangRodataSectionAttr>())
+ GV->addAttribute("rodata-section", SA->getName());
+ }
+
+ if (auto *F = dyn_cast<llvm::Function>(GO)) {
+ if (auto *SA = D->getAttr<PragmaClangTextSectionAttr>())
+ if (!D->getAttr<SectionAttr>())
+ F->addFnAttr("implicit-section-name", SA->getName());
+ }
+
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GO->setSection(SA->getName());
+ }
- getTargetCodeGenInfo().setTargetAttributes(D, GO, *this);
+ getTargetCodeGenInfo().setTargetAttributes(D, GO, *this, ForDefinition);
}
void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
@@ -1021,7 +1112,7 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
const NamedDecl *ND) {
// Set linkage and visibility in case we never see a definition.
LinkageInfo LV = ND->getLinkageAndVisibility();
- if (LV.getLinkage() != ExternalLinkage) {
+ if (!isExternallyVisible(LV.getLinkage())) {
// Don't set internal linkage on declarations.
} else {
if (ND->hasAttr<DLLImportAttr>()) {
@@ -1029,7 +1120,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.
@@ -1062,6 +1152,7 @@ void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD,
llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
F->addTypeMetadata(0, MD);
+ F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
// Emit a hash-based bit set entry for cross-DSO calls.
if (CodeGenOpts.SanitizeCfiCrossDso)
@@ -1071,7 +1162,9 @@ void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD,
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
bool IsIncompleteFunction,
- bool IsThunk) {
+ bool IsThunk,
+ ForDefinition_t IsForDefinition) {
+
if (llvm::Intrinsic::ID IID = F->getIntrinsicID()) {
// If this is an intrinsic function, set the function's attributes
// to the intrinsic's attributes.
@@ -1081,8 +1174,13 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
const auto *FD = cast<FunctionDecl>(GD.getDecl());
- if (!IsIncompleteFunction)
+ if (!IsIncompleteFunction) {
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
+ // Setup target-specific attributes.
+ if (!IsForDefinition)
+ getTargetCodeGenInfo().setTargetAttributes(FD, F, *this,
+ NotForDefinition);
+ }
// Add the Returned attribute for "this", except for iOS 5 and earlier
// where substantial code, including the libstdc++ dylib, was compiled with
@@ -1101,13 +1199,17 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
setLinkageAndVisibilityForGV(F, FD);
+ if (FD->getAttr<PragmaClangTextSectionAttr>()) {
+ F->addFnAttr("implicit-section-name");
+ }
+
if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
if (FD->isReplaceableGlobalAllocationFunction()) {
// A replaceable global allocation function does not act like a builtin by
// default, only if it is invoked by a new-expression or delete-expression.
- F->addAttribute(llvm::AttributeSet::FunctionIndex,
+ F->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoBuiltin);
// A sane operator new returns a non-aliasing pointer.
@@ -1116,7 +1218,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
auto Kind = FD->getDeclName().getCXXOverloadedOperator();
if (getCodeGenOpts().AssumeSaneOperatorNew &&
(Kind == OO_New || Kind == OO_Array_New))
- F->addAttribute(llvm::AttributeSet::ReturnIndex,
+ F->addAttribute(llvm::AttributeList::ReturnIndex,
llvm::Attribute::NoAlias);
}
@@ -1145,7 +1247,7 @@ void CodeGenModule::addCompilerUsedGlobal(llvm::GlobalValue *GV) {
}
static void emitUsed(CodeGenModule &CGM, StringRef Name,
- std::vector<llvm::WeakVH> &List) {
+ std::vector<llvm::WeakTrackingVH> &List) {
// Don't create llvm.used if there is no need.
if (List.empty())
return;
@@ -1197,7 +1299,7 @@ void CodeGenModule::AddDependentLib(StringRef Lib) {
/// \brief Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
- SmallVectorImpl<llvm::Metadata *> &Metadata,
+ SmallVectorImpl<llvm::MDNode *> &Metadata,
llvm::SmallPtrSet<Module *, 16> &Visited) {
// Import this module's parent.
if (Mod->Parent && Visited.insert(Mod->Parent).second) {
@@ -1285,7 +1387,7 @@ void CodeGenModule::EmitModuleLinkOptions() {
// Add link options for all of the imported modules in reverse topological
// order. We don't do anything to try to order import link flags with respect
// to linker options inserted by things like #pragma comment().
- SmallVector<llvm::Metadata *, 16> MetadataArgs;
+ SmallVector<llvm::MDNode *, 16> MetadataArgs;
Visited.clear();
for (Module *M : LinkModules)
if (Visited.insert(M).second)
@@ -1294,9 +1396,9 @@ void CodeGenModule::EmitModuleLinkOptions() {
LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end());
// Add the linker options metadata flag.
- getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
- llvm::MDNode::get(getLLVMContext(),
- LinkerOptionsMetadata));
+ auto *NMD = getModule().getOrInsertNamedMetadata("llvm.linker.options");
+ for (auto *MD : LinkerOptionsMetadata)
+ NMD->addOperand(MD);
}
void CodeGenModule::EmitDeferred() {
@@ -1319,13 +1421,10 @@ void CodeGenModule::EmitDeferred() {
// Grab the list of decls to emit. If EmitGlobalDefinition schedules more
// work, it will not interfere with this.
- std::vector<DeferredGlobal> CurDeclsToEmit;
+ std::vector<GlobalDecl> CurDeclsToEmit;
CurDeclsToEmit.swap(DeferredDeclsToEmit);
- for (DeferredGlobal &G : CurDeclsToEmit) {
- GlobalDecl D = G.GD;
- G.GV = nullptr;
-
+ for (GlobalDecl &D : CurDeclsToEmit) {
// We should call GetAddrOfGlobal with IsForDefinition set to true in order
// to get GlobalValue with exactly the type we need, not something that
// might had been created for another decl with the same mangled name but
@@ -1364,6 +1463,24 @@ void CodeGenModule::EmitDeferred() {
}
}
+void CodeGenModule::EmitVTablesOpportunistically() {
+ // Try to emit external vtables as available_externally if they have emitted
+ // all inlined virtual functions. It runs after EmitDeferred() and therefore
+ // is not allowed to create new references to things that need to be emitted
+ // lazily. Note that it also uses fact that we eagerly emitting RTTI.
+
+ assert((OpportunisticVTables.empty() || shouldOpportunisticallyEmitVTables())
+ && "Only emit opportunistic vtables with optimizations");
+
+ for (const CXXRecordDecl *RD : OpportunisticVTables) {
+ assert(getVTables().isVTableExternal(RD) &&
+ "This queue should only contain external vtables");
+ if (getCXXABI().canSpeculativelyEmitVTable(RD))
+ VTables.GenerateClassData(RD);
+ }
+ OpportunisticVTables.clear();
+}
+
void CodeGenModule::EmitGlobalAnnotations() {
if (Annotations.empty())
return;
@@ -1435,20 +1552,21 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
}
-bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn,
+bool CodeGenModule::isInSanitizerBlacklist(SanitizerMask Kind,
+ llvm::Function *Fn,
SourceLocation Loc) const {
const auto &SanitizerBL = getContext().getSanitizerBlacklist();
// Blacklist by function name.
- if (SanitizerBL.isBlacklistedFunction(Fn->getName()))
+ if (SanitizerBL.isBlacklistedFunction(Kind, Fn->getName()))
return true;
// Blacklist by location.
if (Loc.isValid())
- return SanitizerBL.isBlacklistedLocation(Loc);
+ return SanitizerBL.isBlacklistedLocation(Kind, Loc);
// If location is unknown, this may be a compiler-generated function. Assume
// it's located in the main file.
auto &SM = Context.getSourceManager();
if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- return SanitizerBL.isBlacklistedFile(MainFile->getName());
+ return SanitizerBL.isBlacklistedFile(Kind, MainFile->getName());
}
return false;
}
@@ -1457,13 +1575,14 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
SourceLocation Loc, QualType Ty,
StringRef Category) const {
// For now globals can be blacklisted only in ASan and KASan.
- if (!LangOpts.Sanitize.hasOneOf(
- SanitizerKind::Address | SanitizerKind::KernelAddress))
+ const SanitizerMask EnabledAsanMask = LangOpts.Sanitize.Mask &
+ (SanitizerKind::Address | SanitizerKind::KernelAddress);
+ if (!EnabledAsanMask)
return false;
const auto &SanitizerBL = getContext().getSanitizerBlacklist();
- if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category))
+ if (SanitizerBL.isBlacklistedGlobal(EnabledAsanMask, GV->getName(), Category))
return true;
- if (SanitizerBL.isBlacklistedLocation(Loc, Category))
+ if (SanitizerBL.isBlacklistedLocation(EnabledAsanMask, Loc, Category))
return true;
// Check global type.
if (!Ty.isNull()) {
@@ -1475,13 +1594,41 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
// We allow to blacklist only record types (classes, structs etc.)
if (Ty->isRecordType()) {
std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy());
- if (SanitizerBL.isBlacklistedType(TypeStr, Category))
+ if (SanitizerBL.isBlacklistedType(EnabledAsanMask, TypeStr, Category))
return true;
}
}
return false;
}
+bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
+ StringRef Category) const {
+ if (!LangOpts.XRayInstrument)
+ return false;
+ const auto &XRayFilter = getContext().getXRayFilter();
+ using ImbueAttr = XRayFunctionFilter::ImbueAttribute;
+ auto Attr = XRayFunctionFilter::ImbueAttribute::NONE;
+ if (Loc.isValid())
+ Attr = XRayFilter.shouldImbueLocation(Loc, Category);
+ if (Attr == ImbueAttr::NONE)
+ Attr = XRayFilter.shouldImbueFunction(Fn->getName());
+ switch (Attr) {
+ case ImbueAttr::NONE:
+ return false;
+ case ImbueAttr::ALWAYS:
+ Fn->addFnAttr("function-instrument", "xray-always");
+ break;
+ case ImbueAttr::ALWAYS_ARG1:
+ Fn->addFnAttr("function-instrument", "xray-always");
+ Fn->addFnAttr("xray-log-args", "1");
+ break;
+ case ImbueAttr::NEVER:
+ Fn->addFnAttr("function-instrument", "xray-never");
+ break;
+ }
+ return true;
+}
+
bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
if (LangOpts.EmitAllDecls)
@@ -1678,13 +1825,13 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
StringRef MangledName = getMangledName(GD);
- if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) {
+ if (GetGlobalValue(MangledName) != nullptr) {
// The value has already been used and should therefore be emitted.
- addDeferredDeclToEmit(GV, GD);
+ addDeferredDeclToEmit(GD);
} else if (MustBeEmitted(Global)) {
// The value must be emitted, but cannot be emitted eagerly.
assert(!MayBeEmittedEagerly(Global));
- addDeferredDeclToEmit(/*GV=*/nullptr, GD);
+ addDeferredDeclToEmit(GD);
} else {
// Otherwise, remember that we saw a deferred decl with this name. The
// first use of the mangled name will cause it to move into
@@ -1856,6 +2003,10 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
return !isTriviallyRecursive(F);
}
+bool CodeGenModule::shouldOpportunisticallyEmitVTables() {
+ return CodeGenOpts.OptimizationLevel > 0;
+}
+
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
const auto *D = cast<ValueDecl>(GD.getDecl());
@@ -1904,13 +2055,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.
@@ -1999,13 +2147,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));
+ SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk,
+ IsForDefinition);
+ if (ExtraAttrs.hasAttributes(llvm::AttributeList::FunctionIndex)) {
+ llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex);
+ F->addAttributes(llvm::AttributeList::FunctionIndex, B);
}
if (!DontDefer) {
@@ -2015,7 +2161,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
if (D && isa<CXXDestructorDecl>(D) &&
getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
GD.getDtorType()))
- addDeferredDeclToEmit(F, GD);
+ addDeferredDeclToEmit(GD);
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
@@ -2025,7 +2171,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
// Move the potentially referenced deferred decl to the
// DeferredDeclsToEmit list, and remove it from DeferredDecls (since we
// don't need it anymore).
- addDeferredDeclToEmit(F, DDI->second);
+ addDeferredDeclToEmit(DDI->second);
DeferredDecls.erase(DDI);
// Otherwise, there are cases we have to worry about where we're
@@ -2045,7 +2191,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
FD = FD->getPreviousDecl()) {
if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
if (FD->doesThisDeclarationHaveABody()) {
- addDeferredDeclToEmit(F, GD.getWithDecl(FD));
+ addDeferredDeclToEmit(GD.getWithDecl(FD));
break;
}
}
@@ -2080,7 +2226,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);
}
@@ -2126,7 +2272,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,
@@ -2154,9 +2300,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);
@@ -2247,11 +2392,13 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
return llvm::ConstantExpr::getBitCast(Entry, Ty);
}
- unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace());
+ auto AddrSpace = GetGlobalVarAddressSpace(D);
+ auto TargetAddrSpace = getContext().getTargetAddressSpace(AddrSpace);
+
auto *GV = new llvm::GlobalVariable(
getModule(), Ty->getElementType(), false,
llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr,
- llvm::GlobalVariable::NotThreadLocal, AddrSpace);
+ llvm::GlobalVariable::NotThreadLocal, TargetAddrSpace);
// If we already created a global with the same mangled name (but different
// type) before, take its name and remove it from its parent.
@@ -2274,7 +2421,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
- addDeferredDeclToEmit(GV, DDI->second);
+ addDeferredDeclToEmit(DDI->second);
DeferredDecls.erase(DDI);
}
@@ -2300,16 +2447,70 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
EmitGlobalVarDefinition(D);
}
+ // Emit section information for extern variables.
+ if (D->hasExternalStorage()) {
+ if (const SectionAttr *SA = D->getAttr<SectionAttr>())
+ GV->setSection(SA->getName());
+ }
+
// Handle XCore specific ABI requirements.
if (getTriple().getArch() == llvm::Triple::xcore &&
D->getLanguageLinkage() == CLanguageLinkage &&
D->getType().isConstant(Context) &&
isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
GV->setSection(".cp.rodata");
+
+ // Check if we a have a const declaration with an initializer, we may be
+ // able to emit it as available_externally to expose it's value to the
+ // optimizer.
+ if (Context.getLangOpts().CPlusPlus && GV->hasExternalLinkage() &&
+ D->getType().isConstQualified() && !GV->hasInitializer() &&
+ !D->hasDefinition() && D->hasInit() && !D->hasAttr<DLLImportAttr>()) {
+ const auto *Record =
+ Context.getBaseElementType(D->getType())->getAsCXXRecordDecl();
+ bool HasMutableFields = Record && Record->hasMutableFields();
+ if (!HasMutableFields) {
+ const VarDecl *InitDecl;
+ const Expr *InitExpr = D->getAnyInitializer(InitDecl);
+ if (InitExpr) {
+ ConstantEmitter emitter(*this);
+ llvm::Constant *Init = emitter.tryEmitForInitializer(*InitDecl);
+ if (Init) {
+ auto *InitType = Init->getType();
+ if (GV->getType()->getElementType() != InitType) {
+ // The type of the initializer does not match the definition.
+ // This happens when an initializer has a different type from
+ // the type of the global (because of padding at the end of a
+ // structure for instance).
+ GV->setName(StringRef());
+ // Make a new global with the correct type, this is now guaranteed
+ // to work.
+ auto *NewGV = cast<llvm::GlobalVariable>(
+ GetAddrOfGlobalVar(D, InitType, IsForDefinition));
+
+ // Erase the old global, since it is no longer used.
+ cast<llvm::GlobalValue>(GV)->eraseFromParent();
+ GV = NewGV;
+ } else {
+ GV->setInitializer(Init);
+ GV->setConstant(true);
+ GV->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+ }
+ emitter.finalize(GV);
+ }
+ }
+ }
+ }
}
- if (AddrSpace != Ty->getAddressSpace())
- return llvm::ConstantExpr::getAddrSpaceCast(GV, Ty);
+ LangAS ExpectedAS =
+ D ? D->getType().getAddressSpace()
+ : (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default);
+ assert(getContext().getTargetAddressSpace(ExpectedAS) ==
+ Ty->getPointerAddressSpace());
+ if (AddrSpace != ExpectedAS)
+ return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace,
+ ExpectedAS, Ty);
return GV;
}
@@ -2443,18 +2644,27 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
getDataLayout().getTypeStoreSizeInBits(Ty));
}
-unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
- unsigned AddrSpace) {
- if (D && LangOpts.CUDA && LangOpts.CUDAIsDevice) {
- if (D->hasAttr<CUDAConstantAttr>())
- AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant);
- else if (D->hasAttr<CUDASharedAttr>())
- AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_shared);
+LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) {
+ LangAS AddrSpace = LangAS::Default;
+ if (LangOpts.OpenCL) {
+ AddrSpace = D ? D->getType().getAddressSpace() : LangAS::opencl_global;
+ assert(AddrSpace == LangAS::opencl_global ||
+ AddrSpace == LangAS::opencl_constant ||
+ AddrSpace == LangAS::opencl_local ||
+ AddrSpace >= LangAS::FirstTargetAddressSpace);
+ return AddrSpace;
+ }
+
+ if (LangOpts.CUDA && LangOpts.CUDAIsDevice) {
+ if (D && D->hasAttr<CUDAConstantAttr>())
+ return LangAS::cuda_constant;
+ else if (D && D->hasAttr<CUDASharedAttr>())
+ return LangAS::cuda_shared;
else
- AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device);
+ return LangAS::cuda_device;
}
- return AddrSpace;
+ return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D);
}
template<typename SomeDecl>
@@ -2539,6 +2749,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
const VarDecl *InitDecl;
const Expr *InitExpr = D->getAnyInitializer(InitDecl);
+ Optional<ConstantEmitter> emitter;
+
// CUDA E.2.4.1 "__shared__ variables cannot have an initialization
// as part of their declaration." Sema has already checked for
// error cases, so we just need to set Init to UndefValue.
@@ -2559,7 +2771,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
Init = EmitNullConstant(D->getType());
} else {
initializedGlobalDecl = GlobalDecl(D);
- Init = EmitConstantInit(*InitDecl);
+ emitter.emplace(*this);
+ Init = emitter->tryEmitForInitializer(*InitDecl);
if (!Init) {
QualType T = InitExpr->getType();
@@ -2607,10 +2820,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
// "extern int x[];") and then a definition of a different type (e.g.
// "int x[10];"). This also happens when an initializer has a different type
// from the type of the global (this happens with unions).
- if (!GV ||
- GV->getType()->getElementType() != InitType ||
+ if (!GV || GV->getType()->getElementType() != InitType ||
GV->getType()->getAddressSpace() !=
- GetGlobalVarAddressSpace(D, getContext().getTargetAddressSpace(ASTTy))) {
+ getContext().getTargetAddressSpace(GetGlobalVarAddressSpace(D))) {
// Move the old entry aside so that we'll create a new one.
Entry->setName(StringRef());
@@ -2673,7 +2885,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
Linkage = llvm::GlobalValue::InternalLinkage;
}
}
+
GV->setInitializer(Init);
+ if (emitter) emitter->finalize(GV);
// If it is safe to mark the global 'constant', do so now.
GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor &&
@@ -2762,6 +2976,14 @@ static bool isVarDeclStrongDefinition(const ASTContext &Context,
if (D->hasAttr<SectionAttr>())
return true;
+ // A variable cannot be both common and exist in a section.
+ // We dont try to determine which is the right section in the front-end.
+ // If no specialized section name is applicable, it will resort to default.
+ if (D->hasAttr<PragmaClangBSSSectionAttr>() ||
+ D->hasAttr<PragmaClangDataSectionAttr>() ||
+ D->hasAttr<PragmaClangRodataSectionAttr>())
+ return true;
+
// Thread local vars aren't considered common linkage.
if (D->getTLSKind())
return true;
@@ -2908,14 +3130,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();
@@ -2925,27 +3141,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);
@@ -2969,8 +3177,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.
@@ -3364,6 +3573,10 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
return ConstantAddress(GV, Alignment);
}
+bool CodeGenModule::getExpressionLocationsEnabled() const {
+ return !CodeGenOpts.EmitCodeView || CodeGenOpts.DebugColumnInfo;
+}
+
QualType CodeGenModule::getObjCFastEnumerationStateType() {
if (ObjCFastEnumerationStateType.isNull()) {
RecordDecl *D = Context.buildImplicitRecord("__objcFastEnumerationState");
@@ -3594,12 +3807,18 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
!EvalResult.hasSideEffects())
Value = &EvalResult.Val;
+ LangAS AddrSpace =
+ VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace();
+
+ Optional<ConstantEmitter> emitter;
llvm::Constant *InitialValue = nullptr;
bool Constant = false;
llvm::Type *Type;
if (Value) {
// The temporary has a constant initializer, use it.
- InitialValue = EmitConstantValue(*Value, MaterializedType, nullptr);
+ emitter.emplace(*this);
+ InitialValue = emitter->emitForInitializer(*Value, AddrSpace,
+ MaterializedType);
Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value);
Type = InitialValue->getType();
} else {
@@ -3624,20 +3843,25 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
Linkage = llvm::GlobalVariable::InternalLinkage;
}
}
- unsigned AddrSpace = GetGlobalVarAddressSpace(
- VD, getContext().getTargetAddressSpace(MaterializedType));
+ auto TargetAS = getContext().getTargetAddressSpace(AddrSpace);
auto *GV = new llvm::GlobalVariable(
getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
- /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal,
- AddrSpace);
+ /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
+ if (emitter) emitter->finalize(GV);
setGlobalVisibility(GV, VD);
GV->setAlignment(Align.getQuantity());
if (supportsCOMDAT() && GV->isWeakForLinker())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
if (VD->getTLSKind())
setTLSMode(GV, *VD);
- MaterializedGlobalTemporaryMap[E] = GV;
- return ConstantAddress(GV, Align);
+ llvm::Constant *CV = GV;
+ if (AddrSpace != LangAS::Default)
+ CV = getTargetCodeGenInfo().performAddrSpaceCast(
+ *this, GV, AddrSpace, LangAS::Default,
+ Type->getPointerTo(
+ getContext().getTargetAddressSpace(LangAS::Default)));
+ MaterializedGlobalTemporaryMap[E] = CV;
+ return ConstantAddress(CV, Align);
}
/// EmitObjCPropertyImplementations - Emit information for synthesized
@@ -3779,11 +4003,16 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
AddDeferredUnusedCoverageMapping(D);
break;
+ case Decl::CXXDeductionGuide:
+ // Function-like, but does not result in code emission.
+ break;
+
case Decl::Var:
case Decl::Decomposition:
// Skip variable templates
if (cast<VarDecl>(D)->getDescribedVarTemplate())
return;
+ LLVM_FALLTHROUGH;
case Decl::VarTemplateSpecialization:
EmitGlobal(cast<VarDecl>(D));
if (auto *DD = dyn_cast<DecompositionDecl>(D))
@@ -3802,6 +4031,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))
@@ -4017,6 +4251,9 @@ void CodeGenModule::AddDeferredUnusedCoverageMapping(Decl *D) {
case Decl::CXXDestructor: {
if (!cast<FunctionDecl>(D)->doesThisDeclarationHaveABody())
return;
+ SourceManager &SM = getContext().getSourceManager();
+ if (LimitedCoverage && SM.getMainFileID() != SM.getFileID(D->getLocStart()))
+ return;
auto I = DeferredEmptyCoverageMappingDecls.find(D);
if (I == DeferredEmptyCoverageMappingDecls.end())
DeferredEmptyCoverageMappingDecls[D] = true;
@@ -4307,6 +4544,60 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) {
return InternalId;
}
+// Generalize pointer types to a void pointer with the qualifiers of the
+// originally pointed-to type, e.g. 'const char *' and 'char * const *'
+// generalize to 'const void *' while 'char *' and 'const char **' generalize to
+// 'void *'.
+static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) {
+ if (!Ty->isPointerType())
+ return Ty;
+
+ return Ctx.getPointerType(
+ QualType(Ctx.VoidTy).withCVRQualifiers(
+ Ty->getPointeeType().getCVRQualifiers()));
+}
+
+// Apply type generalization to a FunctionType's return and argument types
+static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty) {
+ if (auto *FnType = Ty->getAs<FunctionProtoType>()) {
+ SmallVector<QualType, 8> GeneralizedParams;
+ for (auto &Param : FnType->param_types())
+ GeneralizedParams.push_back(GeneralizeType(Ctx, Param));
+
+ return Ctx.getFunctionType(
+ GeneralizeType(Ctx, FnType->getReturnType()),
+ GeneralizedParams, FnType->getExtProtoInfo());
+ }
+
+ if (auto *FnType = Ty->getAs<FunctionNoProtoType>())
+ return Ctx.getFunctionNoProtoType(
+ GeneralizeType(Ctx, FnType->getReturnType()));
+
+ llvm_unreachable("Encountered unknown FunctionType");
+}
+
+llvm::Metadata *CodeGenModule::CreateMetadataIdentifierGeneralized(QualType T) {
+ T = GeneralizeFunctionType(getContext(), T);
+
+ llvm::Metadata *&InternalId = GeneralizedMetadataIdMap[T.getCanonicalType()];
+ if (InternalId)
+ return InternalId;
+
+ if (isExternallyVisible(T->getLinkage())) {
+ std::string OutName;
+ llvm::raw_string_ostream Out(OutName);
+ getCXXABI().getMangleContext().mangleTypeName(T, Out);
+ Out << ".generalized";
+
+ InternalId = llvm::MDString::get(getLLVMContext(), Out.str());
+ } else {
+ InternalId = llvm::MDNode::getDistinct(getLLVMContext(),
+ llvm::ArrayRef<llvm::Metadata *>());
+ }
+
+ return InternalId;
+}
+
/// Returns whether this module needs the "all-vtables" type identifier.
bool CodeGenModule::NeedAllVtablesTypeId() const {
// Returns true if at least one of vtable-based CFI checkers is enabled and
@@ -4348,20 +4639,30 @@ void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
// If we have a TargetAttr build up the feature map based on that.
TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
+ ParsedAttr.Features.erase(
+ llvm::remove_if(ParsedAttr.Features,
+ [&](const std::string &Feat) {
+ return !Target.isValidFeatureName(
+ StringRef{Feat}.substr(1));
+ }),
+ ParsedAttr.Features.end());
+
// Make a copy of the features as passed on the command line into the
// beginning of the additional features from the function to override.
- ParsedAttr.first.insert(ParsedAttr.first.begin(),
+ ParsedAttr.Features.insert(ParsedAttr.Features.begin(),
Target.getTargetOpts().FeaturesAsWritten.begin(),
Target.getTargetOpts().FeaturesAsWritten.end());
- if (ParsedAttr.second != "")
- TargetCPU = ParsedAttr.second;
+ if (ParsedAttr.Architecture != "" &&
+ Target.isValidCPUName(ParsedAttr.Architecture))
+ TargetCPU = ParsedAttr.Architecture;
// Now populate the feature map, first with the TargetCPU which is either
// the default or a new one from the target attribute string. Then we'll use
// the passed in features (FeaturesAsWritten) along with the new ones from
// the attribute.
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, ParsedAttr.first);
+ Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
+ ParsedAttr.Features);
} else {
Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
Target.getTargetOpts().Features);
@@ -4377,8 +4678,8 @@ llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
llvm::Value *
CodeGenModule::createOpenCLIntToSamplerConversion(const Expr *E,
CodeGenFunction &CGF) {
- llvm::Constant *C = EmitConstantExpr(E, E->getType(), &CGF);
- auto SamplerT = getOpenCLRuntime().getSamplerType();
+ llvm::Constant *C = ConstantEmitter(CGF).emitAbstract(E, E->getType());
+ auto SamplerT = getOpenCLRuntime().getSamplerType(E->getType().getTypePtr());
auto FTy = llvm::FunctionType::get(SamplerT, {C->getType()}, false);
return CGF.Builder.CreateCall(CreateRuntimeFunction(FTy,
"__translate_sampler_initializer"),
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 8faebe1ea7..7a47c576c0 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"
@@ -314,14 +315,9 @@ private:
/// This is a list of deferred decls which we have seen that *are* actually
/// referenced. These get code generated when the module is done.
- struct DeferredGlobal {
- DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {}
- llvm::TrackingVH<llvm::GlobalValue> GV;
- GlobalDecl GD;
- };
- std::vector<DeferredGlobal> DeferredDeclsToEmit;
- void addDeferredDeclToEmit(llvm::GlobalValue *GV, GlobalDecl GD) {
- DeferredDeclsToEmit.emplace_back(GV, GD);
+ std::vector<GlobalDecl> DeferredDeclsToEmit;
+ void addDeferredDeclToEmit(GlobalDecl GD) {
+ DeferredDeclsToEmit.emplace_back(GD);
}
/// List of alias we have emitted. Used to make sure that what they point to
@@ -345,11 +341,14 @@ private:
/// A queue of (optional) vtables to consider emitting.
std::vector<const CXXRecordDecl*> DeferredVTables;
+ /// A queue of (optional) vtables that may be emitted opportunistically.
+ std::vector<const CXXRecordDecl *> OpportunisticVTables;
+
/// List of global values which are required to be present in the object file;
/// bitcast to i8*. This is used for forcing visibility of symbols which may
/// otherwise be optimized out.
- std::vector<llvm::WeakVH> LLVMUsed;
- std::vector<llvm::WeakVH> LLVMCompilerUsed;
+ std::vector<llvm::WeakTrackingVH> LLVMUsed;
+ std::vector<llvm::WeakTrackingVH> LLVMCompilerUsed;
/// Store the list of global constructors and their respective priorities to
/// be emitted when the translation unit is complete.
@@ -420,7 +419,7 @@ private:
SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
/// Global destructor functions and arguments that need to run on termination.
- std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors;
+ std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>> CXXGlobalDtors;
/// \brief The complete set of modules that has been imported.
llvm::SetVector<clang::Module *> ImportedModules;
@@ -430,14 +429,14 @@ private:
llvm::SmallPtrSet<clang::Module *, 16> EmittedModuleInitializers;
/// \brief A vector of metadata strings.
- SmallVector<llvm::Metadata *, 16> LinkerOptionsMetadata;
+ SmallVector<llvm::MDNode *, 16> LinkerOptionsMetadata;
/// @name Cache for Objective-C runtime types
/// @{
/// Cached reference to the class for constant strings. This value has type
/// int * but is actually an Obj-C class pointer.
- llvm::WeakVH CFConstantStringClassRef;
+ llvm::WeakTrackingVH CFConstantStringClassRef;
/// \brief The type used to describe the state of a fast enumeration in
/// Objective-C's for..in loop.
@@ -454,7 +453,7 @@ private:
bool isTriviallyRecursive(const FunctionDecl *F);
bool shouldEmitFunction(GlobalDecl GD);
-
+ bool shouldOpportunisticallyEmitVTables();
/// Map used to be sure we don't emit the same CompoundLiteral twice.
llvm::DenseMap<const CompoundLiteralExpr *, llvm::GlobalVariable *>
EmittedCompoundLiterals;
@@ -498,7 +497,9 @@ private:
/// Mapping from canonical types to their metadata identifiers. We need to
/// maintain this mapping because identifiers may be formed from distinct
/// MDNodes.
- llvm::DenseMap<QualType, llvm::Metadata *> MetadataIdMap;
+ typedef llvm::DenseMap<QualType, llvm::Metadata *> MetadataTypeMap;
+ MetadataTypeMap MetadataIdMap;
+ MetadataTypeMap GeneralizedMetadataIdMap;
public:
CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
@@ -514,6 +515,9 @@ public:
/// Finalize LLVM code generation.
void Release();
+ /// Return true if we should emit location information for expressions.
+ bool getExpressionLocationsEnabled() const;
+
/// Return a reference to the configured Objective-C runtime.
CGObjCRuntime &getObjCRuntime() {
if (!ObjCRuntime) createObjCRuntime();
@@ -650,25 +654,53 @@ public:
CtorList &getGlobalCtors() { return GlobalCtors; }
CtorList &getGlobalDtors() { return GlobalDtors; }
- llvm::MDNode *getTBAAInfo(QualType QTy);
- llvm::MDNode *getTBAAInfoForVTablePtr();
+ /// getTBAATypeInfo - Get metadata used to describe accesses to objects of
+ /// the given type.
+ llvm::MDNode *getTBAATypeInfo(QualType QTy);
+
+ /// getTBAAAccessInfo - Get TBAA information that describes an access to
+ /// an object of the given type.
+ TBAAAccessInfo getTBAAAccessInfo(QualType AccessType);
+
+ /// getTBAAVTablePtrAccessInfo - Get the TBAA information that describes an
+ /// access to a virtual table pointer.
+ TBAAAccessInfo getTBAAVTablePtrAccessInfo();
+
llvm::MDNode *getTBAAStructInfo(QualType QTy);
- /// Return the path-aware tag for given base type, access node and offset.
- llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN,
- uint64_t O);
+
+ /// getTBAABaseTypeInfo - Get metadata that describes the given base access
+ /// type. Return null if the type is not suitable for use in TBAA access tags.
+ llvm::MDNode *getTBAABaseTypeInfo(QualType QTy);
+
+ /// getTBAAAccessTagInfo - Get TBAA tag for a given memory access.
+ llvm::MDNode *getTBAAAccessTagInfo(TBAAAccessInfo Info);
+
+ /// mergeTBAAInfoForCast - Get merged TBAA information for the purposes of
+ /// type casts.
+ TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
+ TBAAAccessInfo TargetInfo);
+
+ /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the
+ /// purposes of conditional operator.
+ TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+ TBAAAccessInfo InfoB);
+
+ /// getTBAAInfoForSubobject - Get TBAA information for an access with a given
+ /// base lvalue.
+ TBAAAccessInfo getTBAAInfoForSubobject(LValue Base, QualType AccessType) {
+ if (Base.getTBAAInfo().isMayAlias())
+ return TBAAAccessInfo::getMayAliasInfo();
+ return getTBAAAccessInfo(AccessType);
+ }
bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
bool isPaddedAtomicType(QualType type);
bool isPaddedAtomicType(const AtomicType *type);
- /// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag
- /// is the same as the type. For struct-path aware TBAA, the tag
- /// is different from the type: base type, access type and offset.
- /// When ConvertTypeToTag is true, we create a tag based on the scalar type.
+ /// DecorateInstructionWithTBAA - Decorate the instruction with a TBAA tag.
void DecorateInstructionWithTBAA(llvm::Instruction *Inst,
- llvm::MDNode *TBAAInfo,
- bool ConvertTypeToTag = true);
+ TBAAAccessInfo TBAAInfo);
/// Adds !invariant.barrier !tag to instruction
void DecorateInstructionWithInvariantGroup(llvm::Instruction *I,
@@ -711,11 +743,15 @@ public:
SourceLocation Loc = SourceLocation(),
bool TLS = false);
- /// Return the address space of the underlying global variable for D, as
+ /// Return the AST address space of the underlying global variable for D, as
/// determined by its declaration. Normally this is the same as the address
/// space of D's type, but in CUDA, address spaces are associated with
- /// declarations, not types.
- unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace);
+ /// declarations, not types. If D is nullptr, return the default address
+ /// space for global variable.
+ ///
+ /// For languages without explicit address spaces, if D has default address
+ /// space, target-specific global or constant address space may be returned.
+ LangAS GetGlobalVarAddressSpace(const VarDecl *D);
/// Return the llvm::Constant for the address of the given global variable.
/// If Ty is non-null and if the global doesn't exist, then it will be created
@@ -910,14 +946,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);
@@ -940,27 +975,6 @@ public:
llvm::Constant *getMemberPointerConstant(const UnaryOperator *e);
- /// Try to emit the initializer for the given declaration as a constant;
- /// returns 0 if the expression cannot be emitted as a constant.
- llvm::Constant *EmitConstantInit(const VarDecl &D,
- CodeGenFunction *CGF = nullptr);
-
- /// Try to emit the given expression as a constant; returns 0 if the
- /// expression cannot be emitted as a constant.
- llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType,
- CodeGenFunction *CGF = nullptr);
-
- /// Emit the given constant value as a constant, in the type's scalar
- /// representation.
- llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType,
- CodeGenFunction *CGF = nullptr);
-
- /// Emit the given constant value as a constant, in the type's memory
- /// representation.
- llvm::Constant *EmitConstantValueForMemory(const APValue &Value,
- QualType DestType,
- CodeGenFunction *CGF = nullptr);
-
/// \brief Emit type info if type of an expression is a variably modified
/// type. Also emit proper debug info for cast types.
void EmitExplicitCastExprType(const ExplicitCastExpr *E,
@@ -1020,11 +1034,12 @@ public:
/// \param CalleeInfo - The callee information these attributes are being
/// constructed for. If valid, the attributes applied to this decl may
/// contribute to the function attributes and calling convention.
- /// \param PAL [out] - On return, the attribute list to use.
+ /// \param Attrs [out] - On return, the attribute list to use.
/// \param CallingConv [out] - On return, the LLVM calling convention to use.
void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info,
- CGCalleeInfo CalleeInfo, AttributeListType &PAL,
- unsigned &CallingConv, bool AttrOnCallSite);
+ CGCalleeInfo CalleeInfo,
+ llvm::AttributeList &Attrs, unsigned &CallingConv,
+ bool AttrOnCallSite);
/// Adds attributes to F according to our CodeGenOptions and LangOptions, as
/// though we had emitted it ourselves. We remove any attributes on F that
@@ -1059,13 +1074,14 @@ public:
void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
- /// \brief Appends Opts to the "Linker Options" metadata value.
+ /// \brief Appends Opts to the "llvm.linker.options" metadata value.
void AppendLinkerOptions(StringRef Opts);
/// \brief Appends a detect mismatch command to the linker options.
void AddDetectMismatch(StringRef Name, StringRef Value);
- /// \brief Appends a dependent lib to the "Linker Options" metadata value.
+ /// \brief Appends a dependent lib to the "llvm.linker.options" metadata
+ /// value.
void AddDependentLib(StringRef Lib);
llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
@@ -1120,12 +1136,19 @@ public:
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
- bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const;
+ bool isInSanitizerBlacklist(SanitizerMask Kind, llvm::Function *Fn,
+ SourceLocation Loc) const;
bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc,
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();
}
@@ -1138,8 +1161,7 @@ public:
/// are emitted lazily.
void EmitGlobal(GlobalDecl D);
- bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target,
- bool InEveryTU);
+ bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target);
bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D);
/// Set attributes for a global definition.
@@ -1189,6 +1211,11 @@ public:
/// internal identifiers).
llvm::Metadata *CreateMetadataIdentifierForType(QualType T);
+ /// Create a metadata identifier for the generalization of the given type.
+ /// This may either be an MDString (for external identifiers) or a distinct
+ /// unnamed MDNode (for internal identifiers).
+ llvm::Metadata *CreateMetadataIdentifierGeneralized(QualType T);
+
/// Create and attach type metadata to the given function.
void CreateFunctionTypeMetadata(const FunctionDecl *FD, llvm::Function *F);
@@ -1199,7 +1226,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();
@@ -1213,12 +1240,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,
@@ -1230,7 +1256,8 @@ private:
/// Set function attributes for a function declaration.
void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
- bool IsIncompleteFunction, bool IsThunk);
+ bool IsIncompleteFunction, bool IsThunk,
+ ForDefinition_t IsForDefinition);
void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr);
@@ -1277,6 +1304,12 @@ private:
/// Emit any needed decls for which code generation was deferred.
void EmitDeferred();
+ /// Try to emit external vtables as available_externally if they have emitted
+ /// all inlined virtual functions. It runs after EmitDeferred() and therefore
+ /// is not allowed to create new references to things that need to be emitted
+ /// lazily.
+ void EmitVTablesOpportunistically();
+
/// Call replaceAllUsesWith on all pairs in Replacements.
void applyReplacements();
@@ -1288,6 +1321,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();
@@ -1306,6 +1343,9 @@ private:
/// Emits target specific Metadata for global declarations.
void EmitTargetMetadata();
+ /// Emits OpenCL specific Metadata e.g. OpenCL version.
+ void EmitOpenCLMetadata();
+
/// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and
/// .gcda files in a way that persists in .bc files.
void EmitCoverageFile();
@@ -1333,6 +1373,7 @@ private:
bool AttrOnCallSite,
llvm::AttrBuilder &FuncAttrs);
};
+
} // end namespace CodeGen
} // end namespace clang
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index 90711b5479..c3d66c1dab 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -612,11 +612,14 @@ uint64_t PGOHash::finalize() {
llvm::MD5::MD5Result Result;
MD5.final(Result);
using namespace llvm::support;
- return endian::read<uint64_t, little, unaligned>(Result);
+ return Result.low();
}
void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
const Decl *D = GD.getDecl();
+ if (!D->hasBody())
+ return;
+
bool InstrumentRegions = CGM.getCodeGenOpts().hasProfileClangInstr();
llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
if (!InstrumentRegions && !PGOReader)
@@ -666,7 +669,7 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
}
bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) {
- if (SkipCoverageMapping)
+ if (!D->getBody())
return true;
// Don't map the functions in system headers.
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index 0026df570b..0759e65388 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -40,14 +40,11 @@ private:
std::unique_ptr<llvm::InstrProfRecord> ProfRecord;
std::vector<uint64_t> RegionCounts;
uint64_t CurrentRegionCount;
- /// \brief A flag that is set to true when this function doesn't need
- /// to have coverage mapping data.
- bool SkipCoverageMapping;
public:
CodeGenPGO(CodeGenModule &CGM)
- : CGM(CGM), NumValueSites({{0}}), NumRegionCounters(0),
- FunctionHash(0), CurrentRegionCount(0), SkipCoverageMapping(false) {}
+ : CGM(CGM), NumValueSites({{0}}), NumRegionCounters(0), FunctionHash(0),
+ CurrentRegionCount(0) {}
/// Whether or not we have PGO region data for the current function. This is
/// false both when we have no data at all and when our data has been
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 04224e7267..66fdb5f799 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -88,8 +88,26 @@ static bool TypeHasMayAlias(QualType QTy) {
return false;
}
-llvm::MDNode *
-CodeGenTBAA::getTBAAInfo(QualType QTy) {
+/// Check if the given type is a valid base type to be used in access tags.
+static bool isValidBaseType(QualType QTy) {
+ if (QTy->isReferenceType())
+ return false;
+ if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+ // Incomplete types are not valid base access types.
+ if (!RD)
+ return false;
+ if (RD->hasFlexibleArrayMember())
+ return false;
+ // RD can be struct, union, class, interface or enum.
+ // For now, we only handle struct and class.
+ if (RD->isStruct() || RD->isClass())
+ return true;
+ }
+ return false;
+}
+
+llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
// At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
return nullptr;
@@ -99,8 +117,16 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
if (TypeHasMayAlias(QTy))
return getChar();
- const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
+ // We need this function to not fall back to returning the "omnipotent char"
+ // type node for aggregate and union types. Otherwise, any dereference of an
+ // aggregate will result into the may-alias access descriptor, meaning all
+ // subsequent accesses to direct and indirect members of that aggregate will
+ // be considered may-alias too.
+ // TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function.
+ if (isValidBaseType(QTy))
+ return getBaseTypeInfo(QTy);
+ const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
if (llvm::MDNode *N = MetadataCache[Ty])
return N;
@@ -120,15 +146,15 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
// Unsigned types can alias their corresponding signed types.
case BuiltinType::UShort:
- return getTBAAInfo(Context.ShortTy);
+ return getTypeInfo(Context.ShortTy);
case BuiltinType::UInt:
- return getTBAAInfo(Context.IntTy);
+ return getTypeInfo(Context.IntTy);
case BuiltinType::ULong:
- return getTBAAInfo(Context.LongTy);
+ return getTypeInfo(Context.LongTy);
case BuiltinType::ULongLong:
- return getTBAAInfo(Context.LongLongTy);
+ return getTypeInfo(Context.LongLongTy);
case BuiltinType::UInt128:
- return getTBAAInfo(Context.Int128Ty);
+ return getTypeInfo(Context.Int128Ty);
// Treat all other builtin types as distinct types. This includes
// treating wchar_t, char16_t, and char32_t as distinct from their
@@ -139,10 +165,16 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
}
}
- // Handle pointers.
+ // C++1z [basic.lval]p10: "If a program attempts to access the stored value of
+ // an object through a glvalue of other than one of the following types the
+ // behavior is undefined: [...] a char, unsigned char, or std::byte type."
+ if (Ty->isStdByteType())
+ return MetadataCache[Ty] = getChar();
+
+ // Handle pointers and references.
// TODO: Implement C++'s type "similarity" and consider dis-"similar"
// pointers distinct.
- if (Ty->isPointerType())
+ if (Ty->isPointerType() || Ty->isReferenceType())
return MetadataCache[Ty] = createTBAAScalarType("any pointer",
getChar());
@@ -166,8 +198,8 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
return MetadataCache[Ty] = getChar();
}
-llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() {
- return createTBAAScalarType("vtable pointer", getRoot());
+TBAAAccessInfo CodeGenTBAA::getVTablePtrAccessInfo() {
+ return TBAAAccessInfo(createTBAAScalarType("vtable pointer", getRoot()));
}
bool
@@ -206,8 +238,8 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
/* Otherwise, treat whatever it is as a field. */
uint64_t Offset = BaseOffset;
uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity();
- llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy);
- llvm::MDNode *TBAATag = getTBAAScalarTagInfo(TBAAInfo);
+ llvm::MDNode *TBAAType = MayAlias ? getChar() : getTypeInfo(QTy);
+ llvm::MDNode *TBAATag = getAccessTagInfo(TBAAAccessInfo(TBAAType));
Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag));
return true;
}
@@ -227,26 +259,12 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
return StructMetadataCache[Ty] = nullptr;
}
-/// Check if the given type can be handled by path-aware TBAA.
-static bool isTBAAPathStruct(QualType QTy) {
- if (const RecordType *TTy = QTy->getAs<RecordType>()) {
- const RecordDecl *RD = TTy->getDecl()->getDefinition();
- if (RD->hasFlexibleArrayMember())
- return false;
- // RD can be struct, union, class, interface or enum.
- // For now, we only handle struct and class.
- if (RD->isStruct() || RD->isClass())
- return true;
- }
- return false;
-}
+llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) {
+ if (!isValidBaseType(QTy))
+ return nullptr;
-llvm::MDNode *
-CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
- assert(isTBAAPathStruct(QTy));
-
- if (llvm::MDNode *N = StructTypeMetadataCache[Ty])
+ if (llvm::MDNode *N = BaseTypeMetadataCache[Ty])
return N;
if (const RecordType *TTy = QTy->getAs<RecordType>()) {
@@ -258,13 +276,10 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
for (RecordDecl::field_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i, ++idx) {
QualType FieldQTy = i->getType();
- llvm::MDNode *FieldNode;
- if (isTBAAPathStruct(FieldQTy))
- FieldNode = getTBAAStructTypeInfo(FieldQTy);
- else
- FieldNode = getTBAAInfo(FieldQTy);
+ llvm::MDNode *FieldNode = isValidBaseType(FieldQTy) ?
+ getBaseTypeInfo(FieldQTy) : getTypeInfo(FieldQTy);
if (!FieldNode)
- return StructTypeMetadataCache[Ty] = nullptr;
+ return BaseTypeMetadataCache[Ty] = nullptr;
Fields.push_back(std::make_pair(
FieldNode, Layout.getFieldOffset(idx) / Context.getCharWidth()));
}
@@ -278,46 +293,56 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
OutName = RD->getName();
}
// Create the struct type node with a vector of pairs (offset, type).
- return StructTypeMetadataCache[Ty] =
+ return BaseTypeMetadataCache[Ty] =
MDHelper.createTBAAStructTypeNode(OutName, Fields);
}
- return StructMetadataCache[Ty] = nullptr;
+ return BaseTypeMetadataCache[Ty] = nullptr;
}
-/// Return a TBAA tag node for both scalar TBAA and struct-path aware TBAA.
-llvm::MDNode *
-CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
- uint64_t Offset) {
- if (!AccessNode)
+llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) {
+ if (Info.isMayAlias())
+ Info = TBAAAccessInfo(getChar());
+
+ if (!Info.AccessType)
return nullptr;
if (!CodeGenOpts.StructPathTBAA)
- return getTBAAScalarTagInfo(AccessNode);
+ Info = TBAAAccessInfo(Info.AccessType);
- const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr();
- TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset);
- if (llvm::MDNode *N = StructTagMetadataCache[PathTag])
+ llvm::MDNode *&N = AccessTagMetadataCache[Info];
+ if (N)
return N;
- llvm::MDNode *BNode = nullptr;
- if (isTBAAPathStruct(BaseQTy))
- BNode = getTBAAStructTypeInfo(BaseQTy);
- if (!BNode)
- return StructTagMetadataCache[PathTag] =
- MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0);
+ if (!Info.BaseType) {
+ Info.BaseType = Info.AccessType;
+ assert(!Info.Offset && "Nonzero offset for an access with no base type!");
+ }
+ return N = MDHelper.createTBAAStructTagNode(Info.BaseType, Info.AccessType,
+ Info.Offset);
+}
- return StructTagMetadataCache[PathTag] =
- MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset);
+TBAAAccessInfo CodeGenTBAA::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
+ TBAAAccessInfo TargetInfo) {
+ if (SourceInfo.isMayAlias() || TargetInfo.isMayAlias())
+ return TBAAAccessInfo::getMayAliasInfo();
+ return TargetInfo;
}
-llvm::MDNode *
-CodeGenTBAA::getTBAAScalarTagInfo(llvm::MDNode *AccessNode) {
- if (!AccessNode)
- return nullptr;
- if (llvm::MDNode *N = ScalarTagMetadataCache[AccessNode])
- return N;
+TBAAAccessInfo
+CodeGenTBAA::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+ TBAAAccessInfo InfoB) {
+ if (InfoA == InfoB)
+ return InfoA;
+
+ if (!InfoA || !InfoB)
+ return TBAAAccessInfo();
+
+ if (InfoA.isMayAlias() || InfoB.isMayAlias())
+ return TBAAAccessInfo::getMayAliasInfo();
- return ScalarTagMetadataCache[AccessNode] =
- MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0);
+ // TODO: Implement the rest of the logic here. For example, two accesses
+ // with same final access types result in an access to an object of that final
+ // access type regardless of their base types.
+ return TBAAAccessInfo::getMayAliasInfo();
}
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index ddb063d9e8..e4f459ce93 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -30,15 +30,72 @@ namespace clang {
class Type;
namespace CodeGen {
- class CGRecordLayout;
+class CGRecordLayout;
- struct TBAAPathTag {
- TBAAPathTag(const Type *B, const llvm::MDNode *A, uint64_t O)
- : BaseT(B), AccessN(A), Offset(O) {}
- const Type *BaseT;
- const llvm::MDNode *AccessN;
- uint64_t Offset;
- };
+// TBAAAccessKind - A kind of TBAA memory access descriptor.
+enum class TBAAAccessKind : unsigned {
+ Ordinary,
+ MayAlias,
+};
+
+// TBAAAccessInfo - Describes a memory access in terms of TBAA.
+struct TBAAAccessInfo {
+ TBAAAccessInfo(TBAAAccessKind Kind, llvm::MDNode *BaseType,
+ llvm::MDNode *AccessType, uint64_t Offset)
+ : Kind(Kind), BaseType(BaseType), AccessType(AccessType), Offset(Offset)
+ {}
+
+ TBAAAccessInfo(llvm::MDNode *BaseType, llvm::MDNode *AccessType,
+ uint64_t Offset)
+ : TBAAAccessInfo(TBAAAccessKind::Ordinary, BaseType, AccessType, Offset)
+ {}
+
+ explicit TBAAAccessInfo(llvm::MDNode *AccessType)
+ : TBAAAccessInfo(/* BaseType= */ nullptr, AccessType, /* Offset= */ 0)
+ {}
+
+ TBAAAccessInfo()
+ : TBAAAccessInfo(/* AccessType= */ nullptr)
+ {}
+
+ static TBAAAccessInfo getMayAliasInfo() {
+ return TBAAAccessInfo(TBAAAccessKind::MayAlias, /* BaseType= */ nullptr,
+ /* AccessType= */ nullptr, /* Offset= */ 0);
+ }
+
+ bool isMayAlias() const { return Kind == TBAAAccessKind::MayAlias; }
+
+ bool operator==(const TBAAAccessInfo &Other) const {
+ return Kind == Other.Kind &&
+ BaseType == Other.BaseType &&
+ AccessType == Other.AccessType &&
+ Offset == Other.Offset;
+ }
+
+ bool operator!=(const TBAAAccessInfo &Other) const {
+ return !(*this == Other);
+ }
+
+ explicit operator bool() const {
+ return *this != TBAAAccessInfo();
+ }
+
+ /// Kind - The kind of the access descriptor.
+ TBAAAccessKind Kind;
+
+ /// BaseType - The base/leading access type. May be null if this access
+ /// descriptor represents an access that is not considered to be an access
+ /// to an aggregate or union member.
+ llvm::MDNode *BaseType;
+
+ /// AccessType - The final access type. May be null if there is no TBAA
+ /// information available about this access.
+ llvm::MDNode *AccessType;
+
+ /// Offset - The byte offset of the final access within the base one. Must be
+ /// zero if the base access type is not specified.
+ uint64_t Offset;
+};
/// CodeGenTBAA - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
@@ -54,12 +111,10 @@ class CodeGenTBAA {
/// MetadataCache - This maps clang::Types to scalar llvm::MDNodes describing
/// them.
llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
- /// This maps clang::Types to a struct node in the type DAG.
- llvm::DenseMap<const Type *, llvm::MDNode *> StructTypeMetadataCache;
- /// This maps TBAAPathTags to a tag node.
- llvm::DenseMap<TBAAPathTag, llvm::MDNode *> StructTagMetadataCache;
- /// This maps a scalar type to a scalar tag node.
- llvm::DenseMap<const llvm::MDNode *, llvm::MDNode *> ScalarTagMetadataCache;
+ /// This maps clang::Types to a base access type in the type DAG.
+ llvm::DenseMap<const Type *, llvm::MDNode *> BaseTypeMetadataCache;
+ /// This maps TBAA access descriptors to tag nodes.
+ llvm::DenseMap<TBAAAccessInfo, llvm::MDNode *> AccessTagMetadataCache;
/// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing
/// them for struct assignments.
@@ -95,27 +150,34 @@ public:
MangleContext &MContext);
~CodeGenTBAA();
- /// getTBAAInfo - Get the TBAA MDNode to be used for a dereference
- /// of the given type.
- llvm::MDNode *getTBAAInfo(QualType QTy);
+ /// getTypeInfo - Get metadata used to describe accesses to objects of the
+ /// given type.
+ llvm::MDNode *getTypeInfo(QualType QTy);
- /// getTBAAInfoForVTablePtr - Get the TBAA MDNode to be used for a
- /// dereference of a vtable pointer.
- llvm::MDNode *getTBAAInfoForVTablePtr();
+ /// getVTablePtrAccessInfo - Get the TBAA information that describes an
+ /// access to a virtual table pointer.
+ TBAAAccessInfo getVTablePtrAccessInfo();
/// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of
/// the given type.
llvm::MDNode *getTBAAStructInfo(QualType QTy);
- /// Get the MDNode in the type DAG for given struct type QType.
- llvm::MDNode *getTBAAStructTypeInfo(QualType QType);
- /// Get the tag MDNode for a given base type, the actual scalar access MDNode
- /// and offset into the base type.
- llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType,
- llvm::MDNode *AccessNode, uint64_t Offset);
+ /// getBaseTypeInfo - Get metadata that describes the given base access type.
+ /// Return null if the type is not suitable for use in TBAA access tags.
+ llvm::MDNode *getBaseTypeInfo(QualType QTy);
+
+ /// getAccessTagInfo - Get TBAA tag for a given memory access.
+ llvm::MDNode *getAccessTagInfo(TBAAAccessInfo Info);
+
+ /// mergeTBAAInfoForCast - Get merged TBAA information for the purpose of
+ /// type casts.
+ TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
+ TBAAAccessInfo TargetInfo);
- /// Get the scalar tag MDNode for a given scalar type.
- llvm::MDNode *getTBAAScalarTagInfo(llvm::MDNode *AccessNode);
+ /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the
+ /// purpose of conditional operator.
+ TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+ TBAAAccessInfo InfoB);
};
} // end namespace CodeGen
@@ -123,32 +185,36 @@ public:
namespace llvm {
-template<> struct DenseMapInfo<clang::CodeGen::TBAAPathTag> {
- static clang::CodeGen::TBAAPathTag getEmptyKey() {
- return clang::CodeGen::TBAAPathTag(
- DenseMapInfo<const clang::Type *>::getEmptyKey(),
- DenseMapInfo<const MDNode *>::getEmptyKey(),
+template<> struct DenseMapInfo<clang::CodeGen::TBAAAccessInfo> {
+ static clang::CodeGen::TBAAAccessInfo getEmptyKey() {
+ unsigned UnsignedKey = DenseMapInfo<unsigned>::getEmptyKey();
+ return clang::CodeGen::TBAAAccessInfo(
+ static_cast<clang::CodeGen::TBAAAccessKind>(UnsignedKey),
+ DenseMapInfo<MDNode *>::getEmptyKey(),
+ DenseMapInfo<MDNode *>::getEmptyKey(),
DenseMapInfo<uint64_t>::getEmptyKey());
}
- static clang::CodeGen::TBAAPathTag getTombstoneKey() {
- return clang::CodeGen::TBAAPathTag(
- DenseMapInfo<const clang::Type *>::getTombstoneKey(),
- DenseMapInfo<const MDNode *>::getTombstoneKey(),
+ static clang::CodeGen::TBAAAccessInfo getTombstoneKey() {
+ unsigned UnsignedKey = DenseMapInfo<unsigned>::getTombstoneKey();
+ return clang::CodeGen::TBAAAccessInfo(
+ static_cast<clang::CodeGen::TBAAAccessKind>(UnsignedKey),
+ DenseMapInfo<MDNode *>::getTombstoneKey(),
+ DenseMapInfo<MDNode *>::getTombstoneKey(),
DenseMapInfo<uint64_t>::getTombstoneKey());
}
- static unsigned getHashValue(const clang::CodeGen::TBAAPathTag &Val) {
- return DenseMapInfo<const clang::Type *>::getHashValue(Val.BaseT) ^
- DenseMapInfo<const MDNode *>::getHashValue(Val.AccessN) ^
+ static unsigned getHashValue(const clang::CodeGen::TBAAAccessInfo &Val) {
+ auto KindValue = static_cast<unsigned>(Val.Kind);
+ return DenseMapInfo<unsigned>::getHashValue(KindValue) ^
+ DenseMapInfo<MDNode *>::getHashValue(Val.BaseType) ^
+ DenseMapInfo<MDNode *>::getHashValue(Val.AccessType) ^
DenseMapInfo<uint64_t>::getHashValue(Val.Offset);
}
- static bool isEqual(const clang::CodeGen::TBAAPathTag &LHS,
- const clang::CodeGen::TBAAPathTag &RHS) {
- return LHS.BaseT == RHS.BaseT &&
- LHS.AccessN == RHS.AccessN &&
- LHS.Offset == RHS.Offset;
+ static bool isEqual(const clang::CodeGen::TBAAAccessInfo &LHS,
+ const clang::CodeGen::TBAAAccessInfo &RHS) {
+ return LHS == RHS;
}
};
diff --git a/lib/CodeGen/CodeGenTypeCache.h b/lib/CodeGen/CodeGenTypeCache.h
index 47e26bcaa1..2af7b30eaf 100644
--- a/lib/CodeGen/CodeGenTypeCache.h
+++ b/lib/CodeGen/CodeGenTypeCache.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPECACHE_H
#include "clang/AST/CharUnits.h"
+#include "clang/Basic/AddressSpaces.h"
#include "llvm/IR/CallingConv.h"
namespace llvm {
@@ -60,6 +61,12 @@ struct CodeGenTypeCache {
llvm::PointerType *Int8PtrPtrTy;
};
+ /// void* in alloca address space
+ union {
+ llvm::PointerType *AllocaVoidPtrTy;
+ llvm::PointerType *AllocaInt8PtrTy;
+ };
+
/// The size and alignment of the builtin C type 'int'. This comes
/// up enough in various ABI lowering tasks to be worth pre-computing.
union {
@@ -88,6 +95,8 @@ struct CodeGenTypeCache {
unsigned char SizeAlignInBytes;
};
+ LangAS ASTAllocaAddressSpace;
+
CharUnits getSizeSize() const {
return CharUnits::fromQuantity(SizeSizeInBytes);
}
@@ -105,6 +114,8 @@ struct CodeGenTypeCache {
llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; }
llvm::CallingConv::ID BuiltinCC;
llvm::CallingConv::ID getBuiltinCC() const { return BuiltinCC; }
+
+ LangAS getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index dc24b2040f..80f2a31ac0 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -44,6 +44,10 @@ CodeGenTypes::~CodeGenTypes() {
delete &*I++;
}
+const CodeGenOptions &CodeGenTypes::getCodeGenOpts() const {
+ return CGM.getCodeGenOpts();
+}
+
void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
llvm::StructType *Ty,
StringRef suffix) {
@@ -439,6 +443,12 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
static_cast<unsigned>(Context.getTypeSize(T)));
break;
+ case BuiltinType::Float16:
+ ResultType =
+ getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T),
+ /* UseNativeHalf = */ true);
+ break;
+
case BuiltinType::Half:
// Half FP can either be storage-only (lowered to i16) or native.
ResultType =
@@ -490,7 +500,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
llvm_unreachable("Unexpected undeduced type!");
case Type::Complex: {
llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType());
- ResultType = llvm::StructType::get(EltTy, EltTy, nullptr);
+ ResultType = llvm::StructType::get(EltTy, EltTy);
break;
}
case Type::LValueReference:
@@ -635,7 +645,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
break;
}
case Type::Pipe: {
- ResultType = CGM.getOpenCLRuntime().getPipeType();
+ ResultType = CGM.getOpenCLRuntime().getPipeType(cast<PipeType>(Ty));
break;
}
}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index f0b97ebde1..d082342bf5 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -164,8 +164,6 @@ class CodeGenTypes {
llvm::SmallSet<const Type *, 8> RecordsWithOpaqueMemberPointers;
- unsigned ClangCallConvToLLVMCallConv(CallingConv CC);
-
public:
CodeGenTypes(CodeGenModule &cgm);
~CodeGenTypes();
@@ -178,6 +176,10 @@ public:
const TargetInfo &getTarget() const { return Target; }
CGCXXABI &getCXXABI() const { return TheCXXABI; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
+ const CodeGenOptions &getCodeGenOpts() const;
+
+ /// Convert clang calling convention to LLVM callilng convention.
+ unsigned ClangCallConvToLLVMCallConv(CallingConv CC);
/// ConvertType - Convert type T into a llvm::Type.
llvm::Type *ConvertType(QualType T);
diff --git a/lib/CodeGen/ConstantEmitter.h b/lib/CodeGen/ConstantEmitter.h
new file mode 100644
index 0000000000..90c9fcd8cf
--- /dev/null
+++ b/lib/CodeGen/ConstantEmitter.h
@@ -0,0 +1,178 @@
+//===--- ConstantEmitter.h - IR constant emission ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A helper class for emitting expressions and values as llvm::Constants
+// and as initializers for global variables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H
+#define LLVM_CLANG_LIB_CODEGEN_CONSTANTEMITTER_H
+
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+
+namespace clang {
+namespace CodeGen {
+
+class ConstantEmitter {
+public:
+ CodeGenModule &CGM;
+ CodeGenFunction *CGF;
+
+private:
+ bool Abstract = false;
+
+ /// Whether non-abstract components of the emitter have been initialized.
+ bool InitializedNonAbstract = false;
+
+ /// Whether the emitter has been finalized.
+ bool Finalized = false;
+
+ /// Whether the constant-emission failed.
+ bool Failed = false;
+
+ /// The AST address space where this (non-abstract) initializer is going.
+ /// Used for generating appropriate placeholders.
+ LangAS DestAddressSpace;
+
+ llvm::SmallVector<std::pair<llvm::Constant *, llvm::GlobalVariable*>, 4>
+ PlaceholderAddresses;
+
+public:
+ ConstantEmitter(CodeGenModule &CGM, CodeGenFunction *CGF = nullptr)
+ : CGM(CGM), CGF(CGF) {}
+
+ /// Initialize this emission in the context of the given function.
+ /// Use this if the expression might contain contextaul references like
+ /// block addresses or PredefinedExprs.
+ ConstantEmitter(CodeGenFunction &CGF)
+ : CGM(CGF.CGM), CGF(&CGF) {}
+
+ ConstantEmitter(const ConstantEmitter &other) = delete;
+ ConstantEmitter &operator=(const ConstantEmitter &other) = delete;
+
+ ~ConstantEmitter();
+
+ /// Is the current emission context abstract?
+ bool isAbstract() const {
+ return Abstract;
+ }
+
+ /// Try to emit the initiaizer of the given declaration as an abstract
+ /// constant. If this succeeds, the emission must be finalized.
+ llvm::Constant *tryEmitForInitializer(const VarDecl &D);
+ llvm::Constant *tryEmitForInitializer(const Expr *E, LangAS destAddrSpace,
+ QualType destType);
+ llvm::Constant *emitForInitializer(const APValue &value, LangAS destAddrSpace,
+ QualType destType);
+
+ void finalize(llvm::GlobalVariable *global);
+
+ // All of the "abstract" emission methods below permit the emission to
+ // be immediately discarded without finalizing anything. Therefore, they
+ // must also promise not to do anything that will, in the future, require
+ // finalization:
+ //
+ // - using the CGF (if present) for anything other than establishing
+ // semantic context; for example, an expression with ignored
+ // side-effects must not be emitted as an abstract expression
+ //
+ // - doing anything that would not be safe to duplicate within an
+ // initializer or to propagate to another context; for example,
+ // side effects, or emitting an initialization that requires a
+ // reference to its current location.
+
+ /// Try to emit the initializer of the given declaration as an abstract
+ /// constant.
+ llvm::Constant *tryEmitAbstractForInitializer(const VarDecl &D);
+
+ /// Emit the result of the given expression as an abstract constant,
+ /// asserting that it succeeded. This is only safe to do when the
+ /// expression is known to be a constant expression with either a fairly
+ /// simple type or a known simple form.
+ llvm::Constant *emitAbstract(const Expr *E, QualType T);
+ llvm::Constant *emitAbstract(SourceLocation loc, const APValue &value,
+ QualType T);
+
+ /// Try to emit the result of the given expression as an abstract constant.
+ llvm::Constant *tryEmitAbstract(const Expr *E, QualType T);
+ llvm::Constant *tryEmitAbstractForMemory(const Expr *E, QualType T);
+
+ llvm::Constant *tryEmitAbstract(const APValue &value, QualType T);
+ llvm::Constant *tryEmitAbstractForMemory(const APValue &value, QualType T);
+
+ llvm::Constant *emitNullForMemory(QualType T) {
+ return emitNullForMemory(CGM, T);
+ }
+ llvm::Constant *emitForMemory(llvm::Constant *C, QualType T) {
+ return emitForMemory(CGM, C, T);
+ }
+
+ static llvm::Constant *emitNullForMemory(CodeGenModule &CGM, QualType T);
+ static llvm::Constant *emitForMemory(CodeGenModule &CGM, llvm::Constant *C,
+ QualType T);
+
+ // These are private helper routines of the constant emitter that
+ // can't actually be private because things are split out into helper
+ // functions and classes.
+
+ llvm::Constant *tryEmitPrivateForVarInit(const VarDecl &D);
+
+ llvm::Constant *tryEmitPrivate(const Expr *E, QualType T);
+ llvm::Constant *tryEmitPrivateForMemory(const Expr *E, QualType T);
+
+ llvm::Constant *tryEmitPrivate(const APValue &value, QualType T);
+ llvm::Constant *tryEmitPrivateForMemory(const APValue &value, QualType T);
+
+ /// Get the address of the current location. This is a constant
+ /// that will resolve, after finalization, to the address of the
+ /// 'signal' value that is registered with the emitter later.
+ llvm::GlobalValue *getCurrentAddrPrivate();
+
+ /// Register a 'signal' value with the emitter to inform it where to
+ /// resolve a placeholder. The signal value must be unique in the
+ /// initializer; it might, for example, be the address of a global that
+ /// refers to the current-address value in its own initializer.
+ ///
+ /// Uses of the placeholder must be properly anchored before finalizing
+ /// the emitter, e.g. by being installed as the initializer of a global
+ /// variable. That is, it must be possible to replaceAllUsesWith
+ /// the placeholder with the proper address of the signal.
+ void registerCurrentAddrPrivate(llvm::Constant *signal,
+ llvm::GlobalValue *placeholder);
+
+private:
+ void initializeNonAbstract(LangAS destAS) {
+ assert(!InitializedNonAbstract);
+ InitializedNonAbstract = true;
+ DestAddressSpace = destAS;
+ }
+ llvm::Constant *markIfFailed(llvm::Constant *init) {
+ if (!init)
+ Failed = true;
+ return init;
+ }
+
+ struct AbstractState {
+ bool OldValue;
+ size_t OldPlaceholdersSize;
+ };
+ AbstractState pushAbstract() {
+ AbstractState saved = { Abstract, PlaceholderAddresses.size() };
+ Abstract = true;
+ return saved;
+ }
+ llvm::Constant *validateAndPopAbstract(llvm::Constant *C, AbstractState save);
+};
+
+}
+}
+
+#endif
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 5bc9e5011a..08b8c2ec54 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -29,7 +29,7 @@ using namespace clang;
using namespace CodeGen;
using namespace llvm::coverage;
-void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range) {
+void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
SkippedRanges.push_back(Range);
}
@@ -45,10 +45,19 @@ class SourceMappingRegion {
/// \brief The region's ending location.
Optional<SourceLocation> LocEnd;
+ /// Whether this region should be emitted after its parent is emitted.
+ bool DeferRegion;
+
+ /// Whether this region is a gap region. The count from a gap region is set
+ /// as the line execution count if there are no other regions on the line.
+ bool GapRegion;
+
public:
SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart,
- Optional<SourceLocation> LocEnd)
- : Count(Count), LocStart(LocStart), LocEnd(LocEnd) {}
+ Optional<SourceLocation> LocEnd, bool DeferRegion = false,
+ bool GapRegion = false)
+ : Count(Count), LocStart(LocStart), LocEnd(LocEnd),
+ DeferRegion(DeferRegion), GapRegion(GapRegion) {}
const Counter &getCounter() const { return Count; }
@@ -71,6 +80,44 @@ public:
assert(LocEnd && "Region has no end location");
return *LocEnd;
}
+
+ bool isDeferred() const { return DeferRegion; }
+
+ void setDeferred(bool Deferred) { DeferRegion = Deferred; }
+
+ bool isGap() const { return GapRegion; }
+
+ void setGap(bool Gap) { GapRegion = Gap; }
+};
+
+/// Spelling locations for the start and end of a source region.
+struct SpellingRegion {
+ /// The line where the region starts.
+ unsigned LineStart;
+
+ /// The column where the region starts.
+ unsigned ColumnStart;
+
+ /// The line where the region ends.
+ unsigned LineEnd;
+
+ /// The column where the region ends.
+ unsigned ColumnEnd;
+
+ SpellingRegion(SourceManager &SM, SourceLocation LocStart,
+ SourceLocation LocEnd) {
+ LineStart = SM.getSpellingLineNumber(LocStart);
+ ColumnStart = SM.getSpellingColumnNumber(LocStart);
+ LineEnd = SM.getSpellingLineNumber(LocEnd);
+ ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
+ }
+
+ /// Check if the start and end locations appear in source order, i.e
+ /// top->bottom, left->right.
+ bool isInSourceOrder() const {
+ return (LineStart < LineEnd) ||
+ (LineStart == LineEnd && ColumnStart <= ColumnEnd);
+ }
};
/// \brief Provides the common functionality for the different
@@ -241,12 +288,9 @@ public:
auto CovFileID = getCoverageFileID(LocStart);
if (!CovFileID)
continue;
- unsigned LineStart = SM.getSpellingLineNumber(LocStart);
- unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);
- unsigned LineEnd = SM.getSpellingLineNumber(LocEnd);
- unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
+ SpellingRegion SR{SM, LocStart, LocEnd};
auto Region = CounterMappingRegion::makeSkipped(
- *CovFileID, LineStart, ColumnStart, LineEnd, ColumnEnd);
+ *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd);
// Make sure that we only collect the regions that are inside
// the souce code of this function.
if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
@@ -284,16 +328,19 @@ public:
if (Filter.count(std::make_pair(LocStart, LocEnd)))
continue;
- // Find the spilling locations for the mapping region.
- unsigned LineStart = SM.getSpellingLineNumber(LocStart);
- unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);
- unsigned LineEnd = SM.getSpellingLineNumber(LocEnd);
- unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
-
- assert(LineStart <= LineEnd && "region start and end out of order");
- MappingRegions.push_back(CounterMappingRegion::makeRegion(
- Region.getCounter(), *CovFileID, LineStart, ColumnStart, LineEnd,
- ColumnEnd));
+ // Find the spelling locations for the mapping region.
+ SpellingRegion SR{SM, LocStart, LocEnd};
+ assert(SR.isInSourceOrder() && "region start and end out of order");
+
+ if (Region.isGap()) {
+ MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
+ Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
+ SR.LineEnd, SR.ColumnEnd));
+ } else {
+ MappingRegions.push_back(CounterMappingRegion::makeRegion(
+ Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
+ SR.LineEnd, SR.ColumnEnd));
+ }
}
}
@@ -317,14 +364,11 @@ public:
"region spans multiple files");
Filter.insert(std::make_pair(ParentLoc, LocEnd));
- unsigned LineStart = SM.getSpellingLineNumber(ParentLoc);
- unsigned ColumnStart = SM.getSpellingColumnNumber(ParentLoc);
- unsigned LineEnd = SM.getSpellingLineNumber(LocEnd);
- unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
-
+ SpellingRegion SR{SM, ParentLoc, LocEnd};
+ assert(SR.isInSourceOrder() && "region start and end out of order");
MappingRegions.push_back(CounterMappingRegion::makeExpansion(
- *ParentFileID, *ExpandedFileID, LineStart, ColumnStart, LineEnd,
- ColumnEnd));
+ *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
+ SR.LineEnd, SR.ColumnEnd));
}
return Filter;
}
@@ -389,6 +433,10 @@ struct CounterCoverageMappingBuilder
/// \brief A stack of currently live regions.
std::vector<SourceMappingRegion> RegionStack;
+ /// The currently deferred region: its end location and count can be set once
+ /// its parent has been popped from the region stack.
+ Optional<SourceMappingRegion> DeferredRegion;
+
CounterExpressionBuilder Builder;
/// \brief A location in the most recently visited file or macro.
@@ -424,19 +472,61 @@ struct CounterCoverageMappingBuilder
/// used with popRegions to exit a "scope", ending the region that was pushed.
size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None,
Optional<SourceLocation> EndLoc = None) {
- if (StartLoc)
+ if (StartLoc) {
MostRecentLocation = *StartLoc;
+ completeDeferred(Count, MostRecentLocation);
+ }
RegionStack.emplace_back(Count, StartLoc, EndLoc);
return RegionStack.size() - 1;
}
+ /// Complete any pending deferred region by setting its end location and
+ /// count, and then pushing it onto the region stack.
+ size_t completeDeferred(Counter Count, SourceLocation DeferredEndLoc) {
+ size_t Index = RegionStack.size();
+ if (!DeferredRegion)
+ return Index;
+
+ // Consume the pending region.
+ SourceMappingRegion DR = DeferredRegion.getValue();
+ DeferredRegion = None;
+
+ // If the region ends in an expansion, find the expansion site.
+ if (SM.getFileID(DeferredEndLoc) != SM.getMainFileID()) {
+ FileID StartFile = SM.getFileID(DR.getStartLoc());
+ if (isNestedIn(DeferredEndLoc, StartFile)) {
+ do {
+ DeferredEndLoc = getIncludeOrExpansionLoc(DeferredEndLoc);
+ } while (StartFile != SM.getFileID(DeferredEndLoc));
+ }
+ }
+
+ // The parent of this deferred region ends where the containing decl ends,
+ // so the region isn't useful.
+ if (DR.getStartLoc() == DeferredEndLoc)
+ return Index;
+
+ // If we're visiting statements in non-source order (e.g switch cases or
+ // a loop condition) we can't construct a sensible deferred region.
+ if (!SpellingRegion(SM, DR.getStartLoc(), DeferredEndLoc).isInSourceOrder())
+ return Index;
+
+ DR.setGap(true);
+ DR.setCounter(Count);
+ DR.setEndLoc(DeferredEndLoc);
+ handleFileExit(DeferredEndLoc);
+ RegionStack.push_back(DR);
+ return Index;
+ }
+
/// \brief Pop regions from the stack into the function's list of regions.
///
/// Adds all regions from \c ParentIndex to the top of the stack to the
/// function's \c SourceRegions.
void popRegions(size_t ParentIndex) {
assert(RegionStack.size() >= ParentIndex && "parent not in stack");
+ bool ParentOfDeferredRegion = false;
while (RegionStack.size() > ParentIndex) {
SourceMappingRegion &Region = RegionStack.back();
if (Region.hasStartLoc()) {
@@ -468,9 +558,26 @@ struct CounterCoverageMappingBuilder
assert(SM.isWrittenInSameFile(Region.getStartLoc(), EndLoc));
SourceRegions.push_back(Region);
+
+ if (ParentOfDeferredRegion) {
+ ParentOfDeferredRegion = false;
+
+ // If there's an existing deferred region, keep the old one, because
+ // it means there are two consecutive returns (or a similar pattern).
+ if (!DeferredRegion.hasValue() &&
+ // File IDs aren't gathered within macro expansions, so it isn't
+ // useful to try and create a deferred region inside of one.
+ (SM.getFileID(EndLoc) == SM.getMainFileID()))
+ DeferredRegion =
+ SourceMappingRegion(Counter::getZero(), EndLoc, None);
+ }
+ } else if (Region.isDeferred()) {
+ assert(!ParentOfDeferredRegion && "Consecutive deferred regions");
+ ParentOfDeferredRegion = true;
}
RegionStack.pop_back();
}
+ assert(!ParentOfDeferredRegion && "Deferred region with no parent");
}
/// \brief Return the currently active region.
@@ -481,15 +588,17 @@ struct CounterCoverageMappingBuilder
/// \brief Propagate counts through the children of \c S.
Counter propagateCounts(Counter TopCount, const Stmt *S) {
- size_t Index = pushRegion(TopCount, getStart(S), getEnd(S));
+ SourceLocation StartLoc = getStart(S);
+ SourceLocation EndLoc = getEnd(S);
+ size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
Visit(S);
Counter ExitCount = getRegion().getCounter();
popRegions(Index);
// The statement may be spanned by an expansion. Make sure we handle a file
// exit out of this expansion before moving to the next statement.
- if (SM.isBeforeInTranslationUnit(getStart(S), S->getLocStart()))
- MostRecentLocation = getEnd(S);
+ if (SM.isBeforeInTranslationUnit(StartLoc, S->getLocStart()))
+ MostRecentLocation = EndLoc;
return ExitCount;
}
@@ -595,6 +704,8 @@ struct CounterCoverageMappingBuilder
handleFileExit(StartLoc);
if (!Region.hasStartLoc())
Region.setStartLoc(StartLoc);
+
+ completeDeferred(Region.getCounter(), StartLoc);
}
/// \brief Mark \c S as a terminator, starting a zero region.
@@ -604,6 +715,7 @@ struct CounterCoverageMappingBuilder
if (!Region.hasEndLoc())
Region.setEndLoc(getEnd(S));
pushRegion(Counter::getZero());
+ getRegion().setDeferred(true);
}
/// \brief Keep counts of breaks and continues inside loops.
@@ -617,13 +729,15 @@ struct CounterCoverageMappingBuilder
CoverageMappingModuleGen &CVM,
llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
const LangOptions &LangOpts)
- : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
+ : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
+ DeferredRegion(None) {}
/// \brief Write the mapping data to the output stream
void write(llvm::raw_ostream &OS) {
llvm::SmallVector<unsigned, 8> VirtualFileMapping;
gatherFileIDs(VirtualFileMapping);
SourceRegionFilter Filter = emitExpansionRegions();
+ assert(!DeferredRegion && "Deferred region never completed");
emitSourceRegions(Filter);
gatherSkippedRegions();
@@ -644,14 +758,42 @@ struct CounterCoverageMappingBuilder
handleFileExit(getEnd(S));
}
+ /// Determine whether the final deferred region emitted in \p Body should be
+ /// discarded.
+ static bool discardFinalDeferredRegionInDecl(Stmt *Body) {
+ if (auto *CS = dyn_cast<CompoundStmt>(Body)) {
+ Stmt *LastStmt = CS->body_back();
+ if (auto *IfElse = dyn_cast<IfStmt>(LastStmt)) {
+ if (auto *Else = dyn_cast_or_null<CompoundStmt>(IfElse->getElse()))
+ LastStmt = Else->body_back();
+ else
+ LastStmt = IfElse->getElse();
+ }
+ return dyn_cast_or_null<ReturnStmt>(LastStmt);
+ }
+ return false;
+ }
+
void VisitDecl(const Decl *D) {
+ assert(!DeferredRegion && "Deferred region never completed");
+
Stmt *Body = D->getBody();
// Do not propagate region counts into system headers.
if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
return;
- propagateCounts(getRegionCounter(Body), Body);
+ Counter ExitCount = propagateCounts(getRegionCounter(Body), Body);
+ assert(RegionStack.empty() && "Regions entered but never exited");
+
+ if (DeferredRegion) {
+ // Complete (or discard) any deferred regions introduced by the last
+ // statement.
+ if (discardFinalDeferredRegionInDecl(Body))
+ DeferredRegion = None;
+ else
+ popRegions(completeDeferred(ExitCount, getEnd(Body)));
+ }
}
void VisitReturnStmt(const ReturnStmt *S) {
@@ -682,6 +824,8 @@ struct CounterCoverageMappingBuilder
assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
BreakContinueStack.back().BreakCount = addCounters(
BreakContinueStack.back().BreakCount, getRegion().getCounter());
+ // FIXME: a break in a switch should terminate regions for all preceding
+ // case statements, not just the most recent one.
terminateRegion(S);
}
@@ -692,6 +836,16 @@ struct CounterCoverageMappingBuilder
terminateRegion(S);
}
+ void VisitCallExpr(const CallExpr *E) {
+ VisitStmt(E);
+
+ // Terminate the region when we hit a noreturn function.
+ // (This is helpful dealing with switch statements.)
+ QualType CalleeType = E->getCallee()->getType();
+ if (getFunctionExtInfo(*CalleeType).getNoReturn())
+ terminateRegion(E);
+ }
+
void VisitWhileStmt(const WhileStmt *S) {
extendRegion(S);
@@ -823,15 +977,20 @@ struct CounterCoverageMappingBuilder
extendRegion(Body);
if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
if (!CS->body_empty()) {
- // The body of the switch needs a zero region so that fallthrough counts
- // behave correctly, but it would be misleading to include the braces of
- // the compound statement in the zeroed area, so we need to handle this
- // specially.
+ // Make a region for the body of the switch. If the body starts with
+ // a case, that case will reuse this region; otherwise, this covers
+ // the unreachable code at the beginning of the switch body.
size_t Index =
- pushRegion(Counter::getZero(), getStart(CS->body_front()),
- getEnd(CS->body_back()));
+ pushRegion(Counter::getZero(), getStart(CS->body_front()));
for (const auto *Child : CS->children())
Visit(Child);
+
+ // Set the end for the body of the switch, if it isn't already set.
+ for (size_t i = RegionStack.size(); i != Index; --i) {
+ if (!RegionStack[i - 1].hasEndLoc())
+ RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
+ }
+
popRegions(Index);
}
} else
@@ -940,16 +1099,18 @@ struct CounterCoverageMappingBuilder
}
void VisitBinLAnd(const BinaryOperator *E) {
- extendRegion(E);
- Visit(E->getLHS());
+ extendRegion(E->getLHS());
+ propagateCounts(getRegion().getCounter(), E->getLHS());
+ handleFileExit(getEnd(E->getLHS()));
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
}
void VisitBinLOr(const BinaryOperator *E) {
- extendRegion(E);
- Visit(E->getLHS());
+ extendRegion(E->getLHS());
+ propagateCounts(getRegion().getCounter(), E->getLHS());
+ handleFileExit(getEnd(E->getLHS()));
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
@@ -961,12 +1122,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) {
@@ -994,6 +1153,9 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
case CounterMappingRegion::SkippedRegion:
OS << "Skipped,";
break;
+ case CounterMappingRegion::GapRegion:
+ OS << "Gap,";
+ break;
}
OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
diff --git a/lib/CodeGen/CoverageMappingGen.h b/lib/CodeGen/CoverageMappingGen.h
index b6789c2a79..d07ed5ebcf 100644
--- a/lib/CodeGen/CoverageMappingGen.h
+++ b/lib/CodeGen/CoverageMappingGen.h
@@ -39,7 +39,7 @@ class CoverageSourceInfo : public PPCallbacks {
public:
ArrayRef<SourceRange> getSkippedRanges() const { return SkippedRanges; }
- void SourceRangeSkipped(SourceRange Range) override;
+ void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override;
};
namespace CodeGen {
diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
index 2435830385..c7bdeac58a 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 3b2183ea36..173bc4d8df 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -62,12 +62,20 @@ public:
bool classifyReturnType(CGFunctionInfo &FI) const override;
+ bool passClassIndirect(const CXXRecordDecl *RD) const {
+ // Clang <= 4 used the pre-C++11 rule, which ignores move operations.
+ // The PS4 platform ABI follows the behavior of Clang 3.2.
+ if (CGM.getCodeGenOpts().getClangABICompat() <=
+ CodeGenOptions::ClangABI::Ver4 ||
+ CGM.getTriple().getOS() == llvm::Triple::PS4)
+ return RD->hasNonTrivialDestructor() ||
+ RD->hasNonTrivialCopyConstructor();
+ return !canCopyArgument(RD);
+ }
+
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared
- // special members.
- if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor())
+ // If C++ prohibits us from making a copy, pass by address.
+ if (passClassIndirect(RD))
return RAA_Indirect;
return RAA_Default;
}
@@ -157,9 +165,17 @@ public:
Address Ptr, QualType ElementType,
const CXXDestructorDecl *Dtor) override;
+ /// Itanium says that an _Unwind_Exception has to be "double-word"
+ /// aligned (and thus the end of it is also so-aligned), meaning 16
+ /// bytes. Of course, that was written for the actual Itanium,
+ /// which is a 64-bit platform. Classically, the ABI doesn't really
+ /// specify the alignment on other platforms, but in practice
+ /// libUnwind declares the struct with __attribute__((aligned)), so
+ /// we assume that alignment here. (It's generally 16 bytes, but
+ /// some targets overwrite it.)
CharUnits getAlignmentOfExnObject() {
- unsigned Align = CGM.getContext().getTargetInfo().getExnObjectAlignment();
- return CGM.getContext().toCharUnitsFromBits(Align);
+ auto align = CGM.getContext().getTargetDefaultAlignForAttributeAligned();
+ return CGM.getContext().toCharUnitsFromBits(align);
}
void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;
@@ -284,6 +300,14 @@ public:
// linkage together with vtables when needed.
if (ForVTable && !Thunk->hasLocalLinkage())
Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+
+ // Propagate dllexport storage, to enable the linker to generate import
+ // thunks as necessary (e.g. when a parent class has a key function and a
+ // child class doesn't, and the construction vtable for the parent in the
+ // child needs to reference the parent's thunks).
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ if (MD->hasAttr<DLLExportAttr>())
+ Thunk->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
}
llvm::Value *performThisAdjustment(CodeGenFunction &CGF, Address This,
@@ -366,20 +390,30 @@ public:
void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
private:
- bool hasAnyVirtualInlineFunction(const CXXRecordDecl *RD) const {
- const auto &VtableLayout =
- CGM.getItaniumVTableContext().getVTableLayout(RD);
-
- for (const auto &VtableComponent : VtableLayout.vtable_components()) {
- // Skip empty slot.
- if (!VtableComponent.isUsedFunctionPointerKind())
- continue;
-
- const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
- if (Method->getCanonicalDecl()->isInlined())
- return true;
- }
- return false;
+ bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const {
+ const auto &VtableLayout =
+ CGM.getItaniumVTableContext().getVTableLayout(RD);
+
+ for (const auto &VtableComponent : VtableLayout.vtable_components()) {
+ // Skip empty slot.
+ if (!VtableComponent.isUsedFunctionPointerKind())
+ continue;
+
+ const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
+ if (!Method->getCanonicalDecl()->isInlined())
+ continue;
+
+ StringRef Name = CGM.getMangledName(VtableComponent.getGlobalDecl());
+ auto *Entry = CGM.GetGlobalValue(Name);
+ // This checks if virtual inline function has already been emitted.
+ // Note that it is possible that this inline function would be emitted
+ // after trying to emit vtable speculatively. Because of this we do
+ // an extra pass after emitting all deferred vtables to find and emit
+ // these vtables opportunistically.
+ if (!Entry || Entry->isDeclaration())
+ return true;
+ }
+ return false;
}
bool isVTableHidden(const CXXRecordDecl *RD) const {
@@ -499,7 +533,7 @@ llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
if (MPT->isMemberDataPointer())
return CGM.PtrDiffTy;
- return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, nullptr);
+ return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy);
}
/// In the Itanium and ARM ABIs, method pointers have the form:
@@ -988,10 +1022,8 @@ bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
if (!RD)
return false;
- // Return indirectly if we have a non-trivial copy ctor or non-trivial dtor.
- // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared
- // special members.
- if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) {
+ // If C++ prohibits us from making a copy, return by address.
+ if (passClassIndirect(RD)) {
auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType());
FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
return true;
@@ -1134,8 +1166,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);
}
@@ -1398,9 +1430,9 @@ void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
// FIXME: avoid the fake decl
QualType T = Context.getPointerType(Context.VoidPtrTy);
- ImplicitParamDecl *VTTDecl
- = ImplicitParamDecl::Create(Context, nullptr, MD->getLocation(),
- &Context.Idents.get("vtt"), T);
+ auto *VTTDecl = ImplicitParamDecl::Create(
+ Context, /*DC=*/nullptr, MD->getLocation(), &Context.Idents.get("vtt"),
+ T, ImplicitParamDecl::CXXVTT);
Params.insert(Params.begin() + 1, VTTDecl);
getStructorImplicitParamDecl(CGF) = VTTDecl;
}
@@ -1687,11 +1719,11 @@ bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const {
if (CGM.getLangOpts().AppleKext)
return false;
- // If we don't have any inline virtual functions, and if vtable is not hidden,
- // then we are safe to emit available_externally copy of vtable.
+ // If we don't have any not emitted inline virtual function, and if vtable is
+ // not hidden, then we are safe to emit available_externally copy of vtable.
// FIXME we can still emit a copy of the vtable if we
// can emit definition of the inline functions.
- return !hasAnyVirtualInlineFunction(RD) && !isVTableHidden(RD);
+ return !hasAnyUnusedVirtualInlineFunction(RD) && !isVTableHidden(RD);
}
static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
Address InitialPtr,
@@ -1910,10 +1942,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,
@@ -1921,10 +1954,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,
@@ -1932,10 +1966,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 {
@@ -2092,13 +2127,14 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
(UseARMGuardVarABI && !useInt8GuardVariable)
? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1))
: LI;
- llvm::Value *isInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
+ llvm::Value *NeedsInit = Builder.CreateIsNull(V, "guard.uninitialized");
llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
// Check if the first byte of the guard variable is zero.
- Builder.CreateCondBr(isInitialized, InitCheckBlock, EndBlock);
+ CGF.EmitCXXGuardedInitBranch(NeedsInit, InitCheckBlock, EndBlock,
+ CodeGenFunction::GuardKind::VariableGuard, &D);
CGF.EmitBlock(InitCheckBlock);
@@ -2573,6 +2609,9 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
if (!GV) {
// Create a new global variable.
+ // Note for the future: If we would ever like to do deferred emission of
+ // RTTI, check if emitting vtables opportunistically need any adjustment.
+
GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
/*Constant=*/true,
llvm::GlobalValue::ExternalLinkage, nullptr,
@@ -2626,6 +2665,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
+ case BuiltinType::Float16:
case BuiltinType::Float128:
case BuiltinType::Char16:
case BuiltinType::Char32:
@@ -2716,7 +2756,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
// function.
bool IsDLLImport = RD->hasAttr<DLLImportAttr>();
if (CGM.getVTables().isVTableExternal(RD))
- return IsDLLImport ? false : true;
+ return IsDLLImport && !CGM.getTriple().isWindowsItaniumEnvironment()
+ ? false
+ : true;
if (IsDLLImport)
return true;
@@ -2941,6 +2983,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
return llvm::GlobalValue::InternalLinkage;
case VisibleNoLinkage:
+ case ModuleInternalLinkage:
+ case ModuleLinkage:
case ExternalLinkage:
// RTTI is not enabled, which means that this type info struct is going
// to be used for exception handling. Give it linkonce_odr linkage.
@@ -2952,17 +2996,16 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
if (RD->hasAttr<WeakAttr>())
return llvm::GlobalValue::WeakODRLinkage;
if (CGM.getTriple().isWindowsItaniumEnvironment())
- if (RD->hasAttr<DLLImportAttr>())
- return llvm::GlobalValue::ExternalLinkage;
- if (RD->isDynamicClass()) {
- llvm::GlobalValue::LinkageTypes LT = CGM.getVTableLinkage(RD);
- // MinGW won't export the RTTI information when there is a key function.
- // Make sure we emit our own copy instead of attempting to dllimport it.
if (RD->hasAttr<DLLImportAttr>() &&
- llvm::GlobalValue::isAvailableExternallyLinkage(LT))
- LT = llvm::GlobalValue::LinkOnceODRLinkage;
- return LT;
- }
+ ShouldUseExternalRTTIDescriptor(CGM, Ty))
+ return llvm::GlobalValue::ExternalLinkage;
+ // MinGW always uses LinkOnceODRLinkage for type info.
+ if (RD->isDynamicClass() &&
+ !CGM.getContext()
+ .getTargetInfo()
+ .getTriple()
+ .isWindowsGNUEnvironment())
+ return CGM.getVTableLinkage(RD);
}
return llvm::GlobalValue::LinkOnceODRLinkage;
@@ -3165,7 +3208,8 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force,
if (DLLExport || (RD && RD->hasAttr<DLLExportAttr>())) {
TypeName->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- } else if (CGM.getLangOpts().RTTI && RD && RD->hasAttr<DLLImportAttr>()) {
+ } else if (RD && RD->hasAttr<DLLImportAttr>() &&
+ ShouldUseExternalRTTIDescriptor(CGM, Ty)) {
TypeName->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
@@ -3620,6 +3664,18 @@ void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
!CGM.TryEmitBaseDestructorAsAlias(DD))
return;
+ // FIXME: The deleting destructor is equivalent to the selected operator
+ // delete if:
+ // * either the delete is a destroying operator delete or the destructor
+ // would be trivial if it weren't virtual,
+ // * the conversion from the 'this' parameter to the first parameter of the
+ // destructor is equivalent to a bitcast,
+ // * the destructor does not have an implicit "this" return, and
+ // * the operator delete has the same calling convention and IR function type
+ // as the destructor.
+ // In such cases we should try to emit the deleting dtor as an alias to the
+ // selected 'operator delete'.
+
llvm::Function *Fn = CGM.codegenCXXStructor(MD, Type);
if (CGType == StructorCodegen::COMDAT) {
@@ -3927,9 +3983,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
index acea5c1143..a6f21d8ddc 100644
--- a/lib/CodeGen/MacroPPCallbacks.cpp
+++ b/lib/CodeGen/MacroPPCallbacks.cpp
@@ -26,8 +26,8 @@ void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
if (MI.isFunctionLike()) {
Name << '(';
- if (!MI.arg_empty()) {
- MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ if (!MI.param_empty()) {
+ MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
for (; AI + 1 != E; ++AI) {
Name << (*AI)->getName();
Name << ',';
@@ -198,7 +198,8 @@ void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
}
void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
diff --git a/lib/CodeGen/MacroPPCallbacks.h b/lib/CodeGen/MacroPPCallbacks.h
index 06217f9c58..e117f96f47 100644
--- a/lib/CodeGen/MacroPPCallbacks.h
+++ b/lib/CodeGen/MacroPPCallbacks.h
@@ -110,8 +110,8 @@ public:
/// Hook called whenever a macro \#undef is seen.
///
/// MD is released immediately following this callback.
- void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) override;
+ void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
+ const MacroDirective *Undef) override;
};
} // end namespace clang
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index ddfdefac43..e81dedf14d 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -819,46 +819,44 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
return RAA_Default;
case llvm::Triple::x86_64:
- // Win64 passes objects with non-trivial copy ctors indirectly.
- if (RD->hasNonTrivialCopyConstructor())
- return RAA_Indirect;
-
- // If an object has a destructor, we'd really like to pass it indirectly
+ // If a class has a destructor, we'd really like to pass it indirectly
// because it allows us to elide copies. Unfortunately, MSVC makes that
// impossible for small types, which it will pass in a single register or
// stack slot. Most objects with dtors are large-ish, so handle that early.
// We can't call out all large objects as being indirect because there are
// multiple x64 calling conventions and the C++ ABI code shouldn't dictate
// how we pass large POD types.
+ //
+ // Note: This permits small classes with nontrivial destructors to be
+ // passed in registers, which is non-conforming.
if (RD->hasNonTrivialDestructor() &&
getContext().getTypeSize(RD->getTypeForDecl()) > 64)
return RAA_Indirect;
- // If this is true, the implicit copy constructor that Sema would have
- // created would not be deleted. FIXME: We should provide a more direct way
- // for CodeGen to ask whether the constructor was deleted.
- if (!RD->hasUserDeclaredCopyConstructor() &&
- !RD->hasUserDeclaredMoveConstructor() &&
- !RD->needsOverloadResolutionForMoveConstructor() &&
- !RD->hasUserDeclaredMoveAssignment() &&
- !RD->needsOverloadResolutionForMoveAssignment())
- return RAA_Default;
-
- // Otherwise, Sema should have created an implicit copy constructor if
- // needed.
- assert(!RD->needsImplicitCopyConstructor());
-
- // We have to make sure the trivial copy constructor isn't deleted.
- for (const CXXConstructorDecl *CD : RD->ctors()) {
- if (CD->isCopyConstructor()) {
- assert(CD->isTrivial());
- // We had at least one undeleted trivial copy ctor. Return directly.
- if (!CD->isDeleted())
- return RAA_Default;
+ // If a class has at least one non-deleted, trivial copy constructor, it
+ // is passed according to the C ABI. Otherwise, it is passed indirectly.
+ //
+ // Note: This permits classes with non-trivial copy or move ctors to be
+ // passed in registers, so long as they *also* have a trivial copy ctor,
+ // which is non-conforming.
+ if (RD->needsImplicitCopyConstructor()) {
+ // If the copy ctor has not yet been declared, we can read its triviality
+ // off the AST.
+ if (!RD->defaultedCopyConstructorIsDeleted() &&
+ RD->hasTrivialCopyConstructor())
+ return RAA_Default;
+ } else {
+ // Otherwise, we need to find the copy constructor(s) and ask.
+ for (const CXXConstructorDecl *CD : RD->ctors()) {
+ if (CD->isCopyConstructor()) {
+ // We had at least one nondeleted trivial copy ctor. Return directly.
+ if (!CD->isDeleted() && CD->isTrivial())
+ return RAA_Default;
+ }
}
}
- // The trivial copy constructor was deleted. Return indirectly.
+ // We have no trivial, non-deleted copy constructor.
return RAA_Indirect;
}
@@ -1413,11 +1411,10 @@ void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
- ImplicitParamDecl *IsMostDerived
- = ImplicitParamDecl::Create(Context, nullptr,
- CGF.CurGD.getDecl()->getLocation(),
- &Context.Idents.get("is_most_derived"),
- Context.IntTy);
+ auto *IsMostDerived = ImplicitParamDecl::Create(
+ Context, /*DC=*/nullptr, CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("is_most_derived"), Context.IntTy,
+ ImplicitParamDecl::Other);
// The 'most_derived' parameter goes second if the ctor is variadic and last
// if it's not. Dtors can't be variadic.
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
@@ -1427,11 +1424,10 @@ void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
Params.push_back(IsMostDerived);
getStructorImplicitParamDecl(CGF) = IsMostDerived;
} else if (isDeletingDtor(CGF.CurGD)) {
- ImplicitParamDecl *ShouldDelete
- = ImplicitParamDecl::Create(Context, nullptr,
- CGF.CurGD.getDecl()->getLocation(),
- &Context.Idents.get("should_call_delete"),
- Context.IntTy);
+ auto *ShouldDelete = ImplicitParamDecl::Create(
+ Context, /*DC=*/nullptr, CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("should_call_delete"), Context.IntTy,
+ ImplicitParamDecl::Other);
Params.push_back(ShouldDelete);
getStructorImplicitParamDecl(CGF) = ShouldDelete;
}
@@ -2210,9 +2206,8 @@ static void emitGlobalDtorWithTLRegDtor(CodeGenFunction &CGF, const VarDecl &VD,
llvm::FunctionType *TLRegDtorTy = llvm::FunctionType::get(
CGF.IntTy, DtorStub->getType(), /*IsVarArg=*/false);
- llvm::Constant *TLRegDtor =
- CGF.CGM.CreateRuntimeFunction(TLRegDtorTy, "__tlregdtor",
- llvm::AttributeSet(), /*Local=*/true);
+ llvm::Constant *TLRegDtor = CGF.CGM.CreateRuntimeFunction(
+ TLRegDtorTy, "__tlregdtor", llvm::AttributeList(), /*Local=*/true);
if (llvm::Function *TLRegDtorFn = dyn_cast<llvm::Function>(TLRegDtor))
TLRegDtorFn->setDoesNotThrow();
@@ -2308,9 +2303,9 @@ static llvm::Constant *getInitThreadHeaderFn(CodeGenModule &CGM) {
CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(
FTy, "_Init_thread_header",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind),
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
/*Local=*/true);
}
@@ -2320,9 +2315,9 @@ static llvm::Constant *getInitThreadFooterFn(CodeGenModule &CGM) {
CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(
FTy, "_Init_thread_footer",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind),
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
/*Local=*/true);
}
@@ -2332,9 +2327,9 @@ static llvm::Constant *getInitThreadAbortFn(CodeGenModule &CGM) {
CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(
FTy, "_Init_thread_abort",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind),
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
/*Local=*/true);
}
@@ -2466,11 +2461,12 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
// Test our bit from the guard variable.
llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1ULL << GuardNum);
llvm::LoadInst *LI = Builder.CreateLoad(GuardAddr);
- llvm::Value *IsInitialized =
- Builder.CreateICmpNE(Builder.CreateAnd(LI, Bit), Zero);
+ llvm::Value *NeedsInit =
+ Builder.CreateICmpEQ(Builder.CreateAnd(LI, Bit), Zero);
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
- Builder.CreateCondBr(IsInitialized, EndBlock, InitBlock);
+ CGF.EmitCXXGuardedInitBranch(NeedsInit, InitBlock, EndBlock,
+ CodeGenFunction::GuardKind::VariableGuard, &D);
// Set our bit in the guard variable and emit the initializer and add a global
// destructor if appropriate.
@@ -2505,7 +2501,8 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
Builder.CreateICmpSGT(FirstGuardLoad, InitThreadEpoch);
llvm::BasicBlock *AttemptInitBlock = CGF.createBasicBlock("init.attempt");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
- Builder.CreateCondBr(IsUninitialized, AttemptInitBlock, EndBlock);
+ CGF.EmitCXXGuardedInitBranch(IsUninitialized, AttemptInitBlock, EndBlock,
+ CodeGenFunction::GuardKind::VariableGuard, &D);
// This BasicBlock attempts to determine whether or not this thread is
// responsible for doing the initialization.
@@ -3428,6 +3425,8 @@ static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) {
return llvm::GlobalValue::InternalLinkage;
case VisibleNoLinkage:
+ case ModuleInternalLinkage:
+ case ModuleLinkage:
case ExternalLinkage:
return llvm::GlobalValue::LinkOnceODRLinkage;
}
@@ -3720,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 =
@@ -3757,6 +3756,9 @@ llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+ // Note for the future: If we would ever like to do deferred emission of
+ // RTTI, check if emitting vtables opportunistically need any adjustment.
+
// Compute the fields for the TypeDescriptor.
SmallString<256> TypeInfoString;
{
@@ -3803,7 +3805,7 @@ static void emitCXXDestructor(CodeGenModule &CGM, const CXXDestructorDecl *dtor,
if (!dtor->getParent()->getNumVBases() &&
(dtorType == StructorType::Complete || dtorType == StructorType::Base)) {
bool ProducedAlias = !CGM.TryEmitDefinitionAsAlias(
- GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base), true);
+ GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base));
if (ProducedAlias) {
if (dtorType == StructorType::Complete)
return;
@@ -3873,18 +3875,21 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
// Following the 'this' pointer is a reference to the source object that we
// are copying from.
ImplicitParamDecl SrcParam(
- getContext(), nullptr, SourceLocation(), &getContext().Idents.get("src"),
+ getContext(), /*DC=*/nullptr, SourceLocation(),
+ &getContext().Idents.get("src"),
getContext().getLValueReferenceType(RecordTy,
- /*SpelledAsLValue=*/true));
+ /*SpelledAsLValue=*/true),
+ ImplicitParamDecl::Other);
if (IsCopy)
FunctionArgs.push_back(&SrcParam);
// Constructors for classes which utilize virtual bases have an additional
// parameter which indicates whether or not it is being delegated to by a more
// derived constructor.
- ImplicitParamDecl IsMostDerived(getContext(), nullptr, SourceLocation(),
+ ImplicitParamDecl IsMostDerived(getContext(), /*DC=*/nullptr,
+ SourceLocation(),
&getContext().Idents.get("is_most_derived"),
- getContext().IntTy);
+ getContext().IntTy, ImplicitParamDecl::Other);
// Only add the parameter to the list if thie class has virtual bases.
if (RD->getNumVBases() > 0)
FunctionArgs.push_back(&IsMostDerived);
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 89090c8b6a..8aa9bfb421 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -119,6 +119,14 @@ namespace {
return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition));
}
+ llvm::Module *StartModule(llvm::StringRef ModuleName,
+ llvm::LLVMContext &C) {
+ assert(!M && "Replacing existing Module?");
+ M.reset(new llvm::Module(ModuleName, C));
+ Initialize(*Ctx);
+ return M.get();
+ }
+
void Initialize(ASTContext &Context) override {
Ctx = &Context;
@@ -197,7 +205,7 @@ namespace {
// Provide some coverage mapping even for methods that aren't emitted.
// Don't do this for templated classes though, as they may not be
// instantiable.
- if (!MD->getParent()->getDescribedClassTemplate())
+ if (!MD->getParent()->isDependentContext())
Builder->AddDeferredUnusedCoverageMapping(MD);
}
@@ -317,6 +325,11 @@ llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global,
->GetAddrOfGlobal(global, isForDefinition);
}
+llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
+ llvm::LLVMContext &C) {
+ return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
+}
+
CodeGenerator *clang::CreateLLVMCodeGen(
DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
const HeaderSearchOptions &HeaderSearchOpts,
diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index 37ecc05aa1..d0760b9cc2 100644
--- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -152,6 +152,9 @@ public:
CodeGenOpts.CodeModel = "default";
CodeGenOpts.ThreadModel = "single";
CodeGenOpts.DebugTypeExtRefs = true;
+ // When building a module MainFileName is the name of the modulemap file.
+ CodeGenOpts.MainFileName =
+ LangOpts.CurrentModule.empty() ? MainFileName : LangOpts.CurrentModule;
CodeGenOpts.setDebugInfo(codegenoptions::FullDebugInfo);
CodeGenOpts.setDebuggerTuning(CI.getCodeGenOpts().getDebuggerTuning());
}
diff --git a/lib/CodeGen/SwiftCallingConv.cpp b/lib/CodeGen/SwiftCallingConv.cpp
index 0bfe30a32c..fc8e36d2c5 100644
--- a/lib/CodeGen/SwiftCallingConv.cpp
+++ b/lib/CodeGen/SwiftCallingConv.cpp
@@ -57,6 +57,10 @@ static CharUnits getTypeStoreSize(CodeGenModule &CGM, llvm::Type *type) {
return CharUnits::fromQuantity(CGM.getDataLayout().getTypeStoreSize(type));
}
+static CharUnits getTypeAllocSize(CodeGenModule &CGM, llvm::Type *type) {
+ return CharUnits::fromQuantity(CGM.getDataLayout().getTypeAllocSize(type));
+}
+
void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) {
// Deal with various aggregate types as special cases:
@@ -542,7 +546,9 @@ SwiftAggLowering::getCoerceAndExpandTypes() const {
packed = true;
elts.push_back(entry.Type);
- lastEnd = entry.End;
+
+ lastEnd = entry.Begin + getTypeAllocSize(CGM, entry.Type);
+ assert(entry.End <= lastEnd);
}
// We don't need to adjust 'packed' to deal with possible tail padding
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 82f412f012..b1773b7090 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -14,6 +14,7 @@
#include "TargetInfo.h"
#include "ABIInfo.h"
+#include "CGBlocks.h"
#include "CGCXXABI.h"
#include "CGValue.h"
#include "CodeGenFunction.h"
@@ -22,7 +23,9 @@
#include "clang/CodeGen/SwiftCallingConv.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
@@ -183,7 +186,11 @@ const TargetInfo &ABIInfo::getTarget() const {
return CGT.getTarget();
}
-bool ABIInfo:: isAndroid() const { return getTarget().getTriple().isAndroid(); }
+const CodeGenOptions &ABIInfo::getCodeGenOpts() const {
+ return CGT.getCodeGenOpts();
+}
+
+bool ABIInfo::isAndroid() const { return getTarget().getTriple().isAndroid(); }
bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
return false;
@@ -398,7 +405,17 @@ TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,
}
unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const {
- return llvm::CallingConv::C;
+ // OpenCL kernels are called via an explicit runtime API with arguments
+ // set with clSetKernelArg(), not as normal sub-functions.
+ // Return SPIR_KERNEL by default as the kernel calling convention to
+ // ensure the fingerprint is fixed such way that each OpenCL argument
+ // gets one matching argument in the produced kernel function argument
+ // list to enable feasible implementation of clSetKernelArg() with
+ // aggregates etc. In case we would use the default C calling conv here,
+ // clSetKernelArg() might break depending on the target-specific
+ // conventions; different targets might split structs passed as values
+ // to multiple function arguments etc.
+ return llvm::CallingConv::SPIR_KERNEL;
}
llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
@@ -406,13 +423,36 @@ llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &
return llvm::ConstantPointerNull::get(T);
}
+LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const {
+ assert(!CGM.getLangOpts().OpenCL &&
+ !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
+ "Address space agnostic languages only");
+ return D ? D->getType().getAddressSpace() : LangAS::Default;
+}
+
llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(
- CodeGen::CodeGenFunction &CGF, llvm::Value *Src, QualType SrcTy,
- QualType DestTy) const {
+ CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr,
+ LangAS DestAddr, llvm::Type *DestTy, bool isNonNull) const {
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
- return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src,
- CGF.ConvertType(DestTy));
+ if (auto *C = dyn_cast<llvm::Constant>(Src))
+ return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy);
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DestTy);
+}
+
+llvm::Constant *
+TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src,
+ LangAS SrcAddr, LangAS DestAddr,
+ llvm::Type *DestTy) const {
+ // Since target may map different address spaces in AST to the same address
+ // space, an address space conversion may end up as a bitcast.
+ return llvm::ConstantExpr::getPointerCast(Src, DestTy);
+}
+
+llvm::SyncScope::ID
+TargetCodeGenInfo::getLLVMSyncScopeID(SyncScope S, llvm::LLVMContext &C) const {
+ return C.getOrInsertSyncScopeID(""); /* default sync scope */
}
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
@@ -836,7 +876,10 @@ bool IsX86_MMXType(llvm::Type *IRType) {
static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
StringRef Constraint,
llvm::Type* Ty) {
- if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy()) {
+ bool IsMMXCons = llvm::StringSwitch<bool>(Constraint)
+ .Cases("y", "&y", "^Ym", true)
+ .Default(false);
+ if (IsMMXCons && Ty->isVectorTy()) {
if (cast<llvm::VectorType>(Ty)->getBitWidth() != 64) {
// Invalid MMX constraint
return nullptr;
@@ -853,8 +896,14 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
/// X86_VectorCall calling convention. Shared between x86_32 and x86_64.
static bool isX86VectorTypeForVectorCall(ASTContext &Context, QualType Ty) {
if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half)
+ if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) {
+ if (BT->getKind() == BuiltinType::LongDouble) {
+ if (&Context.getTargetInfo().getLongDoubleFormat() ==
+ &llvm::APFloat::x87DoubleExtended())
+ return false;
+ }
return true;
+ }
} else if (const VectorType *VT = Ty->getAs<VectorType>()) {
// vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX
// registers specially.
@@ -942,8 +991,7 @@ class X86_32ABIInfo : public SwiftABIInfo {
Class classify(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
- ABIArgInfo reclassifyHvaArgType(QualType RetTy, CCState &State,
- const ABIArgInfo& current) const;
+
/// \brief Updates the number of available free registers, returns
/// true if any registers were allocated.
bool updateFreeRegs(QualType Ty, CCState &State) const;
@@ -1009,7 +1057,8 @@ public:
const llvm::Triple &Triple, const CodeGenOptions &Opts);
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override;
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
// Darwin uses different dwarf register numbers for EH.
@@ -1038,14 +1087,14 @@ public:
getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override {
unsigned Sig = (0xeb << 0) | // jmp rel8
(0x06 << 8) | // .+0x08
- ('F' << 16) |
- ('T' << 24);
+ ('v' << 16) |
+ ('2' << 24);
return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
}
StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
return "movl\t%ebp, %ebp"
- "\t\t## marker for objc_retainAutoreleaseReturnValue";
+ "\t\t// marker for objc_retainAutoreleaseReturnValue";
}
};
@@ -1527,27 +1576,6 @@ bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
return true;
}
-ABIArgInfo
-X86_32ABIInfo::reclassifyHvaArgType(QualType Ty, CCState &State,
- const ABIArgInfo &current) const {
- // Assumes vectorCall calling convention.
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
-
- if (!Ty->isBuiltinType() && !Ty->isVectorType() &&
- isHomogeneousAggregate(Ty, Base, NumElts)) {
- if (State.FreeSSERegs >= NumElts) {
- // HVA types get passed directly in registers if there is room.
- State.FreeSSERegs -= NumElts;
- return getDirectX86Hva();
- }
- // If there's no room, the HVA gets passed as normal indirect
- // structure.
- return getIndirectResult(Ty, /*ByVal=*/false, State);
- }
- return current;
-}
-
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
CCState &State) const {
// FIXME: Set alignment on indirect arguments.
@@ -1566,35 +1594,20 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
}
}
- // vectorcall adds the concept of a homogenous vector aggregate, similar
- // to other targets, regcall uses some of the HVA rules.
+ // Regcall uses the concept of a homogenous vector aggregate, similar
+ // to other targets.
const Type *Base = nullptr;
uint64_t NumElts = 0;
- if ((State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall) &&
+ if (State.CC == llvm::CallingConv::X86_RegCall &&
isHomogeneousAggregate(Ty, Base, NumElts)) {
- if (State.CC == llvm::CallingConv::X86_RegCall) {
- if (State.FreeSSERegs >= NumElts) {
- State.FreeSSERegs -= NumElts;
- if (Ty->isBuiltinType() || Ty->isVectorType())
- return ABIArgInfo::getDirect();
- return ABIArgInfo::getExpand();
-
- }
- return getIndirectResult(Ty, /*ByVal=*/false, State);
- } else if (State.CC == llvm::CallingConv::X86_VectorCall) {
- if (State.FreeSSERegs >= NumElts && (Ty->isBuiltinType() || Ty->isVectorType())) {
- // Actual floating-point types get registers first time through if
- // there is registers available
- State.FreeSSERegs -= NumElts;
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ if (Ty->isBuiltinType() || Ty->isVectorType())
return ABIArgInfo::getDirect();
- } else if (!Ty->isBuiltinType() && !Ty->isVectorType()) {
- // HVA Types only get registers after everything else has been
- // set, so it gets set as indirect for now.
- return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty));
- }
+ return ABIArgInfo::getExpand();
}
+ return getIndirectResult(Ty, /*ByVal=*/false, State);
}
if (isAggregateTypeForABI(Ty)) {
@@ -1675,31 +1688,53 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
void X86_32ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, CCState &State,
bool &UsedInAlloca) const {
- // Vectorcall only allows the first 6 parameters to be passed in registers,
- // and homogeneous vector aggregates are only put into registers as a second
- // priority.
- unsigned Count = 0;
- CCState ZeroState = State;
- ZeroState.FreeRegs = ZeroState.FreeSSERegs = 0;
- // HVAs must be done as a second priority for registers, so the deferred
- // items are dealt with by going through the pattern a second time.
+ // Vectorcall x86 works subtly different than in x64, so the format is
+ // a bit different than the x64 version. First, all vector types (not HVAs)
+ // are assigned, with the first 6 ending up in the YMM0-5 or XMM0-5 registers.
+ // This differs from the x64 implementation, where the first 6 by INDEX get
+ // registers.
+ // After that, integers AND HVAs are assigned Left to Right in the same pass.
+ // Integers are passed as ECX/EDX if one is available (in order). HVAs will
+ // first take up the remaining YMM/XMM registers. If insufficient registers
+ // remain but an integer register (ECX/EDX) is available, it will be passed
+ // in that, else, on the stack.
for (auto &I : FI.arguments()) {
- if (Count < VectorcallMaxParamNumAsReg)
- I.info = classifyArgumentType(I.type, State);
- else
- // Parameters after the 6th cannot be passed in registers,
- // so pretend there are no registers left for them.
- I.info = classifyArgumentType(I.type, ZeroState);
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- ++Count;
+ // First pass do all the vector types.
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ const QualType& Ty = I.type;
+ if ((Ty->isVectorType() || Ty->isBuiltinType()) &&
+ isHomogeneousAggregate(Ty, Base, NumElts)) {
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ I.info = ABIArgInfo::getDirect();
+ } else {
+ I.info = classifyArgumentType(Ty, State);
+ }
+ UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
+ }
}
- Count = 0;
- // Go through the arguments a second time to get HVAs registers if there
- // are still some available.
+
for (auto &I : FI.arguments()) {
- if (Count < VectorcallMaxParamNumAsReg)
- I.info = reclassifyHvaArgType(I.type, State, I.info);
- ++Count;
+ // Second pass, do the rest!
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ const QualType& Ty = I.type;
+ bool IsHva = isHomogeneousAggregate(Ty, Base, NumElts);
+
+ if (IsHva && !Ty->isVectorType() && !Ty->isBuiltinType()) {
+ // Assign true HVAs (non vector/native FP types).
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ I.info = getDirectX86Hva();
+ } else {
+ I.info = getIndirectResult(Ty, /*ByVal=*/false, State);
+ }
+ } else if (!IsHva) {
+ // Assign all Non-HVAs, so this will exclude Vector/FP args.
+ I.info = classifyArgumentType(Ty, State);
+ UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
+ }
}
}
@@ -1882,7 +1917,6 @@ bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
case llvm::Triple::DragonFly:
case llvm::Triple::FreeBSD:
case llvm::Triple::OpenBSD:
- case llvm::Triple::Bitrig:
case llvm::Triple::Win32:
return true;
default:
@@ -1890,9 +1924,11 @@ bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
}
}
-void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
- llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
+void X86_32TargetCodeGenInfo::setTargetAttributes(
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const {
+ if (!IsForDefinition)
+ return;
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
// Get the LLVM function.
@@ -1901,10 +1937,7 @@ void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
// Now add the 'alignstack' attribute with a value of 16.
llvm::AttrBuilder B;
B.addStackAlignmentAttr(16);
- Fn->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- B));
+ Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
}
if (FD->hasAttr<AnyX86InterruptAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
@@ -2084,9 +2117,14 @@ class X86_64ABIInfo : public SwiftABIInfo {
return !getTarget().getTriple().isOSDarwin();
}
- /// GCC classifies <1 x long long> as SSE but compatibility with older clang
- // compilers require us to classify it as INTEGER.
+ /// GCC classifies <1 x long long> as SSE but some platform ABIs choose to
+ /// classify it as INTEGER (for compatibility with older clang compilers).
bool classifyIntegerMMXAsSSE() const {
+ // Clang <= 3.8 did not do this.
+ if (getCodeGenOpts().getClangABICompat() <=
+ CodeGenOptions::ClangABI::Ver3_8)
+ return false;
+
const llvm::Triple &Triple = getTarget().getTriple();
if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::PS4)
return false;
@@ -2240,23 +2278,28 @@ public:
llvm::Constant *
getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override {
- unsigned Sig;
- if (getABIInfo().has64BitPointers())
- Sig = (0xeb << 0) | // jmp rel8
- (0x0a << 8) | // .+0x0c
- ('F' << 16) |
- ('T' << 24);
- else
- Sig = (0xeb << 0) | // jmp rel8
- (0x06 << 8) | // .+0x08
- ('F' << 16) |
- ('T' << 24);
+ unsigned Sig = (0xeb << 0) | // jmp rel8
+ (0x06 << 8) | // .+0x08
+ ('v' << 16) |
+ ('2' << 24);
return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override {
+ if (!IsForDefinition)
+ return;
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
+ // Get the LLVM function.
+ auto *Fn = cast<llvm::Function>(GV);
+
+ // Now add the 'alignstack' attribute with a value of 16.
+ llvm::AttrBuilder B;
+ B.addStackAlignmentAttr(16);
+ Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
+ }
if (FD->hasAttr<AnyX86InterruptAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
Fn->setCallingConv(llvm::CallingConv::X86_INTR);
@@ -2303,7 +2346,8 @@ public:
Win32StructABI, NumRegisterParameters, false) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override;
void getDependentLibraryOption(llvm::StringRef Lib,
llvm::SmallString<24> &Opt) const override {
@@ -2331,11 +2375,12 @@ static void addStackProbeSizeTargetAttribute(const Decl *D,
}
}
-void WinX86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
- llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
- X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
-
+void WinX86_32TargetCodeGenInfo::setTargetAttributes(
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const {
+ X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition);
+ if (!IsForDefinition)
+ return;
addStackProbeSizeTargetAttribute(D, GV, CGM);
}
@@ -2346,7 +2391,8 @@ public:
: TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override;
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
return 7;
@@ -2375,12 +2421,22 @@ public:
}
};
-void WinX86_64TargetCodeGenInfo::setTargetAttributes(const Decl *D,
- llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
- TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
-
+void WinX86_64TargetCodeGenInfo::setTargetAttributes(
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const {
+ TargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition);
+ if (!IsForDefinition)
+ return;
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (FD->hasAttr<X86ForceAlignArgPointerAttr>()) {
+ // Get the LLVM function.
+ auto *Fn = cast<llvm::Function>(GV);
+
+ // Now add the 'alignstack' attribute with a value of 16.
+ llvm::AttrBuilder B;
+ B.addStackAlignmentAttr(16);
+ Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
+ }
if (FD->hasAttr<AnyX86InterruptAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
Fn->setCallingConv(llvm::CallingConv::X86_INTR);
@@ -3162,8 +3218,7 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
}
}
- llvm::StructType *Result = llvm::StructType::get(Lo, Hi, nullptr);
-
+ llvm::StructType *Result = llvm::StructType::get(Lo, Hi);
// Verify that the second element is at an 8-byte offset.
assert(TD.getStructLayout(Result)->getElementOffset(1) == 8 &&
@@ -3238,8 +3293,7 @@ classifyReturnType(QualType RetTy) const {
case ComplexX87:
assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
ResType = llvm::StructType::get(llvm::Type::getX86_FP80Ty(getVMContext()),
- llvm::Type::getX86_FP80Ty(getVMContext()),
- nullptr);
+ llvm::Type::getX86_FP80Ty(getVMContext()));
break;
}
@@ -3496,18 +3550,27 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
unsigned FreeSSERegs = IsRegCall ? 16 : 8;
unsigned NeededInt, NeededSSE;
- if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() &&
- !FI.getReturnType()->getTypePtr()->isUnionType()) {
- FI.getReturnInfo() =
- classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE);
- if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) {
- FreeIntRegs -= NeededInt;
- FreeSSERegs -= NeededSSE;
- } else {
- FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType());
- }
- } else if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI)) {
+ if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() &&
+ !FI.getReturnType()->getTypePtr()->isUnionType()) {
+ FI.getReturnInfo() =
+ classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE);
+ if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) {
+ FreeIntRegs -= NeededInt;
+ FreeSSERegs -= NeededSSE;
+ } else {
+ FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType());
+ }
+ } else if (IsRegCall && FI.getReturnType()->getAs<ComplexType>()) {
+ // Complex Long Double Type is passed in Memory when Regcall
+ // calling convention is used.
+ const ComplexType *CT = FI.getReturnType()->getAs<ComplexType>();
+ if (getContext().getCanonicalType(CT->getElementType()) ==
+ getContext().LongDoubleTy)
+ FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType());
+ } else
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ }
// If the return value is indirect, then the hidden argument is consuming one
// integer register.
@@ -3735,7 +3798,7 @@ Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
CGF.Builder.CreateConstInBoundsByteGEP(RegAddrLo,
CharUnits::fromQuantity(16));
llvm::Type *DoubleTy = CGF.DoubleTy;
- llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, nullptr);
+ llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy);
llvm::Value *V;
Address Tmp = CGF.CreateMemTemp(Ty);
Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST);
@@ -3897,6 +3960,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI,
bool IsRegCall) const {
unsigned Count = 0;
for (auto &I : FI.arguments()) {
+ // Vectorcall in x64 only permits the first 6 arguments to be passed
+ // as XMM/YMM registers.
if (Count < VectorcallMaxParamNumAsReg)
I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall);
else {
@@ -3909,11 +3974,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI,
++Count;
}
- Count = 0;
for (auto &I : FI.arguments()) {
- if (Count < VectorcallMaxParamNumAsReg)
- I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info);
- ++Count;
+ I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info);
}
}
@@ -3974,7 +4036,10 @@ Address WinX86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
namespace {
/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
-bool IsSoftFloatABI;
+ bool IsSoftFloatABI;
+
+ CharUnits getParamTypeAlignment(QualType Ty) const;
+
public:
PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI)
: DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI) {}
@@ -3996,13 +4061,46 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
};
+}
+
+CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
+ // Complex types are passed just like their elements
+ if (const ComplexType *CTy = Ty->getAs<ComplexType>())
+ Ty = CTy->getElementType();
+
+ if (Ty->isVectorType())
+ return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16
+ : 4);
+
+ // For single-element float/vector structs, we consider the whole type
+ // to have the same alignment requirements as its single element.
+ const Type *AlignTy = nullptr;
+ if (const Type *EltType = isSingleElementStruct(Ty, getContext())) {
+ const BuiltinType *BT = EltType->getAs<BuiltinType>();
+ if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) ||
+ (BT && BT->isFloatingPoint()))
+ AlignTy = EltType;
+ }
+ if (AlignTy)
+ return CharUnits::fromQuantity(AlignTy->isVectorType() ? 16 : 4);
+ return CharUnits::fromQuantity(4);
}
// TODO: this implementation is now likely redundant with
// DefaultABIInfo::EmitVAArg.
Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
QualType Ty) const {
+ if (getTarget().getTriple().isOSDarwin()) {
+ auto TI = getContext().getTypeInfoInChars(Ty);
+ TI.second = getParamTypeAlignment(Ty);
+
+ CharUnits SlotSize = CharUnits::fromQuantity(4);
+ return emitVoidPtrVAArg(CGF, VAList, Ty,
+ classifyArgumentType(Ty).isIndirect(), TI, SlotSize,
+ /*AllowHigherAlign=*/true);
+ }
+
const unsigned OverflowLimit = 8;
if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
// TODO: Implement this. For now ignore.
@@ -4640,7 +4738,7 @@ PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
llvm::Type *CoerceTy;
if (Bits > GPRBits) {
CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
- CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy, nullptr);
+ CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy);
} else
CoerceTy =
llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
@@ -4777,7 +4875,8 @@ class AArch64ABIInfo : public SwiftABIInfo {
public:
enum ABIKind {
AAPCS = 0,
- DarwinPCS
+ DarwinPCS,
+ Win64
};
private:
@@ -4815,10 +4914,14 @@ private:
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override {
- return isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
- : EmitAAPCSVAArg(VAListAddr, Ty, CGF);
+ return Kind == Win64 ? EmitMSVAArg(CGF, VAListAddr, Ty)
+ : isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
+ : EmitAAPCSVAArg(VAListAddr, Ty, CGF);
}
+ Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const override;
+
bool shouldPassIndirectlyForSwift(CharUnits totalSize,
ArrayRef<llvm::Type*> scalars,
bool asReturnValue) const override {
@@ -4827,6 +4930,9 @@ private:
bool isSwiftErrorInRegister() const override {
return true;
}
+
+ bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
+ unsigned elts) const override;
};
class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
@@ -4835,7 +4941,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 {
@@ -4844,6 +4950,22 @@ public:
bool doesReturnSlotInterfereWithArgs() const override { return false; }
};
+
+class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
+public:
+ WindowsAArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind K)
+ : AArch64TargetCodeGenInfo(CGT, K) {}
+
+ void getDependentLibraryOption(llvm::StringRef Lib,
+ llvm::SmallString<24> &Opt) const override {
+ Opt = "/DEFAULTLIB:" + qualifyWindowsLibrary(Lib);
+ }
+
+ void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value,
+ llvm::SmallString<32> &Opt) const override {
+ Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
+ }
+};
}
ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
@@ -4893,10 +5015,16 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
// Empty records are always ignored on Darwin, but actually passed in C++ mode
// elsewhere for GNU compatibility.
- if (isEmptyRecord(getContext(), Ty, true)) {
+ uint64_t Size = getContext().getTypeSize(Ty);
+ bool IsEmpty = isEmptyRecord(getContext(), Ty, true);
+ if (IsEmpty || Size == 0) {
if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS())
return ABIArgInfo::getIgnore();
+ // GNU C mode. The only argument that gets ignored is an empty one with size
+ // 0.
+ if (IsEmpty && Size == 0)
+ return ABIArgInfo::getIgnore();
return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
}
@@ -4909,7 +5037,6 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
}
// Aggregates <= 16 bytes are passed directly in registers or on the stack.
- uint64_t Size = getContext().getTypeSize(Ty);
if (Size <= 128) {
// On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
// same size and alignment.
@@ -4917,7 +5044,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.
@@ -4949,7 +5076,8 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
: ABIArgInfo::getDirect());
}
- if (isEmptyRecord(getContext(), RetTy, true))
+ uint64_t Size = getContext().getTypeSize(RetTy);
+ if (isEmptyRecord(getContext(), RetTy, true) || Size == 0)
return ABIArgInfo::getIgnore();
const Type *Base = nullptr;
@@ -4959,7 +5087,6 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getDirect();
// Aggregates <= 16 bytes are returned directly in registers or on the stack.
- uint64_t Size = getContext().getTypeSize(RetTy);
if (Size <= 128) {
// On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
// same size and alignment.
@@ -4967,7 +5094,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.
@@ -4995,6 +5122,17 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
return false;
}
+bool AArch64ABIInfo::isLegalVectorTypeForSwift(CharUnits totalSize,
+ llvm::Type *eltTy,
+ unsigned elts) const {
+ if (!llvm::isPowerOf2_32(elts))
+ return false;
+ if (totalSize.getQuantity() != 8 &&
+ (totalSize.getQuantity() != 16 || elts == 1))
+ return false;
+ return true;
+}
+
bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
// Homogeneous aggregates for AAPCS64 must have base types of a floating
// point type or a short-vector type. This is the same as the 32-bit ABI,
@@ -5305,6 +5443,14 @@ Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty,
TyInfo, SlotSize, /*AllowHigherAlign*/ true);
}
+Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const {
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
+ CGF.getContext().getTypeInfoInChars(Ty),
+ CharUnits::fromQuantity(8),
+ /*allowHigherAlign*/ false);
+}
+
//===----------------------------------------------------------------------===//
// ARM ABI Implementation
//===----------------------------------------------------------------------===//
@@ -5383,6 +5529,8 @@ private:
bool isSwiftErrorInRegister() const override {
return true;
}
+ bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
+ unsigned elts) const override;
};
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -5399,7 +5547,7 @@ public:
}
StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
- return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
+ return "mov\tr7, r7\t\t// marker for objc_retainAutoreleaseReturnValue";
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
@@ -5417,7 +5565,10 @@ public:
}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override {
+ if (!IsForDefinition)
+ return;
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD)
return;
@@ -5449,10 +5600,7 @@ public:
// the backend to perform a realignment as part of the function prologue.
llvm::AttrBuilder B;
B.addStackAlignmentAttr(8);
- Fn->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- B));
+ Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
}
};
@@ -5462,7 +5610,8 @@ public:
: ARMTargetCodeGenInfo(CGT, K) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override;
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override;
void getDependentLibraryOption(llvm::StringRef Lib,
llvm::SmallString<24> &Opt) const override {
@@ -5476,8 +5625,11 @@ public:
};
void WindowsARMTargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
- ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const {
+ ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM, IsForDefinition);
+ if (!IsForDefinition)
+ return;
addStackProbeSizeTargetAttribute(D, GV, CGM);
}
}
@@ -5534,17 +5686,14 @@ void ARMABIInfo::setCCs() {
// AAPCS apparently requires runtime support functions to be soft-float, but
// that's almost certainly for historic reasons (Thumb1 not supporting VFP
// most likely). It's more convenient for AAPCS16_VFP to be hard-float.
- switch (getABIKind()) {
- case APCS:
- case AAPCS16_VFP:
- if (abiCC != getLLVMDefaultCC())
+
+ // The Run-time ABI for the ARM Architecture section 4.1.2 requires
+ // AEABI-complying FP helper functions to use the base AAPCS.
+ // These AEABI functions are expanded in the ARM llvm backend, all the builtin
+ // support functions emitted by clang such as the _Complex helpers follow the
+ // abiCC.
+ if (abiCC != getLLVMDefaultCC())
BuiltinCC = abiCC;
- break;
- case AAPCS:
- case AAPCS_VFP:
- BuiltinCC = llvm::CallingConv::ARM_AAPCS;
- break;
- }
}
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
@@ -5898,6 +6047,20 @@ bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
return false;
}
+bool ARMABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize,
+ llvm::Type *eltTy,
+ unsigned numElts) const {
+ if (!llvm::isPowerOf2_32(numElts))
+ return false;
+ unsigned size = getDataLayout().getTypeStoreSizeInBits(eltTy);
+ if (size > 64)
+ return false;
+ if (vectorSize.getQuantity() != 8 &&
+ (vectorSize.getQuantity() != 16 || numElts == 1))
+ return false;
+ return true;
+}
+
bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
// Homogeneous aggregates for AAPCS-VFP must have base types of float,
// double, or 64-bit or 128-bit vectors.
@@ -5992,7 +6155,9 @@ public:
: TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
+ CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const override;
+
private:
// Adds a NamedMDNode with F, Name, and Operand as operands, and adds the
// resulting MDNode to the nvvm.annotations MDNode.
@@ -6046,9 +6211,11 @@ Address NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
llvm_unreachable("NVPTX does not support varargs");
}
-void NVPTXTargetCodeGenInfo::
-setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const{
+void NVPTXTargetCodeGenInfo::setTargetAttributes(
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const {
+ if (!IsForDefinition)
+ return;
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD) return;
@@ -6484,14 +6651,17 @@ public:
MSP430TargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
+ CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const override;
};
}
-void MSP430TargetCodeGenInfo::setTargetAttributes(const Decl *D,
- llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const {
+void MSP430TargetCodeGenInfo::setTargetAttributes(
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const {
+ if (!IsForDefinition)
+ return;
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
if (const MSP430InterruptAttr *attr = FD->getAttr<MSP430InterruptAttr>()) {
// Handle 'interrupt' attribute:
@@ -6550,10 +6720,21 @@ public:
}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override {
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD) return;
llvm::Function *Fn = cast<llvm::Function>(GV);
+
+ if (FD->hasAttr<MipsLongCallAttr>())
+ Fn->addFnAttr("long-call");
+ else if (FD->hasAttr<MipsShortCallAttr>())
+ Fn->addFnAttr("short-call");
+
+ // Other attributes do not have a meaning for declarations.
+ if (!IsForDefinition)
+ return;
+
if (FD->hasAttr<Mips16Attr>()) {
Fn->addFnAttr("mips16");
}
@@ -6561,6 +6742,11 @@ public:
Fn->addFnAttr("nomips16");
}
+ if (FD->hasAttr<MicroMipsAttr>())
+ Fn->addFnAttr("micromips");
+ else if (FD->hasAttr<NoMicroMipsAttr>())
+ Fn->addFnAttr("nomicromips");
+
const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>();
if (!Attr)
return;
@@ -6910,7 +7096,10 @@ public:
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) { }
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const override {
+ CodeGen::CodeGenModule &CGM,
+ ForDefinition_t IsForDefinition) const override {
+ if (!IsForDefinition)
+ return;
const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD) return;
auto *Fn = cast<llvm::Function>(GV);
@@ -6938,11 +7127,15 @@ public:
: DefaultTargetCodeGenInfo(CGT) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
+ CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const override;
};
void TCETargetCodeGenInfo::setTargetAttributes(
- const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const {
+ if (!IsForDefinition)
+ return;
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD) return;
@@ -7038,13 +7231,13 @@ ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
+
// Ignore empty records.
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
uint64_t Size = getContext().getTypeSize(Ty);
if (Size > 64)
return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
@@ -7238,38 +7431,138 @@ public:
namespace {
class AMDGPUABIInfo final : public DefaultABIInfo {
+private:
+ static const unsigned MaxNumRegsForArgsRet = 16;
+
+ unsigned numRegsForType(QualType Ty) const;
+
+ bool isHomogeneousAggregateBaseType(QualType Ty) const override;
+ bool isHomogeneousAggregateSmallEnough(const Type *Base,
+ uint64_t Members) const override;
+
public:
- explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+ explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) :
+ DefaultABIInfo(CGT) {}
-private:
- ABIArgInfo classifyArgumentType(QualType Ty) const;
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyKernelArgumentType(QualType Ty) const;
+ ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const;
void computeInfo(CGFunctionInfo &FI) const override;
};
+bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
+ return true;
+}
+
+bool AMDGPUABIInfo::isHomogeneousAggregateSmallEnough(
+ const Type *Base, uint64_t Members) const {
+ uint32_t NumRegs = (getContext().getTypeSize(Base) + 31) / 32;
+
+ // Homogeneous Aggregates may occupy at most 16 registers.
+ return Members * NumRegs <= MaxNumRegsForArgsRet;
+}
+
+/// Estimate number of registers the type will use when passed in registers.
+unsigned AMDGPUABIInfo::numRegsForType(QualType Ty) const {
+ unsigned NumRegs = 0;
+
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ // Compute from the number of elements. The reported size is based on the
+ // in-memory size, which includes the padding 4th element for 3-vectors.
+ QualType EltTy = VT->getElementType();
+ unsigned EltSize = getContext().getTypeSize(EltTy);
+
+ // 16-bit element vectors should be passed as packed.
+ if (EltSize == 16)
+ return (VT->getNumElements() + 1) / 2;
+
+ unsigned EltNumRegs = (EltSize + 31) / 32;
+ return EltNumRegs * VT->getNumElements();
+ }
+
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ assert(!RD->hasFlexibleArrayMember());
+
+ for (const FieldDecl *Field : RD->fields()) {
+ QualType FieldTy = Field->getType();
+ NumRegs += numRegsForType(FieldTy);
+ }
+
+ return NumRegs;
+ }
+
+ return (getContext().getTypeSize(Ty) + 31) / 32;
+}
+
void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ llvm::CallingConv::ID CC = FI.getCallingConvention();
+
if (!getCXXABI().classifyReturnType(FI))
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- unsigned CC = FI.getCallingConvention();
- for (auto &Arg : FI.arguments())
- if (CC == llvm::CallingConv::AMDGPU_KERNEL)
- Arg.info = classifyArgumentType(Arg.type);
- else
- Arg.info = DefaultABIInfo::classifyArgumentType(Arg.type);
+ unsigned NumRegsLeft = MaxNumRegsForArgsRet;
+ for (auto &Arg : FI.arguments()) {
+ if (CC == llvm::CallingConv::AMDGPU_KERNEL) {
+ Arg.info = classifyKernelArgumentType(Arg.type);
+ } else {
+ Arg.info = classifyArgumentType(Arg.type, NumRegsLeft);
+ }
+ }
}
-/// \brief Classify argument of given type \p Ty.
-ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty) const {
- llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
- if (!StrTy) {
- return DefaultABIInfo::classifyArgumentType(Ty);
+ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const {
+ if (isAggregateTypeForABI(RetTy)) {
+ // Records with non-trivial destructors/copy-constructors should not be
+ // returned by value.
+ if (!getRecordArgABI(RetTy, getCXXABI())) {
+ // Ignore empty structs/unions.
+ if (isEmptyRecord(getContext(), RetTy, true))
+ return ABIArgInfo::getIgnore();
+
+ // Lower single-element structs to just return a regular value.
+ if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext()))
+ return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
+
+ if (const RecordType *RT = RetTy->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return DefaultABIInfo::classifyReturnType(RetTy);
+ }
+
+ // Pack aggregates <= 4 bytes into single VGPR or pair.
+ uint64_t Size = getContext().getTypeSize(RetTy);
+ if (Size <= 16)
+ return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
+
+ if (Size <= 32)
+ return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
+
+ if (Size <= 64) {
+ llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
+ return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
+ }
+
+ if (numRegsForType(RetTy) <= MaxNumRegsForArgsRet)
+ return ABIArgInfo::getDirect();
+ }
}
+ // Otherwise just do the default thing.
+ return DefaultABIInfo::classifyReturnType(RetTy);
+}
+
+/// For kernels all parameters are really passed in a special buffer. It doesn't
+/// make sense to pass anything byval, so everything must be direct.
+ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const {
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
+ // TODO: Can we omit empty structs?
+
// Coerce single element structs to its element.
- if (StrTy->getNumElements() == 1) {
- return ABIArgInfo::getDirect();
- }
+ if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+ return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
// If we set CanBeFlattened to true, CodeGen will expand the struct to its
// individual elements, which confuses the Clover OpenCL backend; therefore we
@@ -7277,34 +7570,116 @@ ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty) const {
return ABIArgInfo::getDirect(nullptr, 0, nullptr, false);
}
+ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty,
+ unsigned &NumRegsLeft) const {
+ assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow");
+
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
+ if (isAggregateTypeForABI(Ty)) {
+ // Records with non-trivial destructors/copy-constructors should not be
+ // passed by value.
+ if (auto RAA = getRecordArgABI(Ty, getCXXABI()))
+ return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
+
+ // Ignore empty structs/unions.
+ if (isEmptyRecord(getContext(), Ty, true))
+ return ABIArgInfo::getIgnore();
+
+ // Lower single-element structs to just pass a regular value. TODO: We
+ // could do reasonable-size multiple-element structs too, using getExpand(),
+ // though watch out for things like bitfields.
+ if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
+ return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
+
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return DefaultABIInfo::classifyArgumentType(Ty);
+ }
+
+ // Pack aggregates <= 8 bytes into single VGPR or pair.
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size <= 64) {
+ unsigned NumRegs = (Size + 31) / 32;
+ NumRegsLeft -= std::min(NumRegsLeft, NumRegs);
+
+ if (Size <= 16)
+ return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
+
+ if (Size <= 32)
+ return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
+
+ // XXX: Should this be i64 instead, and should the limit increase?
+ llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext());
+ return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2));
+ }
+
+ if (NumRegsLeft > 0) {
+ unsigned NumRegs = numRegsForType(Ty);
+ if (NumRegsLeft >= NumRegs) {
+ NumRegsLeft -= NumRegs;
+ return ABIArgInfo::getDirect();
+ }
+ }
+ }
+
+ // Otherwise just do the default thing.
+ ABIArgInfo ArgInfo = DefaultABIInfo::classifyArgumentType(Ty);
+ if (!ArgInfo.isIndirect()) {
+ unsigned NumRegs = numRegsForType(Ty);
+ NumRegsLeft -= std::min(NumRegs, NumRegsLeft);
+ }
+
+ return ArgInfo;
+}
+
class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo {
public:
AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new AMDGPUABIInfo(CGT)) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
+ CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const override;
unsigned getOpenCLKernelCallingConv() const override;
llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T, QualType QT) const override;
+
+ LangAS getASTAllocaAddressSpace() const override {
+ return getLangASFromTargetAS(
+ getABIInfo().getDataLayout().getAllocaAddrSpace());
+ }
+ LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const override;
+ llvm::SyncScope::ID getLLVMSyncScopeID(SyncScope S,
+ llvm::LLVMContext &C) const override;
+ llvm::Function *
+ createEnqueuedBlockKernel(CodeGenFunction &CGF,
+ llvm::Function *BlockInvokeFunc,
+ llvm::Value *BlockLiteral) const override;
};
}
-static void appendOpenCLVersionMD (CodeGen::CodeGenModule &CGM);
-
void AMDGPUTargetCodeGenInfo::setTargetAttributes(
- const Decl *D,
- llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const {
+ const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const {
+ if (!IsForDefinition)
+ return;
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD)
return;
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");
@@ -7343,8 +7718,6 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
if (NumVGPR != 0)
F->addFnAttr("amdgpu-num-vgpr", llvm::utostr(NumVGPR));
}
-
- appendOpenCLVersionMD(M);
}
unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
@@ -7369,6 +7742,49 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer(
llvm::ConstantPointerNull::get(NPT), PT);
}
+LangAS
+AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const {
+ assert(!CGM.getLangOpts().OpenCL &&
+ !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
+ "Address space agnostic languages only");
+ LangAS DefaultGlobalAS = getLangASFromTargetAS(
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_global));
+ if (!D)
+ return DefaultGlobalAS;
+
+ LangAS AddrSpace = D->getType().getAddressSpace();
+ assert(AddrSpace == LangAS::Default || isTargetAddressSpace(AddrSpace));
+ if (AddrSpace != LangAS::Default)
+ return AddrSpace;
+
+ if (CGM.isTypeConstant(D->getType(), false)) {
+ if (auto ConstAS = CGM.getTarget().getConstantAddressSpace())
+ return ConstAS.getValue();
+ }
+ return DefaultGlobalAS;
+}
+
+llvm::SyncScope::ID
+AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(SyncScope S,
+ llvm::LLVMContext &C) const {
+ StringRef Name;
+ switch (S) {
+ case SyncScope::OpenCLWorkGroup:
+ Name = "workgroup";
+ break;
+ case SyncScope::OpenCLDevice:
+ Name = "agent";
+ break;
+ case SyncScope::OpenCLAllSVMDevices:
+ Name = "";
+ break;
+ case SyncScope::OpenCLSubGroup:
+ Name = "subgroup";
+ }
+ return C.getOrInsertSyncScopeID(Name);
+}
+
//===----------------------------------------------------------------------===//
// SPARC v8 ABI Implementation.
// Based on the SPARC Compliance Definition version 2.4.1.
@@ -8015,45 +8431,18 @@ class SPIRTargetCodeGenInfo : public TargetCodeGenInfo {
public:
SPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
- void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
unsigned getOpenCLKernelCallingConv() const override;
};
+
} // End anonymous namespace.
-/// Emit SPIR specific metadata: OpenCL and SPIR version.
-void SPIRTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
- llvm::LLVMContext &Ctx = CGM.getModule().getContext();
- llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx);
- llvm::Module &M = CGM.getModule();
- // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the
- // opencl.spir.version named metadata.
- llvm::Metadata *SPIRVerElts[] = {
- llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, (CGM.getLangOpts().OpenCLVersion / 100 > 1) ? 0 : 2))};
- llvm::NamedMDNode *SPIRVerMD =
- M.getOrInsertNamedMetadata("opencl.spir.version");
- SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts));
- appendOpenCLVersionMD(CGM);
-}
-
-static void appendOpenCLVersionMD(CodeGen::CodeGenModule &CGM) {
- llvm::LLVMContext &Ctx = CGM.getModule().getContext();
- llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx);
- llvm::Module &M = CGM.getModule();
- // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
- // opencl.ocl.version named metadata node.
- llvm::Metadata *OCLVerElts[] = {
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, (CGM.getLangOpts().OpenCLVersion % 100) / 10))};
- llvm::NamedMDNode *OCLVerMD =
- M.getOrInsertNamedMetadata("opencl.ocl.version");
- OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
+namespace clang {
+namespace CodeGen {
+void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) {
+ DefaultABIInfo SPIRABI(CGM.getTypes());
+ SPIRABI.computeInfo(FI);
+}
+}
}
unsigned SPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
@@ -8435,6 +8824,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS;
if (getTarget().getABI() == "darwinpcs")
Kind = AArch64ABIInfo::DarwinPCS;
+ else if (Triple.isOSWindows())
+ return SetCGInfo(
+ new WindowsAArch64TargetCodeGenInfo(Types, AArch64ABIInfo::Win64));
return SetCGInfo(new AArch64TargetCodeGenInfo(Types, Kind));
}
@@ -8564,3 +8956,108 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return SetCGInfo(new SPIRTargetCodeGenInfo(Types));
}
}
+
+/// Create an OpenCL kernel for an enqueued block.
+///
+/// The kernel has the same function type as the block invoke function. Its
+/// name is the name of the block invoke function postfixed with "_kernel".
+/// It simply calls the block invoke function then returns.
+llvm::Function *
+TargetCodeGenInfo::createEnqueuedBlockKernel(CodeGenFunction &CGF,
+ llvm::Function *Invoke,
+ llvm::Value *BlockLiteral) const {
+ auto *InvokeFT = Invoke->getFunctionType();
+ llvm::SmallVector<llvm::Type *, 2> ArgTys;
+ for (auto &P : InvokeFT->params())
+ ArgTys.push_back(P);
+ auto &C = CGF.getLLVMContext();
+ std::string Name = Invoke->getName().str() + "_kernel";
+ auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false);
+ auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name,
+ &CGF.CGM.getModule());
+ auto IP = CGF.Builder.saveIP();
+ auto *BB = llvm::BasicBlock::Create(C, "entry", F);
+ auto &Builder = CGF.Builder;
+ Builder.SetInsertPoint(BB);
+ llvm::SmallVector<llvm::Value *, 2> Args;
+ for (auto &A : F->args())
+ Args.push_back(&A);
+ Builder.CreateCall(Invoke, Args);
+ Builder.CreateRetVoid();
+ Builder.restoreIP(IP);
+ return F;
+}
+
+/// Create an OpenCL kernel for an enqueued block.
+///
+/// The type of the first argument (the block literal) is the struct type
+/// of the block literal instead of a pointer type. The first argument
+/// (block literal) is passed directly by value to the kernel. The kernel
+/// allocates the same type of struct on stack and stores the block literal
+/// to it and passes its pointer to the block invoke function. The kernel
+/// has "enqueued-block" function attribute and kernel argument metadata.
+llvm::Function *AMDGPUTargetCodeGenInfo::createEnqueuedBlockKernel(
+ CodeGenFunction &CGF, llvm::Function *Invoke,
+ llvm::Value *BlockLiteral) const {
+ auto &Builder = CGF.Builder;
+ auto &C = CGF.getLLVMContext();
+
+ auto *BlockTy = BlockLiteral->getType()->getPointerElementType();
+ auto *InvokeFT = Invoke->getFunctionType();
+ llvm::SmallVector<llvm::Type *, 2> ArgTys;
+ llvm::SmallVector<llvm::Metadata *, 8> AddressQuals;
+ llvm::SmallVector<llvm::Metadata *, 8> AccessQuals;
+ llvm::SmallVector<llvm::Metadata *, 8> ArgTypeNames;
+ llvm::SmallVector<llvm::Metadata *, 8> ArgBaseTypeNames;
+ llvm::SmallVector<llvm::Metadata *, 8> ArgTypeQuals;
+ llvm::SmallVector<llvm::Metadata *, 8> ArgNames;
+
+ ArgTys.push_back(BlockTy);
+ ArgTypeNames.push_back(llvm::MDString::get(C, "__block_literal"));
+ AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(0)));
+ ArgBaseTypeNames.push_back(llvm::MDString::get(C, "__block_literal"));
+ ArgTypeQuals.push_back(llvm::MDString::get(C, ""));
+ AccessQuals.push_back(llvm::MDString::get(C, "none"));
+ ArgNames.push_back(llvm::MDString::get(C, "block_literal"));
+ for (unsigned I = 1, E = InvokeFT->getNumParams(); I < E; ++I) {
+ ArgTys.push_back(InvokeFT->getParamType(I));
+ ArgTypeNames.push_back(llvm::MDString::get(C, "void*"));
+ AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(3)));
+ AccessQuals.push_back(llvm::MDString::get(C, "none"));
+ ArgBaseTypeNames.push_back(llvm::MDString::get(C, "void*"));
+ ArgTypeQuals.push_back(llvm::MDString::get(C, ""));
+ ArgNames.push_back(
+ llvm::MDString::get(C, (Twine("local_arg") + Twine(I)).str()));
+ }
+ std::string Name = Invoke->getName().str() + "_kernel";
+ auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false);
+ auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name,
+ &CGF.CGM.getModule());
+ F->addFnAttr("enqueued-block");
+ auto IP = CGF.Builder.saveIP();
+ auto *BB = llvm::BasicBlock::Create(C, "entry", F);
+ Builder.SetInsertPoint(BB);
+ unsigned BlockAlign = CGF.CGM.getDataLayout().getPrefTypeAlignment(BlockTy);
+ auto *BlockPtr = Builder.CreateAlloca(BlockTy, nullptr);
+ BlockPtr->setAlignment(BlockAlign);
+ Builder.CreateAlignedStore(F->arg_begin(), BlockPtr, BlockAlign);
+ auto *Cast = Builder.CreatePointerCast(BlockPtr, InvokeFT->getParamType(0));
+ llvm::SmallVector<llvm::Value *, 2> Args;
+ Args.push_back(Cast);
+ for (auto I = F->arg_begin() + 1, E = F->arg_end(); I != E; ++I)
+ Args.push_back(I);
+ Builder.CreateCall(Invoke, Args);
+ Builder.CreateRetVoid();
+ Builder.restoreIP(IP);
+
+ F->setMetadata("kernel_arg_addr_space", llvm::MDNode::get(C, AddressQuals));
+ F->setMetadata("kernel_arg_access_qual", llvm::MDNode::get(C, AccessQuals));
+ F->setMetadata("kernel_arg_type", llvm::MDNode::get(C, ArgTypeNames));
+ F->setMetadata("kernel_arg_base_type",
+ llvm::MDNode::get(C, ArgBaseTypeNames));
+ F->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(C, ArgTypeQuals));
+ if (CGF.CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
+ F->setMetadata("kernel_arg_name", llvm::MDNode::get(C, ArgNames));
+
+ return F;
+}
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 223d6d047a..d745e420c4 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -15,9 +15,11 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
#define LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
+#include "CodeGenModule.h"
#include "CGValue.h"
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SyncScope.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
@@ -34,8 +36,8 @@ class Decl;
namespace CodeGen {
class ABIInfo;
class CallArgList;
-class CodeGenModule;
class CodeGenFunction;
+class CGBlockInfo;
class CGFunctionInfo;
/// TargetCodeGenInfo - This class organizes various target-specific
@@ -55,7 +57,8 @@ public:
/// setTargetAttributes - Provides a convenient hook to handle extra
/// target-specific attributes for the given global.
virtual void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const {}
+ CodeGen::CodeGenModule &M,
+ ForDefinition_t IsForDefinition) const {}
/// emitTargetMD - Provides a convenient hook to handle extra
/// target-specific metadata for the given global.
@@ -229,13 +232,71 @@ public:
virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T, QualType QT) const;
+ /// Get target favored AST address space of a global variable for languages
+ /// other than OpenCL and CUDA.
+ /// If \p D is nullptr, returns the default target favored address space
+ /// for global variable.
+ virtual LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const;
+
+ /// Get the AST address space for alloca.
+ virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; }
+
/// Perform address space cast of an expression of pointer type.
/// \param V is the LLVM value to be casted to another address space.
- /// \param SrcTy is the QualType of \p V.
- /// \param DestTy is the destination QualType.
+ /// \param SrcAddr is the language address space of \p V.
+ /// \param DestAddr is the targeted language address space.
+ /// \param DestTy is the destination LLVM pointer type.
+ /// \param IsNonNull is the flag indicating \p V is known to be non null.
virtual llvm::Value *performAddrSpaceCast(CodeGen::CodeGenFunction &CGF,
- llvm::Value *V, QualType SrcTy, QualType DestTy) const;
+ llvm::Value *V, LangAS SrcAddr,
+ LangAS DestAddr, llvm::Type *DestTy,
+ bool IsNonNull = false) const;
+
+ /// Perform address space cast of a constant expression of pointer type.
+ /// \param V is the LLVM constant to be casted to another address space.
+ /// \param SrcAddr is the language address space of \p V.
+ /// \param DestAddr is the targeted language address space.
+ /// \param DestTy is the destination LLVM pointer type.
+ virtual llvm::Constant *performAddrSpaceCast(CodeGenModule &CGM,
+ llvm::Constant *V,
+ LangAS SrcAddr, LangAS DestAddr,
+ llvm::Type *DestTy) const;
+
+ /// Get the syncscope used in LLVM IR.
+ virtual llvm::SyncScope::ID getLLVMSyncScopeID(SyncScope S,
+ llvm::LLVMContext &C) const;
+
+ /// Inteface class for filling custom fields of a block literal for OpenCL.
+ class TargetOpenCLBlockHelper {
+ public:
+ typedef std::pair<llvm::Value *, StringRef> ValueTy;
+ TargetOpenCLBlockHelper() {}
+ virtual ~TargetOpenCLBlockHelper() {}
+ /// Get the custom field types for OpenCL blocks.
+ virtual llvm::SmallVector<llvm::Type *, 1> getCustomFieldTypes() = 0;
+ /// Get the custom field values for OpenCL blocks.
+ virtual llvm::SmallVector<ValueTy, 1>
+ getCustomFieldValues(CodeGenFunction &CGF, const CGBlockInfo &Info) = 0;
+ virtual bool areAllCustomFieldValuesConstant(const CGBlockInfo &Info) = 0;
+ /// Get the custom field values for OpenCL blocks if all values are LLVM
+ /// constants.
+ virtual llvm::SmallVector<llvm::Constant *, 1>
+ getCustomFieldValues(CodeGenModule &CGM, const CGBlockInfo &Info) = 0;
+ };
+ virtual TargetOpenCLBlockHelper *getTargetOpenCLBlockHelper() const {
+ return nullptr;
+ }
+ /// Create an OpenCL kernel for an enqueued block. The kernel function is
+ /// a wrapper for the block invoke function with target-specific calling
+ /// convention and ABI as an OpenCL kernel. The wrapper function accepts
+ /// block context and block arguments in target-specific way and calls
+ /// the original block invoke function.
+ virtual llvm::Function *
+ createEnqueuedBlockKernel(CodeGenFunction &CGF,
+ llvm::Function *BlockInvokeFunc,
+ llvm::Value *BlockLiteral) const;
};
} // namespace CodeGen
diff --git a/lib/CrossTU/CMakeLists.txt b/lib/CrossTU/CMakeLists.txt
new file mode 100644
index 0000000000..632b5072ad
--- /dev/null
+++ b/lib/CrossTU/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(clangCrossTU
+ CrossTranslationUnit.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangFrontend
+ clangIndex
+ )
diff --git a/lib/CrossTU/CrossTranslationUnit.cpp b/lib/CrossTU/CrossTranslationUnit.cpp
new file mode 100644
index 0000000000..e20ea77022
--- /dev/null
+++ b/lib/CrossTU/CrossTranslationUnit.cpp
@@ -0,0 +1,269 @@
+//===--- CrossTranslationUnit.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 implements the CrossTranslationUnit interface.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CrossTU/CrossTUDiagnostic.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+#include <sstream>
+
+namespace clang {
+namespace cross_tu {
+
+namespace {
+// FIXME: This class is will be removed after the transition to llvm::Error.
+class IndexErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "clang.index"; }
+
+ std::string message(int Condition) const override {
+ switch (static_cast<index_error_code>(Condition)) {
+ case index_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case index_error_code::missing_index_file:
+ return "The index file is missing.";
+ case index_error_code::invalid_index_format:
+ return "Invalid index file format.";
+ case index_error_code::multiple_definitions:
+ return "Multiple definitions in the index file.";
+ case index_error_code::missing_definition:
+ return "Missing definition from the index file.";
+ case index_error_code::failed_import:
+ return "Failed to import the definition.";
+ case index_error_code::failed_to_get_external_ast:
+ return "Failed to load external AST source.";
+ case index_error_code::failed_to_generate_usr:
+ return "Failed to generate USR.";
+ }
+ llvm_unreachable("Unrecognized index_error_code.");
+ }
+};
+
+static llvm::ManagedStatic<IndexErrorCategory> Category;
+} // end anonymous namespace
+
+char IndexError::ID;
+
+void IndexError::log(raw_ostream &OS) const {
+ OS << Category->message(static_cast<int>(Code)) << '\n';
+}
+
+std::error_code IndexError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(Code), *Category);
+}
+
+llvm::Expected<llvm::StringMap<std::string>>
+parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) {
+ std::ifstream ExternalFnMapFile(IndexPath);
+ if (!ExternalFnMapFile)
+ return llvm::make_error<IndexError>(index_error_code::missing_index_file,
+ IndexPath.str());
+
+ llvm::StringMap<std::string> Result;
+ std::string Line;
+ unsigned LineNo = 1;
+ while (std::getline(ExternalFnMapFile, Line)) {
+ const size_t Pos = Line.find(" ");
+ if (Pos > 0 && Pos != std::string::npos) {
+ StringRef LineRef{Line};
+ StringRef FunctionLookupName = LineRef.substr(0, Pos);
+ if (Result.count(FunctionLookupName))
+ return llvm::make_error<IndexError>(
+ index_error_code::multiple_definitions, IndexPath.str(), LineNo);
+ StringRef FileName = LineRef.substr(Pos + 1);
+ SmallString<256> FilePath = CrossTUDir;
+ llvm::sys::path::append(FilePath, FileName);
+ Result[FunctionLookupName] = FilePath.str().str();
+ } else
+ return llvm::make_error<IndexError>(
+ index_error_code::invalid_index_format, IndexPath.str(), LineNo);
+ LineNo++;
+ }
+ return Result;
+}
+
+std::string
+createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
+ std::ostringstream Result;
+ for (const auto &E : Index)
+ Result << E.getKey().str() << " " << E.getValue() << '\n';
+ return Result.str();
+}
+
+CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
+ : CI(CI), Context(CI.getASTContext()) {}
+
+CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
+
+std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
+ SmallString<128> DeclUSR;
+ bool Ret = index::generateUSRForDecl(ND, DeclUSR); (void)Ret;
+ assert(!Ret && "Unable to generate USR");
+ return DeclUSR.str();
+}
+
+/// Recursively visits the function decls of a DeclContext, and looks up a
+/// function based on USRs.
+const FunctionDecl *
+CrossTranslationUnitContext::findFunctionInDeclContext(const DeclContext *DC,
+ StringRef LookupFnName) {
+ assert(DC && "Declaration Context must not be null");
+ for (const Decl *D : DC->decls()) {
+ const auto *SubDC = dyn_cast<DeclContext>(D);
+ if (SubDC)
+ if (const auto *FD = findFunctionInDeclContext(SubDC, LookupFnName))
+ return FD;
+
+ const auto *ND = dyn_cast<FunctionDecl>(D);
+ const FunctionDecl *ResultDecl;
+ if (!ND || !ND->hasBody(ResultDecl))
+ continue;
+ if (getLookupName(ResultDecl) != LookupFnName)
+ continue;
+ return ResultDecl;
+ }
+ return nullptr;
+}
+
+llvm::Expected<const FunctionDecl *>
+CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
+ StringRef CrossTUDir,
+ StringRef IndexName) {
+ assert(!FD->hasBody() && "FD has a definition in current translation unit!");
+ const std::string LookupFnName = getLookupName(FD);
+ if (LookupFnName.empty())
+ return llvm::make_error<IndexError>(
+ index_error_code::failed_to_generate_usr);
+ llvm::Expected<ASTUnit *> ASTUnitOrError =
+ loadExternalAST(LookupFnName, CrossTUDir, IndexName);
+ if (!ASTUnitOrError)
+ return ASTUnitOrError.takeError();
+ ASTUnit *Unit = *ASTUnitOrError;
+ if (!Unit)
+ return llvm::make_error<IndexError>(
+ index_error_code::failed_to_get_external_ast);
+ assert(&Unit->getFileManager() ==
+ &Unit->getASTContext().getSourceManager().getFileManager());
+
+ TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
+ if (const FunctionDecl *ResultDecl =
+ findFunctionInDeclContext(TU, LookupFnName))
+ return importDefinition(ResultDecl);
+ return llvm::make_error<IndexError>(index_error_code::failed_import);
+}
+
+void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
+ switch (IE.getCode()) {
+ case index_error_code::missing_index_file:
+ Context.getDiagnostics().Report(diag::err_fe_error_opening)
+ << IE.getFileName() << "required by the CrossTU functionality";
+ break;
+ case index_error_code::invalid_index_format:
+ Context.getDiagnostics().Report(diag::err_fnmap_parsing)
+ << IE.getFileName() << IE.getLineNum();
+ break;
+ case index_error_code::multiple_definitions:
+ Context.getDiagnostics().Report(diag::err_multiple_def_index)
+ << IE.getLineNum();
+ break;
+ default:
+ break;
+ }
+}
+
+llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
+ StringRef LookupName, StringRef CrossTUDir, StringRef IndexName) {
+ // FIXME: The current implementation only supports loading functions with
+ // a lookup name from a single translation unit. If multiple
+ // translation units contains functions with the same lookup name an
+ // error will be returned.
+ ASTUnit *Unit = nullptr;
+ auto FnUnitCacheEntry = FunctionASTUnitMap.find(LookupName);
+ if (FnUnitCacheEntry == FunctionASTUnitMap.end()) {
+ if (FunctionFileMap.empty()) {
+ SmallString<256> IndexFile = CrossTUDir;
+ if (llvm::sys::path::is_absolute(IndexName))
+ IndexFile = IndexName;
+ else
+ llvm::sys::path::append(IndexFile, IndexName);
+ llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
+ parseCrossTUIndex(IndexFile, CrossTUDir);
+ if (IndexOrErr)
+ FunctionFileMap = *IndexOrErr;
+ else
+ return IndexOrErr.takeError();
+ }
+
+ auto It = FunctionFileMap.find(LookupName);
+ if (It == FunctionFileMap.end())
+ return llvm::make_error<IndexError>(index_error_code::missing_definition);
+ StringRef ASTFileName = It->second;
+ auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName);
+ if (ASTCacheEntry == FileASTUnitMap.end()) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter *DiagClient =
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+
+ std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile(
+ ASTFileName, CI.getPCHContainerOperations()->getRawReader(),
+ ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts()));
+ Unit = LoadedUnit.get();
+ FileASTUnitMap[ASTFileName] = std::move(LoadedUnit);
+ } else {
+ Unit = ASTCacheEntry->second.get();
+ }
+ FunctionASTUnitMap[LookupName] = Unit;
+ } else {
+ Unit = FnUnitCacheEntry->second;
+ }
+ return Unit;
+}
+
+llvm::Expected<const FunctionDecl *>
+CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
+ ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext());
+ auto *ToDecl =
+ cast<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD)));
+ assert(ToDecl->hasBody());
+ assert(FD->hasBody() && "Functions already imported should have body.");
+ return ToDecl;
+}
+
+ASTImporter &
+CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) {
+ auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
+ if (I != ASTUnitImporterMap.end())
+ return *I->second;
+ ASTImporter *NewImporter =
+ new ASTImporter(Context, Context.getSourceManager().getFileManager(),
+ From, From.getSourceManager().getFileManager(), false);
+ ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
+ return *NewImporter;
+}
+
+} // namespace cross_tu
+} // namespace clang
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 0d7a99766b..5bf91f2be9 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
+ BinaryFormat
Option
Support
)
@@ -27,9 +28,10 @@ add_clang_library(clangDriver
ToolChains/Arch/Sparc.cpp
ToolChains/Arch/SystemZ.cpp
ToolChains/Arch/X86.cpp
+ ToolChains/Ananas.cpp
ToolChains/AMDGPU.cpp
ToolChains/AVR.cpp
- ToolChains/Bitrig.cpp
+ ToolChains/BareMetal.cpp
ToolChains/Clang.cpp
ToolChains/CloudABI.cpp
ToolChains/CommonArgs.cpp
@@ -58,6 +60,7 @@ add_clang_library(clangDriver
ToolChains/WebAssembly.cpp
ToolChains/XCore.cpp
Types.cpp
+ XRayArgs.cpp
DEPENDS
ClangDriverOptions
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 5c13e59a0d..c27ea51fa6 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -23,11 +23,12 @@ using namespace clang;
using namespace llvm::opt;
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
- InputArgList *_Args, DerivedArgList *_TranslatedArgs)
+ InputArgList *_Args, DerivedArgList *_TranslatedArgs,
+ bool ContainsError)
: TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u),
- Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
- ForDiagnostics(false) {
- // The offloading host toolchain is the default tool chain.
+ Args(_Args), TranslatedArgs(_TranslatedArgs), ForDiagnostics(false),
+ ContainsError(ContainsError) {
+ // The offloading host toolchain is the default toolchain.
OrderedOffloadingToolchains.insert(
std::make_pair(Action::OFK_Host, &DefaultToolChain));
}
@@ -40,14 +41,6 @@ Compilation::~Compilation() {
for (auto Arg : TCArgs)
if (Arg.second != TranslatedArgs)
delete Arg.second;
-
- // Free redirections of stdout/stderr.
- if (Redirects) {
- delete Redirects[0];
- delete Redirects[1];
- delete Redirects[2];
- delete [] Redirects;
- }
}
const DerivedArgList &
@@ -58,9 +51,32 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
if (!Entry) {
- Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
- if (!Entry)
- Entry = TranslatedArgs;
+ SmallVector<Arg *, 4> AllocatedArgs;
+ DerivedArgList *OpenMPArgs = nullptr;
+ // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
+ if (DeviceOffloadKind == Action::OFK_OpenMP) {
+ const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
+ bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
+ OpenMPArgs = TC->TranslateOpenMPTargetArgs(
+ *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
+ }
+
+ if (!OpenMPArgs) {
+ Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
+ if (!Entry)
+ Entry = TranslatedArgs;
+ } else {
+ Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind);
+ if (!Entry)
+ Entry = OpenMPArgs;
+ else
+ delete OpenMPArgs;
+ }
+
+ // Add allocated arguments to the final DAL.
+ for (auto ArgPtr : AllocatedArgs) {
+ Entry->AddSynthesizedArg(ArgPtr);
+ }
}
return *Entry;
@@ -204,16 +220,13 @@ void Compilation::initCompilationForDiagnostics() {
TranslatedArgs->ClaimAllArgs();
// Redirect stdout/stderr to /dev/null.
- Redirects = new const StringRef*[3]();
- Redirects[0] = nullptr;
- Redirects[1] = new StringRef();
- Redirects[2] = new StringRef();
+ Redirects = {None, {""}, {""}};
}
StringRef Compilation::getSysRoot() const {
return getDriver().SysRoot;
}
-void Compilation::Redirect(const StringRef** Redirects) {
+void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
this->Redirects = Redirects;
}
diff --git a/lib/Driver/Distro.cpp b/lib/Driver/Distro.cpp
index d305b17944..9a0b854e32 100644
--- a/lib/Driver/Distro.cpp
+++ b/lib/Driver/Distro.cpp
@@ -47,6 +47,8 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) {
.Case("xenial", Distro::UbuntuXenial)
.Case("yakkety", Distro::UbuntuYakkety)
.Case("zesty", Distro::UbuntuZesty)
+ .Case("artful", Distro::UbuntuArtful)
+ .Case("bionic", Distro::UbuntuBionic)
.Default(Distro::UnknownDistro);
if (Version != Distro::UnknownDistro)
return Version;
@@ -87,6 +89,8 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) {
return Distro::DebianJessie;
case 9:
return Distro::DebianStretch;
+ case 10:
+ return Distro::DebianBuster;
default:
return Distro::UnknownDistro;
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 1633082fb0..765b006e90 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -11,7 +11,7 @@
#include "InputInfo.h"
#include "ToolChains/AMDGPU.h"
#include "ToolChains/AVR.h"
-#include "ToolChains/Bitrig.h"
+#include "ToolChains/Ananas.h"
#include "ToolChains/Clang.h"
#include "ToolChains/CloudABI.h"
#include "ToolChains/Contiki.h"
@@ -22,6 +22,7 @@
#include "ToolChains/FreeBSD.h"
#include "ToolChains/Fuchsia.h"
#include "ToolChains/Gnu.h"
+#include "ToolChains/BareMetal.h"
#include "ToolChains/Haiku.h"
#include "ToolChains/Hexagon.h"
#include "ToolChains/Lanai.h"
@@ -67,6 +68,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <memory>
@@ -85,13 +87,13 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
: Opts(createDriverOptTable()), Diags(Diags), VFS(std::move(VFS)),
Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone),
LTOMode(LTOK_None), ClangExecutable(ClangExecutable),
- SysRoot(DEFAULT_SYSROOT), UseStdLib(true),
+ SysRoot(DEFAULT_SYSROOT),
DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr),
CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr),
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)
@@ -117,9 +119,8 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
void Driver::ParseDriverMode(StringRef ProgramName,
ArrayRef<const char *> Args) {
- auto Default = ToolChain::getTargetAndModeFromProgramName(ProgramName);
- StringRef DefaultMode(Default.second);
- setDriverModeFromOption(DefaultMode);
+ ClangNameParts = ToolChain::getTargetAndModeFromProgramName(ProgramName);
+ setDriverModeFromOption(ClangNameParts.DriverMode);
for (const char *ArgPtr : Args) {
// Ingore nullptrs, they are response file's EOL markers
@@ -150,8 +151,10 @@ void Driver::setDriverModeFromOption(StringRef Opt) {
Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
}
-InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
+InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
+ bool &ContainsError) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
+ ContainsError = false;
unsigned IncludedFlagsBitmask;
unsigned ExcludedFlagsBitmask;
@@ -164,27 +167,41 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
IncludedFlagsBitmask, ExcludedFlagsBitmask);
// Check for missing argument error.
- if (MissingArgCount)
- Diag(clang::diag::err_drv_missing_argument)
+ if (MissingArgCount) {
+ Diag(diag::err_drv_missing_argument)
<< Args.getArgString(MissingArgIndex) << MissingArgCount;
+ ContainsError |=
+ Diags.getDiagnosticLevel(diag::err_drv_missing_argument,
+ SourceLocation()) > DiagnosticsEngine::Warning;
+ }
// Check for unsupported options.
for (const Arg *A : Args) {
if (A->getOption().hasFlag(options::Unsupported)) {
- Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(Args);
+ Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args);
+ ContainsError |= Diags.getDiagnosticLevel(diag::err_drv_unsupported_opt,
+ SourceLocation()) >
+ DiagnosticsEngine::Warning;
continue;
}
// Warn about -mcpu= without an argument.
if (A->getOption().matches(options::OPT_mcpu_EQ) && A->containsValue("")) {
- Diag(clang::diag::warn_drv_empty_joined_argument) << A->getAsString(Args);
+ Diag(diag::warn_drv_empty_joined_argument) << A->getAsString(Args);
+ ContainsError |= Diags.getDiagnosticLevel(
+ diag::warn_drv_empty_joined_argument,
+ SourceLocation()) > DiagnosticsEngine::Warning;
}
}
- for (const Arg *A : Args.filtered(options::OPT_UNKNOWN))
- Diags.Report(IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl :
- diag::err_drv_unknown_argument)
- << A->getAsString(Args);
+ for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) {
+ auto ID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
+ : diag::err_drv_unknown_argument;
+
+ Diags.Report(ID) << A->getAsString(Args);
+ ContainsError |= Diags.getDiagnosticLevel(ID, SourceLocation()) >
+ DiagnosticsEngine::Warning;
+ }
return Args;
}
@@ -506,7 +523,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
auto &CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()];
if (!CudaTC) {
CudaTC = llvm::make_unique<toolchains::CudaToolChain>(
- *this, CudaTriple, *HostTC, C.getInputArgs());
+ *this, CudaTriple, *HostTC, C.getInputArgs(), Action::OFK_Cuda);
}
C.addOffloadDeviceToolChain(CudaTC.get(), Action::OFK_Cuda);
}
@@ -553,8 +570,22 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
if (TT.getArch() == llvm::Triple::UnknownArch)
Diag(clang::diag::err_drv_invalid_omp_target) << Val;
else {
- const ToolChain &TC = getToolChain(C.getInputArgs(), TT);
- C.addOffloadDeviceToolChain(&TC, Action::OFK_OpenMP);
+ const ToolChain *TC;
+ // CUDA toolchains have to be selected differently. They pair host
+ // and device in their implementation.
+ if (TT.isNVPTX()) {
+ const ToolChain *HostTC =
+ C.getSingleOffloadToolChain<Action::OFK_Host>();
+ assert(HostTC && "Host toolchain should be always defined.");
+ auto &CudaTC =
+ ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()];
+ if (!CudaTC)
+ CudaTC = llvm::make_unique<toolchains::CudaToolChain>(
+ *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP);
+ TC = CudaTC.get();
+ } else
+ TC = &getToolChain(C.getInputArgs(), TT);
+ C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP);
}
}
} else
@@ -597,7 +628,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintPhases;
- InputArgList Args = ParseArgStrings(ArgList.slice(1));
+ bool ContainsError;
+ InputArgList Args = ParseArgStrings(ArgList.slice(1), ContainsError);
// Silence driver warnings if requested
Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
@@ -620,6 +652,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()) {
@@ -628,6 +663,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
T.setOS(llvm::Triple::Win32);
T.setVendor(llvm::Triple::PC);
T.setEnvironment(llvm::Triple::MSVC);
+ T.setObjectFormat(llvm::Triple::COFF);
DefaultTargetTriple = T.str();
}
if (const Arg *A = Args.getLastArg(options::OPT_target))
@@ -642,8 +678,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
SysRoot = A->getValue();
if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ))
DyldPrefix = A->getValue();
- if (Args.hasArg(options::OPT_nostdlib))
- UseStdLib = false;
if (const Arg *A = Args.getLastArg(options::OPT_resource_dir))
ResourceDir = A->getValue();
@@ -684,7 +718,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
*UArgs, computeTargetTriple(*this, DefaultTargetTriple, *UArgs));
// The compilation takes ownership of Args.
- Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs);
+ Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
+ ContainsError);
if (!HandleImmediateArgs(*C))
return C;
@@ -1089,7 +1124,8 @@ void Driver::PrintHelp(bool ShowHidden) const {
ExcludedFlagsBitmask |= HelpHidden;
getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(),
- IncludedFlagsBitmask, ExcludedFlagsBitmask);
+ IncludedFlagsBitmask, ExcludedFlagsBitmask,
+ /*ShowAllAliases=*/false);
}
void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
@@ -1121,6 +1157,54 @@ static void PrintDiagnosticCategories(raw_ostream &OS) {
OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n';
}
+void Driver::handleAutocompletions(StringRef PassedFlags) const {
+ // Print out all options that start with a given argument. This is used for
+ // shell autocompletion.
+ std::vector<std::string> SuggestedCompletions;
+
+ unsigned short DisableFlags =
+ options::NoDriverOption | options::Unsupported | options::Ignored;
+ // We want to show cc1-only options only when clang is invoked as "clang
+ // -cc1". When clang is invoked as "clang -cc1", we add "#" to the beginning
+ // of an --autocomplete option so that the clang driver can distinguish
+ // whether it is requested to show cc1-only options or not.
+ if (PassedFlags.size() > 0 && PassedFlags[0] == '#') {
+ DisableFlags &= ~options::NoDriverOption;
+ PassedFlags = PassedFlags.substr(1);
+ }
+
+ if (PassedFlags.find(',') == StringRef::npos) {
+ // If the flag is in the form of "--autocomplete=-foo",
+ // we were requested to print out all option names that start with "-foo".
+ // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only".
+ SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags);
+
+ // We have to query the -W flags manually as they're not in the OptTable.
+ // TODO: Find a good way to add them to OptTable instead and them remove
+ // this code.
+ for (StringRef S : DiagnosticIDs::getDiagnosticFlags())
+ if (S.startswith(PassedFlags))
+ SuggestedCompletions.push_back(S);
+ } else {
+ // If the flag is in the form of "--autocomplete=foo,bar", we were
+ // requested to print out all option values for "-foo" that start with
+ // "bar". For example,
+ // "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++".
+ StringRef Option, Arg;
+ std::tie(Option, Arg) = PassedFlags.split(',');
+ SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg);
+ }
+
+ // Sort the autocomplete candidates so that shells print them out in a
+ // deterministic order. We could sort in any way, but we chose
+ // case-insensitive sorting for consistency with the -help option
+ // which prints out options in the case-insensitive alphabetical order.
+ std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(),
+ [](StringRef A, StringRef B) { return A.compare_lower(B) < 0; });
+
+ llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n';
+}
+
bool Driver::HandleImmediateArgs(const Compilation &C) {
// The order these options are handled in gcc is all over the place, but we
// don't expect inconsistencies w.r.t. that to matter in practice.
@@ -1169,6 +1253,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;
@@ -1208,8 +1297,16 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return false;
}
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) {
+ StringRef PassedFlags = A->getValue();
+ handleAutocompletions(PassedFlags);
+ return false;
+ }
+
if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) {
ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(C.getArgs());
+ const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(C.getArgs()));
+ RegisterEffectiveTriple TripleRAII(TC, Triple);
switch (RLT) {
case ToolChain::RLT_CompilerRT:
llvm::outs() << TC.getCompilerRT(C.getArgs(), "builtins") << "\n";
@@ -2649,6 +2746,8 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args,
OutputTy = Input->getType();
if (!Args.hasFlag(options::OPT_frewrite_includes,
options::OPT_fno_rewrite_includes, false) &&
+ !Args.hasFlag(options::OPT_frewrite_imports,
+ options::OPT_fno_rewrite_imports, false) &&
!CCGenDiagnostics)
OutputTy = types::getPreprocessedType(OutputTy);
assert(OutputTy != types::TY_INVALID &&
@@ -3133,6 +3232,12 @@ InputInfo Driver::BuildJobsForActionNoCache(
InputInfoList OffloadDependencesInputInfo;
bool BuildingForOffloadDevice = TargetDeviceOffloadKind != Action::OFK_None;
if (const OffloadAction *OA = dyn_cast<OffloadAction>(A)) {
+ // The 'Darwin' toolchain is initialized only when its arguments are
+ // computed. Get the default arguments for OFK_None to ensure that
+ // initialization is performed before processing the offload action.
+ // FIXME: Remove when darwin's toolchain is initialized during construction.
+ C.getArgsForToolChain(TC, BoundArch, Action::OFK_None);
+
// The offload action is expected to be used in four different situations.
//
// a) Set a toolchain/architecture/kind for a host action:
@@ -3310,7 +3415,7 @@ InputInfo Driver::BuildJobsForActionNoCache(
// Get the unique string identifier for this dependence and cache the
// result.
CachedResults[{A, GetTriplePlusArchString(
- UI.DependentToolChain, UI.DependentBoundArch,
+ UI.DependentToolChain, BoundArch,
UI.DependentOffloadKind)}] = CurI;
}
@@ -3585,7 +3690,12 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
return P.str();
}
- SmallString<128> P(ResourceDir);
+ SmallString<128> R(ResourceDir);
+ llvm::sys::path::append(R, Name);
+ if (llvm::sys::fs::exists(Twine(R)))
+ return R.str();
+
+ SmallString<128> P(TC.getCompilerRTPath());
llvm::sys::path::append(P, Name);
if (llvm::sys::fs::exists(Twine(P)))
return P.str();
@@ -3699,6 +3809,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Haiku:
TC = llvm::make_unique<toolchains::Haiku>(*this, Target, Args);
break;
+ case llvm::Triple::Ananas:
+ TC = llvm::make_unique<toolchains::Ananas>(*this, Target, Args);
+ break;
case llvm::Triple::CloudABI:
TC = llvm::make_unique<toolchains::CloudABI>(*this, Target, Args);
break;
@@ -3715,9 +3828,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::OpenBSD:
TC = llvm::make_unique<toolchains::OpenBSD>(*this, Target, Args);
break;
- case llvm::Triple::Bitrig:
- TC = llvm::make_unique<toolchains::Bitrig>(*this, Target, Args);
- break;
case llvm::Triple::NetBSD:
TC = llvm::make_unique<toolchains::NetBSD>(*this, Target, Args);
break;
@@ -3811,6 +3921,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
if (Target.getVendor() == llvm::Triple::Myriad)
TC = llvm::make_unique<toolchains::MyriadToolChain>(*this, Target,
Args);
+ else if (toolchains::BareMetal::handlesTarget(Target))
+ TC = llvm::make_unique<toolchains::BareMetal>(*this, Target, Args);
else if (Target.isOSBinFormatELF())
TC = llvm::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index 6a7410901d..11e7e4c8fe 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -11,6 +11,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
+#include <cassert>
using namespace clang::driver;
using namespace clang::driver::options;
@@ -21,10 +22,10 @@ using namespace llvm::opt;
#undef PREFIX
static const OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
- { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
- FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
#include "clang/Driver/Options.inc"
#undef OPTION
};
@@ -40,5 +41,13 @@ public:
}
std::unique_ptr<OptTable> clang::driver::createDriverOptTable() {
- return llvm::make_unique<DriverOptTable>();
+ auto Result = llvm::make_unique<DriverOptTable>();
+ // Options.inc is included in DriverOptions.cpp, and calls OptTable's
+ // addValues function.
+ // Opt is a variable used in the code fragment in Options.inc.
+ OptTable &Opt = *Result;
+#define OPTTABLE_ARG_INIT
+#include "clang/Driver/Options.inc"
+#undef OPTTABLE_ARG_INIT
+ return std::move(Result);
}
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 9fd8808af3..765c05752d 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -14,6 +14,7 @@
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
@@ -49,7 +50,7 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
// arguments. Therefore, we need to skip the flag and the next argument.
bool ShouldSkip = llvm::StringSwitch<bool>(Flag)
.Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true)
- .Cases("-o", "-coverage-file", "-dependency-file", true)
+ .Cases("-o", "-dependency-file", true)
.Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true)
.Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
.Default(false);
@@ -301,19 +302,33 @@ void Command::setResponseFile(const char *FileName) {
ResponseFileFlag += FileName;
}
-int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
- bool *ExecutionFailed) const {
+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(ArrayRef<llvm::Optional<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 +352,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);
}
@@ -364,8 +379,8 @@ static bool ShouldFallback(int ExitCode) {
return ExitCode != 0;
}
-int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
- bool *ExecutionFailed) const {
+int FallbackCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
+ std::string *ErrMsg, bool *ExecutionFailed) const {
int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
if (!ShouldFallback(PrimaryStatus))
return PrimaryStatus;
@@ -396,7 +411,7 @@ void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator,
OS << " || (exit 0)" << Terminator;
}
-int ForceSuccessCommand::Execute(const StringRef **Redirects,
+int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
std::string *ErrMsg,
bool *ExecutionFailed) const {
int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
diff --git a/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp
index 43b62f7b36..16a81603b3 100644
--- a/lib/Driver/Multilib.cpp
+++ b/lib/Driver/Multilib.cpp
@@ -80,6 +80,10 @@ Multilib &Multilib::includeSuffix(StringRef S) {
return *this;
}
+LLVM_DUMP_METHOD void Multilib::dump() const {
+ print(llvm::errs());
+}
+
void Multilib::print(raw_ostream &OS) const {
assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
if (GCCSuffix.empty())
@@ -270,6 +274,10 @@ bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const {
return false;
}
+LLVM_DUMP_METHOD void MultilibSet::dump() const {
+ print(llvm::errs());
+}
+
void MultilibSet::print(raw_ostream &OS) const {
for (const Multilib &M : *this)
OS << M << "\n";
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index b05596a99f..32c1c43a5b 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -29,10 +29,11 @@ enum : SanitizerMask {
NeedsUbsanRt = Undefined | Integer | Nullability | CFI,
NeedsUbsanCxxRt = Vptr | CFI,
NotAllowedWithTrap = Vptr,
+ NotAllowedWithMinimalRuntime = Vptr,
RequiresPIE = DataFlow,
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
- SupportsCoverage =
- Address | Memory | Leak | Undefined | Integer | Nullability | DataFlow,
+ SupportsCoverage = Address | KernelAddress | Memory | Leak | Undefined |
+ Integer | Nullability | DataFlow | Fuzzer | FuzzerNoLink,
RecoverableByDefault = Undefined | Integer | Nullability,
Unrecoverable = Unreachable | Return,
LegacyFsanitizeRecoverMask = Undefined | Integer,
@@ -41,6 +42,7 @@ enum : SanitizerMask {
Nullability | LocalBounds | CFI,
TrappingDefault = CFI,
CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast,
+ CompatibleWithMinimalRuntime = TrappingSupported,
};
enum CoverageFeature {
@@ -48,13 +50,17 @@ enum CoverageFeature {
CoverageBB = 1 << 1,
CoverageEdge = 1 << 2,
CoverageIndirCall = 1 << 3,
- CoverageTraceBB = 1 << 4,
+ CoverageTraceBB = 1 << 4, // Deprecated.
CoverageTraceCmp = 1 << 5,
CoverageTraceDiv = 1 << 6,
CoverageTraceGep = 1 << 7,
- Coverage8bitCounters = 1 << 8,
+ Coverage8bitCounters = 1 << 8, // Deprecated.
CoverageTracePC = 1 << 9,
CoverageTracePCGuard = 1 << 10,
+ CoverageNoPrune = 1 << 11,
+ CoverageInline8bitCounters = 1 << 12,
+ CoveragePCTable = 1 << 13,
+ CoverageStackDepth = 1 << 14,
};
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
@@ -98,6 +104,8 @@ static bool getDefaultBlacklist(const Driver &D, SanitizerMask Kinds,
BlacklistFile = "dfsan_abilist.txt";
else if (Kinds & CFI)
BlacklistFile = "cfi_blacklist.txt";
+ else if (Kinds & (Undefined | Integer | Nullability))
+ BlacklistFile = "ubsan_blacklist.txt";
if (BlacklistFile) {
clang::SmallString<64> Path(D.ResourceDir);
@@ -163,19 +171,23 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
}
bool SanitizerArgs::needsUbsanRt() const {
- return ((Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) ||
- CoverageFeatures) &&
- !Sanitizers.has(Address) && !Sanitizers.has(Memory) &&
- !Sanitizers.has(Thread) && !Sanitizers.has(DataFlow) &&
- !Sanitizers.has(Leak) && !CfiCrossDso;
+ // All of these include ubsan.
+ if (needsAsanRt() || needsMsanRt() || needsTsanRt() || needsDfsanRt() ||
+ needsLsanRt() || needsCfiDiagRt())
+ return false;
+
+ return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) ||
+ CoverageFeatures;
}
bool SanitizerArgs::needsCfiRt() const {
- return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
+ return !(Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso &&
+ !ImplicitCfiRuntime;
}
bool SanitizerArgs::needsCfiDiagRt() const {
- return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso;
+ return (Sanitizers.Mask & CFI & ~TrapSanitizers.Mask) && CfiCrossDso &&
+ !ImplicitCfiRuntime;
}
bool SanitizerArgs::requiresPIE() const {
@@ -206,12 +218,32 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
+ MinimalRuntime =
+ Args.hasFlag(options::OPT_fsanitize_minimal_runtime,
+ options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime);
+
+ // The object size sanitizer should not be enabled at -O0.
+ Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
+ bool RemoveObjectSizeAtO0 =
+ !OptLevel || OptLevel->getOption().matches(options::OPT_O0);
+
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
I != E; ++I) {
const auto *Arg = *I;
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
Arg->claim();
- SanitizerMask Add = parseArgValues(D, Arg, true);
+ SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true);
+
+ if (RemoveObjectSizeAtO0) {
+ AllRemove |= SanitizerKind::ObjectSize;
+
+ // The user explicitly enabled the object size sanitizer. Warn that
+ // that this does nothing at -O0.
+ if (Add & SanitizerKind::ObjectSize)
+ D.Diag(diag::warn_drv_object_size_disabled_O0)
+ << Arg->getAsString(Args);
+ }
+
AllAddedKinds |= expandSanitizerGroups(Add);
// Avoid diagnosing any sanitizer which is disabled later.
@@ -227,6 +259,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
DiagnosedKinds |= KindsToDiagnose;
}
Add &= ~InvalidTrappingKinds;
+
+ if (MinimalRuntime) {
+ if (SanitizerMask KindsToDiagnose =
+ Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) {
+ std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << Desc << "-fsanitize-minimal-runtime";
+ DiagnosedKinds |= KindsToDiagnose;
+ }
+ Add &= ~NotAllowedWithMinimalRuntime;
+ }
+
if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) {
std::string Desc = describeSanitizeArg(*I, KindsToDiagnose);
D.Diag(diag::err_drv_unsupported_opt_for_target)
@@ -263,8 +307,23 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Silently discard any unsupported sanitizers implicitly enabled through
// group expansion.
Add &= ~InvalidTrappingKinds;
+ if (MinimalRuntime) {
+ Add &= ~NotAllowedWithMinimalRuntime;
+ }
Add &= Supported;
+ if (Add & Fuzzer)
+ Add |= FuzzerNoLink;
+
+ // Enable coverage if the fuzzing flag is set.
+ if (Add & FuzzerNoLink) {
+ CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall |
+ CoverageTraceCmp | CoveragePCTable;
+ // Due to TLS differences, stack depth tracking is only enabled on Linux
+ if (TC.getTriple().isOSLinux())
+ CoverageFeatures |= CoverageStackDepth;
+ }
+
Kinds |= Add;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
Arg->claim();
@@ -434,9 +493,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
}
MsanUseAfterDtor =
- Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor);
+ Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor,
+ options::OPT_fno_sanitize_memory_use_after_dtor,
+ MsanUseAfterDtor);
NeedPIE |= !(TC.getTriple().isOSLinux() &&
TC.getTriple().getArch() == llvm::Triple::x86_64);
+ } else {
+ MsanUseAfterDtor = false;
}
if (AllAddedKinds & Thread) {
@@ -457,11 +520,33 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Without PIE, external function address may resolve to a PLT record, which
// can not be verified by the target module.
NeedPIE |= CfiCrossDso;
+ CfiICallGeneralizePointers =
+ Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
+
+ if (CfiCrossDso && CfiICallGeneralizePointers)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize-cfi-cross-dso"
+ << "-fsanitize-cfi-icall-generalize-pointers";
}
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
options::OPT_fno_sanitize_stats, false);
+ if (MinimalRuntime) {
+ SanitizerMask IncompatibleMask =
+ Kinds & ~setGroupBits(CompatibleWithMinimalRuntime);
+ if (IncompatibleMask)
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize-minimal-runtime"
+ << lastArgumentForMask(D, Args, IncompatibleMask);
+
+ SanitizerMask NonTrappingCfi = Kinds & CFI & ~TrappingKinds;
+ if (NonTrappingCfi)
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << "fsanitize-minimal-runtime"
+ << "fsanitize-trap=cfi";
+ }
+
// Parse -f(no-)?sanitize-coverage flags if coverage is supported by the
// enabled sanitizers.
for (const auto *Arg : Args) {
@@ -469,34 +554,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
int LegacySanitizeCoverage;
if (Arg->getNumValues() == 1 &&
!StringRef(Arg->getValue(0))
- .getAsInteger(0, LegacySanitizeCoverage) &&
- LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) {
- switch (LegacySanitizeCoverage) {
- case 0:
- CoverageFeatures = 0;
- Arg->claim();
- break;
- case 1:
- D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
- << "-fsanitize-coverage=func";
- CoverageFeatures = CoverageFunc;
- break;
- case 2:
- D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
- << "-fsanitize-coverage=bb";
- CoverageFeatures = CoverageBB;
- break;
- case 3:
- D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
- << "-fsanitize-coverage=edge";
- CoverageFeatures = CoverageEdge;
- break;
- case 4:
+ .getAsInteger(0, LegacySanitizeCoverage)) {
+ CoverageFeatures = 0;
+ Arg->claim();
+ if (LegacySanitizeCoverage != 0) {
D.Diag(diag::warn_drv_deprecated_arg)
- << Arg->getAsString(Args)
- << "-fsanitize-coverage=edge,indirect-calls";
- CoverageFeatures = CoverageEdge | CoverageIndirCall;
- break;
+ << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard";
}
continue;
}
@@ -504,7 +567,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// Disable coverage and not claim the flags if there is at least one
// non-supporting sanitizer.
- if (!(AllAddedKinds & ~setGroupBits(SupportsCoverage))) {
+ if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) {
Arg->claim();
} else {
CoverageFeatures = 0;
@@ -529,26 +592,44 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
<< "-fsanitize-coverage=edge";
// Basic block tracing and 8-bit counters require some type of coverage
// enabled.
- int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge;
- if ((CoverageFeatures & CoverageTraceBB) &&
- !(CoverageFeatures & CoverageTypes))
- D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ if (CoverageFeatures & CoverageTraceBB)
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=trace-bb"
- << "-fsanitize-coverage=(func|bb|edge)";
- if ((CoverageFeatures & Coverage8bitCounters) &&
- !(CoverageFeatures & CoverageTypes))
- D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << "-fsanitize-coverage=trace-pc-guard";
+ if (CoverageFeatures & Coverage8bitCounters)
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=8bit-counters"
- << "-fsanitize-coverage=(func|bb|edge)";
+ << "-fsanitize-coverage=trace-pc-guard";
+
+ int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
+ int InstrumentationTypes =
+ CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters;
+ if ((CoverageFeatures & InsertionPointTypes) &&
+ !(CoverageFeatures & InstrumentationTypes)) {
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
+ << "-fsanitize-coverage=[func|bb|edge]"
+ << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
+ }
+
// trace-pc w/o func/bb/edge implies edge.
- if ((CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard)) &&
- !(CoverageFeatures & CoverageTypes))
- CoverageFeatures |= CoverageEdge;
+ if (!(CoverageFeatures & InsertionPointTypes)) {
+ if (CoverageFeatures &
+ (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters))
+ CoverageFeatures |= CoverageEdge;
+
+ if (CoverageFeatures & CoverageStackDepth)
+ CoverageFeatures |= CoverageFunc;
+ }
+
+ SharedRuntime =
+ Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
+ TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() ||
+ TC.getTriple().isOSDarwin());
+
+ ImplicitCfiRuntime = TC.getTriple().isAndroid();
if (AllAddedKinds & Address) {
- AsanSharedRuntime =
- Args.hasArg(options::OPT_shared_libasan) || TC.getTriple().isAndroid();
- NeedPIE |= TC.getTriple().isAndroid();
+ NeedPIE |= TC.getTriple().isOSFuchsia();
if (Arg *A =
Args.getLastArg(options::OPT_fsanitize_address_field_padding)) {
StringRef S = A->getValue();
@@ -574,12 +655,23 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
}
- if (Arg *A = Args.getLastArg(
- options::OPT_fsanitize_address_use_after_scope,
- options::OPT_fno_sanitize_address_use_after_scope)) {
- AsanUseAfterScope = A->getOption().getID() ==
- options::OPT_fsanitize_address_use_after_scope;
- }
+ AsanUseAfterScope = Args.hasFlag(
+ options::OPT_fsanitize_address_use_after_scope,
+ options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
+
+ // As a workaround for a bug in gold 2.26 and earlier, dead stripping of
+ // globals in ASan is disabled by default on ELF targets.
+ // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002
+ AsanGlobalsDeadStripping =
+ !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() ||
+ Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping);
+ } else {
+ AsanUseAfterScope = false;
+ }
+
+ if (AllAddedKinds & SafeStack) {
+ // SafeStack runtime is built into the system on Fuchsia.
+ SafeStackRuntime = !TC.getTriple().isOSFuchsia();
}
// Parse -link-cxx-sanitizer flag.
@@ -641,10 +733,14 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"),
std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"),
std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc"),
- std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard")};
+ std::make_pair(CoverageTracePCGuard, "-fsanitize-coverage-trace-pc-guard"),
+ std::make_pair(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"),
+ std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"),
+ std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
+ std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")};
for (auto F : CoverageFlags) {
if (CoverageFeatures & F.first)
- CmdArgs.push_back(Args.MakeArgString(F.second));
+ CmdArgs.push_back(F.second);
}
if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
@@ -697,7 +793,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::utostr(MsanTrackOrigins)));
if (MsanUseAfterDtor)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor"));
+ CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
// FIXME: Pass these parameters as function attributes, not as -llvm flags.
if (!TsanMemoryAccess) {
@@ -716,17 +812,26 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
}
if (CfiCrossDso)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso"));
+ CmdArgs.push_back("-fsanitize-cfi-cross-dso");
+
+ if (CfiICallGeneralizePointers)
+ CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
if (Stats)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-stats"));
+ CmdArgs.push_back("-fsanitize-stats");
+
+ if (MinimalRuntime)
+ CmdArgs.push_back("-fsanitize-minimal-runtime");
if (AsanFieldPadding)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
llvm::utostr(AsanFieldPadding)));
if (AsanUseAfterScope)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-use-after-scope"));
+ CmdArgs.push_back("-fsanitize-address-use-after-scope");
+
+ if (AsanGlobalsDeadStripping)
+ CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
// MSan: Workaround for PR16386.
// ASan: This is mainly to help LSan with cases such as
@@ -734,7 +839,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
// We can't make this conditional on -fsanitize=leak, as that flag shouldn't
// affect compilation.
if (Sanitizers.has(Memory) || Sanitizers.has(Address))
- CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
+ CmdArgs.push_back("-fno-assume-sane-operator-new");
// Require -fvisibility= flag on non-Windows when compiling if vptr CFI is
// enabled.
@@ -798,6 +903,10 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) {
.Case("8bit-counters", Coverage8bitCounters)
.Case("trace-pc", CoverageTracePC)
.Case("trace-pc-guard", CoverageTracePCGuard)
+ .Case("no-prune", CoverageNoPrune)
+ .Case("inline-8bit-counters", CoverageInline8bitCounters)
+ .Case("pc-table", CoveragePCTable)
+ .Case("stack-depth", CoverageStackDepth)
.Default(0);
if (F == 0)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index f9dafb5475..416d78509d 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -19,6 +19,7 @@
#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"
@@ -73,11 +74,6 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
: D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)),
CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)),
EffectiveTriple() {
- if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
- 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);
@@ -100,13 +96,19 @@ 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;
const char *ModeFlag;
};
-const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
+const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
// A list of known driver suffixes. Suffixes are compared against the
// program name in order. If there is a match, the frontend type is updated as
// necessary by applying the ModeFlag.
@@ -125,9 +127,13 @@ const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
{"++", "--driver-mode=g++"},
};
- for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i)
- if (ProgName.endswith(DriverSuffixes[i].Suffix))
+ for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) {
+ StringRef Suffix(DriverSuffixes[i].Suffix);
+ if (ProgName.endswith(Suffix)) {
+ Pos = ProgName.size() - Suffix.size();
return &DriverSuffixes[i];
+ }
+ }
return nullptr;
}
@@ -142,7 +148,7 @@ std::string normalizeProgramName(llvm::StringRef Argv0) {
return ProgName;
}
-const DriverSuffix *parseDriverSuffix(StringRef ProgName) {
+const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
// Try to infer frontend type and default target from the program name by
// comparing it against DriverSuffixes in order.
@@ -150,47 +156,46 @@ const DriverSuffix *parseDriverSuffix(StringRef ProgName) {
// E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target
// prefix "x86_64-linux". If such a target prefix is found, it may be
// added via -target as implicit first argument.
- const DriverSuffix *DS = FindDriverSuffix(ProgName);
+ const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);
if (!DS) {
// Try again after stripping any trailing version number:
// clang++3.5 -> clang++
ProgName = ProgName.rtrim("0123456789.");
- DS = FindDriverSuffix(ProgName);
+ DS = FindDriverSuffix(ProgName, Pos);
}
if (!DS) {
// Try again after stripping trailing -component.
// clang++-tot -> clang++
ProgName = ProgName.slice(0, ProgName.rfind('-'));
- DS = FindDriverSuffix(ProgName);
+ DS = FindDriverSuffix(ProgName, Pos);
}
return DS;
}
} // anonymous namespace
-std::pair<std::string, std::string>
+ParsedClangName
ToolChain::getTargetAndModeFromProgramName(StringRef PN) {
std::string ProgName = normalizeProgramName(PN);
- const DriverSuffix *DS = parseDriverSuffix(ProgName);
+ size_t SuffixPos;
+ const DriverSuffix *DS = parseDriverSuffix(ProgName, SuffixPos);
if (!DS)
- return std::make_pair("", "");
- std::string ModeFlag = DS->ModeFlag == nullptr ? "" : DS->ModeFlag;
+ return ParsedClangName();
+ size_t SuffixEnd = SuffixPos + strlen(DS->Suffix);
- std::string::size_type LastComponent =
- ProgName.rfind('-', ProgName.size() - strlen(DS->Suffix));
+ size_t LastComponent = ProgName.rfind('-', SuffixPos);
if (LastComponent == std::string::npos)
- return std::make_pair("", ModeFlag);
+ return ParsedClangName(ProgName.substr(0, SuffixEnd), DS->ModeFlag);
+ std::string ModeSuffix = ProgName.substr(LastComponent + 1,
+ SuffixEnd - LastComponent - 1);
// Infer target from the prefix.
StringRef Prefix(ProgName);
Prefix = Prefix.slice(0, LastComponent);
std::string IgnoredError;
- std::string Target;
- if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
- Target = Prefix;
- }
- return std::make_pair(Target, ModeFlag);
+ bool IsRegistered = llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError);
+ return ParsedClangName{Prefix, ModeSuffix, DS->ModeFlag, IsRegistered};
}
StringRef ToolChain::getDefaultUniversalArchName() const {
@@ -210,7 +215,7 @@ StringRef ToolChain::getDefaultUniversalArchName() const {
}
}
-bool ToolChain::IsUnwindTablesDefault() const {
+bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
return false;
}
@@ -290,15 +295,27 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC,
const llvm::Triple &Triple = TC.getTriple();
bool IsWindows = Triple.isOSWindows();
- if (Triple.isWindowsMSVCEnvironment() && TC.getArch() == llvm::Triple::x86)
- return "i386";
-
if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb)
return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows)
? "armhf"
: "arm";
- return TC.getArchName();
+ // For historic reasons, Android library is using i686 instead of i386.
+ if (TC.getArch() == llvm::Triple::x86 && Triple.isAndroid())
+ return "i686";
+
+ return llvm::Triple::getArchTypeName(TC.getArch());
+}
+
+std::string ToolChain::getCompilerRTPath() const {
+ SmallString<128> Path(getDriver().ResourceDir);
+ if (Triple.isOSUnknown()) {
+ llvm::sys::path::append(Path, "lib");
+ } else {
+ StringRef OSLibName = Triple.isOSFreeBSD() ? "freebsd" : getOS();
+ llvm::sys::path::append(Path, "lib", OSLibName);
+ }
+ return Path.str();
}
std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component,
@@ -313,9 +330,7 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component,
const char *Suffix = Shared ? (Triple.isOSWindows() ? ".dll" : ".so")
: (IsITANMSVCWindows ? ".lib" : ".a");
- SmallString<128> Path(getDriver().ResourceDir);
- StringRef OSLibName = Triple.isOSFreeBSD() ? "freebsd" : getOS();
- llvm::sys::path::append(Path, "lib", OSLibName);
+ SmallString<128> Path(getCompilerRTPath());
llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" +
Arch + Env + Suffix);
return Path.str();
@@ -379,7 +394,11 @@ std::string ToolChain::GetLinkerPath() const {
// then use whatever the default system linker is.
return GetProgramPath(getDefaultLinker());
} else {
- llvm::SmallString<8> LinkerName("ld.");
+ llvm::SmallString<8> LinkerName;
+ if (Triple.isOSDarwin())
+ LinkerName.append("ld64.");
+ else
+ LinkerName.append("ld.");
LinkerName.append(UseLinker);
std::string LinkerPath(GetProgramPath(LinkerName.c_str()));
@@ -498,7 +517,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
: tools::arm::getARMTargetCPU(MCPU, MArch, Triple);
StringRef Suffix =
tools::arm::getLLVMArchSuffixForARM(CPU, MArch, Triple);
- bool IsMProfile = ARM::parseArchProfile(Suffix) == ARM::PK_M;
+ bool IsMProfile = ARM::parseArchProfile(Suffix) == ARM::ProfileKind::M;
bool ThumbDefault = IsMProfile || (ARM::parseArchVersion(Suffix) == 7 &&
getTriple().isOSBinFormatMachO());
// FIXME: this is invalid for WindowsCE
@@ -510,6 +529,18 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
else
ArchName = "arm";
+ // Check if ARM ISA was explicitly selected (using -mno-thumb or -marm) for
+ // M-Class CPUs/architecture variants, which is not supported.
+ bool ARMModeRequested = !Args.hasFlag(options::OPT_mthumb,
+ options::OPT_mno_thumb, ThumbDefault);
+ if (IsMProfile && ARMModeRequested) {
+ if (!MCPU.empty())
+ getDriver().Diag(diag::err_cpu_unsupported_isa) << CPU << "ARM";
+ else
+ getDriver().Diag(diag::err_arch_unsupported_isa)
+ << tools::arm::getARMArch(MArch, getTriple()) << "ARM";
+ }
+
// Assembly files should start in ARM mode, unless arch is M-profile.
// Windows is always thumb.
if ((InputType != types::TY_PP_Asm && Args.hasFlag(options::OPT_mthumb,
@@ -537,9 +568,9 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Each toolchain should provide the appropriate include flags.
}
-void ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
-}
+void ToolChain::addClangTargetOptions(
+ const ArgList &DriverArgs, ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const {}
void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {}
@@ -641,8 +672,16 @@ void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
DriverArgs.AddAllArgs(CC1Args, options::OPT_stdlib_EQ);
}
+bool ToolChain::ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const {
+ return getDriver().CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+ options::OPT_nostdlibxx);
+}
+
void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ assert(!Args.hasArg(options::OPT_nostdlibxx) &&
+ "should not have called this");
CXXStdlibType Type = GetCXXStdlibType(Args);
switch (Type) {
@@ -768,3 +807,70 @@ ToolChain::computeMSVCVersion(const Driver *D,
return VersionTuple();
}
+
+llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs(
+ const llvm::opt::DerivedArgList &Args, bool SameTripleAsHost,
+ SmallVectorImpl<llvm::opt::Arg *> &AllocatedArgs) const {
+ DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
+ const OptTable &Opts = getDriver().getOpts();
+ bool Modified = false;
+
+ // Handle -Xopenmp-target flags
+ for (Arg *A : Args) {
+ // Exclude flags which may only apply to the host toolchain.
+ // Do not exclude flags when the host triple (AuxTriple)
+ // matches the current toolchain triple. If it is not present
+ // at all, target and host share a toolchain.
+ if (A->getOption().matches(options::OPT_m_Group)) {
+ if (SameTripleAsHost)
+ DAL->append(A);
+ else
+ Modified = true;
+ continue;
+ }
+
+ unsigned Index;
+ unsigned Prev;
+ bool XOpenMPTargetNoTriple =
+ A->getOption().matches(options::OPT_Xopenmp_target);
+
+ if (A->getOption().matches(options::OPT_Xopenmp_target_EQ)) {
+ // Passing device args: -Xopenmp-target=<triple> -opt=val.
+ if (A->getValue(0) == getTripleString())
+ Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
+ else
+ continue;
+ } else if (XOpenMPTargetNoTriple) {
+ // Passing device args: -Xopenmp-target -opt=val.
+ Index = Args.getBaseArgs().MakeIndex(A->getValue(0));
+ } else {
+ DAL->append(A);
+ continue;
+ }
+
+ // Parse the argument to -Xopenmp-target.
+ Prev = Index;
+ std::unique_ptr<Arg> XOpenMPTargetArg(Opts.ParseOneArg(Args, Index));
+ if (!XOpenMPTargetArg || Index > Prev + 1) {
+ getDriver().Diag(diag::err_drv_invalid_Xopenmp_target_with_args)
+ << A->getAsString(Args);
+ continue;
+ }
+ if (XOpenMPTargetNoTriple && XOpenMPTargetArg &&
+ Args.getAllArgValues(options::OPT_fopenmp_targets_EQ).size() != 1) {
+ getDriver().Diag(diag::err_drv_Xopenmp_target_missing_triple);
+ continue;
+ }
+ XOpenMPTargetArg->setBaseArg(A);
+ A = XOpenMPTargetArg.release();
+ AllocatedArgs.push_back(A);
+ DAL->append(A);
+ Modified = true;
+ }
+
+ if (Modified)
+ return DAL;
+
+ delete DAL;
+ return nullptr;
+}
diff --git a/lib/Driver/ToolChains/AMDGPU.cpp b/lib/Driver/ToolChains/AMDGPU.cpp
index 63e1749e00..ce7f4e852a 100644
--- a/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/lib/Driver/ToolChains/AMDGPU.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "AMDGPU.h"
-#include "InputInfo.h"
#include "CommonArgs.h"
+#include "InputInfo.h"
#include "clang/Driver/Compilation.h"
#include "llvm/Option/ArgList.h"
@@ -38,8 +38,45 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
/// AMDGPU Toolchain
AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
- : Generic_ELF(D, Triple, Args) { }
+ : Generic_ELF(D, Triple, Args),
+ OptionsDefault({{options::OPT_O, "3"},
+ {options::OPT_cl_std_EQ, "CL1.2"}}) {}
Tool *AMDGPUToolChain::buildLinker() const {
return new tools::amdgpu::Linker(*this);
}
+
+DerivedArgList *
+AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const {
+
+ DerivedArgList *DAL =
+ Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
+
+ // Do nothing if not OpenCL (-x cl)
+ if (!Args.getLastArgValue(options::OPT_x).equals("cl"))
+ return DAL;
+
+ if (!DAL)
+ DAL = new DerivedArgList(Args.getBaseArgs());
+ for (auto *A : Args)
+ DAL->append(A);
+
+ const OptTable &Opts = getDriver().getOpts();
+
+ // Phase 1 (.cl -> .bc)
+ if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) {
+ DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit()
+ ? options::OPT_m64
+ : options::OPT_m32));
+
+ // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately
+ // as they defined that way in Options.td
+ if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4,
+ options::OPT_Ofast))
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O),
+ getOptionDefault(options::OPT_O));
+ }
+
+ return DAL;
+}
diff --git a/lib/Driver/ToolChains/AMDGPU.h b/lib/Driver/ToolChains/AMDGPU.h
index 9af1e96489..e2a12d4682 100644
--- a/lib/Driver/ToolChains/AMDGPU.h
+++ b/lib/Driver/ToolChains/AMDGPU.h
@@ -11,8 +11,10 @@
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H
#include "Gnu.h"
+#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include <map>
namespace clang {
namespace driver {
@@ -37,14 +39,26 @@ public:
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
+
+private:
+ const std::map<options::ID, const StringRef> OptionsDefault;
+
protected:
Tool *buildLinker() const override;
+ const StringRef getOptionDefault(options::ID OptID) const {
+ auto opt = OptionsDefault.find(OptID);
+ assert(opt != OptionsDefault.end() && "No Default for Option");
+ return opt->second;
+ }
public:
AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
+ const llvm::opt::ArgList &Args);
unsigned GetDefaultDwarfVersion() const override { return 2; }
bool IsIntegratedAssemblerDefault() const override { return true; }
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
};
} // end namespace toolchains
diff --git a/lib/Driver/ToolChains/Ananas.cpp b/lib/Driver/ToolChains/Ananas.cpp
new file mode 100644
index 0000000000..ee072cc03e
--- /dev/null
+++ b/lib/Driver/ToolChains/Ananas.cpp
@@ -0,0 +1,119 @@
+//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Ananas.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ToolChain &ToolChain = getToolChain();
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ // Ananas only supports static linkage for now.
+ CmdArgs.push_back("-Bstatic");
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_T_Group, options::OPT_e, options::OPT_s,
+ options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
+
+ if (D.isUsingLTO())
+ AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
+ CmdArgs.push_back("-lc");
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+// Ananas - Ananas tool chain which can call as(1) and ld(1) directly.
+
+Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+}
+
+Tool *Ananas::buildAssembler() const {
+ return new tools::ananas::Assembler(*this);
+}
+
+Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); }
diff --git a/lib/Driver/ToolChains/Bitrig.h b/lib/Driver/ToolChains/Ananas.h
index 6edb2e8c7e..2563dd2d49 100644
--- a/lib/Driver/ToolChains/Bitrig.h
+++ b/lib/Driver/ToolChains/Ananas.h
@@ -1,4 +1,4 @@
-//===--- Bitrig.h - Bitrig ToolChain Implementations ------------*- C++ -*-===//
+//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,22 +7,23 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
#include "Gnu.h"
-#include "clang/Driver/Driver.h"
+#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
namespace clang {
namespace driver {
namespace tools {
-/// bitrig -- Directly call GNU Binutils assembler and linker
-namespace bitrig {
+
+/// ananas -- Directly call GNU Binutils assembler and linker
+namespace ananas {
class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
public:
Assembler(const ToolChain &TC)
- : GnuTool("bitrig::Assembler", "assembler", TC) {}
+ : GnuTool("ananas::Assembler", "assembler", TC) {}
bool hasIntegratedCPP() const override { return false; }
@@ -34,7 +35,7 @@ public:
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
- Linker(const ToolChain &TC) : GnuTool("bitrig::Linker", "linker", TC) {}
+ Linker(const ToolChain &TC) : GnuTool("ananas::Linker", "linker", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
@@ -44,29 +45,16 @@ public:
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
-} // end namespace bitrig
+} // end namespace ananas
} // end namespace tools
namespace toolchains {
-class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF {
+class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF {
public:
- Bitrig(const Driver &D, const llvm::Triple &Triple,
+ Ananas(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;
@@ -76,4 +64,4 @@ protected:
} // end namespace driver
} // end namespace clang
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
diff --git a/lib/Driver/ToolChains/Arch/AArch64.cpp b/lib/Driver/ToolChains/Arch/AArch64.cpp
index 7dc2f57d82..ad04aedd09 100644
--- a/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -20,14 +20,12 @@ 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.
+/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is
+/// 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))) {
+ // If we have -mcpu, use that.
+ if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
StringRef Mcpu = A->getValue();
CPU = Mcpu.split("+").first.lower();
}
@@ -74,7 +72,7 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
if (CPU == "generic") {
Features.push_back("+neon");
} else {
- unsigned ArchKind = llvm::AArch64::parseCPUArch(CPU);
+ llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseCPUArch(CPU);
if (!llvm::AArch64::getArchFeatures(ArchKind, Features))
return false;
@@ -96,8 +94,8 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
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::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first);
+ if (ArchKind == llvm::AArch64::ArchKind::INVALID ||
!llvm::AArch64::getArchFeatures(ArchKind, Features) ||
(Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)))
return false;
@@ -122,6 +120,12 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
const ArgList &Args,
std::vector<StringRef> &Features) {
std::string MtuneLowerCase = Mtune.lower();
+ // Check CPU name is valid
+ std::vector<StringRef> MtuneFeatures;
+ StringRef Tune;
+ if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures))
+ return false;
+
// Handle CPU name is 'native'.
if (MtuneLowerCase == "native")
MtuneLowerCase = llvm::sys::getHostCPUName();
@@ -193,4 +197,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
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/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp
index 15f224bb22..44c8871d0e 100644
--- a/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -29,8 +29,7 @@ int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) {
// 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;
+ return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M;
}
// Get Arch/CPU from args.
@@ -88,6 +87,15 @@ static bool DecodeARMFeatures(const Driver &D, StringRef text,
return true;
}
+static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU,
+ std::vector<StringRef> &Features) {
+ if (CPU != "generic") {
+ llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU);
+ unsigned Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind);
+ llvm::ARM::getExtensionFeatures(Extension, Features);
+ }
+}
+
// 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.
@@ -98,7 +106,7 @@ static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
std::pair<StringRef, StringRef> Split = ArchName.split("+");
std::string MArch = arm::getARMArch(ArchName, Triple);
- if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID ||
+ if (llvm::ARM::parseArch(MArch) == llvm::ARM::ArchKind::INVALID ||
(Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
@@ -123,6 +131,26 @@ bool arm::useAAPCSForMachO(const llvm::Triple &T) {
T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T);
}
+// Select mode for reading thread pointer (-mtp=soft/cp15).
+arm::ReadTPMode arm::getReadTPMode(const ToolChain &TC, const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
+ const Driver &D = TC.getDriver();
+ arm::ReadTPMode ThreadPointer =
+ llvm::StringSwitch<arm::ReadTPMode>(A->getValue())
+ .Case("cp15", ReadTPMode::Cp15)
+ .Case("soft", ReadTPMode::Soft)
+ .Default(ReadTPMode::Invalid);
+ if (ThreadPointer != ReadTPMode::Invalid)
+ return ThreadPointer;
+ if (StringRef(A->getValue()).empty())
+ D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args);
+ else
+ D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
+ return ReadTPMode::Invalid;
+ }
+ return ReadTPMode::Soft;
+}
+
// Select the float ABI as determined by -msoft-float, -mhard-float, and
// -mfloat-abi=.
arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) {
@@ -179,6 +207,18 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) {
ABI = FloatABI::Hard;
break;
+ case llvm::Triple::NetBSD:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ ABI = FloatABI::Hard;
+ break;
+ default:
+ ABI = FloatABI::Soft;
+ break;
+ }
+ break;
+
case llvm::Triple::FreeBSD:
switch (Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
@@ -242,6 +282,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC,
bool KernelOrKext =
Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
arm::FloatABI ABI = arm::getARMFloatABI(TC, Args);
+ arm::ReadTPMode ThreadPointer = arm::getReadTPMode(TC, Args);
const Arg *WaCPU = nullptr, *WaFPU = nullptr;
const Arg *WaHDiv = nullptr, *WaArch = nullptr;
@@ -283,6 +324,9 @@ void arm::getARMTargetFeatures(const ToolChain &TC,
}
}
+ if (ThreadPointer == arm::ReadTPMode::Cp15)
+ Features.push_back("+read-tp-hard");
+
// Check -march. ClangAs gives preference to -Wa,-march=.
const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ);
StringRef ArchName;
@@ -320,6 +364,8 @@ void arm::getARMTargetFeatures(const ToolChain &TC,
for (auto &F : HostFeatures)
Features.push_back(
Args.MakeArgString((F.second ? "+" : "-") + F.first()));
+ } else if (!CPUName.empty()) {
+ DecodeARMFeaturesFromCPU(D, CPUName, Features);
}
// Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
@@ -381,7 +427,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC,
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)
+ llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::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);
@@ -392,9 +438,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC,
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");
+ Features.push_back("+execute-only");
}
}
}
@@ -449,6 +493,9 @@ void arm::getARMTargetFeatures(const ToolChain &TC,
// 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) {
@@ -512,11 +559,11 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch,
// FIXME: This is redundant with -mcpu, why does LLVM use this.
StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
const llvm::Triple &Triple) {
- unsigned ArchKind;
+ llvm::ARM::ArchKind ArchKind;
if (CPU == "generic") {
std::string ARMArch = tools::arm::getARMArch(Arch, Triple);
ArchKind = llvm::ARM::parseArch(ARMArch);
- if (ArchKind == llvm::ARM::AK_INVALID)
+ if (ArchKind == llvm::ARM::ArchKind::INVALID)
// In case of generic Arch, i.e. "arm",
// extract arch from default cpu of the Triple
ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch));
@@ -524,10 +571,10 @@ StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
// 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::ArchKind::ARMV7K
: llvm::ARM::parseCPUArch(CPU);
}
- if (ArchKind == llvm::ARM::AK_INVALID)
+ if (ArchKind == llvm::ARM::ArchKind::INVALID)
return "";
return llvm::ARM::getSubArch(ArchKind);
}
diff --git a/lib/Driver/ToolChains/Arch/ARM.h b/lib/Driver/ToolChains/Arch/ARM.h
index 5601799127..c1dc168840 100644
--- a/lib/Driver/ToolChains/Arch/ARM.h
+++ b/lib/Driver/ToolChains/Arch/ARM.h
@@ -32,6 +32,12 @@ StringRef getLLVMArchSuffixForARM(llvm::StringRef CPU, llvm::StringRef Arch,
void appendEBLinkFlags(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const llvm::Triple &Triple);
+enum class ReadTPMode {
+ Invalid,
+ Soft,
+ Cp15,
+};
+
enum class FloatABI {
Invalid,
Soft,
@@ -40,6 +46,7 @@ enum class FloatABI {
};
FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args);
+ReadTPMode getReadTPMode(const ToolChain &TC, const llvm::opt::ArgList &Args);
bool useAAPCSForMachO(const llvm::Triple &T);
void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args,
@@ -53,7 +60,7 @@ int getARMSubArchVersionNumber(const llvm::Triple &Triple);
bool isARMMProfile(const llvm::Triple &Triple);
} // end namespace arm
-} // end namespace target
+} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/lib/Driver/ToolChains/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp
index cd791af832..61481a92d0 100644
--- a/lib/Driver/ToolChains/Arch/Mips.cpp
+++ b/lib/Driver/ToolChains/Arch/Mips.cpp
@@ -35,7 +35,7 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
// 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) {
+ Triple.isGNUEnvironment()) {
DefMips32CPU = "mips32r6";
DefMips64CPU = "mips64r6";
}
@@ -227,11 +227,31 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie));
}
- if (IsN64 && NonPIC) {
+ bool UseAbiCalls = false;
+
+ Arg *ABICallsArg =
+ Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls);
+ UseAbiCalls =
+ !ABICallsArg || ABICallsArg->getOption().matches(options::OPT_mabicalls);
+
+ if (UseAbiCalls && IsN64 && NonPIC) {
+ D.Diag(diag::warn_drv_unsupported_abicalls);
+ UseAbiCalls = false;
+ }
+
+ if (!UseAbiCalls)
Features.push_back("+noabicalls");
- } else {
- AddTargetFeature(Args, Features, options::OPT_mno_abicalls,
- options::OPT_mabicalls, "noabicalls");
+ else
+ Features.push_back("-noabicalls");
+
+ if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
+ options::OPT_mno_long_calls)) {
+ if (A->getOption().matches(options::OPT_mno_long_calls))
+ Features.push_back("-long-calls");
+ else if (!UseAbiCalls)
+ Features.push_back("+long-calls");
+ else
+ D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1);
}
mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args);
@@ -245,14 +265,14 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
StringRef Val = StringRef(A->getValue());
if (Val == "2008") {
- if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008)
+ if (mips::getIEEE754Standard(CPUName) & mips::Std2008)
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)
+ if (mips::getIEEE754Standard(CPUName) & mips::Legacy)
Features.push_back("-nan2008");
else {
Features.push_back("+nan2008");
@@ -263,6 +283,28 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
<< A->getOption().getName() << Val;
}
+ if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) {
+ StringRef Val = StringRef(A->getValue());
+ if (Val == "2008") {
+ if (mips::getIEEE754Standard(CPUName) & mips::Std2008) {
+ Features.push_back("+abs2008");
+ } else {
+ Features.push_back("-abs2008");
+ D.Diag(diag::warn_target_unsupported_abs2008) << CPUName;
+ }
+ } else if (Val == "legacy") {
+ if (mips::getIEEE754Standard(CPUName) & mips::Legacy) {
+ Features.push_back("-abs2008");
+ } else {
+ Features.push_back("+abs2008");
+ D.Diag(diag::warn_target_unsupported_abslegacy) << 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,
@@ -282,45 +324,49 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
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"));
+ Features.push_back("-fp64");
else if (A->getOption().matches(options::OPT_mfpxx)) {
- Features.push_back(Args.MakeArgString("+fpxx"));
- Features.push_back(Args.MakeArgString("+nooddspreg"));
+ Features.push_back("+fpxx");
+ Features.push_back("+nooddspreg");
} else
- Features.push_back(Args.MakeArgString("+fp64"));
+ Features.push_back("+fp64");
} else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) {
- Features.push_back(Args.MakeArgString("+fpxx"));
- Features.push_back(Args.MakeArgString("+nooddspreg"));
+ Features.push_back("+fpxx");
+ Features.push_back("+nooddspreg");
} else if (mips::isFP64ADefault(Triple, CPUName)) {
- Features.push_back(Args.MakeArgString("+fp64"));
- Features.push_back(Args.MakeArgString("+nooddspreg"));
+ Features.push_back("+fp64");
+ Features.push_back("+nooddspreg");
}
AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
options::OPT_modd_spreg, "nooddspreg");
+ AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4,
+ "nomadd4");
+ AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt");
}
-mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) {
- // Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008
- // was first introduced in Release 3. However, other compilers have
- // traditionally allowed it for Release 2 so we should do the same.
- return (NanEncoding)llvm::StringSwitch<int>(CPU)
- .Case("mips1", NanLegacy)
- .Case("mips2", NanLegacy)
- .Case("mips3", NanLegacy)
- .Case("mips4", NanLegacy)
- .Case("mips5", NanLegacy)
- .Case("mips32", NanLegacy)
- .Case("mips32r2", NanLegacy | Nan2008)
- .Case("mips32r3", NanLegacy | Nan2008)
- .Case("mips32r5", NanLegacy | Nan2008)
- .Case("mips32r6", Nan2008)
- .Case("mips64", NanLegacy)
- .Case("mips64r2", NanLegacy | Nan2008)
- .Case("mips64r3", NanLegacy | Nan2008)
- .Case("mips64r5", NanLegacy | Nan2008)
- .Case("mips64r6", Nan2008)
- .Default(NanLegacy);
+mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) {
+ // Strictly speaking, mips32r2 and mips64r2 do not conform to the
+ // IEEE754-2008 standard. Support for this standard was first introduced
+ // in Release 3. However, other compilers have traditionally allowed it
+ // for Release 2 so we should do the same.
+ return (IEEE754Standard)llvm::StringSwitch<int>(CPU)
+ .Case("mips1", Legacy)
+ .Case("mips2", Legacy)
+ .Case("mips3", Legacy)
+ .Case("mips4", Legacy)
+ .Case("mips5", Legacy)
+ .Case("mips32", Legacy)
+ .Case("mips32r2", Legacy | Std2008)
+ .Case("mips32r3", Legacy | Std2008)
+ .Case("mips32r5", Legacy | Std2008)
+ .Case("mips32r6", Std2008)
+ .Case("mips64", Legacy)
+ .Case("mips64r2", Legacy | Std2008)
+ .Case("mips64r3", Legacy | Std2008)
+ .Case("mips64r5", Legacy | Std2008)
+ .Case("mips64r6", Std2008)
+ .Default(Std2008);
}
bool mips::hasCompactBranches(StringRef &CPU) {
diff --git a/lib/Driver/ToolChains/Arch/Mips.h b/lib/Driver/ToolChains/Arch/Mips.h
index 0b78866094..89eea9a151 100644
--- a/lib/Driver/ToolChains/Arch/Mips.h
+++ b/lib/Driver/ToolChains/Arch/Mips.h
@@ -24,7 +24,7 @@ namespace tools {
bool isMipsArch(llvm::Triple::ArchType Arch);
namespace mips {
-typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding;
+typedef enum { Legacy = 1, Std2008 = 2 } IEEE754Standard;
enum class FloatABI {
Invalid,
@@ -32,7 +32,7 @@ enum class FloatABI {
Hard,
};
-NanEncoding getSupportedNanEncoding(StringRef &CPU);
+IEEE754Standard getIEEE754Standard(StringRef &CPU);
bool hasCompactBranches(StringRef &CPU);
void getMipsCPUAndABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, StringRef &CPUName,
diff --git a/lib/Driver/ToolChains/Arch/PPC.cpp b/lib/Driver/ToolChains/Arch/PPC.cpp
index e83b4fe7f9..7c7e1c70e5 100644
--- a/lib/Driver/ToolChains/Arch/PPC.cpp
+++ b/lib/Driver/ToolChains/Arch/PPC.cpp
@@ -86,6 +86,18 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) {
return "";
}
+const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
+ return llvm::StringSwitch<const char *>(Name)
+ .Case("pwr7", "-mpower7")
+ .Case("power7", "-mpower7")
+ .Case("pwr8", "-mpower8")
+ .Case("power8", "-mpower8")
+ .Case("ppc64le", "-mpower8")
+ .Case("pwr9", "-mpower9")
+ .Case("power9", "-mpower9")
+ .Default("-many");
+}
+
void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
@@ -94,10 +106,6 @@ void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
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) {
diff --git a/lib/Driver/ToolChains/Arch/PPC.h b/lib/Driver/ToolChains/Arch/PPC.h
index 892eb2c341..7d7c68101b 100644
--- a/lib/Driver/ToolChains/Arch/PPC.h
+++ b/lib/Driver/ToolChains/Arch/PPC.h
@@ -32,6 +32,7 @@ enum class FloatABI {
FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
std::string getPPCTargetCPU(const llvm::opt::ArgList &Args);
+const char *getPPCAsmModeForCPU(StringRef Name);
void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
diff --git a/lib/Driver/ToolChains/Arch/X86.cpp b/lib/Driver/ToolChains/Arch/X86.cpp
index fde4476c6b..a18b2aa35b 100644
--- a/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/lib/Driver/ToolChains/Arch/X86.cpp
@@ -101,8 +101,6 @@ const char *x86::getX86TargetCPU(const ArgList &Args,
return "i486";
case llvm::Triple::Haiku:
return "i586";
- case llvm::Triple::Bitrig:
- return "i686";
default:
// Fallback to p4.
return "pentium4";
@@ -130,7 +128,6 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("-aes");
Features.push_back("-pclmul");
Features.push_back("-rtm");
- Features.push_back("-hle");
Features.push_back("-fsgsbase");
}
diff --git a/lib/Driver/ToolChains/BareMetal.cpp b/lib/Driver/ToolChains/BareMetal.cpp
new file mode 100644
index 0000000000..57a668650e
--- /dev/null
+++ b/lib/Driver/ToolChains/BareMetal.cpp
@@ -0,0 +1,202 @@
+//===--- BaremMetal.cpp - Bare Metal ToolChain ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BareMetal.h"
+
+#include "CommonArgs.h"
+#include "InputInfo.h"
+#include "Gnu.h"
+
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::opt;
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+
+BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+}
+
+BareMetal::~BareMetal() {}
+
+/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
+static bool isARMBareMetal(const llvm::Triple &Triple) {
+ if (Triple.getArch() != llvm::Triple::arm &&
+ Triple.getArch() != llvm::Triple::thumb)
+ return false;
+
+ if (Triple.getVendor() != llvm::Triple::UnknownVendor)
+ return false;
+
+ if (Triple.getOS() != llvm::Triple::UnknownOS)
+ return false;
+
+ if (Triple.getEnvironment() != llvm::Triple::EABI &&
+ Triple.getEnvironment() != llvm::Triple::EABIHF)
+ return false;
+
+ return true;
+}
+
+bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
+ return isARMBareMetal(Triple);
+}
+
+Tool *BareMetal::buildLinker() const {
+ return new tools::baremetal::Linker(*this);
+}
+
+std::string BareMetal::getRuntimesDir() const {
+ SmallString<128> Dir(getDriver().ResourceDir);
+ llvm::sys::path::append(Dir, "lib", "baremetal");
+ return Dir.str();
+}
+
+void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(getDriver().ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
+ SmallString<128> Dir(getDriver().SysRoot);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+}
+
+void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ CC1Args.push_back("-nostdsysteminc");
+}
+
+std::string BareMetal::findLibCxxIncludePath(CXXStdlibType LibType) const {
+ StringRef SysRoot = getDriver().SysRoot;
+ if (SysRoot.empty())
+ return "";
+
+ switch (LibType) {
+ case ToolChain::CST_Libcxx: {
+ SmallString<128> Dir(SysRoot);
+ llvm::sys::path::append(Dir, "include", "c++", "v1");
+ return Dir.str();
+ }
+ case ToolChain::CST_Libstdcxx: {
+ SmallString<128> Dir(SysRoot);
+ llvm::sys::path::append(Dir, "include", "c++");
+ std::error_code EC;
+ Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
+ // Walk the subdirs, and find the one with the newest gcc version:
+ for (vfs::directory_iterator LI =
+ getDriver().getVFS().dir_begin(Dir.str(), EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->getName());
+ auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
+ if (CandidateVersion.Major == -1)
+ continue;
+ if (CandidateVersion <= Version)
+ continue;
+ Version = CandidateVersion;
+ }
+ if (Version.Major == -1)
+ return "";
+ llvm::sys::path::append(Dir, Version.Text);
+ return Dir.str();
+ }
+ }
+ llvm_unreachable("unhandled LibType");
+}
+
+void BareMetal::AddClangCXXStdlibIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ std::string Path = findLibCxxIncludePath(GetCXXStdlibType(DriverArgs));
+ if (!Path.empty())
+ addSystemInclude(DriverArgs, CC1Args, Path);
+}
+
+void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CmdArgs.push_back("-lstdc++");
+ CmdArgs.push_back("-lsupc++");
+ break;
+ }
+ CmdArgs.push_back("-lunwind");
+}
+
+void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" +
+ getTriple().getArchName() + ".a"));
+}
+
+void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
+
+ AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+
+ CmdArgs.push_back("-Bstatic");
+
+ CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
+
+ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_e, options::OPT_s, options::OPT_t,
+ options::OPT_Z_Flag, options::OPT_r});
+
+ if (TC.ShouldLinkCXXStdlib(Args))
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lm");
+
+ TC.AddLinkRuntimeLib(Args, CmdArgs);
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this,
+ Args.MakeArgString(TC.GetLinkerPath()),
+ CmdArgs, Inputs));
+}
diff --git a/lib/Driver/ToolChains/BareMetal.h b/lib/Driver/ToolChains/BareMetal.h
new file mode 100644
index 0000000000..5e9fd9bffd
--- /dev/null
+++ b/lib/Driver/ToolChains/BareMetal.h
@@ -0,0 +1,89 @@
+//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+#include <string>
+
+namespace clang {
+namespace driver {
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain {
+public:
+ BareMetal(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~BareMetal() override;
+
+ static bool handlesTarget(const llvm::Triple &Triple);
+protected:
+ Tool *buildLinker() const override;
+
+public:
+ bool useIntegratedAs() const override { return true; }
+ bool isCrossCompiling() const override { return true; }
+ bool isPICDefault() const override { return false; }
+ bool isPIEDefault() const override { return false; }
+ bool isPICDefaultForced() const override { return false; }
+ bool SupportsProfiling() const override { return false; }
+ bool SupportsObjCGC() const override { return false; }
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Libcxx;
+ }
+
+ const char *getDefaultLinker() const override { return "ld.lld"; }
+
+ std::string getRuntimesDir() const;
+ void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ std::string findLibCxxIncludePath(ToolChain::CXXStdlibType LibType) const;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+ void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+};
+
+} // namespace toolchains
+
+namespace tools {
+namespace baremetal {
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {}
+ bool isLinkJob() const override { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // namespace baremetal
+} // namespace tools
+
+} // namespace driver
+} // namespace clang
+
+#endif
diff --git a/lib/Driver/ToolChains/Bitrig.cpp b/lib/Driver/ToolChains/Bitrig.cpp
deleted file mode 100644
index d8f541dfba..0000000000
--- a/lib/Driver/ToolChains/Bitrig.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-//===--- 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/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp
index fcb8c3ede1..c1c8813cc4 100644
--- a/lib/Driver/ToolChains/Clang.cpp
+++ b/lib/Driver/ToolChains/Clang.cpp
@@ -27,6 +27,7 @@
#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"
@@ -34,6 +35,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/TargetParser.h"
#include "llvm/Support/YAMLParser.h"
#ifdef LLVM_ON_UNIX
@@ -128,6 +130,13 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA,
else if (JA.isDeviceOffloading(Action::OFK_Cuda))
Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
+ if (JA.isHostOffloading(Action::OFK_OpenMP)) {
+ auto TCs = C.getOffloadToolChains<Action::OFK_OpenMP>();
+ for (auto II = TCs.first, IE = TCs.second; II != IE; ++II)
+ Work(*II->second);
+ } else if (JA.isDeviceOffloading(Action::OFK_OpenMP))
+ Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
+
//
// TODO: Add support for other offloading programming models here.
//
@@ -264,21 +273,6 @@ static void ParseMRecip(const Driver &D, const ArgList &Args,
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);
@@ -340,7 +334,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
x86::getX86TargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::hexagon:
- getHexagonTargetFeatures(Args, Features);
+ hexagon::getHexagonTargetFeatures(D, Args, Features);
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
@@ -648,8 +642,24 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
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()));
+ else {
+ // Map the driver type to the frontend type. This is mostly an identity
+ // mapping, except that the distinction between module interface units
+ // and other source files does not exist at the frontend layer.
+ const char *ClangType;
+ switch (Input.getType()) {
+ case types::TY_CXXModule:
+ ClangType = "c++";
+ break;
+ case types::TY_PP_CXXModule:
+ ClangType = "c++-cpp-output";
+ break;
+ default:
+ ClangType = types::getTypeName(Input.getType());
+ break;
+ }
+ CmdArgs.push_back(ClangType);
+ }
}
static void appendUserToPath(SmallVectorImpl<char> &Result) {
@@ -764,15 +774,14 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D,
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";
+ options::OPT_fno_coverage_mapping, false)) {
+ if (!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)) {
@@ -893,6 +902,37 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
}
}
+static void RenderDebugInfoCompressionArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const Driver &D) {
+ const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ);
+ if (!A)
+ return;
+
+ if (A->getOption().getID() == options::OPT_gz) {
+ if (llvm::zlib::isAvailable())
+ CmdArgs.push_back("-compress-debug-sections");
+ else
+ D.Diag(diag::warn_debug_compression_unavailable);
+ return;
+ }
+
+ StringRef Value = A->getValue();
+ if (Value == "none") {
+ CmdArgs.push_back("-compress-debug-sections=none");
+ } else if (Value == "zlib" || Value == "zlib-gnu") {
+ if (llvm::zlib::isAvailable()) {
+ CmdArgs.push_back(
+ Args.MakeArgString("-compress-debug-sections=" + Twine(Value)));
+ } else {
+ D.Diag(diag::warn_debug_compression_unavailable);
+ }
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+}
+
static const char *RelocationModelName(llvm::Reloc::Model Model) {
switch (Model) {
case llvm::Reloc::Static:
@@ -963,6 +1003,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
DepTarget = Args.MakeArgString(llvm::sys::path::filename(P));
}
+ if (!A->getOption().matches(options::OPT_MD) && !A->getOption().matches(options::OPT_MMD)) {
+ CmdArgs.push_back("-w");
+ }
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
QuoteTarget(DepTarget, Quoted);
@@ -1258,43 +1301,13 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
// 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)) {
+ 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;
- }
+ else {
+ std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false);
+ ABIName = llvm::ARM::computeDefaultTargetABI(Triple, CPU).data();
}
+
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
@@ -1332,6 +1345,77 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
CmdArgs.push_back("-no-implicit-float");
}
+void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
+ const ArgList &Args, bool KernelOrKext,
+ ArgStringList &CmdArgs) const {
+ const ToolChain &TC = getToolChain();
+
+ // Add the target features
+ getTargetFeatures(TC, EffectiveTriple, Args, CmdArgs, false);
+
+ // Add target specific flags.
+ switch (TC.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(EffectiveTriple, Args, CmdArgs, KernelOrKext);
+ CmdArgs.push_back("-fallow-half-arguments-and-returns");
+ break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ AddAArch64TargetArgs(Args, CmdArgs);
+ CmdArgs.push_back("-fallow-half-arguments-and-returns");
+ 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;
+ }
+}
+
void Clang::AddAArch64TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
@@ -1434,6 +1518,80 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
A->claim();
}
+ Arg *GPOpt = Args.getLastArg(options::OPT_mgpopt, options::OPT_mno_gpopt);
+ Arg *ABICalls =
+ Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls);
+
+ // -mabicalls is the default for many MIPS environments, even with -fno-pic.
+ // -mgpopt is the default for static, -fno-pic environments but these two
+ // options conflict. We want to be certain that -mno-abicalls -mgpopt is
+ // the only case where -mllvm -mgpopt is passed.
+ // NOTE: We need a warning here or in the backend to warn when -mgpopt is
+ // passed explicitly when compiling something with -mabicalls
+ // (implictly) in affect. Currently the warning is in the backend.
+ //
+ // When the ABI in use is N64, we also need to determine the PIC mode that
+ // is in use, as -fno-pic for N64 implies -mno-abicalls.
+ bool NoABICalls =
+ ABICalls && ABICalls->getOption().matches(options::OPT_mno_abicalls);
+
+ llvm::Reloc::Model RelocationModel;
+ unsigned PICLevel;
+ bool IsPIE;
+ std::tie(RelocationModel, PICLevel, IsPIE) =
+ ParsePICArgs(getToolChain(), Args);
+
+ NoABICalls = NoABICalls ||
+ (RelocationModel == llvm::Reloc::Static && ABIName == "n64");
+
+ bool WantGPOpt = GPOpt && GPOpt->getOption().matches(options::OPT_mgpopt);
+ // We quietly ignore -mno-gpopt as the backend defaults to -mno-gpopt.
+ if (NoABICalls && (!GPOpt || WantGPOpt)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mgpopt");
+
+ Arg *LocalSData = Args.getLastArg(options::OPT_mlocal_sdata,
+ options::OPT_mno_local_sdata);
+ Arg *ExternSData = Args.getLastArg(options::OPT_mextern_sdata,
+ options::OPT_mno_extern_sdata);
+ Arg *EmbeddedData = Args.getLastArg(options::OPT_membedded_data,
+ options::OPT_mno_embedded_data);
+ if (LocalSData) {
+ CmdArgs.push_back("-mllvm");
+ if (LocalSData->getOption().matches(options::OPT_mlocal_sdata)) {
+ CmdArgs.push_back("-mlocal-sdata=1");
+ } else {
+ CmdArgs.push_back("-mlocal-sdata=0");
+ }
+ LocalSData->claim();
+ }
+
+ if (ExternSData) {
+ CmdArgs.push_back("-mllvm");
+ if (ExternSData->getOption().matches(options::OPT_mextern_sdata)) {
+ CmdArgs.push_back("-mextern-sdata=1");
+ } else {
+ CmdArgs.push_back("-mextern-sdata=0");
+ }
+ ExternSData->claim();
+ }
+
+ if (EmbeddedData) {
+ CmdArgs.push_back("-mllvm");
+ if (EmbeddedData->getOption().matches(options::OPT_membedded_data)) {
+ CmdArgs.push_back("-membedded-data=1");
+ } else {
+ CmdArgs.push_back("-membedded-data=0");
+ }
+ EmbeddedData->claim();
+ }
+
+ } else if ((!ABICalls || (!NoABICalls && ABICalls)) && WantGPOpt)
+ D.Diag(diag::warn_drv_unsupported_gpopt) << (ABICalls ? 0 : 1);
+
+ if (GPOpt)
+ GPOpt->claim();
+
if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) {
StringRef Val = StringRef(A->getValue());
if (mips::hasCompactBranches(CPUName)) {
@@ -1727,10 +1885,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
// 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 :
@@ -1805,12 +1959,11 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
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" ||
+ } else if (Value.startswith("-compress-debug-sections") ||
+ Value.startswith("--compress-debug-sections") ||
+ Value == "-nocompress-debug-sections" ||
Value == "--nocompress-debug-sections") {
- CompressDebugSections = false;
+ CmdArgs.push_back(Value.data());
} else if (Value == "-mrelax-relocations=yes" ||
Value == "--mrelax-relocations=yes") {
UseRelaxRelocations = true;
@@ -1863,12 +2016,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
}
}
}
- 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) {
@@ -1877,9 +2024,984 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
}
}
+static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
+ bool OFastEnabled, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ // 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 = TC.IsMathErrnoDefault();
+ bool AssociativeMath = false;
+ bool ReciprocalMath = false;
+ bool SignedZeros = true;
+ bool TrappingMath = true;
+ StringRef DenormalFPMath = "";
+ StringRef FPContract = "";
+
+ for (const 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 = TC.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(D, 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");
+
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
+ CmdArgs.push_back("-mfpmath");
+ CmdArgs.push_back(A->getValue());
+ }
+}
+
+static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
+ const llvm::Triple &Triple,
+ const InputInfo &Input) {
+ // 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 (!Triple.isWindowsMSVCEnvironment()) {
+ 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 (Triple.isPS4CPU()) {
+ CmdArgs.push_back("-analyzer-disable-checker=unix.API");
+ CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork");
+ }
+
+ if (Triple.isOSDarwin())
+ CmdArgs.push_back("-analyzer-checker=osx");
+
+ CmdArgs.push_back("-analyzer-checker=deadcode");
+
+ if (types::isCXX(Input.getType()))
+ CmdArgs.push_back("-analyzer-checker=cplusplus");
+
+ if (!Triple.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);
+}
+
+static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs, bool KernelOrKext) {
+ const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple();
+
+ // NVPTX doesn't support stack protectors; from the compiler's perspective, it
+ // doesn't even have a stack!
+ if (EffectiveTriple.isNVPTX())
+ return;
+
+ // -stack-protector=0 is default.
+ unsigned StackProtectorLevel = 0;
+ unsigned DefaultStackProtectorLevel =
+ TC.GetDefaultStackProtectorLevel(KernelOrKext);
+
+ 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, DefaultStackProtectorLevel);
+ 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 = DefaultStackProtectorLevel;
+ }
+
+ 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();
+ }
+ }
+}
+
+static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) {
+ const unsigned ForwardedArguments[] = {
+ options::OPT_cl_opt_disable,
+ options::OPT_cl_strict_aliasing,
+ options::OPT_cl_single_precision_constant,
+ options::OPT_cl_finite_math_only,
+ options::OPT_cl_kernel_arg_info,
+ options::OPT_cl_unsafe_math_optimizations,
+ options::OPT_cl_fast_relaxed_math,
+ options::OPT_cl_mad_enable,
+ options::OPT_cl_no_signed_zeros,
+ options::OPT_cl_denorms_are_zero,
+ options::OPT_cl_fp32_correctly_rounded_divide_sqrt,
+ };
+
+ if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) {
+ std::string CLStdStr = std::string("-cl-std=") + A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(CLStdStr));
+ }
+
+ for (const auto &Arg : ForwardedArguments)
+ if (const auto *A = Args.getLastArg(Arg))
+ CmdArgs.push_back(Args.MakeArgString(A->getOption().getPrefixedName()));
+}
+
+static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ 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);
+ }
+}
+
+static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T,
+ const ArgList &Args, ArgStringList &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));
+ }
+
+ // le32-specific flags:
+ // -fno-math-builtin: clang should not convert math builtins to intrinsics
+ // by default.
+ if (TC.getArch() == llvm::Triple::le32)
+ CmdArgs.push_back("-fno-math-builtin");
+}
+
+static void RenderModulesOptions(Compilation &C, const Driver &D,
+ const ArgList &Args, const InputInfo &Input,
+ const InputInfo &Output,
+ ArgStringList &CmdArgs, bool &HaveModules) {
+ // -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(Input.getType())) {
+ CmdArgs.push_back("-fmodules");
+ HaveClangModules = true;
+ }
+ }
+
+ HaveModules = HaveClangModules;
+ if (Args.hasArg(options::OPT_fmodules_ts)) {
+ CmdArgs.push_back("-fmodules-ts");
+ HaveModules = 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 (HaveModules)
+ CmdArgs.push_back("-fno-implicit-modules");
+ } else if (HaveModules) {
+ // -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 (HaveModules) {
+ // -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()));
+ A->claim();
+ }
+ }
+
+ // -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(D.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));
+ }
+
+ // The -fmodule-file=<name>=<file> form specifies the mapping of module
+ // names to precompiled module files (the module is loaded only if used).
+ // The -fmodule-file=<file> form can be used to unconditionally load
+ // precompiled module files (whether used or not).
+ if (HaveModules)
+ 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);
+}
+
+static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
+ ArgStringList &CmdArgs) {
+ // -fsigned-char is default.
+ if (const 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(T)) {
+ CmdArgs.push_back("-fno-signed-char");
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_fshort_wchar,
+ options::OPT_fno_short_wchar)) {
+ if (A->getOption().matches(options::OPT_fshort_wchar)) {
+ CmdArgs.push_back("-fwchar-type=short");
+ CmdArgs.push_back("-fno-signed-wchar");
+ } else {
+ bool IsARM = T.isARM() || T.isThumb() || T.isAArch64();
+ CmdArgs.push_back("-fwchar-type=int");
+ if (IsARM && !(T.isOSWindows() || T.getOS() == llvm::Triple::NetBSD ||
+ T.getOS() == llvm::Triple::OpenBSD))
+ CmdArgs.push_back("-fno-signed-wchar");
+ else
+ CmdArgs.push_back("-fsigned-wchar");
+ }
+ }
+}
+
+static void RenderObjCOptions(const ToolChain &TC, const Driver &D,
+ const llvm::Triple &T, const ArgList &Args,
+ ObjCRuntime &Runtime, bool InferCovariantReturns,
+ const InputInfo &Input, ArgStringList &CmdArgs) {
+ const llvm::Triple::ArchType Arch = TC.getArch();
+
+ // -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 (Runtime.isNonFragile()) {
+ if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ Runtime.isLegacyDispatchDefaultForArch(Arch))) {
+ if (TC.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 (Arch == llvm::Triple::x86 && T.isMacOSX() &&
+ !T.isMacOSXVersionLT(10, 7) &&
+ Runtime.getKind() == ObjCRuntime::FragileMacOSX && Runtime.isNeXTFamily())
+ CmdArgs.push_back("-fobjc-subscripting-legacy-runtime");
+
+ // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
+ // NOTE: This logic is duplicated in ToolChains.cpp.
+ if (isObjCAutoRefCount(Args)) {
+ TC.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(Input.getType()) && types::isObjC(Input.getType())) {
+ if (TC.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 default off for Objective-C, on for Objective-C++.
+ if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
+ options::OPT_fno_objc_arc_exceptions,
+ /*default=*/types::isCXX(Input.getType())))
+ 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 (InferCovariantReturns)
+ CmdArgs.push_back("-fno-objc-infer-related-result-type");
+
+ // Pass down -fobjc-weak or -fno-objc-weak if present.
+ if (types::isObjC(Input.getType())) {
+ auto WeakArg =
+ Args.getLastArg(options::OPT_fobjc_weak, options::OPT_fno_objc_weak);
+ if (!WeakArg) {
+ // nothing to do
+ } else if (!Runtime.allowsWeak()) {
+ if (WeakArg->getOption().matches(options::OPT_fobjc_weak))
+ D.Diag(diag::err_objc_weak_unsupported);
+ } else {
+ WeakArg->render(Args, CmdArgs);
+ }
+ }
+}
+
+static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ bool CaretDefault = true;
+ bool ColumnDefault = true;
+
+ if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diagnostics_classic,
+ options::OPT__SLASH_diagnostics_column,
+ options::OPT__SLASH_diagnostics_caret)) {
+ switch (A->getOption().getID()) {
+ case options::OPT__SLASH_diagnostics_caret:
+ CaretDefault = true;
+ ColumnDefault = true;
+ break;
+ case options::OPT__SLASH_diagnostics_column:
+ CaretDefault = false;
+ ColumnDefault = true;
+ break;
+ case options::OPT__SLASH_diagnostics_classic:
+ CaretDefault = false;
+ ColumnDefault = false;
+ break;
+ }
+ }
+
+ // -fcaret-diagnostics is default.
+ if (!Args.hasFlag(options::OPT_fcaret_diagnostics,
+ options::OPT_fno_caret_diagnostics, CaretDefault))
+ CmdArgs.push_back("-fno-caret-diagnostics");
+
+ // -fdiagnostics-fixit-info is default, only pass non-default.
+ if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
+ options::OPT_fno_diagnostics_fixit_info))
+ CmdArgs.push_back("-fno-diagnostics-fixit-info");
+
+ // Enable -fdiagnostics-show-option by default.
+ if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
+ options::OPT_fno_diagnostics_show_option))
+ CmdArgs.push_back("-fdiagnostics-show-option");
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-show-category");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
+ options::OPT_fno_diagnostics_show_hotness, false))
+ CmdArgs.push_back("-fdiagnostics-show-hotness");
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) {
+ std::string Opt =
+ std::string("-fdiagnostics-hotness-threshold=") + A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(Opt));
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-format");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (const Arg *A = Args.getLastArg(
+ options::OPT_fdiagnostics_show_note_include_stack,
+ options::OPT_fno_diagnostics_show_note_include_stack)) {
+ const Option &O = A->getOption();
+ if (O.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 (const 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")
+ D.Diag(diag::err_drv_clang_unsupported)
+ << ("-fdiagnostics-color=" + Value).str();
+ }
+ A->claim();
+ }
+
+ if (D.getDiags().getDiagnosticOptions().ShowColors)
+ CmdArgs.push_back("-fcolor-diagnostics");
+
+ if (Args.hasArg(options::OPT_fansi_escape_codes))
+ CmdArgs.push_back("-fansi-escape-codes");
+
+ if (!Args.hasFlag(options::OPT_fshow_source_location,
+ options::OPT_fno_show_source_location))
+ CmdArgs.push_back("-fno-show-source-location");
+
+ if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths))
+ CmdArgs.push_back("-fdiagnostics-absolute-paths");
+
+ if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column,
+ ColumnDefault))
+ CmdArgs.push_back("-fno-show-column");
+
+ if (!Args.hasFlag(options::OPT_fspell_checking,
+ options::OPT_fno_spell_checking))
+ CmdArgs.push_back("-fno-spell-checking");
+}
+
+static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
+ const llvm::Triple &T, const ArgList &Args,
+ bool EmitCodeView, bool IsWindowsMSVC,
+ ArgStringList &CmdArgs,
+ codegenoptions::DebugInfoKind &DebugInfoKind,
+ const Arg *&SplitDWARFArg) {
+ if (Args.hasFlag(options::OPT_fdebug_info_for_profiling,
+ options::OPT_fno_debug_info_for_profiling, false))
+ CmdArgs.push_back("-fdebug-info-for-profiling");
+
+ // 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 = TC.getDefaultDebuggerTuning();
+
+ bool SplitDWARFInlining =
+ Args.hasFlag(options::OPT_fsplit_dwarf_inlining,
+ options::OPT_fno_split_dwarf_inlining, true);
+
+ Args.ClaimAllArgs(options::OPT_g_Group);
+
+ SplitDWARFArg = Args.getLastArg(options::OPT_gsplit_dwarf);
+
+ if (const 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 (const 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 (const 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 = TC.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 SCE 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=*/!(IsWindowsMSVC && EmitCodeView) &&
+ DebuggerTuning != llvm::DebuggerKind::SCE))
+ 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 (T.isOSLinux()) {
+ if (!SplitDWARFInlining)
+ CmdArgs.push_back("-fno-split-dwarf-inlining");
+
+ if (SplitDWARFArg) {
+ if (DebugInfoKind == codegenoptions::NoDebugInfo)
+ DebugInfoKind = codegenoptions::LimitedDebugInfo;
+ CmdArgs.push_back("-enable-split-dwarf");
+ }
+ }
+
+ // After we've dealt with all combinations of things that could
+ // make DebugInfoKind be other than None or DebugLineTablesOnly,
+ // figure out if we need to "upgrade" it to standalone debug info.
+ // We parse these two '-f' options whether or not they will be used,
+ // to claim them even if you wrote "-fstandalone-debug -gline-tables-only"
+ bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug,
+ options::OPT_fno_standalone_debug,
+ TC.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("-ggnu-pubnames");
+
+ // -gdwarf-aranges turns on the emission of the aranges section in the
+ // backend.
+ // Always enabled for SCE tuning.
+ if (Args.hasArg(options::OPT_gdwarf_aranges) ||
+ DebuggerTuning == llvm::DebuggerKind::SCE) {
+ 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");
+ }
+
+ // Decide how to render forward declarations of template instantiations.
+ // SCE wants full descriptions, others just get them in the name.
+ if (DebuggerTuning == llvm::DebuggerKind::SCE)
+ CmdArgs.push_back("-debug-forward-template-params");
+
+ // Do we need to explicitly import anonymous namespaces into the parent scope?
+ if (DebuggerTuning == llvm::DebuggerKind::SCE)
+ CmdArgs.push_back("-dwarf-explicit-import");
+
+ RenderDebugInfoCompressionArgs(Args, CmdArgs, D);
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, const char *LinkingOutput) const {
+ const llvm::Triple &RawTriple = getToolChain().getTriple();
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
const std::string &TripleStr = Triple.getTriple();
@@ -1901,18 +3023,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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();
+ const llvm::Triple *AuxTriple =
+ IsCuda ? getToolChain().getAuxTriple() : nullptr;
+
+ bool IsWindowsGNU = RawTriple.isWindowsGNUEnvironment();
+ bool IsWindowsCygnus = RawTriple.isWindowsCygwinEnvironment();
+ bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment();
+ bool IsIAMCU = RawTriple.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();
@@ -1953,6 +3075,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
}
+ if (IsOpenMPDevice) {
+ // We have to pass the triple of the host if compiling for an OpenMP device.
+ std::string NormalizedTriple =
+ C.getSingleOffloadToolChain<Action::OFK_Host>()
+ ->getTriple()
+ .normalize();
+ CmdArgs.push_back("-aux-triple");
+ CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
+ }
+
if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm ||
Triple.getArch() == llvm::Triple::thumb)) {
unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
@@ -2043,10 +3175,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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() ||
+ // The Darwin and PS4 linkers currently use the legacy LTO API, which
+ // does not support LTO unit features (CFI, whole program vtable opt)
+ // under ThinLTO.
+ if (!(RawTriple.isOSDarwin() || RawTriple.isPS4()) ||
D.getLTOMode() == LTOK_Full)
CmdArgs.push_back("-flto-unit");
}
@@ -2093,78 +3225,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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);
- }
+ if (isa<AnalyzeJobAction>(JA))
+ RenderAnalyzerOptions(Args, CmdArgs, Triple, Input);
CheckCodeGenerationOptions(D, Args);
@@ -2199,8 +3261,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back("-mthread-model");
- if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
+ if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) {
+ if (!getToolChain().isThreadModelSupported(A->getValue()))
+ D.Diag(diag::err_drv_invalid_thread_model_for_target)
+ << A->getValue() << A->getAsString(Args);
CmdArgs.push_back(A->getValue());
+ }
else
CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel()));
@@ -2238,6 +3304,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
true))
CmdArgs.push_back("-fno-jump-tables");
+ if (Args.hasFlag(options::OPT_fprofile_sample_accurate,
+ options::OPT_fno_profile_sample_accurate, false))
+ CmdArgs.push_back("-fprofile-sample-accurate");
+
if (!Args.hasFlag(options::OPT_fpreserve_as_comments,
options::OPT_fno_preserve_as_comments, true))
CmdArgs.push_back("-fno-preserve-as-comments");
@@ -2251,7 +3321,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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();
+ << A->getSpelling() << RawTriple.str();
} else if (A->getOption().matches(options::OPT_fpcc_struct_return)) {
CmdArgs.push_back("-fpcc-struct-return");
} else {
@@ -2263,7 +3333,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
CmdArgs.push_back("-fdefault-calling-conv=stdcall");
- if (shouldUseFramePointer(Args, getToolChain().getTriple()))
+ if (shouldUseFramePointer(Args, RawTriple))
CmdArgs.push_back("-mdisable-fp-elim");
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
options::OPT_fno_zero_initialized_in_bss))
@@ -2276,7 +3346,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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();
+ bool TBAAOnByDefault = !D.IsCLMode();
if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
options::OPT_fno_strict_aliasing, TBAAOnByDefault))
CmdArgs.push_back("-relaxed-aliasing");
@@ -2289,6 +3359,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
true))
CmdArgs.push_back("-fno-strict-return");
+ if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
+ options::OPT_fno_allow_editor_placeholders, false))
+ CmdArgs.push_back("-fallow-editor-placeholders");
if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
options::OPT_fno_strict_vtable_pointers,
false))
@@ -2297,159 +3370,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
+ Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses,
+ options::OPT_fno_fine_grained_bitfield_accesses);
+
// 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");
+ RenderFloatingPointOptions(getToolChain(), D, OFastEnabled, Args, CmdArgs);
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
@@ -2476,13 +3404,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// 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())
+ if (!RawTriple.isOSDarwin() && !RawTriple.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())
+ if (KernelOrKext && RawTriple.isOSDarwin())
CmdArgs.push_back("-fforbid-guard-variables");
if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields,
@@ -2496,20 +3423,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-mpie-copy-relocations");
}
+ // -fhosted is default.
+ // TODO: Audit uses of KernelOrKext and see where it'd be more appropriate to
+ // use Freestanding.
+ bool Freestanding =
+ Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
+ KernelOrKext;
+ if (Freestanding)
+ CmdArgs.push_back("-ffreestanding");
+
// 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().IsUnwindTablesDefault(Args) ||
getToolChain().getSanitizerArgs().needsUnwindTables()) &&
- !KernelOrKext);
+ !Freestanding);
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables");
- getToolChain().addClangTargetOptions(Args, CmdArgs);
+ getToolChain().addClangTargetOptions(Args, CmdArgs,
+ JA.getOffloadingDeviceKind());
if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2531,114 +3468,61 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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;
+ RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs);
- 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())
+ if (D.IsCLMode())
AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView);
+ const Arg *SplitDWARFArg = nullptr;
+ RenderDebugOptions(getToolChain(), D, RawTriple, Args, EmitCodeView,
+ IsWindowsMSVC, CmdArgs, DebugInfoKind, SplitDWARFArg);
+
+ // Add the split debug info name to the command lines here so we
+ // can propagate it to the backend.
+ bool SplitDWARF = SplitDWARFArg && RawTriple.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);
+ }
+
// 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()))
+ if (!shouldUseLeafFramePointer(Args, RawTriple))
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() &&
+ if (types::isCXX(InputType) && RawTriple.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);
@@ -2657,135 +3541,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
: "-");
}
- 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);
-
- // -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,
@@ -2804,41 +3559,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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:
- case llvm::Triple::ppc64le:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- // 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);
+ if (auto *ABICompatArg = Args.getLastArg(options::OPT_fclang_abi_compat_EQ))
+ ABICompatArg->render(Args, CmdArgs);
+
// Add runtime flag for PS4 when PGO or Coverage are enabled.
- if (getToolChain().getTriple().isPS4CPU())
+ if (RawTriple.isPS4CPU())
PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs);
// Pass options for controlling the default header search paths.
@@ -2858,75 +3585,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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);
- }
+ RenderARCMigrateToolOptions(D, Args, CmdArgs);
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
@@ -2958,6 +3617,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->claim();
}
+ for (const Arg *A :
+ Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) {
+ D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args);
+ A->claim();
+ }
+
claimNoWarnArgs(Args);
Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
@@ -3165,29 +3830,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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();
+ // Emulated TLS is enabled by default on Android and OpenBSD, and can be enabled
+ // manually with -femulated-tls.
+ bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isOSOpenBSD() ||
+ Triple.isWindowsCygwinEnvironment();
if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls,
EmulatedTLSDefault))
CmdArgs.push_back("-femulated-tls");
// AltiVec-like language extensions aren't relevant for assembling.
- if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) {
- Args.AddLastArg(CmdArgs, options::OPT_faltivec);
+ 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);
@@ -3197,7 +3854,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_openmp, false) &&
(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_OpenMP))) {
- switch (getToolChain().getDriver().getOpenMPRuntime(Args)) {
+ switch (D.getOpenMPRuntime(Args)) {
case Driver::OMPRT_OMP:
case Driver::OMPRT_IOMP5:
// Clang can generate useful OpenMP code for these two runtime libraries.
@@ -3225,20 +3882,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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";
+ const XRayArgs &XRay = getToolChain().getXRayArgs();
+ XRay.addArgs(getToolChain(), Args, CmdArgs, InputType);
if (getToolChain().SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_pg);
@@ -3290,49 +3935,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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();
- }
- }
+ RenderSSPOptions(getToolChain(), Args, CmdArgs, KernelOrKext);
// Translate -mstackrealign
if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
@@ -3353,20 +3956,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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)) {
@@ -3385,48 +3974,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// 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");
- }
+ RenderOpenCLOptions(Args, CmdArgs);
// Forward -f options with positive and negative forms; we translate
// these by hand.
- if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) {
+ if (Arg *A = getLastProfileSampleUseArg(Args)) {
StringRef fname = A->getValue();
if (!llvm::sys::fs::exists(fname))
D.Diag(diag::err_drv_no_such_file) << fname;
@@ -3434,36 +3986,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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));
- }
+ RenderBuiltinOptions(getToolChain(), RawTriple, Args, CmdArgs);
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new))
@@ -3482,163 +4005,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks-runtime-optional");
}
+ // -fencode-extended-block-signature=1 is default.
+ if (getToolChain().IsEncodeExtendedBlockSignatureDefault())
+ CmdArgs.push_back("-fencode-extended-block-signature");
+
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_fdouble_square_bracket_attributes,
+ options::OPT_fno_double_square_bracket_attributes);
- 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);
+ bool HaveModules = false;
+ RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);
// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
@@ -3662,28 +4043,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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");
- }
+ RenderCharacterOptions(Args, AuxTriple ? *AuxTriple : RawTriple, CmdArgs);
// -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 &&
+ !RawTriple.isOSWindows() &&
+ RawTriple.getOS() != llvm::Triple::Solaris &&
getToolChain().getArch() != llvm::Triple::hexagon &&
getToolChain().getArch() != llvm::Triple::xcore &&
- ((getToolChain().getTriple().getVendor() !=
- llvm::Triple::MipsTechnologies) ||
- getToolChain().getTriple().hasEnvironment())) ||
+ ((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) ||
+ RawTriple.hasEnvironment())) ||
KernelOrKext)
CmdArgs.push_back("-fno-use-cxa-atexit");
@@ -3705,8 +4075,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_ms_extensions, true))))
CmdArgs.push_back("-fms-compatibility");
- VersionTuple MSVT =
- getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args);
+ VersionTuple MSVT = getToolChain().computeMSVCVersion(&D, Args);
if (!MSVT.empty())
CmdArgs.push_back(
Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
@@ -3717,7 +4086,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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")
+ .Case("c++17", "-std=c++17")
+ .Case("c++latest", "-std=c++2a")
.Default("");
if (LanguageStandard.empty())
D.Diag(clang::diag::warn_drv_unused_argument)
@@ -3741,7 +4111,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fno-declspec is default, except for PS4.
if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec,
- getToolChain().getTriple().isPS4()))
+ RawTriple.isPS4()))
CmdArgs.push_back("-fdeclspec");
else if (Args.hasArg(options::OPT_fno_declspec))
CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec.
@@ -3753,8 +4123,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
!IsWindowsMSVC || IsMSVC2015Compatible))
CmdArgs.push_back("-fno-threadsafe-statics");
- // -fno-delayed-template-parsing is default, except for Windows where MSVC STL
- // needs it.
+ // -fno-delayed-template-parsing is default, except when targetting MSVC.
+ // Many old Windows SDK versions require this to parse.
+ // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their
+ // compiler. We should be able to disable this by default at some point.
if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
CmdArgs.push_back("-fdelayed-template-parsing");
@@ -3780,90 +4152,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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);
- }
- }
+ ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind);
+ RenderObjCOptions(getToolChain(), D, RawTriple, Args, Runtime,
+ rewriteKind != RK_None, Input, CmdArgs);
if (Args.hasFlag(options::OPT_fapplication_extension,
options::OPT_fno_application_extension, false))
@@ -3871,7 +4162,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Handle GCC-style exception args.
if (!C.getDriver().IsCLMode())
- addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime,
+ addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, Runtime,
CmdArgs);
if (Args.hasArg(options::OPT_fsjlj_exceptions) ||
@@ -3922,12 +4213,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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))
@@ -3952,7 +4237,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
MaxTypeAlignStr += A->getValue();
CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
}
- } else if (getToolChain().getTriple().isOSDarwin()) {
+ } else if (RawTriple.isOSDarwin()) {
if (!SkipMaxTypeAlign) {
std::string MaxTypeAlignStr = "-fmax-type-align=16";
CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
@@ -3960,8 +4245,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// -fcommon is the default unless compiling kernel code or the target says so
- bool NoCommonDefault =
- KernelOrKext || isNoCommonDefault(getToolChain().getTriple());
+ bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple);
if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common,
!NoCommonDefault))
CmdArgs.push_back("-fno-common");
@@ -3994,86 +4278,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
<< 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");
+ RenderDiagnosticsOptions(D, Args, CmdArgs);
// -fno-asm-blocks is default.
if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
@@ -4103,11 +4308,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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);
@@ -4137,13 +4337,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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");
@@ -4153,10 +4346,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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 {
+
+ if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) {
+ if (Arg *FinalOutput = Args.getLastArg(options::OPT_o))
+ F = FinalOutput->getValue();
+ }
+
+ if (F.empty()) {
// Use the input filename.
F = llvm::sys::path::stem(Input.getBaseInput());
@@ -4178,19 +4374,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
-// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
-//
-// FIXME: Now that PR4941 has been fixed this can be enabled.
-#if 0
- if (getToolChain().getTriple().isOSDarwin() &&
- (getToolChain().getArch() == llvm::Triple::arm ||
- getToolChain().getArch() == llvm::Triple::thumb)) {
- if (!Args.hasArg(options::OPT_fbuiltin_strcat))
- CmdArgs.push_back("-fno-builtin-strcat");
- if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
- CmdArgs.push_back("-fno-builtin-strcpy");
- }
-#endif
+ bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports,
+ options::OPT_fno_rewrite_imports, false);
+ if (RewriteImports)
+ CmdArgs.push_back("-frewrite-imports");
// Enable rewrite includes if the user's asked for it or if we're generating
// diagnostics.
@@ -4198,7 +4385,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// 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))
+ (C.isForDiagnostics() && (RewriteImports || !HaveModules)))
CmdArgs.push_back("-frewrite-includes");
// Only allow -traditional or -traditional-cpp outside in preprocessing modes.
@@ -4263,7 +4450,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
- Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
+ // -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();
@@ -4308,11 +4507,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_undef);
- const char *Exec = getToolChain().getDriver().getClangProgramPath();
+ const char *Exec = D.getClangProgramPath();
// Optionally embed the -cc1 level arguments into the debug info, for build
// analysis.
- if (getToolChain().UseDwarfDebugFlags()) {
+ // 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);
@@ -4329,18 +4533,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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)
@@ -4354,10 +4546,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// 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) {
+ if (IsOpenMPDevice) {
CmdArgs.push_back("-fopenmp-is-device");
- CmdArgs.push_back("-fopenmp-host-ir-file-path");
- CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename()));
+ if (Inputs.size() == 2) {
+ CmdArgs.push_back("-fopenmp-host-ir-file-path");
+ CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename()));
+ }
}
// For all the host OpenMP offloading compile jobs we need to pass the targets
@@ -4411,8 +4605,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// 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 (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))
@@ -4687,7 +4881,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
// 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 ((!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) ||
+ (Args.hasArg(options::OPT__SLASH_P) &&
+ Args.hasArg(options::OPT__SLASH_EP) && !Args.hasArg(options::OPT_E)))
if (Arg *A = Args.getLastArg(options::OPT_show_includes))
A->render(Args, CmdArgs);
@@ -4773,14 +4969,36 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
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");
+ // Parse the default calling convention options.
+ if (Arg *CCArg =
+ Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr,
+ options::OPT__SLASH_Gz, options::OPT__SLASH_Gv)) {
+ unsigned DCCOptId = CCArg->getOption().getID();
+ const char *DCCFlag = nullptr;
+ bool ArchSupported = true;
+ llvm::Triple::ArchType Arch = getToolChain().getArch();
+ switch (DCCOptId) {
+ case options::OPT__SLASH_Gd:
+ DCCFlag = "-fdefault-calling-conv=cdecl";
+ break;
+ case options::OPT__SLASH_Gr:
+ ArchSupported = Arch == llvm::Triple::x86;
+ DCCFlag = "-fdefault-calling-conv=fastcall";
+ break;
+ case options::OPT__SLASH_Gz:
+ ArchSupported = Arch == llvm::Triple::x86;
+ DCCFlag = "-fdefault-calling-conv=stdcall";
+ break;
+ case options::OPT__SLASH_Gv:
+ ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64;
+ DCCFlag = "-fdefault-calling-conv=vectorcall";
+ break;
+ }
+
+ // MSVC doesn't warn if /Gr or /Gz is used on x64, so we don't either.
+ if (ArchSupported && DCCFlag)
+ CmdArgs.push_back(DCCFlag);
+ }
if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ))
A->render(Args, CmdArgs);
@@ -4868,6 +5086,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
const std::string &TripleStr = Triple.getTriple();
+ const auto &D = getToolChain().getDriver();
// Don't warn about "clang -w -c foo.s"
Args.ClaimAllArgs(options::OPT_w);
@@ -4955,6 +5174,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
}
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
llvm::DebuggerKind::Default);
+ RenderDebugInfoCompressionArgs(Args, CmdArgs, D);
+
// Handle -fPIC et al -- the relocation-model affects the assembler
// for some targets.
@@ -5008,6 +5229,19 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::x86_64:
AddX86TargetArgs(Args, CmdArgs);
break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ // This isn't in AddARMTargetArgs because we want to do this for assembly
+ // only, not C/C++.
+ if (Args.hasFlag(options::OPT_mdefault_build_attributes,
+ options::OPT_mno_default_build_attributes, true)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-arm-add-build-attributes");
+ }
+ break;
}
// Consume all the warning flags. Usually this would be handled more
@@ -5159,7 +5393,13 @@ void OffloadBundler::ConstructJobMultipleOutputs(
for (unsigned I = 0; I < Outputs.size(); ++I) {
if (I)
UB += ',';
- UB += Outputs[I].getFilename();
+ SmallString<256> OutputFileName(Outputs[I].getFilename());
+ // Change extension of target files for OpenMP offloading
+ // to NVIDIA GPUs.
+ if (DepInfo[I].DependentToolChain->getTriple().isNVPTX() &&
+ JA.isOffloading(Action::OFK_OpenMP))
+ llvm::sys::path::replace_extension(OutputFileName, "cubin");
+ UB += OutputFileName;
}
CmdArgs.push_back(TCArgs.MakeArgString(UB));
CmdArgs.push_back("-unbundle");
diff --git a/lib/Driver/ToolChains/Clang.h b/lib/Driver/ToolChains/Clang.h
index d53c3b4413..e23822b9c6 100644
--- a/lib/Driver/ToolChains/Clang.h
+++ b/lib/Driver/ToolChains/Clang.h
@@ -42,6 +42,10 @@ private:
const InputInfo &Output,
const InputInfoList &Inputs) const;
+ void RenderTargetOptions(const llvm::Triple &EffectiveTriple,
+ const llvm::opt::ArgList &Args, bool KernelOrKext,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
void AddAArch64TargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
void AddARMTargetArgs(const llvm::Triple &Triple,
diff --git a/lib/Driver/ToolChains/CloudABI.cpp b/lib/Driver/ToolChains/CloudABI.cpp
index 0f6c712c5d..cdf807f7f9 100644
--- a/lib/Driver/ToolChains/CloudABI.cpp
+++ b/lib/Driver/ToolChains/CloudABI.cpp
@@ -80,9 +80,9 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
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");
}
diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp
index 5afe135865..b359cbb77e 100644
--- a/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/lib/Driver/ToolChains/CommonArgs.cpp
@@ -215,6 +215,21 @@ static std::string getR600TargetGPU(const ArgList &Args) {
return "";
}
+static std::string getNios2TargetCPU(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mcpu_EQ);
+ if (!A)
+ A = Args.getLastArg(options::OPT_march_EQ);
+
+ if (!A)
+ return "";
+
+ const char *name = A->getValue();
+ return llvm::StringSwitch<const char *>(name)
+ .Case("r1", "nios2r1")
+ .Case("r2", "nios2r2")
+ .Default(name);
+}
+
static std::string getLanaiTargetCPU(const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
return A->getValue();
@@ -261,6 +276,16 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T,
arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs);
return arm::getARMTargetCPU(MCPU, MArch, T);
}
+
+ case llvm::Triple::avr:
+ if (const Arg *A = Args.getLastArg(options::OPT_mmcu_EQ))
+ return A->getValue();
+ return "";
+
+ case llvm::Triple::nios2: {
+ return getNios2TargetCPU(Args);
+ }
+
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
@@ -295,6 +320,8 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T,
return TargetCPUName;
}
+ case llvm::Triple::bpfel:
+ case llvm::Triple::bpfeb:
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::sparcv9:
@@ -351,8 +378,20 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
// 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";
+
+#if defined(LLVM_ON_WIN32)
+ const char *Suffix = ".dll";
+#elif defined(__APPLE__)
+ const char *Suffix = ".dylib";
+#else
+ const char *Suffix = ".so";
+#endif
+
+ SmallString<1024> Plugin;
+ llvm::sys::path::native(Twine(ToolChain.getDriver().Dir) +
+ "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" +
+ Suffix,
+ Plugin);
CmdArgs.push_back(Args.MakeArgString(Plugin));
// Try to pass driver level flags relevant to LTO code generation down to
@@ -407,7 +446,7 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
CmdArgs.push_back("-plugin-opt=-data-sections");
}
- if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) {
+ if (Arg *A = getLastProfileSampleUseArg(Args)) {
StringRef FName = A->getValue();
if (!llvm::sys::fs::exists(FName))
D.Diag(diag::err_drv_no_such_file) << FName;
@@ -415,14 +454,18 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName));
}
+
+ // Need this flag to turn on new pass manager via Gold plugin.
+ if (Args.hasFlag(options::OPT_fexperimental_new_pass_manager,
+ options::OPT_fno_experimental_new_pass_manager,
+ /* Default */ false)) {
+ CmdArgs.push_back("-plugin-opt=new-pass-manager");
+ }
+
}
void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
- // In the cross-compilation case, arch-specific library path is likely
- // unavailable at runtime.
- if (TC.isCrossCompiling()) return;
-
std::string CandidateRPath = TC.getArchSpecificLibPath();
if (TC.getVFS().exists(CandidateRPath)) {
CmdArgs.push_back("-rpath");
@@ -430,11 +473,12 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
}
}
-void tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
- const ArgList &Args) {
+bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
+ const ArgList &Args, bool IsOffloadingHost,
+ bool GompNeedsRT) {
if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false))
- return;
+ return false;
switch (TC.getDriver().getOpenMPRuntime(Args)) {
case Driver::OMPRT_OMP:
@@ -442,16 +486,24 @@ void tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
break;
case Driver::OMPRT_GOMP:
CmdArgs.push_back("-lgomp");
+
+ if (GompNeedsRT)
+ CmdArgs.push_back("-lrt");
break;
case Driver::OMPRT_IOMP5:
CmdArgs.push_back("-liomp5");
break;
case Driver::OMPRT_Unknown:
// Already diagnosed.
- break;
+ return false;
}
+ if (IsOffloadingHost)
+ CmdArgs.push_back("-lomptarget");
+
addArchSpecificRPath(TC, Args, CmdArgs);
+
+ return true;
}
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
@@ -494,6 +546,7 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC,
CmdArgs.push_back("-lm");
// There's no libdl on FreeBSD or RTEMS.
if (TC.getTriple().getOS() != llvm::Triple::FreeBSD &&
+ TC.getTriple().getOS() != llvm::Triple::NetBSD &&
TC.getTriple().getOS() != llvm::Triple::RTEMS)
CmdArgs.push_back("-ldl");
}
@@ -507,26 +560,35 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
SmallVectorImpl<StringRef> &RequiredSymbols) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
// Collect shared runtimes.
- if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) {
- SharedRuntimes.push_back("asan");
+ if (SanArgs.needsSharedRt()) {
+ if (SanArgs.needsAsanRt()) {
+ SharedRuntimes.push_back("asan");
+ if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
+ HelperStaticRuntimes.push_back("asan-preinit");
+ }
+
+ if (SanArgs.needsUbsanRt()) {
+ if (SanArgs.requiresMinimalRuntime()) {
+ SharedRuntimes.push_back("ubsan_minimal");
+ } else {
+ SharedRuntimes.push_back("ubsan_standalone");
+ }
+ }
}
+
// 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.
+ if (Args.hasArg(options::OPT_shared) || SanArgs.needsSharedRt()) {
+ // Don't link static runtimes into DSOs or if -shared-libasan.
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");
- }
+ StaticRuntimes.push_back("asan");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("asan_cxx");
}
if (SanArgs.needsDfsanRt())
StaticRuntimes.push_back("dfsan");
@@ -543,9 +605,13 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("tsan_cxx");
}
if (SanArgs.needsUbsanRt()) {
- StaticRuntimes.push_back("ubsan_standalone");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("ubsan_standalone_cxx");
+ if (SanArgs.requiresMinimalRuntime()) {
+ StaticRuntimes.push_back("ubsan_minimal");
+ } else {
+ StaticRuntimes.push_back("ubsan_standalone");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("ubsan_standalone_cxx");
+ }
}
if (SanArgs.needsSafeStackRt()) {
NonWholeStaticRuntimes.push_back("safestack");
@@ -575,6 +641,16 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
NonWholeStaticRuntimes, HelperStaticRuntimes,
RequiredSymbols);
+
+ // Inject libfuzzer dependencies.
+ if (TC.getSanitizerArgs().needsFuzzer()
+ && !Args.hasArg(options::OPT_shared)) {
+
+ addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer", false, true);
+ if (!Args.hasArg(clang::driver::options::OPT_nostdlibxx))
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
+
for (auto RT : SharedRuntimes)
addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false);
for (auto RT : HelperStaticRuntimes)
@@ -677,6 +753,22 @@ Arg *tools::getLastProfileUseArg(const ArgList &Args) {
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
@@ -725,9 +817,10 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
// 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::sparcel:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
IsPICLevelTwo = false; // "-fpie"
@@ -735,6 +828,7 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
case llvm::Triple::ppc:
case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
case llvm::Triple::sparcv9:
IsPICLevelTwo = true; // "-fPIE"
break;
@@ -933,15 +1027,7 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
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;
- }
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins"));
break;
case ToolChain::RLT_Libgcc:
// Make sure libgcc is not used under MSVC environment by default
@@ -957,3 +1043,128 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
break;
}
}
+
+/// 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.
+void tools::AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ const JobAction &JA) {
+
+ // If this is not an OpenMP host toolchain, we don't need to do anything.
+ if (!JA.isHostOffloading(Action::OFK_OpenMP))
+ return;
+
+ // Create temporary linker script. Keep it if save-temps is enabled.
+ const char *LKS;
+ SmallString<256> Name = llvm::sys::path::filename(Output.getFilename());
+ if (C.getDriver().isSaveTempsEnabled()) {
+ llvm::sys::path::replace_extension(Name, "lk");
+ LKS = C.getArgs().MakeArgString(Name.c_str());
+ } else {
+ llvm::sys::path::replace_extension(Name, "");
+ Name = C.getDriver().GetTemporaryPath(Name, "lk");
+ LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str()));
+ }
+
+ // Add linker script option to the command.
+ CmdArgs.push_back("-T");
+ CmdArgs.push_back(LKS);
+
+ // Create a buffer to write the contents of the linker script.
+ std::string LksBuffer;
+ llvm::raw_string_ostream LksStream(LksBuffer);
+
+ // Get the OpenMP offload tool chains so that we can extract the triple
+ // associated with each device input.
+ auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>();
+ assert(OpenMPToolChains.first != OpenMPToolChains.second &&
+ "No OpenMP toolchains??");
+
+ // Track the input file name and device triple in order to build the script,
+ // inserting binaries in the designated sections.
+ SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo;
+
+ // Add commands to embed target binaries. We ensure that each section and
+ // image is 16-byte aligned. This is not mandatory, but increases the
+ // likelihood of data to be aligned with a cache block in several main host
+ // machines.
+ LksStream << "/*\n";
+ LksStream << " OpenMP Offload Linker Script\n";
+ LksStream << " *** Automatically generated by Clang ***\n";
+ LksStream << "*/\n";
+ LksStream << "TARGET(binary)\n";
+ auto DTC = OpenMPToolChains.first;
+ for (auto &II : Inputs) {
+ const Action *A = II.getAction();
+ // Is this a device linking action?
+ if (A && isa<LinkJobAction>(A) &&
+ A->isDeviceOffloading(Action::OFK_OpenMP)) {
+ assert(DTC != OpenMPToolChains.second &&
+ "More device inputs than device toolchains??");
+ InputBinaryInfo.push_back(std::make_pair(
+ DTC->second->getTriple().normalize(), II.getFilename()));
+ ++DTC;
+ LksStream << "INPUT(" << II.getFilename() << ")\n";
+ }
+ }
+
+ assert(DTC == OpenMPToolChains.second &&
+ "Less device inputs than device toolchains??");
+
+ LksStream << "SECTIONS\n";
+ LksStream << "{\n";
+
+ // Put each target binary into a separate section.
+ for (const auto &BI : InputBinaryInfo) {
+ LksStream << " .omp_offloading." << BI.first << " :\n";
+ LksStream << " ALIGN(0x10)\n";
+ LksStream << " {\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first
+ << " = .);\n";
+ LksStream << " " << BI.second << "\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first
+ << " = .);\n";
+ LksStream << " }\n";
+ }
+
+ // Add commands to define host entries begin and end. We use 1-byte subalign
+ // so that the linker does not add any padding and the elements in this
+ // section form an array.
+ LksStream << " .omp_offloading.entries :\n";
+ LksStream << " ALIGN(0x10)\n";
+ LksStream << " SUBALIGN(0x01)\n";
+ LksStream << " {\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n";
+ LksStream << " *(.omp_offloading.entries)\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n";
+ LksStream << " }\n";
+ LksStream << "}\n";
+ LksStream << "INSERT BEFORE .data\n";
+ LksStream.flush();
+
+ // Dump the contents of the linker script if the user requested that. We
+ // support this option to enable testing of behavior with -###.
+ if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script))
+ llvm::errs() << LksBuffer;
+
+ // If this is a dry run, do not create the linker script file.
+ if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
+ return;
+
+ // Open script file and write the contents.
+ std::error_code EC;
+ llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None);
+
+ if (EC) {
+ C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
+ return;
+ }
+
+ Lksf << LksBuffer;
+}
diff --git a/lib/Driver/ToolChains/CommonArgs.h b/lib/Driver/ToolChains/CommonArgs.h
index 252dbf590b..012f5b9f87 100644
--- a/lib/Driver/ToolChains/CommonArgs.h
+++ b/lib/Driver/ToolChains/CommonArgs.h
@@ -39,6 +39,13 @@ void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
llvm::opt::ArgStringList &CmdArgs,
const llvm::opt::ArgList &Args);
+void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ const JobAction &JA);
+
const char *SplitDebugName(const llvm::opt::ArgList &Args,
const InputInfo &Input);
@@ -59,10 +66,13 @@ void AddAssemblerKPIC(const ToolChain &ToolChain,
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);
+/// Returns true, if an OpenMP runtime has been added.
+bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ bool IsOffloadingHost = false, bool GompNeedsRT = false);
llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args);
+llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args);
bool isObjCAutoRefCount(const llvm::opt::ArgList &Args);
diff --git a/lib/Driver/ToolChains/CrossWindows.cpp b/lib/Driver/ToolChains/CrossWindows.cpp
index dcf085a45d..5049033c41 100644
--- a/lib/Driver/ToolChains/CrossWindows.cpp
+++ b/lib/Driver/ToolChains/CrossWindows.cpp
@@ -36,6 +36,7 @@ void tools::CrossWindows::Assembler::ConstructJob(
llvm_unreachable("unsupported architecture");
case llvm::Triple::arm:
case llvm::Triple::thumb:
+ case llvm::Triple::aarch64:
break;
case llvm::Triple::x86:
CmdArgs.push_back("--32");
@@ -98,6 +99,9 @@ void tools::CrossWindows::Linker::ConstructJob(
// FIXME: this is incorrect for WinCE
CmdArgs.push_back("thumb2pe");
break;
+ case llvm::Triple::aarch64:
+ CmdArgs.push_back("arm64pe");
+ break;
case llvm::Triple::x86:
CmdArgs.push_back("i386pe");
EntryPoint.append("_");
@@ -111,6 +115,7 @@ void tools::CrossWindows::Linker::ConstructJob(
switch (T.getArch()) {
default:
llvm_unreachable("unsupported architecture");
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
case llvm::Triple::x86_64:
@@ -156,21 +161,11 @@ void tools::CrossWindows::Linker::ConstructJob(
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)) {
+ if (TC.ShouldLinkCXXStdlib(Args)) {
bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
if (StaticCXX)
@@ -212,18 +207,9 @@ void tools::CrossWindows::Linker::ConstructJob(
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");
- }
-}
+ : Generic_GCC(D, T, Args) {}
-bool CrossWindowsToolChain::IsUnwindTablesDefault() const {
+bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
// FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
// not know how to emit them.
return getArch() == llvm::Triple::x86_64;
@@ -247,8 +233,15 @@ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
const Driver &D = getDriver();
const std::string &SysRoot = D.SysRoot;
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ auto AddSystemAfterIncludes = [&]() {
+ for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after))
+ addSystemInclude(DriverArgs, CC1Args, P);
+ };
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc)) {
+ AddSystemAfterIncludes();
return;
+ }
addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
@@ -256,51 +249,28 @@ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::sys::path::append(ResourceDir, "include");
addSystemInclude(DriverArgs, CC1Args, ResourceDir);
}
- for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after))
- addSystemInclude(DriverArgs, CC1Args, P);
+ AddSystemAfterIncludes();
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
}
void CrossWindowsToolChain::
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
- const llvm::Triple &Triple = getTriple();
const std::string &SysRoot = getDriver().SysRoot;
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
DriverArgs.hasArg(options::OPT_nostdincxx))
return;
- switch (GetCXXStdlibType(DriverArgs)) {
- case ToolChain::CST_Libcxx:
+ if (GetCXXStdlibType(DriverArgs) == 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:
+ if (GetCXXStdlibType(DriverArgs) == 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 {
diff --git a/lib/Driver/ToolChains/CrossWindows.h b/lib/Driver/ToolChains/CrossWindows.h
index 5375a6324a..2f66446ec7 100644
--- a/lib/Driver/ToolChains/CrossWindows.h
+++ b/lib/Driver/ToolChains/CrossWindows.h
@@ -56,7 +56,7 @@ public:
const llvm::opt::ArgList &Args);
bool IsIntegratedAssemblerDefault() const override { return true; }
- bool IsUnwindTablesDefault() const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPICDefaultForced() const override;
diff --git a/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp
index 42bf164f1b..44ec16e8b8 100644
--- a/lib/Driver/ToolChains/Cuda.cpp
+++ b/lib/Driver/ToolChains/Cuda.cpp
@@ -9,7 +9,9 @@
#include "Cuda.h"
#include "InputInfo.h"
+#include "CommonArgs.h"
#include "clang/Basic/Cuda.h"
+#include "clang/Config/config.h"
#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
@@ -47,6 +49,8 @@ static CudaVersion ParseCudaVersionFile(llvm::StringRef V) {
return CudaVersion::CUDA_75;
if (Major == 8 && Minor == 0)
return CudaVersion::CUDA_80;
+ if (Major == 9 && Minor == 0)
+ return CudaVersion::CUDA_90;
return CudaVersion::UNKNOWN;
}
@@ -83,8 +87,7 @@ CudaInstallationDetector::CudaInstallationDetector(
LibDevicePath = InstallPath + "/nvvm/libdevice";
auto &FS = D.getVFS();
- if (!(FS.exists(IncludePath) && FS.exists(BinPath) &&
- FS.exists(LibDevicePath)))
+ if (!(FS.exists(IncludePath) && FS.exists(BinPath)))
continue;
// On Linux, we have both lib and lib64 directories, and we need to choose
@@ -110,47 +113,64 @@ CudaInstallationDetector::CudaInstallationDetector(
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;
+ if (Version == CudaVersion::CUDA_90) {
+ // CUDA-9 uses single libdevice file for all GPU variants.
+ std::string FilePath = LibDevicePath + "/libdevice.10.bc";
+ if (FS.exists(FilePath)) {
+ for (const char *GpuArch :
+ {"sm_20", "sm_30", "sm_32", "sm_35", "sm_50", "sm_52", "sm_53",
+ "sm_60", "sm_61", "sm_62", "sm_70"})
+ LibDeviceMap[GpuArch] = FilePath;
+ }
+ } else {
+ 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;
+ }
}
}
}
+ // Check that we have found at least one libdevice that we can link in if
+ // -nocudalib hasn't been specified.
+ if (LibDeviceMap.empty() && !Args.hasArg(options::OPT_nocudalib))
+ continue;
+
IsValid = true;
break;
}
@@ -185,15 +205,17 @@ void CudaInstallationDetector::AddCudaIncludeArgs(
void CudaInstallationDetector::CheckCudaVersionSupportsArch(
CudaArch Arch) const {
if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN ||
- ArchsWithVersionTooLowErrors.count(Arch) > 0)
+ ArchsWithBadVersion.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);
+ auto MinVersion = MinVersionForCudaArch(Arch);
+ auto MaxVersion = MaxVersionForCudaArch(Arch);
+ if (Version < MinVersion || Version > MaxVersion) {
+ ArchsWithBadVersion.insert(Arch);
+ D.Diag(diag::err_drv_cuda_version_unsupported)
+ << CudaArchToString(Arch) << CudaVersionToString(MinVersion)
+ << CudaVersionToString(MaxVersion) << InstallPath
+ << CudaVersionToString(Version);
}
}
@@ -212,8 +234,18 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
static_cast<const toolchains::CudaToolChain &>(getToolChain());
assert(TC.getTriple().isNVPTX() && "Wrong platform");
+ StringRef GPUArchName;
+ // If this is an OpenMP action we need to extract the device architecture
+ // from the -march=arch option. This option may come from -Xopenmp-target
+ // flag or the default value.
+ if (JA.isDeviceOffloading(Action::OFK_OpenMP)) {
+ GPUArchName = Args.getLastArgValue(options::OPT_march_EQ);
+ assert(!GPUArchName.empty() && "Must have an architecture passed in.");
+ } else
+ GPUArchName = JA.getOffloadingArch();
+
// Obtain architecture from the action.
- CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch());
+ CudaArch gpu_arch = StringToCudaArch(GPUArchName);
assert(gpu_arch != CudaArch::UNKNOWN &&
"Device action expected to have an architecture.");
@@ -262,16 +294,30 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-O0");
}
+ // Pass -v to ptxas if it was passed to the driver.
+ if (Args.hasArg(options::OPT_v))
+ CmdArgs.push_back("-v");
+
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()));
+ SmallString<256> OutputFileName(Output.getFilename());
+ if (JA.isOffloading(Action::OFK_OpenMP))
+ llvm::sys::path::replace_extension(OutputFileName, "cubin");
+ CmdArgs.push_back(Args.MakeArgString(OutputFileName));
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));
+ // In OpenMP we need to generate relocatable code.
+ if (JA.isOffloading(Action::OFK_OpenMP) &&
+ Args.hasFlag(options::OPT_fopenmp_relocatable_target,
+ options::OPT_fnoopenmp_relocatable_target,
+ /*Default=*/ true))
+ CmdArgs.push_back("-c");
+
const char *Exec;
if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ))
Exec = A->getValue();
@@ -324,41 +370,133 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
+void NVPTX::OpenMPLinker::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;
+
+ // OpenMP uses nvlink to link cubin files. The result will be embedded in the
+ // host binary by the host linker.
+ assert(!JA.isHostOffloading(Action::OFK_OpenMP) &&
+ "CUDA toolchain not expected for an OpenMP host device.");
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else
+ assert(Output.isNothing() && "Invalid output.");
+ if (Args.hasArg(options::OPT_g_Flag))
+ CmdArgs.push_back("-g");
+
+ if (Args.hasArg(options::OPT_v))
+ CmdArgs.push_back("-v");
+
+ StringRef GPUArch =
+ Args.getLastArgValue(options::OPT_march_EQ);
+ assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas.");
+
+ CmdArgs.push_back("-arch");
+ CmdArgs.push_back(Args.MakeArgString(GPUArch));
+
+ // Add paths specified in LIBRARY_PATH environment variable as -L options.
+ addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
+
+ // Add paths for the default clang library path.
+ SmallString<256> DefaultLibPath =
+ llvm::sys::path::parent_path(TC.getDriver().Dir);
+ llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX);
+ CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath));
+
+ // Add linking against library implementing OpenMP calls on NVPTX target.
+ CmdArgs.push_back("-lomptarget-nvptx");
+
+ for (const auto &II : Inputs) {
+ if (II.getType() == types::TY_LLVM_IR ||
+ II.getType() == types::TY_LTO_IR ||
+ II.getType() == types::TY_LTO_BC ||
+ II.getType() == types::TY_LLVM_BC) {
+ C.getDriver().Diag(diag::err_drv_no_linker_llvm_support)
+ << getToolChain().getTripleString();
+ continue;
+ }
+
+ // Currently, we only pass the input files to the linker, we do not pass
+ // any libraries that may be valid only for the host.
+ if (!II.isFilename())
+ continue;
+
+ SmallString<256> Name(II.getFilename());
+ llvm::sys::path::replace_extension(Name, "cubin");
+
+ const char *CubinF =
+ C.addTempFile(C.getArgs().MakeArgString(Name));
+
+ CmdArgs.push_back(CubinF);
+ }
+
+ AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA);
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("nvlink"));
+ 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)
+ const ToolChain &HostTC, const ArgList &Args,
+ const Action::OffloadKind OK)
: ToolChain(D, Triple, Args), HostTC(HostTC),
- CudaInstallation(D, HostTC.getTriple(), Args) {
+ CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) {
if (CudaInstallation.isValid())
getProgramPaths().push_back(CudaInstallation.getBinPath());
+ // Lookup binaries into the driver directory, this is used to
+ // discover the clang-offload-bundler executable.
+ getProgramPaths().push_back(getDriver().Dir);
}
void CudaToolChain::addClangTargetOptions(
const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- HostTC.addClangTargetOptions(DriverArgs, CC1Args);
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const {
+ HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
+
+ StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
+ assert(!GpuArch.empty() && "Must have an explicit GPU arch.");
+ assert((DeviceOffloadingKind == Action::OFK_OpenMP ||
+ DeviceOffloadingKind == Action::OFK_Cuda) &&
+ "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs.");
- CC1Args.push_back("-fcuda-is-device");
+ if (DeviceOffloadingKind == Action::OFK_Cuda) {
+ CC1Args.push_back("-fcuda-is-device");
- if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
- options::OPT_fno_cuda_flush_denormals_to_zero, false))
- CC1Args.push_back("-fcuda-flush-denormals-to-zero");
+ if (DriverArgs.hasFlag(options::OPT_fcuda_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.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()) {
+ if (DeviceOffloadingKind == Action::OFK_OpenMP &&
+ DriverArgs.hasArg(options::OPT_S))
+ return;
+
getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch;
return;
}
@@ -366,11 +504,17 @@ void CudaToolChain::addClangTargetOptions(
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");
+ if (CudaInstallation.version() >= CudaVersion::CUDA_90) {
+ // CUDA-9 uses new instructions that are only available in PTX6.0
+ CC1Args.push_back("-target-feature");
+ CC1Args.push_back("+ptx60");
+ } else {
+ // 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,
@@ -396,6 +540,30 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
const OptTable &Opts = getDriver().getOpts();
+ // For OpenMP device offloading, append derived arguments. Make sure
+ // flags are not duplicated.
+ // Also append the compute capability.
+ if (DeviceOffloadKind == Action::OFK_OpenMP) {
+ for (Arg *A : Args) {
+ bool IsDuplicate = false;
+ for (Arg *DALArg : *DAL) {
+ if (A == DALArg) {
+ IsDuplicate = true;
+ break;
+ }
+ }
+ if (!IsDuplicate)
+ DAL->append(A);
+ }
+
+ StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ);
+ if (Arch.empty())
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
+ CLANG_OPENMP_NVPTX_DEFAULT_ARCH);
+
+ return DAL;
+ }
+
for (Arg *A : Args) {
if (A->getOption().matches(options::OPT_Xarch__)) {
// Skip this argument unless the architecture matches BoundArch
@@ -442,6 +610,8 @@ Tool *CudaToolChain::buildAssembler() const {
}
Tool *CudaToolChain::buildLinker() const {
+ if (OK == Action::OFK_OpenMP)
+ return new tools::NVPTX::OpenMPLinker(*this);
return new tools::NVPTX::Linker(*this);
}
diff --git a/lib/Driver/ToolChains/Cuda.h b/lib/Driver/ToolChains/Cuda.h
index acdb4c4efd..414c9445c7 100644
--- a/lib/Driver/ToolChains/Cuda.h
+++ b/lib/Driver/ToolChains/Cuda.h
@@ -40,7 +40,7 @@ private:
// CUDA architectures for which we have raised an error in
// CheckCudaVersionSupportsArch.
- mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors;
+ mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion;
public:
CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
@@ -112,6 +112,20 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
const char *LinkingOutput) const override;
};
+class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool {
+ public:
+ OpenMPLinker(const ToolChain &TC)
+ : Tool("NVPTX::OpenMPLinker", "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
@@ -120,7 +134,8 @@ 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);
+ const ToolChain &HostTC, const llvm::opt::ArgList &Args,
+ const Action::OffloadKind OK);
virtual const llvm::Triple *getAuxTriple() const override {
return &HostTC.getTriple();
@@ -130,7 +145,8 @@ public:
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;
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
// Never try to use the integrated assembler with CUDA; always fork out to
// ptxas.
@@ -168,6 +184,9 @@ public:
protected:
Tool *buildAssembler() const override; // ptxas
Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
+
+private:
+ const Action::OffloadKind OK;
};
} // end namespace toolchains
diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp
index 4cddf65c6c..39c4525f84 100644
--- a/lib/Driver/ToolChains/Darwin.cpp
+++ b/lib/Driver/ToolChains/Darwin.cpp
@@ -10,6 +10,7 @@
#include "Darwin.h"
#include "Arch/ARM.h"
#include "CommonArgs.h"
+#include "clang/Basic/AlignedAllocation.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Driver/Compilation.h"
@@ -67,14 +68,14 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) {
const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str);
- unsigned ArchKind = llvm::ARM::parseArch(Str);
+ llvm::ARM::ArchKind 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) {
+ else if (ArchKind == llvm::ARM::ArchKind::ARMV6M ||
+ ArchKind == llvm::ARM::ArchKind::ARMV7M ||
+ ArchKind == llvm::ARM::ArchKind::ARMV7EM) {
T.setOS(llvm::Triple::UnknownOS);
T.setObjectFormat(llvm::Triple::MachO);
}
@@ -493,7 +494,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getSanitizerArgs().needsSafeStackRt()) {
getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs,
"libclang_rt.safestack_osx.a",
- /*AlwaysLink=*/true);
+ toolchains::Darwin::RLO_AlwaysLink);
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
@@ -548,10 +549,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism)));
}
+ if (getToolChain().ShouldLinkCXXStdlib(Args))
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
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.
@@ -739,8 +739,8 @@ static const char *ArmMachOArchName(StringRef Arch) {
}
static const char *ArmMachOArchNameCPU(StringRef CPU) {
- unsigned ArchKind = llvm::ARM::parseCPUArch(CPU);
- if (ArchKind == llvm::ARM::AK_INVALID)
+ llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU);
+ if (ArchKind == llvm::ARM::ArchKind::INVALID)
return nullptr;
StringRef Arch = llvm::ARM::getArchName(ArchKind);
@@ -897,10 +897,11 @@ unsigned DarwinClang::GetDefaultDwarfVersion() const {
}
void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
- StringRef DarwinLibName, bool AlwaysLink,
- bool IsEmbedded, bool AddRPath) const {
+ StringRef DarwinLibName,
+ RuntimeLinkOptions Opts) const {
SmallString<128> Dir(getDriver().ResourceDir);
- llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin");
+ llvm::sys::path::append(
+ Dir, "lib", (Opts & RLO_IsEmbedded) ? "macho_embedded" : "darwin");
SmallString<128> P(Dir);
llvm::sys::path::append(P, DarwinLibName);
@@ -908,14 +909,19 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
// 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));
+ if ((Opts & RLO_AlwaysLink) || getVFS().exists(P)) {
+ const char *LibArg = Args.MakeArgString(P);
+ if (Opts & RLO_FirstLink)
+ CmdArgs.insert(CmdArgs.begin(), LibArg);
+ else
+ CmdArgs.push_back(LibArg);
+ }
// 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) {
+ if (Opts & RLO_AddRPath) {
assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library");
// Add @executable_path to rpath to support having the dylib copied with
@@ -980,24 +986,56 @@ StringRef Darwin::getOSLibraryNameSuffix() const {
llvm_unreachable("Unsupported platform");
}
+/// Check if the link command contains a symbol export directive.
+static bool hasExportSymbolDirective(const ArgList &Args) {
+ for (Arg *A : Args) {
+ if (!A->getOption().matches(options::OPT_Wl_COMMA) &&
+ !A->getOption().matches(options::OPT_Xlinker))
+ continue;
+ if (A->containsValue("-exported_symbols_list") ||
+ A->containsValue("-exported_symbol"))
+ return true;
+ }
+ return false;
+}
+
+/// Add an export directive for \p Symbol to the link command.
+static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) {
+ CmdArgs.push_back("-exported_symbol");
+ CmdArgs.push_back(Symbol);
+}
+
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);
+ AddLinkRuntimeLib(
+ Args, CmdArgs,
+ (Twine("libclang_rt.profile_") + getOSLibraryNameSuffix() + ".a").str(),
+ RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink));
+
+ // If we have a symbol export directive and we're linking in the profile
+ // runtime, automatically export symbols necessary to implement some of the
+ // runtime's functionality.
+ if (hasExportSymbolDirective(Args)) {
+ addExportedSymbol(CmdArgs, "_VPMergeHook");
+ addExportedSymbol(CmdArgs, "___llvm_profile_filename");
+ addExportedSymbol(CmdArgs, "___llvm_profile_raw_version");
+ addExportedSymbol(CmdArgs, "_lprofCurFilename");
+ }
}
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);
+ StringRef Sanitizer,
+ bool Shared) const {
+ auto RLO = RuntimeLinkOptions(RLO_AlwaysLink | (Shared ? RLO_AddRPath : 0U));
+ AddLinkRuntimeLib(Args, CmdArgs,
+ (Twine("libclang_rt.") + Sanitizer + "_" +
+ getOSLibraryNameSuffix() +
+ (Shared ? "_dynamic.dylib" : ".a"))
+ .str(),
+ RLO);
}
ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType(
@@ -1035,15 +1073,26 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
const SanitizerArgs &Sanitize = getSanitizerArgs();
if (Sanitize.needsAsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
+ if (Sanitize.needsLsanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
if (Sanitize.needsUbsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
+ AddLinkSanitizerLibArgs(Args, CmdArgs,
+ Sanitize.requiresMinimalRuntime() ? "ubsan_minimal"
+ : "ubsan",
+ Sanitize.needsSharedRt());
if (Sanitize.needsTsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
+ if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
+
+ // Libfuzzer is written in C++ and requires libcxx.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
if (Sanitize.needsStatsRt()) {
StringRef OS = isTargetMacOS() ? "osx" : "iossim";
AddLinkRuntimeLib(Args, CmdArgs,
(Twine("libclang_rt.stats_client_") + OS + ".a").str(),
- /*AlwaysLink=*/true);
+ RLO_AlwaysLink);
AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
}
if (Sanitize.needsEsanRt())
@@ -1102,6 +1151,27 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
+/// Returns the most appropriate macOS target version for the current process.
+///
+/// If the macOS SDK version is the same or earlier than the system version,
+/// then the SDK version is returned. Otherwise the system version is returned.
+static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) {
+ unsigned Major, Minor, Micro;
+ llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
+ if (!SystemTriple.isMacOSX())
+ return MacOSSDKVersion;
+ SystemTriple.getMacOSXVersion(Major, Minor, Micro);
+ VersionTuple SystemVersion(Major, Minor, Micro);
+ bool HadExtra;
+ if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro,
+ HadExtra))
+ return MacOSSDKVersion;
+ VersionTuple SDKVersion(Major, Minor, Micro);
+ if (SDKVersion > SystemVersion)
+ return SystemVersion.getAsString();
+ return MacOSSDKVersion;
+}
+
void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
const OptTable &Opts = getDriver().getOpts();
@@ -1125,9 +1195,32 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
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);
+ Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ,
+ options::OPT_mios_simulator_version_min_EQ);
+ Arg *TvOSVersion =
+ Args.getLastArg(options::OPT_mtvos_version_min_EQ,
+ options::OPT_mtvos_simulator_version_min_EQ);
+ Arg *WatchOSVersion =
+ Args.getLastArg(options::OPT_mwatchos_version_min_EQ,
+ options::OPT_mwatchos_simulator_version_min_EQ);
+
+ unsigned Major, Minor, Micro;
+ bool HadExtra;
+
+ // The iOS deployment target that is explicitly specified via a command line
+ // option or an environment variable.
+ std::string ExplicitIOSDeploymentTargetStr;
+
+ if (iOSVersion)
+ ExplicitIOSDeploymentTargetStr = iOSVersion->getAsString(Args);
+
+ // Add a macro to differentiate between m(iphone|tv|watch)os-version-min=X.Y and
+ // -m(iphone|tv|watch)simulator-version-min=X.Y.
+ if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ) ||
+ Args.hasArg(options::OPT_mtvos_simulator_version_min_EQ) ||
+ Args.hasArg(options::OPT_mwatchos_simulator_version_min_EQ))
+ Args.append(Args.MakeSeparateArg(nullptr, Opts.getOption(options::OPT_D),
+ " __APPLE_EMBEDDED_SIMULATOR__=1"));
if (OSXVersion && (iOSVersion || TvOSVersion || WatchOSVersion)) {
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
@@ -1162,6 +1255,10 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET"))
WatchOSTarget = env;
+ if (!iOSTarget.empty())
+ ExplicitIOSDeploymentTargetStr =
+ std::string("IPHONEOS_DEPLOYMENT_TARGET=") + iOSTarget;
+
// If there is no command-line argument to specify the Target version and
// no environment variable defined, see if we can set the default based
// on -isysroot.
@@ -1181,7 +1278,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
SDK.startswith("iPhoneSimulator"))
iOSTarget = Version;
else if (SDK.startswith("MacOSX"))
- OSXTarget = Version;
+ OSXTarget = getSystemOrSDKMacOSVersion(Version);
else if (SDK.startswith("WatchOS") ||
SDK.startswith("WatchSimulator"))
WatchOSTarget = Version;
@@ -1193,28 +1290,58 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
}
- // If no OSX or iOS target has been specified, try to guess platform
- // from arch name and compute the version from the triple.
+ // If no OS targets have been specified, try to guess platform from -target
+ // or arch name and compute the version from the triple.
if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() &&
WatchOSTarget.empty()) {
- 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::Triple::OSType OSTy = llvm::Triple::UnknownOS;
+
+ // Set the OSTy based on -target if -arch isn't present.
+ if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch)) {
+ OSTy = getTriple().getOS();
+ } else {
+ StringRef MachOArchName = getMachOArchName(Args);
+ if (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
+ MachOArchName == "arm64")
+ OSTy = llvm::Triple::IOS;
+ else if (MachOArchName == "armv7k")
+ OSTy = llvm::Triple::WatchOS;
+ else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
+ MachOArchName != "armv7em")
+ OSTy = llvm::Triple::MacOSX;
+ }
+
+
+ if (OSTy != llvm::Triple::UnknownOS) {
+ unsigned Major, Minor, Micro;
+ std::string *OSTarget;
+
+ switch (OSTy) {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ if (!getTriple().getMacOSXVersion(Major, Minor, Micro))
+ getDriver().Diag(diag::err_drv_invalid_darwin_version)
+ << getTriple().getOSName();
+ OSTarget = &OSXTarget;
+ break;
+ case llvm::Triple::IOS:
+ getTriple().getiOSVersion(Major, Minor, Micro);
+ OSTarget = &iOSTarget;
+ break;
+ case llvm::Triple::TvOS:
+ getTriple().getOSVersion(Major, Minor, Micro);
+ OSTarget = &TvOSTarget;
+ break;
+ case llvm::Triple::WatchOS:
+ getTriple().getWatchOSVersion(Major, Minor, Micro);
+ OSTarget = &WatchOSTarget;
+ break;
+ default:
+ llvm_unreachable("Unexpected OS type");
+ break;
}
- llvm::raw_string_ostream(OSXTarget) << Major << '.' << Minor << '.'
+
+ llvm::raw_string_ostream(*OSTarget) << Major << '.' << Minor << '.'
<< Micro;
}
}
@@ -1279,8 +1406,6 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
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!");
@@ -1296,6 +1421,20 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< iOSVersion->getAsString(Args);
+ // For 32-bit targets, the deployment target for iOS has to be earlier than
+ // iOS 11.
+ if (getTriple().isArch32Bit() && Major >= 11) {
+ // If the deployment target is explicitly specified, print a diagnostic.
+ if (!ExplicitIOSDeploymentTargetStr.empty()) {
+ getDriver().Diag(diag::warn_invalid_ios_deployment_target)
+ << ExplicitIOSDeploymentTargetStr;
+ // Otherwise, set it to 10.99.99.
+ } else {
+ Major = 10;
+ Minor = 99;
+ Micro = 99;
+ }
+ }
} else if (Platform == TvOS) {
if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
@@ -1635,7 +1774,38 @@ void MachO::AddLinkRuntimeLibArgs(const ArgList &Args,
: "soft";
CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a";
- AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true);
+ AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, RLO_IsEmbedded);
+}
+
+bool Darwin::isAlignedAllocationUnavailable() const {
+ llvm::Triple::OSType OS;
+
+ switch (TargetPlatform) {
+ case MacOS: // Earlier than 10.13.
+ OS = llvm::Triple::MacOSX;
+ break;
+ case IPhoneOS:
+ case IPhoneOSSimulator:
+ OS = llvm::Triple::IOS;
+ break;
+ case TvOS:
+ case TvOSSimulator: // Earlier than 11.0.
+ OS = llvm::Triple::TvOS;
+ break;
+ case WatchOS:
+ case WatchOSSimulator: // Earlier than 4.0.
+ OS = llvm::Triple::WatchOS;
+ break;
+ }
+
+ return TargetVersion < alignedAllocMinVersion(OS);
+}
+
+void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const {
+ if (isAlignedAllocationUnavailable())
+ CC1Args.push_back("-faligned-alloc-unavailable");
}
DerivedArgList *
@@ -1671,7 +1841,8 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
A = *it;
assert(A->getOption().getID() == options::OPT_static &&
"missing expected -static argument");
- it = DAL->getArgs().erase(it);
+ *it = nullptr;
+ ++it;
}
}
@@ -1706,8 +1877,13 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
return DAL;
}
-bool MachO::IsUnwindTablesDefault() const {
- return getArch() == llvm::Triple::x86_64;
+bool MachO::IsUnwindTablesDefault(const ArgList &Args) const {
+ // Unwind tables are not emitted if -fno-exceptions is supplied (except when
+ // targeting x86_64).
+ return getArch() == llvm::Triple::x86_64 ||
+ (!UseSjLjExceptions(Args) &&
+ Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
+ true));
}
bool MachO::UseDwarfDebugFlags() const {
@@ -1878,6 +2054,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Leak;
+ Res |= SanitizerKind::Fuzzer;
+ Res |= SanitizerKind::FuzzerNoLink;
+ Res |= SanitizerKind::Function;
if (isTargetMacOS()) {
if (!isMacosxVersionLT(10, 9))
Res |= SanitizerKind::Vptr;
diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h
index 984f8ef0c4..bcc76111a4 100644
--- a/lib/Driver/ToolChains/Darwin.h
+++ b/lib/Driver/ToolChains/Darwin.h
@@ -152,6 +152,9 @@ public:
llvm::opt::ArgStringList &CmdArgs) const {}
/// Add the linker arguments to link the compiler runtime library.
+ ///
+ /// FIXME: This API is intended for use with embedded libraries only, and is
+ /// misleadingly named.
virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
@@ -169,10 +172,26 @@ public:
/// Is the target either iOS or an iOS simulator?
bool isTargetIOSBased() const { return false; }
+ /// Options to control how a runtime library is linked.
+ enum RuntimeLinkOptions : unsigned {
+ /// Link the library in even if it can't be found in the VFS.
+ RLO_AlwaysLink = 1 << 0,
+
+ /// Use the embedded runtime from the macho_embedded directory.
+ RLO_IsEmbedded = 1 << 1,
+
+ /// Emit rpaths for @executable_path as well as the resource directory.
+ RLO_AddRPath = 1 << 2,
+
+ /// Link the library in before any others.
+ RLO_FirstLink = 1 << 3,
+ };
+
+ /// Add a runtime library to the list of items to link.
void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- StringRef DarwinLibName, bool AlwaysLink = false,
- bool IsEmbedded = false, bool AddRPath = false) const;
+ StringRef DarwinLibName,
+ RuntimeLinkOptions Opts = RuntimeLinkOptions()) const;
/// Add any profiling runtime libraries that are needed. This is essentially a
/// MachO specific version of addProfileRT in Tools.cpp.
@@ -214,7 +233,7 @@ public:
bool UseObjCMixedDispatch() const override { return true; }
- bool IsUnwindTablesDefault() const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override {
return ToolChain::RLT_CompilerRT;
@@ -382,6 +401,15 @@ protected:
return TargetVersion < VersionTuple(V0, V1, V2);
}
+ /// Return true if c++17 aligned allocation/deallocation functions are not
+ /// implemented in the c++ standard library of the deployment target we are
+ /// targeting.
+ bool isAlignedAllocationUnavailable() const;
+
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
StringRef getPlatformFamily() const;
static StringRef getSDKName(StringRef isysroot);
StringRef getOSLibraryNameSuffix() const;
@@ -478,7 +506,8 @@ public:
private:
void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- StringRef Sanitizer) const;
+ StringRef Sanitizer,
+ bool shared = true) const;
};
} // end namespace toolchains
diff --git a/lib/Driver/ToolChains/DragonFly.cpp b/lib/Driver/ToolChains/DragonFly.cpp
index bd2c7fc6c4..648469e4ce 100644
--- a/lib/Driver/ToolChains/DragonFly.cpp
+++ b/lib/Driver/ToolChains/DragonFly.cpp
@@ -127,7 +127,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (getToolChain().ShouldLinkCXXStdlib(Args))
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
diff --git a/lib/Driver/ToolChains/FreeBSD.cpp b/lib/Driver/ToolChains/FreeBSD.cpp
index c6626e922e..2f066cf0cc 100644
--- a/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/lib/Driver/ToolChains/FreeBSD.cpp
@@ -240,7 +240,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
addOpenMPRuntime(CmdArgs, ToolChain, Args);
if (D.CCCIsCXX()) {
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
else
diff --git a/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp
index b8757cf4aa..10ee7b7829 100644
--- a/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/lib/Driver/ToolChains/Fuchsia.cpp
@@ -14,6 +14,7 @@
#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/Path.h"
@@ -43,9 +44,10 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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 (llvm::sys::path::filename(Exec).equals_lower("ld.lld") ||
+ llvm::sys::path::stem(Exec).equals_lower("ld.lld")) {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("rodynamic");
}
if (!D.SysRoot.empty())
@@ -60,27 +62,28 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_s))
CmdArgs.push_back("-s");
- if (Args.hasArg(options::OPT_r))
+ if (Args.hasArg(options::OPT_r)) {
CmdArgs.push_back("-r");
- else
+ } else {
CmdArgs.push_back("--build-id");
+ CmdArgs.push_back("--hash-style=gnu");
+ }
- if (!Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--eh-frame-hdr");
+ 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"));
- }
+ if (!Args.hasArg(options::OPT_shared)) {
+ std::string Dyld = D.DyldPrefix;
+ if (ToolChain.getSanitizerArgs().needsAsanRt() &&
+ ToolChain.getSanitizerArgs().needsSharedRt())
+ Dyld += "asan/";
+ Dyld += "ld.so.1";
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back(Args.MakeArgString(Dyld));
}
CmdArgs.push_back("-o");
@@ -97,6 +100,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ addSanitizerRuntimes(ToolChain, Args, CmdArgs);
+
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
@@ -104,13 +109,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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");
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
@@ -131,16 +131,44 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
+static std::string normalizeTriple(llvm::Triple Triple) {
+ SmallString<64> T;
+ T += Triple.getArchName();
+ T += "-";
+ T += Triple.getOSName();
+ return T.str();
+}
+
+static std::string getTargetDir(const Driver &D,
+ llvm::Triple Triple) {
+ SmallString<128> P(llvm::sys::path::parent_path(D.Dir));
+ llvm::sys::path::append(P, "lib", normalizeTriple(Triple));
+ return P.str();
+}
+
Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
-
- getFilePaths().push_back(D.SysRoot + "/lib");
- getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia");
+ : ToolChain(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != D.Dir)
+ getProgramPaths().push_back(D.Dir);
+
+ SmallString<128> P(getTargetDir(D, getTriple()));
+ llvm::sys::path::append(P, "lib");
+ getFilePaths().push_back(P.str());
+
+ if (!D.SysRoot.empty()) {
+ SmallString<128> P(D.SysRoot);
+ llvm::sys::path::append(P, "lib");
+ getFilePaths().push_back(P.str());
+ }
}
-Tool *Fuchsia::buildAssembler() const {
- return new tools::gnutools::Assembler(*this);
+std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
+ Triple.setTriple(normalizeTriple(Triple));
+ return Triple.getTriple();
}
Tool *Fuchsia::buildLinker() const {
@@ -172,7 +200,8 @@ Fuchsia::GetCXXStdlibType(const ArgList &Args) const {
}
void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
options::OPT_fno_use_init_array, true))
CC1Args.push_back("-fuse-init-array");
@@ -207,23 +236,49 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return;
}
- addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include");
+ if (!D.SysRoot.empty()) {
+ SmallString<128> P(D.SysRoot);
+ llvm::sys::path::append(P, "include");
+ addExternCSystemInclude(DriverArgs, CC1Args, P.str());
+ }
}
-std::string Fuchsia::findLibCxxIncludePath() const {
- return getDriver().SysRoot + "/include/c++/v1";
+void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx: {
+ SmallString<128> P(getTargetDir(getDriver(), getTriple()));
+ llvm::sys::path::append(P, "include", "c++", "v1");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ break;
+ }
+
+ default:
+ llvm_unreachable("invalid stdlib name");
+ }
}
void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- (void) GetCXXStdlibType(Args);
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- CmdArgs.push_back("-lunwind");
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lunwind");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ llvm_unreachable("invalid stdlib name");
+ }
}
SanitizerMask Fuchsia::getSupportedSanitizers() const {
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::SafeStack;
+ Res |= SanitizerKind::Address;
return Res;
}
diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h
index 1a8c9903fe..6d825fb817 100644
--- a/lib/Driver/ToolChains/Fuchsia.h
+++ b/lib/Driver/ToolChains/Fuchsia.h
@@ -35,18 +35,33 @@ public:
namespace toolchains {
-class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF {
+class LLVM_LIBRARY_VISIBILITY Fuchsia : public ToolChain {
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; }
+ bool IsMathErrnoDefault() const override { return false; }
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Libcxx;
+ }
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
+ return true;
+ }
+ bool isPICDefault() const override { return false; }
+ bool isPIEDefault() const override { return true; }
+ bool isPICDefaultForced() const override { return false; }
llvm::DebuggerKind getDefaultDebuggerTuning() const override {
return llvm::DebuggerKind::GDB;
}
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType) const override;
+
SanitizerMask getSupportedSanitizers() const override;
RuntimeLibType
@@ -55,20 +70,22 @@ public:
GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- std::string findLibCxxIncludePath() const override;
+ void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
const char *getDefaultLinker() const override {
- return "lld";
+ return "ld.lld";
}
protected:
- Tool *buildAssembler() const override;
Tool *buildLinker() const override;
};
diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp
index fe3c0191bb..08282ff003 100644
--- a/lib/Driver/ToolChains/Gnu.cpp
+++ b/lib/Driver/ToolChains/Gnu.cpp
@@ -11,6 +11,7 @@
#include "Linux.h"
#include "Arch/ARM.h"
#include "Arch/Mips.h"
+#include "Arch/PPC.h"
#include "Arch/Sparc.h"
#include "Arch/SystemZ.h"
#include "CommonArgs.h"
@@ -203,133 +204,12 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA,
// 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) {
+ // Do not add the XRay runtime to shared libraries.
+ if (Args.hasArg(options::OPT_shared))
+ return false;
+
if (Args.hasFlag(options::OPT_fxray_instrument,
options::OPT_fnoxray_instrument, false)) {
CmdArgs.push_back("-whole-archive");
@@ -337,6 +217,7 @@ static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-no-whole-archive");
return true;
}
+
return false;
}
@@ -346,9 +227,6 @@ static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lrt");
CmdArgs.push_back("-lm");
- CmdArgs.push_back("-latomic");
-
- TC.AddCXXStdlibLibArgs(Args, CmdArgs);
if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
CmdArgs.push_back("-ldl");
@@ -404,6 +282,17 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
}
}
+static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) {
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static))
+ return false;
+
+ Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie,
+ options::OPT_nopie);
+ if (!A)
+ return ToolChain.isPIEDefault();
+ return A->getOption().matches(options::OPT_pie);
+}
+
void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -418,9 +307,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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 IsPIE = getPIE(Args, ToolChain);
const bool HasCRTBeginEndFiles =
ToolChain.getTriple().hasEnvironment() ||
(ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies);
@@ -563,13 +450,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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");
+ if (ToolChain.ShouldLinkCXXStdlib(Args)) {
+ 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.
@@ -589,37 +478,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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)) {
+ // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
+ // require librt. Most modern Linux platforms do, but some may not.
+ if (addOpenMPRuntime(CmdArgs, ToolChain, Args,
+ JA.isHostOffloading(Action::OFK_OpenMP),
+ /* GompNeedsRT= */ true))
// OpenMP runtimes implies pthreads when using the GNU toolchain.
// FIXME: Does this really make sense for all GNU toolchains?
WantPthread = true;
- // 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)
@@ -675,6 +542,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
+ const auto &D = getToolChain().getDriver();
+
claimNoWarnArgs(Args);
ArgStringList CmdArgs;
@@ -685,6 +554,23 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
std::tie(RelocationModel, PICLevel, IsPIE) =
ParsePICArgs(getToolChain(), Args);
+ if (const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ)) {
+ if (A->getOption().getID() == options::OPT_gz) {
+ CmdArgs.push_back("-compress-debug-sections");
+ } else {
+ StringRef Value = A->getValue();
+ if (Value == "none") {
+ CmdArgs.push_back("-compress-debug-sections=none");
+ } else if (Value == "zlib" || Value == "zlib-gnu") {
+ CmdArgs.push_back(
+ Args.MakeArgString("-compress-debug-sections=" + Twine(Value)));
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
+ }
+
switch (getToolChain().getArch()) {
default:
break;
@@ -699,22 +585,28 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
else
CmdArgs.push_back("--64");
break;
- case llvm::Triple::ppc:
+ case llvm::Triple::ppc: {
CmdArgs.push_back("-a32");
CmdArgs.push_back("-mppc");
- CmdArgs.push_back("-many");
+ CmdArgs.push_back(
+ ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple())));
break;
- case llvm::Triple::ppc64:
+ }
+ case llvm::Triple::ppc64: {
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64");
- CmdArgs.push_back("-many");
+ CmdArgs.push_back(
+ ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple())));
break;
- case llvm::Triple::ppc64le:
+ }
+ case llvm::Triple::ppc64le: {
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64");
- CmdArgs.push_back("-many");
CmdArgs.push_back("-mlittle-endian");
+ CmdArgs.push_back(
+ ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple())));
break;
+ }
case llvm::Triple::sparc:
case llvm::Triple::sparcel: {
CmdArgs.push_back("-32");
@@ -773,6 +665,12 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
break;
}
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be: {
+ Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
+ break;
+ }
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
@@ -912,6 +810,8 @@ static bool isSoftFloatABI(const ArgList &Args) {
A->getValue() == StringRef("soft"));
}
+/// \p Flag must be a flag accepted by the driver with its leading '-' removed,
+// otherwise '-print-multi-lib' will not emit them correctly.
static void addMultilibFlag(bool Enabled, const char *const Flag,
std::vector<std::string> &Flags) {
if (Enabled)
@@ -1425,12 +1325,12 @@ bool clang::driver::findMIPSMultilibs(const Driver &D,
if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
TargetTriple.getOS() == llvm::Triple::Linux &&
- TargetTriple.getEnvironment() == llvm::Triple::GNU)
+ TargetTriple.isGNUEnvironment())
return findMipsMtiMultilibs(Flags, NonExistent, Result);
if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies &&
TargetTriple.getOS() == llvm::Triple::Linux &&
- TargetTriple.getEnvironment() == llvm::Triple::GNU)
+ TargetTriple.isGNUEnvironment())
return findMipsImgMultilibs(Flags, NonExistent, Result);
if (findMipsCsMultilibs(Flags, NonExistent, Result))
@@ -1456,17 +1356,17 @@ static void findAndroidArmMultilibs(const Driver &D,
// Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb.
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
Multilib ArmV7Multilib = makeMultilib("/armv7-a")
- .flag("+armv7")
- .flag("-thumb");
+ .flag("+march=armv7-a")
+ .flag("-mthumb");
Multilib ThumbMultilib = makeMultilib("/thumb")
- .flag("-armv7")
- .flag("+thumb");
+ .flag("-march=armv7-a")
+ .flag("+mthumb");
Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb")
- .flag("+armv7")
- .flag("+thumb");
+ .flag("+march=armv7-a")
+ .flag("+mthumb");
Multilib DefaultMultilib = makeMultilib("")
- .flag("-armv7")
- .flag("-thumb");
+ .flag("-march=armv7-a")
+ .flag("-mthumb");
MultilibSet AndroidArmMultilibs =
MultilibSet()
.Either(ThumbMultilib, ArmV7Multilib,
@@ -1480,12 +1380,12 @@ static void findAndroidArmMultilibs(const Driver &D,
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);
+ (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::ISAKind::THUMB);
bool IsArmV7Mode = (IsArmArch || IsThumbArch) &&
(llvm::ARM::parseArchVersion(Arch) == 7 ||
(IsArmArch && Arch == "" && IsV7SubArch));
- addMultilibFlag(IsArmV7Mode, "armv7", Flags);
- addMultilibFlag(IsThumbMode, "thumb", Flags);
+ addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags);
+ addMultilibFlag(IsThumbMode, "mthumb", Flags);
if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib))
Result.Multilibs = AndroidArmMultilibs;
@@ -1615,6 +1515,49 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
return false;
}
+/// \brief Parse a GCCVersion object out of a string of text.
+///
+/// This is the primary means of forming GCCVersion objects.
+/*static*/
+Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) {
+ const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
+ std::pair<StringRef, StringRef> First = VersionText.split('.');
+ std::pair<StringRef, StringRef> Second = First.second.split('.');
+
+ GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
+ if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
+ return BadVersion;
+ GoodVersion.MajorStr = First.first.str();
+ if (First.second.empty())
+ return GoodVersion;
+ if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
+ return BadVersion;
+ GoodVersion.MinorStr = Second.first.str();
+
+ // First look for a number prefix and parse that if present. Otherwise just
+ // stash the entire patch string in the suffix, and leave the number
+ // unspecified. This covers versions strings such as:
+ // 5 (handled above)
+ // 4.4
+ // 4.4.0
+ // 4.4.x
+ // 4.4.2-rc4
+ // 4.4.x-patched
+ // And retains any patch number it finds.
+ StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
+ if (!PatchText.empty()) {
+ if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
+ // Try to parse the number and any suffix.
+ if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
+ GoodVersion.Patch < 0)
+ return BadVersion;
+ GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
+ }
+ }
+
+ return GoodVersion;
+}
+
static llvm::StringRef getGCCToolchainDir(const ArgList &Args) {
const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain);
if (A)
@@ -1766,7 +1709,9 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
static const char *const ARMTriples[] = {"arm-linux-gnueabi",
"arm-linux-androideabi"};
static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf",
- "armv7hl-redhat-linux-gnueabi"};
+ "armv7hl-redhat-linux-gnueabi",
+ "armv6hl-suse-linux-gnueabi",
+ "armv7hl-suse-linux-gnueabi"};
static const char *const ARMebLibDirs[] = {"/lib"};
static const char *const ARMebTriples[] = {"armeb-linux-gnueabi",
"armeb-linux-androideabi"};
@@ -2176,6 +2121,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
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 =
@@ -2243,7 +2189,7 @@ void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
CudaInstallation.print(OS);
}
-bool Generic_GCC::IsUnwindTablesDefault() const {
+bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const {
return getArch() == llvm::Triple::x86_64;
}
@@ -2290,9 +2236,11 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
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)
+ // Enabled for Debian and Android mips64/mipsel, as they can precisely
+ // identify the ABI in use (Debian) or only use N64 for MIPS64 (Android).
+ // Other targets are unable to distinguish N32 from N64.
+ if (getTriple().getEnvironment() == llvm::Triple::GNUABI64 ||
+ getTriple().isAndroid())
return true;
return false;
default:
@@ -2411,16 +2359,19 @@ Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef,
void Generic_ELF::anchor() {}
void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
bool UseInitArrayDefault =
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be ||
(getTriple().getOS() == llvm::Triple::Linux &&
- (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) ||
+ ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) ||
+ getTriple().isAndroid())) ||
getTriple().getOS() == llvm::Triple::NaCl ||
(getTriple().getVendor() == llvm::Triple::MipsTechnologies &&
- !getTriple().hasEnvironment());
+ !getTriple().hasEnvironment()) ||
+ getTriple().getOS() == llvm::Triple::Solaris;
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
options::OPT_fno_use_init_array, UseInitArrayDefault))
diff --git a/lib/Driver/ToolChains/Gnu.h b/lib/Driver/ToolChains/Gnu.h
index 1dc1ad49e3..f29342b95a 100644
--- a/lib/Driver/ToolChains/Gnu.h
+++ b/lib/Driver/ToolChains/Gnu.h
@@ -284,7 +284,7 @@ public:
void printVerboseInfo(raw_ostream &OS) const override;
- bool IsUnwindTablesDefault() const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPICDefaultForced() const override;
@@ -341,7 +341,8 @@ public:
: Generic_GCC(D, Triple, Args) {}
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
};
} // end namespace toolchains
diff --git a/lib/Driver/ToolChains/Hexagon.cpp b/lib/Driver/ToolChains/Hexagon.cpp
index c143b7f898..d4ab5dc5b7 100644
--- a/lib/Driver/ToolChains/Hexagon.cpp
+++ b/lib/Driver/ToolChains/Hexagon.cpp
@@ -27,6 +27,100 @@ using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
+// Default hvx-length for various versions.
+static StringRef getDefaultHvxLength(StringRef Cpu) {
+ return llvm::StringSwitch<StringRef>(Cpu)
+ .Case("v60", "64b")
+ .Case("v62", "64b")
+ .Default("128b");
+}
+
+static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
+ // Handle deprecated HVX double warnings.
+ if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_double))
+ D.Diag(diag::warn_drv_deprecated_arg)
+ << A->getAsString(Args) << "-mhvx-length=128B";
+ if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx_double))
+ D.Diag(diag::warn_drv_deprecated_arg) << A->getAsString(Args) << "-mno-hvx";
+ // Handle the unsupported values passed to mhvx-length.
+ if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
+ StringRef Val = A->getValue();
+ if (Val != "64B" && Val != "128B")
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Val;
+ }
+}
+
+// Handle hvx target features explicitly.
+static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
+ std::vector<StringRef> &Features,
+ bool &HasHVX) {
+ // Handle HVX warnings.
+ handleHVXWarnings(D, Args);
+
+ // Add the +hvx* features based on commandline flags.
+ StringRef HVXFeature, HVXLength;
+ StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
+
+ // Handle -mhvx, -mhvx=, -mno-hvx, -mno-hvx-double.
+ if (Arg *A = Args.getLastArg(
+ options::OPT_mno_hexagon_hvx, options::OPT_mno_hexagon_hvx_double,
+ options::OPT_mhexagon_hvx, options::OPT_mhexagon_hvx_EQ)) {
+ if (A->getOption().matches(options::OPT_mno_hexagon_hvx) ||
+ A->getOption().matches(options::OPT_mno_hexagon_hvx_double)) {
+ return;
+ } else if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) {
+ HasHVX = true;
+ HVXFeature = Cpu = A->getValue();
+ HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower());
+ } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) {
+ HasHVX = true;
+ HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu);
+ }
+ Features.push_back(HVXFeature);
+ }
+
+ // Handle -mhvx-length=, -mhvx-double.
+ if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ,
+ options::OPT_mhexagon_hvx_double)) {
+ // These falgs are valid only if HVX in enabled.
+ if (!HasHVX)
+ D.Diag(diag::err_drv_invalid_hvx_length);
+ else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ))
+ HVXLength = A->getValue();
+ else if (A->getOption().matches(options::OPT_mhexagon_hvx_double))
+ HVXLength = "128b";
+ }
+ // Default hvx-length based on Cpu.
+ else if (HasHVX)
+ HVXLength = getDefaultHvxLength(Cpu);
+
+ if (!HVXLength.empty()) {
+ HVXFeature =
+ Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower());
+ Features.push_back(HVXFeature);
+ }
+}
+
+// Hexagon target features.
+void hexagon::getHexagonTargetFeatures(const Driver &D, 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");
+
+ bool HasHVX(false);
+ handleHVXTargetFeatures(D, Args, Features, HasHVX);
+}
+
// Hexagon tools start.
void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const {
@@ -248,7 +342,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
//----------------------------------------------------------------------------
if (IncStdLib && IncDefLibs) {
if (D.CCCIsCXX()) {
- HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (HTC.ShouldLinkCXXStdlib(Args))
+ HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
@@ -402,6 +497,41 @@ Tool *HexagonToolChain::buildLinker() const {
return new tools::hexagon::Linker(*this);
}
+unsigned HexagonToolChain::getOptimizationLevel(
+ const llvm::opt::ArgList &DriverArgs) const {
+ // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
+ Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
+ if (!A)
+ return 0;
+
+ if (A->getOption().matches(options::OPT_O0))
+ return 0;
+ if (A->getOption().matches(options::OPT_Ofast) ||
+ A->getOption().matches(options::OPT_O4))
+ return 3;
+ assert(A->getNumValues() != 0);
+ StringRef S(A->getValue());
+ if (S == "s" || S == "z" || S.empty())
+ return 2;
+ if (S == "g")
+ return 1;
+
+ unsigned OptLevel;
+ if (S.getAsInteger(10, OptLevel))
+ return 0;
+ return OptLevel;
+}
+
+void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ if (DriverArgs.hasArg(options::OPT_ffp_contract))
+ return;
+ unsigned OptLevel = getOptimizationLevel(DriverArgs);
+ if (OptLevel >= 3)
+ CC1Args.push_back("-ffp-contract=fast");
+}
+
void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
diff --git a/lib/Driver/ToolChains/Hexagon.h b/lib/Driver/ToolChains/Hexagon.h
index fb50ba3c72..229a08c76d 100644
--- a/lib/Driver/ToolChains/Hexagon.h
+++ b/lib/Driver/ToolChains/Hexagon.h
@@ -50,6 +50,10 @@ public:
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
+
+void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
+ std::vector<StringRef> &Features);
+
} // end namespace hexagon.
} // end namespace tools
@@ -61,11 +65,16 @@ protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
+ unsigned getOptimizationLevel(const llvm::opt::ArgList &DriverArgs) const;
+
public:
HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
~HexagonToolChain() override;
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp
index e87ef08e90..613a9f3c88 100644
--- a/lib/Driver/ToolChains/Linux.cpp
+++ b/lib/Driver/ToolChains/Linux.cpp
@@ -248,7 +248,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
ExtraOpts.push_back("--build-id");
#endif
- if (Distro.IsOpenSUSE())
+ if (IsAndroid || Distro.IsOpenSUSE())
ExtraOpts.push_back("--enable-new-dtags");
// The selection of paths to try here is designed to match the patterns which
@@ -372,49 +372,6 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
addPathIfExists(D, SysRoot + "/usr/lib", Paths);
}
-/// \brief Parse a GCCVersion object out of a string of text.
-///
-/// This is the primary means of forming GCCVersion objects.
-/*static*/
-Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
- const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
- std::pair<StringRef, StringRef> First = VersionText.split('.');
- std::pair<StringRef, StringRef> Second = First.second.split('.');
-
- GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
- if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
- return BadVersion;
- GoodVersion.MajorStr = First.first.str();
- if (First.second.empty())
- return GoodVersion;
- if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
- return BadVersion;
- GoodVersion.MinorStr = Second.first.str();
-
- // First look for a number prefix and parse that if present. Otherwise just
- // stash the entire patch string in the suffix, and leave the number
- // unspecified. This covers versions strings such as:
- // 5 (handled above)
- // 4.4
- // 4.4.0
- // 4.4.x
- // 4.4.2-rc4
- // 4.4.x-patched
- // And retains any patch number it finds.
- StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
- if (!PatchText.empty()) {
- if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
- // Try to parse the number and any suffix.
- if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
- GoodVersion.Patch < 0)
- return BadVersion;
- GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
- }
- }
-
- return GoodVersion;
-}
-
bool Linux::HasNativeLLVMSupport() const { return true; }
Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); }
@@ -853,7 +810,10 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
}
}
-bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
+bool Linux::isPIEDefault() const {
+ return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) ||
+ getSanitizerArgs().requiresPIE();
+}
SanitizerMask Linux::getSupportedSanitizers() const {
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
@@ -864,14 +824,20 @@ SanitizerMask Linux::getSupportedSanitizers() const {
getTriple().getArch() == llvm::Triple::ppc64le;
const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be;
+ const bool IsArmArch = getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb ||
+ getTriple().getArch() == llvm::Triple::armeb ||
+ getTriple().getArch() == llvm::Triple::thumbeb;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Fuzzer;
+ Res |= SanitizerKind::FuzzerNoLink;
Res |= SanitizerKind::KernelAddress;
Res |= SanitizerKind::Vptr;
Res |= SanitizerKind::SafeStack;
if (IsX86_64 || IsMIPS64 || IsAArch64)
Res |= SanitizerKind::DataFlow;
- if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86)
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64)
Res |= SanitizerKind::Leak;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64)
Res |= SanitizerKind::Thread;
diff --git a/lib/Driver/ToolChains/MSVC.cpp b/lib/Driver/ToolChains/MSVC.cpp
index 7996627f57..ae41ee9e22 100644
--- a/lib/Driver/ToolChains/MSVC.cpp
+++ b/lib/Driver/ToolChains/MSVC.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "Darwin.h"
#include "MSVC.h"
#include "CommonArgs.h"
+#include "Darwin.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Compilation.h"
@@ -25,6 +25,8 @@
#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>
@@ -44,30 +46,269 @@
#include <windows.h>
#endif
+#ifdef _MSC_VER
+// Don't support SetupApi on MinGW.
+#define USE_MSVC_SETUP_API
+
+// Make sure this comes before MSVCSetupApi.h
+#include <comdef.h>
+
+#include "MSVCSetupApi.h"
+#include "llvm/Support/COM.h"
+_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
+_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
+_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
+_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
+_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
+_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
+#endif
+
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
+// Defined below.
+// Forward declare this so there aren't too many things above the constructor.
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ std::string &value, std::string *phValue);
+
+// Check various environment variables to try and find a toolchain.
+static bool findVCToolChainViaEnvironment(std::string &Path,
+ MSVCToolChain::ToolsetLayout &VSLayout) {
+ // These variables are typically set by vcvarsall.bat
+ // when launching a developer command prompt.
+ if (llvm::Optional<std::string> VCToolsInstallDir =
+ llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
+ // This is only set by newer Visual Studios, and it leads straight to
+ // the toolchain directory.
+ Path = std::move(*VCToolsInstallDir);
+ VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
+ return true;
+ }
+ if (llvm::Optional<std::string> VCInstallDir =
+ llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
+ // If the previous variable isn't set but this one is, then we've found
+ // an older Visual Studio. This variable is set by newer Visual Studios too,
+ // so this check has to appear second.
+ // In older Visual Studios, the VC directory is the toolchain.
+ Path = std::move(*VCInstallDir);
+ VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
+ return true;
+ }
+
+ // We couldn't find any VC environment variables. Let's walk through PATH and
+ // see if it leads us to a VC toolchain bin directory. If it does, pick the
+ // first one that we find.
+ if (llvm::Optional<std::string> PathEnv =
+ llvm::sys::Process::GetEnv("PATH")) {
+ llvm::SmallVector<llvm::StringRef, 8> PathEntries;
+ llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
+ for (llvm::StringRef PathEntry : PathEntries) {
+ if (PathEntry.empty())
+ continue;
+
+ llvm::SmallString<256> ExeTestPath;
+
+ // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
+ ExeTestPath = PathEntry;
+ llvm::sys::path::append(ExeTestPath, "cl.exe");
+ if (!llvm::sys::fs::exists(ExeTestPath))
+ continue;
+
+ // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
+ // has a cl.exe. So let's check for link.exe too.
+ ExeTestPath = PathEntry;
+ llvm::sys::path::append(ExeTestPath, "link.exe");
+ if (!llvm::sys::fs::exists(ExeTestPath))
+ continue;
+
+ // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
+ llvm::StringRef TestPath = PathEntry;
+ bool IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
+ if (!IsBin) {
+ // Strip any architecture subdir like "amd64".
+ TestPath = llvm::sys::path::parent_path(TestPath);
+ IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
+ }
+ if (IsBin) {
+ llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
+ llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath);
+ if (ParentFilename == "VC") {
+ Path = ParentPath;
+ VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
+ return true;
+ }
+ if (ParentFilename == "x86ret" || ParentFilename == "x86chk"
+ || ParentFilename == "amd64ret" || ParentFilename == "amd64chk") {
+ Path = ParentPath;
+ VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal;
+ return true;
+ }
+
+ } else {
+ // This could be a new (>=VS2017) toolchain. If it is, we should find
+ // path components with these prefixes when walking backwards through
+ // the path.
+ // Note: empty strings match anything.
+ llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
+ "MSVC", "Tools", "VC"};
+
+ auto It = llvm::sys::path::rbegin(PathEntry);
+ auto End = llvm::sys::path::rend(PathEntry);
+ for (llvm::StringRef Prefix : ExpectedPrefixes) {
+ if (It == End)
+ goto NotAToolChain;
+ if (!It->startswith(Prefix))
+ goto NotAToolChain;
+ ++It;
+ }
+
+ // We've found a new toolchain!
+ // Back up 3 times (/bin/Host/arch) to get the root path.
+ llvm::StringRef ToolChainPath(PathEntry);
+ for (int i = 0; i < 3; ++i)
+ ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
+
+ Path = ToolChainPath;
+ VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
+ return true;
+ }
+
+ NotAToolChain:
+ continue;
+ }
+ }
+ return false;
+}
+
+// Query the Setup Config server for installs, then pick the newest version
+// and find its default VC toolchain.
+// This is the preferred way to discover new Visual Studios, as they're no
+// longer listed in the registry.
+static bool findVCToolChainViaSetupConfig(std::string &Path,
+ MSVCToolChain::ToolsetLayout &VSLayout) {
+#if !defined(USE_MSVC_SETUP_API)
+ return false;
+#else
+ // FIXME: This really should be done once in the top-level program's main
+ // function, as it may have already been initialized with a different
+ // threading model otherwise.
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
+ HRESULT HR;
+
+ // _com_ptr_t will throw a _com_error if a COM calls fail.
+ // The LLVM coding standards forbid exception handling, so we'll have to
+ // stop them from being thrown in the first place.
+ // The destructor will put the regular error handler back when we leave
+ // this scope.
+ struct SuppressCOMErrorsRAII {
+ static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
+
+ SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
+
+ ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
+
+ } COMErrorSuppressor;
+
+ ISetupConfigurationPtr Query;
+ HR = Query.CreateInstance(__uuidof(SetupConfiguration));
+ if (FAILED(HR))
+ return false;
+
+ IEnumSetupInstancesPtr EnumInstances;
+ HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
+ if (FAILED(HR))
+ return false;
+
+ ISetupInstancePtr Instance;
+ HR = EnumInstances->Next(1, &Instance, nullptr);
+ if (HR != S_OK)
+ return false;
+
+ ISetupInstancePtr NewestInstance;
+ Optional<uint64_t> NewestVersionNum;
+ do {
+ bstr_t VersionString;
+ uint64_t VersionNum;
+ HR = Instance->GetInstallationVersion(VersionString.GetAddress());
+ if (FAILED(HR))
+ continue;
+ HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
+ if (FAILED(HR))
+ continue;
+ if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
+ NewestInstance = Instance;
+ NewestVersionNum = VersionNum;
+ }
+ } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
+
+ if (!NewestInstance)
+ return false;
+
+ bstr_t VCPathWide;
+ HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
+ if (FAILED(HR))
+ return false;
+
+ std::string VCRootPath;
+ llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
+
+ llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
+ llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
+ "Microsoft.VCToolsVersion.default.txt");
+
+ auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
+ if (!ToolsVersionFile)
+ return false;
+
+ llvm::SmallString<256> ToolchainPath(VCRootPath);
+ llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
+ ToolsVersionFile->get()->getBuffer().rtrim());
+ if (!llvm::sys::fs::is_directory(ToolchainPath))
+ return false;
+
+ Path = ToolchainPath.str();
+ VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
+ return true;
+#endif
+}
+
+// Look in the registry for Visual Studio installs, and use that to get
+// a toolchain path. VS2017 and newer don't get added to the registry.
+// So if we find something here, we know that it's an older version.
+static bool findVCToolChainViaRegistry(std::string &Path,
+ MSVCToolChain::ToolsetLayout &VSLayout) {
+ std::string VSInstallPath;
+ if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
+ "InstallDir", VSInstallPath, nullptr) ||
+ getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
+ "InstallDir", VSInstallPath, nullptr)) {
+ if (!VSInstallPath.empty()) {
+ llvm::SmallString<256> VCPath(llvm::StringRef(
+ VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
+ llvm::sys::path::append(VCPath, "VC");
+
+ Path = VCPath.str();
+ VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
+ return true;
+ }
+ }
+ return false;
+}
+
// Try to find Exe from a Visual Studio distribution. This first tries to find
// an installed copy of Visual Studio and, failing that, looks in the PATH,
// making sure that whatever executable that's found is not a same-named exe
// from clang itself to prevent clang from falling back to itself.
static std::string FindVisualStudioExecutable(const ToolChain &TC,
- const char *Exe,
- const char *ClangProgramPath) {
+ const char *Exe) {
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;
+ 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,
@@ -76,7 +317,8 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
- const ToolChain &TC = getToolChain();
+
+ auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
assert((Output.isFilename() || Output.isNothing()) && "invalid output");
if (Output.isFilename())
@@ -92,37 +334,20 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// 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));
- }
+ 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 (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
+ if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
CmdArgs.push_back(
Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
}
@@ -150,7 +375,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (TC.getSanitizerArgs().needsAsanRt()) {
CmdArgs.push_back(Args.MakeArgString("-debug"));
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
- if (TC.getSanitizerArgs().needsSharedAsanRt() ||
+ if (TC.getSanitizerArgs().needsSharedRt() ||
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));
@@ -235,6 +460,8 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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.
@@ -247,16 +474,77 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// 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());
+ linkPath = FindVisualStudioExecutable(TC, "link.exe");
+
+#ifdef USE_WIN32
+ // When cross-compiling with VS2017 or newer, link.exe expects to have
+ // its containing bin directory at the top of PATH, followed by the
+ // native target bin directory.
+ // e.g. when compiling for x86 on an x64 host, PATH should start with:
+ // /bin/HostX64/x86;/bin/HostX64/x64
+ // This doesn't attempt to handle ToolsetLayout::DevDivInternal.
+ if (TC.getIsVS2017OrNewer() &&
+ llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
+ auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
+
+ auto EnvBlockWide =
+ std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
+ GetEnvironmentStringsW(), FreeEnvironmentStringsW);
+ if (!EnvBlockWide)
+ goto SkipSettingEnvironment;
+
+ size_t EnvCount = 0;
+ size_t EnvBlockLen = 0;
+ while (EnvBlockWide[EnvBlockLen] != L'\0') {
+ ++EnvCount;
+ EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
+ 1 /*string null-terminator*/;
+ }
+ ++EnvBlockLen; // add the block null-terminator
+
+ std::string EnvBlock;
+ if (!llvm::convertUTF16ToUTF8String(
+ llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
+ EnvBlockLen * sizeof(EnvBlockWide[0])),
+ EnvBlock))
+ goto SkipSettingEnvironment;
+
+ Environment.reserve(EnvCount);
+
+ // Now loop over each string in the block and copy them into the
+ // environment vector, adjusting the PATH variable as needed when we
+ // find it.
+ for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
+ llvm::StringRef EnvVar(Cursor);
+ if (EnvVar.startswith_lower("path=")) {
+ using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
+ constexpr size_t PrefixLen = 5; // strlen("path=")
+ Environment.push_back(Args.MakeArgString(
+ EnvVar.substr(0, PrefixLen) +
+ TC.getSubDirectoryPath(SubDirectoryType::Bin) +
+ llvm::Twine(llvm::sys::EnvPathSeparator) +
+ TC.getSubDirectoryPath(SubDirectoryType::Bin, HostArch) +
+ (EnvVar.size() > PrefixLen
+ ? llvm::Twine(llvm::sys::EnvPathSeparator) +
+ EnvVar.substr(PrefixLen)
+ : "")));
+ } else {
+ Environment.push_back(Args.MakeArgString(EnvVar));
+ }
+ Cursor += EnvVar.size() + 1 /*null-terminator*/;
+ }
+ }
+ SkipSettingEnvironment:;
+#endif
} else {
- linkPath = Linker;
- llvm::sys::path::replace_extension(linkPath, "exe");
- linkPath = TC.GetProgramPath(linkPath.c_str());
+ linkPath = TC.GetProgramPath(Linker.str().c_str());
}
- const char *Exec = Args.MakeArgString(linkPath);
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ 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,
@@ -381,9 +669,7 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand(
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());
+ std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe");
return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
CmdArgs, Inputs);
}
@@ -394,9 +680,19 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
+
+ // Check the environment first, since that's probably the user telling us
+ // what they want to use.
+ // Failing that, just try to find the newest Visual Studio version we can
+ // and use its default VC toolchain.
+ findVCToolChainViaEnvironment(VCToolChainPath, VSLayout) ||
+ findVCToolChainViaSetupConfig(VCToolChainPath, VSLayout) ||
+ findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
}
Tool *MSVCToolChain::buildLinker() const {
+ if (VCToolChainPath.empty())
+ getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
return new tools::visualstudio::Linker(*this);
}
@@ -411,7 +707,7 @@ bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
return true;
}
-bool MSVCToolChain::IsUnwindTablesDefault() const {
+bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
// Emit unwind tables by default on Win64. All non-x86_32 Windows platforms
// such as ARM and PPC actually require unwind tables, but LLVM doesn't know
// how to generate them yet.
@@ -444,6 +740,101 @@ void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
CudaInstallation.print(OS);
}
+// Windows SDKs and VC Toolchains group their contents into subdirectories based
+// on the target architecture. This function converts an llvm::Triple::ArchType
+// to the corresponding subdirectory name.
+static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ return "x86";
+ case ArchType::x86_64:
+ return "x64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Similar to the above function, but for Visual Studios before VS2017.
+static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ // x86 is default in legacy VC toolchains.
+ // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
+ return "";
+ case ArchType::x86_64:
+ return "amd64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Similar to the above function, but for DevDiv internal builds.
+static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ return "i386";
+ case ArchType::x86_64:
+ return "amd64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Get the path to a specific subdirectory in the current toolchain for
+// a given target architecture.
+// VS2017 changed the VC toolchain layout, so this should be used instead
+// of hardcoding paths.
+std::string
+MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
+ llvm::Triple::ArchType TargetArch) const {
+ const char *SubdirName;
+ const char *IncludeName;
+ switch (VSLayout) {
+ case ToolsetLayout::OlderVS:
+ SubdirName = llvmArchToLegacyVCArch(TargetArch);
+ IncludeName = "include";
+ break;
+ case ToolsetLayout::VS2017OrNewer:
+ SubdirName = llvmArchToWindowsSDKArch(TargetArch);
+ IncludeName = "include";
+ break;
+ case ToolsetLayout::DevDivInternal:
+ SubdirName = llvmArchToDevDivInternalArch(TargetArch);
+ IncludeName = "inc";
+ break;
+ }
+
+ llvm::SmallString<256> Path(VCToolChainPath);
+ switch (Type) {
+ case SubDirectoryType::Bin:
+ if (VSLayout == ToolsetLayout::VS2017OrNewer) {
+ const bool HostIsX64 =
+ llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
+ const char *const HostName = HostIsX64 ? "HostX64" : "HostX86";
+ llvm::sys::path::append(Path, "bin", HostName, SubdirName);
+ } else { // OlderVS or DevDivInternal
+ llvm::sys::path::append(Path, "bin", SubdirName);
+ }
+ break;
+ case SubDirectoryType::Include:
+ llvm::sys::path::append(Path, IncludeName);
+ break;
+ case SubDirectoryType::Lib:
+ llvm::sys::path::append(Path, "lib", SubdirName);
+ break;
+ }
+ return Path.str();
+}
+
#ifdef USE_WIN32
static bool readFullStringValue(HKEY hkey, const char *valueName,
std::string &value) {
@@ -573,27 +964,12 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
#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) {
+static bool getWindows10SDKVersionFromPath(const std::string &SDKPath,
+ std::string &SDKVersion) {
SDKVersion.clear();
std::error_code EC;
@@ -617,9 +993,9 @@ static bool getWindows10SDKVersion(const std::string &SDKPath,
}
/// \brief Get Windows SDK installation directory.
-bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major,
- std::string &WindowsSDKIncludeVersion,
- std::string &WindowsSDKLibVersion) const {
+static bool getWindowsSDKDir(std::string &Path, int &Major,
+ std::string &WindowsSDKIncludeVersion,
+ std::string &WindowsSDKLibVersion) {
std::string RegistrySDKVersion;
// Try the Windows registry.
if (!getSystemRegistryString(
@@ -651,7 +1027,7 @@ bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major,
return !WindowsSDKLibVersion.empty();
}
if (Major == 10) {
- if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion))
+ if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion))
return false;
WindowsSDKLibVersion = WindowsSDKIncludeVersion;
return true;
@@ -674,7 +1050,10 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
llvm::SmallString<128> libPath(sdkPath);
llvm::sys::path::append(libPath, "Lib");
- if (sdkMajor <= 7) {
+ 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:
@@ -688,11 +1067,6 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
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();
@@ -701,16 +1075,14 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
// 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");
-
+bool MSVCToolChain::useUniversalCRT() const {
+ llvm::SmallString<128> TestPath(
+ getSubDirectoryPath(SubDirectoryType::Include));
+ llvm::sys::path::append(TestPath, "stdlib.h");
return !llvm::sys::fs::exists(TestPath);
}
-bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path,
- std::string &UCRTVersion) const {
+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(
@@ -718,7 +1090,7 @@ bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path,
Path, nullptr))
return false;
- return getWindows10SDKVersion(Path, UCRTVersion);
+ return getWindows10SDKVersionFromPath(Path, UCRTVersion);
}
bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
@@ -729,7 +1101,7 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
return false;
- StringRef ArchName = getWindowsSDKArch(getArch());
+ StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
if (ArchName.empty())
return false;
@@ -740,104 +1112,18 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
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 {
+static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) {
unsigned Major, Minor, Micro;
- getTriple().getEnvironmentVersion(Major, Minor, Micro);
+ Triple.getEnvironmentVersion(Major, Minor, Micro);
if (Major || Minor || Micro)
return VersionTuple(Major, Minor, Micro);
return VersionTuple();
}
-VersionTuple MSVCToolChain::getMSVCVersionFromExe() const {
+static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
VersionTuple Version;
#ifdef USE_WIN32
- std::string BinPath;
- if (!getVisualStudioBinariesFolder("", BinPath))
- return Version;
- SmallString<128> ClExe(BinPath);
+ SmallString<128> ClExe(BinDir);
llvm::sys::path::append(ClExe, "cl.exe");
std::wstring ClExeWide;
@@ -870,62 +1156,6 @@ VersionTuple MSVCToolChain::getMSVCVersionFromExe() const {
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,
@@ -964,14 +1194,13 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
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 (!VCToolChainPath.empty()) {
+ addSystemInclude(DriverArgs, CC1Args,
+ getSubDirectoryPath(SubDirectoryType::Include));
- if (useUniversalCRT(VSDir)) {
+ if (useUniversalCRT()) {
std::string UniversalCRTSdkPath;
std::string UCRTVersion;
if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
@@ -1002,9 +1231,8 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
"include");
}
- } else {
- addSystemInclude(DriverArgs, CC1Args, VSDir);
}
+
return;
}
@@ -1031,14 +1259,15 @@ 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())
+ 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);
+ // -fms-compatibility-version=19.11 is default, aka 2017
+ MSVT = VersionTuple(19, 11);
}
return MSVT;
}
@@ -1087,24 +1316,26 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
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));
+ // Ignore /O[12xd] flags that aren't the last one on the command line.
+ // Only the last one gets expanded.
+ if (&OptChar != ExpandChar) {
+ A->claim();
+ break;
+ }
+ 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':
@@ -1200,9 +1431,7 @@ MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
// 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;
+ for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
StringRef OptStr = A->getValue();
for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
char OptChar = OptStr[I];
diff --git a/lib/Driver/ToolChains/MSVC.h b/lib/Driver/ToolChains/MSVC.h
index 2b2f3e2d20..854f88a36f 100644
--- a/lib/Driver/ToolChains/MSVC.h
+++ b/lib/Driver/ToolChains/MSVC.h
@@ -73,11 +73,32 @@ public:
Action::OffloadKind DeviceOffloadKind) const override;
bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault() const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPICDefaultForced() const override;
+ enum class SubDirectoryType {
+ Bin,
+ Include,
+ Lib,
+ };
+ std::string getSubDirectoryPath(SubDirectoryType Type,
+ llvm::Triple::ArchType TargetArch) const;
+
+ // Convenience overload.
+ // Uses the current target arch.
+ std::string getSubDirectoryPath(SubDirectoryType Type) const {
+ return getSubDirectoryPath(Type, getArch());
+ }
+
+ enum class ToolsetLayout {
+ OlderVS,
+ VS2017OrNewer,
+ DevDivInternal,
+ };
+ bool getIsVS2017OrNewer() const { return VSLayout == ToolsetLayout::VS2017OrNewer; }
+
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -88,17 +109,10 @@ public:
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;
+ bool useUniversalCRT() const;
VersionTuple
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
@@ -120,9 +134,8 @@ protected:
Tool *buildLinker() const override;
Tool *buildAssembler() const override;
private:
- VersionTuple getMSVCVersionFromTriple() const;
- VersionTuple getMSVCVersionFromExe() const;
-
+ std::string VCToolChainPath;
+ ToolsetLayout VSLayout = ToolsetLayout::OlderVS;
CudaInstallationDetector CudaInstallation;
};
diff --git a/lib/Driver/ToolChains/MSVCSetupApi.h b/lib/Driver/ToolChains/MSVCSetupApi.h
new file mode 100644
index 0000000000..a890b85fd5
--- /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
index ca5bf06f7e..660b0c798e 100644
--- a/lib/Driver/ToolChains/MinGW.cpp
+++ b/lib/Driver/ToolChains/MinGW.cpp
@@ -82,6 +82,9 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
CmdArgs.push_back("-lmoldname");
CmdArgs.push_back("-lmingwex");
+ for (auto Lib : Args.getAllArgValues(options::OPT_l))
+ if (StringRef(Lib).startswith("msvcr") || Lib == "ucrtbase")
+ return;
CmdArgs.push_back("-lmsvcrt");
}
@@ -119,12 +122,24 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-s");
CmdArgs.push_back("-m");
- if (TC.getArch() == llvm::Triple::x86)
+ switch (TC.getArch()) {
+ case llvm::Triple::x86:
CmdArgs.push_back("i386pe");
- if (TC.getArch() == llvm::Triple::x86_64)
+ break;
+ case llvm::Triple::x86_64:
CmdArgs.push_back("i386pep");
- if (TC.getArch() == llvm::Triple::arm)
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // FIXME: this is incorrect for WinCE
CmdArgs.push_back("thumb2pe");
+ break;
+ case llvm::Triple::aarch64:
+ CmdArgs.push_back("arm64pe");
+ break;
+ default:
+ llvm_unreachable("Unsupported target architecture.");
+ }
if (Args.hasArg(options::OPT_mwindows)) {
CmdArgs.push_back("--subsystem");
@@ -185,8 +200,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// TODO: Add profile stuff here
- if (D.CCCIsCXX() &&
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (TC.ShouldLinkCXXStdlib(Args)) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
if (OnlyLibstdcxxStatic)
@@ -285,28 +299,30 @@ void toolchains::MinGW::findGccLibDir() {
}
}
+llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() {
+ llvm::SmallVector<llvm::SmallString<32>, 2> Gccs;
+ Gccs.emplace_back(getTriple().getArchName());
+ Gccs[0] += "-w64-mingw32-gcc";
+ Gccs.emplace_back("mingw32-gcc");
+ // Please do not add "gcc" here
+ for (StringRef CandidateGcc : Gccs)
+ if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc))
+ return GPPName;
+ return make_error_code(std::errc::no_such_file_or_directory);
+}
+
toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
-// 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"))
+ else if (llvm::ErrorOr<std::string> GPPName = findGcc())
Base = llvm::sys::path::parent_path(
llvm::sys::path::parent_path(GPPName.get()));
else
Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
-#else
- if (getDriver().SysRoot.size())
- Base = getDriver().SysRoot;
- else
- Base = "/usr";
-#endif
Base += llvm::sys::path::get_separator();
findGccLibDir();
@@ -345,7 +361,7 @@ Tool *toolchains::MinGW::buildLinker() const {
return new tools::MinGW::Linker(*this);
}
-bool toolchains::MinGW::IsUnwindTablesDefault() const {
+bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const {
return getArch() == llvm::Triple::x86_64;
}
diff --git a/lib/Driver/ToolChains/MinGW.h b/lib/Driver/ToolChains/MinGW.h
index 9d2468ffa2..9b3d7c553f 100644
--- a/lib/Driver/ToolChains/MinGW.h
+++ b/lib/Driver/ToolChains/MinGW.h
@@ -60,7 +60,7 @@ public:
const llvm::opt::ArgList &Args);
bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault() const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault() const override;
bool isPICDefaultForced() const override;
@@ -93,6 +93,7 @@ private:
mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
mutable std::unique_ptr<tools::gcc::Compiler> Compiler;
void findGccLibDir();
+ llvm::ErrorOr<std::string> findGcc();
};
} // end namespace toolchains
diff --git a/lib/Driver/ToolChains/Minix.cpp b/lib/Driver/ToolChains/Minix.cpp
index 2e8939c401..39e6f90b6e 100644
--- a/lib/Driver/ToolChains/Minix.cpp
+++ b/lib/Driver/ToolChains/Minix.cpp
@@ -72,7 +72,8 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (getToolChain().ShouldLinkCXXStdlib(Args))
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
}
diff --git a/lib/Driver/ToolChains/MipsLinux.cpp b/lib/Driver/ToolChains/MipsLinux.cpp
index 709c396a64..b394208336 100644
--- a/lib/Driver/ToolChains/MipsLinux.cpp
+++ b/lib/Driver/ToolChains/MipsLinux.cpp
@@ -109,7 +109,7 @@ std::string MipsLLVMToolChain::findLibCxxIncludePath() const {
void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) &&
- "Only -lc++ (aka libxx) is suported in this toolchain.");
+ "Only -lc++ (aka libxx) is supported in this toolchain.");
CmdArgs.push_back("-lc++");
CmdArgs.push_back("-lc++abi");
diff --git a/lib/Driver/ToolChains/Myriad.cpp b/lib/Driver/ToolChains/Myriad.cpp
index 2935755c12..6fdb5a2248 100644
--- a/lib/Driver/ToolChains/Myriad.cpp
+++ b/lib/Driver/ToolChains/Myriad.cpp
@@ -43,15 +43,17 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back("-DMYRIAD2");
- // Append all -I, -iquote, -isystem paths, defines/undefines,
- // 'f' flags, optimize flags, and warning options.
+ // Append all -I, -iquote, -isystem paths, defines/undefines, 'f'
+ // flags, 'g' flags, 'M' flags, optimize flags, warning options,
+ // mcpu flags, mllvm flags, and Xclang flags.
// These are spelled the same way in clang and moviCompile.
Args.AddAllArgsExcept(
CmdArgs,
{options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ,
options::OPT_D, options::OPT_U, options::OPT_f_Group,
options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group,
- options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ},
+ options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ,
+ options::OPT_mllvm, options::OPT_Xclang},
{options::OPT_fno_split_dwarf_inlining});
Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present.
@@ -215,6 +217,7 @@ MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
default:
D.Diag(clang::diag::err_target_unsupported_arch)
<< Triple.getArchName() << "myriad";
+ LLVM_FALLTHROUGH;
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::shave:
diff --git a/lib/Driver/ToolChains/NaCl.cpp b/lib/Driver/ToolChains/NaCl.cpp
index 5eb5c74f13..128478d638 100644
--- a/lib/Driver/ToolChains/NaCl.cpp
+++ b/lib/Driver/ToolChains/NaCl.cpp
@@ -133,13 +133,15 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &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");
+ if (ToolChain.ShouldLinkCXXStdlib(Args)) {
+ 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");
}
diff --git a/lib/Driver/ToolChains/NetBSD.cpp b/lib/Driver/ToolChains/NetBSD.cpp
index d7d3ad61df..c2c9007af6 100644
--- a/lib/Driver/ToolChains/NetBSD.cpp
+++ b/lib/Driver/ToolChains/NetBSD.cpp
@@ -15,6 +15,7 @@
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
using namespace clang::driver;
@@ -246,6 +247,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_r);
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
unsigned Major, Minor, Micro;
@@ -276,9 +278,12 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
addOpenMPRuntime(CmdArgs, getToolChain(), Args);
if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (getToolChain().ShouldLinkCXXStdlib(Args))
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lm");
}
+ if (NeedsSanitizerDeps)
+ linkSanitizerRuntimeDeps(getToolChain(), CmdArgs);
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lc");
@@ -320,7 +325,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
- if (getDriver().UseStdLib) {
+ if (!Args.hasArg(options::OPT_nostdlib)) {
// 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.
@@ -410,3 +415,22 @@ void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "",
"", DriverArgs, CC1Args);
}
+
+SanitizerMask NetBSD::getSupportedSanitizers() const {
+ const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
+ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ if (IsX86 || IsX86_64) {
+ Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Function;
+ Res |= SanitizerKind::Leak;
+ Res |= SanitizerKind::SafeStack;
+ Res |= SanitizerKind::Vptr;
+ }
+ if (IsX86_64) {
+ Res |= SanitizerKind::Fuzzer;
+ Res |= SanitizerKind::FuzzerNoLink;
+ Res |= SanitizerKind::Thread;
+ }
+ return Res;
+}
diff --git a/lib/Driver/ToolChains/NetBSD.h b/lib/Driver/ToolChains/NetBSD.h
index d53aa68678..5163ff72d8 100644
--- a/lib/Driver/ToolChains/NetBSD.h
+++ b/lib/Driver/ToolChains/NetBSD.h
@@ -65,7 +65,11 @@ public:
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- bool IsUnwindTablesDefault() const override { return true; }
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
+ return true;
+ }
+
+ SanitizerMask getSupportedSanitizers() const override;
protected:
Tool *buildAssembler() const override;
diff --git a/lib/Driver/ToolChains/OpenBSD.cpp b/lib/Driver/ToolChains/OpenBSD.cpp
index c5f266ec8f..fbb84a62ca 100644
--- a/lib/Driver/ToolChains/OpenBSD.cpp
+++ b/lib/Driver/ToolChains/OpenBSD.cpp
@@ -133,6 +133,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
if (Args.hasArg(options::OPT_nopie))
CmdArgs.push_back("-nopie");
@@ -177,7 +179,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (getToolChain().ShouldLinkCXXStdlib(Args))
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
else
diff --git a/lib/Driver/ToolChains/PS4CPU.cpp b/lib/Driver/ToolChains/PS4CPU.cpp
index c1b8c3d660..b37fe7d1f9 100644
--- a/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/lib/Driver/ToolChains/PS4CPU.cpp
@@ -227,7 +227,8 @@ static void ConstructGoldLinkJob(const Tool &T, Compilation &C,
// libraries for both C and C++ compilations.
CmdArgs.push_back("-lkernel");
if (D.CCCIsCXX()) {
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
else
diff --git a/lib/Driver/ToolChains/Solaris.cpp b/lib/Driver/ToolChains/Solaris.cpp
index 78797c49d7..9fe6e9d520 100644
--- a/lib/Driver/ToolChains/Solaris.cpp
+++ b/lib/Driver/ToolChains/Solaris.cpp
@@ -100,7 +100,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (getToolChain().getDriver().CCCIsCXX())
+ if (getToolChain().ShouldLinkCXXStdlib(Args))
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
CmdArgs.push_back("-lgcc_s");
CmdArgs.push_back("-lc");
@@ -126,7 +126,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
- : Generic_GCC(D, Triple, Args) {
+ : Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
diff --git a/lib/Driver/ToolChains/Solaris.h b/lib/Driver/ToolChains/Solaris.h
index edb44373b3..787917afab 100644
--- a/lib/Driver/ToolChains/Solaris.h
+++ b/lib/Driver/ToolChains/Solaris.h
@@ -50,7 +50,7 @@ public:
namespace toolchains {
-class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_ELF {
public:
Solaris(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp
index 123a1516f1..b57989ce45 100644
--- a/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/lib/Driver/ToolChains/WebAssembly.cpp
@@ -38,58 +38,35 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
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");
+ CmdArgs.push_back("wasm");
- // Enable garbage collection of unused input sections by default, since code
- // size is of particular importance. This is significantly facilitated by
- // the enabling of -ffunction-sections and -fdata-sections in
- // Clang::ConstructJob.
- if (areOptimizationsEnabled(Args))
- CmdArgs.push_back("--gc-sections");
-
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
if (Args.hasArg(options::OPT_s))
CmdArgs.push_back("--strip-all");
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-shared");
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-Bstatic");
Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("rcrt1.o")));
- else if (Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
- else
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
- }
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX())
+ if (ToolChain.ShouldLinkCXXStdlib(Args))
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-allow-undefined-file");
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("wasm.syms")));
CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lcompiler_rt");
+ AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
}
- 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());
@@ -101,8 +78,10 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
: ToolChain(D, Triple, Args) {
assert(Triple.isArch32Bit() != Triple.isArch64Bit());
- getFilePaths().push_back(
- getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64"));
+
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+
+ getFilePaths().push_back(getDriver().SysRoot + "/lib");
}
bool WebAssembly::IsMathErrnoDefault() const { return false; }
@@ -130,7 +109,8 @@ bool WebAssembly::SupportsProfiling() const { return false; }
bool WebAssembly::HasNativeLLVMSupport() const { return true; }
void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array,
options::OPT_fno_use_init_array, true))
CC1Args.push_back("-fuse-init-array");
diff --git a/lib/Driver/ToolChains/WebAssembly.h b/lib/Driver/ToolChains/WebAssembly.h
index ca42fc651a..2999db477f 100644
--- a/lib/Driver/ToolChains/WebAssembly.h
+++ b/lib/Driver/ToolChains/WebAssembly.h
@@ -53,7 +53,8 @@ private:
bool SupportsProfiling() const override;
bool HasNativeLLVMSupport() const override;
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override;
CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
void AddClangSystemIncludeArgs(
diff --git a/lib/Driver/ToolChains/XCore.cpp b/lib/Driver/ToolChains/XCore.cpp
index c3ae958212..43175ad7d6 100644
--- a/lib/Driver/ToolChains/XCore.cpp
+++ b/lib/Driver/ToolChains/XCore.cpp
@@ -124,7 +124,8 @@ void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
}
void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
CC1Args.push_back("-nostdsysteminc");
}
diff --git a/lib/Driver/ToolChains/XCore.h b/lib/Driver/ToolChains/XCore.h
index 4084b1cdec..00c89bd15f 100644
--- a/lib/Driver/ToolChains/XCore.h
+++ b/lib/Driver/ToolChains/XCore.h
@@ -67,7 +67,8 @@ public:
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;
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
diff --git a/lib/Driver/XRayArgs.cpp b/lib/Driver/XRayArgs.cpp
new file mode 100644
index 0000000000..8d68a8432d
--- /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/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index 5292a58a9c..444d0393cc 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -25,17 +25,21 @@ void EditsReceiver::remove(CharSourceRange range) {
void EditedSource::deconstructMacroArgLoc(SourceLocation Loc,
SourceLocation &ExpansionLoc,
- IdentifierInfo *&II) {
+ MacroArgUse &ArgUse) {
assert(SourceMgr.isMacroArgExpansion(Loc));
SourceLocation DefArgLoc = SourceMgr.getImmediateExpansionRange(Loc).first;
- ExpansionLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+ SourceLocation ImmediateExpansionLoc =
+ SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+ ExpansionLoc = ImmediateExpansionLoc;
+ while (SourceMgr.isMacroBodyExpansion(ExpansionLoc))
+ ExpansionLoc = SourceMgr.getImmediateExpansionRange(ExpansionLoc).first;
SmallString<20> Buf;
StringRef ArgName = Lexer::getSpelling(SourceMgr.getSpellingLoc(DefArgLoc),
Buf, SourceMgr, LangOpts);
- II = nullptr;
- if (!ArgName.empty()) {
- II = &IdentTable.get(ArgName);
- }
+ ArgUse = MacroArgUse{nullptr, SourceLocation(), SourceLocation()};
+ if (!ArgName.empty())
+ ArgUse = {&IdentTable.get(ArgName), ImmediateExpansionLoc,
+ SourceMgr.getSpellingLoc(DefArgLoc)};
}
void EditedSource::startingCommit() {}
@@ -43,12 +47,11 @@ void EditedSource::startingCommit() {}
void EditedSource::finishedCommit() {
for (auto &ExpArg : CurrCommitMacroArgExps) {
SourceLocation ExpLoc;
- IdentifierInfo *II;
- std::tie(ExpLoc, II) = ExpArg;
- auto &ArgNames = ExpansionToArgMap[ExpLoc.getRawEncoding()];
- if (std::find(ArgNames.begin(), ArgNames.end(), II) == ArgNames.end()) {
- ArgNames.push_back(II);
- }
+ MacroArgUse ArgUse;
+ std::tie(ExpLoc, ArgUse) = ExpArg;
+ auto &ArgUses = ExpansionToArgMap[ExpLoc.getRawEncoding()];
+ if (std::find(ArgUses.begin(), ArgUses.end(), ArgUse) == ArgUses.end())
+ ArgUses.push_back(ArgUse);
}
CurrCommitMacroArgExps.clear();
}
@@ -66,12 +69,16 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
}
if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
- IdentifierInfo *II;
SourceLocation ExpLoc;
- deconstructMacroArgLoc(OrigLoc, ExpLoc, II);
+ MacroArgUse ArgUse;
+ deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
auto I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
if (I != ExpansionToArgMap.end() &&
- std::find(I->second.begin(), I->second.end(), II) != I->second.end()) {
+ find_if(I->second, [&](const MacroArgUse &U) {
+ return ArgUse.Identifier == U.Identifier &&
+ std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
+ std::tie(U.ImmediateExpansionLoc, U.UseLoc);
+ }) != I->second.end()) {
// Trying to write in a macro argument input that has already been
// written by a previous commit for another expansion of the same macro
// argument name. For example:
@@ -88,7 +95,6 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
return false;
}
}
-
return true;
}
@@ -101,13 +107,13 @@ bool EditedSource::commitInsert(SourceLocation OrigLoc,
return true;
if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
- IdentifierInfo *II;
+ MacroArgUse ArgUse;
SourceLocation ExpLoc;
- deconstructMacroArgLoc(OrigLoc, ExpLoc, II);
- if (II)
- CurrCommitMacroArgExps.emplace_back(ExpLoc, II);
+ deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
+ if (ArgUse.Identifier)
+ CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
}
-
+
FileEdit &FA = FileEdits[Offs];
if (FA.Text.empty()) {
FA.Text = copyString(text);
@@ -363,13 +369,14 @@ static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
static void applyRewrite(EditsReceiver &receiver,
StringRef text, FileOffset offs, unsigned len,
- const SourceManager &SM, const LangOptions &LangOpts) {
+ const SourceManager &SM, const LangOptions &LangOpts,
+ bool shouldAdjustRemovals) {
assert(offs.getFID().isValid());
SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
Loc = Loc.getLocWithOffset(offs.getOffset());
assert(Loc.isFileID());
- if (text.empty())
+ if (text.empty() && shouldAdjustRemovals)
adjustRemoval(SM, LangOpts, Loc, offs, len, text);
CharSourceRange range = CharSourceRange::getCharRange(Loc,
@@ -387,7 +394,8 @@ static void applyRewrite(EditsReceiver &receiver,
receiver.insert(Loc, text);
}
-void EditedSource::applyRewrites(EditsReceiver &receiver) {
+void EditedSource::applyRewrites(EditsReceiver &receiver,
+ bool shouldAdjustRemovals) {
SmallString<128> StrVec;
FileOffset CurOffs, CurEnd;
unsigned CurLen;
@@ -414,14 +422,16 @@ void EditedSource::applyRewrites(EditsReceiver &receiver) {
continue;
}
- applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts);
+ applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
+ shouldAdjustRemovals);
CurOffs = offs;
StrVec = act.Text;
CurLen = act.RemoveLen;
CurEnd = CurOffs.getWithOffset(CurLen);
}
- applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts);
+ applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
+ shouldAdjustRemovals);
}
void EditedSource::clearRewrites() {
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index 2148316532..dc501b564e 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -798,24 +798,28 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
case NSAPI::NSNumberWithUnsignedInt:
case NSAPI::NSNumberWithUnsignedInteger:
CallIsUnsigned = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithInt:
case NSAPI::NSNumberWithInteger:
break;
case NSAPI::NSNumberWithUnsignedLong:
CallIsUnsigned = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithLong:
CallIsLong = true;
break;
case NSAPI::NSNumberWithUnsignedLongLong:
CallIsUnsigned = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithLongLong:
CallIsLongLong = true;
break;
case NSAPI::NSNumberWithDouble:
CallIsDouble = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithFloat:
CallIsFloating = true;
break;
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index b42e4aee50..bbf3d88eec 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -41,7 +41,8 @@ static bool IsBlank(char C) {
}
static StringRef getLineCommentIndentPrefix(StringRef Comment) {
- static const char *const KnownPrefixes[] = {"///", "//", "//!"};
+ static const char *const KnownPrefixes[] = {"///<", "//!<", "///", "//",
+ "//!"};
StringRef LongestPrefix;
for (StringRef KnownPrefix : KnownPrefixes) {
if (Comment.startswith(KnownPrefix)) {
@@ -77,6 +78,14 @@ static BreakableToken::Split getCommentSplit(StringRef Text,
}
StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
+
+ // Do not split before a number followed by a dot: this would be interpreted
+ // as a numbered list, which would prevent re-flowing in subsequent passes.
+ static llvm::Regex kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\.");
+ if (SpaceOffset != StringRef::npos &&
+ kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks)))
+ SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+
if (SpaceOffset == StringRef::npos ||
// Don't break at leading whitespace.
Text.find_last_not_of(Blanks, SpaceOffset) == StringRef::npos) {
@@ -186,7 +195,7 @@ BreakableSingleLineToken::BreakableSingleLineToken(
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());
}
@@ -210,21 +219,13 @@ 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, LeadingSpaces);
+ Prefix, InPPDirective, 1, StartColumn);
}
BreakableComment::BreakableComment(const FormatToken &Token,
- unsigned StartColumn,
- bool InPPDirective,
+ unsigned StartColumn, bool InPPDirective,
encoding::Encoding Encoding,
const FormatStyle &Style)
: BreakableToken(Token, InPPDirective, Encoding, Style),
@@ -305,8 +306,9 @@ const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const {
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"};
+ // Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists.
+ static const SmallVector<StringRef, 8> kSpecialMeaningPrefixes = {
+ "@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "};
bool hasSpecialMeaningPrefix = false;
for (StringRef Prefix : kSpecialMeaningPrefixes) {
if (Content.startswith(Prefix)) {
@@ -314,6 +316,14 @@ static bool mayReflowContent(StringRef Content) {
break;
}
}
+
+ // Numbered lists may also start with a number followed by '.'
+ // To avoid issues if a line starts with a number which is actually the end
+ // of a previous line, we only consider numbers with up to 2 digits.
+ static llvm::Regex kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. ");
+ hasSpecialMeaningPrefix =
+ hasSpecialMeaningPrefix || kNumberedListRegexp.match(Content);
+
// Simple heuristic for what to reflow: content should contain at least two
// characters and either the first or second character must be
// non-punctuation.
@@ -328,7 +338,8 @@ BreakableBlockComment::BreakableBlockComment(
const FormatToken &Token, unsigned StartColumn,
unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style)
- : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style) {
+ : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style),
+ DelimitersOnNewline(false) {
assert(Tok.is(TT_BlockComment) &&
"block comment section must start with a block comment");
@@ -373,8 +384,7 @@ BreakableBlockComment::BreakableBlockComment(
// If the last line is empty, the closing "*/" will have a star.
if (i + 1 == e && Content[i].empty())
break;
- if (!Content[i].empty() && i + 1 != e &&
- Decoration.startswith(Content[i]))
+ if (!Content[i].empty() && i + 1 != e && Decoration.startswith(Content[i]))
continue;
while (!Content[i].startswith(Decoration))
Decoration = Decoration.substr(0, Decoration.size() - 1);
@@ -416,11 +426,30 @@ BreakableBlockComment::BreakableBlockComment(
IndentAtLineBreak =
std::min<int>(IndentAtLineBreak, std::max(0, ContentColumn[i]));
}
- IndentAtLineBreak =
- std::max<unsigned>(IndentAtLineBreak, Decoration.size());
+ IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size());
+
+ // Detect a multiline jsdoc comment and set DelimitersOnNewline in that case.
+ if (Style.Language == FormatStyle::LK_JavaScript ||
+ Style.Language == FormatStyle::LK_Java) {
+ if ((Lines[0] == "*" || Lines[0].startswith("* ")) && Lines.size() > 1) {
+ // This is a multiline jsdoc comment.
+ DelimitersOnNewline = true;
+ } else if (Lines[0].startswith("* ") && Lines.size() == 1) {
+ // Detect a long single-line comment, like:
+ // /** long long long */
+ // Below, '2' is the width of '*/'.
+ unsigned EndColumn =
+ ContentColumn[0] +
+ encoding::columnWidthWithTabs(Lines[0], ContentColumn[0],
+ Style.TabWidth, Encoding) +
+ 2;
+ DelimitersOnNewline = EndColumn > Style.ColumnLimit;
+ }
+ }
DEBUG({
llvm::dbgs() << "IndentAtLineBreak " << IndentAtLineBreak << "\n";
+ llvm::dbgs() << "DelimitersOnNewline " << DelimitersOnNewline << "\n";
for (size_t i = 0; i < Lines.size(); ++i) {
llvm::dbgs() << i << " |" << Content[i] << "| "
<< "CC=" << ContentColumn[i] << "| "
@@ -516,38 +545,38 @@ void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
}
BreakableToken::Split BreakableBlockComment::getSplitBefore(
- unsigned LineIndex,
- unsigned PreviousEndColumn,
- unsigned ColumnLimit,
+ 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);
+ Split Result = getReflowSplit(TrimmedContent, ReflowPrefix, PreviousEndColumn,
+ ColumnLimit);
+ // Result is relative to TrimmedContent. Adapt it relative to
+ // Content[LineIndex].
+ if (Result.first != StringRef::npos)
+ Result.first += Content[LineIndex].size() - TrimmedContent.size();
+ return Result;
}
-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::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 {
+ 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
@@ -569,10 +598,28 @@ unsigned BreakableBlockComment::getLineLengthAfterSplitBefore(
return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
}
}
+
+bool BreakableBlockComment::introducesBreakBefore(unsigned LineIndex) const {
+ // A break is introduced when we want delimiters on newline.
+ return LineIndex == 0 && DelimitersOnNewline &&
+ Lines[0].substr(1).find_first_not_of(Blanks) != StringRef::npos;
+}
+
void BreakableBlockComment::replaceWhitespaceBefore(
unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
Split SplitBefore, WhitespaceManager &Whitespaces) {
- if (LineIndex == 0) return;
+ if (LineIndex == 0) {
+ if (DelimitersOnNewline) {
+ // Since we're breaking af index 1 below, the break position and the
+ // break length are the same.
+ size_t BreakLength = Lines[0].substr(1).find_first_not_of(Blanks);
+ if (BreakLength != StringRef::npos) {
+ insertBreak(LineIndex, 0, Split(1, BreakLength), Whitespaces);
+ DelimitersOnNewline = true;
+ }
+ }
+ return;
+ }
StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
if (SplitBefore.first != StringRef::npos) {
// Here we need to reflow.
@@ -581,28 +628,23 @@ void BreakableBlockComment::replaceWhitespaceBefore(
// 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();
+ Content[LineIndex - 1].size() -
+ tokenAt(LineIndex).TokenText.data();
unsigned WhitespaceLength = TrimmedContent.data() -
- tokenAt(LineIndex).TokenText.data() -
- WhitespaceOffsetInToken;
+ 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);
- }
+ if (ReflownColumn > ColumnLimit)
+ insertBreak(LineIndex, 0, SplitBefore, Whitespaces);
return;
}
@@ -640,6 +682,21 @@ void BreakableBlockComment::replaceWhitespaceBefore(
InPPDirective, /*Newlines=*/1, ContentColumn[LineIndex] - Prefix.size());
}
+BreakableToken::Split
+BreakableBlockComment::getSplitAfterLastLine(unsigned TailOffset,
+ unsigned ColumnLimit) const {
+ if (DelimitersOnNewline) {
+ // Replace the trailing whitespace of the last line with a newline.
+ // In case the last line is empty, the ending '*/' is already on its own
+ // line.
+ StringRef Line = Content.back().substr(TailOffset);
+ StringRef TrimmedLine = Line.rtrim(Blanks);
+ if (!TrimmedLine.empty())
+ return Split(TrimmedLine.size(), Line.size() - TrimmedLine.size());
+ }
+ return Split(StringRef::npos, 0);
+}
+
bool BreakableBlockComment::mayReflow(unsigned LineIndex,
llvm::Regex &CommentPragmasRegex) const {
// Content[LineIndex] may exclude the indent after the '*' decoration. In that
@@ -699,22 +756,21 @@ BreakableLineCommentSection::BreakableLineCommentSection(
Prefix[i] = "/// ";
else if (Prefix[i] == "//!")
Prefix[i] = "//! ";
+ else if (Prefix[i] == "///<")
+ Prefix[i] = "///< ";
+ else if (Prefix[i] == "//!<")
+ Prefix[i] = "//!< ";
}
Tokens[i] = LineTok;
Content[i] = Lines[i].substr(IndentPrefix.size());
OriginalContentColumn[i] =
- StartColumn +
- encoding::columnWidthWithTabs(OriginalPrefix[i],
- StartColumn,
- Style.TabWidth,
- Encoding);
+ StartColumn + encoding::columnWidthWithTabs(OriginalPrefix[i],
+ StartColumn,
+ Style.TabWidth, Encoding);
ContentColumn[i] =
- StartColumn +
- encoding::columnWidthWithTabs(Prefix[i],
- StartColumn,
- Style.TabWidth,
- Encoding);
+ 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);
@@ -787,10 +843,8 @@ BreakableComment::Split BreakableLineCommentSection::getSplitBefore(
}
unsigned BreakableLineCommentSection::getLineLengthAfterSplitBefore(
- unsigned LineIndex, unsigned TailOffset,
- unsigned PreviousEndColumn,
- unsigned ColumnLimit,
- Split SplitBefore) const {
+ 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.
@@ -798,10 +852,9 @@ unsigned BreakableLineCommentSection::getLineLengthAfterSplitBefore(
} else {
// The whole line gets reflown.
unsigned StartColumn = PreviousEndColumn + ReflowPrefix.size();
- return StartColumn + encoding::columnWidthWithTabs(Content[LineIndex],
- StartColumn,
- Style.TabWidth,
- Encoding);
+ return StartColumn +
+ encoding::columnWidthWithTabs(Content[LineIndex], StartColumn,
+ Style.TabWidth, Encoding);
}
}
@@ -874,7 +927,7 @@ void BreakableLineCommentSection::replaceWhitespaceBefore(
}
}
-void BreakableLineCommentSection::updateNextToken(LineState& State) const {
+void BreakableLineCommentSection::updateNextToken(LineState &State) const {
if (LastLineTok) {
State.NextToken = LastLineTok->Next;
}
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index e642a538e2..8c2dc741d1 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -58,12 +58,25 @@ struct FormatStyle;
/// 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,
+/// - introducesBreakBefore, for checking if reformatting the beginning
+/// of the content introduces a line break before it,
/// - 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.
///
+/// For tokens that require the whitespace after the last line to be
+/// reformatted, for example in multiline jsdoc comments that require the
+/// trailing '*/' to be on a line of itself, there are analogous operations
+/// that might be executed after the last line has been reformatted:
+/// - getSplitAfterLastLine, for finding a split after the last line that needs
+/// to be reflown,
+/// - getLineLengthAfterSplitAfterLastLine, for calculating the line length in
+/// columns of the remainder of the token, and
+/// - replaceWhitespaceAfterLastLine, 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 {
@@ -124,6 +137,12 @@ public:
return Split(StringRef::npos, 0);
}
+ /// \brief Returns if a break before the content at \p LineIndex will be
+ /// inserted after the whitespace preceding the content has been reformatted.
+ virtual bool introducesBreakBefore(unsigned LineIndex) const {
+ return false;
+ }
+
/// \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
@@ -144,6 +163,38 @@ public:
unsigned ColumnLimit, Split SplitBefore,
WhitespaceManager &Whitespaces) {}
+ /// \brief Returns a whitespace range (offset, length) of the content at
+ /// the last line that needs to be reformatted after the last line has been
+ /// reformatted.
+ ///
+ /// A result having offset == StringRef::npos means that no reformat is
+ /// necessary.
+ virtual Split getSplitAfterLastLine(unsigned TailOffset,
+ unsigned ColumnLimit) const {
+ return Split(StringRef::npos, 0);
+ }
+
+ /// \brief Returns the number of columns required to format the piece token
+ /// after the last line after a reformat of the whitespace range \p
+ /// \p SplitAfterLastLine on the last line has been performed.
+ virtual unsigned
+ getLineLengthAfterSplitAfterLastLine(unsigned TailOffset,
+ Split SplitAfterLastLine) const {
+ return getLineLengthAfterSplit(getLineCount() - 1,
+ TailOffset + SplitAfterLastLine.first +
+ SplitAfterLastLine.second,
+ StringRef::npos);
+ }
+
+ /// \brief Replaces the whitespace from \p SplitAfterLastLine on the last line
+ /// after the last line has been formatted by performing a reformatting.
+ virtual void replaceWhitespaceAfterLastLine(unsigned TailOffset,
+ Split SplitAfterLastLine,
+ WhitespaceManager &Whitespaces) {
+ insertBreak(getLineCount() - 1, TailOffset, SplitAfterLastLine,
+ 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.
@@ -296,6 +347,7 @@ public:
Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn,
unsigned ColumnLimit,
llvm::Regex &CommentPragmasRegex) const override;
+ bool introducesBreakBefore(unsigned LineIndex) const override;
unsigned getLineLengthAfterSplitBefore(unsigned LineIndex,
unsigned TailOffset,
unsigned PreviousEndColumn,
@@ -304,6 +356,9 @@ public:
void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn,
unsigned ColumnLimit, Split SplitBefore,
WhitespaceManager &Whitespaces) override;
+ Split getSplitAfterLastLine(unsigned TailOffset,
+ unsigned ColumnLimit) const override;
+
bool mayReflow(unsigned LineIndex,
llvm::Regex &CommentPragmasRegex) const override;
@@ -348,6 +403,10 @@ private:
// If this block comment has decorations, this is the column of the start of
// the decorations.
unsigned DecorationColumn;
+
+ // If true, make sure that the opening '/**' and the closing '*/' ends on a
+ // line of itself. Styles like jsdoc require this for multiline comments.
+ bool DelimitersOnNewline;
};
class BreakableLineCommentSection : public BreakableComment {
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index 0c7511c1bb..42e6d53d9f 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -13,6 +13,7 @@ add_clang_library(clangFormat
TokenAnnotator.cpp
UnwrappedLineFormatter.cpp
UnwrappedLineParser.cpp
+ UsingDeclarationsSorter.cpp
WhitespaceManager.cpp
LINK_LIBS
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index c518db8b1a..4f624dd2fb 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -12,8 +12,9 @@
///
//===----------------------------------------------------------------------===//
-#include "BreakableToken.h"
#include "ContinuationIndenter.h"
+#include "BreakableToken.h"
+#include "FormatInternal.h"
#include "WhitespaceManager.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Basic/SourceManager.h"
@@ -54,13 +55,73 @@ static bool startsNextParameter(const FormatToken &Current,
const FormatStyle &Style) {
const FormatToken &Previous = *Current.Previous;
if (Current.is(TT_CtorInitializerComma) &&
- Style.BreakConstructorInitializersBeforeComma)
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
+ return true;
+ if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
((Previous.isNot(TT_CtorInitializerComma) ||
- !Style.BreakConstructorInitializersBeforeComma) &&
+ Style.BreakConstructorInitializers !=
+ FormatStyle::BCIS_BeforeComma) &&
(Previous.isNot(TT_InheritanceComma) ||
- !Style.BreakBeforeInheritanceComma));
+ !Style.BreakBeforeInheritanceComma));
+}
+
+static bool opensProtoMessageField(const FormatToken &LessTok,
+ const FormatStyle &Style) {
+ if (LessTok.isNot(tok::less))
+ return false;
+ return Style.Language == FormatStyle::LK_TextProto ||
+ (Style.Language == FormatStyle::LK_Proto &&
+ (LessTok.NestingLevel > 0 ||
+ (LessTok.Previous && LessTok.Previous->is(tok::equal))));
+}
+
+// Returns the delimiter of a raw string literal, or None if TokenText is not
+// the text of a raw string literal. The delimiter could be the empty string.
+// For example, the delimiter of R"deli(cont)deli" is deli.
+static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
+ if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'.
+ || !TokenText.startswith("R\"") || !TokenText.endswith("\""))
+ return None;
+
+ // A raw string starts with 'R"<delimiter>(' and delimiter is ascii and has
+ // size at most 16 by the standard, so the first '(' must be among the first
+ // 19 bytes.
+ size_t LParenPos = TokenText.substr(0, 19).find_first_of('(');
+ if (LParenPos == StringRef::npos)
+ return None;
+ StringRef Delimiter = TokenText.substr(2, LParenPos - 2);
+
+ // Check that the string ends in ')Delimiter"'.
+ size_t RParenPos = TokenText.size() - Delimiter.size() - 2;
+ if (TokenText[RParenPos] != ')')
+ return None;
+ if (!TokenText.substr(RParenPos + 1).startswith(Delimiter))
+ return None;
+ return Delimiter;
+}
+
+RawStringFormatStyleManager::RawStringFormatStyleManager(
+ const FormatStyle &CodeStyle) {
+ for (const auto &RawStringFormat : CodeStyle.RawStringFormats) {
+ FormatStyle Style;
+ if (!getPredefinedStyle(RawStringFormat.BasedOnStyle,
+ RawStringFormat.Language, &Style)) {
+ Style = getLLVMStyle();
+ Style.Language = RawStringFormat.Language;
+ }
+ Style.ColumnLimit = CodeStyle.ColumnLimit;
+ DelimiterStyle.insert({RawStringFormat.Delimiter, Style});
+ }
+}
+
+llvm::Optional<FormatStyle>
+RawStringFormatStyleManager::get(StringRef Delimiter) const {
+ auto It = DelimiterStyle.find(Delimiter);
+ if (It == DelimiterStyle.end())
+ return None;
+ return It->second;
}
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
@@ -72,25 +133,44 @@ ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
: Style(Style), Keywords(Keywords), SourceMgr(SourceMgr),
Whitespaces(Whitespaces), Encoding(Encoding),
BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
- CommentPragmasRegex(Style.CommentPragmas) {}
+ CommentPragmasRegex(Style.CommentPragmas), RawStringFormats(Style) {}
LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
+ unsigned FirstStartColumn,
const AnnotatedLine *Line,
bool DryRun) {
LineState State;
State.FirstIndent = FirstIndent;
- State.Column = FirstIndent;
+ if (FirstStartColumn && Line->First->NewlinesBefore == 0)
+ State.Column = FirstStartColumn;
+ else
+ State.Column = FirstIndent;
+ // With preprocessor directive indentation, the line starts on column 0
+ // since it's indented after the hash, but FirstIndent is set to the
+ // preprocessor indent.
+ if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash &&
+ (Line->Type == LT_PreprocessorDirective ||
+ Line->Type == LT_ImportStatement))
+ State.Column = 0;
State.Line = Line;
State.NextToken = Line->First;
State.Stack.push_back(ParenState(FirstIndent, FirstIndent,
/*AvoidBinPacking=*/false,
/*NoLineBreak=*/false));
State.LineContainsContinuedForLoopSection = false;
+ State.NoContinuation = false;
State.StartOfStringLiteral = 0;
State.StartOfLineLevel = 0;
State.LowestLevelOnLine = 0;
State.IgnoreStackForComparison = false;
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ // We need this in order to deal with the bin packing of text fields at
+ // global scope.
+ State.Stack.back().AvoidBinPacking = true;
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+
// The first token has already been indented and thus consumed.
moveStateToNextToken(State, DryRun, /*Newline=*/false);
return State;
@@ -100,9 +180,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
assert(&Previous == Current.Previous);
- if (!Current.CanBreakBefore &&
- !(State.Stack.back().BreakBeforeClosingBrace &&
- Current.closesBlockOrBlockTypeList(Style)))
+ if (!Current.CanBreakBefore && !(State.Stack.back().BreakBeforeClosingBrace &&
+ Current.closesBlockOrBlockTypeList(Style)))
return false;
// The opening "{" of a braced list has to be on the same line as the first
// element if it is nested in another braced init list or function call.
@@ -158,7 +237,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.IsCpp() &&
+ 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
@@ -173,18 +252,26 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) ||
(Previous.is(TT_ArrayInitializerLSquare) &&
- Previous.ParameterCount > 1)) &&
+ Previous.ParameterCount > 1) ||
+ opensProtoMessageField(Previous, Style)) &&
Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column - 1 >
getColumnLimit(State))
return true;
- if (Current.is(TT_CtorInitializerColon) &&
- (State.Column + State.Line->Last->TotalLength - Current.TotalLength + 2 >
+
+ const FormatToken &BreakConstructorInitializersToken =
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon
+ ? Previous
+ : Current;
+ if (BreakConstructorInitializersToken.is(TT_CtorInitializerColon) &&
+ (State.Column + State.Line->Last->TotalLength - Previous.TotalLength >
getColumnLimit(State) ||
State.Stack.back().BreakBeforeParameter) &&
- ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
- Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
+ (Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All ||
+ Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon ||
+ Style.ColumnLimit != 0))
return true;
+
if (Current.is(TT_ObjCMethodExpr) && !Previous.is(TT_SelectorName) &&
State.Line->startsWith(TT_ObjCMethodSpecifier))
return true;
@@ -288,6 +375,12 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
Previous.TokenText == "\'\\n\'"))))
return true;
+ if (Previous.is(TT_BlockComment) && Previous.IsMultiline)
+ return true;
+
+ if (State.NoContinuation)
+ return true;
+
return false;
}
@@ -297,6 +390,8 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
const FormatToken &Current = *State.NextToken;
assert(!State.Stack.empty());
+ State.NoContinuation = false;
+
if ((Current.is(TT_ImplicitStringLiteral) &&
(Current.Previous->Tok.getIdentifierInfo() == nullptr ||
Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
@@ -348,9 +443,25 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces;
+ // Indent preprocessor directives after the hash if required.
+ int PPColumnCorrection = 0;
+ if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash &&
+ Previous.is(tok::hash) && State.FirstIndent > 0 &&
+ (State.Line->Type == LT_PreprocessorDirective ||
+ State.Line->Type == LT_ImportStatement)) {
+ Spaces += State.FirstIndent;
+
+ // For preprocessor indent with tabs, State.Column will be 1 because of the
+ // hash. This causes second-level indents onward to have an extra space
+ // after the tabs. We avoid this misalignment by subtracting 1 from the
+ // column value passed to replaceWhitespace().
+ if (Style.UseTab != FormatStyle::UT_Never)
+ PPColumnCorrection = -1;
+ }
+
if (!DryRun)
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, Spaces,
- State.Column + Spaces);
+ State.Column + Spaces + PPColumnCorrection);
// If "BreakBeforeInheritanceComma" mode, don't break within the inheritance
// declaration unless there is multiple inheritance.
@@ -377,9 +488,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak &&
Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) &&
State.Column > getNewLineColumn(State) &&
- (!Previous.Previous ||
- !Previous.Previous->isOneOf(tok::kw_for, tok::kw_while,
- tok::kw_switch)) &&
+ (!Previous.Previous || !Previous.Previous->isOneOf(
+ tok::kw_for, tok::kw_while, tok::kw_switch)) &&
// Don't do this for simple (no expressions) one-argument function calls
// as that feels like needlessly wasting whitespace, e.g.:
//
@@ -445,7 +555,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
State.Column += Spaces;
if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
Previous.Previous &&
- Previous.Previous->isOneOf(tok::kw_if, tok::kw_for)) {
+ (Previous.Previous->isOneOf(tok::kw_if, tok::kw_for) ||
+ Previous.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) {
// Treat the condition inside an if as if it was a second function
// parameter, i.e. let nested calls have a continuation indent.
State.Stack.back().LastSpace = State.Column;
@@ -455,6 +566,11 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
!Previous.is(TT_OverloadedOperator)) ||
(Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
State.Stack.back().LastSpace = State.Column;
+ } else if (Previous.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers ==
+ FormatStyle::BCIS_AfterColon) {
+ State.Stack.back().Indent = State.Column;
+ State.Stack.back().LastSpace = State.Column;
} else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
TT_CtorInitializerColon)) &&
((Previous.getPrecedence() != prec::Assignment &&
@@ -587,8 +703,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
if (!DryRun) {
unsigned Newlines = std::max(
1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1));
+ bool ContinuePPDirective =
+ State.Line->InPPDirective && State.Line->Type != LT_ImportStatement;
Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column,
- State.Line->InPPDirective);
+ ContinuePPDirective);
}
if (!Current.isTrailingComment())
@@ -605,14 +723,14 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// Any break on this level means that the parent level has been broken
// and we need to avoid bin packing there.
bool NestedBlockSpecialCase =
- !Style.IsCpp() && Current.is(tok::r_brace) && State.Stack.size() > 1 &&
+ !Style.isCpp() && Current.is(tok::r_brace) && State.Stack.size() > 1 &&
State.Stack[State.Stack.size() - 2].NestedBlockInlined;
if (!NestedBlockSpecialCase)
for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i)
State.Stack[i].BreakBeforeParameter = true;
if (PreviousNonComment &&
- !PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
+ !PreviousNonComment->isOneOf(tok::comma, tok::colon, tok::semi) &&
(PreviousNonComment->isNot(TT_TemplateCloser) ||
Current.NestingLevel != 0) &&
!PreviousNonComment->isOneOf(
@@ -625,8 +743,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// before the corresponding } or ].
if (PreviousNonComment &&
(PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
- (PreviousNonComment->is(TT_TemplateString) &&
- PreviousNonComment->opensScope())))
+ opensProtoMessageField(*PreviousNonComment, Style)))
State.Stack.back().BreakBeforeClosingBrace = true;
if (State.Stack.back().AvoidBinPacking) {
@@ -666,7 +783,11 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
return Current.NestingLevel == 0 ? State.FirstIndent
: State.Stack.back().Indent;
- if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) {
+ if ((Current.isOneOf(tok::r_brace, tok::r_square) ||
+ (Current.is(tok::greater) &&
+ (Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto))) &&
+ State.Stack.size() > 1) {
if (Current.closesBlockOrBlockTypeList(Style))
return State.Stack[State.Stack.size() - 2].NestedBlockIndent;
if (Current.MatchingParen &&
@@ -674,16 +795,32 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return State.Stack[State.Stack.size() - 2].LastSpace;
return State.FirstIndent;
}
+ // Indent a closing parenthesis at the previous level if followed by a semi or
+ // opening brace. This allows indentations such as:
+ // foo(
+ // a,
+ // );
+ // function foo(
+ // a,
+ // ) {
+ // code(); //
+ // }
+ if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+ (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
+ return State.Stack[State.Stack.size() - 2].LastSpace;
if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
return State.Stack[State.Stack.size() - 2].LastSpace;
if (Current.is(tok::identifier) && Current.Next &&
- Current.Next->is(TT_DictLiteral))
+ (Current.Next->is(TT_DictLiteral) ||
+ ((Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) &&
+ Current.Next->isOneOf(TT_TemplateOpener, tok::l_brace))))
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;
@@ -746,6 +883,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return ContinuationIndent;
if (NextNonComment->is(TT_CtorInitializerComma))
return State.Stack.back().Indent;
+ if (PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon)
+ return State.Stack.back().Indent;
if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon,
TT_InheritanceComma))
return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
@@ -792,7 +932,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
if (Previous && Previous->is(tok::question))
State.Stack.back().QuestionColumn = State.Column;
}
- if (!Current.opensScope() && !Current.closesScope())
+ if (!Current.opensScope() && !Current.closesScope() &&
+ !Current.is(TT_PointerOrReference))
State.LowestLevelOnLine =
std::min(State.LowestLevelOnLine, Current.NestingLevel);
if (Current.isMemberAccess())
@@ -805,19 +946,31 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
State.FirstIndent + Style.ContinuationIndentWidth;
}
}
- if (Current.is(TT_CtorInitializerColon)) {
+ if (Current.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
// : First(...), ...
// Next(...)
// ^ line up here.
State.Stack.back().Indent =
- State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
+ State.Column +
+ (Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma
+ ? 0
+ : 2);
State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
State.Stack.back().AvoidBinPacking = true;
State.Stack.back().BreakBeforeParameter = false;
}
+ if (Current.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) {
+ State.Stack.back().Indent =
+ State.FirstIndent + Style.ConstructorInitializerIndentWidth;
+ State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
+ if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ State.Stack.back().AvoidBinPacking = true;
+ }
if (Current.is(TT_InheritanceColon))
State.Stack.back().Indent =
State.FirstIndent + Style.ContinuationIndentWidth;
@@ -844,8 +997,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
State.Stack[i].NoLineBreak = true;
State.Stack[State.Stack.size() - 2].NestedBlockInlined = false;
}
- if (Previous && (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) ||
- Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) &&
+ if (Previous &&
+ (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) ||
+ Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) &&
!Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) {
State.Stack.back().NestedBlockInlined =
!Newline &&
@@ -854,20 +1008,15 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
moveStatePastFakeLParens(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;
@@ -915,9 +1064,14 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
I != E; ++I) {
ParenState NewParenState = State.Stack.back();
NewParenState.ContainsLineBreak = false;
+ NewParenState.LastOperatorWrapped = true;
NewParenState.NoLineBreak =
NewParenState.NoLineBreak || State.Stack.back().NoLineBreakInOperand;
+ // Don't propagate AvoidBinPacking into subexpressions of arg/param lists.
+ if (*I > prec::Comma)
+ NewParenState.AvoidBinPacking = false;
+
// Indent from 'LastSpace' unless these are fake parentheses encapsulating
// a builder type call after 'return' or, if the alignment after opening
// brackets is disabled.
@@ -987,10 +1141,11 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
bool BreakBeforeParameter = false;
unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall,
State.Stack.back().NestedBlockIndent);
- if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
+ if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+ opensProtoMessageField(Current, Style)) {
if (Current.opensBlockOrBlockTypeList(Style)) {
- NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
- NewIndent = std::min(State.Column + 2, NewIndent);
+ NewIndent = Style.IndentWidth +
+ std::min(State.Column, State.Stack.back().NestedBlockIndent);
} else {
NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
}
@@ -998,11 +1153,14 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
bool EndsInComma = Current.MatchingParen &&
Current.MatchingParen->Previous &&
Current.MatchingParen->Previous->is(tok::comma);
- AvoidBinPacking =
- (Current.is(TT_ArrayInitializerLSquare) && EndsInComma) ||
- Current.is(TT_DictLiteral) ||
- Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments ||
- (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));
+ AvoidBinPacking = EndsInComma || Current.is(TT_DictLiteral) ||
+ Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto ||
+ !Style.BinPackArguments ||
+ (NextNoComment &&
+ NextNoComment->isOneOf(TT_DesignatedInitializerPeriod,
+ TT_DesignatedInitializerLSquare));
+ BreakBeforeParameter = EndsInComma;
if (Current.ParameterCount > 1)
NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1);
} else {
@@ -1020,25 +1178,20 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
LastSpace = std::max(LastSpace, State.Stack.back().Indent);
}
- // JavaScript template strings are special as we always want to indent
- // nested expressions relative to the ${}. Otherwise, this can create quite
- // a mess.
- if (Current.is(TT_TemplateString)) {
- unsigned Column = Current.IsMultiline
- ? Current.LastLineColumnWidth
- : State.Column + Current.ColumnWidth;
- NewIndent = Column;
- LastSpace = Column;
- NestedBlockIndent = Column;
- }
+ bool EndsInComma =
+ Current.MatchingParen &&
+ Current.MatchingParen->getPreviousNonComment() &&
+ Current.MatchingParen->getPreviousNonComment()->is(tok::comma);
AvoidBinPacking =
+ (Style.Language == FormatStyle::LK_JavaScript && EndsInComma) ||
(State.Line->MustBeDeclaration && !Style.BinPackParameters) ||
(!State.Line->MustBeDeclaration && !Style.BinPackArguments) ||
(Style.ExperimentalAutoDetectBinPacking &&
(Current.PackingKind == PPK_OnePerLine ||
(!BinPackInconclusiveFunctions &&
Current.PackingKind == PPK_Inconclusive)));
+
if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen) {
if (Style.ColumnLimit) {
// If this '[' opens an ObjC call, determine whether all parameters fit
@@ -1059,6 +1212,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
}
}
}
+
+ if (Style.Language == FormatStyle::LK_JavaScript && EndsInComma)
+ BreakBeforeParameter = true;
}
// Generally inherit NoLineBreak from the current scope to nested scope.
// However, don't do this for non-empty nested blocks, dict literals and
@@ -1112,6 +1268,89 @@ void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
State.Stack.back().BreakBeforeParameter = true;
}
+static unsigned getLastLineEndColumn(StringRef Text, unsigned StartColumn,
+ unsigned TabWidth,
+ encoding::Encoding Encoding) {
+ size_t LastNewlinePos = Text.find_last_of("\n");
+ if (LastNewlinePos == StringRef::npos) {
+ return StartColumn +
+ encoding::columnWidthWithTabs(Text, StartColumn, TabWidth, Encoding);
+ } else {
+ return encoding::columnWidthWithTabs(Text.substr(LastNewlinePos),
+ /*StartColumn=*/0, TabWidth, Encoding);
+ }
+}
+
+unsigned ContinuationIndenter::reformatRawStringLiteral(
+ const FormatToken &Current, unsigned StartColumn, LineState &State,
+ StringRef Delimiter, const FormatStyle &RawStringStyle, bool DryRun) {
+ // The text of a raw string is between the leading 'R"delimiter(' and the
+ // trailing 'delimiter)"'.
+ unsigned PrefixSize = 3 + Delimiter.size();
+ unsigned SuffixSize = 2 + Delimiter.size();
+
+ // The first start column is the column the raw text starts.
+ unsigned FirstStartColumn = StartColumn + PrefixSize;
+
+ // The next start column is the intended indentation a line break inside
+ // the raw string at level 0. It is determined by the following rules:
+ // - if the content starts on newline, it is one level more than the current
+ // indent, and
+ // - if the content does not start on a newline, it is the first start
+ // column.
+ // These rules have the advantage that the formatted content both does not
+ // violate the rectangle rule and visually flows within the surrounding
+ // source.
+ bool ContentStartsOnNewline = Current.TokenText[PrefixSize] == '\n';
+ unsigned NextStartColumn = ContentStartsOnNewline
+ ? State.Stack.back().Indent + Style.IndentWidth
+ : FirstStartColumn;
+
+ // The last start column is the column the raw string suffix starts if it is
+ // put on a newline.
+ // The last start column is the intended indentation of the raw string postfix
+ // if it is put on a newline. It is determined by the following rules:
+ // - if the raw string prefix starts on a newline, it is the column where
+ // that raw string prefix starts, and
+ // - if the raw string prefix does not start on a newline, it is the current
+ // indent.
+ unsigned LastStartColumn = Current.NewlinesBefore
+ ? FirstStartColumn - PrefixSize
+ : State.Stack.back().Indent;
+
+ std::string RawText =
+ Current.TokenText.substr(PrefixSize).drop_back(SuffixSize);
+
+ std::pair<tooling::Replacements, unsigned> Fixes = internal::reformat(
+ RawStringStyle, RawText, {tooling::Range(0, RawText.size())},
+ FirstStartColumn, NextStartColumn, LastStartColumn, "<stdin>",
+ /*FormattingAttemptStatus=*/nullptr);
+
+ auto NewCode = applyAllReplacements(RawText, Fixes.first);
+ tooling::Replacements NoFixes;
+ if (!NewCode) {
+ State.Column += Current.ColumnWidth;
+ return 0;
+ }
+ if (!DryRun) {
+ SourceLocation OriginLoc =
+ Current.Tok.getLocation().getLocWithOffset(PrefixSize);
+ for (const tooling::Replacement &Fix : Fixes.first) {
+ auto Err = Whitespaces.addReplacement(tooling::Replacement(
+ SourceMgr, OriginLoc.getLocWithOffset(Fix.getOffset()),
+ Fix.getLength(), Fix.getReplacementText()));
+ if (Err) {
+ llvm::errs() << "Failed to reformat raw string: "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
+ }
+ unsigned RawLastLineEndColumn = getLastLineEndColumn(
+ *NewCode, FirstStartColumn, Style.TabWidth, Encoding);
+ State.Column = RawLastLineEndColumn + SuffixSize;
+ return Fixes.second;
+}
+
unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
LineState &State) {
if (!Current.IsMultiline)
@@ -1134,9 +1373,18 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
LineState &State,
bool DryRun) {
- // Don't break multi-line tokens other than block comments. Instead, just
- // update the state.
- if (Current.isNot(TT_BlockComment) && Current.IsMultiline)
+ // Compute the raw string style to use in case this is a raw string literal
+ // that can be reformatted.
+ llvm::Optional<StringRef> Delimiter = None;
+ llvm::Optional<FormatStyle> RawStringStyle = None;
+ if (Current.isStringLiteral())
+ Delimiter = getRawStringDelimiter(Current.TokenText);
+ if (Delimiter)
+ RawStringStyle = RawStringFormats.get(*Delimiter);
+
+ // Don't break multi-line tokens other than block comments and raw string
+ // literals. Instead, just update the state.
+ if (Current.isNot(TT_BlockComment) && !RawStringStyle && Current.IsMultiline)
return addMultilineToken(Current, State);
// Don't break implicit string literals or import statements.
@@ -1171,21 +1419,20 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
if (Current.IsUnterminatedLiteral)
return 0;
+ if (RawStringStyle) {
+ RawStringStyle->ColumnLimit = ColumnLimit;
+ return reformatRawStringLiteral(Current, StartColumn, State, *Delimiter,
+ *RawStringStyle, DryRun);
+ }
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\""))) ||
@@ -1197,7 +1444,7 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
return 0;
}
} else if (Current.is(TT_BlockComment)) {
- if (!Current.isTrailingComment() || !Style.ReflowComments ||
+ if (!Style.ReflowComments ||
// 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.
@@ -1232,6 +1479,7 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
bool ReflowInProgress = false;
unsigned Penalty = 0;
unsigned RemainingTokenColumns = 0;
+ unsigned TailOffset = 0;
for (unsigned LineIndex = 0, EndIndex = Token->getLineCount();
LineIndex != EndIndex; ++LineIndex) {
BreakableToken::Split SplitBefore(StringRef::npos, 0);
@@ -1240,8 +1488,9 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
RemainingSpace, CommentPragmasRegex);
}
ReflowInProgress = SplitBefore.first != StringRef::npos;
- unsigned TailOffset =
+ TailOffset =
ReflowInProgress ? (SplitBefore.first + SplitBefore.second) : 0;
+ BreakInserted = BreakInserted || Token->introducesBreakBefore(LineIndex);
if (!DryRun)
Token->replaceWhitespaceBefore(LineIndex, RemainingTokenColumns,
RemainingSpace, SplitBefore, Whitespaces);
@@ -1297,6 +1546,16 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
}
}
+ BreakableToken::Split SplitAfterLastLine =
+ Token->getSplitAfterLastLine(TailOffset, ColumnLimit);
+ if (SplitAfterLastLine.first != StringRef::npos) {
+ if (!DryRun)
+ Token->replaceWhitespaceAfterLastLine(TailOffset, SplitAfterLastLine,
+ Whitespaces);
+ RemainingTokenColumns = Token->getLineLengthAfterSplitAfterLastLine(
+ TailOffset, SplitAfterLastLine);
+ }
+
State.Column = RemainingTokenColumns;
if (BreakInserted) {
@@ -1308,6 +1567,9 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
State.Stack[i].BreakBeforeParameter = true;
}
+ if (Current.is(TT_BlockComment))
+ State.NoContinuation = true;
+
Penalty += Current.isStringLiteral() ? Style.PenaltyBreakString
: Style.PenaltyBreakComment;
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index 9a06aa6f62..3bc9929b3d 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -20,6 +20,8 @@
#include "FormatToken.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Regex.h"
+#include <map>
+#include <tuple>
namespace clang {
class SourceManager;
@@ -30,8 +32,17 @@ class AnnotatedLine;
struct FormatToken;
struct LineState;
struct ParenState;
+struct RawStringFormatStyleManager;
class WhitespaceManager;
+struct RawStringFormatStyleManager {
+ llvm::StringMap<FormatStyle> DelimiterStyle;
+
+ RawStringFormatStyleManager(const FormatStyle &CodeStyle);
+
+ llvm::Optional<FormatStyle> get(StringRef Delimiter) const;
+};
+
class ContinuationIndenter {
public:
/// \brief Constructs a \c ContinuationIndenter to format \p Line starting in
@@ -44,9 +55,11 @@ public:
bool BinPackInconclusiveFunctions);
/// \brief Get the initial state, i.e. the state after placing \p Line's
- /// first token at \p FirstIndent.
- LineState getInitialState(unsigned FirstIndent, const AnnotatedLine *Line,
- bool DryRun);
+ /// first token at \p FirstIndent. When reformatting a fragment of code, as in
+ /// the case of formatting inside raw string literals, \p FirstStartColumn is
+ /// the column at which the state of the parent formatter is.
+ LineState getInitialState(unsigned FirstIndent, unsigned FirstStartColumn,
+ const AnnotatedLine *Line, bool DryRun);
// FIXME: canBreak and mustBreak aren't strictly indentation-related. Find a
// better home.
@@ -88,15 +101,24 @@ private:
/// \brief Update 'State' with the next token opening a nested block.
void moveStateToNewBlock(LineState &State);
+ /// \brief Reformats a raw string literal.
+ ///
+ /// \returns An extra penalty induced by reformatting the token.
+ unsigned reformatRawStringLiteral(const FormatToken &Current,
+ unsigned StartColumn, LineState &State,
+ StringRef Delimiter,
+ const FormatStyle &RawStringStyle,
+ bool DryRun);
+
/// \brief If the current token sticks out over the end of the line, break
/// it if possible.
///
/// \returns An extra penalty if a token was broken, otherwise 0.
///
- /// The returned penalty will cover the cost of the additional line breaks and
- /// column limit violation in all lines except for the last one. The penalty
- /// for the column limit violation in the last line (and in single line
- /// tokens) is handled in \c addNextStateToQueue.
+ /// The returned penalty will cover the cost of the additional line breaks
+ /// and column limit violation in all lines except for the last one. The
+ /// penalty for the column limit violation in the last line (and in single
+ /// line tokens) is handled in \c addNextStateToQueue.
unsigned breakProtrudingToken(const FormatToken &Current, LineState &State,
bool DryRun);
@@ -143,6 +165,7 @@ private:
encoding::Encoding Encoding;
bool BinPackInconclusiveFunctions;
llvm::Regex CommentPragmasRegex;
+ const RawStringFormatStyleManager RawStringFormats;
};
struct ParenState {
@@ -318,6 +341,9 @@ struct LineState {
/// \brief \c true if this line contains a continued for-loop section.
bool LineContainsContinuedForLoopSection;
+ /// \brief \c true if \p NextToken should not continue this line.
+ bool NoContinuation;
+
/// \brief The \c NestingLevel at the start of this line.
unsigned StartOfLineLevel;
@@ -364,6 +390,8 @@ struct LineState {
if (LineContainsContinuedForLoopSection !=
Other.LineContainsContinuedForLoopSection)
return LineContainsContinuedForLoopSection;
+ if (NoContinuation != Other.NoContinuation)
+ return NoContinuation;
if (StartOfLineLevel != Other.StartOfLineLevel)
return StartOfLineLevel < Other.StartOfLineLevel;
if (LowestLevelOnLine != Other.LowestLevelOnLine)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 9bb2a97ce5..2252dd9743 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -16,6 +16,7 @@
#include "clang/Format/Format.h"
#include "AffectedRangeManager.h"
#include "ContinuationIndenter.h"
+#include "FormatInternal.h"
#include "FormatTokenLexer.h"
#include "NamespaceEndCommentsFixer.h"
#include "SortJavaScriptImports.h"
@@ -23,6 +24,7 @@
#include "TokenAnnotator.h"
#include "UnwrappedLineFormatter.h"
#include "UnwrappedLineParser.h"
+#include "UsingDeclarationsSorter.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
@@ -43,8 +45,8 @@
using clang::format::FormatStyle;
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
namespace llvm {
namespace yaml {
@@ -56,6 +58,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
+ IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
}
};
@@ -96,6 +99,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
IO.enumCase(Value, "All", FormatStyle::SFS_All);
IO.enumCase(Value, "true", FormatStyle::SFS_All);
IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
}
};
@@ -124,6 +128,24 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
};
template <>
+struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
+ static void
+ enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
+ IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
+ IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
+ IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
+ static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
+ IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
+ }
+};
+
+template <>
struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
IO.enumCase(Value, "None", FormatStyle::RTBS_None);
@@ -171,6 +193,20 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::EscapedNewlineAlignmentStyle &Value) {
+ IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
+ IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
+ IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
+ IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
@@ -233,6 +269,7 @@ template <> struct MappingTraits<FormatStyle> {
// For backward compatibility.
if (!IO.outputting()) {
+ IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
IO.mapOptional("IndentFunctionDeclarationAfterType",
Style.IndentWrappedFunctionNames);
@@ -247,7 +284,7 @@ template <> struct MappingTraits<FormatStyle> {
Style.AlignConsecutiveAssignments);
IO.mapOptional("AlignConsecutiveDeclarations",
Style.AlignConsecutiveDeclarations);
- IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlinesLeft);
+ IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
@@ -289,17 +326,29 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("BreakBeforeBinaryOperators",
Style.BreakBeforeBinaryOperators);
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
+ IO.mapOptional("BreakBeforeInheritanceComma",
+ Style.BreakBeforeInheritanceComma);
IO.mapOptional("BreakBeforeTernaryOperators",
Style.BreakBeforeTernaryOperators);
+
+ bool BreakConstructorInitializersBeforeComma = false;
IO.mapOptional("BreakConstructorInitializersBeforeComma",
- Style.BreakConstructorInitializersBeforeComma);
+ BreakConstructorInitializersBeforeComma);
+ IO.mapOptional("BreakConstructorInitializers",
+ Style.BreakConstructorInitializers);
+ // If BreakConstructorInitializersBeforeComma was specified but
+ // BreakConstructorInitializers was not, initialize the latter from the
+ // former for backwards compatibility.
+ if (BreakConstructorInitializersBeforeComma &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
+
IO.mapOptional("BreakAfterJavaFieldAnnotations",
Style.BreakAfterJavaFieldAnnotations);
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
- IO.mapOptional("BreakBeforeInheritanceComma",
- Style.BreakBeforeInheritanceComma);
+ IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
IO.mapOptional("ConstructorInitializerIndentWidth",
@@ -315,6 +364,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("IncludeCategories", Style.IncludeCategories);
IO.mapOptional("IncludeIsMainRegex", Style.IncludeIsMainRegex);
IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
+ IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
IO.mapOptional("IndentWidth", Style.IndentWidth);
IO.mapOptional("IndentWrappedFunctionNames",
Style.IndentWrappedFunctionNames);
@@ -330,6 +380,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
+ IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
Style.PenaltyBreakBeforeFirstCallParameter);
IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
@@ -340,10 +391,13 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
Style.PenaltyReturnTypeOnItsOwnLine);
IO.mapOptional("PointerAlignment", Style.PointerAlignment);
+ IO.mapOptional("RawStringFormats", Style.RawStringFormats);
IO.mapOptional("ReflowComments", Style.ReflowComments);
IO.mapOptional("SortIncludes", Style.SortIncludes);
+ IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
- IO.mapOptional("SpaceAfterTemplateKeyword", Style.SpaceAfterTemplateKeyword);
+ IO.mapOptional("SpaceAfterTemplateKeyword",
+ Style.SpaceAfterTemplateKeyword);
IO.mapOptional("SpaceBeforeAssignmentOperators",
Style.SpaceBeforeAssignmentOperators);
IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
@@ -373,9 +427,13 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
+ IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
+ IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
+ IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
+ IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
}
};
@@ -386,6 +444,14 @@ template <> struct MappingTraits<FormatStyle::IncludeCategory> {
}
};
+template <> struct MappingTraits<FormatStyle::RawStringFormat> {
+ static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
+ IO.mapOptional("Delimiter", Format.Delimiter);
+ IO.mapOptional("Language", Format.Language);
+ IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
+ }
+};
+
// Allows to read vector<FormatStyle> while keeping default values.
// IO.getContext() should contain a pointer to the FormatStyle structure, that
// will be used to get default values for missing keys.
@@ -450,8 +516,9 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
return Style;
FormatStyle Expanded = Style;
- Expanded.BraceWrapping = {false, false, false, false, false, false,
- false, false, false, false, false};
+ Expanded.BraceWrapping = {false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, true, true, true};
switch (Style.BreakBeforeBraces) {
case FormatStyle::BS_Linux:
Expanded.BraceWrapping.AfterClass = true;
@@ -464,6 +531,9 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
Expanded.BraceWrapping.AfterFunction = true;
Expanded.BraceWrapping.AfterStruct = true;
Expanded.BraceWrapping.AfterUnion = true;
+ Expanded.BraceWrapping.AfterExternBlock = true;
+ Expanded.BraceWrapping.SplitEmptyFunction = true;
+ Expanded.BraceWrapping.SplitEmptyRecord = false;
break;
case FormatStyle::BS_Stroustrup:
Expanded.BraceWrapping.AfterFunction = true;
@@ -478,12 +548,13 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
Expanded.BraceWrapping.AfterNamespace = true;
Expanded.BraceWrapping.AfterObjCDeclaration = true;
Expanded.BraceWrapping.AfterStruct = true;
+ Expanded.BraceWrapping.AfterExternBlock = true;
Expanded.BraceWrapping.BeforeCatch = true;
Expanded.BraceWrapping.BeforeElse = true;
break;
case FormatStyle::BS_GNU:
- Expanded.BraceWrapping = {true, true, true, true, true, true,
- true, true, true, true, true};
+ Expanded.BraceWrapping = {true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true};
break;
case FormatStyle::BS_WebKit:
Expanded.BraceWrapping.AfterFunction = true;
@@ -498,7 +569,7 @@ FormatStyle getLLVMStyle() {
FormatStyle LLVMStyle;
LLVMStyle.Language = FormatStyle::LK_Cpp;
LLVMStyle.AccessModifierOffset = -2;
- LLVMStyle.AlignEscapedNewlinesLeft = false;
+ LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
LLVMStyle.AlignOperands = true;
LLVMStyle.AlignTrailingComments = true;
@@ -514,19 +585,21 @@ FormatStyle getLLVMStyle() {
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = false;
- LLVMStyle.BinPackParameters = true;
LLVMStyle.BinPackArguments = true;
+ LLVMStyle.BinPackParameters = true;
LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
LLVMStyle.BreakBeforeTernaryOperators = true;
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
- LLVMStyle.BraceWrapping = {false, false, false, false, false, false,
- false, false, false, false, false};
+ LLVMStyle.BraceWrapping = {false, false, false, false, false,
+ false, false, false, false, false,
+ false, false, true, true, true};
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
- LLVMStyle.BreakConstructorInitializersBeforeComma = false;
+ LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
LLVMStyle.BreakBeforeInheritanceComma = false;
LLVMStyle.BreakStringLiterals = true;
LLVMStyle.ColumnLimit = 80;
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
+ LLVMStyle.CompactNamespaces = false;
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
LLVMStyle.ConstructorInitializerIndentWidth = 4;
LLVMStyle.ContinuationIndentWidth = 4;
@@ -538,10 +611,11 @@ FormatStyle getLLVMStyle() {
LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2},
- {"^(<|\"(gtest|isl|json)/)", 3},
+ {"^(<|\"(gtest|gmock|isl|json)/)", 3},
{".*", 1}};
- LLVMStyle.IncludeIsMainRegex = "$";
+ LLVMStyle.IncludeIsMainRegex = "(Test)?$";
LLVMStyle.IndentCaseLabels = false;
+ LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
LLVMStyle.IndentWrappedFunctionNames = false;
LLVMStyle.IndentWidth = 2;
LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
@@ -557,6 +631,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Cpp11;
LLVMStyle.UseTab = FormatStyle::UT_Never;
+ LLVMStyle.RawStringFormats = {{"pb", FormatStyle::LK_TextProto, "google"}};
LLVMStyle.ReflowComments = true;
LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpacesInSquareBrackets = false;
@@ -569,6 +644,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.SpaceBeforeAssignmentOperators = true;
LLVMStyle.SpacesInAngles = false;
+ LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
LLVMStyle.PenaltyBreakComment = 300;
LLVMStyle.PenaltyBreakFirstLessLess = 120;
LLVMStyle.PenaltyBreakString = 1000;
@@ -578,23 +654,31 @@ FormatStyle getLLVMStyle() {
LLVMStyle.DisableFormat = false;
LLVMStyle.SortIncludes = true;
+ LLVMStyle.SortUsingDeclarations = true;
return LLVMStyle;
}
FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
+ if (Language == FormatStyle::LK_TextProto) {
+ FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
+ GoogleStyle.Language = FormatStyle::LK_TextProto;
+ return GoogleStyle;
+ }
+
FormatStyle GoogleStyle = getLLVMStyle();
GoogleStyle.Language = Language;
GoogleStyle.AccessModifierOffset = -1;
- GoogleStyle.AlignEscapedNewlinesLeft = true;
+ GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
GoogleStyle.AllowShortLoopsOnASingleLine = true;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
GoogleStyle.AlwaysBreakTemplateDeclarations = true;
GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
GoogleStyle.DerivePointerAlignment = true;
- GoogleStyle.IncludeCategories = {{"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
+ GoogleStyle.IncludeCategories = {
+ {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
GoogleStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
GoogleStyle.IndentCaseLabels = true;
GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
@@ -624,9 +708,10 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
GoogleStyle.BreakBeforeTernaryOperators = false;
- // 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)";
+ // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
+ // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
+ GoogleStyle.CommentPragmas =
+ "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
GoogleStyle.SpacesInContainerLiterals = false;
@@ -669,15 +754,14 @@ FormatStyle getMozillaStyle() {
FormatStyle MozillaStyle = getLLVMStyle();
MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
- MozillaStyle.AlwaysBreakAfterReturnType =
- FormatStyle::RTBS_TopLevel;
+ MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel;
MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
FormatStyle::DRTBS_TopLevel;
MozillaStyle.AlwaysBreakTemplateDeclarations = true;
MozillaStyle.BinPackParameters = false;
MozillaStyle.BinPackArguments = false;
MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
- MozillaStyle.BreakConstructorInitializersBeforeComma = true;
+ MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
MozillaStyle.BreakBeforeInheritanceComma = true;
MozillaStyle.ConstructorInitializerIndentWidth = 2;
MozillaStyle.ContinuationIndentWidth = 2;
@@ -700,7 +784,7 @@ FormatStyle getWebKitStyle() {
Style.AlignTrailingComments = false;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
- Style.BreakConstructorInitializersBeforeComma = true;
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Style.Cpp11BracedListStyle = false;
Style.ColumnLimit = 0;
Style.FixNamespaceComments = false;
@@ -731,6 +815,7 @@ FormatStyle getNoStyle() {
FormatStyle NoStyle = getLLVMStyle();
NoStyle.DisableFormat = true;
NoStyle.SortIncludes = false;
+ NoStyle.SortUsingDeclarations = false;
return NoStyle;
}
@@ -822,7 +907,7 @@ public:
JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
: TokenAnalyzer(Env, Style) {}
- tooling::Replacements
+ std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) override {
@@ -830,7 +915,7 @@ public:
AnnotatedLines.end());
tooling::Replacements Result;
requoteJSStringLiteral(AnnotatedLines, Result);
- return Result;
+ return {Result, 0};
}
private:
@@ -908,10 +993,10 @@ private:
class Formatter : public TokenAnalyzer {
public:
Formatter(const Environment &Env, const FormatStyle &Style,
- bool *IncompleteFormat)
- : TokenAnalyzer(Env, Style), IncompleteFormat(IncompleteFormat) {}
+ FormattingAttemptStatus *Status)
+ : TokenAnalyzer(Env, Style), Status(Status) {}
- tooling::Replacements
+ std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) override {
@@ -930,17 +1015,23 @@ public:
ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
Env.getSourceManager(), Whitespaces, Encoding,
BinPackInconclusiveFunctions);
- UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(),
- IncompleteFormat)
- .format(AnnotatedLines);
+ unsigned Penalty =
+ UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
+ Tokens.getKeywords(), Env.getSourceManager(),
+ Status)
+ .format(AnnotatedLines, /*DryRun=*/false,
+ /*AdditionalIndent=*/0,
+ /*FixBadIndentation=*/false,
+ /*FirstStartColumn=*/Env.getFirstStartColumn(),
+ /*NextStartColumn=*/Env.getNextStartColumn(),
+ /*LastStartColumn=*/Env.getLastStartColumn());
for (const auto &R : Whitespaces.generateReplacements())
if (Result.add(R))
- return Result;
- return Result;
+ return std::make_pair(Result, 0);
+ return std::make_pair(Result, Penalty);
}
private:
-
static bool inputUsesCRLF(StringRef Text) {
return Text.count('\r') * 2 > Text.count('\n');
}
@@ -1013,7 +1104,7 @@ private:
}
bool BinPackInconclusiveFunctions;
- bool *IncompleteFormat;
+ FormattingAttemptStatus *Status;
};
// This class clean up the erroneous/redundant code around the given ranges in
@@ -1025,7 +1116,7 @@ public:
DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
// FIXME: eliminate unused parameters.
- tooling::Replacements
+ std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) override {
@@ -1053,7 +1144,7 @@ public:
}
}
- return generateFixes();
+ return {generateFixes(), 0};
}
private:
@@ -1364,7 +1455,7 @@ public:
: Style(Style), FileName(FileName) {
FileStem = llvm::sys::path::stem(FileName);
for (const auto &Category : Style.IncludeCategories)
- CategoryRegexs.emplace_back(Category.Regex);
+ CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
FileName.endswith(".cpp") || FileName.endswith(".c++") ||
FileName.endswith(".cxx") || FileName.endswith(".m") ||
@@ -1392,9 +1483,11 @@ private:
return false;
StringRef HeaderStem =
llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
- if (FileStem.startswith(HeaderStem)) {
+ if (FileStem.startswith(HeaderStem) ||
+ FileStem.startswith_lower(HeaderStem)) {
llvm::Regex MainIncludeRegex(
- (HeaderStem + Style.IncludeIsMainRegex).str());
+ (HeaderStem + Style.IncludeIsMainRegex).str(),
+ llvm::Regex::IgnoreCase);
if (MainIncludeRegex.match(FileStem))
return true;
}
@@ -1480,12 +1573,16 @@ bool isMpegTS(StringRef Code) {
return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
}
+bool isLikelyXml(StringRef Code) { return Code.ltrim().startswith("<"); }
+
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 (isLikelyXml(Code))
+ return Replaces;
if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
isMpegTS(Code))
return Replaces;
@@ -1671,7 +1768,7 @@ bool isDeletedHeader(llvm::StringRef HeaderName,
tooling::Replacements
fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
const FormatStyle &Style) {
- if (!Style.IsCpp())
+ if (!Style.isCpp())
return Replaces;
tooling::Replacements HeaderInsertions;
@@ -1828,55 +1925,105 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
return processReplacements(Cleanup, Code, NewReplaces, Style);
}
-tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
- ArrayRef<tooling::Range> Ranges,
- StringRef FileName, bool *IncompleteFormat) {
+namespace internal {
+std::pair<tooling::Replacements, unsigned>
+reformat(const FormatStyle &Style, StringRef Code,
+ ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
+ unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
+ FormattingAttemptStatus *Status) {
FormatStyle Expanded = expandPresets(Style);
if (Expanded.DisableFormat)
- return tooling::Replacements();
+ return {tooling::Replacements(), 0};
+ if (isLikelyXml(Code))
+ return {tooling::Replacements(), 0};
if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
- return tooling::Replacements();
- auto Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
-
- 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(Fixes, Ranges));
- Formatter Format(*NewEnv, Expanded, IncompleteFormat);
- return Fixes.merge(Format.process());
- }
- }
- Formatter Format(*Env, Expanded, IncompleteFormat);
- return Format.process();
- };
+ return {tooling::Replacements(), 0};
+
+ typedef std::function<std::pair<tooling::Replacements, unsigned>(
+ const Environment &)>
+ AnalyzerPass;
+ SmallVector<AnalyzerPass, 4> Passes;
+
+ if (Style.Language == FormatStyle::LK_Cpp) {
+ if (Style.FixNamespaceComments)
+ Passes.emplace_back([&](const Environment &Env) {
+ return NamespaceEndCommentsFixer(Env, Expanded).process();
+ });
- if (Style.Language == FormatStyle::LK_Cpp &&
- Style.FixNamespaceComments) {
- NamespaceEndCommentsFixer CommentsFixer(*Env, Expanded);
- return reformatAfterApplying(CommentsFixer);
+ if (Style.SortUsingDeclarations)
+ Passes.emplace_back([&](const Environment &Env) {
+ return UsingDeclarationsSorter(Env, Expanded).process();
+ });
}
if (Style.Language == FormatStyle::LK_JavaScript &&
- Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) {
- JavaScriptRequoter Requoter(*Env, Expanded);
- return reformatAfterApplying(Requoter);
+ Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
+ Passes.emplace_back([&](const Environment &Env) {
+ return JavaScriptRequoter(Env, Expanded).process();
+ });
+
+ Passes.emplace_back([&](const Environment &Env) {
+ return Formatter(Env, Expanded, Status).process();
+ });
+
+ std::unique_ptr<Environment> Env = Environment::CreateVirtualEnvironment(
+ Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
+ LastStartColumn);
+ llvm::Optional<std::string> CurrentCode = None;
+ tooling::Replacements Fixes;
+ unsigned Penalty = 0;
+ for (size_t I = 0, E = Passes.size(); I < E; ++I) {
+ std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
+ auto NewCode = applyAllReplacements(
+ CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
+ if (NewCode) {
+ Fixes = Fixes.merge(PassFixes.first);
+ Penalty += PassFixes.second;
+ if (I + 1 < E) {
+ CurrentCode = std::move(*NewCode);
+ Env = Environment::CreateVirtualEnvironment(
+ *CurrentCode, FileName,
+ tooling::calculateRangesAfterReplacements(Fixes, Ranges),
+ FirstStartColumn, NextStartColumn, LastStartColumn);
+ }
+ }
}
- Formatter Format(*Env, Expanded, IncompleteFormat);
- return Format.process();
+ return {Fixes, Penalty};
+}
+} // namespace internal
+
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName,
+ FormattingAttemptStatus *Status) {
+ return internal::reformat(Style, Code, Ranges,
+ /*FirstStartColumn=*/0,
+ /*NextStartColumn=*/0,
+ /*LastStartColumn=*/0, FileName, Status)
+ .first;
}
tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName) {
+ // cleanups only apply to C++ (they mostly concern ctor commas etc.)
+ if (Style.Language != FormatStyle::LK_Cpp)
+ return tooling::Replacements();
std::unique_ptr<Environment> Env =
Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
Cleaner Clean(*Env, Style);
- return Clean.process();
+ return Clean.process().first;
+}
+
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName, bool *IncompleteFormat) {
+ FormattingAttemptStatus Status;
+ auto Result = reformat(Style, Code, Ranges, FileName, &Status);
+ if (!Status.FormatComplete)
+ *IncompleteFormat = true;
+ return Result;
}
tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
@@ -1886,7 +2033,17 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
std::unique_ptr<Environment> Env =
Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
NamespaceEndCommentsFixer Fix(*Env, Style);
- return Fix.process();
+ return Fix.process().first;
+}
+
+tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName) {
+ std::unique_ptr<Environment> Env =
+ Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+ UsingDeclarationsSorter Sorter(*Env, Style);
+ return Sorter.process().first;
}
LangOptions getFormattingLangOpts(const FormatStyle &Style) {
@@ -1894,8 +2051,9 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
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.IsCpp();
+ bool AlternativeOperators = Style.isCpp();
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
diff --git a/lib/Format/FormatInternal.h b/lib/Format/FormatInternal.h
new file mode 100644
index 0000000000..1373e9d2ee
--- /dev/null
+++ b/lib/Format/FormatInternal.h
@@ -0,0 +1,79 @@
+//===--- FormatInternal.h - Format C++ code ---------------------*- 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 Format APIs to be used internally by the
+/// formatting library implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
+#define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
+
+namespace clang {
+namespace format {
+namespace internal {
+
+/// \brief Reformats the given \p Ranges in the code fragment \p Code.
+///
+/// A fragment of code could conceptually be surrounded by other code that might
+/// constrain how that fragment is laid out.
+/// For example, consider the fragment of code between 'R"(' and ')"',
+/// exclusive, in the following code:
+///
+/// void outer(int x) {
+/// string inner = R"(name: data
+/// ^ FirstStartColumn
+/// value: {
+/// x: 1
+/// ^ NextStartColumn
+/// }
+/// )";
+/// ^ LastStartColumn
+/// }
+///
+/// The outer code can influence the inner fragment as follows:
+/// * \p FirstStartColumn specifies the column at which \p Code starts.
+/// * \p NextStartColumn specifies the additional indent dictated by the
+/// surrounding code. It is applied to the rest of the lines of \p Code.
+/// * \p LastStartColumn specifies the column at which the last line of
+/// \p Code should end, in case the last line is an empty line.
+///
+/// In the case where the last line of the fragment contains content,
+/// the fragment ends at the end of that content and \p LastStartColumn is
+/// not taken into account, for example in:
+///
+/// void block() {
+/// string inner = R"(name: value)";
+/// }
+///
+/// Each range is extended on either end to its next bigger logic unit, i.e.
+/// everything that might influence its formatting or might be influenced by its
+/// formatting.
+///
+/// Returns a pair P, where:
+/// * P.first are the ``Replacements`` necessary to make all \p Ranges comply
+/// with \p Style.
+/// * P.second is the penalty induced by formatting the fragment \p Code.
+/// If the formatting of the fragment doesn't have a notion of penalty,
+/// returns 0.
+///
+/// If ``Status`` is non-null, its value will be populated with the status of
+/// this formatting attempt. See \c FormattingAttemptStatus.
+std::pair<tooling::Replacements, unsigned>
+reformat(const FormatStyle &Style, StringRef Code,
+ ArrayRef<tooling::Range> Ranges, unsigned FirstStartColumn,
+ unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
+ FormattingAttemptStatus *Status);
+
+} // namespace internal
+} // namespace format
+} // namespace clang
+
+#endif
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index ba5bf03a63..10ac392abb 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -25,10 +25,9 @@ namespace format {
const char *getTokenTypeName(TokenType Type) {
static const char *const TokNames[] = {
#define TYPE(X) #X,
-LIST_TOKEN_TYPES
+ LIST_TOKEN_TYPES
#undef TYPE
- nullptr
- };
+ nullptr};
if (Type < NUM_TOKEN_TYPES)
return TokNames[Type];
@@ -52,6 +51,7 @@ bool FormatToken::isSimpleTypeSpecifier() const {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_wchar_t:
case tok::kw_bool:
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index c9649126d9..3dc0ab0e7c 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -21,79 +21,84 @@
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include <memory>
+#include <unordered_set>
namespace clang {
namespace format {
-#define LIST_TOKEN_TYPES \
- TYPE(ArrayInitializerLSquare) \
- TYPE(ArraySubscriptLSquare) \
- TYPE(AttributeParen) \
- TYPE(BinaryOperator) \
- TYPE(BitFieldColon) \
- TYPE(BlockComment) \
- TYPE(CastRParen) \
- TYPE(ConditionalExpr) \
- TYPE(ConflictAlternative) \
- TYPE(ConflictEnd) \
- TYPE(ConflictStart) \
- TYPE(CtorInitializerColon) \
- TYPE(CtorInitializerComma) \
- TYPE(DesignatedInitializerPeriod) \
- TYPE(DictLiteral) \
- TYPE(ForEachMacro) \
- TYPE(FunctionAnnotationRParen) \
- TYPE(FunctionDeclarationName) \
- TYPE(FunctionLBrace) \
- 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) \
- TYPE(LambdaArrow) \
- TYPE(LambdaLSquare) \
- TYPE(LeadingJavaAnnotation) \
- TYPE(LineComment) \
- TYPE(MacroBlockBegin) \
- TYPE(MacroBlockEnd) \
- TYPE(ObjCBlockLBrace) \
- TYPE(ObjCBlockLParen) \
- TYPE(ObjCDecl) \
- TYPE(ObjCForIn) \
- TYPE(ObjCMethodExpr) \
- TYPE(ObjCMethodSpecifier) \
- TYPE(ObjCProperty) \
- TYPE(ObjCStringLiteral) \
- TYPE(OverloadedOperator) \
- TYPE(OverloadedOperatorLParen) \
- TYPE(PointerOrReference) \
- TYPE(PureVirtualSpecifier) \
- TYPE(RangeBasedForLoopColon) \
- TYPE(RegexLiteral) \
- TYPE(SelectorName) \
- TYPE(StartOfName) \
- TYPE(TemplateCloser) \
- TYPE(TemplateOpener) \
- TYPE(TemplateString) \
- TYPE(TrailingAnnotation) \
- TYPE(TrailingReturnArrow) \
- TYPE(TrailingUnaryOperator) \
- TYPE(UnaryOperator) \
+#define LIST_TOKEN_TYPES \
+ TYPE(ArrayInitializerLSquare) \
+ TYPE(ArraySubscriptLSquare) \
+ TYPE(AttributeParen) \
+ TYPE(BinaryOperator) \
+ TYPE(BitFieldColon) \
+ TYPE(BlockComment) \
+ TYPE(CastRParen) \
+ TYPE(ConditionalExpr) \
+ TYPE(ConflictAlternative) \
+ TYPE(ConflictEnd) \
+ TYPE(ConflictStart) \
+ TYPE(CtorInitializerColon) \
+ TYPE(CtorInitializerComma) \
+ TYPE(DesignatedInitializerLSquare) \
+ TYPE(DesignatedInitializerPeriod) \
+ TYPE(DictLiteral) \
+ TYPE(ForEachMacro) \
+ TYPE(FunctionAnnotationRParen) \
+ TYPE(FunctionDeclarationName) \
+ TYPE(FunctionLBrace) \
+ TYPE(FunctionTypeLParen) \
+ TYPE(ImplicitStringLiteral) \
+ TYPE(InheritanceColon) \
+ TYPE(InheritanceComma) \
+ TYPE(InlineASMBrace) \
+ TYPE(InlineASMColon) \
+ TYPE(JavaAnnotation) \
+ TYPE(JsComputedPropertyName) \
+ TYPE(JsExponentiation) \
+ TYPE(JsExponentiationEqual) \
+ TYPE(JsFatArrow) \
+ TYPE(JsNonNullAssertion) \
+ TYPE(JsTypeColon) \
+ TYPE(JsTypeOperator) \
+ TYPE(JsTypeOptionalQuestion) \
+ TYPE(LambdaArrow) \
+ TYPE(LambdaLSquare) \
+ TYPE(LeadingJavaAnnotation) \
+ TYPE(LineComment) \
+ TYPE(MacroBlockBegin) \
+ TYPE(MacroBlockEnd) \
+ TYPE(ObjCBlockLBrace) \
+ TYPE(ObjCBlockLParen) \
+ TYPE(ObjCDecl) \
+ TYPE(ObjCForIn) \
+ TYPE(ObjCMethodExpr) \
+ TYPE(ObjCMethodSpecifier) \
+ TYPE(ObjCProperty) \
+ TYPE(ObjCStringLiteral) \
+ TYPE(OverloadedOperator) \
+ TYPE(OverloadedOperatorLParen) \
+ TYPE(PointerOrReference) \
+ TYPE(PureVirtualSpecifier) \
+ TYPE(RangeBasedForLoopColon) \
+ TYPE(RegexLiteral) \
+ TYPE(SelectorName) \
+ TYPE(StartOfName) \
+ TYPE(StructuredBindingLSquare) \
+ TYPE(TemplateCloser) \
+ TYPE(TemplateOpener) \
+ TYPE(TemplateString) \
+ TYPE(TrailingAnnotation) \
+ TYPE(TrailingReturnArrow) \
+ TYPE(TrailingUnaryOperator) \
+ TYPE(UnaryOperator) \
TYPE(Unknown)
enum TokenType {
#define TYPE(X) TT_##X,
-LIST_TOKEN_TYPES
+ LIST_TOKEN_TYPES
#undef TYPE
- NUM_TOKEN_TYPES
+ NUM_TOKEN_TYPES
};
/// \brief Determines the name of a token type.
@@ -336,10 +341,11 @@ struct FormatToken {
bool isSimpleTypeSpecifier() const;
bool isObjCAccessSpecifier() const {
- return is(tok::at) && Next && (Next->isObjCAtKeyword(tok::objc_public) ||
- Next->isObjCAtKeyword(tok::objc_protected) ||
- Next->isObjCAtKeyword(tok::objc_package) ||
- Next->isObjCAtKeyword(tok::objc_private));
+ return is(tok::at) && Next &&
+ (Next->isObjCAtKeyword(tok::objc_public) ||
+ Next->isObjCAtKeyword(tok::objc_protected) ||
+ Next->isObjCAtKeyword(tok::objc_package) ||
+ Next->isObjCAtKeyword(tok::objc_private));
}
/// \brief Returns whether \p Tok is ([{ or a template opening <.
@@ -462,7 +468,22 @@ struct FormatToken {
return is(TT_ArrayInitializerLSquare) ||
(is(tok::l_brace) &&
(BlockKind == BK_Block || is(TT_DictLiteral) ||
- (!Style.Cpp11BracedListStyle && NestingLevel == 0)));
+ (!Style.Cpp11BracedListStyle && NestingLevel == 0))) ||
+ (is(tok::less) && (Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto));
+ }
+
+ /// \brief Returns whether the token is the left square bracket of a C++
+ /// structured binding declaration.
+ bool isCppStructuredBinding(const FormatStyle &Style) const {
+ if (!Style.isCpp() || isNot(tok::l_square))
+ return false;
+ const FormatToken *T = this;
+ do {
+ T = T->getPreviousNonComment();
+ } while (T && T->isOneOf(tok::kw_const, tok::kw_volatile, tok::amp,
+ tok::ampamp));
+ return T && T->is(tok::kw_auto);
}
/// \brief Same as opensBlockOrBlockTypeList, but for the closing token.
@@ -472,6 +493,19 @@ struct FormatToken {
return MatchingParen && MatchingParen->opensBlockOrBlockTypeList(Style);
}
+ /// \brief Return the actual namespace token, if this token starts a namespace
+ /// block.
+ const FormatToken *getNamespaceToken() const {
+ const FormatToken *NamespaceTok = this;
+ if (is(tok::comment))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ // Detect "(inline)? namespace" in the beginning of a line.
+ if (NamespaceTok && NamespaceTok->is(tok::kw_inline))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ return NamespaceTok && NamespaceTok->is(tok::kw_namespace) ? NamespaceTok
+ : nullptr;
+ }
+
private:
// Disallow copying.
FormatToken(const FormatToken &) = delete;
@@ -484,15 +518,13 @@ private:
return is(K1) && Next && Next->startsSequenceInternal(Tokens...);
}
- template <typename A>
- bool startsSequenceInternal(A K1) const {
+ template <typename A> bool startsSequenceInternal(A K1) const {
if (is(tok::comment) && Next)
return Next->startsSequenceInternal(K1);
return is(K1);
}
- template <typename A, typename... Ts>
- bool endsSequenceInternal(A K1) const {
+ template <typename A, typename... Ts> bool endsSequenceInternal(A K1) const {
if (is(tok::comment) && Previous)
return Previous->endsSequenceInternal(K1);
return is(K1);
@@ -617,11 +649,15 @@ struct AdditionalKeywords {
kw_finally = &IdentTable.get("finally");
kw_from = &IdentTable.get("from");
kw_function = &IdentTable.get("function");
+ kw_get = &IdentTable.get("get");
kw_import = &IdentTable.get("import");
kw_is = &IdentTable.get("is");
kw_let = &IdentTable.get("let");
kw_module = &IdentTable.get("module");
+ kw_readonly = &IdentTable.get("readonly");
+ kw_set = &IdentTable.get("set");
kw_type = &IdentTable.get("type");
+ kw_typeof = &IdentTable.get("typeof");
kw_var = &IdentTable.get("var");
kw_yield = &IdentTable.get("yield");
@@ -652,6 +688,15 @@ struct AdditionalKeywords {
kw_qsignals = &IdentTable.get("Q_SIGNALS");
kw_slots = &IdentTable.get("slots");
kw_qslots = &IdentTable.get("Q_SLOTS");
+
+ // Keep this at the end of the constructor to make sure everything here is
+ // already initialized.
+ JsExtraKeywords = std::unordered_set<IdentifierInfo *>(
+ {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from,
+ kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly,
+ kw_set, kw_type, kw_typeof, kw_var, kw_yield,
+ // Keywords from the Java section.
+ kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface});
}
// Context sensitive keywords.
@@ -675,11 +720,15 @@ struct AdditionalKeywords {
IdentifierInfo *kw_finally;
IdentifierInfo *kw_from;
IdentifierInfo *kw_function;
+ IdentifierInfo *kw_get;
IdentifierInfo *kw_import;
IdentifierInfo *kw_is;
IdentifierInfo *kw_let;
IdentifierInfo *kw_module;
+ IdentifierInfo *kw_readonly;
+ IdentifierInfo *kw_set;
IdentifierInfo *kw_type;
+ IdentifierInfo *kw_typeof;
IdentifierInfo *kw_var;
IdentifierInfo *kw_yield;
@@ -711,6 +760,18 @@ struct AdditionalKeywords {
IdentifierInfo *kw_qsignals;
IdentifierInfo *kw_slots;
IdentifierInfo *kw_qslots;
+
+ /// \brief Returns \c true if \p Tok is a true JavaScript identifier, returns
+ /// \c false if it is a keyword or a pseudo keyword.
+ bool IsJavaScriptIdentifier(const FormatToken &Tok) const {
+ return Tok.is(tok::identifier) &&
+ JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
+ JsExtraKeywords.end();
+ }
+
+private:
+ /// \brief The JavaScript keywords beyond the C++ keyword set.
+ std::unordered_set<IdentifierInfo *> JsExtraKeywords;
};
} // namespace format
diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp
index 90b80a4544..727437a2a5 100644
--- a/lib/Format/FormatTokenLexer.cpp
+++ b/lib/Format/FormatTokenLexer.cpp
@@ -24,10 +24,10 @@ namespace clang {
namespace format {
FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID,
- const FormatStyle &Style,
+ unsigned Column, const FormatStyle &Style,
encoding::Encoding Encoding)
: FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}),
- Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
+ Column(Column), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
Style(Style), IdentTable(getFormattingLangOpts(Style)),
Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0),
FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin),
@@ -64,6 +64,8 @@ void FormatTokenLexer::tryMergePreviousTokens() {
return;
if (tryMergeLessLess())
return;
+ if (tryMergeNSStringLiteral())
+ return;
if (Style.Language == FormatStyle::LK_JavaScript) {
static const tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
@@ -72,6 +74,10 @@ void FormatTokenLexer::tryMergePreviousTokens() {
static const tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
tok::greaterequal};
static const tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater};
+ static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star};
+ static const tok::TokenKind JSExponentiationEqual[] = {tok::star,
+ tok::starequal};
+
// FIXME: Investigate what token type gives the correct operator priority.
if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
return;
@@ -81,9 +87,38 @@ void FormatTokenLexer::tryMergePreviousTokens() {
return;
if (tryMergeTokens(JSRightArrow, TT_JsFatArrow))
return;
+ if (tryMergeTokens(JSExponentiation, TT_JsExponentiation))
+ return;
+ if (tryMergeTokens(JSExponentiationEqual, TT_JsExponentiationEqual)) {
+ Tokens.back()->Tok.setKind(tok::starequal);
+ return;
+ }
+ }
+
+ if (Style.Language == FormatStyle::LK_Java) {
+ static const tok::TokenKind JavaRightLogicalShiftAssign[] = {
+ tok::greater, tok::greater, tok::greaterequal};
+ if (tryMergeTokens(JavaRightLogicalShiftAssign, TT_BinaryOperator))
+ return;
}
}
+bool FormatTokenLexer::tryMergeNSStringLiteral() {
+ if (Tokens.size() < 2)
+ return false;
+ auto &At = *(Tokens.end() - 2);
+ auto &String = *(Tokens.end() - 1);
+ if (!At->is(tok::at) || !String->is(tok::string_literal))
+ return false;
+ At->Tok.setKind(tok::string_literal);
+ At->TokenText = StringRef(At->TokenText.begin(),
+ String->TokenText.end() - At->TokenText.begin());
+ At->ColumnWidth += String->ColumnWidth;
+ At->Type = TT_ObjCStringLiteral;
+ Tokens.erase(Tokens.end() - 1);
+ return true;
+}
+
bool FormatTokenLexer::tryMergeLessLess() {
// Merge X,less,less,Y into X,lessless,Y unless X or Y is less.
if (Tokens.size() < 3)
@@ -121,9 +156,8 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
return false;
unsigned AddLength = 0;
for (unsigned i = 1; i < Kinds.size(); ++i) {
- if (!First[i]->is(Kinds[i]) ||
- First[i]->WhitespaceRange.getBegin() !=
- First[i]->WhitespaceRange.getEnd())
+ if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() !=
+ First[i]->WhitespaceRange.getEnd())
return false;
AddLength += First[i]->TokenText.size();
}
@@ -436,6 +470,9 @@ FormatToken *FormatTokenLexer::getNextToken() {
if (pos >= 0 && Text[pos] == '\r')
--pos;
// See whether there is an odd number of '\' before this.
+ // FIXME: This is wrong. A '\' followed by a newline is always removed,
+ // regardless of whether there is another '\' before it.
+ // FIXME: Newlines can also be escaped by a '?' '?' '/' trigraph.
unsigned count = 0;
for (; pos >= 0; --pos, ++count)
if (Text[pos] != '\\')
@@ -485,17 +522,53 @@ FormatToken *FormatTokenLexer::getNextToken() {
readRawToken(*FormatTok);
}
+ // JavaScript and Java do not allow to escape the end of the line with a
+ // backslash. Backslashes are syntax errors in plain source, but can occur in
+ // comments. When a single line comment ends with a \, it'll cause the next
+ // line of code to be lexed as a comment, breaking formatting. The code below
+ // finds comments that contain a backslash followed by a line break, truncates
+ // the comment token at the backslash, and resets the lexer to restart behind
+ // the backslash.
+ if ((Style.Language == FormatStyle::LK_JavaScript ||
+ Style.Language == FormatStyle::LK_Java) &&
+ FormatTok->is(tok::comment) && FormatTok->TokenText.startswith("//")) {
+ size_t BackslashPos = FormatTok->TokenText.find('\\');
+ while (BackslashPos != StringRef::npos) {
+ if (BackslashPos + 1 < FormatTok->TokenText.size() &&
+ FormatTok->TokenText[BackslashPos + 1] == '\n') {
+ const char *Offset = Lex->getBufferLocation();
+ Offset -= FormatTok->TokenText.size();
+ Offset += BackslashPos + 1;
+ resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
+ FormatTok->TokenText = FormatTok->TokenText.substr(0, BackslashPos + 1);
+ FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
+ FormatTok->TokenText, FormatTok->OriginalColumn, Style.TabWidth,
+ Encoding);
+ break;
+ }
+ BackslashPos = FormatTok->TokenText.find('\\', BackslashPos + 1);
+ }
+ }
+
// In case the token starts with escaped newlines, we want to
// take them into account as whitespace - this pattern is quite frequent
// in macro definitions.
// FIXME: Add a more explicit test.
- while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' &&
- FormatTok->TokenText[1] == '\n') {
+ while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\') {
+ unsigned SkippedWhitespace = 0;
+ if (FormatTok->TokenText.size() > 2 &&
+ (FormatTok->TokenText[1] == '\r' && FormatTok->TokenText[2] == '\n'))
+ SkippedWhitespace = 3;
+ else if (FormatTok->TokenText[1] == '\n')
+ SkippedWhitespace = 2;
+ else
+ break;
+
++FormatTok->NewlinesBefore;
- WhitespaceLength += 2;
- FormatTok->LastNewlineOffset = 2;
+ WhitespaceLength += SkippedWhitespace;
+ FormatTok->LastNewlineOffset = SkippedWhitespace;
Column = 0;
- FormatTok->TokenText = FormatTok->TokenText.substr(2);
+ FormatTok->TokenText = FormatTok->TokenText.substr(SkippedWhitespace);
}
FormatTok->WhitespaceRange = SourceRange(
@@ -560,7 +633,7 @@ FormatToken *FormatTokenLexer::getNextToken() {
Column = FormatTok->LastLineColumnWidth;
}
- if (Style.IsCpp()) {
+ 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 c47b0e725d..6605a1c35a 100644
--- a/lib/Format/FormatTokenLexer.h
+++ b/lib/Format/FormatTokenLexer.h
@@ -36,7 +36,7 @@ enum LexerState {
class FormatTokenLexer {
public:
- FormatTokenLexer(const SourceManager &SourceMgr, FileID ID,
+ FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, unsigned Column,
const FormatStyle &Style, encoding::Encoding Encoding);
ArrayRef<FormatToken *> lex();
@@ -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
index af751100ec..df99bb2e13 100644
--- a/lib/Format/NamespaceEndCommentsFixer.cpp
+++ b/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -107,33 +107,51 @@ void updateEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
<< llvm::toString(std::move(Err)) << "\n";
}
}
+
+const FormatToken *
+getNamespaceToken(const AnnotatedLine *line,
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+ if (!line->Affected || line->InPPDirective || !line->startsWith(tok::r_brace))
+ return nullptr;
+ size_t StartLineIndex = line->MatchingOpeningBlockLineIndex;
+ if (StartLineIndex == UnwrappedLine::kInvalidIndex)
+ return nullptr;
+ assert(StartLineIndex < AnnotatedLines.size());
+ const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
+ if (NamespaceTok->is(tok::l_brace)) {
+ // "namespace" keyword can be on the line preceding '{', e.g. in styles
+ // where BraceWrapping.AfterNamespace is true.
+ if (StartLineIndex > 0)
+ NamespaceTok = AnnotatedLines[StartLineIndex - 1]->First;
+ }
+ // Detect "(inline)? namespace" in the beginning of a line.
+ if (NamespaceTok->is(tok::kw_inline))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
+ return nullptr;
+ return NamespaceTok;
+}
} // namespace
NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
const FormatStyle &Style)
: TokenAnalyzer(Env, Style) {}
-tooling::Replacements NamespaceEndCommentsFixer::analyze(
+std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze(
TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) {
const SourceManager &SourceMgr = Env.getSourceManager();
AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
AnnotatedLines.end());
tooling::Replacements Fixes;
+ std::string AllNamespaceNames = "";
+ size_t StartLineIndex = SIZE_MAX;
+ unsigned int CompactedNamespacesCount = 0;
for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
- 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->isNot(tok::kw_namespace))
+ const FormatToken *NamespaceTok =
+ getNamespaceToken(EndLine, AnnotatedLines);
+ if (!NamespaceTok)
continue;
FormatToken *RBraceTok = EndLine->First;
if (RBraceTok->Finalized)
@@ -145,6 +163,27 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze(
if (RBraceTok->Next && RBraceTok->Next->is(tok::semi)) {
EndCommentPrevTok = RBraceTok->Next;
}
+ if (StartLineIndex == SIZE_MAX)
+ StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
+ std::string NamespaceName = computeName(NamespaceTok);
+ if (Style.CompactNamespaces) {
+ if ((I + 1 < E) &&
+ getNamespaceToken(AnnotatedLines[I + 1], AnnotatedLines) &&
+ StartLineIndex - CompactedNamespacesCount - 1 ==
+ AnnotatedLines[I + 1]->MatchingOpeningBlockLineIndex &&
+ !AnnotatedLines[I + 1]->First->Finalized) {
+ if (hasEndComment(EndCommentPrevTok)) {
+ // remove end comment, it will be merged in next one
+ updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes);
+ }
+ CompactedNamespacesCount++;
+ AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames;
+ continue;
+ }
+ NamespaceName += AllNamespaceNames;
+ CompactedNamespacesCount = 0;
+ AllNamespaceNames = std::string();
+ }
// The next token in the token stream after the place where the end comment
// token must be. This is either the next token on the current line or the
// first token on the next line.
@@ -156,19 +195,18 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze(
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))
+ } else if (!validEndComment(EndCommentPrevTok, NamespaceName)) {
updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
+ }
+ StartLineIndex = SIZE_MAX;
}
- return Fixes;
+ return {Fixes, 0};
}
} // namespace format
diff --git a/lib/Format/NamespaceEndCommentsFixer.h b/lib/Format/NamespaceEndCommentsFixer.h
index 7790668a2e..4779f0d27c 100644
--- a/lib/Format/NamespaceEndCommentsFixer.h
+++ b/lib/Format/NamespaceEndCommentsFixer.h
@@ -25,7 +25,7 @@ class NamespaceEndCommentsFixer : public TokenAnalyzer {
public:
NamespaceEndCommentsFixer(const Environment &Env, const FormatStyle &Style);
- tooling::Replacements
+ std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) override;
diff --git a/lib/Format/SortJavaScriptImports.cpp b/lib/Format/SortJavaScriptImports.cpp
index e73695ca84..d0b979e100 100644
--- a/lib/Format/SortJavaScriptImports.cpp
+++ b/lib/Format/SortJavaScriptImports.cpp
@@ -123,7 +123,7 @@ public:
: TokenAnalyzer(Env, Style),
FileContents(Env.getSourceManager().getBufferData(Env.getFileID())) {}
- tooling::Replacements
+ std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) override {
@@ -138,7 +138,7 @@ public:
parseModuleReferences(Keywords, AnnotatedLines);
if (References.empty())
- return Result;
+ return {Result, 0};
SmallVector<unsigned, 16> Indices;
for (unsigned i = 0, e = References.size(); i != e; ++i)
@@ -168,7 +168,7 @@ public:
}
if (ReferencesInOrder && SymbolsInOrder)
- return Result;
+ return {Result, 0};
SourceRange InsertionPoint = References[0].Range;
InsertionPoint.setEnd(References[References.size() - 1].Range.getEnd());
@@ -202,7 +202,7 @@ public:
assert(false);
}
- return Result;
+ return {Result, 0};
}
private:
@@ -277,7 +277,7 @@ private:
// Parses module references in the given lines. Returns the module references,
// and a pointer to the first "main code" line if that is adjacent to the
// affected lines of module references, nullptr otherwise.
- std::pair<SmallVector<JsModuleReference, 16>, AnnotatedLine*>
+ std::pair<SmallVector<JsModuleReference, 16>, AnnotatedLine *>
parseModuleReferences(const AdditionalKeywords &Keywords,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
SmallVector<JsModuleReference, 16> References;
@@ -413,7 +413,7 @@ private:
nextToken();
if (Current->is(tok::r_brace))
break;
- if (Current->isNot(tok::identifier))
+ if (!Current->isOneOf(tok::identifier, tok::kw_default))
return false;
JsImportedSymbol Symbol;
@@ -425,7 +425,7 @@ private:
if (Current->is(Keywords.kw_as)) {
nextToken();
- if (Current->isNot(tok::identifier))
+ if (!Current->isOneOf(tok::identifier, tok::kw_default))
return false;
Symbol.Alias = Current->TokenText;
nextToken();
@@ -449,7 +449,7 @@ tooling::Replacements sortJavaScriptImports(const FormatStyle &Style,
std::unique_ptr<Environment> Env =
Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
JavaScriptImportSorter Sorter(*Env, Style);
- return Sorter.process();
+ return Sorter.process().first;
}
} // end namespace format
diff --git a/lib/Format/TokenAnalyzer.cpp b/lib/Format/TokenAnalyzer.cpp
index f2e4e8ef08..d1dfb1fea3 100644
--- a/lib/Format/TokenAnalyzer.cpp
+++ b/lib/Format/TokenAnalyzer.cpp
@@ -38,7 +38,10 @@ namespace format {
// Code.
std::unique_ptr<Environment>
Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName,
- ArrayRef<tooling::Range> Ranges) {
+ ArrayRef<tooling::Range> Ranges,
+ unsigned FirstStartColumn,
+ unsigned NextStartColumn,
+ unsigned LastStartColumn) {
// This is referenced by `FileMgr` and will be released by `FileMgr` when it
// is deleted.
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
@@ -57,8 +60,9 @@ Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName,
std::unique_ptr<SourceManager> VirtualSM(
new SourceManager(*Diagnostics, *FileMgr));
InMemoryFileSystem->addFile(
- FileName, 0, llvm::MemoryBuffer::getMemBuffer(
- Code, FileName, /*RequiresNullTerminator=*/false));
+ FileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(Code, FileName,
+ /*RequiresNullTerminator=*/false));
FileID ID = VirtualSM->createFileID(FileMgr->getFile(FileName),
SourceLocation(), clang::SrcMgr::C_User);
assert(ID.isValid());
@@ -69,9 +73,9 @@ Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName,
SourceLocation End = Start.getLocWithOffset(Range.getLength());
CharRanges.push_back(CharSourceRange::getCharRange(Start, End));
}
- return llvm::make_unique<Environment>(ID, std::move(FileMgr),
- std::move(VirtualSM),
- std::move(Diagnostics), CharRanges);
+ return llvm::make_unique<Environment>(
+ ID, std::move(FileMgr), std::move(VirtualSM), std::move(Diagnostics),
+ CharRanges, FirstStartColumn, NextStartColumn, LastStartColumn);
}
TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style)
@@ -88,14 +92,16 @@ TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style)
<< "\n");
}
-tooling::Replacements TokenAnalyzer::process() {
+std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() {
tooling::Replacements Result;
- FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(), Style,
- Encoding);
+ FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(),
+ Env.getFirstStartColumn(), Style, Encoding);
- UnwrappedLineParser Parser(Style, Tokens.getKeywords(), Tokens.lex(), *this);
+ UnwrappedLineParser Parser(Style, Tokens.getKeywords(),
+ Env.getFirstStartColumn(), Tokens.lex(), *this);
Parser.parse();
assert(UnwrappedLines.rbegin()->empty());
+ unsigned Penalty = 0;
for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE; ++Run) {
DEBUG(llvm::dbgs() << "Run " << Run << "...\n");
SmallVector<AnnotatedLine *, 16> AnnotatedLines;
@@ -106,13 +112,13 @@ tooling::Replacements TokenAnalyzer::process() {
Annotator.annotate(*AnnotatedLines.back());
}
- tooling::Replacements RunResult =
+ std::pair<tooling::Replacements, unsigned> RunResult =
analyze(Annotator, AnnotatedLines, Tokens);
DEBUG({
llvm::dbgs() << "Replacements for run " << Run << ":\n";
- for (tooling::Replacements::const_iterator I = RunResult.begin(),
- E = RunResult.end();
+ for (tooling::Replacements::const_iterator I = RunResult.first.begin(),
+ E = RunResult.first.end();
I != E; ++I) {
llvm::dbgs() << I->toString() << "\n";
}
@@ -120,17 +126,19 @@ tooling::Replacements TokenAnalyzer::process() {
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
delete AnnotatedLines[i];
}
- for (const auto &R : RunResult) {
+
+ Penalty += RunResult.second;
+ for (const auto &R : RunResult.first) {
auto Err = Result.add(R);
// FIXME: better error handling here. For now, simply return an empty
// Replacements to indicate failure.
if (Err) {
llvm::errs() << llvm::toString(std::move(Err)) << "\n";
- return tooling::Replacements();
+ return {tooling::Replacements(), 0};
}
}
}
- return Result;
+ return {Result, Penalty};
}
void TokenAnalyzer::consumeUnwrappedLine(const UnwrappedLine &TheLine) {
diff --git a/lib/Format/TokenAnalyzer.h b/lib/Format/TokenAnalyzer.h
index 78a3d1bc8d..96ea00b25b 100644
--- a/lib/Format/TokenAnalyzer.h
+++ b/lib/Format/TokenAnalyzer.h
@@ -37,21 +37,37 @@ namespace format {
class Environment {
public:
Environment(SourceManager &SM, FileID ID, ArrayRef<CharSourceRange> Ranges)
- : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM) {}
+ : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM),
+ FirstStartColumn(0),
+ NextStartColumn(0),
+ LastStartColumn(0) {}
Environment(FileID ID, std::unique_ptr<FileManager> FileMgr,
std::unique_ptr<SourceManager> VirtualSM,
std::unique_ptr<DiagnosticsEngine> Diagnostics,
- const std::vector<CharSourceRange> &CharRanges)
+ const std::vector<CharSourceRange> &CharRanges,
+ unsigned FirstStartColumn,
+ unsigned NextStartColumn,
+ unsigned LastStartColumn)
: ID(ID), CharRanges(CharRanges.begin(), CharRanges.end()),
- SM(*VirtualSM), FileMgr(std::move(FileMgr)),
+ SM(*VirtualSM),
+ FirstStartColumn(FirstStartColumn),
+ NextStartColumn(NextStartColumn),
+ LastStartColumn(LastStartColumn),
+ FileMgr(std::move(FileMgr)),
VirtualSM(std::move(VirtualSM)), Diagnostics(std::move(Diagnostics)) {}
- // This sets up an virtual file system with file \p FileName containing \p
- // Code.
+ // This sets up an virtual file system with file \p FileName containing the
+ // fragment \p Code. Assumes that \p Code starts at \p FirstStartColumn,
+ // that the next lines of \p Code should start at \p NextStartColumn, and
+ // that \p Code should end at \p LastStartColumn if it ends in newline.
+ // See also the documentation of clang::format::internal::reformat.
static std::unique_ptr<Environment>
CreateVirtualEnvironment(StringRef Code, StringRef FileName,
- ArrayRef<tooling::Range> Ranges);
+ ArrayRef<tooling::Range> Ranges,
+ unsigned FirstStartColumn = 0,
+ unsigned NextStartColumn = 0,
+ unsigned LastStartColumn = 0);
FileID getFileID() const { return ID; }
@@ -59,10 +75,25 @@ public:
const SourceManager &getSourceManager() const { return SM; }
+ // Returns the column at which the fragment of code managed by this
+ // environment starts.
+ unsigned getFirstStartColumn() const { return FirstStartColumn; }
+
+ // Returns the column at which subsequent lines of the fragment of code
+ // managed by this environment should start.
+ unsigned getNextStartColumn() const { return NextStartColumn; }
+
+ // Returns the column at which the fragment of code managed by this
+ // environment should end if it ends in a newline.
+ unsigned getLastStartColumn() const { return LastStartColumn; }
+
private:
FileID ID;
SmallVector<CharSourceRange, 8> CharRanges;
SourceManager &SM;
+ unsigned FirstStartColumn;
+ unsigned NextStartColumn;
+ unsigned LastStartColumn;
// The order of these fields are important - they should be in the same order
// as they are created in `CreateVirtualEnvironment` so that they can be
@@ -76,10 +107,10 @@ class TokenAnalyzer : public UnwrappedLineConsumer {
public:
TokenAnalyzer(const Environment &Env, const FormatStyle &Style);
- tooling::Replacements process();
+ std::pair<tooling::Replacements, unsigned> process();
protected:
- virtual tooling::Replacements
+ virtual std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) = 0;
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 228425bc47..bc8fef8bda 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -47,7 +47,7 @@ private:
if (NonTemplateLess.count(CurrentToken->Previous))
return false;
- const FormatToken& Previous = *CurrentToken->Previous;
+ const FormatToken &Previous = *CurrentToken->Previous; // The '<'.
if (Previous.Previous) {
if (Previous.Previous->Tok.isLiteral())
return false;
@@ -89,7 +89,9 @@ private:
continue;
}
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
- (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext))
+ (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
+ Style.Language != FormatStyle::LK_Proto &&
+ Style.Language != FormatStyle::LK_TextProto))
return false;
// If a && or || is found and interpreted as a binary operator, this set
// of angles is likely part of something like "a < b && c > d". If the
@@ -103,6 +105,14 @@ private:
!Line.startsWith(tok::kw_template))
return false;
updateParameterCount(Left, CurrentToken);
+ if (Style.Language == FormatStyle::LK_Proto) {
+ if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) {
+ if (CurrentToken->is(tok::colon) ||
+ (CurrentToken->isOneOf(tok::l_brace, tok::less) &&
+ Previous->isNot(tok::colon)))
+ Previous->Type = TT_SelectorName;
+ }
+ }
if (!consumeToken())
return false;
}
@@ -135,14 +145,18 @@ private:
if (Left->is(TT_OverloadedOperatorLParen)) {
Contexts.back().IsExpression = false;
} else if (Style.Language == FormatStyle::LK_JavaScript &&
- Line.startsWith(Keywords.kw_type, tok::identifier)) {
+ (Line.startsWith(Keywords.kw_type, tok::identifier) ||
+ Line.startsWith(tok::kw_export, Keywords.kw_type,
+ tok::identifier))) {
// type X = (...);
+ // export type X = (...);
Contexts.back().IsExpression = false;
} else if (Left->Previous &&
- (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
- tok::kw_if, tok::kw_while, tok::l_paren,
- tok::comma) ||
- Left->Previous->is(TT_BinaryOperator))) {
+ (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
+ tok::kw_if, tok::kw_while, tok::l_paren,
+ tok::comma) ||
+ Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) ||
+ Left->Previous->is(TT_BinaryOperator))) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
} else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous &&
@@ -311,13 +325,12 @@ 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.IsCpp() && Parent &&
- Parent->is(TT_TemplateCloser) &&
+ Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) &&
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
Contexts.back().InTemplateArgument);
bool StartsObjCMethodExpr =
- !CppArrayTemplates && Style.IsCpp() &&
+ !CppArrayTemplates && Style.isCpp() &&
Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
CurrentToken->isNot(tok::l_brace) &&
(!Parent ||
@@ -329,13 +342,18 @@ private:
bool ColonFound = false;
unsigned BindingIncrease = 1;
- if (Left->is(TT_Unknown)) {
+ if (Left->isCppStructuredBinding(Style)) {
+ Left->Type = TT_StructuredBindingLSquare;
+ } else if (Left->is(TT_Unknown)) {
if (StartsObjCMethodExpr) {
Left->Type = TT_ObjCMethodExpr;
} else if (Style.Language == FormatStyle::LK_JavaScript && Parent &&
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->Type = TT_JsComputedPropertyName;
+ } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
+ Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
+ Left->Type = TT_DesignatedInitializerLSquare;
} else if (CurrentToken->is(tok::r_square) && Parent &&
Parent->is(TT_TemplateCloser)) {
Left->Type = TT_ArraySubscriptLSquare;
@@ -355,6 +373,10 @@ private:
ScopedContextCreator ContextCreator(*this, tok::l_square, BindingIncrease);
Contexts.back().IsExpression = true;
+ if (Style.Language == FormatStyle::LK_JavaScript && Parent &&
+ Parent->is(TT_JsTypeColon))
+ Contexts.back().IsExpression = false;
+
Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr;
while (CurrentToken) {
@@ -388,7 +410,8 @@ private:
if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
return false;
if (CurrentToken->is(tok::colon)) {
- if (Left->is(TT_ArraySubscriptLSquare)) {
+ if (Left->isOneOf(TT_ArraySubscriptLSquare,
+ TT_DesignatedInitializerLSquare)) {
Left->Type = TT_ObjCMethodExpr;
StartsObjCMethodExpr = true;
Contexts.back().ColonIsObjCMethodExpr = true;
@@ -421,6 +444,9 @@ private:
Contexts.back().ColonIsDictLiteral = true;
if (Left->BlockKind == BK_BracedInit)
Contexts.back().IsExpression = true;
+ if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous &&
+ Left->Previous->is(TT_JsTypeColon))
+ Contexts.back().IsExpression = false;
while (CurrentToken) {
if (CurrentToken->is(tok::r_brace)) {
@@ -432,11 +458,14 @@ private:
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
return false;
updateParameterCount(Left, CurrentToken);
- if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) {
+ if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
FormatToken *Previous = CurrentToken->getPreviousNonComment();
+ if (Previous->is(TT_JsTypeOptionalQuestion))
+ Previous = Previous->getPreviousNonComment();
if (((CurrentToken->is(tok::colon) &&
- (!Contexts.back().ColonIsDictLiteral || !Style.IsCpp())) ||
- Style.Language == FormatStyle::LK_Proto) &&
+ (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
+ Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) &&
(Previous->Tok.getIdentifierInfo() ||
Previous->is(tok::string_literal)))
Previous->Type = TT_SelectorName;
@@ -512,15 +541,23 @@ private:
!Line.First->isOneOf(tok::kw_enum, tok::kw_case)) ||
Contexts.back().ContextKind == tok::l_paren || // function params
Contexts.back().ContextKind == tok::l_square || // array type
+ (!Contexts.back().IsExpression &&
+ Contexts.back().ContextKind == tok::l_brace) || // object type
(Contexts.size() == 1 &&
Line.MustBeDeclaration)) { // method/property declaration
+ Contexts.back().IsExpression = false;
Tok->Type = TT_JsTypeColon;
break;
}
}
if (Contexts.back().ColonIsDictLiteral ||
- Style.Language == FormatStyle::LK_Proto) {
+ Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) {
Tok->Type = TT_DictLiteral;
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ if (FormatToken *Previous = Tok->getPreviousNonComment())
+ Previous->Type = TT_SelectorName;
+ }
} else if (Contexts.back().ColonIsObjCMethodExpr ||
Line.startsWith(TT_ObjCMethodSpecifier)) {
Tok->Type = TT_ObjCMethodExpr;
@@ -569,6 +606,9 @@ private:
break;
case tok::kw_if:
case tok::kw_while:
+ if (Tok->is(tok::kw_if) && CurrentToken &&
+ CurrentToken->is(tok::kw_constexpr))
+ next();
if (CurrentToken && CurrentToken->is(tok::l_paren)) {
next();
if (!parseParens(/*LookForDecls=*/true))
@@ -576,9 +616,13 @@ private:
}
break;
case tok::kw_for:
- if (Style.Language == FormatStyle::LK_JavaScript && Tok->Previous &&
- Tok->Previous->is(tok::period))
- break;
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Tok->Previous && Tok->Previous->is(tok::period))
+ break;
+ // JS' for await ( ...
+ if (CurrentToken && CurrentToken->is(Keywords.kw_await))
+ next();
+ }
Contexts.back().ColonIsForRangeExpr = true;
next();
if (!parseParens())
@@ -589,8 +633,7 @@ private:
// marks the first l_paren as a OverloadedOperatorLParen. Here, we make
// the first two parens OverloadedOperators and the second l_paren an
// OverloadedOperatorLParen.
- if (Tok->Previous &&
- Tok->Previous->is(tok::r_paren) &&
+ if (Tok->Previous && Tok->Previous->is(tok::r_paren) &&
Tok->Previous->MatchingParen &&
Tok->Previous->MatchingParen->is(TT_OverloadedOperatorLParen)) {
Tok->Previous->Type = TT_OverloadedOperator;
@@ -612,12 +655,22 @@ private:
return false;
break;
case tok::l_brace:
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ FormatToken *Previous = Tok->getPreviousNonComment();
+ if (Previous && Previous->Type != TT_DictLiteral)
+ Previous->Type = TT_SelectorName;
+ }
if (!parseBrace())
return false;
break;
case tok::less:
if (parseAngle()) {
Tok->Type = TT_TemplateOpener;
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ FormatToken *Previous = Tok->getPreviousNonComment();
+ if (Previous && Previous->Type != TT_DictLiteral)
+ Previous->Type = TT_SelectorName;
+ }
} else {
Tok->Type = TT_BinaryOperator;
NonTemplateLess.insert(Tok);
@@ -702,7 +755,10 @@ private:
if (CurrentToken && CurrentToken->is(tok::less)) {
next();
while (CurrentToken) {
- if (CurrentToken->isNot(tok::comment) || CurrentToken->Next)
+ // Mark tokens up to the trailing line comments as implicit string
+ // literals.
+ if (CurrentToken->isNot(tok::comment) &&
+ !CurrentToken->TokenText.startswith("//"))
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
@@ -738,9 +794,9 @@ private:
void parseHasInclude() {
if (!CurrentToken || !CurrentToken->is(tok::l_paren))
return;
- next(); // '('
+ next(); // '('
parseIncludeDirective();
- next(); // ')'
+ next(); // ')'
}
LineType parsePreprocessorDirective() {
@@ -796,10 +852,11 @@ private:
while (CurrentToken) {
FormatToken *Tok = CurrentToken;
next();
- if (Tok->isOneOf(Keywords.kw___has_include,
- Keywords.kw___has_include_next)) {
+ if (Tok->is(tok::l_paren))
+ parseParens();
+ else if (Tok->isOneOf(Keywords.kw___has_include,
+ Keywords.kw___has_include_next))
parseHasInclude();
- }
}
return Type;
}
@@ -889,11 +946,11 @@ private:
// FIXME: Closure-library specific stuff should not be hard-coded but be
// configurable.
return Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) &&
- Tok.Next->Next && (Tok.Next->Next->TokenText == "module" ||
- Tok.Next->Next->TokenText == "provide" ||
- Tok.Next->Next->TokenText == "require" ||
- Tok.Next->Next->TokenText == "setTestOnly" ||
- Tok.Next->Next->TokenText == "forwardDeclare") &&
+ Tok.Next->Next &&
+ (Tok.Next->Next->TokenText == "module" ||
+ Tok.Next->Next->TokenText == "provide" ||
+ Tok.Next->Next->TokenText == "require" ||
+ Tok.Next->Next->TokenText == "forwardDeclare") &&
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
}
@@ -907,7 +964,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;
@@ -971,9 +1028,12 @@ private:
void modifyContext(const FormatToken &Current) {
if (Current.getPrecedence() == prec::Assignment &&
!Line.First->isOneOf(tok::kw_template, tok::kw_using, tok::kw_return) &&
- // Type aliases use `type X = ...;` in TypeScript.
+ // Type aliases use `type X = ...;` in TypeScript and can be exported
+ // using `export type ...`.
!(Style.Language == FormatStyle::LK_JavaScript &&
- Line.startsWith(Keywords.kw_type, tok::identifier)) &&
+ (Line.startsWith(Keywords.kw_type, tok::identifier) ||
+ Line.startsWith(tok::kw_export, Keywords.kw_type,
+ tok::identifier))) &&
(!Current.Previous || Current.Previous->isNot(tok::kw_operator))) {
Contexts.back().IsExpression = true;
if (!Line.startsWith(TT_UnaryOperator)) {
@@ -1007,8 +1067,7 @@ private:
Current.Previous->is(TT_CtorInitializerColon)) {
Contexts.back().IsExpression = true;
Contexts.back().InCtorInitializer = true;
- } else if (Current.Previous &&
- Current.Previous->is(TT_InheritanceColon)) {
+ } 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;
@@ -1033,8 +1092,9 @@ private:
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->isOneOf(tok::identifier, tok::kw_namespace,
+ tok::r_paren, tok::r_square,
+ tok::r_brace) ||
Current.Previous->Tok.isLiteral())) {
Current.Type = TT_JsNonNullAssertion;
return;
@@ -1056,6 +1116,11 @@ private:
(!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
Contexts.back().FirstStartOfName = &Current;
Current.Type = TT_StartOfName;
+ } else if (Current.is(tok::semi)) {
+ // Reset FirstStartOfName after finding a semicolon so that a for loop
+ // with multiple increment statements is not confused with a for loop
+ // having multiple variable declarations.
+ Contexts.back().FirstStartOfName = nullptr;
} else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) {
AutoFound = true;
} else if (Current.is(tok::arrow) &&
@@ -1065,10 +1130,10 @@ private:
Current.NestingLevel == 0) {
Current.Type = TT_TrailingReturnArrow;
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
- Current.Type =
- determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
- Contexts.back().IsExpression,
- Contexts.back().InTemplateArgument);
+ Current.Type = determineStarAmpUsage(Current,
+ Contexts.back().CanBeExpression &&
+ Contexts.back().IsExpression,
+ Contexts.back().InTemplateArgument);
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
Current.Type = determinePlusMinusCaretUsage(Current);
if (Current.is(TT_UnaryOperator) && Current.is(tok::caret))
@@ -1119,22 +1184,22 @@ private:
Current.Type = TT_FunctionAnnotationRParen;
}
}
- } else if (Current.is(tok::at) && Current.Next) {
- if (Current.Next->isStringLiteral()) {
- Current.Type = TT_ObjCStringLiteral;
- } else {
- switch (Current.Next->Tok.getObjCKeywordID()) {
- case tok::objc_interface:
- case tok::objc_implementation:
- case tok::objc_protocol:
- Current.Type = TT_ObjCDecl;
- break;
- case tok::objc_property:
- Current.Type = TT_ObjCProperty;
- break;
- default:
- break;
- }
+ } else if (Current.is(tok::at) && Current.Next &&
+ Style.Language != FormatStyle::LK_JavaScript &&
+ Style.Language != FormatStyle::LK_Java) {
+ // In Java & JavaScript, "@..." is a decorator or annotation. In ObjC, it
+ // marks declarations and properties that need special formatting.
+ switch (Current.Next->Tok.getObjCKeywordID()) {
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ case tok::objc_protocol:
+ Current.Type = TT_ObjCDecl;
+ break;
+ case tok::objc_property:
+ Current.Type = TT_ObjCProperty;
+ break;
+ default:
+ break;
}
} else if (Current.is(tok::period)) {
FormatToken *PreviousNoComment = Current.getPreviousNonComment();
@@ -1220,7 +1285,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.IsCpp() && 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.
@@ -1335,7 +1400,8 @@ private:
if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
tok::comma, tok::semi, tok::kw_return, tok::colon,
- tok::equal, tok::kw_delete, tok::kw_sizeof) ||
+ tok::equal, tok::kw_delete, tok::kw_sizeof,
+ tok::kw_throw) ||
PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
TT_UnaryOperator, TT_CastRParen))
return TT_UnaryOperator;
@@ -1347,11 +1413,13 @@ private:
if (NextToken->isOneOf(tok::comma, tok::semi))
return TT_PointerOrReference;
- if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen &&
- PrevToken->MatchingParen->Previous &&
- PrevToken->MatchingParen->Previous->isOneOf(tok::kw_typeof,
- tok::kw_decltype))
- return TT_PointerOrReference;
+ if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen) {
+ FormatToken *TokenBeforeMatchingParen =
+ PrevToken->MatchingParen->getPreviousNonComment();
+ if (TokenBeforeMatchingParen &&
+ TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype))
+ return TT_PointerOrReference;
+ }
if (PrevToken->Tok.isLiteral() ||
PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
@@ -1539,8 +1607,11 @@ private:
const FormatToken *NextNonComment = Current->getNextNonComment();
if (Current->is(TT_ConditionalExpr))
return prec::Conditional;
- if (NextNonComment && NextNonComment->is(tok::colon) &&
- NextNonComment->is(TT_DictLiteral))
+ if (NextNonComment && Current->is(TT_SelectorName) &&
+ (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) ||
+ ((Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) &&
+ NextNonComment->is(tok::less))))
return prec::Assignment;
if (Current->is(TT_JsComputedPropertyName))
return prec::Assignment;
@@ -1591,17 +1662,15 @@ private:
/// \brief Parse unary operator expressions and surround them with fake
/// parentheses if appropriate.
void parseUnaryOperator() {
- if (!Current || Current->isNot(TT_UnaryOperator)) {
- parse(PrecedenceArrowAndPeriod);
- return;
+ llvm::SmallVector<FormatToken *, 2> Tokens;
+ while (Current && Current->is(TT_UnaryOperator)) {
+ Tokens.push_back(Current);
+ next();
}
-
- FormatToken *Start = Current;
- next();
- parseUnaryOperator();
-
- // The actual precedence doesn't matter.
- addFakeParenthesis(Start, prec::Unknown);
+ parse(PrecedenceArrowAndPeriod);
+ for (FormatToken *Token : llvm::reverse(Tokens))
+ // The actual precedence doesn't matter.
+ addFakeParenthesis(Token, prec::Unknown);
}
void parseConditionalExpr() {
@@ -1643,17 +1712,26 @@ void TokenAnnotator::setCommentLineLevels(
for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
E = Lines.rend();
I != E; ++I) {
- bool CommentLine = (*I)->First;
+ bool CommentLine = true;
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
+
+ if (NextNonCommentLine && CommentLine) {
+ // If the comment is currently aligned with the line immediately following
+ // it, that's probably intentional and we should keep it.
+ bool AlignedWithNextLine =
+ NextNonCommentLine->First->NewlinesBefore <= 1 &&
+ NextNonCommentLine->First->OriginalColumn ==
+ (*I)->First->OriginalColumn;
+ if (AlignedWithNextLine)
+ (*I)->Level = NextNonCommentLine->Level;
+ } else {
NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr;
+ }
setCommentLineLevels((*I)->Children);
}
@@ -1661,7 +1739,7 @@ void TokenAnnotator::setCommentLineLevels(
static unsigned maxNestingDepth(const AnnotatedLine &Line) {
unsigned Result = 0;
- for (const auto* Tok = Line.First; Tok != nullptr; Tok = Tok->Next)
+ for (const auto *Tok = Line.First; Tok != nullptr; Tok = Tok->Next)
Result = std::max(Result, Tok->NestingLevel);
return Result;
}
@@ -1703,7 +1781,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
// function declaration.
static bool isFunctionDeclarationName(const FormatToken &Current,
const AnnotatedLine &Line) {
- auto skipOperatorName = [](const FormatToken* Next) -> const FormatToken* {
+ auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
for (; Next; Next = Next->Next) {
if (Next->is(TT_OverloadedOperatorLParen))
return Next;
@@ -1711,8 +1789,8 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
continue;
if (Next->isOneOf(tok::kw_new, tok::kw_delete)) {
// For 'new[]' and 'delete[]'.
- if (Next->Next && Next->Next->is(tok::l_square) &&
- Next->Next->Next && Next->Next->Next->is(tok::r_square))
+ if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next &&
+ Next->Next->Next->is(tok::r_square))
Next = Next->Next->Next;
continue;
}
@@ -1811,7 +1889,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
}
Line.First->TotalLength =
- Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth;
+ Line.First->IsMultiline ? Style.ColumnLimit
+ : Line.FirstStartColumn + Line.First->ColumnWidth;
FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl;
while (Current) {
@@ -1944,6 +2023,9 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
(Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
return 100;
+ // Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
+ if (Left.opensScope() && Right.closesScope())
+ return 200;
}
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
@@ -1957,7 +2039,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Right.is(TT_LambdaLSquare) && Left.is(tok::equal))
return 35;
if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
- TT_ArrayInitializerLSquare))
+ TT_ArrayInitializerLSquare,
+ TT_DesignatedInitializerLSquare))
return 500;
}
@@ -1987,7 +2070,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(tok::comment))
return 1000;
- if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon))
+ if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon,
+ TT_CtorInitializerColon))
return 2;
if (Right.isMemberAccess()) {
@@ -2045,7 +2129,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign)
return 100;
if (Left.is(tok::l_paren) && Left.Previous &&
- Left.Previous->isOneOf(tok::kw_if, tok::kw_for))
+ (Left.Previous->isOneOf(tok::kw_if, tok::kw_for) ||
+ Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if)))
return 1000;
if (Left.is(tok::equal) && InFunctionDecl)
return 110;
@@ -2084,9 +2169,10 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(TT_ConditionalExpr))
return prec::Conditional;
prec::Level Level = Left.getPrecedence();
- if (Level != prec::Unknown)
- return Level;
- Level = Right.getPrecedence();
+ if (Level == prec::Unknown)
+ Level = Right.getPrecedence();
+ if (Level == prec::Assignment)
+ return Style.PenaltyBreakAssignment;
if (Level != prec::Unknown)
return Level;
@@ -2098,6 +2184,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
const FormatToken &Right) {
if (Left.is(tok::kw_return) && Right.isNot(tok::semi))
return true;
+ if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java)
+ return true;
if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty &&
Left.Tok.getObjCKeywordID() == tok::objc_property)
return true;
@@ -2114,8 +2202,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
: Style.SpacesInParentheses;
if (Right.isOneOf(tok::semi, tok::comma))
return false;
- if (Right.is(tok::less) &&
- Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)
+ if (Right.is(tok::less) && Line.Type == LT_ObjCDecl &&
+ Style.ObjCSpaceBeforeProtocolList)
return true;
if (Right.is(tok::less) && Left.is(tok::kw_template))
return Style.SpaceAfterTemplateKeyword;
@@ -2137,15 +2225,23 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Left.Previous->is(tok::kw_case));
if (Left.is(tok::l_square) && Right.is(tok::amp))
return false;
- if (Right.is(TT_PointerOrReference))
- return (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) ||
- (Left.Tok.isLiteral() || (Left.is(tok::kw_const) && Left.Previous &&
- Left.Previous->is(tok::r_paren)) ||
+ if (Right.is(TT_PointerOrReference)) {
+ if (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) {
+ if (!Left.MatchingParen)
+ return true;
+ FormatToken *TokenBeforeMatchingParen =
+ Left.MatchingParen->getPreviousNonComment();
+ if (!TokenBeforeMatchingParen ||
+ !TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype))
+ return true;
+ }
+ return (Left.Tok.isLiteral() ||
(!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
(Style.PointerAlignment != FormatStyle::PAS_Left ||
(Line.IsMultiVariableDeclStmt &&
(Left.NestingLevel == 0 ||
(Left.NestingLevel == 1 && Line.First->is(tok::kw_for)))))));
+ }
if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) &&
(!Left.is(TT_PointerOrReference) ||
(Style.PointerAlignment != FormatStyle::PAS_Right &&
@@ -2167,16 +2263,20 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.is(tok::l_square))
return (Left.is(TT_ArrayInitializerLSquare) &&
Style.SpacesInContainerLiterals && Right.isNot(tok::r_square)) ||
- (Left.is(TT_ArraySubscriptLSquare) && Style.SpacesInSquareBrackets &&
- Right.isNot(tok::r_square));
+ (Left.isOneOf(TT_ArraySubscriptLSquare,
+ TT_StructuredBindingLSquare) &&
+ Style.SpacesInSquareBrackets && Right.isNot(tok::r_square));
if (Right.is(tok::r_square))
return Right.MatchingParen &&
((Style.SpacesInContainerLiterals &&
Right.MatchingParen->is(TT_ArrayInitializerLSquare)) ||
(Style.SpacesInSquareBrackets &&
- Right.MatchingParen->is(TT_ArraySubscriptLSquare)));
+ Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare,
+ TT_StructuredBindingLSquare)));
if (Right.is(tok::l_square) &&
- !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) &&
+ !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
+ TT_DesignatedInitializerLSquare,
+ TT_StructuredBindingLSquare) &&
!Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
@@ -2195,6 +2295,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while,
tok::kw_switch, tok::kw_case, TT_ForEachMacro,
TT_ObjCForIn) ||
+ Left.endsSequence(tok::kw_constexpr, tok::kw_if) ||
(Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
tok::kw_new, tok::kw_delete) &&
(!Left.Previous || Left.Previous->isNot(tok::period))))) ||
@@ -2221,7 +2322,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.is(TT_TemplateCloser) && Left.MatchingParen &&
Left.MatchingParen->Previous &&
Left.MatchingParen->Previous->is(tok::period))
- // A.<B>DoSomething();
+ // A.<B<C<...>>>DoSomething();
return false;
if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square))
return false;
@@ -2233,10 +2334,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
const FormatToken &Left = *Right.Previous;
if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
return true; // Never ever merge two identifiers.
- if (Style.IsCpp()) {
+ if (Style.isCpp()) {
if (Left.is(tok::kw_operator))
return Right.is(tok::coloncolon);
- } else if (Style.Language == FormatStyle::LK_Proto) {
+ } else if (Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) {
if (Right.is(tok::period) &&
Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
Keywords.kw_repeated, Keywords.kw_extend))
@@ -2244,9 +2346,15 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Right.is(tok::l_paren) &&
Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
return true;
+ if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName))
+ return true;
} else if (Style.Language == FormatStyle::LK_JavaScript) {
if (Left.is(TT_JsFatArrow))
return true;
+ // for await ( ...
+ if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && Left.Previous &&
+ Left.Previous->is(tok::kw_for))
+ return true;
if (Left.is(Keywords.kw_async) && Right.is(tok::l_paren) &&
Right.MatchingParen) {
const FormatToken *Next = Right.MatchingParen->getNextNonComment();
@@ -2258,20 +2366,39 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
(Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
return false;
- if (Left.is(tok::identifier) && Right.is(TT_TemplateString))
+ // In tagged template literals ("html`bar baz`"), there is no space between
+ // the tag identifier and the template string. getIdentifierInfo makes sure
+ // that the identifier is not a pseudo keyword like `yield`, either.
+ if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
+ Right.is(TT_TemplateString))
return false;
if (Right.is(tok::star) &&
Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
return false;
if (Right.isOneOf(tok::l_brace, tok::l_square) &&
- Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
+ Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
+ Keywords.kw_extends, Keywords.kw_implements))
return true;
- // JS methods can use some keywords as names (e.g. `delete()`).
- 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 (Right.is(tok::l_paren)) {
+ // JS methods can use some keywords as names (e.g. `delete()`).
+ if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo())
+ return false;
+ // Valid JS method names can include keywords, e.g. `foo.delete()` or
+ // `bar.instanceof()`. Recognize call positions by preceding period.
+ if (Left.Previous && Left.Previous->is(tok::period) &&
+ Left.Tok.getIdentifierInfo())
+ return false;
+ // Additional unary JavaScript operators that need a space after.
+ if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof,
+ tok::kw_void))
+ return true;
+ }
+ 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 &&
@@ -2367,8 +2494,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::greater) && Right.is(tok::greater))
return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
(Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
- if (Right.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
- Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar))
+ if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) ||
+ Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
+ (Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod)))
return false;
if (!Style.SpaceBeforeAssignmentOperators &&
Right.getPrecedence() == prec::Assignment)
@@ -2382,9 +2510,18 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return (Left.is(TT_TemplateOpener) &&
Style.Standard == FormatStyle::LS_Cpp03) ||
!(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
- TT_TemplateCloser, TT_TemplateOpener));
+ tok::kw___super, TT_TemplateCloser,
+ TT_TemplateOpener));
if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
return Style.SpacesInAngles;
+ // Space before TT_StructuredBindingLSquare.
+ if (Right.is(TT_StructuredBindingLSquare))
+ return !Left.isOneOf(tok::amp, tok::ampamp) ||
+ Style.PointerAlignment != FormatStyle::PAS_Right;
+ // Space before & or && following a TT_StructuredBindingLSquare.
+ if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) &&
+ Right.isOneOf(tok::amp, tok::ampamp))
+ return Style.PointerAlignment != FormatStyle::PAS_Left;
if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
(Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
!Right.is(tok::r_paren)))
@@ -2434,7 +2571,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
if (Left.is(tok::l_brace) && Line.Level == 0 &&
(Line.startsWith(tok::kw_enum) ||
- Line.startsWith(tok::kw_export, tok::kw_enum)))
+ Line.startsWith(tok::kw_const, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum)))
// JavaScript top-level enum key/value pairs are put on separate lines
// instead of bin-packing.
return true;
@@ -2444,8 +2583,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty ||
(Left.NestingLevel == 0 && Line.Level == 0 &&
- Style.AllowShortFunctionsOnASingleLine ==
- FormatStyle::SFS_Inline);
+ Style.AllowShortFunctionsOnASingleLine &
+ FormatStyle::SFS_InlineOnly);
} else if (Style.Language == FormatStyle::LK_Java) {
if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next &&
Right.Next->is(tok::string_literal))
@@ -2453,25 +2592,31 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
} else if (Style.Language == FormatStyle::LK_Cpp ||
Style.Language == FormatStyle::LK_ObjC ||
Style.Language == FormatStyle::LK_Proto) {
- if (Left.isStringLiteral() &&
- (Right.isStringLiteral() || Right.is(TT_ObjCStringLiteral)))
+ if (Left.isStringLiteral() && Right.isStringLiteral())
return true;
}
- // If the last token before a '}' is a comma or a trailing comment, the
- // intention is to insert a line break after it in order to make shuffling
- // around entries easier.
- const FormatToken *BeforeClosingBrace = nullptr;
- if (Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) &&
- Left.BlockKind != BK_Block && Left.MatchingParen)
- BeforeClosingBrace = Left.MatchingParen->Previous;
- else if (Right.MatchingParen &&
- Right.MatchingParen->isOneOf(tok::l_brace,
- TT_ArrayInitializerLSquare))
- BeforeClosingBrace = &Left;
- if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) ||
- BeforeClosingBrace->isTrailingComment()))
- return true;
+ // If the last token before a '}', ']', or ')' is a comma or a trailing
+ // comment, the intention is to insert a line break after it in order to make
+ // shuffling around entries easier. Import statements, especially in
+ // JavaScript, can be an exception to this rule.
+ if (Style.JavaScriptWrapImports || Line.Type != LT_ImportStatement) {
+ const FormatToken *BeforeClosingBrace = nullptr;
+ if ((Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ Left.is(tok::l_paren))) &&
+ Left.BlockKind != BK_Block && Left.MatchingParen)
+ BeforeClosingBrace = Left.MatchingParen->Previous;
+ else if (Right.MatchingParen &&
+ (Right.MatchingParen->isOneOf(tok::l_brace,
+ TT_ArrayInitializerLSquare) ||
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ Right.MatchingParen->is(tok::l_paren))))
+ BeforeClosingBrace = &Left;
+ if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) ||
+ BeforeClosingBrace->isTrailingComment()))
+ return true;
+ }
if (Right.is(tok::comment))
return Left.BlockKind != BK_BracedInit &&
@@ -2490,27 +2635,36 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Right.Previous->MatchingParen->NestingLevel == 0 &&
Style.AlwaysBreakTemplateDeclarations)
return true;
- if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) &&
- Style.BreakConstructorInitializersBeforeComma &&
+ if (Right.is(TT_CtorInitializerComma) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
+ !Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ return true;
+ if (Right.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
return true;
// Break only if we have multiple inheritance.
- if (Style.BreakBeforeInheritanceComma &&
- Right.is(TT_InheritanceComma))
- return true;
+ if (Style.BreakBeforeInheritanceComma && Right.is(TT_InheritanceComma))
+ return true;
if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\""))
// Raw string literals are special wrt. line breaks. The author has made a
// deliberate choice and might have aligned the contents of the string
// literal accordingly. Thus, we try keep existing line breaks.
return Right.NewlinesBefore > 0;
- if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
- Style.Language == FormatStyle::LK_Proto)
- // Don't put enums onto single lines in protocol buffers.
+ if ((Right.Previous->is(tok::l_brace) ||
+ (Right.Previous->is(tok::less) && Right.Previous->Previous &&
+ Right.Previous->Previous->is(tok::equal))) &&
+ Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) {
+ // Don't put enums or option definitions onto single lines in protocol
+ // buffers.
return true;
+ }
if (Right.is(TT_InlineASMBrace))
return Right.HasUnescapedNewline;
if (isAllmanBrace(Left) || isAllmanBrace(Right))
return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) ||
+ (Line.startsWith(tok::kw_typedef, tok::kw_enum) &&
+ Style.BraceWrapping.AfterEnum) ||
(Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) ||
(Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct);
if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine)
@@ -2543,8 +2697,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
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.
+ Keywords.kw_type, tok::kw_static, tok::kw_public,
+ tok::kw_private, tok::kw_protected,
+ Keywords.kw_readonly, Keywords.kw_abstract,
+ Keywords.kw_get, Keywords.kw_set))
+ return false; // Otherwise automatic semicolon insertion would trigger.
if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace))
return false;
if (Left.is(TT_JsTypeColon))
@@ -2599,7 +2756,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// The first comment in a braced lists is always interpreted as belonging to
// the first list element. Otherwise, it should be placed outside of the
// list.
- return Left.BlockKind == BK_BracedInit;
+ return Left.BlockKind == BK_BracedInit ||
+ (Left.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon);
if (Left.is(tok::question) && Right.is(tok::colon))
return false;
if (Right.is(TT_ConditionalExpr) || Right.is(tok::question))
@@ -2672,11 +2831,15 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
return true;
+ if (Left.is(TT_CtorInitializerColon))
+ return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon;
+ if (Right.is(TT_CtorInitializerColon))
+ return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon;
if (Left.is(TT_CtorInitializerComma) &&
- Style.BreakConstructorInitializersBeforeComma)
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
return false;
if (Right.is(TT_CtorInitializerComma) &&
- Style.BreakConstructorInitializersBeforeComma)
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
return true;
if (Left.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma)
return false;
@@ -2712,7 +2875,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
}
void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
- llvm::errs() << "AnnotatedTokens:\n";
+ llvm::errs() << "AnnotatedTokens(L=" << Line.Level << "):\n";
const FormatToken *Tok = Line.First;
while (Tok) {
llvm::errs() << " M=" << Tok->MustBreakBefore
@@ -2720,10 +2883,9 @@ 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=";
+ << " BK=" << Tok->BlockKind << " P=" << Tok->SplitPenalty
+ << " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength
+ << " PPK=" << Tok->PackingKind << " FakeLParens=";
for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i)
llvm::errs() << Tok->FakeLParens[i] << "/";
llvm::errs() << " FakeRParens=" << Tok->FakeRParens;
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 805509533b..04a18d45b8 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -43,7 +43,8 @@ public:
InPPDirective(Line.InPPDirective),
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
IsMultiVariableDeclStmt(false), Affected(false),
- LeadingEmptyLinesAffected(false), ChildrenAffected(false) {
+ LeadingEmptyLinesAffected(false), ChildrenAffected(false),
+ FirstStartColumn(Line.FirstStartColumn) {
assert(!Line.Tokens.empty());
// Calculate Next and Previous for all tokens. Note that we must overwrite
@@ -127,6 +128,8 @@ public:
/// \c True if one of this line's children intersects with an input range.
bool ChildrenAffected;
+ unsigned FirstStartColumn;
+
private:
// Disallow copying.
AnnotatedLine(const AnnotatedLine &) = delete;
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index c3c154afeb..a82cd5abe2 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -66,6 +66,13 @@ public:
Indent += Offset;
}
+ /// \brief Update the indent state given that \p Line indent should be
+ /// skipped.
+ void skipLine(const AnnotatedLine &Line) {
+ while (IndentForLevel.size() <= Line.Level)
+ IndentForLevel.push_back(Indent);
+ }
+
/// \brief Update the level indent to adapt to the given \p Line.
///
/// When a line is not formatted, we move the subsequent lines on the same
@@ -127,12 +134,28 @@ private:
unsigned Indent = 0;
};
+bool isNamespaceDeclaration(const AnnotatedLine *Line) {
+ const FormatToken *NamespaceTok = Line->First;
+ return NamespaceTok && NamespaceTok->getNamespaceToken();
+}
+
+bool isEndOfNamespace(const AnnotatedLine *Line,
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+ if (!Line->startsWith(tok::r_brace))
+ return false;
+ size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
+ if (StartLineIndex == UnwrappedLine::kInvalidIndex)
+ return false;
+ assert(StartLineIndex < AnnotatedLines.size());
+ return isNamespaceDeclaration(AnnotatedLines[StartLineIndex]);
+}
+
class LineJoiner {
public:
LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords,
const SmallVectorImpl<AnnotatedLine *> &Lines)
- : Style(Style), Keywords(Keywords), End(Lines.end()),
- Next(Lines.begin()) {}
+ : Style(Style), Keywords(Keywords), End(Lines.end()), Next(Lines.begin()),
+ AnnotatedLines(Lines) {}
/// \brief Returns the next line, merging multiple lines into one if possible.
const AnnotatedLine *getNextMergedLine(bool DryRun,
@@ -141,8 +164,7 @@ public:
return nullptr;
const AnnotatedLine *Current = *Next;
IndentTracker.nextLine(*Current);
- unsigned MergedLines =
- tryFitMultipleLinesInOne(IndentTracker.getIndent(), Next, End);
+ unsigned MergedLines = tryFitMultipleLinesInOne(IndentTracker, Next, End);
if (MergedLines > 0 && Style.ColumnLimit == 0)
// Disallow line merging if there is a break at the start of one of the
// input lines.
@@ -159,9 +181,11 @@ public:
private:
/// \brief Calculates how many lines can be merged into 1 starting at \p I.
unsigned
- tryFitMultipleLinesInOne(unsigned Indent,
+ tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker,
SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ const unsigned Indent = IndentTracker.getIndent();
+
// Can't join the last line with anything.
if (I + 1 == E)
return 0;
@@ -186,24 +210,113 @@ private:
? 0
: Limit - TheLine->Last->TotalLength;
+ if (TheLine->Last->is(TT_FunctionLBrace) &&
+ TheLine->First == TheLine->Last &&
+ !Style.BraceWrapping.SplitEmptyFunction &&
+ I[1]->First->is(tok::r_brace))
+ return tryMergeSimpleBlock(I, E, Limit);
+
+ // Handle empty record blocks where the brace has already been wrapped
+ if (TheLine->Last->is(tok::l_brace) && TheLine->First == TheLine->Last &&
+ I != AnnotatedLines.begin()) {
+ bool EmptyBlock = I[1]->First->is(tok::r_brace);
+
+ const FormatToken *Tok = I[-1]->First;
+ if (Tok && Tok->is(tok::comment))
+ Tok = Tok->getNextNonComment();
+
+ if (Tok && Tok->getNamespaceToken())
+ return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+
+ if (Tok && Tok->is(tok::kw_typedef))
+ Tok = Tok->getNextNonComment();
+ if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
+ tok::kw_extern, Keywords.kw_interface))
+ return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+
// FIXME: TheLine->Level != 0 might or might not be the right check to do.
// If necessary, change to something smarter.
bool MergeShortFunctions =
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
(Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
I[1]->First->is(tok::r_brace)) ||
- (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
+ (Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly &&
TheLine->Level != 0);
+ if (Style.CompactNamespaces) {
+ if (isNamespaceDeclaration(TheLine)) {
+ int i = 0;
+ unsigned closingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
+ for (; I + 1 + i != E && isNamespaceDeclaration(I[i + 1]) &&
+ closingLine == I[i + 1]->MatchingOpeningBlockLineIndex &&
+ I[i + 1]->Last->TotalLength < Limit;
+ i++, closingLine--) {
+ // No extra indent for compacted namespaces
+ IndentTracker.skipLine(*I[i + 1]);
+
+ Limit -= I[i + 1]->Last->TotalLength;
+ }
+ return i;
+ }
+
+ if (isEndOfNamespace(TheLine, AnnotatedLines)) {
+ int i = 0;
+ unsigned openingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
+ for (; I + 1 + i != E && isEndOfNamespace(I[i + 1], AnnotatedLines) &&
+ openingLine == I[i + 1]->MatchingOpeningBlockLineIndex;
+ i++, openingLine--) {
+ // No space between consecutive braces
+ I[i + 1]->First->SpacesRequiredBefore = !I[i]->Last->is(tok::r_brace);
+
+ // Indent like the outer-most namespace
+ IndentTracker.nextLine(*I[i + 1]);
+ }
+ return i;
+ }
+ }
+
+ // Try to merge a function block with left brace unwrapped
if (TheLine->Last->is(TT_FunctionLBrace) &&
TheLine->First != TheLine->Last) {
return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
}
+ // Try to merge a control statement block with left brace unwrapped
+ if (TheLine->Last->is(tok::l_brace) && TheLine->First != TheLine->Last &&
+ TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
+ return Style.AllowShortBlocksOnASingleLine
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ // Try to merge a control statement block with left brace wrapped
+ if (I[1]->First->is(tok::l_brace) &&
+ TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
+ return Style.BraceWrapping.AfterControlStatement
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ // Try to merge either empty or one-line block if is precedeed by control
+ // statement token
+ if (TheLine->First->is(tok::l_brace) && TheLine->First == TheLine->Last &&
+ I != AnnotatedLines.begin() &&
+ I[-1]->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
+ return Style.AllowShortBlocksOnASingleLine
+ ? tryMergeSimpleBlock(I - 1, E, Limit)
+ : 0;
+ }
+ // Try to merge a block with left brace wrapped that wasn't yet covered
if (TheLine->Last->is(tok::l_brace)) {
- return !Style.BraceWrapping.AfterFunction
+ return !Style.BraceWrapping.AfterFunction ||
+ (I[1]->First->is(tok::r_brace) &&
+ !Style.BraceWrapping.SplitEmptyRecord)
? tryMergeSimpleBlock(I, E, Limit)
: 0;
}
+ // Try to merge a function block with left brace wrapped
if (I[1]->First->is(TT_FunctionLBrace) &&
Style.BraceWrapping.AfterFunction) {
if (I[1]->Last->is(TT_LineComment))
@@ -215,7 +328,10 @@ private:
Limit -= 2;
unsigned MergedLines = 0;
- if (MergeShortFunctions) {
+ if (MergeShortFunctions ||
+ (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
+ I[1]->First == I[1]->Last && I + 2 != E &&
+ I[2]->First->is(tok::r_brace))) {
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
// If we managed to merge the block, count the function header, which is
// on a separate line.
@@ -295,7 +411,9 @@ private:
return 0;
unsigned NumStmts = 0;
unsigned Length = 0;
+ bool EndsWithComment = false;
bool InPPDirective = I[0]->InPPDirective;
+ const unsigned Level = I[0]->Level;
for (; NumStmts < 3; ++NumStmts) {
if (I + 1 + NumStmts == E)
break;
@@ -305,9 +423,26 @@ private:
if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
break;
if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
- tok::kw_while, tok::comment) ||
- Line->Last->is(tok::comment))
+ tok::kw_while) ||
+ EndsWithComment)
return 0;
+ if (Line->First->is(tok::comment)) {
+ if (Level != Line->Level)
+ return 0;
+ SmallVectorImpl<AnnotatedLine *>::const_iterator J = I + 2 + NumStmts;
+ for (; J != E; ++J) {
+ Line = *J;
+ if (Line->InPPDirective != InPPDirective)
+ break;
+ if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
+ break;
+ if (Line->First->isNot(tok::comment) || Level != Line->Level)
+ return 0;
+ }
+ break;
+ }
+ if (Line->Last->is(tok::comment))
+ EndsWithComment = true;
Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.
}
if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
@@ -338,11 +473,27 @@ private:
tok::kw_for, tok::r_brace, Keywords.kw___except)) {
if (!Style.AllowShortBlocksOnASingleLine)
return 0;
+ // Don't merge when we can't except the case when
+ // the control statement block is empty
+ if (!Style.AllowShortIfStatementsOnASingleLine &&
+ Line.startsWith(tok::kw_if) &&
+ !Style.BraceWrapping.AfterControlStatement &&
+ !I[1]->First->is(tok::r_brace))
+ return 0;
if (!Style.AllowShortIfStatementsOnASingleLine &&
- Line.startsWith(tok::kw_if))
+ Line.startsWith(tok::kw_if) &&
+ Style.BraceWrapping.AfterControlStatement && I + 2 != E &&
+ !I[2]->First->is(tok::r_brace))
return 0;
if (!Style.AllowShortLoopsOnASingleLine &&
- Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
+ !Style.BraceWrapping.AfterControlStatement &&
+ !I[1]->First->is(tok::r_brace))
+ return 0;
+ if (!Style.AllowShortLoopsOnASingleLine &&
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
+ Style.BraceWrapping.AfterControlStatement && I + 2 != E &&
+ !I[2]->First->is(tok::r_brace))
return 0;
// FIXME: Consider an option to allow short exception handling clauses on
// a single line.
@@ -354,49 +505,73 @@ private:
return 0;
}
- FormatToken *Tok = I[1]->First;
- if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
- (Tok->getNextNonComment() == nullptr ||
- Tok->getNextNonComment()->is(tok::semi))) {
- // We merge empty blocks even if the line exceeds the column limit.
- Tok->SpacesRequiredBefore = 0;
- Tok->CanBreakBefore = true;
- return 1;
- } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
- !startsExternCBlock(Line)) {
- // We don't merge short records.
- if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
- Keywords.kw_interface))
- return 0;
+ if (Line.Last->is(tok::l_brace)) {
+ FormatToken *Tok = I[1]->First;
+ if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
+ (Tok->getNextNonComment() == nullptr ||
+ Tok->getNextNonComment()->is(tok::semi))) {
+ // We merge empty blocks even if the line exceeds the column limit.
+ Tok->SpacesRequiredBefore = 0;
+ Tok->CanBreakBefore = true;
+ return 1;
+ } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
+ !startsExternCBlock(Line)) {
+ // We don't merge short records.
+ FormatToken *RecordTok =
+ Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First;
+ if (RecordTok &&
+ RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
+ Keywords.kw_interface))
+ return 0;
- // Check that we still have three lines and they fit into the limit.
- if (I + 2 == E || I[2]->Type == LT_Invalid)
- return 0;
- Limit = limitConsideringMacros(I + 2, E, Limit);
+ // Check that we still have three lines and they fit into the limit.
+ if (I + 2 == E || I[2]->Type == LT_Invalid)
+ return 0;
+ Limit = limitConsideringMacros(I + 2, E, Limit);
- if (!nextTwoLinesFitInto(I, Limit))
- return 0;
+ if (!nextTwoLinesFitInto(I, Limit))
+ return 0;
- // Second, check that the next line does not contain any braces - if it
- // does, readability declines when putting it into a single line.
- if (I[1]->Last->is(TT_LineComment))
- return 0;
- do {
- if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+ // Second, check that the next line does not contain any braces - if it
+ // does, readability declines when putting it into a single line.
+ if (I[1]->Last->is(TT_LineComment))
+ return 0;
+ do {
+ if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+ return 0;
+ Tok = Tok->Next;
+ } while (Tok);
+
+ // Last, check that the third line starts with a closing brace.
+ Tok = I[2]->First;
+ if (Tok->isNot(tok::r_brace))
return 0;
- Tok = Tok->Next;
- } while (Tok);
- // Last, check that the third line starts with a closing brace.
- Tok = I[2]->First;
- if (Tok->isNot(tok::r_brace))
- return 0;
+ // Don't merge "if (a) { .. } else {".
+ if (Tok->Next && Tok->Next->is(tok::kw_else))
+ return 0;
- // Don't merge "if (a) { .. } else {".
- if (Tok->Next && Tok->Next->is(tok::kw_else))
+ return 2;
+ }
+ } else if (I[1]->First->is(tok::l_brace)) {
+ if (I[1]->Last->is(TT_LineComment))
return 0;
- return 2;
+ // Check for Limit <= 2 to account for the " {".
+ if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(*I)))
+ return 0;
+ Limit -= 2;
+ unsigned MergedLines = 0;
+ if (Style.AllowShortBlocksOnASingleLine ||
+ (I[1]->First == I[1]->Last && I + 2 != E &&
+ I[2]->First->is(tok::r_brace))) {
+ MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+ // If we managed to merge the block, count the statement header, which
+ // is on a separate line.
+ if (MergedLines > 0)
+ ++MergedLines;
+ }
+ return MergedLines;
}
return 0;
}
@@ -449,6 +624,7 @@ private:
const SmallVectorImpl<AnnotatedLine *>::const_iterator End;
SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines;
};
static void markFinalized(FormatToken *Tok) {
@@ -483,7 +659,9 @@ public:
/// \brief Formats an \c AnnotatedLine and returns the penalty.
///
/// If \p DryRun is \c false, directly applies the changes.
- virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
+ virtual unsigned formatLine(const AnnotatedLine &Line,
+ unsigned FirstIndent,
+ unsigned FirstStartColumn,
bool DryRun) = 0;
protected:
@@ -554,7 +732,8 @@ protected:
*Child->First, /*Newlines=*/0, /*Spaces=*/1,
/*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
}
- Penalty += formatLine(*Child, State.Column + 1, DryRun);
+ Penalty +=
+ formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun);
State.Column += 1 + Child->Last->TotalLength;
return true;
@@ -580,10 +759,10 @@ public:
/// \brief Formats the line, simply keeping all of the input's line breaking
/// decisions.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) override {
+ unsigned FirstStartColumn, bool DryRun) override {
assert(!DryRun);
- LineState State =
- Indenter->getInitialState(FirstIndent, &Line, /*DryRun=*/false);
+ LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn,
+ &Line, /*DryRun=*/false);
while (State.NextToken) {
bool Newline =
Indenter->mustBreak(State) ||
@@ -606,12 +785,14 @@ public:
/// \brief Puts all tokens into a single line.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) override {
+ unsigned FirstStartColumn, bool DryRun) override {
unsigned Penalty = 0;
- LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+ LineState State =
+ Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
while (State.NextToken) {
formatChildren(State, /*Newline=*/false, DryRun, Penalty);
- Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
+ Indenter->addTokenToState(
+ State, /*Newline=*/State.NextToken->MustBreakBefore, DryRun);
}
return Penalty;
}
@@ -629,8 +810,9 @@ public:
/// \brief Formats the line by finding the best line breaks with line lengths
/// below the column limit.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) override {
- LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+ unsigned FirstStartColumn, bool DryRun) override {
+ LineState State =
+ Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
// If the ObjC method declaration does not fit on a line, we should format
// it with one arg per line.
@@ -671,7 +853,8 @@ private:
/// \brief The BFS queue type.
typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
- std::greater<QueueItem>> QueueType;
+ std::greater<QueueItem>>
+ QueueType;
/// \brief Analyze the entire solution space starting from \p InitialState.
///
@@ -796,7 +979,10 @@ private:
unsigned
UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
bool DryRun, int AdditionalIndent,
- bool FixBadIndentation) {
+ bool FixBadIndentation,
+ unsigned FirstStartColumn,
+ unsigned NextStartColumn,
+ unsigned LastStartColumn) {
LineJoiner Joiner(Style, Keywords, Lines);
// Try to look up already computed penalty in DryRun-mode.
@@ -816,9 +1002,10 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
// The minimum level of consecutive lines that have been formatted.
unsigned RangeMinLevel = UINT_MAX;
+ bool FirstLine = true;
for (const AnnotatedLine *Line =
Joiner.getNextMergedLine(DryRun, IndentTracker);
- Line; Line = NextLine) {
+ Line; Line = NextLine, FirstLine = false) {
const AnnotatedLine &TheLine = *Line;
unsigned Indent = IndentTracker.getIndent();
@@ -835,12 +1022,19 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
bool ShouldFormat = TheLine.Affected || FixIndentation;
// We cannot format this line; if the reason is that the line had a
// parsing error, remember that.
- if (ShouldFormat && TheLine.Type == LT_Invalid && IncompleteFormat)
- *IncompleteFormat = true;
+ if (ShouldFormat && TheLine.Type == LT_Invalid && Status) {
+ Status->FormatComplete = false;
+ Status->Line =
+ SourceMgr.getSpellingLineNumber(TheLine.First->Tok.getLocation());
+ }
if (ShouldFormat && TheLine.Type != LT_Invalid) {
- if (!DryRun)
- formatFirstToken(TheLine, PreviousLine, Indent);
+ if (!DryRun) {
+ bool LastLine = Line->First->is(tok::eof);
+ formatFirstToken(TheLine, PreviousLine,
+ Indent,
+ LastLine ? LastStartColumn : NextStartColumn + Indent);
+ }
NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
@@ -849,16 +1043,18 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
(TheLine.Type == LT_ImportStatement &&
(Style.Language != FormatStyle::LK_JavaScript ||
!Style.JavaScriptWrapImports));
-
if (Style.ColumnLimit == 0)
NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
- .formatLine(TheLine, Indent, DryRun);
+ .formatLine(TheLine, NextStartColumn + Indent,
+ FirstLine ? FirstStartColumn : 0, DryRun);
else if (FitsIntoOneLine)
Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style, this)
- .formatLine(TheLine, Indent, DryRun);
+ .formatLine(TheLine, NextStartColumn + Indent,
+ FirstLine ? FirstStartColumn : 0, DryRun);
else
Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style, this)
- .formatLine(TheLine, Indent, DryRun);
+ .formatLine(TheLine, NextStartColumn + Indent,
+ FirstLine ? FirstStartColumn : 0, DryRun);
RangeMinLevel = std::min(RangeMinLevel, TheLine.Level);
} else {
// If no token in the current line is affected, we still need to format
@@ -881,6 +1077,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
// Format the first token.
if (ReformatLeadingWhitespace)
formatFirstToken(TheLine, PreviousLine,
+ TheLine.First->OriginalColumn,
TheLine.First->OriginalColumn);
else
Whitespaces->addUntouchableToken(*TheLine.First,
@@ -903,12 +1100,14 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
const AnnotatedLine *PreviousLine,
- unsigned Indent) {
- FormatToken& RootToken = *Line.First;
+ unsigned Indent,
+ unsigned NewlineIndent) {
+ FormatToken &RootToken = *Line.First;
if (RootToken.is(tok::eof)) {
unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
- Whitespaces->replaceWhitespace(RootToken, Newlines, /*Spaces=*/0,
- /*StartOfTokenColumn=*/0);
+ unsigned TokenIndent = Newlines ? NewlineIndent : 0;
+ Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
+ TokenIndent);
return;
}
unsigned Newlines =
@@ -940,6 +1139,13 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
(!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline))
Newlines = std::min(1u, Newlines);
+ if (Newlines)
+ Indent = NewlineIndent;
+
+ // Preprocessor directives get indented after the hash, if indented.
+ if (Line.Type == LT_PreprocessorDirective || Line.Type == LT_ImportStatement)
+ Indent = 0;
+
Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
Line.InPPDirective &&
!RootToken.HasUnescapedNewline);
diff --git a/lib/Format/UnwrappedLineFormatter.h b/lib/Format/UnwrappedLineFormatter.h
index 93247f71d6..6432ca83a4 100644
--- a/lib/Format/UnwrappedLineFormatter.h
+++ b/lib/Format/UnwrappedLineFormatter.h
@@ -32,20 +32,25 @@ public:
WhitespaceManager *Whitespaces,
const FormatStyle &Style,
const AdditionalKeywords &Keywords,
- bool *IncompleteFormat)
+ const SourceManager &SourceMgr,
+ FormattingAttemptStatus *Status)
: Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
- Keywords(Keywords), IncompleteFormat(IncompleteFormat) {}
+ Keywords(Keywords), SourceMgr(SourceMgr), Status(Status) {}
/// \brief Format the current block and return the penalty.
unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines,
bool DryRun = false, int AdditionalIndent = 0,
- bool FixBadIndentation = false);
+ bool FixBadIndentation = false,
+ unsigned FirstStartColumn = 0,
+ unsigned NextStartColumn = 0,
+ unsigned LastStartColumn = 0);
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(const AnnotatedLine &Line,
- const AnnotatedLine *PreviousLine, unsigned Indent);
+ const AnnotatedLine *PreviousLine, unsigned Indent,
+ unsigned NewlineIndent);
/// \brief Returns the column limit for a line, taking into account whether we
/// need an escaped newline due to a continued preprocessor directive.
@@ -63,7 +68,8 @@ private:
WhitespaceManager *Whitespaces;
const FormatStyle &Style;
const AdditionalKeywords &Keywords;
- bool *IncompleteFormat;
+ const SourceManager &SourceMgr;
+ FormattingAttemptStatus *Status;
};
} // end namespace format
} // end namespace clang
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 25bc99118f..9243cd99cb 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -55,13 +55,32 @@ private:
std::vector<bool> &Stack;
};
+static bool isLineComment(const FormatToken &FormatTok) {
+ return FormatTok.is(tok::comment) && FormatTok.TokenText.startswith("//");
+}
+
+// Checks if \p FormatTok is a line comment that continues the line comment
+// \p Previous. The original column of \p MinColumnToken is used to determine
+// whether \p FormatTok is indented enough to the right to continue \p Previous.
+static bool continuesLineComment(const FormatToken &FormatTok,
+ const FormatToken *Previous,
+ const FormatToken *MinColumnToken) {
+ if (!Previous || !MinColumnToken)
+ return false;
+ unsigned MinContinueColumn =
+ MinColumnToken->OriginalColumn + (isLineComment(*MinColumnToken) ? 0 : 1);
+ return isLineComment(FormatTok) && FormatTok.NewlinesBefore == 1 &&
+ isLineComment(*Previous) &&
+ FormatTok.OriginalColumn >= MinContinueColumn;
+}
+
class ScopedMacroState : public FormatTokenSource {
public:
ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
FormatToken *&ResetToken)
: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
- Token(nullptr) {
+ Token(nullptr), PreviousToken(nullptr) {
TokenSource = this;
Line.Level = 0;
Line.InPPDirective = true;
@@ -78,6 +97,7 @@ public:
// The \c UnwrappedLineParser guards against this by never calling
// \c getNextToken() after it has encountered the first eof token.
assert(!eof());
+ PreviousToken = Token;
Token = PreviousTokenSource->getNextToken();
if (eof())
return getFakeEOF();
@@ -87,12 +107,17 @@ public:
unsigned getPosition() override { return PreviousTokenSource->getPosition(); }
FormatToken *setPosition(unsigned Position) override {
+ PreviousToken = nullptr;
Token = PreviousTokenSource->setPosition(Position);
return Token;
}
private:
- bool eof() { return Token && Token->HasUnescapedNewline; }
+ bool eof() {
+ return Token && Token->HasUnescapedNewline &&
+ !continuesLineComment(*Token, PreviousToken,
+ /*MinColumnToken=*/PreviousToken);
+ }
FormatToken *getFakeEOF() {
static bool EOFInitialized = false;
@@ -112,6 +137,7 @@ private:
FormatTokenSource *PreviousTokenSource;
FormatToken *Token;
+ FormatToken *PreviousToken;
};
} // end anonymous namespace
@@ -199,15 +225,21 @@ private:
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
const AdditionalKeywords &Keywords,
+ unsigned FirstStartColumn,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
- Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}
+ Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
+ IfNdefCondition(nullptr), FoundIncludeGuardStart(false),
+ IncludeGuardRejected(false), FirstStartColumn(FirstStartColumn) {}
void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
+ IfNdefCondition = nullptr;
+ FoundIncludeGuardStart = false;
+ IncludeGuardRejected = false;
Line.reset(new UnwrappedLine);
CommentsBeforeNextToken.clear();
FormatTok = nullptr;
@@ -216,10 +248,12 @@ void UnwrappedLineParser::reset() {
CurrentLines = &Lines;
DeclarationScopeStack.clear();
PPStack.clear();
+ Line->FirstStartColumn = FirstStartColumn;
}
void UnwrappedLineParser::parse() {
IndexedTokenSource TokenSource(AllTokens);
+ Line->FirstStartColumn = FirstStartColumn;
do {
DEBUG(llvm::dbgs() << "----\n");
reset();
@@ -259,7 +293,10 @@ void UnwrappedLineParser::parseFile() {
!Line->InPPDirective && Style.Language != FormatStyle::LK_JavaScript;
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
- parseLevel(/*HasOpeningBrace=*/false);
+ if (Style.Language == FormatStyle::LK_TextProto)
+ parseBracedList();
+ else
+ parseLevel(/*HasOpeningBrace=*/false);
// Make sure to format the remaining tokens.
flushComments(true);
addUnwrappedLine();
@@ -296,6 +333,12 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
break;
case tok::kw_default:
case tok::kw_case:
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ Line->MustBeDeclaration) {
+ // A 'case: string' style field declaration.
+ parseStructuralElement();
+ break;
+ }
if (!SwitchLabelEncountered &&
(Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1)))
++Line->Level;
@@ -316,7 +359,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
// definitions, too.
unsigned StoredPosition = Tokens->getPosition();
FormatToken *Tok = FormatTok;
- const FormatToken *PrevTok = getPreviousToken();
+ const FormatToken *PrevTok = Tok->Previous;
// Keep a stack of positions of lbrace tokens. We will
// update information about whether an lbrace starts a
// braced init list or a different block during the loop.
@@ -333,16 +376,21 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
switch (Tok->Tok.getKind()) {
case tok::l_brace:
- if (Style.Language == FormatStyle::LK_JavaScript && PrevTok &&
- PrevTok->is(tok::colon))
- // A colon indicates this code is in a type, or a braced list following
- // a label in an object literal ({a: {b: 1}}).
- // The code below could be confused by semicolons between the individual
- // members in a type member list, which would normally trigger BK_Block.
- // In both cases, this must be parsed as an inline braced init.
- Tok->BlockKind = BK_BracedInit;
- else
+ if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
+ if (PrevTok->is(tok::colon))
+ // A colon indicates this code is in a type, or a braced list
+ // following a label in an object literal ({a: {b: 1}}). The code
+ // below could be confused by semicolons between the individual
+ // members in a type member list, which would normally trigger
+ // BK_Block. In both cases, this must be parsed as an inline braced
+ // init.
+ Tok->BlockKind = BK_BracedInit;
+ else if (PrevTok->is(tok::r_paren))
+ // `) { }` can only occur in function or method declarations in JS.
+ Tok->BlockKind = BK_Block;
+ } else {
Tok->BlockKind = BK_Unknown;
+ }
LBraceStack.push_back(Tok);
break;
case tok::r_brace:
@@ -364,13 +412,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
// BlockKind later if we parse a braced list (where all blocks
// inside are by default braced lists), or when we explicitly detect
// blocks (for example while parsing lambdas).
+ // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
+ // braced list in JS.
ProbablyBracedList =
(Style.Language == FormatStyle::LK_JavaScript &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
Keywords.kw_as)) ||
+ (Style.isCpp() && NextTok->is(tok::l_paren)) ||
NextTok->isOneOf(tok::comma, tok::period, tok::colon,
tok::r_paren, tok::r_square, tok::l_brace,
- tok::l_square, tok::l_paren, tok::ellipsis) ||
+ tok::l_square, tok::ellipsis) ||
(NextTok->is(tok::identifier) &&
!PrevTok->isOneOf(tok::semi, tok::r_brace, tok::l_brace)) ||
(NextTok->is(tok::semi) &&
@@ -414,6 +465,21 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
FormatTok = Tokens->setPosition(StoredPosition);
}
+template <class T>
+static inline void hash_combine(std::size_t &seed, const T &v) {
+ std::hash<T> hasher;
+ seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
+size_t UnwrappedLineParser::computePPHash() const {
+ size_t h = 0;
+ for (const auto &i : PPStack) {
+ hash_combine(h, size_t(i.Kind));
+ hash_combine(h, i.Line);
+ }
+ return h;
+}
+
void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
bool MunchSemi) {
assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
@@ -421,15 +487,21 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
FormatTok->BlockKind = BK_Block;
+ size_t PPStartHash = computePPHash();
+
unsigned InitialLevel = Line->Level;
- nextToken();
+ nextToken(/*LevelDifference=*/AddLevel ? 1 : 0);
if (MacroBlock && FormatTok->is(tok::l_paren))
parseParens();
+ size_t NbPreprocessorDirectives =
+ CurrentLines == &Lines ? PreprocessorDirectives.size() : 0;
addUnwrappedLine();
size_t OpeningLineIndex =
- Lines.empty() ? (UnwrappedLine::kInvalidIndex) : (Lines.size() - 1);
+ CurrentLines->empty()
+ ? (UnwrappedLine::kInvalidIndex)
+ : (CurrentLines->size() - 1 - NbPreprocessorDirectives);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
@@ -447,7 +519,10 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
return;
}
- nextToken(); // Munch the closing brace.
+ size_t PPEndHash = computePPHash();
+
+ // Munch the closing brace.
+ nextToken(/*LevelDifference=*/AddLevel ? -1 : 0);
if (MacroBlock && FormatTok->is(tok::l_paren))
parseParens();
@@ -455,7 +530,15 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
if (MunchSemi && FormatTok->Tok.is(tok::semi))
nextToken();
Line->Level = InitialLevel;
- Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
+
+ if (PPStartHash == PPEndHash) {
+ Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
+ if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
+ // Update the opening line to add the forward reference as well
+ (*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex =
+ CurrentLines->size() - 1;
+ }
+ }
}
static bool isGoogScope(const UnwrappedLine &Line) {
@@ -476,6 +559,24 @@ static bool isGoogScope(const UnwrappedLine &Line) {
return I->Tok->is(tok::l_paren);
}
+static bool isIIFE(const UnwrappedLine &Line,
+ const AdditionalKeywords &Keywords) {
+ // Look for the start of an immediately invoked anonymous function.
+ // https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
+ // This is commonly done in JavaScript to create a new, anonymous scope.
+ // Example: (function() { ... })()
+ if (Line.Tokens.size() < 3)
+ return false;
+ auto I = Line.Tokens.begin();
+ if (I->Tok->isNot(tok::l_paren))
+ return false;
+ ++I;
+ if (I->Tok->isNot(Keywords.kw_function))
+ return false;
+ ++I;
+ return I->Tok->is(tok::l_paren);
+}
+
static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
const FormatToken &InitialToken) {
if (InitialToken.is(tok::kw_namespace))
@@ -493,15 +594,15 @@ void UnwrappedLineParser::parseChildBlock() {
FormatTok->BlockKind = BK_Block;
nextToken();
{
- bool GoogScope =
- Style.Language == FormatStyle::LK_JavaScript && isGoogScope(*Line);
+ bool SkipIndent = (Style.Language == FormatStyle::LK_JavaScript &&
+ (isGoogScope(*Line) || isIIFE(*Line, Keywords)));
ScopedLineState LineState(*this);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
/*MustBeDeclaration=*/false);
- Line->Level += GoogScope ? 0 : 1;
+ Line->Level += SkipIndent ? 0 : 1;
parseLevel(/*HasOpeningBrace=*/true);
flushComments(isOnNewLine(*FormatTok));
- Line->Level -= GoogScope ? 0 : 1;
+ Line->Level -= SkipIndent ? 0 : 1;
}
nextToken();
}
@@ -543,10 +644,15 @@ void UnwrappedLineParser::parsePPDirective() {
}
void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) {
- if (Unreachable || (!PPStack.empty() && PPStack.back() == PP_Unreachable))
- PPStack.push_back(PP_Unreachable);
+ size_t Line = CurrentLines->size();
+ if (CurrentLines == &PreprocessorDirectives)
+ Line += Lines.size();
+
+ if (Unreachable ||
+ (!PPStack.empty() && PPStack.back().Kind == PP_Unreachable))
+ PPStack.push_back({PP_Unreachable, Line});
else
- PPStack.push_back(PP_Conditional);
+ PPStack.push_back({PP_Conditional, Line});
}
void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
@@ -580,7 +686,7 @@ void UnwrappedLineParser::conditionalCompilationEnd() {
}
}
// Guard against #endif's without #if.
- if (PPBranchLevel > 0)
+ if (PPBranchLevel > -1)
--PPBranchLevel;
if (!PPChainBranchIndex.empty())
PPChainBranchIndex.pop();
@@ -597,12 +703,35 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) {
if (IfDef && !IfNDef && FormatTok->TokenText == "SWIG")
Unreachable = true;
conditionalCompilationStart(Unreachable);
+ FormatToken *IfCondition = FormatTok;
+ // If there's a #ifndef on the first line, and the only lines before it are
+ // comments, it could be an include guard.
+ bool MaybeIncludeGuard = IfNDef;
+ if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard) {
+ for (auto &Line : Lines) {
+ if (!Line.Tokens.front().Tok->is(tok::comment)) {
+ MaybeIncludeGuard = false;
+ IncludeGuardRejected = true;
+ break;
+ }
+ }
+ }
+ --PPBranchLevel;
parsePPUnknown();
+ ++PPBranchLevel;
+ if (!IncludeGuardRejected && !FoundIncludeGuardStart && MaybeIncludeGuard)
+ IfNdefCondition = IfCondition;
}
void UnwrappedLineParser::parsePPElse() {
+ // If a potential include guard has an #else, it's not an include guard.
+ if (FoundIncludeGuardStart && PPBranchLevel == 0)
+ FoundIncludeGuardStart = false;
conditionalCompilationAlternative();
+ if (PPBranchLevel > -1)
+ --PPBranchLevel;
parsePPUnknown();
+ ++PPBranchLevel;
}
void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
@@ -610,6 +739,16 @@ void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
void UnwrappedLineParser::parsePPEndIf() {
conditionalCompilationEnd();
parsePPUnknown();
+ // If the #endif of a potential include guard is the last thing in the file,
+ // then we count it as a real include guard and subtract one from every
+ // preprocessor indent.
+ unsigned TokenPosition = Tokens->getPosition();
+ FormatToken *PeekNext = AllTokens[TokenPosition];
+ if (FoundIncludeGuardStart && PPBranchLevel == -1 && PeekNext->is(tok::eof) &&
+ Style.IndentPPDirectives != FormatStyle::PPDIS_None)
+ for (auto &Line : Lines)
+ if (Line.InPPDirective && Line.Level > 0)
+ --Line.Level;
}
void UnwrappedLineParser::parsePPDefine() {
@@ -619,14 +758,26 @@ void UnwrappedLineParser::parsePPDefine() {
parsePPUnknown();
return;
}
+ if (IfNdefCondition && IfNdefCondition->TokenText == FormatTok->TokenText) {
+ FoundIncludeGuardStart = true;
+ for (auto &Line : Lines) {
+ if (!Line.Tokens.front().Tok->isOneOf(tok::comment, tok::hash)) {
+ FoundIncludeGuardStart = false;
+ break;
+ }
+ }
+ }
+ IfNdefCondition = nullptr;
nextToken();
if (FormatTok->Tok.getKind() == tok::l_paren &&
FormatTok->WhitespaceRange.getBegin() ==
FormatTok->WhitespaceRange.getEnd()) {
parseParens();
}
+ if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash)
+ Line->Level += PPBranchLevel + 1;
addUnwrappedLine();
- Line->Level = 1;
+ ++Line->Level;
// Errors during a preprocessor directive can only affect the layout of the
// preprocessor directive, and thus we ignore them. An alternative approach
@@ -640,7 +791,10 @@ void UnwrappedLineParser::parsePPUnknown() {
do {
nextToken();
} while (!eof());
+ if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash)
+ Line->Level += PPBranchLevel + 1;
addUnwrappedLine();
+ IfNdefCondition = nullptr;
}
// Here we blacklist certain tokens that are not usually the first token in an
@@ -683,8 +837,8 @@ static bool mustBeJSIdent(const AdditionalKeywords &Keywords,
Keywords.kw_function, Keywords.kw_import, Keywords.kw_is,
Keywords.kw_let, Keywords.kw_var, tok::kw_const,
Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements,
- Keywords.kw_instanceof, Keywords.kw_interface,
- Keywords.kw_throws));
+ Keywords.kw_instanceof, Keywords.kw_interface, Keywords.kw_throws,
+ Keywords.kw_from));
}
static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords,
@@ -754,7 +908,8 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
tok::minusminus)))
return addUnwrappedLine();
- if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
+ if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
+ isJSDeclOrStmt(Keywords, Next))
return addUnwrappedLine();
}
@@ -772,6 +927,7 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::at:
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
break;
}
@@ -858,13 +1014,22 @@ void UnwrappedLineParser::parseStructuralElement() {
parseDoWhile();
return;
case tok::kw_switch:
+ if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+ // 'switch: string' field declaration.
+ break;
parseSwitch();
return;
case tok::kw_default:
+ if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+ // 'default: string' field declaration.
+ break;
nextToken();
parseLabel();
return;
case tok::kw_case:
+ if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+ // 'case: string' field declaration.
+ break;
parseCaseLabel();
return;
case tok::kw_try:
@@ -876,7 +1041,12 @@ void UnwrappedLineParser::parseStructuralElement() {
if (FormatTok->Tok.is(tok::string_literal)) {
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false);
+ if (Style.BraceWrapping.AfterExternBlock) {
+ addUnwrappedLine();
+ parseBlock(/*MustBeDeclaration=*/true);
+ } else {
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false);
+ }
addUnwrappedLine();
return;
}
@@ -916,7 +1086,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)) {
@@ -931,12 +1102,14 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
}
do {
- const FormatToken *Previous = getPreviousToken();
+ const FormatToken *Previous = FormatTok->Previous;
switch (FormatTok->Tok.getKind()) {
case tok::at:
nextToken();
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ }
break;
case tok::kw_enum:
// Ignore if this is part of "template <enum ...".
@@ -950,7 +1123,7 @@ void UnwrappedLineParser::parseStructuralElement() {
if (!parseEnum())
break;
// This only applies for C++.
- if (!Style.IsCpp()) {
+ if (!Style.isCpp()) {
addUnwrappedLine();
return;
}
@@ -1039,13 +1212,15 @@ void UnwrappedLineParser::parseStructuralElement() {
return;
}
- // Parse function literal unless 'function' is the first token in a line
- // in which case this should be treated as a free-standing function.
+ // Function declarations (as opposed to function expressions) are parsed
+ // on their own unwrapped line by continuing this loop. Function
+ // expressions (functions that are not on their own line) must not create
+ // a new unwrapped line, so they are special cased below.
+ size_t TokenCount = Line->Tokens.size();
if (Style.Language == FormatStyle::LK_JavaScript &&
- (FormatTok->is(Keywords.kw_function) ||
- FormatTok->startsSequence(Keywords.kw_async,
- Keywords.kw_function)) &&
- Line->Tokens.size() > 0) {
+ FormatTok->is(Keywords.kw_function) &&
+ (TokenCount > 1 || (TokenCount == 1 && !Line->Tokens.front().Tok->is(
+ Keywords.kw_async)))) {
tryToParseJSFunction();
break;
}
@@ -1114,7 +1289,13 @@ void UnwrappedLineParser::parseStructuralElement() {
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ } else if (Style.Language == FormatStyle::LK_Proto &&
+ FormatTok->Tok.is(tok::less)) {
+ nextToken();
+ parseBracedList(/*ContinueOnSemicolons=*/false,
+ /*ClosingBraceKind=*/tok::greater);
}
break;
case tok::l_square:
@@ -1131,15 +1312,7 @@ void UnwrappedLineParser::parseStructuralElement() {
}
bool UnwrappedLineParser::tryToParseLambda() {
- if (!Style.IsCpp()) {
- nextToken();
- return false;
- }
- const FormatToken* Previous = getPreviousToken();
- if (Previous &&
- (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
- tok::kw_delete) ||
- Previous->closesScope() || Previous->isSimpleTypeSpecifier())) {
+ if (!Style.isCpp()) {
nextToken();
return false;
}
@@ -1185,49 +1358,18 @@ bool UnwrappedLineParser::tryToParseLambda() {
}
bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
- nextToken();
- if (FormatTok->is(tok::equal)) {
- nextToken();
- if (FormatTok->is(tok::r_square)) {
- nextToken();
- return true;
- }
- if (FormatTok->isNot(tok::comma))
- return false;
- nextToken();
- } else if (FormatTok->is(tok::amp)) {
- nextToken();
- if (FormatTok->is(tok::r_square)) {
- nextToken();
- return true;
- }
- if (!FormatTok->isOneOf(tok::comma, tok::identifier)) {
- return false;
- }
- if (FormatTok->is(tok::comma))
- nextToken();
- } else if (FormatTok->is(tok::r_square)) {
+ const FormatToken *Previous = FormatTok->Previous;
+ if (Previous &&
+ (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
+ tok::kw_delete) ||
+ FormatTok->isCppStructuredBinding(Style) || Previous->closesScope() ||
+ Previous->isSimpleTypeSpecifier())) {
nextToken();
- return true;
+ return false;
}
- do {
- if (FormatTok->is(tok::amp))
- nextToken();
- if (!FormatTok->isOneOf(tok::identifier, tok::kw_this))
- return false;
- nextToken();
- if (FormatTok->is(tok::ellipsis))
- nextToken();
- if (FormatTok->is(tok::comma)) {
- nextToken();
- } else if (FormatTok->is(tok::r_square)) {
- nextToken();
- return true;
- } else {
- return false;
- }
- } while (!eof());
- return false;
+ nextToken();
+ parseSquare(/*LambdaIntroducer=*/true);
+ return true;
}
void UnwrappedLineParser::tryToParseJSFunction() {
@@ -1279,13 +1421,14 @@ bool UnwrappedLineParser::tryToParseBracedList() {
assert(FormatTok->BlockKind != BK_Unknown);
if (FormatTok->BlockKind == BK_Block)
return false;
+ nextToken();
parseBracedList();
return true;
}
-bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
+bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
+ tok::TokenKind ClosingBraceKind) {
bool HasError = false;
- nextToken();
// FIXME: Once we have an expression parser in the UnwrappedLineParser,
// replace this by using parseAssigmentExpression() inside.
@@ -1312,6 +1455,10 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
parseChildBlock();
}
}
+ if (FormatTok->Tok.getKind() == ClosingBraceKind) {
+ nextToken();
+ return !HasError;
+ }
switch (FormatTok->Tok.getKind()) {
case tok::caret:
nextToken();
@@ -1336,11 +1483,18 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
// Assume there are no blocks inside a braced init list apart
// from the ones we explicitly parse out (like lambdas).
FormatTok->BlockKind = BK_BracedInit;
+ nextToken();
parseBracedList();
break;
- case tok::r_brace:
- nextToken();
- return !HasError;
+ case tok::less:
+ if (Style.Language == FormatStyle::LK_Proto) {
+ nextToken();
+ parseBracedList(/*ContinueOnSemicolons=*/false,
+ /*ClosingBraceKind=*/tok::greater);
+ } else {
+ nextToken();
+ }
+ break;
case tok::semi:
// JavaScript (or more precisely TypeScript) can have semicolons in braced
// lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
@@ -1391,8 +1545,10 @@ void UnwrappedLineParser::parseParens() {
break;
case tok::at:
nextToken();
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ }
break;
case tok::kw_class:
if (Style.Language == FormatStyle::LK_JavaScript)
@@ -1415,10 +1571,12 @@ void UnwrappedLineParser::parseParens() {
} while (!eof());
}
-void UnwrappedLineParser::parseSquare() {
- assert(FormatTok->Tok.is(tok::l_square) && "'[' expected.");
- if (tryToParseLambda())
- return;
+void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
+ if (!LambdaIntroducer) {
+ assert(FormatTok->Tok.is(tok::l_square) && "'[' expected.");
+ if (tryToParseLambda())
+ return;
+ }
do {
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
@@ -1440,8 +1598,10 @@ void UnwrappedLineParser::parseSquare() {
}
case tok::at:
nextToken();
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ }
break;
default:
nextToken();
@@ -1453,6 +1613,8 @@ void UnwrappedLineParser::parseSquare() {
void UnwrappedLineParser::parseIfThenElse() {
assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected");
nextToken();
+ if (FormatTok->Tok.is(tok::kw_constexpr))
+ nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
bool NeedsUnwrappedLine = false;
@@ -1612,6 +1774,10 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) &&
"'for', 'while' or foreach macro expected");
nextToken();
+ // JS' for await ( ...
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->is(Keywords.kw_await))
+ nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
if (FormatTok->Tok.is(tok::l_brace)) {
@@ -1741,7 +1907,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.IsCpp() && FormatTok->is(tok::identifier))
+ if (Style.isCpp() && FormatTok->is(tok::identifier))
return false;
}
}
@@ -1762,6 +1928,7 @@ bool UnwrappedLineParser::parseEnum() {
}
// Parse enum body.
+ nextToken();
bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true);
if (HasError) {
if (FormatTok->is(tok::semi))
@@ -1796,6 +1963,7 @@ void UnwrappedLineParser::parseJavaEnumBody() {
FormatTok = Tokens->setPosition(StoredPosition);
if (IsSimple) {
+ nextToken();
parseBracedList();
addUnwrappedLine();
return;
@@ -1849,6 +2017,17 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
FormatTok->isOneOf(tok::period, tok::comma))) {
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+ // JavaScript/TypeScript supports inline object types in
+ // extends/implements positions:
+ // class Foo implements {bar: number} { }
+ nextToken();
+ if (FormatTok->is(tok::l_brace)) {
+ tryToParseBracedList();
+ continue;
+ }
+ }
bool IsNonMacroIdentifier =
FormatTok->is(tok::identifier) &&
FormatTok->TokenText != FormatTok->TokenText.upper();
@@ -2007,6 +2186,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
}
if (FormatTok->is(tok::l_brace)) {
FormatTok->BlockKind = BK_Block;
+ nextToken();
parseBracedList();
} else {
nextToken();
@@ -2016,14 +2196,15 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
StringRef Prefix = "") {
- llvm::dbgs() << Prefix << "Line(" << Line.Level << ")"
+ llvm::dbgs() << Prefix << "Line(" << Line.Level
+ << ", FSC=" << Line.FirstStartColumn << ")"
<< (Line.InPPDirective ? " MACRO" : "") << ": ";
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
E = Line.Tokens.end();
I != E; ++I) {
llvm::dbgs() << I->Tok->Tok.getName() << "["
- << "T=" << I->Tok->Type
- << ", OC=" << I->Tok->OriginalColumn << "] ";
+ << "T=" << I->Tok->Type << ", OC=" << I->Tok->OriginalColumn
+ << "] ";
}
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
E = Line.Tokens.end();
@@ -2049,12 +2230,15 @@ void UnwrappedLineParser::addUnwrappedLine() {
CurrentLines->push_back(std::move(*Line));
Line->Tokens.clear();
Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
+ Line->FirstStartColumn = 0;
if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
CurrentLines->append(
std::make_move_iterator(PreprocessorDirectives.begin()),
std::make_move_iterator(PreprocessorDirectives.end()));
PreprocessorDirectives.clear();
}
+ // Disconnect the current token from the last token on the previous line.
+ FormatTok->Previous = nullptr;
}
bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); }
@@ -2064,16 +2248,11 @@ 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) {
+static bool continuesLineCommentSection(const FormatToken &FormatTok,
+ const UnwrappedLine &Line,
+ llvm::Regex &CommentPragmasRegex) {
if (Line.Tokens.empty())
return false;
@@ -2172,12 +2351,8 @@ static bool continuesLineComment(const FormatToken &FormatTok,
MinColumnToken = PreviousToken;
}
- unsigned MinContinueColumn =
- MinColumnToken->OriginalColumn +
- (isLineComment(*MinColumnToken) ? 0 : 1);
- return isLineComment(FormatTok) && FormatTok.NewlinesBefore == 1 &&
- isLineComment(*(Line.Tokens.back().Tok)) &&
- FormatTok.OriginalColumn >= MinContinueColumn;
+ return continuesLineComment(FormatTok, /*Previous=*/Line.Tokens.back().Tok,
+ MinColumnToken);
}
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
@@ -2195,7 +2370,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
// FIXME: Consider putting separate line comment sections as children to the
// unwrapped line instead.
(*I)->ContinuesLineCommentSection =
- continuesLineComment(**I, *Line, CommentPragmasRegex);
+ continuesLineCommentSection(**I, *Line, CommentPragmasRegex);
if (isOnNewLine(**I) && JustComments && !(*I)->ContinuesLineCommentSection)
addUnwrappedLine();
pushToken(*I);
@@ -2205,30 +2380,24 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
CommentsBeforeNextToken.clear();
}
-void UnwrappedLineParser::nextToken() {
+void UnwrappedLineParser::nextToken(int LevelDifference) {
if (eof())
return;
flushComments(isOnNewLine(*FormatTok));
pushToken(FormatTok);
+ FormatToken *Previous = FormatTok;
if (Style.Language != FormatStyle::LK_JavaScript)
- readToken();
+ readToken(LevelDifference);
else
readTokenWithJavaScriptASI();
-}
-
-const FormatToken *UnwrappedLineParser::getPreviousToken() {
- // FIXME: This is a dirty way to access the previous token. Find a better
- // solution.
- if (!Line || Line->Tokens.empty())
- return nullptr;
- return Line->Tokens.back().Tok;
+ FormatTok->Previous = Previous;
}
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:
+ // the method continuesLineCommentSection, with the following caveat:
//
// Define a trail of Comments to be a nonempty proper postfix of Comments such
// that each comment line from the trail is aligned with the next token, if
@@ -2261,12 +2430,11 @@ void UnwrappedLineParser::distributeComments(
}
for (unsigned i = 0, e = Comments.size(); i < e; ++i) {
FormatToken *FormatTok = Comments[i];
- if (HasTrailAlignedWithNextToken &&
- i == StartOfTrailAlignedWithNextToken) {
+ if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) {
FormatTok->ContinuesLineCommentSection = false;
} else {
FormatTok->ContinuesLineCommentSection =
- continuesLineComment(*FormatTok, *Line, CommentPragmasRegex);
+ continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex);
}
if (!FormatTok->ContinuesLineCommentSection &&
(isOnNewLine(*FormatTok) || FormatTok->IsFirst)) {
@@ -2280,7 +2448,7 @@ void UnwrappedLineParser::distributeComments(
}
}
-void UnwrappedLineParser::readToken() {
+void UnwrappedLineParser::readToken(int LevelDifference) {
SmallVector<FormatToken *, 1> Comments;
do {
FormatTok = Tokens->getNextToken();
@@ -2293,6 +2461,10 @@ void UnwrappedLineParser::readToken() {
// directives only after that unwrapped line was finished later.
bool SwitchToPreprocessorLines = !Line->Tokens.empty();
ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
+ assert((LevelDifference >= 0 ||
+ static_cast<unsigned>(-LevelDifference) <= Line->Level) &&
+ "LevelDifference makes Line->Level negative");
+ Line->Level += LevelDifference;
// Comments stored before the preprocessor directive need to be output
// before the preprocessor directive, at the same level as the
// preprocessor directive, as we consider them to apply to the directive.
@@ -2313,7 +2485,7 @@ void UnwrappedLineParser::readToken() {
FormatTok->MustBreakBefore = true;
}
- if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) &&
+ if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) &&
!Line->InPPDirective) {
continue;
}
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 15d1d9cda7..1d8ccabbd0 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -56,6 +56,8 @@ struct UnwrappedLine {
size_t MatchingOpeningBlockLineIndex;
static const size_t kInvalidIndex = -1;
+
+ unsigned FirstStartColumn = 0;
};
class UnwrappedLineConsumer {
@@ -71,6 +73,7 @@ class UnwrappedLineParser {
public:
UnwrappedLineParser(const FormatStyle &Style,
const AdditionalKeywords &Keywords,
+ unsigned FirstStartColumn,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback);
@@ -93,9 +96,10 @@ private:
void readTokenWithJavaScriptASI();
void parseStructuralElement();
bool tryToParseBracedList();
- bool parseBracedList(bool ContinueOnSemicolons = false);
+ bool parseBracedList(bool ContinueOnSemicolons = false,
+ tok::TokenKind ClosingBraceKind = tok::r_brace);
void parseParens();
- void parseSquare();
+ void parseSquare(bool LambdaIntroducer = false);
void parseIfThenElse();
void parseTryCatch();
void parseForOrWhileLoop();
@@ -122,9 +126,12 @@ private:
void tryToParseJSFunction();
void addUnwrappedLine();
bool eof() const;
- void nextToken();
- const FormatToken *getPreviousToken();
- void readToken();
+ // LevelDifference is the difference of levels after and before the current
+ // token. For example:
+ // - if the token is '{' and opens a block, LevelDifference is 1.
+ // - if the token is '}' and closes a block, LevelDifference is -1.
+ void nextToken(int LevelDifference = 0);
+ void readToken(int LevelDifference = 0);
// Decides which comment tokens should be added to the current line and which
// should be added as comments before the next token.
@@ -155,6 +162,11 @@ private:
bool isOnNewLine(const FormatToken &FormatTok);
+ // Compute hash of the current preprocessor branch.
+ // This is used to identify the different branches, and thus track if block
+ // open and close in the same branch.
+ size_t computePPHash() const;
+
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
// and use that everywhere in the Parser.
@@ -173,7 +185,7 @@ private:
// Preprocessor directives are parsed out-of-order from other unwrapped lines.
// Thus, we need to keep a list of preprocessor directives to be reported
- // after an unwarpped line that has been started was finished.
+ // after an unwrapped line that has been started was finished.
SmallVector<UnwrappedLine, 4> PreprocessorDirectives;
// New unwrapped lines are added via CurrentLines.
@@ -206,8 +218,14 @@ private:
PP_Unreachable // #if 0 or a conditional preprocessor block inside #if 0
};
+ struct PPBranch {
+ PPBranch(PPBranchKind Kind, size_t Line) : Kind(Kind), Line(Line) {}
+ PPBranchKind Kind;
+ size_t Line;
+ };
+
// Keeps a stack of currently active preprocessor branching directives.
- SmallVector<PPBranchKind, 16> PPStack;
+ SmallVector<PPBranch, 16> PPStack;
// The \c UnwrappedLineParser re-parses the code for each combination
// of preprocessor branches that can be taken.
@@ -230,6 +248,15 @@ private:
// sequence.
std::stack<int> PPChainBranchIndex;
+ // Contains the #ifndef condition for a potential include guard.
+ FormatToken *IfNdefCondition;
+ bool FoundIncludeGuardStart;
+ bool IncludeGuardRejected;
+ // Contains the first start column where the source begins. This is zero for
+ // normal source code and may be nonzero when formatting a code fragment that
+ // does not start at the beginning of the file.
+ unsigned FirstStartColumn;
+
friend class ScopedLineState;
friend class CompoundStatementIndenter;
};
@@ -242,8 +269,9 @@ struct UnwrappedLineNode {
SmallVector<UnwrappedLine, 0> Children;
};
-inline UnwrappedLine::UnwrappedLine() : Level(0), InPPDirective(false),
- MustBeDeclaration(false), MatchingOpeningBlockLineIndex(kInvalidIndex) {}
+inline UnwrappedLine::UnwrappedLine()
+ : Level(0), InPPDirective(false), MustBeDeclaration(false),
+ MatchingOpeningBlockLineIndex(kInvalidIndex) {}
} // end namespace format
} // end namespace clang
diff --git a/lib/Format/UsingDeclarationsSorter.cpp b/lib/Format/UsingDeclarationsSorter.cpp
new file mode 100644
index 0000000000..d6753b545e
--- /dev/null
+++ b/lib/Format/UsingDeclarationsSorter.cpp
@@ -0,0 +1,156 @@
+//===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that
+/// sorts consecutive using declarations.
+///
+//===----------------------------------------------------------------------===//
+
+#include "UsingDeclarationsSorter.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Regex.h"
+
+#include <algorithm>
+
+#define DEBUG_TYPE "using-declarations-sorter"
+
+namespace clang {
+namespace format {
+
+namespace {
+
+struct UsingDeclaration {
+ const AnnotatedLine *Line;
+ std::string Label;
+
+ UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
+ : Line(Line), Label(Label) {}
+
+ bool operator<(const UsingDeclaration &Other) const {
+ return StringRef(Label).compare_lower(Other.Label) < 0;
+ }
+};
+
+/// Computes the label of a using declaration starting at tthe using token
+/// \p UsingTok.
+/// If \p UsingTok doesn't begin a using declaration, returns the empty string.
+/// Note that this detects specifically using declarations, as in:
+/// using A::B::C;
+/// and not type aliases, as in:
+/// using A = B::C;
+/// Type aliases are in general not safe to permute.
+std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
+ assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
+ std::string Label;
+ const FormatToken *Tok = UsingTok->Next;
+ if (Tok && Tok->is(tok::kw_typename)) {
+ Label.append("typename ");
+ Tok = Tok->Next;
+ }
+ if (Tok && Tok->is(tok::coloncolon)) {
+ Label.append("::");
+ Tok = Tok->Next;
+ }
+ bool HasIdentifier = false;
+ while (Tok && Tok->is(tok::identifier)) {
+ HasIdentifier = true;
+ Label.append(Tok->TokenText.str());
+ Tok = Tok->Next;
+ if (!Tok || Tok->isNot(tok::coloncolon))
+ break;
+ Label.append("::");
+ Tok = Tok->Next;
+ }
+ if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
+ return Label;
+ return "";
+}
+
+void endUsingDeclarationBlock(
+ SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
+ const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
+ bool BlockAffected = false;
+ for (const UsingDeclaration& Declaration : *UsingDeclarations) {
+ if (Declaration.Line->Affected) {
+ BlockAffected = true;
+ break;
+ }
+ }
+ if (!BlockAffected) {
+ UsingDeclarations->clear();
+ return;
+ }
+ SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
+ UsingDeclarations->begin(), UsingDeclarations->end());
+ std::stable_sort(SortedUsingDeclarations.begin(),
+ SortedUsingDeclarations.end());
+ for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
+ if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
+ continue;
+ auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
+ auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
+ auto SortedBegin =
+ SortedUsingDeclarations[I].Line->First->Tok.getLocation();
+ auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
+ StringRef Text(SourceMgr.getCharacterData(SortedBegin),
+ SourceMgr.getCharacterData(SortedEnd) -
+ SourceMgr.getCharacterData(SortedBegin));
+ DEBUG({
+ StringRef OldText(SourceMgr.getCharacterData(Begin),
+ SourceMgr.getCharacterData(End) -
+ SourceMgr.getCharacterData(Begin));
+ llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
+ });
+ auto Range = CharSourceRange::getCharRange(Begin, End);
+ auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
+ if (Err) {
+ llvm::errs() << "Error while sorting using declarations: "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
+ UsingDeclarations->clear();
+}
+
+} // namespace
+
+UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
+ const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
+ TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) {
+ const SourceManager &SourceMgr = Env.getSourceManager();
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
+ AnnotatedLines.end());
+ tooling::Replacements Fixes;
+ SmallVector<UsingDeclaration, 4> UsingDeclarations;
+ for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
+ if (AnnotatedLines[I]->InPPDirective ||
+ !AnnotatedLines[I]->startsWith(tok::kw_using) ||
+ AnnotatedLines[I]->First->Finalized) {
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ continue;
+ }
+ if (AnnotatedLines[I]->First->NewlinesBefore > 1)
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
+ if (Label.empty()) {
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ continue;
+ }
+ UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
+ }
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ return {Fixes, 0};
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/UsingDeclarationsSorter.h b/lib/Format/UsingDeclarationsSorter.h
new file mode 100644
index 0000000000..6f137712d8
--- /dev/null
+++ b/lib/Format/UsingDeclarationsSorter.h
@@ -0,0 +1,37 @@
+//===--- UsingDeclarationsSorter.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file declares UsingDeclarationsSorter, a TokenAnalyzer that
+/// sorts consecutive using declarations.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H
+#define LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H
+
+#include "TokenAnalyzer.h"
+
+namespace clang {
+namespace format {
+
+class UsingDeclarationsSorter : public TokenAnalyzer {
+public:
+ UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style);
+
+ std::pair<tooling::Replacements, unsigned>
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 93a2e490c6..a5477a9963 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -50,9 +50,9 @@ void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
if (Tok.Finalized)
return;
Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
- Changes.push_back(Change(Tok, /*CreateReplacement=*/true,
- Tok.WhitespaceRange, Spaces, StartOfTokenColumn,
- Newlines, "", "", InPPDirective && !Tok.IsFirst,
+ Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange,
+ Spaces, StartOfTokenColumn, Newlines, "", "",
+ InPPDirective && !Tok.IsFirst,
/*IsInsideToken=*/false));
}
@@ -67,6 +67,11 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
/*IsInsideToken=*/false));
}
+llvm::Error
+WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) {
+ return Replaces.add(Replacement);
+}
+
void WhitespaceManager::replaceWhitespaceInToken(
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
@@ -100,18 +105,56 @@ void WhitespaceManager::calculateLineBreakInformation() {
Changes[0].PreviousEndOfTokenColumn = 0;
Change *LastOutsideTokenChange = &Changes[0];
for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
- unsigned OriginalWhitespaceStart =
- SourceMgr.getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
- unsigned PreviousOriginalWhitespaceEnd = SourceMgr.getFileOffset(
- Changes[i - 1].OriginalWhitespaceRange.getEnd());
- Changes[i - 1].TokenLength = OriginalWhitespaceStart -
- PreviousOriginalWhitespaceEnd +
- Changes[i].PreviousLinePostfix.size() +
- Changes[i - 1].CurrentLinePrefix.size();
+ SourceLocation OriginalWhitespaceStart =
+ Changes[i].OriginalWhitespaceRange.getBegin();
+ SourceLocation PreviousOriginalWhitespaceEnd =
+ Changes[i - 1].OriginalWhitespaceRange.getEnd();
+ unsigned OriginalWhitespaceStartOffset =
+ SourceMgr.getFileOffset(OriginalWhitespaceStart);
+ unsigned PreviousOriginalWhitespaceEndOffset =
+ SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
+ assert(PreviousOriginalWhitespaceEndOffset <=
+ OriginalWhitespaceStartOffset);
+ const char *const PreviousOriginalWhitespaceEndData =
+ SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
+ StringRef Text(PreviousOriginalWhitespaceEndData,
+ SourceMgr.getCharacterData(OriginalWhitespaceStart) -
+ PreviousOriginalWhitespaceEndData);
+ // Usually consecutive changes would occur in consecutive tokens. This is
+ // not the case however when analyzing some preprocessor runs of the
+ // annotated lines. For example, in this code:
+ //
+ // #if A // line 1
+ // int i = 1;
+ // #else B // line 2
+ // int i = 2;
+ // #endif // line 3
+ //
+ // one of the runs will produce the sequence of lines marked with line 1, 2
+ // and 3. So the two consecutive whitespace changes just before '// line 2'
+ // and before '#endif // line 3' span multiple lines and tokens:
+ //
+ // #else B{change X}[// line 2
+ // int i = 2;
+ // ]{change Y}#endif // line 3
+ //
+ // For this reason, if the text between consecutive changes spans multiple
+ // newlines, the token length must be adjusted to the end of the original
+ // line of the token.
+ auto NewlinePos = Text.find_first_of('\n');
+ if (NewlinePos == StringRef::npos) {
+ Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
+ PreviousOriginalWhitespaceEndOffset +
+ Changes[i].PreviousLinePostfix.size() +
+ Changes[i - 1].CurrentLinePrefix.size();
+ } else {
+ Changes[i - 1].TokenLength =
+ NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
+ }
// If there are multiple changes in this token, sum up all the changes until
// the end of the line.
- if (Changes[i - 1].IsInsideToken)
+ if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0)
LastOutsideTokenChange->TokenLength +=
Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
else
@@ -128,15 +171,15 @@ void WhitespaceManager::calculateLineBreakInformation() {
// 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
//
@@ -192,21 +235,56 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
SmallVector<WhitespaceManager::Change, 16> &Changes) {
bool FoundMatchOnLine = false;
int Shift = 0;
+
+ // ScopeStack keeps track of the current scope depth. It contains indices of
+ // the first token on each scope.
+ // We only run the "Matches" function on tokens from the outer-most scope.
+ // However, we do need to pay special attention to one class of tokens
+ // that are not in the outer-most scope, and that is function parameters
+ // which are split across multiple lines, as illustrated by this example:
+ // double a(int x);
+ // int b(int y,
+ // double z);
+ // In the above example, we need to take special care to ensure that
+ // 'double z' is indented along with it's owning function 'b'.
+ SmallVector<unsigned, 16> ScopeStack;
+
for (unsigned i = Start; i != End; ++i) {
- if (Changes[i].NewlinesBefore > 0) {
- FoundMatchOnLine = false;
+ if (ScopeStack.size() != 0 &&
+ Changes[i].indentAndNestingLevel() <
+ Changes[ScopeStack.back()].indentAndNestingLevel())
+ ScopeStack.pop_back();
+
+ if (i != Start && Changes[i].indentAndNestingLevel() >
+ Changes[i - 1].indentAndNestingLevel())
+ ScopeStack.push_back(i);
+
+ bool InsideNestedScope = ScopeStack.size() != 0;
+
+ if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
Shift = 0;
+ FoundMatchOnLine = false;
}
// If this is the first matching token to be aligned, remember by how many
// spaces it has to be shifted, so the rest of the changes on the line are
// shifted by the same amount
- if (!FoundMatchOnLine && Matches(Changes[i])) {
+ if (!FoundMatchOnLine && !InsideNestedScope && Matches(Changes[i])) {
FoundMatchOnLine = true;
Shift = Column - Changes[i].StartOfTokenColumn;
Changes[i].Spaces += Shift;
}
+ // This is for function parameters that are split across multiple lines,
+ // as mentioned in the ScopeStack comment.
+ if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
+ unsigned ScopeStart = ScopeStack.back();
+ if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
+ (ScopeStart > Start + 1 &&
+ Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
+ Changes[i].Spaces += Shift;
+ }
+
assert(Shift >= 0);
Changes[i].StartOfTokenColumn += Shift;
if (i + 1 != Changes.size())
@@ -214,15 +292,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;
@@ -230,14 +330,11 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
unsigned StartOfSequence = 0;
unsigned EndOfSequence = 0;
- // Keep track of the nesting level of matching tokens, i.e. the number of
- // surrounding (), [], or {}. We will only align a sequence of matching
- // token that share the same scope depth.
- //
- // FIXME: This could use FormatToken::NestingLevel information, but there is
- // an outstanding issue wrt the brace scopes.
- unsigned NestingLevelOfLastMatch = 0;
- unsigned NestingLevel = 0;
+ // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
+ // abort when we hit any token in a higher scope than the starting one.
+ auto IndentAndNestingLevel = StartAt < Changes.size()
+ ? Changes[StartAt].indentAndNestingLevel()
+ : std::pair<unsigned, unsigned>(0, 0);
// Keep track of the number of commas before the matching tokens, we will only
// align a sequence of matching tokens if they are preceded by the same number
@@ -265,7 +362,11 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
EndOfSequence = 0;
};
- for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+ unsigned i = StartAt;
+ for (unsigned e = Changes.size(); i != e; ++i) {
+ if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
+ break;
+
if (Changes[i].NewlinesBefore != 0) {
CommasBeforeMatch = 0;
EndOfSequence = i;
@@ -279,29 +380,22 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
if (Changes[i].Tok->is(tok::comma)) {
++CommasBeforeMatch;
- } else if (Changes[i].Tok->isOneOf(tok::r_brace, tok::r_paren,
- tok::r_square)) {
- --NestingLevel;
- } else if (Changes[i].Tok->isOneOf(tok::l_brace, tok::l_paren,
- tok::l_square)) {
- // We want sequences to skip over child scopes if possible, but not the
- // other way around.
- NestingLevelOfLastMatch = std::min(NestingLevelOfLastMatch, NestingLevel);
- ++NestingLevel;
+ } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
+ // Call AlignTokens recursively, skipping over this scope block.
+ unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
+ i = StoppedAt - 1;
+ continue;
}
if (!Matches(Changes[i]))
continue;
// If there is more than one matching token per line, or if the number of
- // preceding commas, or the scope depth, do not match anymore, end the
- // sequence.
- if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch ||
- NestingLevel != NestingLevelOfLastMatch)
+ // preceding commas, do not match anymore, end the sequence.
+ if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
AlignCurrentSequence();
CommasBeforeLastMatch = CommasBeforeMatch;
- NestingLevelOfLastMatch = NestingLevel;
FoundMatchOnLine = true;
if (StartOfSequence == 0)
@@ -324,8 +418,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() {
@@ -344,7 +439,7 @@ void WhitespaceManager::alignConsecutiveAssignments() {
return C.Tok->is(tok::equal);
},
- Changes);
+ Changes, /*StartAt=*/0);
}
void WhitespaceManager::alignConsecutiveDeclarations() {
@@ -357,13 +452,15 @@ void WhitespaceManager::alignConsecutiveDeclarations() {
// const char* const* v1;
// float const* v2;
// SomeVeryLongType const& v3;
-
AlignTokens(Style,
[](Change const &C) {
- return C.Tok->isOneOf(TT_StartOfName,
- TT_FunctionDeclarationName);
+ // 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);
+ Changes, /*StartAt=*/0);
}
void WhitespaceManager::alignTrailingComments() {
@@ -380,7 +477,14 @@ void WhitespaceManager::alignTrailingComments() {
continue;
unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
- unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+ unsigned ChangeMaxColumn;
+
+ if (Style.ColumnLimit == 0)
+ ChangeMaxColumn = UINT_MAX;
+ else if (Style.ColumnLimit >= Changes[i].TokenLength)
+ ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+ else
+ ChangeMaxColumn = ChangeMinColumn;
// If we don't create a replacement for this change, we have to consider
// it to be immovable.
@@ -463,8 +567,11 @@ void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
}
void WhitespaceManager::alignEscapedNewlines() {
- unsigned MaxEndOfLine =
- Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
+ if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign)
+ return;
+
+ bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left;
+ unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
unsigned StartOfMacro = 0;
for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
Change &C = Changes[i];
@@ -473,7 +580,7 @@ void WhitespaceManager::alignEscapedNewlines() {
MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
} else {
alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
- MaxEndOfLine = Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
+ MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
StartOfMacro = i;
}
}
@@ -506,8 +613,9 @@ void WhitespaceManager::generateChanges() {
if (C.CreateReplacement) {
std::string ReplacementText = C.PreviousLinePostfix;
if (C.ContinuesPPDirective)
- appendNewlineText(ReplacementText, C.NewlinesBefore,
- C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
+ appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,
+ C.PreviousEndOfTokenColumn,
+ C.EscapedNewlineColumn);
else
appendNewlineText(ReplacementText, C.NewlinesBefore);
appendIndentText(ReplacementText, C.Tok->IndentLevel,
@@ -519,8 +627,7 @@ void WhitespaceManager::generateChanges() {
}
}
-void WhitespaceManager::storeReplacement(SourceRange Range,
- StringRef Text) {
+void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {
unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
SourceMgr.getFileOffset(Range.getBegin());
// Don't create a replacement, if it does not change anything.
@@ -543,16 +650,16 @@ void WhitespaceManager::appendNewlineText(std::string &Text,
Text.append(UseCRLF ? "\r\n" : "\n");
}
-void WhitespaceManager::appendNewlineText(std::string &Text, unsigned Newlines,
- unsigned PreviousEndOfTokenColumn,
- unsigned EscapedNewlineColumn) {
+void WhitespaceManager::appendEscapedNewlineText(
+ std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,
+ unsigned EscapedNewlineColumn) {
if (Newlines > 0) {
- unsigned Offset =
- std::min<int>(EscapedNewlineColumn - 1, PreviousEndOfTokenColumn);
+ unsigned Spaces =
+ std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);
for (unsigned i = 0; i < Newlines; ++i) {
- Text.append(EscapedNewlineColumn - Offset - 1, ' ');
+ Text.append(Spaces, ' ');
Text.append(UseCRLF ? "\\\r\n" : "\\\n");
- Offset = 0;
+ Spaces = std::max<int>(0, EscapedNewlineColumn - 1);
}
}
}
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index 0a2a031dd6..af20dc5616 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -43,6 +43,10 @@ public:
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
/// each \c AnnotatedToken.
+ ///
+ /// \p StartOfTokenColumn is the column at which the token will start after
+ /// this replacement. It is needed for determining how \p Spaces is turned
+ /// into tabs and spaces for some format styles.
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
unsigned StartOfTokenColumn,
bool InPPDirective = false);
@@ -53,6 +57,8 @@ public:
/// was not called.
void addUntouchableToken(const FormatToken &Tok, bool InPPDirective);
+ llvm::Error addReplacement(const tooling::Replacement &Replacement);
+
/// \brief Inserts or replaces whitespace in the middle of a token.
///
/// Inserts \p PreviousPostfix, \p Newlines, \p Spaces and \p CurrentPrefix
@@ -149,6 +155,13 @@ public:
// the alignment process.
const Change *StartOfBlockComment;
int IndentationOffset;
+
+ // A combination of indent level and nesting level, which are used in
+ // tandem to compute lexical scope, for the purposes of deciding
+ // when to stop consecutive alignment runs.
+ std::pair<unsigned, unsigned> indentAndNestingLevel() const {
+ return std::make_pair(Tok->IndentLevel, Tok->NestingLevel);
+ }
};
private:
@@ -183,9 +196,9 @@ private:
/// \brief Stores \p Text as the replacement for the whitespace in \p Range.
void storeReplacement(SourceRange Range, StringRef Text);
void appendNewlineText(std::string &Text, unsigned Newlines);
- void appendNewlineText(std::string &Text, unsigned Newlines,
- unsigned PreviousEndOfTokenColumn,
- unsigned EscapedNewlineColumn);
+ void appendEscapedNewlineText(std::string &Text, unsigned Newlines,
+ unsigned PreviousEndOfTokenColumn,
+ unsigned EscapedNewlineColumn);
void appendIndentText(std::string &Text, unsigned IndentLevel,
unsigned Spaces, unsigned WhitespaceStartColumn);
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 720baa5e0f..7dc475e26f 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -142,7 +142,7 @@ std::unique_ptr<ASTConsumer> clang::CreateASTDumper(StringRef FilterString,
bool DumpDecls,
bool Deserialize,
bool DumpLookups) {
- assert((DumpDecls || DumpLookups) && "nothing to dump");
+ assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
return llvm::make_unique<ASTPrinter>(nullptr,
Deserialize ? ASTPrinter::DumpFull :
DumpDecls ? ASTPrinter::Dump :
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index 51064da270..354527db7b 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -21,14 +21,13 @@ ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return AdaptedAction->CreateASTConsumer(CI, InFile);
}
-bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI) {
// FIXME: This is a hack. We need a better way to communicate the
// AST file, compiler instance, and file name than member variables
// of FrontendAction.
AdaptedAction->setCurrentInput(getCurrentInput(), takeCurrentASTUnit());
AdaptedAction->setCompilerInstance(&CI);
- return AdaptedAction->BeginSourceFileAction(CI, Filename);
+ return AdaptedAction->BeginSourceFileAction(CI);
}
void ASTMergeAction::ExecuteAction() {
@@ -45,9 +44,9 @@ void ASTMergeAction::ExecuteAction() {
new ForwardingDiagnosticConsumer(
*CI.getDiagnostics().getClient()),
/*ShouldOwnClient=*/true));
- std::unique_ptr<ASTUnit> Unit =
- ASTUnit::LoadFromASTFile(ASTFiles[I], CI.getPCHContainerReader(),
- Diags, CI.getFileSystemOpts(), false);
+ std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
+ ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+ CI.getFileSystemOpts(), false);
if (!Unit)
continue;
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index ac5c7ca3be..9eeec37a75 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"
@@ -78,106 +79,83 @@ namespace {
}
}
};
-
- struct OnDiskData {
- /// \brief The file in which the precompiled preamble is stored.
- std::string PreambleFile;
-
- /// \brief Temporary files that should be removed when the ASTUnit is
- /// destroyed.
- SmallVector<std::string, 4> TemporaryFiles;
-
- /// \brief Erase temporary files.
- void CleanTemporaryFiles();
-
- /// \brief Erase the preamble file.
- void CleanPreambleFile();
-
- /// \brief Erase temporary files and the preamble file.
- void Cleanup();
- };
-}
-
-static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
- static llvm::sys::SmartMutex<false> M(/* recursive = */ true);
- return M;
-}
-
-static void cleanupOnDiskMapAtExit();
-typedef llvm::DenseMap<const ASTUnit *,
- std::unique_ptr<OnDiskData>> OnDiskDataMap;
-static OnDiskDataMap &getOnDiskDataMap() {
- static OnDiskDataMap M;
- static bool hasRegisteredAtExit = false;
- if (!hasRegisteredAtExit) {
- hasRegisteredAtExit = true;
- atexit(cleanupOnDiskMapAtExit);
+ template <class T>
+ std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) {
+ if (!Val)
+ return nullptr;
+ return std::move(*Val);
}
- return M;
-}
-static void cleanupOnDiskMapAtExit() {
- // Use the mutex because there can be an alive thread destroying an ASTUnit.
- llvm::MutexGuard Guard(getOnDiskMutex());
- for (const auto &I : getOnDiskDataMap()) {
- // We don't worry about freeing the memory associated with OnDiskDataMap.
- // All we care about is erasing stale files.
- I.second->Cleanup();
+ template <class T>
+ bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
+ if (!Val)
+ return false;
+ Output = std::move(*Val);
+ return true;
}
-}
-static OnDiskData &getOnDiskData(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- auto &D = M[AU];
- if (!D)
- D = llvm::make_unique<OnDiskData>();
- return *D;
-}
-
-static void erasePreambleFile(const ASTUnit *AU) {
- getOnDiskData(AU).CleanPreambleFile();
-}
+/// \brief Get a source buffer for \p MainFilePath, handling all file-to-file
+/// and file-to-buffer remappings inside \p Invocation.
+static std::unique_ptr<llvm::MemoryBuffer>
+getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation,
+ vfs::FileSystem *VFS,
+ StringRef FilePath) {
+ const auto &PreprocessorOpts = Invocation.getPreprocessorOpts();
-static void removeOnDiskEntry(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- OnDiskDataMap::iterator I = M.find(AU);
- if (I != M.end()) {
- I->second->Cleanup();
- M.erase(I);
- }
-}
-
-static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) {
- getOnDiskData(AU).PreambleFile = preambleFile;
-}
+ // Try to determine if the main file has been remapped, either from the
+ // command line (to another file) or directly through the compiler
+ // invocation (to a memory buffer).
+ llvm::MemoryBuffer *Buffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
+ auto FileStatus = VFS->status(FilePath);
+ if (FileStatus) {
+ llvm::sys::fs::UniqueID MainFileID = FileStatus->getUniqueID();
-static const std::string &getPreambleFile(const ASTUnit *AU) {
- return getOnDiskData(AU).PreambleFile;
-}
+ // Check whether there is a file-file remapping of the main file
+ for (const auto &RF : PreprocessorOpts.RemappedFiles) {
+ std::string MPath(RF.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping. Try to load the resulting, remapped source.
+ BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second));
+ if (!BufferOwner)
+ return nullptr;
+ }
+ }
+ }
-void OnDiskData::CleanTemporaryFiles() {
- for (StringRef File : TemporaryFiles)
- llvm::sys::fs::remove(File);
- TemporaryFiles.clear();
-}
+ // Check whether there is a file-buffer remapping. It supercedes the
+ // file-file remapping.
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ std::string MPath(RB.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping.
+ BufferOwner.reset();
+ Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
+ }
+ }
+ }
+ }
-void OnDiskData::CleanPreambleFile() {
- if (!PreambleFile.empty()) {
- llvm::sys::fs::remove(PreambleFile);
- PreambleFile.clear();
+ // If the main source file was not remapped, load it now.
+ if (!Buffer && !BufferOwner) {
+ BufferOwner = valueOrNull(VFS->getBufferForFile(FilePath));
+ if (!BufferOwner)
+ return nullptr;
}
-}
-void OnDiskData::Cleanup() {
- CleanTemporaryFiles();
- CleanPreambleFile();
+ if (BufferOwner)
+ return BufferOwner;
+ if (!Buffer)
+ return nullptr;
+ return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath);
+}
}
struct ASTUnit::ASTWriterData {
@@ -185,21 +163,14 @@ struct ASTUnit::ASTWriterData {
llvm::BitstreamWriter Stream;
ASTWriter Writer;
- ASTWriterData() : Stream(Buffer), Writer(Stream, Buffer, {}) {}
+ ASTWriterData(MemoryBufferCache &PCMCache)
+ : Stream(Buffer), Writer(Stream, Buffer, PCMCache, {}) {}
};
void ASTUnit::clearFileLevelDecls() {
llvm::DeleteContainerSeconds(FileDecls);
}
-void ASTUnit::CleanTemporaryFiles() {
- getOnDiskData(this).CleanTemporaryFiles();
-}
-
-void ASTUnit::addTemporaryFile(StringRef TempFile) {
- getOnDiskData(this).TemporaryFiles.push_back(TempFile);
-}
-
/// \brief After failing to build a precompiled preamble (due to
/// errors in the source that occurs in the preamble), the number of
/// reparses during which we'll skip even trying to precompile the
@@ -238,9 +209,6 @@ ASTUnit::~ASTUnit() {
clearFileLevelDecls();
- // Clean up the temporary files and the preamble file.
- removeOnDiskEntry(this);
-
// Free the buffers associated with remapped files. We are required to
// perform this operation here because we explicitly request that the
// compiler instance *not* free these buffers for each invocation of the
@@ -275,7 +243,8 @@ static unsigned getDeclShowContexts(const NamedDecl *ND,
uint64_t Contexts = 0;
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) ||
- isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) {
+ isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND) ||
+ isa<TypeAliasTemplateDecl>(ND)) {
// Types can appear in these contexts.
if (LangOpts.CPlusPlus || !isa<TagDecl>(ND))
Contexts |= (1LL << CodeCompletionContext::CCC_TopLevel)
@@ -490,7 +459,9 @@ namespace {
/// a Preprocessor.
class ASTInfoCollector : public ASTReaderListener {
Preprocessor &PP;
- ASTContext &Context;
+ ASTContext *Context;
+ HeaderSearchOptions &HSOpts;
+ PreprocessorOptions &PPOpts;
LangOptions &LangOpt;
std::shared_ptr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
@@ -498,11 +469,14 @@ class ASTInfoCollector : public ASTReaderListener {
bool InitializedLanguage;
public:
- ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
+ ASTInfoCollector(Preprocessor &PP, ASTContext *Context,
+ HeaderSearchOptions &HSOpts, PreprocessorOptions &PPOpts,
+ LangOptions &LangOpt,
std::shared_ptr<TargetOptions> &TargetOpts,
IntrusiveRefCntPtr<TargetInfo> &Target, unsigned &Counter)
- : PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts),
- Target(Target), Counter(Counter), InitializedLanguage(false) {}
+ : PP(PP), Context(Context), HSOpts(HSOpts), PPOpts(PPOpts),
+ LangOpt(LangOpt), TargetOpts(TargetOpts), Target(Target),
+ Counter(Counter), InitializedLanguage(false) {}
bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
bool AllowCompatibleDifferences) override {
@@ -516,6 +490,20 @@ public:
return false;
}
+ virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ StringRef SpecificModuleCachePath,
+ bool Complain) override {
+ this->HSOpts = HSOpts;
+ return false;
+ }
+
+ virtual bool
+ ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain,
+ std::string &SuggestedPredefines) override {
+ this->PPOpts = PPOpts;
+ return false;
+ }
+
bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
bool AllowCompatibleDifferences) override {
// If we've already initialized the target, don't do it again.
@@ -549,28 +537,42 @@ private:
// Initialize the preprocessor.
PP.Initialize(*Target);
+ if (!Context)
+ return;
+
// Initialize the ASTContext
- Context.InitBuiltinTypes(*Target);
+ Context->InitBuiltinTypes(*Target);
+
+ // Adjust printing policy based on language options.
+ Context->setPrintingPolicy(PrintingPolicy(LangOpt));
// We didn't have access to the comment options when the ASTContext was
// constructed, so register them now.
- Context.getCommentCommandTraits().registerCommentOptions(
+ Context->getCommentCommandTraits().registerCommentOptions(
LangOpt.CommentOpts);
}
};
/// \brief Diagnostic consumer that saves each diagnostic it is given.
class StoredDiagnosticConsumer : public DiagnosticConsumer {
- SmallVectorImpl<StoredDiagnostic> &StoredDiags;
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags;
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags;
+ const LangOptions *LangOpts;
SourceManager *SourceMgr;
public:
- explicit StoredDiagnosticConsumer(
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : StoredDiags(StoredDiags), SourceMgr(nullptr) {}
+ StoredDiagnosticConsumer(
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags),
+ LangOpts(nullptr), SourceMgr(nullptr) {
+ assert((StoredDiags || StandaloneDiags) &&
+ "No output collections were passed to StoredDiagnosticConsumer.");
+ }
void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP = nullptr) override {
+ this->LangOpts = &LangOpts;
if (PP)
SourceMgr = &PP->getSourceManager();
}
@@ -589,8 +591,9 @@ class CaptureDroppedDiagnostics {
public:
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr)
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : Diags(Diags), Client(StoredDiags, StandaloneDiags), PreviousClient(nullptr)
{
if (RequestCapture || Diags.getClient() == nullptr) {
OwningPreviousClient = Diags.takeClient();
@@ -607,16 +610,35 @@ public:
} // anonymous namespace
+static ASTUnit::StandaloneDiagnostic
+makeStandaloneDiagnostic(const LangOptions &LangOpts,
+ const StoredDiagnostic &InDiag);
+
void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
- const Diagnostic &Info) {
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
DiagnosticConsumer::HandleDiagnostic(Level, Info);
// Only record the diagnostic if it's part of the source manager we know
// about. This effectively drops diagnostics from modules we're building.
// FIXME: In the long run, ee don't want to drop source managers from modules.
- if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr)
- StoredDiags.emplace_back(Level, Info);
+ if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) {
+ StoredDiagnostic *ResultDiag = nullptr;
+ if (StoredDiags) {
+ StoredDiags->emplace_back(Level, Info);
+ ResultDiag = &StoredDiags->back();
+ }
+
+ if (StandaloneDiags) {
+ llvm::Optional<StoredDiagnostic> StoredDiag = llvm::None;
+ if (!ResultDiag) {
+ StoredDiag.emplace(Level, Info);
+ ResultDiag = StoredDiag.getPointer();
+ }
+ StandaloneDiags->push_back(
+ makeStandaloneDiagnostic(*LangOpts, *ResultDiag));
+ }
+ }
}
IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
@@ -651,12 +673,12 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
if (CaptureDiagnostics)
- Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
+ Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr));
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts, bool UseDebugInfo,
bool OnlyLocalDecls, ArrayRef<RemappedFile> RemappedFiles,
bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors,
@@ -672,6 +694,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+ AST->LangOpts = std::make_shared<LangOptions>();
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
@@ -681,18 +704,18 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager(),
UserFilesAreVolatile);
+ AST->PCMCache = new MemoryBufferCache;
AST->HSOpts = std::make_shared<HeaderSearchOptions>();
AST->HSOpts->ModuleFormat = PCHContainerRdr.getFormat();
AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
AST->getSourceManager(),
AST->getDiagnostics(),
- AST->ASTFileLangOpts,
+ AST->getLangOpts(),
/*Target=*/nullptr));
-
- auto PPOpts = std::make_shared<PreprocessorOptions>();
+ AST->PPOpts = std::make_shared<PreprocessorOptions>();
for (const auto &RemappedFile : RemappedFiles)
- PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second);
+ AST->PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second);
// Gather Info for preprocessor construction later on.
@@ -700,35 +723,36 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
unsigned Counter;
AST->PP = std::make_shared<Preprocessor>(
- std::move(PPOpts), AST->getDiagnostics(), AST->ASTFileLangOpts,
- AST->getSourceManager(), HeaderInfo, *AST,
+ AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts,
+ AST->getSourceManager(), *AST->PCMCache, HeaderInfo, AST->ModuleLoader,
/*IILookup=*/nullptr,
/*OwnsHeaderSearch=*/false);
Preprocessor &PP = *AST->PP;
- AST->Ctx = new ASTContext(AST->ASTFileLangOpts, AST->getSourceManager(),
- PP.getIdentifierTable(), PP.getSelectorTable(),
- PP.getBuiltinInfo());
- ASTContext &Context = *AST->Ctx;
+ if (ToLoad >= LoadASTOnly)
+ AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(),
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ PP.getBuiltinInfo());
bool disableValid = false;
if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
disableValid = true;
- AST->Reader = new ASTReader(PP, Context, PCHContainerRdr, { },
+ AST->Reader = new ASTReader(PP, AST->Ctx.get(), PCHContainerRdr, { },
/*isysroot=*/"",
/*DisableValidation=*/disableValid,
AllowPCHWithCompilerErrors);
AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>(
- *AST->PP, Context, AST->ASTFileLangOpts, AST->TargetOpts, AST->Target,
- Counter));
+ *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts,
+ AST->TargetOpts, AST->Target, Counter));
// Attach the AST reader to the AST context as an external AST
// source, so that declarations will be deserialized from the
// AST file as needed.
// We need the external source to be set up before we read the AST, because
// eagerly-deserialized declarations may use it.
- Context.setExternalSource(AST->Reader);
+ if (AST->Ctx)
+ AST->Ctx->setExternalSource(AST->Reader);
switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile,
SourceLocation(), ASTReader::ARR_None)) {
@@ -750,21 +774,29 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
PP.setCounterValue(Counter);
// Create an AST consumer, even though it isn't used.
- AST->Consumer.reset(new ASTConsumer);
-
+ if (ToLoad >= LoadASTOnly)
+ AST->Consumer.reset(new ASTConsumer);
+
// Create a semantic analysis object and tell the AST reader about it.
- AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
- AST->TheSema->Initialize();
- AST->Reader->InitializeSema(*AST->TheSema);
+ if (ToLoad >= LoadEverything) {
+ AST->TheSema.reset(new Sema(PP, *AST->Ctx, *AST->Consumer));
+ AST->TheSema->Initialize();
+ AST->Reader->InitializeSema(*AST->TheSema);
+ }
// Tell the diagnostic client that we have started a source file.
- AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP);
+ AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP);
return AST;
}
namespace {
+/// \brief Add the given macro to the hash of all top-level entities.
+void AddDefinedMacroToHash(const Token &MacroNameTok, unsigned &Hash) {
+ Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+}
+
/// \brief Preprocessor callback class that updates a hash value with the names
/// of all macros that have been defined by the translation unit.
class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
@@ -775,7 +807,7 @@ public:
void MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) override {
- Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
};
@@ -901,45 +933,27 @@ public:
}
};
-class PrecompilePreambleAction : public ASTFrontendAction {
- ASTUnit &Unit;
- bool HasEmittedPreamblePCH;
-
+class ASTUnitPreambleCallbacks : public PreambleCallbacks {
public:
- explicit PrecompilePreambleAction(ASTUnit &Unit)
- : Unit(Unit), HasEmittedPreamblePCH(false) {}
+ unsigned getHash() const { return Hash; }
- std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
- bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
- void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; }
- bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
+ std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
- bool hasCodeCompletionSupport() const override { return false; }
- bool hasASTFileSupport() const override { return false; }
- TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
-};
-
-class PrecompilePreambleConsumer : public PCHGenerator {
- ASTUnit &Unit;
- unsigned &Hash;
- std::vector<Decl *> TopLevelDecls;
- PrecompilePreambleAction *Action;
- std::unique_ptr<raw_ostream> Out;
+ std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
+ return std::move(TopLevelDeclIDs);
+ }
-public:
- PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action,
- const Preprocessor &PP, StringRef isysroot,
- std::unique_ptr<raw_ostream> Out)
- : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
- ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
- /*AllowASTWithErrors=*/true),
- Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action),
- Out(std::move(Out)) {
- Hash = 0;
+ void AfterPCHEmitted(ASTWriter &Writer) override {
+ TopLevelDeclIDs.reserve(TopLevelDecls.size());
+ for (Decl *D : TopLevelDecls) {
+ // Invalid top-level decls may not have been serialized.
+ if (D->isInvalidDecl())
+ continue;
+ TopLevelDeclIDs.push_back(Writer.getDeclID(D));
+ }
}
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ void HandleTopLevelDecl(DeclGroupRef DG) override {
for (Decl *D : DG) {
// FIXME: Currently ObjC method declarations are incorrectly being
// reported as top-level declarations, even though their DeclContext
@@ -950,59 +964,22 @@ public:
AddTopLevelDeclarationToHash(D, Hash);
TopLevelDecls.push_back(D);
}
- return true;
}
- void HandleTranslationUnit(ASTContext &Ctx) override {
- PCHGenerator::HandleTranslationUnit(Ctx);
- if (hasEmittedPCH()) {
- // Write the generated bitstream to "Out".
- *Out << getPCH();
- // Make sure it hits disk now.
- Out->flush();
- // Free the buffer.
- llvm::SmallVector<char, 0> Empty;
- getPCH() = std::move(Empty);
-
- // Translate the top-level declarations we captured during
- // parsing into declaration IDs in the precompiled
- // preamble. This will allow us to deserialize those top-level
- // declarations when requested.
- for (Decl *D : TopLevelDecls) {
- // Invalid top-level decls may not have been serialized.
- if (D->isInvalidDecl())
- continue;
- Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D));
- }
-
- Action->setHasEmittedPreamblePCH();
- }
+ void HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
+
+private:
+ unsigned Hash = 0;
+ std::vector<Decl *> TopLevelDecls;
+ std::vector<serialization::DeclID> TopLevelDeclIDs;
+ llvm::SmallVector<ASTUnit::StandaloneDiagnostic, 4> PreambleDiags;
};
} // anonymous namespace
-std::unique_ptr<ASTConsumer>
-PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- std::string Sysroot;
- std::string OutputFile;
- std::unique_ptr<raw_ostream> OS =
- GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
- OutputFile);
- if (!OS)
- return nullptr;
-
- if (!CI.getFrontendOpts().RelocatablePCH)
- Sysroot.clear();
-
- CI.getPreprocessor().addPPCallbacks(
- llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
- Unit.getCurrentTopLevelHashValue()));
- return llvm::make_unique<PrecompilePreambleConsumer>(
- Unit, this, CI.getPreprocessor(), Sysroot, std::move(OS));
-}
-
static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) {
return StoredDiag.getLocation().isValid();
}
@@ -1032,21 +1009,62 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
}
}
+static IntrusiveRefCntPtr<vfs::FileSystem> createVFSOverlayForPreamblePCH(
+ StringRef PCHFilename,
+ IntrusiveRefCntPtr<vfs::FileSystem> RealFS,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
+ // We want only the PCH file from the real filesystem to be available,
+ // so we create an in-memory VFS with just that and overlay it on top.
+ auto Buf = RealFS->getBufferForFile(PCHFilename);
+ if (!Buf)
+ return VFS;
+ IntrusiveRefCntPtr<vfs::InMemoryFileSystem>
+ PCHFS(new vfs::InMemoryFileSystem());
+ PCHFS->addFile(PCHFilename, 0, std::move(*Buf));
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem>
+ Overlay(new vfs::OverlayFileSystem(VFS));
+ Overlay->pushOverlay(PCHFS);
+ return Overlay;
+}
+
/// Parse the source file into a translation unit using the given compiler
/// invocation, replacing the current translation unit.
///
/// \returns True if a failure occurred that causes the ASTUnit not to
/// contain any translation-unit information, false otherwise.
bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) {
- SavedMainFileBuffer.reset();
-
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
// Create the compiler instance to use for building the AST.
std::unique_ptr<CompilerInstance> Clang(
new CompilerInstance(std::move(PCHContainerOps)));
+ if (FileMgr && VFS) {
+ assert(VFS == FileMgr->getVirtualFileSystem() &&
+ "VFS passed to Parse and VFS in FileMgr are different");
+ } else if (VFS) {
+ Clang->setVirtualFileSystem(VFS);
+ }
+
+ // Make sure we can access the PCH file even if we're using a VFS
+ if (!VFS && FileMgr)
+ VFS = FileMgr->getVirtualFileSystem();
+ IntrusiveRefCntPtr<vfs::FileSystem> RealFS = vfs::getRealFileSystem();
+ if (OverrideMainBuffer && VFS && RealFS && VFS != RealFS &&
+ !VFS->exists(Preamble->GetPCHPath())) {
+ // We have a slight inconsistency here -- we're using the VFS to
+ // read files, but the PCH was generated in the real file system.
+ VFS = createVFSOverlayForPreamblePCH(Preamble->GetPCHPath(), RealFS, VFS);
+ if (FileMgr) {
+ FileMgr = new FileManager(FileMgr->getFileSystemOpts(), VFS);
+ Clang->setFileManager(FileMgr.get());
+ }
+ else {
+ Clang->setVirtualFileSystem(VFS);
+ }
+ }
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -1073,9 +1091,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
@@ -1085,18 +1105,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
Clang->createFileManager();
FileMgr = &Clang->getFileManager();
}
- SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
- UserFilesAreVolatile);
- TheSema.reset();
- Ctx = nullptr;
- PP = nullptr;
- Reader = nullptr;
- // Clear out old caches and data.
- TopLevelDecls.clear();
- clearFileLevelDecls();
- CleanTemporaryFiles();
+ ResetForParse();
+ SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
+ UserFilesAreVolatile);
if (!OverrideMainBuffer) {
checkAndRemoveNonDriverDiags(StoredDiagnostics);
TopLevelDeclsInPreamble.clear();
@@ -1110,15 +1123,9 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
// The stored diagnostic has the old source manager in it; update
// the locations to refer into the new source manager. Since we've
@@ -1144,6 +1151,8 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
if (SavedMainFileBuffer)
TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
PreambleDiagnostics, StoredDiagnostics);
+ else
+ PreambleSrcLocCache.clear();
if (!Act->Execute())
goto error;
@@ -1169,111 +1178,6 @@ error:
return true;
}
-/// \brief Simple function to retrieve a path for a preamble precompiled header.
-static std::string GetPreamblePCHPath() {
- // FIXME: This is a hack so that we can override the preamble file during
- // crash-recovery testing, which is the only case where the preamble files
- // are not necessarily cleaned up.
- const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
- if (TmpFile)
- return TmpFile;
-
- SmallString<128> Path;
- llvm::sys::fs::createTemporaryFile("preamble", "pch", Path);
-
- return Path.str();
-}
-
-/// \brief Compute the preamble for the main file, providing the source buffer
-/// that corresponds to the main file along with a pair (bytes, start-of-line)
-/// that describes the preamble.
-ASTUnit::ComputedPreamble
-ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) {
- FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
-
- // Try to determine if the main file has been remapped, either from the
- // command line (to another file) or directly through the compiler invocation
- // (to a memory buffer).
- llvm::MemoryBuffer *Buffer = nullptr;
- std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
- std::string MainFilePath(FrontendOpts.Inputs[0].getFile());
- llvm::sys::fs::UniqueID MainFileID;
- if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) {
- // Check whether there is a file-file remapping of the main file
- for (const auto &RF : PreprocessorOpts.RemappedFiles) {
- std::string MPath(RF.first);
- llvm::sys::fs::UniqueID MID;
- if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
- if (MainFileID == MID) {
- // We found a remapping. Try to load the resulting, remapped source.
- BufferOwner = getBufferForFile(RF.second);
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
- }
- }
-
- // Check whether there is a file-buffer remapping. It supercedes the
- // file-file remapping.
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- std::string MPath(RB.first);
- llvm::sys::fs::UniqueID MID;
- if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
- if (MainFileID == MID) {
- // We found a remapping.
- BufferOwner.reset();
- Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
- }
- }
- }
- }
-
- // If the main source file was not remapped, load it now.
- if (!Buffer && !BufferOwner) {
- BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile());
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
-
- if (!Buffer)
- Buffer = BufferOwner.get();
- auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(),
- *Invocation.getLangOpts(), MaxLines);
- return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first,
- Pre.second);
-}
-
-ASTUnit::PreambleFileHash
-ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) {
- PreambleFileHash Result;
- Result.Size = Size;
- Result.ModTime = ModTime;
- memset(Result.MD5, 0, sizeof(Result.MD5));
- return Result;
-}
-
-ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer(
- const llvm::MemoryBuffer *Buffer) {
- PreambleFileHash Result;
- Result.Size = Buffer->getBufferSize();
- Result.ModTime = 0;
-
- llvm::MD5 MD5Ctx;
- MD5Ctx.update(Buffer->getBuffer().data());
- MD5Ctx.final(Result.MD5);
-
- return Result;
-}
-
-namespace clang {
-bool operator==(const ASTUnit::PreambleFileHash &LHS,
- const ASTUnit::PreambleFileHash &RHS) {
- return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
- memcmp(LHS.MD5, RHS.MD5, sizeof(LHS.MD5)) == 0;
-}
-} // namespace clang
-
static std::pair<unsigned, unsigned>
makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
const LangOptions &LangOpts) {
@@ -1342,135 +1246,44 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts,
std::unique_ptr<llvm::MemoryBuffer>
ASTUnit::getMainBufferWithPrecompiledPreamble(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild,
+ const CompilerInvocation &PreambleInvocationIn,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild,
unsigned MaxLines) {
- auto PreambleInvocation =
- std::make_shared<CompilerInvocation>(PreambleInvocationIn);
- FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts
- = PreambleInvocation->getPreprocessorOpts();
-
- ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines);
-
- if (!NewPreamble.Size) {
- // We couldn't find a preamble in the main source. Clear out the current
- // preamble, if we have one. It's obviously no good any more.
- Preamble.clear();
- erasePreambleFile(this);
-
- // The next time we actually see a preamble, precompile it.
- PreambleRebuildCounter = 1;
+ auto MainFilePath =
+ PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile();
+ std::unique_ptr<llvm::MemoryBuffer> MainFileBuffer =
+ getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(),
+ MainFilePath);
+ if (!MainFileBuffer)
return nullptr;
- }
-
- if (!Preamble.empty()) {
- // We've previously computed a preamble. Check whether we have the same
- // preamble now that we did before, and that there's enough space in
- // the main-file buffer within the precompiled preamble to fit the
- // new main file.
- if (Preamble.size() == NewPreamble.Size &&
- PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine &&
- memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Size) == 0) {
- // The preamble has not changed. We may be able to re-use the precompiled
- // preamble.
-
- // Check that none of the files used by the preamble have changed.
- bool AnyFileChanged = false;
-
- // First, make a record of those files that have been overridden via
- // remapping or unsaved_files.
- std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
- for (const auto &R : PreprocessorOpts.RemappedFiles) {
- if (AnyFileChanged)
- break;
-
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(R.second, Status)) {
- // If we can't stat the file we're remapping to, assume that something
- // horrible happened.
- AnyFileChanged = true;
- break;
- }
- OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
- Status.getSize(),
- llvm::sys::toTimeT(Status.getLastModificationTime()));
- }
+ PreambleBounds Bounds =
+ ComputePreambleBounds(*PreambleInvocationIn.getLangOpts(),
+ MainFileBuffer.get(), MaxLines);
+ if (!Bounds.Size)
+ return nullptr;
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- if (AnyFileChanged)
- break;
+ if (Preamble) {
+ if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
+ VFS.get())) {
+ // Okay! We can re-use the precompiled preamble.
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(RB.first, Status)) {
- AnyFileChanged = true;
- break;
- }
+ // Set the state of the diagnostic object to mimic its state
+ // after parsing the preamble.
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(),
+ PreambleInvocationIn.getDiagnosticOpts());
+ getDiagnostics().setNumWarnings(NumWarningsInPreamble);
- OverriddenFiles[Status.getUniqueID()] =
- PreambleFileHash::createForMemoryBuffer(RB.second);
- }
-
- // Check whether anything has changed.
- for (llvm::StringMap<PreambleFileHash>::iterator
- F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
- !AnyFileChanged && F != FEnd;
- ++F) {
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
- // If we can't stat the file, assume that something horrible happened.
- AnyFileChanged = true;
- break;
- }
-
- std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden
- = OverriddenFiles.find(Status.getUniqueID());
- if (Overridden != OverriddenFiles.end()) {
- // This file was remapped; check whether the newly-mapped file
- // matches up with the previous mapping.
- if (Overridden->second != F->second)
- AnyFileChanged = true;
- continue;
- }
-
- // The file was not remapped; check whether it has changed on disk.
- if (Status.getSize() != uint64_t(F->second.Size) ||
- llvm::sys::toTimeT(Status.getLastModificationTime()) !=
- F->second.ModTime)
- AnyFileChanged = true;
- }
-
- if (!AnyFileChanged) {
- // Okay! We can re-use the precompiled preamble.
-
- // Set the state of the diagnostic object to mimic its state
- // after parsing the preamble.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(),
- PreambleInvocation->getDiagnosticOpts());
- getDiagnostics().setNumWarnings(NumWarningsInPreamble);
-
- return llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile());
- }
+ PreambleRebuildCounter = 1;
+ return MainFileBuffer;
+ } else {
+ Preamble.reset();
+ PreambleDiagnostics.clear();
+ TopLevelDeclsInPreamble.clear();
+ PreambleRebuildCounter = 1;
}
-
- // If we aren't allowed to rebuild the precompiled preamble, just
- // return now.
- if (!AllowRebuild)
- return nullptr;
-
- // We can't reuse the previously-computed preamble. Build a new one.
- Preamble.clear();
- PreambleDiagnostics.clear();
- erasePreambleFile(this);
- PreambleRebuildCounter = 1;
- } else if (!AllowRebuild) {
- // We aren't allowed to rebuild the precompiled preamble; just
- // return now.
- return nullptr;
}
// If the preamble rebuild counter > 1, it's because we previously
@@ -1481,162 +1294,61 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
return nullptr;
}
- // Create a temporary file for the precompiled preamble. In rare
- // circumstances, this can fail.
- std::string PreamblePCHPath = GetPreamblePCHPath();
- if (PreamblePCHPath.empty()) {
- // Try again next time.
- PreambleRebuildCounter = 1;
- return nullptr;
- }
-
- // We did not previously compute a preamble, or it can't be reused anyway.
- SimpleTimer PreambleTimer(WantTiming);
- PreambleTimer.setOutput("Precompiling preamble");
-
- // Save the preamble text for later; we'll need to compare against it for
- // subsequent reparses.
- StringRef MainFilename = FrontendOpts.Inputs[0].getFile();
- Preamble.assign(FileMgr->getFile(MainFilename),
- NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Buffer->getBufferStart() + NewPreamble.Size);
- PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine;
-
- PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename);
-
- // Remap the main source file to the preamble buffer.
- StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
- PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get());
-
- // Tell the compiler invocation to generate a temporary precompiled header.
- FrontendOpts.ProgramAction = frontend::GeneratePCH;
- // FIXME: Generate the precompiled header into memory?
- FrontendOpts.OutputFile = PreamblePCHPath;
- PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
- PreprocessorOpts.PrecompiledPreambleBytes.second = false;
-
- // Create the compiler instance to use for building the precompiled preamble.
- std::unique_ptr<CompilerInstance> Clang(
- new CompilerInstance(std::move(PCHContainerOps)));
-
- // Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
- CICleanup(Clang.get());
-
- Clang->setInvocation(std::move(PreambleInvocation));
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
-
- // Set up diagnostics, capturing all of the diagnostics produced.
- Clang->setDiagnostics(&getDiagnostics());
-
- // Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(
- Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
- if (!Clang->hasTarget()) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // Inform the target of the language options.
- //
- // FIXME: We shouldn't need to do this, the target should be immutable once
- // created. This complexity should be lifted elsewhere.
- Clang->getTarget().adjust(Clang->getLangOpts());
-
- assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
- "Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
- "FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
- "IR inputs not support here!");
-
- // Clear out old caches and data.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts());
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
- TopLevelDecls.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleDiagnostics.clear();
-
- IntrusiveRefCntPtr<vfs::FileSystem> VFS =
- createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
- if (!VFS)
+ assert(!Preamble && "No Preamble should be stored at that point");
+ // If we aren't allowed to rebuild the precompiled preamble, just
+ // return now.
+ if (!AllowRebuild)
return nullptr;
- // Create a file manager object to provide access to and cache the filesystem.
- Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
-
- // Create the source manager.
- Clang->setSourceManager(new SourceManager(getDiagnostics(),
- Clang->getFileManager()));
-
- auto PreambleDepCollector = std::make_shared<DependencyCollector>();
- Clang->addDependencyCollector(PreambleDepCollector);
-
- std::unique_ptr<PrecompilePreambleAction> Act;
- Act.reset(new PrecompilePreambleAction(*this));
- if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
+ SmallVector<StandaloneDiagnostic, 4> NewPreambleDiagsStandalone;
+ SmallVector<StoredDiagnostic, 4> NewPreambleDiags;
+ ASTUnitPreambleCallbacks Callbacks;
+ {
+ llvm::Optional<CaptureDroppedDiagnostics> Capture;
+ if (CaptureDiagnostics)
+ Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags,
+ &NewPreambleDiagsStandalone);
+
+ // We did not previously compute a preamble, or it can't be reused anyway.
+ SimpleTimer PreambleTimer(WantTiming);
+ PreambleTimer.setOutput("Precompiling preamble");
+
+ llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build(
+ PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS,
+ PCHContainerOps, Callbacks);
+ if (NewPreamble) {
+ Preamble = std::move(*NewPreamble);
+ PreambleRebuildCounter = 1;
+ } else {
+ switch (static_cast<BuildPreambleError>(NewPreamble.getError().value())) {
+ case BuildPreambleError::CouldntCreateTempFile:
+ case BuildPreambleError::PreambleIsEmpty:
+ // Try again next time.
+ PreambleRebuildCounter = 1;
+ return nullptr;
+ case BuildPreambleError::CouldntCreateTargetInfo:
+ case BuildPreambleError::BeginSourceFileFailed:
+ case BuildPreambleError::CouldntEmitPCH:
+ case BuildPreambleError::CouldntCreateVFSOverlay:
+ // These erros are more likely to repeat, retry after some period.
+ PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+ return nullptr;
+ }
+ llvm_unreachable("unexpected BuildPreambleError");
+ }
}
-
- Act->Execute();
- // Transfer any diagnostics generated when parsing the preamble into the set
- // of preamble diagnostics.
- for (stored_diag_iterator I = stored_diag_afterDriver_begin(),
- E = stored_diag_end();
- I != E; ++I)
- PreambleDiagnostics.push_back(
- makeStandaloneDiagnostic(Clang->getLangOpts(), *I));
-
- Act->EndSourceFile();
+ assert(Preamble && "Preamble wasn't built");
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
+ TopLevelDecls.clear();
+ TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs();
+ PreambleTopLevelHashValue = Callbacks.getHash();
- if (!Act->hasEmittedPreamblePCH()) {
- // The preamble PCH failed (e.g. there was a module loading fatal error),
- // so no precompiled header was generated. Forget that we even tried.
- // FIXME: Should we leave a note for ourselves to try again?
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // Keep track of the preamble we precompiled.
- setPreambleFile(this, FrontendOpts.OutputFile);
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
-
- // Keep track of all of the files that the source manager knows about,
- // so we can verify whether they have changed or not.
- FilesInPreamble.clear();
- SourceManager &SourceMgr = Clang->getSourceManager();
- for (auto &Filename : PreambleDepCollector->getDependencies()) {
- const FileEntry *File = Clang->getFileManager().getFile(Filename);
- if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
- continue;
- if (time_t ModTime = File->getModificationTime()) {
- FilesInPreamble[File->getName()] = PreambleFileHash::createForFile(
- File->getSize(), ModTime);
- } else {
- llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
- FilesInPreamble[File->getName()] =
- PreambleFileHash::createForMemoryBuffer(Buffer);
- }
- }
- PreambleRebuildCounter = 1;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
+ checkAndRemoveNonDriverDiags(NewPreambleDiags);
+ StoredDiagnostics = std::move(NewPreambleDiags);
+ PreambleDiagnostics = std::move(NewPreambleDiagsStandalone);
// If the hash of top-level entities differs from the hash of the top-level
// entities the last time we rebuilt the preamble, clear out the completion
@@ -1646,11 +1358,12 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
PreambleTopLevelHashValue = CurrentTopLevelHashValue;
}
- return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(),
- MainFilename);
+ return MainFileBuffer;
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
+ assert(Preamble && "Should only be called when preamble was built");
+
std::vector<Decl *> Resolved;
Resolved.reserve(TopLevelDeclsInPreamble.size());
ExternalASTSource &Source = *getASTContext().getExternalSource();
@@ -1727,6 +1440,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;
}
@@ -1806,10 +1520,12 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
- "IR inputs not supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
+ "IR inputs not support here!");
// Configure the various subsystems.
AST->TheSema.reset();
@@ -1876,10 +1592,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
bool ASTUnit::LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- unsigned PrecompilePreambleAfterNParses) {
+ unsigned PrecompilePreambleAfterNParses,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
-
+
+ assert(VFS && "VFS is null");
+
// We'll manage file buffers ourselves.
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
Invocation->getFrontendOpts().DisableFree = false;
@@ -1890,19 +1609,19 @@ bool ASTUnit::LoadFromCompilerInvocation(
if (PrecompilePreambleAfterNParses > 0) {
PreambleRebuildCounter = PrecompilePreambleAfterNParses;
OverrideMainBuffer =
- getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
+ getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
getDiagnostics().Reset();
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
}
-
+
SimpleTimer ParsingTimer(WantTiming);
ParsingTimer.setOutput("Parsing " + getMainFileName());
-
+
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
MemBufferCleanup(OverrideMainBuffer.get());
- return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
+ return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
@@ -1936,7 +1655,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
DiagCleanup(Diags.get());
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
- PrecompilePreambleAfterNParses))
+ PrecompilePreambleAfterNParses,
+ AST->FileMgr->getVirtualFileSystem()))
return nullptr;
return AST;
}
@@ -1950,8 +1670,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
- bool UserFilesAreVolatile, bool ForSerialization,
- llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) {
+ bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization,
+ llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -1960,11 +1681,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
{
- CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
- StoredDiagnostics);
+ CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
+ &StoredDiagnostics, nullptr);
CI = clang::createInvocationFromCommandLine(
- llvm::makeArrayRef(ArgBegin, ArgEnd), Diags);
+ llvm::makeArrayRef(ArgBegin, ArgEnd), Diags, VFS);
if (!CI)
return nullptr;
}
@@ -1977,6 +1698,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
+ PPOpts.SingleFileParseMode = SingleFileParse;
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
@@ -1992,11 +1714,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->FileSystemOpts = CI->getFileSystemOpts();
- IntrusiveRefCntPtr<vfs::FileSystem> VFS =
- createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ VFS = vfs::getRealFileSystem();
+ VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
if (!VFS)
return nullptr;
AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
+ AST->PCMCache = new MemoryBufferCache;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->TUKind = TUKind;
@@ -2008,7 +1732,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;
@@ -2018,7 +1742,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
ASTUnitCleanup(AST.get());
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
- PrecompilePreambleAfterNParses)) {
+ PrecompilePreambleAfterNParses,
+ VFS)) {
// Some error occurred, if caller wants to examine diagnostics, pass it the
// ASTUnit.
if (ErrAST) {
@@ -2032,10 +1757,16 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
}
bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- ArrayRef<RemappedFile> RemappedFiles) {
+ ArrayRef<RemappedFile> RemappedFiles,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
+ if (!VFS) {
+ assert(FileMgr && "FileMgr is null on Reparse call");
+ VFS = FileMgr->getVirtualFileSystem();
+ }
+
clearFileLevelDecls();
SimpleTimer ParsingTimer(WantTiming);
@@ -2055,9 +1786,10 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
+ if (Preamble || PreambleRebuildCounter > 0)
OverrideMainBuffer =
- getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
+ getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+
// Clear out the diagnostics state.
FileMgr.reset();
@@ -2068,7 +1800,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// Parse the sources
bool Result =
- Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
+ Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
// If we're caching global code-completion results, and the top-level
// declarations have changed, clear out the code-completion cache.
@@ -2083,6 +1815,19 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
return Result;
}
+void ASTUnit::ResetForParse() {
+ SavedMainFileBuffer.reset();
+
+ SourceMgr.reset();
+ TheSema.reset();
+ Ctx.reset();
+ PP.reset();
+ Reader.reset();
+
+ TopLevelDecls.clear();
+ clearFileLevelDecls();
+}
+
//----------------------------------------------------------------------------//
// Code completion
//----------------------------------------------------------------------------//
@@ -2375,7 +2120,7 @@ void ASTUnit::CodeComplete(
Clang->setDiagnostics(&Diag);
CaptureDroppedDiagnostics Capture(true,
Clang->getDiagnostics(),
- StoredDiagnostics);
+ &StoredDiagnostics, nullptr);
ProcessWarningOptions(Diag, Inv.getDiagnosticOpts());
// Create the target instance.
@@ -2394,11 +2139,12 @@ void ASTUnit::CodeComplete(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
"IR inputs not support here!");
-
// Use the source and file managers that we were given.
Clang->setFileManager(&FileMgr);
@@ -2423,17 +2169,21 @@ void ASTUnit::CodeComplete(
// point is within the main file, after the end of the precompiled
// preamble.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty()) {
+ if (Preamble) {
std::string CompleteFilePath(File);
- llvm::sys::fs::UniqueID CompleteFileID;
- if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) {
+ auto VFS = FileMgr.getVirtualFileSystem();
+ auto CompleteFileStatus = VFS->status(CompleteFilePath);
+ if (CompleteFileStatus) {
+ llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID();
+
std::string MainPath(OriginalSourceFile);
- llvm::sys::fs::UniqueID MainID;
- if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) {
+ auto MainStatus = VFS->status(MainPath);
+ if (MainStatus) {
+ llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
if (CompleteFileID == MainID && Line > 1)
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
- PCHContainerOps, Inv, false, Line - 1);
+ PCHContainerOps, Inv, VFS, false, Line - 1);
}
}
}
@@ -2441,14 +2191,8 @@ void ASTUnit::CodeComplete(
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
-
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
OwnedBuffers.push_back(OverrideMainBuffer.release());
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
@@ -2523,7 +2267,8 @@ bool ASTUnit::serialize(raw_ostream &OS) {
SmallString<128> Buffer;
llvm::BitstreamWriter Stream(Buffer);
- ASTWriter Writer(Stream, Buffer, {});
+ MemoryBufferCache PCMCache;
+ ASTWriter Writer(Stream, Buffer, PCMCache, {});
return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS);
}
@@ -2538,11 +2283,9 @@ void ASTUnit::TranslateStoredDiagnostics(
// remap all the locations to the new view. This includes the diag location,
// any associated source ranges, and the source ranges of associated fix-its.
// FIXME: There should be a cleaner way to do this.
-
SmallVector<StoredDiagnostic, 4> Result;
Result.reserve(Diags.size());
- const FileEntry *PreviousFE = nullptr;
- FileID FID;
+
for (const StandaloneDiagnostic &SD : Diags) {
// Rebuild the StoredDiagnostic.
if (SD.Filename.empty())
@@ -2550,11 +2293,16 @@ void ASTUnit::TranslateStoredDiagnostics(
const FileEntry *FE = FileMgr.getFile(SD.Filename);
if (!FE)
continue;
- if (FE != PreviousFE) {
- FID = SrcMgr.translateFile(FE);
- PreviousFE = FE;
+ SourceLocation FileLoc;
+ auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
+ if (ItFileID == PreambleSrcLocCache.end()) {
+ FileID FID = SrcMgr.translateFile(FE);
+ FileLoc = SrcMgr.getLocForStartOfFile(FID);
+ PreambleSrcLocCache[SD.Filename] = FileLoc;
+ } else {
+ FileLoc = ItFileID->getValue();
}
- SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID);
+
if (FileLoc.isInvalid())
continue;
SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset);
@@ -2686,16 +2434,16 @@ SourceLocation ASTUnit::getLocation(const FileEntry *File,
/// \brief If \arg Loc is a loaded location from the preamble, returns
/// the corresponding local location of the main file, otherwise it returns
/// \arg Loc.
-SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) {
+SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) const {
FileID PreambleID;
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
- if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) {
+ if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc
= SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
return FileLoc.getLocWithOffset(Offs);
@@ -2707,17 +2455,17 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) {
/// \brief If \arg Loc is a local location of the main file but inside the
/// preamble chunk, returns the corresponding loaded location from the
/// preamble, otherwise it returns \arg Loc.
-SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
+SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) const {
FileID PreambleID;
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) &&
- Offs < Preamble.size()) {
+ Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID);
return FileLoc.getLocWithOffset(Offs);
}
@@ -2725,7 +2473,7 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
return Loc;
}
-bool ASTUnit::isInPreambleFileID(SourceLocation Loc) {
+bool ASTUnit::isInPreambleFileID(SourceLocation Loc) const {
FileID FID;
if (SourceMgr)
FID = SourceMgr->getPreambleFileID();
@@ -2736,7 +2484,7 @@ bool ASTUnit::isInPreambleFileID(SourceLocation Loc) {
return SourceMgr->isInFileID(Loc, FID);
}
-bool ASTUnit::isInMainFileID(SourceLocation Loc) {
+bool ASTUnit::isInMainFileID(SourceLocation Loc) const {
FileID FID;
if (SourceMgr)
FID = SourceMgr->getMainFileID();
@@ -2747,7 +2495,7 @@ bool ASTUnit::isInMainFileID(SourceLocation Loc) {
return SourceMgr->isInFileID(Loc, FID);
}
-SourceLocation ASTUnit::getEndOfPreambleFileID() {
+SourceLocation ASTUnit::getEndOfPreambleFileID() const {
FileID FID;
if (SourceMgr)
FID = SourceMgr->getPreambleFileID();
@@ -2758,7 +2506,7 @@ SourceLocation ASTUnit::getEndOfPreambleFileID() {
return SourceMgr->getLocForEndOfFile(FID);
}
-SourceLocation ASTUnit::getStartOfMainFileID() {
+SourceLocation ASTUnit::getStartOfMainFileID() const {
FileID FID;
if (SourceMgr)
FID = SourceMgr->getMainFileID();
@@ -2834,19 +2582,33 @@ const FileEntry *ASTUnit::getPCHFile() {
return nullptr;
}
-bool ASTUnit::isModuleFile() {
- return isMainFileAST() && ASTFileLangOpts.isCompilingModule();
+bool ASTUnit::isModuleFile() const {
+ return isMainFileAST() && getLangOpts().isCompilingModule();
}
-void ASTUnit::PreambleData::countLines() const {
- NumLines = 0;
- if (empty())
- return;
+InputKind ASTUnit::getInputKind() const {
+ auto &LangOpts = getLangOpts();
+
+ InputKind::Language Lang;
+ if (LangOpts.OpenCL)
+ Lang = InputKind::OpenCL;
+ else if (LangOpts.CUDA)
+ Lang = InputKind::CUDA;
+ else if (LangOpts.RenderScript)
+ Lang = InputKind::RenderScript;
+ else if (LangOpts.CPlusPlus)
+ Lang = LangOpts.ObjC1 ? InputKind::ObjCXX : InputKind::CXX;
+ else
+ Lang = LangOpts.ObjC1 ? InputKind::ObjC : InputKind::C;
+
+ InputKind::Format Fmt = InputKind::Source;
+ if (LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap)
+ Fmt = InputKind::ModuleMap;
- NumLines = std::count(Buffer.begin(), Buffer.end(), '\n');
+ // We don't know if input was preprocessed. Assume not.
+ bool PP = false;
- if (Buffer.back() != '\n')
- ++NumLines;
+ return InputKind(Lang, Fmt, PP);
}
#ifndef NDEBUG
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 18abecd207..ba3bd7d28c 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -38,6 +38,7 @@ add_clang_library(clangFrontend
ModuleDependencyCollector.cpp
MultiplexConsumer.cpp
PCHContainerOperations.cpp
+ PrecompiledPreamble.cpp
PrintPreprocessedOutput.cpp
SerializedDiagnosticPrinter.cpp
SerializedDiagnosticReader.cpp
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index b984c2ed0d..534c7587f4 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -83,7 +83,7 @@ createASTReader(CompilerInstance &CI, StringRef pchFile,
ASTDeserializationListener *deserialListener = nullptr) {
Preprocessor &PP = CI.getPreprocessor();
std::unique_ptr<ASTReader> Reader;
- Reader.reset(new ASTReader(PP, CI.getASTContext(),
+ Reader.reset(new ASTReader(PP, &CI.getASTContext(),
CI.getPCHContainerReader(),
/*Extensions=*/{ },
/*isysroot=*/"", /*DisableValidation=*/true));
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index a0e81f01f9..32f1232bbe 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -11,8 +11,10 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
@@ -55,9 +57,15 @@ using namespace clang;
CompilerInstance::CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- bool BuildingModule)
- : ModuleLoader(BuildingModule), Invocation(new CompilerInvocation()),
- ThePCHContainerOperations(std::move(PCHContainerOps)) {}
+ 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?");
@@ -128,6 +136,8 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const {
return ModuleManager;
}
void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) {
+ assert(PCMCache.get() == &Reader->getModuleManager().getPCMCache() &&
+ "Expected ASTReader to use the same PCM cache");
ModuleManager = std::move(Reader);
}
@@ -290,12 +300,16 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
// File Manager
-void CompilerInstance::createFileManager() {
+FileManager *CompilerInstance::createFileManager() {
if (!hasVirtualFileSystem()) {
- // TODO: choose the virtual file system based on the CompilerInvocation.
- setVirtualFileSystem(vfs::getRealFileSystem());
+ if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(getInvocation(), getDiagnostics()))
+ setVirtualFileSystem(VFS);
+ else
+ return nullptr;
}
FileMgr = new FileManager(getFileSystemOpts(), VirtualFileSystem);
+ return FileMgr.get();
}
// Source Manager
@@ -370,8 +384,9 @@ 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);
+ getTarget().adjust(getLangOpts());
PP->Initialize(getTarget(), getAuxTarget());
// Note that this is different then passing PTHMgr to Preprocessor's ctor.
@@ -488,6 +503,8 @@ void CompilerInstance::createPCHExternalASTSource(
AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(),
getPCHContainerReader(),
getFrontendOpts().ModuleFileExtensions,
+ TheDependencyFileGenerator.get(),
+ DependencyCollectors,
DeserializationListener,
OwnDeserializationListener, Preamble,
getFrontendOpts().UseGlobalModuleIndex);
@@ -498,12 +515,14 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
+ DependencyFileGenerator *DependencyFile,
+ ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors,
void *DeserializationListener, bool OwnDeserializationListener,
bool Preamble, bool UseGlobalModuleIndex) {
HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts();
IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader(
- PP, Context, PCHContainerRdr, Extensions,
+ PP, &Context, PCHContainerRdr, Extensions,
Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation,
AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false,
HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex));
@@ -515,6 +534,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,
@@ -648,6 +673,11 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
llvm::sys::fs::remove(OF.Filename);
}
OutputFiles.clear();
+ if (DeleteBuiltModules) {
+ for (auto &Module : BuiltModules)
+ llvm::sys::fs::remove(Module.second);
+ BuiltModules.clear();
+ }
NonSeekStream.reset();
}
@@ -734,9 +764,15 @@ std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
if (UseTemporary) {
// Create a temporary file.
- SmallString<128> TempPath;
- TempPath = OutFile;
+ // Insert -%%%%%%%% before the extension (if any), and because some tools
+ // (noticeable, clang's own GlobalModuleIndex.cpp) glob for build
+ // artifacts, also append .tmp.
+ StringRef OutputExtension = llvm::sys::path::extension(OutFile);
+ SmallString<128> TempPath =
+ StringRef(OutFile).drop_back(OutputExtension.size());
TempPath += "-%%%%%%%%";
+ TempPath += OutputExtension;
+ TempPath += ".tmp";
int fd;
std::error_code EC =
llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath);
@@ -800,12 +836,15 @@ bool CompilerInstance::InitializeSourceManager(
const FrontendInputFile &Input, DiagnosticsEngine &Diags,
FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS,
DependencyOutputOptions &DepOpts, const FrontendOptions &Opts) {
- SrcMgr::CharacteristicKind
- Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
+ SrcMgr::CharacteristicKind Kind =
+ Input.getKind().getFormat() == InputKind::ModuleMap
+ ? Input.isSystem() ? SrcMgr::C_System_ModuleMap
+ : SrcMgr::C_User_ModuleMap
+ : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
if (Input.isBuffer()) {
- SourceMgr.setMainFileID(SourceMgr.createFileID(
- std::unique_ptr<llvm::MemoryBuffer>(Input.getBuffer()), Kind));
+ SourceMgr.setMainFileID(SourceMgr.createFileID(SourceManager::Unowned,
+ Input.getBuffer(), Kind));
assert(SourceMgr.getMainFileID().isValid() &&
"Couldn't establish MainFileID!");
return true;
@@ -839,7 +878,8 @@ bool CompilerInstance::InitializeSourceManager(
/*SearchPath=*/nullptr,
/*RelativePath=*/nullptr,
/*RequestingModule=*/nullptr,
- /*SuggestedModule=*/nullptr, /*SkipCache=*/true);
+ /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr,
+ /*SkipCache=*/true);
// Also add the header to /showIncludes output.
if (File)
DepOpts.ShowIncludesPretendHeader = File->getName();
@@ -907,8 +947,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (!hasTarget())
return false;
- // Create TargetInfo for the other side of CUDA compilation.
- if (getLangOpts().CUDA && !getFrontendOpts().AuxTriple.empty()) {
+ // Create TargetInfo for the other side of CUDA and OpenMP compilation.
+ if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) &&
+ !getFrontendOpts().AuxTriple.empty()) {
auto TO = std::make_shared<TargetOptions>();
TO->Triple = getFrontendOpts().AuxTriple;
TO->HostTriple = getTarget().getTriple().str();
@@ -967,8 +1008,17 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
OS << " and ";
if (NumErrors)
OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
- if (NumWarnings || NumErrors)
- OS << " generated.\n";
+ if (NumWarnings || NumErrors) {
+ OS << " generated";
+ if (getLangOpts().CUDA) {
+ if (!getLangOpts().CUDAIsDevice) {
+ OS << " when compiling for host";
+ } else {
+ OS << " when compiling for " << getTargetOpts().CPU;
+ }
+ }
+ OS << ".\n";
+ }
}
if (getFrontendOpts().ShowStats) {
@@ -996,26 +1046,27 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
/// \brief Determine the appropriate source input kind based on language
/// options.
-static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
+static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) {
if (LangOpts.OpenCL)
- return IK_OpenCL;
+ return InputKind::OpenCL;
if (LangOpts.CUDA)
- return IK_CUDA;
+ return InputKind::CUDA;
if (LangOpts.ObjC1)
- return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC;
- return LangOpts.CPlusPlus? IK_CXX : IK_C;
+ return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC;
+ return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C;
}
/// \brief Compile a module file for the given module, using the options
/// provided by the importing compiler instance. Returns true if the module
/// was built without errors.
-static bool compileModuleImpl(CompilerInstance &ImportingInstance,
- SourceLocation ImportLoc,
- Module *Module,
- StringRef ModuleFileName) {
- ModuleMap &ModMap
- = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
-
+static bool
+compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
+ StringRef ModuleName, FrontendInputFile Input,
+ StringRef OriginalModuleMapFile, StringRef ModuleFileName,
+ llvm::function_ref<void(CompilerInstance &)> PreBuildStep =
+ [](CompilerInstance &) {},
+ llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
+ [](CompilerInstance &) {}) {
// Construct a compiler invocation for creating this module.
auto Invocation =
std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation());
@@ -1040,7 +1091,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
PPOpts.Macros.end());
// Note the name of the module we're building.
- Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
+ Invocation->getLangOpts()->CurrentModule = ModuleName;
// Make sure that the failed-module structure has been allocated in
// the importing instance, and propagate the pointer to the newly-created
@@ -1060,10 +1111,10 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
FrontendOpts.DisableFree = false;
FrontendOpts.GenerateGlobalModuleIndex = false;
FrontendOpts.BuildingImplicitModule = true;
+ FrontendOpts.OriginalModuleMap = OriginalModuleMapFile;
// Force implicitly-built modules to hash the content of the module file.
HSOpts.ModulesHashContent = true;
- FrontendOpts.Inputs.clear();
- InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
+ FrontendOpts.Inputs = {Input};
// Don't free the remapped file buffers; they are owned by our caller.
PPOpts.RetainRemappedFileBuffers = true;
@@ -1073,9 +1124,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));
@@ -1092,7 +1145,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
SourceManager &SourceMgr = Instance.getSourceManager();
SourceMgr.setModuleBuildStack(
ImportingInstance.getSourceManager().getModuleBuildStack());
- SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
+ SourceMgr.pushModuleBuildStack(ModuleName,
FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
// If we're collecting module dependencies, we need to share a collector
@@ -1101,47 +1154,28 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector());
Inv.getDependencyOutputOpts() = DependencyOutputOptions();
- // Get or create the module map that we'll use to build this module.
- std::string InferredModuleMapContent;
- if (const FileEntry *ModuleMapFile =
- ModMap.getContainingModuleMapFile(Module)) {
- // Use the module map where this module resides.
- FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK);
- } else {
- SmallString<128> FakeModuleMapFile(Module->Directory->getName());
- llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
- FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK);
-
- llvm::raw_string_ostream OS(InferredModuleMapContent);
- Module->print(OS);
- OS.flush();
-
- std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
- llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
- ModuleMapFile = Instance.getFileManager().getVirtualFile(
- FakeModuleMapFile, InferredModuleMapContent.size(), 0);
- SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer));
- }
-
- // Construct a module-generating action. Passing through the module map is
- // safe because the FileManager is shared between the compiler instances.
- GenerateModuleFromModuleMapAction CreateModuleAction(
- ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem);
-
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build)
- << Module->Name << ModuleFileName;
+ << ModuleName << ModuleFileName;
+
+ PreBuildStep(Instance);
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
const unsigned ThreadStackSize = 8 << 20;
llvm::CrashRecoveryContext CRC;
- CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); },
- ThreadStackSize);
+ CRC.RunSafelyOnThread(
+ [&]() {
+ GenerateModuleFromModuleMapAction Action;
+ Instance.ExecuteAction(Action);
+ },
+ ThreadStackSize);
+
+ PostBuildStep(Instance);
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build_done)
- << Module->Name;
+ << ModuleName;
// Delete the temporary module map file.
// FIXME: Even though we're executing under crash protection, it would still
@@ -1149,13 +1183,66 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
// doesn't make sense for all clients, so clean this up manually.
Instance.clearOutputFiles(/*EraseFiles=*/true);
+ return !Instance.getDiagnostics().hasErrorOccurred();
+}
+
+/// \brief Compile a module file for the given module, using the options
+/// provided by the importing compiler instance. Returns true if the module
+/// was built without errors.
+static bool compileModuleImpl(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ Module *Module,
+ StringRef ModuleFileName) {
+ InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()),
+ InputKind::ModuleMap);
+
+ // Get or create the module map that we'll use to build this module.
+ ModuleMap &ModMap
+ = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ bool Result;
+ if (const FileEntry *ModuleMapFile =
+ ModMap.getContainingModuleMapFile(Module)) {
+ // Use the module map where this module resides.
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName);
+ } else {
+ // FIXME: We only need to fake up an input file here as a way of
+ // transporting the module's directory to the module map parser. We should
+ // be able to do that more directly, and parse from a memory buffer without
+ // inventing this file.
+ SmallString<128> FakeModuleMapFile(Module->Directory->getName());
+ llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
+
+ std::string InferredModuleMapContent;
+ llvm::raw_string_ostream OS(InferredModuleMapContent);
+ Module->print(OS);
+ OS.flush();
+
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName,
+ [&](CompilerInstance &Instance) {
+ std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
+ llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
+ ModuleMapFile = Instance.getFileManager().getVirtualFile(
+ FakeModuleMapFile, InferredModuleMapContent.size(), 0);
+ Instance.getSourceManager().overrideFileContents(
+ ModuleMapFile, std::move(ModuleMapBuffer));
+ });
+ }
+
// We've rebuilt a module. If we're allowed to generate or update the global
// module index, record that fact in the importing compiler instance.
if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
ImportingInstance.setBuildGlobalModuleIndex(true);
}
- return !Instance.getDiagnostics().hasErrorOccurred();
+ return Result;
}
static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
@@ -1179,10 +1266,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,
@@ -1202,11 +1293,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;
}
@@ -1399,7 +1493,7 @@ void CompilerInstance::createModuleManager() {
"Reading modules",
*FrontendTimerGroup);
ModuleManager = new ASTReader(
- getPreprocessor(), getASTContext(), getPCHContainerReader(),
+ getPreprocessor(), &getASTContext(), getPCHContainerReader(),
getFrontendOpts().ModuleFileExtensions,
Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation,
/*AllowASTWithCompilerErrors=*/false,
@@ -1521,7 +1615,22 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) {
// Determine what file we're searching from.
- StringRef ModuleName = Path[0].first->getName();
+ // FIXME: Should we be deciding whether this is a submodule (here and
+ // below) based on -fmodules-ts or should we pass a flag and make the
+ // caller decide?
+ std::string ModuleName;
+ if (getLangOpts().ModulesTS) {
+ // FIXME: Same code as Sema::ActOnModuleDecl() so there is probably a
+ // better place/way to do this.
+ for (auto &Piece : Path) {
+ if (!ModuleName.empty())
+ ModuleName += ".";
+ ModuleName += Piece.first->getName();
+ }
+ }
+ else
+ ModuleName = Path[0].first->getName();
+
SourceLocation ModuleNameLoc = Path[0].second;
// If we've already handled this import, just return the cached result.
@@ -1546,6 +1655,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
} else if (ModuleName == getLangOpts().CurrentModule) {
// This is the module we're building.
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
+ /// FIXME: perhaps we should (a) look for a module using the module name
+ // to file map (PrebuiltModuleFiles) and (b) diagnose if still not found?
+ //if (Module == nullptr) {
+ // getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
+ // << ModuleName;
+ // ModuleBuildFailed = true;
+ // return ModuleLoadResult();
+ //}
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
} else {
// Search for a module with the given name.
@@ -1554,24 +1671,37 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
PP->getHeaderSearchInfo().getHeaderSearchOpts();
std::string ModuleFileName;
- bool LoadFromPrebuiltModulePath = false;
- // We try to load the module from the prebuilt module paths. If not
- // successful, we then try to find it in the module cache.
- if (!HSOpts.PrebuiltModulePaths.empty()) {
- // Load the module from the prebuilt module path.
- ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(
- ModuleName, "", /*UsePrebuiltPath*/ true);
+ enum ModuleSource {
+ ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma
+ } Source = ModuleNotFound;
+
+ // Check to see if the module has been built as part of this compilation
+ // via a module build pragma.
+ auto BuiltModuleIt = BuiltModules.find(ModuleName);
+ if (BuiltModuleIt != BuiltModules.end()) {
+ ModuleFileName = BuiltModuleIt->second;
+ Source = ModuleBuildPragma;
+ }
+
+ // Try to load the module from the prebuilt module path.
+ if (Source == ModuleNotFound && (!HSOpts.PrebuiltModuleFiles.empty() ||
+ !HSOpts.PrebuiltModulePaths.empty())) {
+ ModuleFileName =
+ PP->getHeaderSearchInfo().getPrebuiltModuleFileName(ModuleName);
if (!ModuleFileName.empty())
- LoadFromPrebuiltModulePath = true;
+ Source = PrebuiltModulePath;
}
- if (!LoadFromPrebuiltModulePath && Module) {
- // Load the module from the module cache.
- ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
- } else if (!LoadFromPrebuiltModulePath) {
+
+ // Try to load the module from the module cache.
+ if (Source == ModuleNotFound && Module) {
+ ModuleFileName = PP->getHeaderSearchInfo().getCachedModuleFileName(Module);
+ Source = ModuleCache;
+ }
+
+ if (Source == ModuleNotFound) {
// We can't find a module, error out here.
getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
+ << ModuleName << SourceRange(ImportLoc, ModuleNameLoc);
ModuleBuildFailed = true;
return ModuleLoadResult();
}
@@ -1599,20 +1729,20 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
*FrontendTimerGroup);
llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr);
- // Try to load the module file. If we are trying to load from the prebuilt
- // module path, we don't have the module map files and don't know how to
- // rebuild modules.
- unsigned ARRFlags = LoadFromPrebuiltModulePath ?
- ASTReader::ARR_ConfigurationMismatch :
- ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ // Try to load the module file. If we are not trying to load from the
+ // module cache, we don't know how to rebuild modules.
+ unsigned ARRFlags = Source == ModuleCache ?
+ ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing :
+ ASTReader::ARR_ConfigurationMismatch;
switch (ModuleManager->ReadAST(ModuleFileName,
- LoadFromPrebuiltModulePath ?
- serialization::MK_PrebuiltModule :
- serialization::MK_ImplicitModule,
- ImportLoc,
- ARRFlags)) {
+ Source == PrebuiltModulePath
+ ? serialization::MK_PrebuiltModule
+ : Source == ModuleBuildPragma
+ ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success: {
- if (LoadFromPrebuiltModulePath && !Module) {
+ if (Source != ModuleCache && !Module) {
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
if (!Module || !Module->getASTFile() ||
FileMgr->getFile(ModuleFileName) != Module->getASTFile()) {
@@ -1630,10 +1760,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::OutOfDate:
case ASTReader::Missing: {
- if (LoadFromPrebuiltModulePath) {
- // We can't rebuild the module without a module map. Since ReadAST
- // already produces diagnostics for these two cases, we simply
- // error out here.
+ if (Source != ModuleCache) {
+ // We don't know the desired configuration for this module and don't
+ // necessarily even have a module map. Since ReadAST already produces
+ // diagnostics for these two cases, we simply error out here.
ModuleBuildFailed = true;
KnownModules[Path[0].first] = nullptr;
return ModuleLoadResult();
@@ -1690,11 +1820,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
}
case ASTReader::ConfigurationMismatch:
- if (LoadFromPrebuiltModulePath)
+ if (Source == PrebuiltModulePath)
+ // FIXME: We shouldn't be setting HadFatalFailure below if we only
+ // produce a warning here!
getDiagnostics().Report(SourceLocation(),
diag::warn_module_config_mismatch)
<< ModuleFileName;
// Fall through to error out.
+ LLVM_FALLTHROUGH;
case ASTReader::VersionMismatch:
case ASTReader::HadErrors:
ModuleLoader::HadFatalFailure = true;
@@ -1718,10 +1851,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// If we never found the module, fail.
if (!Module)
return ModuleLoadResult();
-
+
// Verify that the rest of the module path actually corresponds to
// a submodule.
- if (Path.size() > 1) {
+ if (!getLangOpts().ModulesTS && Path.size() > 1) {
for (unsigned I = 1, N = Path.size(); I != N; ++I) {
StringRef Name = Path[I].first->getName();
clang::Module *Sub = Module->findSubmodule(Name);
@@ -1791,20 +1924,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
}
// Check whether this module is available.
- clang::Module::Requirement Requirement;
- clang::Module::UnresolvedHeaderDirective MissingHeader;
- if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement,
- MissingHeader)) {
- if (MissingHeader.FileNameLoc.isValid()) {
- getDiagnostics().Report(MissingHeader.FileNameLoc,
- diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first
- << SourceRange(Path.front().second, Path.back().second);
- }
+ if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(),
+ getDiagnostics(), Module)) {
+ getDiagnostics().Report(ImportLoc, diag::note_module_import_here)
+ << SourceRange(Path.front().second, Path.back().second);
LastModuleImportLoc = ImportLoc;
LastModuleImportResult = ModuleLoadResult();
return ModuleLoadResult();
@@ -1825,6 +1948,59 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return LastModuleImportResult;
}
+void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
+ StringRef ModuleName,
+ StringRef Source) {
+ // Avoid creating filenames with special characters.
+ SmallString<128> CleanModuleName(ModuleName);
+ for (auto &C : CleanModuleName)
+ if (!isAlphanumeric(C))
+ C = '_';
+
+ // FIXME: Using a randomized filename here means that our intermediate .pcm
+ // output is nondeterministic (as .pcm files refer to each other by name).
+ // Can this affect the output in any way?
+ SmallString<128> ModuleFileName;
+ if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
+ CleanModuleName, "pcm", ModuleFileName)) {
+ getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output)
+ << ModuleFileName << EC.message();
+ return;
+ }
+ std::string ModuleMapFileName = (CleanModuleName + ".map").str();
+
+ FrontendInputFile Input(
+ ModuleMapFileName,
+ InputKind(getLanguageFromOptions(*Invocation->getLangOpts()),
+ InputKind::ModuleMap, /*Preprocessed*/true));
+
+ std::string NullTerminatedSource(Source.str());
+
+ auto PreBuildStep = [&](CompilerInstance &Other) {
+ // Create a virtual file containing our desired source.
+ // FIXME: We shouldn't need to do this.
+ const FileEntry *ModuleMapFile = Other.getFileManager().getVirtualFile(
+ ModuleMapFileName, NullTerminatedSource.size(), 0);
+ Other.getSourceManager().overrideFileContents(
+ ModuleMapFile,
+ llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str()));
+
+ Other.BuiltModules = std::move(BuiltModules);
+ Other.DeleteBuiltModules = false;
+ };
+
+ auto PostBuildStep = [this](CompilerInstance &Other) {
+ BuiltModules = std::move(Other.BuiltModules);
+ };
+
+ // Build the module, inheriting any modules that we've built locally.
+ if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(),
+ ModuleFileName, PreBuildStep, PostBuildStep)) {
+ BuiltModules[ModuleName] = ModuleFileName.str();
+ llvm::sys::RemoveFileOnSignal(ModuleFileName);
+ }
+}
+
void CompilerInstance::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index d5ad3df35d..2c0d99b4be 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -81,7 +81,7 @@ using namespace llvm::opt;
static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
unsigned DefaultOpt = 0;
- if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable))
+ if (IK.getLanguage() == InputKind::OpenCL && !Args.hasArg(OPT_cl_opt_disable))
DefaultOpt = 2;
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
@@ -330,6 +330,17 @@ static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) {
return "default";
}
+static StringRef getRelocModel(ArgList &Args, DiagnosticsEngine &Diags) {
+ if (Arg *A = Args.getLastArg(OPT_mrelocation_model)) {
+ StringRef Value = A->getValue();
+ if (Value == "static" || Value == "pic" || Value == "ropi" ||
+ Value == "rwpi" || Value == "ropi-rwpi" || Value == "dynamic-no-pic")
+ return Value;
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value;
+ }
+ return "pic";
+}
+
/// \brief Create a new Regex instance out of the string value in \p RpassArg.
/// It returns a pointer to the newly generated Regex instance.
static std::shared_ptr<llvm::Regex>
@@ -465,6 +476,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager,
/* Default */ false);
+ Opts.DebugPassManager =
+ Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager,
+ /* Default */ false);
+
if (Arg *A = Args.getLastArg(OPT_fveclib)) {
StringRef Name = A->getValue();
if (Name == "Accelerate")
@@ -508,10 +523,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro);
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std);
+ Opts.EnableSplitDwarf = Args.hasArg(OPT_enable_split_dwarf);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.SplitDwarfInlining = !Args.hasArg(OPT_fno_split_dwarf_inlining);
Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
- Opts.DebugExplicitImport = Triple.isPS4CPU();
+ Opts.DebugExplicitImport = Args.hasArg(OPT_dwarf_explicit_import);
+ Opts.DebugFwdTemplateParams = Args.hasArg(OPT_debug_forward_template_params);
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
Opts.DebugPrefixMap.insert(StringRef(Arg).split('='));
@@ -522,12 +539,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes);
Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers);
+ Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
OPT_fuse_register_sized_bitfield_access);
Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
Opts.StructPathTBAA = !Args.hasArg(OPT_no_struct_path_tbaa);
+ Opts.FineGrainedBitfieldAccesses =
+ Args.hasFlag(OPT_ffine_grained_bitfield_accesses,
+ OPT_fno_fine_grained_bitfield_accesses, false);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
@@ -547,6 +568,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
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);
+ Opts.GnuPubnames = Args.hasArg(OPT_ggnu_pubnames);
setPGOInstrumentor(Opts, Args, Diags);
Opts.InstrProfileOutput =
@@ -556,6 +578,33 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
if (!Opts.ProfileInstrumentUsePath.empty())
setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
+ if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest);
+
+ StringRef Ver = A->getValue();
+ std::pair<StringRef, StringRef> VerParts = Ver.split('.');
+ unsigned Major, Minor = 0;
+
+ // Check the version number is valid: either 3.x (0 <= x <= 9) or
+ // y or y.0 (4 <= y <= current version).
+ if (!VerParts.first.startswith("0") &&
+ !VerParts.first.getAsInteger(10, Major) &&
+ 3 <= Major && Major <= CLANG_VERSION_MAJOR &&
+ (Major == 3 ? VerParts.second.size() == 1 &&
+ !VerParts.second.getAsInteger(10, Minor)
+ : VerParts.first.size() == Ver.size() ||
+ VerParts.second == "0")) {
+ // Got a valid version number.
+ if (Major == 3 && Minor <= 8)
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8);
+ else if (Major <= 4)
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4);
+ } else if (Ver != "latest") {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ }
+
Opts.CoverageMapping =
Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false);
Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
@@ -573,7 +622,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) ||
@@ -583,7 +634,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);
@@ -611,7 +664,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,20 +684,28 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables);
+ Opts.ProfileSampleAccurate = Args.hasArg(OPT_fprofile_sample_accurate);
+
Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ);
- const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ);
- Opts.EmitSummaryIndex = A && A->containsValue("thin");
+ Opts.EmitSummaryIndex = false;
+ if (Arg *A = Args.getLastArg(OPT_flto_EQ)) {
+ StringRef S = A->getValue();
+ if (S == "thin")
+ Opts.EmitSummaryIndex = true;
+ else if (S != "full")
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false);
if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
- if (IK != IK_LLVM_IR)
+ if (IK.getLanguage() != InputKind::LLVM_IR)
Diags.Report(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-x ir";
Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ);
}
+ Opts.ThinLinkBitcodeFile = Args.getLastArgValue(OPT_fthin_link_bitcode_EQ);
Opts.MSVolatile = Args.hasArg(OPT_fms_volatile);
- Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive);
Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops);
Opts.VectorizeSLP = Args.hasArg(OPT_vectorize_slp);
@@ -713,14 +774,30 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
+ Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type);
Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument);
Opts.XRayInstructionThreshold =
- getLastArgIntValue(Args, OPT_fxray_instruction_threshold_, 200, Diags);
+ getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags);
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
Opts.CallFEntry = Args.hasArg(OPT_mfentry);
Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
- Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections);
+
+ if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
+ OPT_compress_debug_sections_EQ)) {
+ if (A->getOption().getID() == OPT_compress_debug_sections) {
+ // TODO: be more clever about the compression type auto-detection
+ Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU);
+ } else {
+ auto DCT = llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
+ .Case("none", llvm::DebugCompressionType::None)
+ .Case("zlib", llvm::DebugCompressionType::Z)
+ .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+ .Default(llvm::DebugCompressionType::None);
+ Opts.setCompressDebugSections(DCT);
+ }
+ }
+
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) {
@@ -748,17 +825,30 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeCoverageTracePC = Args.hasArg(OPT_fsanitize_coverage_trace_pc);
Opts.SanitizeCoverageTracePCGuard =
Args.hasArg(OPT_fsanitize_coverage_trace_pc_guard);
+ Opts.SanitizeCoverageNoPrune = Args.hasArg(OPT_fsanitize_coverage_no_prune);
+ Opts.SanitizeCoverageInline8bitCounters =
+ Args.hasArg(OPT_fsanitize_coverage_inline_8bit_counters);
+ Opts.SanitizeCoveragePCTable = Args.hasArg(OPT_fsanitize_coverage_pc_table);
+ Opts.SanitizeCoverageStackDepth =
+ Args.hasArg(OPT_fsanitize_coverage_stack_depth);
Opts.SanitizeMemoryTrackOrigins =
getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
Opts.SanitizeMemoryUseAfterDtor =
- Args.hasArg(OPT_fsanitize_memory_use_after_dtor);
+ Args.hasFlag(OPT_fsanitize_memory_use_after_dtor,
+ OPT_fno_sanitize_memory_use_after_dtor,
+ false);
+ Opts.SanitizeMinimalRuntime = Args.hasArg(OPT_fsanitize_minimal_runtime);
Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso);
+ Opts.SanitizeCfiICallGeneralizePointers =
+ Args.hasArg(OPT_fsanitize_cfi_icall_generalize_pointers);
Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats);
if (Arg *A = Args.getLastArg(OPT_fsanitize_address_use_after_scope,
OPT_fno_sanitize_address_use_after_scope)) {
Opts.SanitizeAddressUseAfterScope =
A->getOption().getID() == OPT_fsanitize_address_use_after_scope;
}
+ Opts.SanitizeAddressGlobalsDeadStripping =
+ Args.hasArg(OPT_fsanitize_address_globals_dead_stripping);
Opts.SSPBufferSize =
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@@ -811,18 +901,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")
@@ -872,14 +950,24 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DiagnosticsWithHotness =
Args.hasArg(options::OPT_fdiagnostics_show_hotness);
- if (Opts.DiagnosticsWithHotness &&
- Opts.getProfileUse() == CodeGenOptions::ProfileNone)
- Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo);
+ bool UsingSampleProfile = !Opts.SampleProfileFile.empty();
+ bool UsingProfile = UsingSampleProfile ||
+ (Opts.getProfileUse() != CodeGenOptions::ProfileNone);
+
+ if (Opts.DiagnosticsWithHotness && !UsingProfile)
+ Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
+ << "-fdiagnostics-show-hotness";
+
+ Opts.DiagnosticsHotnessThreshold = getLastArgUInt64Value(
+ Args, options::OPT_fdiagnostics_hotness_threshold_EQ, 0);
+ if (Opts.DiagnosticsHotnessThreshold > 0 && !UsingProfile)
+ Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
+ << "-fdiagnostics-hotness-threshold=";
// If the user requested to use a sample profile for PGO, then the
// backend will need to track source location information so the profile
// can be incorporated into the IR.
- if (!Opts.SampleProfileFile.empty())
+ if (UsingSampleProfile)
NeedLocTracking = true;
// If the user requested a flag that requires source locations available in
@@ -930,9 +1018,12 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
// They won't be discovered by the regular preprocessor, so
// we let make / ninja to know about this implicit dependency.
Opts.ExtraDeps = Args.getAllArgValues(OPT_fdepfile_entry);
- auto ModuleFiles = Args.getAllArgValues(OPT_fmodule_file);
- Opts.ExtraDeps.insert(Opts.ExtraDeps.end(), ModuleFiles.begin(),
- ModuleFiles.end());
+ // Only the -fmodule-file=<file> form.
+ for (const Arg *A : Args.filtered(OPT_fmodule_file)) {
+ StringRef Val = A->getValue();
+ if (Val.find('=') == StringRef::npos)
+ Opts.ExtraDeps.push_back(Val);
+ }
}
static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) {
@@ -1078,6 +1169,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.SpellCheckingLimit = getLastArgIntValue(
Args, OPT_fspell_checking_limit,
DiagnosticOptions::DefaultSpellCheckingLimit, Diags);
+ Opts.SnippetLineLimit = getLastArgIntValue(
+ Args, OPT_fcaret_diagnostics_max_lines,
+ DiagnosticOptions::DefaultSnippetLineLimit, Diags);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -1258,7 +1352,12 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex;
Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file);
- Opts.ModuleFiles = Args.getAllArgValues(OPT_fmodule_file);
+ // Only the -fmodule-file=<file> form.
+ for (const Arg *A : Args.filtered(OPT_fmodule_file)) {
+ StringRef Val = A->getValue();
+ if (Val.find('=') == StringRef::npos)
+ Opts.ModuleFiles.push_back(Val);
+ }
Opts.ModulesEmbedFiles = Args.getAllArgValues(OPT_fmodules_embed_file_EQ);
Opts.ModulesEmbedAllFiles = Args.hasArg(OPT_fmodules_embed_all_files);
Opts.IncludeTimestamps = !Args.hasArg(OPT_fno_pch_timestamp);
@@ -1341,44 +1440,54 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
<< "ARC migration" << "ObjC migration";
}
- InputKind DashX = IK_None;
+ InputKind DashX(InputKind::Unknown);
if (const Arg *A = Args.getLastArg(OPT_x)) {
- DashX = llvm::StringSwitch<InputKind>(A->getValue())
- .Case("c", IK_C)
- .Case("cl", IK_OpenCL)
- .Case("cuda", IK_CUDA)
- .Case("c++", IK_CXX)
- .Case("c++-module", IK_CXX)
- .Case("objective-c", IK_ObjC)
- .Case("objective-c++", IK_ObjCXX)
- .Case("cpp-output", IK_PreprocessedC)
- .Case("assembler-with-cpp", IK_Asm)
- .Case("c++-cpp-output", IK_PreprocessedCXX)
- .Case("c++-module-cpp-output", IK_PreprocessedCXX)
- .Case("cuda-cpp-output", IK_PreprocessedCuda)
- .Case("objective-c-cpp-output", IK_PreprocessedObjC)
- .Case("objc-cpp-output", IK_PreprocessedObjC)
- .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX)
- .Case("objc++-cpp-output", IK_PreprocessedObjCXX)
- .Case("c-header", IK_C)
- .Case("cl-header", IK_OpenCL)
- .Case("objective-c-header", IK_ObjC)
- .Case("c++-header", IK_CXX)
- .Case("objective-c++-header", IK_ObjCXX)
- .Cases("ast", "pcm", IK_AST)
- .Case("ir", IK_LLVM_IR)
- .Case("renderscript", IK_RenderScript)
- .Default(IK_None);
- if (DashX == IK_None)
+ StringRef XValue = A->getValue();
+
+ // Parse suffixes: '<lang>(-header|[-module-map][-cpp-output])'.
+ // FIXME: Supporting '<lang>-header-cpp-output' would be useful.
+ bool Preprocessed = XValue.consume_back("-cpp-output");
+ bool ModuleMap = XValue.consume_back("-module-map");
+ IsHeaderFile =
+ !Preprocessed && !ModuleMap && XValue.consume_back("-header");
+
+ // Principal languages.
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("c", InputKind::C)
+ .Case("cl", InputKind::OpenCL)
+ .Case("cuda", InputKind::CUDA)
+ .Case("c++", InputKind::CXX)
+ .Case("objective-c", InputKind::ObjC)
+ .Case("objective-c++", InputKind::ObjCXX)
+ .Case("renderscript", InputKind::RenderScript)
+ .Default(InputKind::Unknown);
+
+ // "objc[++]-cpp-output" is an acceptable synonym for
+ // "objective-c[++]-cpp-output".
+ if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap)
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("objc", InputKind::ObjC)
+ .Case("objc++", InputKind::ObjCXX)
+ .Default(InputKind::Unknown);
+
+ // Some special cases cannot be combined with suffixes.
+ if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile)
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("cpp-output", InputKind(InputKind::C).getPreprocessed())
+ .Case("assembler-with-cpp", InputKind::Asm)
+ .Cases("ast", "pcm",
+ InputKind(InputKind::Unknown, InputKind::Precompiled))
+ .Case("ir", InputKind::LLVM_IR)
+ .Default(InputKind::Unknown);
+
+ if (DashX.isUnknown())
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
- IsHeaderFile = llvm::StringSwitch<bool>(A->getValue())
- .Case("c-header", true)
- .Case("cl-header", true)
- .Case("objective-c-header", true)
- .Case("c++-header", true)
- .Case("objective-c++-header", true)
- .Default(false);
+
+ if (Preprocessed)
+ DashX = DashX.getPreprocessed();
+ if (ModuleMap)
+ DashX = DashX.withFormat(InputKind::ModuleMap);
}
// '-' is the default input if none is given.
@@ -1388,13 +1497,22 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Inputs.push_back("-");
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
InputKind IK = DashX;
- if (IK == IK_None) {
+ if (IK.isUnknown()) {
IK = FrontendOptions::getInputKindForExtension(
StringRef(Inputs[i]).rsplit('.').second);
+ // FIXME: Warn on this?
+ if (IK.isUnknown())
+ IK = InputKind::C;
// FIXME: Remove this hack.
if (i == 0)
DashX = IK;
}
+
+ // The -emit-module action implicitly takes a module map.
+ if (Opts.ProgramAction == frontend::GenerateModule &&
+ IK.getFormat() == InputKind::Source)
+ IK = IK.withFormat(InputKind::ModuleMap);
+
Opts.Inputs.emplace_back(std::move(Inputs[i]), IK);
}
@@ -1419,7 +1537,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);
@@ -1429,8 +1548,25 @@ 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);
+ // Only the -fmodule-file=<name>=<file> form.
+ for (const Arg *A : Args.filtered(OPT_fmodule_file)) {
+ StringRef Val = A->getValue();
+ if (Val.find('=') != StringRef::npos)
+ Opts.PrebuiltModuleFiles.insert(Val.split('='));
+ }
for (const Arg *A : Args.filtered(OPT_fprebuilt_module_path))
Opts.AddPrebuiltModulePath(A->getValue());
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
@@ -1548,53 +1684,48 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// Set some properties which depend solely on the input kind; it would be nice
// to move these to the language standard, and have the driver resolve the
// input kind + language standard.
- if (IK == IK_Asm) {
+ //
+ // FIXME: Perhaps a better model would be for a single source file to have
+ // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std)
+ // simultaneously active?
+ if (IK.getLanguage() == InputKind::Asm) {
Opts.AsmPreprocessor = 1;
- } else if (IK == IK_ObjC ||
- IK == IK_ObjCXX ||
- IK == IK_PreprocessedObjC ||
- IK == IK_PreprocessedObjCXX) {
+ } else if (IK.isObjectiveC()) {
Opts.ObjC1 = Opts.ObjC2 = 1;
}
if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
- switch (IK) {
- case IK_None:
- case IK_AST:
- case IK_LLVM_IR:
+ switch (IK.getLanguage()) {
+ case InputKind::Unknown:
+ case InputKind::LLVM_IR:
llvm_unreachable("Invalid input kind!");
- case IK_OpenCL:
- LangStd = LangStandard::lang_opencl;
+ case InputKind::OpenCL:
+ LangStd = LangStandard::lang_opencl10;
break;
- case IK_CUDA:
- case IK_PreprocessedCuda:
+ case InputKind::CUDA:
LangStd = LangStandard::lang_cuda;
break;
- case IK_Asm:
- case IK_C:
- case IK_PreprocessedC:
+ case InputKind::Asm:
+ case InputKind::C:
// The PS4 uses C99 as the default C standard.
if (T.isPS4())
LangStd = LangStandard::lang_gnu99;
else
LangStd = LangStandard::lang_gnu11;
break;
- case IK_ObjC:
- case IK_PreprocessedObjC:
+ case InputKind::ObjC:
LangStd = LangStandard::lang_gnu11;
break;
- case IK_CXX:
- case IK_PreprocessedCXX:
- case IK_ObjCXX:
- case IK_PreprocessedObjCXX:
+ case InputKind::CXX:
+ case InputKind::ObjCXX:
// The PS4 uses C++11 as the default C++ standard.
if (T.isPS4())
LangStd = LangStandard::lang_gnucxx11;
else
LangStd = LangStandard::lang_gnucxx98;
break;
- case IK_RenderScript:
+ case InputKind::RenderScript:
LangStd = LangStandard::lang_c99;
break;
}
@@ -1608,15 +1739,16 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus14 = Std.isCPlusPlus14();
Opts.CPlusPlus1z = Std.isCPlusPlus1z();
+ Opts.CPlusPlus2a = Std.isCPlusPlus2a();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
- Opts.GNUInline = Std.isC89();
+ Opts.GNUInline = !Opts.C99 && !Opts.CPlusPlus;
Opts.HexFloats = Std.hasHexFloats();
Opts.ImplicitInt = Std.hasImplicitInt();
// Set OpenCL Version.
- Opts.OpenCL = Std.isOpenCL() || IK == IK_OpenCL;
- if (LangStd == LangStandard::lang_opencl)
+ Opts.OpenCL = Std.isOpenCL();
+ if (LangStd == LangStandard::lang_opencl10)
Opts.OpenCLVersion = 100;
else if (LangStd == LangStandard::lang_opencl11)
Opts.OpenCLVersion = 110;
@@ -1629,9 +1761,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.
@@ -1640,10 +1771,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
}
}
- Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda ||
- LangStd == LangStandard::lang_cuda;
+ Opts.CUDA = IK.getLanguage() == InputKind::CUDA;
+ if (Opts.CUDA)
+ // Set default FP_CONTRACT to FAST.
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
- Opts.RenderScript = IK == IK_RenderScript;
+ Opts.RenderScript = IK.getLanguage() == InputKind::RenderScript;
if (Opts.RenderScript) {
Opts.NativeHalfType = 1;
Opts.NativeHalfArgsAndReturns = 1;
@@ -1687,58 +1820,65 @@ static Visibility parseVisibility(Arg *arg, ArgList &args,
/// 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.
+ switch (IK.getLanguage()) {
+ case InputKind::Unknown:
+ case InputKind::LLVM_IR:
+ llvm_unreachable("should not parse language flags for this input");
+
+ case InputKind::C:
+ case InputKind::ObjC:
+ case InputKind::RenderScript:
+ return S.getLanguage() == InputKind::C;
+
+ case InputKind::OpenCL:
+ return S.getLanguage() == InputKind::OpenCL;
+
+ case InputKind::CXX:
+ case InputKind::ObjCXX:
+ return S.getLanguage() == InputKind::CXX;
+
+ case InputKind::CUDA:
+ // FIXME: What -std= values should be permitted for CUDA compilations?
+ return S.getLanguage() == InputKind::CUDA ||
+ S.getLanguage() == InputKind::CXX;
+
+ case InputKind::Asm:
+ // Accept (and ignore) all -std= values.
+ // FIXME: The -std= value is not ignored; it affects the tokenization
+ // and preprocessing rules if we're preprocessing this asm input.
return true;
}
- return false;
+
+ llvm_unreachable("unexpected input language");
}
/// 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:
+ switch (IK.getLanguage()) {
+ case InputKind::C:
+ return "C";
+ case InputKind::ObjC:
+ return "Objective-C";
+ case InputKind::CXX:
+ return "C++";
+ case InputKind::ObjCXX:
+ return "Objective-C++";
+ case InputKind::OpenCL:
return "OpenCL";
- case IK_CUDA:
- case IK_PreprocessedCuda:
+ case InputKind::CUDA:
return "CUDA";
- default:
- llvm_unreachable("Cannot decide on name for InputKind!");
+ case InputKind::RenderScript:
+ return "RenderScript";
+
+ case InputKind::Asm:
+ return "Asm";
+ case InputKind::LLVM_IR:
+ return "LLVM IR";
+
+ case InputKind::Unknown:
+ break;
}
+ llvm_unreachable("unknown input language");
}
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
@@ -1749,7 +1889,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
.Case(name, LangStandard::lang_##id)
#define LANGSTANDARD_ALIAS(id, alias) \
.Case(alias, LangStandard::lang_##id)
@@ -1765,8 +1905,20 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
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();
+ auto Diag = Diags.Report(diag::note_drv_use_standard);
+ Diag << Std.getName() << Std.getDescription();
+ unsigned NumAliases = 0;
+#define LANGSTANDARD(id, name, lang, desc, features)
+#define LANGSTANDARD_ALIAS(id, alias) \
+ if (KindValue == LangStandard::lang_##id) ++NumAliases;
+#define LANGSTANDARD_ALIAS_DEPR(id, alias)
+#include "clang/Frontend/LangStandards.def"
+ Diag << NumAliases;
+#define LANGSTANDARD(id, name, lang, desc, features)
+#define LANGSTANDARD_ALIAS(id, alias) \
+ if (KindValue == LangStandard::lang_##id) Diag << alias;
+#define LANGSTANDARD_ALIAS_DEPR(id, alias)
+#include "clang/Frontend/LangStandards.def"
}
}
} else {
@@ -1785,7 +1937,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
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("cl", "CL", LangStandard::lang_opencl10)
.Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
.Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
.Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
@@ -1912,9 +2064,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;
@@ -1994,6 +2143,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
&& Opts.OpenCLVersion >= 200);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.CoroutinesTS = Args.hasArg(OPT_fcoroutines_ts);
+
+ // Enable [[]] attributes in C++11 by default.
+ Opts.DoubleSquareBracketAttributes =
+ Args.hasFlag(OPT_fdouble_square_bracket_attributes,
+ OPT_fno_double_square_bracket_attributes, Opts.CPlusPlus11);
+
Opts.ModulesTS = Args.hasArg(OPT_fmodules_ts);
Opts.Modules = Args.hasArg(OPT_fmodules) || Opts.ModulesTS;
Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse);
@@ -2001,7 +2156,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.ModularCodegen = Args.hasArg(OPT_fmodule_codegen);
+ 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);
@@ -2009,7 +2165,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.ImplicitModules = !Args.hasArg(OPT_fno_implicit_modules);
Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char);
Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
- Opts.ShortWChar = Args.hasFlag(OPT_fshort_wchar, OPT_fno_short_wchar, false);
+ if (const Arg *A = Args.getLastArg(OPT_fwchar_type_EQ)) {
+ Opts.WCharSize = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("char", 1)
+ .Case("short", 2)
+ .Case("int", 4)
+ .Default(0);
+ if (Opts.WCharSize == 0)
+ Diags.Report(diag::err_fe_invalid_wchar_type) << A->getValue();
+ }
+ Opts.WCharIsSigned = Args.hasFlag(OPT_fsigned_wchar, OPT_fno_signed_wchar, true);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
@@ -2022,6 +2187,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.AlignedAllocation =
Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation,
Opts.AlignedAllocation);
+ Opts.AlignedAllocationUnavailable =
+ Opts.AlignedAllocation && Args.hasArg(OPT_aligned_alloc_unavailable);
Opts.NewAlignOverride =
getLastArgIntValue(Args, OPT_fnew_alignment_EQ, 0, Diags);
if (Opts.NewAlignOverride && !llvm::isPowerOf2_32(Opts.NewAlignOverride)) {
@@ -2100,12 +2267,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)
@@ -2163,8 +2324,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
llvm::Triple T(TargetOpts.Triple);
llvm::Triple::ArchType Arch = T.getArch();
bool emitError = (DefaultCC == LangOptions::DCC_FastCall ||
- DefaultCC == LangOptions::DCC_StdCall) &&
- Arch != llvm::Triple::x86;
+ DefaultCC == LangOptions::DCC_StdCall) &&
+ Arch != llvm::Triple::x86;
emitError |= DefaultCC == LangOptions::DCC_VectorCall &&
!(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64);
if (emitError)
@@ -2217,13 +2378,27 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
}
}
+ // Set the flag to prevent the implementation from emitting device exception
+ // handling code for those requiring so.
+ if (Opts.OpenMPIsDevice && T.isNVPTX()) {
+ Opts.Exceptions = 0;
+ Opts.CXXExceptions = 0;
+ }
+
// Get the OpenMP target triples if any.
if (Arg *A = Args.getLastArg(options::OPT_fopenmp_targets_EQ)) {
for (unsigned i = 0; i < A->getNumValues(); ++i) {
llvm::Triple TT(A->getValue(i));
- if (TT.getArch() == llvm::Triple::UnknownArch)
+ if (TT.getArch() == llvm::Triple::UnknownArch ||
+ !(TT.getArch() == llvm::Triple::ppc ||
+ TT.getArch() == llvm::Triple::ppc64 ||
+ TT.getArch() == llvm::Triple::ppc64le ||
+ TT.getArch() == llvm::Triple::nvptx ||
+ TT.getArch() == llvm::Triple::nvptx64 ||
+ TT.getArch() == llvm::Triple::x86 ||
+ TT.getArch() == llvm::Triple::x86_64))
Diags.Report(clang::diag::err_drv_invalid_omp_target) << A->getValue(i);
else
Opts.OMPTargetTriples.push_back(TT);
@@ -2269,6 +2444,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);
@@ -2291,11 +2478,66 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeAddressFieldPadding =
getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
+
+ // -fxray-instrument
+ Opts.XRayInstrument =
+ Args.hasFlag(OPT_fxray_instrument, OPT_fnoxray_instrument, false);
+
+ // -fxray-{always,never}-instrument= filenames.
+ Opts.XRayAlwaysInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_always_instrument);
+ Opts.XRayNeverInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_never_instrument);
+
+ // -fallow-editor-placeholders
+ Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
+}
+
+static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
+ switch (Action) {
+ case frontend::ASTDeclList:
+ case frontend::ASTDump:
+ case frontend::ASTPrint:
+ case frontend::ASTView:
+ case frontend::EmitAssembly:
+ case frontend::EmitBC:
+ case frontend::EmitHTML:
+ case frontend::EmitLLVM:
+ case frontend::EmitLLVMOnly:
+ case frontend::EmitCodeGenOnly:
+ case frontend::EmitObj:
+ case frontend::FixIt:
+ case frontend::GenerateModule:
+ case frontend::GenerateModuleInterface:
+ case frontend::GeneratePCH:
+ case frontend::GeneratePTH:
+ case frontend::ParseSyntaxOnly:
+ case frontend::ModuleFileInfo:
+ case frontend::VerifyPCH:
+ case frontend::PluginAction:
+ case frontend::PrintDeclContext:
+ case frontend::RewriteObjC:
+ case frontend::RewriteTest:
+ case frontend::RunAnalysis:
+ case frontend::MigrateSource:
+ return false;
+
+ case frontend::DumpRawTokens:
+ case frontend::DumpTokens:
+ case frontend::InitOnly:
+ case frontend::PrintPreamble:
+ case frontend::PrintPreprocessedInput:
+ case frontend::RewriteMacros:
+ case frontend::RunPreprocessorOnly:
+ return true;
+ }
+ llvm_unreachable("invalid frontend action");
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
FileManager &FileMgr,
- DiagnosticsEngine &Diags) {
+ DiagnosticsEngine &Diags,
+ frontend::ActionKind Action) {
using namespace options;
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
@@ -2368,6 +2610,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
else
Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
}
+
+ // Always avoid lexing editor placeholders when we're just running the
+ // preprocessor as we never want to emit the
+ // "editor placeholder in source file" error in PP only mode.
+ if (isStrictlyPreprocessorAction(Action))
+ Opts.LexEditorPlaceholders = false;
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
@@ -2375,45 +2623,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
frontend::ActionKind Action) {
using namespace options;
- switch (Action) {
- case frontend::ASTDeclList:
- case frontend::ASTDump:
- case frontend::ASTPrint:
- case frontend::ASTView:
- case frontend::EmitAssembly:
- case frontend::EmitBC:
- case frontend::EmitHTML:
- case frontend::EmitLLVM:
- case frontend::EmitLLVMOnly:
- case frontend::EmitCodeGenOnly:
- case frontend::EmitObj:
- case frontend::FixIt:
- case frontend::GenerateModule:
- case frontend::GenerateModuleInterface:
- case frontend::GeneratePCH:
- case frontend::GeneratePTH:
- case frontend::ParseSyntaxOnly:
- case frontend::ModuleFileInfo:
- case frontend::VerifyPCH:
- case frontend::PluginAction:
- case frontend::PrintDeclContext:
- case frontend::RewriteObjC:
- case frontend::RewriteTest:
- case frontend::RunAnalysis:
- case frontend::MigrateSource:
- Opts.ShowCPP = 0;
- break;
-
- case frontend::DumpRawTokens:
- case frontend::DumpTokens:
- case frontend::InitOnly:
- case frontend::PrintPreamble:
- case frontend::PrintPreprocessedInput:
- case frontend::RewriteMacros:
- case frontend::RunPreprocessorOnly:
+ if (isStrictlyPreprocessorAction(Action))
Opts.ShowCPP = !Args.hasArg(OPT_dM);
- break;
- }
+ else
+ Opts.ShowCPP = 0;
Opts.ShowComments = Args.hasArg(OPT_C);
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
@@ -2421,6 +2634,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
Opts.ShowIncludeDirectives = Args.hasArg(OPT_dI);
Opts.RewriteIncludes = Args.hasArg(OPT_frewrite_includes);
+ Opts.RewriteImports = Args.hasArg(OPT_frewrite_imports);
Opts.UseLineDirectives = Args.hasArg(OPT_fuse_line_directives);
}
@@ -2440,7 +2654,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
<< Value;
else
- Opts.EABIVersion = Value;
+ Opts.EABIVersion = EABIVersion;
}
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
Opts.FPMath = Args.getLastArgValue(OPT_mfpmath);
@@ -2496,8 +2710,10 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseTargetArgs(Res.getTargetOpts(), Args, Diags);
Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags,
Res.getTargetOpts());
- ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args);
- if (DashX == IK_AST || DashX == IK_LLVM_IR) {
+ ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args,
+ Res.getFileSystemOpts().WorkingDir);
+ if (DashX.getFormat() == InputKind::Precompiled ||
+ DashX.getLanguage() == InputKind::LLVM_IR) {
// ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
// PassManager in BackendUtil.cpp. They need to be initializd no matter
// what the input type is.
@@ -2511,8 +2727,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Diags, LangOpts.Sanitize);
} else {
// Other LangOpts are only initialzed when the input is not AST or LLVM IR.
+ // FIXME: Should we really be calling this for an InputKind::Asm input?
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
- Res.getPreprocessorOpts(), Diags);
+ Res.getPreprocessorOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1;
}
@@ -2522,12 +2739,12 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// triple used for host compilation.
if (LangOpts.CUDAIsDevice)
Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
-
- // Set default FP_CONTRACT to FAST.
- if (!Args.hasArg(OPT_ffp_contract))
- Res.getCodeGenOpts().setFPContractMode(CodeGenOptions::FPC_Fast);
}
+ // Set the triple of the host for OpenMP device compile.
+ if (LangOpts.OpenMPIsDevice)
+ Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
+
// FIXME: Override value name discarding when asan or msan is used because the
// backend passes depend on the name of the alloca in order to print out
// names.
@@ -2540,7 +2757,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// ParsePreprocessorArgs and remove the FileManager
// parameters from the function and the "FileManager.h" #include.
FileManager FileMgr(Res.getFileSystemOpts());
- ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags);
+ ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags,
+ Res.getFrontendOpts().ProgramAction);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args,
Res.getFrontendOpts().ProgramAction);
@@ -2550,6 +2768,13 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
if (Arch == llvm::Triple::spir || Arch == llvm::Triple::spir64) {
Res.getDiagnosticOpts().Warnings.push_back("spir-compat");
}
+
+ // If sanitizer is enabled, disable OPT_ffine_grained_bitfield_accesses.
+ if (Res.getCodeGenOpts().FineGrainedBitfieldAccesses &&
+ !Res.getLangOpts()->Sanitize.empty()) {
+ Res.getCodeGenOpts().FineGrainedBitfieldAccesses = false;
+ Diags.Report(diag::warn_drv_fine_grained_bitfield_accesses_ignored);
+ }
return Success;
}
@@ -2625,28 +2850,12 @@ std::string CompilerInvocation::getModuleHash() const {
code = ext->hashExtension(code);
}
- // Darwin-specific hack: if we have a sysroot, use the contents and
- // modification time of
- // $sysroot/System/Library/CoreServices/SystemVersion.plist
- // as part of the module hash.
- if (!hsOpts.Sysroot.empty()) {
- SmallString<128> systemVersionFile;
- systemVersionFile += hsOpts.Sysroot;
- llvm::sys::path::append(systemVersionFile, "System");
- llvm::sys::path::append(systemVersionFile, "Library");
- llvm::sys::path::append(systemVersionFile, "CoreServices");
- llvm::sys::path::append(systemVersionFile, "SystemVersion.plist");
-
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
- llvm::MemoryBuffer::getFile(systemVersionFile);
- if (buffer) {
- code = hash_combine(code, buffer.get()->getBuffer());
-
- struct stat statBuf;
- if (stat(systemVersionFile.c_str(), &statBuf) == 0)
- code = hash_combine(code, statBuf.st_mtime);
- }
- }
+ // Extend the signature with the enabled sanitizers, if at least one is
+ // enabled. Sanitizers which cannot affect AST generation aren't hashed.
+ SanitizerSet SanHash = LangOpts->Sanitize;
+ SanHash.clear(getPPTransparentSanitizers());
+ if (!SanHash.empty())
+ code = hash_combine(code, SanHash.Mask);
return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
@@ -2699,15 +2908,22 @@ void BuryPointer(const void *Ptr) {
IntrusiveRefCntPtr<vfs::FileSystem>
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
DiagnosticsEngine &Diags) {
+ return createVFSFromCompilerInvocation(CI, Diags, vfs::getRealFileSystem());
+}
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
- return vfs::getRealFileSystem();
+ return BaseFS;
- IntrusiveRefCntPtr<vfs::OverlayFileSystem>
- Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay(
+ new vfs::OverlayFileSystem(BaseFS));
// earlier vfs files are on the bottom
for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
- llvm::MemoryBuffer::getFile(File);
+ BaseFS->getBufferForFile(File);
if (!Buffer) {
Diags.Report(diag::err_missing_vfs_overlay_file) << File;
return IntrusiveRefCntPtr<vfs::FileSystem>();
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 16269064b6..c3ce7ce2b7 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -31,8 +31,8 @@ using namespace llvm::opt;
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
- ArrayRef<const char *> ArgList,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
+ ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -46,12 +46,14 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
- *Diags);
+ *Diags, VFS);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
+ if (!C)
+ return nullptr;
// Just print the cc1 options if -### was present.
if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index bd14c53e4d..561eb9c4a3 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -55,8 +55,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
llvm::sys::path::remove_leading_dotslash(FE->getName());
DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
- FileType != SrcMgr::C_User,
- /*IsModuleFile*/false, /*IsMissing*/false);
+ isSystem(FileType),
+ /*IsModuleFile*/false, /*IsMissing*/false);
}
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
@@ -265,7 +265,7 @@ bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
if (IncludeSystemHeaders)
return true;
- return FileType == SrcMgr::C_User;
+ return !isSystem(FileType);
}
void DFGImpl::FileChanged(SourceLocation Loc,
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index 177feac974..e3263843e2 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -76,20 +76,19 @@ static void mergeFixits(ArrayRef<FixItHint> FixItHints,
}
}
-void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
+void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixItHints,
- const SourceManager *SM,
DiagOrStoredDiag D) {
- assert(SM || Loc.isInvalid());
+ assert(Loc.hasManager() || Loc.isInvalid());
beginDiagnostic(D, Level);
if (!Loc.isValid())
// If we have no source location, just emit the diagnostic message.
- emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D);
+ emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D);
else {
// Get the ranges into a local array we can hack on.
SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
@@ -97,7 +96,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
SmallVector<FixItHint, 8> MergedFixits;
if (!FixItHints.empty()) {
- mergeFixits(FixItHints, *SM, LangOpts, MergedFixits);
+ mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits);
FixItHints = MergedFixits;
}
@@ -107,25 +106,25 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
if (I->RemoveRange.isValid())
MutableRanges.push_back(I->RemoveRange);
- SourceLocation UnexpandedLoc = Loc;
+ FullSourceLoc UnexpandedLoc = Loc;
// Find the ultimate expansion location for the diagnostic.
- Loc = SM->getFileLoc(Loc);
+ Loc = Loc.getFileLoc();
- PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
// First, if this diagnostic is not in the main file, print out the
// "included from" lines.
- emitIncludeStack(Loc, PLoc, Level, *SM);
+ emitIncludeStack(Loc, PLoc, Level);
// Next, emit the actual diagnostic message and caret.
- emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
- emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
+ emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D);
+ emitCaret(Loc, Level, MutableRanges, FixItHints);
// If this location is within a macro, walk from UnexpandedLoc up to Loc
// and produce a macro backtrace.
if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
- emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM);
+ emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
}
}
@@ -139,15 +138,12 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
Diag.getRanges(), Diag.getFixIts(),
- Diag.getLocation().isValid() ? &Diag.getLocation().getManager()
- : nullptr,
&Diag);
}
void DiagnosticRenderer::emitBasicNote(StringRef Message) {
- emitDiagnosticMessage(
- SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message,
- None, nullptr, DiagOrStoredDiag());
+ emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note,
+ Message, None, DiagOrStoredDiag());
}
/// \brief Prints an include stack when appropriate for a particular
@@ -161,12 +157,11 @@ void DiagnosticRenderer::emitBasicNote(StringRef Message) {
/// \param Loc The diagnostic location.
/// \param PLoc The presumed location of the diagnostic location.
/// \param Level The diagnostic level of the message this stack pertains to.
-void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- const SourceManager &SM) {
- SourceLocation IncludeLoc =
- PLoc.isInvalid() ? SourceLocation() : PLoc.getIncludeLoc();
+void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level) {
+ FullSourceLoc IncludeLoc =
+ PLoc.isInvalid() ? FullSourceLoc()
+ : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
// Skip redundant include stacks altogether.
if (LastIncludeLoc == IncludeLoc)
@@ -178,74 +173,70 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
return;
if (IncludeLoc.isValid())
- emitIncludeStackRecursively(IncludeLoc, SM);
+ emitIncludeStackRecursively(IncludeLoc);
else {
- emitModuleBuildStack(SM);
- emitImportStack(Loc, SM);
+ emitModuleBuildStack(Loc.getManager());
+ emitImportStack(Loc);
}
}
/// \brief Helper to recursivly walk up the include stack and print each layer
/// on the way back down.
-void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
if (Loc.isInvalid()) {
- emitModuleBuildStack(SM);
+ emitModuleBuildStack(Loc.getManager());
return;
}
-
- PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
if (PLoc.isInvalid())
return;
// If this source location was imported from a module, print the module
// import stack rather than the
// FIXME: We want submodule granularity here.
- std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
+ std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc();
if (!Imported.second.empty()) {
// This location was imported by a module. Emit the module import stack.
- emitImportStackRecursively(Imported.first, Imported.second, SM);
+ emitImportStackRecursively(Imported.first, Imported.second);
return;
}
// Emit the other include frames first.
- emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
-
+ emitIncludeStackRecursively(
+ FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()));
+
// Emit the inclusion text/note.
- emitIncludeLocation(Loc, PLoc, SM);
+ emitIncludeLocation(Loc, PLoc);
}
/// \brief Emit the module import stack associated with the current location.
-void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) {
if (Loc.isInvalid()) {
- emitModuleBuildStack(SM);
+ emitModuleBuildStack(Loc.getManager());
return;
}
- std::pair<SourceLocation, StringRef> NextImportLoc
- = SM.getModuleImportLoc(Loc);
- emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+ std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
}
/// \brief Helper to recursivly walk up the import stack and print each layer
/// on the way back down.
-void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
+ StringRef ModuleName) {
if (ModuleName.empty()) {
return;
}
- PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
// Emit the other import frames first.
- std::pair<SourceLocation, StringRef> NextImportLoc
- = SM.getModuleImportLoc(Loc);
- emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+ std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
// Emit the inclusion text/note.
- emitImportLocation(Loc, PLoc, ModuleName, SM);
+ emitImportLocation(Loc, PLoc, ModuleName);
}
/// \brief Emit the module build stack, for cases where a module is (re-)built
@@ -253,13 +244,9 @@ void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
ModuleBuildStack Stack = SM.getModuleBuildStack();
for (unsigned I = 0, N = Stack.size(); I != N; ++I) {
- const SourceManager &CurSM = Stack[I].second.getManager();
- SourceLocation CurLoc = Stack[I].second;
- emitBuildingModuleLocation(CurLoc,
- CurSM.getPresumedLoc(CurLoc,
+ emitBuildingModuleLocation(Stack[I].second, Stack[I].second.getPresumedLoc(
DiagOpts->ShowPresumedLoc),
- Stack[I].first,
- CurSM);
+ Stack[I].first);
}
}
@@ -348,12 +335,12 @@ static void computeCommonMacroArgExpansionFileIDs(
// in the same expansion as the caret; otherwise, we crawl to the top of
// each chain. Two locations are part of the same macro expansion
// iff the FileID is the same.
-static void mapDiagnosticRanges(
- SourceLocation CaretLoc,
- ArrayRef<CharSourceRange> Ranges,
- SmallVectorImpl<CharSourceRange> &SpellingRanges,
- const SourceManager *SM) {
- FileID CaretLocFileID = SM->getFileID(CaretLoc);
+static void
+mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges,
+ SmallVectorImpl<CharSourceRange> &SpellingRanges) {
+ FileID CaretLocFileID = CaretLoc.getFileID();
+
+ const SourceManager *SM = &CaretLoc.getManager();
for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
if (I->isInvalid()) continue;
@@ -404,42 +391,39 @@ static void mapDiagnosticRanges(
}
}
-void DiagnosticRenderer::emitCaret(SourceLocation Loc,
+void DiagnosticRenderer::emitCaret(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ ArrayRef<FixItHint> Hints) {
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
- emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
+ emitCodeContext(Loc, Level, SpellingRanges, Hints);
}
/// \brief A helper function for emitMacroExpansion to print the
/// macro expansion message
void DiagnosticRenderer::emitSingleMacroExpansion(
- SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+ FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {
// Find the spelling location for the macro definition. We must use the
// spelling location here to avoid emitting a macro backtrace for the note.
- SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ FullSourceLoc SpellingLoc = Loc.getSpellingLoc();
// Map the ranges into the FileID of the diagnostic location.
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
SmallString<100> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- StringRef MacroName =
- Lexer::getImmediateMacroNameForDiagnostics(Loc, SM, LangOpts);
+ StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+ Loc, Loc.getManager(), LangOpts);
if (MacroName.empty())
Message << "expanded from here";
else
Message << "expanded from macro '" << MacroName << "'";
emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
- SpellingRanges, None, &SM);
+ SpellingRanges, None);
}
/// Check that the macro argument location of Loc starts with ArgumentLoc.
@@ -473,13 +457,12 @@ static bool checkRangeForMacroArgExpansion(CharSourceRange Range,
/// A helper function to check if the current ranges are all inside the same
/// macro argument expansion as Loc.
-static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc,
+ ArrayRef<CharSourceRange> Ranges) {
assert(Loc.isMacroID() && "Must be a macro expansion!");
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
/// Count all valid ranges.
unsigned ValidCount = 0;
@@ -490,15 +473,15 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
return false;
/// To store the source location of the argument location.
- SourceLocation ArgumentLoc;
+ FullSourceLoc ArgumentLoc;
/// Set the ArgumentLoc to the beginning location of the expansion of Loc
/// so to check if the ranges expands to the same beginning location.
- if (!SM.isMacroArgExpansion(Loc,&ArgumentLoc))
+ if (!Loc.isMacroArgExpansion(&ArgumentLoc))
return false;
for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) {
- if (!checkRangeForMacroArgExpansion(*I, SM, ArgumentLoc))
+ if (!checkRangeForMacroArgExpansion(*I, Loc.getManager(), ArgumentLoc))
return false;
}
@@ -516,34 +499,33 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
/// \param Level The diagnostic level currently being emitted.
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
-void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
+void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ ArrayRef<FixItHint> Hints) {
assert(Loc.isValid() && "must have a valid source location here");
// Produce a stack of macro backtraces.
- SmallVector<SourceLocation, 8> LocationStack;
+ SmallVector<FullSourceLoc, 8> LocationStack;
unsigned IgnoredEnd = 0;
while (Loc.isMacroID()) {
// If this is the expansion of a macro argument, point the caret at the
// use of the argument in the definition of the macro, not the expansion.
- if (SM.isMacroArgExpansion(Loc))
- LocationStack.push_back(SM.getImmediateExpansionRange(Loc).first);
+ if (Loc.isMacroArgExpansion())
+ LocationStack.push_back(Loc.getImmediateExpansionRange().first);
else
LocationStack.push_back(Loc);
- if (checkRangesForMacroArgExpansion(Loc, Ranges, SM))
+ if (checkRangesForMacroArgExpansion(Loc, Ranges))
IgnoredEnd = LocationStack.size();
- Loc = SM.getImmediateMacroCallerLoc(Loc);
+ Loc = Loc.getImmediateMacroCallerLoc();
// Once the location no longer points into a macro, try stepping through
// the last found location. This sometimes produces additional useful
// backtraces.
if (Loc.isFileID())
- Loc = SM.getImmediateMacroCallerLoc(LocationStack.back());
+ Loc = LocationStack.back().getImmediateMacroCallerLoc();
assert(Loc.isValid() && "must have a valid source location here");
}
@@ -555,7 +537,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
if (MacroDepth <= MacroLimit || MacroLimit == 0) {
for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
return;
}
@@ -565,7 +547,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
for (auto I = LocationStack.rbegin(),
E = LocationStack.rbegin() + MacroStartMessages;
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -577,26 +559,24 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
for (auto I = LocationStack.rend() - MacroEndMessages,
E = LocationStack.rend();
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
}
DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
-void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- const SourceManager &SM) {
+void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
Message << "in file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
-void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
+void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc,
PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+ StringRef ModuleName) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -605,14 +585,12 @@ void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
Message << "' imported from " << PLoc.getFilename() << ':'
<< PLoc.getLine();
Message << ":";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
-void
-DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -621,5 +599,5 @@ DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":";
else
Message << "while building module '" << ModuleName << "':";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 0dd07d9f81..12226b2314 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -136,6 +136,12 @@ void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput,
CurrentASTUnit = std::move(AST);
}
+Module *FrontendAction::getCurrentModule() const {
+ CompilerInstance &CI = getCompilerInstance();
+ return CI.getPreprocessor().getHeaderSearchInfo().lookupModule(
+ CI.getLangOpts().CurrentModule, /*AllowSearch*/false);
+}
+
std::unique_ptr<ASTConsumer>
FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
StringRef InFile) {
@@ -188,16 +194,25 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
-// For preprocessed files, if the first line is the linemarker and specifies
-// the original source file name, use that name as the input file name.
-static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile)
-{
- bool Invalid = false;
+/// For preprocessed files, if the first line is the linemarker and specifies
+/// the original source file name, use that name as the input file name.
+/// Returns the location of the first token after the line marker directive.
+///
+/// \param CI The compiler instance.
+/// \param InputFile Populated with the filename from the line marker.
+/// \param IsModuleMap If \c true, add a line note corresponding to this line
+/// directive. (We need to do this because the directive will not be
+/// visited by the preprocessor.)
+static SourceLocation ReadOriginalFileName(CompilerInstance &CI,
+ std::string &InputFile,
+ bool IsModuleMap = false) {
auto &SourceMgr = CI.getSourceManager();
auto MainFileID = SourceMgr.getMainFileID();
+
+ bool Invalid = false;
const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid);
if (Invalid)
- return false;
+ return SourceLocation();
std::unique_ptr<Lexer> RawLexer(
new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts()));
@@ -209,23 +224,294 @@ static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile)
// we use FILENAME as the input file name.
Token T;
if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash)
- return false;
+ return SourceLocation();
if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() ||
T.getKind() != tok::numeric_constant)
- return false;
+ return SourceLocation();
+
+ unsigned LineNo;
+ SourceLocation LineNoLoc = T.getLocation();
+ if (IsModuleMap) {
+ llvm::SmallString<16> Buffer;
+ if (Lexer::getSpelling(LineNoLoc, Buffer, SourceMgr, CI.getLangOpts())
+ .getAsInteger(10, LineNo))
+ return SourceLocation();
+ }
+
RawLexer->LexFromRawLexer(T);
if (T.isAtStartOfLine() || T.getKind() != tok::string_literal)
- return false;
+ return SourceLocation();
StringLiteralParser Literal(T, CI.getPreprocessor());
if (Literal.hadError)
- return false;
+ return SourceLocation();
+ RawLexer->LexFromRawLexer(T);
+ if (T.isNot(tok::eof) && !T.isAtStartOfLine())
+ return SourceLocation();
InputFile = Literal.GetString().str();
- return true;
+
+ if (IsModuleMap)
+ CI.getSourceManager().AddLineNote(
+ LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false,
+ false, SrcMgr::C_User_ModuleMap);
+
+ return T.getLocation();
+}
+
+static SmallVectorImpl<char> &
+operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
+ Includes.append(RHS.begin(), RHS.end());
+ return Includes;
+}
+
+static void addHeaderInclude(StringRef HeaderName,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts,
+ bool IsExternC) {
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "extern \"C\" {\n";
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+
+ Includes += HeaderName;
+
+ Includes += "\"\n";
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "}\n";
+}
+
+/// \brief Collect the set of header includes needed to construct the given
+/// module and update the TopHeaders file set of the module.
+///
+/// \param Module The module we're collecting includes from.
+///
+/// \param Includes Will be augmented with the set of \#includes or \#imports
+/// needed to load all of the named headers.
+static std::error_code collectModuleHeaderIncludes(
+ const LangOptions &LangOpts, FileManager &FileMgr, DiagnosticsEngine &Diag,
+ ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) {
+ // Don't collect any headers for unavailable modules.
+ if (!Module->isAvailable())
+ return std::error_code();
+
+ // Resolve all lazy header directives to header files.
+ ModMap.resolveHeaderDirectives(Module);
+
+ // If any headers are missing, we can't build this module. In most cases,
+ // diagnostics for this should have already been produced; we only get here
+ // if explicit stat information was provided.
+ // FIXME: If the name resolves to a file with different stat information,
+ // produce a better diagnostic.
+ if (!Module->MissingHeaders.empty()) {
+ auto &MissingHeader = Module->MissingHeaders.front();
+ Diag.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing)
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ return std::error_code();
+ }
+
+ // Add includes for each of these headers.
+ for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
+ for (Module::Header &H : Module->Headers[HK]) {
+ Module->addTopHeader(H.Entry);
+ // Use the path as specified in the module map file. We'll look for this
+ // file relative to the module build directory (the directory containing
+ // the module map file) so this will find the same file that we found
+ // while parsing the module map.
+ addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
+ }
+ }
+ // Note that Module->PrivateHeaders will not be a TopHeader.
+
+ if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
+ Module->addTopHeader(UmbrellaHeader.Entry);
+ if (Module->Parent)
+ // Include the umbrella header for submodules.
+ addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
+ Module->IsExternC);
+ } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
+ // Add all of the headers we find in this subdirectory.
+ std::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
+
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
+ Dir != End && !EC; Dir.increment(EC)) {
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ const FileEntry *Header = FileMgr.getFile(Dir->getName());
+ // FIXME: This shouldn't happen unless there is a file system race. Is
+ // that worth diagnosing?
+ if (!Header)
+ continue;
+
+ // If this header is marked 'unavailable' in this module, don't include
+ // it.
+ if (ModMap.isHeaderUnavailableInModule(Header, Module))
+ continue;
+
+ // Compute the relative path from the directory to this file.
+ SmallVector<StringRef, 16> Components;
+ auto PathIt = llvm::sys::path::rbegin(Dir->getName());
+ for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
+ Components.push_back(*PathIt);
+ SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
+ for (auto It = Components.rbegin(), End = Components.rend(); It != End;
+ ++It)
+ llvm::sys::path::append(RelativeHeader, *It);
+
+ // Include this header as part of the umbrella directory.
+ Module->addTopHeader(Header);
+ addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
+ }
+
+ if (EC)
+ return EC;
+ }
+
+ // Recurse into submodules.
+ for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
+ SubEnd = Module->submodule_end();
+ Sub != SubEnd; ++Sub)
+ if (std::error_code Err = collectModuleHeaderIncludes(
+ LangOpts, FileMgr, Diag, ModMap, *Sub, Includes))
+ return Err;
+
+ return std::error_code();
+}
+
+static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem,
+ bool IsPreprocessed,
+ std::string &PresumedModuleMapFile,
+ unsigned &Offset) {
+ auto &SrcMgr = CI.getSourceManager();
+ HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+
+ // Map the current input to a file.
+ FileID ModuleMapID = SrcMgr.getMainFileID();
+ const FileEntry *ModuleMap = SrcMgr.getFileEntryForID(ModuleMapID);
+
+ // If the module map is preprocessed, handle the initial line marker;
+ // line directives are not part of the module map syntax in general.
+ Offset = 0;
+ if (IsPreprocessed) {
+ SourceLocation EndOfLineMarker =
+ ReadOriginalFileName(CI, PresumedModuleMapFile, /*IsModuleMap*/ true);
+ if (EndOfLineMarker.isValid())
+ Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second;
+ }
+
+ // Load the module map file.
+ if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset,
+ PresumedModuleMapFile))
+ return true;
+
+ if (SrcMgr.getBuffer(ModuleMapID)->getBufferSize() == Offset)
+ Offset = 0;
+
+ return false;
+}
+
+static Module *prepareToBuildModule(CompilerInstance &CI,
+ StringRef ModuleMapFilename) {
+ if (CI.getLangOpts().CurrentModule.empty()) {
+ CI.getDiagnostics().Report(diag::err_missing_module_name);
+
+ // FIXME: Eventually, we could consider asking whether there was just
+ // a single module described in the module map, and use that as a
+ // default. Then it would be fairly trivial to just "compile" a module
+ // map with a single module (the common case).
+ return nullptr;
+ }
+
+ // Dig out the module definition.
+ HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+ Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule,
+ /*AllowSearch=*/false);
+ if (!M) {
+ CI.getDiagnostics().Report(diag::err_missing_module)
+ << CI.getLangOpts().CurrentModule << ModuleMapFilename;
+
+ return nullptr;
+ }
+
+ // Check whether we can build this module at all.
+ if (Preprocessor::checkModuleIsAvailable(CI.getLangOpts(), CI.getTarget(),
+ CI.getDiagnostics(), M))
+ return nullptr;
+
+ // Inform the preprocessor that includes from within the input buffer should
+ // be resolved relative to the build directory of the module map file.
+ CI.getPreprocessor().setMainFileDir(M->Directory);
+
+ // If the module was inferred from a different module map (via an expanded
+ // umbrella module definition), track that fact.
+ // FIXME: It would be preferable to fill this in as part of processing
+ // the module map, rather than adding it after the fact.
+ StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap;
+ if (!OriginalModuleMapName.empty()) {
+ auto *OriginalModuleMap =
+ CI.getFileManager().getFile(OriginalModuleMapName,
+ /*openFile*/ true);
+ if (!OriginalModuleMap) {
+ CI.getDiagnostics().Report(diag::err_module_map_not_found)
+ << OriginalModuleMapName;
+ return nullptr;
+ }
+ if (OriginalModuleMap != CI.getSourceManager().getFileEntryForID(
+ CI.getSourceManager().getMainFileID())) {
+ M->IsInferred = true;
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()
+ .setInferredModuleAllowedBy(M, OriginalModuleMap);
+ }
+ }
+
+ // If we're being run from the command-line, the module build stack will not
+ // have been filled in yet, so complete it now in order to allow us to detect
+ // module cycles.
+ SourceManager &SourceMgr = CI.getSourceManager();
+ if (SourceMgr.getModuleBuildStack().empty())
+ SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule,
+ FullSourceLoc(SourceLocation(), SourceMgr));
+ return M;
+}
+
+/// Compute the input buffer that should be used to build the specified module.
+static std::unique_ptr<llvm::MemoryBuffer>
+getInputBufferForModule(CompilerInstance &CI, Module *M) {
+ FileManager &FileMgr = CI.getFileManager();
+
+ // Collect the set of #includes we need to build the module.
+ SmallString<256> HeaderContents;
+ std::error_code Err = std::error_code();
+ if (Module::Header UmbrellaHeader = M->getUmbrellaHeader())
+ addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
+ CI.getLangOpts(), M->IsExternC);
+ Err = collectModuleHeaderIncludes(
+ CI.getLangOpts(), FileMgr, CI.getDiagnostics(),
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M,
+ HeaderContents);
+
+ if (Err) {
+ CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
+ << M->getFullModuleName() << Err.message();
+ return nullptr;
+ }
+
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ HeaderContents, Module::getModuleInputBufferName());
}
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
- const FrontendInputFile &Input) {
+ const FrontendInputFile &RealInput) {
+ FrontendInputFile Input(RealInput);
assert(!Instance && "Already processing a source file!");
assert(!Input.isEmpty() && "Unexpected empty filename!");
setCurrentInput(Input);
@@ -233,22 +519,88 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
StringRef InputFile = Input.getFile();
bool HasBegunSourceFile = false;
+ bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled &&
+ usesPreprocessorOnly();
if (!BeginInvocation(CI))
goto failure;
+ // If we're replaying the build of an AST file, import it and set up
+ // the initial state from its build.
+ if (ReplayASTFile) {
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
+
+ // The AST unit populates its own diagnostics engine rather than ours.
+ IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(
+ new DiagnosticsEngine(Diags->getDiagnosticIDs(),
+ &Diags->getDiagnosticOptions()));
+ ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
+
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
+ InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
+ ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
+ if (!AST)
+ goto failure;
+
+ // Options relating to how we treat the input (but not what we do with it)
+ // are inherited from the AST unit.
+ CI.getHeaderSearchOpts() = AST->getHeaderSearchOpts();
+ CI.getPreprocessorOpts() = AST->getPreprocessorOpts();
+ CI.getLangOpts() = AST->getLangOpts();
+
+ // Set the shared objects, these are reset when we finish processing the
+ // file, otherwise the CompilerInstance will happily destroy them.
+ CI.setFileManager(&AST->getFileManager());
+ CI.createSourceManager(CI.getFileManager());
+ CI.getSourceManager().initializeForReplay(AST->getSourceManager());
+
+ // Preload all the module files loaded transitively by the AST unit. Also
+ // load all module map files that were parsed as part of building the AST
+ // unit.
+ if (auto ASTReader = AST->getASTReader()) {
+ auto &MM = ASTReader->getModuleManager();
+ auto &PrimaryModule = MM.getPrimaryModule();
+
+ for (ModuleFile &MF : MM)
+ if (&MF != &PrimaryModule)
+ CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName);
+
+ ASTReader->visitTopLevelModuleMaps(PrimaryModule,
+ [&](const FileEntry *FE) {
+ CI.getFrontendOpts().ModuleMapFiles.push_back(FE->getName());
+ });
+ }
+
+ // Set up the input file for replay purposes.
+ auto Kind = AST->getInputKind();
+ if (Kind.getFormat() == InputKind::ModuleMap) {
+ Module *ASTModule =
+ AST->getPreprocessor().getHeaderSearchInfo().lookupModule(
+ AST->getLangOpts().CurrentModule, /*AllowSearch*/ false);
+ assert(ASTModule && "module file does not define its own module");
+ Input = FrontendInputFile(ASTModule->PresumedModuleMapFile, Kind);
+ } else {
+ auto &SM = CI.getSourceManager();
+ FileID ID = SM.getMainFileID();
+ if (auto *File = SM.getFileEntryForID(ID))
+ Input = FrontendInputFile(File->getName(), Kind);
+ else
+ Input = FrontendInputFile(SM.getBuffer(ID), Kind);
+ }
+ setCurrentInput(Input, std::move(AST));
+ }
+
// AST files follow a very different path, since they share objects via the
// AST unit.
- if (Input.getKind() == IK_AST) {
- assert(!usesPreprocessorOnly() &&
- "Attempt to pass AST file to preprocessor only action!");
+ if (Input.getKind().getFormat() == InputKind::Precompiled) {
+ assert(!usesPreprocessorOnly() && "this case was handled above");
assert(hasASTFileSupport() &&
"This action does not have AST file support!");
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
- InputFile, CI.getPCHContainerReader(), Diags, CI.getFileSystemOpts(),
- CI.getCodeGenOpts().DebugTypeExtRefs);
+ InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+ CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
if (!AST)
goto failure;
@@ -270,7 +622,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
setCurrentInput(Input, std::move(AST));
// Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ if (!BeginSourceFileAction(CI))
goto failure;
// Create the AST consumer.
@@ -281,23 +633,28 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
return true;
}
- if (!CI.hasVirtualFileSystem()) {
- if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
- createVFSFromCompilerInvocation(CI.getInvocation(),
- CI.getDiagnostics()))
- CI.setVirtualFileSystem(VFS);
- else
+ // Set up the file and source managers, if needed.
+ if (!CI.hasFileManager()) {
+ if (!CI.createFileManager()) {
goto failure;
+ }
}
-
- // Set up the file and source managers, if needed.
- if (!CI.hasFileManager())
- CI.createFileManager();
if (!CI.hasSourceManager())
CI.createSourceManager(CI.getFileManager());
+ // Set up embedding for any specified files. Do this before we load any
+ // source files, including the primary module map for the compilation.
+ for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
+ if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
+ CI.getSourceManager().setFileIsTransient(FE);
+ else
+ CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
+ }
+ if (CI.getFrontendOpts().ModulesEmbedAllFiles)
+ CI.getSourceManager().setAllFilesAreTransient(true);
+
// IR files bypass the rest of initialization.
- if (Input.getKind() == IK_LLVM_IR) {
+ if (Input.getKind().getLanguage() == InputKind::LLVM_IR) {
assert(hasIRSupport() &&
"This action does not have IR file support!");
@@ -306,7 +663,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
HasBegunSourceFile = true;
// Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ if (!BeginSourceFileAction(CI))
goto failure;
// Initialize the main file entry.
@@ -359,13 +716,48 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
&CI.getPreprocessor());
HasBegunSourceFile = true;
- // Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ // Initialize the main file entry.
+ if (!CI.InitializeSourceManager(Input))
goto failure;
- // Initialize the main file entry. It is important that this occurs after
- // BeginSourceFileAction, which may change CurrentInput during module builds.
- if (!CI.InitializeSourceManager(CurrentInput))
+ // For module map files, we first parse the module map and synthesize a
+ // "<module-includes>" buffer before more conventional processing.
+ if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
+
+ std::string PresumedModuleMapFile;
+ unsigned OffsetToContents;
+ if (loadModuleMapForModuleBuild(CI, Input.isSystem(),
+ Input.isPreprocessed(),
+ PresumedModuleMapFile, OffsetToContents))
+ goto failure;
+
+ auto *CurrentModule = prepareToBuildModule(CI, Input.getFile());
+ if (!CurrentModule)
+ goto failure;
+
+ CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile;
+
+ if (OffsetToContents)
+ // If the module contents are in the same file, skip to them.
+ CI.getPreprocessor().setSkipMainFilePreamble(OffsetToContents, true);
+ else {
+ // Otherwise, convert the module description to a suitable input buffer.
+ auto Buffer = getInputBufferForModule(CI, CurrentModule);
+ if (!Buffer)
+ goto failure;
+
+ // Reinitialize the main file entry to refer to the new input.
+ auto Kind = CurrentModule->IsSystem ? SrcMgr::C_System : SrcMgr::C_User;
+ auto &SourceMgr = CI.getSourceManager();
+ auto BufferID = SourceMgr.createFileID(std::move(Buffer), Kind);
+ assert(BufferID.isValid() && "couldn't creaate module buffer ID");
+ SourceMgr.setMainFileID(BufferID);
+ }
+ }
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI))
goto failure;
// Create the AST context and consumer unless this is a preprocessor only
@@ -377,13 +769,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// For preprocessed files, check if the first line specifies the original
// source file name with a linemarker.
- std::string OrigFile;
+ std::string PresumedInputFile = InputFile;
if (Input.isPreprocessed())
- if (ReadOriginalFileName(CI, OrigFile))
- InputFile = OrigFile;
+ ReadOriginalFileName(CI, PresumedInputFile);
std::unique_ptr<ASTConsumer> Consumer =
- CreateWrappedASTConsumer(CI, InputFile);
+ CreateWrappedASTConsumer(CI, PresumedInputFile);
if (!Consumer)
goto failure;
@@ -486,17 +877,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If we failed, reset state since the client will not end up calling the
// matching EndSourceFile().
- failure:
- if (isCurrentFileAST()) {
- CI.setASTContext(nullptr);
- CI.setPreprocessor(nullptr);
- CI.setSourceManager(nullptr);
- CI.setFileManager(nullptr);
- }
-
+failure:
if (HasBegunSourceFile)
CI.getDiagnosticClient().EndSourceFile();
CI.clearOutputFiles(/*EraseFiles=*/true);
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
setCurrentInput(FrontendInputFile());
setCompilerInstance(nullptr);
return false;
@@ -570,6 +955,7 @@ void FrontendAction::EndSourceFile() {
CI.resetAndLeakPreprocessor();
CI.resetAndLeakSourceManager();
CI.resetAndLeakFileManager();
+ BuryPointer(CurrentASTUnit.release());
} else {
CI.setPreprocessor(nullptr);
CI.setSourceManager(nullptr);
@@ -579,6 +965,7 @@ void FrontendAction::EndSourceFile() {
setCompilerInstance(nullptr);
setCurrentInput(FrontendInputFile());
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
}
bool FrontendAction::shouldEraseOutputFiles() {
@@ -628,11 +1015,10 @@ WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
return WrappedAction->BeginInvocation(CI);
}
-bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI) {
WrappedAction->setCurrentInput(getCurrentInput());
WrappedAction->setCompilerInstance(&CI);
- auto Ret = WrappedAction->BeginSourceFileAction(CI, Filename);
+ auto Ret = WrappedAction->BeginSourceFileAction(CI);
// BeginSourceFileAction may change CurrentInput, e.g. during module builds.
setCurrentInput(WrappedAction->getCurrentInput());
return Ret;
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index e818038b13..86460f17d0 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -134,8 +134,7 @@ bool GeneratePCHAction::shouldEraseOutputFiles() {
return ASTFrontendAction::shouldEraseOutputFiles();
}
-bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
CI.getLangOpts().CompilingPCH = true;
return true;
}
@@ -164,242 +163,14 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
-bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
- // Set up embedding for any specified files. Do this before we load any
- // source files, including the primary module map for the compilation.
- for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
- if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
- CI.getSourceManager().setFileIsTransient(FE);
- else
- CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
- }
- if (CI.getFrontendOpts().ModulesEmbedAllFiles)
- CI.getSourceManager().setAllFilesAreTransient(true);
-
- return true;
-}
-
-
-static SmallVectorImpl<char> &
-operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
- Includes.append(RHS.begin(), RHS.end());
- return Includes;
-}
-
-static void addHeaderInclude(StringRef HeaderName,
- SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts,
- bool IsExternC) {
- if (IsExternC && LangOpts.CPlusPlus)
- Includes += "extern \"C\" {\n";
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
-
- Includes += HeaderName;
-
- Includes += "\"\n";
- if (IsExternC && LangOpts.CPlusPlus)
- Includes += "}\n";
-}
-
-/// \brief Collect the set of header includes needed to construct the given
-/// module and update the TopHeaders file set of the module.
-///
-/// \param Module The module we're collecting includes from.
-///
-/// \param Includes Will be augmented with the set of \#includes or \#imports
-/// needed to load all of the named headers.
-static std::error_code
-collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
- ModuleMap &ModMap, clang::Module *Module,
- SmallVectorImpl<char> &Includes) {
- // Don't collect any headers for unavailable modules.
- if (!Module->isAvailable())
- return std::error_code();
-
- // Add includes for each of these headers.
- for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
- for (Module::Header &H : Module->Headers[HK]) {
- Module->addTopHeader(H.Entry);
- // Use the path as specified in the module map file. We'll look for this
- // file relative to the module build directory (the directory containing
- // the module map file) so this will find the same file that we found
- // while parsing the module map.
- addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
- }
- }
- // Note that Module->PrivateHeaders will not be a TopHeader.
-
- if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
- Module->addTopHeader(UmbrellaHeader.Entry);
- if (Module->Parent)
- // Include the umbrella header for submodules.
- addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
- Module->IsExternC);
- } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
- // Add all of the headers we find in this subdirectory.
- std::error_code EC;
- SmallString<128> DirNative;
- llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
-
- vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
- for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
- Dir != End && !EC; Dir.increment(EC)) {
- // Check whether this entry has an extension typically associated with
- // headers.
- if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
- .Cases(".h", ".H", ".hh", ".hpp", true)
- .Default(false))
- continue;
-
- const FileEntry *Header = FileMgr.getFile(Dir->getName());
- // FIXME: This shouldn't happen unless there is a file system race. Is
- // that worth diagnosing?
- if (!Header)
- continue;
-
- // If this header is marked 'unavailable' in this module, don't include
- // it.
- if (ModMap.isHeaderUnavailableInModule(Header, Module))
- continue;
-
- // Compute the relative path from the directory to this file.
- SmallVector<StringRef, 16> Components;
- auto PathIt = llvm::sys::path::rbegin(Dir->getName());
- for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
- Components.push_back(*PathIt);
- SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
- for (auto It = Components.rbegin(), End = Components.rend(); It != End;
- ++It)
- llvm::sys::path::append(RelativeHeader, *It);
-
- // Include this header as part of the umbrella directory.
- Module->addTopHeader(Header);
- addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
- }
-
- if (EC)
- return EC;
- }
-
- // Recurse into submodules.
- for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
- SubEnd = Module->submodule_end();
- Sub != SubEnd; ++Sub)
- if (std::error_code Err = collectModuleHeaderIncludes(
- LangOpts, FileMgr, ModMap, *Sub, Includes))
- return Err;
-
- return std::error_code();
-}
-
bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
- CompilerInstance &CI, StringRef Filename) {
- CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
-
- if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename))
- return false;
-
- // Find the module map file.
- const FileEntry *ModuleMap =
- CI.getFileManager().getFile(Filename, /*openFile*/true);
- if (!ModuleMap) {
- CI.getDiagnostics().Report(diag::err_module_map_not_found)
- << Filename;
- return false;
- }
-
- // Parse the module map file.
- HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
- if (HS.loadModuleMapFile(ModuleMap, IsSystem))
- return false;
-
- if (CI.getLangOpts().CurrentModule.empty()) {
- CI.getDiagnostics().Report(diag::err_missing_module_name);
-
- // FIXME: Eventually, we could consider asking whether there was just
- // a single module described in the module map, and use that as a
- // default. Then it would be fairly trivial to just "compile" a module
- // map with a single module (the common case).
- return false;
- }
-
- // If we're being run from the command-line, the module build stack will not
- // have been filled in yet, so complete it now in order to allow us to detect
- // module cycles.
- SourceManager &SourceMgr = CI.getSourceManager();
- if (SourceMgr.getModuleBuildStack().empty())
- SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule,
- FullSourceLoc(SourceLocation(), SourceMgr));
-
- // Dig out the module definition.
- Module = HS.lookupModule(CI.getLangOpts().CurrentModule,
- /*AllowSearch=*/false);
- if (!Module) {
- CI.getDiagnostics().Report(diag::err_missing_module)
- << CI.getLangOpts().CurrentModule << Filename;
-
- return false;
- }
-
- // Check whether we can build this module at all.
- clang::Module::Requirement Requirement;
- clang::Module::UnresolvedHeaderDirective MissingHeader;
- if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
- MissingHeader)) {
- if (MissingHeader.FileNameLoc.isValid()) {
- CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
- diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- CI.getDiagnostics().Report(diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first;
- }
-
- return false;
- }
-
- if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) {
- Module->IsInferred = true;
- HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing);
- } else {
- ModuleMapForUniquing = ModuleMap;
- }
-
- FileManager &FileMgr = CI.getFileManager();
-
- // Collect the set of #includes we need to build the module.
- SmallString<256> HeaderContents;
- std::error_code Err = std::error_code();
- if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader())
- addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
- CI.getLangOpts(), Module->IsExternC);
- Err = collectModuleHeaderIncludes(
- CI.getLangOpts(), FileMgr,
- CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module,
- HeaderContents);
-
- if (Err) {
- CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
- << Module->getFullModuleName() << Err.message();
+ CompilerInstance &CI) {
+ if (!CI.getLangOpts().Modules) {
+ CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules);
return false;
}
- // Inform the preprocessor that includes from within the input buffer should
- // be resolved relative to the build directory of the module map file.
- CI.getPreprocessor().setMainFileDir(Module->Directory);
-
- std::unique_ptr<llvm::MemoryBuffer> InputBuffer =
- llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
- Module::getModuleInputBufferName());
- // Ownership of InputBuffer will be transferred to the SourceManager.
- setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(),
- Module->IsSystem));
- return true;
+ return GenerateModuleAction::BeginSourceFileAction(CI);
}
std::unique_ptr<raw_pwrite_stream>
@@ -408,11 +179,14 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
// If no output file was provided, figure out where this module would go
// in the module cache.
if (CI.getFrontendOpts().OutputFile.empty()) {
+ StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap;
+ if (ModuleMapFile.empty())
+ ModuleMapFile = InFile;
+
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
CI.getFrontendOpts().OutputFile =
- HS.getModuleFileName(CI.getLangOpts().CurrentModule,
- ModuleMapForUniquing->getName(),
- /*UsePrebuiltPath=*/false);
+ HS.getCachedModuleFileName(CI.getLangOpts().CurrentModule,
+ ModuleMapFile);
}
// We use createOutputFile here because this is exposed via libclang, and we
@@ -424,8 +198,8 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
/*CreateMissingDirectories=*/true);
}
-bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool GenerateModuleInterfaceAction::BeginSourceFileAction(
+ CompilerInstance &CI) {
if (!CI.getLangOpts().ModulesTS) {
CI.getDiagnostics().Report(diag::err_module_interface_requires_modules_ts);
return false;
@@ -433,7 +207,7 @@ bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI,
CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
- return GenerateModuleAction::BeginSourceFileAction(CI, Filename);
+ return GenerateModuleAction::BeginSourceFileAction(CI);
}
std::unique_ptr<raw_pwrite_stream>
@@ -466,7 +240,7 @@ void VerifyPCHAction::ExecuteAction() {
bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
std::unique_ptr<ASTReader> Reader(new ASTReader(
- CI.getPreprocessor(), CI.getASTContext(), CI.getPCHContainerReader(),
+ CI.getPreprocessor(), &CI.getASTContext(), CI.getPCHContainerReader(),
CI.getFrontendOpts().ModuleFileExtensions,
Sysroot.empty() ? "" : Sysroot.c_str(),
/*DisableValidation*/ false,
@@ -753,7 +527,7 @@ void PrintPreprocessedAction::ExecuteAction() {
// file. This is mostly a sanity check in case the file has no
// newlines whatsoever.
if (end - cur > 256) end = cur + 256;
-
+
while (next < end) {
if (*cur == 0x0D) { // CR
if (*next == 0x0A) // CRLF
@@ -772,39 +546,52 @@ void PrintPreprocessedAction::ExecuteAction() {
CI.createDefaultOutputFile(BinaryMode, getCurrentFile());
if (!OS) return;
+ // If we're preprocessing a module map, start by dumping the contents of the
+ // module itself before switching to the input buffer.
+ auto &Input = getCurrentInput();
+ if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+ if (Input.isFile()) {
+ (*OS) << "# 1 \"";
+ OS->write_escaped(Input.getFile());
+ (*OS) << "\"\n";
+ }
+ // FIXME: Include additional information here so that we don't need the
+ // original source files to exist on disk.
+ getCurrentModule()->print(*OS);
+ (*OS) << "#pragma clang module contents\n";
+ }
+
DoPrintPreprocessedInput(CI.getPreprocessor(), OS.get(),
CI.getPreprocessorOutputOpts());
}
void PrintPreambleAction::ExecuteAction() {
- switch (getCurrentFileKind()) {
- case IK_C:
- case IK_CXX:
- case IK_ObjC:
- case IK_ObjCXX:
- case IK_OpenCL:
- case IK_CUDA:
+ switch (getCurrentFileKind().getLanguage()) {
+ case InputKind::C:
+ case InputKind::CXX:
+ case InputKind::ObjC:
+ case InputKind::ObjCXX:
+ case InputKind::OpenCL:
+ case InputKind::CUDA:
break;
- case IK_None:
- case IK_Asm:
- case IK_PreprocessedC:
- case IK_PreprocessedCuda:
- case IK_PreprocessedCXX:
- case IK_PreprocessedObjC:
- case IK_PreprocessedObjCXX:
- case IK_AST:
- case IK_LLVM_IR:
- case IK_RenderScript:
+ case InputKind::Unknown:
+ case InputKind::Asm:
+ case InputKind::LLVM_IR:
+ case InputKind::RenderScript:
// We can't do anything with these.
return;
}
+ // We don't expect to find any #include directives in a preprocessed input.
+ if (getCurrentFileKind().isPreprocessed())
+ return;
+
CompilerInstance &CI = getCompilerInstance();
auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile());
if (Buffer) {
unsigned Preamble =
- Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).first;
+ Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).Size;
llvm::outs().write((*Buffer)->getBufferStart(), Preamble);
}
}
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index 6a82084aff..dca434588f 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -13,22 +13,22 @@ using namespace clang;
InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
return llvm::StringSwitch<InputKind>(Extension)
- .Cases("ast", "pcm", IK_AST)
- .Case("c", IK_C)
- .Cases("S", "s", IK_Asm)
- .Case("i", IK_PreprocessedC)
- .Case("ii", IK_PreprocessedCXX)
- .Case("cui", IK_PreprocessedCuda)
- .Case("m", IK_ObjC)
- .Case("mi", IK_PreprocessedObjC)
- .Cases("mm", "M", IK_ObjCXX)
- .Case("mii", IK_PreprocessedObjCXX)
- .Cases("C", "cc", "cp", IK_CXX)
- .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
- .Case("cppm", IK_CXX)
- .Case("iim", IK_PreprocessedCXX)
- .Case("cl", IK_OpenCL)
- .Case("cu", IK_CUDA)
- .Cases("ll", "bc", IK_LLVM_IR)
- .Default(IK_C);
+ .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled))
+ .Case("c", InputKind::C)
+ .Cases("S", "s", InputKind::Asm)
+ .Case("i", InputKind(InputKind::C).getPreprocessed())
+ .Case("ii", InputKind(InputKind::CXX).getPreprocessed())
+ .Case("cui", InputKind(InputKind::CUDA).getPreprocessed())
+ .Case("m", InputKind::ObjC)
+ .Case("mi", InputKind(InputKind::ObjC).getPreprocessed())
+ .Cases("mm", "M", InputKind::ObjCXX)
+ .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed())
+ .Cases("C", "cc", "cp", InputKind::CXX)
+ .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX)
+ .Case("cppm", InputKind::CXX)
+ .Case("iim", InputKind(InputKind::CXX).getPreprocessed())
+ .Case("cl", InputKind::OpenCL)
+ .Case("cu", InputKind::CUDA)
+ .Cases("ll", "bc", InputKind::LLVM_IR)
+ .Default(InputKind::Unknown);
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index d50fb6d788..8c6faced76 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -213,7 +213,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
- case llvm::Triple::Bitrig:
case llvm::Triple::NaCl:
case llvm::Triple::PS4:
case llvm::Triple::ELFIAMCU:
@@ -221,6 +220,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus)
break;
+ LLVM_FALLTHROUGH;
default:
// FIXME: temporary hack: hard-coded paths.
AddPath("/usr/local/include", System, false);
@@ -343,6 +343,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath(BaseSDKPath + "/target/include", System, false);
if (triple.isPS4CPU())
AddPath(BaseSDKPath + "/target/include_common", System, false);
+ LLVM_FALLTHROUGH;
}
default:
AddPath("/usr/include", ExternCSystem, false);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 749dd9b951..1dfbf18755 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -14,6 +14,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SyncScope.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -109,9 +110,11 @@ static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP,
/// PickFP - This is used to pick a value based on the FP semantics of the
/// specified FP model.
template <typename T>
-static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
+static T PickFP(const llvm::fltSemantics *Sem, T IEEEHalfVal, T IEEESingleVal,
T IEEEDoubleVal, T X87DoubleExtendedVal, T PPCDoubleDoubleVal,
T IEEEQuadVal) {
+ if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEhalf())
+ return IEEEHalfVal;
if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle())
return IEEESingleVal;
if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEdouble())
@@ -127,26 +130,26 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
const llvm::fltSemantics *Sem, StringRef Ext) {
const char *DenormMin, *Epsilon, *Max, *Min;
- DenormMin = PickFP(Sem, "1.40129846e-45", "4.9406564584124654e-324",
- "3.64519953188247460253e-4951",
+ DenormMin = PickFP(Sem, "5.9604644775390625e-8", "1.40129846e-45",
+ "4.9406564584124654e-324", "3.64519953188247460253e-4951",
"4.94065645841246544176568792868221e-324",
"6.47517511943802511092443895822764655e-4966");
- int Digits = PickFP(Sem, 6, 15, 18, 31, 33);
- int DecimalDigits = PickFP(Sem, 9, 17, 21, 33, 36);
- Epsilon = PickFP(Sem, "1.19209290e-7", "2.2204460492503131e-16",
- "1.08420217248550443401e-19",
+ int Digits = PickFP(Sem, 3, 6, 15, 18, 31, 33);
+ int DecimalDigits = PickFP(Sem, 5, 9, 17, 21, 33, 36);
+ Epsilon = PickFP(Sem, "9.765625e-4", "1.19209290e-7",
+ "2.2204460492503131e-16", "1.08420217248550443401e-19",
"4.94065645841246544176568792868221e-324",
"1.92592994438723585305597794258492732e-34");
- int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113);
- int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931);
- int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932);
- int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381);
- int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384);
- Min = PickFP(Sem, "1.17549435e-38", "2.2250738585072014e-308",
+ int MantissaDigits = PickFP(Sem, 11, 24, 53, 64, 106, 113);
+ int Min10Exp = PickFP(Sem, -13, -37, -307, -4931, -291, -4931);
+ int Max10Exp = PickFP(Sem, 4, 38, 308, 4932, 308, 4932);
+ int MinExp = PickFP(Sem, -14, -125, -1021, -16381, -968, -16381);
+ int MaxExp = PickFP(Sem, 15, 128, 1024, 16384, 1024, 16384);
+ Min = PickFP(Sem, "6.103515625e-5", "1.17549435e-38", "2.2250738585072014e-308",
"3.36210314311209350626e-4932",
"2.00416836000897277799610805135016e-292",
"3.36210314311209350626267781732175260e-4932");
- Max = PickFP(Sem, "3.40282347e+38", "1.7976931348623157e+308",
+ Max = PickFP(Sem, "6.5504e+4", "3.40282347e+38", "1.7976931348623157e+308",
"1.18973149535723176502e+4932",
"1.79769313486231580793728971405301e+308",
"1.18973149535723176508575932662800702e+4932");
@@ -374,9 +377,14 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
} else {
- // FIXME: Use correct value for C++17.
- if (LangOpts.CPlusPlus1z)
- Builder.defineMacro("__cplusplus", "201406L");
+ // FIXME: Use correct value for C++20.
+ if (LangOpts.CPlusPlus2a)
+ Builder.defineMacro("__cplusplus", "201707L");
+ // C++17 [cpp.predefined]p1:
+ // The name __cplusplus is defined to the value 201703L when compiling a
+ // C++ translation unit.
+ else if (LangOpts.CPlusPlus1z)
+ Builder.defineMacro("__cplusplus", "201703L");
// C++1y [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201402L when compiling a
// C++ translation unit.
@@ -492,6 +500,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_ref_qualifiers", "200710");
Builder.defineMacro("__cpp_alias_templates", "200704");
}
+ if (LangOpts.ThreadsafeStatics)
+ Builder.defineMacro("__cpp_threadsafe_static_init", "200806");
// C++14 features.
if (LangOpts.CPlusPlus14) {
@@ -514,6 +524,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_noexcept_function_type", "201510");
Builder.defineMacro("__cpp_capture_star_this", "201603");
Builder.defineMacro("__cpp_if_constexpr", "201606");
+ Builder.defineMacro("__cpp_deduction_guides", "201611");
Builder.defineMacro("__cpp_template_auto", "201606");
Builder.defineMacro("__cpp_namespace_attributes", "201411");
Builder.defineMacro("__cpp_enumerator_attributes", "201411");
@@ -523,8 +534,6 @@ 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");
@@ -533,7 +542,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
if (LangOpts.ConceptsTS)
Builder.defineMacro("__cpp_experimental_concepts", "1");
if (LangOpts.CoroutinesTS)
- Builder.defineMacro("__cpp_coroutines", "1");
+ Builder.defineMacro("__cpp_coroutines", "201703L");
}
static void InitializePredefinedMacros(const TargetInfo &TI,
@@ -570,6 +579,20 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__ATOMIC_ACQ_REL", "4");
Builder.defineMacro("__ATOMIC_SEQ_CST", "5");
+ // Define macros for the OpenCL memory scope.
+ // The values should match AtomicScopeOpenCLModel::ID enum.
+ static_assert(
+ static_cast<unsigned>(AtomicScopeOpenCLModel::WorkGroup) == 1 &&
+ static_cast<unsigned>(AtomicScopeOpenCLModel::Device) == 2 &&
+ static_cast<unsigned>(AtomicScopeOpenCLModel::AllSVMDevices) == 3 &&
+ static_cast<unsigned>(AtomicScopeOpenCLModel::SubGroup) == 4,
+ "Invalid OpenCL memory scope enum definition");
+ Builder.defineMacro("__OPENCL_MEMORY_SCOPE_WORK_ITEM", "0");
+ Builder.defineMacro("__OPENCL_MEMORY_SCOPE_WORK_GROUP", "1");
+ Builder.defineMacro("__OPENCL_MEMORY_SCOPE_DEVICE", "2");
+ Builder.defineMacro("__OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES", "3");
+ Builder.defineMacro("__OPENCL_MEMORY_SCOPE_SUB_GROUP", "4");
+
// Support for #pragma redefine_extname (Sun compatibility)
Builder.defineMacro("__PRAGMA_REDEFINE_EXTNAME", "1");
@@ -781,6 +804,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineFmt("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
DefineTypeWidth("__UINTPTR_WIDTH__", TI.getUIntPtrType(), TI, Builder);
+ DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16");
DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), "");
DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L");
@@ -880,14 +904,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// The value written by __atomic_test_and_set.
// FIXME: This is target-dependent.
Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
+ }
+ auto addLockFreeMacros = [&](const llvm::Twine &Prefix) {
// Used by libc++ and libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth();
-#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
- Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \
- getLockFreeValue(TI.get##Type##Width(), \
- TI.get##Type##Align(), \
- InlineWidthBits));
+#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
+ Builder.defineMacro(Prefix + #TYPE "_LOCK_FREE", \
+ getLockFreeValue(TI.get##Type##Width(), \
+ TI.get##Type##Align(), \
+ InlineWidthBits));
DEFINE_LOCK_FREE_MACRO(BOOL, Bool);
DEFINE_LOCK_FREE_MACRO(CHAR, Char);
DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16);
@@ -897,12 +923,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DEFINE_LOCK_FREE_MACRO(INT, Int);
DEFINE_LOCK_FREE_MACRO(LONG, Long);
DEFINE_LOCK_FREE_MACRO(LLONG, LongLong);
- Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE",
+ Builder.defineMacro(Prefix + "POINTER_LOCK_FREE",
getLockFreeValue(TI.getPointerWidth(0),
TI.getPointerAlign(0),
InlineWidthBits));
#undef DEFINE_LOCK_FREE_MACRO
- }
+ };
+ addLockFreeMacros("__CLANG_ATOMIC_");
+ if (!LangOpts.MSVCCompat)
+ addLockFreeMacros("__GCC_ATOMIC_");
if (LangOpts.NoInlineDefine)
Builder.defineMacro("__NO_INLINE__");
@@ -1034,7 +1063,9 @@ void clang::InitializePreprocessor(
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines) {
- if (LangOpts.CUDA && PP.getAuxTargetInfo())
+ // FIXME: This will create multiple definitions for most of the predefined
+ // macros. This is not the right way to handle this.
+ if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo())
InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts,
Builder);
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
index f133327f42..47023e58fa 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Frontend/LangStandards.cpp
@@ -13,15 +13,15 @@
using namespace clang;
using namespace clang::frontend;
-#define LANGSTANDARD(id, name, desc, features) \
- static const LangStandard Lang_##id = { name, desc, features };
+#define LANGSTANDARD(id, name, lang, desc, features) \
+static const LangStandard Lang_##id = { name, desc, features, InputKind::lang };
#include "clang/Frontend/LangStandards.def"
const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
switch (K) {
case lang_unspecified:
llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
case lang_##id: return Lang_##id;
#include "clang/Frontend/LangStandards.def"
}
@@ -30,7 +30,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
Kind K = llvm::StringSwitch<Kind>(Name)
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
.Case(name, lang_##id)
#include "clang/Frontend/LangStandards.def"
.Default(lang_unspecified);
diff --git a/lib/Frontend/ModuleDependencyCollector.cpp b/lib/Frontend/ModuleDependencyCollector.cpp
index 9b34d42113..ede12aab6e 100644
--- a/lib/Frontend/ModuleDependencyCollector.cpp
+++ b/lib/Frontend/ModuleDependencyCollector.cpp
@@ -248,7 +248,7 @@ std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src,
// Always map a canonical src path to its real path into the YAML, by doing
// this we map different virtual src paths to the same entry in the VFS
// overlay, which is a way to emulate symlink inside the VFS; this is also
- // needed for correctness, not doing that can lead to module redifinition
+ // needed for correctness, not doing that can lead to module redefinition
// errors.
addFileMapping(VirtualPath, CacheDst);
return std::error_code();
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 8ef6df5e74..16000bc159 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -116,7 +116,8 @@ public:
void ResolvedExceptionSpec(const FunctionDecl *FD) override;
void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
- const FunctionDecl *Delete) override;
+ const FunctionDecl *Delete,
+ Expr *ThisArg) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
void DefaultArgumentInstantiated(const ParmVarDecl *D) override;
@@ -183,9 +184,9 @@ void MultiplexASTMutationListener::DeducedReturnType(const FunctionDecl *FD,
Listeners[i]->DeducedReturnType(FD, ReturnType);
}
void MultiplexASTMutationListener::ResolvedOperatorDelete(
- const CXXDestructorDecl *DD, const FunctionDecl *Delete) {
+ const CXXDestructorDecl *DD, const FunctionDecl *Delete, Expr *ThisArg) {
for (auto *L : Listeners)
- L->ResolvedOperatorDelete(DD, Delete);
+ L->ResolvedOperatorDelete(DD, Delete, ThisArg);
}
void MultiplexASTMutationListener::CompletedImplicitDefinition(
const FunctionDecl *D) {
diff --git a/lib/Frontend/PrecompiledPreamble.cpp b/lib/Frontend/PrecompiledPreamble.cpp
new file mode 100644
index 0000000000..e44f55dbe1
--- /dev/null
+++ b/lib/Frontend/PrecompiledPreamble.cpp
@@ -0,0 +1,572 @@
+//===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper class to build precompiled preamble.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Serialization/ASTWriter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/Process.h"
+
+using namespace clang;
+
+namespace {
+
+/// Keeps a track of files to be deleted in destructor.
+class TemporaryFiles {
+public:
+ // A static instance to be used by all clients.
+ static TemporaryFiles &getInstance();
+
+private:
+ // Disallow constructing the class directly.
+ TemporaryFiles() = default;
+ // Disallow copy.
+ TemporaryFiles(const TemporaryFiles &) = delete;
+
+public:
+ ~TemporaryFiles();
+
+ /// Adds \p File to a set of tracked files.
+ void addFile(StringRef File);
+
+ /// Remove \p File from disk and from the set of tracked files.
+ void removeFile(StringRef File);
+
+private:
+ llvm::sys::SmartMutex<false> Mutex;
+ llvm::StringSet<> Files;
+};
+
+TemporaryFiles &TemporaryFiles::getInstance() {
+ static TemporaryFiles Instance;
+ return Instance;
+}
+
+TemporaryFiles::~TemporaryFiles() {
+ llvm::MutexGuard Guard(Mutex);
+ for (const auto &File : Files)
+ llvm::sys::fs::remove(File.getKey());
+}
+
+void TemporaryFiles::addFile(StringRef File) {
+ llvm::MutexGuard Guard(Mutex);
+ auto IsInserted = Files.insert(File).second;
+ (void)IsInserted;
+ assert(IsInserted && "File has already been added");
+}
+
+void TemporaryFiles::removeFile(StringRef File) {
+ llvm::MutexGuard Guard(Mutex);
+ auto WasPresent = Files.erase(File);
+ (void)WasPresent;
+ assert(WasPresent && "File was not tracked");
+ llvm::sys::fs::remove(File);
+}
+
+class PreambleMacroCallbacks : public PPCallbacks {
+public:
+ PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {}
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ Callbacks.HandleMacroDefined(MacroNameTok, MD);
+ }
+
+private:
+ PreambleCallbacks &Callbacks;
+};
+
+class PrecompilePreambleAction : public ASTFrontendAction {
+public:
+ PrecompilePreambleAction(PreambleCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
+
+ bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
+
+ void setEmittedPreamblePCH(ASTWriter &Writer) {
+ this->HasEmittedPreamblePCH = true;
+ Callbacks.AfterPCHEmitted(Writer);
+ }
+
+ bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
+ bool hasCodeCompletionSupport() const override { return false; }
+ bool hasASTFileSupport() const override { return false; }
+ TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
+
+private:
+ friend class PrecompilePreambleConsumer;
+
+ bool HasEmittedPreamblePCH = false;
+ PreambleCallbacks &Callbacks;
+};
+
+class PrecompilePreambleConsumer : public PCHGenerator {
+public:
+ PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
+ const Preprocessor &PP, StringRef isysroot,
+ std::unique_ptr<raw_ostream> Out)
+ : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
+ ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
+ /*AllowASTWithErrors=*/true),
+ Action(Action), Out(std::move(Out)) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ Action.Callbacks.HandleTopLevelDecl(DG);
+ return true;
+ }
+
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ PCHGenerator::HandleTranslationUnit(Ctx);
+ if (!hasEmittedPCH())
+ return;
+
+ // Write the generated bitstream to "Out".
+ *Out << getPCH();
+ // Make sure it hits disk now.
+ Out->flush();
+ // Free the buffer.
+ llvm::SmallVector<char, 0> Empty;
+ getPCH() = std::move(Empty);
+
+ Action.setEmittedPreamblePCH(getWriter());
+ }
+
+private:
+ PrecompilePreambleAction &Action;
+ std::unique_ptr<raw_ostream> Out;
+};
+
+std::unique_ptr<ASTConsumer>
+PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
+
+ StringRef InFile) {
+ std::string Sysroot;
+ std::string OutputFile;
+ std::unique_ptr<raw_ostream> OS =
+ GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ OutputFile);
+ if (!OS)
+ return nullptr;
+
+ if (!CI.getFrontendOpts().RelocatablePCH)
+ Sysroot.clear();
+
+ CI.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<PreambleMacroCallbacks>(Callbacks));
+ return llvm::make_unique<PrecompilePreambleConsumer>(
+ *this, CI.getPreprocessor(), Sysroot, std::move(OS));
+}
+
+template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
+ if (!Val)
+ return false;
+ Output = std::move(*Val);
+ return true;
+}
+
+} // namespace
+
+PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts,
+ llvm::MemoryBuffer *Buffer,
+ unsigned MaxLines) {
+ return Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
+}
+
+llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
+ const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+ DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ PreambleCallbacks &Callbacks) {
+ assert(VFS && "VFS is null");
+
+ if (!Bounds.Size)
+ return BuildPreambleError::PreambleIsEmpty;
+
+ auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
+ FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
+ PreprocessorOptions &PreprocessorOpts =
+ PreambleInvocation->getPreprocessorOpts();
+
+ // Create a temporary file for the precompiled preamble. In rare
+ // circumstances, this can fail.
+ llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
+ PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
+ if (!PreamblePCHFile)
+ return BuildPreambleError::CouldntCreateTempFile;
+
+ // Save the preamble text for later; we'll need to compare against it for
+ // subsequent reparses.
+ std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
+ MainFileBuffer->getBufferStart() +
+ Bounds.Size);
+ bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
+
+ // Tell the compiler invocation to generate a temporary precompiled header.
+ FrontendOpts.ProgramAction = frontend::GeneratePCH;
+ // FIXME: Generate the precompiled header into memory?
+ FrontendOpts.OutputFile = PreamblePCHFile->getFilePath();
+ PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
+ PreprocessorOpts.PrecompiledPreambleBytes.second = false;
+ // Inform preprocessor to record conditional stack when building the preamble.
+ PreprocessorOpts.GeneratePreamble = true;
+
+ // Create the compiler instance to use for building the precompiled preamble.
+ std::unique_ptr<CompilerInstance> Clang(
+ new CompilerInstance(std::move(PCHContainerOps)));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
+ Clang.get());
+
+ Clang->setInvocation(std::move(PreambleInvocation));
+ Clang->setDiagnostics(&Diagnostics);
+
+ // Create the target instance.
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
+ if (!Clang->hasTarget())
+ return BuildPreambleError::CouldntCreateTargetInfo;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang->getTarget().adjust(Clang->getLangOpts());
+
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
+ "FIXME: AST inputs not yet supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
+ "IR inputs not support here!");
+
+ // Clear out old caches and data.
+ Diagnostics.Reset();
+ ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
+
+ VFS =
+ createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
+ if (!VFS)
+ return BuildPreambleError::CouldntCreateVFSOverlay;
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
+
+ // Create the source manager.
+ Clang->setSourceManager(
+ new SourceManager(Diagnostics, Clang->getFileManager()));
+
+ auto PreambleDepCollector = std::make_shared<DependencyCollector>();
+ Clang->addDependencyCollector(PreambleDepCollector);
+
+ // Remap the main source file to the preamble buffer.
+ StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
+ auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
+ MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
+ if (PreprocessorOpts.RetainRemappedFileBuffers) {
+ // MainFileBuffer will be deleted by unique_ptr after leaving the method.
+ PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
+ } else {
+ // In that case, remapped buffer will be deleted by CompilerInstance on
+ // BeginSourceFile, so we call release() to avoid double deletion.
+ PreprocessorOpts.addRemappedFile(MainFilePath,
+ PreambleInputBuffer.release());
+ }
+
+ std::unique_ptr<PrecompilePreambleAction> Act;
+ Act.reset(new PrecompilePreambleAction(Callbacks));
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
+ return BuildPreambleError::BeginSourceFileFailed;
+
+ Act->Execute();
+
+ // Run the callbacks.
+ Callbacks.AfterExecute(*Clang);
+
+ Act->EndSourceFile();
+
+ if (!Act->hasEmittedPreamblePCH())
+ return BuildPreambleError::CouldntEmitPCH;
+
+ // Keep track of all of the files that the source manager knows about,
+ // so we can verify whether they have changed or not.
+ llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
+
+ SourceManager &SourceMgr = Clang->getSourceManager();
+ for (auto &Filename : PreambleDepCollector->getDependencies()) {
+ const FileEntry *File = Clang->getFileManager().getFile(Filename);
+ if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
+ continue;
+ if (time_t ModTime = File->getModificationTime()) {
+ FilesInPreamble[File->getName()] =
+ PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
+ ModTime);
+ } else {
+ llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
+ FilesInPreamble[File->getName()] =
+ PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
+ }
+ }
+
+ return PrecompiledPreamble(
+ std::move(*PreamblePCHFile), std::move(PreambleBytes),
+ PreambleEndsAtStartOfLine, std::move(FilesInPreamble));
+}
+
+PreambleBounds PrecompiledPreamble::getBounds() const {
+ return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
+}
+
+bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer,
+ PreambleBounds Bounds,
+ vfs::FileSystem *VFS) const {
+
+ assert(
+ Bounds.Size <= MainFileBuffer->getBufferSize() &&
+ "Buffer is too large. Bounds were calculated from a different buffer?");
+
+ auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
+ PreprocessorOptions &PreprocessorOpts =
+ PreambleInvocation->getPreprocessorOpts();
+
+ if (!Bounds.Size)
+ return false;
+
+ // We've previously computed a preamble. Check whether we have the same
+ // preamble now that we did before, and that there's enough space in
+ // the main-file buffer within the precompiled preamble to fit the
+ // new main file.
+ if (PreambleBytes.size() != Bounds.Size ||
+ PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
+ memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
+ Bounds.Size) != 0)
+ return false;
+ // The preamble has not changed. We may be able to re-use the precompiled
+ // preamble.
+
+ // Check that none of the files used by the preamble have changed.
+ // First, make a record of those files that have been overridden via
+ // remapping or unsaved_files.
+ std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
+ for (const auto &R : PreprocessorOpts.RemappedFiles) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(R.second), Status)) {
+ // If we can't stat the file we're remapping to, assume that something
+ // horrible happened.
+ return false;
+ }
+
+ OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
+ Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
+ }
+
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(RB.first), Status))
+ return false;
+
+ OverriddenFiles[Status.getUniqueID()] =
+ PreambleFileHash::createForMemoryBuffer(RB.second);
+ }
+
+ // Check whether anything has changed.
+ for (const auto &F : FilesInPreamble) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(F.first()), Status)) {
+ // If we can't stat the file, assume that something horrible happened.
+ return false;
+ }
+
+ std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
+ OverriddenFiles.find(Status.getUniqueID());
+ if (Overridden != OverriddenFiles.end()) {
+ // This file was remapped; check whether the newly-mapped file
+ // matches up with the previous mapping.
+ if (Overridden->second != F.second)
+ return false;
+ continue;
+ }
+
+ // The file was not remapped; check whether it has changed on disk.
+ if (Status.getSize() != uint64_t(F.second.Size) ||
+ llvm::sys::toTimeT(Status.getLastModificationTime()) !=
+ F.second.ModTime)
+ return false;
+ }
+ return true;
+}
+
+void PrecompiledPreamble::AddImplicitPreamble(
+ CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const {
+ auto &PreprocessorOpts = CI.getPreprocessorOpts();
+
+ // Configure ImpicitPCHInclude.
+ PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size();
+ PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine;
+ PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
+ PreprocessorOpts.DisablePCHValidation = true;
+
+ // Remap main file to point to MainFileBuffer.
+ auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
+ PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
+}
+
+PrecompiledPreamble::PrecompiledPreamble(
+ TempPCHFile PCHFile, std::vector<char> PreambleBytes,
+ bool PreambleEndsAtStartOfLine,
+ llvm::StringMap<PreambleFileHash> FilesInPreamble)
+ : PCHFile(std::move(PCHFile)), FilesInPreamble(std::move(FilesInPreamble)),
+ PreambleBytes(std::move(PreambleBytes)),
+ PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
+ // FIXME: This is a hack so that we can override the preamble file during
+ // crash-recovery testing, which is the only case where the preamble files
+ // are not necessarily cleaned up.
+ const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
+ if (TmpFile)
+ return TempPCHFile::createFromCustomPath(TmpFile);
+ return TempPCHFile::createInSystemTempDir("preamble", "pch");
+}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
+ StringRef Suffix) {
+ llvm::SmallString<64> File;
+ // Using a version of createTemporaryFile with a file descriptor guarantees
+ // that we would never get a race condition in a multi-threaded setting (i.e.,
+ // multiple threads getting the same temporary path).
+ int FD;
+ auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ FD,
+ /*ref*/ File);
+ if (EC)
+ return EC;
+ // We only needed to make sure the file exists, close the file right away.
+ llvm::sys::Process::SafelyCloseFileDescriptor(FD);
+ return TempPCHFile(std::move(File).str());
+}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
+ return TempPCHFile(Path.str());
+}
+
+PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
+ : FilePath(std::move(FilePath)) {
+ TemporaryFiles::getInstance().addFile(*this->FilePath);
+}
+
+PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
+ FilePath = std::move(Other.FilePath);
+ Other.FilePath = None;
+}
+
+PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
+operator=(TempPCHFile &&Other) {
+ RemoveFileIfPresent();
+
+ FilePath = std::move(Other.FilePath);
+ Other.FilePath = None;
+ return *this;
+}
+
+PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
+
+void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
+ if (FilePath) {
+ TemporaryFiles::getInstance().removeFile(*FilePath);
+ FilePath = None;
+ }
+}
+
+llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
+ assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
+ return *FilePath;
+}
+
+PrecompiledPreamble::PreambleFileHash
+PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
+ time_t ModTime) {
+ PreambleFileHash Result;
+ Result.Size = Size;
+ Result.ModTime = ModTime;
+ Result.MD5 = {};
+ return Result;
+}
+
+PrecompiledPreamble::PreambleFileHash
+PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
+ const llvm::MemoryBuffer *Buffer) {
+ PreambleFileHash Result;
+ Result.Size = Buffer->getBufferSize();
+ Result.ModTime = 0;
+
+ llvm::MD5 MD5Ctx;
+ MD5Ctx.update(Buffer->getBuffer().data());
+ MD5Ctx.final(Result.MD5);
+
+ return Result;
+}
+
+void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {}
+void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {}
+void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {}
+void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {}
+
+std::error_code clang::make_error_code(BuildPreambleError Error) {
+ return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
+}
+
+const char *BuildPreambleErrorCategory::name() const noexcept {
+ return "build-preamble.error";
+}
+
+std::string BuildPreambleErrorCategory::message(int condition) const {
+ switch (static_cast<BuildPreambleError>(condition)) {
+ case BuildPreambleError::PreambleIsEmpty:
+ return "Preamble is empty";
+ case BuildPreambleError::CouldntCreateTempFile:
+ return "Could not create temporary file for PCH";
+ case BuildPreambleError::CouldntCreateTargetInfo:
+ return "CreateTargetInfo() return null";
+ case BuildPreambleError::CouldntCreateVFSOverlay:
+ return "Could not create VFS Overlay";
+ case BuildPreambleError::BeginSourceFileFailed:
+ return "BeginSourceFile() return an error";
+ case BuildPreambleError::CouldntEmitPCH:
+ return "Could not emit PCH";
+ }
+ llvm_unreachable("unexpected BuildPreambleError");
+}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index d48b952ef2..2e023294f1 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -38,8 +38,8 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
if (MI.isFunctionLike()) {
OS << '(';
- if (!MI.arg_empty()) {
- MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ if (!MI.param_empty()) {
+ MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
for (; AI+1 != E; ++AI) {
OS << (*AI)->getName();
OS << ',';
@@ -143,6 +143,8 @@ public:
ArrayRef<int> Ids) override;
void PragmaWarningPush(SourceLocation Loc, int Level) override;
void PragmaWarningPop(SourceLocation Loc) override;
+ void PragmaAssumeNonNullBegin(SourceLocation Loc) override;
+ void PragmaAssumeNonNullEnd(SourceLocation Loc) override;
bool HandleFirstTokOnLine(Token &Tok);
@@ -172,7 +174,11 @@ public:
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) override;
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) override;
+
+ void BeginModule(const Module *M);
+ void EndModule(const Module *M);
};
} // end anonymous namespace
@@ -323,47 +329,68 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
StringRef SearchPath,
StringRef RelativePath,
const Module *Imported) {
- if (Imported) {
- // When preprocessing, turn implicit imports into @imports.
- // FIXME: This is a stop-gap until a more comprehensive "preprocessing with
- // modules" solution is introduced.
+ // In -dI mode, dump #include directives prior to dumping their content or
+ // interpretation.
+ if (DumpIncludeDirectives) {
startNewLineIfNeeded();
MoveToLine(HashLoc);
- if (PP.getLangOpts().ObjC2) {
- OS << "@import " << Imported->getFullModuleName() << ";"
- << " /* clang -E: implicit import for \"" << File->getName()
- << "\" */";
- } else {
- const std::string TokenText = PP.getSpelling(IncludeTok);
- assert(!TokenText.empty());
- OS << "#" << TokenText << " "
- << (IsAngled ? '<' : '"')
- << FileName
- << (IsAngled ? '>' : '"')
- << " /* clang -E: implicit import for module "
- << Imported->getFullModuleName() << " */";
- }
- // Since we want a newline after the @import, but not a #<line>, start a new
- // line immediately.
- EmittedTokensOnThisLine = true;
+ const std::string TokenText = PP.getSpelling(IncludeTok);
+ assert(!TokenText.empty());
+ OS << "#" << TokenText << " "
+ << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
+ << " /* clang -E -dI */";
+ setEmittedDirectiveOnThisLine();
startNewLineIfNeeded();
- } else {
- // Not a module import; it's a more vanilla inclusion of some file using one
- // of: #include, #import, #include_next, #include_macros.
- if (DumpIncludeDirectives) {
+ }
+
+ // When preprocessing, turn implicit imports into module import pragmas.
+ if (Imported) {
+ switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_include:
+ case tok::pp_import:
+ case tok::pp_include_next:
startNewLineIfNeeded();
MoveToLine(HashLoc);
- const std::string TokenText = PP.getSpelling(IncludeTok);
- assert(!TokenText.empty());
- OS << "#" << TokenText << " "
+ OS << "#pragma clang module import " << Imported->getFullModuleName(true)
+ << " /* clang -E: implicit import for "
+ << "#" << PP.getSpelling(IncludeTok) << " "
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
- << " /* clang -E -dI */";
- setEmittedDirectiveOnThisLine();
+ << " */";
+ // Since we want a newline after the pragma, but not a #<line>, start a
+ // new line immediately.
+ EmittedTokensOnThisLine = true;
startNewLineIfNeeded();
+ break;
+
+ case tok::pp___include_macros:
+ // #__include_macros has no effect on a user of a preprocessed source
+ // file; the only effect is on preprocessing.
+ //
+ // FIXME: That's not *quite* true: it causes the module in question to
+ // be loaded, which can affect downstream diagnostics.
+ break;
+
+ default:
+ llvm_unreachable("unknown include directive kind");
+ break;
}
}
}
+/// Handle entering the scope of a module during a module compilation.
+void PrintPPOutputPPCallbacks::BeginModule(const Module *M) {
+ startNewLineIfNeeded();
+ OS << "#pragma clang module begin " << M->getFullModuleName(true);
+ setEmittedDirectiveOnThisLine();
+}
+
+/// Handle leaving the scope of a module during a module compilation.
+void PrintPPOutputPPCallbacks::EndModule(const Module *M) {
+ startNewLineIfNeeded();
+ OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/";
+ setEmittedDirectiveOnThisLine();
+}
+
/// Ident - Handle #ident directives when read by the preprocessor.
///
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {
@@ -389,7 +416,8 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
}
void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
// Only print out macro definitions in -dD mode.
if (!DumpDefines) return;
@@ -523,6 +551,22 @@ void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
setEmittedDirectiveOnThisLine();
}
+void PrintPPOutputPPCallbacks::
+PragmaAssumeNonNullBegin(SourceLocation Loc) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma clang assume_nonnull begin";
+ setEmittedDirectiveOnThisLine();
+}
+
+void PrintPPOutputPPCallbacks::
+PragmaAssumeNonNullEnd(SourceLocation Loc) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma clang assume_nonnull end";
+ setEmittedDirectiveOnThisLine();
+}
+
/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
/// is called for the first token on each new line. If this really is the start
/// of a new logical line, handle it and return true, otherwise return false.
@@ -676,13 +720,33 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// -traditional-cpp the lexer keeps /all/ whitespace, including comments.
SourceLocation StartLoc = Tok.getLocation();
Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
- } else if (Tok.is(tok::annot_module_include) ||
- Tok.is(tok::annot_module_begin) ||
- Tok.is(tok::annot_module_end)) {
+ } else if (Tok.is(tok::eod)) {
+ // Don't print end of directive tokens, since they are typically newlines
+ // that mess up our line tracking. These come from unknown pre-processor
+ // directives or hash-prefixed comments in standalone assembly files.
+ PP.Lex(Tok);
+ continue;
+ } else if (Tok.is(tok::annot_module_include)) {
// PrintPPOutputPPCallbacks::InclusionDirective handles producing
// appropriate output here. Ignore this token entirely.
PP.Lex(Tok);
continue;
+ } else if (Tok.is(tok::annot_module_begin)) {
+ // FIXME: We retrieve this token after the FileChanged callback, and
+ // retrieve the module_end token before the FileChanged callback, so
+ // we render this within the file and render the module end outside the
+ // file, but this is backwards from the token locations: the module_begin
+ // token is at the include location (outside the file) and the module_end
+ // token is at the EOF location (within the file).
+ Callbacks->BeginModule(
+ reinterpret_cast<Module *>(Tok.getAnnotationValue()));
+ PP.Lex(Tok);
+ continue;
+ } else if (Tok.is(tok::annot_module_end)) {
+ Callbacks->EndModule(
+ reinterpret_cast<Module *>(Tok.getAnnotationValue()));
+ PP.Lex(Tok);
+ continue;
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS << II->getName();
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
@@ -773,26 +837,33 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
// Expand macros in pragmas with -fms-extensions. The assumption is that
// the majority of pragmas in such a file will be Microsoft pragmas.
- PP.AddPragmaHandler(new UnknownPragmaHandler(
- "#pragma", Callbacks,
+ // Remember the handlers we will add so that we can remove them later.
+ std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler(
+ new UnknownPragmaHandler(
+ "#pragma", Callbacks,
+ /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ std::unique_ptr<UnknownPragmaHandler> GCCHandler(new UnknownPragmaHandler(
+ "#pragma GCC", Callbacks,
+ /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ std::unique_ptr<UnknownPragmaHandler> ClangHandler(new UnknownPragmaHandler(
+ "#pragma clang", Callbacks,
/*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
- PP.AddPragmaHandler(
- "GCC", new UnknownPragmaHandler(
- "#pragma GCC", Callbacks,
- /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
- PP.AddPragmaHandler(
- "clang", new UnknownPragmaHandler(
- "#pragma clang", Callbacks,
- /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ PP.AddPragmaHandler(MicrosoftExtHandler.get());
+ PP.AddPragmaHandler("GCC", GCCHandler.get());
+ PP.AddPragmaHandler("clang", ClangHandler.get());
// The tokens after pragma omp need to be expanded.
//
// OpenMP [2.1, Directive format]
// Preprocessing tokens following the #pragma omp are subject to macro
// replacement.
- PP.AddPragmaHandler("omp",
- new UnknownPragmaHandler("#pragma omp", Callbacks,
- /*RequireTokenExpansion=*/true));
+ std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
+ new UnknownPragmaHandler("#pragma omp", Callbacks,
+ /*RequireTokenExpansion=*/true));
+ PP.AddPragmaHandler("omp", OpenMPHandler.get());
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
@@ -820,4 +891,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
// Read all the preprocessed tokens, printing them out to the stream.
PrintPreprocessedTokens(PP, Tok, Callbacks, *OS);
*OS << '\n';
+
+ // Remove the handlers we just added to leave the preprocessor in a sane state
+ // so that it can be reused (for example by a clang::Parser instance).
+ PP.RemovePragmaHandler(MicrosoftExtHandler.get());
+ PP.RemovePragmaHandler("GCC", GCCHandler.get());
+ PP.RemovePragmaHandler("clang", ClangHandler.get());
+ PP.RemovePragmaHandler("omp", OpenMPHandler.get());
}
diff --git a/lib/Frontend/Rewrite/CMakeLists.txt b/lib/Frontend/Rewrite/CMakeLists.txt
index 924bf5d5ee..61a22b5b13 100644
--- a/lib/Frontend/Rewrite/CMakeLists.txt
+++ b/lib/Frontend/Rewrite/CMakeLists.txt
@@ -19,4 +19,5 @@ add_clang_library(clangRewriteFrontend
clangFrontend
clangLex
clangRewrite
+ clangSerialization
)
diff --git a/lib/Frontend/Rewrite/FrontendActions.cpp b/lib/Frontend/Rewrite/FrontendActions.cpp
index 2e76e2e315..4d587048f6 100644
--- a/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -9,6 +9,8 @@
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Config/config.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -18,6 +20,11 @@
#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -86,8 +93,7 @@ public:
};
} // end anonymous namespace
-bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
if (!FEOpts.FixItSuffix.empty()) {
FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
@@ -148,7 +154,7 @@ bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
return true;
}
-#ifdef CLANG_ENABLE_OBJC_REWRITER
+#if CLANG_ENABLE_OBJC_REWRITER
std::unique_ptr<ASTConsumer>
RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
@@ -190,12 +196,123 @@ void RewriteTestAction::ExecuteAction() {
DoRewriteTest(CI.getPreprocessor(), OS.get());
}
+class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
+ CompilerInstance &CI;
+ std::weak_ptr<raw_ostream> Out;
+
+ llvm::DenseSet<const FileEntry*> Rewritten;
+
+public:
+ RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
+ : CI(CI), Out(Out) {}
+
+ void visitModuleFile(StringRef Filename,
+ serialization::ModuleKind Kind) override {
+ auto *File = CI.getFileManager().getFile(Filename);
+ assert(File && "missing file for loaded module?");
+
+ // Only rewrite each module file once.
+ if (!Rewritten.insert(File).second)
+ return;
+
+ serialization::ModuleFile *MF =
+ CI.getModuleManager()->getModuleManager().lookup(File);
+ assert(File && "missing module file for loaded module?");
+
+ // Not interested in PCH / preambles.
+ if (!MF->isModule())
+ return;
+
+ auto OS = Out.lock();
+ assert(OS && "loaded module file after finishing rewrite action?");
+
+ (*OS) << "#pragma clang module build ";
+ if (isValidIdentifier(MF->ModuleName))
+ (*OS) << MF->ModuleName;
+ else {
+ (*OS) << '"';
+ OS->write_escaped(MF->ModuleName);
+ (*OS) << '"';
+ }
+ (*OS) << '\n';
+
+ // Rewrite the contents of the module in a separate compiler instance.
+ CompilerInstance Instance(CI.getPCHContainerOperations(),
+ &CI.getPreprocessor().getPCMCache());
+ Instance.setInvocation(
+ std::make_shared<CompilerInvocation>(CI.getInvocation()));
+ Instance.createDiagnostics(
+ new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
+ /*ShouldOwnClient=*/true);
+ Instance.getFrontendOpts().DisableFree = false;
+ Instance.getFrontendOpts().Inputs.clear();
+ Instance.getFrontendOpts().Inputs.emplace_back(
+ Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
+ Instance.getFrontendOpts().ModuleFiles.clear();
+ Instance.getFrontendOpts().ModuleMapFiles.clear();
+ // Don't recursively rewrite imports. We handle them all at the top level.
+ Instance.getPreprocessorOutputOpts().RewriteImports = false;
+
+ llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
+ RewriteIncludesAction Action;
+ Action.OutputStream = OS;
+ Instance.ExecuteAction(Action);
+ });
+
+ (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
+ }
+};
+
+bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
+ if (!OutputStream) {
+ OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OutputStream)
+ return false;
+ }
+
+ auto &OS = *OutputStream;
+
+ // If we're preprocessing a module map, start by dumping the contents of the
+ // module itself before switching to the input buffer.
+ auto &Input = getCurrentInput();
+ if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+ if (Input.isFile()) {
+ OS << "# 1 \"";
+ OS.write_escaped(Input.getFile());
+ OS << "\"\n";
+ }
+ getCurrentModule()->print(OS);
+ OS << "#pragma clang module contents\n";
+ }
+
+ // If we're rewriting imports, set up a listener to track when we import
+ // module files.
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ CI.createModuleManager();
+ CI.getModuleManager()->addListener(
+ llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
+ }
+
+ return true;
+}
+
void RewriteIncludesAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- std::unique_ptr<raw_ostream> OS =
- CI.createDefaultOutputFile(true, getCurrentFile());
- if (!OS) return;
- RewriteIncludesInInput(CI.getPreprocessor(), OS.get(),
- CI.getPreprocessorOutputOpts());
+ // If we're rewriting imports, emit the module build output first rather
+ // than switching back and forth (potentially in the middle of a line).
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ std::string Buffer;
+ llvm::raw_string_ostream OS(Buffer);
+
+ RewriteIncludesInInput(CI.getPreprocessor(), &OS,
+ CI.getPreprocessorOutputOpts());
+
+ (*OutputStream) << OS.str();
+ } else {
+ RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
+ CI.getPreprocessorOutputOpts());
+ }
+
+ OutputStream.reset();
}
diff --git a/lib/Frontend/Rewrite/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp
index d953da2e4f..e0477069b3 100644
--- a/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -46,17 +46,24 @@ class InclusionRewriter : public PPCallbacks {
std::map<unsigned, IncludedFile> FileIncludes;
/// Tracks where inclusions that import modules are found.
std::map<unsigned, const Module *> ModuleIncludes;
+ /// Tracks where inclusions that enter modules (in a module build) are found.
+ std::map<unsigned, const Module *> ModuleEntryIncludes;
/// Used transitively for building up the FileIncludes mapping over the
/// various \c PPCallbacks callbacks.
SourceLocation LastInclusionLocation;
public:
InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers,
bool UseLineDirectives);
- bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
+ void Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
PredefinesBuffer = Buf;
}
void detectMainFileEOL();
+ void handleModuleBegin(Token &Tok) {
+ assert(Tok.getKind() == tok::annot_module_begin);
+ ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(),
+ (Module *)Tok.getAnnotationValue()});
+ }
private:
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
@@ -84,6 +91,7 @@ private:
bool &FileExists);
const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const;
const Module *FindModuleAtLocation(SourceLocation Loc) const;
+ const Module *FindEnteredModule(SourceLocation Loc) const;
StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
};
@@ -132,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line,
}
void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) {
- OS << "@import " << Mod->getFullModuleName() << ";"
+ OS << "#pragma clang module import " << Mod->getFullModuleName(true)
<< " /* clang -frewrite-includes: implicit import */" << MainEOL;
}
@@ -169,7 +177,9 @@ void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/,
/// directives. It does not say whether the file has been included, but it
/// provides more information about the directive (hash location instead
/// of location inside the included file). It is assumed that the matching
-/// FileChanged() or FileSkipped() is called after this.
+/// FileChanged() or FileSkipped() is called after this (or neither is
+/// called if this #include results in an error or does not textually include
+/// anything).
void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
const Token &/*IncludeTok*/,
StringRef /*FileName*/,
@@ -179,9 +189,6 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
StringRef /*SearchPath*/,
StringRef /*RelativePath*/,
const Module *Imported) {
- assert(LastInclusionLocation.isInvalid() &&
- "Another inclusion directive was found before the previous one "
- "was processed");
if (Imported) {
auto P = ModuleIncludes.insert(
std::make_pair(HashLoc.getRawEncoding(), Imported));
@@ -211,6 +218,16 @@ InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const {
return nullptr;
}
+/// Simple lookup for a SourceLocation (specifically one denoting the hash in
+/// an inclusion directive) in the map of module entry information.
+const Module *
+InclusionRewriter::FindEnteredModule(SourceLocation Loc) const {
+ const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding());
+ if (I != ModuleEntryIncludes.end())
+ return I->second;
+ return nullptr;
+}
+
/// Detect the likely line ending style of \p FromFile by examining the first
/// newline found within it.
static StringRef DetectEOL(const MemoryBuffer &FromFile) {
@@ -392,7 +409,7 @@ bool InclusionRewriter::HandleHasInclude(
// FIXME: Why don't we call PP.LookupFile here?
const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr,
- nullptr, nullptr, nullptr, false);
+ nullptr, nullptr, nullptr, nullptr);
FileExists = File != nullptr;
return true;
@@ -400,9 +417,8 @@ bool InclusionRewriter::HandleHasInclude(
/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
/// and including content of included files recursively.
-bool InclusionRewriter::Process(FileID FileId,
- SrcMgr::CharacteristicKind FileType)
-{
+void InclusionRewriter::Process(FileID FileId,
+ SrcMgr::CharacteristicKind FileType) {
bool Invalid;
const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid);
assert(!Invalid && "Attempting to process invalid inclusion");
@@ -419,7 +435,7 @@ bool InclusionRewriter::Process(FileID FileId,
WriteLineInfo(FileName, 1, FileType, " 1");
if (SM.getFileIDSize(FileId) == 0)
- return false;
+ return;
// The next byte to be copied from the source file, which may be non-zero if
// the lexer handled a BOM.
@@ -450,19 +466,24 @@ bool InclusionRewriter::Process(FileID FileId,
WriteLineInfo(FileName, Line - 1, FileType, "");
StringRef LineInfoExtra;
SourceLocation Loc = HashToken.getLocation();
- if (const Module *Mod = PP.getLangOpts().ObjC2
- ? FindModuleAtLocation(Loc)
- : nullptr)
+ if (const Module *Mod = FindModuleAtLocation(Loc))
WriteImplicitModuleImport(Mod);
else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
- // include and recursively process the file
- if (Process(Inc->Id, Inc->FileType)) {
- // and set lineinfo back to this file, if the nested one was
- // actually included
- // `2' indicates returning to a file (after having included
- // another file.
- LineInfoExtra = " 2";
- }
+ const Module *Mod = FindEnteredModule(Loc);
+ if (Mod)
+ OS << "#pragma clang module begin "
+ << Mod->getFullModuleName(true) << "\n";
+
+ // Include and recursively process the file.
+ Process(Inc->Id, Inc->FileType);
+
+ if (Mod)
+ OS << "#pragma clang module end /*"
+ << Mod->getFullModuleName(true) << "*/\n";
+
+ // Add line marker to indicate we're returning from an included
+ // file.
+ LineInfoExtra = " 2";
}
// fix up lineinfo (since commented out directive changed line
// numbers) for inclusions that were skipped due to header guards
@@ -571,7 +592,6 @@ bool InclusionRewriter::Process(FileID FileId,
OutputContentUpTo(FromFile, NextToWrite,
SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL,
Line, /*EnsureNewline=*/true);
- return true;
}
/// InclusionRewriterInInput - Implement -frewrite-includes mode.
@@ -597,6 +617,8 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
PP.SetMacroExpansionOnlyInDirectives();
do {
PP.Lex(Tok);
+ if (Tok.is(tok::annot_module_begin))
+ Rewrite->handleModuleBegin(Tok);
} while (Tok.isNot(tok::eof));
Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID()));
Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
diff --git a/lib/Frontend/Rewrite/RewriteMacros.cpp b/lib/Frontend/Rewrite/RewriteMacros.cpp
index 0d0a991fa6..ae6b51bc81 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 e6469f53d4..1954b24aed 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Config/config.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
@@ -30,7 +31,7 @@
#include "llvm/Support/raw_ostream.h"
#include <memory>
-#ifdef CLANG_ENABLE_OBJC_REWRITER
+#if CLANG_ENABLE_OBJC_REWRITER
using namespace clang;
using llvm::utostr;
@@ -146,7 +147,7 @@ namespace {
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
llvm::DenseMap<ObjCInterfaceDecl *,
- llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars;
+ llvm::SmallSetVector<ObjCIvarDecl *, 8> > ReferencedIvars;
// ivar bitfield grouping containers
llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups;
@@ -1013,7 +1014,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
Setr = "\nextern \"C\" __declspec(dllimport) "
"void objc_setProperty (id, SEL, long, id, bool, bool);\n";
}
-
+
RewriteObjCMethodDecl(OID->getContainingInterface(),
PD->getSetterMethodDecl(), Setr);
Setr += "{ ";
@@ -3965,10 +3966,11 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
std::string &Result) {
// write out ivar offset symbols which have been referenced in an ivar
// access expression.
- llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
+ llvm::SmallSetVector<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
+
if (Ivars.empty())
return;
-
+
llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput;
for (ObjCIvarDecl *IvarDecl : Ivars) {
const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface();
@@ -5141,7 +5143,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
if (!hasInit) {
ByrefType += "};\n";
unsigned nameSize = Name.size();
- // for block or function pointer declaration. Name is aleady
+ // for block or function pointer declaration. Name is already
// part of the declaration.
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
nameSize = 1;
@@ -6068,7 +6070,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
}
-/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// RewriteIvarOffsetComputation - This routine synthesizes computation of
/// ivar offset.
void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
@@ -7500,7 +7502,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BinaryOperator *addExpr =
new (Context) BinaryOperator(castExpr, DRE, BO_Add,
Context->getPointerType(Context->CharTy),
- VK_RValue, OK_Ordinary, SourceLocation(), false);
+ VK_RValue, OK_Ordinary, SourceLocation(), FPOptions());
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
SourceLocation(),
diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index 934d6aa34a..096b81bc3f 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Config/config.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
@@ -29,7 +30,7 @@
#include "llvm/Support/raw_ostream.h"
#include <memory>
-#ifdef CLANG_ENABLE_OBJC_REWRITER
+#if CLANG_ENABLE_OBJC_REWRITER
using namespace clang;
using llvm::utostr;
@@ -2992,7 +2993,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
BinaryOperator *lessThanExpr =
new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
VK_RValue, OK_Ordinary, SourceLocation(),
- false);
+ FPOptions());
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
ConditionalOperator *CondExpr =
new (Context) ConditionalOperator(lessThanExpr,
@@ -4261,7 +4262,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
}
ByrefType += "};\n";
unsigned nameSize = Name.size();
- // for block or function pointer declaration. Name is aleady
+ // for block or function pointer declaration. Name is already
// part of the declaration.
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
nameSize = 1;
@@ -5052,7 +5053,7 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) {
Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
}
-/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// RewriteIvarOffsetComputation - This routine synthesizes computation of
/// ivar offset.
void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 7f88c919e2..7666fe10b3 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -63,27 +63,20 @@ public:
~SDiagsRenderer() override {}
protected:
- void emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
+ void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag D) override;
- void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) override {}
+ ArrayRef<CharSourceRange> Ranges) override {}
- void emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) override;
+ void emitNote(FullSourceLoc Loc, StringRef Message) override;
- void emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) override;
+ void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) override;
void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) override;
@@ -193,11 +186,8 @@ private:
void ExitDiagBlock();
/// \brief Emit a DIAG record.
- void EmitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- const SourceManager *SM,
+ void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
DiagOrStoredDiag D);
/// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic.
@@ -220,16 +210,14 @@ private:
/// \brief Emit (lazily) the file string and retrieved the file identifier.
unsigned getEmitFile(const char *Filename);
- /// \brief Add SourceLocation information the specified record.
- void AddLocToRecord(SourceLocation Loc, const SourceManager *SM,
- PresumedLoc PLoc, RecordDataImpl &Record,
- unsigned TokSize = 0);
+ /// \brief Add SourceLocation information the specified record.
+ void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
+ RecordDataImpl &Record, unsigned TokSize = 0);
/// \brief Add SourceLocation information the specified record.
- void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
- const SourceManager *SM,
+ void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record,
unsigned TokSize = 0) {
- AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(),
+ AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(),
Record, TokSize);
}
@@ -350,11 +338,8 @@ static void EmitRecordID(unsigned ID, const char *Name,
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
}
-void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
- const SourceManager *SM,
- PresumedLoc PLoc,
- RecordDataImpl &Record,
- unsigned TokSize) {
+void SDiagsWriter::AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
+ RecordDataImpl &Record, unsigned TokSize) {
if (PLoc.isInvalid()) {
// Emit a "sentinel" location.
Record.push_back((unsigned)0); // File.
@@ -367,19 +352,19 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
Record.push_back(getEmitFile(PLoc.getFilename()));
Record.push_back(PLoc.getLine());
Record.push_back(PLoc.getColumn()+TokSize);
- Record.push_back(SM->getFileOffset(Loc));
+ Record.push_back(Loc.getFileOffset());
}
void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
RecordDataImpl &Record,
const SourceManager &SM) {
- AddLocToRecord(Range.getBegin(), Record, &SM);
+ AddLocToRecord(FullSourceLoc(Range.getBegin(), SM), Record);
unsigned TokSize = 0;
if (Range.isTokenRange())
TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
SM, *LangOpts);
-
- AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
+
+ AddLocToRecord(FullSourceLoc(Range.getEnd(), SM), Record, TokSize);
}
unsigned SDiagsWriter::getEmitFile(const char *FileName){
@@ -506,7 +491,7 @@ void SDiagsWriter::EmitBlockInfoBlock() {
Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
@@ -606,8 +591,8 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
if (DiagLevel == DiagnosticsEngine::Note)
EnterDiagBlock();
- EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
- State->diagBuf, nullptr, &Info);
+ EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel,
+ State->diagBuf, &Info);
if (DiagLevel == DiagnosticsEngine::Note)
ExitDiagBlock();
@@ -618,12 +603,9 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
assert(Info.hasSourceManager() && LangOpts &&
"Unexpected diagnostic with valid location outside of a source file");
SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
- Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
- State->diagBuf,
- Info.getRanges(),
- Info.getFixItHints(),
- &Info.getSourceManager(),
- &Info);
+ Renderer.emitDiagnostic(
+ FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel,
+ State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info);
}
static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
@@ -641,11 +623,9 @@ static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
llvm_unreachable("invalid diagnostic level");
}
-void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
+void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
- const SourceManager *SM,
DiagOrStoredDiag D) {
llvm::BitstreamWriter &Stream = State->Stream;
RecordData &Record = State->Record;
@@ -655,7 +635,7 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
Record.clear();
Record.push_back(RECORD_DIAG);
Record.push_back(getStableLevel(Level));
- AddLocToRecord(Loc, SM, PLoc, Record);
+ AddLocToRecord(Loc, PLoc, Record);
if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
// Emit the category string lazily and get the category ID.
@@ -672,15 +652,11 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
}
-void
-SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<clang::CharSourceRange> Ranges,
- const SourceManager *SM,
- DiagOrStoredDiag D) {
- Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
+void SDiagsRenderer::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+ Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D);
}
void SDiagsWriter::EnterDiagBlock() {
@@ -733,20 +709,18 @@ void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
}
}
-void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
+void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange> &Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
- Writer.EmitCodeContext(Ranges, Hints, SM);
+ ArrayRef<FixItHint> Hints) {
+ Writer.EmitCodeContext(Ranges, Hints, Loc.getManager());
}
-void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) {
+void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) {
Writer.EnterDiagBlock();
- PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
- Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
- Message, SM, DiagOrStoredDiag());
+ PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc();
+ Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message,
+ DiagOrStoredDiag());
Writer.ExitDiagBlock();
}
diff --git a/lib/Frontend/SerializedDiagnosticReader.cpp b/lib/Frontend/SerializedDiagnosticReader.cpp
index c4461d452e..08b7087fba 100644
--- a/lib/Frontend/SerializedDiagnosticReader.cpp
+++ b/lib/Frontend/SerializedDiagnosticReader.cpp
@@ -27,6 +27,9 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
llvm::BitstreamCursor Stream(**Buffer);
Optional<llvm::BitstreamBlockInfo> BlockInfo;
+ if (Stream.AtEndOfStream())
+ return SDError::InvalidSignature;
+
// Sniff for the signature.
if (Stream.Read(8) != 'D' ||
Stream.Read(8) != 'I' ||
@@ -125,6 +128,7 @@ SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
case Cursor::BlockBegin:
if (Stream.SkipBlock())
return SDError::MalformedMetadataBlock;
+ LLVM_FALLTHROUGH;
case Cursor::BlockEnd:
if (!VersionChecked)
return SDError::MissingVersion;
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index a4937386b9..6a72b00c60 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -672,20 +672,16 @@ TextDiagnostic::TextDiagnostic(raw_ostream &OS,
TextDiagnostic::~TextDiagnostic() {}
-void
-TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<clang::CharSourceRange> Ranges,
- const SourceManager *SM,
- DiagOrStoredDiag D) {
+void TextDiagnostic::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
uint64_t StartOfLocationInfo = OS.tell();
// Emit the location of this particular diagnostic.
if (Loc.isValid())
- emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM);
-
+ emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
+
if (DiagOpts->ShowColors)
OS.resetColor();
@@ -787,17 +783,16 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
/// This includes extracting as much location information as is present for
/// the diagnostic and printing it, as well as any include stack or source
/// ranges necessary.
-void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+ ArrayRef<CharSourceRange> Ranges) {
if (PLoc.isInvalid()) {
// At least print the file name if available:
- FileID FID = SM.getFileID(Loc);
+ FileID FID = Loc.getFileID();
if (FID.isValid()) {
- const FileEntry* FE = SM.getFileEntryForID(FID);
+ const FileEntry *FE = Loc.getFileEntry();
if (FE && FE->isValid()) {
- emitFilename(FE->getName(), SM);
+ emitFilename(FE->getName(), Loc.getManager());
if (FE->isInPCH())
OS << " (in PCH)";
OS << ": ";
@@ -813,7 +808,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
- emitFilename(PLoc.getFilename(), SM);
+ emitFilename(PLoc.getFilename(), Loc.getManager());
switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
@@ -848,8 +843,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
}
if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
- FileID CaretFileID =
- SM.getFileID(SM.getExpansionLoc(Loc));
+ FileID CaretFileID = Loc.getExpansionLoc().getFileID();
bool PrintedRange = false;
for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
@@ -858,8 +852,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// Ignore invalid ranges.
if (!RI->isValid()) continue;
- SourceLocation B = SM.getExpansionLoc(RI->getBegin());
- SourceLocation E = SM.getExpansionLoc(RI->getEnd());
+ FullSourceLoc B =
+ FullSourceLoc(RI->getBegin(), Loc.getManager()).getExpansionLoc();
+ FullSourceLoc E =
+ FullSourceLoc(RI->getEnd(), Loc.getManager()).getExpansionLoc();
// If the End location and the start location are the same and are a
// macro location, then the range was something that came from a
@@ -867,10 +863,12 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// best we can do is to highlight the range. If this is a
// function-like macro, we'd also like to highlight the arguments.
if (B == E && RI->getEnd().isMacroID())
- E = SM.getExpansionRange(RI->getEnd()).second;
+ E = FullSourceLoc(RI->getEnd(), Loc.getManager())
+ .getExpansionRange()
+ .second;
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+ std::pair<FileID, unsigned> BInfo = B.getDecomposedLoc();
+ std::pair<FileID, unsigned> EInfo = E.getDecomposedLoc();
// If the start or end of the range is in another file, just discard
// it.
@@ -881,13 +879,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// tokens.
unsigned TokSize = 0;
if (RI->isTokenRange())
- TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
+ TokSize = Lexer::MeasureTokenLength(E, E.getManager(), LangOpts);
- OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
- << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
- << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
- << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
- << '}';
+ OS << '{' << B.getLineNumber() << ':' << B.getColumnNumber() << '-'
+ << E.getLineNumber() << ':' << (E.getColumnNumber() + TokSize) << '}';
PrintedRange = true;
}
@@ -897,9 +892,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
OS << ' ';
}
-void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- const SourceManager &SM) {
+void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "In file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":\n";
@@ -907,9 +900,8 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
OS << "In included file:\n";
}
-void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "In module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
@@ -917,10 +909,9 @@ void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
OS << "In module '" << ModuleName << "':\n";
}
-void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
+void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+ StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "While building module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
@@ -928,6 +919,56 @@ void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
OS << "While building module '" << ModuleName << "':\n";
}
+/// \brief Find the suitable set of lines to show to include a set of ranges.
+static llvm::Optional<std::pair<unsigned, unsigned>>
+findLinesForRange(const CharSourceRange &R, FileID FID,
+ const SourceManager &SM) {
+ if (!R.isValid()) return None;
+
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
+ if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
+ return None;
+
+ return std::make_pair(SM.getExpansionLineNumber(Begin),
+ SM.getExpansionLineNumber(End));
+}
+
+/// Add as much of range B into range A as possible without exceeding a maximum
+/// size of MaxRange. Ranges are inclusive.
+static std::pair<unsigned, unsigned>
+maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
+ unsigned MaxRange) {
+ // If A is already the maximum size, we're done.
+ unsigned Slack = MaxRange - (A.second - A.first + 1);
+ if (Slack == 0)
+ return A;
+
+ // Easy case: merge succeeds within MaxRange.
+ unsigned Min = std::min(A.first, B.first);
+ unsigned Max = std::max(A.second, B.second);
+ if (Max - Min + 1 <= MaxRange)
+ return {Min, Max};
+
+ // If we can't reach B from A within MaxRange, there's nothing to do.
+ // Don't add lines to the range that contain nothing interesting.
+ if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
+ (B.second < A.second && A.second - B.second + 1 > MaxRange))
+ return A;
+
+ // Otherwise, expand A towards B to produce a range of size MaxRange. We
+ // attempt to expand by the same amount in both directions if B strictly
+ // contains A.
+
+ // Expand downwards by up to half the available amount, then upwards as
+ // much as possible, then downwards as much as possible.
+ A.second = std::min(A.second + (Slack + 1) / 2, Max);
+ Slack = MaxRange - (A.second - A.first + 1);
+ A.first = std::max(Min + Slack, A.first) - Slack;
+ A.second = std::min(A.first + MaxRange - 1, Max);
+ return A;
+}
+
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
static void highlightRange(const CharSourceRange &R,
unsigned LineNo, FileID FID,
@@ -990,9 +1031,12 @@ static void highlightRange(const CharSourceRange &R,
EndColNo = map.startOfPreviousColumn(EndColNo);
// If the start/end passed each other, then we are trying to highlight a
- // range that just exists in whitespace, which must be some sort of other
- // bug.
- assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
+ // range that just exists in whitespace. That most likely means we have
+ // a multi-line highlighting range that covers a blank line.
+ if (StartColNo > EndColNo) {
+ assert(StartLineNo != EndLineNo && "trying to highlight whitespace");
+ StartColNo = EndColNo;
+ }
}
assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
@@ -1008,7 +1052,8 @@ static void highlightRange(const CharSourceRange &R,
std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
}
-static std::string buildFixItInsertionLine(unsigned LineNo,
+static std::string buildFixItInsertionLine(FileID FID,
+ unsigned LineNo,
const SourceColumnMap &map,
ArrayRef<FixItHint> Hints,
const SourceManager &SM,
@@ -1025,7 +1070,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
// code contains no newlines and is on the same line as the caret.
std::pair<FileID, unsigned> HintLocInfo
= SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
- if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
+ if (FID == HintLocInfo.first &&
+ LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
// Insert the new code into the line just below the code
// that the user wrote.
@@ -1061,9 +1107,6 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
PrevHintEndCol =
HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
- } else {
- FixItInsertionLine.clear();
- break;
}
}
}
@@ -1081,10 +1124,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
void TextDiagnostic::emitSnippetAndCaret(
- SourceLocation Loc, DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges, ArrayRef<FixItHint> Hints) {
assert(Loc.isValid() && "must have a valid source location here");
assert(Loc.isFileID() && "must have a file location here");
@@ -1101,111 +1142,128 @@ void TextDiagnostic::emitSnippetAndCaret(
return;
// Decompose the location into a FID/Offset pair.
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc();
FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
+ const SourceManager &SM = Loc.getManager();
// Get information about the buffer it points into.
bool Invalid = false;
- StringRef BufData = SM.getBufferData(FID, &Invalid);
+ StringRef BufData = Loc.getBufferData(&Invalid);
if (Invalid)
return;
- const char *BufStart = BufData.data();
- const char *BufEnd = BufStart + BufData.size();
+ unsigned CaretLineNo = Loc.getLineNumber();
+ unsigned CaretColNo = Loc.getColumnNumber();
- unsigned LineNo = SM.getLineNumber(FID, FileOffset);
- unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
-
// Arbitrarily stop showing snippets when the line is too long.
static const size_t MaxLineLengthToPrint = 4096;
- if (ColNo > MaxLineLengthToPrint)
+ if (CaretColNo > MaxLineLengthToPrint)
return;
- // Rewind from the current position to the start of the line.
- const char *TokPtr = BufStart+FileOffset;
- const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
-
- // Compute the line end. Scan forward from the error position to the end of
- // the line.
- const char *LineEnd = TokPtr;
- while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
- ++LineEnd;
-
- // Arbitrarily stop showing snippets when the line is too long.
- if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
- return;
-
- // Trim trailing null-bytes.
- StringRef Line(LineStart, LineEnd - LineStart);
- while (Line.size() > ColNo && Line.back() == '\0')
- Line = Line.drop_back();
+ // Find the set of lines to include.
+ const unsigned MaxLines = DiagOpts->SnippetLineLimit;
+ std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ if (auto OptionalRange = findLinesForRange(*I, FID, SM))
+ Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
+
+ for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) {
+ const char *BufStart = BufData.data();
+ const char *BufEnd = BufStart + BufData.size();
+
+ // Rewind from the current position to the start of the line.
+ const char *LineStart =
+ BufStart +
+ SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
+ if (LineStart == BufEnd)
+ break;
- // Copy the line of code into an std::string for ease of manipulation.
- std::string SourceLine(Line.begin(), Line.end());
+ // Compute the line end.
+ const char *LineEnd = LineStart;
+ while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
+ ++LineEnd;
- // Build the byte to column map.
- const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+ // Arbitrarily stop showing snippets when the line is too long.
+ // FIXME: Don't print any lines in this case.
+ if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
+ return;
- // Create a line for the caret that is filled with spaces that is the same
- // number of columns as the line of source code.
- std::string CaretLine(sourceColMap.columns(), ' ');
+ // Trim trailing null-bytes.
+ StringRef Line(LineStart, LineEnd - LineStart);
+ while (!Line.empty() && Line.back() == '\0' &&
+ (LineNo != CaretLineNo || Line.size() > CaretColNo))
+ Line = Line.drop_back();
+
+ // Copy the line of code into an std::string for ease of manipulation.
+ std::string SourceLine(Line.begin(), Line.end());
+
+ // Build the byte to column map.
+ const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+
+ // Create a line for the caret that is filled with spaces that is the same
+ // number of columns as the line of source code.
+ std::string CaretLine(sourceColMap.columns(), ' ');
+
+ // Highlight all of the characters covered by Ranges with ~ characters.
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
+
+ // Next, insert the caret itself.
+ if (CaretLineNo == LineNo) {
+ CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1);
+ if (CaretLine.size() < CaretColNo + 1)
+ CaretLine.resize(CaretColNo + 1, ' ');
+ CaretLine[CaretColNo] = '^';
+ }
- // Highlight all of the characters covered by Ranges with ~ characters.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I)
- highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
-
- // Next, insert the caret itself.
- ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
- if (CaretLine.size()<ColNo+1)
- CaretLine.resize(ColNo+1, ' ');
- CaretLine[ColNo] = '^';
-
- std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
- sourceColMap,
- Hints, SM,
- DiagOpts.get());
-
- // If the source line is too long for our terminal, select only the
- // "interesting" source region within that line.
- unsigned Columns = DiagOpts->MessageLength;
- if (Columns)
- selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
- Columns, sourceColMap);
-
- // If we are in -fdiagnostics-print-source-range-info mode, we are trying
- // to produce easily machine parsable output. Add a space before the
- // source line and the caret to make it trivial to tell the main diagnostic
- // line from what the user is intended to see.
- if (DiagOpts->ShowSourceRanges) {
- SourceLine = ' ' + SourceLine;
- CaretLine = ' ' + CaretLine;
- }
+ std::string FixItInsertionLine = buildFixItInsertionLine(
+ FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
+
+ // If the source line is too long for our terminal, select only the
+ // "interesting" source region within that line.
+ unsigned Columns = DiagOpts->MessageLength;
+ if (Columns)
+ selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
+ Columns, sourceColMap);
+
+ // If we are in -fdiagnostics-print-source-range-info mode, we are trying
+ // to produce easily machine parsable output. Add a space before the
+ // source line and the caret to make it trivial to tell the main diagnostic
+ // line from what the user is intended to see.
+ if (DiagOpts->ShowSourceRanges) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
- // Finally, remove any blank spaces from the end of CaretLine.
- while (CaretLine[CaretLine.size()-1] == ' ')
- CaretLine.erase(CaretLine.end()-1);
+ // Finally, remove any blank spaces from the end of CaretLine.
+ while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ')
+ CaretLine.erase(CaretLine.end() - 1);
- // Emit what we have computed.
- emitSnippet(SourceLine);
+ // Emit what we have computed.
+ emitSnippet(SourceLine);
- if (DiagOpts->ShowColors)
- OS.changeColor(caretColor, true);
- OS << CaretLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ if (!CaretLine.empty()) {
+ if (DiagOpts->ShowColors)
+ OS.changeColor(caretColor, true);
+ OS << CaretLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
- if (!FixItInsertionLine.empty()) {
- if (DiagOpts->ShowColors)
- // Print fixit line in color
- OS.changeColor(fixitColor, false);
- if (DiagOpts->ShowSourceRanges)
- OS << ' ';
- OS << FixItInsertionLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ if (!FixItInsertionLine.empty()) {
+ if (DiagOpts->ShowColors)
+ // Print fixit line in color
+ OS.changeColor(fixitColor, false);
+ if (DiagOpts->ShowSourceRanges)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
}
// Print out any parseable fixit information requested by the options.
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 17646b48e2..5dd3252d5b 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -150,10 +150,9 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
"Unexpected diagnostic with no source manager");
assert(TextDiag && "Unexpected diagnostic outside source file processing");
- TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(),
- Info.getRanges(),
- Info.getFixItHints(),
- &Info.getSourceManager());
+ TextDiag->emitDiagnostic(
+ FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
+ DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints());
OS.flush();
}
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index ae16ea177f..a49c424e91 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -400,7 +400,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
const DirectoryLookup *CurDir;
const FileEntry *FE =
PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr);
if (!FE) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_file) << Filename << KindStr;
@@ -416,9 +416,12 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
MatchAnyLine = true;
ExpectedLoc = SM.translateFileLineCol(FE, 1, 1);
}
+ } else if (PH.Next("*")) {
+ MatchAnyLine = true;
+ ExpectedLoc = SourceLocation();
}
- if (ExpectedLoc.isInvalid()) {
+ if (ExpectedLoc.isInvalid() && !MatchAnyLine) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_line) << KindStr;
continue;
@@ -650,7 +653,10 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags,
llvm::raw_svector_ostream OS(Fmt);
for (auto *DirPtr : DL) {
Directive &D = *DirPtr;
- OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc);
+ if (D.DiagnosticLoc.isInvalid())
+ OS << "\n File *";
+ else
+ OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc);
if (D.MatchAnyLine)
OS << " Line *";
else
@@ -708,7 +714,8 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
continue;
}
- if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
+ if (!D.DiagnosticLoc.isInvalid() &&
+ !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
continue;
const std::string &RightText = II->second;
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 1f7493c9e3..4167e1fe20 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -15,6 +15,7 @@
#include "clang/FrontendTool/Utils.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -85,25 +86,26 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
case PrintDeclContext: return llvm::make_unique<DeclContextPrintAction>();
case PrintPreamble: return llvm::make_unique<PrintPreambleAction>();
case PrintPreprocessedInput: {
- if (CI.getPreprocessorOutputOpts().RewriteIncludes)
+ if (CI.getPreprocessorOutputOpts().RewriteIncludes ||
+ CI.getPreprocessorOutputOpts().RewriteImports)
return llvm::make_unique<RewriteIncludesAction>();
return llvm::make_unique<PrintPreprocessedAction>();
}
case RewriteMacros: return llvm::make_unique<RewriteMacrosAction>();
case RewriteTest: return llvm::make_unique<RewriteTestAction>();
-#ifdef CLANG_ENABLE_OBJC_REWRITER
+#if CLANG_ENABLE_OBJC_REWRITER
case RewriteObjC: return llvm::make_unique<RewriteObjCAction>();
#else
case RewriteObjC: Action = "RewriteObjC"; break;
#endif
-#ifdef CLANG_ENABLE_ARCMT
+#if CLANG_ENABLE_ARCMT
case MigrateSource:
return llvm::make_unique<arcmt::MigrateSourceAction>();
#else
case MigrateSource: Action = "MigrateSource"; break;
#endif
-#ifdef CLANG_ENABLE_STATIC_ANALYZER
+#if CLANG_ENABLE_STATIC_ANALYZER
case RunAnalysis: return llvm::make_unique<ento::AnalysisAction>();
#else
case RunAnalysis: Action = "RunAnalysis"; break;
@@ -111,8 +113,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
case RunPreprocessorOnly: return llvm::make_unique<PreprocessOnlyAction>();
}
-#if !defined(CLANG_ENABLE_ARCMT) || !defined(CLANG_ENABLE_STATIC_ANALYZER) \
- || !defined(CLANG_ENABLE_OBJC_REWRITER)
+#if !CLANG_ENABLE_ARCMT || !CLANG_ENABLE_STATIC_ANALYZER \
+ || !CLANG_ENABLE_OBJC_REWRITER
CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action;
return 0;
#else
@@ -133,7 +135,7 @@ CreateFrontendAction(CompilerInstance &CI) {
Act = llvm::make_unique<FixItRecompile>(std::move(Act));
}
-#ifdef CLANG_ENABLE_ARCMT
+#if CLANG_ENABLE_ARCMT
if (CI.getFrontendOpts().ProgramAction != frontend::MigrateSource &&
CI.getFrontendOpts().ProgramAction != frontend::GeneratePCH) {
// Potentially wrap the base FE action in an ARC Migrate Tool action.
@@ -177,7 +179,8 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
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);
+ /*Include=*/driver::options::CC1Option,
+ /*Exclude=*/0, /*ShowAllAliases=*/false);
return true;
}
@@ -225,7 +228,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
-#ifdef CLANG_ENABLE_STATIC_ANALYZER
+#if CLANG_ENABLE_STATIC_ANALYZER
// Honor -analyzer-checker-help.
// This should happen AFTER plugins have been loaded!
if (Clang->getAnalyzerOpts()->ShowCheckerHelp) {
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 35aff4017e..7d5e9331a8 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -4,9 +4,11 @@ set(files
ammintrin.h
arm_acle.h
armintr.h
+ arm64intr.h
avx2intrin.h
avx512bwintrin.h
avx512cdintrin.h
+ avx512vpopcntdqintrin.h
avx512dqintrin.h
avx512erintrin.h
avx512fintrin.h
@@ -31,6 +33,7 @@ set(files
clzerointrin.h
cpuid.h
clflushoptintrin.h
+ clwbintrin.h
emmintrin.h
f16cintrin.h
float.h
@@ -45,6 +48,7 @@ set(files
inttypes.h
iso646.h
limits.h
+ lwpintrin.h
lzcntintrin.h
mm3dnow.h
mmintrin.h
diff --git a/lib/Headers/__clang_cuda_intrinsics.h b/lib/Headers/__clang_cuda_intrinsics.h
index b43ce21d0b..bc5b876577 100644
--- a/lib/Headers/__clang_cuda_intrinsics.h
+++ b/lib/Headers/__clang_cuda_intrinsics.h
@@ -92,6 +92,130 @@ __MAKE_SHUFFLES(__shfl_xor, __nvvm_shfl_bfly_i32, __nvvm_shfl_bfly_f32, 0x1f);
#endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 300
+#if CUDA_VERSION >= 9000
+#if (!defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 300)
+// __shfl_sync_* variants available in CUDA-9
+#pragma push_macro("__MAKE_SYNC_SHUFFLES")
+#define __MAKE_SYNC_SHUFFLES(__FnName, __IntIntrinsic, __FloatIntrinsic, \
+ __Mask) \
+ inline __device__ int __FnName(unsigned int __mask, int __val, int __offset, \
+ int __width = warpSize) { \
+ return __IntIntrinsic(__mask, __val, __offset, \
+ ((warpSize - __width) << 8) | (__Mask)); \
+ } \
+ inline __device__ float __FnName(unsigned int __mask, float __val, \
+ int __offset, int __width = warpSize) { \
+ return __FloatIntrinsic(__mask, __val, __offset, \
+ ((warpSize - __width) << 8) | (__Mask)); \
+ } \
+ inline __device__ unsigned int __FnName(unsigned int __mask, \
+ unsigned int __val, int __offset, \
+ int __width = warpSize) { \
+ return static_cast<unsigned int>( \
+ ::__FnName(__mask, static_cast<int>(__val), __offset, __width)); \
+ } \
+ inline __device__ long long __FnName(unsigned int __mask, long long __val, \
+ int __offset, int __width = warpSize) { \
+ struct __Bits { \
+ int __a, __b; \
+ }; \
+ _Static_assert(sizeof(__val) == sizeof(__Bits)); \
+ _Static_assert(sizeof(__Bits) == 2 * sizeof(int)); \
+ __Bits __tmp; \
+ memcpy(&__val, &__tmp, sizeof(__val)); \
+ __tmp.__a = ::__FnName(__mask, __tmp.__a, __offset, __width); \
+ __tmp.__b = ::__FnName(__mask, __tmp.__b, __offset, __width); \
+ long long __ret; \
+ memcpy(&__ret, &__tmp, sizeof(__tmp)); \
+ return __ret; \
+ } \
+ inline __device__ unsigned long long __FnName( \
+ unsigned int __mask, unsigned long long __val, int __offset, \
+ int __width = warpSize) { \
+ return static_cast<unsigned long long>(::__FnName( \
+ __mask, static_cast<unsigned long long>(__val), __offset, __width)); \
+ } \
+ inline __device__ double __FnName(unsigned int __mask, double __val, \
+ int __offset, int __width = warpSize) { \
+ long long __tmp; \
+ _Static_assert(sizeof(__tmp) == sizeof(__val)); \
+ memcpy(&__tmp, &__val, sizeof(__val)); \
+ __tmp = ::__FnName(__mask, __tmp, __offset, __width); \
+ double __ret; \
+ memcpy(&__ret, &__tmp, sizeof(__ret)); \
+ return __ret; \
+ }
+__MAKE_SYNC_SHUFFLES(__shfl_sync, __nvvm_shfl_sync_idx_i32,
+ __nvvm_shfl_sync_idx_f32, 0x1f);
+// We use 0 rather than 31 as our mask, because shfl.up applies to lanes >=
+// maxLane.
+__MAKE_SYNC_SHUFFLES(__shfl_up_sync, __nvvm_shfl_sync_up_i32,
+ __nvvm_shfl_sync_up_f32, 0);
+__MAKE_SYNC_SHUFFLES(__shfl_down_sync, __nvvm_shfl_sync_down_i32,
+ __nvvm_shfl_sync_down_f32, 0x1f);
+__MAKE_SYNC_SHUFFLES(__shfl_xor_sync, __nvvm_shfl_sync_bfly_i32,
+ __nvvm_shfl_sync_bfly_f32, 0x1f);
+#pragma pop_macro("__MAKE_SYNC_SHUFFLES")
+
+inline __device__ void __syncwarp(unsigned int mask = 0xffffffff) {
+ return __nvvm_bar_warp_sync(mask);
+}
+
+inline __device__ void __barrier_sync(unsigned int id) {
+ __nvvm_barrier_sync(id);
+}
+
+inline __device__ void __barrier_sync_count(unsigned int id,
+ unsigned int count) {
+ __nvvm_barrier_sync_cnt(id, count);
+}
+
+inline __device__ int __all_sync(unsigned int mask, int pred) {
+ return __nvvm_vote_all_sync(mask, pred);
+}
+
+inline __device__ int __any_sync(unsigned int mask, int pred) {
+ return __nvvm_vote_any_sync(mask, pred);
+}
+
+inline __device__ int __uni_sync(unsigned int mask, int pred) {
+ return __nvvm_vote_uni_sync(mask, pred);
+}
+
+inline __device__ unsigned int __ballot_sync(unsigned int mask, int pred) {
+ return __nvvm_vote_ballot_sync(mask, pred);
+}
+
+inline __device__ unsigned int __activemask() { return __nvvm_vote_ballot(1); }
+
+#endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 300
+
+// Define __match* builtins CUDA-9 headers expect to see.
+#if !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 700
+inline __device__ unsigned int __match32_any_sync(unsigned int mask,
+ unsigned int value) {
+ return __nvvm_match_any_sync_i32(mask, value);
+}
+
+inline __device__ unsigned long long
+__match64_any_sync(unsigned int mask, unsigned long long value) {
+ return __nvvm_match_any_sync_i64(mask, value);
+}
+
+inline __device__ unsigned int
+__match32_all_sync(unsigned int mask, unsigned int value, int *pred) {
+ return __nvvm_match_all_sync_i32p(mask, value, pred);
+}
+
+inline __device__ unsigned long long
+__match64_all_sync(unsigned int mask, unsigned long long value, int *pred) {
+ return __nvvm_match_all_sync_i64p(mask, value, pred);
+}
+#include "crt/sm_70_rt.hpp"
+
+#endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 700
+#endif // __CUDA_VERSION >= 9000
+
// sm_32 intrinsics: __ldg and __funnelshift_{l,lc,r,rc}.
// Prevent the vanilla sm_32 intrinsics header from being included.
diff --git a/lib/Headers/__clang_cuda_runtime_wrapper.h b/lib/Headers/__clang_cuda_runtime_wrapper.h
index 931d44b696..b8ffc2ce9f 100644
--- a/lib/Headers/__clang_cuda_runtime_wrapper.h
+++ b/lib/Headers/__clang_cuda_runtime_wrapper.h
@@ -62,7 +62,7 @@
#include "cuda.h"
#if !defined(CUDA_VERSION)
#error "cuda.h did not define CUDA_VERSION"
-#elif CUDA_VERSION < 7000 || CUDA_VERSION > 8000
+#elif CUDA_VERSION < 7000 || CUDA_VERSION > 9000
#error "Unsupported CUDA version!"
#endif
@@ -86,7 +86,11 @@
#define __COMMON_FUNCTIONS_H__
#undef __CUDACC__
+#if CUDA_VERSION < 9000
#define __CUDABE__
+#else
+#define __CUDA_LIBDEVICE__
+#endif
// Disables definitions of device-side runtime support stubs in
// cuda_device_runtime_api.h
#include "driver_types.h"
@@ -94,6 +98,7 @@
#include "host_defines.h"
#undef __CUDABE__
+#undef __CUDA_LIBDEVICE__
#define __CUDACC__
#include "cuda_runtime.h"
@@ -105,7 +110,9 @@
#define __nvvm_memcpy(s, d, n, a) __builtin_memcpy(s, d, n)
#define __nvvm_memset(d, c, n, a) __builtin_memset(d, c, n)
+#if CUDA_VERSION < 9000
#include "crt/device_runtime.h"
+#endif
#include "crt/host_runtime.h"
// device_runtime.h defines __cxa_* macros that will conflict with
// cxxabi.h.
@@ -166,7 +173,18 @@ inline __host__ double __signbitd(double x) {
// __device__.
#pragma push_macro("__forceinline__")
#define __forceinline__ __device__ __inline__ __attribute__((always_inline))
+
+#pragma push_macro("__float2half_rn")
+#if CUDA_VERSION >= 9000
+// CUDA-9 has conflicting prototypes for __float2half_rn(float f) in
+// cuda_fp16.h[pp] and device_functions.hpp. We need to get the one in
+// device_functions.hpp out of the way.
+#define __float2half_rn __float2half_rn_disabled
+#endif
+
#include "device_functions.hpp"
+#pragma pop_macro("__float2half_rn")
+
// math_function.hpp uses the __USE_FAST_MATH__ macro to determine whether we
// get the slow-but-accurate or fast-but-inaccurate versions of functions like
@@ -247,7 +265,17 @@ static inline __device__ void __brkpt(int __c) { __brkpt(); }
#pragma push_macro("__GNUC__")
#undef __GNUC__
#define signbit __ignored_cuda_signbit
+
+// CUDA-9 omits device-side definitions of some math functions if it sees
+// include guard from math.h wrapper from libstdc++. We have to undo the header
+// guard temporarily to get the definitions we need.
+#pragma push_macro("_GLIBCXX_MATH_H")
+#if CUDA_VERSION >= 9000
+#undef _GLIBCXX_MATH_H
+#endif
+
#include "math_functions.hpp"
+#pragma pop_macro("_GLIBCXX_MATH_H")
#pragma pop_macro("__GNUC__")
#pragma pop_macro("signbit")
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index 421e2a7754..90fd477d9b 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -2887,87 +2887,79 @@ static __inline__ vector double __ATTRS_o_ai vec_cpsgn(vector double __a,
/* vec_ctf */
-static __inline__ vector float __ATTRS_o_ai vec_ctf(vector int __a, int __b) {
- return __builtin_altivec_vcfsx(__a, __b);
-}
-
-static __inline__ vector float __ATTRS_o_ai vec_ctf(vector unsigned int __a,
- int __b) {
- return __builtin_altivec_vcfux((vector int)__a, __b);
-}
-
#ifdef __VSX__
-static __inline__ vector double __ATTRS_o_ai
-vec_ctf(vector unsigned long long __a, int __b) {
- vector double __ret = __builtin_convertvector(__a, vector double);
- __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
- return __ret;
-}
-
-static __inline__ vector double __ATTRS_o_ai
-vec_ctf(vector signed long long __a, int __b) {
- vector double __ret = __builtin_convertvector(__a, vector double);
- __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
- return __ret;
-}
+#define vec_ctf(__a, __b) \
+ _Generic((__a), vector int \
+ : (vector float)__builtin_altivec_vcfsx((__a), (__b)), \
+ vector unsigned int \
+ : (vector float)__builtin_altivec_vcfux((vector int)(__a), (__b)), \
+ vector unsigned long long \
+ : (__builtin_convertvector((vector unsigned long long)(__a), \
+ vector double) * \
+ (vector double)(vector unsigned long long)((0x3ffULL - (__b)) \
+ << 52)), \
+ vector signed long long \
+ : (__builtin_convertvector((vector signed long long)(__a), \
+ vector double) * \
+ (vector double)(vector unsigned long long)((0x3ffULL - (__b)) \
+ << 52)))
+#else
+#define vec_ctf(__a, __b) \
+ _Generic((__a), vector int \
+ : (vector float)__builtin_altivec_vcfsx((__a), (__b)), \
+ vector unsigned int \
+ : (vector float)__builtin_altivec_vcfux((vector int)(__a), (__b)))
#endif
/* vec_vcfsx */
-static __inline__ vector float __attribute__((__always_inline__))
-vec_vcfsx(vector int __a, int __b) {
- return __builtin_altivec_vcfsx(__a, __b);
-}
+#define vec_vcfux __builtin_altivec_vcfux
/* vec_vcfux */
-static __inline__ vector float __attribute__((__always_inline__))
-vec_vcfux(vector unsigned int __a, int __b) {
- return __builtin_altivec_vcfux((vector int)__a, __b);
-}
+#define vec_vcfsx(__a, __b) __builtin_altivec_vcfsx((vector int)(__a), (__b))
/* vec_cts */
-static __inline__ vector int __ATTRS_o_ai vec_cts(vector float __a, int __b) {
- return __builtin_altivec_vctsxs(__a, __b);
-}
-
#ifdef __VSX__
-static __inline__ vector signed long long __ATTRS_o_ai
-vec_cts(vector double __a, int __b) {
- __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
- return __builtin_convertvector(__a, vector signed long long);
-}
+#define vec_cts(__a, __b) \
+ _Generic((__a), vector float \
+ : __builtin_altivec_vctsxs((__a), (__b)), vector double \
+ : __extension__({ \
+ vector double __ret = \
+ (__a) * \
+ (vector double)(vector unsigned long long)((0x3ffULL + (__b)) \
+ << 52); \
+ __builtin_convertvector(__ret, vector signed long long); \
+ }))
+#else
+#define vec_cts __builtin_altivec_vctsxs
#endif
/* vec_vctsxs */
-static __inline__ vector int __attribute__((__always_inline__))
-vec_vctsxs(vector float __a, int __b) {
- return __builtin_altivec_vctsxs(__a, __b);
-}
+#define vec_vctsxs __builtin_altivec_vctsxs
/* vec_ctu */
-static __inline__ vector unsigned int __ATTRS_o_ai vec_ctu(vector float __a,
- int __b) {
- return __builtin_altivec_vctuxs(__a, __b);
-}
-
#ifdef __VSX__
-static __inline__ vector unsigned long long __ATTRS_o_ai
-vec_ctu(vector double __a, int __b) {
- __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
- return __builtin_convertvector(__a, vector unsigned long long);
-}
+#define vec_ctu(__a, __b) \
+ _Generic((__a), vector float \
+ : __builtin_altivec_vctuxs((__a), (__b)), vector double \
+ : __extension__({ \
+ vector double __ret = \
+ (__a) * \
+ (vector double)(vector unsigned long long)((0x3ffULL + __b) \
+ << 52); \
+ __builtin_convertvector(__ret, vector unsigned long long); \
+ }))
+#else
+#define vec_ctu __builtin_altivec_vctuxs
#endif
/* vec_vctuxs */
-static __inline__ vector unsigned int __attribute__((__always_inline__))
-vec_vctuxs(vector float __a, int __b) {
- return __builtin_altivec_vctuxs(__a, __b);
-}
+#define vec_vctuxs __builtin_altivec_vctuxs
/* vec_signed */
@@ -12156,6 +12148,11 @@ static __inline__ void __ATTRS_o_ai vec_vsx_st(vector unsigned char __a,
#endif
+#ifdef __VSX__
+#define vec_xxpermdi __builtin_vsx_xxpermdi
+#define vec_xxsldwi __builtin_vsx_xxsldwi
+#endif
+
/* vec_xor */
#define __builtin_altivec_vxor vec_xor
diff --git a/lib/Headers/arm64intr.h b/lib/Headers/arm64intr.h
new file mode 100644
index 0000000000..be52283618
--- /dev/null
+++ b/lib/Headers/arm64intr.h
@@ -0,0 +1,49 @@
+/*===---- arm64intr.h - ARM64 Windows intrinsics -------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+/* Only include this if we're compiling for the windows platform. */
+#ifndef _MSC_VER
+#include_next <arm64intr.h>
+#else
+
+#ifndef __ARM64INTR_H
+#define __ARM64INTR_H
+
+typedef enum
+{
+ _ARM64_BARRIER_SY = 0xF,
+ _ARM64_BARRIER_ST = 0xE,
+ _ARM64_BARRIER_LD = 0xD,
+ _ARM64_BARRIER_ISH = 0xB,
+ _ARM64_BARRIER_ISHST = 0xA,
+ _ARM64_BARRIER_ISHLD = 0x9,
+ _ARM64_BARRIER_NSH = 0x7,
+ _ARM64_BARRIER_NSHST = 0x6,
+ _ARM64_BARRIER_NSHLD = 0x5,
+ _ARM64_BARRIER_OSH = 0x3,
+ _ARM64_BARRIER_OSHST = 0x2,
+ _ARM64_BARRIER_OSHLD = 0x1
+} _ARM64INTR_BARRIER_TYPE;
+
+#endif /* __ARM64INTR_H */
+#endif /* _MSC_VER */
diff --git a/lib/Headers/arm_acle.h b/lib/Headers/arm_acle.h
index 8423e62a38..ab25897982 100644
--- a/lib/Headers/arm_acle.h
+++ b/lib/Headers/arm_acle.h
@@ -225,19 +225,49 @@ __rbitl(unsigned long __t) {
}
/*
+ * 9.3 16-bit multiplications
+ */
+#if __ARM_FEATURE_DSP
+static __inline__ int32_t __attribute__((__always_inline__,__nodebug__))
+__smulbb(int32_t __a, int32_t __b) {
+ return __builtin_arm_smulbb(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__,__nodebug__))
+__smulbt(int32_t __a, int32_t __b) {
+ return __builtin_arm_smulbt(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__,__nodebug__))
+__smultb(int32_t __a, int32_t __b) {
+ return __builtin_arm_smultb(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__,__nodebug__))
+__smultt(int32_t __a, int32_t __b) {
+ return __builtin_arm_smultt(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__,__nodebug__))
+__smulwb(int32_t __a, int32_t __b) {
+ return __builtin_arm_smulwb(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__,__nodebug__))
+__smulwt(int32_t __a, int32_t __b) {
+ return __builtin_arm_smulwt(__a, __b);
+}
+#endif
+
+/*
* 9.4 Saturating intrinsics
*
* FIXME: Change guard to their corrosponding __ARM_FEATURE flag when Q flag
* intrinsics are implemented and the flag is enabled.
*/
/* 9.4.1 Width-specified saturation intrinsics */
-#if __ARM_32BIT_STATE
+#if __ARM_FEATURE_SAT
#define __ssat(x, y) __builtin_arm_ssat(x, y)
#define __usat(x, y) __builtin_arm_usat(x, y)
#endif
/* 9.4.2 Saturating addition and subtraction intrinsics */
-#if __ARM_32BIT_STATE
+#if __ARM_FEATURE_DSP
static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
__qadd(int32_t __t, int32_t __v) {
return __builtin_arm_qadd(__t, __v);
@@ -254,6 +284,290 @@ __qdbl(int32_t __t) {
}
#endif
+/* 9.4.3 Accumultating multiplications */
+#if __ARM_FEATURE_DSP
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlabb(int32_t __a, int32_t __b, int32_t __c) {
+ return __builtin_arm_smlabb(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlabt(int32_t __a, int32_t __b, int32_t __c) {
+ return __builtin_arm_smlabt(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlatb(int32_t __a, int32_t __b, int32_t __c) {
+ return __builtin_arm_smlatb(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlatt(int32_t __a, int32_t __b, int32_t __c) {
+ return __builtin_arm_smlatt(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlawb(int32_t __a, int32_t __b, int32_t __c) {
+ return __builtin_arm_smlawb(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlawt(int32_t __a, int32_t __b, int32_t __c) {
+ return __builtin_arm_smlawt(__a, __b, __c);
+}
+#endif
+
+
+/* 9.5.4 Parallel 16-bit saturation */
+#if __ARM_FEATURE_SIMD32
+#define __ssat16(x, y) __builtin_arm_ssat16(x, y)
+#define __usat16(x, y) __builtin_arm_usat16(x, y)
+#endif
+
+/* 9.5.5 Packing and unpacking */
+#if __ARM_FEATURE_SIMD32
+typedef int32_t int8x4_t;
+typedef int32_t int16x2_t;
+typedef uint32_t uint8x4_t;
+typedef uint32_t uint16x2_t;
+
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__sxtab16(int16x2_t __a, int8x4_t __b) {
+ return __builtin_arm_sxtab16(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__sxtb16(int8x4_t __a) {
+ return __builtin_arm_sxtb16(__a);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__uxtab16(int16x2_t __a, int8x4_t __b) {
+ return __builtin_arm_uxtab16(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__uxtb16(int8x4_t __a) {
+ return __builtin_arm_uxtb16(__a);
+}
+#endif
+
+/* 9.5.6 Parallel selection */
+#if __ARM_FEATURE_SIMD32
+static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
+__sel(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_sel(__a, __b);
+}
+#endif
+
+/* 9.5.7 Parallel 8-bit addition and subtraction */
+#if __ARM_FEATURE_SIMD32
+static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__))
+__qadd8(int8x4_t __a, int8x4_t __b) {
+ return __builtin_arm_qadd8(__a, __b);
+}
+static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__))
+__qsub8(int8x4_t __a, int8x4_t __b) {
+ return __builtin_arm_qsub8(__a, __b);
+}
+static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__))
+__sadd8(int8x4_t __a, int8x4_t __b) {
+ return __builtin_arm_sadd8(__a, __b);
+}
+static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__))
+__shadd8(int8x4_t __a, int8x4_t __b) {
+ return __builtin_arm_shadd8(__a, __b);
+}
+static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__))
+__shsub8(int8x4_t __a, int8x4_t __b) {
+ return __builtin_arm_shsub8(__a, __b);
+}
+static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__))
+__ssub8(int8x4_t __a, int8x4_t __b) {
+ return __builtin_arm_ssub8(__a, __b);
+}
+static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
+__uadd8(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_uadd8(__a, __b);
+}
+static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
+__uhadd8(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_uhadd8(__a, __b);
+}
+static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
+__uhsub8(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_uhsub8(__a, __b);
+}
+static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
+__uqadd8(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_uqadd8(__a, __b);
+}
+static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
+__uqsub8(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_uqsub8(__a, __b);
+}
+static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
+__usub8(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_usub8(__a, __b);
+}
+#endif
+
+/* 9.5.8 Sum of 8-bit absolute differences */
+#if __ARM_FEATURE_SIMD32
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+__usad8(uint8x4_t __a, uint8x4_t __b) {
+ return __builtin_arm_usad8(__a, __b);
+}
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+__usada8(uint8x4_t __a, uint8x4_t __b, uint32_t __c) {
+ return __builtin_arm_usada8(__a, __b, __c);
+}
+#endif
+
+/* 9.5.9 Parallel 16-bit addition and subtraction */
+#if __ARM_FEATURE_SIMD32
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__qadd16(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_qadd16(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__qasx(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_qasx(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__qsax(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_qsax(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__qsub16(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_qsub16(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__sadd16(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_sadd16(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__sasx(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_sasx(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__shadd16(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_shadd16(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__shasx(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_shasx(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__shsax(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_shsax(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__shsub16(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_shsub16(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__ssax(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_ssax(__a, __b);
+}
+static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
+__ssub16(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_ssub16(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uadd16(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uadd16(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uasx(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uasx(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uhadd16(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uhadd16(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uhasx(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uhasx(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uhsax(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uhsax(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uhsub16(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uhsub16(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uqadd16(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uqadd16(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uqasx(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uqasx(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uqsax(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uqsax(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__uqsub16(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_uqsub16(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__usax(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_usax(__a, __b);
+}
+static __inline__ uint16x2_t __attribute__((__always_inline__, __nodebug__))
+__usub16(uint16x2_t __a, uint16x2_t __b) {
+ return __builtin_arm_usub16(__a, __b);
+}
+#endif
+
+/* 9.5.10 Parallel 16-bit multiplications */
+#if __ARM_FEATURE_SIMD32
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlad(int16x2_t __a, int16x2_t __b, int32_t __c) {
+ return __builtin_arm_smlad(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smladx(int16x2_t __a, int16x2_t __b, int32_t __c) {
+ return __builtin_arm_smladx(__a, __b, __c);
+}
+static __inline__ int64_t __attribute__((__always_inline__, __nodebug__))
+__smlald(int16x2_t __a, int16x2_t __b, int64_t __c) {
+ return __builtin_arm_smlald(__a, __b, __c);
+}
+static __inline__ int64_t __attribute__((__always_inline__, __nodebug__))
+__smlaldx(int16x2_t __a, int16x2_t __b, int64_t __c) {
+ return __builtin_arm_smlaldx(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlsd(int16x2_t __a, int16x2_t __b, int32_t __c) {
+ return __builtin_arm_smlsd(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smlsdx(int16x2_t __a, int16x2_t __b, int32_t __c) {
+ return __builtin_arm_smlsdx(__a, __b, __c);
+}
+static __inline__ int64_t __attribute__((__always_inline__, __nodebug__))
+__smlsld(int16x2_t __a, int16x2_t __b, int64_t __c) {
+ return __builtin_arm_smlsld(__a, __b, __c);
+}
+static __inline__ int64_t __attribute__((__always_inline__, __nodebug__))
+__smlsldx(int16x2_t __a, int16x2_t __b, int64_t __c) {
+ return __builtin_arm_smlsldx(__a, __b, __c);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smuad(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_smuad(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smuadx(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_smuadx(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smusd(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_smusd(__a, __b);
+}
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+__smusdx(int16x2_t __a, int16x2_t __b) {
+ return __builtin_arm_smusdx(__a, __b);
+}
+#endif
+
/* 9.7 CRC32 intrinsics */
#if __ARM_FEATURE_CRC32
static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 13bcbef4db..caf4ced920 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -145,13 +145,21 @@ _mm256_andnot_si256(__m256i __a, __m256i __b)
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_avg_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pavgb256((__v32qi)__a, (__v32qi)__b);
+ typedef unsigned short __v32hu __attribute__((__vector_size__(64)));
+ return (__m256i)__builtin_convertvector(
+ ((__builtin_convertvector((__v32qu)__a, __v32hu) +
+ __builtin_convertvector((__v32qu)__b, __v32hu)) + 1)
+ >> 1, __v32qu);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_avg_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pavgw256((__v16hi)__a, (__v16hi)__b);
+ typedef unsigned int __v16su __attribute__((__vector_size__(64)));
+ return (__m256i)__builtin_convertvector(
+ ((__builtin_convertvector((__v16hu)__a, __v16su) +
+ __builtin_convertvector((__v16hu)__b, __v16su)) + 1)
+ >> 1, __v16hu);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
@@ -832,7 +840,8 @@ _mm256_xor_si256(__m256i __a, __m256i __b)
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_stream_load_si256(__m256i const *__V)
{
- return (__m256i)__builtin_ia32_movntdqa256((const __v4di *)__V);
+ typedef __v4di __v4di_aligned __attribute__((aligned(32)));
+ return (__m256i)__builtin_nontemporal_load((const __v4di_aligned *)__V);
}
static __inline__ __m128 __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512bwintrin.h b/lib/Headers/avx512bwintrin.h
index 41958b7214..53da5869d3 100644
--- a/lib/Headers/avx512bwintrin.h
+++ b/lib/Headers/avx512bwintrin.h
@@ -706,57 +706,55 @@ _mm512_maskz_adds_epu16 (__mmask32 __U, __m512i __A, __m512i __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_avg_epu8 (__m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_pavgb512_mask ((__v64qi) __A,
- (__v64qi) __B,
- (__v64qi) _mm512_setzero_qi(),
- (__mmask64) -1);
+ typedef unsigned short __v64hu __attribute__((__vector_size__(128)));
+ return (__m512i)__builtin_convertvector(
+ ((__builtin_convertvector((__v64qu) __A, __v64hu) +
+ __builtin_convertvector((__v64qu) __B, __v64hu)) + 1)
+ >> 1, __v64qu);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_avg_epu8 (__m512i __W, __mmask64 __U, __m512i __A,
__m512i __B)
{
- return (__m512i) __builtin_ia32_pavgb512_mask ((__v64qi) __A,
- (__v64qi) __B,
- (__v64qi) __W,
- (__mmask64) __U);
+ return (__m512i)__builtin_ia32_selectb_512((__mmask64)__U,
+ (__v64qi)_mm512_avg_epu8(__A, __B),
+ (__v64qi)__W);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_avg_epu8 (__mmask64 __U, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_pavgb512_mask ((__v64qi) __A,
- (__v64qi) __B,
- (__v64qi) _mm512_setzero_qi(),
- (__mmask64) __U);
+ return (__m512i)__builtin_ia32_selectb_512((__mmask64)__U,
+ (__v64qi)_mm512_avg_epu8(__A, __B),
+ (__v64qi)_mm512_setzero_qi());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_avg_epu16 (__m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_pavgw512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v32hi) _mm512_setzero_hi(),
- (__mmask32) -1);
+ typedef unsigned int __v32su __attribute__((__vector_size__(128)));
+ return (__m512i)__builtin_convertvector(
+ ((__builtin_convertvector((__v32hu) __A, __v32su) +
+ __builtin_convertvector((__v32hu) __B, __v32su)) + 1)
+ >> 1, __v32hu);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_avg_epu16 (__m512i __W, __mmask32 __U, __m512i __A,
__m512i __B)
{
- return (__m512i) __builtin_ia32_pavgw512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v32hi) __W,
- (__mmask32) __U);
+ return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U,
+ (__v32hi)_mm512_avg_epu16(__A, __B),
+ (__v32hi)__W);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_avg_epu16 (__mmask32 __U, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_pavgw512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v32hi) _mm512_setzero_hi(),
- (__mmask32) __U);
+ return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U,
+ (__v32hi)_mm512_avg_epu16(__A, __B),
+ (__v32hi) _mm512_setzero_hi());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
@@ -2028,18 +2026,17 @@ _mm512_maskz_mov_epi8 (__mmask64 __U, __m512i __A)
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_set1_epi8 (__m512i __O, __mmask64 __M, char __A)
{
- return (__m512i) __builtin_ia32_pbroadcastb512_gpr_mask (__A,
- (__v64qi) __O,
- __M);
+ return (__m512i) __builtin_ia32_selectb_512(__M,
+ (__v64qi)_mm512_set1_epi8(__A),
+ (__v64qi) __O);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_set1_epi8 (__mmask64 __M, char __A)
{
- return (__m512i) __builtin_ia32_pbroadcastb512_gpr_mask (__A,
- (__v64qi)
- _mm512_setzero_qi(),
- __M);
+ return (__m512i) __builtin_ia32_selectb_512(__M,
+ (__v64qi) _mm512_set1_epi8(__A),
+ (__v64qi) _mm512_setzero_si512());
}
static __inline__ __mmask64 __DEFAULT_FN_ATTRS
@@ -2219,17 +2216,17 @@ _mm512_maskz_broadcastb_epi8 (__mmask64 __M, __m128i __A)
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_set1_epi16 (__m512i __O, __mmask32 __M, short __A)
{
- return (__m512i) __builtin_ia32_pbroadcastw512_gpr_mask (__A,
- (__v32hi) __O,
- __M);
+ return (__m512i) __builtin_ia32_selectw_512(__M,
+ (__v32hi) _mm512_set1_epi16(__A),
+ (__v32hi) __O);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_set1_epi16 (__mmask32 __M, short __A)
{
- return (__m512i) __builtin_ia32_pbroadcastw512_gpr_mask (__A,
- (__v32hi) _mm512_setzero_hi(),
- __M);
+ return (__m512i) __builtin_ia32_selectw_512(__M,
+ (__v32hi) _mm512_set1_epi16(__A),
+ (__v32hi) _mm512_setzero_si512());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512dqintrin.h b/lib/Headers/avx512dqintrin.h
index 4fd1add773..2c431d9740 100644
--- a/lib/Headers/avx512dqintrin.h
+++ b/lib/Headers/avx512dqintrin.h
@@ -973,25 +973,26 @@ _mm512_movepi64_mask (__m512i __A)
static __inline__ __m512 __DEFAULT_FN_ATTRS
_mm512_broadcast_f32x2 (__m128 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x2_512_mask ((__v4sf) __A,
- (__v16sf)_mm512_undefined_ps(),
- (__mmask16) -1);
+ return (__m512)__builtin_shufflevector((__v4sf)__A,
+ (__v4sf)_mm_undefined_ps(),
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1);
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
_mm512_mask_broadcast_f32x2 (__m512 __O, __mmask16 __M, __m128 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x2_512_mask ((__v4sf) __A,
- (__v16sf)
- __O, __M);
+ return (__m512)__builtin_ia32_selectps_512((__mmask16)__M,
+ (__v16sf)_mm512_broadcast_f32x2(__A),
+ (__v16sf)__O);
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
_mm512_maskz_broadcast_f32x2 (__mmask16 __M, __m128 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x2_512_mask ((__v4sf) __A,
- (__v16sf)_mm512_setzero_ps (),
- __M);
+ return (__m512)__builtin_ia32_selectps_512((__mmask16)__M,
+ (__v16sf)_mm512_broadcast_f32x2(__A),
+ (__v16sf)_mm512_setzero_ps());
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
@@ -1044,25 +1045,26 @@ _mm512_maskz_broadcast_f64x2(__mmask8 __M, __m128d __A)
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_broadcast_i32x2 (__m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x2_512_mask ((__v4si) __A,
- (__v16si)_mm512_setzero_si512(),
- (__mmask16) -1);
+ return (__m512i)__builtin_shufflevector((__v4si)__A,
+ (__v4si)_mm_undefined_si128(),
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_broadcast_i32x2 (__m512i __O, __mmask16 __M, __m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x2_512_mask ((__v4si) __A,
- (__v16si)
- __O, __M);
+ return (__m512i)__builtin_ia32_selectd_512((__mmask16)__M,
+ (__v16si)_mm512_broadcast_i32x2(__A),
+ (__v16si)__O);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_broadcast_i32x2 (__mmask16 __M, __m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x2_512_mask ((__v4si) __A,
- (__v16si)_mm512_setzero_si512 (),
- __M);
+ return (__m512i)__builtin_ia32_selectd_512((__mmask16)__M,
+ (__v16si)_mm512_broadcast_i32x2(__A),
+ (__v16si)_mm512_setzero_si512());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512fintrin.h b/lib/Headers/avx512fintrin.h
index 7d9a52fdf2..247ac879ea 100644
--- a/lib/Headers/avx512fintrin.h
+++ b/lib/Headers/avx512fintrin.h
@@ -258,30 +258,6 @@ _mm512_maskz_broadcastq_epi64 (__mmask8 __M, __m128i __A)
(__v8di) _mm512_setzero_si512());
}
-static __inline __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_set1_epi32(__mmask16 __M, int __A)
-{
- return (__m512i) __builtin_ia32_pbroadcastd512_gpr_mask (__A,
- (__v16si)
- _mm512_setzero_si512 (),
- __M);
-}
-
-static __inline __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_set1_epi64(__mmask8 __M, long long __A)
-{
-#ifdef __x86_64__
- return (__m512i) __builtin_ia32_pbroadcastq512_gpr_mask (__A,
- (__v8di)
- _mm512_setzero_si512 (),
- __M);
-#else
- return (__m512i) __builtin_ia32_pbroadcastq512_mem_mask (__A,
- (__v8di)
- _mm512_setzero_si512 (),
- __M);
-#endif
-}
static __inline __m512 __DEFAULT_FN_ATTRS
_mm512_setzero_ps(void)
@@ -341,11 +317,29 @@ _mm512_set1_epi32(int __s)
}
static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_maskz_set1_epi32(__mmask16 __M, int __A)
+{
+ return (__m512i)__builtin_ia32_selectd_512(__M,
+ (__v16si)_mm512_set1_epi32(__A),
+ (__v16si)_mm512_setzero_si512());
+}
+
+static __inline __m512i __DEFAULT_FN_ATTRS
_mm512_set1_epi64(long long __d)
{
return (__m512i)(__v8di){ __d, __d, __d, __d, __d, __d, __d, __d };
}
+#ifdef __x86_64__
+static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_maskz_set1_epi64(__mmask8 __M, long long __A)
+{
+ return (__m512i)__builtin_ia32_selectq_512(__M,
+ (__v8di)_mm512_set1_epi64(__A),
+ (__v8di)_mm512_setzero_si512());
+}
+#endif
+
static __inline__ __m512 __DEFAULT_FN_ATTRS
_mm512_broadcastss_ps(__m128 __A)
{
@@ -528,6 +522,116 @@ _mm512_mask2int(__mmask16 __a)
return (int)__a;
}
+/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a
+/// 128-bit floating-point vector of [2 x double]. The lower 128 bits
+/// contain the value of the source vector. The upper 384 bits are set
+/// to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [2 x double].
+/// \returns A 512-bit floating-point vector of [8 x double]. The lower 128 bits
+/// contain the value of the parameter. The upper 384 bits are set to zero.
+static __inline __m512d __DEFAULT_FN_ATTRS
+_mm512_zextpd128_pd512(__m128d __a)
+{
+ return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3, 2, 3, 2, 3);
+}
+
+/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a
+/// 256-bit floating-point vector of [4 x double]. The lower 256 bits
+/// contain the value of the source vector. The upper 256 bits are set
+/// to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 256-bit vector of [4 x double].
+/// \returns A 512-bit floating-point vector of [8 x double]. The lower 256 bits
+/// contain the value of the parameter. The upper 256 bits are set to zero.
+static __inline __m512d __DEFAULT_FN_ATTRS
+_mm512_zextpd256_pd512(__m256d __a)
+{
+ return __builtin_shufflevector((__v4df)__a, (__v4df)_mm256_setzero_pd(), 0, 1, 2, 3, 4, 5, 6, 7);
+}
+
+/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a
+/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain
+/// the value of the source vector. The upper 384 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [4 x float].
+/// \returns A 512-bit floating-point vector of [16 x float]. The lower 128 bits
+/// contain the value of the parameter. The upper 384 bits are set to zero.
+static __inline __m512 __DEFAULT_FN_ATTRS
+_mm512_zextps128_ps512(__m128 __a)
+{
+ return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7);
+}
+
+/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a
+/// 256-bit floating-point vector of [8 x float]. The lower 256 bits contain
+/// the value of the source vector. The upper 256 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 256-bit vector of [8 x float].
+/// \returns A 512-bit floating-point vector of [16 x float]. The lower 256 bits
+/// contain the value of the parameter. The upper 256 bits are set to zero.
+static __inline __m512 __DEFAULT_FN_ATTRS
+_mm512_zextps256_ps512(__m256 __a)
+{
+ return __builtin_shufflevector((__v8sf)__a, (__v8sf)_mm256_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+}
+
+/// \brief Constructs a 512-bit integer vector from a 128-bit integer vector.
+/// The lower 128 bits contain the value of the source vector. The upper
+/// 384 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit integer vector.
+/// \returns A 512-bit integer vector. The lower 128 bits contain the value of
+/// the parameter. The upper 384 bits are set to zero.
+static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_zextsi128_si512(__m128i __a)
+{
+ return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3, 2, 3, 2, 3);
+}
+
+/// \brief Constructs a 512-bit integer vector from a 256-bit integer vector.
+/// The lower 256 bits contain the value of the source vector. The upper
+/// 256 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 256-bit integer vector.
+/// \returns A 512-bit integer vector. The lower 256 bits contain the value of
+/// the parameter. The upper 256 bits are set to zero.
+static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_zextsi256_si512(__m256i __a)
+{
+ return __builtin_shufflevector((__v4di)__a, (__v4di)_mm256_setzero_si256(), 0, 1, 2, 3, 4, 5, 6, 7);
+}
+
/* Bitwise operators */
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_and_epi32(__m512i __a, __m512i __b)
@@ -4179,7 +4283,7 @@ static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_cvtps_epu32 ( __mmask16 __U, __m512 __A)
{
return (__m512i) __builtin_ia32_cvtps2udq512_mask ((__v16sf) __A,
- (__v16si)
+ (__v16si)
_mm512_setzero_si512 (),
(__mmask16) __U ,
_MM_FROUND_CUR_DIRECTION);
@@ -4229,6 +4333,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 +4656,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 +4665,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 +4674,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 +4700,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)
@@ -7850,12 +7966,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()); })
@@ -7868,12 +7984,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()); })
@@ -8149,11 +8265,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(), \
@@ -8848,6 +8964,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)
@@ -8858,6 +8976,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)
{
@@ -8909,25 +9029,29 @@ _mm512_kxor (__mmask16 __A, __mmask16 __B)
static __inline__ void __DEFAULT_FN_ATTRS
_mm512_stream_si512 (__m512i * __P, __m512i __A)
{
- __builtin_nontemporal_store((__v8di)__A, (__v8di*)__P);
+ typedef __v8di __v8di_aligned __attribute__((aligned(64)));
+ __builtin_nontemporal_store((__v8di_aligned)__A, (__v8di_aligned*)__P);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_stream_load_si512 (void *__P)
+_mm512_stream_load_si512 (void const *__P)
{
- return __builtin_ia32_movntdqa512 ((__v8di *)__P);
+ typedef __v8di __v8di_aligned __attribute__((aligned(64)));
+ return (__m512i) __builtin_nontemporal_load((const __v8di_aligned *)__P);
}
static __inline__ void __DEFAULT_FN_ATTRS
_mm512_stream_pd (double *__P, __m512d __A)
{
- __builtin_nontemporal_store((__v8df)__A, (__v8df*)__P);
+ typedef __v8df __v8df_aligned __attribute__((aligned(64)));
+ __builtin_nontemporal_store((__v8df_aligned)__A, (__v8df_aligned*)__P);
}
static __inline__ void __DEFAULT_FN_ATTRS
_mm512_stream_ps (float *__P, __m512 __A)
{
- __builtin_nontemporal_store((__v16sf)__A, (__v16sf*)__P);
+ typedef __v16sf __v16sf_aligned __attribute__((aligned(64)));
+ __builtin_nontemporal_store((__v16sf_aligned)__A, (__v16sf_aligned*)__P);
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
@@ -9091,39 +9215,39 @@ _mm512_maskz_moveldup_ps (__mmask16 __U, __m512 __A)
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_move_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B)
{
- __m128 res = __A;
+ __m128 res = __A;
res[0] = (__U & 1) ? __B[0] : __W[0];
- return res;
+ return res;
}
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_move_ss (__mmask8 __U, __m128 __A, __m128 __B)
{
- __m128 res = __A;
- res[0] = (__U & 1) ? __B[0] : 0;
- return res;
+ __m128 res = __A;
+ res[0] = (__U & 1) ? __B[0] : 0;
+ return res;
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_move_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B)
{
- __m128d res = __A;
+ __m128d res = __A;
res[0] = (__U & 1) ? __B[0] : __W[0];
- return res;
+ return res;
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_move_sd (__mmask8 __U, __m128d __A, __m128d __B)
{
- __m128d res = __A;
- res[0] = (__U & 1) ? __B[0] : 0;
- return res;
+ __m128d res = __A;
+ res[0] = (__U & 1) ? __B[0] : 0;
+ return res;
}
static __inline__ void __DEFAULT_FN_ATTRS
_mm_mask_store_ss (float * __W, __mmask8 __U, __m128 __A)
{
- __builtin_ia32_storess128_mask ((__v16sf *)__W,
+ __builtin_ia32_storess128_mask ((__v16sf *)__W,
(__v16sf) _mm512_castps128_ps512(__A),
(__mmask16) __U & (__mmask16)1);
}
@@ -9131,7 +9255,7 @@ _mm_mask_store_ss (float * __W, __mmask8 __U, __m128 __A)
static __inline__ void __DEFAULT_FN_ATTRS
_mm_mask_store_sd (double * __W, __mmask8 __U, __m128d __A)
{
- __builtin_ia32_storesd128_mask ((__v8df *)__W,
+ __builtin_ia32_storesd128_mask ((__v8df *)__W,
(__v8df) _mm512_castpd128_pd512(__A),
(__mmask8) __U & 1);
}
@@ -9480,7 +9604,7 @@ _mm_mask_cvtsd_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128d __B)
{
return __builtin_ia32_cvtsd2ss_round_mask ((__v4sf)(__A),
(__v2df)(__B),
- (__v4sf)(__W),
+ (__v4sf)(__W),
(__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
@@ -9489,7 +9613,7 @@ _mm_maskz_cvtsd_ss (__mmask8 __U, __m128 __A, __m128d __B)
{
return __builtin_ia32_cvtsd2ss_round_mask ((__v4sf)(__A),
(__v2df)(__B),
- (__v4sf)_mm_setzero_ps(),
+ (__v4sf)_mm_setzero_ps(),
(__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
@@ -9554,7 +9678,7 @@ _mm_mask_cvtss_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128 __B)
return __builtin_ia32_cvtss2sd_round_mask((__v2df)(__A),
(__v4sf)(__B),
(__v2df)(__W),
- (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
+ (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
@@ -9562,8 +9686,8 @@ _mm_maskz_cvtss_sd (__mmask8 __U, __m128d __A, __m128 __B)
{
return __builtin_ia32_cvtss2sd_round_mask((__v2df)(__A),
(__v4sf)(__B),
- (__v2df)_mm_setzero_pd(),
- (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
+ (__v2df)_mm_setzero_pd(),
+ (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
@@ -9612,19 +9736,60 @@ _mm_cvtu64_ss (__m128 __A, unsigned long long __B)
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_set1_epi32 (__m512i __O, __mmask16 __M, int __A)
{
- return (__m512i) __builtin_ia32_pbroadcastd512_gpr_mask (__A, (__v16si) __O,
- __M);
+ return (__m512i) __builtin_ia32_selectd_512(__M,
+ (__v16si) _mm512_set1_epi32(__A),
+ (__v16si) __O);
}
#ifdef __x86_64__
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_set1_epi64 (__m512i __O, __mmask8 __M, long long __A)
{
- return (__m512i) __builtin_ia32_pbroadcastq512_gpr_mask (__A, (__v8di) __O,
- __M);
+ return (__m512i) __builtin_ia32_selectq_512(__M,
+ (__v8di) _mm512_set1_epi64(__A),
+ (__v8di) __O);
}
#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,
@@ -9770,7 +9935,7 @@ static __inline__ double __DEFAULT_FN_ATTRS _mm512_reduce_mul_pd(__m512d __W) {
}
// Vec512 - Vector with size 512.
-// Vec512Neutral - All vector elements set to the identity element.
+// Vec512Neutral - All vector elements set to the identity element.
// Identity element: {+,0},{*,1},{&,0xFFFFFFFFFFFFFFFF},{|,0}
// Operator - Can be one of following: +,*,&,|
// Mask - Intrinsic Mask
@@ -9800,19 +9965,19 @@ _mm512_mask_reduce_mul_epi64(__mmask8 __M, __m512i __W) {
static __inline__ long long __DEFAULT_FN_ATTRS
_mm512_mask_reduce_and_epi64(__mmask8 __M, __m512i __W) {
- _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0xFFFFFFFFFFFFFFFF),
+ _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0xFFFFFFFFFFFFFFFF),
&, __M, i, i, q);
}
static __inline__ long long __DEFAULT_FN_ATTRS
_mm512_mask_reduce_or_epi64(__mmask8 __M, __m512i __W) {
- _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0), |, __M,
+ _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0), |, __M,
i, i, q);
}
static __inline__ double __DEFAULT_FN_ATTRS
_mm512_mask_reduce_add_pd(__mmask8 __M, __m512d __W) {
- _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_pd(0), +, __M,
+ _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_pd(0), +, __M,
f, d, pd);
}
@@ -9874,17 +10039,17 @@ _mm512_reduce_add_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, +, i, i);
}
-static __inline__ int __DEFAULT_FN_ATTRS
+static __inline__ int __DEFAULT_FN_ATTRS
_mm512_reduce_mul_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, *, i, i);
}
-static __inline__ int __DEFAULT_FN_ATTRS
+static __inline__ int __DEFAULT_FN_ATTRS
_mm512_reduce_and_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, &, i, i);
}
-static __inline__ int __DEFAULT_FN_ATTRS
+static __inline__ int __DEFAULT_FN_ATTRS
_mm512_reduce_or_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, |, i, i);
}
@@ -9900,7 +10065,7 @@ _mm512_reduce_mul_ps(__m512 __W) {
}
// Vec512 - Vector with size 512.
-// Vec512Neutral - All vector elements set to the identity element.
+// Vec512Neutral - All vector elements set to the identity element.
// Identity element: {+,0},{*,1},{&,0xFFFFFFFF},{|,0}
// Operator - Can be one of following: +,*,&,|
// Mask - Intrinsic Mask
@@ -9930,7 +10095,7 @@ _mm512_mask_reduce_mul_epi32( __mmask16 __M, __m512i __W) {
static __inline__ int __DEFAULT_FN_ATTRS
_mm512_mask_reduce_and_epi32( __mmask16 __M, __m512i __W) {
- _mm512_mask_reduce_operator_32bit(__W, _mm512_set1_epi32(0xFFFFFFFF), &, __M,
+ _mm512_mask_reduce_operator_32bit(__W, _mm512_set1_epi32(0xFFFFFFFF), &, __M,
i, i, d);
}
@@ -9993,7 +10158,7 @@ _mm512_mask_reduce_mul_ps(__mmask16 __M, __m512 __W) {
return Vec512[0]; \
})
-static __inline__ long long __DEFAULT_FN_ATTRS
+static __inline__ long long __DEFAULT_FN_ATTRS
_mm512_reduce_max_epi64(__m512i __V) {
_mm512_reduce_maxMin_64bit(__V, max_epi64, i, i);
}
@@ -10003,7 +10168,7 @@ _mm512_reduce_max_epu64(__m512i __V) {
_mm512_reduce_maxMin_64bit(__V, max_epu64, i, i);
}
-static __inline__ double __DEFAULT_FN_ATTRS
+static __inline__ double __DEFAULT_FN_ATTRS
_mm512_reduce_max_pd(__m512d __V) {
_mm512_reduce_maxMin_64bit(__V, max_pd, d, f);
}
@@ -10018,7 +10183,7 @@ _mm512_reduce_min_epu64(__m512i __V) {
_mm512_reduce_maxMin_64bit(__V, min_epu64, i, i);
}
-static __inline__ double __DEFAULT_FN_ATTRS
+static __inline__ double __DEFAULT_FN_ATTRS
_mm512_reduce_min_pd(__m512d __V) {
_mm512_reduce_maxMin_64bit(__V, min_pd, d, f);
}
diff --git a/lib/Headers/avx512vlbwintrin.h b/lib/Headers/avx512vlbwintrin.h
index 3b58d04339..4ab785bdbb 100644
--- a/lib/Headers/avx512vlbwintrin.h
+++ b/lib/Headers/avx512vlbwintrin.h
@@ -2660,35 +2660,33 @@ _mm256_maskz_mov_epi8 (__mmask32 __U, __m256i __A)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_mask_set1_epi8 (__m128i __O, __mmask16 __M, char __A)
{
- return (__m128i) __builtin_ia32_pbroadcastb128_gpr_mask (__A,
- (__v16qi) __O,
- __M);
+ return (__m128i) __builtin_ia32_selectb_128(__M,
+ (__v16qi) _mm_set1_epi8(__A),
+ (__v16qi) __O);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_maskz_set1_epi8 (__mmask16 __M, char __A)
{
- return (__m128i) __builtin_ia32_pbroadcastb128_gpr_mask (__A,
- (__v16qi)
- _mm_setzero_si128 (),
- __M);
+ return (__m128i) __builtin_ia32_selectb_128(__M,
+ (__v16qi) _mm_set1_epi8(__A),
+ (__v16qi) _mm_setzero_si128());
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_mask_set1_epi8 (__m256i __O, __mmask32 __M, char __A)
{
- return (__m256i) __builtin_ia32_pbroadcastb256_gpr_mask (__A,
- (__v32qi) __O,
- __M);
+ return (__m256i) __builtin_ia32_selectb_256(__M,
+ (__v32qi) _mm256_set1_epi8(__A),
+ (__v32qi) __O);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_maskz_set1_epi8 (__mmask32 __M, char __A)
{
- return (__m256i) __builtin_ia32_pbroadcastb256_gpr_mask (__A,
- (__v32qi)
- _mm256_setzero_si256 (),
- __M);
+ return (__m256i) __builtin_ia32_selectb_256(__M,
+ (__v32qi) _mm256_set1_epi8(__A),
+ (__v32qi) _mm256_setzero_si256());
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
@@ -3025,33 +3023,33 @@ _mm256_maskz_broadcastw_epi16 (__mmask16 __M, __m128i __A)
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_mask_set1_epi16 (__m256i __O, __mmask16 __M, short __A)
{
- return (__m256i) __builtin_ia32_pbroadcastw256_gpr_mask (__A,
- (__v16hi) __O,
- __M);
+ return (__m256i) __builtin_ia32_selectw_256 (__M,
+ (__v16hi) _mm256_set1_epi16(__A),
+ (__v16hi) __O);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_maskz_set1_epi16 (__mmask16 __M, short __A)
{
- return (__m256i) __builtin_ia32_pbroadcastw256_gpr_mask (__A,
- (__v16hi) _mm256_setzero_si256 (),
- __M);
+ return (__m256i) __builtin_ia32_selectw_256(__M,
+ (__v16hi)_mm256_set1_epi16(__A),
+ (__v16hi) _mm256_setzero_si256());
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_mask_set1_epi16 (__m128i __O, __mmask8 __M, short __A)
{
- return (__m128i) __builtin_ia32_pbroadcastw128_gpr_mask (__A,
- (__v8hi) __O,
- __M);
+ return (__m128i) __builtin_ia32_selectw_128(__M,
+ (__v8hi) _mm_set1_epi16(__A),
+ (__v8hi) __O);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_maskz_set1_epi16 (__mmask8 __M, short __A)
{
- return (__m128i) __builtin_ia32_pbroadcastw128_gpr_mask (__A,
- (__v8hi) _mm_setzero_si128 (),
- __M);
+ return (__m128i) __builtin_ia32_selectw_128(__M,
+ (__v8hi) _mm_set1_epi16(__A),
+ (__v8hi) _mm_setzero_si128());
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512vldqintrin.h b/lib/Headers/avx512vldqintrin.h
index aecd7df34d..d80df9eaff 100644
--- a/lib/Headers/avx512vldqintrin.h
+++ b/lib/Headers/avx512vldqintrin.h
@@ -978,25 +978,25 @@ _mm256_movepi64_mask (__m256i __A)
static __inline__ __m256 __DEFAULT_FN_ATTRS
_mm256_broadcast_f32x2 (__m128 __A)
{
- return (__m256) __builtin_ia32_broadcastf32x2_256_mask ((__v4sf) __A,
- (__v8sf)_mm256_undefined_ps(),
- (__mmask8) -1);
+ return (__m256)__builtin_shufflevector((__v4sf)__A,
+ (__v4sf)_mm_undefined_ps(),
+ 0, 1, 0, 1, 0, 1, 0, 1);
}
static __inline__ __m256 __DEFAULT_FN_ATTRS
_mm256_mask_broadcast_f32x2 (__m256 __O, __mmask8 __M, __m128 __A)
{
- return (__m256) __builtin_ia32_broadcastf32x2_256_mask ((__v4sf) __A,
- (__v8sf) __O,
- __M);
+ return (__m256)__builtin_ia32_selectps_256((__mmask8)__M,
+ (__v8sf)_mm256_broadcast_f32x2(__A),
+ (__v8sf)__O);
}
static __inline__ __m256 __DEFAULT_FN_ATTRS
_mm256_maskz_broadcast_f32x2 (__mmask8 __M, __m128 __A)
{
- return (__m256) __builtin_ia32_broadcastf32x2_256_mask ((__v4sf) __A,
- (__v8sf) _mm256_setzero_ps (),
- __M);
+ return (__m256)__builtin_ia32_selectps_256((__mmask8)__M,
+ (__v8sf)_mm256_broadcast_f32x2(__A),
+ (__v8sf)_mm256_setzero_ps());
}
static __inline__ __m256d __DEFAULT_FN_ATTRS
@@ -1025,49 +1025,49 @@ _mm256_maskz_broadcast_f64x2 (__mmask8 __M, __m128d __A)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_broadcast_i32x2 (__m128i __A)
{
- return (__m128i) __builtin_ia32_broadcasti32x2_128_mask ((__v4si) __A,
- (__v4si)_mm_undefined_si128(),
- (__mmask8) -1);
+ return (__m128i)__builtin_shufflevector((__v4si)__A,
+ (__v4si)_mm_undefined_si128(),
+ 0, 1, 0, 1);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_mask_broadcast_i32x2 (__m128i __O, __mmask8 __M, __m128i __A)
{
- return (__m128i) __builtin_ia32_broadcasti32x2_128_mask ((__v4si) __A,
- (__v4si) __O,
- __M);
+ return (__m128i)__builtin_ia32_selectd_128((__mmask8)__M,
+ (__v4si)_mm_broadcast_i32x2(__A),
+ (__v4si)__O);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_maskz_broadcast_i32x2 (__mmask8 __M, __m128i __A)
{
- return (__m128i) __builtin_ia32_broadcasti32x2_128_mask ((__v4si) __A,
- (__v4si) _mm_setzero_si128 (),
- __M);
+ return (__m128i)__builtin_ia32_selectd_128((__mmask8)__M,
+ (__v4si)_mm_broadcast_i32x2(__A),
+ (__v4si)_mm_setzero_si128());
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_broadcast_i32x2 (__m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti32x2_256_mask ((__v4si) __A,
- (__v8si)_mm256_undefined_si256(),
- (__mmask8) -1);
+ return (__m256i)__builtin_shufflevector((__v4si)__A,
+ (__v4si)_mm_undefined_si128(),
+ 0, 1, 0, 1, 0, 1, 0, 1);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_mask_broadcast_i32x2 (__m256i __O, __mmask8 __M, __m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti32x2_256_mask ((__v4si) __A,
- (__v8si) __O,
- __M);
+ return (__m256i)__builtin_ia32_selectd_256((__mmask8)__M,
+ (__v8si)_mm256_broadcast_i32x2(__A),
+ (__v8si)__O);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_maskz_broadcast_i32x2 (__mmask8 __M, __m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti32x2_256_mask ((__v4si) __A,
- (__v8si) _mm256_setzero_si256 (),
- __M);
+ return (__m256i)__builtin_ia32_selectd_256((__mmask8)__M,
+ (__v8si)_mm256_broadcast_i32x2(__A),
+ (__v8si)_mm256_setzero_si256());
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/avx512vlintrin.h b/lib/Headers/avx512vlintrin.h
index 99bb050de4..7e17cff05f 100644
--- a/lib/Headers/avx512vlintrin.h
+++ b/lib/Headers/avx512vlintrin.h
@@ -5723,59 +5723,72 @@ _mm256_maskz_movedup_pd (__mmask8 __U, __m256d __A)
(__v4df)_mm256_setzero_pd());
}
+static __inline__ __m128i __DEFAULT_FN_ATTRS
+_mm_mask_set1_epi32(__m128i __O, __mmask8 __M, int __A)
+{
+ return (__m128i)__builtin_ia32_selectd_128(__M,
+ (__v4si) _mm_set1_epi32(__A),
+ (__v4si)__O);
+}
-#define _mm_mask_set1_epi32(O, M, A) __extension__ ({ \
- (__m128i)__builtin_ia32_pbroadcastd128_gpr_mask((int)(A), \
- (__v4si)(__m128i)(O), \
- (__mmask8)(M)); })
+static __inline__ __m128i __DEFAULT_FN_ATTRS
+_mm_maskz_set1_epi32( __mmask8 __M, int __A)
+{
+ return (__m128i)__builtin_ia32_selectd_128(__M,
+ (__v4si) _mm_set1_epi32(__A),
+ (__v4si)_mm_setzero_si128());
+}
-#define _mm_maskz_set1_epi32(M, A) __extension__ ({ \
- (__m128i)__builtin_ia32_pbroadcastd128_gpr_mask((int)(A), \
- (__v4si)_mm_setzero_si128(), \
- (__mmask8)(M)); })
+static __inline__ __m256i __DEFAULT_FN_ATTRS
+_mm256_mask_set1_epi32(__m256i __O, __mmask8 __M, int __A)
+{
+ return (__m256i)__builtin_ia32_selectd_256(__M,
+ (__v8si) _mm256_set1_epi32(__A),
+ (__v8si)__O);
+}
-#define _mm256_mask_set1_epi32(O, M, A) __extension__ ({ \
- (__m256i)__builtin_ia32_pbroadcastd256_gpr_mask((int)(A), \
- (__v8si)(__m256i)(O), \
- (__mmask8)(M)); })
+static __inline__ __m256i __DEFAULT_FN_ATTRS
+_mm256_maskz_set1_epi32( __mmask8 __M, int __A)
+{
+ return (__m256i)__builtin_ia32_selectd_256(__M,
+ (__v8si) _mm256_set1_epi32(__A),
+ (__v8si)_mm256_setzero_si256());
+}
-#define _mm256_maskz_set1_epi32(M, A) __extension__ ({ \
- (__m256i)__builtin_ia32_pbroadcastd256_gpr_mask((int)(A), \
- (__v8si)_mm256_setzero_si256(), \
- (__mmask8)(M)); })
#ifdef __x86_64__
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_mask_set1_epi64 (__m128i __O, __mmask8 __M, long long __A)
{
- return (__m128i) __builtin_ia32_pbroadcastq128_gpr_mask (__A, (__v2di) __O,
- __M);
+ return (__m128i) __builtin_ia32_selectq_128(__M,
+ (__v2di) _mm_set1_epi64x(__A),
+ (__v2di) __O);
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_maskz_set1_epi64 (__mmask8 __M, long long __A)
{
- return (__m128i) __builtin_ia32_pbroadcastq128_gpr_mask (__A,
- (__v2di)
- _mm_setzero_si128 (),
- __M);
+ return (__m128i) __builtin_ia32_selectq_128(__M,
+ (__v2di) _mm_set1_epi64x(__A),
+ (__v2di) _mm_setzero_si128());
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_mask_set1_epi64 (__m256i __O, __mmask8 __M, long long __A)
{
- return (__m256i) __builtin_ia32_pbroadcastq256_gpr_mask (__A, (__v4di) __O,
- __M);
+ return (__m256i) __builtin_ia32_selectq_256(__M,
+ (__v4di) _mm256_set1_epi64x(__A),
+ (__v4di) __O) ;
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_maskz_set1_epi64 (__mmask8 __M, long long __A)
{
- return (__m256i) __builtin_ia32_pbroadcastq256_gpr_mask (__A,
- (__v4di)
- _mm256_setzero_si256 (),
- __M);
+ return (__m256i) __builtin_ia32_selectq_256(__M,
+ (__v4di) _mm256_set1_epi64x(__A),
+ (__v4di) _mm256_setzero_si256());
}
+
#endif
#define _mm_fixupimm_pd(A, B, C, imm) __extension__ ({ \
diff --git a/lib/Headers/avx512vpopcntdqintrin.h b/lib/Headers/avx512vpopcntdqintrin.h
new file mode 100644
index 0000000000..34ab84932e
--- /dev/null
+++ b/lib/Headers/avx512vpopcntdqintrin.h
@@ -0,0 +1,70 @@
+/*===------------- avx512vpopcntdqintrin.h - AVX512VPOPCNTDQ intrinsics
+ *------------------===
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+#ifndef __IMMINTRIN_H
+#error \
+ "Never use <avx512vpopcntdqintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVX512VPOPCNTDQINTRIN_H
+#define __AVX512VPOPCNTDQINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS \
+ __attribute__((__always_inline__, __nodebug__, __target__("avx512vpopcntd" \
+ "q")))
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi64(__m512i __A) {
+ return (__m512i)__builtin_ia32_vpopcntq_512((__v8di)__A);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_mask_popcnt_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
+ return (__m512i)__builtin_ia32_selectq_512(
+ (__mmask8)__U, (__v8di)_mm512_popcnt_epi64(__A), (__v8di)__W);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_maskz_popcnt_epi64(__mmask8 __U, __m512i __A) {
+ return _mm512_mask_popcnt_epi64((__m512i)_mm512_setzero_si512(), __U, __A);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi32(__m512i __A) {
+ return (__m512i)__builtin_ia32_vpopcntd_512((__v16si)__A);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_mask_popcnt_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
+ return (__m512i)__builtin_ia32_selectd_512(
+ (__mmask16)__U, (__v16si)_mm512_popcnt_epi32(__A), (__v16si)__W);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_maskz_popcnt_epi32(__mmask16 __U, __m512i __A) {
+ return _mm512_mask_popcnt_epi32((__m512i)_mm512_setzero_si512(), __U, __A);
+}
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index eafb32d7ae..dff5897b6b 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -1458,12 +1458,13 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Computes two dot products in parallel, using the lower and upper
/// halves of two [8 x float] vectors as input to the two computations, and
/// returning the two dot products in the lower and upper halves of the
-/// [8 x float] result. The immediate integer operand controls which input
-/// elements will contribute to the dot product, and where the final results
-/// are returned. In general, for each dot product, the four corresponding
-/// elements of the input vectors are multiplied; the first two and second
-/// two products are summed, then the two sums are added to form the final
-/// result.
+/// [8 x float] result.
+///
+/// The immediate integer operand controls which input elements will
+/// contribute to the dot product, and where the final results are returned.
+/// In general, for each dot product, the four corresponding elements of the
+/// input vectors are multiplied; the first two and second two products are
+/// summed, then the two sums are added to form the final result.
///
/// \headerfile <x86intrin.h>
///
@@ -1497,15 +1498,16 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/* Vector shuffle */
/// \brief Selects 8 float values from the 256-bit operands of [8 x float], as
-/// specified by the immediate value operand. The four selected elements in
-/// each operand are copied to the destination according to the bits
-/// specified in the immediate operand. The selected elements from the first
-/// 256-bit operand are copied to bits [63:0] and bits [191:128] of the
-/// destination, and the selected elements from the second 256-bit operand
-/// are copied to bits [127:64] and bits [255:192] of the destination. For
-/// example, if bits [7:0] of the immediate operand contain a value of 0xFF,
-/// the 256-bit destination vector would contain the following values: b[7],
-/// b[7], a[7], a[7], b[3], b[3], a[3], a[3].
+/// specified by the immediate value operand.
+///
+/// The four selected elements in each operand are copied to the destination
+/// according to the bits specified in the immediate operand. The selected
+/// elements from the first 256-bit operand are copied to bits [63:0] and
+/// bits [191:128] of the destination, and the selected elements from the
+/// second 256-bit operand are copied to bits [127:64] and bits [255:192] of
+/// the destination. For example, if bits [7:0] of the immediate operand
+/// contain a value of 0xFF, the 256-bit destination vector would contain the
+/// following values: b[7], b[7], a[7], a[7], b[3], b[3], a[3], a[3].
///
/// \headerfile <x86intrin.h>
///
@@ -1557,13 +1559,14 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
12 + (((mask) >> 6) & 0x3)); })
/// \brief Selects four double-precision values from the 256-bit operands of
-/// [4 x double], as specified by the immediate value operand. The selected
-/// elements from the first 256-bit operand are copied to bits [63:0] and
-/// bits [191:128] in the destination, and the selected elements from the
-/// second 256-bit operand are copied to bits [127:64] and bits [255:192] in
-/// the destination. For example, if bits [3:0] of the immediate operand
-/// contain a value of 0xF, the 256-bit destination vector would contain the
-/// following values: b[3], a[3], b[1], a[1].
+/// [4 x double], as specified by the immediate value operand.
+///
+/// The selected elements from the first 256-bit operand are copied to bits
+/// [63:0] and bits [191:128] in the destination, and the selected elements
+/// from the second 256-bit operand are copied to bits [127:64] and bits
+/// [255:192] in the destination. For example, if bits [3:0] of the immediate
+/// operand contain a value of 0xF, the 256-bit destination vector would
+/// contain the following values: b[3], a[3], b[1], a[1].
///
/// \headerfile <x86intrin.h>
///
@@ -1613,9 +1616,9 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
#define _CMP_NEQ_UQ 0x04 /* Not-equal (unordered, non-signaling) */
#define _CMP_NLT_US 0x05 /* Not-less-than (unordered, signaling) */
#define _CMP_NLE_US 0x06 /* Not-less-than-or-equal (unordered, signaling) */
-#define _CMP_ORD_Q 0x07 /* Ordered (nonsignaling) */
+#define _CMP_ORD_Q 0x07 /* Ordered (non-signaling) */
#define _CMP_EQ_UQ 0x08 /* Equal (unordered, non-signaling) */
-#define _CMP_NGE_US 0x09 /* Not-greater-than-or-equal (unord, signaling) */
+#define _CMP_NGE_US 0x09 /* Not-greater-than-or-equal (unordered, signaling) */
#define _CMP_NGT_US 0x0a /* Not-greater-than (unordered, signaling) */
#define _CMP_FALSE_OQ 0x0b /* False (ordered, non-signaling) */
#define _CMP_NEQ_OQ 0x0c /* Not-equal (ordered, non-signaling) */
@@ -1628,10 +1631,10 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
#define _CMP_UNORD_S 0x13 /* Unordered (signaling) */
#define _CMP_NEQ_US 0x14 /* Not-equal (unordered, signaling) */
#define _CMP_NLT_UQ 0x15 /* Not-less-than (unordered, non-signaling) */
-#define _CMP_NLE_UQ 0x16 /* Not-less-than-or-equal (unord, non-signaling) */
+#define _CMP_NLE_UQ 0x16 /* Not-less-than-or-equal (unordered, non-signaling) */
#define _CMP_ORD_S 0x17 /* Ordered (signaling) */
#define _CMP_EQ_US 0x18 /* Equal (unordered, signaling) */
-#define _CMP_NGE_UQ 0x19 /* Not-greater-than-or-equal (unord, non-sign) */
+#define _CMP_NGE_UQ 0x19 /* Not-greater-than-or-equal (unordered, non-signaling) */
#define _CMP_NGT_UQ 0x1a /* Not-greater-than (unordered, non-signaling) */
#define _CMP_FALSE_OS 0x1b /* False (ordered, signaling) */
#define _CMP_NEQ_OS 0x1c /* Not-equal (ordered, signaling) */
@@ -1641,9 +1644,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding double-precision values of two
/// 128-bit vectors of [2 x double], using the operation specified by the
-/// immediate integer operand. Returns a [2 x double] vector consisting of
-/// two doubles corresponding to the two comparison results: zero if the
-/// comparison is false, and all 1's if the comparison is true.
+/// immediate integer operand.
+///
+/// Returns a [2 x double] vector consisting of two doubles corresponding to
+/// the two comparison results: zero if the comparison is false, and all 1's
+/// if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1660,17 +1665,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [2 x double] containing the comparison results.
#define _mm_cmp_pd(a, b, c) __extension__ ({ \
(__m128d)__builtin_ia32_cmppd((__v2df)(__m128d)(a), \
@@ -1678,9 +1704,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding values of two 128-bit vectors of
/// [4 x float], using the operation specified by the immediate integer
-/// operand. Returns a [4 x float] vector consisting of four floats
-/// corresponding to the four comparison results: zero if the comparison is
-/// false, and all 1's if the comparison is true.
+/// operand.
+///
+/// Returns a [4 x float] vector consisting of four floats corresponding to
+/// the four comparison results: zero if the comparison is false, and all 1's
+/// if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1697,17 +1725,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [4 x float] containing the comparison results.
#define _mm_cmp_ps(a, b, c) __extension__ ({ \
(__m128)__builtin_ia32_cmpps((__v4sf)(__m128)(a), \
@@ -1715,9 +1764,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding double-precision values of two
/// 256-bit vectors of [4 x double], using the operation specified by the
-/// immediate integer operand. Returns a [4 x double] vector consisting of
-/// four doubles corresponding to the four comparison results: zero if the
-/// comparison is false, and all 1's if the comparison is true.
+/// immediate integer operand.
+///
+/// Returns a [4 x double] vector consisting of four doubles corresponding to
+/// the four comparison results: zero if the comparison is false, and all 1's
+/// if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1734,17 +1785,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 256-bit vector of [4 x double] containing the comparison results.
#define _mm256_cmp_pd(a, b, c) __extension__ ({ \
(__m256d)__builtin_ia32_cmppd256((__v4df)(__m256d)(a), \
@@ -1752,9 +1824,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding values of two 256-bit vectors of
/// [8 x float], using the operation specified by the immediate integer
-/// operand. Returns a [8 x float] vector consisting of eight floats
-/// corresponding to the eight comparison results: zero if the comparison is
-/// false, and all 1's if the comparison is true.
+/// operand.
+///
+/// Returns a [8 x float] vector consisting of eight floats corresponding to
+/// the eight comparison results: zero if the comparison is false, and all
+/// 1's if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1771,17 +1845,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 256-bit vector of [8 x float] containing the comparison results.
#define _mm256_cmp_ps(a, b, c) __extension__ ({ \
(__m256)__builtin_ia32_cmpps256((__v8sf)(__m256)(a), \
@@ -1789,8 +1884,10 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding scalar double-precision values of
/// two 128-bit vectors of [2 x double], using the operation specified by the
-/// immediate integer operand. If the result is true, all 64 bits of the
-/// destination vector are set; otherwise they are cleared.
+/// immediate integer operand.
+///
+/// If the result is true, all 64 bits of the destination vector are set;
+/// otherwise they are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1807,17 +1904,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [2 x double] containing the comparison results.
#define _mm_cmp_sd(a, b, c) __extension__ ({ \
(__m128d)__builtin_ia32_cmpsd((__v2df)(__m128d)(a), \
@@ -1825,8 +1943,10 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding scalar values of two 128-bit
/// vectors of [4 x float], using the operation specified by the immediate
-/// integer operand. If the result is true, all 32 bits of the destination
-/// vector are set; otherwise they are cleared.
+/// integer operand.
+///
+/// If the result is true, all 32 bits of the destination vector are set;
+/// otherwise they are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1843,17 +1963,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [4 x float] containing the comparison results.
#define _mm_cmp_ss(a, b, c) __extension__ ({ \
(__m128)__builtin_ia32_cmpss((__v4sf)(__m128)(a), \
@@ -2410,7 +2551,9 @@ _mm256_unpacklo_ps(__m256 __a, __m256 __b)
/// \brief Given two 128-bit floating-point vectors of [2 x double], perform an
/// element-by-element comparison of the double-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2437,7 +2580,9 @@ _mm_testz_pd(__m128d __a, __m128d __b)
/// \brief Given two 128-bit floating-point vectors of [2 x double], perform an
/// element-by-element comparison of the double-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2464,7 +2609,9 @@ _mm_testc_pd(__m128d __a, __m128d __b)
/// \brief Given two 128-bit floating-point vectors of [2 x double], perform an
/// element-by-element comparison of the double-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2492,7 +2639,9 @@ _mm_testnzc_pd(__m128d __a, __m128d __b)
/// \brief Given two 128-bit floating-point vectors of [4 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2519,7 +2668,9 @@ _mm_testz_ps(__m128 __a, __m128 __b)
/// \brief Given two 128-bit floating-point vectors of [4 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2546,7 +2697,9 @@ _mm_testc_ps(__m128 __a, __m128 __b)
/// \brief Given two 128-bit floating-point vectors of [4 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2574,7 +2727,9 @@ _mm_testnzc_ps(__m128 __a, __m128 __b)
/// \brief Given two 256-bit floating-point vectors of [4 x double], perform an
/// element-by-element comparison of the double-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2601,7 +2756,9 @@ _mm256_testz_pd(__m256d __a, __m256d __b)
/// \brief Given two 256-bit floating-point vectors of [4 x double], perform an
/// element-by-element comparison of the double-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2628,7 +2785,9 @@ _mm256_testc_pd(__m256d __a, __m256d __b)
/// \brief Given two 256-bit floating-point vectors of [4 x double], perform an
/// element-by-element comparison of the double-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2656,7 +2815,9 @@ _mm256_testnzc_pd(__m256d __a, __m256d __b)
/// \brief Given two 256-bit floating-point vectors of [8 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2683,7 +2844,9 @@ _mm256_testz_ps(__m256 __a, __m256 __b)
/// \brief Given two 256-bit floating-point vectors of [8 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2710,7 +2873,9 @@ _mm256_testc_ps(__m256 __a, __m256 __b)
/// \brief Given two 256-bit floating-point vectors of [8 x float], perform an
/// element-by-element comparison of the single-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2736,7 +2901,9 @@ _mm256_testnzc_ps(__m256 __a, __m256 __b)
}
/// \brief Given two 256-bit integer vectors, perform a bit-by-bit comparison
-/// of the two source vectors and update the EFLAGS register as follows: \n
+/// of the two source vectors.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of bits where both bits are 1, the ZF flag
/// is set to 0. Otherwise the ZF flag is set to 1. \n
/// If there is at least one pair of bits where the bit from the first source
@@ -2760,7 +2927,9 @@ _mm256_testz_si256(__m256i __a, __m256i __b)
}
/// \brief Given two 256-bit integer vectors, perform a bit-by-bit comparison
-/// of the two source vectors and update the EFLAGS register as follows: \n
+/// of the two source vectors.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of bits where both bits are 1, the ZF flag
/// is set to 0. Otherwise the ZF flag is set to 1. \n
/// If there is at least one pair of bits where the bit from the first source
@@ -2784,7 +2953,9 @@ _mm256_testc_si256(__m256i __a, __m256i __b)
}
/// \brief Given two 256-bit integer vectors, perform a bit-by-bit comparison
-/// of the two source vectors and update the EFLAGS register as follows: \n
+/// of the two source vectors.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of bits where both bits are 1, the ZF flag
/// is set to 0. Otherwise the ZF flag is set to 1. \n
/// If there is at least one pair of bits where the bit from the first source
@@ -3419,7 +3590,8 @@ _mm_maskstore_ps(float *__p, __m128i __m, __m128 __a)
static __inline void __DEFAULT_FN_ATTRS
_mm256_stream_si256(__m256i *__a, __m256i __b)
{
- __builtin_nontemporal_store((__v4di)__b, (__v4di*)__a);
+ typedef __v4di __v4di_aligned __attribute__((aligned(32)));
+ __builtin_nontemporal_store((__v4di_aligned)__b, (__v4di_aligned*)__a);
}
/// \brief Moves double-precision values from a 256-bit vector of [4 x double]
@@ -3432,13 +3604,14 @@ _mm256_stream_si256(__m256i *__a, __m256i __b)
///
/// \param __a
/// A pointer to a 32-byte aligned memory location that will receive the
-/// integer values.
+/// double-precision floating-point values.
/// \param __b
/// A 256-bit vector of [4 x double] containing the values to be moved.
static __inline void __DEFAULT_FN_ATTRS
_mm256_stream_pd(double *__a, __m256d __b)
{
- __builtin_nontemporal_store((__v4df)__b, (__v4df*)__a);
+ typedef __v4df __v4df_aligned __attribute__((aligned(32)));
+ __builtin_nontemporal_store((__v4df_aligned)__b, (__v4df_aligned*)__a);
}
/// \brief Moves single-precision floating point values from a 256-bit vector
@@ -3458,7 +3631,8 @@ _mm256_stream_pd(double *__a, __m256d __b)
static __inline void __DEFAULT_FN_ATTRS
_mm256_stream_ps(float *__p, __m256 __a)
{
- __builtin_nontemporal_store((__v8sf)__a, (__v8sf*)__p);
+ typedef __v8sf __v8sf_aligned __attribute__((aligned(32)));
+ __builtin_nontemporal_store((__v8sf_aligned)__a, (__v8sf_aligned*)__p);
}
/* Create vectors */
@@ -4340,9 +4514,10 @@ _mm256_castsi256_si128(__m256i __a)
}
/// \brief Constructs a 256-bit floating-point vector of [4 x double] from a
-/// 128-bit floating-point vector of [2 x double]. The lower 128 bits
-/// contain the value of the source vector. The contents of the upper 128
-/// bits are undefined.
+/// 128-bit floating-point vector of [2 x double].
+///
+/// The lower 128 bits contain the value of the source vector. The contents
+/// of the upper 128 bits are undefined.
///
/// \headerfile <x86intrin.h>
///
@@ -4360,9 +4535,10 @@ _mm256_castpd128_pd256(__m128d __a)
}
/// \brief Constructs a 256-bit floating-point vector of [8 x float] from a
-/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain
-/// the value of the source vector. The contents of the upper 128 bits are
-/// undefined.
+/// 128-bit floating-point vector of [4 x float].
+///
+/// The lower 128 bits contain the value of the source vector. The contents
+/// of the upper 128 bits are undefined.
///
/// \headerfile <x86intrin.h>
///
@@ -4380,6 +4556,7 @@ _mm256_castps128_ps256(__m128 __a)
}
/// \brief Constructs a 256-bit integer vector from a 128-bit integer vector.
+///
/// The lower 128 bits contain the value of the source vector. The contents
/// of the upper 128 bits are undefined.
///
@@ -4397,6 +4574,61 @@ _mm256_castsi128_si256(__m128i __a)
return __builtin_shufflevector((__v2di)__a, (__v2di)__a, 0, 1, -1, -1);
}
+/// \brief Constructs a 256-bit floating-point vector of [4 x double] from a
+/// 128-bit floating-point vector of [2 x double]. The lower 128 bits
+/// contain the value of the source vector. The upper 128 bits are set
+/// to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [2 x double].
+/// \returns A 256-bit floating-point vector of [4 x double]. The lower 128 bits
+/// contain the value of the parameter. The upper 128 bits are set to zero.
+static __inline __m256d __DEFAULT_FN_ATTRS
+_mm256_zextpd128_pd256(__m128d __a)
+{
+ return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3);
+}
+
+/// \brief Constructs a 256-bit floating-point vector of [8 x float] from a
+/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain
+/// the value of the source vector. The upper 128 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [4 x float].
+/// \returns A 256-bit floating-point vector of [8 x float]. The lower 128 bits
+/// contain the value of the parameter. The upper 128 bits are set to zero.
+static __inline __m256 __DEFAULT_FN_ATTRS
+_mm256_zextps128_ps256(__m128 __a)
+{
+ return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7);
+}
+
+/// \brief Constructs a 256-bit integer vector from a 128-bit integer vector.
+/// The lower 128 bits contain the value of the source vector. The upper
+/// 128 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit integer vector.
+/// \returns A 256-bit integer vector. The lower 128 bits contain the value of
+/// the parameter. The upper 128 bits are set to zero.
+static __inline __m256i __DEFAULT_FN_ATTRS
+_mm256_zextsi128_si256(__m128i __a)
+{
+ return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3);
+}
+
/*
Vector insert.
We use macros rather than inlines because we only want to accept
@@ -4405,8 +4637,10 @@ _mm256_castsi128_si256(__m128i __a)
/// \brief Constructs a new 256-bit vector of [8 x float] by first duplicating
/// a 256-bit vector of [8 x float] given in the first parameter, and then
/// replacing either the upper or the lower 128 bits with the contents of a
-/// 128-bit vector of [4 x float] in the second parameter. The immediate
-/// integer parameter determines between the upper or the lower 128 bits.
+/// 128-bit vector of [4 x float] in the second parameter.
+///
+/// The immediate integer parameter determines between the upper or the lower
+/// 128 bits.
///
/// \headerfile <x86intrin.h>
///
@@ -4450,8 +4684,10 @@ _mm256_castsi128_si256(__m128i __a)
/// \brief Constructs a new 256-bit vector of [4 x double] by first duplicating
/// a 256-bit vector of [4 x double] given in the first parameter, and then
/// replacing either the upper or the lower 128 bits with the contents of a
-/// 128-bit vector of [2 x double] in the second parameter. The immediate
-/// integer parameter determines between the upper or the lower 128 bits.
+/// 128-bit vector of [2 x double] in the second parameter.
+///
+/// The immediate integer parameter determines between the upper or the lower
+/// 128 bits.
///
/// \headerfile <x86intrin.h>
///
@@ -4491,8 +4727,10 @@ _mm256_castsi128_si256(__m128i __a)
/// \brief Constructs a new 256-bit integer vector by first duplicating a
/// 256-bit integer vector given in the first parameter, and then replacing
/// either the upper or the lower 128 bits with the contents of a 128-bit
-/// integer vector in the second parameter. The immediate integer parameter
-/// determines between the upper or the lower 128 bits.
+/// integer vector in the second parameter.
+///
+/// The immediate integer parameter determines between the upper or the lower
+/// 128 bits.
///
/// \headerfile <x86intrin.h>
///
diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h
index 488eb2dbd3..e812a1632b 100644
--- a/lib/Headers/bmiintrin.h
+++ b/lib/Headers/bmiintrin.h
@@ -28,107 +28,17 @@
#ifndef __BMIINTRIN_H
#define __BMIINTRIN_H
-/// \brief Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned short _tzcnt_u16(unsigned short a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param a
-/// An unsigned 16-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 16-bit integer containing the number of trailing zero
-/// bits in the operand.
#define _tzcnt_u16(a) (__tzcnt_u16((a)))
-/// \brief Performs a bitwise AND of the second operand with the one's
-/// complement of the first operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _andn_u32(unsigned int a, unsigned int b);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> ANDN </c> instruction.
-///
-/// \param a
-/// An unsigned integer containing one of the operands.
-/// \param b
-/// An unsigned integer containing one of the operands.
-/// \returns An unsigned integer containing the bitwise AND of the second
-/// operand with the one's complement of the first operand.
#define _andn_u32(a, b) (__andn_u32((a), (b)))
/* _bextr_u32 != __bextr_u32 */
-/// \brief Clears all bits in the source except for the least significant bit
-/// containing a value of 1 and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _blsi_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSI </c> instruction.
-///
-/// \param a
-/// An unsigned integer whose bits are to be cleared.
-/// \returns An unsigned integer containing the result of clearing the bits from
-/// the source operand.
#define _blsi_u32(a) (__blsi_u32((a)))
-/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _blsmsk_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSMSK </c> instruction.
-///
-/// \param a
-/// An unsigned integer used to create the mask.
-/// \returns An unsigned integer containing the newly created mask.
#define _blsmsk_u32(a) (__blsmsk_u32((a)))
-/// \brief Clears the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _blsr_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSR </c> instruction.
-///
-/// \param a
-/// An unsigned integer containing the operand to be cleared.
-/// \returns An unsigned integer containing the result of clearing the source
-/// operand.
#define _blsr_u32(a) (__blsr_u32((a)))
-/// \brief Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _tzcnt_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param a
-/// An unsigned 32-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 32-bit integer containing the number of trailing zero
-/// bits in the operand.
#define _tzcnt_u32(a) (__tzcnt_u32((a)))
/* Define the default attributes for the functions in this file. */
@@ -238,7 +148,7 @@ __blsi_u32(unsigned int __X)
}
/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
+/// including the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
@@ -254,7 +164,7 @@ __blsmsk_u32(unsigned int __X)
return __X ^ (__X - 1);
}
-/// \brief Clears the least siginificant bit that is set to 1 in the source
+/// \brief Clears the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
@@ -305,91 +215,15 @@ _mm_tzcnt_32(unsigned int __X)
#ifdef __x86_64__
-/// \brief Performs a bitwise AND of the second operand with the one's
-/// complement of the first operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _andn_u64 (unsigned long long a, unsigned long long b);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> ANDN </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer containing one of the operands.
-/// \param b
-/// An unsigned 64-bit integer containing one of the operands.
-/// \returns An unsigned 64-bit integer containing the bitwise AND of the second
-/// operand with the one's complement of the first operand.
#define _andn_u64(a, b) (__andn_u64((a), (b)))
/* _bextr_u64 != __bextr_u64 */
-/// \brief Clears all bits in the source except for the least significant bit
-/// containing a value of 1 and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _blsi_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSI </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer whose bits are to be cleared.
-/// \returns An unsigned 64-bit integer containing the result of clearing the
-/// bits from the source operand.
#define _blsi_u64(a) (__blsi_u64((a)))
-/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _blsmsk_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSMSK </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer used to create the mask.
-/// \returns A unsigned 64-bit integer containing the newly created mask.
#define _blsmsk_u64(a) (__blsmsk_u64((a)))
-/// \brief Clears the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _blsr_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSR </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer containing the operand to be cleared.
-/// \returns An unsigned 64-bit integer containing the result of clearing the
-/// source operand.
#define _blsr_u64(a) (__blsr_u64((a)))
-/// \brief Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _tzcnt_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 64-bit integer containing the number of trailing zero
-/// bits in the operand.
#define _tzcnt_u64(a) (__tzcnt_u64((a)))
/// \brief Performs a bitwise AND of the second operand with the one's
@@ -475,7 +309,7 @@ __blsi_u64(unsigned long long __X)
}
/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
+/// including the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
@@ -484,14 +318,14 @@ __blsi_u64(unsigned long long __X)
///
/// \param __X
/// An unsigned 64-bit integer used to create the mask.
-/// \returns A unsigned 64-bit integer containing the newly created mask.
+/// \returns An unsigned 64-bit integer containing the newly created mask.
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
__blsmsk_u64(unsigned long long __X)
{
return __X ^ (__X - 1);
}
-/// \brief Clears the least siginificant bit that is set to 1 in the source
+/// \brief Clears the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
diff --git a/lib/Headers/clflushoptintrin.h b/lib/Headers/clflushoptintrin.h
index 60e0ead762..f1f1330234 100644
--- a/lib/Headers/clflushoptintrin.h
+++ b/lib/Headers/clflushoptintrin.h
@@ -32,7 +32,7 @@
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("clflushopt")))
static __inline__ void __DEFAULT_FN_ATTRS
-_mm_clflushopt(char * __m) {
+_mm_clflushopt(void const * __m) {
__builtin_ia32_clflushopt(__m);
}
diff --git a/lib/Headers/clwbintrin.h b/lib/Headers/clwbintrin.h
new file mode 100644
index 0000000000..2594a6c387
--- /dev/null
+++ b/lib/Headers/clwbintrin.h
@@ -0,0 +1,52 @@
+/*===---- clwbintrin.h - CLWB intrinsic ------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __IMMINTRIN_H
+#error "Never use <clwbintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __CLWBINTRIN_H
+#define __CLWBINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("clwb")))
+
+/// \brief Writes back to memory the cache line (if modified) that contains the
+/// linear address specified in \a __p from any level of the cache hierarchy in
+/// the cache coherence domain
+///
+/// \headerfile <immintrin.h>
+///
+/// This intrinsic corresponds to the <c> CLWB </c> instruction.
+///
+/// \param __p
+/// A pointer to the memory location used to identify the cache line to be
+/// written back.
+static __inline__ void __DEFAULT_FN_ATTRS
+_mm_clwb(void const *__p) {
+ __builtin_ia32_clwb(__p);
+}
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 400dcfacd5..2dd0add236 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -79,7 +79,7 @@
#define signature_VORTEX_edx 0x36387865
#define signature_VORTEX_ecx 0x436f5320
-/* Features in %ecx for level 1 */
+/* Features in %ecx for leaf 1 */
#define bit_SSE3 0x00000001
#define bit_PCLMULQDQ 0x00000002
#define bit_PCLMUL bit_PCLMULQDQ /* for gcc compat */
@@ -114,7 +114,7 @@
#define bit_F16C 0x20000000
#define bit_RDRND 0x40000000
-/* Features in %edx for level 1 */
+/* Features in %edx for leaf 1 */
#define bit_FPU 0x00000001
#define bit_VME 0x00000002
#define bit_DE 0x00000004
@@ -147,44 +147,95 @@
#define bit_TM 0x20000000
#define bit_PBE 0x80000000
-/* Features in %ebx for level 7 sub-leaf 0 */
+/* Features in %ebx for leaf 7 sub-leaf 0 */
#define bit_FSGSBASE 0x00000001
+#define bit_SGX 0x00000004
+#define bit_BMI 0x00000008
+#define bit_HLE 0x00000010
+#define bit_AVX2 0x00000020
#define bit_SMEP 0x00000080
+#define bit_BMI2 0x00000100
#define bit_ENH_MOVSB 0x00000200
+#define bit_RTM 0x00000800
+#define bit_MPX 0x00004000
+#define bit_AVX512F 0x00010000
+#define bit_AVX512DQ 0x00020000
+#define bit_RDSEED 0x00040000
+#define bit_ADX 0x00080000
+#define bit_AVX512IFMA 0x00200000
+#define bit_CLFLUSHOPT 0x00800000
+#define bit_CLWB 0x01000000
+#define bit_AVX512PF 0x04000000
+#define bit_AVX51SER 0x08000000
+#define bit_AVX512CD 0x10000000
+#define bit_SHA 0x20000000
+#define bit_AVX512BW 0x40000000
+#define bit_AVX512VL 0x80000000
+
+/* Features in %ecx for leaf 7 sub-leaf 0 */
+#define bit_PREFTCHWT1 0x00000001
+#define bit_AVX512VBMI 0x00000002
+#define bit_PKU 0x00000004
+#define bit_OSPKE 0x00000010
+#define bit_AVX512VPOPCNTDQ 0x00004000
+#define bit_RDPID 0x00400000
+
+/* Features in %edx for leaf 7 sub-leaf 0 */
+#define bit_AVX5124VNNIW 0x00000004
+#define bit_AVX5124FMAPS 0x00000008
+
+/* Features in %eax for leaf 13 sub-leaf 1 */
+#define bit_XSAVEOPT 0x00000001
+#define bit_XSAVEC 0x00000002
+#define bit_XSAVES 0x00000008
+
+/* Features in %ecx for leaf 0x80000001 */
+#define bit_LAHF_LM 0x00000001
+#define bit_ABM 0x00000020
+#define bit_SSE4a 0x00000040
+#define bit_PRFCHW 0x00000100
+#define bit_XOP 0x00000800
+#define bit_LWP 0x00008000
+#define bit_FMA4 0x00010000
+#define bit_TBM 0x00200000
+#define bit_MWAITX 0x20000000
+
+/* Features in %edx for leaf 0x80000001 */
+#define bit_MMXEXT 0x00400000
+#define bit_LM 0x20000000
+#define bit_3DNOWP 0x40000000
+#define bit_3DNOW 0x80000000
+
+/* Features in %ebx for leaf 0x80000001 */
+#define bit_CLZERO 0x00000001
+
#if __i386__
-#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
+#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \
__asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level))
+ : "0"(__leaf))
-#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
+#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \
__asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level), "2"(__count))
+ : "0"(__leaf), "2"(__count))
#else
/* x86-64 uses %rbx as the base register, so preserve it. */
-#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
+#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \
__asm(" xchgq %%rbx,%q1\n" \
" cpuid\n" \
" xchgq %%rbx,%q1" \
: "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level))
+ : "0"(__leaf))
-#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
+#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \
__asm(" xchgq %%rbx,%q1\n" \
" cpuid\n" \
" xchgq %%rbx,%q1" \
: "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level), "2"(__count))
+ : "0"(__leaf), "2"(__count))
#endif
-static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax,
- unsigned int *__ebx, unsigned int *__ecx,
- unsigned int *__edx) {
- __cpuid(__level, *__eax, *__ebx, *__ecx, *__edx);
- return 1;
-}
-
-static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig)
+static __inline int __get_cpuid_max (unsigned int __leaf, unsigned int *__sig)
{
unsigned int __eax, __ebx, __ecx, __edx;
#if __i386__
@@ -208,8 +259,35 @@ static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig)
return 0;
#endif
- __cpuid(__level, __eax, __ebx, __ecx, __edx);
+ __cpuid(__leaf, __eax, __ebx, __ecx, __edx);
if (__sig)
*__sig = __ebx;
return __eax;
}
+
+static __inline int __get_cpuid (unsigned int __leaf, unsigned int *__eax,
+ unsigned int *__ebx, unsigned int *__ecx,
+ unsigned int *__edx)
+{
+ unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0);
+
+ if (__max_leaf == 0 || __max_leaf < __leaf)
+ return 0;
+
+ __cpuid(__leaf, *__eax, *__ebx, *__ecx, *__edx);
+ return 1;
+}
+
+static __inline int __get_cpuid_count (unsigned int __leaf,
+ unsigned int __subleaf,
+ unsigned int *__eax, unsigned int *__ebx,
+ unsigned int *__ecx, unsigned int *__edx)
+{
+ unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0);
+
+ if (__max_leaf == 0 || __max_leaf < __leaf)
+ return 0;
+
+ __cpuid_count(__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx);
+ return 1;
+}
diff --git a/lib/Headers/cuda_wrappers/new b/lib/Headers/cuda_wrappers/new
index b77131af0e..71b7a52363 100644
--- a/lib/Headers/cuda_wrappers/new
+++ b/lib/Headers/cuda_wrappers/new
@@ -26,7 +26,6 @@
#include_next <new>
-// Device overrides for placement new and delete.
#pragma push_macro("CUDA_NOEXCEPT")
#if __cplusplus >= 201103L
#define CUDA_NOEXCEPT noexcept
@@ -34,6 +33,55 @@
#define CUDA_NOEXCEPT
#endif
+// Device overrides for non-placement new and delete.
+__device__ inline void *operator new(__SIZE_TYPE__ size) {
+ if (size == 0) {
+ size = 1;
+ }
+ return ::malloc(size);
+}
+__device__ inline void *operator new(__SIZE_TYPE__ size,
+ const std::nothrow_t &) CUDA_NOEXCEPT {
+ return ::operator new(size);
+}
+
+__device__ inline void *operator new[](__SIZE_TYPE__ size) {
+ return ::operator new(size);
+}
+__device__ inline void *operator new[](__SIZE_TYPE__ size,
+ const std::nothrow_t &) {
+ return ::operator new(size);
+}
+
+__device__ inline void operator delete(void* ptr) CUDA_NOEXCEPT {
+ if (ptr) {
+ ::free(ptr);
+ }
+}
+__device__ inline void operator delete(void *ptr,
+ const std::nothrow_t &) CUDA_NOEXCEPT {
+ ::operator delete(ptr);
+}
+
+__device__ inline void operator delete[](void* ptr) CUDA_NOEXCEPT {
+ ::operator delete(ptr);
+}
+__device__ inline void operator delete[](void *ptr,
+ const std::nothrow_t &) CUDA_NOEXCEPT {
+ ::operator delete(ptr);
+}
+
+// Sized delete, C++14 only.
+#if __cplusplus >= 201402L
+__device__ void operator delete(void *ptr, __SIZE_TYPE__ size) CUDA_NOEXCEPT {
+ ::operator delete(ptr);
+}
+__device__ void operator delete[](void *ptr, __SIZE_TYPE__ size) CUDA_NOEXCEPT {
+ ::operator delete(ptr);
+}
+#endif
+
+// Device overrides for placement new and delete.
__device__ inline void *operator new(__SIZE_TYPE__, void *__ptr) CUDA_NOEXCEPT {
return __ptr;
}
@@ -42,6 +90,7 @@ __device__ inline void *operator new[](__SIZE_TYPE__, void *__ptr) CUDA_NOEXCEPT
}
__device__ inline void operator delete(void *, void *) CUDA_NOEXCEPT {}
__device__ inline void operator delete[](void *, void *) CUDA_NOEXCEPT {}
+
#pragma pop_macro("CUDA_NOEXCEPT")
#endif // include guard
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 91da77e0c9..3372508a7f 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -302,7 +302,7 @@ _mm_min_pd(__m128d __a, __m128d __b)
return __builtin_ia32_minpd((__v2df)__a, (__v2df)__b);
}
-/// \brief Compares lower 64-bits double-precision values of both operands, and
+/// \brief Compares lower 64-bit double-precision values of both operands, and
/// returns the greater of the pair of values in the lower 64-bits of the
/// result. The upper 64 bits of the result are copied from the upper double-
/// precision value of the first operand.
@@ -462,8 +462,9 @@ _mm_cmplt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are less than or equal to those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are less than or equal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -482,8 +483,9 @@ _mm_cmple_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are greater than those in the second operand. Each comparison
-/// yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -502,8 +504,9 @@ _mm_cmpgt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are greater than or equal to those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are greater than or equal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -522,9 +525,10 @@ _mm_cmpge_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are ordered with respect to those in the second operand. A pair
-/// of double-precision values are "ordered" with respect to each other if
-/// neither value is a NaN. Each comparison yields 0h for false,
+/// operand are ordered with respect to those in the second operand.
+///
+/// A pair of double-precision values are "ordered" with respect to each
+/// other if neither value is a NaN. Each comparison yields 0h for false,
/// FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
@@ -544,9 +548,10 @@ _mm_cmpord_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are unordered with respect to those in the second operand. A pair
-/// of double-precision values are "unordered" with respect to each other if
-/// one or both values are NaN. Each comparison yields 0h for false,
+/// operand are unordered with respect to those in the second operand.
+///
+/// A pair of double-precision values are "unordered" with respect to each
+/// other if one or both values are NaN. Each comparison yields 0h for false,
/// FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
@@ -567,8 +572,9 @@ _mm_cmpunord_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are unequal to those in the second operand. Each comparison
-/// yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are unequal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -587,8 +593,9 @@ _mm_cmpneq_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are not less than those in the second operand. Each comparison
-/// yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are not less than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -607,8 +614,9 @@ _mm_cmpnlt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are not less than or equal to those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are not less than or equal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -627,8 +635,9 @@ _mm_cmpnle_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are not greater than those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are not greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -648,6 +657,7 @@ _mm_cmpngt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
/// operand are not greater than or equal to those in the second operand.
+///
/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
@@ -666,8 +676,9 @@ _mm_cmpnge_pd(__m128d __a, __m128d __b)
}
/// \brief Compares the lower double-precision floating-point values in each of
-/// the two 128-bit floating-point vectors of [2 x double] for equality. The
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// the two 128-bit floating-point vectors of [2 x double] for equality.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -690,8 +701,9 @@ _mm_cmpeq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than the corresponding value in
-/// the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -714,8 +726,9 @@ _mm_cmplt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h for
-/// false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -738,8 +751,9 @@ _mm_cmple_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than the corresponding value
-/// in the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -763,8 +777,9 @@ _mm_cmpgt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h for
-/// false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -788,9 +803,11 @@ _mm_cmpge_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is "ordered" with respect to the
-/// corresponding value in the second parameter. The comparison yields 0h for
-/// false, FFFFFFFFFFFFFFFFh for true. A pair of double-precision values are
-/// "ordered" with respect to each other if neither value is a NaN.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true. A pair of
+/// double-precision values are "ordered" with respect to each other if
+/// neither value is a NaN.
///
/// \headerfile <x86intrin.h>
///
@@ -813,9 +830,11 @@ _mm_cmpord_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is "unordered" with respect to the
-/// corresponding value in the second parameter. The comparison yields 0h
-/// for false, FFFFFFFFFFFFFFFFh for true. A pair of double-precision values
-/// are "unordered" with respect to each other if one or both values are NaN.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true. A pair of
+/// double-precision values are "unordered" with respect to each other if one
+/// or both values are NaN.
///
/// \headerfile <x86intrin.h>
///
@@ -839,8 +858,9 @@ _mm_cmpunord_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is unequal to the corresponding value in
-/// the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -863,8 +883,9 @@ _mm_cmpneq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not less than the corresponding
-/// value in the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -887,8 +908,9 @@ _mm_cmpnlt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h
-/// for false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -911,8 +933,9 @@ _mm_cmpnle_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not greater than the corresponding
-/// value in the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -936,8 +959,9 @@ _mm_cmpngt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h
-/// for false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -982,7 +1006,9 @@ _mm_comieq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1004,8 +1030,9 @@ _mm_comilt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1027,7 +1054,9 @@ _mm_comile_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than the corresponding value
-/// in the second parameter. The comparison yields 0 for false, 1 for true.
+/// in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1049,8 +1078,9 @@ _mm_comigt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1072,7 +1102,9 @@ _mm_comige_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is unequal to the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1093,8 +1125,9 @@ _mm_comineq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] for equality. The
-/// comparison yields 0 for false, 1 for true. If either of the two lower
-/// double-precision values is NaN, 1 is returned.
+/// comparison yields 0 for false, 1 for true.
+///
+/// If either of the two lower double-precision values is NaN, 1 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1117,8 +1150,10 @@ _mm_ucomieq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true. If
-/// either of the two lower double-precision values is NaN, 1 is returned.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 1 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1141,9 +1176,10 @@ _mm_ucomilt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true. If either of the two lower double-precision values is
-/// NaN, 1 is returned.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 1 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1166,8 +1202,10 @@ _mm_ucomile_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than the corresponding value
-/// in the second parameter. The comparison yields 0 for false, 1 for true.
-/// If either of the two lower double-precision values is NaN, 0 is returned.
+/// in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 0 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1190,9 +1228,10 @@ _mm_ucomigt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true. If either of the two lower double-precision values
-/// is NaN, 0 is returned.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two
+/// lower double-precision values is NaN, 0 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1215,8 +1254,10 @@ _mm_ucomige_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is unequal to the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true. If
-/// either of the two lower double-precision values is NaN, 0 is returned.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 0 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1278,8 +1319,9 @@ _mm_cvtps_pd(__m128 __a)
/// \brief Converts the lower two integer elements of a 128-bit vector of
/// [4 x i32] into two double-precision floating-point values, returned in a
-/// 128-bit vector of [2 x double]. The upper two elements of the input
-/// vector are unused.
+/// 128-bit vector of [2 x double].
+///
+/// The upper two elements of the input vector are unused.
///
/// \headerfile <x86intrin.h>
///
@@ -1287,7 +1329,9 @@ _mm_cvtps_pd(__m128 __a)
///
/// \param __a
/// A 128-bit integer vector of [4 x i32]. The lower two integer elements are
-/// converted to double-precision values. The upper two elements are unused.
+/// converted to double-precision values.
+///
+/// The upper two elements are unused.
/// \returns A 128-bit vector of [2 x double] containing the converted values.
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_cvtepi32_pd(__m128i __a)
@@ -1409,10 +1453,11 @@ _mm_cvtss_sd(__m128d __a, __m128 __b)
/// \brief Converts the two double-precision floating-point elements of a
/// 128-bit vector of [2 x double] into two signed 32-bit integer values,
-/// returned in the lower 64 bits of a 128-bit vector of [4 x i32]. If the
-/// result of either conversion is inexact, the result is truncated (rounded
-/// towards zero) regardless of the current MXCSR setting. The upper 64 bits
-/// of the result vector are set to zero.
+/// returned in the lower 64 bits of a 128-bit vector of [4 x i32].
+///
+/// If the result of either conversion is inexact, the result is truncated
+/// (rounded towards zero) regardless of the current MXCSR setting. The upper
+/// 64 bits of the result vector are set to zero.
///
/// \headerfile <x86intrin.h>
///
@@ -1466,9 +1511,10 @@ _mm_cvtpd_pi32(__m128d __a)
/// \brief Converts the two double-precision floating-point elements of a
/// 128-bit vector of [2 x double] into two signed 32-bit integer values,
-/// returned in a 64-bit vector of [2 x i32]. If the result of either
-/// conversion is inexact, the result is truncated (rounded towards zero)
-/// regardless of the current MXCSR setting.
+/// returned in a 64-bit vector of [2 x i32].
+///
+/// If the result of either conversion is inexact, the result is truncated
+/// (rounded towards zero) regardless of the current MXCSR setting.
///
/// \headerfile <x86intrin.h>
///
@@ -1606,7 +1652,7 @@ _mm_loadu_pd(double const *__dp)
///
/// This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction.
///
-/// \param __dp
+/// \param __a
/// A pointer to a 64-bit memory location. The address of the memory
/// location does not have to be aligned.
/// \returns A 128-bit vector of [2 x i64] containing the loaded value.
@@ -1628,7 +1674,7 @@ _mm_loadu_si64(void const *__a)
/// This intrinsic corresponds to the <c> VMOVSD / MOVSD </c> instruction.
///
/// \param __dp
-/// An pointer to a memory location containing a double-precision value.
+/// A pointer to a memory location containing a double-precision value.
/// The address of the memory location does not have to be aligned.
/// \returns A 128-bit vector of [2 x double] containing the loaded value.
static __inline__ __m128d __DEFAULT_FN_ATTRS
@@ -1750,6 +1796,24 @@ _mm_set1_pd(double __w)
return (__m128d){ __w, __w };
}
+/// \brief Constructs a 128-bit floating-point vector of [2 x double], with each
+/// of the two double-precision floating-point vector elements set to the
+/// specified double-precision floating-point value.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VMOVDDUP / MOVLHPS </c> instruction.
+///
+/// \param __w
+/// A double-precision floating-point value used to initialize each vector
+/// element of the result.
+/// \returns An initialized 128-bit floating-point vector of [2 x double].
+static __inline__ __m128d __DEFAULT_FN_ATTRS
+_mm_set_pd1(double __w)
+{
+ return _mm_set1_pd(__w);
+}
+
/// \brief Constructs a 128-bit floating-point vector of [2 x double]
/// initialized with the specified double-precision floating-point values.
///
@@ -1809,7 +1873,7 @@ _mm_setzero_pd(void)
/// \brief Constructs a 128-bit floating-point vector of [2 x double]. The lower
/// 64 bits are set to the lower 64 bits of the second parameter. The upper
/// 64 bits are set to the upper 64 bits of the first parameter.
-//
+///
/// \headerfile <x86intrin.h>
///
/// This intrinsic corresponds to the <c> VBLENDPD / BLENDPD </c> instruction.
@@ -1847,12 +1911,38 @@ _mm_store_sd(double *__dp, __m128d __a)
((struct __mm_store_sd_struct*)__dp)->__u = __a[0];
}
+/// \brief Moves packed double-precision values from a 128-bit vector of
+/// [2 x double] to a memory location.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c>VMOVAPD / MOVAPS</c> instruction.
+///
+/// \param __dp
+/// A pointer to an aligned memory location that can store two
+/// double-precision values.
+/// \param __a
+/// A packed 128-bit vector of [2 x double] containing the values to be
+/// moved.
static __inline__ void __DEFAULT_FN_ATTRS
_mm_store_pd(double *__dp, __m128d __a)
{
*(__m128d*)__dp = __a;
}
+/// \brief Moves the lower 64 bits of a 128-bit vector of [2 x double] twice to
+/// the upper and lower 64 bits of a memory location.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c>VMOVDDUP + VMOVAPD / MOVLHPS + MOVAPS </c> instruction.
+///
+/// \param __dp
+/// A pointer to a memory location that can store two double-precision
+/// values.
+/// \param __a
+/// A 128-bit vector of [2 x double] whose lower 64 bits are copied to each
+/// of the values in \a dp.
static __inline__ void __DEFAULT_FN_ATTRS
_mm_store1_pd(double *__dp, __m128d __a)
{
@@ -1962,8 +2052,9 @@ _mm_storel_pd(double *__dp, __m128d __a)
/// \brief Adds the corresponding elements of two 128-bit vectors of [16 x i8],
/// saving the lower 8 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [16 x i8]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [16 x i8].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -1983,8 +2074,9 @@ _mm_add_epi8(__m128i __a, __m128i __b)
/// \brief Adds the corresponding elements of two 128-bit vectors of [8 x i16],
/// saving the lower 16 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [8 x i16]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [8 x i16].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -2004,8 +2096,9 @@ _mm_add_epi16(__m128i __a, __m128i __b)
/// \brief Adds the corresponding elements of two 128-bit vectors of [4 x i32],
/// saving the lower 32 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [4 x i32]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [4 x i32].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -2043,8 +2136,9 @@ _mm_add_si64(__m64 __a, __m64 __b)
/// \brief Adds the corresponding elements of two 128-bit vectors of [2 x i64],
/// saving the lower 64 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [2 x i64]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [2 x i64].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -2164,7 +2258,11 @@ _mm_adds_epu16(__m128i __a, __m128i __b)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_avg_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pavgb128((__v16qi)__a, (__v16qi)__b);
+ typedef unsigned short __v16hu __attribute__ ((__vector_size__ (32)));
+ return (__m128i)__builtin_convertvector(
+ ((__builtin_convertvector((__v16qu)__a, __v16hu) +
+ __builtin_convertvector((__v16qu)__b, __v16hu)) + 1)
+ >> 1, __v16qu);
}
/// \brief Computes the rounded avarages of corresponding elements of two
@@ -2184,16 +2282,22 @@ _mm_avg_epu8(__m128i __a, __m128i __b)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_avg_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pavgw128((__v8hi)__a, (__v8hi)__b);
+ typedef unsigned int __v8su __attribute__ ((__vector_size__ (32)));
+ return (__m128i)__builtin_convertvector(
+ ((__builtin_convertvector((__v8hu)__a, __v8su) +
+ __builtin_convertvector((__v8hu)__b, __v8su)) + 1)
+ >> 1, __v8hu);
}
/// \brief Multiplies the corresponding elements of two 128-bit signed [8 x i16]
/// vectors, producing eight intermediate 32-bit signed integer products, and
/// adds the consecutive pairs of 32-bit products to form a 128-bit signed
-/// [4 x i32] vector. For example, bits [15:0] of both parameters are
-/// multiplied producing a 32-bit product, bits [31:16] of both parameters
-/// are multiplied producing a 32-bit product, and the sum of those two
-/// products becomes bits [31:0] of the result.
+/// [4 x i32] vector.
+///
+/// For example, bits [15:0] of both parameters are multiplied producing a
+/// 32-bit product, bits [31:16] of both parameters are multiplied producing
+/// a 32-bit product, and the sum of those two products becomes bits [31:0]
+/// of the result.
///
/// \headerfile <x86intrin.h>
///
@@ -3128,8 +3232,9 @@ _mm_cmpgt_epi8(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 16-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are greater than those in the second operand. Each comparison yields 0h
-/// for false, FFFFh for true.
+/// are greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3148,8 +3253,9 @@ _mm_cmpgt_epi16(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 32-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are greater than those in the second operand. Each comparison yields 0h
-/// for false, FFFFFFFFh for true.
+/// are greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3168,8 +3274,9 @@ _mm_cmpgt_epi32(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 8-bit values of the 128-bit
/// integer vectors to determine if the values in the first operand are less
-/// than those in the second operand. Each comparison yields 0h for false,
-/// FFh for true.
+/// than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3188,8 +3295,9 @@ _mm_cmplt_epi8(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 16-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are less than those in the second operand. Each comparison yields 0h for
-/// false, FFFFh for true.
+/// are less than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3208,8 +3316,9 @@ _mm_cmplt_epi16(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 32-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are less than those in the second operand. Each comparison yields 0h for
-/// false, FFFFFFFFh for true.
+/// are less than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3907,10 +4016,11 @@ _mm_storeu_si128(__m128i *__p, __m128i __b)
/// \brief Moves bytes selected by the mask from the first operand to the
/// specified unaligned memory location. When a mask bit is 1, the
-/// corresponding byte is written, otherwise it is not written. To minimize
-/// caching, the date is flagged as non-temporal (unlikely to be used again
-/// soon). Exception and trap behavior for elements not selected for storage
-/// to memory are implementation dependent.
+/// corresponding byte is written, otherwise it is not written.
+///
+/// To minimize caching, the date is flagged as non-temporal (unlikely to be
+/// used again soon). Exception and trap behavior for elements not selected
+/// for storage to memory are implementation dependent.
///
/// \headerfile <x86intrin.h>
///
@@ -3954,8 +4064,10 @@ _mm_storel_epi64(__m128i *__p, __m128i __a)
}
/// \brief Stores a 128-bit floating point vector of [2 x double] to a 128-bit
-/// aligned memory location. To minimize caching, the data is flagged as
-/// non-temporal (unlikely to be used again soon).
+/// aligned memory location.
+///
+/// To minimize caching, the data is flagged as non-temporal (unlikely to be
+/// used again soon).
///
/// \headerfile <x86intrin.h>
///
@@ -3972,6 +4084,7 @@ _mm_stream_pd(double *__p, __m128d __a)
}
/// \brief Stores a 128-bit integer vector to a 128-bit aligned memory location.
+///
/// To minimize caching, the data is flagged as non-temporal (unlikely to be
/// used again soon).
///
@@ -3989,8 +4102,9 @@ _mm_stream_si128(__m128i *__p, __m128i __a)
__builtin_nontemporal_store((__v2di)__a, (__v2di*)__p);
}
-/// \brief Stores a 32-bit integer value in the specified memory location. To
-/// minimize caching, the data is flagged as non-temporal (unlikely to be
+/// \brief Stores a 32-bit integer value in the specified memory location.
+///
+/// To minimize caching, the data is flagged as non-temporal (unlikely to be
/// used again soon).
///
/// \headerfile <x86intrin.h>
@@ -4008,8 +4122,9 @@ _mm_stream_si32(int *__p, int __a)
}
#ifdef __x86_64__
-/// \brief Stores a 64-bit integer value in the specified memory location. To
-/// minimize caching, the data is flagged as non-temporal (unlikely to be
+/// \brief Stores a 64-bit integer value in the specified memory location.
+///
+/// To minimize caching, the data is flagged as non-temporal (unlikely to be
/// used again soon).
///
/// \headerfile <x86intrin.h>
diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
index 180712ffc6..b796cc8431 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/float.h b/lib/Headers/float.h
index 0f453d87cb..44d4d05494 100644
--- a/lib/Headers/float.h
+++ b/lib/Headers/float.h
@@ -33,6 +33,15 @@
*/
#if (defined(__APPLE__) || (defined(__MINGW32__) || defined(_MSC_VER))) && \
__STDC_HOSTED__ && __has_include_next(<float.h>)
+
+/* Prior to Apple's 10.7 SDK, float.h SDK header used to apply an extra level
+ * of #include_next<float.h> to keep Metrowerks compilers happy. Avoid this
+ * extra indirection.
+ */
+#ifdef __APPLE__
+#define _FLOAT_H_
+#endif
+
# include_next <float.h>
/* Undefine anything that we'll be redefining below. */
@@ -134,4 +143,18 @@
# define LDBL_DECIMAL_DIG __LDBL_DECIMAL_DIG__
#endif
+#ifdef __STDC_WANT_IEC_60559_TYPES_EXT__
+# define FLT16_MANT_DIG __FLT16_MANT_DIG__
+# define FLT16_DECIMAL_DIG __FLT16_DECIMAL_DIG__
+# define FLT16_DIG __FLT16_DIG__
+# define FLT16_MIN_EXP __FLT16_MIN_EXP__
+# define FLT16_MIN_10_EXP __FLT16_MIN_10_EXP__
+# define FLT16_MAX_EXP __FLT16_MAX_EXP__
+# define FLT16_MAX_10_EXP __FLT16_MAX_10_EXP__
+# define FLT16_MAX __FLT16_MAX__
+# define FLT16_EPSILON __FLT16_EPSILON__
+# define FLT16_MIN __FLT16_MIN__
+# define FLT16_TRUE_MIN __FLT16_TRUE_MIN__
+#endif /* __STDC_WANT_IEC_60559_TYPES_EXT__ */
+
#endif /* __FLOAT_H */
diff --git a/lib/Headers/htmxlintrin.h b/lib/Headers/htmxlintrin.h
index 16dc7056c6..28f7d025bb 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/immintrin.h b/lib/Headers/immintrin.h
index 7f91d49fbc..d86e0efb82 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -58,6 +58,10 @@
#include <clflushoptintrin.h>
#endif
+#if !defined(_MSC_VER) || __has_feature(modules) || defined(__CLWB__)
+#include <clwbintrin.h>
+#endif
+
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX__)
#include <avxintrin.h>
#endif
@@ -146,6 +150,10 @@ _mm256_cvtph_ps(__m128i __a)
#include <avx512cdintrin.h>
#endif
+#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512VPOPCNTDQ__)
+#include <avx512vpopcntdqintrin.h>
+#endif
+
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512DQ__)
#include <avx512dqintrin.h>
#endif
@@ -208,6 +216,15 @@ _rdrand32_step(unsigned int *__p)
return __builtin_ia32_rdrand32_step(__p);
}
+#ifdef __x86_64__
+static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd")))
+_rdrand64_step(unsigned long long *__p)
+{
+ return __builtin_ia32_rdrand64_step(__p);
+}
+#endif
+#endif /* __RDRND__ */
+
/* __bit_scan_forward */
static __inline__ int __attribute__((__always_inline__, __nodebug__))
_bit_scan_forward(int __A) {
@@ -220,15 +237,6 @@ _bit_scan_reverse(int __A) {
return 31 - __builtin_clz(__A);
}
-#ifdef __x86_64__
-static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd")))
-_rdrand64_step(unsigned long long *__p)
-{
- return __builtin_ia32_rdrand64_step(__p);
-}
-#endif
-#endif /* __RDRND__ */
-
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__FSGSBASE__)
#ifdef __x86_64__
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__, __target__("fsgsbase")))
diff --git a/lib/Headers/intrin.h b/lib/Headers/intrin.h
index af87914a9a..b30aa215a4 100644
--- a/lib/Headers/intrin.h
+++ b/lib/Headers/intrin.h
@@ -38,6 +38,10 @@
#include <armintr.h>
#endif
+#if defined(_M_ARM64)
+#include <arm64intr.h>
+#endif
+
/* For the definition of jmp_buf. */
#if __STDC_HOSTED__
#include <setjmp.h>
@@ -85,9 +89,6 @@ void __inwordstring(unsigned short, unsigned short *, unsigned long);
void __lidt(void *);
unsigned __int64 __ll_lshift(unsigned __int64, int);
__int64 __ll_rshift(__int64, int);
-void __llwpcb(void *);
-unsigned char __lwpins32(unsigned int, unsigned int, unsigned int);
-void __lwpval32(unsigned int, unsigned int, unsigned int);
unsigned int __lzcnt(unsigned int);
unsigned short __lzcnt16(unsigned short);
static __inline__
@@ -126,7 +127,6 @@ unsigned __int64 __readmsr(unsigned long);
unsigned __int64 __readpmc(unsigned long);
unsigned long __segmentlimit(unsigned long);
void __sidt(void *);
-void *__slwpcb(void);
static __inline__
void __stosb(unsigned char *, unsigned char, size_t);
static __inline__
@@ -173,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);
@@ -228,8 +227,6 @@ void __incgsbyte(unsigned long);
void __incgsdword(unsigned long);
void __incgsqword(unsigned long);
void __incgsword(unsigned long);
-unsigned char __lwpins64(unsigned __int64, unsigned int, unsigned int);
-void __lwpval64(unsigned __int64, unsigned int, unsigned int);
unsigned __int64 __lzcnt64(unsigned __int64);
static __inline__
void __movsq(unsigned long long *, unsigned long long const *, size_t);
@@ -369,11 +366,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) {
@@ -840,7 +832,7 @@ _InterlockedCompareExchange_nf(long volatile *_Destination,
__ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
return _Comparand;
}
-static __inline__ short __DEFAULT_FN_ATTRS
+static __inline__ long __DEFAULT_FN_ATTRS
_InterlockedCompareExchange_rel(long volatile *_Destination,
long _Exchange, long _Comparand) {
__atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0,
@@ -869,50 +861,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, (unsigned long long)__offset);
-}
-static __inline__ unsigned short __DEFAULT_FN_ATTRS
-__readgsword(unsigned long __offset) {
- return *__ptr_to_addr_space(256, unsigned short,
- (unsigned long long)__offset);
-}
-static __inline__ unsigned long __DEFAULT_FN_ATTRS
-__readgsdword(unsigned long __offset) {
- return *__ptr_to_addr_space(256, unsigned long, (unsigned long long)__offset);
-}
-static __inline__ unsigned __int64 __DEFAULT_FN_ATTRS
-__readgsqword(unsigned long __offset) {
- return *__ptr_to_addr_space(256, unsigned __int64,
- (unsigned long long)__offset);
-}
-#endif
-#undef __ptr_to_addr_space
/*----------------------------------------------------------------------------*\
|* movs, stos
\*----------------------------------------------------------------------------*/
diff --git a/lib/Headers/lwpintrin.h b/lib/Headers/lwpintrin.h
new file mode 100644
index 0000000000..c95fdd9a20
--- /dev/null
+++ b/lib/Headers/lwpintrin.h
@@ -0,0 +1,150 @@
+/*===---- lwpintrin.h - LWP intrinsics -------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __X86INTRIN_H
+#error "Never use <lwpintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __LWPINTRIN_H
+#define __LWPINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("lwp")))
+
+/// \brief Parses the LWPCB at the specified address and enables
+/// profiling if valid.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> LLWPCB </c> instruction.
+///
+/// \param __addr
+/// Address to the new Lightweight Profiling Control Block (LWPCB). If the
+/// LWPCB is valid, writes the address into the LWP_CBADDR MSR and enables
+/// Lightweight Profiling.
+static __inline__ void __DEFAULT_FN_ATTRS
+__llwpcb (void *__addr)
+{
+ __builtin_ia32_llwpcb(__addr);
+}
+
+/// \brief Flushes the LWP state to memory and returns the address of the LWPCB.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> SLWPCB </c> instruction.
+///
+/// \return
+/// Address to the current Lightweight Profiling Control Block (LWPCB).
+/// If LWP is not currently enabled, returns NULL.
+static __inline__ void* __DEFAULT_FN_ATTRS
+__slwpcb ()
+{
+ return __builtin_ia32_slwpcb();
+}
+
+/// \brief Inserts programmed event record into the LWP event ring buffer
+/// and advances the ring buffer pointer.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> LWPINS </c> instruction.
+///
+/// \param DATA2
+/// A 32-bit value is zero-extended and inserted into the 64-bit Data2 field.
+/// \param DATA1
+/// A 32-bit value is inserted into the 32-bit Data1 field.
+/// \param FLAGS
+/// A 32-bit immediate value is inserted into the 32-bit Flags field.
+/// \returns If the ring buffer is full and LWP is running in Synchronized Mode,
+/// the event record overwrites the last record in the buffer, the MissedEvents
+/// counter in the LWPCB is incremented, the head pointer is not advanced, and
+/// 1 is returned. Otherwise 0 is returned.
+#define __lwpins32(DATA2, DATA1, FLAGS) \
+ (__builtin_ia32_lwpins32((unsigned int) (DATA2), (unsigned int) (DATA1), \
+ (unsigned int) (FLAGS)))
+
+/// \brief Decrements the LWP programmed value sample event counter. If the result is
+/// negative, inserts an event record into the LWP event ring buffer in memory
+/// and advances the ring buffer pointer.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> LWPVAL </c> instruction.
+///
+/// \param DATA2
+/// A 32-bit value is zero-extended and inserted into the 64-bit Data2 field.
+/// \param DATA1
+/// A 32-bit value is inserted into the 32-bit Data1 field.
+/// \param FLAGS
+/// A 32-bit immediate value is inserted into the 32-bit Flags field.
+#define __lwpval32(DATA2, DATA1, FLAGS) \
+ (__builtin_ia32_lwpval32((unsigned int) (DATA2), (unsigned int) (DATA1), \
+ (unsigned int) (FLAGS)))
+
+#ifdef __x86_64__
+
+/// \brief Inserts programmed event record into the LWP event ring buffer
+/// and advances the ring buffer pointer.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> LWPINS </c> instruction.
+///
+/// \param DATA2
+/// A 64-bit value is inserted into the 64-bit Data2 field.
+/// \param DATA1
+/// A 32-bit value is inserted into the 32-bit Data1 field.
+/// \param FLAGS
+/// A 32-bit immediate value is inserted into the 32-bit Flags field.
+/// \returns If the ring buffer is full and LWP is running in Synchronized Mode,
+/// the event record overwrites the last record in the buffer, the MissedEvents
+/// counter in the LWPCB is incremented, the head pointer is not advanced, and
+/// 1 is returned. Otherwise 0 is returned.
+#define __lwpins64(DATA2, DATA1, FLAGS) \
+ (__builtin_ia32_lwpins64((unsigned long long) (DATA2), (unsigned int) (DATA1), \
+ (unsigned int) (FLAGS)))
+
+/// \brief Decrements the LWP programmed value sample event counter. If the result is
+/// negative, inserts an event record into the LWP event ring buffer in memory
+/// and advances the ring buffer pointer.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> LWPVAL </c> instruction.
+///
+/// \param DATA2
+/// A 64-bit value is and inserted into the 64-bit Data2 field.
+/// \param DATA1
+/// A 32-bit value is inserted into the 32-bit Data1 field.
+/// \param FLAGS
+/// A 32-bit immediate value is inserted into the 32-bit Flags field.
+#define __lwpval64(DATA2, DATA1, FLAGS) \
+ (__builtin_ia32_lwpval64((unsigned long long) (DATA2), (unsigned int) (DATA1), \
+ (unsigned int) (FLAGS)))
+
+#endif
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif /* __LWPINTRIN_H */
diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
index 2b3618398c..4b38d51713 100644
--- a/lib/Headers/mmintrin.h
+++ b/lib/Headers/mmintrin.h
@@ -608,10 +608,11 @@ _mm_subs_pi16(__m64 __m1, __m64 __m2)
/// \brief Subtracts each 8-bit unsigned integer element of the second 64-bit
/// integer vector of [8 x i8] from the corresponding 8-bit unsigned integer
-/// element of the first 64-bit integer vector of [8 x i8]. If an element of
-/// the first vector is less than the corresponding element of the second
-/// vector, the result is saturated to 0. The results are packed into a
-/// 64-bit integer vector of [8 x i8].
+/// element of the first 64-bit integer vector of [8 x i8].
+///
+/// If an element of the first vector is less than the corresponding element
+/// of the second vector, the result is saturated to 0. The results are
+/// packed into a 64-bit integer vector of [8 x i8].
///
/// \headerfile <x86intrin.h>
///
@@ -631,10 +632,11 @@ _mm_subs_pu8(__m64 __m1, __m64 __m2)
/// \brief Subtracts each 16-bit unsigned integer element of the second 64-bit
/// integer vector of [4 x i16] from the corresponding 16-bit unsigned
-/// integer element of the first 64-bit integer vector of [4 x i16]. If an
-/// element of the first vector is less than the corresponding element of the
-/// second vector, the result is saturated to 0. The results are packed into
-/// a 64-bit integer vector of [4 x i16].
+/// integer element of the first 64-bit integer vector of [4 x i16].
+///
+/// If an element of the first vector is less than the corresponding element
+/// of the second vector, the result is saturated to 0. The results are
+/// packed into a 64-bit integer vector of [4 x i16].
///
/// \headerfile <x86intrin.h>
///
@@ -657,9 +659,11 @@ _mm_subs_pu16(__m64 __m1, __m64 __m2)
/// element of the second 64-bit integer vector of [4 x i16] and get four
/// 32-bit products. Adds adjacent pairs of products to get two 32-bit sums.
/// The lower 32 bits of these two sums are packed into a 64-bit integer
-/// vector of [2 x i32]. For example, bits [15:0] of both parameters are
-/// multiplied, bits [31:16] of both parameters are multiplied, and the sum
-/// of both results is written to bits [31:0] of the result.
+/// vector of [2 x i32].
+///
+/// For example, bits [15:0] of both parameters are multiplied, bits [31:16]
+/// of both parameters are multiplied, and the sum of both results is written
+/// to bits [31:0] of the result.
///
/// \headerfile <x86intrin.h>
///
@@ -851,10 +855,11 @@ _mm_slli_si64(__m64 __m, int __count)
/// \brief Right-shifts each 16-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [4 x i16], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are filled with the sign bit of the initial value of each 16-bit
-/// element. The 16-bit results are packed into a 64-bit integer vector of
-/// [4 x i16].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are filled with the sign bit of the initial value of each
+/// 16-bit element. The 16-bit results are packed into a 64-bit integer
+/// vector of [4 x i16].
///
/// \headerfile <x86intrin.h>
///
@@ -874,6 +879,7 @@ _mm_sra_pi16(__m64 __m, __m64 __count)
/// \brief Right-shifts each 16-bit integer element of a 64-bit integer vector
/// of [4 x i16] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are filled with the sign bit of the initial value of each
/// 16-bit element. The 16-bit results are packed into a 64-bit integer
/// vector of [4 x i16].
@@ -896,10 +902,11 @@ _mm_srai_pi16(__m64 __m, int __count)
/// \brief Right-shifts each 32-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [2 x i32], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are filled with the sign bit of the initial value of each 32-bit
-/// element. The 32-bit results are packed into a 64-bit integer vector of
-/// [2 x i32].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are filled with the sign bit of the initial value of each
+/// 32-bit element. The 32-bit results are packed into a 64-bit integer
+/// vector of [2 x i32].
///
/// \headerfile <x86intrin.h>
///
@@ -919,6 +926,7 @@ _mm_sra_pi32(__m64 __m, __m64 __count)
/// \brief Right-shifts each 32-bit integer element of a 64-bit integer vector
/// of [2 x i32] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are filled with the sign bit of the initial value of each
/// 32-bit element. The 32-bit results are packed into a 64-bit integer
/// vector of [2 x i32].
@@ -941,9 +949,10 @@ _mm_srai_pi32(__m64 __m, int __count)
/// \brief Right-shifts each 16-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [4 x i16], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are cleared. The 16-bit results are packed into a 64-bit integer
-/// vector of [4 x i16].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are cleared. The 16-bit results are packed into a 64-bit
+/// integer vector of [4 x i16].
///
/// \headerfile <x86intrin.h>
///
@@ -963,6 +972,7 @@ _mm_srl_pi16(__m64 __m, __m64 __count)
/// \brief Right-shifts each 16-bit integer element of a 64-bit integer vector
/// of [4 x i16] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are cleared. The 16-bit results are packed into a 64-bit
/// integer vector of [4 x i16].
///
@@ -984,9 +994,10 @@ _mm_srli_pi16(__m64 __m, int __count)
/// \brief Right-shifts each 32-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [2 x i32], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are cleared. The 32-bit results are packed into a 64-bit integer
-/// vector of [2 x i32].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are cleared. The 32-bit results are packed into a 64-bit
+/// integer vector of [2 x i32].
///
/// \headerfile <x86intrin.h>
///
@@ -1006,6 +1017,7 @@ _mm_srl_pi32(__m64 __m, __m64 __count)
/// \brief Right-shifts each 32-bit integer element of a 64-bit integer vector
/// of [2 x i32] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are cleared. The 32-bit results are packed into a 64-bit
/// integer vector of [2 x i32].
///
@@ -1026,8 +1038,9 @@ _mm_srli_pi32(__m64 __m, int __count)
}
/// \brief Right-shifts the first 64-bit integer parameter by the number of bits
-/// specified by the second 64-bit integer parameter. High-order bits are
-/// cleared.
+/// specified by the second 64-bit integer parameter.
+///
+/// High-order bits are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1046,7 +1059,9 @@ _mm_srl_si64(__m64 __m, __m64 __count)
/// \brief Right-shifts the first parameter, which is a 64-bit integer, by the
/// number of bits specified by the second parameter, which is a 32-bit
-/// integer. High-order bits are cleared.
+/// integer.
+///
+/// High-order bits are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1140,8 +1155,9 @@ _mm_xor_si64(__m64 __m1, __m64 __m2)
/// \brief Compares the 8-bit integer elements of two 64-bit integer vectors of
/// [8 x i8] to determine if the element of the first vector is equal to the
-/// corresponding element of the second vector. The comparison yields 0 for
-/// false, 0xFF for true.
+/// corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1161,8 +1177,9 @@ _mm_cmpeq_pi8(__m64 __m1, __m64 __m2)
/// \brief Compares the 16-bit integer elements of two 64-bit integer vectors of
/// [4 x i16] to determine if the element of the first vector is equal to the
-/// corresponding element of the second vector. The comparison yields 0 for
-/// false, 0xFFFF for true.
+/// corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1182,8 +1199,9 @@ _mm_cmpeq_pi16(__m64 __m1, __m64 __m2)
/// \brief Compares the 32-bit integer elements of two 64-bit integer vectors of
/// [2 x i32] to determine if the element of the first vector is equal to the
-/// corresponding element of the second vector. The comparison yields 0 for
-/// false, 0xFFFFFFFF for true.
+/// corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFFFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1203,8 +1221,9 @@ _mm_cmpeq_pi32(__m64 __m1, __m64 __m2)
/// \brief Compares the 8-bit integer elements of two 64-bit integer vectors of
/// [8 x i8] to determine if the element of the first vector is greater than
-/// the corresponding element of the second vector. The comparison yields 0
-/// for false, 0xFF for true.
+/// the corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1224,8 +1243,9 @@ _mm_cmpgt_pi8(__m64 __m1, __m64 __m2)
/// \brief Compares the 16-bit integer elements of two 64-bit integer vectors of
/// [4 x i16] to determine if the element of the first vector is greater than
-/// the corresponding element of the second vector. The comparison yields 0
-/// for false, 0xFFFF for true.
+/// the corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1245,8 +1265,9 @@ _mm_cmpgt_pi16(__m64 __m1, __m64 __m2)
/// \brief Compares the 32-bit integer elements of two 64-bit integer vectors of
/// [2 x i32] to determine if the element of the first vector is greater than
-/// the corresponding element of the second vector. The comparison yields 0
-/// for false, 0xFFFFFFFF for true.
+/// the corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFFFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1268,7 +1289,7 @@ _mm_cmpgt_pi32(__m64 __m1, __m64 __m2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the the <c> VXORPS / XORPS </c> instruction.
+/// This intrinsic corresponds to the <c> VXORPS / XORPS </c> instruction.
///
/// \returns An initialized 64-bit integer vector with all elements set to zero.
static __inline__ __m64 __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/opencl-c.h b/lib/Headers/opencl-c.h
index 3bcb9a3af1..35fb0a82bc 100644
--- a/lib/Headers/opencl-c.h
+++ b/lib/Headers/opencl-c.h
@@ -6584,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);
-
-#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_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
+#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
@@ -12073,6 +11381,8 @@ half16 __ovld __cnfn bitselect(half16 a, half16 b, half16 c);
* For each component of a vector type,
* result[i] = if MSB of c[i] is set ? b[i] : a[i].
* For a scalar type, result = c ? b : a.
+ * b and a must have the same type.
+ * c must have the same number of elements and bits as a.
*/
char __ovld __cnfn select(char a, char b, char c);
uchar __ovld __cnfn select(uchar a, uchar b, char c);
@@ -12086,60 +11396,7 @@ char8 __ovld __cnfn select(char8 a, char8 b, char8 c);
uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, char8 c);
char16 __ovld __cnfn select(char16 a, char16 b, char16 c);
uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, char16 c);
-short __ovld __cnfn select(short a, short b, char c);
-ushort __ovld __cnfn select(ushort a, ushort b, char c);
-short2 __ovld __cnfn select(short2 a, short2 b, char2 c);
-ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, char2 c);
-short3 __ovld __cnfn select(short3 a, short3 b, char3 c);
-ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, char3 c);
-short4 __ovld __cnfn select(short4 a, short4 b, char4 c);
-ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, char4 c);
-short8 __ovld __cnfn select(short8 a, short8 b, char8 c);
-ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, char8 c);
-short16 __ovld __cnfn select(short16 a, short16 b, char16 c);
-ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, char16 c);
-int __ovld __cnfn select(int a, int b, char c);
-uint __ovld __cnfn select(uint a, uint b, char c);
-int2 __ovld __cnfn select(int2 a, int2 b, char2 c);
-uint2 __ovld __cnfn select(uint2 a, uint2 b, char2 c);
-int3 __ovld __cnfn select(int3 a, int3 b, char3 c);
-uint3 __ovld __cnfn select(uint3 a, uint3 b, char3 c);
-int4 __ovld __cnfn select(int4 a, int4 b, char4 c);
-uint4 __ovld __cnfn select(uint4 a, uint4 b, char4 c);
-int8 __ovld __cnfn select(int8 a, int8 b, char8 c);
-uint8 __ovld __cnfn select(uint8 a, uint8 b, char8 c);
-int16 __ovld __cnfn select(int16 a, int16 b, char16 c);
-uint16 __ovld __cnfn select(uint16 a, uint16 b, char16 c);
-long __ovld __cnfn select(long a, long b, char c);
-ulong __ovld __cnfn select(ulong a, ulong b, char c);
-long2 __ovld __cnfn select(long2 a, long2 b, char2 c);
-ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, char2 c);
-long3 __ovld __cnfn select(long3 a, long3 b, char3 c);
-ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, char3 c);
-long4 __ovld __cnfn select(long4 a, long4 b, char4 c);
-ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, char4 c);
-long8 __ovld __cnfn select(long8 a, long8 b, char8 c);
-ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, char8 c);
-long16 __ovld __cnfn select(long16 a, long16 b, char16 c);
-ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, char16 c);
-float __ovld __cnfn select(float a, float b, char c);
-float2 __ovld __cnfn select(float2 a, float2 b, char2 c);
-float3 __ovld __cnfn select(float3 a, float3 b, char3 c);
-float4 __ovld __cnfn select(float4 a, float4 b, char4 c);
-float8 __ovld __cnfn select(float8 a, float8 b, char8 c);
-float16 __ovld __cnfn select(float16 a, float16 b, char16 c);
-char __ovld __cnfn select(char a, char b, short c);
-uchar __ovld __cnfn select(uchar a, uchar b, short c);
-char2 __ovld __cnfn select(char2 a, char2 b, short2 c);
-uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, short2 c);
-char3 __ovld __cnfn select(char3 a, char3 b, short3 c);
-uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, short3 c);
-char4 __ovld __cnfn select(char4 a, char4 b, short4 c);
-uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, short4 c);
-char8 __ovld __cnfn select(char8 a, char8 b, short8 c);
-uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, short8 c);
-char16 __ovld __cnfn select(char16 a, char16 b, short16 c);
-uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, short16 c);
+
short __ovld __cnfn select(short a, short b, short c);
ushort __ovld __cnfn select(ushort a, ushort b, short c);
short2 __ovld __cnfn select(short2 a, short2 b, short2 c);
@@ -12152,60 +11409,7 @@ short8 __ovld __cnfn select(short8 a, short8 b, short8 c);
ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, short8 c);
short16 __ovld __cnfn select(short16 a, short16 b, short16 c);
ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, short16 c);
-int __ovld __cnfn select(int a, int b, short c);
-uint __ovld __cnfn select(uint a, uint b, short c);
-int2 __ovld __cnfn select(int2 a, int2 b, short2 c);
-uint2 __ovld __cnfn select(uint2 a, uint2 b, short2 c);
-int3 __ovld __cnfn select(int3 a, int3 b, short3 c);
-uint3 __ovld __cnfn select(uint3 a, uint3 b, short3 c);
-int4 __ovld __cnfn select(int4 a, int4 b, short4 c);
-uint4 __ovld __cnfn select(uint4 a, uint4 b, short4 c);
-int8 __ovld __cnfn select(int8 a, int8 b, short8 c);
-uint8 __ovld __cnfn select(uint8 a, uint8 b, short8 c);
-int16 __ovld __cnfn select(int16 a, int16 b, short16 c);
-uint16 __ovld __cnfn select(uint16 a, uint16 b, short16 c);
-long __ovld __cnfn select(long a, long b, short c);
-ulong __ovld __cnfn select(ulong a, ulong b, short c);
-long2 __ovld __cnfn select(long2 a, long2 b, short2 c);
-ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, short2 c);
-long3 __ovld __cnfn select(long3 a, long3 b, short3 c);
-ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, short3 c);
-long4 __ovld __cnfn select(long4 a, long4 b, short4 c);
-ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, short4 c);
-long8 __ovld __cnfn select(long8 a, long8 b, short8 c);
-ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, short8 c);
-long16 __ovld __cnfn select(long16 a, long16 b, short16 c);
-ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, short16 c);
-float __ovld __cnfn select(float a, float b, short c);
-float2 __ovld __cnfn select(float2 a, float2 b, short2 c);
-float3 __ovld __cnfn select(float3 a, float3 b, short3 c);
-float4 __ovld __cnfn select(float4 a, float4 b, short4 c);
-float8 __ovld __cnfn select(float8 a, float8 b, short8 c);
-float16 __ovld __cnfn select(float16 a, float16 b, short16 c);
-char __ovld __cnfn select(char a, char b, int c);
-uchar __ovld __cnfn select(uchar a, uchar b, int c);
-char2 __ovld __cnfn select(char2 a, char2 b, int2 c);
-uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, int2 c);
-char3 __ovld __cnfn select(char3 a, char3 b, int3 c);
-uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, int3 c);
-char4 __ovld __cnfn select(char4 a, char4 b, int4 c);
-uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, int4 c);
-char8 __ovld __cnfn select(char8 a, char8 b, int8 c);
-uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, int8 c);
-char16 __ovld __cnfn select(char16 a, char16 b, int16 c);
-uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, int16 c);
-short __ovld __cnfn select(short a, short b, int c);
-ushort __ovld __cnfn select(ushort a, ushort b, int c);
-short2 __ovld __cnfn select(short2 a, short2 b, int2 c);
-ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, int2 c);
-short3 __ovld __cnfn select(short3 a, short3 b, int3 c);
-ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, int3 c);
-short4 __ovld __cnfn select(short4 a, short4 b, int4 c);
-ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, int4 c);
-short8 __ovld __cnfn select(short8 a, short8 b, int8 c);
-ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, int8 c);
-short16 __ovld __cnfn select(short16 a, short16 b, int16 c);
-ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, int16 c);
+
int __ovld __cnfn select(int a, int b, int c);
uint __ovld __cnfn select(uint a, uint b, int c);
int2 __ovld __cnfn select(int2 a, int2 b, int2 c);
@@ -12218,60 +11422,13 @@ int8 __ovld __cnfn select(int8 a, int8 b, int8 c);
uint8 __ovld __cnfn select(uint8 a, uint8 b, int8 c);
int16 __ovld __cnfn select(int16 a, int16 b, int16 c);
uint16 __ovld __cnfn select(uint16 a, uint16 b, int16 c);
-long __ovld __cnfn select(long a, long b, int c);
-ulong __ovld __cnfn select(ulong a, ulong b, int c);
-long2 __ovld __cnfn select(long2 a, long2 b, int2 c);
-ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, int2 c);
-long3 __ovld __cnfn select(long3 a, long3 b, int3 c);
-ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, int3 c);
-long4 __ovld __cnfn select(long4 a, long4 b, int4 c);
-ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, int4 c);
-long8 __ovld __cnfn select(long8 a, long8 b, int8 c);
-ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, int8 c);
-long16 __ovld __cnfn select(long16 a, long16 b, int16 c);
-ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, int16 c);
float __ovld __cnfn select(float a, float b, int c);
float2 __ovld __cnfn select(float2 a, float2 b, int2 c);
float3 __ovld __cnfn select(float3 a, float3 b, int3 c);
float4 __ovld __cnfn select(float4 a, float4 b, int4 c);
float8 __ovld __cnfn select(float8 a, float8 b, int8 c);
float16 __ovld __cnfn select(float16 a, float16 b, int16 c);
-char __ovld __cnfn select(char a, char b, long c);
-uchar __ovld __cnfn select(uchar a, uchar b, long c);
-char2 __ovld __cnfn select(char2 a, char2 b, long2 c);
-uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, long2 c);
-char3 __ovld __cnfn select(char3 a, char3 b, long3 c);
-uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, long3 c);
-char4 __ovld __cnfn select(char4 a, char4 b, long4 c);
-uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, long4 c);
-char8 __ovld __cnfn select(char8 a, char8 b, long8 c);
-uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, long8 c);
-char16 __ovld __cnfn select(char16 a, char16 b, long16 c);
-uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, long16 c);
-short __ovld __cnfn select(short a, short b, long c);
-ushort __ovld __cnfn select(ushort a, ushort b, long c);
-short2 __ovld __cnfn select(short2 a, short2 b, long2 c);
-ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, long2 c);
-short3 __ovld __cnfn select(short3 a, short3 b, long3 c);
-ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, long3 c);
-short4 __ovld __cnfn select(short4 a, short4 b, long4 c);
-ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, long4 c);
-short8 __ovld __cnfn select(short8 a, short8 b, long8 c);
-ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, long8 c);
-short16 __ovld __cnfn select(short16 a, short16 b, long16 c);
-ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, long16 c);
-int __ovld __cnfn select(int a, int b, long c);
-uint __ovld __cnfn select(uint a, uint b, long c);
-int2 __ovld __cnfn select(int2 a, int2 b, long2 c);
-uint2 __ovld __cnfn select(uint2 a, uint2 b, long2 c);
-int3 __ovld __cnfn select(int3 a, int3 b, long3 c);
-uint3 __ovld __cnfn select(uint3 a, uint3 b, long3 c);
-int4 __ovld __cnfn select(int4 a, int4 b, long4 c);
-uint4 __ovld __cnfn select(uint4 a, uint4 b, long4 c);
-int8 __ovld __cnfn select(int8 a, int8 b, long8 c);
-uint8 __ovld __cnfn select(uint8 a, uint8 b, long8 c);
-int16 __ovld __cnfn select(int16 a, int16 b, long16 c);
-uint16 __ovld __cnfn select(uint16 a, uint16 b, long16 c);
+
long __ovld __cnfn select(long a, long b, long c);
ulong __ovld __cnfn select(ulong a, ulong b, long c);
long2 __ovld __cnfn select(long2 a, long2 b, long2 c);
@@ -12284,12 +11441,7 @@ long8 __ovld __cnfn select(long8 a, long8 b, long8 c);
ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, long8 c);
long16 __ovld __cnfn select(long16 a, long16 b, long16 c);
ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, long16 c);
-float __ovld __cnfn select(float a, float b, long c);
-float2 __ovld __cnfn select(float2 a, float2 b, long2 c);
-float3 __ovld __cnfn select(float3 a, float3 b, long3 c);
-float4 __ovld __cnfn select(float4 a, float4 b, long4 c);
-float8 __ovld __cnfn select(float8 a, float8 b, long8 c);
-float16 __ovld __cnfn select(float16 a, float16 b, long16 c);
+
char __ovld __cnfn select(char a, char b, uchar c);
uchar __ovld __cnfn select(uchar a, uchar b, uchar c);
char2 __ovld __cnfn select(char2 a, char2 b, uchar2 c);
@@ -12302,60 +11454,7 @@ char8 __ovld __cnfn select(char8 a, char8 b, uchar8 c);
uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, uchar8 c);
char16 __ovld __cnfn select(char16 a, char16 b, uchar16 c);
uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, uchar16 c);
-short __ovld __cnfn select(short a, short b, uchar c);
-ushort __ovld __cnfn select(ushort a, ushort b, uchar c);
-short2 __ovld __cnfn select(short2 a, short2 b, uchar2 c);
-ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, uchar2 c);
-short3 __ovld __cnfn select(short3 a, short3 b, uchar3 c);
-ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, uchar3 c);
-short4 __ovld __cnfn select(short4 a, short4 b, uchar4 c);
-ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, uchar4 c);
-short8 __ovld __cnfn select(short8 a, short8 b, uchar8 c);
-ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, uchar8 c);
-short16 __ovld __cnfn select(short16 a, short16 b, uchar16 c);
-ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, uchar16 c);
-int __ovld __cnfn select(int a, int b, uchar c);
-uint __ovld __cnfn select(uint a, uint b, uchar c);
-int2 __ovld __cnfn select(int2 a, int2 b, uchar2 c);
-uint2 __ovld __cnfn select(uint2 a, uint2 b, uchar2 c);
-int3 __ovld __cnfn select(int3 a, int3 b, uchar3 c);
-uint3 __ovld __cnfn select(uint3 a, uint3 b, uchar3 c);
-int4 __ovld __cnfn select(int4 a, int4 b, uchar4 c);
-uint4 __ovld __cnfn select(uint4 a, uint4 b, uchar4 c);
-int8 __ovld __cnfn select(int8 a, int8 b, uchar8 c);
-uint8 __ovld __cnfn select(uint8 a, uint8 b, uchar8 c);
-int16 __ovld __cnfn select(int16 a, int16 b, uchar16 c);
-uint16 __ovld __cnfn select(uint16 a, uint16 b, uchar16 c);
-long __ovld __cnfn select(long a, long b, uchar c);
-ulong __ovld __cnfn select(ulong a, ulong b, uchar c);
-long2 __ovld __cnfn select(long2 a, long2 b, uchar2 c);
-ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, uchar2 c);
-long3 __ovld __cnfn select(long3 a, long3 b, uchar3 c);
-ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, uchar3 c);
-long4 __ovld __cnfn select(long4 a, long4 b, uchar4 c);
-ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, uchar4 c);
-long8 __ovld __cnfn select(long8 a, long8 b, uchar8 c);
-ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, uchar8 c);
-long16 __ovld __cnfn select(long16 a, long16 b, uchar16 c);
-ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, uchar16 c);
-float __ovld __cnfn select(float a, float b, uchar c);
-float2 __ovld __cnfn select(float2 a, float2 b, uchar2 c);
-float3 __ovld __cnfn select(float3 a, float3 b, uchar3 c);
-float4 __ovld __cnfn select(float4 a, float4 b, uchar4 c);
-float8 __ovld __cnfn select(float8 a, float8 b, uchar8 c);
-float16 __ovld __cnfn select(float16 a, float16 b, uchar16 c);
-char __ovld __cnfn select(char a, char b, ushort c);
-uchar __ovld __cnfn select(uchar a, uchar b, ushort c);
-char2 __ovld __cnfn select(char2 a, char2 b, ushort2 c);
-uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, ushort2 c);
-char3 __ovld __cnfn select(char3 a, char3 b, ushort3 c);
-uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, ushort3 c);
-char4 __ovld __cnfn select(char4 a, char4 b, ushort4 c);
-uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, ushort4 c);
-char8 __ovld __cnfn select(char8 a, char8 b, ushort8 c);
-uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, ushort8 c);
-char16 __ovld __cnfn select(char16 a, char16 b, ushort16 c);
-uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, ushort16 c);
+
short __ovld __cnfn select(short a, short b, ushort c);
ushort __ovld __cnfn select(ushort a, ushort b, ushort c);
short2 __ovld __cnfn select(short2 a, short2 b, ushort2 c);
@@ -12368,60 +11467,7 @@ short8 __ovld __cnfn select(short8 a, short8 b, ushort8 c);
ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, ushort8 c);
short16 __ovld __cnfn select(short16 a, short16 b, ushort16 c);
ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, ushort16 c);
-int __ovld __cnfn select(int a, int b, ushort c);
-uint __ovld __cnfn select(uint a, uint b, ushort c);
-int2 __ovld __cnfn select(int2 a, int2 b, ushort2 c);
-uint2 __ovld __cnfn select(uint2 a, uint2 b, ushort2 c);
-int3 __ovld __cnfn select(int3 a, int3 b, ushort3 c);
-uint3 __ovld __cnfn select(uint3 a, uint3 b, ushort3 c);
-int4 __ovld __cnfn select(int4 a, int4 b, ushort4 c);
-uint4 __ovld __cnfn select(uint4 a, uint4 b, ushort4 c);
-int8 __ovld __cnfn select(int8 a, int8 b, ushort8 c);
-uint8 __ovld __cnfn select(uint8 a, uint8 b, ushort8 c);
-int16 __ovld __cnfn select(int16 a, int16 b, ushort16 c);
-uint16 __ovld __cnfn select(uint16 a, uint16 b, ushort16 c);
-long __ovld __cnfn select(long a, long b, ushort c);
-ulong __ovld __cnfn select(ulong a, ulong b, ushort c);
-long2 __ovld __cnfn select(long2 a, long2 b, ushort2 c);
-ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, ushort2 c);
-long3 __ovld __cnfn select(long3 a, long3 b, ushort3 c);
-ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, ushort3 c);
-long4 __ovld __cnfn select(long4 a, long4 b, ushort4 c);
-ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, ushort4 c);
-long8 __ovld __cnfn select(long8 a, long8 b, ushort8 c);
-ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, ushort8 c);
-long16 __ovld __cnfn select(long16 a, long16 b, ushort16 c);
-ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, ushort16 c);
-float __ovld __cnfn select(float a, float b, ushort c);
-float2 __ovld __cnfn select(float2 a, float2 b, ushort2 c);
-float3 __ovld __cnfn select(float3 a, float3 b, ushort3 c);
-float4 __ovld __cnfn select(float4 a, float4 b, ushort4 c);
-float8 __ovld __cnfn select(float8 a, float8 b, ushort8 c);
-float16 __ovld __cnfn select(float16 a, float16 b, ushort16 c);
-char __ovld __cnfn select(char a, char b, uint c);
-uchar __ovld __cnfn select(uchar a, uchar b, uint c);
-char2 __ovld __cnfn select(char2 a, char2 b, uint2 c);
-uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, uint2 c);
-char3 __ovld __cnfn select(char3 a, char3 b, uint3 c);
-uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, uint3 c);
-char4 __ovld __cnfn select(char4 a, char4 b, uint4 c);
-uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, uint4 c);
-char8 __ovld __cnfn select(char8 a, char8 b, uint8 c);
-uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, uint8 c);
-char16 __ovld __cnfn select(char16 a, char16 b, uint16 c);
-uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, uint16 c);
-short __ovld __cnfn select(short a, short b, uint c);
-ushort __ovld __cnfn select(ushort a, ushort b, uint c);
-short2 __ovld __cnfn select(short2 a, short2 b, uint2 c);
-ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, uint2 c);
-short3 __ovld __cnfn select(short3 a, short3 b, uint3 c);
-ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, uint3 c);
-short4 __ovld __cnfn select(short4 a, short4 b, uint4 c);
-ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, uint4 c);
-short8 __ovld __cnfn select(short8 a, short8 b, uint8 c);
-ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, uint8 c);
-short16 __ovld __cnfn select(short16 a, short16 b, uint16 c);
-ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, uint16 c);
+
int __ovld __cnfn select(int a, int b, uint c);
uint __ovld __cnfn select(uint a, uint b, uint c);
int2 __ovld __cnfn select(int2 a, int2 b, uint2 c);
@@ -12434,60 +11480,13 @@ int8 __ovld __cnfn select(int8 a, int8 b, uint8 c);
uint8 __ovld __cnfn select(uint8 a, uint8 b, uint8 c);
int16 __ovld __cnfn select(int16 a, int16 b, uint16 c);
uint16 __ovld __cnfn select(uint16 a, uint16 b, uint16 c);
-long __ovld __cnfn select(long a, long b, uint c);
-ulong __ovld __cnfn select(ulong a, ulong b, uint c);
-long2 __ovld __cnfn select(long2 a, long2 b, uint2 c);
-ulong2 __ovld __cnfn select(ulong2 a, ulong2 b, uint2 c);
-long3 __ovld __cnfn select(long3 a, long3 b, uint3 c);
-ulong3 __ovld __cnfn select(ulong3 a, ulong3 b, uint3 c);
-long4 __ovld __cnfn select(long4 a, long4 b, uint4 c);
-ulong4 __ovld __cnfn select(ulong4 a, ulong4 b, uint4 c);
-long8 __ovld __cnfn select(long8 a, long8 b, uint8 c);
-ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, uint8 c);
-long16 __ovld __cnfn select(long16 a, long16 b, uint16 c);
-ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, uint16 c);
float __ovld __cnfn select(float a, float b, uint c);
float2 __ovld __cnfn select(float2 a, float2 b, uint2 c);
float3 __ovld __cnfn select(float3 a, float3 b, uint3 c);
float4 __ovld __cnfn select(float4 a, float4 b, uint4 c);
float8 __ovld __cnfn select(float8 a, float8 b, uint8 c);
float16 __ovld __cnfn select(float16 a, float16 b, uint16 c);
-char __ovld __cnfn select(char a, char b, ulong c);
-uchar __ovld __cnfn select(uchar a, uchar b, ulong c);
-char2 __ovld __cnfn select(char2 a, char2 b, ulong2 c);
-uchar2 __ovld __cnfn select(uchar2 a, uchar2 b, ulong2 c);
-char3 __ovld __cnfn select(char3 a, char3 b, ulong3 c);
-uchar3 __ovld __cnfn select(uchar3 a, uchar3 b, ulong3 c);
-char4 __ovld __cnfn select(char4 a, char4 b, ulong4 c);
-uchar4 __ovld __cnfn select(uchar4 a, uchar4 b, ulong4 c);
-char8 __ovld __cnfn select(char8 a, char8 b, ulong8 c);
-uchar8 __ovld __cnfn select(uchar8 a, uchar8 b, ulong8 c);
-char16 __ovld __cnfn select(char16 a, char16 b, ulong16 c);
-uchar16 __ovld __cnfn select(uchar16 a, uchar16 b, ulong16 c);
-short __ovld __cnfn select(short a, short b, ulong c);
-ushort __ovld __cnfn select(ushort a, ushort b, ulong c);
-short2 __ovld __cnfn select(short2 a, short2 b, ulong2 c);
-ushort2 __ovld __cnfn select(ushort2 a, ushort2 b, ulong2 c);
-short3 __ovld __cnfn select(short3 a, short3 b, ulong3 c);
-ushort3 __ovld __cnfn select(ushort3 a, ushort3 b, ulong3 c);
-short4 __ovld __cnfn select(short4 a, short4 b, ulong4 c);
-ushort4 __ovld __cnfn select(ushort4 a, ushort4 b, ulong4 c);
-short8 __ovld __cnfn select(short8 a, short8 b, ulong8 c);
-ushort8 __ovld __cnfn select(ushort8 a, ushort8 b, ulong8 c);
-short16 __ovld __cnfn select(short16 a, short16 b, ulong16 c);
-ushort16 __ovld __cnfn select(ushort16 a, ushort16 b, ulong16 c);
-int __ovld __cnfn select(int a, int b, ulong c);
-uint __ovld __cnfn select(uint a, uint b, ulong c);
-int2 __ovld __cnfn select(int2 a, int2 b, ulong2 c);
-uint2 __ovld __cnfn select(uint2 a, uint2 b, ulong2 c);
-int3 __ovld __cnfn select(int3 a, int3 b, ulong3 c);
-uint3 __ovld __cnfn select(uint3 a, uint3 b, ulong3 c);
-int4 __ovld __cnfn select(int4 a, int4 b, ulong4 c);
-uint4 __ovld __cnfn select(uint4 a, uint4 b, ulong4 c);
-int8 __ovld __cnfn select(int8 a, int8 b, ulong8 c);
-uint8 __ovld __cnfn select(uint8 a, uint8 b, ulong8 c);
-int16 __ovld __cnfn select(int16 a, int16 b, ulong16 c);
-uint16 __ovld __cnfn select(uint16 a, uint16 b, ulong16 c);
+
long __ovld __cnfn select(long a, long b, ulong c);
ulong __ovld __cnfn select(ulong a, ulong b, ulong c);
long2 __ovld __cnfn select(long2 a, long2 b, ulong2 c);
@@ -12500,12 +11499,7 @@ long8 __ovld __cnfn select(long8 a, long8 b, ulong8 c);
ulong8 __ovld __cnfn select(ulong8 a, ulong8 b, ulong8 c);
long16 __ovld __cnfn select(long16 a, long16 b, ulong16 c);
ulong16 __ovld __cnfn select(ulong16 a, ulong16 b, ulong16 c);
-float __ovld __cnfn select(float a, float b, ulong c);
-float2 __ovld __cnfn select(float2 a, float2 b, ulong2 c);
-float3 __ovld __cnfn select(float3 a, float3 b, ulong3 c);
-float4 __ovld __cnfn select(float4 a, float4 b, ulong4 c);
-float8 __ovld __cnfn select(float8 a, float8 b, ulong8 c);
-float16 __ovld __cnfn select(float16 a, float16 b, ulong16 c);
+
#ifdef cl_khr_fp64
double __ovld __cnfn select(double a, double b, long c);
double2 __ovld __cnfn select(double2 a, double2 b, long2 c);
@@ -13833,13 +12827,14 @@ void __ovld __conv barrier(cl_mem_fence_flags flags);
#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
-typedef enum memory_scope
-{
- memory_scope_work_item,
- memory_scope_work_group,
- memory_scope_device,
- memory_scope_all_svm_devices,
- memory_scope_sub_group
+typedef enum memory_scope {
+ memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM,
+ memory_scope_work_group = __OPENCL_MEMORY_SCOPE_WORK_GROUP,
+ memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE,
+ memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES,
+#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups)
+ memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP
+#endif
} memory_scope;
void __ovld __conv work_group_barrier(cl_mem_fence_flags flags, memory_scope scope);
@@ -14395,10 +13390,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
@@ -14515,8 +13510,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
@@ -14646,11 +13639,11 @@ unsigned long __ovld atom_xor(volatile __local unsigned long *p, unsigned long v
// enum values aligned with what clang uses in EmitAtomicExpr()
typedef enum memory_order
{
- memory_order_relaxed,
- memory_order_acquire,
- memory_order_release,
- memory_order_acq_rel,
- memory_order_seq_cst
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;
// double atomics support requires extensions cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics
@@ -15656,6 +14649,7 @@ float __purefn __ovld read_imagef(read_only image2d_array_msaa_depth_t image, in
#endif //cl_khr_gl_msaa_sharing
// OpenCL Extension v2.0 s9.18 - Mipmaps
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, float coord, float lod);
@@ -15731,6 +14725,7 @@ int4 __purefn __ovld read_imagei(read_only image3d_t image, sampler_t sampler, f
uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, float4 coord, float lod);
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
/**
* Sampler-less Image Access
@@ -15829,6 +14824,7 @@ float __purefn __ovld read_imagef(read_write image2d_msaa_depth_t image, int2 co
float __purefn __ovld read_imagef(read_write image2d_array_msaa_depth_t image, int4 coord, int sample);
#endif //cl_khr_gl_msaa_sharing
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
float4 __purefn __ovld read_imagef(read_write image1d_t image, sampler_t sampler, float coord, float lod);
int4 __purefn __ovld read_imagei(read_write image1d_t image, sampler_t sampler, float coord, float lod);
@@ -15902,6 +14898,7 @@ float4 __purefn __ovld read_imagef(read_write image3d_t image, sampler_t sampler
int4 __purefn __ovld read_imagei(read_write image3d_t image, sampler_t sampler, float4 coord, float lod);
uint4 __purefn __ovld read_imageui(read_write image3d_t image, sampler_t sampler, float4 coord, float lod);
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// Image read functions returning half4 type
#ifdef cl_khr_fp16
@@ -16013,6 +15010,7 @@ void __ovld write_imagef(write_only image2d_array_depth_t image, int4 coord, flo
#endif //cl_khr_depth_images
// OpenCL Extension v2.0 s9.18 - Mipmaps
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
void __ovld write_imagef(write_only image1d_t image, int coord, int lod, float4 color);
void __ovld write_imagei(write_only image1d_t image, int coord, int lod, int4 color);
@@ -16039,6 +15037,7 @@ void __ovld write_imagei(write_only image3d_t image, int4 coord, int lod, int4 c
void __ovld write_imageui(write_only image3d_t image, int4 coord, int lod, uint4 color);
#endif
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// Image write functions for half4 type
#ifdef cl_khr_fp16
@@ -16085,6 +15084,7 @@ void __ovld write_imagef(read_write image2d_depth_t image, int2 coord, float col
void __ovld write_imagef(read_write image2d_array_depth_t image, int4 coord, float color);
#endif //cl_khr_depth_images
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
void __ovld write_imagef(read_write image1d_t image, int coord, int lod, float4 color);
void __ovld write_imagei(read_write image1d_t image, int coord, int lod, int4 color);
@@ -16111,6 +15111,7 @@ void __ovld write_imagei(read_write image3d_t image, int4 coord, int lod, int4 c
void __ovld write_imageui(read_write image3d_t image, int4 coord, int lod, uint4 color);
#endif
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// Image write functions for half4 type
#ifdef cl_khr_fp16
@@ -16253,6 +15254,7 @@ int __ovld __cnfn get_image_depth(read_write image3d_t image);
#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// OpenCL Extension v2.0 s9.18 - Mipmaps
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
/**
* Return the image miplevels.
@@ -16268,11 +15270,9 @@ int __ovld get_image_num_mip_levels(write_only image2d_t image);
int __ovld get_image_num_mip_levels(write_only image3d_t image);
#endif
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
int __ovld get_image_num_mip_levels(read_write image1d_t image);
int __ovld get_image_num_mip_levels(read_write image2d_t image);
int __ovld get_image_num_mip_levels(read_write image3d_t image);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
int __ovld get_image_num_mip_levels(read_only image1d_array_t image);
int __ovld get_image_num_mip_levels(read_only image2d_array_t image);
@@ -16284,14 +15284,13 @@ int __ovld get_image_num_mip_levels(write_only image2d_array_t image);
int __ovld get_image_num_mip_levels(write_only image2d_array_depth_t image);
int __ovld get_image_num_mip_levels(write_only image2d_depth_t image);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
int __ovld get_image_num_mip_levels(read_write image1d_array_t image);
int __ovld get_image_num_mip_levels(read_write image2d_array_t image);
int __ovld get_image_num_mip_levels(read_write image2d_array_depth_t image);
int __ovld get_image_num_mip_levels(read_write image2d_depth_t image);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
/**
* Return the channel data type. Valid values are:
diff --git a/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h
index a479d9ed29..559ece2e39 100644
--- a/lib/Headers/pmmintrin.h
+++ b/lib/Headers/pmmintrin.h
@@ -31,9 +31,11 @@
__attribute__((__always_inline__, __nodebug__, __target__("sse3")))
/// \brief Loads data from an unaligned memory location to elements in a 128-bit
-/// vector. If the address of the data is not 16-byte aligned, the
-/// instruction may read two adjacent aligned blocks of memory to retrieve
-/// the requested data.
+/// vector.
+///
+/// If the address of the data is not 16-byte aligned, the instruction may
+/// read two adjacent aligned blocks of memory to retrieve the requested
+/// data.
///
/// \headerfile <x86intrin.h>
///
diff --git a/lib/Headers/prfchwintrin.h b/lib/Headers/prfchwintrin.h
index a3789126ef..b52f31da27 100644
--- a/lib/Headers/prfchwintrin.h
+++ b/lib/Headers/prfchwintrin.h
@@ -50,8 +50,10 @@ _m_prefetch(void *__P)
/// 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.
+/// after the prefetch is performed.
+///
+/// Note that the effect of this intrinsic is dependent on the processor
+/// implementation.
///
/// \headerfile <x86intrin.h>
///
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 30d1038fa6..c2fa5a452b 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -56,8 +56,7 @@
/// __m128 _mm_ceil_ps(__m128 X);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
///
/// \param X
/// A 128-bit vector of [4 x float] values to be rounded up.
@@ -74,8 +73,7 @@
/// __m128d _mm_ceil_pd(__m128d X);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
///
/// \param X
/// A 128-bit vector of [2 x double] values to be rounded up.
@@ -94,8 +92,7 @@
/// __m128 _mm_ceil_ss(__m128 X, __m128 Y);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
///
/// \param X
/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
@@ -120,8 +117,7 @@
/// __m128d _mm_ceil_sd(__m128d X, __m128d Y);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
///
/// \param X
/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
@@ -144,8 +140,7 @@
/// __m128 _mm_floor_ps(__m128 X);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
///
/// \param X
/// A 128-bit vector of [4 x float] values to be rounded down.
@@ -162,8 +157,7 @@
/// __m128d _mm_floor_pd(__m128d X);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
///
/// \param X
/// A 128-bit vector of [2 x double].
@@ -174,7 +168,7 @@
/// 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].
+/// result vector of [4 x float].
///
/// \headerfile <x86intrin.h>
///
@@ -182,8 +176,7 @@
/// __m128 _mm_floor_ss(__m128 X, __m128 Y);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDSS / ROUNDSS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
///
/// \param X
/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
@@ -208,8 +201,7 @@
/// __m128d _mm_floor_sd(__m128d X, __m128d Y);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
///
/// \param X
/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
@@ -233,8 +225,7 @@
/// __m128 _mm_round_ps(__m128 X, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDPS / ROUNDPS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
///
/// \param X
/// A 128-bit vector of [4 x float].
@@ -256,7 +247,7 @@
#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
+/// \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
@@ -265,12 +256,11 @@
///
/// \headerfile <x86intrin.h>
///
-/// \code
+/// \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.
+/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
///
/// \param X
/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
@@ -310,8 +300,7 @@
/// __m128d _mm_round_pd(__m128d X, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDPD / ROUNDPD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
///
/// \param X
/// A 128-bit vector of [2 x double].
@@ -333,10 +322,9 @@
#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
+/// 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].
@@ -347,8 +335,7 @@
/// __m128d _mm_round_sd(__m128d X, __m128d Y, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VROUNDSD / ROUNDSD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
///
/// \param X
/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
@@ -388,8 +375,7 @@
/// __m128d _mm_blend_pd(__m128d V1, __m128d V2, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VBLENDPD / BLENDPD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VBLENDPD / BLENDPD </c> instruction.
///
/// \param V1
/// A 128-bit vector of [2 x double].
@@ -419,8 +405,7 @@
/// __m128 _mm_blend_ps(__m128 V1, __m128 V2, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VBLENDPS / BLENDPS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VBLENDPS / BLENDPS </c> instruction.
///
/// \param V1
/// A 128-bit vector of [4 x float].
@@ -447,8 +432,7 @@
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VBLENDVPD / BLENDVPD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VBLENDVPD / BLENDVPD </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [2 x double].
@@ -475,8 +459,7 @@ _mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VBLENDVPS / BLENDVPS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VBLENDVPS / BLENDVPS </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [4 x float].
@@ -503,8 +486,7 @@ _mm_blendv_ps (__m128 __V1, __m128 __V2, __m128 __M)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPBLENDVB / PBLENDVB </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPBLENDVB / PBLENDVB </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [16 x i8].
@@ -535,8 +517,7 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
/// __m128i _mm_blend_epi16(__m128i V1, __m128i V2, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPBLENDW / PBLENDW </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPBLENDW / PBLENDW </c> instruction.
///
/// \param V1
/// A 128-bit vector of [8 x i16].
@@ -569,13 +550,12 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMULLD / PMULLD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMULLD / PMULLD </c> instruction.
///
/// \param __V1
/// A 128-bit integer vector.
/// \param __V2
-/// A 128-bit integer vector.
+/// 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)
@@ -589,8 +569,7 @@ _mm_mullo_epi32 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMULDQ / PMULDQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMULDQ / PMULDQ </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [4 x i32].
@@ -607,7 +586,9 @@ _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
+/// [4 x float].
+///
+/// The immediate integer operand controls which input elements
/// will contribute to the dot product, and where the final results are
/// returned.
///
@@ -617,8 +598,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
/// __m128 _mm_dp_ps(__m128 X, __m128 Y, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VDPPS / DPPS </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VDPPS / DPPS </c> instruction.
///
/// \param X
/// A 128-bit vector of [4 x float].
@@ -642,7 +622,9 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
/// \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
+/// [2 x double].
+///
+/// The immediate integer operand controls which input
/// elements will contribute to the dot product, and where the final results
/// are returned.
///
@@ -652,8 +634,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
/// __m128d _mm_dp_pd(__m128d X, __m128d Y, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VDPPD / DPPD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VDPPD / DPPD </c> instruction.
///
/// \param X
/// A 128-bit vector of [2 x double].
@@ -680,8 +661,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VMOVNTDQA / MOVNTDQA </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VMOVNTDQA / MOVNTDQA </c> instruction.
///
/// \param __V
/// A pointer to a 128-bit aligned memory location that contains the integer
@@ -691,7 +671,7 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
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. */
@@ -701,8 +681,7 @@ _mm_stream_load_si128 (__m128i const *__V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMINSB / PMINSB </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMINSB / PMINSB </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [16 x i8].
@@ -721,8 +700,7 @@ _mm_min_epi8 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMAXSB / PMAXSB </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMAXSB / PMAXSB </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [16 x i8].
@@ -741,8 +719,7 @@ _mm_max_epi8 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMINUW / PMINUW </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMINUW / PMINUW </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [8 x u16].
@@ -761,8 +738,7 @@ _mm_min_epu16 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMAXUW / PMAXUW </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMAXUW / PMAXUW </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [8 x u16].
@@ -781,8 +757,7 @@ _mm_max_epu16 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMINSD / PMINSD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMINSD / PMINSD </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [4 x i32].
@@ -795,14 +770,13 @@ _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
+/// \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.
+/// This intrinsic corresponds to the <c> VPMAXSD / PMAXSD </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [4 x i32].
@@ -821,8 +795,7 @@ _mm_max_epi32 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMINUD / PMINUD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMINUD / PMINUD </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [4 x u32].
@@ -841,8 +814,7 @@ _mm_min_epu32 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMAXUD / PMAXUD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMAXUD / PMAXUD </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [4 x u32].
@@ -867,7 +839,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// __m128 _mm_insert_ps(__m128 X, __m128 Y, const int N);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VINSERTPS </i> </c> instruction.
+/// This intrinsic corresponds to the <c> VINSERTPS </c> instruction.
///
/// \param X
/// A 128-bit vector source operand of [4 x float]. With the exception of
@@ -907,14 +879,14 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// int _mm_extract_ps(__m128 X, const int N);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VEXTRACTPS / EXTRACTPS </i> </c>
+/// This intrinsic corresponds to the <c> VEXTRACTPS / EXTRACTPS </c>
/// instruction.
///
/// \param X
/// A 128-bit vector of [4 x float].
/// \param N
/// An immediate value. Bits [1:0] determines which bits from the argument
-/// \a X are extracted and returned: \n
+/// \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
@@ -951,8 +923,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// __m128i _mm_insert_epi8(__m128i X, int I, const int N);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPINSRB / PINSRB </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPINSRB / PINSRB </c> instruction.
///
/// \param X
/// A 128-bit integer vector of [16 x i8]. This vector is copied to the
@@ -997,8 +968,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// __m128i _mm_insert_epi32(__m128i X, int I, const int N);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPINSRD / PINSRD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPINSRD / PINSRD </c> instruction.
///
/// \param X
/// A 128-bit integer vector of [4 x i32]. This vector is copied to the
@@ -1009,7 +979,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// 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.
+/// which the integer \a I is written. \n
/// 00: Bits [31:0] of the result are used for insertion. \n
/// 01: Bits [63:32] of the result are used for insertion. \n
/// 10: Bits [95:64] of the result are used for insertion. \n
@@ -1019,11 +989,12 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
({ __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.
+/// insertion location selector.
///
/// \headerfile <x86intrin.h>
///
@@ -1031,9 +1002,8 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// __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.
-///
+/// This intrinsic corresponds to the <c> VPINSRQ / PINSRQ </c> instruction.
+///
/// \param X
/// A 128-bit integer vector of [2 x i64]. This vector is copied to the
/// result and then one of the two elements in the result vector is replaced
@@ -1043,7 +1013,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// 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.
+/// which the integer \a I is written. \n
/// 0: Bits [63:0] of the result are used for insertion. \n
/// 1: Bits [127:64] of the result are used for insertion. \n
/// \returns A 128-bit integer vector containing the constructed values.
@@ -1065,14 +1035,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// int _mm_extract_epi8(__m128i X, const int N);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPEXTRB / PEXTRB </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPEXTRB / PEXTRB </c> instruction.
///
/// \param X
/// A 128-bit integer vector.
/// \param N
-/// An immediate value. Bits [3:0] specify which 8-bit vector element
-/// from the argument \a X to extract and copy to the result. \n
+/// 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
@@ -1105,14 +1074,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// int _mm_extract_epi32(__m128i X, const int N);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPEXTRD / PEXTRD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPEXTRD / PEXTRD </c> instruction.
///
/// \param X
/// A 128-bit integer vector.
/// \param N
-/// An immediate value. Bits [1:0] specify which 32-bit vector element
-/// from the argument \a X to extract and copy to the result. \n
+/// 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
@@ -1122,6 +1090,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
#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.
@@ -1132,14 +1101,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/// long long _mm_extract_epi64(__m128i X, const int N);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPEXTRQ / PEXTRQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPEXTRQ / PEXTRQ </c> instruction.
///
/// \param X
/// A 128-bit integer vector.
/// \param N
-/// An immediate value. Bit [0] specifies which 64-bit vector element
-/// from the argument \a X to return. \n
+/// 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.
@@ -1154,8 +1122,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
///
/// \param __M
/// A 128-bit integer vector containing the bits to be tested.
@@ -1173,8 +1140,7 @@ _mm_testz_si128(__m128i __M, __m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
///
/// \param __M
/// A 128-bit integer vector containing the bits to be tested.
@@ -1192,8 +1158,7 @@ _mm_testc_si128(__m128i __M, __m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
///
/// \param __M
/// A 128-bit integer vector containing the bits to be tested.
@@ -1216,8 +1181,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
/// int _mm_test_all_ones(__m128i V);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
///
/// \param V
/// A 128-bit integer vector containing the bits to be tested.
@@ -1234,8 +1198,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
/// int _mm_test_mix_ones_zeros(__m128i M, __m128i V);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
///
/// \param M
/// A 128-bit integer vector containing the bits to be tested.
@@ -1254,8 +1217,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
/// int _mm_test_all_zeros(__m128i M, __m128i V);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPTEST / PTEST </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
///
/// \param M
/// A 128-bit integer vector containing the bits to be tested.
@@ -1270,8 +1232,7 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPCMPEQQ / PCMPEQQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPCMPEQQ / PCMPEQQ </c> instruction.
///
/// \param __V1
/// A 128-bit integer vector.
@@ -1292,8 +1253,7 @@ _mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVSXBW / PMOVSXBW </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVSXBW / PMOVSXBW </c> instruction.
///
/// \param __V
/// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are sign-
@@ -1314,8 +1274,7 @@ _mm_cvtepi8_epi16(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVSXBD / PMOVSXBD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVSXBD / PMOVSXBD </c> instruction.
///
/// \param __V
/// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are sign-
@@ -1336,8 +1295,7 @@ _mm_cvtepi8_epi32(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVSXBQ / PMOVSXBQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVSXBQ / PMOVSXBQ </c> instruction.
///
/// \param __V
/// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are sign-
@@ -1358,8 +1316,7 @@ _mm_cvtepi8_epi64(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVSXWD / PMOVSXWD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVSXWD / PMOVSXWD </c> instruction.
///
/// \param __V
/// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are sign-
@@ -1378,8 +1335,7 @@ _mm_cvtepi16_epi32(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVSXWQ / PMOVSXWQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVSXWQ / PMOVSXWQ </c> instruction.
///
/// \param __V
/// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are sign-
@@ -1398,8 +1354,7 @@ _mm_cvtepi16_epi64(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVSXDQ / PMOVSXDQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVSXDQ / PMOVSXDQ </c> instruction.
///
/// \param __V
/// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are sign-
@@ -1419,8 +1374,7 @@ _mm_cvtepi32_epi64(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVZXBW / PMOVZXBW </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVZXBW / PMOVZXBW </c> instruction.
///
/// \param __V
/// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are zero-
@@ -1439,8 +1393,7 @@ _mm_cvtepu8_epi16(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVZXBD / PMOVZXBD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVZXBD / PMOVZXBD </c> instruction.
///
/// \param __V
/// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are zero-
@@ -1459,8 +1412,7 @@ _mm_cvtepu8_epi32(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVZXBQ / PMOVZXBQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVZXBQ / PMOVZXBQ </c> instruction.
///
/// \param __V
/// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are zero-
@@ -1479,8 +1431,7 @@ _mm_cvtepu8_epi64(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVZXWD / PMOVZXWD </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVZXWD / PMOVZXWD </c> instruction.
///
/// \param __V
/// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are zero-
@@ -1499,8 +1450,7 @@ _mm_cvtepu16_epi32(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVZXWQ / PMOVZXWQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVZXWQ / PMOVZXWQ </c> instruction.
///
/// \param __V
/// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are zero-
@@ -1519,8 +1469,7 @@ _mm_cvtepu16_epi64(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPMOVZXDQ / PMOVZXDQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPMOVZXDQ / PMOVZXDQ </c> instruction.
///
/// \param __V
/// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are zero-
@@ -1535,13 +1484,12 @@ _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
+/// 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.
+/// This intrinsic corresponds to the <c> VPACKUSDW / PACKUSDW </c> instruction.
///
/// \param __V1
/// A 128-bit vector of [4 x i32]. Each 32-bit element is treated as a
@@ -1574,8 +1522,7 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
/// __m128i _mm_mpsadbw_epu8(__m128i X, __m128i Y, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VMPSADBW / MPSADBW </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VMPSADBW / MPSADBW </c> instruction.
///
/// \param X
/// A 128-bit vector of [16 x i8].
@@ -1608,7 +1555,7 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPHMINPOSUW / PHMINPOSUW </i> </c>
+/// This intrinsic corresponds to the <c> VPHMINPOSUW / PHMINPOSUW </c>
/// instruction.
///
/// \param __V
@@ -1668,7 +1615,7 @@ _mm_minpos_epu16(__m128i __V)
/// __m128i _mm_cmpistrm(__m128i A, __m128i B, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPCMPISTRM / PCMPISTRM </i> </c>
+/// This intrinsic corresponds to the <c> VPCMPISTRM / PCMPISTRM </c>
/// instruction.
///
/// \param A
@@ -1724,7 +1671,7 @@ _mm_minpos_epu16(__m128i __V)
/// int _mm_cmpistri(__m128i A, __m128i B, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
/// instruction.
///
/// \param A
@@ -1738,7 +1685,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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
+/// 00: 16 unsigned bytes \n
/// 01: 8 unsigned words \n
/// 10: 16 signed bytes \n
/// 11: 8 signed words \n
@@ -1778,7 +1725,7 @@ _mm_minpos_epu16(__m128i __V)
/// __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>
+/// This intrinsic corresponds to the <c> VPCMPESTRM / PCMPESTRM </c>
/// instruction.
///
/// \param A
@@ -1839,7 +1786,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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>
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
/// instruction.
///
/// \param A
@@ -1899,7 +1846,7 @@ _mm_minpos_epu16(__m128i __V)
/// int _mm_cmpistra(__m128i A, __m128i B, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
/// instruction.
///
/// \param A
@@ -1949,7 +1896,7 @@ _mm_minpos_epu16(__m128i __V)
/// int _mm_cmpistrc(__m128i A, __m128i B, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
/// instruction.
///
/// \param A
@@ -1997,7 +1944,7 @@ _mm_minpos_epu16(__m128i __V)
/// int _mm_cmpistro(__m128i A, __m128i B, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
/// instruction.
///
/// \param A
@@ -2046,7 +1993,7 @@ _mm_minpos_epu16(__m128i __V)
/// int _mm_cmpistrs(__m128i A, __m128i B, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
/// instruction.
///
/// \param A
@@ -2096,7 +2043,7 @@ _mm_minpos_epu16(__m128i __V)
/// int _mm_cmpistrz(__m128i A, __m128i B, const int M);
/// \endcode
///
-/// This intrinsic corresponds to the <c> <i> VPCMPISTRI / PCMPISTRI </i> </c>
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
/// instruction.
///
/// \param A
@@ -2146,7 +2093,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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>
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
/// instruction.
///
/// \param A
@@ -2176,7 +2123,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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
+/// 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
@@ -2201,7 +2148,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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>
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
/// instruction.
///
/// \param A
@@ -2243,6 +2190,7 @@ _mm_minpos_epu16(__m128i __V)
(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.
@@ -2253,7 +2201,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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>
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
/// instruction.
///
/// \param A
@@ -2307,7 +2255,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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>
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
/// instruction.
///
/// \param A
@@ -2362,7 +2310,7 @@ _mm_minpos_epu16(__m128i __V)
/// 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.
+/// This intrinsic corresponds to the <c> VPCMPESTRI </c> instruction.
///
/// \param A
/// A 128-bit integer vector containing one of the source operands to be
@@ -2412,8 +2360,7 @@ _mm_minpos_epu16(__m128i __V)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> VPCMPGTQ / PCMPGTQ </i> </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> VPCMPGTQ / PCMPGTQ </c> instruction.
///
/// \param __V1
/// A 128-bit integer vector.
@@ -2432,7 +2379,7 @@ _mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> CRC32B </i> </c> instruction.
+/// This intrinsic corresponds to the <c> CRC32B </c> instruction.
///
/// \param __C
/// An unsigned integer operand to add to the CRC-32C checksum of operand
@@ -2452,7 +2399,7 @@ _mm_crc32_u8(unsigned int __C, unsigned char __D)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> CRC32W </i> </c> instruction.
+/// This intrinsic corresponds to the <c> CRC32W </c> instruction.
///
/// \param __C
/// An unsigned integer operand to add to the CRC-32C checksum of operand
@@ -2472,7 +2419,7 @@ _mm_crc32_u16(unsigned int __C, unsigned short __D)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> CRC32L </i> </c> instruction.
+/// This intrinsic corresponds to the <c> CRC32L </c> instruction.
///
/// \param __C
/// An unsigned integer operand to add to the CRC-32C checksum of operand
@@ -2493,7 +2440,7 @@ _mm_crc32_u32(unsigned int __C, unsigned int __D)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> <i> CRC32Q </i> </c> instruction.
+/// This intrinsic corresponds to the <c> CRC32Q </c> instruction.
///
/// \param __C
/// An unsigned integer operand to add to the CRC-32C checksum of operand
diff --git a/lib/Headers/stdatomic.h b/lib/Headers/stdatomic.h
index 23bb3a3577..b4845a74e4 100644
--- a/lib/Headers/stdatomic.h
+++ b/lib/Headers/stdatomic.h
@@ -40,16 +40,16 @@ extern "C" {
/* 7.17.1 Introduction */
-#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
-#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
-#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
-#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
-#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
-#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
-#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
-#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
-#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
-#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
+#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
+#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
+#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE
+#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE
+#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE
+#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
+#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
+#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
+#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
+#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
/* 7.17.2 Initialization */
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
index 3f2fcbc570..c48815314b 100644
--- a/lib/Headers/stdint.h
+++ b/lib/Headers/stdint.h
@@ -255,19 +255,16 @@ typedef __uint_least8_t uint_fast8_t;
*/
#define __stdint_join3(a,b,c) a ## b ## c
-#define __intn_t(n) __stdint_join3( int, n, _t)
-#define __uintn_t(n) __stdint_join3(uint, n, _t)
-
#ifndef _INTPTR_T
#ifndef __intptr_t_defined
-typedef __intn_t(__INTPTR_WIDTH__) intptr_t;
+typedef __INTPTR_TYPE__ intptr_t;
#define __intptr_t_defined
#define _INTPTR_T
#endif
#endif
#ifndef _UINTPTR_T
-typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
#define _UINTPTR_T
#endif
@@ -659,12 +656,12 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */
/* C99 7.18.3 Limits of other integer types. */
-#define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__)
-#define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__)
-#define UINTPTR_MAX __UINTN_MAX(__INTPTR_WIDTH__)
-#define PTRDIFF_MIN __INTN_MIN(__PTRDIFF_WIDTH__)
-#define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__)
-#define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__)
+#define INTPTR_MIN (-__INTPTR_MAX__-1)
+#define INTPTR_MAX __INTPTR_MAX__
+#define UINTPTR_MAX __UINTPTR_MAX__
+#define PTRDIFF_MIN (-__PTRDIFF_MAX__-1)
+#define PTRDIFF_MAX __PTRDIFF_MAX__
+#define SIZE_MAX __SIZE_MAX__
/* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__
* is enabled. */
@@ -673,9 +670,9 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#endif
/* C99 7.18.2.5 Limits of greatest-width integer types. */
-#define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__)
-#define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__)
-#define UINTMAX_MAX __UINTN_MAX(__INTMAX_WIDTH__)
+#define INTMAX_MIN (-__INTMAX_MAX__-1)
+#define INTMAX_MAX __INTMAX_MAX__
+#define UINTMAX_MAX __UINTMAX_MAX__
/* C99 7.18.3 Limits of other integer types. */
#define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__)
@@ -700,8 +697,8 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#endif
/* 7.18.4.2 Macros for greatest-width integer constants. */
-#define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v)
-#define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v)
+#define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__)
+#define UINTMAX_C(v) __int_c(v, __UINTMAX_C_SUFFIX__)
#endif /* __STDC_HOSTED__ */
#endif /* __CLANG_STDINT_H */
diff --git a/lib/Headers/tgmath.h b/lib/Headers/tgmath.h
index 318e1185fe..34e26dcc05 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/tmmintrin.h b/lib/Headers/tmmintrin.h
index 80664043a0..042bfc7e3b 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -469,10 +469,11 @@ _mm_hsubs_pi16(__m64 __a, __m64 __b)
/// values contained in the first source operand and packed 8-bit signed
/// integer values contained in the second source operand, adds pairs of
/// contiguous products with signed saturation, and writes the 16-bit sums to
-/// the corresponding bits in the destination. For example, bits [7:0] of
-/// both operands are multiplied, bits [15:8] of both operands are
-/// multiplied, and the sum of both results is written to bits [15:0] of the
-/// destination.
+/// the corresponding bits in the destination.
+///
+/// For example, bits [7:0] of both operands are multiplied, bits [15:8] of
+/// both operands are multiplied, and the sum of both results is written to
+/// bits [15:0] of the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -502,10 +503,11 @@ _mm_maddubs_epi16(__m128i __a, __m128i __b)
/// values contained in the first source operand and packed 8-bit signed
/// integer values contained in the second source operand, adds pairs of
/// contiguous products with signed saturation, and writes the 16-bit sums to
-/// the corresponding bits in the destination. For example, bits [7:0] of
-/// both operands are multiplied, bits [15:8] of both operands are
-/// multiplied, and the sum of both results is written to bits [15:0] of the
-/// destination.
+/// the corresponding bits in the destination.
+///
+/// For example, bits [7:0] of both operands are multiplied, bits [15:8] of
+/// both operands are multiplied, and the sum of both results is written to
+/// bits [15:0] of the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -619,13 +621,14 @@ _mm_shuffle_pi8(__m64 __a, __m64 __b)
}
/// \brief For each 8-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// byte in the second source is negative, calculate the two's complement of
-/// the corresponding byte in the first source, and write that value to the
-/// destination. If the byte in the second source is positive, copy the
-/// corresponding byte from the first source to the destination. If the byte
-/// in the second source is zero, clear the corresponding byte in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the byte in the second source is negative, calculate the two's
+/// complement of the corresponding byte in the first source, and write that
+/// value to the destination. If the byte in the second source is positive,
+/// copy the corresponding byte from the first source to the destination. If
+/// the byte in the second source is zero, clear the corresponding byte in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -644,13 +647,14 @@ _mm_sign_epi8(__m128i __a, __m128i __b)
}
/// \brief For each 16-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// word in the second source is negative, calculate the two's complement of
-/// the corresponding word in the first source, and write that value to the
-/// destination. If the word in the second source is positive, copy the
-/// corresponding word from the first source to the destination. If the word
-/// in the second source is zero, clear the corresponding word in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the word in the second source is negative, calculate the two's
+/// complement of the corresponding word in the first source, and write that
+/// value to the destination. If the word in the second source is positive,
+/// copy the corresponding word from the first source to the destination. If
+/// the word in the second source is zero, clear the corresponding word in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -669,8 +673,9 @@ _mm_sign_epi16(__m128i __a, __m128i __b)
}
/// \brief For each 32-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// doubleword in the second source is negative, calculate the two's
+/// the following actions as specified by the second source operand.
+///
+/// If the doubleword in the second source is negative, calculate the two's
/// complement of the corresponding word in the first source, and write that
/// value to the destination. If the doubleword in the second source is
/// positive, copy the corresponding word from the first source to the
@@ -694,13 +699,14 @@ _mm_sign_epi32(__m128i __a, __m128i __b)
}
/// \brief For each 8-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// byte in the second source is negative, calculate the two's complement of
-/// the corresponding byte in the first source, and write that value to the
-/// destination. If the byte in the second source is positive, copy the
-/// corresponding byte from the first source to the destination. If the byte
-/// in the second source is zero, clear the corresponding byte in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the byte in the second source is negative, calculate the two's
+/// complement of the corresponding byte in the first source, and write that
+/// value to the destination. If the byte in the second source is positive,
+/// copy the corresponding byte from the first source to the destination. If
+/// the byte in the second source is zero, clear the corresponding byte in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -719,13 +725,14 @@ _mm_sign_pi8(__m64 __a, __m64 __b)
}
/// \brief For each 16-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// word in the second source is negative, calculate the two's complement of
-/// the corresponding word in the first source, and write that value to the
-/// destination. If the word in the second source is positive, copy the
-/// corresponding word from the first source to the destination. If the word
-/// in the second source is zero, clear the corresponding word in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the word in the second source is negative, calculate the two's
+/// complement of the corresponding word in the first source, and write that
+/// value to the destination. If the word in the second source is positive,
+/// copy the corresponding word from the first source to the destination. If
+/// the word in the second source is zero, clear the corresponding word in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -744,8 +751,9 @@ _mm_sign_pi16(__m64 __a, __m64 __b)
}
/// \brief For each 32-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// doubleword in the second source is negative, calculate the two's
+/// the following actions as specified by the second source operand.
+///
+/// If the doubleword in the second source is negative, calculate the two's
/// complement of the corresponding doubleword in the first source, and
/// write that value to the destination. If the doubleword in the second
/// source is positive, copy the corresponding doubleword from the first
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
index 4f74a34787..345fa4d0c1 100644
--- a/lib/Headers/unwind.h
+++ b/lib/Headers/unwind.h
@@ -76,7 +76,13 @@ typedef intptr_t _sleb128_t;
typedef uintptr_t _uleb128_t;
struct _Unwind_Context;
+#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__))
+struct _Unwind_Control_Block;
+typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
+#else
struct _Unwind_Exception;
+typedef struct _Unwind_Exception _Unwind_Exception;
+#endif
typedef enum {
_URC_NO_REASON = 0,
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
@@ -109,8 +115,42 @@ typedef enum {
} _Unwind_Action;
typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code,
- struct _Unwind_Exception *);
-
+ _Unwind_Exception *);
+
+#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__))
+typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+typedef uint32_t _Unwind_EHT_Header;
+
+struct _Unwind_Control_Block {
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *);
+ /* unwinder cache (private fields for the unwinder's use) */
+ struct {
+ uint32_t reserved1; /* forced unwind stop function, 0 if not forced */
+ uint32_t reserved2; /* personality routine */
+ uint32_t reserved3; /* callsite */
+ uint32_t reserved4; /* forced unwind stop argument */
+ uint32_t reserved5;
+ } unwinder_cache;
+ /* propagation barrier cache (valid after phase 1) */
+ struct {
+ uint32_t sp;
+ uint32_t bitpattern[5];
+ } barrier_cache;
+ /* cleanup cache (preserved over cleanup) */
+ struct {
+ uint32_t bitpattern[4];
+ } cleanup_cache;
+ /* personality cache (for personality's benefit) */
+ struct {
+ uint32_t fnstart; /* function start address */
+ _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */
+ uint32_t additional; /* additional data */
+ uint32_t reserved1;
+ } pr_cache;
+ long long int : 0; /* force alignment of next item to 8-byte boundary */
+} __attribute__((__aligned__(8)));
+#else
struct _Unwind_Exception {
_Unwind_Exception_Class exception_class;
_Unwind_Exception_Cleanup_Fn exception_cleanup;
@@ -120,23 +160,24 @@ struct _Unwind_Exception {
* aligned". GCC has interpreted this to mean "use the maximum useful
* alignment for the target"; so do we. */
} __attribute__((__aligned__));
+#endif
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(int, _Unwind_Action,
_Unwind_Exception_Class,
- struct _Unwind_Exception *,
+ _Unwind_Exception *,
struct _Unwind_Context *,
void *);
-typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(
- int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
- struct _Unwind_Context *);
+typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(int, _Unwind_Action,
+ _Unwind_Exception_Class,
+ _Unwind_Exception *,
+ struct _Unwind_Context *);
typedef _Unwind_Personality_Fn __personality_routine;
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
void *);
-#if defined(__arm__) && !defined(__APPLE__)
-
+#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || defined(__ARM_DWARF_EH__))
typedef enum {
_UVRSC_CORE = 0, /* integer register */
_UVRSC_VFP = 1, /* vfp */
@@ -158,14 +199,12 @@ typedef enum {
_UVRSR_FAILED = 2
} _Unwind_VRS_Result;
-#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__ARM_DWARF_EH__)
typedef uint32_t _Unwind_State;
#define _US_VIRTUAL_UNWIND_FRAME ((_Unwind_State)0)
#define _US_UNWIND_FRAME_STARTING ((_Unwind_State)1)
#define _US_UNWIND_FRAME_RESUME ((_Unwind_State)2)
#define _US_ACTION_MASK ((_Unwind_State)3)
#define _US_FORCE_UNWIND ((_Unwind_State)8)
-#endif
_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *__context,
_Unwind_VRS_RegClass __regclass,
@@ -224,13 +263,12 @@ _Unwind_Ptr _Unwind_GetRegionStart(struct _Unwind_Context *);
/* DWARF EH functions; currently not available on Darwin/ARM */
#if !defined(__APPLE__) || !defined(__arm__)
-
-_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *);
-_Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *,
- _Unwind_Stop_Fn, void *);
-void _Unwind_DeleteException(struct _Unwind_Exception *);
-void _Unwind_Resume(struct _Unwind_Exception *);
-_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *);
+_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception *);
+_Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *, _Unwind_Stop_Fn,
+ void *);
+void _Unwind_DeleteException(_Unwind_Exception *);
+void _Unwind_Resume(_Unwind_Exception *);
+_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Exception *);
#endif
@@ -241,11 +279,11 @@ typedef struct SjLj_Function_Context *_Unwind_FunctionContext_t;
void _Unwind_SjLj_Register(_Unwind_FunctionContext_t);
void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t);
-_Unwind_Reason_Code _Unwind_SjLj_RaiseException(struct _Unwind_Exception *);
-_Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *,
+_Unwind_Reason_Code _Unwind_SjLj_RaiseException(_Unwind_Exception *);
+_Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *,
_Unwind_Stop_Fn, void *);
-void _Unwind_SjLj_Resume(struct _Unwind_Exception *);
-_Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *);
+void _Unwind_SjLj_Resume(_Unwind_Exception *);
+_Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *);
void *_Unwind_FindEnclosingFunction(void *);
diff --git a/lib/Headers/vecintrin.h b/lib/Headers/vecintrin.h
index ca7acb4731..f7061e8894 100644
--- a/lib/Headers/vecintrin.h
+++ b/lib/Headers/vecintrin.h
@@ -116,6 +116,13 @@ vec_extract(vector unsigned long long __vec, int __index) {
return __vec[__index & 1];
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai float
+vec_extract(vector float __vec, int __index) {
+ return __vec[__index & 3];
+}
+#endif
+
static inline __ATTRS_o_ai double
vec_extract(vector double __vec, int __index) {
return __vec[__index & 1];
@@ -129,6 +136,7 @@ vec_insert(signed char __scalar, vector signed char __vec, int __index) {
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_insert(unsigned char __scalar, vector bool char __vec, int __index) {
vector unsigned char __newvec = (vector unsigned char)__vec;
@@ -148,6 +156,7 @@ vec_insert(signed short __scalar, vector signed short __vec, int __index) {
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_insert(unsigned short __scalar, vector bool short __vec, int __index) {
vector unsigned short __newvec = (vector unsigned short)__vec;
@@ -167,6 +176,7 @@ vec_insert(signed int __scalar, vector signed int __vec, int __index) {
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_insert(unsigned int __scalar, vector bool int __vec, int __index) {
vector unsigned int __newvec = (vector unsigned int)__vec;
@@ -187,6 +197,7 @@ vec_insert(signed long long __scalar, vector signed long long __vec,
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_insert(unsigned long long __scalar, vector bool long long __vec,
int __index) {
@@ -202,6 +213,14 @@ vec_insert(unsigned long long __scalar, vector unsigned long long __vec,
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_insert(float __scalar, vector float __vec, int __index) {
+ __vec[__index & 1] = __scalar;
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_insert(double __scalar, vector double __vec, int __index) {
__vec[__index & 1] = __scalar;
@@ -282,6 +301,16 @@ vec_promote(unsigned long long __scalar, int __index) {
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_promote(float __scalar, int __index) {
+ const vector float __zero = (vector float)0;
+ vector float __vec = __builtin_shufflevector(__zero, __zero, -1, -1, -1, -1);
+ __vec[__index & 3] = __scalar;
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_promote(double __scalar, int __index) {
const vector double __zero = (vector double)0;
@@ -348,6 +377,15 @@ vec_insert_and_zero(const unsigned long long *__ptr) {
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_insert_and_zero(const float *__ptr) {
+ vector float __vec = (vector float)0;
+ __vec[0] = *__ptr;
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_insert_and_zero(const double *__ptr) {
vector double __vec = (vector double)0;
@@ -441,6 +479,15 @@ vec_perm(vector bool long long __a, vector bool long long __b,
(vector unsigned char)__a, (vector unsigned char)__b, __c);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_perm(vector float __a, vector float __b,
+ vector unsigned char __c) {
+ return (vector float)__builtin_s390_vperm(
+ (vector unsigned char)__a, (vector unsigned char)__b, __c);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_perm(vector double __a, vector double __b,
vector unsigned char __c) {
@@ -450,18 +497,22 @@ vec_perm(vector double __a, vector double __b,
/*-- vec_permi --------------------------------------------------------------*/
+// This prototype is deprecated.
extern __ATTRS_o vector signed long long
vec_permi(vector signed long long __a, vector signed long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector unsigned long long
vec_permi(vector unsigned long long __a, vector unsigned long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector bool long long
vec_permi(vector bool long long __a, vector bool long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector double
vec_permi(vector double __a, vector double __b, int __c)
__constant_range(__c, 0, 3);
@@ -471,6 +522,15 @@ vec_permi(vector double __a, vector double __b, int __c)
(vector unsigned long long)(Y), \
(((Z) & 2) << 1) | ((Z) & 1)))
+/*-- vec_bperm_u128 ---------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai vector unsigned long long
+vec_bperm_u128(vector unsigned char __a, vector unsigned char __b) {
+ return __builtin_s390_vbperm(__a, __b);
+}
+#endif
+
/*-- vec_sel ----------------------------------------------------------------*/
static inline __ATTRS_o_ai vector signed char
@@ -614,6 +674,22 @@ vec_sel(vector unsigned long long __a, vector unsigned long long __b,
(~(vector unsigned long long)__c & __a));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_sel(vector float __a, vector float __b, vector unsigned int __c) {
+ return (vector float)((__c & (vector unsigned int)__b) |
+ (~__c & (vector unsigned int)__a));
+}
+
+static inline __ATTRS_o_ai vector float
+vec_sel(vector float __a, vector float __b, vector bool int __c) {
+ vector unsigned int __ac = (vector unsigned int)__a;
+ vector unsigned int __bc = (vector unsigned int)__b;
+ vector unsigned int __cc = (vector unsigned int)__c;
+ return (vector float)((__cc & __bc) | (~__cc & __ac));
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_sel(vector double __a, vector double __b, vector unsigned long long __c) {
return (vector double)((__c & (vector unsigned long long)__b) |
@@ -687,6 +763,17 @@ vec_gather_element(vector unsigned long long __vec,
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_gather_element(vector float __vec, vector unsigned int __offset,
+ const float *__ptr, int __index)
+ __constant_range(__index, 0, 3) {
+ __vec[__index] = *(const float *)(
+ (__INTPTR_TYPE__)__ptr + (__INTPTR_TYPE__)__offset[__index]);
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_gather_element(vector double __vec, vector unsigned long long __offset,
const double *__ptr, int __index)
@@ -749,6 +836,16 @@ vec_scatter_element(vector unsigned long long __vec,
__vec[__index];
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai void
+vec_scatter_element(vector float __vec, vector unsigned int __offset,
+ float *__ptr, int __index)
+ __constant_range(__index, 0, 3) {
+ *(float *)((__INTPTR_TYPE__)__ptr + __offset[__index]) =
+ __vec[__index];
+}
+#endif
+
static inline __ATTRS_o_ai void
vec_scatter_element(vector double __vec, vector unsigned long long __offset,
double *__ptr, int __index)
@@ -757,48 +854,111 @@ vec_scatter_element(vector double __vec, vector unsigned long long __offset,
__vec[__index];
}
+/*-- vec_xl -----------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector signed char
+vec_xl(long __offset, const signed char *__ptr) {
+ return *(const vector signed char *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_xl(long __offset, const unsigned char *__ptr) {
+ return *(const vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_xl(long __offset, const signed short *__ptr) {
+ return *(const vector signed short *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_xl(long __offset, const unsigned short *__ptr) {
+ return *(const vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_xl(long __offset, const signed int *__ptr) {
+ return *(const vector signed int *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_xl(long __offset, const unsigned int *__ptr) {
+ return *(const vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_xl(long __offset, const signed long long *__ptr) {
+ return *(const vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_xl(long __offset, const unsigned long long *__ptr) {
+ return *(const vector unsigned long long *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_xl(long __offset, const float *__ptr) {
+ return *(const vector float *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
+vec_xl(long __offset, const double *__ptr) {
+ return *(const vector double *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
/*-- vec_xld2 ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_xld2(long __offset, const signed char *__ptr) {
return *(const vector signed char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_xld2(long __offset, const unsigned char *__ptr) {
return *(const vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_xld2(long __offset, const signed short *__ptr) {
return *(const vector signed short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_xld2(long __offset, const unsigned short *__ptr) {
return *(const vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_xld2(long __offset, const signed int *__ptr) {
return *(const vector signed int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_xld2(long __offset, const unsigned int *__ptr) {
return *(const vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_xld2(long __offset, const signed long long *__ptr) {
return *(const vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_xld2(long __offset, const unsigned long long *__ptr) {
return *(const vector unsigned long long *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_xld2(long __offset, const double *__ptr) {
return *(const vector double *)((__INTPTR_TYPE__)__ptr + __offset);
@@ -806,74 +966,145 @@ vec_xld2(long __offset, const double *__ptr) {
/*-- vec_xlw4 ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_xlw4(long __offset, const signed char *__ptr) {
return *(const vector signed char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_xlw4(long __offset, const unsigned char *__ptr) {
return *(const vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_xlw4(long __offset, const signed short *__ptr) {
return *(const vector signed short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_xlw4(long __offset, const unsigned short *__ptr) {
return *(const vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_xlw4(long __offset, const signed int *__ptr) {
return *(const vector signed int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_xlw4(long __offset, const unsigned int *__ptr) {
return *(const vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+/*-- vec_xst ----------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed char __vec, long __offset, signed char *__ptr) {
+ *(vector signed char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned char __vec, long __offset, unsigned char *__ptr) {
+ *(vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed short __vec, long __offset, signed short *__ptr) {
+ *(vector signed short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned short __vec, long __offset, unsigned short *__ptr) {
+ *(vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed int __vec, long __offset, signed int *__ptr) {
+ *(vector signed int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned int __vec, long __offset, unsigned int *__ptr) {
+ *(vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed long long __vec, long __offset,
+ signed long long *__ptr) {
+ *(vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned long long __vec, long __offset,
+ unsigned long long *__ptr) {
+ *(vector unsigned long long *)((__INTPTR_TYPE__)__ptr + __offset) =
+ __vec;
+}
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai void
+vec_xst(vector float __vec, long __offset, float *__ptr) {
+ *(vector float *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+#endif
+
+static inline __ATTRS_o_ai void
+vec_xst(vector double __vec, long __offset, double *__ptr) {
+ *(vector double *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
/*-- vec_xstd2 --------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed char __vec, long __offset, signed char *__ptr) {
*(vector signed char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned char __vec, long __offset, unsigned char *__ptr) {
*(vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed short __vec, long __offset, signed short *__ptr) {
*(vector signed short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned short __vec, long __offset, unsigned short *__ptr) {
*(vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed int __vec, long __offset, signed int *__ptr) {
*(vector signed int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned int __vec, long __offset, unsigned int *__ptr) {
*(vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed long long __vec, long __offset,
signed long long *__ptr) {
*(vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned long long __vec, long __offset,
unsigned long long *__ptr) {
@@ -881,6 +1112,7 @@ vec_xstd2(vector unsigned long long __vec, long __offset,
__vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector double __vec, long __offset, double *__ptr) {
*(vector double *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
@@ -888,31 +1120,37 @@ vec_xstd2(vector double __vec, long __offset, double *__ptr) {
/*-- vec_xstw4 --------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector signed char __vec, long __offset, signed char *__ptr) {
*(vector signed char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector unsigned char __vec, long __offset, unsigned char *__ptr) {
*(vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector signed short __vec, long __offset, signed short *__ptr) {
*(vector signed short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector unsigned short __vec, long __offset, unsigned short *__ptr) {
*(vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector signed int __vec, long __offset, signed int *__ptr) {
*(vector signed int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector unsigned int __vec, long __offset, unsigned int *__ptr) {
*(vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
@@ -952,6 +1190,12 @@ extern __ATTRS_o vector unsigned long long
vec_load_bndry(const unsigned long long *__ptr, unsigned short __len)
__constant_pow2_range(__len, 64, 4096);
+#if __ARCH__ >= 12
+extern __ATTRS_o vector float
+vec_load_bndry(const float *__ptr, unsigned short __len)
+ __constant_pow2_range(__len, 64, 4096);
+#endif
+
extern __ATTRS_o vector double
vec_load_bndry(const double *__ptr, unsigned short __len)
__constant_pow2_range(__len, 64, 4096);
@@ -1007,11 +1251,27 @@ vec_load_len(const unsigned long long *__ptr, unsigned int __len) {
return (vector unsigned long long)__builtin_s390_vll(__len, __ptr);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_load_len(const float *__ptr, unsigned int __len) {
+ return (vector float)__builtin_s390_vll(__len, __ptr);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_load_len(const double *__ptr, unsigned int __len) {
return (vector double)__builtin_s390_vll(__len, __ptr);
}
+/*-- vec_load_len_r ---------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai vector unsigned char
+vec_load_len_r(const unsigned char *__ptr, unsigned int __len) {
+ return (vector unsigned char)__builtin_s390_vlrl(__len, __ptr);
+}
+#endif
+
/*-- vec_store_len ----------------------------------------------------------*/
static inline __ATTRS_o_ai void
@@ -1062,12 +1322,30 @@ vec_store_len(vector unsigned long long __vec, unsigned long long *__ptr,
__builtin_s390_vstl((vector signed char)__vec, __len, __ptr);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai void
+vec_store_len(vector float __vec, float *__ptr,
+ unsigned int __len) {
+ __builtin_s390_vstl((vector signed char)__vec, __len, __ptr);
+}
+#endif
+
static inline __ATTRS_o_ai void
vec_store_len(vector double __vec, double *__ptr,
unsigned int __len) {
__builtin_s390_vstl((vector signed char)__vec, __len, __ptr);
}
+/*-- vec_store_len_r --------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai void
+vec_store_len_r(vector unsigned char __vec, unsigned char *__ptr,
+ unsigned int __len) {
+ __builtin_s390_vstrl((vector signed char)__vec, __len, __ptr);
+}
+#endif
+
/*-- vec_load_pair ----------------------------------------------------------*/
static inline __ATTRS_o_ai vector signed long long
@@ -1232,6 +1510,14 @@ vec_splat(vector unsigned long long __vec, int __index)
return (vector unsigned long long)__vec[__index];
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_splat(vector float __vec, int __index)
+ __constant_range(__index, 0, 3) {
+ return (vector float)__vec[__index];
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_splat(vector double __vec, int __index)
__constant_range(__index, 0, 1) {
@@ -1332,6 +1618,13 @@ vec_splats(unsigned long long __scalar) {
return (vector unsigned long long)__scalar;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_splats(float __scalar) {
+ return (vector float)__scalar;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_splats(double __scalar) {
return (vector double)__scalar;
@@ -1425,6 +1718,13 @@ vec_mergeh(vector unsigned long long __a, vector unsigned long long __b) {
return (vector unsigned long long)(__a[0], __b[0]);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_mergeh(vector float __a, vector float __b) {
+ return (vector float)(__a[0], __b[0], __a[1], __b[1]);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_mergeh(vector double __a, vector double __b) {
return (vector double)(__a[0], __b[0]);
@@ -1501,6 +1801,13 @@ vec_mergel(vector unsigned long long __a, vector unsigned long long __b) {
return (vector unsigned long long)(__a[1], __b[1]);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_mergel(vector float __a, vector float __b) {
+ return (vector float)(__a[2], __b[2], __a[3], __b[3]);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_mergel(vector double __a, vector double __b) {
return (vector double)(__a[1], __b[1]);
@@ -1866,6 +2173,13 @@ vec_cmpeq(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a == __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmpeq(vector float __a, vector float __b) {
+ return (vector bool int)(__a == __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmpeq(vector double __a, vector double __b) {
return (vector bool long long)(__a == __b);
@@ -1913,6 +2227,13 @@ vec_cmpge(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a >= __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmpge(vector float __a, vector float __b) {
+ return (vector bool int)(__a >= __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmpge(vector double __a, vector double __b) {
return (vector bool long long)(__a >= __b);
@@ -1960,6 +2281,13 @@ vec_cmpgt(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a > __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmpgt(vector float __a, vector float __b) {
+ return (vector bool int)(__a > __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmpgt(vector double __a, vector double __b) {
return (vector bool long long)(__a > __b);
@@ -2007,6 +2335,13 @@ vec_cmple(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a <= __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmple(vector float __a, vector float __b) {
+ return (vector bool int)(__a <= __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmple(vector double __a, vector double __b) {
return (vector bool long long)(__a <= __b);
@@ -2054,6 +2389,13 @@ vec_cmplt(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a < __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmplt(vector float __a, vector float __b) {
+ return (vector bool int)(__a < __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmplt(vector double __a, vector double __b) {
return (vector bool long long)(__a < __b);
@@ -2068,6 +2410,7 @@ vec_all_eq(vector signed char __a, vector signed char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2075,6 +2418,7 @@ vec_all_eq(vector signed char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2090,6 +2434,7 @@ vec_all_eq(vector unsigned char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2098,6 +2443,7 @@ vec_all_eq(vector unsigned char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2121,6 +2467,7 @@ vec_all_eq(vector signed short __a, vector signed short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2128,6 +2475,7 @@ vec_all_eq(vector signed short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2143,6 +2491,7 @@ vec_all_eq(vector unsigned short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2151,6 +2500,7 @@ vec_all_eq(vector unsigned short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2174,6 +2524,7 @@ vec_all_eq(vector signed int __a, vector signed int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2181,6 +2532,7 @@ vec_all_eq(vector signed int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2196,6 +2548,7 @@ vec_all_eq(vector unsigned int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2204,6 +2557,7 @@ vec_all_eq(vector unsigned int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2227,6 +2581,7 @@ vec_all_eq(vector signed long long __a, vector signed long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2234,6 +2589,7 @@ vec_all_eq(vector signed long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2249,6 +2605,7 @@ vec_all_eq(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2257,6 +2614,7 @@ vec_all_eq(vector unsigned long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2273,6 +2631,15 @@ vec_all_eq(vector bool long long __a, vector bool long long __b) {
return __cc == 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_eq(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_eq(vector double __a, vector double __b) {
int __cc;
@@ -2289,6 +2656,7 @@ vec_all_ne(vector signed char __a, vector signed char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2296,6 +2664,7 @@ vec_all_ne(vector signed char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2311,6 +2680,7 @@ vec_all_ne(vector unsigned char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2319,6 +2689,7 @@ vec_all_ne(vector unsigned char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2342,6 +2713,7 @@ vec_all_ne(vector signed short __a, vector signed short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2349,6 +2721,7 @@ vec_all_ne(vector signed short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2364,6 +2737,7 @@ vec_all_ne(vector unsigned short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2372,6 +2746,7 @@ vec_all_ne(vector unsigned short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2395,6 +2770,7 @@ vec_all_ne(vector signed int __a, vector signed int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2402,6 +2778,7 @@ vec_all_ne(vector signed int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2417,6 +2794,7 @@ vec_all_ne(vector unsigned int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2425,6 +2803,7 @@ vec_all_ne(vector unsigned int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2448,6 +2827,7 @@ vec_all_ne(vector signed long long __a, vector signed long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2455,6 +2835,7 @@ vec_all_ne(vector signed long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2470,6 +2851,7 @@ vec_all_ne(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2478,6 +2860,7 @@ vec_all_ne(vector unsigned long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2494,6 +2877,15 @@ vec_all_ne(vector bool long long __a, vector bool long long __b) {
return __cc == 3;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_ne(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc == 3;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_ne(vector double __a, vector double __b) {
int __cc;
@@ -2510,6 +2902,7 @@ vec_all_ge(vector signed char __a, vector signed char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2517,6 +2910,7 @@ vec_all_ge(vector signed char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2531,6 +2925,7 @@ vec_all_ge(vector unsigned char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2538,6 +2933,7 @@ vec_all_ge(vector unsigned char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2545,6 +2941,7 @@ vec_all_ge(vector bool char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool char __a, vector bool char __b) {
int __cc;
@@ -2560,6 +2957,7 @@ vec_all_ge(vector signed short __a, vector signed short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2567,6 +2965,7 @@ vec_all_ge(vector signed short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2581,6 +2980,7 @@ vec_all_ge(vector unsigned short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2588,6 +2988,7 @@ vec_all_ge(vector unsigned short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2595,6 +2996,7 @@ vec_all_ge(vector bool short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool short __a, vector bool short __b) {
int __cc;
@@ -2610,6 +3012,7 @@ vec_all_ge(vector signed int __a, vector signed int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2617,6 +3020,7 @@ vec_all_ge(vector signed int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2631,6 +3035,7 @@ vec_all_ge(vector unsigned int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2638,6 +3043,7 @@ vec_all_ge(vector unsigned int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2645,6 +3051,7 @@ vec_all_ge(vector bool int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool int __a, vector bool int __b) {
int __cc;
@@ -2660,6 +3067,7 @@ vec_all_ge(vector signed long long __a, vector signed long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2667,6 +3075,7 @@ vec_all_ge(vector signed long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2681,6 +3090,7 @@ vec_all_ge(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2688,6 +3098,7 @@ vec_all_ge(vector unsigned long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2695,6 +3106,7 @@ vec_all_ge(vector bool long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -2703,6 +3115,15 @@ vec_all_ge(vector bool long long __a, vector bool long long __b) {
return __cc == 3;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_ge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_ge(vector double __a, vector double __b) {
int __cc;
@@ -2719,6 +3140,7 @@ vec_all_gt(vector signed char __a, vector signed char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2726,6 +3148,7 @@ vec_all_gt(vector signed char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2740,6 +3163,7 @@ vec_all_gt(vector unsigned char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2747,6 +3171,7 @@ vec_all_gt(vector unsigned char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2754,6 +3179,7 @@ vec_all_gt(vector bool char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -2769,6 +3195,7 @@ vec_all_gt(vector signed short __a, vector signed short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2776,6 +3203,7 @@ vec_all_gt(vector signed short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2790,6 +3218,7 @@ vec_all_gt(vector unsigned short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2797,6 +3226,7 @@ vec_all_gt(vector unsigned short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2804,6 +3234,7 @@ vec_all_gt(vector bool short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -2819,6 +3250,7 @@ vec_all_gt(vector signed int __a, vector signed int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2826,6 +3258,7 @@ vec_all_gt(vector signed int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2840,6 +3273,7 @@ vec_all_gt(vector unsigned int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2847,6 +3281,7 @@ vec_all_gt(vector unsigned int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2854,6 +3289,7 @@ vec_all_gt(vector bool int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -2869,6 +3305,7 @@ vec_all_gt(vector signed long long __a, vector signed long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2876,6 +3313,7 @@ vec_all_gt(vector signed long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2890,6 +3328,7 @@ vec_all_gt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2897,6 +3336,7 @@ vec_all_gt(vector unsigned long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2904,6 +3344,7 @@ vec_all_gt(vector bool long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -2912,6 +3353,15 @@ vec_all_gt(vector bool long long __a, vector bool long long __b) {
return __cc == 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_gt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_gt(vector double __a, vector double __b) {
int __cc;
@@ -2928,6 +3378,7 @@ vec_all_le(vector signed char __a, vector signed char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2935,6 +3386,7 @@ vec_all_le(vector signed char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2949,6 +3401,7 @@ vec_all_le(vector unsigned char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2956,6 +3409,7 @@ vec_all_le(vector unsigned char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2963,6 +3417,7 @@ vec_all_le(vector bool char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool char __a, vector bool char __b) {
int __cc;
@@ -2978,6 +3433,7 @@ vec_all_le(vector signed short __a, vector signed short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2985,6 +3441,7 @@ vec_all_le(vector signed short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2999,6 +3456,7 @@ vec_all_le(vector unsigned short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3006,6 +3464,7 @@ vec_all_le(vector unsigned short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3013,6 +3472,7 @@ vec_all_le(vector bool short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool short __a, vector bool short __b) {
int __cc;
@@ -3028,6 +3488,7 @@ vec_all_le(vector signed int __a, vector signed int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3035,6 +3496,7 @@ vec_all_le(vector signed int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3049,6 +3511,7 @@ vec_all_le(vector unsigned int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3056,6 +3519,7 @@ vec_all_le(vector unsigned int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3063,6 +3527,7 @@ vec_all_le(vector bool int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool int __a, vector bool int __b) {
int __cc;
@@ -3078,6 +3543,7 @@ vec_all_le(vector signed long long __a, vector signed long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3085,6 +3551,7 @@ vec_all_le(vector signed long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3099,6 +3566,7 @@ vec_all_le(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3106,6 +3574,7 @@ vec_all_le(vector unsigned long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3113,6 +3582,7 @@ vec_all_le(vector bool long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -3121,6 +3591,15 @@ vec_all_le(vector bool long long __a, vector bool long long __b) {
return __cc == 3;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_le(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_le(vector double __a, vector double __b) {
int __cc;
@@ -3137,6 +3616,7 @@ vec_all_lt(vector signed char __a, vector signed char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3144,6 +3624,7 @@ vec_all_lt(vector signed char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3158,6 +3639,7 @@ vec_all_lt(vector unsigned char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3165,6 +3647,7 @@ vec_all_lt(vector unsigned char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3172,6 +3655,7 @@ vec_all_lt(vector bool char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -3187,6 +3671,7 @@ vec_all_lt(vector signed short __a, vector signed short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3194,6 +3679,7 @@ vec_all_lt(vector signed short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3208,6 +3694,7 @@ vec_all_lt(vector unsigned short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3215,6 +3702,7 @@ vec_all_lt(vector unsigned short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3222,6 +3710,7 @@ vec_all_lt(vector bool short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -3237,6 +3726,7 @@ vec_all_lt(vector signed int __a, vector signed int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3244,6 +3734,7 @@ vec_all_lt(vector signed int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3258,6 +3749,7 @@ vec_all_lt(vector unsigned int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3265,6 +3757,7 @@ vec_all_lt(vector unsigned int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3272,6 +3765,7 @@ vec_all_lt(vector bool int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -3287,6 +3781,7 @@ vec_all_lt(vector signed long long __a, vector signed long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3294,6 +3789,7 @@ vec_all_lt(vector signed long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3308,6 +3804,7 @@ vec_all_lt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3315,6 +3812,7 @@ vec_all_lt(vector unsigned long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3322,6 +3820,7 @@ vec_all_lt(vector bool long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -3330,6 +3829,15 @@ vec_all_lt(vector bool long long __a, vector bool long long __b) {
return __cc == 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_lt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_lt(vector double __a, vector double __b) {
int __cc;
@@ -3339,7 +3847,16 @@ vec_all_lt(vector double __a, vector double __b) {
/*-- vec_all_nge ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nge(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__a, __b, &__cc);
@@ -3348,7 +3865,16 @@ vec_all_nge(vector double __a, vector double __b) {
/*-- vec_all_ngt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_ngt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_ngt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__a, __b, &__cc);
@@ -3357,7 +3883,16 @@ vec_all_ngt(vector double __a, vector double __b) {
/*-- vec_all_nle ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nle(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nle(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__b, __a, &__cc);
@@ -3366,7 +3901,16 @@ vec_all_nle(vector double __a, vector double __b) {
/*-- vec_all_nlt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nlt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nlt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__b, __a, &__cc);
@@ -3375,7 +3919,16 @@ vec_all_nlt(vector double __a, vector double __b) {
/*-- vec_all_nan ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nan(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc == 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nan(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -3384,7 +3937,16 @@ vec_all_nan(vector double __a) {
/*-- vec_all_numeric --------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_numeric(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_numeric(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -3400,6 +3962,7 @@ vec_any_eq(vector signed char __a, vector signed char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3407,6 +3970,7 @@ vec_any_eq(vector signed char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3422,6 +3986,7 @@ vec_any_eq(vector unsigned char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3430,6 +3995,7 @@ vec_any_eq(vector unsigned char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3453,6 +4019,7 @@ vec_any_eq(vector signed short __a, vector signed short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3460,6 +4027,7 @@ vec_any_eq(vector signed short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3475,6 +4043,7 @@ vec_any_eq(vector unsigned short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3483,6 +4052,7 @@ vec_any_eq(vector unsigned short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3506,6 +4076,7 @@ vec_any_eq(vector signed int __a, vector signed int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3513,6 +4084,7 @@ vec_any_eq(vector signed int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3528,6 +4100,7 @@ vec_any_eq(vector unsigned int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3536,6 +4109,7 @@ vec_any_eq(vector unsigned int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3559,6 +4133,7 @@ vec_any_eq(vector signed long long __a, vector signed long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3566,6 +4141,7 @@ vec_any_eq(vector signed long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3581,6 +4157,7 @@ vec_any_eq(vector unsigned long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3589,6 +4166,7 @@ vec_any_eq(vector unsigned long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3605,6 +4183,15 @@ vec_any_eq(vector bool long long __a, vector bool long long __b) {
return __cc <= 1;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_eq(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_eq(vector double __a, vector double __b) {
int __cc;
@@ -3621,6 +4208,7 @@ vec_any_ne(vector signed char __a, vector signed char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3628,6 +4216,7 @@ vec_any_ne(vector signed char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3643,6 +4232,7 @@ vec_any_ne(vector unsigned char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3651,6 +4241,7 @@ vec_any_ne(vector unsigned char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3674,6 +4265,7 @@ vec_any_ne(vector signed short __a, vector signed short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3681,6 +4273,7 @@ vec_any_ne(vector signed short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3696,6 +4289,7 @@ vec_any_ne(vector unsigned short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3704,6 +4298,7 @@ vec_any_ne(vector unsigned short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3727,6 +4322,7 @@ vec_any_ne(vector signed int __a, vector signed int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3734,6 +4330,7 @@ vec_any_ne(vector signed int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3749,6 +4346,7 @@ vec_any_ne(vector unsigned int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3757,6 +4355,7 @@ vec_any_ne(vector unsigned int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3780,6 +4379,7 @@ vec_any_ne(vector signed long long __a, vector signed long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3787,6 +4387,7 @@ vec_any_ne(vector signed long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3802,6 +4403,7 @@ vec_any_ne(vector unsigned long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3810,6 +4412,7 @@ vec_any_ne(vector unsigned long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3826,6 +4429,15 @@ vec_any_ne(vector bool long long __a, vector bool long long __b) {
return __cc != 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_ne(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc != 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_ne(vector double __a, vector double __b) {
int __cc;
@@ -3842,6 +4454,7 @@ vec_any_ge(vector signed char __a, vector signed char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3849,6 +4462,7 @@ vec_any_ge(vector signed char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3863,6 +4477,7 @@ vec_any_ge(vector unsigned char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3870,6 +4485,7 @@ vec_any_ge(vector unsigned char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3877,6 +4493,7 @@ vec_any_ge(vector bool char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool char __a, vector bool char __b) {
int __cc;
@@ -3892,6 +4509,7 @@ vec_any_ge(vector signed short __a, vector signed short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3899,6 +4517,7 @@ vec_any_ge(vector signed short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3913,6 +4532,7 @@ vec_any_ge(vector unsigned short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3920,6 +4540,7 @@ vec_any_ge(vector unsigned short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3927,6 +4548,7 @@ vec_any_ge(vector bool short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool short __a, vector bool short __b) {
int __cc;
@@ -3942,6 +4564,7 @@ vec_any_ge(vector signed int __a, vector signed int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3949,6 +4572,7 @@ vec_any_ge(vector signed int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3963,6 +4587,7 @@ vec_any_ge(vector unsigned int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3970,6 +4595,7 @@ vec_any_ge(vector unsigned int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3977,6 +4603,7 @@ vec_any_ge(vector bool int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool int __a, vector bool int __b) {
int __cc;
@@ -3992,6 +4619,7 @@ vec_any_ge(vector signed long long __a, vector signed long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3999,6 +4627,7 @@ vec_any_ge(vector signed long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4013,6 +4642,7 @@ vec_any_ge(vector unsigned long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4020,6 +4650,7 @@ vec_any_ge(vector unsigned long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4027,6 +4658,7 @@ vec_any_ge(vector bool long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4035,6 +4667,15 @@ vec_any_ge(vector bool long long __a, vector bool long long __b) {
return __cc != 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_ge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_ge(vector double __a, vector double __b) {
int __cc;
@@ -4051,6 +4692,7 @@ vec_any_gt(vector signed char __a, vector signed char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -4058,6 +4700,7 @@ vec_any_gt(vector signed char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -4072,6 +4715,7 @@ vec_any_gt(vector unsigned char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -4079,6 +4723,7 @@ vec_any_gt(vector unsigned char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -4086,6 +4731,7 @@ vec_any_gt(vector bool char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -4101,6 +4747,7 @@ vec_any_gt(vector signed short __a, vector signed short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -4108,6 +4755,7 @@ vec_any_gt(vector signed short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -4122,6 +4770,7 @@ vec_any_gt(vector unsigned short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -4129,6 +4778,7 @@ vec_any_gt(vector unsigned short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -4136,6 +4786,7 @@ vec_any_gt(vector bool short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -4151,6 +4802,7 @@ vec_any_gt(vector signed int __a, vector signed int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -4158,6 +4810,7 @@ vec_any_gt(vector signed int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -4172,6 +4825,7 @@ vec_any_gt(vector unsigned int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -4179,6 +4833,7 @@ vec_any_gt(vector unsigned int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -4186,6 +4841,7 @@ vec_any_gt(vector bool int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -4201,6 +4857,7 @@ vec_any_gt(vector signed long long __a, vector signed long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -4208,6 +4865,7 @@ vec_any_gt(vector signed long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4222,6 +4880,7 @@ vec_any_gt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4229,6 +4888,7 @@ vec_any_gt(vector unsigned long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4236,6 +4896,7 @@ vec_any_gt(vector bool long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4244,6 +4905,15 @@ vec_any_gt(vector bool long long __a, vector bool long long __b) {
return __cc <= 1;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_gt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_gt(vector double __a, vector double __b) {
int __cc;
@@ -4260,6 +4930,7 @@ vec_any_le(vector signed char __a, vector signed char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed char __a, vector bool char __b) {
int __cc;
@@ -4267,6 +4938,7 @@ vec_any_le(vector signed char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool char __a, vector signed char __b) {
int __cc;
@@ -4281,6 +4953,7 @@ vec_any_le(vector unsigned char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -4288,6 +4961,7 @@ vec_any_le(vector unsigned char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -4295,6 +4969,7 @@ vec_any_le(vector bool char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool char __a, vector bool char __b) {
int __cc;
@@ -4310,6 +4985,7 @@ vec_any_le(vector signed short __a, vector signed short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed short __a, vector bool short __b) {
int __cc;
@@ -4317,6 +4993,7 @@ vec_any_le(vector signed short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool short __a, vector signed short __b) {
int __cc;
@@ -4331,6 +5008,7 @@ vec_any_le(vector unsigned short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -4338,6 +5016,7 @@ vec_any_le(vector unsigned short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -4345,6 +5024,7 @@ vec_any_le(vector bool short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool short __a, vector bool short __b) {
int __cc;
@@ -4360,6 +5040,7 @@ vec_any_le(vector signed int __a, vector signed int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed int __a, vector bool int __b) {
int __cc;
@@ -4367,6 +5048,7 @@ vec_any_le(vector signed int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool int __a, vector signed int __b) {
int __cc;
@@ -4381,6 +5063,7 @@ vec_any_le(vector unsigned int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -4388,6 +5071,7 @@ vec_any_le(vector unsigned int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -4395,6 +5079,7 @@ vec_any_le(vector bool int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool int __a, vector bool int __b) {
int __cc;
@@ -4410,6 +5095,7 @@ vec_any_le(vector signed long long __a, vector signed long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -4417,6 +5103,7 @@ vec_any_le(vector signed long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4431,6 +5118,7 @@ vec_any_le(vector unsigned long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4438,6 +5126,7 @@ vec_any_le(vector unsigned long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4445,6 +5134,7 @@ vec_any_le(vector bool long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4453,6 +5143,15 @@ vec_any_le(vector bool long long __a, vector bool long long __b) {
return __cc != 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_le(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_le(vector double __a, vector double __b) {
int __cc;
@@ -4469,6 +5168,7 @@ vec_any_lt(vector signed char __a, vector signed char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -4476,6 +5176,7 @@ vec_any_lt(vector signed char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -4490,6 +5191,7 @@ vec_any_lt(vector unsigned char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -4497,6 +5199,7 @@ vec_any_lt(vector unsigned char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -4504,6 +5207,7 @@ vec_any_lt(vector bool char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -4519,6 +5223,7 @@ vec_any_lt(vector signed short __a, vector signed short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -4526,6 +5231,7 @@ vec_any_lt(vector signed short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -4540,6 +5246,7 @@ vec_any_lt(vector unsigned short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -4547,6 +5254,7 @@ vec_any_lt(vector unsigned short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -4554,6 +5262,7 @@ vec_any_lt(vector bool short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -4569,6 +5278,7 @@ vec_any_lt(vector signed int __a, vector signed int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -4576,6 +5286,7 @@ vec_any_lt(vector signed int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -4590,6 +5301,7 @@ vec_any_lt(vector unsigned int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -4597,6 +5309,7 @@ vec_any_lt(vector unsigned int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -4604,6 +5317,7 @@ vec_any_lt(vector bool int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -4619,6 +5333,7 @@ vec_any_lt(vector signed long long __a, vector signed long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -4626,6 +5341,7 @@ vec_any_lt(vector signed long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4640,6 +5356,7 @@ vec_any_lt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4647,6 +5364,7 @@ vec_any_lt(vector unsigned long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4654,6 +5372,7 @@ vec_any_lt(vector bool long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4662,6 +5381,15 @@ vec_any_lt(vector bool long long __a, vector bool long long __b) {
return __cc <= 1;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_lt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_lt(vector double __a, vector double __b) {
int __cc;
@@ -4671,7 +5399,16 @@ vec_any_lt(vector double __a, vector double __b) {
/*-- vec_any_nge ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nge(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__a, __b, &__cc);
@@ -4680,7 +5417,16 @@ vec_any_nge(vector double __a, vector double __b) {
/*-- vec_any_ngt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_ngt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_ngt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__a, __b, &__cc);
@@ -4689,7 +5435,16 @@ vec_any_ngt(vector double __a, vector double __b) {
/*-- vec_any_nle ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nle(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nle(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__b, __a, &__cc);
@@ -4698,7 +5453,16 @@ vec_any_nle(vector double __a, vector double __b) {
/*-- vec_any_nlt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nlt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nlt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__b, __a, &__cc);
@@ -4707,7 +5471,16 @@ vec_any_nlt(vector double __a, vector double __b) {
/*-- vec_any_nan ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nan(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc != 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nan(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -4716,7 +5489,16 @@ vec_any_nan(vector double __a) {
/*-- vec_any_numeric --------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_numeric(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_numeric(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -4735,11 +5517,13 @@ vec_andc(vector signed char __a, vector signed char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_andc(vector bool char __a, vector signed char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_andc(vector signed char __a, vector bool char __b) {
return __a & ~__b;
@@ -4750,11 +5534,13 @@ vec_andc(vector unsigned char __a, vector unsigned char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_andc(vector bool char __a, vector unsigned char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_andc(vector unsigned char __a, vector bool char __b) {
return __a & ~__b;
@@ -4770,11 +5556,13 @@ vec_andc(vector signed short __a, vector signed short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_andc(vector bool short __a, vector signed short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_andc(vector signed short __a, vector bool short __b) {
return __a & ~__b;
@@ -4785,11 +5573,13 @@ vec_andc(vector unsigned short __a, vector unsigned short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_andc(vector bool short __a, vector unsigned short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_andc(vector unsigned short __a, vector bool short __b) {
return __a & ~__b;
@@ -4805,11 +5595,13 @@ vec_andc(vector signed int __a, vector signed int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_andc(vector bool int __a, vector signed int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_andc(vector signed int __a, vector bool int __b) {
return __a & ~__b;
@@ -4820,11 +5612,13 @@ vec_andc(vector unsigned int __a, vector unsigned int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_andc(vector bool int __a, vector unsigned int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_andc(vector unsigned int __a, vector bool int __b) {
return __a & ~__b;
@@ -4840,11 +5634,13 @@ vec_andc(vector signed long long __a, vector signed long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_andc(vector bool long long __a, vector signed long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_andc(vector signed long long __a, vector bool long long __b) {
return __a & ~__b;
@@ -4855,28 +5651,40 @@ vec_andc(vector unsigned long long __a, vector unsigned long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_andc(vector bool long long __a, vector unsigned long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_andc(vector unsigned long long __a, vector bool long long __b) {
return __a & ~__b;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_andc(vector float __a, vector float __b) {
+ return (vector float)((vector unsigned int)__a &
+ ~(vector unsigned int)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_andc(vector double __a, vector double __b) {
return (vector double)((vector unsigned long long)__a &
~(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_andc(vector bool long long __a, vector double __b) {
return (vector double)((vector unsigned long long)__a &
~(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_andc(vector double __a, vector bool long long __b) {
return (vector double)((vector unsigned long long)__a &
@@ -4895,11 +5703,13 @@ vec_nor(vector signed char __a, vector signed char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_nor(vector bool char __a, vector signed char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_nor(vector signed char __a, vector bool char __b) {
return ~(__a | __b);
@@ -4910,11 +5720,13 @@ vec_nor(vector unsigned char __a, vector unsigned char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_nor(vector bool char __a, vector unsigned char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_nor(vector unsigned char __a, vector bool char __b) {
return ~(__a | __b);
@@ -4930,11 +5742,13 @@ vec_nor(vector signed short __a, vector signed short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_nor(vector bool short __a, vector signed short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_nor(vector signed short __a, vector bool short __b) {
return ~(__a | __b);
@@ -4945,11 +5759,13 @@ vec_nor(vector unsigned short __a, vector unsigned short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_nor(vector bool short __a, vector unsigned short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_nor(vector unsigned short __a, vector bool short __b) {
return ~(__a | __b);
@@ -4965,11 +5781,13 @@ vec_nor(vector signed int __a, vector signed int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_nor(vector bool int __a, vector signed int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_nor(vector signed int __a, vector bool int __b) {
return ~(__a | __b);
@@ -4980,11 +5798,13 @@ vec_nor(vector unsigned int __a, vector unsigned int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_nor(vector bool int __a, vector unsigned int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_nor(vector unsigned int __a, vector bool int __b) {
return ~(__a | __b);
@@ -5000,11 +5820,13 @@ vec_nor(vector signed long long __a, vector signed long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_nor(vector bool long long __a, vector signed long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_nor(vector signed long long __a, vector bool long long __b) {
return ~(__a | __b);
@@ -5015,34 +5837,274 @@ vec_nor(vector unsigned long long __a, vector unsigned long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_nor(vector bool long long __a, vector unsigned long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_nor(vector unsigned long long __a, vector bool long long __b) {
return ~(__a | __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nor(vector float __a, vector float __b) {
+ return (vector float)~((vector unsigned int)__a |
+ (vector unsigned int)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_nor(vector double __a, vector double __b) {
return (vector double)~((vector unsigned long long)__a |
(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_nor(vector bool long long __a, vector double __b) {
return (vector double)~((vector unsigned long long)__a |
(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_nor(vector double __a, vector bool long long __b) {
return (vector double)~((vector unsigned long long)__a |
(vector unsigned long long)__b);
}
+/*-- vec_orc ----------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool char
+vec_orc(vector bool char __a, vector bool char __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed char
+vec_orc(vector signed char __a, vector signed char __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_orc(vector unsigned char __a, vector unsigned char __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector bool short
+vec_orc(vector bool short __a, vector bool short __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_orc(vector signed short __a, vector signed short __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_orc(vector unsigned short __a, vector unsigned short __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector bool int
+vec_orc(vector bool int __a, vector bool int __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_orc(vector signed int __a, vector signed int __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_orc(vector unsigned int __a, vector unsigned int __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector bool long long
+vec_orc(vector bool long long __a, vector bool long long __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_orc(vector signed long long __a, vector signed long long __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_orc(vector unsigned long long __a, vector unsigned long long __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector float
+vec_orc(vector float __a, vector float __b) {
+ return (vector float)((vector unsigned int)__a &
+ ~(vector unsigned int)__b);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_orc(vector double __a, vector double __b) {
+ return (vector double)((vector unsigned long long)__a &
+ ~(vector unsigned long long)__b);
+}
+#endif
+
+/*-- vec_nand ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool char
+vec_nand(vector bool char __a, vector bool char __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed char
+vec_nand(vector signed char __a, vector signed char __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_nand(vector unsigned char __a, vector unsigned char __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector bool short
+vec_nand(vector bool short __a, vector bool short __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_nand(vector signed short __a, vector signed short __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_nand(vector unsigned short __a, vector unsigned short __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector bool int
+vec_nand(vector bool int __a, vector bool int __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_nand(vector signed int __a, vector signed int __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_nand(vector unsigned int __a, vector unsigned int __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector bool long long
+vec_nand(vector bool long long __a, vector bool long long __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_nand(vector signed long long __a, vector signed long long __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_nand(vector unsigned long long __a, vector unsigned long long __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_nand(vector float __a, vector float __b) {
+ return (vector float)~((vector unsigned int)__a &
+ (vector unsigned int)__b);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_nand(vector double __a, vector double __b) {
+ return (vector double)~((vector unsigned long long)__a &
+ (vector unsigned long long)__b);
+}
+#endif
+
+/*-- vec_eqv ----------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool char
+vec_eqv(vector bool char __a, vector bool char __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed char
+vec_eqv(vector signed char __a, vector signed char __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_eqv(vector unsigned char __a, vector unsigned char __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector bool short
+vec_eqv(vector bool short __a, vector bool short __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_eqv(vector signed short __a, vector signed short __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_eqv(vector unsigned short __a, vector unsigned short __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector bool int
+vec_eqv(vector bool int __a, vector bool int __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_eqv(vector signed int __a, vector signed int __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_eqv(vector unsigned int __a, vector unsigned int __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector bool long long
+vec_eqv(vector bool long long __a, vector bool long long __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_eqv(vector signed long long __a, vector signed long long __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_eqv(vector unsigned long long __a, vector unsigned long long __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_eqv(vector float __a, vector float __b) {
+ return (vector float)~((vector unsigned int)__a ^
+ (vector unsigned int)__b);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_eqv(vector double __a, vector double __b) {
+ return (vector double)~((vector unsigned long long)__a ^
+ (vector unsigned long long)__b);
+}
+#endif
+
/*-- vec_cntlz --------------------------------------------------------------*/
static inline __ATTRS_o_ai vector unsigned char
@@ -5323,30 +6385,35 @@ vec_sll(vector signed char __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sll(vector signed char __a, vector unsigned short __b) {
return (vector signed char)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sll(vector signed char __a, vector unsigned int __b) {
return (vector signed char)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sll(vector bool char __a, vector unsigned char __b) {
return (vector bool char)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sll(vector bool char __a, vector unsigned short __b) {
return (vector bool char)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sll(vector bool char __a, vector unsigned int __b) {
return (vector bool char)__builtin_s390_vsl(
@@ -5358,11 +6425,13 @@ vec_sll(vector unsigned char __a, vector unsigned char __b) {
return __builtin_s390_vsl(__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sll(vector unsigned char __a, vector unsigned short __b) {
return __builtin_s390_vsl(__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sll(vector unsigned char __a, vector unsigned int __b) {
return __builtin_s390_vsl(__a, (vector unsigned char)__b);
@@ -5374,30 +6443,35 @@ vec_sll(vector signed short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sll(vector signed short __a, vector unsigned short __b) {
return (vector signed short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sll(vector signed short __a, vector unsigned int __b) {
return (vector signed short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sll(vector bool short __a, vector unsigned char __b) {
return (vector bool short)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sll(vector bool short __a, vector unsigned short __b) {
return (vector bool short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sll(vector bool short __a, vector unsigned int __b) {
return (vector bool short)__builtin_s390_vsl(
@@ -5410,12 +6484,14 @@ vec_sll(vector unsigned short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sll(vector unsigned short __a, vector unsigned short __b) {
return (vector unsigned short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sll(vector unsigned short __a, vector unsigned int __b) {
return (vector unsigned short)__builtin_s390_vsl(
@@ -5428,30 +6504,35 @@ vec_sll(vector signed int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sll(vector signed int __a, vector unsigned short __b) {
return (vector signed int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sll(vector signed int __a, vector unsigned int __b) {
return (vector signed int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sll(vector bool int __a, vector unsigned char __b) {
return (vector bool int)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sll(vector bool int __a, vector unsigned short __b) {
return (vector bool int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sll(vector bool int __a, vector unsigned int __b) {
return (vector bool int)__builtin_s390_vsl(
@@ -5464,12 +6545,14 @@ vec_sll(vector unsigned int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sll(vector unsigned int __a, vector unsigned short __b) {
return (vector unsigned int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sll(vector unsigned int __a, vector unsigned int __b) {
return (vector unsigned int)__builtin_s390_vsl(
@@ -5482,30 +6565,35 @@ vec_sll(vector signed long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sll(vector signed long long __a, vector unsigned short __b) {
return (vector signed long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sll(vector signed long long __a, vector unsigned int __b) {
return (vector signed long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sll(vector bool long long __a, vector unsigned char __b) {
return (vector bool long long)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sll(vector bool long long __a, vector unsigned short __b) {
return (vector bool long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sll(vector bool long long __a, vector unsigned int __b) {
return (vector bool long long)__builtin_s390_vsl(
@@ -5518,12 +6606,14 @@ vec_sll(vector unsigned long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sll(vector unsigned long long __a, vector unsigned short __b) {
return (vector unsigned long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sll(vector unsigned long long __a, vector unsigned int __b) {
return (vector unsigned long long)__builtin_s390_vsl(
@@ -5626,6 +6716,20 @@ vec_slb(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__a, (vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_slb(vector float __a, vector signed int __b) {
+ return (vector float)__builtin_s390_vslb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_slb(vector float __a, vector unsigned int __b) {
+ return (vector float)__builtin_s390_vslb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_slb(vector double __a, vector signed long long __b) {
return (vector double)__builtin_s390_vslb(
@@ -5644,6 +6748,10 @@ extern __ATTRS_o vector signed char
vec_sld(vector signed char __a, vector signed char __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool char
+vec_sld(vector bool char __a, vector bool char __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned char
vec_sld(vector unsigned char __a, vector unsigned char __b, int __c)
__constant_range(__c, 0, 15);
@@ -5652,6 +6760,10 @@ extern __ATTRS_o vector signed short
vec_sld(vector signed short __a, vector signed short __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool short
+vec_sld(vector bool short __a, vector bool short __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned short
vec_sld(vector unsigned short __a, vector unsigned short __b, int __c)
__constant_range(__c, 0, 15);
@@ -5660,6 +6772,10 @@ extern __ATTRS_o vector signed int
vec_sld(vector signed int __a, vector signed int __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool int
+vec_sld(vector bool int __a, vector bool int __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned int
vec_sld(vector unsigned int __a, vector unsigned int __b, int __c)
__constant_range(__c, 0, 15);
@@ -5668,10 +6784,20 @@ extern __ATTRS_o vector signed long long
vec_sld(vector signed long long __a, vector signed long long __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool long long
+vec_sld(vector bool long long __a, vector bool long long __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned long long
vec_sld(vector unsigned long long __a, vector unsigned long long __b, int __c)
__constant_range(__c, 0, 15);
+#if __ARCH__ >= 12
+extern __ATTRS_o vector float
+vec_sld(vector float __a, vector float __b, int __c)
+ __constant_range(__c, 0, 15);
+#endif
+
extern __ATTRS_o vector double
vec_sld(vector double __a, vector double __b, int __c)
__constant_range(__c, 0, 15);
@@ -5714,6 +6840,7 @@ extern __ATTRS_o vector unsigned long long
vec_sldw(vector unsigned long long __a, vector unsigned long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector double
vec_sldw(vector double __a, vector double __b, int __c)
__constant_range(__c, 0, 3);
@@ -5730,30 +6857,35 @@ vec_sral(vector signed char __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sral(vector signed char __a, vector unsigned short __b) {
return (vector signed char)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sral(vector signed char __a, vector unsigned int __b) {
return (vector signed char)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sral(vector bool char __a, vector unsigned char __b) {
return (vector bool char)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sral(vector bool char __a, vector unsigned short __b) {
return (vector bool char)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sral(vector bool char __a, vector unsigned int __b) {
return (vector bool char)__builtin_s390_vsra(
@@ -5765,11 +6897,13 @@ vec_sral(vector unsigned char __a, vector unsigned char __b) {
return __builtin_s390_vsra(__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sral(vector unsigned char __a, vector unsigned short __b) {
return __builtin_s390_vsra(__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sral(vector unsigned char __a, vector unsigned int __b) {
return __builtin_s390_vsra(__a, (vector unsigned char)__b);
@@ -5781,30 +6915,35 @@ vec_sral(vector signed short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sral(vector signed short __a, vector unsigned short __b) {
return (vector signed short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sral(vector signed short __a, vector unsigned int __b) {
return (vector signed short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sral(vector bool short __a, vector unsigned char __b) {
return (vector bool short)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sral(vector bool short __a, vector unsigned short __b) {
return (vector bool short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sral(vector bool short __a, vector unsigned int __b) {
return (vector bool short)__builtin_s390_vsra(
@@ -5817,12 +6956,14 @@ vec_sral(vector unsigned short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sral(vector unsigned short __a, vector unsigned short __b) {
return (vector unsigned short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sral(vector unsigned short __a, vector unsigned int __b) {
return (vector unsigned short)__builtin_s390_vsra(
@@ -5835,30 +6976,35 @@ vec_sral(vector signed int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sral(vector signed int __a, vector unsigned short __b) {
return (vector signed int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sral(vector signed int __a, vector unsigned int __b) {
return (vector signed int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sral(vector bool int __a, vector unsigned char __b) {
return (vector bool int)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sral(vector bool int __a, vector unsigned short __b) {
return (vector bool int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sral(vector bool int __a, vector unsigned int __b) {
return (vector bool int)__builtin_s390_vsra(
@@ -5871,12 +7017,14 @@ vec_sral(vector unsigned int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sral(vector unsigned int __a, vector unsigned short __b) {
return (vector unsigned int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sral(vector unsigned int __a, vector unsigned int __b) {
return (vector unsigned int)__builtin_s390_vsra(
@@ -5889,30 +7037,35 @@ vec_sral(vector signed long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sral(vector signed long long __a, vector unsigned short __b) {
return (vector signed long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sral(vector signed long long __a, vector unsigned int __b) {
return (vector signed long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sral(vector bool long long __a, vector unsigned char __b) {
return (vector bool long long)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sral(vector bool long long __a, vector unsigned short __b) {
return (vector bool long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sral(vector bool long long __a, vector unsigned int __b) {
return (vector bool long long)__builtin_s390_vsra(
@@ -5925,12 +7078,14 @@ vec_sral(vector unsigned long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sral(vector unsigned long long __a, vector unsigned short __b) {
return (vector unsigned long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sral(vector unsigned long long __a, vector unsigned int __b) {
return (vector unsigned long long)__builtin_s390_vsra(
@@ -6033,6 +7188,20 @@ vec_srab(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__a, (vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_srab(vector float __a, vector signed int __b) {
+ return (vector float)__builtin_s390_vsrab(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_srab(vector float __a, vector unsigned int __b) {
+ return (vector float)__builtin_s390_vsrab(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_srab(vector double __a, vector signed long long __b) {
return (vector double)__builtin_s390_vsrab(
@@ -6053,30 +7222,35 @@ vec_srl(vector signed char __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_srl(vector signed char __a, vector unsigned short __b) {
return (vector signed char)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_srl(vector signed char __a, vector unsigned int __b) {
return (vector signed char)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_srl(vector bool char __a, vector unsigned char __b) {
return (vector bool char)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_srl(vector bool char __a, vector unsigned short __b) {
return (vector bool char)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_srl(vector bool char __a, vector unsigned int __b) {
return (vector bool char)__builtin_s390_vsrl(
@@ -6088,11 +7262,13 @@ vec_srl(vector unsigned char __a, vector unsigned char __b) {
return __builtin_s390_vsrl(__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_srl(vector unsigned char __a, vector unsigned short __b) {
return __builtin_s390_vsrl(__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_srl(vector unsigned char __a, vector unsigned int __b) {
return __builtin_s390_vsrl(__a, (vector unsigned char)__b);
@@ -6104,30 +7280,35 @@ vec_srl(vector signed short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_srl(vector signed short __a, vector unsigned short __b) {
return (vector signed short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_srl(vector signed short __a, vector unsigned int __b) {
return (vector signed short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_srl(vector bool short __a, vector unsigned char __b) {
return (vector bool short)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_srl(vector bool short __a, vector unsigned short __b) {
return (vector bool short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_srl(vector bool short __a, vector unsigned int __b) {
return (vector bool short)__builtin_s390_vsrl(
@@ -6140,12 +7321,14 @@ vec_srl(vector unsigned short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_srl(vector unsigned short __a, vector unsigned short __b) {
return (vector unsigned short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_srl(vector unsigned short __a, vector unsigned int __b) {
return (vector unsigned short)__builtin_s390_vsrl(
@@ -6158,30 +7341,35 @@ vec_srl(vector signed int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_srl(vector signed int __a, vector unsigned short __b) {
return (vector signed int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_srl(vector signed int __a, vector unsigned int __b) {
return (vector signed int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_srl(vector bool int __a, vector unsigned char __b) {
return (vector bool int)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_srl(vector bool int __a, vector unsigned short __b) {
return (vector bool int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_srl(vector bool int __a, vector unsigned int __b) {
return (vector bool int)__builtin_s390_vsrl(
@@ -6194,12 +7382,14 @@ vec_srl(vector unsigned int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_srl(vector unsigned int __a, vector unsigned short __b) {
return (vector unsigned int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_srl(vector unsigned int __a, vector unsigned int __b) {
return (vector unsigned int)__builtin_s390_vsrl(
@@ -6212,30 +7402,35 @@ vec_srl(vector signed long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_srl(vector signed long long __a, vector unsigned short __b) {
return (vector signed long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_srl(vector signed long long __a, vector unsigned int __b) {
return (vector signed long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_srl(vector bool long long __a, vector unsigned char __b) {
return (vector bool long long)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_srl(vector bool long long __a, vector unsigned short __b) {
return (vector bool long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_srl(vector bool long long __a, vector unsigned int __b) {
return (vector bool long long)__builtin_s390_vsrl(
@@ -6248,12 +7443,14 @@ vec_srl(vector unsigned long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_srl(vector unsigned long long __a, vector unsigned short __b) {
return (vector unsigned long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_srl(vector unsigned long long __a, vector unsigned int __b) {
return (vector unsigned long long)__builtin_s390_vsrl(
@@ -6356,6 +7553,20 @@ vec_srb(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__a, (vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_srb(vector float __a, vector signed int __b) {
+ return (vector float)__builtin_s390_vsrlb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_srb(vector float __a, vector unsigned int __b) {
+ return (vector float)__builtin_s390_vsrlb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_srb(vector double __a, vector signed long long __b) {
return (vector double)__builtin_s390_vsrlb(
@@ -6390,6 +7601,13 @@ vec_abs(vector signed long long __a) {
return vec_sel(__a, -__a, vec_cmplt(__a, (vector signed long long)0));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_abs(vector float __a) {
+ return __builtin_s390_vflpsb(__a);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_abs(vector double __a) {
return __builtin_s390_vflpdb(__a);
@@ -6397,7 +7615,14 @@ vec_abs(vector double __a) {
/*-- vec_nabs ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nabs(vector float __a) {
+ return __builtin_s390_vflnsb(__a);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_nabs(vector double __a) {
return __builtin_s390_vflndb(__a);
}
@@ -6409,12 +7634,14 @@ vec_max(vector signed char __a, vector signed char __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_max(vector signed char __a, vector bool char __b) {
vector signed char __bc = (vector signed char)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_max(vector bool char __a, vector signed char __b) {
vector signed char __ac = (vector signed char)__a;
@@ -6426,12 +7653,14 @@ vec_max(vector unsigned char __a, vector unsigned char __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_max(vector unsigned char __a, vector bool char __b) {
vector unsigned char __bc = (vector unsigned char)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_max(vector bool char __a, vector unsigned char __b) {
vector unsigned char __ac = (vector unsigned char)__a;
@@ -6443,12 +7672,14 @@ vec_max(vector signed short __a, vector signed short __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_max(vector signed short __a, vector bool short __b) {
vector signed short __bc = (vector signed short)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_max(vector bool short __a, vector signed short __b) {
vector signed short __ac = (vector signed short)__a;
@@ -6460,12 +7691,14 @@ vec_max(vector unsigned short __a, vector unsigned short __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_max(vector unsigned short __a, vector bool short __b) {
vector unsigned short __bc = (vector unsigned short)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_max(vector bool short __a, vector unsigned short __b) {
vector unsigned short __ac = (vector unsigned short)__a;
@@ -6477,12 +7710,14 @@ vec_max(vector signed int __a, vector signed int __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_max(vector signed int __a, vector bool int __b) {
vector signed int __bc = (vector signed int)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_max(vector bool int __a, vector signed int __b) {
vector signed int __ac = (vector signed int)__a;
@@ -6494,12 +7729,14 @@ vec_max(vector unsigned int __a, vector unsigned int __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_max(vector unsigned int __a, vector bool int __b) {
vector unsigned int __bc = (vector unsigned int)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_max(vector bool int __a, vector unsigned int __b) {
vector unsigned int __ac = (vector unsigned int)__a;
@@ -6511,12 +7748,14 @@ vec_max(vector signed long long __a, vector signed long long __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_max(vector signed long long __a, vector bool long long __b) {
vector signed long long __bc = (vector signed long long)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_max(vector bool long long __a, vector signed long long __b) {
vector signed long long __ac = (vector signed long long)__a;
@@ -6528,21 +7767,34 @@ vec_max(vector unsigned long long __a, vector unsigned long long __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_max(vector unsigned long long __a, vector bool long long __b) {
vector unsigned long long __bc = (vector unsigned long long)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_max(vector bool long long __a, vector unsigned long long __b) {
vector unsigned long long __ac = (vector unsigned long long)__a;
return vec_sel(__b, __ac, vec_cmpgt(__ac, __b));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_max(vector float __a, vector float __b) {
+ return __builtin_s390_vfmaxsb(__a, __b, 0);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_max(vector double __a, vector double __b) {
+#if __ARCH__ >= 12
+ return __builtin_s390_vfmaxdb(__a, __b, 0);
+#else
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
+#endif
}
/*-- vec_min ----------------------------------------------------------------*/
@@ -6552,12 +7804,14 @@ vec_min(vector signed char __a, vector signed char __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_min(vector signed char __a, vector bool char __b) {
vector signed char __bc = (vector signed char)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_min(vector bool char __a, vector signed char __b) {
vector signed char __ac = (vector signed char)__a;
@@ -6569,12 +7823,14 @@ vec_min(vector unsigned char __a, vector unsigned char __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_min(vector unsigned char __a, vector bool char __b) {
vector unsigned char __bc = (vector unsigned char)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_min(vector bool char __a, vector unsigned char __b) {
vector unsigned char __ac = (vector unsigned char)__a;
@@ -6586,12 +7842,14 @@ vec_min(vector signed short __a, vector signed short __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_min(vector signed short __a, vector bool short __b) {
vector signed short __bc = (vector signed short)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_min(vector bool short __a, vector signed short __b) {
vector signed short __ac = (vector signed short)__a;
@@ -6603,12 +7861,14 @@ vec_min(vector unsigned short __a, vector unsigned short __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_min(vector unsigned short __a, vector bool short __b) {
vector unsigned short __bc = (vector unsigned short)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_min(vector bool short __a, vector unsigned short __b) {
vector unsigned short __ac = (vector unsigned short)__a;
@@ -6620,12 +7880,14 @@ vec_min(vector signed int __a, vector signed int __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_min(vector signed int __a, vector bool int __b) {
vector signed int __bc = (vector signed int)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_min(vector bool int __a, vector signed int __b) {
vector signed int __ac = (vector signed int)__a;
@@ -6637,12 +7899,14 @@ vec_min(vector unsigned int __a, vector unsigned int __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_min(vector unsigned int __a, vector bool int __b) {
vector unsigned int __bc = (vector unsigned int)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_min(vector bool int __a, vector unsigned int __b) {
vector unsigned int __ac = (vector unsigned int)__a;
@@ -6654,12 +7918,14 @@ vec_min(vector signed long long __a, vector signed long long __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_min(vector signed long long __a, vector bool long long __b) {
vector signed long long __bc = (vector signed long long)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_min(vector bool long long __a, vector signed long long __b) {
vector signed long long __ac = (vector signed long long)__a;
@@ -6671,21 +7937,34 @@ vec_min(vector unsigned long long __a, vector unsigned long long __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_min(vector unsigned long long __a, vector bool long long __b) {
vector unsigned long long __bc = (vector unsigned long long)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_min(vector bool long long __a, vector unsigned long long __b) {
vector unsigned long long __ac = (vector unsigned long long)__a;
return vec_sel(__ac, __b, vec_cmpgt(__ac, __b));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_min(vector float __a, vector float __b) {
+ return __builtin_s390_vfminsb(__a, __b, 0);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_min(vector double __a, vector double __b) {
+#if __ARCH__ >= 12
+ return __builtin_s390_vfmindb(__a, __b, 0);
+#else
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
+#endif
}
/*-- vec_add_u128 -----------------------------------------------------------*/
@@ -7126,6 +8405,13 @@ vec_mulo(vector unsigned int __a, vector unsigned int __b) {
return __builtin_s390_vmlof(__a, __b);
}
+/*-- vec_msum_u128 ----------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+#define vec_msum_u128(X, Y, Z, W) \
+ ((vector unsigned char)__builtin_s390_vmslg((X), (Y), (Z), (W)));
+#endif
+
/*-- vec_sub_u128 -----------------------------------------------------------*/
static inline __ATTRS_ai vector unsigned char
@@ -7263,6 +8549,14 @@ vec_test_mask(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_test_mask(vector float __a, vector unsigned int __b) {
+ return __builtin_s390_vtm((vector unsigned char)__a,
+ (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_test_mask(vector double __a, vector unsigned long long __b) {
return __builtin_s390_vtm((vector unsigned char)__a,
@@ -7271,27 +8565,77 @@ vec_test_mask(vector double __a, vector unsigned long long __b) {
/*-- vec_madd ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_madd(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfmasb(__a, __b, __c);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_madd(vector double __a, vector double __b, vector double __c) {
return __builtin_s390_vfmadb(__a, __b, __c);
}
/*-- vec_msub ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_msub(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfmssb(__a, __b, __c);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_msub(vector double __a, vector double __b, vector double __c) {
return __builtin_s390_vfmsdb(__a, __b, __c);
}
+/*-- vec_nmadd ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nmadd(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfnmasb(__a, __b, __c);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_nmadd(vector double __a, vector double __b, vector double __c) {
+ return __builtin_s390_vfnmadb(__a, __b, __c);
+}
+#endif
+
+/*-- vec_nmsub ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nmsub(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfnmssb(__a, __b, __c);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_nmsub(vector double __a, vector double __b, vector double __c) {
+ return __builtin_s390_vfnmsdb(__a, __b, __c);
+}
+#endif
+
/*-- vec_sqrt ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_sqrt(vector float __a) {
+ return __builtin_s390_vfsqsb(__a);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_sqrt(vector double __a) {
return __builtin_s390_vfsqdb(__a);
}
/*-- vec_ld2f ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_ai vector double
vec_ld2f(const float *__ptr) {
typedef float __v2f32 __attribute__((__vector_size__(8)));
@@ -7300,6 +8644,7 @@ vec_ld2f(const float *__ptr) {
/*-- vec_st2f ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_ai void
vec_st2f(vector double __a, float *__ptr) {
typedef float __v2f32 __attribute__((__vector_size__(8)));
@@ -7308,6 +8653,7 @@ vec_st2f(vector double __a, float *__ptr) {
/*-- vec_ctd ----------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_ctd(vector signed long long __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7316,6 +8662,7 @@ vec_ctd(vector signed long long __a, int __b)
return __conv;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_ctd(vector unsigned long long __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7326,6 +8673,7 @@ vec_ctd(vector unsigned long long __a, int __b)
/*-- vec_ctsl ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_ctsl(vector double __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7335,6 +8683,7 @@ vec_ctsl(vector double __a, int __b)
/*-- vec_ctul ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_ctul(vector double __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7342,16 +8691,79 @@ vec_ctul(vector double __a, int __b)
return __builtin_convertvector(__a, vector unsigned long long);
}
-/*-- vec_roundp -------------------------------------------------------------*/
+/*-- vec_doublee ------------------------------------------------------------*/
+#if __ARCH__ >= 12
static inline __ATTRS_ai vector double
+vec_doublee(vector float __a) {
+ typedef float __v2f32 __attribute__((__vector_size__(8)));
+ __v2f32 __pack = __builtin_shufflevector(__a, __a, 0, 2);
+ return __builtin_convertvector(__pack, vector double);
+}
+#endif
+
+/*-- vec_floate -------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai vector float
+vec_floate(vector double __a) {
+ typedef float __v2f32 __attribute__((__vector_size__(8)));
+ __v2f32 __pack = __builtin_convertvector(__a, __v2f32);
+ return __builtin_shufflevector(__pack, __pack, 0, -1, 1, -1);
+}
+#endif
+
+/*-- vec_double -------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector double
+vec_double(vector signed long long __a) {
+ return __builtin_convertvector(__a, vector double);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_double(vector unsigned long long __a) {
+ return __builtin_convertvector(__a, vector double);
+}
+
+/*-- vec_signed -------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector signed long long
+vec_signed(vector double __a) {
+ return __builtin_convertvector(__a, vector signed long long);
+}
+
+/*-- vec_unsigned -----------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_unsigned(vector double __a) {
+ return __builtin_convertvector(__a, vector unsigned long long);
+}
+
+/*-- vec_roundp -------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundp(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 6);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundp(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 6);
}
/*-- vec_ceil ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_ceil(vector float __a) {
+ // On this platform, vec_ceil never triggers the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 4, 6);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_ceil(vector double __a) {
// On this platform, vec_ceil never triggers the IEEE-inexact exception.
return __builtin_s390_vfidb(__a, 4, 6);
@@ -7359,14 +8771,29 @@ vec_ceil(vector double __a) {
/*-- vec_roundm -------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundm(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 7);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundm(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 7);
}
/*-- vec_floor --------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_floor(vector float __a) {
+ // On this platform, vec_floor never triggers the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 4, 7);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_floor(vector double __a) {
// On this platform, vec_floor never triggers the IEEE-inexact exception.
return __builtin_s390_vfidb(__a, 4, 7);
@@ -7374,14 +8801,29 @@ vec_floor(vector double __a) {
/*-- vec_roundz -------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundz(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 5);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundz(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 5);
}
/*-- vec_trunc --------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_trunc(vector float __a) {
+ // On this platform, vec_trunc never triggers the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 4, 5);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_trunc(vector double __a) {
// On this platform, vec_trunc never triggers the IEEE-inexact exception.
return __builtin_s390_vfidb(__a, 4, 5);
@@ -7389,22 +8831,104 @@ vec_trunc(vector double __a) {
/*-- vec_roundc -------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundc(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 0);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundc(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 0);
}
+/*-- vec_rint ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_rint(vector float __a) {
+ // vec_rint may trigger the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 0, 0);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
+vec_rint(vector double __a) {
+ // vec_rint may trigger the IEEE-inexact exception.
+ return __builtin_s390_vfidb(__a, 0, 0);
+}
+
/*-- vec_round --------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_round(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 4);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_round(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 4);
}
/*-- vec_fp_test_data_class -------------------------------------------------*/
+#if __ARCH__ >= 12
+extern __ATTRS_o vector bool int
+vec_fp_test_data_class(vector float __a, int __b, int *__c)
+ __constant_range(__b, 0, 4095);
+
+extern __ATTRS_o vector bool long long
+vec_fp_test_data_class(vector double __a, int __b, int *__c)
+ __constant_range(__b, 0, 4095);
+
+#define vec_fp_test_data_class(X, Y, Z) \
+ ((__typeof__((vec_fp_test_data_class)((X), (Y), (Z)))) \
+ __extension__ ({ \
+ vector unsigned char __res; \
+ vector unsigned char __x = (vector unsigned char)(X); \
+ int *__z = (Z); \
+ switch (sizeof ((X)[0])) { \
+ case 4: __res = (vector unsigned char) \
+ __builtin_s390_vftcisb((vector float)__x, (Y), __z); \
+ break; \
+ default: __res = (vector unsigned char) \
+ __builtin_s390_vftcidb((vector double)__x, (Y), __z); \
+ break; \
+ } __res; }))
+#else
#define vec_fp_test_data_class(X, Y, Z) \
((vector bool long long)__builtin_s390_vftcidb((X), (Y), (Z)))
+#endif
+
+#define __VEC_CLASS_FP_ZERO_P (1 << 11)
+#define __VEC_CLASS_FP_ZERO_N (1 << 10)
+#define __VEC_CLASS_FP_ZERO (__VEC_CLASS_FP_ZERO_P | __VEC_CLASS_FP_ZERO_N)
+#define __VEC_CLASS_FP_NORMAL_P (1 << 9)
+#define __VEC_CLASS_FP_NORMAL_N (1 << 8)
+#define __VEC_CLASS_FP_NORMAL (__VEC_CLASS_FP_NORMAL_P | \
+ __VEC_CLASS_FP_NORMAL_N)
+#define __VEC_CLASS_FP_SUBNORMAL_P (1 << 7)
+#define __VEC_CLASS_FP_SUBNORMAL_N (1 << 6)
+#define __VEC_CLASS_FP_SUBNORMAL (__VEC_CLASS_FP_SUBNORMAL_P | \
+ __VEC_CLASS_FP_SUBNORMAL_N)
+#define __VEC_CLASS_FP_INFINITY_P (1 << 5)
+#define __VEC_CLASS_FP_INFINITY_N (1 << 4)
+#define __VEC_CLASS_FP_INFINITY (__VEC_CLASS_FP_INFINITY_P | \
+ __VEC_CLASS_FP_INFINITY_N)
+#define __VEC_CLASS_FP_QNAN_P (1 << 3)
+#define __VEC_CLASS_FP_QNAN_N (1 << 2)
+#define __VEC_CLASS_FP_QNAN (__VEC_CLASS_FP_QNAN_P | __VEC_CLASS_FP_QNAN_N)
+#define __VEC_CLASS_FP_SNAN_P (1 << 1)
+#define __VEC_CLASS_FP_SNAN_N (1 << 0)
+#define __VEC_CLASS_FP_SNAN (__VEC_CLASS_FP_SNAN_P | __VEC_CLASS_FP_SNAN_N)
+#define __VEC_CLASS_FP_NAN (__VEC_CLASS_FP_QNAN | __VEC_CLASS_FP_SNAN)
+#define __VEC_CLASS_FP_NOT_NORMAL (__VEC_CLASS_FP_NAN | \
+ __VEC_CLASS_FP_SUBNORMAL | \
+ __VEC_CLASS_FP_ZERO | \
+ __VEC_CLASS_FP_INFINITY)
/*-- vec_cp_until_zero ------------------------------------------------------*/
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 2003029cb5..31ee7b82dd 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -72,6 +72,10 @@
#include <tbmintrin.h>
#endif
+#if !defined(_MSC_VER) || __has_feature(modules) || defined(__LWP__)
+#include <lwpintrin.h>
+#endif
+
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__F16C__)
#include <f16cintrin.h>
#endif
@@ -84,6 +88,4 @@
#include <clzerointrin.h>
#endif
-/* FIXME: LWP */
-
#endif /* __X86INTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index bb8e29cd90..bbc2117b4e 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -2099,7 +2099,7 @@ _mm_stream_pi(__m64 *__p, __m64 __a)
///
/// \param __p
/// A pointer to a 128-bit aligned memory location that will receive the
-/// integer values.
+/// single-precision floating-point values.
/// \param __a
/// A 128-bit vector of [4 x float] containing the values to be moved.
static __inline__ void __DEFAULT_FN_ATTRS
@@ -2133,7 +2133,7 @@ void _mm_sfence(void);
/// \headerfile <x86intrin.h>
///
/// \code
-/// void _mm_extract_pi(__m64 a, int n);
+/// int _mm_extract_pi16(__m64 a, int n);
/// \endcode
///
/// This intrinsic corresponds to the <c> VPEXTRW / PEXTRW </c> instruction.
@@ -2157,7 +2157,7 @@ void _mm_sfence(void);
/// \headerfile <x86intrin.h>
///
/// \code
-/// void _mm_insert_pi(__m64 a, int d, int n);
+/// __m64 _mm_insert_pi16(__m64 a, int d, int n);
/// \endcode
///
/// This intrinsic corresponds to the <c> VPINSRW / PINSRW </c> instruction.
@@ -2331,8 +2331,10 @@ _mm_mulhi_pu16(__m64 __a, __m64 __b)
/// \brief Conditionally copies the values from each 8-bit element in the first
/// 64-bit integer vector operand to the specified memory location, as
/// specified by the most significant bit in the corresponding element in the
-/// second 64-bit integer vector operand. To minimize caching, the data is
-/// flagged as non-temporal (unlikely to be used again soon).
+/// second 64-bit integer vector operand.
+///
+/// To minimize caching, the data is flagged as non-temporal
+/// (unlikely to be used again soon).
///
/// \headerfile <x86intrin.h>
///
@@ -2540,7 +2542,7 @@ void _mm_setcsr(unsigned int __i);
/// A 128-bit vector of [4 x float].
/// \param mask
/// An immediate value containing an 8-bit value specifying which elements to
-/// copy from \ a and \a b. \n
+/// copy from \a a and \a b. \n
/// Bits [3:0] specify the values copied from operand \a a. \n
/// Bits [7:4] specify the values copied from operand \a b. \n
/// The destinations within the 128-bit destination are assigned values as
@@ -2678,8 +2680,7 @@ _mm_movelh_ps(__m128 __a, __m128 __b)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [4 x i16]. The elements of the destination are copied
@@ -2709,8 +2710,7 @@ _mm_cvtpi16_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of 16-bit unsigned integer values. The elements of the
@@ -2739,8 +2739,7 @@ _mm_cvtpu16_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [8 x i8]. The elements of the destination are copied
@@ -2764,8 +2763,7 @@ _mm_cvtpi8_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of unsigned 8-bit integer values. The elements of the
@@ -2789,8 +2787,7 @@ _mm_cvtpu8_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [2 x i32]. The lower elements of the destination are
@@ -2815,16 +2812,16 @@ _mm_cvtpi32x2_ps(__m64 __a, __m64 __b)
/// \brief Converts each single-precision floating-point element of a 128-bit
/// floating-point vector of [4 x float] into a 16-bit signed integer, and
-/// packs the results into a 64-bit integer vector of [4 x i16]. If the
-/// floating-point element is NaN or infinity, or if the floating-point
-/// element is greater than 0x7FFFFFFF or less than -0x8000, it is converted
-/// to 0x8000. Otherwise if the floating-point element is greater than
-/// 0x7FFF, it is converted to 0x7FFF.
+/// packs the results into a 64-bit integer vector of [4 x i16].
+///
+/// If the floating-point element is NaN or infinity, or if the
+/// floating-point element is greater than 0x7FFFFFFF or less than -0x8000,
+/// it is converted to 0x8000. Otherwise if the floating-point element is
+/// greater than 0x7FFF, it is converted to 0x7FFF.
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPS2PI + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPS2PI + COMPOSITE </c> instruction.
///
/// \param __a
/// A 128-bit floating-point vector of [4 x float].
@@ -2845,16 +2842,16 @@ _mm_cvtps_pi16(__m128 __a)
/// \brief Converts each single-precision floating-point element of a 128-bit
/// floating-point vector of [4 x float] into an 8-bit signed integer, and
/// packs the results into the lower 32 bits of a 64-bit integer vector of
-/// [8 x i8]. The upper 32 bits of the vector are set to 0. If the
-/// floating-point element is NaN or infinity, or if the floating-point
-/// element is greater than 0x7FFFFFFF or less than -0x80, it is converted
-/// to 0x80. Otherwise if the floating-point element is greater than 0x7F,
-/// it is converted to 0x7F.
+/// [8 x i8]. The upper 32 bits of the vector are set to 0.
+///
+/// If the floating-point element is NaN or infinity, or if the
+/// floating-point element is greater than 0x7FFFFFFF or less than -0x80, it
+/// is converted to 0x80. Otherwise if the floating-point element is greater
+/// than 0x7F, it is converted to 0x7F.
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPS2PI + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPS2PI + COMPOSITE </c> instruction.
///
/// \param __a
/// 128-bit floating-point vector of [4 x float].
diff --git a/lib/Index/CodegenNameGenerator.cpp b/lib/Index/CodegenNameGenerator.cpp
index 92740b0570..bf52e2108b 100644
--- a/lib/Index/CodegenNameGenerator.cpp
+++ b/lib/Index/CodegenNameGenerator.cpp
@@ -68,7 +68,38 @@ struct CodegenNameGenerator::Implementation {
return Name;
}
+ enum ObjCKind {
+ ObjCClass,
+ ObjCMetaclass,
+ };
+
+ std::vector<std::string> getAllManglings(const ObjCContainerDecl *OCD) {
+ StringRef ClassName;
+ if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
+ ClassName = OID->getObjCRuntimeNameAsString();
+ else if (const auto *OID = dyn_cast<ObjCImplementationDecl>(OCD))
+ ClassName = OID->getObjCRuntimeNameAsString();
+
+ if (ClassName.empty())
+ return {};
+
+ auto Mangle = [&](ObjCKind Kind, StringRef ClassName) -> std::string {
+ SmallString<40> Mangled;
+ auto Prefix = getClassSymbolPrefix(Kind, OCD->getASTContext());
+ llvm::Mangler::getNameWithPrefix(Mangled, Prefix + ClassName, DL);
+ return Mangled.str();
+ };
+
+ return {
+ Mangle(ObjCClass, ClassName),
+ Mangle(ObjCMetaclass, ClassName),
+ };
+ }
+
std::vector<std::string> getAllManglings(const Decl *D) {
+ if (const auto *OCD = dyn_cast<ObjCContainerDecl>(D))
+ return getAllManglings(OCD);
+
if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D)))
return {};
@@ -135,12 +166,14 @@ private:
}
void writeObjCClassName(const ObjCInterfaceDecl *D, raw_ostream &OS) {
- OS << getClassSymbolPrefix();
+ OS << getClassSymbolPrefix(ObjCClass, D->getASTContext());
OS << D->getObjCRuntimeNameAsString();
}
- static StringRef getClassSymbolPrefix() {
- return "OBJC_CLASS_$_";
+ static StringRef getClassSymbolPrefix(ObjCKind Kind, const ASTContext &Context) {
+ if (Context.getLangOpts().ObjCRuntime.isGNUFamily())
+ return Kind == ObjCMetaclass ? "_OBJC_METACLASS_" : "_OBJC_CLASS_";
+ return Kind == ObjCMetaclass ? "OBJC_METACLASS_$_" : "OBJC_CLASS_$_";
}
std::string getMangledStructor(const NamedDecl *ND, unsigned StructorType) {
diff --git a/lib/Index/CommentToXML.cpp b/lib/Index/CommentToXML.cpp
index 08acc96c4e..918068a240 100644
--- a/lib/Index/CommentToXML.cpp
+++ b/lib/Index/CommentToXML.cpp
@@ -579,6 +579,7 @@ void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
PrintingPolicy PPolicy(LangOpts);
PPolicy.PolishForDeclaration = true;
PPolicy.TerseOutput = true;
+ PPolicy.ConstantsAsWritten = true;
ThisDecl->CurrentDecl->print(OS, PPolicy,
/*Indentation*/0, /*PrintInstantiation*/false);
}
@@ -592,12 +593,10 @@ void CommentASTToXMLConverter::formatTextOfDeclaration(
unsigned Offset = 0;
unsigned Length = Declaration.size();
- bool IncompleteFormat = false;
format::FormatStyle Style = format::getLLVMStyle();
Style.FixNamespaceComments = false;
tooling::Replacements Replaces =
- reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd",
- &IncompleteFormat);
+ reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd");
auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces);
if (static_cast<bool>(FormattedStringDecl)) {
Declaration = *FormattedStringDecl;
diff --git a/lib/Index/IndexBody.cpp b/lib/Index/IndexBody.cpp
index 7681de7559..6bbd381025 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)
@@ -146,6 +150,53 @@ public:
Parent, ParentDC, Roles, Relations, E);
}
+ bool indexDependentReference(
+ const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
+ if (!T)
+ return true;
+ const TemplateSpecializationType *TST =
+ T->getAs<TemplateSpecializationType>();
+ if (!TST)
+ return true;
+ TemplateName TN = TST->getTemplateName();
+ const ClassTemplateDecl *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return true;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ if (!RD->hasDefinition())
+ return true;
+ RD = RD->getDefinition();
+ std::vector<const NamedDecl *> Symbols =
+ RD->lookupDependentName(NameInfo.getName(), Filter);
+ // FIXME: Improve overload handling.
+ if (Symbols.size() != 1)
+ return true;
+ SourceLocation Loc = NameInfo.getLoc();
+ if (Loc.isInvalid())
+ Loc = E->getLocStart();
+ SmallVector<SymbolRelation, 4> Relations;
+ SymbolRoleSet Roles = getRolesForRef(E, Relations);
+ return IndexCtx.handleReference(Symbols[0], Loc, Parent, ParentDC, Roles,
+ Relations, E);
+ }
+
+ bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
+ const DeclarationNameInfo &Info = E->getMemberNameInfo();
+ return indexDependentReference(
+ E, E->getBaseType().getTypePtrOrNull(), Info,
+ [](const NamedDecl *D) { return D->isCXXInstanceMember(); });
+ }
+
+ bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ const DeclarationNameInfo &Info = E->getNameInfo();
+ const NestedNameSpecifier *NNS = E->getQualifier();
+ return indexDependentReference(
+ E, NNS->getAsType(), Info,
+ [](const NamedDecl *D) { return !D->isCXXInstanceMember(); });
+ }
+
bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {
if (D.isFieldDesignator() && D.getField())
@@ -178,7 +229,32 @@ public:
SymbolRoleSet Roles{};
SmallVector<SymbolRelation, 2> Relations;
addCallRole(Roles, Relations);
- if (E->isImplicit())
+ Stmt *Containing = getParentStmt();
+
+ auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool {
+ const auto *E = POE->getSyntacticForm();
+ if (const auto *BinOp = dyn_cast<BinaryOperator>(E))
+ E = BinOp->getLHS();
+ const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E);
+ if (!PRE)
+ return false;
+ if (PRE->isExplicitProperty())
+ return false;
+ if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) {
+ // Class properties that are explicitly defined using @property
+ // declarations are represented implicitly as there is no ivar for
+ // class properties.
+ if (Getter->isClassMethod() &&
+ Getter->getCanonicalDecl()->findPropertyDecl())
+ return false;
+ }
+ return true;
+ };
+ bool IsPropCall = Containing && isa<PseudoObjectExpr>(Containing);
+ // Implicit property message sends are not 'implicit'.
+ if ((E->isImplicit() || IsPropCall) &&
+ !(IsPropCall &&
+ IsImplicitProperty(cast<PseudoObjectExpr>(Containing))))
Roles |= (unsigned)SymbolRole::Implicit;
if (isDynamic(E)) {
@@ -194,9 +270,27 @@ public:
}
bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- if (E->isExplicitProperty())
+ if (E->isClassReceiver())
+ IndexCtx.handleReference(E->getClassReceiver(), E->getReceiverLocation(),
+ Parent, ParentDC);
+ if (E->isExplicitProperty()) {
+ SmallVector<SymbolRelation, 2> Relations;
+ SymbolRoleSet Roles = getRolesForRef(E, Relations);
return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
- Parent, ParentDC, SymbolRoleSet(), {}, E);
+ Parent, ParentDC, Roles, Relations, E);
+ } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {
+ // Class properties that are explicitly defined using @property
+ // declarations are represented implicitly as there is no ivar for class
+ // properties.
+ if (Getter->isClassMethod()) {
+ if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {
+ SmallVector<SymbolRelation, 2> Relations;
+ SymbolRoleSet Roles = getRolesForRef(E, Relations);
+ return IndexCtx.handleReference(PD, E->getLocation(), Parent,
+ ParentDC, Roles, Relations, E);
+ }
+ }
+ }
// No need to do a handleReference for the objc method, because there will
// be a message expr as part of PseudoObjectExpr.
diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp
index 4c5a87b29b..2704e6da95 100644
--- a/lib/Index/IndexDecl.cpp
+++ b/lib/Index/IndexDecl.cpp
@@ -14,6 +14,13 @@
using namespace clang;
using namespace index;
+#define TRY_DECL(D,CALL_EXPR) \
+ do { \
+ if (!IndexCtx.shouldIndex(D)) return true; \
+ if (!CALL_EXPR) \
+ return false; \
+ } while (0)
+
#define TRY_TO(CALL_EXPR) \
do { \
if (!CALL_EXPR) \
@@ -45,6 +52,33 @@ public:
return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
}
+ void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ const TemplateArgumentLocInfo &LocInfo = TALoc.getLocInfo();
+ switch (TALoc.getArgument().getKind()) {
+ case TemplateArgument::Expression:
+ IndexCtx.indexBody(LocInfo.getAsExpr(), Parent, DC);
+ break;
+ case TemplateArgument::Type:
+ IndexCtx.indexTypeSourceInfo(LocInfo.getAsTypeSourceInfo(), Parent, DC);
+ break;
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ IndexCtx.indexNestedNameSpecifierLoc(TALoc.getTemplateQualifierLoc(),
+ Parent, DC);
+ if (const TemplateDecl *TD = TALoc.getArgument()
+ .getAsTemplateOrTemplatePattern()
+ .getAsTemplateDecl()) {
+ if (const NamedDecl *TTD = TD->getTemplatedDecl())
+ IndexCtx.handleReference(TTD, TALoc.getTemplateNameLoc(), Parent, DC);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
void handleDeclarator(const DeclaratorDecl *D,
const NamedDecl *Parent = nullptr,
bool isIBType = false) {
@@ -75,6 +109,17 @@ public:
}
}
}
+ } else {
+ // Index the default parameter value for function definitions.
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isThisDeclarationADefinition()) {
+ for (const auto *PV : FD->parameters()) {
+ if (PV->hasDefaultArg() && !PV->hasUninstantiatedDefaultArg() &&
+ !PV->hasUnparsedDefaultArg())
+ IndexCtx.indexBody(PV->getDefaultArg(), D);
+ }
+ }
+ }
}
}
@@ -98,11 +143,29 @@ public:
if (MethodLoc.isInvalid())
MethodLoc = D->getLocation();
+ 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())
- Roles |= (SymbolRoleSet)SymbolRole::Implicit;
- if (!IndexCtx.handleDecl(D, MethodLoc, Roles, Relations))
- return false;
+ if (D->isImplicit()) {
+ if (AttrLoc.isValid()) {
+ MethodLoc = AttrLoc;
+ } else {
+ Roles |= (SymbolRoleSet)SymbolRole::Implicit;
+ }
+ } else if (AttrLoc.isValid()) {
+ IndexCtx.handleReference(D, AttrLoc, cast<NamedDecl>(D->getDeclContext()),
+ D->getDeclContext(), 0);
+ }
+
+ TRY_DECL(D, IndexCtx.handleDecl(D, MethodLoc, Roles, Relations));
IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>();
for (const auto *I : D->parameters()) {
@@ -119,10 +182,52 @@ public:
return true;
}
- bool VisitFunctionDecl(const FunctionDecl *D) {
- if (D->isDeleted())
- return true;
+ /// Gather the declarations which the given declaration \D overrides in a
+ /// pseudo-override manner.
+ ///
+ /// Pseudo-overrides occur when a class template specialization declares
+ /// a declaration that has the same name as a similar declaration in the
+ /// non-specialized template.
+ void
+ gatherTemplatePseudoOverrides(const NamedDecl *D,
+ SmallVectorImpl<SymbolRelation> &Relations) {
+ if (!IndexCtx.getLangOpts().CPlusPlus)
+ return;
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(D->getLexicalDeclContext());
+ if (!CTSD)
+ return;
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ Template = CTSD->getSpecializedTemplateOrPartial();
+ if (const auto *CTD = Template.dyn_cast<ClassTemplateDecl *>()) {
+ const CXXRecordDecl *Pattern = CTD->getTemplatedDecl();
+ bool TypeOverride = isa<TypeDecl>(D);
+ for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) {
+ if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
+ ND = CTD->getTemplatedDecl();
+ if (ND->isImplicit())
+ continue;
+ // Types can override other types.
+ if (!TypeOverride) {
+ if (ND->getKind() != D->getKind())
+ continue;
+ } else if (!isa<TypeDecl>(ND))
+ continue;
+ if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+ const auto *DFD = cast<FunctionDecl>(D);
+ // Function overrides are approximated using the number of parameters.
+ if (FD->getStorageClass() != DFD->getStorageClass() ||
+ FD->getNumParams() != DFD->getNumParams())
+ continue;
+ }
+ Relations.emplace_back(
+ SymbolRoleSet(SymbolRole::RelationSpecializationOf), ND);
+ }
+ }
+ }
+ bool VisitFunctionDecl(const FunctionDecl *D) {
SymbolRoleSet Roles{};
SmallVector<SymbolRelation, 4> Relations;
if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
@@ -133,12 +238,19 @@ public:
Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
}
}
+ gatherTemplatePseudoOverrides(D, Relations);
+ if (const auto *Base = D->getPrimaryTemplate())
+ Relations.push_back(
+ SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
+ Base->getTemplatedDecl()));
- if (!IndexCtx.handleDecl(D, Roles, Relations))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations));
handleDeclarator(D);
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
+ IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(),
+ Ctor->getParent(), Ctor->getDeclContext());
+
// Constructor initializers.
for (const auto *Init : Ctor->inits()) {
if (Init->isWritten()) {
@@ -149,6 +261,22 @@ 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());
+ }
+ } else if (const auto *Guide = dyn_cast<CXXDeductionGuideDecl>(D)) {
+ IndexCtx.handleReference(Guide->getDeducedTemplate()->getTemplatedDecl(),
+ Guide->getLocation(), Guide,
+ Guide->getDeclContext());
+ }
+ // Template specialization arguments.
+ if (const ASTTemplateArgumentListInfo *TemplateArgInfo =
+ D->getTemplateSpecializationArgsAsWritten()) {
+ for (const auto &Arg : TemplateArgInfo->arguments())
+ handleTemplateArgumentLoc(Arg, D, D->getLexicalDeclContext());
}
if (D->isThisDeclarationADefinition()) {
@@ -161,16 +289,24 @@ public:
}
bool VisitVarDecl(const VarDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
handleDeclarator(D);
IndexCtx.indexBody(D->getInit(), D);
return true;
}
+ bool VisitDecompositionDecl(const DecompositionDecl *D) {
+ for (const auto *Binding : D->bindings())
+ TRY_DECL(Binding, IndexCtx.handleDecl(Binding));
+ return Base::VisitDecompositionDecl(D);
+ }
+
bool VisitFieldDecl(const FieldDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
handleDeclarator(D);
if (D->isBitField())
IndexCtx.indexBody(D->getBitWidth(), D);
@@ -184,8 +320,7 @@ public:
// handled in VisitObjCPropertyImplDecl
return true;
}
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
handleDeclarator(D);
return true;
}
@@ -196,16 +331,18 @@ public:
}
bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
IndexCtx.indexBody(D->getInitExpr(), D);
return true;
}
bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
- IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ if (!D->isTransparentTag()) {
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ }
return true;
}
@@ -213,12 +350,16 @@ public:
// Non-free standing tags are handled in indexTypeSourceInfo.
if (D->isFreeStanding()) {
if (D->isThisDeclarationADefinition()) {
- IndexCtx.indexTagDecl(D);
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ IndexCtx.indexTagDecl(D, Relations);
} else {
auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
+ SmallVector<SymbolRelation, 1> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
return IndexCtx.handleReference(D, D->getLocation(), Parent,
D->getLexicalDeclContext(),
- SymbolRoleSet());
+ SymbolRoleSet(), Relations);
}
}
return true;
@@ -243,7 +384,7 @@ public:
bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
if (D->isThisDeclarationADefinition()) {
- TRY_TO(IndexCtx.handleDecl(D));
+ TRY_DECL(D, IndexCtx.handleDecl(D));
SourceLocation SuperLoc = D->getSuperClassLoc();
if (auto *SuperD = D->getSuperClass()) {
bool hasSuperTypedef = false;
@@ -274,7 +415,7 @@ public:
bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
if (D->isThisDeclarationADefinition()) {
- TRY_TO(IndexCtx.handleDecl(D));
+ TRY_DECL(D, IndexCtx.handleDecl(D));
TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
/*superLoc=*/SourceLocation()));
TRY_TO(IndexCtx.indexDeclContext(D));
@@ -293,8 +434,7 @@ public:
if (Class->isImplicitInterfaceDecl())
IndexCtx.handleDecl(Class);
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
// Visit implicit @synthesize property implementations first as their
// location is reported at the name of the @implementation block. This
@@ -313,6 +453,8 @@ public:
}
bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+ if (!IndexCtx.shouldIndex(D))
+ return true;
const ObjCInterfaceDecl *C = D->getClassInterface();
if (!C)
return true;
@@ -341,8 +483,7 @@ public:
SourceLocation CategoryLoc = D->getCategoryNameLoc();
if (!CategoryLoc.isValid())
CategoryLoc = D->getLocation();
- if (!IndexCtx.handleDecl(D, CategoryLoc))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc));
IndexCtx.indexDeclContext(D);
return true;
}
@@ -364,8 +505,7 @@ public:
if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
handleObjCMethod(MD, D);
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>())
IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D,
D->getLexicalDeclContext(), false, true);
@@ -386,24 +526,23 @@ public:
Loc = Container->getLocation();
Roles |= (SymbolRoleSet)SymbolRole::Implicit;
}
- if (!IndexCtx.handleDecl(D, Loc, Roles, Relations))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations));
if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
return true;
assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
+ SymbolRoleSet AccessorMethodRoles =
+ SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit);
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
if (MD->isPropertyAccessor() &&
!hasUserDefined(MD, Container))
- IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {},
- Container);
+ IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
}
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
if (MD->isPropertyAccessor() &&
!hasUserDefined(MD, Container))
- IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {},
- Container);
+ IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
}
if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
if (IvarD->getSynthesize()) {
@@ -421,8 +560,7 @@ public:
} else if (D->getLocation() == IvarLoc) {
IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
}
- if(!IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles))
- return false;
+ TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles));
} else {
IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
D->getDeclContext(), SymbolRoleSet());
@@ -432,12 +570,19 @@ public:
}
bool VisitNamespaceDecl(const NamespaceDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
IndexCtx.indexDeclContext(D);
return true;
}
+ bool VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
+ TRY_DECL(D, IndexCtx.handleDecl(D));
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ IndexCtx.handleReference(D->getAliasedNamespace(), D->getTargetNameLoc(), D,
+ D->getLexicalDeclContext());
+ return true;
+ }
+
bool VisitUsingDecl(const UsingDecl *D) {
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
@@ -454,25 +599,94 @@ public:
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
- IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
- D->getLexicalDeclContext());
+ // NNS for the local 'using namespace' directives is visited by the body
+ // visitor.
+ if (!D->getParentFunctionOrMethod())
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
+ D->getLexicalDeclContext());
+
return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
D->getLocation(), Parent,
D->getLexicalDeclContext(),
SymbolRoleSet());
}
+ bool VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
+ TRY_DECL(D, IndexCtx.handleDecl(D));
+ const DeclContext *DC = D->getDeclContext()->getRedeclContext();
+ const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
+ D->getLexicalDeclContext());
+ return true;
+ }
+
+ bool VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
+ TRY_DECL(D, IndexCtx.handleDecl(D));
+ const DeclContext *DC = D->getDeclContext()->getRedeclContext();
+ const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
+ D->getLexicalDeclContext());
+ return true;
+ }
+
bool VisitClassTemplateSpecializationDecl(const
ClassTemplateSpecializationDecl *D) {
// FIXME: Notify subsequent callbacks if info comes from implicit
// instantiation.
- if (D->isThisDeclarationADefinition())
- IndexCtx.indexTagDecl(D);
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ Template = D->getSpecializedTemplateOrPartial();
+ const Decl *SpecializationOf =
+ Template.is<ClassTemplateDecl *>()
+ ? (Decl *)Template.get<ClassTemplateDecl *>()
+ : Template.get<ClassTemplatePartialSpecializationDecl *>();
+ if (!D->isThisDeclarationADefinition())
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ IndexCtx.indexTagDecl(
+ D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
+ SpecializationOf));
+ if (TypeSourceInfo *TSI = D->getTypeAsWritten())
+ IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr,
+ D->getLexicalDeclContext());
+ return true;
+ }
+
+ static bool shouldIndexTemplateParameterDefaultValue(const NamedDecl *D) {
+ if (!D)
+ return false;
+ // We want to index the template parameters only once when indexing the
+ // canonical declaration.
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getCanonicalDecl() == FD;
+ else if (const auto *TD = dyn_cast<TagDecl>(D))
+ return TD->getCanonicalDecl() == TD;
+ else if (const auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getCanonicalDecl() == VD;
return true;
}
bool VisitTemplateDecl(const TemplateDecl *D) {
- // FIXME: Template parameters.
+
+ // Index the default values for the template parameters.
+ const NamedDecl *Parent = D->getTemplatedDecl();
+ if (D->getTemplateParameters() &&
+ shouldIndexTemplateParameterDefaultValue(Parent)) {
+ const TemplateParameterList *Params = D->getTemplateParameters();
+ for (const NamedDecl *TP : *Params) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(TP)) {
+ if (TTP->hasDefaultArgument())
+ IndexCtx.indexTypeSourceInfo(TTP->getDefaultArgumentInfo(), Parent);
+ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TP)) {
+ if (NTTP->hasDefaultArgument())
+ IndexCtx.indexBody(NTTP->getDefaultArgument(), Parent);
+ } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(TP)) {
+ if (TTPD->hasDefaultArgument())
+ handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent,
+ TP->getLexicalDeclContext());
+ }
+ }
+ }
+
return Visit(D->getTemplatedDecl());
}
@@ -497,6 +711,13 @@ public:
bool VisitImportDecl(const ImportDecl *D) {
return IndexCtx.importedModule(D);
}
+
+ bool VisitStaticAssertDecl(const StaticAssertDecl *D) {
+ IndexCtx.indexBody(D->getAssertExpr(),
+ dyn_cast<NamedDecl>(D->getDeclContext()),
+ D->getLexicalDeclContext());
+ return true;
+ }
};
} // anonymous namespace
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index 785125cd5e..03db0cd53f 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -61,17 +61,21 @@ bool index::isFunctionLocalSymbol(const Decl *D) {
if (isa<ObjCTypeParamDecl>(D))
return true;
+ if (isa<UsingDirectiveDecl>(D))
+ return false;
if (!D->getParentFunctionOrMethod())
return false;
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
switch (ND->getFormalLinkage()) {
case NoLinkage:
- case VisibleNoLinkage:
case InternalLinkage:
return true;
+ case VisibleNoLinkage:
case UniqueExternalLinkage:
+ case ModuleInternalLinkage:
llvm_unreachable("Not a sema linkage");
+ case ModuleLinkage:
case ExternalLinkage:
return false;
}
@@ -197,25 +201,22 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Properties |= (unsigned)SymbolProperty::UnitTest;
break;
}
- case Decl::ObjCMethod:
- if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) {
- const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
- Info.Kind = SymbolKind::InstanceMethod;
- if (MD->isPropertyAccessor()) {
- if (MD->param_size())
- Info.SubKind = SymbolSubKind::AccessorSetter;
- else
- Info.SubKind = SymbolSubKind::AccessorGetter;
- }
- } else {
- Info.Kind = SymbolKind::ClassMethod;
+ case Decl::ObjCMethod: {
+ const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
+ Info.Kind = MD->isInstanceMethod() ? SymbolKind::InstanceMethod : SymbolKind::ClassMethod;
+ if (MD->isPropertyAccessor()) {
+ if (MD->param_size())
+ Info.SubKind = SymbolSubKind::AccessorSetter;
+ else
+ Info.SubKind = SymbolSubKind::AccessorGetter;
}
Info.Lang = SymbolLanguage::ObjC;
- if (isUnitTest(cast<ObjCMethodDecl>(D)))
+ if (isUnitTest(MD))
Info.Properties |= (unsigned)SymbolProperty::UnitTest;
if (D->hasAttr<IBActionAttr>())
Info.Properties |= (unsigned)SymbolProperty::IBAnnotated;
break;
+ }
case Decl::ObjCProperty:
Info.Kind = SymbolKind::InstanceProperty;
Info.Lang = SymbolLanguage::ObjC;
@@ -299,6 +300,22 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Kind = SymbolKind::TypeAlias;
Info.Lang = SymbolLanguage::CXX;
break;
+ case Decl::UnresolvedUsingTypename:
+ Info.Kind = SymbolKind::Using;
+ Info.SubKind = SymbolSubKind::UsingTypename;
+ Info.Lang = SymbolLanguage::CXX;
+ Info.Properties |= (unsigned)SymbolProperty::Generic;
+ break;
+ case Decl::UnresolvedUsingValue:
+ Info.Kind = SymbolKind::Using;
+ Info.SubKind = SymbolSubKind::UsingValue;
+ Info.Lang = SymbolLanguage::CXX;
+ Info.Properties |= (unsigned)SymbolProperty::Generic;
+ break;
+ case Decl::Binding:
+ Info.Kind = SymbolKind::Variable;
+ Info.Lang = SymbolLanguage::CXX;
+ break;
default:
break;
}
@@ -318,14 +335,20 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
if (Info.Properties & (unsigned)SymbolProperty::Generic)
Info.Lang = SymbolLanguage::CXX;
+ if (auto *attr = D->getExternalSourceSymbolAttr()) {
+ if (attr->getLanguage() == "Swift")
+ Info.Lang = SymbolLanguage::Swift;
+ }
+
return Info;
}
-void index::applyForEachSymbolRole(SymbolRoleSet Roles,
- llvm::function_ref<void(SymbolRole)> Fn) {
+bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles,
+ llvm::function_ref<bool(SymbolRole)> Fn) {
#define APPLY_FOR_ROLE(Role) \
if (Roles & (unsigned)SymbolRole::Role) \
- Fn(SymbolRole::Role)
+ if (!Fn(SymbolRole::Role)) \
+ return false;
APPLY_FOR_ROLE(Declaration);
APPLY_FOR_ROLE(Definition);
@@ -345,8 +368,19 @@ void index::applyForEachSymbolRole(SymbolRoleSet Roles,
APPLY_FOR_ROLE(RelationAccessorOf);
APPLY_FOR_ROLE(RelationContainedBy);
APPLY_FOR_ROLE(RelationIBTypeOf);
+ APPLY_FOR_ROLE(RelationSpecializationOf);
#undef APPLY_FOR_ROLE
+
+ return true;
+}
+
+void index::applyForEachSymbolRole(SymbolRoleSet Roles,
+ llvm::function_ref<void(SymbolRole)> Fn) {
+ applyForEachSymbolRoleInterruptible(Roles, [&](SymbolRole r) -> bool {
+ Fn(r);
+ return true;
+ });
}
void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
@@ -375,6 +409,7 @@ void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break;
case SymbolRole::RelationContainedBy: OS << "RelCont"; break;
case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break;
+ case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break;
}
});
}
@@ -425,6 +460,7 @@ StringRef index::getSymbolKindString(SymbolKind K) {
case SymbolKind::Destructor: return "destructor";
case SymbolKind::ConversionFunction: return "coversion-func";
case SymbolKind::Parameter: return "param";
+ case SymbolKind::Using: return "using";
}
llvm_unreachable("invalid symbol kind");
}
@@ -436,6 +472,8 @@ StringRef index::getSymbolSubKindString(SymbolSubKind K) {
case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor";
case SymbolSubKind::AccessorGetter: return "acc-get";
case SymbolSubKind::AccessorSetter: return "acc-set";
+ case SymbolSubKind::UsingTypename: return "using-typename";
+ case SymbolSubKind::UsingValue: return "using-value";
}
llvm_unreachable("invalid symbol subkind");
}
@@ -445,6 +483,7 @@ StringRef index::getSymbolLanguageString(SymbolLanguage K) {
case SymbolLanguage::C: return "C";
case SymbolLanguage::ObjC: return "ObjC";
case SymbolLanguage::CXX: return "C++";
+ case SymbolLanguage::Swift: return "Swift";
}
llvm_unreachable("invalid symbol language kind");
}
diff --git a/lib/Index/IndexTypeSourceInfo.cpp b/lib/Index/IndexTypeSourceInfo.cpp
index 33848da0cb..c8ff3d72d4 100644
--- a/lib/Index/IndexTypeSourceInfo.cpp
+++ b/lib/Index/IndexTypeSourceInfo.cpp
@@ -47,9 +47,15 @@ public:
} 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) {
- SourceLocation Loc = TL.getNameLoc();
- TRY_TO(IndexCtx.handleReference(TL.getTypedefNameDecl(), Loc,
+ TRY_TO(IndexCtx.handleReference(ND, Loc,
Parent, ParentDC, SymbolRoleSet()));
if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
@@ -57,7 +63,7 @@ public:
Relations));
}
} else {
- TRY_TO(IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(),
+ TRY_TO(IndexCtx.handleReference(ND, Loc,
Parent, ParentDC, SymbolRoleSet(),
Relations));
}
@@ -120,8 +126,9 @@ public:
return true;
}
- bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
- if (const TemplateSpecializationType *T = TL.getTypePtr()) {
+ template<typename TypeLocType>
+ bool HandleTemplateSpecializationTypeLoc(TypeLocType TL) {
+ if (const auto *T = TL.getTypePtr()) {
if (IndexCtx.shouldIndexImplicitTemplateInsts()) {
if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
IndexCtx.handleReference(RD, TL.getTemplateNameLoc(),
@@ -135,6 +142,42 @@ public:
return true;
}
+ bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
+ return HandleTemplateSpecializationTypeLoc(TL);
+ }
+
+ bool VisitDeducedTemplateSpecializationTypeLoc(DeducedTemplateSpecializationTypeLoc TL) {
+ return HandleTemplateSpecializationTypeLoc(TL);
+ }
+
+ bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ const DependentNameType *DNT = TL.getTypePtr();
+ const NestedNameSpecifier *NNS = DNT->getQualifier();
+ const Type *T = NNS->getAsType();
+ if (!T)
+ return true;
+ const TemplateSpecializationType *TST =
+ T->getAs<TemplateSpecializationType>();
+ if (!TST)
+ return true;
+ TemplateName TN = TST->getTemplateName();
+ const ClassTemplateDecl *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return true;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ if (!RD->hasDefinition())
+ return true;
+ RD = RD->getDefinition();
+ DeclarationName Name(DNT->getIdentifier());
+ std::vector<const NamedDecl *> Symbols = RD->lookupDependentName(
+ Name, [](const NamedDecl *ND) { return isa<TypeDecl>(ND); });
+ if (Symbols.size() != 1)
+ return true;
+ return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,
+ ParentDC, SymbolRoleSet(), Relations);
+ }
+
bool TraverseStmt(Stmt *S) {
IndexCtx.indexBody(S, Parent, ParentDC);
return true;
@@ -178,7 +221,7 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
if (!DC)
DC = Parent->getLexicalDeclContext();
- SourceLocation Loc = NNS.getSourceRange().getBegin();
+ SourceLocation Loc = NNS.getLocalBeginLoc();
switch (NNS.getNestedNameSpecifier()->getKind()) {
case NestedNameSpecifier::Identifier:
@@ -202,11 +245,14 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
}
}
-void IndexingContext::indexTagDecl(const TagDecl *D) {
+void IndexingContext::indexTagDecl(const TagDecl *D,
+ ArrayRef<SymbolRelation> Relations) {
+ if (!shouldIndex(D))
+ return;
if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
return;
- if (handleDecl(D)) {
+ if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {
if (D->isThisDeclarationADefinition()) {
indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
diff --git a/lib/Index/IndexingAction.cpp b/lib/Index/IndexingAction.cpp
index cac24d4b9c..84d31200ba 100644
--- a/lib/Index/IndexingAction.cpp
+++ b/lib/Index/IndexingAction.cpp
@@ -177,6 +177,18 @@ void index::indexASTUnit(ASTUnit &Unit,
DataConsumer->finish();
}
+void index::indexTopLevelDecls(ASTContext &Ctx, ArrayRef<const Decl *> Decls,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts) {
+ IndexingContext IndexCtx(Opts, *DataConsumer);
+ IndexCtx.setASTContext(Ctx);
+
+ DataConsumer->initialize(Ctx);
+ for (const Decl *D : Decls)
+ IndexCtx.indexTopLevelDecl(D);
+ DataConsumer->finish();
+}
+
void index::indexModuleFile(serialization::ModuleFile &Mod,
ASTReader &Reader,
std::shared_ptr<IndexDataConsumer> DataConsumer,
diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp
index 9a4028f5c5..de9fe39df0 100644
--- a/lib/Index/IndexingContext.cpp
+++ b/lib/Index/IndexingContext.cpp
@@ -17,6 +17,21 @@
using namespace clang;
using namespace index;
+static bool isGeneratedDecl(const Decl *D) {
+ if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
+ return attr->getGeneratedDeclaration();
+ }
+ return false;
+}
+
+bool IndexingContext::shouldIndex(const Decl *D) {
+ return !isGeneratedDecl(D);
+}
+
+const LangOptions &IndexingContext::getLangOpts() const {
+ return Ctx->getLangOpts();
+}
+
bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
return IndexOpts.IndexFunctionLocals;
}
@@ -109,6 +124,16 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
TKind = FD->getTemplateSpecializationKind();
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
TKind = VD->getTemplateSpecializationKind();
+ } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (RD->getInstantiatedFromMemberClass())
+ TKind = RD->getTemplateSpecializationKind();
+ } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ if (ED->getInstantiatedFromMemberEnum())
+ TKind = ED->getTemplateSpecializationKind();
+ } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
+ isa<EnumConstantDecl>(D)) {
+ if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
+ return isTemplateImplicitInstantiation(Parent);
}
switch (TKind) {
case TSK_Undeclared:
@@ -136,6 +161,16 @@ bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
return true;
}
+static const CXXRecordDecl *
+getDeclContextForTemplateInstationPattern(const Decl *D) {
+ if (const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
+ return CTSD->getTemplateInstantiationPattern();
+ else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
+ return RD->getInstantiatedFromMemberClass();
+ return nullptr;
+}
+
static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
if (const ClassTemplateSpecializationDecl *
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
@@ -144,6 +179,28 @@ static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
return FD->getTemplateInstantiationPattern();
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
return VD->getTemplateInstantiationPattern();
+ } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ return RD->getInstantiatedFromMemberClass();
+ } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ return ED->getInstantiatedFromMemberEnum();
+ } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
+ const auto *ND = cast<NamedDecl>(D);
+ if (const CXXRecordDecl *Pattern =
+ getDeclContextForTemplateInstationPattern(ND)) {
+ for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
+ if (BaseND->isImplicit())
+ continue;
+ if (BaseND->getKind() == ND->getKind())
+ return BaseND;
+ }
+ }
+ } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
+ if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
+ if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
+ for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
+ return BaseECD;
+ }
+ }
}
return nullptr;
}
@@ -172,6 +229,12 @@ static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, AST
return false;
}
+/// Whether the given NamedDecl should be skipped because it has no name.
+static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
+ return (ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
+ !isa<ObjCCategoryDecl>(ND)) || isa<CXXDeductionGuideDecl>(ND);
+}
+
static const Decl *adjustParent(const Decl *Parent) {
if (!Parent)
return nullptr;
@@ -186,8 +249,8 @@ static const Decl *adjustParent(const Decl *Parent) {
} else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
if (RD->isAnonymousStructOrUnion())
continue;
- } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
- if (FD->getDeclName().isEmpty())
+ } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
+ if (shouldSkipNamelessDecl(ND))
continue;
}
return Parent;
@@ -197,13 +260,60 @@ static const Decl *adjustParent(const Decl *Parent) {
static const Decl *getCanonicalDecl(const Decl *D) {
D = D->getCanonicalDecl();
if (auto TD = dyn_cast<TemplateDecl>(D)) {
- D = TD->getTemplatedDecl();
- assert(D->isCanonicalDecl());
+ if (auto TTD = TD->getTemplatedDecl()) {
+ D = TTD;
+ assert(D->isCanonicalDecl());
+ }
}
return D;
}
+static bool shouldReportOccurrenceForSystemDeclOnlyMode(
+ bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
+ if (!IsRef)
+ return true;
+
+ auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
+ bool accept = false;
+ applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
+ switch (r) {
+ case SymbolRole::RelationChildOf:
+ case SymbolRole::RelationBaseOf:
+ case SymbolRole::RelationOverrideOf:
+ case SymbolRole::RelationExtendedBy:
+ case SymbolRole::RelationAccessorOf:
+ case SymbolRole::RelationIBTypeOf:
+ accept = true;
+ return false;
+ case SymbolRole::Declaration:
+ case SymbolRole::Definition:
+ case SymbolRole::Reference:
+ case SymbolRole::Read:
+ case SymbolRole::Write:
+ case SymbolRole::Call:
+ case SymbolRole::Dynamic:
+ case SymbolRole::AddressOf:
+ case SymbolRole::Implicit:
+ case SymbolRole::RelationReceivedBy:
+ case SymbolRole::RelationCalledBy:
+ case SymbolRole::RelationContainedBy:
+ case SymbolRole::RelationSpecializationOf:
+ return true;
+ }
+ llvm_unreachable("Unsupported SymbolRole value!");
+ });
+ return accept;
+ };
+
+ for (auto &Rel : Relations) {
+ if (acceptForRelation(Rel.Roles))
+ return true;
+ }
+
+ return false;
+}
+
bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
bool IsRef, const Decl *Parent,
SymbolRoleSet Roles,
@@ -213,9 +323,7 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
const DeclContext *ContainerDC) {
if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
return true;
- if (!isa<NamedDecl>(D) ||
- (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
- !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
+ if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
return true;
SourceManager &SM = Ctx->getSourceManager();
@@ -239,7 +347,7 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
case IndexingOptions::SystemSymbolFilterKind::None:
return true;
case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
- if (IsRef)
+ if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
return true;
break;
case IndexingOptions::SystemSymbolFilterKind::All:
diff --git a/lib/Index/IndexingContext.h b/lib/Index/IndexingContext.h
index 5f4215858c..566651c83a 100644
--- a/lib/Index/IndexingContext.h
+++ b/lib/Index/IndexingContext.h
@@ -48,6 +48,10 @@ public:
void setASTContext(ASTContext &ctx) { Ctx = &ctx; }
+ bool shouldIndex(const Decl *D);
+
+ const LangOptions &getLangOpts() const;
+
bool shouldSuppressRefs() const {
return false;
}
@@ -71,7 +75,7 @@ public:
bool handleReference(const NamedDecl *D, SourceLocation Loc,
const NamedDecl *Parent,
const DeclContext *DC,
- SymbolRoleSet Roles,
+ SymbolRoleSet Roles = SymbolRoleSet(),
ArrayRef<SymbolRelation> Relations = None,
const Expr *RefE = nullptr,
const Decl *RefD = nullptr);
@@ -80,7 +84,8 @@ public:
bool indexDecl(const Decl *D);
- void indexTagDecl(const TagDecl *D);
+ void indexTagDecl(const TagDecl *D,
+ ArrayRef<SymbolRelation> Relations = None);
void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent,
const DeclContext *DC = nullptr,
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
index 73dddd9a8b..3a06554b25 100644
--- a/lib/Index/USRGeneration.cpp
+++ b/lib/Index/USRGeneration.cpp
@@ -46,6 +46,15 @@ static bool printLoc(llvm::raw_ostream &OS, SourceLocation Loc,
return false;
}
+static StringRef GetExternalSourceContainer(const NamedDecl *D) {
+ if (!D)
+ return StringRef();
+ if (auto *attr = D->getExternalSourceSymbolAttr()) {
+ return attr->getDefinedIn();
+ }
+ return StringRef();
+}
+
namespace {
class USRGenerator : public ConstDeclVisitor<USRGenerator> {
SmallVectorImpl<char> &Buf;
@@ -79,7 +88,8 @@ public:
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
void VisitClassTemplateDecl(const ClassTemplateDecl *D);
- void VisitObjCContainerDecl(const ObjCContainerDecl *CD);
+ void VisitObjCContainerDecl(const ObjCContainerDecl *CD,
+ const ObjCCategoryDecl *CatD = nullptr);
void VisitObjCMethodDecl(const ObjCMethodDecl *MD);
void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
@@ -89,6 +99,8 @@ public:
void VisitVarDecl(const VarDecl *D);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
+ void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
void VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
IgnoreResults = true;
@@ -102,20 +114,14 @@ public:
IgnoreResults = true;
}
- void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
- IgnoreResults = true;
- }
-
- void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
- IgnoreResults = true;
- }
-
bool ShouldGenerateLocation(const NamedDecl *D);
bool isLocal(const NamedDecl *D) {
return D->getParentFunctionOrMethod() != nullptr;
}
+ void GenExtSymbolContainer(const NamedDecl *D);
+
/// Generate the string component containing the location of the
/// declaration.
bool GenLoc(const Decl *D, bool IncludeOffset);
@@ -127,13 +133,16 @@ public:
/// itself.
/// Generate a USR for an Objective-C class.
- void GenObjCClass(StringRef cls) {
- generateUSRForObjCClass(cls, Out);
+ void GenObjCClass(StringRef cls, StringRef ExtSymDefinedIn,
+ StringRef CategoryContextExtSymbolDefinedIn) {
+ generateUSRForObjCClass(cls, Out, ExtSymDefinedIn,
+ CategoryContextExtSymbolDefinedIn);
}
/// Generate a USR for an Objective-C class category.
- void GenObjCCategory(StringRef cls, StringRef cat) {
- generateUSRForObjCCategory(cls, cat, Out);
+ void GenObjCCategory(StringRef cls, StringRef cat,
+ StringRef clsExt, StringRef catExt) {
+ generateUSRForObjCCategory(cls, cat, Out, clsExt, catExt);
}
/// Generate a USR fragment for an Objective-C property.
@@ -142,8 +151,8 @@ public:
}
/// Generate a USR for an Objective-C protocol.
- void GenObjCProtocol(StringRef prot) {
- generateUSRForObjCProtocol(prot, Out);
+ void GenObjCProtocol(StringRef prot, StringRef ext) {
+ generateUSRForObjCProtocol(prot, Out, ext);
}
void VisitType(QualType T);
@@ -204,7 +213,11 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
+ const unsigned StartSize = Buf.size();
VisitDeclContext(D->getDeclContext());
+ if (Buf.size() == StartSize)
+ GenExtSymbolContainer(D);
+
bool IsTemplate = false;
if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) {
IsTemplate = true;
@@ -367,7 +380,16 @@ void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
IgnoreResults = true;
return;
}
- Visit(ID);
+ auto getCategoryContext = [](const ObjCMethodDecl *D) ->
+ const ObjCCategoryDecl * {
+ if (auto *CD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))
+ return CD;
+ if (auto *ICD = dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
+ return ICD->getCategoryDecl();
+ return nullptr;
+ };
+ auto *CD = getCategoryContext(D);
+ VisitObjCContainerDecl(ID, CD);
}
// Ideally we would use 'GenObjCMethod', but this is such a hot path
// for Objective-C code that we don't want to use
@@ -376,13 +398,15 @@ void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
<< DeclarationName(D->getSelector());
}
-void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
+void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D,
+ const ObjCCategoryDecl *CatD) {
switch (D->getKind()) {
default:
llvm_unreachable("Invalid ObjC container.");
case Decl::ObjCInterface:
case Decl::ObjCImplementation:
- GenObjCClass(D->getName());
+ GenObjCClass(D->getName(), GetExternalSourceContainer(D),
+ GetExternalSourceContainer(CatD));
break;
case Decl::ObjCCategory: {
const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
@@ -402,7 +426,9 @@ void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
GenLoc(CD, /*IncludeOffset=*/true);
}
else
- GenObjCCategory(ID->getName(), CD->getName());
+ GenObjCCategory(ID->getName(), CD->getName(),
+ GetExternalSourceContainer(ID),
+ GetExternalSourceContainer(CD));
break;
}
@@ -417,12 +443,16 @@ void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
IgnoreResults = true;
return;
}
- GenObjCCategory(ID->getName(), CD->getName());
+ GenObjCCategory(ID->getName(), CD->getName(),
+ GetExternalSourceContainer(ID),
+ GetExternalSourceContainer(CD));
break;
}
- case Decl::ObjCProtocol:
- GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
+ case Decl::ObjCProtocol: {
+ const ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D);
+ GenObjCProtocol(PD->getName(), GetExternalSourceContainer(PD));
break;
+ }
}
}
@@ -452,6 +482,8 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
+ GenExtSymbolContainer(D);
+
D = D->getCanonicalDecl();
VisitDeclContext(D->getDeclContext());
@@ -544,6 +576,12 @@ void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
GenLoc(D, /*IncludeOffset=*/true);
}
+void USRGenerator::GenExtSymbolContainer(const NamedDecl *D) {
+ StringRef Container = GetExternalSourceContainer(D);
+ if (!Container.empty())
+ Out << "@M@" << Container;
+}
+
bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) {
if (generatedLoc)
return IgnoreResults;
@@ -565,6 +603,16 @@ bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) {
return IgnoreResults;
}
+static void printQualifier(llvm::raw_ostream &Out, ASTContext &Ctx, NestedNameSpecifier *NNS) {
+ // FIXME: Encode the qualifier, don't just print it.
+ PrintingPolicy PO(Ctx.getLangOpts());
+ PO.SuppressTagKeyword = true;
+ PO.SuppressUnwrittenScope = true;
+ PO.ConstantArraySizeAsWritten = false;
+ PO.AnonymousTagLocations = false;
+ NNS->print(Out, PO);
+}
+
void USRGenerator::VisitType(QualType T) {
// This method mangles in USR information for types. It can possibly
// just reuse the naming-mangling logic used by codegen, although the
@@ -632,6 +680,7 @@ void USRGenerator::VisitType(QualType T) {
c = 'K'; break;
case BuiltinType::Int128:
c = 'J'; break;
+ case BuiltinType::Float16:
case BuiltinType::Half:
c = 'h'; break;
case BuiltinType::Float:
@@ -705,8 +754,12 @@ void USRGenerator::VisitType(QualType T) {
if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
Out << 'F';
VisitType(FT->getReturnType());
- for (const auto &I : FT->param_types())
+ Out << '(';
+ for (const auto &I : FT->param_types()) {
+ Out << '#';
VisitType(I);
+ }
+ Out << ')';
if (FT->isVariadic())
Out << '.';
return;
@@ -753,13 +806,7 @@ void USRGenerator::VisitType(QualType T) {
}
if (const DependentNameType *DNT = T->getAs<DependentNameType>()) {
Out << '^';
- // FIXME: Encode the qualifier, don't just print it.
- PrintingPolicy PO(Ctx.getLangOpts());
- PO.SuppressTagKeyword = true;
- PO.SuppressUnwrittenScope = true;
- PO.ConstantArraySizeAsWritten = false;
- PO.AnonymousTagLocations = false;
- DNT->getQualifier()->print(Out, PO);
+ printQualifier(Out, Ctx, DNT->getQualifier());
Out << ':' << DNT->getIdentifier()->getName();
return;
}
@@ -767,7 +814,32 @@ void USRGenerator::VisitType(QualType T) {
T = InjT->getInjectedSpecializationType();
continue;
}
-
+ if (const auto *VT = T->getAs<VectorType>()) {
+ Out << (T->isExtVectorType() ? ']' : '[');
+ Out << VT->getNumElements();
+ T = VT->getElementType();
+ continue;
+ }
+ if (const auto *const AT = dyn_cast<ArrayType>(T)) {
+ Out << '{';
+ switch (AT->getSizeModifier()) {
+ case ArrayType::Static:
+ Out << 's';
+ break;
+ case ArrayType::Star:
+ Out << '*';
+ break;
+ case ArrayType::Normal:
+ Out << 'n';
+ break;
+ }
+ if (const auto *const CAT = dyn_cast<ConstantArrayType>(T))
+ Out << CAT->getSize();
+
+ T = AT->getElementType();
+ continue;
+ }
+
// Unhandled type.
Out << ' ';
break;
@@ -862,16 +934,58 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
}
}
+void USRGenerator::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
+ return;
+ VisitDeclContext(D->getDeclContext());
+ Out << "@UUV@";
+ printQualifier(Out, D->getASTContext(), D->getQualifier());
+ EmitDeclName(D);
+}
+
+void USRGenerator::VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
+ if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
+ return;
+ VisitDeclContext(D->getDeclContext());
+ Out << "@UUT@";
+ printQualifier(Out, D->getASTContext(), D->getQualifier());
+ Out << D->getName(); // Simple name.
+}
+
+
+
//===----------------------------------------------------------------------===//
// USR generation functions.
//===----------------------------------------------------------------------===//
-void clang::index::generateUSRForObjCClass(StringRef Cls, raw_ostream &OS) {
+static void combineClassAndCategoryExtContainers(StringRef ClsSymDefinedIn,
+ StringRef CatSymDefinedIn,
+ raw_ostream &OS) {
+ if (ClsSymDefinedIn.empty() && CatSymDefinedIn.empty())
+ return;
+ if (CatSymDefinedIn.empty()) {
+ OS << "@M@" << ClsSymDefinedIn << '@';
+ return;
+ }
+ OS << "@CM@" << CatSymDefinedIn << '@';
+ if (ClsSymDefinedIn != CatSymDefinedIn) {
+ OS << ClsSymDefinedIn << '@';
+ }
+}
+
+void clang::index::generateUSRForObjCClass(StringRef Cls, raw_ostream &OS,
+ StringRef ExtSymDefinedIn,
+ StringRef CategoryContextExtSymbolDefinedIn) {
+ combineClassAndCategoryExtContainers(ExtSymDefinedIn,
+ CategoryContextExtSymbolDefinedIn, OS);
OS << "objc(cs)" << Cls;
}
void clang::index::generateUSRForObjCCategory(StringRef Cls, StringRef Cat,
- raw_ostream &OS) {
+ raw_ostream &OS,
+ StringRef ClsSymDefinedIn,
+ StringRef CatSymDefinedIn) {
+ combineClassAndCategoryExtContainers(ClsSymDefinedIn, CatSymDefinedIn, OS);
OS << "objc(cy)" << Cls << '@' << Cat;
}
@@ -890,10 +1004,25 @@ void clang::index::generateUSRForObjCProperty(StringRef Prop, bool isClassProp,
OS << (isClassProp ? "(cpy)" : "(py)") << Prop;
}
-void clang::index::generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS) {
+void clang::index::generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS,
+ StringRef ExtSymDefinedIn) {
+ if (!ExtSymDefinedIn.empty())
+ OS << "@M@" << ExtSymDefinedIn << '@';
OS << "objc(pl)" << Prot;
}
+void clang::index::generateUSRForGlobalEnum(StringRef EnumName, raw_ostream &OS,
+ StringRef ExtSymDefinedIn) {
+ if (!ExtSymDefinedIn.empty())
+ OS << "@M@" << ExtSymDefinedIn;
+ OS << "@E@" << EnumName;
+}
+
+void clang::index::generateUSRForEnumConstant(StringRef EnumConstantName,
+ raw_ostream &OS) {
+ OS << '@' << EnumConstantName;
+}
+
bool clang::index::generateUSRForDecl(const Decl *D,
SmallVectorImpl<char> &Buf) {
if (!D)
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 4ee3871928..b18d27376a 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -128,21 +128,24 @@ void HeaderSearch::getHeaderMapFileNames(
Names.push_back(HM.first->getName());
}
-std::string HeaderSearch::getModuleFileName(Module *Module) {
+std::string HeaderSearch::getCachedModuleFileName(Module *Module) {
const FileEntry *ModuleMap =
getModuleMap().getModuleMapFileForUniquing(Module);
- return getModuleFileName(Module->Name, ModuleMap->getName(),
- /*UsePrebuiltPath*/false);
+ return getCachedModuleFileName(Module->Name, ModuleMap->getName());
}
-std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
- StringRef ModuleMapPath,
- bool UsePrebuiltPath) {
- if (UsePrebuiltPath) {
- if (HSOpts->PrebuiltModulePaths.empty())
+std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName,
+ bool FileMapOnly) {
+ // First check the module name to pcm file map.
+ auto i (HSOpts->PrebuiltModuleFiles.find(ModuleName));
+ if (i != HSOpts->PrebuiltModuleFiles.end())
+ return i->second;
+
+ if (FileMapOnly || HSOpts->PrebuiltModulePaths.empty())
return std::string();
- // Go though each prebuilt module path and try to find the pcm file.
+ // Then go through each prebuilt module directory and try to find the pcm
+ // file.
for (const std::string &Dir : HSOpts->PrebuiltModulePaths) {
SmallString<256> Result(Dir);
llvm::sys::fs::make_absolute(Result);
@@ -154,6 +157,8 @@ std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
return std::string();
}
+std::string HeaderSearch::getCachedModuleFileName(StringRef ModuleName,
+ StringRef ModuleMapPath) {
// If we don't have a module cache path or aren't supposed to use one, we
// can't do anything.
if (getModuleCachePath().empty())
@@ -624,7 +629,10 @@ const FileEntry *HeaderSearch::LookupFile(
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache, bool BuildSystemModule) {
+ bool *IsMapped, bool SkipCache, bool BuildSystemModule) {
+ if (IsMapped)
+ *IsMapped = false;
+
if (SuggestedModule)
*SuggestedModule = ModuleMap::KnownHeader();
@@ -754,8 +762,11 @@ const FileEntry *HeaderSearch::LookupFile(
if (!SkipCache && CacheLookup.StartIdx == i+1) {
// Skip querying potentially lots of directories for this lookup.
i = CacheLookup.HitIdx;
- if (CacheLookup.MappedName)
+ if (CacheLookup.MappedName) {
Filename = CacheLookup.MappedName;
+ if (IsMapped)
+ *IsMapped = true;
+ }
} else {
// Otherwise, this is the first query, or the previous query didn't match
// our search start. We will fill in our found location below, so prime the
@@ -776,6 +787,8 @@ const FileEntry *HeaderSearch::LookupFile(
if (HasBeenMapped) {
CacheLookup.MappedName =
copyString(Filename, LookupFileCache.getAllocator());
+ if (IsMapped)
+ *IsMapped = true;
}
if (!FE) continue;
@@ -839,7 +852,7 @@ const FileEntry *HeaderSearch::LookupFile(
const FileEntry *FE =
LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir,
CurDir, Includers.front(), SearchPath, RelativePath,
- RequestingModule, SuggestedModule);
+ RequestingModule, SuggestedModule, IsMapped);
if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
if (SuggestedModule)
@@ -1106,6 +1119,8 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
auto TryEnterImported = [&](void) -> bool {
if (!ModulesEnabled)
return false;
+ // Ensure FileInfo bits are up to date.
+ ModMap.resolveHeaderDirectives(File);
// Modules with builtins are special; multiple modules use builtins as
// modular headers, example:
//
@@ -1317,14 +1332,28 @@ static const FileEntry *getPrivateModuleMap(const FileEntry *File,
return FileMgr.getFile(PrivateFilename);
}
-bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
+bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
+ FileID ID, unsigned *Offset,
+ StringRef OriginalModuleMapFile) {
// Find the directory for the module. For frameworks, that may require going
// up from the 'Modules' directory.
const DirectoryEntry *Dir = nullptr;
if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd)
Dir = FileMgr.getDirectory(".");
else {
- Dir = File->getDir();
+ if (!OriginalModuleMapFile.empty()) {
+ // We're building a preprocessed module map. Find or invent the directory
+ // that it originally occupied.
+ Dir = FileMgr.getDirectory(
+ llvm::sys::path::parent_path(OriginalModuleMapFile));
+ if (!Dir) {
+ auto *FakeFile = FileMgr.getVirtualFile(OriginalModuleMapFile, 0, 0);
+ Dir = FakeFile->getDir();
+ }
+ } else {
+ Dir = File->getDir();
+ }
+
StringRef DirName(Dir->getName());
if (llvm::sys::path::filename(DirName) == "Modules") {
DirName = llvm::sys::path::parent_path(DirName);
@@ -1336,7 +1365,7 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
}
}
- switch (loadModuleMapFileImpl(File, IsSystem, Dir)) {
+ switch (loadModuleMapFileImpl(File, IsSystem, Dir, ID, Offset)) {
case LMM_AlreadyLoaded:
case LMM_NewlyLoaded:
return false;
@@ -1349,7 +1378,8 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
HeaderSearch::LoadModuleMapResult
HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem,
- const DirectoryEntry *Dir) {
+ const DirectoryEntry *Dir, FileID ID,
+ unsigned *Offset) {
assert(File && "expected FileEntry");
// Check whether we've already loaded this module map, and mark it as being
@@ -1358,7 +1388,7 @@ HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem,
if (!AddResult.second)
return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
- if (ModMap.parseModuleMapFile(File, IsSystem, Dir)) {
+ if (ModMap.parseModuleMapFile(File, IsSystem, Dir, ID, Offset)) {
LoadedModuleMaps[File] = false;
return LMM_InvalidModuleMap;
}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 6025a66751..5132d0e62c 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -19,6 +19,7 @@
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
@@ -43,6 +44,8 @@ using namespace clang;
/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier.
bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
+ if (isAnnotation())
+ return false;
if (IdentifierInfo *II = getIdentifierInfo())
return II->getObjCKeywordID() == objcKey;
return false;
@@ -50,6 +53,8 @@ bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
/// getObjCKeywordID - Return the ObjC keyword kind.
tok::ObjCKeywordKind Token::getObjCKeywordID() const {
+ if (isAnnotation())
+ return tok::objc_not_keyword;
IdentifierInfo *specId = getIdentifierInfo();
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
}
@@ -452,6 +457,25 @@ bool Lexer::getRawToken(SourceLocation Loc, Token &Result,
return false;
}
+/// Returns the pointer that points to the beginning of line that contains
+/// the given offset, or null if the offset if invalid.
+static const char *findBeginningOfLine(StringRef Buffer, unsigned Offset) {
+ const char *BufStart = Buffer.data();
+ if (Offset >= Buffer.size())
+ return nullptr;
+
+ const char *LexStart = BufStart + Offset;
+ for (; LexStart != BufStart; --LexStart) {
+ if (isVerticalWhitespace(LexStart[0]) &&
+ !Lexer::isNewLineEscaped(BufStart, LexStart)) {
+ // LexStart should point at first character of logical line.
+ ++LexStart;
+ break;
+ }
+ }
+ return LexStart;
+}
+
static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
@@ -459,7 +483,7 @@ static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
if (LocInfo.first.isInvalid())
return Loc;
-
+
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
@@ -467,47 +491,35 @@ static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
// Back up from the current location until we hit the beginning of a line
// (or the buffer). We'll relex from that point.
- const char *BufStart = Buffer.data();
- if (LocInfo.second >= Buffer.size())
+ const char *StrData = Buffer.data() + LocInfo.second;
+ const char *LexStart = findBeginningOfLine(Buffer, LocInfo.second);
+ if (!LexStart || LexStart == StrData)
return Loc;
-
- const char *StrData = BufStart+LocInfo.second;
- if (StrData[0] == '\n' || StrData[0] == '\r')
- return Loc;
-
- const char *LexStart = StrData;
- while (LexStart != BufStart) {
- if (LexStart[0] == '\n' || LexStart[0] == '\r') {
- ++LexStart;
- break;
- }
- --LexStart;
- }
-
// Create a lexer starting at the beginning of this token.
SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second);
- Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end());
+ Lexer TheLexer(LexerStartLoc, LangOpts, Buffer.data(), LexStart,
+ Buffer.end());
TheLexer.SetCommentRetentionState(true);
-
+
// Lex tokens until we find the token that contains the source location.
Token TheTok;
do {
TheLexer.LexFromRawLexer(TheTok);
-
+
if (TheLexer.getBufferLocation() > StrData) {
// Lexing this token has taken the lexer past the source location we're
// looking for. If the current token encompasses our source location,
// return the beginning of that token.
if (TheLexer.getBufferLocation() - TheTok.getLength() <= StrData)
return TheTok.getLocation();
-
+
// We ended up skipping over the source location entirely, which means
// that it points into whitespace. We're done here.
break;
}
} while (TheTok.getKind() != tok::eof);
-
+
// We've passed our source location; just return the original source location.
return Loc;
}
@@ -515,36 +527,34 @@ static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
- if (Loc.isFileID())
- return getBeginningOfFileToken(Loc, SM, LangOpts);
-
- if (!SM.isMacroArgExpansion(Loc))
- return Loc;
+ if (Loc.isFileID())
+ return getBeginningOfFileToken(Loc, SM, LangOpts);
- SourceLocation FileLoc = SM.getSpellingLoc(Loc);
- SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts);
- std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc);
- std::pair<FileID, unsigned> BeginFileLocInfo
- = SM.getDecomposedLoc(BeginFileLoc);
- assert(FileLocInfo.first == BeginFileLocInfo.first &&
- FileLocInfo.second >= BeginFileLocInfo.second);
- return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second);
+ if (!SM.isMacroArgExpansion(Loc))
+ return Loc;
+
+ SourceLocation FileLoc = SM.getSpellingLoc(Loc);
+ SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts);
+ std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc);
+ std::pair<FileID, unsigned> BeginFileLocInfo =
+ SM.getDecomposedLoc(BeginFileLoc);
+ assert(FileLocInfo.first == BeginFileLocInfo.first &&
+ FileLocInfo.second >= BeginFileLocInfo.second);
+ return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second);
}
namespace {
enum PreambleDirectiveKind {
PDK_Skipped,
- PDK_StartIf,
- PDK_EndIf,
PDK_Unknown
};
} // end anonymous namespace
-std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
- const LangOptions &LangOpts,
- unsigned MaxLines) {
+PreambleBounds Lexer::ComputePreamble(StringRef Buffer,
+ const LangOptions &LangOpts,
+ unsigned MaxLines) {
// Create a lexer starting at the beginning of the file. Note that we use a
// "fake" file source location at offset 1 so that the lexer will track our
// position within the file.
@@ -554,13 +564,8 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
Buffer.end());
TheLexer.SetCommentRetentionState(true);
- // StartLoc will differ from FileLoc if there is a BOM that was skipped.
- SourceLocation StartLoc = TheLexer.getSourceLocation();
-
bool InPreprocessorDirective = false;
Token TheTok;
- Token IfStartTok;
- unsigned IfCount = 0;
SourceLocation ActiveCommentLoc;
unsigned MaxLineOffset = 0;
@@ -643,33 +648,18 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
.Case("sccs", PDK_Skipped)
.Case("assert", PDK_Skipped)
.Case("unassert", PDK_Skipped)
- .Case("if", PDK_StartIf)
- .Case("ifdef", PDK_StartIf)
- .Case("ifndef", PDK_StartIf)
+ .Case("if", PDK_Skipped)
+ .Case("ifdef", PDK_Skipped)
+ .Case("ifndef", PDK_Skipped)
.Case("elif", PDK_Skipped)
.Case("else", PDK_Skipped)
- .Case("endif", PDK_EndIf)
+ .Case("endif", PDK_Skipped)
.Default(PDK_Unknown);
switch (PDK) {
case PDK_Skipped:
continue;
- case PDK_StartIf:
- if (IfCount == 0)
- IfStartTok = HashTok;
-
- ++IfCount;
- continue;
-
- case PDK_EndIf:
- // Mismatched #endif. The preamble ends here.
- if (IfCount == 0)
- break;
-
- --IfCount;
- continue;
-
case PDK_Unknown:
// We don't know what this directive is; stop at the '#'.
break;
@@ -690,16 +680,13 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
} while (true);
SourceLocation End;
- if (IfCount)
- End = IfStartTok.getLocation();
- else if (ActiveCommentLoc.isValid())
+ if (ActiveCommentLoc.isValid())
End = ActiveCommentLoc; // don't truncate a decl comment.
else
End = TheTok.getLocation();
- return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(),
- IfCount? IfStartTok.isAtStartOfLine()
- : TheTok.isAtStartOfLine());
+ return PreambleBounds(End.getRawEncoding() - FileLoc.getRawEncoding(),
+ TheTok.isAtStartOfLine());
}
/// AdvanceToTokenCharacter - Given a location that specifies the start of a
@@ -1038,6 +1025,47 @@ bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) {
return isIdentifierBody(c, LangOpts.DollarIdents);
}
+bool Lexer::isNewLineEscaped(const char *BufferStart, const char *Str) {
+ assert(isVerticalWhitespace(Str[0]));
+ if (Str - 1 < BufferStart)
+ return false;
+
+ if ((Str[0] == '\n' && Str[-1] == '\r') ||
+ (Str[0] == '\r' && Str[-1] == '\n')) {
+ if (Str - 2 < BufferStart)
+ return false;
+ --Str;
+ }
+ --Str;
+
+ // Rewind to first non-space character:
+ while (Str > BufferStart && isHorizontalWhitespace(*Str))
+ --Str;
+
+ return *Str == '\\';
+}
+
+StringRef Lexer::getIndentationForLine(SourceLocation Loc,
+ const SourceManager &SM) {
+ if (Loc.isInvalid() || Loc.isMacroID())
+ return "";
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (LocInfo.first.isInvalid())
+ return "";
+ bool Invalid = false;
+ StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return "";
+ const char *Line = findBeginningOfLine(Buffer, LocInfo.second);
+ if (!Line)
+ return "";
+ StringRef Rest = Buffer.substr(Line - Buffer.data());
+ size_t NumWhitespaceChars = Rest.find_first_not_of(" \t");
+ return NumWhitespaceChars == StringRef::npos
+ ? ""
+ : Rest.take_front(NumWhitespaceChars);
+}
+
//===----------------------------------------------------------------------===//
// Diagnostics forwarding code.
//===----------------------------------------------------------------------===//
@@ -1171,6 +1199,8 @@ const char *Lexer::SkipEscapedNewLines(const char *P) {
// If not a trigraph for escape, bail out.
if (P[1] != '?' || P[2] != '/')
return P;
+ // FIXME: Take LangOpts into account; the language might not
+ // support trigraphs.
AfterEscape = P+3;
} else {
return P;
@@ -1282,12 +1312,6 @@ Slash:
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
- // If the char that we finally got was a \n, then we must have had
- // something like \<newline><newline>. We don't want to consume the
- // second newline.
- if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
- return ' ';
-
// Use slow version to accumulate a correct size field.
return getCharAndSizeSlow(Ptr, Size, Tok);
}
@@ -1338,12 +1362,6 @@ Slash:
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
- // If the char that we finally got was a \n, then we must have had
- // something like \<newline><newline>. We don't want to consume the
- // second newline.
- if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
- return ' ';
-
// Use slow version to accumulate a correct size field.
return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
@@ -1373,9 +1391,9 @@ Slash:
// Helper methods for lexing.
//===----------------------------------------------------------------------===//
-/// \brief Routine that indiscriminately skips bytes in the source file.
-void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) {
- BufferPtr += Bytes;
+/// \brief Routine that indiscriminately sets the offset into the source file.
+void Lexer::SetByteOffset(unsigned Offset, bool StartOfLine) {
+ BufferPtr = BufferStart + Offset;
if (BufferPtr > BufferEnd)
BufferPtr = BufferEnd;
// FIXME: What exactly does the StartOfLine bit mean? There are two
@@ -2070,8 +2088,11 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
// Scan over the body of the comment. The common case, when scanning, is that
// the comment contains normal ascii characters with nothing interesting in
// them. As such, optimize for this case with the inner loop.
+ //
+ // This loop terminates with CurPtr pointing at the newline (or end of buffer)
+ // character that ends the line comment.
char C;
- do {
+ while (true) {
C = *CurPtr;
// Skip over characters in the fast loop.
while (C != 0 && // Potentially EOF.
@@ -2088,10 +2109,12 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
HasSpace = true;
}
- if (*EscapePtr == '\\') // Escaped newline.
+ if (*EscapePtr == '\\')
+ // Escaped newline.
CurPtr = EscapePtr;
else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' &&
- EscapePtr[-2] == '?') // Trigraph-escaped newline.
+ EscapePtr[-2] == '?' && LangOpts.Trigraphs)
+ // Trigraph-escaped newline.
CurPtr = EscapePtr-2;
else
break; // This is a newline, we're done.
@@ -2121,7 +2144,8 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
// If we read multiple characters, and one of those characters was a \r or
// \n, then we had an escaped newline within the comment. Emit diagnostic
// unless the next line is also a // comment.
- if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') {
+ if (CurPtr != OldPtr + 1 && C != '/' &&
+ (CurPtr == BufferEnd + 1 || CurPtr[0] != '/')) {
for (; OldPtr != CurPtr; ++OldPtr)
if (OldPtr[0] == '\n' || OldPtr[0] == '\r') {
// Okay, we found a // comment that ends in a newline, if the next
@@ -2140,9 +2164,9 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
}
}
- if (CurPtr == BufferEnd+1) {
- --CurPtr;
- break;
+ if (C == '\r' || C == '\n' || CurPtr == BufferEnd + 1) {
+ --CurPtr;
+ break;
}
if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
@@ -2150,8 +2174,7 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
cutOffLexing();
return false;
}
-
- } while (C != '\n' && C != '\r');
+ }
// Found but did not consume the newline. Notify comment handlers about the
// comment unless we're in a #if 0 block.
@@ -2490,6 +2513,7 @@ void Lexer::ReadToEndOfLine(SmallVectorImpl<char> *Result) {
break;
}
// FALL THROUGH.
+ LLVM_FALLTHROUGH;
case '\r':
case '\n':
// Okay, we found the end of the line. First, back up past the \0, \r, \n.
@@ -2540,6 +2564,11 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
return true;
}
+ if (PP->isRecordingPreamble() && PP->isInPrimaryFile()) {
+ PP->setRecordedPreambleConditionalStack(ConditionalStack);
+ ConditionalStack.clear();
+ }
+
// Issue diagnostics for unterminated #if and missing newline.
// If we are in a #if directive, emit an error.
@@ -2722,6 +2751,37 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
return false;
}
+static const char *findPlaceholderEnd(const char *CurPtr,
+ const char *BufferEnd) {
+ if (CurPtr == BufferEnd)
+ return nullptr;
+ BufferEnd -= 1; // Scan until the second last character.
+ for (; CurPtr != BufferEnd; ++CurPtr) {
+ if (CurPtr[0] == '#' && CurPtr[1] == '>')
+ return CurPtr + 2;
+ }
+ return nullptr;
+}
+
+bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) {
+ assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!");
+ if (!PP || !PP->getPreprocessorOpts().LexEditorPlaceholders || LexingRawMode)
+ return false;
+ const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd);
+ if (!End)
+ return false;
+ const char *Start = CurPtr - 1;
+ if (!LangOpts.AllowEditorPlaceholders)
+ Diag(Start, diag::err_placeholder_in_source);
+ Result.startToken();
+ FormTokenWithChars(Result, End, tok::raw_identifier);
+ Result.setRawIdentifierData(Start);
+ PP->LookUpIdentifierInfo(Result);
+ Result.setFlag(Token::IsEditorPlaceholder);
+ BufferPtr = End;
+ return true;
+}
+
bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
if (PP && PP->isCodeCompletionEnabled()) {
SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
@@ -3009,8 +3069,11 @@ LexNextToken:
Kind = tok::unknown;
break;
- case '\n':
case '\r':
+ if (CurPtr[0] == '\n')
+ Char = getAndAdvanceChar(CurPtr, Result);
+ LLVM_FALLTHROUGH;
+ case '\n':
// If we are inside a preprocessor directive and we see the end of line,
// we know we are done with the directive, so return an EOD token.
if (ParsingPreprocessorDirective) {
@@ -3203,6 +3266,7 @@ LexNextToken:
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::wide_char_constant);
// FALL THROUGH, treating L like the start of an identifier.
+ LLVM_FALLTHROUGH;
// C99 6.4.2: Identifiers.
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
@@ -3479,6 +3543,9 @@ LexNextToken:
} else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_brace;
+ } else if (Char == '#' && /*Not a trigraph*/ SizeTmp == 1 &&
+ lexEditorPlaceholder(Result, CurPtr)) {
+ return true;
} else {
Kind = tok::less;
}
@@ -3545,7 +3612,9 @@ LexNextToken:
if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_square; // ':>' -> ']'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
- } else if (LangOpts.CPlusPlus && Char == ':') {
+ } else if ((LangOpts.CPlusPlus ||
+ LangOpts.DoubleSquareBracketAttributes) &&
+ Char == ':') {
Kind = tok::coloncolon;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
@@ -3603,17 +3672,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/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index fbfd3fe5cc..5f6e5efa23 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -456,10 +456,17 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// Finally, we write the bytes into ResultBuf.
ResultBuf += bytesToWrite;
switch (bytesToWrite) { // note: everything falls through.
- case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
+ case 4:
+ *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ LLVM_FALLTHROUGH;
+ case 3:
+ *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ LLVM_FALLTHROUGH;
+ case 2:
+ *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ LLVM_FALLTHROUGH;
+ case 1:
+ *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
}
// Update the buffer.
ResultBuf += bytesToWrite;
@@ -537,6 +544,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isHalf = false;
isFloat = false;
isImaginary = false;
+ isFloat16 = false;
isFloat128 = false;
MicrosoftInteger = 0;
hadError = false;
@@ -563,7 +571,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// Parse the suffix. At this point we can classify whether we have an FP or
// integer constant.
bool isFPConstant = isFloatingLiteral();
- const char *ImaginarySuffixLoc = nullptr;
// Loop over all of the characters of the suffix. If we see something bad,
// we break out of the loop.
@@ -582,6 +589,13 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
if (!isFPConstant) break; // Error for integer constant.
if (isHalf || isFloat || isLong || isFloat128)
break; // HF, FF, LF, QF invalid.
+
+ if (s + 2 < ThisTokEnd && s[1] == '1' && s[2] == '6') {
+ s += 2; // success, eat up 2 characters.
+ isFloat16 = true;
+ continue;
+ }
+
isFloat = true;
continue; // Success.
case 'q': // FP Suffix for "__float128"
@@ -652,51 +666,46 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
break;
}
}
- // "i", "if", and "il" are user-defined suffixes in C++1y.
- if (*s == 'i' && PP.getLangOpts().CPlusPlus14)
- break;
// fall through.
case 'j':
case 'J':
if (isImaginary) break; // Cannot be repeated.
isImaginary = true;
- ImaginarySuffixLoc = s;
continue; // Success.
}
// If we reached here, there was an error or a ud-suffix.
break;
}
- if (s != ThisTokEnd) {
+ // "i", "if", and "il" are user-defined suffixes in C++1y.
+ if (s != ThisTokEnd || isImaginary) {
// FIXME: Don't bother expanding UCNs if !tok.hasUCN().
expandUCNs(UDSuffixBuf, StringRef(SuffixBegin, ThisTokEnd - SuffixBegin));
if (isValidUDSuffix(PP.getLangOpts(), UDSuffixBuf)) {
- // Any suffix pieces we might have parsed are actually part of the
- // ud-suffix.
- isLong = false;
- isUnsigned = false;
- isLongLong = false;
- isFloat = false;
- isHalf = false;
- isImaginary = false;
- MicrosoftInteger = 0;
+ if (!isImaginary) {
+ // Any suffix pieces we might have parsed are actually part of the
+ // ud-suffix.
+ isLong = false;
+ isUnsigned = false;
+ isLongLong = false;
+ isFloat = false;
+ isFloat16 = false;
+ isHalf = false;
+ isImaginary = false;
+ MicrosoftInteger = 0;
+ }
saw_ud_suffix = true;
return;
}
- // Report an error if there are any.
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
- diag::err_invalid_suffix_constant)
- << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin) << isFPConstant;
- hadError = true;
- return;
- }
-
- if (isImaginary) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc,
- ImaginarySuffixLoc - ThisTokBegin),
- diag::ext_imaginary_constant);
+ if (s != ThisTokEnd) {
+ // Report an error if there are any.
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
+ diag::err_invalid_suffix_constant)
+ << StringRef(SuffixBegin, ThisTokEnd - SuffixBegin) << isFPConstant;
+ hadError = true;
+ }
}
}
@@ -847,7 +856,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
? diag::ext_hex_literal_invalid
: diag::ext_hex_constant_invalid);
else if (PP.getLangOpts().CPlusPlus1z)
- PP.Diag(TokLoc, diag::warn_cxx1z_hex_literal);
+ PP.Diag(TokLoc, diag::warn_cxx17_hex_literal);
} else if (saw_period) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::err_hex_constant_requires)
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index 1c1979d8e8..5c0f0623c3 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -33,7 +33,7 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
// See if we have an entry with a big enough argument list to reuse on the
// free list. If so, reuse it.
for (MacroArgs **Entry = &PP.MacroArgCache; *Entry;
- Entry = &(*Entry)->ArgCache)
+ Entry = &(*Entry)->ArgCache) {
if ((*Entry)->NumUnexpArgTokens >= UnexpArgTokens.size() &&
(*Entry)->NumUnexpArgTokens < ClosestMatch) {
ResultEnt = Entry;
@@ -44,26 +44,31 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
// Otherwise, use the best fit.
ClosestMatch = (*Entry)->NumUnexpArgTokens;
}
-
+ }
MacroArgs *Result;
if (!ResultEnt) {
- // Allocate memory for a MacroArgs object with the lexer tokens at the end.
- Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
- UnexpArgTokens.size() * sizeof(Token));
- // Construct the MacroArgs object.
- new (Result) MacroArgs(UnexpArgTokens.size(), VarargsElided);
+ // Allocate memory for a MacroArgs object with the lexer tokens at the end,
+ // and construct the MacroArgs object.
+ Result = new (std::malloc(totalSizeToAlloc<Token>(UnexpArgTokens.size())))
+ MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumParams());
} else {
Result = *ResultEnt;
// Unlink this node from the preprocessors singly linked list.
*ResultEnt = Result->ArgCache;
Result->NumUnexpArgTokens = UnexpArgTokens.size();
Result->VarargsElided = VarargsElided;
+ Result->NumMacroArgs = MI->getNumParams();
}
// Copy the actual unexpanded tokens to immediately after the result ptr.
- if (!UnexpArgTokens.empty())
- std::copy(UnexpArgTokens.begin(), UnexpArgTokens.end(),
- const_cast<Token*>(Result->getUnexpArgument(0)));
+ if (!UnexpArgTokens.empty()) {
+ static_assert(std::is_trivial<Token>::value,
+ "assume trivial copyability if copying into the "
+ "uninitialized array (as opposed to reusing a cached "
+ "MacroArgs)");
+ std::copy(UnexpArgTokens.begin(), UnexpArgTokens.end(),
+ Result->getTrailingObjects<Token>());
+ }
return Result;
}
@@ -91,6 +96,8 @@ MacroArgs *MacroArgs::deallocate() {
// Run the dtor to deallocate the vectors.
this->~MacroArgs();
// Release the memory for the object.
+ static_assert(std::is_trivially_destructible<Token>::value,
+ "assume trivially destructible and forego destructors");
free(this);
return Next;
@@ -111,10 +118,13 @@ unsigned MacroArgs::getArgLength(const Token *ArgPtr) {
/// getUnexpArgument - Return the unexpanded tokens for the specified formal.
///
const Token *MacroArgs::getUnexpArgument(unsigned Arg) const {
+
+ assert(Arg < getNumMacroArguments() && "Invalid arg #");
// The unexpanded argument tokens start immediately after the MacroArgs object
// in memory.
- const Token *Start = (const Token *)(this+1);
+ const Token *Start = getTrailingObjects<Token>();
const Token *Result = Start;
+
// Scan to find Arg.
for (; Arg; ++Result) {
assert(Result < Start+NumUnexpArgTokens && "Invalid arg #");
@@ -125,6 +135,16 @@ const Token *MacroArgs::getUnexpArgument(unsigned Arg) const {
return Result;
}
+// This function assumes that the variadic arguments are the tokens
+// corresponding to the last parameter (ellipsis) - and since tokens are
+// separated by the 'eof' token, if that is the only token corresponding to that
+// last parameter, we know no variadic arguments were supplied.
+bool MacroArgs::invokedWithVariadicArgument(const MacroInfo *const MI) const {
+ if (!MI->isVariadic())
+ return false;
+ const int VariadicArgIndex = getNumMacroArguments() - 1;
+ return getUnexpArgument(VariadicArgIndex)->isNot(tok::eof);
+}
/// ArgNeedsPreexpansion - If we can prove that the argument won't be affected
/// by pre-expansion, return false. Otherwise, conservatively return true.
@@ -143,14 +163,13 @@ bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok,
/// getPreExpArgument - Return the pre-expanded form of the specified
/// argument.
-const std::vector<Token> &
-MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
- Preprocessor &PP) {
- assert(Arg < MI->getNumArgs() && "Invalid argument number!");
+const std::vector<Token> &MacroArgs::getPreExpArgument(unsigned Arg,
+ Preprocessor &PP) {
+ assert(Arg < getNumMacroArguments() && "Invalid argument number!");
// If we have already computed this, return it.
- if (PreExpArgTokens.size() < MI->getNumArgs())
- PreExpArgTokens.resize(MI->getNumArgs());
+ if (PreExpArgTokens.size() < getNumMacroArguments())
+ PreExpArgTokens.resize(getNumMacroArguments());
std::vector<Token> &Result = PreExpArgTokens[Arg];
if (!Result.empty()) return Result;
@@ -298,12 +317,10 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
Preprocessor &PP,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd) {
- assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
- if (StringifiedArgs.empty()) {
- StringifiedArgs.resize(getNumArguments());
- memset((void*)&StringifiedArgs[0], 0,
- sizeof(StringifiedArgs[0])*getNumArguments());
- }
+ assert(ArgNo < getNumMacroArguments() && "Invalid argument number!");
+ if (StringifiedArgs.empty())
+ StringifiedArgs.resize(getNumMacroArguments(), {});
+
if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP,
/*Charify=*/false,
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 924613dcb8..6dc7841bc1 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -17,8 +17,8 @@ using namespace clang;
MacroInfo::MacroInfo(SourceLocation DefLoc)
: Location(DefLoc),
- ArgumentList(nullptr),
- NumArguments(0),
+ ParameterList(nullptr),
+ NumParameters(0),
IsDefinitionLengthCached(false),
IsFunctionLike(false),
IsC99Varargs(false),
@@ -29,11 +29,10 @@ MacroInfo::MacroInfo(SourceLocation DefLoc)
IsUsed(false),
IsAllowRedefinitionsWithoutWarning(false),
IsWarnIfUnused(false),
- FromASTFile(false),
UsedForHeaderGuard(false) {
}
-unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
+unsigned MacroInfo::getDefinitionLengthSlow(const SourceManager &SM) const {
assert(!IsDefinitionLengthCached);
IsDefinitionLengthCached = true;
@@ -75,7 +74,7 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
// Check # tokens in replacement, number of args, and various flags all match.
if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
- getNumArgs() != Other.getNumArgs() ||
+ getNumParams() != Other.getNumParams() ||
isFunctionLike() != Other.isFunctionLike() ||
isC99Varargs() != Other.isC99Varargs() ||
isGNUVarargs() != Other.isGNUVarargs())
@@ -83,7 +82,8 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
if (Lexically) {
// Check arguments.
- for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
+ for (param_iterator I = param_begin(), OI = Other.param_begin(),
+ E = param_end();
I != E; ++I, ++OI)
if (*I != *OI) return false;
}
@@ -110,10 +110,10 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
return false;
// With syntactic equivalence the parameter names can be different as long
// as they are used in the same place.
- int AArgNum = getArgumentNum(A.getIdentifierInfo());
+ int AArgNum = getParameterNum(A.getIdentifierInfo());
if (AArgNum == -1)
return false;
- if (AArgNum != Other.getArgumentNum(B.getIdentifierInfo()))
+ if (AArgNum != Other.getParameterNum(B.getIdentifierInfo()))
return false;
continue;
}
@@ -137,18 +137,17 @@ LLVM_DUMP_METHOD void MacroInfo::dump() const {
if (IsAllowRedefinitionsWithoutWarning)
Out << " allow_redefinitions_without_warning";
if (IsWarnIfUnused) Out << " warn_if_unused";
- if (FromASTFile) Out << " imported";
if (UsedForHeaderGuard) Out << " header_guard";
Out << "\n #define <macro>";
if (IsFunctionLike) {
Out << "(";
- for (unsigned I = 0; I != NumArguments; ++I) {
+ for (unsigned I = 0; I != NumParameters; ++I) {
if (I) Out << ", ";
- Out << ArgumentList[I]->getName();
+ Out << ParameterList[I]->getName();
}
if (IsC99Varargs || IsGNUVarargs) {
- if (NumArguments && IsC99Varargs) Out << ", ";
+ if (NumParameters && IsC99Varargs) Out << ", ";
Out << "...";
}
Out << ")";
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 384e5707dc..fc7fe138c5 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -36,6 +36,37 @@
#endif
using namespace clang;
+Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) {
+ switch ((int)Role) {
+ default: llvm_unreachable("unknown header role");
+ case NormalHeader:
+ return Module::HK_Normal;
+ case PrivateHeader:
+ return Module::HK_Private;
+ case TextualHeader:
+ return Module::HK_Textual;
+ case PrivateHeader | TextualHeader:
+ return Module::HK_PrivateTextual;
+ }
+}
+
+ModuleMap::ModuleHeaderRole
+ModuleMap::headerKindToRole(Module::HeaderKind Kind) {
+ switch ((int)Kind) {
+ case Module::HK_Normal:
+ return NormalHeader;
+ case Module::HK_Private:
+ return PrivateHeader;
+ case Module::HK_Textual:
+ return TextualHeader;
+ case Module::HK_PrivateTextual:
+ return ModuleHeaderRole(PrivateHeader | TextualHeader);
+ case Module::HK_Excluded:
+ llvm_unreachable("unexpected header kind");
+ }
+ llvm_unreachable("unknown header kind");
+}
+
Module::ExportDecl
ModuleMap::resolveExport(Module *Mod,
const Module::UnresolvedExportDecl &Unresolved,
@@ -84,14 +115,149 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
return Context;
}
+/// \brief Append to \p Paths the set of paths needed to get to the
+/// subframework in which the given module lives.
+static void appendSubframeworkPaths(Module *Mod,
+ SmallVectorImpl<char> &Path) {
+ // Collect the framework names from the given module to the top-level module.
+ SmallVector<StringRef, 2> Paths;
+ for (; Mod; Mod = Mod->Parent) {
+ if (Mod->IsFramework)
+ Paths.push_back(Mod->Name);
+ }
+
+ if (Paths.empty())
+ return;
+
+ // Add Frameworks/Name.framework for each subframework.
+ for (unsigned I = Paths.size() - 1; I != 0; --I)
+ llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
+}
+
+const FileEntry *
+ModuleMap::findHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header,
+ SmallVectorImpl<char> &RelativePathName) {
+ auto GetFile = [&](StringRef Filename) -> const FileEntry * {
+ auto *File = SourceMgr.getFileManager().getFile(Filename);
+ if (!File ||
+ (Header.Size && File->getSize() != *Header.Size) ||
+ (Header.ModTime && File->getModificationTime() != *Header.ModTime))
+ return nullptr;
+ return File;
+ };
+
+ if (llvm::sys::path::is_absolute(Header.FileName)) {
+ RelativePathName.clear();
+ RelativePathName.append(Header.FileName.begin(), Header.FileName.end());
+ return GetFile(Header.FileName);
+ }
+
+ // Search for the header file within the module's home directory.
+ auto *Directory = M->Directory;
+ SmallString<128> FullPathName(Directory->getName());
+ unsigned FullPathLength = FullPathName.size();
+
+ if (M->isPartOfFramework()) {
+ appendSubframeworkPaths(M, RelativePathName);
+ unsigned RelativePathLength = RelativePathName.size();
+
+ // Check whether this file is in the public headers.
+ llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName);
+ if (auto *File = GetFile(FullPathName))
+ return File;
+
+ // Check whether this file is in the private headers.
+ // Ideally, private modules in the form 'FrameworkName.Private' should
+ // be defined as 'module FrameworkName.Private', and not as
+ // 'framework module FrameworkName.Private', since a 'Private.Framework'
+ // does not usually exist. However, since both are currently widely used
+ // for private modules, make sure we find the right path in both cases.
+ if (M->IsFramework && M->Name == "Private")
+ RelativePathName.clear();
+ else
+ RelativePathName.resize(RelativePathLength);
+ FullPathName.resize(FullPathLength);
+ llvm::sys::path::append(RelativePathName, "PrivateHeaders",
+ Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName);
+ return GetFile(FullPathName);
+ }
+
+ // Lookup for normal headers.
+ llvm::sys::path::append(RelativePathName, Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName);
+ return GetFile(FullPathName);
+}
+
+void ModuleMap::resolveHeader(Module *Mod,
+ const Module::UnresolvedHeaderDirective &Header) {
+ SmallString<128> RelativePathName;
+ if (const FileEntry *File = findHeader(Mod, Header, RelativePathName)) {
+ if (Header.IsUmbrella) {
+ const DirectoryEntry *UmbrellaDir = File->getDir();
+ if (Module *UmbrellaMod = UmbrellaDirs[UmbrellaDir])
+ Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
+ << UmbrellaMod->getFullModuleName();
+ else
+ // Record this umbrella header.
+ setUmbrellaHeader(Mod, File, RelativePathName.str());
+ } else {
+ Module::Header H = {RelativePathName.str(), File};
+ if (Header.Kind == Module::HK_Excluded)
+ excludeHeader(Mod, H);
+ else
+ addHeader(Mod, H, headerKindToRole(Header.Kind));
+ }
+ } else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {
+ // There's a builtin header but no corresponding on-disk header. Assume
+ // this was supposed to modularize the builtin header alone.
+ } else if (Header.Kind == Module::HK_Excluded) {
+ // Ignore missing excluded header files. They're optional anyway.
+ } else {
+ // If we find a module that has a missing header, we mark this module as
+ // unavailable and store the header directive for displaying diagnostics.
+ Mod->MissingHeaders.push_back(Header);
+ // A missing header with stat information doesn't make the module
+ // unavailable; this keeps our behavior consistent as headers are lazily
+ // resolved. (Such a module still can't be built though, except from
+ // preprocessed source.)
+ if (!Header.Size && !Header.ModTime)
+ Mod->markUnavailable();
+ }
+}
+
+bool ModuleMap::resolveAsBuiltinHeader(
+ Module *Mod, const Module::UnresolvedHeaderDirective &Header) {
+ if (Header.Kind == Module::HK_Excluded ||
+ llvm::sys::path::is_absolute(Header.FileName) ||
+ Mod->isPartOfFramework() || !Mod->IsSystem || Header.IsUmbrella ||
+ !BuiltinIncludeDir || BuiltinIncludeDir == Mod->Directory ||
+ !isBuiltinHeader(Header.FileName))
+ return false;
+
+ // This is a system module with a top-level header. This header
+ // may have a counterpart (or replacement) in the set of headers
+ // supplied by Clang. Find that builtin header.
+ SmallString<128> Path;
+ llvm::sys::path::append(Path, BuiltinIncludeDir->getName(), Header.FileName);
+ auto *File = SourceMgr.getFileManager().getFile(Path);
+ if (!File)
+ return false;
+
+ auto Role = headerKindToRole(Header.Kind);
+ Module::Header H = {Path.str(), File};
+ addHeader(Mod, H, Role);
+ return true;
+}
+
ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,
const LangOptions &LangOpts, const TargetInfo *Target,
HeaderSearch &HeaderInfo)
: SourceMgr(SourceMgr), Diags(Diags), LangOpts(LangOpts), Target(Target),
- HeaderInfo(HeaderInfo), BuiltinIncludeDir(nullptr),
- SourceModule(nullptr), NumCreatedModules(0) {
+ HeaderInfo(HeaderInfo) {
MMapLangOpts.LineComment = true;
- MMapLangOpts.ModularCodegen = LangOpts.ModularCodegen;
}
ModuleMap::~ModuleMap() {
@@ -163,6 +329,7 @@ bool ModuleMap::isBuiltinHeader(StringRef FileName) {
ModuleMap::HeadersMap::iterator
ModuleMap::findKnownHeader(const FileEntry *File) {
+ resolveHeaderDirectives(File);
HeadersMap::iterator Known = Headers.find(File);
if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
@@ -245,8 +412,10 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule))
return;
- if (RequestingModule)
+ if (RequestingModule) {
resolveUses(RequestingModule, /*Complain=*/false);
+ resolveHeaderDirectives(RequestingModule);
+ }
bool Excluded = false;
Module *Private = nullptr;
@@ -428,6 +597,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
ArrayRef<ModuleMap::KnownHeader>
ModuleMap::findAllModulesForHeader(const FileEntry *File) const {
+ resolveHeaderDirectives(File);
auto It = Headers.find(File);
if (It == Headers.end())
return None;
@@ -441,6 +611,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
bool
ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
const Module *RequestingModule) const {
+ resolveHeaderDirectives(Header);
HeadersMap::const_iterator Known = Headers.find(Header);
if (Known != Headers.end()) {
for (SmallVectorImpl<KnownHeader>::const_iterator
@@ -574,16 +745,33 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
return std::make_pair(Result, true);
}
+Module *ModuleMap::createGlobalModuleForInterfaceUnit(SourceLocation Loc) {
+ assert(!PendingGlobalModule && "created multiple global modules");
+ PendingGlobalModule.reset(
+ new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
+ /*IsExplicit*/ true, NumCreatedModules++));
+ PendingGlobalModule->Kind = Module::GlobalModuleFragment;
+ return PendingGlobalModule.get();
+}
+
Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
- StringRef Name) {
+ StringRef Name,
+ Module *GlobalModule) {
assert(LangOpts.CurrentModule == Name && "module name mismatch");
assert(!Modules[Name] && "redefining existing module");
auto *Result =
new Module(Name, Loc, nullptr, /*IsFramework*/ false,
/*IsExplicit*/ false, NumCreatedModules++);
+ Result->Kind = Module::ModuleInterfaceUnit;
Modules[Name] = SourceModule = Result;
+ // Reparent the current global module fragment as a submodule of this module.
+ assert(GlobalModule == PendingGlobalModule.get() &&
+ "unexpected global module");
+ GlobalModule->setParent(Result);
+ PendingGlobalModule.release(); // now owned by parent
+
// Mark the main source file as being within the newly-created module so that
// declarations and macros are properly visibility-restricted to it.
auto *MainFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
@@ -812,20 +1000,65 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir,
UmbrellaDirs[UmbrellaDir] = Mod;
}
-static Module::HeaderKind headerRoleToKind(ModuleMap::ModuleHeaderRole Role) {
- switch ((int)Role) {
- default: llvm_unreachable("unknown header role");
- case ModuleMap::NormalHeader:
- return Module::HK_Normal;
- case ModuleMap::PrivateHeader:
- return Module::HK_Private;
- case ModuleMap::TextualHeader:
- return Module::HK_Textual;
- case ModuleMap::PrivateHeader | ModuleMap::TextualHeader:
- return Module::HK_PrivateTextual;
+void ModuleMap::addUnresolvedHeader(Module *Mod,
+ Module::UnresolvedHeaderDirective Header) {
+ // If there is a builtin counterpart to this file, add it now so it can
+ // wrap the system header.
+ if (resolveAsBuiltinHeader(Mod, Header)) {
+ // If we have both a builtin and system version of the file, the
+ // builtin version may want to inject macros into the system header, so
+ // force the system header to be treated as a textual header in this
+ // case.
+ Header.Kind = headerRoleToKind(ModuleMap::ModuleHeaderRole(
+ headerKindToRole(Header.Kind) | ModuleMap::TextualHeader));
+ Header.HasBuiltinHeader = true;
+ }
+
+ // If possible, don't stat the header until we need to. This requires the
+ // user to have provided us with some stat information about the file.
+ // FIXME: Add support for lazily stat'ing umbrella headers and excluded
+ // headers.
+ if ((Header.Size || Header.ModTime) && !Header.IsUmbrella &&
+ Header.Kind != Module::HK_Excluded) {
+ // We expect more variation in mtime than size, so if we're given both,
+ // use the mtime as the key.
+ if (Header.ModTime)
+ LazyHeadersByModTime[*Header.ModTime].push_back(Mod);
+ else
+ LazyHeadersBySize[*Header.Size].push_back(Mod);
+ Mod->UnresolvedHeaders.push_back(Header);
+ return;
+ }
+
+ // We don't have stat information or can't defer looking this file up.
+ // Perform the lookup now.
+ resolveHeader(Mod, Header);
+}
+
+void ModuleMap::resolveHeaderDirectives(const FileEntry *File) const {
+ auto BySize = LazyHeadersBySize.find(File->getSize());
+ if (BySize != LazyHeadersBySize.end()) {
+ for (auto *M : BySize->second)
+ resolveHeaderDirectives(M);
+ LazyHeadersBySize.erase(BySize);
+ }
+
+ auto ByModTime = LazyHeadersByModTime.find(File->getModificationTime());
+ if (ByModTime != LazyHeadersByModTime.end()) {
+ for (auto *M : ByModTime->second)
+ resolveHeaderDirectives(M);
+ LazyHeadersByModTime.erase(ByModTime);
}
}
+void ModuleMap::resolveHeaderDirectives(Module *Mod) const {
+ for (auto &Header : Mod->UnresolvedHeaders)
+ // This operation is logically const; we're just changing how we represent
+ // the header information for this file.
+ const_cast<ModuleMap*>(this)->resolveHeader(Mod, Header);
+ Mod->UnresolvedHeaders.clear();
+}
+
void ModuleMap::addHeader(Module *Mod, Module::Header Header,
ModuleHeaderRole Role, bool Imported) {
KnownHeader KH(Mod, Role);
@@ -950,39 +1183,6 @@ bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
return !Mod->UnresolvedConflicts.empty();
}
-Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
- if (Loc.isInvalid())
- return nullptr;
-
- if (UmbrellaDirs.empty() && Headers.empty())
- return nullptr;
-
- // Use the expansion location to determine which module we're in.
- FullSourceLoc ExpansionLoc = Loc.getExpansionLoc();
- if (!ExpansionLoc.isFileID())
- return nullptr;
-
- const SourceManager &SrcMgr = Loc.getManager();
- FileID ExpansionFileID = ExpansionLoc.getFileID();
-
- while (const FileEntry *ExpansionFile
- = SrcMgr.getFileEntryForID(ExpansionFileID)) {
- // Find the module that owns this header (if any).
- if (Module *Mod = findModuleForHeader(ExpansionFile).getModule())
- return Mod;
-
- // No module owns this header, so look up the inclusion chain to see if
- // any included header has an associated module.
- SourceLocation IncludeLoc = SrcMgr.getIncludeLoc(ExpansionFileID);
- if (IncludeLoc.isInvalid())
- return nullptr;
-
- ExpansionFileID = SrcMgr.getFileID(IncludeLoc);
- }
-
- return nullptr;
-}
-
//----------------------------------------------------------------------------//
// Module map file parser
//----------------------------------------------------------------------------//
@@ -1001,6 +1201,7 @@ namespace clang {
ExcludeKeyword,
ExplicitKeyword,
ExportKeyword,
+ ExportAsKeyword,
ExternKeyword,
FrameworkKeyword,
LinkKeyword,
@@ -1012,6 +1213,7 @@ namespace clang {
RequiresKeyword,
Star,
StringLiteral,
+ IntegerLiteral,
TextualKeyword,
LBrace,
RBrace,
@@ -1021,7 +1223,12 @@ namespace clang {
unsigned Location;
unsigned StringLength;
- const char *StringData;
+ union {
+ // If Kind != IntegerLiteral.
+ const char *StringData;
+ // If Kind == IntegerLiteral.
+ uint64_t IntegerValue;
+ };
void clear() {
Kind = EndOfFile;
@@ -1035,9 +1242,14 @@ namespace clang {
SourceLocation getLocation() const {
return SourceLocation::getFromRawEncoding(Location);
}
+
+ uint64_t getInteger() const {
+ return Kind == IntegerLiteral ? IntegerValue : 0;
+ }
StringRef getString() const {
- return StringRef(StringData, StringLength);
+ return Kind == IntegerLiteral ? StringRef()
+ : StringRef(StringData, StringLength);
}
};
@@ -1059,9 +1271,6 @@ namespace clang {
/// be resolved relative to.
const DirectoryEntry *Directory;
- /// \brief The directory containing Clang-supplied headers.
- const DirectoryEntry *BuiltinIncludeDir;
-
/// \brief Whether this module map is in a system header directory.
bool IsSystem;
@@ -1104,6 +1313,7 @@ namespace clang {
SourceLocation LeadingLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
+ void parseExportAsDecl();
void parseUseDecl();
void parseLinkDecl();
void parseConfigMacros();
@@ -1120,26 +1330,27 @@ namespace clang {
ModuleMap &Map,
const FileEntry *ModuleMapFile,
const DirectoryEntry *Directory,
- const DirectoryEntry *BuiltinIncludeDir,
bool IsSystem)
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
ModuleMapFile(ModuleMapFile), Directory(Directory),
- BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem),
- HadError(false), ActiveModule(nullptr)
+ IsSystem(IsSystem), HadError(false), ActiveModule(nullptr)
{
Tok.clear();
consumeToken();
}
bool parseModuleMapFile();
+
+ bool terminatedByDirective() { return false; }
+ SourceLocation getLocation() { return Tok.getLocation(); }
};
}
SourceLocation ModuleMapParser::consumeToken() {
-retry:
SourceLocation Result = Tok.getLocation();
+
+retry:
Tok.clear();
-
Token LToken;
L.LexFromRawLexer(LToken);
Tok.Location = LToken.getLocation().getRawEncoding();
@@ -1154,6 +1365,7 @@ retry:
.Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
+ .Case("export_as", MMToken::ExportAsKeyword)
.Case("extern", MMToken::ExternKeyword)
.Case("framework", MMToken::FrameworkKeyword)
.Case("header", MMToken::HeaderKeyword)
@@ -1229,12 +1441,50 @@ retry:
Tok.StringLength = Length;
break;
}
+
+ case tok::numeric_constant: {
+ // We don't support any suffixes or other complications.
+ SmallString<32> SpellingBuffer;
+ SpellingBuffer.resize(LToken.getLength() + 1);
+ const char *Start = SpellingBuffer.data();
+ unsigned Length =
+ Lexer::getSpelling(LToken, Start, SourceMgr, L.getLangOpts());
+ uint64_t Value;
+ if (StringRef(Start, Length).getAsInteger(0, Value)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
+ HadError = true;
+ goto retry;
+ }
+
+ Tok.Kind = MMToken::IntegerLiteral;
+ Tok.IntegerValue = Value;
+ break;
+ }
case tok::comment:
goto retry;
-
+
+ case tok::hash:
+ // A module map can be terminated prematurely by
+ // #pragma clang module contents
+ // When building the module, we'll treat the rest of the file as the
+ // contents of the module.
+ {
+ auto NextIsIdent = [&](StringRef Str) -> bool {
+ L.LexFromRawLexer(LToken);
+ return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) &&
+ LToken.getRawIdentifier() == Str;
+ };
+ if (NextIsIdent("pragma") && NextIsIdent("clang") &&
+ NextIsIdent("module") && NextIsIdent("contents")) {
+ Tok.Kind = MMToken::EndOfFile;
+ break;
+ }
+ }
+ LLVM_FALLTHROUGH;
+
default:
- Diags.Report(LToken.getLocation(), diag::err_mmap_unknown_token);
+ Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
HadError = true;
goto retry;
}
@@ -1343,6 +1593,7 @@ namespace {
/// header-declaration
/// submodule-declaration
/// export-declaration
+/// export-as-declaration
/// link-declaration
///
/// submodule-declaration:
@@ -1463,7 +1714,19 @@ void ModuleMapParser::parseModuleDecl() {
// Determine whether this (sub)module has already been defined.
if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
- if (Existing->DefinitionLoc.isInvalid() && !ActiveModule) {
+ // We might see a (re)definition of a module that we already have a
+ // definition for in two cases:
+ // - If we loaded one definition from an AST file and we've just found a
+ // corresponding definition in a module map file, or
+ bool LoadedFromASTFile = Existing->DefinitionLoc.isInvalid();
+ // - If we're building a (preprocessed) module and we've just loaded the
+ // module map file from which it was created.
+ bool ParsedAsMainInput =
+ Map.LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap &&
+ Map.LangOpts.CurrentModule == ModuleName &&
+ SourceMgr.getDecomposedLoc(ModuleNameLoc).first !=
+ SourceMgr.getDecomposedLoc(Existing->DefinitionLoc).first;
+ if (!ActiveModule && (LoadedFromASTFile || ParsedAsMainInput)) {
// Skip the module definition.
skipUntil(MMToken::RBrace);
if (Tok.is(MMToken::RBrace))
@@ -1565,6 +1828,10 @@ void ModuleMapParser::parseModuleDecl() {
parseExportDecl();
break;
+ case MMToken::ExportAsKeyword:
+ parseExportAsDecl();
+ break;
+
case MMToken::UseKeyword:
parseUseDecl();
break;
@@ -1682,7 +1949,8 @@ void ModuleMapParser::parseExternModuleDecl() {
File, /*IsSystem=*/false,
Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd
? Directory
- : File->getDir(), ExternLoc);
+ : File->getDir(),
+ FileID(), nullptr, ExternLoc);
}
/// Whether to add the requirement \p Feature to the module \p M.
@@ -1770,25 +2038,6 @@ void ModuleMapParser::parseRequiresDecl() {
} while (true);
}
-/// \brief Append to \p Paths the set of paths needed to get to the
-/// subframework in which the given module lives.
-static void appendSubframeworkPaths(Module *Mod,
- SmallVectorImpl<char> &Path) {
- // Collect the framework names from the given module to the top-level module.
- SmallVector<StringRef, 2> Paths;
- for (; Mod; Mod = Mod->Parent) {
- if (Mod->IsFramework)
- Paths.push_back(Mod->Name);
- }
-
- if (Paths.empty())
- return;
-
- // Add Frameworks/Name.framework for each subframework.
- for (unsigned I = Paths.size() - 1; I != 0; --I)
- llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
-}
-
/// \brief Parse a header declaration.
///
/// header-declaration:
@@ -1841,119 +2090,75 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
Module::UnresolvedHeaderDirective Header;
Header.FileName = Tok.getString();
Header.FileNameLoc = consumeToken();
-
+ Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
+ Header.Kind =
+ (LeadingToken == MMToken::ExcludeKeyword ? Module::HK_Excluded
+ : Map.headerRoleToKind(Role));
+
// Check whether we already have an umbrella.
- if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) {
+ if (Header.IsUmbrella && ActiveModule->Umbrella) {
Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName();
HadError = true;
return;
}
- // Look for this file.
- const FileEntry *File = nullptr;
- const FileEntry *BuiltinFile = nullptr;
- SmallString<128> RelativePathName;
- if (llvm::sys::path::is_absolute(Header.FileName)) {
- RelativePathName = Header.FileName;
- File = SourceMgr.getFileManager().getFile(RelativePathName);
- } else {
- // Search for the header file within the search directory.
- SmallString<128> FullPathName(Directory->getName());
- unsigned FullPathLength = FullPathName.size();
-
- if (ActiveModule->isPartOfFramework()) {
- appendSubframeworkPaths(ActiveModule, RelativePathName);
-
- // Check whether this file is in the public headers.
- llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName);
- File = SourceMgr.getFileManager().getFile(FullPathName);
-
- if (!File) {
- // Check whether this file is in the private headers.
- // FIXME: Should we retain the subframework paths here?
- RelativePathName.clear();
- FullPathName.resize(FullPathLength);
- llvm::sys::path::append(RelativePathName, "PrivateHeaders",
- Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName);
- File = SourceMgr.getFileManager().getFile(FullPathName);
- }
- } else {
- // Lookup for normal headers.
- llvm::sys::path::append(RelativePathName, Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName);
- File = SourceMgr.getFileManager().getFile(FullPathName);
-
- // If this is a system module with a top-level header, this header
- // may have a counterpart (or replacement) in the set of headers
- // supplied by Clang. Find that builtin header.
- if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
- BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
- ModuleMap::isBuiltinHeader(Header.FileName)) {
- SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
- llvm::sys::path::append(BuiltinPathName, Header.FileName);
- BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
-
- // If Clang supplies this header but the underlying system does not,
- // just silently swap in our builtin version. Otherwise, we'll end
- // up adding both (later).
- if (BuiltinFile && !File) {
- File = BuiltinFile;
- RelativePathName = BuiltinPathName;
- BuiltinFile = nullptr;
+ // If we were given stat information, parse it so we can skip looking for
+ // the file.
+ if (Tok.is(MMToken::LBrace)) {
+ SourceLocation LBraceLoc = consumeToken();
+
+ while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {
+ enum Attribute { Size, ModTime, Unknown };
+ StringRef Str = Tok.getString();
+ SourceLocation Loc = consumeToken();
+ switch (llvm::StringSwitch<Attribute>(Str)
+ .Case("size", Size)
+ .Case("mtime", ModTime)
+ .Default(Unknown)) {
+ case Size:
+ if (Header.Size)
+ Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
+ if (!Tok.is(MMToken::IntegerLiteral)) {
+ Diags.Report(Tok.getLocation(),
+ diag::err_mmap_invalid_header_attribute_value) << Str;
+ skipUntil(MMToken::RBrace);
+ break;
}
- }
- }
- }
+ Header.Size = Tok.getInteger();
+ consumeToken();
+ break;
- // FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
- // Come up with a lazy way to do this.
- if (File) {
- if (LeadingToken == MMToken::UmbrellaKeyword) {
- const DirectoryEntry *UmbrellaDir = File->getDir();
- if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
- Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)
- << UmbrellaModule->getFullModuleName();
- HadError = true;
- } else {
- // Record this umbrella header.
- Map.setUmbrellaHeader(ActiveModule, File, RelativePathName.str());
- }
- } else if (LeadingToken == MMToken::ExcludeKeyword) {
- Module::Header H = {RelativePathName.str(), File};
- Map.excludeHeader(ActiveModule, H);
- } else {
- // If there is a builtin counterpart to this file, add it now so it can
- // wrap the system header.
- if (BuiltinFile) {
- // FIXME: Taking the name from the FileEntry is unstable and can give
- // different results depending on how we've previously named that file
- // in this build.
- Module::Header H = { BuiltinFile->getName(), BuiltinFile };
- Map.addHeader(ActiveModule, H, Role);
-
- // If we have both a builtin and system version of the file, the
- // builtin version may want to inject macros into the system header, so
- // force the system header to be treated as a textual header in this
- // case.
- Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
- }
+ case ModTime:
+ if (Header.ModTime)
+ Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
+ if (!Tok.is(MMToken::IntegerLiteral)) {
+ Diags.Report(Tok.getLocation(),
+ diag::err_mmap_invalid_header_attribute_value) << Str;
+ skipUntil(MMToken::RBrace);
+ break;
+ }
+ Header.ModTime = Tok.getInteger();
+ consumeToken();
+ break;
- // Record this header.
- Module::Header H = { RelativePathName.str(), File };
- Map.addHeader(ActiveModule, H, Role);
+ case Unknown:
+ Diags.Report(Loc, diag::err_mmap_expected_header_attribute);
+ skipUntil(MMToken::RBrace);
+ break;
+ }
}
- } else if (LeadingToken != MMToken::ExcludeKeyword) {
- // Ignore excluded header files. They're optional anyway.
- // If we find a module that has a missing header, we mark this module as
- // unavailable and store the header directive for displaying diagnostics.
- Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
- ActiveModule->markUnavailable();
- ActiveModule->MissingHeaders.push_back(Header);
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+ else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
+ Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
+ HadError = true;
+ }
}
+
+ Map.addUnresolvedHeader(ActiveModule, std::move(Header));
}
static int compareModuleHeaders(const Module::Header *A,
@@ -1997,9 +2202,8 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
if (!Dir) {
- Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found)
+ Diags.Report(DirNameLoc, diag::warn_mmap_umbrella_dir_not_found)
<< DirName;
- HadError = true;
return;
}
@@ -2088,6 +2292,41 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
+/// \brief Parse a module export_as declaration.
+///
+/// export-as-declaration:
+/// 'export_as' identifier
+void ModuleMapParser::parseExportAsDecl() {
+ assert(Tok.is(MMToken::ExportAsKeyword));
+ consumeToken();
+
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
+ HadError = true;
+ return;
+ }
+
+ if (ActiveModule->Parent) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as);
+ consumeToken();
+ return;
+ }
+
+ if (!ActiveModule->ExportAsModule.empty()) {
+ if (ActiveModule->ExportAsModule == Tok.getString()) {
+ Diags.Report(Tok.getLocation(), diag::warn_mmap_redundant_export_as)
+ << ActiveModule->Name << Tok.getString();
+ } else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_conflicting_export_as)
+ << ActiveModule->Name << ActiveModule->ExportAsModule
+ << Tok.getString();
+ }
+ }
+
+ ActiveModule->ExportAsModule = Tok.getString();
+ consumeToken();
+}
+
/// \brief Parse a module use declaration.
///
/// use-declaration:
@@ -2493,6 +2732,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::Exclaim:
case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
+ case MMToken::ExportAsKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
case MMToken::LBrace:
@@ -2505,6 +2745,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::RequiresKeyword:
case MMToken::Star:
case MMToken::StringLiteral:
+ case MMToken::IntegerLiteral:
case MMToken::TextualKeyword:
case MMToken::UmbrellaKeyword:
case MMToken::UseKeyword:
@@ -2517,28 +2758,46 @@ bool ModuleMapParser::parseModuleMapFile() {
}
bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
- const DirectoryEntry *Dir,
+ const DirectoryEntry *Dir, FileID ID,
+ unsigned *Offset,
SourceLocation ExternModuleLoc) {
+ assert(Target && "Missing target information");
llvm::DenseMap<const FileEntry *, bool>::iterator Known
= ParsedModuleMap.find(File);
if (Known != ParsedModuleMap.end())
return Known->second;
+ // If the module map file wasn't already entered, do so now.
+ if (ID.isInvalid()) {
+ auto FileCharacter =
+ IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap;
+ ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter);
+ }
+
assert(Target && "Missing target information");
- auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User;
- FileID ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter);
const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
if (!Buffer)
return ParsedModuleMap[File] = true;
+ assert((!Offset || *Offset <= Buffer->getBufferSize()) &&
+ "invalid buffer offset");
// Parse this module map file.
- Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
+ Lexer L(SourceMgr.getLocForStartOfFile(ID), MMapLangOpts,
+ Buffer->getBufferStart(),
+ Buffer->getBufferStart() + (Offset ? *Offset : 0),
+ Buffer->getBufferEnd());
SourceLocation Start = L.getSourceLocation();
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
- BuiltinIncludeDir, IsSystem);
+ IsSystem);
bool Result = Parser.parseModuleMapFile();
ParsedModuleMap[File] = Result;
+ if (Offset) {
+ auto Loc = SourceMgr.getDecomposedLoc(Parser.getLocation());
+ assert(Loc.first == ID && "stopped in a different file?");
+ *Offset = Loc.second;
+ }
+
// Notify callbacks that we parsed it.
for (const auto &Cb : Callbacks)
Cb->moduleMapFileRead(Start, *File, IsSystem);
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 8a56ddf236..f9a97505bf 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -30,8 +30,10 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/PTHLexer.h"
#include "clang/Lex/Token.h"
+#include "clang/Lex/VariadicMacroSupport.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -54,35 +56,12 @@ using namespace clang;
// Utility Methods for Preprocessor Directive Handling.
//===----------------------------------------------------------------------===//
-MacroInfo *Preprocessor::AllocateMacroInfo() {
- MacroInfoChain *MIChain = BP.Allocate<MacroInfoChain>();
- MIChain->Next = MIChainHead;
+MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
+ auto *MIChain = new (BP) MacroInfoChain{L, MIChainHead};
MIChainHead = MIChain;
return &MIChain->MI;
}
-MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
- MacroInfo *MI = AllocateMacroInfo();
- new (MI) MacroInfo(L);
- return MI;
-}
-
-MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L,
- unsigned SubModuleID) {
- static_assert(alignof(MacroInfo) >= sizeof(SubModuleID),
- "alignment for MacroInfo is less than the ID");
- DeserializedMacroInfoChain *MIChain =
- BP.Allocate<DeserializedMacroInfoChain>();
- MIChain->Next = DeserialMIChainHead;
- DeserialMIChainHead = MIChain;
-
- MacroInfo *MI = &MIChain->MI;
- new (MI) MacroInfo(L);
- MI->FromASTFile = true;
- MI->setOwningModuleID(SubModuleID);
- return MI;
-}
-
DefMacroDirective *Preprocessor::AllocateDefMacroDirective(MacroInfo *MI,
SourceLocation Loc) {
return new (BP) DefMacroDirective(MI, Loc);
@@ -242,26 +221,18 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
- if (!II) {
- bool Invalid = false;
- std::string Spelling = getSpelling(MacroNameTok, &Invalid);
- if (Invalid)
- return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
- II = getIdentifierInfo(Spelling);
-
- if (!II->isCPlusPlusOperatorKeyword())
- return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ if (!II)
+ return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ if (II->isCPlusPlusOperatorKeyword()) {
// C++ 2.5p2: Alternative tokens behave the same as its primary token
// except for their spellings.
Diag(MacroNameTok, getLangOpts().MicrosoftExt
? diag::ext_pp_operator_used_as_macro_name
: diag::err_pp_operator_used_as_macro_name)
<< II << MacroNameTok.getKind();
-
// Allow #defining |and| and friends for Microsoft compatibility or
// recovery when legacy C headers are included in C++.
- MacroNameTok.setIdentifierInfo(II);
}
if ((isDefineUndef != MU_Other) && II->getPPKeywordID() == tok::pp_defined) {
@@ -379,7 +350,8 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
/// If ElseOk is true, then \#else directives are ok, if not, then we have
/// already seen one so a \#else directive is a duplicate. When this returns,
/// the caller can lex the first valid token.
-void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
+void Preprocessor::SkipExcludedConditionalBlock(const Token &HashToken,
+ SourceLocation IfTokenLoc,
bool FoundNonSkipPortion,
bool FoundElse,
SourceLocation ElseLoc) {
@@ -410,15 +382,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// If this is the end of the buffer, we have an error.
if (Tok.is(tok::eof)) {
- // Emit errors for each unterminated conditional on the stack, including
- // the current one.
- while (!CurPPLexer->ConditionalStack.empty()) {
- if (CurLexer->getFileLoc() != CodeCompletionFileLoc)
- Diag(CurPPLexer->ConditionalStack.back().IfLoc,
- diag::err_pp_unterminated_conditional);
- CurPPLexer->ConditionalStack.pop_back();
- }
-
+ // We don't emit errors for unterminated conditionals here,
+ // Lexer::LexEndOfFile can do that propertly.
// Just return and let the caller lex after this #include.
break;
}
@@ -560,7 +525,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
assert(CurPPLexer->LexingRawMode && "We have to be skipping here!");
CurPPLexer->LexingRawMode = false;
IdentifierInfo *IfNDefMacro = nullptr;
- const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro);
+ const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro).Conditional;
CurPPLexer->LexingRawMode = true;
if (Callbacks) {
const SourceLocation CondEnd = CurPPLexer->getSourceLocation();
@@ -587,10 +552,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// the #if block.
CurPPLexer->LexingRawMode = false;
- if (Callbacks) {
- SourceLocation BeginLoc = ElseLoc.isValid() ? ElseLoc : IfTokenLoc;
- Callbacks->SourceRangeSkipped(SourceRange(BeginLoc, Tok.getLocation()));
- }
+ if (Callbacks)
+ Callbacks->SourceRangeSkipped(
+ SourceRange(HashToken.getLocation(), CurPPLexer->getSourceLocation()),
+ Tok.getLocation());
}
void Preprocessor::PTHSkipExcludedConditionalBlock() {
@@ -657,7 +622,7 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
// Evaluate the condition of the #elif.
IdentifierInfo *IfNDefMacro = nullptr;
CurPTHLexer->ParsingPreprocessorDirective = true;
- bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
+ bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro).Conditional;
CurPTHLexer->ParsingPreprocessorDirective = false;
// If this condition is true, enter it!
@@ -690,24 +655,17 @@ Module *Preprocessor::getModuleForLocation(SourceLocation Loc) {
: HeaderInfo.lookupModule(getLangOpts().CurrentModule);
}
-Module *Preprocessor::getModuleContainingLocation(SourceLocation Loc) {
- return HeaderInfo.getModuleMap().inferModuleFromLocation(
- FullSourceLoc(Loc, SourceMgr));
-}
-
const FileEntry *
Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+ Module *M,
SourceLocation Loc) {
+ assert(M && "no module to include");
+
// If we have a module import syntax, we shouldn't include a header to
// make a particular module visible.
if (getLangOpts().ObjC2)
return nullptr;
- // Figure out which module we'd want to import.
- Module *M = getModuleContainingLocation(Loc);
- if (!M)
- return nullptr;
-
Module *TopM = M->getTopLevelModule();
Module *IncM = getModuleForLocation(IncLoc);
@@ -719,6 +677,8 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
while (!Loc.isInvalid() && !SM.isInMainFile(Loc)) {
auto ID = SM.getFileID(SM.getExpansionLoc(Loc));
auto *FE = SM.getFileEntryForID(ID);
+ if (!FE)
+ break;
bool InTextualHeader = false;
for (auto Header : HeaderInfo.getModuleMap().findAllModulesForHeader(FE)) {
@@ -752,16 +712,11 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
}
const FileEntry *Preprocessor::LookupFile(
- SourceLocation FilenameLoc,
- StringRef Filename,
- bool isAngled,
- const DirectoryLookup *FromDir,
- const FileEntry *FromFile,
- const DirectoryLookup *&CurDir,
- SmallVectorImpl<char> *SearchPath,
+ SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
+ const DirectoryLookup *FromDir, const FileEntry *FromFile,
+ const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache) {
+ ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool SkipCache) {
Module *RequestingModule = getModuleForLocation(FilenameLoc);
bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc);
@@ -819,7 +774,7 @@ const FileEntry *Preprocessor::LookupFile(
while (const FileEntry *FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
Includers, SearchPath, RelativePath, RequestingModule,
- SuggestedModule, SkipCache)) {
+ SuggestedModule, /*IsMapped=*/nullptr, SkipCache)) {
// Keep looking as if this file did a #include_next.
TmpFromDir = TmpCurDir;
++TmpFromDir;
@@ -835,7 +790,7 @@ const FileEntry *Preprocessor::LookupFile(
// Do a standard file entry lookup.
const FileEntry *FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
- RelativePath, RequestingModule, SuggestedModule, SkipCache,
+ RelativePath, RequestingModule, SuggestedModule, IsMapped, SkipCache,
BuildSystemModule);
if (FE) {
if (SuggestedModule && !LangOpts.AsmPreprocessor)
@@ -988,15 +943,17 @@ void Preprocessor::HandleDirective(Token &Result) {
default: break;
// C99 6.10.1 - Conditional Inclusion.
case tok::pp_if:
- return HandleIfDirective(Result, ReadAnyTokensBeforeDirective);
+ return HandleIfDirective(Result, SavedHash, ReadAnyTokensBeforeDirective);
case tok::pp_ifdef:
- return HandleIfdefDirective(Result, false, true/*not valid for miopt*/);
+ return HandleIfdefDirective(Result, SavedHash, false,
+ true /*not valid for miopt*/);
case tok::pp_ifndef:
- return HandleIfdefDirective(Result, true, ReadAnyTokensBeforeDirective);
+ return HandleIfdefDirective(Result, SavedHash, true,
+ ReadAnyTokensBeforeDirective);
case tok::pp_elif:
- return HandleElifDirective(Result);
+ return HandleElifDirective(Result, SavedHash);
case tok::pp_else:
- return HandleElseDirective(Result);
+ return HandleElseDirective(Result, SavedHash);
case tok::pp_endif:
return HandleEndifDirective(Result);
@@ -1206,18 +1163,26 @@ void Preprocessor::HandleLineDirective() {
CheckEndOfDirective("line", true);
}
- SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID);
+ // Take the file kind of the file containing the #line directive. #line
+ // directives are often used for generated sources from the same codebase, so
+ // the new file should generally be classified the same way as the current
+ // file. This is visible in GCC's pre-processed output, which rewrites #line
+ // to GNU line markers.
+ SrcMgr::CharacteristicKind FileKind =
+ SourceMgr.getFileCharacteristic(DigitTok.getLocation());
+
+ SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, false,
+ false, FileKind);
if (Callbacks)
Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
- PPCallbacks::RenameFile,
- SrcMgr::C_User);
+ PPCallbacks::RenameFile, FileKind);
}
/// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line
/// marker directive.
static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
- bool &IsSystemHeader, bool &IsExternCHeader,
+ SrcMgr::CharacteristicKind &FileKind,
Preprocessor &PP) {
unsigned FlagVal;
Token FlagTok;
@@ -1268,7 +1233,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
return true;
}
- IsSystemHeader = true;
+ FileKind = SrcMgr::C_System;
PP.Lex(FlagTok);
if (FlagTok.is(tok::eod)) return false;
@@ -1282,7 +1247,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
return true;
}
- IsExternCHeader = true;
+ FileKind = SrcMgr::C_ExternCSystem;
PP.Lex(FlagTok);
if (FlagTok.is(tok::eod)) return false;
@@ -1312,14 +1277,15 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
Lex(StrTok);
bool IsFileEntry = false, IsFileExit = false;
- bool IsSystemHeader = false, IsExternCHeader = false;
int FilenameID = -1;
+ SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
// If the StrTok is "eod", then it wasn't present. Otherwise, it must be a
// string followed by eod.
- if (StrTok.is(tok::eod))
- ; // ok
- else if (StrTok.isNot(tok::string_literal)) {
+ if (StrTok.is(tok::eod)) {
+ // Treat this like "#line NN", which doesn't change file characteristics.
+ FileKind = SourceMgr.getFileCharacteristic(DigitTok.getLocation());
+ } else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
return DiscardUntilEndOfDirective();
} else if (StrTok.hasUDSuffix()) {
@@ -1338,15 +1304,13 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
// If a filename was present, read any flags that are present.
- if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
- IsSystemHeader, IsExternCHeader, *this))
+ if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this))
return;
}
// Create a line note with this information.
- SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID,
- IsFileEntry, IsFileExit,
- IsSystemHeader, IsExternCHeader);
+ SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, IsFileEntry,
+ IsFileExit, FileKind);
// If the preprocessor has callbacks installed, notify them of the #line
// change. This is used so that the line marker comes out in -E mode for
@@ -1357,11 +1321,6 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
Reason = PPCallbacks::EnterFile;
else if (IsFileExit)
Reason = PPCallbacks::ExitFile;
- SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
- if (IsExternCHeader)
- FileKind = SrcMgr::C_ExternCSystem;
- else if (IsSystemHeader)
- FileKind = SrcMgr::C_System;
Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind);
}
@@ -1593,18 +1552,18 @@ bool Preprocessor::ConcatenateIncludeName(SmallString<128> &FilenameBuffer,
}
/// \brief Push a token onto the token stream containing an annotation.
-static void EnterAnnotationToken(Preprocessor &PP,
- SourceLocation Begin, SourceLocation End,
- tok::TokenKind Kind, void *AnnotationVal) {
+void Preprocessor::EnterAnnotationToken(SourceRange Range,
+ tok::TokenKind Kind,
+ void *AnnotationVal) {
// FIXME: Produce this as the current token directly, rather than
// allocating a new token for it.
auto Tok = llvm::make_unique<Token[]>(1);
Tok[0].startToken();
Tok[0].setKind(Kind);
- Tok[0].setLocation(Begin);
- Tok[0].setAnnotationEndLoc(End);
+ Tok[0].setLocation(Range.getBegin());
+ Tok[0].setAnnotationEndLoc(Range.getEnd());
Tok[0].setAnnotationValue(AnnotationVal);
- PP.EnterTokenStream(std::move(Tok), 1, true);
+ EnterTokenStream(std::move(Tok), 1, true);
}
/// \brief Produce a diagnostic informing the user that a #include or similar
@@ -1685,6 +1644,26 @@ static bool trySimplifyPath(SmallVectorImpl<StringRef> &Components,
return SuggestReplacement;
}
+bool Preprocessor::checkModuleIsAvailable(const LangOptions &LangOpts,
+ const TargetInfo &TargetInfo,
+ DiagnosticsEngine &Diags, Module *M) {
+ Module::Requirement Requirement;
+ Module::UnresolvedHeaderDirective MissingHeader;
+ if (M->isAvailable(LangOpts, TargetInfo, Requirement, MissingHeader))
+ return false;
+
+ if (MissingHeader.FileNameLoc.isValid()) {
+ Diags.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing)
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ } else {
+ // FIXME: Track the location at which the requirement was specified, and
+ // use it here.
+ Diags.Report(M->DefinitionLoc, diag::err_module_unavailable)
+ << M->getFullModuleName() << Requirement.second << Requirement.first;
+ }
+ return true;
+}
+
/// HandleIncludeDirective - The "\#include" tokens have just been read, read
/// the file to be included from the lexer, then include it! This is a common
/// routine with functionality shared between \#include, \#include_next and
@@ -1783,6 +1762,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
// Search include directories.
+ bool IsMapped = false;
const DirectoryLookup *CurDir;
SmallString<1024> SearchPath;
SmallString<1024> RelativePath;
@@ -1801,7 +1781,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
isAngled, LookupFrom, LookupFromFile, CurDir,
Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
- &SuggestedModule);
+ &SuggestedModule, &IsMapped);
if (!File) {
if (Callbacks) {
@@ -1818,7 +1798,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
FilenameLoc,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
- &SuggestedModule, /*SkipCache*/ true);
+ &SuggestedModule, &IsMapped, /*SkipCache*/ true);
}
}
}
@@ -1833,8 +1813,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false,
LookupFrom, LookupFromFile, CurDir,
Callbacks ? &SearchPath : nullptr,
- Callbacks ? &RelativePath : nullptr,
- &SuggestedModule);
+ Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped);
if (File) {
SourceRange Range(FilenameTok.getLocation(), CharEnd);
Diag(FilenameTok, diag::err_pp_file_not_found_not_fatal) <<
@@ -1856,33 +1835,24 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// we've imported or already built.
bool ShouldEnter = true;
+ if (PPOpts->SingleFileParseMode)
+ ShouldEnter = false;
+
// Determine whether we should try to import the module for this #include, if
// there is one. Don't do so if precompiled module support is disabled or we
// are processing this module textually (because we're building the module).
- if (File && SuggestedModule && getLangOpts().Modules &&
+ if (ShouldEnter && File && SuggestedModule && getLangOpts().Modules &&
SuggestedModule.getModule()->getTopLevelModuleName() !=
getLangOpts().CurrentModule) {
// If this include corresponds to a module but that module is
// unavailable, diagnose the situation and bail out.
// FIXME: Remove this; loadModule does the same check (but produces
// slightly worse diagnostics).
- if (!SuggestedModule.getModule()->isAvailable()) {
- Module::Requirement Requirement;
- Module::UnresolvedHeaderDirective MissingHeader;
- Module *M = SuggestedModule.getModule();
- // Identify the cause.
- (void)M->isAvailable(getLangOpts(), getTargetInfo(), Requirement,
- MissingHeader);
- if (MissingHeader.FileNameLoc.isValid()) {
- Diag(MissingHeader.FileNameLoc, diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- Diag(M->DefinitionLoc, diag::err_module_unavailable)
- << M->getFullModuleName() << Requirement.second << Requirement.first;
- }
+ if (checkModuleIsAvailable(getLangOpts(), getTargetInfo(), getDiagnostics(),
+ SuggestedModule.getModule())) {
Diag(FilenameTok.getLocation(),
diag::note_implicit_top_level_module_import_here)
- << M->getTopLevelModuleName();
+ << SuggestedModule.getModule()->getTopLevelModuleName();
return;
}
@@ -1939,6 +1909,25 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
}
+ // The #included file will be considered to be a system header if either it is
+ // in a system include directory, or if the #includer is a system include
+ // header.
+ SrcMgr::CharacteristicKind FileCharacter =
+ SourceMgr.getFileCharacteristic(FilenameTok.getLocation());
+ if (File)
+ FileCharacter = std::max(HeaderInfo.getFileDirFlavor(File), FileCharacter);
+
+ // Ask HeaderInfo if we should enter this #include file. If not, #including
+ // this file will have no effect.
+ bool SkipHeader = false;
+ if (ShouldEnter && File &&
+ !HeaderInfo.ShouldEnterIncludeFile(*this, File, isImport,
+ getLangOpts().Modules,
+ SuggestedModule.getModule())) {
+ ShouldEnter = false;
+ SkipHeader = true;
+ }
+
if (Callbacks) {
// Notify the callback object that we've seen an inclusion directive.
Callbacks->InclusionDirective(
@@ -1946,25 +1935,20 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
FilenameRange, File, SearchPath, RelativePath,
ShouldEnter ? nullptr : SuggestedModule.getModule());
+ if (SkipHeader && !SuggestedModule.getModule())
+ Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
}
if (!File)
return;
- // The #included file will be considered to be a system header if either it is
- // in a system include directory, or if the #includer is a system include
- // header.
- SrcMgr::CharacteristicKind FileCharacter =
- std::max(HeaderInfo.getFileDirFlavor(File),
- SourceMgr.getFileCharacteristic(FilenameTok.getLocation()));
-
// FIXME: If we have a suggested module, and we've already visited this file,
// don't bother entering it again. We know it has no further effect.
// Issue a diagnostic if the name of the file on disk has a different case
// than the one we're about to open.
const bool CheckIncludePathPortability =
- File && !File->tryGetRealPathName().empty();
+ !IsMapped && File && !File->tryGetRealPathName().empty();
if (CheckIncludePathPortability) {
StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename;
@@ -1997,19 +1981,6 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
}
- // Ask HeaderInfo if we should enter this #include file. If not, #including
- // this file will have no effect.
- bool SkipHeader = false;
- if (ShouldEnter &&
- !HeaderInfo.ShouldEnterIncludeFile(*this, File, isImport,
- getLangOpts().Modules,
- SuggestedModule.getModule())) {
- ShouldEnter = false;
- SkipHeader = true;
- if (Callbacks)
- Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
- }
-
// If we don't need to enter the file, stop now.
if (!ShouldEnter) {
// If this is a module import, make it visible if needed.
@@ -2026,7 +1997,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (IncludeTok.getIdentifierInfo()->getPPKeywordID() !=
tok::pp___include_macros)
- EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_include, M);
+ EnterAnnotationToken(SourceRange(HashLoc, End),
+ tok::annot_module_include, M);
}
return;
}
@@ -2053,18 +2025,18 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
M->getTopLevelModuleName() == getLangOpts().CurrentModule)
return;
- assert(!CurSubmodule && "should not have marked this as a module yet");
- CurSubmodule = M;
+ assert(!CurLexerSubmodule && "should not have marked this as a module yet");
+ CurLexerSubmodule = M;
// Let the macro handling code know that any future macros are within
// the new submodule.
- EnterSubmodule(M, HashLoc);
+ EnterSubmodule(M, HashLoc, /*ForPragma*/false);
// Let the parser know that any future declarations are within the new
// submodule.
// FIXME: There's no point doing this if we're handling a #__include_macros
// directive.
- EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_begin, M);
+ EnterAnnotationToken(SourceRange(HashLoc, End), tok::annot_module_begin, M);
}
}
@@ -2086,7 +2058,7 @@ void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
} else if (isInPrimaryFile()) {
Lookup = nullptr;
Diag(IncludeNextTok, diag::pp_include_next_in_primary);
- } else if (CurSubmodule) {
+ } else if (CurLexerSubmodule) {
// Start looking up in the directory *after* the one in which the current
// file would be found, if any.
assert(CurPPLexer && "#include_next directive in macro?");
@@ -2160,19 +2132,19 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
// Preprocessor Macro Directive Handling.
//===----------------------------------------------------------------------===//
-/// ReadMacroDefinitionArgList - The ( starting an argument list of a macro
-/// definition has just been read. Lex the rest of the arguments and the
+/// ReadMacroParameterList - The ( starting a parameter list of a macro
+/// definition has just been read. Lex the rest of the parameters and the
/// closing ), updating MI with what we learn. Return true if an error occurs
-/// parsing the arg list.
-bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
- SmallVector<IdentifierInfo*, 32> Arguments;
+/// parsing the param list.
+bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) {
+ SmallVector<IdentifierInfo*, 32> Parameters;
while (true) {
LexUnexpandedToken(Tok);
switch (Tok.getKind()) {
case tok::r_paren:
- // Found the end of the argument list.
- if (Arguments.empty()) // #define FOO()
+ // Found the end of the parameter list.
+ if (Parameters.empty()) // #define FOO()
return false;
// Otherwise we have #define FOO(A,)
Diag(Tok, diag::err_pp_expected_ident_in_arg_list);
@@ -2195,10 +2167,10 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
return true;
}
- // Add the __VA_ARGS__ identifier as an argument.
- Arguments.push_back(Ident__VA_ARGS__);
+ // Add the __VA_ARGS__ identifier as a parameter.
+ Parameters.push_back(Ident__VA_ARGS__);
MI->setIsC99Varargs();
- MI->setArgumentList(Arguments, BP);
+ MI->setParameterList(Parameters, BP);
return false;
case tok::eod: // #define X(
Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
@@ -2213,16 +2185,16 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
return true;
}
- // If this is already used as an argument, it is used multiple times (e.g.
+ // If this is already used as a parameter, it is used multiple times (e.g.
// #define X(A,A.
- if (std::find(Arguments.begin(), Arguments.end(), II) !=
- Arguments.end()) { // C99 6.10.3p6
+ if (std::find(Parameters.begin(), Parameters.end(), II) !=
+ Parameters.end()) { // C99 6.10.3p6
Diag(Tok, diag::err_pp_duplicate_name_in_arg_list) << II;
return true;
}
- // Add the argument to the macro info.
- Arguments.push_back(II);
+ // Add the parameter to the macro info.
+ Parameters.push_back(II);
// Lex the token after the identifier.
LexUnexpandedToken(Tok);
@@ -2232,7 +2204,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
Diag(Tok, diag::err_pp_expected_comma_in_arg_list);
return true;
case tok::r_paren: // #define X(A)
- MI->setArgumentList(Arguments, BP);
+ MI->setParameterList(Parameters, BP);
return false;
case tok::comma: // #define X(A,
break;
@@ -2248,7 +2220,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
}
MI->setIsGNUVarargs();
- MI->setArgumentList(Arguments, BP);
+ MI->setParameterList(Parameters, BP);
return false;
}
}
@@ -2297,32 +2269,28 @@ static bool isConfigurationPattern(Token &MacroName, MacroInfo *MI,
MI->getNumTokens() == 0;
}
-/// HandleDefineDirective - Implements \#define. This consumes the entire macro
-/// line then lets the caller lex the next real token.
-void Preprocessor::HandleDefineDirective(Token &DefineTok,
- bool ImmediatelyAfterHeaderGuard) {
- ++NumDefined;
-
- Token MacroNameTok;
- bool MacroShadowsKeyword;
- ReadMacroName(MacroNameTok, MU_Define, &MacroShadowsKeyword);
+// ReadOptionalMacroParameterListAndBody - This consumes all (i.e. the
+// entire line) of the macro's tokens and adds them to MacroInfo, and while
+// doing so performs certain validity checks including (but not limited to):
+// - # (stringization) is followed by a macro parameter
+//
+// Returns a nullptr if an invalid sequence of tokens is encountered or returns
+// a pointer to a MacroInfo object.
- // Error reading macro name? If so, diagnostic already issued.
- if (MacroNameTok.is(tok::eod))
- return;
+MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
+ const Token &MacroNameTok, const bool ImmediatelyAfterHeaderGuard) {
Token LastTok = MacroNameTok;
-
- // If we are supposed to keep comments in #defines, reenable comment saving
- // mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments);
-
// Create the new macro.
- MacroInfo *MI = AllocateMacroInfo(MacroNameTok.getLocation());
+ MacroInfo *const MI = AllocateMacroInfo(MacroNameTok.getLocation());
Token Tok;
LexUnexpandedToken(Tok);
+ // Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk
+ // within their appropriate context.
+ VariadicMacroScopeGuard VariadicMacroScopeGuard(*this);
+
// If this is a function-like macro definition, parse the argument list,
// marking each of the identifiers as being used as macro arguments. Also,
// check other constraints on the first token of the macro body.
@@ -2340,21 +2308,21 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
} else if (Tok.is(tok::l_paren)) {
// This is a function-like macro definition. Read the argument list.
MI->setIsFunctionLike();
- if (ReadMacroDefinitionArgList(MI, LastTok)) {
+ if (ReadMacroParameterList(MI, LastTok)) {
// Throw away the rest of the line.
if (CurPPLexer->ParsingPreprocessorDirective)
DiscardUntilEndOfDirective();
- return;
+ return nullptr;
}
- // If this is a definition of a variadic C99 function-like macro, not using
- // the GNU named varargs extension, enabled __VA_ARGS__.
+ // If this is a definition of an ISO C/C++ variadic function-like macro (not
+ // using the GNU named varargs extension) inform our variadic scope guard
+ // which un-poisons and re-poisons certain identifiers (e.g. __VA_ARGS__)
+ // allowed only within the definition of a variadic macro.
- // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
- // This gets unpoisoned where it is allowed.
- assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!");
- if (MI->isC99Varargs())
- Ident__VA_ARGS__->setIsPoisoned(false);
+ if (MI->isC99Varargs()) {
+ VariadicMacroScopeGuard.enterScope();
+ }
// Read the first token after the arg list for down below.
LexUnexpandedToken(Tok);
@@ -2400,12 +2368,50 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
// Otherwise, read the body of a function-like macro. While we are at it,
// check C99 6.10.3.2p1: ensure that # operators are followed by macro
// parameters in function-like macro expansions.
+
+ VAOptDefinitionContext VAOCtx(*this);
+
while (Tok.isNot(tok::eod)) {
LastTok = Tok;
if (!Tok.isOneOf(tok::hash, tok::hashat, tok::hashhash)) {
MI->AddTokenToBody(Tok);
+ if (VAOCtx.isVAOptToken(Tok)) {
+ // If we're already within a VAOPT, emit an error.
+ if (VAOCtx.isInVAOpt()) {
+ Diag(Tok, diag::err_pp_vaopt_nested_use);
+ return nullptr;
+ }
+ // Ensure VAOPT is followed by a '(' .
+ LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_pp_missing_lparen_in_vaopt_use);
+ return nullptr;
+ }
+ MI->AddTokenToBody(Tok);
+ VAOCtx.sawVAOptFollowedByOpeningParens(Tok.getLocation());
+ LexUnexpandedToken(Tok);
+ if (Tok.is(tok::hashhash)) {
+ Diag(Tok, diag::err_vaopt_paste_at_start);
+ return nullptr;
+ }
+ continue;
+ } else if (VAOCtx.isInVAOpt()) {
+ if (Tok.is(tok::r_paren)) {
+ if (VAOCtx.sawClosingParen()) {
+ const unsigned NumTokens = MI->getNumTokens();
+ assert(NumTokens >= 3 && "Must have seen at least __VA_OPT__( "
+ "and a subsequent tok::r_paren");
+ if (MI->getReplacementToken(NumTokens - 2).is(tok::hashhash)) {
+ Diag(Tok, diag::err_vaopt_paste_at_end);
+ return nullptr;
+ }
+ }
+ } else if (Tok.is(tok::l_paren)) {
+ VAOCtx.sawOpeningParen(Tok.getLocation());
+ }
+ }
// Get the next token of the macro.
LexUnexpandedToken(Tok);
continue;
@@ -2446,12 +2452,14 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
continue;
}
+ // Our Token is a stringization operator.
// Get the next token of the macro.
LexUnexpandedToken(Tok);
- // Check for a valid macro arg identifier.
- if (Tok.getIdentifierInfo() == nullptr ||
- MI->getArgumentNum(Tok.getIdentifierInfo()) == -1) {
+ // Check for a valid macro arg identifier or __VA_OPT__.
+ if (!VAOCtx.isVAOptToken(Tok) &&
+ (Tok.getIdentifierInfo() == nullptr ||
+ MI->getParameterNum(Tok.getIdentifierInfo()) == -1)) {
// If this is assembler-with-cpp mode, we accept random gibberish after
// the '#' because '#' is often a comment character. However, change
@@ -2464,31 +2472,62 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
} else {
Diag(Tok, diag::err_pp_stringize_not_parameter)
<< LastTok.is(tok::hashat);
-
- // Disable __VA_ARGS__ again.
- Ident__VA_ARGS__->setIsPoisoned(true);
- return;
+ return nullptr;
}
}
// Things look ok, add the '#' and param name tokens to the macro.
MI->AddTokenToBody(LastTok);
- MI->AddTokenToBody(Tok);
- LastTok = Tok;
- // Get the next token of the macro.
- LexUnexpandedToken(Tok);
+ // If the token following '#' is VAOPT, let the next iteration handle it
+ // and check it for correctness, otherwise add the token and prime the
+ // loop with the next one.
+ if (!VAOCtx.isVAOptToken(Tok)) {
+ MI->AddTokenToBody(Tok);
+ LastTok = Tok;
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+ }
+ }
+ if (VAOCtx.isInVAOpt()) {
+ assert(Tok.is(tok::eod) && "Must be at End Of preprocessing Directive");
+ Diag(Tok, diag::err_pp_expected_after)
+ << LastTok.getKind() << tok::r_paren;
+ Diag(VAOCtx.getUnmatchedOpeningParenLoc(), diag::note_matching) << tok::l_paren;
+ return nullptr;
}
}
+ MI->setDefinitionEndLoc(LastTok.getLocation());
+ return MI;
+}
+/// HandleDefineDirective - Implements \#define. This consumes the entire macro
+/// line then lets the caller lex the next real token.
+void Preprocessor::HandleDefineDirective(
+ Token &DefineTok, const bool ImmediatelyAfterHeaderGuard) {
+ ++NumDefined;
+
+ Token MacroNameTok;
+ bool MacroShadowsKeyword;
+ ReadMacroName(MacroNameTok, MU_Define, &MacroShadowsKeyword);
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.is(tok::eod))
+ return;
+
+ // If we are supposed to keep comments in #defines, reenable comment saving
+ // mode.
+ if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments);
+
+ MacroInfo *const MI = ReadOptionalMacroParameterListAndBody(
+ MacroNameTok, ImmediatelyAfterHeaderGuard);
+
+ if (!MI) return;
if (MacroShadowsKeyword &&
!isConfigurationPattern(MacroNameTok, MI, getLangOpts())) {
Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword);
- }
-
- // Disable __VA_ARGS__ again.
- Ident__VA_ARGS__->setIsPoisoned(true);
-
+ }
// Check that there is no paste (##) operator at the beginning or end of the
// replacement list.
unsigned NumTokens = MI->getNumTokens();
@@ -2503,7 +2542,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
}
}
- MI->setDefinitionEndLoc(LastTok.getLocation());
+
// Finally, if this identifier already had a macro defined for it, verify that
// the macro bodies are identical, and issue diagnostics if they are not.
@@ -2592,25 +2631,26 @@ void Preprocessor::HandleUndefDirective() {
// Okay, we have a valid identifier to undef.
auto *II = MacroNameTok.getIdentifierInfo();
auto MD = getMacroDefinition(II);
+ UndefMacroDirective *Undef = nullptr;
+
+ // If the macro is not defined, this is a noop undef.
+ if (const MacroInfo *MI = MD.getMacroInfo()) {
+ if (!MI->isUsed() && MI->isWarnIfUnused())
+ Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
+
+ if (MI->isWarnIfUnused())
+ WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
+
+ Undef = AllocateUndefMacroDirective(MacroNameTok.getLocation());
+ }
// If the callbacks want to know, tell them about the macro #undef.
// Note: no matter if the macro was defined or not.
if (Callbacks)
- Callbacks->MacroUndefined(MacroNameTok, MD);
-
- // If the macro is not defined, this is a noop undef, just return.
- const MacroInfo *MI = MD.getMacroInfo();
- if (!MI)
- return;
-
- if (!MI->isUsed() && MI->isWarnIfUnused())
- Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
-
- if (MI->isWarnIfUnused())
- WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
+ Callbacks->MacroUndefined(MacroNameTok, MD, Undef);
- appendMacroDirective(MacroNameTok.getIdentifierInfo(),
- AllocateUndefMacroDirective(MacroNameTok.getLocation()));
+ if (Undef)
+ appendMacroDirective(II, Undef);
}
//===----------------------------------------------------------------------===//
@@ -2622,7 +2662,9 @@ void Preprocessor::HandleUndefDirective() {
/// true if any tokens have been returned or pp-directives activated before this
/// \#ifndef has been lexed.
///
-void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
+void Preprocessor::HandleIfdefDirective(Token &Result,
+ const Token &HashToken,
+ bool isIfndef,
bool ReadAnyTokensBeforeDirective) {
++NumIf;
Token DirectiveTok = Result;
@@ -2634,8 +2676,8 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
if (MacroNameTok.is(tok::eod)) {
// Skip code until we get to #endif. This helps with recovery by not
// emitting an error when the #endif is reached.
- SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
- /*Foundnonskip*/false, /*FoundElse*/false);
+ SkipExcludedConditionalBlock(HashToken, DirectiveTok.getLocation(),
+ /*Foundnonskip*/ false, /*FoundElse*/ false);
return;
}
@@ -2670,29 +2712,37 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
}
// Should we include the stuff contained by this directive?
- if (!MI == isIfndef) {
+ if (PPOpts->SingleFileParseMode && !MI) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
+ /*wasskip*/false, /*foundnonskip*/false,
+ /*foundelse*/false);
+ } else if (!MI == isIfndef) {
// Yes, remember that we are inside a conditional, then lex the next token.
CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
/*wasskip*/false, /*foundnonskip*/true,
/*foundelse*/false);
} else {
// No, skip the contents of this block.
- SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
- /*Foundnonskip*/false,
- /*FoundElse*/false);
+ SkipExcludedConditionalBlock(HashToken, DirectiveTok.getLocation(),
+ /*Foundnonskip*/ false,
+ /*FoundElse*/ false);
}
}
/// HandleIfDirective - Implements the \#if directive.
///
void Preprocessor::HandleIfDirective(Token &IfToken,
+ const Token &HashToken,
bool ReadAnyTokensBeforeDirective) {
++NumIf;
// Parse and evaluate the conditional expression.
IdentifierInfo *IfNDefMacro = nullptr;
const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation();
- const bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro);
+ const DirectiveEvalResult DER = EvaluateDirectiveExpression(IfNDefMacro);
+ const bool ConditionalTrue = DER.Conditional;
const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation();
// If this condition is equivalent to #ifndef X, and if this is the first
@@ -2711,14 +2761,20 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
(ConditionalTrue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False));
// Should we include the stuff contained by this directive?
- if (ConditionalTrue) {
+ if (PPOpts->SingleFileParseMode && DER.IncludedUndefinedIds) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
+ /*foundnonskip*/false, /*foundelse*/false);
+ } else if (ConditionalTrue) {
// Yes, remember that we are inside a conditional, then lex the next token.
CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
/*foundnonskip*/true, /*foundelse*/false);
} else {
// No, skip the contents of this block.
- SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false,
- /*FoundElse*/false);
+ SkipExcludedConditionalBlock(HashToken, IfToken.getLocation(),
+ /*Foundnonskip*/ false,
+ /*FoundElse*/ false);
}
}
@@ -2750,7 +2806,7 @@ void Preprocessor::HandleEndifDirective(Token &EndifToken) {
/// HandleElseDirective - Implements the \#else directive.
///
-void Preprocessor::HandleElseDirective(Token &Result) {
+void Preprocessor::HandleElseDirective(Token &Result, const Token &HashToken) {
++NumElse;
// #else directive in a non-skipping conditional... start skipping.
@@ -2772,14 +2828,23 @@ void Preprocessor::HandleElseDirective(Token &Result) {
if (Callbacks)
Callbacks->Else(Result.getLocation(), CI.IfLoc);
+ if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false,
+ /*foundnonskip*/false, /*foundelse*/true);
+ return;
+ }
+
// Finally, skip the rest of the contents of this block.
- SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
- /*FoundElse*/true, Result.getLocation());
+ SkipExcludedConditionalBlock(HashToken, CI.IfLoc, /*Foundnonskip*/ true,
+ /*FoundElse*/ true, Result.getLocation());
}
/// HandleElifDirective - Implements the \#elif directive.
///
-void Preprocessor::HandleElifDirective(Token &ElifToken) {
+void Preprocessor::HandleElifDirective(Token &ElifToken,
+ const Token &HashToken) {
++NumElse;
// #elif directive in a non-skipping conditional... start skipping.
@@ -2807,8 +2872,16 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
SourceRange(ConditionalBegin, ConditionalEnd),
PPCallbacks::CVK_NotEvaluated, CI.IfLoc);
+ if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(ElifToken.getLocation(), /*wasskip*/false,
+ /*foundnonskip*/false, /*foundelse*/false);
+ return;
+ }
+
// Finally, skip the rest of the contents of this block.
- SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
- /*FoundElse*/CI.FoundElse,
+ SkipExcludedConditionalBlock(HashToken, CI.IfLoc, /*Foundnonskip*/ true,
+ /*FoundElse*/ CI.FoundElse,
ElifToken.getLocation());
}
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 862a4713e4..d8431827e9 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@ public:
static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
Token &PeekTok, bool ValueLive,
+ bool &IncludedUndefinedIds,
Preprocessor &PP);
/// DefinedTracker - This struct is used while parsing expressions to keep track
@@ -93,6 +94,7 @@ struct DefinedTracker {
/// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
/// indicates the macro that was checked.
IdentifierInfo *TheMacro;
+ bool IncludedUndefinedIds = false;
};
/// EvaluateDefined - Process a 'defined(sym)' expression.
@@ -128,6 +130,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
MacroDefinition Macro = PP.getMacroDefinition(II);
Result.Val = !!Macro;
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+ DT.IncludedUndefinedIds = !Macro;
// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive)
@@ -234,33 +237,32 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.setCodeCompletionReached();
PP.LexNonComment(PeekTok);
}
-
- // If this token's spelling is a pp-identifier, check to see if it is
- // 'defined' or if it is a macro. Note that we check here because many
- // keywords are pp-identifiers, so we can't check the kind.
- if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
- // Handle "defined X" and "defined(X)".
- if (II->isStr("defined"))
- return EvaluateDefined(Result, PeekTok, DT, ValueLive, PP);
-
- // If this identifier isn't 'defined' or one of the special
- // preprocessor keywords and it wasn't macro expanded, it turns
- // into a simple 0, unless it is the C++ keyword "true", in which case it
- // turns into "1".
- if (ValueLive &&
- II->getTokenID() != tok::kw_true &&
- II->getTokenID() != tok::kw_false)
- PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
- Result.Val = II->getTokenID() == tok::kw_true;
- Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
- Result.setIdentifier(II);
- Result.setRange(PeekTok.getLocation());
- PP.LexNonComment(PeekTok);
- return false;
- }
switch (PeekTok.getKind()) {
- default: // Non-value token.
+ default:
+ // If this token's spelling is a pp-identifier, check to see if it is
+ // 'defined' or if it is a macro. Note that we check here because many
+ // keywords are pp-identifiers, so we can't check the kind.
+ if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
+ // Handle "defined X" and "defined(X)".
+ if (II->isStr("defined"))
+ return EvaluateDefined(Result, PeekTok, DT, ValueLive, PP);
+
+ if (!II->isCPlusPlusOperatorKeyword()) {
+ // If this identifier isn't 'defined' or one of the special
+ // preprocessor keywords and it wasn't macro expanded, it turns
+ // into a simple 0
+ if (ValueLive)
+ PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
+ Result.Val = 0;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setIdentifier(II);
+ Result.setRange(PeekTok.getLocation());
+ DT.IncludedUndefinedIds = true;
+ PP.LexNonComment(PeekTok);
+ return false;
+ }
+ }
PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr);
return true;
case tok::eod:
@@ -400,7 +402,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// Just use DT unmodified as our result.
} else {
// Otherwise, we have something like (x+y), and we consumed '(x'.
- if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+ if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
+ DT.IncludedUndefinedIds, PP))
return true;
if (PeekTok.isNot(tok::r_paren)) {
@@ -475,6 +478,14 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
DT.State = DefinedTracker::DefinedMacro;
return false;
}
+ case tok::kw_true:
+ case tok::kw_false:
+ Result.Val = PeekTok.getKind() == tok::kw_true;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setIdentifier(PeekTok.getIdentifierInfo());
+ Result.setRange(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ return false;
// FIXME: Handle #assert
}
@@ -532,6 +543,7 @@ static void diagnoseUnexpectedOperator(Preprocessor &PP, PPValue &LHS,
/// evaluation, such as division by zero warnings.
static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
Token &PeekTok, bool ValueLive,
+ bool &IncludedUndefinedIds,
Preprocessor &PP) {
unsigned PeekPrec = getPrecedence(PeekTok.getKind());
// If this token isn't valid, report the error.
@@ -571,6 +583,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
// Parse the RHS of the operator.
DefinedTracker DT;
if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true;
+ IncludedUndefinedIds = DT.IncludedUndefinedIds;
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
@@ -601,7 +614,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
RHSPrec = ThisPrec+1;
if (PeekPrec >= RHSPrec) {
- if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive, PP))
+ if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive,
+ IncludedUndefinedIds, PP))
return true;
PeekPrec = getPrecedence(PeekTok.getKind());
}
@@ -769,7 +783,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
// Parse anything after the : with the same precedence as ?. We allow
// things of equal precedence because ?: is right associative.
if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec,
- PeekTok, AfterColonLive, PP))
+ PeekTok, AfterColonLive,
+ IncludedUndefinedIds, PP))
return true;
// Now that we have the condition, the LHS and the RHS of the :, evaluate.
@@ -806,7 +821,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
/// may occur after a #if or #elif directive. If the expression is equivalent
/// to "!defined(X)" return X in IfNDefMacro.
-bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
+Preprocessor::DirectiveEvalResult
+Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
// Save the current state of 'DisableMacroExpansion' and reset it to false. If
// 'DisableMacroExpansion' is true, then we must be in a macro argument list
@@ -833,7 +849,7 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return false;
+ return {false, DT.IncludedUndefinedIds};
}
// If we are at the end of the expression after just parsing a value, there
@@ -847,20 +863,20 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return ResVal.Val != 0;
+ return {ResVal.Val != 0, DT.IncludedUndefinedIds};
}
// Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the
// operator and the stuff after it.
if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question),
- Tok, true, *this)) {
+ Tok, true, DT.IncludedUndefinedIds, *this)) {
// Parse error, skip the rest of the macro line.
if (Tok.isNot(tok::eod))
DiscardUntilEndOfDirective();
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return false;
+ return {false, DT.IncludedUndefinedIds};
}
// If we aren't at the tok::eod token, something bad happened, like an extra
@@ -872,5 +888,5 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return ResVal.Val != 0;
+ return {ResVal.Val != 0, DT.IncludedUndefinedIds};
}
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 4db17c344b..e484e9c4c3 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -40,10 +40,9 @@ bool Preprocessor::isInPrimaryFile() const {
// If there are any stacked lexers, we're in a #include.
assert(IsFileLexer(IncludeMacroStack[0]) &&
"Top level include stack isn't our primary lexer?");
- return std::none_of(IncludeMacroStack.begin() + 1, IncludeMacroStack.end(),
- [this](const IncludeStackInfo &ISI) -> bool {
- return IsFileLexer(ISI);
- });
+ return std::none_of(
+ IncludeMacroStack.begin() + 1, IncludeMacroStack.end(),
+ [&](const IncludeStackInfo &ISI) -> bool { return IsFileLexer(ISI); });
}
/// getCurrentLexer - Return the current file lexer being lexed from. Note
@@ -117,7 +116,7 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
CurLexer.reset(TheLexer);
CurPPLexer = TheLexer;
CurDirLookup = CurDir;
- CurSubmodule = nullptr;
+ CurLexerSubmodule = nullptr;
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_Lexer;
@@ -142,7 +141,7 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
CurDirLookup = CurDir;
CurPTHLexer.reset(PL);
CurPPLexer = CurPTHLexer.get();
- CurSubmodule = nullptr;
+ CurLexerSubmodule = nullptr;
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_PTHLexer;
@@ -287,6 +286,48 @@ const char *Preprocessor::getCurLexerEndPos() {
return EndPos;
}
+static void collectAllSubModulesWithUmbrellaHeader(
+ const Module &Mod, SmallVectorImpl<const Module *> &SubMods) {
+ if (Mod.getUmbrellaHeader())
+ SubMods.push_back(&Mod);
+ for (auto *M : Mod.submodules())
+ collectAllSubModulesWithUmbrellaHeader(*M, SubMods);
+}
+
+void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) {
+ assert(Mod.getUmbrellaHeader() && "Module must use umbrella header");
+ SourceLocation StartLoc =
+ SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+ if (getDiagnostics().isIgnored(diag::warn_uncovered_module_header, StartLoc))
+ return;
+
+ ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+ const DirectoryEntry *Dir = Mod.getUmbrellaDir().Entry;
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ std::error_code EC;
+ for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End;
+ Entry != End && !EC; Entry.increment(EC)) {
+ using llvm::StringSwitch;
+
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ if (const FileEntry *Header = getFileManager().getFile(Entry->getName()))
+ if (!getSourceManager().hasFileInfo(Header)) {
+ if (!ModMap.isHeaderInUnavailableModule(Header)) {
+ // Find the relative path that would access this header.
+ SmallString<128> RelativePath;
+ computeRelativePath(FileMgr, Dir, Header, RelativePath);
+ Diag(StartLoc, diag::warn_uncovered_module_header)
+ << Mod.getFullModuleName() << RelativePath;
+ }
+ }
+ }
+}
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
/// the current file. This either returns the EOF token or pops a level off
@@ -295,6 +336,26 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
assert(!CurTokenLexer &&
"Ending a file when currently in a macro!");
+ // If we have an unclosed module region from a pragma at the end of a
+ // module, complain and close it now.
+ // FIXME: This is not correct if we are building a module from PTH.
+ const bool LeavingSubmodule = CurLexer && CurLexerSubmodule;
+ if ((LeavingSubmodule || IncludeMacroStack.empty()) &&
+ !BuildingSubmoduleStack.empty() &&
+ BuildingSubmoduleStack.back().IsPragma) {
+ Diag(BuildingSubmoduleStack.back().ImportLoc,
+ diag::err_pp_module_begin_without_module_end);
+ Module *M = LeaveSubmodule(/*ForPragma*/true);
+
+ Result.startToken();
+ const char *EndPos = getCurLexerEndPos();
+ CurLexer->BufferPtr = EndPos;
+ CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end);
+ Result.setAnnotationEndLoc(Result.getLocation());
+ Result.setAnnotationValue(M);
+ return true;
+ }
+
// See if this file had a controlling macro.
if (CurPPLexer) { // Not ending a macro, ignore it.
if (const IdentifierInfo *ControllingMacro =
@@ -303,9 +364,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
if (const FileEntry *FE = CurPPLexer->getFileEntry()) {
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
if (MacroInfo *MI =
- getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) {
- MI->UsedForHeaderGuard = true;
- }
+ getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro)))
+ MI->setUsedForHeaderGuard(true);
if (const IdentifierInfo *DefinedMacro =
CurPPLexer->MIOpt.GetDefinedMacro()) {
if (!isMacroDefined(ControllingMacro) &&
@@ -397,22 +457,27 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs);
}
+ bool ExitedFromPredefinesFile = false;
FileID ExitedFID;
- if (Callbacks && !isEndOfMacro && CurPPLexer)
+ if (!isEndOfMacro && CurPPLexer) {
ExitedFID = CurPPLexer->getFileID();
- bool LeavingSubmodule = CurSubmodule && CurLexer;
+ assert(PredefinesFileID.isValid() &&
+ "HandleEndOfFile is called before PredefinesFileId is set");
+ ExitedFromPredefinesFile = (PredefinesFileID == ExitedFID);
+ }
+
if (LeavingSubmodule) {
+ // We're done with this submodule.
+ Module *M = LeaveSubmodule(/*ForPragma*/false);
+
// Notify the parser that we've left the module.
const char *EndPos = getCurLexerEndPos();
Result.startToken();
CurLexer->BufferPtr = EndPos;
CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end);
Result.setAnnotationEndLoc(Result.getLocation());
- Result.setAnnotationValue(CurSubmodule);
-
- // We're done with this submodule.
- LeaveSubmodule();
+ Result.setAnnotationValue(M);
}
// We're done with the #included file.
@@ -429,6 +494,11 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
PPCallbacks::ExitFile, FileType, ExitedFID);
}
+ // Restore conditional stack from the preamble right after exiting from the
+ // predefines file.
+ if (ExitedFromPredefinesFile)
+ replayPreambleConditionalStack();
+
// Client should lex another token unless we generated an EOM.
return LeavingSubmodule;
}
@@ -474,44 +544,14 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
// If we are building a module that has an umbrella header, make sure that
- // each of the headers within the directory covered by the umbrella header
- // was actually included by the umbrella header.
+ // each of the headers within the directory, including all submodules, is
+ // covered by the umbrella header was actually included by the umbrella
+ // header.
if (Module *Mod = getCurrentModule()) {
- if (Mod->getUmbrellaHeader()) {
- SourceLocation StartLoc
- = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
-
- if (!getDiagnostics().isIgnored(diag::warn_uncovered_module_header,
- StartLoc)) {
- ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
- const DirectoryEntry *Dir = Mod->getUmbrellaDir().Entry;
- vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
- std::error_code EC;
- for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End;
- Entry != End && !EC; Entry.increment(EC)) {
- using llvm::StringSwitch;
-
- // Check whether this entry has an extension typically associated with
- // headers.
- if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
- .Cases(".h", ".H", ".hh", ".hpp", true)
- .Default(false))
- continue;
-
- if (const FileEntry *Header =
- getFileManager().getFile(Entry->getName()))
- if (!getSourceManager().hasFileInfo(Header)) {
- if (!ModMap.isHeaderInUnavailableModule(Header)) {
- // Find the relative path that would access this header.
- SmallString<128> RelativePath;
- computeRelativePath(FileMgr, Dir, Header, RelativePath);
- Diag(StartLoc, diag::warn_uncovered_module_header)
- << Mod->getFullModuleName() << RelativePath;
- }
- }
- }
- }
- }
+ llvm::SmallVector<const Module *, 4> AllMods;
+ collectAllSubModulesWithUmbrellaHeader(*Mod, AllMods);
+ for (auto *M : AllMods)
+ diagnoseMissingHeaderInUmbrellaDir(*M);
}
return true;
@@ -617,11 +657,13 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
assert(!FoundLexer && "Lexer should return EOD before EOF in PP mode");
}
-void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) {
+void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc,
+ bool ForPragma) {
if (!getLangOpts().ModulesLocalVisibility) {
// Just track that we entered this submodule.
- BuildingSubmoduleStack.push_back(BuildingSubmoduleInfo(
- M, ImportLoc, CurSubmoduleState, PendingModuleMacroNames.size()));
+ BuildingSubmoduleStack.push_back(
+ BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState,
+ PendingModuleMacroNames.size()));
return;
}
@@ -662,8 +704,9 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) {
}
// Track that we entered this module.
- BuildingSubmoduleStack.push_back(BuildingSubmoduleInfo(
- M, ImportLoc, CurSubmoduleState, PendingModuleMacroNames.size()));
+ BuildingSubmoduleStack.push_back(
+ BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState,
+ PendingModuleMacroNames.size()));
// Switch to this submodule as the current submodule.
CurSubmoduleState = &State;
@@ -686,13 +729,19 @@ bool Preprocessor::needModuleMacros() const {
return getLangOpts().isCompilingModule();
}
-void Preprocessor::LeaveSubmodule() {
+Module *Preprocessor::LeaveSubmodule(bool ForPragma) {
+ if (BuildingSubmoduleStack.empty() ||
+ BuildingSubmoduleStack.back().IsPragma != ForPragma) {
+ assert(ForPragma && "non-pragma module enter/leave mismatch");
+ return nullptr;
+ }
+
auto &Info = BuildingSubmoduleStack.back();
Module *LeavingMod = Info.M;
SourceLocation ImportLoc = Info.ImportLoc;
- if (!needModuleMacros() ||
+ if (!needModuleMacros() ||
(!getLangOpts().ModulesLocalVisibility &&
LeavingMod->getTopLevelModuleName() != getLangOpts().CurrentModule)) {
// If we don't need module macros, or this is not a module for which we
@@ -700,7 +749,7 @@ void Preprocessor::LeaveSubmodule() {
// of pending names for the surrounding submodule.
BuildingSubmoduleStack.pop_back();
makeModuleVisible(LeavingMod, ImportLoc);
- return;
+ return LeavingMod;
}
// Create ModuleMacros for any macros defined in this submodule.
@@ -738,17 +787,6 @@ void Preprocessor::LeaveSubmodule() {
for (auto *MD = Macro.getLatest(); MD != OldMD; MD = MD->getPrevious()) {
assert(MD && "broken macro directive chain");
- // Stop on macros defined in other submodules of this module that we
- // #included along the way. There's no point doing this if we're
- // tracking local submodule visibility, since there can be no such
- // directives in our list.
- if (!getLangOpts().ModulesLocalVisibility) {
- Module *Mod = getModuleContainingLocation(MD->getLocation());
- if (Mod != LeavingMod &&
- Mod->getTopLevelModule() == LeavingMod->getTopLevelModule())
- break;
- }
-
if (auto *VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
// The latest visibility directive for a name in a submodule affects
// all the directives that come before it.
@@ -770,6 +808,13 @@ void Preprocessor::LeaveSubmodule() {
if (Def || !Macro.getOverriddenMacros().empty())
addModuleMacro(LeavingMod, II, Def,
Macro.getOverriddenMacros(), IsNew);
+
+ if (!getLangOpts().ModulesLocalVisibility) {
+ // This macro is exposed to the rest of this compilation as a
+ // ModuleMacro; we don't need to track its MacroDirective any more.
+ Macro.setLatest(nullptr);
+ Macro.setOverriddenMacros(*this, {});
+ }
break;
}
}
@@ -789,4 +834,5 @@ void Preprocessor::LeaveSubmodule() {
// A nested #include makes the included submodule visible.
makeModuleVisible(LeavingMod, ImportLoc);
+ return LeavingMod;
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index de166c75e2..b0330f2881 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -412,7 +412,7 @@ static bool isTrivialSingleTokenExpansion(const MacroInfo *MI,
// If this is a function-like macro invocation, it's safe to trivially expand
// as long as the identifier is not a macro argument.
- return std::find(MI->arg_begin(), MI->arg_end(), II) == MI->arg_end();
+ return std::find(MI->param_begin(), MI->param_end(), II) == MI->param_end();
}
/// isNextPPTokenLParen - Determine whether the next preprocessor token to be
@@ -492,7 +492,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// Preprocessor directives used inside macro arguments are not portable, and
// this enables the warning.
InMacroArgs = true;
- Args = ReadFunctionLikeMacroArgs(Identifier, MI, ExpansionEnd);
+ Args = ReadMacroCallArgumentList(Identifier, MI, ExpansionEnd);
// Finished parsing args.
InMacroArgs = false;
@@ -745,11 +745,11 @@ static bool GenerateNewArgTokens(Preprocessor &PP,
/// token is the '(' of the macro, this method is invoked to read all of the
/// actual arguments specified for the macro invocation. This returns null on
/// error.
-MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
+MacroArgs *Preprocessor::ReadMacroCallArgumentList(Token &MacroName,
MacroInfo *MI,
SourceLocation &MacroEnd) {
// The number of fixed arguments to parse.
- unsigned NumFixedArgsLeft = MI->getNumArgs();
+ unsigned NumFixedArgsLeft = MI->getNumParams();
bool isVariadic = MI->isVariadic();
// Outer loop, while there are more arguments, keep reading them.
@@ -889,7 +889,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// Okay, we either found the r_paren. Check to see if we parsed too few
// arguments.
- unsigned MinArgsExpected = MI->getNumArgs();
+ unsigned MinArgsExpected = MI->getNumParams();
// If this is not a variadic macro, and too many args were specified, emit
// an error.
@@ -1023,7 +1023,7 @@ Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer,
size_t newIndex = MacroExpandedTokens.size();
bool cacheNeedsToGrow = tokens.size() >
- MacroExpandedTokens.capacity()-MacroExpandedTokens.size();
+ MacroExpandedTokens.capacity()-MacroExpandedTokens.size();
MacroExpandedTokens.append(tokens.begin(), tokens.end());
if (cacheNeedsToGrow) {
@@ -1125,6 +1125,7 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
.Case("attribute_overloadable", true)
.Case("attribute_unavailable_with_message", true)
.Case("attribute_unused_on_fields", true)
+ .Case("attribute_diagnose_if_objc", true)
.Case("blocks", LangOpts.Blocks)
.Case("c_thread_safety_attributes", true)
.Case("cxx_exceptions", LangOpts.CXXExceptions)
@@ -1314,6 +1315,8 @@ static bool HasExtension(const Preprocessor &PP, StringRef Extension) {
.Case("cxx_binary_literals", true)
.Case("cxx_init_captures", LangOpts.CPlusPlus11)
.Case("cxx_variable_templates", LangOpts.CPlusPlus)
+ // Miscellaneous language extensions
+ .Case("overloadable_unmarked", true)
.Default(false);
}
@@ -1422,7 +1425,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
const DirectoryLookup *CurDir;
const FileEntry *File =
PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
- CurDir, nullptr, nullptr, nullptr);
+ CurDir, nullptr, nullptr, nullptr, nullptr);
// Get the result value. A result of true means the file exists.
return File != nullptr;
@@ -1453,7 +1456,7 @@ static bool EvaluateHasIncludeNext(Token &Tok,
} else if (PP.isInPrimaryFile()) {
Lookup = nullptr;
PP.Diag(Tok, diag::pp_include_next_in_primary);
- } else if (PP.getCurrentSubmodule()) {
+ } else if (PP.getCurrentLexerSubmodule()) {
// Start looking up in the directory *after* the one in which the current
// file would be found, if any.
assert(PP.getCurrentLexer() && "#include_next directive in macro?");
@@ -1746,6 +1749,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
return llvm::StringSwitch<bool>(II->getName())
.Case("__make_integer_seq", LangOpts.CPlusPlus)
.Case("__type_pack_element", LangOpts.CPlusPlus)
+ .Case("__builtin_available", true)
.Default(false);
}
});
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index f81eaa31e9..b5d0f93954 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
@@ -475,9 +476,9 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
// Emit a line marker. This will change any source locations from this point
// forward to realize they are in a system header.
// Create a line note with this information.
- SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine()+1,
+ SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine() + 1,
FilenameID, /*IsEntry=*/false, /*IsExit=*/false,
- /*IsSystem=*/true, /*IsExternC=*/false);
+ SrcMgr::C_System);
}
/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
@@ -508,7 +509,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
const DirectoryLookup *CurDir;
const FileEntry *File =
LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
- nullptr, CurDir, nullptr, nullptr, nullptr);
+ nullptr, CurDir, nullptr, nullptr, nullptr, nullptr);
if (!File) {
if (!SuppressIncludeNotFoundError)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
@@ -754,6 +755,125 @@ void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) {
getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
}
+// Lex a component of a module name: either an identifier or a string literal;
+// for components that can be expressed both ways, the two forms are equivalent.
+static bool LexModuleNameComponent(
+ Preprocessor &PP, Token &Tok,
+ std::pair<IdentifierInfo *, SourceLocation> &ModuleNameComponent,
+ bool First) {
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
+ StringLiteralParser Literal(Tok, PP);
+ if (Literal.hadError)
+ return true;
+ ModuleNameComponent = std::make_pair(
+ PP.getIdentifierInfo(Literal.GetString()), Tok.getLocation());
+ } else if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) {
+ ModuleNameComponent =
+ std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation());
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << First;
+ return true;
+ }
+ return false;
+}
+
+static bool LexModuleName(
+ Preprocessor &PP, Token &Tok,
+ llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
+ &ModuleName) {
+ while (true) {
+ std::pair<IdentifierInfo*, SourceLocation> NameComponent;
+ if (LexModuleNameComponent(PP, Tok, NameComponent, ModuleName.empty()))
+ return true;
+ ModuleName.push_back(NameComponent);
+
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::period))
+ return false;
+ }
+}
+
+void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
+ SourceLocation Loc = Tok.getLocation();
+
+ std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
+ if (LexModuleNameComponent(*this, Tok, ModuleNameLoc, true))
+ return;
+ IdentifierInfo *ModuleName = ModuleNameLoc.first;
+
+ LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eod)) {
+ Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+ DiscardUntilEndOfDirective();
+ }
+
+ if (CurPTHLexer) {
+ // FIXME: Support this somehow?
+ Diag(Loc, diag::err_pp_module_build_pth);
+ return;
+ }
+
+ CurLexer->LexingRawMode = true;
+
+ auto TryConsumeIdentifier = [&](StringRef Ident) -> bool {
+ if (Tok.getKind() != tok::raw_identifier ||
+ Tok.getRawIdentifier() != Ident)
+ return false;
+ CurLexer->Lex(Tok);
+ return true;
+ };
+
+ // Scan forward looking for the end of the module.
+ const char *Start = CurLexer->getBufferLocation();
+ const char *End = nullptr;
+ unsigned NestingLevel = 1;
+ while (true) {
+ End = CurLexer->getBufferLocation();
+ CurLexer->Lex(Tok);
+
+ if (Tok.is(tok::eof)) {
+ Diag(Loc, diag::err_pp_module_build_missing_end);
+ break;
+ }
+
+ if (Tok.isNot(tok::hash) || !Tok.isAtStartOfLine()) {
+ // Token was part of module; keep going.
+ continue;
+ }
+
+ // We hit something directive-shaped; check to see if this is the end
+ // of the module build.
+ CurLexer->ParsingPreprocessorDirective = true;
+ CurLexer->Lex(Tok);
+ if (TryConsumeIdentifier("pragma") && TryConsumeIdentifier("clang") &&
+ TryConsumeIdentifier("module")) {
+ if (TryConsumeIdentifier("build"))
+ // #pragma clang module build -> entering a nested module build.
+ ++NestingLevel;
+ else if (TryConsumeIdentifier("endbuild")) {
+ // #pragma clang module endbuild -> leaving a module build.
+ if (--NestingLevel == 0)
+ break;
+ }
+ // We should either be looking at the EOD or more of the current directive
+ // preceding the EOD. Either way we can ignore this token and keep going.
+ assert(Tok.getKind() != tok::eof && "missing EOD before EOF");
+ }
+ }
+
+ CurLexer->LexingRawMode = false;
+
+ // Load the extracted text as a preprocessed module.
+ assert(CurLexer->getBuffer().begin() <= Start &&
+ Start <= CurLexer->getBuffer().end() &&
+ CurLexer->getBuffer().begin() <= End &&
+ End <= CurLexer->getBuffer().end() &&
+ "module source range not contained within same file buffer");
+ TheModuleLoader.loadModuleFromSource(Loc, ModuleName->getName(),
+ StringRef(Start, End - Start));
+}
+
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
@@ -989,9 +1109,9 @@ struct PragmaDebugHandler : public PragmaHandler {
#ifdef _MSC_VER
#pragma warning(disable : 4717)
#endif
- static void DebugOverflowStack() {
- void (*volatile Self)() = DebugOverflowStack;
- Self();
+ static void DebugOverflowStack(void (*P)() = nullptr) {
+ void (*volatile Self)(void(*P)()) = DebugOverflowStack;
+ Self(reinterpret_cast<void(*)()>(Self));
}
#ifdef _MSC_VER
#pragma warning(default : 4717)
@@ -1301,6 +1421,160 @@ public:
}
};
+/// Handle the clang \#pragma module import extension. The syntax is:
+/// \code
+/// #pragma clang module import some.module.name
+/// \endcode
+struct PragmaModuleImportHandler : public PragmaHandler {
+ PragmaModuleImportHandler() : PragmaHandler("import") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation ImportLoc = Tok.getLocation();
+
+ // Read the module name.
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
+ ModuleName;
+ if (LexModuleName(PP, Tok, ModuleName))
+ return;
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // If we have a non-empty module path, load the named module.
+ Module *Imported =
+ PP.getModuleLoader().loadModule(ImportLoc, ModuleName, Module::Hidden,
+ /*IsIncludeDirective=*/false);
+ if (!Imported)
+ return;
+
+ PP.makeModuleVisible(Imported, ImportLoc);
+ PP.EnterAnnotationToken(SourceRange(ImportLoc, ModuleName.back().second),
+ tok::annot_module_include, Imported);
+ if (auto *CB = PP.getPPCallbacks())
+ CB->moduleImport(ImportLoc, ModuleName, Imported);
+ }
+};
+
+/// Handle the clang \#pragma module begin extension. The syntax is:
+/// \code
+/// #pragma clang module begin some.module.name
+/// ...
+/// #pragma clang module end
+/// \endcode
+struct PragmaModuleBeginHandler : public PragmaHandler {
+ PragmaModuleBeginHandler() : PragmaHandler("begin") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation BeginLoc = Tok.getLocation();
+
+ // Read the module name.
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
+ ModuleName;
+ if (LexModuleName(PP, Tok, ModuleName))
+ return;
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // We can only enter submodules of the current module.
+ StringRef Current = PP.getLangOpts().CurrentModule;
+ if (ModuleName.front().first->getName() != Current) {
+ PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_wrong_module)
+ << ModuleName.front().first << (ModuleName.size() > 1)
+ << Current.empty() << Current;
+ return;
+ }
+
+ // Find the module we're entering. We require that a module map for it
+ // be loaded or implicitly loadable.
+ // FIXME: We could create the submodule here. We'd need to know whether
+ // it's supposed to be explicit, but not much else.
+ Module *M = PP.getHeaderSearchInfo().lookupModule(Current);
+ if (!M) {
+ PP.Diag(ModuleName.front().second,
+ diag::err_pp_module_begin_no_module_map) << Current;
+ return;
+ }
+ for (unsigned I = 1; I != ModuleName.size(); ++I) {
+ auto *NewM = M->findSubmodule(ModuleName[I].first->getName());
+ if (!NewM) {
+ PP.Diag(ModuleName[I].second, diag::err_pp_module_begin_no_submodule)
+ << M->getFullModuleName() << ModuleName[I].first;
+ return;
+ }
+ M = NewM;
+ }
+
+ // If the module isn't available, it doesn't make sense to enter it.
+ if (Preprocessor::checkModuleIsAvailable(
+ PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics(), M)) {
+ PP.Diag(BeginLoc, diag::note_pp_module_begin_here)
+ << M->getTopLevelModuleName();
+ return;
+ }
+
+ // Enter the scope of the submodule.
+ PP.EnterSubmodule(M, BeginLoc, /*ForPragma*/true);
+ PP.EnterAnnotationToken(SourceRange(BeginLoc, ModuleName.back().second),
+ tok::annot_module_begin, M);
+ }
+};
+
+/// Handle the clang \#pragma module end extension.
+struct PragmaModuleEndHandler : public PragmaHandler {
+ PragmaModuleEndHandler() : PragmaHandler("end") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation Loc = Tok.getLocation();
+
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ Module *M = PP.LeaveSubmodule(/*ForPragma*/true);
+ if (M)
+ PP.EnterAnnotationToken(SourceRange(Loc), tok::annot_module_end, M);
+ else
+ PP.Diag(Loc, diag::err_pp_module_end_without_module_begin);
+ }
+};
+
+/// Handle the clang \#pragma module build extension.
+struct PragmaModuleBuildHandler : public PragmaHandler {
+ PragmaModuleBuildHandler() : PragmaHandler("build") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ PP.HandlePragmaModuleBuild(Tok);
+ }
+};
+
+/// Handle the clang \#pragma module load extension.
+struct PragmaModuleLoadHandler : public PragmaHandler {
+ PragmaModuleLoadHandler() : PragmaHandler("load") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation Loc = Tok.getLocation();
+
+ // Read the module name.
+ llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
+ ModuleName;
+ if (LexModuleName(PP, Tok, ModuleName))
+ return;
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+
+ // Load the module, don't make it visible.
+ PP.getModuleLoader().loadModule(Loc, ModuleName, Module::Hidden,
+ /*IsIncludeDirective=*/false);
+ }
+};
+
/// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the
/// macro on the top of the stack.
struct PragmaPushMacroHandler : public PragmaHandler {
@@ -1451,6 +1725,7 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler {
// The start location we want after processing this.
SourceLocation NewLoc;
+ PPCallbacks *Callbacks = PP.getPPCallbacks();
if (IsBegin) {
// Complain about attempts to re-enter an audit.
@@ -1459,6 +1734,8 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler {
PP.Diag(BeginLoc, diag::note_pragma_entered_here);
}
NewLoc = Loc;
+ if (Callbacks)
+ Callbacks->PragmaAssumeNonNullBegin(NewLoc);
} else {
// Complain about attempts to leave an audit that doesn't exist.
if (!BeginLoc.isValid()) {
@@ -1466,6 +1743,8 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler {
return;
}
NewLoc = SourceLocation();
+ if (Callbacks)
+ Callbacks->PragmaAssumeNonNullEnd(NewLoc);
}
PP.setPragmaAssumeNonNullLoc(NewLoc);
@@ -1524,6 +1803,15 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler());
AddPragmaHandler("clang", new PragmaAssumeNonNullHandler());
+ // #pragma clang module ...
+ auto *ModuleHandler = new PragmaNamespace("module");
+ AddPragmaHandler("clang", ModuleHandler);
+ ModuleHandler->AddPragma(new PragmaModuleImportHandler());
+ ModuleHandler->AddPragma(new PragmaModuleBeginHandler());
+ ModuleHandler->AddPragma(new PragmaModuleEndHandler());
+ ModuleHandler->AddPragma(new PragmaModuleBuildHandler());
+ ModuleHandler->AddPragma(new PragmaModuleLoadHandler());
+
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler());
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 13e15f3c94..954b569bb0 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -400,8 +400,9 @@ void PreprocessingRecord::Defined(const Token &MacroNameTok,
MacroNameTok.getLocation());
}
-void PreprocessingRecord::SourceRangeSkipped(SourceRange Range) {
- SkippedRanges.push_back(Range);
+void PreprocessingRecord::SourceRangeSkipped(SourceRange Range,
+ SourceLocation EndifLoc) {
+ SkippedRanges.emplace_back(Range.getBegin(), EndifLoc);
}
void PreprocessingRecord::MacroExpands(const Token &Id,
@@ -422,7 +423,8 @@ void PreprocessingRecord::MacroDefined(const Token &Id,
}
void PreprocessingRecord::MacroUndefined(const Token &Id,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); });
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 91319bedd6..65df6a57f1 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -70,25 +70,25 @@ ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts,
- SourceManager &SM, HeaderSearch &Headers,
- ModuleLoader &TheModuleLoader,
+ SourceManager &SM, MemoryBufferCache &PCMCache,
+ HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup, bool OwnsHeaders,
TranslationUnitKind TUKind)
: PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), Target(nullptr),
AuxTarget(nullptr), FileMgr(Headers.getFileMgr()), SourceMgr(SM),
- ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers),
- TheModuleLoader(TheModuleLoader), ExternalSource(nullptr),
- Identifiers(opts, IILookup),
+ PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)),
+ HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
+ ExternalSource(nullptr), Identifiers(opts, IILookup),
PragmaHandlers(new PragmaNamespace(StringRef())),
IncrementalProcessing(false), TUKind(TUKind), CodeComplete(nullptr),
CodeCompletionFile(nullptr), CodeCompletionOffset(0),
LastTokenWasAt(false), ModuleImportExpectsIdentifier(false),
CodeCompletionReached(false), CodeCompletionII(nullptr),
MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
- CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr),
- Callbacks(nullptr), CurSubmoduleState(&NullSubmoduleState),
- MacroArgCache(nullptr), Record(nullptr), MIChainHead(nullptr),
- DeserialMIChainHead(nullptr) {
+ CurDirLookup(nullptr), CurLexerKind(CLK_Lexer),
+ CurLexerSubmodule(nullptr), Callbacks(nullptr),
+ CurSubmoduleState(&NullSubmoduleState), MacroArgCache(nullptr),
+ Record(nullptr), MIChainHead(nullptr) {
OwnsHeaderSearch = OwnsHeaders;
CounterValue = 0; // __COUNTER__ starts at 0.
@@ -121,12 +121,18 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
// We haven't read anything from the external source.
ReadMacrosFromExternalSource = false;
-
- // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
- // This gets unpoisoned where it is allowed.
+
+ // "Poison" __VA_ARGS__, __VA_OPT__ which can only appear in the expansion of
+ // a macro. They get unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
-
+ if (getLangOpts().CPlusPlus2a) {
+ (Ident__VA_OPT__ = getIdentifierInfo("__VA_OPT__"))->setIsPoisoned();
+ SetPoisonReason(Ident__VA_OPT__,diag::ext_pp_bad_vaopt_use);
+ } else {
+ Ident__VA_OPT__ = nullptr;
+ }
+
// Initialize the pragma handlers.
RegisterBuiltinPragmas();
@@ -150,6 +156,9 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
Ident_GetExceptionInfo = Ident_GetExceptionCode = nullptr;
Ident_AbnormalTermination = nullptr;
}
+
+ if (this->PPOpts->GeneratePreamble)
+ PreambleConditionalStack.startRecording();
}
Preprocessor::~Preprocessor() {
@@ -169,11 +178,6 @@ Preprocessor::~Preprocessor() {
std::fill(TokenLexerCache, TokenLexerCache + NumCachedTokenLexers, nullptr);
CurTokenLexer.reset();
- while (DeserializedMacroInfoChain *I = DeserialMIChainHead) {
- DeserialMIChainHead = I->Next;
- I->~DeserializedMacroInfoChain();
- }
-
// Free any cached MacroArgs.
for (MacroArgs *ArgList = MacroArgCache; ArgList;)
ArgList = ArgList->deallocate();
@@ -518,9 +522,9 @@ void Preprocessor::EnterMainSourceFile() {
// If we've been asked to skip bytes in the main file (e.g., as part of a
// precompiled preamble), do so now.
if (SkipMainFilePreamble.first > 0)
- CurLexer->SkipBytes(SkipMainFilePreamble.first,
- SkipMainFilePreamble.second);
-
+ CurLexer->SetByteOffset(SkipMainFilePreamble.first,
+ SkipMainFilePreamble.second);
+
// Tell the header info that the main file was entered. If the file is later
// #imported, it won't be re-entered.
if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
@@ -539,6 +543,16 @@ void Preprocessor::EnterMainSourceFile() {
EnterSourceFile(FID, nullptr, SourceLocation());
}
+void Preprocessor::replayPreambleConditionalStack() {
+ // Restore the conditional stack from the preamble, if there is one.
+ if (PreambleConditionalStack.isReplaying()) {
+ assert(CurPPLexer &&
+ "CurPPLexer is null when calling replayPreambleConditionalStack.");
+ CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack());
+ PreambleConditionalStack.doneReplaying();
+ }
+}
+
void Preprocessor::EndSourceFile() {
// Notify the client that we reached the end of the source file.
if (Callbacks)
@@ -576,7 +590,11 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
// Update the token info (identifier info and appropriate token kind).
Identifier.setIdentifierInfo(II);
- Identifier.setKind(II->getTokenID());
+ if (getLangOpts().MSVCCompat && II->isCPlusPlusOperatorKeyword() &&
+ getSourceManager().isInSystemHeader(Identifier.getLocation()))
+ Identifier.setKind(clang::tok::identifier);
+ else
+ Identifier.setKind(II->getTokenID());
return II;
}
@@ -620,6 +638,8 @@ static diag::kind getFutureCompatDiagKind(const IdentifierInfo &II,
return llvm::StringSwitch<diag::kind>(II.getName())
#define CXX11_KEYWORD(NAME, FLAGS) \
.Case(#NAME, diag::warn_cxx11_keyword)
+#define CXX2A_KEYWORD(NAME, FLAGS) \
+ .Case(#NAME, diag::warn_cxx2a_keyword)
#include "clang/Basic/TokenKinds.def"
;
@@ -653,13 +673,15 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
// unpoisoned it if we're defining a C99 macro.
if (II.isOutOfDate()) {
bool CurrentIsPoisoned = false;
- if (&II == Ident__VA_ARGS__)
- CurrentIsPoisoned = Ident__VA_ARGS__->isPoisoned();
+ const bool IsSpecialVariadicMacro =
+ &II == Ident__VA_ARGS__ || &II == Ident__VA_OPT__;
+ if (IsSpecialVariadicMacro)
+ CurrentIsPoisoned = II.isPoisoned();
updateOutOfDateIdentifier(II);
Identifier.setKind(II.getTokenID());
- if (&II == Ident__VA_ARGS__)
+ if (IsSpecialVariadicMacro)
II.setIsPoisoned(CurrentIsPoisoned);
}
@@ -702,12 +724,6 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
II.setIsFutureCompatKeyword(false);
}
- // C++ 2.11p2: If this is an alternative representation of a C++ operator,
- // then we act as if it is the actual operator and not the textual
- // representation of it.
- if (II.isCPlusPlusOperatorKeyword())
- Identifier.setIdentifierInfo(nullptr);
-
// If this is an extension token, diagnose its use.
// We avoid diagnosing tokens that originate from macro definitions.
// FIXME: This warning is disabled in cases where it shouldn't be,
diff --git a/lib/Lex/ScratchBuffer.cpp b/lib/Lex/ScratchBuffer.cpp
index cd8a27e76c..e0f3966fce 100644
--- a/lib/Lex/ScratchBuffer.cpp
+++ b/lib/Lex/ScratchBuffer.cpp
@@ -35,6 +35,14 @@ SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
const char *&DestPtr) {
if (BytesUsed+Len+2 > ScratchBufSize)
AllocScratchBuffer(Len+2);
+ else {
+ // Clear out the source line cache if it's already been computed.
+ // FIXME: Allow this to be incrementally extended.
+ auto *ContentCache = const_cast<SrcMgr::ContentCache *>(
+ SourceMgr.getSLocEntry(SourceMgr.getFileID(BufferStartLoc))
+ .getFile().getContentCache());
+ ContentCache->SourceLineCache = nullptr;
+ }
// Prefix the token with a \n, so that it looks like it is the first thing on
// its own virtual line in caret diagnostics.
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index a53c8014eb..194ceecc07 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -17,6 +17,7 @@
#include "clang/Lex/MacroArgs.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/VariadicMacroSupport.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -31,7 +32,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI,
Macro = MI;
ActualArgs = Actuals;
- CurToken = 0;
+ CurTokenIdx = 0;
ExpandLocStart = Tok.getLocation();
ExpandLocEnd = ELEnd;
@@ -67,7 +68,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI,
// If this is a function-like macro, expand the arguments and change
// Tokens to point to the expanded tokens.
- if (Macro->isFunctionLike() && Macro->getNumArgs())
+ if (Macro->isFunctionLike() && Macro->getNumParams())
ExpandFunctionArguments();
// Mark the macro as currently disabled, so that it is not recursively
@@ -90,7 +91,7 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
OwnsTokens = ownsTokens;
DisableMacroExpansion = disableMacroExpansion;
NumTokens = NumToks;
- CurToken = 0;
+ CurTokenIdx = 0;
ExpandLocStart = ExpandLocEnd = SourceLocation();
AtStartOfLine = false;
HasLeadingSpace = false;
@@ -122,7 +123,7 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
SmallVectorImpl<Token> &ResultToks, bool HasPasteOperator, MacroInfo *Macro,
unsigned MacroArgNo, Preprocessor &PP) {
// Is the macro argument __VA_ARGS__?
- if (!Macro->isVariadic() || MacroArgNo != Macro->getNumArgs()-1)
+ if (!Macro->isVariadic() || MacroArgNo != Macro->getNumParams()-1)
return false;
// In Microsoft-compatibility mode, a comma is removed in the expansion
@@ -137,7 +138,7 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
// with GNU extensions, it is removed regardless of named arguments.
// Microsoft also appears to support this extension, unofficially.
if (PP.getLangOpts().C99 && !PP.getLangOpts().GNUMode
- && Macro->getNumArgs() < 2)
+ && Macro->getNumParams() < 2)
return false;
// Is a comma available to be removed?
@@ -168,6 +169,59 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
return true;
}
+void TokenLexer::stringifyVAOPTContents(
+ SmallVectorImpl<Token> &ResultToks, const VAOptExpansionContext &VCtx,
+ const SourceLocation VAOPTClosingParenLoc) {
+ const int NumToksPriorToVAOpt = VCtx.getNumberOfTokensPriorToVAOpt();
+ const unsigned int NumVAOptTokens = ResultToks.size() - NumToksPriorToVAOpt;
+ Token *const VAOPTTokens =
+ NumVAOptTokens ? &ResultToks[NumToksPriorToVAOpt] : nullptr;
+
+ SmallVector<Token, 64> ConcatenatedVAOPTResultToks;
+ // FIXME: Should we keep track within VCtx that we did or didnot
+ // encounter pasting - and only then perform this loop.
+
+ // Perform token pasting (concatenation) prior to stringization.
+ for (unsigned int CurTokenIdx = 0; CurTokenIdx != NumVAOptTokens;
+ ++CurTokenIdx) {
+ if (VAOPTTokens[CurTokenIdx].is(tok::hashhash)) {
+ assert(CurTokenIdx != 0 &&
+ "Can not have __VAOPT__ contents begin with a ##");
+ Token &LHS = VAOPTTokens[CurTokenIdx - 1];
+ pasteTokens(LHS, llvm::makeArrayRef(VAOPTTokens, NumVAOptTokens),
+ CurTokenIdx);
+ // Replace the token prior to the first ## in this iteration.
+ ConcatenatedVAOPTResultToks.back() = LHS;
+ if (CurTokenIdx == NumVAOptTokens)
+ break;
+ }
+ ConcatenatedVAOPTResultToks.push_back(VAOPTTokens[CurTokenIdx]);
+ }
+
+ ConcatenatedVAOPTResultToks.push_back(VCtx.getEOFTok());
+ // Get the SourceLocation that represents the start location within
+ // the macro definition that marks where this string is substituted
+ // into: i.e. the __VA_OPT__ and the ')' within the spelling of the
+ // macro definition, and use it to indicate that the stringified token
+ // was generated from that location.
+ const SourceLocation ExpansionLocStartWithinMacro =
+ getExpansionLocForMacroDefLoc(VCtx.getVAOptLoc());
+ const SourceLocation ExpansionLocEndWithinMacro =
+ getExpansionLocForMacroDefLoc(VAOPTClosingParenLoc);
+
+ Token StringifiedVAOPT = MacroArgs::StringifyArgument(
+ &ConcatenatedVAOPTResultToks[0], PP, VCtx.hasCharifyBefore() /*Charify*/,
+ ExpansionLocStartWithinMacro, ExpansionLocEndWithinMacro);
+
+ if (VCtx.getLeadingSpaceForStringifiedToken())
+ StringifiedVAOPT.setFlag(Token::LeadingSpace);
+
+ StringifiedVAOPT.setFlag(Token::StringifiedInMacro);
+ // Resize (shrink) the token stream to just capture this stringified token.
+ ResultToks.resize(NumToksPriorToVAOpt + 1);
+ ResultToks.back() = StringifiedVAOPT;
+}
+
/// Expand the arguments of a function-like macro so that we can quickly
/// return preexpanded tokens from Tokens.
void TokenLexer::ExpandFunctionArguments() {
@@ -178,22 +232,119 @@ void TokenLexer::ExpandFunctionArguments() {
// we install the newly expanded sequence as the new 'Tokens' list.
bool MadeChange = false;
- for (unsigned i = 0, e = NumTokens; i != e; ++i) {
- // If we found the stringify operator, get the argument stringified. The
- // preprocessor already verified that the following token is a macro name
- // when the #define was parsed.
- const Token &CurTok = Tokens[i];
- if (i != 0 && !Tokens[i-1].is(tok::hashhash) && CurTok.hasLeadingSpace())
+ const bool CalledWithVariadicArguments =
+ ActualArgs->invokedWithVariadicArgument(Macro);
+
+ VAOptExpansionContext VCtx(PP);
+
+ for (unsigned I = 0, E = NumTokens; I != E; ++I) {
+
+ const Token &CurTok = Tokens[I];
+ // We don't want a space for the next token after a paste
+ // operator. In valid code, the token will get smooshed onto the
+ // preceding one anyway. In assembler-with-cpp mode, invalid
+ // pastes are allowed through: in this case, we do not want the
+ // extra whitespace to be added. For example, we want ". ## foo"
+ // -> ".foo" not ". foo".
+ if (I != 0 && !Tokens[I-1].is(tok::hashhash) && CurTok.hasLeadingSpace())
NextTokGetsSpace = true;
- if (CurTok.isOneOf(tok::hash, tok::hashat)) {
- int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
- assert(ArgNo != -1 && "Token following # is not an argument?");
+ if (VCtx.isVAOptToken(CurTok)) {
+ MadeChange = true;
+ assert(Tokens[I + 1].is(tok::l_paren) &&
+ "__VA_OPT__ must be followed by '('");
+
+ ++I; // Skip the l_paren
+ VCtx.sawVAOptFollowedByOpeningParens(CurTok.getLocation(),
+ ResultToks.size());
+
+ continue;
+ }
+ // We have entered into the __VA_OPT__ context, so handle tokens
+ // appropriately.
+ if (VCtx.isInVAOpt()) {
+ // If we are about to process a token that is either an argument to
+ // __VA_OPT__ or its closing rparen, then:
+ // 1) If the token is the closing rparen that exits us out of __VA_OPT__,
+ // perform any necessary stringification or placemarker processing,
+ // and/or skip to the next token.
+ // 2) else if macro was invoked without variadic arguments skip this
+ // token.
+ // 3) else (macro was invoked with variadic arguments) process the token
+ // normally.
+
+ if (Tokens[I].is(tok::l_paren))
+ VCtx.sawOpeningParen(Tokens[I].getLocation());
+ // Continue skipping tokens within __VA_OPT__ if the macro was not
+ // called with variadic arguments, else let the rest of the loop handle
+ // this token. Note sawClosingParen() returns true only if the r_paren matches
+ // the closing r_paren of the __VA_OPT__.
+ if (!Tokens[I].is(tok::r_paren) || !VCtx.sawClosingParen()) {
+ if (!CalledWithVariadicArguments) {
+ // Skip this token.
+ continue;
+ }
+ // ... else the macro was called with variadic arguments, and we do not
+ // have a closing rparen - so process this token normally.
+
+ } else {
+ // Current token is the closing r_paren which marks the end of the
+ // __VA_OPT__ invocation, so handle any place-marker pasting (if
+ // empty) by removing hashhash either before (if exists) or after. And
+ // also stringify the entire contents if VAOPT was preceded by a hash,
+ // but do so only after any token concatenation that needs to occur
+ // within the contents of VAOPT.
+
+ if (VCtx.hasStringifyOrCharifyBefore()) {
+ // Replace all the tokens just added from within VAOPT into a single
+ // stringified token. This requires token-pasting to eagerly occur
+ // within these tokens. If either the contents of VAOPT were empty
+ // or the macro wasn't called with any variadic arguments, the result
+ // is a token that represents an empty string.
+ stringifyVAOPTContents(ResultToks, VCtx,
+ /*ClosingParenLoc*/ Tokens[I].getLocation());
+
+ } else if (/*No tokens within VAOPT*/ !(
+ ResultToks.size() - VCtx.getNumberOfTokensPriorToVAOpt())) {
+ // Treat VAOPT as a placemarker token. Eat either the '##' before the
+ // RHS/VAOPT (if one exists, suggesting that the LHS (if any) to that
+ // hashhash was not a placemarker) or the '##'
+ // after VAOPT, but not both.
+
+ if (ResultToks.size() && ResultToks.back().is(tok::hashhash)) {
+ ResultToks.pop_back();
+ } else if ((I + 1 != E) && Tokens[I + 1].is(tok::hashhash)) {
+ ++I; // Skip the following hashhash.
+ }
+ }
+ VCtx.reset();
+ // We processed __VA_OPT__'s closing paren (and the exit out of
+ // __VA_OPT__), so skip to the next token.
+ continue;
+ }
+ }
+
+ // If we found the stringify operator, get the argument stringified. The
+ // preprocessor already verified that the following token is a macro
+ // parameter or __VA_OPT__ when the #define was lexed.
+
+ if (CurTok.isOneOf(tok::hash, tok::hashat)) {
+ int ArgNo = Macro->getParameterNum(Tokens[I+1].getIdentifierInfo());
+ assert((ArgNo != -1 || VCtx.isVAOptToken(Tokens[I + 1])) &&
+ "Token following # is not an argument or __VA_OPT__!");
+
+ if (ArgNo == -1) {
+ // Handle the __VA_OPT__ case.
+ VCtx.sawHashOrHashAtBefore(NextTokGetsSpace,
+ CurTok.is(tok::hashat));
+ continue;
+ }
+ // Else handle the simple argument case.
SourceLocation ExpansionLocStart =
getExpansionLocForMacroDefLoc(CurTok.getLocation());
SourceLocation ExpansionLocEnd =
- getExpansionLocForMacroDefLoc(Tokens[i+1].getLocation());
+ getExpansionLocForMacroDefLoc(Tokens[I+1].getLocation());
Token Res;
if (CurTok.is(tok::hash)) // Stringify
@@ -216,7 +367,7 @@ void TokenLexer::ExpandFunctionArguments() {
ResultToks.push_back(Res);
MadeChange = true;
- ++i; // Skip arg name.
+ ++I; // Skip arg name.
NextTokGetsSpace = false;
continue;
}
@@ -224,14 +375,16 @@ void TokenLexer::ExpandFunctionArguments() {
// Find out if there is a paste (##) operator before or after the token.
bool NonEmptyPasteBefore =
!ResultToks.empty() && ResultToks.back().is(tok::hashhash);
- bool PasteBefore = i != 0 && Tokens[i-1].is(tok::hashhash);
- bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
- assert(!NonEmptyPasteBefore || PasteBefore);
+ bool PasteBefore = I != 0 && Tokens[I-1].is(tok::hashhash);
+ bool PasteAfter = I+1 != E && Tokens[I+1].is(tok::hashhash);
+
+ assert((!NonEmptyPasteBefore || PasteBefore || VCtx.isInVAOpt()) &&
+ "unexpected ## in ResultToks");
// Otherwise, if this is not an argument token, just add the token to the
// output buffer.
IdentifierInfo *II = CurTok.getIdentifierInfo();
- int ArgNo = II ? Macro->getArgumentNum(II) : -1;
+ int ArgNo = II ? Macro->getParameterNum(II) : -1;
if (ArgNo == -1) {
// This isn't an argument, just add it.
ResultToks.push_back(CurTok);
@@ -269,7 +422,7 @@ void TokenLexer::ExpandFunctionArguments() {
// avoids some work in common cases.
const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo);
if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP))
- ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, Macro, PP)[0];
+ ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0];
else
ResultArgToks = ArgTok; // Use non-preexpanded tokens.
@@ -317,14 +470,16 @@ void TokenLexer::ExpandFunctionArguments() {
const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo);
unsigned NumToks = MacroArgs::getArgLength(ArgToks);
if (NumToks) { // Not an empty argument?
+ bool VaArgsPseudoPaste = false;
// If this is the GNU ", ## __VA_ARGS__" extension, and we just learned
// that __VA_ARGS__ expands to multiple tokens, avoid a pasting error when
// the expander trys to paste ',' with the first token of the __VA_ARGS__
// expansion.
if (NonEmptyPasteBefore && ResultToks.size() >= 2 &&
ResultToks[ResultToks.size()-2].is(tok::comma) &&
- (unsigned)ArgNo == Macro->getNumArgs()-1 &&
+ (unsigned)ArgNo == Macro->getNumParams()-1 &&
Macro->isVariadic()) {
+ VaArgsPseudoPaste = true;
// Remove the paste operator, report use of the extension.
PP.Diag(ResultToks.pop_back_val().getLocation(), diag::ext_paste_comma);
}
@@ -344,18 +499,16 @@ void TokenLexer::ExpandFunctionArguments() {
ResultToks.end()-NumToks, ResultToks.end());
}
- // If this token (the macro argument) was supposed to get leading
- // whitespace, transfer this information onto the first token of the
- // expansion.
- //
- // Do not do this if the paste operator occurs before the macro argument,
- // as in "A ## MACROARG". In valid code, the first token will get
- // smooshed onto the preceding one anyway (forming AMACROARG). In
- // assembler-with-cpp mode, invalid pastes are allowed through: in this
- // case, we do not want the extra whitespace to be added. For example,
- // we want ". ## foo" -> ".foo" not ". foo".
- if (NextTokGetsSpace)
- ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
+ // Transfer the leading whitespace information from the token
+ // (the macro argument) onto the first token of the
+ // expansion. Note that we don't do this for the GNU
+ // pseudo-paste extension ", ## __VA_ARGS__".
+ if (!VaArgsPseudoPaste) {
+ ResultToks[ResultToks.size() - NumToks].setFlagValue(Token::StartOfLine,
+ false);
+ ResultToks[ResultToks.size() - NumToks].setFlagValue(
+ Token::LeadingSpace, NextTokGetsSpace);
+ }
NextTokGetsSpace = false;
continue;
@@ -368,7 +521,7 @@ void TokenLexer::ExpandFunctionArguments() {
if (PasteAfter) {
// Discard the argument token and skip (don't copy to the expansion
// buffer) the paste operator after it.
- ++i;
+ ++I;
continue;
}
@@ -378,7 +531,13 @@ void TokenLexer::ExpandFunctionArguments() {
assert(PasteBefore);
if (NonEmptyPasteBefore) {
assert(ResultToks.back().is(tok::hashhash));
- ResultToks.pop_back();
+ // Do not remove the paste operator if it is the one before __VA_OPT__
+ // (and we are still processing tokens within VA_OPT). We handle the case
+ // of removing the paste operator if __VA_OPT__ reduces to the notional
+ // placemarker above when we encounter the closing paren of VA_OPT.
+ if (!VCtx.isInVAOpt() ||
+ ResultToks.size() > VCtx.getNumberOfTokensPriorToVAOpt())
+ ResultToks.pop_back();
}
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
@@ -425,7 +584,7 @@ bool TokenLexer::Lex(Token &Tok) {
Tok.startToken();
Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace || NextTokGetsSpace);
- if (CurToken == 0)
+ if (CurTokenIdx == 0)
Tok.setFlag(Token::LeadingEmptyMacro);
return PP.HandleEndOfTokenLexer(Tok);
}
@@ -434,25 +593,25 @@ bool TokenLexer::Lex(Token &Tok) {
// If this is the first token of the expanded result, we inherit spacing
// properties later.
- bool isFirstToken = CurToken == 0;
+ bool isFirstToken = CurTokenIdx == 0;
// Get the next token to return.
- Tok = Tokens[CurToken++];
+ Tok = Tokens[CurTokenIdx++];
bool TokenIsFromPaste = false;
// If this token is followed by a token paste (##) operator, paste the tokens!
// Note that ## is a normal token when not expanding a macro.
if (!isAtEnd() && Macro &&
- (Tokens[CurToken].is(tok::hashhash) ||
+ (Tokens[CurTokenIdx].is(tok::hashhash) ||
// Special processing of L#x macros in -fms-compatibility mode.
// Microsoft compiler is able to form a wide string literal from
// 'L#macro_arg' construct in a function-like macro.
(PP.getLangOpts().MSVCCompat &&
- isWideStringLiteralFromMacro(Tok, Tokens[CurToken])))) {
+ isWideStringLiteralFromMacro(Tok, Tokens[CurTokenIdx])))) {
// When handling the microsoft /##/ extension, the final token is
- // returned by PasteTokens, not the pasted token.
- if (PasteTokens(Tok))
+ // returned by pasteTokens, not the pasted token.
+ if (pasteTokens(Tok))
return true;
TokenIsFromPaste = true;
@@ -515,40 +674,56 @@ bool TokenLexer::Lex(Token &Tok) {
return true;
}
-/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
+bool TokenLexer::pasteTokens(Token &Tok) {
+ return pasteTokens(Tok, llvm::makeArrayRef(Tokens, NumTokens), CurTokenIdx);
+}
+/// LHSTok is the LHS of a ## operator, and CurTokenIdx is the ##
/// operator. Read the ## and RHS, and paste the LHS/RHS together. If there
-/// are more ## after it, chomp them iteratively. Return the result as Tok.
+/// are more ## after it, chomp them iteratively. Return the result as LHSTok.
/// If this returns true, the caller should immediately return the token.
-bool TokenLexer::PasteTokens(Token &Tok) {
+bool TokenLexer::pasteTokens(Token &LHSTok, ArrayRef<Token> TokenStream,
+ unsigned int &CurIdx) {
+ assert(CurIdx > 0 && "## can not be the first token within tokens");
+ assert((TokenStream[CurIdx].is(tok::hashhash) ||
+ (PP.getLangOpts().MSVCCompat &&
+ isWideStringLiteralFromMacro(LHSTok, TokenStream[CurIdx]))) &&
+ "Token at this Index must be ## or part of the MSVC 'L "
+ "#macro-arg' pasting pair");
+
// MSVC: If previous token was pasted, this must be a recovery from an invalid
// paste operation. Ignore spaces before this token to mimic MSVC output.
// Required for generating valid UUID strings in some MS headers.
- if (PP.getLangOpts().MicrosoftExt && (CurToken >= 2) &&
- Tokens[CurToken - 2].is(tok::hashhash))
- Tok.clearFlag(Token::LeadingSpace);
+ if (PP.getLangOpts().MicrosoftExt && (CurIdx >= 2) &&
+ TokenStream[CurIdx - 2].is(tok::hashhash))
+ LHSTok.clearFlag(Token::LeadingSpace);
SmallString<128> Buffer;
const char *ResultTokStrPtr = nullptr;
- SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation StartLoc = LHSTok.getLocation();
SourceLocation PasteOpLoc;
+
+ auto IsAtEnd = [&TokenStream, &CurIdx] {
+ return TokenStream.size() == CurIdx;
+ };
+
do {
// Consume the ## operator if any.
- PasteOpLoc = Tokens[CurToken].getLocation();
- if (Tokens[CurToken].is(tok::hashhash))
- ++CurToken;
- assert(!isAtEnd() && "No token on the RHS of a paste operator!");
+ PasteOpLoc = TokenStream[CurIdx].getLocation();
+ if (TokenStream[CurIdx].is(tok::hashhash))
+ ++CurIdx;
+ assert(!IsAtEnd() && "No token on the RHS of a paste operator!");
// Get the RHS token.
- const Token &RHS = Tokens[CurToken];
+ const Token &RHS = TokenStream[CurIdx];
// Allocate space for the result token. This is guaranteed to be enough for
// the two tokens.
- Buffer.resize(Tok.getLength() + RHS.getLength());
+ Buffer.resize(LHSTok.getLength() + RHS.getLength());
// Get the spelling of the LHS token in Buffer.
const char *BufPtr = &Buffer[0];
bool Invalid = false;
- unsigned LHSLen = PP.getSpelling(Tok, BufPtr, &Invalid);
+ unsigned LHSLen = PP.getSpelling(LHSTok, BufPtr, &Invalid);
if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer!
memcpy(&Buffer[0], BufPtr, LHSLen);
if (Invalid)
@@ -580,7 +755,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Lex the resultant pasted token into Result.
Token Result;
- if (Tok.isAnyIdentifier() && RHS.isAnyIdentifier()) {
+ if (LHSTok.isAnyIdentifier() && RHS.isAnyIdentifier()) {
// Common paste case: identifier+identifier = identifier. Avoid creating
// a lexer and other overhead.
PP.IncrementPasteCounter(true);
@@ -620,7 +795,7 @@ bool TokenLexer::PasteTokens(Token &Tok) {
isInvalid |= Result.is(tok::eof);
// If pasting the two tokens didn't form a full new token, this is an
- // error. This occurs with "x ## +" and other stuff. Return with Tok
+ // error. This occurs with "x ## +" and other stuff. Return with LHSTok
// unmodified and with RHS as the next token to lex.
if (isInvalid) {
// Explicitly convert the token location to have proper expansion
@@ -631,9 +806,9 @@ bool TokenLexer::PasteTokens(Token &Tok) {
// Test for the Microsoft extension of /##/ turning into // here on the
// error path.
- if (PP.getLangOpts().MicrosoftExt && Tok.is(tok::slash) &&
+ if (PP.getLangOpts().MicrosoftExt && LHSTok.is(tok::slash) &&
RHS.is(tok::slash)) {
- HandleMicrosoftCommentPaste(Tok, Loc);
+ HandleMicrosoftCommentPaste(LHSTok, Loc);
return true;
}
@@ -658,15 +833,15 @@ bool TokenLexer::PasteTokens(Token &Tok) {
}
// Transfer properties of the LHS over the Result.
- Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine());
- Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace());
+ Result.setFlagValue(Token::StartOfLine , LHSTok.isAtStartOfLine());
+ Result.setFlagValue(Token::LeadingSpace, LHSTok.hasLeadingSpace());
// Finally, replace LHS with the result, consume the RHS, and iterate.
- ++CurToken;
- Tok = Result;
- } while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash));
+ ++CurIdx;
+ LHSTok = Result;
+ } while (!IsAtEnd() && TokenStream[CurIdx].is(tok::hashhash));
- SourceLocation EndLoc = Tokens[CurToken - 1].getLocation();
+ SourceLocation EndLoc = TokenStream[CurIdx - 1].getLocation();
// The token's current location indicate where the token was lexed from. We
// need this information to compute the spelling of the token, but any
@@ -684,16 +859,16 @@ bool TokenLexer::PasteTokens(Token &Tok) {
while (SM.getFileID(EndLoc) != MacroFID)
EndLoc = SM.getImmediateExpansionRange(EndLoc).second;
- Tok.setLocation(SM.createExpansionLoc(Tok.getLocation(), StartLoc, EndLoc,
- Tok.getLength()));
+ LHSTok.setLocation(SM.createExpansionLoc(LHSTok.getLocation(), StartLoc, EndLoc,
+ LHSTok.getLength()));
// Now that we got the result token, it will be subject to expansion. Since
// token pasting re-lexes the result token in raw mode, identifier information
// isn't looked up. As such, if the result is an identifier, look up id info.
- if (Tok.is(tok::raw_identifier)) {
+ if (LHSTok.is(tok::raw_identifier)) {
// Look up the identifier info for the token. We disabled identifier lookup
// by saying we're skipping contents, so we need to do this manually.
- PP.LookUpIdentifierInfo(Tok);
+ PP.LookUpIdentifierInfo(LHSTok);
}
return false;
}
@@ -705,7 +880,7 @@ unsigned TokenLexer::isNextTokenLParen() const {
// Out of tokens?
if (isAtEnd())
return 2;
- return Tokens[CurToken].is(tok::l_paren);
+ return Tokens[CurTokenIdx].is(tok::l_paren);
}
/// isParsingPreprocessorDirective - Return true if we are in the middle of a
@@ -825,9 +1000,8 @@ static void updateConsecutiveMacroArgTokens(SourceManager &SM,
/// \brief Creates SLocEntries and updates the locations of macro argument
/// tokens to their new expanded locations.
///
-/// \param ArgIdDefLoc the location of the macro argument id inside the macro
+/// \param ArgIdSpellLoc the location of the macro argument id inside the macro
/// definition.
-/// \param Tokens the macro argument tokens to update.
void TokenLexer::updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
Token *begin_tokens,
Token *end_tokens) {
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index c52b61e7e9..2b3d4ba85b 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;
@@ -166,20 +166,11 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
}
if (FnD) {
- // If this is a friend function, mark that it's late-parsed so that
- // it's still known to be a definition even before we attach the
- // parsed body. Sema needs to treat friend function definitions
- // differently during template instantiation, and it's possible for
- // the containing class to be instantiated before all its member
- // function definitions are parsed.
- //
- // If you remove this, you can remove the code that clears the flag
- // after parsing the member.
- if (D.getDeclSpec().isFriendSpecified()) {
- FunctionDecl *FD = FnD->getAsFunction();
- Actions.CheckForFunctionRedefinition(FD);
- FD->setLateTemplateParsed(true);
- }
+ FunctionDecl *FD = FnD->getAsFunction();
+ // Track that this function will eventually have a body; Sema needs
+ // to know this.
+ Actions.CheckForFunctionRedefinition(FD);
+ FD->setWillHaveBody(true);
} else {
// If semantic analysis could not build a function declaration,
// just throw away the late-parsed declaration.
@@ -344,9 +335,9 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// The argument isn't actually potentially evaluated unless it is
// used.
- EnterExpressionEvaluationContext Eval(Actions,
- Sema::PotentiallyEvaluatedIfUsed,
- Param);
+ EnterExpressionEvaluationContext Eval(
+ Actions,
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, Param);
ExprResult DefArgResult;
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
@@ -518,7 +509,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
// Parse the method body. Function body parsing code is similar enough
// to be re-used for method bodies as well.
- ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
+ ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D);
if (Tok.is(tok::kw_try)) {
@@ -558,10 +550,6 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
ParseFunctionStatementBody(LM.D, FnScope);
- // Clear the late-template-parsed bit if we set it before.
- if (LM.D)
- LM.D->getAsFunction()->setLateTemplateParsed(false);
-
while (Tok.isNot(tok::eof))
ConsumeAnyToken();
@@ -731,19 +719,6 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
ConsumeBrace();
break;
- case tok::code_completion:
- Toks.push_back(Tok);
- ConsumeCodeCompletionToken();
- break;
-
- case tok::string_literal:
- case tok::wide_string_literal:
- case tok::utf8_string_literal:
- case tok::utf16_string_literal:
- case tok::utf32_string_literal:
- Toks.push_back(Tok);
- ConsumeStringToken();
- break;
case tok::semi:
if (StopAtSemi)
return false;
@@ -751,7 +726,7 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
default:
// consume this token.
Toks.push_back(Tok);
- ConsumeToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok*/true);
break;
}
isFirstTokenConsumed = false;
@@ -902,7 +877,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
// If the opening brace is not preceded by one of these tokens, we are
// missing the mem-initializer-id. In order to recover better, we need
// to use heuristics to determine if this '{' is most likely the
- // begining of a brace-init-list or the function body.
+ // beginning of a brace-init-list or the function body.
// Check the token after the corresponding '}'.
TentativeParsingAction PA(*this);
if (SkipUntil(tok::r_brace) &&
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 226e2610ee..cc032c8cf3 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"
@@ -71,11 +71,18 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
}
+/// \brief Normalizes an attribute name by dropping prefixed and suffixed __.
+static StringRef normalizeAttrName(StringRef Name) {
+ if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
+ return Name.drop_front(2).drop_back(2);
+ return Name;
+}
+
/// isAttributeLateParsed - Return true if the attribute has arguments that
/// require late parsing.
static bool isAttributeLateParsed(const IdentifierInfo &II) {
#define CLANG_ATTR_LATE_PARSED_LIST
- return llvm::StringSwitch<bool>(II.getName())
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_LATE_PARSED_LIST
@@ -200,13 +207,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
}
-/// \brief Normalizes an attribute name by dropping prefixed and suffixed __.
-static StringRef normalizeAttrName(StringRef Name) {
- if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
- Name = Name.drop_front(2).drop_back(2);
- return Name;
-}
-
/// \brief Determine whether the given attribute has an identifier argument.
static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
#define CLANG_ATTR_IDENTIFIER_ARG_LIST
@@ -308,7 +308,9 @@ unsigned Parser::ParseAttributeArgsCommon(
do {
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
EnterExpressionEvaluationContext Unevaluated(
- Actions, Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated,
+ Actions,
+ Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
+ : Sema::ExpressionEvaluationContext::ConstantEvaluated,
/*LambdaContextDecl=*/nullptr,
/*IsDecltype=*/false);
@@ -910,13 +912,18 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
return;
}
IdentifierLoc *Platform = ParseIdentifierLoc();
- // Canonicalize platform name from "macosx" to "macos".
- if (Platform->Ident && Platform->Ident->getName() == "macosx")
- Platform->Ident = PP.getIdentifierInfo("macos");
- // Canonicalize platform name from "macosx_app_extension" to
- // "macos_app_extension".
- if (Platform->Ident && Platform->Ident->getName() == "macosx_app_extension")
- Platform->Ident = PP.getIdentifierInfo("macos_app_extension");
+ if (const IdentifierInfo *const Ident = Platform->Ident) {
+ // Canonicalize platform name from "macosx" to "macos".
+ if (Ident->getName() == "macosx")
+ Platform->Ident = PP.getIdentifierInfo("macos");
+ // Canonicalize platform name from "macosx_app_extension" to
+ // "macos_app_extension".
+ else if (Ident->getName() == "macosx_app_extension")
+ Platform->Ident = PP.getIdentifierInfo("macos_app_extension");
+ else
+ Platform->Ident = PP.getIdentifierInfo(
+ AvailabilityAttr::canonicalizePlatformName(Ident->getName()));
+ }
// Parse the ',' following the platform name.
if (ExpectAndConsume(tok::comma)) {
@@ -1386,7 +1393,9 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
// If the Decl is on a function, add function parameters to the scope.
bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate();
- ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunScope);
+ ParseScope FnScope(
+ this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope,
+ HasFunScope);
if (HasFunScope)
Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
@@ -1553,7 +1562,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
unsigned DiagID) {
for (AttributeList *Attr = Attrs.getList(); Attr; Attr = Attr->getNext()) {
- if (!Attr->isCXX11Attribute())
+ if (!Attr->isCXX11Attribute() && !Attr->isC2xAttribute())
continue;
if (Attr->getKind() == AttributeList::UnknownAttribute)
Diag(Attr->getLoc(), diag::warn_unknown_attribute_ignored)
@@ -2122,6 +2131,37 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
+ // RAII type used to track whether we're inside an initializer.
+ struct InitializerScopeRAII {
+ Parser &P;
+ Declarator &D;
+ Decl *ThisDecl;
+
+ InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
+ : P(P), D(D), ThisDecl(ThisDecl) {
+ if (ThisDecl && P.getLangOpts().CPlusPlus) {
+ Scope *S = nullptr;
+ if (D.getCXXScopeSpec().isSet()) {
+ P.EnterScope(0);
+ S = P.getCurScope();
+ }
+ P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl);
+ }
+ }
+ ~InitializerScopeRAII() { pop(); }
+ void pop() {
+ if (ThisDecl && P.getLangOpts().CPlusPlus) {
+ Scope *S = nullptr;
+ if (D.getCXXScopeSpec().isSet())
+ S = P.getCurScope();
+ P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl);
+ if (S)
+ P.ExitScope();
+ }
+ ThisDecl = nullptr;
+ }
+ };
+
// Inform the current actions module that we just parsed this declarator.
Decl *ThisDecl = nullptr;
switch (TemplateInfo.Kind) {
@@ -2199,10 +2239,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
else
Diag(ConsumeToken(), diag::err_default_special_members);
} else {
- if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
- EnterScope(0);
- Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
- }
+ InitializerScopeRAII InitScope(*this, D, ThisDecl);
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteInitializer(getCurScope(), ThisDecl);
@@ -2225,10 +2262,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
FRI->RangeExpr = Init;
}
- if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
- Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
- ExitScope();
- }
+ InitScope.pop();
if (Init.isInvalid()) {
SmallVector<tok::TokenKind, 2> StopTokens;
@@ -2250,23 +2284,27 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
ExprVector Exprs;
CommaLocsTy CommaLocs;
- if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
- EnterScope(0);
- Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
+ InitializerScopeRAII InitScope(*this, D, ThisDecl);
+
+ llvm::function_ref<void()> ExprListCompleter;
+ auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
+ auto ConstructorCompleter = [&, ThisVarDecl] {
+ Actions.CodeCompleteConstructor(
+ getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(),
+ ThisDecl->getLocation(), Exprs);
+ };
+ if (ThisVarDecl) {
+ // ParseExpressionList can sometimes succeed even when ThisDecl is not
+ // VarDecl. This is an error and it is reported in a call to
+ // Actions.ActOnInitializerError(). However, we call
+ // CodeCompleteConstructor only on VarDecls, falling back to default
+ // completer in other cases.
+ ExprListCompleter = ConstructorCompleter;
}
- if (ParseExpressionList(Exprs, CommaLocs, [&] {
- Actions.CodeCompleteConstructor(getCurScope(),
- cast<VarDecl>(ThisDecl)->getType()->getCanonicalTypeInternal(),
- ThisDecl->getLocation(), Exprs);
- })) {
+ if (ParseExpressionList(Exprs, CommaLocs, ExprListCompleter)) {
Actions.ActOnInitializerError(ThisDecl);
SkipUntil(tok::r_paren, StopAtSemi);
-
- if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
- Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
- ExitScope();
- }
} else {
// Match the ')'.
T.consumeClose();
@@ -2274,10 +2312,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
"Unexpected number of commas!");
- if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
- Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
- ExitScope();
- }
+ InitScope.pop();
ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
T.getCloseLocation(),
@@ -2290,17 +2325,11 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
// Parse C++0x braced-init-list.
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
- if (D.getCXXScopeSpec().isSet()) {
- EnterScope(0);
- Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
- }
+ InitializerScopeRAII InitScope(*this, D, ThisDecl);
ExprResult Init(ParseBraceInitializer());
- if (D.getCXXScopeSpec().isSet()) {
- Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
- ExitScope();
- }
+ InitScope.pop();
if (Init.isInvalid()) {
Actions.ActOnInitializerError(ThisDecl);
@@ -2550,6 +2579,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
}
// Fall through.
+ LLVM_FALLTHROUGH;
}
case tok::comma:
case tok::equal:
@@ -2575,9 +2605,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// and attempt to recover.
ParsedType T;
IdentifierInfo *II = Tok.getIdentifierInfo();
+ bool IsTemplateName = getLangOpts().CPlusPlus && NextToken().is(tok::less);
Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T,
- getLangOpts().CPlusPlus &&
- NextToken().is(tok::less));
+ IsTemplateName);
if (T) {
// The action has suggested that the type T could be used. Set that as
// the type in the declaration specifiers, consume the would-be type
@@ -2602,6 +2632,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
+ // Eat any following template arguments.
+ if (IsTemplateName) {
+ SourceLocation LAngle, RAngle;
+ TemplateArgList Args;
+ ParseTemplateIdAfterTemplateName(true, LAngle, Args, RAngle);
+ }
+
// TODO: Could inject an invalid typedef decl in an enclosing scope to
// avoid rippling error messages on subsequent uses of the same type,
// could be useful if #include was forgotten.
@@ -2619,6 +2656,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
return DSC_class;
if (Context == Declarator::FileContext)
return DSC_top_level;
+ if (Context == Declarator::TemplateParamContext)
+ return DSC_template_param;
if (Context == Declarator::TemplateTypeArgContext)
return DSC_template_type_arg;
if (Context == Declarator::TrailingReturnContext)
@@ -2886,7 +2925,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::l_square:
case tok::kw_alignas:
- if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier())
+ if (!standardAttributesAllowed() || !isCXX11AttributeSpecifier())
goto DoneWithDeclSpec;
ProhibitAttributes(attrs);
@@ -2980,7 +3019,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
DS.getTypeSpecScope() = SS;
- ConsumeToken(); // The C++ scope.
+ ConsumeAnnotationToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
AnnotateTemplateIdTokenAsType();
@@ -2989,7 +3028,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Next.is(tok::annot_typename)) {
DS.getTypeSpecScope() = SS;
- ConsumeToken(); // The C++ scope.
+ ConsumeAnnotationToken(); // The C++ scope.
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
@@ -3001,7 +3040,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
else
DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- ConsumeToken(); // The typename
+ ConsumeAnnotationToken(); // The typename
}
if (Next.isNot(tok::identifier))
@@ -3028,7 +3067,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
// typename.
if (!TypeRep) {
- ConsumeToken(); // Eat the scope spec so the identifier is current.
+ // Eat the scope spec so the identifier is current.
+ ConsumeAnnotationToken();
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
@@ -3041,7 +3081,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
DS.getTypeSpecScope() = SS;
- ConsumeToken(); // The C++ scope.
+ ConsumeAnnotationToken(); // The C++ scope.
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, TypeRep, Policy);
@@ -3071,7 +3111,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- ConsumeToken(); // The typename
+ ConsumeAnnotationToken(); // The typename
continue;
}
@@ -3490,6 +3530,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec,
DiagID, Policy);
break;
+ case tok::kw__Float16:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float16, Loc, PrevSpec,
+ DiagID, Policy);
+ break;
case tok::kw___float128:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec,
DiagID, Policy);
@@ -3668,6 +3712,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = true;
break;
};
+ LLVM_FALLTHROUGH;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -3733,7 +3778,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
/// semicolon.
///
/// struct-declaration:
-/// specifier-qualifier-list struct-declarator-list
+/// [C2x] attributes-specifier-seq[opt]
+/// specifier-qualifier-list struct-declarator-list
/// [GNU] __extension__ struct-declaration
/// [GNU] specifier-qualifier-list
/// struct-declarator-list:
@@ -3757,6 +3803,11 @@ void Parser::ParseStructDeclaration(
return ParseStructDeclaration(DS, FieldsCallback);
}
+ // Parse leading attributes.
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ MaybeParseCXX11Attributes(Attrs);
+ DS.takeAttributesFrom(Attrs);
+
// Parse the common specifier-qualifiers-list piece.
ParseSpecifierQualifierList(DS);
@@ -4093,8 +4144,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.
@@ -4249,7 +4300,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
AS, DS.getModulePrivateSpecLoc(), TParams,
Owned, IsDependent, ScopedEnumKWLoc,
IsScopedUsingClassTag, BaseType,
- DSC == DSC_type_specifier, &SkipBody);
+ DSC == DSC_type_specifier,
+ DSC == DSC_template_param ||
+ DSC == DSC_template_type_arg, &SkipBody);
if (SkipBody.ShouldSkip) {
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
@@ -4303,8 +4356,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
- if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference)
- ParseEnumBody(StartLoc, TagDecl);
+ if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
+ Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl;
+ ParseEnumBody(StartLoc, D);
+ if (SkipBody.CheckSameAsPrevious &&
+ !Actions.ActOnDuplicateDefinition(DS, TagDecl, SkipBody)) {
+ DS.SetTypeSpecError();
+ return;
+ }
+ }
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
@@ -4358,9 +4418,11 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
ProhibitAttributes(attrs); // GNU-style attributes are prohibited.
- if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
- if (!getLangOpts().CPlusPlus1z)
- Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute)
+ if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
+ if (getLangOpts().CPlusPlus)
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx14_compat_ns_enum_attribute
+ : diag::ext_ns_enum_attribute)
<< 1 /*enumerator*/;
ParseCXX11Attributes(attrs);
}
@@ -4376,11 +4438,9 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
}
// Install the enumerator constant into EnumDecl.
- Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl,
- LastEnumConstDecl,
- IdentLoc, Ident,
- attrs.getList(), EqualLoc,
- AssignedVal.get());
+ Decl *EnumConstDecl = Actions.ActOnEnumConstant(
+ getCurScope(), EnumDecl, LastEnumConstDecl, IdentLoc, Ident,
+ attrs.getList(), EqualLoc, AssignedVal.get());
EnumAvailabilityDiags.back().done();
EnumConstantDecls.push_back(EnumConstDecl);
@@ -4485,6 +4545,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_bool:
case tok::kw__Bool:
@@ -4560,6 +4621,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_bool:
case tok::kw__Bool:
@@ -4716,6 +4778,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_bool:
case tok::kw__Bool:
@@ -4827,10 +4890,12 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
}
// Parse the constructor name.
- if (Tok.isOneOf(tok::identifier, tok::annot_template_id)) {
+ if (Tok.is(tok::identifier)) {
// We already know that we have a constructor name; just consume
// the token.
ConsumeToken();
+ } else if (Tok.is(tok::annot_template_id)) {
+ ConsumeAnnotationToken();
} else {
TPA.Revert();
return false;
@@ -4886,7 +4951,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
// be a constructor declaration with an invalid argument type. Keep
// looking.
if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
+ ConsumeAnnotationToken();
ConsumeToken();
// If this is not a constructor, we must be parsing a declarator,
@@ -4967,7 +5032,7 @@ void Parser::ParseTypeQualifierListOpt(
DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
bool IdentifierRequired,
Optional<llvm::function_ref<void()>> CodeCompletionHandler) {
- if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) &&
+ if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
ParseCXX11Attributes(attrs);
@@ -5033,6 +5098,7 @@ void Parser::ParseTypeQualifierListOpt(
if (TryKeywordIdentFallback(false))
continue;
}
+ LLVM_FALLTHROUGH;
case tok::kw___sptr:
case tok::kw___w64:
case tok::kw___ptr64:
@@ -5082,6 +5148,7 @@ void Parser::ParseTypeQualifierListOpt(
continue; // do *not* consume the next token!
}
// otherwise, FALL THROUGH!
+ LLVM_FALLTHROUGH;
default:
DoneWithTypeQuals:
// If this is not a type-qualifier token, we're done reading type
@@ -5530,11 +5597,28 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetRangeEnd(Tok.getLocation());
ConsumeToken();
goto PastIdentifier;
- } else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) {
- // A virt-specifier isn't treated as an identifier if it appears after a
- // trailing-return-type.
- if (D.getContext() != Declarator::TrailingReturnContext ||
- !isCXX11VirtSpecifier(Tok)) {
+ } else if (Tok.is(tok::identifier) && !D.mayHaveIdentifier()) {
+ // We're not allowed an identifier here, but we got one. Try to figure out
+ // if the user was trying to attach a name to the type, or whether the name
+ // is some unrelated trailing syntax.
+ bool DiagnoseIdentifier = false;
+ if (D.hasGroupingParens())
+ // An identifier within parens is unlikely to be intended to be anything
+ // other than a name being "declared".
+ DiagnoseIdentifier = true;
+ else if (D.getContext() == Declarator::TemplateTypeArgContext)
+ // T<int N> is an accidental identifier; T<int N indicates a missing '>'.
+ DiagnoseIdentifier =
+ NextToken().isOneOf(tok::comma, tok::greater, tok::greatergreater);
+ else if (D.getContext() == Declarator::AliasDeclContext ||
+ D.getContext() == Declarator::AliasTemplateContext)
+ // The most likely error is that the ';' was forgotten.
+ DiagnoseIdentifier = NextToken().isOneOf(tok::comma, tok::semi);
+ else if (D.getContext() == Declarator::TrailingReturnContext &&
+ !isCXX11VirtSpecifier(Tok))
+ DiagnoseIdentifier = NextToken().isOneOf(
+ tok::comma, tok::semi, tok::equal, tok::l_brace, tok::kw_try);
+ if (DiagnoseIdentifier) {
Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id)
<< FixItHint::CreateRemoval(Tok.getLocation());
D.SetIdentifier(nullptr, Tok.getLocation());
@@ -5578,6 +5662,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()
@@ -5870,7 +5969,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
CachedTokens *ExceptionSpecTokens = nullptr;
- ParsedAttributes FnAttrs(AttrFactory);
+ ParsedAttributesWithRange FnAttrs(AttrFactory);
TypeResult TrailingReturnType;
/* LocalEndLoc is the end location for the local FunctionTypeLoc.
@@ -5891,6 +5990,11 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
RParenLoc = Tracker.getCloseLocation();
LocalEndLoc = RParenLoc;
EndLoc = RParenLoc;
+
+ // If there are attributes following the identifier list, parse them and
+ // prohibit them.
+ MaybeParseCXX11Attributes(FnAttrs);
+ ProhibitAttributes(FnAttrs);
} else {
if (Tok.isNot(tok::r_paren))
ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo,
@@ -5898,7 +6002,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
- HasProto = ParamInfo.size() || getLangOpts().CPlusPlus;
+ HasProto = ParamInfo.size() || getLangOpts().CPlusPlus
+ || getLangOpts().OpenCL;
// If we have the closing ')', eat it.
Tracker.consumeClose();
@@ -5996,6 +6101,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
TrailingReturnType = ParseTrailingReturnType(Range);
EndLoc = Range.getEnd();
}
+ } else if (standardAttributesAllowed()) {
+ MaybeParseCXX11Attributes(FnAttrs);
}
}
@@ -6270,9 +6377,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)) {
@@ -6422,8 +6530,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());
}
@@ -6558,8 +6666,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;
@@ -6591,7 +6700,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
return;
}
- // If we get here, the operand to the typeof was an expresion.
+ // If we get here, the operand to the typeof was an expression.
if (Operand.isInvalid()) {
DS.SetTypeSpecError();
return;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 618c8ab2ea..ca195901cf 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"
@@ -77,9 +77,10 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(unsigned Context,
ParsedAttributesWithRange attrs(AttrFactory);
SourceLocation attrLoc;
if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
- if (!getLangOpts().CPlusPlus1z)
- Diag(Tok.getLocation(), diag::warn_cxx14_compat_attribute)
- << 0 /*namespace*/;
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx14_compat_ns_enum_attribute
+ : diag::ext_ns_enum_attribute)
+ << 0 /*namespace*/;
attrLoc = Tok.getLocation();
ParseCXX11Attributes(attrs);
}
@@ -266,15 +267,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 +499,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 +517,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();
@@ -583,7 +606,7 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
if (TryConsumeToken(tok::ellipsis, D.EllipsisLoc))
Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ?
- diag::warn_cxx1z_compat_using_declaration_pack :
+ diag::warn_cxx17_compat_using_declaration_pack :
diag::ext_using_declaration_pack);
return false;
@@ -701,7 +724,7 @@ Parser::ParseUsingDeclaration(unsigned Context,
if (DeclsInGroup.size() > 1)
Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ?
- diag::warn_cxx1z_compat_multi_using_declaration :
+ diag::warn_cxx17_compat_multi_using_declaration :
diag::ext_multi_using_declaration);
// Eat ';'.
@@ -818,7 +841,9 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
return nullptr;
}
- ExprResult AssertExpr(ParseConstantExpression());
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ ExprResult AssertExpr(ParseConstantExpressionInExprEvalContext());
if (AssertExpr.isInvalid()) {
SkipMalformedDecl();
return nullptr;
@@ -879,7 +904,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
if (Tok.is(tok::annot_decltype)) {
Result = getExprAnnotation(Tok);
EndLoc = Tok.getAnnotationEndLoc();
- ConsumeToken();
+ ConsumeAnnotationToken();
if (Result.isInvalid()) {
DS.SetTypeSpecError();
return EndLoc;
@@ -913,8 +938,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;
@@ -1082,7 +1108,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
ParsedType Type = getTypeAnnotation(Tok);
EndLocation = Tok.getAnnotationEndLoc();
- ConsumeToken();
+ ConsumeAnnotationToken();
if (Type)
return Type;
@@ -1114,8 +1140,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (!Template) {
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- ParseTemplateIdAfterTemplateName(nullptr, IdLoc, SS, true, LAngleLoc,
- TemplateArgs, RAngleLoc);
+ ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs,
+ RAngleLoc);
return true;
}
@@ -1139,7 +1165,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// return.
EndLocation = Tok.getAnnotationEndLoc();
ParsedType Type = getTypeAnnotation(Tok);
- ConsumeToken();
+ ConsumeAnnotationToken();
return Type;
}
@@ -1383,6 +1409,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,
@@ -1506,8 +1533,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// a class (or template thereof).
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- if (ParseTemplateIdAfterTemplateName(
- nullptr, NameLoc, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) {
+ if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs,
+ RAngleLoc)) {
// We couldn't parse the template argument list at all, so don't
// try to give any location information for the list.
LAngleLoc = RAngleLoc = SourceLocation();
@@ -1541,7 +1568,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
} else if (Tok.is(tok::annot_template_id)) {
TemplateId = takeTemplateIdAnnotation(Tok);
- NameLoc = ConsumeToken();
+ NameLoc = ConsumeAnnotationToken();
if (TemplateId->Kind != TNK_Type_template &&
TemplateId->Kind != TNK_Dependent_template_name) {
@@ -1861,7 +1888,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation(), false,
clang::TypeResult(),
DSC == DSC_type_specifier,
- &SkipBody);
+ DSC == DSC_template_param ||
+ DSC == DSC_template_type_arg, &SkipBody);
// If ActOnTag said the type was dependent, try again with the
// less common call.
@@ -1883,12 +1911,22 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
else if (getLangOpts().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
TagOrTempResult.get());
- else
- ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
+ else {
+ Decl *D =
+ SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get();
+ // Parse the definition body.
+ ParseStructUnionBody(StartLoc, TagType, D);
+ if (SkipBody.CheckSameAsPrevious &&
+ !Actions.ActOnDuplicateDefinition(DS, TagOrTempResult.get(),
+ SkipBody)) {
+ DS.SetTypeSpecError();
+ return;
+ }
+ }
}
if (!TagOrTempResult.isInvalid())
- // Delayed proccessing of attributes.
+ // Delayed processing of attributes.
Actions.ProcessDeclAttributeDelayed(TagOrTempResult.get(), attrs.getList());
const char *PrevSpec = nullptr;
@@ -2683,10 +2721,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
InClassInitStyle HasInClassInit = ICIS_NoInit;
bool HasStaticInitializer = false;
if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) {
- if (BitfieldSize.get()) {
- Diag(Tok, diag::err_bitfield_member_init);
- SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
- } else if (DeclaratorInfo.isDeclarationOfFunction()) {
+ if (DeclaratorInfo.isDeclarationOfFunction()) {
// It's a pure-specifier.
if (!TryConsumePureSpecifier(/*AllowFunctionDefinition*/ false))
// Parse it as an expression so that Sema can diagnose it.
@@ -2697,6 +2732,10 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclSpec::SCS_typedef &&
!DS.isFriendSpecified()) {
// It's a default member initializer.
+ if (BitfieldSize.get())
+ Diag(Tok, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_bitfield_member_init
+ : diag::ext_bitfield_member_init);
HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit;
} else {
HasStaticInitializer = true;
@@ -2875,9 +2914,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
@@ -3157,6 +3195,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
if (Tok.is(tok::colon)) {
+ ParseScope InheritanceScope(this, getCurScope()->getFlags() |
+ Scope::ClassInheritanceScope);
+
ParseBaseClause(TagDecl);
if (!Tok.is(tok::l_brace)) {
bool SuggestFixIt = false;
@@ -3382,39 +3423,42 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
- ParsedType TemplateTypeTy;
- if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- if (TemplateId->Kind == TNK_Type_template ||
- TemplateId->Kind == TNK_Dependent_template_name) {
- AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
- assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
- TemplateTypeTy = getTypeAnnotation(Tok);
- }
- }
- // Uses of decltype will already have been converted to annot_decltype by
- // ParseOptionalCXXScopeSpecifier at this point.
- if (!TemplateTypeTy && Tok.isNot(tok::identifier)
- && Tok.isNot(tok::annot_decltype)) {
- Diag(Tok, diag::err_expected_member_or_base_name);
- return true;
- }
+ // : identifier
IdentifierInfo *II = nullptr;
- DeclSpec DS(AttrFactory);
SourceLocation IdLoc = Tok.getLocation();
- if (Tok.is(tok::annot_decltype)) {
+ // : declype(...)
+ DeclSpec DS(AttrFactory);
+ // : template_name<...>
+ ParsedType TemplateTypeTy;
+
+ if (Tok.is(tok::identifier)) {
+ // Get the identifier. This may be a member name or a class name,
+ // but we'll let the semantic analysis determine which it is.
+ II = Tok.getIdentifierInfo();
+ ConsumeToken();
+ } else if (Tok.is(tok::annot_decltype)) {
// Get the decltype expression, if there is one.
+ // Uses of decltype will already have been converted to annot_decltype by
+ // ParseOptionalCXXScopeSpecifier at this point.
+ // FIXME: Can we get here with a scope specifier?
ParseDecltypeSpecifier(DS);
} else {
- if (Tok.is(tok::identifier))
- // Get the identifier. This may be a member name or a class name,
- // but we'll let the semantic analysis determine which it is.
- II = Tok.getIdentifierInfo();
- ConsumeToken();
+ TemplateIdAnnotation *TemplateId = Tok.is(tok::annot_template_id)
+ ? takeTemplateIdAnnotation(Tok)
+ : nullptr;
+ if (TemplateId && (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name)) {
+ AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+ assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
+ TemplateTypeTy = getTypeAnnotation(Tok);
+ ConsumeAnnotationToken();
+ } else {
+ Diag(Tok, diag::err_expected_member_or_base_name);
+ return true;
+ }
}
-
// Parse the '('.
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
@@ -3773,7 +3817,7 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
}
static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
- IdentifierInfo *ScopeName) {
+ IdentifierInfo *ScopeName) {
switch (AttributeList::getKind(AttrName, ScopeName,
AttributeList::AS_CXX11)) {
case AttributeList::AT_CarriesDependency:
@@ -3812,11 +3856,14 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
SourceLocation ScopeLoc) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
SourceLocation LParenLoc = Tok.getLocation();
+ const LangOptions &LO = getLangOpts();
+ AttributeList::Syntax Syntax =
+ LO.CPlusPlus ? AttributeList::AS_CXX11 : AttributeList::AS_C2x;
// If the attribute isn't known, we will not attempt to parse any
// arguments.
- if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName,
- getTargetInfo(), getLangOpts())) {
+ if (!hasAttribute(LO.CPlusPlus ? AttrSyntax::CXX : AttrSyntax::C, ScopeName,
+ AttrName, getTargetInfo(), getLangOpts())) {
// Eat the left paren, then skip to the ending right paren.
ConsumeParen();
SkipUntil(tok::r_paren);
@@ -3827,7 +3874,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
// GNU-scoped attributes have some special cases to handle GNU-specific
// behaviors.
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
- ScopeLoc, AttributeList::AS_CXX11, nullptr);
+ ScopeLoc, Syntax, nullptr);
return true;
}
@@ -3836,11 +3883,11 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
if (ScopeName && ScopeName->getName() == "clang")
NumArgs =
ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
- ScopeLoc, AttributeList::AS_CXX11);
+ ScopeLoc, Syntax);
else
NumArgs =
ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
- ScopeName, ScopeLoc, AttributeList::AS_CXX11);
+ ScopeName, ScopeLoc, Syntax);
const AttributeList *Attr = Attrs.getList();
if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
@@ -3866,7 +3913,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
return true;
}
-/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier.
+/// ParseCXX11AttributeSpecifier - Parse a C++11 or C2x attribute-specifier.
///
/// [C++11] attribute-specifier:
/// '[' '[' attribute-list ']' ']'
@@ -3898,8 +3945,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
return;
}
- assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
- && "Not a C++11 attribute list");
+ assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) &&
+ "Not a double square bracket attribute list");
Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
@@ -3975,10 +4022,12 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
ScopeName, ScopeLoc);
if (!AttrParsed)
- attrs.addNew(AttrName,
- SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
- AttrLoc),
- ScopeName, ScopeLoc, nullptr, 0, AttributeList::AS_CXX11);
+ attrs.addNew(
+ AttrName,
+ SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc),
+ ScopeName, ScopeLoc, nullptr, 0,
+ getLangOpts().CPlusPlus ? AttributeList::AS_CXX11
+ : AttributeList::AS_C2x);
if (TryConsumeToken(tok::ellipsis))
Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
@@ -3993,13 +4042,13 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
SkipUntil(tok::r_square);
}
-/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq.
+/// ParseCXX11Attributes - Parse a C++11 or C2x attribute-specifier-seq.
///
/// attribute-specifier-seq:
/// attribute-specifier-seq[opt] attribute-specifier
void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc) {
- assert(getLangOpts().CPlusPlus11);
+ assert(standardAttributesAllowed());
SourceLocation StartLoc = Tok.getLocation(), Loc;
if (!endLoc)
@@ -4128,8 +4177,6 @@ void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) {
}
if (!T.consumeClose()) {
- // FIXME: Warn that this syntax is deprecated, with a Fix-It suggesting
- // using __declspec(uuid()) instead.
Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr,
SourceLocation(), ArgExprs.data(), ArgExprs.size(),
AttributeList::AS_Microsoft);
@@ -4191,6 +4238,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
<< Result.IsIfExists;
// Fall through to skip.
+ LLVM_FALLTHROUGH;
case IEB_Skip:
Braces.skipToEnd();
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 56c7685d93..0f2ec6b1c1 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"
@@ -192,18 +192,25 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
return ParseRHSOfBinaryExpression(R, prec::Assignment);
}
+ExprResult
+Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) {
+ assert(Actions.ExprEvalContexts.back().Context ==
+ Sema::ExpressionEvaluationContext::ConstantEvaluated &&
+ "Call this function only if your ExpressionEvaluationContext is "
+ "already ConstantEvaluated");
+ ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
+ ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+ return Actions.ActOnConstantExpression(Res);
+}
ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
// C++03 [basic.def.odr]p2:
// An expression is potentially evaluated unless it appears where an
// integral constant expression is required (see 5.19) [...].
// C++98 and C++11 have no such rule, but this is only a defect in C++98.
- EnterExpressionEvaluationContext ConstantEvaluated(Actions,
- Sema::ConstantEvaluated);
-
- ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
- ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
- return Actions.ActOnConstantExpression(Res);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ return ParseConstantExpressionInExprEvalContext(isTypeCast);
}
/// \brief Parse a constraint-expression.
@@ -235,11 +242,36 @@ bool Parser::isNotExpressionStart() {
return isKnownToBeDeclarationSpecifier();
}
-static bool isFoldOperator(prec::Level Level) {
+/// We've parsed something that could plausibly be intended to be a template
+/// name (\p LHS) followed by a '<' token, and the following code can't possibly
+/// be an expression. Determine if this is likely to be a template-id and if so,
+/// diagnose it.
+bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) {
+ TentativeParsingAction TPA(*this);
+ // FIXME: We could look at the token sequence in a lot more detail here.
+ if (SkipUntil(tok::greater, tok::greatergreater, tok::greatergreatergreater,
+ StopAtSemi | StopBeforeMatch)) {
+ TPA.Commit();
+
+ SourceLocation Greater;
+ ParseGreaterThanInTemplateList(Greater, true, false);
+ Actions.diagnoseExprIntendedAsTemplateName(getCurScope(), LHS,
+ Less, Greater);
+ return true;
+ }
+
+ // There's no matching '>' token, this probably isn't supposed to be
+ // interpreted as a template-id. Parse it as an (ill-formed) comparison.
+ TPA.Revert();
+ return false;
+}
+
+bool Parser::isFoldOperator(prec::Level Level) const {
return Level > prec::Unknown && Level != prec::Conditional;
}
-static bool isFoldOperator(tok::TokenKind Kind) {
- return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+
+bool Parser::isFoldOperator(tok::TokenKind Kind) const {
+ return isFoldOperator(getBinOpPrecedence(Kind, GreaterThanIsOperator, true));
}
/// \brief Parse a binary expression that starts with \p LHS and has a
@@ -276,6 +308,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
return LHS;
}
+ // If a '<' token is followed by a type that can be a template argument and
+ // cannot be an expression, then this is ill-formed, but might be intended
+ // to be a template-id.
+ if (OpToken.is(tok::less) && Actions.mightBeIntendedToBeTemplateName(LHS) &&
+ (isKnownToBeDeclarationSpecifier() ||
+ Tok.isOneOf(tok::greater, tok::greatergreater,
+ tok::greatergreatergreater)) &&
+ diagnoseUnknownTemplateId(LHS, OpToken.getLocation()))
+ return ExprError();
+
// If the next token is an ellipsis, then this is a fold-expression. Leave
// it alone so we can handle it in the paren expression.
if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) {
@@ -339,7 +381,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
ColonLoc = Tok.getLocation();
}
}
-
+
// Code completion for the right-hand side of an assignment expression
// goes through a special hook that takes the left-hand side into account.
if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) {
@@ -347,7 +389,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
cutOffParsing();
return ExprError();
}
-
+
// Parse another leaf here for the RHS of the operator.
// ParseCastExpression works here because all RHS expressions in C have it
// as a prefix, at least. However, in C++, an assignment-expression could
@@ -456,6 +498,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
if (!getLangOpts().CPlusPlus)
continue;
}
+
// Ensure potential typos aren't left undiagnosed.
if (LHS.isInvalid()) {
Actions.CorrectDelayedTyposInExpr(OrigLHS);
@@ -473,12 +516,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;
@@ -672,8 +717,10 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
/// '__is_sealed' [MS]
/// '__is_trivial'
/// '__is_union'
+/// '__has_unique_object_representations'
///
/// [Clang] unary-type-trait:
+/// '__is_aggregate'
/// '__trivially_copyable'
///
/// binary-type-trait:
@@ -694,7 +741,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 +770,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.
@@ -749,7 +800,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_true:
case tok::kw_false:
- return ParseCXXBoolLiteral();
+ Res = ParseCXXBoolLiteral();
+ break;
case tok::kw___objc_yes:
case tok::kw___objc_no:
@@ -762,7 +814,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::annot_primary_expr:
assert(Res.get() == nullptr && "Stray primary-expression annotation?");
Res = getExprAnnotation(Tok);
- ConsumeToken();
+ ConsumeAnnotationToken();
break;
case tok::kw___super:
@@ -798,6 +850,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
= RTT_JOIN(tok::kw_,Name)
REVERTIBLE_TYPE_TRAIT(__is_abstract);
+ REVERTIBLE_TYPE_TRAIT(__is_aggregate);
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
REVERTIBLE_TYPE_TRAIT(__is_array);
REVERTIBLE_TYPE_TRAIT(__is_assignable);
@@ -1156,7 +1209,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (Ty.isInvalid())
break;
- ConsumeToken();
+ ConsumeAnnotationToken();
Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
Ty.get(), nullptr);
break;
@@ -1179,6 +1232,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_void:
case tok::kw_typename:
@@ -1264,6 +1318,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
// Fall through to treat the template-id as an id-expression.
+ LLVM_FALLTHROUGH;
}
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
@@ -1307,7 +1362,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// C++11 [expr.unary.noexcept]p1:
// The noexcept operator determines whether the evaluation of its operand,
// which is an unevaluated operand, can throw an exception.
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult Result = ParseExpression();
T.consumeClose();
@@ -1433,9 +1489,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
nullptr, LHS.get());
break;
}
-
// Fall through; this isn't a message send.
-
+ LLVM_FALLTHROUGH;
+
default: // Not a postfix-expression suffix.
return LHS;
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
@@ -1814,7 +1870,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
}
}
- // If we get here, the operand to the typeof/sizeof/alignof was an expresion.
+ // If we get here, the operand to the typeof/sizeof/alignof was an expression.
isCastExpr = false;
return Operand;
}
@@ -1876,9 +1932,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(),
@@ -1889,8 +1946,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;
@@ -1918,7 +1976,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo();
- // If we get here, the operand to the sizeof/alignof was an expresion.
+ // If we get here, the operand to the sizeof/alignof was an expression.
if (!Operand.isInvalid())
Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
ExprKind,
@@ -2350,6 +2408,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 '{'.
@@ -2521,7 +2621,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()) {
@@ -2665,7 +2766,7 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS,
/// \endverbatim
bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
SmallVectorImpl<SourceLocation> &CommaLocs,
- std::function<void()> Completer) {
+ llvm::function_ref<void()> Completer) {
bool SawError = false;
while (1) {
if (Tok.is(tok::code_completion)) {
@@ -2784,7 +2885,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
// allows determining whether a variable reference inside the block is
// within or outside of the block.
ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
- Scope::DeclScope);
+ Scope::CompoundStmtScope | Scope::DeclScope);
// Inform sema that we are starting a block.
Actions.ActOnBlockStart(CaretLoc, getCurScope());
@@ -2934,6 +3035,11 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
return AvailabilitySpec(ConsumeToken());
} else {
// Parse the platform name.
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteAvailabilityPlatformName();
+ cutOffParsing();
+ return None;
+ }
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_avail_query_expected_platform_name);
return None;
@@ -2946,12 +3052,14 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
if (Version.empty())
return None;
- StringRef Platform = PlatformIdentifier->Ident->getName();
+ StringRef GivenPlatform = PlatformIdentifier->Ident->getName();
+ StringRef Platform =
+ AvailabilityAttr::canonicalizePlatformName(GivenPlatform);
if (AvailabilityAttr::getPrettyPlatformName(Platform).empty()) {
Diag(PlatformIdentifier->Loc,
diag::err_avail_query_unrecognized_platform_name)
- << Platform;
+ << GivenPlatform;
return None;
}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index cb56ebb104..a640439b8f 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++");
@@ -157,7 +160,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
Tok.getAnnotationRange(),
SS);
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
@@ -343,7 +346,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
*LastII = TemplateId->Name;
// Consume the template-id token.
- ConsumeToken();
+ ConsumeAnnotationToken();
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
@@ -450,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) {
@@ -863,8 +866,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// Each lambda init-capture forms its own full expression, which clears
// Actions.MaybeODRUseExprs. So create an expression evaluation context
// to save the necessary state, and restore it later.
- EnterExpressionEvaluationContext EC(Actions,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EC(
+ Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
if (TryConsumeToken(tok::equal))
InitKind = LambdaCaptureInitKind::CopyInit;
@@ -917,7 +920,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
PP.AnnotateCachedTokens(Tok);
// Consume the annotated initializer.
- ConsumeToken();
+ ConsumeAnnotationToken();
}
}
} else
@@ -963,6 +966,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// that would be an error.
ParsedType InitCaptureType;
+ if (!Init.isInvalid())
+ Init = Actions.CorrectDelayedTyposInExpr(Init.get());
if (Init.isUsable()) {
// Get the pointer and store it in an lvalue, so we can use it as an
// out argument.
@@ -1051,7 +1056,7 @@ addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc,
DeclSpec &DS) {
if (ConstexprLoc.isValid()) {
P.Diag(ConstexprLoc, !P.getLangOpts().CPlusPlus1z
- ? diag::ext_constexpr_on_lambda_cxx1z
+ ? diag::ext_constexpr_on_lambda_cxx17
: diag::warn_cxx14_compat_constexpr_on_lambda);
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
@@ -1278,7 +1283,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
// it.
- unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope;
+ unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope;
ParseScope BodyScope(this, ScopeFlags);
Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope());
@@ -1348,7 +1354,6 @@ ExprResult Parser::ParseCXXCasts() {
if (ExpectAndConsume(tok::greater))
return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << tok::less);
- SourceLocation LParenLoc, RParenLoc;
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after, CastName))
@@ -1402,8 +1407,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 +1472,8 @@ ExprResult Parser::ParseCXXUuidof() {
Ty.get().getAsOpaquePtr(),
T.getCloseLocation());
} else {
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
Result = ParseExpression();
// Match the ')'.
@@ -1523,7 +1530,7 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
// store it in the pseudo-dtor node (to be used when instantiating it).
FirstTypeName.setTemplateId(
(TemplateIdAnnotation *)Tok.getAnnotationValue());
- ConsumeToken();
+ ConsumeAnnotationToken();
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
CCLoc = ConsumeToken();
} else {
@@ -1877,7 +1884,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- ConsumeToken();
+ ConsumeAnnotationToken();
DS.Finish(Actions, Policy);
return;
@@ -1920,6 +1927,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
case tok::kw_double:
DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy);
break;
+ case tok::kw__Float16:
+ DS.SetTypeSpecType(DeclSpec::TST_float16, Loc, PrevSpec, DiagID, Policy);
+ break;
case tok::kw___float128:
DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy);
break;
@@ -1946,11 +1956,8 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.Finish(Actions, Policy);
return;
}
- if (Tok.is(tok::annot_typename))
- DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- else
- DS.SetRangeEnd(Tok.getLocation());
- ConsumeToken();
+ ConsumeAnyToken();
+ DS.SetRangeEnd(PrevTokLocation);
DS.Finish(Actions, Policy);
}
@@ -2109,11 +2116,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- if (Tok.is(tok::less) &&
- ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
- SS, true, LAngleLoc,
- TemplateArgs,
- RAngleLoc))
+ if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName(
+ true, LAngleLoc, TemplateArgs, RAngleLoc))
return true;
if (Id.getKind() == UnqualifiedId::IK_Identifier ||
@@ -2121,31 +2125,18 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) {
// Form a parsed representation of the template-id to be stored in the
// UnqualifiedId.
- TemplateIdAnnotation *TemplateId
- = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
// FIXME: Store name for literal operator too.
- if (Id.getKind() == UnqualifiedId::IK_Identifier) {
- TemplateId->Name = Id.Identifier;
- TemplateId->Operator = OO_None;
- TemplateId->TemplateNameLoc = Id.StartLocation;
- } else {
- TemplateId->Name = nullptr;
- TemplateId->Operator = Id.OperatorFunctionId.Operator;
- TemplateId->TemplateNameLoc = Id.StartLocation;
- }
+ IdentifierInfo *TemplateII =
+ Id.getKind() == UnqualifiedId::IK_Identifier ? Id.Identifier : nullptr;
+ OverloadedOperatorKind OpKind = Id.getKind() == UnqualifiedId::IK_Identifier
+ ? OO_None
+ : Id.OperatorFunctionId.Operator;
+
+ TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
+ SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
+ LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
- TemplateId->SS = SS;
- TemplateId->TemplateKWLoc = TemplateKWLoc;
- TemplateId->Template = Template;
- TemplateId->Kind = TNK;
- TemplateId->LAngleLoc = LAngleLoc;
- TemplateId->RAngleLoc = RAngleLoc;
- ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
- for (unsigned Arg = 0, ArgEnd = TemplateArgs.size();
- Arg != ArgEnd; ++Arg)
- Args[Arg] = TemplateArgs[Arg];
-
Id.setTemplateId(TemplateId);
return false;
}
@@ -2527,12 +2518,12 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
/*NontrivialTypeSourceInfo=*/true);
Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
Result.setConstructorTemplateId(TemplateId);
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
@@ -2540,7 +2531,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// our unqualified-id.
Result.setTemplateId(TemplateId);
TemplateKWLoc = TemplateId->TemplateKWLoc;
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index fa6b75daed..90f3561cb9 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"
@@ -501,7 +501,8 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
<< Result.IsIfExists;
// Fall through to skip.
-
+ LLVM_FALLTHROUGH;
+
case IEB_Skip:
Braces.skipToEnd();
return false;
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 81761bf8d2..edf1da171b 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)
@@ -1024,6 +1007,10 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
switch (Tok.getKind()) {
default:
return nullptr;
+ case tok::colon:
+ // Empty selector piece uses the location of the ':'.
+ SelectorLoc = Tok.getLocation();
+ return nullptr;
case tok::ampamp:
case tok::ampequal:
case tok::amp:
@@ -1448,12 +1435,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
cutOffParsing();
return nullptr;
}
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing argument name.
- break;
- }
+
+ if (expectIdentifier())
+ break; // missing argument name.
ArgInfo.Name = Tok.getIdentifierInfo();
ArgInfo.NameLoc = Tok.getLocation();
@@ -1562,8 +1546,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
return true;
}
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier()) {
SkipUntil(tok::greater, StopAtSemi);
return true;
}
@@ -2045,10 +2028,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
MaybeSkipAttributes(tok::objc_protocol);
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier; // missing protocol name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing protocol name.
// Save the protocol name, then consume it.
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
@@ -2068,8 +2049,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
// Parse the list of forward declarations.
while (1) {
ConsumeToken(); // the ','
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier()) {
SkipUntil(tok::semi);
return nullptr;
}
@@ -2136,11 +2116,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
MaybeSkipAttributes(tok::objc_implementation);
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing class or category name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing class or category name.
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
@@ -2210,11 +2187,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
IdentifierInfo *superClassId = nullptr;
if (TryConsumeToken(tok::colon)) {
// We have a super class
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing super class name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing super class name.
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken(); // Consume super class name
}
@@ -2285,7 +2259,7 @@ Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
assert(!Finished);
- P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl);
+ P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin());
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
true/*Methods*/);
@@ -2314,16 +2288,12 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
ConsumeToken(); // consume compatibility_alias
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier())
return nullptr;
- }
IdentifierInfo *aliasId = Tok.getIdentifierInfo();
SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier())
return nullptr;
- }
IdentifierInfo *classId = Tok.getIdentifierInfo();
SourceLocation classLoc = ConsumeToken(); // consume class-name;
ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
@@ -2371,11 +2341,9 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
cutOffParsing();
return nullptr;
}
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+
+ if (expectIdentifier())
break;
- }
propertyIvar = Tok.getIdentifierInfo();
propertyIvarLoc = ConsumeToken(); // consume ivar-name
}
@@ -2433,9 +2401,8 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
cutOffParsing();
return nullptr;
}
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+
+ if (expectIdentifier()) {
SkipUntil(tok::semi);
return nullptr;
}
@@ -2511,7 +2478,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
// Parse the compound statement within a new scope.
- ParseScope bodyScope(this, Scope::DeclScope);
+ ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult body(ParseCompoundStatementBody());
bodyScope.Exit();
@@ -2547,7 +2514,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
}
StmtVector CatchStmts;
StmtResult FinallyStmt;
- ParseScope TryScope(this, Scope::DeclScope);
+ ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult TryBody(ParseCompoundStatementBody());
TryScope.Exit();
if (TryBody.isInvalid())
@@ -2568,7 +2535,9 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
ConsumeToken(); // consume catch
if (Tok.is(tok::l_paren)) {
ConsumeParen();
- ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
+ ParseScope CatchScope(this, Scope::DeclScope |
+ Scope::CompoundStmtScope |
+ Scope::AtCatchScope);
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS(AttrFactory);
ParseDeclarationSpecifiers(DS);
@@ -2612,7 +2581,8 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
} else {
assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
ConsumeToken(); // consume finally
- ParseScope FinallyScope(this, Scope::DeclScope);
+ ParseScope FinallyScope(this,
+ Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult FinallyBody(true);
if (Tok.is(tok::l_brace))
@@ -2649,7 +2619,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
}
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
- ParseScope BodyScope(this, Scope::DeclScope);
+ ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
@@ -3571,8 +3541,8 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- if (Tok.isNot(tok::identifier))
- return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
+ if (expectIdentifier())
+ return ExprError();
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
SourceLocation ProtoIdLoc = ConsumeToken();
@@ -3664,6 +3634,14 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
SourceLocation OrigLoc = Tok.getLocation();
assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
+ // Store an artificial EOF token to ensure that we don't run off the end of
+ // the method's body when we come to parse it.
+ Token Eof;
+ Eof.startToken();
+ Eof.setKind(tok::eof);
+ Eof.setEofData(MCDecl);
+ Eof.setLocation(OrigLoc);
+ LM.Toks.push_back(Eof);
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
LM.Toks.push_back(Tok);
@@ -3675,11 +3653,10 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
"Inline objective-c method not starting with '{' or 'try' or ':'");
// Enter a scope for the method or c-function body.
- ParseScope BodyScope(this,
- parseMethod
- ? Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope
- : Scope::FnScope|Scope::DeclScope);
-
+ ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
+ Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
+
// Tell the actions module that we have entered a method or c-function definition
// with the specified Declarator for the method/function.
if (parseMethod)
@@ -3695,7 +3672,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
Actions.ActOnDefaultCtorInitializers(MCDecl);
ParseFunctionStatementBody(MCDecl, BodyScope);
}
-
+
if (Tok.getLocation() != OrigLoc) {
// Due to parsing error, we either went over the cached tokens or
// there are still cached tokens left. If it's the latter case skip the
@@ -3707,4 +3684,6 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
}
+ // Clean up the remaining EOF token.
+ ConsumeAnyToken();
}
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 574ed6ee59..e1685f6a9d 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"
@@ -192,6 +192,7 @@ static DeclarationName parseOpenMPReductionId(Parser &P) {
case tok::identifier: // identifier
if (!WithOperator)
break;
+ LLVM_FALLTHROUGH;
default:
P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);
P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -301,6 +302,7 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
for (auto *D : DRD.get()) {
TentativeParsingAction TPA(*this);
ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope |
Scope::OpenMPDirectiveScope);
// Parse <combiner> expression.
Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);
@@ -336,14 +338,24 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
IsCorrect;
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope |
Scope::OpenMPDirectiveScope);
// Parse expression.
- Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), D);
- InitializerResult = Actions.ActOnFinishFullExpr(
- ParseAssignmentExpression().get(), D->getLocation(),
- /*DiscardedValue=*/true);
+ VarDecl *OmpPrivParm =
+ Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(),
+ D);
+ // Check if initializer is omp_priv <init_expr> or something else.
+ if (Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->isStr("omp_priv")) {
+ ConsumeToken();
+ ParseOpenMPReductionInitializerForDecl(OmpPrivParm);
+ } else {
+ InitializerResult = Actions.ActOnFinishFullExpr(
+ ParseAssignmentExpression().get(), D->getLocation(),
+ /*DiscardedValue=*/true);
+ }
Actions.ActOnOpenMPDeclareReductionInitializerEnd(
- D, InitializerResult.get());
+ D, InitializerResult.get(), OmpPrivParm);
if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) &&
Tok.isNot(tok::annot_pragma_openmp_end)) {
TPA.Commit();
@@ -367,6 +379,72 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
IsCorrect);
}
+void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
+ // Parse declarator '=' initializer.
+ // If a '==' or '+=' is found, suggest a fixit to '='.
+ if (isTokenEqualOrEqualTypo()) {
+ ConsumeToken();
+
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteInitializer(getCurScope(), OmpPrivParm);
+ Actions.FinalizeDeclaration(OmpPrivParm);
+ cutOffParsing();
+ return;
+ }
+
+ ExprResult Init(ParseInitializer());
+
+ if (Init.isInvalid()) {
+ SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
+ Actions.ActOnInitializerError(OmpPrivParm);
+ } else {
+ Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),
+ /*DirectInit=*/false);
+ }
+ } else if (Tok.is(tok::l_paren)) {
+ // Parse C++ direct initializer: '(' expression-list ')'
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
+ ExprVector Exprs;
+ CommaLocsTy CommaLocs;
+
+ if (ParseExpressionList(Exprs, CommaLocs, [this, OmpPrivParm, &Exprs] {
+ Actions.CodeCompleteConstructor(
+ getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(),
+ OmpPrivParm->getLocation(), Exprs);
+ })) {
+ Actions.ActOnInitializerError(OmpPrivParm);
+ SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
+ } else {
+ // Match the ')'.
+ T.consumeClose();
+
+ assert(!Exprs.empty() && Exprs.size() - 1 == CommaLocs.size() &&
+ "Unexpected number of commas!");
+
+ ExprResult Initializer = Actions.ActOnParenListExpr(
+ T.getOpenLocation(), T.getCloseLocation(), Exprs);
+ Actions.AddInitializerToDecl(OmpPrivParm, Initializer.get(),
+ /*DirectInit=*/true);
+ }
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
+ // Parse C++0x braced-init-list.
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+
+ ExprResult Init(ParseBraceInitializer());
+
+ if (Init.isInvalid()) {
+ Actions.ActOnInitializerError(OmpPrivParm);
+ } else {
+ Actions.AddInitializerToDecl(OmpPrivParm, Init.get(),
+ /*DirectInit=*/true);
+ }
+ } else {
+ Actions.ActOnUninitializedDecl(OmpPrivParm);
+ }
+}
+
namespace {
/// RAII that recreates function context for correct parsing of clauses of
/// 'declare simd' construct.
@@ -404,8 +482,9 @@ public:
// If the Decl is on a function, add function parameters to the scope.
HasFunScope = D->isFunctionOrFunctionTemplate();
- FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope,
- HasFunScope);
+ FnScope = new Parser::ParseScope(
+ &P, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope,
+ HasFunScope);
if (HasFunScope)
Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D);
}
@@ -532,7 +611,7 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
ConsumeAnyToken();
}
// Skip the last annot_pragma_openmp_end.
- SourceLocation EndLoc = ConsumeToken();
+ SourceLocation EndLoc = ConsumeAnnotationToken();
if (!IsError) {
return Actions.ActOnOpenMPDeclareSimdDirective(
Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears,
@@ -562,7 +641,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
- SourceLocation Loc = ConsumeToken();
+ SourceLocation Loc = ConsumeAnnotationToken();
auto DKind = ParseOpenMPDirectiveKind(*this);
switch (DKind) {
@@ -578,7 +657,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
// Skip the last annot_pragma_openmp_end.
- ConsumeToken();
+ ConsumeAnnotationToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
Helper.getIdentifiers());
}
@@ -596,7 +675,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ConsumeAnyToken();
}
// Skip the last annot_pragma_openmp_end.
- ConsumeToken();
+ ConsumeAnnotationToken();
return Res;
}
break;
@@ -681,12 +760,20 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
DKind = ParseOpenMPDirectiveKind(*this);
while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target &&
Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- ParseExternalDeclaration(attrs);
+ DeclGroupPtrTy Ptr;
+ // Here we expect to see some function declaration.
+ if (AS == AS_none) {
+ assert(TagType == DeclSpec::TST_unspecified);
+ MaybeParseCXX11Attributes(Attrs);
+ ParsingDeclSpec PDS(*this);
+ Ptr = ParseExternalDeclaration(Attrs, &PDS);
+ } else {
+ Ptr =
+ ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);
+ }
if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
TentativeParsingAction TPA(*this);
- ConsumeToken();
+ ConsumeAnnotationToken();
DKind = ParseOpenMPDirectiveKind(*this);
if (DKind != OMPD_end_declare_target)
TPA.Revert();
@@ -806,15 +893,15 @@ 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;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
FirstClauses(OMPC_unknown + 1);
- unsigned ScopeFlags =
- Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
- SourceLocation Loc = ConsumeToken(), EndLoc;
+ unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
+ SourceLocation Loc = ConsumeAnnotationToken(), EndLoc;
auto DKind = ParseOpenMPDirectiveKind(*this);
OpenMPDirectiveKind CancelRegion = OMPD_unknown;
// Name of critical directive.
@@ -869,6 +956,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
// pseudo-clause OMPFlushClause.
PP.EnterToken(Tok);
}
+ LLVM_FALLTHROUGH;
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
@@ -883,6 +971,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
}
HasAssociatedStatement = false;
// Fall through for further analysis.
+ LLVM_FALLTHROUGH;
case OMPD_parallel:
case OMPD_simd:
case OMPD_for:
@@ -973,7 +1062,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
// End location of the directive.
EndLoc = Tok.getLocation();
// Consume final annot_pragma_openmp_end.
- ConsumeToken();
+ ConsumeAnnotationToken();
// OpenMP [2.13.8, ordered Construct, Syntax]
// If the depend clause is specified, the ordered construct is a stand-alone
@@ -1099,7 +1188,8 @@ bool Parser::ParseOpenMPSimpleVarList(
/// simdlen-clause | threads-clause | simd-clause | num_teams-clause |
/// thread_limit-clause | priority-clause | grainsize-clause |
/// nogroup-clause | num_tasks-clause | hint-clause | to-clause |
-/// from-clause | is_device_ptr-clause
+/// from-clause | is_device_ptr-clause | task_reduction-clause |
+/// in_reduction-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -1184,6 +1274,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
}
+ LLVM_FALLTHROUGH;
case OMPC_if:
Clause = ParseOpenMPSingleExprWithArgClause(CKind);
@@ -1216,6 +1307,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -1581,7 +1674,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
BalancedDelimiterTracker LinearT(*this, tok::l_paren,
tok::annot_pragma_openmp_end);
// Handle reduction-identifier for reduction clause.
- if (Kind == OMPC_reduction) {
+ if (Kind == OMPC_reduction || Kind == OMPC_task_reduction ||
+ Kind == OMPC_in_reduction) {
ColonProtectionRAIIObject ColonRAII(*this);
if (getLangOpts().CPlusPlus)
ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec,
@@ -1690,6 +1784,30 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.MapType = OMPC_MAP_tofrom;
Data.IsMapTypeImplicit = true;
}
+ } else if (IsMapClauseModifierToken(PP.LookAhead(0))) {
+ if (PP.LookAhead(1).is(tok::colon)) {
+ Data.MapTypeModifier = Data.MapType;
+ if (Data.MapTypeModifier != OMPC_MAP_always) {
+ Diag(Tok, diag::err_omp_unknown_map_type_modifier);
+ Data.MapTypeModifier = OMPC_MAP_unknown;
+ } else
+ MapTypeModifierSpecified = true;
+
+ ConsumeToken();
+
+ Data.MapType =
+ IsMapClauseModifierToken(Tok)
+ ? static_cast<OpenMPMapClauseKind>(
+ getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)))
+ : OMPC_MAP_unknown;
+ if (Data.MapType == OMPC_MAP_unknown ||
+ Data.MapType == OMPC_MAP_always)
+ Diag(Tok, diag::err_omp_unknown_map_type);
+ ConsumeToken();
+ } else {
+ Data.MapType = OMPC_MAP_tofrom;
+ Data.IsMapTypeImplicit = true;
+ }
} else {
Data.MapType = OMPC_MAP_tofrom;
Data.IsMapTypeImplicit = true;
@@ -1706,7 +1824,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
}
bool IsComma =
- (Kind != OMPC_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
+ (Kind != OMPC_reduction && Kind != OMPC_task_reduction &&
+ Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
(Kind == OMPC_reduction && !InvalidReductionId) ||
(Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown &&
(!MapTypeModifierSpecified ||
@@ -1767,7 +1886,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
}
/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
-/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
+/// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction' or
+/// 'in_reduction'.
///
/// private-clause:
/// 'private' '(' list ')'
@@ -1783,6 +1903,10 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
/// 'aligned' '(' list [ ':' alignment ] ')'
/// reduction-clause:
/// 'reduction' '(' reduction-identifier ':' list ')'
+/// task_reduction-clause:
+/// 'task_reduction' '(' reduction-identifier ':' list ')'
+/// in_reduction-clause:
+/// 'in_reduction' '(' reduction-identifier ':' list ')'
/// copyprivate-clause:
/// 'copyprivate' '(' list ')'
/// flush-clause:
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 89733237c1..198d5c6e9c 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"
@@ -49,6 +49,15 @@ struct PragmaPackHandler : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaClangSectionHandler : public PragmaHandler {
+ explicit PragmaClangSectionHandler(Sema &S)
+ : PragmaHandler("section"), Actions(S) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+private:
+ Sema &Actions;
+};
+
struct PragmaMSStructHandler : public PragmaHandler {
explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
@@ -86,6 +95,12 @@ struct PragmaFPContractHandler : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaFPHandler : public PragmaHandler {
+ PragmaFPHandler() : PragmaHandler("fp") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
struct PragmaNoOpenMPHandler : public PragmaHandler {
PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
@@ -177,6 +192,17 @@ private:
Sema &Actions;
};
+/// PragmaAttributeHandler - "\#pragma clang attribute ...".
+struct PragmaAttributeHandler : public PragmaHandler {
+ PragmaAttributeHandler(AttributeFactory &AttrFactory)
+ : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+
+ /// A pool of attributes that were parsed in \#pragma clang attribute.
+ ParsedAttributes AttributesForPragmaAttribute;
+};
+
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -207,6 +233,9 @@ void Parser::initializePragmaHandlers() {
FPContractHandler.reset(new PragmaFPContractHandler());
PP.AddPragmaHandler("STDC", FPContractHandler.get());
+ PCSectionHandler.reset(new PragmaClangSectionHandler(Actions));
+ PP.AddPragmaHandler("clang", PCSectionHandler.get());
+
if (getLangOpts().OpenCL) {
OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler());
PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
@@ -266,6 +295,12 @@ void Parser::initializePragmaHandlers() {
NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
PP.AddPragmaHandler(NoUnrollHintHandler.get());
+
+ FPHandler.reset(new PragmaFPHandler());
+ PP.AddPragmaHandler("clang", FPHandler.get());
+
+ AttributePragmaHandler.reset(new PragmaAttributeHandler(AttrFactory));
+ PP.AddPragmaHandler("clang", AttributePragmaHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -300,6 +335,9 @@ void Parser::resetPragmaHandlers() {
MSCommentHandler.reset();
}
+ PP.RemovePragmaHandler("clang", PCSectionHandler.get());
+ PCSectionHandler.reset();
+
if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset();
@@ -344,6 +382,12 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler(NoUnrollHintHandler.get());
NoUnrollHintHandler.reset();
+
+ PP.RemovePragmaHandler("clang", FPHandler.get());
+ FPHandler.reset();
+
+ PP.RemovePragmaHandler("clang", AttributePragmaHandler.get());
+ AttributePragmaHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -353,7 +397,7 @@ void Parser::resetPragmaHandlers() {
/// annot_pragma_unused 'x' annot_pragma_unused 'y'
void Parser::HandlePragmaUnused() {
assert(Tok.is(tok::annot_pragma_unused));
- SourceLocation UnusedLoc = ConsumeToken();
+ SourceLocation UnusedLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc);
ConsumeToken(); // The argument token.
}
@@ -362,7 +406,7 @@ void Parser::HandlePragmaVisibility() {
assert(Tok.is(tok::annot_pragma_vis));
const IdentifierInfo *VisType =
static_cast<IdentifierInfo *>(Tok.getAnnotationValue());
- SourceLocation VisLoc = ConsumeToken();
+ SourceLocation VisLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaVisibility(VisType, VisLoc);
}
@@ -378,15 +422,20 @@ void Parser::HandlePragmaPack() {
assert(Tok.is(tok::annot_pragma_pack));
PragmaPackInfo *Info =
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = Tok.getLocation();
ExprResult Alignment;
if (Info->Alignment.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Info->Alignment);
- if (Alignment.isInvalid())
+ if (Alignment.isInvalid()) {
+ ConsumeAnnotationToken();
return;
+ }
}
Actions.ActOnPragmaPack(PragmaLoc, Info->Action, Info->SlotLabel,
Alignment.get());
+ // Consume the token after processing the pragma to enable pragma-specific
+ // #include warnings.
+ ConsumeAnnotationToken();
}
void Parser::HandlePragmaMSStruct() {
@@ -394,7 +443,7 @@ void Parser::HandlePragmaMSStruct() {
PragmaMSStructKind Kind = static_cast<PragmaMSStructKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
Actions.ActOnPragmaMSStruct(Kind);
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
}
void Parser::HandlePragmaAlign() {
@@ -402,7 +451,7 @@ void Parser::HandlePragmaAlign() {
Sema::PragmaOptionsAlignKind Kind =
static_cast<Sema::PragmaOptionsAlignKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc);
}
@@ -411,12 +460,12 @@ void Parser::HandlePragmaDump() {
IdentifierInfo *II =
reinterpret_cast<IdentifierInfo *>(Tok.getAnnotationValue());
Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II);
- ConsumeToken();
+ ConsumeAnnotationToken();
}
void Parser::HandlePragmaWeak() {
assert(Tok.is(tok::annot_pragma_weak));
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc,
Tok.getLocation());
ConsumeToken(); // The weak name.
@@ -424,7 +473,7 @@ void Parser::HandlePragmaWeak() {
void Parser::HandlePragmaWeakAlias() {
assert(Tok.is(tok::annot_pragma_weakalias));
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
IdentifierInfo *WeakName = Tok.getIdentifierInfo();
SourceLocation WeakNameLoc = Tok.getLocation();
ConsumeToken();
@@ -438,7 +487,7 @@ void Parser::HandlePragmaWeakAlias() {
void Parser::HandlePragmaRedefineExtname() {
assert(Tok.is(tok::annot_pragma_redefine_extname));
- SourceLocation RedefLoc = ConsumeToken();
+ SourceLocation RedefLoc = ConsumeAnnotationToken();
IdentifierInfo *RedefName = Tok.getIdentifierInfo();
SourceLocation RedefNameLoc = Tok.getLocation();
ConsumeToken();
@@ -454,14 +503,28 @@ void Parser::HandlePragmaFPContract() {
tok::OnOffSwitch OOS =
static_cast<tok::OnOffSwitch>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- Actions.ActOnPragmaFPContract(OOS);
- ConsumeToken(); // The annotation token.
+
+ LangOptions::FPContractModeKind FPC;
+ switch (OOS) {
+ case tok::OOS_ON:
+ FPC = LangOptions::FPC_On;
+ break;
+ case tok::OOS_OFF:
+ FPC = LangOptions::FPC_Off;
+ break;
+ case tok::OOS_DEFAULT:
+ FPC = getLangOpts().getDefaultFPContractMode();
+ break;
+ }
+
+ Actions.ActOnPragmaFPContract(FPC);
+ ConsumeAnnotationToken();
}
StmtResult Parser::HandlePragmaCaptured()
{
assert(Tok.is(tok::annot_pragma_captured));
- ConsumeToken();
+ ConsumeAnnotationToken();
if (Tok.isNot(tok::l_brace)) {
PP.Diag(Tok, diag::err_expected) << tok::l_brace;
@@ -470,7 +533,8 @@ StmtResult Parser::HandlePragmaCaptured()
SourceLocation Loc = Tok.getLocation();
- ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope);
+ ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default,
/*NumParams=*/1);
@@ -498,7 +562,7 @@ void Parser::HandlePragmaOpenCLExtension() {
auto State = Data->second;
auto Ident = Data->first;
SourceLocation NameLoc = Tok.getLocation();
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
auto &Opt = Actions.getOpenCLOptions();
auto Name = Ident->getName();
@@ -537,7 +601,7 @@ void Parser::HandlePragmaMSPointersToMembers() {
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod =
static_cast<LangOptions::PragmaMSPointersToMembersKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaMSPointersToMembers(RepresentationMethod, PragmaLoc);
}
@@ -547,7 +611,7 @@ void Parser::HandlePragmaMSVtorDisp() {
Sema::PragmaMsStackAction Action =
static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF);
- SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode);
}
@@ -557,7 +621,7 @@ void Parser::HandlePragmaMSPragma() {
auto TheTokens =
(std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue();
PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true);
- SourceLocation PragmaLocation = ConsumeToken(); // The annotation token.
+ SourceLocation PragmaLocation = ConsumeAnnotationToken();
assert(Tok.isAnyIdentifier());
StringRef PragmaName = Tok.getIdentifierInfo()->getName();
PP.Lex(Tok); // pragma kind
@@ -853,7 +917,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll)) {
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
Hint.Range = Info->PragmaName.getLocation();
return true;
}
@@ -880,7 +944,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
bool AssumeSafetyArg = !OptionUnroll && !OptionDistribute;
// Verify loop hint has an argument.
if (Toks[0].is(tok::eof)) {
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
<< /*StateArgument=*/StateOption << /*FullKeyword=*/OptionUnroll
<< /*AssumeSafetyKeyword=*/AssumeSafetyArg;
@@ -889,7 +953,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
// Validate the argument.
if (StateOption) {
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
SourceLocation StateLoc = Toks[0].getLocation();
IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
@@ -912,7 +976,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
} else {
// Enter constant expression including eof terminator into token stream.
PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false);
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
ExprResult R = ParseConstantExpression();
@@ -940,6 +1004,422 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
return true;
}
+namespace {
+struct PragmaAttributeInfo {
+ enum ActionType { Push, Pop };
+ ParsedAttributes &Attributes;
+ ActionType Action;
+ ArrayRef<Token> Tokens;
+
+ PragmaAttributeInfo(ParsedAttributes &Attributes) : Attributes(Attributes) {}
+};
+
+#include "clang/Parse/AttrSubMatchRulesParserStringSwitches.inc"
+
+} // end anonymous namespace
+
+static StringRef getIdentifier(const Token &Tok) {
+ if (Tok.is(tok::identifier))
+ return Tok.getIdentifierInfo()->getName();
+ const char *S = tok::getKeywordSpelling(Tok.getKind());
+ if (!S)
+ return "";
+ return S;
+}
+
+static bool isAbstractAttrMatcherRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) \
+ case Value: \
+ return IsAbstract;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+ llvm_unreachable("Invalid attribute subject match rule");
+ return false;
+}
+
+static void diagnoseExpectedAttributeSubjectSubRule(
+ Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
+ SourceLocation SubRuleLoc) {
+ auto Diagnostic =
+ PRef.Diag(SubRuleLoc,
+ diag::err_pragma_attribute_expected_subject_sub_identifier)
+ << PrimaryRuleName;
+ if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
+ Diagnostic << /*SubRulesSupported=*/1 << SubRules;
+ else
+ Diagnostic << /*SubRulesSupported=*/0;
+}
+
+static void diagnoseUnknownAttributeSubjectSubRule(
+ Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
+ StringRef SubRuleName, SourceLocation SubRuleLoc) {
+
+ auto Diagnostic =
+ PRef.Diag(SubRuleLoc, diag::err_pragma_attribute_unknown_subject_sub_rule)
+ << SubRuleName << PrimaryRuleName;
+ if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
+ Diagnostic << /*SubRulesSupported=*/1 << SubRules;
+ else
+ Diagnostic << /*SubRulesSupported=*/0;
+}
+
+bool Parser::ParsePragmaAttributeSubjectMatchRuleSet(
+ attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc,
+ SourceLocation &LastMatchRuleEndLoc) {
+ bool IsAny = false;
+ BalancedDelimiterTracker AnyParens(*this, tok::l_paren);
+ if (getIdentifier(Tok) == "any") {
+ AnyLoc = ConsumeToken();
+ IsAny = true;
+ if (AnyParens.expectAndConsume())
+ return true;
+ }
+
+ do {
+ // Parse the subject matcher rule.
+ StringRef Name = getIdentifier(Tok);
+ if (Name.empty()) {
+ Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier);
+ return true;
+ }
+ std::pair<Optional<attr::SubjectMatchRule>,
+ Optional<attr::SubjectMatchRule> (*)(StringRef, bool)>
+ Rule = isAttributeSubjectMatchRule(Name);
+ if (!Rule.first) {
+ Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name;
+ return true;
+ }
+ attr::SubjectMatchRule PrimaryRule = *Rule.first;
+ SourceLocation RuleLoc = ConsumeToken();
+
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ if (isAbstractAttrMatcherRule(PrimaryRule)) {
+ if (Parens.expectAndConsume())
+ return true;
+ } else if (Parens.consumeOpen()) {
+ if (!SubjectMatchRules
+ .insert(
+ std::make_pair(PrimaryRule, SourceRange(RuleLoc, RuleLoc)))
+ .second)
+ Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
+ << Name
+ << FixItHint::CreateRemoval(SourceRange(
+ RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleLoc));
+ LastMatchRuleEndLoc = RuleLoc;
+ continue;
+ }
+
+ // Parse the sub-rules.
+ StringRef SubRuleName = getIdentifier(Tok);
+ if (SubRuleName.empty()) {
+ diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ Tok.getLocation());
+ return true;
+ }
+ attr::SubjectMatchRule SubRule;
+ if (SubRuleName == "unless") {
+ SourceLocation SubRuleLoc = ConsumeToken();
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ if (Parens.expectAndConsume())
+ return true;
+ SubRuleName = getIdentifier(Tok);
+ if (SubRuleName.empty()) {
+ diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleLoc);
+ return true;
+ }
+ auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true);
+ if (!SubRuleOrNone) {
+ std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")";
+ diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleUnlessName, SubRuleLoc);
+ return true;
+ }
+ SubRule = *SubRuleOrNone;
+ ConsumeToken();
+ if (Parens.consumeClose())
+ return true;
+ } else {
+ auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false);
+ if (!SubRuleOrNone) {
+ diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleName, Tok.getLocation());
+ return true;
+ }
+ SubRule = *SubRuleOrNone;
+ ConsumeToken();
+ }
+ SourceLocation RuleEndLoc = Tok.getLocation();
+ LastMatchRuleEndLoc = RuleEndLoc;
+ if (Parens.consumeClose())
+ return true;
+ if (!SubjectMatchRules
+ .insert(std::make_pair(SubRule, SourceRange(RuleLoc, RuleEndLoc)))
+ .second) {
+ Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
+ << attr::getSubjectMatchRuleSpelling(SubRule)
+ << FixItHint::CreateRemoval(SourceRange(
+ RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleEndLoc));
+ continue;
+ }
+ } while (IsAny && TryConsumeToken(tok::comma));
+
+ if (IsAny)
+ if (AnyParens.consumeClose())
+ return true;
+
+ return false;
+}
+
+namespace {
+
+/// Describes the stage at which attribute subject rule parsing was interruped.
+enum class MissingAttributeSubjectRulesRecoveryPoint {
+ Comma,
+ ApplyTo,
+ Equals,
+ Any,
+ None,
+};
+
+MissingAttributeSubjectRulesRecoveryPoint
+getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
+ if (const auto *II = Tok.getIdentifierInfo()) {
+ if (II->isStr("apply_to"))
+ return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo;
+ if (II->isStr("any"))
+ return MissingAttributeSubjectRulesRecoveryPoint::Any;
+ }
+ if (Tok.is(tok::equal))
+ return MissingAttributeSubjectRulesRecoveryPoint::Equals;
+ return MissingAttributeSubjectRulesRecoveryPoint::None;
+}
+
+/// Creates a diagnostic for the attribute subject rule parsing diagnostic that
+/// suggests the possible attribute subject rules in a fix-it together with
+/// any other missing tokens.
+DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic(
+ unsigned DiagID, AttributeList &Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) {
+ SourceLocation Loc = PRef.getEndOfPreviousToken();
+ if (Loc.isInvalid())
+ Loc = PRef.getCurToken().getLocation();
+ auto Diagnostic = PRef.Diag(Loc, DiagID);
+ std::string FixIt;
+ MissingAttributeSubjectRulesRecoveryPoint EndPoint =
+ getAttributeSubjectRulesRecoveryPointForToken(PRef.getCurToken());
+ if (Point == MissingAttributeSubjectRulesRecoveryPoint::Comma)
+ FixIt = ", ";
+ if (Point <= MissingAttributeSubjectRulesRecoveryPoint::ApplyTo &&
+ EndPoint > MissingAttributeSubjectRulesRecoveryPoint::ApplyTo)
+ FixIt += "apply_to";
+ if (Point <= MissingAttributeSubjectRulesRecoveryPoint::Equals &&
+ EndPoint > MissingAttributeSubjectRulesRecoveryPoint::Equals)
+ FixIt += " = ";
+ SourceRange FixItRange(Loc);
+ if (EndPoint == MissingAttributeSubjectRulesRecoveryPoint::None) {
+ // Gather the subject match rules that are supported by the attribute.
+ SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> SubjectMatchRuleSet;
+ Attribute.getMatchRules(PRef.getLangOpts(), SubjectMatchRuleSet);
+ if (SubjectMatchRuleSet.empty()) {
+ // FIXME: We can emit a "fix-it" with a subject list placeholder when
+ // placeholders will be supported by the fix-its.
+ return Diagnostic;
+ }
+ FixIt += "any(";
+ bool NeedsComma = false;
+ for (const auto &I : SubjectMatchRuleSet) {
+ // Ensure that the missing rule is reported in the fix-it only when it's
+ // supported in the current language mode.
+ if (!I.second)
+ continue;
+ if (NeedsComma)
+ FixIt += ", ";
+ else
+ NeedsComma = true;
+ FixIt += attr::getSubjectMatchRuleSpelling(I.first);
+ }
+ FixIt += ")";
+ // Check if we need to remove the range
+ PRef.SkipUntil(tok::eof, Parser::StopBeforeMatch);
+ FixItRange.setEnd(PRef.getCurToken().getLocation());
+ }
+ if (FixItRange.getBegin() == FixItRange.getEnd())
+ Diagnostic << FixItHint::CreateInsertion(FixItRange.getBegin(), FixIt);
+ else
+ Diagnostic << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(FixItRange), FixIt);
+ return Diagnostic;
+}
+
+} // end anonymous namespace
+
+void Parser::HandlePragmaAttribute() {
+ assert(Tok.is(tok::annot_pragma_attribute) &&
+ "Expected #pragma attribute annotation token");
+ SourceLocation PragmaLoc = Tok.getLocation();
+ auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue());
+ if (Info->Action == PragmaAttributeInfo::Pop) {
+ ConsumeAnnotationToken();
+ Actions.ActOnPragmaAttributePop(PragmaLoc);
+ return;
+ }
+ // Parse the actual attribute with its arguments.
+ assert(Info->Action == PragmaAttributeInfo::Push &&
+ "Unexpected #pragma attribute command");
+ PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false);
+ ConsumeAnnotationToken();
+
+ ParsedAttributes &Attrs = Info->Attributes;
+ Attrs.clearListOnly();
+
+ auto SkipToEnd = [this]() {
+ SkipUntil(tok::eof, StopBeforeMatch);
+ ConsumeToken();
+ };
+
+ if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
+ // Parse the CXX11 style attribute.
+ ParseCXX11AttributeSpecifier(Attrs);
+ } else if (Tok.is(tok::kw___attribute)) {
+ ConsumeToken();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "attribute"))
+ return SkipToEnd();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "("))
+ return SkipToEnd();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_pragma_attribute_expected_attribute_name);
+ SkipToEnd();
+ return;
+ }
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ AttributeList::AS_GNU);
+ else
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr,
+ /*ScopeName=*/nullptr,
+ /*ScopeLoc=*/SourceLocation(),
+ AttributeList::AS_GNU,
+ /*Declarator=*/nullptr);
+
+ if (ExpectAndConsume(tok::r_paren))
+ return SkipToEnd();
+ if (ExpectAndConsume(tok::r_paren))
+ return SkipToEnd();
+ } else if (Tok.is(tok::kw___declspec)) {
+ ParseMicrosoftDeclSpecs(Attrs);
+ } else {
+ Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax);
+ if (Tok.getIdentifierInfo()) {
+ // If we suspect that this is an attribute suggest the use of
+ // '__attribute__'.
+ if (AttributeList::getKind(Tok.getIdentifierInfo(), /*ScopeName=*/nullptr,
+ AttributeList::AS_GNU) !=
+ AttributeList::UnknownAttribute) {
+ SourceLocation InsertStartLoc = Tok.getLocation();
+ ConsumeToken();
+ if (Tok.is(tok::l_paren)) {
+ ConsumeAnyToken();
+ SkipUntil(tok::r_paren, StopBeforeMatch);
+ if (Tok.isNot(tok::r_paren))
+ return SkipToEnd();
+ }
+ Diag(Tok, diag::note_pragma_attribute_use_attribute_kw)
+ << FixItHint::CreateInsertion(InsertStartLoc, "__attribute__((")
+ << FixItHint::CreateInsertion(Tok.getEndLoc(), "))");
+ }
+ }
+ SkipToEnd();
+ return;
+ }
+
+ if (!Attrs.getList() || Attrs.getList()->isInvalid()) {
+ SkipToEnd();
+ return;
+ }
+
+ // Ensure that we don't have more than one attribute.
+ if (Attrs.getList()->getNext()) {
+ SourceLocation Loc = Attrs.getList()->getNext()->getLoc();
+ Diag(Loc, diag::err_pragma_attribute_multiple_attributes);
+ SkipToEnd();
+ return;
+ }
+
+ if (!Attrs.getList()->isSupportedByPragmaAttribute()) {
+ Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute)
+ << Attrs.getList()->getName();
+ SkipToEnd();
+ return;
+ }
+ AttributeList &Attribute = *Attrs.getList();
+
+ // Parse the subject-list.
+ if (!TryConsumeToken(tok::comma)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_expected, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::Comma, *this)
+ << tok::comma;
+ SkipToEnd();
+ return;
+ }
+
+ if (Tok.isNot(tok::identifier)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
+ SkipToEnd();
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (!II->isStr("apply_to")) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
+ SkipToEnd();
+ return;
+ }
+ ConsumeToken();
+
+ if (!TryConsumeToken(tok::equal)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_expected, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::Equals, *this)
+ << tok::equal;
+ SkipToEnd();
+ return;
+ }
+
+ attr::ParsedSubjectMatchRuleSet SubjectMatchRules;
+ SourceLocation AnyLoc, LastMatchRuleEndLoc;
+ if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc,
+ LastMatchRuleEndLoc)) {
+ SkipToEnd();
+ return;
+ }
+
+ // Tokens following an ill-formed attribute will remain in the token stream
+ // and must be removed.
+ if (Tok.isNot(tok::eof)) {
+ Diag(Tok, diag::err_pragma_attribute_extra_tokens_after_attribute);
+ SkipToEnd();
+ return;
+ }
+
+ // Consume the eof terminator token.
+ ConsumeToken();
+
+ Actions.ActOnPragmaAttributePush(Attribute, PragmaLoc,
+ std::move(SubjectMatchRules));
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -1155,6 +1635,51 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true);
}
+// #pragma clang section bss="abc" data="" rodata="def" text=""
+void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer, Token &FirstToken) {
+
+ Token Tok;
+ auto SecKind = Sema::PragmaClangSectionKind::PCSK_Invalid;
+
+ PP.Lex(Tok); // eat 'section'
+ while (Tok.isNot(tok::eod)) {
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section";
+ return;
+ }
+
+ const IdentifierInfo *SecType = Tok.getIdentifierInfo();
+ if (SecType->isStr("bss"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_BSS;
+ else if (SecType->isStr("data"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_Data;
+ else if (SecType->isStr("rodata"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata;
+ else if (SecType->isStr("text"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_Text;
+ else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section";
+ return;
+ }
+
+ PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text']
+ if (Tok.isNot(tok::equal)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << SecKind;
+ return;
+ }
+
+ std::string SecName;
+ if (!PP.LexStringLiteral(Tok, SecName, "pragma clang section", false))
+ return;
+
+ Actions.ActOnPragmaClangSection(Tok.getLocation(),
+ (SecName.size()? Sema::PragmaClangSectionAction::PCSA_Set :
+ Sema::PragmaClangSectionAction::PCSA_Clear),
+ SecKind, SecName);
+ }
+}
+
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
@@ -1947,6 +2472,129 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
}
+namespace {
+/// Used as the annotation value for tok::annot_pragma_fp.
+struct TokFPAnnotValue {
+ enum FlagKinds { Contract };
+ enum FlagValues { On, Off, Fast };
+
+ FlagKinds FlagKind;
+ FlagValues FlagValue;
+};
+} // end anonymous namespace
+
+void PragmaFPHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ // fp
+ Token PragmaName = Tok;
+ SmallVector<Token, 1> TokenList;
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+ << /*MissingOption=*/true << "";
+ return;
+ }
+
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
+
+ auto FlagKind =
+ llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>(
+ OptionInfo->getName())
+ .Case("contract", TokFPAnnotValue::Contract)
+ .Default(None);
+ if (!FlagKind) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+ << /*MissingOption=*/false << OptionInfo;
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Read '('
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName();
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ auto FlagValue =
+ llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>(
+ II->getName())
+ .Case("on", TokFPAnnotValue::On)
+ .Case("off", TokFPAnnotValue::Off)
+ .Case("fast", TokFPAnnotValue::Fast)
+ .Default(llvm::None);
+
+ if (!FlagValue) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName();
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Read ')'
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ auto *AnnotValue = new (PP.getPreprocessorAllocator())
+ TokFPAnnotValue{*FlagKind, *FlagValue};
+ // Generate the loop hint token.
+ Token FPTok;
+ FPTok.startToken();
+ FPTok.setKind(tok::annot_pragma_fp);
+ FPTok.setLocation(PragmaName.getLocation());
+ FPTok.setAnnotationEndLoc(PragmaName.getLocation());
+ FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
+ TokenList.push_back(FPTok);
+ }
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang fp";
+ return;
+ }
+
+ auto TokenArray = llvm::make_unique<Token[]>(TokenList.size());
+ std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
+
+ PP.EnterTokenStream(std::move(TokenArray), TokenList.size(),
+ /*DisableMacroExpansion=*/false);
+}
+
+void Parser::HandlePragmaFP() {
+ assert(Tok.is(tok::annot_pragma_fp));
+ auto *AnnotValue =
+ reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
+
+ LangOptions::FPContractModeKind FPC;
+ switch (AnnotValue->FlagValue) {
+ case TokFPAnnotValue::On:
+ FPC = LangOptions::FPC_On;
+ break;
+ case TokFPAnnotValue::Fast:
+ FPC = LangOptions::FPC_Fast;
+ break;
+ case TokFPAnnotValue::Off:
+ FPC = LangOptions::FPC_Off;
+ break;
+ }
+
+ Actions.ActOnPragmaFPContract(FPC);
+ ConsumeAnnotationToken();
+}
+
/// \brief Parses loop or unroll pragma hint value and fills in Info.
static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
Token Option, bool ValueInParens,
@@ -2246,3 +2894,104 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma(
PP.Diag(FirstTok.getLocation(),
diag::warn_pragma_force_cuda_host_device_bad_arg);
}
+
+/// \brief Handle the #pragma clang attribute directive.
+///
+/// The syntax is:
+/// \code
+/// #pragma clang attribute push(attribute, subject-set)
+/// #pragma clang attribute pop
+/// \endcode
+///
+/// The subject-set clause defines the set of declarations which receive the
+/// attribute. Its exact syntax is described in the LanguageExtensions document
+/// in Clang's documentation.
+///
+/// This directive instructs the compiler to begin/finish applying the specified
+/// attribute to the set of attribute-specific declarations in the active range
+/// of the pragma.
+void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstToken) {
+ Token Tok;
+ PP.Lex(Tok);
+ auto *Info = new (PP.getPreprocessorAllocator())
+ PragmaAttributeInfo(AttributesForPragmaAttribute);
+
+ // Parse the 'push' or 'pop'.
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_push_pop);
+ return;
+ }
+ const auto *II = Tok.getIdentifierInfo();
+ if (II->isStr("push"))
+ Info->Action = PragmaAttributeInfo::Push;
+ else if (II->isStr("pop"))
+ Info->Action = PragmaAttributeInfo::Pop;
+ else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument)
+ << PP.getSpelling(Tok);
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Parse the actual attribute.
+ if (Info->Action == PragmaAttributeInfo::Push) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Lex the attribute tokens.
+ SmallVector<Token, 16> AttributeTokens;
+ int OpenParens = 1;
+ while (Tok.isNot(tok::eod)) {
+ if (Tok.is(tok::l_paren))
+ OpenParens++;
+ else if (Tok.is(tok::r_paren)) {
+ OpenParens--;
+ if (OpenParens == 0)
+ break;
+ }
+
+ AttributeTokens.push_back(Tok);
+ PP.Lex(Tok);
+ }
+
+ if (AttributeTokens.empty()) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_attribute);
+ return;
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return;
+ }
+ SourceLocation EndLoc = Tok.getLocation();
+ PP.Lex(Tok);
+
+ // Terminate the attribute for parsing.
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(EndLoc);
+ AttributeTokens.push_back(EOFTok);
+
+ Info->Tokens =
+ llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator());
+ }
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang attribute";
+
+ // Generate the annotated pragma token.
+ auto TokenArray = llvm::make_unique<Token[]>(1);
+ TokenArray[0].startToken();
+ TokenArray[0].setKind(tok::annot_pragma_attribute);
+ TokenArray[0].setLocation(FirstToken.getLocation());
+ TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation());
+ TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
+ PP.EnterTokenStream(std::move(TokenArray), 1,
+ /*DisableMacroExpansion=*/false);
+}
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index db6ed6f984..e8cf7d5fa4 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;
@@ -203,6 +203,7 @@ Retry:
}
// Fall through
+ LLVM_FALLTHROUGH;
}
default: {
@@ -338,7 +339,13 @@ Retry:
case tok::annot_pragma_fp_contract:
ProhibitAttributes(Attrs);
Diag(Tok, diag::err_pragma_fp_contract_scope);
- ConsumeToken();
+ ConsumeAnnotationToken();
+ return StmtError();
+
+ case tok::annot_pragma_fp:
+ ProhibitAttributes(Attrs);
+ Diag(Tok, diag::err_pragma_fp_scope);
+ ConsumeAnnotationToken();
return StmtError();
case tok::annot_pragma_opencl_extension:
@@ -376,6 +383,10 @@ Retry:
case tok::annot_pragma_dump:
HandlePragmaDump();
return StmtEmpty();
+
+ case tok::annot_pragma_attribute:
+ HandlePragmaAttribute();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -442,9 +453,10 @@ StmtResult Parser::ParseSEHTryBlock() {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- Scope::DeclScope | Scope::SEHTryScope));
- if(TryBlock.isInvalid())
+ StmtResult TryBlock(ParseCompoundStatement(
+ /*isStmtExpr=*/false,
+ Scope::DeclScope | Scope::CompoundStmtScope | Scope::SEHTryScope));
+ if (TryBlock.isInvalid())
return TryBlock;
StmtResult Handler;
@@ -829,7 +841,8 @@ StmtResult Parser::ParseDefaultStatement() {
}
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
- return ParseCompoundStatement(isStmtExpr, Scope::DeclScope);
+ return ParseCompoundStatement(isStmtExpr,
+ Scope::DeclScope | Scope::CompoundStmtScope);
}
/// ParseCompoundStatement - Parse a "{}" block.
@@ -900,6 +913,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 +1195,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 +1229,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();
@@ -1461,6 +1479,9 @@ StmtResult Parser::ParseDoStatement() {
DiagnoseAndSkipCXX11Attributes();
ExprResult Cond = ParseExpression();
+ // Correct the typos in condition before closing the scope.
+ if (Cond.isUsable())
+ Cond = Actions.CorrectDelayedTyposInExpr(Cond);
T.consumeClose();
DoScope.Exit();
@@ -1903,7 +1924,7 @@ StmtResult Parser::ParseReturnStatement() {
}
StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
// Create temporary attribute list.
@@ -2069,9 +2090,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- Scope::DeclScope | Scope::TryScope |
- (FnTry ? Scope::FnTryCatchScope : 0)));
+ StmtResult TryBlock(ParseCompoundStatement(
+ /*isStmtExpr=*/false, Scope::DeclScope | Scope::TryScope |
+ Scope::CompoundStmtScope |
+ (FnTry ? Scope::FnTryCatchScope : 0)));
if (TryBlock.isInvalid())
return TryBlock;
diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index 85cd22fef4..d81029e279 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"
@@ -54,54 +54,13 @@ public:
assert(AsmToks.size() == AsmTokOffsets.size());
}
- void *LookupInlineAsmIdentifier(StringRef &LineBuf,
- llvm::InlineAsmIdentifierInfo &Info,
- bool IsUnevaluatedContext) override {
- // Collect the desired tokens.
- SmallVector<Token, 16> LineToks;
- const Token *FirstOrigToken = nullptr;
- findTokensForString(LineBuf, LineToks, FirstOrigToken);
-
- unsigned NumConsumedToks;
- ExprResult Result = TheParser.ParseMSAsmIdentifier(
- LineToks, NumConsumedToks, &Info, IsUnevaluatedContext);
-
- // If we consumed the entire line, tell MC that.
- // Also do this if we consumed nothing as a way of reporting failure.
- if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
- // By not modifying LineBuf, we're implicitly consuming it all.
-
- // Otherwise, consume up to the original tokens.
- } else {
- assert(FirstOrigToken && "not using original tokens?");
-
- // Since we're using original tokens, apply that offset.
- assert(FirstOrigToken[NumConsumedToks].getLocation() ==
- LineToks[NumConsumedToks].getLocation());
- unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
- unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
-
- // The total length we've consumed is the relative offset
- // of the last token we consumed plus its length.
- unsigned TotalOffset =
- (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
- AsmTokOffsets[FirstIndex]);
- LineBuf = LineBuf.substr(0, TotalOffset);
- }
-
- // Initialize the "decl" with the lookup result.
- Info.OpDecl = static_cast<void *>(Result.get());
- return Info.OpDecl;
- }
+ void LookupInlineAsmIdentifier(StringRef &LineBuf,
+ llvm::InlineAsmIdentifierInfo &Info,
+ bool IsUnevaluatedContext) override;
StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
llvm::SMLoc Location,
- bool Create) override {
- SourceLocation Loc = translateLocation(LSM, Location);
- LabelDecl *Label =
- TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
- return Label->getMSAsmLabel();
- }
+ bool Create) override;
bool LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset) override {
@@ -116,78 +75,133 @@ public:
private:
/// Collect the appropriate tokens for the given string.
void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
- const Token *&FirstOrigToken) const {
- // For now, assert that the string we're working with is a substring
- // of what we gave to MC. This lets us use the original tokens.
- assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
- !std::less<const char *>()(AsmString.end(), Str.end()));
-
- // Try to find a token whose offset matches the first token.
- unsigned FirstCharOffset = Str.begin() - AsmString.begin();
- const unsigned *FirstTokOffset = std::lower_bound(
- AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
-
- // For now, assert that the start of the string exactly
- // corresponds to the start of a token.
- assert(*FirstTokOffset == FirstCharOffset);
-
- // Use all the original tokens for this line. (We assume the
- // end of the line corresponds cleanly to a token break.)
- unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
- FirstOrigToken = &AsmToks[FirstTokIndex];
- unsigned LastCharOffset = Str.end() - AsmString.begin();
- for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
- if (AsmTokOffsets[i] >= LastCharOffset)
- break;
- TempToks.push_back(AsmToks[i]);
- }
+ const Token *&FirstOrigToken) const;
+
+ SourceLocation translateLocation(const llvm::SourceMgr &LSM,
+ llvm::SMLoc SMLoc);
+
+ void handleDiagnostic(const llvm::SMDiagnostic &D);
+};
+}
+
+void ClangAsmParserCallback::LookupInlineAsmIdentifier(
+ StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info,
+ bool IsUnevaluatedContext) {
+ // Collect the desired tokens.
+ SmallVector<Token, 16> LineToks;
+ const Token *FirstOrigToken = nullptr;
+ findTokensForString(LineBuf, LineToks, FirstOrigToken);
+
+ unsigned NumConsumedToks;
+ ExprResult Result = TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks,
+ IsUnevaluatedContext);
+
+ // If we consumed the entire line, tell MC that.
+ // Also do this if we consumed nothing as a way of reporting failure.
+ if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
+ // By not modifying LineBuf, we're implicitly consuming it all.
+
+ // Otherwise, consume up to the original tokens.
+ } else {
+ assert(FirstOrigToken && "not using original tokens?");
+
+ // Since we're using original tokens, apply that offset.
+ assert(FirstOrigToken[NumConsumedToks].getLocation() ==
+ LineToks[NumConsumedToks].getLocation());
+ unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
+ unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
+
+ // The total length we've consumed is the relative offset
+ // of the last token we consumed plus its length.
+ unsigned TotalOffset =
+ (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
+ AsmTokOffsets[FirstIndex]);
+ LineBuf = LineBuf.substr(0, TotalOffset);
}
- SourceLocation translateLocation(const llvm::SourceMgr &LSM, llvm::SMLoc SMLoc) {
- // Compute an offset into the inline asm buffer.
- // FIXME: This isn't right if .macro is involved (but hopefully, no
- // real-world code does that).
- const llvm::MemoryBuffer *LBuf =
- LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
- unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
-
- // Figure out which token that offset points into.
- const unsigned *TokOffsetPtr =
- std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
- unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
- unsigned TokOffset = *TokOffsetPtr;
-
- // If we come up with an answer which seems sane, use it; otherwise,
- // just point at the __asm keyword.
- // FIXME: Assert the answer is sane once we handle .macro correctly.
- SourceLocation Loc = AsmLoc;
- if (TokIndex < AsmToks.size()) {
- const Token &Tok = AsmToks[TokIndex];
- Loc = Tok.getLocation();
- Loc = Loc.getLocWithOffset(Offset - TokOffset);
- }
- return Loc;
+ // Initialize Info with the lookup result.
+ if (!Result.isUsable())
+ return;
+ TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info);
+}
+
+StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef Identifier,
+ llvm::SourceMgr &LSM,
+ llvm::SMLoc Location,
+ bool Create) {
+ SourceLocation Loc = translateLocation(LSM, Location);
+ LabelDecl *Label =
+ TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
+ return Label->getMSAsmLabel();
+}
+
+void ClangAsmParserCallback::findTokensForString(
+ StringRef Str, SmallVectorImpl<Token> &TempToks,
+ const Token *&FirstOrigToken) const {
+ // For now, assert that the string we're working with is a substring
+ // of what we gave to MC. This lets us use the original tokens.
+ assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
+ !std::less<const char *>()(AsmString.end(), Str.end()));
+
+ // Try to find a token whose offset matches the first token.
+ unsigned FirstCharOffset = Str.begin() - AsmString.begin();
+ const unsigned *FirstTokOffset = std::lower_bound(
+ AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
+
+ // For now, assert that the start of the string exactly
+ // corresponds to the start of a token.
+ assert(*FirstTokOffset == FirstCharOffset);
+
+ // Use all the original tokens for this line. (We assume the
+ // end of the line corresponds cleanly to a token break.)
+ unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
+ FirstOrigToken = &AsmToks[FirstTokIndex];
+ unsigned LastCharOffset = Str.end() - AsmString.begin();
+ for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
+ if (AsmTokOffsets[i] >= LastCharOffset)
+ break;
+ TempToks.push_back(AsmToks[i]);
}
+}
- void handleDiagnostic(const llvm::SMDiagnostic &D) {
- const llvm::SourceMgr &LSM = *D.getSourceMgr();
- SourceLocation Loc = translateLocation(LSM, D.getLoc());
- TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
+SourceLocation
+ClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM,
+ llvm::SMLoc SMLoc) {
+ // Compute an offset into the inline asm buffer.
+ // FIXME: This isn't right if .macro is involved (but hopefully, no
+ // real-world code does that).
+ const llvm::MemoryBuffer *LBuf =
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
+ unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
+
+ // Figure out which token that offset points into.
+ const unsigned *TokOffsetPtr =
+ std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
+ unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
+ unsigned TokOffset = *TokOffsetPtr;
+
+ // If we come up with an answer which seems sane, use it; otherwise,
+ // just point at the __asm keyword.
+ // FIXME: Assert the answer is sane once we handle .macro correctly.
+ SourceLocation Loc = AsmLoc;
+ if (TokIndex < AsmToks.size()) {
+ const Token &Tok = AsmToks[TokIndex];
+ Loc = Tok.getLocation();
+ Loc = Loc.getLocWithOffset(Offset - TokOffset);
}
-};
+ return Loc;
+}
+
+void ClangAsmParserCallback::handleDiagnostic(const llvm::SMDiagnostic &D) {
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+ SourceLocation Loc = translateLocation(LSM, D.getLoc());
+ TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
}
/// Parse an identifier in an MS-style inline assembly block.
-///
-/// \param CastInfo - a void* so that we don't have to teach Parser.h
-/// about the actual type.
ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
unsigned &NumLineToksConsumed,
- void *CastInfo,
bool IsUnevaluatedContext) {
- llvm::InlineAsmIdentifierInfo &Info =
- *(llvm::InlineAsmIdentifierInfo *)CastInfo;
-
// Push a fake token on the end so that we don't overrun the token
// stream. We use ';' because it expression-parsing should never
// overrun it.
@@ -227,7 +241,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
/*AllowDeductionGuide=*/false,
/*ObjectType=*/nullptr, TemplateKWLoc, Id);
// Perform the lookup.
- Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
+ Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
IsUnevaluatedContext);
}
// While the next two tokens are 'period' 'identifier', repeatedly parse it as
@@ -241,7 +255,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
IdentifierInfo *Id = Tok.getIdentifierInfo();
ConsumeToken(); // Consume the identifier.
Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(),
- Info, Tok.getLocation());
+ Tok.getLocation());
}
// Figure out how many tokens we are into LineToks.
@@ -452,7 +466,7 @@ 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;
@@ -564,7 +578,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
return StmtError();
- TargetOptions TO = Actions.Context.getTargetInfo().getTargetOpts();
+ const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts();
std::string FeaturesStr =
llvm::join(TO.Features.begin(), TO.Features.end(), ",");
@@ -578,8 +592,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
llvm::SourceMgr TempSrcMgr;
llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
- MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, llvm::CodeModel::Default,
- Ctx);
+ MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, Ctx);
std::unique_ptr<llvm::MemoryBuffer> Buffer =
llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index f12e3f55e5..fcb1142b9c 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"
@@ -112,7 +112,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
// Parse the '<' template-parameter-list '>'
SourceLocation LAngleLoc, RAngleLoc;
- SmallVector<Decl*, 4> TemplateParams;
+ SmallVector<NamedDecl*, 4> TemplateParams;
if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
TemplateParams, LAngleLoc, RAngleLoc)) {
// Skip until the semi-colon or a '}'.
@@ -197,10 +197,11 @@ Parser::ParseSingleDeclarationAfterTemplate(
MaybeParseCXX11Attributes(prefixAttrs);
if (Tok.is(tok::kw_using)) {
- // FIXME: We should return the DeclGroup to the caller.
- ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
- prefixAttrs);
- return nullptr;
+ auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
+ prefixAttrs);
+ if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl())
+ return nullptr;
+ return usingDeclPtr.get().getSingleDecl();
}
// Parse the declaration specifiers, stealing any diagnostics from
@@ -329,10 +330,9 @@ Parser::ParseSingleDeclarationAfterTemplate(
/// that enclose this template parameter list.
///
/// \returns true if an error occurred, false otherwise.
-bool Parser::ParseTemplateParameters(unsigned Depth,
- SmallVectorImpl<Decl*> &TemplateParams,
- SourceLocation &LAngleLoc,
- SourceLocation &RAngleLoc) {
+bool Parser::ParseTemplateParameters(
+ unsigned Depth, SmallVectorImpl<NamedDecl *> &TemplateParams,
+ SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) {
// Get the template parameter list.
if (!TryConsumeToken(tok::less, LAngleLoc)) {
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
@@ -370,11 +370,12 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
/// template-parameter-list ',' template-parameter
bool
Parser::ParseTemplateParameterList(unsigned Depth,
- SmallVectorImpl<Decl*> &TemplateParams) {
+ SmallVectorImpl<NamedDecl*> &TemplateParams) {
while (1) {
+ // FIXME: ParseTemplateParameter should probably just return a NamedDecl.
if (Decl *TmpParam
= ParseTemplateParameter(Depth, TemplateParams.size())) {
- TemplateParams.push_back(TmpParam);
+ TemplateParams.push_back(dyn_cast<NamedDecl>(TmpParam));
} else {
// If we failed to parse a template parameter, skip until we find
// a comma or closing brace.
@@ -569,7 +570,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// Handle the template <...> part.
SourceLocation TemplateLoc = ConsumeToken();
- SmallVector<Decl*,8> TemplateParams;
+ SmallVector<NamedDecl*,8> TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
{
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
@@ -674,7 +675,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// FIXME: The type should probably be restricted in some way... Not all
// declarators (parts of declarators?) are accepted for parameters.
DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
+ DSC_template_param);
// Parse this as a typename.
Declarator ParamDecl(DS, Declarator::TemplateParamContext);
@@ -701,8 +703,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// end of the template-parameter-list rather than a greater-than
// operator.
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
- EnterExpressionEvaluationContext ConstantEvaluated(Actions,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (DefaultArg.isInvalid())
@@ -886,22 +888,12 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
/// list ('<' template-parameter-list [opt] '>') and placing the
/// results into a form that can be transferred to semantic analysis.
///
-/// \param Template the template declaration produced by isTemplateName
-///
-/// \param TemplateNameLoc the source location of the template name
-///
-/// \param SS if non-NULL, the nested-name-specifier preceding the
-/// template name.
-///
/// \param ConsumeLastToken if true, then we will consume the last
/// token that forms the template-id. Otherwise, we will leave the
/// last token in the stream (e.g., so that it can be replaced with an
/// annotation token).
bool
-Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
- const CXXScopeSpec &SS,
- bool ConsumeLastToken,
+Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
SourceLocation &RAngleLoc) {
@@ -983,9 +975,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- bool Invalid = ParseTemplateIdAfterTemplateName(Template,
- TemplateNameLoc,
- SS, false, LAngleLoc,
+ bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
TemplateArgs,
RAngleLoc);
@@ -1023,25 +1013,21 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build a template-id annotation token that can be processed
// later.
Tok.setKind(tok::annot_template_id);
- TemplateIdAnnotation *TemplateId
- = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
- TemplateId->TemplateNameLoc = TemplateNameLoc;
- if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
- TemplateId->Name = TemplateName.Identifier;
- TemplateId->Operator = OO_None;
- } else {
- TemplateId->Name = nullptr;
- TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
- }
- TemplateId->SS = SS;
- TemplateId->TemplateKWLoc = TemplateKWLoc;
- TemplateId->Template = Template;
- TemplateId->Kind = TNK;
- TemplateId->LAngleLoc = LAngleLoc;
- TemplateId->RAngleLoc = RAngleLoc;
- ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
- for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
- Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]);
+
+ IdentifierInfo *TemplateII =
+ TemplateName.getKind() == UnqualifiedId::IK_Identifier
+ ? TemplateName.Identifier
+ : nullptr;
+
+ OverloadedOperatorKind OpKind =
+ TemplateName.getKind() == UnqualifiedId::IK_Identifier
+ ? OO_None
+ : TemplateName.OperatorFunctionId.Operator;
+
+ TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
+ SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+ LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
+
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
@@ -1198,7 +1184,13 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
// expression is resolved to a type-id, regardless of the form of
// the corresponding template-parameter.
//
- // Therefore, we initially try to parse a type-id.
+ // Therefore, we initially try to parse a type-id - and isCXXTypeId might look
+ // up and annotate an identifier as an id-expression during disambiguation,
+ // so enter the appropriate context for a constant expression template
+ // argument before trying to disambiguate.
+
+ EnterExpressionEvaluationContext EnterConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
SourceLocation Loc = Tok.getLocation();
TypeResult TypeArg = ParseTypeName(/*Range=*/nullptr,
@@ -1228,7 +1220,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
// Parse a non-type template argument.
SourceLocation Loc = Tok.getLocation();
- ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast);
+ ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast);
if (ExprArg.isInvalid() || !ExprArg.get())
return ParsedTemplateArgument();
@@ -1246,7 +1238,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
} Tentative(*this);
while (Skip) {
- ConsumeToken();
+ ConsumeAnyToken();
--Skip;
}
@@ -1260,7 +1252,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
// See whether we have declaration specifiers, which indicate a type.
while (isCXXDeclarationSpecifier() == TPResult::True)
- ConsumeToken();
+ ConsumeAnyToken();
// If we have a '>' or a ',' then this is a template argument list.
return Tok.isOneOf(tok::greater, tok::comma);
@@ -1274,8 +1266,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
/// template-argument-list ',' template-argument
bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
- // Template argument lists are constant-evaluation contexts.
- EnterExpressionEvaluationContext EvalContext(Actions,Sema::ConstantEvaluated);
+
ColonProtectionRAIIObject ColonProtection(*this, false);
do {
@@ -1390,7 +1381,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
// Parse the method body. Function body parsing code is similar enough
// to be re-used for method bodies as well.
- ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
+ ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
// Recreate the containing function DeclContext.
Sema::ContextRAII FunctionSavedContext(Actions,
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 0ea3f8d951..48393d9c00 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -208,17 +208,20 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
TryAnnotateCXXScopeToken())
return TPResult::Error;
if (Tok.is(tok::annot_cxxscope))
+ ConsumeAnnotationToken();
+ if (Tok.is(tok::identifier))
ConsumeToken();
- if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+ else if (Tok.is(tok::annot_template_id))
+ ConsumeAnnotationToken();
+ else
return TPResult::Error;
- ConsumeToken();
break;
case tok::annot_cxxscope:
- ConsumeToken();
+ ConsumeAnnotationToken();
// Fall through.
default:
- ConsumeToken();
+ ConsumeAnyToken();
if (getLangOpts().ObjC1 && Tok.is(tok::less))
return TryParseProtocolQualifiers();
@@ -478,10 +481,10 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement) {
/// the corresponding ')'. If the context is
/// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
/// before this template argument, and will cease lookahead when we
- /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
- /// and false for an expression. If during the disambiguation
- /// process a parsing error is encountered, the function returns
- /// true to let the declaration parsing code handle it.
+ /// hit a '>', '>>' (in C++0x), or ','; or, in C++0x, an ellipsis immediately
+ /// preceding such. Returns true for a type-id and false for an expression.
+ /// If during the disambiguation process a parsing error is encountered,
+ /// the function returns true to let the declaration parsing code handle it.
///
/// type-id:
/// type-specifier-seq abstract-declarator[opt]
@@ -530,10 +533,15 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
// We are supposed to be inside a template argument, so if after
// the abstract declarator we encounter a '>', '>>' (in C++0x), or
- // ',', this is a type-id. Otherwise, it's an expression.
+ // ','; or, in C++0x, an ellipsis immediately preceding such, this
+ // is a type-id. Otherwise, it's an expression.
} else if (Context == TypeIdAsTemplateArgument &&
(Tok.isOneOf(tok::greater, tok::comma) ||
- (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater)))) {
+ (getLangOpts().CPlusPlus11 &&
+ (Tok.is(tok::greatergreater) ||
+ (Tok.is(tok::ellipsis) &&
+ NextToken().isOneOf(tok::greater, tok::greatergreater,
+ tok::comma)))))) {
TPR = TPResult::True;
isAmbiguous = true;
@@ -706,7 +714,7 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() {
if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
// ptr-operator
- ConsumeToken();
+ ConsumeAnyToken();
while (Tok.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict,
tok::kw__Nonnull, tok::kw__Nullable,
tok::kw__Null_unspecified))
@@ -826,14 +834,14 @@ Parser::TPResult Parser::TryParseOperatorId() {
/// abstract-declarator:
/// ptr-operator abstract-declarator[opt]
/// direct-abstract-declarator
-/// ...
///
/// direct-abstract-declarator:
/// direct-abstract-declarator[opt]
-/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
/// exception-specification[opt]
/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
/// '(' abstract-declarator ')'
+/// [C++0x] ...
///
/// ptr-operator:
/// '*' cv-qualifier-seq[opt]
@@ -883,7 +891,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
mayHaveIdentifier) {
// declarator-id
if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
+ ConsumeAnnotationToken();
else if (Tok.is(tok::identifier))
TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
if (Tok.is(tok::kw_operator)) {
@@ -925,10 +933,6 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
while (1) {
TPResult TPR(TPResult::Ambiguous);
- // abstract-declarator: ...
- if (Tok.is(tok::ellipsis))
- ConsumeToken();
-
if (Tok.is(tok::l_paren)) {
// Check whether we have a function declarator or a possible ctor-style
// initializer that follows the declarator. Note that ctor-style
@@ -1022,6 +1026,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_char:
case tok::kw_const:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_enum:
case tok::kw_half:
@@ -1399,7 +1404,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
SS);
if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) {
RevertingTentativeParsingAction PA(*this);
- ConsumeToken();
+ ConsumeAnnotationToken();
ConsumeToken();
bool isIdentifier = Tok.is(tok::identifier);
TPResult TPR = TPResult::False;
@@ -1446,6 +1451,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return TPResult::False;
}
// If that succeeded, fallthrough into the generic simple-type-id case.
+ LLVM_FALLTHROUGH;
// The ambiguity resides in a simple-type-specifier/typename-specifier
// followed by a '('. The '(' could either be the start of:
@@ -1471,7 +1477,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
// Tentatively parse the protocol qualifiers.
RevertingTentativeParsingAction PA(*this);
- ConsumeToken(); // The type token
+ ConsumeAnyToken(); // The type token
TPResult TPR = TryParseProtocolQualifiers();
bool isFollowedByParen = Tok.is(tok::l_paren);
@@ -1488,6 +1494,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return TPResult::True;
}
+ LLVM_FALLTHROUGH;
case tok::kw_char:
case tok::kw_wchar_t:
@@ -1504,6 +1511,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_void:
case tok::annot_decltype:
@@ -1594,6 +1602,7 @@ bool Parser::isCXXDeclarationSpecifierAType() {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_void:
case tok::kw___unknown_anytype:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 7df2e3288c..0b07ba1888 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.
//===----------------------------------------------------------------------===//
@@ -342,21 +337,13 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
ConsumeBrace();
break;
- case tok::string_literal:
- case tok::wide_string_literal:
- case tok::utf8_string_literal:
- case tok::utf16_string_literal:
- case tok::utf32_string_literal:
- ConsumeStringToken();
- break;
-
case tok::semi:
if (HasFlagsSet(Flags, StopAtSemi))
return false;
// FALL THROUGH.
default:
// Skip this token.
- ConsumeToken();
+ ConsumeAnyToken();
break;
}
isFirstTokenSkipped = false;
@@ -539,22 +526,7 @@ void Parser::LateTemplateParserCleanupCallback(void *P) {
}
bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
- // C++ Modules TS: module-declaration must be the first declaration in the
- // file. (There can be no preceding preprocessor directives, but we expect
- // the lexer to check that.)
- if (Tok.is(tok::kw_module)) {
- Result = ParseModuleDecl();
- return false;
- } else if (getLangOpts().getCompilingModule() ==
- LangOptions::CMK_ModuleInterface) {
- // FIXME: We avoid providing this diagnostic when generating an object file
- // from an existing PCM file. This is not a good way to detect this
- // condition; we should provide a mechanism to indicate whether we've
- // already parsed a declaration in this translation unit and avoid calling
- // ParseFirstTopLevelDecl in that case.
- if (Actions.TUKind == TU_Module)
- Diag(Tok, diag::err_expected_module_interface_decl);
- }
+ Actions.ActOnStartOfTranslationUnit();
// C11 6.9p1 says translation units must have at least one top-level
// declaration. C++ doesn't have this restriction. We also don't want to
@@ -588,23 +560,35 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
Result = ParseModuleImport(SourceLocation());
return false;
+ case tok::kw_export:
+ if (NextToken().isNot(tok::kw_module))
+ break;
+ LLVM_FALLTHROUGH;
+ case tok::kw_module:
+ Result = ParseModuleDecl();
+ return false;
+
case tok::annot_module_include:
Actions.ActOnModuleInclude(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
case tok::annot_module_begin:
Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
case tok::annot_module_end:
Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
+ return false;
+
+ case tok::annot_pragma_attribute:
+ HandlePragmaAttribute();
return false;
case tok::eof:
@@ -690,6 +674,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_fp_contract:
HandlePragmaFPContract();
return nullptr;
+ case tok::annot_pragma_fp:
+ HandlePragmaFP();
+ break;
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return nullptr;
@@ -766,9 +753,15 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
SingleDecl = ParseObjCMethodDefinition();
break;
case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(getCurScope(),
- CurParsedObjCImpl? Sema::PCC_ObjCImplementation
- : Sema::PCC_Namespace);
+ if (CurParsedObjCImpl) {
+ // Code-complete Objective-C methods even without leading '-'/'+' prefix.
+ Actions.CodeCompleteObjCMethodDecl(getCurScope(),
+ /*IsInstanceMethod=*/None,
+ /*ReturnType=*/nullptr);
+ }
+ Actions.CodeCompleteOrdinaryName(
+ getCurScope(),
+ CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace);
cutOffParsing();
return nullptr;
case tok::kw_export:
@@ -778,6 +771,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
}
// This must be 'export template'. Parse it so we can diagnose our lack
// of support.
+ LLVM_FALLTHROUGH;
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -849,6 +843,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
default:
dont_know:
+ if (Tok.isEditorPlaceholder()) {
+ ConsumeToken();
+ return nullptr;
+ }
// We can't tell whether this is a function-definition or declaration yet.
return ParseDeclarationOrFunctionDefinition(attrs, DS);
}
@@ -1081,8 +1079,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
TemplateInfo.Kind == ParsedTemplateInfo::Template &&
Actions.canDelayFunctionBody(D)) {
MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
-
- ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+
+ ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
@@ -1112,7 +1111,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
(Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
Tok.is(tok::colon)) &&
Actions.CurContext->isTranslationUnit()) {
- ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+ ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FDK_Definition);
@@ -1130,7 +1130,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
}
// Enter a scope for the function body.
- ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+ ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
// Tell the actions module that we have entered a function definition with the
// specified Declarator for the function.
@@ -1677,6 +1678,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
return false;
}
}
+ if (Tok.isEditorPlaceholder())
+ return true;
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
return true;
@@ -1884,6 +1887,7 @@ bool Parser::isTokenEqualOrEqualTypo() {
Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal)
<< Kind
<< FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
+ LLVM_FALLTHROUGH;
case tok::equal:
return true;
}
@@ -2041,30 +2045,28 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
/// Parse a C++ Modules TS module declaration, which appears at the beginning
/// of a module interface, module partition, or module implementation file.
///
-/// module-declaration: [Modules TS + P0273R0]
-/// 'module' module-kind[opt] module-name attribute-specifier-seq[opt] ';'
-/// module-kind:
-/// 'implementation'
-/// 'partition'
+/// module-declaration: [Modules TS + P0273R0 + P0629R0]
+/// 'export'[opt] 'module' 'partition'[opt]
+/// module-name attribute-specifier-seq[opt] ';'
///
-/// Note that the module-kind values are context-sensitive keywords.
+/// Note that 'partition' is a context-sensitive keyword.
Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
- assert(Tok.is(tok::kw_module) && getLangOpts().ModulesTS &&
- "should not be parsing a module declaration");
+ SourceLocation StartLoc = Tok.getLocation();
+
+ Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export)
+ ? Sema::ModuleDeclKind::Interface
+ : Sema::ModuleDeclKind::Implementation;
+
+ assert(Tok.is(tok::kw_module) && "not a module declaration");
SourceLocation ModuleLoc = ConsumeToken();
- // Check for a module-kind.
- Sema::ModuleDeclKind MDK = Sema::ModuleDeclKind::Module;
- if (Tok.is(tok::identifier) && NextToken().is(tok::identifier)) {
- if (Tok.getIdentifierInfo()->isStr("implementation"))
- MDK = Sema::ModuleDeclKind::Implementation;
- else if (Tok.getIdentifierInfo()->isStr("partition"))
- MDK = Sema::ModuleDeclKind::Partition;
- else {
- Diag(Tok, diag::err_unexpected_module_kind) << Tok.getIdentifierInfo();
- SkipUntil(tok::semi);
- return nullptr;
- }
+ if (Tok.is(tok::identifier) && NextToken().is(tok::identifier) &&
+ Tok.getIdentifierInfo()->isStr("partition")) {
+ // If 'partition' is present, this must be a module interface unit.
+ if (MDK != Sema::ModuleDeclKind::Interface)
+ Diag(Tok.getLocation(), diag::err_module_implementation_partition)
+ << FixItHint::CreateInsertion(ModuleLoc, "export ");
+ MDK = Sema::ModuleDeclKind::Partition;
ConsumeToken();
}
@@ -2072,14 +2074,14 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false))
return nullptr;
+ // We don't support any module attributes yet; just parse them and diagnose.
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
- // We don't support any module attributes yet.
ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
- return Actions.ActOnModuleDecl(ModuleLoc, MDK, Path);
+ return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path);
}
/// Parse a module import declaration. This is essentially the same for
@@ -2172,7 +2174,7 @@ bool Parser::parseMisplacedModuleImport() {
Actions.ActOnModuleEnd(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
continue;
}
// Inform caller that recovery failed, the error must be handled at upper
@@ -2184,7 +2186,7 @@ bool Parser::parseMisplacedModuleImport() {
Actions.ActOnModuleBegin(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
++MisplacedModuleBeginCount;
continue;
case tok::annot_module_include:
@@ -2193,7 +2195,7 @@ bool Parser::parseMisplacedModuleImport() {
Actions.ActOnModuleInclude(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
// If there is another module import, process it.
continue;
default:
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index 27bb976a6e..23d1895e31 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -289,6 +289,11 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter &R, FileID FID,
" body { color:#000000; background-color:#ffffff }\n"
" body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
" h1 { font-size:14pt }\n"
+ " .FileName { margin-top: 5px; margin-bottom: 5px; display: inline; }\n"
+ " .FileNav { margin-left: 5px; margin-right: 5px; display: inline; }\n"
+ " .FileNav a { text-decoration:none; font-size: larger; }\n"
+ " .divider { margin-top: 30px; margin-bottom: 30px; height: 15px; }\n"
+ " .divider { background-color: gray; }\n"
" .code { border-collapse:collapse; width:100%; }\n"
" .code { font-family: \"Monospace\", monospace; font-size:10pt }\n"
" .code { line-height: 1.2em }\n"
@@ -409,6 +414,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
++TokOffs;
--TokLen;
// FALL THROUGH to chop the 8
+ LLVM_FALLTHROUGH;
case tok::wide_string_literal:
case tok::utf16_string_literal:
case tok::utf32_string_literal:
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index a987a8ce0b..f004a990a4 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -29,7 +29,7 @@
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Basic/SourceLocation.h"
@@ -279,6 +279,158 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
}
//===----------------------------------------------------------------------===//
+// Check for throw in a non-throwing function.
+//===----------------------------------------------------------------------===//
+enum ThrowState {
+ FoundNoPathForThrow,
+ FoundPathForThrow,
+ FoundPathWithNoThrowOutFunction,
+};
+
+static bool isThrowCaught(const CXXThrowExpr *Throw,
+ const CXXCatchStmt *Catch) {
+ const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull();
+ if (!CaughtType)
+ return true;
+ const Type *ThrowType = nullptr;
+ if (Throw->getSubExpr())
+ ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull();
+ if (!ThrowType)
+ return false;
+ if (ThrowType->isReferenceType())
+ ThrowType = ThrowType->castAs<ReferenceType>()
+ ->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ if (CaughtType->isReferenceType())
+ CaughtType = CaughtType->castAs<ReferenceType>()
+ ->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ if (ThrowType->isPointerType() && CaughtType->isPointerType()) {
+ ThrowType = ThrowType->getPointeeType()->getUnqualifiedDesugaredType();
+ CaughtType = CaughtType->getPointeeType()->getUnqualifiedDesugaredType();
+ }
+ if (CaughtType == ThrowType)
+ return true;
+ const CXXRecordDecl *CaughtAsRecordType =
+ CaughtType->getAsCXXRecordDecl();
+ const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl();
+ if (CaughtAsRecordType && ThrowTypeAsRecordType)
+ return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType);
+ return false;
+}
+
+static bool isThrowCaughtByHandlers(const CXXThrowExpr *CE,
+ const CXXTryStmt *TryStmt) {
+ for (unsigned H = 0, E = TryStmt->getNumHandlers(); H < E; ++H) {
+ if (isThrowCaught(CE, TryStmt->getHandler(H)))
+ return true;
+ }
+ return false;
+}
+
+static bool doesThrowEscapePath(CFGBlock Block, SourceLocation &OpLoc) {
+ for (const auto &B : Block) {
+ if (B.getKind() != CFGElement::Statement)
+ continue;
+ const auto *CE = dyn_cast<CXXThrowExpr>(B.getAs<CFGStmt>()->getStmt());
+ if (!CE)
+ continue;
+
+ OpLoc = CE->getThrowLoc();
+ for (const auto &I : Block.succs()) {
+ if (!I.isReachable())
+ continue;
+ if (const auto *Terminator =
+ dyn_cast_or_null<CXXTryStmt>(I->getTerminator()))
+ if (isThrowCaughtByHandlers(CE, Terminator))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) {
+
+ unsigned ExitID = BodyCFG->getExit().getBlockID();
+
+ SmallVector<ThrowState, 16> States(BodyCFG->getNumBlockIDs(),
+ FoundNoPathForThrow);
+ States[BodyCFG->getEntry().getBlockID()] = FoundPathWithNoThrowOutFunction;
+
+ SmallVector<CFGBlock *, 16> Stack;
+ Stack.push_back(&BodyCFG->getEntry());
+ while (!Stack.empty()) {
+ CFGBlock *CurBlock = Stack.pop_back_val();
+
+ unsigned ID = CurBlock->getBlockID();
+ ThrowState CurState = States[ID];
+ if (CurState == FoundPathWithNoThrowOutFunction) {
+ if (ExitID == ID)
+ continue;
+
+ if (doesThrowEscapePath(*CurBlock, OpLoc))
+ CurState = FoundPathForThrow;
+ }
+
+ // Loop over successor blocks and add them to the Stack if their state
+ // changes.
+ for (const auto &I : CurBlock->succs())
+ if (I.isReachable()) {
+ unsigned NextID = I->getBlockID();
+ if (NextID == ExitID && CurState == FoundPathForThrow) {
+ States[NextID] = CurState;
+ } else if (States[NextID] < CurState) {
+ States[NextID] = CurState;
+ Stack.push_back(I);
+ }
+ }
+ }
+ // Return true if the exit node is reachable, and only reachable through
+ // a throw expression.
+ return States[ExitID] == FoundPathForThrow;
+}
+
+static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,
+ const FunctionDecl *FD) {
+ if (!S.getSourceManager().isInSystemHeader(OpLoc) &&
+ FD->getTypeSourceInfo()) {
+ S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
+ if (S.getLangOpts().CPlusPlus11 &&
+ (isa<CXXDestructorDecl>(FD) ||
+ FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||
+ FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) {
+ if (const auto *Ty = FD->getTypeSourceInfo()->getType()->
+ getAs<FunctionProtoType>())
+ S.Diag(FD->getLocation(), diag::note_throw_in_dtor)
+ << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
+ << FD->getExceptionSpecSourceRange();
+ } else
+ S.Diag(FD->getLocation(), diag::note_throw_in_function)
+ << FD->getExceptionSpecSourceRange();
+ }
+}
+
+static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
+ AnalysisDeclContext &AC) {
+ CFG *BodyCFG = AC.getCFG();
+ if (!BodyCFG)
+ return;
+ if (BodyCFG->getExit().pred_empty())
+ return;
+ SourceLocation OpLoc;
+ if (hasThrowOutNonThrowingFunc(OpLoc, BodyCFG))
+ EmitDiagForCXXThrowInNonThrowingFunc(S, OpLoc, FD);
+}
+
+static bool isNoexcept(const FunctionDecl *FD) {
+ const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ if (FPT->isNothrow(FD->getASTContext()) || FD->hasAttr<NoThrowAttr>())
+ return true;
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
// Check for missing return value.
//===----------------------------------------------------------------------===//
@@ -542,6 +694,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
bool ReturnsVoid = false;
bool HasNoReturn = false;
+ bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine();
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
@@ -570,8 +723,13 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
return;
-
SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd();
+ auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) {
+ if (IsCoroutine)
+ S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType();
+ else
+ S.Diag(Loc, DiagID);
+ };
// Either in a function body compound statement, or a function-try-block.
switch (CheckFallThrough(AC)) {
case UnknownFallThrough:
@@ -579,15 +737,15 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
case MaybeFallThrough:
if (HasNoReturn)
- S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
+ EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
else if (!ReturnsVoid)
- S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
+ EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
break;
case AlwaysFallThrough:
if (HasNoReturn)
- S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
+ EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
else if (!ReturnsVoid)
- S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
+ EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
break;
case NeverFallThroughOrReturn:
if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
@@ -972,7 +1130,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 +1161,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;
@@ -1128,16 +1291,15 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
- // Only perform this analysis when using C++11. There is no good workflow
- // for this warning when not using C++11. There is no good way to silence
- // the warning (no attribute is available) unless we are using C++11's support
- // for generalized attributes. Once could use pragmas to silence the warning,
- // but as a general solution that is gross and not in the spirit of this
- // warning.
+ // Only perform this analysis when using [[]] attributes. There is no good
+ // workflow for this warning when not using C++11. There is no good way to
+ // silence the warning (no attribute is available) unless we are using
+ // [[]] attributes. One could use pragmas to silence the warning, but as a
+ // general solution that is gross and not in the spirit of this warning.
//
- // NOTE: This an intermediate solution. There are on-going discussions on
+ // NOTE: This an intermediate solution. There are on-going discussions on
// how to properly support this warning outside of C++11 with an annotation.
- if (!AC.getASTContext().getLangOpts().CPlusPlus11)
+ if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes)
return;
FallthroughMapper FM(S);
@@ -1164,7 +1326,11 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
int AnnotatedCnt;
- if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt))
+ bool IsTemplateInstantiation = false;
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl()))
+ IsTemplateInstantiation = Function->isTemplateInstantiation();
+ if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
+ IsTemplateInstantiation))
continue;
S.Diag(Label->getLocStart(),
@@ -2018,12 +2184,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Warning: check missing 'return'
if (P.enableCheckFallThrough) {
- auto IsCoro = [&]() {
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- if (FD->getBody() && isa<CoroutineBodyStmt>(FD->getBody()))
- return true;
- return false;
- };
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D)
? CheckFallThroughDiagnostics::MakeForBlock()
@@ -2031,7 +2191,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
cast<CXXMethodDecl>(D)->getParent()->isLambda())
? CheckFallThroughDiagnostics::MakeForLambda()
- : (IsCoro()
+ : (fscope->isCoroutine()
? CheckFallThroughDiagnostics::MakeForCoroutine(D)
: CheckFallThroughDiagnostics::MakeForFunction(D)));
CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
@@ -2118,6 +2278,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
}
}
+ // Check for throw out of non-throwing function.
+ if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getLocStart()))
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (S.getLangOpts().CPlusPlus && isNoexcept(FD))
+ checkThrowInNonThrowingFunc(S, FD, AC);
+
// If none of the previous checks caused a CFG build, trigger one here
// for -Wtautological-overlap-compare
if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 55e9601bf5..14d334746f 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaInternal.h"
@@ -113,7 +114,8 @@ static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName,
// Normalize the attribute name, __foo__ becomes foo. This is only allowable
// for GNU attributes.
bool IsGNU = SyntaxUsed == AttributeList::AS_GNU ||
- (SyntaxUsed == AttributeList::AS_CXX11 && ScopeName == "gnu");
+ ((SyntaxUsed == AttributeList::AS_CXX11 ||
+ SyntaxUsed == AttributeList::AS_C2x) && ScopeName == "gnu");
if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") &&
AttrName.endswith("__"))
AttrName = AttrName.slice(2, AttrName.size() - 2);
@@ -134,7 +136,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
// Ensure that in the case of C++11 attributes, we look for '::foo' if it is
// unscoped.
- if (ScopeName || SyntaxUsed == AS_CXX11)
+ if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
FullName += "::";
FullName += AttrName;
@@ -160,12 +162,16 @@ struct ParsedAttrInfo {
unsigned IsType : 1;
unsigned IsStmt : 1;
unsigned IsKnownToGCC : 1;
+ unsigned IsSupportedByPragmaAttribute : 1;
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
const Decl *);
bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
bool (*ExistsInTarget)(const TargetInfo &Target);
unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
+ void (*GetPragmaAttributeMatchRules)(
+ llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
+ const LangOptions &LangOpts);
};
namespace {
@@ -192,6 +198,18 @@ bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
}
+bool AttributeList::appliesToDecl(const Decl *D,
+ attr::SubjectMatchRule MatchRule) const {
+ return checkAttributeMatchRuleAppliesTo(D, MatchRule);
+}
+
+void AttributeList::getMatchRules(
+ const LangOptions &LangOpts,
+ SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
+ const {
+ return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
+}
+
bool AttributeList::diagnoseLangOpts(Sema &S) const {
return getInfo(*this).DiagLangOpts(S, *this);
}
@@ -216,6 +234,10 @@ bool AttributeList::isKnownToGCC() const {
return getInfo(*this).IsKnownToGCC;
}
+bool AttributeList::isSupportedByPragmaAttribute() const {
+ return getInfo(*this).IsSupportedByPragmaAttribute;
+}
+
unsigned AttributeList::getSemanticSpelling() const {
return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 7a5973299f..7d9ae621c9 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
)
if (MSVC)
+ set_source_files_properties(SemaDeclAttr.cpp PROPERTIES COMPILE_FLAGS /bigobj)
set_source_files_properties(SemaExpr.cpp PROPERTIES COMPILE_FLAGS /bigobj)
endif()
diff --git a/lib/Sema/CoroutineStmtBuilder.h b/lib/Sema/CoroutineStmtBuilder.h
new file mode 100644
index 0000000000..33a368d92f
--- /dev/null
+++ b/lib/Sema/CoroutineStmtBuilder.h
@@ -0,0 +1,73 @@
+//===- CoroutineStmtBuilder.h - Implicit coroutine stmt builder -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===//
+//
+// This file defines CoroutineStmtBuilder, a class for building the implicit
+// statements required for building a coroutine body.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_SEMA_COROUTINESTMTBUILDER_H
+#define LLVM_CLANG_LIB_SEMA_COROUTINESTMTBUILDER_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaInternal.h"
+
+namespace clang {
+
+class CoroutineStmtBuilder : public CoroutineBodyStmt::CtorArgs {
+ Sema &S;
+ FunctionDecl &FD;
+ sema::FunctionScopeInfo &Fn;
+ bool IsValid = true;
+ SourceLocation Loc;
+ SmallVector<Stmt *, 4> ParamMovesVector;
+ const bool IsPromiseDependentType;
+ CXXRecordDecl *PromiseRecordDecl = nullptr;
+
+public:
+ /// \brief Construct a CoroutineStmtBuilder and initialize the promise
+ /// statement and initial/final suspends from the FunctionScopeInfo.
+ CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, sema::FunctionScopeInfo &Fn,
+ Stmt *Body);
+
+ /// \brief Build the coroutine body statements, including the
+ /// "promise dependent" statements when the promise type is not dependent.
+ bool buildStatements();
+
+ /// \brief Build the coroutine body statements that require a non-dependent
+ /// promise type in order to construct.
+ ///
+ /// For example different new/delete overloads are selected depending on
+ /// if the promise type provides `unhandled_exception()`, and therefore they
+ /// cannot be built until the promise type is complete so that we can perform
+ /// name lookup.
+ bool buildDependentStatements();
+
+ /// \brief Build just parameter moves. To use for rebuilding in TreeTransform.
+ bool buildParameterMoves();
+
+ bool isInvalid() const { return !this->IsValid; }
+
+private:
+ bool makePromiseStmt();
+ bool makeInitialAndFinalSuspend();
+ bool makeNewAndDeleteExpr();
+ bool makeOnFallthrough();
+ bool makeOnException();
+ bool makeReturnObject();
+ bool makeGroDeclAndReturnStmt();
+ bool makeReturnOnAllocFailure();
+ bool makeParamMoves();
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_SEMA_COROUTINESTMTBUILDER_H
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index a55cdcccee..bce493989d 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -336,6 +336,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_decimal32:
case TST_decimal64:
case TST_double:
+ case TST_Float16:
case TST_float128:
case TST_enum:
case TST_error:
@@ -505,6 +506,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_half: return "half";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
+ case DeclSpec::TST_float16: return "_Float16";
case DeclSpec::TST_float128: return "__float128";
case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool";
case DeclSpec::TST_decimal32: return "_Decimal32";
@@ -1082,8 +1084,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
!S.getLangOpts().ZVector)
S.Diag(TSTLoc, diag::err_invalid_vector_double_decl_spec);
} else if (TypeSpecType == TST_float) {
- // vector float is unsupported for ZVector.
- if (S.getLangOpts().ZVector)
+ // vector float is unsupported for ZVector unless we have the
+ // vector-enhancements facility 1 (ISA revision 12).
+ if (S.getLangOpts().ZVector &&
+ !S.Context.getTargetInfo().hasFeature("arch12"))
S.Diag(TSTLoc, diag::err_invalid_vector_float_decl_spec);
} else if (TypeSpecWidth == TSW_long) {
// vector long is unsupported for ZVector and deprecated for AltiVec.
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index 2fa5718d4e..3d321d561e 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -22,7 +22,8 @@ using namespace sema;
DelayedDiagnostic
DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
SourceLocation Loc,
- const NamedDecl *D,
+ const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
StringRef Msg,
@@ -31,7 +32,8 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
DD.Kind = Availability;
DD.Triggered = false;
DD.Loc = Loc;
- DD.AvailabilityData.Decl = D;
+ DD.AvailabilityData.ReferringDecl = ReferringDecl;
+ DD.AvailabilityData.OffendingDecl = OffendingDecl;
DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass;
DD.AvailabilityData.ObjCProperty = ObjCProperty;
char *MessageData = nullptr;
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 899d3fa83c..865aea9e22 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -287,6 +287,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
break;
+ case Stmt::ObjCForCollectionStmtClass: {
+ auto *CS = cast<ObjCForCollectionStmt>(S);
+ unsigned Diag = diag::note_protected_by_objc_fast_enumeration;
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->getLocStart()));
+ BuildScopeInformation(CS->getBody(), NewParentScope);
+ return;
+ }
+
case Stmt::IndirectGotoStmtClass:
// "goto *&&lbl;" is a special case which we treat as equivalent
// to a normal goto. In addition, we don't calculate scope in the
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index c97e4dfdd6..77ace0cfa5 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -19,8 +19,6 @@ using namespace clang;
///\brief Constructs a new multiplexing external sema source and appends the
/// given element to it.
///
-///\param[in] source - An ExternalSemaSource.
-///
MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1,
ExternalSemaSource &s2){
Sources.push_back(&s1);
@@ -95,9 +93,9 @@ MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
}
ExternalASTSource::ExtKind
-MultiplexExternalSemaSource::hasExternalDefinitions(unsigned int ID) {
+MultiplexExternalSemaSource::hasExternalDefinitions(const Decl *D) {
for (const auto &S : Sources)
- if (auto EK = S->hasExternalDefinitions(ID))
+ if (auto EK = S->hasExternalDefinitions(D))
if (EK != EK_ReplyHazy)
return EK;
return EK_ReplyHazy;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 1677d340fb..31400e1de8 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -70,43 +70,78 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
PushDeclContext(S, Context.getTranslationUnitDecl());
}
+namespace clang {
+namespace sema {
+
+class SemaPPCallbacks : public PPCallbacks {
+ Sema *S = nullptr;
+ llvm::SmallVector<SourceLocation, 8> IncludeStack;
+
+public:
+ void set(Sema &S) { this->S = &S; }
+
+ void reset() { S = nullptr; }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override {
+ if (!S)
+ return;
+ switch (Reason) {
+ case EnterFile: {
+ SourceManager &SM = S->getSourceManager();
+ SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc));
+ if (IncludeLoc.isValid()) {
+ IncludeStack.push_back(IncludeLoc);
+ S->DiagnoseNonDefaultPragmaPack(
+ Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc);
+ }
+ break;
+ }
+ case ExitFile:
+ if (!IncludeStack.empty())
+ S->DiagnoseNonDefaultPragmaPack(
+ Sema::PragmaPackDiagnoseKind::ChangedStateAtExit,
+ IncludeStack.pop_back_val());
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+} // end namespace sema
+} // end namespace clang
+
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
- TranslationUnitKind TUKind,
- CodeCompleteConsumer *CodeCompleter)
- : ExternalSource(nullptr),
- isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
- LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
- Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- CollectStats(false), CodeCompleter(CodeCompleter),
- CurContext(nullptr), OriginalLexicalContext(nullptr),
- MSStructPragmaOn(false),
- MSPointerToMemberRepresentationMethod(
- LangOpts.getMSPointerToMemberRepresentationMethod()),
- VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
- PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr),
- ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr),
- VisContext(nullptr),
- IsBuildingRecoveryCallExpr(false),
- Cleanup{}, LateTemplateParser(nullptr),
- LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
- StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
- CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
- NSNumberDecl(nullptr), NSValueDecl(nullptr),
- NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
- ValueWithBytesObjCTypeMethod(nullptr),
- NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
- NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
- GlobalNewDeleteDeclared(false),
- TUKind(TUKind),
- NumSFINAEErrors(0),
- CachedFakeTopLevelModule(nullptr),
- AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
- VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
- Ident_super(nullptr), Ident___float128(nullptr)
-{
+ TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
+ : ExternalSource(nullptr), isMultiplexExternalSource(false),
+ FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
+ Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
+ SourceMgr(PP.getSourceManager()), CollectStats(false),
+ CodeCompleter(CodeCompleter), CurContext(nullptr),
+ OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
+ MSPointerToMemberRepresentationMethod(
+ LangOpts.getMSPointerToMemberRepresentationMethod()),
+ VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0),
+ DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
+ CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
+ PragmaAttributeCurrentTargetDecl(nullptr),
+ IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
+ LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
+ StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
+ CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr),
+ NSValueDecl(nullptr), NSStringDecl(nullptr),
+ StringWithUTF8StringMethod(nullptr),
+ ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
+ ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
+ DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
+ TUKind(TUKind), NumSFINAEErrors(0), AccessCheckingSFINAE(false),
+ InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
+ ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
+ DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
+ ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
+ CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
LoadedExternalKnownNamespaces = false;
@@ -122,13 +157,20 @@ 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));
// Initilization of data sharing attributes stack for OpenMP
InitDataSharingAttributesStack();
+
+ std::unique_ptr<sema::SemaPPCallbacks> Callbacks =
+ llvm::make_unique<sema::SemaPPCallbacks>();
+ SemaPPCallbackHandler = Callbacks.get();
+ PP.addPPCallbacks(std::move(Callbacks));
+ SemaPPCallbackHandler->set(*this);
}
void Sema::addImplicitTypedef(StringRef Name, QualType T) {
@@ -313,6 +355,10 @@ Sema::~Sema() {
// Destroys data sharing attributes stack for OpenMP
DestroyDataSharingAttributesStack();
+ // Detach from the PP callback handler which outlives Sema since it's owned
+ // by the preprocessor.
+ SemaPPCallbackHandler->reset();
+
assert(DelayedTypos.empty() && "Uncorrected typos!");
}
@@ -389,6 +435,31 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType;
}
+void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
+ if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant,
+ E->getLocStart()))
+ return;
+ // nullptr only exists from C++11 on, so don't warn on its absence earlier.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer)
+ return;
+ if (E->IgnoreParenImpCasts()->getType()->isNullPtrType())
+ return;
+
+ // If it is a macro from system header, and if the macro name is not "NULL",
+ // do not warn.
+ SourceLocation MaybeMacroLoc = E->getLocStart();
+ if (Diags.getSuppressSystemWarnings() &&
+ SourceMgr.isInSystemMacro(MaybeMacroLoc) &&
+ !findMacroSpelling(MaybeMacroLoc, "NULL"))
+ return;
+
+ Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant)
+ << FixItHint::CreateReplacement(E->getSourceRange(), "nullptr");
+}
+
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// The result is of the given category.
@@ -413,6 +484,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
#endif
diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getLocStart());
+ diagnoseZeroToNullptrConversion(Kind, E);
QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
@@ -469,6 +541,13 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
return true;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If this is a function template and none of its specializations is used,
+ // we should warn.
+ if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate())
+ for (const auto *Spec : Template->specializations())
+ if (ShouldRemoveFromUnused(SemaRef, Spec))
+ return true;
+
// UnusedFileScopedDecls stores the first declaration.
// The declaration may have become definition so check again.
const FunctionDecl *DeclToCheck;
@@ -492,6 +571,13 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
VD->isUsableInConstantExpressions(SemaRef->Context))
return true;
+ if (VarTemplateDecl *Template = VD->getDescribedVarTemplate())
+ // If this is a variable template and none of its specializations is used,
+ // we should warn.
+ for (const auto *Spec : Template->specializations())
+ if (ShouldRemoveFromUnused(SemaRef, Spec))
+ return true;
+
// UnusedFileScopedDecls stores the first declaration.
// The declaration may have become definition so check again.
const VarDecl *DeclToCheck = VD->getDefinition();
@@ -508,6 +594,23 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
return false;
}
+static bool isFunctionOrVarDeclExternC(NamedDecl *ND) {
+ if (auto *FD = dyn_cast<FunctionDecl>(ND))
+ return FD->isExternC();
+ return cast<VarDecl>(ND)->isExternC();
+}
+
+/// Determine whether ND is an external-linkage function or variable whose
+/// type has no linkage.
+bool Sema::isExternalWithNoLinkageType(ValueDecl *VD) {
+ // Note: it's not quite enough to check whether VD has UniqueExternalLinkage,
+ // because we also want to catch the case where its type has VisibleNoLinkage,
+ // which does not affect the linkage of VD.
+ return getLangOpts().CPlusPlus && VD->hasExternalFormalLinkage() &&
+ !isExternalFormalLinkage(VD->getType()->getLinkage()) &&
+ !isFunctionOrVarDeclExternC(VD);
+}
+
/// Obtains a sorted list of functions and variables that are undefined but
/// ODR-used.
void Sema::getUndefinedButUsed(
@@ -521,17 +624,30 @@ void Sema::getUndefinedButUsed(
// __attribute__((weakref)) is basically a definition.
if (ND->hasAttr<WeakRefAttr>()) continue;
+ if (isa<CXXDeductionGuideDecl>(ND))
+ continue;
+
+ if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) {
+ // An exported function will always be emitted when defined, so even if
+ // the function is inline, it doesn't have to be emitted in this TU. An
+ // imported function implies that it has been exported somewhere else.
+ continue;
+ }
+
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (FD->isDefined())
continue;
if (FD->isExternallyVisible() &&
+ !isExternalWithNoLinkageType(FD) &&
!FD->getMostRecentDecl()->isInlined())
continue;
} else {
auto *VD = cast<VarDecl>(ND);
if (VD->hasDefinition() != VarDecl::DeclarationOnly)
continue;
- if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline())
+ if (VD->isExternallyVisible() &&
+ !isExternalWithNoLinkageType(VD) &&
+ !VD->getMostRecentDecl()->isInline())
continue;
}
@@ -549,33 +665,43 @@ static void checkUndefinedButUsed(Sema &S) {
S.getUndefinedButUsed(Undefined);
if (Undefined.empty()) return;
- for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
- I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
- NamedDecl *ND = I->first;
-
- if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) {
- // An exported function will always be emitted when defined, so even if
- // the function is inline, it doesn't have to be emitted in this TU. An
- // imported function implies that it has been exported somewhere else.
- continue;
- }
-
- if (!ND->isExternallyVisible()) {
- S.Diag(ND->getLocation(), diag::warn_undefined_internal)
- << isa<VarDecl>(ND) << ND;
- } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) {
+ for (auto Undef : Undefined) {
+ ValueDecl *VD = cast<ValueDecl>(Undef.first);
+ SourceLocation UseLoc = Undef.second;
+
+ if (S.isExternalWithNoLinkageType(VD)) {
+ // C++ [basic.link]p8:
+ // A type without linkage shall not be used as the type of a variable
+ // or function with external linkage unless
+ // -- the entity has C language linkage
+ // -- the entity is not odr-used or is defined in the same TU
+ //
+ // As an extension, accept this in cases where the type is externally
+ // visible, since the function or variable actually can be defined in
+ // another translation unit in that case.
+ S.Diag(VD->getLocation(), isExternallyVisible(VD->getType()->getLinkage())
+ ? diag::ext_undefined_internal_type
+ : diag::err_undefined_internal_type)
+ << isa<VarDecl>(VD) << VD;
+ } else if (!VD->isExternallyVisible()) {
+ // FIXME: We can promote this to an error. The function or variable can't
+ // be defined anywhere else, so the program must necessarily violate the
+ // one definition rule.
+ S.Diag(VD->getLocation(), diag::warn_undefined_internal)
+ << isa<VarDecl>(VD) << VD;
+ } else if (auto *FD = dyn_cast<FunctionDecl>(VD)) {
(void)FD;
assert(FD->getMostRecentDecl()->isInlined() &&
"used object requires definition but isn't inline or internal?");
// FIXME: This is ill-formed; we should reject.
- S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND;
+ S.Diag(VD->getLocation(), diag::warn_undefined_inline) << VD;
} else {
- assert(cast<VarDecl>(ND)->getMostRecentDecl()->isInline() &&
+ assert(cast<VarDecl>(VD)->getMostRecentDecl()->isInline() &&
"used var requires definition but isn't inline or internal?");
- S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND;
+ S.Diag(VD->getLocation(), diag::err_undefined_inline_var) << VD;
}
- if (I->second.isValid())
- S.Diag(I->second, diag::note_used_here);
+ if (UseLoc.isValid())
+ S.Diag(UseLoc, diag::note_used_here);
}
S.UndefinedButUsed.clear();
@@ -611,7 +737,8 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD,
E = RD->decls_end();
I != E && Complete; ++I) {
if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I))
- Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M));
+ Complete = M->isDefined() || M->isDefaulted() ||
+ (M->isPure() && !isa<CXXDestructorDecl>(M));
else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I))
// If the template function is marked as late template parsed at this
// point, it has not been instantiated and therefore we have not
@@ -684,6 +811,32 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() {
UnusedLocalTypedefNameCandidates.clear();
}
+/// This is called before the very first declaration in the translation unit
+/// is parsed. Note that the ASTContext may have already injected some
+/// declarations.
+void Sema::ActOnStartOfTranslationUnit() {
+ if (getLangOpts().ModulesTS) {
+ SourceLocation StartOfTU =
+ SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+
+ // We start in the global module; all those declarations are implicitly
+ // module-private (though they do not have module linkage).
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(StartOfTU);
+ assert(GlobalModule && "module creation should not fail");
+
+ // Enter the scope of the global module.
+ ModuleScopes.push_back({});
+ ModuleScopes.back().Module = GlobalModule;
+ VisibleModules.setVisible(GlobalModule, StartOfTU);
+
+ // All declarations created from now on are owned by the global module.
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+ TU->setLocalOwningModule(GlobalModule);
+ }
+}
+
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
@@ -719,6 +872,9 @@ void Sema::ActOnEndOfTranslationUnit() {
// Load pending instantiations from the external source.
SmallVector<PendingImplicitInstantiation, 4> Pending;
ExternalSource->ReadPendingInstantiations(Pending);
+ for (auto PII : Pending)
+ if (auto Func = dyn_cast<FunctionDecl>(PII.first))
+ Func->setInstantiationIsPending(true);
PendingInstantiations.insert(PendingInstantiations.begin(),
Pending.begin(), Pending.end());
}
@@ -730,6 +886,9 @@ void Sema::ActOnEndOfTranslationUnit() {
CheckDelayedMemberExceptionSpecs();
}
+ DiagnoseUnterminatedPragmaPack();
+ DiagnoseUnterminatedPragmaAttribute();
+
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
// FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to
@@ -744,7 +903,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) {
@@ -782,6 +943,17 @@ void Sema::ActOnEndOfTranslationUnit() {
}
if (TUKind == TU_Module) {
+ // If we are building a module interface unit, we need to have seen the
+ // module declaration by now.
+ if (getLangOpts().getCompilingModule() ==
+ LangOptions::CMK_ModuleInterface &&
+ ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) {
+ // FIXME: Make a better guess as to where to put the module declaration.
+ Diag(getSourceManager().getLocForStartOfFile(
+ getSourceManager().getMainFileID()),
+ diag::err_module_declaration_missing);
+ }
+
// If we are building a module, resolve all of the exported declarations
// now.
if (Module *CurrentModule = PP.getCurrentModule()) {
@@ -810,7 +982,8 @@ void Sema::ActOnEndOfTranslationUnit() {
emitAndClearUnusedLocalTypedefWarnings();
// Modules don't need any of the checking below.
- TUScope = nullptr;
+ if (!PP.isIncrementalProcessingEnabled())
+ TUScope = nullptr;
return;
}
@@ -893,10 +1066,14 @@ void Sema::ActOnEndOfTranslationUnit() {
<< /*function*/0 << DiagD->getDeclName();
}
} else {
- Diag(DiagD->getLocation(),
- isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
- : diag::warn_unused_function)
- << DiagD->getDeclName();
+ if (FD->getDescribedFunctionTemplate())
+ Diag(DiagD->getLocation(), diag::warn_unused_template)
+ << /*function*/0 << DiagD->getDeclName();
+ else
+ Diag(DiagD->getLocation(),
+ isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
+ : diag::warn_unused_function)
+ << DiagD->getDeclName();
}
} else {
const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition();
@@ -912,7 +1089,11 @@ void Sema::ActOnEndOfTranslationUnit() {
Diag(DiagD->getLocation(), diag::warn_unused_const_variable)
<< DiagD->getDeclName();
} else {
- Diag(DiagD->getLocation(), diag::warn_unused_variable)
+ if (DiagD->getDescribedVarTemplate())
+ Diag(DiagD->getLocation(), diag::warn_unused_template)
+ << /*variable*/1 << DiagD->getDeclName();
+ else
+ Diag(DiagD->getLocation(), diag::warn_unused_variable)
<< DiagD->getDeclName();
}
}
@@ -1163,10 +1344,14 @@ void Sema::PushFunctionScope() {
// memory for a new scope.
FunctionScopes.back()->Clear();
FunctionScopes.push_back(FunctionScopes.back());
+ if (LangOpts.OpenMP)
+ pushOpenMPFunctionRegion();
return;
}
FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics()));
+ if (LangOpts.OpenMP)
+ pushOpenMPFunctionRegion();
}
void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
@@ -1194,6 +1379,9 @@ void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");
+ if (LangOpts.OpenMP)
+ popOpenMPFunctionRegion(Scope);
+
// Issue any analysis-based warnings.
if (WP && D)
AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
@@ -1645,7 +1833,8 @@ bool Sema::checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType QT) {
QT, OpenCLTypeExtMap);
}
-bool Sema::checkOpenCLDisabledDecl(const Decl &D, const Expr &E) {
- return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), "",
+bool Sema::checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E) {
+ IdentifierInfo *FnName = D.getIdentifier();
+ return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), FnName,
OpenCLDeclExtMap, 1, D.getSourceRange());
}
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index bad9e70242..4ba2a317e1 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -61,6 +61,17 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
Alignment * 8));
}
+ if (PackIncludeStack.empty())
+ return;
+ // The #pragma pack affected a record in an included file, so Clang should
+ // warn when that pragma was written in a file that included the included
+ // file.
+ for (auto &PackedInclude : llvm::reverse(PackIncludeStack)) {
+ if (PackedInclude.CurrentPragmaLocation != PackStack.CurrentPragmaLocation)
+ break;
+ if (PackedInclude.HasNonDefaultValue)
+ PackedInclude.ShouldWarnOnInclude = true;
+ }
}
void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
@@ -126,6 +137,36 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
PackStack.Act(PragmaLoc, Action, StringRef(), Alignment);
}
+void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action,
+ PragmaClangSectionKind SecKind, StringRef SecName) {
+ PragmaClangSection *CSec;
+ switch (SecKind) {
+ case PragmaClangSectionKind::PCSK_BSS:
+ CSec = &PragmaClangBSSSection;
+ break;
+ case PragmaClangSectionKind::PCSK_Data:
+ CSec = &PragmaClangDataSection;
+ break;
+ case PragmaClangSectionKind::PCSK_Rodata:
+ CSec = &PragmaClangRodataSection;
+ break;
+ case PragmaClangSectionKind::PCSK_Text:
+ CSec = &PragmaClangTextSection;
+ break;
+ default:
+ llvm_unreachable("invalid clang section kind");
+ }
+
+ if (Action == PragmaClangSectionAction::PCSA_Clear) {
+ CSec->Valid = false;
+ return;
+ }
+
+ CSec->Valid = true;
+ CSec->SectionName = SecName;
+ CSec->PragmaLocation = PragmaLoc;
+}
+
void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
StringRef SlotLabel, Expr *alignment) {
Expr *Alignment = static_cast<Expr *>(alignment);
@@ -172,6 +213,61 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
}
+void Sema::DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
+ SourceLocation IncludeLoc) {
+ if (Kind == PragmaPackDiagnoseKind::NonDefaultStateAtInclude) {
+ SourceLocation PrevLocation = PackStack.CurrentPragmaLocation;
+ // Warn about non-default alignment at #includes (without redundant
+ // warnings for the same directive in nested includes).
+ // The warning is delayed until the end of the file to avoid warnings
+ // for files that don't have any records that are affected by the modified
+ // alignment.
+ bool HasNonDefaultValue =
+ PackStack.hasValue() &&
+ (PackIncludeStack.empty() ||
+ PackIncludeStack.back().CurrentPragmaLocation != PrevLocation);
+ PackIncludeStack.push_back(
+ {PackStack.CurrentValue,
+ PackStack.hasValue() ? PrevLocation : SourceLocation(),
+ HasNonDefaultValue, /*ShouldWarnOnInclude*/ false});
+ return;
+ }
+
+ assert(Kind == PragmaPackDiagnoseKind::ChangedStateAtExit && "invalid kind");
+ PackIncludeState PrevPackState = PackIncludeStack.pop_back_val();
+ if (PrevPackState.ShouldWarnOnInclude) {
+ // Emit the delayed non-default alignment at #include warning.
+ Diag(IncludeLoc, diag::warn_pragma_pack_non_default_at_include);
+ Diag(PrevPackState.CurrentPragmaLocation, diag::note_pragma_pack_here);
+ }
+ // Warn about modified alignment after #includes.
+ if (PrevPackState.CurrentValue != PackStack.CurrentValue) {
+ Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include);
+ Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here);
+ }
+}
+
+void Sema::DiagnoseUnterminatedPragmaPack() {
+ if (PackStack.Stack.empty())
+ return;
+ bool IsInnermost = true;
+ for (const auto &StackSlot : llvm::reverse(PackStack.Stack)) {
+ Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof);
+ // The user might have already reset the alignment, so suggest replacing
+ // the reset with a pop.
+ if (IsInnermost && PackStack.CurrentValue == PackStack.DefaultValue) {
+ DiagnosticBuilder DB = Diag(PackStack.CurrentPragmaLocation,
+ diag::note_pragma_pack_pop_instead_reset);
+ SourceLocation FixItLoc = Lexer::findLocationAfterToken(
+ PackStack.CurrentPragmaLocation, tok::l_paren, SourceMgr, LangOpts,
+ /*SkipTrailing=*/false);
+ if (FixItLoc.isValid())
+ DB << FixItHint::CreateInsertion(FixItLoc, "pop");
+ }
+ IsInnermost = false;
+ }
+}
+
void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
MSStructPragmaOn = (Kind == PMSST_ON);
}
@@ -215,10 +311,12 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
ValueType Value) {
if (Action == PSK_Reset) {
CurrentValue = DefaultValue;
+ CurrentPragmaLocation = PragmaLocation;
return;
}
if (Action & PSK_Push)
- Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation));
+ Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation,
+ PragmaLocation);
else if (Action & PSK_Pop) {
if (!StackSlotLabel.empty()) {
// If we've got a label, try to find it and jump there.
@@ -367,6 +465,219 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
}
+namespace {
+
+Optional<attr::SubjectMatchRule>
+getParentAttrMatcherRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+ default:
+ return None;
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
+#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
+ case Value: \
+ return Parent;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+}
+
+bool isNegatedAttrMatcherSubRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+ default:
+ return false;
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
+#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
+ case Value: \
+ return IsNegated;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+}
+
+CharSourceRange replacementRangeForListElement(const Sema &S,
+ SourceRange Range) {
+ // Make sure that the ',' is removed as well.
+ SourceLocation AfterCommaLoc = Lexer::findLocationAfterToken(
+ Range.getEnd(), tok::comma, S.getSourceManager(), S.getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/false);
+ if (AfterCommaLoc.isValid())
+ return CharSourceRange::getCharRange(Range.getBegin(), AfterCommaLoc);
+ else
+ return CharSourceRange::getTokenRange(Range);
+}
+
+std::string
+attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ for (const auto &I : llvm::enumerate(Rules)) {
+ if (I.index())
+ OS << (I.index() == Rules.size() - 1 ? ", and " : ", ");
+ OS << "'" << attr::getSubjectMatchRuleSpelling(I.value()) << "'";
+ }
+ return OS.str();
+}
+
+} // end anonymous namespace
+
+void Sema::ActOnPragmaAttributePush(AttributeList &Attribute,
+ SourceLocation PragmaLoc,
+ attr::ParsedSubjectMatchRuleSet Rules) {
+ SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules;
+ // Gather the subject match rules that are supported by the attribute.
+ SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4>
+ StrictSubjectMatchRuleSet;
+ Attribute.getMatchRules(LangOpts, StrictSubjectMatchRuleSet);
+
+ // Figure out which subject matching rules are valid.
+ if (StrictSubjectMatchRuleSet.empty()) {
+ // Check for contradicting match rules. Contradicting match rules are
+ // either:
+ // - a top-level rule and one of its sub-rules. E.g. variable and
+ // variable(is_parameter).
+ // - a sub-rule and a sibling that's negated. E.g.
+ // variable(is_thread_local) and variable(unless(is_parameter))
+ llvm::SmallDenseMap<int, std::pair<int, SourceRange>, 2>
+ RulesToFirstSpecifiedNegatedSubRule;
+ for (const auto &Rule : Rules) {
+ attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
+ Optional<attr::SubjectMatchRule> ParentRule =
+ getParentAttrMatcherRule(MatchRule);
+ if (!ParentRule)
+ continue;
+ auto It = Rules.find(*ParentRule);
+ if (It != Rules.end()) {
+ // A sub-rule contradicts a parent rule.
+ Diag(Rule.second.getBegin(),
+ diag::err_pragma_attribute_matcher_subrule_contradicts_rule)
+ << attr::getSubjectMatchRuleSpelling(MatchRule)
+ << attr::getSubjectMatchRuleSpelling(*ParentRule) << It->second
+ << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, Rule.second));
+ // Keep going without removing this rule as it won't change the set of
+ // declarations that receive the attribute.
+ continue;
+ }
+ if (isNegatedAttrMatcherSubRule(MatchRule))
+ RulesToFirstSpecifiedNegatedSubRule.insert(
+ std::make_pair(*ParentRule, Rule));
+ }
+ bool IgnoreNegatedSubRules = false;
+ for (const auto &Rule : Rules) {
+ attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
+ Optional<attr::SubjectMatchRule> ParentRule =
+ getParentAttrMatcherRule(MatchRule);
+ if (!ParentRule)
+ continue;
+ auto It = RulesToFirstSpecifiedNegatedSubRule.find(*ParentRule);
+ if (It != RulesToFirstSpecifiedNegatedSubRule.end() &&
+ It->second != Rule) {
+ // Negated sub-rule contradicts another sub-rule.
+ Diag(
+ It->second.second.getBegin(),
+ diag::
+ err_pragma_attribute_matcher_negated_subrule_contradicts_subrule)
+ << attr::getSubjectMatchRuleSpelling(
+ attr::SubjectMatchRule(It->second.first))
+ << attr::getSubjectMatchRuleSpelling(MatchRule) << Rule.second
+ << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, It->second.second));
+ // Keep going but ignore all of the negated sub-rules.
+ IgnoreNegatedSubRules = true;
+ RulesToFirstSpecifiedNegatedSubRule.erase(It);
+ }
+ }
+
+ if (!IgnoreNegatedSubRules) {
+ for (const auto &Rule : Rules)
+ SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
+ } else {
+ for (const auto &Rule : Rules) {
+ if (!isNegatedAttrMatcherSubRule(attr::SubjectMatchRule(Rule.first)))
+ SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
+ }
+ }
+ Rules.clear();
+ } else {
+ for (const auto &Rule : StrictSubjectMatchRuleSet) {
+ if (Rules.erase(Rule.first)) {
+ // Add the rule to the set of attribute receivers only if it's supported
+ // in the current language mode.
+ if (Rule.second)
+ SubjectMatchRules.push_back(Rule.first);
+ }
+ }
+ }
+
+ if (!Rules.empty()) {
+ auto Diagnostic =
+ Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers)
+ << Attribute.getName();
+ SmallVector<attr::SubjectMatchRule, 2> ExtraRules;
+ for (const auto &Rule : Rules) {
+ ExtraRules.push_back(attr::SubjectMatchRule(Rule.first));
+ Diagnostic << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, Rule.second));
+ }
+ Diagnostic << attrMatcherRuleListToString(ExtraRules);
+ }
+
+ PragmaAttributeStack.push_back(
+ {PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false});
+}
+
+void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc) {
+ if (PragmaAttributeStack.empty()) {
+ Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch);
+ return;
+ }
+ const PragmaAttributeEntry &Entry = PragmaAttributeStack.back();
+ if (!Entry.IsUsed) {
+ assert(Entry.Attribute && "Expected an attribute");
+ Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
+ << Entry.Attribute->getName();
+ Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
+ }
+ PragmaAttributeStack.pop_back();
+}
+
+void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
+ if (PragmaAttributeStack.empty())
+ return;
+ for (auto &Entry : PragmaAttributeStack) {
+ const AttributeList *Attribute = Entry.Attribute;
+ assert(Attribute && "Expected an attribute");
+
+ // Ensure that the attribute can be applied to the given declaration.
+ bool Applies = false;
+ for (const auto &Rule : Entry.MatchRules) {
+ if (Attribute->appliesToDecl(D, Rule)) {
+ Applies = true;
+ break;
+ }
+ }
+ if (!Applies)
+ continue;
+ Entry.IsUsed = true;
+ assert(!Attribute->getNext() && "Expected just one attribute");
+ PragmaAttributeCurrentTargetDecl = D;
+ ProcessDeclAttributeList(S, D, Attribute);
+ PragmaAttributeCurrentTargetDecl = nullptr;
+ }
+}
+
+void Sema::PrintPragmaAttributeInstantiationPoint() {
+ assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration");
+ Diags.Report(PragmaAttributeCurrentTargetDecl->getLocStart(),
+ diag::note_pragma_attribute_applied_decl_here);
+}
+
+void Sema::DiagnoseUnterminatedPragmaAttribute() {
+ if (PragmaAttributeStack.empty())
+ return;
+ Diag(PragmaAttributeStack.back().Loc, diag::err_pragma_attribute_no_pop_eof);
+}
+
void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
if(On)
OptimizeOffPragmaLocation = SourceLocation();
@@ -447,16 +758,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 b938ac387c..cac5f68227 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/lib/Sema/SemaCUDA.cpp
@@ -629,12 +629,6 @@ static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) {
// emitted, because (say) the definition could include "inline".
FunctionDecl *Def = FD->getDefinition();
- // We may currently be parsing the body of FD, in which case
- // FD->getDefinition() will be null, but we still want to treat FD as though
- // it's a definition.
- if (!Def && FD->willHaveBody())
- Def = FD;
-
if (Def &&
!isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
return true;
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index ee4317fe88..6da4d2a261 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,17 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
/// scope if it *knows* that the result is correct. It should not return in a
/// dependent context, for example. Nor will it extend \p SS with the scope
/// specifier.
-bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
- NestedNameSpecInfo &IdInfo,
- bool EnteringContext,
- CXXScopeSpec &SS,
+bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
+ bool EnteringContext, CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon) {
+ bool *IsCorrectedToColon,
+ bool OnlyNamespace) {
+ if (IdInfo.Identifier->isEditorPlaceholder())
+ return true;
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
- LookupNestedNameSpecifierName);
+ OnlyNamespace ? LookupNamespaceName
+ : LookupNestedNameSpecifierName);
QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType);
// Determine where to perform name lookup
@@ -594,7 +597,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
return true;
}
// Replacement '::' -> ':' is not allowed, just issue respective error.
- Diag(R.getNameLoc(), diag::err_expected_class_or_namespace)
+ Diag(R.getNameLoc(), OnlyNamespace
+ ? unsigned(diag::err_expected_namespace_name)
+ : unsigned(diag::err_expected_class_or_namespace))
<< IdInfo.Identifier << getLangOpts().CPlusPlus;
if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
Diag(ND->getLocation(), diag::note_entity_declared_at)
@@ -819,19 +824,17 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
return true;
}
-bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- NestedNameSpecInfo &IdInfo,
- bool EnteringContext,
- CXXScopeSpec &SS,
+bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
+ bool EnteringContext, CXXScopeSpec &SS,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon) {
+ bool *IsCorrectedToColon,
+ bool OnlyNamespace) {
if (SS.isInvalid())
return true;
- return BuildCXXNestedNameSpecifier(S, IdInfo,
- EnteringContext, SS,
+ return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
/*ScopeLookupResult=*/nullptr, false,
- IsCorrectedToColon);
+ IsCorrectedToColon, OnlyNamespace);
}
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 39e85e76d6..ad6348685b 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;
}
@@ -143,6 +143,9 @@ namespace {
};
}
+static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType);
+
// The Try functions attempt a specific way of casting. If they succeed, they
// return TC_Success. If their way of casting is not appropriate for the given
// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic
@@ -427,6 +430,10 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
/// the same kind of pointer (plain or to-member). Unlike the Sema function,
/// this one doesn't care if the two pointers-to-member don't point into the
/// same class. This is because CastsAwayConstness doesn't care.
+/// And additionally, it handles C++ references. If both the types are
+/// references, then their pointee types are returned,
+/// else if only one of them is reference, it's pointee type is returned,
+/// and the other type is returned as-is.
static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
const PointerType *T1PtrType = T1->getAs<PointerType>(),
*T2PtrType = T2->getAs<PointerType>();
@@ -475,6 +482,26 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
return true;
}
+ const LValueReferenceType *T1RefType = T1->getAs<LValueReferenceType>(),
+ *T2RefType = T2->getAs<LValueReferenceType>();
+ if (T1RefType && T2RefType) {
+ T1 = T1RefType->getPointeeType();
+ T2 = T2RefType->getPointeeType();
+ return true;
+ }
+
+ if (T1RefType) {
+ T1 = T1RefType->getPointeeType();
+ // T2 = T2;
+ return true;
+ }
+
+ if (T2RefType) {
+ // T1 = T1;
+ T2 = T2RefType->getPointeeType();
+ return true;
+ }
+
return false;
}
@@ -503,11 +530,13 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
// the rules are non-trivial. So first we construct Tcv *...cv* as described
// in C++ 5.2.11p8.
assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() ||
- SrcType->isBlockPointerType()) &&
+ SrcType->isBlockPointerType() ||
+ DestType->isLValueReferenceType()) &&
"Source type is not pointer or pointer to member.");
assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() ||
- DestType->isBlockPointerType()) &&
- "Destination type is not pointer or pointer to member.");
+ DestType->isBlockPointerType() ||
+ DestType->isLValueReferenceType()) &&
+ "Destination type is not pointer or pointer to member, or reference.");
QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
UnwrappedDestType = Self.Context.getCanonicalType(DestType);
@@ -523,7 +552,14 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
Qualifiers SrcQuals, DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
-
+
+ // We do not meaningfully track object const-ness of Objective-C object
+ // types. Remove const from the source type if either the source or
+ // the destination is an Objective-C object type.
+ if (UnwrappedSrcType->isObjCObjectType() ||
+ UnwrappedDestType->isObjCObjectType())
+ SrcQuals.removeConst();
+
Qualifiers RetainedSrcQuals, RetainedDestQuals;
if (CheckCVR) {
RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
@@ -871,8 +907,8 @@ void CastOperation::CheckReinterpretCast() {
}
SrcExpr = ExprError();
} else if (tcr == TC_Success) {
- if (Self.getLangOpts().ObjCAutoRefCount)
- checkObjCARCConversion(Sema::CCK_OtherCast);
+ if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
+ checkObjCConversion(Sema::CCK_OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
}
}
@@ -935,8 +971,8 @@ void CastOperation::CheckStaticCast() {
} else if (tcr == TC_Success) {
if (Kind == CK_BitCast)
checkCastAlign();
- if (Self.getLangOpts().ObjCAutoRefCount)
- checkObjCARCConversion(Sema::CCK_OtherCast);
+ if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
+ checkObjCConversion(Sema::CCK_OtherCast);
} else if (Kind == CK_BitCast) {
checkCastAlign();
}
@@ -1871,7 +1907,8 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
// No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
// preserves Result.
Result = E;
- if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+ if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ Result, /*DoFunctionPointerConversion=*/true))
return false;
return Result.isUsable();
}
@@ -2176,6 +2213,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
bool ListInitialization) {
+ assert(Self.getLangOpts().CPlusPlus);
+
// Handle placeholders.
if (isPlaceholder()) {
// C-style casts can resolve __unknown_any types.
@@ -2272,8 +2311,9 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
}
}
- if (Self.getLangOpts().ObjCAutoRefCount && tcr == TC_Success)
- checkObjCARCConversion(CCK);
+ if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
+ tcr == TC_Success)
+ checkObjCConversion(CCK);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
@@ -2418,24 +2458,17 @@ void CastOperation::CheckCStyleCast() {
// GCC's cast to union extension.
if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) {
RecordDecl *RD = DestRecordTy->getDecl();
- RecordDecl::field_iterator Field, FieldEnd;
- for (Field = RD->field_begin(), FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field) {
- if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) &&
- !Field->isUnnamedBitfield()) {
- Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union)
- << SrcExpr.get()->getSourceRange();
- break;
- }
- }
- if (Field == FieldEnd) {
+ if (CastExpr::getTargetFieldForToUnionCast(RD, SrcType)) {
+ Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union)
+ << SrcExpr.get()->getSourceRange();
+ Kind = CK_ToUnion;
+ return;
+ } else {
Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< SrcType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
- Kind = CK_ToUnion;
- return;
}
// OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type.
@@ -2539,12 +2572,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();
@@ -2577,30 +2611,42 @@ void CastOperation::CheckCStyleCast() {
if (Kind == CK_BitCast)
checkCastAlign();
+}
+
+/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either
+/// const, volatile or both.
+static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType) {
+ if (SrcExpr.isInvalid())
+ return;
+
+ QualType SrcType = SrcExpr.get()->getType();
+ if (!((SrcType->isAnyPointerType() && DestType->isAnyPointerType()) ||
+ DestType->isLValueReferenceType()))
+ return;
- // -Wcast-qual
QualType TheOffendingSrcType, TheOffendingDestType;
Qualifiers CastAwayQualifiers;
- if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() &&
- CastsAwayConstness(Self, SrcType, DestType, true, false,
- &TheOffendingSrcType, &TheOffendingDestType,
- &CastAwayQualifiers)) {
- int qualifiers = -1;
- if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) {
- qualifiers = 0;
- } else if (CastAwayQualifiers.hasConst()) {
- qualifiers = 1;
- } else if (CastAwayQualifiers.hasVolatile()) {
- qualifiers = 2;
- }
- // This is a variant of int **x; const int **y = (const int **)x;
- if (qualifiers == -1)
- Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) <<
- SrcType << DestType;
- else
- Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) <<
- TheOffendingSrcType << TheOffendingDestType << qualifiers;
- }
+ if (!CastsAwayConstness(Self, SrcType, DestType, true, false,
+ &TheOffendingSrcType, &TheOffendingDestType,
+ &CastAwayQualifiers))
+ return;
+
+ int qualifiers = -1;
+ if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) {
+ qualifiers = 0;
+ } else if (CastAwayQualifiers.hasConst()) {
+ qualifiers = 1;
+ } else if (CastAwayQualifiers.hasVolatile()) {
+ qualifiers = 2;
+ }
+ // This is a variant of int **x; const int **y = (const int **)x;
+ if (qualifiers == -1)
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2)
+ << SrcType << DestType;
+ else
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual)
+ << TheOffendingSrcType << TheOffendingDestType << qualifiers;
}
ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
@@ -2621,6 +2667,9 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
if (Op.SrcExpr.isInvalid())
return ExprError();
+ // -Wcast-qual
+ DiagnoseCastQual(Op.Self, Op.SrcExpr, Op.DestType);
+
return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, CastTypeInfo, LPLoc, RPLoc));
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 9858244d56..53e710d7b7 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/SyncScope.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
@@ -98,6 +99,28 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
return false;
}
+static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) {
+ // We need at least one argument.
+ if (TheCall->getNumArgs() < 1) {
+ S.Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return true;
+ }
+
+ // All arguments should be wide string literals.
+ for (Expr *Arg : TheCall->arguments()) {
+ auto *Literal = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
+ if (!Literal || !Literal->isWide()) {
+ S.Diag(Arg->getLocStart(), diag::err_msvc_annotation_wide_str)
+ << Arg->getSourceRange();
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Check that the argument to __builtin_addressof is a glvalue, and set the
/// result type to the corresponding pointer type.
static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
@@ -299,6 +322,41 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) {
return IllegalParams;
}
+static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) {
+ if (!S.getOpenCLOptions().isEnabled("cl_khr_subgroups")) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_requires_extension)
+ << 1 << Call->getDirectCallee() << "cl_khr_subgroups";
+ return true;
+ }
+ return false;
+}
+
+static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) {
+ if (checkArgCount(S, TheCall, 2))
+ return true;
+
+ if (checkOpenCLSubgroupExt(S, TheCall))
+ return true;
+
+ // First argument is an ndrange_t type.
+ Expr *NDRangeArg = TheCall->getArg(0);
+ if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") {
+ S.Diag(NDRangeArg->getLocStart(),
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "'ndrange_t'";
+ return true;
+ }
+
+ Expr *BlockArg = TheCall->getArg(1);
+ if (!isBlockPointer(BlockArg)) {
+ S.Diag(BlockArg->getLocStart(),
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
+ return true;
+ }
+ return checkOpenCLBlockArgs(S, BlockArg);
+}
+
/// OpenCL C v2.0, s6.13.17.6 - Check the argument to the
/// get_kernel_work_group_size
/// and get_kernel_preferred_work_group_size_multiple builtin functions.
@@ -309,13 +367,14 @@ static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) {
Expr *BlockArg = TheCall->getArg(0);
if (!isBlockPointer(BlockArg)) {
S.Diag(BlockArg->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type) << "block";
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
return true;
}
return checkOpenCLBlockArgs(S, BlockArg);
}
-/// Diagnose integer type and any valid implicit convertion to it.
+/// Diagnose integer type and any valid implicit conversion to it.
static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E,
const QualType &IntType);
@@ -394,24 +453,24 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// First argument always needs to be a queue_t type.
if (!Arg0->getType()->isQueueT()) {
S.Diag(TheCall->getArg(0)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << S.Context.OCLQueueTy;
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << S.Context.OCLQueueTy;
return true;
}
// Second argument always needs to be a kernel_enqueue_flags_t enum value.
if (!Arg1->getType()->isIntegerType()) {
S.Diag(TheCall->getArg(1)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << "'kernel_enqueue_flags_t' (i.e. uint)";
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "'kernel_enqueue_flags_t' (i.e. uint)";
return true;
}
// Third argument is always an ndrange_t type.
- if (Arg2->getType().getAsString() != "ndrange_t") {
+ if (Arg2->getType().getUnqualifiedType().getAsString() != "ndrange_t") {
S.Diag(TheCall->getArg(2)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << "'ndrange_t'";
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "'ndrange_t'";
return true;
}
@@ -420,8 +479,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
if (NumArgs == 4) {
// check that the last argument is the right block type.
if (!isBlockPointer(Arg3)) {
- S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type)
- << "block";
+ S.Diag(Arg3->getLocStart(), diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
return true;
}
// we have a block type, check the prototype
@@ -443,8 +502,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// check common block argument.
Expr *Arg6 = TheCall->getArg(6);
if (!isBlockPointer(Arg6)) {
- S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type)
- << "block";
+ S.Diag(Arg6->getLocStart(), diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
return true;
}
if (checkOpenCLBlockArgs(S, Arg6))
@@ -453,8 +512,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// Forth argument has to be any integer type.
if (!Arg3->getType()->isIntegerType()) {
S.Diag(TheCall->getArg(3)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << "integer";
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "integer";
return true;
}
// check remaining common arguments.
@@ -466,7 +525,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
Expr::NPC_ValueDependentIsNotNull) &&
!Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) {
S.Diag(TheCall->getArg(4)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee()
<< S.Context.getPointerType(S.Context.OCLClkEventTy);
return true;
}
@@ -477,7 +537,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
!(Arg5->getType()->isPointerType() &&
Arg5->getType()->getPointeeType()->isClkEventT())) {
S.Diag(TheCall->getArg(5)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee()
<< S.Context.getPointerType(S.Context.OCLClkEventTy);
return true;
}
@@ -644,6 +705,11 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) {
return true;
}
+ // Since return type of reserve_read/write_pipe built-in function is
+ // reserve_id_t, which is not defined in the builtin def file , we used int
+ // as return type and need to override the return type of these functions.
+ Call->setType(S.Context.OCLReserveIDTy);
+
return false;
}
@@ -718,8 +784,11 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID,
case Builtin::BIto_local:
Qual.setAddressSpace(LangAS::opencl_local);
break;
+ case Builtin::BIto_private:
+ Qual.setAddressSpace(LangAS::opencl_private);
+ break;
default:
- Qual.removeAddressSpace();
+ llvm_unreachable("Invalid builtin function");
}
Call->setType(S.Context.getPointerType(S.Context.getQualifiedType(
RT.getUnqualifiedType(), Qual)));
@@ -757,20 +826,21 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (CheckObjCString(TheCall->getArg(0)))
return ExprError();
break;
+ case Builtin::BI__builtin_ms_va_start:
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
- if (SemaBuiltinVAStart(TheCall))
+ if (SemaBuiltinVAStart(BuiltinID, TheCall))
return ExprError();
break;
case Builtin::BI__va_start: {
switch (Context.getTargetInfo().getTriple().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
- if (SemaBuiltinVAStartARM(TheCall))
+ if (SemaBuiltinVAStartARMMicrosoft(TheCall))
return ExprError();
break;
default:
- if (SemaBuiltinVAStart(TheCall))
+ if (SemaBuiltinVAStart(BuiltinID, TheCall))
return ExprError();
break;
}
@@ -955,6 +1025,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI##ID: \
return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID);
#include "clang/Basic/Builtins.def"
+ case Builtin::BI__annotation:
+ if (SemaBuiltinMSVCAnnotation(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_annotation:
if (SemaBuiltinAnnotation(*this, TheCall))
return ExprError();
@@ -1044,22 +1118,26 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BIreserve_write_pipe:
case Builtin::BIwork_group_reserve_read_pipe:
case Builtin::BIwork_group_reserve_write_pipe:
+ if (SemaBuiltinReserveRWPipe(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BIsub_group_reserve_read_pipe:
case Builtin::BIsub_group_reserve_write_pipe:
- if (SemaBuiltinReserveRWPipe(*this, TheCall))
+ if (checkOpenCLSubgroupExt(*this, TheCall) ||
+ SemaBuiltinReserveRWPipe(*this, TheCall))
return ExprError();
- // Since return type of reserve_read/write_pipe built-in function is
- // reserve_id_t, which is not defined in the builtin def file , we used int
- // as return type and need to override the return type of these functions.
- TheCall->setType(Context.OCLReserveIDTy);
break;
case Builtin::BIcommit_read_pipe:
case Builtin::BIcommit_write_pipe:
case Builtin::BIwork_group_commit_read_pipe:
case Builtin::BIwork_group_commit_write_pipe:
+ if (SemaBuiltinCommitRWPipe(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BIsub_group_commit_read_pipe:
case Builtin::BIsub_group_commit_write_pipe:
- if (SemaBuiltinCommitRWPipe(*this, TheCall))
+ if (checkOpenCLSubgroupExt(*this, TheCall) ||
+ SemaBuiltinCommitRWPipe(*this, TheCall))
return ExprError();
break;
case Builtin::BIget_pipe_num_packets:
@@ -1084,6 +1162,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall))
return ExprError();
break;
+ break;
+ case Builtin::BIget_kernel_max_sub_group_size_for_ndrange:
+ case Builtin::BIget_kernel_sub_group_count_for_ndrange:
+ if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_os_log_format:
case Builtin::BI__builtin_os_log_format_buffer_size:
if (SemaBuiltinOSLogFormat(TheCall)) {
@@ -1391,8 +1475,6 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
}
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
- llvm::APSInt Result;
-
if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
BuiltinID == ARM::BI__builtin_arm_ldaex ||
BuiltinID == ARM::BI__builtin_arm_strex ||
@@ -1439,8 +1521,6 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
- llvm::APSInt Result;
-
if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
BuiltinID == AArch64::BI__builtin_arm_ldaex ||
BuiltinID == AArch64::BI__builtin_arm_strex ||
@@ -1640,7 +1720,7 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
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;
@@ -1700,6 +1780,9 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case PPC::BI__builtin_tabortdci:
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 31);
+ case PPC::BI__builtin_vsx_xxpermdi:
+ case PPC::BI__builtin_vsx_xxsldwi:
+ return SemaBuiltinVSX(TheCall);
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
@@ -1737,9 +1820,11 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
case SystemZ::BI__builtin_s390_vfaezbs:
case SystemZ::BI__builtin_s390_vfaezhs:
case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break;
+ case SystemZ::BI__builtin_s390_vfisb:
case SystemZ::BI__builtin_s390_vfidb:
return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 15);
+ case SystemZ::BI__builtin_s390_vftcisb:
case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break;
case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break;
case SystemZ::BI__builtin_s390_vpdi: i = 2; l = 0; u = 15; break;
@@ -1756,6 +1841,11 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
case SystemZ::BI__builtin_s390_vstrczbs:
case SystemZ::BI__builtin_s390_vstrczhs:
case SystemZ::BI__builtin_s390_vstrczfs: i = 3; l = 0; u = 15; break;
+ case SystemZ::BI__builtin_s390_vmslg: i = 3; l = 0; u = 15; break;
+ case SystemZ::BI__builtin_s390_vfminsb:
+ case SystemZ::BI__builtin_s390_vfmaxsb:
+ case SystemZ::BI__builtin_s390_vfmindb:
+ case SystemZ::BI__builtin_s390_vfmaxdb: i = 2; l = 0; u = 15; break;
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
@@ -1780,6 +1870,26 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) {
return false;
}
+/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *).
+/// This checks that the target supports __builtin_cpu_is and
+/// that the string argument is constant and valid.
+static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) {
+ Expr *Arg = TheCall->getArg(0);
+
+ // Check if the argument is a string literal.
+ if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
+ return S.Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal)
+ << Arg->getSourceRange();
+
+ // Check the contents of the string.
+ StringRef Feature =
+ cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
+ if (!S.Context.getTargetInfo().validateCpuIs(Feature))
+ return S.Diag(TheCall->getLocStart(), diag::err_invalid_cpu_is)
+ << Arg->getSourceRange();
+ return false;
+}
+
// Check if the rounding mode is legal.
bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
// Indicates if this instruction has rounding control or just SAE.
@@ -2093,8 +2203,8 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (BuiltinID == X86::BI__builtin_cpu_supports)
return SemaBuiltinCpuSupports(*this, TheCall);
- if (BuiltinID == X86::BI__builtin_ms_va_start)
- return SemaBuiltinMSVAStart(TheCall);
+ if (BuiltinID == X86::BI__builtin_cpu_is)
+ return SemaBuiltinCpuIs(*this, TheCall);
// If the intrinsic has rounding or SAE make sure its valid.
if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall))
@@ -2308,7 +2418,7 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_scatterpfdps:
case X86::BI__builtin_ia32_scatterpfqpd:
case X86::BI__builtin_ia32_scatterpfqps:
- i = 4; l = 1; u = 2;
+ i = 4; l = 2; u = 3;
break;
case X86::BI__builtin_ia32_pcmpestrm128:
case X86::BI__builtin_ia32_pcmpestri128:
@@ -2727,15 +2837,18 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering;
switch (Op) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
llvm_unreachable("There is no ordering argument for an init");
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_load:
case AtomicExpr::AO__atomic_load_n:
case AtomicExpr::AO__atomic_load:
return OrderingCABI != llvm::AtomicOrderingCABI::release &&
OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n:
return OrderingCABI != llvm::AtomicOrderingCABI::consume &&
@@ -2752,7 +2865,9 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
- // All these operations take one of the following forms:
+ // All the non-OpenCL operations take one of the following forms.
+ // The OpenCL operations take the __c11 forms with one extra argument for
+ // synchronization scope.
enum {
// C __c11_atomic_init(A *, C)
Init,
@@ -2773,6 +2888,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// bool __atomic_compare_exchange(A *, C *, CP, bool, int, int)
GNUCmpXchg
} Form = Init;
+ const unsigned NumForm = GNUCmpXchg + 1;
const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 };
const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 };
// where:
@@ -2782,12 +2898,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// M is C if C is an integer, and ptrdiff_t if C is a pointer, and
// the int parameters are for orderings.
+ static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm
+ && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
+ "need to update code for modified forms");
static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
AtomicExpr::AO__c11_atomic_fetch_xor + 1 ==
AtomicExpr::AO__atomic_load,
"need to update code for modified C11 atomics");
- bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init &&
- Op <= AtomicExpr::AO__c11_atomic_fetch_xor;
+ bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init &&
+ Op <= AtomicExpr::AO__opencl_atomic_fetch_max;
+ bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init &&
+ Op <= AtomicExpr::AO__c11_atomic_fetch_xor) ||
+ IsOpenCL;
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
Op == AtomicExpr::AO__atomic_store_n ||
Op == AtomicExpr::AO__atomic_exchange_n ||
@@ -2796,10 +2918,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
switch (Op) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
Form = Init;
break;
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_load:
case AtomicExpr::AO__atomic_load_n:
Form = Load;
break;
@@ -2809,6 +2933,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n:
Form = Copy;
@@ -2816,6 +2941,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case AtomicExpr::AO__c11_atomic_fetch_add:
case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_add:
+ case AtomicExpr::AO__opencl_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_sub:
case AtomicExpr::AO__atomic_add_fetch:
@@ -2825,6 +2954,9 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_and:
+ case AtomicExpr::AO__opencl_atomic_fetch_or:
+ case AtomicExpr::AO__opencl_atomic_fetch_xor:
case AtomicExpr::AO__atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_xor:
@@ -2837,6 +2969,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__opencl_atomic_exchange:
case AtomicExpr::AO__atomic_exchange_n:
Form = Xchg;
break;
@@ -2847,6 +2980,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
Form = C11CmpXchg;
break;
@@ -2856,16 +2991,19 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
}
+ unsigned AdjustedNumArgs = NumArgs[Form];
+ if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init)
+ ++AdjustedNumArgs;
// Check we have the right number of arguments.
- if (TheCall->getNumArgs() < NumArgs[Form]) {
+ if (TheCall->getNumArgs() < AdjustedNumArgs) {
Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 << NumArgs[Form] << TheCall->getNumArgs()
+ << 0 << AdjustedNumArgs << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
- } else if (TheCall->getNumArgs() > NumArgs[Form]) {
- Diag(TheCall->getArg(NumArgs[Form])->getLocStart(),
+ } else if (TheCall->getNumArgs() > AdjustedNumArgs) {
+ Diag(TheCall->getArg(AdjustedNumArgs)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 << NumArgs[Form] << TheCall->getNumArgs()
+ << 0 << AdjustedNumArgs << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
}
@@ -2893,9 +3031,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
- if (AtomTy.isConstQualified()) {
+ if (AtomTy.isConstQualified() ||
+ AtomTy.getAddressSpace() == LangAS::opencl_constant) {
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic)
- << Ptr->getType() << Ptr->getSourceRange();
+ << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType()
+ << Ptr->getSourceRange();
return ExprError();
}
ValType = AtomTy->getAs<AtomicType>()->getValueType();
@@ -2964,7 +3104,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
ValType.removeLocalVolatile();
ValType.removeLocalConst();
QualType ResultType = ValType;
- if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init)
+ if (Form == Copy || Form == LoadCopy || Form == GNUXchg ||
+ Form == Init)
ResultType = Context.VoidTy;
else if (Form == C11CmpXchg || Form == GNUCmpXchg)
ResultType = Context.BoolTy;
@@ -2978,7 +3119,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
- for (unsigned i = 1; i != NumArgs[Form]; ++i) {
+ for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) {
QualType Ty;
if (i < NumVals[Form] + 1) {
switch (i) {
@@ -2999,7 +3140,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// Treat this argument as _Nonnull as we want to show a warning if
// NULL is passed into it.
CheckNonNullArgument(*this, ValArg, DRE->getLocStart());
- unsigned AS = 0;
+ LangAS AS = LangAS::Default;
// Keep address space of non-atomic pointer type.
if (const PointerType *PtrTy =
ValArg->getType()->getAs<PointerType>()) {
@@ -3020,7 +3161,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
}
} else {
- // The order(s) are always converted to int.
+ // The order(s) and scope are always converted to int.
Ty = Context.IntTy;
}
@@ -3081,15 +3222,30 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
<< SubExprs[1]->getSourceRange();
}
+ if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
+ auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1);
+ llvm::APSInt Result(32);
+ if (Scope->isIntegerConstantExpr(Result, Context) &&
+ !ScopeModel->isValid(Result.getZExtValue())) {
+ Diag(Scope->getLocStart(), diag::err_atomic_op_has_invalid_synch_scope)
+ << Scope->getSourceRange();
+ }
+ SubExprs.push_back(Scope);
+ }
+
AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
SubExprs, ResultType, Op,
TheCall->getRParenLoc());
if ((Op == AtomicExpr::AO__c11_atomic_load ||
- (Op == AtomicExpr::AO__c11_atomic_store)) &&
+ Op == AtomicExpr::AO__c11_atomic_store ||
+ Op == AtomicExpr::AO__opencl_atomic_load ||
+ Op == AtomicExpr::AO__opencl_atomic_store ) &&
Context.AtomicUsesUnsupportedLibcall(AE))
- Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) <<
- ((Op == AtomicExpr::AO__c11_atomic_load) ? 0 : 1);
+ Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib)
+ << ((Op == AtomicExpr::AO__c11_atomic_load ||
+ Op == AtomicExpr::AO__opencl_atomic_load)
+ ? 0 : 1);
return AE;
}
@@ -3615,11 +3771,89 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
return Result;
}
+/// Check that the user is calling the appropriate va_start builtin for the
+/// target and calling convention.
+static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
+ const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
+ bool IsX64 = TT.getArch() == llvm::Triple::x86_64;
+ bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64;
+ bool IsWindows = TT.isOSWindows();
+ bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start;
+ if (IsX64 || IsAArch64) {
+ clang::CallingConv CC = CC_C;
+ if (const FunctionDecl *FD = S.getCurFunctionDecl())
+ CC = FD->getType()->getAs<FunctionType>()->getCallConv();
+ if (IsMSVAStart) {
+ // Don't allow this in System V ABI functions.
+ if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_Win64))
+ return S.Diag(Fn->getLocStart(),
+ diag::err_ms_va_start_used_in_sysv_function);
+ } else {
+ // On x86-64/AArch64 Unix, don't allow this in Win64 ABI functions.
+ // On x64 Windows, don't allow this in System V ABI functions.
+ // (Yes, that means there's no corresponding way to support variadic
+ // System V ABI functions on Windows.)
+ if ((IsWindows && CC == CC_X86_64SysV) ||
+ (!IsWindows && CC == CC_Win64))
+ return S.Diag(Fn->getLocStart(),
+ diag::err_va_start_used_in_wrong_abi_function)
+ << !IsWindows;
+ }
+ return false;
+ }
+
+ if (IsMSVAStart)
+ return S.Diag(Fn->getLocStart(), diag::err_builtin_x64_aarch64_only);
+ return false;
+}
+
+static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn,
+ ParmVarDecl **LastParam = nullptr) {
+ // Determine whether the current function, block, or obj-c method is variadic
+ // and get its parameter list.
+ bool IsVariadic = false;
+ ArrayRef<ParmVarDecl *> Params;
+ DeclContext *Caller = S.CurContext;
+ if (auto *Block = dyn_cast<BlockDecl>(Caller)) {
+ IsVariadic = Block->isVariadic();
+ Params = Block->parameters();
+ } else if (auto *FD = dyn_cast<FunctionDecl>(Caller)) {
+ IsVariadic = FD->isVariadic();
+ Params = FD->parameters();
+ } else if (auto *MD = dyn_cast<ObjCMethodDecl>(Caller)) {
+ IsVariadic = MD->isVariadic();
+ // FIXME: This isn't correct for methods (results in bogus warning).
+ Params = MD->parameters();
+ } else if (isa<CapturedDecl>(Caller)) {
+ // We don't support va_start in a CapturedDecl.
+ S.Diag(Fn->getLocStart(), diag::err_va_start_captured_stmt);
+ return true;
+ } else {
+ // This must be some other declcontext that parses exprs.
+ S.Diag(Fn->getLocStart(), diag::err_va_start_outside_function);
+ return true;
+ }
+
+ if (!IsVariadic) {
+ S.Diag(Fn->getLocStart(), diag::err_va_start_fixed_function);
+ return true;
+ }
+
+ if (LastParam)
+ *LastParam = Params.empty() ? nullptr : Params.back();
+
+ return false;
+}
+
/// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start'
/// for validity. Emit an error and return true on failure; return false
/// on success.
-bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
+bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
Expr *Fn = TheCall->getCallee();
+
+ if (checkVAStartABI(*this, BuiltinID, Fn))
+ return true;
+
if (TheCall->getNumArgs() > 2) {
Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
@@ -3640,20 +3874,10 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
if (checkBuiltinArgument(*this, TheCall, 0))
return true;
- // Determine whether the current function is variadic or not.
- BlockScopeInfo *CurBlock = getCurBlock();
- bool isVariadic;
- if (CurBlock)
- isVariadic = CurBlock->TheDecl->isVariadic();
- else if (FunctionDecl *FD = getCurFunctionDecl())
- isVariadic = FD->isVariadic();
- else
- isVariadic = getCurMethodDecl()->isVariadic();
-
- if (!isVariadic) {
- Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
+ // Check that the current function is variadic, and get its last parameter.
+ ParmVarDecl *LastParam;
+ if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam))
return true;
- }
// Verify that the second argument to the builtin is the last argument of the
// current function or method.
@@ -3668,16 +3892,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
- // FIXME: This isn't correct for methods (results in bogus warning).
- // Get the last formal in the current function.
- const ParmVarDecl *LastArg;
- if (CurBlock)
- LastArg = CurBlock->TheDecl->parameters().back();
- else if (FunctionDecl *FD = getCurFunctionDecl())
- LastArg = FD->parameters().back();
- else
- LastArg = getCurMethodDecl()->parameters().back();
- SecondArgIsLastNamedArgument = PV == LastArg;
+ SecondArgIsLastNamedArgument = PV == LastParam;
Type = PV->getType();
ParamLoc = PV->getLocation();
@@ -3712,49 +3927,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
return false;
}
-/// Check the arguments to '__builtin_va_start' for validity, and that
-/// it was called from a function of the native ABI.
-/// Emit an error and return true on failure; return false on success.
-bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
- // On x86-64 Unix, don't allow this in Win64 ABI functions.
- // On x64 Windows, don't allow this in System V ABI functions.
- // (Yes, that means there's no corresponding way to support variadic
- // System V ABI functions on Windows.)
- if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64) {
- unsigned OS = Context.getTargetInfo().getTriple().getOS();
- clang::CallingConv CC = CC_C;
- if (const FunctionDecl *FD = getCurFunctionDecl())
- CC = FD->getType()->getAs<FunctionType>()->getCallConv();
- if ((OS == llvm::Triple::Win32 && CC == CC_X86_64SysV) ||
- (OS != llvm::Triple::Win32 && CC == CC_X86_64Win64))
- return Diag(TheCall->getCallee()->getLocStart(),
- diag::err_va_start_used_in_wrong_abi_function)
- << (OS != llvm::Triple::Win32);
- }
- return SemaBuiltinVAStartImpl(TheCall);
-}
-
-/// Check the arguments to '__builtin_ms_va_start' for validity, and that
-/// it was called from a Win64 ABI function.
-/// Emit an error and return true on failure; return false on success.
-bool Sema::SemaBuiltinMSVAStart(CallExpr *TheCall) {
- // This only makes sense for x86-64.
- const llvm::Triple &TT = Context.getTargetInfo().getTriple();
- Expr *Callee = TheCall->getCallee();
- if (TT.getArch() != llvm::Triple::x86_64)
- return Diag(Callee->getLocStart(), diag::err_x86_builtin_32_bit_tgt);
- // Don't allow this in System V ABI functions.
- clang::CallingConv CC = CC_C;
- if (const FunctionDecl *FD = getCurFunctionDecl())
- CC = FD->getType()->getAs<FunctionType>()->getCallConv();
- if (CC == CC_X86_64SysV ||
- (TT.getOS() != llvm::Triple::Win32 && CC != CC_X86_64Win64))
- return Diag(Callee->getLocStart(),
- diag::err_ms_va_start_used_in_sysv_function);
- return SemaBuiltinVAStartImpl(TheCall);
-}
-
-bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
+bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) {
// void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
// const char *named_addr);
@@ -3765,43 +3938,41 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
diag::err_typecheck_call_too_few_args_at_least)
<< 0 /*function call*/ << 3 << Call->getNumArgs();
- // Determine whether the current function is variadic or not.
- bool IsVariadic;
- if (BlockScopeInfo *CurBlock = getCurBlock())
- IsVariadic = CurBlock->TheDecl->isVariadic();
- else if (FunctionDecl *FD = getCurFunctionDecl())
- IsVariadic = FD->isVariadic();
- else if (ObjCMethodDecl *MD = getCurMethodDecl())
- IsVariadic = MD->isVariadic();
- else
- llvm_unreachable("unexpected statement type");
-
- if (!IsVariadic) {
- Diag(Func->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
- return true;
- }
-
// Type-check the first argument normally.
if (checkBuiltinArgument(*this, Call, 0))
return true;
- const struct {
- unsigned ArgNo;
- QualType Type;
- } ArgumentTypes[] = {
- { 1, Context.getPointerType(Context.CharTy.withConst()) },
- { 2, Context.getSizeType() },
- };
+ // Check that the current function is variadic.
+ if (checkVAStartIsInVariadicFunction(*this, Func))
+ return true;
- for (const auto &AT : ArgumentTypes) {
- const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens();
- if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType())
- continue;
- Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible)
- << Arg->getType() << AT.Type << 1 /* different class */
- << 0 /* qualifier difference */ << 3 /* parameter mismatch */
- << AT.ArgNo + 1 << Arg->getType() << AT.Type;
- }
+ // __va_start on Windows does not validate the parameter qualifiers
+
+ const Expr *Arg1 = Call->getArg(1)->IgnoreParens();
+ const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr();
+
+ const Expr *Arg2 = Call->getArg(2)->IgnoreParens();
+ const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr();
+
+ const QualType &ConstCharPtrTy =
+ Context.getPointerType(Context.CharTy.withConst());
+ if (!Arg1Ty->isPointerType() ||
+ Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy)
+ Diag(Arg1->getLocStart(), diag::err_typecheck_convert_incompatible)
+ << Arg1->getType() << ConstCharPtrTy
+ << 1 /* different class */
+ << 0 /* qualifier difference */
+ << 3 /* parameter mismatch */
+ << 2 << Arg1->getType() << ConstCharPtrTy;
+
+ const QualType SizeTy = Context.getSizeType();
+ if (Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers() != SizeTy)
+ Diag(Arg2->getLocStart(), diag::err_typecheck_convert_incompatible)
+ << Arg2->getType() << SizeTy
+ << 1 /* different class */
+ << 0 /* qualifier difference */
+ << 3 /* parameter mismatch */
+ << 3 << Arg2->getType() << SizeTy;
return false;
}
@@ -3892,6 +4063,65 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
return false;
}
+// Customized Sema Checking for VSX builtins that have the following signature:
+// vector [...] builtinName(vector [...], vector [...], const int);
+// Which takes the same type of vectors (any legal vector type) for the first
+// two arguments and takes compile time constant for the third argument.
+// Example builtins are :
+// vector double vec_xxpermdi(vector double, vector double, int);
+// vector short vec_xxsldwi(vector short, vector short, int);
+bool Sema::SemaBuiltinVSX(CallExpr *TheCall) {
+ unsigned ExpectedNumArgs = 3;
+ if (TheCall->getNumArgs() < ExpectedNumArgs)
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs()
+ << TheCall->getSourceRange();
+
+ if (TheCall->getNumArgs() > ExpectedNumArgs)
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_many_args_at_most)
+ << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs()
+ << TheCall->getSourceRange();
+
+ // Check the third argument is a compile time constant
+ llvm::APSInt Value;
+ if(!TheCall->getArg(2)->isIntegerConstantExpr(Value, Context))
+ return Diag(TheCall->getLocStart(),
+ diag::err_vsx_builtin_nonconstant_argument)
+ << 3 /* argument index */ << TheCall->getDirectCallee()
+ << SourceRange(TheCall->getArg(2)->getLocStart(),
+ TheCall->getArg(2)->getLocEnd());
+
+ QualType Arg1Ty = TheCall->getArg(0)->getType();
+ QualType Arg2Ty = TheCall->getArg(1)->getType();
+
+ // Check the type of argument 1 and argument 2 are vectors.
+ SourceLocation BuiltinLoc = TheCall->getLocStart();
+ if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) ||
+ (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) {
+ return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
+ << TheCall->getDirectCallee()
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd());
+ }
+
+ // Check the first two arguments are the same type.
+ if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) {
+ return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee()
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd());
+ }
+
+ // When default clang type checking is turned off and the customized type
+ // checking is used, the returning type of the function must be explicitly
+ // set. Otherwise it is _Bool by default.
+ TheCall->setType(Arg1Ty);
+
+ return false;
+}
+
/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
// This is declared to take (...), so we have to check everything.
ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
@@ -3914,7 +4144,8 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (!LHSType->isVectorType() || !RHSType->isVectorType())
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_non_vector)
+ diag::err_vec_builtin_non_vector)
+ << TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd()));
@@ -3928,12 +4159,14 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (!RHSType->hasIntegerRepresentation() ||
RHSType->getAs<VectorType>()->getNumElements() != numElements)
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_incompatible_vector)
+ diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(1)->getLocStart(),
TheCall->getArg(1)->getLocEnd()));
} else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_incompatible_vector)
+ diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd()));
} else if (numElements != numResElements) {
@@ -5935,8 +6168,9 @@ shouldNotPrintDirectly(const ASTContext &Context,
while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
StringRef Name = UserTy->getDecl()->getName();
QualType CastTy = llvm::StringSwitch<QualType>(Name)
- .Case("NSInteger", Context.LongTy)
- .Case("NSUInteger", Context.UnsignedLongTy)
+ .Case("CFIndex", Context.getNSIntegerType())
+ .Case("NSInteger", Context.getNSIntegerType())
+ .Case("NSUInteger", Context.getNSUIntegerType())
.Case("SInt32", Context.IntTy)
.Case("UInt32", Context.UnsignedIntTy)
.Default(QualType());
@@ -6125,7 +6359,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CastFix << ")";
SmallVector<FixItHint,4> Hints;
- if (!AT.matchesType(S.Context, IntendedTy))
+ if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly)
Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) {
@@ -7453,7 +7687,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()))
@@ -7947,11 +8181,18 @@ struct IntRange {
if (const AtomicType *AT = dyn_cast<AtomicType>(T))
T = AT->getValueType().getTypePtr();
- // For enum types, use the known bit width of the enumerators.
- if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+ if (!C.getLangOpts().CPlusPlus) {
+ // For enum types in C code, use the underlying datatype.
+ if (const EnumType *ET = dyn_cast<EnumType>(T))
+ T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr();
+ } else if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+ // For enum types in C++, use the known bit width of the enumerators.
EnumDecl *Enum = ET->getDecl();
+ // In C++11, enums without definitions can have an explicitly specified
+ // underlying type. Use this type to compute the range.
if (!Enum->isCompleteDefinition())
- return IntRange(C.getIntWidth(QualType(T, 0)), false);
+ return IntRange(C.getIntWidth(QualType(T, 0)),
+ !ET->isSignedIntegerOrEnumerationType());
unsigned NumPositive = Enum->getNumPositiveBits();
unsigned NumNegative = Enum->getNumNegativeBits();
@@ -8319,19 +8560,77 @@ bool IsSameFloatAfterCast(const APValue &value,
void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
-bool IsZero(Sema &S, Expr *E) {
+bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
// Suppress cases where we are comparing against an enum constant.
if (const DeclRefExpr *DR =
dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
if (isa<EnumConstantDecl>(DR->getDecl()))
- return false;
+ return true;
// Suppress cases where the '0' value is expanded from a macro.
if (E->getLocStart().isMacroID())
- return false;
+ return true;
- llvm::APSInt Value;
- return E->isIntegerConstantExpr(Value, S.Context) && Value == 0;
+ return false;
+}
+
+bool isNonBooleanIntegerValue(Expr *E) {
+ return !E->isKnownToHaveBooleanValue() && E->getType()->isIntegerType();
+}
+
+bool isNonBooleanUnsignedValue(Expr *E) {
+ // We are checking that the expression is not known to have boolean value,
+ // is an integer type; and is either unsigned after implicit casts,
+ // or was unsigned before implicit casts.
+ return isNonBooleanIntegerValue(E) &&
+ (!E->getType()->isSignedIntegerType() ||
+ !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType());
+}
+
+enum class LimitType {
+ Max = 1U << 0U, // e.g. 32767 for short
+ Min = 1U << 1U, // e.g. -32768 for short
+ Both = Max | Min // When the value is both the Min and the Max limit at the
+ // same time; e.g. in C++, A::a in enum A { a = 0 };
+};
+
+/// Checks whether Expr 'Constant' may be the
+/// std::numeric_limits<>::max() or std::numeric_limits<>::min()
+/// of the Expr 'Other'. If true, then returns the limit type (min or max).
+/// The Value is the evaluation of Constant
+llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, Expr *Other,
+ const llvm::APSInt &Value) {
+ if (IsEnumConstOrFromMacro(S, Constant))
+ return llvm::Optional<LimitType>();
+
+ if (isNonBooleanUnsignedValue(Other) && Value == 0)
+ return LimitType::Min;
+
+ // TODO: Investigate using GetExprRange() to get tighter bounds
+ // on the bit ranges.
+ QualType OtherT = Other->IgnoreParenImpCasts()->getType();
+ if (const auto *AT = OtherT->getAs<AtomicType>())
+ OtherT = AT->getValueType();
+
+ IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+
+ // Special-case for C++ for enum with one enumerator with value of 0.
+ if (OtherRange.Width == 0)
+ return Value == 0 ? LimitType::Both : llvm::Optional<LimitType>();
+
+ if (llvm::APSInt::isSameValue(
+ llvm::APSInt::getMaxValue(OtherRange.Width,
+ OtherT->isUnsignedIntegerType()),
+ Value))
+ return LimitType::Max;
+
+ if (llvm::APSInt::isSameValue(
+ llvm::APSInt::getMinValue(OtherRange.Width,
+ OtherT->isUnsignedIntegerType()),
+ Value))
+ return LimitType::Min;
+
+ return llvm::None;
}
bool HasEnumType(Expr *E) {
@@ -8346,40 +8645,63 @@ bool HasEnumType(Expr *E) {
return E->getType()->isEnumeralType();
}
-void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
- // Disable warning in template instantiations.
- if (S.inTemplateInstantiation())
- return;
+bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, Expr *Constant,
+ Expr *Other, const llvm::APSInt &Value,
+ bool RhsConstant) {
+ // Disable warning in template instantiations
+ // and only analyze <, >, <= and >= operations.
+ if (S.inTemplateInstantiation() || !E->isRelationalOp())
+ return false;
- BinaryOperatorKind op = E->getOpcode();
- if (E->isValueDependent())
- return;
+ BinaryOperatorKind Op = E->getOpcode();
- if (op == BO_LT && IsZero(S, E->getRHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
- << "< 0" << "false" << HasEnumType(E->getLHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_GE && IsZero(S, E->getRHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
- << ">= 0" << "true" << HasEnumType(E->getLHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_GT && IsZero(S, E->getLHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
- << "0 >" << "false" << HasEnumType(E->getRHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_LE && IsZero(S, E->getLHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
- << "0 <=" << "true" << HasEnumType(E->getRHS())
+ QualType OType = Other->IgnoreParenImpCasts()->getType();
+
+ llvm::Optional<LimitType> ValueType; // Which limit (min/max) is the constant?
+
+ if (!(isNonBooleanIntegerValue(Other) &&
+ (ValueType = IsTypeLimit(S, Constant, Other, Value))))
+ return false;
+
+ bool ConstIsLowerBound = (Op == BO_LT || Op == BO_LE) ^ RhsConstant;
+ bool ResultWhenConstEqualsOther = (Op == BO_LE || Op == BO_GE);
+ if (ValueType != LimitType::Both) {
+ bool ResultWhenConstNeOther =
+ ConstIsLowerBound ^ (ValueType == LimitType::Max);
+ if (ResultWhenConstEqualsOther != ResultWhenConstNeOther)
+ return false; // The comparison is not tautological.
+ } else if (ResultWhenConstEqualsOther == ConstIsLowerBound)
+ return false; // The comparison is not tautological.
+
+ const bool Result = ResultWhenConstEqualsOther;
+
+ unsigned Diag = (isNonBooleanUnsignedValue(Other) && Value == 0)
+ ? (HasEnumType(Other)
+ ? diag::warn_unsigned_enum_always_true_comparison
+ : diag::warn_unsigned_always_true_comparison)
+ : diag::warn_tautological_constant_compare;
+
+ // Should be enough for uint128 (39 decimal digits)
+ SmallString<64> PrettySourceValue;
+ llvm::raw_svector_ostream OS(PrettySourceValue);
+ OS << Value;
+
+ S.Diag(E->getOperatorLoc(), Diag)
+ << RhsConstant << OType << E->getOpcodeStr() << OS.str() << Result
<< E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- }
+
+ return true;
}
-void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
+bool DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
Expr *Other, const llvm::APSInt &Value,
bool RhsConstant) {
// Disable warning in template instantiations.
if (S.inTemplateInstantiation())
- return;
+ return false;
+
+ Constant = Constant->IgnoreParenImpCasts();
+ Other = Other->IgnoreParenImpCasts();
// TODO: Investigate using GetExprRange() to get tighter bounds
// on the bit ranges.
@@ -8391,10 +8713,6 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue();
- // 0 values are handled later by CheckTrivialUnsignedComparison().
- if ((Value == 0) && (!OtherIsBooleanType))
- return;
-
BinaryOperatorKind op = E->getOpcode();
bool IsTrue = true;
@@ -8410,7 +8728,7 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
QualType CommonT = E->getLHS()->getType();
if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
- return;
+ return false;
assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) &&
"comparison with non-integer type");
@@ -8425,38 +8743,38 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
// Check that the constant is representable in type OtherT.
if (ConstantSigned) {
if (OtherWidth >= Value.getMinSignedBits())
- return;
+ return false;
} else { // !ConstantSigned
if (OtherWidth >= Value.getActiveBits() + 1)
- return;
+ return false;
}
} else { // !OtherSigned
// Check that the constant is representable in type OtherT.
// Negative values are out of range.
if (ConstantSigned) {
if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
- return;
+ return false;
} else { // !ConstantSigned
if (OtherWidth >= Value.getActiveBits())
- return;
+ return false;
}
}
} else { // !CommonSigned
if (OtherRange.NonNegative) {
if (OtherWidth >= Value.getActiveBits())
- return;
+ return false;
} else { // OtherSigned
assert(!ConstantSigned &&
"Two signed types converted to unsigned types.");
// Check to see if the constant is representable in OtherT.
if (OtherWidth > Value.getActiveBits())
- return;
+ return false;
// Check to see if the constant is equivalent to a negative value
// cast to CommonT.
if (S.Context.getIntWidth(ConstantT) ==
S.Context.getIntWidth(CommonT) &&
Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
- return;
+ return false;
// The constant value rests between values that OtherT can represent
// after conversion. Relational comparison still works, but equality
// comparisons will be tautological.
@@ -8469,7 +8787,7 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
if (op == BO_EQ || op == BO_NE) {
IsTrue = op == BO_NE;
} else if (EqualityOnly) {
- return;
+ return false;
} else if (RhsConstant) {
if (op == BO_GT || op == BO_GE)
IsTrue = !PositiveConstant;
@@ -8557,7 +8875,7 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
} else if (CmpRes == ATrue) {
IsTrue = true;
} else {
- return;
+ return false;
}
}
@@ -8580,6 +8898,8 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
<< OS.str() << LiteralOrBoolConstant
<< OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue
<< E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
+
+ return true;
}
/// Analyze the operands of the given comparison. Implements the
@@ -8605,39 +8925,49 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
if (E->isValueDependent())
return AnalyzeImpConvsInComparison(S, E);
- Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
- Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
-
- bool IsComparisonConstant = false;
-
- // Check whether an integer constant comparison results in a value
- // of 'true' or 'false'.
+ Expr *LHS = E->getLHS();
+ Expr *RHS = E->getRHS();
+
if (T->isIntegralType(S.Context)) {
llvm::APSInt RHSValue;
- bool IsRHSIntegralLiteral =
- RHS->isIntegerConstantExpr(RHSValue, S.Context);
llvm::APSInt LHSValue;
- bool IsLHSIntegralLiteral =
- LHS->isIntegerConstantExpr(LHSValue, S.Context);
- if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral)
- DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true);
- else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral)
- DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false);
- else
- IsComparisonConstant =
- (IsRHSIntegralLiteral && IsLHSIntegralLiteral);
- } else if (!T->hasUnsignedIntegerRepresentation())
- IsComparisonConstant = E->isIntegerConstantExpr(S.Context);
-
- // We don't do anything special if this isn't an unsigned integral
- // comparison: we're only interested in integral comparisons, and
- // signed comparisons only happen in cases we don't care to warn about.
- //
- // We also don't care about value-dependent expressions or expressions
- // whose result is a constant.
- if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant)
+
+ bool IsRHSIntegralLiteral = RHS->isIntegerConstantExpr(RHSValue, S.Context);
+ bool IsLHSIntegralLiteral = LHS->isIntegerConstantExpr(LHSValue, S.Context);
+
+ // We don't care about expressions whose result is a constant.
+ if (IsRHSIntegralLiteral && IsLHSIntegralLiteral)
+ return AnalyzeImpConvsInComparison(S, E);
+
+ // We only care about expressions where just one side is literal
+ if (IsRHSIntegralLiteral ^ IsLHSIntegralLiteral) {
+ // Is the constant on the RHS or LHS?
+ const bool RhsConstant = IsRHSIntegralLiteral;
+ Expr *Const = RhsConstant ? RHS : LHS;
+ Expr *Other = RhsConstant ? LHS : RHS;
+ const llvm::APSInt &Value = RhsConstant ? RHSValue : LHSValue;
+
+ // Check whether an integer constant comparison results in a value
+ // of 'true' or 'false'.
+
+ if (CheckTautologicalComparison(S, E, Const, Other, Value, RhsConstant))
+ return AnalyzeImpConvsInComparison(S, E);
+
+ if (DiagnoseOutOfRangeComparison(S, E, Const, Other, Value, RhsConstant))
+ return AnalyzeImpConvsInComparison(S, E);
+ }
+ }
+
+ if (!T->hasUnsignedIntegerRepresentation()) {
+ // We don't do anything special if this isn't an unsigned integral
+ // comparison: we're only interested in integral comparisons, and
+ // signed comparisons only happen in cases we don't care to warn about.
return AnalyzeImpConvsInComparison(S, E);
-
+ }
+
+ LHS = LHS->IgnoreParenImpCasts();
+ RHS = RHS->IgnoreParenImpCasts();
+
// Check to see if one of the (unmodified) operands is of different
// signedness.
Expr *signedOperand, *unsignedOperand;
@@ -8650,7 +8980,6 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
signedOperand = RHS;
unsignedOperand = LHS;
} else {
- CheckTrivialUnsignedComparison(S, E);
return AnalyzeImpConvsInComparison(S, E);
}
@@ -8662,11 +8991,9 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
- // If the signed range is non-negative, -Wsign-compare won't fire,
- // but we should still check for comparisons which are always true
- // or false.
+ // If the signed range is non-negative, -Wsign-compare won't fire.
if (signedRange.NonNegative)
- return CheckTrivialUnsignedComparison(S, E);
+ return;
// For (in)equality comparisons, if the unsigned operand is a
// constant which cannot collide with a overflowed signed operand,
@@ -8729,13 +9056,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))
@@ -9188,10 +9568,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Strip complex types.
if (isa<ComplexType>(Source)) {
if (!isa<ComplexType>(Target)) {
- if (S.SourceMgr.isInSystemMacro(CC))
+ if (S.SourceMgr.isInSystemMacro(CC) || Target->isBooleanType())
return;
- return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar);
+ return DiagnoseImpCast(S, E, T, CC,
+ S.getLangOpts().CPlusPlus
+ ? diag::err_impcast_complex_scalar
+ : diag::warn_impcast_complex_scalar);
}
Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
@@ -9833,6 +10216,9 @@ void Sema::CheckForIntOverflow (Expr *E) {
if (auto InitList = dyn_cast<InitListExpr>(E))
Exprs.append(InitList->inits().begin(), InitList->inits().end());
+
+ if (isa<ObjCBoxedExpr>(E))
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
} while (!Exprs.empty());
}
@@ -11446,9 +11832,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
return;
// Check for a call to std::move
- const FunctionDecl *FD = CE->getDirectCallee();
- if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() ||
- !FD->getIdentifier()->isStr("move"))
+ if (!CE->isCallToStdMove())
return;
// Get argument from std::move
@@ -11972,6 +12356,8 @@ void Sema::RefersToMemberWithReducedAlignment(
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl();
+ if (RD->isInvalidDecl())
+ return;
ValueDecl *MD = ME->getMemberDecl();
auto *FD = dyn_cast<FieldDecl>(MD);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index ea4a33d3f5..72ab65fc58 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -10,7 +10,7 @@
// This file defines the code-completion semantic actions.
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -23,6 +23,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -46,7 +47,7 @@ namespace {
/// the result set (when it returns true) and which declarations should be
/// filtered out (returns false).
typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const;
-
+
typedef CodeCompletionResult Result;
private:
@@ -741,8 +742,18 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) {
}
const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
- if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
+ if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) {
+ // Explicit destructor calls are very rare.
+ if (isa<CXXDestructorDecl>(ND))
+ return CCP_Unlikely;
+ // Explicit operator and conversion function calls are also very rare.
+ auto DeclNameKind = ND->getDeclName().getNameKind();
+ if (DeclNameKind == DeclarationName::CXXOperatorName ||
+ DeclNameKind == DeclarationName::CXXLiteralOperatorName ||
+ DeclNameKind == DeclarationName::CXXConversionFunctionName)
+ return CCP_Unlikely;
return CCP_MemberDeclaration;
+ }
// Content-based decisions.
if (isa<EnumConstantDecl>(ND))
@@ -1647,21 +1658,23 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
if (CCC == Sema::PCC_Class) {
AddTypedefResult(Results);
+ bool IsNotInheritanceScope =
+ !(S->getFlags() & Scope::ClassInheritanceScope);
// public:
Builder.AddTypedTextChunk("public");
- if (Results.includeCodePatterns())
+ if (IsNotInheritanceScope && Results.includeCodePatterns())
Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
// protected:
Builder.AddTypedTextChunk("protected");
- if (Results.includeCodePatterns())
+ if (IsNotInheritanceScope && Results.includeCodePatterns())
Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
// private:
Builder.AddTypedTextChunk("private");
- if (Results.includeCodePatterns())
+ if (IsNotInheritanceScope && Results.includeCodePatterns())
Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
}
@@ -1860,12 +1873,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
}
+ LLVM_FALLTHROUGH;
// Fall through (for statement expressions).
case Sema::PCC_ForInit:
case Sema::PCC_Condition:
AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
// Fall through: conditions and statements can have expressions.
+ LLVM_FALLTHROUGH;
case Sema::PCC_ParenthesizedExpression:
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
@@ -1895,6 +1910,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Results.AddResult(Result(Builder.TakeString()));
}
// Fall through
+ LLVM_FALLTHROUGH;
case Sema::PCC_Expression: {
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2395,6 +2411,34 @@ formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
return Result;
}
+static std::string GetDefaultValueString(const ParmVarDecl *Param,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ const SourceRange SrcRange = Param->getDefaultArgRange();
+ CharSourceRange CharSrcRange = CharSourceRange::getTokenRange(SrcRange);
+ bool Invalid = CharSrcRange.isInvalid();
+ if (Invalid)
+ return "";
+ StringRef srcText = Lexer::getSourceText(CharSrcRange, SM, LangOpts, &Invalid);
+ if (Invalid)
+ return "";
+
+ if (srcText.empty() || srcText == "=") {
+ // Lexer can't determine the value.
+ // This happens if the code is incorrect (for example class is forward declared).
+ return "";
+ }
+ std::string DefValue(srcText.str());
+ // FIXME: remove this check if the Lexer::getSourceText value is fixed and
+ // this value always has (or always does not have) '=' in front of it
+ if (DefValue.at(0) != '=') {
+ // If we don't have '=' in front of value.
+ // Lexer returns built-in types values without '=' and user-defined types values with it.
+ return " = " + DefValue;
+ }
+ return " " + DefValue;
+}
+
/// \brief Add function parameter chunks to the given code completion string.
static void AddFunctionParameterChunks(Preprocessor &PP,
const PrintingPolicy &Policy,
@@ -2428,6 +2472,8 @@ static void AddFunctionParameterChunks(Preprocessor &PP,
// Format the placeholder string.
std::string PlaceholderStr = FormatFunctionParameter(Policy, Param);
+ if (Param->hasDefaultArg())
+ PlaceholderStr += GetDefaultValueString(Param, PP.getSourceManager(), PP.getLangOpts());
if (Function->isVariadic() && P == N - 1)
PlaceholderStr += ", ...";
@@ -2735,7 +2781,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
// Format a function-like macro with placeholders for the arguments.
Result.AddChunk(CodeCompletionString::CK_LeftParen);
- MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
+ MacroInfo::param_iterator A = MI->param_begin(), AEnd = MI->param_end();
// C99 variadic macros add __VA_ARGS__ at the end. Skip it.
if (MI->isC99Varargs()) {
@@ -2746,8 +2792,8 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
}
- for (MacroInfo::arg_iterator A = MI->arg_begin(); A != AEnd; ++A) {
- if (A != MI->arg_begin())
+ for (MacroInfo::param_iterator A = MI->param_begin(); A != AEnd; ++A) {
+ if (A != MI->param_begin())
Result.AddChunk(CodeCompletionString::CK_Comma);
if (MI->isVariadic() && (A+1) == AEnd) {
@@ -3009,10 +3055,14 @@ static void AddOverloadParameterChunks(ASTContext &Context,
// Format the placeholder string.
std::string Placeholder;
- if (Function)
- Placeholder = FormatFunctionParameter(Policy, Function->getParamDecl(P));
- else
+ if (Function) {
+ const ParmVarDecl *Param = Function->getParamDecl(P);
+ Placeholder = FormatFunctionParameter(Policy, Param);
+ if (Param->hasDefaultArg())
+ Placeholder += GetDefaultValueString(Param, Context.getSourceManager(), Context.getLangOpts());
+ } else {
Placeholder = Prototype->getParamType(P).getAsString(Policy);
+ }
if (P == CurrentArg)
Result.AddCurrentParameterChunk(
@@ -3869,6 +3919,41 @@ static void AddObjCProperties(
}
}
+static void AddRecordMembersCompletionResults(Sema &SemaRef,
+ ResultBuilder &Results, Scope *S,
+ QualType BaseType,
+ RecordDecl *RD) {
+ // Indicate that we are performing a member access, and the cv-qualifiers
+ // for the base object type.
+ Results.setObjectTypeQualifiers(BaseType.getQualifiers());
+
+ // Access to a C/C++ class, struct, or union.
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);
+ SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer,
+ SemaRef.CodeCompleter->includeGlobals(),
+ /*IncludeDependentBases=*/true);
+
+ if (SemaRef.getLangOpts().CPlusPlus) {
+ if (!Results.empty()) {
+ // The "template" keyword can follow "->" or "." in the grammar.
+ // However, we only want to suggest the template keyword if something
+ // is dependent.
+ bool IsDependent = BaseType->isDependentType();
+ if (!IsDependent) {
+ for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
+ if (DeclContext *Ctx = DepScope->getEntity()) {
+ IsDependent = Ctx->isDependentContext();
+ break;
+ }
+ }
+
+ if (IsDependent)
+ Results.AddResult(CodeCompletionResult("template"));
+ }
+ }
+}
+
void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
SourceLocation OpLoc, bool IsArrow,
bool IsBaseExprStatement) {
@@ -3879,8 +3964,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
if (ConvertedBase.isInvalid())
return;
Base = ConvertedBase.get();
-
- typedef CodeCompletionResult Result;
QualType BaseType = Base->getType();
@@ -3915,34 +3998,18 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
&ResultBuilder::IsMember);
Results.EnterNewScope();
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
- // Indicate that we are performing a member access, and the cv-qualifiers
- // for the base object type.
- Results.setObjectTypeQualifiers(BaseType.getQualifiers());
-
- // Access to a C/C++ class, struct, or union.
- Results.allowNestedNameSpecifiers();
- CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer,
- CodeCompleter->includeGlobals());
-
- if (getLangOpts().CPlusPlus) {
- if (!Results.empty()) {
- // The "template" keyword can follow "->" or "." in the grammar.
- // However, we only want to suggest the template keyword if something
- // is dependent.
- bool IsDependent = BaseType->isDependentType();
- if (!IsDependent) {
- for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
- if (DeclContext *Ctx = DepScope->getEntity()) {
- IsDependent = Ctx->isDependentContext();
- break;
- }
- }
-
- if (IsDependent)
- Results.AddResult(Result("template"));
- }
- }
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType,
+ Record->getDecl());
+ } else if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) {
+ TemplateName TN = TST->getTemplateName();
+ if (const auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) {
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
+ }
+ } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) {
+ if (auto *RD = ICNT->getDecl())
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
} else if (!IsArrow && BaseType->isObjCObjectPointerType()) {
// Objective-C property reference.
AddedPropertiesSet AddedProperties;
@@ -4228,13 +4295,17 @@ static void mergeCandidatesWithResults(Sema &SemaRef,
std::stable_sort(
CandidateSet.begin(), CandidateSet.end(),
[&](const OverloadCandidate &X, const OverloadCandidate &Y) {
- return isBetterOverloadCandidate(SemaRef, X, Y, Loc);
+ return isBetterOverloadCandidate(SemaRef, X, Y, Loc,
+ CandidateSet.getKind());
});
// Add the remaining viable overload candidates as code-completion results.
- for (auto &Candidate : CandidateSet)
+ for (auto &Candidate : CandidateSet) {
+ if (Candidate.Function && Candidate.Function->isDeleted())
+ continue;
if (Candidate.Viable)
Results.push_back(ResultCandidate(Candidate.Function));
+ }
}
}
@@ -4318,13 +4389,18 @@ 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());
+ const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase();
AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs,
/*SuppressUsedConversions=*/false,
- /*PartialOverloading=*/true);
+ /*PartialOverloading=*/true,
+ FirstArgumentIsBase);
} else {
FunctionDecl *FD = nullptr;
if (auto MCE = dyn_cast<MemberExpr>(NakedFn))
@@ -4519,8 +4595,10 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) {
if (!SS.getScopeRep() || !CodeCompleter)
return;
-
- DeclContext *Ctx = computeDeclContext(SS, EnteringContext);
+
+ // Always pretend to enter a context to ensure that a dependent type
+ // resolves to a dependent record.
+ DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true);
if (!Ctx)
return;
@@ -4550,7 +4628,9 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
Results.ExitScope();
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer,
+ /*IncludeGlobalScope=*/true,
+ /*IncludeDependentBases=*/true);
HandleCodeCompleteResults(this, CodeCompleter,
Results.getCompletionContext(),
@@ -6569,7 +6649,7 @@ typedef llvm::DenseMap<
/// indexed by selector so they can be easily found.
static void FindImplementableMethods(ASTContext &Context,
ObjCContainerDecl *Container,
- bool WantInstanceMethods,
+ Optional<bool> WantInstanceMethods,
QualType ReturnType,
KnownMethodsMap &KnownMethods,
bool InOriginalClass = true) {
@@ -6640,7 +6720,7 @@ static void FindImplementableMethods(ASTContext &Context,
// we want the methods from this container to override any methods
// we've previously seen with the same selector.
for (auto *M : Container->methods()) {
- if (M->isInstanceMethod() == WantInstanceMethods) {
+ if (!WantInstanceMethods || M->isInstanceMethod() == *WantInstanceMethods) {
if (!ReturnType.isNull() &&
!Context.hasSameUnqualifiedType(ReturnType, M->getReturnType()))
continue;
@@ -7312,8 +7392,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
}
}
-void Sema::CodeCompleteObjCMethodDecl(Scope *S,
- bool IsInstanceMethod,
+void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
ParsedType ReturnTy) {
// Determine the return type of the method we're declaring, if
// provided.
@@ -7368,7 +7447,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
ObjCMethodDecl *Method = M->second.getPointer();
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
-
+
+ // Add the '-'/'+' prefix if it wasn't provided yet.
+ if (!IsInstanceMethod) {
+ Builder.AddTextChunk(Method->isInstanceMethod() ? "-" : "+");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ }
+
// If the result type was not already provided, add it to the
// pattern as (type).
if (ReturnType.isNull()) {
@@ -7470,11 +7555,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
if (IFace)
for (auto *Cat : IFace->visible_categories())
Containers.push_back(Cat);
-
- for (unsigned I = 0, N = Containers.size(); I != N; ++I)
- for (auto *P : Containers[I]->instance_properties())
- AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context,
- KnownSelectors, Results);
+
+ if (IsInstanceMethod) {
+ for (unsigned I = 0, N = Containers.size(); I != N; ++I)
+ for (auto *P : Containers[I]->instance_properties())
+ AddObjCKeyValueCompletions(P, *IsInstanceMethod, ReturnType, Context,
+ KnownSelectors, Results);
+ }
}
Results.ExitScope();
@@ -7808,6 +7895,23 @@ void Sema::CodeCompleteNaturalLanguage() {
nullptr, 0);
}
+void Sema::CodeCompleteAvailabilityPlatformName() {
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_Other);
+ Results.EnterNewScope();
+ static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"};
+ for (const char *Platform : llvm::makeArrayRef(Platforms)) {
+ Results.AddResult(CodeCompletionResult(Platform));
+ Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString(
+ Twine(Platform) + "ApplicationExtension")));
+ }
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter,
+ CodeCompletionContext::CCC_Other, Results.data(),
+ Results.size());
+}
+
void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
SmallVectorImpl<CodeCompletionResult> &Results) {
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index 4d0f8a8f76..e6b640f878 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -11,31 +11,42 @@
//
//===----------------------------------------------------------------------===//
-#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) {
+static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
+ SourceLocation Loc, bool &Res) {
DeclarationName DN = S.PP.getIdentifierInfo(Name);
LookupResult LR(S, DN, Loc, Sema::LookupMemberName);
// Suppress diagnostics when a private member is selected. The same warnings
// will be produced again when building the call.
LR.suppressDiagnostics();
- return S.LookupQualifiedName(LR, RD);
+ Res = S.LookupQualifiedName(LR, RD);
+ return LR;
+}
+
+static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
+ SourceLocation Loc) {
+ bool Res;
+ lookupMember(S, Name, RD, Loc, Res);
+ return Res;
}
/// Look up the std::coroutine_traits<...>::promise_type for the given
/// function type.
-static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
- SourceLocation KwLoc,
- SourceLocation FuncLoc) {
+static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
+ SourceLocation KwLoc) {
+ const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>();
+ const SourceLocation FuncLoc = FD->getLocation();
// FIXME: Cache std::coroutine_traits once we've found it.
NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
if (!StdExp) {
@@ -61,16 +72,35 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
return QualType();
}
- // Form template argument list for coroutine_traits<R, P1, P2, ...>.
+ // Form template argument list for coroutine_traits<R, P1, P2, ...> according
+ // to [dcl.fct.def.coroutine]3
TemplateArgumentListInfo Args(KwLoc, KwLoc);
- Args.addArgument(TemplateArgumentLoc(
- TemplateArgument(FnType->getReturnType()),
- 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())
+ auto AddArg = [&](QualType T) {
Args.addArgument(TemplateArgumentLoc(
TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc)));
+ };
+ AddArg(FnType->getReturnType());
+ // If the function is a non-static member function, add the type
+ // of the implicit object parameter before the formal parameters.
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isInstance()) {
+ // [over.match.funcs]4
+ // For non-static member functions, the type of the implicit object
+ // parameter is
+ // -- "lvalue reference to cv X" for functions declared without a
+ // ref-qualifier or with the & ref-qualifier
+ // -- "rvalue reference to cv X" for functions declared with the &&
+ // ref-qualifier
+ QualType T =
+ MD->getThisType(S.Context)->getAs<PointerType>()->getPointeeType();
+ T = FnType->getRefQualifier() == RQ_RValue
+ ? S.Context.getRValueReferenceType(T)
+ : S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true);
+ AddArg(T);
+ }
+ }
+ for (QualType T : FnType->getParamTypes())
+ AddArg(T);
// Build the template-id.
QualType CoroTrait =
@@ -118,8 +148,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
return PromiseType;
}
-/// Look up the std::coroutine_traits<...>::promise_type for the given
-/// function type.
+/// Look up the std::experimental::coroutine_handle<PromiseType>.
static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
SourceLocation Loc) {
if (PromiseType.isNull())
@@ -312,6 +341,7 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
}
struct ReadySuspendResumeResult {
+ enum AwaitCallType { ACT_Ready, ACT_Suspend, ACT_Resume };
Expr *Results[3];
OpaqueValueExpr *OpaqueValue;
bool IsInvalid;
@@ -333,6 +363,32 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
}
+// See if return type is coroutine-handle and if so, invoke builtin coro-resume
+// on its address. This is to enable experimental support for coroutine-handle
+// returning await_suspend that results in a guranteed tail call to the target
+// coroutine.
+static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
+ SourceLocation Loc) {
+ if (RetType->isReferenceType())
+ return nullptr;
+ Type const *T = RetType.getTypePtr();
+ if (!T->isClassType() && !T->isStructureType())
+ return nullptr;
+
+ // FIXME: Add convertability check to coroutine_handle<>. Possibly via
+ // EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment
+ // a private function in SemaExprCXX.cpp
+
+ ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", None);
+ if (AddressExpr.isInvalid())
+ return nullptr;
+
+ Expr *JustAddress = AddressExpr.get();
+ // FIXME: Check that the type of AddressExpr is void*
+ return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
+ JustAddress);
+}
+
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
/// expression.
static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
@@ -357,7 +413,49 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
Calls.Results[I] = Result.get();
}
+ // Assume the calls are valid; all further checking should make them invalid.
Calls.IsInvalid = false;
+
+ using ACT = ReadySuspendResumeResult::AwaitCallType;
+ CallExpr *AwaitReady = cast<CallExpr>(Calls.Results[ACT::ACT_Ready]);
+ if (!AwaitReady->getType()->isDependentType()) {
+ // [expr.await]p3 [...]
+ // — await-ready is the expression e.await_ready(), contextually converted
+ // to bool.
+ ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady);
+ if (Conv.isInvalid()) {
+ S.Diag(AwaitReady->getDirectCallee()->getLocStart(),
+ diag::note_await_ready_no_bool_conversion);
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << AwaitReady->getDirectCallee() << E->getSourceRange();
+ Calls.IsInvalid = true;
+ }
+ Calls.Results[ACT::ACT_Ready] = Conv.get();
+ }
+ CallExpr *AwaitSuspend = cast<CallExpr>(Calls.Results[ACT::ACT_Suspend]);
+ if (!AwaitSuspend->getType()->isDependentType()) {
+ // [expr.await]p3 [...]
+ // - await-suspend is the expression e.await_suspend(h), which shall be
+ // a prvalue of type void or bool.
+ QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
+
+ // Experimental support for coroutine_handle returning await_suspend.
+ if (Expr *TailCallSuspend = maybeTailCall(S, RetType, AwaitSuspend, Loc))
+ Calls.Results[ACT::ACT_Suspend] = TailCallSuspend;
+ else {
+ // non-class prvalues always have cv-unqualified types
+ if (RetType->isReferenceType() ||
+ (!RetType->isBooleanType() && !RetType->isVoidType())) {
+ S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(),
+ diag::err_await_suspend_invalid_return_type)
+ << RetType;
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << AwaitSuspend->getDirectCallee();
+ Calls.IsInvalid = true;
+ }
+ }
+ }
+
return Calls;
}
@@ -371,19 +469,22 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise,
if (PromiseRef.isInvalid())
return ExprError();
- // Call 'yield_value', passing in E.
return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
}
VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
assert(isa<FunctionDecl>(CurContext) && "not in a function scope");
auto *FD = cast<FunctionDecl>(CurContext);
+ bool IsThisDependentType = [&] {
+ if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD))
+ return MD->isInstance() && MD->getThisType(Context)->isDependentType();
+ else
+ return false;
+ }();
- QualType T =
- FD->getType()->isDependentType()
- ? Context.DependentTy
- : lookupPromiseType(*this, FD->getType()->castAs<FunctionProtoType>(),
- Loc, FD->getLocation());
+ QualType T = FD->getType()->isDependentType() || IsThisDependentType
+ ? Context.DependentTy
+ : lookupPromiseType(*this, FD, Loc);
if (T.isNull())
return nullptr;
@@ -394,6 +495,7 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
if (VD->isInvalidDecl())
return nullptr;
ActOnUninitializedDecl(VD);
+ FD->addDecl(VD);
assert(!VD->isInvalidDecl());
return VD;
}
@@ -423,11 +525,11 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
return ScopeInfo;
}
-static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
- StringRef Keyword) {
- if (!checkCoroutineContext(S, KWLoc, Keyword))
+bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
+ StringRef Keyword) {
+ if (!checkCoroutineContext(*this, KWLoc, Keyword))
return false;
- auto *ScopeInfo = S.getCurFunction();
+ auto *ScopeInfo = getCurFunction();
assert(ScopeInfo->CoroutinePromise);
// If we have existing coroutine statements then we have already built
@@ -437,24 +539,24 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
ScopeInfo->setNeedsCoroutineSuspends(false);
- auto *Fn = cast<FunctionDecl>(S.CurContext);
+ auto *Fn = cast<FunctionDecl>(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);
+ buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None);
if (Suspend.isInvalid())
return StmtError();
- Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get());
+ Suspend = buildOperatorCoawaitCall(*this, SC, Loc, Suspend.get());
if (Suspend.isInvalid())
return StmtError();
- Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(),
- /*IsImplicit*/ true);
- Suspend = S.ActOnFinishFullExpr(Suspend.get());
+ Suspend = BuildResolvedCoawaitExpr(Loc, Suspend.get(),
+ /*IsImplicit*/ true);
+ Suspend = ActOnFinishFullExpr(Suspend.get());
if (Suspend.isInvalid()) {
- S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
<< ((Name == "initial_suspend") ? 0 : 1);
- S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
+ Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
return StmtError();
}
return cast<Stmt>(Suspend.get());
@@ -474,7 +576,7 @@ static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
}
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
- if (!actOnCoroutineBodyStart(*this, S, Loc, "co_await")) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
@@ -566,7 +668,7 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *E,
}
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
- if (!actOnCoroutineBodyStart(*this, S, Loc, "co_yield")) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
@@ -611,14 +713,15 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
if (RSS.IsInvalid)
return ExprError();
- Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
- RSS.Results[2], RSS.OpaqueValue);
+ Expr *Res =
+ new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
+ RSS.Results[2], RSS.OpaqueValue);
return Res;
}
StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) {
- if (!actOnCoroutineBodyStart(*this, S, Loc, "co_return")) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) {
CorrectDelayedTyposInExpr(E);
return StmtError();
}
@@ -658,32 +761,35 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
return Res;
}
-static ExprResult buildStdCurrentExceptionCall(Sema &S, SourceLocation Loc) {
+/// Look up the std::nothrow object.
+static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {
NamespaceDecl *Std = S.getStdNamespace();
- if (!Std) {
- S.Diag(Loc, diag::err_implied_std_current_exception_not_found);
- return ExprError();
- }
- LookupResult Result(S, &S.PP.getIdentifierTable().get("current_exception"),
- Loc, Sema::LookupOrdinaryName);
+ assert(Std && "Should already be diagnosed");
+
+ LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc,
+ Sema::LookupOrdinaryName);
if (!S.LookupQualifiedName(Result, Std)) {
- S.Diag(Loc, diag::err_implied_std_current_exception_not_found);
- return ExprError();
+ // FIXME: <experimental/coroutine> should have been included already.
+ // If we require it to include <new> then this diagnostic is no longer
+ // needed.
+ S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found);
+ return nullptr;
}
- // FIXME The STL is free to provide more than one overload.
- FunctionDecl *FD = Result.getAsSingle<FunctionDecl>();
- if (!FD) {
- S.Diag(Loc, diag::err_malformed_std_current_exception);
- return ExprError();
- }
- ExprResult Res = S.BuildDeclRefExpr(FD, FD->getType(), VK_LValue, Loc);
- Res = S.ActOnCallExpr(/*Scope*/ nullptr, Res.get(), Loc, None, Loc);
- if (Res.isInvalid()) {
- S.Diag(Loc, diag::err_malformed_std_current_exception);
- return ExprError();
+ auto *VD = Result.getAsSingle<VarDecl>();
+ if (!VD) {
+ Result.suppressDiagnostics();
+ // We found something weird. Complain about the first thing we found.
+ NamedDecl *Found = *Result.begin();
+ S.Diag(Found->getLocation(), diag::err_malformed_std_nothrow);
+ return nullptr;
}
- return Res;
+
+ ExprResult DR = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, Loc);
+ if (DR.isInvalid())
+ return nullptr;
+
+ return DR.get();
}
// Find an appropriate delete for the promise.
@@ -711,60 +817,22 @@ static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc,
return OperatorDelete;
}
-namespace {
-class SubStmtBuilder : public CoroutineBodyStmt::CtorArgs {
- Sema &S;
- FunctionDecl &FD;
- FunctionScopeInfo &Fn;
- bool IsValid;
- SourceLocation Loc;
- QualType RetType;
- SmallVector<Stmt *, 4> ParamMovesVector;
- const bool IsPromiseDependentType;
- CXXRecordDecl *PromiseRecordDecl = nullptr;
-
-public:
- SubStmtBuilder(Sema &S, FunctionDecl &FD, 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() &&
- makeOnException() && makeOnFallthrough() &&
- makeNewAndDeleteExpr() && makeReturnObject() &&
- makeParamMoves();
- }
-
- bool isInvalid() const { return !this->IsValid; }
-
- bool makePromiseStmt();
- bool makeInitialAndFinalSuspend();
- bool makeNewAndDeleteExpr();
- bool makeOnFallthrough();
- bool makeOnException();
- bool makeReturnObject();
- bool makeParamMoves();
-};
-}
void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
FunctionScopeInfo *Fn = getCurFunction();
- assert(Fn && Fn->CoroutinePromise && "not a coroutine");
-
+ assert(Fn && Fn->isCoroutine() && "not a coroutine");
if (!Body) {
assert(FD->isInvalidDecl() &&
"a null body is only allowed for invalid declarations");
return;
}
+ // We have a function that uses coroutine keywords, but we failed to build
+ // the promise type.
+ if (!Fn->CoroutinePromise)
+ return FD->setInvalidDecl();
if (isa<CoroutineBodyStmt>(Body)) {
- // FIXME(EricWF): Nothing todo. the body is already a transformed coroutine
- // body statement.
+ // Nothing todo. the body is already a transformed coroutine body statement.
return;
}
@@ -777,15 +845,54 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
<< Fn->getFirstCoroutineStmtKeyword();
}
- SubStmtBuilder Builder(*this, *FD, *Fn, Body);
- if (Builder.isInvalid())
+ 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);
}
-bool SubStmtBuilder::makePromiseStmt() {
+CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD,
+ sema::FunctionScopeInfo &Fn,
+ Stmt *Body)
+ : S(S), FD(FD), Fn(Fn), Loc(FD.getLocation()),
+ IsPromiseDependentType(
+ !Fn.CoroutinePromise ||
+ Fn.CoroutinePromise->getType()->isDependentType()) {
+ this->Body = Body;
+ if (!IsPromiseDependentType) {
+ PromiseRecordDecl = Fn.CoroutinePromise->getType()->getAsCXXRecordDecl();
+ assert(PromiseRecordDecl && "Type should have already been checked");
+ }
+ this->IsValid = makePromiseStmt() && makeInitialAndFinalSuspend();
+}
+
+bool CoroutineStmtBuilder::buildStatements() {
+ assert(this->IsValid && "coroutine already invalid");
+ this->IsValid = makeReturnObject() && makeParamMoves();
+ if (this->IsValid && !IsPromiseDependentType)
+ buildDependentStatements();
+ return this->IsValid;
+}
+
+bool CoroutineStmtBuilder::buildDependentStatements() {
+ assert(this->IsValid && "coroutine already invalid");
+ assert(!this->IsPromiseDependentType &&
+ "coroutine cannot have a dependent promise type");
+ this->IsValid = makeOnException() && makeOnFallthrough() &&
+ makeGroDeclAndReturnStmt() && makeReturnOnAllocFailure() &&
+ makeNewAndDeleteExpr();
+ return this->IsValid;
+}
+
+bool CoroutineStmtBuilder::buildParameterMoves() {
+ assert(this->IsValid && "coroutine already invalid");
+ assert(this->ParamMoves.empty() && "param moves already built");
+ return this->IsValid = makeParamMoves();
+}
+
+bool CoroutineStmtBuilder::makePromiseStmt() {
// Form a declaration statement for the promise declaration, so that AST
// visitors can more easily find it.
StmtResult PromiseStmt =
@@ -797,7 +904,7 @@ bool SubStmtBuilder::makePromiseStmt() {
return true;
}
-bool SubStmtBuilder::makeInitialAndFinalSuspend() {
+bool CoroutineStmtBuilder::makeInitialAndFinalSuspend() {
if (Fn.hasInvalidCoroutineSuspends())
return false;
this->InitialSuspend = cast<Expr>(Fn.CoroutineSuspends.first);
@@ -805,31 +912,129 @@ bool SubStmtBuilder::makeInitialAndFinalSuspend() {
return true;
}
-bool SubStmtBuilder::makeNewAndDeleteExpr() {
+static bool diagReturnOnAllocFailure(Sema &S, Expr *E,
+ CXXRecordDecl *PromiseRecordDecl,
+ FunctionScopeInfo &Fn) {
+ auto Loc = E->getExprLoc();
+ if (auto *DeclRef = dyn_cast_or_null<DeclRefExpr>(E)) {
+ auto *Decl = DeclRef->getDecl();
+ if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(Decl)) {
+ if (Method->isStatic())
+ return true;
+ else
+ Loc = Decl->getLocation();
+ }
+ }
+
+ S.Diag(
+ Loc,
+ diag::err_coroutine_promise_get_return_object_on_allocation_failure)
+ << PromiseRecordDecl;
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+ return false;
+}
+
+bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+
+ // [dcl.fct.def.coroutine]/8
+ // The unqualified-id get_return_object_on_allocation_failure is looked up in
+ // the scope of class P by class member access lookup (3.4.5). ...
+ // If an allocation function returns nullptr, ... the coroutine return value
+ // is obtained by a call to ... get_return_object_on_allocation_failure().
+
+ DeclarationName DN =
+ S.PP.getIdentifierInfo("get_return_object_on_allocation_failure");
+ LookupResult Found(S, DN, Loc, Sema::LookupMemberName);
+ if (!S.LookupQualifiedName(Found, PromiseRecordDecl))
+ return true;
+
+ CXXScopeSpec SS;
+ ExprResult DeclNameExpr =
+ S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
+ if (DeclNameExpr.isInvalid())
+ return false;
+
+ if (!diagReturnOnAllocFailure(S, DeclNameExpr.get(), PromiseRecordDecl, Fn))
+ return false;
+
+ ExprResult ReturnObjectOnAllocationFailure =
+ S.ActOnCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc);
+ if (ReturnObjectOnAllocationFailure.isInvalid())
+ return false;
+
+ StmtResult ReturnStmt =
+ S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get());
+ if (ReturnStmt.isInvalid()) {
+ S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here)
+ << DN;
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+ return false;
+ }
+
+ this->ReturnStmtOnAllocFailure = ReturnStmt.get();
+ return true;
+}
+
+bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// Form and check allocation and deallocation calls.
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
QualType PromiseType = Fn.CoroutinePromise->getType();
- if (PromiseType->isDependentType())
- return true;
if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type))
return false;
- // FIXME: Add support for get_return_object_on_allocation failure.
+ const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr;
+
// FIXME: Add support for stateful allocators.
FunctionDecl *OperatorNew = nullptr;
FunctionDecl *OperatorDelete = nullptr;
FunctionDecl *UnusedResult = nullptr;
bool PassAlignment = false;
+ SmallVector<Expr *, 1> PlacementArgs;
S.FindAllocationFunctions(Loc, SourceRange(),
/*UseGlobal*/ false, PromiseType,
- /*isArray*/ false, PassAlignment,
- /*PlacementArgs*/ None, OperatorNew, UnusedResult);
+ /*isArray*/ false, PassAlignment, PlacementArgs,
+ OperatorNew, UnusedResult);
+
+ bool IsGlobalOverload =
+ OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext());
+ // If we didn't find a class-local new declaration and non-throwing new
+ // was is required then we need to lookup the non-throwing global operator
+ // instead.
+ if (RequiresNoThrowAlloc && (!OperatorNew || IsGlobalOverload)) {
+ auto *StdNoThrow = buildStdNoThrowDeclRef(S, Loc);
+ if (!StdNoThrow)
+ return false;
+ PlacementArgs = {StdNoThrow};
+ OperatorNew = nullptr;
+ S.FindAllocationFunctions(Loc, SourceRange(),
+ /*UseGlobal*/ true, PromiseType,
+ /*isArray*/ false, PassAlignment, PlacementArgs,
+ OperatorNew, UnusedResult);
+ }
- OperatorDelete = findDeleteForPromise(S, Loc, PromiseType);
+ assert(OperatorNew && "expected definition of operator new to be found");
- if (!OperatorDelete || !OperatorNew)
+ if (RequiresNoThrowAlloc) {
+ const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>();
+ if (!FT->isNothrow(S.Context, /*ResultIfDependent*/ false)) {
+ S.Diag(OperatorNew->getLocation(),
+ diag::err_coroutine_promise_new_requires_nothrow)
+ << OperatorNew;
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << OperatorNew;
+ return false;
+ }
+ }
+
+ if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr)
return false;
Expr *FramePtr =
@@ -845,8 +1050,13 @@ bool SubStmtBuilder::makeNewAndDeleteExpr() {
if (NewRef.isInvalid())
return false;
+ SmallVector<Expr *, 2> NewArgs(1, FrameSize);
+ for (auto Arg : PlacementArgs)
+ NewArgs.push_back(Arg);
+
ExprResult NewExpr =
- S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, FrameSize, Loc);
+ S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
+ NewExpr = S.ActOnFinishFullExpr(NewExpr.get());
if (NewExpr.isInvalid())
return false;
@@ -872,6 +1082,7 @@ bool SubStmtBuilder::makeNewAndDeleteExpr() {
ExprResult DeleteExpr =
S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
+ DeleteExpr = S.ActOnFinishFullExpr(DeleteExpr.get());
if (DeleteExpr.isInvalid())
return false;
@@ -881,20 +1092,39 @@ bool SubStmtBuilder::makeNewAndDeleteExpr() {
return true;
}
-bool SubStmtBuilder::makeOnFallthrough() {
- if (!PromiseRecordDecl)
- return true;
+bool CoroutineStmtBuilder::makeOnFallthrough() {
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
// [dcl.fct.def.coroutine]/4
// The unqualified-ids 'return_void' and 'return_value' are looked up in
// the scope of class P. If both are found, the program is ill-formed.
- const bool HasRVoid = lookupMember(S, "return_void", PromiseRecordDecl, Loc);
- const bool HasRValue = lookupMember(S, "return_value", PromiseRecordDecl, Loc);
+ bool HasRVoid, HasRValue;
+ LookupResult LRVoid =
+ lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid);
+ LookupResult LRValue =
+ lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue);
StmtResult Fallthrough;
if (HasRVoid && HasRValue) {
// FIXME Improve this diagnostic
- S.Diag(FD.getLocation(), diag::err_coroutine_promise_return_ill_formed)
+ S.Diag(FD.getLocation(),
+ diag::err_coroutine_promise_incompatible_return_functions)
+ << PromiseRecordDecl;
+ S.Diag(LRVoid.getRepresentativeDecl()->getLocation(),
+ diag::note_member_first_declared_here)
+ << LRVoid.getLookupName();
+ S.Diag(LRValue.getRepresentativeDecl()->getLocation(),
+ diag::note_member_first_declared_here)
+ << LRValue.getLookupName();
+ return false;
+ } else if (!HasRVoid && !HasRValue) {
+ // FIXME: The PDTS currently specifies this case as UB, not ill-formed.
+ // However we still diagnose this as an error since until the PDTS is fixed.
+ S.Diag(FD.getLocation(),
+ diag::err_coroutine_promise_requires_return_function)
+ << PromiseRecordDecl;
+ S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
<< PromiseRecordDecl;
return false;
} else if (HasRVoid) {
@@ -912,67 +1142,209 @@ bool SubStmtBuilder::makeOnFallthrough() {
return true;
}
-bool SubStmtBuilder::makeOnException() {
- // Try to form 'p.set_exception(std::current_exception());' to handle
- // uncaught exceptions.
- // TODO: Post WG21 Issaquah 2016 renamed set_exception to unhandled_exception
- // TODO: and dropped exception_ptr parameter. Make it so.
-
- if (!PromiseRecordDecl)
- return true;
+bool CoroutineStmtBuilder::makeOnException() {
+ // Try to form 'p.unhandled_exception();'
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+
+ const bool RequireUnhandledException = S.getLangOpts().CXXExceptions;
+
+ if (!lookupMember(S, "unhandled_exception", PromiseRecordDecl, Loc)) {
+ auto DiagID =
+ RequireUnhandledException
+ ? diag::err_coroutine_promise_unhandled_exception_required
+ : diag::
+ warn_coroutine_promise_unhandled_exception_required_with_exceptions;
+ S.Diag(Loc, DiagID) << PromiseRecordDecl;
+ S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
+ << PromiseRecordDecl;
+ return !RequireUnhandledException;
+ }
// If exceptions are disabled, don't try to build OnException.
if (!S.getLangOpts().CXXExceptions)
return true;
- ExprResult SetException;
+ ExprResult UnhandledException = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
+ "unhandled_exception", None);
+ UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc);
+ if (UnhandledException.isInvalid())
+ return false;
- // [dcl.fct.def.coroutine]/3
- // The unqualified-id set_exception is found in the scope of P by class
- // member access lookup (3.4.5).
- if (lookupMember(S, "set_exception", PromiseRecordDecl, Loc)) {
- // Form the call 'p.set_exception(std::current_exception())'
- SetException = buildStdCurrentExceptionCall(S, Loc);
- if (SetException.isInvalid())
- return false;
- Expr *E = SetException.get();
- SetException = buildPromiseCall(S, Fn.CoroutinePromise, Loc, "set_exception", E);
- SetException = S.ActOnFinishFullExpr(SetException.get(), Loc);
- if (SetException.isInvalid())
- return false;
+ // Since the body of the coroutine will be wrapped in try-catch, it will
+ // be incompatible with SEH __try if present in a function.
+ if (!S.getLangOpts().Borland && Fn.FirstSEHTryLoc.isValid()) {
+ S.Diag(Fn.FirstSEHTryLoc, diag::err_seh_in_a_coroutine_with_cxx_exceptions);
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+ return false;
}
- this->OnException = SetException.get();
+ this->OnException = UnhandledException.get();
return true;
}
-bool SubStmtBuilder::makeReturnObject() {
-
+bool CoroutineStmtBuilder::makeReturnObject() {
// Build implicit 'p.get_return_object()' expression and form initialization
// of return type from it.
ExprResult ReturnObject =
buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None);
if (ReturnObject.isInvalid())
return false;
- QualType RetType = FD.getReturnType();
- if (!RetType->isDependentType()) {
- InitializedEntity Entity =
- InitializedEntity::InitializeResult(Loc, RetType, false);
- ReturnObject = S.PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
- ReturnObject.get());
- if (ReturnObject.isInvalid())
+
+ this->ReturnValue = ReturnObject.get();
+ return true;
+}
+
+static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) {
+ if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) {
+ auto *MethodDecl = MbrRef->getMethodDecl();
+ S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here)
+ << MethodDecl;
+ }
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+}
+
+bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+ assert(this->ReturnValue && "ReturnValue must be already formed");
+
+ QualType const GroType = this->ReturnValue->getType();
+ assert(!GroType->isDependentType() &&
+ "get_return_object type must no longer be dependent");
+
+ QualType const FnRetType = FD.getReturnType();
+ assert(!FnRetType->isDependentType() &&
+ "get_return_object type must no longer be dependent");
+
+ if (FnRetType->isVoidType()) {
+ ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc);
+ if (Res.isInvalid())
return false;
+
+ this->ResultDecl = Res.get();
+ return true;
}
- ReturnObject = S.ActOnFinishFullExpr(ReturnObject.get(), Loc);
- if (ReturnObject.isInvalid())
+
+ if (GroType->isVoidType()) {
+ // Trigger a nice error message.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeResult(Loc, FnRetType, false);
+ S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue);
+ noteMemberDeclaredHere(S, ReturnValue, Fn);
return false;
+ }
- this->ReturnValue = ReturnObject.get();
+ auto *GroDecl = VarDecl::Create(
+ S.Context, &FD, FD.getLocation(), FD.getLocation(),
+ &S.PP.getIdentifierTable().get("__coro_gro"), GroType,
+ S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None);
+
+ S.CheckVariableDeclarationType(GroDecl);
+ if (GroDecl->isInvalidDecl())
+ return false;
+
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
+ ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType,
+ this->ReturnValue);
+ if (Res.isInvalid())
+ return false;
+
+ Res = S.ActOnFinishFullExpr(Res.get());
+ if (Res.isInvalid())
+ return false;
+
+ if (GroType == FnRetType) {
+ GroDecl->setNRVOVariable(true);
+ }
+
+ S.AddInitializerToDecl(GroDecl, Res.get(),
+ /*DirectInit=*/false);
+
+ S.FinalizeDeclaration(GroDecl);
+
+ // Form a declaration statement for the return declaration, so that AST
+ // visitors can more easily find it.
+ StmtResult GroDeclStmt =
+ S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc);
+ if (GroDeclStmt.isInvalid())
+ return false;
+
+ this->ResultDecl = GroDeclStmt.get();
+
+ ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc);
+ if (declRef.isInvalid())
+ return false;
+
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get());
+ if (ReturnStmt.isInvalid()) {
+ noteMemberDeclaredHere(S, ReturnValue, Fn);
+ return false;
+ }
+
+ this->ReturnStmt = ReturnStmt.get();
return true;
}
-bool SubStmtBuilder::makeParamMoves() {
- // FIXME: Perform move-initialization of parameters into frame-local copies.
+// Create a static_cast\<T&&>(expr).
+static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) {
+ if (T.isNull())
+ T = E->getType();
+ QualType TargetType = S.BuildReferenceType(
+ T, /*SpelledAsLValue*/ false, SourceLocation(), DeclarationName());
+ SourceLocation ExprLoc = E->getLocStart();
+ TypeSourceInfo *TargetLoc =
+ S.Context.getTrivialTypeSourceInfo(TargetType, ExprLoc);
+
+ return S
+ .BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E,
+ SourceRange(ExprLoc, ExprLoc), E->getSourceRange())
+ .get();
+}
+
+
+/// \brief Build a variable declaration for move parameter.
+static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type,
+ IdentifierInfo *II) {
+ TypeSourceInfo *TInfo = S.Context.getTrivialTypeSourceInfo(Type, Loc);
+ VarDecl *Decl =
+ VarDecl::Create(S.Context, S.CurContext, Loc, Loc, II, Type, TInfo, SC_None);
+ Decl->setImplicit();
+ return Decl;
+}
+
+bool CoroutineStmtBuilder::makeParamMoves() {
+ for (auto *paramDecl : FD.parameters()) {
+ auto Ty = paramDecl->getType();
+ if (Ty->isDependentType())
+ continue;
+
+ // No need to copy scalars, llvm will take care of them.
+ if (Ty->getAsCXXRecordDecl()) {
+ ExprResult ParamRef =
+ S.BuildDeclRefExpr(paramDecl, paramDecl->getType(),
+ ExprValueKind::VK_LValue, Loc); // FIXME: scope?
+ if (ParamRef.isInvalid())
+ return false;
+
+ Expr *RCast = castForMoving(S, ParamRef.get());
+
+ auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier());
+ S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true);
+
+ // Convert decl to a statement.
+ StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc);
+ if (Stmt.isInvalid())
+ return false;
+
+ ParamMovesVector.push_back(Stmt.get());
+ }
+ }
+
+ // Convert to ArrayRef in CtorArgs structure that builder inherits from.
+ ParamMoves = ParamMovesVector;
return true;
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d7d71221b5..0c00ef7e26 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -64,22 +64,45 @@ namespace {
class TypeNameValidatorCCC : public CorrectionCandidateCallback {
public:
- TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false,
- bool AllowTemplates=false)
- : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
- AllowTemplates(AllowTemplates) {
- WantExpressionKeywords = false;
- WantCXXNamedCasts = false;
- WantRemainingKeywords = false;
+ TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false,
+ bool AllowTemplates = false,
+ bool AllowNonTemplates = true)
+ : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
+ AllowTemplates(AllowTemplates), AllowNonTemplates(AllowNonTemplates) {
+ WantExpressionKeywords = false;
+ WantCXXNamedCasts = false;
+ WantRemainingKeywords = false;
}
bool ValidateCandidate(const TypoCorrection &candidate) override {
if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+ if (!AllowInvalidDecl && ND->isInvalidDecl())
+ return false;
+
+ if (getAsTypeTemplateDecl(ND))
+ return AllowTemplates;
+
bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
- bool AllowedTemplate = AllowTemplates && getAsTypeTemplateDecl(ND);
- return (IsType || AllowedTemplate) &&
- (AllowInvalidDecl || !ND->isInvalidDecl());
+ if (!IsType)
+ return false;
+
+ if (AllowNonTemplates)
+ return true;
+
+ // An injected-class-name of a class template (specialization) is valid
+ // as a template or as a non-template.
+ if (AllowTemplates) {
+ auto *RD = dyn_cast<CXXRecordDecl>(ND);
+ if (!RD || !RD->isInjectedClassName())
+ return false;
+ RD = cast<CXXRecordDecl>(RD->getDeclContext());
+ return RD->getDescribedClassTemplate() ||
+ isa<ClassTemplateSpecializationDecl>(RD);
+ }
+
+ return false;
}
+
return !WantClassName && candidate.isKeyword();
}
@@ -87,6 +110,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
bool AllowInvalidDecl;
bool WantClassName;
bool AllowTemplates;
+ bool AllowNonTemplates;
};
} // end anonymous namespace
@@ -108,6 +132,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_wchar_t:
case tok::kw_bool:
@@ -380,6 +405,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
}
}
// If typo correction failed or was not performed, fall through
+ LLVM_FALLTHROUGH;
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Result.suppressDiagnostics();
@@ -615,7 +641,7 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext);
for (const auto &Base : RD->bases())
- if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType()))
+ if (Ty && Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType()))
return true;
return S->isFunctionPrototypeScope();
}
@@ -627,7 +653,10 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
Scope *S,
CXXScopeSpec *SS,
ParsedType &SuggestedType,
- bool AllowClassTemplates) {
+ bool IsTemplateName) {
+ // Don't report typename errors for editor placeholders.
+ if (II->isEditorPlaceholder())
+ return;
// We don't have anything to suggest (yet).
SuggestedType = nullptr;
@@ -636,28 +665,41 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
if (TypoCorrection Corrected =
CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS,
llvm::make_unique<TypeNameValidatorCCC>(
- false, false, AllowClassTemplates),
+ false, false, IsTemplateName, !IsTemplateName),
CTK_ErrorRecovery)) {
+ // FIXME: Support error recovery for the template-name case.
+ bool CanRecover = !IsTemplateName;
if (Corrected.isKeyword()) {
// We corrected to a keyword.
- diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
+ diagnoseTypo(Corrected,
+ PDiag(IsTemplateName ? diag::err_no_template_suggest
+ : diag::err_unknown_typename_suggest)
+ << II);
II = Corrected.getCorrectionAsIdentifierInfo();
} else {
// We found a similarly-named type or interface; suggest that.
if (!SS || !SS->isSet()) {
diagnoseTypo(Corrected,
- PDiag(diag::err_unknown_typename_suggest) << II);
+ PDiag(IsTemplateName ? diag::err_no_template_suggest
+ : diag::err_unknown_typename_suggest)
+ << II, CanRecover);
} else if (DeclContext *DC = computeDeclContext(*SS, false)) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
II->getName().equals(CorrectedStr);
diagnoseTypo(Corrected,
- PDiag(diag::err_unknown_nested_typename_suggest)
- << II << DC << DroppedSpecifier << SS->getRange());
+ PDiag(IsTemplateName
+ ? diag::err_no_member_template_suggest
+ : diag::err_unknown_nested_typename_suggest)
+ << II << DC << DroppedSpecifier << SS->getRange(),
+ CanRecover);
} else {
llvm_unreachable("could not have corrected a typo here");
}
+ if (!CanRecover)
+ return;
+
CXXScopeSpec tmpSS;
if (Corrected.getCorrectionSpecifier())
tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
@@ -672,7 +714,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
return;
}
- if (getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus && !IsTemplateName) {
// See if II is a class template that the user forgot to pass arguments to.
UnqualifiedId Name;
Name.setIdentifier(II, IILoc);
@@ -697,10 +739,13 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
// (struct, union, enum) from Parser::ParseImplicitInt here, instead?
if (!SS || (!SS->isSet() && !SS->isInvalid()))
- Diag(IILoc, diag::err_unknown_typename) << II;
+ Diag(IILoc, IsTemplateName ? diag::err_no_template
+ : diag::err_unknown_typename)
+ << II;
else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_typename_nested_not_found)
- << II << DC << SS->getRange();
+ Diag(IILoc, IsTemplateName ? diag::err_no_member_template
+ : diag::err_typename_nested_not_found)
+ << II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S))
@@ -1283,15 +1328,17 @@ void Sema::ActOnExitFunctionContext() {
/// overloaded function declaration or has the "overloadable"
/// attribute.
static bool AllowOverloadingOfFunction(LookupResult &Previous,
- ASTContext &Context) {
+ ASTContext &Context,
+ const FunctionDecl *New) {
if (Context.getLangOpts().CPlusPlus)
return true;
if (Previous.getResultKind() == LookupResult::FoundOverloaded)
return true;
- return (Previous.getResultKind() == LookupResult::Found
- && Previous.getFoundDecl()->hasAttr<OverloadableAttr>());
+ return Previous.getResultKind() == LookupResult::Found &&
+ (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() ||
+ New->hasAttr<OverloadableAttr>());
}
/// Add this decl to the scope shadowed decl chains.
@@ -1401,6 +1448,46 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
F.done();
}
+/// We've determined that \p New is a redeclaration of \p Old. Check that they
+/// have compatible owning modules.
+bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
+ // FIXME: The Modules TS is not clear about how friend declarations are
+ // to be treated. It's not meaningful to have different owning modules for
+ // linkage in redeclarations of the same entity, so for now allow the
+ // redeclaration and change the owning modules to match.
+ if (New->getFriendObjectKind() &&
+ Old->getOwningModuleForLinkage() != New->getOwningModuleForLinkage()) {
+ New->setLocalOwningModule(Old->getOwningModule());
+ makeMergedDefinitionVisible(New);
+ return false;
+ }
+
+ Module *NewM = New->getOwningModule();
+ Module *OldM = Old->getOwningModule();
+ if (NewM == OldM)
+ return false;
+
+ // FIXME: Check proclaimed-ownership-declarations here too.
+ bool NewIsModuleInterface = NewM && NewM->Kind == Module::ModuleInterfaceUnit;
+ bool OldIsModuleInterface = OldM && OldM->Kind == Module::ModuleInterfaceUnit;
+ if (NewIsModuleInterface || OldIsModuleInterface) {
+ // C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]:
+ // if a declaration of D [...] appears in the purview of a module, all
+ // other such declarations shall appear in the purview of the same module
+ Diag(New->getLocation(), diag::err_mismatched_owning_module)
+ << New
+ << NewIsModuleInterface
+ << (NewIsModuleInterface ? NewM->getFullModuleName() : "")
+ << OldIsModuleInterface
+ << (OldIsModuleInterface ? OldM->getFullModuleName() : "");
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ New->setInvalidDecl();
+ return true;
+ }
+
+ return false;
+}
+
static bool isUsingDecl(NamedDecl *D) {
return isa<UsingShadowDecl>(D) ||
isa<UnresolvedUsingTypenameDecl>(D) ||
@@ -1485,6 +1572,11 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
+ // A non-out-of-line declaration of a member specialization was implicitly
+ // instantiated; it's the out-of-line declaration that we're interested in.
+ if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ FD->getMemberSpecializationInfo() && !FD->isOutOfLine())
+ return false;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD))
@@ -1511,6 +1603,10 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
+ if (VD->isStaticDataMember() &&
+ VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ VD->getMemberSpecializationInfo() && !VD->isOutOfLine())
+ return false;
if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation()))
return false;
@@ -1548,7 +1644,24 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (D->isInvalidDecl())
return false;
- if (D->isReferenced() || D->isUsed() || D->hasAttr<UnusedAttr>() ||
+ bool Referenced = false;
+ if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
+ // For a decomposition declaration, warn if none of the bindings are
+ // referenced, instead of if the variable itself is referenced (which
+ // it is, by the bindings' expressions).
+ for (auto *BD : DD->bindings()) {
+ if (BD->isReferenced()) {
+ Referenced = true;
+ break;
+ }
+ }
+ } else if (!D->getDeclName()) {
+ return false;
+ } else if (D->isReferenced() || D->isUsed()) {
+ Referenced = true;
+ }
+
+ if (Referenced || D->hasAttr<UnusedAttr>() ||
D->hasAttr<ObjCPreciseLifetimeAttr>())
return false;
@@ -1610,7 +1723,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
CXXConstructorDecl *CD = Construct->getConstructor();
- if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>())
+ if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>() &&
+ (VD->getInit()->isValueDependent() || !VD->evaluateValue()))
return false;
}
}
@@ -1671,7 +1785,7 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
else
DiagID = diag::warn_unused_variable;
- Diag(D->getLocation(), DiagID) << D->getDeclName() << Hint;
+ Diag(D->getLocation(), DiagID) << D << Hint;
}
static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
@@ -1701,8 +1815,6 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
assert(isa<NamedDecl>(TmpD) && "Decl isn't NamedDecl?");
NamedDecl *D = cast<NamedDecl>(TmpD);
- if (!D->getDeclName()) continue;
-
// Diagnose unused variables in this scope.
if (!S->hasUnrecoverableErrorOccurred()) {
DiagnoseUnusedDecl(D);
@@ -1710,6 +1822,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
DiagnoseUnusedNestedTypedefs(RD);
}
+ if (!D->getDeclName()) continue;
+
// If this was a forward reference to a label, verify it was defined.
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
CheckPoppedLabel(LD, *this);
@@ -1943,8 +2057,7 @@ static void filterNonConflictingPreviousTypedefDecls(Sema &S,
// If both declarations give a tag declaration a typedef name for linkage
// purposes, then they declare the same entity.
- if (S.getLangOpts().CPlusPlus &&
- OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) &&
+ if (OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) &&
Decl->getAnonDeclWithTypedefName())
continue;
}
@@ -1969,7 +2082,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef)
<< Kind << NewType;
if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->setInvalidDecl();
return true;
}
@@ -1982,7 +2095,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
<< Kind << NewType << OldType;
if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->setInvalidDecl();
return true;
}
@@ -2049,7 +2162,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
NamedDecl *OldD = OldDecls.getRepresentativeDecl();
if (OldD->getLocation().isValid())
- Diag(OldD->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(OldD, New->getLocation());
return New->setInvalidDecl();
}
@@ -2062,7 +2175,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
auto *OldTag = OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true);
auto *NewTag = New->getAnonDeclWithTypedefName();
NamedDecl *Hidden = nullptr;
- if (getLangOpts().CPlusPlus && OldTag && NewTag &&
+ if (OldTag && NewTag &&
OldTag->getCanonicalDecl() != NewTag->getCanonicalDecl() &&
!hasVisibleDefinition(OldTag, &Hidden)) {
// There is a definition of this tag, but it is not visible. Use it
@@ -2075,7 +2188,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
New->setTypeSourceInfo(OldTD->getTypeSourceInfo());
// Make the old tag definition visible.
- makeMergedDefinitionVisible(Hidden, NewTag->getLocation());
+ makeMergedDefinitionVisible(Hidden);
// If this was an unscoped enumeration, yank all of its enumerators
// out of the scope.
@@ -2141,7 +2254,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
Diag(New->getLocation(), diag::err_redefinition)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
return New->setInvalidDecl();
}
@@ -2154,13 +2267,15 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
// -Wtypedef-redefinition. If either the original or the redefinition is
// in a system header, don't emit this for compatibility with GCC.
if (getDiagnostics().getSuppressSystemWarnings() &&
- (Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
+ // Some standard types are defined implicitly in Clang (e.g. OpenCL).
+ (Old->isImplicit() ||
+ Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
Context.getSourceManager().isInSystemHeader(New->getLocation())))
return;
Diag(New->getLocation(), diag::ext_redefinition_of_typedef)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
}
/// DeclhasAttr - returns true if decl Declaration already has the target
@@ -2394,7 +2509,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
return false;
}
-static const Decl *getDefinition(const Decl *D) {
+static const NamedDecl *getDefinition(const Decl *D) {
if (const TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
@@ -2421,7 +2536,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
if (!New->hasAttrs())
return;
- const Decl *Def = getDefinition(Old);
+ const NamedDecl *Def = getDefinition(Old);
if (!Def || Def == New)
return;
@@ -2447,7 +2562,10 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
? diag::err_alias_after_tentative
: diag::err_redefinition;
S.Diag(VD->getLocation(), Diag) << VD->getDeclName();
- S.Diag(Def->getLocation(), diag::note_previous_definition);
+ if (Diag == diag::err_redefinition)
+ S.notePreviousDefinition(Def, VD->getLocation());
+ else
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
VD->setInvalidDecl();
}
++I;
@@ -2547,6 +2665,16 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
}
}
+ // This redeclaration adds a section attribute.
+ if (New->hasAttr<SectionAttr>() && !Old->hasAttr<SectionAttr>()) {
+ if (auto *VD = dyn_cast<VarDecl>(New)) {
+ if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) {
+ Diag(New->getLocation(), diag::warn_attribute_section_on_redeclaration);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ }
+
if (!Old->hasAttrs())
return;
@@ -2834,7 +2962,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
} else {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
- Diag(OldD->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(OldD, New->getLocation());
return true;
}
}
@@ -2871,10 +2999,48 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->dropAttr<InternalLinkageAttr>();
}
+ if (CheckRedeclarationModuleOwnership(New, Old))
+ return true;
+
+ if (!getLangOpts().CPlusPlus) {
+ bool OldOvl = Old->hasAttr<OverloadableAttr>();
+ if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) {
+ Diag(New->getLocation(), diag::err_attribute_overloadable_mismatch)
+ << New << OldOvl;
+
+ // Try our best to find a decl that actually has the overloadable
+ // attribute for the note. In most cases (e.g. programs with only one
+ // broken declaration/definition), this won't matter.
+ //
+ // FIXME: We could do this if we juggled some extra state in
+ // OverloadableAttr, rather than just removing it.
+ const Decl *DiagOld = Old;
+ if (OldOvl) {
+ auto OldIter = llvm::find_if(Old->redecls(), [](const Decl *D) {
+ const auto *A = D->getAttr<OverloadableAttr>();
+ return A && !A->isImplicit();
+ });
+ // If we've implicitly added *all* of the overloadable attrs to this
+ // chain, emitting a "previous redecl" note is pointless.
+ DiagOld = OldIter == Old->redecls_end() ? nullptr : *OldIter;
+ }
+
+ if (DiagOld)
+ Diag(DiagOld->getLocation(),
+ diag::note_attribute_overloadable_prev_overload)
+ << OldOvl;
+
+ if (OldOvl)
+ New->addAttr(OverloadableAttr::CreateImplicit(Context));
+ else
+ New->dropAttr<OverloadableAttr>();
+ }
+ }
+
// If a function is first declared with a calling convention, but is later
// declared or defined without one, all following decls assume the calling
// convention of the first.
@@ -2946,7 +3112,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// Merge ns_returns_retained attribute.
if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) {
if (NewTypeInfo.getProducesResult()) {
- Diag(New->getLocation(), diag::err_returns_retained_mismatch);
+ Diag(New->getLocation(), diag::err_function_attribute_mismatch)
+ << "'ns_returns_retained'";
Diag(OldLocation, diag::note_previous_declaration);
return true;
}
@@ -2955,6 +3122,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
RequiresAdjustment = true;
}
+ if (OldTypeInfo.getNoCallerSavedRegs() !=
+ NewTypeInfo.getNoCallerSavedRegs()) {
+ if (NewTypeInfo.getNoCallerSavedRegs()) {
+ AnyX86NoCallerSavedRegistersAttr *Attr =
+ New->getAttr<AnyX86NoCallerSavedRegistersAttr>();
+ Diag(New->getLocation(), diag::err_function_attribute_mismatch) << Attr;
+ Diag(OldLocation, diag::note_previous_declaration);
+ return true;
+ }
+
+ NewTypeInfo = NewTypeInfo.withNoCallerSavedRegs(true);
+ RequiresAdjustment = true;
+ }
+
if (RequiresAdjustment) {
const FunctionType *AdjustedType = New->getType()->getAs<FunctionType>();
AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo);
@@ -3400,8 +3581,6 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
ni = newMethod->param_begin(), ne = newMethod->param_end();
ni != ne && oi != oe; ++ni, ++oi)
mergeParamDeclAttributes(*ni, *oi, *this);
-
- CheckObjCMethodOverride(newMethod, oldMethod);
}
static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) {
@@ -3584,9 +3763,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
- << New->getDeclName();
- Diag(Previous.getRepresentativeDecl()->getLocation(),
- diag::note_previous_definition);
+ << New->getDeclName();
+ notePreviousDefinition(Previous.getRepresentativeDecl(),
+ New->getLocation());
return New->setInvalidDecl();
}
@@ -3615,7 +3794,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
Old->getStorageClass() == SC_None &&
!Old->hasAttr<WeakImportAttr>()) {
Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
// Remove weak_import attribute on new declaration.
New->dropAttr<WeakImportAttr>();
}
@@ -3624,7 +3803,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->dropAttr<InternalLinkageAttr>();
}
@@ -3694,6 +3873,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return New->setInvalidDecl();
}
+ if (CheckRedeclarationModuleOwnership(New, Old))
+ return;
+
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
// FIXME: The test for external storage here seems wrong? We still
@@ -3717,7 +3899,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
}
- // If this redeclaration makes the function inline, we may need to add it to
+ // If this redeclaration makes the variable inline, we may need to add it to
// UndefinedButUsed.
if (!Old->isInline() && New->isInline() && Old->isUsed(false) &&
!Old->getDefinition() && !New->isThisDeclarationADefinition())
@@ -3781,6 +3963,60 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setImplicitlyInline();
}
+void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) {
+ SourceManager &SrcMgr = getSourceManager();
+ auto FNewDecLoc = SrcMgr.getDecomposedLoc(New);
+ auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old->getLocation());
+ auto *FNew = SrcMgr.getFileEntryForID(FNewDecLoc.first);
+ auto *FOld = SrcMgr.getFileEntryForID(FOldDecLoc.first);
+ auto &HSI = PP.getHeaderSearchInfo();
+ StringRef HdrFilename =
+ SrcMgr.getFilename(SrcMgr.getSpellingLoc(Old->getLocation()));
+
+ auto noteFromModuleOrInclude = [&](Module *Mod,
+ SourceLocation IncLoc) -> bool {
+ // Redefinition errors with modules are common with non modular mapped
+ // headers, example: a non-modular header H in module A that also gets
+ // included directly in a TU. Pointing twice to the same header/definition
+ // is confusing, try to get better diagnostics when modules is on.
+ if (IncLoc.isValid()) {
+ if (Mod) {
+ Diag(IncLoc, diag::note_redefinition_modules_same_file)
+ << HdrFilename.str() << Mod->getFullModuleName();
+ if (!Mod->DefinitionLoc.isInvalid())
+ Diag(Mod->DefinitionLoc, diag::note_defined_here)
+ << Mod->getFullModuleName();
+ } else {
+ Diag(IncLoc, diag::note_redefinition_include_same_file)
+ << HdrFilename.str();
+ }
+ return true;
+ }
+
+ return false;
+ };
+
+ // Is it the same file and same offset? Provide more information on why
+ // this leads to a redefinition error.
+ bool EmittedDiag = false;
+ if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) {
+ SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first);
+ SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first);
+ EmittedDiag = noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc);
+ EmittedDiag |= noteFromModuleOrInclude(getCurrentModule(), NewIncLoc);
+
+ // If the header has no guards, emit a note suggesting one.
+ if (FOld && !HSI.isFileMultipleIncludeGuarded(FOld))
+ Diag(Old->getLocation(), diag::note_use_ifdef_guards);
+
+ if (EmittedDiag)
+ return;
+ }
+
+ // Redefinition coming from different files or couldn't do better above.
+ Diag(Old->getLocation(), diag::note_previous_definition);
+}
+
/// We've just determined that \p Old and \p New both appear to be definitions
/// of the same variable. Either diagnose or fix the problem.
bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
@@ -3796,12 +4032,12 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
// Make the canonical definition visible.
if (auto *OldTD = Old->getDescribedVarTemplate())
- makeMergedDefinitionVisible(OldTD, New->getLocation());
- makeMergedDefinitionVisible(Old, New->getLocation());
+ makeMergedDefinitionVisible(OldTD);
+ makeMergedDefinitionVisible(Old);
return false;
} else {
Diag(New->getLocation(), diag::err_redefinition) << New;
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->setInvalidDecl();
return true;
}
@@ -4191,7 +4427,7 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
SourceLocation NameLoc,
bool IsUnion) {
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName,
- Sema::ForRedeclaration);
+ Sema::ForVisibleRedeclaration);
if (!SemaRef.LookupName(R, S)) return false;
// Pick a representative declaration.
@@ -5125,19 +5361,12 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
- if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo))
- // If this is a typedef, we'll end up spewing multiple diagnostics.
- // Just return early; it's safer. If this is a function, let the
- // "constructor cannot have a return type" diagnostic handle it.
- if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- return nullptr;
-
if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
UPPC_DeclarationType))
D.setInvalidType();
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
// See if this is a redefinition of a variable in the same scope.
if (!D.getCXXScopeSpec().isSet()) {
@@ -5163,8 +5392,10 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
CreateBuiltins = true;
- if (IsLinkageLookup)
+ if (IsLinkageLookup) {
Previous.clear(LookupRedeclarationWithLinkage);
+ Previous.setRedeclarationKind(ForExternalRedeclaration);
+ }
LookupName(Previous, S, CreateBuiltins);
} else { // Something like "int foo::x;"
@@ -5210,12 +5441,17 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
Previous.clear();
}
+ if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo))
+ // Forget that the previous declaration is the injected-class-name.
+ Previous.clear();
+
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
- // typedef (C++ [dcl.typedef]p4).
+ // tag type. Note that this applies to functions, function templates, and
+ // variables, but not to typedefs (C++ [dcl.typedef]p4) or variable templates.
if (Previous.isSingleTagDecl() &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ (TemplateParamLists.size() == 0 || R->isFunctionType()))
Previous.clear();
// Check that there are no default arguments other than in the parameters
@@ -5530,6 +5766,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,
@@ -5540,6 +5780,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() &&
@@ -5732,7 +5975,7 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
NamedDecl *NewDecl,
bool IsSpecialization,
bool IsDefinition) {
- if (OldDecl->isInvalidDecl())
+ if (OldDecl->isInvalidDecl() || NewDecl->isInvalidDecl())
return;
bool IsTemplate = false;
@@ -5838,13 +6081,30 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
NewDecl->dropAttr<DLLImportAttr>();
}
} else if (IsInline && OldImportAttr && !IsMicrosoft) {
- // In MinGW, seeing a function declared inline drops the dllimport attribute.
+ // In MinGW, seeing a function declared inline drops the dllimport
+ // attribute.
OldDecl->dropAttr<DLLImportAttr>();
NewDecl->dropAttr<DLLImportAttr>();
S.Diag(NewDecl->getLocation(),
diag::warn_dllimport_dropped_from_inline_function)
<< NewDecl << OldImportAttr;
}
+
+ // A specialization of a class template member function is processed here
+ // since it's a redeclaration. If the parent class is dllexport, the
+ // specialization inherits that attribute. This doesn't happen automatically
+ // since the parent class isn't instantiated until later.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDecl)) {
+ if (MD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization &&
+ !NewImportAttr && !NewExportAttr) {
+ if (const DLLExportAttr *ParentExportAttr =
+ MD->getParent()->getAttr<DLLExportAttr>()) {
+ DLLExportAttr *NewAttr = ParentExportAttr->clone(S.Context);
+ NewAttr->setInherited(true);
+ NewDecl->addAttr(NewAttr);
+ }
+ }
+ }
}
/// Given that we are within the definition of the given function,
@@ -5985,7 +6245,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (D.isDecompositionDeclarator()) {
- AddToScope = false;
// Take the name of the first declarator as our name for diagnostic
// purposes.
auto &Decomp = D.getDecompositionDeclarator();
@@ -6027,7 +6286,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
QualType NR = R;
while (NR->isPointerType()) {
if (NR->isFunctionPointerType()) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer_variable);
+ Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
D.setInvalidType();
break;
}
@@ -6043,19 +6302,31 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- // OpenCL v1.2 s6.9.b p4:
- // The sampler type cannot be used with the __local and __global address
- // space qualifiers.
- if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local ||
- R.getAddressSpace() == LangAS::opencl_global)) {
- Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
+ if (R->isSamplerT()) {
+ // OpenCL v1.2 s6.9.b p4:
+ // The sampler type cannot be used with the __local and __global address
+ // space qualifiers.
+ if (R.getAddressSpace() == LangAS::opencl_local ||
+ R.getAddressSpace() == LangAS::opencl_global) {
+ Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
+ }
+
+ // OpenCL v1.2 s6.12.14.1:
+ // A global sampler must be declared with either the constant address
+ // space qualifier or with the const qualifier.
+ if (DC->isTranslationUnit() &&
+ !(R.getAddressSpace() == LangAS::opencl_constant ||
+ R.isConstQualified())) {
+ Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler);
+ D.setInvalidType();
+ }
}
// OpenCL v1.2 s6.9.r:
// The event type cannot be used with the __local, __constant and __global
// address space qualifiers.
if (R->isEventT()) {
- if (R.getAddressSpace()) {
+ if (R.getAddressSpace() != LangAS::opencl_private) {
Diag(D.getLocStart(), diag::err_event_t_addr_space_qual);
D.setInvalidType();
}
@@ -6371,7 +6642,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
diag::err_thread_non_global)
<< DeclSpec::getSpecifierName(TSCS);
else if (!Context.getTargetInfo().isTLSSupported()) {
- if (getLangOpts().CUDA) {
+ if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
// Postpone error emission until we've collected attributes required to
// figure out whether it's a host or device variable and whether the
// error should be ignored.
@@ -6433,8 +6704,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
- if (getLangOpts().CUDA) {
- if (EmitTLSUnsupportedError && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD))
+ if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
+ if (EmitTLSUnsupportedError &&
+ ((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) ||
+ (getLangOpts().OpenMPIsDevice &&
+ NewVD->hasAttr<OMPDeclareTargetDeclAttr>())))
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_thread_unsupported);
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
@@ -6667,17 +6941,32 @@ NamedDecl *Sema::ActOnVariableDeclarator(
return NewTemplate;
}
+ if (IsMemberSpecialization && !NewVD->isInvalidDecl())
+ CompleteMemberSpecialization(NewVD, Previous);
+
return NewVD;
}
/// Enum describing the %select options in diag::warn_decl_shadow.
-enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field };
+enum ShadowedDeclKind {
+ SDK_Local,
+ SDK_Global,
+ SDK_StaticMember,
+ SDK_Field,
+ SDK_Typedef,
+ SDK_Using
+};
/// Determine what kind of declaration we're shadowing.
static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl,
const DeclContext *OldDC) {
- if (isa<RecordDecl>(OldDC))
+ if (isa<TypeAliasDecl>(ShadowedDecl))
+ return SDK_Using;
+ else if (isa<TypedefDecl>(ShadowedDecl))
+ return SDK_Typedef;
+ else if (isa<RecordDecl>(OldDC))
return isa<FieldDecl>(ShadowedDecl) ? SDK_Field : SDK_StaticMember;
+
return OldDC->isFileContext() ? SDK_Global : SDK_Local;
}
@@ -6692,28 +6981,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.
///
@@ -6723,7 +7032,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();
@@ -6735,13 +7044,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))
@@ -6755,11 +7064,12 @@ void Sema::CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl,
}
}
- DeclContext *OldDC = ShadowedDecl->getDeclContext();
+ DeclContext *OldDC = ShadowedDecl->getDeclContext()->getRedeclContext();
unsigned WarningDiag = diag::warn_decl_shadow;
SourceLocation CaptureLoc;
- if (isa<VarDecl>(ShadowedDecl) && NewDC && isa<CXXMethodDecl>(NewDC)) {
+ if (isa<VarDecl>(D) && isa<VarDecl>(ShadowedDecl) && NewDC &&
+ isa<CXXMethodDecl>(NewDC)) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
if (RD->getLambdaCaptureDefault() == LCD_None) {
@@ -6773,10 +7083,26 @@ void Sema::CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl,
// Remember that this was shadowed so we can avoid the warning if the
// shadowed decl isn't captured and the warning settings allow it.
cast<LambdaScopeInfo>(getCurFunction())
- ->ShadowingDecls.push_back({D, cast<VarDecl>(ShadowedDecl)});
+ ->ShadowingDecls.push_back(
+ {cast<VarDecl>(D), cast<VarDecl>(ShadowedDecl)});
return;
}
}
+
+ if (cast<VarDecl>(ShadowedDecl)->hasLocalStorage()) {
+ // A variable can't shadow a local variable in an enclosing scope, if
+ // they are separated by a non-capturing declaration context.
+ for (DeclContext *ParentDC = NewDC;
+ ParentDC && !ParentDC->Equals(OldDC);
+ ParentDC = getLambdaAwareParentOfDeclContext(ParentDC)) {
+ // Only block literals, captured statements, and lambda expressions
+ // can capture; other scopes don't.
+ if (!isa<BlockDecl>(ParentDC) && !isa<CapturedDecl>(ParentDC) &&
+ !isLambdaCallOperator(ParentDC)) {
+ return;
+ }
+ }
+ }
}
}
@@ -6834,7 +7160,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
return;
LookupResult R(*this, D->getDeclName(), D->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
LookupName(R, S);
if (NamedDecl *ShadowedDecl = getShadowedDeclaration(D, R))
CheckShadow(D, ShadowedDecl, R);
@@ -7007,9 +7333,9 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
// This includes arrays of objects with address space qualifiers, but not
// automatic variables that point to other address spaces.
// ISO/IEC TR 18037 S5.1.2
- if (!getLangOpts().OpenCL
- && NewVD->hasLocalStorage() && T.getAddressSpace() != 0) {
- Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl);
+ if (!getLangOpts().OpenCL && NewVD->hasLocalStorage() &&
+ T.getAddressSpace() != LangAS::Default) {
+ Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 0;
NewVD->setInvalidDecl();
return;
}
@@ -7074,11 +7400,11 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
- // OpenCL v1.1 s6.5.2 and s6.5.3 no local or constant variables
- // in functions.
if (T.getAddressSpace() == LangAS::opencl_constant ||
T.getAddressSpace() == LangAS::opencl_local) {
FunctionDecl *FD = getCurFunctionDecl();
+ // OpenCL v1.1 s6.5.2 and s6.5.3: no local or constant variables
+ // in functions.
if (FD && !FD->hasAttr<OpenCLKernelAttr>()) {
if (T.getAddressSpace() == LangAS::opencl_constant)
Diag(NewVD->getLocation(), diag::err_opencl_function_variable)
@@ -7089,6 +7415,25 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
+ // OpenCL v2.0 s6.5.2 and s6.5.3: local and constant variables must be
+ // in the outermost scope of a kernel function.
+ if (FD && FD->hasAttr<OpenCLKernelAttr>()) {
+ if (!getCurScope()->isFunctionScope()) {
+ if (T.getAddressSpace() == LangAS::opencl_constant)
+ Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope)
+ << "constant";
+ else
+ Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope)
+ << "local";
+ NewVD->setInvalidDecl();
+ return;
+ }
+ }
+ } else if (T.getAddressSpace() != LangAS::opencl_private) {
+ // Do not allow other address spaces on automatic variable.
+ Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1;
+ NewVD->setInvalidDecl();
+ return;
}
}
}
@@ -7364,6 +7709,10 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
} // end anonymous namespace
+void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) {
+ TypoCorrectedFunctionDefinitions.insert(F);
+}
+
/// \brief Generate diagnostics for an invalid function redeclaration.
///
/// This routine handles generating the diagnostic messages for an invalid
@@ -7387,7 +7736,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
IsLocalFriend ? Sema::LookupLocalFriendName
: Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ Sema::ForVisibleRedeclaration);
NewFD->setInvalidDecl();
if (IsLocalFriend)
@@ -7461,6 +7810,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
if ((*I)->getCanonicalDecl() == Canonical)
Correction.setCorrectionDecl(*I);
+ // Let Sema know about the correction.
+ SemaRef.MarkTypoCorrectedFunctionDefinition(Result);
SemaRef.diagnoseTypo(
Correction,
SemaRef.PDiag(IsLocalFriend
@@ -7713,7 +8064,8 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PointeeType->isPointerType())
return PtrPtrKernelParam;
if (PointeeType.getAddressSpace() == LangAS::opencl_generic ||
- PointeeType.getAddressSpace() == 0)
+ PointeeType.getAddressSpace() == LangAS::opencl_private ||
+ PointeeType.getAddressSpace() == LangAS::Default)
return InvalidAddrSpacePtrKernelParam;
return PtrKernelParam;
}
@@ -7724,10 +8076,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PT->isImageType())
return PtrKernelParam;
- if (PT->isBooleanType())
- return InvalidKernelParam;
-
- if (PT->isEventT())
+ if (PT->isBooleanType() || PT->isEventT() || PT->isReserveIDT())
return InvalidKernelParam;
// OpenCL extension spec v1.2 s9.5:
@@ -8457,6 +8806,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setInvalidDecl();
}
+ // Apply an implicit SectionAttr if '#pragma clang section text' is active
+ if (PragmaClangTextSection.Valid && D.isFunctionDefinition() &&
+ !NewFD->hasAttr<SectionAttr>()) {
+ NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(Context,
+ PragmaClangTextSection.SectionName,
+ PragmaClangTextSection.PragmaLocation));
+ }
+
// Apply an implicit SectionAttr if #pragma code_seg is active.
if (CodeSegStack.CurrentValue && D.isFunctionDefinition() &&
!NewFD->hasAttr<SectionAttr>()) {
@@ -8477,10 +8834,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
// type declaration will generate a compilation error.
- unsigned AddressSpace = NewFD->getReturnType().getAddressSpace();
- if (AddressSpace == LangAS::opencl_local ||
- AddressSpace == LangAS::opencl_global ||
- AddressSpace == LangAS::opencl_constant) {
+ LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
+ if (AddressSpace != LangAS::Default) {
Diag(NewFD->getLocation(),
diag::err_opencl_return_value_with_address_space);
NewFD->setInvalidDecl();
@@ -8607,10 +8962,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::ext_function_specialization_in_class :
diag::err_function_specialization_in_class)
<< NewFD->getDeclName();
- } else if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs
- : nullptr),
- Previous))
+ } else if (!NewFD->isInvalidDecl() &&
+ CheckFunctionTemplateSpecialization(
+ NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr),
+ Previous))
NewFD->setInvalidDecl();
// C++ [dcl.stc]p1:
@@ -8840,12 +9195,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ MarkUnusedFileScopedDecl(NewFD);
+
if (getLangOpts().CPlusPlus) {
if (FunctionTemplate) {
if (NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
return FunctionTemplate;
}
+
+ if (isMemberSpecialization && !NewFD->isInvalidDecl())
+ CompleteMemberSpecialization(NewFD, Previous);
}
if (NewFD->hasAttr<OpenCLKernelAttr>()) {
@@ -8885,8 +9245,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- MarkUnusedFileScopedDecl(NewFD);
-
// Here we have an function template explicit specialization at class scope.
// The actually specialization will be postponed to template instatiation
// time via the ClassScopeFunctionSpecializationDecl node.
@@ -8960,6 +9318,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
bool Redeclaration = false;
NamedDecl *OldDecl = nullptr;
+ bool MayNeedOverloadableChecks = false;
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
@@ -8968,13 +9327,14 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
- if (!AllowOverloadingOfFunction(Previous, Context)) {
+ if (!AllowOverloadingOfFunction(Previous, Context, NewFD)) {
NamedDecl *Candidate = Previous.getRepresentativeDecl();
if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) {
Redeclaration = true;
OldDecl = Candidate;
}
} else {
+ MayNeedOverloadableChecks = true;
switch (CheckOverload(S, NewFD, Previous, OldDecl,
/*NewIsUsingDecl*/ false)) {
case Ovl_Match:
@@ -8989,22 +9349,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Redeclaration = false;
break;
}
-
- if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
- // If a function name is overloadable in C, then every function
- // with that name must be marked "overloadable".
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- NamedDecl *OverloadedDecl = nullptr;
- if (Redeclaration)
- OverloadedDecl = OldDecl;
- else if (!Previous.empty())
- OverloadedDecl = Previous.getRepresentativeDecl();
- if (OverloadedDecl)
- Diag(OverloadedDecl->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
}
}
@@ -9019,15 +9363,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
MergeTypeWithPrevious = false;
// ... except in the presence of __attribute__((overloadable)).
- if (OldDecl->hasAttr<OverloadableAttr>()) {
- if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- Diag(Previous.getFoundDecl()->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
+ if (OldDecl->hasAttr<OverloadableAttr>() ||
+ NewFD->hasAttr<OverloadableAttr>()) {
if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
+ MayNeedOverloadableChecks = true;
Redeclaration = false;
OldDecl = nullptr;
}
@@ -9107,7 +9446,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) {
FunctionDecl *const OldTemplatedDecl =
OldTemplateDecl->getTemplatedDecl();
+ // FIXME: This assert will not hold in the presence of modules.
assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl);
+ // FIXME: We need an update record for this AST mutation.
OldTemplatedDecl->setDeletedAsWritten(false);
}
}
@@ -9120,6 +9461,29 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
NewFD->setAccess(OldDecl->getAccess());
}
}
+ } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks &&
+ !NewFD->getAttr<OverloadableAttr>()) {
+ assert((Previous.empty() ||
+ llvm::any_of(Previous,
+ [](const NamedDecl *ND) {
+ return ND->hasAttr<OverloadableAttr>();
+ })) &&
+ "Non-redecls shouldn't happen without overloadable present");
+
+ auto OtherUnmarkedIter = llvm::find_if(Previous, [](const NamedDecl *ND) {
+ const auto *FD = dyn_cast<FunctionDecl>(ND);
+ return FD && !FD->hasAttr<OverloadableAttr>();
+ });
+
+ if (OtherUnmarkedIter != Previous.end()) {
+ Diag(NewFD->getLocation(),
+ diag::err_attribute_overloadable_multiple_unmarked_overloads);
+ Diag((*OtherUnmarkedIter)->getLocation(),
+ diag::note_attribute_overloadable_prev_overload)
+ << false;
+
+ NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
+ }
}
// Semantic checking for this function declaration (in isolation).
@@ -9260,7 +9624,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
AnyNoexcept |= HasNoexcept(T);
if (AnyNoexcept)
Diag(NewFD->getLocation(),
- diag::warn_cxx1z_compat_exception_spec_in_signature)
+ diag::warn_cxx17_compat_exception_spec_in_signature)
<< NewFD;
}
@@ -9504,7 +9868,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;
@@ -9708,14 +10072,9 @@ namespace {
void VisitCallExpr(CallExpr *E) {
// Treat std::move as a use.
- if (E->getNumArgs() == 1) {
- if (FunctionDecl *FD = E->getDirectCallee()) {
- if (FD->isInStdNamespace() && FD->getIdentifier() &&
- FD->getIdentifier()->isStr("move")) {
- HandleValue(E->getArg(0));
- return;
- }
- }
+ if (E->isCallToStdMove()) {
+ HandleValue(E->getArg(0));
+ return;
}
Inherited::VisitCallExpr(E);
@@ -10102,18 +10461,6 @@ 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 = InitializationKind::CreateForInit(
VDecl->getLocation(), DirectInit, Init);
@@ -10179,7 +10526,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);
@@ -10209,23 +10557,36 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
VDecl->setInit(Init);
if (VDecl->isLocalVarDecl()) {
+ // Don't check the initializer if the declaration is malformed.
+ if (VDecl->isInvalidDecl()) {
+ // do nothing
+
+ // OpenCL v1.2 s6.5.3: __constant locals must be constant-initialized.
+ // This is true even in OpenCL C++.
+ } else if (VDecl->getType().getAddressSpace() == LangAS::opencl_constant) {
+ CheckForConstantInitializer(Init, DclT);
+
+ // Otherwise, C++ does not restrict the initializer.
+ } else if (getLangOpts().CPlusPlus) {
+ // do nothing
+
// C99 6.7.8p4: All the expressions in an initializer for an object that has
// static storage duration shall be constant expressions or string literals.
- // C++ does not have this restriction.
- if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) {
+ } else if (VDecl->getStorageClass() == SC_Static) {
+ CheckForConstantInitializer(Init, DclT);
+
+ // C89 is stricter than C99 for aggregate initializers.
+ // C89 6.5.7p3: All the expressions [...] in an initializer list
+ // for an object that has aggregate or union type shall be
+ // constant expressions.
+ } else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
+ isa<InitListExpr>(Init)) {
const Expr *Culprit;
- if (VDecl->getStorageClass() == SC_Static)
- CheckForConstantInitializer(Init, DclT);
- // C89 is stricter than C99 for non-static aggregate types.
- // C89 6.5.7p3: All the expressions [...] in an initializer list
- // for an object that has aggregate or union type shall be
- // constant expressions.
- else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
- isa<InitListExpr>(Init) &&
- !Init->isConstantInitializer(Context, false, &Culprit))
+ if (!Init->isConstantInitializer(Context, false, &Culprit)) {
Diag(Culprit->getExprLoc(),
diag::ext_aggregate_init_not_constant)
<< Culprit->getSourceRange();
+ }
}
} else if (VDecl->isStaticDataMember() && !VDecl->isInline() &&
VDecl->getLexicalDeclContext()->isRecord()) {
@@ -10243,7 +10604,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
@@ -10413,18 +10774,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)
@@ -10873,7 +11222,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
@@ -10892,9 +11242,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
bool IsGlobal = GlobalStorage && !var->isStaticLocal();
QualType baseType = Context.getBaseElementType(type);
- if (!var->getDeclContext()->isDependentContext() &&
- Init && !Init->isValueDependent()) {
-
+ if (Init && !Init->isValueDependent()) {
if (var->isConstexpr()) {
SmallVector<PartialDiagnosticAt, 8> Notes;
if (!var->evaluateValue(Notes) || !var->isInitICE()) {
@@ -10931,6 +11279,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
<< Init->getSourceRange();
Diag(attr->getLocation(), diag::note_declared_required_constant_init_here)
<< attr->getRange();
+ if (getLangOpts().CPlusPlus11) {
+ APValue Value;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
+ Init->EvaluateAsInitializer(Value, getASTContext(), var, Notes);
+ for (auto &it : Notes)
+ Diag(it.first, it.second);
+ } else {
+ Diag(CacheCulprit->getExprLoc(),
+ diag::note_invalid_subexpr_in_const_expr)
+ << CacheCulprit->getSourceRange();
+ }
}
}
else if (!var->isConstexpr() && IsGlobal &&
@@ -10970,8 +11329,7 @@ static bool hasDependentAlignment(VarDecl *VD) {
/// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform
/// any semantic actions necessary after any initializer has been attached.
-void
-Sema::FinalizeDeclaration(Decl *ThisDecl) {
+void Sema::FinalizeDeclaration(Decl *ThisDecl) {
// Note that we are no longer parsing the initializer for this declaration.
ParsingInitForAutoVars.erase(ThisDecl);
@@ -10979,6 +11337,23 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!VD)
return;
+ // Apply an implicit SectionAttr if '#pragma clang section bss|data|rodata' is active
+ if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() &&
+ !inTemplateInstantiation() && !VD->hasAttr<SectionAttr>()) {
+ if (PragmaClangBSSSection.Valid)
+ VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(Context,
+ PragmaClangBSSSection.SectionName,
+ PragmaClangBSSSection.PragmaLocation));
+ if (PragmaClangDataSection.Valid)
+ VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(Context,
+ PragmaClangDataSection.SectionName,
+ PragmaClangDataSection.PragmaLocation));
+ if (PragmaClangRodataSection.Valid)
+ VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(Context,
+ PragmaClangRodataSection.SectionName,
+ PragmaClangRodataSection.PragmaLocation));
+ }
+
if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) {
for (auto *BD : DD->bindings()) {
FinalizeDeclaration(BD);
@@ -11136,9 +11511,8 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (DC->getRedeclContext()->isFileContext() && VD->isExternallyVisible())
AddPushedVisibilityAttribute(VD);
- // FIXME: Warn on unused templates.
- if (VD->isFileVarDecl() && !VD->getDescribedVarTemplate() &&
- !isa<VarTemplatePartialSpecializationDecl>(VD))
+ // FIXME: Warn on unused var template partial specializations.
+ if (VD->isFileVarDecl() && !isa<VarTemplatePartialSpecializationDecl>(VD))
MarkUnusedFileScopedDecl(VD);
// Now we have parsed the initializer and can update the table of magic
@@ -11344,6 +11718,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
StorageClass SC = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
SC = SC_Register;
+ // In C++11, the 'register' storage class specifier is deprecated.
+ // In C++17, it is not allowed, but we tolerate it as an extension.
+ if (getLangOpts().CPlusPlus11) {
+ Diag(DS.getStorageClassSpecLoc(),
+ getLangOpts().CPlusPlus1z ? diag::ext_register_storage_class
+ : diag::warn_deprecated_register)
+ << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+ }
} else if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
SC = SC_Auto;
@@ -11397,7 +11779,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Check for redeclaration of parameters, e.g. int foo(int x, int x);
if (II) {
LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
LookupName(R, S);
if (R.isSingleResult()) {
NamedDecl *PrevDecl = R.getFoundDecl();
@@ -11566,13 +11948,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
- if (T.getAddressSpace() != 0) {
- // OpenCL allows function arguments declared to be an array of a type
- // to be qualified with an address space.
- if (!(getLangOpts().OpenCL && T->isArrayType())) {
- Diag(NameLoc, diag::err_arg_with_address_space);
- New->setInvalidDecl();
- }
+ if (T.getAddressSpace() != LangAS::Default &&
+ // OpenCL allows function arguments declared to be an array of a type
+ // to be qualified with an address space.
+ !(getLangOpts().OpenCL &&
+ (T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private))) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ New->setInvalidDecl();
}
return New;
@@ -11698,6 +12080,11 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
if (canRedefineFunction(Definition, getLangOpts()))
return;
+ // Don't emit an error when this is redefinition of a typo-corrected
+ // definition.
+ if (TypoCorrectedFunctionDefinitions.count(Definition))
+ return;
+
// If we don't have a visible definition of the function, and it's inline or
// a template, skip the new definition.
if (SkipBody && !hasVisibleDefinition(Definition) &&
@@ -11707,9 +12094,8 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
Definition->getNumTemplateParameterLists())) {
SkipBody->ShouldSkip = true;
if (auto *TD = Definition->getDescribedFunctionTemplate())
- makeMergedDefinitionVisible(TD, FD->getLocation());
- makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition),
- FD->getLocation());
+ makeMergedDefinitionVisible(TD);
+ makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition));
return;
}
@@ -11795,8 +12181,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
FD->setInvalidDecl();
}
- // See if this is a redefinition.
- if (!FD->isLateTemplateParsed()) {
+ // See if this is a redefinition. If 'will have body' is already set, then
+ // these checks were already performed when it was set.
+ if (!FD->willHaveBody() && !FD->isLateTemplateParsed()) {
CheckForFunctionRedefinition(FD, nullptr, SkipBody);
// If we're skipping the body, we're done. Don't enter the scope.
@@ -11989,11 +12376,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
- if (getLangOpts().CoroutinesTS && getCurFunction()->CoroutinePromise)
+ if (getLangOpts().CoroutinesTS && getCurFunction()->isCoroutine())
CheckCompletedCoroutineBody(FD, Body);
if (FD) {
FD->setBody(Body);
+ FD->setWillHaveBody(false);
if (getLangOpts().CPlusPlus14) {
if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
@@ -12033,18 +12421,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
}
- // The only way to be included in UndefinedButUsed is if there is an
- // ODR use before the definition. Avoid the expensive map lookup if this
- // is the first declaration.
- if (!FD->isFirstDecl() && FD->getPreviousDecl()->isUsed()) {
- if (!FD->isExternallyVisible())
- UndefinedButUsed.erase(FD);
- else if (FD->isInlined() &&
- !LangOpts.GNUInline &&
- (!FD->getPreviousDecl()->hasAttr<GNUInlineAttr>()))
- UndefinedButUsed.erase(FD);
- }
-
// If the function implicitly returns zero (like 'main') or is naked,
// don't complain about missing return statements.
if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>())
@@ -12111,7 +12487,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
TypeSourceInfo *TI = FD->getTypeSourceInfo();
TypeLoc TL = TI->getTypeLoc();
FunctionTypeLoc FTL = TL.getAsAdjusted<FunctionTypeLoc>();
- Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1;
+ Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2;
}
}
@@ -12308,25 +12684,50 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
IdentifierInfo &II, Scope *S) {
+ Scope *BlockScope = S;
+ while (!BlockScope->isCompoundStmtScope() && BlockScope->getParent())
+ BlockScope = BlockScope->getParent();
+
// Before we produce a declaration for an implicitly defined
// function, see whether there was a locally-scoped declaration of
// this name as a function or variable. If so, use that
// (non-visible) declaration, and complain about it.
- if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) {
- Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev;
- Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
- return ExternCPrev;
+ NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II);
+ if (ExternCPrev) {
+ // We still need to inject the function into the enclosing block scope so
+ // that later (non-call) uses can see it.
+ PushOnScopeChains(ExternCPrev, BlockScope, /*AddToContext*/false);
+
+ // C89 footnote 38:
+ // If in fact it is not defined as having type "function returning int",
+ // the behavior is undefined.
+ if (!isa<FunctionDecl>(ExternCPrev) ||
+ !Context.typesAreCompatible(
+ cast<FunctionDecl>(ExternCPrev)->getType(),
+ Context.getFunctionNoProtoType(Context.IntTy))) {
+ Diag(Loc, diag::ext_use_out_of_scope_declaration)
+ << ExternCPrev << !getLangOpts().C99;
+ Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
+ return ExternCPrev;
+ }
}
// Extension in C99. Legal in C90, but warn about it.
+ // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported.
unsigned diag_id;
if (II.getName().startswith("__builtin_"))
diag_id = diag::warn_builtin_unknown;
- else if (getLangOpts().C99)
+ else if (getLangOpts().C99 || getLangOpts().OpenCL)
diag_id = diag::ext_implicit_function_decl;
else
diag_id = diag::warn_implicit_function_decl;
- Diag(Loc, diag_id) << &II;
+ Diag(Loc, diag_id) << &II << getLangOpts().OpenCL;
+
+ // If we found a prior declaration of this function, don't bother building
+ // another one. We've already pushed that one into scope, so there's nothing
+ // more to do.
+ if (ExternCPrev)
+ return ExternCPrev;
// Because typo correction is expensive, only do it if the implicit
// function declaration is going to be treated as an error.
@@ -12378,16 +12779,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
SourceLocation());
D.SetIdentifier(&II, Loc);
- // Insert this function into translation-unit scope.
-
- DeclContext *PrevDC = CurContext;
- CurContext = Context.getTranslationUnitDecl();
-
- FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
+ // Insert this function into the enclosing block scope.
+ FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(BlockScope, D));
FD->setImplicit();
- CurContext = PrevDC;
-
AddKnownFunctionAttributes(FD);
return FD;
@@ -12848,7 +13243,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag,
TypeResult UnderlyingType,
- bool IsTypeSpecifier, SkipBodyInfo *SkipBody) {
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ SkipBodyInfo *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -12943,10 +13339,60 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
bool isStdBadAlloc = false;
bool isStdAlignValT = false;
- RedeclarationKind Redecl = ForRedeclaration;
+ RedeclarationKind Redecl = forRedeclarationInCurContext();
if (TUK == TUK_Friend || TUK == TUK_Reference)
Redecl = NotForRedeclaration;
+ /// Create a new tag decl in C/ObjC. Since the ODR-like semantics for ObjC/C
+ /// implemented asks for structural equivalence checking, the returned decl
+ /// here is passed back to the parser, allowing the tag body to be parsed.
+ auto createTagFromNewDecl = [&]() -> TagDecl * {
+ assert(!getLangOpts().CPlusPlus && "not meant for C++ usage");
+ // If there is an identifier, use the location of the identifier as the
+ // location of the decl, otherwise use the location of the struct/union
+ // keyword.
+ SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
+ TagDecl *New = nullptr;
+
+ if (Kind == TTK_Enum) {
+ New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr,
+ ScopedEnum, ScopedEnumUsesClassTag,
+ !EnumUnderlying.isNull());
+ // If this is an undefined enum, bail.
+ if (TUK != TUK_Definition && !Invalid)
+ return nullptr;
+ if (EnumUnderlying) {
+ EnumDecl *ED = cast<EnumDecl>(New);
+ if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo *>())
+ ED->setIntegerTypeSourceInfo(TI);
+ else
+ ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0));
+ ED->setPromotionType(ED->getIntegerType());
+ }
+ } else { // struct/union
+ New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name,
+ nullptr);
+ }
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) {
+ // Add alignment attributes if necessary; these attributes are checked
+ // when the ASTContext lays out the structure.
+ //
+ // It is important for implementing the correct semantics that this
+ // happen here (in ActOnTag). The #pragma pack stack is
+ // maintained as a result of parser callbacks which can occur at
+ // many points during the parsing of a struct declaration (because
+ // the #pragma tokens are effectively skipped over during the
+ // parsing of the struct).
+ if (TUK == TUK_Definition) {
+ AddAlignmentAttributesForRecord(RD);
+ AddMsStructLayoutForRecord(RD);
+ }
+ }
+ New->setLexicalDeclContext(CurContext);
+ return New;
+ };
+
LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl);
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -13118,11 +13564,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// also need to do a redeclaration lookup there, just in case
// there's a shadow friend decl.
if (Name && Previous.empty() &&
- (TUK == TUK_Reference || TUK == TUK_Friend)) {
+ (TUK == TUK_Reference || TUK == TUK_Friend || IsTemplateParamOrArg)) {
if (Invalid) goto CreateNewDecl;
assert(SS.isEmpty());
- if (TUK == TUK_Reference) {
+ if (TUK == TUK_Reference || IsTemplateParamOrArg) {
// C++ [basic.scope.pdecl]p5:
// -- for an elaborated-type-specifier of the form
//
@@ -13171,10 +13617,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// type declared by an elaborated-type-specifier. In C that is not correct
// and we should instead merge compatible types found by lookup.
if (getLangOpts().CPlusPlus) {
- Previous.setRedeclarationKind(ForRedeclaration);
+ Previous.setRedeclarationKind(forRedeclarationInCurContext());
LookupQualifiedName(Previous, SearchDC);
} else {
- Previous.setRedeclarationKind(ForRedeclaration);
+ Previous.setRedeclarationKind(forRedeclarationInCurContext());
LookupName(Previous, S);
}
}
@@ -13314,9 +13760,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else if (TUK == TUK_Reference &&
(PrevTagDecl->getFriendObjectKind() ==
Decl::FOK_Undeclared ||
- PP.getModuleContainingLocation(
- PrevDecl->getLocation()) !=
- PP.getModuleContainingLocation(KWLoc)) &&
+ PrevDecl->getOwningModule() != getCurrentModule()) &&
SS.isEmpty()) {
// This declaration is a reference to an existing entity, but
// has different visibility from that entity: it either makes
@@ -13354,16 +13798,28 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TSK_ExplicitSpecialization;
}
+ // Note that clang allows ODR-like semantics for ObjC/C, i.e., do
+ // not keep more that one definition around (merge them). However,
+ // ensure the decl passes the structural compatibility check in
+ // C11 6.2.7/1 (or 6.1.2.6/1 in C89).
NamedDecl *Hidden = nullptr;
- if (SkipBody && getLangOpts().CPlusPlus &&
- !hasVisibleDefinition(Def, &Hidden)) {
+ if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
// There is a definition of this tag, but it is not visible. We
// explicitly make use of C++'s one definition rule here, and
// assume that this definition is identical to the hidden one
// we already have. Make the existing definition visible and
// use it in place of this one.
- SkipBody->ShouldSkip = true;
- makeMergedDefinitionVisible(Hidden, KWLoc);
+ if (!getLangOpts().CPlusPlus) {
+ // Postpone making the old definition visible until after we
+ // complete parsing the new one and do the structural
+ // comparison.
+ SkipBody->CheckSameAsPrevious = true;
+ SkipBody->New = createTagFromNewDecl();
+ SkipBody->Previous = Hidden;
+ } else {
+ SkipBody->ShouldSkip = true;
+ makeMergedDefinitionVisible(Hidden);
+ }
return Def;
} else if (!IsExplicitSpecializationAfterInstantiation) {
// A redeclaration in function prototype scope in C isn't
@@ -13372,7 +13828,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name;
else
Diag(NameLoc, diag::err_redefinition) << Name;
- Diag(Def->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Def,
+ NameLoc.isValid() ? NameLoc : KWLoc);
// If this is a redefinition, recover by making this
// struct be anonymous, which will make any later
// references get the previous definition.
@@ -13462,7 +13919,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// The tag name clashes with something else in the target scope,
// issue an error and recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(PrevDecl, NameLoc);
Name = nullptr;
Invalid = true;
}
@@ -13503,7 +13960,8 @@ CreateNewDecl:
// If this is an undefined enum, warn.
if (TUK != TUK_Definition && !Invalid) {
TagDecl *Def;
- if ((getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) &&
+ if (!EnumUnderlyingIsImplicit &&
+ (getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) &&
cast<EnumDecl>(New)->isFixed()) {
// C++0x: 7.2p2: opaque-enum-declaration.
// Conflicts are diagnosed above. Do nothing.
@@ -13555,12 +14013,20 @@ CreateNewDecl:
// C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration [...].
- if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) {
+ if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
+ TUK == TUK_Definition) {
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTagDeclType(New);
Invalid = true;
}
+ if (!Invalid && getLangOpts().CPlusPlus && TUK == TUK_Definition &&
+ DC->getDeclKind() == Decl::Enum) {
+ Diag(New->getLocation(), diag::err_type_defined_in_enum)
+ << Context.getTagDeclType(New);
+ Invalid = true;
+ }
+
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
if (SS.isSet()) {
@@ -13588,7 +14054,7 @@ CreateNewDecl:
// the ASTContext lays out the structure.
//
// It is important for implementing the correct semantics that this
- // happen here (in act on tag decl). The #pragma pack stack is
+ // happen here (in ActOnTag). The #pragma pack stack is
// maintained as a result of parser callbacks which can occur at
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
@@ -13652,11 +14118,15 @@ CreateNewDecl:
if (!Invalid && SearchDC->isRecord())
SetMemberAccessSpecifier(New, PrevDecl, AS);
+ if (PrevDecl)
+ CheckRedeclarationModuleOwnership(New, PrevDecl);
+
if (TUK == TUK_Definition)
New->startDefinition();
if (Attr)
ProcessDeclAttributeList(S, New, Attr);
+ AddPragmaAttributes(S, New);
// If this has an identifier, add it to the scope stack.
if (TUK == TUK_Friend) {
@@ -13693,6 +14163,9 @@ CreateNewDecl:
// record.
AddPushedVisibilityAttribute(New);
+ if (isMemberSpecialization && !New->isInvalidDecl())
+ CompleteMemberSpecialization(New, Previous);
+
OwnedDecl = true;
// In C++, don't return an invalid declaration. We can't recover well from
// the cases where we make the type anonymous.
@@ -13720,6 +14193,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
AddPushedVisibilityAttribute(Tag);
}
+bool Sema::ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev,
+ SkipBodyInfo &SkipBody) {
+ if (!hasStructuralCompatLayout(Prev, SkipBody.New))
+ return false;
+
+ // Make the previous decl visible.
+ makeMergedDefinitionVisible(SkipBody.Previous);
+ return true;
+}
+
Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
assert(isa<ObjCContainerDecl>(IDecl) &&
"ActOnObjCContainerStartDefinition - Not ObjCContainerDecl");
@@ -13780,10 +14263,8 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
RD->completeDefinition();
}
- if (auto *RD = dyn_cast<CXXRecordDecl>(Tag)) {
+ if (isa<CXXRecordDecl>(Tag)) {
FieldCollector->FinishClass();
- if (Context.getLangOpts().Modules)
- RD->computeODRHash();
}
// Exit this scope of this tag's definition.
@@ -13966,7 +14447,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
}
// TR 18037 does not allow fields to be declared with address spaces.
- if (T.getQualifiers().hasAddressSpace()) {
+ if (T.getQualifiers().hasAddressSpace() ||
+ T->isDependentAddressSpaceType() ||
+ T->getBaseElementTypeUnsafe()->isDependentAddressSpaceType()) {
Diag(Loc, diag::err_field_with_address_space);
D.setInvalidType();
}
@@ -13991,7 +14474,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = nullptr;
- LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
+ LookupResult Previous(*this, II, Loc, LookupMemberName,
+ ForVisibleRedeclaration);
LookupName(Previous, S);
switch (Previous.getResultKind()) {
case LookupResult::Found:
@@ -14379,7 +14863,7 @@ Decl *Sema::ActOnIvar(Scope *S,
if (II) {
NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S)
&& !isa<TagDecl>(PrevDecl)) {
Diag(Loc, diag::err_duplicate_member) << II;
@@ -14491,7 +14975,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);
@@ -14521,6 +15005,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// possibly recursively, a member that is such a structure)
// shall not be a member of a structure or an element of an
// array.
+ bool IsLastField = (i + 1 == Fields.end());
if (FDTy->isFunctionType()) {
// Field declared as a function.
Diag(FD->getLocation(), diag::err_field_declared_as_function)
@@ -14528,60 +15013,70 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (FDTy->isIncompleteArrayType() && Record &&
- ((i + 1 == Fields.end() && !Record->isUnion()) ||
- ((getLangOpts().MicrosoftExt ||
- getLangOpts().CPlusPlus) &&
- (i + 1 == Fields.end() || Record->isUnion())))) {
- // Flexible array member.
- // Microsoft and g++ is more permissive regarding flexible array.
- // It will accept flexible array in union and also
- // as the sole element of a struct/class.
- unsigned DiagID = 0;
- if (Record->isUnion())
- DiagID = getLangOpts().MicrosoftExt
- ? diag::ext_flexible_array_union_ms
- : getLangOpts().CPlusPlus
- ? diag::ext_flexible_array_union_gnu
- : diag::err_flexible_array_union;
- else if (NumNamedMembers < 1)
- DiagID = getLangOpts().MicrosoftExt
- ? diag::ext_flexible_array_empty_aggregate_ms
- : getLangOpts().CPlusPlus
- ? diag::ext_flexible_array_empty_aggregate_gnu
- : diag::err_flexible_array_empty_aggregate;
-
- if (DiagID)
- Diag(FD->getLocation(), DiagID) << FD->getDeclName()
- << Record->getTagKind();
- // While the layout of types that contain virtual bases is not specified
- // by the C++ standard, both the Itanium and Microsoft C++ ABIs place
- // virtual bases after the derived members. This would make a flexible
- // array member declared at the end of an object not adjacent to the end
- // of the type.
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record))
- if (RD->getNumVBases() != 0)
- Diag(FD->getLocation(), diag::err_flexible_array_virtual_base)
+ } else if (FDTy->isIncompleteArrayType() &&
+ (Record || isa<ObjCContainerDecl>(EnclosingDecl))) {
+ if (Record) {
+ // Flexible array member.
+ // Microsoft and g++ is more permissive regarding flexible array.
+ // It will accept flexible array in union and also
+ // as the sole element of a struct/class.
+ unsigned DiagID = 0;
+ if (!Record->isUnion() && !IsLastField) {
+ Diag(FD->getLocation(), diag::err_flexible_array_not_at_end)
+ << FD->getDeclName() << FD->getType() << Record->getTagKind();
+ Diag((*(i + 1))->getLocation(), diag::note_next_field_declaration);
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ } else if (Record->isUnion())
+ DiagID = getLangOpts().MicrosoftExt
+ ? diag::ext_flexible_array_union_ms
+ : getLangOpts().CPlusPlus
+ ? diag::ext_flexible_array_union_gnu
+ : diag::err_flexible_array_union;
+ else if (NumNamedMembers < 1)
+ DiagID = getLangOpts().MicrosoftExt
+ ? diag::ext_flexible_array_empty_aggregate_ms
+ : getLangOpts().CPlusPlus
+ ? diag::ext_flexible_array_empty_aggregate_gnu
+ : diag::err_flexible_array_empty_aggregate;
+
+ if (DiagID)
+ Diag(FD->getLocation(), DiagID) << FD->getDeclName()
+ << Record->getTagKind();
+ // While the layout of types that contain virtual bases is not specified
+ // by the C++ standard, both the Itanium and Microsoft C++ ABIs place
+ // virtual bases after the derived members. This would make a flexible
+ // array member declared at the end of an object not adjacent to the end
+ // of the type.
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record))
+ if (RD->getNumVBases() != 0)
+ Diag(FD->getLocation(), diag::err_flexible_array_virtual_base)
+ << FD->getDeclName() << Record->getTagKind();
+ if (!getLangOpts().C99)
+ Diag(FD->getLocation(), diag::ext_c99_flexible_array_member)
<< FD->getDeclName() << Record->getTagKind();
- if (!getLangOpts().C99)
- Diag(FD->getLocation(), diag::ext_c99_flexible_array_member)
- << FD->getDeclName() << Record->getTagKind();
- // If the element type has a non-trivial destructor, we would not
- // implicitly destroy the elements, so disallow it for now.
- //
- // FIXME: GCC allows this. We should probably either implicitly delete
- // the destructor of the containing class, or just allow this.
- QualType BaseElem = Context.getBaseElementType(FD->getType());
- if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) {
- Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor)
- << FD->getDeclName() << FD->getType();
- FD->setInvalidDecl();
- EnclosingDecl->setInvalidDecl();
- continue;
+ // If the element type has a non-trivial destructor, we would not
+ // implicitly destroy the elements, so disallow it for now.
+ //
+ // FIXME: GCC allows this. We should probably either implicitly delete
+ // the destructor of the containing class, or just allow this.
+ QualType BaseElem = Context.getBaseElementType(FD->getType());
+ if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) {
+ Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor)
+ << FD->getDeclName() << FD->getType();
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // Okay, we have a legal flexible array member at the end of the struct.
+ Record->setHasFlexibleArrayMember(true);
+ } else {
+ // In ObjCContainerDecl ivars with incomplete array type are accepted,
+ // unless they are followed by another ivar. That check is done
+ // elsewhere, after synthesized ivars are known.
}
- // Okay, we have a legal flexible array member at the end of the struct.
- Record->setHasFlexibleArrayMember(true);
} else if (!FDTy->isDependentType() &&
RequireCompleteType(FD->getLocation(), FD->getType(),
diag::err_field_incomplete)) {
@@ -14598,7 +15093,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// If this is a struct/class and this is not the last element, reject
// it. Note that GCC supports variable sized arrays in the middle of
// structures.
- if (i + 1 != Fields.end())
+ if (!IsLastField)
Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct)
<< FD->getDeclName() << FD->getType();
else {
@@ -14626,16 +15121,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>()) {
@@ -14646,7 +15141,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 &&
@@ -14745,8 +15240,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) {
auto *Dtor = CXXRecord->getDestructor();
if (Dtor && Dtor->isImplicit() &&
- ShouldDeleteSpecialMember(Dtor, CXXDestructor))
+ ShouldDeleteSpecialMember(Dtor, CXXDestructor)) {
+ CXXRecord->setImplicitDestructorIsDeleted();
SetDeclDeleted(Dtor, CXXRecord->getLocation());
+ }
}
if (Record->hasAttrs()) {
@@ -14934,7 +15431,6 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (Enum->isDependentType() || Val->isTypeDependent())
EltTy = Context.DependentTy;
else {
- SourceLocation ExpLoc;
if (getLangOpts().CPlusPlus11 && Enum->isFixed() &&
!getLangOpts().MSVCCompat) {
// C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
@@ -15099,7 +15595,7 @@ Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
// determine if we should merge the definition with an existing one and
// skip the body.
NamedDecl *PrevDecl = LookupSingleName(S, II, IILoc, LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
auto *PrevECD = dyn_cast_or_null<EnumConstantDecl>(PrevDecl);
if (!PrevECD)
return SkipBodyInfo();
@@ -15130,7 +15626,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// Verify that there isn't already something declared with this name in this
// scope.
NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
@@ -15143,7 +15639,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// different from T:
// - every enumerator of every member of class T that is an unscoped
// enumerated type
- if (!TheEnumDecl->isScoped())
+ if (getLangOpts().CPlusPlus && !TheEnumDecl->isScoped())
DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(),
DeclarationNameInfo(Id, IdLoc));
@@ -15157,19 +15653,19 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// enum constant will 'hide' the tag.
assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
"Received TagDecl when not in C++!");
- if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S) &&
- shouldLinkPossiblyHiddenDecl(PrevDecl, New)) {
+ if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) {
if (isa<EnumConstantDecl>(PrevDecl))
Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
else
Diag(IdLoc, diag::err_redefinition) << Id;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(PrevDecl, IdLoc);
return nullptr;
}
}
// Process attributes.
if (Attr) ProcessDeclAttributeList(S, New, Attr);
+ AddPragmaAttributes(S, New);
// Register this decl in the current scope stack.
New->setAccess(TheEnumDecl->getAccess());
@@ -15358,7 +15854,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()));
@@ -15603,7 +16099,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.
@@ -15667,30 +16163,53 @@ static void checkModuleImportContext(Sema &S, Module *M,
}
}
-Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
+Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
+ SourceLocation ModuleLoc,
ModuleDeclKind MDK,
ModuleIdPath Path) {
- // 'module implementation' requires that we are not compiling a module of any
- // kind. 'module' and 'module partition' require that we are compiling a
- // module inteface (not a module map).
- auto CMK = getLangOpts().getCompilingModule();
- if (MDK == ModuleDeclKind::Implementation
- ? CMK != LangOptions::CMK_None
- : CMK != LangOptions::CMK_ModuleInterface) {
+ assert(getLangOpts().ModulesTS &&
+ "should only have module decl in modules TS");
+
+ // A module implementation unit requires that we are not compiling a module
+ // of any kind. A module interface unit requires that we are not compiling a
+ // module map.
+ switch (getLangOpts().getCompilingModule()) {
+ case LangOptions::CMK_None:
+ // It's OK to compile a module interface as a normal translation unit.
+ break;
+
+ case LangOptions::CMK_ModuleInterface:
+ if (MDK != ModuleDeclKind::Implementation)
+ break;
+
+ // We were asked to compile a module interface unit but this is a module
+ // implementation unit. That indicates the 'export' is missing.
Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
- << (unsigned)MDK;
+ << FixItHint::CreateInsertion(ModuleLoc, "export ");
+ MDK = ModuleDeclKind::Interface;
+ break;
+
+ case LangOptions::CMK_ModuleMap:
+ Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
return nullptr;
}
- // FIXME: Create a ModuleDecl and return it.
+ assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
// FIXME: Most of this work should be done by the preprocessor rather than
- // here, in case we look ahead across something where the current
- // module matters (eg a #include).
+ // here, in order to support macro import.
- // The dots in a module name in the Modules TS are a lie. Unlike Clang's
- // hierarchical module map modules, the dots here are just another character
- // that can appear in a module name. Flatten down to the actual module name.
+ // Only one module-declaration is permitted per source file.
+ if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
+ Diag(ModuleLoc, diag::err_module_redeclaration);
+ Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
+ diag::note_prev_module_declaration);
+ return nullptr;
+ }
+
+ // Flatten the dots in a module name. Unlike Clang's hierarchical module map
+ // modules, the dots here are just another character that can appear in a
+ // module name.
std::string ModuleName;
for (auto &Piece : Path) {
if (!ModuleName.empty())
@@ -15710,13 +16229,12 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName;
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ Module *Mod;
switch (MDK) {
- case ModuleDeclKind::Module: {
- // FIXME: Check we're not in a submodule.
-
- // We can't have imported a definition of this module or parsed a module
- // map defining it already.
+ case ModuleDeclKind::Interface: {
+ // We can't have parsed or imported a definition of this module or parsed a
+ // module map defining it already.
if (auto *M = Map.findModule(ModuleName)) {
Diag(Path[0].second, diag::err_module_redefinition) << ModuleName;
if (M->DefinitionLoc.isValid())
@@ -15724,16 +16242,15 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
else if (const auto *FE = M->getASTFile())
Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
<< FE->getName();
- return nullptr;
+ Mod = M;
+ break;
}
// Create a Module for the module that we're defining.
- Module *Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+ ModuleScopes.front().Module);
assert(Mod && "module creation should not fail");
-
- // Enter the semantic scope of the module.
- ActOnModuleBegin(ModuleLoc, Mod);
- return nullptr;
+ break;
}
case ModuleDeclKind::Partition:
@@ -15743,14 +16260,31 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
case ModuleDeclKind::Implementation:
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
PP.getIdentifierInfo(ModuleName), Path[0].second);
-
- DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, ModuleNameLoc);
- if (Import.isInvalid())
- return nullptr;
- return ConvertDeclToDeclGroup(Import.get());
+ Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible,
+ /*IsIncludeDirective=*/false);
+ if (!Mod) {
+ Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
+ // Create an empty module interface unit for error recovery.
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+ ModuleScopes.front().Module);
+ }
+ break;
}
- llvm_unreachable("unexpected module decl kind");
+ // Switch from the global module to the named module.
+ ModuleScopes.back().Module = Mod;
+ ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation;
+ VisibleModules.setVisible(Mod, ModuleLoc);
+
+ // From now on, we have an owning module for all declarations we see.
+ // However, those declarations are module-private unless explicitly
+ // exported.
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+ TU->setLocalOwningModule(Mod);
+
+ // FIXME: Create a ModuleDecl.
+ return nullptr;
}
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
@@ -15842,9 +16376,22 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
VisibleModules.setVisible(Mod, DirectiveLoc);
+
+ // The enclosing context is now part of this module.
+ // FIXME: Consider creating a child DeclContext to hold the entities
+ // lexically within the module.
+ if (getLangOpts().trackLocalOwningModule()) {
+ for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ getLangOpts().ModulesLocalVisibility
+ ? Decl::ModuleOwnershipKind::VisibleWhenImported
+ : Decl::ModuleOwnershipKind::Visible);
+ cast<Decl>(DC)->setLocalOwningModule(Mod);
+ }
+ }
}
-void Sema::ActOnModuleEnd(SourceLocation EofLoc, Module *Mod) {
+void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
if (getLangOpts().ModulesLocalVisibility) {
VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules);
// Leaving a module hides namespace names, so our visible namespace cache
@@ -15856,19 +16403,39 @@ void Sema::ActOnModuleEnd(SourceLocation EofLoc, Module *Mod) {
"left the wrong module scope");
ModuleScopes.pop_back();
- // We got to the end of processing a #include of a local module. Create an
+ // We got to the end of processing a local module. Create an
// ImportDecl as we would for an imported module.
- FileID File = getSourceManager().getFileID(EofLoc);
- assert(File != getSourceManager().getMainFileID() &&
- "end of submodule in main source file");
- SourceLocation DirectiveLoc = getSourceManager().getIncludeLoc(File);
+ FileID File = getSourceManager().getFileID(EomLoc);
+ SourceLocation DirectiveLoc;
+ if (EomLoc == getSourceManager().getLocForEndOfFile(File)) {
+ // We reached the end of a #included module header. Use the #include loc.
+ assert(File != getSourceManager().getMainFileID() &&
+ "end of submodule in main source file");
+ DirectiveLoc = getSourceManager().getIncludeLoc(File);
+ } else {
+ // We reached an EOM pragma. Use the pragma location.
+ DirectiveLoc = EomLoc;
+ }
BuildModuleInclude(DirectiveLoc, Mod);
+
+ // Any further declarations are in whatever module we returned to.
+ if (getLangOpts().trackLocalOwningModule()) {
+ // The parser guarantees that this is the same context that we entered
+ // the module within.
+ for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+ cast<Decl>(DC)->setLocalOwningModule(getCurrentModule());
+ if (!getCurrentModule())
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::Unowned);
+ }
+ }
}
void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
Module *Mod) {
// Bail if we're not allowed to implicitly import a module here.
- if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery)
+ if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery ||
+ VisibleModules.isVisible(Mod))
return;
// Create the implicit import declaration.
@@ -15890,6 +16457,11 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
// C++ Modules TS draft:
+ // An export-declaration shall appear in the purview of a module other than
+ // the global module.
+ if (ModuleScopes.empty() || !ModuleScopes.back().ModuleInterface)
+ Diag(ExportLoc, diag::err_export_not_in_module_interface);
+
// An export-declaration [...] shall not contain more than one
// export keyword.
//
@@ -15900,6 +16472,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
CurContext->addDecl(D);
PushDeclContext(S, D);
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported);
return D;
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 3979383966..655d6e90e2 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;
+}
+static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) {
+ return Attr.getName();
+}
+
/// \brief If Expr is a valid integer constant, get the value of the integer
/// expression and return success or failure. May output an error.
-static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
- const Expr *Expr, uint32_t &Val,
- unsigned Idx = UINT_MAX) {
+template<typename AttrInfo>
+static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr,
+ uint32_t &Val, unsigned Idx = UINT_MAX) {
llvm::APSInt I(32);
if (Expr->isTypeDependent() || Expr->isValueDependent() ||
!Expr->isIntegerConstantExpr(I, S.Context)) {
if (Idx != UINT_MAX)
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << Idx << AANT_ArgumentIntegerConstant
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type)
+ << getAttrName(Attr) << Idx << AANT_ArgumentIntegerConstant
<< Expr->getSourceRange();
else
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_type)
+ << getAttrName(Attr) << AANT_ArgumentIntegerConstant
<< Expr->getSourceRange();
return false;
}
@@ -250,9 +274,9 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
/// \brief Wrapper around checkUInt32Argument, with an extra check to be sure
/// that the result will fit into a regular (signed) int. All args have the same
/// purpose as they do in checkUInt32Argument.
-static bool checkPositiveIntArgument(Sema &S, const AttributeList &Attr,
- const Expr *Expr, int &Val,
- unsigned Idx = UINT_MAX) {
+template<typename AttrInfo>
+static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr *Expr,
+ int &Val, unsigned Idx = UINT_MAX) {
uint32_t UVal;
if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx))
return false;
@@ -287,11 +311,10 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range,
/// instance method D. May output an error.
///
/// \returns true if IdxExpr is a valid index.
-static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D,
- const AttributeList &Attr,
- unsigned AttrArgNum,
- const Expr *IdxExpr,
- uint64_t &Idx) {
+template <typename AttrInfo>
+static bool checkFunctionOrMethodParameterIndex(
+ Sema &S, const Decl *D, const AttrInfo &Attr, unsigned AttrArgNum,
+ const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) {
assert(isFunctionOrMethodOrBlock(D));
// In C++ the implicit 'this' function parameter also counts.
@@ -305,24 +328,24 @@ static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D,
llvm::APSInt IdxInt;
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << AttrArgNum << AANT_ArgumentIntegerConstant
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type)
+ << getAttrName(Attr) << AttrArgNum << AANT_ArgumentIntegerConstant
<< IdxExpr->getSourceRange();
return false;
}
Idx = IdxInt.getLimitedValue();
if (Idx < 1 || (!IV && Idx > NumParams)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << Attr.getName() << AttrArgNum << IdxExpr->getSourceRange();
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_out_of_bounds)
+ << getAttrName(Attr) << AttrArgNum << IdxExpr->getSourceRange();
return false;
}
Idx--; // Convert to zero-based.
- if (HasImplicitThisParam) {
+ if (HasImplicitThisParam && !AllowImplicitThis) {
if (Idx == 0) {
- S.Diag(Attr.getLoc(),
+ S.Diag(getAttrLoc(Attr),
diag::err_attribute_invalid_implicit_this_argument)
- << Attr.getName() << IdxExpr->getSourceRange();
+ << getAttrName(Attr) << IdxExpr->getSourceRange();
return false;
}
--Idx;
@@ -753,31 +776,48 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-/// \brief Checks to be sure that the given parameter number is inbounds, and is
-/// an some integral type. Will emit appropriate diagnostics if this returns
+/// \brief Checks to be sure that the given parameter number is in bounds, and is
+/// an integral type. Will emit appropriate diagnostics if this returns
/// false.
///
/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used
/// to actually retrieve the argument, so it's base-0.
+template <typename AttrInfo>
static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
- const AttributeList &Attr,
- unsigned FuncParamNo, unsigned AttrArgNo) {
- assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument");
+ const AttrInfo &Attr, Expr *AttrArg,
+ unsigned FuncParamNo, unsigned AttrArgNo,
+ bool AllowDependentType = false) {
uint64_t Idx;
- if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo,
- Attr.getArgAsExpr(AttrArgNo), Idx))
+ if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, AttrArg,
+ Idx))
return false;
const ParmVarDecl *Param = FD->getParamDecl(Idx);
+ if (AllowDependentType && Param->getType()->isDependentType())
+ return true;
if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) {
- SourceLocation SrcLoc = Attr.getArgAsExpr(AttrArgNo)->getLocStart();
+ SourceLocation SrcLoc = AttrArg->getLocStart();
S.Diag(SrcLoc, diag::err_attribute_integers_only)
- << Attr.getName() << Param->getSourceRange();
+ << getAttrName(Attr) << Param->getSourceRange();
return false;
}
return true;
}
+/// \brief Checks to be sure that the given parameter number is in bounds, and is
+/// an integral type. Will emit appropriate diagnostics if this returns false.
+///
+/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used
+/// to actually retrieve the argument, so it's base-0.
+static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
+ const AttributeList &Attr,
+ unsigned FuncParamNo, unsigned AttrArgNo,
+ bool AllowDependentType = false) {
+ assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument");
+ return checkParamIsIntegerType(S, FD, Attr, Attr.getArgAsExpr(AttrArgNo),
+ FuncParamNo, AttrArgNo, AllowDependentType);
+}
+
static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1) ||
!checkAttributeAtMostNumArgs(S, Attr, 2))
@@ -909,7 +949,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D,
Msg = "<no message provided>";
SmallVector<PartialDiagnosticAt, 8> Diags;
- if (!Cond->isValueDependent() &&
+ if (isa<FunctionDecl>(D) && !Cond->isValueDependent() &&
!Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D),
Diags)) {
S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr)
@@ -997,10 +1037,11 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- auto *FD = cast<FunctionDecl>(D);
- bool ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
+ bool ArgDependent = false;
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
D->addAttr(::new (S.Context) DiagnoseIfAttr(
- Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, FD,
+ Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D),
Attr.getAttributeSpellingListIndex()));
}
@@ -1263,14 +1304,28 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- // Report warning about changed offset in the newer compiler versions.
- if (!FD->getType()->isDependentType() &&
- !FD->getType()->isIncompleteType() && FD->isBitField() &&
- S.Context.getTypeAlign(FD->getType()) <= 8)
- S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield);
+ bool BitfieldByteAligned = (!FD->getType()->isDependentType() &&
+ !FD->getType()->isIncompleteType() &&
+ FD->isBitField() &&
+ S.Context.getTypeAlign(FD->getType()) <= 8);
+
+ if (S.getASTContext().getTargetInfo().getTriple().isPS4()) {
+ if (BitfieldByteAligned)
+ // The PS4 target needs to maintain ABI backwards compatibility.
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
+ << Attr.getName() << FD->getType();
+ else
+ FD->addAttr(::new (S.Context) PackedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+ } else {
+ // Report warning about changed offset in the newer compiler versions.
+ if (BitfieldByteAligned)
+ S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield);
+
+ FD->addAttr(::new (S.Context) PackedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+ }
- FD->addAttr(::new (S.Context) PackedAttr(
- Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -1476,6 +1531,22 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (D->isInvalidDecl())
+ return;
+
+ // noescape only applies to pointer types.
+ QualType T = cast<ParmVarDecl>(D)->getType();
+ if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only)
+ << Attr.getName() << Attr.getRange() << 0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) NoEscapeAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
static void handleAssumeAlignedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
Expr *E = Attr.getArgAsExpr(0),
@@ -1484,6 +1555,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 +1612,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,29 +1954,65 @@ 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()));
}
-static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
+static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) {
if (hasDeclarator(D)) return;
- if (S.CheckNoReturnAttr(attr)) return;
+ if (S.CheckNoReturnAttr(Attrs))
+ return;
if (!isa<ObjCMethodDecl>(D)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attrs.getName() << ExpectedFunctionOrMethod;
return;
}
- D->addAttr(::new (S.Context)
- NoReturnAttr(attr.getRange(), S.Context,
- attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoReturnAttr(
+ Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+}
+
+static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (S.CheckNoCallerSavedRegsAttr(Attr))
+ return;
+
+ D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
}
-bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
- if (!checkAttributeNumArgs(*this, attr, 0)) {
- attr.setInvalid();
+bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) {
+ if (!checkAttributeNumArgs(*this, Attrs, 0)) {
+ Attrs.setInvalid();
+ return true;
+ }
+
+ return false;
+}
+
+bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) {
+ // Check whether the attribute is valid on the current target.
+ if (!Attr.existsInTarget(Context.getTargetInfo())) {
+ Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName();
+ Attr.setInvalid();
+ return true;
+ }
+
+ if (!checkAttributeNumArgs(*this, Attr, 0)) {
+ Attr.setInvalid();
return true;
}
@@ -2016,7 +2167,7 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// If this is spelled as the standard C++1z attribute, but not in C++1z, warn
// about using it as an extension.
if (!S.getLangOpts().CPlusPlus1z && IsCXX1zAttr)
- S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
+ S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName();
D->addAttr(::new (S.Context) UnusedAttr(
Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
@@ -2303,10 +2454,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
<< Platform->Ident;
NamedDecl *ND = dyn_cast<NamedDecl>(D);
- if (!ND) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ if (!ND) // We warned about this already, so just return.
return;
- }
AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
@@ -2416,12 +2565,6 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
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();
@@ -2722,7 +2865,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
// about using it as an extension.
if (!S.getLangOpts().CPlusPlus1z && Attr.isCXX11Attribute() &&
!Attr.getScopeName())
- S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
+ S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName();
D->addAttr(::new (S.Context)
WarnUnusedResultAttr(Attr.getRange(), S.Context,
@@ -2779,6 +2922,28 @@ static void handleWorkGroupSize(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+// Handles intel_reqd_sub_group_size.
+static void handleSubGroupSize(Sema &S, Decl *D, const AttributeList &Attr) {
+ uint32_t SGSize;
+ const Expr *E = Attr.getArgAsExpr(0);
+ if (!checkUInt32Argument(S, Attr, E, SGSize))
+ return;
+ if (SGSize == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero)
+ << Attr.getName() << E->getSourceRange();
+ return;
+ }
+
+ OpenCLIntelReqdSubGroupSizeAttr *Existing =
+ D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>();
+ if (Existing && Existing->getSubGroupSize() != SGSize)
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
+
+ D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr(
+ Attr.getRange(), S.Context, SGSize,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.hasParsedType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
@@ -2858,22 +3023,43 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(NewAttr);
}
-// Check for things we'd like to warn about, no errors or validation for now.
-// TODO: Validation should use a backend target library that specifies
-// the allowable subtarget features and cpus. We could use something like a
-// TargetCodeGenInfo hook here to do validation.
-void Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
+// Check for things we'd like to warn about. Multiversioning issues are
+// handled later in the process, once we know how many exist.
+bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
+ enum FirstParam { Unsupported, Duplicate };
+ enum SecondParam { None, Architecture };
for (auto Str : {"tune=", "fpmath="})
if (AttrStr.find(Str) != StringRef::npos)
- Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Str;
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << Str;
+
+ TargetAttr::ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
+
+ if (!ParsedAttrs.Architecture.empty() &&
+ !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << Architecture << ParsedAttrs.Architecture;
+
+ if (ParsedAttrs.DuplicateArchitecture)
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Duplicate << None << "arch=";
+
+ for (const auto &Feature : ParsedAttrs.Features) {
+ auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
+ if (!Context.getTargetInfo().isValidFeatureName(CurFeature))
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << CurFeature;
+ }
+
+ return true;
}
static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) {
StringRef Str;
SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc))
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc) ||
+ !S.checkTargetAttr(LiteralLoc, Str))
return;
- S.checkTargetAttr(LiteralLoc, Str);
unsigned Index = Attr.getAttributeSpellingListIndex();
TargetAttr *NewAttr =
::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index);
@@ -2943,6 +3129,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) {
@@ -4075,24 +4283,44 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
-bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
+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 &Attrs, CallingConv &CC,
const FunctionDecl *FD) {
- if (attr.isInvalid())
+ if (Attrs.isInvalid())
return true;
- if (attr.hasProcessingCache()) {
- CC = (CallingConv) attr.getProcessingCache();
+ if (Attrs.hasProcessingCache()) {
+ CC = (CallingConv) Attrs.getProcessingCache();
return false;
}
- unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0;
- if (!checkAttributeNumArgs(*this, attr, ReqArgs)) {
- attr.setInvalid();
+ unsigned ReqArgs = Attrs.getKind() == AttributeList::AT_Pcs ? 1 : 0;
+ if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) {
+ Attrs.setInvalid();
return true;
}
// TODO: diagnose uses of these conventions on the wrong target.
- switch (attr.getKind()) {
+ switch (Attrs.getKind()) {
case AttributeList::AT_CDecl: CC = CC_C; break;
case AttributeList::AT_FastCall: CC = CC_X86FastCall; break;
case AttributeList::AT_StdCall: CC = CC_X86StdCall; break;
@@ -4103,7 +4331,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
case AttributeList::AT_RegCall: CC = CC_X86RegCall; break;
case AttributeList::AT_MSABI:
CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
- CC_X86_64Win64;
+ CC_Win64;
break;
case AttributeList::AT_SysVABI:
CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV :
@@ -4111,8 +4339,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
break;
case AttributeList::AT_Pcs: {
StringRef StrRef;
- if (!checkStringLiteralArgumentAttr(attr, 0, StrRef)) {
- attr.setInvalid();
+ if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) {
+ Attrs.setInvalid();
return true;
}
if (StrRef == "aapcs") {
@@ -4123,8 +4351,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
break;
}
- attr.setInvalid();
- Diag(attr.getLoc(), diag::err_invalid_pcs);
+ Attrs.setInvalid();
+ Diag(Attrs.getLoc(), diag::err_invalid_pcs);
return true;
}
case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break;
@@ -4137,7 +4365,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC);
if (A != TargetInfo::CCCR_OK) {
if (A == TargetInfo::CCCR_Warning)
- Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName();
+ Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs.getName();
// This convention is not valid for the target. Use the default function or
// method calling convention.
@@ -4149,7 +4377,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod);
}
- attr.setProcessingCache((unsigned) CC);
+ Attrs.setProcessingCache((unsigned) CC);
return false;
}
@@ -4157,7 +4385,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
static bool isValidSwiftContextType(QualType type) {
if (!type->hasPointerRepresentation())
return type->isDependentType();
- return type->getPointeeType().getAddressSpace() == 0;
+ return type->getPointeeType().getAddressSpace() == LangAS::Default;
}
/// Pointers and references in the default address space.
@@ -4169,7 +4397,7 @@ static bool isValidSwiftIndirectResultType(QualType type) {
} else {
return type->isDependentType();
}
- return type.getAddressSpace() == 0;
+ return type.getAddressSpace() == LangAS::Default;
}
/// Pointers and references to pointers in the default address space.
@@ -4186,10 +4414,10 @@ static bool isValidSwiftErrorResultType(QualType type) {
return isValidSwiftContextType(type);
}
-static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &attr,
- ParameterABI abi) {
- S.AddParameterABIAttr(attr.getRange(), D, abi,
- attr.getAttributeSpellingListIndex());
+static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &Attrs,
+ ParameterABI Abi) {
+ S.AddParameterABIAttr(Attrs.getRange(), D, Abi,
+ Attrs.getAttributeSpellingListIndex());
}
void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi,
@@ -4427,14 +4655,16 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
static void handleXRayLogArgsAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
uint64_t ArgCount;
+
if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0),
- ArgCount))
+ ArgCount,
+ true /* AllowImplicitThis*/))
return;
// ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1.
D->addAttr(::new (S.Context)
- XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount,
- Attr.getAttributeSpellingListIndex()));
+ XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount,
+ Attr.getAttributeSpellingListIndex()));
}
//===----------------------------------------------------------------------===//
@@ -4500,6 +4730,16 @@ void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D,
CFConsumedAttr(attrRange, Context, spellingIndex));
}
+bool Sema::checkNSReturnsRetainedReturnType(SourceLocation loc,
+ QualType type) {
+ if (isValidSubjectOfNSReturnsRetainedAttribute(type))
+ return false;
+
+ Diag(loc, diag::warn_ns_attribute_wrong_return_type)
+ << "'ns_returns_retained'" << 0 << 0;
+ return true;
+}
+
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
QualType returnType;
@@ -4521,6 +4761,8 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
<< Attr.getRange();
return;
}
+ } else if (Attr.isUsedAsTypeAttr()) {
+ return;
} else {
AttributeDeclKind ExpectedDeclKind;
switch (Attr.getKind()) {
@@ -4564,6 +4806,9 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
}
if (!typeOK) {
+ if (Attr.isUsedAsTypeAttr())
+ return;
+
if (isa<ParmVarDecl>(D)) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
<< Attr.getName() << /*pointer-to-CF*/2
@@ -4613,11 +4858,11 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
}
static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
- const AttributeList &attr) {
+ const AttributeList &Attrs) {
const int EP_ObjCMethod = 1;
const int EP_ObjCProperty = 2;
- SourceLocation loc = attr.getLoc();
+ SourceLocation loc = Attrs.getLoc();
QualType resultType;
if (isa<ObjCMethodDecl>(D))
resultType = cast<ObjCMethodDecl>(D)->getReturnType();
@@ -4628,7 +4873,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
(!resultType->isPointerType() || resultType->isObjCRetainableType())) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
<< SourceRange(loc)
- << attr.getName()
+ << Attrs.getName()
<< (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty)
<< /*non-retainable pointer*/ 2;
@@ -4637,29 +4882,29 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(
- attr.getRange(), S.Context, attr.getAttributeSpellingListIndex()));
+ Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
- const AttributeList &attr) {
+ const AttributeList &Attrs) {
ObjCMethodDecl *method = cast<ObjCMethodDecl>(D);
DeclContext *DC = method->getDeclContext();
if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
- << attr.getName() << 0;
+ << Attrs.getName() << 0;
S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
return;
}
if (method->getMethodFamily() == OMF_dealloc) {
S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
- << attr.getName() << 1;
+ << Attrs.getName() << 1;
return;
}
method->addAttr(::new (S.Context)
- ObjCRequiresSuperAttr(attr.getRange(), S.Context,
- attr.getAttributeSpellingListIndex()));
+ ObjCRequiresSuperAttr(Attrs.getRange(), S.Context,
+ Attrs.getAttributeSpellingListIndex()));
}
static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
@@ -4903,6 +5148,15 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
+ // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's
+ // the only thing in the [] list, the [] too), and add an insertion of
+ // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas
+ // separating attributes nor of the [ and the ] are in the AST.
+ // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc"
+ // on cfe-dev.
+ if (Attr.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
+ S.Diag(Attr.getLoc(), diag::warn_atl_uuid_deprecated);
+
UuidAttr *UA = S.mergeUuidAttr(D, Attr.getRange(),
Attr.getAttributeSpellingListIndex(), StrRef);
if (UA)
@@ -5462,8 +5716,12 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleAssertCapabilityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context,
- Attr.getArgAsExpr(0),
+ Args.data(), Args.size(),
Attr.getAttributeSpellingListIndex()));
}
@@ -5628,18 +5886,21 @@ static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
// Several attributes carry different semantics than the parsing requires, so
- // those are opted out of the common handling.
+ // those are opted out of the common argument checks.
//
// We also bail on unknown and ignored attributes because those are handled
// as part of the target-specific handling logic.
- if (Attr.hasCustomParsing() ||
- Attr.getKind() == AttributeList::UnknownAttribute)
+ if (Attr.getKind() == AttributeList::UnknownAttribute)
return false;
-
// Check whether the attribute requires specific language extensions to be
// enabled.
if (!Attr.diagnoseLangOpts(S))
return true;
+ // Check whether the attribute appertains to the given subject.
+ if (!Attr.diagnoseAppertainsTo(S, D))
+ return true;
+ if (Attr.hasCustomParsing())
+ return false;
if (Attr.getMinArgs() == Attr.getMaxArgs()) {
// If there are no optional arguments, then checking for the argument count
@@ -5656,10 +5917,6 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
return true;
}
- // Check whether the attribute appertains to the given subject.
- if (!Attr.diagnoseAppertainsTo(S, D))
- return true;
-
return false;
}
@@ -5751,12 +6008,26 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleDLLAttr(S, D, Attr);
break;
case AttributeList::AT_Mips16:
- handleSimpleAttributeWithExclusions<Mips16Attr, MipsInterruptAttr>(S, D,
- Attr);
+ handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr,
+ MipsInterruptAttr>(S, D, Attr);
break;
case AttributeList::AT_NoMips16:
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
break;
+ case AttributeList::AT_MicroMips:
+ handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NoMicroMips:
+ handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_MipsLongCall:
+ handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>(
+ S, D, Attr);
+ break;
+ case AttributeList::AT_MipsShortCall:
+ handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>(
+ S, D, Attr);
+ break;
case AttributeList::AT_AMDGPUFlatWorkGroupSize:
handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr);
break;
@@ -5856,6 +6127,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;
@@ -5909,9 +6183,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ReturnsNonNull:
handleReturnsNonNullAttr(S, D, Attr);
break;
+ case AttributeList::AT_NoEscape:
+ handleNoEscapeAttr(S, D, Attr);
+ break;
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;
@@ -5998,6 +6278,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ReqdWorkGroupSize:
handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, Attr);
break;
+ case AttributeList::AT_OpenCLIntelReqdSubGroupSize:
+ handleSubGroupSize(S, D, Attr);
+ break;
case AttributeList::AT_VecTypeHint:
handleVecTypeHint(S, D, Attr);
break;
@@ -6131,6 +6414,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;
@@ -6291,6 +6577,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_TypeTagForDatatype:
handleTypeTagForDatatypeAttr(S, D, Attr);
break;
+ case AttributeList::AT_AnyX86NoCallerSavedRegisters:
+ handleNoCallerSavedRegsAttr(S, D, Attr);
+ break;
case AttributeList::AT_RenderScriptKernel:
handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr);
break;
@@ -6356,11 +6645,14 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
<< A << ExpectedKernelFunction;
D->setInvalidDecl();
+ } else if (Attr *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) {
+ Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
+ D->setInvalidDecl();
}
}
}
-// Helper for delayed proccessing TransparentUnion attribute.
+// Helper for delayed processing TransparentUnion attribute.
void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) {
for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext())
if (Attr->getKind() == AttributeList::AT_TransparentUnion) {
@@ -6530,6 +6822,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
+
+ // Apply additional attributes specified by '#pragma clang attribute'.
+ AddPragmaAttributes(S, D);
}
/// Is the given declaration allowed to use a forbidden type?
@@ -6624,6 +6919,50 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
return nullptr;
}
+/// The diagnostic we should emit for \c D, and the declaration that
+/// originated it, or \c AR_Available.
+///
+/// \param D The declaration to check.
+/// \param Message If non-null, this will be populated with the message from
+/// the availability attribute that is selected.
+static std::pair<AvailabilityResult, const NamedDecl *>
+ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) {
+ AvailabilityResult Result = D->getAvailability(Message);
+
+ // For typedefs, if the typedef declaration appears available look
+ // to the underlying type to see if it is more restrictive.
+ while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ if (Result == AR_Available) {
+ if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
+ D = TT->getDecl();
+ Result = D->getAvailability(Message);
+ continue;
+ }
+ }
+ break;
+ }
+
+ // Forward class declarations get their attributes from their definition.
+ if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (IDecl->getDefinition()) {
+ D = IDecl->getDefinition();
+ Result = D->getAvailability(Message);
+ }
+ }
+
+ if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
+ if (Result == AR_Available) {
+ const DeclContext *DC = ECD->getDeclContext();
+ if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
+ Result = TheEnumDecl->getAvailability(Message);
+ D = TheEnumDecl;
+ }
+ }
+
+ return {Result, D};
+}
+
+
/// \brief whether we should emit a diagnostic for \c K and \c DeclVersion in
/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
/// in a deprecated context, but not the other way around.
@@ -6689,8 +7028,103 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
return true;
}
+static bool
+shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
+ const VersionTuple &DeploymentVersion,
+ const VersionTuple &DeclVersion) {
+ const auto &Triple = Context.getTargetInfo().getTriple();
+ VersionTuple ForceAvailabilityFromVersion;
+ switch (Triple.getOS()) {
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
+ break;
+ case llvm::Triple::WatchOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
+ break;
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
+ break;
+ default:
+ // New targets should always warn about availability.
+ return Triple.getVendor() == llvm::Triple::Apple;
+ }
+ return DeploymentVersion >= ForceAvailabilityFromVersion ||
+ DeclVersion >= ForceAvailabilityFromVersion;
+}
+
+static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
+ for (Decl *Ctx = OrigCtx; Ctx;
+ Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
+ if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
+ return cast<NamedDecl>(Ctx);
+ if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
+ if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
+ return Imp->getClassInterface();
+ return CD;
+ }
+ }
+
+ return dyn_cast<NamedDecl>(OrigCtx);
+}
+
+namespace {
+
+struct AttributeInsertion {
+ StringRef Prefix;
+ SourceLocation Loc;
+ StringRef Suffix;
+
+ static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
+ return {" ", D->getLocEnd(), ""};
+ }
+ static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
+ return {" ", Loc, ""};
+ }
+ static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
+ return {"", D->getLocStart(), "\n"};
+ }
+};
+
+} // end anonymous namespace
+
+/// Returns a source location in which it's appropriate to insert a new
+/// attribute for the given declaration \D.
+static Optional<AttributeInsertion>
+createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (isa<ObjCPropertyDecl>(D))
+ return AttributeInsertion::createInsertionAfter(D);
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->hasBody())
+ return None;
+ return AttributeInsertion::createInsertionAfter(D);
+ }
+ if (const auto *TD = dyn_cast<TagDecl>(D)) {
+ SourceLocation Loc =
+ Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
+ if (Loc.isInvalid())
+ return None;
+ // Insert after the 'struct'/whatever keyword.
+ return AttributeInsertion::createInsertionAfter(Loc);
+ }
+ return AttributeInsertion::createInsertionBefore(D);
+}
+
+/// Actually emit an availability diagnostic for a reference to an unavailable
+/// decl.
+///
+/// \param Ctx The context that the reference occurred in
+/// \param ReferringDecl The exact declaration that was referenced.
+/// \param OffendingDecl A related decl to \c ReferringDecl that has an
+/// availability attribute corrisponding to \c K attached to it. Note that this
+/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
+/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
+/// and OffendingDecl is the EnumDecl.
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
- Decl *Ctx, const NamedDecl *D,
+ Decl *Ctx, const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
StringRef Message, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
@@ -6698,6 +7132,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// Diagnostics for deprecated or unavailable.
unsigned diag, diag_message, diag_fwdclass_message;
unsigned diag_available_here = diag::note_availability_specified_here;
+ SourceLocation NoteLocation = OffendingDecl->getLocation();
// Matches 'diag::note_property_attribute' options.
unsigned property_note_select;
@@ -6706,13 +7141,89 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
unsigned available_here_select_kind;
VersionTuple DeclVersion;
- if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D))
+ if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
DeclVersion = AA->getIntroduced();
if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
return;
+ // The declaration can have multiple availability attributes, we are looking
+ // at one of them.
+ const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
+ if (A && A->isInherited()) {
+ for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
+ Redecl = Redecl->getPreviousDecl()) {
+ const AvailabilityAttr *AForRedecl =
+ getAttrForPlatform(S.Context, Redecl);
+ if (AForRedecl && !AForRedecl->isInherited()) {
+ // If D is a declaration with inherited attributes, the note should
+ // point to the declaration with actual attributes.
+ NoteLocation = Redecl->getLocation();
+ break;
+ }
+ }
+ }
+
switch (K) {
+ case AR_NotYetIntroduced: {
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ const AvailabilityAttr *AA =
+ getAttrForPlatform(S.getASTContext(), OffendingDecl);
+ VersionTuple Introduced = AA->getIntroduced();
+
+ bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
+ S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
+ Introduced);
+ unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability;
+
+ S.Diag(Loc, Warning)
+ << OffendingDecl
+ << AvailabilityAttr::getPrettyPlatformName(
+ S.getASTContext().getTargetInfo().getPlatformName())
+ << Introduced.getAsString();
+
+ S.Diag(OffendingDecl->getLocation(), diag::note_availability_specified_here)
+ << OffendingDecl << /* partial */ 3;
+
+ if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
+ if (auto *TD = dyn_cast<TagDecl>(Enclosing))
+ if (TD->getDeclName().isEmpty()) {
+ S.Diag(TD->getLocation(),
+ diag::note_decl_unguarded_availability_silence)
+ << /*Anonymous*/ 1 << TD->getKindName();
+ return;
+ }
+ auto FixitNoteDiag =
+ S.Diag(Enclosing->getLocation(),
+ diag::note_decl_unguarded_availability_silence)
+ << /*Named*/ 0 << Enclosing;
+ // Don't offer a fixit for declarations with availability attributes.
+ if (Enclosing->hasAttr<AvailabilityAttr>())
+ return;
+ if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
+ return;
+ Optional<AttributeInsertion> Insertion = createAttributeInsertion(
+ Enclosing, S.getSourceManager(), S.getLangOpts());
+ if (!Insertion)
+ return;
+ std::string PlatformName =
+ AvailabilityAttr::getPlatformNameSourceSpelling(
+ S.getASTContext().getTargetInfo().getPlatformName())
+ .lower();
+ std::string Introduced =
+ OffendingDecl->getVersionIntroduced().getAsString();
+ FixitNoteDiag << FixItHint::CreateInsertion(
+ Insertion->Loc,
+ (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
+ "(" + Introduced + "))" + Insertion->Suffix)
+ .str());
+ }
+ return;
+ }
case AR_Deprecated:
diag = !ObjCPropertyAccess ? diag::warn_deprecated
: diag::warn_property_method_deprecated;
@@ -6720,6 +7231,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
property_note_select = /* deprecated */ 0;
available_here_select_kind = /* deprecated */ 2;
+ if (const auto *Attr = OffendingDecl->getAttr<DeprecatedAttr>())
+ NoteLocation = Attr->getLocation();
break;
case AR_Unavailable:
@@ -6730,17 +7243,18 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
property_note_select = /* unavailable */ 1;
available_here_select_kind = /* unavailable */ 0;
- if (auto attr = D->getAttr<UnavailableAttr>()) {
- if (attr->isImplicit() && attr->getImplicitReason()) {
+ if (auto Attr = OffendingDecl->getAttr<UnavailableAttr>()) {
+ if (Attr->isImplicit() && Attr->getImplicitReason()) {
// Most of these failures are due to extra restrictions in ARC;
// reflect that in the primary diagnostic when applicable.
auto flagARCError = [&] {
if (S.getLangOpts().ObjCAutoRefCount &&
- S.getSourceManager().isInSystemHeader(D->getLocation()))
+ S.getSourceManager().isInSystemHeader(
+ OffendingDecl->getLocation()))
diag = diag::err_unavailable_in_arc;
};
- switch (attr->getImplicitReason()) {
+ switch (Attr->getImplicitReason()) {
case UnavailableAttr::IR_None: break;
case UnavailableAttr::IR_ARCForbiddenType:
@@ -6774,14 +7288,6 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
break;
- case AR_NotYetIntroduced:
- diag = diag::warn_partial_availability;
- diag_message = diag::warn_partial_message;
- diag_fwdclass_message = diag::warn_partial_fwdclass_message;
- property_note_select = /* partial */ 2;
- available_here_select_kind = /* partial */ 3;
- break;
-
case AR_Available:
llvm_unreachable("Warning for availability of available declaration?");
}
@@ -6789,10 +7295,10 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
CharSourceRange UseRange;
StringRef Replacement;
if (K == AR_Deprecated) {
- if (auto attr = D->getAttr<DeprecatedAttr>())
- Replacement = attr->getReplacement();
- if (auto attr = getAttrForPlatform(S.Context, D))
- Replacement = attr->getReplacement();
+ if (auto Attr = OffendingDecl->getAttr<DeprecatedAttr>())
+ Replacement = Attr->getReplacement();
+ if (auto Attr = getAttrForPlatform(S.Context, OffendingDecl))
+ Replacement = Attr->getReplacement();
if (!Replacement.empty())
UseRange =
@@ -6800,49 +7306,28 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
if (!Message.empty()) {
- S.Diag(Loc, diag_message) << D << Message
+ S.Diag(Loc, diag_message) << ReferringDecl << Message
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else if (!UnknownObjCClass) {
- S.Diag(Loc, diag) << D
+ S.Diag(Loc, diag) << ReferringDecl
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else {
- S.Diag(Loc, diag_fwdclass_message) << D
+ S.Diag(Loc, diag_fwdclass_message) << ReferringDecl
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
}
- // The declaration can have multiple availability attributes, we are looking
- // at one of them.
- const AvailabilityAttr *A = getAttrForPlatform(S.Context, D);
- if (A && A->isInherited()) {
- for (const Decl *Redecl = D->getMostRecentDecl(); Redecl;
- Redecl = Redecl->getPreviousDecl()) {
- const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context,
- Redecl);
- if (AForRedecl && !AForRedecl->isInherited()) {
- // If D is a declaration with inherited attributes, the note should
- // point to the declaration with actual attributes.
- S.Diag(Redecl->getLocation(), diag_available_here) << D
- << available_here_select_kind;
- break;
- }
- }
- }
- else
- S.Diag(D->getLocation(), diag_available_here)
- << D << available_here_select_kind;
-
- if (K == AR_NotYetIntroduced)
- S.Diag(Loc, diag::note_partial_availability_silence) << D;
+ S.Diag(NoteLocation, diag_available_here)
+ << OffendingDecl << available_here_select_kind;
}
static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
@@ -6852,9 +7337,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
DD.Triggered = true;
DoEmitAvailabilityWarning(
- S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(),
- DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(),
- DD.getObjCProperty(), false);
+ S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
+ DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc,
+ DD.getUnknownObjCClass(), DD.getObjCProperty(), false);
}
void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
@@ -6912,27 +7397,93 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
curPool->steal(pool);
}
-void Sema::EmitAvailabilityWarning(AvailabilityResult AR,
- NamedDecl *D, StringRef Message,
- SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess) {
+static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
+ const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
+ StringRef Message, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
+ bool ObjCPropertyAccess) {
// Delay if we're currently parsing a declaration.
- if (DelayedDiagnostics.shouldDelayDiagnostics()) {
- DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
- AR, Loc, D, UnknownObjCClass, ObjCProperty, Message,
- ObjCPropertyAccess));
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ DelayedDiagnostic::makeAvailability(
+ AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass,
+ ObjCProperty, Message, ObjCPropertyAccess));
return;
}
- Decl *Ctx = cast<Decl>(getCurLexicalContext());
- DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass,
- ObjCProperty, ObjCPropertyAccess);
+ Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
+ DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
+ Message, Loc, UnknownObjCClass, ObjCProperty,
+ ObjCPropertyAccess);
}
namespace {
+/// Returns true if the given statement can be a body-like child of \p Parent.
+bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
+ switch (Parent->getStmtClass()) {
+ case Stmt::IfStmtClass:
+ return cast<IfStmt>(Parent)->getThen() == S ||
+ cast<IfStmt>(Parent)->getElse() == S;
+ case Stmt::WhileStmtClass:
+ return cast<WhileStmt>(Parent)->getBody() == S;
+ case Stmt::DoStmtClass:
+ return cast<DoStmt>(Parent)->getBody() == S;
+ case Stmt::ForStmtClass:
+ return cast<ForStmt>(Parent)->getBody() == S;
+ case Stmt::CXXForRangeStmtClass:
+ return cast<CXXForRangeStmt>(Parent)->getBody() == S;
+ case Stmt::ObjCForCollectionStmtClass:
+ return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ return cast<SwitchCase>(Parent)->getSubStmt() == S;
+ default:
+ return false;
+ }
+}
+
+class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
+ const Stmt *Target;
+
+public:
+ bool VisitStmt(Stmt *S) { return S != Target; }
+
+ /// Returns true if the given statement is present in the given declaration.
+ static bool isContained(const Stmt *Target, const Decl *D) {
+ StmtUSEFinder Visitor;
+ Visitor.Target = Target;
+ return !Visitor.TraverseDecl(const_cast<Decl *>(D));
+ }
+};
+
+/// Traverses the AST and finds the last statement that used a given
+/// declaration.
+class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
+ const Decl *D;
+
+public:
+ bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+ if (DRE->getDecl() == D)
+ return false;
+ return true;
+ }
+
+ static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
+ const CompoundStmt *Scope) {
+ LastDeclUSEFinder Visitor;
+ Visitor.D = D;
+ for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) {
+ const Stmt *S = *I;
+ if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
+ return S;
+ }
+ return nullptr;
+ }
+};
+
/// \brief This class implements -Wunguarded-availability.
///
/// This is done with a traversal of the AST of a function that makes reference
@@ -6948,6 +7499,7 @@ class DiagnoseUnguardedAvailability
/// Stack of potentially nested 'if (@available(...))'s.
SmallVector<VersionTuple, 8> AvailabilityStack;
+ SmallVector<const Stmt *, 16> StmtStack;
void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range);
@@ -6958,10 +7510,38 @@ public:
SemaRef.Context.getTargetInfo().getPlatformMinVersion());
}
+ bool TraverseDecl(Decl *D) {
+ // Avoid visiting nested functions to prevent duplicate warnings.
+ if (!D || isa<FunctionDecl>(D))
+ return true;
+ return Base::TraverseDecl(D);
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ if (!S)
+ return true;
+ StmtStack.push_back(S);
+ bool Result = Base::TraverseStmt(S);
+ StmtStack.pop_back();
+ return Result;
+ }
+
void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
bool TraverseIfStmt(IfStmt *If);
+ bool TraverseLambdaExpr(LambdaExpr *E) { return true; }
+
+ // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
+ // to any useful diagnostics.
+ bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
+
+ bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) {
+ if (PRE->isClassReceiver())
+ DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation());
+ return true;
+ }
+
bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
if (ObjCMethodDecl *D = Msg->getMethodDecl())
DiagnoseDeclAvailability(
@@ -6981,24 +7561,32 @@ public:
return true;
}
+ bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
+ SemaRef.Diag(E->getLocStart(), diag::warn_at_available_unchecked_use)
+ << (!SemaRef.getLangOpts().ObjC1);
+ return true;
+ }
+
bool VisitTypeLoc(TypeLoc Ty);
};
void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
NamedDecl *D, SourceRange Range) {
-
- VersionTuple ContextVersion = AvailabilityStack.back();
- if (AvailabilityResult Result =
- SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) {
+ AvailabilityResult Result;
+ const NamedDecl *OffendingDecl;
+ std::tie(Result, OffendingDecl) =
+ ShouldDiagnoseAvailabilityOfDecl(D, nullptr);
+ if (Result != AR_Available) {
// All other diagnostic kinds have already been handled in
// DiagnoseAvailabilityOfDecl.
if (Result != AR_NotYetIntroduced)
return;
- const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D);
+ const AvailabilityAttr *AA =
+ getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
VersionTuple Introduced = AA->getIntroduced();
- if (ContextVersion >= Introduced)
+ if (AvailabilityStack.back() >= Introduced)
return;
// If the context of this function is less available than D, we should not
@@ -7006,18 +7594,96 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx))
return;
- SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability)
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ unsigned DiagKind =
+ shouldDiagnoseAvailabilityByDefault(
+ SemaRef.Context,
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
+ ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability;
+
+ SemaRef.Diag(Range.getBegin(), DiagKind)
<< Range << D
<< AvailabilityAttr::getPrettyPlatformName(
SemaRef.getASTContext().getTargetInfo().getPlatformName())
<< Introduced.getAsString();
- SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here)
- << D << /* partial */ 3;
+ SemaRef.Diag(OffendingDecl->getLocation(),
+ diag::note_availability_specified_here)
+ << OffendingDecl << /* partial */ 3;
+
+ auto FixitDiag =
+ SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
+ << Range << D
+ << (SemaRef.getLangOpts().ObjC1 ? /*@available*/ 0
+ : /*__builtin_available*/ 1);
- // FIXME: Replace this with a fixit diagnostic.
- SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
- << Range << D;
+ // Find the statement which should be enclosed in the if @available check.
+ if (StmtStack.empty())
+ return;
+ const Stmt *StmtOfUse = StmtStack.back();
+ const CompoundStmt *Scope = nullptr;
+ for (const Stmt *S : llvm::reverse(StmtStack)) {
+ if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
+ Scope = CS;
+ break;
+ }
+ if (isBodyLikeChildStmt(StmtOfUse, S)) {
+ // The declaration won't be seen outside of the statement, so we don't
+ // have to wrap the uses of any declared variables in if (@available).
+ // Therefore we can avoid setting Scope here.
+ break;
+ }
+ StmtOfUse = S;
+ }
+ const Stmt *LastStmtOfUse = nullptr;
+ if (isa<DeclStmt>(StmtOfUse) && Scope) {
+ for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
+ if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
+ LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
+ break;
+ }
+ }
+ }
+
+ const SourceManager &SM = SemaRef.getSourceManager();
+ SourceLocation IfInsertionLoc =
+ SM.getExpansionLoc(StmtOfUse->getLocStart());
+ SourceLocation StmtEndLoc =
+ SM.getExpansionRange(
+ (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getLocEnd())
+ .second;
+ if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
+ return;
+
+ StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
+ const char *ExtraIndentation = " ";
+ std::string FixItString;
+ llvm::raw_string_ostream FixItOS(FixItString);
+ FixItOS << "if (" << (SemaRef.getLangOpts().ObjC1 ? "@available"
+ : "__builtin_available")
+ << "("
+ << AvailabilityAttr::getPlatformNameSourceSpelling(
+ SemaRef.getASTContext().getTargetInfo().getPlatformName())
+ << " " << Introduced.getAsString() << ", *)) {\n"
+ << Indentation << ExtraIndentation;
+ FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
+ SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken(
+ StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/false);
+ if (ElseInsertionLoc.isInvalid())
+ ElseInsertionLoc =
+ Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
+ FixItOS.str().clear();
+ FixItOS << "\n"
+ << Indentation << "} else {\n"
+ << Indentation << ExtraIndentation
+ << "// Fallback on earlier versions\n"
+ << Indentation << "}";
+ FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
}
}
@@ -7025,6 +7691,9 @@ bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
const Type *TyPtr = Ty.getTypePtr();
SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
+ if (Range.isInvalid())
+ return true;
+
if (const TagType *TT = dyn_cast<TagType>(TyPtr)) {
TagDecl *TD = TT->getDecl();
DiagnoseDeclAvailability(TD, Range);
@@ -7049,8 +7718,7 @@ bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
// If we're using the '*' case here or if this check is redundant, then we
// use the enclosing version to check both branches.
if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
- return Base::TraverseStmt(If->getThen()) &&
- Base::TraverseStmt(If->getElse());
+ return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
} else {
// This isn't an availability checking 'if', we can just continue.
return Base::TraverseIfStmt(If);
@@ -7077,8 +7745,51 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
Body = FD->getBody();
} else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
Body = MD->getBody();
+ else if (auto *BD = dyn_cast<BlockDecl>(D))
+ Body = BD->getBody();
assert(Body && "Need a body here!");
DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
}
+
+void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess,
+ bool AvoidPartialAvailabilityChecks) {
+ std::string Message;
+ AvailabilityResult Result;
+ const NamedDecl* OffendingDecl;
+ // See if this declaration is unavailable, deprecated, or partial.
+ std::tie(Result, OffendingDecl) = ShouldDiagnoseAvailabilityOfDecl(D, &Message);
+ if (Result == AR_Available)
+ return;
+
+ if (Result == AR_NotYetIntroduced) {
+ if (AvoidPartialAvailabilityChecks)
+ return;
+
+ // We need to know the @available context in the current function to
+ // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
+ // when we're done parsing the current function.
+ if (getCurFunctionOrMethodDecl()) {
+ getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
+ return;
+ } else if (getCurBlock() || getCurLambda()) {
+ getCurFunction()->HasPotentialAvailabilityViolations = true;
+ return;
+ }
+ }
+
+ const ObjCPropertyDecl *ObjCPDecl = nullptr;
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
+ AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
+ if (PDeclResult == Result)
+ ObjCPDecl = PD;
+ }
+ }
+
+ EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Loc,
+ UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
+}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 668d4b2de3..a5ccce6154 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -143,7 +143,7 @@ namespace {
if (Lambda->capture_begin() == Lambda->capture_end())
return false;
- return S->Diag(Lambda->getLocStart(),
+ return S->Diag(Lambda->getLocStart(),
diag::err_lambda_capture_default_arg);
}
}
@@ -167,6 +167,9 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
if (ComputedEST == EST_None)
return;
+ if (EST == EST_None && Method->hasAttr<NoThrowAttr>())
+ EST = EST_BasicNoexcept;
+
switch(EST) {
// If this function can throw any exceptions, make a note of that.
case EST_MSAny:
@@ -276,18 +279,18 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
// Okay: add the default argument to the parameter
Param->setDefaultArg(Arg);
- // We have already instantiated this parameter; provide each of the
+ // We have already instantiated this parameter; provide each of the
// instantiations with the uninstantiated default argument.
UnparsedDefaultArgInstantiationsMap::iterator InstPos
= UnparsedDefaultArgInstantiations.find(Param);
if (InstPos != UnparsedDefaultArgInstantiations.end()) {
for (unsigned I = 0, N = InstPos->second.size(); I != N; ++I)
InstPos->second[I]->setUninstantiatedDefaultArg(Arg);
-
+
// We're done tracking this parameter's instantiations.
UnparsedDefaultArgInstantiations.erase(InstPos);
}
-
+
return false;
}
@@ -467,7 +470,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;
}
@@ -524,8 +527,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = false;
}
}
-
- // FIXME: If we knew where the '=' was, we could easily provide a fix-it
+
+ // FIXME: If we knew where the '=' was, we could easily provide a fix-it
// hint here. Alternatively, we could walk the type-source information
// for NewParam to find the last source location in the type... but it
// isn't worth the effort right now. This is the kind of test case that
@@ -535,7 +538,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// void g(int (*fp)(int) = &f);
Diag(NewParam->getLocation(), DiagDefaultParamID)
<< NewParam->getDefaultArgRange();
-
+
// Look for the function declaration where the default argument was
// actually written, which may be a declaration prior to Old.
for (auto Older = PrevForDefaultArgs;
@@ -547,17 +550,23 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Diag(OldParam->getLocation(), diag::note_previous_definition)
<< OldParam->getDefaultArgRange();
} else if (OldParamHasDfl) {
- // Merge the old default argument into the new parameter.
- // It's important to use getInit() here; getDefaultArg()
- // strips off any top-level ExprWithCleanups.
- NewParam->setHasInheritedDefaultArg();
- if (OldParam->hasUnparsedDefaultArg())
- NewParam->setUnparsedDefaultArg();
- else if (OldParam->hasUninstantiatedDefaultArg())
- NewParam->setUninstantiatedDefaultArg(
- OldParam->getUninstantiatedDefaultArg());
- else
- NewParam->setDefaultArg(OldParam->getInit());
+ // Merge the old default argument into the new parameter unless the new
+ // function is a friend declaration in a template class. In the latter
+ // case the default arguments will be inherited when the friend
+ // declaration will be instantiated.
+ if (New->getFriendObjectKind() == Decl::FOK_None ||
+ !New->getLexicalDeclContext()->isDependentContext()) {
+ // It's important to use getInit() here; getDefaultArg()
+ // strips off any top-level ExprWithCleanups.
+ NewParam->setHasInheritedDefaultArg();
+ if (OldParam->hasUnparsedDefaultArg())
+ NewParam->setUnparsedDefaultArg();
+ else if (OldParam->hasUninstantiatedDefaultArg())
+ NewParam->setUninstantiatedDefaultArg(
+ OldParam->getUninstantiatedDefaultArg());
+ else
+ NewParam->setDefaultArg(OldParam->getInit());
+ }
} else if (NewParamHasDfl) {
if (New->getDescribedFunctionTemplate()) {
// Paragraph 4, quoted above, only applies to non-template functions.
@@ -575,9 +584,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// or a definition for one of the following explicit specializations:
// - the explicit specialization of a function template;
// - the explicit specialization of a member function template;
- // - the explicit specialization of a member function of a class
+ // - the explicit specialization of a member function of a class
// template where the class template specialization to which the
- // member function specialization belongs is implicitly
+ // member function specialization belongs is implicitly
// instantiated.
Diag(NewParam->getLocation(), diag::err_template_spec_default_arg)
<< (New->getTemplateSpecializationKind() ==TSK_ExplicitSpecialization)
@@ -585,16 +594,16 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
<< NewParam->getDefaultArgRange();
} else if (New->getDeclContext()->isDependentContext()) {
// C++ [dcl.fct.default]p6 (DR217):
- // Default arguments for a member function of a class template shall
- // be specified on the initial declaration of the member function
+ // Default arguments for a member function of a class template shall
+ // be specified on the initial declaration of the member function
// within the class template.
//
- // Reading the tea leaves a bit in DR217 and its reference to DR205
- // leads me to the conclusion that one cannot add default function
- // arguments for an out-of-line definition of a member function of a
+ // Reading the tea leaves a bit in DR217 and its reference to DR205
+ // leads me to the conclusion that one cannot add default function
+ // arguments for an out-of-line definition of a member function of a
// dependent type.
int WhichKind = 2;
- if (CXXRecordDecl *Record
+ if (CXXRecordDecl *Record
= dyn_cast<CXXRecordDecl>(New->getDeclContext())) {
if (Record->getDescribedClassTemplate())
WhichKind = 0;
@@ -603,8 +612,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
else
WhichKind = 2;
}
-
- Diag(NewParam->getLocation(),
+
+ Diag(NewParam->getLocation(),
diag::err_param_default_argument_member_template_redecl)
<< WhichKind
<< NewParam->getDefaultArgRange();
@@ -638,7 +647,12 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Diag(Old->getLocation(), diag::note_previous_declaration);
Invalid = true;
} else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
- Old->isDefined(Def)) {
+ Old->isDefined(Def) &&
+ // If a friend function is inlined but does not have 'inline'
+ // specifier, it is a definition. Do not report attribute conflict
+ // in this case, redefinition will be diagnosed later.
+ (New->isInlineSpecified() ||
+ New->getFriendObjectKind() == Decl::FOK_None)) {
// C++11 [dcl.fcn.spec]p4:
// If the definition of a function appears in a translation unit before its
// first declaration as inline, the program is ill-formed.
@@ -776,7 +790,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// Check for name conflicts.
DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
LookupName(Previous, S,
/*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit());
@@ -808,14 +822,18 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// is unnamed.
DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,
Decomp.getLSquareLoc());
- LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+ ForVisibleRedeclaration);
// Build the variable that holds the non-decomposed object.
bool AddToScope = true;
NamedDecl *New =
ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
MultiTemplateParamsArg(), AddToScope, Bindings);
- CurContext->addHiddenDecl(New);
+ if (AddToScope) {
+ S->AddDecl(New);
+ CurContext->addHiddenDecl(New);
+ }
if (isInOpenMPDeclareTargetContext())
checkDeclIsAllowedInOpenMPTarget(nullptr, New);
@@ -981,7 +999,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);
@@ -2136,7 +2155,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
return nullptr;
}
- if (EllipsisLoc.isValid() &&
+ if (EllipsisLoc.isValid() &&
!TInfo->getType()->containsUnexpandedParameterPack()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< TInfo->getTypeLoc().getSourceRange();
@@ -2285,10 +2304,10 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
GetTypeFromParser(basetype, &TInfo);
if (EllipsisLoc.isInvalid() &&
- DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo,
+ DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo,
UPPC_BaseType))
return true;
-
+
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
Virtual, Access, TInfo,
EllipsisLoc))
@@ -2372,11 +2391,11 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class,
// Note this base's direct & indirect bases, if there could be ambiguity.
if (Bases.size() > 1)
NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType);
-
+
if (const RecordType *Record = NewBaseType->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
if (Class->isInterface() &&
- (!RD->isInterface() ||
+ (!RD->isInterfaceLike() ||
KnownBase->getAccessSpecifier() != AS_public)) {
// The Microsoft extension __interface does not permit bases that
// are not themselves public interfaces.
@@ -2393,7 +2412,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class,
// Attach the remaining base class specifiers to the derived class.
Class->setBases(Bases.data(), NumGoodBases);
-
+
for (unsigned idx = 0; idx < NumGoodBases; ++idx) {
// Check whether this direct base is inaccessible due to ambiguity.
QualType BaseType = Bases[idx]->getType();
@@ -2445,7 +2464,7 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) {
CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
-
+
CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
@@ -2459,7 +2478,7 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) {
// to be able to use the inheritance relationship?
if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined())
return false;
-
+
return DerivedRD->isDerivedFrom(BaseRD);
}
@@ -2469,28 +2488,23 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base,
CXXBasePaths &Paths) {
if (!getLangOpts().CPlusPlus)
return false;
-
+
CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
-
+
CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
-
+
if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined())
return false;
-
+
return DerivedRD->isDerivedFrom(BaseRD, Paths);
}
-void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
- CXXCastPath &BasePathArray) {
- assert(BasePathArray.empty() && "Base path array must be empty!");
- assert(Paths.isRecordingPaths() && "Must record paths!");
-
- const CXXBasePath &Path = Paths.front();
-
+static void BuildBasePathArray(const CXXBasePath &Path,
+ CXXCastPath &BasePathArray) {
// We first go backward and check if we have a virtual base.
// FIXME: It would be better if CXXBasePath had the base specifier for
// the nearest virtual base.
@@ -2507,6 +2521,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
BasePathArray.push_back(const_cast<CXXBaseSpecifier*>(Path[I].Base));
}
+
+void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
+ CXXCastPath &BasePathArray) {
+ assert(BasePathArray.empty() && "Base path array must be empty!");
+ assert(Paths.isRecordingPaths() && "Must record paths!");
+ return ::BuildBasePathArray(Paths.front(), BasePathArray);
+}
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
/// conversion (where Derived and Base are class types) is
/// well-formed, meaning that the conversion is unambiguous (and
@@ -2534,30 +2555,48 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
bool DerivationOkay = IsDerivedFrom(Loc, Derived, Base, Paths);
- assert(DerivationOkay &&
- "Can only be used with a derived-to-base conversion");
- (void)DerivationOkay;
-
- if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
+ if (!DerivationOkay)
+ return true;
+
+ const CXXBasePath *Path = nullptr;
+ if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType()))
+ Path = &Paths.front();
+
+ // For MSVC compatibility, check if Derived directly inherits from Base. Clang
+ // warns about this hierarchy under -Winaccessible-base, but MSVC allows the
+ // user to access such bases.
+ if (!Path && getLangOpts().MSVCCompat) {
+ for (const CXXBasePath &PossiblePath : Paths) {
+ if (PossiblePath.size() == 1) {
+ Path = &PossiblePath;
+ if (AmbigiousBaseConvID)
+ Diag(Loc, diag::ext_ms_ambiguous_direct_base)
+ << Base << Derived << Range;
+ break;
+ }
+ }
+ }
+
+ if (Path) {
if (!IgnoreAccess) {
// Check that the base class can be accessed.
- switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
- InaccessibleBaseID)) {
- case AR_inaccessible:
- return true;
- case AR_accessible:
- case AR_dependent:
- case AR_delayed:
- break;
+ switch (
+ CheckBaseClassAccess(Loc, Base, Derived, *Path, InaccessibleBaseID)) {
+ case AR_inaccessible:
+ return true;
+ case AR_accessible:
+ case AR_dependent:
+ case AR_delayed:
+ break;
}
}
-
+
// Build a base path if necessary.
if (BasePath)
- BuildBasePathArray(Paths, *BasePath);
+ ::BuildBasePathArray(*Path, *BasePath);
return false;
}
-
+
if (AmbigiousBaseConvID) {
// We know that the derived-to-base conversion is ambiguous, and
// we're going to produce a diagnostic. Perform the derived-to-base
@@ -2622,7 +2661,7 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) {
PathDisplayStr += " -> " + Element->Base->getType().getAsString();
}
}
-
+
return PathDisplayStr;
}
@@ -2845,6 +2884,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
assert(!DS.isFriendSpecified());
bool isFunc = D.isDeclarationOfFunction();
+ AttributeList *MSPropertyAttr =
+ getMSPropertyAttr(D.getDeclSpec().getAttributes().getList());
if (cast<CXXRecordDecl>(CurContext)->isInterface()) {
// The Microsoft extension __interface only permits public member functions
@@ -2852,8 +2893,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// functions, static methods and data members.
unsigned InvalidDecl;
bool ShowDeclName = true;
- if (!isFunc)
- InvalidDecl = (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) ? 0 : 1;
+ if (!isFunc &&
+ (DS.getStorageClassSpec() == DeclSpec::SCS_typedef || MSPropertyAttr))
+ InvalidDecl = 0;
+ else if (!isFunc)
+ InvalidDecl = 1;
else if (AS != AS_public)
InvalidDecl = 2;
else if (DS.getStorageClassSpec() == DeclSpec::SCS_static)
@@ -3001,12 +3045,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
else
Diag(D.getIdentifierLoc(), diag::err_member_qualification)
<< Name << SS.getRange();
-
+
SS.clear();
}
- AttributeList *MSPropertyAttr =
- getMSPropertyAttr(D.getDeclSpec().getAttributes().getList());
if (MSPropertyAttr) {
Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D,
BitWidth, InitStyle, AS, MSPropertyAttr);
@@ -3375,14 +3417,9 @@ namespace {
void VisitCallExpr(CallExpr *E) {
// Treat std::move as a use.
- if (E->getNumArgs() == 1) {
- if (FunctionDecl *FD = E->getDirectCallee()) {
- if (FD->isInStdNamespace() && FD->getIdentifier() &&
- FD->getIdentifier()->isStr("move")) {
- HandleValue(E->getArg(0), false /*AddressOf*/);
- return;
- }
- }
+ if (E->isCallToStdMove()) {
+ HandleValue(E->getArg(0), /*AddressOf=*/false);
+ return;
}
Inherited::VisitCallExpr(E);
@@ -3570,7 +3607,7 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
/// \brief Find the direct and/or virtual base specifiers that
/// correspond to the given base type, for use in base initialization
/// within a constructor.
-static bool FindBaseInitializer(Sema &SemaRef,
+static bool FindBaseInitializer(Sema &SemaRef,
CXXRecordDecl *ClassDecl,
QualType BaseType,
const CXXBaseSpecifier *&DirectBaseSpec,
@@ -3754,7 +3791,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (SS.isSet() && isDependentScopeSpecifier(SS)) {
bool NotUnknownSpecialization = false;
DeclContext *DC = computeDeclContext(SS, false);
- if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC))
+ if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC))
NotUnknownSpecialization = !Record->hasAnyDependentBases();
if (!NotUnknownSpecialization) {
@@ -3766,6 +3803,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (BaseType.isNull())
return true;
+ TInfo = Context.CreateTypeSourceInfo(BaseType);
+ DependentNameTypeLoc TL =
+ TInfo->getTypeLoc().castAs<DependentNameTypeLoc>();
+ if (!TL.isNull()) {
+ TL.setNameLoc(IdLoc);
+ TL.setElaboratedKeywordLoc(SourceLocation());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ }
+
R.clear();
R.setLookupName(MemberOrBase);
}
@@ -3789,7 +3835,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
} else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
const CXXBaseSpecifier *VirtualBaseSpec;
- if (FindBaseInitializer(*this, ClassDecl,
+ if (FindBaseInitializer(*this, ClassDecl,
Context.getTypeDeclType(Type),
DirectBaseSpec, VirtualBaseSpec)) {
// We have found a direct or virtual base class with a
@@ -4014,7 +4060,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
if (CurContext->isDependentContext())
DelegationInit = Init;
- return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
+ return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
DelegationInit.getAs<Expr>(),
InitRange.getEnd());
}
@@ -4059,12 +4105,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// Check for direct and virtual base classes.
const CXXBaseSpecifier *DirectBaseSpec = nullptr;
const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
- if (!Dependent) {
+ if (!Dependent) {
if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
BaseType))
return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
- FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+ FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
VirtualBaseSpec);
// C++ [base.class.init]p2:
@@ -4184,7 +4230,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
IsInheritedVirtualBase);
ExprResult BaseInit;
-
+
switch (ImplicitInitKind) {
case IIK_Inherit:
case IIK_Default: {
@@ -4201,7 +4247,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
- Expr *CopyCtorArg =
+ Expr *CopyCtorArg =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
SourceLocation(), Param, false,
Constructor->getLocation(), ParamType,
@@ -4210,8 +4256,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(CopyCtorArg));
// Cast to the base class to avoid ambiguities.
- QualType ArgTy =
- SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
+ QualType ArgTy =
+ SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
ParamType.getQualifiers());
if (Moving) {
@@ -4237,10 +4283,10 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit);
if (BaseInit.isInvalid())
return true;
-
+
CXXBaseInit =
new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context,
- SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(),
+ SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(),
SourceLocation()),
BaseSpec->isVirtual(),
SourceLocation(),
@@ -4274,8 +4320,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// Suppress copying zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0)
return false;
-
- Expr *MemberExprBase =
+
+ Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
SourceLocation(), Param, false,
Loc, ParamType, VK_LValue, nullptr);
@@ -4293,7 +4339,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect)
: cast<ValueDecl>(Field), AS_public);
MemberLookup.resolveKind();
- ExprResult CtorArg
+ ExprResult CtorArg
= SemaRef.BuildMemberReferenceExpr(MemberExprBase,
ParamType, Loc,
/*IsArrow=*/false,
@@ -4322,7 +4368,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// Direct-initialize to use the copy constructor.
InitializationKind InitKind =
InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
-
+
Expr *CtorArgE = CtorArg.getAs<Expr>();
InitializationSequence InitSeq(SemaRef, Entity, InitKind, CtorArgE);
ExprResult MemberInit =
@@ -4343,16 +4389,16 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) &&
"Unhandled implicit init kind!");
- QualType FieldBaseElementType =
+ QualType FieldBaseElementType =
SemaRef.Context.getBaseElementType(Field->getType());
-
+
if (FieldBaseElementType->isRecordType()) {
InitializedEntity InitEntity =
Indirect ? InitializedEntity::InitializeMember(Indirect, nullptr,
/*Implicit*/ true)
: InitializedEntity::InitializeMember(Field, nullptr,
/*Implicit*/ true);
- InitializationKind InitKind =
+ InitializationKind InitKind =
InitializationKind::CreateDefault(Loc);
InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None);
@@ -4362,10 +4408,10 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit);
if (MemberInit.isInvalid())
return true;
-
+
if (Indirect)
CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context,
- Indirect, Loc,
+ Indirect, Loc,
Loc,
MemberInit.get(),
Loc);
@@ -4379,9 +4425,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
if (!Field->getParent()->isUnion()) {
if (FieldBaseElementType->isReferenceType()) {
- SemaRef.Diag(Constructor->getLocation(),
+ SemaRef.Diag(Constructor->getLocation(),
diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
+ << (int)Constructor->isImplicit()
<< SemaRef.Context.getTagDeclType(Constructor->getParent())
<< 0 << Field->getDeclName();
SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
@@ -4389,30 +4435,27 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
if (FieldBaseElementType.isConstQualified()) {
- SemaRef.Diag(Constructor->getLocation(),
+ SemaRef.Diag(Constructor->getLocation(),
diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
+ << (int)Constructor->isImplicit()
<< SemaRef.Context.getTagDeclType(Constructor->getParent())
<< 1 << Field->getDeclName();
SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
return true;
}
}
-
- 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,
- Loc, Loc,
- new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()),
+ = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ Loc, Loc,
+ new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()),
Loc);
return false;
}
-
+
// Nothing to initialize.
CXXMemberInit = nullptr;
return false;
@@ -4440,13 +4483,13 @@ struct BaseAndFieldInfo {
else
IIK = IIK_Default;
}
-
+
bool isImplicitCopyOrMove() const {
switch (IIK) {
case IIK_Copy:
case IIK_Move:
return true;
-
+
case IIK_Default:
case IIK_Inherit:
return false;
@@ -4513,19 +4556,19 @@ struct BaseAndFieldInfo {
static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
if (T->isIncompleteArrayType())
return true;
-
+
while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) {
if (!ArrayT->getSize())
return true;
-
+
T = ArrayT->getElementType();
}
-
+
return false;
}
static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
- FieldDecl *Field,
+ FieldDecl *Field,
IndirectFieldDecl *Indirect = nullptr) {
if (Field->isInvalidDecl())
return false;
@@ -4638,7 +4681,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
if (!ClassDecl)
return true;
-
+
bool HadError = false;
for (unsigned i = 0; i < Initializers.size(); i++) {
@@ -4737,34 +4780,34 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
// initialized.
if (F->isUnnamedBitfield())
continue;
-
+
// If we're not generating the implicit copy/move constructor, then we'll
// handle anonymous struct/union fields based on their individual
// indirect fields.
if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove())
continue;
-
+
if (CollectFieldInitializer(*this, Info, F))
HadError = true;
continue;
}
-
+
// Beyond this point, we only consider default initialization.
if (Info.isImplicitCopyOrMove())
continue;
-
+
if (auto *F = dyn_cast<IndirectFieldDecl>(Mem)) {
if (F->getType()->isIncompleteArrayType()) {
assert(ClassDecl->hasFlexibleArrayMember() &&
"Incomplete array type is not valid");
continue;
}
-
+
// Initialize each field of an anonymous struct individually.
if (CollectFieldInitializer(*this, Info, F->getAnonField(), F))
HadError = true;
-
- continue;
+
+ continue;
}
}
@@ -4806,7 +4849,7 @@ static const void *GetKeyForMember(ASTContext &Context,
CXXCtorInitializer *Member) {
if (!Member->isAnyMemberInitializer())
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
-
+
return Member->getAnyMember()->getCanonicalDecl();
}
@@ -4817,7 +4860,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
return;
// Don't check initializers order unless the warning is enabled at the
- // location of at least one initializer.
+ // location of at least one initializer.
bool ShouldCheckOrder = false;
for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
@@ -4829,7 +4872,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
}
if (!ShouldCheckOrder)
return;
-
+
// Build the list of bases and members in the order that they'll
// actually be initialized. The explicit initializers should be in
// this same order but may be missing things.
@@ -4852,10 +4895,10 @@ static void DiagnoseBaseOrMemInitializerOrder(
for (auto *Field : ClassDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
-
+
PopulateKeysForFields(Field, IdealInitKeys);
}
-
+
unsigned NumIdealInits = IdealInitKeys.size();
unsigned IdealIndex = 0;
@@ -4882,7 +4925,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
D << 0 << PrevInit->getAnyMember()->getDeclName();
else
D << 1 << PrevInit->getTypeSourceInfo()->getType();
-
+
if (Init->isAnyMemberInitializer())
D << 0 << Init->getAnyMember()->getDeclName();
else
@@ -4950,7 +4993,7 @@ bool CheckRedundantUnionInit(Sema &S,
S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer)
<< 0 << En.second->getSourceRange();
return true;
- }
+ }
if (!En.first) {
En.first = Child;
En.second = Init;
@@ -4984,7 +5027,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
return;
}
-
+
// Mapping for the duplicate initializers check.
// For member initializers, this is keyed with a FieldDecl*.
// For base initializers, this is keyed with a Type*.
@@ -5046,22 +5089,22 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// field/base declaration. That's probably good; that said, the
// user might reasonably want to know why the destructor is being
// emitted, and we currently don't say.
-
+
// Non-static data members.
for (auto *Field : ClassDecl->fields()) {
if (Field->isInvalidDecl())
continue;
-
+
// Don't destroy incomplete or zero-length arrays.
if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
continue;
QualType FieldType = Context.getBaseElementType(Field->getType());
-
+
const RecordType* RT = FieldType->getAs<RecordType>();
if (!RT)
continue;
-
+
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (FieldClassDecl->isInvalidDecl())
continue;
@@ -5116,14 +5159,14 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
<< Base.getType()
<< Base.getSourceRange(),
Context.getTypeDeclType(ClassDecl));
-
+
MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
if (!VisitVirtualBases)
return;
-
+
// Virtual bases.
for (const auto &VBase : ClassDecl->vbases()) {
// Bases are always records in a well-formed non-dependent class.
@@ -5220,12 +5263,12 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
// Keep a set of seen pure methods so we won't diagnose the same method
// more than once.
llvm::SmallPtrSet<const CXXMethodDecl *, 8> SeenPureMethods;
-
- for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
MEnd = FinalOverriders.end();
- M != MEnd;
+ M != MEnd;
++M) {
- for (OverridingMethods::iterator SO = M->second.begin(),
+ for (OverridingMethods::iterator SO = M->second.begin(),
SOEnd = M->second.end();
SO != SOEnd; ++SO) {
// C++ [class.abstract]p4:
@@ -5233,7 +5276,7 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
// pure virtual function for which the final overrider is pure
// virtual.
- //
+ //
if (SO->second.size() != 1)
continue;
@@ -5243,8 +5286,8 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
if (!SeenPureMethods.insert(SO->second.front().Method).second)
continue;
- Diag(SO->second.front().Method->getLocation(),
- diag::note_pure_virtual_function)
+ Diag(SO->second.front().Method->getLocation(),
+ diag::note_pure_virtual_function)
<< SO->second.front().Method->getDeclName() << RD->getDeclName();
}
}
@@ -5455,7 +5498,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()) {
@@ -5708,6 +5751,53 @@ static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
}
}
+/// Determine whether a type is permitted to be passed or returned in
+/// registers, per C++ [class.temporary]p3.
+static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) {
+ if (D->isDependentType() || D->isInvalidDecl())
+ return false;
+
+ // Per C++ [class.temporary]p3, the relevant condition is:
+ // each copy constructor, move constructor, and destructor of X is
+ // either trivial or deleted, and X has at least one non-deleted copy
+ // or move constructor
+ bool HasNonDeletedCopyOrMove = false;
+
+ if (D->needsImplicitCopyConstructor() &&
+ !D->defaultedCopyConstructorIsDeleted()) {
+ if (!D->hasTrivialCopyConstructor())
+ return false;
+ HasNonDeletedCopyOrMove = true;
+ }
+
+ if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() &&
+ !D->defaultedMoveConstructorIsDeleted()) {
+ if (!D->hasTrivialMoveConstructor())
+ return false;
+ HasNonDeletedCopyOrMove = true;
+ }
+
+ if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() &&
+ !D->hasTrivialDestructor())
+ return false;
+
+ for (const CXXMethodDecl *MD : D->methods()) {
+ if (MD->isDeleted())
+ continue;
+
+ auto *CD = dyn_cast<CXXConstructorDecl>(MD);
+ if (CD && CD->isCopyOrMoveConstructor())
+ HasNonDeletedCopyOrMove = true;
+ else if (!isa<CXXDestructorDecl>(MD))
+ continue;
+
+ if (!MD->isTrivial())
+ return false;
+ }
+
+ return HasNonDeletedCopyOrMove;
+}
+
/// \brief Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
@@ -5719,7 +5809,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
AbstractUsageInfo Info(*this, Record);
CheckAbstractClassUsage(Info, Record);
}
-
+
// If this is not an aggregate type and has no user-declared constructor,
// complain about any non-static data members of reference or const scalar
// type, since they will never get initializers.
@@ -5738,7 +5828,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
<< Record->getTagKind() << Record;
Complained = true;
}
-
+
Diag(F->getLocation(), diag::note_refconst_member_not_initialized)
<< F->getType()->isReferenceType()
<< F->getDeclName();
@@ -5748,12 +5838,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->getIdentifier()) {
// C++ [class.mem]p13:
- // If T is the name of a class, then each of the following shall have a
+ // If T is the name of a class, then each of the following shall have a
// name different from T:
// - every member of every anonymous union that is a member of class T.
//
// C++ [class.mem]p14:
- // In addition, if class T has a user-declared constructor (12.1), every
+ // In addition, if class T has a user-declared constructor (12.1), every
// non-static data member of class T shall have a name different from T.
DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
@@ -5852,6 +5942,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
checkClassLevelDLLAttribute(Record);
+
+ Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record));
}
/// Look up the special member function that would be called by a special
@@ -7148,8 +7240,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();
@@ -7479,8 +7570,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(
- dyn_cast_or_null<CXXRecordDecl>(TagDecl));
+ CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl));
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -7753,11 +7843,11 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
// A constructor shall not be declared with a ref-qualifier.
if (FTI.hasRefQualifier()) {
Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor)
- << FTI.RefQualifierIsLValueRef
+ << FTI.RefQualifierIsLValueRef
<< FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
D.setInvalidType();
}
-
+
// Rebuild the function type "R" without any type qualifiers (in
// case any of the errors above fired) and with "void" as the
// return type, since constructors don't have return types.
@@ -7796,8 +7886,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
QualType ClassTy = Context.getTagDeclType(ClassDecl);
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
- const char *ConstRef
- = Constructor->getParamDecl(0)->getIdentifier() ? "const &"
+ const char *ConstRef
+ = Constructor->getParamDecl(0)->getIdentifier() ? "const &"
: " const &";
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
<< FixItHint::CreateInsertion(ParamLoc, ConstRef);
@@ -7814,23 +7904,49 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
/// on error.
bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
CXXRecordDecl *RD = Destructor->getParent();
-
+
if (!Destructor->getOperatorDelete() && Destructor->isVirtual()) {
SourceLocation Loc;
-
+
if (!Destructor->isImplicit())
Loc = Destructor->getLocation();
else
Loc = RD->getLocation();
-
+
// If we have a virtual destructor, look up the deallocation function
if (FunctionDecl *OperatorDelete =
FindDeallocationFunctionForDestructor(Loc, RD)) {
+ Expr *ThisArg = nullptr;
+
+ // If the notional 'delete this' expression requires a non-trivial
+ // conversion from 'this' to the type of a destroying operator delete's
+ // first parameter, perform that conversion now.
+ if (OperatorDelete->isDestroyingOperatorDelete()) {
+ QualType ParamType = OperatorDelete->getParamDecl(0)->getType();
+ if (!declaresSameEntity(ParamType->getAsCXXRecordDecl(), RD)) {
+ // C++ [class.dtor]p13:
+ // ... as if for the expression 'delete this' appearing in a
+ // non-virtual destructor of the destructor's class.
+ ContextRAII SwitchContext(*this, Destructor);
+ ExprResult This =
+ ActOnCXXThis(OperatorDelete->getParamDecl(0)->getLocation());
+ assert(!This.isInvalid() && "couldn't form 'this' expr in dtor?");
+ This = PerformImplicitConversion(This.get(), ParamType, AA_Passing);
+ if (This.isInvalid()) {
+ // FIXME: Register this as a context note so that it comes out
+ // in the right order.
+ Diag(Loc, diag::note_implicit_delete_this_in_destructor_here);
+ return true;
+ }
+ ThisArg = This.get();
+ }
+ }
+
MarkFunctionReferenced(Loc, OperatorDelete);
- Destructor->setOperatorDelete(OperatorDelete);
+ Destructor->setOperatorDelete(OperatorDelete, ThisArg);
}
}
-
+
return false;
}
@@ -7871,7 +7987,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
<< "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
<< SourceRange(D.getIdentifierLoc())
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
-
+
SC = SC_None;
}
if (!D.isInvalidType()) {
@@ -7920,7 +8036,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
<< FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
D.setInvalidType();
}
-
+
// Make sure we don't have any parameters.
if (FTIHasNonVoidParameters(FTI)) {
Diag(D.getIdentifierLoc(), diag::err_destructor_with_params);
@@ -7939,7 +8055,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
// Rebuild the function type "R" without any type qualifiers or
// parameters (in case any of the errors above fired) and with
// "void" as the return type, since destructors don't have return
- // types.
+ // types.
if (!D.isInvalidType())
return R;
@@ -8168,7 +8284,7 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
return ConversionTemplate;
-
+
return Conversion;
}
@@ -8396,7 +8512,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// Since namespace names are unique in their scope, and we don't
// look through using directives, just look for any ordinary names
// as if by qualified name lookup.
- LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, ForRedeclaration);
+ LookupResult R(*this, II, IdentLoc, LookupOrdinaryName,
+ ForExternalRedeclaration);
LookupQualifiedName(R, CurContext->getRedeclContext());
NamedDecl *PrevDecl =
R.isSingleResult() ? R.getRepresentativeDecl() : nullptr;
@@ -8427,7 +8544,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
}
} else {
// Anonymous namespaces.
-
+
// Determine whether the parent already has an anonymous namespace.
DeclContext *Parent = CurContext->getRedeclContext();
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
@@ -8441,13 +8558,14 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, NamespaceLoc, II,
&IsInline, PrevNS);
}
-
+
NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
StartLoc, Loc, II, PrevNS);
if (IsInvalid)
Namespc->setInvalidDecl();
-
+
ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
+ AddPragmaAttributes(DeclRegionScope, Namespc);
// FIXME: Should we be merging attributes?
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
@@ -8457,7 +8575,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
StdNamespace = Namespc;
if (AddToKnown)
KnownNamespaces[Namespc] = false;
-
+
if (II) {
PushOnScopeChains(Namespc, DeclRegionScope);
} else {
@@ -8558,12 +8676,12 @@ NamespaceDecl *Sema::lookupStdExperimentalNamespace() {
return StdExperimentalNamespaceCache;
}
-/// \brief Retrieve the special "std" namespace, which may require us to
+/// \brief Retrieve the special "std" namespace, which may require us to
/// implicitly define the namespace.
NamespaceDecl *Sema::getOrCreateStdNamespace() {
if (!StdNamespace) {
// The "std" namespace has not yet been defined, so build one implicitly.
- StdNamespace = NamespaceDecl::Create(Context,
+ StdNamespace = NamespaceDecl::Create(Context,
Context.getTranslationUnitDecl(),
/*Inline=*/false,
SourceLocation(), SourceLocation(),
@@ -8776,7 +8894,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
NestedNameSpecifier *Qualifier = nullptr;
if (SS.isSet())
Qualifier = SS.getScopeRep();
-
+
// Lookup namespace name.
LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS);
@@ -8785,18 +8903,18 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
if (R.empty()) {
R.clear();
- // Allow "using namespace std;" or "using namespace ::std;" even if
+ // Allow "using namespace std;" or "using namespace ::std;" even if
// "std" hasn't been defined yet, for GCC compatibility.
if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) &&
NamespcName->isStr("std")) {
Diag(IdentLoc, diag::ext_using_undefined_std);
R.addDecl(getOrCreateStdNamespace());
R.resolveKind();
- }
+ }
// Otherwise, attempt typo correction.
else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName);
}
-
+
if (!R.empty()) {
NamedDecl *Named = R.getRepresentativeDecl();
NamespaceDecl *NS = R.getAsSingle<NamespaceDecl>();
@@ -8877,7 +8995,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_ConversionFunctionId:
break;
-
+
case UnqualifiedId::IK_ConstructorName:
case UnqualifiedId::IK_ConstructorTemplateId:
// C++11 inheriting constructors.
@@ -9020,7 +9138,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// If the target happens to be one of the previous declarations, we
// don't have a conflict.
- //
+ //
// FIXME: but we might be increasing its access, in which case we
// should redeclare it.
NamedDecl *NonTag = nullptr, *Tag = nullptr;
@@ -9332,7 +9450,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Do the redeclaration lookup in the current scope.
LookupResult Previous(*this, UsingName, LookupUsingDeclName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
Previous.setHideTags(false);
if (S) {
LookupName(Previous, S);
@@ -9395,7 +9513,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
IdentLoc, NameInfo.getName(),
EllipsisLoc);
} else {
- D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc,
+ D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc,
QualifierLoc, NameInfo, EllipsisLoc);
}
D->setAccess(AS);
@@ -9908,11 +10026,14 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
UPPC_DeclarationType)) {
Invalid = true;
- TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
+ TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
TInfo->getTypeLoc().getBeginLoc());
}
- LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+ TemplateParamLists.size()
+ ? forRedeclarationInCurContext()
+ : ForVisibleRedeclaration);
LookupName(Previous, S);
// Warn about shadowing the name of a template parameter.
@@ -9934,6 +10055,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
NewTD->setInvalidDecl();
ProcessDeclAttributeList(S, NewTD, AttrList);
+ AddPragmaAttributes(S, NewTD);
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
@@ -10014,8 +10136,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewDecl->setInvalidDecl();
- else if (OldDecl)
+ else if (OldDecl) {
NewDecl->setPreviousDecl(OldDecl);
+ CheckRedeclarationModuleOwnership(NewDecl, OldDecl);
+ }
NewND = NewDecl;
} else {
@@ -10056,7 +10180,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
// Check if we have a previous declaration with the same name.
LookupResult PrevR(*this, Alias, AliasLoc, LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
LookupName(PrevR, S);
// Check we're not shadowing a template parameter.
@@ -10070,7 +10194,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
/*AllowInlineNamespace*/false);
// Find the previous declaration and check that we can redeclare it.
- NamespaceAliasDecl *Prev = nullptr;
+ NamespaceAliasDecl *Prev = nullptr;
if (PrevR.isSingleResult()) {
NamedDecl *PrevDecl = PrevR.getRepresentativeDecl();
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
@@ -10191,7 +10315,7 @@ ComputeDefaultedSpecialMemberExceptionSpec(
CXXRecordDecl *ClassDecl = MD->getParent();
// C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
+ // An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc);
if (ClassDecl->isInvalidDecl())
@@ -10269,7 +10393,7 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
// implicit special members with this name.
DeclarationName Name = FD->getDeclName();
LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName,
- ForRedeclaration);
+ ForExternalRedeclaration);
for (auto *D : FD->getParent()->lookup(Name))
if (auto *Acceptable = R.getAcceptableDecl(D))
R.addDecl(Acceptable);
@@ -10349,32 +10473,33 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
!Constructor->doesThisDeclarationHaveABody() &&
!Constructor->isDeleted()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
+ if (Constructor->willHaveBody() || Constructor->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
SynthesizedFunctionScope Scope(*this, Constructor);
- DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
- Constructor->setInvalidDecl();
- return;
- }
// The exception specification is needed because we are defining the
// function.
ResolveExceptionSpec(CurrentLocation,
Constructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
+ if (SetCtorInitializers(Constructor, /*AnyErrors=*/false)) {
+ Constructor->setInvalidDecl();
+ return;
+ }
SourceLocation Loc = Constructor->getLocEnd().isValid()
? Constructor->getLocEnd()
: Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc));
-
Constructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
@@ -10484,9 +10609,22 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
assert(Constructor->getInheritedConstructor() &&
!Constructor->doesThisDeclarationHaveABody() &&
!Constructor->isDeleted());
- if (Constructor->isInvalidDecl())
+ if (Constructor->willHaveBody() || Constructor->isInvalidDecl())
return;
+ // Initializations are performed "as if by a defaulted default constructor",
+ // so enter the appropriate scope.
+ SynthesizedFunctionScope Scope(*this, Constructor);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Constructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
ConstructorUsingShadowDecl *Shadow =
Constructor->getInheritedConstructor().getShadowDecl();
CXXConstructorDecl *InheritedCtor =
@@ -10501,11 +10639,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *RD = Shadow->getParent();
SourceLocation InitLoc = Shadow->getLocation();
- // Initializations are performed "as if by a defaulted default constructor",
- // so enter the appropriate scope.
- SynthesizedFunctionScope Scope(*this, Constructor);
- DiagnosticErrorTrap Trap(Diags);
-
// Build explicit initializers for all base classes from which the
// constructor was inherited.
SmallVector<CXXCtorInitializer*, 8> Inits;
@@ -10536,22 +10669,13 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
// We now proceed as if for a defaulted default constructor, with the relevant
// initializers replaced.
- bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits);
- if (HadError || Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD;
+ if (SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits)) {
Constructor->setInvalidDecl();
return;
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- Constructor->getType()->castAs<FunctionProtoType>());
-
Constructor->setBody(new (Context) CompoundStmt(InitLoc));
-
Constructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
@@ -10627,37 +10751,36 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
!Destructor->doesThisDeclarationHaveABody() &&
!Destructor->isDeleted()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
+ if (Destructor->willHaveBody() || Destructor->isInvalidDecl())
+ return;
+
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
- if (Destructor->isInvalidDecl())
- return;
-
SynthesizedFunctionScope Scope(*this, Destructor);
- DiagnosticErrorTrap Trap(Diags);
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Destructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
- if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXDestructor << Context.getTagDeclType(ClassDecl);
-
+ if (CheckDestructor(Destructor)) {
Destructor->setInvalidDecl();
return;
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- Destructor->getType()->castAs<FunctionProtoType>());
-
SourceLocation Loc = Destructor->getLocEnd().isValid()
? Destructor->getLocEnd()
: Destructor->getLocation();
Destructor->setBody(new (Context) CompoundStmt(Loc));
Destructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Destructor);
@@ -11057,7 +11180,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
//
// for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0)
//
- // that will copy each of the array elements.
+ // that will copy each of the array elements.
QualType SizeType = S.Context.getSizeType();
// Create the iteration variable.
@@ -11111,7 +11234,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
@@ -11225,8 +11348,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
/// Diagnose an implicit copy operation for a class which is odr-used, but
/// which is deprecated because the class has a user-declared copy constructor,
/// copy assignment operator, or destructor.
-static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
- SourceLocation UseLoc) {
+static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
assert(CopyOp->isImplicit());
CXXRecordDecl *RD = CopyOp->getParent();
@@ -11265,52 +11387,54 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
diag::warn_deprecated_copy_operation)
<< RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp)
<< /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation);
- S.Diag(UseLoc, diag::note_member_synthesized_at)
- << (isa<CXXConstructorDecl>(CopyOp) ? Sema::CXXCopyConstructor
- : Sema::CXXCopyAssignment)
- << RD;
}
}
void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *CopyAssignOperator) {
- assert((CopyAssignOperator->isDefaulted() &&
+ assert((CopyAssignOperator->isDefaulted() &&
CopyAssignOperator->isOverloadedOperator() &&
CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
!CopyAssignOperator->doesThisDeclarationHaveABody() &&
!CopyAssignOperator->isDeleted()) &&
"DefineImplicitCopyAssignment called for wrong function");
+ if (CopyAssignOperator->willHaveBody() || CopyAssignOperator->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
-
- if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) {
+ if (ClassDecl->isInvalidDecl()) {
CopyAssignOperator->setInvalidDecl();
return;
}
+ SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ CopyAssignOperator->getType()->castAs<FunctionProtoType>());
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
// C++11 [class.copy]p18:
// The [definition of an implicitly declared copy assignment operator] is
// deprecated if the class has a user-declared copy constructor or a
// user-declared destructor.
if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit())
- diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation);
-
- CopyAssignOperator->markUsed(Context);
-
- SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
- DiagnosticErrorTrap Trap(Diags);
+ diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator);
// C++0x [class.copy]p30:
// The implicitly-defined or explicitly-defaulted copy assignment operator
- // for a non-union class X performs memberwise copy assignment of its
- // subobjects. The direct base classes of X are assigned first, in the
- // order of their declaration in the base-specifier-list, and then the
- // immediate non-static data members of X are assigned, in the order in
+ // for a non-union class X performs memberwise copy assignment of its
+ // subobjects. The direct base classes of X are assigned first, in the
+ // order of their declaration in the base-specifier-list, and then the
+ // immediate non-static data members of X are assigned, in the order in
// which they were declared in the class definition.
-
+
// The statements that form the synthesized function body.
SmallVector<Stmt*, 8> Statements;
-
+
// The parameter for the "other" object, which we are copying from.
ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
Qualifiers OtherQuals = Other->getType().getQualifiers();
@@ -11320,7 +11444,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
OtherRefType = OtherRef->getPointeeType();
OtherQuals = OtherRefType.getQualifiers();
}
-
+
// Our location for everything implicitly-generated.
SourceLocation Loc = CopyAssignOperator->getLocEnd().isValid()
? CopyAssignOperator->getLocEnd()
@@ -11331,7 +11455,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Builds the "this" pointer.
ThisBuilder This;
-
+
// Assign base classes.
bool Invalid = false;
for (auto &Base : ClassDecl->bases()) {
@@ -11364,16 +11488,14 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/true,
/*Copying=*/true);
if (Copy.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
CopyAssignOperator->setInvalidDecl();
return;
}
-
+
// Success! Record the copy.
Statements.push_back(Copy.getAs<Expr>());
}
-
+
// Assign non-static members.
for (auto *Field : ClassDecl->fields()) {
// FIXME: We should form some kind of AST representation for the implied
@@ -11391,35 +11513,31 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
-
+
// Check for members of const-qualified, non-class type.
QualType BaseType = Context.getBaseElementType(Field->getType());
if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
- Invalid = true;
+ Invalid = true;
continue;
}
// Suppress assigning zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
continue;
-
+
QualType FieldType = Field->getType().getNonReferenceType();
if (FieldType->isIncompleteArrayType()) {
- assert(ClassDecl->hasFlexibleArrayMember() &&
+ assert(ClassDecl->hasFlexibleArrayMember() &&
"Incomplete array type is not valid");
continue;
}
-
+
// Build references to the field in the object we're copying from and to.
CXXScopeSpec SS; // Intentionally empty
LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
@@ -11437,12 +11555,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/false,
/*Copying=*/true);
if (Copy.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
CopyAssignOperator->setInvalidDecl();
return;
}
-
+
// Success! Record the copy.
Statements.push_back(Copy.getAs<Stmt>());
}
@@ -11450,26 +11566,14 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
-
+
StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
Invalid = true;
- else {
+ else
Statements.push_back(Return.getAs<Stmt>());
-
- if (Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
- Invalid = true;
- }
- }
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- CopyAssignOperator->getType()->castAs<FunctionProtoType>());
-
if (Invalid) {
CopyAssignOperator->setInvalidDecl();
return;
@@ -11483,6 +11587,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
CopyAssignOperator->setBody(Body.getAs<Stmt>());
+ CopyAssignOperator->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyAssignOperator);
@@ -11649,24 +11754,20 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *MoveAssignOperator) {
- assert((MoveAssignOperator->isDefaulted() &&
+ assert((MoveAssignOperator->isDefaulted() &&
MoveAssignOperator->isOverloadedOperator() &&
MoveAssignOperator->getOverloadedOperator() == OO_Equal &&
!MoveAssignOperator->doesThisDeclarationHaveABody() &&
!MoveAssignOperator->isDeleted()) &&
"DefineImplicitMoveAssignment called for wrong function");
+ if (MoveAssignOperator->willHaveBody() || MoveAssignOperator->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent();
-
- if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) {
+ if (ClassDecl->isInvalidDecl()) {
MoveAssignOperator->setInvalidDecl();
return;
}
-
- MoveAssignOperator->markUsed(Context);
-
- SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
- DiagnosticErrorTrap Trap(Diags);
// C++0x [class.copy]p28:
// The implicitly-defined or move assignment operator for a non-union class
@@ -11680,6 +11781,16 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// from a virtual base more than once.
checkMoveAssignmentForRepeatedMove(*this, ClassDecl, CurrentLocation);
+ SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ MoveAssignOperator->getType()->castAs<FunctionProtoType>());
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
// The statements that form the synthesized function body.
SmallVector<Stmt*, 8> Statements;
@@ -11744,8 +11855,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/true,
/*Copying=*/false);
if (Move.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
MoveAssignOperator->setInvalidDecl();
return;
}
@@ -11771,8 +11880,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
@@ -11783,23 +11890,21 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
- Invalid = true;
+ Invalid = true;
continue;
}
// Suppress assigning zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
continue;
-
+
QualType FieldType = Field->getType().getNonReferenceType();
if (FieldType->isIncompleteArrayType()) {
- assert(ClassDecl->hasFlexibleArrayMember() &&
+ assert(ClassDecl->hasFlexibleArrayMember() &&
"Incomplete array type is not valid");
continue;
}
-
+
// Build references to the field in the object we're copying from and to.
LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
LookupMemberName);
@@ -11820,8 +11925,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/false,
/*Copying=*/false);
if (Move.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
MoveAssignOperator->setInvalidDecl();
return;
}
@@ -11838,22 +11941,10 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
Invalid = true;
- else {
+ else
Statements.push_back(Return.getAs<Stmt>());
-
- if (Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
- Invalid = true;
- }
- }
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- MoveAssignOperator->getType()->castAs<FunctionProtoType>());
-
if (Invalid) {
MoveAssignOperator->setInvalidDecl();
return;
@@ -11867,6 +11958,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
MoveAssignOperator->setBody(Body.getAs<Stmt>());
+ MoveAssignOperator->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveAssignOperator);
@@ -11942,8 +12034,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);
- if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
+ if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) {
+ ClassDecl->setImplicitCopyConstructorIsDeleted();
SetDeclDeleted(CopyConstructor, ClassLoc);
+ }
if (S)
PushOnScopeChains(CopyConstructor, S, false);
@@ -11953,30 +12047,37 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *CopyConstructor) {
+ CXXConstructorDecl *CopyConstructor) {
assert((CopyConstructor->isDefaulted() &&
CopyConstructor->isCopyConstructor() &&
!CopyConstructor->doesThisDeclarationHaveABody() &&
!CopyConstructor->isDeleted()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
+ if (CopyConstructor->willHaveBody() || CopyConstructor->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
+ SynthesizedFunctionScope Scope(*this, CopyConstructor);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ CopyConstructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
// C++11 [class.copy]p7:
// The [definition of an implicitly declared copy constructor] is
// deprecated if the class has a user-declared copy assignment operator
// or a user-declared destructor.
if (getLangOpts().CPlusPlus11 && CopyConstructor->isImplicit())
- diagnoseDeprecatedCopyOperation(*this, CopyConstructor, CurrentLocation);
-
- SynthesizedFunctionScope Scope(*this, CopyConstructor);
- DiagnosticErrorTrap Trap(Diags);
+ diagnoseDeprecatedCopyOperation(*this, CopyConstructor);
- if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+ if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false)) {
CopyConstructor->setInvalidDecl();
} else {
SourceLocation Loc = CopyConstructor->getLocEnd().isValid()
@@ -11985,16 +12086,9 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
Sema::CompoundScopeRAII CompoundScope(*this);
CopyConstructor->setBody(
ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
+ CopyConstructor->markUsed(Context);
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- CopyConstructor->getType()->castAs<FunctionProtoType>());
-
- CopyConstructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
-
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyConstructor);
}
@@ -12076,41 +12170,41 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
}
void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *MoveConstructor) {
+ CXXConstructorDecl *MoveConstructor) {
assert((MoveConstructor->isDefaulted() &&
MoveConstructor->isMoveConstructor() &&
!MoveConstructor->doesThisDeclarationHaveABody() &&
!MoveConstructor->isDeleted()) &&
"DefineImplicitMoveConstructor - call it for implicit move ctor");
+ if (MoveConstructor->willHaveBody() || MoveConstructor->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = MoveConstructor->getParent();
assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor");
SynthesizedFunctionScope Scope(*this, MoveConstructor);
- DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ MoveConstructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
+ if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false)) {
MoveConstructor->setInvalidDecl();
- } else {
+ } else {
SourceLocation Loc = MoveConstructor->getLocEnd().isValid()
? MoveConstructor->getLocEnd()
: MoveConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
MoveConstructor->setBody(ActOnCompoundStmt(
Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
+ MoveConstructor->markUsed(Context);
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- MoveConstructor->getType()->castAs<FunctionProtoType>());
-
- MoveConstructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
-
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveConstructor);
}
@@ -12123,28 +12217,31 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv) {
+ SynthesizedFunctionScope Scope(*this, Conv);
+
CXXRecordDecl *Lambda = Conv->getParent();
CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
// If we are defining a specialization of a conversion to function-ptr
// cache the deduced template arguments for this specialization
// so that we can use them to retrieve the corresponding call-operator
- // and static-invoker.
+ // and static-invoker.
const TemplateArgumentList *DeducedTemplateArgs = nullptr;
// Retrieve the corresponding call-operator specialization.
if (Lambda->isGenericLambda()) {
assert(Conv->isFunctionTemplateSpecialization());
- FunctionTemplateDecl *CallOpTemplate =
+ FunctionTemplateDecl *CallOpTemplate =
CallOp->getDescribedFunctionTemplate();
DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
void *InsertPos = nullptr;
FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
DeducedTemplateArgs->asArray(),
InsertPos);
- assert(CallOpSpec &&
+ assert(CallOpSpec &&
"Conversion operator must have a corresponding call operator");
CallOp = cast<CXXMethodDecl>(CallOpSpec);
}
+
// Mark the call operator referenced (and add to pending instantiations
// if necessary).
// For both the conversion and static-invoker template specializations
@@ -12152,22 +12249,19 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// to the PendingInstantiations.
MarkFunctionReferenced(CurrentLocation, CallOp);
- SynthesizedFunctionScope Scope(*this, Conv);
- DiagnosticErrorTrap Trap(Diags);
-
// Retrieve the static invoker...
CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
// ... and get the corresponding specialization for a generic lambda.
if (Lambda->isGenericLambda()) {
- assert(DeducedTemplateArgs &&
+ assert(DeducedTemplateArgs &&
"Must have deduced template arguments from Conversion Operator");
- FunctionTemplateDecl *InvokeTemplate =
+ FunctionTemplateDecl *InvokeTemplate =
Invoker->getDescribedFunctionTemplate();
void *InsertPos = nullptr;
FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
DeducedTemplateArgs->asArray(),
InsertPos);
- assert(InvokeSpec &&
+ assert(InvokeSpec &&
"Must have a corresponding static invoker specialization");
Invoker = cast<CXXMethodDecl>(InvokeSpec);
}
@@ -12182,36 +12276,33 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
Conv->markUsed(Context);
Conv->setReferenced();
-
+
// Fill in the __invoke function with a dummy implementation. IR generation
// will fill in the actual details.
Invoker->markUsed(Context);
Invoker->setReferenced();
Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
-
+
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
L->CompletedImplicitDefinition(Invoker);
- }
+ }
}
void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
+ CXXConversionDecl *Conv)
{
assert(!Conv->getParent()->isGenericLambda());
- Conv->markUsed(Context);
-
SynthesizedFunctionScope Scope(*this, Conv);
- DiagnosticErrorTrap Trap(Diags);
-
+
// Copy-initialize the lambda object as needed to capture it.
Expr *This = ActOnCXXThis(CurrentLocation).get();
Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).get();
-
+
ExprResult BuildBlock = BuildBlockForLambdaConversion(CurrentLocation,
Conv->getLocation(),
Conv, DerefThis);
@@ -12243,31 +12334,32 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
// Set the body of the conversion function.
Stmt *ReturnS = Return.get();
Conv->setBody(new (Context) CompoundStmt(Context, ReturnS,
- Conv->getLocation(),
+ Conv->getLocation(),
Conv->getLocation()));
-
+ Conv->markUsed(Context);
+
// We're done; notify the mutation listener, if any.
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
}
}
-/// \brief Determine whether the given list arguments contains exactly one
+/// \brief Determine whether the given list arguments contains exactly one
/// "real" (non-default) argument.
static bool hasOneRealArgument(MultiExprArg Args) {
switch (Args.size()) {
case 0:
return false;
-
+
default:
if (!Args[1]->isDefaultArgument())
return false;
-
+
// fall through
case 1:
return !Args[0]->isDefaultArgument();
}
-
+
return false;
}
@@ -12324,7 +12416,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
if (DiagnoseUseOfDecl(Constructor, ConstructLoc))
- return ExprError();
+ return ExprError();
}
return BuildCXXConstructExpr(
@@ -12401,7 +12493,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
assert(Pattern && "We must have set the Pattern!");
}
- if (InstantiateInClassInitializer(Loc, Field, Pattern,
+ if (!Pattern->hasInClassInitializer() ||
+ InstantiateInClassInitializer(Loc, Field, Pattern,
getTemplateInstantiationArgs(Field))) {
// Don't diagnose this again.
Field->setInvalidDecl();
@@ -12467,7 +12560,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
/// to form a proper call to this constructor.
///
/// \returns true if an error occurred, false otherwise.
-bool
+bool
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
@@ -12478,7 +12571,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
unsigned NumArgs = ArgsPtr.size();
Expr **Args = ArgsPtr.data();
- const FunctionProtoType *Proto
+ const FunctionProtoType *Proto
= Constructor->getType()->getAs<FunctionProtoType>();
assert(Proto && "Constructor without a prototype?");
unsigned NumParams = Proto->getNumParams();
@@ -12489,7 +12582,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
else
ConvertedArgs.reserve(NumArgs);
- VariadicCallType CallType =
+ VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
SmallVector<Expr *, 8> AllArgs;
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
@@ -12510,22 +12603,22 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
}
static inline bool
-CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
+CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
const FunctionDecl *FnDecl) {
const DeclContext *DC = FnDecl->getDeclContext()->getRedeclContext();
if (isa<NamespaceDecl>(DC)) {
- return SemaRef.Diag(FnDecl->getLocation(),
+ return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_declared_in_namespace)
<< FnDecl->getDeclName();
}
-
- if (isa<TranslationUnitDecl>(DC) &&
+
+ if (isa<TranslationUnitDecl>(DC) &&
FnDecl->getStorageClass() == SC_Static) {
return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_declared_static)
<< FnDecl->getDeclName();
}
-
+
return false;
}
@@ -12547,21 +12640,21 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
// Check that the result type is what we expect.
if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType)
return SemaRef.Diag(FnDecl->getLocation(),
- diag::err_operator_new_delete_invalid_result_type)
+ diag::err_operator_new_delete_invalid_result_type)
<< FnDecl->getDeclName() << ExpectedResultType;
-
+
// A function template must have at least 2 parameters.
if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2)
return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_template_too_few_parameters)
<< FnDecl->getDeclName();
-
+
// The function decl must have at least 1 parameter.
if (FnDecl->getNumParams() == 0)
return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_too_few_parameters)
<< FnDecl->getDeclName();
-
+
// Check the first parameter type is not dependent.
QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
if (FirstParamType->isDependentType())
@@ -12569,11 +12662,11 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
<< FnDecl->getDeclName() << ExpectedFirstParamType;
// Check that the first parameter type is what we expect.
- if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() !=
+ if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() !=
ExpectedFirstParamType)
return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)
<< FnDecl->getDeclName() << ExpectedFirstParamType;
-
+
return false;
}
@@ -12581,18 +12674,18 @@ static bool
CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
// C++ [basic.stc.dynamic.allocation]p1:
// A program is ill-formed if an allocation function is declared in a
- // namespace scope other than global scope or declared static in global
+ // namespace scope other than global scope or declared static in global
// scope.
if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
return true;
- CanQualType SizeTy =
+ CanQualType SizeTy =
SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType());
// C++ [basic.stc.dynamic.allocation]p1:
- // The return type shall be void*. The first parameter shall have type
+ // The return type shall be void*. The first parameter shall have type
// std::size_t.
- if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy,
+ if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy,
SizeTy,
diag::err_operator_new_dependent_param_type,
diag::err_operator_new_param_type))
@@ -12612,20 +12705,40 @@ static bool
CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
// C++ [basic.stc.dynamic.deallocation]p1:
// A program is ill-formed if deallocation functions are declared in a
- // namespace scope other than global scope or declared static in global
+ // namespace scope other than global scope or declared static in global
// scope.
if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
return true;
+ auto *MD = dyn_cast<CXXMethodDecl>(FnDecl);
+
+ // C++ P0722:
+ // Within a class C, the first parameter of a destroying operator delete
+ // shall be of type C *. The first parameter of any other deallocation
+ // function shall be of type void *.
+ CanQualType ExpectedFirstParamType =
+ MD && MD->isDestroyingOperatorDelete()
+ ? SemaRef.Context.getCanonicalType(SemaRef.Context.getPointerType(
+ SemaRef.Context.getRecordType(MD->getParent())))
+ : SemaRef.Context.VoidPtrTy;
+
// C++ [basic.stc.dynamic.deallocation]p2:
- // Each deallocation function shall return void and its first parameter
- // shall be void*.
- if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy,
- SemaRef.Context.VoidPtrTy,
- diag::err_operator_delete_dependent_param_type,
- diag::err_operator_delete_param_type))
+ // Each deallocation function shall return void
+ if (CheckOperatorNewDeleteTypes(
+ SemaRef, FnDecl, SemaRef.Context.VoidTy, ExpectedFirstParamType,
+ diag::err_operator_delete_dependent_param_type,
+ diag::err_operator_delete_param_type))
return true;
+ // C++ P0722:
+ // A destroying operator delete shall be a usual deallocation function.
+ if (MD && !MD->getParent()->isDependentContext() &&
+ MD->isDestroyingOperatorDelete() && !MD->isUsualDeallocationFunction()) {
+ SemaRef.Diag(MD->getLocation(),
+ diag::err_destroying_operator_delete_not_usual);
+ return true;
+ }
+
return false;
}
@@ -12646,7 +12759,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// explicitly stated in 3.7.3.
if (Op == OO_Delete || Op == OO_Array_Delete)
return CheckOperatorDeleteDeclaration(*this, FnDecl);
-
+
if (Op == OO_New || Op == OO_Array_New)
return CheckOperatorNewDeclaration(*this, FnDecl);
@@ -13049,7 +13162,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
IdentifierInfo *Name) {
bool Invalid = false;
QualType ExDeclType = TInfo->getType();
-
+
// Arrays and functions decay.
if (ExDeclType->isArrayType())
ExDeclType = Context.getArrayDecayedType(ExDeclType);
@@ -13113,7 +13226,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name,
ExDeclType, TInfo, SC_None);
ExDecl->setExceptionVariable(true);
-
+
// In ARC, infer 'retaining' for variables of retainable type.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(ExDecl))
Invalid = true;
@@ -13121,7 +13234,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
@@ -13153,13 +13267,13 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Expr *init = MaybeCreateExprWithCleanups(construct);
ExDecl->setInit(init);
}
-
+
// And make sure it's destructable.
FinalizeVarWithDestructor(ExDecl, recordType);
}
}
}
-
+
if (Invalid)
ExDecl->setInvalidDecl();
@@ -13175,7 +13289,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
UPPC_ExceptionType)) {
- TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
+ TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
D.getIdentifierLoc());
Invalid = true;
}
@@ -13183,7 +13297,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
IdentifierInfo *II = D.getIdentifier();
if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(),
LookupOrdinaryName,
- ForRedeclaration)) {
+ ForVisibleRedeclaration)) {
// The scope should be freshly made just for us. There is just no way
// it contains any previous declaration, except for function parameters in
// a function-try-block's catch statement.
@@ -13260,12 +13374,32 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
llvm::raw_svector_ostream Msg(MsgBuffer);
if (AssertMessage)
AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy());
- Diag(StaticAssertLoc, diag::err_static_assert_failed)
- << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+
+ Expr *InnerCond = nullptr;
+ std::string InnerCondDescription;
+ std::tie(InnerCond, InnerCondDescription) =
+ findFailedBooleanCondition(Converted.get(),
+ /*AllowTopLevelCond=*/false);
+ if (InnerCond) {
+ Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
+ << InnerCondDescription << !AssertMessage
+ << Msg.str() << InnerCond->getSourceRange();
+ } else {
+ Diag(StaticAssertLoc, diag::err_static_assert_failed)
+ << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+ }
Failed = true;
}
}
+ ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc,
+ /*DiscardedValue*/false,
+ /*IsConstexpr*/true);
+ if (FullAssertExpr.isInvalid())
+ Failed = true;
+ else
+ AssertExpr = FullAssertExpr.get();
+
Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
AssertExpr, AssertMessage, RParenLoc,
Failed);
@@ -13281,10 +13415,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
TypeSourceInfo *TSInfo) {
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
-
+
QualType T = TSInfo->getType();
SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange();
-
+
// C++03 [class.friend]p2:
// An elaborated-type-specifier shall be used in a friend declaration
// for a class.*
@@ -13328,7 +13462,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
<< T
<< TypeRange;
}
-
+
// C++11 [class.friend]p3:
// A friend declaration that does not declare a function shall have one
// of the following forms:
@@ -13409,7 +13543,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult(),
- /*IsTypeSpecifier=*/false);
+ /*IsTypeSpecifier=*/false,
+ /*IsTemplateParamOrArg=*/false);
}
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
@@ -13440,9 +13575,9 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
CurContext->addDecl(Friend);
return Friend;
}
-
+
assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?");
-
+
// Handle the case of a templated-scope friend class. e.g.
@@ -13522,7 +13657,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< DS.getSourceRange();
return nullptr;
}
-
+
// C++98 [class.friend]p1: A friend of a class is a function
// or class that is not a member of the class . . .
// This is fixed in DR77, which just barely didn't make the C++03
@@ -13542,7 +13677,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
DS.getFriendSpecLoc());
else
D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI);
-
+
if (!D)
return nullptr;
@@ -13611,7 +13746,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
DeclContext *DC;
Scope *DCScope = S;
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForRedeclaration);
+ ForExternalRedeclaration);
// There are five cases here.
// - There's no scope specifier and we're in a local class. Only look
@@ -13742,15 +13877,15 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_is_member :
diag::err_friend_is_member);
-
+
if (D.isFunctionDefinition()) {
// C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
+ // A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
// unqualified, and the function has namespace scope.
SemaDiagnosticBuilder DB
= Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
-
+
DB << SS.getScopeRep();
if (DC->isFileContext())
DB << FixItHint::CreateRemoval(SS.getRange());
@@ -13765,13 +13900,13 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
} else {
if (D.isFunctionDefinition()) {
// C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
+ // A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
// unqualified, and the function has namespace scope.
Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
<< SS.getScopeRep();
}
-
+
DC = CurContext;
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
}
@@ -13807,7 +13942,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
}
// FIXME: This is an egregious hack to cope with cases where the scope stack
- // does not contain the declaration context, i.e., in an out-of-line
+ // does not contain the declaration context, i.e., in an out-of-line
// definition of a class.
Scope FakeDCScope(S, Scope::DeclScope, Diags);
if (!DCScope) {
@@ -13893,6 +14028,9 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
return;
}
+ // Deleted function does not have a body.
+ Fn->setWillHaveBody(false);
+
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
// Don't consider the implicit declaration we generate for explicit
// specializations. FIXME: Do not generate these implicit declarations.
@@ -13971,6 +14109,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
MD->setDefaulted();
MD->setExplicitlyDefaulted();
+ // Unset that we will have a body for this function. We might not,
+ // if it turns out to be trivial, and we don't need this marking now
+ // that we've marked it as defaulted.
+ MD->setWillHaveBody(false);
+
// If this definition appears within the record, do the checking when
// the record is complete.
const FunctionDecl *Primary = MD;
@@ -14015,8 +14158,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- const FunctionType *NewFT = New->getType()->getAs<FunctionType>();
- const FunctionType *OldFT = Old->getType()->getAs<FunctionType>();
+ const auto *NewFT = New->getType()->getAs<FunctionProtoType>();
+ const auto *OldFT = Old->getType()->getAs<FunctionProtoType>();
+
+ if (OldFT->hasExtParameterInfos()) {
+ for (unsigned I = 0, E = OldFT->getNumParams(); I != E; ++I)
+ // A parameter of the overriding method should be annotated with noescape
+ // if the corresponding parameter of the overridden method is annotated.
+ if (OldFT->getExtParameterInfo(I).isNoEscape() &&
+ !NewFT->getExtParameterInfo(I).isNoEscape()) {
+ Diag(New->getParamDecl(I)->getLocation(),
+ diag::warn_overriding_method_missing_noescape);
+ Diag(Old->getParamDecl(I)->getLocation(),
+ diag::note_overridden_marked_noescape);
+ }
+ }
CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();
@@ -14174,21 +14330,22 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
Diag(D->getLocation(), diag::err_illegal_initializer);
}
-/// \brief Determine whether the given declaration is a static data member.
-static bool isStaticDataMember(const Decl *D) {
+/// \brief Determine whether the given declaration is a global variable or
+/// static data member.
+static bool isNonlocalVariable(const Decl *D) {
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
- return Var->isStaticDataMember();
+ return Var->hasGlobalStorage();
return false;
}
-/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse
-/// an initializer for the out-of-line declaration 'Dcl'. The scope
-/// is a fresh scope pushed for just this purpose.
+/// Invoked when we are about to parse an initializer for the declaration
+/// 'Dcl'.
///
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
/// static data member of class X, names should be looked up in the scope of
-/// class X.
+/// class X. If the declaration had a scope specifier, a scope will have
+/// been created and passed in for this purpose. Otherwise, S will be null.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
@@ -14198,27 +14355,27 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// might not be out of line if the specifier names the current namespace:
// extern int n;
// int ::n = 0;
- if (D->isOutOfLine())
+ if (S && D->isOutOfLine())
EnterDeclaratorContext(S, D->getDeclContext());
// If we are parsing the initializer for a static data member, push a
// new expression evaluation context that is associated with this static
// data member.
- if (isStaticDataMember(D))
- PushExpressionEvaluationContext(PotentiallyEvaluated, D);
+ if (isNonlocalVariable(D))
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated, D);
}
-/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
-/// initializer for the out-of-line declaration 'D'.
+/// Invoked after we are finished parsing an initializer for the declaration D.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
return;
- if (isStaticDataMember(D))
+ if (isNonlocalVariable(D))
PopExpressionEvaluationContext();
- if (D->isOutOfLine())
+ if (S && D->isOutOfLine())
ExitDeclaratorContext(S);
}
@@ -14249,7 +14406,7 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
void Sema::LoadExternalVTableUses() {
if (!ExternalSource)
return;
-
+
SmallVector<ExternalVTableUse, 4> VTables;
ExternalSource->ReadUsedVTables(VTables);
SmallVector<VTableUse, 4> NewUses;
@@ -14262,11 +14419,11 @@ void Sema::LoadExternalVTableUses() {
Pos->second = true;
continue;
}
-
+
VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired;
NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location));
}
-
+
VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end());
}
@@ -14473,17 +14630,17 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
FieldDecl *Field = ivars[i];
if (Field->isInvalidDecl())
continue;
-
+
CXXCtorInitializer *Member;
InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
- InitializationKind InitKind =
+ InitializationKind InitKind =
InitializationKind::CreateDefault(ObjCImplementation->getLocation());
InitializationSequence InitSeq(*this, InitEntity, InitKind, None);
ExprResult MemberInit =
InitSeq.Perform(*this, InitEntity, InitKind, None);
MemberInit = MaybeCreateExprWithCleanups(MemberInit);
- // Note, MemberInit could actually come back empty if no initialization
+ // Note, MemberInit could actually come back empty if no initialization
// is required (e.g., because it would call a trivial default constructor)
if (!MemberInit.get() || MemberInit.isInvalid())
continue;
@@ -14494,7 +14651,7 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
MemberInit.getAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
-
+
// Be sure that the destructor is accessible and is marked as referenced.
if (const RecordType *RecordTy =
Context.getBaseElementType(Field->getType())
@@ -14506,9 +14663,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
PDiag(diag::err_access_dtor_ivar)
<< Context.getBaseElementType(Field->getType()));
}
- }
+ }
}
- ObjCImplementation->setIvarInitializers(Context,
+ ObjCImplementation->setIvarInitializers(Context,
AllToInit.data(), AllToInit.size());
}
}
@@ -14576,7 +14733,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
DelegatingCycleHelper(Target, Valid, Invalid, Current, S);
}
}
-
+
void Sema::CheckDelegatingCtorCycles() {
llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current;
@@ -14597,10 +14754,10 @@ namespace {
/// \brief AST visitor that finds references to the 'this' expression.
class FindCXXThisExpr : public RecursiveASTVisitor<FindCXXThisExpr> {
Sema &S;
-
+
public:
explicit FindCXXThisExpr(Sema &S) : S(S) { }
-
+
bool VisitCXXThisExpr(CXXThisExpr *E) {
S.Diag(E->getLocation(), diag::err_this_static_member_func)
<< E->isImplicit();
@@ -14613,22 +14770,22 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
TypeSourceInfo *TSInfo = Method->getTypeSourceInfo();
if (!TSInfo)
return false;
-
+
TypeLoc TL = TSInfo->getTypeLoc();
FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
-
+
// C++11 [expr.prim.general]p3:
- // [The expression this] shall not appear before the optional
- // cv-qualifier-seq and it shall not appear within the declaration of a
+ // [The expression this] shall not appear before the optional
+ // cv-qualifier-seq and it shall not appear within the declaration of a
// static member function (although its type and value category are defined
// within a static member function as they are within a non-static member
// function). [ Note: this is because declaration matching does not occur
// until the complete declarator is known. - end note ]
const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
-
+
// If the return type came after the cv-qualifier-seq, check it now.
if (Proto->hasTrailingReturn() &&
!Finder.TraverseTypeLoc(ProtoTL.getReturnLoc()))
@@ -14637,7 +14794,7 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
// Check the exception specification.
if (checkThisInStaticMemberFunctionExceptionSpec(Method))
return true;
-
+
return checkThisInStaticMemberFunctionAttributes(Method);
}
@@ -14645,12 +14802,12 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
TypeSourceInfo *TSInfo = Method->getTypeSourceInfo();
if (!TSInfo)
return false;
-
+
TypeLoc TL = TSInfo->getTypeLoc();
FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
-
+
const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
@@ -14663,11 +14820,12 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
case EST_MSAny:
case EST_None:
break;
-
+
case EST_ComputedNoexcept:
if (!Finder.TraverseStmt(Proto->getNoexceptExpr()))
return true;
-
+ LLVM_FALLTHROUGH;
+
case EST_Dynamic:
for (const auto &E : Proto->exceptions()) {
if (!Finder.TraverseType(E))
@@ -14716,13 +14874,13 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
if (Arg && !Finder.TraverseStmt(Arg))
return true;
-
+
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
if (!Finder.TraverseStmt(Args[I]))
return true;
}
}
-
+
return false;
}
@@ -14773,10 +14931,16 @@ void Sema::checkExceptionSpecification(
return;
}
- if (!NoexceptExpr->isValueDependent())
- NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, nullptr,
- diag::err_noexcept_needs_constant_expression,
- /*AllowFold*/ false).get();
+ if (!NoexceptExpr->isValueDependent()) {
+ ExprResult Result = VerifyIntegerConstantExpression(
+ NoexceptExpr, nullptr, diag::err_noexcept_needs_constant_expression,
+ /*AllowFold*/ false);
+ if (Result.isInvalid()) {
+ ESI.Type = EST_BasicNoexcept;
+ return;
+ }
+ NoexceptExpr = Result.get();
+ }
ESI.NoexceptExpr = NoexceptExpr;
}
return;
@@ -14862,7 +15026,8 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = nullptr;
- LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
+ LookupResult Previous(*this, II, Loc, LookupMemberName,
+ ForVisibleRedeclaration);
LookupName(Previous, S);
switch (Previous.getResultKind()) {
case LookupResult::Found:
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index b43e5b9e32..abdcc4da62 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -157,34 +157,44 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
diag::note_related_result_type_overridden);
}
if (getLangOpts().ObjCAutoRefCount) {
- if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() !=
- Overridden->hasAttr<NSReturnsRetainedAttr>())) {
- Diag(NewMethod->getLocation(),
- diag::err_nsreturns_retained_attribute_mismatch) << 1;
- Diag(Overridden->getLocation(), diag::note_previous_decl)
- << "method";
+ Diags.setSeverity(diag::warn_nsreturns_retained_attribute_mismatch,
+ diag::Severity::Error, SourceLocation());
+ Diags.setSeverity(diag::warn_nsconsumed_attribute_mismatch,
+ diag::Severity::Error, SourceLocation());
+ }
+
+ if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() !=
+ Overridden->hasAttr<NSReturnsRetainedAttr>())) {
+ Diag(NewMethod->getLocation(),
+ diag::warn_nsreturns_retained_attribute_mismatch) << 1;
+ Diag(Overridden->getLocation(), diag::note_previous_decl) << "method";
+ }
+ if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() !=
+ Overridden->hasAttr<NSReturnsNotRetainedAttr>())) {
+ Diag(NewMethod->getLocation(),
+ diag::warn_nsreturns_retained_attribute_mismatch) << 0;
+ Diag(Overridden->getLocation(), diag::note_previous_decl) << "method";
+ }
+
+ ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(),
+ oe = Overridden->param_end();
+ for (ObjCMethodDecl::param_iterator ni = NewMethod->param_begin(),
+ ne = NewMethod->param_end();
+ ni != ne && oi != oe; ++ni, ++oi) {
+ const ParmVarDecl *oldDecl = (*oi);
+ ParmVarDecl *newDecl = (*ni);
+ if (newDecl->hasAttr<NSConsumedAttr>() !=
+ oldDecl->hasAttr<NSConsumedAttr>()) {
+ Diag(newDecl->getLocation(), diag::warn_nsconsumed_attribute_mismatch);
+ Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter";
}
- if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() !=
- Overridden->hasAttr<NSReturnsNotRetainedAttr>())) {
- Diag(NewMethod->getLocation(),
- diag::err_nsreturns_retained_attribute_mismatch) << 0;
- Diag(Overridden->getLocation(), diag::note_previous_decl)
- << "method";
- }
- ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(),
- oe = Overridden->param_end();
- for (ObjCMethodDecl::param_iterator
- ni = NewMethod->param_begin(), ne = NewMethod->param_end();
- ni != ne && oi != oe; ++ni, ++oi) {
- const ParmVarDecl *oldDecl = (*oi);
- ParmVarDecl *newDecl = (*ni);
- if (newDecl->hasAttr<NSConsumedAttr>() !=
- oldDecl->hasAttr<NSConsumedAttr>()) {
- Diag(newDecl->getLocation(),
- diag::err_nsconsumed_attribute_mismatch);
- Diag(oldDecl->getLocation(), diag::note_previous_decl)
- << "parameter";
- }
+
+ // A parameter of the overriding method should be annotated with noescape
+ // if the corresponding parameter of the overridden method is annotated.
+ if (oldDecl->hasAttr<NoEscapeAttr>() && !newDecl->hasAttr<NoEscapeAttr>()) {
+ Diag(newDecl->getLocation(),
+ diag::warn_overriding_method_missing_noescape);
+ Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape);
}
}
}
@@ -248,18 +258,41 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
return false;
}
-static void DiagnoseObjCImplementedDeprecations(Sema &S,
- NamedDecl *ND,
- SourceLocation ImplLoc,
- int select) {
- if (ND && ND->isDeprecated()) {
- S.Diag(ImplLoc, diag::warn_deprecated_def) << select;
- if (select == 0)
+static void DiagnoseObjCImplementedDeprecations(Sema &S, const NamedDecl *ND,
+ SourceLocation ImplLoc) {
+ if (!ND)
+ return;
+ bool IsCategory = false;
+ AvailabilityResult Availability = ND->getAvailability();
+ if (Availability != AR_Deprecated) {
+ if (isa<ObjCMethodDecl>(ND)) {
+ if (Availability != AR_Unavailable)
+ return;
+ // Warn about implementing unavailable methods.
+ S.Diag(ImplLoc, diag::warn_unavailable_def);
S.Diag(ND->getLocation(), diag::note_method_declared_at)
- << ND->getDeclName();
- else
- S.Diag(ND->getLocation(), diag::note_previous_decl) << "class";
+ << ND->getDeclName();
+ return;
+ }
+ if (const auto *CD = dyn_cast<ObjCCategoryDecl>(ND)) {
+ if (!CD->getClassInterface()->isDeprecated())
+ return;
+ ND = CD->getClassInterface();
+ IsCategory = true;
+ } else
+ return;
}
+ S.Diag(ImplLoc, diag::warn_deprecated_def)
+ << (isa<ObjCMethodDecl>(ND)
+ ? /*Method*/ 0
+ : isa<ObjCCategoryDecl>(ND) || IsCategory ? /*Category*/ 2
+ : /*Class*/ 1);
+ if (isa<ObjCMethodDecl>(ND))
+ S.Diag(ND->getLocation(), diag::note_method_declared_at)
+ << ND->getDeclName();
+ else
+ S.Diag(ND->getLocation(), diag::note_previous_decl)
+ << (isa<ObjCCategoryDecl>(ND) ? "category" : "class");
}
/// AddAnyMethodToGlobalPool - Add any method, instance or factory to global
@@ -384,9 +417,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// No need to issue deprecated warning if deprecated mehod in class/category
// is being implemented in its own implementation (no overriding is involved).
if (!ImplDeclOfMethodDecl || ImplDeclOfMethodDecl != ImplDeclOfMethodDef)
- DiagnoseObjCImplementedDeprecations(*this,
- dyn_cast<NamedDecl>(IMD),
- MDecl->getLocation(), 0);
+ DiagnoseObjCImplementedDeprecations(*this, IMD, MDecl->getLocation());
}
if (MDecl->getMethodFamily() == OMF_init) {
@@ -457,7 +488,10 @@ static void diagnoseUseOfProtocols(Sema &TheSema,
// Diagnose availability in the context of the ObjC container.
Sema::ContextRAII SavedContext(TheSema, CD);
for (unsigned i = 0; i < NumProtoRefs; ++i) {
- (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i]);
+ (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i],
+ /*UnknownObjCClass=*/nullptr,
+ /*ObjCPropertyAccess=*/false,
+ /*AvoidPartialAvailabilityChecks=*/true);
}
}
@@ -909,8 +943,9 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc,
assert(ClassName && "Missing class identifier");
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc,
- LookupOrdinaryName, ForRedeclaration);
+ NamedDecl *PrevDecl =
+ LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
+ forRedeclarationInCurContext());
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
@@ -992,6 +1027,7 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc,
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+ AddPragmaAttributes(TUScope, IDecl);
PushOnScopeChains(IDecl, TUScope);
// Start the definition of this class. If we're in a redefinition case, there
@@ -1060,16 +1096,18 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLocation) {
// Look for previous declaration of alias name
- NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation,
- LookupOrdinaryName, ForRedeclaration);
+ NamedDecl *ADecl =
+ LookupSingleName(TUScope, AliasName, AliasLocation, LookupOrdinaryName,
+ forRedeclarationInCurContext());
if (ADecl) {
Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName;
Diag(ADecl->getLocation(), diag::note_previous_declaration);
return nullptr;
}
// Check for class declaration
- NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
- LookupOrdinaryName, ForRedeclaration);
+ NamedDecl *CDeclU =
+ LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName,
+ forRedeclarationInCurContext());
if (const TypedefNameDecl *TDecl =
dyn_cast_or_null<TypedefNameDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
@@ -1077,7 +1115,8 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
ClassName = IDecl->getIdentifier();
CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName,
+ forRedeclarationInCurContext());
}
}
}
@@ -1139,7 +1178,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc,
- ForRedeclaration);
+ forRedeclarationInCurContext());
ObjCProtocolDecl *PDecl = nullptr;
if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) {
// If we already have a definition, complain.
@@ -1175,7 +1214,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
-
+ AddPragmaAttributes(TUScope, PDecl);
+
// Merge attributes from previous declarations.
if (PrevDecl)
mergeDeclAttributes(PDecl, PrevDecl);
@@ -1694,7 +1734,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
for (const IdentifierLocPair &IdentPair : IdentList) {
IdentifierInfo *Ident = IdentPair.first;
ObjCProtocolDecl *PrevDecl = LookupProtocol(Ident, IdentPair.second,
- ForRedeclaration);
+ forRedeclarationInCurContext());
ObjCProtocolDecl *PDecl
= ObjCProtocolDecl::Create(Context, CurContext, Ident,
IdentPair.second, AtProtocolLoc,
@@ -1705,7 +1745,8 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
-
+ AddPragmaAttributes(TUScope, PDecl);
+
if (PrevDecl)
mergeDeclAttributes(PDecl, PrevDecl);
@@ -1724,7 +1765,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 +1843,10 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
NumProtoRefs, Context);
}
+ if (AttrList)
+ ProcessDeclAttributeList(TUScope, CDecl, AttrList);
+ AddPragmaAttributes(TUScope, CDecl);
+
CheckObjCDeclScope(CDecl);
return ActOnObjCContainerStartDefinition(CDecl);
}
@@ -1842,10 +1888,6 @@ Decl *Sema::ActOnStartCategoryImplementation(
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
- // If the interface is deprecated/unavailable, warn/error about it.
- if (IDecl)
- DiagnoseUseOfDecl(IDecl, ClassLoc);
-
// If the interface has the objc_runtime_visible attribute, we
// cannot implement a category for it.
if (IDecl && IDecl->hasAttr<ObjCRuntimeVisibleAttr>()) {
@@ -1865,9 +1907,8 @@ Decl *Sema::ActOnStartCategoryImplementation(
CatIDecl->setImplementation(CDecl);
// Warn on implementating category of deprecated class under
// -Wdeprecated-implementations flag.
- DiagnoseObjCImplementedDeprecations(*this,
- dyn_cast<NamedDecl>(IDecl),
- CDecl->getLocation(), 2);
+ DiagnoseObjCImplementedDeprecations(*this, CatIDecl,
+ CDecl->getLocation());
}
}
@@ -1884,7 +1925,7 @@ Decl *Sema::ActOnStartClassImplementation(
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
= LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
@@ -1948,6 +1989,7 @@ Decl *Sema::ActOnStartClassImplementation(
ClassName, /*typeParamList=*/nullptr,
/*PrevDecl=*/nullptr, ClassLoc,
true);
+ AddPragmaAttributes(TUScope, IDecl);
IDecl->startDefinition();
if (SDecl) {
IDecl->setSuperClass(Context.getTrivialTypeSourceInfo(
@@ -1986,9 +2028,7 @@ Decl *Sema::ActOnStartClassImplementation(
PushOnScopeChains(IMPDecl, TUScope);
// Warn on implementating deprecated class under
// -Wdeprecated-implementations flag.
- DiagnoseObjCImplementedDeprecations(*this,
- dyn_cast<NamedDecl>(IDecl),
- IMPDecl->getLocation(), 1);
+ DiagnoseObjCImplementedDeprecations(*this, IDecl, IMPDecl->getLocation());
}
// If the superclass has the objc_runtime_visible attribute, we
@@ -2961,7 +3001,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
= LookupSingleName(TUScope, IdentList[i], IdentLocs[i],
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName, forRedeclarationInCurContext());
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
// GCC apparently allows the following idiom:
//
@@ -3037,7 +3077,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
ClassName, TypeParams, PrevIDecl,
IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
-
+
PushOnScopeChains(IDecl, TUScope);
CheckObjCDeclScope(IDecl);
DeclsInGroup.push_back(IDecl);
@@ -3681,6 +3721,26 @@ static void DiagnoseWeakIvars(Sema &S, ObjCImplementationDecl *ID) {
}
}
+/// Diagnose attempts to use flexible array member with retainable object type.
+static void DiagnoseRetainableFlexibleArrayMember(Sema &S,
+ ObjCInterfaceDecl *ID) {
+ if (!S.getLangOpts().ObjCAutoRefCount)
+ return;
+
+ for (auto ivar = ID->all_declared_ivar_begin(); ivar;
+ ivar = ivar->getNextIvar()) {
+ if (ivar->isInvalidDecl())
+ continue;
+ QualType IvarTy = ivar->getType();
+ if (IvarTy->isIncompleteArrayType() &&
+ (IvarTy.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) &&
+ IvarTy->isObjCLifetimeType()) {
+ S.Diag(ivar->getLocation(), diag::err_flexible_array_arc_retainable);
+ ivar->setInvalidDecl();
+ }
+ }
+}
+
Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
switch (CurContext->getDeclKind()) {
case Decl::ObjCInterface:
@@ -3701,6 +3761,96 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
}
}
+static bool IsVariableSizedType(QualType T) {
+ if (T->isIncompleteArrayType())
+ return true;
+ const auto *RecordTy = T->getAs<RecordType>();
+ return (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember());
+}
+
+static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) {
+ ObjCInterfaceDecl *IntfDecl = nullptr;
+ ObjCInterfaceDecl::ivar_range Ivars = llvm::make_range(
+ ObjCInterfaceDecl::ivar_iterator(), ObjCInterfaceDecl::ivar_iterator());
+ if ((IntfDecl = dyn_cast<ObjCInterfaceDecl>(OCD))) {
+ Ivars = IntfDecl->ivars();
+ } else if (auto *ImplDecl = dyn_cast<ObjCImplementationDecl>(OCD)) {
+ IntfDecl = ImplDecl->getClassInterface();
+ Ivars = ImplDecl->ivars();
+ } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(OCD)) {
+ if (CategoryDecl->IsClassExtension()) {
+ IntfDecl = CategoryDecl->getClassInterface();
+ Ivars = CategoryDecl->ivars();
+ }
+ }
+
+ // Check if variable sized ivar is in interface and visible to subclasses.
+ if (!isa<ObjCInterfaceDecl>(OCD)) {
+ for (auto ivar : Ivars) {
+ if (!ivar->isInvalidDecl() && IsVariableSizedType(ivar->getType())) {
+ S.Diag(ivar->getLocation(), diag::warn_variable_sized_ivar_visibility)
+ << ivar->getDeclName() << ivar->getType();
+ }
+ }
+ }
+
+ // Subsequent checks require interface decl.
+ if (!IntfDecl)
+ return;
+
+ // Check if variable sized ivar is followed by another ivar.
+ for (ObjCIvarDecl *ivar = IntfDecl->all_declared_ivar_begin(); ivar;
+ ivar = ivar->getNextIvar()) {
+ if (ivar->isInvalidDecl() || !ivar->getNextIvar())
+ continue;
+ QualType IvarTy = ivar->getType();
+ bool IsInvalidIvar = false;
+ if (IvarTy->isIncompleteArrayType()) {
+ S.Diag(ivar->getLocation(), diag::err_flexible_array_not_at_end)
+ << ivar->getDeclName() << IvarTy
+ << TTK_Class; // Use "class" for Obj-C.
+ IsInvalidIvar = true;
+ } else if (const RecordType *RecordTy = IvarTy->getAs<RecordType>()) {
+ if (RecordTy->getDecl()->hasFlexibleArrayMember()) {
+ S.Diag(ivar->getLocation(),
+ diag::err_objc_variable_sized_type_not_at_end)
+ << ivar->getDeclName() << IvarTy;
+ IsInvalidIvar = true;
+ }
+ }
+ if (IsInvalidIvar) {
+ S.Diag(ivar->getNextIvar()->getLocation(),
+ diag::note_next_ivar_declaration)
+ << ivar->getNextIvar()->getSynthesize();
+ ivar->setInvalidDecl();
+ }
+ }
+
+ // Check if ObjC container adds ivars after variable sized ivar in superclass.
+ // Perform the check only if OCD is the first container to declare ivars to
+ // avoid multiple warnings for the same ivar.
+ ObjCIvarDecl *FirstIvar =
+ (Ivars.begin() == Ivars.end()) ? nullptr : *Ivars.begin();
+ if (FirstIvar && (FirstIvar == IntfDecl->all_declared_ivar_begin())) {
+ const ObjCInterfaceDecl *SuperClass = IntfDecl->getSuperClass();
+ while (SuperClass && SuperClass->ivar_empty())
+ SuperClass = SuperClass->getSuperClass();
+ if (SuperClass) {
+ auto IvarIter = SuperClass->ivar_begin();
+ std::advance(IvarIter, SuperClass->ivar_size() - 1);
+ const ObjCIvarDecl *LastIvar = *IvarIter;
+ if (IsVariableSizedType(LastIvar->getType())) {
+ S.Diag(FirstIvar->getLocation(),
+ diag::warn_superclass_variable_sized_type_not_at_end)
+ << FirstIvar->getDeclName() << LastIvar->getDeclName()
+ << LastIvar->getType() << SuperClass->getDeclName();
+ S.Diag(LastIvar->getLocation(), diag::note_entity_declared_at)
+ << LastIvar->getDeclName();
+ }
+ }
+ }
+}
+
// Note: For class/category implementations, allMethods is always null.
Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
ArrayRef<DeclGroupPtrTy> allTUVars) {
@@ -3832,6 +3982,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
if (IDecl->hasDesignatedInitializers())
DiagnoseMissingDesignatedInitOverrides(IC, IDecl);
DiagnoseWeakIvars(*this, IC);
+ DiagnoseRetainableFlexibleArrayMember(*this, IDecl);
bool HasRootClassAttr = IDecl->hasAttr<ObjCRootClassAttr>();
if (IDecl->getSuperClass() == nullptr) {
@@ -3901,6 +4052,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
}
}
}
+ DiagnoseVariableSizedIvars(*this, OCD);
if (isInterfaceDeclKind) {
// Reject invalid vardecls.
for (unsigned i = 0, e = allTUVars.size(); i != e; i++) {
@@ -4183,6 +4335,10 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
// Then merge the declarations.
mergeObjCMethodDecls(ObjCMethod, overridden);
+ }
+
+ for (ObjCMethodDecl *overridden : overrides) {
+ CheckObjCMethodOverride(ObjCMethod, overridden);
if (ObjCMethod->isImplicit() && overridden->isImplicit())
continue; // Conflicting properties are detected elsewhere.
@@ -4302,6 +4458,49 @@ static void mergeInterfaceMethodToImpl(Sema &S,
}
}
+/// Verify that the method parameters/return value have types that are supported
+/// by the x86 target.
+static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
+ const ObjCMethodDecl *Method) {
+ assert(SemaRef.getASTContext().getTargetInfo().getTriple().getArch() ==
+ llvm::Triple::x86 &&
+ "x86-specific check invoked for a different target");
+ SourceLocation Loc;
+ QualType T;
+ for (const ParmVarDecl *P : Method->parameters()) {
+ if (P->getType()->isVectorType()) {
+ Loc = P->getLocStart();
+ T = P->getType();
+ break;
+ }
+ }
+ if (Loc.isInvalid()) {
+ if (Method->getReturnType()->isVectorType()) {
+ Loc = Method->getReturnTypeSourceRange().getBegin();
+ T = Method->getReturnType();
+ } else
+ return;
+ }
+
+ // Vector parameters/return values are not supported by objc_msgSend on x86 in
+ // iOS < 9 and macOS < 10.11.
+ const auto &Triple = SemaRef.getASTContext().getTargetInfo().getTriple();
+ VersionTuple AcceptedInVersion;
+ if (Triple.getOS() == llvm::Triple::IOS)
+ AcceptedInVersion = VersionTuple(/*Major=*/9);
+ else if (Triple.isMacOSX())
+ AcceptedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/11);
+ else
+ return;
+ if (SemaRef.getASTContext().getTargetInfo().getPlatformMinVersion() >=
+ AcceptedInVersion)
+ return;
+ SemaRef.Diag(Loc, diag::err_objc_method_unsupported_param_ret_type)
+ << T << (Method->getReturnType()->isVectorType() ? /*return value*/ 1
+ : /*parameter*/ 0)
+ << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9");
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc,
@@ -4364,7 +4563,7 @@ Decl *Sema::ActOnMethodDeclaration(
}
LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc,
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName, forRedeclarationInCurContext());
LookupName(R, S);
if (R.isSingleResult()) {
NamedDecl *PrevDecl = R.getFoundDecl();
@@ -4393,6 +4592,7 @@ Decl *Sema::ActOnMethodDeclaration(
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
+ AddPragmaAttributes(TUScope, Param);
if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
@@ -4423,6 +4623,7 @@ Decl *Sema::ActOnMethodDeclaration(
if (AttrList)
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
+ AddPragmaAttributes(TUScope, ObjCMethod);
// Add the method now.
const ObjCMethodDecl *PrevMethod = nullptr;
@@ -4521,6 +4722,10 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethod->SetRelatedResultType();
}
+ if (MethodDefinition &&
+ Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+ checkObjCMethodX86VectorTypes(*this, ObjCMethod);
+
ActOnDocumentableDecl(ObjCMethod);
return ObjCMethod;
@@ -4595,7 +4800,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
- if (T.getAddressSpace() != 0) {
+ if (T.getAddressSpace() != LangAS::Default) {
Diag(IdLoc, diag::err_arg_with_address_space);
Invalid = true;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c5b2e1b3a2..d80237d248 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -79,7 +79,8 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
if (const auto *A = D->getAttr<UnusedAttr>()) {
// [[maybe_unused]] should not diagnose uses, but __attribute__((unused))
// should diagnose them.
- if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused) {
+ if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused &&
+ A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) {
const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext());
if (DC && !DC->hasAttr<UnusedAttr>())
S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
@@ -87,109 +88,6 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
}
}
-static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) {
- const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
- if (!OMD)
- return false;
- const ObjCInterfaceDecl *OID = OMD->getClassInterface();
- if (!OID)
- return false;
-
- for (const ObjCCategoryDecl *Cat : OID->visible_categories())
- if (ObjCMethodDecl *CatMeth =
- Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod()))
- if (!CatMeth->hasAttr<AvailabilityAttr>())
- return true;
- return false;
-}
-
-AvailabilityResult
-Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
- AvailabilityResult Result = D->getAvailability(Message);
-
- // For typedefs, if the typedef declaration appears available look
- // to the underlying type to see if it is more restrictive.
- while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (Result == AR_Available) {
- if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
- D = TT->getDecl();
- Result = D->getAvailability(Message);
- continue;
- }
- }
- break;
- }
-
- // Forward class declarations get their attributes from their definition.
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
- if (IDecl->getDefinition()) {
- D = IDecl->getDefinition();
- Result = D->getAvailability(Message);
- }
- }
-
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
- if (Result == AR_Available) {
- const DeclContext *DC = ECD->getDeclContext();
- if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
- Result = TheEnumDecl->getAvailability(Message);
- }
-
- if (Result == AR_NotYetIntroduced) {
- // Don't do this for enums, they can't be redeclared.
- if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
- return AR_Available;
-
- bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited();
- // Objective-C method declarations in categories are not modelled as
- // redeclarations, so manually look for a redeclaration in a category
- // if necessary.
- if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D))
- Warn = false;
- // In general, D will point to the most recent redeclaration. However,
- // for `@class A;` decls, this isn't true -- manually go through the
- // redecl chain in that case.
- if (Warn && isa<ObjCInterfaceDecl>(D))
- for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn;
- Redecl = Redecl->getPreviousDecl())
- if (!Redecl->hasAttr<AvailabilityAttr>() ||
- Redecl->getAttr<AvailabilityAttr>()->isInherited())
- Warn = false;
-
- return Warn ? AR_NotYetIntroduced : AR_Available;
- }
-
- return Result;
-}
-
-static void
-DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- bool ObjCPropertyAccess) {
- std::string Message;
- // See if this declaration is unavailable, deprecated, or partial.
- if (AvailabilityResult Result =
- S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) {
-
- if (Result == AR_NotYetIntroduced && S.getCurFunctionOrMethodDecl()) {
- S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
- return;
- }
-
- const ObjCPropertyDecl *ObjCPDecl = nullptr;
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
- AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
- if (PDeclResult == Result)
- ObjCPDecl = PD;
- }
- }
-
- S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass,
- ObjCPDecl, ObjCPropertyAccess);
- }
-}
-
/// \brief Emit a note explaining that this function is deleted.
void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
assert(Decl->isDeleted());
@@ -305,7 +203,8 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
///
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
- bool ObjCPropertyAccess) {
+ bool ObjCPropertyAccess,
+ bool AvoidPartialAvailabilityChecks) {
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
@@ -361,8 +260,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
return true;
+ }
- if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc))
+ auto getReferencedObjCProp = [](const NamedDecl *D) ->
+ const ObjCPropertyDecl * {
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->findPropertyDecl();
+ return nullptr;
+ };
+ if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) {
+ if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc))
+ return true;
+ } else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) {
return true;
}
@@ -379,8 +288,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return true;
}
- DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
- ObjCPropertyAccess);
+ DiagnoseAvailabilityOfDecl(D, Loc, UnknownObjCClass, ObjCPropertyAccess,
+ AvoidPartialAvailabilityChecks);
DiagnoseUnusedOfDecl(*this, D, Loc);
@@ -517,14 +426,6 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
if (Ty->isFunctionType()) {
- // If we are here, we are not calling a function but taking
- // its address (which is not allowed in OpenCL v1.0 s6.8.a.3).
- if (getLangOpts().OpenCL) {
- if (Diagnose)
- Diag(E->getExprLoc(), diag::err_opencl_taking_function_address);
- return ExprError();
- }
-
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()))
if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc()))
@@ -704,8 +605,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,
@@ -815,8 +715,10 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
return ExprError();
E = Res.get();
- // If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to
- // double.
+ // If this is a 'float' or '__fp16' (CVR qualified or typedef)
+ // promote to double.
+ // Note that default argument promotion applies only to float (and
+ // half/fp16); it does not apply to _Float16.
const BuiltinType *BTy = Ty->getAs<BuiltinType>();
if (BTy && (BTy->getKind() == BuiltinType::Half ||
BTy->getKind() == BuiltinType::Float)) {
@@ -1088,7 +990,7 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
return ResultType;
}
-/// \brief Hande arithmetic conversion from integer to float. Helper function
+/// \brief Handle arithmetic conversion from integer to float. Helper function
/// of UsualArithmeticConversions()
static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
ExprResult &IntExpr,
@@ -1432,7 +1334,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();
@@ -1594,8 +1497,9 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
- /*AllowRaw*/false, /*AllowTemplate*/false,
- /*AllowStringTemplate*/false) == Sema::LOLR_Error)
+ /*AllowRaw*/ false, /*AllowTemplate*/ false,
+ /*AllowStringTemplate*/ false,
+ /*DiagnoseMissing*/ true) == Sema::LOLR_Error)
return ExprError();
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
@@ -1686,8 +1590,9 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
switch (LookupLiteralOperator(UDLScope, R, ArgTy,
- /*AllowRaw*/false, /*AllowTemplate*/false,
- /*AllowStringTemplate*/true)) {
+ /*AllowRaw*/ false, /*AllowTemplate*/ false,
+ /*AllowStringTemplate*/ true,
+ /*DiagnoseMissing*/ true)) {
case LOLR_Cooked: {
llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars());
@@ -1720,6 +1625,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
}
case LOLR_Raw:
case LOLR_Template:
+ case LOLR_ErrorNoDiagnostic:
llvm_unreachable("unexpected literal operator lookup result");
case LOLR_Error:
return ExprError();
@@ -1772,7 +1678,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())
@@ -2126,6 +2035,12 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
IdentifierInfo *II = Name.getAsIdentifierInfo();
SourceLocation NameLoc = NameInfo.getLoc();
+ if (II && II->isEditorPlaceholder()) {
+ // FIXME: When typed placeholders are supported we can create a typed
+ // placeholder expression node.
+ return ExprError();
+ }
+
// C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
// -- an identifier that was declared with a dependent type,
@@ -2509,11 +2424,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->");
@@ -2889,6 +2804,8 @@ ExprResult Sema::BuildDeclarationNameExpr(
{
QualType type = VD->getType();
+ if (type.isNull())
+ return ExprError();
if (auto *FPT = type->getAs<FunctionProtoType>()) {
// C++ [except.spec]p17:
// An exception-specification is considered to be needed when:
@@ -3333,11 +3250,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// literal or a cooked one.
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
switch (LookupLiteralOperator(UDLScope, R, CookedTy,
- /*AllowRaw*/true, /*AllowTemplate*/true,
- /*AllowStringTemplate*/false)) {
+ /*AllowRaw*/ true, /*AllowTemplate*/ true,
+ /*AllowStringTemplate*/ false,
+ /*DiagnoseMissing*/ !Literal.isImaginary)) {
+ case LOLR_ErrorNoDiagnostic:
+ // Lookup failure for imaginary constants isn't fatal, there's still the
+ // GNU extension producing _Complex types.
+ break;
case LOLR_Error:
return ExprError();
-
case LOLR_Cooked: {
Expr *Lit;
if (Literal.isFloatingLiteral()) {
@@ -3405,6 +3326,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Ty = Context.FloatTy;
else if (Literal.isLong)
Ty = Context.LongDoubleTy;
+ else if (Literal.isFloat16)
+ Ty = Context.Float16Ty;
else if (Literal.isFloat128)
Ty = Context.Float128Ty;
else
@@ -3553,10 +3476,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
// If this is an imaginary literal, create the ImaginaryLiteral wrapper.
- if (Literal.isImaginary)
+ if (Literal.isImaginary) {
Res = new (Context) ImaginaryLiteral(Res,
Context.getComplexType(Res->getType()));
+ Diag(Tok.getLocation(), diag::ext_imaginary_constant);
+ }
return Res;
}
@@ -4556,10 +4481,26 @@ 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.
+ //
+ // FIXME: Pass in a correct Pattern argument, otherwise
+ // getTemplateInstantiationArgs uses the lexical context of FD, e.g.
+ //
+ // template<typename T>
+ // struct A {
+ // static int FooImpl();
+ //
+ // template<typename Tp>
+ // // bug: default argument A<T>::FooImpl() is evaluated with 2-level
+ // // template argument list [[T], [Tp]], should be [[Tp]].
+ // friend A<Tp> Foo(int a);
+ // };
+ //
+ // template<typename T>
+ // A<T> Foo(int a = A<T>::FooImpl());
MultiLevelTemplateArgumentList MutiLevelArgList
= getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
@@ -5124,7 +5065,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
}
NeedsNewDecl = true;
- unsigned AS = ArgType->getPointeeType().getQualifiers().getAddressSpace();
+ LangAS AS = ArgType->getPointeeType().getAddressSpace();
QualType PointeeType = ParamType->getPointeeType();
PointeeType = Context.getAddrSpaceQualType(PointeeType, AS);
@@ -5187,6 +5128,87 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn,
}
}
+static bool enclosingClassIsRelatedToClassInWhichMembersWereFound(
+ const UnresolvedMemberExpr *const UME, Sema &S) {
+
+ const auto GetFunctionLevelDCIfCXXClass =
+ [](Sema &S) -> const CXXRecordDecl * {
+ const DeclContext *const DC = S.getFunctionLevelDeclContext();
+ if (!DC || !DC->getParent())
+ return nullptr;
+
+ // If the call to some member function was made from within a member
+ // function body 'M' return return 'M's parent.
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(DC))
+ return MD->getParent()->getCanonicalDecl();
+ // else the call was made from within a default member initializer of a
+ // class, so return the class.
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ return RD->getCanonicalDecl();
+ return nullptr;
+ };
+ // If our DeclContext is neither a member function nor a class (in the
+ // case of a lambda in a default member initializer), we can't have an
+ // enclosing 'this'.
+
+ const CXXRecordDecl *const CurParentClass = GetFunctionLevelDCIfCXXClass(S);
+ if (!CurParentClass)
+ return false;
+
+ // The naming class for implicit member functions call is the class in which
+ // name lookup starts.
+ const CXXRecordDecl *const NamingClass =
+ UME->getNamingClass()->getCanonicalDecl();
+ assert(NamingClass && "Must have naming class even for implicit access");
+
+ // If the unresolved member functions were found in a 'naming class' that is
+ // related (either the same or derived from) to the class that contains the
+ // member function that itself contained the implicit member access.
+
+ return CurParentClass == NamingClass ||
+ CurParentClass->isDerivedFrom(NamingClass);
+}
+
+static void
+tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs(
+ Sema &S, const UnresolvedMemberExpr *const UME, SourceLocation CallLoc) {
+
+ if (!UME)
+ return;
+
+ LambdaScopeInfo *const CurLSI = S.getCurLambda();
+ // Only try and implicitly capture 'this' within a C++ Lambda if it hasn't
+ // already been captured, or if this is an implicit member function call (if
+ // it isn't, an attempt to capture 'this' should already have been made).
+ if (!CurLSI || CurLSI->ImpCaptureStyle == CurLSI->ImpCap_None ||
+ !UME->isImplicitAccess() || CurLSI->isCXXThisCaptured())
+ return;
+
+ // Check if the naming class in which the unresolved members were found is
+ // related (same as or is a base of) to the enclosing class.
+
+ if (!enclosingClassIsRelatedToClassInWhichMembersWereFound(UME, S))
+ return;
+
+
+ DeclContext *EnclosingFunctionCtx = S.CurContext->getParent()->getParent();
+ // If the enclosing function is not dependent, then this lambda is
+ // capture ready, so if we can capture this, do so.
+ if (!EnclosingFunctionCtx->isDependentContext()) {
+ // If the current lambda and all enclosing lambdas can capture 'this' -
+ // then go ahead and capture 'this' (since our unresolved overload set
+ // contains at least one non-static member function).
+ if (!S.CheckCXXThisCapture(CallLoc, /*Explcit*/ false, /*Diagnose*/ false))
+ S.CheckCXXThisCapture(CallLoc);
+ } else if (S.CurContext->isDependentContext()) {
+ // ... since this is an implicit member reference, that might potentially
+ // involve a 'this' capture, mark 'this' for potential capture in
+ // enclosing lambdas.
+ if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None)
+ CurLSI->addPotentialThisCapture(CallLoc);
+ }
+}
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -5235,6 +5257,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs,
Context.DependentTy, VK_RValue, RParenLoc);
} else {
+
+ tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs(
+ *this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()),
+ Fn->getLocStart());
+
return new (Context) CallExpr(
Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc);
}
@@ -5261,9 +5288,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (Fn->getType() == Context.OverloadTy) {
OverloadExpr::FindResult find = OverloadExpr::find(Fn);
- // We aren't supposed to apply this logic for if there'Scope an '&'
- // involved.
+ // We aren't supposed to apply this logic if there's an '&' involved.
if (!find.HasFormOfMemberPointer) {
+ if (Expr::hasAnyTypeDependentArguments(ArgExprs))
+ return new (Context) CallExpr(
+ Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc);
OverloadExpr *ovl = find.Expression;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl))
return BuildOverloadedCallExpr(
@@ -5386,9 +5415,11 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// that the callee might not preserve them. This is easy to diagnose here,
// but can be very challenging to debug.
if (auto *Caller = getCurFunctionDecl())
- if (Caller->hasAttr<ARMInterruptAttr>())
- if (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>())
+ if (Caller->hasAttr<ARMInterruptAttr>()) {
+ bool VFP = Context.getTargetInfo().hasFeature("vfp");
+ if (VFP && (!FDecl || !FDecl->hasAttr<ARMInterruptAttr>()))
Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention);
+ }
// Promote the function operand.
// We special-case function promotion here because we only allow promoting
@@ -5730,8 +5761,8 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_ObjCObjectPointer:
switch (DestTy->getScalarTypeKind()) {
case Type::STK_CPointer: {
- unsigned SrcAS = SrcTy->getPointeeType().getAddressSpace();
- unsigned DestAS = DestTy->getPointeeType().getAddressSpace();
+ LangAS SrcAS = SrcTy->getPointeeType().getAddressSpace();
+ LangAS DestAS = DestTy->getPointeeType().getAddressSpace();
if (SrcAS != DestAS)
return CK_AddressSpaceConversion;
return CK_BitCast;
@@ -6003,9 +6034,9 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
// In OpenCL, casts between vectors of different types are not allowed.
// (See OpenCL 6.2).
if (SrcTy->isVectorType()) {
- if (!areLaxCompatibleVectorTypes(SrcTy, DestTy)
- || (getLangOpts().OpenCL &&
- (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) {
+ if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) ||
+ (getLangOpts().OpenCL &&
+ !Context.hasSameUnqualifiedType(DestTy, SrcTy))) {
Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
<< DestTy << SrcTy << R;
return ExprError();
@@ -6335,9 +6366,9 @@ 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();
+ LangAS ResultAddrSpace = LangAS::Default;
+ LangAS LAddrSpace = lhQual.getAddressSpace();
+ LangAS RAddrSpace = rhQual.getAddressSpace();
if (S.getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
// spaces is disallowed.
@@ -6418,14 +6449,13 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
return S.Context
.getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals)
.withCVRQualifiers(MergedCVRQual);
- } else
- return CompositeTy.withCVRQualifiers(MergedCVRQual);
+ }
+ return CompositeTy.withCVRQualifiers(MergedCVRQual);
}();
if (IsBlockPointer)
ResultTy = S.Context.getBlockPointerType(ResultTy);
- else {
+ else
ResultTy = S.Context.getPointerType(ResultTy);
- }
LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind);
RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind);
@@ -7212,6 +7242,16 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
commonExpr = commonRes.get();
}
+ // If the common expression is a class or array prvalue, materialize it
+ // so that we can safely refer to it multiple times.
+ if (commonExpr->isRValue() && (commonExpr->getType()->isRecordType() ||
+ commonExpr->getType()->isArrayType())) {
+ ExprResult MatExpr = TemporaryMaterializationConversion(commonExpr);
+ if (MatExpr.isInvalid())
+ return ExprError();
+ commonExpr = MatExpr.get();
+ }
+
opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
commonExpr->getType(),
commonExpr->getValueKind(),
@@ -7476,6 +7516,14 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false);
}
+/// This helper function returns true if QT is a vector type that has element
+/// type ElementType.
+static bool isVector(QualType QT, QualType ElementType) {
+ if (const VectorType *VT = QT->getAs<VectorType>())
+ return VT->getElementType() == ElementType;
+ return false;
+}
+
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
/// has code to accommodate several GCC extensions when type checking
/// pointers. Here are some objectionable examples that GCC considers warnings:
@@ -7594,6 +7642,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (unsupportedTypeConversion(*this, LHSType, RHSType))
return Incompatible;
+ // Disallow assigning a _Complex to a real type in C++ mode since it simply
+ // discards the imaginary part.
+ if (getLangOpts().CPlusPlus && RHSType->getAs<ComplexType>() &&
+ !LHSType->getAs<ComplexType>())
+ return Incompatible;
+
// Arithmetic conversions.
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
@@ -7606,8 +7660,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) {
// U* -> T*
if (isa<PointerType>(RHSType)) {
- unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
- unsigned AddrSpaceR = RHSType->getPointeeType().getAddressSpace();
+ LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
+ LangAS AddrSpaceR = RHSType->getPointeeType().getAddressSpace();
Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return checkPointerTypesForAssignment(*this, LHSType, RHSType);
}
@@ -7642,10 +7696,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// U^ -> void*
if (RHSType->getAs<BlockPointerType>()) {
if (LHSPointer->getPointeeType()->isVoidType()) {
- unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
- unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>()
- ->getPointeeType()
- .getAddressSpace();
+ LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
+ LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
Kind =
AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return Compatible;
@@ -7659,12 +7713,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (isa<BlockPointerType>(LHSType)) {
// U^ -> T^
if (RHSType->isBlockPointerType()) {
- unsigned AddrSpaceL = LHSType->getAs<BlockPointerType>()
- ->getPointeeType()
- .getAddressSpace();
- unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>()
- ->getPointeeType()
- .getAddressSpace();
+ LangAS AddrSpaceL = LHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
+ LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType);
}
@@ -7698,7 +7752,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;
@@ -7905,7 +7959,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;
@@ -7982,9 +8036,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;
}
@@ -8014,34 +8068,71 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS,
return QualType();
}
+// Diagnose cases where a scalar was implicitly converted to a vector and
+// diagnose the underlying types. Otherwise, diagnose the error
+// as invalid vector logical operands for non-C++ cases.
+QualType Sema::InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS,
+ ExprResult &RHS) {
+ QualType LHSType = LHS.get()->IgnoreImpCasts()->getType();
+ QualType RHSType = RHS.get()->IgnoreImpCasts()->getType();
+
+ bool LHSNatVec = LHSType->isVectorType();
+ bool RHSNatVec = RHSType->isVectorType();
+
+ if (!(LHSNatVec && RHSNatVec)) {
+ Expr *Vector = LHSNatVec ? LHS.get() : RHS.get();
+ Expr *NonVector = !LHSNatVec ? LHS.get() : RHS.get();
+ Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict)
+ << 0 << Vector->getType() << NonVector->IgnoreImpCasts()->getType()
+ << Vector->getSourceRange();
+ return QualType();
+ }
+
+ Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict)
+ << 1 << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+
+ return QualType();
+}
+
/// Try to convert a value of non-vector type to a vector type by converting
/// the type to the element type of the vector and then performing a splat.
/// If the language is OpenCL, we only use conversions that promote scalar
/// rank; for C, Obj-C, and C++ we allow any real scalar conversion except
/// for float->int.
///
+/// OpenCL V2.0 6.2.6.p2:
+/// An error shall occur if any scalar operand type has greater rank
+/// than the type of the vector element.
+///
/// \param scalar - if non-null, actually perform the conversions
/// \return true if the operation fails (but without diagnosing the failure)
static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
QualType scalarTy,
QualType vectorEltTy,
- QualType vectorTy) {
+ QualType vectorTy,
+ unsigned &DiagID) {
// The conversion to apply to the scalar before splatting it,
// if necessary.
CastKind scalarCast = CK_Invalid;
if (vectorEltTy->isIntegralType(S.Context)) {
- if (!scalarTy->isIntegralType(S.Context))
+ if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() ||
+ (scalarTy->isIntegerType() &&
+ S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0))) {
+ DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type;
return true;
- if (S.getLangOpts().OpenCL &&
- S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0)
+ }
+ if (!scalarTy->isIntegralType(S.Context))
return true;
scalarCast = CK_IntegralCast;
} else if (vectorEltTy->isRealFloatingType()) {
if (scalarTy->isRealFloatingType()) {
if (S.getLangOpts().OpenCL &&
- S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0)
+ S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0) {
+ DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type;
return true;
+ }
scalarCast = CK_FloatingCast;
}
else if (scalarTy->isIntegralType(S.Context))
@@ -8061,6 +8152,181 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
return false;
}
+/// Convert vector E to a vector with the same number of elements but different
+/// element type.
+static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) {
+ const auto *VecTy = E->getType()->getAs<VectorType>();
+ assert(VecTy && "Expression E must be a vector");
+ QualType NewVecTy = S.Context.getVectorType(ElementType,
+ VecTy->getNumElements(),
+ VecTy->getVectorKind());
+
+ // Look through the implicit cast. Return the subexpression if its type is
+ // NewVecTy.
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getSubExpr()->getType() == NewVecTy)
+ return ICE->getSubExpr();
+
+ auto Cast = ElementType->isIntegerType() ? CK_IntegralCast : CK_FloatingCast;
+ return S.ImpCastExprToType(E, NewVecTy, Cast);
+}
+
+/// Test if a (constant) integer Int can be casted to another integer type
+/// IntTy without losing precision.
+static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int,
+ QualType OtherIntTy) {
+ QualType IntTy = Int->get()->getType().getUnqualifiedType();
+
+ // Reject cases where the value of the Int is unknown as that would
+ // possibly cause truncation, but accept cases where the scalar can be
+ // demoted without loss of precision.
+ llvm::APSInt Result;
+ bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context);
+ int Order = S.Context.getIntegerTypeOrder(OtherIntTy, IntTy);
+ bool IntSigned = IntTy->hasSignedIntegerRepresentation();
+ bool OtherIntSigned = OtherIntTy->hasSignedIntegerRepresentation();
+
+ if (CstInt) {
+ // If the scalar is constant and is of a higher order and has more active
+ // bits that the vector element type, reject it.
+ unsigned NumBits = IntSigned
+ ? (Result.isNegative() ? Result.getMinSignedBits()
+ : Result.getActiveBits())
+ : Result.getActiveBits();
+ if (Order < 0 && S.Context.getIntWidth(OtherIntTy) < NumBits)
+ return true;
+
+ // If the signedness of the scalar type and the vector element type
+ // differs and the number of bits is greater than that of the vector
+ // element reject it.
+ return (IntSigned != OtherIntSigned &&
+ NumBits > S.Context.getIntWidth(OtherIntTy));
+ }
+
+ // Reject cases where the value of the scalar is not constant and it's
+ // order is greater than that of the vector element type.
+ return (Order < 0);
+}
+
+/// Test if a (constant) integer Int can be casted to floating point type
+/// FloatTy without losing precision.
+static bool canConvertIntTyToFloatTy(Sema &S, ExprResult *Int,
+ QualType FloatTy) {
+ QualType IntTy = Int->get()->getType().getUnqualifiedType();
+
+ // Determine if the integer constant can be expressed as a floating point
+ // number of the appropiate type.
+ llvm::APSInt Result;
+ bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context);
+ uint64_t Bits = 0;
+ if (CstInt) {
+ // Reject constants that would be truncated if they were converted to
+ // the floating point type. Test by simple to/from conversion.
+ // FIXME: Ideally the conversion to an APFloat and from an APFloat
+ // could be avoided if there was a convertFromAPInt method
+ // which could signal back if implicit truncation occurred.
+ llvm::APFloat Float(S.Context.getFloatTypeSemantics(FloatTy));
+ Float.convertFromAPInt(Result, IntTy->hasSignedIntegerRepresentation(),
+ llvm::APFloat::rmTowardZero);
+ llvm::APSInt ConvertBack(S.Context.getIntWidth(IntTy),
+ !IntTy->hasSignedIntegerRepresentation());
+ bool Ignored = false;
+ Float.convertToInteger(ConvertBack, llvm::APFloat::rmNearestTiesToEven,
+ &Ignored);
+ if (Result != ConvertBack)
+ return true;
+ } else {
+ // Reject types that cannot be fully encoded into the mantissa of
+ // the float.
+ Bits = S.Context.getTypeSize(IntTy);
+ unsigned FloatPrec = llvm::APFloat::semanticsPrecision(
+ S.Context.getFloatTypeSemantics(FloatTy));
+ if (Bits > FloatPrec)
+ return true;
+ }
+
+ return false;
+}
+
+/// Attempt to convert and splat Scalar into a vector whose types matches
+/// Vector following GCC conversion rules. The rule is that implicit
+/// conversion can occur when Scalar can be casted to match Vector's element
+/// type without causing truncation of Scalar.
+static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
+ ExprResult *Vector) {
+ QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType();
+ QualType VectorTy = Vector->get()->getType().getUnqualifiedType();
+ const VectorType *VT = VectorTy->getAs<VectorType>();
+
+ assert(!isa<ExtVectorType>(VT) &&
+ "ExtVectorTypes should not be handled here!");
+
+ QualType VectorEltTy = VT->getElementType();
+
+ // Reject cases where the vector element type or the scalar element type are
+ // not integral or floating point types.
+ if (!VectorEltTy->isArithmeticType() || !ScalarTy->isArithmeticType())
+ return true;
+
+ // The conversion to apply to the scalar before splatting it,
+ // if necessary.
+ CastKind ScalarCast = CK_NoOp;
+
+ // Accept cases where the vector elements are integers and the scalar is
+ // an integer.
+ // FIXME: Notionally if the scalar was a floating point value with a precise
+ // integral representation, we could cast it to an appropriate integer
+ // type and then perform the rest of the checks here. GCC will perform
+ // this conversion in some cases as determined by the input language.
+ // We should accept it on a language independent basis.
+ if (VectorEltTy->isIntegralType(S.Context) &&
+ ScalarTy->isIntegralType(S.Context) &&
+ S.Context.getIntegerTypeOrder(VectorEltTy, ScalarTy)) {
+
+ if (canConvertIntToOtherIntTy(S, Scalar, VectorEltTy))
+ return true;
+
+ ScalarCast = CK_IntegralCast;
+ } else if (VectorEltTy->isRealFloatingType()) {
+ if (ScalarTy->isRealFloatingType()) {
+
+ // Reject cases where the scalar type is not a constant and has a higher
+ // Order than the vector element type.
+ llvm::APFloat Result(0.0);
+ bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context);
+ int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy);
+ if (!CstScalar && Order < 0)
+ return true;
+
+ // If the scalar cannot be safely casted to the vector element type,
+ // reject it.
+ if (CstScalar) {
+ bool Truncated = false;
+ Result.convert(S.Context.getFloatTypeSemantics(VectorEltTy),
+ llvm::APFloat::rmNearestTiesToEven, &Truncated);
+ if (Truncated)
+ return true;
+ }
+
+ ScalarCast = CK_FloatingCast;
+ } else if (ScalarTy->isIntegralType(S.Context)) {
+ if (canConvertIntTyToFloatTy(S, Scalar, VectorEltTy))
+ return true;
+
+ ScalarCast = CK_IntegralToFloating;
+ } else
+ return true;
+ }
+
+ // Adjust scalar if desired.
+ if (Scalar) {
+ if (ScalarCast != CK_NoOp)
+ *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast);
+ *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat);
+ }
+ return false;
+}
+
QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign,
bool AllowBothBool,
@@ -8129,22 +8395,34 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
}
}
- // If there's an ext-vector type and a scalar, try to convert the scalar to
+ // If there's a vector type and a scalar, try to convert the scalar to
// the vector element type and splat.
- // FIXME: this should also work for regular vector types as supported in GCC.
- if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) {
- if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
- LHSVecType->getElementType(), LHSType))
- return LHSType;
+ unsigned DiagID = diag::err_typecheck_vector_not_convertable;
+ if (!RHSVecType) {
+ if (isa<ExtVectorType>(LHSVecType)) {
+ if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
+ LHSVecType->getElementType(), LHSType,
+ DiagID))
+ return LHSType;
+ } else {
+ if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS))
+ return LHSType;
+ }
}
- if (!LHSVecType && isa<ExtVectorType>(RHSVecType)) {
- if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS),
- LHSType, RHSVecType->getElementType(),
- RHSType))
- return RHSType;
+ if (!LHSVecType) {
+ if (isa<ExtVectorType>(RHSVecType)) {
+ if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS),
+ LHSType, RHSVecType->getElementType(),
+ RHSType, DiagID))
+ return RHSType;
+ } else {
+ if (LHS.get()->getValueKind() == VK_LValue ||
+ !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS))
+ return RHSType;
+ }
}
- // FIXME: The code below also handles convertion between vectors and
+ // FIXME: The code below also handles conversion between vectors and
// non-scalars, we should break this down into fine grained specific checks
// and emit proper diagnostics.
QualType VecType = LHSVecType ? LHSType : RHSType;
@@ -8163,7 +8441,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
// type. Note that this is already done by non-compound assignments in
// CheckAssignmentConstraints. If it's a scalar type, only bitcast for
// <1 x T> -> T. The result is also a vector type.
- } else if (OtherType->isExtVectorType() ||
+ } else if (OtherType->isExtVectorType() || OtherType->isVectorType() ||
(OtherType->isScalarType() && VT->getNumElements() == 1)) {
ExprResult *RHSExpr = &RHS;
*RHSExpr = ImpCastExprToType(RHSExpr->get(), LHSType, CK_BitCast);
@@ -8194,8 +8472,24 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
+
+ // If there is a vector type that is not a ExtVector and a scalar, we reach
+ // this point if scalar could not be converted to the vector's element type
+ // without truncation.
+ if ((RHSVecType && !isa<ExtVectorType>(RHSVecType)) ||
+ (LHSVecType && !isa<ExtVectorType>(LHSVecType))) {
+ QualType Scalar = LHSVecType ? RHSType : LHSType;
+ QualType Vector = LHSVecType ? LHSType : RHSType;
+ unsigned ScalarOrVector = LHSVecType && RHSVecType ? 1 : 0;
+ Diag(Loc,
+ diag::err_typecheck_vector_not_convertable_implict_truncation)
+ << ScalarOrVector << Scalar << Vector;
+
+ return QualType();
+ }
+
// Otherwise, use the generic diagnostic.
- Diag(Loc, diag::err_typecheck_vector_not_convertable)
+ Diag(Loc, DiagID)
<< LHSType << RHSType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
@@ -8318,6 +8612,21 @@ static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
<< 0 /* one pointer */ << Pointer->getSourceRange();
}
+/// \brief Diagnose invalid arithmetic on a null pointer.
+///
+/// If \p IsGNUIdiom is true, the operation is using the 'p = (i8*)nullptr + n'
+/// idiom, which we recognize as a GNU extension.
+///
+static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer, bool IsGNUIdiom) {
+ if (IsGNUIdiom)
+ S.Diag(Loc, diag::warn_gnu_null_ptr_arith)
+ << Pointer->getSourceRange();
+ else
+ S.Diag(Loc, diag::warn_pointer_arith_null_ptr)
+ << S.getLangOpts().CPlusPlus << Pointer->getSourceRange();
+}
+
/// \brief Diagnose invalid arithmetic on two function pointers.
static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
@@ -8612,6 +8921,21 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
if (!IExp->getType()->isIntegerType())
return InvalidOperands(Loc, LHS, RHS);
+ // Adding to a null pointer results in undefined behavior.
+ if (PExp->IgnoreParenCasts()->isNullPointerConstant(
+ Context, Expr::NPC_ValueDependentIsNotNull)) {
+ // In C++ adding zero to a null pointer is defined.
+ llvm::APSInt KnownVal;
+ if (!getLangOpts().CPlusPlus ||
+ (!IExp->isValueDependent() &&
+ (!IExp->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) {
+ // Check the conditions to see if this is the 'p = nullptr + n' idiom.
+ bool IsGNUIdiom = BinaryOperator::isNullPointerArithmeticExtension(
+ Context, BO_Add, PExp, IExp);
+ diagnoseArithmeticOnNullPointer(*this, Loc, PExp, IsGNUIdiom);
+ }
+ }
+
if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
return QualType();
@@ -8673,6 +8997,20 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
// The result type of a pointer-int computation is the pointer type.
if (RHS.get()->getType()->isIntegerType()) {
+ // Subtracting from a null pointer should produce a warning.
+ // The last argument to the diagnose call says this doesn't match the
+ // GNU int-to-pointer idiom.
+ if (LHS.get()->IgnoreParenCasts()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull)) {
+ // In C++ adding zero to a null pointer is defined.
+ llvm::APSInt KnownVal;
+ if (!getLangOpts().CPlusPlus ||
+ (!RHS.get()->isValueDependent() &&
+ (!RHS.get()->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) {
+ diagnoseArithmeticOnNullPointer(*this, Loc, LHS.get(), false);
+ }
+ }
+
if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get()))
return QualType();
@@ -8708,6 +9046,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
LHS.get(), RHS.get()))
return QualType();
+ // FIXME: Add warnings for nullptr - ptr.
+
// The pointee type may have zero size. As an extension, a structure or
// union may have zero size or an array may have zero length. In this
// case subtraction does not make sense.
@@ -8983,9 +9323,11 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
return;
// Ignore anonymous enums.
- if (!LHSEnumType->getDecl()->getIdentifier())
+ if (!LHSEnumType->getDecl()->getIdentifier() &&
+ !LHSEnumType->getDecl()->getTypedefNameForAnonDecl())
return;
- if (!RHSEnumType->getDecl()->getIdentifier())
+ if (!RHSEnumType->getDecl()->getIdentifier() &&
+ !RHSEnumType->getDecl()->getTypedefNameForAnonDecl())
return;
if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
@@ -9424,7 +9766,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
@@ -9470,8 +9815,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
}
- unsigned AddrSpaceL = LCanPointeeTy.getAddressSpace();
- unsigned AddrSpaceR = RCanPointeeTy.getAddressSpace();
+ LangAS AddrSpaceL = LCanPointeeTy.getAddressSpace();
+ LangAS AddrSpaceR = RCanPointeeTy.getAddressSpace();
CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion
: CK_BitCast;
if (LHSIsNull && !RHSIsNull)
@@ -9610,16 +9955,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);
}
@@ -9707,24 +10053,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
@@ -9771,7 +10138,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);
}
@@ -9788,7 +10155,13 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 &&
vType->hasFloatingRepresentation())
return InvalidOperands(Loc, LHS, RHS);
-
+ // FIXME: The check for C++ here is for GCC compatibility. GCC rejects the
+ // usage of the logical operators && and || with vectors in C. This
+ // check could be notionally dropped.
+ if (!getLangOpts().CPlusPlus &&
+ !(isa<ExtVectorType>(vType->getAs<VectorType>())))
+ return InvalidLogicalVectorOperands(Loc, LHS, RHS);
+
return GetSignedVectorType(LHS.get()->getType());
}
@@ -9973,22 +10346,23 @@ static bool IsTypeModifiable(QualType Ty, bool IsDereference) {
return !Ty.isConstQualified();
}
+// Update err_typecheck_assign_const and note_typecheck_assign_const
+// when this enum is changed.
+enum {
+ ConstFunction,
+ ConstVariable,
+ ConstMember,
+ ConstMethod,
+ NestedConstMember,
+ ConstUnknown, // Keep as last element
+};
+
/// Emit the "read-only variable not assignable" error and print notes to give
/// more information about why the variable is not assignable, such as pointing
/// to the declaration of a const variable, showing that a method is const, or
/// that the function is returning a const reference.
static void DiagnoseConstAssignment(Sema &S, const Expr *E,
SourceLocation Loc) {
- // Update err_typecheck_assign_const and note_typecheck_assign_const
- // when this enum is changed.
- enum {
- ConstFunction,
- ConstVariable,
- ConstMember,
- ConstMethod,
- ConstUnknown, // Keep as last element
- };
-
SourceRange ExprRange = E->getSourceRange();
// Only emit one error on the first const found. All other consts will emit
@@ -10098,6 +10472,66 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown;
}
+enum OriginalExprKind {
+ OEK_Variable,
+ OEK_Member,
+ OEK_LValue
+};
+
+static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD,
+ const RecordType *Ty,
+ SourceLocation Loc, SourceRange Range,
+ OriginalExprKind OEK,
+ bool &DiagnosticEmitted,
+ bool IsNested = false) {
+ // We walk the record hierarchy breadth-first to ensure that we print
+ // diagnostics in field nesting order.
+ // First, check every field for constness.
+ for (const FieldDecl *Field : Ty->getDecl()->fields()) {
+ if (Field->getType().isConstQualified()) {
+ if (!DiagnosticEmitted) {
+ S.Diag(Loc, diag::err_typecheck_assign_const)
+ << Range << NestedConstMember << OEK << VD
+ << IsNested << Field;
+ DiagnosticEmitted = true;
+ }
+ S.Diag(Field->getLocation(), diag::note_typecheck_assign_const)
+ << NestedConstMember << IsNested << Field
+ << Field->getType() << Field->getSourceRange();
+ }
+ }
+ // Then, recurse.
+ for (const FieldDecl *Field : Ty->getDecl()->fields()) {
+ QualType FTy = Field->getType();
+ if (const RecordType *FieldRecTy = FTy->getAs<RecordType>())
+ DiagnoseRecursiveConstFields(S, VD, FieldRecTy, Loc, Range,
+ OEK, DiagnosticEmitted, true);
+ }
+}
+
+/// Emit an error for the case where a record we are trying to assign to has a
+/// const-qualified field somewhere in its hierarchy.
+static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E,
+ SourceLocation Loc) {
+ QualType Ty = E->getType();
+ assert(Ty->isRecordType() && "lvalue was not record?");
+ SourceRange Range = E->getSourceRange();
+ const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>();
+ bool DiagEmitted = false;
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ DiagnoseRecursiveConstFields(S, ME->getMemberDecl(), RTy, Loc,
+ Range, OEK_Member, DiagEmitted);
+ else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ DiagnoseRecursiveConstFields(S, DRE->getDecl(), RTy, Loc,
+ Range, OEK_Variable, DiagEmitted);
+ else
+ DiagnoseRecursiveConstFields(S, nullptr, RTy, Loc,
+ Range, OEK_LValue, DiagEmitted);
+ if (!DiagEmitted)
+ DiagnoseConstAssignment(S, E, Loc);
+}
+
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
@@ -10173,6 +10607,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_ConstAddrSpace:
DiagnoseConstAssignment(S, E, Loc);
return true;
+ case Expr::MLV_ConstQualifiedField:
+ DiagnoseRecursiveConstFields(S, E, Loc);
+ return true;
case Expr::MLV_ArrayType:
case Expr::MLV_ArrayTemporary:
DiagID = diag::err_typecheck_array_not_modifiable_lvalue;
@@ -10317,7 +10754,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;
@@ -10325,11 +10765,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());
}
}
@@ -10661,10 +11103,17 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
// Make sure to ignore parentheses in subsequent checks
Expr *op = OrigOp.get()->IgnoreParens();
- // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
- if (LangOpts.OpenCL && op->getType()->isFunctionType()) {
- Diag(op->getExprLoc(), diag::err_opencl_taking_function_address);
- return QualType();
+ // In OpenCL captures for blocks called as lambda functions
+ // are located in the private address space. Blocks used in
+ // enqueue_kernel can be located in a different address space
+ // depending on a vendor implementation. Thus preventing
+ // taking an address of the capture to avoid invalid AS casts.
+ if (LangOpts.OpenCL) {
+ auto* VarRef = dyn_cast<DeclRefExpr>(op);
+ if (VarRef && VarRef->refersToEnclosingVariableOrCapture()) {
+ Diag(op->getExprLoc(), diag::err_opencl_taking_address_capture);
+ return QualType();
+ }
}
if (getLangOpts().C99) {
@@ -11056,6 +11505,69 @@ static NamedDecl *getDeclFromExpr(Expr *E) {
return nullptr;
}
+// This helper function promotes a binary operator's operands (which are of a
+// half vector type) to a vector of floats and then truncates the result to
+// a vector of either half or short.
+static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
+ BinaryOperatorKind Opc, QualType ResultTy,
+ ExprValueKind VK, ExprObjectKind OK,
+ bool IsCompAssign, SourceLocation OpLoc,
+ FPOptions FPFeatures) {
+ auto &Context = S.getASTContext();
+ assert((isVector(ResultTy, Context.HalfTy) ||
+ isVector(ResultTy, Context.ShortTy)) &&
+ "Result must be a vector of half or short");
+ assert(isVector(LHS.get()->getType(), Context.HalfTy) &&
+ isVector(RHS.get()->getType(), Context.HalfTy) &&
+ "both operands expected to be a half vector");
+
+ RHS = convertVector(RHS.get(), Context.FloatTy, S);
+ QualType BinOpResTy = RHS.get()->getType();
+
+ // If Opc is a comparison, ResultType is a vector of shorts. In that case,
+ // change BinOpResTy to a vector of ints.
+ if (isVector(ResultTy, Context.ShortTy))
+ BinOpResTy = S.GetSignedVectorType(BinOpResTy);
+
+ if (IsCompAssign)
+ return new (Context) CompoundAssignOperator(
+ LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy,
+ OpLoc, FPFeatures);
+
+ LHS = convertVector(LHS.get(), Context.FloatTy, S);
+ auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
+ VK, OK, OpLoc, FPFeatures);
+ return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S);
+}
+
+static std::pair<ExprResult, ExprResult>
+CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr,
+ Expr *RHSExpr) {
+ ExprResult LHS = LHSExpr, RHS = RHSExpr;
+ if (!S.getLangOpts().CPlusPlus) {
+ // C cannot handle TypoExpr nodes on either side of a binop because it
+ // doesn't handle dependent types properly, so make sure any TypoExprs have
+ // been dealt with before checking the operands.
+ LHS = S.CorrectDelayedTyposInExpr(LHS);
+ RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) {
+ if (Opc != BO_Assign)
+ return ExprResult(E);
+ // Avoid correcting the RHS to the same Expr as the LHS.
+ Decl *D = getDeclFromExpr(E);
+ return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
+ });
+ }
+ return std::make_pair(LHS, RHS);
+}
+
+/// Returns true if conversion between vectors of halfs and vectors of floats
+/// is needed.
+static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx,
+ QualType SrcType) {
+ return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType &&
+ Ctx.getLangOpts().HalfArgsAndReturns && isVector(SrcType, Ctx.HalfTy);
+}
+
/// CreateBuiltinBinOp - Creates a new built-in binary operation with
/// operator @p Opc at location @c TokLoc. This routine only supports
/// built-in operations; ActOnBinOp handles overloaded operators.
@@ -11087,22 +11599,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
QualType CompResultTy; // Type of computation result
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
+ bool ConvertHalfVec = false;
- if (!getLangOpts().CPlusPlus) {
- // C cannot handle TypoExpr nodes on either side of a binop because it
- // doesn't handle dependent types properly, so make sure any TypoExprs have
- // been dealt with before checking the operands.
- LHS = CorrectDelayedTyposInExpr(LHSExpr);
- RHS = CorrectDelayedTyposInExpr(RHSExpr, [Opc, LHS](Expr *E) {
- if (Opc != BO_Assign)
- return ExprResult(E);
- // Avoid correcting the RHS to the same Expr as the LHS.
- Decl *D = getDeclFromExpr(E);
- return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
- });
- if (!LHS.isUsable() || !RHS.isUsable())
- return ExprError();
- }
+ std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return ExprError();
if (getLangOpts().OpenCL) {
QualType LHSTy = LHSExpr->getType();
@@ -11112,7 +11613,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();
@@ -11150,6 +11651,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_Mul:
case BO_Div:
+ ConvertHalfVec = true;
ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false,
Opc == BO_Div);
break;
@@ -11157,9 +11659,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc);
break;
case BO_Add:
+ ConvertHalfVec = true;
ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_Sub:
+ ConvertHalfVec = true;
ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc);
break;
case BO_Shl:
@@ -11170,24 +11674,29 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_LT:
case BO_GE:
case BO_GT:
+ ConvertHalfVec = true;
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true);
break;
case BO_EQ:
case BO_NE:
+ ConvertHalfVec = true;
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false);
break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
+ LLVM_FALLTHROUGH;
case BO_Xor:
case BO_Or:
ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_LAnd:
case BO_LOr:
+ ConvertHalfVec = true;
ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_MulAssign:
case BO_DivAssign:
+ ConvertHalfVec = true;
CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true,
Opc == BO_DivAssign);
CompLHSTy = CompResultTy;
@@ -11201,11 +11710,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_AddAssign:
+ ConvertHalfVec = true;
CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_SubAssign:
+ ConvertHalfVec = true;
CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
@@ -11220,6 +11731,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_AndAssign:
case BO_OrAssign: // fallthrough
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
+ LLVM_FALLTHROUGH;
case BO_XorAssign:
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
CompLHSTy = CompResultTy;
@@ -11237,6 +11749,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
+ // Some of the binary operations require promoting operands of half vector to
+ // float vectors and truncating the result back to half vector. For now, we do
+ // this only when HalfArgsAndReturn is set (that is, when the target is arm or
+ // arm64).
+ assert(isVector(RHS.get()->getType(), Context.HalfTy) ==
+ isVector(LHS.get()->getType(), Context.HalfTy) &&
+ "both sides are half vectors or neither sides are");
+ ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context,
+ LHS.get()->getType());
+
// Check for array bounds violations for both sides of the BinaryOperator
CheckArrayAccess(LHS.get());
CheckArrayAccess(RHS.get());
@@ -11259,17 +11781,29 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts()))
DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get());
- if (CompResultTy.isNull())
+ // Opc is not a compound assignment if CompResultTy is null.
+ if (CompResultTy.isNull()) {
+ if (ConvertHalfVec)
+ return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false,
+ OpLoc, FPFeatures);
return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK,
- OK, OpLoc, FPFeatures.fp_contract);
+ OK, OpLoc, FPFeatures);
+ }
+
+ // Handle compound assignments.
if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
OK_ObjCProperty) {
VK = VK_LValue;
OK = LHS.get()->getObjectKind();
}
+
+ if (ConvertHalfVec)
+ return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true,
+ OpLoc, FPFeatures);
+
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
@@ -11514,6 +12048,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
+ ExprResult LHS, RHS;
+ std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return ExprError();
+ LHSExpr = LHS.get();
+ RHSExpr = RHS.get();
+
// We want to end up calling one of checkPseudoObjectAssignment
// (if the LHS is a pseudo-object), BuildOverloadedBinOp (if
// both expressions are overloadable or either is type-dependent),
@@ -11542,6 +12083,28 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
RHSExpr->getType()->isOverloadableType())
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
}
+
+ // If we're instantiating "a.x < b" or "A::x < b" and 'x' names a function
+ // template, diagnose the missing 'template' keyword instead of diagnosing
+ // an invalid use of a bound member function.
+ //
+ // Note that "A::x < b" might be valid if 'b' has an overloadable type due
+ // to C++1z [over.over]/1.4, but we already checked for that case above.
+ if (Opc == BO_LT && inTemplateInstantiation() &&
+ (pty->getKind() == BuiltinType::BoundMember ||
+ pty->getKind() == BuiltinType::Overload)) {
+ auto *OE = dyn_cast<OverloadExpr>(LHSExpr);
+ if (OE && !OE->hasTemplateKeyword() && !OE->hasExplicitTemplateArgs() &&
+ std::any_of(OE->decls_begin(), OE->decls_end(), [](NamedDecl *ND) {
+ return isa<FunctionTemplateDecl>(ND);
+ })) {
+ Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc()
+ : OE->getNameLoc(),
+ diag::err_template_kw_missing)
+ << OE->getName().getAsString() << "";
+ return ExprError();
+ }
+ }
ExprResult LHS = CheckPlaceholderExpr(LHSExpr);
if (LHS.isInvalid()) return ExprError();
@@ -11595,6 +12158,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
QualType resultType;
+ bool ConvertHalfVec = false;
if (getLangOpts().OpenCL) {
QualType Ty = InputExpr->getType();
// The only legal unary operation for atomics is '&'.
@@ -11634,6 +12198,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Minus:
Input = UsualUnaryConversions(Input.get());
if (Input.isInvalid()) return ExprError();
+ // Unary plus and minus require promoting an operand of half vector to a
+ // float vector and truncating the result back to a half vector. For now, we
+ // do this only when HalfArgsAndReturns is set (that is, when the target is
+ // arm or arm64).
+ ConvertHalfVec =
+ needsConversionOfHalfVec(true, Context, Input.get()->getType());
+
+ // If the operand is a half vector, promote it to a float vector.
+ if (ConvertHalfVec)
+ Input = convertVector(Input.get(), Context.FloatTy, *this);
resultType = Input.get()->getType();
if (resultType->isDependentType())
break;
@@ -11667,16 +12241,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
- else if (resultType->isExtVectorType()) {
- if (Context.getLangOpts().OpenCL) {
- // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
- // on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
- if (!T->isIntegerType())
- return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
- << resultType << Input.get()->getSourceRange());
- }
- break;
+ else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+ // on vector float types.
+ QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ if (!T->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -11726,6 +12297,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = GetSignedVectorType(resultType);
break;
} else {
+ // FIXME: GCC's vector extension permits the usage of '!' with a vector
+ // type in C++. We should allow that here too.
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
@@ -11750,11 +12323,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
break;
case UO_Extension:
- case UO_Coawait:
resultType = Input.get()->getType();
VK = Input.get()->getValueKind();
OK = Input.get()->getObjectKind();
break;
+ case UO_Coawait:
+ // It's unnessesary to represent the pass-through operator co_await in the
+ // AST; just return the input expression instead.
+ assert(!Input.get()->getType()->isDependentType() &&
+ "the co_await expression must be non-dependant before "
+ "building operator co_await");
+ return Input;
}
if (resultType.isNull() || Input.isInvalid())
return ExprError();
@@ -11766,8 +12345,12 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Opc != UO_AddrOf && Opc != UO_Deref)
CheckArrayAccess(Input.get());
- return new (Context)
+ auto *UO = new (Context)
UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc);
+ // Convert the result back to a half vector.
+ if (ConvertHalfVec)
+ return convertVector(UO, Context.HalfTy, *this);
+ return UO;
}
/// \brief Determine whether the given expression is a qualified member
@@ -12242,7 +12825,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,
@@ -12458,6 +13042,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
+ if (Body && getCurFunction()->HasPotentialAvailabilityViolations)
+ DiagnoseUnguardedAvailabilityViolations(BSI->TheDecl);
+
// Try to apply the named return value optimization. We have to check again
// if we can do this, though, because blocks keep return statements around
// to deduce an implicit return type.
@@ -13135,7 +13722,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:
@@ -13156,7 +13743,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 {
@@ -13173,7 +13760,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;
@@ -13215,19 +13802,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.
@@ -13245,17 +13832,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");
@@ -13415,6 +14002,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// call to such a function.
InstantiateFunctionDefinition(PointOfInstantiation, Func);
else {
+ Func->setInstantiationIsPending(true);
PendingInstantiations.push_back(std::make_pair(Func,
PointOfInstantiation));
// Notify the consumer that a function was implicitly instantiated.
@@ -13439,6 +14027,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
!LangOpts.GNUInline &&
!Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>())
UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ else if (isExternalWithNoLinkageType(Func))
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
}
Func->markUsed(Context);
@@ -13710,7 +14300,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
@@ -13785,6 +14376,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
Field->setImplicit(true);
Field->setAccess(AS_private);
RD->addDecl(Field);
+ if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
+ S.setOpenMPCaptureKind(Field, Var, RSI->OpenMPLevel);
CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable,
DeclRefType, VK_LValue, Loc);
@@ -13955,6 +14548,7 @@ bool Sema::tryCaptureVariable(
bool IsGlobal = !Var->hasLocalStorage();
if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var)))
return true;
+ Var = Var->getCanonicalDecl();
// Walk up the stack to determine whether we can capture the variable,
// performing the "simple" checks that don't depend on type. We stop when
@@ -14239,9 +14833,10 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
bool OdrUseContext = isOdrUseContext(SemaRef);
+ bool UsableInConstantExpr =
+ Var->isUsableInConstantExpressions(SemaRef.Context);
bool NeedDefinition =
- OdrUseContext || (isEvaluatableContext(SemaRef) &&
- Var->isUsableInConstantExpressions(SemaRef.Context));
+ OdrUseContext || (isEvaluatableContext(SemaRef) && UsableInConstantExpr);
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -14260,14 +14855,19 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// instantiations of variable templates, except for those that could be used
// in a constant expression.
if (NeedDefinition && isTemplateInstantiation(TSK)) {
- bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
+ // Per C++17 [temp.explicit]p10, we may instantiate despite an explicit
+ // instantiation declaration if a variable is usable in a constant
+ // expression (among other cases).
+ bool TryInstantiating =
+ TSK == TSK_ImplicitInstantiation ||
+ (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr);
if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) {
if (Var->getPointOfInstantiation().isInvalid()) {
// This is a modification of an existing AST node. Notify listeners.
if (ASTMutationListener *L = SemaRef.getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
- } else if (!Var->isUsableInConstantExpressions(SemaRef.Context))
+ } else if (!UsableInConstantExpr)
// Don't bother trying to instantiate it again, unless we might need
// its initializer before we get to the end of the TU.
TryInstantiating = false;
@@ -14286,7 +14886,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// Do not instantiate specializations that are still type-dependent.
if (IsNonDependent) {
- if (Var->isUsableInConstantExpressions(SemaRef.Context)) {
+ if (UsableInConstantExpr) {
// Do not defer instantiations of variables which could be used in a
// constant expression.
SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
@@ -14310,7 +14910,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
IsVariableAConstantExpression(Var, SemaRef.Context)) {
// A reference initialized by a constant expression can never be
// odr-used, so simply ignore it.
- if (!Var->getType()->isReferenceType())
+ if (!Var->getType()->isReferenceType() ||
+ (SemaRef.LangOpts.OpenMP && SemaRef.IsOpenMPCapturedDecl(Var)))
SemaRef.MaybeODRUseExprs.insert(E);
} else if (OdrUseContext) {
MarkVarDeclODRUsed(Var, Loc, SemaRef,
@@ -14376,24 +14977,24 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
ME->performsVirtualDispatch(SemaRef.getLangOpts());
if (!IsVirtualCall)
return;
- const Expr *Base = ME->getBase();
- const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
- if (!MostDerivedClassDecl)
- return;
- CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
- if (!DM || DM->isPure())
- return;
- SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse);
-}
+
+ // If it's possible to devirtualize the call, mark the called function
+ // referenced.
+ CXXMethodDecl *DM = MD->getDevirtualizedMethod(
+ ME->getBase(), SemaRef.getLangOpts().AppleKext);
+ if (DM)
+ SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse);
+}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
-void Sema::MarkDeclRefReferenced(DeclRefExpr *E) {
+void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
// TODO: update this with DR# once a defect report is filed.
// C++11 defect. The address of a pure member should not be an ODR use, even
// if it's a qualified reference.
bool OdrUse = true;
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
- if (Method->isVirtual())
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
+ if (Method->isVirtual() &&
+ !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext))
OdrUse = false;
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
}
@@ -14461,7 +15062,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);
@@ -14581,26 +15183,40 @@ 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));
+ return true;
}
- else
- Diag(Loc, PD);
-
+
+ // The initializer of a constexpr variable or of the first declaration of a
+ // static data member is not syntactically a constant evaluated constant,
+ // but nonetheless is always required to be a constant expression, so we
+ // can skip diagnosing.
+ // FIXME: Using the mangling context here is a hack.
+ if (auto *VD = dyn_cast_or_null<VarDecl>(
+ ExprEvalContexts.back().ManglingContextDecl)) {
+ if (VD->isConstexpr() ||
+ (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline()))
+ break;
+ // FIXME: For any other kind of variable, we should build a CFG for its
+ // initializer and check whether the context in question is reachable.
+ }
+
+ Diag(Loc, PD);
return true;
}
@@ -15324,7 +15940,7 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
}
/// Check for operands with placeholder types and complain if found.
-/// Returns true if there was an error and no recovery was possible.
+/// Returns ExprError() if there was an error and no recovery was possible.
ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
if (!getLangOpts().CPlusPlus) {
// C cannot handle TypoExpr nodes on either side of a binop because it
@@ -15472,6 +16088,13 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
if (Spec != AvailSpecs.end())
Version = Spec->getVersion();
+ // The use of `@available` in the enclosing function should be analyzed to
+ // warn when it's used inappropriately (i.e. not if(@available)).
+ if (getCurFunctionOrMethodDecl())
+ getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
+ else if (getCurBlock() || getCurLambda())
+ getCurFunction()->HasPotentialAvailabilityViolations = true;
+
return new (Context)
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 561e12d87a..1ed714f8c8 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/AlignedAllocation.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -189,12 +190,15 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
// have one) and, if that fails to find a match, in the scope (if
// we're allowed to look there).
Found.clear();
- if (Step == 0 && LookupCtx)
+ if (Step == 0 && LookupCtx) {
+ if (RequireCompleteDeclContext(SS, LookupCtx))
+ return nullptr;
LookupQualifiedName(Found, LookupCtx);
- else if (Step == 1 && LookInScope && S)
+ } else if (Step == 1 && LookInScope && S) {
LookupName(Found, S);
- else
+ } else {
continue;
+ }
// FIXME: Should we be suppressing ambiguities here?
if (Found.isAmbiguous())
@@ -901,17 +905,36 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
// capturing lamdbda's call operator.
//
- // The issue is that we cannot rely entirely on the FunctionScopeInfo stack
- // since ScopeInfos are pushed on during parsing and treetransforming. But
- // since a generic lambda's call operator can be instantiated anywhere (even
- // end of the TU) we need to be able to examine its enclosing lambdas and so
- // we use the DeclContext to get a hold of the closure-class and query it for
- // capture information. The reason we don't just resort to always using the
- // DeclContext chain is that it is only mature for lambda expressions
- // enclosing generic lambda's call operators that are being instantiated.
-
+ // Since the FunctionScopeInfo stack is representative of the lexical
+ // nesting of the lambda expressions during initial parsing (and is the best
+ // place for querying information about captures about lambdas that are
+ // partially processed) and perhaps during instantiation of function templates
+ // that contain lambda expressions that need to be transformed BUT not
+ // necessarily during instantiation of a nested generic lambda's function call
+ // operator (which might even be instantiated at the end of the TU) - at which
+ // time the DeclContext tree is mature enough to query capture information
+ // reliably - we use a two pronged approach to walk through all the lexically
+ // enclosing lambda expressions:
+ //
+ // 1) Climb down the FunctionScopeInfo stack as long as each item represents
+ // a Lambda (i.e. LambdaScopeInfo) AND each LSI's 'closure-type' is lexically
+ // enclosed by the call-operator of the LSI below it on the stack (while
+ // tracking the enclosing DC for step 2 if needed). Note the topmost LSI on
+ // the stack represents the innermost lambda.
+ //
+ // 2) If we run out of enclosing LSI's, check if the enclosing DeclContext
+ // represents a lambda's call operator. If it does, we must be instantiating
+ // a generic lambda's call operator (represented by the Current LSI, and
+ // should be the only scenario where an inconsistency between the LSI and the
+ // DeclContext should occur), so climb out the DeclContexts if they
+ // represent lambdas, while querying the corresponding closure types
+ // regarding capture information.
+
+ // 1) Climb down the function scope info stack.
for (int I = FunctionScopes.size();
- I-- && isa<LambdaScopeInfo>(FunctionScopes[I]);
+ I-- && isa<LambdaScopeInfo>(FunctionScopes[I]) &&
+ (!CurLSI || !CurLSI->Lambda || CurLSI->Lambda->getDeclContext() ==
+ cast<LambdaScopeInfo>(FunctionScopes[I])->CallOperator);
CurDC = getLambdaAwareParentOfDeclContext(CurDC)) {
CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]);
@@ -927,11 +950,17 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
return ASTCtx.getPointerType(ClassType);
}
}
- // We've run out of ScopeInfos but check if CurDC is a lambda (which can
- // happen during instantiation of generic lambdas)
+
+ // 2) We've run out of ScopeInfos but check if CurDC is a lambda (which can
+ // happen during instantiation of its nested generic lambda call operator)
if (isLambdaCallOperator(CurDC)) {
- assert(CurLSI);
- assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator));
+ assert(CurLSI && "While computing 'this' capture-type for a generic "
+ "lambda, we must have a corresponding LambdaScopeInfo");
+ assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) &&
+ "While computing 'this' capture-type for a generic lambda, when we "
+ "run out of enclosing LSI's, yet the enclosing DC is a "
+ "lambda-call-operator we must be (i.e. Current LSI) in a generic "
+ "lambda call oeprator");
assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator));
auto IsThisCaptured =
@@ -1228,17 +1257,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
@@ -1295,46 +1313,51 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
}
// 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, 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();
+ // 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.
@@ -1355,9 +1378,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
/// \brief Determine whether the given function is a non-placement
/// deallocation function.
static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
- if (FD->isInvalidDecl())
- return false;
-
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
return Method->isUsualDeallocationFunction();
@@ -1387,14 +1407,20 @@ namespace {
UsualDeallocFnInfo() : Found(), FD(nullptr) {}
UsualDeallocFnInfo(Sema &S, DeclAccessPair Found)
: Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())),
- HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) {
+ Destroying(false), HasSizeT(false), HasAlignValT(false),
+ CUDAPref(Sema::CFP_Native) {
// A function template declaration is never a usual deallocation function.
if (!FD)
return;
- if (FD->getNumParams() == 3)
+ unsigned NumBaseParams = 1;
+ if (FD->isDestroyingOperatorDelete()) {
+ Destroying = true;
+ ++NumBaseParams;
+ }
+ if (FD->getNumParams() == NumBaseParams + 2)
HasAlignValT = HasSizeT = true;
- else if (FD->getNumParams() == 2) {
- HasSizeT = FD->getParamDecl(1)->getType()->isIntegerType();
+ else if (FD->getNumParams() == NumBaseParams + 1) {
+ HasSizeT = FD->getParamDecl(NumBaseParams)->getType()->isIntegerType();
HasAlignValT = !HasSizeT;
}
@@ -1408,6 +1434,12 @@ namespace {
bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize,
bool WantAlign) const {
+ // C++ P0722:
+ // A destroying operator delete is preferred over a non-destroying
+ // operator delete.
+ if (Destroying != Other.Destroying)
+ return Destroying;
+
// C++17 [expr.delete]p10:
// If the type has new-extended alignment, a function with a parameter
// of type std::align_val_t is preferred; otherwise a function without
@@ -1424,7 +1456,7 @@ namespace {
DeclAccessPair Found;
FunctionDecl *FD;
- bool HasSizeT, HasAlignValT;
+ bool Destroying, HasSizeT, HasAlignValT;
Sema::CUDAFunctionPreference CUDAPref;
};
}
@@ -1590,20 +1622,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,
@@ -1636,6 +1656,31 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
return false;
}
+// Emit a diagnostic if an aligned allocation/deallocation function that is not
+// implemented in the standard library is selected.
+static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
+ SourceLocation Loc, bool IsDelete,
+ Sema &S) {
+ if (!S.getLangOpts().AlignedAllocationUnavailable)
+ return;
+
+ // Return if there is a definition.
+ if (FD.isDefined())
+ return;
+
+ bool IsAligned = false;
+ if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) {
+ const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple();
+ StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling(
+ S.getASTContext().getTargetInfo().getPlatformName());
+
+ S.Diag(Loc, diag::warn_aligned_allocation_unavailable)
+ << IsDelete << FD.getType().getAsString() << OSName
+ << alignedAllocMinVersion(T.getOS()).getAsString();
+ S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable);
+ }
+}
+
ExprResult
Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceLocation PlacementLParen,
@@ -2013,11 +2058,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (DiagnoseUseOfDecl(OperatorNew, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorNew);
+ diagnoseUnavailableAlignedAllocation(*OperatorNew, StartLoc, false, *this);
}
if (OperatorDelete) {
if (DiagnoseUseOfDecl(OperatorDelete, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorDelete);
+ diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this);
}
// C++0x [expr.new]p17:
@@ -2066,9 +2113,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() != LangAS::Default)
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);
@@ -2619,7 +2667,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
- Func->setHidden(false);
+ Func->setVisibleDespiteOwningModule();
return;
}
}
@@ -2650,6 +2698,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Context, GlobalCtx, SourceLocation(), SourceLocation(), Name,
FnType, /*TInfo=*/nullptr, SC_None, false, true);
Alloc->setImplicit();
+ // Global allocation functions should always be visible.
+ Alloc->setVisibleDespiteOwningModule();
// Implicit sized deallocation functions always have default visibility.
Alloc->addAttr(
@@ -3135,10 +3185,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() != LangAS::Default)
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()) {
@@ -3222,13 +3273,30 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
MarkFunctionReferenced(StartLoc, OperatorDelete);
- // Check access and ambiguity of operator delete and destructor.
+ // Check access and ambiguity of destructor if we're going to call it.
+ // Note that this is required even for a virtual delete.
+ bool IsVirtualDelete = false;
if (PointeeRD) {
if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
- CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor,
- PDiag(diag::err_access_dtor) << PointeeElem);
+ CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor,
+ PDiag(diag::err_access_dtor) << PointeeElem);
+ IsVirtualDelete = Dtor->isVirtual();
}
}
+
+ diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true,
+ *this);
+
+ // Convert the operand to the type of the first parameter of operator
+ // delete. This is only necessary if we selected a destroying operator
+ // delete that we are going to call (non-virtually); converting to void*
+ // is trivial and left to AST consumers to handle.
+ QualType ParamType = OperatorDelete->getParamDecl(0)->getType();
+ if (!IsVirtualDelete && !ParamType->getPointeeType()->isVoidType()) {
+ Ex = PerformImplicitConversion(Ex.get(), ParamType, AA_Passing);
+ if (Ex.isInvalid())
+ return ExprError();
+ }
}
CXXDeleteExpr *Result = new (Context) CXXDeleteExpr(
@@ -3242,7 +3310,7 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
bool IsDelete, bool CallCanBeVirtual,
bool WarnOnNonAbstractTypes,
SourceLocation DtorLoc) {
- if (!dtor || dtor->isVirtual() || !CallCanBeVirtual)
+ if (!dtor || dtor->isVirtual() || !CallCanBeVirtual || isUnevaluatedContext())
return;
// C++ [expr.delete]p3:
@@ -3257,6 +3325,12 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr<FinalAttr>())
return;
+ // If the superclass is in a system header, there's nothing that can be done.
+ // The `delete` (where we emit the warning) can be in a system header,
+ // what matters for this warning is where the deleted type is defined.
+ if (getSourceManager().isInSystemHeader(PointeeRD->getLocation()))
+ return;
+
QualType ClassType = dtor->getThisType(Context)->getPointeeType();
if (PointeeRD->isAbstract()) {
// If the class is abstract, we warn by default, because we're
@@ -3744,10 +3818,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);
@@ -3770,8 +3843,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;
@@ -4072,23 +4145,17 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
return true;
- // C++0x [meta.unary.prop] Table 49 requires the following traits to be
- // applied to a complete type.
+ // C++1z [meta.unary.prop]:
+ // remove_all_extents_t<T> shall be a complete type or cv void.
+ case UTT_IsAggregate:
case UTT_IsTrivial:
case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
case UTT_IsPOD:
case UTT_IsLiteral:
-
- case UTT_IsDestructible:
- case UTT_IsNothrowDestructible:
- // Fall-through
-
- // These trait expressions are designed to help implement predicates in
- // [meta.unary.prop] despite not being named the same. They are specified
- // by both GCC and the Embarcadero C++ compiler, and require the complete
- // type due to the overarching C++0x type predicates being implemented
- // requiring the complete type.
+ // Per the GCC type traits documentation, T shall be a complete type, cv void,
+ // or an array of unknown bound. But GCC actually imposes the same constraints
+ // as above.
case UTT_HasNothrowAssign:
case UTT_HasNothrowMoveAssign:
case UTT_HasNothrowConstructor:
@@ -4100,17 +4167,20 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
- // Arrays of unknown bound are expressly allowed.
- QualType ElTy = ArgTy;
- if (ArgTy->isIncompleteArrayType())
- ElTy = S.Context.getAsArrayType(ArgTy)->getElementType();
+ ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
+ LLVM_FALLTHROUGH;
- // The void type is expressly allowed.
- if (ElTy->isVoidType())
+ // C++1z [meta.unary.prop]:
+ // T shall be a complete type, cv void, or an array of unknown bound.
+ case UTT_IsDestructible:
+ case UTT_IsNothrowDestructible:
+ case UTT_IsTriviallyDestructible:
+ case UTT_HasUniqueObjectRepresentations:
+ if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
return true;
return !S.RequireCompleteType(
- Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr);
+ Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
}
}
@@ -4248,6 +4318,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.
@@ -4341,6 +4417,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
!RD->hasNonTrivialCopyAssignment();
return false;
case UTT_IsDestructible:
+ case UTT_IsTriviallyDestructible:
case UTT_IsNothrowDestructible:
// C++14 [meta.unary.prop]:
// For reference types, is_destructible<T>::value is true.
@@ -4358,6 +4435,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (T->isIncompleteType() || T->isFunctionType())
return false;
+ // A type that requires destruction (via a non-trivial destructor or ARC
+ // lifetime semantics) is not trivially-destructible.
+ if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType())
+ return false;
+
// C++14 [meta.unary.prop]:
// For object types and given U equal to remove_all_extents_t<T>, if the
// expression std::declval<U&>().~U() is well-formed when treated as an
@@ -4533,28 +4615,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
// Returns True if and only if T is a complete type at the point of the
// function call.
return !T->isIncompleteType();
+ case UTT_HasUniqueObjectRepresentations:
+ return T.hasUniqueObjectRepresentations(C);
}
}
-/// \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);
@@ -4627,7 +4692,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]));
@@ -4648,10 +4714,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
@@ -4724,10 +4789,24 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
// regard to cv-qualifiers.
const RecordType *lhsRecord = LhsT->getAs<RecordType>();
- if (!lhsRecord) return false;
-
const RecordType *rhsRecord = RhsT->getAs<RecordType>();
- if (!rhsRecord) return false;
+ if (!rhsRecord || !lhsRecord) {
+ const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>();
+ const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>();
+ if (!LHSObjTy || !RHSObjTy)
+ return false;
+
+ ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface();
+ ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface();
+ if (!BaseInterface || !DerivedInterface)
+ return false;
+
+ if (Self.RequireCompleteType(
+ KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr))
+ return false;
+
+ return BaseInterface->isSuperClassOf(DerivedInterface);
+ }
assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT)
== (lhsRecord == rhsRecord));
@@ -4748,9 +4827,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
}
case BTT_IsSame:
return Self.Context.hasSameType(LhsT, RhsT);
- case BTT_TypeCompatible:
- return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(),
- RhsT.getUnqualifiedType());
+ case BTT_TypeCompatible: {
+ // GCC ignores cv-qualifiers on arrays for this builtin.
+ Qualifiers LhsQuals, RhsQuals;
+ QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals);
+ QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals);
+ return Self.Context.typesAreCompatible(Lhs, Rhs);
+ }
case BTT_IsConvertible:
case BTT_IsConvertibleTo: {
// C++0x [meta.rel]p4:
@@ -4804,7 +4887,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);
@@ -4855,7 +4939,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,
@@ -4870,10 +4955,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);
@@ -5094,7 +5178,9 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
// Cast LHS to type of use.
- QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
+ QualType UseType = Context.getQualifiedType(Class, LHSType.getQualifiers());
+ if (isIndirect)
+ UseType = Context.getPointerType(UseType);
ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind();
LHS = ImpCastExprToType(LHS.get(), UseType, CK_DerivedToBase, VK,
&BasePath);
@@ -5128,9 +5214,16 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
break;
case RQ_LValue:
- if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
- Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
- << RHSType << 1 << LHS.get()->getSourceRange();
+ if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+ // C++2a allows functions with ref-qualifier & if they are also 'const'.
+ if (Proto->isConst())
+ Diag(Loc, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+ : diag::ext_pointer_to_const_ref_member_on_rvalue);
+ else
+ Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+ << RHSType << 1 << LHS.get()->getSourceRange();
+ }
break;
case RQ_RValue:
@@ -5271,16 +5364,16 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS
switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) {
case OR_Success: {
// We found a match. Perform the conversions on the arguments and move on.
- ExprResult LHSRes =
- Self.PerformImplicitConversion(LHS.get(), Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], Sema::AA_Converting);
+ ExprResult LHSRes = Self.PerformImplicitConversion(
+ LHS.get(), Best->BuiltinParamTypes[0], Best->Conversions[0],
+ Sema::AA_Converting);
if (LHSRes.isInvalid())
break;
LHS = LHSRes;
- ExprResult RHSRes =
- Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], Sema::AA_Converting);
+ ExprResult RHSRes = Self.PerformImplicitConversion(
+ RHS.get(), Best->BuiltinParamTypes[1], Best->Conversions[1],
+ Sema::AA_Converting);
if (RHSRes.isInvalid())
break;
RHS = RHSRes;
@@ -5345,6 +5438,15 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
+ //
+ // FIXME; GCC's vector extension permits the use of a?b:c where the type of
+ // a is that of a integer vector with the same number of elements and
+ // size as the vectors of b and c. If one of either b or c is a scalar
+ // it is implicitly converted to match the type of the vector.
+ // Otherwise the expression is ill-formed. If both b and c are scalars,
+ // then b and c are checked and converted to the type of a if possible.
+ // Unlike the OpenCL ?: operator, the expression is evaluated as
+ // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
if (!Cond.get()->isTypeDependent()) {
ExprResult CondRes = CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
@@ -6008,9 +6110,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();
}
@@ -6177,7 +6291,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());
}
}
@@ -6766,7 +6880,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);
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index f08bdc5e9c..03ddcc0a3e 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,21 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
}
}
+ // OpenCL mode requires swizzle length to be in accordance with accepted
+ // sizes. Clang however supports arbitrary lengths for other languages.
+ if (S.getLangOpts().OpenCL && !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.
@@ -672,8 +695,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
Sema::RedeclarationKind Redecl;
};
QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(),
- R.isForRedeclaration() ? Sema::ForRedeclaration
- : Sema::NotForRedeclaration};
+ R.redeclarationKind()};
TE = SemaRef.CorrectTypoDelayed(
R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS,
llvm::make_unique<RecordMemberExprValidatorCCC>(RTy),
@@ -980,53 +1002,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
BaseExpr = Converted.get();
}
- LambdaScopeInfo *const CurLSI = getCurLambda();
- // If this is an implicit member reference and the overloaded
- // name refers to both static and non-static member functions
- // (i.e. BaseExpr is null) and if we are currently processing a lambda,
- // check if we should/can capture 'this'...
- // Keep this example in mind:
- // struct X {
- // void f(int) { }
- // static void f(double) { }
- //
- // int g() {
- // auto L = [=](auto a) {
- // return [](int i) {
- // return [=](auto b) {
- // f(b);
- // //f(decltype(a){});
- // };
- // };
- // };
- // auto M = L(0.0);
- // auto N = M(3);
- // N(5.32); // OK, must not error.
- // return 0;
- // }
- // };
- //
- if (!BaseExpr && CurLSI) {
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- DeclContext *EnclosingFunctionCtx = CurContext->getParent()->getParent();
- // If the enclosing function is not dependent, then this lambda is
- // capture ready, so if we can capture this, do so.
- if (!EnclosingFunctionCtx->isDependentContext()) {
- // If the current lambda and all enclosing lambdas can capture 'this' -
- // then go ahead and capture 'this' (since our unresolved overload set
- // contains both static and non-static member functions).
- if (!CheckCXXThisCapture(Loc, /*Explcit*/false, /*Diagnose*/false))
- CheckCXXThisCapture(Loc);
- } else if (CurContext->isDependentContext()) {
- // ... since this is an implicit member reference, that might potentially
- // involve a 'this' capture, mark 'this' for potential capture in
- // enclosing lambdas.
- if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None)
- CurLSI->addPotentialThisCapture(Loc);
- }
- }
+
const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
DeclarationName MemberName = MemberNameInfo.getName();
SourceLocation MemberLoc = MemberNameInfo.getLoc();
@@ -1475,7 +1451,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 +1478,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;
@@ -1817,26 +1791,29 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
MemberType = Context.getQualifiedType(MemberType, Combined);
}
- UnusedPrivateFields.remove(Field);
+ auto *CurMethod = dyn_cast<CXXMethodDecl>(CurContext);
+ if (!(CurMethod && CurMethod->isDefaulted()))
+ UnusedPrivateFields.remove(Field);
ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
- MemberExpr *ME =
- BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
- /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
- MemberNameInfo, MemberType, VK, OK);
// Build a reference to a private copy for non-static data members in
// non-static member functions, privatized by OpenMP constructs.
if (getLangOpts().OpenMP && IsArrow &&
!CurContext->isDependentContext() &&
isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
- if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field))
- return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
+ if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) {
+ return getOpenMPCapturedExpr(PrivateCopy, VK, OK,
+ MemberNameInfo.getLoc());
+ }
}
- return ME;
+
+ return BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
+ /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
+ MemberNameInfo, MemberType, VK, OK);
}
/// Builds an implicit member access expression. The current context
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 67876c261d..369ba64cd9 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -595,7 +595,6 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
break;
}
}
- CheckForIntOverflow(ValueExpr);
// FIXME: Do I need to do anything special with BoolTy expressions?
// Look for the appropriate method within NSNumber.
@@ -2272,7 +2271,8 @@ static void checkFoundationAPI(Sema &S, SourceLocation Loc,
bool IsClassObjectCall) {
// Check if this is a performSelector method that uses a selector that returns
// a record or a vector type.
- if (Method->getMethodFamily() != OMF_performSelector || Args.empty())
+ if (Method->getSelector().getMethodFamily() != OMF_performSelector ||
+ Args.empty())
return;
const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens());
if (!SE)
@@ -2556,6 +2556,24 @@ ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
/*isImplicit=*/true);
}
+static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) {
+ if (!S.NSAPIObj)
+ return false;
+ const auto *Protocol = dyn_cast<ObjCProtocolDecl>(M->getDeclContext());
+ if (!Protocol)
+ return false;
+ const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject);
+ if (const auto *RootClass = dyn_cast_or_null<ObjCInterfaceDecl>(
+ S.LookupSingleName(S.TUScope, II, Protocol->getLocStart(),
+ Sema::LookupOrdinaryName))) {
+ for (const ObjCProtocolDecl *P : RootClass->all_referenced_protocols()) {
+ if (P->getCanonicalDecl() == Protocol->getCanonicalDecl())
+ return true;
+ }
+ }
+ return false;
+}
+
/// \brief Build an Objective-C instance message expression.
///
/// This routine takes care of both normal instance messages and
@@ -2687,6 +2705,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
+ if (ReceiverType->isObjCIdType() && !isImplicit)
+ Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
+
// There's a somewhat weird interaction here where we assume that we
// won't actually have a method unless we also don't need to do some
// of the more detailed type-checking on the receiver.
@@ -2731,7 +2752,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)
@@ -2992,7 +3013,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>()) {
@@ -3082,7 +3102,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 =
@@ -3335,7 +3357,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.
@@ -4088,11 +4110,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
@@ -4132,7 +4153,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
@@ -4218,8 +4244,7 @@ void Sema::diagnoseARCUnbridgedCast(Expr *e) {
castType = cast->getTypeAsWritten();
CCK = CCK_OtherCast;
} else {
- castType = cast->getType();
- CCK = CCK_ImplicitConversion;
+ llvm_unreachable("Unexpected ImplicitCastExpr");
}
ARCConversionTypeClass castACTC =
@@ -4292,14 +4317,37 @@ bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
/// Look for an ObjCReclaimReturnedObject cast and destroy it.
static Expr *maybeUndoReclaimObject(Expr *e) {
- // For now, we just undo operands that are *immediately* reclaim
- // expressions, which prevents the vast majority of potential
- // problems here. To catch them all, we'd need to rebuild arbitrary
- // value-propagating subexpressions --- we can't reliably rebuild
- // in-place because of expression sharing.
- if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
- if (ice->getCastKind() == CK_ARCReclaimReturnedObject)
- return ice->getSubExpr();
+ Expr *curExpr = e, *prevExpr = nullptr;
+
+ // Walk down the expression until we hit an implicit cast of kind
+ // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
+ while (true) {
+ if (auto *pe = dyn_cast<ParenExpr>(curExpr)) {
+ prevExpr = curExpr;
+ curExpr = pe->getSubExpr();
+ continue;
+ }
+
+ if (auto *ce = dyn_cast<CastExpr>(curExpr)) {
+ if (auto *ice = dyn_cast<ImplicitCastExpr>(ce))
+ if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
+ if (!prevExpr)
+ return ice->getSubExpr();
+ if (auto *pe = dyn_cast<ParenExpr>(prevExpr))
+ pe->setSubExpr(ice->getSubExpr());
+ else
+ cast<CastExpr>(prevExpr)->setSubExpr(ice->getSubExpr());
+ return e;
+ }
+
+ prevExpr = curExpr;
+ curExpr = ce->getSubExpr();
+ continue;
+ }
+
+ // Break out of the loop if curExpr is neither a Paren nor a Cast.
+ break;
+ }
return e;
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3970e831c5..dc7fe1d92b 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -826,6 +826,34 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
+/// Determine whether Entity is an entity for which it is idiomatic to elide
+/// the braces in aggregate initialization.
+static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) {
+ // Recursive initialization of the one and only field within an aggregate
+ // class is considered idiomatic. This case arises in particular for
+ // initialization of std::array, where the C++ standard suggests the idiom of
+ //
+ // std::array<T, N> arr = {1, 2, 3};
+ //
+ // (where std::array is an aggregate struct containing a single array field.
+
+ // FIXME: Should aggregate initialization of a struct with a single
+ // base class and no members also suppress the warning?
+ if (Entity.getKind() != InitializedEntity::EK_Member || !Entity.getParent())
+ return false;
+
+ auto *ParentRD =
+ Entity.getParent()->getType()->castAs<RecordType>()->getDecl();
+ if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD))
+ if (CXXRD->getNumBases())
+ return false;
+
+ auto FieldIt = ParentRD->field_begin();
+ assert(FieldIt != ParentRD->field_end() &&
+ "no fields but have initializer for member?");
+ return ++FieldIt == ParentRD->field_end();
+}
+
/// Check whether the range of the initializer \p ParentIList from element
/// \p Index onwards can be used to initialize an object of type \p T. Update
/// \p Index to indicate how many elements of the list were consumed.
@@ -886,7 +914,9 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
}
// Complain about missing braces.
- if (T->isArrayType() || T->isRecordType()) {
+ if ((T->isArrayType() || T->isRecordType()) &&
+ !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
+ !isIdiomaticBraceElisionEntity(Entity)) {
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
diag::warn_missing_braces)
<< StructuredSubobjectInitList->getSourceRange()
@@ -950,6 +980,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");
}
@@ -1208,7 +1239,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
} else {
assert((ElemType->isRecordType() || ElemType->isVectorType() ||
- ElemType->isClkEventT()) && "Unexpected type");
+ ElemType->isOpenCLSpecificType()) && "Unexpected type");
// C99 6.7.8p13:
//
@@ -1832,7 +1863,9 @@ void InitListChecker::CheckStructUnionTypes(
// worthwhile to skip over the rest of the initializer, though.
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
- bool CheckForMissingFields = true;
+ bool CheckForMissingFields =
+ !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
+
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
@@ -2269,15 +2302,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);
@@ -2934,6 +2969,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();
@@ -2963,6 +2999,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:
@@ -2992,6 +3029,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
+ case EK_LambdaToBlockConversionBlockElement:
case EK_LambdaCapture:
case EK_RelatedResult:
break;
@@ -3025,6 +3063,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);
@@ -3112,6 +3153,7 @@ bool InitializationSequence::isAmbiguous() const {
switch (getFailureKind()) {
case FK_TooManyInitsForReference:
+ case FK_ParenthesizedListInitForReference:
case FK_ArrayNeedsInitList:
case FK_ArrayNeedsInitListOrStringLiteral:
case FK_ArrayNeedsInitListOrWideStringLiteral:
@@ -3129,6 +3171,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:
@@ -3520,12 +3563,13 @@ static OverloadingResult
ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
MultiExprArg Args,
OverloadCandidateSet &CandidateSet,
+ QualType DestType,
DeclContext::lookup_result Ctors,
OverloadCandidateSet::iterator &Best,
bool CopyInitializing, bool AllowExplicit,
bool OnlyListConstructors, bool IsListInit,
bool SecondStepOfCopyInit = false) {
- CandidateSet.clear();
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
for (NamedDecl *D : Ctors) {
auto Info = getConstructorInfo(D);
@@ -3576,6 +3620,50 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
}
}
+ // FIXME: Work around a bug in C++17 guaranteed copy elision.
+ //
+ // When initializing an object of class type T by constructor
+ // ([over.match.ctor]) or by list-initialization ([over.match.list])
+ // from a single expression of class type U, conversion functions of
+ // U that convert to the non-reference type cv T are candidates.
+ // Explicit conversion functions are only candidates during
+ // direct-initialization.
+ //
+ // Note: SecondStepOfCopyInit is only ever true in this case when
+ // evaluating whether to produce a C++98 compatibility warning.
+ if (S.getLangOpts().CPlusPlus1z && Args.size() == 1 &&
+ !SecondStepOfCopyInit) {
+ Expr *Initializer = Args[0];
+ auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl();
+ if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) {
+ const auto &Conversions = SourceRD->getVisibleConversionFunctions();
+ for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ D = D->getUnderlyingDecl();
+
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(D);
+
+ if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
+ ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit,
+ /*AllowResultConversion*/false);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ /*AllowResultConversion*/false);
+ }
+ }
+ }
+ }
+
// Perform overload resolution and return the result.
return CandidateSet.BestViableFunction(S, DeclLoc, Best);
}
@@ -3620,9 +3708,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.
@@ -3671,7 +3763,7 @@ static void TryConstructorInitialization(Sema &S,
// the first phase is omitted.
if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor()))
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
- CandidateSet, Ctors, Best,
+ CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructor=*/true,
IsListInit);
@@ -3685,7 +3777,7 @@ static void TryConstructorInitialization(Sema &S,
if (Result == OR_No_Viable_Function) {
AsInitializerList = false;
Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs,
- CandidateSet, Ctors, Best,
+ CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructors=*/false,
IsListInit);
@@ -3698,6 +3790,24 @@ static void TryConstructorInitialization(Sema &S,
return;
}
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
+ // In C++17, ResolveConstructorOverload can select a conversion function
+ // instead of a constructor.
+ if (auto *CD = dyn_cast<CXXConversionDecl>(Best->Function)) {
+ // Add the user-defined conversion step that calls the conversion function.
+ QualType ConvType = CD->getConversionType();
+ assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) &&
+ "should not have selected this conversion function");
+ Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType,
+ HadMultipleCandidates);
+ if (!S.Context.hasSameType(ConvType, DestType))
+ Sequence.AddQualificationConversionStep(DestType, VK_RValue);
+ if (IsListInit)
+ Sequence.RewrapReferenceInitList(Entity.getType(), ILE);
+ return;
+ }
+
// C++11 [dcl.init]p6:
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
@@ -3726,7 +3836,6 @@ static void TryConstructorInitialization(Sema &S,
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
- bool HadMultipleCandidates = (CandidateSet.size() > 1);
Sequence.AddConstructorInitializationStep(
Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates,
IsListInit | IsInitListCopy, AsInitializerList);
@@ -4072,7 +4181,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- CandidateSet.clear();
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
@@ -4158,7 +4267,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
- = CandidateSet.BestViableFunction(S, DeclLoc, Best, true))
+ = CandidateSet.BestViableFunction(S, DeclLoc, Best))
return Result;
FunctionDecl *Function = Best->Function;
@@ -4672,7 +4781,7 @@ static void TryUserDefinedConversion(Sema &S,
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- CandidateSet.clear();
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
@@ -4751,7 +4860,7 @@ static void TryUserDefinedConversion(Sema &S,
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
- = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
+ = CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
Sequence.SetOverloadFailure(
InitializationSequence::FK_UserConversionOverloadFailed,
Result);
@@ -5179,6 +5288,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;
@@ -5344,11 +5459,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.
@@ -5475,6 +5595,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;
@@ -5498,6 +5619,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;
@@ -5524,6 +5646,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;
@@ -5571,6 +5694,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();
@@ -5627,7 +5751,7 @@ static ExprResult CopyObject(Sema &S,
OverloadCandidateSet::iterator Best;
switch (ResolveConstructorOverload(
- S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
+ S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best,
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
/*SecondStepOfCopyInit=*/true)) {
@@ -5767,7 +5891,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
OverloadingResult OR = ResolveConstructorOverload(
- S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
+ S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best,
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
/*SecondStepOfCopyInit=*/true);
@@ -6008,6 +6132,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.
@@ -6096,6 +6221,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:
@@ -6489,6 +6615,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() &&
@@ -6640,6 +6780,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.
@@ -6674,14 +6827,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;
@@ -7165,7 +7314,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;
@@ -7389,6 +7538,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;
@@ -7476,8 +7629,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
- = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best,
- true);
+ = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl == OR_Deleted) {
S.NoteDeletedFunction(Best->Function);
} else {
@@ -7600,6 +7752,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();
@@ -7782,6 +7939,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;
@@ -7866,6 +8027,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;
@@ -8224,11 +8389,59 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
AllowExplicit);
InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList);
+ // Prevent infinite recursion when performing parameter copy-initialization.
+ const bool ShouldTrackCopy =
+ Entity.isParameterKind() && Seq.isConstructorInitialization();
+ if (ShouldTrackCopy) {
+ if (llvm::find(CurrentParameterCopyTypes, Entity.getType()) !=
+ CurrentParameterCopyTypes.end()) {
+ Seq.SetOverloadFailure(
+ InitializationSequence::FK_ConstructorOverloadFailed,
+ OR_No_Viable_Function);
+
+ // Try to give a meaningful diagnostic note for the problematic
+ // constructor.
+ const auto LastStep = Seq.step_end() - 1;
+ assert(LastStep->Kind ==
+ InitializationSequence::SK_ConstructorInitialization);
+ const FunctionDecl *Function = LastStep->Function.Function;
+ auto Candidate =
+ llvm::find_if(Seq.getFailedCandidateSet(),
+ [Function](const OverloadCandidate &Candidate) -> bool {
+ return Candidate.Viable &&
+ Candidate.Function == Function &&
+ Candidate.Conversions.size() > 0;
+ });
+ if (Candidate != Seq.getFailedCandidateSet().end() &&
+ Function->getNumParams() > 0) {
+ Candidate->Viable = false;
+ Candidate->FailureKind = ovl_fail_bad_conversion;
+ Candidate->Conversions[0].setBad(BadConversionSequence::no_conversion,
+ InitE,
+ Function->getParamDecl(0)->getType());
+ }
+ }
+ CurrentParameterCopyTypes.push_back(Entity.getType());
+ }
+
ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE);
+ if (ShouldTrackCopy)
+ CurrentParameterCopyTypes.pop_back();
+
return Result;
}
+/// Determine whether RD is, or is derived from, a specialization of CTD.
+static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD,
+ ClassTemplateDecl *CTD) {
+ auto NotSpecialization = [&] (const CXXRecordDecl *Candidate) {
+ auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Candidate);
+ return !CTSD || !declaresSameEntity(CTSD->getSpecializedTemplate(), CTD);
+ };
+ return !(NotSpecialization(RD) && RD->forallBases(NotSpecialization));
+}
+
QualType Sema::DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Inits) {
@@ -8295,7 +8508,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
OverloadCandidateSet::iterator Best;
auto tryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
- Candidates.clear();
+ Candidates.clear(OverloadCandidateSet::CSK_Normal);
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (D->isInvalidDecl())
@@ -8373,6 +8586,17 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
break;
}
}
+ } else if (ListInit->getNumInits() == 1) {
+ // C++ [over.match.class.deduct]:
+ // As an exception, the first phase in [over.match.list] (considering
+ // initializer-list constructors) is omitted if the initializer list
+ // consists of a single expression of type cv U, where U is a
+ // specialization of C or a class derived from a specialization of C.
+ Expr *E = ListInit->getInit(0);
+ auto *RD = E->getType()->getAsCXXRecordDecl();
+ if (!isa<InitListExpr>(E) && RD &&
+ isOrIsDerivedFromSpecializationOf(RD, Template))
+ TryListConstructors = false;
}
if (TryListConstructors)
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index fc823f4aca..996ed3ea7e 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -288,7 +288,9 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
Normal,
DefaultArgument,
DataMember,
- StaticDataMember
+ StaticDataMember,
+ InlineVariable,
+ VariableTemplate
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
@@ -303,6 +305,14 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
} else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) {
if (Var->getDeclContext()->isRecord())
Kind = StaticDataMember;
+ else if (Var->getMostRecentDecl()->isInline())
+ Kind = InlineVariable;
+ else if (Var->getDescribedVarTemplate())
+ Kind = VariableTemplate;
+ else if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
+ if (!VTS->isExplicitSpecialization())
+ Kind = VariableTemplate;
+ }
} else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
}
@@ -337,11 +347,16 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
return nullptr;
}
// Fall through to get the current context.
+ LLVM_FALLTHROUGH;
case DataMember:
// -- the in-class initializers of class members
case DefaultArgument:
// -- default arguments appearing in class definitions
+ case InlineVariable:
+ // -- the initializers of inline variables
+ case VariableTemplate:
+ // -- the initializers of templated variables
return &ExprEvalContexts.back().getMangleNumberingContext(Context);
}
@@ -763,7 +778,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();
@@ -933,7 +948,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Kind == LCK_This || C->Kind == LCK_StarThis) {
if (C->Kind == LCK_StarThis)
Diag(C->Loc, !getLangOpts().CPlusPlus1z
- ? diag::ext_star_this_lambda_capture_cxx1z
+ ? diag::ext_star_this_lambda_capture_cxx17
: diag::warn_cxx14_compat_star_this_lambda_capture);
// C++11 [expr.prim.lambda]p8:
@@ -947,17 +962,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- // C++1z [expr.prim.lambda]p8:
- // If a lambda-capture includes a capture-default that is =, each
- // simple-capture of that lambda-capture shall be of the form "&
- // identifier" or "* this". [ Note: The form [&,this] is redundant but
- // accepted for compatibility with ISO C++14. --end note ]
- if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) {
- Diag(C->Loc, diag::err_this_capture_with_copy_default)
- << FixItHint::CreateRemoval(
- SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
- continue;
- }
+ // C++2a [expr.prim.lambda]p8:
+ // If a lambda-capture includes a capture-default that is =,
+ // each simple-capture of that lambda-capture shall be of the form
+ // "&identifier", "this", or "* this". [ Note: The form [&,this] is
+ // redundant but accepted for compatibility with ISO C++14. --end note ]
+ if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis)
+ Diag(C->Loc, !getLangOpts().CPlusPlus2a
+ ? diag::ext_equals_this_lambda_capture_cxx2a
+ : diag::warn_cxx17_compat_equals_this_lambda_capture);
// C++11 [expr.prim.lambda]p12:
// If this is captured by a local lambda expression, its nearest
@@ -1127,7 +1140,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,
@@ -1490,6 +1504,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
bool ExplicitResultType;
CleanupInfo LambdaCleanup;
bool ContainsUnexpandedParameterPack;
+ bool IsGenericLambda;
{
CallOperator = LSI->CallOperator;
Class = LSI->Lambda;
@@ -1498,7 +1513,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
ExplicitResultType = !LSI->HasImplicitReturnType;
LambdaCleanup = LSI->Cleanup;
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
-
+ IsGenericLambda = Class->isGenericLambda();
+
CallOperator->setLexicalDeclContext(Class);
Decl *TemplateOrNonTemplateCallOperatorDecl =
CallOperator->getDescribedFunctionTemplate()
@@ -1518,8 +1534,13 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
bool IsImplicit = I >= LSI->NumExplicitCaptures;
// Warn about unused explicit captures.
- if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed())
- DiagnoseUnusedLambdaCapture(From);
+ if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
+ // Initialized captures that are non-ODR used may not be eliminated.
+ bool NonODRUsedInitCapture =
+ IsGenericLambda && From.isNonODRUsed() && From.getInitExpr();
+ if (!NonODRUsedInitCapture)
+ DiagnoseUnusedLambdaCapture(From);
+ }
// Handle 'this' capture.
if (From.isThisCapture()) {
@@ -1566,8 +1587,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// same parameter and return types as the closure type's function call
// operator.
// FIXME: Fix generic lambda to block conversions.
- if (getLangOpts().Blocks && getLangOpts().ObjC1 &&
- !Class->isGenericLambda())
+ if (getLangOpts().Blocks && getLangOpts().ObjC1 && !IsGenericLambda)
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
@@ -1587,9 +1607,10 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
ContainsUnexpandedParameterPack);
// If the lambda expression's call operator is not explicitly marked constexpr
// and we are not in a dependent context, analyze the call operator to infer
- // its constexpr-ness, supressing diagnostics while doing so.
+ // its constexpr-ness, suppressing diagnostics while doing so.
if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() &&
!CallOperator->isConstexpr() &&
+ !isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
!Class->getDeclContext()->isDependentContext()) {
TentativeAnalysisScope DiagnosticScopeGuard(*this);
CallOperator->setConstexpr(
@@ -1605,9 +1626,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
@@ -1617,16 +1638,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;
}
}
@@ -1648,10 +1669,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 e393f905bb..d3f91a4e27 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -88,13 +88,15 @@ namespace {
/// A collection of using directives, as used by C++ unqualified
/// lookup.
class UnqualUsingDirectiveSet {
+ Sema &SemaRef;
+
typedef SmallVector<UnqualUsingEntry, 8> ListTy;
ListTy list;
llvm::SmallPtrSet<DeclContext*, 8> visited;
public:
- UnqualUsingDirectiveSet() {}
+ UnqualUsingDirectiveSet(Sema &SemaRef) : SemaRef(SemaRef) {}
void visitScopeChain(Scope *S, Scope *InnermostFileScope) {
// C++ [namespace.udir]p1:
@@ -113,7 +115,8 @@ namespace {
visit(Ctx, Ctx);
} else if (!Ctx || Ctx->isFunctionOrMethod()) {
for (auto *I : S->using_directives())
- visit(I, InnermostFileDC);
+ if (SemaRef.isVisible(I))
+ visit(I, InnermostFileDC);
}
}
}
@@ -152,7 +155,7 @@ namespace {
while (true) {
for (auto UD : DC->using_directives()) {
DeclContext *NS = UD->getNominatedNamespace();
- if (visited.insert(NS).second) {
+ if (SemaRef.isVisible(UD) && visited.insert(NS).second) {
addUsingDirective(UD, EffectiveDC);
queue.push_back(NS);
}
@@ -838,9 +841,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *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;
@@ -864,6 +865,16 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
if (!Record->isCompleteDefinition())
return Found;
+ // For conversion operators, 'operator auto' should only match
+ // 'operator auto'. Since 'auto' is not a type, it shouldn't be considered
+ // as a candidate for template substitution.
+ auto *ContainedDeducedType =
+ R.getLookupName().getCXXNameType()->getContainedDeducedType();
+ if (R.getLookupName().getNameKind() ==
+ DeclarationName::CXXConversionFunctionName &&
+ ContainedDeducedType && ContainedDeducedType->isUndeducedType())
+ return Found;
+
for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(),
UEnd = Record->conversion_end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
@@ -1023,7 +1034,8 @@ struct FindLocalExternScope {
FindLocalExternScope(LookupResult &R)
: R(R), OldFindLocalExtern(R.getIdentifierNamespace() &
Decl::IDNS_LocalExtern) {
- R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary);
+ R.setFindLocalExtern(R.getIdentifierNamespace() &
+ (Decl::IDNS_Ordinary | Decl::IDNS_NonMemberOperator));
}
void restore() {
R.setFindLocalExtern(OldFindLocalExtern);
@@ -1076,7 +1088,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// }
// }
//
- UnqualUsingDirectiveSet UDirs;
+ UnqualUsingDirectiveSet UDirs(*this);
bool VisitedUsingDirectives = false;
bool LeftStartingScope = false;
DeclContext *OutsideOfTemplateParamDC = nullptr;
@@ -1328,80 +1340,18 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return !R.empty();
}
-/// \brief Find the declaration that a class temploid member specialization was
-/// instantiated from, or the member itself if it is an explicit specialization.
-static Decl *getInstantiatedFrom(Decl *D, MemberSpecializationInfo *MSInfo) {
- return MSInfo->isExplicitSpecialization() ? D : MSInfo->getInstantiatedFrom();
-}
-
-Module *Sema::getOwningModule(Decl *Entity) {
- // If it's imported, grab its owning module.
- Module *M = Entity->getImportedOwningModule();
- if (M || !isa<NamedDecl>(Entity) || !cast<NamedDecl>(Entity)->isHidden())
- return M;
- assert(!Entity->isFromASTFile() &&
- "hidden entity from AST file has no owning module");
-
- if (!getLangOpts().ModulesLocalVisibility) {
- // If we're not tracking visibility locally, the only way a declaration
- // can be hidden and local is if it's hidden because it's parent is (for
- // instance, maybe this is a lazily-declared special member of an imported
- // class).
- auto *Parent = cast<NamedDecl>(Entity->getDeclContext());
- assert(Parent->isHidden() && "unexpectedly hidden decl");
- return getOwningModule(Parent);
- }
-
- // It's local and hidden; grab or compute its owning module.
- M = Entity->getLocalOwningModule();
- if (M)
- return M;
-
- if (auto *Containing =
- PP.getModuleContainingLocation(Entity->getLocation())) {
- M = Containing;
- } else if (Entity->isInvalidDecl() || Entity->getLocation().isInvalid()) {
- // Don't bother tracking visibility for invalid declarations with broken
- // locations.
- cast<NamedDecl>(Entity)->setHidden(false);
- } else {
- // We need to assign a module to an entity that exists outside of any
- // module, so that we can hide it from modules that we textually enter.
- // Invent a fake module for all such entities.
- if (!CachedFakeTopLevelModule) {
- CachedFakeTopLevelModule =
- PP.getHeaderSearchInfo().getModuleMap().findOrCreateModule(
- "<top-level>", nullptr, false, false).first;
-
- auto &SrcMgr = PP.getSourceManager();
- SourceLocation StartLoc =
- SrcMgr.getLocForStartOfFile(SrcMgr.getMainFileID());
- auto &TopLevel = ModuleScopes.empty()
- ? VisibleModules
- : ModuleScopes[0].OuterVisibleModules;
- TopLevel.setVisible(CachedFakeTopLevelModule, StartLoc);
- }
-
- M = CachedFakeTopLevelModule;
- }
-
- if (M)
- Entity->setLocalOwningModule(M);
- return M;
-}
-
-void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) {
- if (auto *M = PP.getModuleContainingLocation(Loc))
+void Sema::makeMergedDefinitionVisible(NamedDecl *ND) {
+ if (auto *M = getCurrentModule())
Context.mergeDefinitionIntoModule(ND, M);
else
// We're not building a module; just make the definition visible.
- ND->setHidden(false);
+ ND->setVisibleDespiteOwningModule();
// If ND is a template declaration, make the template parameters
// visible too. They're not (necessarily) within a mergeable DeclContext.
if (auto *TD = dyn_cast<TemplateDecl>(ND))
for (auto *Param : *TD->getTemplateParameters())
- makeMergedDefinitionVisible(Param, Loc);
+ makeMergedDefinitionVisible(Param);
}
/// \brief Find the module in which the given declaration was defined.
@@ -1415,17 +1365,16 @@ static Module *getDefiningModule(Sema &S, Decl *Entity) {
if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern())
Entity = Pattern;
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(Entity)) {
- if (MemberSpecializationInfo *MSInfo = ED->getMemberSpecializationInfo())
- Entity = getInstantiatedFrom(ED, MSInfo);
+ if (auto *Pattern = ED->getTemplateInstantiationPattern())
+ Entity = Pattern;
} else if (VarDecl *VD = dyn_cast<VarDecl>(Entity)) {
- // FIXME: Map from variable template specializations back to the template.
- if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo())
- Entity = getInstantiatedFrom(VD, MSInfo);
+ if (VarDecl *Pattern = VD->getTemplateInstantiationPattern())
+ Entity = Pattern;
}
// Walk up to the containing context. That might also have been instantiated
// from a template.
- DeclContext *Context = Entity->getDeclContext();
+ DeclContext *Context = Entity->getLexicalDeclContext();
if (Context->isFileContext())
return S.getOwningModule(Entity);
return getDefiningModule(S, cast<Decl>(Context));
@@ -1450,6 +1399,20 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {
return false;
}
+bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) {
+ // FIXME: When not in local visibility mode, we can't tell the difference
+ // between a declaration being visible because we merged a local copy of
+ // the same declaration into it, and it being visible because its owning
+ // module is visible.
+ if (Def->getModuleOwnershipKind() == Decl::ModuleOwnershipKind::Visible &&
+ getLangOpts().ModulesLocalVisibility)
+ return true;
+ for (Module *Merged : Context.getModulesWithMergedDefinition(Def))
+ if (Merged->getTopLevelModuleName() == getLangOpts().CurrentModule)
+ return true;
+ return false;
+}
+
template<typename ParmDecl>
static bool
hasVisibleDefaultArgument(Sema &S, const ParmDecl *D,
@@ -1485,11 +1448,46 @@ bool Sema::hasVisibleDefaultArgument(const NamedDecl *D,
Modules);
}
+template<typename Filter>
+static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules,
+ Filter F) {
+ for (auto *Redecl : D->redecls()) {
+ auto *R = cast<NamedDecl>(Redecl);
+ if (!F(R))
+ continue;
+
+ if (S.isVisible(R))
+ return true;
+
+ if (Modules) {
+ Modules->push_back(R->getOwningModule());
+ const auto &Merged = S.Context.getModulesWithMergedDefinition(R);
+ Modules->insert(Modules->end(), Merged.begin(), Merged.end());
+ }
+ }
+
+ return false;
+}
+
+bool Sema::hasVisibleExplicitSpecialization(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ return RD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+ llvm_unreachable("unknown explicit specialization kind");
+ });
+}
+
bool Sema::hasVisibleMemberSpecialization(
const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
assert(isa<CXXRecordDecl>(D->getDeclContext()) &&
"not a member specialization");
- for (auto *Redecl : D->redecls()) {
+ return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) {
// If the specialization is declared at namespace scope, then it's a member
// specialization declaration. If it's lexically inside the class
// definition then it was instantiated.
@@ -1497,19 +1495,8 @@ bool Sema::hasVisibleMemberSpecialization(
// FIXME: This is a hack. There should be a better way to determine this.
// FIXME: What about MS-style explicit specializations declared within a
// class definition?
- if (Redecl->getLexicalDeclContext()->isFileContext()) {
- auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl));
-
- if (isVisible(NonConstR))
- return true;
-
- if (Modules) {
- Modules->push_back(getOwningModule(NonConstR));
- const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR);
- Modules->insert(Modules->end(), Merged.begin(), Merged.end());
- }
- }
- }
+ return D->getLexicalDeclContext()->isFileContext();
+ });
return false;
}
@@ -1524,30 +1511,42 @@ bool Sema::hasVisibleMemberSpecialization(
/// your module can see, including those later on in your module).
bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
assert(D->isHidden() && "should not call this: not in slow case");
- Module *DeclModule = nullptr;
-
- if (SemaRef.getLangOpts().ModulesLocalVisibility) {
- DeclModule = SemaRef.getOwningModule(D);
- if (!DeclModule) {
- // getOwningModule() may have decided the declaration should not be hidden.
- assert(!D->isHidden() && "hidden decl not from a module");
- return true;
- }
+ Module *DeclModule = SemaRef.getOwningModule(D);
+ if (!DeclModule) {
+ // A module-private declaration with no owning module means this is in the
+ // global module in the C++ Modules TS. This is visible within the same
+ // translation unit only.
+ // FIXME: Don't assume that "same translation unit" means the same thing
+ // as "not from an AST file".
+ assert(D->isModulePrivate() && "hidden decl has no module");
+ if (!D->isFromASTFile() || SemaRef.hasMergedDefinitionInCurrentModule(D))
+ return true;
+ } else {
// If the owning module is visible, and the decl is not module private,
// then the decl is visible too. (Module private is ignored within the same
// top-level module.)
- if ((!D->isFromASTFile() || !D->isModulePrivate()) &&
- (SemaRef.isModuleVisible(DeclModule) ||
- SemaRef.hasVisibleMergedDefinition(D)))
+ if (D->isModulePrivate()
+ ? DeclModule->getTopLevelModuleName() ==
+ SemaRef.getLangOpts().CurrentModule ||
+ SemaRef.hasMergedDefinitionInCurrentModule(D)
+ : SemaRef.isModuleVisible(DeclModule) ||
+ SemaRef.hasVisibleMergedDefinition(D))
return true;
}
- // If this declaration is not at namespace scope nor module-private,
+ // Determine whether a decl context is a file context for the purpose of
+ // visibility. This looks through some (export and linkage spec) transparent
+ // contexts, but not others (enums).
+ auto IsEffectivelyFileContext = [](const DeclContext *DC) {
+ return DC->isFileContext() || isa<LinkageSpecDecl>(DC) ||
+ isa<ExportDecl>(DC);
+ };
+
+ // If this declaration is not at namespace scope
// then it is visible if its lexical parent has a visible definition.
DeclContext *DC = D->getLexicalDeclContext();
- if (!D->isModulePrivate() && DC && !DC->isFileContext() &&
- !isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC)) {
+ if (DC && !IsEffectivelyFileContext(DC)) {
// For a parameter, check whether our current template declaration's
// lexical context is visible, not whether there's some other visible
// definition of it, because parameters aren't "within" the definition.
@@ -1555,32 +1554,45 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
// In C++ we need to check for a visible definition due to ODR merging,
// and in C we must not because each declaration of a function gets its own
// set of declarations for tags in prototype scope.
- if ((D->isTemplateParameter() || isa<ParmVarDecl>(D)
- || (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
- ? isVisible(SemaRef, cast<NamedDecl>(DC))
- : SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) {
- if (SemaRef.CodeSynthesisContexts.empty() &&
- // FIXME: Do something better in this case.
- !SemaRef.getLangOpts().ModulesLocalVisibility) {
- // Cache the fact that this declaration is implicitly visible because
- // its parent has a visible definition.
- D->setHidden(false);
- }
- return true;
+ bool VisibleWithinParent;
+ if (D->isTemplateParameter() || isa<ParmVarDecl>(D) ||
+ (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
+ VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC));
+ else if (D->isModulePrivate()) {
+ // A module-private declaration is only visible if an enclosing lexical
+ // parent was merged with another definition in the current module.
+ VisibleWithinParent = false;
+ do {
+ if (SemaRef.hasMergedDefinitionInCurrentModule(cast<NamedDecl>(DC))) {
+ VisibleWithinParent = true;
+ break;
+ }
+ DC = DC->getLexicalParent();
+ } while (!IsEffectivelyFileContext(DC));
+ } else {
+ VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC));
}
- return false;
+
+ if (VisibleWithinParent && SemaRef.CodeSynthesisContexts.empty() &&
+ // FIXME: Do something better in this case.
+ !SemaRef.getLangOpts().ModulesLocalVisibility) {
+ // Cache the fact that this declaration is implicitly visible because
+ // its parent has a visible definition.
+ D->setVisibleDespiteOwningModule();
+ }
+ return VisibleWithinParent;
}
+ // FIXME: All uses of DeclModule below this point should also check merged
+ // modules.
+ if (!DeclModule)
+ return false;
+
// Find the extra places where we need to look.
llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules();
if (LookupModules.empty())
return false;
- if (!DeclModule) {
- DeclModule = SemaRef.getOwningModule(D);
- assert(DeclModule && "hidden decl not from a module");
- }
-
// If our lookup set contains the decl's module, it's visible.
if (LookupModules.count(DeclModule))
return true;
@@ -1600,11 +1612,39 @@ bool Sema::isVisibleSlow(const NamedDecl *D) {
}
bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) {
+ // FIXME: If there are both visible and hidden declarations, we need to take
+ // into account whether redeclaration is possible. Example:
+ //
+ // Non-imported module:
+ // int f(T); // #1
+ // Some TU:
+ // static int f(U); // #2, not a redeclaration of #1
+ // int f(T); // #3, finds both, should link with #1 if T != U, but
+ // // with #2 if T == U; neither should be ambiguous.
for (auto *D : R) {
if (isVisible(D))
return true;
+ assert(D->isExternallyDeclarable() &&
+ "should not have hidden, non-externally-declarable result here");
}
- return New->isExternallyVisible();
+
+ // This function is called once "New" is essentially complete, but before a
+ // previous declaration is attached. We can't query the linkage of "New" in
+ // general, because attaching the previous declaration can change the
+ // linkage of New to match the previous declaration.
+ //
+ // However, because we've just determined that there is no *visible* prior
+ // declaration, we can compute the linkage here. There are two possibilities:
+ //
+ // * This is not a redeclaration; it's safe to compute the linkage now.
+ //
+ // * This is a redeclaration of a prior declaration that is externally
+ // redeclarable. In that case, the linkage of the declaration is not
+ // changed by attaching the prior declaration, because both are externally
+ // declarable (and thus ExternalLinkage or VisibleNoLinkage).
+ //
+ // FIXME: This is subtle and fragile.
+ return New->isExternallyDeclarable();
}
/// \brief Retrieve the visible declaration corresponding to D, if any.
@@ -1637,20 +1677,8 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D,
llvm::SmallVectorImpl<Module *> *Modules) {
assert(!isVisible(D) && "not in slow case");
-
- for (auto *Redecl : D->redecls()) {
- auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl));
- if (isVisible(NonConstR))
- return true;
-
- if (Modules) {
- Modules->push_back(getOwningModule(NonConstR));
- const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR);
- Modules->insert(Modules->end(), Merged.begin(), Merged.end());
- }
- }
-
- return false;
+ return hasVisibleDeclarationImpl(*this, D, Modules,
+ [](const NamedDecl *) { return true; });
}
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
@@ -1843,22 +1871,19 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
DeclContext *StartDC) {
assert(StartDC->isFileContext() && "start context is not a file context");
- DeclContext::udir_range UsingDirectives = StartDC->using_directives();
- if (UsingDirectives.begin() == UsingDirectives.end()) return false;
+ // We have not yet looked into these namespaces, much less added
+ // their "using-children" to the queue.
+ SmallVector<NamespaceDecl*, 8> Queue;
// We have at least added all these contexts to the queue.
llvm::SmallPtrSet<DeclContext*, 8> Visited;
Visited.insert(StartDC);
- // We have not yet looked into these namespaces, much less added
- // their "using-children" to the queue.
- SmallVector<NamespaceDecl*, 8> Queue;
-
// We have already looked into the initial namespace; seed the queue
// with its using-children.
- for (auto *I : UsingDirectives) {
+ for (auto *I : StartDC->using_directives()) {
NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace();
- if (Visited.insert(ND).second)
+ if (S.isVisible(I) && Visited.insert(ND).second)
Queue.push_back(ND);
}
@@ -1906,7 +1931,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
for (auto I : ND->using_directives()) {
NamespaceDecl *Nom = I->getNominatedNamespace();
- if (Visited.insert(Nom).second)
+ if (S.isVisible(I) && Visited.insert(Nom).second)
Queue.push_back(Nom);
}
}
@@ -2652,6 +2677,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
for (const auto &Arg : Proto->param_types())
Queue.push_back(Arg.getTypePtr());
// fallthrough
+ LLVM_FALLTHROUGH;
}
case Type::FunctionNoProto: {
const FunctionType *FnType = cast<FunctionType>(T);
@@ -3124,7 +3150,7 @@ Sema::LiteralOperatorLookupResult
Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
ArrayRef<QualType> ArgTys,
bool AllowRaw, bool AllowTemplate,
- bool AllowStringTemplate) {
+ bool AllowStringTemplate, bool DiagnoseMissing) {
LookupName(R, S);
assert(R.getResultKind() != LookupResult::Ambiguous &&
"literal operator lookup can't be ambiguous");
@@ -3225,11 +3251,15 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
return LOLR_StringTemplate;
// Didn't find anything we could use.
- Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator)
- << R.getLookupName() << (int)ArgTys.size() << ArgTys[0]
- << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw
- << (AllowTemplate || AllowStringTemplate);
- return LOLR_Error;
+ if (DiagnoseMissing) {
+ Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator)
+ << R.getLookupName() << (int)ArgTys.size() << ArgTys[0]
+ << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw
+ << (AllowTemplate || AllowStringTemplate);
+ return LOLR_Error;
+ }
+
+ return LOLR_ErrorNoDiagnostic;
}
void ADLResult::insert(NamedDecl *New) {
@@ -3319,16 +3349,24 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
continue;
}
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
+ auto *Underlying = D;
+ if (auto *USD = dyn_cast<UsingShadowDecl>(D))
+ Underlying = USD->getTargetDecl();
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D))
+ if (!isa<FunctionDecl>(Underlying) &&
+ !isa<FunctionTemplateDecl>(Underlying))
continue;
- if (!isVisible(D) && !(D = findAcceptableDecl(*this, D)))
- continue;
+ if (!isVisible(D)) {
+ D = findAcceptableDecl(*this, D);
+ if (!D)
+ continue;
+ if (auto *USD = dyn_cast<UsingShadowDecl>(D))
+ Underlying = USD->getTargetDecl();
+ }
- Result.insert(D);
+ // FIXME: Preserve D as the FoundDecl.
+ Result.insert(Underlying);
}
}
}
@@ -3454,7 +3492,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
bool QualifiedNameLookup,
bool InBaseClass,
VisibleDeclConsumer &Consumer,
- VisibleDeclsRecord &Visited) {
+ VisibleDeclsRecord &Visited,
+ bool IncludeDependentBases = false) {
if (!Ctx)
return;
@@ -3509,8 +3548,11 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
for (auto I : Ctx->using_directives()) {
+ if (!Result.getSema().isVisible(I))
+ continue;
LookupVisibleDecls(I->getNominatedNamespace(), Result,
- QualifiedNameLookup, InBaseClass, Consumer, Visited);
+ QualifiedNameLookup, InBaseClass, Consumer, Visited,
+ IncludeDependentBases);
}
}
@@ -3522,14 +3564,28 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
for (const auto &B : Record->bases()) {
QualType BaseType = B.getType();
- // Don't look into dependent bases, because name lookup can't look
- // there anyway.
- if (BaseType->isDependentType())
- continue;
-
- const RecordType *Record = BaseType->getAs<RecordType>();
- if (!Record)
- continue;
+ RecordDecl *RD;
+ if (BaseType->isDependentType()) {
+ if (!IncludeDependentBases) {
+ // Don't look into dependent bases, because name lookup can't look
+ // there anyway.
+ continue;
+ }
+ const auto *TST = BaseType->getAs<TemplateSpecializationType>();
+ if (!TST)
+ continue;
+ TemplateName TN = TST->getTemplateName();
+ const auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ continue;
+ RD = TD->getTemplatedDecl();
+ } else {
+ const auto *Record = BaseType->getAs<RecordType>();
+ if (!Record)
+ continue;
+ RD = Record->getDecl();
+ }
// FIXME: It would be nice to be able to determine whether referencing
// a particular member would be ambiguous. For example, given
@@ -3552,8 +3608,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Find results in this base class (and its bases).
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup,
- true, Consumer, Visited);
+ LookupVisibleDecls(RD, Result, QualifiedNameLookup, true, Consumer,
+ Visited, IncludeDependentBases);
}
}
@@ -3621,8 +3677,10 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
!Visited.alreadyVisitedContext(S->getEntity())) ||
(S->getEntity())->isFunctionOrMethod()) {
FindLocalExternScope FindLocals(Result);
- // Walk through the declarations in this Scope.
- for (auto *D : S->decls()) {
+ // Walk through the declarations in this Scope. The consumer might add new
+ // decls to the scope as part of deserialization, so make a copy first.
+ SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end());
+ for (Decl *D : ScopeDecls) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
if ((ND = Result.getAcceptableDecl(ND))) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false);
@@ -3700,7 +3758,7 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
// Determine the set of using directives available during
// unqualified name lookup.
Scope *Initial = S;
- UnqualUsingDirectiveSet UDirs;
+ UnqualUsingDirectiveSet UDirs(*this);
if (getLangOpts().CPlusPlus) {
// Find the first namespace or translation-unit scope.
while (S && !isNamespaceOrTranslationUnitScope(S))
@@ -3722,7 +3780,8 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
- bool IncludeGlobalScope) {
+ bool IncludeGlobalScope,
+ bool IncludeDependentBases) {
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
Result.setAllowHidden(Consumer.includeHiddenDecls());
VisibleDeclsRecord Visited;
@@ -3730,7 +3789,8 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
Visited.visitedContext(Context.getTranslationUnitDecl());
ShadowContextRAII Shadow(Visited);
::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
- /*InBaseClass=*/false, Consumer, Visited);
+ /*InBaseClass=*/false, Consumer, Visited,
+ IncludeDependentBases);
}
/// LookupOrCreateLabel - Do a name lookup of a label with the specified name.
@@ -3786,20 +3846,19 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
bool FindHidden);
/// \brief Check whether the declarations found for a typo correction are
-/// visible, and if none of them are, convert the correction to an 'import
-/// a module' correction.
+/// visible. Set the correction's RequiresImport flag to true if none of the
+/// declarations are visible, false otherwise.
static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) {
- if (TC.begin() == TC.end())
- return;
-
TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end();
for (/**/; DI != DE; ++DI)
if (!LookupResult::isVisible(SemaRef, *DI))
break;
- // Nothing to do if all decls are visible.
- if (DI == DE)
+ // No filtering needed if all decls are visible.
+ if (DI == DE) {
+ TC.setRequiresImport(false);
return;
+ }
llvm::SmallVector<NamedDecl*, 4> NewDecls(TC.begin(), DI);
bool AnyVisibleDecls = !NewDecls.empty();
@@ -4969,8 +5028,6 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
MissingImportKind MIK, bool Recover) {
- assert(!isVisible(Decl) && "missing import for non-hidden decl?");
-
// Suggest importing a module providing the definition of this entity, if
// possible.
NamedDecl *Def = getDefinitionToImport(Decl);
@@ -5005,6 +5062,14 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
MissingImportKind MIK, bool Recover) {
assert(!Modules.empty());
+ // Weed out duplicates from module list.
+ llvm::SmallVector<Module*, 8> UniqueModules;
+ llvm::SmallDenseSet<Module*, 8> UniqueModuleSet;
+ for (auto *M : Modules)
+ if (UniqueModuleSet.insert(M).second)
+ UniqueModules.push_back(M);
+ Modules = UniqueModules;
+
if (Modules.size() > 1) {
std::string ModuleList;
unsigned N = 0;
@@ -5019,8 +5084,8 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
Diag(UseLoc, diag::err_module_unimported_use_multiple)
<< (int)MIK << Decl << ModuleList;
- } else if (const FileEntry *E =
- PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) {
+ } else if (const FileEntry *E = PP.getModuleHeaderToIncludeForDiagnostics(
+ UseLoc, Modules[0], DeclLoc)) {
// The right way to make the declaration visible is to include a header;
// suggest doing so.
//
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 3481b82679..ea5b1da46f 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));
@@ -806,53 +814,185 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
}
-/// DiagnosePropertyMismatchDeclInProtocols - diagnose properties declared
-/// in inherited protocols with mismatched types. Since any of them can
-/// be candidate for synthesis.
-static void
-DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,
+static bool
+isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,
+ ObjCPropertyDecl::PropertyAttributeKind Kind) {
+ return (Attr1 & Kind) != (Attr2 & Kind);
+}
+
+static bool areIncompatiblePropertyAttributes(unsigned Attr1, unsigned Attr2,
+ unsigned Kinds) {
+ return ((Attr1 & Kinds) != 0) != ((Attr2 & Kinds) != 0);
+}
+
+/// SelectPropertyForSynthesisFromProtocols - Finds the most appropriate
+/// property declaration that should be synthesised in all of the inherited
+/// protocols. It also diagnoses properties declared in inherited protocols with
+/// mismatched types or attributes, since any of them can be candidate for
+/// synthesis.
+static ObjCPropertyDecl *
+SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc,
ObjCInterfaceDecl *ClassDecl,
ObjCPropertyDecl *Property) {
- ObjCInterfaceDecl::ProtocolPropertyMap PropMap;
+ assert(isa<ObjCProtocolDecl>(Property->getDeclContext()) &&
+ "Expected a property from a protocol");
+ ObjCInterfaceDecl::ProtocolPropertySet ProtocolSet;
+ ObjCInterfaceDecl::PropertyDeclOrder Properties;
for (const auto *PI : ClassDecl->all_referenced_protocols()) {
if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
- PDecl->collectInheritedProtocolProperties(Property, PropMap);
+ PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
+ Properties);
}
- if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass())
+ if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass()) {
while (SDecl) {
for (const auto *PI : SDecl->all_referenced_protocols()) {
if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
- PDecl->collectInheritedProtocolProperties(Property, PropMap);
+ PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
+ Properties);
}
SDecl = SDecl->getSuperClass();
}
-
- if (PropMap.empty())
- return;
-
+ }
+
+ if (Properties.empty())
+ return Property;
+
+ ObjCPropertyDecl *OriginalProperty = Property;
+ size_t SelectedIndex = 0;
+ for (const auto &Prop : llvm::enumerate(Properties)) {
+ // Select the 'readwrite' property if such property exists.
+ if (Property->isReadOnly() && !Prop.value()->isReadOnly()) {
+ Property = Prop.value();
+ SelectedIndex = Prop.index();
+ }
+ }
+ if (Property != OriginalProperty) {
+ // Check that the old property is compatible with the new one.
+ Properties[SelectedIndex] = OriginalProperty;
+ }
+
QualType RHSType = S.Context.getCanonicalType(Property->getType());
- bool FirsTime = true;
- for (ObjCInterfaceDecl::ProtocolPropertyMap::iterator
- I = PropMap.begin(), E = PropMap.end(); I != E; I++) {
- ObjCPropertyDecl *Prop = I->second;
+ unsigned OriginalAttributes = Property->getPropertyAttributesAsWritten();
+ enum MismatchKind {
+ IncompatibleType = 0,
+ HasNoExpectedAttribute,
+ HasUnexpectedAttribute,
+ DifferentGetter,
+ DifferentSetter
+ };
+ // Represents a property from another protocol that conflicts with the
+ // selected declaration.
+ struct MismatchingProperty {
+ const ObjCPropertyDecl *Prop;
+ MismatchKind Kind;
+ StringRef AttributeName;
+ };
+ SmallVector<MismatchingProperty, 4> Mismatches;
+ for (ObjCPropertyDecl *Prop : Properties) {
+ // Verify the property attributes.
+ unsigned Attr = Prop->getPropertyAttributesAsWritten();
+ if (Attr != OriginalAttributes) {
+ auto Diag = [&](bool OriginalHasAttribute, StringRef AttributeName) {
+ MismatchKind Kind = OriginalHasAttribute ? HasNoExpectedAttribute
+ : HasUnexpectedAttribute;
+ Mismatches.push_back({Prop, Kind, AttributeName});
+ };
+ if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
+ ObjCPropertyDecl::OBJC_PR_copy)) {
+ Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_copy, "copy");
+ continue;
+ }
+ if (areIncompatiblePropertyAttributes(
+ OriginalAttributes, Attr, ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong)) {
+ Diag(OriginalAttributes & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong),
+ "retain (or strong)");
+ continue;
+ }
+ if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
+ ObjCPropertyDecl::OBJC_PR_atomic)) {
+ Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_atomic, "atomic");
+ continue;
+ }
+ }
+ if (Property->getGetterName() != Prop->getGetterName()) {
+ Mismatches.push_back({Prop, DifferentGetter, ""});
+ continue;
+ }
+ if (!Property->isReadOnly() && !Prop->isReadOnly() &&
+ Property->getSetterName() != Prop->getSetterName()) {
+ Mismatches.push_back({Prop, DifferentSetter, ""});
+ continue;
+ }
QualType LHSType = S.Context.getCanonicalType(Prop->getType());
if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {
bool IncompatibleObjC = false;
QualType ConvertedType;
if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)
|| IncompatibleObjC) {
- if (FirsTime) {
- S.Diag(Property->getLocation(), diag::warn_protocol_property_mismatch)
- << Property->getType();
- FirsTime = false;
- }
- S.Diag(Prop->getLocation(), diag::note_protocol_property_declare)
- << Prop->getType();
+ Mismatches.push_back({Prop, IncompatibleType, ""});
+ continue;
}
}
}
- if (!FirsTime && AtLoc.isValid())
+
+ if (Mismatches.empty())
+ return Property;
+
+ // Diagnose incompability.
+ {
+ bool HasIncompatibleAttributes = false;
+ for (const auto &Note : Mismatches)
+ HasIncompatibleAttributes =
+ Note.Kind != IncompatibleType ? true : HasIncompatibleAttributes;
+ // Promote the warning to an error if there are incompatible attributes or
+ // incompatible types together with readwrite/readonly incompatibility.
+ auto Diag = S.Diag(Property->getLocation(),
+ Property != OriginalProperty || HasIncompatibleAttributes
+ ? diag::err_protocol_property_mismatch
+ : diag::warn_protocol_property_mismatch);
+ Diag << Mismatches[0].Kind;
+ switch (Mismatches[0].Kind) {
+ case IncompatibleType:
+ Diag << Property->getType();
+ break;
+ case HasNoExpectedAttribute:
+ case HasUnexpectedAttribute:
+ Diag << Mismatches[0].AttributeName;
+ break;
+ case DifferentGetter:
+ Diag << Property->getGetterName();
+ break;
+ case DifferentSetter:
+ Diag << Property->getSetterName();
+ break;
+ }
+ }
+ for (const auto &Note : Mismatches) {
+ auto Diag =
+ S.Diag(Note.Prop->getLocation(), diag::note_protocol_property_declare)
+ << Note.Kind;
+ switch (Note.Kind) {
+ case IncompatibleType:
+ Diag << Note.Prop->getType();
+ break;
+ case HasNoExpectedAttribute:
+ case HasUnexpectedAttribute:
+ Diag << Note.AttributeName;
+ break;
+ case DifferentGetter:
+ Diag << Note.Prop->getGetterName();
+ break;
+ case DifferentSetter:
+ Diag << Note.Prop->getSetterName();
+ break;
+ }
+ }
+ if (AtLoc.isValid())
S.Diag(AtLoc, diag::note_property_synthesize);
+
+ return Property;
}
/// Determine whether any storage attributes were written on the property.
@@ -988,8 +1128,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
}
if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
- DiagnosePropertyMismatchDeclInProtocols(*this, AtLoc, IDecl, property);
-
+ property = SelectPropertyForSynthesisFromProtocols(*this, AtLoc, IDecl,
+ property);
+
} else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
if (Synthesize) {
Diag(AtLoc, diag::err_synthesize_category_decl);
@@ -1149,6 +1290,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// An abstract type is as bad as an incomplete type.
CompleteTypeErr = true;
}
+ if (!CompleteTypeErr) {
+ const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>();
+ if (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()) {
+ Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar)
+ << PropertyIvarType;
+ CompleteTypeErr = true; // suppress later diagnostics about the ivar
+ }
+ }
if (CompleteTypeErr)
Ivar->setInvalidDecl();
ClassImpDecl->addDecl(Ivar);
@@ -1458,7 +1607,11 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
// meaningless for readonly properties, so don't diagnose if the
// atomic property is 'readonly'.
checkAtomicPropertyMismatch(*this, SuperProperty, Property, false);
- if (Property->getSetterName() != SuperProperty->getSetterName()) {
+ // Readonly properties from protocols can be implemented as "readwrite"
+ // with a custom setter name.
+ if (Property->getSetterName() != SuperProperty->getSetterName() &&
+ !(SuperProperty->isReadOnly() &&
+ isa<ObjCProtocolDecl>(SuperProperty->getDeclContext()))) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "setter" << inheritedName;
Diag(SuperProperty->getLocation(), diag::note_property_declare);
@@ -1668,8 +1821,9 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
/// \brief Default synthesizes all properties which must be synthesized
/// in class's \@implementation.
-void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
- ObjCInterfaceDecl *IDecl) {
+void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
+ ObjCInterfaceDecl *IDecl,
+ SourceLocation AtEnd) {
ObjCInterfaceDecl::PropertyMap PropMap;
ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
@@ -1717,6 +1871,10 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
diag::warn_auto_synthesizing_protocol_property)
<< Prop << Proto;
Diag(Prop->getLocation(), diag::note_property_declare);
+ std::string FixIt =
+ (Twine("@synthesize ") + Prop->getName() + ";\n\n").str();
+ Diag(AtEnd, diag::note_add_synthesize_directive)
+ << FixItHint::CreateInsertion(AtEnd, FixIt);
}
continue;
}
@@ -1749,14 +1907,15 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
/* property = */ Prop->getIdentifier(),
/* ivar = */ Prop->getDefaultSynthIvarName(Context),
Prop->getLocation(), Prop->getQueryKind()));
- if (PIDecl) {
+ if (PIDecl && !Prop->isUnavailable()) {
Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
}
}
}
-void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
+void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D,
+ SourceLocation AtEnd) {
if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile())
return;
ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
@@ -1764,7 +1923,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
return;
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
if (!IDecl->isObjCRequiresPropertyDefs())
- DefaultSynthesizeProperties(S, IC, IDecl);
+ DefaultSynthesizeProperties(S, IC, IDecl, AtEnd);
}
static void DiagnoseUnimplementedAccessor(
@@ -2177,12 +2336,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 7d47997455..941ac75fa6 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -22,27 +22,36 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/PointerEmbeddedInt.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Stack of data-sharing attributes for variables
//===----------------------------------------------------------------------===//
+static Expr *CheckMapClauseExpressionBase(
+ Sema &SemaRef, Expr *E,
+ OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
+ OpenMPClauseKind CKind);
+
namespace {
/// \brief Default data sharing attributes, which can be applied to directive.
enum DefaultDataSharingAttributes {
DSA_unspecified = 0, /// \brief Data sharing attribute not specified.
DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'.
- DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'.
+ DSA_shared = 1 << 1, /// \brief Default data sharing attribute 'shared'.
+};
+
+/// Attributes of the defaultmap clause.
+enum DefaultMapAttributes {
+ DMA_unspecified, /// Default mapping is not specified.
+ DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'.
};
/// \brief Stack for tracking declarations used in OpenMP directives and
@@ -55,7 +64,11 @@ public:
Expr *RefExpr = nullptr;
DeclRefExpr *PrivateCopy = nullptr;
SourceLocation ImplicitDSALoc;
- DSAVarData() {}
+ DSAVarData() = default;
+ DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, Expr *RefExpr,
+ DeclRefExpr *PrivateCopy, SourceLocation ImplicitDSALoc)
+ : DKind(DKind), CKind(CKind), RefExpr(RefExpr),
+ PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {}
};
typedef llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>
OperatorOffsetTy;
@@ -84,14 +97,32 @@ private:
CriticalsWithHintsTy;
typedef llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>
DoacrossDependMapTy;
+ struct ReductionData {
+ typedef llvm::PointerEmbeddedInt<BinaryOperatorKind, 16> BOKPtrType;
+ SourceRange ReductionRange;
+ llvm::PointerUnion<const Expr *, BOKPtrType> ReductionOp;
+ ReductionData() = default;
+ void set(BinaryOperatorKind BO, SourceRange RR) {
+ ReductionRange = RR;
+ ReductionOp = BO;
+ }
+ void set(const Expr *RefExpr, SourceRange RR) {
+ ReductionRange = RR;
+ ReductionOp = RefExpr;
+ }
+ };
+ typedef llvm::DenseMap<ValueDecl *, ReductionData> DeclReductionMapTy;
struct SharingMapTy final {
DeclSAMapTy SharingMap;
+ DeclReductionMapTy ReductionMap;
AlignedMapTy AlignedMap;
MappedExprComponentsTy MappedExprComponents;
LoopControlVariablesMapTy LCVMap;
DefaultDataSharingAttributes DefaultAttr = DSA_unspecified;
SourceLocation DefaultAttrLoc;
+ DefaultMapAttributes DefaultMapAttr = DMA_unspecified;
+ SourceLocation DefaultMapAttrLoc;
OpenMPDirectiveKind Directive = OMPD_unknown;
DeclarationNameInfo DirectiveName;
Scope *CurScope = nullptr;
@@ -108,17 +139,21 @@ private:
bool CancelRegion = false;
unsigned AssociatedLoops = 1;
SourceLocation InnerTeamsRegionLoc;
+ /// Reference to the taskgroup task_reduction reference expression.
+ Expr *TaskgroupReductionRef = nullptr;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
ConstructLoc(Loc) {}
- SharingMapTy() {}
+ SharingMapTy() = default;
};
typedef SmallVector<SharingMapTy, 4> StackTy;
/// \brief Stack of used declaration and their data-sharing attributes.
- StackTy Stack;
+ DeclSAMapTy Threadprivates;
+ const FunctionScopeInfo *CurrentNonCapturingFunctionScope = nullptr;
+ SmallVector<std::pair<StackTy, const FunctionScopeInfo *>, 4> Stack;
/// \brief true, if check for DSA must be from parent directive, false, if
/// from current directive.
OpenMPClauseKind ClauseKindMode = OMPC_unknown;
@@ -133,8 +168,14 @@ private:
/// \brief Checks if the variable is a local for OpenMP region.
bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter);
+ bool isStackEmpty() const {
+ return Stack.empty() ||
+ Stack.back().second != CurrentNonCapturingFunctionScope ||
+ Stack.back().first.empty();
+ }
+
public:
- explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {}
+ explicit DSAStackTy(Sema &S) : SemaRef(S) {}
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
@@ -144,13 +185,38 @@ public:
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
- Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc));
- Stack.back().DefaultAttrLoc = Loc;
+ if (Stack.empty() ||
+ Stack.back().second != CurrentNonCapturingFunctionScope)
+ Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope);
+ Stack.back().first.emplace_back(DKind, DirName, CurScope, Loc);
+ Stack.back().first.back().DefaultAttrLoc = Loc;
}
void pop() {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty!");
- Stack.pop_back();
+ assert(!Stack.back().first.empty() &&
+ "Data-sharing attributes stack is empty!");
+ Stack.back().first.pop_back();
+ }
+
+ /// Start new OpenMP region stack in new non-capturing function.
+ void pushFunction() {
+ const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction();
+ assert(!isa<CapturingScopeInfo>(CurFnScope));
+ CurrentNonCapturingFunctionScope = CurFnScope;
+ }
+ /// Pop region stack for non-capturing function.
+ void popFunction(const FunctionScopeInfo *OldFSI) {
+ if (!Stack.empty() && Stack.back().second == OldFSI) {
+ assert(Stack.back().first.empty());
+ Stack.pop_back();
+ }
+ CurrentNonCapturingFunctionScope = nullptr;
+ for (const FunctionScopeInfo *FSI : llvm::reverse(SemaRef.FunctionScopes)) {
+ if (!isa<CapturingScopeInfo>(FSI)) {
+ CurrentNonCapturingFunctionScope = FSI;
+ break;
+ }
+ }
}
void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) {
@@ -188,6 +254,39 @@ public:
void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
DeclRefExpr *PrivateCopy = nullptr);
+ /// Adds additional information for the reduction items with the reduction id
+ /// represented as an operator.
+ void addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ BinaryOperatorKind BOK);
+ /// Adds additional information for the reduction items with the reduction id
+ /// represented as reduction identifier.
+ void addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ const Expr *ReductionRef);
+ /// Returns the location and reduction operation from the innermost parent
+ /// region for the given \p D.
+ DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ BinaryOperatorKind &BOK,
+ Expr *&TaskgroupDescriptor);
+ /// Returns the location and reduction operation from the innermost parent
+ /// region for the given \p D.
+ DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ const Expr *&ReductionRef,
+ Expr *&TaskgroupDescriptor);
+ /// Return reduction reference expression for the current taskgroup.
+ Expr *getTaskgroupReductionRef() const {
+ assert(Stack.back().first.back().Directive == OMPD_taskgroup &&
+ "taskgroup reference expression requested for non taskgroup "
+ "directive.");
+ return Stack.back().first.back().TaskgroupReductionRef;
+ }
+ /// Checks if the given \p VD declaration is actually a taskgroup reduction
+ /// descriptor variable at the \p Level of OpenMP regions.
+ bool isTaskgroupReductionRef(ValueDecl *VD, unsigned Level) const {
+ return Stack.back().first[Level].TaskgroupReductionRef &&
+ cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef)
+ ->getDecl() == VD;
+ }
+
/// \brief Returns data sharing attributes from top of the stack for the
/// specified declaration.
DSAVarData getTopDSA(ValueDecl *D, bool FromParent);
@@ -229,31 +328,52 @@ public:
/// \brief Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
- return Stack.back().Directive;
+ return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive;
}
/// \brief Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].Directive;
- return OMPD_unknown;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return OMPD_unknown;
+ return std::next(Stack.back().first.rbegin())->Directive;
}
/// \brief Set default data sharing attribute to none.
void setDefaultDSANone(SourceLocation Loc) {
- Stack.back().DefaultAttr = DSA_none;
- Stack.back().DefaultAttrLoc = Loc;
+ assert(!isStackEmpty());
+ Stack.back().first.back().DefaultAttr = DSA_none;
+ Stack.back().first.back().DefaultAttrLoc = Loc;
}
/// \brief Set default data sharing attribute to shared.
void setDefaultDSAShared(SourceLocation Loc) {
- Stack.back().DefaultAttr = DSA_shared;
- Stack.back().DefaultAttrLoc = Loc;
+ assert(!isStackEmpty());
+ Stack.back().first.back().DefaultAttr = DSA_shared;
+ Stack.back().first.back().DefaultAttrLoc = Loc;
+ }
+ /// Set default data mapping attribute to 'tofrom:scalar'.
+ void setDefaultDMAToFromScalar(SourceLocation Loc) {
+ assert(!isStackEmpty());
+ Stack.back().first.back().DefaultMapAttr = DMA_tofrom_scalar;
+ Stack.back().first.back().DefaultMapAttrLoc = Loc;
}
DefaultDataSharingAttributes getDefaultDSA() const {
- return Stack.back().DefaultAttr;
+ return isStackEmpty() ? DSA_unspecified
+ : Stack.back().first.back().DefaultAttr;
}
SourceLocation getDefaultDSALocation() const {
- return Stack.back().DefaultAttrLoc;
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().DefaultAttrLoc;
+ }
+ DefaultMapAttributes getDefaultDMA() const {
+ return isStackEmpty() ? DMA_unspecified
+ : Stack.back().first.back().DefaultMapAttr;
+ }
+ DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const {
+ return Stack.back().first[Level].DefaultMapAttr;
+ }
+ SourceLocation getDefaultDMALocation() const {
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().DefaultMapAttrLoc;
}
/// \brief Checks if the specified variable is a threadprivate.
@@ -264,52 +384,64 @@ public:
/// \brief Marks current region as ordered (it has an 'ordered' clause).
void setOrderedRegion(bool IsOrdered, Expr *Param) {
- Stack.back().OrderedRegion.setInt(IsOrdered);
- Stack.back().OrderedRegion.setPointer(Param);
+ assert(!isStackEmpty());
+ Stack.back().first.back().OrderedRegion.setInt(IsOrdered);
+ Stack.back().first.back().OrderedRegion.setPointer(Param);
}
/// \brief Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].OrderedRegion.getInt();
- return false;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return false;
+ return std::next(Stack.back().first.rbegin())->OrderedRegion.getInt();
}
/// \brief Returns optional parameter for the ordered region.
Expr *getParentOrderedRegionParam() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].OrderedRegion.getPointer();
- return nullptr;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return nullptr;
+ return std::next(Stack.back().first.rbegin())->OrderedRegion.getPointer();
}
/// \brief Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
- Stack.back().NowaitRegion = IsNowait;
+ assert(!isStackEmpty());
+ Stack.back().first.back().NowaitRegion = IsNowait;
}
/// \brief Returns true, if parent region is nowait (has associated
/// 'nowait' clause), false - otherwise.
bool isParentNowaitRegion() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].NowaitRegion;
- return false;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return false;
+ return std::next(Stack.back().first.rbegin())->NowaitRegion;
}
/// \brief Marks parent region as cancel region.
void setParentCancelRegion(bool Cancel = true) {
- if (Stack.size() > 2)
- Stack[Stack.size() - 2].CancelRegion =
- Stack[Stack.size() - 2].CancelRegion || Cancel;
+ if (!isStackEmpty() && Stack.back().first.size() > 1) {
+ auto &StackElemRef = *std::next(Stack.back().first.rbegin());
+ StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel;
+ }
}
/// \brief Return true if current region has inner cancel construct.
- bool isCancelRegion() const { return Stack.back().CancelRegion; }
+ bool isCancelRegion() const {
+ return isStackEmpty() ? false : Stack.back().first.back().CancelRegion;
+ }
/// \brief Set collapse value for the region.
- void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; }
+ void setAssociatedLoops(unsigned Val) {
+ assert(!isStackEmpty());
+ Stack.back().first.back().AssociatedLoops = Val;
+ }
/// \brief Return collapse value for region.
- unsigned getAssociatedLoops() const { return Stack.back().AssociatedLoops; }
+ unsigned getAssociatedLoops() const {
+ return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops;
+ }
/// \brief Marks current target region as one with closely nested teams
/// region.
void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
- if (Stack.size() > 2)
- Stack[Stack.size() - 2].InnerTeamsRegionLoc = TeamsRegionLoc;
+ if (!isStackEmpty() && Stack.back().first.size() > 1) {
+ std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc =
+ TeamsRegionLoc;
+ }
}
/// \brief Returns true, if current region has closely nested teams region.
bool hasInnerTeamsRegion() const {
@@ -317,14 +449,20 @@ public:
}
/// \brief Returns location of the nested teams region (if any).
SourceLocation getInnerTeamsRegionLoc() const {
- if (Stack.size() > 1)
- return Stack.back().InnerTeamsRegionLoc;
- return SourceLocation();
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().InnerTeamsRegionLoc;
}
- Scope *getCurScope() const { return Stack.back().CurScope; }
- Scope *getCurScope() { return Stack.back().CurScope; }
- SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
+ Scope *getCurScope() const {
+ return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
+ }
+ Scope *getCurScope() {
+ return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
+ }
+ SourceLocation getConstructLoc() {
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().ConstructLoc;
+ }
/// Do the check specified in \a Check to all component lists and return true
/// if any issue is found.
@@ -333,8 +471,10 @@ public:
const llvm::function_ref<
bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind)> &Check) {
- auto SI = Stack.rbegin();
- auto SE = Stack.rend();
+ if (isStackEmpty())
+ return false;
+ auto SI = Stack.back().first.rbegin();
+ auto SE = Stack.back().first.rend();
if (SI == SE)
return false;
@@ -355,15 +495,39 @@ public:
return false;
}
+ /// Do the check specified in \a Check to all component lists at a given level
+ /// and return true if any issue is found.
+ bool checkMappableExprComponentListsForDeclAtLevel(
+ ValueDecl *VD, unsigned Level,
+ const llvm::function_ref<
+ bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind)> &Check) {
+ if (isStackEmpty())
+ return false;
+
+ auto StartI = Stack.back().first.begin();
+ auto EndI = Stack.back().first.end();
+ if (std::distance(StartI, EndI) <= (int)Level)
+ return false;
+ std::advance(StartI, Level);
+
+ auto MI = StartI->MappedExprComponents.find(VD);
+ if (MI != StartI->MappedExprComponents.end())
+ for (auto &L : MI->second.Components)
+ if (Check(L, MI->second.Kind))
+ return true;
+ return false;
+ }
+
/// Create a new mappable expression component list associated with a given
/// declaration and initialize it with the provided list of components.
void addMappableExpressionComponents(
ValueDecl *VD,
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
OpenMPClauseKind WhereFoundClauseKind) {
- assert(Stack.size() > 1 &&
+ assert(!isStackEmpty() &&
"Not expecting to retrieve components from a empty stack!");
- auto &MEC = Stack.back().MappedExprComponents[VD];
+ auto &MEC = Stack.back().first.back().MappedExprComponents[VD];
// Create new entry and append the new components there.
MEC.Components.resize(MEC.Components.size() + 1);
MEC.Components.back().append(Components.begin(), Components.end());
@@ -371,23 +535,25 @@ public:
}
unsigned getNestingLevel() const {
- assert(Stack.size() > 1);
- return Stack.size() - 2;
+ assert(!isStackEmpty());
+ return Stack.back().first.size() - 1;
}
void addDoacrossDependClause(OMPDependClause *C, OperatorOffsetTy &OpsOffs) {
- assert(Stack.size() > 2);
- assert(isOpenMPWorksharingDirective(Stack[Stack.size() - 2].Directive));
- Stack[Stack.size() - 2].DoacrossDepends.insert({C, OpsOffs});
+ assert(!isStackEmpty() && Stack.back().first.size() > 1);
+ auto &StackElem = *std::next(Stack.back().first.rbegin());
+ assert(isOpenMPWorksharingDirective(StackElem.Directive));
+ StackElem.DoacrossDepends.insert({C, OpsOffs});
}
llvm::iterator_range<DoacrossDependMapTy::const_iterator>
getDoacrossDependClauses() const {
- assert(Stack.size() > 1);
- if (isOpenMPWorksharingDirective(Stack[Stack.size() - 1].Directive)) {
- auto &Ref = Stack[Stack.size() - 1].DoacrossDepends;
+ assert(!isStackEmpty());
+ auto &StackElem = Stack.back().first.back();
+ if (isOpenMPWorksharingDirective(StackElem.Directive)) {
+ auto &Ref = StackElem.DoacrossDepends;
return llvm::make_range(Ref.begin(), Ref.end());
}
- return llvm::make_range(Stack[0].DoacrossDepends.end(),
- Stack[0].DoacrossDepends.end());
+ return llvm::make_range(StackElem.DoacrossDepends.end(),
+ StackElem.DoacrossDepends.end());
}
};
bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
@@ -396,7 +562,25 @@ bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
}
} // namespace
+static Expr *getExprAsWritten(Expr *E) {
+ if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E))
+ E = ExprTemp->getSubExpr();
+
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
+ E = MTE->GetTemporaryExpr();
+
+ while (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = Binder->getSubExpr();
+
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExprAsWritten();
+ return E->IgnoreParens();
+}
+
static ValueDecl *getCanonicalDecl(ValueDecl *D) {
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D))
+ if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
+ D = ME->getMemberDecl();
auto *VD = dyn_cast<VarDecl>(D);
auto *FD = dyn_cast<FieldDecl>(D);
if (VD != nullptr) {
@@ -416,7 +600,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
auto *VD = dyn_cast<VarDecl>(D);
auto *FD = dyn_cast<FieldDecl>(D);
DSAVarData DVar;
- if (Iter == std::prev(Stack.rend())) {
+ if (isStackEmpty() || Iter == Stack.back().first.rend()) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// File-scope or namespace-scope variables referenced in called routines
@@ -439,7 +623,6 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
return DVar;
}
- DVar.DKind = Iter->Directive;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.1]
// Variables with automatic storage duration that are declared in a scope
@@ -450,6 +633,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
return DVar;
}
+ DVar.DKind = Iter->Directive;
// Explicitly specified attributes and local variables with predetermined
// attributes.
if (Iter->SharingMap.count(D)) {
@@ -490,8 +674,9 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
// bound to the current team is shared.
if (isOpenMPTaskingDirective(DVar.DKind)) {
DSAVarData DVarTemp;
- for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend();
- I != EE; ++I) {
+ auto I = Iter, E = Stack.back().first.rend();
+ do {
+ ++I;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
// Referenced in a Construct, implicitly determined, p.6]
// In a task construct, if no default clause is present, a variable
@@ -503,9 +688,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
DVar.CKind = OMPC_firstprivate;
return DVar;
}
- if (isParallelOrTaskRegion(I->Directive))
- break;
- }
+ } while (I != E && !isParallelOrTaskRegion(I->Directive));
DVar.CKind =
(DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
return DVar;
@@ -520,12 +703,13 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
}
Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) {
- assert(Stack.size() > 1 && "Data sharing attributes stack is empty");
+ assert(!isStackEmpty() && "Data sharing attributes stack is empty");
D = getCanonicalDecl(D);
- auto It = Stack.back().AlignedMap.find(D);
- if (It == Stack.back().AlignedMap.end()) {
+ auto &StackElem = Stack.back().first.back();
+ auto It = StackElem.AlignedMap.find(D);
+ if (It == StackElem.AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
- Stack.back().AlignedMap[D] = NewDE;
+ StackElem.AlignedMap[D] = NewDE;
return nullptr;
} else {
assert(It->second && "Unexpected nullptr expr in the aligned map");
@@ -535,35 +719,43 @@ Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) {
}
void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- Stack.back().LCVMap.insert(
- std::make_pair(D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture)));
+ auto &StackElem = Stack.back().first.back();
+ StackElem.LCVMap.insert(
+ {D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture)});
}
DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D]
- : LCDeclInfo(0, nullptr);
+ auto &StackElem = Stack.back().first.back();
+ auto It = StackElem.LCVMap.find(D);
+ if (It != StackElem.LCVMap.end())
+ return It->second;
+ return {0, nullptr};
}
DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) {
- assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
+ assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
+ "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- return Stack[Stack.size() - 2].LCVMap.count(D) > 0
- ? Stack[Stack.size() - 2].LCVMap[D]
- : LCDeclInfo(0, nullptr);
+ auto &StackElem = *std::next(Stack.back().first.rbegin());
+ auto It = StackElem.LCVMap.find(D);
+ if (It != StackElem.LCVMap.end())
+ return It->second;
+ return {0, nullptr};
}
ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) {
- assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
- if (Stack[Stack.size() - 2].LCVMap.size() < I)
+ assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
+ "Data-sharing attributes stack is empty");
+ auto &StackElem = *std::next(Stack.back().first.rbegin());
+ if (StackElem.LCVMap.size() < I)
return nullptr;
- for (auto &Pair : Stack[Stack.size() - 2].LCVMap) {
+ for (auto &Pair : StackElem.LCVMap)
if (Pair.second.first == I)
return Pair.first;
- }
return nullptr;
}
@@ -571,13 +763,13 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
DeclRefExpr *PrivateCopy) {
D = getCanonicalDecl(D);
if (A == OMPC_threadprivate) {
- auto &Data = Stack[0].SharingMap[D];
+ auto &Data = Threadprivates[D];
Data.Attributes = A;
Data.RefExpr.setPointer(E);
Data.PrivateCopy = nullptr;
} else {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
- auto &Data = Stack.back().SharingMap[D];
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ auto &Data = Stack.back().first.back().SharingMap[D];
assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
(A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
(A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
@@ -592,7 +784,7 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
Data.RefExpr.setPointerAndInt(E, IsLastprivate);
Data.PrivateCopy = PrivateCopy;
if (PrivateCopy) {
- auto &Data = Stack.back().SharingMap[PrivateCopy->getDecl()];
+ auto &Data = Stack.back().first.back().SharingMap[PrivateCopy->getDecl()];
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
Data.PrivateCopy = nullptr;
@@ -600,26 +792,6 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
}
}
-bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
- D = D->getCanonicalDecl();
- if (Stack.size() > 2) {
- reverse_iterator I = Iter, E = std::prev(Stack.rend());
- Scope *TopScope = nullptr;
- while (I != E && !isParallelOrTaskRegion(I->Directive)) {
- ++I;
- }
- if (I == E)
- return false;
- TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
- Scope *CurScope = getCurScope();
- while (CurScope != TopScope && !CurScope->isDeclScope(D)) {
- CurScope = CurScope->getParent();
- }
- return CurScope != TopScope;
- }
- return false;
-}
-
/// \brief Build a variable declaration for OpenMP loop iteration variable.
static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
StringRef Name, const AttrVec *Attrs = nullptr) {
@@ -647,6 +819,130 @@ static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty,
VK_LValue);
}
+void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ BinaryOperatorKind BOK) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ assert(
+ Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ "Additional reduction info may be specified only for reduction items.");
+ auto &ReductionData = Stack.back().first.back().ReductionMap[D];
+ assert(ReductionData.ReductionRange.isInvalid() &&
+ Stack.back().first.back().Directive == OMPD_taskgroup &&
+ "Additional reduction info may be specified only once for reduction "
+ "items.");
+ ReductionData.set(BOK, SR);
+ Expr *&TaskgroupReductionRef =
+ Stack.back().first.back().TaskgroupReductionRef;
+ if (!TaskgroupReductionRef) {
+ auto *VD = buildVarDecl(SemaRef, SR.getBegin(),
+ SemaRef.Context.VoidPtrTy, ".task_red.");
+ TaskgroupReductionRef =
+ buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin());
+ }
+}
+
+void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ const Expr *ReductionRef) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ assert(
+ Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ "Additional reduction info may be specified only for reduction items.");
+ auto &ReductionData = Stack.back().first.back().ReductionMap[D];
+ assert(ReductionData.ReductionRange.isInvalid() &&
+ Stack.back().first.back().Directive == OMPD_taskgroup &&
+ "Additional reduction info may be specified only once for reduction "
+ "items.");
+ ReductionData.set(ReductionRef, SR);
+ Expr *&TaskgroupReductionRef =
+ Stack.back().first.back().TaskgroupReductionRef;
+ if (!TaskgroupReductionRef) {
+ auto *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy,
+ ".task_red.");
+ TaskgroupReductionRef =
+ buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin());
+ }
+}
+
+DSAStackTy::DSAVarData
+DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ BinaryOperatorKind &BOK,
+ Expr *&TaskgroupDescriptor) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
+ if (Stack.back().first.empty())
+ return DSAVarData();
+ for (auto I = std::next(Stack.back().first.rbegin(), 1),
+ E = Stack.back().first.rend();
+ I != E; std::advance(I, 1)) {
+ auto &Data = I->SharingMap[D];
+ if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
+ continue;
+ auto &ReductionData = I->ReductionMap[D];
+ if (!ReductionData.ReductionOp ||
+ ReductionData.ReductionOp.is<const Expr *>())
+ return DSAVarData();
+ SR = ReductionData.ReductionRange;
+ BOK = ReductionData.ReductionOp.get<ReductionData::BOKPtrType>();
+ assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
+ "expression for the descriptor is not "
+ "set.");
+ TaskgroupDescriptor = I->TaskgroupReductionRef;
+ return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc);
+ }
+ return DSAVarData();
+}
+
+DSAStackTy::DSAVarData
+DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ const Expr *&ReductionRef,
+ Expr *&TaskgroupDescriptor) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
+ if (Stack.back().first.empty())
+ return DSAVarData();
+ for (auto I = std::next(Stack.back().first.rbegin(), 1),
+ E = Stack.back().first.rend();
+ I != E; std::advance(I, 1)) {
+ auto &Data = I->SharingMap[D];
+ if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
+ continue;
+ auto &ReductionData = I->ReductionMap[D];
+ if (!ReductionData.ReductionOp ||
+ !ReductionData.ReductionOp.is<const Expr *>())
+ return DSAVarData();
+ SR = ReductionData.ReductionRange;
+ ReductionRef = ReductionData.ReductionOp.get<const Expr *>();
+ assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
+ "expression for the descriptor is not "
+ "set.");
+ TaskgroupDescriptor = I->TaskgroupReductionRef;
+ return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc);
+ }
+ return DSAVarData();
+}
+
+bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
+ D = D->getCanonicalDecl();
+ if (!isStackEmpty() && Stack.back().first.size() > 1) {
+ reverse_iterator I = Iter, E = Stack.back().first.rend();
+ Scope *TopScope = nullptr;
+ while (I != E && !isParallelOrTaskRegion(I->Directive))
+ ++I;
+ if (I == E)
+ return false;
+ TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
+ Scope *CurScope = getCurScope();
+ while (CurScope != TopScope && !CurScope->isDeclScope(D))
+ CurScope = CurScope->getParent();
+ return CurScope != TopScope;
+ }
+ return false;
+}
+
DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
D = getCanonicalDecl(D);
DSAVarData DVar;
@@ -665,16 +961,16 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
D->getLocation()),
OMPC_threadprivate);
}
- if (Stack[0].SharingMap.count(D)) {
- DVar.RefExpr = Stack[0].SharingMap[D].RefExpr.getPointer();
+ auto TI = Threadprivates.find(D);
+ if (TI != Threadprivates.end()) {
+ DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
return DVar;
}
- if (Stack.size() == 1) {
+ if (isStackEmpty())
// Not in OpenMP execution region and top scope was already checked.
return DVar;
- }
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.4]
@@ -722,17 +1018,16 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
// Explicitly specified attributes and local variables with predetermined
// attributes.
- auto StartI = std::next(Stack.rbegin());
- auto EndI = std::prev(Stack.rend());
- if (FromParent && StartI != EndI) {
- StartI = std::next(StartI);
- }
- auto I = std::prev(StartI);
+ auto I = Stack.back().first.rbegin();
+ auto EndI = Stack.back().first.rend();
+ if (FromParent && I != EndI)
+ std::advance(I, 1);
if (I->SharingMap.count(D)) {
DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer();
DVar.PrivateCopy = I->SharingMap[D].PrivateCopy;
DVar.CKind = I->SharingMap[D].Attributes;
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
+ DVar.DKind = I->Directive;
}
return DVar;
@@ -740,12 +1035,15 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
bool FromParent) {
- D = getCanonicalDecl(D);
- auto StartI = Stack.rbegin();
- auto EndI = std::prev(Stack.rend());
- if (FromParent && StartI != EndI) {
- StartI = std::next(StartI);
+ if (isStackEmpty()) {
+ StackTy::reverse_iterator I;
+ return getDSA(I, D);
}
+ D = getCanonicalDecl(D);
+ auto StartI = Stack.back().first.rbegin();
+ auto EndI = Stack.back().first.rend();
+ if (FromParent && StartI != EndI)
+ std::advance(StartI, 1);
return getDSA(StartI, D);
}
@@ -754,35 +1052,40 @@ DSAStackTy::hasDSA(ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
bool FromParent) {
+ if (isStackEmpty())
+ return {};
D = getCanonicalDecl(D);
- auto StartI = std::next(Stack.rbegin());
- auto EndI = Stack.rend();
- if (FromParent && StartI != EndI) {
- StartI = std::next(StartI);
- }
- for (auto I = StartI, EE = EndI; I != EE; ++I) {
+ auto I = Stack.back().first.rbegin();
+ auto EndI = Stack.back().first.rend();
+ if (FromParent && I != EndI)
+ std::advance(I, 1);
+ for (; I != EndI; std::advance(I, 1)) {
if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive))
continue;
- DSAVarData DVar = getDSA(I, D);
- if (CPred(DVar.CKind))
+ auto NewI = I;
+ DSAVarData DVar = getDSA(NewI, D);
+ if (I == NewI && CPred(DVar.CKind))
return DVar;
}
- return DSAVarData();
+ return {};
}
DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
bool FromParent) {
+ if (isStackEmpty())
+ return {};
D = getCanonicalDecl(D);
- auto StartI = std::next(Stack.rbegin());
- auto EndI = Stack.rend();
+ auto StartI = Stack.back().first.rbegin();
+ auto EndI = Stack.back().first.rend();
if (FromParent && StartI != EndI)
- StartI = std::next(StartI);
+ std::advance(StartI, 1);
if (StartI == EndI || !DPred(StartI->Directive))
- return DSAVarData();
- DSAVarData DVar = getDSA(StartI, D);
- return CPred(DVar.CKind) ? DVar : DSAVarData();
+ return {};
+ auto NewI = StartI;
+ DSAVarData DVar = getDSA(NewI, D);
+ return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData();
}
bool DSAStackTy::hasExplicitDSA(
@@ -790,9 +1093,11 @@ bool DSAStackTy::hasExplicitDSA(
unsigned Level, bool NotLastprivate) {
if (CPred(ClauseKindMode))
return true;
+ if (isStackEmpty())
+ return false;
D = getCanonicalDecl(D);
- auto StartI = std::next(Stack.begin());
- auto EndI = Stack.end();
+ auto StartI = Stack.back().first.begin();
+ auto EndI = Stack.back().first.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
@@ -805,8 +1110,10 @@ bool DSAStackTy::hasExplicitDSA(
bool DSAStackTy::hasExplicitDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
unsigned Level) {
- auto StartI = std::next(Stack.begin());
- auto EndI = Stack.end();
+ if (isStackEmpty())
+ return false;
+ auto StartI = Stack.back().first.begin();
+ auto EndI = Stack.back().first.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
@@ -819,13 +1126,12 @@ bool DSAStackTy::hasDirective(
&DPred,
bool FromParent) {
// We look only in the enclosing region.
- if (Stack.size() < 2)
+ if (isStackEmpty())
return false;
- auto StartI = std::next(Stack.rbegin());
- auto EndI = std::prev(Stack.rend());
- if (FromParent && StartI != EndI) {
+ auto StartI = std::next(Stack.back().first.rbegin());
+ auto EndI = Stack.back().first.rend();
+ if (FromParent && StartI != EndI)
StartI = std::next(StartI);
- }
for (auto I = StartI, EE = EndI; I != EE; ++I) {
if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc))
return true;
@@ -839,6 +1145,14 @@ void Sema::InitDataSharingAttributesStack() {
#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
+void Sema::pushOpenMPFunctionRegion() {
+ DSAStack->pushFunction();
+}
+
+void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
+ DSAStack->popFunction(OldFSI);
+}
+
bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@@ -846,6 +1160,7 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
bool IsByRef = true;
// Find the directive that is associated with the provided scope.
+ D = cast<ValueDecl>(D->getCanonicalDecl());
auto Ty = D->getType();
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) {
@@ -912,9 +1227,8 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
bool IsVariableUsedInMapClause = false;
bool IsVariableAssociatedWithSection = false;
- DSAStack->checkMappableExprComponentListsForDecl(
- D, /*CurrentRegionOnly=*/true,
- [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ DSAStack->checkMappableExprComponentListsForDeclAtLevel(
+ D, Level, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
MapExprComponents,
OpenMPClauseKind WhereFoundClauseKind) {
// Only the map clause information influences how a variable is
@@ -953,7 +1267,8 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
IsByRef = !(Ty->isPointerType() && IsVariableAssociatedWithSection);
} else {
// By default, all the data that has a scalar type is mapped by copy.
- IsByRef = !Ty->isScalarType();
+ IsByRef = !Ty->isScalarType() ||
+ DSAStack->getDefaultDMAAtLevel(Level) == DMA_tofrom_scalar;
}
}
@@ -995,7 +1310,7 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
//
auto *VD = dyn_cast<VarDecl>(D);
if (VD && !VD->hasLocalStorage()) {
- if (DSAStack->getCurrentDirective() == OMPD_target &&
+ if (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) &&
!DSAStack->isClauseParsingMode())
return VD;
if (DSAStack->hasDirective(
@@ -1031,7 +1346,47 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
return DSAStack->hasExplicitDSA(
- D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level);
+ D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; },
+ Level) ||
+ // Consider taskgroup reduction descriptor variable a private to avoid
+ // possible capture in the region.
+ (DSAStack->hasExplicitDirective(
+ [](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; },
+ Level) &&
+ DSAStack->isTaskgroupReductionRef(D, Level));
+}
+
+void Sema::setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level) {
+ assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ D = getCanonicalDecl(D);
+ OpenMPClauseKind OMPC = OMPC_unknown;
+ for (unsigned I = DSAStack->getNestingLevel() + 1; I > Level; --I) {
+ const unsigned NewLevel = I - 1;
+ if (DSAStack->hasExplicitDSA(D,
+ [&OMPC](const OpenMPClauseKind K) {
+ if (isOpenMPPrivate(K)) {
+ OMPC = K;
+ return true;
+ }
+ return false;
+ },
+ NewLevel))
+ break;
+ if (DSAStack->checkMappableExprComponentListsForDeclAtLevel(
+ D, NewLevel,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind) { return true; })) {
+ OMPC = OMPC_map;
+ break;
+ }
+ if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
+ NewLevel)) {
+ OMPC = OMPC_firstprivate;
+ break;
+ }
+ }
+ if (OMPC != OMPC_unknown)
+ FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC));
}
bool Sema::isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level) {
@@ -1050,7 +1405,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) {
@@ -1462,7 +1818,9 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> {
bool ErrorFound;
CapturedStmt *CS;
llvm::SmallVector<Expr *, 8> ImplicitFirstprivate;
+ llvm::SmallVector<Expr *, 8> ImplicitMap;
llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA;
+ llvm::DenseSet<ValueDecl *> ImplicitDeclarations;
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
@@ -1470,13 +1828,18 @@ public:
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
+ VD = VD->getCanonicalDecl();
// Skip internally declared variables.
- if (VD->isLocalVarDecl() && !CS->capturesVariable(VD))
+ if (VD->hasLocalStorage() && !CS->capturesVariable(VD))
return;
auto DVar = Stack->getTopDSA(VD, false);
// Check if the variable has explicit DSA set and stop analysis if it so.
- if (DVar.RefExpr)
+ if (DVar.RefExpr || !ImplicitDeclarations.insert(VD).second)
+ return;
+
+ // Skip internally declared static variables.
+ if (VD->hasGlobalStorage() && !CS->capturesVariable(VD))
return;
auto ELoc = E->getExprLoc();
@@ -1492,6 +1855,46 @@ public:
return;
}
+ if (isOpenMPTargetExecutionDirective(DKind) &&
+ !Stack->isLoopControlVariable(VD).first) {
+ if (!Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ StackComponents,
+ OpenMPClauseKind) {
+ // Variable is used if it has been marked as an array, array
+ // section or the variable iself.
+ return StackComponents.size() == 1 ||
+ std::all_of(
+ std::next(StackComponents.rbegin()),
+ StackComponents.rend(),
+ [](const OMPClauseMappableExprCommon::
+ MappableComponent &MC) {
+ return MC.getAssociatedDeclaration() ==
+ nullptr &&
+ (isa<OMPArraySectionExpr>(
+ MC.getAssociatedExpression()) ||
+ isa<ArraySubscriptExpr>(
+ MC.getAssociatedExpression()));
+ });
+ })) {
+ bool IsFirstprivate = false;
+ // By default lambdas are captured as firstprivates.
+ if (const auto *RD =
+ VD->getType().getNonReferenceType()->getAsCXXRecordDecl())
+ IsFirstprivate = RD->isLambda();
+ IsFirstprivate =
+ IsFirstprivate ||
+ (VD->getType().getNonReferenceType()->isScalarType() &&
+ Stack->getDefaultDMA() != DMA_tofrom_scalar);
+ if (IsFirstprivate)
+ ImplicitFirstprivate.emplace_back(E);
+ else
+ ImplicitMap.emplace_back(E);
+ return;
+ }
+ }
+
// OpenMP [2.9.3.6, Restrictions, p.2]
// A list item that appears in a reduction clause of the innermost
// enclosing worksharing or parallel construct may not be accessed in an
@@ -1502,7 +1905,7 @@ public:
return isOpenMPParallelDirective(K) ||
isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K);
},
- false);
+ /*FromParent=*/true);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
ErrorFound = true;
SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
@@ -1521,40 +1924,105 @@ public:
if (E->isTypeDependent() || E->isValueDependent() ||
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
+ auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ if (!FD)
+ return;
+ OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) {
- if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
- auto DVar = Stack->getTopDSA(FD, false);
- // Check if the variable has explicit DSA set and stop analysis if it
- // so.
- if (DVar.RefExpr)
- return;
+ auto DVar = Stack->getTopDSA(FD, false);
+ // Check if the variable has explicit DSA set and stop analysis if it
+ // so.
+ if (DVar.RefExpr || !ImplicitDeclarations.insert(FD).second)
+ return;
- auto ELoc = E->getExprLoc();
- auto DKind = Stack->getCurrentDirective();
- // OpenMP [2.9.3.6, Restrictions, p.2]
- // A list item that appears in a reduction clause of the innermost
- // enclosing worksharing or parallel construct may not be accessed in
- // an explicit task.
- DVar = Stack->hasInnermostDSA(
- FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPParallelDirective(K) ||
- isOpenMPWorksharingDirective(K) ||
- isOpenMPTeamsDirective(K);
- },
- false);
- if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
- ErrorFound = true;
- SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
- ReportOriginalDSA(SemaRef, Stack, FD, DVar);
+ if (isOpenMPTargetExecutionDirective(DKind) &&
+ !Stack->isLoopControlVariable(FD).first &&
+ !Stack->checkMappableExprComponentListsForDecl(
+ FD, /*CurrentRegionOnly=*/true,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ StackComponents,
+ OpenMPClauseKind) {
+ return isa<CXXThisExpr>(
+ cast<MemberExpr>(
+ StackComponents.back().getAssociatedExpression())
+ ->getBase()
+ ->IgnoreParens());
+ })) {
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
+ // A bit-field cannot appear in a map clause.
+ //
+ if (FD->isBitField()) {
+ SemaRef.Diag(E->getMemberLoc(),
+ diag::err_omp_bit_fields_forbidden_in_clause)
+ << E->getSourceRange() << getOpenMPClauseName(OMPC_map);
return;
}
+ ImplicitMap.emplace_back(E);
+ return;
+ }
- // Define implicit data-sharing attributes for task.
- DVar = Stack->getImplicitDSA(FD, false);
- if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
- !Stack->isLoopControlVariable(FD).first)
- ImplicitFirstprivate.push_back(E);
+ auto ELoc = E->getExprLoc();
+ // OpenMP [2.9.3.6, Restrictions, p.2]
+ // A list item that appears in a reduction clause of the innermost
+ // enclosing worksharing or parallel construct may not be accessed in
+ // an explicit task.
+ DVar = Stack->hasInnermostDSA(
+ FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K);
+ },
+ /*FromParent=*/true);
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
+ ErrorFound = true;
+ SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
+ ReportOriginalDSA(SemaRef, Stack, FD, DVar);
+ return;
+ }
+
+ // Define implicit data-sharing attributes for task.
+ DVar = Stack->getImplicitDSA(FD, false);
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
+ !Stack->isLoopControlVariable(FD).first)
+ ImplicitFirstprivate.push_back(E);
+ return;
+ }
+ if (isOpenMPTargetExecutionDirective(DKind) && !FD->isBitField()) {
+ OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
+ CheckMapClauseExpressionBase(SemaRef, E, CurComponents, OMPC_map);
+ auto *VD = cast<ValueDecl>(
+ CurComponents.back().getAssociatedDeclaration()->getCanonicalDecl());
+ if (!Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [&CurComponents](
+ OMPClauseMappableExprCommon::MappableExprComponentListRef
+ StackComponents,
+ OpenMPClauseKind) {
+ auto CCI = CurComponents.rbegin();
+ auto CCE = CurComponents.rend();
+ for (const auto &SC : llvm::reverse(StackComponents)) {
+ // Do both expressions have the same kind?
+ if (CCI->getAssociatedExpression()->getStmtClass() !=
+ SC.getAssociatedExpression()->getStmtClass())
+ if (!(isa<OMPArraySectionExpr>(
+ SC.getAssociatedExpression()) &&
+ isa<ArraySubscriptExpr>(
+ CCI->getAssociatedExpression())))
+ return false;
+
+ Decl *CCD = CCI->getAssociatedDeclaration();
+ Decl *SCD = SC.getAssociatedDeclaration();
+ CCD = CCD ? CCD->getCanonicalDecl() : nullptr;
+ SCD = SCD ? SCD->getCanonicalDecl() : nullptr;
+ if (SCD != CCD)
+ return false;
+ std::advance(CCI, 1);
+ if (CCI == CCE)
+ break;
+ }
+ return true;
+ })) {
+ Visit(E->getBase());
}
} else
Visit(E->getBase());
@@ -1562,12 +2030,16 @@ public:
void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
for (auto *C : S->clauses()) {
// Skip analysis of arguments of implicitly defined firstprivate clause
- // for task directives.
- if (C && (!isa<OMPFirstprivateClause>(C) || C->getLocStart().isValid()))
+ // for task|target directives.
+ // Skip analysis of arguments of implicitly defined map clause for target
+ // directives.
+ if (C && !((isa<OMPFirstprivateClause>(C) || isa<OMPMapClause>(C)) &&
+ C->isImplicit())) {
for (auto *CC : C->children()) {
if (CC)
Visit(CC);
}
+ }
}
}
void VisitStmt(Stmt *S) {
@@ -1578,7 +2050,10 @@ public:
}
bool isErrorFound() { return ErrorFound; }
- ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; }
+ ArrayRef<Expr *> getImplicitFirstprivate() const {
+ return ImplicitFirstprivate;
+ }
+ ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; }
llvm::DenseMap<ValueDecl *, Expr *> &getVarsWithInheritedDSA() {
return VarsWithInheritedDSA;
}
@@ -1594,7 +2069,8 @@ 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_teams:
+ case OMPD_teams_distribute: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
@@ -1701,6 +2177,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(".lb.", KmpUInt64Ty),
std::make_pair(".ub.", KmpUInt64Ty), std::make_pair(".st.", KmpInt64Ty),
std::make_pair(".liter.", KmpInt32Ty),
+ std::make_pair(".reductions.",
+ Context.VoidPtrTy.withConst().withRestrict()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
@@ -1715,7 +2193,6 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_distribute_parallel_for_simd:
case OMPD_distribute_simd:
case OMPD_distribute_parallel_for:
- case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_teams_distribute_parallel_for:
@@ -1867,6 +2344,15 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
SmallVector<OMPClauseWithPreInit *, 8> PICs;
// This is required for proper codegen.
for (auto *Clause : Clauses) {
+ if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
+ Clause->getClauseKind() == OMPC_in_reduction) {
+ // Capture taskgroup task_reduction descriptors inside the tasking regions
+ // with the corresponding in_reduction items.
+ auto *IRC = cast<OMPInReductionClause>(Clause);
+ for (auto *E : IRC->taskgroup_descriptors())
+ if (E)
+ MarkDeclarationsReferencedInExpr(E);
+ }
if (isOpenMPPrivate(Clause->getClauseKind()) ||
Clause->getClauseKind() == OMPC_copyprivate ||
(getLangOpts().OpenMPUseTLS &&
@@ -2282,7 +2768,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA;
bool ErrorFound = false;
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
- if (AStmt) {
+ if (AStmt && !CurContext->isDependentContext()) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
// Check default data sharing attributes for referenced variables.
@@ -2297,13 +2783,37 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
// Generate list of implicitly defined firstprivate variables.
VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA();
- if (!DSAChecker.getImplicitFirstprivate().empty()) {
+ SmallVector<Expr *, 4> ImplicitFirstprivates(
+ DSAChecker.getImplicitFirstprivate().begin(),
+ DSAChecker.getImplicitFirstprivate().end());
+ SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(),
+ DSAChecker.getImplicitMap().end());
+ // Mark taskgroup task_reduction descriptors as implicitly firstprivate.
+ for (auto *C : Clauses) {
+ if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) {
+ for (auto *E : IRC->taskgroup_descriptors())
+ if (E)
+ ImplicitFirstprivates.emplace_back(E);
+ }
+ }
+ if (!ImplicitFirstprivates.empty()) {
if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
- DSAChecker.getImplicitFirstprivate(), SourceLocation(),
- SourceLocation(), SourceLocation())) {
+ ImplicitFirstprivates, SourceLocation(), SourceLocation(),
+ SourceLocation())) {
ClausesWithImplicit.push_back(Implicit);
ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
- DSAChecker.getImplicitFirstprivate().size();
+ ImplicitFirstprivates.size();
+ } else
+ ErrorFound = true;
+ }
+ if (!ImplicitMaps.empty()) {
+ if (OMPClause *Implicit = ActOnOpenMPMapClause(
+ OMPC_MAP_unknown, OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true,
+ SourceLocation(), SourceLocation(), ImplicitMaps,
+ SourceLocation(), SourceLocation(), SourceLocation())) {
+ ClausesWithImplicit.emplace_back(Implicit);
+ ErrorFound |=
+ cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size();
} else
ErrorFound = true;
}
@@ -2392,9 +2902,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc);
break;
case OMPD_taskgroup:
- assert(ClausesWithImplicit.empty() &&
- "No clauses are allowed for 'omp taskgroup' directive");
- Res = ActOnOpenMPTaskgroupDirective(AStmt, StartLoc, EndLoc);
+ Res = ActOnOpenMPTaskgroupDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
break;
case OMPD_flush:
assert(AStmt == nullptr &&
@@ -2946,21 +3455,6 @@ bool OpenMPIterationSpaceChecker::Dependent() const {
(Step && Step->isValueDependent());
}
-static Expr *getExprAsWritten(Expr *E) {
- if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E))
- E = ExprTemp->getSubExpr();
-
- if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- E = MTE->GetTemporaryExpr();
-
- while (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
- E = Binder->getSubExpr();
-
- if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
- E = ICE->getSubExprAsWritten();
- return E->IgnoreParens();
-}
-
bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl,
Expr *NewLCRefExpr,
Expr *NewLB) {
@@ -3004,8 +3498,8 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
if (!NewStep->isValueDependent()) {
// Check that the step is integer expression.
SourceLocation StepLoc = NewStep->getLocStart();
- ExprResult Val =
- SemaRef.PerformOpenMPImplicitIntegerConversion(StepLoc, NewStep);
+ ExprResult Val = SemaRef.PerformOpenMPImplicitIntegerConversion(
+ StepLoc, getExprAsWritten(NewStep));
if (Val.isInvalid())
return true;
NewStep = Val.get();
@@ -3142,12 +3636,8 @@ static const ValueDecl *GetInitLCDecl(Expr *E) {
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
E = CE->getArg(0)->IgnoreParenImpCasts();
if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) {
- if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
- if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
- return getCanonicalDecl(ME->getMemberDecl());
+ if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
return getCanonicalDecl(VD);
- }
}
if (auto *ME = dyn_cast_or_null<MemberExpr>(E))
if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
@@ -3832,7 +4322,7 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) {
/// Build preinits statement for the given declarations.
static Stmt *buildPreInits(ASTContext &Context,
- SmallVectorImpl<Decl *> &PreInits) {
+ MutableArrayRef<Decl *> PreInits) {
if (!PreInits.empty()) {
return new (Context) DeclStmt(
DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()),
@@ -3842,8 +4332,9 @@ static Stmt *buildPreInits(ASTContext &Context,
}
/// Build preinits statement for the given declarations.
-static Stmt *buildPreInits(ASTContext &Context,
- llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
+static Stmt *
+buildPreInits(ASTContext &Context,
+ const llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
if (!Captures.empty()) {
SmallVector<Decl *, 16> PreInits;
for (auto &Pair : Captures)
@@ -4067,7 +4558,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin();
// Build variables passed into runtime, necessary for worksharing directives.
- ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB;
+ ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB;
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind)) {
// Lower bound variable, initialized with zero.
@@ -4115,8 +4606,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// enclosing region. E.g. in 'distribute parallel for' the bounds obtained
// by scheduling 'distribute' have to be passed to the schedule of 'for'.
if (isOpenMPLoopBoundSharingDirective(DKind)) {
- auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
+ // Lower bound variable, initialized with zero.
+ VarDecl *CombLBDecl =
+ buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.lb");
+ CombLB = buildDeclRefExpr(SemaRef, CombLBDecl, VType, InitLoc);
+ SemaRef.AddInitializerToDecl(
+ CombLBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
+ /*DirectInit*/ false);
+
+ // Upper bound variable, initialized with last iteration number.
+ VarDecl *CombUBDecl =
+ buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.ub");
+ CombUB = buildDeclRefExpr(SemaRef, CombUBDecl, VType, InitLoc);
+ SemaRef.AddInitializerToDecl(CombUBDecl, LastIteration.get(),
+ /*DirectInit*/ false);
+
+ ExprResult CombIsUBGreater = SemaRef.BuildBinOp(
+ CurScope, InitLoc, BO_GT, CombUB.get(), LastIteration.get());
+ ExprResult CombCondOp =
+ SemaRef.ActOnConditionalOp(InitLoc, InitLoc, CombIsUBGreater.get(),
+ LastIteration.get(), CombUB.get());
+ CombEUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, CombUB.get(),
+ CombCondOp.get());
+ CombEUB = SemaRef.ActOnFinishFullExpr(CombEUB.get());
+
+ auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
// We expect to have at least 2 more parameters than the 'parallel'
// directive does - the lower and upper bounds of the previous schedule.
assert(CD->getNumParams() >= 4 &&
@@ -4138,7 +4653,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// Build the iteration variable and its initialization before loop.
ExprResult IV;
- ExprResult Init;
+ ExprResult Init, CombInit;
{
VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv");
IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc);
@@ -4149,6 +4664,18 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS);
Init = SemaRef.ActOnFinishFullExpr(Init.get());
+
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ Expr *CombRHS =
+ (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind))
+ ? CombLB.get()
+ : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
+ CombInit =
+ SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), CombRHS);
+ CombInit = SemaRef.ActOnFinishFullExpr(CombInit.get());
+ }
}
// Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
@@ -4159,7 +4686,11 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
NumIterations.get());
-
+ ExprResult CombCond;
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ CombCond =
+ SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get());
+ }
// Loop increment (IV = IV + 1)
SourceLocation IncLoc;
ExprResult Inc =
@@ -4174,7 +4705,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// Increments for worksharing loops (LB = LB + ST; UB = UB + ST).
// Used for directives with static scheduling.
- ExprResult NextLB, NextUB;
+ // In combined construct, add combined version that use CombLB and CombUB
+ // base variables for the update
+ ExprResult NextLB, NextUB, CombNextLB, CombNextUB;
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind)) {
// LB + ST
@@ -4197,9 +4730,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get());
if (!NextUB.isUsable())
return 0;
- }
-
- // Create: increment expression for distribute loop when combined in a same
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ CombNextLB =
+ SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombLB.get(), ST.get());
+ if (!NextLB.isUsable())
+ return 0;
+ // LB = LB + ST
+ CombNextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombLB.get(),
+ CombNextLB.get());
+ CombNextLB = SemaRef.ActOnFinishFullExpr(CombNextLB.get());
+ if (!CombNextLB.isUsable())
+ return 0;
+ // UB + ST
+ CombNextUB =
+ SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombUB.get(), ST.get());
+ if (!CombNextUB.isUsable())
+ return 0;
+ // UB = UB + ST
+ CombNextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombUB.get(),
+ CombNextUB.get());
+ CombNextUB = SemaRef.ActOnFinishFullExpr(CombNextUB.get());
+ if (!CombNextUB.isUsable())
+ return 0;
+ }
+ }
+
+ // Create increment expression for distribute loop when combined in a same
// directive with for as IV = IV + ST; ensure upper bound expression based
// on PrevUB instead of NumIterations - used to implement 'for' when found
// in combination with 'distribute', like in 'distribute parallel for'
@@ -4345,6 +4901,13 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.PrevUB = PrevUB.get();
Built.DistInc = DistInc.get();
Built.PrevEUB = PrevEUB.get();
+ Built.DistCombinedFields.LB = CombLB.get();
+ Built.DistCombinedFields.UB = CombUB.get();
+ Built.DistCombinedFields.EUB = CombEUB.get();
+ Built.DistCombinedFields.Init = CombInit.get();
+ Built.DistCombinedFields.Cond = CombCond.get();
+ Built.DistCombinedFields.NLB = CombNextLB.get();
+ Built.DistCombinedFields.NUB = CombNextUB.get();
Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get();
// Fill data for doacross depend clauses.
@@ -4889,7 +5452,8 @@ StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc,
return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc);
}
-StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt,
+StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
@@ -4899,7 +5463,9 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt,
getCurFunction()->setHasBranchProtectedScope();
- return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, AStmt);
+ return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt,
+ DSAStack->getTaskgroupReductionRef());
}
StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
@@ -5774,16 +6340,17 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
B, DSAStack->isCancelRegion());
}
-/// \brief Check for existence of a map clause in the list of clauses.
-static bool HasMapClause(ArrayRef<OMPClause *> Clauses) {
- for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
- I != E; ++I) {
- if (*I != nullptr && (*I)->getClauseKind() == OMPC_map) {
- return true;
- }
- }
+/// Check for existence of a map clause in the list of clauses.
+static bool hasClauses(ArrayRef<OMPClause *> Clauses,
+ const OpenMPClauseKind K) {
+ return llvm::any_of(
+ Clauses, [K](const OMPClause *C) { return C->getClauseKind() == K; });
+}
- return false;
+template <typename... Params>
+static bool hasClauses(ArrayRef<OMPClause *> Clauses, const OpenMPClauseKind K,
+ const Params... ClauseTypes) {
+ return hasClauses(Clauses, K) || hasClauses(Clauses, ClauseTypes...);
}
StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
@@ -5797,8 +6364,9 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
// OpenMP [2.10.1, Restrictions, p. 97]
// At least one map clause must appear on the directive.
- if (!HasMapClause(Clauses)) {
- Diag(StartLoc, diag::err_omp_no_map_for_directive)
+ if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) {
+ Diag(StartLoc, diag::err_omp_no_clause_for_directive)
+ << "'map' or 'use_device_ptr'"
<< getOpenMPDirectiveName(OMPD_target_data);
return StmtError();
}
@@ -5815,9 +6383,9 @@ Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation EndLoc) {
// OpenMP [2.10.2, Restrictions, p. 99]
// At least one map clause must appear on the directive.
- if (!HasMapClause(Clauses)) {
- Diag(StartLoc, diag::err_omp_no_map_for_directive)
- << getOpenMPDirectiveName(OMPD_target_enter_data);
+ if (!hasClauses(Clauses, OMPC_map)) {
+ Diag(StartLoc, diag::err_omp_no_clause_for_directive)
+ << "'map'" << getOpenMPDirectiveName(OMPD_target_enter_data);
return StmtError();
}
@@ -5831,9 +6399,9 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation EndLoc) {
// OpenMP [2.10.3, Restrictions, p. 102]
// At least one map clause must appear on the directive.
- if (!HasMapClause(Clauses)) {
- Diag(StartLoc, diag::err_omp_no_map_for_directive)
- << getOpenMPDirectiveName(OMPD_target_exit_data);
+ if (!hasClauses(Clauses, OMPC_map)) {
+ Diag(StartLoc, diag::err_omp_no_clause_for_directive)
+ << "'map'" << getOpenMPDirectiveName(OMPD_target_exit_data);
return StmtError();
}
@@ -5843,12 +6411,7 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- bool seenMotionClause = false;
- for (auto *C : Clauses) {
- if (C->getClauseKind() == OMPC_to || C->getClauseKind() == OMPC_from)
- seenMotionClause = true;
- }
- if (!seenMotionClause) {
+ if (!hasClauses(Clauses, OMPC_to, OMPC_from)) {
Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required);
return StmtError();
}
@@ -5931,6 +6494,33 @@ static bool checkGrainsizeNumTasksClauses(Sema &S,
return ErrorFound;
}
+static bool checkReductionClauseWithNogroup(Sema &S,
+ ArrayRef<OMPClause *> Clauses) {
+ OMPClause *ReductionClause = nullptr;
+ OMPClause *NogroupClause = nullptr;
+ for (auto *C : Clauses) {
+ if (C->getClauseKind() == OMPC_reduction) {
+ ReductionClause = C;
+ if (NogroupClause)
+ break;
+ continue;
+ }
+ if (C->getClauseKind() == OMPC_nogroup) {
+ NogroupClause = C;
+ if (ReductionClause)
+ break;
+ continue;
+ }
+ }
+ if (ReductionClause && NogroupClause) {
+ S.Diag(ReductionClause->getLocStart(), diag::err_omp_reduction_with_nogroup)
+ << SourceRange(NogroupClause->getLocStart(),
+ NogroupClause->getLocEnd());
+ return true;
+ }
+ return false;
+}
+
StmtResult Sema::ActOnOpenMPTaskLoopDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
@@ -5957,6 +6547,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective(
// not appear on the same taskloop directive.
if (checkGrainsizeNumTasksClauses(*this, Clauses))
return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
getCurFunction()->setHasBranchProtectedScope();
return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc,
@@ -6000,6 +6595,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
// not appear on the same taskloop directive.
if (checkGrainsizeNumTasksClauses(*this, Clauses))
return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
getCurFunction()->setHasBranchProtectedScope();
return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc,
@@ -6637,6 +7237,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -6940,6 +7542,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_default:
case OMPC_proc_bind:
@@ -7255,6 +7859,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7412,6 +8018,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7609,6 +8217,8 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7721,6 +8331,16 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
EndLoc, ReductionIdScopeSpec, ReductionId);
break;
+ case OMPC_task_reduction:
+ Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionIdScopeSpec,
+ ReductionId);
+ break;
+ case OMPC_in_reduction:
+ Res =
+ ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionIdScopeSpec, ReductionId);
+ break;
case OMPC_linear:
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
LinKind, DepLinMapLoc, ColonLoc, EndLoc);
@@ -7872,7 +8492,8 @@ getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
}
return std::make_pair(nullptr, false);
}
- return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false);
+ return std::make_pair(
+ getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
}
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
@@ -8074,13 +8695,18 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (!IsImplicitClause) {
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
TopDVar = DVar;
+ OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
bool IsConstant = ElemType.isConstant(Context);
// OpenMP [2.4.13, Data-sharing Attribute Clauses]
// A list item that specifies a given variable may not appear in more
// than one clause on the same directive, except that a variable may be
// specified in both firstprivate and lastprivate clauses.
+ // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
+ // A list item may appear in a firstprivate or lastprivate clause but not
+ // both.
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
- DVar.CKind != OMPC_lastprivate && DVar.RefExpr) {
+ (CurrDir == OMPD_distribute || DVar.CKind != OMPC_lastprivate) &&
+ DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
@@ -8108,18 +8734,29 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
continue;
}
- OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.9.3.4, Restrictions, p.2]
// A list item that is private within a parallel region must not appear
// in a firstprivate clause on a worksharing construct if any of the
// worksharing regions arising from the worksharing construct ever bind
// to any of the parallel regions arising from the parallel construct.
- if (isOpenMPWorksharingDirective(CurrDir) &&
+ // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
+ // A list item that is private within a teams region must not appear in a
+ // firstprivate clause on a distribute construct if any of the distribute
+ // regions arising from the distribute construct ever bind to any of the
+ // teams regions arising from the teams construct.
+ // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
+ // A list item that appears in a reduction clause of a teams construct
+ // must not appear in a firstprivate clause on a distribute construct if
+ // any of the distribute regions arising from the distribute construct
+ // ever bind to any of the teams regions arising from the teams construct.
+ if ((isOpenMPWorksharingDirective(CurrDir) ||
+ isOpenMPDistributeDirective(CurrDir)) &&
!isOpenMPParallelDirective(CurrDir) &&
!isOpenMPTeamsDirective(CurrDir)) {
DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared &&
(isOpenMPParallelDirective(DVar.DKind) ||
+ isOpenMPTeamsDirective(DVar.DKind) ||
DVar.DKind == OMPD_unknown)) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_firstprivate)
@@ -8144,12 +8781,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
[](OpenMPDirectiveKind K) -> bool {
return isOpenMPParallelDirective(K) ||
- isOpenMPWorksharingDirective(K);
+ isOpenMPWorksharingDirective(K) ||
+ isOpenMPTeamsDirective(K);
},
- false);
+ /*FromParent=*/true);
if (DVar.CKind == OMPC_reduction &&
(isOpenMPParallelDirective(DVar.DKind) ||
- isOpenMPWorksharingDirective(DVar.DKind))) {
+ isOpenMPWorksharingDirective(DVar.DKind) ||
+ isOpenMPTeamsDirective(DVar.DKind))) {
Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate)
<< getOpenMPDirectiveName(DVar.DKind);
ReportOriginalDSA(*this, DSAStack, D, DVar);
@@ -8157,50 +8796,6 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
}
}
- // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
- // A list item that is private within a teams region must not appear in a
- // firstprivate clause on a distribute construct if any of the distribute
- // regions arising from the distribute construct ever bind to any of the
- // teams regions arising from the teams construct.
- // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
- // A list item that appears in a reduction clause of a teams construct
- // must not appear in a firstprivate clause on a distribute construct if
- // any of the distribute regions arising from the distribute construct
- // ever bind to any of the teams regions arising from the teams construct.
- // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
- // A list item may appear in a firstprivate or lastprivate clause but not
- // both.
- if (CurrDir == OMPD_distribute) {
- DVar = DSAStack->hasInnermostDSA(
- D, [](OpenMPClauseKind C) -> bool { return C == OMPC_private; },
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPTeamsDirective(K);
- },
- false);
- if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) {
- Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- DVar = DSAStack->hasInnermostDSA(
- D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPTeamsDirective(K);
- },
- false);
- if (DVar.CKind == OMPC_reduction &&
- isOpenMPTeamsDirective(DVar.DKind)) {
- Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- DVar = DSAStack->getTopDSA(D, false);
- if (DVar.CKind == OMPC_lastprivate) {
- Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- }
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
@@ -8360,14 +8955,18 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
continue;
Type = Type.getNonReferenceType();
+ OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below.
+ // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
+ // A list item may appear in a firstprivate or lastprivate clause but not
+ // both.
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
- DVar.CKind != OMPC_firstprivate &&
+ (CurrDir == OMPD_distribute || DVar.CKind != OMPC_firstprivate) &&
(DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
@@ -8376,7 +8975,6 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
continue;
}
- OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.14.3.5, Restrictions, p.2]
// A list item that is private within a parallel region, or that appears in
// the reduction clause of a parallel construct, must not appear in a
@@ -8397,18 +8995,6 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
}
}
- // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
- // A list item may appear in a firstprivate or lastprivate clause but not
- // both.
- if (CurrDir == OMPD_distribute) {
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
- if (DVar.CKind == OMPC_firstprivate) {
- Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- }
-
// OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
// A variable of class type (or array thereof) that appears in a
// lastprivate clause requires an accessible, unambiguous default
@@ -8545,7 +9131,7 @@ public:
return true;
DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(
VD, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; },
- false);
+ /*FromParent=*/true);
if (DVarPrivate.CKind != OMPC_unknown)
return true;
return false;
@@ -8633,7 +9219,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
PrevD = D;
}
}
- if (Ty->isDependentType() || Ty->isInstantiationDependentType() ||
+ if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() ||
+ Ty->isInstantiationDependentType() ||
Ty->containsUnexpandedParameterPack() ||
filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) -> bool {
return !D->isInvalidDecl() &&
@@ -8689,15 +9276,134 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
return ExprEmpty();
}
-OMPClause *Sema::ActOnOpenMPReductionClause(
+namespace {
+/// Data for the reduction-based clauses.
+struct ReductionData {
+ /// List of original reduction items.
+ SmallVector<Expr *, 8> Vars;
+ /// List of private copies of the reduction items.
+ SmallVector<Expr *, 8> Privates;
+ /// LHS expressions for the reduction_op expressions.
+ SmallVector<Expr *, 8> LHSs;
+ /// RHS expressions for the reduction_op expressions.
+ SmallVector<Expr *, 8> RHSs;
+ /// Reduction operation expression.
+ SmallVector<Expr *, 8> ReductionOps;
+ /// Taskgroup descriptors for the corresponding reduction items in
+ /// in_reduction clauses.
+ SmallVector<Expr *, 8> TaskgroupDescriptors;
+ /// List of captures for clause.
+ SmallVector<Decl *, 4> ExprCaptures;
+ /// List of postupdate expressions.
+ SmallVector<Expr *, 4> ExprPostUpdates;
+ ReductionData() = delete;
+ /// Reserves required memory for the reduction data.
+ ReductionData(unsigned Size) {
+ Vars.reserve(Size);
+ Privates.reserve(Size);
+ LHSs.reserve(Size);
+ RHSs.reserve(Size);
+ ReductionOps.reserve(Size);
+ TaskgroupDescriptors.reserve(Size);
+ ExprCaptures.reserve(Size);
+ ExprPostUpdates.reserve(Size);
+ }
+ /// Stores reduction item and reduction operation only (required for dependent
+ /// reduction item).
+ void push(Expr *Item, Expr *ReductionOp) {
+ Vars.emplace_back(Item);
+ Privates.emplace_back(nullptr);
+ LHSs.emplace_back(nullptr);
+ RHSs.emplace_back(nullptr);
+ ReductionOps.emplace_back(ReductionOp);
+ TaskgroupDescriptors.emplace_back(nullptr);
+ }
+ /// Stores reduction data.
+ void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp,
+ Expr *TaskgroupDescriptor) {
+ Vars.emplace_back(Item);
+ Privates.emplace_back(Private);
+ LHSs.emplace_back(LHS);
+ RHSs.emplace_back(RHS);
+ ReductionOps.emplace_back(ReductionOp);
+ TaskgroupDescriptors.emplace_back(TaskgroupDescriptor);
+ }
+};
+} // namespace
+
+static bool CheckOMPArraySectionConstantForReduction(
+ ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement,
+ SmallVectorImpl<llvm::APSInt> &ArraySizes) {
+ const Expr *Length = OASE->getLength();
+ if (Length == nullptr) {
+ // For array sections of the form [1:] or [:], we would need to analyze
+ // the lower bound...
+ if (OASE->getColonLoc().isValid())
+ return false;
+
+ // This is an array subscript which has implicit length 1!
+ SingleElement = true;
+ ArraySizes.push_back(llvm::APSInt::get(1));
+ } else {
+ llvm::APSInt ConstantLengthValue;
+ if (!Length->EvaluateAsInt(ConstantLengthValue, Context))
+ return false;
+
+ SingleElement = (ConstantLengthValue.getSExtValue() == 1);
+ ArraySizes.push_back(ConstantLengthValue);
+ }
+
+ // Get the base of this array section and walk up from there.
+ const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
+
+ // We require length = 1 for all array sections except the right-most to
+ // guarantee that the memory region is contiguous and has no holes in it.
+ while (const auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) {
+ Length = TempOASE->getLength();
+ if (Length == nullptr) {
+ // For array sections of the form [1:] or [:], we would need to analyze
+ // the lower bound...
+ if (OASE->getColonLoc().isValid())
+ return false;
+
+ // This is an array subscript which has implicit length 1!
+ ArraySizes.push_back(llvm::APSInt::get(1));
+ } else {
+ llvm::APSInt ConstantLengthValue;
+ if (!Length->EvaluateAsInt(ConstantLengthValue, Context) ||
+ ConstantLengthValue.getSExtValue() != 1)
+ return false;
+
+ ArraySizes.push_back(ConstantLengthValue);
+ }
+ Base = TempOASE->getBase()->IgnoreParenImpCasts();
+ }
+
+ // If we have a single element, we don't need to add the implicit lengths.
+ if (!SingleElement) {
+ while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) {
+ // Has implicit length 1!
+ ArraySizes.push_back(llvm::APSInt::get(1));
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ }
+ }
+
+ // This array section can be privatized as a single value or as a constant
+ // sized array.
+ return true;
+}
+
+static bool ActOnOMPReductionKindClause(
+ Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind,
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
- ArrayRef<Expr *> UnresolvedReductions) {
+ ArrayRef<Expr *> UnresolvedReductions, ReductionData &RD) {
auto DN = ReductionId.getName();
auto OOK = DN.getCXXOverloadedOperator();
BinaryOperatorKind BOK = BO_Comma;
+ ASTContext &Context = S.Context;
// OpenMP [2.14.3.6, reduction clause]
// C
// reduction-identifier is either an identifier or one of the following
@@ -8705,7 +9411,6 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// C++
// reduction-identifier is either an id-expression or one of the following
// operators: +, -, *, &, |, ^, && and ||
- // FIXME: Only 'min' and 'max' identifiers are supported for now.
switch (OOK) {
case OO_Plus:
case OO_Minus:
@@ -8768,7 +9473,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("Unexpected reduction identifier");
case OO_None:
- if (auto II = DN.getAsIdentifierInfo()) {
+ if (auto *II = DN.getAsIdentifierInfo()) {
if (II->isStr("max"))
BOK = BO_GT;
else if (II->isStr("min"))
@@ -8779,15 +9484,10 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
SourceRange ReductionIdRange;
if (ReductionIdScopeSpec.isValid())
ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
+ else
+ ReductionIdRange.setBegin(ReductionId.getBeginLoc());
ReductionIdRange.setEnd(ReductionId.getEndLoc());
- SmallVector<Expr *, 8> Vars;
- SmallVector<Expr *, 8> Privates;
- SmallVector<Expr *, 8> LHSs;
- SmallVector<Expr *, 8> RHSs;
- SmallVector<Expr *, 8> ReductionOps;
- SmallVector<Decl *, 4> ExprCaptures;
- SmallVector<Expr *, 4> ExprPostUpdates;
auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end();
bool FirstIter = true;
for (auto RefExpr : VarList) {
@@ -8805,32 +9505,29 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
- auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
/*AllowArraySection=*/true);
if (Res.second) {
- // It will be analyzed later.
- Vars.push_back(RefExpr);
- Privates.push_back(nullptr);
- LHSs.push_back(nullptr);
- RHSs.push_back(nullptr);
// Try to find 'declare reduction' corresponding construct before using
// builtin/overloaded operators.
QualType Type = Context.DependentTy;
CXXCastPath BasePath;
ExprResult DeclareReductionRef = buildDeclareReductionRef(
- *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec,
ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
- if (CurContext->isDependentContext() &&
+ Expr *ReductionOp = nullptr;
+ if (S.CurContext->isDependentContext() &&
(DeclareReductionRef.isUnset() ||
isa<UnresolvedLookupExpr>(DeclareReductionRef.get())))
- ReductionOps.push_back(DeclareReductionRef.get());
- else
- ReductionOps.push_back(nullptr);
+ ReductionOp = DeclareReductionRef.get();
+ // It will be analyzed later.
+ RD.push(RefExpr, ReductionOp);
}
ValueDecl *D = Res.first;
if (!D)
continue;
+ Expr *TaskgroupDescriptor = nullptr;
QualType Type;
auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens());
auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens());
@@ -8850,21 +9547,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
- if (RequireCompleteType(ELoc, Type,
- diag::err_omp_reduction_incomplete_type))
+ if (S.RequireCompleteType(ELoc, Type,
+ diag::err_omp_reduction_incomplete_type))
continue;
// OpenMP [2.14.3.6, reduction clause, Restrictions]
// A list item that appears in a reduction clause must not be
// const-qualified.
if (Type.getNonReferenceType().isConstant(Context)) {
- Diag(ELoc, diag::err_omp_const_reduction_list_item)
- << getOpenMPClauseName(OMPC_reduction) << Type << ERange;
+ S.Diag(ELoc, diag::err_omp_const_reduction_list_item) << ERange;
if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
@@ -8875,10 +9570,11 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
if (!ASE && !OASE && VD) {
VarDecl *VDDef = VD->getDefinition();
if (VD->getType()->isReferenceType() && VDDef && VDDef->hasInit()) {
- DSARefChecker Check(DSAStack);
+ DSARefChecker Check(Stack);
if (Check.Visit(VDDef->getInit())) {
- Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange;
- Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
+ S.Diag(ELoc, diag::err_omp_reduction_ref_type_arg)
+ << getOpenMPClauseName(ClauseKind) << ERange;
+ S.Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
continue;
}
}
@@ -8896,17 +9592,18 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// but a list item can appear only once in the reduction clauses for that
// directive.
DSAStackTy::DSAVarData DVar;
- DVar = DSAStack->getTopDSA(D, false);
+ DVar = Stack->getTopDSA(D, false);
if (DVar.CKind == OMPC_reduction) {
- Diag(ELoc, diag::err_omp_once_referenced)
- << getOpenMPClauseName(OMPC_reduction);
+ S.Diag(ELoc, diag::err_omp_once_referenced)
+ << getOpenMPClauseName(ClauseKind);
if (DVar.RefExpr)
- Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
+ S.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
+ continue;
} else if (DVar.CKind != OMPC_unknown) {
- Diag(ELoc, diag::err_omp_wrong_dsa)
+ S.Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_reduction);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
+ ReportOriginalDSA(S, Stack, D, DVar);
continue;
}
@@ -8914,16 +9611,16 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// A list item that appears in a reduction clause of a worksharing
// construct must be shared in the parallel regions to which any of the
// worksharing regions arising from the worksharing construct bind.
- OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
+ OpenMPDirectiveKind CurrDir = Stack->getCurrentDirective();
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir) &&
!isOpenMPTeamsDirective(CurrDir)) {
- DVar = DSAStack->getImplicitDSA(D, true);
+ DVar = Stack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared) {
- Diag(ELoc, diag::err_omp_required_access)
+ S.Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_reduction)
<< getOpenMPClauseName(OMPC_shared);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
+ ReportOriginalDSA(S, Stack, D, DVar);
continue;
}
}
@@ -8932,24 +9629,20 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// builtin/overloaded operators.
CXXCastPath BasePath;
ExprResult DeclareReductionRef = buildDeclareReductionRef(
- *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec,
ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
if (DeclareReductionRef.isInvalid())
continue;
- if (CurContext->isDependentContext() &&
+ if (S.CurContext->isDependentContext() &&
(DeclareReductionRef.isUnset() ||
isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) {
- Vars.push_back(RefExpr);
- Privates.push_back(nullptr);
- LHSs.push_back(nullptr);
- RHSs.push_back(nullptr);
- ReductionOps.push_back(DeclareReductionRef.get());
+ RD.push(RefExpr, DeclareReductionRef.get());
continue;
}
if (BOK == BO_Comma && DeclareReductionRef.isUnset()) {
// Not allowed reduction identifier is found.
- Diag(ReductionId.getLocStart(),
- diag::err_omp_unknown_reduction_identifier)
+ S.Diag(ReductionId.getLocStart(),
+ diag::err_omp_unknown_reduction_identifier)
<< Type << ReductionIdRange;
continue;
}
@@ -8965,28 +9658,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
if (DeclareReductionRef.isUnset()) {
if ((BOK == BO_GT || BOK == BO_LT) &&
!(Type->isScalarType() ||
- (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
- Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
- << getLangOpts().CPlusPlus;
+ (S.getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
+ S.Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
+ << getOpenMPClauseName(ClauseKind) << S.getLangOpts().CPlusPlus;
if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
}
if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
- !getLangOpts().CPlusPlus && Type->isFloatingType()) {
- Diag(ELoc, diag::err_omp_clause_floating_type_arg);
+ !S.getLangOpts().CPlusPlus && Type->isFloatingType()) {
+ S.Diag(ELoc, diag::err_omp_clause_floating_type_arg)
+ << getOpenMPClauseName(ClauseKind);
if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
@@ -8994,12 +9686,31 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
}
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
- auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs",
+ auto *LHSVD = buildVarDecl(S, ELoc, Type, ".reduction.lhs",
D->hasAttrs() ? &D->getAttrs() : nullptr);
- auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(),
+ auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr);
auto PrivateTy = Type;
- if (OASE ||
+
+ // Try if we can determine constant lengths for all array sections and avoid
+ // the VLA.
+ bool ConstantLengthOASE = false;
+ if (OASE) {
+ bool SingleElement;
+ llvm::SmallVector<llvm::APSInt, 4> ArraySizes;
+ ConstantLengthOASE = CheckOMPArraySectionConstantForReduction(
+ Context, OASE, SingleElement, ArraySizes);
+
+ // If we don't have a single element, we must emit a constant array type.
+ if (ConstantLengthOASE && !SingleElement) {
+ for (auto &Size : ArraySizes) {
+ PrivateTy = Context.getConstantArrayType(
+ PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ }
+ }
+ }
+
+ if ((OASE && !ConstantLengthOASE) ||
(!ASE &&
D->getType().getNonReferenceType()->isVariablyModifiedType())) {
// For arrays/array sections only:
@@ -9008,19 +9719,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// For array subscripts or single variables Private Ty is the same as Type
// (type of the variable or single array element).
PrivateTy = Context.getVariableArrayType(
- Type, new (Context) OpaqueValueExpr(SourceLocation(),
- Context.getSizeType(), VK_RValue),
+ Type,
+ new (Context) OpaqueValueExpr(ELoc, Context.getSizeType(), VK_RValue),
ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange());
} else if (!ASE && !OASE &&
Context.getAsArrayType(D->getType().getNonReferenceType()))
PrivateTy = D->getType().getNonReferenceType();
// Private copy.
- auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, D->getName(),
+ auto *PrivateVD = buildVarDecl(S, ELoc, PrivateTy, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr);
// Add initializer for private variable.
Expr *Init = nullptr;
- auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
- auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
+ auto *LHSDRE = buildDeclRefExpr(S, LHSVD, Type, ELoc);
+ auto *RHSDRE = buildDeclRefExpr(S, RHSVD, Type, ELoc);
if (DeclareReductionRef.isUsable()) {
auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>();
auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl());
@@ -9037,13 +9748,13 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
case BO_LOr:
// '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
if (Type->isScalarType() || Type->isAnyComplexType())
- Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
+ Init = S.ActOnIntegerConstant(ELoc, /*Val=*/0).get();
break;
case BO_Mul:
case BO_LAnd:
if (Type->isScalarType() || Type->isAnyComplexType()) {
// '*' and '&&' reduction ops - initializer is '1'.
- Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get();
+ Init = S.ActOnIntegerConstant(ELoc, /*Val=*/1).get();
}
break;
case BO_And: {
@@ -9066,7 +9777,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
if (Init && OrigType->isAnyComplexType()) {
// Init = 0xFFFF + 0xFFFFi;
auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
- Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
+ Init = S.CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
}
Type = OrigType;
break;
@@ -9083,17 +9794,15 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
QualType IntTy =
Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
llvm::APInt InitValue =
- (BOK != BO_LT)
- ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
- : llvm::APInt::getMinValue(Size)
- : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
- : llvm::APInt::getMaxValue(Size);
+ (BOK != BO_LT) ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
+ : llvm::APInt::getMinValue(Size)
+ : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
+ : llvm::APInt::getMaxValue(Size);
Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
if (Type->isPointerType()) {
// Cast to pointer type.
- auto CastExpr = BuildCStyleCastExpr(
- SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
- SourceLocation(), Init);
+ auto CastExpr = S.BuildCStyleCastExpr(
+ ELoc, Context.getTrivialTypeSourceInfo(Type, ELoc), ELoc, Init);
if (CastExpr.isInvalid())
continue;
Init = CastExpr.get();
@@ -9132,20 +9841,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
llvm_unreachable("Unexpected reduction operation");
}
}
- if (Init && DeclareReductionRef.isUnset()) {
- AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false);
- } else if (!Init)
- ActOnUninitializedDecl(RHSVD);
+ if (Init && DeclareReductionRef.isUnset())
+ S.AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false);
+ else if (!Init)
+ S.ActOnUninitializedDecl(RHSVD);
if (RHSVD->isInvalidDecl())
continue;
if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
- Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
- << ReductionIdRange;
- bool IsDecl =
- !VD ||
- VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible)
+ << Type << ReductionIdRange;
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
continue;
}
@@ -9153,16 +9861,16 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// codegen.
PrivateVD->setInit(RHSVD->getInit());
PrivateVD->setInitStyle(RHSVD->getInitStyle());
- auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc);
+ auto *PrivateDRE = buildDeclRefExpr(S, PrivateVD, PrivateTy, ELoc);
ExprResult ReductionOp;
if (DeclareReductionRef.isUsable()) {
QualType RedTy = DeclareReductionRef.get()->getType();
QualType PtrRedTy = Context.getPointerType(RedTy);
- ExprResult LHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE);
- ExprResult RHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE);
+ ExprResult LHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE);
+ ExprResult RHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE);
if (!BasePath.empty()) {
- LHS = DefaultLvalueConversion(LHS.get());
- RHS = DefaultLvalueConversion(RHS.get());
+ LHS = S.DefaultLvalueConversion(LHS.get());
+ RHS = S.DefaultLvalueConversion(RHS.get());
LHS = ImplicitCastExpr::Create(Context, PtrRedTy,
CK_UncheckedDerivedToBase, LHS.get(),
&BasePath, LHS.get()->getValueKind());
@@ -9175,76 +9883,196 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
QualType FnTy = Context.getFunctionType(Context.VoidTy, Params, EPI);
auto *OVE = new (Context) OpaqueValueExpr(
ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary,
- DefaultLvalueConversion(DeclareReductionRef.get()).get());
+ S.DefaultLvalueConversion(DeclareReductionRef.get()).get());
Expr *Args[] = {LHS.get(), RHS.get()};
ReductionOp = new (Context)
CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc);
} else {
- ReductionOp = BuildBinOp(DSAStack->getCurScope(),
- ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE);
+ ReductionOp = S.BuildBinOp(
+ Stack->getCurScope(), ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE);
if (ReductionOp.isUsable()) {
if (BOK != BO_LT && BOK != BO_GT) {
ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ReductionOp.get());
+ S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ReductionOp.get());
} else {
- auto *ConditionalOp = new (Context) ConditionalOperator(
- ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
- RHSDRE, Type, VK_LValue, OK_Ordinary);
+ auto *ConditionalOp = new (Context)
+ ConditionalOperator(ReductionOp.get(), ELoc, LHSDRE, ELoc, RHSDRE,
+ Type, VK_LValue, OK_Ordinary);
ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ConditionalOp);
+ S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ConditionalOp);
}
- ReductionOp = ActOnFinishFullExpr(ReductionOp.get());
+ if (ReductionOp.isUsable())
+ ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get());
}
- if (ReductionOp.isInvalid())
+ if (!ReductionOp.isUsable())
continue;
}
+ // OpenMP [2.15.4.6, Restrictions, p.2]
+ // A list item that appears in an in_reduction clause of a task construct
+ // must appear in a task_reduction clause of a construct associated with a
+ // taskgroup region that includes the participating task in its taskgroup
+ // set. The construct associated with the innermost region that meets this
+ // condition must specify the same reduction-identifier as the in_reduction
+ // clause.
+ if (ClauseKind == OMPC_in_reduction) {
+ SourceRange ParentSR;
+ BinaryOperatorKind ParentBOK;
+ const Expr *ParentReductionOp;
+ Expr *ParentBOKTD, *ParentReductionOpTD;
+ DSAStackTy::DSAVarData ParentBOKDSA =
+ Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK,
+ ParentBOKTD);
+ DSAStackTy::DSAVarData ParentReductionOpDSA =
+ Stack->getTopMostTaskgroupReductionData(
+ D, ParentSR, ParentReductionOp, ParentReductionOpTD);
+ bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown;
+ bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown;
+ if (!IsParentBOK && !IsParentReductionOp) {
+ S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction);
+ continue;
+ }
+ if ((DeclareReductionRef.isUnset() && IsParentReductionOp) ||
+ (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK ||
+ IsParentReductionOp) {
+ bool EmitError = true;
+ if (IsParentReductionOp && DeclareReductionRef.isUsable()) {
+ llvm::FoldingSetNodeID RedId, ParentRedId;
+ ParentReductionOp->Profile(ParentRedId, Context, /*Canonical=*/true);
+ DeclareReductionRef.get()->Profile(RedId, Context,
+ /*Canonical=*/true);
+ EmitError = RedId != ParentRedId;
+ }
+ if (EmitError) {
+ S.Diag(ReductionId.getLocStart(),
+ diag::err_omp_reduction_identifier_mismatch)
+ << ReductionIdRange << RefExpr->getSourceRange();
+ S.Diag(ParentSR.getBegin(),
+ diag::note_omp_previous_reduction_identifier)
+ << ParentSR
+ << (IsParentBOK ? ParentBOKDSA.RefExpr
+ : ParentReductionOpDSA.RefExpr)
+ ->getSourceRange();
+ continue;
+ }
+ }
+ TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD;
+ assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined.");
+ }
+
DeclRefExpr *Ref = nullptr;
Expr *VarsExpr = RefExpr->IgnoreParens();
- if (!VD && !CurContext->isDependentContext()) {
+ if (!VD && !S.CurContext->isDependentContext()) {
if (ASE || OASE) {
- TransformExprToCaptures RebuildToCapture(*this, D);
+ TransformExprToCaptures RebuildToCapture(S, D);
VarsExpr =
RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get();
Ref = RebuildToCapture.getCapturedExpr();
} else {
- VarsExpr = Ref =
- buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ VarsExpr = Ref = buildCapture(S, D, SimpleRefExpr, /*WithInit=*/false);
}
- if (!IsOpenMPCapturedDecl(D)) {
- ExprCaptures.push_back(Ref->getDecl());
+ if (!S.IsOpenMPCapturedDecl(D)) {
+ RD.ExprCaptures.emplace_back(Ref->getDecl());
if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
- ExprResult RefRes = DefaultLvalueConversion(Ref);
+ ExprResult RefRes = S.DefaultLvalueConversion(Ref);
if (!RefRes.isUsable())
continue;
ExprResult PostUpdateRes =
- BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign,
- SimpleRefExpr, RefRes.get());
+ S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr,
+ RefRes.get());
if (!PostUpdateRes.isUsable())
continue;
- ExprPostUpdates.push_back(
- IgnoredValueConversions(PostUpdateRes.get()).get());
+ if (isOpenMPTaskingDirective(Stack->getCurrentDirective()) ||
+ Stack->getCurrentDirective() == OMPD_taskgroup) {
+ S.Diag(RefExpr->getExprLoc(),
+ diag::err_omp_reduction_non_addressable_expression)
+ << RefExpr->getSourceRange();
+ continue;
+ }
+ RD.ExprPostUpdates.emplace_back(
+ S.IgnoredValueConversions(PostUpdateRes.get()).get());
}
}
}
- DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
- Vars.push_back(VarsExpr);
- Privates.push_back(PrivateDRE);
- LHSs.push_back(LHSDRE);
- RHSs.push_back(RHSDRE);
- ReductionOps.push_back(ReductionOp.get());
+ // All reduction items are still marked as reduction (to do not increase
+ // code base size).
+ Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
+ if (CurrDir == OMPD_taskgroup) {
+ if (DeclareReductionRef.isUsable())
+ Stack->addTaskgroupReductionData(D, ReductionIdRange,
+ DeclareReductionRef.get());
+ else
+ Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK);
+ }
+ RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(),
+ TaskgroupDescriptor);
}
+ return RD.Vars.empty();
+}
- if (Vars.empty())
+OMPClause *Sema::ActOnOpenMPReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ ReductionData RD(VarList.size());
+
+ if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList,
+ StartLoc, LParenLoc, ColonLoc, EndLoc,
+ ReductionIdScopeSpec, ReductionId,
+ UnresolvedReductions, RD))
return nullptr;
return OMPReductionClause::Create(
- Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
- ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates,
- LHSs, RHSs, ReductionOps, buildPreInits(Context, ExprCaptures),
- buildPostUpdate(*this, ExprPostUpdates));
+ Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
+ buildPreInits(Context, RD.ExprCaptures),
+ buildPostUpdate(*this, RD.ExprPostUpdates));
+}
+
+OMPClause *Sema::ActOnOpenMPTaskReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ ReductionData RD(VarList.size());
+
+ if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_task_reduction,
+ VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionIdScopeSpec, ReductionId,
+ UnresolvedReductions, RD))
+ return nullptr;
+
+ return OMPTaskReductionClause::Create(
+ Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
+ buildPreInits(Context, RD.ExprCaptures),
+ buildPostUpdate(*this, RD.ExprPostUpdates));
+}
+
+OMPClause *Sema::ActOnOpenMPInReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ ReductionData RD(VarList.size());
+
+ if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_in_reduction, VarList,
+ StartLoc, LParenLoc, ColonLoc, EndLoc,
+ ReductionIdScopeSpec, ReductionId,
+ UnresolvedReductions, RD))
+ return nullptr;
+
+ return OMPInReductionClause::Create(
+ Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.TaskgroupDescriptors,
+ buildPreInits(Context, RD.ExprCaptures),
+ buildPostUpdate(*this, RD.ExprPostUpdates));
}
bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
@@ -9471,10 +10299,6 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
HasErrors = true;
continue;
}
- if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) {
- D = cast<MemberExpr>(CED->getInit()->IgnoreParenImpCasts())
- ->getMemberDecl();
- }
auto &&Info = Stack->isLoopControlVariable(D);
Expr *InitExpr = *CurInit;
@@ -9930,30 +10754,38 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
if (!CurContext->isDependentContext() &&
DSAStack->getParentOrderedRegionParam() &&
DepCounter != DSAStack->isParentLoopControlVariable(D).first) {
- Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration)
- << DSAStack->getParentLoopControlVariable(
- DepCounter.getZExtValue());
+ ValueDecl* VD = DSAStack->getParentLoopControlVariable(
+ DepCounter.getZExtValue());
+ if (VD) {
+ Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration)
+ << 1 << VD;
+ } else {
+ Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0;
+ }
continue;
}
OpsOffs.push_back({RHS, OOK});
} else {
- // OpenMP [2.11.1.1, Restrictions, p.3]
- // A variable that is part of another variable (such as a field of a
- // structure) but is not an array element or an array section cannot
- // appear in a depend clause.
- auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
- auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
- (!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) ||
(ASE &&
!ASE->getBase()
->getType()
.getNonReferenceType()
->isPointerType() &&
!ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
- Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item)
- << 0 << RefExpr->getSourceRange();
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << RefExpr->getSourceRange();
+ continue;
+ }
+ bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
+ getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ ExprResult Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ getDiagnostics().setSuppressAllDiagnostics(Suppress);
+ if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << RefExpr->getSourceRange();
continue;
}
}
@@ -9962,8 +10794,9 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink &&
TotalDepCount > VarList.size() &&
- DSAStack->getParentOrderedRegionParam()) {
- Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration)
+ DSAStack->getParentOrderedRegionParam() &&
+ DSAStack->getParentLoopControlVariable(VarList.size() + 1)) {
+ Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) << 1
<< DSAStack->getParentLoopControlVariable(VarList.size() + 1);
}
if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink &&
@@ -9981,6 +10814,7 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Device;
+ Stmt *HelperValStmt = nullptr;
// OpenMP [2.9.1, Restrictions]
// The device expression must evaluate to a non-negative integer value.
@@ -9988,48 +10822,16 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
/*StrictlyPositive=*/false))
return nullptr;
- return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc);
-}
-
-static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc,
- DSAStackTy *Stack, CXXRecordDecl *RD) {
- if (!RD || RD->isInvalidDecl())
- return true;
-
- auto QTy = SemaRef.Context.getRecordType(RD);
- if (RD->isDynamicClass()) {
- SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
- SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target);
- return false;
- }
- auto *DC = RD;
- bool IsCorrect = true;
- for (auto *I : DC->decls()) {
- if (I) {
- if (auto *MD = dyn_cast<CXXMethodDecl>(I)) {
- if (MD->isStatic()) {
- SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
- SemaRef.Diag(MD->getLocation(),
- diag::note_omp_static_member_in_target);
- IsCorrect = false;
- }
- } else if (auto *VD = dyn_cast<VarDecl>(I)) {
- if (VD->isStaticDataMember()) {
- SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
- SemaRef.Diag(VD->getLocation(),
- diag::note_omp_static_member_in_target);
- IsCorrect = false;
- }
- }
- }
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ if (isOpenMPTargetExecutionDirective(DKind) &&
+ !CurContext->isDependentContext()) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
}
- for (auto &I : RD->bases()) {
- if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack,
- I.getType()->getAsCXXRecordDecl()))
- IsCorrect = false;
- }
- return IsCorrect;
+ return new (Context)
+ OMPDeviceClause(ValExpr, HelperValStmt, StartLoc, LParenLoc, EndLoc);
}
static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
@@ -10038,9 +10840,6 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
if (QTy->isIncompleteType(&ND)) {
SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR;
return false;
- } else if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(ND)) {
- if (!RD->isInvalidDecl() && !IsCXXRecordForMappable(SemaRef, SL, Stack, RD))
- return false;
}
return true;
}
@@ -10820,7 +11619,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart(
Decls.reserve(ReductionTypes.size());
LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
// A reduction-identifier may not be re-declared in the current scope for the
// same type or for a type that is compatible according to the base language
@@ -10907,7 +11706,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
@@ -10949,7 +11749,7 @@ void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) {
DRD->setInvalidDecl();
}
-void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
+VarDecl *Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
// Enter new function scope.
@@ -10961,7 +11761,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
@@ -10987,10 +11788,11 @@ void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
DRD->addDecl(OmpPrivParm);
DRD->addDecl(OmpOrigParm);
}
+ return OmpPrivParm;
}
-void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D,
- Expr *Initializer) {
+void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer,
+ VarDecl *OmpPrivParm) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
@@ -10998,10 +11800,16 @@ void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D,
PopDeclContext();
PopFunctionScopeInfo();
- if (Initializer != nullptr)
- DRD->setInitializer(Initializer);
- else
+ if (Initializer != nullptr) {
+ DRD->setInitializer(Initializer, OMPDeclareReductionDecl::CallInit);
+ } else if (OmpPrivParm->hasInit()) {
+ DRD->setInitializer(OmpPrivParm->getInit(),
+ OmpPrivParm->isDirectInit()
+ ? OMPDeclareReductionDecl::DirectInit
+ : OMPDeclareReductionDecl::CopyInit);
+ } else {
DRD->setInvalidDecl();
+ }
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd(
@@ -11203,6 +12011,7 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
<< Value << getOpenMPClauseName(OMPC_defaultmap);
return nullptr;
}
+ DSAStack->setDefaultDMAToFromScalar(StartLoc);
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
@@ -11212,7 +12021,11 @@ bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) {
DeclContext *CurLexicalContext = getCurLexicalContext();
if (!CurLexicalContext->isFileContext() &&
!CurLexicalContext->isExternCContext() &&
- !CurLexicalContext->isExternCXXContext()) {
+ !CurLexicalContext->isExternCXXContext() &&
+ !isa<CXXRecordDecl>(CurLexicalContext) &&
+ !isa<ClassTemplateDecl>(CurLexicalContext) &&
+ !isa<ClassTemplatePartialSpecializationDecl>(CurLexicalContext) &&
+ !isa<ClassTemplateSpecializationDecl>(CurLexicalContext)) {
Diag(Loc, diag::err_omp_region_not_file_context);
return false;
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 8b53258803..56135288db 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -48,13 +48,13 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
/// A convenience routine for creating a decayed reference to a function.
static ExprResult
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
- bool HadMultipleCandidates,
- SourceLocation Loc = SourceLocation(),
+ const Expr *Base, bool HadMultipleCandidates,
+ SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
- return ExprError();
+ return ExprError();
// If FoundDecl is different from Fn (such as if one is a template
- // and the other a specialization), make sure DiagnoseUseOfDecl is
+ // and the other a specialization), make sure DiagnoseUseOfDecl is
// called on both.
// FIXME: This would be more comprehensively addressed by modifying
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
@@ -68,7 +68,7 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
- S.MarkDeclRefReferenced(DRE);
+ S.MarkDeclRefReferenced(DRE, Base);
return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
CK_FunctionToPointerDecay);
}
@@ -79,7 +79,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool CStyle,
bool AllowObjCWritebackConversion);
-static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
+static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
@@ -131,7 +131,7 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
- ICR_Conversion,
+ ICR_OCL_Scalar_Widening,
ICR_Complex_Real_Conversion,
ICR_Conversion,
ICR_Conversion,
@@ -330,13 +330,13 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
} else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
llvm::APSInt IntConstantValue;
const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ assert(Initializer && "Unknown conversion expression");
// If it's value-dependent, we can't tell whether it's narrowing.
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
- if (Initializer &&
- Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
+ if (Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
// Convert the integer to the floating type.
llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(),
@@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandidates() {
}
}
-void OverloadCandidateSet::clear() {
+void OverloadCandidateSet::clear(CandidateSetKind CSK) {
destroyCandidates();
SlabAllocator.Reset();
NumInlineBytesUsed = 0;
Candidates.clear();
Functions.clear();
+ Kind = CSK;
}
namespace {
@@ -852,7 +853,7 @@ namespace {
Expr *Saved;
};
SmallVector<Entry, 2> Entries;
-
+
public:
void save(Sema &S, Expr *&E) {
assert(E->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
@@ -863,7 +864,7 @@ namespace {
void restore() {
for (SmallVectorImpl<Entry>::iterator
- i = Entries.begin(), e = Entries.end(); i != e; ++i)
+ i = Entries.begin(), e = Entries.end(); i != e; ++i)
*i->Addr = i->Saved;
}
};
@@ -917,40 +918,39 @@ static bool checkArgPlaceholdersForOverload(Sema &S,
return false;
}
-// IsOverload - Determine whether the given New declaration is an
-// overload of the declarations in Old. This routine returns false if
-// New and Old cannot be overloaded, e.g., if New has the same
-// signature as some function in Old (C++ 1.3.10) or if the Old
-// declarations aren't functions (or function templates) at all. When
-// it does return false, MatchedDecl will point to the decl that New
-// cannot be overloaded with. This decl may be a UsingShadowDecl on
-// top of the underlying declaration.
-//
-// Example: Given the following input:
-//
-// void f(int, float); // #1
-// void f(int, int); // #2
-// int f(int, int); // #3
-//
-// When we process #1, there is no previous declaration of "f",
-// so IsOverload will not be used.
-//
-// When we process #2, Old contains only the FunctionDecl for #1. By
-// comparing the parameter types, we see that #1 and #2 are overloaded
-// (since they have different signatures), so this routine returns
-// false; MatchedDecl is unchanged.
-//
-// When we process #3, Old is an overload set containing #1 and #2. We
-// compare the signatures of #3 to #1 (they're overloaded, so we do
-// nothing) and then #3 to #2. Since the signatures of #3 and #2 are
-// identical (return types of functions are not part of the
-// signature), IsOverload returns false and MatchedDecl will be set to
-// point to the FunctionDecl for #2.
-//
-// 'NewIsUsingShadowDecl' indicates that 'New' is being introduced
-// into a class by a using declaration. The rules for whether to hide
-// shadow declarations ignore some properties which otherwise figure
-// into a function template's signature.
+/// Determine whether the given New declaration is an overload of the
+/// declarations in Old. This routine returns Ovl_Match or Ovl_NonFunction if
+/// New and Old cannot be overloaded, e.g., if New has the same signature as
+/// some function in Old (C++ 1.3.10) or if the Old declarations aren't
+/// functions (or function templates) at all. When it does return Ovl_Match or
+/// Ovl_NonFunction, MatchedDecl will point to the decl that New cannot be
+/// overloaded with. This decl may be a UsingShadowDecl on top of the underlying
+/// declaration.
+///
+/// Example: Given the following input:
+///
+/// void f(int, float); // #1
+/// void f(int, int); // #2
+/// int f(int, int); // #3
+///
+/// When we process #1, there is no previous declaration of "f", so IsOverload
+/// will not be used.
+///
+/// When we process #2, Old contains only the FunctionDecl for #1. By comparing
+/// the parameter types, we see that #1 and #2 are overloaded (since they have
+/// different signatures), so this routine returns Ovl_Overload; MatchedDecl is
+/// unchanged.
+///
+/// When we process #3, Old is an overload set containing #1 and #2. We compare
+/// the signatures of #3 to #1 (they're overloaded, so we do nothing) and then
+/// #3 to #2. Since the signatures of #3 and #2 are identical (return types of
+/// functions are not part of the signature), IsOverload returns Ovl_Match and
+/// MatchedDecl will be set to point to the FunctionDecl for #2.
+///
+/// 'NewIsUsingShadowDecl' indicates that 'New' is being introduced into a class
+/// by a using declaration. The rules for whether to hide shadow declarations
+/// ignore some properties which otherwise figure into a function template's
+/// signature.
Sema::OverloadKind
Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
NamedDecl *&Match, bool NewIsUsingDecl) {
@@ -1369,9 +1369,9 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion) {
- return ::TryImplicitConversion(*this, From, ToType,
+ return ::TryImplicitConversion(*this, From, ToType,
SuppressUserConversions, AllowExplicit,
- InOverloadResolution, CStyle,
+ InOverloadResolution, CStyle,
AllowObjCWritebackConversion,
/*AllowObjCConversionOnExplicit=*/false);
}
@@ -1397,7 +1397,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Objective-C ARC: Determine whether we will allow the writeback conversion.
bool AllowObjCWritebackConversion
- = getLangOpts().ObjCAutoRefCount &&
+ = getLangOpts().ObjCAutoRefCount &&
(Action == AA_Passing || Action == AA_Sending);
if (getLangOpts().ObjC1)
CheckObjCBridgeRelatedConversions(From->getLocStart(),
@@ -1482,6 +1482,23 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
.getTypePtr());
Changed = true;
}
+
+ // Convert FromFPT's ExtParameterInfo if necessary. The conversion is valid
+ // only if the ExtParameterInfo lists of the two function prototypes can be
+ // merged and the merged list is identical to ToFPT's ExtParameterInfo list.
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos;
+ bool CanUseToFPT, CanUseFromFPT;
+ if (Context.mergeExtParameterInfo(ToFPT, FromFPT, CanUseToFPT,
+ CanUseFromFPT, NewParamInfos) &&
+ CanUseToFPT && !CanUseFromFPT) {
+ FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo();
+ ExtInfo.ExtParameterInfos =
+ NewParamInfos.empty() ? nullptr : NewParamInfos.data();
+ QualType QT = Context.getFunctionType(FromFPT->getReturnType(),
+ FromFPT->getParamTypes(), ExtInfo);
+ FromFn = QT->getAs<FunctionType>();
+ Changed = true;
+ }
}
if (!Changed)
@@ -1593,15 +1610,15 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// if the function type matches except for [[noreturn]], it's ok
if (!S.IsFunctionConversion(FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
- // otherwise, only a boolean conversion is standard
- if (!ToType->isBooleanType())
- return false;
+ // otherwise, only a boolean conversion is standard
+ if (!ToType->isBooleanType())
+ return false;
}
// Check if the "from" expression is taking the address of an overloaded
// function and recompute the FromType accordingly. Take advantage of the
// fact that non-static member functions *must* have such an address-of
- // expression.
+ // expression.
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn);
if (Method && !Method->isStatic()) {
assert(isa<UnaryOperator>(From->IgnoreParens()) &&
@@ -1639,7 +1656,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS.First = ICK_Lvalue_To_Rvalue;
// C11 6.3.2.1p2:
- // ... if the lvalue has atomic type, the value has the non-atomic version
+ // ... if the lvalue has atomic type, the value has the non-atomic version
// of the type of the lvalue ...
if (const AtomicType *Atomic = FromType->getAs<AtomicType>())
FromType = Atomic->getValueType();
@@ -1891,12 +1908,12 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
}
static bool
-IsTransparentUnionStandardConversion(Sema &S, Expr* From,
+IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle) {
-
+
const RecordType *UT = ToType->getAsUnionType();
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
return false;
@@ -2130,7 +2147,7 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
"Invalid similarly-qualified pointer type");
/// Conversions to 'id' subsume cv-qualifier conversions.
- if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
+ if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
return ToType.getUnqualifiedType();
QualType CanonFromPointee
@@ -2140,7 +2157,7 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
if (StripObjCLifetime)
Quals.removeObjCLifetime();
-
+
// Exact qualifier match -> return the pointer type we're converting to.
if (CanonToPointee.getLocalQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
@@ -2324,21 +2341,21 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
ToType, Context);
return true;
}
-
+
return false;
}
-
+
/// \brief Adopt the given qualifiers for the given type.
static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){
Qualifiers TQs = T.getQualifiers();
-
+
// Check whether qualifiers already match.
if (TQs == Qs)
return T;
-
+
if (Qs.compatiblyIncludes(TQs))
return Context.getQualifiedType(T, Qs);
-
+
return Context.getQualifiedType(T.getUnqualifiedType(), Qs);
}
@@ -2353,7 +2370,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// The set of qualifiers on the type we're converting from.
Qualifiers FromQualifiers = FromType.getQualifiers();
-
+
// First, we handle all conversions on ObjC object pointer types.
const ObjCObjectPointerType* ToObjCPtr =
ToType->getAs<ObjCObjectPointerType>();
@@ -2444,7 +2461,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ToPointeeType->getAs<ObjCObjectPointerType>() &&
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
IncompatibleObjC)) {
-
+
ConvertedType = Context.getPointerType(ConvertedType);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
@@ -2527,46 +2544,46 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// this conversion.
bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
QualType &ConvertedType) {
- if (!getLangOpts().ObjCAutoRefCount ||
+ if (!getLangOpts().ObjCAutoRefCount ||
Context.hasSameUnqualifiedType(FromType, ToType))
return false;
-
+
// Parameter must be a pointer to __autoreleasing (with no other qualifiers).
QualType ToPointee;
if (const PointerType *ToPointer = ToType->getAs<PointerType>())
ToPointee = ToPointer->getPointeeType();
else
return false;
-
+
Qualifiers ToQuals = ToPointee.getQualifiers();
- if (!ToPointee->isObjCLifetimeType() ||
+ if (!ToPointee->isObjCLifetimeType() ||
ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing ||
!ToQuals.withoutObjCLifetime().empty())
return false;
-
+
// Argument must be a pointer to __strong to __weak.
QualType FromPointee;
if (const PointerType *FromPointer = FromType->getAs<PointerType>())
FromPointee = FromPointer->getPointeeType();
else
return false;
-
+
Qualifiers FromQuals = FromPointee.getQualifiers();
if (!FromPointee->isObjCLifetimeType() ||
(FromQuals.getObjCLifetime() != Qualifiers::OCL_Strong &&
FromQuals.getObjCLifetime() != Qualifiers::OCL_Weak))
return false;
-
+
// Make sure that we have compatible qualifiers.
FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing);
if (!ToQuals.compatiblyIncludes(FromQuals))
return false;
-
+
// Remove qualifiers from the pointee type we're converting from; they
// aren't used in the compatibility check belong, and we'll be adding back
// qualifiers (with __autoreleasing) if the compatibility check succeeds.
FromPointee = FromPointee.getUnqualifiedType();
-
+
// The unqualified form of the pointee types must be compatible.
ToPointee = ToPointee.getUnqualifiedType();
bool IncompatibleObjC;
@@ -2575,7 +2592,7 @@ bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
else if (!isObjCPointerConversion(FromPointee, ToPointee, FromPointee,
IncompatibleObjC))
return false;
-
+
/// \brief Construct the type we're converting to, which is a pointer to
/// __autoreleasing pointee.
FromPointee = Context.getQualifiedType(FromPointee, FromQuals);
@@ -2591,7 +2608,7 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
ToPointeeType = ToBlockPtr->getPointeeType();
else
return false;
-
+
QualType FromPointeeType;
if (const BlockPointerType *FromBlockPtr =
FromType->getAs<BlockPointerType>())
@@ -2601,24 +2618,24 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
// We have pointer to blocks, check whether the only
// differences in the argument and result types are in Objective-C
// pointer conversions. If so, we permit the conversion.
-
+
const FunctionProtoType *FromFunctionType
= FromPointeeType->getAs<FunctionProtoType>();
const FunctionProtoType *ToFunctionType
= ToPointeeType->getAs<FunctionProtoType>();
-
+
if (!FromFunctionType || !ToFunctionType)
return false;
if (Context.hasSameType(FromPointeeType, ToPointeeType))
return true;
-
+
// Perform the quick checks that will tell us whether these
// function types are obviously different.
if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() ||
FromFunctionType->isVariadic() != ToFunctionType->isVariadic())
return false;
-
+
FunctionType::ExtInfo FromEInfo = FromFunctionType->getExtInfo();
FunctionType::ExtInfo ToEInfo = ToFunctionType->getExtInfo();
if (FromEInfo != ToEInfo)
@@ -2646,7 +2663,7 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
else
return false;
}
-
+
// Check argument types.
for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumParams();
ArgIdx != NumArgs; ++ArgIdx) {
@@ -2664,10 +2681,14 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
// Argument types are too different. Abort.
return false;
}
- if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType,
- ToFunctionType))
+
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos;
+ bool CanUseToFPT, CanUseFromFPT;
+ if (!Context.mergeExtParameterInfo(ToFunctionType, FromFunctionType,
+ CanUseToFPT, CanUseFromFPT,
+ NewParamInfos))
return false;
-
+
ConvertedType = ToType;
return true;
}
@@ -3013,7 +3034,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
Qualifiers ToQuals) {
// Converting anything to const __unsafe_unretained is trivial.
- if (ToQuals.hasConst() &&
+ if (ToQuals.hasConst() &&
ToQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
return false;
@@ -3033,7 +3054,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
FromType = Context.getCanonicalType(FromType);
ToType = Context.getCanonicalType(ToType);
ObjCLifetimeConversion = false;
-
+
// If FromType and ToType are the same type, this is not a
// qualification conversion.
if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
@@ -3059,7 +3080,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
// Ignore __unaligned qualifier if this type is void.
if (ToType.getUnqualifiedType()->isVoidType())
FromQuals.removeUnaligned();
-
+
// Objective-C ARC:
// Check Objective-C lifetime conversions.
if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
@@ -3075,14 +3096,14 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
return false;
}
}
-
+
// Allow addition/removal of GC attributes but not changing GC attributes.
if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
(!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
FromQuals.removeObjCGCAttr();
ToQuals.removeObjCGCAttr();
}
-
+
// -- for every j > 0, if const is in cv 1,j then const is in cv
// 2,j, and similarly for volatile.
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
@@ -3120,13 +3141,13 @@ static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
const AtomicType *ToAtomic = ToType->getAs<AtomicType>();
if (!ToAtomic)
return false;
-
+
StandardConversionSequence InnerSCS;
- if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
+ if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
InOverloadResolution, InnerSCS,
CStyle, /*AllowObjCWritebackConversion=*/false))
return false;
-
+
SCS.Second = InnerSCS.Second;
SCS.setToType(1, InnerSCS.getToType(1));
SCS.Third = InnerSCS.Third;
@@ -3155,6 +3176,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
for (auto *D : S.LookupConstructors(To)) {
auto Info = getConstructorInfo(D);
if (!Info)
@@ -3181,9 +3203,9 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
- switch (auto Result =
- CandidateSet.BestViableFunction(S, From->getLocStart(),
- Best, true)) {
+ switch (auto Result =
+ CandidateSet.BestViableFunction(S, From->getLocStart(),
+ Best)) {
case OR_Deleted:
case OR_Success: {
// Record the standard conversion we used and the conversion function.
@@ -3230,6 +3252,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool AllowExplicit,
bool AllowObjCConversionOnExplicit) {
assert(AllowExplicit || !AllowObjCConversionOnExplicit);
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Whether we will only visit constructors.
bool ConstructorsOnly = false;
@@ -3265,7 +3288,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (Result != OR_No_Viable_Function)
return Result;
// Never mind.
- CandidateSet.clear();
+ CandidateSet.clear(
+ OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// If we're list-initializing, we pass the individual elements as
// arguments, not the entire list.
@@ -3355,7 +3379,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
OverloadCandidateSet::iterator Best;
switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(),
- Best, true)) {
+ Best)) {
case OR_Success:
case OR_Deleted:
// Record the standard conversion we used and the conversion function.
@@ -3553,7 +3577,7 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc,
// Two implicit conversion sequences of the same form are
// indistinguishable conversion sequences unless one of the
// following rules apply: (C++ 13.3.3.2p3):
-
+
// List-initialization sequence L1 is a better conversion sequence than
// list-initialization sequence L2 if:
// - L1 converts to std::initializer_list<X> for some X and L2 does not, or,
@@ -3588,7 +3612,7 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc,
ICS1.UserDefined.After,
ICS2.UserDefined.After);
else
- Result = compareConversionFunctions(S,
+ Result = compareConversionFunctions(S,
ICS1.UserDefined.ConversionFunction,
ICS2.UserDefined.ConversionFunction);
}
@@ -3770,9 +3794,9 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
const ObjCObjectPointerType* FromObjCPtr2
= FromType2->getAs<ObjCObjectPointerType>();
if (FromObjCPtr1 && FromObjCPtr2) {
- bool AssignLeft = S.Context.canAssignObjCInterfaces(FromObjCPtr1,
+ bool AssignLeft = S.Context.canAssignObjCInterfaces(FromObjCPtr1,
FromObjCPtr2);
- bool AssignRight = S.Context.canAssignObjCInterfaces(FromObjCPtr2,
+ bool AssignRight = S.Context.canAssignObjCInterfaces(FromObjCPtr2,
FromObjCPtr1);
if (AssignLeft != AssignRight) {
return AssignLeft? ImplicitConversionSequence::Better
@@ -3810,13 +3834,13 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
if (UnqualT1 == UnqualT2) {
// Objective-C++ ARC: If the references refer to objects with different
// lifetimes, prefer bindings that don't change lifetime.
- if (SCS1.ObjCLifetimeConversionBinding !=
+ if (SCS1.ObjCLifetimeConversionBinding !=
SCS2.ObjCLifetimeConversionBinding) {
return SCS1.ObjCLifetimeConversionBinding
? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
}
-
+
// If the type is an array type, promote the element qualifiers to the
// type for comparison.
if (isa<ArrayType>(T1) && T1Quals)
@@ -3826,7 +3850,7 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
else if (T1.isMoreQualifiedThan(T2))
- return ImplicitConversionSequence::Worse;
+ return ImplicitConversionSequence::Worse;
}
}
@@ -3892,17 +3916,17 @@ CompareQualificationConversions(Sema &S,
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
-
+
// Objective-C++ ARC:
// Prefer qualification conversions not involving a change in lifetime
// to qualification conversions that do not change lifetime.
- if (SCS1.QualificationIncludesObjCLifetime !=
+ if (SCS1.QualificationIncludesObjCLifetime !=
SCS2.QualificationIncludesObjCLifetime) {
Result = SCS1.QualificationIncludesObjCLifetime
? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
}
-
+
while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) {
// Within each iteration of the loop, we check the qualifiers to
// determine if this still looks like a qualification
@@ -4034,7 +4058,7 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
= ToType1->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *ToPtr2
= ToType2->getAs<ObjCObjectPointerType>();
-
+
if (FromPtr1 && FromPtr2 && ToPtr1 && ToPtr2) {
// Apply the same conversion ranking rules for Objective-C pointer types
// that we do for C++ pointers to class types. However, we employ the
@@ -4048,8 +4072,8 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
= S.Context.canAssignObjCInterfaces(ToPtr1, ToPtr2);
bool ToAssignRight
= S.Context.canAssignObjCInterfaces(ToPtr2, ToPtr1);
-
- // A conversion to an a non-id object pointer type or qualified 'id'
+
+ // A conversion to an a non-id object pointer type or qualified 'id'
// type is better than a conversion to 'id'.
if (ToPtr1->isObjCIdType() &&
(ToPtr2->isObjCQualifiedIdType() || ToPtr2->getInterfaceDecl()))
@@ -4057,15 +4081,15 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
if (ToPtr2->isObjCIdType() &&
(ToPtr1->isObjCQualifiedIdType() || ToPtr1->getInterfaceDecl()))
return ImplicitConversionSequence::Better;
-
- // A conversion to a non-id object pointer type is better than a
- // conversion to a qualified 'id' type
+
+ // A conversion to a non-id object pointer type is better than a
+ // conversion to a qualified 'id' type
if (ToPtr1->isObjCQualifiedIdType() && ToPtr2->getInterfaceDecl())
return ImplicitConversionSequence::Worse;
if (ToPtr2->isObjCQualifiedIdType() && ToPtr1->getInterfaceDecl())
return ImplicitConversionSequence::Better;
-
- // A conversion to an a non-Class object pointer type or qualified 'Class'
+
+ // A conversion to an a non-Class object pointer type or qualified 'Class'
// type is better than a conversion to 'Class'.
if (ToPtr1->isObjCClassType() &&
(ToPtr2->isObjCQualifiedClassType() || ToPtr2->getInterfaceDecl()))
@@ -4073,8 +4097,8 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
if (ToPtr2->isObjCClassType() &&
(ToPtr1->isObjCQualifiedClassType() || ToPtr1->getInterfaceDecl()))
return ImplicitConversionSequence::Better;
-
- // A conversion to a non-Class object pointer type is better than a
+
+ // A conversion to a non-Class object pointer type is better than a
// conversion to a qualified 'Class' type.
if (ToPtr1->isObjCQualifiedClassType() && ToPtr2->getInterfaceDecl())
return ImplicitConversionSequence::Worse;
@@ -4082,11 +4106,25 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
return ImplicitConversionSequence::Better;
// -- "conversion of C* to B* is better than conversion of C* to A*,"
- if (S.Context.hasSameType(FromType1, FromType2) &&
+ if (S.Context.hasSameType(FromType1, FromType2) &&
!FromPtr1->isObjCIdType() && !FromPtr1->isObjCClassType() &&
- (ToAssignLeft != ToAssignRight))
+ (ToAssignLeft != ToAssignRight)) {
+ if (FromPtr1->isSpecialized()) {
+ // "conversion of B<A> * to B * is better than conversion of B * to
+ // C *.
+ bool IsFirstSame =
+ FromPtr1->getInterfaceDecl() == ToPtr1->getInterfaceDecl();
+ bool IsSecondSame =
+ FromPtr1->getInterfaceDecl() == ToPtr2->getInterfaceDecl();
+ if (IsFirstSame) {
+ if (!IsSecondSame)
+ return ImplicitConversionSequence::Better;
+ } else if (IsSecondSame)
+ return ImplicitConversionSequence::Worse;
+ }
return ToAssignLeft? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
+ }
// -- "conversion of B* to A* is better than conversion of C* to A*,"
if (S.Context.hasSameUnqualifiedType(ToType1, ToType2) &&
@@ -4095,7 +4133,7 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
: ImplicitConversionSequence::Worse;
}
}
-
+
// Ranking of member-pointer types.
if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member &&
FromType1->isMemberPointerType() && FromType2->isMemberPointerType() &&
@@ -4251,9 +4289,9 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
ObjCLifetimeConversion = true;
T1Quals.removeObjCLifetime();
- T2Quals.removeObjCLifetime();
+ T2Quals.removeObjCLifetime();
}
-
+
// MS compiler ignores __unaligned qualifier for references; do the same.
T1Quals.removeUnaligned();
T2Quals.removeUnaligned();
@@ -4275,7 +4313,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
- OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet CandidateSet(
+ DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -4300,7 +4339,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
-
+
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
if (!ConvTemplate && DeclType->isRValueReferenceType()) {
@@ -4309,7 +4348,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (RefType && !RefType->getPointeeType()->isFunctionType())
continue;
}
-
+
if (!ConvTemplate &&
S.CompareReferenceRelationship(
DeclLoc,
@@ -4345,7 +4384,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
- switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
+ switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
case OR_Success:
// C++ [over.ics.ref]p1:
//
@@ -5888,7 +5927,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
return;
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// Add this candidate
OverloadCandidate &Candidate =
@@ -6037,24 +6077,24 @@ Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance,
NumNamedArgs = Method->param_size();
if (Args.size() < NumNamedArgs)
continue;
-
+
for (unsigned i = 0; i < NumNamedArgs; i++) {
// We can't do any type-checking on a type-dependent argument.
if (Args[i]->isTypeDependent()) {
Match = false;
break;
}
-
+
ParmVarDecl *param = Method->parameters()[i];
Expr *argExpr = Args[i];
assert(argExpr && "SelectBestMethod(): missing expression");
-
+
// Strip the unbridged-cast placeholder expression off unless it's
// a consumed argument.
if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
!param->hasAttr<CFConsumedAttr>())
argExpr = stripARCUnbridgedCast(argExpr);
-
+
// If the parameter is __unknown_anytype, move on to the next method.
if (param->getType() == Context.UnknownAnyTy) {
Match = false;
@@ -6228,11 +6268,11 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
}
template <typename CheckFn>
-static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD,
+static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
bool ArgDependent, SourceLocation Loc,
CheckFn &&IsSuccessful) {
SmallVector<const DiagnoseIfAttr *, 8> Attrs;
- for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) {
+ for (const auto *DIA : ND->specific_attrs<DiagnoseIfAttr>()) {
if (ArgDependent == DIA->getArgDependent())
Attrs.push_back(DIA);
}
@@ -6279,16 +6319,16 @@ bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
// EvaluateWithSubstitution only cares about the position of each
// argument in the arg list, not the ParmVarDecl* it maps to.
if (!DIA->getCond()->EvaluateWithSubstitution(
- Result, Context, DIA->getParent(), Args, ThisArg))
+ Result, Context, cast<FunctionDecl>(DIA->getParent()), Args, ThisArg))
return false;
return Result.isInt() && Result.getInt().getBoolValue();
});
}
-bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
+bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
SourceLocation Loc) {
return diagnoseDiagnoseIfAttrsWith(
- *this, Function, /*ArgDependent=*/false, Loc,
+ *this, ND, /*ArgDependent=*/false, Loc,
[&](const DiagnoseIfAttr *DIA) {
bool Result;
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
@@ -6303,34 +6343,61 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
OverloadCandidateSet& CandidateSet,
TemplateArgumentListInfo *ExplicitTemplateArgs,
bool SuppressUserConversions,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ bool FirstArgumentIsBase) {
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())
+ ArrayRef<Expr *> FunctionArgs = Args;
+ if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) {
+ QualType ObjectType;
+ Expr::Classification ObjectClassification;
+ if (Args.size() > 0) {
+ 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.
+ FunctionArgs = Args.slice(1);
+ }
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
- cast<CXXMethodDecl>(FD)->getParent(),
- Args[0]->getType(), Args[0]->Classify(Context),
- Args.slice(1), CandidateSet, SuppressUserConversions,
- PartialOverloading);
- else
- AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
+ cast<CXXMethodDecl>(FD)->getParent(), ObjectType,
+ ObjectClassification, FunctionArgs, CandidateSet,
+ SuppressUserConversions, PartialOverloading);
+ } else {
+ // Slice the first argument (which is the base) when we access
+ // static method as non-static
+ if (Args.size() > 0 && (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) &&
+ !isa<CXXConstructorDecl>(FD)))) {
+ assert(cast<CXXMethodDecl>(FD)->isStatic());
+ FunctionArgs = Args.slice(1);
+ }
+ AddOverloadCandidate(FD, F.getPair(), FunctionArgs, 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 +6463,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 +6720,8 @@ bool Sema::CheckNonDependentConversions(
CandidateSet.allocateConversionSequences(ThisConversions + Args.size());
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// For a method call, check the 'this' conversion here too. DR1391 doesn't
// require that, but this check should never result in a hard error, and
@@ -6723,7 +6792,7 @@ static bool isAllowableExplicitConversion(Sema &S,
return S.isObjCPointerConversion(ConvType, ToNonRefType, ConvertedType,
IncompatibleObjC);
}
-
+
/// AddConversionCandidate - Add a C++ conversion function as a
/// candidate in the candidate set (C++ [over.match.conv],
/// C++ [over.match.copy]). From is the expression we're converting from,
@@ -6736,7 +6805,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet,
- bool AllowObjCConversionOnExplicit) {
+ bool AllowObjCConversionOnExplicit,
+ bool AllowResultConversion) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -6751,16 +6821,23 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
ConvType = Conversion->getConversionType().getNonReferenceType();
}
+ // If we don't allow any conversion of the result type, ignore conversion
+ // functions that don't convert to exactly (possibly cv-qualified) T.
+ if (!AllowResultConversion &&
+ !Context.hasSameUnqualifiedType(Conversion->getConversionType(), ToType))
+ return;
+
// Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
// operator is only a candidate if its return type is the target type or
// can be converted to the target type with a qualification conversion.
- if (Conversion->isExplicit() &&
- !isAllowableExplicitConversion(*this, ConvType, ToType,
+ if (Conversion->isExplicit() &&
+ !isAllowableExplicitConversion(*this, ConvType, ToType,
AllowObjCConversionOnExplicit))
return;
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// Add this candidate
OverloadCandidate &Candidate = CandidateSet.addCandidate(1);
@@ -6903,7 +6980,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
CXXRecordDecl *ActingDC,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet,
- bool AllowObjCConversionOnExplicit) {
+ bool AllowObjCConversionOnExplicit,
+ bool AllowResultConversion) {
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
"Only conversion function templates permitted here");
@@ -6932,7 +7010,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
// template argument deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
- CandidateSet, AllowObjCConversionOnExplicit);
+ CandidateSet, AllowObjCConversionOnExplicit,
+ AllowResultConversion);
}
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -6951,7 +7030,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
return;
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
Candidate.FoundDecl = FoundDecl;
@@ -7103,13 +7183,13 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
/// operator. NumContextualBoolArguments is the number of arguments
/// (at the beginning of the argument list) that will be contextually
/// converted to bool.
-void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
- ArrayRef<Expr *> Args,
+void Sema::AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator,
unsigned NumContextualBoolArguments) {
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// Add this candidate
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
@@ -7117,9 +7197,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Candidate.Function = nullptr;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
- Candidate.BuiltinTypes.ResultTy = ResultTy;
- for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx)
- Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx];
+ std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes);
// Determine the implicit conversion sequences for each of the
// arguments.
@@ -7196,7 +7274,7 @@ class BuiltinCandidateTypeSet {
/// \brief A flag indicating whether the nullptr type was present in the
/// candidate set.
bool HasNullPtrType;
-
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
@@ -7280,14 +7358,14 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
} else {
PointeeTy = PointerTy->getPointeeType();
}
-
+
// Don't add qualified variants of arrays. For one, they're not allowed
// (the qualifier would sink to the element type), and for another, the
// only overload situation where it matters is subscript or pointer +- int,
// and those shouldn't have qualifier variants anyway.
if (PointeeTy->isArrayType())
return true;
-
+
unsigned BaseCVR = PointeeTy.getCVRQualifiers();
bool hasVolatile = VisibleQuals.hasVolatile();
bool hasRestrict = VisibleQuals.hasRestrict();
@@ -7297,24 +7375,24 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
if ((CVR | BaseCVR) != CVR) continue;
// Skip over volatile if no volatile found anywhere in the types.
if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue;
-
+
// Skip over restrict if no restrict found anywhere in the types, or if
// the type cannot be restrict-qualified.
if ((CVR & Qualifiers::Restrict) &&
(!hasRestrict ||
(!(PointeeTy->isAnyPointerType() || PointeeTy->isReferenceType()))))
continue;
-
+
// Build qualified pointee type.
QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
-
+
// Build qualified pointer type.
QualType QPointerTy;
if (!buildObjCPtr)
QPointerTy = Context.getPointerType(QPointeeTy);
else
QPointerTy = Context.getObjCObjectPointerType(QPointeeTy);
-
+
// Insert qualified pointer type.
PointerTypes.insert(QPointerTy);
}
@@ -7458,7 +7536,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
// T& operator=(T&, T)
ParamTypes[0] = S.Context.getLValueReferenceType(T);
ParamTypes[1] = T;
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/true);
if (!S.Context.getCanonicalType(T).isVolatileQualified()) {
@@ -7466,7 +7544,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getVolatileType(T));
ParamTypes[1] = T;
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/true);
}
}
@@ -7586,64 +7664,6 @@ class BuiltinOperatorOverloadBuilder {
return S.Context.*ArithmeticTypes[index];
}
- /// \brief Gets the canonical type resulting from the usual arithemetic
- /// converions for the given arithmetic types.
- CanQualType getUsualArithmeticConversions(unsigned L, unsigned R) {
- // Accelerator table for performing the usual arithmetic conversions.
- // The rules are basically:
- // - if either is floating-point, use the wider floating-point
- // - if same signedness, use the higher rank
- // - if same size, use unsigned of the higher rank
- // - use the larger type
- // These rules, together with the axiom that higher ranks are
- // never smaller, are sufficient to precompute all of these results
- // *except* when dealing with signed types of higher rank.
- // (we could precompute SLL x UI for all known platforms, but it's
- // better not to make any assumptions).
- // We assume that int128 has a higher rank than long long on all platforms.
- enum PromotedType : int8_t {
- Dep=-1,
- Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128
- };
- static const PromotedType ConversionsTable[LastPromotedArithmeticType]
- [LastPromotedArithmeticType] = {
-/* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt, Flt, Flt },
-/* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl },
-/*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl },
-/* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128 },
-/* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, S128, Dep, UL, ULL, U128 },
-/* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, S128, Dep, Dep, ULL, U128 },
-/*S128*/ { Flt, Dbl, LDbl, S128, S128, S128, S128, S128, S128, S128, U128 },
-/* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, S128, UI, UL, ULL, U128 },
-/* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, S128, UL, UL, ULL, U128 },
-/* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, S128, ULL, ULL, ULL, U128 },
-/*U128*/ { Flt, Dbl, LDbl, U128, U128, U128, U128, U128, U128, U128, U128 },
- };
-
- assert(L < LastPromotedArithmeticType);
- assert(R < LastPromotedArithmeticType);
- int Idx = ConversionsTable[L][R];
-
- // Fast path: the table gives us a concrete answer.
- if (Idx != Dep) return getArithmeticType(Idx);
-
- // Slow path: we need to compare widths.
- // An invariant is that the signed type has higher rank.
- CanQualType LT = getArithmeticType(L),
- RT = getArithmeticType(R);
- unsigned LW = S.Context.getIntWidth(LT),
- RW = S.Context.getIntWidth(RT);
-
- // If they're different widths, use the signed type.
- if (LW > RW) return LT;
- else if (LW < RW) return RT;
-
- // Otherwise, use the unsigned type of the signed type's rank.
- if (L == SL || R == SL) return S.Context.UnsignedLongTy;
- assert(L == SLL || R == SLL);
- return S.Context.UnsignedLongLongTy;
- }
-
/// \brief Helper method to factor out the common pattern of adding overloads
/// for '++' and '--' builtin operators.
void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy,
@@ -7655,10 +7675,7 @@ class BuiltinOperatorOverloadBuilder {
};
// Non-volatile version.
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
// Use a heuristic to reduce number of builtin candidates in the set:
// add volatile version only if there are conversions to a volatile type.
@@ -7666,12 +7683,9 @@ class BuiltinOperatorOverloadBuilder {
ParamTypes[0] =
S.Context.getLValueReferenceType(
S.Context.getVolatileType(CandidateTy));
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
-
+
// Add restrict version only if there are conversions to a restrict type
// and our candidate type is a non-restrict-qualified pointer.
if (HasRestrict && CandidateTy->isAnyPointerType() &&
@@ -7679,21 +7693,15 @@ class BuiltinOperatorOverloadBuilder {
ParamTypes[0]
= S.Context.getLValueReferenceType(
S.Context.getCVRQualifiedType(CandidateTy, Qualifiers::Restrict));
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
-
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
+
if (HasVolatile) {
ParamTypes[0]
= S.Context.getLValueReferenceType(
S.Context.getCVRQualifiedType(CandidateTy,
(Qualifiers::Volatile |
Qualifiers::Restrict)));
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
@@ -7807,8 +7815,7 @@ public:
if (Proto->getTypeQuals() || Proto->getRefQualifier())
continue;
- S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy),
- &ParamTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet);
}
}
@@ -7825,7 +7832,7 @@ public:
for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
QualType ArithTy = getArithmeticType(Arith);
- S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&ArithTy, Args, CandidateSet);
}
// Extension: We also add these operators for vector types.
@@ -7834,7 +7841,7 @@ public:
VecEnd = CandidateTypes[0].vector_end();
Vec != VecEnd; ++Vec) {
QualType VecTy = *Vec;
- S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
}
}
@@ -7849,7 +7856,7 @@ public:
PtrEnd = CandidateTypes[0].pointer_end();
Ptr != PtrEnd; ++Ptr) {
QualType ParamTy = *Ptr;
- S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet);
}
}
@@ -7865,7 +7872,7 @@ public:
for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
QualType IntTy = getArithmeticType(Int);
- S.AddBuiltinCandidate(IntTy, &IntTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&IntTy, Args, CandidateSet);
}
// Extension: We also add this operator for vector types.
@@ -7874,7 +7881,7 @@ public:
VecEnd = CandidateTypes[0].vector_end();
Vec != VecEnd; ++Vec) {
QualType VecTy = *Vec;
- S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
}
}
@@ -7899,15 +7906,14 @@ public:
continue;
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
if (CandidateTypes[ArgIdx].hasNullPtrType()) {
CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
if (AddedTypes.insert(NullPtrTy).second) {
QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args,
- CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -7983,7 +7989,7 @@ public:
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
@@ -7999,7 +8005,7 @@ public:
continue;
QualType ParamTypes[2] = { *Enum, *Enum };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8042,7 +8048,7 @@ public:
if (Arg == 0 || Op == OO_Plus) {
// operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t)
// T* operator+(ptrdiff_t, T*);
- S.AddBuiltinCandidate(*Ptr, AsymmetricParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(AsymmetricParamTypes, Args, CandidateSet);
}
if (Op == OO_Minus) {
// ptrdiff_t operator-(T, T);
@@ -8050,8 +8056,7 @@ public:
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
- S.AddBuiltinCandidate(S.Context.getPointerDiffType(), ParamTypes,
- Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8086,7 +8091,7 @@ public:
// where LR is the result of the usual arithmetic conversions
// between types L and R.
// Our candidates ignore the first parameter.
- void addGenericBinaryArithmeticOverloads(bool isComparison) {
+ void addGenericBinaryArithmeticOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
@@ -8096,10 +8101,7 @@ public:
Right < LastPromotedArithmeticType; ++Right) {
QualType LandR[2] = { getArithmeticType(Left),
getArithmeticType(Right) };
- QualType Result =
- isComparison ? S.Context.BoolTy
- : getUsualArithmeticConversions(Left, Right);
- S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet);
+ S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
@@ -8114,15 +8116,7 @@ public:
Vec2End = CandidateTypes[1].vector_end();
Vec2 != Vec2End; ++Vec2) {
QualType LandR[2] = { *Vec1, *Vec2 };
- QualType Result = S.Context.BoolTy;
- if (!isComparison) {
- if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType())
- Result = *Vec1;
- else
- Result = *Vec2;
- }
-
- S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet);
+ S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
}
@@ -8151,10 +8145,7 @@ public:
Right < LastPromotedIntegralType; ++Right) {
QualType LandR[2] = { getArithmeticType(Left),
getArithmeticType(Right) };
- QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
- ? LandR[0]
- : getUsualArithmeticConversions(Left, Right);
- S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet);
+ S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
}
@@ -8228,7 +8219,7 @@ public:
S.Context.getLValueReferenceType(*Ptr),
isEqualOp ? *Ptr : S.Context.getPointerDiffType(),
};
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/ isEqualOp);
bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
@@ -8237,18 +8228,18 @@ public:
// volatile version
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
-
+
if (!(*Ptr).isRestrictQualified() &&
VisibleTypeConversionsQuals.hasRestrict()) {
// restrict version
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
-
+
if (NeedVolatile) {
// volatile restrict version
ParamTypes[0]
@@ -8256,7 +8247,7 @@ public:
S.Context.getCVRQualifiedType(*Ptr,
(Qualifiers::Volatile |
Qualifiers::Restrict)));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
}
@@ -8277,7 +8268,7 @@ public:
};
// non-volatile version
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
@@ -8286,18 +8277,18 @@ public:
// volatile version
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
}
-
+
if (!(*Ptr).isRestrictQualified() &&
VisibleTypeConversionsQuals.hasRestrict()) {
// restrict version
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
-
+
if (NeedVolatile) {
// volatile restrict version
ParamTypes[0]
@@ -8305,7 +8296,7 @@ public:
S.Context.getCVRQualifiedType(*Ptr,
(Qualifiers::Volatile |
Qualifiers::Restrict)));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
}
}
@@ -8338,7 +8329,7 @@ public:
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
S.Context.getLValueReferenceType(getArithmeticType(Left));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
@@ -8346,7 +8337,7 @@ public:
ParamTypes[0] =
S.Context.getVolatileType(getArithmeticType(Left));
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
}
@@ -8365,14 +8356,14 @@ public:
ParamTypes[1] = *Vec2;
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
ParamTypes[0] = S.Context.getVolatileType(*Vec1);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
}
@@ -8404,13 +8395,13 @@ public:
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
S.Context.getLValueReferenceType(getArithmeticType(Left));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
if (VisibleTypeConversionsQuals.hasVolatile()) {
// Add this built-in operator as a candidate (VQ is 'volatile').
ParamTypes[0] = getArithmeticType(Left);
ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8425,13 +8416,13 @@ public:
// bool operator||(bool, bool);
void addExclaimOverload() {
QualType ParamTy = S.Context.BoolTy;
- S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet,
+ S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet,
/*IsAssignmentOperator=*/false,
/*NumContextualBoolArguments=*/1);
}
void addAmpAmpOrPipePipeOverload() {
QualType ParamTypes[2] = { S.Context.BoolTy, S.Context.BoolTy };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/false,
/*NumContextualBoolArguments=*/2);
}
@@ -8456,10 +8447,8 @@ public:
if (!PointeeType->isObjectType())
continue;
- QualType ResultTy = S.Context.getLValueReferenceType(PointeeType);
-
// T& operator[](T*, ptrdiff_t)
- S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (BuiltinCandidateTypeSet::iterator
@@ -8471,10 +8460,8 @@ public:
if (!PointeeType->isObjectType())
continue;
- QualType ResultTy = S.Context.getLValueReferenceType(PointeeType);
-
// T& operator[](ptrdiff_t, T*)
- S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
@@ -8524,8 +8511,7 @@ public:
T.isRestrictQualified())
continue;
T = Q1.apply(S.Context, T);
- QualType ResultTy = S.Context.getLValueReferenceType(T);
- S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8553,7 +8539,7 @@ public:
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
- S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (BuiltinCandidateTypeSet::iterator
@@ -8564,7 +8550,7 @@ public:
continue;
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
- S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
if (S.getLangOpts().CPlusPlus11) {
@@ -8579,7 +8565,7 @@ public:
continue;
QualType ParamTypes[2] = { *Enum, *Enum };
- S.AddBuiltinCandidate(*Enum, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8673,7 +8659,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
OpBuilder.addUnaryPlusOrMinusArithmeticOverloads();
} else {
OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op);
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
}
break;
@@ -8681,11 +8667,11 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
if (Args.size() == 1)
OpBuilder.addUnaryStarPointerOverloads();
else
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_Slash:
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_PlusPlus:
@@ -8704,7 +8690,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_LessEqual:
case OO_GreaterEqual:
OpBuilder.addRelationalPointerOrEnumeralOverloads();
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/true);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_Percent:
@@ -8771,7 +8757,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_Conditional:
OpBuilder.addConditionalOperatorOverloads();
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
}
}
@@ -8884,10 +8870,9 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
-bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
- const OverloadCandidate &Cand2,
- SourceLocation Loc,
- bool UserDefinedConversion) {
+bool clang::isBetterOverloadCandidate(
+ Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2,
+ SourceLocation Loc, OverloadCandidateSet::CandidateSetKind Kind) {
// Define viable functions to be better candidates than non-viable
// functions.
if (!Cand2.Viable)
@@ -8969,7 +8954,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// the type of the entity being initialized) is a better
// conversion sequence than the standard conversion sequence
// from the return type of F2 to the destination type.
- if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
+ if (Kind == OverloadCandidateSet::CSK_InitByUserDefinedConversion &&
+ Cand1.Function && Cand2.Function &&
isa<CXXConversionDecl>(Cand1.Function) &&
isa<CXXConversionDecl>(Cand2.Function)) {
// First check whether we prefer one of the conversion functions over the
@@ -8991,11 +8977,17 @@ 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();
+ // FIXME: Work around a defect in the C++17 guaranteed copy elision wording,
+ // as combined with the resolution to CWG issue 243.
+ //
+ // When the context is initialization by constructor ([over.match.ctor] or
+ // either phase of [over.match.list]), a constructor is preferred over
+ // a conversion function.
+ if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 &&
+ Cand1.Function && Cand2.Function &&
+ isa<CXXConstructorDecl>(Cand1.Function) !=
+ isa<CXXConstructorDecl>(Cand2.Function))
+ return isa<CXXConstructorDecl>(Cand1.Function);
// -- F1 is a non-template function and F2 is a function template
// specialization, or, if not that,
@@ -9041,6 +9033,21 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// Inherited from sibling base classes: still ambiguous.
}
+ // Check C++17 tie-breakers for deduction guides.
+ {
+ auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
+ auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function);
+ if (Guide1 && Guide2) {
+ // -- F1 is generated from a deduction-guide and F2 is not
+ if (Guide1->isImplicit() != Guide2->isImplicit())
+ return Guide2->isImplicit();
+
+ // -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not
+ if (Guide1->isCopyDeductionCandidate())
+ return true;
+ }
+ }
+
// Check for enable_if value-based overload resolution.
if (Cand1.Function && Cand2.Function) {
Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function);
@@ -9140,8 +9147,7 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
/// \returns The result of overload resolution.
OverloadingResult
OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
- iterator &Best,
- bool UserDefinedConversion) {
+ iterator &Best) {
llvm::SmallVector<OverloadCandidate *, 16> Candidates;
std::transform(begin(), end(), std::back_inserter(Candidates),
[](OverloadCandidate &Cand) { return &Cand; });
@@ -9175,8 +9181,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
Best = end();
for (auto *Cand : Candidates)
if (Cand->Viable)
- if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc,
- UserDefinedConversion))
+ if (Best == end() ||
+ isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
Best = Cand;
// If we didn't find any viable functions, abort.
@@ -9188,10 +9194,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Make sure that this function is better than every other viable
// function. If not, we have an ambiguity.
for (auto *Cand : Candidates) {
- if (Cand->Viable &&
- Cand != Best &&
- !isBetterOverloadCandidate(S, *Best, *Cand, Loc,
- UserDefinedConversion)) {
+ if (Cand->Viable && Cand != Best &&
+ !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) {
if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
Cand->Function)) {
EquivalentCands.push_back(Cand->Function);
@@ -9390,13 +9394,13 @@ void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
OverloadExpr *OvlExpr = Ovl.Expression;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
- IEnd = OvlExpr->decls_end();
+ IEnd = OvlExpr->decls_end();
I != IEnd; ++I) {
- if (FunctionTemplateDecl *FunTmpl =
+ if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType,
TakingAddress);
- } else if (FunctionDecl *Fun
+ } else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(*I, Fun, DestType, TakingAddress);
}
@@ -9494,7 +9498,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;
@@ -9573,7 +9578,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1
<< (unsigned) (Cand->Fix.Kind);
-
+
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9676,7 +9681,7 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
// right number of arguments, because only overloaded operators have
// the weird behavior of overloading member and non-member functions.
// Just don't report anything.
- if (Fn->isInvalidDecl() &&
+ if (Fn->isInvalidDecl() &&
Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
return true;
@@ -9700,9 +9705,9 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
"The templated declaration should at least be a function"
" when diagnosing bad template argument deduction due to too many"
" or too few arguments");
-
+
FunctionDecl *Fn = cast<FunctionDecl>(D);
-
+
// TODO: treat calls to a missing default constructor as a special case
const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredArguments();
@@ -9890,6 +9895,15 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
return;
}
+ // We found a specific requirement that disabled the enable_if.
+ if (PDiag && PDiag->second.getDiagID() ==
+ diag::err_typename_nested_not_found_requirement) {
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_disabled_by_requirement)
+ << PDiag->second.getStringArg(0) << TemplateArgString;
+ return;
+ }
+
// Format the SFINAE diagnostic into the argument string.
// FIXME: Add a general mechanism to include a PartialDiagnostic *'s
// formatted message in another diagnostic.
@@ -9958,8 +9972,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
return;
// FIXME: For generic lambda parameters, check if the function is a lambda
- // call operator, and if so, emit a prettier and more informative
- // diagnostic that mentions 'auto' and lambda in addition to
+ // call operator, and if so, emit a prettier and more informative
+ // diagnostic that mentions 'auto' and lambda in addition to
// (or instead of?) the canonical template type parameters.
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_non_deduced_mismatch)
@@ -10202,13 +10216,13 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
std::string TypeStr("operator");
TypeStr += Opc;
TypeStr += "(";
- TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
+ TypeStr += Cand->BuiltinParamTypes[0].getAsString();
if (Cand->Conversions.size() == 1) {
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
} else {
TypeStr += ", ";
- TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString();
+ TypeStr += Cand->BuiltinParamTypes[1].getAsString();
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr;
}
@@ -10273,9 +10287,12 @@ struct CompareOverloadCandidatesForDisplay {
Sema &S;
SourceLocation Loc;
size_t NumArgs;
+ OverloadCandidateSet::CandidateSetKind CSK;
- CompareOverloadCandidatesForDisplay(Sema &S, SourceLocation Loc, size_t nArgs)
- : S(S), NumArgs(nArgs) {}
+ CompareOverloadCandidatesForDisplay(
+ Sema &S, SourceLocation Loc, size_t NArgs,
+ OverloadCandidateSet::CandidateSetKind CSK)
+ : S(S), NumArgs(NArgs), CSK(CSK) {}
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
@@ -10289,8 +10306,10 @@ struct CompareOverloadCandidatesForDisplay {
// TODO: introduce a tri-valued comparison for overload
// candidates. Would be more worthwhile if we had a sort
// that could exploit it.
- if (isBetterOverloadCandidate(S, *L, *R, SourceLocation())) return true;
- if (isBetterOverloadCandidate(S, *R, *L, SourceLocation())) return false;
+ if (isBetterOverloadCandidate(S, *L, *R, SourceLocation(), CSK))
+ return true;
+ if (isBetterOverloadCandidate(S, *R, *L, SourceLocation(), CSK))
+ return false;
} else if (R->Viable)
return false;
@@ -10445,7 +10464,7 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
} else {
// Builtin operator.
assert(ConvCount <= 3);
- ParamTypes = Cand->BuiltinTypes.ParamTypes;
+ ParamTypes = Cand->BuiltinParamTypes;
}
// Fill in the rest of the conversions.
@@ -10498,7 +10517,7 @@ void OverloadCandidateSet::NoteCandidates(
}
std::sort(Cands.begin(), Cands.end(),
- CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size()));
+ CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind));
bool ReportedAmbiguousConversions = false;
@@ -10657,16 +10676,16 @@ void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) {
// R (S::*)(A) --> R (A)
QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) {
QualType Ret = PossiblyAFunctionType;
- if (const PointerType *ToTypePtr =
+ if (const PointerType *ToTypePtr =
PossiblyAFunctionType->getAs<PointerType>())
Ret = ToTypePtr->getPointeeType();
- else if (const ReferenceType *ToTypeRef =
+ else if (const ReferenceType *ToTypeRef =
PossiblyAFunctionType->getAs<ReferenceType>())
Ret = ToTypeRef->getPointeeType();
else if (const MemberPointerType *MemTypePtr =
- PossiblyAFunctionType->getAs<MemberPointerType>())
- Ret = MemTypePtr->getPointeeType();
- Ret =
+ PossiblyAFunctionType->getAs<MemberPointerType>())
+ Ret = MemTypePtr->getPointeeType();
+ Ret =
Context.getCanonicalType(Ret).getUnqualifiedType();
return Ret;
}
@@ -10692,9 +10711,9 @@ namespace {
class AddressOfFunctionResolver {
Sema& S;
Expr* SourceExpr;
- const QualType& TargetType;
- QualType TargetFunctionType; // Extracted function type from target type
-
+ const QualType& TargetType;
+ QualType TargetFunctionType; // Extracted function type from target type
+
bool Complain;
//DeclAccessPair& ResultFunctionAccessPair;
ASTContext& Context;
@@ -10704,7 +10723,7 @@ class AddressOfFunctionResolver {
bool StaticMemberFunctionFromBoundPointer;
bool HasComplained;
- OverloadExpr::FindResult OvlExprInfo;
+ OverloadExpr::FindResult OvlExprInfo;
OverloadExpr *OvlExpr;
TemplateArgumentListInfo OvlExplicitTemplateArgs;
SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
@@ -10751,7 +10770,7 @@ public:
}
return;
}
-
+
if (OvlExpr->hasExplicitTemplateArgs())
OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs);
@@ -10829,7 +10848,7 @@ private:
}
// return true if any matching specializations were found
- bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate,
+ bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
@@ -10837,7 +10856,7 @@ private:
// static when converting to member pointer.
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
return false;
- }
+ }
else if (TargetTypeIsNonStaticMemberFunction)
return false;
@@ -10850,17 +10869,17 @@ private:
FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (Sema::TemplateDeductionResult Result
- = S.DeduceTemplateArguments(FunctionTemplate,
+ = S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
- TargetFunctionType, Specialization,
+ TargetFunctionType, Specialization,
Info, /*IsAddressOfFunction*/true)) {
// Make a note of the failed deduction for diagnostics.
FailedCandidates.addCandidate()
.set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, Result, Info));
return false;
- }
-
+ }
+
// Template argument deduction ensures that we have an exact match or
// compatible pointer-to-function arguments that would be adjusted by ICS.
// This function template specicalization works.
@@ -10874,15 +10893,15 @@ private:
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
return true;
}
-
- bool AddMatchingNonTemplateFunction(NamedDecl* Fn,
+
+ bool AddMatchingNonTemplateFunction(NamedDecl* Fn,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
// Skip non-static functions when converting to pointer, and static
// when converting to member pointer.
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
return false;
- }
+ }
else if (TargetTypeIsNonStaticMemberFunction)
return false;
@@ -10912,20 +10931,20 @@ private:
return true;
}
}
-
+
return false;
}
-
+
bool FindAllFunctionsThatMatchTargetTypeExactly() {
bool Ret = false;
-
+
// If the overload expression doesn't have the form of a pointer to
// member, don't try to convert it to a pointer-to-member type.
if (IsInvalidFormOfPointerToMemberFunction())
return false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
- E = OvlExpr->decls_end();
+ E = OvlExpr->decls_end();
I != E; ++I) {
// Look through any using declarations to find the underlying function.
NamedDecl *Fn = (*I)->getUnderlyingDecl();
@@ -11068,12 +11087,12 @@ public:
bool hadMultipleCandidates() const { return (OvlExpr->getNumDecls() > 1); }
int getNumMatches() const { return Matches.size(); }
-
+
FunctionDecl* getMatchingFunctionDecl() const {
if (Matches.size() != 1) return nullptr;
return Matches[0].second;
}
-
+
const DeclAccessPair* getMatchingFunctionAccessPair() const {
if (Matches.size() != 1) return nullptr;
return &Matches[0].first;
@@ -11175,12 +11194,12 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
/// \brief Given an overloaded function, tries to turn it into a non-overloaded
/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This
/// will perform access checks, diagnose the use of the resultant decl, and, if
-/// necessary, perform a function-to-pointer decay.
+/// requested, potentially perform a function-to-pointer decay.
///
/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails.
/// Otherwise, returns true. This may emit diagnostics and return true.
bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
- ExprResult &SrcExpr) {
+ ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
Expr *E = SrcExpr.get();
assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
@@ -11195,7 +11214,7 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
DiagnoseUseOfDecl(Found, E->getExprLoc());
CheckAddressOfMemberAccess(E, DAP);
Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found);
- if (Fixed->getType()->isFunctionType())
+ if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType())
SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
else
SrcExpr = Fixed;
@@ -11213,7 +11232,7 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
/// If no template-ids are found, no diagnostics are emitted and NULL is
/// returned.
FunctionDecl *
-Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
+Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
bool Complain,
DeclAccessPair *FoundResult) {
// C++ [over.over]p1:
@@ -11276,9 +11295,9 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
}
return nullptr;
}
-
+
Matched = Specialization;
- if (FoundResult) *FoundResult = I.getPair();
+ if (FoundResult) *FoundResult = I.getPair();
}
if (Matched &&
@@ -11301,8 +11320,8 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// returns true if 'complain' is set.
bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
ExprResult &SrcExpr, bool doFunctionPointerConverion,
- bool complain, SourceRange OpRangeForComplaining,
- QualType DestTypeForComplaining,
+ bool complain, SourceRange OpRangeForComplaining,
+ QualType DestTypeForComplaining,
unsigned DiagIDForComplaining) {
assert(SrcExpr.get()->getType() == Context.OverloadTy);
@@ -11359,7 +11378,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
<< ovl.Expression->getName()
<< DestTypeForComplaining
- << OpRangeForComplaining
+ << OpRangeForComplaining
<< ovl.Expression->getQualifierLoc().getSourceRange();
NoteAllOverloadCandidates(SrcExpr.get());
@@ -11391,6 +11410,10 @@ static void AddOverloadedCallCandidate(Sema &S,
assert(!KnownValid && "Explicit template arguments?");
return;
}
+ // Prevent ill-formed function decls to be added as overload candidates.
+ if (!dyn_cast<FunctionProtoType>(Func->getType()->getAs<FunctionType>()))
+ return;
+
S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet,
/*SuppressUsedConversions=*/false,
PartialOverloading);
@@ -11925,7 +11948,7 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
ExprResult
Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *Input) {
+ Expr *Input, bool PerformADL) {
OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -11963,7 +11986,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.
@@ -11976,9 +11999,11 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
- /*ExplicitTemplateArgs*/nullptr,
- CandidateSet);
+ if (PerformADL) {
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
+ /*ExplicitTemplateArgs*/nullptr,
+ CandidateSet);
+ }
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
@@ -11993,6 +12018,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
FunctionDecl *FnDecl = Best->Function;
if (FnDecl) {
+ Expr *Base = nullptr;
// We matched an overloaded operator. Build a call to that
// operator.
@@ -12005,7 +12031,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Best->FoundDecl, Method);
if (InputRes.isInvalid())
return ExprError();
- Input = InputRes.get();
+ Base = Input = InputRes.get();
} else {
// Convert the arguments.
ExprResult InputInit
@@ -12021,7 +12047,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl,
- HadMultipleCandidates, OpLoc);
+ Base, HadMultipleCandidates,
+ OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -12033,7 +12060,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();
@@ -12047,9 +12074,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- ExprResult InputRes =
- PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing);
+ ExprResult InputRes = PerformImplicitConversion(
+ Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing);
if (InputRes.isInvalid())
return ExprError();
Input = InputRes.get();
@@ -12115,7 +12141,7 @@ ExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *LHS, Expr *RHS) {
+ Expr *LHS, Expr *RHS, bool PerformADL) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
@@ -12131,12 +12157,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,13 +12170,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// TODO: provide better source location info in DNLoc component.
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, NamingClass,
- NestedNameSpecifierLoc(), OpNameInfo,
- /*ADL*/ true, IsOverloaded(Fns),
+ = UnresolvedLookupExpr::Create(Context, NamingClass,
+ NestedNameSpecifierLoc(), OpNameInfo,
+ /*ADL*/PerformADL, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return new (Context)
CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy,
- VK_RValue, OpLoc, FPFeatures.fp_contract);
+ VK_RValue, OpLoc, FPFeatures);
}
// Always do placeholder-like conversions on the RHS.
@@ -12189,7 +12215,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
// performed for an assignment operator (nor for operator[] nor operator->,
// which don't get here).
- if (Opc != BO_Assign)
+ if (Opc != BO_Assign && PerformADL)
AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
/*ExplicitTemplateArgs*/ nullptr,
CandidateSet);
@@ -12207,6 +12233,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
FunctionDecl *FnDecl = Best->Function;
if (FnDecl) {
+ Expr *Base = nullptr;
// We matched an overloaded operator. Build a call to that
// operator.
@@ -12228,7 +12255,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Best->FoundDecl, Method);
if (Arg0.isInvalid())
return ExprError();
- Args[0] = Arg0.getAs<Expr>();
+ Base = Args[0] = Arg0.getAs<Expr>();
Args[1] = RHS = Arg1.getAs<Expr>();
} else {
// Convert the arguments.
@@ -12252,7 +12279,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
- Best->FoundDecl,
+ Best->FoundDecl, Base,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -12265,7 +12292,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))
@@ -12293,15 +12320,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// break out so that we will build the appropriate built-in
// operator node.
ExprResult ArgsRes0 =
- PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing);
+ PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0],
+ Best->Conversions[0], AA_Passing);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 =
- PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], AA_Passing);
+ PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1],
+ Best->Conversions[1], AA_Passing);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
@@ -12413,7 +12440,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.
@@ -12474,6 +12501,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
Best->FoundDecl,
+ Base,
HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
@@ -12489,7 +12517,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();
@@ -12504,15 +12532,15 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// break out so that we will build the appropriate built-in
// operator node.
ExprResult ArgsRes0 =
- PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing);
+ PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0],
+ Best->Conversions[0], AA_Passing);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 =
- PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], AA_Passing);
+ PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1],
+ Best->Conversions[1], AA_Passing);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
@@ -12708,12 +12736,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
return ExprError();
// If FoundDecl is different from Method (such as if one is a template
- // and the other a specialization), make sure DiagnoseUseOfDecl is
+ // and the other a specialization), make sure DiagnoseUseOfDecl is
// called on both.
// FIXME: This would be more comprehensively addressed by modifying
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
// being used.
- if (Method != FoundDecl.getDecl() &&
+ if (Method != FoundDecl.getDecl() &&
DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc()))
return ExprError();
break;
@@ -12736,7 +12764,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
case OR_Deleted:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
- << DeclName
+ << DeclName
<< getDeletedOrUnavailableSuffix(Best->Function)
<< MemExprE->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
@@ -12809,8 +12837,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
}
- if ((isa<CXXConstructorDecl>(CurContext) ||
- isa<CXXDestructorDecl>(CurContext)) &&
+ if ((isa<CXXConstructorDecl>(CurContext) ||
+ isa<CXXDestructorDecl>(CurContext)) &&
TheCall->getMethodDecl()->isPure()) {
const CXXMethodDecl *MD = TheCall->getMethodDecl();
@@ -12890,7 +12918,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
}
// C++ [over.call.object]p2:
- // In addition, for each (non-explicit in C++0x) conversion function
+ // In addition, for each (non-explicit in C++0x) conversion function
// declared in T of the form
//
// operator conversion-type-id () cv-qualifier;
@@ -12940,7 +12968,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(),
- Best)) {
+ Best)) {
case OR_Success:
// Overload resolution succeeded; we'll build the appropriate call
// below.
@@ -12969,7 +12997,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Diag(Object.get()->getLocStart(),
diag::err_ovl_deleted_object_call)
<< Best->Function->isDeleted()
- << Object.get()->getType()
+ << Object.get()->getType()
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Object.get()->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
@@ -12992,7 +13020,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Best->FoundDecl);
if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc))
return ExprError();
- assert(Conv == Best->FoundDecl.getDecl() &&
+ assert(Conv == Best->FoundDecl.getDecl() &&
"Found Decl & conversion-to-functionptr should be same, right?!");
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
@@ -13032,7 +13060,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc));
ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
- HadMultipleCandidates,
+ Obj, HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
if (NewFn.isInvalid())
@@ -13052,7 +13080,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;
@@ -13203,7 +13231,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
- << "->"
+ << "->"
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Base->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base);
@@ -13223,7 +13251,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
// Build the operator call.
ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
- HadMultipleCandidates, OpLoc);
+ Base, HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -13232,7 +13260,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();
@@ -13282,7 +13310,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
FunctionDecl *FD = Best->Function;
ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl,
- HadMultipleCandidates,
+ nullptr, HadMultipleCandidates,
SuffixInfo.getLoc(),
SuffixInfo.getInfo());
if (Fn.isInvalid())
@@ -13334,7 +13362,7 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
Expr *Range, ExprResult *CallExpr) {
Scope *S = nullptr;
- CandidateSet->clear();
+ CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
if (!MemberLookup.empty()) {
ExprResult MemberRef =
BuildMemberReferenceExpr(Range, Range->getType(), Loc,
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 8e53fda846..d159172a69 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() {
@@ -1177,8 +1176,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType,
true /*instance*/);
- bool receiverIdType = (BaseT->isObjCIdType() ||
- BaseT->isObjCQualifiedIdType());
if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) {
AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
@@ -1204,7 +1201,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
}
if (!AtIndexGetter) {
- if (!receiverIdType) {
+ if (!BaseT->isObjCIdType()) {
S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found)
<< BaseExpr->getType() << 0 << arrayRef;
return false;
@@ -1285,9 +1282,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
}
AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType,
true /*instance*/);
-
- bool receiverIdType = (BaseT->isObjCIdType() ||
- BaseT->isObjCQualifiedIdType());
if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) {
TypeSourceInfo *ReturnTInfo = nullptr;
@@ -1322,7 +1316,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
}
if (!AtIndexSetter) {
- if (!receiverIdType) {
+ if (!BaseT->isObjCIdType()) {
S.Diag(BaseExpr->getExprLoc(),
diag::err_objc_subscript_method_not_found)
<< BaseExpr->getType() << 1 << arrayRef;
@@ -1587,7 +1581,8 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
// Do nothing if either argument is dependent.
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
- VK_RValue, OK_Ordinary, opcLoc, false);
+ VK_RValue, OK_Ordinary, opcLoc,
+ FPOptions());
// Filter out non-overload placeholder types in the RHS.
if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1652,14 +1647,15 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
cop->getObjectKind(),
cop->getComputationLHSType(),
cop->getComputationResultType(),
- cop->getOperatorLoc(), false);
+ cop->getOperatorLoc(),
+ FPOptions());
} else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
bop->getType(), bop->getValueKind(),
bop->getObjectKind(),
- bop->getOperatorLoc(), false);
+ bop->getOperatorLoc(), FPOptions());
} else {
assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 3f6c467955..3a3eb5e7b5 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)) {
@@ -596,14 +602,14 @@ static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
/// potentially integral-promoted expression @p expr.
-static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) {
- if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr))
- expr = cleanups->getSubExpr();
- while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) {
- if (impcast->getCastKind() != CK_IntegralCast) break;
- expr = impcast->getSubExpr();
+static QualType GetTypeBeforeIntegralPromotion(const Expr *&E) {
+ if (const auto *CleanUps = dyn_cast<ExprWithCleanups>(E))
+ E = CleanUps->getSubExpr();
+ while (const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ImpCast->getCastKind() != CK_IntegralCast) break;
+ E = ImpCast->getSubExpr();
}
- return expr->getType();
+ return E->getType();
}
ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) {
@@ -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,19 +731,44 @@ 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;
}
+static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond,
+ const Expr *Case) {
+ QualType CondType = GetTypeBeforeIntegralPromotion(Cond);
+ QualType CaseType = Case->getType();
+
+ const EnumType *CondEnumType = CondType->getAs<EnumType>();
+ const EnumType *CaseEnumType = CaseType->getAs<EnumType>();
+ if (!CondEnumType || !CaseEnumType)
+ return;
+
+ // Ignore anonymous enums.
+ if (!CondEnumType->getDecl()->getIdentifier() &&
+ !CondEnumType->getDecl()->getTypedefNameForAnonDecl())
+ return;
+ if (!CaseEnumType->getDecl()->getIdentifier() &&
+ !CaseEnumType->getDecl()->getTypedefNameForAnonDecl())
+ return;
+
+ if (S.Context.hasSameUnqualifiedType(CondType, CaseType))
+ return;
+
+ S.Diag(Case->getExprLoc(), diag::warn_comparison_of_mixed_enum_types_switch)
+ << CondType << CaseType << Cond->getSourceRange()
+ << Case->getSourceRange();
+}
+
StmtResult
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
Stmt *BodyStmt) {
@@ -752,7 +786,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
QualType CondType = CondExpr->getType();
- Expr *CondExprBeforePromotion = CondExpr;
+ const Expr *CondExprBeforePromotion = CondExpr;
QualType CondTypeBeforePromotion =
GetTypeBeforeIntegralPromotion(CondExprBeforePromotion);
@@ -835,6 +869,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
break;
}
+ checkEnumTypesInSwitchStmt(*this, CondExpr, Lo);
+
llvm::APSInt LoVal;
if (getLangOpts().CPlusPlus11) {
@@ -1147,7 +1183,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 +1234,9 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);
const EnumDecl *ED = ET->getDecl();
+ if (!ED->isClosed())
+ return;
+
if (ED->hasAttr<FlagEnumAttr>()) {
if (!IsValueInFlagEnum(ED, RhsVal, true))
Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
@@ -1277,17 +1316,22 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
}
namespace {
+ // Use SetVector since the diagnostic cares about the ordering of the Decl's.
+ using DeclSetVector =
+ llvm::SetVector<VarDecl *, llvm::SmallVector<VarDecl *, 8>,
+ llvm::SmallPtrSet<VarDecl *, 8>>;
+
// This visitor will traverse a conditional statement and store all
// the evaluated decls into a vector. Simple is set to true if none
// of the excluded constructs are used.
class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
- llvm::SmallPtrSetImpl<VarDecl*> &Decls;
+ DeclSetVector &Decls;
SmallVectorImpl<SourceRange> &Ranges;
bool Simple;
public:
typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
- DeclExtractor(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls,
+ DeclExtractor(Sema &S, DeclSetVector &Decls,
SmallVectorImpl<SourceRange> &Ranges) :
Inherited(S.Context),
Decls(Decls),
@@ -1359,14 +1403,13 @@ namespace {
// DeclMatcher checks to see if the decls are used in a non-evaluated
// context.
class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> {
- llvm::SmallPtrSetImpl<VarDecl*> &Decls;
+ DeclSetVector &Decls;
bool FoundDecl;
public:
typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
- DeclMatcher(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls,
- Stmt *Statement) :
+ DeclMatcher(Sema &S, DeclSetVector &Decls, Stmt *Statement) :
Inherited(S.Context), Decls(Decls), FoundDecl(false) {
if (!Statement) return;
@@ -1448,7 +1491,7 @@ namespace {
return;
PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
- llvm::SmallPtrSet<VarDecl*, 8> Decls;
+ DeclSetVector Decls;
SmallVector<SourceRange, 10> Ranges;
DeclExtractor DE(S, Decls, Ranges);
DE.Visit(Second);
@@ -1460,11 +1503,9 @@ namespace {
if (Decls.size() == 0) return;
// Don't warn on volatile, static, or global variables.
- for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(),
- E = Decls.end();
- I != E; ++I)
- if ((*I)->getType().isVolatileQualified() ||
- (*I)->hasGlobalStorage()) return;
+ for (auto *VD : Decls)
+ if (VD->getType().isVolatileQualified() || VD->hasGlobalStorage())
+ return;
if (DeclMatcher(S, Decls, Second).FoundDeclInUse() ||
DeclMatcher(S, Decls, Third).FoundDeclInUse() ||
@@ -1472,25 +1513,16 @@ namespace {
return;
// Load decl names into diagnostic.
- if (Decls.size() > 4)
+ if (Decls.size() > 4) {
PDiag << 0;
- else {
- PDiag << Decls.size();
- for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(),
- E = Decls.end();
- I != E; ++I)
- PDiag << (*I)->getDeclName();
- }
-
- // Load SourceRanges into diagnostic if there is room.
- // Otherwise, load the SourceRange of the conditional expression.
- if (Ranges.size() <= PartialDiagnostic::MaxArguments)
- for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I)
- PDiag << *I;
- else
- PDiag << Second->getSourceRange();
+ } else {
+ PDiag << (unsigned)Decls.size();
+ for (auto *VD : Decls)
+ PDiag << VD->getDeclName();
+ }
+
+ for (auto Range : Ranges)
+ PDiag << Range;
S.Diag(Ranges.begin()->getBegin(), PDiag);
}
@@ -1540,23 +1572,78 @@ namespace {
// A visitor to determine if a continue or break statement is a
// subexpression.
- class BreakContinueFinder : public EvaluatedExprVisitor<BreakContinueFinder> {
+ class BreakContinueFinder : public ConstEvaluatedExprVisitor<BreakContinueFinder> {
SourceLocation BreakLoc;
SourceLocation ContinueLoc;
+ bool InSwitch = false;
+
public:
- BreakContinueFinder(Sema &S, Stmt* Body) :
+ BreakContinueFinder(Sema &S, const Stmt* Body) :
Inherited(S.Context) {
Visit(Body);
}
- typedef EvaluatedExprVisitor<BreakContinueFinder> Inherited;
+ typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited;
- void VisitContinueStmt(ContinueStmt* E) {
+ void VisitContinueStmt(const ContinueStmt* E) {
ContinueLoc = E->getContinueLoc();
}
- void VisitBreakStmt(BreakStmt* E) {
- BreakLoc = E->getBreakLoc();
+ void VisitBreakStmt(const BreakStmt* E) {
+ if (!InSwitch)
+ BreakLoc = E->getBreakLoc();
+ }
+
+ void VisitSwitchStmt(const SwitchStmt* S) {
+ if (const Stmt *Init = S->getInit())
+ Visit(Init);
+ if (const Stmt *CondVar = S->getConditionVariableDeclStmt())
+ Visit(CondVar);
+ if (const Stmt *Cond = S->getCond())
+ Visit(Cond);
+
+ // Don't return break statements from the body of a switch.
+ InSwitch = true;
+ if (const Stmt *Body = S->getBody())
+ Visit(Body);
+ InSwitch = false;
+ }
+
+ void VisitForStmt(const ForStmt *S) {
+ // Only visit the init statement of a for loop; the body
+ // has a different break/continue scope.
+ if (const Stmt *Init = S->getInit())
+ Visit(Init);
+ }
+
+ void VisitWhileStmt(const WhileStmt *) {
+ // Do nothing; the children of a while loop have a different
+ // break/continue scope.
+ }
+
+ void VisitDoStmt(const DoStmt *) {
+ // Do nothing; the children of a while loop have a different
+ // break/continue scope.
+ }
+
+ void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
+ // Only visit the initialization of a for loop; the body
+ // has a different break/continue scope.
+ if (const Stmt *Range = S->getRangeStmt())
+ Visit(Range);
+ if (const Stmt *Begin = S->getBeginStmt())
+ Visit(Begin);
+ if (const Stmt *End = S->getEndStmt())
+ Visit(End);
+ }
+
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
+ // Only visit the initialization of a for loop; the body
+ // has a different break/continue scope.
+ if (const Stmt *Element = S->getElement())
+ Visit(Element);
+ if (const Stmt *Collection = S->getCollection())
+ Visit(Collection);
}
bool ContinueFound() { return ContinueLoc.isValid(); }
@@ -1772,6 +1859,7 @@ StmtResult
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
Stmt *First, Expr *collection,
SourceLocation RParenLoc) {
+ getCurFunction()->setHasBranchProtectedScope();
ExprResult CollectionExprResult =
CheckObjCForCollectionOperand(ForLoc, collection);
@@ -1984,11 +2072,11 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
return StmtError();
}
- // Coroutines: 'for co_await' implicitly co_awaits its range.
- if (CoawaitLoc.isValid()) {
- ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range);
- if (Coawait.isInvalid()) return StmtError();
- Range = Coawait.get();
+ // Build the coroutine state immediately and not later during template
+ // instantiation
+ if (!CoawaitLoc.isInvalid()) {
+ if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await"))
+ return StmtError();
}
// Build auto && __range = range-init
@@ -2026,16 +2114,12 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
/// BeginExpr and EndExpr are set and FRS_Success is returned on success;
/// CandidateSet and BEF are set and some non-success value is returned on
/// failure.
-static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
- Expr *BeginRange, Expr *EndRange,
- QualType RangeType,
- VarDecl *BeginVar,
- VarDecl *EndVar,
- SourceLocation ColonLoc,
- OverloadCandidateSet *CandidateSet,
- ExprResult *BeginExpr,
- ExprResult *EndExpr,
- BeginEndFunction *BEF) {
+static Sema::ForRangeStatus
+BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
+ QualType RangeType, VarDecl *BeginVar, VarDecl *EndVar,
+ SourceLocation ColonLoc, SourceLocation CoawaitLoc,
+ OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr,
+ ExprResult *EndExpr, BeginEndFunction *BEF) {
DeclarationNameInfo BeginNameInfo(
&SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
@@ -2082,6 +2166,15 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
<< ColonLoc << BEF_begin << BeginRange->getType();
return RangeStatus;
}
+ if (!CoawaitLoc.isInvalid()) {
+ // FIXME: getCurScope() should not be used during template instantiation.
+ // We should pick up the set of unqualified lookup results for operator
+ // co_await during the initial parse.
+ *BeginExpr = SemaRef.ActOnCoawaitExpr(SemaRef.getCurScope(), ColonLoc,
+ BeginExpr->get());
+ if (BeginExpr->isInvalid())
+ return Sema::FRS_DiagnosticIssued;
+ }
if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
@@ -2201,8 +2294,12 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
// them in properly when we instantiate the loop.
- if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
+ if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
+ if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
+ for (auto *Binding : DD->bindings())
+ Binding->setType(Context.DependentTy);
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
+ }
} else if (!BeginDeclStmt.get()) {
SourceLocation RangeLoc = RangeVar->getLocation();
@@ -2244,6 +2341,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// begin-expr is __range.
BeginExpr = BeginRangeRef;
+ if (!CoawaitLoc.isInvalid()) {
+ BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
+ if (BeginExpr.isInvalid())
+ return StmtError();
+ }
if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
@@ -2256,9 +2358,57 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
BoundExpr = IntegerLiteral::Create(
Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
else if (const VariableArrayType *VAT =
- dyn_cast<VariableArrayType>(UnqAT))
- BoundExpr = VAT->getSizeExpr();
- else {
+ dyn_cast<VariableArrayType>(UnqAT)) {
+ // For a variably modified type we can't just use the expression within
+ // the array bounds, since we don't want that to be re-evaluated here.
+ // Rather, we need to determine what it was when the array was first
+ // created - so we resort to using sizeof(vla)/sizeof(element).
+ // For e.g.
+ // void f(int b) {
+ // int vla[b];
+ // b = -1; <-- This should not affect the num of iterations below
+ // for (int &c : vla) { .. }
+ // }
+
+ // FIXME: This results in codegen generating IR that recalculates the
+ // run-time number of elements (as opposed to just using the IR Value
+ // that corresponds to the run-time value of each bound that was
+ // generated when the array was created.) If this proves too embarassing
+ // even for unoptimized IR, consider passing a magic-value/cookie to
+ // codegen that then knows to simply use that initial llvm::Value (that
+ // corresponds to the bound at time of array creation) within
+ // getelementptr. But be prepared to pay the price of increasing a
+ // customized form of coupling between the two components - which could
+ // be hard to maintain as the codebase evolves.
+
+ ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*isType=*/true,
+ CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
+ VAT->desugar(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfVLAExprR.isInvalid())
+ return StmtError();
+
+ ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*isType=*/true,
+ CreateParsedType(VAT->desugar(),
+ Context.getTrivialTypeSourceInfo(
+ VAT->getElementType(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfEachElementExprR.isInvalid())
+ return StmtError();
+
+ BoundExpr =
+ ActOnBinOp(S, EndVar->getLocation(), tok::slash,
+ SizeOfVLAExprR.get(), SizeOfEachElementExprR.get());
+ if (BoundExpr.isInvalid())
+ return StmtError();
+
+ } else {
// Can't be a DependentSizedArrayType or an IncompleteArrayType since
// UnqAT is not incomplete and Range is not type-dependent.
llvm_unreachable("Unexpected array type in for-range");
@@ -2278,11 +2428,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
OverloadCandidateSet CandidateSet(RangeLoc,
OverloadCandidateSet::CSK_Normal);
BeginEndFunction BEFFailure;
- ForRangeStatus RangeStatus =
- BuildNonArrayForRange(*this, BeginRangeRef.get(),
- EndRangeRef.get(), RangeType,
- BeginVar, EndVar, ColonLoc, &CandidateSet,
- &BeginExpr, &EndExpr, &BEFFailure);
+ ForRangeStatus RangeStatus = BuildNonArrayForRange(
+ *this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar,
+ EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr,
+ &BEFFailure);
if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
BEFFailure == BEF_begin) {
@@ -2379,6 +2528,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
+ // FIXME: getCurScope() should not be used during template instantiation.
+ // We should pick up the set of unqualified lookup results for operator
+ // co_await during the initial parse.
IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get());
if (!IncrExpr.isInvalid())
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
@@ -2816,7 +2968,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// [...] If the first overload resolution fails or was not performed, or
// if the type of the first parameter of the selected constructor is not
- // an rvalue reference to the object’s type (possibly cv-qualified),
+ // an rvalue reference to the object's type (possibly cv-qualified),
// overload resolution is performed again, considering the object as an
// lvalue.
if (!RRefType ||
@@ -2866,7 +3018,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 +3311,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 +3368,8 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// C++1z: discarded return statements are not considered when deducing a
// return type.
- if (ExprEvalContexts.back().Context == DiscardedStatement &&
+ if (ExprEvalContexts.back().Context ==
+ ExpressionEvaluationContext::DiscardedStatement &&
FnRetType->getContainedAutoType()) {
if (RetValExp) {
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
@@ -3900,8 +4055,9 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
DeclContext *DC = CapturedDecl::castToDeclContext(CD);
IdentifierInfo *ParamName = &Context.Idents.get("__context");
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
- ImplicitParamDecl *Param
- = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setContextParam(0, Param);
@@ -3914,7 +4070,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
else
CurContext = CD;
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
@@ -3935,15 +4092,17 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
"null type has been found already for '__context' parameter");
IdentifierInfo *ParamName = &Context.Idents.get("__context");
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
- ImplicitParamDecl *Param
- = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setContextParam(ParamNum, Param);
ContextIsFound = true;
} else {
IdentifierInfo *ParamName = &Context.Idents.get(I->first);
- ImplicitParamDecl *Param
- = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, I->second);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, I->second,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setParam(ParamNum, Param);
}
@@ -3953,8 +4112,9 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
// Add __context implicitly if it is not specified.
IdentifierInfo *ParamName = &Context.Idents.get("__context");
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
- ImplicitParamDecl *Param =
- ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setContextParam(ParamNum, Param);
}
@@ -3966,7 +4126,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 76de9e2993..fc1cc7bbe5 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -48,10 +48,10 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
if (E != E2 && E2->isLValue()) {
if (!S.getLangOpts().HeinousExtensions)
S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
- << E->getSourceRange();
+ << E->getSourceRange();
else
S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
- << E->getSourceRange();
+ << E->getSourceRange();
// Accept, even if we emitted an error diagnostic.
return false;
}
@@ -62,11 +62,13 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
/// isOperandMentioned - Return true if the specified operand # is mentioned
/// anywhere in the decomposed asm string.
-static bool isOperandMentioned(unsigned OpNo,
- ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) {
+static bool
+isOperandMentioned(unsigned OpNo,
+ ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) {
for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
- if (!Piece.isOperand()) continue;
+ if (!Piece.isOperand())
+ continue;
// If this is a reference to the input and if the input was the smaller
// one, then we have to reject this asm.
@@ -277,6 +279,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(),
diag::err_dereference_incomplete_type))
return StmtError();
+ LLVM_FALLTHROUGH;
default:
return StmtError(Diag(OutputExpr->getLocStart(),
diag::err_asm_invalid_lvalue_in_output)
@@ -604,27 +607,36 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return NS;
}
-static void fillInlineAsmTypeInfo(const ASTContext &Context, QualType T,
- llvm::InlineAsmIdentifierInfo &Info) {
- // Compute the type size (and array length if applicable?).
- Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity();
- if (T->isArrayType()) {
- const ArrayType *ATy = Context.getAsArrayType(T);
- Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
- Info.Length = Info.Size / Info.Type;
+void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
+ llvm::InlineAsmIdentifierInfo &Info) {
+ QualType T = Res->getType();
+ Expr::EvalResult Eval;
+ if (T->isFunctionType() || T->isDependentType())
+ return Info.setLabel(Res);
+ if (Res->isRValue()) {
+ if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context))
+ return Info.setEnum(Eval.Val.getInt().getSExtValue());
+ return Info.setLabel(Res);
}
+ unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
+ unsigned Type = Size;
+ if (const auto *ATy = Context.getAsArrayType(T))
+ Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
+ bool IsGlobalLV = false;
+ if (Res->EvaluateAsLValue(Eval, Context))
+ IsGlobalLV = Eval.isGlobalLValue();
+ Info.setVar(Res, IsGlobalLV, Size, Type);
}
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
- llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) {
- Info.clear();
if (IsUnevaluatedContext)
- PushExpressionEvaluationContext(UnevaluatedAbstract,
- ReuseLambdaContextDecl);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::UnevaluatedAbstract,
+ ReuseLambdaContextDecl);
ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id,
/*trailing lparen*/ false,
@@ -660,12 +672,6 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
return ExprError();
}
- fillInlineAsmTypeInfo(Context, T, Info);
-
- // We can work with the expression as long as it's not an r-value.
- if (!Result.get()->isRValue())
- Info.IsVarDecl = true;
-
return Result;
}
@@ -675,22 +681,33 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
SmallVector<StringRef, 2> Members;
Member.split(Members, ".");
- LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
- LookupOrdinaryName);
+ NamedDecl *FoundDecl = nullptr;
- if (!LookupName(BaseResult, getCurScope()))
- return true;
-
- if(!BaseResult.isSingleResult())
+ // MS InlineAsm uses 'this' as a base
+ if (getLangOpts().CPlusPlus && Base.equals("this")) {
+ if (const Type *PT = getCurrentThisType().getTypePtrOrNull())
+ FoundDecl = PT->getPointeeType()->getAsTagDecl();
+ } else {
+ LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
+ LookupOrdinaryName);
+ if (LookupName(BaseResult, getCurScope()) && BaseResult.isSingleResult())
+ FoundDecl = BaseResult.getFoundDecl();
+ }
+
+ if (!FoundDecl)
return true;
- NamedDecl *FoundDecl = BaseResult.getFoundDecl();
+
for (StringRef NextMember : Members) {
const RecordType *RT = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
RT = VD->getType()->getAs<RecordType>();
else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
- RT = TD->getUnderlyingType()->getAs<RecordType>();
+ // MS InlineAsm often uses struct pointer aliases as a base
+ QualType QT = TD->getUnderlyingType();
+ if (const auto *PT = QT->getAs<PointerType>())
+ QT = PT->getPointeeType();
+ RT = QT->getAs<RecordType>();
} else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
RT = TD->getTypeForDecl()->getAs<RecordType>();
else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl))
@@ -728,9 +745,7 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
ExprResult
Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
- llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc) {
- Info.clear();
QualType T = E->getType();
if (T->isDependentType()) {
@@ -765,14 +780,6 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
ExprResult Result = BuildMemberReferenceExpr(
E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
SourceLocation(), nullptr, FieldResult, nullptr, nullptr);
- if (Result.isInvalid())
- return Result;
- Info.OpDecl = Result.get();
-
- fillInlineAsmTypeInfo(Context, Result.get()->getType(), Info);
-
- // Fields are "variables" as far as inline assembly is concerned.
- Info.IsVarDecl = true;
return Result;
}
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 01fa856132..d43c8c38f6 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -47,12 +47,37 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
// about using it as an extension.
if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() &&
!A.getScopeName())
- S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName();
+ S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A.getName();
FnScope->setHasFallthroughStmt();
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);
@@ -75,16 +100,15 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
return nullptr;
}
- LoopHintAttr::Spelling Spelling;
+ LoopHintAttr::Spelling Spelling =
+ LoopHintAttr::Spelling(A.getAttributeSpellingListIndex());
LoopHintAttr::OptionType Option;
LoopHintAttr::LoopHintState State;
if (PragmaNoUnroll) {
// #pragma nounroll
- Spelling = LoopHintAttr::Pragma_nounroll;
Option = LoopHintAttr::Unroll;
State = LoopHintAttr::Disable;
} else if (PragmaUnroll) {
- Spelling = LoopHintAttr::Pragma_unroll;
if (ValueExpr) {
// #pragma unroll N
Option = LoopHintAttr::UnrollCount;
@@ -96,7 +120,6 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
}
} else {
// #pragma clang loop ...
- Spelling = LoopHintAttr::Pragma_clang_loop;
assert(OptionLoc && OptionLoc->Ident &&
"Attribute must have valid option info.");
Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
@@ -279,6 +302,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 f6c6ccbd41..26b80f11fb 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -455,6 +455,85 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
}
+void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
+ SourceLocation Less,
+ SourceLocation Greater) {
+ if (TemplateName.isInvalid())
+ return;
+
+ DeclarationNameInfo NameInfo;
+ CXXScopeSpec SS;
+ LookupNameKind LookupKind;
+
+ DeclContext *LookupCtx = nullptr;
+ NamedDecl *Found = nullptr;
+
+ // Figure out what name we looked up.
+ if (auto *ME = dyn_cast<MemberExpr>(TemplateName.get())) {
+ NameInfo = ME->getMemberNameInfo();
+ SS.Adopt(ME->getQualifierLoc());
+ LookupKind = LookupMemberName;
+ LookupCtx = ME->getBase()->getType()->getAsCXXRecordDecl();
+ Found = ME->getMemberDecl();
+ } else {
+ auto *DRE = cast<DeclRefExpr>(TemplateName.get());
+ NameInfo = DRE->getNameInfo();
+ SS.Adopt(DRE->getQualifierLoc());
+ LookupKind = LookupOrdinaryName;
+ Found = DRE->getFoundDecl();
+ }
+
+ // Try to correct the name by looking for templates and C++ named casts.
+ struct TemplateCandidateFilter : CorrectionCandidateCallback {
+ TemplateCandidateFilter() {
+ WantTypeSpecifiers = false;
+ WantExpressionKeywords = false;
+ WantRemainingKeywords = false;
+ WantCXXNamedCasts = true;
+ };
+ bool ValidateCandidate(const TypoCorrection &Candidate) override {
+ if (auto *ND = Candidate.getCorrectionDecl())
+ return isAcceptableTemplateName(ND->getASTContext(), ND, true);
+ return Candidate.isKeyword();
+ }
+ };
+
+ DeclarationName Name = NameInfo.getName();
+ if (TypoCorrection Corrected =
+ CorrectTypo(NameInfo, LookupKind, S, &SS,
+ llvm::make_unique<TemplateCandidateFilter>(),
+ CTK_ErrorRecovery, LookupCtx)) {
+ auto *ND = Corrected.getFoundDecl();
+ if (ND)
+ ND = isAcceptableTemplateName(Context, ND,
+ /*AllowFunctionTemplates*/ true);
+ if (ND || Corrected.isKeyword()) {
+ if (LookupCtx) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
+ Name.getAsString() == CorrectedStr;
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_non_template_in_member_template_id_suggest)
+ << Name << LookupCtx << DroppedSpecifier
+ << SS.getRange(), false);
+ } else {
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_non_template_in_template_id_suggest)
+ << Name, false);
+ }
+ if (Found)
+ Diag(Found->getLocation(),
+ diag::note_non_template_in_template_id_found);
+ return;
+ }
+ }
+
+ Diag(NameInfo.getLoc(), diag::err_non_template_in_template_id)
+ << Name << SourceRange(Less, Greater);
+ if (Found)
+ Diag(Found->getLocation(), diag::note_non_template_in_template_id_found);
+}
+
/// ActOnDependentIdExpression - Handle a dependent id-expression that
/// was just parsed. This is only possible with an explicit scope
/// specifier naming a dependent type.
@@ -699,7 +778,7 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S,
SourceLocation Loc,
IdentifierInfo *Name) {
NamedDecl *PrevDecl = SemaRef.LookupSingleName(
- S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter())
SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl);
}
@@ -1001,7 +1080,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- ArrayRef<Decl *> Params,
+ ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc,
Expr *RequiresClause) {
if (ExportLoc.isValid())
@@ -1009,7 +1088,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
return TemplateParameterList::Create(
Context, TemplateLoc, LAngleLoc,
- llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()),
+ llvm::makeArrayRef(Params.data(), Params.size()),
RAngleLoc, RequiresClause);
}
@@ -1054,7 +1133,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
LookupResult Previous(*this, Name, NameLoc,
(SS.isEmpty() && TUK == TUK_Friend)
? LookupTagName : LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = computeDeclContext(SS, true);
if (!SemanticContext) {
@@ -1113,8 +1192,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
- ClassTemplateDecl *PrevClassTemplate
- = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+ ClassTemplateDecl *PrevClassTemplate =
+ dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
// We may have found the injected-class-name of a class template,
// class template partial specialization, or class template specialization.
@@ -1251,8 +1330,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
assert(Tmpl && "original definition of a class template is not a "
"class template?");
- makeMergedDefinitionVisible(Hidden, KWLoc);
- makeMergedDefinitionVisible(Tmpl, KWLoc);
+ makeMergedDefinitionVisible(Hidden);
+ makeMergedDefinitionVisible(Tmpl);
return Def;
}
@@ -1405,6 +1484,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
CurContext->addDecl(Friend);
}
+ if (PrevClassTemplate)
+ CheckRedeclarationModuleOwnership(NewTemplate, PrevClassTemplate);
+
if (Invalid) {
NewTemplate->setInvalidDecl();
NewClass->setInvalidDecl();
@@ -1636,11 +1718,22 @@ private:
transformFunctionTypeParam(ParmVarDecl *OldParam,
MultiLevelTemplateArgumentList &Args) {
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
- TypeSourceInfo *NewDI =
- Args.getNumLevels()
- ? SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
- OldParam->getDeclName())
- : OldDI;
+ TypeSourceInfo *NewDI;
+ if (!Args.getNumLevels())
+ NewDI = OldDI;
+ else if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) {
+ // Expand out the one and only element in each inner pack.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0);
+ NewDI =
+ SemaRef.SubstType(PackTL.getPatternLoc(), Args,
+ OldParam->getLocation(), OldParam->getDeclName());
+ if (!NewDI) return nullptr;
+ NewDI =
+ SemaRef.CheckPackExpansion(NewDI, PackTL.getEllipsisLoc(),
+ PackTL.getTypePtr()->getNumExpansions());
+ } else
+ NewDI = SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
+ OldParam->getDeclName());
if (!NewDI)
return nullptr;
@@ -1744,7 +1837,6 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
// 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())
@@ -1761,20 +1853,22 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
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.
+ // C++17 [over.match.class.deduct]
+ // -- If C is not defined or does not declare any constructors, an
+ // additional function template derived as above from a hypothetical
+ // constructor C().
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);
+ // -- An additional function template derived as above from a hypothetical
+ // constructor C(C), called the copy deduction candidate.
+ cast<CXXDeductionGuideDecl>(
+ cast<FunctionTemplateDecl>(
+ Transform.buildSimpleDeductionGuide(Transform.DeducedType))
+ ->getTemplatedDecl())
+ ->setIsCopyDeductionCandidate();
}
/// \brief Diagnose the presence of a default template argument on a
@@ -2109,7 +2203,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
@@ -2120,16 +2213,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;
@@ -2708,6 +2810,109 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
+/// Determine whether this alias template is "enable_if_t".
+static bool isEnableIfAliasTemplate(TypeAliasTemplateDecl *AliasTemplate) {
+ return AliasTemplate->getName().equals("enable_if_t");
+}
+
+/// Collect all of the separable terms in the given condition, which
+/// might be a conjunction.
+///
+/// FIXME: The right answer is to convert the logical expression into
+/// disjunctive normal form, so we can find the first failed term
+/// within each possible clause.
+static void collectConjunctionTerms(Expr *Clause,
+ SmallVectorImpl<Expr *> &Terms) {
+ if (auto BinOp = dyn_cast<BinaryOperator>(Clause->IgnoreParenImpCasts())) {
+ if (BinOp->getOpcode() == BO_LAnd) {
+ collectConjunctionTerms(BinOp->getLHS(), Terms);
+ collectConjunctionTerms(BinOp->getRHS(), Terms);
+ }
+
+ return;
+ }
+
+ Terms.push_back(Clause);
+}
+
+// The ranges-v3 library uses an odd pattern of a top-level "||" with
+// a left-hand side that is value-dependent but never true. Identify
+// the idiom and ignore that term.
+static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) {
+ // Top-level '||'.
+ auto *BinOp = dyn_cast<BinaryOperator>(Cond->IgnoreParenImpCasts());
+ if (!BinOp) return Cond;
+
+ if (BinOp->getOpcode() != BO_LOr) return Cond;
+
+ // With an inner '==' that has a literal on the right-hand side.
+ Expr *LHS = BinOp->getLHS();
+ auto *InnerBinOp = dyn_cast<BinaryOperator>(LHS->IgnoreParenImpCasts());
+ if (!InnerBinOp) return Cond;
+
+ if (InnerBinOp->getOpcode() != BO_EQ ||
+ !isa<IntegerLiteral>(InnerBinOp->getRHS()))
+ return Cond;
+
+ // If the inner binary operation came from a macro expansion named
+ // CONCEPT_REQUIRES or CONCEPT_REQUIRES_, return the right-hand side
+ // of the '||', which is the real, user-provided condition.
+ SourceLocation Loc = InnerBinOp->getExprLoc();
+ if (!Loc.isMacroID()) return Cond;
+
+ StringRef MacroName = PP.getImmediateMacroName(Loc);
+ if (MacroName == "CONCEPT_REQUIRES" || MacroName == "CONCEPT_REQUIRES_")
+ return BinOp->getRHS();
+
+ return Cond;
+}
+
+std::pair<Expr *, std::string>
+Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
+ Cond = lookThroughRangesV3Condition(PP, Cond);
+
+ // Separate out all of the terms in a conjunction.
+ SmallVector<Expr *, 4> Terms;
+ collectConjunctionTerms(Cond, Terms);
+
+ // Determine which term failed.
+ Expr *FailedCond = nullptr;
+ for (Expr *Term : Terms) {
+ Expr *TermAsWritten = Term->IgnoreParenImpCasts();
+
+ // Literals are uninteresting.
+ if (isa<CXXBoolLiteralExpr>(TermAsWritten) ||
+ isa<IntegerLiteral>(TermAsWritten))
+ continue;
+
+ // The initialization of the parameter from the argument is
+ // a constant-evaluated context.
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ bool Succeeded;
+ if (Term->EvaluateAsBooleanCondition(Succeeded, Context) &&
+ !Succeeded) {
+ FailedCond = TermAsWritten;
+ break;
+ }
+ }
+
+ if (!FailedCond) {
+ if (!AllowTopLevelCond)
+ return { nullptr, "" };
+
+ FailedCond = Cond->IgnoreParenImpCasts();
+ }
+
+ std::string Description;
+ {
+ llvm::raw_string_ostream Out(Description);
+ FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+ }
+ return { FailedCond, Description };
+}
+
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
@@ -2754,12 +2959,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (Pattern->isInvalidDecl())
return QualType();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted);
+ TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
+ Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs);
unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth();
for (unsigned I = 0; I < Depth; ++I)
TemplateArgLists.addOuterTemplateArguments(None);
@@ -2772,8 +2977,43 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName());
- if (CanonType.isNull())
+ if (CanonType.isNull()) {
+ // If this was enable_if and we failed to find the nested type
+ // within enable_if in a SFINAE context, dig out the specific
+ // enable_if condition that failed and present that instead.
+ if (isEnableIfAliasTemplate(AliasTemplate)) {
+ if (auto DeductionInfo = isSFINAEContext()) {
+ if (*DeductionInfo &&
+ (*DeductionInfo)->hasSFINAEDiagnostic() &&
+ (*DeductionInfo)->peekSFINAEDiagnostic().second.getDiagID() ==
+ diag::err_typename_nested_not_found_enable_if &&
+ TemplateArgs[0].getArgument().getKind()
+ == TemplateArgument::Expression) {
+ Expr *FailedCond;
+ std::string FailedDescription;
+ std::tie(FailedCond, FailedDescription) =
+ findFailedBooleanCondition(
+ TemplateArgs[0].getSourceExpression(),
+ /*AllowTopLevelCond=*/true);
+
+ // Remove the old SFINAE diagnostic.
+ PartialDiagnosticAt OldDiag =
+ {SourceLocation(), PartialDiagnostic::NullDiagnostic()};
+ (*DeductionInfo)->takeSFINAEDiagnostic(OldDiag);
+
+ // Add a new SFINAE diagnostic specifying which condition
+ // failed.
+ (*DeductionInfo)->addSFINAEDiagnostic(
+ OldDiag.first,
+ PDiag(diag::err_typename_nested_not_found_requirement)
+ << FailedDescription
+ << FailedCond->getSourceRange());
+ }
+ }
+ }
+
return QualType();
+ }
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, InstantiationDependent)) {
@@ -2846,6 +3086,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);
@@ -3434,7 +3681,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// Check that this isn't a redefinition of this specialization,
// merging with previous declarations.
LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
PrevSpec.addDecl(PrevDecl);
D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
} else if (Specialization->isStaticDataMember() &&
@@ -3915,6 +4162,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
}
}
// fallthrough
+ LLVM_FALLTHROUGH;
}
default: {
// We have a template type parameter but the template argument
@@ -4047,8 +4295,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);
}
@@ -4557,7 +4805,12 @@ bool Sema::CheckTemplateArgumentList(
// template.
TemplateArgumentListInfo NewArgs = TemplateArgs;
- TemplateParameterList *Params = Template->getTemplateParameters();
+ // Make sure we get the template parameter list from the most
+ // recentdeclaration, since that is the only one that has is guaranteed to
+ // have all the default template argument information.
+ TemplateParameterList *Params =
+ cast<TemplateDecl>(Template->getMostRecentDecl())
+ ->getTemplateParameters();
SourceLocation RAngleLoc = NewArgs.getRAngleLoc();
@@ -4881,6 +5134,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType(
return Visit(T->getElementType());
}
+bool UnnamedLocalNoLinkageFinder::VisitDependentAddressSpaceType(
+ const DependentAddressSpaceType *T) {
+ return Visit(T->getPointeeType());
+}
+
bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) {
return Visit(T->getElementType());
}
@@ -5084,10 +5342,16 @@ enum NullPointerValueKind {
/// value of the appropriate type.
static NullPointerValueKind
isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
- QualType ParamType, Expr *Arg) {
+ QualType ParamType, Expr *Arg,
+ Decl *Entity = nullptr) {
if (Arg->isValueDependent() || Arg->isTypeDependent())
return NPV_NotNullPointer;
+ // dllimport'd entities aren't constant but are available inside of template
+ // arguments.
+ if (Entity && Entity->hasAttr<DLLImportAttr>())
+ return NPV_NotNullPointer;
+
if (!S.isCompleteType(Arg->getExprLoc(), ParamType))
llvm_unreachable(
"Incomplete parameter type in isNullPointerValueTemplateArgument!");
@@ -5331,14 +5595,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// If our parameter has pointer type, check for a null template value.
if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
- NullPointerValueKind NPV;
- // dllimport'd entities aren't constant but are available inside of template
- // arguments.
- if (Entity && Entity->hasAttr<DLLImportAttr>())
- NPV = NPV_NotNullPointer;
- else
- NPV = isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn);
- switch (NPV) {
+ switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn,
+ Entity)) {
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
@@ -5530,39 +5788,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
TemplateArgument &Converted) {
bool Invalid = false;
- // Check for a null pointer value.
Expr *Arg = ResultArg;
- switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
- case NPV_Error:
- return true;
- case NPV_NullPointer:
- S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
- return false;
- case NPV_NotNullPointer:
- break;
- }
-
bool ObjCLifetimeConversion;
- if (S.IsQualificationConversion(Arg->getType(),
- ParamType.getNonReferenceType(),
- false, ObjCLifetimeConversion)) {
- Arg = S.ImpCastExprToType(Arg, ParamType, CK_NoOp,
- Arg->getValueKind()).get();
- ResultArg = Arg;
- } else if (!S.Context.hasSameUnqualifiedType(Arg->getType(),
- ParamType.getNonReferenceType())) {
- // We can't perform this conversion.
- S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
- << Arg->getType() << ParamType << Arg->getSourceRange();
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
- // See through any implicit casts we added to fix the type.
- while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = Cast->getSubExpr();
// C++ [temp.arg.nontype]p1:
//
@@ -5619,6 +5846,37 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
DRE = nullptr;
}
+ ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr;
+
+ // Check for a null pointer value.
+ switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ResultArg,
+ Entity)) {
+ case NPV_Error:
+ return true;
+ case NPV_NullPointer:
+ S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
+ Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr*/true);
+ return false;
+ case NPV_NotNullPointer:
+ break;
+ }
+
+ if (S.IsQualificationConversion(ResultArg->getType(),
+ ParamType.getNonReferenceType(), false,
+ ObjCLifetimeConversion)) {
+ ResultArg = S.ImpCastExprToType(ResultArg, ParamType, CK_NoOp,
+ ResultArg->getValueKind())
+ .get();
+ } else if (!S.Context.hasSameUnqualifiedType(
+ ResultArg->getType(), ParamType.getNonReferenceType())) {
+ // We can't perform this conversion.
+ S.Diag(ResultArg->getLocStart(), diag::err_template_arg_not_convertible)
+ << ResultArg->getType() << ParamType << ResultArg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
if (!DRE)
return S.Diag(Arg->getLocStart(),
diag::err_template_arg_not_pointer_to_member_form)
@@ -5746,8 +6004,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:
@@ -5803,7 +6061,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));
@@ -5917,7 +6175,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- an integral constant-expression of integral or enumeration
// type; or
// -- the name of a non-type template-parameter; or
- SourceLocation NonConstantLoc;
llvm::APSInt Value;
if (!ArgType->isIntegralOrEnumerationType()) {
Diag(Arg->getLocStart(),
@@ -6425,15 +6682,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,
@@ -6490,10 +6738,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())) {
@@ -7334,7 +7583,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
NamedDecl *Hidden = nullptr;
if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
SkipBody->ShouldSkip = true;
- makeMergedDefinitionVisible(Hidden, KWLoc);
+ makeMergedDefinitionVisible(Hidden);
// From here on out, treat this as just a redeclaration.
TUK = TUK_Declaration;
} else if (Def) {
@@ -7497,6 +7746,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return false;
}
// Fall through
+ LLVM_FALLTHROUGH;
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
@@ -7523,6 +7773,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return true;
}
+ llvm_unreachable("The switch over PrevTSK must be exhaustive.");
case TSK_ExplicitInstantiationDeclaration:
switch (PrevTSK) {
@@ -7804,9 +8055,13 @@ bool Sema::CheckFunctionTemplateSpecialization(
TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) {
Specialization->setLocation(FD->getLocation());
+ Specialization->setLexicalDeclContext(FD->getLexicalDeclContext());
// C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr
// function can differ from the template declaration with respect to
// the constexpr specifier.
+ // FIXME: We need an update record for this AST mutation.
+ // FIXME: What if there are multiple such prior declarations (for instance,
+ // from different modules)?
Specialization->setConstexpr(FD->isConstexpr());
}
@@ -7854,11 +8109,14 @@ bool Sema::CheckFunctionTemplateSpecialization(
// flag to not-deleted, so that we can inherit that information from 'FD'.
if (Specialization->isDeleted() && !SpecInfo->isExplicitSpecialization() &&
!Specialization->getCanonicalDecl()->isReferenced()) {
+ // FIXME: This assert will not hold in the presence of modules.
assert(
Specialization->getCanonicalDecl() == Specialization &&
"This must be the only existing declaration of this specialization");
+ // FIXME: We need an update record for this AST mutation.
Specialization->setDeletedAsWritten(false);
}
+ // FIXME: We need an update record for this AST mutation.
SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(Specialization);
}
@@ -7969,8 +8227,11 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
return false;
}
- // If this is a friend, just bail out here before we start turning
- // things into explicit specializations.
+ // A member specialization in a friend declaration isn't really declaring
+ // an explicit specialization, just identifying a specific (possibly implicit)
+ // specialization. Don't change the template specialization kind.
+ //
+ // FIXME: Is this really valid? Other compilers reject.
if (Member->getFriendObjectKind() != Decl::FOK_None) {
// Preserve instantiation information.
if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
@@ -8020,66 +8281,36 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
false))
return true;
- // Note that this is an explicit instantiation of a member.
- // the original declaration to note that it is an explicit specialization
- // (if it was previously an implicit instantiation). This latter step
- // makes bookkeeping easier.
- if (isa<FunctionDecl>(Member)) {
+ // Note that this member specialization is an "instantiation of" the
+ // corresponding member of the original template.
+ if (auto *MemberFunction = dyn_cast<FunctionDecl>(Member)) {
FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation);
if (InstantiationFunction->getTemplateSpecializationKind() ==
TSK_ImplicitInstantiation) {
- InstantiationFunction->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationFunction->setLocation(Member->getLocation());
// Explicit specializations of member functions of class templates do not
// inherit '=delete' from the member function they are specializing.
if (InstantiationFunction->isDeleted()) {
+ // FIXME: This assert will not hold in the presence of modules.
assert(InstantiationFunction->getCanonicalDecl() ==
InstantiationFunction);
+ // FIXME: We need an update record for this AST mutation.
InstantiationFunction->setDeletedAsWritten(false);
}
}
- cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
- cast<CXXMethodDecl>(InstantiatedFrom),
- TSK_ExplicitSpecialization);
- MarkUnusedFileScopedDecl(InstantiationFunction);
- } else if (isa<VarDecl>(Member)) {
- VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
- if (InstantiationVar->getTemplateSpecializationKind() ==
- TSK_ImplicitInstantiation) {
- InstantiationVar->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationVar->setLocation(Member->getLocation());
- }
-
- cast<VarDecl>(Member)->setInstantiationOfStaticDataMember(
+ MemberFunction->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
+ } else if (auto *MemberVar = dyn_cast<VarDecl>(Member)) {
+ MemberVar->setInstantiationOfStaticDataMember(
cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
- MarkUnusedFileScopedDecl(InstantiationVar);
- } else if (isa<CXXRecordDecl>(Member)) {
- CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
- if (InstantiationClass->getTemplateSpecializationKind() ==
- TSK_ImplicitInstantiation) {
- InstantiationClass->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationClass->setLocation(Member->getLocation());
- }
-
- cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
- cast<CXXRecordDecl>(InstantiatedFrom),
- TSK_ExplicitSpecialization);
- } else {
- assert(isa<EnumDecl>(Member) && "Only member enums remain");
- EnumDecl *InstantiationEnum = cast<EnumDecl>(Instantiation);
- if (InstantiationEnum->getTemplateSpecializationKind() ==
- TSK_ImplicitInstantiation) {
- InstantiationEnum->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationEnum->setLocation(Member->getLocation());
- }
-
- cast<EnumDecl>(Member)->setInstantiationOfMemberEnum(
+ } else if (auto *MemberClass = dyn_cast<CXXRecordDecl>(Member)) {
+ MemberClass->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
+ } else if (auto *MemberEnum = dyn_cast<EnumDecl>(Member)) {
+ MemberEnum->setInstantiationOfMemberEnum(
cast<EnumDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
+ } else {
+ llvm_unreachable("unknown member specialization kind");
}
// Save the caller the trouble of having to figure out which declaration
@@ -8089,6 +8320,43 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
return false;
}
+/// Complete the explicit specialization of a member of a class template by
+/// updating the instantiated member to be marked as an explicit specialization.
+///
+/// \param OrigD The member declaration instantiated from the template.
+/// \param Loc The location of the explicit specialization of the member.
+template<typename DeclT>
+static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD,
+ SourceLocation Loc) {
+ if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
+ return;
+
+ // FIXME: Inform AST mutation listeners of this AST mutation.
+ // FIXME: If there are multiple in-class declarations of the member (from
+ // multiple modules, or a declaration and later definition of a member type),
+ // should we update all of them?
+ OrigD->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+ OrigD->setLocation(Loc);
+}
+
+void Sema::CompleteMemberSpecialization(NamedDecl *Member,
+ LookupResult &Previous) {
+ NamedDecl *Instantiation = cast<NamedDecl>(Member->getCanonicalDecl());
+ if (Instantiation == Member)
+ return;
+
+ if (auto *Function = dyn_cast<CXXMethodDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Function, Member->getLocation());
+ else if (auto *Var = dyn_cast<VarDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Var, Member->getLocation());
+ else if (auto *Record = dyn_cast<CXXRecordDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Record, Member->getLocation());
+ else if (auto *Enum = dyn_cast<EnumDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Enum, Member->getLocation());
+ else
+ llvm_unreachable("unknown member specialization kind");
+}
+
/// \brief Check the scope of an explicit instantiation.
///
/// \returns true if a serious error occurs, false otherwise.
@@ -8495,7 +8763,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
SourceLocation(), false, TypeResult(),
- /*IsTypeSpecifier*/false);
+ /*IsTypeSpecifier*/false,
+ /*IsTemplateParamOrArg*/false);
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -8841,7 +9110,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// A member function [...] of a class template can be explicitly
// instantiated from the member definition associated with its class
// template.
- UnresolvedSet<8> Matches;
+ UnresolvedSet<8> TemplateMatches;
+ FunctionDecl *NonTemplateMatch = nullptr;
AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc());
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
@@ -8852,11 +9122,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
QualType Adjusted = adjustCCAndNoReturn(R, Method->getType(),
/*AdjustExceptionSpec*/true);
if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) {
- Matches.clear();
-
- Matches.addDecl(Method, P.getAccess());
- if (Method->getTemplateSpecializationKind() == TSK_Undeclared)
- break;
+ if (Method->getPrimaryTemplate()) {
+ TemplateMatches.addDecl(Method, P.getAccess());
+ } else {
+ // FIXME: Can this assert ever happen? Needs a test.
+ assert(!NonTemplateMatch && "Multiple NonTemplateMatches");
+ NonTemplateMatch = Method;
+ }
}
}
}
@@ -8895,22 +9167,25 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
continue;
}
- Matches.addDecl(Specialization, P.getAccess());
+ TemplateMatches.addDecl(Specialization, P.getAccess());
}
- // Find the most specialized function template specialization.
- UnresolvedSetIterator Result = getMostSpecialized(
- Matches.begin(), Matches.end(), FailedCandidates,
- D.getIdentifierLoc(),
- PDiag(diag::err_explicit_instantiation_not_known) << Name,
- PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
- PDiag(diag::note_explicit_instantiation_candidate));
-
- if (Result == Matches.end())
- return true;
+ FunctionDecl *Specialization = NonTemplateMatch;
+ if (!Specialization) {
+ // Find the most specialized function template specialization.
+ UnresolvedSetIterator Result = getMostSpecialized(
+ TemplateMatches.begin(), TemplateMatches.end(), FailedCandidates,
+ D.getIdentifierLoc(),
+ PDiag(diag::err_explicit_instantiation_not_known) << Name,
+ PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
+ PDiag(diag::note_explicit_instantiation_candidate));
+
+ if (Result == TemplateMatches.end())
+ return true;
- // Ignore access control bits, we don't need them for redeclaration checking.
- FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
+ // Ignore access control bits, we don't need them for redeclaration checking.
+ Specialization = cast<FunctionDecl>(*Result);
+ }
// C++11 [except.spec]p4
// In an explicit instantiation an exception-specification may be specified,
@@ -9166,7 +9441,7 @@ Sema::ActOnTypenameType(Scope *S,
/// Determine whether this failed name lookup should be treated as being
/// disabled by a usage of std::enable_if.
static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
- SourceRange &CondRange) {
+ SourceRange &CondRange, Expr *&Cond) {
// We must be looking for a ::type...
if (!II.isStr("type"))
return false;
@@ -9196,6 +9471,19 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
// Assume the first template argument is the condition.
CondRange = EnableIfTSTLoc.getArgLoc(0).getSourceRange();
+
+ // Dig out the condition.
+ Cond = nullptr;
+ if (EnableIfTSTLoc.getArgLoc(0).getArgument().getKind()
+ != TemplateArgument::Expression)
+ return true;
+
+ Cond = EnableIfTSTLoc.getArgLoc(0).getSourceExpression();
+
+ // Ignore Boolean literals; they add no value.
+ if (isa<CXXBoolLiteralExpr>(Cond->IgnoreParenCasts()))
+ Cond = nullptr;
+
return true;
}
@@ -9239,9 +9527,25 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// If we're looking up 'type' within a template named 'enable_if', produce
// a more specific diagnostic.
SourceRange CondRange;
- if (isEnableIf(QualifierLoc, II, CondRange)) {
+ Expr *Cond = nullptr;
+ if (isEnableIf(QualifierLoc, II, CondRange, Cond)) {
+ // If we have a condition, narrow it down to the specific failed
+ // condition.
+ if (Cond) {
+ Expr *FailedCond;
+ std::string FailedDescription;
+ std::tie(FailedCond, FailedDescription) =
+ findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
+
+ Diag(FailedCond->getExprLoc(),
+ diag::err_typename_nested_not_found_requirement)
+ << FailedDescription
+ << FailedCond->getSourceRange();
+ return QualType();
+ }
+
Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if)
- << Ctx << CondRange;
+ << Ctx << CondRange;
return QualType();
}
@@ -9265,6 +9569,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
}
// Fall through to create a dependent typename type, from which we can recover
// better.
+ LLVM_FALLTHROUGH;
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
@@ -9633,7 +9938,7 @@ private:
IsHiddenExplicitSpecialization =
Spec->getMemberSpecializationInfo()
? !S.hasVisibleMemberSpecialization(Spec, &Modules)
- : !S.hasVisibleDeclaration(Spec);
+ : !S.hasVisibleExplicitSpecialization(Spec, &Modules);
} else {
checkInstantiated(Spec);
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 4116ae979b..51f21be64a 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -56,8 +56,12 @@ namespace clang {
TDF_TopLevelParameterTypeList = 0x10,
/// \brief Within template argument deduction from overload resolution per
/// C++ [over.over] allow matching function types that are compatible in
- /// terms of noreturn and default calling convention adjustments.
- TDF_InOverloadResolution = 0x20
+ /// terms of noreturn and default calling convention adjustments, or
+ /// similarly matching a declared template specialization against a
+ /// possible template, per C++ [temp.deduct.decl]. In either case, permit
+ /// deduction where the parameter is a function type that can be converted
+ /// to the argument type.
+ TDF_AllowCompatibleFunctionType = 0x20,
};
}
@@ -1306,9 +1310,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// If the parameter type is not dependent, there is nothing to deduce.
if (!Param->isDependentType()) {
if (!(TDF & TDF_SkipNonDependent)) {
- bool NonDeduced = (TDF & TDF_InOverloadResolution)?
- !S.isSameOrCompatibleFunctionType(CanParam, CanArg) :
- Param != Arg;
+ bool NonDeduced =
+ (TDF & TDF_AllowCompatibleFunctionType)
+ ? !S.isSameOrCompatibleFunctionType(CanParam, CanArg)
+ : Param != Arg;
if (NonDeduced) {
return Sema::TDK_NonDeducedMismatch;
}
@@ -1318,10 +1323,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
} else if (!Param->isDependentType()) {
CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
ArgUnqualType = CanArg.getUnqualifiedType();
- bool Success = (TDF & TDF_InOverloadResolution)?
- S.isSameOrCompatibleFunctionType(ParamUnqualType,
- ArgUnqualType) :
- ParamUnqualType == ArgUnqualType;
+ bool Success =
+ (TDF & TDF_AllowCompatibleFunctionType)
+ ? S.isSameOrCompatibleFunctionType(ParamUnqualType, ArgUnqualType)
+ : ParamUnqualType == ArgUnqualType;
if (Success)
return Sema::TDK_Success;
}
@@ -1524,17 +1529,56 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
// Check return types.
- if (Sema::TemplateDeductionResult Result =
- DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, FunctionProtoParam->getReturnType(),
- FunctionProtoArg->getReturnType(), Info, Deduced, 0))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, FunctionProtoParam->getReturnType(),
+ FunctionProtoArg->getReturnType(), Info, Deduced, 0))
return Result;
- return DeduceTemplateArguments(
- S, TemplateParams, FunctionProtoParam->param_type_begin(),
- FunctionProtoParam->getNumParams(),
- FunctionProtoArg->param_type_begin(),
- FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF);
+ // Check parameter types.
+ if (auto Result = DeduceTemplateArguments(
+ S, TemplateParams, FunctionProtoParam->param_type_begin(),
+ FunctionProtoParam->getNumParams(),
+ FunctionProtoArg->param_type_begin(),
+ FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF))
+ return Result;
+
+ if (TDF & TDF_AllowCompatibleFunctionType)
+ return Sema::TDK_Success;
+
+ // FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit
+ // deducing through the noexcept-specifier if it's part of the canonical
+ // type. libstdc++ relies on this.
+ Expr *NoexceptExpr = FunctionProtoParam->getNoexceptExpr();
+ if (NonTypeTemplateParmDecl *NTTP =
+ NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
+ : nullptr) {
+ assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ "saw non-type template parameter with wrong depth");
+
+ llvm::APSInt Noexcept(1);
+ switch (FunctionProtoArg->canThrow(S.Context)) {
+ case CT_Cannot:
+ Noexcept = 1;
+ LLVM_FALLTHROUGH;
+
+ case CT_Can:
+ // We give E in noexcept(E) the "deduced from array bound" treatment.
+ // FIXME: Should we?
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy,
+ /*ArrayBound*/true, Info, Deduced);
+
+ case CT_Dependent:
+ if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr())
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced);
+ // Can't deduce anything from throw(T...).
+ break;
+ }
+ }
+ // FIXME: Detect non-deduced exception specification mismatches?
+
+ return Sema::TDK_Success;
}
case Type::InjectedClassName: {
@@ -1544,7 +1588,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
->getInjectedSpecializationType();
assert(isa<TemplateSpecializationType>(Param) &&
"injected class name is not a template specialization type");
- // fall through
+ LLVM_FALLTHROUGH;
}
// template-name<T> (where template-name refers to a class template)
@@ -1799,6 +1843,59 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
}
+ // (clang extension)
+ //
+ // T __attribute__(((address_space(N))))
+ case Type::DependentAddressSpace: {
+ const DependentAddressSpaceType *AddressSpaceParam =
+ cast<DependentAddressSpaceType>(Param);
+
+ if (const DependentAddressSpaceType *AddressSpaceArg =
+ dyn_cast<DependentAddressSpaceType>(Arg)) {
+ // Perform deduction on the pointer type.
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, AddressSpaceParam->getPointeeType(),
+ AddressSpaceArg->getPointeeType(), Info, Deduced, TDF))
+ return Result;
+
+ // Perform deduction on the address space, if we can.
+ NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+ Info, AddressSpaceParam->getAddrSpaceExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info,
+ Deduced);
+ }
+
+ if (isTargetAddressSpace(Arg.getAddressSpace())) {
+ llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy),
+ false);
+ ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace());
+
+ // Perform deduction on the pointer types.
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, AddressSpaceParam->getPointeeType(),
+ S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF))
+ return Result;
+
+ // Perform deduction on the address space, if we can.
+ NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+ Info, AddressSpaceParam->getAddrSpaceExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ ArgAddressSpace, S.Context.IntTy,
+ true, Info, Deduced);
+ }
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::DependentName:
@@ -2383,7 +2480,8 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
bool HasDefaultArg = false;
TemplateDecl *TD = dyn_cast<TemplateDecl>(Template);
if (!TD) {
- assert(isa<ClassTemplatePartialSpecializationDecl>(Template));
+ assert(isa<ClassTemplatePartialSpecializationDecl>(Template) ||
+ isa<VarTemplatePartialSpecializationDecl>(Template));
return Sema::TDK_Incomplete;
}
@@ -2447,7 +2545,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));
@@ -2525,7 +2624,8 @@ static Sema::TemplateDeductionResult 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(Template));
@@ -2575,7 +2675,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;
@@ -2617,7 +2718,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;
@@ -2646,6 +2748,17 @@ static bool isSimpleTemplateIdType(QualType T) {
= T->getAs<TemplateSpecializationType>())
return Spec->getTemplateName().getAsTemplateDecl() != nullptr;
+ // C++17 [temp.local]p2:
+ // the injected-class-name [...] is equivalent to the template-name followed
+ // by the template-arguments of the class template specialization or partial
+ // specialization enclosed in <>
+ // ... which means it's equivalent to a simple-template-id.
+ //
+ // This only arises during class template argument deduction for a copy
+ // deduction candidate, where it permits slicing.
+ if (T->getAs<InjectedClassNameType>())
+ return true;
+
return false;
}
@@ -2697,7 +2810,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:
@@ -2814,6 +2928,17 @@ Sema::SubstituteExplicitTemplateArguments(
if (FunctionType) {
auto EPI = Proto->getExtProtoInfo();
EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size());
+
+ // In C++1z onwards, exception specifications are part of the function type,
+ // so substitution into the type must also substitute into the exception
+ // specification.
+ SmallVector<QualType, 4> ExceptionStorage;
+ if (getLangOpts().CPlusPlus1z &&
+ SubstExceptionSpec(
+ Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
+ return TDK_SubstitutionFailure;
+
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
Function->getLocation(),
Function->getDeclName(),
@@ -2846,17 +2971,26 @@ Sema::SubstituteExplicitTemplateArguments(
/// \brief Check whether the deduced argument type for a call to a function
/// template matches the actual argument type per C++ [temp.deduct.call]p4.
-static bool
-CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
+static Sema::TemplateDeductionResult
+CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info,
+ Sema::OriginalCallArg OriginalArg,
QualType DeducedA) {
ASTContext &Context = S.Context;
+ auto Failed = [&]() -> Sema::TemplateDeductionResult {
+ Info.FirstArg = TemplateArgument(DeducedA);
+ Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
+ Info.CallArgIndex = OriginalArg.ArgIdx;
+ return OriginalArg.DecomposedParam ? Sema::TDK_DeducedMismatchNested
+ : Sema::TDK_DeducedMismatch;
+ };
+
QualType A = OriginalArg.OriginalArgType;
QualType OriginalParamType = OriginalArg.OriginalParamType;
// Check for type equality (top-level cv-qualifiers are ignored).
if (Context.hasSameUnqualifiedType(A, DeducedA))
- return false;
+ return Sema::TDK_Success;
// Strip off references on the argument types; they aren't needed for
// the following checks.
@@ -2880,7 +3014,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
// the deduced A can be F.
QualType Tmp;
if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp))
- return false;
+ return Sema::TDK_Success;
Qualifiers AQuals = A.getQualifiers();
Qualifiers DeducedAQuals = DeducedA.getQualifiers();
@@ -2900,7 +3034,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
if (AQuals == DeducedAQuals) {
// Qualifiers match; there's nothing to do.
} else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
- return true;
+ return Failed();
} else {
// Qualifiers are compatible, so have the argument type adopt the
// deduced argument type's qualifiers as if we had performed the
@@ -2921,7 +3055,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
(S.IsQualificationConversion(A, DeducedA, false,
ObjCLifetimeConversion) ||
S.IsFunctionConversion(A, DeducedA, ResultTy)))
- return false;
+ return Sema::TDK_Success;
// - If P is a class and P has the form simple-template-id, then the
// transformed A can be a derived class of the deduced A. [...]
@@ -2942,13 +3076,13 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
}
if (Context.hasSameUnqualifiedType(A, DeducedA))
- return false;
+ return Sema::TDK_Success;
if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) &&
S.IsDerivedFrom(SourceLocation(), A, DeducedA))
- return false;
+ return Sema::TDK_Success;
- return true;
+ return Failed();
}
/// Find the pack index for a particular parameter index in an instantiation of
@@ -2995,7 +3129,8 @@ 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
@@ -3103,13 +3238,9 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
DeducedA = CacheEntry;
}
- if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
- Info.FirstArg = TemplateArgument(DeducedA);
- Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
- Info.CallArgIndex = OriginalArg.ArgIdx;
- return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested
- : TDK_DeducedMismatch;
- }
+ if (auto TDK =
+ CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA))
+ return TDK;
}
}
@@ -3707,13 +3838,6 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
= FunctionTemplate->getTemplateParameters();
QualType FunctionType = Function->getType();
- // When taking the address of a function, we require convertibility of
- // the resulting function type. Otherwise, we allow arbitrary mismatches
- // of calling convention, noreturn, and noexcept.
- if (!IsAddressOfFunction)
- ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType,
- /*AdjustExceptionSpec*/true);
-
// Substitute any explicit template arguments.
LocalInstantiationScope InstScope(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
@@ -3730,8 +3854,16 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
NumExplicitlySpecified = Deduced.size();
}
+ // When taking the address of a function, we require convertibility of
+ // the resulting function type. Otherwise, we allow arbitrary mismatches
+ // of calling convention and noreturn.
+ if (!IsAddressOfFunction)
+ ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType,
+ /*AdjustExceptionSpec*/false);
+
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
Deduced.resize(TemplateParams->size());
@@ -3748,9 +3880,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
if (!ArgFunctionType.isNull()) {
- unsigned TDF = TDF_TopLevelParameterTypeList;
- if (IsAddressOfFunction)
- TDF |= TDF_InOverloadResolution;
+ unsigned TDF =
+ TDF_TopLevelParameterTypeList | TDF_AllowCompatibleFunctionType;
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
@@ -3781,7 +3912,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TDK_MiscellaneousDeductionFailure;
- // Adjust the exception specification of the argument again to match the
+ // Adjust the exception specification of the argument to match the
// substituted and resolved type we just formed. (Calling convention and
// noreturn can't be dependent, so we don't actually need this for them
// right now.)
@@ -3979,7 +4110,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:
@@ -4168,6 +4300,31 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
DependentDeductionDepth);
}
+/// Attempt to produce an informative diagostic explaining why auto deduction
+/// failed.
+/// \return \c true if diagnosed, \c false if not.
+static bool diagnoseAutoDeductionFailure(Sema &S,
+ Sema::TemplateDeductionResult TDK,
+ TemplateDeductionInfo &Info,
+ ArrayRef<SourceRange> Ranges) {
+ switch (TDK) {
+ case Sema::TDK_Inconsistent: {
+ // Inconsistent deduction means we were deducing from an initializer list.
+ auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
+ D << Info.FirstArg << Info.SecondArg;
+ for (auto R : Ranges)
+ D << R;
+ return true;
+ }
+
+ // FIXME: Are there other cases for which a custom diagnostic is more useful
+ // than the basic "types don't match" diagnostic?
+
+ default:
+ return false;
+ }
+}
+
/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// Note that this is done even if the initializer is dependent. (This is
@@ -4255,12 +4412,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// If deduction failed, don't diagnose if the initializer is dependent; it
// might acquire a matching type in the instantiation.
- auto DeductionFailed = [&]() -> DeduceAutoResult {
+ auto DeductionFailed = [&](TemplateDeductionResult TDK,
+ ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
if (Init->isTypeDependent()) {
Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
+ if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges))
+ return DAR_FailedAlreadyDiagnosed;
return DAR_Failed;
};
@@ -4274,12 +4434,20 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
return DAR_Failed;
+ SourceRange DeducedFromInitRange;
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- if (DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, TemplArg, InitList->getInit(i),
+ Expr *Init = InitList->getInit(i);
+
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), 0, TemplArg, Init,
Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
/*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed();
+ return DeductionFailed(TDK, {DeducedFromInitRange,
+ Init->getSourceRange()});
+
+ if (DeducedFromInitRange.isInvalid() &&
+ Deduced[0].getKind() != TemplateArgument::Null)
+ DeducedFromInitRange = Init->getSourceRange();
}
} else {
if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
@@ -4287,15 +4455,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
- if (DeduceTemplateArgumentsFromCallArgument(
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed();
+ return DeductionFailed(TDK, {});
}
// Could be null if somehow 'auto' appears in a non-deduced context.
if (Deduced[0].getKind() != TemplateArgument::Type)
- return DeductionFailed();
+ return DeductionFailed(TDK_Incomplete, {});
QualType DeducedType = Deduced[0].getAsType();
@@ -4315,9 +4483,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
assert((bool)InitList == OriginalArg.DecomposedParam &&
"decomposed non-init-list in auto deduction?");
- if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
+ if (auto TDK =
+ CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
Result = QualType();
- return DeductionFailed();
+ return DeductionFailed(TDK, {});
}
}
@@ -5085,6 +5254,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
OnlyDeduced, Depth, Used);
// Fall through to check the element type
+ LLVM_FALLTHROUGH;
case Type::ConstantArray:
case Type::IncompleteArray:
@@ -5110,6 +5280,17 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
break;
}
+ case Type::DependentAddressSpace: {
+ const DependentAddressSpaceType *DependentASType =
+ cast<DependentAddressSpaceType>(T);
+ MarkUsedTemplateParameters(Ctx, DependentASType->getPointeeType(),
+ OnlyDeduced, Depth, Used);
+ MarkUsedTemplateParameters(Ctx,
+ DependentASType->getAddrSpaceExpr(),
+ OnlyDeduced, Depth, Used);
+ break;
+ }
+
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth,
@@ -5117,6 +5298,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I)
MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced,
Depth, Used);
+ if (auto *E = Proto->getNoexceptExpr())
+ MarkUsedTemplateParameters(Ctx, E, OnlyDeduced, Depth, Used);
break;
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 314dfe3256..16f7381330 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -197,6 +197,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
+ case DefiningSynthesizedFunction:
return false;
}
@@ -624,6 +625,17 @@ void Sema::PrintInstantiationStack() {
diag::note_in_declaration_of_implicit_special_member)
<< cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
break;
+
+ case CodeSynthesisContext::DefiningSynthesizedFunction:
+ // FIXME: For synthesized members other than special members, produce a note.
+ auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity);
+ auto CSM = MD ? getSpecialMember(MD) : CXXInvalid;
+ if (CSM != CXXInvalid) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_member_synthesized_at)
+ << CSM << Context.getTagDeclType(MD->getParent());
+ }
+ break;
}
}
}
@@ -666,6 +678,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
return Active->DeductionInfo;
case CodeSynthesisContext::DeclaringSpecialMember:
+ case CodeSynthesisContext::DefiningSynthesizedFunction:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
return None;
@@ -962,7 +975,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
return Template.getAsTemplateDecl();
@@ -1109,14 +1122,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
assert(!Template.isNull() && "Null template template argument");
-
- // We don't ever want to substitute for a qualified template name, since
- // the qualifier is handled separately. So, look through the qualified
- // template name to its underlying declaration.
- if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- Template = TemplateName(QTN->getTemplateDecl());
+ assert(!Template.getAsQualifiedTemplateName() &&
+ "template decl to substitute is qualified?");
Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template);
return Template;
@@ -1130,7 +1139,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(
TemplateArgument Arg = SubstPack->getArgumentPack();
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- return Arg.getAsTemplate();
+ return Arg.getAsTemplate().getNameToSubstitute();
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
@@ -1679,20 +1688,26 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
return TLB.getTypeSourceInfo(Context, Result);
}
+bool Sema::SubstExceptionSpec(SourceLocation Loc,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
+ SmallVectorImpl<QualType> &ExceptionStorage,
+ const MultiLevelTemplateArgumentList &Args) {
+ assert(ESI.Type != EST_Uninstantiated);
+
+ bool Changed = false;
+ TemplateInstantiator Instantiator(*this, Args, Loc, DeclarationName());
+ return Instantiator.TransformExceptionSpec(Loc, ESI, ExceptionStorage,
+ Changed);
+}
+
void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
const MultiLevelTemplateArgumentList &Args) {
FunctionProtoType::ExceptionSpecInfo ESI =
Proto->getExtProtoInfo().ExceptionSpec;
- assert(ESI.Type != EST_Uninstantiated);
-
- TemplateInstantiator Instantiator(*this, Args, New->getLocation(),
- New->getDeclName());
SmallVector<QualType, 4> ExceptionStorage;
- bool Changed = false;
- if (Instantiator.TransformExceptionSpec(
- New->getTypeSourceInfo()->getTypeLoc().getLocEnd(), ESI,
- ExceptionStorage, Changed))
+ if (SubstExceptionSpec(New->getTypeSourceInfo()->getTypeLoc().getLocEnd(),
+ ESI, ExceptionStorage, Args))
// On error, recover by dropping the exception specification.
ESI.Type = EST_None;
@@ -1939,6 +1954,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);
}
}
@@ -1999,8 +2017,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
@@ -2008,12 +2026,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod();
LocalInstantiationScope Scope(*this, MergeWithParentScope);
- // All dllexported classes created during instantiation should be fully
- // emitted after instantiation completes. We may not be ready to emit any
- // delayed classes already on the stack, so save them away and put them back
- // later.
- decltype(DelayedDllExportClasses) ExportedClasses;
- std::swap(ExportedClasses, DelayedDllExportClasses);
+ // Some class state isn't processed immediately but delayed till class
+ // instantiation completes. We may not be ready to handle any delayed state
+ // already on the stack as it might correspond to a different class, so save
+ // it now and put it back later.
+ SavePendingParsedClassStateRAII SavedPendingParsedClassState(*this);
// Pull attributes from the pattern onto the instantiation.
InstantiateAttrs(TemplateArgs, Pattern, Instantiation);
@@ -2023,7 +2040,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Instantiation->setHidden(false);
+ Instantiation->setVisibleDespiteOwningModule();
// FIXME: This loses the as-written tag kind for an explicit instantiation.
Instantiation->setTagKind(Pattern->getTagKind());
@@ -2100,9 +2117,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// default arg exprs for default constructors if necessary now.
ActOnFinishCXXNonNestedClass(Instantiation);
- // Put back the delayed exported classes that we moved out of the way.
- std::swap(ExportedClasses, DelayedDllExportClasses);
-
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
@@ -2225,13 +2239,13 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Instantiation->setHidden(false);
+ Instantiation->setVisibleDespiteOwningModule();
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII SavedContext(*this, Instantiation);
- EnterExpressionEvaluationContext EvalContext(*this,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EvalContext(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
LocalInstantiationScope Scope(*this, /*MergeWithParentScope*/true);
@@ -2302,8 +2316,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);
@@ -2334,6 +2348,25 @@ namespace {
};
}
+bool Sema::usesPartialOrExplicitSpecialization(
+ SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec) {
+ if (ClassTemplateSpec->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization)
+ return true;
+
+ SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ ClassTemplateSpec->getSpecializedTemplate()
+ ->getPartialSpecializations(PartialSpecs);
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
+ TemplateDeductionInfo Info(Loc);
+ if (!DeduceTemplateArguments(PartialSpecs[I],
+ ClassTemplateSpec->getTemplateArgs(), Info))
+ return true;
+ }
+
+ return false;
+}
+
/// Get the instantiation pattern to use to instantiate the definition of a
/// given ClassTemplateSpecializationDecl (either the pattern of the primary
/// template or of a partial specialization).
@@ -2602,10 +2635,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
== TSK_ExplicitSpecialization)
continue;
- if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+ Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
TSK == TSK_ExplicitInstantiationDeclaration) {
- // In MSVC mode, explicit instantiation decl of the outer class doesn't
- // affect the inner class.
+ // In MSVC and Windows Itanium mode, explicit instantiation decl of the
+ // outer class doesn't affect the inner class.
continue;
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index cab55ea0bf..5b528fa9c2 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);
}
}
@@ -627,6 +677,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) {
auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getIdentifier());
+ NewBD->setReferenced(D->isReferenced());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD);
return NewBD;
}
@@ -745,8 +796,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);
@@ -922,8 +973,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);
@@ -1033,8 +1084,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);
}
@@ -1144,7 +1195,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Look for a previous declaration of the template in the owning
// context.
LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ Sema::LookupOrdinaryName,
+ SemaRef.forRedeclarationInCurContext());
SemaRef.LookupQualifiedName(R, DC);
if (R.isSingleResult()) {
@@ -1490,8 +1542,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
// DR1484 clarifies that the members of a local class are instantiated as part
// of the instantiation of their enclosing entity.
if (D->isCompleteDefinition() && D->isLocalClass()) {
- Sema::SavePendingLocalImplicitInstantiationsRAII
- SavedPendingLocalImplicitInstantiations(SemaRef);
+ Sema::LocalEagerInstantiationScope LocalInstantiations(SemaRef);
SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
TSK_ImplicitInstantiation,
@@ -1505,7 +1556,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
// This class may have local implicit instantiations that need to be
// performed within this scope.
- SemaRef.PerformPendingInstantiations(/*LocalOnly=*/true);
+ LocalInstantiations.perform();
}
SemaRef.DiagnoseUnusedNestedTypedefs(Record);
@@ -1600,11 +1651,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
FunctionDecl *Function;
- if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D))
+ 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 {
+ SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
+ D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd());
+ if (DGuide->isCopyDeductionCandidate())
+ cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
+ } else {
Function = FunctionDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo,
D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
@@ -1635,7 +1688,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Params[P]->setOwningFunction(Function);
Function->setParams(Params);
- SourceLocation InstantiateAtPOI;
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -1686,7 +1738,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
SemaRef, Function->getDeclName(), SourceLocation(),
D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
: Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ D->isLocalExternDecl() ? Sema::ForExternalRedeclaration
+ : SemaRef.forRedeclarationInCurContext());
if (DependentFunctionTemplateSpecializationInfo *Info
= D->getDependentSpecializationInfo()) {
@@ -1733,6 +1786,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Previous.clear();
}
+ if (isFriend)
+ Function->setObjectOfFriendDecl();
+
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
isExplicitSpecialization);
@@ -1799,6 +1855,19 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
}
}
+
+ // Check the template parameter list against the previous declaration. The
+ // goal here is to pick up default arguments added since the friend was
+ // declared; we know the template parameter lists match, since otherwise
+ // we would not have picked this template as the previous declaration.
+ if (TemplateParams && FunctionTemplate->getPreviousDecl()) {
+ SemaRef.CheckTemplateParameterList(
+ TemplateParams,
+ FunctionTemplate->getPreviousDecl()->getTemplateParameters(),
+ Function->isThisDeclarationADefinition()
+ ? Sema::TPC_FriendFunctionTemplateDefinition
+ : Sema::TPC_FriendFunctionTemplate);
+ }
}
if (Function->isLocalExternDecl() && !Function->getPreviousDecl())
@@ -1988,7 +2057,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setInvalidDecl();
LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ Sema::ForExternalRedeclaration);
if (!FunctionTemplate || TemplateParams || isFriend) {
SemaRef.LookupQualifiedName(Previous, Record);
@@ -2229,8 +2298,8 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
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());
@@ -2427,7 +2496,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
bool CheckRedeclaration = Owner->isRecord();
LookupResult Prev(SemaRef, NameInfo, Sema::LookupUsingDeclName,
- Sema::ForRedeclaration);
+ Sema::ForVisibleRedeclaration);
UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner,
D->getUsingLoc(),
@@ -2646,7 +2715,7 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
return nullptr;
LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ Sema::ForExternalRedeclaration);
TemplateArgumentListInfo TemplateArgs;
TemplateArgumentListInfo *TemplateArgsPtr = nullptr;
@@ -2734,8 +2803,9 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner);
// Initializers instantiation sequence.
if (D->getInitializer()) {
- SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
- /*S=*/nullptr, NewDRD);
+ VarDecl *OmpPrivParm =
+ SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
+ /*S=*/nullptr, NewDRD);
const char *Names[] = {"omp_orig", "omp_priv"};
for (auto &Name : Names) {
DeclarationName DN(&SemaRef.Context.Idents.get(Name));
@@ -2743,17 +2813,28 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
auto Lookup = NewDRD->lookup(DN);
if (!OldLookup.empty() && !Lookup.empty()) {
assert(Lookup.size() == 1 && OldLookup.size() == 1);
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(
- OldLookup.front(), Lookup.front());
+ auto *OldVD = cast<VarDecl>(OldLookup.front());
+ auto *NewVD = cast<VarDecl>(Lookup.front());
+ SemaRef.InstantiateVariableInitializer(NewVD, OldVD, TemplateArgs);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldVD, NewVD);
}
}
- SubstInitializer =
- SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
- SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD,
- SubstInitializer);
+ if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) {
+ SubstInitializer =
+ SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
+ } else {
+ IsCorrect = IsCorrect && OmpPrivParm->hasInit();
+ }
+ SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(
+ NewDRD, SubstInitializer, OmpPrivParm);
}
- IsCorrect = IsCorrect && SubstCombiner &&
- (!D->getInitializer() || SubstInitializer);
+ IsCorrect =
+ IsCorrect && SubstCombiner &&
+ (!D->getInitializer() ||
+ (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit &&
+ SubstInitializer) ||
+ (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit &&
+ !SubstInitializer && !SubstInitializer));
} else
IsCorrect = false;
@@ -3610,6 +3691,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
New->setType(SemaRef.Context.getFunctionType(
NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
} else {
+ Sema::ContextRAII SwitchContext(SemaRef, New);
SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs);
}
}
@@ -3686,7 +3768,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
bool Recursive,
bool DefinitionRequired,
bool AtEndOfTU) {
- if (Function->isInvalidDecl() || Function->isDefined())
+ if (Function->isInvalidDecl() || Function->isDefined() ||
+ isa<CXXDeductionGuideDecl>(Function))
return;
// Never instantiate an explicit specialization except if it is a class scope
@@ -3705,6 +3788,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (PatternDef) {
Pattern = PatternDef->getBody(PatternDef);
PatternDecl = PatternDef;
+ if (PatternDef->willHaveBody())
+ PatternDef = nullptr;
}
// FIXME: We need to track the instantiation stack in order to know which
@@ -3719,6 +3804,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Try again at the end of the translation unit (at which point a
// definition will be required).
assert(!Recursive);
+ Function->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
} else if (TSK == TSK_ImplicitInstantiation) {
@@ -3738,6 +3824,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Postpone late parsed template instantiations.
if (PatternDecl->isLateTemplateParsed() &&
!LateTemplateParser) {
+ Function->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
return;
@@ -3748,10 +3835,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// while we're still within our own instantiation context.
// This has to happen before LateTemplateParser below is called, so that
// it marks vtables used in late parsed templates as used.
- SavePendingLocalImplicitInstantiationsRAII
- SavedPendingLocalImplicitInstantiations(*this);
- SavePendingInstantiationsAndVTableUsesRAII
- SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive);
+ GlobalEagerInstantiationScope GlobalInstantiations(*this,
+ /*Enabled=*/Recursive);
+ LocalEagerInstantiationScope LocalInstantiations(*this);
// Call the LateTemplateParser callback if there is a need to late parse
// a templated function definition.
@@ -3801,13 +3887,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Function->setHidden(false);
+ Function->setVisibleDespiteOwningModule();
// Copy the inner loc start from the pattern.
Function->setInnerLocStart(PatternDecl->getInnerLocStart());
- EnterExpressionEvaluationContext EvalContext(*this,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EvalContext(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
@@ -3878,20 +3964,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// This class may have local implicit instantiations that need to be
// instantiation within this scope.
- PerformPendingInstantiations(/*LocalOnly=*/true);
+ LocalInstantiations.perform();
Scope.Exit();
-
- if (Recursive) {
- // Define any pending vtables.
- DefineUsedVTables();
-
- // Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
- PerformPendingInstantiations();
-
- // PendingInstantiations and VTableUses are restored through
- // SavePendingInstantiationsAndVTableUses's destructor.
- }
+ GlobalInstantiations.perform();
}
VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
@@ -4004,7 +4079,8 @@ void Sema::BuildVariableInstantiation(
*this, NewVar->getDeclName(), NewVar->getLocation(),
NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
: Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ NewVar->isLocalExternDecl() ? Sema::ForExternalRedeclaration
+ : forRedeclarationInCurContext());
if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl() &&
(!OldVar->getPreviousDecl()->getDeclContext()->isDependentContext() ||
@@ -4070,10 +4146,8 @@ void Sema::InstantiateVariableInitializer(
Var->setImplicitlyInline();
if (OldVar->getInit()) {
- if (Var->isStaticDataMember() && !OldVar->isOutOfLine())
- PushExpressionEvaluationContext(Sema::ConstantEvaluated, OldVar);
- else
- PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar);
+ EnterExpressionEvaluationContext Evaluated(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
// Instantiate the initializer.
ExprResult Init;
@@ -4101,8 +4175,6 @@ void Sema::InstantiateVariableInitializer(
// because of a bogus initializer.
Var->setInvalidDecl();
}
-
- PopExpressionEvaluationContext();
} else {
if (Var->isStaticDataMember()) {
if (!Var->isOutOfLine())
@@ -4216,15 +4288,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Var->setHidden(false);
+ Var->setVisibleDespiteOwningModule();
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate
// later, while we're still within our own instantiation context.
- SavePendingInstantiationsAndVTableUsesRAII
- SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive);
-
+ GlobalEagerInstantiationScope GlobalInstantiations(*this,
+ /*Enabled=*/Recursive);
LocalInstantiationScope Local(*this);
+ LocalEagerInstantiationScope LocalInstantiations(*this);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
@@ -4232,26 +4304,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs);
PreviousContext.pop();
- // FIXME: Need to inform the ASTConsumer that we instantiated the
- // initializer?
-
// This variable may have local implicit instantiations that need to be
// instantiated within this scope.
- PerformPendingInstantiations(/*LocalOnly=*/true);
-
+ LocalInstantiations.perform();
Local.Exit();
-
- if (Recursive) {
- // Define any newly required vtables.
- DefineUsedVTables();
-
- // Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
- PerformPendingInstantiations();
-
- // PendingInstantiations and VTableUses are restored through
- // SavePendingInstantiationsAndVTableUses's destructor.
- }
+ GlobalInstantiations.perform();
}
// Find actual definition
@@ -4305,10 +4362,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
return;
// C++11 [temp.explicit]p10:
- // Except for inline functions, [...] explicit instantiation declarations
+ // Except for inline functions, const variables of literal types, variables
+ // of reference types, [...] explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
// to which they refer.
- if (TSK == TSK_ExplicitInstantiationDeclaration)
+ if (TSK == TSK_ExplicitInstantiationDeclaration &&
+ !Var->isUsableInConstantExpressions(getASTContext()))
return;
// Make sure to pass the instantiated variable to the consumer at the end.
@@ -4342,21 +4401,20 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
- SavePendingLocalImplicitInstantiationsRAII
- SavedPendingLocalImplicitInstantiations(*this);
- SavePendingInstantiationsAndVTableUsesRAII
- SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive);
+ GlobalEagerInstantiationScope GlobalInstantiations(*this,
+ /*Enabled=*/Recursive);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII PreviousContext(*this, Var->getDeclContext());
LocalInstantiationScope Local(*this);
+ LocalEagerInstantiationScope LocalInstantiations(*this);
+
VarDecl *OldVar = Var;
if (Def->isStaticDataMember() && !Def->isOutOfLine()) {
// We're instantiating an inline static data member whose definition was
// provided inside the class.
- // FIXME: Update record?
InstantiateVariableInitializer(Var, Def, TemplateArgs);
} else if (!VarSpec) {
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
@@ -4382,7 +4440,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// Merge the definition with the declaration.
LookupResult R(*this, Var->getDeclName(), Var->getLocation(),
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName, forRedeclarationInCurContext());
R.addDecl(OldVar);
MergeVarDecl(Var, R);
@@ -4404,21 +4462,9 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// This variable may have local implicit instantiations that need to be
// instantiated within this scope.
- PerformPendingInstantiations(/*LocalOnly=*/true);
-
+ LocalInstantiations.perform();
Local.Exit();
-
- if (Recursive) {
- // Define any newly required vtables.
- DefineUsedVTables();
-
- // Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
- PerformPendingInstantiations();
-
- // PendingInstantiations and VTableUses are restored through
- // SavePendingInstantiationsAndVTableUses's destructor.
- }
+ GlobalInstantiations.perform();
}
void
@@ -4778,7 +4824,7 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
- Decl* ID = FindInstantiatedDecl(Loc, D, TemplateArgs);
+ Decl* ID = FindInstantiatedDecl(Loc, D, TemplateArgs, true);
return cast_or_null<DeclContext>(ID);
} else return DC;
}
@@ -4810,7 +4856,8 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
/// (<tt>X<int>::<Kind>::KnownValue</tt>). \p FindInstantiatedDecl performs
/// this mapping from within the instantiation of <tt>X<int></tt>.
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool FindingInstantiatedContext) {
DeclContext *ParentDC = D->getDeclContext();
// FIXME: Parmeters of pointer to functions (y below) that are themselves
// parameters (p below) can have their ParentDC set to the translation-unit
@@ -4971,7 +5018,22 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args);
if (T.isNull())
return nullptr;
- DC = T->getAsCXXRecordDecl();
+ auto *SubstRecord = T->getAsCXXRecordDecl();
+ assert(SubstRecord && "class template id not a class type?");
+ // Check that this template-id names the primary template and not a
+ // partial or explicit specialization. (In the latter cases, it's
+ // meaningless to attempt to find an instantiation of D within the
+ // specialization.)
+ // FIXME: The standard doesn't say what should happen here.
+ if (FindingInstantiatedContext &&
+ usesPartialOrExplicitSpecialization(
+ Loc, cast<ClassTemplateSpecializationDecl>(SubstRecord))) {
+ Diag(Loc, diag::err_specialization_not_primary_template)
+ << T << (SubstRecord->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization);
+ return nullptr;
+ }
+ DC = SubstRecord;
continue;
}
}
@@ -5101,6 +5163,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired, true);
+ if (Function->isDefined())
+ Function->setInstantiationIsPending(false);
continue;
}
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 9f572007d8..d81837dad5 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -26,6 +26,19 @@ using namespace clang;
// Visitor that collects unexpanded parameter packs
//----------------------------------------------------------------------------
+/// \brief Retrieve the depth and index of a parameter pack.
+static std::pair<unsigned, unsigned>
+getDepthAndIndex(NamedDecl *ND) {
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
+ return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
+
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+}
+
namespace {
/// \brief A class that collects unexpanded parameter packs.
class CollectUnexpandedParameterPacksVisitor :
@@ -36,15 +49,36 @@ namespace {
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
- bool InLambda;
-
+ bool InLambda = false;
+ unsigned DepthLimit = (unsigned)-1;
+
+ void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
+ if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) {
+ // For now, the only problematic case is a generic lambda's templated
+ // call operator, so we don't need to look for all the other ways we
+ // could have reached a dependent parameter pack.
+ auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
+ auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
+ if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
+ return;
+ } else if (getDepthAndIndex(ND).first >= DepthLimit)
+ return;
+
+ Unexpanded.push_back({ND, Loc});
+ }
+ void addUnexpanded(const TemplateTypeParmType *T,
+ SourceLocation Loc = SourceLocation()) {
+ if (T->getDepth() < DepthLimit)
+ Unexpanded.push_back({T, Loc});
+ }
+
public:
explicit CollectUnexpandedParameterPacksVisitor(
- SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
- : Unexpanded(Unexpanded), InLambda(false) { }
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
+ : Unexpanded(Unexpanded) {}
bool shouldWalkTypesOfTypeLocs() const { return false; }
-
+
//------------------------------------------------------------------------
// Recording occurrences of (unexpanded) parameter packs.
//------------------------------------------------------------------------
@@ -52,7 +86,7 @@ namespace {
/// \brief Record occurrences of template type parameter packs.
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
if (TL.getTypePtr()->isParameterPack())
- Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc()));
+ addUnexpanded(TL.getTypePtr(), TL.getNameLoc());
return true;
}
@@ -63,7 +97,7 @@ namespace {
/// Ideally, this routine would never be used.
bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
if (T->isParameterPack())
- Unexpanded.push_back(std::make_pair(T, SourceLocation()));
+ addUnexpanded(T);
return true;
}
@@ -72,18 +106,18 @@ namespace {
/// parameter packs in an expression.
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (E->getDecl()->isParameterPack())
- Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation()));
+ addUnexpanded(E->getDecl(), E->getLocation());
return true;
}
/// \brief Record occurrences of template template parameter packs.
bool TraverseTemplateName(TemplateName Template) {
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Template.getAsTemplateDecl()))
+ if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Template.getAsTemplateDecl())) {
if (TTP->isParameterPack())
- Unexpanded.push_back(std::make_pair(TTP, SourceLocation()));
+ addUnexpanded(TTP);
+ }
return inherited::TraverseTemplateName(Template);
}
@@ -127,7 +161,7 @@ namespace {
return true;
}
- /// \brief Suppress traversel into types with location information
+ /// \brief Suppress traversal into types with location information
/// that do not contain unexpanded parameter packs.
bool TraverseTypeLoc(TypeLoc TL) {
if ((!TL.getType().isNull() &&
@@ -138,13 +172,48 @@ namespace {
return true;
}
- /// \brief Suppress traversal of non-parameter declarations, since
- /// they cannot contain unexpanded parameter packs.
+ /// \brief Suppress traversal of parameter packs.
bool TraverseDecl(Decl *D) {
- if ((D && isa<ParmVarDecl>(D)) || InLambda)
- return inherited::TraverseDecl(D);
+ // A function parameter pack is a pack expansion, so cannot contain
+ // an unexpanded parameter pack. Likewise for a template parameter
+ // pack that contains any references to other packs.
+ if (D->isParameterPack())
+ return true;
- return true;
+ return inherited::TraverseDecl(D);
+ }
+
+ /// \brief Suppress traversal of pack-expanded attributes.
+ bool TraverseAttr(Attr *A) {
+ if (A->isPackExpansion())
+ return true;
+
+ return inherited::TraverseAttr(A);
+ }
+
+ /// \brief Suppress traversal of pack expansion expressions and types.
+ ///@{
+ bool TraversePackExpansionType(PackExpansionType *T) { return true; }
+ bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; }
+ bool TraversePackExpansionExpr(PackExpansionExpr *E) { return true; }
+ bool TraverseCXXFoldExpr(CXXFoldExpr *E) { return true; }
+
+ ///@}
+
+ /// \brief Suppress traversal of using-declaration pack expansion.
+ bool TraverseUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ if (D->isPackExpansion())
+ return true;
+
+ return inherited::TraverseUnresolvedUsingValueDecl(D);
+ }
+
+ /// \brief Suppress traversal of using-declaration pack expansion.
+ bool TraverseUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+ if (D->isPackExpansion())
+ return true;
+
+ return inherited::TraverseUnresolvedUsingTypenameDecl(D);
}
/// \brief Suppress traversal of template argument pack expansions.
@@ -163,6 +232,22 @@ namespace {
return inherited::TraverseTemplateArgumentLoc(ArgLoc);
}
+ /// \brief Suppress traversal of base specifier pack expansions.
+ bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {
+ if (Base.isPackExpansion())
+ return true;
+
+ return inherited::TraverseCXXBaseSpecifier(Base);
+ }
+
+ /// \brief Suppress traversal of mem-initializer pack expansions.
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
+ if (Init->isPackExpansion())
+ return true;
+
+ return inherited::TraverseConstructorInitializer(Init);
+ }
+
/// \brief Note whether we're traversing a lambda containing an unexpanded
/// parameter pack. In this case, the unexpanded pack can occur anywhere,
/// including all the places where we normally wouldn't look. Within a
@@ -175,25 +260,27 @@ namespace {
return true;
bool WasInLambda = InLambda;
- InLambda = true;
+ unsigned OldDepthLimit = DepthLimit;
- // If any capture names a function parameter pack, that pack is expanded
- // when the lambda is expanded.
- for (LambdaExpr::capture_iterator I = Lambda->capture_begin(),
- E = Lambda->capture_end();
- I != E; ++I) {
- if (I->capturesVariable()) {
- VarDecl *VD = I->getCapturedVar();
- if (VD->isParameterPack())
- Unexpanded.push_back(std::make_pair(VD, I->getLocation()));
- }
- }
+ InLambda = true;
+ if (auto *TPL = Lambda->getTemplateParameterList())
+ DepthLimit = TPL->getDepth();
inherited::TraverseLambdaExpr(Lambda);
InLambda = WasInLambda;
+ DepthLimit = OldDepthLimit;
return true;
}
+
+ /// Suppress traversal within pack expansions in lambda captures.
+ bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C,
+ Expr *Init) {
+ if (C->isPackExpansion())
+ return true;
+
+ return inherited::TraverseLambdaCapture(Lambda, C, Init);
+ }
};
}
@@ -220,13 +307,33 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
if (Unexpanded.empty())
return false;
- // If we are within a lambda expression, that lambda contains an unexpanded
+ // If we are within a lambda expression and referencing a pack that is not
+ // a parameter of the lambda itself, that lambda contains an unexpanded
// parameter pack, and we are done.
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
// later.
+ SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
for (unsigned N = FunctionScopes.size(); N; --N) {
if (sema::LambdaScopeInfo *LSI =
dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) {
+ if (N == FunctionScopes.size()) {
+ for (auto &Param : Unexpanded) {
+ auto *PD = dyn_cast_or_null<ParmVarDecl>(
+ Param.first.dyn_cast<NamedDecl *>());
+ if (PD && PD->getDeclContext() == LSI->CallOperator)
+ LambdaParamPackReferences.push_back(Param);
+ }
+ }
+
+ // If we have references to a parameter pack of the innermost enclosing
+ // lambda, only diagnose those ones. We don't know whether any other
+ // unexpanded parameters referenced herein are actually unexpanded;
+ // they might be expanded at an outer level.
+ if (!LambdaParamPackReferences.empty()) {
+ Unexpanded = LambdaParamPackReferences;
+ break;
+ }
+
LSI->ContainsUnexpandedParameterPack = true;
return false;
}
@@ -520,19 +627,6 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions);
}
-/// \brief Retrieve the depth and index of a parameter pack.
-static std::pair<unsigned, unsigned>
-getDepthAndIndex(NamedDecl *ND) {
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
- return std::make_pair(TTP->getDepth(), TTP->getIndex());
-
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
- return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
-
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
- return std::make_pair(TTP->getDepth(), TTP->getIndex());
-}
-
bool Sema::CheckParameterPacksForExpansion(
SourceLocation EllipsisLoc, SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
@@ -725,6 +819,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_half:
case TST_float:
case TST_double:
+ case TST_Float16:
case TST_float128:
case TST_bool:
case TST_decimal32:
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 4fe0cf337f..ec0d93cf67 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -119,8 +120,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
// Function type attributes.
#define FUNCTION_TYPE_ATTRS_CASELIST \
- case AttributeList::AT_NoReturn: \
- case AttributeList::AT_Regparm: \
+ case AttributeList::AT_NSReturnsRetained: \
+ case AttributeList::AT_NoReturn: \
+ case AttributeList::AT_Regparm: \
+ case AttributeList::AT_AnyX86NoCallerSavedRegisters: \
CALLING_CONV_ATTRS_CASELIST
// Microsoft-specific type qualifiers.
@@ -638,11 +641,6 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
- case AttributeList::AT_NSReturnsRetained:
- if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
- // fallthrough
-
FUNCTION_TYPE_ATTRS_CASELIST:
distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
@@ -1394,8 +1392,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
else
Result = Context.Int128Ty;
break;
- case DeclSpec::TST_half: Result = Context.HalfTy; break;
- case DeclSpec::TST_float: Result = Context.FloatTy; break;
+ case DeclSpec::TST_float16: Result = Context.Float16Ty; break;
+ case DeclSpec::TST_half: Result = Context.HalfTy; break;
+ case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
Result = Context.LongDoubleTy;
@@ -1880,6 +1879,11 @@ QualType Sema::BuildPointerType(QualType T,
return QualType();
}
+ if (T->isFunctionType() && getLangOpts().OpenCL) {
+ Diag(Loc, diag::err_opencl_function_pointer);
+ return QualType();
+ }
+
if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer))
return QualType();
@@ -2284,8 +2288,9 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
// Methods cannot return interface types. All ObjC objects are
// passed by reference.
if (T->isObjCObjectType()) {
- Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << T;
- return 0;
+ Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value)
+ << 0 << T << FixItHint::CreateInsertion(Loc, "*");
+ return true;
}
return false;
@@ -2376,6 +2381,11 @@ QualType Sema::BuildFunctionType(QualType T,
[=](unsigned i) { return Loc; });
}
+ if (EPI.ExtInfo.getProducesResult()) {
+ // This is just a warning, so we can't fail to build if we see it.
+ checkNSReturnsRetainedReturnType(Loc, T);
+ }
+
if (Invalid)
return QualType();
@@ -3055,6 +3065,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
S.Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
<< FixItHint::CreateReplacement(D.getCommaLoc(), ";")
<< D.getIdentifier();
+ Result.suppressDiagnostics();
}
}
@@ -3096,6 +3107,99 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
}
}
+/// Produce an appropriate diagnostic for a declarator with top-level
+/// parentheses.
+static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) {
+ DeclaratorChunk &Paren = D.getTypeObject(D.getNumTypeObjects() - 1);
+ assert(Paren.Kind == DeclaratorChunk::Paren &&
+ "do not have redundant top-level parentheses");
+
+ // This is a syntactic check; we're not interested in cases that arise
+ // during template instantiation.
+ if (S.inTemplateInstantiation())
+ return;
+
+ // Check whether this could be intended to be a construction of a temporary
+ // object in C++ via a function-style cast.
+ bool CouldBeTemporaryObject =
+ S.getLangOpts().CPlusPlus && D.isExpressionContext() &&
+ !D.isInvalidType() && D.getIdentifier() &&
+ D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier &&
+ (T->isRecordType() || T->isDependentType()) &&
+ D.getDeclSpec().getTypeQualifiers() == 0 && D.isFirstDeclarator();
+
+ for (auto &C : D.type_objects()) {
+ switch (C.Kind) {
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Paren:
+ continue;
+
+ case DeclaratorChunk::Array:
+ if (!C.Arr.NumElts)
+ CouldBeTemporaryObject = false;
+ continue;
+
+ case DeclaratorChunk::Reference:
+ // FIXME: Suppress the warning here if there is no initializer; we're
+ // going to give an error anyway.
+ // We assume that something like 'T (&x) = y;' is highly likely to not
+ // be intended to be a temporary object.
+ CouldBeTemporaryObject = false;
+ continue;
+
+ case DeclaratorChunk::Function:
+ // In a new-type-id, function chunks require parentheses.
+ if (D.getContext() == Declarator::CXXNewContext)
+ return;
+ LLVM_FALLTHROUGH;
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
+ // These cannot appear in expressions.
+ CouldBeTemporaryObject = false;
+ continue;
+ }
+ }
+
+ // FIXME: If there is an initializer, assume that this is not intended to be
+ // a construction of a temporary object.
+
+ // Check whether the name has already been declared; if not, this is not a
+ // function-style cast.
+ if (CouldBeTemporaryObject) {
+ LookupResult Result(S, D.getIdentifier(), SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (!S.LookupName(Result, S.getCurScope()))
+ CouldBeTemporaryObject = false;
+ Result.suppressDiagnostics();
+ }
+
+ SourceRange ParenRange(Paren.Loc, Paren.EndLoc);
+
+ if (!CouldBeTemporaryObject) {
+ S.Diag(Paren.Loc, diag::warn_redundant_parens_around_declarator)
+ << ParenRange << FixItHint::CreateRemoval(Paren.Loc)
+ << FixItHint::CreateRemoval(Paren.EndLoc);
+ return;
+ }
+
+ S.Diag(Paren.Loc, diag::warn_parens_disambiguated_as_variable_declaration)
+ << ParenRange << D.getIdentifier();
+ auto *RD = T->getAsCXXRecordDecl();
+ if (!RD || !RD->hasDefinition() || RD->hasNonTrivialDestructor())
+ S.Diag(Paren.Loc, diag::note_raii_guard_add_name)
+ << FixItHint::CreateInsertion(Paren.Loc, " varname") << T
+ << D.getIdentifier();
+ // FIXME: A cast to void is probably a better suggestion in cases where it's
+ // valid (when there is no initializer and we're not in a condition).
+ S.Diag(D.getLocStart(), diag::note_function_style_cast_add_parentheses)
+ << FixItHint::CreateInsertion(D.getLocStart(), "(")
+ << FixItHint::CreateInsertion(S.getLocForEndOfToken(D.getLocEnd()), ")");
+ S.Diag(Paren.Loc, diag::note_remove_parens_for_variable_declaration)
+ << FixItHint::CreateRemoval(Paren.Loc)
+ << FixItHint::CreateRemoval(Paren.EndLoc);
+}
+
/// Helper for figuring out the default CC for a function declarator type. If
/// this is the outermost chunk, then we can determine the CC from the
/// declarator context. If not, then this could be either a member function
@@ -3173,11 +3277,7 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D,
for (const AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
Attr; Attr = Attr->getNext()) {
if (Attr->getKind() == AttributeList::AT_OpenCLKernel) {
- llvm::Triple::ArchType arch = S.Context.getTargetInfo().getTriple().getArch();
- if (arch == llvm::Triple::spir || arch == llvm::Triple::spir64 ||
- arch == llvm::Triple::amdgcn || arch == llvm::Triple::r600) {
- CC = CC_OpenCLKernel;
- }
+ CC = CC_OpenCLKernel;
break;
}
}
@@ -3363,7 +3463,7 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator,
if (auto objcClass = type->getAs<ObjCInterfaceType>()) {
if (objcClass->getInterface()->getIdentifier() == S.getNSErrorIdent()) {
if (numNormalPointers == 2 && numTypeSpecifierPointers < 2)
- return PointerDeclaratorKind::NSErrorPointerPointer;;
+ return PointerDeclaratorKind::NSErrorPointerPointer;
}
break;
@@ -3382,13 +3482,20 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator,
isCFError = (S.CFError == recordDecl);
} else {
// Check whether this is CFError, which we identify based on its bridge
- // to NSError.
+ // to NSError. CFErrorRef used to be declared with "objc_bridge" but is
+ // now declared with "objc_bridge_mutable", so look for either one of
+ // the two attributes.
if (recordDecl->getTagKind() == TTK_Struct && numNormalPointers > 0) {
- if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) {
- if (bridgeAttr->getBridgedType() == S.getNSErrorIdent()) {
- S.CFError = recordDecl;
- isCFError = true;
- }
+ IdentifierInfo *bridgedType = nullptr;
+ if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>())
+ bridgedType = bridgeAttr->getBridgedType();
+ else if (auto bridgeAttr =
+ recordDecl->getAttr<ObjCBridgeMutableAttr>())
+ bridgedType = bridgeAttr->getBridgedType();
+
+ if (bridgedType == S.getNSErrorIdent()) {
+ S.CFError = recordDecl;
+ isCFError = true;
}
}
}
@@ -3494,7 +3601,8 @@ static void fixItNullability(Sema &S, DiagnosticBuilder &Diag,
static void emitNullabilityConsistencyWarning(Sema &S,
SimplePointerKind PointerKind,
- SourceLocation PointerLoc) {
+ SourceLocation PointerLoc,
+ SourceLocation PointerEndLoc) {
assert(PointerLoc.isValid());
if (PointerKind == SimplePointerKind::Array) {
@@ -3504,14 +3612,15 @@ static void emitNullabilityConsistencyWarning(Sema &S,
<< static_cast<unsigned>(PointerKind);
}
- if (PointerLoc.isMacroID())
+ auto FixItLoc = PointerEndLoc.isValid() ? PointerEndLoc : PointerLoc;
+ if (FixItLoc.isMacroID())
return;
auto addFixIt = [&](NullabilityKind Nullability) {
- auto Diag = S.Diag(PointerLoc, diag::note_nullability_fix_it);
+ auto Diag = S.Diag(FixItLoc, diag::note_nullability_fix_it);
Diag << static_cast<unsigned>(Nullability);
Diag << static_cast<unsigned>(PointerKind);
- fixItNullability(S, Diag, PointerLoc, Nullability);
+ fixItNullability(S, Diag, FixItLoc, Nullability);
};
addFixIt(NullabilityKind::Nullable);
addFixIt(NullabilityKind::NonNull);
@@ -3523,9 +3632,10 @@ static void emitNullabilityConsistencyWarning(Sema &S,
///
/// If the file has \e not seen other uses of nullability, this particular
/// pointer is saved for possible later diagnosis. See recordNullabilitySeen().
-static void checkNullabilityConsistency(Sema &S,
- SimplePointerKind pointerKind,
- SourceLocation pointerLoc) {
+static void
+checkNullabilityConsistency(Sema &S, SimplePointerKind pointerKind,
+ SourceLocation pointerLoc,
+ SourceLocation pointerEndLoc = SourceLocation()) {
// Determine which file we're performing consistency checking for.
FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc);
if (file.isInvalid())
@@ -3546,6 +3656,7 @@ static void checkNullabilityConsistency(Sema &S,
if (fileNullability.PointerLoc.isInvalid() &&
!S.Context.getDiagnostics().isIgnored(diagKind, pointerLoc)) {
fileNullability.PointerLoc = pointerLoc;
+ fileNullability.PointerEndLoc = pointerEndLoc;
fileNullability.PointerKind = static_cast<unsigned>(pointerKind);
}
@@ -3553,7 +3664,7 @@ static void checkNullabilityConsistency(Sema &S,
}
// Complain about missing nullability.
- emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc);
+ emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc, pointerEndLoc);
}
/// Marks that a nullability feature has been used in the file containing
@@ -3579,7 +3690,8 @@ static void recordNullabilitySeen(Sema &S, SourceLocation loc) {
return;
auto kind = static_cast<SimplePointerKind>(fileNullability.PointerKind);
- emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc);
+ emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc,
+ fileNullability.PointerEndLoc);
}
/// Returns true if any of the declarator chunks before \p endIndex include a
@@ -3733,16 +3845,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// inner pointers.
complainAboutMissingNullability = CAMN_InnerPointers;
- auto isDependentNonPointerType = [](QualType T) -> bool {
- // Note: This is intended to be the same check as Type::canHaveNullability
- // except with all of the ambiguous cases being treated as 'false' rather
- // than 'true'.
- return T->isDependentType() && !T->isAnyPointerType() &&
- !T->isBlockPointerType() && !T->isMemberPointerType();
- };
-
- if (T->canHaveNullability() && !T->getNullability(S.Context) &&
- !isDependentNonPointerType(T)) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
+ !T->getNullability(S.Context)) {
// Note that we allow but don't require nullability on dependent types.
++NumPointersRemaining;
}
@@ -3897,6 +4001,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Returns true if _Nonnull was inferred.
auto inferPointerNullability = [&](SimplePointerKind pointerKind,
SourceLocation pointerLoc,
+ SourceLocation pointerEndLoc,
AttributeList *&attrs) -> AttributeList * {
// We've seen a pointer.
if (NumPointersRemaining > 0)
@@ -3952,7 +4057,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Fallthrough.
case CAMN_Yes:
- checkNullabilityConsistency(S, pointerKind, pointerLoc);
+ checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc);
}
return nullptr;
};
@@ -3960,7 +4065,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If the type itself could have nullability but does not, infer pointer
// nullability and perform consistency checking.
if (S.CodeSynthesisContexts.empty()) {
- if (T->canHaveNullability() && !T->getNullability(S.Context)) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
+ !T->getNullability(S.Context)) {
if (isVaList(T)) {
// Record that we've seen a pointer, but do nothing else.
if (NumPointersRemaining > 0)
@@ -3974,6 +4080,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (auto *attr = inferPointerNullability(
pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
+ D.getDeclSpec().getLocEnd(),
D.getMutableDeclSpec().getAttributes().getListRef())) {
T = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*inferNullability),T,T);
@@ -4001,6 +4108,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
IsQualifiedFunction &= DeclType.Kind == DeclaratorChunk::Paren;
switch (DeclType.Kind) {
case DeclaratorChunk::Paren:
+ if (i == 0)
+ warnAboutRedundantParens(S, D, T);
T = S.BuildParenType(T);
break;
case DeclaratorChunk::BlockPointer:
@@ -4009,8 +4118,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(DeclType.Loc, diag::err_blocks_disable) << LangOpts.OpenCL;
// Handle pointer nullability.
- inferPointerNullability(SimplePointerKind::BlockPointer,
- DeclType.Loc, DeclType.getAttrListRef());
+ inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc,
+ DeclType.EndLoc, DeclType.getAttrListRef());
T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) {
@@ -4032,7 +4141,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Handle pointer nullability
inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc,
- DeclType.getAttrListRef());
+ DeclType.EndLoc, DeclType.getAttrListRef());
if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) {
T = Context.getObjCObjectPointerType(T);
@@ -4356,22 +4465,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.isAmbiguous)
warnAboutAmbiguousFunction(S, D, DeclType, T);
- // GNU warning -Wstrict-prototypes
- // Warn if a function declaration is without a prototype.
- // This warning is issued for all kinds of unprototyped function
- // declarations (i.e. function type typedef, function pointer etc.)
- // C99 6.7.5.3p14:
- // The empty list in a function declarator that is not part of a
- // definition of that function specifies that no information
- // about the number or types of the parameters is supplied.
- if (D.getFunctionDefinitionKind() == FDK_Declaration &&
- FTI.NumParams == 0 && !LangOpts.CPlusPlus)
- S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
- << 0 << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
-
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
- if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) {
+ if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus
+ && !LangOpts.OpenCL) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T, EI);
} else {
@@ -4493,6 +4590,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
HasAnyInterestingExtParameterInfos = true;
}
+ if (Param->hasAttr<NoEscapeAttr>()) {
+ ExtParameterInfos[i] = ExtParameterInfos[i].withIsNoEscape(true);
+ HasAnyInterestingExtParameterInfos = true;
+ }
+
ParamTys.push_back(ParamTy);
}
@@ -4539,8 +4641,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType ClsType;
// Handle pointer nullability.
- inferPointerNullability(SimplePointerKind::MemberPointer,
- DeclType.Loc, DeclType.getAttrListRef());
+ inferPointerNullability(SimplePointerKind::MemberPointer, DeclType.Loc,
+ DeclType.EndLoc, DeclType.getAttrListRef());
if (SS.isInvalid()) {
// Avoid emitting extra errors if we already errored on the scope.
@@ -4611,6 +4713,36 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
const_cast<AttributeList *>(DeclType.getAttrs()));
}
+ // GNU warning -Wstrict-prototypes
+ // Warn if a function declaration is without a prototype.
+ // This warning is issued for all kinds of unprototyped function
+ // declarations (i.e. function type typedef, function pointer etc.)
+ // C99 6.7.5.3p14:
+ // The empty list in a function declarator that is not part of a definition
+ // of that function specifies that no information about the number or types
+ // of the parameters is supplied.
+ if (!LangOpts.CPlusPlus && D.getFunctionDefinitionKind() == FDK_Declaration) {
+ bool IsBlock = false;
+ for (const DeclaratorChunk &DeclType : D.type_objects()) {
+ switch (DeclType.Kind) {
+ case DeclaratorChunk::BlockPointer:
+ IsBlock = true;
+ break;
+ case DeclaratorChunk::Function: {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ if (FTI.NumParams == 0)
+ S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
+ << IsBlock
+ << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
+ IsBlock = false;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
assert(!T.isNull() && "T must not be null after this point");
if (LangOpts.CPlusPlus && T->isFunctionType()) {
@@ -4813,7 +4945,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
TypeSourceInfo *ReturnTypeInfo = nullptr;
QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
-
if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount)
inferARCWriteback(state, T);
@@ -5002,6 +5133,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_TypeNullUnspecified;
case AttributedType::attr_objc_kindof:
return AttributeList::AT_ObjCKindOf;
+ case AttributedType::attr_ns_returns_retained:
+ return AttributeList::AT_NSReturnsRetained;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -5361,6 +5494,18 @@ static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) {
ATL.setParensRange(SourceRange());
}
+static void fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL,
+ const AttributeList *Attrs) {
+ while (Attrs && Attrs->getKind() != AttributeList::AT_AddressSpace)
+ Attrs = Attrs->getNext();
+
+ assert(Attrs && "no address_space attribute found at the expected location!");
+
+ DASTL.setAttrNameLoc(Attrs->getLoc());
+ DASTL.setAttrExprOperand(Attrs->getArgAsExpr(0));
+ DASTL.setAttrOperandParensRange(SourceRange());
+}
+
/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
@@ -5383,6 +5528,13 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+
+ if (DependentAddressSpaceTypeLoc DASTL =
+ CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
+ fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
+ CurrTL = DASTL.getPointeeTypeLoc().getUnqualifiedLoc();
+ }
+
// An AtomicTypeLoc might be produced by an atomic qualifier in this
// declarator chunk.
if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) {
@@ -5475,16 +5627,77 @@ ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) {
// Type Attribute Processing
//===----------------------------------------------------------------------===//
+/// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression
+/// is uninstantiated. If instantiated it will apply the appropriate address space
+/// to the type. This function allows dependent template variables to be used in
+/// conjunction with the address_space attribute
+QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
+ SourceLocation AttrLoc) {
+ if (!AddrSpace->isValueDependent()) {
+
+ // If this type is already address space qualified, reject it.
+ // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified
+ // by qualifiers for two or more different address spaces."
+ if (T.getAddressSpace() != LangAS::Default) {
+ Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers);
+ return QualType();
+ }
+
+ llvm::APSInt addrSpace(32);
+ if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) {
+ Diag(AttrLoc, diag::err_attribute_argument_type)
+ << "'address_space'" << AANT_ArgumentIntegerConstant
+ << AddrSpace->getSourceRange();
+ return QualType();
+ }
+
+ // Bounds checking.
+ if (addrSpace.isSigned()) {
+ if (addrSpace.isNegative()) {
+ Diag(AttrLoc, diag::err_attribute_address_space_negative)
+ << AddrSpace->getSourceRange();
+ return QualType();
+ }
+ addrSpace.setIsSigned(false);
+ }
+
+ llvm::APSInt max(addrSpace.getBitWidth());
+ max =
+ Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace;
+ if (addrSpace > max) {
+ Diag(AttrLoc, diag::err_attribute_address_space_too_high)
+ << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange();
+ return QualType();
+ }
+
+ LangAS ASIdx =
+ getLangASFromTargetAS(static_cast<unsigned>(addrSpace.getZExtValue()));
+
+ return Context.getAddrSpaceQualType(T, ASIdx);
+ }
+
+ // A check with similar intentions as checking if a type already has an
+ // address space except for on a dependent types, basically if the
+ // current type is already a DependentAddressSpaceType then its already
+ // lined up to have another address space on it and we can't have
+ // multiple address spaces on the one pointer indirection
+ if (T->getAs<DependentAddressSpaceType>()) {
+ Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers);
+ return QualType();
+ }
+
+ return Context.getDependentAddressSpaceType(T, AddrSpace, AttrLoc);
+}
+
/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the
/// specified type. The attribute contains 1 argument, the id of the address
/// space for the type.
static void HandleAddressSpaceTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S){
-
// If this type is already address space qualified, reject it.
// ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by
// qualifiers for two or more different address spaces."
- if (Type.getAddressSpace()) {
+ if (Type.getAddressSpace() != LangAS::Default) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
Attr.setInvalid();
return;
@@ -5498,45 +5711,43 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
return;
}
- unsigned ASIdx;
+ LangAS ASIdx;
if (Attr.getKind() == AttributeList::AT_AddressSpace) {
+
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 1;
- Attr.setInvalid();
- return;
- }
- Expr *ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
- llvm::APSInt addrSpace(32);
- if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() ||
- !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << ASArgExpr->getSourceRange();
+ << Attr.getName() << 1;
Attr.setInvalid();
return;
}
- // Bounds checking.
- if (addrSpace.isSigned()) {
- if (addrSpace.isNegative()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
- << ASArgExpr->getSourceRange();
- Attr.setInvalid();
+ Expr *ASArgExpr;
+ if (Attr.isArgIdent(0)) {
+ // Special case where the argument is a template id.
+ CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
+
+ ExprResult AddrSpace = S.ActOnIdExpression(
+ S.getCurScope(), SS, TemplateKWLoc, id, false, false);
+ if (AddrSpace.isInvalid())
return;
- }
- addrSpace.setIsSigned(false);
+
+ ASArgExpr = static_cast<Expr *>(AddrSpace.get());
+ } else {
+ ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
}
- llvm::APSInt max(addrSpace.getBitWidth());
- max = Qualifiers::MaxAddressSpace;
- if (addrSpace > max) {
- S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
- << int(Qualifiers::MaxAddressSpace) << ASArgExpr->getSourceRange();
+
+ // Create the DependentAddressSpaceType or append an address space onto
+ // the type.
+ QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc());
+
+ if (!T.isNull())
+ Type = T;
+ else
Attr.setInvalid();
- return;
- }
- ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
} else {
// The keyword-based type attributes imply which address space to use.
switch (Attr.getKind()) {
@@ -5548,13 +5759,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
ASIdx = LangAS::opencl_constant; break;
case AttributeList::AT_OpenCLGenericAddressSpace:
ASIdx = LangAS::opencl_generic; break;
+ case AttributeList::AT_OpenCLPrivateAddressSpace:
+ ASIdx = LangAS::opencl_private; break;
default:
- assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace);
- ASIdx = 0; break;
+ llvm_unreachable("Invalid address space");
}
+
+ Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
-
- Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
/// Does this type have a "direct" ownership qualifier? That is,
@@ -6357,16 +6569,39 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
// ns_returns_retained is not always a type attribute, but if we got
// here, we're treating it as one right now.
if (attr.getKind() == AttributeList::AT_NSReturnsRetained) {
- assert(S.getLangOpts().ObjCAutoRefCount &&
- "ns_returns_retained treated as type attribute in non-ARC");
if (attr.getNumArgs()) return true;
// Delay if this is not a function type.
if (!unwrapped.isFunctionType())
return false;
- FunctionType::ExtInfo EI
- = unwrapped.get()->getExtInfo().withProducesResult(true);
+ // Check whether the return type is reasonable.
+ if (S.checkNSReturnsRetainedReturnType(attr.getLoc(),
+ unwrapped.get()->getReturnType()))
+ return true;
+
+ // Only actually change the underlying type in ARC builds.
+ QualType origType = type;
+ if (state.getSema().getLangOpts().ObjCAutoRefCount) {
+ FunctionType::ExtInfo EI
+ = unwrapped.get()->getExtInfo().withProducesResult(true);
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ }
+ type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained,
+ origType, type);
+ return true;
+ }
+
+ if (attr.getKind() == AttributeList::AT_AnyX86NoCallerSavedRegisters) {
+ if (S.CheckNoCallerSavedRegsAttr(attr))
+ return true;
+
+ // Delay if this is not a function type.
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ FunctionType::ExtInfo EI =
+ unwrapped.get()->getExtInfo().withNoCallerSavedRegs(true);
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
return true;
}
@@ -6759,6 +6994,92 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr,
}
}
+static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
+ QualType &T, TypeAttrLocation TAL) {
+ Declarator &D = State.getDeclarator();
+
+ // Handle the cases where address space should not be deduced.
+ //
+ // The pointee type of a pointer type is alwasy deduced since a pointer always
+ // points to some memory location which should has an address space.
+ //
+ // There are situations that at the point of certain declarations, the address
+ // space may be unknown and better to be left as default. For example, when
+ // definining a typedef or struct type, they are not associated with any
+ // specific address space. Later on, they may be used with any address space
+ // to declare a variable.
+ //
+ // The return value of a function is r-value, therefore should not have
+ // address space.
+ //
+ // The void type does not occupy memory, therefore should not have address
+ // space, except when it is used as a pointee type.
+ //
+ // Since LLVM assumes function type is in default address space, it should not
+ // have address space.
+ auto ChunkIndex = State.getCurrentChunkIndex();
+ bool IsPointee =
+ ChunkIndex > 0 &&
+ (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer ||
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer);
+ bool IsFuncReturnType =
+ ChunkIndex > 0 &&
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function;
+ bool IsFuncType =
+ ChunkIndex < D.getNumTypeObjects() &&
+ D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function;
+ if ( // Do not deduce addr space for function return type and function type,
+ // otherwise it will fail some sema check.
+ IsFuncReturnType || IsFuncType ||
+ // Do not deduce addr space for member types of struct, except the pointee
+ // type of a pointer member type.
+ (D.getContext() == Declarator::MemberContext && !IsPointee) ||
+ // Do not deduce addr space for types used to define a typedef and the
+ // typedef itself, except the pointee type of a pointer type which is used
+ // to define the typedef.
+ (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef &&
+ !IsPointee) ||
+ // Do not deduce addr space of the void type, e.g. in f(void), otherwise
+ // it will fail some sema check.
+ (T->isVoidType() && !IsPointee))
+ return;
+
+ LangAS ImpAddr;
+ // Put OpenCL automatic variable in private address space.
+ // OpenCL v1.2 s6.5:
+ // The default address space name for arguments to a function in a
+ // program, or local variables of a function is __private. All function
+ // arguments shall be in the __private address space.
+ if (State.getSema().getLangOpts().OpenCLVersion <= 120) {
+ ImpAddr = LangAS::opencl_private;
+ } else {
+ // If address space is not set, OpenCL 2.0 defines non private default
+ // address spaces for some cases:
+ // OpenCL 2.0, section 6.5:
+ // The address space for a variable at program scope or a static variable
+ // inside a function can either be __global or __constant, but defaults to
+ // __global if not specified.
+ // (...)
+ // Pointers that are declared without pointing to a named address space
+ // point to the generic address space.
+ if (IsPointee) {
+ ImpAddr = LangAS::opencl_generic;
+ } else {
+ if (D.getContext() == Declarator::FileContext) {
+ ImpAddr = LangAS::opencl_global;
+ } else {
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) {
+ ImpAddr = LangAS::opencl_global;
+ } else {
+ ImpAddr = LangAS::opencl_private;
+ }
+ }
+ }
+ }
+ T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
+}
+
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL, AttributeList *attrs) {
// Scan through and apply attributes to this type where it makes sense. Some
@@ -6766,7 +7087,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// type, but others can be present in the type specifiers even though they
// apply to the decl. Here we apply type attributes and ignore the rest.
- bool hasOpenCLAddressSpace = false;
while (attrs) {
AttributeList &attr = *attrs;
attrs = attr.getNext(); // reset to the next here due to early loop continue
@@ -6829,7 +7149,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
- hasOpenCLAddressSpace = true;
break;
OBJC_POINTER_TYPE_ATTRS_CASELIST:
if (!handleObjCPointerTypeAttr(state, attr, type))
@@ -6915,11 +7234,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_NSReturnsRetained:
- if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
- // fallthrough into the function attrs
-
FUNCTION_TYPE_ATTRS_CASELIST:
attr.setUsedAsTypeAttr();
@@ -6935,39 +7249,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
}
}
- // If address space is not set, OpenCL 2.0 defines non private default
- // address spaces for some cases:
- // OpenCL 2.0, section 6.5:
- // The address space for a variable at program scope or a static variable
- // inside a function can either be __global or __constant, but defaults to
- // __global if not specified.
- // (...)
- // Pointers that are declared without pointing to a named address space point
- // to the generic address space.
- if (state.getSema().getLangOpts().OpenCLVersion >= 200 &&
- !hasOpenCLAddressSpace && type.getAddressSpace() == 0 &&
- (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::BlockPointer)) {
- type = state.getSema().Context.getAddrSpaceQualType(
- type, LangAS::opencl_generic);
- } else if (state.getCurrentChunkIndex() == 0 &&
- D.getContext() == Declarator::FileContext &&
- !D.isFunctionDeclarator() && !D.isFunctionDefinition() &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
- !type->isSamplerT())
- type = state.getSema().Context.getAddrSpaceQualType(
- type, LangAS::opencl_global);
- else if (state.getCurrentChunkIndex() == 0 &&
- D.getContext() == Declarator::BlockContext &&
- D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
- type = state.getSema().Context.getAddrSpaceQualType(
- type, LangAS::opencl_global);
- }
+ if (!state.getSema().getLangOpts().OpenCL ||
+ type.getAddressSpace() != LangAS::Default)
+ return;
+
+ deduceOpenCLImplicitAddrSpace(state, type, TAL);
}
void Sema::completeExprArrayBound(Expr *E) {
@@ -7081,6 +7367,20 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return false;
}
+bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) {
+ llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
+ if (!Suggested)
+ return false;
+
+ // FIXME: Add a specific mode for C11 6.2.7/1 in StructuralEquivalenceContext
+ // and isolate from other C++ specific checks.
+ StructuralEquivalenceContext Ctx(
+ D->getASTContext(), Suggested->getASTContext(), NonEquivalentDecls,
+ false /*StrictTypeSpelling*/, true /*Complain*/,
+ true /*ErrorOnTagTypeMismatch*/);
+ return Ctx.IsStructurallyEquivalent(D, Suggested);
+}
+
/// \brief Determine whether there is any declaration of \p D that was ever a
/// definition (perhaps before module merging) and is currently visible.
/// \param D The definition of the entity.
@@ -7253,11 +7553,15 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// Give the external AST source a chance to complete the type.
if (auto *Source = Context.getExternalSource()) {
- if (Tag)
- Source->CompleteType(Tag->getDecl());
- else
- Source->CompleteType(IFace->getDecl());
-
+ if (Tag) {
+ TagDecl *TagD = Tag->getDecl();
+ if (TagD->hasExternalLexicalStorage())
+ Source->CompleteType(TagD);
+ } else {
+ ObjCInterfaceDecl *IFaceD = IFace->getDecl();
+ if (IFaceD->hasExternalLexicalStorage())
+ Source->CompleteType(IFace->getDecl());
+ }
// If the external source completed the type, go through the motions
// again to ensure we're allowed to use the completed type.
if (!T->isIncompleteType())
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 7a89c9dea1..96969ea87a 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"
@@ -834,6 +835,18 @@ public:
Expr *SizeExpr,
SourceLocation AttributeLoc);
+ /// \brief Build a new DependentAddressSpaceType or return the pointee
+ /// type variable with the correct address space (retrieved from
+ /// AddrSpaceExpr) applied to it. The former will be returned in cases
+ /// where the address space remains dependent.
+ ///
+ /// By default, performs semantic analysis when building the type with address
+ /// space applied. Subclasses may override this routine to provide different
+ /// behavior.
+ QualType RebuildDependentAddressSpaceType(QualType PointeeType,
+ Expr *AddrSpaceExpr,
+ SourceLocation AttributeLoc);
+
/// \brief Build a new function type.
///
/// By default, performs semantic analysis when building the function type.
@@ -1650,6 +1663,37 @@ public:
ReductionId, UnresolvedReductions);
}
+ /// Build a new OpenMP 'task_reduction' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPTaskReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ return getSema().ActOnOpenMPTaskReductionClause(
+ VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
+ ReductionId, UnresolvedReductions);
+ }
+
+ /// Build a new OpenMP 'in_reduction' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *
+ RebuildOMPInReductionClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ return getSema().ActOnOpenMPInReductionClause(
+ VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
+ ReductionId, UnresolvedReductions);
+ }
+
/// \brief Build a new OpenMP 'linear' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -2219,6 +2263,9 @@ public:
Base = BaseResult.get();
QualType BaseType = Base->getType();
+ if (isArrow && !BaseType->isPointerType())
+ return ExprError();
+
// FIXME: this involves duplicating earlier analysis in a lot of
// cases; we should avoid this when possible.
LookupResult R(getSema(), MemberNameInfo, Sema::LookupMemberName);
@@ -3867,7 +3914,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();
@@ -4150,7 +4199,6 @@ TreeTransform<Derived>::TransformTypeWithDeducedTST(TypeSourceInfo *DI) {
TypeLoc TL = DI->getTypeLoc();
TLB.reserve(TL.getFullDataSize());
- Qualifiers Quals;
auto QTL = TL.getAs<QualifiedTypeLoc>();
if (QTL)
TL = QTL.getUnqualifiedLoc();
@@ -4572,8 +4620,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();
}
@@ -4621,8 +4669,8 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
ExprResult SizeResult;
{
- EnterExpressionEvaluationContext Context(SemaRef,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext Context(
+ SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
SizeResult = getDerived().TransformExpr(T->getSizeExpr());
}
if (SizeResult.isInvalid())
@@ -4666,8 +4714,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();
@@ -4716,8 +4764,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);
@@ -4748,7 +4796,53 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
return Result;
}
-template<typename Derived>
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformDependentAddressSpaceType(
+ TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) {
+ const DependentAddressSpaceType *T = TL.getTypePtr();
+
+ QualType pointeeType = getDerived().TransformType(T->getPointeeType());
+
+ if (pointeeType.isNull())
+ return QualType();
+
+ // Address spaces are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ ExprResult AddrSpace = getDerived().TransformExpr(T->getAddrSpaceExpr());
+ AddrSpace = SemaRef.ActOnConstantExpression(AddrSpace);
+ if (AddrSpace.isInvalid())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || pointeeType != T->getPointeeType() ||
+ AddrSpace.get() != T->getAddrSpaceExpr()) {
+ Result = getDerived().RebuildDependentAddressSpaceType(
+ pointeeType, AddrSpace.get(), T->getAttributeLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ // Result might be dependent or not.
+ if (isa<DependentAddressSpaceType>(Result)) {
+ DependentAddressSpaceTypeLoc NewTL =
+ TLB.push<DependentAddressSpaceTypeLoc>(Result);
+
+ NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange());
+ NewTL.setAttrExprOperand(TL.getAttrExprOperand());
+ NewTL.setAttrNameLoc(TL.getAttrNameLoc());
+
+ } else {
+ TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(
+ Result, getDerived().getBaseLocation());
+ TransformType(TLB, DI->getTypeLoc());
+ }
+
+ return Result;
+}
+
+template <typename Derived>
QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
VectorTypeLoc TL) {
const VectorType *T = TL.getTypePtr();
@@ -5184,8 +5278,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;
@@ -5352,8 +5446,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())
@@ -5410,8 +5505,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())
@@ -6386,8 +6482,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());
@@ -6562,8 +6658,7 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
// Rebuild the switch statement.
StmtResult Switch
- = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(),
- S->getInit(), Cond);
+ = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Init.get(), Cond);
if (Switch.isInvalid())
return StmtError();
@@ -6847,13 +6942,9 @@ 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
- CoroutineBodyStmt::CtorArgs BodyArgs;
-
auto *ScopeInfo = SemaRef.getCurFunction();
auto *FD = cast<FunctionDecl>(SemaRef.CurContext);
- assert(ScopeInfo && !ScopeInfo->CoroutinePromise &&
+ assert(FD && ScopeInfo && !ScopeInfo->CoroutinePromise &&
ScopeInfo->NeedsCoroutineSuspends &&
ScopeInfo->CoroutineSuspends.first == nullptr &&
ScopeInfo->CoroutineSuspends.second == nullptr &&
@@ -6865,17 +6956,11 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
// The new CoroutinePromise object needs to be built and put into the current
// FunctionScopeInfo before any transformations or rebuilding occurs.
- auto *Promise = S->getPromiseDecl();
- auto *NewPromise = SemaRef.buildCoroutinePromise(FD->getLocation());
- if (!NewPromise)
+ auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
+ if (!Promise)
return StmtError();
- getDerived().transformedLocalDecl(Promise, NewPromise);
- ScopeInfo->CoroutinePromise = NewPromise;
- StmtResult PromiseStmt = SemaRef.ActOnDeclStmt(
- SemaRef.ConvertDeclToDeclGroup(NewPromise),
- FD->getLocation(), FD->getLocation());
- assert(!PromiseStmt.isInvalid());
- BodyArgs.Promise = PromiseStmt.get();
+ getDerived().transformedLocalDecl(S->getPromiseDecl(), Promise);
+ ScopeInfo->CoroutinePromise = Promise;
// Transform the implicit coroutine statements we built during the initial
// parse.
@@ -6888,52 +6973,83 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
return StmtError();
ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
assert(isa<Expr>(InitSuspend.get()) && isa<Expr>(FinalSuspend.get()));
- BodyArgs.InitialSuspend = cast<Expr>(InitSuspend.get());
- BodyArgs.FinalSuspend = cast<Expr>(FinalSuspend.get());
StmtResult BodyRes = getDerived().TransformStmt(S->getBody());
if (BodyRes.isInvalid())
return StmtError();
- BodyArgs.Body = BodyRes.get();
- if (S->getFallthroughHandler()) {
- StmtResult Res = getDerived().TransformStmt(S->getFallthroughHandler());
- if (Res.isInvalid())
- return StmtError();
- BodyArgs.OnFallthrough = Res.get();
- }
+ CoroutineStmtBuilder Builder(SemaRef, *FD, *ScopeInfo, BodyRes.get());
+ if (Builder.isInvalid())
+ return StmtError();
- if (S->getExceptionHandler()) {
- StmtResult Res = getDerived().TransformStmt(S->getExceptionHandler());
- if (Res.isInvalid())
+ 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();
- BodyArgs.OnException = Res.get();
- }
+ } else {
+ if (auto *OnFallthrough = S->getFallthroughHandler()) {
+ StmtResult Res = getDerived().TransformStmt(OnFallthrough);
+ if (Res.isInvalid())
+ return StmtError();
+ Builder.OnFallthrough = Res.get();
+ }
- // Transform any additional statements we may have already built
- if (S->getAllocate() && S->getDeallocate()) {
+ 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();
- BodyArgs.Allocate = AllocRes.get();
+ Builder.Allocate = AllocRes.get();
ExprResult DeallocRes = getDerived().TransformExpr(S->getDeallocate());
if (DeallocRes.isInvalid())
return StmtError();
- BodyArgs.Deallocate = DeallocRes.get();
- }
+ Builder.Deallocate = DeallocRes.get();
- Expr *ReturnObject = S->getReturnValueInit();
- if (ReturnObject) {
- ExprResult Res = getDerived().TransformInitializer(ReturnObject,
- /*NoCopyInit*/false);
- if (Res.isInvalid())
+ assert(S->getResultDecl() && "ResultDecl must already be built");
+ StmtResult ResultDecl = getDerived().TransformStmt(S->getResultDecl());
+ if (ResultDecl.isInvalid())
return StmtError();
- BodyArgs.ReturnValue = Res.get();
+ Builder.ResultDecl = ResultDecl.get();
+
+ if (auto *ReturnStmt = S->getReturnStmt()) {
+ StmtResult Res = getDerived().TransformStmt(ReturnStmt);
+ if (Res.isInvalid())
+ return StmtError();
+ Builder.ReturnStmt = Res.get();
+ }
}
+ if (!Builder.buildParameterMoves())
+ return StmtError();
- // Do a partial rebuild of the coroutine body and stash it in the ScopeInfo
- return getDerived().RebuildCoroutineBodyStmt(BodyArgs);
+ return getDerived().RebuildCoroutineBodyStmt(Builder);
}
template<typename Derived>
@@ -8371,6 +8487,96 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPTaskReductionClause(
+ OMPTaskReductionClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ CXXScopeSpec ReductionIdScopeSpec;
+ ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
+
+ DeclarationNameInfo NameInfo = C->getNameInfo();
+ if (NameInfo.getName()) {
+ NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
+ if (!NameInfo.getName())
+ return nullptr;
+ }
+ // Build a list of all UDR decls with the same names ranged by the Scopes.
+ // The Scope boundary is a duplication of the previous decl.
+ llvm::SmallVector<Expr *, 16> UnresolvedReductions;
+ for (auto *E : C->reduction_ops()) {
+ // Transform all the decls.
+ if (E) {
+ auto *ULE = cast<UnresolvedLookupExpr>(E);
+ UnresolvedSet<8> Decls;
+ for (auto *D : ULE->decls()) {
+ NamedDecl *InstD =
+ cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
+ Decls.addDecl(InstD, InstD->getAccess());
+ }
+ UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
+ /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
+ } else
+ UnresolvedReductions.push_back(nullptr);
+ }
+ return getDerived().RebuildOMPTaskReductionClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
+ C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPInReductionClause(OMPInReductionClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ CXXScopeSpec ReductionIdScopeSpec;
+ ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
+
+ DeclarationNameInfo NameInfo = C->getNameInfo();
+ if (NameInfo.getName()) {
+ NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
+ if (!NameInfo.getName())
+ return nullptr;
+ }
+ // Build a list of all UDR decls with the same names ranged by the Scopes.
+ // The Scope boundary is a duplication of the previous decl.
+ llvm::SmallVector<Expr *, 16> UnresolvedReductions;
+ for (auto *E : C->reduction_ops()) {
+ // Transform all the decls.
+ if (E) {
+ auto *ULE = cast<UnresolvedLookupExpr>(E);
+ UnresolvedSet<8> Decls;
+ for (auto *D : ULE->decls()) {
+ NamedDecl *InstD =
+ cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
+ Decls.addDecl(InstD, InstD->getAccess());
+ }
+ UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
+ /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
+ } else
+ UnresolvedReductions.push_back(nullptr);
+ }
+ return getDerived().RebuildOMPInReductionClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
+ C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
@@ -8933,8 +9139,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.
@@ -9146,7 +9353,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());
@@ -9626,7 +9833,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(),
@@ -9770,8 +9977,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())
@@ -9806,7 +10014,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())
@@ -10420,7 +10629,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();
@@ -10441,7 +10651,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();
@@ -10677,8 +10888,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);
@@ -10754,7 +10965,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());
@@ -10894,7 +11106,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 =
@@ -11130,7 +11343,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();
@@ -11163,7 +11377,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;
@@ -12155,10 +12370,18 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
IndexTypeQuals, BracketsRange);
}
-template<typename Derived>
-QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
- unsigned NumElements,
- VectorType::VectorKind VecKind) {
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildDependentAddressSpaceType(
+ QualType PointeeType, Expr *AddrSpaceExpr, SourceLocation AttributeLoc) {
+ return SemaRef.BuildAddressSpaceAttr(PointeeType, AddrSpaceExpr,
+ AttributeLoc);
+}
+
+template <typename Derived>
+QualType
+TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
+ unsigned NumElements,
+ VectorType::VectorKind VecKind) {
// FIXME: semantic checking!
return SemaRef.Context.getVectorType(ElementType, NumElements, VecKind);
}
@@ -12412,10 +12635,14 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Compute the transformed set of functions (and function templates) to be
// used during overload resolution.
UnresolvedSet<16> Functions;
+ bool RequiresADL;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
- assert(ULE->requiresADL());
Functions.append(ULE->decls_begin(), ULE->decls_end());
+ // If the overload could not be resolved in the template definition
+ // (because we had a dependent argument), ADL is performed as part of
+ // template instantiation.
+ RequiresADL = ULE->requiresADL();
} else {
// If we've resolved this to a particular non-member function, just call
// that function. If we resolved it to a member function,
@@ -12423,6 +12650,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl();
if (!isa<CXXMethodDecl>(ND))
Functions.addDecl(ND);
+ RequiresADL = false;
}
// Add any functions found via argument-dependent lookup.
@@ -12433,7 +12661,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (NumArgs == 1 || isPostIncDec) {
UnaryOperatorKind Opc
= UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
- return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First);
+ return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First,
+ RequiresADL);
}
if (Op == OO_Subscript) {
@@ -12457,8 +12686,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Create the overloaded operator invocation for binary operators.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
- ExprResult Result
- = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]);
+ ExprResult Result = SemaRef.CreateOverloadedBinOp(
+ OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL);
if (Result.isInvalid())
return ExprError();
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 684ec24303..9c6f03cd0b 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -91,6 +91,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::LongDouble:
ID = PREDEF_TYPE_LONGDOUBLE_ID;
break;
+ case BuiltinType::Float16:
+ ID = PREDEF_TYPE_FLOAT16_ID;
+ break;
case BuiltinType::Float128:
ID = PREDEF_TYPE_FLOAT128_ID;
break;
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index be0cc9ab1a..5a3423a3ec 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -37,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"
@@ -291,6 +292,33 @@ static bool checkLanguageOptions(const LangOptions &LangOpts,
return true;
}
+ // Sanitizer feature mismatches are treated as compatible differences. If
+ // compatible differences aren't allowed, we still only want to check for
+ // mismatches of non-modular sanitizers (the only ones which can affect AST
+ // generation).
+ if (!AllowCompatibleDifferences) {
+ SanitizerMask ModularSanitizers = getPPTransparentSanitizers();
+ SanitizerSet ExistingSanitizers = ExistingLangOpts.Sanitize;
+ SanitizerSet ImportedSanitizers = LangOpts.Sanitize;
+ ExistingSanitizers.clear(ModularSanitizers);
+ ImportedSanitizers.clear(ModularSanitizers);
+ if (ExistingSanitizers.Mask != ImportedSanitizers.Mask) {
+ const std::string Flag = "-fsanitize=";
+ if (Diags) {
+#define SANITIZER(NAME, ID) \
+ { \
+ bool InExistingModule = ExistingSanitizers.has(SanitizerKind::ID); \
+ bool InImportedModule = ImportedSanitizers.has(SanitizerKind::ID); \
+ if (InExistingModule != InImportedModule) \
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch) \
+ << InExistingModule << (Flag + NAME); \
+ }
+#include "clang/Basic/Sanitizers.def"
+ }
+ return true;
+ }
+ }
+
return false;
}
@@ -463,19 +491,9 @@ static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags,
return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain);
}
-bool PCHValidator::ReadDiagnosticOptions(
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
- DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
- IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
- // This should never fail, because we would have processed these options
- // before writing them to an ASTFile.
- ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false);
-
- ModuleManager &ModuleMgr = Reader.getModuleManager();
- assert(ModuleMgr.size() >= 1 && "what ASTFile is this then");
-
+/// Return the top import module if it is implicit, nullptr otherwise.
+static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr,
+ Preprocessor &PP) {
// If the original import came from a file explicitly generated by the user,
// don't check the diagnostic mappings.
// FIXME: currently this is approximated by checking whether this is not a
@@ -487,17 +505,37 @@ bool PCHValidator::ReadDiagnosticOptions(
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
@@ -818,7 +856,7 @@ static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II,
II.isPoisoned() ||
(IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) ||
II.hasRevertedTokenIDToIdentifier() ||
- (!(IsModule && Reader.getContext().getLangOpts().CPlusPlus) &&
+ (!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) &&
II.getFETokenInfo<void>());
}
@@ -1110,7 +1148,7 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M,
void ASTReader::Error(StringRef Msg) const {
Error(diag::err_fe_pch_malformed, Msg);
- if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight() &&
+ if (PP.getLangOpts().Modules && !Diags.isDiagnosticInFlight() &&
!PP.getHeaderSearchInfo().getModuleCachePath().empty()) {
Diag(diag::note_module_cache_path)
<< PP.getHeaderSearchInfo().getModuleCachePath();
@@ -1353,15 +1391,14 @@ bool ASTReader::ReadSLocEntry(int ID) {
const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
unsigned NumFileDecls = Record[7];
- if (NumFileDecls) {
+ if (NumFileDecls && ContextObj) {
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
NumFileDecls));
}
const SrcMgr::ContentCache *ContentCache
- = SourceMgr.getOrCreateContentCache(File,
- /*isSystemFile=*/FileCharacter != SrcMgr::C_User);
+ = SourceMgr.getOrCreateContentCache(File, isSystem(FileCharacter));
if (OverriddenBuffer && !ContentCache->BufferOverridden &&
ContentCache->ContentsEntry == ContentCache->OrigEntry &&
!ContentCache->getRawBuffer()) {
@@ -1483,7 +1520,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
Stream.JumpToBit(Offset);
RecordData Record;
- SmallVector<IdentifierInfo*, 16> MacroArgs;
+ SmallVector<IdentifierInfo*, 16> MacroParams;
MacroInfo *Macro = nullptr;
while (true) {
@@ -1523,9 +1560,8 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
return Macro;
unsigned NextIndex = 1; // Skip identifier ID.
- SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]);
SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
- MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
+ MacroInfo *MI = PP.AllocateMacroInfo(Loc);
MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
MI->setIsUsed(Record[NextIndex++]);
MI->setUsedForHeaderGuard(Record[NextIndex++]);
@@ -1535,17 +1571,17 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
bool isC99VarArgs = Record[NextIndex++];
bool isGNUVarArgs = Record[NextIndex++];
bool hasCommaPasting = Record[NextIndex++];
- MacroArgs.clear();
+ MacroParams.clear();
unsigned NumArgs = Record[NextIndex++];
for (unsigned i = 0; i != NumArgs; ++i)
- MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
+ MacroParams.push_back(getLocalIdentifier(F, Record[NextIndex++]));
// Install function-like macro info.
MI->setIsFunctionLike();
if (isC99VarArgs) MI->setIsC99Varargs();
if (isGNUVarArgs) MI->setIsGNUVarargs();
if (hasCommaPasting) MI->setHasCommaPasting();
- MI->setArgumentList(MacroArgs, PP.getPreprocessorAllocator());
+ MI->setParameterList(MacroParams, PP.getPreprocessorAllocator());
}
// Remember that we saw this macro last so that we add the tokens that
@@ -1660,9 +1696,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HeaderFileInfo HFI;
unsigned Flags = *d++;
// FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp.
- HFI.isImport |= (Flags >> 4) & 0x01;
- HFI.isPragmaOnce |= (Flags >> 3) & 0x01;
- HFI.DirInfo = (Flags >> 1) & 0x03;
+ HFI.isImport |= (Flags >> 5) & 0x01;
+ HFI.isPragmaOnce |= (Flags >> 4) & 0x01;
+ HFI.DirInfo = (Flags >> 1) & 0x07;
HFI.IndexHeaderMapHeader = Flags & 0x01;
// FIXME: Find a better way to handle this. Maybe just store a
// "has been included" flag?
@@ -1992,6 +2028,7 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
R.StoredTime = static_cast<time_t>(Record[2]);
R.Overridden = static_cast<bool>(Record[3]);
R.Transient = static_cast<bool>(Record[4]);
+ R.TopLevelModuleMap = static_cast<bool>(Record[5]);
R.Filename = Blob;
ResolveImportedPath(F, R.Filename);
return R;
@@ -2023,14 +2060,12 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
StringRef Filename = FI.Filename;
const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false);
-
// If we didn't find the file, resolve it relative to the
// original directory from which this AST file was created.
- if (File == nullptr && !F.OriginalDir.empty() && !CurrentDir.empty() &&
- F.OriginalDir != CurrentDir) {
- std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
- F.OriginalDir,
- CurrentDir);
+ if (File == nullptr && !F.OriginalDir.empty() && !F.BaseDirectory.empty() &&
+ F.OriginalDir != F.BaseDirectory) {
+ std::string Resolved = resolveFileRelativeToOriginalDir(
+ Filename, F.OriginalDir, F.BaseDirectory);
if (!Resolved.empty())
File = FileMgr.getFile(Resolved);
}
@@ -2450,7 +2485,23 @@ ASTReader::ReadControlBlock(ModuleFile &F,
{{(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);
+
+ std::string ImportedName = ReadString(Record, Idx);
+ std::string ImportedFile;
+
+ // For prebuilt and explicit modules first consult the file map for
+ // an override. Note that here we don't search prebuilt module
+ // directories, only the explicit name to file mappings. Also, we will
+ // still verify the size/signature making sure it is essentially the
+ // same file but perhaps in a different location.
+ if (ImportedKind == MK_PrebuiltModule || ImportedKind == MK_ExplicitModule)
+ ImportedFile = PP.getHeaderSearchInfo().getPrebuiltModuleFileName(
+ ImportedName, /*FileMapOnly*/ true);
+
+ if (ImportedFile.empty())
+ ImportedFile = ReadPath(F, Record, Idx);
+ else
+ SkipPath(Record, Idx);
// If our client can't cope with us being out of date, we can't cope with
// our dependency being missing.
@@ -2577,10 +2628,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// contains any declarations lexically within it (which it always does!).
// This usually has no cost, since we very rarely need the lookup map for
// the translation unit outside C++.
- DeclContext *DC = Context.getTranslationUnitDecl();
- if (DC->hasExternalLexicalStorage() &&
- !getContext().getLangOpts().CPlusPlus)
- DC->setMustBuildLookupTable();
+ if (ASTContext *Ctx = ContextObj) {
+ DeclContext *DC = Ctx->getTranslationUnitDecl();
+ if (DC->hasExternalLexicalStorage() && !Ctx->getLangOpts().CPlusPlus)
+ DC->setMustBuildLookupTable();
+ }
return Success;
}
@@ -2669,7 +2721,33 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Read and process a record.
Record.clear();
StringRef Blob;
- switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
+ auto RecordType =
+ (ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob);
+
+ // If we're not loading an AST context, we don't care about most records.
+ if (!ContextObj) {
+ switch (RecordType) {
+ case IDENTIFIER_TABLE:
+ case IDENTIFIER_OFFSET:
+ case INTERESTING_IDENTIFIERS:
+ case STATISTICS:
+ case PP_CONDITIONAL_STACK:
+ case PP_COUNTER_VALUE:
+ case SOURCE_LOCATION_OFFSETS:
+ case MODULE_OFFSET_MAP:
+ case SOURCE_MANAGER_LINE_TABLE:
+ case SOURCE_LOCATION_PRELOADS:
+ case PPD_ENTITIES_OFFSETS:
+ case HEADER_SEARCH_TABLE:
+ case IMPORTED_MODULES:
+ case MACRO_OFFSET:
+ break;
+ default:
+ continue;
+ }
+ }
+
+ switch (RecordType) {
default: // Default behavior: ignore.
break;
@@ -2728,7 +2806,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
case TU_UPDATE_LEXICAL: {
- DeclContext *TU = Context.getTranslationUnitDecl();
+ DeclContext *TU = ContextObj->getTranslationUnitDecl();
LexicalContents Contents(
reinterpret_cast<const llvm::support::unaligned_uint32_t *>(
Blob.data()),
@@ -2746,7 +2824,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
- PendingUpdateRecords.push_back(std::make_pair(ID, D));
+ PendingUpdateRecords.push_back(
+ PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
break;
}
@@ -2914,6 +2993,21 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
break;
+ case PP_CONDITIONAL_STACK:
+ if (!Record.empty()) {
+ SmallVector<PPConditionalInfo, 4> ConditionalStack;
+ for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
+ auto Loc = ReadSourceLocation(F, Record, Idx);
+ bool WasSkipping = Record[Idx++];
+ bool FoundNonSkip = Record[Idx++];
+ bool FoundElse = Record[Idx++];
+ ConditionalStack.push_back(
+ {Loc, WasSkipping, FoundNonSkip, FoundElse});
+ }
+ PP.setReplayablePreambleConditionalStack(ConditionalStack);
+ }
+ break;
+
case PP_COUNTER_VALUE:
if (!Record.empty() && Listener)
Listener->ReadCounter(F, Record[0]);
@@ -3076,7 +3170,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
- PendingUpdateRecords.push_back(std::make_pair(ID, D));
+ PendingUpdateRecords.push_back(
+ PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
}
break;
}
@@ -3287,6 +3382,29 @@ 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++]);
+ Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]);
+ PragmaPackStrings.push_back(ReadString(Record, Idx));
+ Entry.SlotLabel = PragmaPackStrings.back();
+ PragmaPackStack.push_back(Entry);
+ }
+ break;
+ }
}
}
}
@@ -3318,12 +3436,18 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
RemapBuilder TypeRemap(F.TypeRemap);
while (Data < DataEnd) {
- // FIXME: Looking up dependency modules by filename is horrible.
+ // FIXME: Looking up dependency modules by filename is horrible. Let's
+ // start fixing this with prebuilt and explicit modules and see how it
+ // goes...
using namespace llvm::support;
+ ModuleKind Kind = static_cast<ModuleKind>(
+ endian::readNext<uint8_t, little, unaligned>(Data));
uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data);
StringRef Name = StringRef((const char*)Data, Len);
Data += Len;
- ModuleFile *OM = ModuleMgr.lookup(Name);
+ ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule
+ ? ModuleMgr.lookupByModuleName(Name)
+ : ModuleMgr.lookupByFileName(Name));
if (!OM) {
std::string Msg =
"SourceLocation remap refers to unknown module, cannot find ";
@@ -3379,12 +3503,6 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
unsigned Idx = 0;
F.ModuleMapPath = ReadPath(F, Record, Idx);
- if (F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule) {
- // For an explicitly-loaded module, we don't care whether the original
- // module map file exists or matches.
- return Success;
- }
-
// Try to resolve ModuleName in the current header search context and
// verify that it is found in the same module map file as we saved. If the
// top-level AST file is a main file, skip this check because there is no
@@ -3504,8 +3622,8 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?");
for (Decl *D : Names) {
- bool wasHidden = D->Hidden;
- D->Hidden = false;
+ bool wasHidden = D->isHidden();
+ D->setVisibleDespiteOwningModule();
if (wasHidden && SemaObj) {
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
@@ -3572,7 +3690,7 @@ void ASTReader::mergeDefinitionVisibility(NamedDecl *Def,
if (Def->isHidden()) {
// If MergedDef is visible or becomes visible, make the definition visible.
if (!MergedDef->isHidden())
- Def->Hidden = false;
+ Def->setVisibleDespiteOwningModule();
else if (getContext().getLangOpts().ModulesLocalVisibility) {
getContext().mergeDefinitionIntoModule(
Def, MergedDef->getImportedOwningModule(),
@@ -3591,7 +3709,7 @@ bool ASTReader::loadGlobalIndex() {
return false;
if (TriedLoadingGlobalIndex || !UseGlobalIndex ||
- !Context.getLangOpts().Modules)
+ !PP.getLangOpts().Modules)
return true;
// Try to load the global index.
@@ -3609,7 +3727,7 @@ bool ASTReader::loadGlobalIndex() {
}
bool ASTReader::isGlobalIndexUnavailable() const {
- return Context.getLangOpts().Modules && UseGlobalIndex &&
+ return PP.getLangOpts().Modules && UseGlobalIndex &&
!hasGlobalIndex() && TriedLoadingGlobalIndex;
}
@@ -3621,6 +3739,8 @@ static void updateModuleTimestamp(ModuleFile &MF) {
if (EC)
return;
OS << "Timestamp file\n";
+ OS.close();
+ OS.clear_error(); // Avoid triggering a fatal error.
}
/// \brief Given a cursor at the start of an AST file, scan ahead and drop the
@@ -3665,7 +3785,9 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
Deserializing AnASTFile(this);
// Bump the generation number.
- unsigned PreviousGeneration = incrementGeneration(Context);
+ unsigned PreviousGeneration = 0;
+ if (ContextObj)
+ PreviousGeneration = incrementGeneration(*ContextObj);
unsigned NumModules = ModuleMgr.size();
SmallVector<ImportedModule, 4> Loaded;
@@ -3684,7 +3806,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
LoadedSet.insert(IM.Mod);
ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet,
- Context.getLangOpts().Modules
+ PP.getLangOpts().Modules
? &PP.getHeaderSearchInfo().getModuleMap()
: nullptr);
@@ -3732,6 +3854,13 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
SourceMgr.getLoadedSLocEntryByID(Index);
}
+ // Map the original source file ID into the ID space of the current
+ // compilation.
+ if (F.OriginalSourceFileID.isValid()) {
+ F.OriginalSourceFileID = FileID::get(
+ F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1);
+ }
+
// Preload all the pending interesting identifiers by marking them out of
// date.
for (auto Offset : F.PreloadIdentifierOffsets) {
@@ -3773,7 +3902,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc);
}
- if (!Context.getLangOpts().CPlusPlus ||
+ if (!PP.getLangOpts().CPlusPlus ||
(Type != MK_ImplicitModule && Type != MK_ExplicitModule &&
Type != MK_PrebuiltModule)) {
// Mark all of the identifiers in the identifier table as being out of date,
@@ -3830,7 +3959,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
// Might be unnecessary as use declarations are only used to build the
// module itself.
- InitializeContext();
+ if (ContextObj)
+ InitializeContext();
if (SemaObj)
UpdateSema();
@@ -3840,10 +3970,6 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
if (PrimaryModule.OriginalSourceFileID.isValid()) {
- PrimaryModule.OriginalSourceFileID
- = FileID::get(PrimaryModule.SLocEntryBaseID
- + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
-
// If this AST file is a precompiled preamble, then set the
// preamble file ID of the source manager to the file source file
// from which the preamble was built.
@@ -3856,10 +3982,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
// For any Objective-C class definitions we have already loaded, make sure
// that we load any additional categories.
- for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
- loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
- ObjCClassesLoaded[I],
- PreviousGeneration);
+ if (ContextObj) {
+ for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
+ loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
+ ObjCClassesLoaded[I],
+ PreviousGeneration);
+ }
}
if (PP.getHeaderSearchInfo()
@@ -3958,13 +4086,6 @@ ASTReader::ReadASTCore(StringRef FileName,
assert(M && "Missing module file");
- // FIXME: This seems rather a hack. Should CurrentDir be part of the
- // module?
- if (FileName != "-") {
- CurrentDir = llvm::sys::path::parent_path(FileName);
- if (CurrentDir.empty()) CurrentDir = ".";
- }
-
ModuleFile &F = *M;
BitstreamCursor &Stream = F.Stream;
Stream = BitstreamCursor(PCHContainerRdr.ExtractPCH(*F.Buffer));
@@ -4064,12 +4185,41 @@ ASTReader::readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy,
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)
+ 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;
}
@@ -4122,7 +4272,7 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl(
if (Listener && ValidateDiagnosticOptions &&
!AllowCompatibleConfigurationMismatch &&
ParseDiagnosticOptions(Record, Complain, *Listener))
- return OutOfDate;
+ Result = OutOfDate; // Don't return early. Read the signature.
break;
}
case DIAG_PRAGMA_MAPPINGS:
@@ -4210,6 +4360,9 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) {
}
void ASTReader::InitializeContext() {
+ assert(ContextObj && "no context to initialize");
+ ASTContext &Context = *ContextObj;
+
// If there's a listener, notify them that we "read" the translation unit.
if (DeserializationListener)
DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
@@ -4625,6 +4778,7 @@ bool ASTReader::readASTFileControlBlock(
while (Idx < N) {
// Read information about the AST file.
Idx += 5; // ImportLoc, Size, ModTime, Signature
+ SkipString(Record, Idx); // Module name; FIXME: pass to listener?
std::string Filename = ReadString(Record, Idx);
ResolveImportedPath(Filename, ModuleDir);
Listener.visitImport(Filename);
@@ -4692,11 +4846,12 @@ bool ASTReader::readASTFileControlBlock(
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,
@@ -4763,6 +4918,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
unsigned Idx = 0;
SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]);
SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]);
+ Module::ModuleKind Kind = (Module::ModuleKind)Record[Idx++];
bool IsFramework = Record[Idx++];
bool IsExplicit = Record[Idx++];
bool IsSystem = Record[Idx++];
@@ -4771,7 +4927,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
bool InferExplicitSubmodules = Record[Idx++];
bool InferExportWildcard = Record[Idx++];
bool ConfigMacrosExhaustive = Record[Idx++];
- bool WithCodegen = Record[Idx++];
Module *ParentModule = nullptr;
if (Parent)
@@ -4807,8 +4962,10 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
CurrentModule->setASTFile(F.File);
+ CurrentModule->PresumedModuleMapFile = F.ModuleMapPath;
}
+ CurrentModule->Kind = Kind;
CurrentModule->Signature = F.Signature;
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
@@ -4817,7 +4974,6 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
- CurrentModule->WithCodegen = WithCodegen;
if (DeserializationListener)
DeserializationListener->ModuleRead(GlobalID, CurrentModule);
@@ -4849,13 +5005,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;
@@ -4945,8 +5097,8 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
case SUBMODULE_REQUIRES: {
- CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(),
- Context.getTargetInfo());
+ CurrentModule->addRequirement(Blob, Record[0], PP.getLangOpts(),
+ PP.getTargetInfo());
break;
}
@@ -4971,11 +5123,18 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
- case SUBMODULE_INITIALIZERS:
+ case SUBMODULE_INITIALIZERS: {
+ if (!ContextObj)
+ break;
SmallVector<uint32_t, 16> Inits;
for (auto &ID : Record)
Inits.push_back(getGlobalDeclID(F, ID));
- Context.addLazyModuleInitializers(CurrentModule, Inits);
+ ContextObj->addLazyModuleInitializers(CurrentModule, Inits);
+ break;
+ }
+
+ case SUBMODULE_EXPORT_AS:
+ CurrentModule->ExportAsModule = Blob.str();
break;
}
}
@@ -5103,6 +5262,8 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
HSOpts.ModuleCachePath = ReadString(Record, Idx);
HSOpts.ModuleUserBuildPath = ReadString(Record, Idx);
HSOpts.DisableModuleHash = Record[Idx++];
+ HSOpts.ImplicitModuleMaps = Record[Idx++];
+ HSOpts.ModuleMapFileHomeIsCwd = Record[Idx++];
HSOpts.UseBuiltinIncludes = Record[Idx++];
HSOpts.UseStandardSystemIncludes = Record[Idx++];
HSOpts.UseStandardCXXIncludes = Record[Idx++];
@@ -5264,10 +5425,12 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
llvm_unreachable("Invalid PreprocessorDetailRecordTypes");
}
-/// \brief \arg SLocMapI points at a chunk of a module that contains no
-/// preprocessed entities or the entities it contains are not the ones we are
-/// looking for. Find the next module that contains entities and return the ID
+/// \brief Find the next module that contains entities and return the ID
/// of the first entry.
+///
+/// \param SLocMapI points at a chunk of a module that contains no
+/// preprocessed entities or the entities it contains are not the ones we are
+/// looking for.
PreprocessedEntityID ASTReader::findNextPreprocessedEntity(
GlobalSLocOffsetMapType::const_iterator SLocMapI) const {
++SLocMapI;
@@ -5463,40 +5626,78 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
Diag.DiagStates.push_back(BasedOn);
DiagState *NewState = &Diag.DiagStates.back();
DiagStates.push_back(NewState);
- while (Idx + 1 < Record.size() && Record[Idx] != unsigned(-1)) {
+ unsigned Size = Record[Idx++];
+ assert(Idx + Size * 2 <= Record.size() &&
+ "Invalid data, not enough diag/map pairs");
+ while (Size--) {
unsigned DiagID = Record[Idx++];
- diag::Severity Map = (diag::Severity)Record[Idx++];
- DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc);
- if (Mapping.isPragma() || IncludeNonPragmaStates)
- NewState->setMapping(DiagID, Mapping);
- }
- assert(Idx != Record.size() && Record[Idx] == unsigned(-1) &&
- "Invalid data, didn't find '-1' marking end of diag/map pairs");
- ++Idx;
- return NewState;
- };
+ DiagnosticMapping NewMapping =
+ DiagnosticMapping::deserialize(Record[Idx++]);
+ if (!NewMapping.isPragma() && !IncludeNonPragmaStates)
+ continue;
- auto *FirstState = ReadDiagState(
- F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState,
- SourceLocation(), F.isModule());
- SourceLocation CurStateLoc =
- ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
- auto *CurState = ReadDiagState(*FirstState, CurStateLoc, false);
+ DiagnosticMapping &Mapping = NewState->getOrAddMapping(DiagID);
- if (!F.isModule()) {
- Diag.DiagStatesByLoc.CurDiagState = CurState;
- Diag.DiagStatesByLoc.CurDiagStateLoc = CurStateLoc;
+ // If this mapping was specified as a warning but the severity was
+ // upgraded due to diagnostic settings, simulate the current diagnostic
+ // settings (and use a warning).
+ if (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) {
+ NewMapping.setSeverity(diag::Severity::Warning);
+ NewMapping.setUpgradedFromWarning(false);
+ }
- // 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;
- }
+ Mapping = NewMapping;
+ }
+ return NewState;
+ };
- while (Idx < Record.size()) {
+ // Read the first state.
+ DiagState *FirstState;
+ if (F.Kind == MK_ImplicitModule) {
+ // Implicitly-built modules are reused with different diagnostic
+ // settings. Use the initial diagnostic state from Diag to simulate this
+ // compilation's diagnostic settings.
+ FirstState = Diag.DiagStatesByLoc.FirstDiagState;
+ DiagStates.push_back(FirstState);
+
+ // Skip the initial diagnostic state from the serialized module.
+ assert(Record[1] == 0 &&
+ "Invalid data, unexpected backref in initial state");
+ Idx = 3 + Record[2] * 2;
+ assert(Idx < Record.size() &&
+ "Invalid data, not enough state change pairs in initial state");
+ } else if (F.isModule()) {
+ // For an explicit module, preserve the flags from the module build
+ // command line (-w, -Weverything, -Werror, ...) along with any explicit
+ // -Wblah flags.
+ unsigned Flags = Record[Idx++];
+ DiagState Initial;
+ Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1;
+ Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1;
+ Initial.WarningsAsErrors = Flags & 1; Flags >>= 1;
+ Initial.EnableAllWarnings = Flags & 1; Flags >>= 1;
+ Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1;
+ Initial.ExtBehavior = (diag::Severity)Flags;
+ FirstState = ReadDiagState(Initial, SourceLocation(), true);
+
+ // Set up the root buffer of the module to start with the initial
+ // diagnostic state of the module itself, to cover files that contain no
+ // explicit transitions (for which we did not serialize anything).
+ Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID]
+ .StateTransitions.push_back({FirstState, 0});
+ } else {
+ // For prefix ASTs, start with whatever the user configured on the
+ // command line.
+ Idx++; // Skip flags.
+ FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState,
+ SourceLocation(), false);
+ }
+
+ // Read the state transitions.
+ unsigned NumLocations = Record[Idx++];
+ while (NumLocations--) {
+ assert(Idx < Record.size() &&
+ "Invalid data, missing pragma diagnostic states");
SourceLocation Loc = ReadSourceLocation(F, Record[Idx++]);
auto IDAndOffset = SourceMgr.getDecomposedLoc(Loc);
assert(IDAndOffset.second == 0 && "not a start location for a FileID");
@@ -5516,6 +5717,27 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
}
}
+ // 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.
+ FileID NullFile;
+ auto &T = Diag.DiagStatesByLoc.Files[NullFile].StateTransitions;
+ if (T.empty())
+ T.push_back({CurState, 0});
+ else
+ T[0].State = CurState;
+ }
+
// Don't try to read these mappings again.
Record.clear();
}
@@ -5536,6 +5758,8 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
/// location. It is a helper routine for GetType, which deals with reading type
/// IDs.
QualType ASTReader::readTypeRecord(unsigned Index) {
+ assert(ContextObj && "reading type with no AST context");
+ ASTContext &Context = *ContextObj;
RecordLocation Loc = TypeCursorForIndex(Index);
BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
@@ -5696,13 +5920,13 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
}
case TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 6) {
+ if (Record.size() != 7) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
QualType ResultType = readType(*Loc.F, Record, Idx);
FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
- (CallingConv)Record[4], Record[5]);
+ (CallingConv)Record[4], Record[5], Record[6]);
return Context.getFunctionNoProtoType(ResultType, Info);
}
@@ -5714,9 +5938,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
/*hasregparm*/ Record[2],
/*regparm*/ Record[3],
static_cast<CallingConv>(Record[4]),
- /*produces*/ Record[5]);
+ /*produces*/ Record[5],
+ /*nocallersavedregs*/ Record[6]);
- unsigned Idx = 6;
+ unsigned Idx = 7;
EPI.Variadic = Record[Idx++];
EPI.HasTrailingReturn = Record[Idx++];
@@ -6036,6 +6261,29 @@ 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);
+ }
+
+ case TYPE_DEPENDENT_ADDRESS_SPACE: {
+ unsigned Idx = 0;
+
+ // DependentAddressSpaceType
+ QualType PointeeType = readType(*Loc.F, Record, Idx);
+ Expr *AddrSpaceExpr = ReadExpr(*Loc.F);
+ SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx);
+
+ return Context.getDependentAddressSpaceType(PointeeType, AddrSpaceExpr,
+ AttrLoc);
+ }
}
llvm_unreachable("Invalid TypeCode!");
}
@@ -6169,6 +6417,17 @@ void TypeLocReader::VisitDependentSizedArrayTypeLoc(
VisitArrayTypeLoc(TL);
}
+void TypeLocReader::VisitDependentAddressSpaceTypeLoc(
+ DependentAddressSpaceTypeLoc TL) {
+
+ TL.setAttrNameLoc(ReadSourceLocation());
+ SourceRange range;
+ range.setBegin(ReadSourceLocation());
+ range.setEnd(ReadSourceLocation());
+ TL.setAttrOperandParensRange(range);
+ TL.setAttrExprOperand(Reader->ReadExpr(*F));
+}
+
void TypeLocReader::VisitDependentSizedExtVectorTypeLoc(
DependentSizedExtVectorTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation());
@@ -6380,6 +6639,9 @@ ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record,
}
QualType ASTReader::GetType(TypeID ID) {
+ assert(ContextObj && "reading type with no AST context");
+ ASTContext &Context = *ContextObj;
+
unsigned FastQuals = ID & Qualifiers::FastMask;
unsigned Index = ID >> Qualifiers::FastWidth;
@@ -6452,6 +6714,9 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_LONGDOUBLE_ID:
T = Context.LongDoubleTy;
break;
+ case PREDEF_TYPE_FLOAT16_ID:
+ T = Context.Float16Ty;
+ break;
case PREDEF_TYPE_FLOAT128_ID:
T = Context.Float128Ty;
break;
@@ -6711,6 +6976,9 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
}
CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
+ assert(ContextObj && "reading base specifiers with no AST context");
+ ASTContext &Context = *ContextObj;
+
RecordLocation Loc = getLocalBitOffset(Offset);
BitstreamCursor &Cursor = Loc.F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
@@ -6842,8 +7110,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
}
Decl *ASTReader::GetExistingDecl(DeclID ID) {
+ assert(ContextObj && "reading decl with no AST context");
if (ID < NUM_PREDEF_DECL_IDS) {
- Decl *D = getPredefinedDecl(Context, (PredefinedDeclIDs)ID);
+ Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID);
if (D) {
// Track that we have merged the declaration with ID \p ID into the
// pre-existing predefined declaration \p D.
@@ -7121,31 +7390,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);
@@ -7301,7 +7545,7 @@ LLVM_DUMP_METHOD void ASTReader::dump() {
/// by heap-backed versus mmap'ed memory.
void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
for (ModuleFile &I : ModuleMgr) {
- if (llvm::MemoryBuffer *buf = I.Buffer.get()) {
+ if (llvm::MemoryBuffer *buf = I.Buffer) {
size_t bytes = buf->getBufferSize();
switch (buf->getBufferKind()) {
case llvm::MemoryBuffer::MemoryBuffer_Malloc:
@@ -7330,7 +7574,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);
@@ -7371,6 +7615,35 @@ 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,
+ PragmaPackStack.front().PushLocation);
+ 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, Entry.PushLocation);
+ 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) {
@@ -7385,7 +7658,7 @@ IdentifierInfo *ASTReader::get(StringRef Name) {
// all interesting declarations, and don't need to use the scope for name
// lookups). Perform the lookup in PCH files, though, since we don't build
// a complete initial identifier table if we're carrying on from a PCH.
- if (Context.getLangOpts().CPlusPlus) {
+ if (PP.getLangOpts().CPlusPlus) {
for (auto F : ModuleMgr.pch_modules())
if (Visitor(*F))
break;
@@ -8039,7 +8312,7 @@ ASTReader::getSourceDescriptor(unsigned ID) {
return ExternalASTSource::ASTSourceDescriptor(*M);
// If there is only a single PCH, return it instead.
- // Chained PCH are not suported.
+ // Chained PCH are not supported.
const auto &PCHChain = ModuleMgr.pch_modules();
if (std::distance(std::begin(PCHChain), std::end(PCHChain))) {
ModuleFile &MF = ModuleMgr.getPrimaryModule();
@@ -8051,16 +8324,11 @@ ASTReader::getSourceDescriptor(unsigned ID) {
return None;
}
-ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(unsigned ID) {
- const Module *M = getSubmodule(ID);
- if (!M || !M->WithCodegen)
+ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) {
+ auto I = DefinitionSource.find(FD);
+ if (I == DefinitionSource.end())
return EK_ReplyHazy;
-
- ModuleFile *MF = ModuleMgr.lookup(M->getASTFile());
- assert(MF); // ?
- if (MF->Kind == ModuleKind::MK_MainFile)
- return EK_Never;
- return EK_Always;
+ return I->second ? EK_Never : EK_Always;
}
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
@@ -8120,6 +8388,7 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
DeclarationName
ASTReader::ReadDeclarationName(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
+ ASTContext &Context = getContext();
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
switch (Kind) {
case DeclarationName::Identifier:
@@ -8210,7 +8479,8 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
unsigned NumTPLists = Record[Idx++];
Info.NumTemplParamLists = NumTPLists;
if (NumTPLists) {
- Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
+ Info.TemplParamLists =
+ new (getContext()) TemplateParameterList *[NumTPLists];
for (unsigned i = 0; i != NumTPLists; ++i)
Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
}
@@ -8219,6 +8489,7 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
TemplateName
ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
+ ASTContext &Context = getContext();
TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
switch (Kind) {
case TemplateName::Template:
@@ -8279,6 +8550,7 @@ TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F,
const RecordData &Record,
unsigned &Idx,
bool Canonicalize) {
+ ASTContext &Context = getContext();
if (Canonicalize) {
// The caller wants a canonical template argument. Sometimes the AST only
// wants template arguments in canonical form (particularly as the template
@@ -8342,9 +8614,8 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F,
Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
// TODO: Concepts
- TemplateParameterList* TemplateParams =
- TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- Params, RAngleLoc, nullptr);
+ TemplateParameterList *TemplateParams = TemplateParameterList::Create(
+ getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr);
return TemplateParams;
}
@@ -8363,11 +8634,11 @@ ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
const RecordData &Record, unsigned &Idx) {
unsigned NumDecls = Record[Idx++];
- Set.reserve(Context, NumDecls);
+ Set.reserve(getContext(), NumDecls);
while (NumDecls--) {
DeclID ID = ReadDeclID(F, Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
- Set.addLazyDecl(Context, ID, AS);
+ Set.addLazyDecl(getContext(), ID, AS);
}
}
@@ -8390,6 +8661,7 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
CXXCtorInitializer **
ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
+ ASTContext &Context = getContext();
unsigned NumInitializers = Record[Idx++];
assert(NumInitializers && "wrote ctor initializers but have no inits");
auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers];
@@ -8455,6 +8727,7 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
NestedNameSpecifier *
ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
+ ASTContext &Context = getContext();
unsigned N = Record[Idx++];
NestedNameSpecifier *NNS = nullptr, *Prev = nullptr;
for (unsigned I = 0; I != N; ++I) {
@@ -8510,6 +8783,7 @@ ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
NestedNameSpecifierLoc
ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
+ ASTContext &Context = getContext();
unsigned N = Record[Idx++];
NestedNameSpecifierLocBuilder Builder;
for (unsigned I = 0; I != N; ++I) {
@@ -8631,7 +8905,7 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
const RecordData &Record,
unsigned &Idx) {
CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
- return CXXTemporary::Create(Context, Decl);
+ return CXXTemporary::Create(getContext(), Decl);
}
DiagnosticBuilder ASTReader::Diag(unsigned DiagID) const {
@@ -8667,6 +8941,7 @@ void ASTReader::ClearSwitchCaseIDs() {
}
void ASTReader::ReadComments() {
+ ASTContext &Context = getContext();
std::vector<RawComment *> Comments;
for (SmallVectorImpl<std::pair<BitstreamCursor,
serialization::ModuleFile *> >::iterator
@@ -8736,6 +9011,19 @@ void ASTReader::visitInputFiles(serialization::ModuleFile &MF,
}
}
+void ASTReader::visitTopLevelModuleMaps(
+ serialization::ModuleFile &MF,
+ llvm::function_ref<void(const FileEntry *FE)> Visitor) {
+ unsigned NumInputs = MF.InputFilesLoaded.size();
+ for (unsigned I = 0; I < NumInputs; ++I) {
+ InputFileInfo IFI = readInputFileInfo(MF, I + 1);
+ if (IFI.TopLevelModuleMap)
+ // FIXME: This unnecessarily re-reads the InputFileInfo.
+ if (auto *FE = getInputFile(MF, I + 1).getFile())
+ Visitor(FE);
+ }
+}
+
std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
// If we know the owning module, use it.
if (Module *M = D->getImportedOwningModule())
@@ -8826,7 +9114,7 @@ void ASTReader::finishPendingActions() {
while (!PendingUpdateRecords.empty()) {
auto Update = PendingUpdateRecords.pop_back_val();
ReadingKindTracker ReadingKind(Read_Decl, *this);
- loadDeclUpdateRecords(Update.first, Update.second);
+ loadDeclUpdateRecords(Update);
}
}
@@ -8894,9 +9182,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;
}
@@ -8928,7 +9216,8 @@ void ASTReader::diagnoseOdrViolations() {
Merge.first->decls_begin();
Merge.first->bases_begin();
Merge.first->vbases_begin();
- for (auto *RD : Merge.second) {
+ for (auto &RecordPair : Merge.second) {
+ auto *RD = RecordPair.first;
RD->decls_begin();
RD->bases_begin();
RD->vbases_begin();
@@ -9034,14 +9323,326 @@ void ASTReader::diagnoseOdrViolations() {
bool Diagnosed = false;
CXXRecordDecl *FirstRecord = Merge.first;
std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
- for (CXXRecordDecl *SecondRecord : Merge.second) {
+ for (auto &RecordPair : Merge.second) {
+ CXXRecordDecl *SecondRecord = RecordPair.first;
// Multiple different declarations got merged together; tell the user
// where they came from.
if (FirstRecord == SecondRecord)
continue;
std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
+
+ auto *FirstDD = FirstRecord->DefinitionData;
+ auto *SecondDD = RecordPair.second;
+
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+
+ // Diagnostics from DefinitionData are emitted here.
+ if (FirstDD != SecondDD) {
+ enum ODRDefinitionDataDifference {
+ NumBases,
+ NumVBases,
+ BaseType,
+ BaseVirtual,
+ BaseAccess,
+ };
+ auto ODRDiagError = [FirstRecord, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRDefinitionDataDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_definition_data)
+ << FirstRecord << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto ODRDiagNote = [&SecondModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRDefinitionDataDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_definition_data)
+ << SecondModule << Range << DiffType;
+ };
+
+ ODRHash Hash;
+ auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
+ Hash.clear();
+ Hash.AddQualType(Ty);
+ return Hash.CalculateHash();
+ };
+
+ unsigned FirstNumBases = FirstDD->NumBases;
+ unsigned FirstNumVBases = FirstDD->NumVBases;
+ unsigned SecondNumBases = SecondDD->NumBases;
+ unsigned SecondNumVBases = SecondDD->NumVBases;
+
+ auto GetSourceRange = [](struct CXXRecordDecl::DefinitionData *DD) {
+ unsigned NumBases = DD->NumBases;
+ if (NumBases == 0) return SourceRange();
+ auto bases = DD->bases();
+ return SourceRange(bases[0].getLocStart(),
+ bases[NumBases - 1].getLocEnd());
+ };
+
+ if (FirstNumBases != SecondNumBases) {
+ ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumBases)
+ << FirstNumBases;
+ ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumBases)
+ << SecondNumBases;
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstNumVBases != SecondNumVBases) {
+ ODRDiagError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumVBases)
+ << FirstNumVBases;
+ ODRDiagNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumVBases)
+ << SecondNumVBases;
+ Diagnosed = true;
+ break;
+ }
+
+ auto FirstBases = FirstDD->bases();
+ auto SecondBases = SecondDD->bases();
+ unsigned i = 0;
+ for (i = 0; i < FirstNumBases; ++i) {
+ auto FirstBase = FirstBases[i];
+ auto SecondBase = SecondBases[i];
+ if (ComputeQualTypeODRHash(FirstBase.getType()) !=
+ ComputeQualTypeODRHash(SecondBase.getType())) {
+ ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseType)
+ << (i + 1) << FirstBase.getType();
+ ODRDiagNote(SecondRecord->getLocation(),
+ SecondBase.getSourceRange(), BaseType)
+ << (i + 1) << SecondBase.getType();
+ break;
+ }
+
+ if (FirstBase.isVirtual() != SecondBase.isVirtual()) {
+ ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseVirtual)
+ << (i + 1) << FirstBase.isVirtual() << FirstBase.getType();
+ ODRDiagNote(SecondRecord->getLocation(),
+ SecondBase.getSourceRange(), BaseVirtual)
+ << (i + 1) << SecondBase.isVirtual() << SecondBase.getType();
+ break;
+ }
+
+ if (FirstBase.getAccessSpecifierAsWritten() !=
+ SecondBase.getAccessSpecifierAsWritten()) {
+ ODRDiagError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseAccess)
+ << (i + 1) << FirstBase.getType()
+ << (int)FirstBase.getAccessSpecifierAsWritten();
+ ODRDiagNote(SecondRecord->getLocation(),
+ SecondBase.getSourceRange(), BaseAccess)
+ << (i + 1) << SecondBase.getType()
+ << (int)SecondBase.getAccessSpecifierAsWritten();
+ break;
+ }
+ }
+
+ if (i != FirstNumBases) {
+ Diagnosed = true;
+ break;
+ }
+ }
+
using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
+
+ const ClassTemplateDecl *FirstTemplate =
+ FirstRecord->getDescribedClassTemplate();
+ const ClassTemplateDecl *SecondTemplate =
+ SecondRecord->getDescribedClassTemplate();
+
+ assert(!FirstTemplate == !SecondTemplate &&
+ "Both pointers should be null or non-null");
+
+ enum ODRTemplateDifference {
+ ParamEmptyName,
+ ParamName,
+ ParamSingleDefaultArgument,
+ ParamDifferentDefaultArgument,
+ };
+
+ if (FirstTemplate && SecondTemplate) {
+ DeclHashes FirstTemplateHashes;
+ DeclHashes SecondTemplateHashes;
+ ODRHash Hash;
+
+ auto PopulateTemplateParameterHashs =
+ [&Hash](DeclHashes &Hashes, const ClassTemplateDecl *TD) {
+ for (auto *D : TD->getTemplateParameters()->asArray()) {
+ Hash.clear();
+ Hash.AddSubDecl(D);
+ Hashes.emplace_back(D, Hash.CalculateHash());
+ }
+ };
+
+ PopulateTemplateParameterHashs(FirstTemplateHashes, FirstTemplate);
+ PopulateTemplateParameterHashs(SecondTemplateHashes, SecondTemplate);
+
+ assert(FirstTemplateHashes.size() == SecondTemplateHashes.size() &&
+ "Number of template parameters should be equal.");
+
+ auto FirstIt = FirstTemplateHashes.begin();
+ auto FirstEnd = FirstTemplateHashes.end();
+ auto SecondIt = SecondTemplateHashes.begin();
+ for (; FirstIt != FirstEnd; ++FirstIt, ++SecondIt) {
+ if (FirstIt->second == SecondIt->second)
+ continue;
+
+ auto ODRDiagError = [FirstRecord, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRTemplateDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_template_parameter)
+ << FirstRecord << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto ODRDiagNote = [&SecondModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRTemplateDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_template_parameter)
+ << SecondModule << Range << DiffType;
+ };
+
+ const NamedDecl* FirstDecl = cast<NamedDecl>(FirstIt->first);
+ const NamedDecl* SecondDecl = cast<NamedDecl>(SecondIt->first);
+
+ assert(FirstDecl->getKind() == SecondDecl->getKind() &&
+ "Parameter Decl's should be the same kind.");
+
+ DeclarationName FirstName = FirstDecl->getDeclName();
+ DeclarationName SecondName = SecondDecl->getDeclName();
+
+ if (FirstName != SecondName) {
+ const bool FirstNameEmpty =
+ FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo();
+ const bool SecondNameEmpty =
+ SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo();
+ assert((!FirstNameEmpty || !SecondNameEmpty) &&
+ "Both template parameters cannot be unnamed.");
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ FirstNameEmpty ? ParamEmptyName : ParamName)
+ << FirstName;
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ SecondNameEmpty ? ParamEmptyName : ParamName)
+ << SecondName;
+ break;
+ }
+
+ switch (FirstDecl->getKind()) {
+ default:
+ llvm_unreachable("Invalid template parameter type.");
+ case Decl::TemplateTypeParm: {
+ const auto *FirstParam = cast<TemplateTypeParmDecl>(FirstDecl);
+ const auto *SecondParam = cast<TemplateTypeParmDecl>(SecondDecl);
+ const bool HasFirstDefaultArgument =
+ FirstParam->hasDefaultArgument() &&
+ !FirstParam->defaultArgumentWasInherited();
+ const bool HasSecondDefaultArgument =
+ SecondParam->hasDefaultArgument() &&
+ !SecondParam->defaultArgumentWasInherited();
+
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ ODRDiagError(FirstDecl->getLocation(),
+ FirstDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasFirstDefaultArgument;
+ ODRDiagNote(SecondDecl->getLocation(),
+ SecondDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasSecondDefaultArgument;
+ break;
+ }
+
+ assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
+ "Expecting default arguments.");
+
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+
+ break;
+ }
+ case Decl::NonTypeTemplateParm: {
+ const auto *FirstParam = cast<NonTypeTemplateParmDecl>(FirstDecl);
+ const auto *SecondParam = cast<NonTypeTemplateParmDecl>(SecondDecl);
+ const bool HasFirstDefaultArgument =
+ FirstParam->hasDefaultArgument() &&
+ !FirstParam->defaultArgumentWasInherited();
+ const bool HasSecondDefaultArgument =
+ SecondParam->hasDefaultArgument() &&
+ !SecondParam->defaultArgumentWasInherited();
+
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ ODRDiagError(FirstDecl->getLocation(),
+ FirstDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasFirstDefaultArgument;
+ ODRDiagNote(SecondDecl->getLocation(),
+ SecondDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasSecondDefaultArgument;
+ break;
+ }
+
+ assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
+ "Expecting default arguments.");
+
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+
+ break;
+ }
+ case Decl::TemplateTemplateParm: {
+ const auto *FirstParam = cast<TemplateTemplateParmDecl>(FirstDecl);
+ const auto *SecondParam =
+ cast<TemplateTemplateParmDecl>(SecondDecl);
+ const bool HasFirstDefaultArgument =
+ FirstParam->hasDefaultArgument() &&
+ !FirstParam->defaultArgumentWasInherited();
+ const bool HasSecondDefaultArgument =
+ SecondParam->hasDefaultArgument() &&
+ !SecondParam->defaultArgumentWasInherited();
+
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ ODRDiagError(FirstDecl->getLocation(),
+ FirstDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasFirstDefaultArgument;
+ ODRDiagNote(SecondDecl->getLocation(),
+ SecondDecl->getSourceRange(),
+ ParamSingleDefaultArgument)
+ << HasSecondDefaultArgument;
+ break;
+ }
+
+ assert(HasFirstDefaultArgument && HasSecondDefaultArgument &&
+ "Expecting default arguments.");
+
+ ODRDiagError(FirstDecl->getLocation(), FirstDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+ ODRDiagNote(SecondDecl->getLocation(), SecondDecl->getSourceRange(),
+ ParamDifferentDefaultArgument);
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ if (FirstIt != FirstEnd) {
+ Diagnosed = true;
+ break;
+ }
+ }
+
DeclHashes FirstHashes;
DeclHashes SecondHashes;
ODRHash Hash;
@@ -9063,6 +9664,7 @@ void ASTReader::diagnoseOdrViolations() {
// Used with err_module_odr_violation_mismatch_decl and
// note_module_odr_violation_mismatch_decl
+ // This list should be the same Decl's as in ODRHash::isWhiteListedDecl
enum {
EndOfClass,
PublicSpecifer,
@@ -9071,6 +9673,10 @@ void ASTReader::diagnoseOdrViolations() {
StaticAssert,
Field,
CXXMethod,
+ TypeAlias,
+ TypeDef,
+ Var,
+ Friend,
Other
} FirstDiffType = Other,
SecondDiffType = Other;
@@ -9097,7 +9703,17 @@ void ASTReader::diagnoseOdrViolations() {
case Decl::Field:
return Field;
case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
return CXXMethod;
+ case Decl::TypeAlias:
+ return TypeAlias;
+ case Decl::Typedef:
+ return TypeDef;
+ case Decl::Var:
+ return Var;
+ case Decl::Friend:
+ return Friend;
}
};
@@ -9135,9 +9751,20 @@ void ASTReader::diagnoseOdrViolations() {
diag::err_module_odr_violation_different_definitions)
<< FirstRecord << FirstModule.empty() << FirstModule;
+ if (FirstDecl) {
+ Diag(FirstDecl->getLocation(), diag::note_first_module_difference)
+ << FirstRecord << FirstDecl->getSourceRange();
+ }
+
Diag(SecondRecord->getLocation(),
diag::note_module_odr_violation_different_definitions)
<< SecondModule;
+
+ if (SecondDecl) {
+ Diag(SecondDecl->getLocation(), diag::note_second_module_difference)
+ << SecondDecl->getSourceRange();
+ }
+
Diagnosed = true;
break;
}
@@ -9191,6 +9818,21 @@ void ASTReader::diagnoseOdrViolations() {
MethodVolatile,
MethodConst,
MethodInline,
+ MethodNumberParameters,
+ MethodParameterType,
+ MethodParameterName,
+ MethodParameterSingleDefaultArgument,
+ MethodParameterDifferentDefaultArgument,
+ TypedefName,
+ TypedefType,
+ VarName,
+ VarType,
+ VarSingleInitializer,
+ VarDifferentInitializer,
+ VarConstexpr,
+ FriendTypeFunction,
+ FriendType,
+ FriendFunction,
};
// These lambdas have the common portions of the ODR diagnostics. This
@@ -9215,9 +9857,9 @@ void ASTReader::diagnoseOdrViolations() {
return Hash.CalculateHash();
};
- auto ComputeDeclNameODRHash = [&Hash](const DeclarationName Name) {
+ auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
Hash.clear();
- Hash.AddDeclarationName(Name);
+ Hash.AddQualType(Ty);
return Hash.CalculateHash();
};
@@ -9302,16 +9944,13 @@ void ASTReader::diagnoseOdrViolations() {
break;
}
- assert(
- Context.hasSameType(FirstField->getType(), SecondField->getType()));
+ assert(getContext().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)) {
+ if (ComputeQualTypeODRHash(FirstType) !=
+ ComputeQualTypeODRHash(SecondType)) {
ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
FieldTypeName)
<< FirstII << FirstType;
@@ -9323,24 +9962,6 @@ void ASTReader::diagnoseOdrViolations() {
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) {
@@ -9412,17 +10033,30 @@ void ASTReader::diagnoseOdrViolations() {
break;
}
case CXXMethod: {
+ enum {
+ DiagMethod,
+ DiagConstructor,
+ DiagDestructor,
+ } FirstMethodType,
+ SecondMethodType;
+ auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl* D) {
+ if (isa<CXXConstructorDecl>(D)) return DiagConstructor;
+ if (isa<CXXDestructorDecl>(D)) return DiagDestructor;
+ return DiagMethod;
+ };
const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
+ FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod);
+ SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod);
auto FirstName = FirstMethod->getDeclName();
auto SecondName = SecondMethod->getDeclName();
- if (FirstName != SecondName) {
+ if (FirstMethodType != SecondMethodType || FirstName != SecondName) {
ODRDiagError(FirstMethod->getLocation(),
FirstMethod->getSourceRange(), MethodName)
- << FirstName;
+ << FirstMethodType << FirstName;
ODRDiagNote(SecondMethod->getLocation(),
SecondMethod->getSourceRange(), MethodName)
- << SecondName;
+ << SecondMethodType << SecondName;
Diagnosed = true;
break;
@@ -9433,11 +10067,11 @@ void ASTReader::diagnoseOdrViolations() {
if (FirstDeleted != SecondDeleted) {
ODRDiagError(FirstMethod->getLocation(),
FirstMethod->getSourceRange(), MethodDeleted)
- << FirstName << FirstDeleted;
+ << FirstMethodType << FirstName << FirstDeleted;
ODRDiagNote(SecondMethod->getLocation(),
SecondMethod->getSourceRange(), MethodDeleted)
- << SecondName << SecondDeleted;
+ << SecondMethodType << SecondName << SecondDeleted;
Diagnosed = true;
break;
}
@@ -9450,10 +10084,10 @@ void ASTReader::diagnoseOdrViolations() {
(FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
ODRDiagError(FirstMethod->getLocation(),
FirstMethod->getSourceRange(), MethodVirtual)
- << FirstName << FirstPure << FirstVirtual;
+ << FirstMethodType << FirstName << FirstPure << FirstVirtual;
ODRDiagNote(SecondMethod->getLocation(),
SecondMethod->getSourceRange(), MethodVirtual)
- << SecondName << SecondPure << SecondVirtual;
+ << SecondMethodType << SecondName << SecondPure << SecondVirtual;
Diagnosed = true;
break;
}
@@ -9468,10 +10102,10 @@ void ASTReader::diagnoseOdrViolations() {
if (FirstStatic != SecondStatic) {
ODRDiagError(FirstMethod->getLocation(),
FirstMethod->getSourceRange(), MethodStatic)
- << FirstName << FirstStatic;
+ << FirstMethodType << FirstName << FirstStatic;
ODRDiagNote(SecondMethod->getLocation(),
SecondMethod->getSourceRange(), MethodStatic)
- << SecondName << SecondStatic;
+ << SecondMethodType << SecondName << SecondStatic;
Diagnosed = true;
break;
}
@@ -9481,10 +10115,10 @@ void ASTReader::diagnoseOdrViolations() {
if (FirstVolatile != SecondVolatile) {
ODRDiagError(FirstMethod->getLocation(),
FirstMethod->getSourceRange(), MethodVolatile)
- << FirstName << FirstVolatile;
+ << FirstMethodType << FirstName << FirstVolatile;
ODRDiagNote(SecondMethod->getLocation(),
SecondMethod->getSourceRange(), MethodVolatile)
- << SecondName << SecondVolatile;
+ << SecondMethodType << SecondName << SecondVolatile;
Diagnosed = true;
break;
}
@@ -9494,10 +10128,10 @@ void ASTReader::diagnoseOdrViolations() {
if (FirstConst != SecondConst) {
ODRDiagError(FirstMethod->getLocation(),
FirstMethod->getSourceRange(), MethodConst)
- << FirstName << FirstConst;
+ << FirstMethodType << FirstName << FirstConst;
ODRDiagNote(SecondMethod->getLocation(),
SecondMethod->getSourceRange(), MethodConst)
- << SecondName << SecondConst;
+ << SecondMethodType << SecondName << SecondConst;
Diagnosed = true;
break;
}
@@ -9507,14 +10141,273 @@ void ASTReader::diagnoseOdrViolations() {
if (FirstInline != SecondInline) {
ODRDiagError(FirstMethod->getLocation(),
FirstMethod->getSourceRange(), MethodInline)
- << FirstName << FirstInline;
+ << FirstMethodType << FirstName << FirstInline;
ODRDiagNote(SecondMethod->getLocation(),
SecondMethod->getSourceRange(), MethodInline)
- << SecondName << SecondInline;
+ << SecondMethodType << SecondName << SecondInline;
+ Diagnosed = true;
+ break;
+ }
+
+ const unsigned FirstNumParameters = FirstMethod->param_size();
+ const unsigned SecondNumParameters = SecondMethod->param_size();
+ if (FirstNumParameters != SecondNumParameters) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodNumberParameters)
+ << FirstMethodType << FirstName << FirstNumParameters;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodNumberParameters)
+ << SecondMethodType << SecondName << SecondNumParameters;
+ Diagnosed = true;
+ break;
+ }
+
+ // Need this status boolean to know when break out of the switch.
+ bool ParameterMismatch = false;
+ for (unsigned I = 0; I < FirstNumParameters; ++I) {
+ const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ ComputeQualTypeODRHash(FirstParamType) !=
+ ComputeQualTypeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodParameterType)
+ << FirstMethodType << FirstName << (I + 1) << FirstParamType
+ << true << ParamDecayedType->getOriginalType();
+ } else {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodParameterType)
+ << FirstMethodType << FirstName << (I + 1) << FirstParamType
+ << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodParameterType)
+ << SecondMethodType << SecondName << (I + 1)
+ << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodParameterType)
+ << SecondMethodType << SecondName << (I + 1)
+ << SecondParamType << false;
+ }
+ ParameterMismatch = true;
+ break;
+ }
+
+ DeclarationName FirstParamName = FirstParam->getDeclName();
+ DeclarationName SecondParamName = SecondParam->getDeclName();
+ if (FirstParamName != SecondParamName) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodParameterName)
+ << FirstMethodType << FirstName << (I + 1) << FirstParamName;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodParameterName)
+ << SecondMethodType << SecondName << (I + 1) << SecondParamName;
+ ParameterMismatch = true;
+ break;
+ }
+
+ const Expr *FirstInit = FirstParam->getInit();
+ const Expr *SecondInit = SecondParam->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(),
+ MethodParameterSingleDefaultArgument)
+ << FirstMethodType << FirstName << (I + 1)
+ << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(),
+ MethodParameterSingleDefaultArgument)
+ << SecondMethodType << SecondName << (I + 1)
+ << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ ParameterMismatch = true;
+ break;
+ }
+
+ if (FirstInit && SecondInit &&
+ ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(),
+ MethodParameterDifferentDefaultArgument)
+ << FirstMethodType << FirstName << (I + 1)
+ << FirstInit->getSourceRange();
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(),
+ MethodParameterDifferentDefaultArgument)
+ << SecondMethodType << SecondName << (I + 1)
+ << SecondInit->getSourceRange();
+ ParameterMismatch = true;
+ break;
+
+ }
+ }
+
+ if (ParameterMismatch) {
+ Diagnosed = true;
+ break;
+ }
+
+ break;
+ }
+ case TypeAlias:
+ case TypeDef: {
+ TypedefNameDecl *FirstTD = cast<TypedefNameDecl>(FirstDecl);
+ TypedefNameDecl *SecondTD = cast<TypedefNameDecl>(SecondDecl);
+ auto FirstName = FirstTD->getDeclName();
+ auto SecondName = SecondTD->getDeclName();
+ if (FirstName != SecondName) {
+ ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
+ TypedefName)
+ << (FirstDiffType == TypeAlias) << FirstName;
+ ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
+ TypedefName)
+ << (FirstDiffType == TypeAlias) << SecondName;
+ Diagnosed = true;
+ break;
+ }
+
+ QualType FirstType = FirstTD->getUnderlyingType();
+ QualType SecondType = SecondTD->getUnderlyingType();
+ if (ComputeQualTypeODRHash(FirstType) !=
+ ComputeQualTypeODRHash(SecondType)) {
+ ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
+ TypedefType)
+ << (FirstDiffType == TypeAlias) << FirstName << FirstType;
+ ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
+ TypedefType)
+ << (FirstDiffType == TypeAlias) << SecondName << SecondType;
+ Diagnosed = true;
+ break;
+ }
+ break;
+ }
+ case Var: {
+ VarDecl *FirstVD = cast<VarDecl>(FirstDecl);
+ VarDecl *SecondVD = cast<VarDecl>(SecondDecl);
+ auto FirstName = FirstVD->getDeclName();
+ auto SecondName = SecondVD->getDeclName();
+ if (FirstName != SecondName) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarName)
+ << FirstName;
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarName)
+ << SecondName;
+ Diagnosed = true;
+ break;
+ }
+
+ QualType FirstType = FirstVD->getType();
+ QualType SecondType = SecondVD->getType();
+ if (ComputeQualTypeODRHash(FirstType) !=
+ ComputeQualTypeODRHash(SecondType)) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarType)
+ << FirstName << FirstType;
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarType)
+ << SecondName << SecondType;
+ Diagnosed = true;
+ break;
+ }
+
+ const Expr *FirstInit = FirstVD->getInit();
+ const Expr *SecondInit = SecondVD->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarSingleInitializer)
+ << FirstName << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange(): SourceRange());
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarSingleInitializer)
+ << SecondName << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstInit && SecondInit &&
+ ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarDifferentInitializer)
+ << FirstName << FirstInit->getSourceRange();
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarDifferentInitializer)
+ << SecondName << SecondInit->getSourceRange();
Diagnosed = true;
break;
}
+ const bool FirstIsConstexpr = FirstVD->isConstexpr();
+ const bool SecondIsConstexpr = SecondVD->isConstexpr();
+ if (FirstIsConstexpr != SecondIsConstexpr) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarConstexpr)
+ << FirstName << FirstIsConstexpr;
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarConstexpr)
+ << SecondName << SecondIsConstexpr;
+ Diagnosed = true;
+ break;
+ }
+ break;
+ }
+ case Friend: {
+ FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl);
+ FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl);
+
+ NamedDecl *FirstND = FirstFriend->getFriendDecl();
+ NamedDecl *SecondND = SecondFriend->getFriendDecl();
+
+ TypeSourceInfo *FirstTSI = FirstFriend->getFriendType();
+ TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
+
+ if (FirstND && SecondND) {
+ ODRDiagError(FirstFriend->getFriendLoc(),
+ FirstFriend->getSourceRange(), FriendFunction)
+ << FirstND;
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendFunction)
+ << SecondND;
+
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstTSI && SecondTSI) {
+ QualType FirstFriendType = FirstTSI->getType();
+ QualType SecondFriendType = SecondTSI->getType();
+ assert(ComputeQualTypeODRHash(FirstFriendType) !=
+ ComputeQualTypeODRHash(SecondFriendType));
+ ODRDiagError(FirstFriend->getFriendLoc(),
+ FirstFriend->getSourceRange(), FriendType)
+ << FirstFriendType;
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendType)
+ << SecondFriendType;
+ Diagnosed = true;
+ break;
+ }
+
+ ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendTypeFunction)
+ << (FirstTSI == nullptr);
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendTypeFunction)
+ << (SecondTSI == nullptr);
+
+ Diagnosed = true;
break;
}
}
@@ -9522,13 +10415,13 @@ void ASTReader::diagnoseOdrViolations() {
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;
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule << FirstDiffType << SecondDecl->getSourceRange();
Diagnosed = true;
}
@@ -9570,10 +10463,10 @@ void ASTReader::FinishedDeserializing() {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
auto ESI = FPT->getExtProtoInfo().ExceptionSpec;
- if (auto *Listener = Context.getASTMutationListener())
+ if (auto *Listener = getContext().getASTMutationListener())
Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second));
for (auto *Redecl : Update.second->redecls())
- Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
+ getContext().adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
}
}
@@ -9615,7 +10508,7 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
}
}
-ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
+ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
StringRef isysroot, bool DisableValidation,
@@ -9628,8 +10521,11 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
: cast<ASTReaderListener>(new PCHValidator(PP, *this))),
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP),
- Context(Context), ModuleMgr(PP.getFileManager(), PCHContainerRdr),
- DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot),
+ ContextObj(Context),
+ ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr,
+ PP.getHeaderSearchInfo()),
+ 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 d33a475927..ae9efa9948 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -119,12 +119,16 @@ namespace clang {
}
void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
- void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data);
+ void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
+ const CXXRecordDecl *D);
void MergeDefinitionData(CXXRecordDecl *D,
struct CXXRecordDecl::DefinitionData &&NewDD);
void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
void MergeDefinitionData(ObjCInterfaceDecl *D,
struct ObjCInterfaceDecl::DefinitionData &&NewDD);
+ void ReadObjCDefinitionData(struct ObjCProtocolDecl::DefinitionData &Data);
+ void MergeDefinitionData(ObjCProtocolDecl *D,
+ struct ObjCProtocolDecl::DefinitionData &&NewDD);
static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader,
DeclContext *DC,
@@ -215,6 +219,30 @@ namespace clang {
TypedefNameForLinkage(nullptr), HasPendingBody(false),
IsDeclMarkedUsed(false) {}
+ template <typename T> static
+ void AddLazySpecializations(T *D,
+ SmallVectorImpl<serialization::DeclID>& IDs) {
+ if (IDs.empty())
+ return;
+
+ // FIXME: We should avoid this pattern of getting the ASTContext.
+ ASTContext &C = D->getASTContext();
+
+ auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;
+
+ if (auto &Old = LazySpecializations) {
+ IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
+ std::sort(IDs.begin(), IDs.end());
+ IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
+ }
+
+ auto *Result = new (C) serialization::DeclID[1 + IDs.size()];
+ *Result = IDs.size();
+ std::copy(IDs.begin(), IDs.end(), Result + 1);
+
+ LazySpecializations = Result;
+ }
+
template <typename DeclT>
static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
static Decl *getMostRecentDeclImpl(...);
@@ -243,7 +271,7 @@ namespace clang {
void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);
- void UpdateDecl(Decl *D);
+ void UpdateDecl(Decl *D, llvm::SmallVectorImpl<serialization::DeclID>&);
static void setNextObjCCategory(ObjCCategoryDecl *Cat,
ObjCCategoryDecl *Next) {
@@ -424,6 +452,8 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() {
}
void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) {
+ if (Record.readInt())
+ Reader.DefinitionSource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile;
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
CD->NumCtorInitializers = Record.readInt();
if (CD->NumCtorInitializers)
@@ -519,32 +549,32 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setTopLevelDeclInObjCContainer(Record.readInt());
D->setAccess((AccessSpecifier)Record.readInt());
D->FromASTFile = true;
- D->setModulePrivate(Record.readInt());
- D->Hidden = D->isModulePrivate();
+ bool ModulePrivate = Record.readInt();
// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
if (unsigned SubmoduleID = readSubmoduleID()) {
// Store the owning submodule ID in the declaration.
+ D->setModuleOwnershipKind(
+ ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate
+ : Decl::ModuleOwnershipKind::VisibleWhenImported);
D->setOwningModuleID(SubmoduleID);
- if (D->Hidden) {
- // Module-private declarations are never visible, so there is no work to do.
+ if (ModulePrivate) {
+ // Module-private declarations are never visible, so there is no work to
+ // do.
} else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
// If local visibility is being tracked, this declaration will become
- // hidden and visible as the owning module does. Inform Sema that this
- // declaration might not be visible.
- D->Hidden = true;
+ // hidden and visible as the owning module does.
} else if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
- if (Owner->NameVisibility != Module::AllVisible) {
- // The owning module is not visible. Mark this declaration as hidden.
- D->Hidden = true;
-
- // Note that this declaration was hidden because its owning module is
- // not yet visible.
+ // Mark the declaration as visible when its owning module becomes visible.
+ if (Owner->NameVisibility == Module::AllVisible)
+ D->setVisibleDespiteOwningModule();
+ else
Reader.HiddenNamesMap[Owner].push_back(D);
- }
}
+ } else if (ModulePrivate) {
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
}
}
@@ -1044,18 +1074,8 @@ void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
IVD->setSynthesize(synth);
}
-void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
- RedeclarableResult Redecl = VisitRedeclarable(PD);
- VisitObjCContainerDecl(PD);
- mergeRedeclarable(PD, Redecl);
-
- if (Record.readInt()) {
- // Read the definition.
- PD->allocateDefinitionData();
-
- // Set the definition data of the canonical declaration, so other
- // redeclarations will see it.
- PD->getCanonicalDecl()->Data = PD->Data;
+void ASTDeclReader::ReadObjCDefinitionData(
+ struct ObjCProtocolDecl::DefinitionData &Data) {
unsigned NumProtoRefs = Record.readInt();
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
@@ -1066,9 +1086,37 @@ void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
ProtoLocs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoLocs.push_back(ReadSourceLocation());
- PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- Reader.getContext());
+ Data.ReferencedProtocols.set(ProtoRefs.data(), NumProtoRefs,
+ ProtoLocs.data(), Reader.getContext());
+}
+
+void ASTDeclReader::MergeDefinitionData(ObjCProtocolDecl *D,
+ struct ObjCProtocolDecl::DefinitionData &&NewDD) {
+ // FIXME: odr checking?
+}
+void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
+ RedeclarableResult Redecl = VisitRedeclarable(PD);
+ VisitObjCContainerDecl(PD);
+ mergeRedeclarable(PD, Redecl);
+
+ if (Record.readInt()) {
+ // Read the definition.
+ PD->allocateDefinitionData();
+
+ ReadObjCDefinitionData(PD->data());
+
+ ObjCProtocolDecl *Canon = PD->getCanonicalDecl();
+ if (Canon->Data.getPointer()) {
+ // If we already have a definition, keep the definition invariant and
+ // merge the data.
+ MergeDefinitionData(Canon, std::move(PD->data()));
+ PD->Data = Canon->Data;
+ } else {
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ PD->getCanonicalDecl()->Data = PD->Data;
+ }
// Note that we have deserialized a definition.
Reader.PendingDefinitions.insert(PD);
} else {
@@ -1124,8 +1172,12 @@ void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
(ObjCPropertyDecl::PropertyAttributeKind)Record.readInt());
D->setPropertyImplementation(
(ObjCPropertyDecl::PropertyControl)Record.readInt());
- D->setGetterName(Record.readDeclarationName().getObjCSelector());
- D->setSetterName(Record.readDeclarationName().getObjCSelector());
+ DeclarationName GetterName = Record.readDeclarationName();
+ SourceLocation GetterLoc = ReadSourceLocation();
+ D->setGetterName(GetterName.getObjCSelector(), GetterLoc);
+ DeclarationName SetterName = Record.readDeclarationName();
+ SourceLocation SetterLoc = ReadSourceLocation();
+ D->setSetterName(SetterName.getObjCSelector(), SetterLoc);
D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>());
@@ -1167,16 +1219,17 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
VisitDeclaratorDecl(FD);
FD->Mutable = Record.readInt();
- if (int BitWidthOrInitializer = Record.readInt()) {
- FD->InitStorage.setInt(
- static_cast<FieldDecl::InitStorageKind>(BitWidthOrInitializer - 1));
- if (FD->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) {
- // Read captured variable length array.
- FD->InitStorage.setPointer(Record.readType().getAsOpaquePtr());
- } else {
- FD->InitStorage.setPointer(Record.readExpr());
- }
+
+ if (auto ISK = static_cast<FieldDecl::InitStorageKind>(Record.readInt())) {
+ FD->InitStorage.setInt(ISK);
+ FD->InitStorage.setPointer(ISK == FieldDecl::ISK_CapturedVLAType
+ ? Record.readType().getAsOpaquePtr()
+ : Record.readExpr());
}
+
+ if (auto *BW = Record.readExpr())
+ FD->setBitWidth(BW);
+
if (!FD->getDeclName()) {
if (FieldDecl *Tmpl = ReadDeclAs<FieldDecl>())
Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
@@ -1222,6 +1275,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->NonParmVarDeclBits.IsConstexpr = Record.readInt();
VD->NonParmVarDeclBits.IsInitCapture = Record.readInt();
VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = Record.readInt();
+ VD->NonParmVarDeclBits.ImplicitParamKind = Record.readInt();
}
Linkage VarLinkage = Linkage(Record.readInt());
VD->setCachedLinkage(VarLinkage);
@@ -1240,6 +1294,9 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
}
}
+ if (VD->getStorageDuration() == SD_Static && Record.readInt())
+ Reader.DefinitionSource[VD] = Loc.F->Kind == ModuleKind::MK_MainFile;
+
enum VarKind {
VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
};
@@ -1484,7 +1541,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();
@@ -1506,9 +1563,11 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasUninitializedFields = Record.readInt();
Data.HasInheritedConstructor = Record.readInt();
Data.HasInheritedAssignment = Record.readInt();
+ Data.NeedOverloadResolutionForCopyConstructor = Record.readInt();
Data.NeedOverloadResolutionForMoveConstructor = Record.readInt();
Data.NeedOverloadResolutionForMoveAssignment = Record.readInt();
Data.NeedOverloadResolutionForDestructor = Record.readInt();
+ Data.DefaultedCopyConstructorIsDeleted = Record.readInt();
Data.DefaultedMoveConstructorIsDeleted = Record.readInt();
Data.DefaultedMoveAssignmentIsDeleted = Record.readInt();
Data.DefaultedDestructorIsDeleted = Record.readInt();
@@ -1517,6 +1576,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasIrrelevantDestructor = Record.readInt();
Data.HasConstexprNonCopyMoveConstructor = Record.readInt();
Data.HasDefaultedDefaultConstructor = Record.readInt();
+ Data.CanPassInRegisters = Record.readInt();
Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();
Data.HasConstexprDefaultConstructor = Record.readInt();
Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();
@@ -1529,6 +1589,10 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt();
Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
Data.ODRHash = Record.readInt();
+ Data.HasODRHash = true;
+
+ if (Record.readInt())
+ Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile;
Data.NumBases = Record.readInt();
if (Data.NumBases)
@@ -1553,8 +1617,8 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.NumExplicitCaptures = Record.readInt();
Lambda.ManglingNumber = Record.readInt();
Lambda.ContextDecl = ReadDeclID();
- Lambda.Captures
- = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
+ Lambda.Captures = (Capture *)Reader.getContext().Allocate(
+ sizeof(Capture) * Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures;
Lambda.MethodTyInfo = GetTypeSourceInfo();
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
@@ -1637,9 +1701,11 @@ void ASTDeclReader::MergeDefinitionData(
MATCH_FIELD(HasUninitializedFields)
MATCH_FIELD(HasInheritedConstructor)
MATCH_FIELD(HasInheritedAssignment)
+ MATCH_FIELD(NeedOverloadResolutionForCopyConstructor)
MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
MATCH_FIELD(NeedOverloadResolutionForDestructor)
+ MATCH_FIELD(DefaultedCopyConstructorIsDeleted)
MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
MATCH_FIELD(DefaultedDestructorIsDeleted)
@@ -1648,6 +1714,7 @@ void ASTDeclReader::MergeDefinitionData(
MATCH_FIELD(HasIrrelevantDestructor)
OR_FIELD(HasConstexprNonCopyMoveConstructor)
OR_FIELD(HasDefaultedDefaultConstructor)
+ MATCH_FIELD(CanPassInRegisters)
MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
OR_FIELD(HasConstexprDefaultConstructor)
MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
@@ -1660,7 +1727,6 @@ void ASTDeclReader::MergeDefinitionData(
OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
MATCH_FIELD(IsLambda)
- MATCH_FIELD(ODRHash)
#undef OR_FIELD
#undef MATCH_FIELD
@@ -1684,8 +1750,13 @@ 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);
+ Reader.PendingOdrMergeFailures[DD.Definition].push_back(
+ {MergeDD.Definition, &MergeDD});
}
void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
@@ -1701,7 +1772,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
@@ -1792,6 +1863,8 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
VisitFunctionDecl(D);
+ if (Record.readInt())
+ D->setIsCopyDeductionCandidate();
}
void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
@@ -1830,9 +1903,12 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>()) {
auto *Canon = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ auto *ThisArg = Record.readExpr();
// FIXME: Check consistency if we have an old and new operator delete.
- if (!Canon->OperatorDelete)
+ if (!Canon->OperatorDelete) {
Canon->OperatorDelete = OperatorDelete;
+ Canon->OperatorDeleteThisArg = ThisArg;
+ }
}
}
@@ -1934,21 +2010,6 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
return Redecl;
}
-static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old,
- SmallVectorImpl<DeclID> &IDs) {
- assert(!IDs.empty() && "no IDs to add to list");
- if (Old) {
- IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
- std::sort(IDs.begin(), IDs.end());
- IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
- }
-
- auto *Result = new (Context) DeclID[1 + IDs.size()];
- *Result = IDs.size();
- std::copy(IDs.begin(), IDs.end(), Result + 1);
- return Result;
-}
-
void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
@@ -1957,19 +2018,14 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// the specializations.
SmallVector<serialization::DeclID, 32> SpecIDs;
ReadDeclIDList(SpecIDs);
-
- if (!SpecIDs.empty()) {
- auto *CommonPtr = D->getCommonPtr();
- CommonPtr->LazySpecializations = newDeclIDList(
- Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
- }
+ ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
if (D->getTemplatedDecl()->TemplateOrInstantiation) {
// We were loaded before our templated declaration was. We've not set up
// its corresponding type yet (see VisitCXXRecordDeclImpl), so reconstruct
// it now.
- Reader.Context.getInjectedClassNameType(
+ Reader.getContext().getInjectedClassNameType(
D->getTemplatedDecl(), D->getInjectedClassNameSpecialization());
}
}
@@ -1989,12 +2045,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
// the specializations.
SmallVector<serialization::DeclID, 32> SpecIDs;
ReadDeclIDList(SpecIDs);
-
- if (!SpecIDs.empty()) {
- auto *CommonPtr = D->getCommonPtr();
- CommonPtr->LazySpecializations = newDeclIDList(
- Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
- }
+ ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}
@@ -2100,12 +2151,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
SmallVector<serialization::DeclID, 32> SpecIDs;
ReadDeclIDList(SpecIDs);
-
- if (!SpecIDs.empty()) {
- auto *CommonPtr = D->getCommonPtr();
- CommonPtr->LazySpecializations = newDeclIDList(
- Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
- }
+ ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}
@@ -2456,8 +2502,8 @@ void ASTDeclReader::mergeMergeable(Mergeable<T> *D) {
if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
if (T *Existing = ExistingRes)
- Reader.Context.setPrimaryMergedDecl(static_cast<T*>(D),
- Existing->getCanonicalDecl());
+ Reader.getContext().setPrimaryMergedDecl(static_cast<T *>(D),
+ Existing->getCanonicalDecl());
}
void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
@@ -2475,7 +2521,9 @@ void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
VisitValueDecl(D);
D->setLocation(ReadSourceLocation());
D->setCombiner(Record.readExpr());
- D->setInitializer(Record.readExpr());
+ D->setInitializer(
+ Record.readExpr(),
+ static_cast<OMPDeclareReductionDecl::InitKind>(Record.readInt()));
D->PrevDeclInScope = ReadDeclID();
}
@@ -2493,6 +2541,7 @@ void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) {
Attr *New = nullptr;
attr::Kind Kind = (attr::Kind)Record.readInt();
SourceRange Range = Record.readSourceRange();
+ ASTContext &Context = getContext();
#include "clang/Serialization/AttrPCHRead.inc"
@@ -2527,11 +2576,14 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) {
// An ObjCMethodDecl is never considered as "interesting" because its
// implementation container always is.
- // An ImportDecl or VarDecl imported from a module will get emitted when
- // we import the relevant module.
- if ((isa<ImportDecl>(D) || isa<VarDecl>(D)) && D->getImportedOwningModule() &&
- Ctx.DeclMustBeEmitted(D))
- return false;
+ // An ImportDecl or VarDecl imported from a module map module will get
+ // emitted when we import the relevant module.
+ if (isa<ImportDecl>(D) || isa<VarDecl>(D)) {
+ auto *M = D->getImportedOwningModule();
+ if (M && M->Kind == Module::ModuleMapModule &&
+ Ctx.DeclMustBeEmitted(D))
+ return false;
+ }
if (isa<FileScopeAsmDecl>(D) ||
isa<ObjCProtocolDecl>(D) ||
@@ -2547,7 +2599,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;
}
@@ -2887,7 +2943,7 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
// commit to DC being the canonical definition now, and will fix this when
// we load the update record.
if (!DD) {
- DD = new (Reader.Context) struct CXXRecordDecl::DefinitionData(RD);
+ DD = new (Reader.getContext()) struct CXXRecordDecl::DefinitionData(RD);
RD->IsCompleteDefinition = true;
RD->DefinitionData = DD;
RD->getCanonicalDecl()->DefinitionData = DD;
@@ -3332,6 +3388,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
ASTDeclReader Reader(*this, Record, Loc, ID, DeclLoc);
unsigned Code = DeclsCursor.ReadCode();
+ ASTContext &Context = getContext();
Decl *D = nullptr;
switch ((DeclCode)Record.readRecord(DeclsCursor, Code)) {
case DECL_CONTEXT_LEXICAL:
@@ -3591,7 +3648,8 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
assert(Record.getIdx() == Record.size());
// Load any relevant update records.
- PendingUpdateRecords.push_back(std::make_pair(ID, D));
+ PendingUpdateRecords.push_back(
+ PendingUpdateRecord(ID, D, /*JustLoaded=*/true));
// Load the categories after recursive loading is finished.
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
@@ -3605,23 +3663,58 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// AST consumer might need to know about, queue it.
// We don't pass it to the consumer immediately because we may be in recursive
// loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(Context, D, Reader.hasPendingBody()))
- InterestingDecls.push_back(D);
+ PotentiallyInterestingDecls.push_back(
+ InterestingDecl(D, Reader.hasPendingBody()));
return D;
}
-void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
+void ASTReader::PassInterestingDeclsToConsumer() {
+ assert(Consumer);
+
+ if (PassingDeclsToConsumer)
+ return;
+
+ // Guard variable to avoid recursively redoing the process of passing
+ // decls to consumer.
+ SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
+ true);
+
+ // Ensure that we've loaded all potentially-interesting declarations
+ // that need to be eagerly loaded.
+ for (auto ID : EagerlyDeserializedDecls)
+ GetDecl(ID);
+ EagerlyDeserializedDecls.clear();
+
+ while (!PotentiallyInterestingDecls.empty()) {
+ InterestingDecl D = PotentiallyInterestingDecls.front();
+ PotentiallyInterestingDecls.pop_front();
+ if (isConsumerInterestedIn(getContext(), D.getDecl(), D.hasPendingBody()))
+ PassInterestingDeclToConsumer(D.getDecl());
+ }
+}
+
+void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
// The declaration may have been modified by files later in the chain.
// If this is the case, read the record containing the updates from each file
// and pass it to ASTDeclReader to make the modifications.
+ serialization::GlobalDeclID ID = Record.ID;
+ Decl *D = Record.D;
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
+
+ llvm::SmallVector<serialization::DeclID, 8> PendingLazySpecializationIDs;
+
if (UpdI != DeclUpdateOffsets.end()) {
auto UpdateOffsets = std::move(UpdI->second);
DeclUpdateOffsets.erase(UpdI);
- bool WasInteresting = isConsumerInterestedIn(Context, D, false);
+ // Check if this decl was interesting to the consumer. If we just loaded
+ // the declaration, then we know it was interesting and we skip the call
+ // to isConsumerInterestedIn because it is unsafe to call in the
+ // current ASTReader state.
+ bool WasInteresting =
+ Record.JustLoaded || isConsumerInterestedIn(getContext(), D, false);
for (auto &FileAndOffset : UpdateOffsets) {
ModuleFile *F = FileAndOffset.first;
uint64_t Offset = FileAndOffset.second;
@@ -3636,17 +3729,29 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID,
SourceLocation());
- Reader.UpdateDecl(D);
+ Reader.UpdateDecl(D, PendingLazySpecializationIDs);
// We might have made this declaration interesting. If so, remember that
// we need to hand it off to the consumer.
if (!WasInteresting &&
- isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) {
- InterestingDecls.push_back(D);
+ isConsumerInterestedIn(getContext(), D, Reader.hasPendingBody())) {
+ PotentiallyInterestingDecls.push_back(
+ InterestingDecl(D, Reader.hasPendingBody()));
WasInteresting = true;
}
}
}
+ // Add the lazy specializations to the template.
+ assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) || isa<VarTemplateDecl>(D)) &&
+ "Must not have pending specializations");
+ if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
+ ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
+ else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs);
+ else if (auto *VTD = dyn_cast<VarTemplateDecl>(D))
+ ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs);
+ PendingLazySpecializationIDs.clear();
// Load the pending visible updates for this decl context, if it has any.
auto I = PendingVisibleUpdates.find(ID);
@@ -3843,7 +3948,8 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
}
}
-void ASTDeclReader::UpdateDecl(Decl *D) {
+void ASTDeclReader::UpdateDecl(Decl *D,
+ llvm::SmallVectorImpl<serialization::DeclID> &PendingLazySpecializationIDs) {
while (Record.getIdx() < Record.size()) {
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
@@ -3859,8 +3965,8 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
}
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
- // It will be added to the template's specializations set when loaded.
- (void)Record.readDecl();
+ // It will be added to the template's lazy specialization set.
+ PendingLazySpecializationIDs.push_back(ReadDeclID());
break;
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
@@ -3878,10 +3984,23 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
break;
}
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
- cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
+ VarDecl *VD = cast<VarDecl>(D);
+ VD->getMemberSpecializationInfo()->setPointOfInstantiation(
ReadSourceLocation());
+ VD->NonParmVarDeclBits.IsInline = Record.readInt();
+ VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt();
+ uint64_t Val = Record.readInt();
+ if (Val && !VD->getInit()) {
+ VD->setInit(Record.readExpr());
+ if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3
+ EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = Val == 3;
+ }
+ }
break;
+ }
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: {
auto Param = cast<ParmVarDecl>(D);
@@ -4001,9 +4120,12 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
// record.
auto *Del = ReadDeclAs<FunctionDecl>();
auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ auto *ThisArg = Record.readExpr();
// FIXME: Check consistency if we have an old and new operator delete.
- if (!First->OperatorDelete)
+ if (!First->OperatorDelete) {
First->OperatorDelete = Del;
+ First->OperatorDeleteThisArg = ThisArg;
+ }
break;
}
@@ -4018,7 +4140,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
// FIXME: If the exception specification is already present, check that it
// matches.
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- FD->setType(Reader.Context.getFunctionType(
+ FD->setType(Reader.getContext().getFunctionType(
FPT->getReturnType(), FPT->getParamTypes(),
FPT->getExtProtoInfo().withExceptionSpec(ESI)));
@@ -4036,28 +4158,31 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
for (auto *Redecl : merged_redecls(D)) {
// FIXME: If the return type is already deduced, check that it matches.
FunctionDecl *FD = cast<FunctionDecl>(Redecl);
- Reader.Context.adjustDeducedFunctionResultType(FD, DeducedResultType);
+ Reader.getContext().adjustDeducedFunctionResultType(FD,
+ DeducedResultType);
}
break;
}
case UPD_DECL_MARKED_USED: {
// Maintain AST consistency: any later redeclarations are used too.
- D->markUsed(Reader.Context);
+ D->markUsed(Reader.getContext());
break;
}
case UPD_MANGLING_NUMBER:
- Reader.Context.setManglingNumber(cast<NamedDecl>(D), Record.readInt());
+ Reader.getContext().setManglingNumber(cast<NamedDecl>(D),
+ Record.readInt());
break;
case UPD_STATIC_LOCAL_NUMBER:
- Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record.readInt());
+ Reader.getContext().setStaticLocalNumber(cast<VarDecl>(D),
+ Record.readInt());
break;
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
- D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
- Reader.Context, ReadSourceRange()));
+ D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(Reader.getContext(),
+ ReadSourceRange()));
break;
case UPD_DECL_EXPORTED: {
@@ -4077,7 +4202,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
Reader.HiddenNamesMap[Owner].push_back(Exported);
} else {
// The declaration is now visible.
- Exported->Hidden = false;
+ Exported->setVisibleDespiteOwningModule();
}
break;
}
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 6a4482ba53..2b8a10f174 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -367,28 +367,45 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
}
void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+ VisitStmt(S);
+ assert(Record.peekInt() == S->NumParams);
+ Record.skipInts(1);
+ auto *StoredStmts = S->getStoredStmts();
+ for (unsigned i = 0;
+ i < CoroutineBodyStmt::SubStmt::FirstParamMove + S->NumParams; ++i)
+ StoredStmts[i] = Record.readSubStmt();
}
void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+ VisitStmt(S);
+ S->CoreturnLoc = Record.readSourceLocation();
+ for (auto &SubStmt: S->SubStmts)
+ SubStmt = Record.readSubStmt();
+ S->IsImplicit = Record.readInt() != 0;
}
-void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) {
+ VisitExpr(E);
+ E->KeywordLoc = ReadSourceLocation();
+ for (auto &SubExpr: E->SubExprs)
+ SubExpr = Record.readSubStmt();
+ E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt());
+ E->setIsImplicit(Record.readInt() != 0);
}
-void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) {
+ VisitExpr(E);
+ E->KeywordLoc = ReadSourceLocation();
+ for (auto &SubExpr: E->SubExprs)
+ SubExpr = Record.readSubStmt();
+ E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt());
}
-void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
+ VisitExpr(E);
+ E->KeywordLoc = ReadSourceLocation();
+ for (auto &SubExpr: E->SubExprs)
+ SubExpr = Record.readSubStmt();
}
void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
@@ -670,7 +687,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
E->setRHS(Record.readSubExpr());
E->setOpcode((BinaryOperator::Opcode)Record.readInt());
E->setOperatorLoc(ReadSourceLocation());
- E->setFPContractable((bool)Record.readInt());
+ E->setFPFeatures(FPOptions(Record.readInt()));
}
void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -1225,7 +1242,7 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
E->Operator = (OverloadedOperatorKind)Record.readInt();
E->Range = Record.readSourceRange();
- E->setFPContractable((bool)Record.readInt());
+ E->setFPFeatures(FPOptions(Record.readInt()));
}
void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
@@ -1834,6 +1851,12 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_reduction:
C = OMPReductionClause::CreateEmpty(Context, Reader->Record.readInt());
break;
+ case OMPC_task_reduction:
+ C = OMPTaskReductionClause::CreateEmpty(Context, Reader->Record.readInt());
+ break;
+ case OMPC_in_reduction:
+ C = OMPInReductionClause::CreateEmpty(Context, Reader->Record.readInt());
+ break;
case OMPC_linear:
C = OMPLinearClause::CreateEmpty(Context, Reader->Record.readInt());
break;
@@ -2138,6 +2161,78 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
C->setReductionOps(Vars);
}
+void OMPClauseReader::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) {
+ VisitOMPClauseWithPostUpdate(C);
+ C->setLParenLoc(Reader->ReadSourceLocation());
+ C->setColonLoc(Reader->ReadSourceLocation());
+ NestedNameSpecifierLoc NNSL = Reader->Record.readNestedNameSpecifierLoc();
+ DeclarationNameInfo DNI;
+ Reader->ReadDeclarationNameInfo(DNI);
+ C->setQualifierLoc(NNSL);
+ C->setNameInfo(DNI);
+
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setPrivates(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setLHSExprs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setRHSExprs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setReductionOps(Vars);
+}
+
+void OMPClauseReader::VisitOMPInReductionClause(OMPInReductionClause *C) {
+ VisitOMPClauseWithPostUpdate(C);
+ C->setLParenLoc(Reader->ReadSourceLocation());
+ C->setColonLoc(Reader->ReadSourceLocation());
+ NestedNameSpecifierLoc NNSL = Reader->Record.readNestedNameSpecifierLoc();
+ DeclarationNameInfo DNI;
+ Reader->ReadDeclarationNameInfo(DNI);
+ C->setQualifierLoc(NNSL);
+ C->setNameInfo(DNI);
+
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setPrivates(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setLHSExprs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setRHSExprs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setReductionOps(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setTaskgroupDescriptors(Vars);
+}
+
void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
VisitOMPClauseWithPostUpdate(C);
C->setLParenLoc(Reader->ReadSourceLocation());
@@ -2252,6 +2347,7 @@ void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) {
}
void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setDevice(Reader->Record.readSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation());
}
@@ -2578,6 +2674,13 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) {
D->setPrevUpperBoundVariable(Record.readSubExpr());
D->setDistInc(Record.readSubExpr());
D->setPrevEnsureUpperBound(Record.readSubExpr());
+ D->setCombinedLowerBoundVariable(Record.readSubExpr());
+ D->setCombinedUpperBoundVariable(Record.readSubExpr());
+ D->setCombinedEnsureUpperBound(Record.readSubExpr());
+ D->setCombinedInit(Record.readSubExpr());
+ D->setCombinedCond(Record.readSubExpr());
+ D->setCombinedNextLowerBound(Record.readSubExpr());
+ D->setCombinedNextUpperBound(Record.readSubExpr());
}
SmallVector<Expr *, 4> Sub;
unsigned CollapsedNum = D->getCollapsedNumber();
@@ -2702,7 +2805,10 @@ void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
void ASTStmtReader::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) {
VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ Record.skipInts(1);
VisitOMPExecutableDirective(D);
+ D->setReductionRef(Record.readSubExpr());
}
void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) {
@@ -2947,6 +3053,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ ASTContext &Context = getContext();
Stmt *S = nullptr;
bool Finished = false;
bool IsStmtReference = false;
@@ -3471,7 +3578,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case STMT_OMP_TASKGROUP_DIRECTIVE:
- S = OMPTaskgroupDirective::CreateEmpty(Context, Empty);
+ S = OMPTaskgroupDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
case STMT_OMP_FLUSH_DIRECTIVE:
@@ -3899,6 +4007,29 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = LambdaExpr::CreateDeserialized(Context, NumCaptures);
break;
}
+
+ case STMT_COROUTINE_BODY: {
+ unsigned NumParams = Record[ASTStmtReader::NumStmtFields];
+ S = CoroutineBodyStmt::Create(Context, Empty, NumParams);
+ break;
+ }
+
+ case STMT_CORETURN:
+ S = new (Context) CoreturnStmt(Empty);
+ break;
+
+ case EXPR_COAWAIT:
+ S = new (Context) CoawaitExpr(Empty);
+ break;
+
+ case EXPR_COYIELD:
+ S = new (Context) CoyieldExpr(Empty);
+ break;
+
+ case EXPR_DEPENDENT_COAWAIT:
+ S = new (Context) DependentCoawaitExpr(Empty);
+ break;
+
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b13a4e1ff4..dec8d8f7d7 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -35,6 +35,7 @@
#include "clang/Basic/FileSystemOptions.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"
@@ -254,6 +255,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
// FIXME: need to stabilize encoding of calling convention...
Record.push_back(C.getCC());
Record.push_back(C.getProducesResult());
+ Record.push_back(C.getNoCallerSavedRegs());
if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult())
AbbrevToUse = 0;
@@ -425,8 +427,19 @@ 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
+ASTTypeWriter::VisitDependentAddressSpaceType(
+ const DependentAddressSpaceType *T) {
+ Record.AddTypeRef(T->getPointeeType());
+ Record.AddStmt(T->getAddrSpaceExpr());
+ Record.AddSourceLocation(T->getAttributeLoc());
+ Code = TYPE_DEPENDENT_ADDRESS_SPACE;
}
void
@@ -623,6 +636,15 @@ void TypeLocWriter::VisitDependentSizedArrayTypeLoc(
VisitArrayTypeLoc(TL);
}
+void TypeLocWriter::VisitDependentAddressSpaceTypeLoc(
+ DependentAddressSpaceTypeLoc TL) {
+ Record.AddSourceLocation(TL.getAttrNameLoc());
+ SourceRange range = TL.getAttrOperandParensRange();
+ Record.AddSourceLocation(range.getBegin());
+ Record.AddSourceLocation(range.getEnd());
+ Record.AddStmt(TL.getAttrExprOperand());
+}
+
void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc(
DependentSizedExtVectorTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
@@ -836,6 +858,7 @@ void ASTWriter::WriteTypeAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // RegParm
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // CC
Abv->Add(BitCodeAbbrevOp(0)); // ProducesResult
+ Abv->Add(BitCodeAbbrevOp(0)); // NoCallerSavedRegs
// FunctionProtoType
Abv->Add(BitCodeAbbrevOp(0)); // IsVariadic
Abv->Add(BitCodeAbbrevOp(0)); // HasTrailingReturn
@@ -1088,6 +1111,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES);
RECORD(DELETE_EXPRS_TO_ANALYZE);
RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH);
+ RECORD(PP_CONDITIONAL_STACK);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -1124,6 +1148,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(SUBMODULE_TEXTUAL_HEADER);
RECORD(SUBMODULE_PRIVATE_TEXTUAL_HEADER);
RECORD(SUBMODULE_INITIALIZERS);
+ RECORD(SUBMODULE_EXPORT_AS);
// Comments Block.
BLOCK(COMMENTS_BLOCK);
@@ -1416,8 +1441,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
}
- if (WritingModule) {
+ if (WritingModule) {
// Module name
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
@@ -1456,13 +1481,14 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
}
// Module map file
- if (WritingModule) {
+ if (WritingModule && WritingModule->Kind == Module::ModuleMapModule) {
Record.clear();
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
-
- // Primary module map file.
- AddPath(Map.getModuleMapFileForUniquing(WritingModule)->getName(), Record);
+ AddPath(WritingModule->PresumedModuleMapFile.empty()
+ ? Map.getModuleMapFileForUniquing(WritingModule)->getName()
+ : StringRef(WritingModule->PresumedModuleMapFile),
+ Record);
// Additional module map files.
if (auto *AdditionalModMaps =
@@ -1498,6 +1524,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
for (auto I : M.Signature)
Record.push_back(I);
+ AddString(M.ModuleName, Record);
AddPath(M.FileName, Record);
}
Stream.EmitRecord(IMPORTS, Record);
@@ -1594,6 +1621,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
AddString(HSOpts.ModuleCachePath, Record);
AddString(HSOpts.ModuleUserBuildPath, Record);
Record.push_back(HSOpts.DisableModuleHash);
+ Record.push_back(HSOpts.ImplicitModuleMaps);
+ Record.push_back(HSOpts.ModuleMapFileHomeIsCwd);
Record.push_back(HSOpts.UseBuiltinIncludes);
Record.push_back(HSOpts.UseStandardSystemIncludes);
Record.push_back(HSOpts.UseStandardCXXIncludes);
@@ -1683,6 +1712,7 @@ namespace {
bool IsSystemFile;
bool IsTransient;
bool BufferOverridden;
+ bool IsTopLevelModuleMap;
};
} // end anonymous namespace
@@ -1701,6 +1731,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Module map
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(IFAbbrev));
@@ -1715,7 +1746,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
// We only care about file entries that were not overridden.
if (!SLoc->isFile())
continue;
- const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ const SrcMgr::FileInfo &File = SLoc->getFile();
+ const SrcMgr::ContentCache *Cache = File.getContentCache();
if (!Cache->OrigEntry)
continue;
@@ -1724,6 +1756,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
Entry.IsSystemFile = Cache->IsSystemFile;
Entry.IsTransient = Cache->IsTransient;
Entry.BufferOverridden = Cache->BufferOverridden;
+ Entry.IsTopLevelModuleMap = isModuleMap(File.getFileCharacteristic()) &&
+ File.getIncludeLoc().isInvalid();
if (Cache->IsSystemFile)
SortedFiles.push_back(Entry);
else
@@ -1754,7 +1788,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
(uint64_t)Entry.File->getSize(),
(uint64_t)getTimestampForOutput(Entry.File),
Entry.BufferOverridden,
- Entry.IsTransient};
+ Entry.IsTransient,
+ Entry.IsTopLevelModuleMap};
EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
}
@@ -1789,7 +1824,7 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
// FileEntry fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID
@@ -1808,7 +1843,7 @@ static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob
return Stream.EmitAbbrev(std::move(Abbrev));
@@ -1849,24 +1884,31 @@ namespace {
// Trait used for the on-disk hash table of header search information.
class HeaderFileInfoTrait {
ASTWriter &Writer;
- const HeaderSearch &HS;
// Keep track of the framework names we've used during serialization.
SmallVector<char, 128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;
public:
- HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
- : Writer(Writer), HS(HS) { }
-
+ HeaderFileInfoTrait(ASTWriter &Writer) : Writer(Writer) {}
+
struct key_type {
- const FileEntry *FE;
StringRef Filename;
+ off_t Size;
+ time_t ModTime;
};
typedef const key_type &key_type_ref;
+
+ using UnresolvedModule =
+ llvm::PointerIntPair<Module *, 2, ModuleMap::ModuleHeaderRole>;
- typedef HeaderFileInfo data_type;
+ struct data_type {
+ const HeaderFileInfo &HFI;
+ ArrayRef<ModuleMap::KnownHeader> KnownHeaders;
+ UnresolvedModule Unresolved;
+ };
typedef const data_type &data_type_ref;
+
typedef unsigned hash_value_type;
typedef unsigned offset_type;
@@ -1874,8 +1916,7 @@ namespace {
// The hash is based only on size/time of the file, so that the reader can
// match even when symlinking or excess path elements ("foo/../", "../")
// change the form of the name. However, complete path is still the key.
- return llvm::hash_combine(key.FE->getSize(),
- Writer.getTimestampForOutput(key.FE));
+ return llvm::hash_combine(key.Size, key.ModTime);
}
std::pair<unsigned,unsigned>
@@ -1885,68 +1926,74 @@ namespace {
unsigned KeyLen = key.Filename.size() + 1 + 8 + 8;
LE.write<uint16_t>(KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
- for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE))
+ for (auto ModInfo : Data.KnownHeaders)
if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule()))
DataLen += 4;
+ if (Data.Unresolved.getPointer())
+ DataLen += 4;
LE.write<uint8_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
}
-
+
void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
- LE.write<uint64_t>(key.FE->getSize());
+ LE.write<uint64_t>(key.Size);
KeyLen -= 8;
- LE.write<uint64_t>(Writer.getTimestampForOutput(key.FE));
+ LE.write<uint64_t>(key.ModTime);
KeyLen -= 8;
Out.write(key.Filename.data(), KeyLen);
}
-
+
void EmitData(raw_ostream &Out, key_type_ref key,
data_type_ref Data, unsigned DataLen) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
uint64_t Start = Out.tell(); (void)Start;
- unsigned char Flags = (Data.isImport << 4)
- | (Data.isPragmaOnce << 3)
- | (Data.DirInfo << 1)
- | Data.IndexHeaderMapHeader;
+ unsigned char Flags = (Data.HFI.isImport << 5)
+ | (Data.HFI.isPragmaOnce << 4)
+ | (Data.HFI.DirInfo << 1)
+ | Data.HFI.IndexHeaderMapHeader;
LE.write<uint8_t>(Flags);
- LE.write<uint16_t>(Data.NumIncludes);
+ LE.write<uint16_t>(Data.HFI.NumIncludes);
- if (!Data.ControllingMacro)
- LE.write<uint32_t>(Data.ControllingMacroID);
+ if (!Data.HFI.ControllingMacro)
+ LE.write<uint32_t>(Data.HFI.ControllingMacroID);
else
- LE.write<uint32_t>(Writer.getIdentifierRef(Data.ControllingMacro));
-
+ LE.write<uint32_t>(Writer.getIdentifierRef(Data.HFI.ControllingMacro));
+
unsigned Offset = 0;
- if (!Data.Framework.empty()) {
+ if (!Data.HFI.Framework.empty()) {
// If this header refers into a framework, save the framework name.
llvm::StringMap<unsigned>::iterator Pos
- = FrameworkNameOffset.find(Data.Framework);
+ = FrameworkNameOffset.find(Data.HFI.Framework);
if (Pos == FrameworkNameOffset.end()) {
Offset = FrameworkStringData.size() + 1;
- FrameworkStringData.append(Data.Framework.begin(),
- Data.Framework.end());
+ FrameworkStringData.append(Data.HFI.Framework.begin(),
+ Data.HFI.Framework.end());
FrameworkStringData.push_back(0);
- FrameworkNameOffset[Data.Framework] = Offset;
+ FrameworkNameOffset[Data.HFI.Framework] = Offset;
} else
Offset = Pos->second;
}
LE.write<uint32_t>(Offset);
- // FIXME: If the header is excluded, we should write out some
- // record of that fact.
- for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE)) {
- if (uint32_t ModID =
- Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) {
- uint32_t Value = (ModID << 2) | (unsigned)ModInfo.getRole();
+ auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) {
+ if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) {
+ uint32_t Value = (ModID << 2) | (unsigned)Role;
assert((Value >> 2) == ModID && "overflow in header module info");
LE.write<uint32_t>(Value);
}
- }
+ };
+
+ // FIXME: If the header is excluded, we should write out some
+ // record of that fact.
+ for (auto ModInfo : Data.KnownHeaders)
+ EmitModule(ModInfo.getModule(), ModInfo.getRole());
+ if (Data.Unresolved.getPointer())
+ EmitModule(Data.Unresolved.getPointer(), Data.Unresolved.getInt());
assert(Out.tell() - Start == DataLen && "Wrong data length");
}
@@ -1961,16 +2008,72 @@ namespace {
///
/// \param HS The header search structure to save.
void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
+ HeaderFileInfoTrait GeneratorTrait(*this);
+ llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
+ SmallVector<const char *, 4> SavedStrings;
+ unsigned NumHeaderSearchEntries = 0;
+
+ // Find all unresolved headers for the current module. We generally will
+ // have resolved them before we get here, but not necessarily: we might be
+ // compiling a preprocessed module, where there is no requirement for the
+ // original files to exist any more.
+ const HeaderFileInfo Empty; // So we can take a reference.
+ if (WritingModule) {
+ llvm::SmallVector<Module *, 16> Worklist(1, WritingModule);
+ while (!Worklist.empty()) {
+ Module *M = Worklist.pop_back_val();
+ if (!M->isAvailable())
+ continue;
+
+ // Map to disk files where possible, to pick up any missing stat
+ // information. This also means we don't need to check the unresolved
+ // headers list when emitting resolved headers in the first loop below.
+ // FIXME: It'd be preferable to avoid doing this if we were given
+ // sufficient stat information in the module map.
+ HS.getModuleMap().resolveHeaderDirectives(M);
+
+ // If the file didn't exist, we can still create a module if we were given
+ // enough information in the module map.
+ for (auto U : M->MissingHeaders) {
+ // Check that we were given enough information to build a module
+ // without this file existing on disk.
+ if (!U.Size || (!U.ModTime && IncludeTimestamps)) {
+ PP->Diag(U.FileNameLoc, diag::err_module_no_size_mtime_for_header)
+ << WritingModule->getFullModuleName() << U.Size.hasValue()
+ << U.FileName;
+ continue;
+ }
+
+ // Form the effective relative pathname for the file.
+ SmallString<128> Filename(M->Directory->getName());
+ llvm::sys::path::append(Filename, U.FileName);
+ PreparePathForOutput(Filename);
+
+ StringRef FilenameDup = strdup(Filename.c_str());
+ SavedStrings.push_back(FilenameDup.data());
+
+ HeaderFileInfoTrait::key_type Key = {
+ FilenameDup, *U.Size, IncludeTimestamps ? *U.ModTime : 0
+ };
+ HeaderFileInfoTrait::data_type Data = {
+ Empty, {}, {M, ModuleMap::headerKindToRole(U.Kind)}
+ };
+ // FIXME: Deal with cases where there are multiple unresolved header
+ // directives in different submodules for the same header.
+ Generator.insert(Key, Data, GeneratorTrait);
+ ++NumHeaderSearchEntries;
+ }
+
+ Worklist.append(M->submodule_begin(), M->submodule_end());
+ }
+ }
+
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
if (FilesByUID.size() > HS.header_file_size())
FilesByUID.resize(HS.header_file_size());
-
- HeaderFileInfoTrait GeneratorTrait(*this, HS);
- llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
- SmallVector<const char *, 4> SavedStrings;
- unsigned NumHeaderSearchEntries = 0;
+
for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
const FileEntry *File = FilesByUID[UID];
if (!File)
@@ -1997,11 +2100,16 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
SavedStrings.push_back(Filename.data());
}
- HeaderFileInfoTrait::key_type key = { File, Filename };
- Generator.insert(key, *HFI, GeneratorTrait);
+ HeaderFileInfoTrait::key_type Key = {
+ Filename, File->getSize(), getTimestampForOutput(File)
+ };
+ HeaderFileInfoTrait::data_type Data = {
+ *HFI, HS.getModuleMap().findAllModulesForHeader(File), {}
+ };
+ Generator.insert(Key, Data, GeneratorTrait);
++NumHeaderSearchEntries;
}
-
+
// Create the on-disk hash table in a buffer.
SmallString<4096> TableData;
uint32_t BucketOffset;
@@ -2297,6 +2405,18 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
Stream.EmitRecord(PP_COUNTER_VALUE, Record);
}
+ if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) {
+ assert(!IsModule);
+ for (const auto &Cond : PP.getPreambleConditionalStack()) {
+ AddSourceLocation(Cond.IfLoc, Record);
+ Record.push_back(Cond.WasSkipping);
+ Record.push_back(Cond.FoundNonSkip);
+ Record.push_back(Cond.FoundElse);
+ }
+ Stream.EmitRecord(PP_CONDITIONAL_STACK, Record);
+ Record.clear();
+ }
+
// Enter the preprocessor block.
Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
@@ -2408,7 +2528,6 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
}
AddIdentifierRef(Name, Record);
- Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
AddSourceLocation(MI->getDefinitionLoc(), Record);
AddSourceLocation(MI->getDefinitionEndLoc(), Record);
Record.push_back(MI->isUsed());
@@ -2422,9 +2541,9 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
Record.push_back(MI->isC99Varargs());
Record.push_back(MI->isGNUVarargs());
Record.push_back(MI->hasCommaPasting());
- Record.push_back(MI->getNumArgs());
- for (const IdentifierInfo *Arg : MI->args())
- AddIdentifierRef(Arg, Record);
+ Record.push_back(MI->getNumParams());
+ for (const IdentifierInfo *Param : MI->params())
+ AddIdentifierRef(Param, Record);
}
// If we have a detailed preprocessing record, record the macro definition
@@ -2616,6 +2735,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Kind
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
@@ -2624,7 +2744,6 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // WithCodegen
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
@@ -2691,10 +2810,15 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message
unsigned ConflictAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
+ Abbrev = std::make_shared<BitCodeAbbrev>();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXPORT_AS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
+ unsigned ExportAsAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
+
// Write the submodule metadata block.
- RecordData::value_type Record[] = {getNumberOfModules(WritingModule),
- FirstSubmoduleID -
- NUM_PREDEF_SUBMODULE_IDS};
+ RecordData::value_type Record[] = {
+ getNumberOfModules(WritingModule),
+ FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS};
Stream.EmitRecord(SUBMODULE_METADATA, Record);
// Write all of the submodules.
@@ -2716,6 +2840,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
RecordData::value_type Record[] = {SUBMODULE_DEFINITION,
ID,
ParentID,
+ (RecordData::value_type)Mod->Kind,
Mod->IsFramework,
Mod->IsExplicit,
Mod->IsSystem,
@@ -2723,8 +2848,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Mod->InferSubmodules,
Mod->InferExplicitSubmodules,
Mod->InferExportWildcard,
- Mod->ConfigMacrosExhaustive,
- Context->getLangOpts().ModularCodegen && WritingModule};
+ Mod->ConfigMacrosExhaustive};
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
}
@@ -2825,6 +2949,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
if (!Inits.empty())
Stream.EmitRecord(SUBMODULE_INITIALIZERS, Inits);
+ // Emit the name of the re-exported module, if any.
+ if (!Mod->ExportAsModule.empty()) {
+ RecordData::value_type Record[] = {SUBMODULE_EXPORT_AS};
+ Stream.EmitRecordWithBlob(ExportAsAbbrev, Record, Mod->ExportAsModule);
+ }
+
// Queue up the submodules of this module.
for (auto *M : Mod->submodules())
Q.push(M);
@@ -2838,25 +2968,6 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
"non-imported submodule?");
}
-serialization::SubmoduleID
-ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
- if (Loc.isInvalid() || !WritingModule)
- return 0; // No submodule
-
- // Find the module that owns this location.
- ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
- Module *OwningMod
- = ModMap.inferModuleFromLocation(FullSourceLoc(Loc,PP->getSourceManager()));
- if (!OwningMod)
- return 0;
-
- // Check whether this submodule is part of our own module.
- if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule))
- return 0;
-
- return getSubmoduleID(OwningMod);
-}
-
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
bool isModule) {
llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
@@ -2864,32 +2975,60 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
unsigned CurrID = 0;
RecordData Record;
+ auto EncodeDiagStateFlags =
+ [](const DiagnosticsEngine::DiagState *DS) -> unsigned {
+ unsigned Result = (unsigned)DS->ExtBehavior;
+ for (unsigned Val :
+ {(unsigned)DS->IgnoreAllWarnings, (unsigned)DS->EnableAllWarnings,
+ (unsigned)DS->WarningsAsErrors, (unsigned)DS->ErrorsAsFatal,
+ (unsigned)DS->SuppressSystemWarnings})
+ Result = (Result << 1) | Val;
+ return Result;
+ };
+
+ unsigned Flags = EncodeDiagStateFlags(Diag.DiagStatesByLoc.FirstDiagState);
+ Record.push_back(Flags);
+
auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State,
bool IncludeNonPragmaStates) {
+ // Ensure that the diagnostic state wasn't modified since it was created.
+ // We will not correctly round-trip this information otherwise.
+ assert(Flags == EncodeDiagStateFlags(State) &&
+ "diag state flags vary in single AST file");
+
unsigned &DiagStateID = DiagStateIDMap[State];
Record.push_back(DiagStateID);
if (DiagStateID == 0) {
DiagStateID = ++CurrID;
+
+ // Add a placeholder for the number of mappings.
+ auto SizeIdx = Record.size();
+ Record.emplace_back();
for (const auto &I : *State) {
if (I.second.isPragma() || IncludeNonPragmaStates) {
Record.push_back(I.first);
- Record.push_back((unsigned)I.second.getSeverity());
+ Record.push_back(I.second.serialize());
}
}
- // Add a sentinel to mark the end of the diag IDs.
- Record.push_back(unsigned(-1));
+ // Update the placeholder.
+ Record[SizeIdx] = (Record.size() - SizeIdx) / 2;
}
};
AddDiagState(Diag.DiagStatesByLoc.FirstDiagState, isModule);
- AddSourceLocation(Diag.DiagStatesByLoc.CurDiagStateLoc, Record);
- AddDiagState(Diag.DiagStatesByLoc.CurDiagState, false);
+ // 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());
@@ -2899,8 +3038,19 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
}
}
- 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);
}
//===----------------------------------------------------------------------===//
@@ -4008,7 +4158,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);
}
@@ -4163,6 +4313,26 @@ 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);
+ AddSourceLocation(StackEntry.PragmaPushLocation, Record);
+ AddString(StackEntry.StackSlotLabel, Record);
+ }
+ Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);
+}
+
void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer) {
// Enter the extension block.
@@ -4300,10 +4470,11 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream,
- SmallVectorImpl<char> &Buffer,
+ SmallVectorImpl<char> &Buffer, MemoryBufferCache &PCMCache,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool IncludeTimestamps)
- : Stream(Stream), Buffer(Buffer), 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));
@@ -4350,6 +4521,12 @@ ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef,
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;
}
@@ -4634,7 +4811,8 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
// each of those modules were mapped into our own offset/ID space, so that
// the reader can build the appropriate mapping to its own offset/ID space.
// The map consists solely of a blob with the following format:
- // *(module-name-len:i16 module-name:len*i8
+ // *(module-kind:i8
+ // module-name-len:i16 module-name:len*i8
// source-location-offset:i32
// identifier-id:i32
// preprocessed-entity-id:i32
@@ -4645,6 +4823,10 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
// c++-base-specifiers-id:i32
// type-id:i32)
//
+ // module-kind is the ModuleKind enum value. If it is MK_PrebuiltModule or
+ // MK_ExplicitModule, then the module-name is the module name. Otherwise,
+ // it is the module file name.
+ //
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
@@ -4655,9 +4837,13 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
for (ModuleFile &M : Chain->ModuleMgr) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
- StringRef FileName = M.FileName;
- LE.write<uint16_t>(FileName.size());
- Out.write(FileName.data(), FileName.size());
+ LE.write<uint8_t>(static_cast<uint8_t>(M.Kind));
+ StringRef Name =
+ M.Kind == MK_PrebuiltModule || M.Kind == MK_ExplicitModule
+ ? M.ModuleName
+ : M.FileName;
+ LE.write<uint16_t>(Name.size());
+ Out.write(Name.data(), Name.size());
// Note: if a base ID was uint max, it would not be possible to load
// another module after it or have more than one entity inside it.
@@ -4740,7 +4926,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
if (!EagerlyDeserializedDecls.empty())
Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls);
- if (Context.getLangOpts().ModularCodegen)
+ if (!ModularCodegenDecls.empty())
Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls);
// Write the record containing tentative definitions.
@@ -4846,6 +5032,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
WriteMSStructPragmaOptions(SemaRef);
WriteMSPointersToMembersPragmaOptions(SemaRef);
}
+ WritePackPragmaOptions(SemaRef);
// Some simple statistics
RecordData::value_type Record[] = {
@@ -4894,9 +5081,20 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
break;
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
+ const VarDecl *VD = cast<VarDecl>(D);
Record.AddSourceLocation(Update.getLoc());
+ Record.push_back(VD->isInline());
+ Record.push_back(VD->isInlineSpecified());
+ if (VD->getInit()) {
+ Record.push_back(!VD->isInitKnownICE() ? 1
+ : (VD->isInitICE() ? 3 : 2));
+ Record.AddStmt(const_cast<Expr*>(VD->getInit()));
+ } else {
+ Record.push_back(0);
+ }
break;
+ }
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT:
Record.AddStmt(const_cast<Expr *>(
@@ -4955,6 +5153,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
case UPD_CXX_RESOLVED_DTOR_DELETE:
Record.AddDeclRef(Update.getDecl());
+ Record.AddStmt(cast<CXXDestructorDecl>(D)->getOperatorDeleteThisArg());
break;
case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
@@ -5720,9 +5919,11 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
Record->push_back(Data.HasUninitializedFields);
Record->push_back(Data.HasInheritedConstructor);
Record->push_back(Data.HasInheritedAssignment);
+ Record->push_back(Data.NeedOverloadResolutionForCopyConstructor);
Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);
Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);
Record->push_back(Data.NeedOverloadResolutionForDestructor);
+ Record->push_back(Data.DefaultedCopyConstructorIsDeleted);
Record->push_back(Data.DefaultedMoveConstructorIsDeleted);
Record->push_back(Data.DefaultedMoveAssignmentIsDeleted);
Record->push_back(Data.DefaultedDestructorIsDeleted);
@@ -5731,6 +5932,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
Record->push_back(Data.HasIrrelevantDestructor);
Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
Record->push_back(Data.HasDefaultedDefaultConstructor);
+ Record->push_back(Data.CanPassInRegisters);
Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
Record->push_back(Data.HasConstexprDefaultConstructor);
Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);
@@ -5742,7 +5944,15 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
Record->push_back(Data.ImplicitCopyAssignmentHasConstParam);
Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
- Record->push_back(Data.ODRHash);
+
+ // 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);
@@ -5971,7 +6181,8 @@ void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
}
void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD,
- const FunctionDecl *Delete) {
+ const FunctionDecl *Delete,
+ Expr *ThisArg) {
if (Chain && Chain->isProcessingUpdateRecords()) return;
assert(!WritingAST && "Already writing the AST!");
assert(Delete && "Not given an operator delete");
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 190d3975b7..803795887c 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -299,7 +299,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->isTopLevelDeclInObjCContainer());
Record.push_back(D->getAccess());
Record.push_back(D->isModulePrivate());
- Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation()));
+ Record.push_back(Writer.getSubmoduleID(D->getOwningModule()));
// If this declaration injected a name into a context different from its
// lexical context, and that context is an imported namespace, we need to
@@ -612,6 +612,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
VisitFunctionDecl(D);
+ Record.push_back(D->isCopyDeductionCandidate());
Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
}
@@ -799,7 +800,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());
@@ -847,17 +850,16 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
VisitDeclaratorDecl(D);
Record.push_back(D->isMutable());
- if (D->InitStorage.getInt() == FieldDecl::ISK_BitWidthOrNothing &&
- D->InitStorage.getPointer() == nullptr) {
- Record.push_back(0);
- } else if (D->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) {
- Record.push_back(D->InitStorage.getInt() + 1);
- Record.AddTypeRef(
- QualType(static_cast<Type *>(D->InitStorage.getPointer()), 0));
- } else {
- Record.push_back(D->InitStorage.getInt() + 1);
- Record.AddStmt(static_cast<Expr *>(D->InitStorage.getPointer()));
- }
+
+ FieldDecl::InitStorageKind ISK = D->InitStorage.getInt();
+ Record.push_back(ISK);
+ if (ISK == FieldDecl::ISK_CapturedVLAType)
+ Record.AddTypeRef(QualType(D->getCapturedVLAType(), 0));
+ else if (ISK)
+ Record.AddStmt(D->getInClassInitializer());
+
+ Record.AddStmt(D->getBitWidth());
+
if (!D->getDeclName())
Record.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D));
@@ -871,6 +873,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
!D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasInClassInitializer() &&
+ !D->hasCapturedVLAType() &&
!D->hasExtInfo() &&
!ObjCIvarDecl::classofKind(D->getKind()) &&
!ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
@@ -913,6 +916,10 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isConstexpr());
Record.push_back(D->isInitCapture());
Record.push_back(D->isPreviousDeclInSameBlockScope());
+ if (const auto *IPD = dyn_cast<ImplicitParamDecl>(D))
+ Record.push_back(static_cast<unsigned>(IPD->getParameterKind()));
+ else
+ Record.push_back(0);
}
Record.push_back(D->getLinkageInternal());
@@ -922,6 +929,24 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
} else {
Record.push_back(0);
}
+
+ if (D->getStorageDuration() == SD_Static) {
+ bool ModulesCodegen = false;
+ if (Writer.WritingModule &&
+ !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() &&
+ !isa<VarTemplateSpecializationDecl>(D)) {
+ // When building a C++ Modules TS module interface unit, a strong
+ // definition in the module interface is provided by the compilation of
+ // that module interface unit, not by its users. (Inline variables are
+ // still emitted in module users.)
+ ModulesCodegen =
+ (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit &&
+ Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal);
+ }
+ Record.push_back(ModulesCodegen);
+ if (ModulesCodegen)
+ Writer.ModularCodegenDecls.push_back(Writer.GetDeclRef(D));
+ }
enum {
VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
@@ -957,6 +982,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isConstexpr() &&
!D->isInitCapture() &&
!D->isPreviousDeclInSameBlockScope() &&
+ D->getStorageDuration() != SD_Static &&
!D->getMemberSpecializationInfo())
AbbrevToUse = Writer.getDeclVarAbbrev();
@@ -1284,6 +1310,8 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
Record.AddDeclRef(D->getOperatorDelete());
+ if (D->getOperatorDelete())
+ Record.AddStmt(D->getOperatorDeleteThisArg());
Code = serialization::DECL_CXX_DESTRUCTOR;
}
@@ -1691,6 +1719,7 @@ void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
Record.AddSourceLocation(D->getLocStart());
Record.AddStmt(D->getCombiner());
Record.AddStmt(D->getInitializer());
+ Record.push_back(D->getInitializerKind());
Record.AddDeclRef(D->getPrevDeclInScope());
Code = serialization::DECL_OMP_DECLARE_REDUCTION;
}
@@ -1735,7 +1764,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// FieldDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
- Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ Abv->Add(BitCodeAbbrevOp(0)); // InitStyle
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
@@ -1768,7 +1797,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// FieldDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
- Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ Abv->Add(BitCodeAbbrevOp(0)); // InitStyle
// ObjC Ivar
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize
@@ -1987,6 +2016,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
+ Abv->Add(BitCodeAbbrevOp(0)); // ImplicitParamKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // IsInitICE (local)
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local enum)
@@ -2157,7 +2187,7 @@ void ASTWriter::WriteDeclAbbrevs() {
/// relatively painless since they would presumably only do it for top-level
/// decls.
static bool isRequiredDecl(const Decl *D, ASTContext &Context,
- bool WritingModule, bool ModularCode) {
+ bool WritingModule) {
// An ObjCMethodDecl is never considered as "required" because its
// implementation container always is.
@@ -2173,7 +2203,7 @@ static bool isRequiredDecl(const Decl *D, ASTContext &Context,
return false;
}
- return Context.DeclMustBeEmitted(D, ModularCode);
+ return Context.DeclMustBeEmitted(D);
}
void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
@@ -2217,11 +2247,8 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
// Note declarations that should be deserialized eagerly so that we can add
// them to a record in the AST file later.
- if (isRequiredDecl(D, Context, WritingModule, false))
+ if (isRequiredDecl(D, Context, WritingModule))
EagerlyDeserializedDecls.push_back(ID);
- else if (Context.getLangOpts().ModularCodegen && WritingModule &&
- isRequiredDecl(D, Context, true, true))
- ModularCodegenDecls.push_back(ID);
}
void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
@@ -2229,6 +2256,21 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
Writer->ClearSwitchCaseIDs();
assert(FD->doesThisDeclarationHaveABody());
+ bool ModulesCodegen = false;
+ if (Writer->WritingModule && !FD->isDependentContext()) {
+ // Under -fmodules-codegen, codegen is performed for all defined functions.
+ // When building a C++ Modules TS module interface unit, a strong definition
+ // in the module interface is provided by the compilation of that module
+ // interface unit, not by its users. (Inline functions are still emitted
+ // in module users.)
+ ModulesCodegen =
+ Writer->Context->getLangOpts().ModulesCodegen ||
+ (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit &&
+ Writer->Context->GetGVALinkageForFunction(FD) == GVA_StrongExternal);
+ }
+ Record->push_back(ModulesCodegen);
+ if (ModulesCodegen)
+ Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD));
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
Record->push_back(CD->getNumCtorInitializers());
if (CD->getNumCtorInitializers())
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index bade553425..15d2425713 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -286,7 +286,7 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
}
// Outputs
- for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
Record.AddStmt(S->getOutputExpr(I));
Record.AddString(S->getOutputConstraint(I));
}
@@ -300,29 +300,48 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
Code = serialization::STMT_MSASM;
}
-void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *CoroStmt) {
+ VisitStmt(CoroStmt);
+ Record.push_back(CoroStmt->getParamMoves().size());
+ for (Stmt *S : CoroStmt->children())
+ Record.AddStmt(S);
+ Code = serialization::STMT_COROUTINE_BODY;
}
void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+ VisitStmt(S);
+ Record.AddSourceLocation(S->getKeywordLoc());
+ Record.AddStmt(S->getOperand());
+ Record.AddStmt(S->getPromiseCall());
+ Record.push_back(S->isImplicit());
+ Code = serialization::STMT_CORETURN;
+}
+
+void ASTStmtWriter::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E) {
+ VisitExpr(E);
+ Record.AddSourceLocation(E->getKeywordLoc());
+ for (Stmt *S : E->children())
+ Record.AddStmt(S);
+ Record.AddStmt(E->getOpaqueValue());
}
-void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *E) {
+ VisitCoroutineSuspendExpr(E);
+ Record.push_back(E->isImplicit());
+ Code = serialization::EXPR_COAWAIT;
}
-void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *E) {
+ VisitCoroutineSuspendExpr(E);
+ Code = serialization::EXPR_COYIELD;
}
-void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
+ VisitExpr(E);
+ Record.AddSourceLocation(E->getKeywordLoc());
+ for (Stmt *S : E->children())
+ Record.AddStmt(S);
+ Code = serialization::EXPR_DEPENDENT_COAWAIT;
}
void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
@@ -650,7 +669,7 @@ void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
Record.AddStmt(E->getRHS());
Record.push_back(E->getOpcode()); // FIXME: stable encoding
Record.AddSourceLocation(E->getOperatorLoc());
- Record.push_back(E->isFPContractable());
+ Record.push_back(E->getFPFeatures().getInt());
Code = serialization::EXPR_BINARY_OPERATOR;
}
@@ -1218,7 +1237,7 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
Record.push_back(E->getOperator());
Record.AddSourceRange(E->Range);
- Record.push_back(E->isFPContractable());
+ Record.push_back(E->getFPFeatures().getInt());
Code = serialization::EXPR_CXX_OPERATOR_CALL;
}
@@ -1963,6 +1982,46 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
Record.AddStmt(E);
}
+void OMPClauseWriter::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) {
+ Record.push_back(C->varlist_size());
+ VisitOMPClauseWithPostUpdate(C);
+ Record.AddSourceLocation(C->getLParenLoc());
+ Record.AddSourceLocation(C->getColonLoc());
+ Record.AddNestedNameSpecifierLoc(C->getQualifierLoc());
+ Record.AddDeclarationNameInfo(C->getNameInfo());
+ for (auto *VE : C->varlists())
+ Record.AddStmt(VE);
+ for (auto *VE : C->privates())
+ Record.AddStmt(VE);
+ for (auto *E : C->lhs_exprs())
+ Record.AddStmt(E);
+ for (auto *E : C->rhs_exprs())
+ Record.AddStmt(E);
+ for (auto *E : C->reduction_ops())
+ Record.AddStmt(E);
+}
+
+void OMPClauseWriter::VisitOMPInReductionClause(OMPInReductionClause *C) {
+ Record.push_back(C->varlist_size());
+ VisitOMPClauseWithPostUpdate(C);
+ Record.AddSourceLocation(C->getLParenLoc());
+ Record.AddSourceLocation(C->getColonLoc());
+ Record.AddNestedNameSpecifierLoc(C->getQualifierLoc());
+ Record.AddDeclarationNameInfo(C->getNameInfo());
+ for (auto *VE : C->varlists())
+ Record.AddStmt(VE);
+ for (auto *VE : C->privates())
+ Record.AddStmt(VE);
+ for (auto *E : C->lhs_exprs())
+ Record.AddStmt(E);
+ for (auto *E : C->rhs_exprs())
+ Record.AddStmt(E);
+ for (auto *E : C->reduction_ops())
+ Record.AddStmt(E);
+ for (auto *E : C->taskgroup_descriptors())
+ Record.AddStmt(E);
+}
+
void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
Record.push_back(C->varlist_size());
VisitOMPClauseWithPostUpdate(C);
@@ -2043,6 +2102,7 @@ void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) {
}
void OMPClauseWriter::VisitOMPDeviceClause(OMPDeviceClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getDevice());
Record.AddSourceLocation(C->getLParenLoc());
}
@@ -2248,6 +2308,13 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
Record.AddStmt(D->getPrevUpperBoundVariable());
Record.AddStmt(D->getDistInc());
Record.AddStmt(D->getPrevEnsureUpperBound());
+ Record.AddStmt(D->getCombinedLowerBoundVariable());
+ Record.AddStmt(D->getCombinedUpperBoundVariable());
+ Record.AddStmt(D->getCombinedEnsureUpperBound());
+ Record.AddStmt(D->getCombinedInit());
+ Record.AddStmt(D->getCombinedCond());
+ Record.AddStmt(D->getCombinedNextLowerBound());
+ Record.AddStmt(D->getCombinedNextUpperBound());
}
for (auto I : D->counters()) {
Record.AddStmt(I);
@@ -2433,7 +2500,9 @@ void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
void ASTStmtWriter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) {
VisitStmt(D);
+ Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
+ Record.AddStmt(D->getReductionRef());
Code = serialization::STMT_OMP_TASKGROUP_DIRECTIVE;
}
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 141a5594ae..2e0076521f 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, Buffer->Data, 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 6978e7e097..20c114297b 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -619,6 +619,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
(uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
(uint32_t)Record[Idx++]}}};
+ // Skip the module name (currently this is only used for prebuilt
+ // modules while here we are only dealing with cached).
+ Idx += Record[Idx] + 1;
+
// Retrieve the imported file name.
unsigned Length = Record[Idx++];
SmallString<128> ImportedFile(Record.begin() + Idx,
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index f0654fc10b..75634401f6 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) const {
+ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const {
const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
/*cacheFailure=*/false);
if (Entry)
@@ -36,6 +37,14 @@ ModuleFile *ModuleManager::lookup(StringRef Name) const {
return nullptr;
}
+ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const {
+ if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
+ if (const FileEntry *File = Mod->getASTFile())
+ return lookup(File);
+
+ return nullptr;
+}
+
ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
auto Known = Modules.find(File);
if (Known == Modules.end())
@@ -137,7 +146,9 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// Load the contents of the module
if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
// The buffer was already provided for us.
- NewModule->Buffer = std::move(Buffer);
+ 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()));
@@ -158,7 +169,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return Missing;
}
- NewModule->Buffer = std::move(*Buf);
+ NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(*Buf));
}
// Initialize the stream.
@@ -167,8 +178,13 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// 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))
+ 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;
+ }
// We're keeping this module. Store it everywhere.
Module = Modules[Entry] = NewModule.get();
@@ -235,7 +251,12 @@ 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)
+ //
+ // 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);
}
@@ -292,9 +313,11 @@ void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
ModulesInCommonWithGlobalIndex.push_back(MF);
}
-ModuleManager::ModuleManager(FileManager &FileMgr,
- const PCHContainerReader &PCHContainerRdr)
- : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr), GlobalIndex(),
+ModuleManager::ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache,
+ const PCHContainerReader &PCHContainerRdr,
+ const HeaderSearch& HeaderSearchInfo)
+ : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr),
+ HeaderSearchInfo (HeaderSearchInfo), GlobalIndex(),
FirstVisitState(nullptr) {}
ModuleManager::~ModuleManager() { delete FirstVisitState; }
diff --git a/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
index e6592a285e..90d5c0e36a 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/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 1ea85d60c9..371187747f 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -233,19 +233,16 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (StringSelectors.empty()) {
ASTContext &Ctx = C.getASTContext();
Selector Sels[] = {
- getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
- getKeywordSelector(Ctx, "compare", nullptr),
- getKeywordSelector(Ctx, "compare", "options", nullptr),
- getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
- getKeywordSelector(Ctx, "compare", "options", "range", "locale",
- nullptr),
- getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
- nullptr),
- getKeywordSelector(Ctx, "initWithFormat",
- nullptr),
- getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
- getKeywordSelector(Ctx, "localizedCompare", nullptr),
- getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
+ getKeywordSelector(Ctx, "caseInsensitiveCompare"),
+ getKeywordSelector(Ctx, "compare"),
+ getKeywordSelector(Ctx, "compare", "options"),
+ getKeywordSelector(Ctx, "compare", "options", "range"),
+ getKeywordSelector(Ctx, "compare", "options", "range", "locale"),
+ getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet"),
+ getKeywordSelector(Ctx, "initWithFormat"),
+ getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare"),
+ getKeywordSelector(Ctx, "localizedCompare"),
+ getKeywordSelector(Ctx, "localizedStandardCompare"),
};
for (Selector KnownSel : Sels)
StringSelectors[KnownSel] = 0;
@@ -262,16 +259,15 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (ArrayWithObjectSel.isNull()) {
ASTContext &Ctx = C.getASTContext();
- ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
- AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
+ ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject");
+ AddObjectSel = getKeywordSelector(Ctx, "addObject");
InsertObjectAtIndexSel =
- getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
+ getKeywordSelector(Ctx, "insertObject", "atIndex");
ReplaceObjectAtIndexWithObjectSel =
- getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
+ getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject");
SetObjectAtIndexedSubscriptSel =
- getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
- ArrayByAddingObjectSel =
- getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
+ getKeywordSelector(Ctx, "setObject", "atIndexedSubscript");
+ ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
}
if (S == ArrayWithObjectSel || S == AddObjectSel ||
@@ -292,13 +288,11 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (DictionaryWithObjectForKeySel.isNull()) {
ASTContext &Ctx = C.getASTContext();
DictionaryWithObjectForKeySel =
- getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
- SetObjectForKeySel =
- getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
+ getKeywordSelector(Ctx, "dictionaryWithObject", "forKey");
+ SetObjectForKeySel = getKeywordSelector(Ctx, "setObject", "forKey");
SetObjectForKeyedSubscriptSel =
- getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
- RemoveObjectForKeySel =
- getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
+ getKeywordSelector(Ctx, "setObject", "forKeyedSubscript");
+ RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
}
if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
diff --git a/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index d19630eeef..c31f2794df 100644
--- a/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -26,15 +26,22 @@ using namespace ento;
namespace {
-class BlockInCriticalSectionChecker : public Checker<check::PostCall,
- check::PreCall> {
+class BlockInCriticalSectionChecker : public Checker<check::PostCall> {
+
+ mutable IdentifierInfo *IILockGuard, *IIUniqueLock;
CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn,
PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn,
MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock;
+ StringRef ClassLockGuard, ClassUniqueLock;
+
+ mutable bool IdentifierInfoInitialized;
+
std::unique_ptr<BugType> BlockInCritSectionBugType;
+ void initIdentifierInfo(ASTContext &Ctx) const;
+
void reportBlockInCritSection(SymbolRef FileDescSym,
const CallEvent &call,
CheckerContext &C) const;
@@ -46,13 +53,10 @@ public:
bool isLockFunction(const CallEvent &Call) const;
bool isUnlockFunction(const CallEvent &Call) const;
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
-
/// Process unlock.
/// Process lock.
/// Process blocking functions (sleep, getc, fgets, read, recv)
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
-
};
} // end anonymous namespace
@@ -60,7 +64,8 @@ public:
REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
- : LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
+ : IILockGuard(nullptr), IIUniqueLock(nullptr),
+ LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
PthreadLockFn("pthread_mutex_lock"),
PthreadTryLockFn("pthread_mutex_trylock"),
@@ -68,13 +73,29 @@ BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
MtxLock("mtx_lock"),
MtxTimedLock("mtx_timedlock"),
MtxTryLock("mtx_trylock"),
- MtxUnlock("mtx_unlock") {
+ MtxUnlock("mtx_unlock"),
+ ClassLockGuard("lock_guard"),
+ ClassUniqueLock("unique_lock"),
+ IdentifierInfoInitialized(false) {
// Initialize the bug type.
BlockInCritSectionBugType.reset(
new BugType(this, "Call to blocking function in critical section",
"Blocking Error"));
}
+void BlockInCriticalSectionChecker::initIdentifierInfo(ASTContext &Ctx) const {
+ if (!IdentifierInfoInitialized) {
+ /* In case of checking C code, or when the corresponding headers are not
+ * included, we might end up query the identifier table every time when this
+ * function is called instead of early returning it. To avoid this, a bool
+ * variable (IdentifierInfoInitialized) is used and the function will be run
+ * only once. */
+ IILockGuard = &Ctx.Idents.get(ClassLockGuard);
+ IIUniqueLock = &Ctx.Idents.get(ClassUniqueLock);
+ IdentifierInfoInitialized = true;
+ }
+}
+
bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const {
if (Call.isCalled(SleepFn)
|| Call.isCalled(GetcFn)
@@ -87,6 +108,12 @@ bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) co
}
bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const {
+ if (const auto *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
+ auto IdentifierInfo = Ctor->getDecl()->getParent()->getIdentifier();
+ if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock)
+ return true;
+ }
+
if (Call.isCalled(LockFn)
|| Call.isCalled(PthreadLockFn)
|| Call.isCalled(PthreadTryLockFn)
@@ -99,6 +126,13 @@ bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const
}
bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const {
+ if (const auto *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
+ const auto *DRecordDecl = dyn_cast<CXXRecordDecl>(Dtor->getDecl()->getParent());
+ auto IdentifierInfo = DRecordDecl->getIdentifier();
+ if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock)
+ return true;
+ }
+
if (Call.isCalled(UnlockFn)
|| Call.isCalled(PthreadUnlockFn)
|| Call.isCalled(MtxUnlock)) {
@@ -107,12 +141,10 @@ bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) cons
return false;
}
-void BlockInCriticalSectionChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
-}
-
void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
+ initIdentifierInfo(C.getASTContext());
+
if (!isBlockingFunction(Call)
&& !isLockFunction(Call)
&& !isUnlockFunction(Call))
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 8c2aef21b3..097d419880 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -41,6 +41,24 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
default:
return false;
+ case Builtin::BI__builtin_assume: {
+ assert (CE->arg_begin() != CE->arg_end());
+ SVal ArgSVal = state->getSVal(CE->getArg(0), LCtx);
+ if (ArgSVal.isUndef())
+ return true; // Return true to model purity.
+
+ state = state->assume(ArgSVal.castAs<DefinedOrUnknownSVal>(), true);
+ // FIXME: do we want to warn here? Not right now. The most reports might
+ // come from infeasible paths, thus being false positives.
+ if (!state) {
+ C.generateSink(C.getState(), C.getPredecessor());
+ return true;
+ }
+
+ C.addTransition(state);
+ return true;
+ }
+
case Builtin::BI__builtin_unpredictable:
case Builtin::BI__builtin_expect:
case Builtin::BI__builtin_assume_aligned:
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 05505ec386..7ab9c6114e 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -29,6 +29,7 @@ add_clang_library(clangStaticAnalyzerCheckers
CXXSelfAssignmentChecker.cpp
DeadStoresChecker.cpp
DebugCheckers.cpp
+ DeleteWithNonVirtualDtorChecker.cpp
DereferenceChecker.cpp
DirectIvarAssignment.cpp
DivZeroChecker.cpp
@@ -39,7 +40,7 @@ add_clang_library(clangStaticAnalyzerCheckers
GenericTaintChecker.cpp
GTestChecker.cpp
IdenticalExprChecker.cpp
- IteratorPastEndChecker.cpp
+ IteratorChecker.cpp
IvarInvalidationChecker.cpp
LLVMConventionsChecker.cpp
LocalizationChecker.cpp
@@ -48,6 +49,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
@@ -55,6 +57,7 @@ add_clang_library(clangStaticAnalyzerCheckers
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
NonNullParamChecker.cpp
+ NonnullGlobalConstantsChecker.cpp
NullabilityChecker.cpp
NumberObjectConversionChecker.cpp
ObjCAtSyncChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 32e3ce9270..58218df238 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -120,6 +120,7 @@ public:
void evalStdCopy(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemset(CheckerContext &C, const CallExpr *CE) const;
// Utility methods
std::pair<ProgramStateRef , ProgramStateRef >
@@ -1049,31 +1050,22 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// If this is mempcpy, get the byte after the last byte copied and
// bind the expr.
if (IsMempcpy) {
- loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>();
-
- // Get the length to copy.
- if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) {
- // Get the byte after the last byte copied.
- SValBuilder &SvalBuilder = C.getSValBuilder();
- ASTContext &Ctx = SvalBuilder.getContext();
- QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
- loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal,
- CharPtrTy, Dest->getType()).castAs<loc::MemRegionVal>();
- SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
- DestRegCharVal,
- *lenValNonLoc,
- Dest->getType());
-
- // The byte after the last byte copied is the return value.
- state = state->BindExpr(CE, LCtx, lastElement);
- } else {
- // If we don't know how much we copied, we can at least
- // conjure a return value for later.
- SVal result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
+ // Get the byte after the last byte copied.
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ ASTContext &Ctx = SvalBuilder.getContext();
+ QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+ SVal DestRegCharVal =
+ SvalBuilder.evalCast(destVal, CharPtrTy, Dest->getType());
+ SVal lastElement = C.getSValBuilder().evalBinOp(
+ state, BO_Add, DestRegCharVal, sizeVal, Dest->getType());
+ // If we don't know how much we copied, we can at least
+ // conjure a return value for later.
+ if (lastElement.isUnknown())
+ lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
C.blockCount());
- state = state->BindExpr(CE, LCtx, result);
- }
+ // The byte after the last byte copied is the return value.
+ state = state->BindExpr(CE, LCtx, lastElement);
} else {
// All other copies return the destination buffer.
// (Well, bcopy() has a void return type, but this won't hurt.)
@@ -1999,6 +1991,54 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
C.addTransition(State);
}
+void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() != 3)
+ return;
+
+ CurrentFunctionDescription = "memory set function";
+
+ const Expr *Mem = CE->getArg(0);
+ const Expr *Size = CE->getArg(2);
+ ProgramStateRef State = C.getState();
+
+ // See if the size argument is zero.
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal SizeVal = State->getSVal(Size, LCtx);
+ QualType SizeTy = Size->getType();
+
+ ProgramStateRef StateZeroSize, StateNonZeroSize;
+ std::tie(StateZeroSize, StateNonZeroSize) =
+ assumeZero(C, State, SizeVal, SizeTy);
+
+ // Get the value of the memory area.
+ SVal MemVal = State->getSVal(Mem, LCtx);
+
+ // If the size is zero, there won't be any actual memory access, so
+ // just bind the return value to the Mem buffer and return.
+ if (StateZeroSize && !StateNonZeroSize) {
+ StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal);
+ C.addTransition(StateZeroSize);
+ return;
+ }
+
+ // Ensure the memory area is not null.
+ // If it is NULL there will be a NULL pointer dereference.
+ State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+ if (!State)
+ return;
+
+ State = CheckBufferAccess(C, State, Size, Mem);
+ if (!State)
+ return;
+ State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem),
+ /*IsSourceBuffer*/false, Size);
+ if (!State)
+ return;
+
+ State = State->BindExpr(CE, LCtx, MemVal);
+ C.addTransition(State);
+}
+
static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) {
IdentifierInfo *II = FD->getIdentifier();
if (!II)
@@ -2032,6 +2072,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
evalFunction = &CStringChecker::evalMemcmp;
else if (C.isCLibraryFunction(FDecl, "memmove"))
evalFunction = &CStringChecker::evalMemmove;
+ else if (C.isCLibraryFunction(FDecl, "memset"))
+ evalFunction = &CStringChecker::evalMemset;
else if (C.isCLibraryFunction(FDecl, "strcpy"))
evalFunction = &CStringChecker::evalStrcpy;
else if (C.isCLibraryFunction(FDecl, "strncpy"))
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index 391b843ff3..4b5e97b692 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -16,7 +16,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 60f16188bc..6dbacad7f2 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -13,7 +13,7 @@
#include "ClangSACheckers.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -32,7 +32,6 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) {
T.getOS() == llvm::Triple::FreeBSD ||
T.getOS() == llvm::Triple::NetBSD ||
T.getOS() == llvm::Triple::OpenBSD ||
- T.getOS() == llvm::Triple::Bitrig ||
T.getOS() == llvm::Triple::DragonFly;
}
diff --git a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
index 6fa5732d10..ee517ed977 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
@@ -63,7 +64,7 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
// the CloneDetector. The only thing left to do is to report the found clones.
int MinComplexity = Mgr.getAnalyzerOptions().getOptionAsInteger(
- "MinimumCloneComplexity", 10, this);
+ "MinimumCloneComplexity", 50, this);
assert(MinComplexity >= 0);
bool ReportSuspiciousClones = Mgr.getAnalyzerOptions().getBooleanOption(
@@ -72,11 +73,35 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
bool ReportNormalClones = Mgr.getAnalyzerOptions().getBooleanOption(
"ReportNormalClones", true, this);
+ StringRef IgnoredFilesPattern = Mgr.getAnalyzerOptions().getOptionAsString(
+ "IgnoredFilesPattern", "", this);
+
+ // Let the CloneDetector create a list of clones from all the analyzed
+ // statements. We don't filter for matching variable patterns at this point
+ // because reportSuspiciousClones() wants to search them for errors.
+ std::vector<CloneDetector::CloneGroup> AllCloneGroups;
+
+ Detector.findClones(
+ AllCloneGroups, FilenamePatternConstraint(IgnoredFilesPattern),
+ RecursiveCloneTypeIIHashConstraint(), MinGroupSizeConstraint(2),
+ MinComplexityConstraint(MinComplexity),
+ RecursiveCloneTypeIIVerifyConstraint(), OnlyLargestCloneConstraint());
+
if (ReportSuspiciousClones)
- reportSuspiciousClones(BR, Mgr, MinComplexity);
+ reportSuspiciousClones(BR, Mgr, AllCloneGroups);
+
+ // We are done for this translation unit unless we also need to report normal
+ // clones.
+ if (!ReportNormalClones)
+ return;
+
+ // Now that the suspicious clone detector has checked for pattern errors,
+ // we also filter all clones who don't have matching patterns
+ CloneDetector::constrainClones(AllCloneGroups,
+ MatchingVariablePatternConstraint(),
+ MinGroupSizeConstraint(2));
- if (ReportNormalClones)
- reportClones(BR, Mgr, MinComplexity);
+ reportClones(BR, Mgr, AllCloneGroups);
}
static PathDiagnosticLocation makeLocation(const StmtSequence &S,
@@ -87,37 +112,55 @@ static PathDiagnosticLocation makeLocation(const StmtSequence &S,
Mgr.getAnalysisDeclContext(ACtx.getTranslationUnitDecl()));
}
-void CloneChecker::reportClones(BugReporter &BR, AnalysisManager &Mgr,
- int MinComplexity) const {
-
- std::vector<CloneDetector::CloneGroup> CloneGroups;
- Detector.findClones(CloneGroups, MinComplexity);
+void CloneChecker::reportClones(
+ BugReporter &BR, AnalysisManager &Mgr,
+ std::vector<CloneDetector::CloneGroup> &CloneGroups) const {
if (!BT_Exact)
BT_Exact.reset(new BugType(this, "Exact code clone", "Code clone"));
- for (CloneDetector::CloneGroup &Group : CloneGroups) {
+ for (const CloneDetector::CloneGroup &Group : CloneGroups) {
// We group the clones by printing the first as a warning and all others
// as a note.
- auto R = llvm::make_unique<BugReport>(
- *BT_Exact, "Duplicate code detected",
- makeLocation(Group.Sequences.front(), Mgr));
- R->addRange(Group.Sequences.front().getSourceRange());
-
- for (unsigned i = 1; i < Group.Sequences.size(); ++i)
- R->addNote("Similar code here",
- makeLocation(Group.Sequences[i], Mgr),
- Group.Sequences[i].getSourceRange());
+ auto R = llvm::make_unique<BugReport>(*BT_Exact, "Duplicate code detected",
+ makeLocation(Group.front(), Mgr));
+ R->addRange(Group.front().getSourceRange());
+
+ for (unsigned i = 1; i < Group.size(); ++i)
+ R->addNote("Similar code here", makeLocation(Group[i], Mgr),
+ Group[i].getSourceRange());
BR.emitReport(std::move(R));
}
}
-void CloneChecker::reportSuspiciousClones(BugReporter &BR,
- AnalysisManager &Mgr,
- int MinComplexity) const {
-
- std::vector<CloneDetector::SuspiciousClonePair> Clones;
- Detector.findSuspiciousClones(Clones, MinComplexity);
+void CloneChecker::reportSuspiciousClones(
+ BugReporter &BR, AnalysisManager &Mgr,
+ std::vector<CloneDetector::CloneGroup> &CloneGroups) const {
+ std::vector<VariablePattern::SuspiciousClonePair> Pairs;
+
+ for (const CloneDetector::CloneGroup &Group : CloneGroups) {
+ for (unsigned i = 0; i < Group.size(); ++i) {
+ VariablePattern PatternA(Group[i]);
+
+ for (unsigned j = i + 1; j < Group.size(); ++j) {
+ VariablePattern PatternB(Group[j]);
+
+ VariablePattern::SuspiciousClonePair ClonePair;
+ // For now, we only report clones which break the variable pattern just
+ // once because multiple differences in a pattern are an indicator that
+ // those differences are maybe intended (e.g. because it's actually a
+ // different algorithm).
+ // FIXME: In very big clones even multiple variables can be unintended,
+ // so replacing this number with a percentage could better handle such
+ // cases. On the other hand it could increase the false-positive rate
+ // for all clones if the percentage is too high.
+ if (PatternA.countPatternDifferences(PatternB, &ClonePair) == 1) {
+ Pairs.push_back(ClonePair);
+ break;
+ }
+ }
+ }
+ }
if (!BT_Suspicious)
BT_Suspicious.reset(
@@ -128,7 +171,7 @@ void CloneChecker::reportSuspiciousClones(BugReporter &BR,
AnalysisDeclContext *ADC =
Mgr.getAnalysisDeclContext(ACtx.getTranslationUnitDecl());
- for (CloneDetector::SuspiciousClonePair &Pair : Clones) {
+ for (VariablePattern::SuspiciousClonePair &Pair : Pairs) {
// FIXME: We are ignoring the suggestions currently, because they are
// only 50% accurate (even if the second suggestion is unavailable),
// which may confuse the user.
diff --git a/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
index 2bb9e85873..17ec2c2887 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) {
@@ -108,83 +123,39 @@ void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
C.emitReport(std::move(R));
}
-// Is E value greater or equal than Val?
-static bool isGreaterEqual(CheckerContext &C, const Expr *E,
- unsigned long long Val) {
- ProgramStateRef State = C.getState();
- SVal EVal = C.getSVal(E);
- if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
- return false;
-
- SValBuilder &Bldr = C.getSValBuilder();
- DefinedSVal V = Bldr.makeIntVal(Val, C.getASTContext().LongLongTy);
-
- // Is DefinedEVal greater or equal with V?
- SVal GE = Bldr.evalBinOp(State, BO_GE, EVal, V, Bldr.getConditionType());
- if (GE.isUnknownOrUndef())
- return false;
- ConstraintManager &CM = C.getConstraintManager();
- ProgramStateRef StGE, StLT;
- std::tie(StGE, StLT) = CM.assumeDual(State, GE.castAs<DefinedSVal>());
- return StGE && !StLT;
-}
-
-// Is E value negative?
-static bool isNegative(CheckerContext &C, const Expr *E) {
- ProgramStateRef State = C.getState();
- SVal EVal = State->getSVal(E, C.getLocationContext());
- if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
- return false;
- DefinedSVal DefinedEVal = EVal.castAs<DefinedSVal>();
-
- SValBuilder &Bldr = C.getSValBuilder();
- DefinedSVal V = Bldr.makeIntVal(0, false);
-
- SVal LT =
- Bldr.evalBinOp(State, BO_LT, DefinedEVal, V, Bldr.getConditionType());
-
- // Is E value greater than MaxVal?
- ConstraintManager &CM = C.getConstraintManager();
- ProgramStateRef StNegative, StPositive;
- std::tie(StNegative, StPositive) =
- CM.assumeDual(State, LT.castAs<DefinedSVal>());
-
- return StNegative && !StPositive;
-}
-
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;
unsigned long long MaxVal = 1ULL << W;
- return isGreaterEqual(C, Cast->getSubExpr(), MaxVal);
+ return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
}
bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
- CheckerContext &C) const {
+ CheckerContext &C) const {
QualType CastType = Cast->getType();
QualType SubType = Cast->IgnoreParenImpCasts()->getType();
if (!CastType->isUnsignedIntegerType() || !SubType->isSignedIntegerType())
return false;
- return isNegative(C, Cast->getSubExpr());
+ return C.isNegative(Cast->getSubExpr());
}
void ento::registerConversionChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 8ca2a24cff..f7b5f61cfb 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -189,6 +189,7 @@ public:
case DeadIncrement:
BugType = "Dead increment";
+ LLVM_FALLTHROUGH;
case Standard:
if (!BugType) BugType = "Dead assignment";
os << "Value stored to '" << *V << "' is never read";
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 2eef1688d4..810a33ed40 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -16,7 +16,6 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CallGraph.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/IssueHash.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -213,35 +212,3 @@ void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
mgr.registerChecker<ExplodedGraphViewer>();
}
-//===----------------------------------------------------------------------===//
-// DumpBugHash
-//===----------------------------------------------------------------------===//
-
-namespace {
-class BugHashDumper : public Checker<check::PostStmt<Stmt>> {
-public:
- mutable std::unique_ptr<BugType> BT;
-
- void checkPostStmt(const Stmt *S, CheckerContext &C) const {
- if (!BT)
- BT.reset(new BugType(this, "Dump hash components", "debug"));
-
- ExplodedNode *N = C.generateNonFatalErrorNode();
- if (!N)
- return;
-
- const LangOptions &Opts = C.getLangOpts();
- const SourceManager &SM = C.getSourceManager();
- FullSourceLoc FL(S->getLocStart(), SM);
- std::string HashContent =
- GetIssueString(SM, FL, getCheckName().getName(), BT->getCategory(),
- C.getLocationContext()->getDecl(), Opts);
-
- C.emitReport(llvm::make_unique<BugReport>(*BT, HashContent, N));
- }
-};
-}
-
-void ento::registerBugHashDumper(CheckerManager &mgr) {
- mgr.registerChecker<BugHashDumper>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp b/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp
new file mode 100644
index 0000000000..e04e2ab2c3
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp
@@ -0,0 +1,153 @@
+//===-- DeleteWithNonVirtualDtorChecker.cpp -----------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for the OOP52-CPP CERT rule: Do not delete a polymorphic
+// object without a virtual destructor.
+//
+// Diagnostic flags -Wnon-virtual-dtor and -Wdelete-non-virtual-dtor report if
+// an object with a virtual function but a non-virtual destructor exists or is
+// deleted, respectively.
+//
+// This check exceeds them by comparing the dynamic and static types of the
+// object at the point of destruction and only warns if it happens through a
+// pointer to a base type without a virtual destructor. The check places a note
+// at the last point where the conversion from derived to base happened.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.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"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class DeleteWithNonVirtualDtorChecker
+ : public Checker<check::PreStmt<CXXDeleteExpr>> {
+ mutable std::unique_ptr<BugType> BT;
+
+ class DeleteBugVisitor : public BugReporterVisitorImpl<DeleteBugVisitor> {
+ public:
+ DeleteBugVisitor() : Satisfied(false) {}
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ static int X = 0;
+ ID.AddPointer(&X);
+ }
+ std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+
+ private:
+ bool Satisfied;
+ };
+
+public:
+ void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+void DeleteWithNonVirtualDtorChecker::checkPreStmt(const CXXDeleteExpr *DE,
+ CheckerContext &C) const {
+ const Expr *DeletedObj = DE->getArgument();
+ const MemRegion *MR = C.getSVal(DeletedObj).getAsRegion();
+ if (!MR)
+ return;
+
+ const auto *BaseClassRegion = MR->getAs<TypedValueRegion>();
+ const auto *DerivedClassRegion = MR->getBaseRegion()->getAs<SymbolicRegion>();
+ if (!BaseClassRegion || !DerivedClassRegion)
+ return;
+
+ const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl();
+ const auto *DerivedClass =
+ DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl();
+ if (!BaseClass || !DerivedClass)
+ return;
+
+ if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())
+ return;
+
+ if (BaseClass->getDestructor()->isVirtual())
+ return;
+
+ if (!DerivedClass->isDerivedFrom(BaseClass))
+ return;
+
+ if (!BT)
+ BT.reset(new BugType(this,
+ "Destruction of a polymorphic object with no "
+ "virtual destructor",
+ "Logic error"));
+
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
+
+ // Mark region of problematic base class for later use in the BugVisitor.
+ R->markInteresting(BaseClassRegion);
+ R->addVisitor(llvm::make_unique<DeleteBugVisitor>());
+ C.emitReport(std::move(R));
+}
+
+std::shared_ptr<PathDiagnosticPiece>
+DeleteWithNonVirtualDtorChecker::DeleteBugVisitor::VisitNode(
+ const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
+ BugReport &BR) {
+ // Stop traversal after the first conversion was found on a path.
+ if (Satisfied)
+ return nullptr;
+
+ ProgramStateRef State = N->getState();
+ const LocationContext *LC = N->getLocationContext();
+ const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ if (!S)
+ return nullptr;
+
+ const auto *CastE = dyn_cast<CastExpr>(S);
+ if (!CastE)
+ return nullptr;
+
+ // Only interested in DerivedToBase implicit casts.
+ // Explicit casts can have different CastKinds.
+ if (const auto *ImplCastE = dyn_cast<ImplicitCastExpr>(CastE)) {
+ if (ImplCastE->getCastKind() != CK_DerivedToBase)
+ return nullptr;
+ }
+
+ // Region associated with the current cast expression.
+ const MemRegion *M = State->getSVal(CastE, LC).getAsRegion();
+ if (!M)
+ return nullptr;
+
+ // Check if target region was marked as problematic previously.
+ if (!BR.isInteresting(M))
+ return nullptr;
+
+ // Stop traversal on this path.
+ Satisfied = true;
+
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream OS(Buf);
+ OS << "Conversion from derived to base happened here";
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
+ nullptr);
+}
+
+void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) {
+ mgr.registerChecker<DeleteWithNonVirtualDtorChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 32040e7116..0005ec470d 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -8,10 +8,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/IssueHash.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -41,6 +42,7 @@ class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols,
void analyzerExplain(const CallExpr *CE, CheckerContext &C) const;
void analyzerPrintState(const CallExpr *CE, CheckerContext &C) const;
void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerHashDump(const CallExpr *CE, CheckerContext &C) const;
typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
CheckerContext &C) const;
@@ -79,6 +81,7 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE,
&ExprInspectionChecker::analyzerPrintState)
.Case("clang_analyzer_numTimesReached",
&ExprInspectionChecker::analyzerNumTimesReached)
+ .Case("clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump)
.Default(nullptr);
if (!Handler)
@@ -272,6 +275,7 @@ void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
reportBug(llvm::to_string(NumTimesReached), BR, N);
}
+ ReachedStats.clear();
}
void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
@@ -279,7 +283,18 @@ void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
LLVM_BUILTIN_TRAP;
}
+void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE,
+ CheckerContext &C) const {
+ const LangOptions &Opts = C.getLangOpts();
+ const SourceManager &SM = C.getSourceManager();
+ FullSourceLoc FL(CE->getArg(0)->getLocStart(), SM);
+ std::string HashContent =
+ GetIssueString(SM, FL, getCheckName().getName(), "Category",
+ C.getLocationContext()->getDecl(), Opts);
+
+ reportBug(HashContent, C);
+}
+
void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
Mgr.registerChecker<ExprInspectionChecker>();
}
-
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index b1a54e7795..883c6a6632 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -65,21 +65,8 @@ 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);
+ /// \brief Given a pointer argument, return the value it points to.
+ static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg);
/// Functions defining the attack surface.
typedef ProgramStateRef (GenericTaintChecker::*FnCheck)(const CallExpr *,
@@ -186,9 +173,14 @@ private:
static inline bool isTaintedOrPointsToTainted(const Expr *E,
ProgramStateRef State,
CheckerContext &C) {
- return (State->isTainted(E, C.getLocationContext()) || isStdin(E, C) ||
- (E->getType().getTypePtr()->isPointerType() &&
- State->isTainted(getPointedToSymbol(C, E))));
+ if (State->isTainted(E, C.getLocationContext()) || isStdin(E, C))
+ return true;
+
+ if (!E->getType().getTypePtr()->isPointerType())
+ return false;
+
+ Optional<SVal> V = getPointedToSVal(C, E);
+ return (V && State->isTainted(*V));
}
/// \brief Pre-process a function which propagates taint according to the
@@ -400,9 +392,9 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
if (CE->getNumArgs() < (ArgNum + 1))
return false;
const Expr* Arg = CE->getArg(ArgNum);
- SymbolRef Sym = getPointedToSymbol(C, Arg);
- if (Sym)
- State = State->addTaint(Sym);
+ Optional<SVal> V = getPointedToSVal(C, Arg);
+ if (V)
+ State = State->addTaint(*V);
}
// Clear up the taint info from the state.
@@ -473,47 +465,20 @@ 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) {
+Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
+ const Expr* Arg) {
ProgramStateRef State = C.getState();
SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext());
if (AddrVal.isUnknownOrUndef())
- return nullptr;
+ return None;
Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
if (!AddrLoc)
- return nullptr;
+ return None;
const PointerType *ArgTy =
dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr());
- SVal Val = State->getSVal(*AddrLoc,
- ArgTy ? ArgTy->getPointeeType(): QualType());
-
- if (auto LCV = Val.getAs<nonloc::LazyCompoundVal>())
- return getLCVSymbol(C, *LCV);
-
- return Val.getAsSymbol();
+ return State->getSVal(*AddrLoc, ArgTy ? ArgTy->getPointeeType(): QualType());
}
ProgramStateRef
@@ -633,9 +598,9 @@ ProgramStateRef GenericTaintChecker::postScanf(const CallExpr *CE,
// The arguments are pointer arguments. The data they are pointing at is
// tainted after the call.
const Expr* Arg = CE->getArg(i);
- SymbolRef Sym = getPointedToSymbol(C, Arg);
- if (Sym)
- State = State->addTaint(Sym);
+ Optional<SVal> V = getPointedToSVal(C, Arg);
+ if (V)
+ State = State->addTaint(*V);
}
return State;
}
@@ -710,10 +675,10 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
// Check for taint.
ProgramStateRef State = C.getState();
- const SymbolRef PointedToSym = getPointedToSymbol(C, E);
+ Optional<SVal> PointedToSVal = getPointedToSVal(C, E);
SVal TaintedSVal;
- if (State->isTainted(PointedToSym))
- TaintedSVal = nonloc::SymbolVal(PointedToSym);
+ if (PointedToSVal && State->isTainted(*PointedToSVal))
+ TaintedSVal = *PointedToSVal;
else if (State->isTainted(E, C.getLocationContext()))
TaintedSVal = C.getSVal(E);
else
diff --git a/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
new file mode 100644
index 0000000000..0f9b749506
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
@@ -0,0 +1,833 @@
+//===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for using iterators outside their range (past end). Usage
+// means here dereferencing, incrementing etc.
+//
+//===----------------------------------------------------------------------===//
+//
+// In the code, iterator can be represented as a:
+// * type-I: typedef-ed pointer. Operations over such iterator, such as
+// comparisons or increments, are modeled straightforwardly by the
+// analyzer.
+// * type-II: structure with its method bodies available. Operations over such
+// iterator are inlined by the analyzer, and results of modeling
+// these operations are exposing implementation details of the
+// iterators, which is not necessarily helping.
+// * type-III: completely opaque structure. Operations over such iterator are
+// modeled conservatively, producing conjured symbols everywhere.
+//
+// To handle all these types in a common way we introduce a structure called
+// IteratorPosition which is an abstraction of the position the iterator
+// represents using symbolic expressions. The checker handles all the
+// operations on this structure.
+//
+// Additionally, depending on the circumstances, operators of types II and III
+// can be represented as:
+// * type-IIa, type-IIIa: conjured structure symbols - when returned by value
+// from conservatively evaluated methods such as
+// `.begin()`.
+// * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
+// variables or temporaries, when the iterator object is
+// currently treated as an lvalue.
+// * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
+// iterator object is treated as an rvalue taken of a
+// particular lvalue, eg. a copy of "type-a" iterator
+// object, or an iterator that existed before the
+// analysis has started.
+//
+// To handle any of these three different representations stored in an SVal we
+// use setter and getters functions which separate the three cases. To store
+// them we use a pointer union of symbol and memory region.
+//
+// The checker works the following way: We record the past-end iterator for
+// all containers whenever their `.end()` is called. Since the Constraint
+// Manager cannot handle SVals we need to take over its role. We post-check
+// equality and non-equality comparisons and propagate the position of the
+// iterator to the other side of the comparison if it is past-end and we are in
+// the 'equal' branch (true-branch for `==` and false-branch for `!=`).
+//
+// In case of type-I or type-II iterators we get a concrete integer as a result
+// of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
+// this latter case we record the symbol and reload it in evalAssume() and do
+// the propagation there. We also handle (maybe double) negated comparisons
+// which are represented in the form of (x == 0 or x !=0 ) where x is the
+// comparison itself.
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+// Abstract position of an iterator. This helps to handle all three kinds
+// of operators in a common way by using a symbolic position.
+struct IteratorPosition {
+private:
+
+ // Container the iterator belongs to
+ const MemRegion *Cont;
+
+ // Abstract offset
+ SymbolRef Offset;
+
+ IteratorPosition(const MemRegion *C, SymbolRef Of)
+ : Cont(C), Offset(Of) {}
+
+public:
+ const MemRegion *getContainer() const { return Cont; }
+ SymbolRef getOffset() const { return Offset; }
+
+ static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
+ return IteratorPosition(C, Of);
+ }
+
+ IteratorPosition setTo(SymbolRef NewOf) const {
+ return IteratorPosition(Cont, NewOf);
+ }
+
+ bool operator==(const IteratorPosition &X) const {
+ return Cont == X.Cont && Offset == X.Offset;
+ }
+
+ bool operator!=(const IteratorPosition &X) const {
+ return Cont != X.Cont || Offset != X.Offset;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(Cont);
+ ID.Add(Offset);
+ }
+};
+
+typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
+
+// Structure to record the symbolic end position of a container
+struct ContainerData {
+private:
+ SymbolRef End;
+
+ ContainerData(SymbolRef E) : End(E) {}
+
+public:
+ static ContainerData fromEnd(SymbolRef E) {
+ return ContainerData(E);
+ }
+
+ SymbolRef getEnd() const { return End; }
+
+ ContainerData newEnd(SymbolRef E) const { return ContainerData(E); }
+
+ bool operator==(const ContainerData &X) const {
+ return End == X.End;
+ }
+
+ bool operator!=(const ContainerData &X) const {
+ return End != X.End;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.Add(End);
+ }
+};
+
+// Structure fo recording iterator comparisons. We needed to retrieve the
+// original comparison expression in assumptions.
+struct IteratorComparison {
+private:
+ RegionOrSymbol Left, Right;
+ bool Equality;
+
+public:
+ IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
+ : Left(L), Right(R), Equality(Eq) {}
+
+ RegionOrSymbol getLeft() const { return Left; }
+ RegionOrSymbol getRight() const { return Right; }
+ bool isEquality() const { return Equality; }
+ bool operator==(const IteratorComparison &X) const {
+ return Left == X.Left && Right == X.Right && Equality == X.Equality;
+ }
+ bool operator!=(const IteratorComparison &X) const {
+ return Left != X.Left || Right != X.Right || Equality != X.Equality;
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
+};
+
+class IteratorChecker
+ : public Checker<check::PreCall, check::PostCall,
+ check::PostStmt<MaterializeTemporaryExpr>,
+ check::DeadSymbols,
+ eval::Assume> {
+
+ std::unique_ptr<BugType> OutOfRangeBugType;
+
+ void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
+ const SVal &RVal, OverloadedOperatorKind Op) const;
+ void verifyDereference(CheckerContext &C, const SVal &Val) const;
+ void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
+ const SVal &Cont) const;
+ void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
+ const MemRegion *Cont) const;
+ void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
+ CheckerContext &C, ExplodedNode *ErrNode) const;
+
+public:
+ IteratorChecker();
+
+ enum CheckKind {
+ CK_IteratorRangeChecker,
+ CK_NumCheckKinds
+ };
+
+ DefaultBool ChecksEnabled[CK_NumCheckKinds];
+ CheckName CheckNames[CK_NumCheckKinds];
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostStmt(const MaterializeTemporaryExpr *MTE,
+ CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+ ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const;
+};
+} // namespace
+
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
+ IteratorPosition)
+
+REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
+
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
+ IteratorComparison)
+
+namespace {
+
+bool isIteratorType(const QualType &Type);
+bool isIterator(const CXXRecordDecl *CRD);
+bool isEndCall(const FunctionDecl *Func);
+bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
+bool isDereferenceOperator(OverloadedOperatorKind OK);
+BinaryOperator::Opcode getOpcode(const SymExpr *SE);
+const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
+const ProgramStateRef processComparison(ProgramStateRef State,
+ RegionOrSymbol LVal,
+ RegionOrSymbol RVal, bool Equal);
+const ProgramStateRef saveComparison(ProgramStateRef State,
+ const SymExpr *Condition, const SVal &LVal,
+ const SVal &RVal, bool Eq);
+const IteratorComparison *loadComparison(ProgramStateRef State,
+ const SymExpr *Condition);
+SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
+ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
+ const SymbolRef Sym);
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val);
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym);
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ const IteratorPosition &Pos);
+ProgramStateRef setIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos);
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
+ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos, bool Equal);
+ProgramStateRef relateIteratorPositions(ProgramStateRef State,
+ const IteratorPosition &Pos1,
+ const IteratorPosition &Pos2,
+ bool Equal);
+const ContainerData *getContainerData(ProgramStateRef State,
+ const MemRegion *Cont);
+ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
+ const ContainerData &CData);
+bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos);
+} // namespace
+
+IteratorChecker::IteratorChecker() {
+ OutOfRangeBugType.reset(
+ new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
+ OutOfRangeBugType->setSuppressOnSink(true);
+}
+
+void IteratorChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Check for out of range access
+ const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!Func)
+ return;
+
+ if (Func->isOverloadedOperator()) {
+ if (ChecksEnabled[CK_IteratorRangeChecker] &&
+ isDereferenceOperator(Func->getOverloadedOperator())) {
+ // Check for dereference of out-of-range iterators
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ verifyDereference(C, InstCall->getCXXThisVal());
+ } else {
+ verifyDereference(C, Call.getArgSVal(0));
+ }
+ }
+ }
+}
+
+void IteratorChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Record new iterator positions and iterator position changes
+ const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!Func)
+ return;
+
+ if (Func->isOverloadedOperator()) {
+ const auto Op = Func->getOverloadedOperator();
+ if (isSimpleComparisonOperator(Op)) {
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
+ Call.getArgSVal(0), Op);
+ } else {
+ handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
+ Call.getArgSVal(1), Op);
+ }
+ }
+ } else {
+ const auto *OrigExpr = Call.getOriginExpr();
+ if (!OrigExpr)
+ return;
+
+ if (!isIteratorType(Call.getResultType()))
+ return;
+
+ auto State = C.getState();
+ // Already bound to container?
+ if (getIteratorPosition(State, Call.getReturnValue()))
+ return;
+
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ if (isEndCall(Func)) {
+ handleEnd(C, OrigExpr, Call.getReturnValue(),
+ InstCall->getCXXThisVal());
+ return;
+ }
+ }
+
+ // Copy-like and move constructors
+ if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
+ if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
+ State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
+ if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
+ State = removeIteratorPosition(State, Call.getArgSVal(0));
+ }
+ C.addTransition(State);
+ return;
+ }
+ }
+
+ // Assumption: if return value is an iterator which is not yet bound to a
+ // container, then look for the first iterator argument, and
+ // bind the return value to the same container. This approach
+ // works for STL algorithms.
+ // FIXME: Add a more conservative mode
+ for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
+ if (isIteratorType(Call.getArgExpr(i)->getType())) {
+ if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
+ assignToContainer(C, OrigExpr, Call.getReturnValue(),
+ Pos->getContainer());
+ return;
+ }
+ }
+ }
+ }
+}
+
+void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
+ CheckerContext &C) const {
+ /* Transfer iterator state to temporary objects */
+ auto State = C.getState();
+ const auto *LCtx = C.getLocationContext();
+ const auto *Pos =
+ getIteratorPosition(State, State->getSVal(MTE->GetTemporaryExpr(), LCtx));
+ if (!Pos)
+ return;
+ State = setIteratorPosition(State, State->getSVal(MTE, LCtx), *Pos);
+ C.addTransition(State);
+}
+
+void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
+ CheckerContext &C) const {
+ // Cleanup
+ auto State = C.getState();
+
+ auto RegionMap = State->get<IteratorRegionMap>();
+ for (const auto Reg : RegionMap) {
+ if (!SR.isLiveRegion(Reg.first)) {
+ State = State->remove<IteratorRegionMap>(Reg.first);
+ }
+ }
+
+ auto SymbolMap = State->get<IteratorSymbolMap>();
+ for (const auto Sym : SymbolMap) {
+ if (!SR.isLive(Sym.first)) {
+ State = State->remove<IteratorSymbolMap>(Sym.first);
+ }
+ }
+
+ auto ContMap = State->get<ContainerMap>();
+ for (const auto Cont : ContMap) {
+ if (!SR.isLiveRegion(Cont.first)) {
+ State = State->remove<ContainerMap>(Cont.first);
+ }
+ }
+
+ auto ComparisonMap = State->get<IteratorComparisonMap>();
+ for (const auto Comp : ComparisonMap) {
+ if (!SR.isLive(Comp.first)) {
+ State = State->remove<IteratorComparisonMap>(Comp.first);
+ }
+ }
+}
+
+ProgramStateRef IteratorChecker::evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const {
+ // Load recorded comparison and transfer iterator state between sides
+ // according to comparison operator and assumption
+ const auto *SE = Cond.getAsSymExpr();
+ if (!SE)
+ return State;
+
+ auto Opc = getOpcode(SE);
+ if (Opc != BO_EQ && Opc != BO_NE)
+ return State;
+
+ bool Negated = false;
+ const auto *Comp = loadComparison(State, SE);
+ if (!Comp) {
+ // Try negated comparison, which is a SymExpr to 0 integer comparison
+ const auto *SIE = dyn_cast<SymIntExpr>(SE);
+ if (!SIE)
+ return State;
+
+ if (SIE->getRHS() != 0)
+ return State;
+
+ SE = SIE->getLHS();
+ Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
+ Opc = getOpcode(SE);
+ if (Opc != BO_EQ && Opc != BO_NE)
+ return State;
+
+ Comp = loadComparison(State, SE);
+ if (!Comp)
+ return State;
+ }
+
+ return processComparison(State, Comp->getLeft(), Comp->getRight(),
+ (Comp->isEquality() == Assumption) != Negated);
+}
+
+void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal,
+ const SVal &LVal, const SVal &RVal,
+ OverloadedOperatorKind Op) const {
+ // Record the operands and the operator of the comparison for the next
+ // evalAssume, if the result is a symbolic expression. If it is a concrete
+ // value (only one branch is possible), then transfer the state between
+ // the operands according to the operator and the result
+ auto State = C.getState();
+ if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
+ const auto *LPos = getIteratorPosition(State, LVal);
+ const auto *RPos = getIteratorPosition(State, RVal);
+ if (!LPos && !RPos)
+ return;
+ State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
+ C.addTransition(State);
+ } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
+ if ((State = processComparison(
+ State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
+ (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
+ C.addTransition(State);
+ } else {
+ C.generateSink(State, C.getPredecessor());
+ }
+ }
+}
+
+void IteratorChecker::verifyDereference(CheckerContext &C,
+ const SVal &Val) const {
+ auto State = C.getState();
+ const auto *Pos = getIteratorPosition(State, Val);
+ if (Pos && isOutOfRange(State, *Pos)) {
+ // If I do not put a tag here, some range tests will fail
+ static CheckerProgramPointTag Tag("IteratorRangeChecker",
+ "IteratorOutOfRange");
+ auto *N = C.generateNonFatalErrorNode(State, &Tag);
+ if (!N) {
+ return;
+ }
+ reportOutOfRangeBug("Iterator accessed outside of its range.", Val, C, N);
+ }
+}
+
+void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
+ const SVal &RetVal, const SVal &Cont) const {
+ const auto *ContReg = Cont.getAsRegion();
+ if (!ContReg)
+ return;
+
+ while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
+ ContReg = CBOR->getSuperRegion();
+ }
+
+ // If the container already has an end symbol then use it. Otherwise first
+ // create a new one.
+ auto State = C.getState();
+ auto EndSym = getContainerEnd(State, ContReg);
+ if (!EndSym) {
+ auto &SymMgr = C.getSymbolManager();
+ EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ C.getASTContext().LongTy, C.blockCount());
+ State = createContainerEnd(State, ContReg, EndSym);
+ }
+ State = setIteratorPosition(State, RetVal,
+ IteratorPosition::getPosition(ContReg, EndSym));
+ C.addTransition(State);
+}
+
+void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
+ const SVal &RetVal,
+ const MemRegion *Cont) const {
+ while (const auto *CBOR = Cont->getAs<CXXBaseObjectRegion>()) {
+ Cont = CBOR->getSuperRegion();
+ }
+
+ auto State = C.getState();
+ auto &SymMgr = C.getSymbolManager();
+ auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ C.getASTContext().LongTy, C.blockCount());
+ State = setIteratorPosition(State, RetVal,
+ IteratorPosition::getPosition(Cont, Sym));
+ C.addTransition(State);
+}
+
+void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
+ const SVal &Val, CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
+ R->markInteresting(Val);
+ C.emitReport(std::move(R));
+}
+
+namespace {
+
+bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
+bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+ BinaryOperator::Opcode Opc);
+
+bool isIteratorType(const QualType &Type) {
+ if (Type->isPointerType())
+ return true;
+
+ const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
+ return isIterator(CRD);
+}
+
+bool isIterator(const CXXRecordDecl *CRD) {
+ if (!CRD)
+ return false;
+
+ const auto Name = CRD->getName();
+ if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
+ Name.endswith_lower("it")))
+ return false;
+
+ bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
+ HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
+ for (const auto *Method : CRD->methods()) {
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
+ if (Ctor->isCopyConstructor()) {
+ HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
+ }
+ continue;
+ }
+ if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
+ HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
+ continue;
+ }
+ if (Method->isCopyAssignmentOperator()) {
+ HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
+ continue;
+ }
+ if (!Method->isOverloadedOperator())
+ continue;
+ const auto OPK = Method->getOverloadedOperator();
+ if (OPK == OO_PlusPlus) {
+ HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
+ HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
+ continue;
+ }
+ if (OPK == OO_Star) {
+ HasDerefOp = (Method->getNumParams() == 0);
+ continue;
+ }
+ }
+
+ return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
+ HasPostIncrOp && HasDerefOp;
+}
+
+bool isEndCall(const FunctionDecl *Func) {
+ const auto *IdInfo = Func->getIdentifier();
+ if (!IdInfo)
+ return false;
+ return IdInfo->getName().endswith_lower("end");
+}
+
+bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
+ return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
+}
+
+bool isDereferenceOperator(OverloadedOperatorKind OK) {
+ return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
+ OK == OO_Subscript;
+}
+
+BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
+ if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
+ return BSE->getOpcode();
+ } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
+ const auto *COE = dyn_cast<CXXOperatorCallExpr>(SC->getStmt());
+ if (!COE)
+ return BO_Comma; // Extremal value, neither EQ nor NE
+ if (COE->getOperator() == OO_EqualEqual) {
+ return BO_EQ;
+ } else if (COE->getOperator() == OO_ExclaimEqual) {
+ return BO_NE;
+ }
+ return BO_Comma; // Extremal value, neither EQ nor NE
+ }
+ return BO_Comma; // Extremal value, neither EQ nor NE
+}
+
+const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return Reg;
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return Sym;
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return LCVal->getRegion();
+ }
+ return RegionOrSymbol();
+}
+
+const ProgramStateRef processComparison(ProgramStateRef State,
+ RegionOrSymbol LVal,
+ RegionOrSymbol RVal, bool Equal) {
+ const auto *LPos = getIteratorPosition(State, LVal);
+ const auto *RPos = getIteratorPosition(State, RVal);
+ if (LPos && !RPos) {
+ State = adjustIteratorPosition(State, RVal, *LPos, Equal);
+ } else if (!LPos && RPos) {
+ State = adjustIteratorPosition(State, LVal, *RPos, Equal);
+ } else if (LPos && RPos) {
+ State = relateIteratorPositions(State, *LPos, *RPos, Equal);
+ }
+ return State;
+}
+
+const ProgramStateRef saveComparison(ProgramStateRef State,
+ const SymExpr *Condition, const SVal &LVal,
+ const SVal &RVal, bool Eq) {
+ const auto Left = getRegionOrSymbol(LVal);
+ const auto Right = getRegionOrSymbol(RVal);
+ if (!Left || !Right)
+ return State;
+ return State->set<IteratorComparisonMap>(Condition,
+ IteratorComparison(Left, Right, Eq));
+}
+
+const IteratorComparison *loadComparison(ProgramStateRef State,
+ const SymExpr *Condition) {
+ return State->get<IteratorComparisonMap>(Condition);
+}
+
+SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
+ const auto *CDataPtr = getContainerData(State, Cont);
+ if (!CDataPtr)
+ return nullptr;
+
+ return CDataPtr->getEnd();
+}
+
+ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
+ const SymbolRef Sym) {
+ // Only create if it does not exist
+ const auto *CDataPtr = getContainerData(State, Cont);
+ if (CDataPtr) {
+ if (CDataPtr->getEnd()) {
+ return State;
+ } else {
+ const auto CData = CDataPtr->newEnd(Sym);
+ return setContainerData(State, Cont, CData);
+ }
+ } else {
+ const auto CData = ContainerData::fromEnd(Sym);
+ return setContainerData(State, Cont, CData);
+ }
+}
+
+const ContainerData *getContainerData(ProgramStateRef State,
+ const MemRegion *Cont) {
+ return State->get<ContainerMap>(Cont);
+}
+
+ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
+ const ContainerData &CData) {
+ return State->set<ContainerMap>(Cont, CData);
+}
+
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->get<IteratorRegionMap>(Reg);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->get<IteratorSymbolMap>(Sym);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->get<IteratorRegionMap>(LCVal->getRegion());
+ }
+ return nullptr;
+}
+
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym) {
+ if (RegOrSym.is<const MemRegion *>()) {
+ return State->get<IteratorRegionMap>(RegOrSym.get<const MemRegion *>());
+ } else if (RegOrSym.is<SymbolRef>()) {
+ return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
+ }
+ return nullptr;
+}
+
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ const IteratorPosition &Pos) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->set<IteratorRegionMap>(Reg, Pos);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->set<IteratorSymbolMap>(Sym, Pos);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
+ }
+ return nullptr;
+}
+
+ProgramStateRef setIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos) {
+ if (RegOrSym.is<const MemRegion *>()) {
+ return State->set<IteratorRegionMap>(RegOrSym.get<const MemRegion *>(),
+ Pos);
+ } else if (RegOrSym.is<SymbolRef>()) {
+ return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
+ }
+ return nullptr;
+}
+
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->remove<IteratorRegionMap>(Reg);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->remove<IteratorSymbolMap>(Sym);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->remove<IteratorRegionMap>(LCVal->getRegion());
+ }
+ return nullptr;
+}
+
+ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos,
+ bool Equal) {
+ if (Equal) {
+ return setIteratorPosition(State, RegOrSym, Pos);
+ } else {
+ return State;
+ }
+}
+
+ProgramStateRef relateIteratorPositions(ProgramStateRef State,
+ const IteratorPosition &Pos1,
+ const IteratorPosition &Pos2,
+ bool Equal) {
+ // Try to compare them and get a defined value
+ auto &SVB = State->getStateManager().getSValBuilder();
+ const auto comparison =
+ SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()),
+ nonloc::SymbolVal(Pos2.getOffset()), SVB.getConditionType())
+ .getAs<DefinedSVal>();
+ if (comparison) {
+ return State->assume(*comparison, Equal);
+ }
+
+ return State;
+}
+
+bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
+ const auto *Cont = Pos.getContainer();
+ const auto *CData = getContainerData(State, Cont);
+ if (!CData)
+ return false;
+
+ // Out of range means less than the begin symbol or greater or equal to the
+ // end symbol.
+
+ const auto End = CData->getEnd();
+ if (End) {
+ if (isGreaterOrEqual(State, Pos.getOffset(), End)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
+ return compare(State, Sym1, Sym2, BO_GE);
+}
+
+bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+ BinaryOperator::Opcode Opc) {
+ auto &SMgr = State->getStateManager();
+ auto &SVB = SMgr.getSValBuilder();
+
+ const auto comparison =
+ SVB.evalBinOp(State, Opc, nonloc::SymbolVal(Sym1),
+ nonloc::SymbolVal(Sym2), SVB.getConditionType())
+ .getAs<DefinedSVal>();
+
+ if(comparison) {
+ return !!State->assume(*comparison, true);
+ }
+
+ return false;
+}
+
+} // namespace
+
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &Mgr) { \
+ auto *checker = Mgr.registerChecker<IteratorChecker>(); \
+ checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
+ checker->CheckNames[IteratorChecker::CK_##name] = \
+ Mgr.getCurrentCheckName(); \
+ }
+
+REGISTER_CHECKER(IteratorRangeChecker)
diff --git a/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
deleted file mode 100644
index 531054aa78..0000000000
--- a/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
+++ /dev/null
@@ -1,842 +0,0 @@
-//===-- IteratorPastEndChecker.cpp --------------------------------*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines a checker for using iterators outside their range (past end). Usage
-// means here dereferencing, incrementing etc.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
-#include <utility>
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-struct IteratorPosition {
-private:
- enum Kind { InRange, OutofRange } K;
- IteratorPosition(Kind InK) : K(InK) {}
-
-public:
- bool isInRange() const { return K == InRange; }
- bool isOutofRange() const { return K == OutofRange; }
-
- static IteratorPosition getInRange() { return IteratorPosition(InRange); }
- static IteratorPosition getOutofRange() {
- return IteratorPosition(OutofRange);
- }
-
- bool operator==(const IteratorPosition &X) const { return K == X.K; }
- bool operator!=(const IteratorPosition &X) const { return K != X.K; }
- void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
-};
-
-typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
-
-struct IteratorComparison {
-private:
- RegionOrSymbol Left, Right;
- bool Equality;
-
-public:
- IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
- : Left(L), Right(R), Equality(Eq) {}
-
- RegionOrSymbol getLeft() const { return Left; }
- RegionOrSymbol getRight() const { return Right; }
- bool isEquality() const { return Equality; }
- bool operator==(const IteratorComparison &X) const {
- return Left == X.Left && Right == X.Right && Equality == X.Equality;
- }
- bool operator!=(const IteratorComparison &X) const {
- return Left != X.Left || Right != X.Right || Equality != X.Equality;
- }
- void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
-};
-
-class IteratorPastEndChecker
- : public Checker<
- check::PreCall, check::PostCall, check::PreStmt<CXXOperatorCallExpr>,
- check::PostStmt<CXXConstructExpr>, check::PostStmt<DeclStmt>,
- check::PostStmt<MaterializeTemporaryExpr>, check::BeginFunction,
- check::DeadSymbols, eval::Assume, eval::Call> {
- mutable IdentifierInfo *II_find = nullptr,
- *II_find_end = nullptr, *II_find_first_of = nullptr,
- *II_find_if = nullptr, *II_find_if_not = nullptr,
- *II_lower_bound = nullptr, *II_upper_bound = nullptr,
- *II_search = nullptr, *II_search_n = nullptr;
-
- std::unique_ptr<BugType> PastEndBugType;
-
- void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
- const SVal &RVal, OverloadedOperatorKind Op) const;
- void handleAccess(CheckerContext &C, const SVal &Val) const;
- void handleDecrement(CheckerContext &C, const SVal &Val) const;
- void handleEnd(CheckerContext &C, const SVal &RetVal) const;
-
- bool evalFind(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindEnd(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindFirstOf(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindIf(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindIfNot(CheckerContext &C, const CallExpr *CE) const;
- bool evalLowerBound(CheckerContext &C, const CallExpr *CE) const;
- bool evalUpperBound(CheckerContext &C, const CallExpr *CE) const;
- bool evalSearch(CheckerContext &C, const CallExpr *CE) const;
- bool evalSearchN(CheckerContext &C, const CallExpr *CE) const;
- void Find(CheckerContext &C, const CallExpr *CE) const;
-
- void reportPastEndBug(const StringRef &Message, const SVal &Val,
- CheckerContext &C, ExplodedNode *ErrNode) const;
- void initIdentifiers(ASTContext &Ctx) const;
-
-public:
- IteratorPastEndChecker();
-
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
- void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
- void checkPreStmt(const CXXOperatorCallExpr *COCE, CheckerContext &C) const;
- void checkBeginFunction(CheckerContext &C) const;
- void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
- void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
- void checkPostStmt(const MaterializeTemporaryExpr *MTE,
- CheckerContext &C) const;
- void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
- bool Assumption) const;
- bool evalCall(const CallExpr *CE, CheckerContext &C) const;
-};
-}
-
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
- IteratorPosition)
-
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
- IteratorComparison)
-
-#define INIT_ID(Id) \
- if (!II_##Id) \
- II_##Id = &Ctx.Idents.get(#Id)
-
-namespace {
-
-bool isIteratorType(const QualType &Type);
-bool isIterator(const CXXRecordDecl *CRD);
-bool isEndCall(const FunctionDecl *Func);
-bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
-bool isAccessOperator(OverloadedOperatorKind OK);
-bool isDecrementOperator(OverloadedOperatorKind OK);
-BinaryOperator::Opcode getOpcode(const SymExpr *SE);
-const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
-const ProgramStateRef processComparison(ProgramStateRef State,
- RegionOrSymbol LVal,
- RegionOrSymbol RVal, bool Equal);
-const ProgramStateRef saveComparison(ProgramStateRef State,
- const SymExpr *Condition, const SVal &LVal,
- const SVal &RVal, bool Eq);
-const IteratorComparison *loadComparison(ProgramStateRef State,
- const SymExpr *Condition);
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- const SVal &Val);
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym);
-ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
- IteratorPosition Pos);
-ProgramStateRef setIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos);
-ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos, bool Equal);
-bool contradictingIteratorPositions(IteratorPosition Pos1,
- IteratorPosition Pos2, bool Equal);
-}
-
-IteratorPastEndChecker::IteratorPastEndChecker() {
- PastEndBugType.reset(
- new BugType(this, "Iterator Past End", "Misuse of STL APIs"));
- PastEndBugType->setSuppressOnSink(true);
-}
-
-void IteratorPastEndChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- // Check for access past end
- const auto *Func = Call.getDecl()->getAsFunction();
- if (!Func)
- return;
- if (Func->isOverloadedOperator()) {
- if (isAccessOperator(Func->getOverloadedOperator())) {
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- handleAccess(C, InstCall->getCXXThisVal());
- } else {
- handleAccess(C, Call.getArgSVal(0));
- }
- }
- }
-}
-
-void IteratorPastEndChecker::checkPostCall(const CallEvent &Call,
- CheckerContext &C) const {
- // Record end() iterators, iterator decrementation and comparison
- const auto *Func = Call.getDecl()->getAsFunction();
- if (!Func)
- return;
- if (Func->isOverloadedOperator()) {
- const auto Op = Func->getOverloadedOperator();
- if (isSimpleComparisonOperator(Op)) {
- if (Func->isCXXInstanceMember()) {
- const auto &InstCall = static_cast<const CXXInstanceCall &>(Call);
- handleComparison(C, InstCall.getReturnValue(), InstCall.getCXXThisVal(),
- InstCall.getArgSVal(0), Op);
- } else {
- handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
- Call.getArgSVal(1), Op);
- }
- } else if (isDecrementOperator(Func->getOverloadedOperator())) {
- if (Func->isCXXInstanceMember()) {
- const auto &InstCall = static_cast<const CXXInstanceCall &>(Call);
- handleDecrement(C, InstCall.getCXXThisVal());
- } else {
- handleDecrement(C, Call.getArgSVal(0));
- }
- }
- } else if (Func->isCXXInstanceMember()) {
- if (!isEndCall(Func))
- return;
- if (!isIteratorType(Call.getResultType()))
- return;
- handleEnd(C, Call.getReturnValue());
- }
-}
-
-void IteratorPastEndChecker::checkPreStmt(const CXXOperatorCallExpr *COCE,
- CheckerContext &C) const {
- const auto *ThisExpr = COCE->getArg(0);
-
- auto State = C.getState();
- const auto *LCtx = C.getPredecessor()->getLocationContext();
-
- const auto CurrentThis = State->getSVal(ThisExpr, LCtx);
- if (const auto *Reg = CurrentThis.getAsRegion()) {
- if (!Reg->getAs<CXXTempObjectRegion>())
- return;
- const auto OldState = C.getPredecessor()->getFirstPred()->getState();
- const auto OldThis = OldState->getSVal(ThisExpr, LCtx);
- const auto *Pos = getIteratorPosition(OldState, OldThis);
- if (!Pos)
- return;
- State = setIteratorPosition(State, CurrentThis, *Pos);
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::checkBeginFunction(CheckerContext &C) const {
- // Copy state of iterator arguments to iterator parameters
- auto State = C.getState();
- const auto *LCtx = C.getLocationContext();
-
- const auto *Site = cast<StackFrameContext>(LCtx)->getCallSite();
- if (!Site)
- return;
-
- const auto *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
- if (!FD)
- return;
-
- const auto *CE = dyn_cast<CallExpr>(Site);
- if (!CE)
- return;
-
- bool Change = false;
- int idx = 0;
- for (const auto P : FD->parameters()) {
- auto Param = State->getLValue(P, LCtx);
- auto Arg = State->getSVal(CE->getArg(idx++), LCtx->getParent());
- const auto *Pos = getIteratorPosition(State, Arg);
- if (!Pos)
- continue;
- State = setIteratorPosition(State, Param, *Pos);
- Change = true;
- }
- if (Change) {
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::checkPostStmt(const CXXConstructExpr *CCE,
- CheckerContext &C) const {
- // Transfer iterator state in case of copy or move by constructor
- const auto *ctr = CCE->getConstructor();
- if (!ctr->isCopyOrMoveConstructor())
- return;
- const auto *RHSExpr = CCE->getArg(0);
-
- auto State = C.getState();
- const auto *LCtx = C.getLocationContext();
-
- const auto RetVal = State->getSVal(CCE, LCtx);
-
- const auto RHSVal = State->getSVal(RHSExpr, LCtx);
- const auto *RHSPos = getIteratorPosition(State, RHSVal);
- if (!RHSPos)
- return;
- State = setIteratorPosition(State, RetVal, *RHSPos);
- C.addTransition(State);
-}
-
-void IteratorPastEndChecker::checkPostStmt(const DeclStmt *DS,
- CheckerContext &C) const {
- // Transfer iterator state to new variable declaration
- for (const auto *D : DS->decls()) {
- const auto *VD = dyn_cast<VarDecl>(D);
- if (!VD || !VD->hasInit())
- continue;
-
- auto State = C.getState();
- const auto *LCtx = C.getPredecessor()->getLocationContext();
- const auto *Pos =
- getIteratorPosition(State, State->getSVal(VD->getInit(), LCtx));
- if (!Pos)
- continue;
- State = setIteratorPosition(State, State->getLValue(VD, LCtx), *Pos);
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
- CheckerContext &C) const {
- /* Transfer iterator state for to temporary objects */
- auto State = C.getState();
- const auto *LCtx = C.getPredecessor()->getLocationContext();
- const auto *Pos =
- getIteratorPosition(State, State->getSVal(MTE->GetTemporaryExpr(), LCtx));
- if (!Pos)
- return;
- State = setIteratorPosition(State, State->getSVal(MTE, LCtx), *Pos);
- C.addTransition(State);
-}
-
-void IteratorPastEndChecker::checkDeadSymbols(SymbolReaper &SR,
- CheckerContext &C) const {
- auto State = C.getState();
-
- auto RegionMap = State->get<IteratorRegionMap>();
- for (const auto Reg : RegionMap) {
- if (!SR.isLiveRegion(Reg.first)) {
- State = State->remove<IteratorRegionMap>(Reg.first);
- }
- }
-
- auto SymbolMap = State->get<IteratorSymbolMap>();
- for (const auto Sym : SymbolMap) {
- if (SR.isDead(Sym.first)) {
- State = State->remove<IteratorSymbolMap>(Sym.first);
- }
- }
-
- auto ComparisonMap = State->get<IteratorComparisonMap>();
- for (const auto Comp : ComparisonMap) {
- if (SR.isDead(Comp.first)) {
- State = State->remove<IteratorComparisonMap>(Comp.first);
- }
- }
-}
-
-ProgramStateRef IteratorPastEndChecker::evalAssume(ProgramStateRef State,
- SVal Cond,
- bool Assumption) const {
- // Load recorded comparison and transfer iterator state between sides
- // according to comparison operator and assumption
- const auto *SE = Cond.getAsSymExpr();
- if (!SE)
- return State;
-
- auto Opc = getOpcode(SE);
- if (Opc != BO_EQ && Opc != BO_NE)
- return State;
-
- bool Negated = false;
- const auto *Comp = loadComparison(State, SE);
- if (!Comp) {
- // Try negated comparison, which is a SymExpr to 0 integer comparison
- const auto *SIE = dyn_cast<SymIntExpr>(SE);
- if (!SIE)
- return State;
-
- if (SIE->getRHS() != 0)
- return State;
-
- SE = SIE->getLHS();
- Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
- Opc = getOpcode(SE);
- if (Opc != BO_EQ && Opc != BO_NE)
- return State;
-
- Comp = loadComparison(State, SE);
- if (!Comp)
- return State;
- }
-
- return processComparison(State, Comp->getLeft(), Comp->getRight(),
- (Comp->isEquality() == Assumption) != Negated);
-}
-
-// FIXME: Evaluation of these STL calls should be moved to StdCLibraryFunctions
-// checker (see patch r284960) or another similar checker for C++ STL
-// functions (e.g. StdCXXLibraryFunctions or StdCppLibraryFunctions).
-bool IteratorPastEndChecker::evalCall(const CallExpr *CE,
- CheckerContext &C) const {
- const FunctionDecl *FD = C.getCalleeDecl(CE);
- if (!FD)
- return false;
-
- ASTContext &Ctx = C.getASTContext();
- initIdentifiers(Ctx);
-
- if (FD->getKind() == Decl::Function) {
- if (FD->isInStdNamespace()) {
- if (FD->getIdentifier() == II_find) {
- return evalFind(C, CE);
- } else if (FD->getIdentifier() == II_find_end) {
- return evalFindEnd(C, CE);
- } else if (FD->getIdentifier() == II_find_first_of) {
- return evalFindFirstOf(C, CE);
- } else if (FD->getIdentifier() == II_find_if) {
- return evalFindIf(C, CE);
- } else if (FD->getIdentifier() == II_find_if) {
- return evalFindIf(C, CE);
- } else if (FD->getIdentifier() == II_find_if_not) {
- return evalFindIfNot(C, CE);
- } else if (FD->getIdentifier() == II_upper_bound) {
- return evalUpperBound(C, CE);
- } else if (FD->getIdentifier() == II_lower_bound) {
- return evalLowerBound(C, CE);
- } else if (FD->getIdentifier() == II_search) {
- return evalSearch(C, CE);
- } else if (FD->getIdentifier() == II_search_n) {
- return evalSearchN(C, CE);
- }
- }
- }
-
- return false;
-}
-
-void IteratorPastEndChecker::handleComparison(CheckerContext &C,
- const SVal &RetVal,
- const SVal &LVal,
- const SVal &RVal,
- OverloadedOperatorKind Op) const {
- // Record the operands and the operator of the comparison for the next
- // evalAssume, if the result is a symbolic expression. If it is a concrete
- // value (only one branch is possible), then transfer the state between
- // the operands according to the operator and the result
- auto State = C.getState();
- if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
- const auto *LPos = getIteratorPosition(State, LVal);
- const auto *RPos = getIteratorPosition(State, RVal);
- if (!LPos && !RPos)
- return;
- State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
- C.addTransition(State);
- } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
- if ((State = processComparison(
- State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
- (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
- C.addTransition(State);
- } else {
- C.generateSink(State, C.getPredecessor());
- }
- }
-}
-
-void IteratorPastEndChecker::handleAccess(CheckerContext &C,
- const SVal &Val) const {
- auto State = C.getState();
- const auto *Pos = getIteratorPosition(State, Val);
- if (Pos && Pos->isOutofRange()) {
- auto *N = C.generateNonFatalErrorNode(State);
- if (!N) {
- return;
- }
- reportPastEndBug("Iterator accessed past its end.", Val, C, N);
- }
-}
-
-void IteratorPastEndChecker::handleDecrement(CheckerContext &C,
- const SVal &Val) const {
- auto State = C.getState();
- const auto *Pos = getIteratorPosition(State, Val);
- if (Pos && Pos->isOutofRange()) {
- State = setIteratorPosition(State, Val, IteratorPosition::getInRange());
- // FIXME: We could also check for iterators ahead of their beginnig in the
- // future, but currently we do not care for such errors. We also
- // assume that the iterator is not past its end by more then one
- // position.
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::handleEnd(CheckerContext &C,
- const SVal &RetVal) const {
- auto State = C.getState();
- State = setIteratorPosition(State, RetVal, IteratorPosition::getOutofRange());
- C.addTransition(State);
-}
-
-bool IteratorPastEndChecker::evalFind(CheckerContext &C,
- const CallExpr *CE) const {
- if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindEnd(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType()) &&
- isIteratorType(CE->getArg(2)->getType()) &&
- isIteratorType(CE->getArg(3)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindFirstOf(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType()) &&
- isIteratorType(CE->getArg(2)->getType()) &&
- isIteratorType(CE->getArg(3)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindIf(CheckerContext &C,
- const CallExpr *CE) const {
- if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindIfNot(CheckerContext &C,
- const CallExpr *CE) const {
- if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalLowerBound(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 3 || CE->getNumArgs() == 4) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalUpperBound(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 3 || CE->getNumArgs() == 4) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalSearch(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType()) &&
- isIteratorType(CE->getArg(2)->getType()) &&
- isIteratorType(CE->getArg(3)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalSearchN(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-void IteratorPastEndChecker::Find(CheckerContext &C, const CallExpr *CE) const {
- auto state = C.getState();
- auto &svalBuilder = C.getSValBuilder();
- const auto *LCtx = C.getLocationContext();
-
- auto RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
- auto SecondParam = state->getSVal(CE->getArg(1), LCtx);
-
- auto stateFound = state->BindExpr(CE, LCtx, RetVal);
- auto stateNotFound = state->BindExpr(CE, LCtx, SecondParam);
-
- C.addTransition(stateFound);
- C.addTransition(stateNotFound);
-}
-
-void IteratorPastEndChecker::reportPastEndBug(const StringRef &Message,
- const SVal &Val,
- CheckerContext &C,
- ExplodedNode *ErrNode) const {
- auto R = llvm::make_unique<BugReport>(*PastEndBugType, Message, ErrNode);
- R->markInteresting(Val);
- C.emitReport(std::move(R));
-}
-
-void IteratorPastEndChecker::initIdentifiers(ASTContext &Ctx) const {
- INIT_ID(find);
- INIT_ID(find_end);
- INIT_ID(find_first_of);
- INIT_ID(find_if);
- INIT_ID(find_if_not);
- INIT_ID(lower_bound);
- INIT_ID(upper_bound);
- INIT_ID(search);
- INIT_ID(search_n);
-}
-
-namespace {
-
-bool isIteratorType(const QualType &Type) {
- if (Type->isPointerType())
- return true;
-
- const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
- return isIterator(CRD);
-}
-
-bool isIterator(const CXXRecordDecl *CRD) {
- if (!CRD)
- return false;
-
- const auto Name = CRD->getName();
- if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
- Name.endswith_lower("it")))
- return false;
-
- bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
- HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
- for (const auto *Method : CRD->methods()) {
- if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
- if (Ctor->isCopyConstructor()) {
- HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
- }
- continue;
- }
- if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
- HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
- continue;
- }
- if (Method->isCopyAssignmentOperator()) {
- HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
- continue;
- }
- if (!Method->isOverloadedOperator())
- continue;
- const auto OPK = Method->getOverloadedOperator();
- if (OPK == OO_PlusPlus) {
- HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
- HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
- continue;
- }
- if (OPK == OO_Star) {
- HasDerefOp = (Method->getNumParams() == 0);
- continue;
- }
- }
-
- return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
- HasPostIncrOp && HasDerefOp;
-}
-
-bool isEndCall(const FunctionDecl *Func) {
- const auto *IdInfo = Func->getIdentifier();
- if (!IdInfo)
- return false;
- return IdInfo->getName().endswith_lower("end");
-}
-
-bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
- return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
-}
-
-bool isAccessOperator(OverloadedOperatorKind OK) {
- return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
- OK == OO_Plus || OK == OO_PlusEqual || OK == OO_PlusPlus ||
- OK == OO_Subscript;
-}
-
-bool isDecrementOperator(OverloadedOperatorKind OK) {
- return OK == OO_MinusEqual || OK == OO_MinusMinus;
-}
-
-BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
- if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
- return BSE->getOpcode();
- } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
- const auto *COE = dyn_cast<CXXOperatorCallExpr>(SC->getStmt());
- if (!COE)
- return BO_Comma; // Extremal value, neither EQ nor NE
- if (COE->getOperator() == OO_EqualEqual) {
- return BO_EQ;
- } else if (COE->getOperator() == OO_ExclaimEqual) {
- return BO_NE;
- }
- return BO_Comma; // Extremal value, neither EQ nor NE
- }
- return BO_Comma; // Extremal value, neither EQ nor NE
-}
-
-const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
- if (const auto Reg = Val.getAsRegion()) {
- return Reg;
- } else if (const auto Sym = Val.getAsSymbol()) {
- return Sym;
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return LCVal->getRegion();
- }
- return RegionOrSymbol();
-}
-
-const ProgramStateRef processComparison(ProgramStateRef State,
- RegionOrSymbol LVal,
- RegionOrSymbol RVal, bool Equal) {
- const auto *LPos = getIteratorPosition(State, LVal);
- const auto *RPos = getIteratorPosition(State, RVal);
- if (LPos && !RPos) {
- State = adjustIteratorPosition(State, RVal, *LPos, Equal);
- } else if (!LPos && RPos) {
- State = adjustIteratorPosition(State, LVal, *RPos, Equal);
- } else if (LPos && RPos) {
- if (contradictingIteratorPositions(*LPos, *RPos, Equal)) {
- return nullptr;
- }
- }
- return State;
-}
-
-const ProgramStateRef saveComparison(ProgramStateRef State,
- const SymExpr *Condition, const SVal &LVal,
- const SVal &RVal, bool Eq) {
- const auto Left = getRegionOrSymbol(LVal);
- const auto Right = getRegionOrSymbol(RVal);
- if (!Left || !Right)
- return State;
- return State->set<IteratorComparisonMap>(Condition,
- IteratorComparison(Left, Right, Eq));
-}
-
-const IteratorComparison *loadComparison(ProgramStateRef State,
- const SymExpr *Condition) {
- return State->get<IteratorComparisonMap>(Condition);
-}
-
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- const SVal &Val) {
- if (const auto Reg = Val.getAsRegion()) {
- return State->get<IteratorRegionMap>(Reg);
- } else if (const auto Sym = Val.getAsSymbol()) {
- return State->get<IteratorSymbolMap>(Sym);
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return State->get<IteratorRegionMap>(LCVal->getRegion());
- }
- return nullptr;
-}
-
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym) {
- if (RegOrSym.is<const MemRegion *>()) {
- return State->get<IteratorRegionMap>(RegOrSym.get<const MemRegion *>());
- } else if (RegOrSym.is<SymbolRef>()) {
- return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
- }
- return nullptr;
-}
-
-ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
- IteratorPosition Pos) {
- if (const auto Reg = Val.getAsRegion()) {
- return State->set<IteratorRegionMap>(Reg, Pos);
- } else if (const auto Sym = Val.getAsSymbol()) {
- return State->set<IteratorSymbolMap>(Sym, Pos);
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
- }
- return nullptr;
-}
-
-ProgramStateRef setIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos) {
- if (RegOrSym.is<const MemRegion *>()) {
- return State->set<IteratorRegionMap>(RegOrSym.get<const MemRegion *>(),
- Pos);
- } else if (RegOrSym.is<SymbolRef>()) {
- return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
- }
- return nullptr;
-}
-
-ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos, bool Equal) {
-
- if ((Pos.isInRange() && Equal) || (Pos.isOutofRange() && !Equal)) {
- return setIteratorPosition(State, RegOrSym, IteratorPosition::getInRange());
- } else if (Pos.isOutofRange() && Equal) {
- return setIteratorPosition(State, RegOrSym,
- IteratorPosition::getOutofRange());
- } else {
- return State;
- }
-}
-
-bool contradictingIteratorPositions(IteratorPosition Pos1,
- IteratorPosition Pos2, bool Equal) {
- return ((Pos1 != Pos2) && Equal) ||
- ((Pos1.isOutofRange() && Pos2.isOutofRange()) && !Equal);
-}
-}
-
-void ento::registerIteratorPastEndChecker(CheckerManager &Mgr) {
- Mgr.registerChecker<IteratorPastEndChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index af35c2b0e9..655ce33390 100644
--- a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -57,7 +57,7 @@ public:
};
class NonLocalizedStringChecker
- : public Checker<check::PostCall, check::PreObjCMessage,
+ : public Checker<check::PreCall, check::PostCall, check::PreObjCMessage,
check::PostObjCMessage,
check::PostStmt<ObjCStringLiteral>> {
@@ -79,9 +79,10 @@ class NonLocalizedStringChecker
void setNonLocalizedState(SVal S, CheckerContext &C) const;
void setLocalizedState(SVal S, CheckerContext &C) const;
- bool isAnnotatedAsLocalized(const Decl *D) const;
- void reportLocalizationError(SVal S, const ObjCMethodCall &M,
- CheckerContext &C, int argumentNumber = 0) const;
+ bool isAnnotatedAsReturningLocalized(const Decl *D) const;
+ bool isAnnotatedAsTakingLocalized(const Decl *D) const;
+ void reportLocalizationError(SVal S, const CallEvent &M, CheckerContext &C,
+ int argumentNumber = 0) const;
int getLocalizedArgumentForSelector(const IdentifierInfo *Receiver,
Selector S) const;
@@ -97,6 +98,7 @@ public:
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
void checkPostStmt(const ObjCStringLiteral *SL, CheckerContext &C) const;
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
};
@@ -281,6 +283,9 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const {
IdentifierInfo *setLabelNSSegmentedControl[] = {
&Ctx.Idents.get("setLabel"), &Ctx.Idents.get("forSegment")};
ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0)
+ IdentifierInfo *setToolTipNSSegmentedControl[] = {
+ &Ctx.Idents.get("setToolTip"), &Ctx.Idents.get("forSegment")};
+ ADD_METHOD(NSSegmentedControl, setToolTipNSSegmentedControl, 2, 0)
NEW_RECEIVER(NSButtonCell)
ADD_UNARY_METHOD(NSButtonCell, setTitle, 0)
@@ -562,6 +567,46 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const {
IdentifierInfo *setTitleUISegmentedControl[] = {
&Ctx.Idents.get("setTitle"), &Ctx.Idents.get("forSegmentAtIndex")};
ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomRotorItemResult)
+ IdentifierInfo
+ *initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult[] = {
+ &Ctx.Idents.get("initWithItemLoadingToken"),
+ &Ctx.Idents.get("customLabel")};
+ ADD_METHOD(NSAccessibilityCustomRotorItemResult,
+ initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult, 2, 1)
+ ADD_UNARY_METHOD(NSAccessibilityCustomRotorItemResult, setCustomLabel, 0)
+
+ NEW_RECEIVER(UIContextualAction)
+ IdentifierInfo *contextualActionWithStyleUIContextualAction[] = {
+ &Ctx.Idents.get("contextualActionWithStyle"), &Ctx.Idents.get("title"),
+ &Ctx.Idents.get("handler")};
+ ADD_METHOD(UIContextualAction, contextualActionWithStyleUIContextualAction, 3,
+ 1)
+ ADD_UNARY_METHOD(UIContextualAction, setTitle, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomRotor)
+ IdentifierInfo *initWithLabelNSAccessibilityCustomRotor[] = {
+ &Ctx.Idents.get("initWithLabel"), &Ctx.Idents.get("itemSearchDelegate")};
+ ADD_METHOD(NSAccessibilityCustomRotor,
+ initWithLabelNSAccessibilityCustomRotor, 2, 0)
+ ADD_UNARY_METHOD(NSAccessibilityCustomRotor, setLabel, 0)
+
+ NEW_RECEIVER(NSWindowTab)
+ ADD_UNARY_METHOD(NSWindowTab, setTitle, 0)
+ ADD_UNARY_METHOD(NSWindowTab, setToolTip, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomAction)
+ IdentifierInfo *initWithNameNSAccessibilityCustomAction[] = {
+ &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("handler")};
+ ADD_METHOD(NSAccessibilityCustomAction,
+ initWithNameNSAccessibilityCustomAction, 2, 0)
+ IdentifierInfo *initWithNameTargetNSAccessibilityCustomAction[] = {
+ &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"),
+ &Ctx.Idents.get("selector")};
+ ADD_METHOD(NSAccessibilityCustomAction,
+ initWithNameTargetNSAccessibilityCustomAction, 3, 0)
+ ADD_UNARY_METHOD(NSAccessibilityCustomAction, setName, 0)
}
#define LSF_INSERT(function_name) LSF.insert(&Ctx.Idents.get(function_name));
@@ -601,7 +646,8 @@ void NonLocalizedStringChecker::initLocStringsMethods(ASTContext &Ctx) const {
/// Checks to see if the method / function declaration includes
/// __attribute__((annotate("returns_localized_nsstring")))
-bool NonLocalizedStringChecker::isAnnotatedAsLocalized(const Decl *D) const {
+bool NonLocalizedStringChecker::isAnnotatedAsReturningLocalized(
+ const Decl *D) const {
if (!D)
return false;
return std::any_of(
@@ -611,6 +657,19 @@ bool NonLocalizedStringChecker::isAnnotatedAsLocalized(const Decl *D) const {
});
}
+/// Checks to see if the method / function declaration includes
+/// __attribute__((annotate("takes_localized_nsstring")))
+bool NonLocalizedStringChecker::isAnnotatedAsTakingLocalized(
+ const Decl *D) const {
+ if (!D)
+ return false;
+ return std::any_of(
+ D->specific_attr_begin<AnnotateAttr>(),
+ D->specific_attr_end<AnnotateAttr>(), [](const AnnotateAttr *Ann) {
+ return Ann->getAnnotation() == "takes_localized_nsstring";
+ });
+}
+
/// Returns true if the given SVal is marked as Localized in the program state
bool NonLocalizedStringChecker::hasLocalizedState(SVal S,
CheckerContext &C) const {
@@ -690,8 +749,7 @@ static bool isDebuggingContext(CheckerContext &C) {
/// Reports a localization error for the passed in method call and SVal
void NonLocalizedStringChecker::reportLocalizationError(
- SVal S, const ObjCMethodCall &M, CheckerContext &C,
- int argumentNumber) const {
+ SVal S, const CallEvent &M, CheckerContext &C, int argumentNumber) const {
// Don't warn about localization errors in classes and methods that
// may be debug code.
@@ -789,7 +847,21 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
}
}
- if (argumentNumber < 0) // There was no match in UIMethods
+ if (argumentNumber < 0) { // There was no match in UIMethods
+ if (const Decl *D = msg.getDecl()) {
+ if (const ObjCMethodDecl *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
+ auto formals = OMD->parameters();
+ for (unsigned i = 0, ei = formals.size(); i != ei; ++i) {
+ if (isAnnotatedAsTakingLocalized(formals[i])) {
+ argumentNumber = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (argumentNumber < 0) // Still no match
return;
SVal svTitle = msg.getArgSVal(argumentNumber);
@@ -812,6 +884,25 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
}
}
+void NonLocalizedStringChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const Decl *D = Call.getDecl();
+ if (D && isa<FunctionDecl>(D)) {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ auto formals = FD->parameters();
+ for (unsigned i = 0,
+ ei = std::min(unsigned(formals.size()), Call.getNumArgs());
+ i != ei; ++i) {
+ if (isAnnotatedAsTakingLocalized(formals[i])) {
+ auto actual = Call.getArgSVal(i);
+ if (hasNonLocalizedState(actual, C)) {
+ reportLocalizationError(actual, Call, C, i + 1);
+ }
+ }
+ }
+ }
+}
+
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
@@ -863,7 +954,7 @@ void NonLocalizedStringChecker::checkPostCall(const CallEvent &Call,
const IdentifierInfo *Identifier = Call.getCalleeIdentifier();
SVal sv = Call.getReturnValue();
- if (isAnnotatedAsLocalized(D) || LSF.count(Identifier) != 0) {
+ if (isAnnotatedAsReturningLocalized(D) || LSF.count(Identifier) != 0) {
setLocalizedState(sv, C);
} else if (isNSStringType(RT, C.getASTContext()) &&
!hasLocalizedState(sv, C)) {
@@ -897,7 +988,8 @@ void NonLocalizedStringChecker::checkPostObjCMessage(const ObjCMethodCall &msg,
std::pair<const IdentifierInfo *, Selector> MethodDescription = {odInfo, S};
- if (LSM.count(MethodDescription) || isAnnotatedAsLocalized(msg.getDecl())) {
+ if (LSM.count(MethodDescription) ||
+ isAnnotatedAsReturningLocalized(msg.getDecl())) {
SVal sv = msg.getReturnValue();
setLocalizedState(sv, C);
}
diff --git a/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
index c667b9e67d..696cf39473 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/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 6e9b7fefa3..851114004b 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -177,7 +178,10 @@ public:
II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_g_malloc(nullptr),
II_g_malloc0(nullptr), II_g_realloc(nullptr), II_g_try_malloc(nullptr),
II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),
- II_g_free(nullptr), II_g_memdup(nullptr) {}
+ II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),
+ II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),
+ II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),
+ II_g_try_realloc_n(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -241,7 +245,10 @@ private:
*II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
*II_win_wcsdup, *II_g_malloc, *II_g_malloc0,
*II_g_realloc, *II_g_try_malloc, *II_g_try_malloc0,
- *II_g_try_realloc, *II_g_free, *II_g_memdup;
+ *II_g_try_realloc, *II_g_free, *II_g_memdup,
+ *II_g_malloc_n, *II_g_malloc0_n, *II_g_realloc_n,
+ *II_g_try_malloc_n, *II_g_try_malloc0_n,
+ *II_g_try_realloc_n;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -321,9 +328,12 @@ private:
bool &ReleasedAllocated,
bool ReturnsNullOnFailure = false) const;
- ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
- bool FreesMemOnFailure,
- ProgramStateRef State) const;
+ ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE,
+ bool FreesMemOnFailure,
+ ProgramStateRef State,
+ bool SuffixWithN = false) const;
+ static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
+ const Expr *BlockBytes);
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State);
@@ -392,6 +402,9 @@ private:
void ReportUseZeroAllocated(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const;
+ void ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range, const Expr *FreeExpr) const;
+
/// Find the location of the allocation for Sym on the path leading to the
/// exploded node N.
LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
@@ -569,6 +582,12 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
II_g_try_realloc = &Ctx.Idents.get("g_try_realloc");
II_g_free = &Ctx.Idents.get("g_free");
II_g_memdup = &Ctx.Idents.get("g_memdup");
+ II_g_malloc_n = &Ctx.Idents.get("g_malloc_n");
+ II_g_malloc0_n = &Ctx.Idents.get("g_malloc0_n");
+ II_g_realloc_n = &Ctx.Idents.get("g_realloc_n");
+ II_g_try_malloc_n = &Ctx.Idents.get("g_try_malloc_n");
+ II_g_try_malloc0_n = &Ctx.Idents.get("g_try_malloc0_n");
+ II_g_try_realloc_n = &Ctx.Idents.get("g_try_realloc_n");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -617,7 +636,10 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
FunI == II_g_malloc || FunI == II_g_malloc0 ||
FunI == II_g_realloc || FunI == II_g_try_malloc ||
FunI == II_g_try_malloc0 || FunI == II_g_try_realloc ||
- FunI == II_g_memdup)
+ FunI == II_g_memdup || FunI == II_g_malloc_n ||
+ FunI == II_g_malloc0_n || FunI == II_g_realloc_n ||
+ FunI == II_g_try_malloc_n || FunI == II_g_try_malloc0_n ||
+ FunI == II_g_try_realloc_n)
return true;
}
@@ -767,6 +789,17 @@ llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
return None;
}
+SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
+ const Expr *BlockBytes) {
+ SValBuilder &SB = C.getSValBuilder();
+ SVal BlocksVal = C.getSVal(Blocks);
+ SVal BlockBytesVal = C.getSVal(BlockBytes);
+ ProgramStateRef State = C.getState();
+ SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
+ SB.getContext().getSizeType());
+ return TotalSize;
+}
+
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
if (C.wasInlined)
return;
@@ -813,10 +846,10 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
State = ProcessZeroAllocation(C, CE, 0, State);
} else if (FunI == II_realloc || FunI == II_g_realloc ||
FunI == II_g_try_realloc) {
- State = ReallocMem(C, CE, false, State);
+ State = ReallocMemAux(C, CE, false, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_reallocf) {
- State = ReallocMem(C, CE, true, State);
+ State = ReallocMemAux(C, CE, true, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_calloc) {
State = CallocMem(C, CE, State);
@@ -874,6 +907,25 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
return;
State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
State = ProcessZeroAllocation(C, CE, 1, State);
+ } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||
+ FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ if (CE->getNumArgs() < 2)
+ return;
+ SVal Init = UndefinedVal();
+ if (FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ SValBuilder &SB = C.getSValBuilder();
+ Init = SB.makeZeroVal(SB.getContext().CharTy);
+ }
+ SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
+ State = MallocMemAux(C, CE, TotalSize, Init, State);
+ State = ProcessZeroAllocation(C, CE, 0, State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ } else if (FunI == II_g_realloc_n || FunI == II_g_try_realloc_n) {
+ if (CE->getNumArgs() < 3)
+ return;
+ State = ReallocMemAux(C, CE, false, State, true);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ State = ProcessZeroAllocation(C, CE, 2, State);
}
}
@@ -1516,6 +1568,11 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
}
}
+ if (SymBase->getType()->isFunctionPointerType()) {
+ ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+ return nullptr;
+ }
+
ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
RsBase->isAllocatedOfSizeZero());
@@ -1697,8 +1754,8 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_BadFree[*CheckKind])
- BT_BadFree[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
+ BT_BadFree[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Bad free", categories::MemoryError));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1742,8 +1799,8 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_FreeAlloca[*CheckKind])
- BT_FreeAlloca[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Free alloca()", "Memory Error"));
+ BT_FreeAlloca[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Free alloca()", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(
*BT_FreeAlloca[*CheckKind],
@@ -1768,7 +1825,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
if (!BT_MismatchedDealloc)
BT_MismatchedDealloc.reset(
new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
- "Bad deallocator", "Memory Error"));
+ "Bad deallocator", categories::MemoryError));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1828,8 +1885,8 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
return;
if (!BT_OffsetFree[*CheckKind])
- BT_OffsetFree[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Offset free", "Memory Error"));
+ BT_OffsetFree[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Offset free", categories::MemoryError));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1880,7 +1937,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_UseFree[*CheckKind])
BT_UseFree[*CheckKind].reset(new BugType(
- CheckNames[*CheckKind], "Use-after-free", "Memory Error"));
+ CheckNames[*CheckKind], "Use-after-free", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT_UseFree[*CheckKind],
"Use of memory after it is freed", N);
@@ -1906,8 +1963,8 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_DoubleFree[*CheckKind])
- BT_DoubleFree[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Double free", "Memory Error"));
+ BT_DoubleFree[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Double free", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(
*BT_DoubleFree[*CheckKind],
@@ -1935,7 +1992,8 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_DoubleDelete)
BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
- "Double delete", "Memory Error"));
+ "Double delete",
+ categories::MemoryError));
auto R = llvm::make_unique<BugReport>(
*BT_DoubleDelete, "Attempt to delete released memory", N);
@@ -1961,8 +2019,9 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_UseZerroAllocated[*CheckKind])
- BT_UseZerroAllocated[*CheckKind].reset(new BugType(
- CheckNames[*CheckKind], "Use of zero allocated", "Memory Error"));
+ BT_UseZerroAllocated[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Use of zero allocated",
+ categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT_UseZerroAllocated[*CheckKind],
"Use of zero-allocated memory", N);
@@ -1976,14 +2035,52 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
}
}
-ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
- const CallExpr *CE,
- bool FreesOnFail,
- ProgramStateRef State) const {
+void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range,
+ const Expr *FreeExpr) const {
+ if (!ChecksEnabled[CK_MallocChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, FreeExpr);
+ if (!CheckKind.hasValue())
+ return;
+
+ if (ExplodedNode *N = C.generateErrorNode()) {
+ if (!BT_BadFree[*CheckKind])
+ BT_BadFree[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
+
+ SmallString<100> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+
+ const MemRegion *MR = ArgVal.getAsRegion();
+ while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
+ MR = ER->getSuperRegion();
+
+ Os << "Argument to ";
+ if (!printAllocDeallocName(Os, C, FreeExpr))
+ Os << "deallocator";
+
+ Os << " is a function pointer";
+
+ auto R = llvm::make_unique<BugReport>(*BT_BadFree[*CheckKind], Os.str(), N);
+ R->markInteresting(MR);
+ R->addRange(Range);
+ C.emitReport(std::move(R));
+ }
+}
+
+ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ bool FreesOnFail,
+ ProgramStateRef State,
+ bool SuffixWithN) const {
if (!State)
return nullptr;
- if (CE->getNumArgs() < 2)
+ if (SuffixWithN && CE->getNumArgs() < 3)
+ return nullptr;
+ else if (CE->getNumArgs() < 2)
return nullptr;
const Expr *arg0Expr = CE->getArg(0);
@@ -1998,20 +2095,19 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
DefinedOrUnknownSVal PtrEQ =
svalBuilder.evalEQ(State, arg0Val, svalBuilder.makeNull());
- // Get the size argument. If there is no size arg then give up.
+ // Get the size argument.
const Expr *Arg1 = CE->getArg(1);
- if (!Arg1)
- return nullptr;
// Get the value of the size argument.
- SVal Arg1ValG = State->getSVal(Arg1, LCtx);
- if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
+ SVal TotalSize = State->getSVal(Arg1, LCtx);
+ if (SuffixWithN)
+ TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
+ if (!TotalSize.getAs<DefinedOrUnknownSVal>())
return nullptr;
- DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
- svalBuilder.evalEQ(State, Arg1Val,
+ svalBuilder.evalEQ(State, TotalSize.castAs<DefinedOrUnknownSVal>(),
svalBuilder.makeIntValWithPtrWidth(0, false));
ProgramStateRef StatePtrIsNull, StatePtrNotNull;
@@ -2025,8 +2121,8 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
// If the ptr is NULL and the size is not 0, the call is equivalent to
// malloc(size).
- if ( PrtIsNull && !SizeIsZero) {
- ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
+ if (PrtIsNull && !SizeIsZero) {
+ ProgramStateRef stateMalloc = MallocMemAux(C, CE, TotalSize,
UndefinedVal(), StatePtrIsNull);
return stateMalloc;
}
@@ -2059,7 +2155,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
if (ProgramStateRef stateFree =
FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
- ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
+ ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,
UnknownVal(), stateFree);
if (!stateRealloc)
return nullptr;
@@ -2090,12 +2186,8 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
return nullptr;
SValBuilder &svalBuilder = C.getSValBuilder();
- const LocationContext *LCtx = C.getLocationContext();
- SVal count = State->getSVal(CE->getArg(0), LCtx);
- SVal elementSize = State->getSVal(CE->getArg(1), LCtx);
- SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize,
- svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
+ SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
return MallocMemAux(C, CE, TotalSize, zeroVal, State);
}
@@ -2164,8 +2256,8 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
assert(N);
if (!BT_Leak[*CheckKind]) {
- BT_Leak[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Memory leak", "Memory Error"));
+ BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",
+ categories::MemoryError));
// Leaks should not be reported if they are post-dominated by a sink:
// (1) Sinks are higher importance bugs.
// (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
diff --git a/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp b/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
new file mode 100644
index 0000000000..497978f078
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
@@ -0,0 +1,526 @@
+// 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;
+ void printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const override;
+
+private:
+ enum MisuseKind {MK_FunCall, MK_Copy, MK_Move};
+ 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, MisuseKind MK) 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,
+ MisuseKind MK) 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;
+ switch(MK) {
+ case MK_FunCall:
+ ErrorMessage = "Method call on a 'moved-from' object";
+ break;
+ case MK_Copy:
+ ErrorMessage = "Copying a 'moved-from' object";
+ break;
+ case MK_Move:
+ ErrorMessage = "Moving a 'moved-from' object";
+ break;
+ }
+ 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 assignment
+ // 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)) {
+ if(CtorDec->isMoveConstructor())
+ N = reportBug(ArgRegion, Call, C, MK_Move);
+ else
+ N = reportBug(ArgRegion, Call, C, MK_Copy);
+ 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 (!ThisRegion)
+ return;
+
+ if (dyn_cast_or_null<CXXDestructorDecl>(Call.getDecl())) {
+ State = removeFromState(State, ThisRegion);
+ 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();
+ if(MethodDecl->isMoveAssignmentOperator())
+ N = reportBug(ArgRegion, Call, C, MK_Move);
+ else
+ N = reportBug(ArgRegion, Call, C, MK_Copy);
+ 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.
+
+ // We want to investigate the whole object, not only sub-object of a parent
+ // class in which the encountered method defined.
+ while (const CXXBaseObjectRegion *BR =
+ dyn_cast<CXXBaseObjectRegion>(ThisRegion))
+ ThisRegion = BR->getSuperRegion();
+
+ if (isMoveSafeMethod(MethodDecl))
+ return;
+
+ if (isStateResetMethod(MethodDecl)) {
+ State = removeFromState(State, ThisRegion);
+ C.addTransition(State);
+ return;
+ }
+
+ // If it is already reported then we don't report the bug again.
+ const RegionState *ThisState = State->get<TrackedRegionMap>(ThisRegion);
+ if (!(ThisState && ThisState->isMoved()))
+ return;
+
+ // Don't 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, MK_FunCall);
+ 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 MisusedMovedObjectChecker::printState(raw_ostream &Out,
+ ProgramStateRef State,
+ const char *NL,
+ const char *Sep) const {
+
+ TrackedRegionMapTy RS = State->get<TrackedRegionMap>();
+
+ if (!RS.isEmpty()) {
+ Out << Sep << "Moved-from objects :" << NL;
+ for (auto I: RS) {
+ I.first->dumpToStream(Out);
+ if (I.second.isMoved())
+ Out << ": moved";
+ else
+ Out << ": moved and reported";
+ Out << NL;
+ }
+ }
+}
+void ento::registerMisusedMovedObjectChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MisusedMovedObjectChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index c1deadef42..8a5c769b6b 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -123,14 +123,14 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
case 4:
lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
"handleFailureInFunction", "file", "lineNumber",
- "description", nullptr);
+ "description");
if (Sel != HandleFailureInFunctionSel)
return;
break;
case 5:
lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
"handleFailureInMethod", "object", "file",
- "lineNumber", "description", nullptr);
+ "lineNumber", "description");
if (Sel != HandleFailureInMethodSel)
return;
break;
diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index 1f82ab94af..6d05159e51 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/NonnullGlobalConstantsChecker.cpp b/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
new file mode 100644
index 0000000000..0b4ecb41d2
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
@@ -0,0 +1,140 @@
+//==- NonnullGlobalConstantsChecker.cpp ---------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker adds an assumption that constant globals of certain types* are
+// non-null, as otherwise they generally do not convey any useful information.
+// The assumption is useful, as many framework use e. g. global const strings,
+// and the analyzer might not be able to infer the global value if the
+// definition is in a separate translation unit.
+// The following types (and their typedef aliases) are considered to be
+// non-null:
+// - `char* const`
+// - `const CFStringRef` from CoreFoundation
+// - `NSString* const` from Foundation
+// - `CFBooleanRef` from Foundation
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.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/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class NonnullGlobalConstantsChecker : public Checker<check::Location> {
+ mutable IdentifierInfo *NSStringII = nullptr;
+ mutable IdentifierInfo *CFStringRefII = nullptr;
+ mutable IdentifierInfo *CFBooleanRefII = nullptr;
+
+public:
+ NonnullGlobalConstantsChecker() {}
+
+ void checkLocation(SVal l, bool isLoad, const Stmt *S,
+ CheckerContext &C) const;
+
+private:
+ void initIdentifierInfo(ASTContext &Ctx) const;
+
+ bool isGlobalConstString(SVal V) const;
+
+ bool isNonnullType(QualType Ty) const;
+};
+
+} // namespace
+
+/// Lazily initialize cache for required identifier informations.
+void NonnullGlobalConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const {
+ if (NSStringII)
+ return;
+
+ NSStringII = &Ctx.Idents.get("NSString");
+ CFStringRefII = &Ctx.Idents.get("CFStringRef");
+ CFBooleanRefII = &Ctx.Idents.get("CFBooleanRef");
+}
+
+/// Add an assumption that const string-like globals are non-null.
+void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad,
+ const Stmt *S,
+ CheckerContext &C) const {
+ initIdentifierInfo(C.getASTContext());
+ if (!isLoad || !location.isValid())
+ return;
+
+ ProgramStateRef State = C.getState();
+ SVal V = State->getSVal(location.castAs<Loc>());
+
+ if (isGlobalConstString(location)) {
+ Optional<DefinedOrUnknownSVal> Constr = V.getAs<DefinedOrUnknownSVal>();
+
+ if (Constr) {
+
+ // Assume that the variable is non-null.
+ ProgramStateRef OutputState = State->assume(*Constr, true);
+ C.addTransition(OutputState);
+ }
+ }
+}
+
+/// \param V loaded lvalue.
+/// \return whether {@code val} is a string-like const global.
+bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const {
+ Optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>();
+ if (!RegionVal)
+ return false;
+ auto *Region = dyn_cast<VarRegion>(RegionVal->getAsRegion());
+ if (!Region)
+ return false;
+ const VarDecl *Decl = Region->getDecl();
+
+ if (!Decl->hasGlobalStorage())
+ return false;
+
+ QualType Ty = Decl->getType();
+ bool HasConst = Ty.isConstQualified();
+ if (isNonnullType(Ty) && HasConst)
+ return true;
+
+ // Look through the typedefs.
+ while (auto *T = dyn_cast<TypedefType>(Ty)) {
+ Ty = T->getDecl()->getUnderlyingType();
+
+ // It is sufficient for any intermediate typedef
+ // to be classified const.
+ HasConst = HasConst || Ty.isConstQualified();
+ if (isNonnullType(Ty) && HasConst)
+ return true;
+ }
+ return false;
+}
+
+/// \return whether {@code type} is extremely unlikely to be null
+bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const {
+
+ if (Ty->isPointerType() && Ty->getPointeeType()->isCharType())
+ return true;
+
+ if (auto *T = dyn_cast<ObjCObjectPointerType>(Ty)) {
+ return T->getInterfaceDecl() &&
+ T->getInterfaceDecl()->getIdentifier() == NSStringII;
+ } else if (auto *T = dyn_cast<TypedefType>(Ty)) {
+ IdentifierInfo* II = T->getDecl()->getIdentifier();
+ return II == CFStringRefII || II == CFBooleanRefII;
+ }
+ return false;
+}
+
+void ento::registerNonnullGlobalConstantsChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<NonnullGlobalConstantsChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index c14a87c9d2..fa9a317683 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.
@@ -178,7 +178,7 @@ private:
const MemRegion *Region, BugReporter &BR,
const Stmt *ValueExpr = nullptr) const {
if (!BT)
- BT.reset(new BugType(this, "Nullability", "Memory error"));
+ BT.reset(new BugType(this, "Nullability", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
if (Region) {
@@ -326,7 +326,7 @@ NullabilityChecker::NullabilityBugVisitor::VisitNode(const ExplodedNode *N,
// Retrieve the associated statement.
const Stmt *S = TrackedNullab->getNullabilitySource();
- if (!S) {
+ if (!S || S->getLocStart().isInvalid()) {
S = PathDiagnosticLocation::getStmt(N);
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index b10ec848ee..e4737fcee7 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 7ef79c683c..dab29be1c8 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -25,7 +25,13 @@ using namespace ento;
namespace {
struct LockState {
- enum Kind { Destroyed, Locked, Unlocked } K;
+ enum Kind {
+ Destroyed,
+ Locked,
+ Unlocked,
+ UntouchedAndPossiblyDestroyed,
+ UnlockedAndPossiblyDestroyed
+ } K;
private:
LockState(Kind K) : K(K) {}
@@ -34,6 +40,12 @@ public:
static LockState getLocked() { return LockState(Locked); }
static LockState getUnlocked() { return LockState(Unlocked); }
static LockState getDestroyed() { return LockState(Destroyed); }
+ static LockState getUntouchedAndPossiblyDestroyed() {
+ return LockState(UntouchedAndPossiblyDestroyed);
+ }
+ static LockState getUnlockedAndPossiblyDestroyed() {
+ return LockState(UnlockedAndPossiblyDestroyed);
+ }
bool operator==(const LockState &X) const {
return K == X.K;
@@ -42,13 +54,20 @@ public:
bool isLocked() const { return K == Locked; }
bool isUnlocked() const { return K == Unlocked; }
bool isDestroyed() const { return K == Destroyed; }
+ bool isUntouchedAndPossiblyDestroyed() const {
+ return K == UntouchedAndPossiblyDestroyed;
+ }
+ bool isUnlockedAndPossiblyDestroyed() const {
+ return K == UnlockedAndPossiblyDestroyed;
+ }
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(K);
}
};
-class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
+class PthreadLockChecker
+ : public Checker<check::PostStmt<CallExpr>, check::DeadSymbols> {
mutable std::unique_ptr<BugType> BT_doublelock;
mutable std::unique_ptr<BugType> BT_doubleunlock;
mutable std::unique_ptr<BugType> BT_destroylock;
@@ -61,22 +80,33 @@ class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
};
public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ void printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const override;
void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
bool isTryLock, enum LockingSemantics semantics) const;
void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
- void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
+ void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock,
+ enum LockingSemantics semantics) const;
void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const;
+ ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
+ const MemRegion *lockR,
+ const SymbolRef *sym) const;
};
} // end anonymous namespace
-// GDM Entry for tracking lock state.
+// A stack of locks for tracking lock-unlock order.
REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
+// An entry for tracking lock states.
REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState)
+// Return values for unresolved calls to pthread_mutex_destroy().
+REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef)
+
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
@@ -113,13 +143,82 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
FName == "lck_mtx_unlock" ||
FName == "lck_rw_done")
ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
- else if (FName == "pthread_mutex_destroy" ||
- FName == "lck_mtx_destroy")
- DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
+ else if (FName == "pthread_mutex_destroy")
+ DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx), PthreadSemantics);
+ else if (FName == "lck_mtx_destroy")
+ DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx), XNUSemantics);
else if (FName == "pthread_mutex_init")
InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
}
+// When a lock is destroyed, in some semantics(like PthreadSemantics) we are not
+// sure if the destroy call has succeeded or failed, and the lock enters one of
+// the 'possibly destroyed' state. There is a short time frame for the
+// programmer to check the return value to see if the lock was successfully
+// destroyed. Before we model the next operation over that lock, we call this
+// function to see if the return value was checked by now and set the lock state
+// - either to destroyed state or back to its previous state.
+
+// In PthreadSemantics, pthread_mutex_destroy() returns zero if the lock is
+// successfully destroyed and it returns a non-zero value otherwise.
+ProgramStateRef PthreadLockChecker::resolvePossiblyDestroyedMutex(
+ ProgramStateRef state, const MemRegion *lockR, const SymbolRef *sym) const {
+ const LockState *lstate = state->get<LockMap>(lockR);
+ // Existence in DestroyRetVal ensures existence in LockMap.
+ // Existence in Destroyed also ensures that the lock state for lockR is either
+ // UntouchedAndPossiblyDestroyed or UnlockedAndPossiblyDestroyed.
+ assert(lstate->isUntouchedAndPossiblyDestroyed() ||
+ lstate->isUnlockedAndPossiblyDestroyed());
+
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal retZero = CMgr.isNull(state, *sym);
+ if (retZero.isConstrainedFalse()) {
+ if (lstate->isUntouchedAndPossiblyDestroyed())
+ state = state->remove<LockMap>(lockR);
+ else if (lstate->isUnlockedAndPossiblyDestroyed())
+ state = state->set<LockMap>(lockR, LockState::getUnlocked());
+ } else
+ state = state->set<LockMap>(lockR, LockState::getDestroyed());
+
+ // Removing the map entry (lockR, sym) from DestroyRetVal as the lock state is
+ // now resolved.
+ state = state->remove<DestroyRetVal>(lockR);
+ return state;
+}
+
+void PthreadLockChecker::printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const {
+ LockMapTy LM = State->get<LockMap>();
+ if (!LM.isEmpty()) {
+ Out << Sep << "Mutex states:" << NL;
+ for (auto I : LM) {
+ I.first->dumpToStream(Out);
+ if (I.second.isLocked())
+ Out << ": locked";
+ else if (I.second.isUnlocked())
+ Out << ": unlocked";
+ else if (I.second.isDestroyed())
+ Out << ": destroyed";
+ else if (I.second.isUntouchedAndPossiblyDestroyed())
+ Out << ": not tracked, possibly destroyed";
+ else if (I.second.isUnlockedAndPossiblyDestroyed())
+ Out << ": unlocked, possibly destroyed";
+ Out << NL;
+ }
+ }
+
+ LockSetTy LS = State->get<LockSet>();
+ if (!LS.isEmpty()) {
+ Out << Sep << "Mutex lock order:" << NL;
+ for (auto I: LS) {
+ I->dumpToStream(Out);
+ Out << NL;
+ }
+ }
+
+ // TODO: Dump destroyed mutex symbols?
+}
+
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
SVal lock, bool isTryLock,
enum LockingSemantics semantics) const {
@@ -129,6 +228,9 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
+ const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
+ if (sym)
+ state = resolvePossiblyDestroyedMutex(state, lockR, sym);
SVal X = state->getSVal(CE, C.getLocationContext());
if (X.isUnknownOrUndef())
@@ -197,6 +299,9 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
+ const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
+ if (sym)
+ state = resolvePossiblyDestroyedMutex(state, lockR, sym);
if (const LockState *LState = state->get<LockMap>(lockR)) {
if (LState->isUnlocked()) {
@@ -245,7 +350,8 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
}
void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
- SVal Lock) const {
+ SVal Lock,
+ enum LockingSemantics semantics) const {
const MemRegion *LockR = Lock.getAsRegion();
if (!LockR)
@@ -253,13 +359,38 @@ void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State = C.getState();
+ const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
+ if (sym)
+ State = resolvePossiblyDestroyedMutex(State, LockR, sym);
+
const LockState *LState = State->get<LockMap>(LockR);
- if (!LState || LState->isUnlocked()) {
- State = State->set<LockMap>(LockR, LockState::getDestroyed());
- C.addTransition(State);
- return;
+ // Checking the return value of the destroy method only in the case of
+ // PthreadSemantics
+ if (semantics == PthreadSemantics) {
+ if (!LState || LState->isUnlocked()) {
+ SymbolRef sym = C.getSVal(CE).getAsSymbol();
+ if (!sym) {
+ State = State->remove<LockMap>(LockR);
+ C.addTransition(State);
+ return;
+ }
+ State = State->set<DestroyRetVal>(LockR, sym);
+ if (LState && LState->isUnlocked())
+ State = State->set<LockMap>(
+ LockR, LockState::getUnlockedAndPossiblyDestroyed());
+ else
+ State = State->set<LockMap>(
+ LockR, LockState::getUntouchedAndPossiblyDestroyed());
+ C.addTransition(State);
+ return;
+ }
+ } else {
+ if (!LState || LState->isUnlocked()) {
+ State = State->set<LockMap>(LockR, LockState::getDestroyed());
+ C.addTransition(State);
+ return;
+ }
}
-
StringRef Message;
if (LState->isLocked()) {
@@ -288,6 +419,10 @@ void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State = C.getState();
+ const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
+ if (sym)
+ State = resolvePossiblyDestroyedMutex(State, LockR, sym);
+
const struct LockState *LState = State->get<LockMap>(LockR);
if (!LState || LState->isDestroyed()) {
State = State->set<LockMap>(LockR, LockState::getUnlocked());
@@ -328,6 +463,26 @@ void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
C.emitReport(std::move(Report));
}
+void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ // TODO: Clean LockMap when a mutex region dies.
+
+ DestroyRetValTy TrackedSymbols = State->get<DestroyRetVal>();
+ for (DestroyRetValTy::iterator I = TrackedSymbols.begin(),
+ E = TrackedSymbols.end();
+ I != E; ++I) {
+ const SymbolRef Sym = I->second;
+ const MemRegion *lockR = I->first;
+ bool IsSymDead = SymReaper.isDead(Sym);
+ // Remove the dead symbol from the return value symbols map.
+ if (IsSymDead)
+ State = resolvePossiblyDestroyedMutex(State, lockR, &Sym);
+ }
+ C.addTransition(State);
+}
+
void ento::registerPthreadLockChecker(CheckerManager &mgr) {
mgr.registerChecker<PthreadLockChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 3f6ae6222c..4db83af17f 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -462,6 +462,7 @@ private:
ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; }
friend class RetainSummaryManager;
+ friend class RetainCountChecker;
};
} // end anonymous namespace
@@ -703,31 +704,30 @@ private:
ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
+ template <typename... Keywords>
void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
- const RetainSummary *Summ, va_list argp) {
- Selector S = getKeywordSelector(Ctx, argp);
+ const RetainSummary *Summ, Keywords *... Kws) {
+ Selector S = getKeywordSelector(Ctx, Kws...);
Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
- void addInstMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
- va_list argp;
- va_start(argp, Summ);
- addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
- va_end(argp);
+ template <typename... Keywords>
+ void addInstMethSummary(const char *Cls, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...);
}
- void addClsMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
- va_list argp;
- va_start(argp, Summ);
- addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp);
- va_end(argp);
+ template <typename... Keywords>
+ void addClsMethSummary(const char *Cls, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCClassMethodSummaries, Summ,
+ Kws...);
}
- void addClsMethSummary(IdentifierInfo *II, const RetainSummary * Summ, ...) {
- va_list argp;
- va_start(argp, Summ);
- addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp);
- va_end(argp);
+ template <typename... Keywords>
+ void addClsMethSummary(IdentifierInfo *II, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...);
}
public:
@@ -1062,6 +1062,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
// Inspect the result type.
QualType RetTy = FT->getReturnType();
+ std::string RetTyName = RetTy.getAsString();
// FIXME: This should all be refactored into a chain of "summary lookup"
// filters.
@@ -1081,12 +1082,14 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
AllowAnnotations = false;
} else if (FName == "CFPlugInInstanceCreate") {
S = getPersistentSummary(RetEffect::MakeNoRet());
- } else if (FName == "IOBSDNameMatching" ||
+ } else if (FName == "IORegistryEntrySearchCFProperty"
+ || (RetTyName == "CFMutableDictionaryRef" && (
+ FName == "IOBSDNameMatching" ||
FName == "IOServiceMatching" ||
FName == "IOServiceNameMatching" ||
- FName == "IORegistryEntrySearchCFProperty" ||
FName == "IORegistryEntryIDMatching" ||
- FName == "IOOpenFirmwarePathMatching") {
+ FName == "IOOpenFirmwarePathMatching"
+ ))) {
// Part of <rdar://problem/6961230>. (IOKit)
// This should be addressed using a API table.
S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF),
@@ -1167,6 +1170,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName)) {
S = getUnarySummary(FT, cfretain);
+ // CFRetain isn't supposed to be annotated. However, this may as well
+ // be a user-made "safe" CFRetain function that is incorrectly
+ // annotated as cf_returns_retained due to lack of better options.
+ // We want to ignore such annotation.
+ AllowAnnotations = false;
} else if (isAutorelease(FD, FName)) {
S = getUnarySummary(FT, cfautorelease);
// The headers use cf_consumed, but we can fully model CFAutorelease
@@ -1211,7 +1219,8 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
// Check for release functions, the only kind of functions that we care
// about that don't return a pointer type.
- if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) {
+ if (FName.size() >= 2 &&
+ FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) {
// Test for 'CGCF'.
FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
@@ -1305,6 +1314,28 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
DoNothing, DoNothing);
}
+/// Returns true if the declaration 'D' is annotated with 'rcAnnotation'.
+static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
+ for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
+ if (Ann->getAnnotation() == rcAnnotation)
+ return true;
+ }
+ return false;
+}
+
+/// Returns true if the function declaration 'FD' contains
+/// 'rc_ownership_trusted_implementation' annotate attribute.
+static bool isTrustedReferenceCountImplementation(const FunctionDecl *FD) {
+ return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
+}
+
+static bool isGeneralizedObjectRef(QualType Ty) {
+ if (Ty.getAsString().substr(0, 4) == "isl_")
+ return true;
+ else
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
@@ -1326,6 +1357,8 @@ RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
if (D->hasAttr<CFReturnsRetainedAttr>())
return RetEffect::MakeOwned(RetEffect::CF);
+ else if (hasRCAnnotation(D, "rc_ownership_returns_retained"))
+ return RetEffect::MakeOwned(RetEffect::Generalized);
if (D->hasAttr<CFReturnsNotRetainedAttr>())
return RetEffect::MakeNotOwned(RetEffect::CF);
@@ -1349,9 +1382,11 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const ParmVarDecl *pd = *pi;
if (pd->hasAttr<NSConsumedAttr>())
Template->addArg(AF, parm_idx, DecRefMsg);
- else if (pd->hasAttr<CFConsumedAttr>())
+ else if (pd->hasAttr<CFConsumedAttr>() ||
+ hasRCAnnotation(pd, "rc_ownership_consumed"))
Template->addArg(AF, parm_idx, DecRef);
- else if (pd->hasAttr<CFReturnsRetainedAttr>()) {
+ else if (pd->hasAttr<CFReturnsRetainedAttr>() ||
+ hasRCAnnotation(pd, "rc_ownership_returns_retained")) {
QualType PointeeTy = pd->getType()->getPointeeType();
if (!PointeeTy.isNull())
if (coreFoundation::isCFObjectRef(PointeeTy))
@@ -1640,20 +1675,16 @@ void RetainSummaryManager::InitializeMethodSummaries() {
addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
- addInstMethSummary("QCRenderer", AllocSumm,
- "createSnapshotImageOfType", nullptr);
- addInstMethSummary("QCView", AllocSumm,
- "createSnapshotImageOfType", nullptr);
+ addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
+ addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
// Create summaries for CIContext, 'createCGImage' and
// 'createCGLayerWithSize'. These objects are CF objects, and are not
// automatically garbage collected.
- addInstMethSummary("CIContext", CFAllocSumm,
- "createCGImage", "fromRect", nullptr);
+ addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");
addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
- "format", "colorSpace", nullptr);
- addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info",
- nullptr);
+ "format", "colorSpace");
+ addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
}
//===----------------------------------------------------------------------===//
@@ -1834,6 +1865,15 @@ namespace {
class CFRefLeakReport : public CFRefReport {
const MemRegion* AllocBinding;
+ const Stmt *AllocStmt;
+
+ // Finds the function declaration where a leak warning for the parameter 'sym' should be raised.
+ void deriveParamLocation(CheckerContext &Ctx, SymbolRef sym);
+ // Finds the location where a leak warning for 'sym' should be raised.
+ void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym);
+ // Produces description of a leak warning which is printed on the console.
+ void createDescription(CheckerContext &Ctx, bool GCEnabled, bool IncludeAllocationLine);
+
public:
CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
@@ -1989,17 +2029,15 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
}
if (CurrV.getObjKind() == RetEffect::CF) {
- if (Sym->getType().isNull()) {
- os << " returns a Core Foundation object with a ";
- } else {
- os << " returns a Core Foundation object of type "
- << Sym->getType().getAsString() << " with a ";
- }
- }
- else {
+ os << " returns a Core Foundation object of type "
+ << Sym->getType().getAsString() << " with a ";
+ } else if (CurrV.getObjKind() == RetEffect::Generalized) {
+ os << " returns an object of type " << Sym->getType().getAsString()
+ << " with a ";
+ } else {
assert (CurrV.getObjKind() == RetEffect::ObjC);
QualType T = Sym->getType();
- if (T.isNull() || !isa<ObjCObjectPointerType>(T)) {
+ if (!isa<ObjCObjectPointerType>(T)) {
os << " returns an Objective-C object with a ";
} else {
const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
@@ -2415,13 +2453,25 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
return llvm::make_unique<PathDiagnosticEventPiece>(L, os.str());
}
-CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
- bool GCEnabled, const SummaryLogTy &Log,
- ExplodedNode *n, SymbolRef sym,
- CheckerContext &Ctx,
- bool IncludeAllocationLine)
- : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) {
+void CFRefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
+ const SourceManager& SMgr = Ctx.getSourceManager();
+
+ if (!sym->getOriginRegion())
+ return;
+
+ auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
+ if (Region) {
+ const Decl *PDecl = Region->getDecl();
+ if (PDecl && isa<ParmVarDecl>(PDecl)) {
+ PathDiagnosticLocation ParamLocation = PathDiagnosticLocation::create(PDecl, SMgr);
+ Location = ParamLocation;
+ UniqueingLocation = ParamLocation;
+ UniqueingDecl = Ctx.getLocationContext()->getDecl();
+ }
+ }
+}
+void CFRefLeakReport::deriveAllocLocation(CheckerContext &Ctx,SymbolRef sym) {
// Most bug reports are cached at the location where they occurred.
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path. To do this, we need to find
@@ -2445,8 +2495,12 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// FIXME: This will crash the analyzer if an allocation comes from an
// implicit call (ex: a destructor call).
// (Currently there are no such allocations in Cocoa, though.)
- const Stmt *AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
- assert(AllocStmt && "Cannot find allocation statement");
+ AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
+
+ if (!AllocStmt) {
+ AllocBinding = nullptr;
+ return;
+ }
PathDiagnosticLocation AllocLocation =
PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
@@ -2457,8 +2511,10 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// leaks should be uniqued on the allocation site.
UniqueingLocation = AllocLocation;
UniqueingDecl = AllocNode->getLocationContext()->getDecl();
+}
- // Fill in the description of the bug.
+void CFRefLeakReport::createDescription(CheckerContext &Ctx, bool GCEnabled, bool IncludeAllocationLine) {
+ assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
Description.clear();
llvm::raw_string_ostream os(Description);
os << "Potential leak ";
@@ -2473,6 +2529,20 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
os << " (allocated on line " << SL.getSpellingLineNumber() << ")";
}
}
+}
+
+CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
+ bool GCEnabled, const SummaryLogTy &Log,
+ ExplodedNode *n, SymbolRef sym,
+ CheckerContext &Ctx,
+ bool IncludeAllocationLine)
+ : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) {
+
+ deriveAllocLocation(Ctx, sym);
+ if (!AllocBinding)
+ deriveParamLocation(Ctx, sym);
+
+ createDescription(Ctx, GCEnabled, IncludeAllocationLine);
addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, GCEnabled, Log));
}
@@ -2486,6 +2556,7 @@ class RetainCountChecker
: public Checker< check::Bind,
check::DeadSymbols,
check::EndAnalysis,
+ check::BeginFunction,
check::EndFunction,
check::PostStmt<BlockExpr>,
check::PostStmt<CastExpr>,
@@ -2670,6 +2741,7 @@ public:
SymbolRef Sym, ProgramStateRef state) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+ void checkBeginFunction(CheckerContext &C) const;
void checkEndFunction(CheckerContext &C) const;
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
@@ -3385,6 +3457,9 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// See if it's one of the specific functions we know how to eval.
bool canEval = false;
+ // See if the function has 'rc_ownership_trusted_implementation'
+ // annotate attribute. If it does, we will not inline it.
+ bool hasTrustedImplementationAnnotation = false;
QualType ResultTy = CE->getCallReturnType(C.getASTContext());
if (ResultTy->isObjCIdType()) {
@@ -3400,6 +3475,11 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
cocoa::isRefType(ResultTy, "CV", FName)) {
canEval = isRetain(FD, FName) || isAutorelease(FD, FName) ||
isMakeCollectable(FD, FName);
+ } else {
+ if (FD->getDefinition()) {
+ canEval = isTrustedReferenceCountImplementation(FD->getDefinition());
+ hasTrustedImplementationAnnotation = canEval;
+ }
}
}
@@ -3409,8 +3489,11 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Bind the return value.
const LocationContext *LCtx = C.getLocationContext();
SVal RetVal = state->getSVal(CE->getArg(0), LCtx);
- if (RetVal.isUnknown()) {
- // If the receiver is unknown, conjure a return value.
+ if (RetVal.isUnknown() ||
+ (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
+ // If the receiver is unknown or the function has
+ // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
+ // return value.
SValBuilder &SVB = C.getSValBuilder();
RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
}
@@ -3426,8 +3509,9 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
Binding = getRefBinding(state, Sym);
// Invalidate the argument region.
- state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx,
- /*CausesPointerEscape*/ false);
+ state = state->invalidateRegions(
+ ArgRegion, CE, C.blockCount(), LCtx,
+ /*CausesPointerEscape*/ hasTrustedImplementationAnnotation);
// Restore the refcount status of the argument.
if (Binding)
@@ -3879,6 +3963,36 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
return N;
}
+void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
+ if (!Ctx.inTopFrame())
+ return;
+
+ const LocationContext *LCtx = Ctx.getLocationContext();
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
+
+ if (!FD || isTrustedReferenceCountImplementation(FD))
+ return;
+
+ ProgramStateRef state = Ctx.getState();
+
+ const RetainSummary *FunctionSummary = getSummaryManager(Ctx).getFunctionSummary(FD);
+ ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
+
+ for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) {
+ const ParmVarDecl *Param = FD->getParamDecl(idx);
+ SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
+
+ QualType Ty = Param->getType();
+ const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
+ if (AE && *AE == DecRef && isGeneralizedObjectRef(Ty))
+ state = setRefBinding(state, Sym, RefVal::makeOwned(RetEffect::ObjKind::Generalized, Ty));
+ else if (isGeneralizedObjectRef(Ty))
+ state = setRefBinding(state, Sym, RefVal::makeNotOwned(RetEffect::ObjKind::Generalized, Ty));
+ }
+
+ Ctx.addTransition(state);
+}
+
void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
RefBindingsTy B = state->get<RefBindings>();
diff --git a/lib/StaticAnalyzer/Checkers/SelectorExtras.h b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
index 41f70d7d5b..b11d070c62 100644
--- a/lib/StaticAnalyzer/Checkers/SelectorExtras.h
+++ b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
@@ -11,48 +11,26 @@
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H
#include "clang/AST/ASTContext.h"
-#include <cstdarg>
namespace clang {
namespace ento {
-static inline Selector getKeywordSelectorImpl(ASTContext &Ctx,
- const char *First,
- va_list argp) {
- SmallVector<IdentifierInfo*, 10> II;
- II.push_back(&Ctx.Idents.get(First));
-
- while (const char *s = va_arg(argp, const char *))
- II.push_back(&Ctx.Idents.get(s));
+template <typename... IdentifierInfos>
+static inline Selector getKeywordSelector(ASTContext &Ctx,
+ IdentifierInfos *... IIs) {
+ static_assert(sizeof...(IdentifierInfos),
+ "keyword selectors must have at least one argument");
+ SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
return Ctx.Selectors.getSelector(II.size(), &II[0]);
}
-static inline Selector getKeywordSelector(ASTContext &Ctx, va_list argp) {
- const char *First = va_arg(argp, const char *);
- assert(First && "keyword selectors must have at least one argument");
- return getKeywordSelectorImpl(Ctx, First, argp);
-}
-
-LLVM_END_WITH_NULL
-static inline Selector getKeywordSelector(ASTContext &Ctx,
- const char *First, ...) {
- va_list argp;
- va_start(argp, First);
- Selector result = getKeywordSelectorImpl(Ctx, First, argp);
- va_end(argp);
- return result;
-}
-
-LLVM_END_WITH_NULL
+template <typename... IdentifierInfos>
static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
- const char *First, ...) {
+ IdentifierInfos *... IIs) {
if (!Sel.isNull())
return;
- va_list argp;
- va_start(argp, First);
- Sel = getKeywordSelectorImpl(Ctx, First, argp);
- va_end(argp);
+ Sel = getKeywordSelector(Ctx, IIs...);
}
static inline void lazyInitNullarySelector(Selector &Sel, ASTContext &Ctx,
diff --git a/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 93ad17cffb..2f9f5d2d9c 100644
--- a/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -440,7 +440,10 @@ StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
BasicValueFactory &BVF = SVB.getBasicValueFactory();
initFunctionSummaries(BVF);
- std::string Name = FD->getQualifiedNameAsString();
+ IdentifierInfo *II = FD->getIdentifier();
+ if (!II)
+ return None;
+ StringRef Name = II->getName();
if (Name.empty() || !C.isCLibraryFunction(FD, Name))
return None;
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index f3c2ffc586..172ce346f1 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -59,6 +59,11 @@ static bool isArrayIndexOutOfBounds(CheckerContext &C, const Expr *Ex) {
return StOutBound && !StInBound;
}
+static bool isShiftOverflow(const BinaryOperator *B, CheckerContext &C) {
+ return C.isGreaterOrEqual(
+ B->getRHS(), C.getASTContext().getIntWidth(B->getLHS()->getType()));
+}
+
void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
@@ -97,18 +102,50 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
}
if (Ex) {
- OS << "The " << (isLeft ? "left" : "right")
- << " operand of '"
+ OS << "The " << (isLeft ? "left" : "right") << " operand of '"
<< BinaryOperator::getOpcodeStr(B->getOpcode())
<< "' is a garbage value";
if (isArrayIndexOutOfBounds(C, Ex))
OS << " due to array index out of bounds";
- }
- else {
+ } else {
// Neither operand was undefined, but the result is undefined.
- OS << "The result of the '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' expression is undefined";
+ if ((B->getOpcode() == BinaryOperatorKind::BO_Shl ||
+ B->getOpcode() == BinaryOperatorKind::BO_Shr) &&
+ C.isNegative(B->getRHS())) {
+ OS << "The result of the "
+ << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left"
+ : "right")
+ << " shift is undefined because the right operand is negative";
+ } else if ((B->getOpcode() == BinaryOperatorKind::BO_Shl ||
+ B->getOpcode() == BinaryOperatorKind::BO_Shr) &&
+ isShiftOverflow(B, C)) {
+
+ OS << "The result of the "
+ << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left"
+ : "right")
+ << " shift is undefined due to shifting by ";
+
+ SValBuilder &SB = C.getSValBuilder();
+ const llvm::APSInt *I =
+ SB.getKnownValue(C.getState(), C.getSVal(B->getRHS()));
+ if (!I)
+ OS << "a value that is";
+ else if (I->isUnsigned())
+ OS << '\'' << I->getZExtValue() << "\', which is";
+ else
+ OS << '\'' << I->getSExtValue() << "\', which is";
+
+ OS << " greater or equal to the width of type '"
+ << B->getLHS()->getType().getAsString() << "'.";
+ } else if (B->getOpcode() == BinaryOperatorKind::BO_Shl &&
+ C.isNegative(B->getLHS())) {
+ OS << "The result of the left shift is undefined because the left "
+ "operand is negative";
+ } else {
+ OS << "The result of the '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' expression is undefined";
+ }
}
auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N);
if (Ex) {
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 26bf597bd9..7f9a00ff87 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -45,6 +45,8 @@ class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
mutable Optional<uint64_t> Val_O_CREAT;
public:
+ DefaultBool CheckMisuse, CheckPortability;
+
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
@@ -437,29 +439,42 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
if (FName.empty())
return;
- SubChecker SC =
- llvm::StringSwitch<SubChecker>(FName)
- .Case("open", &UnixAPIChecker::CheckOpen)
- .Case("openat", &UnixAPIChecker::CheckOpenAt)
- .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
- .Case("calloc", &UnixAPIChecker::CheckCallocZero)
- .Case("malloc", &UnixAPIChecker::CheckMallocZero)
- .Case("realloc", &UnixAPIChecker::CheckReallocZero)
- .Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
- .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
- .Case("__builtin_alloca_with_align",
- &UnixAPIChecker::CheckAllocaWithAlignZero)
- .Case("valloc", &UnixAPIChecker::CheckVallocZero)
- .Default(nullptr);
-
- if (SC)
- (this->*SC)(C, CE);
+ if (CheckMisuse) {
+ if (SubChecker SC =
+ llvm::StringSwitch<SubChecker>(FName)
+ .Case("open", &UnixAPIChecker::CheckOpen)
+ .Case("openat", &UnixAPIChecker::CheckOpenAt)
+ .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
+ .Default(nullptr)) {
+ (this->*SC)(C, CE);
+ }
+ }
+ if (CheckPortability) {
+ if (SubChecker SC =
+ llvm::StringSwitch<SubChecker>(FName)
+ .Case("calloc", &UnixAPIChecker::CheckCallocZero)
+ .Case("malloc", &UnixAPIChecker::CheckMallocZero)
+ .Case("realloc", &UnixAPIChecker::CheckReallocZero)
+ .Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
+ .Cases("alloca", "__builtin_alloca",
+ &UnixAPIChecker::CheckAllocaZero)
+ .Case("__builtin_alloca_with_align",
+ &UnixAPIChecker::CheckAllocaWithAlignZero)
+ .Case("valloc", &UnixAPIChecker::CheckVallocZero)
+ .Default(nullptr)) {
+ (this->*SC)(C, CE);
+ }
+ }
}
//===----------------------------------------------------------------------===//
// Registration.
//===----------------------------------------------------------------------===//
-void ento::registerUnixAPIChecker(CheckerManager &mgr) {
- mgr.registerChecker<UnixAPIChecker>();
-}
+#define REGISTER_CHECKER(Name) \
+ void ento::registerUnixAPI##Name##Checker(CheckerManager &mgr) { \
+ mgr.registerChecker<UnixAPIChecker>()->Check##Name = true; \
+ }
+
+REGISTER_CHECKER(Misuse)
+REGISTER_CHECKER(Portability)
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index ccd8e9a18b..6f21e868b1 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -112,7 +112,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
continue;
// Check for false positives
- if (CB->size() > 0 && isInvalidPath(CB, *PM))
+ if (isInvalidPath(CB, *PM))
continue;
// It is good practice to always have a "default" label in a "switch", even
diff --git a/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
index d12ba62580..06c4ef71d8 100644
--- a/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
@@ -256,7 +256,7 @@ void ValistChecker::reportUninitializedAccess(const MemRegion *VAList,
if (!BT_uninitaccess)
BT_uninitaccess.reset(new BugType(CheckNames[CK_Uninitialized],
"Uninitialized va_list",
- "Memory Error"));
+ categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT_uninitaccess, Msg, N);
R->markInteresting(VAList);
R->addVisitor(llvm::make_unique<ValistBugVisitor>(VAList));
@@ -274,7 +274,8 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists,
for (auto Reg : LeakedVALists) {
if (!BT_leakedvalist) {
BT_leakedvalist.reset(new BugType(CheckNames[CK_Unterminated],
- "Leaked va_list", "Memory Error"));
+ "Leaked va_list",
+ categories::MemoryError));
BT_leakedvalist->setSuppressOnSink(true);
}
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index b47762b915..c5010f5378 100644
--- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -14,279 +14,272 @@
#include "ClangSACheckers.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/SaveAndRestore.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
using namespace clang;
using namespace ento;
namespace {
-
-class WalkAST : public StmtVisitor<WalkAST> {
- const CheckerBase *Checker;
- BugReporter &BR;
- AnalysisDeclContext *AC;
-
- /// The root constructor or destructor whose callees are being analyzed.
- const CXXMethodDecl *RootMethod = nullptr;
-
- /// Whether the checker should walk into bodies of called functions.
- /// Controlled by the "Interprocedural" analyzer-config option.
- bool IsInterprocedural = false;
-
- /// Whether the checker should only warn for calls to pure virtual functions
- /// (which is undefined behavior) or for all virtual functions (which may
- /// may result in unexpected behavior).
- bool ReportPureOnly = false;
-
- typedef const CallExpr * WorkListUnit;
- typedef SmallVector<WorkListUnit, 20> DFSWorkList;
-
- /// A vector representing the worklist which has a chain of CallExprs.
- DFSWorkList WList;
-
- // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
- // body has not been visited yet.
- // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
- // body has been visited.
- enum Kind { NotVisited,
- PreVisited, /**< A CallExpr to this FunctionDecl is in the
- worklist, but the body has not yet been
- visited. */
- PostVisited /**< A CallExpr to this FunctionDecl is in the
- worklist, and the body has been visited. */
- };
-
- /// A DenseMap that records visited states of FunctionDecls.
- llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions;
-
- /// The CallExpr whose body is currently being visited. This is used for
- /// generating bug reports. This is null while visiting the body of a
- /// constructor or destructor.
- const CallExpr *visitingCallExpr;
-
-public:
- WalkAST(const CheckerBase *checker, BugReporter &br, AnalysisDeclContext *ac,
- const CXXMethodDecl *rootMethod, bool isInterprocedural,
- bool reportPureOnly)
- : Checker(checker), BR(br), AC(ac), RootMethod(rootMethod),
- IsInterprocedural(isInterprocedural), ReportPureOnly(reportPureOnly),
- visitingCallExpr(nullptr) {
- // Walking should always start from either a constructor or a destructor.
- assert(isa<CXXConstructorDecl>(rootMethod) ||
- isa<CXXDestructorDecl>(rootMethod));
- }
-
- bool hasWork() const { return !WList.empty(); }
-
- /// This method adds a CallExpr to the worklist and marks the callee as
- /// being PreVisited.
- void Enqueue(WorkListUnit WLUnit) {
- const FunctionDecl *FD = WLUnit->getDirectCallee();
- if (!FD || !FD->getBody())
- return;
- Kind &K = VisitedFunctions[FD];
- if (K != NotVisited)
- return;
- K = PreVisited;
- WList.push_back(WLUnit);
+enum class ObjectState : bool { CtorCalled, DtorCalled };
+} // end namespace
+ // FIXME: Ascending over StackFrameContext maybe another method.
+
+namespace llvm {
+template <> struct FoldingSetTrait<ObjectState> {
+ static inline void Profile(ObjectState X, FoldingSetNodeID &ID) {
+ ID.AddInteger(static_cast<int>(X));
}
+};
+} // end namespace llvm
- /// This method returns an item from the worklist without removing it.
- WorkListUnit Dequeue() {
- assert(!WList.empty());
- return WList.back();
- }
+namespace {
+class VirtualCallChecker
+ : public Checker<check::BeginFunction, check::EndFunction, check::PreCall> {
+ mutable std::unique_ptr<BugType> BT;
- void Execute() {
- while (hasWork()) {
- WorkListUnit WLUnit = Dequeue();
- const FunctionDecl *FD = WLUnit->getDirectCallee();
- assert(FD && FD->getBody());
-
- if (VisitedFunctions[FD] == PreVisited) {
- // If the callee is PreVisited, walk its body.
- // Visit the body.
- SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
- Visit(FD->getBody());
-
- // Mark the function as being PostVisited to indicate we have
- // scanned the body.
- VisitedFunctions[FD] = PostVisited;
- continue;
- }
-
- // Otherwise, the callee is PostVisited.
- // Remove it from the worklist.
- assert(VisitedFunctions[FD] == PostVisited);
- WList.pop_back();
+public:
+ // The flag to determine if pure virtual functions should be issued only.
+ DefaultBool IsPureOnly;
+
+ void checkBeginFunction(CheckerContext &C) const;
+ void checkEndFunction(CheckerContext &C) const;
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+private:
+ void registerCtorDtorCallInState(bool IsBeginFunction,
+ CheckerContext &C) const;
+ void reportBug(StringRef Msg, bool PureError, const MemRegion *Reg,
+ CheckerContext &C) const;
+
+ class VirtualBugVisitor : public BugReporterVisitorImpl<VirtualBugVisitor> {
+ private:
+ const MemRegion *ObjectRegion;
+ bool Found;
+
+ public:
+ VirtualBugVisitor(const MemRegion *R) : ObjectRegion(R), Found(false) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ static int X = 0;
+ ID.AddPointer(&X);
+ ID.AddPointer(ObjectRegion);
}
- }
-
- // Stmt visitor methods.
- void VisitCallExpr(CallExpr *CE);
- void VisitCXXMemberCallExpr(CallExpr *CE);
- void VisitStmt(Stmt *S) { VisitChildren(S); }
- void VisitChildren(Stmt *S);
-
- void ReportVirtualCall(const CallExpr *CE, bool isPure);
+ std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+ };
};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// AST walking.
-//===----------------------------------------------------------------------===//
-
-void WalkAST::VisitChildren(Stmt *S) {
- for (Stmt *Child : S->children())
- if (Child)
- Visit(Child);
-}
-
-void WalkAST::VisitCallExpr(CallExpr *CE) {
- VisitChildren(CE);
- if (IsInterprocedural)
- Enqueue(CE);
+} // end namespace
+
+// GDM (generic data map) to the memregion of this for the ctor and dtor.
+REGISTER_MAP_WITH_PROGRAMSTATE(CtorDtorMap, const MemRegion *, ObjectState)
+
+std::shared_ptr<PathDiagnosticPiece>
+VirtualCallChecker::VirtualBugVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ // We need the last ctor/dtor which call the virtual function.
+ // The visitor walks the ExplodedGraph backwards.
+ if (Found)
+ return nullptr;
+
+ ProgramStateRef State = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
+ const CXXConstructorDecl *CD =
+ dyn_cast_or_null<CXXConstructorDecl>(LCtx->getDecl());
+ const CXXDestructorDecl *DD =
+ dyn_cast_or_null<CXXDestructorDecl>(LCtx->getDecl());
+
+ if (!CD && !DD)
+ return nullptr;
+
+ ProgramStateManager &PSM = State->getStateManager();
+ auto &SVB = PSM.getSValBuilder();
+ const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
+ if (!MD)
+ return nullptr;
+ auto ThiSVal =
+ State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame()));
+ const MemRegion *Reg = ThiSVal.castAs<loc::MemRegionVal>().getRegion();
+ if (!Reg)
+ return nullptr;
+ if (Reg != ObjectRegion)
+ return nullptr;
+
+ const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ if (!S)
+ return nullptr;
+ Found = true;
+
+ std::string InfoText;
+ if (CD)
+ InfoText = "This constructor of an object of type '" +
+ CD->getNameAsString() +
+ "' has not returned when the virtual method was called";
+ else
+ InfoText = "This destructor of an object of type '" +
+ DD->getNameAsString() +
+ "' has not returned when the virtual method was called";
+
+ // Generate the extra diagnostic.
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true);
}
-void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
- VisitChildren(CE);
- bool callIsNonVirtual = false;
+// The function to check if a callexpr is a virtual function.
+static bool isVirtualCall(const CallExpr *CE) {
+ bool CallIsNonVirtual = false;
- // Several situations to elide for checking.
- if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
- // If the member access is fully qualified (i.e., X::F), then treat
- // this as a non-virtual call and do not warn.
+ if (const MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
+ // The member access is fully qualified (i.e., X::F).
+ // Treat this as a non-virtual call and do not warn.
if (CME->getQualifier())
- callIsNonVirtual = true;
+ CallIsNonVirtual = true;
- if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
- // Elide analyzing the call entirely if the base pointer is not 'this'.
- if (!isa<CXXThisExpr>(base))
- return;
-
- // If the most derived class is marked final, we know that now subclass
- // can override this member.
- if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
- callIsNonVirtual = true;
+ if (const Expr *Base = CME->getBase()) {
+ // The most derived class is marked final.
+ if (Base->getBestDynamicClassType()->hasAttr<FinalAttr>())
+ CallIsNonVirtual = true;
}
}
- // Get the callee.
const CXXMethodDecl *MD =
dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
- if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
+ if (MD && MD->isVirtual() && !CallIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
!MD->getParent()->hasAttr<FinalAttr>())
- ReportVirtualCall(CE, MD->isPure());
+ return true;
+ return false;
+}
+
+// The BeginFunction callback when enter a constructor or a destructor.
+void VirtualCallChecker::checkBeginFunction(CheckerContext &C) const {
+ registerCtorDtorCallInState(true, C);
+}
- if (IsInterprocedural)
- Enqueue(CE);
+// The EndFunction callback when leave a constructor or a destructor.
+void VirtualCallChecker::checkEndFunction(CheckerContext &C) const {
+ registerCtorDtorCallInState(false, C);
}
-void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
- if (ReportPureOnly && !isPure)
+void VirtualCallChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const auto MC = dyn_cast<CXXMemberCall>(&Call);
+ if (!MC)
return;
- SmallString<100> buf;
- llvm::raw_svector_ostream os(buf);
-
- // FIXME: The interprocedural diagnostic experience here is not good.
- // Ultimately this checker should be re-written to be path sensitive.
- // For now, only diagnose intraprocedurally, by default.
- if (IsInterprocedural) {
- os << "Call Path : ";
- // Name of current visiting CallExpr.
- os << *CE->getDirectCallee();
-
- // Name of the CallExpr whose body is current being walked.
- if (visitingCallExpr)
- os << " <-- " << *visitingCallExpr->getDirectCallee();
- // Names of FunctionDecls in worklist with state PostVisited.
- for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(),
- E = WList.begin(); I != E; --I) {
- const FunctionDecl *FD = (*(I-1))->getDirectCallee();
- assert(FD);
- if (VisitedFunctions[FD] == PostVisited)
- os << " <-- " << *FD;
- }
+ const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
+ if (!MD)
+ return;
+ ProgramStateRef State = C.getState();
+ const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
- os << "\n";
+ if (IsPureOnly && !MD->isPure())
+ return;
+ if (!isVirtualCall(CE))
+ return;
+
+ const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
+ const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
+ if (!ObState)
+ return;
+ // Check if a virtual method is called.
+ // The GDM of constructor and destructor should be true.
+ if (*ObState == ObjectState::CtorCalled) {
+ if (IsPureOnly && MD->isPure())
+ reportBug("Call to pure virtual function during construction", true, Reg,
+ C);
+ else if (!MD->isPure())
+ reportBug("Call to virtual function during construction", false, Reg, C);
+ else
+ reportBug("Call to pure virtual function during construction", false, Reg,
+ C);
}
- PathDiagnosticLocation CELoc =
- PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- SourceRange R = CE->getCallee()->getSourceRange();
+ if (*ObState == ObjectState::DtorCalled) {
+ if (IsPureOnly && MD->isPure())
+ reportBug("Call to pure virtual function during destruction", true, Reg,
+ C);
+ else if (!MD->isPure())
+ reportBug("Call to virtual function during destruction", false, Reg, C);
+ else
+ reportBug("Call to pure virtual function during construction", false, Reg,
+ C);
+ }
+}
- os << "Call to ";
- if (isPure)
- os << "pure ";
+void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
+ CheckerContext &C) const {
+ const auto *LCtx = C.getLocationContext();
+ const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
+ if (!MD)
+ return;
- os << "virtual function during ";
+ ProgramStateRef State = C.getState();
+ auto &SVB = C.getSValBuilder();
- if (isa<CXXConstructorDecl>(RootMethod))
- os << "construction ";
- else
- os << "destruction ";
+ // Enter a constructor, set the corresponding memregion be true.
+ if (isa<CXXConstructorDecl>(MD)) {
+ auto ThiSVal =
+ State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame()));
+ const MemRegion *Reg = ThiSVal.getAsRegion();
+ if (IsBeginFunction)
+ State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
+ else
+ State = State->remove<CtorDtorMap>(Reg);
- if (isPure)
- os << "has undefined behavior";
- else
- os << "will not dispatch to derived class";
+ C.addTransition(State);
+ return;
+ }
- BR.EmitBasicReport(AC->getDecl(), Checker,
- "Call to virtual function during construction or "
- "destruction",
- "C++ Object Lifecycle", os.str(), CELoc, R);
+ // Enter a Destructor, set the corresponding memregion be true.
+ if (isa<CXXDestructorDecl>(MD)) {
+ auto ThiSVal =
+ State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame()));
+ const MemRegion *Reg = ThiSVal.getAsRegion();
+ if (IsBeginFunction)
+ State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
+ else
+ State = State->remove<CtorDtorMap>(Reg);
+
+ C.addTransition(State);
+ return;
+ }
}
-//===----------------------------------------------------------------------===//
-// VirtualCallChecker
-//===----------------------------------------------------------------------===//
-
-namespace {
-class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
-public:
- DefaultBool isInterprocedural;
- DefaultBool isPureOnly;
-
- void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
- BugReporter &BR) const {
- AnalysisDeclContext *ADC = mgr.getAnalysisDeclContext(RD);
-
- // Check the constructors.
- for (const auto *I : RD->ctors()) {
- if (!I->isCopyOrMoveConstructor())
- if (Stmt *Body = I->getBody()) {
- WalkAST walker(this, BR, ADC, I, isInterprocedural, isPureOnly);
- walker.Visit(Body);
- walker.Execute();
- }
- }
+void VirtualCallChecker::reportBug(StringRef Msg, bool IsSink,
+ const MemRegion *Reg,
+ CheckerContext &C) const {
+ ExplodedNode *N;
+ if (IsSink)
+ N = C.generateErrorNode();
+ else
+ N = C.generateNonFatalErrorNode();
- // Check the destructor.
- if (CXXDestructorDecl *DD = RD->getDestructor())
- if (Stmt *Body = DD->getBody()) {
- WalkAST walker(this, BR, ADC, DD, isInterprocedural, isPureOnly);
- walker.Visit(Body);
- walker.Execute();
- }
- }
-};
+ if (!N)
+ return;
+ if (!BT)
+ BT.reset(new BugType(
+ this, "Call to virtual function during construction or destruction",
+ "C++ Object Lifecycle"));
+
+ auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N);
+ Reporter->addVisitor(llvm::make_unique<VirtualBugVisitor>(Reg));
+ C.emitReport(std::move(Reporter));
}
void ento::registerVirtualCallChecker(CheckerManager &mgr) {
VirtualCallChecker *checker = mgr.registerChecker<VirtualCallChecker>();
- checker->isInterprocedural =
- mgr.getAnalyzerOptions().getBooleanOption("Interprocedural", false,
- checker);
- checker->isPureOnly =
- mgr.getAnalyzerOptions().getBooleanOption("PureOnly", false,
- checker);
+ checker->IsPureOnly =
+ mgr.getAnalyzerOptions().getBooleanOption("PureOnly", false, checker);
}
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 54634fdffe..1cc08f0d9f 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -14,29 +14,25 @@ using namespace ento;
void AnalysisManager::anchor() { }
-AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
- const LangOptions &lang,
- const PathDiagnosticConsumers &PDC,
- StoreManagerCreator storemgr,
- ConstraintManagerCreator constraintmgr,
- CheckerManager *checkerMgr,
- AnalyzerOptions &Options,
- CodeInjector *injector)
- : AnaCtxMgr(Options.UnoptimizedCFG,
- /*AddImplicitDtors=*/true,
- /*AddInitializers=*/true,
- Options.includeTemporaryDtorsInCFG(),
- Options.shouldSynthesizeBodies(),
- Options.shouldConditionalizeStaticInitializers(),
- /*addCXXNewAllocator=*/true,
- injector),
- Ctx(ctx),
- Diags(diags),
- LangOpts(lang),
- PathConsumers(PDC),
- CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
- CheckerMgr(checkerMgr),
- options(Options) {
+AnalysisManager::AnalysisManager(
+ ASTContext &ASTCtx, DiagnosticsEngine &diags, const LangOptions &lang,
+ const PathDiagnosticConsumers &PDC, StoreManagerCreator storemgr,
+ ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr,
+ AnalyzerOptions &Options, CodeInjector *injector)
+ : AnaCtxMgr(ASTCtx, Options.UnoptimizedCFG,
+ Options.includeImplicitDtorsInCFG(),
+ /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(),
+ Options.includeLifetimeInCFG(),
+ // Adding LoopExit elements to the CFG is a requirement for loop
+ // unrolling.
+ Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(),
+ Options.shouldSynthesizeBodies(),
+ Options.shouldConditionalizeStaticInitializers(),
+ /*addCXXNewAllocator=*/true,
+ injector),
+ Ctx(ASTCtx), Diags(diags), LangOpts(lang), PathConsumers(PDC),
+ CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
+ CheckerMgr(checkerMgr), options(Options) {
AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
}
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 45ef612ee1..48e3e22af0 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -172,6 +172,22 @@ bool AnalyzerOptions::includeTemporaryDtorsInCFG() {
/* Default = */ false);
}
+bool AnalyzerOptions::includeImplicitDtorsInCFG() {
+ return getBooleanOption(IncludeImplicitDtorsInCFG,
+ "cfg-implicit-dtors",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::includeLifetimeInCFG() {
+ return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime",
+ /* Default = */ false);
+}
+
+bool AnalyzerOptions::includeLoopExitInCFG() {
+ return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit",
+ /* Default = */ false);
+}
+
bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
return getBooleanOption(InlineCXXStandardLibrary,
"c++-stdlib-inlining",
@@ -293,7 +309,7 @@ unsigned AnalyzerOptions::getMaxInlinableSize() {
DefaultValue = 4;
break;
case UMK_Deep:
- DefaultValue = 50;
+ DefaultValue = 100;
break;
}
@@ -332,7 +348,7 @@ unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
DefaultValue = 75000;
break;
case UMK_Deep:
- DefaultValue = 150000;
+ DefaultValue = 225000;
break;
}
MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
@@ -364,6 +380,12 @@ bool AnalyzerOptions::shouldWidenLoops() {
return WidenLoops.getValue();
}
+bool AnalyzerOptions::shouldUnrollLoops() {
+ if (!UnrollLoops.hasValue())
+ UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false);
+ return UnrollLoops.getValue();
+}
+
bool AnalyzerOptions::shouldDisplayNotesAsEvents() {
if (!DisplayNotesAsEvents.hasValue())
DisplayNotesAsEvents =
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index ebbace4e33..ec7a7e9e4b 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -225,6 +225,8 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
// test these conditions symbolically.
// FIXME: Expand these checks to include all undefined behavior.
+ if (V1.isSigned() && V1.isNegative())
+ return nullptr;
if (V2.isSigned() && V2.isNegative())
return nullptr;
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 2114033ba8..4a5d25fc56 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1671,9 +1671,15 @@ static bool GenerateAlternateExtensivePathDiagnostic(
// Add an edge to the start of the function.
const StackFrameContext *CalleeLC = CE->getCalleeContext();
const Decl *D = CalleeLC->getDecl();
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createBegin(D, SM),
- CalleeLC);
+ // Add the edge only when the callee has body. We jump to the beginning
+ // of the *declaration*, however we expect it to be followed by the
+ // body. This isn't the case for autosynthesized property accessors in
+ // Objective-C. No need for a similar extra check for CallExit points
+ // because the exit edge comes from a statement (i.e. return),
+ // not from declaration.
+ if (D->hasBody())
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createBegin(D, SM), CalleeLC);
// Did we visit an entire call?
bool VisitedEntireCall = PD.isWithinCall();
@@ -3304,6 +3310,78 @@ static const CFGBlock *findBlockForNode(const ExplodedNode *N) {
return nullptr;
}
+// Returns true if by simply looking at the block, we can be sure that it
+// results in a sink during analysis. This is useful to know when the analysis
+// was interrupted, and we try to figure out if it would sink eventually.
+// There may be many more reasons why a sink would appear during analysis
+// (eg. checkers may generate sinks arbitrarily), but here we only consider
+// sinks that would be obvious by looking at the CFG.
+static bool isImmediateSinkBlock(const CFGBlock *Blk) {
+ if (Blk->hasNoReturnElement())
+ return true;
+
+ // FIXME: Throw-expressions are currently generating sinks during analysis:
+ // they're not supported yet, and also often used for actually terminating
+ // the program. So we should treat them as sinks in this analysis as well,
+ // at least for now, but once we have better support for exceptions,
+ // we'd need to carefully handle the case when the throw is being
+ // immediately caught.
+ if (std::any_of(Blk->begin(), Blk->end(), [](const CFGElement &Elm) {
+ if (Optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>())
+ if (isa<CXXThrowExpr>(StmtElm->getStmt()))
+ return true;
+ return false;
+ }))
+ return true;
+
+ return false;
+}
+
+// Returns true if by looking at the CFG surrounding the node's program
+// point, we can be sure that any analysis starting from this point would
+// eventually end with a sink. We scan the child CFG blocks in a depth-first
+// manner and see if all paths eventually end up in an immediate sink block.
+static bool isInevitablySinking(const ExplodedNode *N) {
+ const CFG &Cfg = N->getCFG();
+
+ const CFGBlock *StartBlk = findBlockForNode(N);
+ if (!StartBlk)
+ return false;
+ if (isImmediateSinkBlock(StartBlk))
+ return true;
+
+ llvm::SmallVector<const CFGBlock *, 32> DFSWorkList;
+ llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
+
+ DFSWorkList.push_back(StartBlk);
+ while (!DFSWorkList.empty()) {
+ const CFGBlock *Blk = DFSWorkList.back();
+ DFSWorkList.pop_back();
+ Visited.insert(Blk);
+
+ for (const auto &Succ : Blk->succs()) {
+ if (const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
+ if (SuccBlk == &Cfg.getExit()) {
+ // If at least one path reaches the CFG exit, it means that control is
+ // returned to the caller. For now, say that we are not sure what
+ // happens next. If necessary, this can be improved to analyze
+ // the parent StackFrameContext's call site in a similar manner.
+ return false;
+ }
+
+ if (!isImmediateSinkBlock(SuccBlk) && !Visited.count(SuccBlk)) {
+ // If the block has reachable child blocks that aren't no-return,
+ // add them to the worklist.
+ DFSWorkList.push_back(SuccBlk);
+ }
+ }
+ }
+ }
+
+ // Nothing reached the exit. It can only mean one thing: there's no return.
+ return true;
+}
+
static BugReport *
FindReportInEquivalenceClass(BugReportEquivClass& EQ,
SmallVectorImpl<BugReport*> &bugReports) {
@@ -3354,15 +3432,10 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
// See if we are in a no-return CFG block. If so, treat this similarly
// to being post-dominated by a sink. This works better when the analysis
- // is incomplete and we have never reached a no-return function
- // we're post-dominated by.
- // This is not quite enough to handle the incomplete analysis case.
- // We may be post-dominated in subsequent blocks, or even
- // inter-procedurally. However, it is not clear if more complicated
- // cases are generally worth suppressing.
- if (const CFGBlock *B = findBlockForNode(errorNode))
- if (B->hasNoReturnElement())
- continue;
+ // is incomplete and we have never reached the no-return function call(s)
+ // that we'd inevitably bump into on this path.
+ if (isInevitablySinking(errorNode))
+ continue;
// At this point we know that 'N' is not a sink and it has at least one
// successor. Use a DFS worklist to find a non-sink end-of-path node.
@@ -3448,14 +3521,12 @@ void BugReporter::FlushReport(BugReport *exampleReport,
// the BugReporterVisitors may mark this bug as a false positive.
assert(!bugReports.empty());
- MaxBugClassSize =
- std::max(bugReports.size(), static_cast<size_t>(MaxBugClassSize));
+ MaxBugClassSize.updateMax(bugReports.size());
if (!generatePathDiagnostic(*D.get(), PD, bugReports))
return;
- MaxValidBugClassSize =
- std::max(bugReports.size(), static_cast<size_t>(MaxValidBugClassSize));
+ MaxValidBugClassSize.updateMax(bugReports.size());
// Examine the report and see if the last piece is in a header. Reset the
// report location to the last piece in the main source file.
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index c3c3f2ff76..f651596006 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -11,7 +11,7 @@
// enhance the diagnostics reported for a bug.
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -42,46 +42,80 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) {
return false;
}
+/// Given that expression S represents a pointer that would be dereferenced,
+/// try to find a sub-expression from which the pointer came from.
+/// This is used for tracking down origins of a null or undefined value:
+/// "this is null because that is null because that is null" etc.
+/// We wipe away field and element offsets because they merely add offsets.
+/// We also wipe away all casts except lvalue-to-rvalue casts, because the
+/// latter represent an actual pointer dereference; however, we remove
+/// the final lvalue-to-rvalue cast before returning from this function
+/// because it demonstrates more clearly from where the pointer rvalue was
+/// loaded. Examples:
+/// x->y.z ==> x (lvalue)
+/// foo()->y.z ==> foo() (rvalue)
const Expr *bugreporter::getDerefExpr(const Stmt *S) {
- // Pattern match for a few useful cases:
- // a[0], p->f, *p
const Expr *E = dyn_cast<Expr>(S);
if (!E)
return nullptr;
- E = E->IgnoreParenCasts();
while (true) {
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) {
- assert(B->isAssignmentOp());
- E = B->getLHS()->IgnoreParenCasts();
- continue;
- }
- else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) {
- if (U->getOpcode() == UO_Deref)
- return U->getSubExpr()->IgnoreParenCasts();
- }
- else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
- return ME->getBase()->IgnoreParenCasts();
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() == CK_LValueToRValue) {
+ // This cast represents the load we're looking for.
+ break;
+ }
+ E = CE->getSubExpr();
+ } else if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) {
+ // Pointer arithmetic: '*(x + 2)' -> 'x') etc.
+ if (B->getType()->isPointerType()) {
+ if (B->getLHS()->getType()->isPointerType()) {
+ E = B->getLHS();
+ } else if (B->getRHS()->getType()->isPointerType()) {
+ E = B->getRHS();
+ } else {
+ break;
+ }
} else {
- // If we have a member expr with a dot, the base must have been
- // dereferenced.
- return getDerefExpr(ME->getBase());
+ // Probably more arithmetic can be pattern-matched here,
+ // but for now give up.
+ break;
+ }
+ } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) {
+ if (U->getOpcode() == UO_Deref || U->getOpcode() == UO_AddrOf ||
+ (U->isIncrementDecrementOp() && U->getType()->isPointerType())) {
+ // Operators '*' and '&' don't actually mean anything.
+ // We look at casts instead.
+ E = U->getSubExpr();
+ } else {
+ // Probably more arithmetic can be pattern-matched here,
+ // but for now give up.
+ break;
}
}
- else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
- return IvarRef->getBase()->IgnoreParenCasts();
- }
- else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) {
- return AE->getBase();
- }
- else if (isDeclRefExprToReference(E)) {
- return E;
+ // Pattern match for a few useful cases: a[0], p->f, *p etc.
+ else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ E = ME->getBase();
+ } else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
+ E = IvarRef->getBase();
+ } else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) {
+ E = AE->getBase();
+ } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ E = PE->getSubExpr();
+ } else {
+ // Other arbitrary stuff.
+ break;
}
- break;
}
- return nullptr;
+ // Special case: remove the final lvalue-to-rvalue cast, but do not recurse
+ // deeper into the sub-expression. This way we return the lvalue from which
+ // our pointer rvalue was loaded.
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
+ if (CE->getCastKind() == CK_LValueToRValue)
+ E = CE->getSubExpr();
+
+ return E;
}
const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) {
@@ -961,7 +995,24 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
const Expr *Inner = nullptr;
if (const Expr *Ex = dyn_cast<Expr>(S)) {
Ex = Ex->IgnoreParenCasts();
- if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
+
+ // Performing operator `&' on an lvalue expression is essentially a no-op.
+ // Then, if we are taking addresses of fields or elements, these are also
+ // unlikely to matter.
+ // FIXME: There's a hack in our Store implementation that always computes
+ // field offsets around null pointers as if they are always equal to 0.
+ // The idea here is to report accesses to fields as null dereferences
+ // even though the pointer value that's being dereferenced is actually
+ // the offset of the field rather than exactly 0.
+ // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
+ // This code interacts heavily with this hack; otherwise the value
+ // would not be null at all for most fields, so we'd be unable to track it.
+ if (const auto *Op = dyn_cast<UnaryOperator>(Ex))
+ if (Op->getOpcode() == UO_AddrOf && Op->getSubExpr()->isLValue())
+ if (const Expr *DerefEx = getDerefExpr(Op->getSubExpr()))
+ Ex = DerefEx;
+
+ if (Ex && (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)))
Inner = Ex;
}
@@ -1027,7 +1078,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 +1341,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 +1710,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 +1741,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 0b4606ba17..5ac4f942f3 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
@@ -28,6 +35,7 @@ add_clang_library(clangStaticAnalyzerCore
ExprEngineObjC.cpp
FunctionSummary.cpp
HTMLDiagnostics.cpp
+ LoopUnrolling.cpp
LoopWidening.cpp
MemRegion.cpp
PathDiagnostic.cpp
@@ -43,11 +51,21 @@ add_clang_library(clangStaticAnalyzerCore
Store.cpp
SubEngine.cpp
SymbolManager.cpp
+ Z3ConstraintManager.cpp
LINK_LIBS
clangAST
+ clangASTMatchers
clangAnalysis
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 ef824b8a3b..776369be9d 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -21,6 +21,9 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "static-analyzer-call-event"
using namespace clang;
using namespace ento;
@@ -97,9 +100,6 @@ bool CallEvent::hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const {
for (CallEvent::param_type_iterator I = param_type_begin(),
E = param_type_end();
I != E && Idx < NumOfArgs; ++I, ++Idx) {
- if (NumOfArgs <= Idx)
- break;
-
// If the parameter is 0, it's harmless.
if (getArgSVal(Idx).isZeroConstant())
continue;
@@ -211,7 +211,9 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
}
bool CallEvent::isCalled(const CallDescription &CD) const {
- assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported");
+ // FIXME: Add ObjC Message support.
+ if (getKind() == CE_ObjCMessage)
+ return false;
if (!CD.IsLookupDone) {
CD.IsLookupDone = true;
CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName);
@@ -346,6 +348,30 @@ ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const {
return D->parameters();
}
+RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const {
+ const FunctionDecl *FD = getDecl();
+ // Note that the AnalysisDeclContext will have the FunctionDecl with
+ // the definition (if one exists).
+ if (FD) {
+ AnalysisDeclContext *AD =
+ getLocationContext()->getAnalysisDeclContext()->
+ getManager()->getContext(FD);
+ bool IsAutosynthesized;
+ Stmt* Body = AD->getBody(IsAutosynthesized);
+ DEBUG({
+ if (IsAutosynthesized)
+ llvm::dbgs() << "Using autosynthesized body for " << FD->getName()
+ << "\n";
+ });
+ if (Body) {
+ const Decl* Decl = AD->getDecl();
+ return RuntimeDefinition(Decl);
+ }
+ }
+
+ return RuntimeDefinition();
+}
+
void AnyFunctionCall::getInitialStackFrameContents(
const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const {
@@ -695,13 +721,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;
}
}
@@ -955,6 +983,12 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
return RuntimeDefinition();
DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver);
+ if (!DTI.isValid()) {
+ assert(isa<AllocaRegion>(Receiver) &&
+ "Unhandled untyped region class!");
+ return RuntimeDefinition();
+ }
+
QualType DynType = DTI.getType();
CanBeSubClassed = DTI.canBeASubClass();
ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType.getCanonicalType());
diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 548b06ef91..61cbf3854b 100644
--- a/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -99,3 +99,35 @@ StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) {
return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts());
}
+/// Evaluate comparison and return true if it's known that condition is true
+static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp,
+ SVal RHSVal, ProgramStateRef State) {
+ if (LHSVal.isUnknownOrUndef())
+ return false;
+ ProgramStateManager &Mgr = State->getStateManager();
+ if (!LHSVal.getAs<NonLoc>()) {
+ LHSVal = Mgr.getStoreManager().getBinding(State->getStore(),
+ LHSVal.castAs<Loc>());
+ if (LHSVal.isUnknownOrUndef() || !LHSVal.getAs<NonLoc>())
+ return false;
+ }
+
+ SValBuilder &Bldr = Mgr.getSValBuilder();
+ SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal,
+ Bldr.getConditionType());
+ if (Eval.isUnknownOrUndef())
+ return false;
+ ProgramStateRef StTrue, StFalse;
+ std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>());
+ return StTrue && !StFalse;
+}
+
+bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) {
+ DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy);
+ return evalComparison(getSVal(E), BO_GE, V, getState());
+}
+
+bool CheckerContext::isNegative(const Expr *E) {
+ DefinedSVal V = getSValBuilder().makeIntVal(0, false);
+ return evalComparison(getSVal(E), BO_LT, V, getState());
+}
diff --git a/lib/StaticAnalyzer/Core/CommonBugCategories.cpp b/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
index 3cb9323563..421dfa48c9 100644
--- a/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
+++ b/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
@@ -16,5 +16,6 @@ const char * const CoreFoundationObjectiveC = "Core Foundation/Objective-C";
const char * const LogicError = "Logic error";
const char * const MemoryCoreFoundationObjectiveC =
"Memory (Core Foundation/Objective-C)";
+const char * const MemoryError = "Memory error";
const char * const UnixAPI = "Unix API";
}}}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 4e2866c56f..e2e9ddf504 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -274,7 +274,8 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
assert(Loc.getAs<PostStmt>() ||
Loc.getAs<PostInitializer>() ||
Loc.getAs<PostImplicitCall>() ||
- Loc.getAs<CallExitEnd>());
+ Loc.getAs<CallExitEnd>() ||
+ Loc.getAs<LoopExit>());
HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
break;
}
@@ -566,7 +567,8 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
// Do not create extra nodes. Move to the next CFG element.
if (N->getLocation().getAs<PostInitializer>() ||
- N->getLocation().getAs<PostImplicitCall>()) {
+ N->getLocation().getAs<PostImplicitCall>()||
+ N->getLocation().getAs<LoopExit>()) {
WList->enqueue(N, Block, Idx+1);
return;
}
diff --git a/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp b/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
index fd35b664a9..a01ff36a8a 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/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index e2cb52cb41..c6acb9d185 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -13,7 +13,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index a5d8fb7e48..0126e03d60 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -17,6 +17,7 @@
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
@@ -27,6 +28,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
@@ -182,19 +184,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 +234,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 +250,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 +264,47 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
break;
case SubobjectAdjustment::MemberPointerAdjustment:
// FIXME: Unimplemented.
- State->bindDefault(Reg, UnknownVal(), LC);
+ 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, LC);
+ // 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;
}
@@ -326,6 +364,11 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
case CFGElement::TemporaryDtor:
ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
return;
+ case CFGElement::LoopExit:
+ ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred);
+ return;
+ case CFGElement::LifetimeEnds:
+ return;
}
}
@@ -469,6 +512,24 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
+void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+ S->getLocStart(),
+ "Error evaluating end of the loop");
+ ExplodedNodeSet Dst;
+ Dst.Add(Pred);
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ ProgramStateRef NewState = Pred->getState();
+
+ if(AMgr.options.shouldUnrollLoops())
+ NewState = processLoopEnd(S, NewState);
+
+ LoopExit PP(S, Pred->getLocationContext());
+ Bldr.generateNode(PP, NewState, Pred);
+ // Enqueue the new nodes onto the work list.
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
ExplodedNode *Pred) {
const CXXCtorInitializer *BMI = Init.getInitializer();
@@ -766,6 +827,21 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
}
}
+namespace {
+class CollectReachableSymbolsCallback final : public SymbolVisitor {
+ InvalidatedSymbols Symbols;
+
+public:
+ explicit CollectReachableSymbolsCallback(ProgramStateRef State) {}
+ const InvalidatedSymbols &getSymbols() const { return Symbols; }
+
+ bool VisitSymbol(SymbolRef Sym) override {
+ Symbols.insert(Sym);
+ return true;
+ }
+};
+} // end anonymous namespace
+
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet &DstTop) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
@@ -1042,8 +1118,29 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
resultType,
currBldrCtx->blockCount());
- ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
- Bldr2.generateNode(S, N, state);
+ ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result);
+
+ // Escape pointers passed into the list, unless it's an ObjC boxed
+ // expression which is not a boxable C structure.
+ if (!(isa<ObjCBoxedExpr>(Ex) &&
+ !cast<ObjCBoxedExpr>(Ex)->getSubExpr()
+ ->getType()->isRecordType()))
+ for (auto Child : Ex->children()) {
+ assert(Child);
+
+ SVal Val = State->getSVal(Child, LCtx);
+
+ CollectReachableSymbolsCallback Scanner =
+ State->scanReachableSymbols<CollectReachableSymbolsCallback>(
+ Val);
+ const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols();
+
+ State = getCheckerManager().runCheckersForPointerEscape(
+ State, EscapedSymbols,
+ /*CallEvent*/ nullptr, PSK_EscapeOther, nullptr);
+ }
+
+ Bldr2.generateNode(S, N, State);
}
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
@@ -1140,6 +1237,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
}
}
// FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
case Stmt::CallExprClass:
case Stmt::CXXMemberCallExprClass:
@@ -1458,6 +1556,25 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
NodeBuilderWithSinks &nodeBuilder,
ExplodedNode *Pred) {
PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+ // If we reach a loop which has a known bound (and meets
+ // other constraints) then consider completely unrolling it.
+ if(AMgr.options.shouldUnrollLoops()) {
+ unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
+ const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
+ if (Term) {
+ ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
+ Pred, maxBlockVisitOnPath);
+ if (NewState != Pred->getState()) {
+ ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
+ if (!UpdatedNode)
+ return;
+ Pred = UpdatedNode;
+ }
+ }
+ // Is we are inside an unrolled loop then no need the check the counters.
+ if(isUnrolledState(Pred->getState()))
+ return;
+ }
// If this block is terminated by a loop and it has already been visited the
// maximum number of times, widen the loop.
@@ -1868,8 +1985,8 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// Evaluate the LHS of the case value.
llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext());
- assert(V1.getBitWidth() == getContext().getTypeSize(CondE->getType()));
-
+ assert(V1.getBitWidth() == getContext().getIntWidth(CondE->getType()));
+
// Get the RHS of the case, if it exists.
llvm::APSInt V2;
if (const Expr *E = Case->getRHS())
@@ -2156,21 +2273,6 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, *this);
}
-namespace {
-class CollectReachableSymbolsCallback final : public SymbolVisitor {
- InvalidatedSymbols Symbols;
-
-public:
- CollectReachableSymbolsCallback(ProgramStateRef State) {}
- const InvalidatedSymbols &getSymbols() const { return Symbols; }
-
- bool VisitSymbol(SymbolRef Sym) override {
- Symbols.insert(Sym);
- return true;
- }
-};
-} // end anonymous namespace
-
// A value escapes in three possible cases:
// (1) We are binding to something that is not a memory region.
// (2) We are binding to a MemrRegion that does not have stack storage.
@@ -2627,6 +2729,12 @@ struct DOTGraphTraits<ExplodedNode*> :
Out << "Epsilon Point";
break;
+ case ProgramPoint::LoopExitKind: {
+ LoopExit LE = Loc.castAs<LoopExit>();
+ Out << "LoopExit: " << LE.getLoopStmt()->getStmtClassName();
+ break;
+ }
+
case ProgramPoint::PreImplicitCallKind: {
ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PreCall: ";
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index ea4ff916c8..6f1e8391e6 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -980,10 +980,9 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
// transfer functions as "0 == E".
SVal Result;
if (Optional<Loc> LV = V.getAs<Loc>()) {
- Loc X = svalBuilder.makeNull();
+ Loc X = svalBuilder.makeNullWithType(Ex->getType());
Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
- }
- else if (Ex->getType()->isFloatingType()) {
+ } else if (Ex->getType()->isFloatingType()) {
// FIXME: handle floating point types.
Result = UnknownVal();
} else {
@@ -1054,7 +1053,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal =
- svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
+ svalBuilder.conjureSymbolVal(nullptr, U, LCtx,
currBldrCtx->blockCount());
Result = SymVal;
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index ca2e2424b2..03e0095d0e 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -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);
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 39d88bfda1..caf86b26b6 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -447,6 +447,7 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
Bldr.takeNodes(Pred);
NumInlinedCalls++;
+ Engine.FunctionSummaries->bumpNumTimesInlined(D);
// Mark the decl as visited.
if (VisitedCallees)
@@ -868,8 +869,6 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
|| IsRecursive))
return false;
- Engine.FunctionSummaries->bumpNumTimesInlined(D);
-
return true;
}
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index f0f6dd2e43..9b820e81e3 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -44,8 +44,12 @@ class HTMLDiagnostics : public PathDiagnosticConsumer {
bool createdDir, noDir;
const Preprocessor &PP;
AnalyzerOptions &AnalyzerOpts;
+ const bool SupportsCrossFileDiagnostics;
public:
- HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp);
+ HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts,
+ const std::string& prefix,
+ const Preprocessor &pp,
+ bool supportsMultipleFiles);
~HTMLDiagnostics() override { FlushDiagnostics(nullptr); }
@@ -56,6 +60,10 @@ public:
return "HTMLDiagnostics";
}
+ bool supportsCrossFileDiagnostics() const override {
+ return SupportsCrossFileDiagnostics;
+ }
+
unsigned ProcessMacroPiece(raw_ostream &os,
const PathDiagnosticMacroPiece& P,
unsigned num);
@@ -69,21 +77,47 @@ public:
void ReportDiag(const PathDiagnostic& D,
FilesMade *filesMade);
+
+ // Generate the full HTML report
+ std::string GenerateHTML(const PathDiagnostic& D, Rewriter &R,
+ const SourceManager& SMgr, const PathPieces& path,
+ const char *declName);
+
+ // Add HTML header/footers to file specified by FID
+ void FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
+ const SourceManager& SMgr, const PathPieces& path,
+ FileID FID, const FileEntry *Entry, const char *declName);
+
+ // Rewrite the file specified by FID with HTML formatting.
+ void RewriteFile(Rewriter &R, const SourceManager& SMgr,
+ const PathPieces& path, FileID FID);
};
} // end anonymous namespace
HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts,
const std::string& prefix,
- const Preprocessor &pp)
- : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) {
-}
+ const Preprocessor &pp,
+ bool supportsMultipleFiles)
+ : Directory(prefix),
+ createdDir(false),
+ noDir(false),
+ PP(pp),
+ AnalyzerOpts(AnalyzerOpts),
+ SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
PathDiagnosticConsumers &C,
const std::string& prefix,
const Preprocessor &PP) {
- C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP));
+ C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, true));
+}
+
+void ento::createHTMLSingleFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
+ const std::string& prefix,
+ const Preprocessor &PP) {
+ C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, false));
}
//===----------------------------------------------------------------------===//
@@ -121,24 +155,24 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
// First flatten out the entire path to make it easier to use.
PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false);
- // The path as already been prechecked that all parts of the path are
- // from the same file and that it is non-empty.
- const SourceManager &SMgr = path.front()->getLocation().getManager();
+ // The path as already been prechecked that the path is non-empty.
assert(!path.empty());
- FileID FID =
- path.front()->getLocation().asLocation().getExpansionLoc().getFileID();
- assert(FID.isValid());
+ const SourceManager &SMgr = path.front()->getLocation().getManager();
// Create a new rewriter to generate HTML.
Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());
+ // The file for the first path element is considered the main report file, it
+ // will usually be equivalent to SMgr.getMainFileID(); however, it might be a
+ // header when -analyzer-opt-analyze-headers is used.
+ FileID ReportFile = path.front()->getLocation().asLocation().getExpansionLoc().getFileID();
+
// Get the function/method name
SmallString<128> declName("unknown");
int offsetDecl = 0;
if (const Decl *DeclWithIssue = D.getDeclWithIssue()) {
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue))
declName = ND->getDeclName().getAsString();
- }
if (const Stmt *Body = DeclWithIssue->getBody()) {
// Retrieve the relative position of the declaration which will be used
@@ -151,49 +185,144 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
}
}
- // Process the path.
- // Maintain the counts of extra note pieces separately.
- unsigned TotalPieces = path.size();
- unsigned TotalNotePieces =
- std::count_if(path.begin(), path.end(),
- [](const std::shared_ptr<PathDiagnosticPiece> &p) {
- return isa<PathDiagnosticNotePiece>(*p);
- });
+ std::string report = GenerateHTML(D, R, SMgr, path, declName.c_str());
+ if (report.empty()) {
+ llvm::errs() << "warning: no diagnostics generated for main file.\n";
+ return;
+ }
- unsigned TotalRegularPieces = TotalPieces - TotalNotePieces;
- unsigned NumRegularPieces = TotalRegularPieces;
- unsigned NumNotePieces = TotalNotePieces;
+ // Create a path for the target HTML file.
+ int FD;
+ SmallString<128> Model, ResultPath;
- for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) {
- if (isa<PathDiagnosticNotePiece>(I->get())) {
- // This adds diagnostic bubbles, but not navigation.
- // Navigation through note pieces would be added later,
- // as a separate pass through the piece list.
- HandlePiece(R, FID, **I, NumNotePieces, TotalNotePieces);
- --NumNotePieces;
- } else {
- HandlePiece(R, FID, **I, NumRegularPieces, TotalRegularPieces);
- --NumRegularPieces;
- }
+ if (!AnalyzerOpts.shouldWriteStableReportFilename()) {
+ llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
+ if (std::error_code EC =
+ llvm::sys::fs::make_absolute(Model)) {
+ llvm::errs() << "warning: could not make '" << Model
+ << "' absolute: " << EC.message() << '\n';
+ return;
+ }
+ if (std::error_code EC =
+ llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) {
+ llvm::errs() << "warning: could not create file in '" << Directory
+ << "': " << EC.message() << '\n';
+ return;
+ }
+
+ } else {
+ int i = 1;
+ std::error_code EC;
+ do {
+ // Find a filename which is not already used
+ const FileEntry* Entry = SMgr.getFileEntryForID(ReportFile);
+ std::stringstream filename;
+ Model = "";
+ filename << "report-"
+ << llvm::sys::path::filename(Entry->getName()).str()
+ << "-" << declName.c_str()
+ << "-" << offsetDecl
+ << "-" << i << ".html";
+ llvm::sys::path::append(Model, Directory,
+ filename.str());
+ EC = llvm::sys::fs::openFileForWrite(Model,
+ FD,
+ llvm::sys::fs::F_RW |
+ llvm::sys::fs::F_Excl);
+ if (EC && EC != llvm::errc::file_exists) {
+ llvm::errs() << "warning: could not create file '" << Model
+ << "': " << EC.message() << '\n';
+ return;
+ }
+ i++;
+ } while (EC);
}
- // Add line numbers, header, footer, etc.
+ llvm::raw_fd_ostream os(FD, true);
- // unsigned FID = R.getSourceMgr().getMainFileID();
- html::EscapeText(R, FID);
- html::AddLineNumbers(R, FID);
+ if (filesMade)
+ filesMade->addDiagnostic(D, getName(),
+ llvm::sys::path::filename(ResultPath));
- // If we have a preprocessor, relex the file and syntax highlight.
- // We might not have a preprocessor if we come from a deserialized AST file,
- // for example.
+ // Emit the HTML to disk.
+ os << report;
+}
- html::SyntaxHighlight(R, FID, PP);
- html::HighlightMacros(R, FID, PP);
+std::string HTMLDiagnostics::GenerateHTML(const PathDiagnostic& D, Rewriter &R,
+ const SourceManager& SMgr, const PathPieces& path, const char *declName) {
+
+ // Rewrite source files as HTML for every new file the path crosses
+ std::vector<FileID> FileIDs;
+ for (auto I : path) {
+ FileID FID = I->getLocation().asLocation().getExpansionLoc().getFileID();
+ if (std::find(FileIDs.begin(), FileIDs.end(), FID) != FileIDs.end())
+ continue;
+
+ FileIDs.push_back(FID);
+ RewriteFile(R, SMgr, path, FID);
+ }
+
+ if (SupportsCrossFileDiagnostics && FileIDs.size() > 1) {
+ // Prefix file names, anchor tags, and nav cursors to every file
+ for (auto I = FileIDs.begin(), E = FileIDs.end(); I != E; I++) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+
+ if (I != FileIDs.begin())
+ os << "<hr class=divider>\n";
+
+ os << "<div id=File" << I->getHashValue() << ">\n";
- // Get the full directory name of the analyzed file.
+ // Left nav arrow
+ if (I != FileIDs.begin())
+ os << "<div class=FileNav><a href=\"#File" << (I - 1)->getHashValue()
+ << "\">&#x2190;</a></div>";
- const FileEntry* Entry = SMgr.getFileEntryForID(FID);
+ os << "<h4 class=FileName>" << SMgr.getFileEntryForID(*I)->getName()
+ << "</h4>\n";
+ // Right nav arrow
+ if (I + 1 != E)
+ os << "<div class=FileNav><a href=\"#File" << (I + 1)->getHashValue()
+ << "\">&#x2192;</a></div>";
+
+ os << "</div>\n";
+
+ R.InsertTextBefore(SMgr.getLocForStartOfFile(*I), os.str());
+ }
+
+ // Append files to the main report file in the order they appear in the path
+ for (auto I : llvm::make_range(FileIDs.begin() + 1, FileIDs.end())) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+
+ const RewriteBuffer *Buf = R.getRewriteBufferFor(I);
+ for (auto BI : *Buf)
+ os << BI;
+
+ R.InsertTextAfter(SMgr.getLocForEndOfFile(FileIDs[0]), os.str());
+ }
+ }
+
+ const RewriteBuffer *Buf = R.getRewriteBufferFor(FileIDs[0]);
+ if (!Buf)
+ return "";
+
+ // Add CSS, header, and footer.
+ const FileEntry* Entry = SMgr.getFileEntryForID(FileIDs[0]);
+ FinalizeHTML(D, R, SMgr, path, FileIDs[0], Entry, declName);
+
+ std::string file;
+ llvm::raw_string_ostream os(file);
+ for (auto BI : *Buf)
+ os << BI;
+
+ return os.str();
+}
+
+void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
+ const SourceManager& SMgr, const PathPieces& path, FileID FID,
+ const FileEntry *Entry, const char *declName) {
// This is a cludge; basically we want to append either the full
// working directory if we have no directory information. This is
// a work in progress.
@@ -306,73 +435,48 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
}
- // Add CSS, header, and footer.
-
html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
+}
- // Get the rewrite buffer.
- const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);
-
- if (!Buf) {
- llvm::errs() << "warning: no diagnostics generated for main file.\n";
- return;
- }
-
- // Create a path for the target HTML file.
- int FD;
- SmallString<128> Model, ResultPath;
+void HTMLDiagnostics::RewriteFile(Rewriter &R, const SourceManager& SMgr,
+ const PathPieces& path, FileID FID) {
+ // Process the path.
+ // Maintain the counts of extra note pieces separately.
+ unsigned TotalPieces = path.size();
+ unsigned TotalNotePieces =
+ std::count_if(path.begin(), path.end(),
+ [](const std::shared_ptr<PathDiagnosticPiece> &p) {
+ return isa<PathDiagnosticNotePiece>(*p);
+ });
- if (!AnalyzerOpts.shouldWriteStableReportFilename()) {
- llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
- if (std::error_code EC =
- llvm::sys::fs::make_absolute(Model)) {
- llvm::errs() << "warning: could not make '" << Model
- << "' absolute: " << EC.message() << '\n';
- return;
- }
- if (std::error_code EC =
- llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) {
- llvm::errs() << "warning: could not create file in '" << Directory
- << "': " << EC.message() << '\n';
- return;
- }
+ unsigned TotalRegularPieces = TotalPieces - TotalNotePieces;
+ unsigned NumRegularPieces = TotalRegularPieces;
+ unsigned NumNotePieces = TotalNotePieces;
- } else {
- int i = 1;
- std::error_code EC;
- do {
- // Find a filename which is not already used
- std::stringstream filename;
- Model = "";
- filename << "report-"
- << llvm::sys::path::filename(Entry->getName()).str()
- << "-" << declName.c_str()
- << "-" << offsetDecl
- << "-" << i << ".html";
- llvm::sys::path::append(Model, Directory,
- filename.str());
- EC = llvm::sys::fs::openFileForWrite(Model,
- FD,
- llvm::sys::fs::F_RW |
- llvm::sys::fs::F_Excl);
- if (EC && EC != llvm::errc::file_exists) {
- llvm::errs() << "warning: could not create file '" << Model
- << "': " << EC.message() << '\n';
- return;
- }
- i++;
- } while (EC);
+ for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) {
+ if (isa<PathDiagnosticNotePiece>(I->get())) {
+ // This adds diagnostic bubbles, but not navigation.
+ // Navigation through note pieces would be added later,
+ // as a separate pass through the piece list.
+ HandlePiece(R, FID, **I, NumNotePieces, TotalNotePieces);
+ --NumNotePieces;
+ } else {
+ HandlePiece(R, FID, **I, NumRegularPieces, TotalRegularPieces);
+ --NumRegularPieces;
+ }
}
- llvm::raw_fd_ostream os(FD, true);
+ // Add line numbers, header, footer, etc.
- if (filesMade)
- filesMade->addDiagnostic(D, getName(),
- llvm::sys::path::filename(ResultPath));
+ html::EscapeText(R, FID);
+ html::AddLineNumbers(R, FID);
- // Emit the HTML to disk.
- for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
- os << *I;
+ // If we have a preprocessor, relex the file and syntax highlight.
+ // We might not have a preprocessor if we come from a deserialized AST file,
+ // for example.
+
+ html::SyntaxHighlight(R, FID, PP);
+ html::HighlightMacros(R, FID, PP);
}
void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
diff --git a/lib/StaticAnalyzer/Core/IssueHash.cpp b/lib/StaticAnalyzer/Core/IssueHash.cpp
index abdea88b1d..274ebe7a94 100644
--- a/lib/StaticAnalyzer/Core/IssueHash.cpp
+++ b/lib/StaticAnalyzer/Core/IssueHash.cpp
@@ -33,6 +33,13 @@ static std::string GetSignature(const FunctionDecl *Target) {
return "";
std::string Signature;
+ // When a flow sensitive bug happens in templated code we should not generate
+ // distinct hash value for every instantiation. Use the signature from the
+ // primary template.
+ if (const FunctionDecl *InstantiatedFrom =
+ Target->getTemplateInstantiationPattern())
+ Target = InstantiatedFrom;
+
if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) &&
!isa<CXXConversionDecl>(Target))
Signature.append(Target->getReturnType().getAsString()).append(" ");
diff --git a/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
new file mode 100644
index 0000000000..a8c4b05cea
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -0,0 +1,294 @@
+//===--- LoopUnrolling.cpp - Unroll loops -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file contains functions which are used to decide if a loop worth to be
+/// unrolled. Moreover, these functions manages the stack of loop which is
+/// tracked by the ProgramState.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
+
+using namespace clang;
+using namespace ento;
+using namespace clang::ast_matchers;
+
+static const int MAXIMUM_STEP_UNROLLED = 128;
+
+struct LoopState {
+private:
+ enum Kind { Normal, Unrolled } K;
+ const Stmt *LoopStmt;
+ const LocationContext *LCtx;
+ unsigned maxStep;
+ LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
+ : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
+
+public:
+ static LoopState getNormal(const Stmt *S, const LocationContext *L,
+ unsigned N) {
+ return LoopState(Normal, S, L, N);
+ }
+ static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
+ unsigned N) {
+ return LoopState(Unrolled, S, L, N);
+ }
+ bool isUnrolled() const { return K == Unrolled; }
+ unsigned getMaxStep() const { return maxStep; }
+ const Stmt *getLoopStmt() const { return LoopStmt; }
+ const LocationContext *getLocationContext() const { return LCtx; }
+ bool operator==(const LoopState &X) const {
+ return K == X.K && LoopStmt == X.LoopStmt;
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ ID.AddPointer(LoopStmt);
+ ID.AddPointer(LCtx);
+ ID.AddInteger(maxStep);
+ }
+};
+
+// The tracked stack of loops. The stack indicates that which loops the
+// simulated element contained by. The loops are marked depending if we decided
+// to unroll them.
+// TODO: The loop stack should not need to be in the program state since it is
+// lexical in nature. Instead, the stack of loops should be tracked in the
+// LocationContext.
+REGISTER_LIST_WITH_PROGRAMSTATE(LoopStack, LoopState)
+
+namespace clang {
+namespace ento {
+
+static bool isLoopStmt(const Stmt *S) {
+ return S && (isa<ForStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S));
+}
+
+ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
+ auto LS = State->get<LoopStack>();
+ if (!LS.isEmpty() && LS.getHead().getLoopStmt() == LoopStmt)
+ State = State->set<LoopStack>(LS.getTail());
+ return State;
+}
+
+static internal::Matcher<Stmt> simpleCondition(StringRef BindName) {
+ return binaryOperator(anyOf(hasOperatorName("<"), hasOperatorName(">"),
+ hasOperatorName("<="), hasOperatorName(">="),
+ hasOperatorName("!=")),
+ hasEitherOperand(ignoringParenImpCasts(declRefExpr(
+ to(varDecl(hasType(isInteger())).bind(BindName))))),
+ hasEitherOperand(ignoringParenImpCasts(
+ integerLiteral().bind("boundNum"))))
+ .bind("conditionOperator");
+}
+
+static internal::Matcher<Stmt>
+changeIntBoundNode(internal::Matcher<Decl> VarNodeMatcher) {
+ return anyOf(
+ unaryOperator(anyOf(hasOperatorName("--"), hasOperatorName("++")),
+ hasUnaryOperand(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(VarNodeMatcher)))))),
+ binaryOperator(anyOf(hasOperatorName("="), hasOperatorName("+="),
+ hasOperatorName("/="), hasOperatorName("*="),
+ hasOperatorName("-=")),
+ hasLHS(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(VarNodeMatcher)))))));
+}
+
+static internal::Matcher<Stmt>
+callByRef(internal::Matcher<Decl> VarNodeMatcher) {
+ return callExpr(forEachArgumentWithParam(
+ declRefExpr(to(varDecl(VarNodeMatcher))),
+ parmVarDecl(hasType(references(qualType(unless(isConstQualified())))))));
+}
+
+static internal::Matcher<Stmt>
+assignedToRef(internal::Matcher<Decl> VarNodeMatcher) {
+ return declStmt(hasDescendant(varDecl(
+ allOf(hasType(referenceType()),
+ hasInitializer(anyOf(
+ initListExpr(has(declRefExpr(to(varDecl(VarNodeMatcher))))),
+ declRefExpr(to(varDecl(VarNodeMatcher)))))))));
+}
+
+static internal::Matcher<Stmt>
+getAddrTo(internal::Matcher<Decl> VarNodeMatcher) {
+ return unaryOperator(
+ hasOperatorName("&"),
+ hasUnaryOperand(declRefExpr(hasDeclaration(VarNodeMatcher))));
+}
+
+static internal::Matcher<Stmt> hasSuspiciousStmt(StringRef NodeName) {
+ return hasDescendant(stmt(
+ anyOf(gotoStmt(), switchStmt(), returnStmt(),
+ // Escaping and not known mutation of the loop counter is handled
+ // by exclusion of assigning and address-of operators and
+ // pass-by-ref function calls on the loop counter from the body.
+ changeIntBoundNode(equalsBoundNode(NodeName)),
+ callByRef(equalsBoundNode(NodeName)),
+ getAddrTo(equalsBoundNode(NodeName)),
+ assignedToRef(equalsBoundNode(NodeName)))));
+}
+
+static internal::Matcher<Stmt> forLoopMatcher() {
+ return forStmt(
+ hasCondition(simpleCondition("initVarName")),
+ // Initialization should match the form: 'int i = 6' or 'i = 42'.
+ hasLoopInit(anyOf(
+ declStmt(hasSingleDecl(varDecl(
+ allOf(hasInitializer(integerLiteral().bind("initNum")),
+ equalsBoundNode("initVarName"))))),
+ binaryOperator(hasLHS(declRefExpr(to(
+ varDecl(equalsBoundNode("initVarName"))))),
+ hasRHS(integerLiteral().bind("initNum"))))),
+ // Incrementation should be a simple increment or decrement
+ // operator call.
+ hasIncrement(unaryOperator(
+ anyOf(hasOperatorName("++"), hasOperatorName("--")),
+ hasUnaryOperand(declRefExpr(
+ to(varDecl(allOf(equalsBoundNode("initVarName"),
+ hasType(isInteger())))))))),
+ unless(hasBody(hasSuspiciousStmt("initVarName")))).bind("forLoop");
+}
+
+static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) {
+ // Global variables assumed as escaped variables.
+ if (VD->hasGlobalStorage())
+ return true;
+
+ while (!N->pred_empty()) {
+ const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ if (!S) {
+ N = N->getFirstPred();
+ continue;
+ }
+
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ for (const Decl *D : DS->decls()) {
+ // Once we reach the declaration of the VD we can return.
+ if (D->getCanonicalDecl() == VD)
+ return false;
+ }
+ }
+ // Check the usage of the pass-by-ref function calls and adress-of operator
+ // on VD and reference initialized by VD.
+ ASTContext &ASTCtx =
+ N->getLocationContext()->getAnalysisDeclContext()->getASTContext();
+ auto Match =
+ match(stmt(anyOf(callByRef(equalsNode(VD)), getAddrTo(equalsNode(VD)),
+ assignedToRef(equalsNode(VD)))),
+ *S, ASTCtx);
+ if (!Match.empty())
+ return true;
+
+ N = N->getFirstPred();
+ }
+ llvm_unreachable("Reached root without finding the declaration of VD");
+}
+
+bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx,
+ ExplodedNode *Pred, unsigned &maxStep) {
+
+ if (!isLoopStmt(LoopStmt))
+ return false;
+
+ // TODO: Match the cases where the bound is not a concrete literal but an
+ // integer with known value
+ auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx);
+ if (Matches.empty())
+ return false;
+
+ auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName");
+ llvm::APInt BoundNum =
+ Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue();
+ llvm::APInt InitNum =
+ Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue();
+ auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator");
+ if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
+ InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
+ BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
+ }
+
+ if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
+ maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
+ else
+ maxStep = (BoundNum - InitNum).abs().getZExtValue();
+
+ // Check if the counter of the loop is not escaped before.
+ return !isPossiblyEscaped(CounterVar->getCanonicalDecl(), Pred);
+}
+
+bool madeNewBranch(ExplodedNode *N, const Stmt *LoopStmt) {
+ const Stmt *S = nullptr;
+ while (!N->pred_empty()) {
+ if (N->succ_size() > 1)
+ return true;
+
+ ProgramPoint P = N->getLocation();
+ if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>())
+ S = BE->getBlock()->getTerminator();
+
+ if (S == LoopStmt)
+ return false;
+
+ N = N->getFirstPred();
+ }
+
+ llvm_unreachable("Reached root without encountering the previous step");
+}
+
+// updateLoopStack is called on every basic block, therefore it needs to be fast
+ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
+ ExplodedNode *Pred, unsigned maxVisitOnPath) {
+ auto State = Pred->getState();
+ auto LCtx = Pred->getLocationContext();
+
+ if (!isLoopStmt(LoopStmt))
+ return State;
+
+ auto LS = State->get<LoopStack>();
+ if (!LS.isEmpty() && LoopStmt == LS.getHead().getLoopStmt() &&
+ LCtx == LS.getHead().getLocationContext()) {
+ if (LS.getHead().isUnrolled() && madeNewBranch(Pred, LoopStmt)) {
+ State = State->set<LoopStack>(LS.getTail());
+ State = State->add<LoopStack>(
+ LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
+ }
+ return State;
+ }
+ unsigned maxStep;
+ if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred, maxStep)) {
+ State = State->add<LoopStack>(
+ LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
+ return State;
+ }
+
+ unsigned outerStep = (LS.isEmpty() ? 1 : LS.getHead().getMaxStep());
+
+ unsigned innerMaxStep = maxStep * outerStep;
+ if (innerMaxStep > MAXIMUM_STEP_UNROLLED)
+ State = State->add<LoopStack>(
+ LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
+ else
+ State = State->add<LoopStack>(
+ LoopState::getUnrolled(LoopStmt, LCtx, innerMaxStep));
+ return State;
+}
+
+bool isUnrolledState(ProgramStateRef State) {
+ auto LS = State->get<LoopStack>();
+ if (LS.isEmpty() || !LS.getHead().isUnrolled())
+ return false;
+ return true;
+}
+}
+}
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index d6e8fe5b51..640e63d137 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
@@ -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/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 7c5ee3b259..907755683f 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -579,6 +579,9 @@ getLocationForCaller(const StackFrameContext *SFC,
case CFGElement::TemporaryDtor:
case CFGElement::NewAllocator:
llvm_unreachable("not yet implemented!");
+ case CFGElement::LifetimeEnds:
+ case CFGElement::LoopExit:
+ llvm_unreachable("CFGElement kind should not be on callsite!");
}
llvm_unreachable("Unknown CFGElement kind");
@@ -694,7 +697,30 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
return PathDiagnosticLocation(S, SMng, P.getLocationContext());
}
+static const LocationContext *
+findTopAutosynthesizedParentContext(const LocationContext *LC) {
+ assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized());
+ const LocationContext *ParentLC = LC->getParent();
+ assert(ParentLC && "We don't start analysis from autosynthesized code");
+ while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
+ LC = ParentLC;
+ ParentLC = LC->getParent();
+ assert(ParentLC && "We don't start analysis from autosynthesized code");
+ }
+ return LC;
+}
+
const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
+ // We cannot place diagnostics on autosynthesized code.
+ // Put them onto the call site through which we jumped into autosynthesized
+ // code for the first time.
+ const LocationContext *LC = N->getLocationContext();
+ if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
+ // It must be a stack frame because we only autosynthesize functions.
+ return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC))
+ ->getCallSite();
+ }
+ // Otherwise, see if the node's program point directly points to a statement.
ProgramPoint P = N->getLocation();
if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
return SP->getStmt();
@@ -912,6 +938,17 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
+
+ // Autosynthesized property accessors are special because we'd never
+ // pop back up to non-autosynthesized code until we leave them.
+ // This is not generally true for autosynthesized callees, which may call
+ // non-autosynthesized callbacks.
+ // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
+ // defaults to false.
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Callee))
+ IsCalleeAnAutosynthesizedPropertyAccessor = (
+ MD->isPropertyAccessor() &&
+ CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
}
static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
@@ -986,7 +1023,11 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
std::shared_ptr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterEvent() const {
- if (!Callee)
+ // We do not produce call enters and call exits for autosynthesized property
+ // accessors. We do generally produce them for other functions coming from
+ // the body farm because they may call callbacks that bring us back into
+ // visible code.
+ if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)
return nullptr;
SmallString<256> buf;
@@ -1020,7 +1061,11 @@ PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
std::shared_ptr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallExitEvent() const {
- if (NoExit)
+ // We do not produce call enters and call exits for autosynthesized property
+ // accessors. We do generally produce them for other functions coming from
+ // the body farm because they may call callbacks that bring us back into
+ // visible code.
+ if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)
return nullptr;
SmallString<256> buf;
diff --git a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
index e7cc23ca82..4bb694819c 100644
--- a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
+++ b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
@@ -10,7 +10,7 @@
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_PRETTYSTACKTRACELOCATIONCONTEXT_H
#define LLVM_CLANG_LIB_STATICANALYZER_CORE_PRETTYSTACKTRACELOCATIONCONTEXT_H
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
namespace clang {
namespace ento {
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 31556c792f..3215c3ccd2 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -644,15 +644,33 @@ ProgramStateRef ProgramState::addTaint(const Stmt *S,
if (const Expr *E = dyn_cast_or_null<Expr>(S))
S = E->IgnoreParens();
- SymbolRef Sym = getSVal(S, LCtx).getAsSymbol();
+ return addTaint(getSVal(S, LCtx), Kind);
+}
+
+ProgramStateRef ProgramState::addTaint(SVal V,
+ TaintTagType Kind) const {
+ SymbolRef Sym = V.getAsSymbol();
if (Sym)
return addTaint(Sym, Kind);
- const MemRegion *R = getSVal(S, LCtx).getAsRegion();
- addTaint(R, Kind);
+ // If the SVal represents a structure, try to mass-taint all values within the
+ // structure. For now it only works efficiently on lazy compound values that
+ // were conjured during a conservative evaluation of a function - either as
+ // return values of functions that return structures or arrays by value, or as
+ // values of structures or arrays passed into the function by reference,
+ // directly or through pointer aliasing. Such lazy compound values are
+ // characterized by having exactly one binding in their captured store within
+ // their parent region, which is a conjured symbol default-bound to the base
+ // region of the parent region.
+ if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
+ if (Optional<SVal> binding = getStateManager().StoreMgr->getDefaultBinding(*LCV)) {
+ if (SymbolRef Sym = binding->getAsSymbol())
+ return addPartialTaint(Sym, LCV->getRegion(), Kind);
+ }
+ }
- // Cannot add taint, so just return the state.
- return this;
+ const MemRegion *R = V.getAsRegion();
+ return addTaint(R, Kind);
}
ProgramStateRef ProgramState::addTaint(const MemRegion *R,
@@ -674,6 +692,27 @@ ProgramStateRef ProgramState::addTaint(SymbolRef Sym,
return NewState;
}
+ProgramStateRef ProgramState::addPartialTaint(SymbolRef ParentSym,
+ const SubRegion *SubRegion,
+ TaintTagType Kind) const {
+ // Ignore partial taint if the entire parent symbol is already tainted.
+ if (contains<TaintMap>(ParentSym) && *get<TaintMap>(ParentSym) == Kind)
+ return this;
+
+ // Partial taint applies if only a portion of the symbol is tainted.
+ if (SubRegion == SubRegion->getBaseRegion())
+ return addTaint(ParentSym, Kind);
+
+ const TaintedSubRegions *SavedRegs = get<DerivedSymTaint>(ParentSym);
+ TaintedSubRegions Regs =
+ SavedRegs ? *SavedRegs : stateMgr->TSRFactory.getEmptyMap();
+
+ Regs = stateMgr->TSRFactory.add(Regs, SubRegion, Kind);
+ ProgramStateRef NewState = set<DerivedSymTaint>(ParentSym, Regs);
+ assert(NewState);
+ return NewState;
+}
+
bool ProgramState::isTainted(const Stmt *S, const LocationContext *LCtx,
TaintTagType Kind) const {
if (const Expr *E = dyn_cast_or_null<Expr>(S))
@@ -714,31 +753,52 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
return false;
// Traverse all the symbols this symbol depends on to see if any are tainted.
- bool Tainted = false;
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
SI != SE; ++SI) {
if (!isa<SymbolData>(*SI))
continue;
- const TaintTagType *Tag = get<TaintMap>(*SI);
- Tainted = (Tag && *Tag == Kind);
+ if (const TaintTagType *Tag = get<TaintMap>(*SI)) {
+ if (*Tag == Kind)
+ return true;
+ }
- // If this is a SymbolDerived with a tainted parent, it's also tainted.
- if (const SymbolDerived *SD = dyn_cast<SymbolDerived>(*SI))
- Tainted = Tainted || isTainted(SD->getParentSymbol(), Kind);
+ if (const SymbolDerived *SD = dyn_cast<SymbolDerived>(*SI)) {
+ // If this is a SymbolDerived with a tainted parent, it's also tainted.
+ if (isTainted(SD->getParentSymbol(), Kind))
+ return true;
+
+ // If this is a SymbolDerived with the same parent symbol as another
+ // tainted SymbolDerived and a region that's a sub-region of that tainted
+ // symbol, it's also tainted.
+ if (const TaintedSubRegions *Regs =
+ get<DerivedSymTaint>(SD->getParentSymbol())) {
+ const TypedValueRegion *R = SD->getRegion();
+ for (auto I : *Regs) {
+ // FIXME: The logic to identify tainted regions could be more
+ // complete. For example, this would not currently identify
+ // overlapping fields in a union as tainted. To identify this we can
+ // check for overlapping/nested byte offsets.
+ if (Kind == I.second &&
+ (R == I.first || R->isSubRegionOf(I.first)))
+ return true;
+ }
+ }
+ }
// If memory region is tainted, data is also tainted.
- if (const SymbolRegionValue *SRV = dyn_cast<SymbolRegionValue>(*SI))
- Tainted = Tainted || isTainted(SRV->getRegion(), Kind);
-
- // If If this is a SymbolCast from a tainted value, it's also tainted.
- if (const SymbolCast *SC = dyn_cast<SymbolCast>(*SI))
- Tainted = Tainted || isTainted(SC->getOperand(), Kind);
+ if (const SymbolRegionValue *SRV = dyn_cast<SymbolRegionValue>(*SI)) {
+ if (isTainted(SRV->getRegion(), Kind))
+ return true;
+ }
- if (Tainted)
- return true;
+ // If this is a SymbolCast from a tainted value, it's also tainted.
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(*SI)) {
+ if (isTainted(SC->getOperand(), Kind))
+ return true;
+ }
}
- return Tainted;
+ return false;
}
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index f0c2df4627..693a617fb6 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -18,7 +18,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -409,6 +409,19 @@ public: // Part of public interface to class.
// BindDefault is only used to initialize a region with a default value.
StoreRef BindDefault(Store store, const MemRegion *R, SVal V) override {
+ // FIXME: The offsets of empty bases can be tricky because of
+ // of the so called "empty base class optimization".
+ // If a base class has been optimized out
+ // we should not try to create a binding, otherwise we should.
+ // Unfortunately, at the moment ASTRecordLayout doesn't expose
+ // the actual sizes of the empty bases
+ // and trying to infer them from offsets/alignments
+ // seems to be error-prone and non-trivial because of the trailing padding.
+ // As a temporary mitigation we don't create bindings for empty bases.
+ if (R->getKind() == MemRegion::CXXBaseObjectRegionKind &&
+ cast<CXXBaseObjectRegion>(R)->getDecl()->isEmpty())
+ return StoreRef(store, *this);
+
RegionBindingsRef B = getRegionBindings(store);
assert(!B.lookup(R, BindingKey::Direct));
@@ -496,7 +509,10 @@ public: // Part of public interface to class.
Optional<SVal> getDefaultBinding(Store S, const MemRegion *R) override {
RegionBindingsRef B = getRegionBindings(S);
- return B.getDefaultBinding(R);
+ // Default bindings are always applied over a base region so look up the
+ // base region's default binding, otherwise the lookup will fail when R
+ // is at an offset from R->getBaseRegion().
+ return B.getDefaultBinding(R->getBaseRegion());
}
SVal getBinding(RegionBindingsConstRef B, Loc L, QualType T = QualType());
@@ -1338,10 +1354,14 @@ RegionStoreManager::getSizeInElements(ProgramStateRef state,
/// the array). This is called by ExprEngine when evaluating casts
/// from arrays to pointers.
SVal RegionStoreManager::ArrayToPointer(Loc Array, QualType T) {
+ if (Array.getAs<loc::ConcreteInt>())
+ return Array;
+
if (!Array.getAs<loc::MemRegionVal>())
return UnknownVal();
- const MemRegion* R = Array.castAs<loc::MemRegionVal>().getRegion();
+ const SubRegion *R =
+ cast<SubRegion>(Array.castAs<loc::MemRegionVal>().getRegion());
NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, R, Ctx));
}
@@ -1373,18 +1393,21 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
return UnknownVal();
}
- if (isa<AllocaRegion>(MR) ||
- isa<SymbolicRegion>(MR) ||
- isa<CodeTextRegion>(MR)) {
+ if (!isa<TypedValueRegion>(MR)) {
if (T.isNull()) {
if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR))
- T = TR->getLocationType();
- else {
- const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
- T = SR->getSymbol()->getType();
- }
+ T = TR->getLocationType()->getPointeeType();
+ else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+ T = SR->getSymbol()->getType()->getPointeeType();
+ else if (isa<AllocaRegion>(MR))
+ T = Ctx.VoidTy;
}
- MR = GetElementZeroRegion(MR, T);
+ assert(!T.isNull() && "Unable to auto-detect binding type!");
+ if (T->isVoidType()) {
+ // When trying to dereference a void pointer, read the first byte.
+ T = Ctx.CharTy;
+ }
+ MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
}
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
@@ -2065,15 +2088,12 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B,
if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT))
Size = CAT->getSize().getZExtValue();
- // Check if the init expr is a string literal.
+ // Check if the init expr is a literal. If so, bind the rvalue instead.
+ // FIXME: It's not responsibility of the Store to transform this lvalue
+ // to rvalue. ExprEngine or maybe even CFG should do this before binding.
if (Optional<loc::MemRegionVal> MRV = Init.getAs<loc::MemRegionVal>()) {
- const StringRegion *S = cast<StringRegion>(MRV->getRegion());
-
- // Treat the string as a lazy compound value.
- StoreRef store(B.asStore(), *this);
- nonloc::LazyCompoundVal LCV = svalBuilder.makeLazyCompoundVal(store, S)
- .castAs<nonloc::LazyCompoundVal>();
- return bindAggregate(B, R, LCV);
+ SVal V = getBinding(B.asStore(), *MRV, R->getValueType());
+ return bindAggregate(B, R, V);
}
// Handle lazy compound values.
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index ffaa0eda91..04452e3e7c 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -325,6 +325,7 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
}
}
// FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
// If we don't have a special case, fall back to the AST's constant evaluator.
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index 9f2af3ffa7..a83421426a 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -113,12 +113,12 @@ SymbolRef SVal::getLocSymbolInBase() const {
/// Casts are ignored during lookup.
/// \param IncludeBaseRegions The boolean that controls whether the search
/// should continue to the base regions if the region is not symbolic.
-SymbolRef SVal::getAsSymbol(bool IncludeBaseRegion) const {
+SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
return X->getSymbol();
- return getAsLocSymbol(IncludeBaseRegion);
+ return getAsLocSymbol(IncludeBaseRegions);
}
/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 28b43dd566..a5b5744c3f 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);
};
@@ -66,18 +71,15 @@ SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) {
}
SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
-
bool isLocType = Loc::isLocType(castTy);
-
if (val.getAs<nonloc::PointerToMember>())
return val;
if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) {
if (isLocType)
return LI->getLoc();
-
// FIXME: Correctly support promotions/truncations.
- unsigned castSize = Context.getTypeSize(castTy);
+ unsigned castSize = Context.getIntWidth(castTy);
if (castSize == LI->getNumBits())
return val;
return makeLocAsInteger(LI->getLoc(), castSize);
@@ -158,6 +160,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
return nonloc::SymbolVal(SymR->getSymbol());
// FALL-THROUGH
+ LLVM_FALLTHROUGH;
}
case loc::GotoLabelKind:
@@ -167,7 +170,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
}
if (castTy->isIntegralOrEnumerationType()) {
- unsigned BitWidth = Context.getTypeSize(castTy);
+ unsigned BitWidth = Context.getIntWidth(castTy);
if (!val.getAs<loc::ConcreteInt>())
return makeLocAsInteger(val, BitWidth);
@@ -357,11 +360,22 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc();
switch (rhs.getSubKind()) {
case nonloc::LocAsIntegerKind:
+ // FIXME: at the moment the implementation
+ // of modeling "pointers as integers" is not complete.
+ if (!BinaryOperator::isComparisonOp(op))
+ return UnknownVal();
return evalBinOpLL(state, op, lhsL,
rhs.castAs<nonloc::LocAsInteger>().getLoc(),
resultTy);
case nonloc::ConcreteIntKind: {
+ // FIXME: at the moment the implementation
+ // of modeling "pointers as integers" is not complete.
+ if (!BinaryOperator::isComparisonOp(op))
+ return UnknownVal();
// 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 +548,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))
@@ -711,9 +726,11 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
- if (SymbolRef lSym = lhs.getAsLocSymbol(true))
- return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);
-
+ if (SymbolRef lSym = lhs.getAsLocSymbol(true)) {
+ if (BinaryOperator::isComparisonOp(op))
+ return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);
+ return UnknownVal();
+ }
// Special case comparisons to NULL.
// This must come after the test if the LHS is a symbol, which is used to
// build constraints. The address of any non-symbolic region is guaranteed
@@ -905,6 +922,10 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
if (rhs.isZeroConstant())
return lhs;
+ // Perserve the null pointer so that it can be found by the DerefChecker.
+ if (lhs.isZeroConstant())
+ return lhs;
+
// We are dealing with pointer arithmetic.
// Handle pointer arithmetic on constant values.
@@ -920,6 +941,8 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// Offset the increment by the pointer size.
llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true);
+ QualType pointeeType = resultTy->getPointeeType();
+ Multiplicand = getContext().getTypeSizeInChars(pointeeType).getQuantity();
rightI *= Multiplicand;
// Compute the adjusted pointer.
@@ -941,20 +964,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 +1013,75 @@ 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 Loc::isLocType(S->getType()) ? (SVal)SVB.makeLoc(S)
+ : 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 aca6e3b625..173fdd8d00 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:
@@ -403,9 +404,15 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
case loc::ConcreteIntKind:
// While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
+ // FIXME: What we should return is the field offset, not base. For example,
+ // add the field offset to the integer value. That way things
// like this work properly: &(((struct foo *) 0xa)->f)
+ // However, that's not easy to fix without reducing our abilities
+ // to catch null pointer dereference. Eg., ((struct foo *)0x0)->f = 7
+ // is a null dereference even though we're dereferencing offset of f
+ // rather than null. Coming up with an approach that computes offsets
+ // over null pointers properly while still being able to catch null
+ // dereferences might be worth it.
return Base;
default:
@@ -430,11 +437,15 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
// If the base is an unknown or undefined value, just return it back.
// FIXME: For absolute pointer addresses, we just return that value back as
// well, although in reality we should return the offset added to that
- // value.
+ // value. See also the similar FIXME in getLValueFieldOrIvar().
if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>())
return Base;
-
- const MemRegion* BaseRegion = Base.castAs<loc::MemRegionVal>().getRegion();
+
+ if (Base.getAs<loc::GotoLabel>())
+ return UnknownVal();
+
+ 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 +482,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 +494,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/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 4be85661b6..f2d5ee83f3 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -31,14 +31,20 @@ void SymIntExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
os << ") "
- << BinaryOperator::getOpcodeStr(getOpcode()) << ' '
- << getRHS().getZExtValue();
+ << BinaryOperator::getOpcodeStr(getOpcode()) << ' ';
+ if (getRHS().isUnsigned())
+ os << getRHS().getZExtValue();
+ else
+ os << getRHS().getSExtValue();
if (getRHS().isUnsigned())
os << 'U';
}
void IntSymExpr::dumpToStream(raw_ostream &os) const {
- os << getLHS().getZExtValue();
+ if (getLHS().isUnsigned())
+ os << getLHS().getZExtValue();
+ else
+ os << getLHS().getSExtValue();
if (getLHS().isUnsigned())
os << 'U';
os << ' '
diff --git a/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp b/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp
new file mode 100644
index 0000000000..f9f9057a89
--- /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 0fe0f3a6ed..fccea9ee53 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -674,10 +674,8 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
DisplayFunction(D, Mode, IMode);
CFG *DeclCFG = Mgr->getCFG(D);
- if (DeclCFG) {
- unsigned CFGSize = DeclCFG->size();
- MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
- }
+ if (DeclCFG)
+ MaxCFGSize.updateMax(DeclCFG->size());
BugReporter BR(*Mgr);
@@ -856,8 +854,7 @@ UbigraphViz::~UbigraphViz() {
Ubiviz = *Path;
const char *args[] = {Ubiviz.c_str(), Filename.c_str(), nullptr};
- if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], nullptr, nullptr, 0, 0,
- &ErrMsg)) {
+ if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], nullptr, {}, 0, 0, &ErrMsg)) {
llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
}
diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
index c6f3baa7e3..cdb1ed9b38 100644
--- a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
+++ b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
@@ -65,7 +65,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) {
auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation());
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
- InputKind IK = IK_CXX; // FIXME
+ InputKind IK = InputKind::CXX; // FIXME
FrontendOpts.Inputs.clear();
FrontendOpts.Inputs.emplace_back(fileName, IK);
FrontendOpts.DisableFree = true;
diff --git a/lib/Tooling/ASTDiff/ASTDiff.cpp b/lib/Tooling/ASTDiff/ASTDiff.cpp
new file mode 100644
index 0000000000..6da0de7edf
--- /dev/null
+++ b/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -0,0 +1,1021 @@
+//===- ASTDiff.cpp - AST differencing implementation-----------*- C++ -*- -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains definitons for the AST differencing interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ASTDiff/ASTDiff.h"
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/PriorityQueue.h"
+
+#include <limits>
+#include <memory>
+#include <unordered_set>
+
+using namespace llvm;
+using namespace clang;
+
+namespace clang {
+namespace diff {
+
+namespace {
+/// Maps nodes of the left tree to ones on the right, and vice versa.
+class Mapping {
+public:
+ Mapping() = default;
+ Mapping(Mapping &&Other) = default;
+ Mapping &operator=(Mapping &&Other) = default;
+
+ Mapping(size_t Size) {
+ SrcToDst = llvm::make_unique<NodeId[]>(Size);
+ DstToSrc = llvm::make_unique<NodeId[]>(Size);
+ }
+
+ void link(NodeId Src, NodeId Dst) {
+ SrcToDst[Src] = Dst, DstToSrc[Dst] = Src;
+ }
+
+ NodeId getDst(NodeId Src) const { return SrcToDst[Src]; }
+ NodeId getSrc(NodeId Dst) const { return DstToSrc[Dst]; }
+ bool hasSrc(NodeId Src) const { return getDst(Src).isValid(); }
+ bool hasDst(NodeId Dst) const { return getSrc(Dst).isValid(); }
+
+private:
+ std::unique_ptr<NodeId[]> SrcToDst, DstToSrc;
+};
+} // end anonymous namespace
+
+class ASTDiff::Impl {
+public:
+ SyntaxTree::Impl &T1, &T2;
+ Mapping TheMapping;
+
+ Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2,
+ const ComparisonOptions &Options);
+
+ /// Matches nodes one-by-one based on their similarity.
+ void computeMapping();
+
+ // Compute Change for each node based on similarity.
+ void computeChangeKinds(Mapping &M);
+
+ NodeId getMapped(const std::unique_ptr<SyntaxTree::Impl> &Tree,
+ NodeId Id) const {
+ if (&*Tree == &T1)
+ return TheMapping.getDst(Id);
+ assert(&*Tree == &T2 && "Invalid tree.");
+ return TheMapping.getSrc(Id);
+ }
+
+private:
+ // Returns true if the two subtrees are identical.
+ bool identical(NodeId Id1, NodeId Id2) const;
+
+ // Returns false if the nodes must not be mached.
+ bool isMatchingPossible(NodeId Id1, NodeId Id2) const;
+
+ // Returns true if the nodes' parents are matched.
+ bool haveSameParents(const Mapping &M, NodeId Id1, NodeId Id2) const;
+
+ // Uses an optimal albeit slow algorithm to compute a mapping between two
+ // subtrees, but only if both have fewer nodes than MaxSize.
+ void addOptimalMapping(Mapping &M, NodeId Id1, NodeId Id2) const;
+
+ // Computes the ratio of common descendants between the two nodes.
+ // Descendants are only considered to be equal when they are mapped in M.
+ double getJaccardSimilarity(const Mapping &M, NodeId Id1, NodeId Id2) const;
+
+ // Returns the node that has the highest degree of similarity.
+ NodeId findCandidate(const Mapping &M, NodeId Id1) const;
+
+ // Returns a mapping of identical subtrees.
+ Mapping matchTopDown() const;
+
+ // Tries to match any yet unmapped nodes, in a bottom-up fashion.
+ void matchBottomUp(Mapping &M) const;
+
+ const ComparisonOptions &Options;
+
+ friend class ZhangShashaMatcher;
+};
+
+/// Represents the AST of a TranslationUnit.
+class SyntaxTree::Impl {
+public:
+ Impl(SyntaxTree *Parent, ASTContext &AST);
+ /// Constructs a tree from an AST node.
+ Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST);
+ Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST);
+ template <class T>
+ Impl(SyntaxTree *Parent,
+ typename std::enable_if<std::is_base_of<Stmt, T>::value, T>::type *Node,
+ ASTContext &AST)
+ : Impl(Parent, dyn_cast<Stmt>(Node), AST) {}
+ template <class T>
+ Impl(SyntaxTree *Parent,
+ typename std::enable_if<std::is_base_of<Decl, T>::value, T>::type *Node,
+ ASTContext &AST)
+ : Impl(Parent, dyn_cast<Decl>(Node), AST) {}
+
+ SyntaxTree *Parent;
+ ASTContext &AST;
+ PrintingPolicy TypePP;
+ /// Nodes in preorder.
+ std::vector<Node> Nodes;
+ std::vector<NodeId> Leaves;
+ // Maps preorder indices to postorder ones.
+ std::vector<int> PostorderIds;
+ std::vector<NodeId> NodesBfs;
+
+ int getSize() const { return Nodes.size(); }
+ NodeId getRootId() const { return 0; }
+ PreorderIterator begin() const { return getRootId(); }
+ PreorderIterator end() const { return getSize(); }
+
+ const Node &getNode(NodeId Id) const { return Nodes[Id]; }
+ Node &getMutableNode(NodeId Id) { return Nodes[Id]; }
+ bool isValidNodeId(NodeId Id) const { return Id >= 0 && Id < getSize(); }
+ void addNode(Node &N) { Nodes.push_back(N); }
+ int getNumberOfDescendants(NodeId Id) const;
+ bool isInSubtree(NodeId Id, NodeId SubtreeRoot) const;
+ int findPositionInParent(NodeId Id, bool Shifted = false) const;
+
+ std::string getRelativeName(const NamedDecl *ND,
+ const DeclContext *Context) const;
+ std::string getRelativeName(const NamedDecl *ND) const;
+
+ std::string getNodeValue(NodeId Id) const;
+ std::string getNodeValue(const Node &Node) const;
+ std::string getDeclValue(const Decl *D) const;
+ std::string getStmtValue(const Stmt *S) const;
+
+private:
+ void initTree();
+ void setLeftMostDescendants();
+};
+
+static bool isSpecializedNodeExcluded(const Decl *D) { return D->isImplicit(); }
+static bool isSpecializedNodeExcluded(const Stmt *S) { return false; }
+static bool isSpecializedNodeExcluded(CXXCtorInitializer *I) {
+ return !I->isWritten();
+}
+
+template <class T>
+static bool isNodeExcluded(const SourceManager &SrcMgr, T *N) {
+ if (!N)
+ return true;
+ SourceLocation SLoc = N->getSourceRange().getBegin();
+ if (SLoc.isValid()) {
+ // Ignore everything from other files.
+ if (!SrcMgr.isInMainFile(SLoc))
+ return true;
+ // Ignore macros.
+ if (SLoc != SrcMgr.getSpellingLoc(SLoc))
+ return true;
+ }
+ return isSpecializedNodeExcluded(N);
+}
+
+namespace {
+// Sets Height, Parent and Children for each node.
+struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> {
+ int Id = 0, Depth = 0;
+ NodeId Parent;
+ SyntaxTree::Impl &Tree;
+
+ PreorderVisitor(SyntaxTree::Impl &Tree) : Tree(Tree) {}
+
+ template <class T> std::tuple<NodeId, NodeId> PreTraverse(T *ASTNode) {
+ NodeId MyId = Id;
+ Tree.Nodes.emplace_back();
+ Node &N = Tree.getMutableNode(MyId);
+ N.Parent = Parent;
+ N.Depth = Depth;
+ N.ASTNode = DynTypedNode::create(*ASTNode);
+ assert(!N.ASTNode.getNodeKind().isNone() &&
+ "Expected nodes to have a valid kind.");
+ if (Parent.isValid()) {
+ Node &P = Tree.getMutableNode(Parent);
+ P.Children.push_back(MyId);
+ }
+ Parent = MyId;
+ ++Id;
+ ++Depth;
+ return std::make_tuple(MyId, Tree.getNode(MyId).Parent);
+ }
+ void PostTraverse(std::tuple<NodeId, NodeId> State) {
+ NodeId MyId, PreviousParent;
+ std::tie(MyId, PreviousParent) = State;
+ assert(MyId.isValid() && "Expecting to only traverse valid nodes.");
+ Parent = PreviousParent;
+ --Depth;
+ Node &N = Tree.getMutableNode(MyId);
+ N.RightMostDescendant = Id - 1;
+ assert(N.RightMostDescendant >= 0 &&
+ N.RightMostDescendant < Tree.getSize() &&
+ "Rightmost descendant must be a valid tree node.");
+ if (N.isLeaf())
+ Tree.Leaves.push_back(MyId);
+ N.Height = 1;
+ for (NodeId Child : N.Children)
+ N.Height = std::max(N.Height, 1 + Tree.getNode(Child).Height);
+ }
+ bool TraverseDecl(Decl *D) {
+ if (isNodeExcluded(Tree.AST.getSourceManager(), D))
+ return true;
+ auto SavedState = PreTraverse(D);
+ RecursiveASTVisitor<PreorderVisitor>::TraverseDecl(D);
+ PostTraverse(SavedState);
+ return true;
+ }
+ bool TraverseStmt(Stmt *S) {
+ if (S)
+ S = S->IgnoreImplicit();
+ if (isNodeExcluded(Tree.AST.getSourceManager(), S))
+ return true;
+ auto SavedState = PreTraverse(S);
+ RecursiveASTVisitor<PreorderVisitor>::TraverseStmt(S);
+ PostTraverse(SavedState);
+ return true;
+ }
+ bool TraverseType(QualType T) { return true; }
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
+ if (isNodeExcluded(Tree.AST.getSourceManager(), Init))
+ return true;
+ auto SavedState = PreTraverse(Init);
+ RecursiveASTVisitor<PreorderVisitor>::TraverseConstructorInitializer(Init);
+ PostTraverse(SavedState);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, ASTContext &AST)
+ : Parent(Parent), AST(AST), TypePP(AST.getLangOpts()) {
+ TypePP.AnonymousTagLocations = false;
+}
+
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST)
+ : Impl(Parent, AST) {
+ PreorderVisitor PreorderWalker(*this);
+ PreorderWalker.TraverseDecl(N);
+ initTree();
+}
+
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST)
+ : Impl(Parent, AST) {
+ PreorderVisitor PreorderWalker(*this);
+ PreorderWalker.TraverseStmt(N);
+ initTree();
+}
+
+static std::vector<NodeId> getSubtreePostorder(const SyntaxTree::Impl &Tree,
+ NodeId Root) {
+ std::vector<NodeId> Postorder;
+ std::function<void(NodeId)> Traverse = [&](NodeId Id) {
+ const Node &N = Tree.getNode(Id);
+ for (NodeId Child : N.Children)
+ Traverse(Child);
+ Postorder.push_back(Id);
+ };
+ Traverse(Root);
+ return Postorder;
+}
+
+static std::vector<NodeId> getSubtreeBfs(const SyntaxTree::Impl &Tree,
+ NodeId Root) {
+ std::vector<NodeId> Ids;
+ size_t Expanded = 0;
+ Ids.push_back(Root);
+ while (Expanded < Ids.size())
+ for (NodeId Child : Tree.getNode(Ids[Expanded++]).Children)
+ Ids.push_back(Child);
+ return Ids;
+}
+
+void SyntaxTree::Impl::initTree() {
+ setLeftMostDescendants();
+ int PostorderId = 0;
+ PostorderIds.resize(getSize());
+ std::function<void(NodeId)> PostorderTraverse = [&](NodeId Id) {
+ for (NodeId Child : getNode(Id).Children)
+ PostorderTraverse(Child);
+ PostorderIds[Id] = PostorderId;
+ ++PostorderId;
+ };
+ PostorderTraverse(getRootId());
+ NodesBfs = getSubtreeBfs(*this, getRootId());
+}
+
+void SyntaxTree::Impl::setLeftMostDescendants() {
+ for (NodeId Leaf : Leaves) {
+ getMutableNode(Leaf).LeftMostDescendant = Leaf;
+ NodeId Parent, Cur = Leaf;
+ while ((Parent = getNode(Cur).Parent).isValid() &&
+ getNode(Parent).Children[0] == Cur) {
+ Cur = Parent;
+ getMutableNode(Cur).LeftMostDescendant = Leaf;
+ }
+ }
+}
+
+int SyntaxTree::Impl::getNumberOfDescendants(NodeId Id) const {
+ return getNode(Id).RightMostDescendant - Id + 1;
+}
+
+bool SyntaxTree::Impl::isInSubtree(NodeId Id, NodeId SubtreeRoot) const {
+ return Id >= SubtreeRoot && Id <= getNode(SubtreeRoot).RightMostDescendant;
+}
+
+int SyntaxTree::Impl::findPositionInParent(NodeId Id, bool Shifted) const {
+ NodeId Parent = getNode(Id).Parent;
+ if (Parent.isInvalid())
+ return 0;
+ const auto &Siblings = getNode(Parent).Children;
+ int Position = 0;
+ for (size_t I = 0, E = Siblings.size(); I < E; ++I) {
+ if (Shifted)
+ Position += getNode(Siblings[I]).Shift;
+ if (Siblings[I] == Id) {
+ Position += I;
+ return Position;
+ }
+ }
+ llvm_unreachable("Node not found in parent's children.");
+}
+
+// Returns the qualified name of ND. If it is subordinate to Context,
+// then the prefix of the latter is removed from the returned value.
+std::string
+SyntaxTree::Impl::getRelativeName(const NamedDecl *ND,
+ const DeclContext *Context) const {
+ std::string Val = ND->getQualifiedNameAsString();
+ std::string ContextPrefix;
+ if (!Context)
+ return Val;
+ if (auto *Namespace = dyn_cast<NamespaceDecl>(Context))
+ ContextPrefix = Namespace->getQualifiedNameAsString();
+ else if (auto *Record = dyn_cast<RecordDecl>(Context))
+ ContextPrefix = Record->getQualifiedNameAsString();
+ else if (AST.getLangOpts().CPlusPlus11)
+ if (auto *Tag = dyn_cast<TagDecl>(Context))
+ ContextPrefix = Tag->getQualifiedNameAsString();
+ // Strip the qualifier, if Val refers to somthing in the current scope.
+ // But leave one leading ':' in place, so that we know that this is a
+ // relative path.
+ if (!ContextPrefix.empty() && StringRef(Val).startswith(ContextPrefix))
+ Val = Val.substr(ContextPrefix.size() + 1);
+ return Val;
+}
+
+std::string SyntaxTree::Impl::getRelativeName(const NamedDecl *ND) const {
+ return getRelativeName(ND, ND->getDeclContext());
+}
+
+static const DeclContext *getEnclosingDeclContext(ASTContext &AST,
+ const Stmt *S) {
+ while (S) {
+ const auto &Parents = AST.getParents(*S);
+ if (Parents.empty())
+ return nullptr;
+ const auto &P = Parents[0];
+ if (const auto *D = P.get<Decl>())
+ return D->getDeclContext();
+ S = P.get<Stmt>();
+ }
+ return nullptr;
+}
+
+static std::string getInitializerValue(const CXXCtorInitializer *Init,
+ const PrintingPolicy &TypePP) {
+ if (Init->isAnyMemberInitializer())
+ return Init->getAnyMember()->getName();
+ if (Init->isBaseInitializer())
+ return QualType(Init->getBaseClass(), 0).getAsString(TypePP);
+ if (Init->isDelegatingInitializer())
+ return Init->getTypeSourceInfo()->getType().getAsString(TypePP);
+ llvm_unreachable("Unknown initializer type");
+}
+
+std::string SyntaxTree::Impl::getNodeValue(NodeId Id) const {
+ return getNodeValue(getNode(Id));
+}
+
+std::string SyntaxTree::Impl::getNodeValue(const Node &N) const {
+ const DynTypedNode &DTN = N.ASTNode;
+ if (auto *S = DTN.get<Stmt>())
+ return getStmtValue(S);
+ if (auto *D = DTN.get<Decl>())
+ return getDeclValue(D);
+ if (auto *Init = DTN.get<CXXCtorInitializer>())
+ return getInitializerValue(Init, TypePP);
+ llvm_unreachable("Fatal: unhandled AST node.\n");
+}
+
+std::string SyntaxTree::Impl::getDeclValue(const Decl *D) const {
+ std::string Value;
+ if (auto *V = dyn_cast<ValueDecl>(D))
+ return getRelativeName(V) + "(" + V->getType().getAsString(TypePP) + ")";
+ if (auto *N = dyn_cast<NamedDecl>(D))
+ Value += getRelativeName(N) + ";";
+ if (auto *T = dyn_cast<TypedefNameDecl>(D))
+ return Value + T->getUnderlyingType().getAsString(TypePP) + ";";
+ if (auto *T = dyn_cast<TypeDecl>(D))
+ if (T->getTypeForDecl())
+ Value +=
+ T->getTypeForDecl()->getCanonicalTypeInternal().getAsString(TypePP) +
+ ";";
+ if (auto *U = dyn_cast<UsingDirectiveDecl>(D))
+ return U->getNominatedNamespace()->getName();
+ if (auto *A = dyn_cast<AccessSpecDecl>(D)) {
+ CharSourceRange Range(A->getSourceRange(), false);
+ return Lexer::getSourceText(Range, AST.getSourceManager(),
+ AST.getLangOpts());
+ }
+ return Value;
+}
+
+std::string SyntaxTree::Impl::getStmtValue(const Stmt *S) const {
+ if (auto *U = dyn_cast<UnaryOperator>(S))
+ return UnaryOperator::getOpcodeStr(U->getOpcode());
+ if (auto *B = dyn_cast<BinaryOperator>(S))
+ return B->getOpcodeStr();
+ if (auto *M = dyn_cast<MemberExpr>(S))
+ return getRelativeName(M->getMemberDecl());
+ if (auto *I = dyn_cast<IntegerLiteral>(S)) {
+ SmallString<256> Str;
+ I->getValue().toString(Str, /*Radix=*/10, /*Signed=*/false);
+ return Str.str();
+ }
+ if (auto *F = dyn_cast<FloatingLiteral>(S)) {
+ SmallString<256> Str;
+ F->getValue().toString(Str);
+ return Str.str();
+ }
+ if (auto *D = dyn_cast<DeclRefExpr>(S))
+ return getRelativeName(D->getDecl(), getEnclosingDeclContext(AST, S));
+ if (auto *String = dyn_cast<StringLiteral>(S))
+ return String->getString();
+ if (auto *B = dyn_cast<CXXBoolLiteralExpr>(S))
+ return B->getValue() ? "true" : "false";
+ return "";
+}
+
+/// Identifies a node in a subtree by its postorder offset, starting at 1.
+struct SNodeId {
+ int Id = 0;
+
+ explicit SNodeId(int Id) : Id(Id) {}
+ explicit SNodeId() = default;
+
+ operator int() const { return Id; }
+ SNodeId &operator++() { return ++Id, *this; }
+ SNodeId &operator--() { return --Id, *this; }
+ SNodeId operator+(int Other) const { return SNodeId(Id + Other); }
+};
+
+class Subtree {
+private:
+ /// The parent tree.
+ const SyntaxTree::Impl &Tree;
+ /// Maps SNodeIds to original ids.
+ std::vector<NodeId> RootIds;
+ /// Maps subtree nodes to their leftmost descendants wtihin the subtree.
+ std::vector<SNodeId> LeftMostDescendants;
+
+public:
+ std::vector<SNodeId> KeyRoots;
+
+ Subtree(const SyntaxTree::Impl &Tree, NodeId SubtreeRoot) : Tree(Tree) {
+ RootIds = getSubtreePostorder(Tree, SubtreeRoot);
+ int NumLeaves = setLeftMostDescendants();
+ computeKeyRoots(NumLeaves);
+ }
+ int getSize() const { return RootIds.size(); }
+ NodeId getIdInRoot(SNodeId Id) const {
+ assert(Id > 0 && Id <= getSize() && "Invalid subtree node index.");
+ return RootIds[Id - 1];
+ }
+ const Node &getNode(SNodeId Id) const {
+ return Tree.getNode(getIdInRoot(Id));
+ }
+ SNodeId getLeftMostDescendant(SNodeId Id) const {
+ assert(Id > 0 && Id <= getSize() && "Invalid subtree node index.");
+ return LeftMostDescendants[Id - 1];
+ }
+ /// Returns the postorder index of the leftmost descendant in the subtree.
+ NodeId getPostorderOffset() const {
+ return Tree.PostorderIds[getIdInRoot(SNodeId(1))];
+ }
+ std::string getNodeValue(SNodeId Id) const {
+ return Tree.getNodeValue(getIdInRoot(Id));
+ }
+
+private:
+ /// Returns the number of leafs in the subtree.
+ int setLeftMostDescendants() {
+ int NumLeaves = 0;
+ LeftMostDescendants.resize(getSize());
+ for (int I = 0; I < getSize(); ++I) {
+ SNodeId SI(I + 1);
+ const Node &N = getNode(SI);
+ NumLeaves += N.isLeaf();
+ assert(I == Tree.PostorderIds[getIdInRoot(SI)] - getPostorderOffset() &&
+ "Postorder traversal in subtree should correspond to traversal in "
+ "the root tree by a constant offset.");
+ LeftMostDescendants[I] = SNodeId(Tree.PostorderIds[N.LeftMostDescendant] -
+ getPostorderOffset());
+ }
+ return NumLeaves;
+ }
+ void computeKeyRoots(int Leaves) {
+ KeyRoots.resize(Leaves);
+ std::unordered_set<int> Visited;
+ int K = Leaves - 1;
+ for (SNodeId I(getSize()); I > 0; --I) {
+ SNodeId LeftDesc = getLeftMostDescendant(I);
+ if (Visited.count(LeftDesc))
+ continue;
+ assert(K >= 0 && "K should be non-negative");
+ KeyRoots[K] = I;
+ Visited.insert(LeftDesc);
+ --K;
+ }
+ }
+};
+
+/// Implementation of Zhang and Shasha's Algorithm for tree edit distance.
+/// Computes an optimal mapping between two trees using only insertion,
+/// deletion and update as edit actions (similar to the Levenshtein distance).
+class ZhangShashaMatcher {
+ const ASTDiff::Impl &DiffImpl;
+ Subtree S1;
+ Subtree S2;
+ std::unique_ptr<std::unique_ptr<double[]>[]> TreeDist, ForestDist;
+
+public:
+ ZhangShashaMatcher(const ASTDiff::Impl &DiffImpl, const SyntaxTree::Impl &T1,
+ const SyntaxTree::Impl &T2, NodeId Id1, NodeId Id2)
+ : DiffImpl(DiffImpl), S1(T1, Id1), S2(T2, Id2) {
+ TreeDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
+ size_t(S1.getSize()) + 1);
+ ForestDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
+ size_t(S1.getSize()) + 1);
+ for (int I = 0, E = S1.getSize() + 1; I < E; ++I) {
+ TreeDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1);
+ ForestDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1);
+ }
+ }
+
+ std::vector<std::pair<NodeId, NodeId>> getMatchingNodes() {
+ std::vector<std::pair<NodeId, NodeId>> Matches;
+ std::vector<std::pair<SNodeId, SNodeId>> TreePairs;
+
+ computeTreeDist();
+
+ bool RootNodePair = true;
+
+ TreePairs.emplace_back(SNodeId(S1.getSize()), SNodeId(S2.getSize()));
+
+ while (!TreePairs.empty()) {
+ SNodeId LastRow, LastCol, FirstRow, FirstCol, Row, Col;
+ std::tie(LastRow, LastCol) = TreePairs.back();
+ TreePairs.pop_back();
+
+ if (!RootNodePair) {
+ computeForestDist(LastRow, LastCol);
+ }
+
+ RootNodePair = false;
+
+ FirstRow = S1.getLeftMostDescendant(LastRow);
+ FirstCol = S2.getLeftMostDescendant(LastCol);
+
+ Row = LastRow;
+ Col = LastCol;
+
+ while (Row > FirstRow || Col > FirstCol) {
+ if (Row > FirstRow &&
+ ForestDist[Row - 1][Col] + 1 == ForestDist[Row][Col]) {
+ --Row;
+ } else if (Col > FirstCol &&
+ ForestDist[Row][Col - 1] + 1 == ForestDist[Row][Col]) {
+ --Col;
+ } else {
+ SNodeId LMD1 = S1.getLeftMostDescendant(Row);
+ SNodeId LMD2 = S2.getLeftMostDescendant(Col);
+ if (LMD1 == S1.getLeftMostDescendant(LastRow) &&
+ LMD2 == S2.getLeftMostDescendant(LastCol)) {
+ NodeId Id1 = S1.getIdInRoot(Row);
+ NodeId Id2 = S2.getIdInRoot(Col);
+ assert(DiffImpl.isMatchingPossible(Id1, Id2) &&
+ "These nodes must not be matched.");
+ Matches.emplace_back(Id1, Id2);
+ --Row;
+ --Col;
+ } else {
+ TreePairs.emplace_back(Row, Col);
+ Row = LMD1;
+ Col = LMD2;
+ }
+ }
+ }
+ }
+ return Matches;
+ }
+
+private:
+ /// We use a simple cost model for edit actions, which seems good enough.
+ /// Simple cost model for edit actions. This seems to make the matching
+ /// algorithm perform reasonably well.
+ /// The values range between 0 and 1, or infinity if this edit action should
+ /// always be avoided.
+ static constexpr double DeletionCost = 1;
+ static constexpr double InsertionCost = 1;
+
+ double getUpdateCost(SNodeId Id1, SNodeId Id2) {
+ if (!DiffImpl.isMatchingPossible(S1.getIdInRoot(Id1), S2.getIdInRoot(Id2)))
+ return std::numeric_limits<double>::max();
+ return S1.getNodeValue(Id1) != S2.getNodeValue(Id2);
+ }
+
+ void computeTreeDist() {
+ for (SNodeId Id1 : S1.KeyRoots)
+ for (SNodeId Id2 : S2.KeyRoots)
+ computeForestDist(Id1, Id2);
+ }
+
+ void computeForestDist(SNodeId Id1, SNodeId Id2) {
+ assert(Id1 > 0 && Id2 > 0 && "Expecting offsets greater than 0.");
+ SNodeId LMD1 = S1.getLeftMostDescendant(Id1);
+ SNodeId LMD2 = S2.getLeftMostDescendant(Id2);
+
+ ForestDist[LMD1][LMD2] = 0;
+ for (SNodeId D1 = LMD1 + 1; D1 <= Id1; ++D1) {
+ ForestDist[D1][LMD2] = ForestDist[D1 - 1][LMD2] + DeletionCost;
+ for (SNodeId D2 = LMD2 + 1; D2 <= Id2; ++D2) {
+ ForestDist[LMD1][D2] = ForestDist[LMD1][D2 - 1] + InsertionCost;
+ SNodeId DLMD1 = S1.getLeftMostDescendant(D1);
+ SNodeId DLMD2 = S2.getLeftMostDescendant(D2);
+ if (DLMD1 == LMD1 && DLMD2 == LMD2) {
+ double UpdateCost = getUpdateCost(D1, D2);
+ ForestDist[D1][D2] =
+ std::min({ForestDist[D1 - 1][D2] + DeletionCost,
+ ForestDist[D1][D2 - 1] + InsertionCost,
+ ForestDist[D1 - 1][D2 - 1] + UpdateCost});
+ TreeDist[D1][D2] = ForestDist[D1][D2];
+ } else {
+ ForestDist[D1][D2] =
+ std::min({ForestDist[D1 - 1][D2] + DeletionCost,
+ ForestDist[D1][D2 - 1] + InsertionCost,
+ ForestDist[DLMD1][DLMD2] + TreeDist[D1][D2]});
+ }
+ }
+ }
+ }
+};
+
+ast_type_traits::ASTNodeKind Node::getType() const {
+ return ASTNode.getNodeKind();
+}
+
+StringRef Node::getTypeLabel() const { return getType().asStringRef(); }
+
+llvm::Optional<std::string> Node::getQualifiedIdentifier() const {
+ if (auto *ND = ASTNode.get<NamedDecl>()) {
+ if (ND->getDeclName().isIdentifier())
+ return ND->getQualifiedNameAsString();
+ }
+ return llvm::None;
+}
+
+llvm::Optional<StringRef> Node::getIdentifier() const {
+ if (auto *ND = ASTNode.get<NamedDecl>()) {
+ if (ND->getDeclName().isIdentifier())
+ return ND->getName();
+ }
+ return llvm::None;
+}
+
+namespace {
+// Compares nodes by their depth.
+struct HeightLess {
+ const SyntaxTree::Impl &Tree;
+ HeightLess(const SyntaxTree::Impl &Tree) : Tree(Tree) {}
+ bool operator()(NodeId Id1, NodeId Id2) const {
+ return Tree.getNode(Id1).Height < Tree.getNode(Id2).Height;
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// Priority queue for nodes, sorted descendingly by their height.
+class PriorityList {
+ const SyntaxTree::Impl &Tree;
+ HeightLess Cmp;
+ std::vector<NodeId> Container;
+ PriorityQueue<NodeId, std::vector<NodeId>, HeightLess> List;
+
+public:
+ PriorityList(const SyntaxTree::Impl &Tree)
+ : Tree(Tree), Cmp(Tree), List(Cmp, Container) {}
+
+ void push(NodeId id) { List.push(id); }
+
+ std::vector<NodeId> pop() {
+ int Max = peekMax();
+ std::vector<NodeId> Result;
+ if (Max == 0)
+ return Result;
+ while (peekMax() == Max) {
+ Result.push_back(List.top());
+ List.pop();
+ }
+ // TODO this is here to get a stable output, not a good heuristic
+ std::sort(Result.begin(), Result.end());
+ return Result;
+ }
+ int peekMax() const {
+ if (List.empty())
+ return 0;
+ return Tree.getNode(List.top()).Height;
+ }
+ void open(NodeId Id) {
+ for (NodeId Child : Tree.getNode(Id).Children)
+ push(Child);
+ }
+};
+} // end anonymous namespace
+
+bool ASTDiff::Impl::identical(NodeId Id1, NodeId Id2) const {
+ const Node &N1 = T1.getNode(Id1);
+ const Node &N2 = T2.getNode(Id2);
+ if (N1.Children.size() != N2.Children.size() ||
+ !isMatchingPossible(Id1, Id2) ||
+ T1.getNodeValue(Id1) != T2.getNodeValue(Id2))
+ return false;
+ for (size_t Id = 0, E = N1.Children.size(); Id < E; ++Id)
+ if (!identical(N1.Children[Id], N2.Children[Id]))
+ return false;
+ return true;
+}
+
+bool ASTDiff::Impl::isMatchingPossible(NodeId Id1, NodeId Id2) const {
+ return Options.isMatchingAllowed(T1.getNode(Id1), T2.getNode(Id2));
+}
+
+bool ASTDiff::Impl::haveSameParents(const Mapping &M, NodeId Id1,
+ NodeId Id2) const {
+ NodeId P1 = T1.getNode(Id1).Parent;
+ NodeId P2 = T2.getNode(Id2).Parent;
+ return (P1.isInvalid() && P2.isInvalid()) ||
+ (P1.isValid() && P2.isValid() && M.getDst(P1) == P2);
+}
+
+void ASTDiff::Impl::addOptimalMapping(Mapping &M, NodeId Id1,
+ NodeId Id2) const {
+ if (std::max(T1.getNumberOfDescendants(Id1), T2.getNumberOfDescendants(Id2)) >
+ Options.MaxSize)
+ return;
+ ZhangShashaMatcher Matcher(*this, T1, T2, Id1, Id2);
+ std::vector<std::pair<NodeId, NodeId>> R = Matcher.getMatchingNodes();
+ for (const auto Tuple : R) {
+ NodeId Src = Tuple.first;
+ NodeId Dst = Tuple.second;
+ if (!M.hasSrc(Src) && !M.hasDst(Dst))
+ M.link(Src, Dst);
+ }
+}
+
+double ASTDiff::Impl::getJaccardSimilarity(const Mapping &M, NodeId Id1,
+ NodeId Id2) const {
+ int CommonDescendants = 0;
+ const Node &N1 = T1.getNode(Id1);
+ // Count the common descendants, excluding the subtree root.
+ for (NodeId Src = Id1 + 1; Src <= N1.RightMostDescendant; ++Src) {
+ NodeId Dst = M.getDst(Src);
+ CommonDescendants += int(Dst.isValid() && T2.isInSubtree(Dst, Id2));
+ }
+ // We need to subtract 1 to get the number of descendants excluding the root.
+ double Denominator = T1.getNumberOfDescendants(Id1) - 1 +
+ T2.getNumberOfDescendants(Id2) - 1 - CommonDescendants;
+ // CommonDescendants is less than the size of one subtree.
+ assert(Denominator >= 0 && "Expected non-negative denominator.");
+ if (Denominator == 0)
+ return 0;
+ return CommonDescendants / Denominator;
+}
+
+NodeId ASTDiff::Impl::findCandidate(const Mapping &M, NodeId Id1) const {
+ NodeId Candidate;
+ double HighestSimilarity = 0.0;
+ for (NodeId Id2 : T2) {
+ if (!isMatchingPossible(Id1, Id2))
+ continue;
+ if (M.hasDst(Id2))
+ continue;
+ double Similarity = getJaccardSimilarity(M, Id1, Id2);
+ if (Similarity >= Options.MinSimilarity && Similarity > HighestSimilarity) {
+ HighestSimilarity = Similarity;
+ Candidate = Id2;
+ }
+ }
+ return Candidate;
+}
+
+void ASTDiff::Impl::matchBottomUp(Mapping &M) const {
+ std::vector<NodeId> Postorder = getSubtreePostorder(T1, T1.getRootId());
+ for (NodeId Id1 : Postorder) {
+ if (Id1 == T1.getRootId() && !M.hasSrc(T1.getRootId()) &&
+ !M.hasDst(T2.getRootId())) {
+ if (isMatchingPossible(T1.getRootId(), T2.getRootId())) {
+ M.link(T1.getRootId(), T2.getRootId());
+ addOptimalMapping(M, T1.getRootId(), T2.getRootId());
+ }
+ break;
+ }
+ bool Matched = M.hasSrc(Id1);
+ const Node &N1 = T1.getNode(Id1);
+ bool MatchedChildren =
+ std::any_of(N1.Children.begin(), N1.Children.end(),
+ [&](NodeId Child) { return M.hasSrc(Child); });
+ if (Matched || !MatchedChildren)
+ continue;
+ NodeId Id2 = findCandidate(M, Id1);
+ if (Id2.isValid()) {
+ M.link(Id1, Id2);
+ addOptimalMapping(M, Id1, Id2);
+ }
+ }
+}
+
+Mapping ASTDiff::Impl::matchTopDown() const {
+ PriorityList L1(T1);
+ PriorityList L2(T2);
+
+ Mapping M(T1.getSize() + T2.getSize());
+
+ L1.push(T1.getRootId());
+ L2.push(T2.getRootId());
+
+ int Max1, Max2;
+ while (std::min(Max1 = L1.peekMax(), Max2 = L2.peekMax()) >
+ Options.MinHeight) {
+ if (Max1 > Max2) {
+ for (NodeId Id : L1.pop())
+ L1.open(Id);
+ continue;
+ }
+ if (Max2 > Max1) {
+ for (NodeId Id : L2.pop())
+ L2.open(Id);
+ continue;
+ }
+ std::vector<NodeId> H1, H2;
+ H1 = L1.pop();
+ H2 = L2.pop();
+ for (NodeId Id1 : H1) {
+ for (NodeId Id2 : H2) {
+ if (identical(Id1, Id2) && !M.hasSrc(Id1) && !M.hasDst(Id2)) {
+ for (int I = 0, E = T1.getNumberOfDescendants(Id1); I < E; ++I)
+ M.link(Id1 + I, Id2 + I);
+ }
+ }
+ }
+ for (NodeId Id1 : H1) {
+ if (!M.hasSrc(Id1))
+ L1.open(Id1);
+ }
+ for (NodeId Id2 : H2) {
+ if (!M.hasDst(Id2))
+ L2.open(Id2);
+ }
+ }
+ return M;
+}
+
+ASTDiff::Impl::Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2,
+ const ComparisonOptions &Options)
+ : T1(T1), T2(T2), Options(Options) {
+ computeMapping();
+ computeChangeKinds(TheMapping);
+}
+
+void ASTDiff::Impl::computeMapping() {
+ TheMapping = matchTopDown();
+ if (Options.StopAfterTopDown)
+ return;
+ matchBottomUp(TheMapping);
+}
+
+void ASTDiff::Impl::computeChangeKinds(Mapping &M) {
+ for (NodeId Id1 : T1) {
+ if (!M.hasSrc(Id1)) {
+ T1.getMutableNode(Id1).Change = Delete;
+ T1.getMutableNode(Id1).Shift -= 1;
+ }
+ }
+ for (NodeId Id2 : T2) {
+ if (!M.hasDst(Id2)) {
+ T2.getMutableNode(Id2).Change = Insert;
+ T2.getMutableNode(Id2).Shift -= 1;
+ }
+ }
+ for (NodeId Id1 : T1.NodesBfs) {
+ NodeId Id2 = M.getDst(Id1);
+ if (Id2.isInvalid())
+ continue;
+ if (!haveSameParents(M, Id1, Id2) ||
+ T1.findPositionInParent(Id1, true) !=
+ T2.findPositionInParent(Id2, true)) {
+ T1.getMutableNode(Id1).Shift -= 1;
+ T2.getMutableNode(Id2).Shift -= 1;
+ }
+ }
+ for (NodeId Id2 : T2.NodesBfs) {
+ NodeId Id1 = M.getSrc(Id2);
+ if (Id1.isInvalid())
+ continue;
+ Node &N1 = T1.getMutableNode(Id1);
+ Node &N2 = T2.getMutableNode(Id2);
+ if (Id1.isInvalid())
+ continue;
+ if (!haveSameParents(M, Id1, Id2) ||
+ T1.findPositionInParent(Id1, true) !=
+ T2.findPositionInParent(Id2, true)) {
+ N1.Change = N2.Change = Move;
+ }
+ if (T1.getNodeValue(Id1) != T2.getNodeValue(Id2)) {
+ N1.Change = N2.Change = (N1.Change == Move ? UpdateMove : Update);
+ }
+ }
+}
+
+ASTDiff::ASTDiff(SyntaxTree &T1, SyntaxTree &T2,
+ const ComparisonOptions &Options)
+ : DiffImpl(llvm::make_unique<Impl>(*T1.TreeImpl, *T2.TreeImpl, Options)) {}
+
+ASTDiff::~ASTDiff() = default;
+
+NodeId ASTDiff::getMapped(const SyntaxTree &SourceTree, NodeId Id) const {
+ return DiffImpl->getMapped(SourceTree.TreeImpl, Id);
+}
+
+SyntaxTree::SyntaxTree(ASTContext &AST)
+ : TreeImpl(llvm::make_unique<SyntaxTree::Impl>(
+ this, AST.getTranslationUnitDecl(), AST)) {}
+
+SyntaxTree::~SyntaxTree() = default;
+
+const ASTContext &SyntaxTree::getASTContext() const { return TreeImpl->AST; }
+
+const Node &SyntaxTree::getNode(NodeId Id) const {
+ return TreeImpl->getNode(Id);
+}
+
+int SyntaxTree::getSize() const { return TreeImpl->getSize(); }
+NodeId SyntaxTree::getRootId() const { return TreeImpl->getRootId(); }
+SyntaxTree::PreorderIterator SyntaxTree::begin() const {
+ return TreeImpl->begin();
+}
+SyntaxTree::PreorderIterator SyntaxTree::end() const { return TreeImpl->end(); }
+
+int SyntaxTree::findPositionInParent(NodeId Id) const {
+ return TreeImpl->findPositionInParent(Id);
+}
+
+std::pair<unsigned, unsigned>
+SyntaxTree::getSourceRangeOffsets(const Node &N) const {
+ const SourceManager &SrcMgr = TreeImpl->AST.getSourceManager();
+ SourceRange Range = N.ASTNode.getSourceRange();
+ SourceLocation BeginLoc = Range.getBegin();
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Range.getEnd(), /*Offset=*/0, SrcMgr, TreeImpl->AST.getLangOpts());
+ if (auto *ThisExpr = N.ASTNode.get<CXXThisExpr>()) {
+ if (ThisExpr->isImplicit())
+ EndLoc = BeginLoc;
+ }
+ unsigned Begin = SrcMgr.getFileOffset(SrcMgr.getExpansionLoc(BeginLoc));
+ unsigned End = SrcMgr.getFileOffset(SrcMgr.getExpansionLoc(EndLoc));
+ return {Begin, End};
+}
+
+std::string SyntaxTree::getNodeValue(NodeId Id) const {
+ return TreeImpl->getNodeValue(Id);
+}
+
+std::string SyntaxTree::getNodeValue(const Node &N) const {
+ return TreeImpl->getNodeValue(N);
+}
+
+} // end namespace diff
+} // end namespace clang
diff --git a/lib/Tooling/ASTDiff/CMakeLists.txt b/lib/Tooling/ASTDiff/CMakeLists.txt
new file mode 100644
index 0000000000..578d8ca0cb
--- /dev/null
+++ b/lib/Tooling/ASTDiff/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(clangToolingASTDiff
+ ASTDiff.cpp
+ LINK_LIBS
+ clangBasic
+ clangAST
+ clangLex
+ )
diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp
index 48b925c698..962ea45258 100644
--- a/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/lib/Tooling/ArgumentsAdjusters.cpp
@@ -42,7 +42,7 @@ ArgumentsAdjuster getClangStripOutputAdjuster() {
AdjustedArgs.push_back(Args[i]);
if (Arg == "-o") {
- // Output is specified as -o foo. Skip the next argument also.
+ // Output is specified as -o foo. Skip the next argument too.
++i;
}
// Else, the output is specified as -ofoo. Just do nothing.
@@ -51,6 +51,26 @@ ArgumentsAdjuster getClangStripOutputAdjuster() {
};
}
+ArgumentsAdjuster getClangStripDependencyFileAdjuster() {
+ return [](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ // All dependency-file options begin with -M. These include -MM,
+ // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD.
+ if (!Arg.startswith("-M"))
+ AdjustedArgs.push_back(Args[i]);
+
+ if ((Arg == "-MF") || (Arg == "-MT") || (Arg == "-MQ") ||
+ (Arg == "-MD") || (Arg == "-MMD")) {
+ // Output is specified as -MX foo. Skip the next argument also.
+ ++i;
+ }
+ }
+ return AdjustedArgs;
+ };
+}
+
ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
ArgumentInsertPosition Pos) {
return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) {
@@ -76,6 +96,10 @@ ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra,
ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
ArgumentsAdjuster Second) {
+ if (!First)
+ return Second;
+ if (!Second)
+ return First;
return [First, Second](const CommandLineArguments &Args, StringRef File) {
return Second(First(Args, File), File);
};
@@ -83,4 +107,3 @@ ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
} // end namespace tooling
} // end namespace clang
-
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
index 7b0c58e794..ee681bbb45 100644
--- a/lib/Tooling/CMakeLists.txt
+++ b/lib/Tooling/CMakeLists.txt
@@ -5,16 +5,19 @@ set(LLVM_LINK_COMPONENTS
add_subdirectory(Core)
add_subdirectory(Refactoring)
+add_subdirectory(ASTDiff)
add_clang_library(clangTooling
ArgumentsAdjusters.cpp
CommonOptionsParser.cpp
CompilationDatabase.cpp
+ Execution.cpp
FileMatchTrie.cpp
FixIt.cpp
JSONCompilationDatabase.cpp
Refactoring.cpp
RefactoringCallbacks.cpp
+ StandaloneExecution.cpp
Tooling.cpp
DEPENDS
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 5a44061cbd..74ad4e83ee 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -24,10 +24,9 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/CommandLine.h"
-#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
using namespace clang::tooling;
using namespace llvm;
@@ -54,78 +53,83 @@ const char *const CommonOptionsParser::HelpMessage =
"\tsuffix of a path in the compile command database.\n"
"\n";
-namespace {
-class ArgumentsAdjustingCompilations : public CompilationDatabase {
-public:
- ArgumentsAdjustingCompilations(
- std::unique_ptr<CompilationDatabase> Compilations)
- : Compilations(std::move(Compilations)) {}
-
- void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
- Adjusters.push_back(std::move(Adjuster));
- }
-
- std::vector<CompileCommand>
- getCompileCommands(StringRef FilePath) const override {
- return adjustCommands(Compilations->getCompileCommands(FilePath));
- }
+void ArgumentsAdjustingCompilations::appendArgumentsAdjuster(
+ ArgumentsAdjuster Adjuster) {
+ Adjusters.push_back(std::move(Adjuster));
+}
- std::vector<std::string> getAllFiles() const override {
- return Compilations->getAllFiles();
- }
+std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands(
+ StringRef FilePath) const {
+ return adjustCommands(Compilations->getCompileCommands(FilePath));
+}
- std::vector<CompileCommand> getAllCompileCommands() const override {
- return adjustCommands(Compilations->getAllCompileCommands());
- }
+std::vector<std::string>
+ArgumentsAdjustingCompilations::getAllFiles() const {
+ return Compilations->getAllFiles();
+}
-private:
- std::unique_ptr<CompilationDatabase> Compilations;
- std::vector<ArgumentsAdjuster> Adjusters;
+std::vector<CompileCommand>
+ArgumentsAdjustingCompilations::getAllCompileCommands() const {
+ return adjustCommands(Compilations->getAllCompileCommands());
+}
- std::vector<CompileCommand>
- adjustCommands(std::vector<CompileCommand> Commands) const {
- for (CompileCommand &Command : Commands)
- for (const auto &Adjuster : Adjusters)
- Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
- return Commands;
- }
-};
-} // namespace
+std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
+ std::vector<CompileCommand> Commands) const {
+ for (CompileCommand &Command : Commands)
+ for (const auto &Adjuster : Adjusters)
+ Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
+ return Commands;
+}
-CommonOptionsParser::CommonOptionsParser(
+llvm::Error CommonOptionsParser::init(
int &argc, const char **argv, cl::OptionCategory &Category,
llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
- static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+ static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden,
+ cl::sub(*cl::AllSubCommands));
static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
- cl::Optional, cl::cat(Category));
+ cl::Optional, cl::cat(Category),
+ cl::sub(*cl::AllSubCommands));
static cl::list<std::string> SourcePaths(
cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
- cl::cat(Category));
+ cl::cat(Category), cl::sub(*cl::AllSubCommands));
static cl::list<std::string> ArgsAfter(
"extra-arg",
cl::desc("Additional argument to append to the compiler command line"),
- cl::cat(Category));
+ cl::cat(Category), cl::sub(*cl::AllSubCommands));
static cl::list<std::string> ArgsBefore(
"extra-arg-before",
cl::desc("Additional argument to prepend to the compiler command line"),
- cl::cat(Category));
+ cl::cat(Category), cl::sub(*cl::AllSubCommands));
+
+ cl::ResetAllOptionOccurrences();
cl::HideUnrelatedOptions(Category);
- Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
- cl::ParseCommandLineOptions(argc, argv, Overview);
+ std::string ErrorMessage;
+ Compilations =
+ FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
+ if (!ErrorMessage.empty())
+ ErrorMessage.append("\n");
+ llvm::raw_string_ostream OS(ErrorMessage);
+ // Stop initializing if command-line option parsing failed.
+ if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) {
+ OS.flush();
+ return llvm::make_error<llvm::StringError>("[CommonOptionsParser]: " +
+ ErrorMessage,
+ llvm::inconvertibleErrorCode());
+ }
+
cl::PrintOptionValues();
SourcePathList = SourcePaths;
if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
SourcePathList.empty())
- return;
+ return llvm::Error::success();
if (!Compilations) {
- std::string ErrorMessage;
if (!BuildPath.empty()) {
Compilations =
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
@@ -143,9 +147,34 @@ CommonOptionsParser::CommonOptionsParser(
auto AdjustingCompilations =
llvm::make_unique<ArgumentsAdjustingCompilations>(
std::move(Compilations));
- AdjustingCompilations->appendArgumentsAdjuster(
- getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN));
- AdjustingCompilations->appendArgumentsAdjuster(
+ Adjuster =
+ getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
+ Adjuster = combineAdjusters(
+ std::move(Adjuster),
getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
+ AdjustingCompilations->appendArgumentsAdjuster(Adjuster);
Compilations = std::move(AdjustingCompilations);
+ return llvm::Error::success();
+}
+
+llvm::Expected<CommonOptionsParser> CommonOptionsParser::create(
+ int &argc, const char **argv, llvm::cl::OptionCategory &Category,
+ llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
+ CommonOptionsParser Parser;
+ llvm::Error Err =
+ Parser.init(argc, argv, Category, OccurrencesFlag, Overview);
+ if (Err)
+ return std::move(Err);
+ return std::move(Parser);
+}
+
+CommonOptionsParser::CommonOptionsParser(
+ int &argc, const char **argv, cl::OptionCategory &Category,
+ llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
+ llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview);
+ if (Err) {
+ llvm::report_fatal_error(
+ "CommonOptionsParser: failed to parse command-line arguments. " +
+ llvm::toString(std::move(Err)));
+ }
}
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 8ca0b2df70..0e835579e0 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -27,6 +27,7 @@
#include "llvm/Option/Arg.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <sstream>
#include <system_error>
using namespace clang;
@@ -150,23 +151,21 @@ private:
// options.
class UnusedInputDiagConsumer : public DiagnosticConsumer {
public:
- UnusedInputDiagConsumer() : Other(nullptr) {}
-
- // Useful for debugging, chain diagnostics to another consumer after
- // recording for our own purposes.
- UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
+ UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override {
if (Info.getID() == clang::diag::warn_drv_input_file_unused) {
// Arg 1 for this diagnostic is the option that didn't get used.
UnusedInputs.push_back(Info.getArgStdStr(0));
+ } else if (DiagLevel >= DiagnosticsEngine::Error) {
+ // If driver failed to create compilation object, show the diagnostics
+ // to user.
+ Other.HandleDiagnostic(DiagLevel, Info);
}
- if (Other)
- Other->HandleDiagnostic(DiagLevel, Info);
}
- DiagnosticConsumer *Other;
+ DiagnosticConsumer &Other;
SmallVector<std::string, 2> UnusedInputs;
};
@@ -205,9 +204,12 @@ private:
/// \li false if \c Args cannot be used for compilation jobs (e.g.
/// contains an option like -E or -version).
static bool stripPositionalArgs(std::vector<const char *> Args,
- std::vector<std::string> &Result) {
+ std::vector<std::string> &Result,
+ std::string &ErrorMsg) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
- UnusedInputDiagConsumer DiagClient;
+ llvm::raw_string_ostream Output(ErrorMsg);
+ TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
+ UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
DiagnosticsEngine Diagnostics(
IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
&*DiagOpts, &DiagClient, false);
@@ -245,21 +247,24 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
const std::unique_ptr<driver::Compilation> Compilation(
NewDriver->BuildCompilation(Args));
+ if (!Compilation)
+ return false;
const driver::JobList &Jobs = Compilation->getJobs();
CompileJobAnalyzer CompileAnalyzer;
for (const auto &Cmd : Jobs) {
- // Collect only for Assemble jobs. If we do all jobs we get duplicates
- // since Link jobs point to Assemble jobs as inputs.
- if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass)
+ // Collect only for Assemble and Compile jobs. If we do all jobs we get
+ // duplicates since Link jobs point to Assemble jobs as inputs.
+ if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass ||
+ Cmd.getSource().getKind() == driver::Action::CompileJobClass) {
CompileAnalyzer.run(&Cmd.getSource());
+ }
}
if (CompileAnalyzer.Inputs.empty()) {
- // No compile jobs found.
- // FIXME: Emit a warning of some kind?
+ ErrorMsg = "warning: no compile jobs found\n";
return false;
}
@@ -280,8 +285,14 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
return true;
}
-FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine(
- int &Argc, const char *const *Argv, Twine Directory) {
+std::unique_ptr<FixedCompilationDatabase>
+FixedCompilationDatabase::loadFromCommandLine(int &Argc,
+ const char *const *Argv,
+ std::string &ErrorMsg,
+ Twine Directory) {
+ ErrorMsg.clear();
+ if (Argc == 0)
+ return nullptr;
const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
if (DoubleDash == Argv + Argc)
return nullptr;
@@ -289,9 +300,10 @@ FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine(
Argc = DoubleDash - Argv;
std::vector<std::string> StrippedArgs;
- if (!stripPositionalArgs(CommandLine, StrippedArgs))
+ if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
return nullptr;
- return new FixedCompilationDatabase(Directory, StrippedArgs);
+ return std::unique_ptr<FixedCompilationDatabase>(
+ new FixedCompilationDatabase(Directory, StrippedArgs));
}
FixedCompilationDatabase::
diff --git a/lib/Tooling/Core/Diagnostic.cpp b/lib/Tooling/Core/Diagnostic.cpp
index 3bbc2b901e..9e4833f2ef 100644
--- a/lib/Tooling/Core/Diagnostic.cpp
+++ b/lib/Tooling/Core/Diagnostic.cpp
@@ -35,9 +35,9 @@ Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
BuildDirectory(BuildDirectory) {}
Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
- DiagnosticMessage &Message,
- llvm::StringMap<Replacements> &Fix,
- SmallVector<DiagnosticMessage, 1> &Notes,
+ const DiagnosticMessage &Message,
+ const llvm::StringMap<Replacements> &Fix,
+ const SmallVector<DiagnosticMessage, 1> &Notes,
Level DiagLevel, llvm::StringRef BuildDirectory)
: DiagnosticName(DiagnosticName), Message(Message), Fix(Fix), Notes(Notes),
DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {}
diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp
index e194b59a6e..6d4f3a3401 100644
--- a/lib/Tooling/Core/Replacement.cpp
+++ b/lib/Tooling/Core/Replacement.cpp
@@ -503,7 +503,7 @@ calculateRangesAfterReplacements(const Replacements &Replaces,
std::string(R.getLength(), ' ')));
assert(!Err &&
"Replacements must not conflict since ranges have been merged.");
- (void)Err;
+ llvm::consumeError(std::move(Err));
}
return FakeReplaces.merge(Replaces).getAffectedRanges();
}
diff --git a/lib/Tooling/Execution.cpp b/lib/Tooling/Execution.cpp
new file mode 100644
index 0000000000..1a078ef7e1
--- /dev/null
+++ b/lib/Tooling/Execution.cpp
@@ -0,0 +1,89 @@
+//===- lib/Tooling/Execution.cpp - Implements tool execution framework. ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/ToolExecutorPluginRegistry.h"
+#include "clang/Tooling/Tooling.h"
+
+LLVM_INSTANTIATE_REGISTRY(clang::tooling::ToolExecutorPluginRegistry)
+
+namespace clang {
+namespace tooling {
+
+static llvm::cl::opt<std::string>
+ ExecutorName("executor", llvm::cl::desc("The name of the executor to use."),
+ llvm::cl::init("standalone"));
+
+void InMemoryToolResults::addResult(StringRef Key, StringRef Value) {
+ KVResults.push_back({Key.str(), Value.str()});
+}
+
+std::vector<std::pair<std::string, std::string>>
+InMemoryToolResults::AllKVResults() {
+ return KVResults;
+}
+
+void InMemoryToolResults::forEachResult(
+ llvm::function_ref<void(StringRef Key, StringRef Value)> Callback) {
+ for (const auto &KV : KVResults) {
+ Callback(KV.first, KV.second);
+ }
+}
+
+void ExecutionContext::reportResult(StringRef Key, StringRef Value) {
+ Results->addResult(Key, Value);
+}
+
+llvm::Error
+ToolExecutor::execute(std::unique_ptr<FrontendActionFactory> Action) {
+ return execute(std::move(Action), ArgumentsAdjuster());
+}
+
+llvm::Error ToolExecutor::execute(std::unique_ptr<FrontendActionFactory> Action,
+ ArgumentsAdjuster Adjuster) {
+ std::vector<
+ std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
+ Actions;
+ Actions.emplace_back(std::move(Action), std::move(Adjuster));
+ return execute(Actions);
+}
+
+llvm::Expected<std::unique_ptr<ToolExecutor>>
+createExecutorFromCommandLineArgs(int &argc, const char **argv,
+ llvm::cl::OptionCategory &Category,
+ const char *Overview) {
+ auto OptionsParser =
+ CommonOptionsParser::create(argc, argv, Category, llvm::cl::ZeroOrMore,
+ /*Overview=*/nullptr);
+ if (!OptionsParser)
+ return OptionsParser.takeError();
+ for (auto I = ToolExecutorPluginRegistry::begin(),
+ E = ToolExecutorPluginRegistry::end();
+ I != E; ++I) {
+ if (I->getName() != ExecutorName) {
+ continue;
+ }
+ std::unique_ptr<ToolExecutorPlugin> Plugin(I->instantiate());
+ llvm::Expected<std::unique_ptr<ToolExecutor>> Executor =
+ Plugin->create(*OptionsParser);
+ if (!Executor) {
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("Failed to create '") + I->getName() +
+ "': " + llvm::toString(Executor.takeError()) + "\n",
+ llvm::inconvertibleErrorCode());
+ }
+ return std::move(*Executor);
+ }
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("Executor \"") + ExecutorName + "\" is not registered.",
+ llvm::inconvertibleErrorCode());
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index 738e610ed9..f9a230eb63 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -146,12 +146,8 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
SmallString<1024> JSONDatabasePath(Directory);
llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
- std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromFile(
- JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect));
- if (!Database)
- return nullptr;
- return Database;
+ return JSONCompilationDatabase::loadFromFile(
+ JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect);
}
};
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index 954a473f07..db34c952d7 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;
diff --git a/lib/Tooling/Refactoring/ASTSelection.cpp b/lib/Tooling/Refactoring/ASTSelection.cpp
new file mode 100644
index 0000000000..71a0d44be1
--- /dev/null
+++ b/lib/Tooling/Refactoring/ASTSelection.cpp
@@ -0,0 +1,384 @@
+//===--- ASTSelection.cpp - Clang refactoring library ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/SaveAndRestore.h"
+
+using namespace clang;
+using namespace tooling;
+using ast_type_traits::DynTypedNode;
+
+namespace {
+
+CharSourceRange getLexicalDeclRange(Decl *D, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (!isa<ObjCImplDecl>(D))
+ return CharSourceRange::getTokenRange(D->getSourceRange());
+ // Objective-C implementation declarations end at the '@' instead of the 'end'
+ // keyword. Use the lexer to find the location right after 'end'.
+ SourceRange R = D->getSourceRange();
+ SourceLocation LocAfterEnd = Lexer::findLocationAfterToken(
+ R.getEnd(), tok::raw_identifier, SM, LangOpts,
+ /*SkipTrailingWhitespaceAndNewLine=*/false);
+ return LocAfterEnd.isValid()
+ ? CharSourceRange::getCharRange(R.getBegin(), LocAfterEnd)
+ : CharSourceRange::getTokenRange(R);
+}
+
+/// Constructs the tree of selected AST nodes that either contain the location
+/// of the cursor or overlap with the selection range.
+class ASTSelectionFinder
+ : public LexicallyOrderedRecursiveASTVisitor<ASTSelectionFinder> {
+public:
+ ASTSelectionFinder(SourceRange Selection, FileID TargetFile,
+ const ASTContext &Context)
+ : LexicallyOrderedRecursiveASTVisitor(Context.getSourceManager()),
+ SelectionBegin(Selection.getBegin()),
+ SelectionEnd(Selection.getBegin() == Selection.getEnd()
+ ? SourceLocation()
+ : Selection.getEnd()),
+ TargetFile(TargetFile), Context(Context) {
+ // The TU decl is the root of the selected node tree.
+ SelectionStack.push_back(
+ SelectedASTNode(DynTypedNode::create(*Context.getTranslationUnitDecl()),
+ SourceSelectionKind::None));
+ }
+
+ Optional<SelectedASTNode> getSelectedASTNode() {
+ assert(SelectionStack.size() == 1 && "stack was not popped");
+ SelectedASTNode Result = std::move(SelectionStack.back());
+ SelectionStack.pop_back();
+ if (Result.Children.empty())
+ return None;
+ return std::move(Result);
+ }
+
+ bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
+ // Avoid traversing the semantic expressions. They should be handled by
+ // looking through the appropriate opaque expressions in order to build
+ // a meaningful selection tree.
+ llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, true);
+ return TraverseStmt(E->getSyntacticForm());
+ }
+
+ bool TraverseOpaqueValueExpr(OpaqueValueExpr *E) {
+ if (!LookThroughOpaqueValueExprs)
+ return true;
+ llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, false);
+ return TraverseStmt(E->getSourceExpr());
+ }
+
+ bool TraverseDecl(Decl *D) {
+ if (isa<TranslationUnitDecl>(D))
+ return LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+ if (D->isImplicit())
+ return true;
+
+ // Check if this declaration is written in the file of interest.
+ const SourceRange DeclRange = D->getSourceRange();
+ const SourceManager &SM = Context.getSourceManager();
+ SourceLocation FileLoc;
+ if (DeclRange.getBegin().isMacroID() && !DeclRange.getEnd().isMacroID())
+ FileLoc = DeclRange.getEnd();
+ else
+ FileLoc = SM.getSpellingLoc(DeclRange.getBegin());
+ if (SM.getFileID(FileLoc) != TargetFile)
+ return true;
+
+ SourceSelectionKind SelectionKind =
+ selectionKindFor(getLexicalDeclRange(D, SM, Context.getLangOpts()));
+ SelectionStack.push_back(
+ SelectedASTNode(DynTypedNode::create(*D), SelectionKind));
+ LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+ popAndAddToSelectionIfSelected(SelectionKind);
+
+ if (DeclRange.getEnd().isValid() &&
+ SM.isBeforeInTranslationUnit(SelectionEnd.isValid() ? SelectionEnd
+ : SelectionBegin,
+ DeclRange.getEnd())) {
+ // Stop early when we've reached a declaration after the selection.
+ return false;
+ }
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ if (!S)
+ return true;
+ if (auto *Opaque = dyn_cast<OpaqueValueExpr>(S))
+ return TraverseOpaqueValueExpr(Opaque);
+ // FIXME (Alex Lorenz): Improve handling for macro locations.
+ SourceSelectionKind SelectionKind =
+ selectionKindFor(CharSourceRange::getTokenRange(S->getSourceRange()));
+ SelectionStack.push_back(
+ SelectedASTNode(DynTypedNode::create(*S), SelectionKind));
+ LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
+ popAndAddToSelectionIfSelected(SelectionKind);
+ return true;
+ }
+
+private:
+ void popAndAddToSelectionIfSelected(SourceSelectionKind SelectionKind) {
+ SelectedASTNode Node = std::move(SelectionStack.back());
+ SelectionStack.pop_back();
+ if (SelectionKind != SourceSelectionKind::None || !Node.Children.empty())
+ SelectionStack.back().Children.push_back(std::move(Node));
+ }
+
+ SourceSelectionKind selectionKindFor(CharSourceRange Range) {
+ SourceLocation End = Range.getEnd();
+ const SourceManager &SM = Context.getSourceManager();
+ if (Range.isTokenRange())
+ End = Lexer::getLocForEndOfToken(End, 0, SM, Context.getLangOpts());
+ if (!SourceLocation::isPairOfFileLocations(Range.getBegin(), End))
+ return SourceSelectionKind::None;
+ if (!SelectionEnd.isValid()) {
+ // Do a quick check when the selection is of length 0.
+ if (SM.isPointWithin(SelectionBegin, Range.getBegin(), End))
+ return SourceSelectionKind::ContainsSelection;
+ return SourceSelectionKind::None;
+ }
+ bool HasStart = SM.isPointWithin(SelectionBegin, Range.getBegin(), End);
+ bool HasEnd = SM.isPointWithin(SelectionEnd, Range.getBegin(), End);
+ if (HasStart && HasEnd)
+ return SourceSelectionKind::ContainsSelection;
+ if (SM.isPointWithin(Range.getBegin(), SelectionBegin, SelectionEnd) &&
+ SM.isPointWithin(End, SelectionBegin, SelectionEnd))
+ return SourceSelectionKind::InsideSelection;
+ // Ensure there's at least some overlap with the 'start'/'end' selection
+ // types.
+ if (HasStart && SelectionBegin != End)
+ return SourceSelectionKind::ContainsSelectionStart;
+ if (HasEnd && SelectionEnd != Range.getBegin())
+ return SourceSelectionKind::ContainsSelectionEnd;
+
+ return SourceSelectionKind::None;
+ }
+
+ const SourceLocation SelectionBegin, SelectionEnd;
+ FileID TargetFile;
+ const ASTContext &Context;
+ std::vector<SelectedASTNode> SelectionStack;
+ /// Controls whether we can traverse through the OpaqueValueExpr. This is
+ /// typically enabled during the traversal of syntactic form for
+ /// PseudoObjectExprs.
+ bool LookThroughOpaqueValueExprs = false;
+};
+
+} // end anonymous namespace
+
+Optional<SelectedASTNode>
+clang::tooling::findSelectedASTNodes(const ASTContext &Context,
+ SourceRange SelectionRange) {
+ assert(SelectionRange.isValid() &&
+ SourceLocation::isPairOfFileLocations(SelectionRange.getBegin(),
+ SelectionRange.getEnd()) &&
+ "Expected a file range");
+ FileID TargetFile =
+ Context.getSourceManager().getFileID(SelectionRange.getBegin());
+ assert(Context.getSourceManager().getFileID(SelectionRange.getEnd()) ==
+ TargetFile &&
+ "selection range must span one file");
+
+ ASTSelectionFinder Visitor(SelectionRange, TargetFile, Context);
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ return Visitor.getSelectedASTNode();
+}
+
+static const char *selectionKindToString(SourceSelectionKind Kind) {
+ switch (Kind) {
+ case SourceSelectionKind::None:
+ return "none";
+ case SourceSelectionKind::ContainsSelection:
+ return "contains-selection";
+ case SourceSelectionKind::ContainsSelectionStart:
+ return "contains-selection-start";
+ case SourceSelectionKind::ContainsSelectionEnd:
+ return "contains-selection-end";
+ case SourceSelectionKind::InsideSelection:
+ return "inside";
+ }
+ llvm_unreachable("invalid selection kind");
+}
+
+static void dump(const SelectedASTNode &Node, llvm::raw_ostream &OS,
+ unsigned Indent = 0) {
+ OS.indent(Indent * 2);
+ if (const Decl *D = Node.Node.get<Decl>()) {
+ OS << D->getDeclKindName() << "Decl";
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ OS << " \"" << ND->getNameAsString() << '"';
+ } else if (const Stmt *S = Node.Node.get<Stmt>()) {
+ OS << S->getStmtClassName();
+ }
+ OS << ' ' << selectionKindToString(Node.SelectionKind) << "\n";
+ for (const auto &Child : Node.Children)
+ dump(Child, OS, Indent + 1);
+}
+
+void SelectedASTNode::dump(llvm::raw_ostream &OS) const { ::dump(*this, OS); }
+
+/// Returns true if the given node has any direct children with the following
+/// selection kind.
+///
+/// Note: The direct children also include children of direct children with the
+/// "None" selection kind.
+static bool hasAnyDirectChildrenWithKind(const SelectedASTNode &Node,
+ SourceSelectionKind Kind) {
+ assert(Kind != SourceSelectionKind::None && "invalid predicate!");
+ for (const auto &Child : Node.Children) {
+ if (Child.SelectionKind == Kind)
+ return true;
+ if (Child.SelectionKind == SourceSelectionKind::None)
+ return hasAnyDirectChildrenWithKind(Child, Kind);
+ }
+ return false;
+}
+
+namespace {
+struct SelectedNodeWithParents {
+ SelectedNodeWithParents(SelectedNodeWithParents &&) = default;
+ SelectedNodeWithParents &operator=(SelectedNodeWithParents &&) = default;
+ SelectedASTNode::ReferenceType Node;
+ llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents;
+};
+} // end anonymous namespace
+
+/// Finds the set of bottom-most selected AST nodes that are in the selection
+/// tree with the specified selection kind.
+///
+/// For example, given the following selection tree:
+///
+/// FunctionDecl "f" contains-selection
+/// CompoundStmt contains-selection [#1]
+/// CallExpr inside
+/// ImplicitCastExpr inside
+/// DeclRefExpr inside
+/// IntegerLiteral inside
+/// IntegerLiteral inside
+/// FunctionDecl "f2" contains-selection
+/// CompoundStmt contains-selection [#2]
+/// CallExpr inside
+/// ImplicitCastExpr inside
+/// DeclRefExpr inside
+/// IntegerLiteral inside
+/// IntegerLiteral inside
+///
+/// This function will find references to nodes #1 and #2 when searching for the
+/// \c ContainsSelection kind.
+static void findDeepestWithKind(
+ const SelectedASTNode &ASTSelection,
+ llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes,
+ SourceSelectionKind Kind,
+ llvm::SmallVectorImpl<SelectedASTNode::ReferenceType> &ParentStack) {
+ if (ASTSelection.Node.get<DeclStmt>()) {
+ // Select the entire decl stmt when any of its child declarations is the
+ // bottom-most.
+ for (const auto &Child : ASTSelection.Children) {
+ if (!hasAnyDirectChildrenWithKind(Child, Kind)) {
+ MatchingNodes.push_back(SelectedNodeWithParents{
+ std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
+ return;
+ }
+ }
+ } else {
+ if (!hasAnyDirectChildrenWithKind(ASTSelection, Kind)) {
+ // This node is the bottom-most.
+ MatchingNodes.push_back(SelectedNodeWithParents{
+ std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
+ return;
+ }
+ }
+ // Search in the children.
+ ParentStack.push_back(std::cref(ASTSelection));
+ for (const auto &Child : ASTSelection.Children)
+ findDeepestWithKind(Child, MatchingNodes, Kind, ParentStack);
+ ParentStack.pop_back();
+}
+
+static void findDeepestWithKind(
+ const SelectedASTNode &ASTSelection,
+ llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes,
+ SourceSelectionKind Kind) {
+ llvm::SmallVector<SelectedASTNode::ReferenceType, 16> ParentStack;
+ findDeepestWithKind(ASTSelection, MatchingNodes, Kind, ParentStack);
+}
+
+Optional<CodeRangeASTSelection>
+CodeRangeASTSelection::create(SourceRange SelectionRange,
+ const SelectedASTNode &ASTSelection) {
+ // Code range is selected when the selection range is not empty.
+ if (SelectionRange.getBegin() == SelectionRange.getEnd())
+ return None;
+ llvm::SmallVector<SelectedNodeWithParents, 4> ContainSelection;
+ findDeepestWithKind(ASTSelection, ContainSelection,
+ SourceSelectionKind::ContainsSelection);
+ // We are looking for a selection in one body of code, so let's focus on
+ // one matching result.
+ if (ContainSelection.size() != 1)
+ return None;
+ SelectedNodeWithParents &Selected = ContainSelection[0];
+ if (!Selected.Node.get().Node.get<Stmt>())
+ return None;
+ const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<Stmt>();
+ if (!isa<CompoundStmt>(CodeRangeStmt)) {
+ // FIXME (Alex L): Canonicalize.
+ return CodeRangeASTSelection(Selected.Node, Selected.Parents,
+ /*AreChildrenSelected=*/false);
+ }
+ // FIXME (Alex L): First selected SwitchCase means that first case statement.
+ // is selected actually
+ // (See https://github.com/apple/swift-clang & CompoundStmtRange).
+
+ // FIXME (Alex L): Tweak selection rules for compound statements, see:
+ // https://github.com/apple/swift-clang/blob/swift-4.1-branch/lib/Tooling/
+ // Refactor/ASTSlice.cpp#L513
+ // The user selected multiple statements in a compound statement.
+ Selected.Parents.push_back(Selected.Node);
+ return CodeRangeASTSelection(Selected.Node, Selected.Parents,
+ /*AreChildrenSelected=*/true);
+}
+
+static bool isFunctionLikeDeclaration(const Decl *D) {
+ // FIXME (Alex L): Test for BlockDecl.
+ return isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D);
+}
+
+bool CodeRangeASTSelection::isInFunctionLikeBodyOfCode() const {
+ bool IsPrevCompound = false;
+ // Scan through the parents (bottom-to-top) and check if the selection is
+ // contained in a compound statement that's a body of a function/method
+ // declaration.
+ for (const auto &Parent : llvm::reverse(Parents)) {
+ const DynTypedNode &Node = Parent.get().Node;
+ if (const auto *D = Node.get<Decl>()) {
+ if (isFunctionLikeDeclaration(D))
+ return IsPrevCompound;
+ // FIXME (Alex L): We should return false on top-level decls in functions
+ // e.g. we don't want to extract:
+ // function foo() { struct X {
+ // int m = /*selection:*/ 1 + 2 /*selection end*/; }; };
+ }
+ IsPrevCompound = Node.get<CompoundStmt>() != nullptr;
+ }
+ return false;
+}
+
+const Decl *CodeRangeASTSelection::getFunctionLikeNearestParent() const {
+ for (const auto &Parent : llvm::reverse(Parents)) {
+ const DynTypedNode &Node = Parent.get().Node;
+ if (const auto *D = Node.get<Decl>()) {
+ if (isFunctionLikeDeclaration(D))
+ return D;
+ }
+ }
+ return nullptr;
+}
diff --git a/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
new file mode 100644
index 0000000000..c0232c5da4
--- /dev/null
+++ b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
@@ -0,0 +1,48 @@
+//===--- ASTSelectionRequirements.cpp - Clang refactoring library ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
+
+using namespace clang;
+using namespace tooling;
+
+Expected<SelectedASTNode>
+ASTSelectionRequirement::evaluate(RefactoringRuleContext &Context) const {
+ // FIXME: Memoize so that selection is evaluated only once.
+ Expected<SourceRange> Range =
+ SourceRangeSelectionRequirement::evaluate(Context);
+ if (!Range)
+ return Range.takeError();
+
+ Optional<SelectedASTNode> Selection =
+ findSelectedASTNodes(Context.getASTContext(), *Range);
+ if (!Selection)
+ return Context.createDiagnosticError(
+ Range->getBegin(), diag::err_refactor_selection_invalid_ast);
+ return std::move(*Selection);
+}
+
+Expected<CodeRangeASTSelection> CodeRangeASTSelectionRequirement::evaluate(
+ RefactoringRuleContext &Context) const {
+ // FIXME: Memoize so that selection is evaluated only once.
+ Expected<SelectedASTNode> ASTSelection =
+ ASTSelectionRequirement::evaluate(Context);
+ if (!ASTSelection)
+ return ASTSelection.takeError();
+ std::unique_ptr<SelectedASTNode> StoredSelection =
+ llvm::make_unique<SelectedASTNode>(std::move(*ASTSelection));
+ Optional<CodeRangeASTSelection> CodeRange = CodeRangeASTSelection::create(
+ Context.getSelectionRange(), *StoredSelection);
+ if (!CodeRange)
+ return Context.createDiagnosticError(
+ Context.getSelectionRange().getBegin(),
+ diag::err_refactor_selection_invalid_ast);
+ Context.setASTSelection(std::move(StoredSelection));
+ return std::move(*CodeRange);
+}
diff --git a/lib/Tooling/Refactoring/AtomicChange.cpp b/lib/Tooling/Refactoring/AtomicChange.cpp
index 02c55100ff..e4cc6a5617 100644
--- a/lib/Tooling/Refactoring/AtomicChange.cpp
+++ b/lib/Tooling/Refactoring/AtomicChange.cpp
@@ -12,7 +12,6 @@
#include "llvm/Support/YAMLTraits.h"
#include <string>
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
namespace {
@@ -84,6 +83,116 @@ template <> struct MappingTraits<clang::tooling::AtomicChange> {
namespace clang {
namespace tooling {
+namespace {
+
+// Returns true if there is any line that violates \p ColumnLimit in range
+// [Start, End].
+bool violatesColumnLimit(llvm::StringRef Code, unsigned ColumnLimit,
+ unsigned Start, unsigned End) {
+ auto StartPos = Code.rfind('\n', Start);
+ StartPos = (StartPos == llvm::StringRef::npos) ? 0 : StartPos + 1;
+
+ auto EndPos = Code.find("\n", End);
+ if (EndPos == llvm::StringRef::npos)
+ EndPos = Code.size();
+
+ llvm::SmallVector<llvm::StringRef, 8> Lines;
+ Code.substr(StartPos, EndPos - StartPos).split(Lines, '\n');
+ for (llvm::StringRef Line : Lines)
+ if (Line.size() > ColumnLimit)
+ return true;
+ return false;
+}
+
+std::vector<Range>
+getRangesForFormating(llvm::StringRef Code, unsigned ColumnLimit,
+ ApplyChangesSpec::FormatOption Format,
+ const clang::tooling::Replacements &Replaces) {
+ // kNone suppresses formatting entirely.
+ if (Format == ApplyChangesSpec::kNone)
+ return {};
+ std::vector<clang::tooling::Range> Ranges;
+ // This works assuming that replacements are ordered by offset.
+ // FIXME: use `getAffectedRanges()` to calculate when it does not include '\n'
+ // at the end of an insertion in affected ranges.
+ int Offset = 0;
+ for (const clang::tooling::Replacement &R : Replaces) {
+ int Start = R.getOffset() + Offset;
+ int End = Start + R.getReplacementText().size();
+ if (!R.getReplacementText().empty() &&
+ R.getReplacementText().back() == '\n' && R.getLength() == 0 &&
+ R.getOffset() > 0 && R.getOffset() <= Code.size() &&
+ Code[R.getOffset() - 1] == '\n')
+ // If we are inserting at the start of a line and the replacement ends in
+ // a newline, we don't need to format the subsequent line.
+ --End;
+ Offset += R.getReplacementText().size() - R.getLength();
+
+ if (Format == ApplyChangesSpec::kAll ||
+ violatesColumnLimit(Code, ColumnLimit, Start, End))
+ Ranges.emplace_back(Start, End - Start);
+ }
+ return Ranges;
+}
+
+inline llvm::Error make_string_error(const llvm::Twine &Message) {
+ return llvm::make_error<llvm::StringError>(Message,
+ llvm::inconvertibleErrorCode());
+}
+
+// Creates replacements for inserting/deleting #include headers.
+llvm::Expected<Replacements>
+createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code,
+ llvm::ArrayRef<AtomicChange> Changes,
+ const format::FormatStyle &Style) {
+ // Create header insertion/deletion replacements to be cleaned up
+ // (i.e. converted to real insertion/deletion replacements).
+ Replacements HeaderReplacements;
+ for (const auto &Change : Changes) {
+ for (llvm::StringRef Header : Change.getInsertedHeaders()) {
+ std::string EscapedHeader =
+ Header.startswith("<") || Header.startswith("\"")
+ ? Header.str()
+ : ("\"" + Header + "\"").str();
+ std::string ReplacementText = "#include " + EscapedHeader;
+ // Offset UINT_MAX and length 0 indicate that the replacement is a header
+ // insertion.
+ llvm::Error Err = HeaderReplacements.add(
+ tooling::Replacement(FilePath, UINT_MAX, 0, ReplacementText));
+ if (Err)
+ return std::move(Err);
+ }
+ for (const std::string &Header : Change.getRemovedHeaders()) {
+ // Offset UINT_MAX and length 1 indicate that the replacement is a header
+ // deletion.
+ llvm::Error Err =
+ HeaderReplacements.add(Replacement(FilePath, UINT_MAX, 1, Header));
+ if (Err)
+ return std::move(Err);
+ }
+ }
+
+ // cleanupAroundReplacements() converts header insertions/deletions into
+ // actual replacements that add/remove headers at the right location.
+ return clang::format::cleanupAroundReplacements(Code, HeaderReplacements,
+ Style);
+}
+
+// Combine replacements in all Changes as a `Replacements`. This ignores the
+// file path in all replacements and replaces them with \p FilePath.
+llvm::Expected<Replacements>
+combineReplacementsInChanges(llvm::StringRef FilePath,
+ llvm::ArrayRef<AtomicChange> Changes) {
+ Replacements Replaces;
+ for (const auto &Change : Changes)
+ for (const auto &R : Change.getReplacements())
+ if (auto Err = Replaces.add(Replacement(
+ FilePath, R.getOffset(), R.getLength(), R.getReplacementText())))
+ return std::move(Err);
+ return Replaces;
+}
+
+} // end namespace
AtomicChange::AtomicChange(const SourceManager &SM,
SourceLocation KeyPosition) {
@@ -106,6 +215,15 @@ AtomicChange::AtomicChange(std::string Key, std::string FilePath,
RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {
}
+bool AtomicChange::operator==(const AtomicChange &Other) const {
+ if (Key != Other.Key || FilePath != Other.FilePath || Error != Other.Error)
+ return false;
+ if (!(Replaces == Other.Replaces))
+ return false;
+ // FXIME: Compare header insertions/removals.
+ return true;
+}
+
std::string AtomicChange::toYAMLString() {
std::string YamlContent;
llvm::raw_string_ostream YamlContentStream(YamlContent);
@@ -132,6 +250,12 @@ AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
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));
@@ -168,5 +292,74 @@ void AtomicChange::removeHeader(llvm::StringRef Header) {
RemovedHeaders.push_back(Header);
}
+llvm::Expected<std::string>
+applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code,
+ llvm::ArrayRef<AtomicChange> Changes,
+ const ApplyChangesSpec &Spec) {
+ llvm::Expected<Replacements> HeaderReplacements =
+ createReplacementsForHeaders(FilePath, Code, Changes, Spec.Style);
+ if (!HeaderReplacements)
+ return make_string_error(
+ "Failed to create replacements for header changes: " +
+ llvm::toString(HeaderReplacements.takeError()));
+
+ llvm::Expected<Replacements> Replaces =
+ combineReplacementsInChanges(FilePath, Changes);
+ if (!Replaces)
+ return make_string_error("Failed to combine replacements in all changes: " +
+ llvm::toString(Replaces.takeError()));
+
+ Replacements AllReplaces = std::move(*Replaces);
+ for (const auto &R : *HeaderReplacements) {
+ llvm::Error Err = AllReplaces.add(R);
+ if (Err)
+ return make_string_error(
+ "Failed to combine existing replacements with header replacements: " +
+ llvm::toString(std::move(Err)));
+ }
+
+ if (Spec.Cleanup) {
+ llvm::Expected<Replacements> CleanReplaces =
+ format::cleanupAroundReplacements(Code, AllReplaces, Spec.Style);
+ if (!CleanReplaces)
+ return make_string_error("Failed to cleanup around replacements: " +
+ llvm::toString(CleanReplaces.takeError()));
+ AllReplaces = std::move(*CleanReplaces);
+ }
+
+ // Apply all replacements.
+ llvm::Expected<std::string> ChangedCode =
+ applyAllReplacements(Code, AllReplaces);
+ if (!ChangedCode)
+ return make_string_error("Failed to apply all replacements: " +
+ llvm::toString(ChangedCode.takeError()));
+
+ // Sort inserted headers. This is done even if other formatting is turned off
+ // as incorrectly sorted headers are always just wrong, it's not a matter of
+ // taste.
+ Replacements HeaderSortingReplacements = format::sortIncludes(
+ Spec.Style, *ChangedCode, AllReplaces.getAffectedRanges(), FilePath);
+ ChangedCode = applyAllReplacements(*ChangedCode, HeaderSortingReplacements);
+ if (!ChangedCode)
+ return make_string_error(
+ "Failed to apply replacements for sorting includes: " +
+ llvm::toString(ChangedCode.takeError()));
+
+ AllReplaces = AllReplaces.merge(HeaderSortingReplacements);
+
+ std::vector<Range> FormatRanges = getRangesForFormating(
+ *ChangedCode, Spec.Style.ColumnLimit, Spec.Format, AllReplaces);
+ if (!FormatRanges.empty()) {
+ Replacements FormatReplacements =
+ format::reformat(Spec.Style, *ChangedCode, FormatRanges, FilePath);
+ ChangedCode = applyAllReplacements(*ChangedCode, FormatReplacements);
+ if (!ChangedCode)
+ return make_string_error(
+ "Failed to apply replacements for formatting changed code: " +
+ llvm::toString(ChangedCode.takeError()));
+ }
+ return ChangedCode;
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/lib/Tooling/Refactoring/CMakeLists.txt b/lib/Tooling/Refactoring/CMakeLists.txt
index b2f9b4f4c0..5d3ddd45b6 100644
--- a/lib/Tooling/Refactoring/CMakeLists.txt
+++ b/lib/Tooling/Refactoring/CMakeLists.txt
@@ -1,12 +1,24 @@
-set(LLVM_LINK_COMPONENTS
- Option
- Support
- )
+set(LLVM_LINK_COMPONENTS Support)
add_clang_library(clangToolingRefactor
+ ASTSelection.cpp
+ ASTSelectionRequirements.cpp
AtomicChange.cpp
+ Extract.cpp
+ RefactoringActions.cpp
+ Rename/RenamingAction.cpp
+ Rename/SymbolOccurrences.cpp
+ Rename/USRFinder.cpp
+ Rename/USRFindingAction.cpp
+ Rename/USRLocFinder.cpp
LINK_LIBS
+ clangAST
+ clangASTMatchers
clangBasic
+ clangFormat
+ clangIndex
+ clangLex
+ clangRewrite
clangToolingCore
)
diff --git a/lib/Tooling/Refactoring/Extract.cpp b/lib/Tooling/Refactoring/Extract.cpp
new file mode 100644
index 0000000000..3f5a839318
--- /dev/null
+++ b/lib/Tooling/Refactoring/Extract.cpp
@@ -0,0 +1,195 @@
+//===--- Extract.cpp - Clang refactoring library --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements the "extract" refactoring that can pull code into
+/// new functions, methods or declare new variables.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// Returns true if \c E is a simple literal or a reference expression that
+/// should not be extracted.
+bool isSimpleExpression(const Expr *E) {
+ if (!E)
+ return false;
+ switch (E->IgnoreParenCasts()->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ case Stmt::PredefinedExprClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::StringLiteralClass:
+ return true;
+ default:
+ return false;
+ }
+}
+
+SourceLocation computeFunctionExtractionLocation(const Decl *D) {
+ if (isa<CXXMethodDecl>(D)) {
+ // Code from method that is defined in class body should be extracted to a
+ // function defined just before the class.
+ while (const auto *RD = dyn_cast<CXXRecordDecl>(D->getLexicalDeclContext()))
+ D = RD;
+ }
+ return D->getLocStart();
+}
+
+} // end anonymous namespace
+
+const RefactoringDescriptor &ExtractFunction::describe() {
+ static const RefactoringDescriptor Descriptor = {
+ "extract-function",
+ "Extract Function",
+ "(WIP action; use with caution!) Extracts code into a new function",
+ };
+ return Descriptor;
+}
+
+Expected<ExtractFunction>
+ExtractFunction::initiate(RefactoringRuleContext &Context,
+ CodeRangeASTSelection Code,
+ Optional<std::string> DeclName) {
+ // We would like to extract code out of functions/methods/blocks.
+ // Prohibit extraction from things like global variable / field
+ // initializers and other top-level expressions.
+ if (!Code.isInFunctionLikeBodyOfCode())
+ return Context.createDiagnosticError(
+ diag::err_refactor_code_outside_of_function);
+
+ if (Code.size() == 1) {
+ // Avoid extraction of simple literals and references.
+ if (isSimpleExpression(dyn_cast<Expr>(Code[0])))
+ return Context.createDiagnosticError(
+ diag::err_refactor_extract_simple_expression);
+
+ // Property setters can't be extracted.
+ if (const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(Code[0])) {
+ if (!PRE->isMessagingGetter())
+ return Context.createDiagnosticError(
+ diag::err_refactor_extract_prohibited_expression);
+ }
+ }
+
+ return ExtractFunction(std::move(Code), DeclName);
+}
+
+// FIXME: Support C++ method extraction.
+// FIXME: Support Objective-C method extraction.
+Expected<AtomicChanges>
+ExtractFunction::createSourceReplacements(RefactoringRuleContext &Context) {
+ const Decl *ParentDecl = Code.getFunctionLikeNearestParent();
+ assert(ParentDecl && "missing parent");
+
+ // Compute the source range of the code that should be extracted.
+ SourceRange ExtractedRange(Code[0]->getLocStart(),
+ Code[Code.size() - 1]->getLocEnd());
+ // FIXME (Alex L): Add code that accounts for macro locations.
+
+ ASTContext &AST = Context.getASTContext();
+ SourceManager &SM = AST.getSourceManager();
+ const LangOptions &LangOpts = AST.getLangOpts();
+ Rewriter ExtractedCodeRewriter(SM, LangOpts);
+
+ // FIXME: Capture used variables.
+
+ // Compute the return type.
+ QualType ReturnType = AST.VoidTy;
+ // FIXME (Alex L): Account for the return statement in extracted code.
+ // FIXME (Alex L): Check for lexical expression instead.
+ bool IsExpr = Code.size() == 1 && isa<Expr>(Code[0]);
+ if (IsExpr) {
+ // FIXME (Alex L): Get a more user-friendly type if needed.
+ ReturnType = cast<Expr>(Code[0])->getType();
+ }
+
+ // FIXME: Rewrite the extracted code performing any required adjustments.
+
+ // FIXME: Capture any field if necessary (method -> function extraction).
+
+ // FIXME: Sort captured variables by name.
+
+ // FIXME: Capture 'this' / 'self' if necessary.
+
+ // FIXME: Compute the actual parameter types.
+
+ // Compute the location of the extracted declaration.
+ SourceLocation ExtractedDeclLocation =
+ computeFunctionExtractionLocation(ParentDecl);
+ // FIXME: Adjust the location to account for any preceding comments.
+
+ // FIXME: Adjust with PP awareness like in Sema to get correct 'bool'
+ // treatment.
+ PrintingPolicy PP = AST.getPrintingPolicy();
+ // FIXME: PP.UseStdFunctionForLambda = true;
+ PP.SuppressStrongLifetime = true;
+ PP.SuppressLifetimeQualifiers = true;
+ PP.SuppressUnwrittenScope = true;
+
+ AtomicChange Change(SM, ExtractedDeclLocation);
+ // Create the replacement for the extracted declaration.
+ {
+ std::string ExtractedCode;
+ llvm::raw_string_ostream OS(ExtractedCode);
+ // FIXME: Use 'inline' in header.
+ OS << "static ";
+ ReturnType.print(OS, PP, DeclName);
+ OS << '(';
+ // FIXME: Arguments.
+ OS << ')';
+
+ // Function body.
+ OS << " {\n";
+ if (IsExpr && !ReturnType->isVoidType())
+ OS << "return ";
+ OS << ExtractedCodeRewriter.getRewrittenText(ExtractedRange);
+ // FIXME: Compute the correct semicolon policy.
+ OS << ';';
+ OS << "\n}\n\n";
+ auto Err = Change.insert(SM, ExtractedDeclLocation, OS.str());
+ if (Err)
+ return std::move(Err);
+ }
+
+ // Create the replacement for the call to the extracted declaration.
+ {
+ std::string ReplacedCode;
+ llvm::raw_string_ostream OS(ReplacedCode);
+
+ OS << DeclName << '(';
+ // FIXME: Forward arguments.
+ OS << ')';
+ // FIXME: Add semicolon if needed.
+
+ auto Err = Change.replace(
+ SM, CharSourceRange::getTokenRange(ExtractedRange), OS.str());
+ if (Err)
+ return std::move(Err);
+ }
+
+ // FIXME: Add support for assocciated symbol location to AtomicChange to mark
+ // the ranges of the name of the extracted declaration.
+ return AtomicChanges{std::move(Change)};
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Refactoring/RefactoringActions.cpp b/lib/Tooling/Refactoring/RefactoringActions.cpp
new file mode 100644
index 0000000000..73a3118396
--- /dev/null
+++ b/lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -0,0 +1,94 @@
+//===--- RefactoringActions.cpp - Constructs refactoring actions ----------===//
+//
+// 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/Extract/Extract.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+class DeclNameOption final : public OptionalRefactoringOption<std::string> {
+public:
+ StringRef getName() const { return "name"; }
+ StringRef getDescription() const {
+ return "Name of the extracted declaration";
+ }
+};
+
+// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with
+// rules.
+class ExtractRefactoring final : public RefactoringAction {
+public:
+ StringRef getCommand() const override { return "extract"; }
+
+ StringRef getDescription() const override {
+ return "(WIP action; use with caution!) Extracts code into a new function";
+ }
+
+ /// Returns a set of refactoring actions rules that are defined by this
+ /// action.
+ RefactoringActionRules createActionRules() const override {
+ RefactoringActionRules Rules;
+ Rules.push_back(createRefactoringActionRule<ExtractFunction>(
+ CodeRangeASTSelectionRequirement(),
+ OptionRequirement<DeclNameOption>()));
+ return Rules;
+ }
+};
+
+class NewNameOption : public RequiredRefactoringOption<std::string> {
+public:
+ StringRef getName() const override { return "new-name"; }
+ StringRef getDescription() const override {
+ return "The new name to change the symbol to";
+ }
+};
+
+// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with
+// rules.
+class LocalRename final : public RefactoringAction {
+public:
+ StringRef getCommand() const override { return "local-rename"; }
+
+ StringRef getDescription() const override {
+ return "Finds and renames symbols in code with no indexer support";
+ }
+
+ /// Returns a set of refactoring actions rules that are defined by this
+ /// action.
+ RefactoringActionRules createActionRules() const override {
+ RefactoringActionRules Rules;
+ Rules.push_back(createRefactoringActionRule<RenameOccurrences>(
+ SourceRangeSelectionRequirement(), OptionRequirement<NewNameOption>()));
+ return Rules;
+ }
+};
+
+} // end anonymous namespace
+
+std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions() {
+ std::vector<std::unique_ptr<RefactoringAction>> Actions;
+
+ Actions.push_back(llvm::make_unique<LocalRename>());
+ Actions.push_back(llvm::make_unique<ExtractRefactoring>());
+
+ return Actions;
+}
+
+RefactoringActionRules RefactoringAction::createActiveActionRules() {
+ // FIXME: Filter out rules that are not supported by a particular client.
+ return createActionRules();
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
new file mode 100644
index 0000000000..695fa553b4
--- /dev/null
+++ b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -0,0 +1,230 @@
+//===--- RenamingAction.cpp - Clang refactoring library -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to rename every symbol at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+class OccurrenceFinder final : public FindSymbolOccurrencesRefactoringRule {
+public:
+ OccurrenceFinder(const NamedDecl *ND) : ND(ND) {}
+
+ Expected<SymbolOccurrences>
+ findSymbolOccurrences(RefactoringRuleContext &Context) override {
+ std::vector<std::string> USRs =
+ getUSRsForDeclaration(ND, Context.getASTContext());
+ std::string PrevName = ND->getNameAsString();
+ return getOccurrencesOfUSRs(
+ USRs, PrevName, Context.getASTContext().getTranslationUnitDecl());
+ }
+
+private:
+ const NamedDecl *ND;
+};
+
+} // end anonymous namespace
+
+const RefactoringDescriptor &RenameOccurrences::describe() {
+ static const RefactoringDescriptor Descriptor = {
+ "local-rename",
+ "Rename",
+ "Finds and renames symbols in code with no indexer support",
+ };
+ return Descriptor;
+}
+
+Expected<RenameOccurrences>
+RenameOccurrences::initiate(RefactoringRuleContext &Context,
+ SourceRange SelectionRange, std::string NewName) {
+ const NamedDecl *ND =
+ getNamedDeclAt(Context.getASTContext(), SelectionRange.getBegin());
+ if (!ND)
+ return Context.createDiagnosticError(
+ SelectionRange.getBegin(), diag::err_refactor_selection_no_symbol);
+ return RenameOccurrences(getCanonicalSymbolDeclaration(ND),
+ std::move(NewName));
+}
+
+Expected<AtomicChanges>
+RenameOccurrences::createSourceReplacements(RefactoringRuleContext &Context) {
+ Expected<SymbolOccurrences> Occurrences =
+ OccurrenceFinder(ND).findSymbolOccurrences(Context);
+ if (!Occurrences)
+ return Occurrences.takeError();
+ // FIXME: Verify that the new name is valid.
+ SymbolName Name(NewName);
+ return createRenameReplacements(
+ *Occurrences, Context.getASTContext().getSourceManager(), Name);
+}
+
+Expected<std::vector<AtomicChange>>
+createRenameReplacements(const SymbolOccurrences &Occurrences,
+ const SourceManager &SM, const SymbolName &NewName) {
+ // FIXME: A true local rename can use just one AtomicChange.
+ std::vector<AtomicChange> Changes;
+ for (const auto &Occurrence : Occurrences) {
+ ArrayRef<SourceRange> Ranges = Occurrence.getNameRanges();
+ assert(NewName.getNamePieces().size() == Ranges.size() &&
+ "Mismatching number of ranges and name pieces");
+ AtomicChange Change(SM, Ranges[0].getBegin());
+ for (const auto &Range : llvm::enumerate(Ranges)) {
+ auto Error =
+ Change.replace(SM, CharSourceRange::getCharRange(Range.value()),
+ NewName.getNamePieces()[Range.index()]);
+ if (Error)
+ return std::move(Error);
+ }
+ Changes.push_back(std::move(Change));
+ }
+ return std::move(Changes);
+}
+
+/// Takes each atomic change and inserts its replacements into the set of
+/// replacements that belong to the appropriate file.
+static void convertChangesToFileReplacements(
+ ArrayRef<AtomicChange> AtomicChanges,
+ std::map<std::string, tooling::Replacements> *FileToReplaces) {
+ for (const auto &AtomicChange : AtomicChanges) {
+ for (const auto &Replace : AtomicChange.getReplacements()) {
+ llvm::Error Err = (*FileToReplaces)[Replace.getFilePath()].add(Replace);
+ if (Err) {
+ llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
+ }
+}
+
+class RenamingASTConsumer : public ASTConsumer {
+public:
+ RenamingASTConsumer(
+ const std::vector<std::string> &NewNames,
+ const std::vector<std::string> &PrevNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces,
+ bool PrintLocations)
+ : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
+ FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ for (unsigned I = 0; I < NewNames.size(); ++I) {
+ // If the previous name was not found, ignore this rename request.
+ if (PrevNames[I].empty())
+ continue;
+
+ HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]);
+ }
+ }
+
+ void HandleOneRename(ASTContext &Context, const std::string &NewName,
+ const std::string &PrevName,
+ const std::vector<std::string> &USRs) {
+ const SourceManager &SourceMgr = Context.getSourceManager();
+
+ SymbolOccurrences Occurrences = tooling::getOccurrencesOfUSRs(
+ USRs, PrevName, Context.getTranslationUnitDecl());
+ if (PrintLocations) {
+ for (const auto &Occurrence : Occurrences) {
+ FullSourceLoc FullLoc(Occurrence.getNameRanges()[0].getBegin(),
+ SourceMgr);
+ errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(FullLoc)
+ << ":" << FullLoc.getSpellingLineNumber() << ":"
+ << FullLoc.getSpellingColumnNumber() << "\n";
+ }
+ }
+ // FIXME: Support multi-piece names.
+ // FIXME: better error handling (propagate error out).
+ SymbolName NewNameRef(NewName);
+ Expected<std::vector<AtomicChange>> Change =
+ createRenameReplacements(Occurrences, SourceMgr, NewNameRef);
+ if (!Change) {
+ llvm::errs() << "Failed to create renaming replacements for '" << PrevName
+ << "'! " << llvm::toString(Change.takeError()) << "\n";
+ return;
+ }
+ convertChangesToFileReplacements(*Change, &FileToReplaces);
+ }
+
+private:
+ const std::vector<std::string> &NewNames, &PrevNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+ bool PrintLocations;
+};
+
+// A renamer to rename symbols which are identified by a give USRList to
+// new name.
+//
+// FIXME: Merge with the above RenamingASTConsumer.
+class USRSymbolRenamer : public ASTConsumer {
+public:
+ USRSymbolRenamer(const std::vector<std::string> &NewNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces)
+ : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {
+ assert(USRList.size() == NewNames.size());
+ }
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ for (unsigned I = 0; I < NewNames.size(); ++I) {
+ // FIXME: Apply AtomicChanges directly once the refactoring APIs are
+ // ready.
+ auto AtomicChanges = tooling::createRenameAtomicChanges(
+ USRList[I], NewNames[I], Context.getTranslationUnitDecl());
+ convertChangesToFileReplacements(AtomicChanges, &FileToReplaces);
+ }
+ }
+
+private:
+ const std::vector<std::string> &NewNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+};
+
+std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
+ return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList,
+ FileToReplaces, PrintLocations);
+}
+
+std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() {
+ return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp b/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
new file mode 100644
index 0000000000..ea64b2c1aa
--- /dev/null
+++ b/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
@@ -0,0 +1,37 @@
+//===--- SymbolOccurrences.cpp - Clang refactoring library ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+using namespace tooling;
+
+SymbolOccurrence::SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind,
+ ArrayRef<SourceLocation> Locations)
+ : Kind(Kind) {
+ ArrayRef<std::string> NamePieces = Name.getNamePieces();
+ assert(Locations.size() == NamePieces.size() &&
+ "mismatching number of locations and lengths");
+ assert(!Locations.empty() && "no locations");
+ if (Locations.size() == 1) {
+ RangeOrNumRanges = SourceRange(
+ Locations[0], Locations[0].getLocWithOffset(NamePieces[0].size()));
+ return;
+ }
+ MultipleRanges = llvm::make_unique<SourceRange[]>(Locations.size());
+ RangeOrNumRanges.setBegin(
+ SourceLocation::getFromRawEncoding(Locations.size()));
+ for (const auto &Loc : llvm::enumerate(Locations)) {
+ MultipleRanges[Loc.index()] = SourceRange(
+ Loc.value(),
+ Loc.value().getLocWithOffset(NamePieces[Loc.index()].size()));
+ }
+}
diff --git a/lib/Tooling/Refactoring/Rename/USRFinder.cpp b/lib/Tooling/Refactoring/Rename/USRFinder.cpp
new file mode 100644
index 0000000000..3bfb5bbe35
--- /dev/null
+++ b/lib/Tooling/Refactoring/Rename/USRFinder.cpp
@@ -0,0 +1,146 @@
+//===--- USRFinder.cpp - Clang refactoring library ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
+/// point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// Recursively visits each AST node to find the symbol underneath the cursor.
+class NamedDeclOccurrenceFindingVisitor
+ : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
+public:
+ // \brief Finds the NamedDecl at a point in the source.
+ // \param Point the location in the source to search for the NamedDecl.
+ explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,
+ const ASTContext &Context)
+ : RecursiveSymbolVisitor(Context.getSourceManager(),
+ Context.getLangOpts()),
+ Point(Point), Context(Context) {}
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ if (!ND)
+ return true;
+ for (const auto &Range : NameRanges) {
+ SourceLocation Start = Range.getBegin();
+ SourceLocation End = Range.getEnd();
+ if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
+ !End.isFileID() || !isPointWithin(Start, End))
+ return true;
+ }
+ Result = ND;
+ return false;
+ }
+
+ const NamedDecl *getNamedDecl() const { return Result; }
+
+private:
+ // \brief Determines if the Point is within Start and End.
+ bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
+ // FIXME: Add tests for Point == End.
+ return Point == Start || Point == End ||
+ (Context.getSourceManager().isBeforeInTranslationUnit(Start,
+ Point) &&
+ Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
+ }
+
+ const NamedDecl *Result = nullptr;
+ const SourceLocation Point; // The location to find the NamedDecl.
+ const ASTContext &Context;
+};
+
+} // end anonymous namespace
+
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,
+ const SourceLocation Point) {
+ const SourceManager &SM = Context.getSourceManager();
+ NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);
+
+ // Try to be clever about pruning down the number of top-level declarations we
+ // see. If both start and end is either before or after the point we're
+ // looking for the point cannot be inside of this decl. Don't even look at it.
+ for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
+ SourceLocation StartLoc = CurrDecl->getLocStart();
+ SourceLocation EndLoc = CurrDecl->getLocEnd();
+ if (StartLoc.isValid() && EndLoc.isValid() &&
+ SM.isBeforeInTranslationUnit(StartLoc, Point) !=
+ SM.isBeforeInTranslationUnit(EndLoc, Point))
+ Visitor.TraverseDecl(CurrDecl);
+ }
+
+ return Visitor.getNamedDecl();
+}
+
+namespace {
+
+/// Recursively visits each NamedDecl node to find the declaration with a
+/// specific name.
+class NamedDeclFindingVisitor
+ : public RecursiveASTVisitor<NamedDeclFindingVisitor> {
+public:
+ explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}
+
+ // We don't have to traverse the uses to find some declaration with a
+ // specific name, so just visit the named declarations.
+ bool VisitNamedDecl(const NamedDecl *ND) {
+ if (!ND)
+ return true;
+ // Fully qualified name is used to find the declaration.
+ if (Name != ND->getQualifiedNameAsString() &&
+ Name != "::" + ND->getQualifiedNameAsString())
+ return true;
+ Result = ND;
+ return false;
+ }
+
+ const NamedDecl *getNamedDecl() const { return Result; }
+
+private:
+ const NamedDecl *Result = nullptr;
+ StringRef Name;
+};
+
+} // end anonymous namespace
+
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,
+ const std::string &Name) {
+ NamedDeclFindingVisitor Visitor(Name);
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ return Visitor.getNamedDecl();
+}
+
+std::string getUSRForDecl(const Decl *Decl) {
+ llvm::SmallVector<char, 128> Buff;
+
+ // FIXME: Add test for the nullptr case.
+ if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
+ return "";
+
+ return std::string(Buff.data(), Buff.size());
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
new file mode 100644
index 0000000000..40b70d8a05
--- /dev/null
+++ b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
@@ -0,0 +1,274 @@
+//===--- USRFindingAction.cpp - Clang refactoring library -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to find USR for the symbol at <offset>, as well as
+/// all additional USRs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/Tooling/Tooling.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl) {
+ // If FoundDecl is a constructor or destructor, we want to instead take
+ // the Decl of the corresponding class.
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
+ FoundDecl = CtorDecl->getParent();
+ else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
+ FoundDecl = DtorDecl->getParent();
+ // FIXME: (Alex L): Canonicalize implicit template instantions, just like
+ // the indexer does it.
+
+ // Note: please update the declaration's doc comment every time the
+ // canonicalization rules are changed.
+ return FoundDecl;
+}
+
+namespace {
+// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to
+// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given
+// Decl refers to class and adds USRs of all overridden methods if Decl refers
+// to virtual method.
+class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> {
+public:
+ AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
+ : FoundDecl(FoundDecl), Context(Context) {}
+
+ std::vector<std::string> Find() {
+ // Fill OverriddenMethods and PartialSpecs storages.
+ TraverseDecl(Context.getTranslationUnitDecl());
+ if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
+ addUSRsOfOverridenFunctions(MethodDecl);
+ for (const auto &OverriddenMethod : OverriddenMethods) {
+ if (checkIfOverriddenFunctionAscends(OverriddenMethod))
+ USRSet.insert(getUSRForDecl(OverriddenMethod));
+ }
+ addUSRsOfInstantiatedMethods(MethodDecl);
+ } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) {
+ handleCXXRecordDecl(RecordDecl);
+ } else if (const auto *TemplateDecl =
+ dyn_cast<ClassTemplateDecl>(FoundDecl)) {
+ handleClassTemplateDecl(TemplateDecl);
+ } else {
+ USRSet.insert(getUSRForDecl(FoundDecl));
+ }
+ return std::vector<std::string>(USRSet.begin(), USRSet.end());
+ }
+
+ bool shouldVisitTemplateInstantiations() const { return true; }
+
+ bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {
+ if (MethodDecl->isVirtual())
+ OverriddenMethods.push_back(MethodDecl);
+ if (MethodDecl->getInstantiatedFromMemberFunction())
+ InstantiatedMethods.push_back(MethodDecl);
+ return true;
+ }
+
+ bool VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *PartialSpec) {
+ PartialSpecs.push_back(PartialSpec);
+ return true;
+ }
+
+private:
+ void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
+ RecordDecl = RecordDecl->getDefinition();
+ if (const auto *ClassTemplateSpecDecl =
+ dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
+ handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate());
+ addUSRsOfCtorDtors(RecordDecl);
+ }
+
+ void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {
+ for (const auto *Specialization : TemplateDecl->specializations())
+ addUSRsOfCtorDtors(Specialization);
+
+ for (const auto *PartialSpec : PartialSpecs) {
+ if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
+ addUSRsOfCtorDtors(PartialSpec);
+ }
+ addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
+ }
+
+ void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) {
+ RecordDecl = RecordDecl->getDefinition();
+
+ // Skip if the CXXRecordDecl doesn't have definition.
+ if (!RecordDecl)
+ return;
+
+ for (const auto *CtorDecl : RecordDecl->ctors())
+ USRSet.insert(getUSRForDecl(CtorDecl));
+
+ USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
+ USRSet.insert(getUSRForDecl(RecordDecl));
+ }
+
+ void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) {
+ USRSet.insert(getUSRForDecl(MethodDecl));
+ // Recursively visit each OverridenMethod.
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
+ addUSRsOfOverridenFunctions(OverriddenMethod);
+ }
+
+ void addUSRsOfInstantiatedMethods(const CXXMethodDecl *MethodDecl) {
+ // For renaming a class template method, all references of the instantiated
+ // member methods should be renamed too, so add USRs of the instantiated
+ // methods to the USR set.
+ USRSet.insert(getUSRForDecl(MethodDecl));
+ if (const auto *FT = MethodDecl->getInstantiatedFromMemberFunction())
+ USRSet.insert(getUSRForDecl(FT));
+ for (const auto *Method : InstantiatedMethods) {
+ if (USRSet.find(getUSRForDecl(
+ Method->getInstantiatedFromMemberFunction())) != USRSet.end())
+ USRSet.insert(getUSRForDecl(Method));
+ }
+ }
+
+ bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) {
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) {
+ if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end())
+ return true;
+ return checkIfOverriddenFunctionAscends(OverriddenMethod);
+ }
+ return false;
+ }
+
+ const Decl *FoundDecl;
+ ASTContext &Context;
+ std::set<std::string> USRSet;
+ std::vector<const CXXMethodDecl *> OverriddenMethods;
+ std::vector<const CXXMethodDecl *> InstantiatedMethods;
+ std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs;
+};
+} // namespace
+
+std::vector<std::string> getUSRsForDeclaration(const NamedDecl *ND,
+ ASTContext &Context) {
+ AdditionalUSRFinder Finder(ND, Context);
+ return Finder.Find();
+}
+
+class NamedDeclFindingConsumer : public ASTConsumer {
+public:
+ NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets,
+ ArrayRef<std::string> QualifiedNames,
+ std::vector<std::string> &SpellingNames,
+ std::vector<std::vector<std::string>> &USRList,
+ bool Force, bool &ErrorOccurred)
+ : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
+ SpellingNames(SpellingNames), USRList(USRList), Force(Force),
+ ErrorOccurred(ErrorOccurred) {}
+
+private:
+ bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
+ unsigned SymbolOffset, const std::string &QualifiedName) {
+ DiagnosticsEngine &Engine = Context.getDiagnostics();
+ const FileID MainFileID = SourceMgr.getMainFileID();
+
+ if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
+ ErrorOccurred = true;
+ unsigned InvalidOffset = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "SourceLocation in file %0 at offset %1 is invalid");
+ Engine.Report(SourceLocation(), InvalidOffset)
+ << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset;
+ return false;
+ }
+
+ const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID)
+ .getLocWithOffset(SymbolOffset);
+ const NamedDecl *FoundDecl = QualifiedName.empty()
+ ? getNamedDeclAt(Context, Point)
+ : getNamedDeclFor(Context, QualifiedName);
+
+ if (FoundDecl == nullptr) {
+ if (QualifiedName.empty()) {
+ FullSourceLoc FullLoc(Point, SourceMgr);
+ unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "clang-rename could not find symbol (offset %0)");
+ Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
+ ErrorOccurred = true;
+ return false;
+ }
+
+ if (Force) {
+ SpellingNames.push_back(std::string());
+ USRList.push_back(std::vector<std::string>());
+ return true;
+ }
+
+ unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error, "clang-rename could not find symbol %0");
+ Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
+ ErrorOccurred = true;
+ return false;
+ }
+
+ FoundDecl = getCanonicalSymbolDeclaration(FoundDecl);
+ SpellingNames.push_back(FoundDecl->getNameAsString());
+ AdditionalUSRFinder Finder(FoundDecl, Context);
+ USRList.push_back(Finder.Find());
+ return true;
+ }
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ const SourceManager &SourceMgr = Context.getSourceManager();
+ for (unsigned Offset : SymbolOffsets) {
+ if (!FindSymbol(Context, SourceMgr, Offset, ""))
+ return;
+ }
+ for (const std::string &QualifiedName : QualifiedNames) {
+ if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
+ return;
+ }
+ }
+
+ ArrayRef<unsigned> SymbolOffsets;
+ ArrayRef<std::string> QualifiedNames;
+ std::vector<std::string> &SpellingNames;
+ std::vector<std::vector<std::string>> &USRList;
+ bool Force;
+ bool &ErrorOccurred;
+};
+
+std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
+ return llvm::make_unique<NamedDeclFindingConsumer>(
+ SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
+ ErrorOccurred);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
new file mode 100644
index 0000000000..c77304a173
--- /dev/null
+++ b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
@@ -0,0 +1,585 @@
+//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Methods for finding all instances of a USR. Our strategy is very
+/// simple; we just compare the USR at every relevant AST node with the one
+/// provided.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Lookup.h"
+#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <cstddef>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// Returns true if the given Loc is valid for edit. We don't edit the
+// SourceLocations that are valid or in temporary buffer.
+bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return false;
+ const clang::FullSourceLoc FullLoc(Loc, SM);
+ std::pair<clang::FileID, unsigned> FileIdAndOffset =
+ FullLoc.getSpellingLoc().getDecomposedLoc();
+ return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr;
+}
+
+// \brief This visitor recursively searches for all instances of a USR in a
+// translation unit and stores them for later usage.
+class USRLocFindingASTVisitor
+ : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
+public:
+ explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
+ StringRef PrevName,
+ const ASTContext &Context)
+ : RecursiveSymbolVisitor(Context.getSourceManager(),
+ Context.getLangOpts()),
+ USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
+ }
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) {
+ assert(NameRanges.size() == 1 &&
+ "Multiple name pieces are not supported yet!");
+ SourceLocation Loc = NameRanges[0].getBegin();
+ const SourceManager &SM = Context.getSourceManager();
+ // TODO: Deal with macro occurrences correctly.
+ if (Loc.isMacroID())
+ Loc = SM.getSpellingLoc(Loc);
+ checkAndAddLocation(Loc);
+ }
+ return true;
+ }
+
+ // Non-visitors:
+
+ /// \brief Returns a set of unique symbol occurrences. Duplicate or
+ /// overlapping occurrences are erroneous and should be reported!
+ SymbolOccurrences takeOccurrences() { return std::move(Occurrences); }
+
+private:
+ void checkAndAddLocation(SourceLocation Loc) {
+ const SourceLocation BeginLoc = Loc;
+ const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
+ StringRef TokenName =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
+ Context.getSourceManager(), Context.getLangOpts());
+ size_t Offset = TokenName.find(PrevName.getNamePieces()[0]);
+
+ // The token of the source location we find actually has the old
+ // name.
+ if (Offset != StringRef::npos)
+ Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol,
+ BeginLoc.getLocWithOffset(Offset));
+ }
+
+ const std::set<std::string> USRSet;
+ const SymbolName PrevName;
+ SymbolOccurrences Occurrences;
+ const ASTContext &Context;
+};
+
+SourceLocation StartLocationForType(TypeLoc TL) {
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
+ NestedNameSpecifierLoc NestedNameSpecifier =
+ ElaboratedTypeLoc.getQualifierLoc();
+ if (NestedNameSpecifier.getNestedNameSpecifier())
+ return NestedNameSpecifier.getBeginLoc();
+ TL = TL.getNextTypeLoc();
+ }
+ return TL.getLocStart();
+}
+
+SourceLocation EndLocationForType(TypeLoc TL) {
+ // Dig past any namespace or keyword qualifications.
+ while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
+ TL.getTypeLocClass() == TypeLoc::Qualified)
+ TL = TL.getNextTypeLoc();
+
+ // The location for template specializations (e.g. Foo<int>) includes the
+ // templated types in its location range. We want to restrict this to just
+ // before the `<` character.
+ if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
+ return TL.castAs<TemplateSpecializationTypeLoc>()
+ .getLAngleLoc()
+ .getLocWithOffset(-1);
+ }
+ return TL.getEndLoc();
+}
+
+NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
+ // Dig past any keyword qualifications.
+ while (TL.getTypeLocClass() == TypeLoc::Qualified)
+ TL = TL.getNextTypeLoc();
+
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
+ return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
+ return nullptr;
+}
+
+// Find all locations identified by the given USRs for rename.
+//
+// This class will traverse the AST and find every AST node whose USR is in the
+// given USRs' set.
+class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
+public:
+ RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
+ : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
+
+ // A structure records all information of a symbol reference being renamed.
+ // We try to add as few prefix qualifiers as possible.
+ struct RenameInfo {
+ // The begin location of a symbol being renamed.
+ SourceLocation Begin;
+ // The end location of a symbol being renamed.
+ SourceLocation End;
+ // The declaration of a symbol being renamed (can be nullptr).
+ const NamedDecl *FromDecl;
+ // The declaration in which the nested name is contained (can be nullptr).
+ const Decl *Context;
+ // The nested name being replaced (can be nullptr).
+ const NestedNameSpecifier *Specifier;
+ // Determine whether the prefix qualifiers of the NewName should be ignored.
+ // Normally, we set it to true for the symbol declaration and definition to
+ // avoid adding prefix qualifiers.
+ // For example, if it is true and NewName is "a::b::foo", then the symbol
+ // occurrence which the RenameInfo points to will be renamed to "foo".
+ bool IgnorePrefixQualifers;
+ };
+
+ bool VisitNamedDecl(const NamedDecl *Decl) {
+ // UsingDecl has been handled in other place.
+ if (llvm::isa<UsingDecl>(Decl))
+ return true;
+
+ // DestructorDecl has been handled in Typeloc.
+ if (llvm::isa<CXXDestructorDecl>(Decl))
+ return true;
+
+ if (Decl->isImplicit())
+ return true;
+
+ if (isInUSRSet(Decl)) {
+ // For the case of renaming an alias template, we actually rename the
+ // underlying alias declaration of the template.
+ if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl))
+ Decl = TAT->getTemplatedDecl();
+
+ auto StartLoc = Decl->getLocation();
+ auto EndLoc = StartLoc;
+ if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {StartLoc,
+ EndLoc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifers=*/true};
+ RenameInfos.push_back(Info);
+ }
+ }
+ return true;
+ }
+
+ bool VisitMemberExpr(const MemberExpr *Expr) {
+ const NamedDecl *Decl = Expr->getFoundDecl();
+ auto StartLoc = Expr->getMemberLoc();
+ auto EndLoc = Expr->getMemberLoc();
+ if (isInUSRSet(Decl)) {
+ RenameInfos.push_back({StartLoc, EndLoc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifiers=*/true});
+ }
+ return true;
+ }
+
+ bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
+ // Fix the constructor initializer when renaming class members.
+ for (const auto *Initializer : CD->inits()) {
+ // Ignore implicit initializers.
+ if (!Initializer->isWritten())
+ continue;
+
+ if (const FieldDecl *FD = Initializer->getMember()) {
+ if (isInUSRSet(FD)) {
+ auto Loc = Initializer->getSourceLocation();
+ RenameInfos.push_back({Loc, Loc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifiers=*/true});
+ }
+ }
+ }
+ return true;
+ }
+
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+ const NamedDecl *Decl = Expr->getFoundDecl();
+ // Get the underlying declaration of the shadow declaration introduced by a
+ // using declaration.
+ if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
+ Decl = UsingShadow->getTargetDecl();
+ }
+
+ auto StartLoc = Expr->getLocStart();
+ // For template function call expressions like `foo<int>()`, we want to
+ // restrict the end of location to just before the `<` character.
+ SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
+ ? Expr->getLAngleLoc().getLocWithOffset(-1)
+ : Expr->getLocEnd();
+
+ if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
+ if (isInUSRSet(MD)) {
+ // Handle renaming static template class methods, we only rename the
+ // name without prefix qualifiers and restrict the source range to the
+ // name.
+ RenameInfos.push_back({EndLoc, EndLoc,
+ /*FromDecl=*/nullptr,
+ /*Context=*/nullptr,
+ /*Specifier=*/nullptr,
+ /*IgnorePrefixQualifiers=*/true});
+ return true;
+ }
+ }
+
+ // In case of renaming an enum declaration, we have to explicitly handle
+ // unscoped enum constants referenced in expressions (e.g.
+ // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped
+ // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by
+ // TypeLoc.
+ if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
+ // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`)
+ // when renaming an unscoped enum declaration with a new namespace.
+ if (!Expr->hasQualifier())
+ return true;
+
+ if (const auto *ED =
+ llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) {
+ if (ED->isScoped())
+ return true;
+ Decl = ED;
+ }
+ // The current fix would qualify "ns1::ns2::Green" as
+ // "ns1::ns2::Color::Green".
+ //
+ // Get the EndLoc of the replacement by moving 1 character backward (
+ // to exclude the last '::').
+ //
+ // ns1::ns2::Green;
+ // ^ ^^
+ // BeginLoc |EndLoc of the qualifier
+ // new EndLoc
+ EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
+ assert(EndLoc.isValid() &&
+ "The enum constant should have prefix qualifers.");
+ }
+ if (isInUSRSet(Decl) &&
+ IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {StartLoc,
+ EndLoc,
+ Decl,
+ getClosestAncestorDecl(*Expr),
+ Expr->getQualifier(),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+
+ return true;
+ }
+
+ bool VisitUsingDecl(const UsingDecl *Using) {
+ for (const auto *UsingShadow : Using->shadows()) {
+ if (isInUSRSet(UsingShadow->getTargetDecl())) {
+ UsingDecls.push_back(Using);
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
+ if (!NestedLoc.getNestedNameSpecifier()->getAsType())
+ return true;
+
+ if (const auto *TargetDecl =
+ getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
+ if (isInUSRSet(TargetDecl)) {
+ RenameInfo Info = {NestedLoc.getBeginLoc(),
+ EndLocationForType(NestedLoc.getTypeLoc()),
+ TargetDecl,
+ getClosestAncestorDecl(NestedLoc),
+ NestedLoc.getNestedNameSpecifier()->getPrefix(),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+ }
+ return true;
+ }
+
+ bool VisitTypeLoc(TypeLoc Loc) {
+ auto Parents = Context.getParents(Loc);
+ TypeLoc ParentTypeLoc;
+ if (!Parents.empty()) {
+ // Handle cases of nested name specificier locations.
+ //
+ // The VisitNestedNameSpecifierLoc interface is not impelmented in
+ // RecursiveASTVisitor, we have to handle it explicitly.
+ if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
+ VisitNestedNameSpecifierLocations(*NSL);
+ return true;
+ }
+
+ if (const auto *TL = Parents[0].get<TypeLoc>())
+ ParentTypeLoc = *TL;
+ }
+
+ // Handle the outermost TypeLoc which is directly linked to the interesting
+ // declaration and don't handle nested name specifier locations.
+ if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
+ if (isInUSRSet(TargetDecl)) {
+ // Only handle the outermost typeLoc.
+ //
+ // For a type like "a::Foo", there will be two typeLocs for it.
+ // One ElaboratedType, the other is RecordType:
+ //
+ // ElaboratedType 0x33b9390 'a::Foo' sugar
+ // `-RecordType 0x338fef0 'class a::Foo'
+ // `-CXXRecord 0x338fe58 'Foo'
+ //
+ // Skip if this is an inner typeLoc.
+ if (!ParentTypeLoc.isNull() &&
+ isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
+ return true;
+
+ auto StartLoc = StartLocationForType(Loc);
+ auto EndLoc = EndLocationForType(Loc);
+ if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {StartLoc,
+ EndLoc,
+ TargetDecl,
+ getClosestAncestorDecl(Loc),
+ GetNestedNameForType(Loc),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+ return true;
+ }
+ }
+
+ // Handle specific template class specialiation cases.
+ if (const auto *TemplateSpecType =
+ dyn_cast<TemplateSpecializationType>(Loc.getType())) {
+ TypeLoc TargetLoc = Loc;
+ if (!ParentTypeLoc.isNull()) {
+ if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+ TargetLoc = ParentTypeLoc;
+ }
+
+ if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
+ TypeLoc TargetLoc = Loc;
+ // FIXME: Find a better way to handle this case.
+ // For the qualified template class specification type like
+ // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc
+ // (ElaboratedType) of the TemplateSpecializationType in order to
+ // catch the prefix qualifiers "ns::".
+ if (!ParentTypeLoc.isNull() &&
+ llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+ TargetLoc = ParentTypeLoc;
+
+ auto StartLoc = StartLocationForType(TargetLoc);
+ auto EndLoc = EndLocationForType(TargetLoc);
+ if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
+ RenameInfo Info = {
+ StartLoc,
+ EndLoc,
+ TemplateSpecType->getTemplateName().getAsTemplateDecl(),
+ getClosestAncestorDecl(
+ ast_type_traits::DynTypedNode::create(TargetLoc)),
+ GetNestedNameForType(TargetLoc),
+ /*IgnorePrefixQualifers=*/false};
+ RenameInfos.push_back(Info);
+ }
+ }
+ }
+ return true;
+ }
+
+ // Returns a list of RenameInfo.
+ const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
+
+ // Returns a list of using declarations which are needed to update.
+ const std::vector<const UsingDecl *> &getUsingDecls() const {
+ return UsingDecls;
+ }
+
+private:
+ // Get the supported declaration from a given typeLoc. If the declaration type
+ // is not supported, returns nullptr.
+ const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
+ if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>())
+ return TT->getDecl();
+ if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
+ return RD;
+ if (const auto *ED =
+ llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl()))
+ return ED;
+ return nullptr;
+ }
+
+ // Get the closest ancester which is a declaration of a given AST node.
+ template <typename ASTNodeType>
+ const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
+ auto Parents = Context.getParents(Node);
+ // FIXME: figure out how to handle it when there are multiple parents.
+ if (Parents.size() != 1)
+ return nullptr;
+ if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
+ Parents[0].getNodeKind()))
+ return Parents[0].template get<Decl>();
+ return getClosestAncestorDecl(Parents[0]);
+ }
+
+ // Get the parent typeLoc of a given typeLoc. If there is no such parent,
+ // return nullptr.
+ const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
+ auto Parents = Context.getParents(Loc);
+ // FIXME: figure out how to handle it when there are multiple parents.
+ if (Parents.size() != 1)
+ return nullptr;
+ return Parents[0].get<TypeLoc>();
+ }
+
+ // Check whether the USR of a given Decl is in the USRSet.
+ bool isInUSRSet(const Decl *Decl) const {
+ auto USR = getUSRForDecl(Decl);
+ if (USR.empty())
+ return false;
+ return llvm::is_contained(USRSet, USR);
+ }
+
+ const std::set<std::string> USRSet;
+ ASTContext &Context;
+ std::vector<RenameInfo> RenameInfos;
+ // Record all interested using declarations which contains the using-shadow
+ // declarations of the symbol declarations being renamed.
+ std::vector<const UsingDecl *> UsingDecls;
+};
+
+} // namespace
+
+SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs,
+ StringRef PrevName, Decl *Decl) {
+ USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
+ Visitor.TraverseDecl(Decl);
+ return Visitor.takeOccurrences();
+}
+
+std::vector<tooling::AtomicChange>
+createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
+ llvm::StringRef NewName, Decl *TranslationUnitDecl) {
+ RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
+ Finder.TraverseDecl(TranslationUnitDecl);
+
+ const SourceManager &SM =
+ TranslationUnitDecl->getASTContext().getSourceManager();
+
+ std::vector<tooling::AtomicChange> AtomicChanges;
+ auto Replace = [&](SourceLocation Start, SourceLocation End,
+ llvm::StringRef Text) {
+ tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
+ llvm::Error Err = ReplaceChange.replace(
+ SM, CharSourceRange::getTokenRange(Start, End), Text);
+ if (Err) {
+ llvm::errs() << "Faile to add replacement to AtomicChange: "
+ << llvm::toString(std::move(Err)) << "\n";
+ return;
+ }
+ AtomicChanges.push_back(std::move(ReplaceChange));
+ };
+
+ for (const auto &RenameInfo : Finder.getRenameInfos()) {
+ std::string ReplacedName = NewName.str();
+ if (RenameInfo.IgnorePrefixQualifers) {
+ // Get the name without prefix qualifiers from NewName.
+ size_t LastColonPos = NewName.find_last_of(':');
+ if (LastColonPos != std::string::npos)
+ ReplacedName = NewName.substr(LastColonPos + 1);
+ } else {
+ if (RenameInfo.FromDecl && RenameInfo.Context) {
+ if (!llvm::isa<clang::TranslationUnitDecl>(
+ RenameInfo.Context->getDeclContext())) {
+ ReplacedName = tooling::replaceNestedName(
+ RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
+ RenameInfo.FromDecl,
+ NewName.startswith("::") ? NewName.str()
+ : ("::" + NewName).str());
+ } else {
+ // This fixes the case where type `T` is a parameter inside a function
+ // type (e.g. `std::function<void(T)>`) and the DeclContext of `T`
+ // becomes the translation unit. As a workaround, we simply use
+ // fully-qualified name here for all references whose `DeclContext` is
+ // the translation unit and ignore the possible existence of
+ // using-decls (in the global scope) that can shorten the replaced
+ // name.
+ llvm::StringRef ActualName = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ SourceRange(RenameInfo.Begin, RenameInfo.End)),
+ SM, TranslationUnitDecl->getASTContext().getLangOpts());
+ // Add the leading "::" back if the name written in the code contains
+ // it.
+ if (ActualName.startswith("::") && !NewName.startswith("::")) {
+ ReplacedName = "::" + NewName.str();
+ }
+ }
+ }
+ // If the NewName contains leading "::", add it back.
+ if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
+ ReplacedName = NewName.str();
+ }
+ Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
+ }
+
+ // Hanlde using declarations explicitly as "using a::Foo" don't trigger
+ // typeLoc for "a::Foo".
+ for (const auto *Using : Finder.getUsingDecls())
+ Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str());
+
+ return AtomicChanges;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/RefactoringCallbacks.cpp b/lib/Tooling/RefactoringCallbacks.cpp
index e900c23e4f..9fd333ca55 100644
--- a/lib/Tooling/RefactoringCallbacks.cpp
+++ b/lib/Tooling/RefactoringCallbacks.cpp
@@ -9,8 +9,13 @@
//
//
//===----------------------------------------------------------------------===//
-#include "clang/Lex/Lexer.h"
#include "clang/Tooling/RefactoringCallbacks.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+
+using llvm::StringError;
+using llvm::make_error;
namespace clang {
namespace tooling {
@@ -20,18 +25,62 @@ tooling::Replacements &RefactoringCallback::getReplacements() {
return Replace;
}
-static Replacement replaceStmtWithText(SourceManager &Sources,
- const Stmt &From,
+ASTMatchRefactorer::ASTMatchRefactorer(
+ std::map<std::string, Replacements> &FileToReplaces)
+ : FileToReplaces(FileToReplaces) {}
+
+void ASTMatchRefactorer::addDynamicMatcher(
+ const ast_matchers::internal::DynTypedMatcher &Matcher,
+ RefactoringCallback *Callback) {
+ MatchFinder.addDynamicMatcher(Matcher, Callback);
+ Callbacks.push_back(Callback);
+}
+
+class RefactoringASTConsumer : public ASTConsumer {
+public:
+ explicit RefactoringASTConsumer(ASTMatchRefactorer &Refactoring)
+ : Refactoring(Refactoring) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ // The ASTMatchRefactorer is re-used between translation units.
+ // Clear the matchers so that each Replacement is only emitted once.
+ for (const auto &Callback : Refactoring.Callbacks) {
+ Callback->getReplacements().clear();
+ }
+ Refactoring.MatchFinder.matchAST(Context);
+ for (const auto &Callback : Refactoring.Callbacks) {
+ for (const auto &Replacement : Callback->getReplacements()) {
+ llvm::Error Err =
+ Refactoring.FileToReplaces[Replacement.getFilePath()].add(
+ Replacement);
+ if (Err) {
+ llvm::errs() << "Skipping replacement " << Replacement.toString()
+ << " due to this error:\n"
+ << toString(std::move(Err)) << "\n";
+ }
+ }
+ }
+ }
+
+private:
+ ASTMatchRefactorer &Refactoring;
+};
+
+std::unique_ptr<ASTConsumer> ASTMatchRefactorer::newASTConsumer() {
+ return llvm::make_unique<RefactoringASTConsumer>(*this);
+}
+
+static Replacement replaceStmtWithText(SourceManager &Sources, const Stmt &From,
StringRef Text) {
- return tooling::Replacement(Sources, CharSourceRange::getTokenRange(
- From.getSourceRange()), Text);
+ return tooling::Replacement(
+ Sources, CharSourceRange::getTokenRange(From.getSourceRange()), Text);
}
-static Replacement replaceStmtWithStmt(SourceManager &Sources,
- const Stmt &From,
+static Replacement replaceStmtWithStmt(SourceManager &Sources, const Stmt &From,
const Stmt &To) {
- return replaceStmtWithText(Sources, From, Lexer::getSourceText(
- CharSourceRange::getTokenRange(To.getSourceRange()),
- Sources, LangOptions()));
+ return replaceStmtWithText(
+ Sources, From,
+ Lexer::getSourceText(CharSourceRange::getTokenRange(To.getSourceRange()),
+ Sources, LangOptions()));
}
ReplaceStmtWithText::ReplaceStmtWithText(StringRef FromId, StringRef ToText)
@@ -103,5 +152,90 @@ void ReplaceIfStmtWithItsBody::run(
}
}
+ReplaceNodeWithTemplate::ReplaceNodeWithTemplate(
+ llvm::StringRef FromId, std::vector<TemplateElement> Template)
+ : FromId(FromId), Template(std::move(Template)) {}
+
+llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>>
+ReplaceNodeWithTemplate::create(StringRef FromId, StringRef ToTemplate) {
+ std::vector<TemplateElement> ParsedTemplate;
+ for (size_t Index = 0; Index < ToTemplate.size();) {
+ if (ToTemplate[Index] == '$') {
+ if (ToTemplate.substr(Index, 2) == "$$") {
+ Index += 2;
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Literal, "$"});
+ } else if (ToTemplate.substr(Index, 2) == "${") {
+ size_t EndOfIdentifier = ToTemplate.find("}", Index);
+ if (EndOfIdentifier == std::string::npos) {
+ return make_error<StringError>(
+ "Unterminated ${...} in replacement template near " +
+ ToTemplate.substr(Index),
+ llvm::inconvertibleErrorCode());
+ }
+ std::string SourceNodeName =
+ ToTemplate.substr(Index + 2, EndOfIdentifier - Index - 2);
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Identifier, SourceNodeName});
+ Index = EndOfIdentifier + 1;
+ } else {
+ return make_error<StringError>(
+ "Invalid $ in replacement template near " +
+ ToTemplate.substr(Index),
+ llvm::inconvertibleErrorCode());
+ }
+ } else {
+ size_t NextIndex = ToTemplate.find('$', Index + 1);
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Literal,
+ ToTemplate.substr(Index, NextIndex - Index)});
+ Index = NextIndex;
+ }
+ }
+ return std::unique_ptr<ReplaceNodeWithTemplate>(
+ new ReplaceNodeWithTemplate(FromId, std::move(ParsedTemplate)));
+}
+
+void ReplaceNodeWithTemplate::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ const auto &NodeMap = Result.Nodes.getMap();
+
+ std::string ToText;
+ for (const auto &Element : Template) {
+ switch (Element.Type) {
+ case TemplateElement::Literal:
+ ToText += Element.Value;
+ break;
+ case TemplateElement::Identifier: {
+ auto NodeIter = NodeMap.find(Element.Value);
+ if (NodeIter == NodeMap.end()) {
+ llvm::errs() << "Node " << Element.Value
+ << " used in replacement template not bound in Matcher \n";
+ llvm::report_fatal_error("Unbound node in replacement template.");
+ }
+ CharSourceRange Source =
+ CharSourceRange::getTokenRange(NodeIter->second.getSourceRange());
+ ToText += Lexer::getSourceText(Source, *Result.SourceManager,
+ Result.Context->getLangOpts());
+ break;
+ }
+ }
+ }
+ if (NodeMap.count(FromId) == 0) {
+ llvm::errs() << "Node to be replaced " << FromId
+ << " not bound in query.\n";
+ llvm::report_fatal_error("FromId node not bound in MatchResult");
+ }
+ auto Replacement =
+ tooling::Replacement(*Result.SourceManager, &NodeMap.at(FromId), ToText,
+ Result.Context->getLangOpts());
+ llvm::Error Err = Replace.add(Replacement);
+ if (Err) {
+ llvm::errs() << "Query and replace failed in " << Replacement.getFilePath()
+ << "! " << llvm::toString(std::move(Err)) << "\n";
+ llvm::report_fatal_error("Replacement failed");
+ }
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/lib/Tooling/StandaloneExecution.cpp b/lib/Tooling/StandaloneExecution.cpp
new file mode 100644
index 0000000000..e52e4a611f
--- /dev/null
+++ b/lib/Tooling/StandaloneExecution.cpp
@@ -0,0 +1,91 @@
+//===- lib/Tooling/Execution.cpp - Standalone clang action execution. -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/ToolExecutorPluginRegistry.h"
+
+namespace clang {
+namespace tooling {
+
+static llvm::Error make_string_error(const llvm::Twine &Message) {
+ return llvm::make_error<llvm::StringError>(Message,
+ llvm::inconvertibleErrorCode());
+}
+
+const char *StandaloneToolExecutor::ExecutorName = "StandaloneToolExecutor";
+
+static ArgumentsAdjuster getDefaultArgumentsAdjusters() {
+ return combineAdjusters(
+ getClangStripOutputAdjuster(),
+ combineAdjusters(getClangSyntaxOnlyAdjuster(),
+ getClangStripDependencyFileAdjuster()));
+}
+
+StandaloneToolExecutor::StandaloneToolExecutor(
+ const CompilationDatabase &Compilations,
+ llvm::ArrayRef<std::string> SourcePaths,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : Tool(Compilations, SourcePaths), Context(&Results),
+ ArgsAdjuster(getDefaultArgumentsAdjusters()) {
+ // Use self-defined default argument adjusters instead of the default
+ // adjusters that come with the old `ClangTool`.
+ Tool.clearArgumentsAdjusters();
+}
+
+StandaloneToolExecutor::StandaloneToolExecutor(
+ CommonOptionsParser Options,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ : OptionsParser(std::move(Options)),
+ Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList(),
+ PCHContainerOps),
+ Context(&Results), ArgsAdjuster(getDefaultArgumentsAdjusters()) {
+ Tool.clearArgumentsAdjusters();
+}
+
+llvm::Error StandaloneToolExecutor::execute(
+ llvm::ArrayRef<
+ std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
+ Actions) {
+ if (Actions.empty())
+ return make_string_error("No action to execute.");
+
+ if (Actions.size() != 1)
+ return make_string_error(
+ "Only support executing exactly 1 action at this point.");
+
+ auto &Action = Actions.front();
+ Tool.appendArgumentsAdjuster(Action.second);
+ Tool.appendArgumentsAdjuster(ArgsAdjuster);
+ if (Tool.run(Action.first.get()))
+ return make_string_error("Failed to run action.");
+
+ return llvm::Error::success();
+}
+
+class StandaloneToolExecutorPlugin : public ToolExecutorPlugin {
+public:
+ llvm::Expected<std::unique_ptr<ToolExecutor>>
+ create(CommonOptionsParser &OptionsParser) override {
+ if (OptionsParser.getSourcePathList().empty())
+ return make_string_error(
+ "[StandaloneToolExecutorPlugin] No positional argument found.");
+ return llvm::make_unique<StandaloneToolExecutor>(std::move(OptionsParser));
+ }
+};
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the plugin.
+volatile int ToolExecutorPluginAnchorSource = 0;
+
+static ToolExecutorPluginRegistry::Add<StandaloneToolExecutorPlugin>
+ X("standalone", "Runs FrontendActions on a set of files provided "
+ "via positional arguments.");
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 9e1181281f..4fbfa4f004 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -29,6 +29,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
@@ -100,7 +101,6 @@ clang::CompilerInvocation *newInvocation(
*Diagnostics);
Invocation->getFrontendOpts().DisableFree = false;
Invocation->getCodeGenOpts().DisableFree = false;
- Invocation->getDependencyOutputOpts() = DependencyOutputOptions();
return Invocation;
}
@@ -140,9 +140,11 @@ bool runToolOnCodeWithArgs(
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
llvm::IntrusiveRefCntPtr<FileManager> Files(
new FileManager(FileSystemOptions(), OverlayFileSystem));
- ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef),
- ToolAction, Files.get(),
- std::move(PCHContainerOps));
+ ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster();
+ ToolInvocation Invocation(
+ getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
+ ToolAction, Files.get(),
+ std::move(PCHContainerOps));
SmallString<1024> CodeStorage;
InMemoryFileSystem->addFile(FileNameRef, 0,
@@ -189,11 +191,12 @@ void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
}
auto TargetMode =
clang::driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs);
- if (!AlreadyHasMode && !TargetMode.second.empty()) {
- CommandLine.insert(++CommandLine.begin(), TargetMode.second);
+ if (!AlreadyHasMode && TargetMode.DriverMode) {
+ CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
}
- if (!AlreadyHasTarget && !TargetMode.first.empty()) {
- CommandLine.insert(++CommandLine.begin(), {"-target", TargetMode.first});
+ if (!AlreadyHasTarget && TargetMode.TargetIsValid) {
+ CommandLine.insert(++CommandLine.begin(), {"-target",
+ TargetMode.TargetPrefix});
}
}
}
@@ -260,6 +263,8 @@ bool ToolInvocation::run() {
Driver->setCheckInputsExist(false);
const std::unique_ptr<clang::driver::Compilation> Compilation(
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
+ if (!Compilation)
+ return false;
const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
&Diagnostics, Compilation.get());
if (!CC1Args) {
@@ -333,6 +338,7 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations,
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
appendArgumentsAdjuster(getClangStripOutputAdjuster());
appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
+ appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
}
ClangTool::~ClangTool() {}
@@ -342,11 +348,7 @@ void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
}
void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
- if (ArgsAdjuster)
- ArgsAdjuster =
- combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
- else
- ArgsAdjuster = std::move(Adjuster);
+ ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
}
void ClangTool::clearArgumentsAdjusters() {
@@ -508,7 +510,8 @@ buildASTFromCode(const Twine &Code, const Twine &FileName,
std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
const Twine &Code, const std::vector<std::string> &Args,
const Twine &FileName, const Twine &ToolName,
- std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ ArgumentsAdjuster Adjuster) {
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
@@ -521,8 +524,10 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
llvm::IntrusiveRefCntPtr<FileManager> Files(
new FileManager(FileSystemOptions(), OverlayFileSystem));
- ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef),
- &Action, Files.get(), std::move(PCHContainerOps));
+
+ ToolInvocation Invocation(
+ getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
+ &Action, Files.get(), std::move(PCHContainerOps));
SmallString<1024> CodeStorage;
InMemoryFileSystem->addFile(FileNameRef, 0,
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index 27cb83afcc..2190f27492 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -77,6 +77,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
-DCOMPILER_RT_INCLUDE_TESTS=${LLVM_INCLUDE_TESTS}
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
-DLLVM_LIBDIR_SUFFIX=${LLVM_LIBDIR_SUFFIX}
+ -DLLVM_RUNTIME_OUTPUT_INTDIR=${LLVM_RUNTIME_OUTPUT_INTDIR}
-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}
-DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT}
${COMPILER_RT_PASSTHROUGH_VARIABLES}
@@ -108,7 +109,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
USES_TERMINAL)
# Add top-level targets that build specific compiler-rt runtimes.
- set(COMPILER_RT_RUNTIMES asan builtins dfsan lsan msan profile tsan ubsan)
+ set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan ubsan ubsan-minimal)
foreach(runtime ${COMPILER_RT_RUNTIMES})
get_ext_project_build_command(build_runtime_cmd ${runtime})
add_custom_target(${runtime}
@@ -124,8 +125,8 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
FileCheck count not llvm-nm llvm-objdump llvm-symbolizer)
# Add top-level targets for various compiler-rt test suites.
- set(COMPILER_RT_TEST_SUITES check-asan check-asan-dynamic check-dfsan
- check-lsan check-msan check-sanitizer check-tsan check-ubsan
+ set(COMPILER_RT_TEST_SUITES check-fuzzer check-asan check-asan-dynamic check-dfsan
+ check-lsan check-msan check-sanitizer check-tsan check-ubsan check-ubsan-minimal
check-profile check-cfi check-cfi-and-supported check-safestack)
foreach(test_suite ${COMPILER_RT_TEST_SUITES})
get_ext_project_build_command(run_test_suite ${test_suite})
diff --git a/test/ARCMT/remap-applying.c b/test/ARCMT/remap-applying.c
new file mode 100644
index 0000000000..dee2e391d5
--- /dev/null
+++ b/test/ARCMT/remap-applying.c
@@ -0,0 +1,4 @@
+a bc
+
+// RUN: echo "[{\"file\": \"%/s\", \"offset\": 1, \"remove\": 2, }]" > %t.remap
+// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
diff --git a/test/ARCMT/remap-applying.c.result b/test/ARCMT/remap-applying.c.result
new file mode 100644
index 0000000000..514e9c2649
--- /dev/null
+++ b/test/ARCMT/remap-applying.c.result
@@ -0,0 +1,4 @@
+ac
+
+// RUN: echo "[{\"file\": \"%/s\", \"offset\": 1, \"remove\": 2, }]" > %t.remap
+// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
diff --git a/test/ASTMerge/struct/Inputs/struct1.c b/test/ASTMerge/struct/Inputs/struct1.c
index af2af8abc4..0f3e8b9bc3 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 4b43df71d8..7fe17a576b 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 4f41cea26b..ed7750f6be 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/DeleteWithNonVirtualDtor.cpp b/test/Analysis/DeleteWithNonVirtualDtor.cpp
new file mode 100644
index 0000000000..a9b8a11f34
--- /dev/null
+++ b/test/Analysis/DeleteWithNonVirtualDtor.cpp
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.DeleteWithNonVirtualDtor -std=c++11 -verify -analyzer-output=text %s
+
+struct Virtual {
+ virtual ~Virtual() {}
+};
+
+struct VDerived : public Virtual {};
+
+struct NonVirtual {
+ ~NonVirtual() {}
+};
+
+struct NVDerived : public NonVirtual {};
+struct NVDoubleDerived : public NVDerived {};
+
+struct Base {
+ virtual void destroy() = 0;
+};
+
+class PrivateDtor final : public Base {
+public:
+ void destroy() { delete this; }
+private:
+ ~PrivateDtor() {}
+};
+
+struct ImplicitNV {
+ virtual void f();
+};
+
+struct ImplicitNVDerived : public ImplicitNV {};
+
+NVDerived *get();
+
+NonVirtual *create() {
+ NonVirtual *x = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ return x;
+}
+
+void sink(NonVirtual *x) {
+ delete x; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void sinkCast(NonVirtual *y) {
+ delete reinterpret_cast<NVDerived*>(y);
+}
+
+void sinkParamCast(NVDerived *z) {
+ delete z;
+}
+
+void singleDerived() {
+ NonVirtual *sd;
+ sd = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete sd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void singleDerivedArr() {
+ NonVirtual *sda = new NVDerived[5]; // expected-note{{Conversion from derived to base happened here}}
+ delete[] sda; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleDerived() {
+ NonVirtual *dd = new NVDoubleDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete (dd); // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void assignThroughFunction() {
+ NonVirtual *atf = get(); // expected-note{{Conversion from derived to base happened here}}
+ delete atf; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void assignThroughFunction2() {
+ NonVirtual *atf2;
+ atf2 = get(); // expected-note{{Conversion from derived to base happened here}}
+ delete atf2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void createThroughFunction() {
+ NonVirtual *ctf = create(); // expected-note{{Calling 'create'}}
+ // expected-note@-1{{Returning from 'create'}}
+ delete ctf; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void deleteThroughFunction() {
+ NonVirtual *dtf = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ sink(dtf); // expected-note{{Calling 'sink'}}
+}
+
+void singleCastCStyle() {
+ NVDerived *sccs = new NVDerived();
+ NonVirtual *sccs2 = (NonVirtual*)sccs; // expected-note{{Conversion from derived to base happened here}}
+ delete sccs2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleCastCStyle() {
+ NonVirtual *dccs = new NVDerived();
+ NVDerived *dccs2 = (NVDerived*)dccs;
+ dccs = (NonVirtual*)dccs2; // expected-note{{Conversion from derived to base happened here}}
+ delete dccs; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void singleCast() {
+ NVDerived *sc = new NVDerived();
+ NonVirtual *sc2 = reinterpret_cast<NonVirtual*>(sc); // expected-note{{Conversion from derived to base happened here}}
+ delete sc2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleCast() {
+ NonVirtual *dd = new NVDerived();
+ NVDerived *dd2 = reinterpret_cast<NVDerived*>(dd);
+ dd = reinterpret_cast<NonVirtual*>(dd2); // expected-note {{Conversion from derived to base happened here}}
+ delete dd; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void implicitNV() {
+ ImplicitNV *invd = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete invd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleDecl() {
+ ImplicitNV *dd1, *dd2;
+ dd1 = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete dd1; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void virtualBase() {
+ Virtual *vb = new VDerived();
+ delete vb; // no-warning
+}
+
+void notDerived() {
+ NonVirtual *nd = new NonVirtual();
+ delete nd; // no-warning
+}
+
+void notDerivedArr() {
+ NonVirtual *nda = new NonVirtual[3];
+ delete[] nda; // no-warning
+}
+
+void cast() {
+ NonVirtual *c = new NVDerived();
+ delete reinterpret_cast<NVDerived*>(c); // no-warning
+}
+
+void deleteThroughFunction2() {
+ NonVirtual *dtf2 = new NVDerived();
+ sinkCast(dtf2); // no-warning
+}
+
+void deleteThroughFunction3() {
+ NVDerived *dtf3;
+ dtf3 = new NVDerived();
+ sinkParamCast(dtf3); // no-warning
+}
+
+void stackVar() {
+ NonVirtual sv2;
+ delete &sv2; // no-warning
+}
+
+// Deleting a polymorphic object with a non-virtual dtor
+// is not a problem if it is referenced by its precise type.
+
+void preciseType() {
+ NVDerived *pt = new NVDerived();
+ delete pt; // no-warning
+}
+
+void privateDtor() {
+ Base *pd = new PrivateDtor();
+ pd->destroy(); // no-warning
+}
diff --git a/test/Analysis/DynamicTypePropagation.m b/test/Analysis/DynamicTypePropagation.m
index 25a0ae35fd..63904b8425 100644
--- a/test/Analysis/DynamicTypePropagation.m
+++ b/test/Analysis/DynamicTypePropagation.m
@@ -4,6 +4,9 @@
# error Compiler does not support Objective-C generics?
#endif
+typedef __typeof(sizeof(int)) size_t;
+void *memset(void *, int, size_t);
+
#define nil 0
typedef unsigned long NSUInteger;
typedef int BOOL;
@@ -21,6 +24,7 @@ __attribute__((objc_root_class))
@end
@interface NSArray<ObjectType> : NSObject
+- (void) init;
- (BOOL)contains:(ObjectType)obj;
- (ObjectType)getObjAtIndex:(NSUInteger)idx;
- (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;
@@ -55,3 +59,11 @@ void testArgument(NSArray<MyType *> *arr, id element) {
// MyType!
[element myFunction:0 myParam:0 ];
}
+
+// Do not try this at home! The analyzer shouldn't crash though when it
+// tries to figure out the dynamic type behind the alloca's return value.
+void testAlloca(size_t NSArrayClassSizeWeKnowSomehow) {
+ NSArray *arr = __builtin_alloca(NSArrayClassSizeWeKnowSomehow);
+ memset(arr, 0, NSArrayClassSizeWeKnowSomehow);
+ [arr init]; // no-crash
+}
diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h
index 005e7f57af..809b768d71 100644
--- a/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -8,18 +8,61 @@
typedef unsigned char uint8_t;
typedef __typeof__(sizeof(int)) size_t;
+typedef __typeof__((char*)0-(char*)0) ptrdiff_t;
void *memmove(void *s1, const void *s2, size_t n);
-template <typename T, typename Ptr, typename Ref> struct __iterator {
- typedef __iterator<T, T *, T &> iterator;
- typedef __iterator<T, const T *, const T &> const_iterator;
+namespace std {
+ struct input_iterator_tag { };
+ struct output_iterator_tag { };
+ struct forward_iterator_tag : public input_iterator_tag { };
+ struct bidirectional_iterator_tag : public forward_iterator_tag { };
+ struct random_access_iterator_tag : public bidirectional_iterator_tag { };
- __iterator(const Ptr p) : ptr(p) {}
+ template <typename Iterator> struct iterator_traits {
+ typedef typename Iterator::difference_type difference_type;
+ typedef typename Iterator::value_type value_type;
+ typedef typename Iterator::pointer pointer;
+ typedef typename Iterator::reference reference;
+ typedef typename Iterator::iterator_category iterator_category;
+ };
+}
+
+template <typename T, typename Ptr, typename Ref> struct __vector_iterator {
+ typedef __vector_iterator<T, T *, T &> iterator;
+ typedef __vector_iterator<T, const T *, const T &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::random_access_iterator_tag iterator_category;
+
+ __vector_iterator(const Ptr p = 0) : ptr(p) {}
+ __vector_iterator(const iterator &rhs): ptr(rhs.base()) {}
+ __vector_iterator<T, Ptr, Ref> operator++() { ++ ptr; return *this; }
+ __vector_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ ++ ptr;
+ return tmp;
+ }
+ __vector_iterator<T, Ptr, Ref> operator--() { -- ptr; return *this; }
+ __vector_iterator<T, Ptr, Ref> operator--(int) {
+ auto tmp = *this; -- ptr;
+ return tmp;
+ }
+ __vector_iterator<T, Ptr, Ref> operator+(difference_type n) {
+ return ptr + n;
+ }
+ __vector_iterator<T, Ptr, Ref> operator-(difference_type n) {
+ return ptr - n;
+ }
+ __vector_iterator<T, Ptr, Ref> operator+=(difference_type n) {
+ return ptr += n;
+ }
+ __vector_iterator<T, Ptr, Ref> operator-=(difference_type n) {
+ return ptr -= n;
+ }
- __iterator<T, Ptr, Ref> operator++() { return *this; }
- __iterator<T, Ptr, Ref> operator++(int) { return *this; }
- __iterator<T, Ptr, Ref> operator--() { return *this; }
- __iterator<T, Ptr, Ref> operator--(int) { return *this; }
Ref operator*() const { return *ptr; }
Ptr operator->() const { return *ptr; }
@@ -29,10 +72,136 @@ template <typename T, typename Ptr, typename Ref> struct __iterator {
bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; }
bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; }
+ const Ptr& base() const { return ptr; }
+
private:
Ptr ptr;
};
+template <typename T, typename Ptr, typename Ref> struct __deque_iterator {
+ typedef __deque_iterator<T, T *, T &> iterator;
+ typedef __deque_iterator<T, const T *, const T &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::random_access_iterator_tag iterator_category;
+
+ __deque_iterator(const Ptr p = 0) : ptr(p) {}
+ __deque_iterator(const iterator &rhs): ptr(rhs.base()) {}
+ __deque_iterator<T, Ptr, Ref> operator++() { ++ ptr; return *this; }
+ __deque_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ ++ ptr;
+ return tmp;
+ }
+ __deque_iterator<T, Ptr, Ref> operator--() { -- ptr; return *this; }
+ __deque_iterator<T, Ptr, Ref> operator--(int) {
+ auto tmp = *this; -- ptr;
+ return tmp;
+ }
+ __deque_iterator<T, Ptr, Ref> operator+(difference_type n) {
+ return ptr + n;
+ }
+ __deque_iterator<T, Ptr, Ref> operator-(difference_type n) {
+ return ptr - n;
+ }
+ __deque_iterator<T, Ptr, Ref> operator+=(difference_type n) {
+ return ptr += n;
+ }
+ __deque_iterator<T, Ptr, Ref> operator-=(difference_type n) {
+ return ptr -= n;
+ }
+
+ Ref operator*() const { return *ptr; }
+ Ptr operator->() const { return *ptr; }
+
+ bool operator==(const iterator &rhs) const { return ptr == rhs.ptr; }
+ bool operator==(const const_iterator &rhs) const { return ptr == rhs.ptr; }
+
+ bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; }
+ bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; }
+
+ const Ptr& base() const { return ptr; }
+
+private:
+ Ptr ptr;
+};
+
+template <typename T, typename Ptr, typename Ref> struct __list_iterator {
+ typedef __list_iterator<T, __typeof__(T::data) *, __typeof__(T::data) &> iterator;
+ typedef __list_iterator<T, const __typeof__(T::data) *, const __typeof__(T::data) &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+ __list_iterator(T* it = 0) : item(it) {}
+ __list_iterator(const iterator &rhs): item(rhs.base()) {}
+ __list_iterator<T, Ptr, Ref> operator++() { item = item->next; return *this; }
+ __list_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ item = item->next;
+ return tmp;
+ }
+ __list_iterator<T, Ptr, Ref> operator--() { item = item->prev; return *this; }
+ __list_iterator<T, Ptr, Ref> operator--(int) {
+ auto tmp = *this;
+ item = item->prev;
+ return tmp;
+ }
+
+ Ref operator*() const { return item->data; }
+ Ptr operator->() const { return item->data; }
+
+ bool operator==(const iterator &rhs) const { return item == rhs->item; }
+ bool operator==(const const_iterator &rhs) const { return item == rhs->item; }
+
+ bool operator!=(const iterator &rhs) const { return item != rhs->item; }
+ bool operator!=(const const_iterator &rhs) const { return item != rhs->item; }
+
+ const T* &base() const { return item; }
+
+private:
+ T* item;
+};
+
+template <typename T, typename Ptr, typename Ref> struct __fwdl_iterator {
+ typedef __fwdl_iterator<T, __typeof__(T::data) *, __typeof__(T::data) &> iterator;
+ typedef __fwdl_iterator<T, const __typeof__(T::data) *, const __typeof__(T::data) &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::forward_iterator_tag iterator_category;
+
+ __fwdl_iterator(T* it = 0) : item(it) {}
+ __fwdl_iterator(const iterator &rhs): item(rhs.base()) {}
+ __fwdl_iterator<T, Ptr, Ref> operator++() { item = item->next; return *this; }
+ __fwdl_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ item = item->next;
+ return tmp;
+ }
+ Ref operator*() const { return item->data; }
+ Ptr operator->() const { return item->data; }
+
+ bool operator==(const iterator &rhs) const { return item == rhs->item; }
+ bool operator==(const const_iterator &rhs) const { return item == rhs->item; }
+
+ bool operator!=(const iterator &rhs) const { return item != rhs->item; }
+ bool operator!=(const const_iterator &rhs) const { return item != rhs->item; }
+
+ const T* &base() const { return item; }
+
+private:
+ T* item;
+};
+
namespace std {
template <class T1, class T2>
struct pair {
@@ -43,30 +212,124 @@ namespace std {
pair(const T1 &a, const T2 &b) : first(a), second(b) {}
template<class U1, class U2>
- pair(const pair<U1, U2> &other) : first(other.first), second(other.second) {}
+ pair(const pair<U1, U2> &other) : first(other.first),
+ second(other.second) {}
};
typedef __typeof__(sizeof(int)) size_t;
+
+ template <class T> class initializer_list;
+ template< class T > struct remove_reference {typedef T type;};
+ template< class T > struct remove_reference<T&> {typedef T type;};
+ template< class T > struct remove_reference<T&&> {typedef T type;};
+
+ template<class T>
+ typename remove_reference<T>::type&& move(T&& a) {
+ typedef typename remove_reference<T>::type&& RvalRef;
+ return static_cast<RvalRef>(a);
+ }
+
template<typename T>
class vector {
- typedef __iterator<T, T *, T &> iterator;
- typedef __iterator<T, const T *, const T &> const_iterator;
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __vector_iterator<T, T *, T &> iterator;
+ typedef __vector_iterator<T, const T *, const T &> const_iterator;
T *_start;
T *_finish;
T *_end_of_storage;
public:
vector() : _start(0), _finish(0), _end_of_storage(0) {}
+ template <typename InputIterator>
+ vector(InputIterator first, InputIterator last);
+ vector(const vector &other);
+ vector(vector &&other);
~vector();
size_t size() const {
return size_t(_finish - _start);
}
+
+ T &operator[](size_t n) {
+ return _start[n];
+ }
+
+ const T &operator[](size_t n) const {
+ return _start[n];
+ }
+
+ iterator begin() { return iterator(_start); }
+ const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
+ iterator end() { return iterator(_finish); }
+ const_iterator end() const { return const_iterator(_finish); }
+ const_iterator cend() const { return const_iterator(_finish); }
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ T& back() { return *(end() - 1); }
+ const T& back() const { return *(end() - 1); }
+ };
+
+ template<typename T>
+ class list {
+ struct __item {
+ T data;
+ __item *prev, *next;
+ } *_start, *_finish;
+ public:
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __list_iterator<__item, T *, T &> iterator;
+ typedef __list_iterator<__item, const T *, const T &> const_iterator;
+
+ list() : _start(0), _finish(0) {}
+ template <typename InputIterator>
+ list(InputIterator first, InputIterator last);
+ list(const list &other);
+ list(list &&other);
+ ~list();
- void push_back();
- T pop_back();
+ list& operator=(const list &other);
+ list& operator=(list &&other);
+ list& operator=(std::initializer_list<T> ilist);
+
+ iterator begin() { return iterator(_start); }
+ const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
+ iterator end() { return iterator(_finish); }
+ const_iterator end() const { return const_iterator(_finish); }
+ const_iterator cend() const { return const_iterator(_finish); }
+
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ T& back() { return *--end(); }
+ const T& back() const { return *--end(); }
+ };
+ template<typename T>
+ class deque {
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __deque_iterator<T, T *, T &> iterator;
+ typedef __deque_iterator<T, const T *, const T &> const_iterator;
+
+ T *_start;
+ T *_finish;
+ T *_end_of_storage;
+ public:
+ deque() : _start(0), _finish(0), _end_of_storage(0) {}
+ template <typename InputIterator>
+ deque(InputIterator first, InputIterator last);
+ deque(const deque &other);
+ deque(deque &&other);
+ ~deque();
+
+ size_t size() const {
+ return size_t(_finish - _start);
+ }
+
T &operator[](size_t n) {
return _start[n];
}
@@ -77,10 +340,46 @@ namespace std {
iterator begin() { return iterator(_start); }
const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
iterator end() { return iterator(_finish); }
const_iterator end() const { return const_iterator(_finish); }
+ const_iterator cend() const { return const_iterator(_finish); }
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ T& back() { return *(end() - 1); }
+ const T& back() const { return *(end() - 1); }
};
+ template<typename T>
+ class forward_list {
+ struct __item {
+ T data;
+ __item *next;
+ } *_start;
+ public:
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __fwdl_iterator<__item, T *, T &> iterator;
+ typedef __fwdl_iterator<__item, const T *, const T &> const_iterator;
+
+ forward_list() : _start(0) {}
+ template <typename InputIterator>
+ forward_list(InputIterator first, InputIterator last);
+ forward_list(const forward_list &other);
+ forward_list(forward_list &&other);
+ ~forward_list();
+
+ iterator begin() { return iterator(_start); }
+ const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
+ iterator end() { return iterator(); }
+ const_iterator end() const { return const_iterator(); }
+ const_iterator cend() const { return const_iterator(); }
+
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ };
+
class exception {
public:
exception() throw();
@@ -247,41 +546,41 @@ namespace std {
OutputIter copy_backward(InputIter II, InputIter IE, OutputIter OI) {
return __copy_backward(II, IE, OI);
}
+}
+
+template <class BidirectionalIterator, class Distance>
+void __advance (BidirectionalIterator& it, Distance n,
+ std::bidirectional_iterator_tag) {
+ if (n >= 0) while(n-- > 0) ++it; else while (n++<0) --it;
+}
+
+template <class RandomAccessIterator, class Distance>
+void __advance (RandomAccessIterator& it, Distance n,
+ std::random_access_iterator_tag) {
+ it += n;
+}
+
+namespace std {
+ template <class InputIterator, class Distance>
+ void advance (InputIterator& it, Distance n) {
+ __advance(it, n, typename InputIterator::iterator_category());
+ }
+
+ template <class BidirectionalIterator>
+ BidirectionalIterator
+ prev (BidirectionalIterator it,
+ typename iterator_traits<BidirectionalIterator>::difference_type n =
+ 1) {
+ advance(it, -n);
+ return it;
+ }
template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T &val);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 find_end(ForwardIterator1 first1, ForwardIterator1 last1,
- ForwardIterator2 first2, ForwardIterator2 last2);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 find_first_of(ForwardIterator1 first1,
- ForwardIterator1 last1,
- ForwardIterator2 first2,
- ForwardIterator2 last2);
- template <class InputIterator, class UnaryPredicate>
- InputIterator find_if(InputIterator first, InputIterator last,
- UnaryPredicate pred);
- template <class InputIterator, class UnaryPredicate>
- InputIterator find_if_not(InputIterator first, InputIterator last,
- UnaryPredicate pred);
- template <class InputIterator, class T>
- InputIterator lower_bound(InputIterator first, InputIterator last,
- const T &val);
- template <class InputIterator, class T>
- InputIterator upper_bound(InputIterator first, InputIterator last,
- const T &val);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 search(ForwardIterator1 first1, ForwardIterator1 last1,
- ForwardIterator2 first2, ForwardIterator2 last2);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 search_n(ForwardIterator1 first1, ForwardIterator1 last1,
- ForwardIterator2 first2, ForwardIterator2 last2);
- struct input_iterator_tag { };
- struct output_iterator_tag { };
- struct forward_iterator_tag : public input_iterator_tag { };
- struct bidirectional_iterator_tag : public forward_iterator_tag { };
- struct random_access_iterator_tag : public bidirectional_iterator_tag { };
+ template <class InputIterator, class OutputIterator>
+ OutputIterator copy(InputIterator first, InputIterator last,
+ OutputIterator result);
}
diff --git a/test/Analysis/MismatchedDeallocator-path-notes.cpp b/test/Analysis/MismatchedDeallocator-path-notes.cpp
index 118f23bca1..1354386fc8 100644
--- a/test/Analysis/MismatchedDeallocator-path-notes.cpp
+++ b/test/Analysis/MismatchedDeallocator-path-notes.cpp
@@ -287,7 +287,7 @@ void test() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/MisusedMovedObject.cpp b/test/Analysis/MisusedMovedObject.cpp
new file mode 100644
index 0000000000..132a65de10
--- /dev/null
+++ b/test/Analysis/MisusedMovedObject.cpp
@@ -0,0 +1,675 @@
+// 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;
+ B& operator=(const B &q) = 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=(const A &other) {
+ i = other.i;
+ d = other.d;
+ b = other.b;
+ return;
+ }
+ 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 = 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 a;
+ A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ b = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+ }
+ {
+ A a;
+ A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ b = std::move(a); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving 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'}}
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ A c(a); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ A c(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving 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 {{Moving a 'moved-from' object 'a'}} expected-note {{Moving 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
+ // Test if resets the state of subregions as well.
+ a.b.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
+ a.b.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 483}}
+ 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 495}}
+ 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
+ }
+ }
+}
+
+class C : public A {};
+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
+ }
+ {
+ C c;
+ C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}}
+ c.foo(); // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}}
+ c.b.foo(); // no-warning
+ }
+}
+
+void resetSuperClass() {
+ C c;
+ C c1 = std::move(c);
+ c.clear();
+ C c2 = c; // no-warning
+}
+
+void reportSuperClass() {
+ C c;
+ C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}}
+ c.foo(); // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}}
+ C c2 = c; // no-warning
+}
diff --git a/test/Analysis/NewDelete-path-notes.cpp b/test/Analysis/NewDelete-path-notes.cpp
index 115a4addca..ac760ca60e 100644
--- a/test/Analysis/NewDelete-path-notes.cpp
+++ b/test/Analysis/NewDelete-path-notes.cpp
@@ -257,7 +257,7 @@ void test(Odd *odd) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Attempt to free released memory</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Double free</string>
// CHECK-NEXT: <key>check_name</key><string>cplusplus.NewDelete</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -475,7 +475,7 @@ void test(Odd *odd) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Attempt to free released memory</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Double free</string>
// CHECK-NEXT: <key>check_name</key><string>cplusplus.NewDelete</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/additive-folding.cpp b/test/Analysis/additive-folding.cpp
index 52056d472b..823b176004 100644
--- a/test/Analysis/additive-folding.cpp
+++ b/test/Analysis/additive-folding.cpp
@@ -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/analyzer-config.c b/test/Analysis/analyzer-config.c
index c0153a5053..4daea898ec 100644
--- a/test/Analysis/analyzer-config.c
+++ b/test/Analysis/analyzer-config.c
@@ -12,6 +12,9 @@ void foo() {
// CHECK: [config]
// CHECK-NEXT: cfg-conditional-static-initializers = true
+// CHECK-NEXT: cfg-implicit-dtors = true
+// CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -19,13 +22,13 @@ void foo() {
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: leak-diagnostics-reference-allocation = false
-// CHECK-NEXT: max-inlinable-size = 50
-// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-inlinable-size = 100
+// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 15
-
+// CHECK-NEXT: num-entries = 19
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
index f84be17811..a08e85e53e 100644
--- a/test/Analysis/analyzer-config.cpp
+++ b/test/Analysis/analyzer-config.cpp
@@ -23,6 +23,9 @@ public:
// CHECK-NEXT: c++-stdlib-inlining = true
// CHECK-NEXT: c++-template-inlining = true
// CHECK-NEXT: cfg-conditional-static-initializers = true
+// CHECK-NEXT: cfg-implicit-dtors = true
+// CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -30,12 +33,13 @@ public:
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: leak-diagnostics-reference-allocation = false
-// CHECK-NEXT: max-inlinable-size = 50
-// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-inlinable-size = 100
+// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 20
+// CHECK-NEXT: num-entries = 24
diff --git a/test/Analysis/analyzer_test.py b/test/Analysis/analyzer_test.py
new file mode 100644
index 0000000000..0aa2dbc1bb
--- /dev/null
+++ b/test/Analysis/analyzer_test.py
@@ -0,0 +1,43 @@
+import lit.formats
+import lit.TestRunner
+
+# Custom format class for static analyzer tests
+class AnalyzerTest(lit.formats.ShTest):
+
+ def execute(self, test, litConfig):
+ results = []
+
+ # Parse any test requirements ('REQUIRES: ')
+ saved_test = test
+ lit.TestRunner.parseIntegratedTestScript(test)
+
+ if 'z3' not in test.requires:
+ results.append(self.executeWithAnalyzeSubstitution(
+ saved_test, litConfig, '-analyzer-constraints=range'))
+
+ if results[-1].code == lit.Test.FAIL:
+ return results[-1]
+
+ # If z3 backend available, add an additional run line for it
+ if test.config.clang_staticanalyzer_z3 == '1':
+ results.append(self.executeWithAnalyzeSubstitution(
+ saved_test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3'))
+
+ # Combine all result outputs into the last element
+ for x in results:
+ if x != results[-1]:
+ results[-1].output = x.output + results[-1].output
+
+ if results:
+ return results[-1]
+ return lit.Test.Result(lit.Test.UNSUPPORTED,
+ "Test requires the following unavailable features: z3")
+
+ 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/bitwise-ops.c b/test/Analysis/bitwise-ops.c
index 407aa19289..fe546580be 100644
--- a/test/Analysis/bitwise-ops.c
+++ b/test/Analysis/bitwise-ops.c
@@ -22,11 +22,32 @@ int testConstantShifts_PR18073(int which) {
case 1:
return 0ULL << 63; // no-warning
case 2:
- return 0ULL << 64; // expected-warning{{The result of the '<<' expression is undefined}}
+ return 0ULL << 64; // expected-warning{{The result of the left shift is undefined due to shifting by '64', which is greater or equal to the width of type 'unsigned long long'}}
case 3:
- return 0ULL << 65; // expected-warning{{The result of the '<<' expression is undefined}}
+ return 0ULL << 65; // expected-warning{{The result of the left shift is undefined due to shifting by '65', which is greater or equal to the width of type 'unsigned long long'}}
default:
return 0;
}
-} \ No newline at end of file
+}
+
+int testOverflowShift(int a) {
+ if (a == 323) {
+ return 1 << a; // expected-warning{{The result of the left shift is undefined due to shifting by '323', which is greater or equal to the width of type 'int'}}
+ }
+ return 0;
+}
+
+int testNegativeShift(int a) {
+ if (a == -5) {
+ return 1 << a; // expected-warning{{The result of the left shift is undefined because the right operand is negative}}
+ }
+ return 0;
+}
+
+int testNegativeLeftShift(int a) {
+ if (a == -3) {
+ return a << 1; // expected-warning{{The result of the left shift is undefined because the left operand is negative}}
+ }
+ return 0;
+}
diff --git a/test/Analysis/block-in-critical-section.cpp b/test/Analysis/block-in-critical-section.cpp
index c65cc612cf..fcf6188fc0 100644
--- a/test/Analysis/block-in-critical-section.cpp
+++ b/test/Analysis/block-in-critical-section.cpp
@@ -7,6 +7,20 @@ struct mutex {
void lock() {}
void unlock() {}
};
+template<typename T>
+struct lock_guard {
+ lock_guard<T>(std::mutex) {}
+ ~lock_guard<T>() {}
+};
+template<typename T>
+struct unique_lock {
+ unique_lock<T>(std::mutex) {}
+ ~unique_lock<T>() {}
+};
+template<typename T>
+struct not_real_lock {
+ not_real_lock<T>(std::mutex) {}
+};
}
void getc() {}
@@ -110,3 +124,31 @@ void testBlockInCriticalSectionUnexpectedUnlock() {
m.lock();
sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
}
+
+void testBlockInCriticalSectionLockGuard() {
+ std::mutex g_mutex;
+ std::not_real_lock<std::mutex> not_real_lock(g_mutex);
+ sleep(1); // no-warning
+
+ std::lock_guard<std::mutex> lock(g_mutex);
+ sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+}
+
+void testBlockInCriticalSectionLockGuardNested() {
+ testBlockInCriticalSectionLockGuard();
+ sleep(1); // no-warning
+}
+
+void testBlockInCriticalSectionUniqueLock() {
+ std::mutex g_mutex;
+ std::not_real_lock<std::mutex> not_real_lock(g_mutex);
+ sleep(1); // no-warning
+
+ std::unique_lock<std::mutex> lock(g_mutex);
+ sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+}
+
+void testBlockInCriticalSectionUniqueLockNested() {
+ testBlockInCriticalSectionUniqueLock();
+ sleep(1); // no-warning
+}
diff --git a/test/Analysis/block-in-critical-section.m b/test/Analysis/block-in-critical-section.m
new file mode 100644
index 0000000000..73d58479f4
--- /dev/null
+++ b/test/Analysis/block-in-critical-section.m
@@ -0,0 +1,10 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.BlockInCriticalSection -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
+
+@interface SomeClass
+-(void)someMethod;
+@end
+
+void shouldNotCrash(SomeClass *o) {
+ [o someMethod];
+}
diff --git a/test/Analysis/bstring.cpp b/test/Analysis/bstring.cpp
index a6d7b40162..fea76cc082 100644
--- a/test/Analysis/bstring.cpp
+++ b/test/Analysis/bstring.cpp
@@ -1,8 +1,35 @@
// 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
#include "Inputs/system-header-simulator-cxx.h"
#include "Inputs/system-header-simulator-for-malloc.h"
+// This provides us with four possible mempcpy() definitions.
+// See also comments in bstring.c.
+
+#ifdef USE_BUILTINS
+#define BUILTIN(f) __builtin_##f
+#else /* USE_BUILTINS */
+#define BUILTIN(f) f
+#endif /* USE_BUILTINS */
+
+#ifdef VARIANT
+
+#define __mempcpy_chk BUILTIN(__mempcpy_chk)
+void *__mempcpy_chk(void *__restrict__ s1, const void *__restrict__ s2,
+ size_t n, size_t destlen);
+
+#define mempcpy(a,b,c) __mempcpy_chk(a,b,c,(size_t)-1)
+
+#else /* VARIANT */
+
+#define mempcpy BUILTIN(mempcpy)
+void *mempcpy(void *__restrict__ s1, const void *__restrict__ s2, size_t n);
+
+#endif /* VARIANT */
+
void clang_analyzer_eval(int);
int *testStdCopyInvalidatesBuffer(std::vector<int> v) {
@@ -36,3 +63,17 @@ int *testStdCopyBackwardInvalidatesBuffer(std::vector<int> v) {
return buf;
}
+
+namespace pr34460 {
+short a;
+class b {
+ int c;
+ long g;
+ void d() {
+ int e = c;
+ f += e;
+ mempcpy(f, &a, g);
+ }
+ unsigned *f;
+};
+}
diff --git a/test/Analysis/bug_hash_test.cpp b/test/Analysis/bug_hash_test.cpp
index 0efcb5f7cd..f397d181e6 100644
--- a/test/Analysis/bug_hash_test.cpp
+++ b/test/Analysis/bug_hash_test.cpp
@@ -1,1345 +1,122 @@
-// 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
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.ExprInspection %s -verify
-int function(int p) {
- return 5;
+constexpr int clang_analyzer_hashDump(int) { return 5; }
+
+void function(int) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void function(int)$27$clang_analyzer_hashDump(5);$Category}}
}
namespace {
-int variadicParam(int p, ...) {
- return 5;
-}
+void variadicParam(int, ...) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void (anonymous namespace)::variadicParam(int, ...)$27$clang_analyzer_hashDump(5);$Category}}
}
+} // namespace
-constexpr int f() { return 5; }
+constexpr int f() {
+ return clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$int f()$34$returnclang_analyzer_hashDump(5);$Category}}
+}
namespace AA {
- class X {
- int priv;
- X() : priv(5) { priv = 0; }
+class X {
+ X() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::X()$29$clang_analyzer_hashDump(5);$Category}}
+ }
- static int static_method() {
- return 5;
- }
+ static void static_method() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::static_method()$29$clang_analyzer_hashDump(5);$Category}}
+ variadicParam(5);
+ }
- int method() && {
- class Y {
- inline int method() const & {
- return 5;
- }
- };
+ void method() && {
+ struct Y {
+ inline void method() const & {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::method()::Y::method() const &$33$clang_analyzer_hashDump(5);$Category}}
+ }
+ };
- return 5;
- }
+ Y y;
+ y.method();
- int OutOfLine();
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::method() &&$29$clang_analyzer_hashDump(5);$Category}}
+ }
- X& operator=(int a) {
- return *this;
- }
+ void OutOfLine();
- operator int() {
- return 0;
- }
+ X &operator=(int) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$class AA::X & AA::X::operator=(int)$29$clang_analyzer_hashDump(5);$Category}}
+ return *this;
+ }
- explicit operator float() {
- return 0;
- }
- };
-}
+ operator int() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::operator int()$29$clang_analyzer_hashDump(5);$Category}}
+ return 0;
+ }
-int AA::X::OutOfLine() {
- return 5;
+ explicit operator float() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::operator float()$29$clang_analyzer_hashDump(5);$Category}}
+ return 0;
+ }
+};
+} // namespace AA
+
+void AA::X::OutOfLine() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::OutOfLine()$27$clang_analyzer_hashDump(5);$Category}}
}
void testLambda() {
- [] () {
- return;
+ []() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void testLambda()::(anonymous class)::operator()() const$29$clang_analyzer_hashDump(5);$Category}}
}();
}
-// CHECK: <key>diagnostics</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>5</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>5</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>debug.DumpBugHash$int function(int)$10$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int function(int)$10$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int function(int)$10$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>e7be204e83f8e5ad3c870ec011d5131d</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>function</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>10</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>10</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>bc5dc0507ee90f1d14259057d25fb2b9</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>variadicParam</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>14</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>26</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>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</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: </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>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</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>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</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>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f5471f52854dc14167fe96db50c4ba5f</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>f</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</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>debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>d23266517ac17d5ec5e2fbbdb1922af1</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>7bfcc45512a6a3f61dda6e3ecebc7384</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>95dbfbcdd1dd6401d262994c45d088be</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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: </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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>064a01551caa8eca3202f1fd55b9c692</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>22</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>22</integer>
-// CHECK-NEXT: <key>col</key><integer>12</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>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>651fcca72f8ad65771702903ecd5f68a</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>static_method</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>32</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>32</integer>
-// CHECK-NEXT: <key>col</key><integer>12</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>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>debug.DumpBugHash$int AA::X::method() &amp;&amp;$14$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::method() &amp;&amp;$14$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int AA::X::method() &amp;&amp;$14$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>c8ac8f24467234bea1f34adf5ad5007b</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>method</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>7</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>38</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>38</integer>
-// CHECK-NEXT: <key>col</key><integer>12</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>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>18</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>debug.DumpBugHash$class AA::X &amp; AA::X::operator=(int)$14$return*this;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$class AA::X &amp; AA::X::operator=(int)$14$return*this;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$class AA::X &amp; AA::X::operator=(int)$14$return*this;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>b47cf7973c9b459d9c99c483e722db8e</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>operator=</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>42</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>42</integer>
-// CHECK-NEXT: <key>col</key><integer>12</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>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>debug.DumpBugHash$AA::X::operator int()$14$return0;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::operator int()$14$return0;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::operator int()$14$return0;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>0cbb0e1e5b03ba5b4f7f8f17504de671</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>46</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>46</integer>
-// CHECK-NEXT: <key>col</key><integer>12</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>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>debug.DumpBugHash$AA::X::operator float()$14$return0;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::operator float()$14$return0;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::operator float()$14$return0;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>df306826bf89e50c1b55e1d379a761b3</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>52</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>52</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</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>debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>9dd7b17a6f62ed8c95b37a38cf71f3a9</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>OutOfLine</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>56</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>58</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>6ad4400e40885a78a0f57f585421a515</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testLambda</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</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: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>56</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>58</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: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>6ad4400e40885a78a0f57f585421a515</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testLambda</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</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: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>56</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>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</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>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</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>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</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: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$4$}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$4$}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testLambda()$4$}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>378e6de75fb41b05bcef3950ad5ffa5e</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testLambda</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>3</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
+template <typename T>
+void f(T) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(T)$27$clang_analyzer_hashDump(5);$Category}}
+}
+
+template <typename T>
+struct TX {
+ void f(T) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX::f(T)$29$clang_analyzer_hashDump(5);$Category}}
+ }
+};
+
+template <>
+void f<long>(long) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(long)$27$clang_analyzer_hashDump(5);$Category}}
+}
+
+template <>
+struct TX<long> {
+ void f(long) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX<long>::f(long)$29$clang_analyzer_hashDump(5);$Category}}
+ }
+};
+
+template <typename T>
+struct TTX {
+ template<typename S>
+ void f(T, S) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TTX::f(T, S)$29$clang_analyzer_hashDump(5);$Category}}
+ }
+};
+
+void g() {
+ // TX<int> and TX<double> is instantiated from the same code with the same
+ // source locations. The same error happining in both of the instantiations
+ // should share the common hash. This means we should not include the
+ // template argument for these types in the function signature.
+ // Note that, we still want the hash to be different for explicit
+ // specializations.
+ TX<int> x;
+ TX<double> y;
+ TX<long> xl;
+ x.f(1);
+ xl.f(1);
+ f(5);
+ f(3.0);
+ y.f(2);
+ TTX<int> z;
+ z.f<int>(5, 5);
+ f(5l);
+}
diff --git a/test/Analysis/bug_hash_test.m b/test/Analysis/bug_hash_test.m
index 1e99d3c0b9..fbb70e5d62 100644
--- a/test/Analysis/bug_hash_test.m
+++ b/test/Analysis/bug_hash_test.m
@@ -1,5 +1,6 @@
-// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
-// RUN: FileCheck --input-file=%t.plist %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,debug.ExprInspection %s -verify
+
+void clang_analyzer_hashDump(int);
@protocol NSObject
+ (id)alloc;
@@ -15,1178 +16,21 @@ __attribute__((objc_root_class))
@end
@implementation NSObject
++ (id)alloc {
+ return 0;
+}
+- (id)init {
+ return self;
+}
- (void)method:(int)arg param:(int)arg2 {
- arg = 5;
- return;
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$NSObject::method:param:$27$clang_analyzer_hashDump(5);$Category}}
}
@end
void testBlocks() {
int x = 5;
- ^{ int y = 1 + x; }();
+ ^{
+ clang_analyzer_hashDump(x); // expected-warning {{debug.ExprInspection$$29$clang_analyzer_hashDump(x);$Category}}
+ }();
}
-
-// CHECK: <key>diagnostics</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>19</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>19</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>19</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>7</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>19</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>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</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>debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f9f569e94382c1f969aabd304581b294</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>method:param:</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</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: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>19</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>19</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</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>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</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>debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>ca44d6aa882ee55f76e11a80d5a66372</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>method:param:</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>26</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>26</integer>
-// CHECK-NEXT: <key>col</key><integer>7</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>debug.DumpBugHash$void testBlocks()$3$intx=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$intx=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$3$intx=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>84ec7c854c1c7849abfa03f7f20b4f06</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</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: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</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>26</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>26</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>26</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>26</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>26</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>26</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: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$11$intx=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$11$intx=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$11$intx=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f91db2d7b129ed60e7c9caf6f8a84d5c</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</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: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</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>26</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>21</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>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>0f1e9483a8ff59e787eaac18b68068ad</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>2</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</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: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</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>26</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</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>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>0f1e9483a8ff59e787eaac18b68068ad</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>2</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</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: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</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>26</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</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>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// 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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$6$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$6$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$6$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>8a8e42efc427e1334b77d510d3fb6361</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</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>26</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</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>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// 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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>6d6028808f1d47ec5b74a417e96c2a02</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</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>26</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</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>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// 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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>162138b23629276baad7dd3e8051fd6f</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// 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>26</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>26</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</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>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// 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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&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>27</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</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>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$18$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$18$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$18$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>b3add78bcab0ebc3da3b640081057525</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
diff --git a/test/Analysis/builtin-functions.cpp b/test/Analysis/builtin-functions.cpp
index 4e9859754d..2c19502511 100644
--- a/test/Analysis/builtin-functions.cpp
+++ b/test/Analysis/builtin-functions.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,debug.ExprInspection %s -std=c++11 -verify
void clang_analyzer_eval(bool);
+void clang_analyzer_warnIfReached();
void testAddressof(int x) {
clang_analyzer_eval(&x == __builtin_addressof(x)); // expected-warning{{TRUE}}
@@ -50,3 +51,16 @@ void test_assume_aligned_4(char *p) {
q = (char*) __builtin_assume_aligned(p + 1, 16);
clang_analyzer_eval(p == q); // expected-warning{{FALSE}}
}
+
+void f(int i) {
+ __builtin_assume(i < 10);
+ clang_analyzer_eval(i < 15); // expected-warning {{TRUE}}
+}
+
+void g(int i) {
+ if (i > 5) {
+ __builtin_assume(i < 5);
+ clang_analyzer_warnIfReached(); // Assumtion contradicts constraints.
+ // We give up the analysis on this path.
+ }
+}
diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp
new file mode 100644
index 0000000000..5013cd423e
--- /dev/null
+++ b/test/Analysis/call_once.cpp
@@ -0,0 +1,305 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s
+
+void clang_analyzer_eval(bool);
+
+// Faking std::std::call_once implementation.
+namespace std {
+
+#ifndef EMULATE_LIBSTDCPP
+typedef struct once_flag_s {
+ unsigned long __state_ = 0;
+} once_flag;
+#else
+typedef struct once_flag_s {
+ int _M_once = 0;
+} once_flag;
+#endif
+
+template <class Callable, class... Args>
+void call_once(once_flag &o, Callable&& func, Args&&... args) {};
+
+} // namespace std
+
+// Check with Lambdas.
+void test_called_warning() {
+ std::once_flag g_initialize;
+ int z;
+
+ std::call_once(g_initialize, [&] {
+ int *x = nullptr;
+ int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+ z = 200;
+ });
+}
+
+void test_called_on_path_inside_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+ int z;
+
+ std::call_once(g_initialize, [&] {
+ z = 200;
+ x = &z;
+ });
+
+ *x = 100; // no-warning
+ clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}
+}
+
+void test_called_on_path_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+ *x = 100; // no-warning
+}
+
+void test_called_on_path_warning() {
+ std::once_flag g_initialize;
+
+ int y = 100;
+ int *x = &y;
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+ *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+}
+
+void test_called_once_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+ *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+}
+
+void test_called_once_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+ *x = 100; // no-warning
+}
+
+static int global = 0;
+void funcPointer() {
+ global = 1;
+}
+
+void test_func_pointers() {
+ static std::once_flag flag;
+ std::call_once(flag, &funcPointer);
+ clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}
+}
+
+template <class _Fp>
+class function; // undefined
+template <class _Rp, class... _ArgTypes>
+struct function<_Rp(_ArgTypes...)> {
+ _Rp operator()(_ArgTypes...) const {};
+ template <class _Fp>
+ function(_Fp) {};
+};
+
+// Note: currently we do not support calls to std::function,
+// but the analyzer should not crash either.
+void test_function_objects_warning() {
+ int x = 0;
+ int *y = &x;
+
+ std::once_flag flag;
+
+ function<void()> func = [&]() {
+ y = nullptr;
+ };
+
+ std::call_once(flag, func);
+
+ func();
+ int z = *y;
+}
+
+void test_param_passing_lambda() {
+ std::once_flag flag;
+ int x = 120;
+ int y = 0;
+
+ std::call_once(flag, [&](int p) {
+ y = p;
+ },
+ x);
+
+ clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
+}
+
+void test_param_passing_lambda_false() {
+ std::once_flag flag;
+ int x = 120;
+
+ std::call_once(flag, [&](int p) {
+ x = 0;
+ },
+ x);
+
+ clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
+}
+
+void test_param_passing_stored_lambda() {
+ std::once_flag flag;
+ int x = 120;
+ int y = 0;
+
+ auto lambda = [&](int p) {
+ y = p;
+ };
+
+ std::call_once(flag, lambda, x);
+ clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
+}
+
+void test_multiparam_passing_lambda() {
+ std::once_flag flag;
+ int x = 120;
+
+ std::call_once(flag, [&](int a, int b, int c) {
+ x = a + b + c;
+ },
+ 1, 2, 3);
+
+ clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
+ clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}
+}
+
+static int global2 = 0;
+void test_param_passing_lambda_global() {
+ std::once_flag flag;
+ global2 = 0;
+ std::call_once(flag, [&](int a, int b, int c) {
+ global2 = a + b + c;
+ },
+ 1, 2, 3);
+ clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}
+}
+
+static int global3 = 0;
+void funcptr(int a, int b, int c) {
+ global3 = a + b + c;
+}
+
+void test_param_passing_funcptr() {
+ std::once_flag flag;
+ global3 = 0;
+
+ std::call_once(flag, &funcptr, 1, 2, 3);
+
+ clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}
+}
+
+void test_blocks() {
+ global3 = 0;
+ std::once_flag flag;
+ std::call_once(flag, ^{
+ global3 = 120;
+ });
+ clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}
+}
+
+int call_once() {
+ return 5;
+}
+
+void test_non_std_call_once() {
+ int x = call_once();
+ clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
+}
+
+namespace std {
+template <typename d, typename e>
+void call_once(d, e);
+}
+void g();
+void test_no_segfault_on_different_impl() {
+ std::call_once(g, false); // no-warning
+}
+
+void test_lambda_refcapture() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [&](int &a) { a = 42; }, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+}
+
+void test_lambda_refcapture2() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [=](int &a) { a = 42; }, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+}
+
+void test_lambda_fail_refcapture() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [=](int a) { a = 42; }, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
+}
+
+void mutator(int &param) {
+ param = 42;
+}
+void test_reftypes_funcptr() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, &mutator, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+}
+
+void fail_mutator(int param) {
+ param = 42;
+}
+void test_mutator_noref() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, &fail_mutator, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
+}
+
+// Function is implicitly treated as a function pointer
+// even when an ampersand is not explicitly set.
+void callbackn(int &param) {
+ param = 42;
+}
+void test_implicit_funcptr() {
+ int x = 0;
+ static std::once_flag flagn;
+
+ std::call_once(flagn, callbackn, x);
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index 92082fec2b..24bba8a30a 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -118,3 +118,34 @@ 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}}
+}
+
+void multiDimensionalArrayPointerCasts() {
+ static int x[10][10];
+ int *y1 = &(x[3][5]);
+ char *z = ((char *) y1) + 2;
+ int *y2 = (int *)(z - 2);
+ int *y3 = ((int *)x) + 35; // This is offset for [3][5].
+
+ clang_analyzer_eval(y1 == y2); // expected-warning{{TRUE}}
+
+ // FIXME: should be FALSE (i.e. equal pointers).
+ clang_analyzer_eval(y1 - y2); // expected-warning{{UNKNOWN}}
+ // FIXME: should be TRUE (i.e. same symbol).
+ clang_analyzer_eval(*y1 == *y2); // expected-warning{{UNKNOWN}}
+
+ clang_analyzer_eval(*((char *)y1) == *((char *) y2)); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(y1 == y3); // expected-warning{{TRUE}}
+
+ // FIXME: should be FALSE (i.e. equal pointers).
+ clang_analyzer_eval(y1 - y3); // expected-warning{{UNKNOWN}}
+ // FIXME: should be TRUE (i.e. same symbol).
+ clang_analyzer_eval(*y1 == *y3); // expected-warning{{UNKNOWN}}
+
+ clang_analyzer_eval(*((char *)y1) == *((char *) y3)); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/compound-literals.c b/test/Analysis/compound-literals.c
new file mode 100644
index 0000000000..a2556d2a79
--- /dev/null
+++ b/test/Analysis/compound-literals.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple=i386-apple-darwin10 -analyze -analyzer-checker=debug.ExprInspection -verify %s
+void clang_analyzer_eval(int);
+
+// pr28449: Used to crash.
+void foo(void) {
+ static const unsigned short array[] = (const unsigned short[]){0x0F00};
+ // FIXME: Should be true.
+ clang_analyzer_eval(array[0] == 0x0F00); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/conversion.c b/test/Analysis/conversion.c
index 5827794af2..7adb336eb2 100644
--- a/test/Analysis/conversion.c
+++ b/test/Analysis/conversion.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -Wno-conversion -analyzer-checker=core,alpha.core.Conversion -verify %s
+// RUN: %clang_analyze_cc1 -Wno-conversion -Wno-tautological-constant-compare -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 2e3613dfca..1d93469aa3 100644
--- a/test/Analysis/copypaste/asm.cpp
+++ b/test/Analysis/copypaste/asm.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/attributes.cpp b/test/Analysis/copypaste/attributes.cpp
index 083be74436..f71545130c 100644
--- a/test/Analysis/copypaste/attributes.cpp
+++ b/test/Analysis/copypaste/attributes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/autogenerated_automoc.cpp b/test/Analysis/copypaste/autogenerated_automoc.cpp
new file mode 100644
index 0000000000..0f7f9c9e45
--- /dev/null
+++ b/test/Analysis/copypaste/autogenerated_automoc.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|.*_automoc.cpp" -verify %s
+
+// Because files that have `_automoc.' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/blocks.cpp b/test/Analysis/copypaste/blocks.cpp
index 10467b7248..23821560ea 100644
--- a/test/Analysis/copypaste/blocks.cpp
+++ b/test/Analysis/copypaste/blocks.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -fblocks -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 046229a30a..c5ddae5a65 100644
--- a/test/Analysis/copypaste/call.cpp
+++ b/test/Analysis/copypaste/call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/catch.cpp b/test/Analysis/copypaste/catch.cpp
index cf3e8076bd..edcf44ae6f 100644
--- a/test/Analysis/copypaste/catch.cpp
+++ b/test/Analysis/copypaste/catch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -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 -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/dbus_autogenerated.cpp b/test/Analysis/copypaste/dbus_autogenerated.cpp
new file mode 100644
index 0000000000..1824375658
--- /dev/null
+++ b/test/Analysis/copypaste/dbus_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|dbus_|.*_automoc" -verify %s
+
+// Because files that have `dbus_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/delete.cpp b/test/Analysis/copypaste/delete.cpp
index 394226bedf..4edb46035a 100644
--- a/test/Analysis/copypaste/delete.cpp
+++ b/test/Analysis/copypaste/delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/dependent-exist.cpp b/test/Analysis/copypaste/dependent-exist.cpp
index 9046353d0f..28f2ceb21a 100644
--- a/test/Analysis/copypaste/dependent-exist.cpp
+++ b/test/Analysis/copypaste/dependent-exist.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -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 -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/expr-types.cpp b/test/Analysis/copypaste/expr-types.cpp
index 601f0b192a..6062be306e 100644
--- a/test/Analysis/copypaste/expr-types.cpp
+++ b/test/Analysis/copypaste/expr-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/fold.cpp b/test/Analysis/copypaste/fold.cpp
index 0aed11bcf0..fadcb49fa0 100644
--- a/test/Analysis/copypaste/fold.cpp
+++ b/test/Analysis/copypaste/fold.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/function-try-block.cpp b/test/Analysis/copypaste/function-try-block.cpp
index d77714591b..d0fbc50f67 100644
--- a/test/Analysis/copypaste/function-try-block.cpp
+++ b/test/Analysis/copypaste/function-try-block.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -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 -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 d2c607b217..2bfe591a50 100644
--- a/test/Analysis/copypaste/functions.cpp
+++ b/test/Analysis/copypaste/functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 d4d4564736..2fa6c302da 100644
--- a/test/Analysis/copypaste/generic.c
+++ b/test/Analysis/copypaste/generic.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/labels.cpp b/test/Analysis/copypaste/labels.cpp
index eff3330a0f..18c5b22d3b 100644
--- a/test/Analysis/copypaste/labels.cpp
+++ b/test/Analysis/copypaste/labels.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=gnu++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=gnu++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/lambda.cpp b/test/Analysis/copypaste/lambda.cpp
index 17c8748943..456d83a995 100644
--- a/test/Analysis/copypaste/lambda.cpp
+++ b/test/Analysis/copypaste/lambda.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/macros.cpp b/test/Analysis/copypaste/macros.cpp
index bdacd4839a..ea05bbd428 100644
--- a/test/Analysis/copypaste/macros.cpp
+++ b/test/Analysis/copypaste/macros.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -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 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/moc_autogenerated.cpp b/test/Analysis/copypaste/moc_autogenerated.cpp
new file mode 100644
index 0000000000..626fe2a3dd
--- /dev/null
+++ b/test/Analysis/copypaste/moc_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|.*_automoc" -verify %s
+
+// Because files that have `moc_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/not-autogenerated.cpp b/test/Analysis/copypaste/not-autogenerated.cpp
new file mode 100644
index 0000000000..d54ee176fa
--- /dev/null
+++ b/test/Analysis/copypaste/not-autogenerated.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|ui_|dbus_|.*_automoc" -verify %s
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1; // expected-note{{Similar code using 'p1' here}}
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // expected-warning{{Potential copy-paste error; did you really mean to use 'p1' here?}}
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/objc-methods.m b/test/Analysis/copypaste/objc-methods.m
index e63c7f6288..0a84370793 100644
--- a/test/Analysis/copypaste/objc-methods.m
+++ b/test/Analysis/copypaste/objc-methods.m
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -Wno-objc-root-class -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -Wno-objc-root-class -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 7c4f35525f..d4402a9dd5 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_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: %clang_analyze_cc1 -analyzer-output=plist -analyzer-config notes-as-events=true -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 e2fa7597ca..c138c6f1f9 100644
--- a/test/Analysis/copypaste/plist-diagnostics.cpp
+++ b/test/Analysis/copypaste/plist-diagnostics.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -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 -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 798662d256..d2c08350ab 100644
--- a/test/Analysis/copypaste/sub-sequences.cpp
+++ b/test/Analysis/copypaste/sub-sequences.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 3a760e2562..ae29b0e16d 100644
--- a/test/Analysis/copypaste/suspicious-clones.cpp
+++ b/test/Analysis/copypaste/suspicious-clones.cpp
@@ -1,4 +1,4 @@
-// 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
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:ReportSuspiciousClones=true -analyzer-config alpha.clone.CloneChecker:ReportNormalClones=false -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -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 a6e358cc85..a3132e9534 100644
--- a/test/Analysis/copypaste/text-diagnostics.cpp
+++ b/test/Analysis/copypaste/text-diagnostics.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -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 -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
void log();
diff --git a/test/Analysis/copypaste/ui_autogenerated.cpp b/test/Analysis/copypaste/ui_autogenerated.cpp
new file mode 100644
index 0000000000..a08c33fe9e
--- /dev/null
+++ b/test/Analysis/copypaste/ui_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|ui_|.*_automoc" -verify %s
+
+// Because files that have `ui_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/ctor.mm b/test/Analysis/ctor.mm
index 646229aac9..e903263431 100644
--- a/test/Analysis/ctor.mm
+++ b/test/Analysis/ctor.mm
@@ -199,7 +199,7 @@ namespace PODUninitialized {
Inner p;
};
- void testPOD() {
+ void testPOD(const POD &pp) {
POD p;
p.x = 1;
POD p2 = p; // no-warning
@@ -210,6 +210,15 @@ namespace PODUninitialized {
// Use rvalues as well.
clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
+ // Copy from symbolic references correctly.
+ POD p4 = pp;
+ // Make sure that p4.x contains a symbol after copy.
+ if (p4.x > 0)
+ clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}}
+ // FIXME: Element region gets in the way, so these aren't the same symbols
+ // as they should be.
+ clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}}
+
PODWrapper w;
w.p.y = 1;
PODWrapper w2 = w; // no-warning
@@ -704,3 +713,20 @@ namespace PR19579 {
};
}
}
+
+namespace NoCrashOnEmptyBaseOptimization {
+ struct NonEmptyBase {
+ int X;
+ explicit NonEmptyBase(int X) : X(X) {}
+ };
+
+ struct EmptyBase {};
+
+ struct S : NonEmptyBase, EmptyBase {
+ S() : NonEmptyBase(0), EmptyBase() {}
+ };
+
+ void testSCtorNoCrash() {
+ S s;
+ }
+}
diff --git a/test/Analysis/diagnostics/diag-cross-file-boundaries.c b/test/Analysis/diagnostics/diag-cross-file-boundaries.c
deleted file mode 100644
index b975af3fb2..0000000000
--- a/test/Analysis/diagnostics/diag-cross-file-boundaries.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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"
-
-int main(){
- f();
- return 0;
-}
-
-// CHECK: warning: Path diagnostic report is not generated.
diff --git a/test/Analysis/diagnostics/explicit-suppression.cpp b/test/Analysis/diagnostics/explicit-suppression.cpp
index 193846c082..96d2b4a7d0 100644
--- a/test/Analysis/diagnostics/explicit-suppression.cpp
+++ b/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -19,6 +19,6 @@ class C {
void testCopyNull(C *I, C *E) {
std::copy(I, E, (C *)0);
#ifndef SUPPRESSED
- // expected-warning@../Inputs/system-header-simulator-cxx.h:191 {{Called C++ object pointer is null}}
+ // expected-warning@../Inputs/system-header-simulator-cxx.h:490 {{Called C++ object pointer is null}}
#endif
}
diff --git a/test/Analysis/diagnostics/report-issues-within-main-file.cpp b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
index 784fdba972..e1dccc8e32 100644
--- a/test/Analysis/diagnostics/report-issues-within-main-file.cpp
+++ b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
@@ -945,7 +945,7 @@ void callInMacroArg() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos; (within a call to &apos;~auto_ptr&apos;)</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/edges-new.mm b/test/Analysis/edges-new.mm
index 217cd4aa46..f310f1bfa1 100644
--- a/test/Analysis/edges-new.mm
+++ b/test/Analysis/edges-new.mm
@@ -20042,7 +20042,7 @@ namespace rdar14960554 {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -20284,11 +20284,11 @@ namespace rdar14960554 {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>d9dbbf68db41ab74e2158f4b131abe34</string>
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>046c88d1c91ff46d6506dff5ff880756</string>
// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
diff --git a/test/Analysis/enum.cpp b/test/Analysis/enum.cpp
index e26b8f00d9..96408473ce 100644
--- a/test/Analysis/enum.cpp
+++ b/test/Analysis/enum.cpp
@@ -24,3 +24,46 @@ void testCasting(int i) {
clang_analyzer_eval(j == 0); // expected-warning{{FALSE}}
}
}
+
+enum class EnumBool : bool {
+ F = false,
+ T = true
+};
+
+bool testNoCrashOnSwitchEnumBool(EnumBool E) {
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
+
+bool testNoCrashOnSwitchEnumBoolConstant() {
+ EnumBool E = EnumBool::F;
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
+
+typedef __INTPTR_TYPE__ intptr_t;
+bool testNoCrashOnSwitchEnumBoolConstantCastedFromNullptr() {
+ EnumBool E = static_cast<EnumBool>((intptr_t)nullptr);
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
+
+bool testNoCrashOnSwitchEnumBoolConstantCastedFromPtr() {
+ int X;
+ intptr_t P = (intptr_t)&X;
+ EnumBool E = static_cast<EnumBool>(P);
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index 577b88bf83..c459260c2a 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -21,3 +21,11 @@ static void f2(void *buf) {
memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring library function 'memcpy' with type 'void *(void *, const void *}} \
// expected-note{{include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
}
+
+// AllocaRegion is untyped. Void pointer isn't of much help either. Before
+// realizing that the value is undefined, we need to somehow figure out
+// what type of value do we expect.
+void f3(void *dest) {
+ void *src = __builtin_alloca(5);
+ memcpy(dest, src, 1); // expected-warning{{2nd function call argument is a pointer to uninitialized value}}
+}
diff --git a/test/Analysis/expr-inspection.c b/test/Analysis/expr-inspection.c
index 1e21efb4ef..ec0e682b65 100644
--- a/test/Analysis/expr-inspection.c
+++ b/test/Analysis/expr-inspection.c
@@ -8,6 +8,7 @@ void clang_analyzer_numTimesReached();
void foo(int x) {
clang_analyzer_dump(x); // expected-warning{{reg_$0<int x>}}
+ clang_analyzer_dump(x + (-1)); // expected-warning{{(reg_$0<int x>) + -1}}
int y = 1;
clang_analyzer_printState();
for (; y < 3; ++y)
@@ -19,4 +20,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/func-mapping-test.cpp b/test/Analysis/func-mapping-test.cpp
new file mode 100644
index 0000000000..37e653882b
--- /dev/null
+++ b/test/Analysis/func-mapping-test.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_func_map %s -- | FileCheck %s
+
+int f(int) {
+ return 0;
+}
+
+// CHECK: c:@F@f#I#
diff --git a/test/Analysis/gmalloc.c b/test/Analysis/gmalloc.c
index 10c4fe2840..50413e2e9b 100644
--- a/test/Analysis/gmalloc.c
+++ b/test/Analysis/gmalloc.c
@@ -13,6 +13,12 @@ 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);
+gpointer g_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
void g_free(gpointer mem);
gpointer g_memdup(gconstpointer mem, guint byte_size);
@@ -25,6 +31,12 @@ void f1() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
g_free(g1);
g_free(g2);
@@ -38,6 +50,12 @@ void f2() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
g_free(g1);
g_free(g2);
@@ -52,8 +70,100 @@ void f3() {
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'}}
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+}
+
+void f4() {
+ 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);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+}
+
+void f5() {
+ 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);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+ g_free(g5);
+}
+
+void f6() {
+ 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);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+ g_free(g5);
+ g_free(g6);
+}
+
+void f7() {
+ 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);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
g_free(g1);
g_free(g2);
g_free(g3);
+ g_free(g4);
+ g_free(g5);
+ g_free(g6);
+ g_free(g7);
}
diff --git a/test/Analysis/gtest.cpp b/test/Analysis/gtest.cpp
index 5797a773b4..98f415eea4 100644
--- a/test/Analysis/gtest.cpp
+++ b/test/Analysis/gtest.cpp
@@ -151,3 +151,17 @@ void testConstrainState(int p) {
ASSERT_TRUE(false);
clang_analyzer_warnIfReached(); // no-warning
}
+
+void testAssertSymbolicPtr(const bool *b) {
+ ASSERT_TRUE(*b); // no-crash
+
+ // FIXME: Our solver doesn't handle this well yet.
+ clang_analyzer_eval(*b); // expected-warning{{UNKNOWN}}
+}
+
+void testAssertSymbolicRef(const bool &b) {
+ ASSERT_TRUE(b); // no-crash
+
+ // FIXME: Our solver doesn't handle this well yet.
+ clang_analyzer_eval(b); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/html-diag-singlefile.c b/test/Analysis/html-diag-singlefile.c
new file mode 100644
index 0000000000..fc0dcc7a42
--- /dev/null
+++ b/test/Analysis/html-diag-singlefile.c
@@ -0,0 +1,14 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=html-single-file -o D30406.html %s 2>&1 | FileCheck %s
+
+// Check that single file HTML output does not process multi-file diagnostics.
+// (This used to test for PR12421, before the introduction of the html-single-file format)
+
+#include "html-diag-singlefile.h"
+
+int main(){
+ f();
+ return 0;
+}
+
+// CHECK: warning: Path diagnostic report is not generated.
diff --git a/test/Analysis/diagnostics/diag-cross-file-boundaries.h b/test/Analysis/html-diag-singlefile.h
index 1af7d1f1fb..1af7d1f1fb 100644
--- a/test/Analysis/diagnostics/diag-cross-file-boundaries.h
+++ b/test/Analysis/html-diag-singlefile.h
diff --git a/test/Analysis/html-diags-analyze-headers.c b/test/Analysis/html-diags-analyze-headers.c
new file mode 100644
index 0000000000..fa5f21de04
--- /dev/null
+++ b/test/Analysis/html-diags-analyze-headers.c
@@ -0,0 +1,10 @@
+// RUN: mkdir -p %t.dir
+// RUN: %clang_analyze_cc1 -analyzer-opt-analyze-headers -analyzer-output=html -analyzer-checker=core -o %t.dir %s
+// RUN: ls %t.dir | grep report
+// RUN: rm -rf %t.dir
+
+// This tests that we emit HTML diagnostics for reports in headers when the
+// analyzer is run with -analyzer-opt-analyze-headers. This was handled
+// incorrectly in the first iteration of D30406.
+
+#include "html-diags-analyze-headers.h"
diff --git a/test/Analysis/html-diags-analyze-headers.h b/test/Analysis/html-diags-analyze-headers.h
new file mode 100644
index 0000000000..3641ca9c04
--- /dev/null
+++ b/test/Analysis/html-diags-analyze-headers.h
@@ -0,0 +1,5 @@
+#include "html-diags-multifile.h"
+
+void test_call_macro() {
+ has_bug(0);
+}
diff --git a/test/Analysis/html-diags-multifile.c b/test/Analysis/html-diags-multifile.c
index ce1f72b6bb..ff7b625ad0 100644
--- a/test/Analysis/html-diags-multifile.c
+++ b/test/Analysis/html-diags-multifile.c
@@ -1,10 +1,9 @@
// RUN: mkdir -p %t.dir
// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %t.dir %s
-// RUN: ls %t.dir | not grep report
+// RUN: ls %t.dir | grep report
// RUN: rm -fR %t.dir
-// This tests that we do not currently emit HTML diagnostics for reports that
-// cross file boundaries.
+// This tests that we emit HTML diagnostics for reports that cross file boundaries.
#include "html-diags-multifile.h"
diff --git a/test/Analysis/html-diags.c b/test/Analysis/html-diags.c
index 182bcfbdfa..89f1e8ba79 100644
--- a/test/Analysis/html-diags.c
+++ b/test/Analysis/html-diags.c
@@ -1,12 +1,18 @@
-// RUN: rm -fR %T/dir
-// RUN: mkdir %T/dir
-// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %T/dir %s
-// RUN: ls %T/dir | grep report
+// RUN: rm -fR %t
+// RUN: mkdir %t
+// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %t %s
+// RUN: ls %t | grep report
+
+// D30406: Test new html-single-file output
+// RUN: rm -fR %t
+// RUN: mkdir %t
+// RUN: %clang_analyze_cc1 -analyzer-output=html-single-file -analyzer-checker=core -o %t %s
+// RUN: ls %t | grep report
// PR16547: Test relative paths
-// RUN: cd %T/dir
+// RUN: cd %t
// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o testrelative %s
-// RUN: ls %T/dir/testrelative | grep report
+// RUN: ls %t/testrelative | grep report
// Currently this test mainly checks that the HTML diagnostics doesn't crash
// when handling macros will calls with macros. We should actually validate
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index c73635686d..e9658a067c 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -1,7 +1,9 @@
-// RUN: %clang_analyze_cc1 -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,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
void clang_analyzer_eval(bool);
+#include "Inputs/system-header-simulator-cxx.h"
+
class A {
int x;
public:
@@ -204,3 +206,17 @@ struct C {
const char(&f)[2];
};
}
+
+namespace CXX_initializer_lists {
+struct C {
+ C(std::initializer_list<int *> list);
+};
+void foo() {
+ C empty{}; // no-crash
+
+ // Do not warn that 'x' leaks. It might have been deleted by
+ // the destructor of 'c'.
+ int *x = new int;
+ C c{x}; // no-warning
+}
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.c b/test/Analysis/inlining/inline-defensive-checks.c
index 4029da651b..9f211b502b 100644
--- a/test/Analysis/inlining/inline-defensive-checks.c
+++ b/test/Analysis/inlining/inline-defensive-checks.c
@@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
// Perform inline defensive checks.
-void idc(int *p) {
+void idc(void *p) {
if (p)
;
}
@@ -139,3 +139,54 @@ void idcTrackZeroThroughDoubleAssignemnt(int x) {
int z = y;
idcTriggerZeroValueThroughCall(z);
}
+
+struct S {
+ int f1;
+ int f2;
+};
+
+void idcTrackZeroValueThroughUnaryPointerOperators(struct S *s) {
+ idc(s);
+ *(&(s->f1)) = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithOffset1(struct S *s) {
+ idc(s);
+ int *x = &(s->f2);
+ *x = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithOffset2(struct S *s) {
+ idc(s);
+ int *x = &(s->f2) - 1;
+ // FIXME: Should not warn.
+ *x = 7; // expected-warning{{Dereference of null pointer}}
+}
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithAssignment(struct S *s) {
+ idc(s);
+ int *x = &(s->f1);
+ *x = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignment(struct S *s) {
+ idc(s);
+ int *x = &*&(s->f1);
+ *x = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignmentAndUnaryIncrement(struct S *s) {
+ idc(s);
+ int *x = &*&((++s)->f1);
+ *x = 7; // no-warning
+}
+
+
+struct S2 {
+ int a[1];
+};
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithArrayField(struct S2 *s) {
+ idc(s);
+ *(&(s->a[0])) = 7; // no-warning
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.cpp b/test/Analysis/inlining/inline-defensive-checks.cpp
index 6a803fa695..eaae8d2ae2 100644
--- a/test/Analysis/inlining/inline-defensive-checks.cpp
+++ b/test/Analysis/inlining/inline-defensive-checks.cpp
@@ -70,4 +70,17 @@ int *retNull() {
void test(int *p1, int *p2) {
idc(p1);
Foo f(p1);
-} \ No newline at end of file
+}
+
+struct Bar {
+ int x;
+};
+void idcBar(Bar *b) {
+ if (b)
+ ;
+}
+void testRefToField(Bar *b) {
+ idcBar(b);
+ int &x = b->x; // no-warning
+ x = 5;
+}
diff --git a/test/Analysis/iterator-past-end.cpp b/test/Analysis/iterator-past-end.cpp
deleted file mode 100644
index 252d1044bd..0000000000
--- a/test/Analysis/iterator-past-end.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-// 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"
-
-void simple_good(const std::vector<int> &v) {
- auto i = v.end();
- if (i != v.end())
- *i; // no-warning
-}
-
-void simple_good_negated(const std::vector<int> &v) {
- auto i = v.end();
- if (!(i == v.end()))
- *i; // no-warning
-}
-
-void simple_bad(const std::vector<int> &v) {
- auto i = v.end();
- *i; // expected-warning{{Iterator accessed past its end}}
-}
-
-void copy(const std::vector<int> &v) {
- auto i1 = v.end();
- auto i2 = i1;
- *i2; // expected-warning{{Iterator accessed past its end}}
-}
-
-void decrease(const std::vector<int> &v) {
- auto i = v.end();
- --i;
- *i; // no-warning
-}
-
-void copy_and_decrease1(const std::vector<int> &v) {
- auto i1 = v.end();
- auto i2 = i1;
- --i1;
- *i1; // no-warning
-}
-
-void copy_and_decrease2(const std::vector<int> &v) {
- auto i1 = v.end();
- auto i2 = i1;
- --i1;
- *i2; // expected-warning{{Iterator accessed past its end}}
-}
-
-void copy_and_increase1(const std::vector<int> &v) {
- auto i1 = v.begin();
- auto i2 = i1;
- ++i1;
- if (i1 == v.end())
- *i2; // no-warning
-}
-
-void copy_and_increase2(const std::vector<int> &v) {
- auto i1 = v.begin();
- auto i2 = i1;
- ++i1;
- if (i2 == v.end())
- *i2; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find(std::vector<int> &vec, int e) {
- auto first = std::find(vec.begin(), vec.end(), e);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find(std::vector<int> &vec, int e) {
- auto first = std::find(vec.begin(), vec.end(), e);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find_end(std::vector<int> &vec, std::vector<int> &seq) {
- auto last = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != last)
- *last; // no-warning
-}
-
-void bad_find_end(std::vector<int> &vec, std::vector<int> &seq) {
- auto last = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
- *last; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find_first_of(std::vector<int> &vec, std::vector<int> &seq) {
- auto first =
- std::find_first_of(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find_first_of(std::vector<int> &vec, std::vector<int> &seq) {
- auto first = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-bool odd(int i) { return i % 2; }
-
-void good_find_if(std::vector<int> &vec) {
- auto first = std::find_if(vec.begin(), vec.end(), odd);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find_if(std::vector<int> &vec, int e) {
- auto first = std::find_if(vec.begin(), vec.end(), odd);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find_if_not(std::vector<int> &vec) {
- auto first = std::find_if_not(vec.begin(), vec.end(), odd);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find_if_not(std::vector<int> &vec, int e) {
- auto first = std::find_if_not(vec.begin(), vec.end(), odd);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_lower_bound(std::vector<int> &vec, int e) {
- auto first = std::lower_bound(vec.begin(), vec.end(), e);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_lower_bound(std::vector<int> &vec, int e) {
- auto first = std::lower_bound(vec.begin(), vec.end(), e);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_upper_bound(std::vector<int> &vec, int e) {
- auto last = std::lower_bound(vec.begin(), vec.end(), e);
- if (vec.end() != last)
- *last; // no-warning
-}
-
-void bad_upper_bound(std::vector<int> &vec, int e) {
- auto last = std::lower_bound(vec.begin(), vec.end(), e);
- *last; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_search(std::vector<int> &vec, std::vector<int> &seq) {
- auto first = std::search(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_search(std::vector<int> &vec, std::vector<int> &seq) {
- auto first = std::search(vec.begin(), vec.end(), seq.begin(), seq.end());
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_search_n(std::vector<int> &vec, std::vector<int> &seq) {
- auto nth = std::search_n(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != nth)
- *nth; // no-warning
-}
-
-void bad_search_n(std::vector<int> &vec, std::vector<int> &seq) {
- auto nth = std::search_n(vec.begin(), vec.end(), seq.begin(), seq.end());
- *nth; // expected-warning{{Iterator accessed past its end}}
-}
-
-template <class InputIterator, class T>
-InputIterator nonStdFind(InputIterator first, InputIterator last,
- const T &val) {
- for (auto i = first; i != last; ++i) {
- if (*i == val) {
- return i;
- }
- }
- return last;
-}
-
-void good_non_std_find(std::vector<int> &vec, int e) {
- auto first = nonStdFind(vec.begin(), vec.end(), e);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_non_std_find(std::vector<int> &vec, int e) {
- auto first = nonStdFind(vec.begin(), vec.end(), e);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void tricky(std::vector<int> &vec, int e) {
- const auto first = vec.begin();
- const auto comp1 = (first != vec.end()), comp2 = (first == vec.end());
- if (comp1)
- *first;
-}
-
-void loop(std::vector<int> &vec, int e) {
- auto start = vec.begin();
- while (true) {
- auto item = std::find(start, vec.end(), e);
- if (item == vec.end())
- break;
- *item; // no-warning
- start = ++item; // no-warning
- }
-}
diff --git a/test/Analysis/iterator-range.cpp b/test/Analysis/iterator-range.cpp
new file mode 100644
index 0000000000..79b45188ab
--- /dev/null
+++ b/test/Analysis/iterator-range.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-eagerly-assume -analyzer-config c++-container-inlining=false %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-eagerly-assume -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void clang_analyzer_warnIfReached();
+
+void simple_good_end(const std::vector<int> &v) {
+ auto i = v.end();
+ if (i != v.end()) {
+ clang_analyzer_warnIfReached();
+ *i; // no-warning
+ }
+}
+
+void simple_bad_end(const std::vector<int> &v) {
+ auto i = v.end();
+ *i; // expected-warning{{Iterator accessed outside of its range}}
+}
diff --git a/test/Analysis/lifetime-cfg-output.cpp b/test/Analysis/lifetime-cfg-output.cpp
new file mode 100644
index 0000000000..1e6f56df6a
--- /dev/null
+++ b/test/Analysis/lifetime-cfg-output.cpp
@@ -0,0 +1,783 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-lifetime=true -analyzer-config cfg-implicit-dtors=false %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+extern bool UV;
+class A {
+public:
+ // CHECK: [B2 (ENTRY)]
+ // CHECK-NEXT: Succs (1): B1
+ // CHECK: [B1]
+ // CHECK-NEXT: 1: true
+ // CHECK-NEXT: 2: UV
+ // CHECK-NEXT: 3: [B1.2] = [B1.1]
+ // CHECK-NEXT: Preds (1): B2
+ // CHECK-NEXT: Succs (1): B0
+ // CHECK: [B0 (EXIT)]
+ // CHECK-NEXT: Preds (1): B1
+ A() {
+ UV = true;
+ }
+ // CHECK: [B3 (ENTRY)]
+ // CHECK-NEXT: Succs (1): B2
+ // CHECK: [B1]
+ // CHECK-NEXT: 1: 0
+ // CHECK-NEXT: 2: this
+ // CHECK-NEXT: 3: [B1.2]->p
+ // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, LValueToRValue, int *)
+ // CHECK-NEXT: 5: *[B1.4]
+ // CHECK-NEXT: 6: [B1.5] = [B1.1]
+ // CHECK-NEXT: Preds (1): B2
+ // CHECK-NEXT: Succs (1): B0
+ // CHECK: [B2]
+ // CHECK-NEXT: 1: this
+ // CHECK-NEXT: 2: [B2.1]->p
+ // CHECK-NEXT: 3: [B2.2] (ImplicitCastExpr, LValueToRValue, int *)
+ // CHECK-NEXT: 4: [B2.3] (ImplicitCastExpr, PointerToBoolean, _Bool)
+ // CHECK-NEXT: T: if [B2.4]
+ // CHECK-NEXT: Preds (1): B3
+ // CHECK-NEXT: Succs (2): B1 B0
+ // CHECK: [B0 (EXIT)]
+ // CHECK-NEXT: Preds (2): B1 B2
+ ~A() {
+ if (p)
+ *p = 0;
+ }
+ // CHECK: [B2 (ENTRY)]
+ // CHECK-NEXT: Succs (1): B1
+ // CHECK: [B1]
+ // CHECK-NEXT: 1: 1
+ // CHECK-NEXT: 2: return [B1.1];
+ // CHECK-NEXT: Preds (1): B2
+ // CHECK-NEXT: Succs (1): B0
+ // CHECK: [B0 (EXIT)]
+ // CHECK-NEXT: Preds (1): B1
+ operator int() const { return 1; }
+ int *p;
+};
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: const A &b = a;
+// CHECK-NEXT: 6: A() (CXXConstructExpr, class A)
+// CHECK-NEXT: 7: [B1.6] (BindTemporary)
+// CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B1.8]
+// CHECK-NEXT: 10: const A &c = A();
+// CHECK-NEXT: 11: [B1.10] (Lifetime ends)
+// CHECK-NEXT: 12: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 13: [B1.5] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_const_ref() {
+ A a;
+ const A &b = a;
+ const A &c = A();
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A [2])
+// CHECK-NEXT: 2: A a[2];
+// CHECK-NEXT: 3: (CXXConstructExpr, class A [0])
+// CHECK-NEXT: 4: A b[0];
+// lifetime of a ends when its destructors are run
+// CHECK-NEXT: 5: [B1.2] (Lifetime ends)
+// lifetime of b ends when its storage duration ends
+// CHECK-NEXT: 6: [B1.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_array() {
+ A a[2];
+ A b[0];
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A c;
+// CHECK-NEXT: 5: (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A d;
+// CHECK-NEXT: 7: [B1.6] (Lifetime ends)
+// CHECK-NEXT: 8: [B1.4] (Lifetime ends)
+// CHECK-NEXT: 9: (CXXConstructExpr, class A)
+// CHECK-NEXT: 10: A b;
+// CHECK-NEXT: 11: [B1.10] (Lifetime ends)
+// CHECK-NEXT: 12: [B1.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_scope() {
+ A a;
+ {
+ A c;
+ A d;
+ }
+ A b;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B3.4] (Lifetime ends)
+// CHECK-NEXT: 5: [B3.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B3.4] (Lifetime ends)
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b;
+// CHECK-NEXT: 5: UV
+// CHECK-NEXT: 6: [B3.5] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B3.6]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (2): B2 B1
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B2
+void test_return() {
+ A a;
+ A b;
+ if (UV)
+ return;
+ A c;
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.6] (Lifetime ends)
+// CHECK-NEXT: 2: [B4.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B4]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: [B4.4] (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A b = a;
+// CHECK-NEXT: 7: b
+// CHECK-NEXT: 8: [B4.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B4.8].operator int
+// CHECK-NEXT: 10: [B4.8]
+// CHECK-NEXT: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 12: [B4.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B4.12]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B3 B2
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_if_implicit_scope() {
+ A a;
+ if (A b = a)
+ A c;
+ else
+ A c;
+}
+
+// CHECK: [B9 (ENTRY)]
+// CHECK-NEXT: Succs (1): B8
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B8.6] (Lifetime ends)
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: A e;
+// CHECK-NEXT: 4: [B1.3] (Lifetime ends)
+// CHECK-NEXT: 5: [B8.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B4.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B4.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B8.6] (Lifetime ends)
+// CHECK-NEXT: 4: [B8.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B4]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B4.4]
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (2): B3 B2
+// CHECK: [B5]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B5.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B7.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B6]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B7.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B8.6] (Lifetime ends)
+// CHECK-NEXT: 4: [B8.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B7]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B7.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.4]
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B8.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: [B8.4] (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A b = a;
+// CHECK-NEXT: 7: b
+// CHECK-NEXT: 8: [B8.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B8.8].operator int
+// CHECK-NEXT: 10: [B8.8]
+// CHECK-NEXT: 11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 12: [B8.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B8.12]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B7 B4
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (3): B1 B3 B6
+void test_if_jumps() {
+ A a;
+ if (A b = a) {
+ A c;
+ if (UV)
+ return;
+ A d;
+ } else {
+ A c;
+ if (UV)
+ return;
+ A d;
+ }
+ A e;
+}
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.4] (Lifetime ends)
+// CHECK-NEXT: 2: [B5.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B4.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: a
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B4.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b = a;
+// CHECK-NEXT: 5: b
+// CHECK-NEXT: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B4.6].operator int
+// CHECK-NEXT: 8: [B4.6]
+// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: while [B4.10]
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 B1
+// CHECK: [B5]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_while_implicit_scope() {
+ A a;
+ while (A b = a)
+ A c;
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: A e;
+// CHECK-NEXT: 4: [B1.3] (Lifetime ends)
+// CHECK-NEXT: 5: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B8 B10
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (2): B3 B6
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 5: [B10.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 4: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B5]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B5.2]
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (2): B4 B3
+// CHECK: [B6]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 2: [B10.4] (Lifetime ends)
+// CHECK-NEXT: T: continue;
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B7]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.2]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B9]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (2): B8 B7
+// CHECK: [B10]
+// CHECK-NEXT: 1: a
+// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B10.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b = a;
+// CHECK-NEXT: 5: b
+// CHECK-NEXT: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B10.6].operator int
+// CHECK-NEXT: 8: [B10.6]
+// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: while [B10.10]
+// CHECK-NEXT: Preds (2): B2 B11
+// CHECK-NEXT: Succs (2): B9 B1
+// CHECK: [B11]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B4
+void test_while_jumps() {
+ A a;
+ while (A b = a) {
+ A c;
+ if (UV)
+ break;
+ if (UV)
+ continue;
+ if (UV)
+ return;
+ A d;
+ }
+ A e;
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B8 B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: do ... while [B2.2]
+// CHECK-NEXT: Preds (2): B3 B6
+// CHECK-NEXT: Succs (2): B10 B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B9.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B5]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B5.2]
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (2): B4 B3
+// CHECK: [B6]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: continue;
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B7]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.2]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B9]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A b;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (2): B10 B11
+// CHECK-NEXT: Succs (2): B8 B7
+// CHECK: [B10]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B9
+// CHECK: [B11]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B9
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B4
+void test_do_jumps() {
+ A a;
+ do {
+ A b;
+ if (UV)
+ break;
+ if (UV)
+ continue;
+ if (UV)
+ return;
+ A c;
+ } while (UV);
+ A d;
+}
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.4] (Lifetime ends)
+// CHECK-NEXT: 2: [B5.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B4.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: a
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B4.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b = a;
+// CHECK-NEXT: 5: b
+// CHECK-NEXT: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B4.6].operator int
+// CHECK-NEXT: 8: [B4.6]
+// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: for (...; [B4.10]; )
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 B1
+// CHECK: [B5]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_for_implicit_scope() {
+ for (A a; A b = a;)
+ A c;
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 2: [B11.4] (Lifetime ends)
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A f;
+// CHECK-NEXT: 5: [B1.4] (Lifetime ends)
+// CHECK-NEXT: 6: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B8 B10
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (2): B3 B6
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A e;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 5: [B10.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 4: [B11.4] (Lifetime ends)
+// CHECK-NEXT: 5: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B5]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B5.2]
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (2): B4 B3
+// CHECK: [B6]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: continue;
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B7]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.2]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B9]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (2): B8 B7
+// CHECK: [B10]
+// CHECK-NEXT: 1: b
+// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B10.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A c = b;
+// CHECK-NEXT: 5: c
+// CHECK-NEXT: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B10.6].operator int
+// CHECK-NEXT: 8: [B10.6]
+// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: for (...; [B10.10]; )
+// CHECK-NEXT: Preds (2): B2 B11
+// CHECK-NEXT: Succs (2): B9 B1
+// CHECK: [B11]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B4
+void test_for_jumps() {
+ A a;
+ for (A b; A c = b;) {
+ A d;
+ if (UV)
+ break;
+ if (UV)
+ continue;
+ if (UV)
+ return;
+ A e;
+ }
+ A f;
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: int n;
+// CHECK-NEXT: 4: n
+// CHECK-NEXT: 5: &[B1.4]
+// CHECK-NEXT: 6: a
+// CHECK-NEXT: 7: [B1.6].p
+// CHECK-NEXT: 8: [B1.7] = [B1.5]
+// CHECK-NEXT: 9: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 10: [B1.3] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_trivial_vs_non_trivial_order() {
+ A a;
+ int n;
+ a.p = &n;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: a:
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: i
+// CHECK-NEXT: 3: [B1.2] = [B1.1]
+// CHECK-NEXT: 4: [B2.1] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: T: goto a;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void goto_past_declaration() {
+ goto a;
+ int i;
+a:
+ i = 1;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: a:
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: k
+// CHECK-NEXT: 3: [B1.2] = [B1.1]
+// CHECK-NEXT: 4: [B2.4] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: int j;
+// CHECK-NEXT: 2: [B2.1] (Lifetime ends)
+// CHECK-NEXT: 3: [B3.1] (Lifetime ends)
+// CHECK-NEXT: 4: int k;
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: 2: [B3.1] (Lifetime ends)
+// CHECK-NEXT: T: goto a;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void goto_past_declaration2() {
+ {
+ int i;
+ goto a;
+ int j;
+ }
+ {
+ int k;
+ a:
+ k = 1;
+ }
+}
+
+struct B {
+ ~B();
+};
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B1.1]++
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B3.1] (Lifetime ends)
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: label:
+// CHECK-NEXT: 1: (CXXConstructExpr, struct B)
+// CHECK-NEXT: 2: B b;
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: T: goto label;
+// CHECK-NEXT: Preds (2): B3 B2
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B3]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+int backpatched_goto() {
+ int i;
+label:
+ B b;
+ goto label;
+ i++;
+}
diff --git a/test/Analysis/lit.local.cfg b/test/Analysis/lit.local.cfg
index acae2bdcd4..a594c5dada 100644
--- a/test/Analysis/lit.local.cfg
+++ b/test/Analysis/lit.local.cfg
@@ -1,30 +1,13 @@
-import lit.TestRunner
-import sys
+# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
-# Custom format class for static analyzer tests
-class AnalyzerTest(lit.formats.ShTest, object):
+import site
- def execute(self, test, litConfig):
- result = self.executeWithAnalyzeSubstitution(test, litConfig, '-analyzer-constraints=range')
-
- if result.code == lit.Test.FAIL:
- return result
-
- 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
-
-# This results in a pickling-related failure on Windows
-if (not sys.platform in ['win32']):
- config.test_format = AnalyzerTest(config.test_format.execute_external)
-else:
- config.substitutions.append(('%analyze', '-analyzer-constraints=range'))
+# 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/localization-aggressive.m b/test/Analysis/localization-aggressive.m
index 346cf3ef22..ea5e0b1529 100644
--- a/test/Analysis/localization-aggressive.m
+++ b/test/Analysis/localization-aggressive.m
@@ -61,8 +61,16 @@ int random();
NSString *CFNumberFormatterCreateStringWithNumber(float x);
+ (NSString *)forceLocalized:(NSString *)str
__attribute__((annotate("returns_localized_nsstring")));
++ (NSString *)takesLocalizedString:
+ (NSString *)__attribute__((annotate("takes_localized_nsstring")))str;
@end
+NSString *
+takesLocalizedString(NSString *str
+ __attribute__((annotate("takes_localized_nsstring")))) {
+ return str;
+}
+
// Test cases begin here
@implementation LocalizationTestSuite
@@ -75,6 +83,8 @@ NSString *ForceLocalized(NSString *str) { return str; }
return str;
}
++ (NSString *) takesLocalizedString:(NSString *)str { return str; }
+
// An ObjC method that returns a localized string
+ (NSString *)unLocalizedStringMethod {
return @"UnlocalizedString";
@@ -269,4 +279,13 @@ NSString *ForceLocalized(NSString *str) { return str; }
NSString *string2 = POSSIBLE_FALSE_POSITIVE(@"Hello", @"Hello"); // no-warning
}
+- (void)testTakesLocalizedString {
+ NSString *localized = NSLocalizedString(@"Hello", @"World");
+ NSString *alsoLocalized = [LocalizationTestSuite takesLocalizedString:localized]; // no-warning
+ NSString *stillLocalized = [LocalizationTestSuite takesLocalizedString:alsoLocalized]; // no-warning
+ takesLocalizedString(stillLocalized); // no-warning
+
+ [LocalizationTestSuite takesLocalizedString:@"not localized"]; // expected-warning {{User-facing text should use localized string macro}}
+ takesLocalizedString(@"not localized"); // expected-warning {{User-facing text should use localized string macro}}
+}
@end
diff --git a/test/Analysis/loop-unrolling.cpp b/test/Analysis/loop-unrolling.cpp
new file mode 100644
index 0000000000..844d1f18ea
--- /dev/null
+++ b/test/Analysis/loop-unrolling.cpp
@@ -0,0 +1,381 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config unroll-loops=true,cfg-loopexit=true -verify -std=c++11 %s
+
+void clang_analyzer_numTimesReached();
+void clang_analyzer_warnIfReached();
+
+int getNum();
+void foo(int &);
+
+int simple_unroll1() {
+ int a[9];
+ int k = 42;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_unroll2() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ a[i] = 42;
+ }
+
+ for (int j = 0; j <= 9; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ a[j] = 42;
+ }
+
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_no_unroll1() {
+ int a[9];
+ int k = 42;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ foo(i);
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_no_unroll2() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ i += getNum();
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_no_unroll3() {
+ int a[9];
+ int k = 42;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ (void)&i;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int simple_no_unroll4() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ int &j = i;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int simple_no_unroll5() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ int &j{i};
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int make_new_branches_loop_cached() {
+ for (int i = 0; i < 8; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ if(getNum()){
+ (void) i; // Since this Stmt does not change the State the analyzer
+ // won't make a new execution path but reuse the earlier nodes.
+ }
+ }
+ clang_analyzer_warnIfReached(); // no-warning
+ return 0;
+}
+
+int make_new_branches_loop_uncached() {
+ int l = 2;
+ for (int i = 0; i < 8; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ if(getNum()){
+ ++l;
+ }
+ }
+ clang_analyzer_warnIfReached(); // no-warning
+ return 0;
+}
+
+int make_new_branches_loop_uncached2() {
+ int l = 2;
+ for (int i = 0; i < 8; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ if(getNum()){
+ ++l;
+ }
+ (void)&i; // This ensures that the loop won't be unrolled.
+ }
+ clang_analyzer_warnIfReached(); // no-warning
+ return 0;
+}
+
+
+int escape_before_loop_no_unroll1() {
+ int a[9];
+ int k = 42;
+ int i;
+ int &j = i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int escape_before_loop_no_unroll2() {
+ int a[9];
+ int k = 42;
+ int i;
+ int *p = &i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int escape_before_loop_no_unroll3() {
+ int a[9];
+ int k = 42;
+ int i;
+ foo(i);
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int nested_outer_unrolled() {
+ int a[9];
+ int k = 42;
+ int j = 0;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (j = 0; j < 9; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[j] = 22;
+ (void) &j; // ensures that the inner loop won't be unrolled
+ }
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int nested_inner_unrolled() {
+ int a[9];
+ int k = 42;
+ int j = 0;
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ for (j = 0; j < 8; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{32}}
+ a[j] = 22;
+ }
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int nested_both_unrolled() {
+ int a[9];
+ int k = 42;
+ int j = 0;
+ for (int i = 0; i < 7; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{7}}
+ for (j = 0; j < 6; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{42}}
+ a[j] = 22;
+ }
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_known_bound_loop() {
+ for (int i = 2; i < 12; i++) {
+ // This function is inlined in nested_inlined_unroll1()
+ clang_analyzer_numTimesReached(); // expected-warning {{90}}
+ }
+ return 0;
+}
+
+int simple_unknown_bound_loop() {
+ for (int i = 2; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ }
+ return 0;
+}
+
+int nested_inlined_unroll1() {
+ int k;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ k = simple_known_bound_loop(); // no reevaluation without inlining
+ }
+ int a = 22 / k; // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int nested_inlined_no_unroll1() {
+ int k;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{15}}
+ k = simple_unknown_bound_loop(); // reevaluation without inlining, splits the state as well
+ }
+ int a = 22 / k; // no-warning
+ return 0;
+}
+
+int recursion_unroll1(bool b) {
+ int k = 2;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{13}}
+ if(i == 0 && b) // Splits the state in the first iteration but the recursion
+ // call will be unrolled anyway since the condition is known there.
+ recursion_unroll1(false);
+ clang_analyzer_numTimesReached(); // expected-warning {{14}}
+ }
+ int a = 22 / k; // no-warning
+ return 0;
+}
+
+int recursion_unroll2(bool b) {
+ int k = 0;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ if(i == 0 && b)
+ recursion_unroll2(false);
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ }
+ int a = 22 / k; // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int recursion_unroll3(bool b) {
+ int k = 2;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ if (i == 4 && b) {
+ recursion_unroll3(false);
+ break;
+ }
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ }
+ int a = 22 / k;
+ return 0;
+}
+
+int recursion_unroll4(bool b) {
+ int k = 2;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{13}}
+ if(i == 0 && b) {
+ recursion_unroll4(false);
+ continue;
+ }
+ clang_analyzer_numTimesReached(); // expected-warning {{13}}
+ }
+ int a = 22 / k;
+ return 0;
+}
+
+int loop_exit_while_empty_loop_stack() {
+ if (getNum())
+ for (int i = 1; i < 8; i++)
+ ;
+ return 0;
+}
+
+int num_steps_on_limit() {
+ for (int i = 0; i < 128; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ return 0;
+}
+
+int num_steps_over_limit1() {
+ for (int i = 0; i < 129; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ return 0;
+}
+
+int num_steps_on_limit2() {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 64; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_over_limit2() {
+ for (int i = 0; i < 2; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (int j = 0; j <= 64; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_on_limit3() {
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ for (int j = 0; j < 32; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_over_limit3() {
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (int j = 0; j < 33; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ }
+ return 0;
+}
+
+
+void pr34943() {
+ for (int i = 0; i < 6L; ++i) {
+ clang_analyzer_numTimesReached(); // expected-warning {{6}}
+ }
+}
diff --git a/test/Analysis/loopexit-cfg-output.cpp b/test/Analysis/loopexit-cfg-output.cpp
new file mode 100644
index 0000000000..8e53ce3066
--- /dev/null
+++ b/test/Analysis/loopexit-cfg-output.cpp
@@ -0,0 +1,476 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-loopexit=true %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: 2: return;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B2.1]++
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B3.1]++
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 12
+// CHECK-NEXT: 4: [B4.2] < [B4.3]
+// CHECK-NEXT: T: for (...; [B4.4]; ...)
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 B1
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: 0
+// CHECK-NEXT: 2: int i = 0;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_forloop1() {
+ for (int i = 0; i < 12; i++) {
+ i++;
+ }
+ return;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: T: for (; ; )
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): B2 NULL
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_forloop2() {
+ for (;;)
+ ;
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: true
+// CHECK-NEXT: T: while [B4.1]
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 NULL
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while1() {
+ while (true) {
+ int i;
+ }
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: 2: 2
+// CHECK-NEXT: 3: int k = 2;
+// CHECK-NEXT: 4: return;
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: l
+// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 42
+// CHECK-NEXT: 4: [B3.2] < [B3.3]
+// CHECK-NEXT: T: while [B3.4]
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): B2 B1
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: int l;
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while2() {
+ int l;
+ while (l < 42)
+ ;
+ int k = 2;
+ return;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: false
+// CHECK-NEXT: T: while [B3.1]
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): NULL B1
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while3() {
+ while (false) {
+ ;
+ }
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: false
+// CHECK-NEXT: T: do ... while [B2.1]
+// CHECK-NEXT: Preds (2): B3 B4
+// CHECK-NEXT: Succs (2): NULL B1
+
+// CHECK: [B3]
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_dowhile1() {
+ do {
+ } while (false);
+}
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: 2: j
+// CHECK-NEXT: 3: [B1.2]--
+// CHECK-NEXT: 4: return;
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 20
+// CHECK-NEXT: 4: [B2.2] < [B2.3]
+// CHECK-NEXT: T: do ... while [B2.4]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (2): B4 B1
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: 2
+// CHECK-NEXT: 3: [B3.1] += [B3.2]
+// CHECK-NEXT: Preds (2): B4 B5
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: 2
+// CHECK-NEXT: 2: int j = 2;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_dowhile2() {
+ int j = 2;
+ do {
+ j += 2;
+ } while (j < 20);
+ j--;
+ return;
+}
+
+// CHECK: [B10 (ENTRY)]
+// CHECK-NEXT: Succs (1): B9
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B4.1]++
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1]++
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B6]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B6.2] < [B6.3]
+// CHECK-NEXT: T: for (...; [B6.4]; ...)
+// CHECK-NEXT: Preds (2): B4 B7
+// CHECK-NEXT: Succs (2): B5 B3
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: int j = 1;
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B8]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B8.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 2
+// CHECK-NEXT: 4: [B8.2] < [B8.3]
+// CHECK-NEXT: T: while [B8.4]
+// CHECK-NEXT: Preds (2): B2 B9
+// CHECK-NEXT: Succs (2): B7 B1
+
+// CHECK: [B9]
+// CHECK-NEXT: 1: 40
+// CHECK-NEXT: 2: -[B9.1]
+// CHECK-NEXT: 3: int i = -40;
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void nested_loops1() {
+ int i = -40;
+ while (i < 2) {
+ for (int j = 1; j < 6; j++)
+ i++;
+ }
+}
+
+// CHECK: [B9 (ENTRY)]
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B2.1]++
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B7
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: 2: i
+// CHECK-NEXT: 3: [B3.2]--
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 2
+// CHECK-NEXT: 4: [B4.2] < [B4.3]
+// CHECK-NEXT: T: do ... while [B4.4]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B6 B3
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1]++
+// CHECK-NEXT: Preds (2): B6 B7
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B6]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B7.2] < [B7.3]
+// CHECK-NEXT: T: for (...; [B7.4]; ...)
+// CHECK-NEXT: Preds (2): B2 B8
+// CHECK-NEXT: Succs (2): B5 B1
+
+// CHECK: [B8]
+// CHECK-NEXT: 1: 40
+// CHECK-NEXT: 2: -[B8.1]
+// CHECK-NEXT: 3: int i = -40;
+// CHECK-NEXT: 4: 1
+// CHECK-NEXT: 5: int j = 1;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B7
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void nested_loops2() {
+ int i = -40;
+ for (int j = 1; j < 6; j++) {
+ do {
+ i++;
+ } while (i < 2);
+ i--;
+ }
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: 2: return;
+// CHECK-NEXT: Preds (2): B3 B5
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B3]
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1]++
+// CHECK-NEXT: 3: i
+// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 5: 2
+// CHECK-NEXT: 6: [B4.4] % [B4.5]
+// CHECK-NEXT: 7: [B4.6] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B4.7]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B3 B2
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 5
+// CHECK-NEXT: 4: [B5.2] < [B5.3]
+// CHECK-NEXT: T: while [B5.4]
+// CHECK-NEXT: Preds (2): B2 B6
+// CHECK-NEXT: Succs (2): B4 B1
+
+// CHECK: [B6]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: 2: 1
+// CHECK-NEXT: 3: int i = 1;
+// CHECK-NEXT: Preds (2): B8 B10
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B7.1]++
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B10
+
+// CHECK: [B8]
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B9]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 4
+// CHECK-NEXT: 4: [B9.2] == [B9.3]
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (2): B8 B7
+
+// CHECK: [B10]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B10.2] < [B10.3]
+// CHECK-NEXT: T: for (...; [B10.4]; ...)
+// CHECK-NEXT: Preds (2): B7 B11
+// CHECK-NEXT: Succs (2): B9 B6
+
+// CHECK: [B11]
+// CHECK-NEXT: 1: 2
+// CHECK-NEXT: 2: int i = 2;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B10
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_break()
+{
+ for(int i = 2; i < 6; i++) {
+ if(i == 4)
+ break;
+ }
+
+ int i = 1;
+ while(i<5){
+ i++;
+ if(i%2)
+ break;
+ }
+
+ return;
+}
diff --git a/test/Analysis/malloc-overflow2.c b/test/Analysis/malloc-overflow2.c
index 2e1b1d4d2b..7c580602e6 100644
--- a/test/Analysis/malloc-overflow2.c
+++ b/test/Analysis/malloc-overflow2.c
@@ -1,4 +1,5 @@
// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -analyzer-checker=alpha.security.MallocOverflow,unix -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -analyzer-checker=alpha.security.MallocOverflow,unix,optin.portability -DPORTABILITY -verify %s
typedef __typeof__(sizeof(int)) size_t;
extern void *malloc(size_t);
@@ -32,5 +33,8 @@ static int table_build_1(struct table *t) {
}
void *f(int n) {
- return malloc(n * 0 * sizeof(int)); // expected-warning {{Call to 'malloc' has an allocation size of 0 bytes}}
+ return malloc(n * 0 * sizeof(int));
+#ifdef PORTABILITY
+ // expected-warning@-2{{Call to 'malloc' has an allocation size of 0 bytes}}
+#endif
}
diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c
index 26aea16045..e2062e8582 100644
--- a/test/Analysis/malloc-plist.c
+++ b/test/Analysis/malloc-plist.c
@@ -421,7 +421,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;p&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -586,7 +586,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;A&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -974,7 +974,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -1376,7 +1376,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -1962,7 +1962,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Use of memory after it is freed</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Use-after-free</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -2524,7 +2524,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -2795,7 +2795,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;v&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3144,7 +3144,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Use of memory after it is freed</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Use-after-free</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3309,7 +3309,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;m&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3517,7 +3517,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3725,7 +3725,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4030,7 +4030,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4335,7 +4335,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4543,7 +4543,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4751,7 +4751,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4988,7 +4988,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential memory leak</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -5225,7 +5225,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential memory leak</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -5496,7 +5496,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential memory leak</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index d5f2cfedd1..4c364ebd9a 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1774,6 +1774,16 @@ int testNoCheckerDataPropogationFromLogicalOpOperandToOpResult(void) {
return ok; // no warning
}
+void (*fnptr)(int);
+void freeIndirectFunctionPtr() {
+ void *p = (void *)fnptr;
+ free(p); // expected-warning {{Argument to free() is a function pointer}}
+}
+
+void freeFunctionPtr() {
+ free((void *)fnptr); // expected-warning {{Argument to free() is a function pointer}}
+}
+
// ----------------------------------------------------------------------------
// False negatives.
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
index f8a43b3b6a..e3daa858be 100644
--- a/test/Analysis/malloc.mm
+++ b/test/Analysis/malloc.mm
@@ -187,7 +187,7 @@ typedef volatile struct {
void *opaque1;
long opaque2;
} OSQueueHead;
-void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
+extern "C" void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
static inline void radar11111210(OSQueueHead *pool) {
void *newItem = malloc(4);
OSAtomicEnqueue(pool, newItem, 4);
diff --git a/test/Analysis/max-nodes-suppress-on-sink.c b/test/Analysis/max-nodes-suppress-on-sink.c
index 8d955b91c1..da1e7bf022 100644
--- a/test/Analysis/max-nodes-suppress-on-sink.c
+++ b/test/Analysis/max-nodes-suppress-on-sink.c
@@ -15,6 +15,8 @@ extern void exit(int) __attribute__ ((__noreturn__));
void clang_analyzer_warnIfReached(void);
+int coin();
+
void test_single_cfg_block_sink() {
void *p = malloc(1); // no-warning (wherever the leak warning may occur here)
@@ -29,3 +31,53 @@ void test_single_cfg_block_sink() {
// the leak report.
exit(0);
}
+
+// A similar test with more complicated control flow before the no-return thing,
+// so that the no-return thing wasn't in the same CFG block.
+void test_more_complex_control_flow_before_sink() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ if (coin())
+ exit(0);
+ else
+ exit(1);
+}
+
+// A loop before the no-return function, to make sure that
+// the dominated-by-sink analysis doesn't hang.
+void test_loop_before_sink(int n) {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ for (int i = 0; i < n; ++i) {
+ }
+ exit(1);
+}
+
+// We're not sure if this is no-return.
+void test_loop_with_sink(int n) {
+ void *p = malloc(1); // expected-warning@+2{{Potential leak of memory}}
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ for (int i = 0; i < n; ++i)
+ if (i == 0)
+ exit(1);
+}
+
+// Handle unreachable blocks correctly.
+void test_unreachable_successor_blocks() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ if (1) // no-crash
+ exit(1);
+}
diff --git a/test/Analysis/max-nodes-suppress-on-sink.cpp b/test/Analysis/max-nodes-suppress-on-sink.cpp
new file mode 100644
index 0000000000..814b302789
--- /dev/null
+++ b/test/Analysis/max-nodes-suppress-on-sink.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_analyze_cc1 -x c++ -fcxx-exceptions -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. See comments in max-nodes-suppress-on-sink.c
+// for more discussion.
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+void clang_analyzer_warnIfReached(void);
+
+// Because we don't have a better approach, we currently treat throw as
+// noreturn.
+void test_throw_treated_as_noreturn() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ throw 0;
+}
+
+// FIXME: Handled throws shouldn't be suppressing us!
+void test_handled_throw_treated_as_noreturn() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ try {
+ throw 0;
+ } catch (int i) {
+ }
+}
diff --git a/test/Analysis/nonnull-global-constants.mm b/test/Analysis/nonnull-global-constants.mm
new file mode 100644
index 0000000000..7900b9dd12
--- /dev/null
+++ b/test/Analysis/nonnull-global-constants.mm
@@ -0,0 +1,103 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+
+// Nullability of const string-like globals, testing
+// NonnullGlobalConstantsChecker.
+
+void clang_analyzer_eval(bool);
+
+@class NSString;
+typedef const struct __CFString *CFStringRef;
+typedef const struct __CFBoolean * CFBooleanRef;
+
+// Global NSString* is non-null.
+extern NSString *const StringConstGlobal;
+void stringConstGlobal() {
+ clang_analyzer_eval(StringConstGlobal); // expected-warning{{TRUE}}
+}
+
+// The logic does not apply to local variables though.
+extern NSString *stringGetter();
+void stringConstLocal() {
+ NSString *const local = stringGetter();
+ clang_analyzer_eval(local); // expected-warning{{UNKNOWN}}
+}
+
+// Global const CFStringRef's are also assumed to be non-null.
+extern const CFStringRef CFStringConstGlobal;
+void cfStringCheckGlobal() {
+ clang_analyzer_eval(CFStringConstGlobal); // expected-warning{{TRUE}}
+}
+
+// But only "const" ones.
+extern CFStringRef CFStringNonConstGlobal;
+void cfStringCheckMutableGlobal() {
+ clang_analyzer_eval(CFStringNonConstGlobal); // expected-warning{{UNKNOWN}}
+}
+
+// char* const is also assumed to be non-null.
+extern const char *const ConstCharStarConst;
+void constCharStarCheckGlobal() {
+ clang_analyzer_eval(ConstCharStarConst); // expected-warning{{TRUE}}
+}
+
+// Pointer value can be mutable.
+extern char *const CharStarConst;
+void charStarCheckGlobal() {
+ clang_analyzer_eval(CharStarConst); // expected-warning{{TRUE}}
+}
+
+// But the pointer itself should be immutable.
+extern char *CharStar;
+void charStartCheckMutableGlobal() {
+ clang_analyzer_eval(CharStar); // expected-warning{{UNKNOWN}}
+}
+
+// Type definitions should also work across typedefs, for pointers:
+typedef char *const str;
+extern str globalStr;
+void charStarCheckTypedef() {
+ clang_analyzer_eval(globalStr); // expected-warning{{TRUE}}
+}
+
+// And for types.
+typedef NSString *const NStr;
+extern NStr globalNSString;
+void NSStringCheckTypedef() {
+ clang_analyzer_eval(globalNSString); // expected-warning{{TRUE}}
+}
+
+// Note that constness could be either inside
+// the var declaration, or in a typedef.
+typedef NSString *NStr2;
+extern const NStr2 globalNSString2;
+void NSStringCheckConstTypedef() {
+ clang_analyzer_eval(globalNSString2); // expected-warning{{TRUE}}
+}
+
+// Nested typedefs should work as well.
+typedef const CFStringRef str1;
+typedef str1 str2;
+extern str2 globalStr2;
+void testNestedTypedefs() {
+ clang_analyzer_eval(globalStr2); // expected-warning{{TRUE}}
+}
+
+// And for NSString *.
+typedef NSString *const nstr1;
+typedef nstr1 nstr2;
+extern nstr2 nglobalStr2;
+void testNestedTypedefsForNSString() {
+ clang_analyzer_eval(nglobalStr2); // expected-warning{{TRUE}}
+}
+
+// And for CFBooleanRefs.
+extern const CFBooleanRef kBool;
+void testNonnullBool() {
+ clang_analyzer_eval(kBool); // expected-warning{{TRUE}}
+}
+
+// And again, only for const one.
+extern CFBooleanRef kBoolMutable;
+void testNonnullNonconstBool() {
+ clang_analyzer_eval(kBoolMutable); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/null-deref-offsets.c b/test/Analysis/null-deref-offsets.c
new file mode 100644
index 0000000000..988cec4985
--- /dev/null
+++ b/test/Analysis/null-deref-offsets.c
@@ -0,0 +1,37 @@
+// RUN: %clang_analyze_cc1 -w -triple i386-apple-darwin10 -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+struct S {
+ int x, y;
+ int z[2];
+};
+
+void testOffsets(struct S *s, int coin) {
+ if (s != 0)
+ return;
+
+ // FIXME: Here we are testing the hack that computes offsets to null pointers
+ // as 0 in order to find null dereferences of not-exactly-null pointers,
+ // such as &(s->y) below, which is equal to 4 rather than 0 in run-time.
+
+ // These are indeed null.
+ clang_analyzer_eval(s == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&(s->x) == 0); // expected-warning{{TRUE}}
+
+ // FIXME: These should ideally be true.
+ clang_analyzer_eval(&(s->y) == 4); // expected-warning{{FALSE}}
+ clang_analyzer_eval(&(s->z[0]) == 8); // expected-warning{{FALSE}}
+ clang_analyzer_eval(&(s->z[1]) == 12); // expected-warning{{FALSE}}
+
+ // FIXME: These should ideally be false.
+ clang_analyzer_eval(&(s->y) == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&(s->z[0]) == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&(s->z[1]) == 0); // expected-warning{{TRUE}}
+
+ // But these should still be reported as null dereferences.
+ if (coin)
+ s->y = 5; // expected-warning{{Access to field 'y' results in a dereference of a null pointer (loaded from variable 's')}}
+ else
+ s->z[1] = 6; // expected-warning{{Array access (via field 'z') results in a null pointer dereference}}
+}
diff --git a/test/Analysis/null-deref-path-notes.c b/test/Analysis/null-deref-path-notes.c
new file mode 100644
index 0000000000..a1477a6226
--- /dev/null
+++ b/test/Analysis/null-deref-path-notes.c
@@ -0,0 +1,9 @@
+// RUN: %clang_analyze_cc1 -w -x c -analyzer-checker=core -analyzer-output=text -verify %s
+
+// Avoid the crash when finding the expression for tracking the origins
+// of the null pointer for path notes.
+void pr34373() {
+ int *a = 0; // expected-note{{'a' initialized to a null pointer value}}
+ (a + 0)[0]; // expected-warning{{Array access results in a null pointer dereference}}
+ // expected-note@-1{{Array access results in a null pointer dereference}}
+}
diff --git a/test/Analysis/null-deref-path-notes.cpp b/test/Analysis/null-deref-path-notes.cpp
new file mode 100644
index 0000000000..617f5def15
--- /dev/null
+++ b/test/Analysis/null-deref-path-notes.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -w -x c++ -analyzer-checker=core -analyzer-output=text -analyzer-eagerly-assume -verify %s
+
+namespace pr34731 {
+int b;
+class c {
+ class B {
+ public:
+ double ***d;
+ B();
+ };
+ void e(double **, int);
+ void f(B &, int &);
+};
+
+// Properly track the null pointer in the array field back to the default
+// constructor of 'h'.
+void c::f(B &g, int &i) {
+ e(g.d[9], i); // expected-warning{{Array access (via field 'd') results in a null pointer dereference}}
+ // expected-note@-1{{Array access (via field 'd') results in a null pointer dereference}}
+ B h, a; // expected-note{{Value assigned to 'h.d'}}
+ a.d == __null; // expected-note{{Assuming the condition is true}}
+ a.d != h.d; // expected-note{{Assuming pointer value is null}}
+ f(h, b); // expected-note{{Calling 'c::f'}}
+}
+}
diff --git a/test/Analysis/null-deref-path-notes.m b/test/Analysis/null-deref-path-notes.m
index 242b5daa9b..39cf9c79f3 100644
--- a/test/Analysis/null-deref-path-notes.m
+++ b/test/Analysis/null-deref-path-notes.m
@@ -50,6 +50,23 @@ void repeatedStores(int coin) {
*p = 1; // expected-warning{{Dereference of null pointer}} expected-note{{Dereference of null pointer}}
}
+@interface WithArrayPtr
+- (void) useArray;
+@end
+
+@implementation WithArrayPtr {
+@public int *p;
+}
+- (void)useArray {
+ p[1] = 2; // expected-warning{{Array access (via ivar 'p') results in a null pointer dereference}}
+ // expected-note@-1{{Array access (via ivar 'p') results in a null pointer dereference}}
+}
+@end
+
+void testWithArrayPtr(WithArrayPtr *w) {
+ w->p = 0; // expected-note{{Null pointer value stored to 'p'}}
+ [w useArray]; // expected-note{{Calling 'useArray'}}
+}
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
@@ -801,4 +818,227 @@ void repeatedStores(int coin) {
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// 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>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>67</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>67</integer>
+// CHECK-NEXT: <key>col</key><integer>10</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>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&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>67</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>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>68</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>68</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>68</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>68</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>68</integer>
+// CHECK-NEXT: <key>col</key><integer>14</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>Calling &apos;useArray&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;useArray&apos;</string>
+// 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>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testWithArrayPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testWithArrayPtr&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>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</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>61</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>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Array access (via ivar &apos;p&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Array access (via ivar &apos;p&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Array access (via ivar &apos;p&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>check_name</key><string>core.NullDereference</string>
+// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>fb0ad1e4e3090d9834d542eb54bc9d2e</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>useArray</string>
+// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index 6ef99ae473..c46ca6c52a 100644
--- a/test/Analysis/null-deref-ps-region.c
+++ b/test/Analysis/null-deref-ps-region.c
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
-// expected-no-diagnostics
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,unix,alpha.unix -std=gnu99 -analyzer-store=region -verify %s
+#include "Inputs/system-header-simulator.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *memset(void *__s, int __c, size_t __n);
+void *malloc(size_t __size);
+void free(void *__ptr);
// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
// also be live roots.
@@ -13,3 +18,55 @@ void f14(int *a) {
i = *p; // no-warning
}
}
+
+void foo() {
+ int *x = malloc(sizeof(int));
+ memset(x, 0, sizeof(int));
+ int n = 1 / *x; // FIXME: no-warning
+ free(x);
+}
+
+void bar() {
+ int *x = malloc(sizeof(int));
+ memset(x, 0, 1);
+ int n = 1 / *x; // no-warning
+ free(x);
+}
+
+void testConcreteNull() {
+ int *x = 0;
+ memset(x, 0, 1); // expected-warning {{Null pointer argument in call to memory set function}}
+}
+
+void testStackArray() {
+ char buf[13];
+ memset(buf, 0, 1); // no-warning
+}
+
+void testHeapSymbol() {
+ char *buf = (char *)malloc(13);
+ memset(buf, 0, 1); // no-warning
+ free(buf);
+}
+
+void testStackArrayOutOfBound() {
+ char buf[1];
+ memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+}
+
+void testHeapSymbolOutOfBound() {
+ char *buf = (char *)malloc(1);
+ memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+ free(buf);
+}
+
+void testStackArraySameSize() {
+ char buf[1];
+ memset(buf, 0, sizeof(buf)); // no-warning
+}
+
+void testHeapSymbolSameSize() {
+ char *buf = (char *)malloc(1);
+ memset(buf, 0, 1); // no-warning
+ free(buf);
+}
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 5dee308a00..d0e1f9f5cc 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,5 +1,5 @@
-// 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
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -Wno-tautological-constant-compare -Wtautological-unsigned-zero-compare -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 -Wno-tautological-constant-compare -Wtautological-unsigned-zero-compare -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -verify %s -Wno-error=return-type
typedef unsigned uintptr_t;
diff --git a/test/Analysis/nullability-notes.m b/test/Analysis/nullability-notes.m
new file mode 100644
index 0000000000..c93aa02c42
--- /dev/null
+++ b/test/Analysis/nullability-notes.m
@@ -0,0 +1,204 @@
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=plist -analyzer-config path-diagnostics-alternate=true -o %t.plist %s
+// RUN: FileCheck --input-file=%t.plist %s
+
+#include "Inputs/system-header-simulator-for-nullability.h"
+
+void takesNonnull(NSObject *_Nonnull y);
+
+@interface ClassWithProperties: NSObject
+@property(copy, nullable) NSObject *x; // plist check ensures no control flow piece from here to 'self.x'.
+-(void) method;
+@end;
+@implementation ClassWithProperties
+-(void) method {
+ // no-crash
+ NSObject *x = self.x; // expected-note{{Nullability 'nullable' is inferred}}
+ takesNonnull(x); // expected-warning{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+ // expected-note@-1{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+}
+@end
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// 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>16</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>10</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Nullability &apos;nullable&apos; is inferred</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Nullability &apos;nullable&apos; is inferred</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</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>16</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>10</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>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>16</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>16</integer>
+// CHECK-NEXT: <key>col</key><integer>10</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>17</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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>14</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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</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>17</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>16</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>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
+// CHECK-NEXT: <key>type</key><string>Nullability</string>
+// CHECK-NEXT: <key>check_name</key><string>nullability.NullPassedToNonnull</string>
+// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>b6bc8126de8e6eb3375483a656fe858d</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>method</string>
+// CHECK-NEXT: <key>issue_hash_function_offset</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</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: </array>
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index 229ad7bbb5..b3e61c9def 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -1,11 +1,12 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -Wno-conversion-null -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 -analyzer-output=text -verify %s
void clang_analyzer_eval(int);
// test to see if nullptr is detected as a null pointer
void foo1(void) {
- char *np = nullptr;
+ char *np = nullptr; // expected-note{{'np' initialized to a null pointer value}}
*np = 0; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
}
// check if comparing nullptr to nullptr is detected properly
@@ -23,10 +24,11 @@ void foo3(void) {
struct foo {
int a, f;
};
- char *np = nullptr;
+ char *np = nullptr; // expected-note{{'np' initialized to a null pointer value}}
// casting a nullptr to anything should be caught eventually
- int *ip = &(((struct foo *)np)->f);
+ int *ip = &(((struct foo *)np)->f); // expected-note{{'ip' initialized to a null pointer value}}
*ip = 0; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
// should be error here too, but analysis gets stopped
// *np = 0;
}
@@ -49,16 +51,31 @@ int pr10372(void *& x) {
}
void zoo1() {
- char **p = 0;
+ char **p = 0; // expected-note{{'p' initialized to a null pointer value}}
delete *(p + 0); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
+}
+
+void zoo1backwards() {
+ char **p = 0; // expected-note{{'p' initialized to a null pointer value}}
+ delete *(0 + p); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
+}
+
+typedef __INTPTR_TYPE__ intptr_t;
+void zoo1multiply() {
+ char **p = 0; // FIXME-should-be-note:{{'p' initialized to a null pointer value}}
+ delete *((char **)((intptr_t)p * 2)); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
}
void zoo2() {
int **a = 0;
- int **b = 0;
+ int **b = 0; // expected-note{{'b' initialized to a null pointer value}}
asm ("nop"
:"=r"(*a)
:"0"(*b) // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
);
}
@@ -70,17 +87,19 @@ int exprWithCleanups() {
int a;
};
- int *x = 0;
+ int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
return S(*x).a; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
}
int materializeTempExpr() {
- int *n = 0;
+ int *n = 0; // expected-note{{'n' initialized to a null pointer value}}
struct S {
int a;
S(int i): a(i) {}
};
const S &s = S(*n); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
return s.a;
}
@@ -98,6 +117,7 @@ struct X {
void invokeF(X* x) {
x->f(); // expected-warning{{Called C++ object pointer is null}}
+ // expected-note@-1{{Called C++ object pointer is null}}
}
struct Type {
@@ -105,26 +125,41 @@ struct Type {
};
void shouldNotCrash() {
- decltype(nullptr) p;
- if (getSymbol())
- invokeF(p); // expected-warning{{1st function call argument is an uninit}}
- if (getSymbol())
- invokeF(nullptr);
- if (getSymbol()) {
- X *x = Type().x;
+ decltype(nullptr) p; // expected-note{{'p' declared without an initial value}}
+ if (getSymbol()) // expected-note {{Assuming the condition is false}}
+ // expected-note@-1{{Taking false branch}}
+ // expected-note@-2{{Assuming the condition is false}}
+ // expected-note@-3{{Taking false branch}}
+ // expected-note@-4{{Assuming the condition is true}}
+ // expected-note@-5{{Taking true branch}}
+ invokeF(p); // expected-warning{{1st function call argument is an uninitialized value}}
+ // expected-note@-1{{1st function call argument is an uninitialized value}}
+ if (getSymbol()) // expected-note {{Assuming the condition is false}}
+ // expected-note@-1{{Taking false branch}}
+ // expected-note@-2{{Assuming the condition is true}}
+ // expected-note@-3{{Taking true branch}}
+ invokeF(nullptr); // expected-note {{Calling 'invokeF'}}
+ // expected-note@-1{{Passing null pointer value via 1st parameter 'x'}}
+ if (getSymbol()) { // expected-note {{Assuming the condition is true}}
+ // expected-note@-1{{Taking true branch}}
+ X *x = Type().x; // expected-note{{'x' initialized to a null pointer value}}
x->f(); // expected-warning{{Called C++ object pointer is null}}
+ // expected-note@-1{{Called C++ object pointer is null}}
}
}
void f(decltype(nullptr) p) {
int *q = nullptr;
clang_analyzer_eval(p == 0); // expected-warning{{TRUE}}
+ // expected-note@-1{{TRUE}}
clang_analyzer_eval(q == 0); // expected-warning{{TRUE}}
+ // expected-note@-1{{TRUE}}
}
decltype(nullptr) returnsNullPtrType();
void fromReturnType() {
((X *)returnsNullPtrType())->f(); // expected-warning{{Called C++ object pointer is null}}
+ // expected-note@-1{{Called C++ object pointer is null}}
}
#define AS_ATTRIBUTE __attribute__((address_space(256)))
diff --git a/test/Analysis/objc-boxing.m b/test/Analysis/objc-boxing.m
index 963374b3ef..66f24ddf77 100644
--- a/test/Analysis/objc-boxing.m
+++ b/test/Analysis/objc-boxing.m
@@ -5,6 +5,16 @@ void clang_analyzer_eval(int);
typedef signed char BOOL;
typedef long NSInteger;
typedef unsigned long NSUInteger;
+
+@protocol NSObject
+@end
+@interface NSObject <NSObject> {}
+@end
+@protocol NSCopying
+@end
+@protocol NSCoding
+@end
+
@interface NSString @end
@interface NSString (NSStringExtensionMethods)
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
@@ -28,7 +38,15 @@ typedef unsigned long NSUInteger;
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value ;
@end
+@interface NSValue : NSObject <NSCopying, NSCoding>
+- (void)getValue:(void *)value;
++ (NSValue *)valueWithBytes:(const void *)value
+ objCType:(const char *)type;
+@end
+typedef typeof(sizeof(int)) size_t;
+extern void *malloc(size_t);
+extern void free(void *);
extern char *strdup(const char *str);
id constant_string() {
@@ -39,6 +57,23 @@ id dynamic_string() {
return @(strdup("boxed dynamic string")); // expected-warning{{Potential memory leak}}
}
+typedef struct __attribute__((objc_boxable)) {
+ const char *str;
+} BoxableStruct;
+
+id leak_within_boxed_struct() {
+ BoxableStruct bs;
+ bs.str = strdup("dynamic string"); // The duped string shall be owned by val.
+ NSValue *val = @(bs); // no-warning
+ return val;
+}
+
+id leak_of_boxed_struct() {
+ BoxableStruct *bs = malloc(sizeof(BoxableStruct)); // The pointer stored in bs isn't owned by val.
+ NSValue *val = @(*bs); // expected-warning{{Potential leak of memory pointed to by 'bs'}}
+ return val;
+}
+
id const_char_pointer(int *x) {
if (x)
return @(3);
diff --git a/test/Analysis/objc-encode.m b/test/Analysis/objc-encode.m
new file mode 100644
index 0000000000..b2379e96d9
--- /dev/null
+++ b/test/Analysis/objc-encode.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection -verify %s
+// expected-no-diagnostics
+
+void clang_analyzer_eval(int);
+
+// rdar://problem/34831581: Used to crash.
+void foo(void) {
+ char buf1[] = @encode(int **);
+}
diff --git a/test/Analysis/objc-for.m b/test/Analysis/objc-for.m
index 41709bee35..f1d0cf18d6 100644
--- a/test/Analysis/objc-for.m
+++ b/test/Analysis/objc-for.m
@@ -1,6 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
#define nil ((id)0)
@@ -20,11 +21,13 @@ typedef unsigned long NSUInteger;
@interface NSArray : NSObject <NSFastEnumeration>
- (NSUInteger)count;
- (NSEnumerator *)objectEnumerator;
++ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
@end
@interface NSDictionary : NSObject <NSFastEnumeration>
- (NSUInteger)count;
- (id)objectForKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
@end
@interface NSDictionary (SomeCategory)
@@ -324,3 +327,19 @@ void protocolMethods(NSMutableArray *array) {
for (id key in array)
clang_analyzer_eval(0); // expected-warning{{FALSE}}
}
+
+NSArray *globalArray;
+NSDictionary *globalDictionary;
+void boxedArrayEscape(NSMutableArray *array) {
+ if ([array count])
+ return;
+ globalArray = @[array];
+ for (id key in array)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+
+ if ([array count])
+ return;
+ globalDictionary = @{ @"array" : array };
+ for (id key in array)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
diff --git a/test/Analysis/plist-macros.cpp b/test/Analysis/plist-macros.cpp
index 594cfdc6ef..18d3ce11e6 100644
--- a/test/Analysis/plist-macros.cpp
+++ b/test/Analysis/plist-macros.cpp
@@ -218,7 +218,7 @@ void test2(int *p) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by malloc() should be deallocated by free(), not &apos;delete&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -315,7 +315,7 @@ void test2(int *p) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/pointer-arithmetic.c b/test/Analysis/pointer-arithmetic.c
new file mode 100644
index 0000000000..575dfffc01
--- /dev/null
+++ b/test/Analysis/pointer-arithmetic.c
@@ -0,0 +1,30 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+int test1() {
+ int *p = (int *)sizeof(int);
+ p -= 1;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test2() {
+ int *p = (int *)sizeof(int);
+ p -= 2;
+ p += 1;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test3() {
+ int *p = (int *)sizeof(int);
+ p++;
+ p--;
+ p--;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test4() {
+ // This is a special case where pointer arithmetic is not calculated to
+ // preserve useful warnings on dereferences of null pointers.
+ int *p = 0;
+ p += 1;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index 542a339cd6..e792bb2e6b 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -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/pthreadlock.c b/test/Analysis/pthreadlock.c
index 9886817252..56a92d7d4d 100644
--- a/test/Analysis/pthreadlock.c
+++ b/test/Analysis/pthreadlock.c
@@ -176,6 +176,42 @@ ok22(void) {
pthread_mutex_unlock(pmtx); // no-warning
}
+void ok23(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_destroy(&mtx1); // no-warning
+}
+
+void ok24(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+}
+
+void ok25(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+}
+
+void ok26(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+}
+
+void ok27(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ else
+ pthread_mutex_init(&mtx1, NULL); // no-warning
+}
+
+void ok28(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) { // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ pthread_mutex_destroy(&mtx1); // no-warning
+ }
+}
void
bad1(void)
@@ -392,3 +428,46 @@ bad26(void)
pthread_mutex_unlock(&mtx1); // no-warning
pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
}
+
+void bad27(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ int ret = pthread_mutex_destroy(&mtx1); // no-warning
+ if (ret != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ else
+ pthread_mutex_unlock(&mtx1); // expected-warning{{This lock has already been destroyed}}
+}
+
+void bad28(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ int ret = pthread_mutex_destroy(&mtx1); // no-warning
+ if (ret != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ else
+ pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been destroyed}}
+}
+
+void bad29(void) {
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
+ else
+ pthread_mutex_init(&mtx1, NULL); // no-warning
+}
+
+void bad30(void) {
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
+ else
+ pthread_mutex_destroy(&mtx1); // expected-warning{{This lock has already been destroyed}}
+}
+
+void bad31(void) {
+ int ret = pthread_mutex_destroy(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been destroyed}}
+ if (ret != 0)
+ pthread_mutex_lock(&mtx1);
+}
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index b78ec503a1..93cb4ee9a6 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -342,3 +342,8 @@ void negativeIndex(char *str) {
clang_analyzer_eval(*ptr3 == 'a'); // expected-warning{{UNKNOWN}}
}
+void test_no_crash_on_pointer_to_label() {
+ char *a = &&label;
+ a[0] = 0;
+label:;
+}
diff --git a/test/Analysis/ptr-arith.cpp b/test/Analysis/ptr-arith.cpp
index e1860f4268..1eec83c643 100644
--- a/test/Analysis/ptr-arith.cpp
+++ b/test/Analysis/ptr-arith.cpp
@@ -98,3 +98,22 @@ void checkMultiDimansionalArray() {
int a[5][5];
*(*(a+1)+2) = 2;
}
+
+unsigned ptrSubtractionNoCrash(char *Begin, char *End) {
+ auto N = End - Begin;
+ if (Begin)
+ return 0;
+ return N;
+}
+
+// Bug 34309
+bool ptrAsIntegerSubtractionNoCrash(__UINTPTR_TYPE__ x, char *p) {
+ __UINTPTR_TYPE__ y = (__UINTPTR_TYPE__)p - 1;
+ return y == x;
+}
+
+// Bug 34374
+bool integerAsPtrSubtractionNoCrash(char *p, __UINTPTR_TYPE__ m) {
+ auto n = p - reinterpret_cast<char*>((__UINTPTR_TYPE__)1);
+ return n == m;
+}
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index b323b96661..c269dd7bad 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -117,6 +117,11 @@ void testRetroactiveNullReference(int *x) {
y = 5; // expected-warning{{Dereference of null pointer}}
}
+namespace TestReferenceAddress {
+struct S { int &x; };
+S getS();
+S *getSP();
+
void testReferenceAddress(int &x) {
// FIXME: Move non-zero reference assumption out of RangeConstraintManager.cpp:422
#ifdef ANALYZER_CM_Z3
@@ -127,23 +132,19 @@ void testReferenceAddress(int &x) {
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
}
-
+}
void testFunctionPointerReturn(void *opaque) {
typedef int &(*RefFn)();
diff --git a/test/Analysis/retain-release-inline.m b/test/Analysis/retain-release-inline.m
index 0cde2c1cf5..4fe6bca4a4 100644
--- a/test/Analysis/retain-release-inline.m
+++ b/test/Analysis/retain-release-inline.m
@@ -12,7 +12,7 @@
//
// It includes the basic definitions for the test cases below.
//===----------------------------------------------------------------------===//
-
+#define NULL 0
typedef unsigned int __darwin_natural_t;
typedef unsigned long uintptr_t;
typedef unsigned int uint32_t;
@@ -267,6 +267,10 @@ typedef NSUInteger NSStringEncoding;
extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator);
+typedef struct {
+ int ref;
+} isl_basic_map;
+
//===----------------------------------------------------------------------===//
// Test cases.
//===----------------------------------------------------------------------===//
@@ -285,6 +289,7 @@ void test() {
foo(s);
bar(s);
}
+
void test_neg() {
NSString *s = [[NSString alloc] init]; // no-warning
foo(s);
@@ -294,6 +299,89 @@ void test_neg() {
bar(s);
}
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_cow(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap);
+void free(void *);
+
+void callee_side_parameter_checking_leak(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) { // expected-warning {{Potential leak of an object}}
+}
+
+// As 'isl_basic_map_free' is annotated with 'rc_ownership_trusted_implementation', RetainCountChecker trusts its
+// implementation and doesn't analyze its body. If the annotation 'rc_ownership_trusted_implementation' is removed,
+// a leak warning is raised by RetainCountChecker as the analyzer is unable to detect a decrement in the reference
+// count of 'bmap' along the path in 'isl_basic_map_free' assuming the predicate of the second 'if' branch to be
+// true or assuming both the predicates in the function to be false.
+__attribute__((annotate("rc_ownership_trusted_implementation"))) isl_basic_map *isl_basic_map_free(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ if (!bmap)
+ return NULL;
+
+ if (--bmap->ref > 0)
+ return NULL;
+
+ free(bmap);
+ return NULL;
+}
+
+// As 'isl_basic_map_copy' is annotated with 'rc_ownership_trusted_implementation', RetainCountChecker trusts its
+// implementation and doesn't analyze its body. If that annotation is removed, a 'use-after-release' warning might
+// be raised by RetainCountChecker as the pointer which is passed as an argument to this function and the pointer
+// which is returned from the function point to the same memory location.
+__attribute__((annotate("rc_ownership_trusted_implementation"))) __attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_copy(isl_basic_map *bmap) {
+ if (!bmap)
+ return NULL;
+
+ bmap->ref++;
+ return bmap;
+}
+
+void test_use_after_release_with_trusted_implementation_annotate_attribute(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ // After this call, 'bmap' has a +1 reference count.
+ bmap = isl_basic_map_cow(bmap);
+ // After the call to 'isl_basic_map_copy', 'bmap' has a +1 reference count.
+ isl_basic_map *temp = isl_basic_map_cow(isl_basic_map_copy(bmap));
+ // After this call, 'bmap' has a +0 reference count.
+ isl_basic_map *temp2 = isl_basic_map_cow(bmap); // no-warning
+ isl_basic_map_free(temp2);
+ isl_basic_map_free(temp);
+}
+
+void test_leak_with_trusted_implementation_annotate_attribute(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ // After this call, 'bmap' has a +1 reference count.
+ bmap = isl_basic_map_cow(bmap); // no-warning
+ // After this call, 'bmap' has a +0 reference count.
+ isl_basic_map_free(bmap);
+}
+
+void callee_side_parameter_checking_incorrect_rc_decrement(isl_basic_map *bmap) {
+ isl_basic_map_free(bmap); // expected-warning {{Incorrect decrement of the reference count}}
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *callee_side_parameter_checking_return_notowned_object(isl_basic_map *bmap) {
+ return bmap; // expected-warning {{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *callee_side_parameter_checking_assign_consumed_parameter_leak_return(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap1, __attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap2) { // expected-warning {{Potential leak of an object}}
+ bmap1 = bmap2;
+ isl_basic_map_free(bmap2);
+ return bmap1;
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *callee_side_parameter_checking_assign_consumed_parameter_leak(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap1, __attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap2) { // expected-warning {{Potential leak of an object}}
+ bmap1 = bmap2;
+ isl_basic_map_free(bmap1);
+ return bmap2;
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *error_path_leak(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap1, __attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap2) { // expected-warning {{Potential leak of an object}}
+ bmap1 = isl_basic_map_cow(bmap1);
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ isl_basic_map_free(bmap2);
+ return bmap1;
+error:
+ return isl_basic_map_free(bmap1);
+}
+
//===----------------------------------------------------------------------===//
// Test returning retained and not-retained values.
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/retain-release-safe.c b/test/Analysis/retain-release-safe.c
new file mode 100644
index 0000000000..de74355242
--- /dev/null
+++ b/test/Analysis/retain-release-safe.c
@@ -0,0 +1,72 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.RetainCount -verify %s
+
+#pragma clang arc_cf_code_audited begin
+typedef const void * CFTypeRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+#pragma clang arc_cf_code_audited end
+
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#define CF_CONSUMED __attribute__((cf_consumed))
+
+extern CFTypeRef CFCreate() CF_RETURNS_RETAINED;
+
+// A "safe" variant of CFRetain that doesn't crash when a null pointer is
+// retained. This is often defined by users in a similar manner. The
+// CF_RETURNS_RETAINED annotation is misleading here, because the function
+// is not supposed to return an object with a +1 retain count. Instead, it
+// is supposed to return an object with +(N+1) retain count, where N is
+// the original retain count of 'cf'. However, there is no good annotation
+// to use in this case, and it is pointless to provide such annotation
+// because the only use cases would be CFRetain and SafeCFRetain.
+// So instead we teach the analyzer to be able to accept such code
+// and ignore the misplaced annotation.
+CFTypeRef SafeCFRetain(CFTypeRef cf) CF_RETURNS_RETAINED {
+ if (cf) {
+ return CFRetain(cf);
+ }
+ return cf;
+}
+
+// A "safe" variant of CFRelease that doesn't crash when a null pointer is
+// released. The CF_CONSUMED annotation seems reasonable here.
+void SafeCFRelease(CFTypeRef CF_CONSUMED cf) {
+ if (cf)
+ CFRelease(cf); // no-warning (when inlined)
+}
+
+void escape(CFTypeRef cf);
+
+void makeSureTestsWork() {
+ CFTypeRef cf = CFCreate();
+ CFRelease(cf);
+ CFRelease(cf); // expected-warning{{Reference-counted object is used after it is released}}
+}
+
+// Make sure we understand that the second SafeCFRetain doesn't return an
+// object with +1 retain count, which we won't be able to release twice.
+void falseOverrelease(CFTypeRef cf) {
+ SafeCFRetain(cf);
+ SafeCFRetain(cf);
+ SafeCFRelease(cf);
+ SafeCFRelease(cf); // no-warning after inlining this.
+}
+
+// Regular CFRelease() should behave similarly.
+void sameWithNormalRelease(CFTypeRef cf) {
+ SafeCFRetain(cf);
+ SafeCFRetain(cf);
+ CFRelease(cf);
+ CFRelease(cf); // no-warning
+}
+
+// Make sure we understand that the second SafeCFRetain doesn't return an
+// object with +1 retain count, which would no longer be owned by us after
+// it escapes to escape() and released once.
+void falseReleaseNotOwned(CFTypeRef cf) {
+ SafeCFRetain(cf);
+ SafeCFRetain(cf);
+ escape(cf);
+ SafeCFRelease(cf);
+ SafeCFRelease(cf); // no-warning after inlining this.
+}
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 39a3baa896..a1cc62cb35 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -325,6 +325,9 @@ typedef const struct __CFUUID * CFUUIDRef;
extern
void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef factoryUUID, CFUUIDRef typeUUID);
+typedef struct {
+ int ref;
+} isl_basic_map;
//===----------------------------------------------------------------------===//
// Test cases.
@@ -574,6 +577,14 @@ void f17(int x, CFTypeRef p) {
}
}
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_cow(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap);
+
+// Test custom diagnostics for generalized objects.
+void f18(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ // After this call, 'bmap' has a +1 reference count.
+ bmap = isl_basic_map_cow(bmap); // expected-warning {{Potential leak of an object}}
+}
+
// Test basic tracking of ivars associated with 'self'. For the retain/release
// checker we currently do not want to flag leaks associated with stores
// of tracked objects to ivars.
@@ -1447,7 +1458,7 @@ typedef NSString* MyStringTy;
+ (void) consume2:(id) CF_CONSUMED x;
@end
-static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}}
+static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' only applies to function types; type here is 'int'}}
void test_attr_1(TestOwnershipAttr *X) {
NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
@@ -1776,15 +1787,15 @@ CFArrayRef camel_copymachine() {
// rdar://problem/8024350
@protocol F18P
-- (id) clone;
+- (id) clone; // expected-note 2 {{method declared here}}
@end
@interface F18 : NSObject<F18P> @end
@interface F18(Cat)
-- (id) clone NS_RETURNS_RETAINED;
+- (id) clone NS_RETURNS_RETAINED; // expected-warning {{overriding method has mismatched ns_returns_retained attributes}}
@end
@implementation F18
-- (id) clone {
+- (id) clone { // expected-warning {{overriding method has mismatched ns_returns_retained attributes}}
return [F18 alloc];
}
@end
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index c9817005c2..ac83c1a48e 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -461,3 +461,12 @@ void radar13722286::PrepareBitmap() {
}
}
+// rdar://34210609
+void _() { _(); }; // no-warning
+
+// Do not assume that IOBSDNameMatching increments a reference counter,
+// unless return type is CFMutableDictionaryRef.
+void* IOBSDNameMatching();
+void rdar33832412() {
+ void* x = IOBSDNameMatching(); // no-warning
+}
diff --git a/test/Analysis/simple-stream-checks.c b/test/Analysis/simple-stream-checks.c
index f47e488110..ca1c781575 100644
--- a/test/Analysis/simple-stream-checks.c
+++ b/test/Analysis/simple-stream-checks.c
@@ -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/taint-generic.c b/test/Analysis/taint-generic.c
index 8efed66dac..d3ca246b82 100644
--- a/test/Analysis/taint-generic.c
+++ b/test/Analysis/taint-generic.c
@@ -192,20 +192,41 @@ void testStruct() {
void testStructArray() {
struct {
- char buf[16];
- struct {
- int length;
- } st[1];
- } tainted;
+ int length;
+ } tainted[4];
- char buffer[16];
+ char dstbuf[16], srcbuf[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
+ __builtin_memset(srcbuf, 0, sizeof(srcbuf));
+
+ read(sock, &tainted[0], sizeof(tainted));
+ __builtin_memcpy(dstbuf, srcbuf, tainted[0].length); // expected-warning {{Untrusted data is used to specify the buffer size}}
+
+ __builtin_memset(&tainted, 0, sizeof(tainted));
+ read(sock, &tainted, sizeof(tainted));
+ __builtin_memcpy(dstbuf, srcbuf, tainted[0].length); // expected-warning {{Untrusted data is used to specify the buffer size}}
+
+ __builtin_memset(&tainted, 0, sizeof(tainted));
+ // If we taint element 1, we should not raise an alert on taint for element 0 or element 2
+ read(sock, &tainted[1], sizeof(tainted));
+ __builtin_memcpy(dstbuf, srcbuf, tainted[0].length); // no-warning
+ __builtin_memcpy(dstbuf, srcbuf, tainted[2].length); // no-warning
+}
+
+void testUnion() {
+ union {
+ int x;
+ char y[4];
+ } tainted;
+
+ char buffer[4];
+
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+ read(sock, &tainted.y, sizeof(tainted.y));
+ // FIXME: overlapping regions aren't detected by isTainted yet
+ __builtin_memcpy(buffer, tainted.y, tainted.x);
}
int testDivByZero() {
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 372443bedf..05b6a31059 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -834,7 +834,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
-// CHECK: 1: [B7.2] ?: [B6.6]
+// CXX98: 1: [B7.2] ?: [B6.6]
+// CXX11: 1: [B7.3] ?: [B6.6]
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
// CHECK: 4: [B4.3] (CXXConstructExpr, class A)
@@ -843,10 +844,13 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (2): B5 B6
// CHECK: Succs (2): B3 B2
// CHECK: [B5]
-// CHECK: 1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 2: [B5.1]
-// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
-// CHECK: 4: [B5.3] (BindTemporary)
+// CXX98: 1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98: 2: [B5.1]
+// CXX98: 3: [B5.2] (CXXConstructExpr, class A)
+// CXX98: 4: [B5.3] (BindTemporary)
+// CXX11: 1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11: 2: [B5.1] (CXXConstructExpr, class A)
+// CXX11: 3: [B5.2] (BindTemporary)
// CHECK: Preds (1): B7
// CHECK: Succs (1): B4
// CHECK: [B6]
@@ -861,10 +865,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B7]
// CHECK: 1: A() (CXXConstructExpr, class A)
// CHECK: 2: [B7.1] (BindTemporary)
-// CHECK: 3: [B7.2].operator bool
-// CHECK: 4: [B7.2]
-// CHECK: 5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B7.5] ? ... : ...
+// CXX98: 3: [B7.2].operator bool
+// CXX98: 4: [B7.2]
+// CXX98: 5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98: T: [B7.5] ? ... : ...
+// CXX11: 3: [B7.2]
+// CXX11: 4: [B7.3].operator bool
+// CXX11: 5: [B7.3]
+// CXX11: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11: T: [B7.6] ? ... : ...
// CHECK: Preds (1): B8
// CHECK: Succs (2): B5 B6
// CHECK: [B0 (EXIT)]
@@ -886,7 +895,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
-// CHECK: 1: [B7.4] ?: [B6.6]
+// CXX98: 1: [B7.4] ?: [B6.6]
+// CXX11: 1: [B7.5] ?: [B6.6]
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
// CHECK: 4: [B7.2]([B4.3])
@@ -894,10 +904,13 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (2): B5 B6
// CHECK: Succs (2): B3 B2
// CHECK: [B5]
-// CHECK: 1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 2: [B5.1]
-// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
-// CHECK: 4: [B5.3] (BindTemporary)
+// CXX98: 1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
+// CXX98: 2: [B5.1]
+// CXX98: 3: [B5.2] (CXXConstructExpr, class A)
+// CXX98: 4: [B5.3] (BindTemporary)
+// CXX11: 1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
+// CXX11: 2: [B5.1] (CXXConstructExpr, class A)
+// CXX11: 3: [B5.2] (BindTemporary)
// CHECK: Preds (1): B7
// CHECK: Succs (1): B4
// CHECK: [B6]
@@ -914,10 +927,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
// CHECK: 3: A() (CXXConstructExpr, class A)
// CHECK: 4: [B7.3] (BindTemporary)
-// CHECK: 5: [B7.4].operator bool
-// CHECK: 6: [B7.4]
-// CHECK: 7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B7.7] ? ... : ...
+// CXX98: 5: [B7.4].operator bool
+// CXX98: 6: [B7.4]
+// CXX98: 7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98: T: [B7.7] ? ... : ...
+// CXX11: 5: [B7.4]
+// CXX11: 6: [B7.5].operator bool
+// CXX11: 7: [B7.5]
+// CXX11: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11: T: [B7.8] ? ... : ...
// CHECK: Preds (2): B8 B9
// CHECK: Succs (2): B5 B6
// CHECK: [B8]
@@ -925,7 +943,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B9
// CHECK: Succs (1): B7
// CHECK: [B9]
-// CHECK: 1: [B12.2] ?: [B11.6]
+// CXX98: 1: [B12.2] ?: [B11.6]
+// CXX11: 1: [B12.3] ?: [B11.6]
// CHECK: 2: [B9.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B9.2]
// CHECK: 4: const A &a = A() ?: A();
@@ -933,10 +952,13 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (2): B10 B11
// CHECK: Succs (2): B8 B7
// CHECK: [B10]
-// CHECK: 1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 2: [B10.1]
-// CHECK: 3: [B10.2] (CXXConstructExpr, class A)
-// CHECK: 4: [B10.3] (BindTemporary)
+// CXX98: 1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98: 2: [B10.1]
+// CXX98: 3: [B10.2] (CXXConstructExpr, class A)
+// CXX98: 4: [B10.3] (BindTemporary)
+// CXX11: 1: [B12.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11: 2: [B10.1] (CXXConstructExpr, class A)
+// CXX11: 3: [B10.2] (BindTemporary)
// CHECK: Preds (1): B12
// CHECK: Succs (1): B9
// CHECK: [B11]
@@ -951,10 +973,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B12]
// CHECK: 1: A() (CXXConstructExpr, class A)
// CHECK: 2: [B12.1] (BindTemporary)
-// CHECK: 3: [B12.2].operator bool
-// CHECK: 4: [B12.2]
-// CHECK: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B12.5] ? ... : ...
+// CXX98: 3: [B12.2].operator bool
+// CXX98: 4: [B12.2]
+// CXX98: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98: T: [B12.5] ? ... : ...
+// CXX11: 3: [B12.2]
+// CXX11: 4: [B12.3].operator bool
+// CXX11: 5: [B12.3]
+// CXX11: 6: [B12.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11: T: [B12.6] ? ... : ...
// CHECK: Preds (1): B13
// CHECK: Succs (2): B10 B11
// CHECK: [B0 (EXIT)]
diff --git a/test/Analysis/temporaries-callback-order.cpp b/test/Analysis/temporaries-callback-order.cpp
new file mode 100644
index 0000000000..df916cc4e7
--- /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 2c052f8b51..99851dd685 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -503,3 +503,30 @@ namespace PR32088 {
});
}
}
+
+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/uninit-const.cpp b/test/Analysis/uninit-const.cpp
index 75e932a77c..db969bfb67 100644
--- a/test/Analysis/uninit-const.cpp
+++ b/test/Analysis/uninit-const.cpp
@@ -122,7 +122,7 @@ void f1(void) {
}
void f_uninit(void) {
- int x;
+ int x; // expected-note {{'x' declared without an initial 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/unix-fns.c b/test/Analysis/unix-fns.c
index 3eccd51d2c..481f545e28 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,7 +1,7 @@
-// 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: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,unix.API,osx.API,optin.portability %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_analyze_cc1 -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,optin.portability -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 ff58587be2..effa4d9bfa 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -213,3 +213,13 @@ void macro(void) {
RETURN(1); // no-warning
}
+// Avoid FP when macro argument is known
+void writeSomething(int *x);
+#define MACRO(C) \
+ if (!C) { \
+ static int x; \
+ writeSomething(&x); \
+ }
+void macro2(void) {
+ MACRO(1);
+}
diff --git a/test/Analysis/unsupported-types.c b/test/Analysis/unsupported-types.c
new file mode 100644
index 0000000000..9233095e42
--- /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/virtualcall.cpp b/test/Analysis/virtualcall.cpp
index 56bd32446e..c22a8463c0 100644
--- a/test/Analysis/virtualcall.cpp
+++ b/test/Analysis/virtualcall.cpp
@@ -1,98 +1,83 @@
-// 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
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-output=text -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
- only in the constructor or destructor.
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -analyzer-output=text -verify -std=c++11 %s
- When PUREONLY is set, we expect diagnostics only for calls to pure virtual
- functions not to non-pure virtual functions.
-*/
+#include "virtualcall.h"
class A {
public:
A();
- A(int i);
- ~A() {};
-
- virtual int foo() = 0; // from Sema: expected-note {{'foo' declared here}}
+ ~A(){};
+
+ virtual int foo() = 0;
virtual void bar() = 0;
void f() {
foo();
-#if INTERPROCEDURAL
- // expected-warning-re@-2 {{{{^}}Call Path : foo <-- fCall to pure virtual function during construction has undefined behavior}}
-#endif
+ // expected-warning-re@-1 {{{{^}}Call to pure virtual function during construction}}
+ // expected-note-re@-2 {{{{^}}Call to pure virtual function during construction}}
}
};
class B : public A {
public:
- B() {
- foo();
+ B() { // expected-note {{Calling default constructor for 'A'}}
+ foo();
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
-#endif
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'B' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
-
}
~B();
-
+
virtual int foo();
- virtual void bar() { foo(); }
-#if INTERPROCEDURAL
- // expected-warning-re@-2 {{{{^}}Call Path : foo <-- barCall to virtual function during destruction will not dispatch to derived class}}
+ virtual void bar() {
+ foo();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during destruction}}
+ // expected-note-re@-3 {{{{^}}Call to virtual function during destruction}}
#endif
+ }
};
-A::A() {
- f();
-}
-
-A::A(int i) {
- foo(); // From Sema: expected-warning {{call to pure virtual member function 'foo' has undefined behavior}}
-#if INTERPROCEDURAL
- // expected-warning-re@-2 {{{{^}}Call Path : fooCall to pure virtual function during construction has undefined behavior}}
-#else
- // expected-warning-re@-4 {{{{^}}Call to pure virtual function during construction has undefined behavior}}
-#endif
+A::A() {
+ f();
+// expected-note-re@-1 {{{{^}}This constructor of an object of type 'A' has not returned when the virtual method was called}}
+// expected-note-re@-2 {{{{^}}Calling 'A::f'}}
}
B::~B() {
this->B::foo(); // no-warning
this->B::bar();
- this->foo();
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during destruction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during destruction will not dispatch to derived class}}
+ // expected-note-re@-2 {{{{^}}This destructor of an object of type '~B' has not returned when the virtual method was called}}
+ // expected-note-re@-3 {{{{^}}Calling 'B::bar'}}
#endif
+ this->foo();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during destruction}}
+ // expected-note-re@-3 {{{{^}}This destructor of an object of type '~B' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during destruction}}
#endif
-
+
}
class C : public B {
public:
C();
~C();
-
+
virtual int foo();
void f(int i);
};
C::C() {
- f(foo());
+ f(foo());
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
-#endif
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'C' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
}
@@ -112,30 +97,198 @@ public:
foo(); // no-warning
}
~E() { bar(); }
+#if !PUREONLY
+ // expected-note-re@-2 2{{{{^}}Calling '~B'}}
+#endif
int foo() override;
};
-// Regression test: don't crash when there's no direct callee.
class F {
public:
F() {
- void (F::* ptr)() = &F::foo;
+ void (F::*ptr)() = &F::foo;
(this->*ptr)();
}
void foo();
};
+class G {
+public:
+ G() {}
+ virtual void bar();
+ void foo() {
+ bar(); // no warning
+ }
+};
+
+class H {
+public:
+ H() : initState(0) { init(); }
+ int initState;
+ virtual void f() const;
+ void init() {
+ if (initState)
+ f(); // no warning
+ }
+
+ H(int i) {
+ G g;
+ g.foo();
+ g.bar(); // no warning
+ f();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'H' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ H &h = *this;
+ h.f();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'H' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+};
+
+class X {
+public:
+ X() {
+ g();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'X' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+ X(int i) {
+ if (i > 0) {
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}Taking true branch}}
+ // expected-note-re@-3 {{{{^}}Taking false branch}}
+#endif
+ X x(i - 1);
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}Calling constructor for 'X'}}
+#endif
+ x.g(); // no warning
+ }
+ g();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'X' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+ virtual void g();
+};
+
+class M;
+class N {
+public:
+ virtual void virtualMethod();
+ void callFooOfM(M *);
+};
+class M {
+public:
+ M() {
+ N n;
+ n.virtualMethod(); // no warning
+ n.callFooOfM(this);
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}This constructor of an object of type 'M' has not returned when the virtual method was called}}
+ // expected-note-re@-3 {{{{^}}Calling 'N::callFooOfM'}}
+#endif
+ }
+ virtual void foo();
+};
+void N::callFooOfM(M *m) {
+ m->foo();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}Call to virtual function during construction}}
+#endif
+}
+
+class Y {
+public:
+ virtual void foobar();
+ void fooY() {
+ F f1;
+ foobar();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+ Y() { fooY(); }
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}This constructor of an object of type 'Y' has not returned when the virtual method was called}}
+ // expected-note-re@-3 {{{{^}}Calling 'Y::fooY'}}
+#endif
+};
+
int main() {
- A *a;
- B *b;
- C *c;
- D *d;
- E *e;
- F *f;
+ B b;
+#if PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'B'}}
+#else
+ //expected-note-re@-4 2{{{{^}}Calling default constructor for 'B'}}
+#endif
+ C c;
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'C'}}
+#endif
+ D d;
+ E e;
+ F f;
+ G g;
+ H h;
+ H h1(1);
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling constructor for 'H'}}
+ //expected-note-re@-3 {{{{^}}Calling constructor for 'H'}}
+#endif
+ X x;
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'X'}}
+#endif
+ X x1(1);
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling constructor for 'X'}}
+#endif
+ M m;
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'M'}}
+#endif
+ Y *y = new Y;
+ delete y;
+ header::Z z;
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}Calling default constructor for 'Z'}}
+#endif
}
+#if !PUREONLY
+ //expected-note-re@-2 2{{{{^}}Calling '~E'}}
+#endif
-#include "virtualcall.h"
+namespace PR34451 {
+struct a {
+ void b() {
+ a c[1];
+ c->b();
+ }
+};
-#define AS_SYSTEM
-#include "virtualcall.h"
-#undef AS_SYSTEM
+class e {
+ public:
+ void b() const;
+};
+
+class c {
+ void m_fn2() const;
+ e d[];
+};
+
+void c::m_fn2() const { d->b(); }
+}
diff --git a/test/Analysis/virtualcall.h b/test/Analysis/virtualcall.h
index c2ad8a6444..e2fde2415e 100644
--- a/test/Analysis/virtualcall.h
+++ b/test/Analysis/virtualcall.h
@@ -1,36 +1,14 @@
-#ifdef AS_SYSTEM
-#pragma clang system_header
-
-namespace system {
- class A {
- public:
- A() {
- foo(); // no-warning
- }
-
- virtual int foo();
- };
-}
-
-#else
-
namespace header {
- class A {
+ class Z {
public:
- A() {
+ Z() {
foo();
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
-#endif
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'Z' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
-
}
-
virtual int foo();
};
}
-
-#endif
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 23d23bcddc..c1ac9e4f0f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -26,13 +26,17 @@ llvm_canonicalize_cmake_booleans(
HAVE_LIBZ)
configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
+ MAIN_CONFIG
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
)
configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
+ MAIN_CONFIG
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
)
option(CLANG_TEST_USE_VG "Run Clang tests under Valgrind" OFF)
@@ -47,11 +51,15 @@ list(APPEND CLANG_TEST_DEPS
clang-tblgen
clang-offload-bundler
clang-import-test
+ clang-rename
+ clang-refactor
+ clang-diff
)
if(CLANG_ENABLE_STATIC_ANALYZER)
list(APPEND CLANG_TEST_DEPS
clang-check
+ clang-func-mapping
)
endif()
diff --git a/test/CXX/basic/basic.link/p8.cpp b/test/CXX/basic/basic.link/p8.cpp
new file mode 100644
index 0000000000..54b977d77f
--- /dev/null
+++ b/test/CXX/basic/basic.link/p8.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s -pedantic
+
+template<typename T> struct Template {};
+
+struct Linkage1 { struct Inner {}; };
+typedef struct { struct Inner {}; } Linkage2;
+
+typedef struct {} const NoLinkage1;
+auto x = [] {};
+typedef decltype(x) NoLinkage2;
+auto f() { return [] {}; }
+typedef decltype(f()) NoLinkage3;
+
+inline auto g() { return [] {}; }
+typedef decltype(g()) VisibleNoLinkage1;
+inline auto y = [] {};
+typedef decltype(y) VisibleNoLinkage2;
+inline auto h() { struct {} x; return x; }
+typedef decltype(h()) VisibleNoLinkage3;
+
+extern Linkage1 linkage1v;
+extern Linkage1::Inner linkage1iv;
+extern Linkage2 linkage2v;
+extern Linkage2::Inner linkage2iv;
+extern Template<Linkage1> linkaget1v;
+extern Linkage1 linkage1f();
+void linkage2f(Linkage2);
+
+void use_linkage() {
+ &linkage1v, &linkage1iv, &linkage2v, &linkage2iv, &linkaget1v; // expected-warning 5{{unused}}
+ linkage1f();
+ linkage2f({});
+}
+
+extern NoLinkage1 no_linkage1(); // expected-error {{function 'no_linkage1' is used but not defined in this translation unit}}
+extern NoLinkage2 no_linkage2(); // expected-error {{function 'no_linkage2' is used but not defined in this translation unit}}
+extern NoLinkage3 no_linkage3(); // expected-error {{function 'no_linkage3' is used but not defined in this translation unit}}
+
+void use_no_linkage() {
+ no_linkage1(); // expected-note {{used here}}
+ no_linkage2(); // expected-note {{used here}}
+ no_linkage3(); // expected-note {{used here}}
+}
+
+extern VisibleNoLinkage1 visible_no_linkage1(); // expected-warning {{ISO C++ requires a definition}}
+extern VisibleNoLinkage2 visible_no_linkage2(); // expected-warning {{ISO C++ requires a definition}}
+extern VisibleNoLinkage3 visible_no_linkage3(); // expected-warning {{ISO C++ requires a definition}}
+
+void use_visible_no_linkage() {
+ visible_no_linkage1(); // expected-note {{used here}}
+ visible_no_linkage2(); // expected-note {{used here}}
+ visible_no_linkage3(); // expected-note {{used here}}
+}
+
+namespace {
+ struct InternalLinkage {};
+}
+InternalLinkage internal_linkage(); // expected-error {{used but not defined}}
+void use_internal_linkage() {
+ internal_linkage(); // expected-note {{used here}}
+}
+
+extern inline int not_defined; // expected-error {{not defined}}
+extern inline int defined_after_use;
+void use_inline_vars() {
+ not_defined = 1; // expected-note {{used here}}
+ defined_after_use = 2;
+}
+inline int defined_after_use;
+
+namespace {
+ template<typename T> struct A {
+ static const int n;
+ };
+ template<typename T> const int A<T>::n = 3;
+ static_assert(A<int>::n == 3);
+ int k = A<float>::n;
+}
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 18b18834bb..cf58a85d84 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
@@ -73,6 +73,7 @@ void other_contexts() {
int a;
{
X0::X0(a); // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
+ // expected-warning@-1 {{redundant parentheses around declaration of variable named 'a'}} expected-note@-1 2{{}}
}
}
diff --git a/test/CXX/basic/basic.scope/basic.scope.declarative/p4.cpp b/test/CXX/basic/basic.scope/basic.scope.declarative/p4.cpp
new file mode 100644
index 0000000000..8c14546edc
--- /dev/null
+++ b/test/CXX/basic/basic.scope/basic.scope.declarative/p4.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+namespace TagVs {
+ struct Bindable { int a; };
+ struct binding_a {}; // expected-note {{previous}}
+ auto [binding_a] = Bindable{}; // expected-error {{redefinition}}
+ auto [binding_b] = Bindable{}; // expected-note {{previous}}
+ struct binding_b {}; // expected-error {{redefinition}}
+
+ struct vartemplate_a {}; // expected-note {{previous}}
+ template<typename T> int vartemplate_a; // expected-error {{redefinition}}
+ template<typename T> int vartemplate_b; // expected-note {{previous}}
+ struct vartemplate_b {}; // expected-error {{redefinition}}
+
+ struct aliastemplate_a {}; // expected-note {{previous}}
+ template<typename T> using aliastemplate_a = int; // expected-error {{redefinition}}
+ template<typename T> using aliastemplate_b = int; // expected-note {{previous}}
+ struct aliastemplate_b {}; // expected-error {{redefinition}}
+}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index f010ad5a2c..6d452d8199 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -167,7 +167,7 @@ namespace test3 {
Base2, // expected-error 2 {{base class 'test3::Base2' has private destructor}}
virtual Base3
{};
- Derived3 d3; // expected-note {{implicit default constructor}}\
+ Derived3 d3; // expected-note 3{{implicit default constructor}}\
// expected-note{{implicit destructor}}}
#else
template <unsigned N> class Base { ~Base(); }; // expected-note 4{{declared private here}}
diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp
index 413017d133..5640bc30ad 100644
--- a/test/CXX/class/class.static/class.static.data/p3.cpp
+++ b/test/CXX/class/class.static/class.static.data/p3.cpp
@@ -50,4 +50,4 @@ U<NonLit> u2; // expected-note {{here}}
static_assert(U<int>::a == 0, "");
-constexpr int outofline = (U<NonLit>::d, 0); // expected-note {{here}} expected-warning {{unused}}
+constexpr int outofline = (U<NonLit>::d, 0); // expected-note {{here}}
diff --git a/test/CXX/conv/conv.prom/p2.cpp b/test/CXX/conv/conv.prom/p2.cpp
index ca64cfa8d0..c5ac9112d8 100644
--- a/test/CXX/conv/conv.prom/p2.cpp
+++ b/test/CXX/conv/conv.prom/p2.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -triple x86_64-pc-linux-gnu -ffreestanding %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -triple x86_64-pc-linux-gnu -ffreestanding -fshort-wchar %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -triple x86_64-pc-linux-gnu -ffreestanding -fwchar-type=short -fno-signed-wchar %s
// expected-no-diagnostics
#include <stdint.h>
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 a27cea84db..58c7c0cfac 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.attr/dcl.attr.fallthrough/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp
index e7c90339a2..f267d9067b 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.fallthrough/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1z -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify %s
void f(int n) {
switch (n) {
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
index 3d4b925188..49c418a687 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify -Wc++1z-extensions %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT -Wc++1z-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify -Wc++17-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -DEXT -Wc++17-extensions %s
struct [[nodiscard]] S {};
S get_s();
@@ -9,21 +9,33 @@ enum [[nodiscard]] E {};
E get_e();
[[nodiscard]] int get_i();
+[[nodiscard]] volatile int &get_vi();
void f() {
get_s(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
get_i(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ get_vi(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
get_e(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
// Okay, warnings are not encouraged
get_s_ref();
(void)get_s();
(void)get_i();
+ (void)get_vi();
(void)get_e();
}
+[[nodiscard]] volatile char &(*fp)();
+void g() {
+ fp(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ // OK, warning suppressed.
+ (void)fp();
+}
#ifdef EXT
-// expected-warning@4 {{use of the 'nodiscard' attribute is a C++1z extension}}
-// expected-warning@8 {{use of the 'nodiscard' attribute is a C++1z extension}}
-// expected-warning@11 {{use of the 'nodiscard' attribute is a C++1z extension}}
+// expected-warning@4 {{use of the 'nodiscard' attribute is a C++17 extension}}
+// expected-warning@8 {{use of the 'nodiscard' attribute is a C++17 extension}}
+// expected-warning@11 {{use of the 'nodiscard' attribute is a C++17 extension}}
+// expected-warning@12 {{use of the 'nodiscard' attribute is a C++17 extension}}
+// expected-warning@28 {{use of the 'nodiscard' attribute is a C++17 extension}}
#endif
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp
index a627d8331a..551df38a81 100644
--- a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.unused/p3.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused -Wused-but-marked-unused -std=c++1z -Wc++1z-extensions -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wunused -Wused-but-marked-unused -std=c++11 -Wc++1z-extensions -verify -DEXT %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused -Wused-but-marked-unused -std=c++17 -Wc++17-extensions -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused -Wused-but-marked-unused -std=c++11 -Wc++17-extensions -verify -DEXT %s
static_assert(__has_cpp_attribute(maybe_unused) == 201603, "");
@@ -20,7 +20,7 @@ void f() {
}
#ifdef EXT
-// expected-warning@6 {{use of the 'maybe_unused' attribute is a C++1z extension}}
-// expected-warning@13 {{use of the 'maybe_unused' attribute is a C++1z extension}}
-// expected-warning@14 {{use of the 'maybe_unused' attribute is a C++1z extension}}
+// expected-warning@6 {{use of the 'maybe_unused' attribute is a C++17 extension}}
+// expected-warning@13 {{use of the 'maybe_unused' attribute is a C++17 extension}}
+// expected-warning@14 {{use of the 'maybe_unused' attribute is a C++17 extension}}
#endif
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
index 12237a39ab..6e150ce5a5 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.fct.spec/p4.cpp
@@ -4,3 +4,31 @@ void f0() { // expected-note {{previous definition is here}}
}
inline void f0(); // expected-error {{inline declaration of 'f0' follows non-inline definition}}
+
+void func_01() {} // expected-note{{previous definition is here}}
+struct C01 {
+ friend void func_01() {} // expected-error{{redefinition of 'func_01'}}
+};
+
+void func_02() {} // expected-note{{previous definition is here}}
+struct C02 {
+ friend inline void func_02(); // expected-error{{inline declaration of 'func_02' follows non-inline definition}}
+};
+
+void func_03() {} // expected-note{{previous definition is here}}
+struct C03 {
+ friend inline void func_03() {} // expected-error{{inline declaration of 'func_03' follows non-inline definition}}
+};
+
+void func_04() {} // expected-note{{previous definition is here}}
+inline void func_04() {} // expected-error{{inline declaration of 'func_04' follows non-inline definition}}
+
+void func_06() {} // expected-note{{previous definition is here}}
+template<typename T> struct C06 {
+ friend inline void func_06() {} // expected-error{{inline declaration of 'func_06' follows non-inline definition}}
+};
+
+void func_07() {} // expected-note{{previous definition is here}}
+template<typename T> struct C07 {
+ friend inline void func_07(); // expected-error{{inline declaration of 'func_07' follows non-inline definition}}
+};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
index 0b7a902f93..13721518e6 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp
@@ -39,6 +39,7 @@ struct S {
void foo(auto int ap, register int rp) {
#if __cplusplus >= 201103L // C++11 or later
// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}}
+// expected-warning@-3 {{'register' storage class specifier is deprecated}}
#endif
auto int abo;
#if __cplusplus >= 201103L // C++11 or later
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
index a5ac85cb6f..6014268a18 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
@@ -73,3 +73,36 @@ void Test ()
}
} // namespace
+
+namespace pr12724 {
+
+void func_01(bool param = true);
+class C01 {
+public:
+ friend void func_01(bool param);
+};
+
+void func_02(bool param = true);
+template<typename T>
+class C02 {
+public:
+ friend void func_02(bool param);
+};
+C02<int> c02;
+
+void func_03(bool param);
+template<typename T>
+class C03 {
+public:
+ friend void func_03(bool param);
+};
+void func_03(bool param = true);
+C03<int> c03;
+
+void main() {
+ func_01();
+ func_02();
+ func_03();
+}
+
+} // namespace pr12724
diff --git a/test/CXX/drs/dr0xx.cpp b/test/CXX/drs/dr0xx.cpp
index 055f40f98f..fbca6635ec 100644
--- a/test/CXX/drs/dr0xx.cpp
+++ b/test/CXX/drs/dr0xx.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-bind-to-temporary-copy
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
-// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
+// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
namespace dr1 { // dr1: no
namespace X { extern "C" void dr1_f(int a = 1); }
@@ -276,9 +276,9 @@ namespace dr23 { // dr23: yes
namespace dr25 { // dr25: yes
struct A {
- void f() throw(int); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
+ void f() throw(int); // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
};
- void (A::*f)() throw (int); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
+ void (A::*f)() throw (int); // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
void (A::*g)() throw () = f;
#if __cplusplus <= 201402L
// expected-error@-2 {{is not superset of source}}
@@ -286,7 +286,7 @@ namespace dr25 { // dr25: yes
// expected-error@-4 {{different exception specifications}}
#endif
void (A::*g2)() throw () = 0;
- void (A::*h)() throw (int, char) = f; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
+ void (A::*h)() throw (int, char) = f; // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
void (A::*i)() throw () = &A::f;
#if __cplusplus <= 201402L
// expected-error@-2 {{is not superset of source}}
@@ -294,7 +294,7 @@ namespace dr25 { // dr25: yes
// expected-error@-4 {{different exception specifications}}
#endif
void (A::*i2)() throw () = 0;
- void (A::*j)() throw (int, char) = &A::f; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
+ void (A::*j)() throw (int, char) = &A::f; // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
void x() {
g2 = f;
#if __cplusplus <= 201402L
@@ -941,7 +941,7 @@ namespace dr84 { // dr84: yes
};
A a;
// Cannot use B(C) / operator C() pair to construct the B from the B temporary
- // here. In C++1z, we initialize the B object directly using 'A::operator B()'.
+ // here. In C++17, we initialize the B object directly using 'A::operator B()'.
B b = a;
#if __cplusplus <= 201402L
// expected-error@-2 {{no viable}}
@@ -1033,14 +1033,14 @@ namespace dr91 { // dr91: yes
}
namespace dr92 { // dr92: 4 c++17
- void f() throw(int, float); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
- void (*p)() throw(int) = &f; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
+ void f() throw(int, float); // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
+ void (*p)() throw(int) = &f; // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
#if __cplusplus <= 201402L
// expected-error@-2 {{target exception specification is not superset of source}}
#else
// expected-warning@-4 {{target exception specification is not superset of source}}
#endif
- void (*q)() throw(int); // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
+ void (*q)() throw(int); // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
void (**pp)() throw() = &q;
#if __cplusplus <= 201402L
// expected-error@-2 {{exception specifications are not allowed}}
@@ -1064,7 +1064,7 @@ namespace dr92 { // dr92: 4 c++17
// expected-error@-2 {{not implicitly convertible}}
#endif
- template<void() throw(int)> struct Y {}; // expected-error 0-1{{ISO C++1z does not allow}} expected-note 0-1{{use 'noexcept}}
+ template<void() throw(int)> struct Y {}; // expected-error 0-1{{ISO C++17 does not allow}} expected-note 0-1{{use 'noexcept}}
Y<&h> yp; // ok
}
diff --git a/test/CXX/drs/dr11xx.cpp b/test/CXX/drs/dr11xx.cpp
new file mode 100644
index 0000000000..81fbc1e3ef
--- /dev/null
+++ b/test/CXX/drs/dr11xx.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+namespace dr1113 { // dr1113: partial
+ namespace named {
+ extern int a; // expected-note {{previous}}
+ static int a; // expected-error {{static declaration of 'a' follows non-static}}
+ }
+ namespace {
+ extern int a;
+ static int a; // ok, both declarations have internal linkage
+ int b = a;
+ }
+
+ // FIXME: Per DR1113 and DR4, this is ill-formed due to ambiguity: the second
+ // 'f' has internal linkage, and so does not have C language linkage, so is
+ // not a redeclaration of the first 'f'.
+ //
+ // To avoid a breaking change here, Clang ignores the "internal linkage" effect
+ // of anonymous namespaces on declarations declared within an 'extern "C"'
+ // linkage-specification.
+ extern "C" void f();
+ namespace {
+ extern "C" void f();
+ }
+ void g() { f(); }
+}
diff --git a/test/CXX/drs/dr13xx.cpp b/test/CXX/drs/dr13xx.cpp
index 56ff123748..f193c8e024 100644
--- a/test/CXX/drs/dr13xx.cpp
+++ b/test/CXX/drs/dr13xx.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// 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
+// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
__extension__ typedef __SIZE_TYPE__ size_t;
@@ -124,7 +124,7 @@ namespace dr1315 { // dr1315: partial
namespace dr1330 { // dr1330: 4 c++11
// exception-specifications are parsed in a context where the class is complete.
struct A {
- void f() throw(T) {} // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
+ void f() throw(T) {} // expected-error 0-1{{C++17}} expected-note 0-1{{noexcept}}
struct T {};
#if __cplusplus >= 201103L
@@ -134,7 +134,7 @@ namespace dr1330 { // dr1330: 4 c++11
#endif
};
- void (A::*af1)() throw(A::T) = &A::f; // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
+ void (A::*af1)() throw(A::T) = &A::f; // expected-error 0-1{{C++17}} expected-note 0-1{{noexcept}}
void (A::*af2)() throw() = &A::f; // expected-error-re {{{{not superset|different exception spec}}}}
#if __cplusplus >= 201103L
@@ -144,7 +144,7 @@ namespace dr1330 { // dr1330: 4 c++11
// Likewise, they're instantiated separately from an enclosing class template.
template<typename U>
struct B {
- void f() throw(T, typename U::type) {} // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
+ void f() throw(T, typename U::type) {} // expected-error 0-1{{C++17}} expected-note 0-1{{noexcept}}
struct T {};
#if __cplusplus >= 201103L
@@ -161,7 +161,7 @@ namespace dr1330 { // dr1330: 4 c++11
static const int value = true;
};
- void (B<P>::*bpf1)() throw(B<P>::T, int) = &B<P>::f; // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
+ void (B<P>::*bpf1)() throw(B<P>::T, int) = &B<P>::f; // expected-error 0-1{{C++17}} expected-note 0-1{{noexcept}}
#if __cplusplus < 201103L
// expected-error@-2 {{not superset}}
// FIXME: We only delay instantiation in C++11 onwards. In C++98, something
@@ -172,7 +172,7 @@ namespace dr1330 { // dr1330: 4 c++11
// the "T has not yet been instantiated" error here, rather than giving
// confusing errors later on.
#endif
- void (B<P>::*bpf2)() throw(int) = &B<P>::f; // expected-error 0-1{{C++1z}} expected-note 0-1{{noexcept}}
+ void (B<P>::*bpf2)() throw(int) = &B<P>::f; // expected-error 0-1{{C++17}} expected-note 0-1{{noexcept}}
#if __cplusplus <= 201402L
// expected-error@-2 {{not superset}}
#else
@@ -192,9 +192,9 @@ namespace dr1330 { // dr1330: 4 c++11
static_assert(!noexcept(B<Q>().g()), "");
#endif
- template<typename T> int f() throw(typename T::error) { return 0; } // expected-error 1-4{{prior to '::'}} expected-note 0-1{{instantiation of}}
+ template<typename T> int f() throw(typename T::error) { return 0; } // expected-error 1-4{{prior to '::'}} expected-note 0-1{{prior to '::'}} expected-note 0-1{{requested here}}
#if __cplusplus > 201402L
- // expected-error@-2 0-1{{C++1z}} expected-note@-2 0-1{{noexcept}}
+ // expected-error@-2 0-1{{C++17}} expected-note@-2 0-1{{noexcept}}
#endif
// An exception-specification is needed even if the function is only used in
// an unevaluated operand.
@@ -203,12 +203,21 @@ namespace dr1330 { // dr1330: 4 c++11
decltype(f<char>()) f2; // expected-note {{instantiation of}}
bool f3 = noexcept(f<float>()); // expected-note {{instantiation of}}
#endif
- template int f<short>(); // expected-note {{instantiation of}}
+ // In C++17 onwards, substituting explicit template arguments into the
+ // function type substitutes into the exception specification (because it's
+ // part of the type). In earlier languages, we don't notice there's a problem
+ // until we've already started to instantiate.
+ template int f<short>();
+#if __cplusplus >= 201703L
+ // expected-error@-2 {{does not refer to a function template}}
+#else
+ // expected-note@-4 {{instantiation of}}
+#endif
template<typename T> struct C {
C() throw(typename T::type); // expected-error 1-2{{prior to '::'}}
#if __cplusplus > 201402L
- // expected-error@-2 0-1{{C++1z}} expected-note@-2 0-1{{noexcept}}
+ // expected-error@-2 0-1{{C++17}} expected-note@-2 0-1{{noexcept}}
#endif
};
struct D : C<void> {}; // ok
diff --git a/test/CXX/drs/dr1xx.cpp b/test/CXX/drs/dr1xx.cpp
index f5395cfe18..d62ed9f0d3 100644
--- a/test/CXX/drs/dr1xx.cpp
+++ b/test/CXX/drs/dr1xx.cpp
@@ -1,7 +1,7 @@
// 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
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
namespace dr100 { // dr100: yes
template<const char *> struct A {}; // expected-note 0-1{{declared here}}
@@ -313,7 +313,7 @@ namespace dr126 { // dr126: no
virtual void z() throw(long); // expected-error {{more lax}}
};
#else
- void f() throw(int); // expected-error {{ISO C++1z does not allow}} expected-note {{use 'noexcept}}
+ void f() throw(int); // expected-error {{ISO C++17 does not allow}} expected-note {{use 'noexcept}}
#endif
}
diff --git a/test/CXX/drs/dr20xx.cpp b/test/CXX/drs/dr20xx.cpp
new file mode 100644
index 0000000000..5819c319fd
--- /dev/null
+++ b/test/CXX/drs/dr20xx.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors \
+// RUN: -Wno-variadic-macros -Wno-c11-extensions
+// 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
+
+// expected-no-diagnostics
+
+#if __cplusplus < 201103L
+#define static_assert(...) _Static_assert(__VA_ARGS__)
+#endif
+
+namespace dr2094 { // dr2094: 5
+ struct A { int n; };
+ struct B { volatile int n; };
+ static_assert(__is_trivially_copyable(volatile int), "");
+ static_assert(__is_trivially_copyable(const volatile int), "");
+ static_assert(__is_trivially_copyable(const volatile int[]), "");
+ static_assert(__is_trivially_copyable(A), "");
+ static_assert(__is_trivially_copyable(volatile A), "");
+ static_assert(__is_trivially_copyable(const volatile A), "");
+ static_assert(__is_trivially_copyable(const volatile A[]), "");
+ static_assert(__is_trivially_copyable(B), "");
+
+ static_assert(__is_trivially_constructible(A, A const&), "");
+ static_assert(__is_trivially_constructible(B, B const&), "");
+
+ static_assert(__is_trivially_assignable(A, const A&), "");
+ static_assert(__is_trivially_assignable(B, const B&), "");
+}
diff --git a/test/CXX/drs/dr2xx.cpp b/test/CXX/drs/dr2xx.cpp
index a5677a125a..4e745ef2f4 100644
--- a/test/CXX/drs/dr2xx.cpp
+++ b/test/CXX/drs/dr2xx.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// 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
+// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// PR13819 -- __SIZE_TYPE__ is incompatible.
typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}}
@@ -984,7 +984,7 @@ namespace dr289 { // dr289: yes
namespace dr294 { // dr294: no
void f() throw(int);
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
+ // expected-error@-2 {{ISO C++17 does not allow}} expected-note@-2 {{use 'noexcept}}
#endif
int main() {
(void)static_cast<void (*)() throw()>(f); // FIXME: ill-formed in C++14 and before
@@ -1001,13 +1001,13 @@ namespace dr294 { // dr294: no
#endif
(void)static_cast<void (*)() throw(int)>(f); // FIXME: ill-formed in C++14 and before
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
+ // expected-error@-2 {{ISO C++17 does not allow}} expected-note@-2 {{use 'noexcept}}
#endif
void (*p)() throw() = f; // expected-error-re {{{{not superset|different exception specification}}}}
void (*q)() throw(int) = f;
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
+ // expected-error@-2 {{ISO C++17 does not allow}} expected-note@-2 {{use 'noexcept}}
#endif
}
}
diff --git a/test/CXX/drs/dr3xx.cpp b/test/CXX/drs/dr3xx.cpp
index a1c1c4ce61..3342148461 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 3ea226a745..1a5976eada 100644
--- a/test/CXX/drs/dr4xx.cpp
+++ b/test/CXX/drs/dr4xx.cpp
@@ -1,7 +1,7 @@
// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// FIXME: __SIZE_TYPE__ expands to 'long long' on some targets.
__extension__ typedef __SIZE_TYPE__ size_t;
@@ -507,16 +507,16 @@ namespace dr437 { // dr437: sup 1308
struct S {
void f() throw(S);
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
+ // expected-error@-2 {{ISO C++17 does not allow}} expected-note@-2 {{use 'noexcept}}
#endif
void g() throw(T<S>);
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
+ // expected-error@-2 {{ISO C++17 does not allow}} expected-note@-2 {{use 'noexcept}}
#endif
struct U;
void h() throw(U);
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
+ // expected-error@-2 {{ISO C++17 does not allow}} expected-note@-2 {{use 'noexcept}}
#endif
struct U {};
};
@@ -1202,16 +1202,15 @@ namespace dr495 { // dr495: 3.5
long n2 = s2;
}
-namespace dr496 { // dr496: no
+namespace dr496 { // dr496: sup 2094
struct A { int n; };
struct B { volatile int n; };
int check1[ __is_trivially_copyable(const int) ? 1 : -1];
- int check2[!__is_trivially_copyable(volatile int) ? 1 : -1];
+ // This checks the dr2094 behavior, not dr496
+ int check2[ __is_trivially_copyable(volatile int) ? 1 : -1];
int check3[ __is_trivially_constructible(A, const A&) ? 1 : -1];
- // FIXME: This is wrong.
int check4[ __is_trivially_constructible(B, const B&) ? 1 : -1];
int check5[ __is_trivially_assignable(A, const A&) ? 1 : -1];
- // FIXME: This is wrong.
int check6[ __is_trivially_assignable(B, const B&) ? 1 : -1];
}
diff --git a/test/CXX/drs/dr5xx.cpp b/test/CXX/drs/dr5xx.cpp
index 97b40b8b7c..5122398b7c 100644
--- a/test/CXX/drs/dr5xx.cpp
+++ b/test/CXX/drs/dr5xx.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// 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
+// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// FIXME: This is included to avoid a diagnostic with no source location
// pointing at the implicit operator new. We can't match such a diagnostic
@@ -966,7 +966,7 @@ namespace dr595 { // dr595: dup 1330
template<class T> struct X {
void f() throw(T) {}
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow}} expected-note@-2 {{use 'noexcept}}
+ // expected-error@-2 {{ISO C++17 does not allow}} expected-note@-2 {{use 'noexcept}}
#endif
};
struct S {
diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp
index fa53c9f5d2..03d75326a6 100644
--- a/test/CXX/except/except.spec/p1.cpp
+++ b/test/CXX/except/except.spec/p1.cpp
@@ -86,3 +86,12 @@ namespace PR11084 {
f<0>(); // expected-note{{in instantiation of function template specialization}}
}
}
+
+namespace FuncTmplNoexceptError {
+ int a = 0;
+ // expected-error@+1{{argument to noexcept specifier must be a constant expression}}
+ template <class T> T f() noexcept(a++){ return {};}
+ void g(){
+ f<int>();
+ }
+};
diff --git a/test/CXX/except/except.spec/p11.cpp b/test/CXX/except/except.spec/p11.cpp
index 1d0a647fb4..b7b9fcb231 100644
--- a/test/CXX/except/except.spec/p11.cpp
+++ b/test/CXX/except/except.spec/p11.cpp
@@ -1,12 +1,11 @@
// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
-// expected-no-diagnostics
// This is the "let the user shoot themselves in the foot" clause.
-void f() noexcept {
- throw 0; // no-error
+void f() noexcept { // expected-note {{function declared non-throwing here}}
+ throw 0; // expected-warning {{has a non-throwing exception specification but}}
}
-void g() throw() {
- throw 0; // no-error
+void g() throw() { // expected-note {{function declared non-throwing here}}
+ throw 0; // expected-warning {{has a non-throwing exception specification but}}
}
void h() throw(int) {
throw 0.0; // no-error
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 6d46bf5d77..4daed23bf9 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -145,19 +145,19 @@ namespace UndefinedBehavior {
constexpr int int_min = ~0x7fffffff;
constexpr int minus_int_min = -int_min; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
- constexpr int div0 = 3 / 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}}
- constexpr int mod0 = 3 % 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}}
+ constexpr int div0 = 3 / 0; // expected-error {{constant expression}} expected-note {{division by zero}}
+ constexpr int mod0 = 3 % 0; // expected-error {{constant expression}} expected-note {{division by zero}}
constexpr int int_min_div_minus_1 = int_min / -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
constexpr int int_min_mod_minus_1 = int_min % -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
- constexpr int shl_m1 = 0 << -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}}
+ constexpr int shl_m1 = 0 << -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}}
constexpr int shl_0 = 0 << 0; // ok
constexpr int shl_31 = 0 << 31; // ok
- constexpr int shl_32 = 0 << 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type 'int' (32}} expected-warning {{>= width of type}}
+ constexpr int shl_32 = 0 << 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type 'int' (32}}
constexpr int shl_unsigned_negative = unsigned(-3) << 1; // ok
constexpr int shl_unsigned_into_sign = 1u << 31; // ok
constexpr int shl_unsigned_overflow = 1024u << 31; // ok
- constexpr int shl_signed_negative = (-3) << 1; // expected-warning {{shifting a negative signed value is undefined}} // expected-error {{constant expression}} expected-note {{left shift of negative value -3}}
+ constexpr int shl_signed_negative = (-3) << 1; // expected-error {{constant expression}} expected-note {{left shift of negative value -3}}
constexpr int shl_signed_ok = 1 << 30; // ok
constexpr int shl_signed_into_sign = 1 << 31; // ok (DR1457)
constexpr int shl_signed_into_sign_2 = 0x7fffffff << 1; // ok (DR1457)
@@ -166,10 +166,10 @@ namespace UndefinedBehavior {
constexpr int shl_signed_overflow = 1024 << 31; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{requires 43 bits to represent}}
constexpr int shl_signed_ok2 = 1024 << 20; // ok
- constexpr int shr_m1 = 0 >> -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}}
+ constexpr int shr_m1 = 0 >> -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}}
constexpr int shr_0 = 0 >> 0; // ok
constexpr int shr_31 = 0 >> 31; // ok
- constexpr int shr_32 = 0 >> 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type}} expected-warning {{>= width of type}}
+ constexpr int shr_32 = 0 >> 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type}}
struct S {
int m;
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
index b9b8cd76c0..1cc1fd974c 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p8.cpp
@@ -8,7 +8,7 @@ class X0 {
(void)[this, this] () {}; // expected-error {{'this' can appear only once}}
(void)[=, foo] () {}; // expected-error {{'&' must precede a capture when}}
(void)[=, &foo] () {};
- (void)[=, this] () {}; // expected-error {{'this' cannot be explicitly captured}}
+ (void)[=, this] () {}; // expected-warning {{C++2a extension}}
(void)[&, foo] () {};
(void)[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}}
(void)[&, this] () {};
@@ -23,7 +23,7 @@ struct S2 {
void S2::f(int i) {
(void)[&, i]{ };
(void)[&, &i]{ }; // expected-error{{'&' cannot precede a capture when the capture default is '&'}}
- (void)[=, this]{ }; // expected-error{{'this' cannot be explicitly captured}}
+ (void)[=, this]{ }; // expected-warning{{C++2a extension}}
(void)[=]{ this->g(i); };
(void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
(void)[i(0), i(1)]{ }; // expected-error{{'i' can appear only once in a capture list}}
diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp
new file mode 100644
index 0000000000..79e68655b4
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t
+// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module
+
+// CHECK-DAG: @extern_var_exported = external global
+// CHECK-DAG: @inline_var_exported = linkonce_odr global
+// CHECK-DAG: @_ZW6ModuleE19static_var_exported = available_externally global i32 0,
+// CHECK-DAG: @const_var_exported = available_externally constant i32 3,
+//
+// CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external global
+// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = linkonce_odr global
+// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = available_externally global i32 0,
+// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = available_externally constant i32 3,
+
+module Module;
+
+void use() {
+ // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv
+ used_inline_exported();
+ // CHECK: declare {{.*}}@_Z18noninline_exportedv
+ noninline_exported();
+
+ (void)&extern_var_exported;
+ (void)&inline_var_exported;
+ (void)&static_var_exported; // FIXME: Should not be exported.
+ (void)&const_var_exported;
+
+ // FIXME: This symbol should not be visible here.
+ // CHECK: declare {{.*}}@_ZW6ModuleE26used_static_module_linkagev
+ used_static_module_linkage();
+
+ // CHECK: define linkonce_odr {{.*}}@_ZW6ModuleE26used_inline_module_linkagev
+ used_inline_module_linkage();
+
+ // CHECK: declare {{.*}}@_ZW6ModuleE24noninline_module_linkagev
+ noninline_module_linkage();
+
+ (void)&extern_var_module_linkage;
+ (void)&inline_var_module_linkage;
+ (void)&static_var_module_linkage; // FIXME: Should not be visible here.
+ (void)&const_var_module_linkage;
+}
diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm
new file mode 100644
index 0000000000..15d1114fb0
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s --implicit-check-not unused_inline --implicit-check-not unused_stastic_global_module
+
+// CHECK-DAG: @extern_var_global_module = external global
+// CHECK-DAG: @inline_var_global_module = linkonce_odr global
+// CHECK-DAG: @_ZL24static_var_global_module = internal global
+// CHECK-DAG: @_ZL23const_var_global_module = internal constant
+//
+// For ABI compatibility, these symbols do not include the module name.
+// CHECK-DAG: @extern_var_exported = external global
+// FIXME: Should this be 'weak_odr global'? Presumably it must be, since we
+// can discard this global and its initializer (if any), and other TUs are not
+// permitted to run the initializer for this variable.
+// CHECK-DAG: @inline_var_exported = linkonce_odr global
+// CHECK-DAG: @_ZW6ModuleE19static_var_exported = global
+// CHECK-DAG: @const_var_exported = constant
+//
+// CHECK-DAG: @_ZW6ModuleE25extern_var_module_linkage = external global
+// FIXME: Should this be 'weak_odr global'? Presumably it must be, since we
+// can discard this global and its initializer (if any), and other TUs are not
+// permitted to run the initializer for this variable.
+// CHECK-DAG: @_ZW6ModuleE25inline_var_module_linkage = linkonce_odr global
+// CHECK-DAG: @_ZW6ModuleE25static_var_module_linkage = global
+// CHECK-DAG: @_ZW6ModuleE24const_var_module_linkage = constant
+//
+// CHECK-DAG: @_ZW6ModuleE25unused_var_module_linkage = global i32 4
+// CHECK-DAG: @_ZW6ModuleE32unused_static_var_module_linkage = global i32 5
+// CHECK-DAG: @_ZW6ModuleE31unused_const_var_module_linkage = constant i32 7
+
+static void unused_static_global_module() {}
+static void used_static_global_module() {}
+
+inline void unused_inline_global_module() {}
+inline void used_inline_global_module() {}
+
+extern int extern_var_global_module;
+inline int inline_var_global_module;
+static int static_var_global_module;
+const int const_var_global_module = 3;
+
+// CHECK: define void {{.*}}@_Z23noninline_global_modulev
+void noninline_global_module() {
+ // FIXME: This should be promoted to module linkage and given a
+ // module-mangled name, if it's called from an inline function within
+ // the module interface.
+ // (We should try to avoid this when it's not reachable from outside
+ // the module interface unit.)
+ // CHECK: define internal {{.*}}@_ZL25used_static_global_modulev
+ used_static_global_module();
+ // CHECK: define linkonce_odr {{.*}}@_Z25used_inline_global_modulev
+ used_inline_global_module();
+
+ (void)&extern_var_global_module;
+ (void)&inline_var_global_module;
+ (void)&static_var_global_module;
+ (void)&const_var_global_module;
+}
+
+export module Module;
+
+export {
+ // FIXME: These should be ill-formed: you can't export an internal linkage
+ // symbol, per [dcl.module.interface]p2.
+ // CHECK: define void {{.*}}@_ZW6ModuleE22unused_static_exportedv
+ static void unused_static_exported() {}
+ // CHECK: define void {{.*}}@_ZW6ModuleE20used_static_exportedv
+ static void used_static_exported() {}
+
+ inline void unused_inline_exported() {}
+ inline void used_inline_exported() {}
+
+ extern int extern_var_exported;
+ inline int inline_var_exported;
+ // FIXME: This should be ill-formed: you can't export an internal linkage
+ // symbol.
+ static int static_var_exported;
+ const int const_var_exported = 3;
+
+ // CHECK: define void {{.*}}@_Z18noninline_exportedv
+ void noninline_exported() {
+ used_static_exported();
+ // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv
+ used_inline_exported();
+
+ (void)&extern_var_exported;
+ (void)&inline_var_exported;
+ (void)&static_var_exported;
+ (void)&const_var_exported;
+ }
+}
+
+// FIXME: Ideally we wouldn't emit this as its name is not visible outside this
+// TU, but this module interface might contain a template that can use this
+// function so we conservatively emit it for now.
+// CHECK: define void {{.*}}@_ZW6ModuleE28unused_static_module_linkagev
+static void unused_static_module_linkage() {}
+// CHECK: define void {{.*}}@_ZW6ModuleE26used_static_module_linkagev
+static void used_static_module_linkage() {}
+
+inline void unused_inline_module_linkage() {}
+inline void used_inline_module_linkage() {}
+
+extern int extern_var_module_linkage;
+inline int inline_var_module_linkage;
+static int static_var_module_linkage;
+const int const_var_module_linkage = 3;
+
+// CHECK: define void {{.*}}@_ZW6ModuleE24noninline_module_linkagev
+void noninline_module_linkage() {
+ used_static_module_linkage();
+ // CHECK: define linkonce_odr {{.*}}@_ZW6ModuleE26used_inline_module_linkagev
+ used_inline_module_linkage();
+
+ (void)&extern_var_module_linkage;
+ (void)&inline_var_module_linkage;
+ (void)&static_var_module_linkage;
+ (void)&const_var_module_linkage;
+}
+
+int unused_var_module_linkage = 4;
+static int unused_static_var_module_linkage = 5;
+inline int unused_inline_var_module_linkage = 6;
+const int unused_const_var_module_linkage = 7;
+
+struct a {
+ struct b {};
+ struct c {};
+};
+// CHECK: define void @_ZW6ModuleE1fW_0EN1a1bEW_0ENS_1cE(
+void f(a::b, a::c) {}
diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp
new file mode 100644
index 0000000000..5e9f7ecf5b
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t
+// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module
+
+// CHECK-DAG: @extern_var_exported = external global
+// CHECK-DAG: @inline_var_exported = linkonce_odr global
+// CHECK-DAG: @_ZW6ModuleE19static_var_exported = available_externally global i32 0
+// CHECK-DAG: @const_var_exported = available_externally constant i32 3
+
+import Module;
+
+void use() {
+ // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv
+ used_inline_exported();
+ // CHECK: declare {{.*}}@_Z18noninline_exportedv
+ noninline_exported();
+
+ (void)&extern_var_exported;
+ (void)&inline_var_exported;
+ (void)&static_var_exported;
+ (void)&const_var_exported;
+
+ // Module-linkage declarations are not visible here.
+}
diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp
new file mode 100644
index 0000000000..cceca5106c
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.def.odr/p6/global-vs-module.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s
+// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s -DEXPORT
+// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s -DUSING
+
+#ifndef NO_GLOBAL
+extern int var; // expected-note {{previous declaration is here}}
+int func(); // expected-note {{previous declaration is here}}
+struct str; // expected-note {{previous declaration is here}}
+using type = int;
+
+template<typename> extern int var_tpl; // expected-note {{previous declaration is here}}
+template<typename> int func_tpl(); // expected-note-re {{{{previous declaration is here|target of using declaration}}}}
+template<typename> struct str_tpl; // expected-note {{previous declaration is here}}
+template<typename> using type_tpl = int; // expected-note {{previous declaration is here}}
+
+typedef int type;
+namespace ns { using ::func; }
+namespace ns_alias = ns;
+#endif
+
+export module M;
+
+#ifdef USING
+using ::var;
+using ::func;
+using ::str;
+using ::type;
+using ::var_tpl;
+using ::func_tpl; // expected-note {{using declaration}}
+using ::str_tpl;
+using ::type_tpl;
+#endif
+
+#ifdef EXPORT
+export {
+#endif
+
+extern int var; // expected-error {{declaration of 'var' in module M follows declaration in the global module}}
+int func(); // expected-error {{declaration of 'func' in module M follows declaration in the global module}}
+struct str; // expected-error {{declaration of 'str' in module M follows declaration in the global module}}
+using type = int;
+
+template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module M follows declaration in the global module}}
+// FIXME: Is this the right diagnostic in the -DUSING case?
+template<typename> int func_tpl(); // expected-error-re {{{{declaration of 'func_tpl' in module M follows declaration in the global module|conflicts with target of using declaration}}}}
+template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module M follows declaration in the global module}}
+template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module M follows declaration in the global module}}
+
+typedef int type;
+namespace ns { using ::func; }
+namespace ns_alias = ns;
+
+#ifdef EXPORT
+}
+#endif
diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp
new file mode 100644
index 0000000000..f58506dd9c
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-global.cpp
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-ts -emit-module-interface -std=c++17 %S/global-vs-module.cpp -o %t -DNO_GLOBAL -DEXPORT
+// RUN: %clang_cc1 -fmodules-ts -verify -std=c++17 %s -fmodule-file=%t
+
+import M;
+
+extern int var; // expected-error {{declaration of 'var' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:38 {{previous}}
+int func(); // expected-error {{declaration of 'func' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:39 {{previous}}
+struct str; // expected-error {{declaration of 'str' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:40 {{previous}}
+using type = int;
+
+template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:43 {{previous}}
+template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:45 {{previous}}
+template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:46 {{previous}}
+template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in the global module follows declaration in module M}} expected-note@global-vs-module.cpp:47 {{previous}}
+
+typedef int type;
+namespace ns { using ::func; }
+namespace ns_alias = ns;
diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp
new file mode 100644
index 0000000000..39e210c4ad
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.def.odr/p6/module-vs-module.cpp
@@ -0,0 +1,44 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+//
+// Some of the following tests intentionally have no -verify in their RUN
+// lines; we are testing that those cases do not produce errors.
+//
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %S/global-vs-module.cpp -emit-module-interface -o %t/M.pcm -DNO_GLOBAL -DEXPORT
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -DMODULE_INTERFACE -verify
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -DMODULE_INTERFACE -DNO_IMPORT
+//
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -emit-module-interface -o %t/N.pcm -DMODULE_INTERFACE -DNO_ERRORS
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N.pcm -verify
+// FIXME: Once we start importing "import" declarations properly, this should
+// be rejected (-verify should be added to the following line).
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N.pcm -DNO_IMPORT
+//
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/M.pcm -emit-module-interface -o %t/N-no-M.pcm -DMODULE_INTERFACE -DNO_ERRORS -DNO_IMPORT
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N-no-M.pcm -verify
+// RUN: %clang_cc1 -fmodules-ts -std=c++17 %s -fmodule-file=%t/N-no-M.pcm -DNO_IMPORT
+
+#ifdef MODULE_INTERFACE
+export
+#endif
+module N;
+
+#ifndef NO_IMPORT
+import M;
+#endif
+
+#ifndef NO_ERRORS
+extern int var; // expected-error {{declaration of 'var' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:38 {{previous}}
+int func(); // expected-error {{declaration of 'func' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:39 {{previous}}
+struct str; // expected-error {{declaration of 'str' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:40 {{previous}}
+using type = int;
+
+template<typename> extern int var_tpl; // expected-error {{declaration of 'var_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:43 {{previous}}
+template<typename> int func_tpl(); // expected-error {{declaration of 'func_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:45 {{previous}}
+template<typename> struct str_tpl; // expected-error {{declaration of 'str_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:46 {{previous}}
+template<typename> using type_tpl = int; // expected-error {{declaration of 'type_tpl' in module N follows declaration in module M}} expected-note@global-vs-module.cpp:47 {{previous}}
+
+typedef int type;
+namespace ns { using ::func; }
+namespace ns_alias = ns;
+#endif
diff --git a/test/CXX/modules-ts/basic/basic.link/module-declaration.cpp b/test/CXX/modules-ts/basic/basic.link/module-declaration.cpp
new file mode 100644
index 0000000000..feb0afdda0
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.link/module-declaration.cpp
@@ -0,0 +1,56 @@
+// Tests for module-declaration syntax.
+//
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: echo 'export module x; int a, b;' > %t/x.cppm
+// RUN: echo 'export module x.y; int c;' > %t/x.y.cppm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %t/x.cppm -o %t/x.pcm
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface -fmodule-file=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
+//
+// Module implementation for unknown and known module. (The former is ill-formed.)
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=1 -DEXPORT= -DPARTITION= -DMODULE_NAME=z
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=2 -DEXPORT= -DPARTITION= -DMODULE_NAME=x
+//
+// Module interface for unknown and known module. (The latter is ill-formed due to
+// redefinition.)
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=3 -DEXPORT=export -DPARTITION= -DMODULE_NAME=z
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=4 -DEXPORT=export -DPARTITION= -DMODULE_NAME=x
+//
+// Defining a module partition.
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=5 -DEXPORT=export -DPARTITION=partition -DMODULE_NAME=z
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=6 -DEXPORT= -DPARTITION=partition -DMODULE_NAME=z
+//
+// Miscellaneous syntax.
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=7 -DEXPORT= -DPARTITION=elderberry -DMODULE_NAME=z
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=8 -DEXPORT=export -DPARTITION= -DMODULE_NAME='z [[]]'
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=9 -DEXPORT=export -DPARTITION= -DMODULE_NAME='z [[fancy]]'
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
+// RUN: -DTEST=10 -DEXPORT=export -DPARTITION= -DMODULE_NAME='z [[maybe_unused]]'
+
+EXPORT module PARTITION MODULE_NAME;
+#if TEST == 4
+// expected-error@-2 {{redefinition of module 'x'}}
+// expected-note-re@module-declaration.cpp:* {{loaded from '{{.*[/\\]}}x.pcm'}}
+#elif TEST == 6
+// expected-error@-5 {{module partition must be declared 'export'}}
+#elif TEST == 7
+// expected-error@-7 {{expected ';'}} expected-error@-7 {{requires a type specifier}} expected-error@-7 {{definition of module 'elderberry' is not available}}
+#elif TEST == 9
+// expected-warning@-9 {{unknown attribute 'fancy' ignored}}
+#elif TEST == 10
+// expected-error-re@-11 {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
+#elif TEST == 1
+// expected-error@-13 {{definition of module 'z' is not available}}
+#else
+// expected-no-diagnostics
+#endif
diff --git a/test/CXX/modules-ts/basic/basic.link/p2/module.cpp b/test/CXX/modules-ts/basic/basic.link/p2/module.cpp
new file mode 100644
index 0000000000..3fc6044d8e
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.link/p2/module.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts %S/module.cppm -emit-module-interface -o %t
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify
+// expected-no-diagnostics
+module M;
+
+// FIXME: Use of internal linkage entities should be rejected.
+void use_from_module_impl() {
+ external_linkage_fn();
+ module_linkage_fn();
+ internal_linkage_fn();
+ (void)external_linkage_class{};
+ (void)module_linkage_class{};
+ (void)internal_linkage_class{};
+ (void)external_linkage_var;
+ (void)module_linkage_var;
+ (void)internal_linkage_var;
+}
diff --git a/test/CXX/modules-ts/basic/basic.link/p2/module.cppm b/test/CXX/modules-ts/basic/basic.link/p2/module.cppm
new file mode 100644
index 0000000000..bb261700db
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.link/p2/module.cppm
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts %s -verify
+// expected-no-diagnostics
+export module M;
+
+export int external_linkage_var;
+int module_linkage_var;
+static int internal_linkage_var;
+
+export void external_linkage_fn() {}
+void module_linkage_fn() {}
+static void internal_linkage_fn() {}
+
+export struct external_linkage_class {};
+struct module_linkage_class {};
+namespace {
+ struct internal_linkage_class {};
+}
+
+void use() {
+ external_linkage_fn();
+ module_linkage_fn();
+ internal_linkage_fn();
+ (void)external_linkage_class{};
+ (void)module_linkage_class{};
+ (void)internal_linkage_class{};
+ (void)external_linkage_var;
+ (void)module_linkage_var;
+ (void)internal_linkage_var;
+}
diff --git a/test/CXX/modules-ts/basic/basic.link/p2/other.cpp b/test/CXX/modules-ts/basic/basic.link/p2/other.cpp
new file mode 100644
index 0000000000..8370777e7e
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.link/p2/other.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts %S/module.cppm -emit-module-interface -o %t
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify
+import M;
+
+void use_from_module_impl() {
+ external_linkage_fn();
+ module_linkage_fn(); // expected-error {{undeclared identifier}}
+ internal_linkage_fn(); // expected-error {{undeclared identifier}}
+ (void)external_linkage_class{};
+ (void)module_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}}
+ (void)internal_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}}
+ // expected-note@module.cppm:9 {{here}}
+ (void)external_linkage_var;
+ (void)module_linkage_var; // expected-error {{undeclared identifier}}
+ (void)internal_linkage_var; // expected-error {{undeclared identifier}}
+}
diff --git a/test/CXX/modules-ts/basic/basic.link/p3.cppm b/test/CXX/modules-ts/basic/basic.link/p3.cppm
new file mode 100644
index 0000000000..8ff141c5ff
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.link/p3.cppm
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fmodules-ts -triple x86_64-linux %s -emit-module-interface -o %t
+// RUN: %clang_cc1 -fmodules-ts -triple x86_64-linux -x pcm %t -emit-llvm -o - | FileCheck %s
+
+export module M;
+
+// CHECK-DAG: @_ZW1ME1a = constant i32 1
+const int a = 1;
+// CHECK-DAG: @b = constant i32 2
+export const int b = 2;
+
+export int f() { return a + b; }
diff --git a/test/CXX/modules-ts/basic/basic.search/module-import.cpp b/test/CXX/modules-ts/basic/basic.search/module-import.cpp
new file mode 100644
index 0000000000..0b5f39d072
--- /dev/null
+++ b/test/CXX/modules-ts/basic/basic.search/module-import.cpp
@@ -0,0 +1,39 @@
+// Tests for imported module search.
+//
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: echo 'export module x; int a, b;' > %t/x.cppm
+// RUN: echo 'export module y; import x; int c;' > %t/y.cppm
+// RUN: echo 'export module z; import y; int d;' > %t/z.cppm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %t/x.cppm -o %t/x.pcm
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface -fmodule-file=%t/x.pcm %t/y.cppm -o %t/y.pcm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.pcm -verify %s \
+// RUN: -DMODULE_NAME=x
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/y.pcm -verify %s \
+// RUN: -DMODULE_NAME=y
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=x=%t/x.pcm -verify %s \
+// RUN: -DMODULE_NAME=x
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=y=%t/y.pcm -verify %s \
+// RUN: -DMODULE_NAME=y
+//
+// RUN: mv %t/x.pcm %t/a.pcm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=x=%t/a.pcm -verify %s \
+// RUN: -DMODULE_NAME=x
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/y.pcm -fmodule-file=x=%t/a.pcm -verify %s \
+// RUN: -DMODULE_NAME=y
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=y=%t/y.pcm -fmodule-file=x=%t/a.pcm -verify %s \
+// RUN: -DMODULE_NAME=y
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface -fmodule-file=y=%t/y.pcm -fmodule-file=x=%t/a.pcm %t/z.cppm -o %t/z.pcm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=z=%t/z.pcm -fmodule-file=y=%t/y.pcm -fmodule-file=x=%t/a.pcm -verify %s \
+// RUN: -DMODULE_NAME=z
+//
+
+import MODULE_NAME;
+
+// expected-no-diagnostics
diff --git a/test/CodeGenCXX/modules-ts.cppm b/test/CXX/modules-ts/codegen-basics.cppm
index 90f6b5319e..a85e12df26 100644
--- a/test/CodeGenCXX/modules-ts.cppm
+++ b/test/CXX/modules-ts/codegen-basics.cppm
@@ -1,23 +1,21 @@
// 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;
+export module FooBar;
export {
- // CHECK-LABEL: define i32 @_Z1fv(
+ // CHECK-DAG: define i32 @_Z1fv(
int f() { return 0; }
}
-// CHECK-LABEL: define weak_odr void @_Z2f2v(
+// CHECK-DAG: define weak_odr void @_ZW6FooBarE2f2v(
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.
-
-// FIXME: Mangle non-exported symbols so they don't collide with
-// non-exported symbols from other modules?
+// CHECK-DAG: define void @_ZW6FooBarE2f3v(
+static void f3() {}
+export void use_f3() { f3(); }
-// FIXME: Formally-internal-linkage symbols that are used from an exported
-// symbol need a mangled name and external linkage.
+// FIXME: Emit global variables and their initializers with this TU.
+// Emit an initialization function that other TUs can call, with guard variable?
// FIXME: const-qualified variables don't have implicit internal linkage when owned by a module.
diff --git a/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp b/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp
new file mode 100644
index 0000000000..15900c1f6a
--- /dev/null
+++ b/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp
@@ -0,0 +1,49 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: echo 'export module x; export int a, b;' > %t/x.cppm
+// RUN: echo 'export module x.y; export int c;' > %t/x.y.cppm
+// RUN: echo 'export module a.b; export int d;' > %t/a.b.cppm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %t/x.cppm -o %t/x.pcm
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface -fmodule-file=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %t/a.b.cppm -o %t/a.b.pcm
+//
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -fmodule-file=%t/a.b.pcm -verify %s \
+// RUN: -DMODULE_NAME=z -DINTERFACE
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -fmodule-file=%t/a.b.pcm -verify %s \
+// RUN: -DMODULE_NAME=a.b
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -fmodule-file=%t/a.b.pcm -verify %s \
+// RUN: -DMODULE_X -DMODULE_NAME=x
+
+#ifdef INTERFACE
+export
+#endif
+module MODULE_NAME;
+
+int use_1 = a;
+#if !MODULE_X
+// expected-error@-2 {{declaration of 'a' must be imported from module 'x' before it is required}}
+// expected-note@x.cppm:1 {{here}}
+#endif
+
+import x;
+
+int use_2 = b; // ok
+
+// There is no relation between module x and module x.y.
+int use_3 = c; // expected-error {{declaration of 'c' must be imported from module 'x.y'}}
+ // expected-note@x.y.cppm:1 {{here}}
+
+import x [[]];
+import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}
+import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}}
+import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'noreturn' ignored}}
+
+import x.y;
+import a.b; // Does not imply existence of module a.
+import x.; // expected-error {{expected a module name after 'import'}}
+import .x; // expected-error {{expected a module name after 'import'}}
+
+int use_4 = c; // ok
+
+import blarg; // expected-error {{module 'blarg' not found}}
diff --git a/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp b/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp
new file mode 100644
index 0000000000..68f2570dd3
--- /dev/null
+++ b/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fmodules-ts %s -verify -o /dev/null
+// RUN: %clang_cc1 -fmodules-ts %s -DINTERFACE -verify -emit-module-interface -o %t
+// RUN: %clang_cc1 -fmodules-ts %s -DIMPLEMENTATION -verify -fmodule-file=%t -o /dev/null
+//
+// RUN: %clang_cc1 -fmodules-ts %s -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null
+// RUN: %clang_cc1 -fmodules-ts %s -DINTERFACE -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null
+// RUN: %clang_cc1 -fmodules-ts %s -DIMPLEMENTATION -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null
+
+#if INTERFACE
+// expected-no-diagnostics
+export module A;
+#elif IMPLEMENTATION
+module A;
+ #ifdef BUILT_AS_INTERFACE
+ // expected-error@-2 {{missing 'export' specifier in module declaration while building module interface}}
+ #define INTERFACE
+ #endif
+#else
+ #ifdef BUILT_AS_INTERFACE
+ // expected-error@1 {{missing 'export module' declaration in module interface unit}}
+ #endif
+#endif
+
+#ifndef INTERFACE
+export int b; // expected-error {{export declaration can only be used within a module interface unit}}
+#else
+export int a;
+#endif
diff --git a/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp b/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp
new file mode 100644
index 0000000000..2393aa1843
--- /dev/null
+++ b/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts -verify %s -DFOO=export -DBAR=export
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts -verify %s -DFOO=export -DBAR=
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s -DFOO=export -emit-module-interface -o %t
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s -fmodule-file=%t -DFOO=
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s -fmodule-file=%t -DBAR=export
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts -verify %s -fmodule-file=%t -DFOO= -DBAR=export
+
+#ifdef FOO
+FOO module foo; // expected-note {{previous module declaration is here}}
+#endif
+
+#ifdef BAR
+BAR module bar; // expected-error {{translation unit contains multiple module declarations}}
+#endif
diff --git a/test/CXX/modules-ts/dcl.dcl/dcl.module/p2.cpp b/test/CXX/modules-ts/dcl.dcl/dcl.module/p2.cpp
new file mode 100644
index 0000000000..992715e6b1
--- /dev/null
+++ b/test/CXX/modules-ts/dcl.dcl/dcl.module/p2.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fmodules-ts -verify %s
+
+// A named module shall contain exactly one module interface unit.
+module M; // expected-error {{definition of module 'M' is not available; use -fmodule-file= to specify path to precompiled module interface}}
+
+// FIXME: How do we ensure there is not more than one?
diff --git a/test/CXX/modules-ts/dcl.dcl/dcl.module/p5.cpp b/test/CXX/modules-ts/dcl.dcl/dcl.module/p5.cpp
new file mode 100644
index 0000000000..734b89173d
--- /dev/null
+++ b/test/CXX/modules-ts/dcl.dcl/dcl.module/p5.cpp
@@ -0,0 +1,33 @@
+// RUN: rm -f %t
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t -DINTERFACE
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify -DIMPLEMENTATION
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify -DEARLY_IMPLEMENTATION
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify -DUSER
+
+// expected-no-diagnostics
+
+#ifdef USER
+import Foo;
+#endif
+
+#ifdef EARLY_IMPLEMENTATION
+module Foo;
+#endif
+
+template<typename T> struct type_template {
+ typedef T type;
+ void f(type);
+};
+
+template<typename T> void type_template<T>::f(type) {}
+
+template<int = 0, typename = int, template<typename> class = type_template>
+struct default_template_args {};
+
+#ifdef INTERFACE
+export module Foo;
+#endif
+
+#ifdef IMPLEMENTATION
+module Foo;
+#endif
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 fad5bf9a72..a933f62a30 100644
--- a/test/CXX/over/over.match/over.match.best/p1.cpp
+++ b/test/CXX/over/over.match/over.match.best/p1.cpp
@@ -25,13 +25,13 @@ namespace deduction_guide_example {
// 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>;
+ 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 b{a, 0}; // uses the implicit ctor that is more specialized
A<int> *pa = &a;
- A<A<int>&> *pb = &b;
+ A<int> *pb = &b;
}
// Partial ordering of function template specializations will be tested
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
index fe1b6a63d7..cb9541caad 100644
--- 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
@@ -6,9 +6,10 @@ namespace Explicit {
template<typename T> struct A {
A(T);
A(T*);
+ A(...);
};
template<typename T> A(T) -> A<T>;
- template<typename T> explicit A(T*) -> A<T>; // expected-note {{explicit}}
+ template<typename T> explicit A(T*) -> A<T**>; // expected-note {{explicit}}
int *p;
A a(p);
@@ -16,10 +17,71 @@ namespace Explicit {
A c{p};
A d = {p}; // expected-error {{selected an explicit deduction guide}}
- using X = A<int>;
- using Y = A<int*>;
+ using X = A<int**>;
+ using Y = A<int>; // uses the implicit guide, being more specialized than the eligible user-defined deduction guides.
using X = decltype(a);
using Y = decltype(b);
using X = decltype(c);
}
+
+
+namespace std {
+ template<typename T> struct initializer_list {
+ const T *ptr;
+ __SIZE_TYPE__ size;
+ initializer_list();
+ };
+}
+
+namespace p0702r1 {
+ template<typename T> struct X { // expected-note {{candidate}}
+ X(std::initializer_list<T>); // expected-note {{candidate}}
+ };
+
+ X xi = {0};
+ X xxi = {xi};
+ extern X<int> xi;
+ // Prior to P0702R1, this is X<X<int>>.
+ extern X<int> xxi;
+
+ struct Y : X<int> {};
+ Y y {{0}};
+ X xy {y};
+ extern X<int> xy;
+
+ struct Z : X<int>, X<float> {};
+ Z z = {{0}, {0.0f}};
+ // This is not X<Z> even though that would work. Instead, it's ambiguous
+ // between X<int> and X<float>.
+ X xz = {z}; // expected-error {{no viable constructor or deduction guide}}
+}
+namespace pr34970 {
+//https://bugs.llvm.org/show_bug.cgi?id=34970
+
+template <typename X, typename Y> struct IsSame {
+ static constexpr bool value = false;
+};
+
+template <typename Z> struct IsSame<Z, Z> {
+ static constexpr bool value = true;
+};
+
+template <typename T> struct Optional {
+ template <typename U> Optional(U&&) { }
+};
+
+template <typename A> Optional(A) -> Optional<A>;
+
+int main() {
+ Optional opt(1729);
+ Optional dupe(opt);
+
+ static_assert(IsSame<decltype(opt), Optional<int>>::value);
+ static_assert(IsSame<decltype(dupe), Optional<int>>::value);
+ static_assert(!IsSame<decltype(dupe), Optional<Optional<int>>>::value);
+ return 0;
+}
+
+
+} \ No newline at end of file
diff --git a/test/CXX/special/class.dtor/p5-implicit.cpp b/test/CXX/special/class.dtor/p5-implicit.cpp
new file mode 100644
index 0000000000..703be15b70
--- /dev/null
+++ b/test/CXX/special/class.dtor/p5-implicit.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++11 %s -ast-dump | FileCheck %s
+
+struct A { ~A() = delete; };
+// CHECK-LABEL: CXXRecordDecl {{.*}} struct A
+// CHECK: Destructor trivial user_declared
+
+struct B : A {};
+// CHECK-LABEL: CXXRecordDecl {{.*}} struct B
+// CHECK: Destructor trivial needs_overload_resolution
+
+struct C : B {};
+// CHECK-LABEL: CXXRecordDecl {{.*}} struct C
+// CHECK: Destructor trivial needs_overload_resolution
+
+struct D { ~D(); };
+struct E : D {};
+union U {
+ E e;
+};
+// CHECK-LABEL: CXXRecordDecl {{.*}} union U
+// CHECK: Destructor non_trivial needs_implicit defaulted_is_deleted
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 8c4f36c0ff..ad60868358 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
struct pr12960 {
int begin;
@@ -125,7 +125,7 @@ void g() {
};
for (auto a : Differ())
#if __cplusplus <= 201402L
- // expected-warning@-2 {{'begin' and 'end' returning different types ('int *' and 'null_t') is a C++1z extension}}
+ // expected-warning@-2 {{'begin' and 'end' returning different types ('int *' and 'null_t') is a C++17 extension}}
// expected-note@-6 {{selected 'begin' function with iterator type 'int *'}}
// expected-note@-6 {{selected 'end' function with iterator type 'null_t'}}
#endif
diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
index 1e061fa33d..a41ea6b5e1 100644
--- a/test/CXX/temp/temp.decls/temp.mem/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
@@ -77,3 +77,16 @@ void test_X0(X0 x0, const X0 &x0c) {
x0.operator float *();
x0c.operator const char*();
}
+
+namespace PR14211 {
+template <class U> struct X {
+ void foo(U){}
+ template <class T> void foo(T){}
+
+ template <class T> void bar(T){}
+ void bar(U){}
+};
+
+template void X<int>::foo(int);
+template void X<int>::bar(int);
+}
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
index d8294a1f15..1681325f2e 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fexceptions -fcxx-exceptions -verify %s
template<typename... Types> struct tuple;
template<int I> struct int_c;
@@ -174,6 +175,7 @@ int check_temp_arg_1[is_same<tuple_of_ints<1, 2, 3, 4, 5>::type,
tuple<int_c<1>, int_c<2>, int_c<3>, int_c<4>,
int_c<5>>>::value? 1 : -1];
+#if __cplusplus < 201703L
// In a dynamic-exception-specification (15.4); the pattern is a type-id.
template<typename ...Types>
struct f_with_except {
@@ -191,3 +193,99 @@ struct check_f_with_except_2 : f_with_except<int, float> {
struct check_f_with_except_3 : f_with_except<int, float> {
virtual void f() throw(int, float, double); // expected-error{{exception specification of overriding function is more lax than base version}}
};
+#endif
+
+namespace PackExpansionWithinLambda {
+ void swallow(...);
+ template<typename ...T, typename ...U> void f(U ...u) {
+ swallow([=] {
+ // C++17 [temp.variadic]p4:
+ // Pack expansions can occur in the following contexts:
+
+ // - in a function parameter pack
+ void g(T...);
+
+#if __cplusplus >= 201703L
+ struct A : T... {
+ // - in a using-declaration
+ using T::x...;
+ using typename T::U...;
+ };
+#endif
+
+ // - in a template parameter pack that is a pack expansion
+ // FIXME: We do not support any way to reach this case yet.
+
+ // - in an initializer-list
+ int arr[] = {T().x...};
+
+ // - in a base-specifier-list
+ struct B : T... {
+ // - in a mem-initializer-list
+ B() : T{0}... {}
+ };
+
+ // - in a template-argument-list
+ f<T...>();
+
+ // - in an attribute-list
+ // FIXME: We do not support any such attributes yet.
+
+ // - in an alignment-specifier
+ alignas(T...) int y;
+
+ // - in a capture-list
+ [](T ...t) { [t...]{}(); } (T()...);
+
+ // - in a sizeof... expression
+ const int k1 = sizeof...(T);
+
+#if __cplusplus >= 201703L
+ // - in a fold-expression
+ const int k2 = ((sizeof(T)/sizeof(T)) + ...);
+
+ static_assert(k1 == k2);
+#endif
+
+ // Trigger clang to look in here for unexpanded packs.
+ U u;
+ } ...);
+ }
+
+ template<typename ...T> void nested() {
+ swallow([=] {
+ [](T ...t) { [t]{}(); } (T()...); // expected-error {{unexpanded parameter pack 't'}}
+ }...); // expected-error {{does not contain any unexpanded}}
+ }
+
+ template <typename ...T> void g() {
+ // Check that we do detect the above cases when the pack is not expanded.
+ swallow([=] { void h(T); }); // expected-error {{unexpanded parameter pack 'T'}}
+ swallow([=] { struct A : T {}; }); // expected-error {{unexpanded parameter pack 'T'}}
+#if __cplusplus >= 201703L
+ swallow([=] { struct A : T... { using T::x; }; }); // expected-error {{unexpanded parameter pack 'T'}}
+ swallow([=] { struct A : T... { using typename T::U; }; }); // expected-error {{unexpanded parameter pack 'T'}}
+#endif
+
+ swallow([=] { int arr[] = {T().x}; }); // expected-error {{unexpanded parameter pack 'T'}}
+ swallow([=] { struct B : T... { B() : T{0} {} }; }); // expected-error {{unexpanded parameter pack 'T'}}
+ swallow([=] { f<T>(); }); // expected-error {{unexpanded parameter pack 'T'}}
+ swallow([=] { alignas(T) int y; }); // expected-error {{unexpanded parameter pack 'T'}}
+ swallow([=] { [](T ...t) {
+ [t]{}(); // expected-error {{unexpanded parameter pack 't'}}
+ } (T()...); });
+ }
+
+ struct T { int x; using U = int; };
+ void g() { f<T>(1, 2, 3); }
+
+ template<typename ...T, typename ...U> void pack_in_lambda(U ...u) { // expected-note {{here}}
+ // FIXME: Move this test into 'f' above once we support this syntax.
+ []<T *...v, template<T *> typename ...U>(U<v> ...uv) {}; // expected-error {{expected body of lambda}} expected-error {{does not refer to a value}}
+ }
+
+ template<typename ...T> void pack_expand_attr() {
+ // FIXME: Move this test into 'f' above once we support this.
+ [[gnu::aligned(alignof(T))...]] int x; // expected-error {{cannot be used as an attribute pack}} expected-error {{unexpanded}}
+ }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
index e7b665a341..357ea66403 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
@@ -46,10 +46,11 @@ namespace noexcept_conversion {
template <class T> int h(T *, T *); // expected-note {{deduced conflicting types for parameter 'T' ('void () noexcept' vs. 'void ()')}}
int x = h(g1, g2); // expected-error {{no matching function}}
- // FIXME: It seems like a defect that B is not deducible here.
- template<bool B> int i(void () noexcept(B)); // expected-note 2{{couldn't infer template argument 'B'}}
- int i1 = i(g1); // expected-error {{no matching function}}
- int i2 = i(g2); // expected-error {{no matching function}}
+ // We consider it a defect that deduction does not support the following.
+ // FIXME: Check that the defect is resolved as we expect.
+ template<bool B> int i(void () noexcept(B));
+ int i1 = i(g1);
+ int i2 = i(g2);
}
#else
// expected-no-diagnostics
diff --git a/test/CodeCompletion/crash-func-init.cpp b/test/CodeCompletion/crash-func-init.cpp
new file mode 100644
index 0000000000..6d84b843ea
--- /dev/null
+++ b/test/CodeCompletion/crash-func-init.cpp
@@ -0,0 +1,4 @@
+int (*foo(int a))(flo
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:1:21 %s -o - \
+// RUN: | FileCheck %s
+// CHECK: COMPLETION: float
diff --git a/test/CodeCompletion/functions.cpp b/test/CodeCompletion/functions.cpp
index 036ed29e4a..aa303f29eb 100644
--- a/test/CodeCompletion/functions.cpp
+++ b/test/CodeCompletion/functions.cpp
@@ -4,5 +4,5 @@ void f(float x, float y...);
void test() {
::
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:5 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
- // CHECK-CC1: f(<#int i#>{#, <#int j#>{#, <#int k#>#}#})
+ // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#})
// CHECK-CC1: f(<#float x#>, <#float y, ...#>)
diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp
index 8195f764fb..a0dc7b4856 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,104 @@ 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
+
+
+template<typename T>
+class BaseTemplate {
+public:
+ T baseTemplateFunction();
+
+ T baseTemplateField;
+};
+
+template<typename T, typename S>
+class TemplateClass: public Base1 , public BaseTemplate<T> {
+public:
+ T function() { }
+ T field;
+
+ void overload1(const T &);
+ void overload1(const S &);
+};
+
+template<typename T, typename S>
+void completeDependentMembers(TemplateClass<T, S> &object,
+ TemplateClass<int, S> *object2) {
+ object.field;
+ object2->field;
+// CHECK-CC2: baseTemplateField : [#T#][#BaseTemplate<T>::#]baseTemplateField
+// CHECK-CC2: baseTemplateFunction : [#T#][#BaseTemplate<T>::#]baseTemplateFunction()
+// CHECK-CC2: field : [#T#]field
+// CHECK-CC2: function : [#T#]function()
+// CHECK-CC2: member1 : [#int#][#Base1::#]member1
+// CHECK-CC2: member2 : [#float#][#Base1::#]member2
+// CHECK-CC2: overload1 : [#void#]overload1(<#const T &#>)
+// CHECK-CC2: overload1 : [#void#]overload1(<#const S &#>)
+
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:92:10 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:93:12 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+}
+
+
+void completeDependentSpecializedMembers(TemplateClass<int, double> &object,
+ TemplateClass<int, double> *object2) {
+ object.field;
+ object2->field;
+// CHECK-CC3: baseTemplateField : [#int#][#BaseTemplate<int>::#]baseTemplateField
+// CHECK-CC3: baseTemplateFunction : [#int#][#BaseTemplate<int>::#]baseTemplateFunction()
+// CHECK-CC3: field : [#int#]field
+// CHECK-CC3: function : [#int#]function()
+// CHECK-CC3: member1 : [#int#][#Base1::#]member1
+// CHECK-CC3: member2 : [#float#][#Base1::#]member2
+// CHECK-CC3: overload1 : [#void#]overload1(<#const int &#>)
+// CHECK-CC3: overload1 : [#void#]overload1(<#const double &#>)
+
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:110:10 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:111:12 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+}
+
+template <typename T>
+class Template {
+public:
+ BaseTemplate<int> o1;
+ BaseTemplate<T> o2;
+
+ void function() {
+ o1.baseTemplateField;
+// CHECK-CC4: BaseTemplate : BaseTemplate::
+// CHECK-CC4: baseTemplateField : [#int#]baseTemplateField
+// CHECK-CC4: baseTemplateFunction : [#int#]baseTemplateFunction()
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:132:8 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+ o2.baseTemplateField;
+// CHECK-CC5: BaseTemplate : BaseTemplate::
+// CHECK-CC5: baseTemplateField : [#T#]baseTemplateField
+// CHECK-CC5: baseTemplateFunction : [#T#]baseTemplateFunction()
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:137:8 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
+ this->o1;
+// CHECK-CC6: [#void#]function()
+// CHECK-CC6: o1 : [#BaseTemplate<int>#]o1
+// CHECK-CC6: o2 : [#BaseTemplate<T>#]o2
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:142:11 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
+ }
+
+ static void staticFn(T &obj);
+
+ struct Nested { };
+};
+
+template<typename T>
+void dependentColonColonCompletion() {
+ Template<T>::staticFn();
+// CHECK-CC7: function : [#void#]function()
+// CHECK-CC7: Nested : Nested
+// CHECK-CC7: o1 : [#BaseTemplate<int>#]o1
+// CHECK-CC7: o2 : [#BaseTemplate<T>#]o2
+// CHECK-CC7: staticFn : [#void#]staticFn(<#T &obj#>)
+// CHECK-CC7: Template : Template
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:156:16 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
+ typename Template<T>::Nested m;
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:164:25 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
+}
diff --git a/test/CodeCompletion/uninstantiated_params.cpp b/test/CodeCompletion/uninstantiated_params.cpp
new file mode 100644
index 0000000000..57a520dd57
--- /dev/null
+++ b/test/CodeCompletion/uninstantiated_params.cpp
@@ -0,0 +1,13 @@
+template <class T>
+struct unique_ptr {
+ typedef T* pointer;
+
+ void reset(pointer ptr = pointer());
+};
+
+void test() {
+ unique_ptr<int> x;
+ x.
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:5 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+ // CHECK-CC1: [#void#]reset({#<#unique_ptr<int>::pointer ptr = pointer()#>#})
+}
diff --git a/test/CodeGen/2004-02-20-Builtins.c b/test/CodeGen/2004-02-20-Builtins.c
index 9be0523b4a..13f970127d 100644
--- a/test/CodeGen/2004-02-20-Builtins.c
+++ b/test/CodeGen/2004-02-20-Builtins.c
@@ -1,5 +1,8 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | not grep builtin
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
double sqrt(double x);
+
+// CHECK-LABEL: @zsqrtxxx
+// CHECK-NOT: builtin
void zsqrtxxx(float num) {
num = sqrt(num);
}
diff --git a/test/CodeGen/2005-07-20-SqrtNoErrno.c b/test/CodeGen/2005-07-20-SqrtNoErrno.c
deleted file mode 100644
index 96761e4cfb..0000000000
--- a/test/CodeGen/2005-07-20-SqrtNoErrno.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
-// llvm.sqrt has undefined behavior on negative inputs, so it is
-// inappropriate to translate C/C++ sqrt to this.
-float sqrtf(float x);
-float foo(float X) {
- // CHECK: foo
- // CHECK: call float @sqrtf(float %
- // Check that this is marked readonly when errno is ignored.
- return sqrtf(X);
-}
diff --git a/test/CodeGen/2006-05-19-SingleEltReturn.c b/test/CodeGen/2006-05-19-SingleEltReturn.c
index 819237ce53..dfc23f84ab 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/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c
index 0d7c759f90..c8c247f6b0 100644
--- a/test/CodeGen/2009-10-20-GlobalDebug.c
+++ b/test/CodeGen/2009-10-20-GlobalDebug.c
@@ -10,11 +10,11 @@ int main() {
return 0;
}
-// CHECK: [[L]] = !DIGlobalVariableExpression(var: [[LV:.*]])
+// CHECK: [[L]] = !DIGlobalVariableExpression(var: [[LV:.*]], expr: !DIExpression())
// CHECK: [[LV]] = distinct !DIGlobalVariable(name: "localstatic"
// CHECK-NOT: linkageName:
// CHECK-SAME: line: 9,
-// CHECK: [[G]] = !DIGlobalVariableExpression(var: [[GV:.*]])
+// CHECK: [[G]] = !DIGlobalVariableExpression(var: [[GV:.*]], expr: !DIExpression())
// CHECK: [[GV]] = distinct !DIGlobalVariable(name: "global"
// CHECK-NOT: linkageName:
// CHECK-SAME: line: 7,
diff --git a/test/CodeGen/2010-08-10-DbgConstant.c b/test/CodeGen/2010-08-10-DbgConstant.c
index 68947edd52..ad9d566186 100644
--- a/test/CodeGen/2010-08-10-DbgConstant.c
+++ b/test/CodeGen/2010-08-10-DbgConstant.c
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -S -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s
-// CHECK: !DIGlobalVariableExpression(var: [[VAR:.*]], expr: [[EXPR:![0-9]+]])
-// CHECK: [[EXPR]] = !DIExpression(DW_OP_constu, 201, DW_OP_stack_value)
+// CHECK: !DIGlobalVariableExpression(var: [[VAR:.*]], expr: !DIExpression(DW_OP_constu, 201, DW_OP_stack_value))
static const unsigned int ro = 201;
void bar(int);
diff --git a/test/CodeGen/64bit-swiftcall.c b/test/CodeGen/64bit-swiftcall.c
index c1f0981723..92ba37cd7f 100644
--- a/test/CodeGen/64bit-swiftcall.c
+++ b/test/CodeGen/64bit-swiftcall.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s --check-prefix=X86-64
// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM64
// REQUIRES: aarch64-registered-target,x86-registered-target
@@ -60,6 +62,7 @@ SWIFTCALL void context_error_2(short s, CONTEXT int *self, ERROR float **error)
/********************************** LOWERING *********************************/
/*****************************************************************************/
+typedef float float3 __attribute__((ext_vector_type(3)));
typedef float float4 __attribute__((ext_vector_type(4)));
typedef float float8 __attribute__((ext_vector_type(8)));
typedef double double2 __attribute__((ext_vector_type(2)));
@@ -1005,3 +1008,27 @@ struct {
TEST(union_het_vecint)
// CHECK: define swiftcc void @return_union_het_vecint([[UNION:%.*]]* noalias sret
// CHECK: define swiftcc void @take_union_het_vecint([[UNION]]*
+
+typedef struct {
+ float3 f3;
+} struct_v1f3;
+TEST(struct_v1f3)
+// ARM64-LABEL: define swiftcc { <2 x float>, float } @return_struct_v1f3()
+// ARM64-LABEL: define swiftcc void @take_struct_v1f3(<2 x float>, float)
+
+typedef struct {
+ int3 vect;
+ unsigned long long val;
+} __attribute__((packed)) padded_alloc_size_vector;
+TEST(padded_alloc_size_vector)
+// X86-64-LABEL: take_padded_alloc_size_vector(<3 x i32>, i64)
+// X86-64-NOT: [4 x i8]
+// x86-64: ret void
+
+typedef union {
+ float f1;
+ float3 fv2;
+} union_hom_fp_partial2;
+TEST(union_hom_fp_partial2)
+// X86-64-LABEL: take_union_hom_fp_partial2(i64, float)
+// ARM64-LABEL: take_union_hom_fp_partial2(i64, float)
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 0000000000..d3680dc1f7
--- /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/Inputs/sanitizer-special-case-list.sanitized.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.sanitized.txt
new file mode 100644
index 0000000000..a2afde027b
--- /dev/null
+++ b/test/CodeGen/Inputs/sanitizer-special-case-list.sanitized.txt
@@ -0,0 +1,4 @@
+[unsigned-integer-overflow]
+fun:*cfi*
+[cfi]
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized1.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized1.txt
new file mode 100644
index 0000000000..45ad57bbeb
--- /dev/null
+++ b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized1.txt
@@ -0,0 +1,2 @@
+fun:*cfi*
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized2.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized2.txt
new file mode 100644
index 0000000000..375b246f16
--- /dev/null
+++ b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized2.txt
@@ -0,0 +1,4 @@
+[cfi]
+fun:*cfi*
+[unsigned-integer-overflow]
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized3.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized3.txt
new file mode 100644
index 0000000000..b038fee52b
--- /dev/null
+++ b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized3.txt
@@ -0,0 +1,4 @@
+[cfi-icall]
+fun:*cfi*
+[unsigned-integer-overflow]
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized4.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized4.txt
new file mode 100644
index 0000000000..b31747ec3e
--- /dev/null
+++ b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized4.txt
@@ -0,0 +1,4 @@
+[c*]
+fun:*cfi*
+[u*]
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/thinlto-multi-module.ll b/test/CodeGen/Inputs/thinlto-multi-module.ll
new file mode 100644
index 0000000000..e8dc16a8f5
--- /dev/null
+++ b/test/CodeGen/Inputs/thinlto-multi-module.ll
@@ -0,0 +1,9 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f2() {
+ ret void
+}
+
+!0 = !{i32 1, !"ThinLTO", i32 0}
+!llvm.module.flags = !{ !0 }
diff --git a/test/CodeGen/PR32874.c b/test/CodeGen/PR32874.c
new file mode 100644
index 0000000000..f8aa1c2a66
--- /dev/null
+++ b/test/CodeGen/PR32874.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -x c -S -emit-llvm -o - -triple x86_64-apple-darwin10 %s \
+// RUN: -w -fsanitize=signed-integer-overflow,unsigned-integer-overflow,integer-divide-by-zero,float-divide-by-zero \
+// RUN: | FileCheck %s
+
+// CHECK-LABEL: define void @foo
+// CHECK-NOT: !nosanitize
+void foo(const int *p) {
+ // __builtin_prefetch expects its optional arguments to be constant integers.
+ // Check that ubsan does not instrument any safe arithmetic performed in
+ // operands to __builtin_prefetch. (A clang frontend check should reject
+ // unsafe arithmetic in these operands.)
+
+ __builtin_prefetch(p, 0 + 1, 0 + 3);
+ __builtin_prefetch(p, 1 - 0, 3 - 0);
+ __builtin_prefetch(p, 1 * 1, 1 * 3);
+ __builtin_prefetch(p, 1 / 1, 3 / 1);
+ __builtin_prefetch(p, 3 % 2, 3 % 1);
+
+ __builtin_prefetch(p, 0U + 1U, 0U + 3U);
+ __builtin_prefetch(p, 1U - 0U, 3U - 0U);
+ __builtin_prefetch(p, 1U * 1U, 1U * 3U);
+ __builtin_prefetch(p, 1U / 1U, 3U / 1U);
+ __builtin_prefetch(p, 3U % 2U, 3U % 1U);
+}
+
+// CHECK-LABEL: define void @ub_constant_arithmetic
+void ub_constant_arithmetic() {
+ // Check that we still instrument unsafe arithmetic, even if it is known to
+ // be unsafe at compile time.
+
+ int INT_MIN = 0xffffffff;
+ int INT_MAX = 0x7fffffff;
+
+ // CHECK: call void @__ubsan_handle_add_overflow
+ // CHECK: call void @__ubsan_handle_add_overflow
+ INT_MAX + 1;
+ INT_MAX + -1;
+
+ // CHECK: call void @__ubsan_handle_negate_overflow
+ // CHECK: call void @__ubsan_handle_sub_overflow
+ -INT_MIN;
+ -INT_MAX - 2;
+
+ // CHECK: call void @__ubsan_handle_mul_overflow
+ // CHECK: call void @__ubsan_handle_mul_overflow
+ INT_MAX * INT_MAX;
+ INT_MIN * INT_MIN;
+
+ // CHECK: call void @__ubsan_handle_divrem_overflow
+ // CHECK: call void @__ubsan_handle_divrem_overflow
+ 1 / 0;
+ INT_MIN / -1;
+
+ // CHECK: call void @__ubsan_handle_divrem_overflow
+ // CHECK: call void @__ubsan_handle_divrem_overflow
+ 1 % 0;
+ INT_MIN % -1;
+
+ // CHECK: call void @__ubsan_handle_divrem_overflow
+ 1.0 / 0.0;
+}
diff --git a/test/CodeGen/aarch64-args.cpp b/test/CodeGen/aarch64-args.cpp
new file mode 100644
index 0000000000..4097736272
--- /dev/null
+++ b/test/CodeGen/aarch64-args.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | FileCheck %s --check-prefix=CHECK-GNU-C
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-GNU-CXX
+
+// Empty structs are ignored for PCS purposes on Darwin and in C mode elsewhere.
+// In C++ mode on ELF they consume a register slot though. Functions are
+// slightly bigger than minimal to make confirmation against actual GCC
+// behaviour easier.
+
+#if __cplusplus
+#define EXTERNC extern "C"
+#else
+#define EXTERNC
+#endif
+
+struct Empty {};
+
+// CHECK: define i32 @empty_arg(i32 %a)
+// CHECK-GNU-C: define i32 @empty_arg(i32 %a)
+// CHECK-GNU-CXX: define i32 @empty_arg(i8 %e.coerce, i32 %a)
+EXTERNC int empty_arg(struct Empty e, int a) {
+ return a;
+}
+
+// CHECK: define void @empty_ret()
+// CHECK-GNU-C: define void @empty_ret()
+// CHECK-GNU-CXX: define void @empty_ret()
+EXTERNC struct Empty empty_ret() {
+ struct Empty e;
+ return e;
+}
+
+// However, what counts as "empty" is a baroque mess. This is super-empty, it's
+// ignored even in C++ mode. It also has sizeof == 0, violating C++, but that's
+// legacy for you:
+
+struct SuperEmpty {
+ int arr[0];
+};
+
+// CHECK: define i32 @super_empty_arg(i32 %a)
+// CHECK-GNU-C: define i32 @super_empty_arg(i32 %a)
+// CHECK-GNU-CXX: define i32 @super_empty_arg(i32 %a)
+EXTERNC int super_empty_arg(struct SuperEmpty e, int a) {
+ return a;
+}
+
+// This is not empty. It has 0 size but consumes a register slot for GCC.
+
+struct SortOfEmpty {
+ struct SuperEmpty e;
+};
+
+// CHECK: define i32 @sort_of_empty_arg(i32 %a)
+// CHECK-GNU-C: define i32 @sort_of_empty_arg(i32 %a)
+// CHECK-GNU-CXX: define i32 @sort_of_empty_arg(i8 %e.coerce, i32 %a)
+EXTERNC int sort_of_empty_arg(struct Empty e, int a) {
+ return a;
+}
+
+// CHECK: define void @sort_of_empty_ret()
+// CHECK-GNU-C: define void @sort_of_empty_ret()
+// CHECK-GNU-CXX: define void @sort_of_empty_ret()
+EXTERNC struct SortOfEmpty sort_of_empty_ret() {
+ struct SortOfEmpty e;
+ return e;
+}
diff --git a/test/CodeGen/aarch64-neon-2velem.c b/test/CodeGen/aarch64-neon-2velem.c
index 2866990433..3867b01afb 100644
--- a/test/CodeGen/aarch64-neon-2velem.c
+++ b/test/CodeGen/aarch64-neon-2velem.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
@@ -497,7 +497,7 @@ float64_t test_vfmsd_laneq_f64(float64_t a, float64_t b, float64x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -508,7 +508,7 @@ int32x4_t test_vmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -519,7 +519,7 @@ int64x2_t test_vmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -530,7 +530,7 @@ int32x4_t test_vmlal_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -542,7 +542,7 @@ int64x2_t test_vmlal_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -554,7 +554,7 @@ int32x4_t test_vmlal_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -566,7 +566,7 @@ int64x2_t test_vmlal_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -578,7 +578,7 @@ int32x4_t test_vmlal_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -589,7 +589,7 @@ int64x2_t test_vmlal_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -600,7 +600,7 @@ int32x4_t test_vmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -611,7 +611,7 @@ int64x2_t test_vmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -622,7 +622,7 @@ int32x4_t test_vmlsl_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -634,7 +634,7 @@ int64x2_t test_vmlsl_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -646,7 +646,7 @@ int32x4_t test_vmlsl_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -658,7 +658,7 @@ int64x2_t test_vmlsl_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -670,7 +670,7 @@ int32x4_t test_vmlsl_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -681,7 +681,7 @@ int64x2_t test_vmlsl_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_lane_u16(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -692,7 +692,7 @@ int32x4_t test_vmlal_lane_u16(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_lane_u32(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -703,7 +703,7 @@ int64x2_t test_vmlal_lane_u32(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_laneq_u16(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -714,7 +714,7 @@ int32x4_t test_vmlal_laneq_u16(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_laneq_u32(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -726,7 +726,7 @@ int64x2_t test_vmlal_laneq_u32(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_lane_u16(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -738,7 +738,7 @@ int32x4_t test_vmlal_high_lane_u16(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_lane_u32(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -750,7 +750,7 @@ int64x2_t test_vmlal_high_lane_u32(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_laneq_u16(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -762,7 +762,7 @@ int32x4_t test_vmlal_high_laneq_u16(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_laneq_u32(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -773,7 +773,7 @@ int64x2_t test_vmlal_high_laneq_u32(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_lane_u16(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -784,7 +784,7 @@ int32x4_t test_vmlsl_lane_u16(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_lane_u32(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -795,7 +795,7 @@ int64x2_t test_vmlsl_lane_u32(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_laneq_u16(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -806,7 +806,7 @@ int32x4_t test_vmlsl_laneq_u16(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_laneq_u32(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -818,7 +818,7 @@ int64x2_t test_vmlsl_laneq_u32(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_lane_u16(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -830,7 +830,7 @@ int32x4_t test_vmlsl_high_lane_u16(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_lane_u32(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -842,7 +842,7 @@ int64x2_t test_vmlsl_high_lane_u32(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_laneq_u16(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -854,7 +854,7 @@ int32x4_t test_vmlsl_high_laneq_u16(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_laneq_u32(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -865,7 +865,7 @@ int64x2_t test_vmlsl_high_laneq_u32(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_lane_s16(int16x4_t a, int16x4_t v) {
return vmull_lane_s16(a, v, 3);
@@ -875,7 +875,7 @@ int32x4_t test_vmull_lane_s16(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_lane_s32(int32x2_t a, int32x2_t v) {
return vmull_lane_s32(a, v, 1);
@@ -885,7 +885,7 @@ int64x2_t test_vmull_lane_s32(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_lane_u16(uint16x4_t a, uint16x4_t v) {
return vmull_lane_u16(a, v, 3);
@@ -895,7 +895,7 @@ uint32x4_t test_vmull_lane_u16(uint16x4_t a, uint16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_lane_u32(uint32x2_t a, uint32x2_t v) {
return vmull_lane_u32(a, v, 1);
@@ -906,7 +906,7 @@ uint64x2_t test_vmull_lane_u32(uint32x2_t a, uint32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_high_lane_s16(int16x8_t a, int16x4_t v) {
return vmull_high_lane_s16(a, v, 3);
@@ -917,7 +917,7 @@ int32x4_t test_vmull_high_lane_s16(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_high_lane_s32(int32x4_t a, int32x2_t v) {
return vmull_high_lane_s32(a, v, 1);
@@ -928,7 +928,7 @@ int64x2_t test_vmull_high_lane_s32(int32x4_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_high_lane_u16(uint16x8_t a, uint16x4_t v) {
return vmull_high_lane_u16(a, v, 3);
@@ -939,7 +939,7 @@ uint32x4_t test_vmull_high_lane_u16(uint16x8_t a, uint16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_high_lane_u32(uint32x4_t a, uint32x2_t v) {
return vmull_high_lane_u32(a, v, 1);
@@ -949,7 +949,7 @@ uint64x2_t test_vmull_high_lane_u32(uint32x4_t a, uint32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_laneq_s16(int16x4_t a, int16x8_t v) {
return vmull_laneq_s16(a, v, 7);
@@ -959,7 +959,7 @@ int32x4_t test_vmull_laneq_s16(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_laneq_s32(int32x2_t a, int32x4_t v) {
return vmull_laneq_s32(a, v, 3);
@@ -969,7 +969,7 @@ int64x2_t test_vmull_laneq_s32(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_laneq_u16(uint16x4_t a, uint16x8_t v) {
return vmull_laneq_u16(a, v, 7);
@@ -979,7 +979,7 @@ uint32x4_t test_vmull_laneq_u16(uint16x4_t a, uint16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_laneq_u32(uint32x2_t a, uint32x4_t v) {
return vmull_laneq_u32(a, v, 3);
@@ -990,7 +990,7 @@ uint64x2_t test_vmull_laneq_u32(uint32x2_t a, uint32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_high_laneq_s16(int16x8_t a, int16x8_t v) {
return vmull_high_laneq_s16(a, v, 7);
@@ -1001,7 +1001,7 @@ int32x4_t test_vmull_high_laneq_s16(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_high_laneq_s32(int32x4_t a, int32x4_t v) {
return vmull_high_laneq_s32(a, v, 3);
@@ -1012,7 +1012,7 @@ int64x2_t test_vmull_high_laneq_s32(int32x4_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_high_laneq_u16(uint16x8_t a, uint16x8_t v) {
return vmull_high_laneq_u16(a, v, 7);
@@ -1023,7 +1023,7 @@ uint32x4_t test_vmull_high_laneq_u16(uint16x8_t a, uint16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_high_laneq_u32(uint32x4_t a, uint32x4_t v) {
return vmull_high_laneq_u32(a, v, 3);
@@ -1034,8 +1034,8 @@ uint64x2_t test_vmull_high_laneq_u32(uint32x4_t a, uint32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
return vqdmlal_lane_s16(a, b, v, 3);
@@ -1046,8 +1046,8 @@ int32x4_t test_vqdmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
return vqdmlal_lane_s32(a, b, v, 1);
@@ -1059,8 +1059,8 @@ int64x2_t test_vqdmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
return vqdmlal_high_lane_s16(a, b, v, 3);
@@ -1072,8 +1072,8 @@ int32x4_t test_vqdmlal_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
return vqdmlal_high_lane_s32(a, b, v, 1);
@@ -1084,8 +1084,8 @@ int64x2_t test_vqdmlal_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
return vqdmlsl_lane_s16(a, b, v, 3);
@@ -1096,8 +1096,8 @@ int32x4_t test_vqdmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
return vqdmlsl_lane_s32(a, b, v, 1);
@@ -1109,8 +1109,8 @@ int64x2_t test_vqdmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
return vqdmlsl_high_lane_s16(a, b, v, 3);
@@ -1122,8 +1122,8 @@ int32x4_t test_vqdmlsl_high_lane_s16(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
return vqdmlsl_high_lane_s32(a, b, v, 1);
@@ -1133,7 +1133,7 @@ int64x2_t test_vqdmlsl_high_lane_s32(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_lane_s16(int16x4_t a, int16x4_t v) {
@@ -1144,7 +1144,7 @@ int32x4_t test_vqdmull_lane_s16(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_lane_s32(int32x2_t a, int32x2_t v) {
@@ -1155,7 +1155,7 @@ int64x2_t test_vqdmull_lane_s32(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_laneq_s16(int16x4_t a, int16x8_t v) {
@@ -1166,7 +1166,7 @@ int32x4_t test_vqdmull_laneq_s16(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_laneq_s32(int32x2_t a, int32x4_t v) {
@@ -1178,7 +1178,7 @@ int64x2_t test_vqdmull_laneq_s32(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_high_lane_s16(int16x8_t a, int16x4_t v) {
@@ -1190,7 +1190,7 @@ int32x4_t test_vqdmull_high_lane_s16(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_high_lane_s32(int32x4_t a, int32x2_t v) {
@@ -1202,7 +1202,7 @@ int64x2_t test_vqdmull_high_lane_s32(int32x4_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_high_laneq_s16(int16x8_t a, int16x8_t v) {
@@ -1214,7 +1214,7 @@ int32x4_t test_vqdmull_high_laneq_s16(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_high_laneq_s32(int32x4_t a, int32x4_t v) {
@@ -1225,7 +1225,7 @@ int64x2_t test_vqdmull_high_laneq_s32(int32x4_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V2_I]]
int16x4_t test_vqdmulh_lane_s16(int16x4_t a, int16x4_t v) {
@@ -1236,7 +1236,7 @@ int16x4_t test_vqdmulh_lane_s16(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V2_I]]
int16x8_t test_vqdmulhq_lane_s16(int16x8_t a, int16x4_t v) {
@@ -1247,7 +1247,7 @@ int16x8_t test_vqdmulhq_lane_s16(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V2_I]]
int32x2_t test_vqdmulh_lane_s32(int32x2_t a, int32x2_t v) {
@@ -1258,7 +1258,7 @@ int32x2_t test_vqdmulh_lane_s32(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V2_I]]
int32x4_t test_vqdmulhq_lane_s32(int32x4_t a, int32x2_t v) {
@@ -1269,7 +1269,7 @@ int32x4_t test_vqdmulhq_lane_s32(int32x4_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V2_I]]
int16x4_t test_vqrdmulh_lane_s16(int16x4_t a, int16x4_t v) {
@@ -1280,7 +1280,7 @@ int16x4_t test_vqrdmulh_lane_s16(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V2_I]]
int16x8_t test_vqrdmulhq_lane_s16(int16x8_t a, int16x4_t v) {
@@ -1291,7 +1291,7 @@ int16x8_t test_vqrdmulhq_lane_s16(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V2_I]]
int32x2_t test_vqrdmulh_lane_s32(int32x2_t a, int32x2_t v) {
@@ -1302,7 +1302,7 @@ int32x2_t test_vqrdmulh_lane_s32(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V2_I]]
int32x4_t test_vqrdmulhq_lane_s32(int32x4_t a, int32x2_t v) {
@@ -1390,7 +1390,7 @@ float64x2_t test_vmulq_laneq_f64(float64x2_t a, float64x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x float> %v, <2 x float> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]])
// CHECK: ret <2 x float> [[VMULX2_I]]
float32x2_t test_vmulx_lane_f32(float32x2_t a, float32x2_t v) {
return vmulx_lane_f32(a, v, 1);
@@ -1400,7 +1400,7 @@ float32x2_t test_vmulx_lane_f32(float32x2_t a, float32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x float> %v, <2 x float> %v, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]])
// CHECK: ret <4 x float> [[VMULX2_I]]
float32x4_t test_vmulxq_lane_f32(float32x4_t a, float32x2_t v) {
return vmulxq_lane_f32(a, v, 1);
@@ -1410,7 +1410,7 @@ float32x4_t test_vmulxq_lane_f32(float32x4_t a, float32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <1 x double> %v, <1 x double> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]])
// CHECK: ret <2 x double> [[VMULX2_I]]
float64x2_t test_vmulxq_lane_f64(float64x2_t a, float64x1_t v) {
return vmulxq_lane_f64(a, v, 0);
@@ -1420,7 +1420,7 @@ float64x2_t test_vmulxq_lane_f64(float64x2_t a, float64x1_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x float> %v, <4 x float> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]])
// CHECK: ret <2 x float> [[VMULX2_I]]
float32x2_t test_vmulx_laneq_f32(float32x2_t a, float32x4_t v) {
return vmulx_laneq_f32(a, v, 3);
@@ -1430,7 +1430,7 @@ float32x2_t test_vmulx_laneq_f32(float32x2_t a, float32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x float> %v, <4 x float> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]])
// CHECK: ret <4 x float> [[VMULX2_I]]
float32x4_t test_vmulxq_laneq_f32(float32x4_t a, float32x4_t v) {
return vmulxq_laneq_f32(a, v, 3);
@@ -1440,7 +1440,7 @@ float32x4_t test_vmulxq_laneq_f32(float32x4_t a, float32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x double> %v, <2 x double> %v, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]])
// CHECK: ret <2 x double> [[VMULX2_I]]
float64x2_t test_vmulxq_laneq_f64(float64x2_t a, float64x2_t v) {
return vmulxq_laneq_f64(a, v, 1);
@@ -1867,7 +1867,7 @@ float64x2_t test_vfmsq_laneq_f64_0(float64x2_t a, float64x2_t b, float64x2_t v)
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -1878,7 +1878,7 @@ int32x4_t test_vmlal_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -1889,7 +1889,7 @@ int64x2_t test_vmlal_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -1900,7 +1900,7 @@ int32x4_t test_vmlal_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -1912,7 +1912,7 @@ int64x2_t test_vmlal_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -1924,7 +1924,7 @@ int32x4_t test_vmlal_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -1936,7 +1936,7 @@ int64x2_t test_vmlal_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -1948,7 +1948,7 @@ int32x4_t test_vmlal_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -1959,7 +1959,7 @@ int64x2_t test_vmlal_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -1970,7 +1970,7 @@ int32x4_t test_vmlsl_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -1981,7 +1981,7 @@ int64x2_t test_vmlsl_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -1992,7 +1992,7 @@ int32x4_t test_vmlsl_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -2004,7 +2004,7 @@ int64x2_t test_vmlsl_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -2016,7 +2016,7 @@ int32x4_t test_vmlsl_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -2028,7 +2028,7 @@ int64x2_t test_vmlsl_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -2040,7 +2040,7 @@ int32x4_t test_vmlsl_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -2051,7 +2051,7 @@ int64x2_t test_vmlsl_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_lane_u16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -2062,7 +2062,7 @@ int32x4_t test_vmlal_lane_u16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_lane_u32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -2073,7 +2073,7 @@ int64x2_t test_vmlal_lane_u32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_laneq_u16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -2084,7 +2084,7 @@ int32x4_t test_vmlal_laneq_u16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_laneq_u32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -2096,7 +2096,7 @@ int64x2_t test_vmlal_laneq_u32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_lane_u16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -2108,7 +2108,7 @@ int32x4_t test_vmlal_high_lane_u16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_lane_u32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -2120,7 +2120,7 @@ int64x2_t test_vmlal_high_lane_u32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_high_laneq_u16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -2132,7 +2132,7 @@ int32x4_t test_vmlal_high_laneq_u16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_high_laneq_u32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -2143,7 +2143,7 @@ int64x2_t test_vmlal_high_laneq_u32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_lane_u16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
@@ -2154,7 +2154,7 @@ int32x4_t test_vmlsl_lane_u16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_lane_u32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
@@ -2165,7 +2165,7 @@ int64x2_t test_vmlsl_lane_u32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_laneq_u16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
@@ -2176,7 +2176,7 @@ int32x4_t test_vmlsl_laneq_u16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_laneq_u32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
@@ -2188,7 +2188,7 @@ int64x2_t test_vmlsl_laneq_u32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_lane_u16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
@@ -2200,7 +2200,7 @@ int32x4_t test_vmlsl_high_lane_u16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_lane_u32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
@@ -2212,7 +2212,7 @@ int64x2_t test_vmlsl_high_lane_u32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_high_laneq_u16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
@@ -2224,7 +2224,7 @@ int32x4_t test_vmlsl_high_laneq_u16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_high_laneq_u32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
@@ -2235,7 +2235,7 @@ int64x2_t test_vmlsl_high_laneq_u32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_lane_s16_0(int16x4_t a, int16x4_t v) {
return vmull_lane_s16(a, v, 0);
@@ -2245,7 +2245,7 @@ int32x4_t test_vmull_lane_s16_0(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_lane_s32_0(int32x2_t a, int32x2_t v) {
return vmull_lane_s32(a, v, 0);
@@ -2255,7 +2255,7 @@ int64x2_t test_vmull_lane_s32_0(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_lane_u16_0(uint16x4_t a, uint16x4_t v) {
return vmull_lane_u16(a, v, 0);
@@ -2265,7 +2265,7 @@ uint32x4_t test_vmull_lane_u16_0(uint16x4_t a, uint16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_lane_u32_0(uint32x2_t a, uint32x2_t v) {
return vmull_lane_u32(a, v, 0);
@@ -2276,7 +2276,7 @@ uint64x2_t test_vmull_lane_u32_0(uint32x2_t a, uint32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_high_lane_s16_0(int16x8_t a, int16x4_t v) {
return vmull_high_lane_s16(a, v, 0);
@@ -2287,7 +2287,7 @@ int32x4_t test_vmull_high_lane_s16_0(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_high_lane_s32_0(int32x4_t a, int32x2_t v) {
return vmull_high_lane_s32(a, v, 0);
@@ -2298,7 +2298,7 @@ int64x2_t test_vmull_high_lane_s32_0(int32x4_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_high_lane_u16_0(uint16x8_t a, uint16x4_t v) {
return vmull_high_lane_u16(a, v, 0);
@@ -2309,7 +2309,7 @@ uint32x4_t test_vmull_high_lane_u16_0(uint16x8_t a, uint16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_high_lane_u32_0(uint32x4_t a, uint32x2_t v) {
return vmull_high_lane_u32(a, v, 0);
@@ -2319,7 +2319,7 @@ uint64x2_t test_vmull_high_lane_u32_0(uint32x4_t a, uint32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_laneq_s16_0(int16x4_t a, int16x8_t v) {
return vmull_laneq_s16(a, v, 0);
@@ -2329,7 +2329,7 @@ int32x4_t test_vmull_laneq_s16_0(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_laneq_s32_0(int32x2_t a, int32x4_t v) {
return vmull_laneq_s32(a, v, 0);
@@ -2339,7 +2339,7 @@ int64x2_t test_vmull_laneq_s32_0(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_laneq_u16_0(uint16x4_t a, uint16x8_t v) {
return vmull_laneq_u16(a, v, 0);
@@ -2349,7 +2349,7 @@ uint32x4_t test_vmull_laneq_u16_0(uint16x4_t a, uint16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_laneq_u32_0(uint32x2_t a, uint32x4_t v) {
return vmull_laneq_u32(a, v, 0);
@@ -2360,7 +2360,7 @@ uint64x2_t test_vmull_laneq_u32_0(uint32x2_t a, uint32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_high_laneq_s16_0(int16x8_t a, int16x8_t v) {
return vmull_high_laneq_s16(a, v, 0);
@@ -2371,7 +2371,7 @@ int32x4_t test_vmull_high_laneq_s16_0(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_high_laneq_s32_0(int32x4_t a, int32x4_t v) {
return vmull_high_laneq_s32(a, v, 0);
@@ -2382,7 +2382,7 @@ int64x2_t test_vmull_high_laneq_s32_0(int32x4_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_high_laneq_u16_0(uint16x8_t a, uint16x8_t v) {
return vmull_high_laneq_u16(a, v, 0);
@@ -2393,7 +2393,7 @@ uint32x4_t test_vmull_high_laneq_u16_0(uint16x8_t a, uint16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_high_laneq_u32_0(uint32x4_t a, uint32x4_t v) {
return vmull_high_laneq_u32(a, v, 0);
@@ -2404,8 +2404,8 @@ uint64x2_t test_vmull_high_laneq_u32_0(uint32x4_t a, uint32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
return vqdmlal_lane_s16(a, b, v, 0);
@@ -2416,8 +2416,8 @@ int32x4_t test_vqdmlal_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
return vqdmlal_lane_s32(a, b, v, 0);
@@ -2429,8 +2429,8 @@ int64x2_t test_vqdmlal_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
return vqdmlal_high_lane_s16(a, b, v, 0);
@@ -2442,8 +2442,8 @@ int32x4_t test_vqdmlal_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
return vqdmlal_high_lane_s32(a, b, v, 0);
@@ -2454,8 +2454,8 @@ int64x2_t test_vqdmlal_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
return vqdmlsl_lane_s16(a, b, v, 0);
@@ -2466,8 +2466,8 @@ int32x4_t test_vqdmlsl_lane_s16_0(int32x4_t a, int16x4_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
return vqdmlsl_lane_s32(a, b, v, 0);
@@ -2479,8 +2479,8 @@ int64x2_t test_vqdmlsl_lane_s32_0(int64x2_t a, int32x2_t b, int32x2_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
return vqdmlsl_high_lane_s16(a, b, v, 0);
@@ -2492,8 +2492,8 @@ int32x4_t test_vqdmlsl_high_lane_s16_0(int32x4_t a, int16x8_t b, int16x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
return vqdmlsl_high_lane_s32(a, b, v, 0);
@@ -2503,7 +2503,7 @@ int64x2_t test_vqdmlsl_high_lane_s32_0(int64x2_t a, int32x4_t b, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_lane_s16_0(int16x4_t a, int16x4_t v) {
@@ -2514,7 +2514,7 @@ int32x4_t test_vqdmull_lane_s16_0(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_lane_s32_0(int32x2_t a, int32x2_t v) {
@@ -2525,7 +2525,7 @@ int64x2_t test_vqdmull_lane_s32_0(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_laneq_s16_0(int16x4_t a, int16x8_t v) {
@@ -2536,7 +2536,7 @@ int32x4_t test_vqdmull_laneq_s16_0(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_laneq_s32_0(int32x2_t a, int32x4_t v) {
@@ -2548,7 +2548,7 @@ int64x2_t test_vqdmull_laneq_s32_0(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_high_lane_s16_0(int16x8_t a, int16x4_t v) {
@@ -2560,7 +2560,7 @@ int32x4_t test_vqdmull_high_lane_s16_0(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_high_lane_s32_0(int32x4_t a, int32x2_t v) {
@@ -2572,7 +2572,7 @@ int64x2_t test_vqdmull_high_lane_s32_0(int32x4_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_high_laneq_s16_0(int16x8_t a, int16x8_t v) {
@@ -2584,7 +2584,7 @@ int32x4_t test_vqdmull_high_laneq_s16_0(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_high_laneq_s32_0(int32x4_t a, int32x4_t v) {
@@ -2595,7 +2595,7 @@ int64x2_t test_vqdmull_high_laneq_s32_0(int32x4_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V2_I]]
int16x4_t test_vqdmulh_lane_s16_0(int16x4_t a, int16x4_t v) {
@@ -2606,7 +2606,7 @@ int16x4_t test_vqdmulh_lane_s16_0(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <8 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V2_I]]
int16x8_t test_vqdmulhq_lane_s16_0(int16x8_t a, int16x4_t v) {
@@ -2617,7 +2617,7 @@ int16x8_t test_vqdmulhq_lane_s16_0(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V2_I]]
int32x2_t test_vqdmulh_lane_s32_0(int32x2_t a, int32x2_t v) {
@@ -2628,7 +2628,7 @@ int32x2_t test_vqdmulh_lane_s32_0(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V2_I]]
int32x4_t test_vqdmulhq_lane_s32_0(int32x4_t a, int32x2_t v) {
@@ -2639,7 +2639,7 @@ int32x4_t test_vqdmulhq_lane_s32_0(int32x4_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V2_I]]
int16x4_t test_vqrdmulh_lane_s16_0(int16x4_t a, int16x4_t v) {
@@ -2650,7 +2650,7 @@ int16x4_t test_vqrdmulh_lane_s16_0(int16x4_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %v, <4 x i16> %v, <8 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: ret <8 x i16> [[VQRDMULHQ_V2_I]]
int16x8_t test_vqrdmulhq_lane_s16_0(int16x8_t a, int16x4_t v) {
return vqrdmulhq_lane_s16(a, v, 0);
@@ -2660,7 +2660,7 @@ int16x8_t test_vqrdmulhq_lane_s16_0(int16x8_t a, int16x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V2_I]]
int32x2_t test_vqrdmulh_lane_s32_0(int32x2_t a, int32x2_t v) {
@@ -2671,7 +2671,7 @@ int32x2_t test_vqrdmulh_lane_s32_0(int32x2_t a, int32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %v, <2 x i32> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VQRDMULHQ_V2_I]]
int32x4_t test_vqrdmulhq_lane_s32_0(int32x4_t a, int32x2_t v) {
return vqrdmulhq_lane_s32(a, v, 0);
@@ -2734,7 +2734,7 @@ float64x2_t test_vmulq_laneq_f64_0(float64x2_t a, float64x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x float> %v, <2 x float> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]])
// CHECK: ret <2 x float> [[VMULX2_I]]
float32x2_t test_vmulx_lane_f32_0(float32x2_t a, float32x2_t v) {
return vmulx_lane_f32(a, v, 0);
@@ -2744,7 +2744,7 @@ float32x2_t test_vmulx_lane_f32_0(float32x2_t a, float32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x float> %v, <2 x float> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]])
// CHECK: ret <4 x float> [[VMULX2_I]]
float32x4_t test_vmulxq_lane_f32_0(float32x4_t a, float32x2_t v) {
return vmulxq_lane_f32(a, v, 0);
@@ -2754,7 +2754,7 @@ float32x4_t test_vmulxq_lane_f32_0(float32x4_t a, float32x2_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <1 x double> %v, <1 x double> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]])
// CHECK: ret <2 x double> [[VMULX2_I]]
float64x2_t test_vmulxq_lane_f64_0(float64x2_t a, float64x1_t v) {
return vmulxq_lane_f64(a, v, 0);
@@ -2764,7 +2764,7 @@ float64x2_t test_vmulxq_lane_f64_0(float64x2_t a, float64x1_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x float> %v, <4 x float> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> [[SHUFFLE]])
// CHECK: ret <2 x float> [[VMULX2_I]]
float32x2_t test_vmulx_laneq_f32_0(float32x2_t a, float32x4_t v) {
return vmulx_laneq_f32(a, v, 0);
@@ -2774,7 +2774,7 @@ float32x2_t test_vmulx_laneq_f32_0(float32x2_t a, float32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x float> %v, <4 x float> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> [[SHUFFLE]])
// CHECK: ret <4 x float> [[VMULX2_I]]
float32x4_t test_vmulxq_laneq_f32_0(float32x4_t a, float32x4_t v) {
return vmulxq_laneq_f32(a, v, 0);
@@ -2784,7 +2784,7 @@ float32x4_t test_vmulxq_laneq_f32_0(float32x4_t a, float32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x double> %v, <2 x double> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]]) #2
+// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> [[SHUFFLE]])
// CHECK: ret <2 x double> [[VMULX2_I]]
float64x2_t test_vmulxq_laneq_f64_0(float64x2_t a, float64x2_t v) {
return vmulxq_laneq_f64(a, v, 0);
@@ -2798,7 +2798,7 @@ float64x2_t test_vmulxq_laneq_f64_0(float64x2_t a, float64x2_t v) {
// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VMULL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
+// CHECK: [[VMULL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
// CHECK: ret <4 x i32> [[VMULL5_I_I]]
int32x4_t test_vmull_high_n_s16(int16x8_t a, int16_t b) {
return vmull_high_n_s16(a, b);
@@ -2810,7 +2810,7 @@ int32x4_t test_vmull_high_n_s16(int16x8_t a, int16_t b) {
// CHECK: [[VECINIT_I_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VMULL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
+// CHECK: [[VMULL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
// CHECK: ret <2 x i64> [[VMULL3_I_I]]
int64x2_t test_vmull_high_n_s32(int32x4_t a, int32_t b) {
return vmull_high_n_s32(a, b);
@@ -2824,7 +2824,7 @@ int64x2_t test_vmull_high_n_s32(int32x4_t a, int32_t b) {
// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VMULL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
+// CHECK: [[VMULL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
// CHECK: ret <4 x i32> [[VMULL5_I_I]]
uint32x4_t test_vmull_high_n_u16(uint16x8_t a, uint16_t b) {
return vmull_high_n_u16(a, b);
@@ -2836,7 +2836,7 @@ uint32x4_t test_vmull_high_n_u16(uint16x8_t a, uint16_t b) {
// CHECK: [[VECINIT_I_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VMULL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
+// CHECK: [[VMULL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
// CHECK: ret <2 x i64> [[VMULL3_I_I]]
uint64x2_t test_vmull_high_n_u32(uint32x4_t a, uint32_t b) {
return vmull_high_n_u32(a, b);
@@ -2850,7 +2850,7 @@ uint64x2_t test_vmull_high_n_u32(uint32x4_t a, uint32_t b) {
// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
+// CHECK: [[VQDMULL_V5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
// CHECK: [[VQDMULL_V6_I_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V5_I_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V5_I_I]]
int32x4_t test_vqdmull_high_n_s16(int16x8_t a, int16_t b) {
@@ -2863,7 +2863,7 @@ int32x4_t test_vqdmull_high_n_s16(int16x8_t a, int16_t b) {
// CHECK: [[VECINIT_I_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
+// CHECK: [[VQDMULL_V3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
// CHECK: [[VQDMULL_V4_I_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V3_I_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V3_I_I]]
int64x2_t test_vqdmull_high_n_s32(int32x4_t a, int32_t b) {
@@ -2878,7 +2878,7 @@ int64x2_t test_vqdmull_high_n_s32(int32x4_t a, int32_t b) {
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
// CHECK: [[ADD_I_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[ADD_I_I]]
int32x4_t test_vmlal_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
@@ -2891,7 +2891,7 @@ int32x4_t test_vmlal_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
// CHECK: [[ADD_I_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[ADD_I_I]]
int64x2_t test_vmlal_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
@@ -2906,7 +2906,7 @@ int64x2_t test_vmlal_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
// CHECK: [[ADD_I_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[ADD_I_I]]
uint32x4_t test_vmlal_high_n_u16(uint32x4_t a, uint16x8_t b, uint16_t c) {
@@ -2919,7 +2919,7 @@ uint32x4_t test_vmlal_high_n_u16(uint32x4_t a, uint16x8_t b, uint16_t c) {
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
// CHECK: [[ADD_I_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[ADD_I_I]]
uint64x2_t test_vmlal_high_n_u32(uint64x2_t a, uint32x4_t b, uint32_t c) {
@@ -2935,8 +2935,8 @@ uint64x2_t test_vmlal_high_n_u32(uint64x2_t a, uint32x4_t b, uint32_t c) {
// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I_I]], i16 %c, i32 2
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %c, i32 3
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VQDMLAL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
-// CHECK: [[VQDMLAL_V6_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I_I]]) #2
+// CHECK: [[VQDMLAL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
+// CHECK: [[VQDMLAL_V6_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V6_I_I]]
int32x4_t test_vqdmlal_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
return vqdmlal_high_n_s16(a, b, c);
@@ -2949,8 +2949,8 @@ int32x4_t test_vqdmlal_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
// CHECK: [[VECINIT_I_I:%.*]] = insertelement <2 x i32> undef, i32 %c, i32 0
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %c, i32 1
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VQDMLAL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
-// CHECK: [[VQDMLAL_V4_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I_I]]) #2
+// CHECK: [[VQDMLAL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
+// CHECK: [[VQDMLAL_V4_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V4_I_I]]
int64x2_t test_vqdmlal_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
return vqdmlal_high_n_s32(a, b, c);
@@ -2964,7 +2964,7 @@ int64x2_t test_vqdmlal_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[SUB_I_I]]
int32x4_t test_vmlsl_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
@@ -2977,7 +2977,7 @@ int32x4_t test_vmlsl_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[SUB_I_I]]
int64x2_t test_vmlsl_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
@@ -2992,7 +2992,7 @@ int64x2_t test_vmlsl_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[SUB_I_I]]
uint32x4_t test_vmlsl_high_n_u16(uint32x4_t a, uint16x8_t b, uint16_t c) {
@@ -3005,7 +3005,7 @@ uint32x4_t test_vmlsl_high_n_u16(uint32x4_t a, uint16x8_t b, uint16_t c) {
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[SUB_I_I]]
uint64x2_t test_vmlsl_high_n_u32(uint64x2_t a, uint32x4_t b, uint32_t c) {
@@ -3021,8 +3021,8 @@ uint64x2_t test_vmlsl_high_n_u32(uint64x2_t a, uint32x4_t b, uint32_t c) {
// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I_I]], i16 %c, i32 2
// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I_I]], i16 %c, i32 3
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VECINIT3_I_I]] to <8 x i8>
-// CHECK: [[VQDMLAL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]]) #2
-// CHECK: [[VQDMLSL_V6_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I_I]]) #2
+// CHECK: [[VQDMLAL5_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[VECINIT3_I_I]])
+// CHECK: [[VQDMLSL_V6_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V6_I_I]]
int32x4_t test_vqdmlsl_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
return vqdmlsl_high_n_s16(a, b, c);
@@ -3035,8 +3035,8 @@ int32x4_t test_vqdmlsl_high_n_s16(int32x4_t a, int16x8_t b, int16_t c) {
// CHECK: [[VECINIT_I_I:%.*]] = insertelement <2 x i32> undef, i32 %c, i32 0
// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <2 x i32> [[VECINIT_I_I]], i32 %c, i32 1
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VECINIT1_I_I]] to <8 x i8>
-// CHECK: [[VQDMLAL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]]) #2
-// CHECK: [[VQDMLSL_V4_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I_I]]) #2
+// CHECK: [[VQDMLAL3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[VECINIT1_I_I]])
+// CHECK: [[VQDMLSL_V4_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V4_I_I]]
int64x2_t test_vqdmlsl_high_n_s32(int64x2_t a, int32x4_t b, int32_t c) {
return vqdmlsl_high_n_s32(a, b, c);
@@ -3077,7 +3077,7 @@ float64x2_t test_vmulq_n_f64(float64x2_t a, float64_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x float> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> %b, <2 x float> [[VECINIT1_I]], <2 x float> %a) #2
+// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> %b, <2 x float> [[VECINIT1_I]], <2 x float> %a)
// CHECK: ret <2 x float> [[TMP3]]
float32x2_t test_vfma_n_f32(float32x2_t a, float32x2_t b, float32_t n) {
return vfma_n_f32(a, b, n);
@@ -3091,7 +3091,7 @@ float32x2_t test_vfma_n_f32(float32x2_t a, float32x2_t b, float32_t n) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x float> [[VECINIT3_I]] to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %b, <4 x float> [[VECINIT3_I]], <4 x float> %a) #2
+// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %b, <4 x float> [[VECINIT3_I]], <4 x float> %a)
// CHECK: ret <4 x float> [[TMP3]]
float32x4_t test_vfmaq_n_f32(float32x4_t a, float32x4_t b, float32_t n) {
return vfmaq_n_f32(a, b, n);
@@ -3104,7 +3104,7 @@ float32x4_t test_vfmaq_n_f32(float32x4_t a, float32x4_t b, float32_t n) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> [[SUB_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x float> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[SUB_I]], <2 x float> [[VECINIT1_I]], <2 x float> %a) #2
+// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[SUB_I]], <2 x float> [[VECINIT1_I]], <2 x float> %a)
// CHECK: ret <2 x float> [[TMP3]]
float32x2_t test_vfms_n_f32(float32x2_t a, float32x2_t b, float32_t n) {
return vfms_n_f32(a, b, n);
@@ -3119,7 +3119,7 @@ float32x2_t test_vfms_n_f32(float32x2_t a, float32x2_t b, float32_t n) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> [[SUB_I]] to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x float> [[VECINIT3_I]] to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> [[SUB_I]], <4 x float> [[VECINIT3_I]], <4 x float> %a) #2
+// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> [[SUB_I]], <4 x float> [[VECINIT3_I]], <4 x float> %a)
// CHECK: ret <4 x float> [[TMP3]]
float32x4_t test_vfmsq_n_f32(float32x4_t a, float32x4_t b, float32_t n) {
return vfmsq_n_f32(a, b, n);
@@ -3224,7 +3224,7 @@ uint32x4_t test_vmulq_n_u32(uint32x4_t a, uint32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: ret <4 x i32> [[VMULL5_I]]
int32x4_t test_vmull_n_s16(int16x4_t a, int16_t b) {
return vmull_n_s16(a, b);
@@ -3235,7 +3235,7 @@ int32x4_t test_vmull_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: ret <2 x i64> [[VMULL3_I]]
int64x2_t test_vmull_n_s32(int32x2_t a, int32_t b) {
return vmull_n_s32(a, b);
@@ -3248,7 +3248,7 @@ int64x2_t test_vmull_n_s32(int32x2_t a, int32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: ret <4 x i32> [[VMULL5_I]]
uint32x4_t test_vmull_n_u16(uint16x4_t a, uint16_t b) {
return vmull_n_u16(a, b);
@@ -3259,7 +3259,7 @@ uint32x4_t test_vmull_n_u16(uint16x4_t a, uint16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: ret <2 x i64> [[VMULL3_I]]
uint64x2_t test_vmull_n_u32(uint32x2_t a, uint32_t b) {
return vmull_n_u32(a, b);
@@ -3272,7 +3272,7 @@ uint64x2_t test_vmull_n_u32(uint32x2_t a, uint32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VQDMULL_V5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: [[VQDMULL_V6_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V5_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V5_I]]
int32x4_t test_vqdmull_n_s16(int16x4_t a, int16_t b) {
@@ -3284,7 +3284,7 @@ int32x4_t test_vqdmull_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VQDMULL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: [[VQDMULL_V4_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V3_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V3_I]]
int64x2_t test_vqdmull_n_s32(int32x2_t a, int32_t b) {
@@ -3298,7 +3298,7 @@ int64x2_t test_vqdmull_n_s32(int32x2_t a, int32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMULH_V5_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VQDMULH_V5_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: [[VQDMULH_V6_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V5_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V5_I]]
int16x4_t test_vqdmulh_n_s16(int16x4_t a, int16_t b) {
@@ -3316,7 +3316,7 @@ int16x4_t test_vqdmulh_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT6_I:%.*]] = insertelement <8 x i16> [[VECINIT5_I]], i16 %b, i32 6
// CHECK: [[VECINIT7_I:%.*]] = insertelement <8 x i16> [[VECINIT6_I]], i16 %b, i32 7
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[VECINIT7_I]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]]) #2
+// CHECK: [[VQDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]])
// CHECK: [[VQDMULHQ_V10_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V9_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V9_I]]
int16x8_t test_vqdmulhq_n_s16(int16x8_t a, int16_t b) {
@@ -3328,7 +3328,7 @@ int16x8_t test_vqdmulhq_n_s16(int16x8_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMULH_V3_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VQDMULH_V3_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: [[VQDMULH_V4_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V3_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V3_I]]
int32x2_t test_vqdmulh_n_s32(int32x2_t a, int32_t b) {
@@ -3342,7 +3342,7 @@ int32x2_t test_vqdmulh_n_s32(int32x2_t a, int32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i32> [[VECINIT1_I]], i32 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i32> [[VECINIT2_I]], i32 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[VECINIT3_I]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]]) #2
+// CHECK: [[VQDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]])
// CHECK: [[VQDMULHQ_V6_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V5_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V5_I]]
int32x4_t test_vqdmulhq_n_s32(int32x4_t a, int32_t b) {
@@ -3356,7 +3356,7 @@ int32x4_t test_vqdmulhq_n_s32(int32x4_t a, int32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQRDMULH_V5_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VQRDMULH_V5_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: [[VQRDMULH_V6_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V5_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V5_I]]
int16x4_t test_vqrdmulh_n_s16(int16x4_t a, int16_t b) {
@@ -3374,7 +3374,7 @@ int16x4_t test_vqrdmulh_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT6_I:%.*]] = insertelement <8 x i16> [[VECINIT5_I]], i16 %b, i32 6
// CHECK: [[VECINIT7_I:%.*]] = insertelement <8 x i16> [[VECINIT6_I]], i16 %b, i32 7
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[VECINIT7_I]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]]) #2
+// CHECK: [[VQRDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]])
// CHECK: [[VQRDMULHQ_V10_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V9_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V9_I]]
int16x8_t test_vqrdmulhq_n_s16(int16x8_t a, int16_t b) {
@@ -3386,7 +3386,7 @@ int16x8_t test_vqrdmulhq_n_s16(int16x8_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQRDMULH_V3_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VQRDMULH_V3_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: [[VQRDMULH_V4_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V3_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V3_I]]
int32x2_t test_vqrdmulh_n_s32(int32x2_t a, int32_t b) {
@@ -3400,7 +3400,7 @@ int32x2_t test_vqrdmulh_n_s32(int32x2_t a, int32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i32> [[VECINIT1_I]], i32 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i32> [[VECINIT2_I]], i32 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[VECINIT3_I]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]]) #2
+// CHECK: [[VQRDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]])
// CHECK: [[VQRDMULHQ_V6_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V5_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V5_I]]
int32x4_t test_vqrdmulhq_n_s32(int32x4_t a, int32_t b) {
@@ -3514,7 +3514,7 @@ uint32x4_t test_vmlaq_n_u32(uint32x4_t a, uint32x4_t b, uint32_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
int32x4_t test_vmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
@@ -3526,7 +3526,7 @@ int32x4_t test_vmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
int64x2_t test_vmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
@@ -3540,7 +3540,7 @@ int64x2_t test_vmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
uint32x4_t test_vmlal_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
@@ -3552,7 +3552,7 @@ uint32x4_t test_vmlal_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
uint64x2_t test_vmlal_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
@@ -3567,8 +3567,8 @@ uint64x2_t test_vmlal_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %c, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #2
-// CHECK: [[VQDMLAL_V6_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]]) #2
+// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
+// CHECK: [[VQDMLAL_V6_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V6_I]]
int32x4_t test_vqdmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
return vqdmlal_n_s16(a, b, c);
@@ -3580,8 +3580,8 @@ int32x4_t test_vqdmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %c, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #2
-// CHECK: [[VQDMLAL_V4_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]]) #2
+// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
+// CHECK: [[VQDMLAL_V4_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V4_I]]
int64x2_t test_vqdmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
return vqdmlal_n_s32(a, b, c);
@@ -3694,7 +3694,7 @@ uint32x4_t test_vmlsq_n_u32(uint32x4_t a, uint32x4_t b, uint32_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
int32x4_t test_vmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
@@ -3706,7 +3706,7 @@ int32x4_t test_vmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
int64x2_t test_vmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
@@ -3720,7 +3720,7 @@ int64x2_t test_vmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
uint32x4_t test_vmlsl_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
@@ -3732,7 +3732,7 @@ uint32x4_t test_vmlsl_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #2
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
uint64x2_t test_vmlsl_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
@@ -3747,8 +3747,8 @@ uint64x2_t test_vmlsl_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %c, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #2
-// CHECK: [[VQDMLSL_V6_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]]) #2
+// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
+// CHECK: [[VQDMLSL_V6_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V6_I]]
int32x4_t test_vqdmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
return vqdmlsl_n_s16(a, b, c);
@@ -3760,8 +3760,8 @@ int32x4_t test_vqdmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %c, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #2
-// CHECK: [[VQDMLSL_V4_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]]) #2
+// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
+// CHECK: [[VQDMLSL_V4_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V4_I]]
int64x2_t test_vqdmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
return vqdmlsl_n_s32(a, b, c);
@@ -3844,8 +3844,8 @@ uint32x4_t test_vmlaq_laneq_u32_0(uint32x4_t a, uint32x4_t b, uint32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
return vqdmlal_laneq_s16(a, b, v, 0);
@@ -3856,8 +3856,8 @@ int32x4_t test_vqdmlal_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
return vqdmlal_laneq_s32(a, b, v, 0);
@@ -3869,8 +3869,8 @@ int64x2_t test_vqdmlal_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
return vqdmlal_high_laneq_s16(a, b, v, 0);
@@ -3882,8 +3882,8 @@ int32x4_t test_vqdmlal_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
return vqdmlal_high_laneq_s32(a, b, v, 0);
@@ -3966,8 +3966,8 @@ uint32x4_t test_vmlsq_laneq_u32_0(uint32x4_t a, uint32x4_t b, uint32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
return vqdmlsl_laneq_s16(a, b, v, 0);
@@ -3978,8 +3978,8 @@ int32x4_t test_vqdmlsl_laneq_s16_0(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
return vqdmlsl_laneq_s32(a, b, v, 0);
@@ -3991,8 +3991,8 @@ int64x2_t test_vqdmlsl_laneq_s32_0(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
return vqdmlsl_high_laneq_s16(a, b, v, 0);
@@ -4004,8 +4004,8 @@ int32x4_t test_vqdmlsl_high_laneq_s16_0(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
return vqdmlsl_high_laneq_s32(a, b, v, 0);
@@ -4015,7 +4015,7 @@ int64x2_t test_vqdmlsl_high_laneq_s32_0(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V2_I]]
int16x4_t test_vqdmulh_laneq_s16_0(int16x4_t a, int16x8_t v) {
@@ -4026,7 +4026,7 @@ int16x4_t test_vqdmulh_laneq_s16_0(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <8 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V2_I]]
int16x8_t test_vqdmulhq_laneq_s16_0(int16x8_t a, int16x8_t v) {
@@ -4037,7 +4037,7 @@ int16x8_t test_vqdmulhq_laneq_s16_0(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V2_I]]
int32x2_t test_vqdmulh_laneq_s32_0(int32x2_t a, int32x4_t v) {
@@ -4048,7 +4048,7 @@ int32x2_t test_vqdmulh_laneq_s32_0(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V2_I]]
int32x4_t test_vqdmulhq_laneq_s32_0(int32x4_t a, int32x4_t v) {
@@ -4059,7 +4059,7 @@ int32x4_t test_vqdmulhq_laneq_s32_0(int32x4_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V2_I]]
int16x4_t test_vqrdmulh_laneq_s16_0(int16x4_t a, int16x8_t v) {
@@ -4070,7 +4070,7 @@ int16x4_t test_vqrdmulh_laneq_s16_0(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <8 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V2_I]]
int16x8_t test_vqrdmulhq_laneq_s16_0(int16x8_t a, int16x8_t v) {
@@ -4081,7 +4081,7 @@ int16x8_t test_vqrdmulhq_laneq_s16_0(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V2_I]]
int32x2_t test_vqrdmulh_laneq_s32_0(int32x2_t a, int32x4_t v) {
@@ -4092,7 +4092,7 @@ int32x2_t test_vqrdmulh_laneq_s32_0(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <4 x i32> zeroinitializer
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V2_I]]
int32x4_t test_vqrdmulhq_laneq_s32_0(int32x4_t a, int32x4_t v) {
@@ -4176,8 +4176,8 @@ uint32x4_t test_vmlaq_laneq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
return vqdmlal_laneq_s16(a, b, v, 7);
@@ -4188,8 +4188,8 @@ int32x4_t test_vqdmlal_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
return vqdmlal_laneq_s32(a, b, v, 3);
@@ -4201,8 +4201,8 @@ int64x2_t test_vqdmlal_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
return vqdmlal_high_laneq_s16(a, b, v, 7);
@@ -4214,8 +4214,8 @@ int32x4_t test_vqdmlal_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
return vqdmlal_high_laneq_s32(a, b, v, 3);
@@ -4298,8 +4298,8 @@ uint32x4_t test_vmlsq_laneq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
return vqdmlsl_laneq_s16(a, b, v, 7);
@@ -4310,8 +4310,8 @@ int32x4_t test_vqdmlsl_laneq_s16(int32x4_t a, int16x4_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
return vqdmlsl_laneq_s32(a, b, v, 3);
@@ -4323,8 +4323,8 @@ int64x2_t test_vqdmlsl_laneq_s32(int64x2_t a, int32x2_t b, int32x4_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I]], <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
return vqdmlsl_high_laneq_s16(a, b, v, 7);
@@ -4336,8 +4336,8 @@ int32x4_t test_vqdmlsl_high_laneq_s16(int32x4_t a, int16x8_t b, int16x8_t v) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]]) #2
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #2
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I]], <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
return vqdmlsl_high_laneq_s32(a, b, v, 3);
@@ -4347,7 +4347,7 @@ int64x2_t test_vqdmlsl_high_laneq_s32(int64x2_t a, int32x4_t b, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V2_I]]
int16x4_t test_vqdmulh_laneq_s16(int16x4_t a, int16x8_t v) {
@@ -4358,7 +4358,7 @@ int16x4_t test_vqdmulh_laneq_s16(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V2_I]]
int16x8_t test_vqdmulhq_laneq_s16(int16x8_t a, int16x8_t v) {
@@ -4369,7 +4369,7 @@ int16x8_t test_vqdmulhq_laneq_s16(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V2_I]]
int32x2_t test_vqdmulh_laneq_s32(int32x2_t a, int32x4_t v) {
@@ -4380,7 +4380,7 @@ int32x2_t test_vqdmulh_laneq_s32(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V2_I]]
int32x4_t test_vqdmulhq_laneq_s32(int32x4_t a, int32x4_t v) {
@@ -4391,7 +4391,7 @@ int32x4_t test_vqdmulhq_laneq_s32(int32x4_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V2_I]]
int16x4_t test_vqrdmulh_laneq_s16(int16x4_t a, int16x8_t v) {
@@ -4402,7 +4402,7 @@ int16x4_t test_vqrdmulh_laneq_s16(int16x4_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <8 x i16> %v, <8 x i16> %v, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V2_I]]
int16x8_t test_vqrdmulhq_laneq_s16(int16x8_t a, int16x8_t v) {
@@ -4413,7 +4413,7 @@ int16x8_t test_vqrdmulhq_laneq_s16(int16x8_t a, int16x8_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <2 x i32> <i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V2_I]]
int32x2_t test_vqrdmulh_laneq_s32(int32x2_t a, int32x4_t v) {
@@ -4424,7 +4424,7 @@ int32x2_t test_vqrdmulh_laneq_s32(int32x2_t a, int32x4_t v) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i32> %v, <4 x i32> %v, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #2
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V2_I]]
int32x4_t test_vqrdmulhq_laneq_s32(int32x4_t a, int32x4_t v) {
diff --git a/test/CodeGen/aarch64-neon-3v.c b/test/CodeGen/aarch64-neon-3v.c
index 3581f780ff..de38e95c44 100644
--- a/test/CodeGen/aarch64-neon-3v.c
+++ b/test/CodeGen/aarch64-neon-3v.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-across.c b/test/CodeGen/aarch64-neon-across.c
index 6d7a0d5bcd..767825461b 100644
--- a/test/CodeGen/aarch64-neon-across.c
+++ b/test/CodeGen/aarch64-neon-across.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-extract.c b/test/CodeGen/aarch64-neon-extract.c
index c84c861b87..6b62d9f1cf 100644
--- a/test/CodeGen/aarch64-neon-extract.c
+++ b/test/CodeGen/aarch64-neon-extract.c
@@ -1,6 +1,6 @@
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-fcvt-intrinsics.c b/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
index f2c238ebeb..929a6501df 100644
--- a/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
+++ b/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-fma.c b/test/CodeGen/aarch64-neon-fma.c
index 6ada533c66..3a84834e11 100644
--- a/test/CodeGen/aarch64-neon-fma.c
+++ b/test/CodeGen/aarch64-neon-fma.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-intrinsics.c b/test/CodeGen/aarch64-neon-intrinsics.c
index 2ffbcdce37..bcb680c4b5 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 -disable-O0-optnone -emit-llvm -o - %s \
// RUN: | opt -S -mem2reg \
// RUN: | FileCheck %s
@@ -379,14 +379,14 @@ float64x2_t test_vmulq_f64(float64x2_t v1, float64x2_t v2) {
}
// CHECK-LABEL: @test_vmul_p8(
-// CHECK: [[VMUL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.pmul.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VMUL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.pmul.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VMUL_V_I]]
poly8x8_t test_vmul_p8(poly8x8_t v1, poly8x8_t v2) {
return vmul_p8(v1, v2);
}
// CHECK-LABEL: @test_vmulq_p8(
-// CHECK: [[VMULQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.pmul.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VMULQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.pmul.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VMULQ_V_I]]
poly8x16_t test_vmulq_p8(poly8x16_t v1, poly8x16_t v2) {
return vmulq_p8(v1, v2);
@@ -638,7 +638,7 @@ float64x2_t test_vmlsq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x float> %v3 to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> %v2, <2 x float> %v3, <2 x float> %v1) #4
+// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> %v2, <2 x float> %v3, <2 x float> %v1)
// CHECK: ret <2 x float> [[TMP3]]
float32x2_t test_vfma_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
return vfma_f32(v1, v2, v3);
@@ -648,7 +648,7 @@ float32x2_t test_vfma_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x float> %v3 to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %v2, <4 x float> %v3, <4 x float> %v1) #4
+// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %v2, <4 x float> %v3, <4 x float> %v1)
// CHECK: ret <4 x float> [[TMP3]]
float32x4_t test_vfmaq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
return vfmaq_f32(v1, v2, v3);
@@ -658,7 +658,7 @@ float32x4_t test_vfmaq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x double> %v3 to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %v2, <2 x double> %v3, <2 x double> %v1) #4
+// CHECK: [[TMP3:%.*]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %v2, <2 x double> %v3, <2 x double> %v1)
// CHECK: ret <2 x double> [[TMP3]]
float64x2_t test_vfmaq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
return vfmaq_f64(v1, v2, v3);
@@ -669,7 +669,7 @@ float64x2_t test_vfmaq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> [[SUB_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x float> %v3 to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[SUB_I]], <2 x float> %v3, <2 x float> %v1) #4
+// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[SUB_I]], <2 x float> %v3, <2 x float> %v1)
// CHECK: ret <2 x float> [[TMP3]]
float32x2_t test_vfms_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
return vfms_f32(v1, v2, v3);
@@ -680,7 +680,7 @@ float32x2_t test_vfms_f32(float32x2_t v1, float32x2_t v2, float32x2_t v3) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> [[SUB_I]] to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x float> %v3 to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> [[SUB_I]], <4 x float> %v3, <4 x float> %v1) #4
+// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> [[SUB_I]], <4 x float> %v3, <4 x float> %v1)
// CHECK: ret <4 x float> [[TMP3]]
float32x4_t test_vfmsq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
return vfmsq_f32(v1, v2, v3);
@@ -691,7 +691,7 @@ float32x4_t test_vfmsq_f32(float32x4_t v1, float32x4_t v2, float32x4_t v3) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> [[SUB_I]] to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x double> %v3 to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x double> @llvm.fma.v2f64(<2 x double> [[SUB_I]], <2 x double> %v3, <2 x double> %v1) #4
+// CHECK: [[TMP3:%.*]] = call <2 x double> @llvm.fma.v2f64(<2 x double> [[SUB_I]], <2 x double> %v3, <2 x double> %v1)
// CHECK: ret <2 x double> [[TMP3]]
float64x2_t test_vfmsq_f64(float64x2_t v1, float64x2_t v2, float64x2_t v3) {
return vfmsq_f64(v1, v2, v3);
@@ -719,7 +719,7 @@ float32x2_t test_vdiv_f32(float32x2_t v1, float32x2_t v2) {
}
// CHECK-LABEL: @test_vaba_s8(
-// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %v2, <8 x i8> %v3) #4
+// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %v2, <8 x i8> %v3)
// CHECK: [[ADD_I:%.*]] = add <8 x i8> %v1, [[VABD_I_I]]
// CHECK: ret <8 x i8> [[ADD_I]]
int8x8_t test_vaba_s8(int8x8_t v1, int8x8_t v2, int8x8_t v3) {
@@ -729,7 +729,7 @@ int8x8_t test_vaba_s8(int8x8_t v1, int8x8_t v2, int8x8_t v3) {
// CHECK-LABEL: @test_vaba_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v3 to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %v2, <4 x i16> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %v2, <4 x i16> %v3)
// CHECK: [[ADD_I:%.*]] = add <4 x i16> %v1, [[VABD2_I_I]]
// CHECK: ret <4 x i16> [[ADD_I]]
int16x4_t test_vaba_s16(int16x4_t v1, int16x4_t v2, int16x4_t v3) {
@@ -739,7 +739,7 @@ int16x4_t test_vaba_s16(int16x4_t v1, int16x4_t v2, int16x4_t v3) {
// CHECK-LABEL: @test_vaba_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v3 to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %v2, <2 x i32> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %v2, <2 x i32> %v3)
// CHECK: [[ADD_I:%.*]] = add <2 x i32> %v1, [[VABD2_I_I]]
// CHECK: ret <2 x i32> [[ADD_I]]
int32x2_t test_vaba_s32(int32x2_t v1, int32x2_t v2, int32x2_t v3) {
@@ -747,7 +747,7 @@ int32x2_t test_vaba_s32(int32x2_t v1, int32x2_t v2, int32x2_t v3) {
}
// CHECK-LABEL: @test_vaba_u8(
-// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %v2, <8 x i8> %v3) #4
+// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %v2, <8 x i8> %v3)
// CHECK: [[ADD_I:%.*]] = add <8 x i8> %v1, [[VABD_I_I]]
// CHECK: ret <8 x i8> [[ADD_I]]
uint8x8_t test_vaba_u8(uint8x8_t v1, uint8x8_t v2, uint8x8_t v3) {
@@ -757,7 +757,7 @@ uint8x8_t test_vaba_u8(uint8x8_t v1, uint8x8_t v2, uint8x8_t v3) {
// CHECK-LABEL: @test_vaba_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v3 to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %v2, <4 x i16> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %v2, <4 x i16> %v3)
// CHECK: [[ADD_I:%.*]] = add <4 x i16> %v1, [[VABD2_I_I]]
// CHECK: ret <4 x i16> [[ADD_I]]
uint16x4_t test_vaba_u16(uint16x4_t v1, uint16x4_t v2, uint16x4_t v3) {
@@ -767,7 +767,7 @@ uint16x4_t test_vaba_u16(uint16x4_t v1, uint16x4_t v2, uint16x4_t v3) {
// CHECK-LABEL: @test_vaba_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v3 to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %v2, <2 x i32> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %v2, <2 x i32> %v3)
// CHECK: [[ADD_I:%.*]] = add <2 x i32> %v1, [[VABD2_I_I]]
// CHECK: ret <2 x i32> [[ADD_I]]
uint32x2_t test_vaba_u32(uint32x2_t v1, uint32x2_t v2, uint32x2_t v3) {
@@ -775,7 +775,7 @@ uint32x2_t test_vaba_u32(uint32x2_t v1, uint32x2_t v2, uint32x2_t v3) {
}
// CHECK-LABEL: @test_vabaq_s8(
-// CHECK: [[VABD_I_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sabd.v16i8(<16 x i8> %v2, <16 x i8> %v3) #4
+// CHECK: [[VABD_I_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sabd.v16i8(<16 x i8> %v2, <16 x i8> %v3)
// CHECK: [[ADD_I:%.*]] = add <16 x i8> %v1, [[VABD_I_I]]
// CHECK: ret <16 x i8> [[ADD_I]]
int8x16_t test_vabaq_s8(int8x16_t v1, int8x16_t v2, int8x16_t v3) {
@@ -785,7 +785,7 @@ int8x16_t test_vabaq_s8(int8x16_t v1, int8x16_t v2, int8x16_t v3) {
// CHECK-LABEL: @test_vabaq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v3 to <16 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> %v2, <8 x i16> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> %v2, <8 x i16> %v3)
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %v1, [[VABD2_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
int16x8_t test_vabaq_s16(int16x8_t v1, int16x8_t v2, int16x8_t v3) {
@@ -795,7 +795,7 @@ int16x8_t test_vabaq_s16(int16x8_t v1, int16x8_t v2, int16x8_t v3) {
// CHECK-LABEL: @test_vabaq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v3 to <16 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sabd.v4i32(<4 x i32> %v2, <4 x i32> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sabd.v4i32(<4 x i32> %v2, <4 x i32> %v3)
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %v1, [[VABD2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
int32x4_t test_vabaq_s32(int32x4_t v1, int32x4_t v2, int32x4_t v3) {
@@ -803,7 +803,7 @@ int32x4_t test_vabaq_s32(int32x4_t v1, int32x4_t v2, int32x4_t v3) {
}
// CHECK-LABEL: @test_vabaq_u8(
-// CHECK: [[VABD_I_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uabd.v16i8(<16 x i8> %v2, <16 x i8> %v3) #4
+// CHECK: [[VABD_I_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uabd.v16i8(<16 x i8> %v2, <16 x i8> %v3)
// CHECK: [[ADD_I:%.*]] = add <16 x i8> %v1, [[VABD_I_I]]
// CHECK: ret <16 x i8> [[ADD_I]]
uint8x16_t test_vabaq_u8(uint8x16_t v1, uint8x16_t v2, uint8x16_t v3) {
@@ -813,7 +813,7 @@ uint8x16_t test_vabaq_u8(uint8x16_t v1, uint8x16_t v2, uint8x16_t v3) {
// CHECK-LABEL: @test_vabaq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v3 to <16 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> %v2, <8 x i16> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> %v2, <8 x i16> %v3)
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %v1, [[VABD2_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
uint16x8_t test_vabaq_u16(uint16x8_t v1, uint16x8_t v2, uint16x8_t v3) {
@@ -823,7 +823,7 @@ uint16x8_t test_vabaq_u16(uint16x8_t v1, uint16x8_t v2, uint16x8_t v3) {
// CHECK-LABEL: @test_vabaq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v3 to <16 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uabd.v4i32(<4 x i32> %v2, <4 x i32> %v3) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uabd.v4i32(<4 x i32> %v2, <4 x i32> %v3)
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %v1, [[VABD2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
uint32x4_t test_vabaq_u32(uint32x4_t v1, uint32x4_t v2, uint32x4_t v3) {
@@ -831,7 +831,7 @@ uint32x4_t test_vabaq_u32(uint32x4_t v1, uint32x4_t v2, uint32x4_t v3) {
}
// CHECK-LABEL: @test_vabd_s8(
-// CHECK: [[VABD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VABD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VABD_I]]
int8x8_t test_vabd_s8(int8x8_t v1, int8x8_t v2) {
return vabd_s8(v1, v2);
@@ -840,7 +840,7 @@ int8x8_t test_vabd_s8(int8x8_t v1, int8x8_t v2) {
// CHECK-LABEL: @test_vabd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: ret <4 x i16> [[VABD2_I]]
int16x4_t test_vabd_s16(int16x4_t v1, int16x4_t v2) {
return vabd_s16(v1, v2);
@@ -849,14 +849,14 @@ int16x4_t test_vabd_s16(int16x4_t v1, int16x4_t v2) {
// CHECK-LABEL: @test_vabd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: ret <2 x i32> [[VABD2_I]]
int32x2_t test_vabd_s32(int32x2_t v1, int32x2_t v2) {
return vabd_s32(v1, v2);
}
// CHECK-LABEL: @test_vabd_u8(
-// CHECK: [[VABD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VABD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VABD_I]]
uint8x8_t test_vabd_u8(uint8x8_t v1, uint8x8_t v2) {
return vabd_u8(v1, v2);
@@ -865,7 +865,7 @@ uint8x8_t test_vabd_u8(uint8x8_t v1, uint8x8_t v2) {
// CHECK-LABEL: @test_vabd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: ret <4 x i16> [[VABD2_I]]
uint16x4_t test_vabd_u16(uint16x4_t v1, uint16x4_t v2) {
return vabd_u16(v1, v2);
@@ -874,7 +874,7 @@ uint16x4_t test_vabd_u16(uint16x4_t v1, uint16x4_t v2) {
// CHECK-LABEL: @test_vabd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: ret <2 x i32> [[VABD2_I]]
uint32x2_t test_vabd_u32(uint32x2_t v1, uint32x2_t v2) {
return vabd_u32(v1, v2);
@@ -883,14 +883,14 @@ uint32x2_t test_vabd_u32(uint32x2_t v1, uint32x2_t v2) {
// CHECK-LABEL: @test_vabd_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fabd.v2f32(<2 x float> %v1, <2 x float> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fabd.v2f32(<2 x float> %v1, <2 x float> %v2)
// CHECK: ret <2 x float> [[VABD2_I]]
float32x2_t test_vabd_f32(float32x2_t v1, float32x2_t v2) {
return vabd_f32(v1, v2);
}
// CHECK-LABEL: @test_vabdq_s8(
-// CHECK: [[VABD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sabd.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VABD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sabd.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VABD_I]]
int8x16_t test_vabdq_s8(int8x16_t v1, int8x16_t v2) {
return vabdq_s8(v1, v2);
@@ -899,7 +899,7 @@ int8x16_t test_vabdq_s8(int8x16_t v1, int8x16_t v2) {
// CHECK-LABEL: @test_vabdq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: ret <8 x i16> [[VABD2_I]]
int16x8_t test_vabdq_s16(int16x8_t v1, int16x8_t v2) {
return vabdq_s16(v1, v2);
@@ -908,14 +908,14 @@ int16x8_t test_vabdq_s16(int16x8_t v1, int16x8_t v2) {
// CHECK-LABEL: @test_vabdq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sabd.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sabd.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: ret <4 x i32> [[VABD2_I]]
int32x4_t test_vabdq_s32(int32x4_t v1, int32x4_t v2) {
return vabdq_s32(v1, v2);
}
// CHECK-LABEL: @test_vabdq_u8(
-// CHECK: [[VABD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uabd.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VABD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uabd.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VABD_I]]
uint8x16_t test_vabdq_u8(uint8x16_t v1, uint8x16_t v2) {
return vabdq_u8(v1, v2);
@@ -924,7 +924,7 @@ uint8x16_t test_vabdq_u8(uint8x16_t v1, uint8x16_t v2) {
// CHECK-LABEL: @test_vabdq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: ret <8 x i16> [[VABD2_I]]
uint16x8_t test_vabdq_u16(uint16x8_t v1, uint16x8_t v2) {
return vabdq_u16(v1, v2);
@@ -933,7 +933,7 @@ uint16x8_t test_vabdq_u16(uint16x8_t v1, uint16x8_t v2) {
// CHECK-LABEL: @test_vabdq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uabd.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uabd.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: ret <4 x i32> [[VABD2_I]]
uint32x4_t test_vabdq_u32(uint32x4_t v1, uint32x4_t v2) {
return vabdq_u32(v1, v2);
@@ -942,7 +942,7 @@ uint32x4_t test_vabdq_u32(uint32x4_t v1, uint32x4_t v2) {
// CHECK-LABEL: @test_vabdq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fabd.v4f32(<4 x float> %v1, <4 x float> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fabd.v4f32(<4 x float> %v1, <4 x float> %v2)
// CHECK: ret <4 x float> [[VABD2_I]]
float32x4_t test_vabdq_f32(float32x4_t v1, float32x4_t v2) {
return vabdq_f32(v1, v2);
@@ -951,7 +951,7 @@ float32x4_t test_vabdq_f32(float32x4_t v1, float32x4_t v2) {
// CHECK-LABEL: @test_vabdq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fabd.v2f64(<2 x double> %v1, <2 x double> %v2) #4
+// CHECK: [[VABD2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fabd.v2f64(<2 x double> %v1, <2 x double> %v2)
// CHECK: ret <2 x double> [[VABD2_I]]
float64x2_t test_vabdq_f64(float64x2_t v1, float64x2_t v2) {
return vabdq_f64(v1, v2);
@@ -1268,7 +1268,7 @@ float64x2_t test_vbslq_f64(uint64x2_t v1, float64x2_t v2, float64x2_t v3) {
// CHECK-LABEL: @test_vrecps_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
-// CHECK: [[VRECPS_V2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frecps.v2f32(<2 x float> %v1, <2 x float> %v2) #4
+// CHECK: [[VRECPS_V2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frecps.v2f32(<2 x float> %v1, <2 x float> %v2)
// CHECK: ret <2 x float> [[VRECPS_V2_I]]
float32x2_t test_vrecps_f32(float32x2_t v1, float32x2_t v2) {
return vrecps_f32(v1, v2);
@@ -1277,7 +1277,7 @@ float32x2_t test_vrecps_f32(float32x2_t v1, float32x2_t v2) {
// CHECK-LABEL: @test_vrecpsq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
-// CHECK: [[VRECPSQ_V2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frecps.v4f32(<4 x float> %v1, <4 x float> %v2) #4
+// CHECK: [[VRECPSQ_V2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frecps.v4f32(<4 x float> %v1, <4 x float> %v2)
// CHECK: [[VRECPSQ_V3_I:%.*]] = bitcast <4 x float> [[VRECPSQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VRECPSQ_V2_I]]
float32x4_t test_vrecpsq_f32(float32x4_t v1, float32x4_t v2) {
@@ -1287,7 +1287,7 @@ float32x4_t test_vrecpsq_f32(float32x4_t v1, float32x4_t v2) {
// CHECK-LABEL: @test_vrecpsq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
-// CHECK: [[VRECPSQ_V2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frecps.v2f64(<2 x double> %v1, <2 x double> %v2) #4
+// CHECK: [[VRECPSQ_V2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frecps.v2f64(<2 x double> %v1, <2 x double> %v2)
// CHECK: [[VRECPSQ_V3_I:%.*]] = bitcast <2 x double> [[VRECPSQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x double> [[VRECPSQ_V2_I]]
float64x2_t test_vrecpsq_f64(float64x2_t v1, float64x2_t v2) {
@@ -1297,7 +1297,7 @@ float64x2_t test_vrecpsq_f64(float64x2_t v1, float64x2_t v2) {
// CHECK-LABEL: @test_vrsqrts_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
-// CHECK: [[VRSQRTS_V2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frsqrts.v2f32(<2 x float> %v1, <2 x float> %v2) #4
+// CHECK: [[VRSQRTS_V2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frsqrts.v2f32(<2 x float> %v1, <2 x float> %v2)
// CHECK: [[VRSQRTS_V3_I:%.*]] = bitcast <2 x float> [[VRSQRTS_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VRSQRTS_V2_I]]
float32x2_t test_vrsqrts_f32(float32x2_t v1, float32x2_t v2) {
@@ -1307,7 +1307,7 @@ float32x2_t test_vrsqrts_f32(float32x2_t v1, float32x2_t v2) {
// CHECK-LABEL: @test_vrsqrtsq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
-// CHECK: [[VRSQRTSQ_V2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frsqrts.v4f32(<4 x float> %v1, <4 x float> %v2) #4
+// CHECK: [[VRSQRTSQ_V2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frsqrts.v4f32(<4 x float> %v1, <4 x float> %v2)
// CHECK: [[VRSQRTSQ_V3_I:%.*]] = bitcast <4 x float> [[VRSQRTSQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VRSQRTSQ_V2_I]]
float32x4_t test_vrsqrtsq_f32(float32x4_t v1, float32x4_t v2) {
@@ -1317,7 +1317,7 @@ float32x4_t test_vrsqrtsq_f32(float32x4_t v1, float32x4_t v2) {
// CHECK-LABEL: @test_vrsqrtsq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
-// CHECK: [[VRSQRTSQ_V2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frsqrts.v2f64(<2 x double> %v1, <2 x double> %v2) #4
+// CHECK: [[VRSQRTSQ_V2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frsqrts.v2f64(<2 x double> %v1, <2 x double> %v2)
// CHECK: [[VRSQRTSQ_V3_I:%.*]] = bitcast <2 x double> [[VRSQRTSQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x double> [[VRSQRTSQ_V2_I]]
float64x2_t test_vrsqrtsq_f64(float64x2_t v1, float64x2_t v2) {
@@ -1327,7 +1327,7 @@ float64x2_t test_vrsqrtsq_f64(float64x2_t v1, float64x2_t v2) {
// CHECK-LABEL: @test_vcage_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
-// CHECK: [[VCAGE_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facge.v2i32.v2f32(<2 x float> %v1, <2 x float> %v2) #4
+// CHECK: [[VCAGE_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facge.v2i32.v2f32(<2 x float> %v1, <2 x float> %v2)
// CHECK: ret <2 x i32> [[VCAGE_V2_I]]
uint32x2_t test_vcage_f32(float32x2_t v1, float32x2_t v2) {
return vcage_f32(v1, v2);
@@ -1336,7 +1336,7 @@ uint32x2_t test_vcage_f32(float32x2_t v1, float32x2_t v2) {
// CHECK-LABEL: @test_vcage_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VCAGE_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facge.v1i64.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VCAGE_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facge.v1i64.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x i64> [[VCAGE_V2_I]]
uint64x1_t test_vcage_f64(float64x1_t a, float64x1_t b) {
return vcage_f64(a, b);
@@ -1345,7 +1345,7 @@ uint64x1_t test_vcage_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vcageq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
-// CHECK: [[VCAGEQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facge.v4i32.v4f32(<4 x float> %v1, <4 x float> %v2) #4
+// CHECK: [[VCAGEQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facge.v4i32.v4f32(<4 x float> %v1, <4 x float> %v2)
// CHECK: ret <4 x i32> [[VCAGEQ_V2_I]]
uint32x4_t test_vcageq_f32(float32x4_t v1, float32x4_t v2) {
return vcageq_f32(v1, v2);
@@ -1354,7 +1354,7 @@ uint32x4_t test_vcageq_f32(float32x4_t v1, float32x4_t v2) {
// CHECK-LABEL: @test_vcageq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
-// CHECK: [[VCAGEQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facge.v2i64.v2f64(<2 x double> %v1, <2 x double> %v2) #4
+// CHECK: [[VCAGEQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facge.v2i64.v2f64(<2 x double> %v1, <2 x double> %v2)
// CHECK: ret <2 x i64> [[VCAGEQ_V2_I]]
uint64x2_t test_vcageq_f64(float64x2_t v1, float64x2_t v2) {
return vcageq_f64(v1, v2);
@@ -1363,7 +1363,7 @@ uint64x2_t test_vcageq_f64(float64x2_t v1, float64x2_t v2) {
// CHECK-LABEL: @test_vcagt_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
-// CHECK: [[VCAGT_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facgt.v2i32.v2f32(<2 x float> %v1, <2 x float> %v2) #4
+// CHECK: [[VCAGT_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facgt.v2i32.v2f32(<2 x float> %v1, <2 x float> %v2)
// CHECK: ret <2 x i32> [[VCAGT_V2_I]]
uint32x2_t test_vcagt_f32(float32x2_t v1, float32x2_t v2) {
return vcagt_f32(v1, v2);
@@ -1372,7 +1372,7 @@ uint32x2_t test_vcagt_f32(float32x2_t v1, float32x2_t v2) {
// CHECK-LABEL: @test_vcagt_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VCAGT_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facgt.v1i64.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VCAGT_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facgt.v1i64.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x i64> [[VCAGT_V2_I]]
uint64x1_t test_vcagt_f64(float64x1_t a, float64x1_t b) {
return vcagt_f64(a, b);
@@ -1381,7 +1381,7 @@ uint64x1_t test_vcagt_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vcagtq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
-// CHECK: [[VCAGTQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facgt.v4i32.v4f32(<4 x float> %v1, <4 x float> %v2) #4
+// CHECK: [[VCAGTQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facgt.v4i32.v4f32(<4 x float> %v1, <4 x float> %v2)
// CHECK: ret <4 x i32> [[VCAGTQ_V2_I]]
uint32x4_t test_vcagtq_f32(float32x4_t v1, float32x4_t v2) {
return vcagtq_f32(v1, v2);
@@ -1390,7 +1390,7 @@ uint32x4_t test_vcagtq_f32(float32x4_t v1, float32x4_t v2) {
// CHECK-LABEL: @test_vcagtq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
-// CHECK: [[VCAGTQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facgt.v2i64.v2f64(<2 x double> %v1, <2 x double> %v2) #4
+// CHECK: [[VCAGTQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facgt.v2i64.v2f64(<2 x double> %v1, <2 x double> %v2)
// CHECK: ret <2 x i64> [[VCAGTQ_V2_I]]
uint64x2_t test_vcagtq_f64(float64x2_t v1, float64x2_t v2) {
return vcagtq_f64(v1, v2);
@@ -1399,7 +1399,7 @@ uint64x2_t test_vcagtq_f64(float64x2_t v1, float64x2_t v2) {
// CHECK-LABEL: @test_vcale_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
-// CHECK: [[VCALE_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facge.v2i32.v2f32(<2 x float> %v2, <2 x float> %v1) #4
+// CHECK: [[VCALE_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facge.v2i32.v2f32(<2 x float> %v2, <2 x float> %v1)
// CHECK: ret <2 x i32> [[VCALE_V2_I]]
uint32x2_t test_vcale_f32(float32x2_t v1, float32x2_t v2) {
return vcale_f32(v1, v2);
@@ -1409,7 +1409,7 @@ uint32x2_t test_vcale_f32(float32x2_t v1, float32x2_t v2) {
// CHECK-LABEL: @test_vcale_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VCALE_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facge.v1i64.v1f64(<1 x double> %b, <1 x double> %a) #4
+// CHECK: [[VCALE_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facge.v1i64.v1f64(<1 x double> %b, <1 x double> %a)
// CHECK: ret <1 x i64> [[VCALE_V2_I]]
uint64x1_t test_vcale_f64(float64x1_t a, float64x1_t b) {
return vcale_f64(a, b);
@@ -1418,7 +1418,7 @@ uint64x1_t test_vcale_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vcaleq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
-// CHECK: [[VCALEQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facge.v4i32.v4f32(<4 x float> %v2, <4 x float> %v1) #4
+// CHECK: [[VCALEQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facge.v4i32.v4f32(<4 x float> %v2, <4 x float> %v1)
// CHECK: ret <4 x i32> [[VCALEQ_V2_I]]
uint32x4_t test_vcaleq_f32(float32x4_t v1, float32x4_t v2) {
return vcaleq_f32(v1, v2);
@@ -1428,7 +1428,7 @@ uint32x4_t test_vcaleq_f32(float32x4_t v1, float32x4_t v2) {
// CHECK-LABEL: @test_vcaleq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
-// CHECK: [[VCALEQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facge.v2i64.v2f64(<2 x double> %v2, <2 x double> %v1) #4
+// CHECK: [[VCALEQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facge.v2i64.v2f64(<2 x double> %v2, <2 x double> %v1)
// CHECK: ret <2 x i64> [[VCALEQ_V2_I]]
uint64x2_t test_vcaleq_f64(float64x2_t v1, float64x2_t v2) {
return vcaleq_f64(v1, v2);
@@ -1438,7 +1438,7 @@ uint64x2_t test_vcaleq_f64(float64x2_t v1, float64x2_t v2) {
// CHECK-LABEL: @test_vcalt_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %v2 to <8 x i8>
-// CHECK: [[VCALT_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facgt.v2i32.v2f32(<2 x float> %v2, <2 x float> %v1) #4
+// CHECK: [[VCALT_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.facgt.v2i32.v2f32(<2 x float> %v2, <2 x float> %v1)
// CHECK: ret <2 x i32> [[VCALT_V2_I]]
uint32x2_t test_vcalt_f32(float32x2_t v1, float32x2_t v2) {
return vcalt_f32(v1, v2);
@@ -1448,7 +1448,7 @@ uint32x2_t test_vcalt_f32(float32x2_t v1, float32x2_t v2) {
// CHECK-LABEL: @test_vcalt_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VCALT_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facgt.v1i64.v1f64(<1 x double> %b, <1 x double> %a) #4
+// CHECK: [[VCALT_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.facgt.v1i64.v1f64(<1 x double> %b, <1 x double> %a)
// CHECK: ret <1 x i64> [[VCALT_V2_I]]
uint64x1_t test_vcalt_f64(float64x1_t a, float64x1_t b) {
return vcalt_f64(a, b);
@@ -1457,7 +1457,7 @@ uint64x1_t test_vcalt_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vcaltq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %v2 to <16 x i8>
-// CHECK: [[VCALTQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facgt.v4i32.v4f32(<4 x float> %v2, <4 x float> %v1) #4
+// CHECK: [[VCALTQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.facgt.v4i32.v4f32(<4 x float> %v2, <4 x float> %v1)
// CHECK: ret <4 x i32> [[VCALTQ_V2_I]]
uint32x4_t test_vcaltq_f32(float32x4_t v1, float32x4_t v2) {
return vcaltq_f32(v1, v2);
@@ -1467,7 +1467,7 @@ uint32x4_t test_vcaltq_f32(float32x4_t v1, float32x4_t v2) {
// CHECK-LABEL: @test_vcaltq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %v2 to <16 x i8>
-// CHECK: [[VCALTQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facgt.v2i64.v2f64(<2 x double> %v2, <2 x double> %v1) #4
+// CHECK: [[VCALTQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.facgt.v2i64.v2f64(<2 x double> %v2, <2 x double> %v1)
// CHECK: ret <2 x i64> [[VCALTQ_V2_I]]
uint64x2_t test_vcaltq_f64(float64x2_t v1, float64x2_t v2) {
return vcaltq_f64(v1, v2);
@@ -2505,7 +2505,7 @@ uint64x2_t test_vcltq_f64(float64x2_t v1, float64x2_t v2) {
}
// CHECK-LABEL: @test_vhadd_s8(
-// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.shadd.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.shadd.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VHADD_V_I]]
int8x8_t test_vhadd_s8(int8x8_t v1, int8x8_t v2) {
return vhadd_s8(v1, v2);
@@ -2514,7 +2514,7 @@ int8x8_t test_vhadd_s8(int8x8_t v1, int8x8_t v2) {
// CHECK-LABEL: @test_vhadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.shadd.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.shadd.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <4 x i16> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHADD_V2_I]]
int16x4_t test_vhadd_s16(int16x4_t v1, int16x4_t v2) {
@@ -2524,7 +2524,7 @@ int16x4_t test_vhadd_s16(int16x4_t v1, int16x4_t v2) {
// CHECK-LABEL: @test_vhadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.shadd.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.shadd.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <2 x i32> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHADD_V2_I]]
int32x2_t test_vhadd_s32(int32x2_t v1, int32x2_t v2) {
@@ -2532,7 +2532,7 @@ int32x2_t test_vhadd_s32(int32x2_t v1, int32x2_t v2) {
}
// CHECK-LABEL: @test_vhadd_u8(
-// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uhadd.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uhadd.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VHADD_V_I]]
uint8x8_t test_vhadd_u8(uint8x8_t v1, uint8x8_t v2) {
return vhadd_u8(v1, v2);
@@ -2541,7 +2541,7 @@ uint8x8_t test_vhadd_u8(uint8x8_t v1, uint8x8_t v2) {
// CHECK-LABEL: @test_vhadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uhadd.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uhadd.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <4 x i16> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHADD_V2_I]]
uint16x4_t test_vhadd_u16(uint16x4_t v1, uint16x4_t v2) {
@@ -2551,7 +2551,7 @@ uint16x4_t test_vhadd_u16(uint16x4_t v1, uint16x4_t v2) {
// CHECK-LABEL: @test_vhadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uhadd.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uhadd.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <2 x i32> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHADD_V2_I]]
uint32x2_t test_vhadd_u32(uint32x2_t v1, uint32x2_t v2) {
@@ -2559,7 +2559,7 @@ uint32x2_t test_vhadd_u32(uint32x2_t v1, uint32x2_t v2) {
}
// CHECK-LABEL: @test_vhaddq_s8(
-// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.shadd.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.shadd.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VHADDQ_V_I]]
int8x16_t test_vhaddq_s8(int8x16_t v1, int8x16_t v2) {
return vhaddq_s8(v1, v2);
@@ -2568,7 +2568,7 @@ int8x16_t test_vhaddq_s8(int8x16_t v1, int8x16_t v2) {
// CHECK-LABEL: @test_vhaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.shadd.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.shadd.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHADDQ_V2_I]]
int16x8_t test_vhaddq_s16(int16x8_t v1, int16x8_t v2) {
@@ -2578,7 +2578,7 @@ int16x8_t test_vhaddq_s16(int16x8_t v1, int16x8_t v2) {
// CHECK-LABEL: @test_vhaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.shadd.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.shadd.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHADDQ_V2_I]]
int32x4_t test_vhaddq_s32(int32x4_t v1, int32x4_t v2) {
@@ -2586,7 +2586,7 @@ int32x4_t test_vhaddq_s32(int32x4_t v1, int32x4_t v2) {
}
// CHECK-LABEL: @test_vhaddq_u8(
-// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uhadd.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uhadd.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VHADDQ_V_I]]
uint8x16_t test_vhaddq_u8(uint8x16_t v1, uint8x16_t v2) {
return vhaddq_u8(v1, v2);
@@ -2595,7 +2595,7 @@ uint8x16_t test_vhaddq_u8(uint8x16_t v1, uint8x16_t v2) {
// CHECK-LABEL: @test_vhaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uhadd.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uhadd.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHADDQ_V2_I]]
uint16x8_t test_vhaddq_u16(uint16x8_t v1, uint16x8_t v2) {
@@ -2605,7 +2605,7 @@ uint16x8_t test_vhaddq_u16(uint16x8_t v1, uint16x8_t v2) {
// CHECK-LABEL: @test_vhaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uhadd.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uhadd.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHADDQ_V2_I]]
uint32x4_t test_vhaddq_u32(uint32x4_t v1, uint32x4_t v2) {
@@ -2613,7 +2613,7 @@ uint32x4_t test_vhaddq_u32(uint32x4_t v1, uint32x4_t v2) {
}
// CHECK-LABEL: @test_vhsub_s8(
-// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.shsub.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.shsub.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VHSUB_V_I]]
int8x8_t test_vhsub_s8(int8x8_t v1, int8x8_t v2) {
return vhsub_s8(v1, v2);
@@ -2622,7 +2622,7 @@ int8x8_t test_vhsub_s8(int8x8_t v1, int8x8_t v2) {
// CHECK-LABEL: @test_vhsub_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.shsub.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.shsub.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <4 x i16> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHSUB_V2_I]]
int16x4_t test_vhsub_s16(int16x4_t v1, int16x4_t v2) {
@@ -2632,7 +2632,7 @@ int16x4_t test_vhsub_s16(int16x4_t v1, int16x4_t v2) {
// CHECK-LABEL: @test_vhsub_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.shsub.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.shsub.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <2 x i32> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHSUB_V2_I]]
int32x2_t test_vhsub_s32(int32x2_t v1, int32x2_t v2) {
@@ -2640,7 +2640,7 @@ int32x2_t test_vhsub_s32(int32x2_t v1, int32x2_t v2) {
}
// CHECK-LABEL: @test_vhsub_u8(
-// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uhsub.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uhsub.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VHSUB_V_I]]
uint8x8_t test_vhsub_u8(uint8x8_t v1, uint8x8_t v2) {
return vhsub_u8(v1, v2);
@@ -2649,7 +2649,7 @@ uint8x8_t test_vhsub_u8(uint8x8_t v1, uint8x8_t v2) {
// CHECK-LABEL: @test_vhsub_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uhsub.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uhsub.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <4 x i16> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHSUB_V2_I]]
uint16x4_t test_vhsub_u16(uint16x4_t v1, uint16x4_t v2) {
@@ -2659,7 +2659,7 @@ uint16x4_t test_vhsub_u16(uint16x4_t v1, uint16x4_t v2) {
// CHECK-LABEL: @test_vhsub_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uhsub.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uhsub.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <2 x i32> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHSUB_V2_I]]
uint32x2_t test_vhsub_u32(uint32x2_t v1, uint32x2_t v2) {
@@ -2667,7 +2667,7 @@ uint32x2_t test_vhsub_u32(uint32x2_t v1, uint32x2_t v2) {
}
// CHECK-LABEL: @test_vhsubq_s8(
-// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.shsub.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.shsub.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VHSUBQ_V_I]]
int8x16_t test_vhsubq_s8(int8x16_t v1, int8x16_t v2) {
return vhsubq_s8(v1, v2);
@@ -2676,7 +2676,7 @@ int8x16_t test_vhsubq_s8(int8x16_t v1, int8x16_t v2) {
// CHECK-LABEL: @test_vhsubq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.shsub.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.shsub.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHSUBQ_V2_I]]
int16x8_t test_vhsubq_s16(int16x8_t v1, int16x8_t v2) {
@@ -2686,7 +2686,7 @@ int16x8_t test_vhsubq_s16(int16x8_t v1, int16x8_t v2) {
// CHECK-LABEL: @test_vhsubq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.shsub.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.shsub.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHSUBQ_V2_I]]
int32x4_t test_vhsubq_s32(int32x4_t v1, int32x4_t v2) {
@@ -2694,7 +2694,7 @@ int32x4_t test_vhsubq_s32(int32x4_t v1, int32x4_t v2) {
}
// CHECK-LABEL: @test_vhsubq_u8(
-// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uhsub.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uhsub.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VHSUBQ_V_I]]
uint8x16_t test_vhsubq_u8(uint8x16_t v1, uint8x16_t v2) {
return vhsubq_u8(v1, v2);
@@ -2703,7 +2703,7 @@ uint8x16_t test_vhsubq_u8(uint8x16_t v1, uint8x16_t v2) {
// CHECK-LABEL: @test_vhsubq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uhsub.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uhsub.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHSUBQ_V2_I]]
uint16x8_t test_vhsubq_u16(uint16x8_t v1, uint16x8_t v2) {
@@ -2713,7 +2713,7 @@ uint16x8_t test_vhsubq_u16(uint16x8_t v1, uint16x8_t v2) {
// CHECK-LABEL: @test_vhsubq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uhsub.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uhsub.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHSUBQ_V2_I]]
uint32x4_t test_vhsubq_u32(uint32x4_t v1, uint32x4_t v2) {
@@ -2721,7 +2721,7 @@ uint32x4_t test_vhsubq_u32(uint32x4_t v1, uint32x4_t v2) {
}
// CHECK-LABEL: @test_vrhadd_s8(
-// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.srhadd.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.srhadd.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VRHADD_V_I]]
int8x8_t test_vrhadd_s8(int8x8_t v1, int8x8_t v2) {
return vrhadd_s8(v1, v2);
@@ -2730,7 +2730,7 @@ int8x8_t test_vrhadd_s8(int8x8_t v1, int8x8_t v2) {
// CHECK-LABEL: @test_vrhadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.srhadd.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.srhadd.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <4 x i16> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRHADD_V2_I]]
int16x4_t test_vrhadd_s16(int16x4_t v1, int16x4_t v2) {
@@ -2740,7 +2740,7 @@ int16x4_t test_vrhadd_s16(int16x4_t v1, int16x4_t v2) {
// CHECK-LABEL: @test_vrhadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.srhadd.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.srhadd.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <2 x i32> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRHADD_V2_I]]
int32x2_t test_vrhadd_s32(int32x2_t v1, int32x2_t v2) {
@@ -2748,7 +2748,7 @@ int32x2_t test_vrhadd_s32(int32x2_t v1, int32x2_t v2) {
}
// CHECK-LABEL: @test_vrhadd_u8(
-// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.urhadd.v8i8(<8 x i8> %v1, <8 x i8> %v2) #4
+// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.urhadd.v8i8(<8 x i8> %v1, <8 x i8> %v2)
// CHECK: ret <8 x i8> [[VRHADD_V_I]]
uint8x8_t test_vrhadd_u8(uint8x8_t v1, uint8x8_t v2) {
return vrhadd_u8(v1, v2);
@@ -2757,7 +2757,7 @@ uint8x8_t test_vrhadd_u8(uint8x8_t v1, uint8x8_t v2) {
// CHECK-LABEL: @test_vrhadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %v2 to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.urhadd.v4i16(<4 x i16> %v1, <4 x i16> %v2) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.urhadd.v4i16(<4 x i16> %v1, <4 x i16> %v2)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <4 x i16> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRHADD_V2_I]]
uint16x4_t test_vrhadd_u16(uint16x4_t v1, uint16x4_t v2) {
@@ -2767,7 +2767,7 @@ uint16x4_t test_vrhadd_u16(uint16x4_t v1, uint16x4_t v2) {
// CHECK-LABEL: @test_vrhadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %v1 to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %v2 to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.urhadd.v2i32(<2 x i32> %v1, <2 x i32> %v2) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.urhadd.v2i32(<2 x i32> %v1, <2 x i32> %v2)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <2 x i32> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRHADD_V2_I]]
uint32x2_t test_vrhadd_u32(uint32x2_t v1, uint32x2_t v2) {
@@ -2775,7 +2775,7 @@ uint32x2_t test_vrhadd_u32(uint32x2_t v1, uint32x2_t v2) {
}
// CHECK-LABEL: @test_vrhaddq_s8(
-// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.srhadd.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.srhadd.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VRHADDQ_V_I]]
int8x16_t test_vrhaddq_s8(int8x16_t v1, int8x16_t v2) {
return vrhaddq_s8(v1, v2);
@@ -2784,7 +2784,7 @@ int8x16_t test_vrhaddq_s8(int8x16_t v1, int8x16_t v2) {
// CHECK-LABEL: @test_vrhaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.srhadd.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.srhadd.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRHADDQ_V2_I]]
int16x8_t test_vrhaddq_s16(int16x8_t v1, int16x8_t v2) {
@@ -2794,7 +2794,7 @@ int16x8_t test_vrhaddq_s16(int16x8_t v1, int16x8_t v2) {
// CHECK-LABEL: @test_vrhaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.srhadd.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.srhadd.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRHADDQ_V2_I]]
int32x4_t test_vrhaddq_s32(int32x4_t v1, int32x4_t v2) {
@@ -2802,7 +2802,7 @@ int32x4_t test_vrhaddq_s32(int32x4_t v1, int32x4_t v2) {
}
// CHECK-LABEL: @test_vrhaddq_u8(
-// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.urhadd.v16i8(<16 x i8> %v1, <16 x i8> %v2) #4
+// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.urhadd.v16i8(<16 x i8> %v1, <16 x i8> %v2)
// CHECK: ret <16 x i8> [[VRHADDQ_V_I]]
uint8x16_t test_vrhaddq_u8(uint8x16_t v1, uint8x16_t v2) {
return vrhaddq_u8(v1, v2);
@@ -2811,7 +2811,7 @@ uint8x16_t test_vrhaddq_u8(uint8x16_t v1, uint8x16_t v2) {
// CHECK-LABEL: @test_vrhaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %v2 to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.urhadd.v8i16(<8 x i16> %v1, <8 x i16> %v2) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.urhadd.v8i16(<8 x i16> %v1, <8 x i16> %v2)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRHADDQ_V2_I]]
uint16x8_t test_vrhaddq_u16(uint16x8_t v1, uint16x8_t v2) {
@@ -2821,7 +2821,7 @@ uint16x8_t test_vrhaddq_u16(uint16x8_t v1, uint16x8_t v2) {
// CHECK-LABEL: @test_vrhaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %v1 to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %v2 to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.urhadd.v4i32(<4 x i32> %v1, <4 x i32> %v2) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.urhadd.v4i32(<4 x i32> %v1, <4 x i32> %v2)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRHADDQ_V2_I]]
uint32x4_t test_vrhaddq_u32(uint32x4_t v1, uint32x4_t v2) {
@@ -2829,7 +2829,7 @@ uint32x4_t test_vrhaddq_u32(uint32x4_t v1, uint32x4_t v2) {
}
// CHECK-LABEL: @test_vqadd_s8(
-// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqadd.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqadd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQADD_V_I]]
int8x8_t test_vqadd_s8(int8x8_t a, int8x8_t b) {
return vqadd_s8(a, b);
@@ -2838,7 +2838,7 @@ int8x8_t test_vqadd_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <4 x i16> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQADD_V2_I]]
int16x4_t test_vqadd_s16(int16x4_t a, int16x4_t b) {
@@ -2848,7 +2848,7 @@ int16x4_t test_vqadd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqadd.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqadd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <2 x i32> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQADD_V2_I]]
int32x2_t test_vqadd_s32(int32x2_t a, int32x2_t b) {
@@ -2858,7 +2858,7 @@ int32x2_t test_vqadd_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqadd_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqadd.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqadd.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <1 x i64> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQADD_V2_I]]
int64x1_t test_vqadd_s64(int64x1_t a, int64x1_t b) {
@@ -2866,7 +2866,7 @@ int64x1_t test_vqadd_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqadd_u8(
-// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqadd.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqadd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQADD_V_I]]
uint8x8_t test_vqadd_u8(uint8x8_t a, uint8x8_t b) {
return vqadd_u8(a, b);
@@ -2875,7 +2875,7 @@ uint8x8_t test_vqadd_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vqadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqadd.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqadd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <4 x i16> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQADD_V2_I]]
uint16x4_t test_vqadd_u16(uint16x4_t a, uint16x4_t b) {
@@ -2885,7 +2885,7 @@ uint16x4_t test_vqadd_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vqadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqadd.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqadd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <2 x i32> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQADD_V2_I]]
uint32x2_t test_vqadd_u32(uint32x2_t a, uint32x2_t b) {
@@ -2895,7 +2895,7 @@ uint32x2_t test_vqadd_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vqadd_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqadd.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqadd.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <1 x i64> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQADD_V2_I]]
uint64x1_t test_vqadd_u64(uint64x1_t a, uint64x1_t b) {
@@ -2903,7 +2903,7 @@ uint64x1_t test_vqadd_u64(uint64x1_t a, uint64x1_t b) {
}
// CHECK-LABEL: @test_vqaddq_s8(
-// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqadd.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqadd.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQADDQ_V_I]]
int8x16_t test_vqaddq_s8(int8x16_t a, int8x16_t b) {
return vqaddq_s8(a, b);
@@ -2912,7 +2912,7 @@ int8x16_t test_vqaddq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqadd.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqadd.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQADDQ_V2_I]]
int16x8_t test_vqaddq_s16(int16x8_t a, int16x8_t b) {
@@ -2922,7 +2922,7 @@ int16x8_t test_vqaddq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQADDQ_V2_I]]
int32x4_t test_vqaddq_s32(int32x4_t a, int32x4_t b) {
@@ -2932,7 +2932,7 @@ int32x4_t test_vqaddq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqaddq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <2 x i64> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQADDQ_V2_I]]
int64x2_t test_vqaddq_s64(int64x2_t a, int64x2_t b) {
@@ -2940,7 +2940,7 @@ int64x2_t test_vqaddq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqaddq_u8(
-// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqadd.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqadd.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQADDQ_V_I]]
uint8x16_t test_vqaddq_u8(uint8x16_t a, uint8x16_t b) {
return vqaddq_u8(a, b);
@@ -2949,7 +2949,7 @@ uint8x16_t test_vqaddq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vqaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqadd.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqadd.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQADDQ_V2_I]]
uint16x8_t test_vqaddq_u16(uint16x8_t a, uint16x8_t b) {
@@ -2959,7 +2959,7 @@ uint16x8_t test_vqaddq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vqaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqadd.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqadd.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQADDQ_V2_I]]
uint32x4_t test_vqaddq_u32(uint32x4_t a, uint32x4_t b) {
@@ -2969,7 +2969,7 @@ uint32x4_t test_vqaddq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vqaddq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqadd.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqadd.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <2 x i64> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQADDQ_V2_I]]
uint64x2_t test_vqaddq_u64(uint64x2_t a, uint64x2_t b) {
@@ -2977,7 +2977,7 @@ uint64x2_t test_vqaddq_u64(uint64x2_t a, uint64x2_t b) {
}
// CHECK-LABEL: @test_vqsub_s8(
-// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqsub.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqsub.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSUB_V_I]]
int8x8_t test_vqsub_s8(int8x8_t a, int8x8_t b) {
return vqsub_s8(a, b);
@@ -2986,7 +2986,7 @@ int8x8_t test_vqsub_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqsub_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <4 x i16> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSUB_V2_I]]
int16x4_t test_vqsub_s16(int16x4_t a, int16x4_t b) {
@@ -2996,7 +2996,7 @@ int16x4_t test_vqsub_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqsub_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqsub.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqsub.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <2 x i32> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSUB_V2_I]]
int32x2_t test_vqsub_s32(int32x2_t a, int32x2_t b) {
@@ -3006,7 +3006,7 @@ int32x2_t test_vqsub_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqsub_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqsub.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqsub.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <1 x i64> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSUB_V2_I]]
int64x1_t test_vqsub_s64(int64x1_t a, int64x1_t b) {
@@ -3014,7 +3014,7 @@ int64x1_t test_vqsub_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqsub_u8(
-// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqsub.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqsub.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSUB_V_I]]
uint8x8_t test_vqsub_u8(uint8x8_t a, uint8x8_t b) {
return vqsub_u8(a, b);
@@ -3023,7 +3023,7 @@ uint8x8_t test_vqsub_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vqsub_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqsub.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqsub.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <4 x i16> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSUB_V2_I]]
uint16x4_t test_vqsub_u16(uint16x4_t a, uint16x4_t b) {
@@ -3033,7 +3033,7 @@ uint16x4_t test_vqsub_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vqsub_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqsub.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqsub.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <2 x i32> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSUB_V2_I]]
uint32x2_t test_vqsub_u32(uint32x2_t a, uint32x2_t b) {
@@ -3043,7 +3043,7 @@ uint32x2_t test_vqsub_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vqsub_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqsub.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqsub.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <1 x i64> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSUB_V2_I]]
uint64x1_t test_vqsub_u64(uint64x1_t a, uint64x1_t b) {
@@ -3051,7 +3051,7 @@ uint64x1_t test_vqsub_u64(uint64x1_t a, uint64x1_t b) {
}
// CHECK-LABEL: @test_vqsubq_s8(
-// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqsub.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqsub.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSUBQ_V_I]]
int8x16_t test_vqsubq_s8(int8x16_t a, int8x16_t b) {
return vqsubq_s8(a, b);
@@ -3060,7 +3060,7 @@ int8x16_t test_vqsubq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqsubq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqsub.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqsub.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSUBQ_V2_I]]
int16x8_t test_vqsubq_s16(int16x8_t a, int16x8_t b) {
@@ -3070,7 +3070,7 @@ int16x8_t test_vqsubq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqsubq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSUBQ_V2_I]]
int32x4_t test_vqsubq_s32(int32x4_t a, int32x4_t b) {
@@ -3080,7 +3080,7 @@ int32x4_t test_vqsubq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqsubq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSUBQ_V2_I]]
int64x2_t test_vqsubq_s64(int64x2_t a, int64x2_t b) {
@@ -3088,7 +3088,7 @@ int64x2_t test_vqsubq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqsubq_u8(
-// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqsub.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqsub.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSUBQ_V_I]]
uint8x16_t test_vqsubq_u8(uint8x16_t a, uint8x16_t b) {
return vqsubq_u8(a, b);
@@ -3097,7 +3097,7 @@ uint8x16_t test_vqsubq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vqsubq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqsub.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqsub.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSUBQ_V2_I]]
uint16x8_t test_vqsubq_u16(uint16x8_t a, uint16x8_t b) {
@@ -3107,7 +3107,7 @@ uint16x8_t test_vqsubq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vqsubq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqsub.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqsub.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSUBQ_V2_I]]
uint32x4_t test_vqsubq_u32(uint32x4_t a, uint32x4_t b) {
@@ -3117,7 +3117,7 @@ uint32x4_t test_vqsubq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vqsubq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqsub.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqsub.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSUBQ_V2_I]]
uint64x2_t test_vqsubq_u64(uint64x2_t a, uint64x2_t b) {
@@ -3125,7 +3125,7 @@ uint64x2_t test_vqsubq_u64(uint64x2_t a, uint64x2_t b) {
}
// CHECK-LABEL: @test_vshl_s8(
-// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sshl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sshl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VSHL_V_I]]
int8x8_t test_vshl_s8(int8x8_t a, int8x8_t b) {
return vshl_s8(a, b);
@@ -3134,7 +3134,7 @@ int8x8_t test_vshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sshl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sshl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <4 x i16> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VSHL_V2_I]]
int16x4_t test_vshl_s16(int16x4_t a, int16x4_t b) {
@@ -3144,7 +3144,7 @@ int16x4_t test_vshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sshl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sshl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <2 x i32> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VSHL_V2_I]]
int32x2_t test_vshl_s32(int32x2_t a, int32x2_t b) {
@@ -3154,7 +3154,7 @@ int32x2_t test_vshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sshl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sshl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <1 x i64> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VSHL_V2_I]]
int64x1_t test_vshl_s64(int64x1_t a, int64x1_t b) {
@@ -3162,7 +3162,7 @@ int64x1_t test_vshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vshl_u8(
-// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.ushl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.ushl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VSHL_V_I]]
uint8x8_t test_vshl_u8(uint8x8_t a, int8x8_t b) {
return vshl_u8(a, b);
@@ -3171,7 +3171,7 @@ uint8x8_t test_vshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.ushl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.ushl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <4 x i16> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VSHL_V2_I]]
uint16x4_t test_vshl_u16(uint16x4_t a, int16x4_t b) {
@@ -3181,7 +3181,7 @@ uint16x4_t test_vshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.ushl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.ushl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <2 x i32> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VSHL_V2_I]]
uint32x2_t test_vshl_u32(uint32x2_t a, int32x2_t b) {
@@ -3191,7 +3191,7 @@ uint32x2_t test_vshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.ushl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.ushl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <1 x i64> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VSHL_V2_I]]
uint64x1_t test_vshl_u64(uint64x1_t a, int64x1_t b) {
@@ -3199,7 +3199,7 @@ uint64x1_t test_vshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vshlq_s8(
-// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sshl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sshl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VSHLQ_V_I]]
int8x16_t test_vshlq_s8(int8x16_t a, int8x16_t b) {
return vshlq_s8(a, b);
@@ -3208,7 +3208,7 @@ int8x16_t test_vshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sshl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VSHLQ_V2_I]]
int16x8_t test_vshlq_s16(int16x8_t a, int16x8_t b) {
@@ -3218,7 +3218,7 @@ int16x8_t test_vshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sshl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VSHLQ_V2_I]]
int32x4_t test_vshlq_s32(int32x4_t a, int32x4_t b) {
@@ -3228,7 +3228,7 @@ int32x4_t test_vshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sshl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sshl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VSHLQ_V2_I]]
int64x2_t test_vshlq_s64(int64x2_t a, int64x2_t b) {
@@ -3236,7 +3236,7 @@ int64x2_t test_vshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vshlq_u8(
-// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.ushl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VSHLQ_V_I]]
uint8x16_t test_vshlq_u8(uint8x16_t a, int8x16_t b) {
return vshlq_u8(a, b);
@@ -3245,7 +3245,7 @@ uint8x16_t test_vshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.ushl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VSHLQ_V2_I]]
uint16x8_t test_vshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -3255,7 +3255,7 @@ uint16x8_t test_vshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.ushl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VSHLQ_V2_I]]
uint32x4_t test_vshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -3265,7 +3265,7 @@ uint32x4_t test_vshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.ushl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.ushl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VSHLQ_V2_I]]
uint64x2_t test_vshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -3273,7 +3273,7 @@ uint64x2_t test_vshlq_u64(uint64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqshl_s8(
-// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSHL_V_I]]
int8x8_t test_vqshl_s8(int8x8_t a, int8x8_t b) {
return vqshl_s8(a, b);
@@ -3282,7 +3282,7 @@ int8x8_t test_vqshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSHL_V2_I]]
int16x4_t test_vqshl_s16(int16x4_t a, int16x4_t b) {
@@ -3292,7 +3292,7 @@ int16x4_t test_vqshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqshl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSHL_V2_I]]
int32x2_t test_vqshl_s32(int32x2_t a, int32x2_t b) {
@@ -3302,7 +3302,7 @@ int32x2_t test_vqshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqshl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqshl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSHL_V2_I]]
int64x1_t test_vqshl_s64(int64x1_t a, int64x1_t b) {
@@ -3310,7 +3310,7 @@ int64x1_t test_vqshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqshl_u8(
-// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSHL_V_I]]
uint8x8_t test_vqshl_u8(uint8x8_t a, int8x8_t b) {
return vqshl_u8(a, b);
@@ -3319,7 +3319,7 @@ uint8x8_t test_vqshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSHL_V2_I]]
uint16x4_t test_vqshl_u16(uint16x4_t a, int16x4_t b) {
@@ -3329,7 +3329,7 @@ uint16x4_t test_vqshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqshl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqshl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSHL_V2_I]]
uint32x2_t test_vqshl_u32(uint32x2_t a, int32x2_t b) {
@@ -3339,7 +3339,7 @@ uint32x2_t test_vqshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqshl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqshl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSHL_V2_I]]
uint64x1_t test_vqshl_u64(uint64x1_t a, int64x1_t b) {
@@ -3347,7 +3347,7 @@ uint64x1_t test_vqshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqshlq_s8(
-// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqshl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqshl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSHLQ_V_I]]
int8x16_t test_vqshlq_s8(int8x16_t a, int8x16_t b) {
return vqshlq_s8(a, b);
@@ -3356,7 +3356,7 @@ int8x16_t test_vqshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqshl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqshl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSHLQ_V2_I]]
int16x8_t test_vqshlq_s16(int16x8_t a, int16x8_t b) {
@@ -3366,7 +3366,7 @@ int16x8_t test_vqshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqshl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqshl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSHLQ_V2_I]]
int32x4_t test_vqshlq_s32(int32x4_t a, int32x4_t b) {
@@ -3376,7 +3376,7 @@ int32x4_t test_vqshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqshl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqshl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSHLQ_V2_I]]
int64x2_t test_vqshlq_s64(int64x2_t a, int64x2_t b) {
@@ -3384,7 +3384,7 @@ int64x2_t test_vqshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqshlq_u8(
-// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqshl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqshl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSHLQ_V_I]]
uint8x16_t test_vqshlq_u8(uint8x16_t a, int8x16_t b) {
return vqshlq_u8(a, b);
@@ -3393,7 +3393,7 @@ uint8x16_t test_vqshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqshl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqshl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSHLQ_V2_I]]
uint16x8_t test_vqshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -3403,7 +3403,7 @@ uint16x8_t test_vqshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqshl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqshl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSHLQ_V2_I]]
uint32x4_t test_vqshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -3413,7 +3413,7 @@ uint32x4_t test_vqshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqshl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqshl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSHLQ_V2_I]]
uint64x2_t test_vqshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -3421,7 +3421,7 @@ uint64x2_t test_vqshlq_u64(uint64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vrshl_s8(
-// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.srshl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.srshl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VRSHL_V_I]]
int8x8_t test_vrshl_s8(int8x8_t a, int8x8_t b) {
return vrshl_s8(a, b);
@@ -3430,7 +3430,7 @@ int8x8_t test_vrshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vrshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.srshl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.srshl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSHL_V2_I]]
int16x4_t test_vrshl_s16(int16x4_t a, int16x4_t b) {
@@ -3440,7 +3440,7 @@ int16x4_t test_vrshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vrshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.srshl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.srshl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSHL_V2_I]]
int32x2_t test_vrshl_s32(int32x2_t a, int32x2_t b) {
@@ -3450,7 +3450,7 @@ int32x2_t test_vrshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vrshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.srshl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.srshl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VRSHL_V2_I]]
int64x1_t test_vrshl_s64(int64x1_t a, int64x1_t b) {
@@ -3458,7 +3458,7 @@ int64x1_t test_vrshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vrshl_u8(
-// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.urshl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.urshl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VRSHL_V_I]]
uint8x8_t test_vrshl_u8(uint8x8_t a, int8x8_t b) {
return vrshl_u8(a, b);
@@ -3467,7 +3467,7 @@ uint8x8_t test_vrshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vrshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.urshl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.urshl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSHL_V2_I]]
uint16x4_t test_vrshl_u16(uint16x4_t a, int16x4_t b) {
@@ -3477,7 +3477,7 @@ uint16x4_t test_vrshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vrshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.urshl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.urshl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSHL_V2_I]]
uint32x2_t test_vrshl_u32(uint32x2_t a, int32x2_t b) {
@@ -3487,7 +3487,7 @@ uint32x2_t test_vrshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vrshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.urshl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.urshl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VRSHL_V2_I]]
uint64x1_t test_vrshl_u64(uint64x1_t a, int64x1_t b) {
@@ -3495,7 +3495,7 @@ uint64x1_t test_vrshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vrshlq_s8(
-// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.srshl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.srshl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VRSHLQ_V_I]]
int8x16_t test_vrshlq_s8(int8x16_t a, int8x16_t b) {
return vrshlq_s8(a, b);
@@ -3504,7 +3504,7 @@ int8x16_t test_vrshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vrshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.srshl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.srshl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRSHLQ_V2_I]]
int16x8_t test_vrshlq_s16(int16x8_t a, int16x8_t b) {
@@ -3514,7 +3514,7 @@ int16x8_t test_vrshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.srshl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.srshl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRSHLQ_V2_I]]
int32x4_t test_vrshlq_s32(int32x4_t a, int32x4_t b) {
@@ -3524,7 +3524,7 @@ int32x4_t test_vrshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vrshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.srshl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.srshl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VRSHLQ_V2_I]]
int64x2_t test_vrshlq_s64(int64x2_t a, int64x2_t b) {
@@ -3532,7 +3532,7 @@ int64x2_t test_vrshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vrshlq_u8(
-// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.urshl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.urshl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VRSHLQ_V_I]]
uint8x16_t test_vrshlq_u8(uint8x16_t a, int8x16_t b) {
return vrshlq_u8(a, b);
@@ -3541,7 +3541,7 @@ uint8x16_t test_vrshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vrshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.urshl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.urshl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRSHLQ_V2_I]]
uint16x8_t test_vrshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -3551,7 +3551,7 @@ uint16x8_t test_vrshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.urshl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.urshl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRSHLQ_V2_I]]
uint32x4_t test_vrshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -3561,7 +3561,7 @@ uint32x4_t test_vrshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vrshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.urshl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.urshl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VRSHLQ_V2_I]]
uint64x2_t test_vrshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -3569,7 +3569,7 @@ uint64x2_t test_vrshlq_u64(uint64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqrshl_s8(
-// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQRSHL_V_I]]
int8x8_t test_vqrshl_s8(int8x8_t a, int8x8_t b) {
return vqrshl_s8(a, b);
@@ -3578,7 +3578,7 @@ int8x8_t test_vqrshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqrshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRSHL_V2_I]]
int16x4_t test_vqrshl_s16(int16x4_t a, int16x4_t b) {
@@ -3588,7 +3588,7 @@ int16x4_t test_vqrshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqrshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrshl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrshl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRSHL_V2_I]]
int32x2_t test_vqrshl_s32(int32x2_t a, int32x2_t b) {
@@ -3598,7 +3598,7 @@ int32x2_t test_vqrshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqrshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqrshl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqrshl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQRSHL_V2_I]]
int64x1_t test_vqrshl_s64(int64x1_t a, int64x1_t b) {
@@ -3606,7 +3606,7 @@ int64x1_t test_vqrshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqrshl_u8(
-// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqrshl.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqrshl.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQRSHL_V_I]]
uint8x8_t test_vqrshl_u8(uint8x8_t a, int8x8_t b) {
return vqrshl_u8(a, b);
@@ -3615,7 +3615,7 @@ uint8x8_t test_vqrshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqrshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqrshl.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqrshl.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRSHL_V2_I]]
uint16x4_t test_vqrshl_u16(uint16x4_t a, int16x4_t b) {
@@ -3625,7 +3625,7 @@ uint16x4_t test_vqrshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqrshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqrshl.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqrshl.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRSHL_V2_I]]
uint32x2_t test_vqrshl_u32(uint32x2_t a, int32x2_t b) {
@@ -3635,7 +3635,7 @@ uint32x2_t test_vqrshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqrshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqrshl.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uqrshl.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQRSHL_V2_I]]
uint64x1_t test_vqrshl_u64(uint64x1_t a, int64x1_t b) {
@@ -3643,7 +3643,7 @@ uint64x1_t test_vqrshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqrshlq_s8(
-// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqrshl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqrshl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQRSHLQ_V_I]]
int8x16_t test_vqrshlq_s8(int8x16_t a, int8x16_t b) {
return vqrshlq_s8(a, b);
@@ -3652,7 +3652,7 @@ int8x16_t test_vqrshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqrshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrshl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrshl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRSHLQ_V2_I]]
int16x8_t test_vqrshlq_s16(int16x8_t a, int16x8_t b) {
@@ -3662,7 +3662,7 @@ int16x8_t test_vqrshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqrshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrshl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrshl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRSHLQ_V2_I]]
int32x4_t test_vqrshlq_s32(int32x4_t a, int32x4_t b) {
@@ -3672,7 +3672,7 @@ int32x4_t test_vqrshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqrshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqrshl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqrshl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQRSHLQ_V2_I]]
int64x2_t test_vqrshlq_s64(int64x2_t a, int64x2_t b) {
@@ -3680,7 +3680,7 @@ int64x2_t test_vqrshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqrshlq_u8(
-// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqrshl.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uqrshl.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQRSHLQ_V_I]]
uint8x16_t test_vqrshlq_u8(uint8x16_t a, int8x16_t b) {
return vqrshlq_u8(a, b);
@@ -3689,7 +3689,7 @@ uint8x16_t test_vqrshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqrshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqrshl.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uqrshl.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRSHLQ_V2_I]]
uint16x8_t test_vqrshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -3699,7 +3699,7 @@ uint16x8_t test_vqrshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqrshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqrshl.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uqrshl.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRSHLQ_V2_I]]
uint32x4_t test_vqrshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -3709,7 +3709,7 @@ uint32x4_t test_vqrshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqrshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqrshl.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uqrshl.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQRSHLQ_V2_I]]
uint64x2_t test_vqrshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -3739,7 +3739,7 @@ poly64x2_t test_vsliq_n_p64(poly64x2_t a, poly64x2_t b) {
}
// CHECK-LABEL: @test_vmax_s8(
-// CHECK: [[VMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.smax.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.smax.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMAX_I]]
int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) {
return vmax_s8(a, b);
@@ -3748,7 +3748,7 @@ int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vmax_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.smax.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.smax.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VMAX2_I]]
int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) {
return vmax_s16(a, b);
@@ -3757,14 +3757,14 @@ int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vmax_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.smax.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.smax.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VMAX2_I]]
int32x2_t test_vmax_s32(int32x2_t a, int32x2_t b) {
return vmax_s32(a, b);
}
// CHECK-LABEL: @test_vmax_u8(
-// CHECK: [[VMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.umax.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.umax.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMAX_I]]
uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) {
return vmax_u8(a, b);
@@ -3773,7 +3773,7 @@ uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vmax_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.umax.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.umax.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VMAX2_I]]
uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) {
return vmax_u16(a, b);
@@ -3782,7 +3782,7 @@ uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vmax_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.umax.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.umax.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VMAX2_I]]
uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) {
return vmax_u32(a, b);
@@ -3791,14 +3791,14 @@ uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vmax_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmax.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmax.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VMAX2_I]]
float32x2_t test_vmax_f32(float32x2_t a, float32x2_t b) {
return vmax_f32(a, b);
}
// CHECK-LABEL: @test_vmaxq_s8(
-// CHECK: [[VMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.smax.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.smax.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMAX_I]]
int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) {
return vmaxq_s8(a, b);
@@ -3807,7 +3807,7 @@ int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vmaxq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smax.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smax.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VMAX2_I]]
int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) {
return vmaxq_s16(a, b);
@@ -3816,14 +3816,14 @@ int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vmaxq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smax.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smax.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VMAX2_I]]
int32x4_t test_vmaxq_s32(int32x4_t a, int32x4_t b) {
return vmaxq_s32(a, b);
}
// CHECK-LABEL: @test_vmaxq_u8(
-// CHECK: [[VMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.umax.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.umax.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMAX_I]]
uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) {
return vmaxq_u8(a, b);
@@ -3832,7 +3832,7 @@ uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vmaxq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umax.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umax.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VMAX2_I]]
uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) {
return vmaxq_u16(a, b);
@@ -3841,7 +3841,7 @@ uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vmaxq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umax.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umax.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VMAX2_I]]
uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) {
return vmaxq_u32(a, b);
@@ -3850,7 +3850,7 @@ uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vmaxq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmax.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmax.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VMAX2_I]]
float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) {
return vmaxq_f32(a, b);
@@ -3859,14 +3859,14 @@ float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vmaxq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmax.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmax.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VMAX2_I]]
float64x2_t test_vmaxq_f64(float64x2_t a, float64x2_t b) {
return vmaxq_f64(a, b);
}
// CHECK-LABEL: @test_vmin_s8(
-// CHECK: [[VMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.smin.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.smin.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMIN_I]]
int8x8_t test_vmin_s8(int8x8_t a, int8x8_t b) {
return vmin_s8(a, b);
@@ -3875,7 +3875,7 @@ int8x8_t test_vmin_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vmin_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.smin.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.smin.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VMIN2_I]]
int16x4_t test_vmin_s16(int16x4_t a, int16x4_t b) {
return vmin_s16(a, b);
@@ -3884,14 +3884,14 @@ int16x4_t test_vmin_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vmin_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.smin.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.smin.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VMIN2_I]]
int32x2_t test_vmin_s32(int32x2_t a, int32x2_t b) {
return vmin_s32(a, b);
}
// CHECK-LABEL: @test_vmin_u8(
-// CHECK: [[VMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.umin.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.umin.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMIN_I]]
uint8x8_t test_vmin_u8(uint8x8_t a, uint8x8_t b) {
return vmin_u8(a, b);
@@ -3900,7 +3900,7 @@ uint8x8_t test_vmin_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vmin_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.umin.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.umin.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VMIN2_I]]
uint16x4_t test_vmin_u16(uint16x4_t a, uint16x4_t b) {
return vmin_u16(a, b);
@@ -3909,7 +3909,7 @@ uint16x4_t test_vmin_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vmin_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.umin.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.umin.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VMIN2_I]]
uint32x2_t test_vmin_u32(uint32x2_t a, uint32x2_t b) {
return vmin_u32(a, b);
@@ -3918,14 +3918,14 @@ uint32x2_t test_vmin_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vmin_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmin.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmin.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VMIN2_I]]
float32x2_t test_vmin_f32(float32x2_t a, float32x2_t b) {
return vmin_f32(a, b);
}
// CHECK-LABEL: @test_vminq_s8(
-// CHECK: [[VMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.smin.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.smin.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMIN_I]]
int8x16_t test_vminq_s8(int8x16_t a, int8x16_t b) {
return vminq_s8(a, b);
@@ -3934,7 +3934,7 @@ int8x16_t test_vminq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vminq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smin.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smin.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VMIN2_I]]
int16x8_t test_vminq_s16(int16x8_t a, int16x8_t b) {
return vminq_s16(a, b);
@@ -3943,14 +3943,14 @@ int16x8_t test_vminq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vminq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smin.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smin.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VMIN2_I]]
int32x4_t test_vminq_s32(int32x4_t a, int32x4_t b) {
return vminq_s32(a, b);
}
// CHECK-LABEL: @test_vminq_u8(
-// CHECK: [[VMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.umin.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.umin.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMIN_I]]
uint8x16_t test_vminq_u8(uint8x16_t a, uint8x16_t b) {
return vminq_u8(a, b);
@@ -3959,7 +3959,7 @@ uint8x16_t test_vminq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vminq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umin.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umin.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VMIN2_I]]
uint16x8_t test_vminq_u16(uint16x8_t a, uint16x8_t b) {
return vminq_u16(a, b);
@@ -3968,7 +3968,7 @@ uint16x8_t test_vminq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vminq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umin.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umin.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VMIN2_I]]
uint32x4_t test_vminq_u32(uint32x4_t a, uint32x4_t b) {
return vminq_u32(a, b);
@@ -3977,7 +3977,7 @@ uint32x4_t test_vminq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vminq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmin.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmin.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VMIN2_I]]
float32x4_t test_vminq_f32(float32x4_t a, float32x4_t b) {
return vminq_f32(a, b);
@@ -3986,7 +3986,7 @@ float32x4_t test_vminq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vminq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmin.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmin.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VMIN2_I]]
float64x2_t test_vminq_f64(float64x2_t a, float64x2_t b) {
return vminq_f64(a, b);
@@ -3995,7 +3995,7 @@ float64x2_t test_vminq_f64(float64x2_t a, float64x2_t b) {
// CHECK-LABEL: @test_vmaxnm_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VMAXNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmaxnm.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VMAXNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmaxnm.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VMAXNM2_I]]
float32x2_t test_vmaxnm_f32(float32x2_t a, float32x2_t b) {
return vmaxnm_f32(a, b);
@@ -4004,7 +4004,7 @@ float32x2_t test_vmaxnm_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vmaxnmq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VMAXNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmaxnm.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VMAXNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmaxnm.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VMAXNM2_I]]
float32x4_t test_vmaxnmq_f32(float32x4_t a, float32x4_t b) {
return vmaxnmq_f32(a, b);
@@ -4013,7 +4013,7 @@ float32x4_t test_vmaxnmq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vmaxnmq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VMAXNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmaxnm.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VMAXNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmaxnm.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VMAXNM2_I]]
float64x2_t test_vmaxnmq_f64(float64x2_t a, float64x2_t b) {
return vmaxnmq_f64(a, b);
@@ -4022,7 +4022,7 @@ float64x2_t test_vmaxnmq_f64(float64x2_t a, float64x2_t b) {
// CHECK-LABEL: @test_vminnm_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VMINNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fminnm.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VMINNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fminnm.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VMINNM2_I]]
float32x2_t test_vminnm_f32(float32x2_t a, float32x2_t b) {
return vminnm_f32(a, b);
@@ -4031,7 +4031,7 @@ float32x2_t test_vminnm_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vminnmq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VMINNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fminnm.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VMINNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fminnm.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VMINNM2_I]]
float32x4_t test_vminnmq_f32(float32x4_t a, float32x4_t b) {
return vminnmq_f32(a, b);
@@ -4040,14 +4040,14 @@ float32x4_t test_vminnmq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vminnmq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VMINNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fminnm.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VMINNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fminnm.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VMINNM2_I]]
float64x2_t test_vminnmq_f64(float64x2_t a, float64x2_t b) {
return vminnmq_f64(a, b);
}
// CHECK-LABEL: @test_vpmax_s8(
-// CHECK: [[VPMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.smaxp.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.smaxp.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMAX_I]]
int8x8_t test_vpmax_s8(int8x8_t a, int8x8_t b) {
return vpmax_s8(a, b);
@@ -4056,7 +4056,7 @@ int8x8_t test_vpmax_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpmax_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.smaxp.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.smaxp.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VPMAX2_I]]
int16x4_t test_vpmax_s16(int16x4_t a, int16x4_t b) {
return vpmax_s16(a, b);
@@ -4065,14 +4065,14 @@ int16x4_t test_vpmax_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpmax_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.smaxp.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.smaxp.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VPMAX2_I]]
int32x2_t test_vpmax_s32(int32x2_t a, int32x2_t b) {
return vpmax_s32(a, b);
}
// CHECK-LABEL: @test_vpmax_u8(
-// CHECK: [[VPMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.umaxp.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.umaxp.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMAX_I]]
uint8x8_t test_vpmax_u8(uint8x8_t a, uint8x8_t b) {
return vpmax_u8(a, b);
@@ -4081,7 +4081,7 @@ uint8x8_t test_vpmax_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpmax_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.umaxp.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.umaxp.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VPMAX2_I]]
uint16x4_t test_vpmax_u16(uint16x4_t a, uint16x4_t b) {
return vpmax_u16(a, b);
@@ -4090,7 +4090,7 @@ uint16x4_t test_vpmax_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpmax_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.umaxp.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.umaxp.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VPMAX2_I]]
uint32x2_t test_vpmax_u32(uint32x2_t a, uint32x2_t b) {
return vpmax_u32(a, b);
@@ -4099,14 +4099,14 @@ uint32x2_t test_vpmax_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpmax_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmaxp.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmaxp.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VPMAX2_I]]
float32x2_t test_vpmax_f32(float32x2_t a, float32x2_t b) {
return vpmax_f32(a, b);
}
// CHECK-LABEL: @test_vpmaxq_s8(
-// CHECK: [[VPMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.smaxp.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VPMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.smaxp.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VPMAX_I]]
int8x16_t test_vpmaxq_s8(int8x16_t a, int8x16_t b) {
return vpmaxq_s8(a, b);
@@ -4115,7 +4115,7 @@ int8x16_t test_vpmaxq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vpmaxq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smaxp.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smaxp.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VPMAX2_I]]
int16x8_t test_vpmaxq_s16(int16x8_t a, int16x8_t b) {
return vpmaxq_s16(a, b);
@@ -4124,14 +4124,14 @@ int16x8_t test_vpmaxq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vpmaxq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smaxp.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smaxp.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VPMAX2_I]]
int32x4_t test_vpmaxq_s32(int32x4_t a, int32x4_t b) {
return vpmaxq_s32(a, b);
}
// CHECK-LABEL: @test_vpmaxq_u8(
-// CHECK: [[VPMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.umaxp.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VPMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.umaxp.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VPMAX_I]]
uint8x16_t test_vpmaxq_u8(uint8x16_t a, uint8x16_t b) {
return vpmaxq_u8(a, b);
@@ -4140,7 +4140,7 @@ uint8x16_t test_vpmaxq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vpmaxq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umaxp.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umaxp.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VPMAX2_I]]
uint16x8_t test_vpmaxq_u16(uint16x8_t a, uint16x8_t b) {
return vpmaxq_u16(a, b);
@@ -4149,7 +4149,7 @@ uint16x8_t test_vpmaxq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vpmaxq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umaxp.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umaxp.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VPMAX2_I]]
uint32x4_t test_vpmaxq_u32(uint32x4_t a, uint32x4_t b) {
return vpmaxq_u32(a, b);
@@ -4158,7 +4158,7 @@ uint32x4_t test_vpmaxq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vpmaxq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmaxp.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmaxp.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VPMAX2_I]]
float32x4_t test_vpmaxq_f32(float32x4_t a, float32x4_t b) {
return vpmaxq_f32(a, b);
@@ -4167,14 +4167,14 @@ float32x4_t test_vpmaxq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vpmaxq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VPMAX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmaxp.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VPMAX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmaxp.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VPMAX2_I]]
float64x2_t test_vpmaxq_f64(float64x2_t a, float64x2_t b) {
return vpmaxq_f64(a, b);
}
// CHECK-LABEL: @test_vpmin_s8(
-// CHECK: [[VPMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sminp.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sminp.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMIN_I]]
int8x8_t test_vpmin_s8(int8x8_t a, int8x8_t b) {
return vpmin_s8(a, b);
@@ -4183,7 +4183,7 @@ int8x8_t test_vpmin_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpmin_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sminp.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sminp.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VPMIN2_I]]
int16x4_t test_vpmin_s16(int16x4_t a, int16x4_t b) {
return vpmin_s16(a, b);
@@ -4192,14 +4192,14 @@ int16x4_t test_vpmin_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpmin_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sminp.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sminp.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VPMIN2_I]]
int32x2_t test_vpmin_s32(int32x2_t a, int32x2_t b) {
return vpmin_s32(a, b);
}
// CHECK-LABEL: @test_vpmin_u8(
-// CHECK: [[VPMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uminp.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMIN_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uminp.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMIN_I]]
uint8x8_t test_vpmin_u8(uint8x8_t a, uint8x8_t b) {
return vpmin_u8(a, b);
@@ -4208,7 +4208,7 @@ uint8x8_t test_vpmin_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpmin_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uminp.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uminp.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VPMIN2_I]]
uint16x4_t test_vpmin_u16(uint16x4_t a, uint16x4_t b) {
return vpmin_u16(a, b);
@@ -4217,7 +4217,7 @@ uint16x4_t test_vpmin_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpmin_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uminp.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uminp.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VPMIN2_I]]
uint32x2_t test_vpmin_u32(uint32x2_t a, uint32x2_t b) {
return vpmin_u32(a, b);
@@ -4226,14 +4226,14 @@ uint32x2_t test_vpmin_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpmin_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fminp.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fminp.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VPMIN2_I]]
float32x2_t test_vpmin_f32(float32x2_t a, float32x2_t b) {
return vpmin_f32(a, b);
}
// CHECK-LABEL: @test_vpminq_s8(
-// CHECK: [[VPMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sminp.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VPMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sminp.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VPMIN_I]]
int8x16_t test_vpminq_s8(int8x16_t a, int8x16_t b) {
return vpminq_s8(a, b);
@@ -4242,7 +4242,7 @@ int8x16_t test_vpminq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vpminq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sminp.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sminp.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VPMIN2_I]]
int16x8_t test_vpminq_s16(int16x8_t a, int16x8_t b) {
return vpminq_s16(a, b);
@@ -4251,14 +4251,14 @@ int16x8_t test_vpminq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vpminq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sminp.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sminp.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VPMIN2_I]]
int32x4_t test_vpminq_s32(int32x4_t a, int32x4_t b) {
return vpminq_s32(a, b);
}
// CHECK-LABEL: @test_vpminq_u8(
-// CHECK: [[VPMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uminp.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VPMIN_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.uminp.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VPMIN_I]]
uint8x16_t test_vpminq_u8(uint8x16_t a, uint8x16_t b) {
return vpminq_u8(a, b);
@@ -4267,7 +4267,7 @@ uint8x16_t test_vpminq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vpminq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uminp.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uminp.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VPMIN2_I]]
uint16x8_t test_vpminq_u16(uint16x8_t a, uint16x8_t b) {
return vpminq_u16(a, b);
@@ -4276,7 +4276,7 @@ uint16x8_t test_vpminq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vpminq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uminp.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uminp.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VPMIN2_I]]
uint32x4_t test_vpminq_u32(uint32x4_t a, uint32x4_t b) {
return vpminq_u32(a, b);
@@ -4285,7 +4285,7 @@ uint32x4_t test_vpminq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vpminq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fminp.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fminp.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VPMIN2_I]]
float32x4_t test_vpminq_f32(float32x4_t a, float32x4_t b) {
return vpminq_f32(a, b);
@@ -4294,7 +4294,7 @@ float32x4_t test_vpminq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vpminq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VPMIN2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fminp.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VPMIN2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fminp.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VPMIN2_I]]
float64x2_t test_vpminq_f64(float64x2_t a, float64x2_t b) {
return vpminq_f64(a, b);
@@ -4303,7 +4303,7 @@ float64x2_t test_vpminq_f64(float64x2_t a, float64x2_t b) {
// CHECK-LABEL: @test_vpmaxnm_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPMAXNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmaxnmp.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPMAXNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmaxnmp.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VPMAXNM2_I]]
float32x2_t test_vpmaxnm_f32(float32x2_t a, float32x2_t b) {
return vpmaxnm_f32(a, b);
@@ -4312,7 +4312,7 @@ float32x2_t test_vpmaxnm_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vpmaxnmq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VPMAXNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmaxnmp.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VPMAXNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmaxnmp.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VPMAXNM2_I]]
float32x4_t test_vpmaxnmq_f32(float32x4_t a, float32x4_t b) {
return vpmaxnmq_f32(a, b);
@@ -4321,7 +4321,7 @@ float32x4_t test_vpmaxnmq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vpmaxnmq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VPMAXNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmaxnmp.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VPMAXNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmaxnmp.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VPMAXNM2_I]]
float64x2_t test_vpmaxnmq_f64(float64x2_t a, float64x2_t b) {
return vpmaxnmq_f64(a, b);
@@ -4330,7 +4330,7 @@ float64x2_t test_vpmaxnmq_f64(float64x2_t a, float64x2_t b) {
// CHECK-LABEL: @test_vpminnm_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPMINNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fminnmp.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPMINNM2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fminnmp.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VPMINNM2_I]]
float32x2_t test_vpminnm_f32(float32x2_t a, float32x2_t b) {
return vpminnm_f32(a, b);
@@ -4339,7 +4339,7 @@ float32x2_t test_vpminnm_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vpminnmq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VPMINNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fminnmp.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VPMINNM2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fminnmp.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VPMINNM2_I]]
float32x4_t test_vpminnmq_f32(float32x4_t a, float32x4_t b) {
return vpminnmq_f32(a, b);
@@ -4348,14 +4348,14 @@ float32x4_t test_vpminnmq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vpminnmq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VPMINNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fminnmp.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VPMINNM2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fminnmp.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VPMINNM2_I]]
float64x2_t test_vpminnmq_f64(float64x2_t a, float64x2_t b) {
return vpminnmq_f64(a, b);
}
// CHECK-LABEL: @test_vpadd_s8(
-// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.addp.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.addp.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPADD_V_I]]
int8x8_t test_vpadd_s8(int8x8_t a, int8x8_t b) {
return vpadd_s8(a, b);
@@ -4364,7 +4364,7 @@ int8x8_t test_vpadd_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.addp.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.addp.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <4 x i16> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPADD_V2_I]]
int16x4_t test_vpadd_s16(int16x4_t a, int16x4_t b) {
@@ -4374,7 +4374,7 @@ int16x4_t test_vpadd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.addp.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.addp.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <2 x i32> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPADD_V2_I]]
int32x2_t test_vpadd_s32(int32x2_t a, int32x2_t b) {
@@ -4382,7 +4382,7 @@ int32x2_t test_vpadd_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vpadd_u8(
-// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.addp.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.addp.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPADD_V_I]]
uint8x8_t test_vpadd_u8(uint8x8_t a, uint8x8_t b) {
return vpadd_u8(a, b);
@@ -4391,7 +4391,7 @@ uint8x8_t test_vpadd_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.addp.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.addp.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <4 x i16> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPADD_V2_I]]
uint16x4_t test_vpadd_u16(uint16x4_t a, uint16x4_t b) {
@@ -4401,7 +4401,7 @@ uint16x4_t test_vpadd_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.addp.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.addp.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <2 x i32> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPADD_V2_I]]
uint32x2_t test_vpadd_u32(uint32x2_t a, uint32x2_t b) {
@@ -4411,7 +4411,7 @@ uint32x2_t test_vpadd_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpadd_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.addp.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.addp.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <2 x float> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VPADD_V2_I]]
float32x2_t test_vpadd_f32(float32x2_t a, float32x2_t b) {
@@ -4419,7 +4419,7 @@ float32x2_t test_vpadd_f32(float32x2_t a, float32x2_t b) {
}
// CHECK-LABEL: @test_vpaddq_s8(
-// CHECK: [[VPADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.addp.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VPADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.addp.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VPADDQ_V_I]]
int8x16_t test_vpaddq_s8(int8x16_t a, int8x16_t b) {
return vpaddq_s8(a, b);
@@ -4428,7 +4428,7 @@ int8x16_t test_vpaddq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vpaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.addp.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.addp.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VPADDQ_V2_I]]
int16x8_t test_vpaddq_s16(int16x8_t a, int16x8_t b) {
@@ -4438,7 +4438,7 @@ int16x8_t test_vpaddq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vpaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.addp.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.addp.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VPADDQ_V2_I]]
int32x4_t test_vpaddq_s32(int32x4_t a, int32x4_t b) {
@@ -4446,7 +4446,7 @@ int32x4_t test_vpaddq_s32(int32x4_t a, int32x4_t b) {
}
// CHECK-LABEL: @test_vpaddq_u8(
-// CHECK: [[VPADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.addp.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VPADDQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.addp.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VPADDQ_V_I]]
uint8x16_t test_vpaddq_u8(uint8x16_t a, uint8x16_t b) {
return vpaddq_u8(a, b);
@@ -4455,7 +4455,7 @@ uint8x16_t test_vpaddq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vpaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.addp.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.addp.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VPADDQ_V2_I]]
uint16x8_t test_vpaddq_u16(uint16x8_t a, uint16x8_t b) {
@@ -4465,7 +4465,7 @@ uint16x8_t test_vpaddq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vpaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.addp.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.addp.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VPADDQ_V2_I]]
uint32x4_t test_vpaddq_u32(uint32x4_t a, uint32x4_t b) {
@@ -4475,7 +4475,7 @@ uint32x4_t test_vpaddq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vpaddq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.addp.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.addp.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <4 x float> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VPADDQ_V2_I]]
float32x4_t test_vpaddq_f32(float32x4_t a, float32x4_t b) {
@@ -4485,7 +4485,7 @@ float32x4_t test_vpaddq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vpaddq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.addp.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.addp.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <2 x double> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x double> [[VPADDQ_V2_I]]
float64x2_t test_vpaddq_f64(float64x2_t a, float64x2_t b) {
@@ -4495,7 +4495,7 @@ float64x2_t test_vpaddq_f64(float64x2_t a, float64x2_t b) {
// CHECK-LABEL: @test_vqdmulh_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V2_I]]
int16x4_t test_vqdmulh_s16(int16x4_t a, int16x4_t b) {
@@ -4505,7 +4505,7 @@ int16x4_t test_vqdmulh_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqdmulh_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqdmulh.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V2_I]]
int32x2_t test_vqdmulh_s32(int32x2_t a, int32x2_t b) {
@@ -4515,7 +4515,7 @@ int32x2_t test_vqdmulh_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqdmulhq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqdmulh.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V2_I]]
int16x8_t test_vqdmulhq_s16(int16x8_t a, int16x8_t b) {
@@ -4525,7 +4525,7 @@ int16x8_t test_vqdmulhq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqdmulhq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmulh.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V2_I]]
int32x4_t test_vqdmulhq_s32(int32x4_t a, int32x4_t b) {
@@ -4535,7 +4535,7 @@ int32x4_t test_vqdmulhq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqrdmulh_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V2_I]]
int16x4_t test_vqrdmulh_s16(int16x4_t a, int16x4_t b) {
@@ -4545,7 +4545,7 @@ int16x4_t test_vqrdmulh_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqrdmulh_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqrdmulh.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V2_I]]
int32x2_t test_vqrdmulh_s32(int32x2_t a, int32x2_t b) {
@@ -4555,7 +4555,7 @@ int32x2_t test_vqrdmulh_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqrdmulhq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqrdmulh.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V2_I]]
int16x8_t test_vqrdmulhq_s16(int16x8_t a, int16x8_t b) {
@@ -4565,7 +4565,7 @@ int16x8_t test_vqrdmulhq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqrdmulhq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqrdmulh.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V2_I]]
int32x4_t test_vqrdmulhq_s32(int32x4_t a, int32x4_t b) {
@@ -4575,7 +4575,7 @@ int32x4_t test_vqrdmulhq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vmulx_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VMULX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmulx.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x float> [[VMULX2_I]]
float32x2_t test_vmulx_f32(float32x2_t a, float32x2_t b) {
return vmulx_f32(a, b);
@@ -4584,7 +4584,7 @@ float32x2_t test_vmulx_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vmulxq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VMULX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmulx.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x float> [[VMULX2_I]]
float32x4_t test_vmulxq_f32(float32x4_t a, float32x4_t b) {
return vmulxq_f32(a, b);
@@ -4593,7 +4593,7 @@ float32x4_t test_vmulxq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vmulxq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> %b) #4
+// CHECK: [[VMULX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmulx.v2f64(<2 x double> %a, <2 x double> %b)
// CHECK: ret <2 x double> [[VMULX2_I]]
float64x2_t test_vmulxq_f64(float64x2_t a, float64x2_t b) {
return vmulxq_f64(a, b);
@@ -7203,7 +7203,7 @@ uint32x4_t test_vaddhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vraddhn_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRADDHN_V2_I]]
int8x8_t test_vraddhn_s16(int16x8_t a, int16x8_t b) {
return vraddhn_s16(a, b);
@@ -7212,7 +7212,7 @@ int8x8_t test_vraddhn_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vraddhn_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <4 x i16> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRADDHN_V2_I]]
int16x4_t test_vraddhn_s32(int32x4_t a, int32x4_t b) {
@@ -7222,7 +7222,7 @@ int16x4_t test_vraddhn_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vraddhn_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <2 x i32> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRADDHN_V2_I]]
int32x2_t test_vraddhn_s64(int64x2_t a, int64x2_t b) {
@@ -7232,7 +7232,7 @@ int32x2_t test_vraddhn_s64(int64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vraddhn_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRADDHN_V2_I]]
uint8x8_t test_vraddhn_u16(uint16x8_t a, uint16x8_t b) {
return vraddhn_u16(a, b);
@@ -7241,7 +7241,7 @@ uint8x8_t test_vraddhn_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vraddhn_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <4 x i16> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRADDHN_V2_I]]
uint16x4_t test_vraddhn_u32(uint32x4_t a, uint32x4_t b) {
@@ -7251,7 +7251,7 @@ uint16x4_t test_vraddhn_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vraddhn_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <2 x i32> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRADDHN_V2_I]]
uint32x2_t test_vraddhn_u64(uint64x2_t a, uint64x2_t b) {
@@ -7261,7 +7261,7 @@ uint32x2_t test_vraddhn_u64(uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vraddhn_high_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> %r, <8 x i8> [[VRADDHN_V2_I_I]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: ret <16 x i8> [[SHUFFLE_I_I]]
int8x16_t test_vraddhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
@@ -7271,7 +7271,7 @@ int8x16_t test_vraddhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vraddhn_high_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRADDHN_V3_I_I:%.*]] = bitcast <4 x i16> [[VRADDHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> %r, <4 x i16> [[VRADDHN_V2_I_I]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
// CHECK: ret <8 x i16> [[SHUFFLE_I_I]]
@@ -7282,7 +7282,7 @@ int16x8_t test_vraddhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vraddhn_high_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRADDHN_V3_I_I:%.*]] = bitcast <2 x i32> [[VRADDHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> %r, <2 x i32> [[VRADDHN_V2_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x i32> [[SHUFFLE_I_I]]
@@ -7293,7 +7293,7 @@ int32x4_t test_vraddhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vraddhn_high_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.raddhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> %r, <8 x i8> [[VRADDHN_V2_I_I]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: ret <16 x i8> [[SHUFFLE_I_I]]
uint8x16_t test_vraddhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
@@ -7303,7 +7303,7 @@ uint8x16_t test_vraddhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vraddhn_high_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.raddhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRADDHN_V3_I_I:%.*]] = bitcast <4 x i16> [[VRADDHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> %r, <4 x i16> [[VRADDHN_V2_I_I]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
// CHECK: ret <8 x i16> [[SHUFFLE_I_I]]
@@ -7314,7 +7314,7 @@ uint16x8_t test_vraddhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vraddhn_high_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRADDHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.raddhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRADDHN_V3_I_I:%.*]] = bitcast <2 x i32> [[VRADDHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> %r, <2 x i32> [[VRADDHN_V2_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x i32> [[SHUFFLE_I_I]]
@@ -7463,7 +7463,7 @@ uint32x4_t test_vsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vrsubhn_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRSUBHN_V2_I]]
int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
return vrsubhn_s16(a, b);
@@ -7472,7 +7472,7 @@ int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrsubhn_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSUBHN_V2_I]]
int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
@@ -7482,7 +7482,7 @@ int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vrsubhn_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSUBHN_V2_I]]
int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
@@ -7492,7 +7492,7 @@ int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vrsubhn_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRSUBHN_V2_I]]
uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
return vrsubhn_u16(a, b);
@@ -7501,7 +7501,7 @@ uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vrsubhn_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSUBHN_V2_I]]
uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
@@ -7511,7 +7511,7 @@ uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vrsubhn_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSUBHN_V2_I]]
uint32x2_t test_vrsubhn_u64(uint64x2_t a, uint64x2_t b) {
@@ -7521,7 +7521,7 @@ uint32x2_t test_vrsubhn_u64(uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vrsubhn_high_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> %r, <8 x i8> [[VRSUBHN_V2_I_I]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: ret <16 x i8> [[SHUFFLE_I_I]]
int8x16_t test_vrsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
@@ -7531,7 +7531,7 @@ int8x16_t test_vrsubhn_high_s16(int8x8_t r, int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrsubhn_high_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSUBHN_V3_I_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> %r, <4 x i16> [[VRSUBHN_V2_I_I]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
// CHECK: ret <8 x i16> [[SHUFFLE_I_I]]
@@ -7542,7 +7542,7 @@ int16x8_t test_vrsubhn_high_s32(int16x4_t r, int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vrsubhn_high_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSUBHN_V3_I_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> %r, <2 x i32> [[VRSUBHN_V2_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x i32> [[SHUFFLE_I_I]]
@@ -7553,7 +7553,7 @@ int32x4_t test_vrsubhn_high_s64(int32x2_t r, int64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vrsubhn_high_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rsubhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> %r, <8 x i8> [[VRSUBHN_V2_I_I]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: ret <16 x i8> [[SHUFFLE_I_I]]
uint8x16_t test_vrsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
@@ -7563,7 +7563,7 @@ uint8x16_t test_vrsubhn_high_u16(uint8x8_t r, uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vrsubhn_high_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.rsubhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSUBHN_V3_I_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> %r, <4 x i16> [[VRSUBHN_V2_I_I]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
// CHECK: ret <8 x i16> [[SHUFFLE_I_I]]
@@ -7574,7 +7574,7 @@ uint16x8_t test_vrsubhn_high_u32(uint16x4_t r, uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vrsubhn_high_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSUBHN_V2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.rsubhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSUBHN_V3_I_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> %r, <2 x i32> [[VRSUBHN_V2_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x i32> [[SHUFFLE_I_I]]
@@ -7583,7 +7583,7 @@ uint32x4_t test_vrsubhn_high_u64(uint32x2_t r, uint64x2_t a, uint64x2_t b) {
}
// CHECK-LABEL: @test_vabdl_s8(
-// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: [[VMOVL_I_I:%.*]] = zext <8 x i8> [[VABD_I_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[VMOVL_I_I]]
int16x8_t test_vabdl_s8(int8x8_t a, int8x8_t b) {
@@ -7593,7 +7593,7 @@ int16x8_t test_vabdl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vabdl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I]] to <4 x i32>
// CHECK: ret <4 x i32> [[VMOVL_I_I]]
@@ -7604,7 +7604,7 @@ int32x4_t test_vabdl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vabdl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I]] to <2 x i64>
// CHECK: ret <2 x i64> [[VMOVL_I_I]]
@@ -7613,7 +7613,7 @@ int64x2_t test_vabdl_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vabdl_u8(
-// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VABD_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: [[VMOVL_I_I:%.*]] = zext <8 x i8> [[VABD_I_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[VMOVL_I_I]]
uint16x8_t test_vabdl_u8(uint8x8_t a, uint8x8_t b) {
@@ -7623,7 +7623,7 @@ uint16x8_t test_vabdl_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vabdl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I]] to <4 x i32>
// CHECK: ret <4 x i32> [[VMOVL_I_I]]
@@ -7634,7 +7634,7 @@ uint32x4_t test_vabdl_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vabdl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VABD2_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I]] to <2 x i64>
// CHECK: ret <2 x i64> [[VMOVL_I_I]]
@@ -7643,7 +7643,7 @@ uint64x2_t test_vabdl_u32(uint32x2_t a, uint32x2_t b) {
}
// CHECK-LABEL: @test_vabal_s8(
-// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <8 x i8> [[VABD_I_I_I]] to <8 x i16>
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMOVL_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
@@ -7654,7 +7654,7 @@ int16x8_t test_vabal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
// CHECK-LABEL: @test_vabal_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I_I]] to <4 x i32>
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMOVL_I_I_I]]
@@ -7666,7 +7666,7 @@ int32x4_t test_vabal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK-LABEL: @test_vabal_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I_I]] to <2 x i64>
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMOVL_I_I_I]]
@@ -7676,7 +7676,7 @@ int64x2_t test_vabal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
}
// CHECK-LABEL: @test_vabal_u8(
-// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <8 x i8> [[VABD_I_I_I]] to <8 x i16>
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMOVL_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
@@ -7687,7 +7687,7 @@ uint16x8_t test_vabal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK-LABEL: @test_vabal_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I_I]] to <4 x i32>
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMOVL_I_I_I]]
@@ -7699,7 +7699,7 @@ uint32x4_t test_vabal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK-LABEL: @test_vabal_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I_I]] to <2 x i64>
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMOVL_I_I_I]]
@@ -7711,7 +7711,7 @@ uint64x2_t test_vabal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK-LABEL: @test_vabdl_high_s8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %a, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <8 x i8> [[VABD_I_I_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[VMOVL_I_I_I]]
int16x8_t test_vabdl_high_s8(int8x16_t a, int8x16_t b) {
@@ -7723,7 +7723,7 @@ int16x8_t test_vabdl_high_s8(int8x16_t a, int8x16_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %b, <8 x i16> %b, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I_I]] to <4 x i32>
// CHECK: ret <4 x i32> [[VMOVL_I_I_I]]
@@ -7736,7 +7736,7 @@ int32x4_t test_vabdl_high_s16(int16x8_t a, int16x8_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %b, <4 x i32> %b, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I_I]] to <2 x i64>
// CHECK: ret <2 x i64> [[VMOVL_I_I_I]]
@@ -7747,7 +7747,7 @@ int64x2_t test_vabdl_high_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vabdl_high_u8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %a, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <8 x i8> [[VABD_I_I_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[VMOVL_I_I_I]]
uint16x8_t test_vabdl_high_u8(uint8x16_t a, uint8x16_t b) {
@@ -7759,7 +7759,7 @@ uint16x8_t test_vabdl_high_u8(uint8x16_t a, uint8x16_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %b, <8 x i16> %b, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I_I]] to <4 x i32>
// CHECK: ret <4 x i32> [[VMOVL_I_I_I]]
@@ -7772,7 +7772,7 @@ uint32x4_t test_vabdl_high_u16(uint16x8_t a, uint16x8_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %b, <4 x i32> %b, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I_I]] to <2 x i64>
// CHECK: ret <2 x i64> [[VMOVL_I_I_I]]
@@ -7783,7 +7783,7 @@ uint64x2_t test_vabdl_high_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vabal_high_s8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %c, <16 x i8> %c, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VABD_I_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD_I_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[VMOVL_I_I_I_I:%.*]] = zext <8 x i8> [[VABD_I_I_I_I]] to <8 x i16>
// CHECK: [[ADD_I_I:%.*]] = add <8 x i16> %a, [[VMOVL_I_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I_I]]
@@ -7796,7 +7796,7 @@ int16x8_t test_vabal_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %c, <8 x i16> %c, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I_I_I]] to <4 x i32>
// CHECK: [[ADD_I_I:%.*]] = add <4 x i32> %a, [[VMOVL_I_I_I_I]]
@@ -7810,7 +7810,7 @@ int32x4_t test_vabal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %c, <4 x i32> %c, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I_I_I]] to <2 x i64>
// CHECK: [[ADD_I_I:%.*]] = add <2 x i64> %a, [[VMOVL_I_I_I_I]]
@@ -7822,7 +7822,7 @@ int64x2_t test_vabal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
// CHECK-LABEL: @test_vabal_high_u8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %c, <16 x i8> %c, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VABD_I_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD_I_I_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[VMOVL_I_I_I_I:%.*]] = zext <8 x i8> [[VABD_I_I_I_I]] to <8 x i16>
// CHECK: [[ADD_I_I:%.*]] = add <8 x i16> %a, [[VMOVL_I_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I_I]]
@@ -7835,7 +7835,7 @@ uint16x8_t test_vabal_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %c, <8 x i16> %c, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uabd.v4i16(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD2_I_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I_I:%.*]] = zext <4 x i16> [[VABD2_I_I_I_I]] to <4 x i32>
// CHECK: [[ADD_I_I:%.*]] = add <4 x i32> %a, [[VMOVL_I_I_I_I]]
@@ -7849,7 +7849,7 @@ uint32x4_t test_vabal_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %c, <4 x i32> %c, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VABD2_I_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VABD2_I_I_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uabd.v2i32(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD2_I_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I_I:%.*]] = zext <2 x i32> [[VABD2_I_I_I_I]] to <2 x i64>
// CHECK: [[ADD_I_I:%.*]] = add <2 x i64> %a, [[VMOVL_I_I_I_I]]
@@ -7859,7 +7859,7 @@ uint64x2_t test_vabal_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
}
// CHECK-LABEL: @test_vmull_s8(
-// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i16> [[VMULL_I]]
int16x8_t test_vmull_s8(int8x8_t a, int8x8_t b) {
return vmull_s8(a, b);
@@ -7868,7 +7868,7 @@ int16x8_t test_vmull_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vmull_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_s16(int16x4_t a, int16x4_t b) {
return vmull_s16(a, b);
@@ -7877,14 +7877,14 @@ int32x4_t test_vmull_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vmull_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_s32(int32x2_t a, int32x2_t b) {
return vmull_s32(a, b);
}
// CHECK-LABEL: @test_vmull_u8(
-// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i16> [[VMULL_I]]
uint16x8_t test_vmull_u8(uint8x8_t a, uint8x8_t b) {
return vmull_u8(a, b);
@@ -7893,7 +7893,7 @@ uint16x8_t test_vmull_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vmull_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_u16(uint16x4_t a, uint16x4_t b) {
return vmull_u16(a, b);
@@ -7902,7 +7902,7 @@ uint32x4_t test_vmull_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vmull_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_u32(uint32x2_t a, uint32x2_t b) {
return vmull_u32(a, b);
@@ -7911,7 +7911,7 @@ uint64x2_t test_vmull_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vmull_high_s8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %a, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: ret <8 x i16> [[VMULL_I_I]]
int16x8_t test_vmull_high_s8(int8x16_t a, int8x16_t b) {
return vmull_high_s8(a, b);
@@ -7922,7 +7922,7 @@ int16x8_t test_vmull_high_s8(int8x16_t a, int8x16_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %b, <8 x i16> %b, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: ret <4 x i32> [[VMULL2_I_I]]
int32x4_t test_vmull_high_s16(int16x8_t a, int16x8_t b) {
return vmull_high_s16(a, b);
@@ -7933,7 +7933,7 @@ int32x4_t test_vmull_high_s16(int16x8_t a, int16x8_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %b, <4 x i32> %b, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: ret <2 x i64> [[VMULL2_I_I]]
int64x2_t test_vmull_high_s32(int32x4_t a, int32x4_t b) {
return vmull_high_s32(a, b);
@@ -7942,7 +7942,7 @@ int64x2_t test_vmull_high_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vmull_high_u8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %a, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: ret <8 x i16> [[VMULL_I_I]]
uint16x8_t test_vmull_high_u8(uint8x16_t a, uint8x16_t b) {
return vmull_high_u8(a, b);
@@ -7953,7 +7953,7 @@ uint16x8_t test_vmull_high_u8(uint8x16_t a, uint8x16_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %b, <8 x i16> %b, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: ret <4 x i32> [[VMULL2_I_I]]
uint32x4_t test_vmull_high_u16(uint16x8_t a, uint16x8_t b) {
return vmull_high_u16(a, b);
@@ -7964,14 +7964,14 @@ uint32x4_t test_vmull_high_u16(uint16x8_t a, uint16x8_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %b, <4 x i32> %b, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: ret <2 x i64> [[VMULL2_I_I]]
uint64x2_t test_vmull_high_u32(uint32x4_t a, uint32x4_t b) {
return vmull_high_u32(a, b);
}
// CHECK-LABEL: @test_vmlal_s8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
int16x8_t test_vmlal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
@@ -7981,7 +7981,7 @@ int16x8_t test_vmlal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
// CHECK-LABEL: @test_vmlal_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
int32x4_t test_vmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
@@ -7991,7 +7991,7 @@ int32x4_t test_vmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK-LABEL: @test_vmlal_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
int64x2_t test_vmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
@@ -7999,7 +7999,7 @@ int64x2_t test_vmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
}
// CHECK-LABEL: @test_vmlal_u8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
uint16x8_t test_vmlal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
@@ -8009,7 +8009,7 @@ uint16x8_t test_vmlal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK-LABEL: @test_vmlal_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
uint32x4_t test_vmlal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
@@ -8019,7 +8019,7 @@ uint32x4_t test_vmlal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK-LABEL: @test_vmlal_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
uint64x2_t test_vmlal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
@@ -8029,7 +8029,7 @@ uint64x2_t test_vmlal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK-LABEL: @test_vmlal_high_s8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %c, <16 x i8> %c, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[ADD_I_I:%.*]] = add <8 x i16> %a, [[VMULL_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I_I]]
int16x8_t test_vmlal_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
@@ -8041,7 +8041,7 @@ int16x8_t test_vmlal_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %c, <8 x i16> %c, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[ADD_I_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[ADD_I_I]]
int32x4_t test_vmlal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
@@ -8053,7 +8053,7 @@ int32x4_t test_vmlal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %c, <4 x i32> %c, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[ADD_I_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[ADD_I_I]]
int64x2_t test_vmlal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
@@ -8063,7 +8063,7 @@ int64x2_t test_vmlal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
// CHECK-LABEL: @test_vmlal_high_u8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %c, <16 x i8> %c, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[ADD_I_I:%.*]] = add <8 x i16> %a, [[VMULL_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I_I]]
uint16x8_t test_vmlal_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
@@ -8075,7 +8075,7 @@ uint16x8_t test_vmlal_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %c, <8 x i16> %c, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[ADD_I_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[ADD_I_I]]
uint32x4_t test_vmlal_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
@@ -8087,7 +8087,7 @@ uint32x4_t test_vmlal_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %c, <4 x i32> %c, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[ADD_I_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[ADD_I_I]]
uint64x2_t test_vmlal_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
@@ -8095,7 +8095,7 @@ uint64x2_t test_vmlal_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
}
// CHECK-LABEL: @test_vmlsl_s8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[SUB_I:%.*]] = sub <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[SUB_I]]
int16x8_t test_vmlsl_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
@@ -8105,7 +8105,7 @@ int16x8_t test_vmlsl_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
// CHECK-LABEL: @test_vmlsl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
int32x4_t test_vmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
@@ -8115,7 +8115,7 @@ int32x4_t test_vmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK-LABEL: @test_vmlsl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
int64x2_t test_vmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
@@ -8123,7 +8123,7 @@ int64x2_t test_vmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
}
// CHECK-LABEL: @test_vmlsl_u8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[SUB_I:%.*]] = sub <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[SUB_I]]
uint16x8_t test_vmlsl_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
@@ -8133,7 +8133,7 @@ uint16x8_t test_vmlsl_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK-LABEL: @test_vmlsl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
uint32x4_t test_vmlsl_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
@@ -8143,7 +8143,7 @@ uint32x4_t test_vmlsl_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK-LABEL: @test_vmlsl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
uint64x2_t test_vmlsl_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
@@ -8153,7 +8153,7 @@ uint64x2_t test_vmlsl_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK-LABEL: @test_vmlsl_high_s8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %c, <16 x i8> %c, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <8 x i16> %a, [[VMULL_I_I_I]]
// CHECK: ret <8 x i16> [[SUB_I_I]]
int16x8_t test_vmlsl_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
@@ -8165,7 +8165,7 @@ int16x8_t test_vmlsl_high_s8(int16x8_t a, int8x16_t b, int8x16_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %c, <8 x i16> %c, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[SUB_I_I]]
int32x4_t test_vmlsl_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
@@ -8177,7 +8177,7 @@ int32x4_t test_vmlsl_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %c, <4 x i32> %c, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.smull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[SUB_I_I]]
int64x2_t test_vmlsl_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
@@ -8187,7 +8187,7 @@ int64x2_t test_vmlsl_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
// CHECK-LABEL: @test_vmlsl_high_u8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %c, <16 x i8> %c, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL_I_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <8 x i16> %a, [[VMULL_I_I_I]]
// CHECK: ret <8 x i16> [[SUB_I_I]]
uint16x8_t test_vmlsl_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
@@ -8199,7 +8199,7 @@ uint16x8_t test_vmlsl_high_u8(uint16x8_t a, uint8x16_t b, uint8x16_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %c, <8 x i16> %c, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I_I]]
// CHECK: ret <4 x i32> [[SUB_I_I]]
uint32x4_t test_vmlsl_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
@@ -8211,7 +8211,7 @@ uint32x4_t test_vmlsl_high_u16(uint32x4_t a, uint16x8_t b, uint16x8_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %c, <4 x i32> %c, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL2_I_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.umull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[SUB_I_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I_I]]
// CHECK: ret <2 x i64> [[SUB_I_I]]
uint64x2_t test_vmlsl_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
@@ -8221,7 +8221,7 @@ uint64x2_t test_vmlsl_high_u32(uint64x2_t a, uint32x4_t b, uint32x4_t c) {
// CHECK-LABEL: @test_vqdmull_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_s16(int16x4_t a, int16x4_t b) {
@@ -8231,7 +8231,7 @@ int32x4_t test_vqdmull_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqdmull_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_s32(int32x2_t a, int32x2_t b) {
@@ -8242,8 +8242,8 @@ int64x2_t test_vqdmull_s32(int32x2_t a, int32x2_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> %c)
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
return vqdmlal_s16(a, b, c);
@@ -8253,8 +8253,8 @@ int32x4_t test_vqdmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> %c)
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
return vqdmlal_s32(a, b, c);
@@ -8264,8 +8264,8 @@ int64x2_t test_vqdmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> %b, <4 x i16> %c)
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
return vqdmlsl_s16(a, b, c);
@@ -8275,8 +8275,8 @@ int32x4_t test_vqdmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> %b, <2 x i32> %c)
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
return vqdmlsl_s32(a, b, c);
@@ -8287,7 +8287,7 @@ int64x2_t test_vqdmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <8 x i16> %b, <8 x i16> %b, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VQDMULL_V2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
// CHECK: [[VQDMULL_V3_I_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I_I]]
int32x4_t test_vqdmull_high_s16(int16x8_t a, int16x8_t b) {
@@ -8299,7 +8299,7 @@ int32x4_t test_vqdmull_high_s16(int16x8_t a, int16x8_t b) {
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <4 x i32> %b, <4 x i32> %b, <2 x i32> <i32 2, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VQDMULL_V2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
// CHECK: [[VQDMULL_V3_I_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I_I]]
int64x2_t test_vqdmull_high_s32(int32x4_t a, int32x4_t b) {
@@ -8312,8 +8312,8 @@ int64x2_t test_vqdmull_high_s32(int32x4_t a, int32x4_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
-// CHECK: [[VQDMLAL_V3_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I_I]]) #4
+// CHECK: [[VQDMLAL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
+// CHECK: [[VQDMLAL_V3_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqadd.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I_I]]
int32x4_t test_vqdmlal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
return vqdmlal_high_s16(a, b, c);
@@ -8325,8 +8325,8 @@ int32x4_t test_vqdmlal_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
-// CHECK: [[VQDMLAL_V3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I_I]]) #4
+// CHECK: [[VQDMLAL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
+// CHECK: [[VQDMLAL_V3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqadd.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I_I]]
int64x2_t test_vqdmlal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
return vqdmlal_high_s32(a, b, c);
@@ -8338,8 +8338,8 @@ int64x2_t test_vqdmlal_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]]) #4
-// CHECK: [[VQDMLSL_V3_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I_I]]) #4
+// CHECK: [[VQDMLAL2_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[SHUFFLE_I_I]], <4 x i16> [[SHUFFLE_I7_I]])
+// CHECK: [[VQDMLSL_V3_I_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqsub.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I_I]]
int32x4_t test_vqdmlsl_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
return vqdmlsl_high_s16(a, b, c);
@@ -8351,15 +8351,15 @@ int32x4_t test_vqdmlsl_high_s16(int32x4_t a, int16x8_t b, int16x8_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE_I7_I]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]]) #4
-// CHECK: [[VQDMLSL_V3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I_I]]) #4
+// CHECK: [[VQDMLAL2_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqdmull.v2i64(<2 x i32> [[SHUFFLE_I_I]], <2 x i32> [[SHUFFLE_I7_I]])
+// CHECK: [[VQDMLSL_V3_I_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqsub.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I_I]]
int64x2_t test_vqdmlsl_high_s32(int64x2_t a, int32x4_t b, int32x4_t c) {
return vqdmlsl_high_s32(a, b, c);
}
// CHECK-LABEL: @test_vmull_p8(
-// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.pmull.v8i16(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.pmull.v8i16(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i16> [[VMULL_I]]
poly16x8_t test_vmull_p8(poly8x8_t a, poly8x8_t b) {
return vmull_p8(a, b);
@@ -8368,7 +8368,7 @@ poly16x8_t test_vmull_p8(poly8x8_t a, poly8x8_t b) {
// CHECK-LABEL: @test_vmull_high_p8(
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %a, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: [[SHUFFLE_I7_I:%.*]] = shufflevector <16 x i8> %b, <16 x i8> %b, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.pmull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]]) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.pmull.v8i16(<8 x i8> [[SHUFFLE_I_I]], <8 x i8> [[SHUFFLE_I7_I]])
// CHECK: ret <8 x i16> [[VMULL_I_I]]
poly16x8_t test_vmull_high_p8(poly8x16_t a, poly8x16_t b) {
return vmull_high_p8(a, b);
@@ -8405,7 +8405,7 @@ uint64_t test_vsubd_u64(uint64_t a, uint64_t b) {
// CHECK-LABEL: @test_vqaddb_s8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQADDB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQADDB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQADDB_S8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
int8_t test_vqaddb_s8(int8_t a, int8_t b) {
@@ -8415,7 +8415,7 @@ int8_t test_vqaddb_s8(int8_t a, int8_t b) {
// CHECK-LABEL: @test_vqaddh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQADDH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQADDH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQADDH_S16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
int16_t test_vqaddh_s16(int16_t a, int16_t b) {
@@ -8423,14 +8423,14 @@ int16_t test_vqaddh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vqadds_s32(
-// CHECK: [[VQADDS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqadd.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQADDS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqadd.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQADDS_S32_I]]
int32_t test_vqadds_s32(int32_t a, int32_t b) {
return vqadds_s32(a, b);
}
// CHECK-LABEL: @test_vqaddd_s64(
-// CHECK: [[VQADDD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqadd.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQADDD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqadd.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQADDD_S64_I]]
int64_t test_vqaddd_s64(int64_t a, int64_t b) {
return vqaddd_s64(a, b);
@@ -8439,7 +8439,7 @@ int64_t test_vqaddd_s64(int64_t a, int64_t b) {
// CHECK-LABEL: @test_vqaddb_u8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQADDB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQADDB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQADDB_U8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
uint8_t test_vqaddb_u8(uint8_t a, uint8_t b) {
@@ -8449,7 +8449,7 @@ uint8_t test_vqaddb_u8(uint8_t a, uint8_t b) {
// CHECK-LABEL: @test_vqaddh_u16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQADDH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQADDH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQADDH_U16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
uint16_t test_vqaddh_u16(uint16_t a, uint16_t b) {
@@ -8457,14 +8457,14 @@ uint16_t test_vqaddh_u16(uint16_t a, uint16_t b) {
}
// CHECK-LABEL: @test_vqadds_u32(
-// CHECK: [[VQADDS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqadd.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQADDS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqadd.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQADDS_U32_I]]
uint32_t test_vqadds_u32(uint32_t a, uint32_t b) {
return vqadds_u32(a, b);
}
// CHECK-LABEL: @test_vqaddd_u64(
-// CHECK: [[VQADDD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqadd.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQADDD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqadd.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQADDD_U64_I]]
uint64_t test_vqaddd_u64(uint64_t a, uint64_t b) {
return vqaddd_u64(a, b);
@@ -8473,7 +8473,7 @@ uint64_t test_vqaddd_u64(uint64_t a, uint64_t b) {
// CHECK-LABEL: @test_vqsubb_s8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQSUBB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqsub.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQSUBB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqsub.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQSUBB_S8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
int8_t test_vqsubb_s8(int8_t a, int8_t b) {
@@ -8483,7 +8483,7 @@ int8_t test_vqsubb_s8(int8_t a, int8_t b) {
// CHECK-LABEL: @test_vqsubh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQSUBH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQSUBH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqsub.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQSUBH_S16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
int16_t test_vqsubh_s16(int16_t a, int16_t b) {
@@ -8491,14 +8491,14 @@ int16_t test_vqsubh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vqsubs_s32(
-// CHECK: [[VQSUBS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqsub.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQSUBS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqsub.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQSUBS_S32_I]]
int32_t test_vqsubs_s32(int32_t a, int32_t b) {
return vqsubs_s32(a, b);
}
// CHECK-LABEL: @test_vqsubd_s64(
-// CHECK: [[VQSUBD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqsub.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQSUBD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqsub.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQSUBD_S64_I]]
int64_t test_vqsubd_s64(int64_t a, int64_t b) {
return vqsubd_s64(a, b);
@@ -8507,7 +8507,7 @@ int64_t test_vqsubd_s64(int64_t a, int64_t b) {
// CHECK-LABEL: @test_vqsubb_u8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQSUBB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqsub.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQSUBB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqsub.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQSUBB_U8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
uint8_t test_vqsubb_u8(uint8_t a, uint8_t b) {
@@ -8517,7 +8517,7 @@ uint8_t test_vqsubb_u8(uint8_t a, uint8_t b) {
// CHECK-LABEL: @test_vqsubh_u16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQSUBH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqsub.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQSUBH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqsub.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQSUBH_U16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
uint16_t test_vqsubh_u16(uint16_t a, uint16_t b) {
@@ -8525,28 +8525,28 @@ uint16_t test_vqsubh_u16(uint16_t a, uint16_t b) {
}
// CHECK-LABEL: @test_vqsubs_u32(
-// CHECK: [[VQSUBS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqsub.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQSUBS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqsub.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQSUBS_U32_I]]
uint32_t test_vqsubs_u32(uint32_t a, uint32_t b) {
return vqsubs_u32(a, b);
}
// CHECK-LABEL: @test_vqsubd_u64(
-// CHECK: [[VQSUBD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqsub.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQSUBD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqsub.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQSUBD_U64_I]]
uint64_t test_vqsubd_u64(uint64_t a, uint64_t b) {
return vqsubd_u64(a, b);
}
// CHECK-LABEL: @test_vshld_s64(
-// CHECK: [[VSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sshl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sshl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VSHLD_S64_I]]
int64_t test_vshld_s64(int64_t a, int64_t b) {
return vshld_s64(a, b);
}
// CHECK-LABEL: @test_vshld_u64(
-// CHECK: [[VSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.ushl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.ushl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VSHLD_U64_I]]
uint64_t test_vshld_u64(uint64_t a, uint64_t b) {
return vshld_u64(a, b);
@@ -8555,7 +8555,7 @@ uint64_t test_vshld_u64(uint64_t a, uint64_t b) {
// CHECK-LABEL: @test_vqshlb_s8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQSHLB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQSHLB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQSHLB_S8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
int8_t test_vqshlb_s8(int8_t a, int8_t b) {
@@ -8565,7 +8565,7 @@ int8_t test_vqshlb_s8(int8_t a, int8_t b) {
// CHECK-LABEL: @test_vqshlh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQSHLH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQSHLH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQSHLH_S16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
int16_t test_vqshlh_s16(int16_t a, int16_t b) {
@@ -8573,14 +8573,14 @@ int16_t test_vqshlh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vqshls_s32(
-// CHECK: [[VQSHLS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqshl.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQSHLS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqshl.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQSHLS_S32_I]]
int32_t test_vqshls_s32(int32_t a, int32_t b) {
return vqshls_s32(a, b);
}
// CHECK-LABEL: @test_vqshld_s64(
-// CHECK: [[VQSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqshl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqshl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQSHLD_S64_I]]
int64_t test_vqshld_s64(int64_t a, int64_t b) {
return vqshld_s64(a, b);
@@ -8589,7 +8589,7 @@ int64_t test_vqshld_s64(int64_t a, int64_t b) {
// CHECK-LABEL: @test_vqshlb_u8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQSHLB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQSHLB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQSHLB_U8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
uint8_t test_vqshlb_u8(uint8_t a, uint8_t b) {
@@ -8599,7 +8599,7 @@ uint8_t test_vqshlb_u8(uint8_t a, uint8_t b) {
// CHECK-LABEL: @test_vqshlh_u16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQSHLH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQSHLH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQSHLH_U16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
uint16_t test_vqshlh_u16(uint16_t a, uint16_t b) {
@@ -8607,28 +8607,28 @@ uint16_t test_vqshlh_u16(uint16_t a, uint16_t b) {
}
// CHECK-LABEL: @test_vqshls_u32(
-// CHECK: [[VQSHLS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqshl.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQSHLS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqshl.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQSHLS_U32_I]]
uint32_t test_vqshls_u32(uint32_t a, uint32_t b) {
return vqshls_u32(a, b);
}
// CHECK-LABEL: @test_vqshld_u64(
-// CHECK: [[VQSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqshl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqshl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQSHLD_U64_I]]
uint64_t test_vqshld_u64(uint64_t a, uint64_t b) {
return vqshld_u64(a, b);
}
// CHECK-LABEL: @test_vrshld_s64(
-// CHECK: [[VRSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.srshl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VRSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.srshl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VRSHLD_S64_I]]
int64_t test_vrshld_s64(int64_t a, int64_t b) {
return vrshld_s64(a, b);
}
// CHECK-LABEL: @test_vrshld_u64(
-// CHECK: [[VRSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.urshl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VRSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.urshl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VRSHLD_U64_I]]
uint64_t test_vrshld_u64(uint64_t a, uint64_t b) {
return vrshld_u64(a, b);
@@ -8637,7 +8637,7 @@ uint64_t test_vrshld_u64(uint64_t a, uint64_t b) {
// CHECK-LABEL: @test_vqrshlb_s8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQRSHLB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQRSHLB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqrshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQRSHLB_S8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
int8_t test_vqrshlb_s8(int8_t a, int8_t b) {
@@ -8647,7 +8647,7 @@ int8_t test_vqrshlb_s8(int8_t a, int8_t b) {
// CHECK-LABEL: @test_vqrshlh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQRSHLH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQRSHLH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQRSHLH_S16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
int16_t test_vqrshlh_s16(int16_t a, int16_t b) {
@@ -8655,14 +8655,14 @@ int16_t test_vqrshlh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vqrshls_s32(
-// CHECK: [[VQRSHLS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrshl.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQRSHLS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrshl.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQRSHLS_S32_I]]
int32_t test_vqrshls_s32(int32_t a, int32_t b) {
return vqrshls_s32(a, b);
}
// CHECK-LABEL: @test_vqrshld_s64(
-// CHECK: [[VQRSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqrshl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQRSHLD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqrshl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQRSHLD_S64_I]]
int64_t test_vqrshld_s64(int64_t a, int64_t b) {
return vqrshld_s64(a, b);
@@ -8671,7 +8671,7 @@ int64_t test_vqrshld_s64(int64_t a, int64_t b) {
// CHECK-LABEL: @test_vqrshlb_u8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VQRSHLB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqrshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VQRSHLB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqrshl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VQRSHLB_U8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
uint8_t test_vqrshlb_u8(uint8_t a, uint8_t b) {
@@ -8681,7 +8681,7 @@ uint8_t test_vqrshlb_u8(uint8_t a, uint8_t b) {
// CHECK-LABEL: @test_vqrshlh_u16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQRSHLH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqrshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQRSHLH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqrshl.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQRSHLH_U16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
uint16_t test_vqrshlh_u16(uint16_t a, uint16_t b) {
@@ -8689,14 +8689,14 @@ uint16_t test_vqrshlh_u16(uint16_t a, uint16_t b) {
}
// CHECK-LABEL: @test_vqrshls_u32(
-// CHECK: [[VQRSHLS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqrshl.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQRSHLS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uqrshl.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQRSHLS_U32_I]]
uint32_t test_vqrshls_u32(uint32_t a, uint32_t b) {
return vqrshls_u32(a, b);
}
// CHECK-LABEL: @test_vqrshld_u64(
-// CHECK: [[VQRSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqrshl.i64(i64 %a, i64 %b) #4
+// CHECK: [[VQRSHLD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uqrshl.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VQRSHLD_U64_I]]
uint64_t test_vqrshld_u64(uint64_t a, uint64_t b) {
return vqrshld_u64(a, b);
@@ -8704,7 +8704,7 @@ uint64_t test_vqrshld_u64(uint64_t a, uint64_t b) {
// CHECK-LABEL: @test_vpaddd_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VPADDD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a) #4
+// CHECK: [[VPADDD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a)
// CHECK: ret i64 [[VPADDD_S64_I]]
int64_t test_vpaddd_s64(int64x2_t a) {
return vpaddd_s64(a);
@@ -8732,7 +8732,7 @@ float64_t test_vpaddd_f64(float64x2_t a) {
// CHECK-LABEL: @test_vpmaxnms_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VPMAXNMS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxnmv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VPMAXNMS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxnmv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VPMAXNMS_F32_I]]
float32_t test_vpmaxnms_f32(float32x2_t a) {
return vpmaxnms_f32(a);
@@ -8740,7 +8740,7 @@ float32_t test_vpmaxnms_f32(float32x2_t a) {
// CHECK-LABEL: @test_vpmaxnmqd_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VPMAXNMQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxnmv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VPMAXNMQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxnmv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VPMAXNMQD_F64_I]]
float64_t test_vpmaxnmqd_f64(float64x2_t a) {
return vpmaxnmqd_f64(a);
@@ -8748,7 +8748,7 @@ float64_t test_vpmaxnmqd_f64(float64x2_t a) {
// CHECK-LABEL: @test_vpmaxs_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VPMAXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VPMAXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VPMAXS_F32_I]]
float32_t test_vpmaxs_f32(float32x2_t a) {
return vpmaxs_f32(a);
@@ -8756,7 +8756,7 @@ float32_t test_vpmaxs_f32(float32x2_t a) {
// CHECK-LABEL: @test_vpmaxqd_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VPMAXQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VPMAXQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VPMAXQD_F64_I]]
float64_t test_vpmaxqd_f64(float64x2_t a) {
return vpmaxqd_f64(a);
@@ -8764,7 +8764,7 @@ float64_t test_vpmaxqd_f64(float64x2_t a) {
// CHECK-LABEL: @test_vpminnms_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VPMINNMS_F32_I:%.*]] = call float @llvm.aarch64.neon.fminnmv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VPMINNMS_F32_I:%.*]] = call float @llvm.aarch64.neon.fminnmv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VPMINNMS_F32_I]]
float32_t test_vpminnms_f32(float32x2_t a) {
return vpminnms_f32(a);
@@ -8772,7 +8772,7 @@ float32_t test_vpminnms_f32(float32x2_t a) {
// CHECK-LABEL: @test_vpminnmqd_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VPMINNMQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fminnmv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VPMINNMQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fminnmv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VPMINNMQD_F64_I]]
float64_t test_vpminnmqd_f64(float64x2_t a) {
return vpminnmqd_f64(a);
@@ -8780,7 +8780,7 @@ float64_t test_vpminnmqd_f64(float64x2_t a) {
// CHECK-LABEL: @test_vpmins_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VPMINS_F32_I:%.*]] = call float @llvm.aarch64.neon.fminv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VPMINS_F32_I:%.*]] = call float @llvm.aarch64.neon.fminv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VPMINS_F32_I]]
float32_t test_vpmins_f32(float32x2_t a) {
return vpmins_f32(a);
@@ -8788,7 +8788,7 @@ float32_t test_vpmins_f32(float32x2_t a) {
// CHECK-LABEL: @test_vpminqd_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VPMINQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fminv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VPMINQD_F64_I:%.*]] = call double @llvm.aarch64.neon.fminv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VPMINQD_F64_I]]
float64_t test_vpminqd_f64(float64x2_t a) {
return vpminqd_f64(a);
@@ -8797,7 +8797,7 @@ float64_t test_vpminqd_f64(float64x2_t a) {
// CHECK-LABEL: @test_vqdmulhh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQDMULHH_S16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
int16_t test_vqdmulhh_s16(int16_t a, int16_t b) {
@@ -8805,7 +8805,7 @@ int16_t test_vqdmulhh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vqdmulhs_s32(
-// CHECK: [[VQDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqdmulh.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqdmulh.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQDMULHS_S32_I]]
int32_t test_vqdmulhs_s32(int32_t a, int32_t b) {
return vqdmulhs_s32(a, b);
@@ -8814,7 +8814,7 @@ int32_t test_vqdmulhs_s32(int32_t a, int32_t b) {
// CHECK-LABEL: @test_vqrdmulhh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQRDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQRDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VQRDMULHH_S16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
int16_t test_vqrdmulhh_s16(int16_t a, int16_t b) {
@@ -8822,21 +8822,21 @@ int16_t test_vqrdmulhh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vqrdmulhs_s32(
-// CHECK: [[VQRDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 %a, i32 %b) #4
+// CHECK: [[VQRDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VQRDMULHS_S32_I]]
int32_t test_vqrdmulhs_s32(int32_t a, int32_t b) {
return vqrdmulhs_s32(a, b);
}
// CHECK-LABEL: @test_vmulxs_f32(
-// CHECK: [[VMULXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmulx.f32(float %a, float %b) #4
+// CHECK: [[VMULXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmulx.f32(float %a, float %b)
// CHECK: ret float [[VMULXS_F32_I]]
float32_t test_vmulxs_f32(float32_t a, float32_t b) {
return vmulxs_f32(a, b);
}
// CHECK-LABEL: @test_vmulxd_f64(
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double %a, double %b) #4
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double %a, double %b)
// CHECK: ret double [[VMULXD_F64_I]]
float64_t test_vmulxd_f64(float64_t a, float64_t b) {
return vmulxd_f64(a, b);
@@ -8845,35 +8845,35 @@ float64_t test_vmulxd_f64(float64_t a, float64_t b) {
// CHECK-LABEL: @test_vmulx_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VMULX2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmulx.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VMULX2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmulx.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x double> [[VMULX2_I]]
float64x1_t test_vmulx_f64(float64x1_t a, float64x1_t b) {
return vmulx_f64(a, b);
}
// CHECK-LABEL: @test_vrecpss_f32(
-// CHECK: [[VRECPS_I:%.*]] = call float @llvm.aarch64.neon.frecps.f32(float %a, float %b) #4
+// CHECK: [[VRECPS_I:%.*]] = call float @llvm.aarch64.neon.frecps.f32(float %a, float %b)
// CHECK: ret float [[VRECPS_I]]
float32_t test_vrecpss_f32(float32_t a, float32_t b) {
return vrecpss_f32(a, b);
}
// CHECK-LABEL: @test_vrecpsd_f64(
-// CHECK: [[VRECPS_I:%.*]] = call double @llvm.aarch64.neon.frecps.f64(double %a, double %b) #4
+// CHECK: [[VRECPS_I:%.*]] = call double @llvm.aarch64.neon.frecps.f64(double %a, double %b)
// CHECK: ret double [[VRECPS_I]]
float64_t test_vrecpsd_f64(float64_t a, float64_t b) {
return vrecpsd_f64(a, b);
}
// CHECK-LABEL: @test_vrsqrtss_f32(
-// CHECK: [[VRSQRTSS_F32_I:%.*]] = call float @llvm.aarch64.neon.frsqrts.f32(float %a, float %b) #4
+// CHECK: [[VRSQRTSS_F32_I:%.*]] = call float @llvm.aarch64.neon.frsqrts.f32(float %a, float %b)
// CHECK: ret float [[VRSQRTSS_F32_I]]
float32_t test_vrsqrtss_f32(float32_t a, float32_t b) {
return vrsqrtss_f32(a, b);
}
// CHECK-LABEL: @test_vrsqrtsd_f64(
-// CHECK: [[VRSQRTSD_F64_I:%.*]] = call double @llvm.aarch64.neon.frsqrts.f64(double %a, double %b) #4
+// CHECK: [[VRSQRTSD_F64_I:%.*]] = call double @llvm.aarch64.neon.frsqrts.f64(double %a, double %b)
// CHECK: ret double [[VRSQRTSD_F64_I]]
float64_t test_vrsqrtsd_f64(float64_t a, float64_t b) {
return vrsqrtsd_f64(a, b);
@@ -8908,28 +8908,28 @@ float64_t test_vcvtd_f64_u64(uint64_t a) {
}
// CHECK-LABEL: @test_vrecpes_f32(
-// CHECK: [[VRECPES_F32_I:%.*]] = call float @llvm.aarch64.neon.frecpe.f32(float %a) #4
+// CHECK: [[VRECPES_F32_I:%.*]] = call float @llvm.aarch64.neon.frecpe.f32(float %a)
// CHECK: ret float [[VRECPES_F32_I]]
float32_t test_vrecpes_f32(float32_t a) {
return vrecpes_f32(a);
}
// CHECK-LABEL: @test_vrecped_f64(
-// CHECK: [[VRECPED_F64_I:%.*]] = call double @llvm.aarch64.neon.frecpe.f64(double %a) #4
+// CHECK: [[VRECPED_F64_I:%.*]] = call double @llvm.aarch64.neon.frecpe.f64(double %a)
// CHECK: ret double [[VRECPED_F64_I]]
float64_t test_vrecped_f64(float64_t a) {
return vrecped_f64(a);
}
// CHECK-LABEL: @test_vrecpxs_f32(
-// CHECK: [[VRECPXS_F32_I:%.*]] = call float @llvm.aarch64.neon.frecpx.f32(float %a) #4
+// CHECK: [[VRECPXS_F32_I:%.*]] = call float @llvm.aarch64.neon.frecpx.f32(float %a)
// CHECK: ret float [[VRECPXS_F32_I]]
float32_t test_vrecpxs_f32(float32_t a) {
return vrecpxs_f32(a);
}
// CHECK-LABEL: @test_vrecpxd_f64(
-// CHECK: [[VRECPXD_F64_I:%.*]] = call double @llvm.aarch64.neon.frecpx.f64(double %a) #4
+// CHECK: [[VRECPXD_F64_I:%.*]] = call double @llvm.aarch64.neon.frecpx.f64(double %a)
// CHECK: ret double [[VRECPXD_F64_I]]
float64_t test_vrecpxd_f64(float64_t a) {
return vrecpxd_f64(a);
@@ -8937,7 +8937,7 @@ float64_t test_vrecpxd_f64(float64_t a) {
// CHECK-LABEL: @test_vrsqrte_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.ursqrte.v2i32(<2 x i32> %a) #4
+// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.ursqrte.v2i32(<2 x i32> %a)
// CHECK: ret <2 x i32> [[VRSQRTE_V1_I]]
uint32x2_t test_vrsqrte_u32(uint32x2_t a) {
return vrsqrte_u32(a);
@@ -8945,21 +8945,21 @@ uint32x2_t test_vrsqrte_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vrsqrteq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.ursqrte.v4i32(<4 x i32> %a) #4
+// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.ursqrte.v4i32(<4 x i32> %a)
// CHECK: ret <4 x i32> [[VRSQRTEQ_V1_I]]
uint32x4_t test_vrsqrteq_u32(uint32x4_t a) {
return vrsqrteq_u32(a);
}
// CHECK-LABEL: @test_vrsqrtes_f32(
-// CHECK: [[VRSQRTES_F32_I:%.*]] = call float @llvm.aarch64.neon.frsqrte.f32(float %a) #4
+// CHECK: [[VRSQRTES_F32_I:%.*]] = call float @llvm.aarch64.neon.frsqrte.f32(float %a)
// CHECK: ret float [[VRSQRTES_F32_I]]
float32_t test_vrsqrtes_f32(float32_t a) {
return vrsqrtes_f32(a);
}
// CHECK-LABEL: @test_vrsqrted_f64(
-// CHECK: [[VRSQRTED_F64_I:%.*]] = call double @llvm.aarch64.neon.frsqrte.f64(double %a) #4
+// CHECK: [[VRSQRTED_F64_I:%.*]] = call double @llvm.aarch64.neon.frsqrte.f64(double %a)
// CHECK: ret double [[VRSQRTED_F64_I]]
float64_t test_vrsqrted_f64(float64_t a) {
return vrsqrted_f64(a);
@@ -17146,7 +17146,7 @@ uint64_t test_vtstd_u64(uint64_t a, uint64_t b) {
}
// CHECK-LABEL: @test_vabsd_s64(
-// CHECK: [[VABSD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.abs.i64(i64 %a) #4
+// CHECK: [[VABSD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.abs.i64(i64 %a)
// CHECK: ret i64 [[VABSD_S64_I]]
int64_t test_vabsd_s64(int64_t a) {
return (int64_t)vabsd_s64(a);
@@ -17154,7 +17154,7 @@ int64_t test_vabsd_s64(int64_t a) {
// CHECK-LABEL: @test_vqabsb_s8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
-// CHECK: [[VQABSB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqabs.v8i8(<8 x i8> [[TMP0]]) #4
+// CHECK: [[VQABSB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqabs.v8i8(<8 x i8> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <8 x i8> [[VQABSB_S8_I]], i64 0
// CHECK: ret i8 [[TMP1]]
int8_t test_vqabsb_s8(int8_t a) {
@@ -17163,7 +17163,7 @@ int8_t test_vqabsb_s8(int8_t a) {
// CHECK-LABEL: @test_vqabsh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
-// CHECK: [[VQABSH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqabs.v4i16(<4 x i16> [[TMP0]]) #4
+// CHECK: [[VQABSH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqabs.v4i16(<4 x i16> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <4 x i16> [[VQABSH_S16_I]], i64 0
// CHECK: ret i16 [[TMP1]]
int16_t test_vqabsh_s16(int16_t a) {
@@ -17171,14 +17171,14 @@ int16_t test_vqabsh_s16(int16_t a) {
}
// CHECK-LABEL: @test_vqabss_s32(
-// CHECK: [[VQABSS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqabs.i32(i32 %a) #4
+// CHECK: [[VQABSS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqabs.i32(i32 %a)
// CHECK: ret i32 [[VQABSS_S32_I]]
int32_t test_vqabss_s32(int32_t a) {
return (int32_t)vqabss_s32(a);
}
// CHECK-LABEL: @test_vqabsd_s64(
-// CHECK: [[VQABSD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqabs.i64(i64 %a) #4
+// CHECK: [[VQABSD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqabs.i64(i64 %a)
// CHECK: ret i64 [[VQABSD_S64_I]]
int64_t test_vqabsd_s64(int64_t a) {
return (int64_t)vqabsd_s64(a);
@@ -17193,7 +17193,7 @@ int64_t test_vnegd_s64(int64_t a) {
// CHECK-LABEL: @test_vqnegb_s8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
-// CHECK: [[VQNEGB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqneg.v8i8(<8 x i8> [[TMP0]]) #4
+// CHECK: [[VQNEGB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqneg.v8i8(<8 x i8> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <8 x i8> [[VQNEGB_S8_I]], i64 0
// CHECK: ret i8 [[TMP1]]
int8_t test_vqnegb_s8(int8_t a) {
@@ -17202,7 +17202,7 @@ int8_t test_vqnegb_s8(int8_t a) {
// CHECK-LABEL: @test_vqnegh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
-// CHECK: [[VQNEGH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqneg.v4i16(<4 x i16> [[TMP0]]) #4
+// CHECK: [[VQNEGH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqneg.v4i16(<4 x i16> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <4 x i16> [[VQNEGH_S16_I]], i64 0
// CHECK: ret i16 [[TMP1]]
int16_t test_vqnegh_s16(int16_t a) {
@@ -17210,14 +17210,14 @@ int16_t test_vqnegh_s16(int16_t a) {
}
// CHECK-LABEL: @test_vqnegs_s32(
-// CHECK: [[VQNEGS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqneg.i32(i32 %a) #4
+// CHECK: [[VQNEGS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqneg.i32(i32 %a)
// CHECK: ret i32 [[VQNEGS_S32_I]]
int32_t test_vqnegs_s32(int32_t a) {
return (int32_t)vqnegs_s32(a);
}
// CHECK-LABEL: @test_vqnegd_s64(
-// CHECK: [[VQNEGD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqneg.i64(i64 %a) #4
+// CHECK: [[VQNEGD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.sqneg.i64(i64 %a)
// CHECK: ret i64 [[VQNEGD_S64_I]]
int64_t test_vqnegd_s64(int64_t a) {
return (int64_t)vqnegd_s64(a);
@@ -17226,7 +17226,7 @@ int64_t test_vqnegd_s64(int64_t a) {
// CHECK-LABEL: @test_vuqaddb_s8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VUQADDB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.suqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VUQADDB_S8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.suqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VUQADDB_S8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
int8_t test_vuqaddb_s8(int8_t a, int8_t b) {
@@ -17236,7 +17236,7 @@ int8_t test_vuqaddb_s8(int8_t a, int8_t b) {
// CHECK-LABEL: @test_vuqaddh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VUQADDH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.suqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VUQADDH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.suqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VUQADDH_S16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
int16_t test_vuqaddh_s16(int16_t a, int16_t b) {
@@ -17244,14 +17244,14 @@ int16_t test_vuqaddh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vuqadds_s32(
-// CHECK: [[VUQADDS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.suqadd.i32(i32 %a, i32 %b) #4
+// CHECK: [[VUQADDS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.suqadd.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VUQADDS_S32_I]]
int32_t test_vuqadds_s32(int32_t a, int32_t b) {
return (int32_t)vuqadds_s32(a, b);
}
// CHECK-LABEL: @test_vuqaddd_s64(
-// CHECK: [[VUQADDD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.suqadd.i64(i64 %a, i64 %b) #4
+// CHECK: [[VUQADDD_S64_I:%.*]] = call i64 @llvm.aarch64.neon.suqadd.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VUQADDD_S64_I]]
int64_t test_vuqaddd_s64(int64_t a, int64_t b) {
return (int64_t)vuqaddd_s64(a, b);
@@ -17260,7 +17260,7 @@ int64_t test_vuqaddd_s64(int64_t a, int64_t b) {
// CHECK-LABEL: @test_vsqaddb_u8(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i8> undef, i8 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <8 x i8> undef, i8 %b, i64 0
-// CHECK: [[VSQADDB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.usqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]]) #4
+// CHECK: [[VSQADDB_U8_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.usqadd.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <8 x i8> [[VSQADDB_U8_I]], i64 0
// CHECK: ret i8 [[TMP2]]
uint8_t test_vsqaddb_u8(uint8_t a, uint8_t b) {
@@ -17270,7 +17270,7 @@ uint8_t test_vsqaddb_u8(uint8_t a, uint8_t b) {
// CHECK-LABEL: @test_vsqaddh_u16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VSQADDH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.usqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VSQADDH_U16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.usqadd.v4i16(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i16> [[VSQADDH_U16_I]], i64 0
// CHECK: ret i16 [[TMP2]]
uint16_t test_vsqaddh_u16(uint16_t a, uint16_t b) {
@@ -17278,14 +17278,14 @@ uint16_t test_vsqaddh_u16(uint16_t a, uint16_t b) {
}
// CHECK-LABEL: @test_vsqadds_u32(
-// CHECK: [[VSQADDS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %a, i32 %b) #4
+// CHECK: [[VSQADDS_U32_I:%.*]] = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %a, i32 %b)
// CHECK: ret i32 [[VSQADDS_U32_I]]
uint32_t test_vsqadds_u32(uint32_t a, uint32_t b) {
return (uint32_t)vsqadds_u32(a, b);
}
// CHECK-LABEL: @test_vsqaddd_u64(
-// CHECK: [[VSQADDD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %a, i64 %b) #4
+// CHECK: [[VSQADDD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %a, i64 %b)
// CHECK: ret i64 [[VSQADDD_U64_I]]
uint64_t test_vsqaddd_u64(uint64_t a, uint64_t b) {
return (uint64_t)vsqaddd_u64(a, b);
@@ -17294,17 +17294,17 @@ uint64_t test_vsqaddd_u64(uint64_t a, uint64_t b) {
// CHECK-LABEL: @test_vqdmlalh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %c, i64 0
-// CHECK: [[VQDMLXL_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQDMLXL_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[LANE0_I:%.*]] = extractelement <4 x i32> [[VQDMLXL_I]], i64 0
-// CHECK: [[VQDMLXL1_I:%.*]] = call i32 @llvm.aarch64.neon.sqadd.i32(i32 %a, i32 [[LANE0_I]]) #4
+// CHECK: [[VQDMLXL1_I:%.*]] = call i32 @llvm.aarch64.neon.sqadd.i32(i32 %a, i32 [[LANE0_I]])
// CHECK: ret i32 [[VQDMLXL1_I]]
int32_t test_vqdmlalh_s16(int32_t a, int16_t b, int16_t c) {
return (int32_t)vqdmlalh_s16(a, b, c);
}
// CHECK-LABEL: @test_vqdmlals_s32(
-// CHECK: [[VQDMLXL_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %b, i32 %c) #4
-// CHECK: [[VQDMLXL1_I:%.*]] = call i64 @llvm.aarch64.neon.sqadd.i64(i64 %a, i64 [[VQDMLXL_I]]) #4
+// CHECK: [[VQDMLXL_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %b, i32 %c)
+// CHECK: [[VQDMLXL1_I:%.*]] = call i64 @llvm.aarch64.neon.sqadd.i64(i64 %a, i64 [[VQDMLXL_I]])
// CHECK: ret i64 [[VQDMLXL1_I]]
int64_t test_vqdmlals_s32(int64_t a, int32_t b, int32_t c) {
return (int64_t)vqdmlals_s32(a, b, c);
@@ -17313,17 +17313,17 @@ int64_t test_vqdmlals_s32(int64_t a, int32_t b, int32_t c) {
// CHECK-LABEL: @test_vqdmlslh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %c, i64 0
-// CHECK: [[VQDMLXL_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQDMLXL_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[LANE0_I:%.*]] = extractelement <4 x i32> [[VQDMLXL_I]], i64 0
-// CHECK: [[VQDMLXL1_I:%.*]] = call i32 @llvm.aarch64.neon.sqsub.i32(i32 %a, i32 [[LANE0_I]]) #4
+// CHECK: [[VQDMLXL1_I:%.*]] = call i32 @llvm.aarch64.neon.sqsub.i32(i32 %a, i32 [[LANE0_I]])
// CHECK: ret i32 [[VQDMLXL1_I]]
int32_t test_vqdmlslh_s16(int32_t a, int16_t b, int16_t c) {
return (int32_t)vqdmlslh_s16(a, b, c);
}
// CHECK-LABEL: @test_vqdmlsls_s32(
-// CHECK: [[VQDMLXL_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %b, i32 %c) #4
-// CHECK: [[VQDMLXL1_I:%.*]] = call i64 @llvm.aarch64.neon.sqsub.i64(i64 %a, i64 [[VQDMLXL_I]]) #4
+// CHECK: [[VQDMLXL_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %b, i32 %c)
+// CHECK: [[VQDMLXL1_I:%.*]] = call i64 @llvm.aarch64.neon.sqsub.i64(i64 %a, i64 [[VQDMLXL_I]])
// CHECK: ret i64 [[VQDMLXL1_I]]
int64_t test_vqdmlsls_s32(int64_t a, int32_t b, int32_t c) {
return (int64_t)vqdmlsls_s32(a, b, c);
@@ -17332,7 +17332,7 @@ int64_t test_vqdmlsls_s32(int64_t a, int32_t b, int32_t c) {
// CHECK-LABEL: @test_vqdmullh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP1:%.*]] = insertelement <4 x i16> undef, i16 %b, i64 0
-// CHECK: [[VQDMULLH_S16_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]]) #4
+// CHECK: [[VQDMULLH_S16_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP0]], <4 x i16> [[TMP1]])
// CHECK: [[TMP2:%.*]] = extractelement <4 x i32> [[VQDMULLH_S16_I]], i64 0
// CHECK: ret i32 [[TMP2]]
int32_t test_vqdmullh_s16(int16_t a, int16_t b) {
@@ -17340,7 +17340,7 @@ int32_t test_vqdmullh_s16(int16_t a, int16_t b) {
}
// CHECK-LABEL: @test_vqdmulls_s32(
-// CHECK: [[VQDMULLS_S32_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %a, i32 %b) #4
+// CHECK: [[VQDMULLS_S32_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %a, i32 %b)
// CHECK: ret i64 [[VQDMULLS_S32_I]]
int64_t test_vqdmulls_s32(int32_t a, int32_t b) {
return (int64_t)vqdmulls_s32(a, b);
@@ -17348,7 +17348,7 @@ int64_t test_vqdmulls_s32(int32_t a, int32_t b) {
// CHECK-LABEL: @test_vqmovunh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i16> undef, i16 %a, i64 0
-// CHECK: [[VQMOVUNH_S16_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtun.v8i8(<8 x i16> [[TMP0]]) #4
+// CHECK: [[VQMOVUNH_S16_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtun.v8i8(<8 x i16> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <8 x i8> [[VQMOVUNH_S16_I]], i64 0
// CHECK: ret i8 [[TMP1]]
int8_t test_vqmovunh_s16(int16_t a) {
@@ -17357,7 +17357,7 @@ int8_t test_vqmovunh_s16(int16_t a) {
// CHECK-LABEL: @test_vqmovuns_s32(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i32> undef, i32 %a, i64 0
-// CHECK: [[VQMOVUNS_S32_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> [[TMP0]]) #4
+// CHECK: [[VQMOVUNS_S32_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <4 x i16> [[VQMOVUNS_S32_I]], i64 0
// CHECK: ret i16 [[TMP1]]
int16_t test_vqmovuns_s32(int32_t a) {
@@ -17365,7 +17365,7 @@ int16_t test_vqmovuns_s32(int32_t a) {
}
// CHECK-LABEL: @test_vqmovund_s64(
-// CHECK: [[VQMOVUND_S64_I:%.*]] = call i32 @llvm.aarch64.neon.scalar.sqxtun.i32.i64(i64 %a) #4
+// CHECK: [[VQMOVUND_S64_I:%.*]] = call i32 @llvm.aarch64.neon.scalar.sqxtun.i32.i64(i64 %a)
// CHECK: ret i32 [[VQMOVUND_S64_I]]
int32_t test_vqmovund_s64(int64_t a) {
return (int32_t)vqmovund_s64(a);
@@ -17373,7 +17373,7 @@ int32_t test_vqmovund_s64(int64_t a) {
// CHECK-LABEL: @test_vqmovnh_s16(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i16> undef, i16 %a, i64 0
-// CHECK: [[VQMOVNH_S16_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtn.v8i8(<8 x i16> [[TMP0]]) #4
+// CHECK: [[VQMOVNH_S16_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtn.v8i8(<8 x i16> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <8 x i8> [[VQMOVNH_S16_I]], i64 0
// CHECK: ret i8 [[TMP1]]
int8_t test_vqmovnh_s16(int16_t a) {
@@ -17382,7 +17382,7 @@ int8_t test_vqmovnh_s16(int16_t a) {
// CHECK-LABEL: @test_vqmovns_s32(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i32> undef, i32 %a, i64 0
-// CHECK: [[VQMOVNS_S32_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> [[TMP0]]) #4
+// CHECK: [[VQMOVNS_S32_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <4 x i16> [[VQMOVNS_S32_I]], i64 0
// CHECK: ret i16 [[TMP1]]
int16_t test_vqmovns_s32(int32_t a) {
@@ -17390,7 +17390,7 @@ int16_t test_vqmovns_s32(int32_t a) {
}
// CHECK-LABEL: @test_vqmovnd_s64(
-// CHECK: [[VQMOVND_S64_I:%.*]] = call i32 @llvm.aarch64.neon.scalar.sqxtn.i32.i64(i64 %a) #4
+// CHECK: [[VQMOVND_S64_I:%.*]] = call i32 @llvm.aarch64.neon.scalar.sqxtn.i32.i64(i64 %a)
// CHECK: ret i32 [[VQMOVND_S64_I]]
int32_t test_vqmovnd_s64(int64_t a) {
return (int32_t)vqmovnd_s64(a);
@@ -17398,7 +17398,7 @@ int32_t test_vqmovnd_s64(int64_t a) {
// CHECK-LABEL: @test_vqmovnh_u16(
// CHECK: [[TMP0:%.*]] = insertelement <8 x i16> undef, i16 %a, i64 0
-// CHECK: [[VQMOVNH_U16_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16> [[TMP0]]) #4
+// CHECK: [[VQMOVNH_U16_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <8 x i8> [[VQMOVNH_U16_I]], i64 0
// CHECK: ret i8 [[TMP1]]
int8_t test_vqmovnh_u16(int16_t a) {
@@ -17407,7 +17407,7 @@ int8_t test_vqmovnh_u16(int16_t a) {
// CHECK-LABEL: @test_vqmovns_u32(
// CHECK: [[TMP0:%.*]] = insertelement <4 x i32> undef, i32 %a, i64 0
-// CHECK: [[VQMOVNS_U32_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqxtn.v4i16(<4 x i32> [[TMP0]]) #4
+// CHECK: [[VQMOVNS_U32_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqxtn.v4i16(<4 x i32> [[TMP0]])
// CHECK: [[TMP1:%.*]] = extractelement <4 x i16> [[VQMOVNS_U32_I]], i64 0
// CHECK: ret i16 [[TMP1]]
int16_t test_vqmovns_u32(int32_t a) {
@@ -17415,7 +17415,7 @@ int16_t test_vqmovns_u32(int32_t a) {
}
// CHECK-LABEL: @test_vqmovnd_u64(
-// CHECK: [[VQMOVND_U64_I:%.*]] = call i32 @llvm.aarch64.neon.scalar.uqxtn.i32.i64(i64 %a) #4
+// CHECK: [[VQMOVND_U64_I:%.*]] = call i32 @llvm.aarch64.neon.scalar.uqxtn.i32.i64(i64 %a)
// CHECK: ret i32 [[VQMOVND_U64_I]]
int32_t test_vqmovnd_u64(int64_t a) {
return (int32_t)vqmovnd_u64(a);
@@ -17582,56 +17582,56 @@ uint64_t test_vcltzd_f64(float64_t a) {
}
// CHECK-LABEL: @test_vcages_f32(
-// CHECK: [[VCAGES_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facge.i32.f32(float %a, float %b) #4
+// CHECK: [[VCAGES_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facge.i32.f32(float %a, float %b)
// CHECK: ret i32 [[VCAGES_F32_I]]
uint32_t test_vcages_f32(float32_t a, float32_t b) {
return (uint32_t)vcages_f32(a, b);
}
// CHECK-LABEL: @test_vcaged_f64(
-// CHECK: [[VCAGED_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facge.i64.f64(double %a, double %b) #4
+// CHECK: [[VCAGED_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facge.i64.f64(double %a, double %b)
// CHECK: ret i64 [[VCAGED_F64_I]]
uint64_t test_vcaged_f64(float64_t a, float64_t b) {
return (uint64_t)vcaged_f64(a, b);
}
// CHECK-LABEL: @test_vcagts_f32(
-// CHECK: [[VCAGTS_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facgt.i32.f32(float %a, float %b) #4
+// CHECK: [[VCAGTS_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facgt.i32.f32(float %a, float %b)
// CHECK: ret i32 [[VCAGTS_F32_I]]
uint32_t test_vcagts_f32(float32_t a, float32_t b) {
return (uint32_t)vcagts_f32(a, b);
}
// CHECK-LABEL: @test_vcagtd_f64(
-// CHECK: [[VCAGTD_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facgt.i64.f64(double %a, double %b) #4
+// CHECK: [[VCAGTD_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facgt.i64.f64(double %a, double %b)
// CHECK: ret i64 [[VCAGTD_F64_I]]
uint64_t test_vcagtd_f64(float64_t a, float64_t b) {
return (uint64_t)vcagtd_f64(a, b);
}
// CHECK-LABEL: @test_vcales_f32(
-// CHECK: [[VCALES_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facge.i32.f32(float %b, float %a) #4
+// CHECK: [[VCALES_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facge.i32.f32(float %b, float %a)
// CHECK: ret i32 [[VCALES_F32_I]]
uint32_t test_vcales_f32(float32_t a, float32_t b) {
return (uint32_t)vcales_f32(a, b);
}
// CHECK-LABEL: @test_vcaled_f64(
-// CHECK: [[VCALED_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facge.i64.f64(double %b, double %a) #4
+// CHECK: [[VCALED_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facge.i64.f64(double %b, double %a)
// CHECK: ret i64 [[VCALED_F64_I]]
uint64_t test_vcaled_f64(float64_t a, float64_t b) {
return (uint64_t)vcaled_f64(a, b);
}
// CHECK-LABEL: @test_vcalts_f32(
-// CHECK: [[VCALTS_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facgt.i32.f32(float %b, float %a) #4
+// CHECK: [[VCALTS_F32_I:%.*]] = call i32 @llvm.aarch64.neon.facgt.i32.f32(float %b, float %a)
// CHECK: ret i32 [[VCALTS_F32_I]]
uint32_t test_vcalts_f32(float32_t a, float32_t b) {
return (uint32_t)vcalts_f32(a, b);
}
// CHECK-LABEL: @test_vcaltd_f64(
-// CHECK: [[VCALTD_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facgt.i64.f64(double %b, double %a) #4
+// CHECK: [[VCALTD_F64_I:%.*]] = call i64 @llvm.aarch64.neon.facgt.i64.f64(double %b, double %a)
// CHECK: ret i64 [[VCALTD_F64_I]]
uint64_t test_vcaltd_f64(float64_t a, float64_t b) {
return (uint64_t)vcaltd_f64(a, b);
@@ -20865,14 +20865,14 @@ poly64x2_t test_vreinterpretq_p64_p16(poly16x8_t a) {
}
// CHECK-LABEL: @test_vabds_f32(
-// CHECK: [[VABDS_F32_I:%.*]] = call float @llvm.aarch64.sisd.fabd.f32(float %a, float %b) #4
+// CHECK: [[VABDS_F32_I:%.*]] = call float @llvm.aarch64.sisd.fabd.f32(float %a, float %b)
// CHECK: ret float [[VABDS_F32_I]]
float32_t test_vabds_f32(float32_t a, float32_t b) {
return vabds_f32(a, b);
}
// CHECK-LABEL: @test_vabdd_f64(
-// CHECK: [[VABDD_F64_I:%.*]] = call double @llvm.aarch64.sisd.fabd.f64(double %a, double %b) #4
+// CHECK: [[VABDD_F64_I:%.*]] = call double @llvm.aarch64.sisd.fabd.f64(double %a, double %b)
// CHECK: ret double [[VABDD_F64_I]]
float64_t test_vabdd_f64(float64_t a, float64_t b) {
return vabdd_f64(a, b);
@@ -20881,7 +20881,7 @@ float64_t test_vabdd_f64(float64_t a, float64_t b) {
// CHECK-LABEL: @test_vuqadd_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VUQADD2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.suqadd.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VUQADD2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.suqadd.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: ret <1 x i64> [[VUQADD2_I]]
int64x1_t test_vuqadd_s64(int64x1_t a, uint64x1_t b) {
return vuqadd_s64(a, b);
@@ -20890,21 +20890,21 @@ int64x1_t test_vuqadd_s64(int64x1_t a, uint64x1_t b) {
// CHECK-LABEL: @test_vsqadd_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VSQADD2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.usqadd.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VSQADD2_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.usqadd.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: ret <1 x i64> [[VSQADD2_I]]
uint64x1_t test_vsqadd_u64(uint64x1_t a, int64x1_t b) {
return vsqadd_u64(a, b);
}
// CHECK-LABEL: @test_vsqadd_u8(
-// CHECK: [[VSQADD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.usqadd.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VSQADD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.usqadd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VSQADD_I]]
uint8x8_t test_vsqadd_u8(uint8x8_t a, int8x8_t b) {
return vsqadd_u8(a, b);
}
// CHECK-LABEL: @test_vsqaddq_u8(
-// CHECK: [[VSQADD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.usqadd.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VSQADD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.usqadd.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VSQADD_I]]
uint8x16_t test_vsqaddq_u8(uint8x16_t a, int8x16_t b) {
return vsqaddq_u8(a, b);
@@ -20913,7 +20913,7 @@ uint8x16_t test_vsqaddq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vsqadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VSQADD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.usqadd.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VSQADD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.usqadd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VSQADD2_I]]
uint16x4_t test_vsqadd_u16(uint16x4_t a, int16x4_t b) {
return vsqadd_u16(a, b);
@@ -20922,7 +20922,7 @@ uint16x4_t test_vsqadd_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vsqaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VSQADD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.usqadd.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VSQADD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.usqadd.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VSQADD2_I]]
uint16x8_t test_vsqaddq_u16(uint16x8_t a, int16x8_t b) {
return vsqaddq_u16(a, b);
@@ -20931,7 +20931,7 @@ uint16x8_t test_vsqaddq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vsqadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VSQADD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.usqadd.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VSQADD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.usqadd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VSQADD2_I]]
uint32x2_t test_vsqadd_u32(uint32x2_t a, int32x2_t b) {
return vsqadd_u32(a, b);
@@ -20940,7 +20940,7 @@ uint32x2_t test_vsqadd_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vsqaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VSQADD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.usqadd.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VSQADD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.usqadd.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VSQADD2_I]]
uint32x4_t test_vsqaddq_u32(uint32x4_t a, int32x4_t b) {
return vsqaddq_u32(a, b);
@@ -20949,7 +20949,7 @@ uint32x4_t test_vsqaddq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vsqaddq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VSQADD2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.usqadd.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VSQADD2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.usqadd.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: ret <2 x i64> [[VSQADD2_I]]
uint64x2_t test_vsqaddq_u64(uint64x2_t a, int64x2_t b) {
return vsqaddq_u64(a, b);
@@ -20957,7 +20957,7 @@ uint64x2_t test_vsqaddq_u64(uint64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vabs_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.abs.v1i64(<1 x i64> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.abs.v1i64(<1 x i64> %a)
// CHECK: ret <1 x i64> [[VABS1_I]]
int64x1_t test_vabs_s64(int64x1_t a) {
return vabs_s64(a);
@@ -20965,7 +20965,7 @@ int64x1_t test_vabs_s64(int64x1_t a) {
// CHECK-LABEL: @test_vqabs_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
-// CHECK: [[VQABS_V1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqabs.v1i64(<1 x i64> %a) #4
+// CHECK: [[VQABS_V1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqabs.v1i64(<1 x i64> %a)
// CHECK: [[VQABS_V2_I:%.*]] = bitcast <1 x i64> [[VQABS_V1_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQABS_V1_I]]
int64x1_t test_vqabs_s64(int64x1_t a) {
@@ -20974,7 +20974,7 @@ int64x1_t test_vqabs_s64(int64x1_t a) {
// CHECK-LABEL: @test_vqneg_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
-// CHECK: [[VQNEG_V1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqneg.v1i64(<1 x i64> %a) #4
+// CHECK: [[VQNEG_V1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.sqneg.v1i64(<1 x i64> %a)
// CHECK: [[VQNEG_V2_I:%.*]] = bitcast <1 x i64> [[VQNEG_V1_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQNEG_V1_I]]
int64x1_t test_vqneg_s64(int64x1_t a) {
@@ -20990,7 +20990,7 @@ int64x1_t test_vneg_s64(int64x1_t a) {
// CHECK-LABEL: @test_vaddv_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VADDV_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VADDV_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VADDV_F32_I]]
float32_t test_vaddv_f32(float32x2_t a) {
return vaddv_f32(a);
@@ -20998,7 +20998,7 @@ float32_t test_vaddv_f32(float32x2_t a) {
// CHECK-LABEL: @test_vaddvq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VADDVQ_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> %a) #4
+// CHECK: [[VADDVQ_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> %a)
// CHECK: ret float [[VADDVQ_F32_I]]
float32_t test_vaddvq_f32(float32x4_t a) {
return vaddvq_f32(a);
@@ -21006,7 +21006,7 @@ float32_t test_vaddvq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vaddvq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VADDVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VADDVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VADDVQ_F64_I]]
float64_t test_vaddvq_f64(float64x2_t a) {
return vaddvq_f64(a);
@@ -21014,7 +21014,7 @@ float64_t test_vaddvq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vmaxv_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VMAXV_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VMAXV_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VMAXV_F32_I]]
float32_t test_vmaxv_f32(float32x2_t a) {
return vmaxv_f32(a);
@@ -21022,7 +21022,7 @@ float32_t test_vmaxv_f32(float32x2_t a) {
// CHECK-LABEL: @test_vmaxvq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VMAXVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VMAXVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VMAXVQ_F64_I]]
float64_t test_vmaxvq_f64(float64x2_t a) {
return vmaxvq_f64(a);
@@ -21030,7 +21030,7 @@ float64_t test_vmaxvq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vminv_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VMINV_F32_I:%.*]] = call float @llvm.aarch64.neon.fminv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VMINV_F32_I:%.*]] = call float @llvm.aarch64.neon.fminv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VMINV_F32_I]]
float32_t test_vminv_f32(float32x2_t a) {
return vminv_f32(a);
@@ -21038,7 +21038,7 @@ float32_t test_vminv_f32(float32x2_t a) {
// CHECK-LABEL: @test_vminvq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VMINVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fminv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VMINVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fminv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VMINVQ_F64_I]]
float64_t test_vminvq_f64(float64x2_t a) {
return vminvq_f64(a);
@@ -21046,7 +21046,7 @@ float64_t test_vminvq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vmaxnmvq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VMAXNMVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxnmv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VMAXNMVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fmaxnmv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VMAXNMVQ_F64_I]]
float64_t test_vmaxnmvq_f64(float64x2_t a) {
return vmaxnmvq_f64(a);
@@ -21054,7 +21054,7 @@ float64_t test_vmaxnmvq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vmaxnmv_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VMAXNMV_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxnmv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VMAXNMV_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxnmv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VMAXNMV_F32_I]]
float32_t test_vmaxnmv_f32(float32x2_t a) {
return vmaxnmv_f32(a);
@@ -21062,7 +21062,7 @@ float32_t test_vmaxnmv_f32(float32x2_t a) {
// CHECK-LABEL: @test_vminnmvq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VMINNMVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fminnmv.f64.v2f64(<2 x double> %a) #4
+// CHECK: [[VMINNMVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.fminnmv.f64.v2f64(<2 x double> %a)
// CHECK: ret double [[VMINNMVQ_F64_I]]
float64_t test_vminnmvq_f64(float64x2_t a) {
return vminnmvq_f64(a);
@@ -21070,7 +21070,7 @@ float64_t test_vminnmvq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vminnmv_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VMINNMV_F32_I:%.*]] = call float @llvm.aarch64.neon.fminnmv.f32.v2f32(<2 x float> %a) #4
+// CHECK: [[VMINNMV_F32_I:%.*]] = call float @llvm.aarch64.neon.fminnmv.f32.v2f32(<2 x float> %a)
// CHECK: ret float [[VMINNMV_F32_I]]
float32_t test_vminnmv_f32(float32x2_t a) {
return vminnmv_f32(a);
@@ -21079,7 +21079,7 @@ float32_t test_vminnmv_f32(float32x2_t a) {
// CHECK-LABEL: @test_vpaddq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.addp.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.addp.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <2 x i64> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VPADDQ_V2_I]]
int64x2_t test_vpaddq_s64(int64x2_t a, int64x2_t b) {
@@ -21089,7 +21089,7 @@ int64x2_t test_vpaddq_s64(int64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vpaddq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VPADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.addp.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VPADDQ_V2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.addp.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VPADDQ_V3_I:%.*]] = bitcast <2 x i64> [[VPADDQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VPADDQ_V2_I]]
uint64x2_t test_vpaddq_u64(uint64x2_t a, uint64x2_t b) {
@@ -21098,7 +21098,7 @@ uint64x2_t test_vpaddq_u64(uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vpaddd_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VPADDD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a) #4
+// CHECK: [[VPADDD_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a)
// CHECK: ret i64 [[VPADDD_U64_I]]
uint64_t test_vpaddd_u64(uint64x2_t a) {
return vpaddd_u64(a);
@@ -21106,7 +21106,7 @@ uint64_t test_vpaddd_u64(uint64x2_t a) {
// CHECK-LABEL: @test_vaddvq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VADDVQ_S64_I:%.*]] = call i64 @llvm.aarch64.neon.saddv.i64.v2i64(<2 x i64> %a) #4
+// CHECK: [[VADDVQ_S64_I:%.*]] = call i64 @llvm.aarch64.neon.saddv.i64.v2i64(<2 x i64> %a)
// CHECK: ret i64 [[VADDVQ_S64_I]]
int64_t test_vaddvq_s64(int64x2_t a) {
return vaddvq_s64(a);
@@ -21114,7 +21114,7 @@ int64_t test_vaddvq_s64(int64x2_t a) {
// CHECK-LABEL: @test_vaddvq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VADDVQ_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a) #4
+// CHECK: [[VADDVQ_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> %a)
// CHECK: ret i64 [[VADDVQ_U64_I]]
uint64_t test_vaddvq_u64(uint64x2_t a) {
return vaddvq_u64(a);
@@ -21161,7 +21161,7 @@ float64x1_t test_vmls_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <1 x double> %c to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <1 x double> @llvm.fma.v1f64(<1 x double> %b, <1 x double> %c, <1 x double> %a) #4
+// CHECK: [[TMP3:%.*]] = call <1 x double> @llvm.fma.v1f64(<1 x double> %b, <1 x double> %c, <1 x double> %a)
// CHECK: ret <1 x double> [[TMP3]]
float64x1_t test_vfma_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
return vfma_f64(a, b, c);
@@ -21172,7 +21172,7 @@ float64x1_t test_vfma_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> [[SUB_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <1 x double> %c to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <1 x double> @llvm.fma.v1f64(<1 x double> [[SUB_I]], <1 x double> %c, <1 x double> %a) #4
+// CHECK: [[TMP3:%.*]] = call <1 x double> @llvm.fma.v1f64(<1 x double> [[SUB_I]], <1 x double> %c, <1 x double> %a)
// CHECK: ret <1 x double> [[TMP3]]
float64x1_t test_vfms_f64(float64x1_t a, float64x1_t b, float64x1_t c) {
return vfms_f64(a, b, c);
@@ -21188,7 +21188,7 @@ float64x1_t test_vsub_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vabd_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VABD2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fabd.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VABD2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fabd.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x double> [[VABD2_I]]
float64x1_t test_vabd_f64(float64x1_t a, float64x1_t b) {
return vabd_f64(a, b);
@@ -21197,7 +21197,7 @@ float64x1_t test_vabd_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vmax_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VMAX2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmax.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VMAX2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmax.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x double> [[VMAX2_I]]
float64x1_t test_vmax_f64(float64x1_t a, float64x1_t b) {
return vmax_f64(a, b);
@@ -21206,7 +21206,7 @@ float64x1_t test_vmax_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vmin_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VMIN2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmin.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VMIN2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmin.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x double> [[VMIN2_I]]
float64x1_t test_vmin_f64(float64x1_t a, float64x1_t b) {
return vmin_f64(a, b);
@@ -21215,7 +21215,7 @@ float64x1_t test_vmin_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vmaxnm_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VMAXNM2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmaxnm.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VMAXNM2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmaxnm.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x double> [[VMAXNM2_I]]
float64x1_t test_vmaxnm_f64(float64x1_t a, float64x1_t b) {
return vmaxnm_f64(a, b);
@@ -21224,7 +21224,7 @@ float64x1_t test_vmaxnm_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vminnm_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VMINNM2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fminnm.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VMINNM2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fminnm.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x double> [[VMINNM2_I]]
float64x1_t test_vminnm_f64(float64x1_t a, float64x1_t b) {
return vminnm_f64(a, b);
@@ -21232,7 +21232,7 @@ float64x1_t test_vminnm_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vabs_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <1 x double> @llvm.fabs.v1f64(<1 x double> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <1 x double> @llvm.fabs.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VABS1_I]]
float64x1_t test_vabs_f64(float64x1_t a) {
return vabs_f64(a);
@@ -21263,7 +21263,7 @@ uint64x1_t test_vcvt_u64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvtn_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtns.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTN1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtns.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTN1_I]]
int64x1_t test_vcvtn_s64_f64(float64x1_t a) {
return vcvtn_s64_f64(a);
@@ -21271,7 +21271,7 @@ int64x1_t test_vcvtn_s64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvtn_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtnu.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTN1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtnu.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTN1_I]]
uint64x1_t test_vcvtn_u64_f64(float64x1_t a) {
return vcvtn_u64_f64(a);
@@ -21279,7 +21279,7 @@ uint64x1_t test_vcvtn_u64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvtp_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtps.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTP1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtps.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTP1_I]]
int64x1_t test_vcvtp_s64_f64(float64x1_t a) {
return vcvtp_s64_f64(a);
@@ -21287,7 +21287,7 @@ int64x1_t test_vcvtp_s64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvtp_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtpu.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTP1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtpu.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTP1_I]]
uint64x1_t test_vcvtp_u64_f64(float64x1_t a) {
return vcvtp_u64_f64(a);
@@ -21295,7 +21295,7 @@ uint64x1_t test_vcvtp_u64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvtm_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtms.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTM1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtms.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTM1_I]]
int64x1_t test_vcvtm_s64_f64(float64x1_t a) {
return vcvtm_s64_f64(a);
@@ -21303,7 +21303,7 @@ int64x1_t test_vcvtm_s64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvtm_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtmu.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTM1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtmu.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTM1_I]]
uint64x1_t test_vcvtm_u64_f64(float64x1_t a) {
return vcvtm_u64_f64(a);
@@ -21311,7 +21311,7 @@ uint64x1_t test_vcvtm_u64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvta_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtas.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTA1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtas.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTA1_I]]
int64x1_t test_vcvta_s64_f64(float64x1_t a) {
return vcvta_s64_f64(a);
@@ -21319,7 +21319,7 @@ int64x1_t test_vcvta_s64_f64(float64x1_t a) {
// CHECK-LABEL: @test_vcvta_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtau.v1i64.v1f64(<1 x double> %a) #4
+// CHECK: [[VCVTA1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.fcvtau.v1i64.v1f64(<1 x double> %a)
// CHECK: ret <1 x i64> [[VCVTA1_I]]
uint64x1_t test_vcvta_u64_f64(float64x1_t a) {
return vcvta_u64_f64(a);
@@ -21379,7 +21379,7 @@ float64x1_t test_vcvt_n_f64_u64(uint64x1_t a) {
// CHECK-LABEL: @test_vrndn_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRNDN1_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frintn.v1f64(<1 x double> %a) #4
+// CHECK: [[VRNDN1_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frintn.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRNDN1_I]]
float64x1_t test_vrndn_f64(float64x1_t a) {
return vrndn_f64(a);
@@ -21387,7 +21387,7 @@ float64x1_t test_vrndn_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrnda_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRNDA1_I:%.*]] = call <1 x double> @llvm.round.v1f64(<1 x double> %a) #4
+// CHECK: [[VRNDA1_I:%.*]] = call <1 x double> @llvm.round.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRNDA1_I]]
float64x1_t test_vrnda_f64(float64x1_t a) {
return vrnda_f64(a);
@@ -21395,7 +21395,7 @@ float64x1_t test_vrnda_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrndp_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRNDP1_I:%.*]] = call <1 x double> @llvm.ceil.v1f64(<1 x double> %a) #4
+// CHECK: [[VRNDP1_I:%.*]] = call <1 x double> @llvm.ceil.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRNDP1_I]]
float64x1_t test_vrndp_f64(float64x1_t a) {
return vrndp_f64(a);
@@ -21403,7 +21403,7 @@ float64x1_t test_vrndp_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrndm_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRNDM1_I:%.*]] = call <1 x double> @llvm.floor.v1f64(<1 x double> %a) #4
+// CHECK: [[VRNDM1_I:%.*]] = call <1 x double> @llvm.floor.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRNDM1_I]]
float64x1_t test_vrndm_f64(float64x1_t a) {
return vrndm_f64(a);
@@ -21411,7 +21411,7 @@ float64x1_t test_vrndm_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrndx_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRNDX1_I:%.*]] = call <1 x double> @llvm.rint.v1f64(<1 x double> %a) #4
+// CHECK: [[VRNDX1_I:%.*]] = call <1 x double> @llvm.rint.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRNDX1_I]]
float64x1_t test_vrndx_f64(float64x1_t a) {
return vrndx_f64(a);
@@ -21419,7 +21419,7 @@ float64x1_t test_vrndx_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrnd_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRNDZ1_I:%.*]] = call <1 x double> @llvm.trunc.v1f64(<1 x double> %a) #4
+// CHECK: [[VRNDZ1_I:%.*]] = call <1 x double> @llvm.trunc.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRNDZ1_I]]
float64x1_t test_vrnd_f64(float64x1_t a) {
return vrnd_f64(a);
@@ -21427,7 +21427,7 @@ float64x1_t test_vrnd_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrndi_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRNDI1_I:%.*]] = call <1 x double> @llvm.nearbyint.v1f64(<1 x double> %a) #4
+// CHECK: [[VRNDI1_I:%.*]] = call <1 x double> @llvm.nearbyint.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRNDI1_I]]
float64x1_t test_vrndi_f64(float64x1_t a) {
return vrndi_f64(a);
@@ -21435,7 +21435,7 @@ float64x1_t test_vrndi_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrsqrte_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRSQRTE_V1_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frsqrte.v1f64(<1 x double> %a) #4
+// CHECK: [[VRSQRTE_V1_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frsqrte.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRSQRTE_V1_I]]
float64x1_t test_vrsqrte_f64(float64x1_t a) {
return vrsqrte_f64(a);
@@ -21443,7 +21443,7 @@ float64x1_t test_vrsqrte_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrecpe_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VRECPE_V1_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frecpe.v1f64(<1 x double> %a) #4
+// CHECK: [[VRECPE_V1_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frecpe.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VRECPE_V1_I]]
float64x1_t test_vrecpe_f64(float64x1_t a) {
return vrecpe_f64(a);
@@ -21451,7 +21451,7 @@ float64x1_t test_vrecpe_f64(float64x1_t a) {
// CHECK-LABEL: @test_vsqrt_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
-// CHECK: [[VSQRT_I:%.*]] = call <1 x double> @llvm.sqrt.v1f64(<1 x double> %a) #4
+// CHECK: [[VSQRT_I:%.*]] = call <1 x double> @llvm.sqrt.v1f64(<1 x double> %a)
// CHECK: ret <1 x double> [[VSQRT_I]]
float64x1_t test_vsqrt_f64(float64x1_t a) {
return vsqrt_f64(a);
@@ -21460,7 +21460,7 @@ float64x1_t test_vsqrt_f64(float64x1_t a) {
// CHECK-LABEL: @test_vrecps_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VRECPS_V2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frecps.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VRECPS_V2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frecps.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: ret <1 x double> [[VRECPS_V2_I]]
float64x1_t test_vrecps_f64(float64x1_t a, float64x1_t b) {
return vrecps_f64(a, b);
@@ -21469,7 +21469,7 @@ float64x1_t test_vrecps_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vrsqrts_f64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8>
-// CHECK: [[VRSQRTS_V2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frsqrts.v1f64(<1 x double> %a, <1 x double> %b) #4
+// CHECK: [[VRSQRTS_V2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.frsqrts.v1f64(<1 x double> %a, <1 x double> %b)
// CHECK: [[VRSQRTS_V3_I:%.*]] = bitcast <1 x double> [[VRSQRTS_V2_I]] to <8 x i8>
// CHECK: ret <1 x double> [[VRSQRTS_V2_I]]
float64x1_t test_vrsqrts_f64(float64x1_t a, float64x1_t b) {
@@ -21478,7 +21478,7 @@ float64x1_t test_vrsqrts_f64(float64x1_t a, float64x1_t b) {
// CHECK-LABEL: @test_vminv_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VMINV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sminv.i32.v2i32(<2 x i32> %a) #4
+// CHECK: [[VMINV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sminv.i32.v2i32(<2 x i32> %a)
// CHECK: ret i32 [[VMINV_S32_I]]
int32_t test_vminv_s32(int32x2_t a) {
return vminv_s32(a);
@@ -21486,7 +21486,7 @@ int32_t test_vminv_s32(int32x2_t a) {
// CHECK-LABEL: @test_vminv_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VMINV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uminv.i32.v2i32(<2 x i32> %a) #4
+// CHECK: [[VMINV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uminv.i32.v2i32(<2 x i32> %a)
// CHECK: ret i32 [[VMINV_U32_I]]
uint32_t test_vminv_u32(uint32x2_t a) {
return vminv_u32(a);
@@ -21494,7 +21494,7 @@ uint32_t test_vminv_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vmaxv_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VMAXV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.smaxv.i32.v2i32(<2 x i32> %a) #4
+// CHECK: [[VMAXV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.smaxv.i32.v2i32(<2 x i32> %a)
// CHECK: ret i32 [[VMAXV_S32_I]]
int32_t test_vmaxv_s32(int32x2_t a) {
return vmaxv_s32(a);
@@ -21502,7 +21502,7 @@ int32_t test_vmaxv_s32(int32x2_t a) {
// CHECK-LABEL: @test_vmaxv_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VMAXV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.umaxv.i32.v2i32(<2 x i32> %a) #4
+// CHECK: [[VMAXV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.umaxv.i32.v2i32(<2 x i32> %a)
// CHECK: ret i32 [[VMAXV_U32_I]]
uint32_t test_vmaxv_u32(uint32x2_t a) {
return vmaxv_u32(a);
@@ -21510,7 +21510,7 @@ uint32_t test_vmaxv_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vaddv_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VADDV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.saddv.i32.v2i32(<2 x i32> %a) #4
+// CHECK: [[VADDV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.saddv.i32.v2i32(<2 x i32> %a)
// CHECK: ret i32 [[VADDV_S32_I]]
int32_t test_vaddv_s32(int32x2_t a) {
return vaddv_s32(a);
@@ -21518,7 +21518,7 @@ int32_t test_vaddv_s32(int32x2_t a) {
// CHECK-LABEL: @test_vaddv_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VADDV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uaddv.i32.v2i32(<2 x i32> %a) #4
+// CHECK: [[VADDV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uaddv.i32.v2i32(<2 x i32> %a)
// CHECK: ret i32 [[VADDV_U32_I]]
uint32_t test_vaddv_u32(uint32x2_t a) {
return vaddv_u32(a);
@@ -21526,7 +21526,7 @@ uint32_t test_vaddv_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vaddlv_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VADDLV_S32_I:%.*]] = call i64 @llvm.aarch64.neon.saddlv.i64.v2i32(<2 x i32> %a) #4
+// CHECK: [[VADDLV_S32_I:%.*]] = call i64 @llvm.aarch64.neon.saddlv.i64.v2i32(<2 x i32> %a)
// CHECK: ret i64 [[VADDLV_S32_I]]
int64_t test_vaddlv_s32(int32x2_t a) {
return vaddlv_s32(a);
@@ -21534,7 +21534,7 @@ int64_t test_vaddlv_s32(int32x2_t a) {
// CHECK-LABEL: @test_vaddlv_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VADDLV_U32_I:%.*]] = call i64 @llvm.aarch64.neon.uaddlv.i64.v2i32(<2 x i32> %a) #4
+// CHECK: [[VADDLV_U32_I:%.*]] = call i64 @llvm.aarch64.neon.uaddlv.i64.v2i32(<2 x i32> %a)
// CHECK: ret i64 [[VADDLV_U32_I]]
uint64_t test_vaddlv_u32(uint32x2_t a) {
return vaddlv_u32(a);
diff --git a/test/CodeGen/aarch64-neon-ldst-one.c b/test/CodeGen/aarch64-neon-ldst-one.c
index 25bd797b92..9bd9ab1cb6 100644
--- a/test/CodeGen/aarch64-neon-ldst-one.c
+++ b/test/CodeGen/aarch64-neon-ldst-one.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -fallow-half-arguments-and-returns -emit-llvm -o - %s \
+// RUN: -disable-O0-optnone -fallow-half-arguments-and-returns -emit-llvm -o - %s \
// RUN: | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/aarch64-neon-misc.c b/test/CodeGen/aarch64-neon-misc.c
index 1342bbb0c8..0772d4fc67 100644
--- a/test/CodeGen/aarch64-neon-misc.c
+++ b/test/CodeGen/aarch64-neon-misc.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -fallow-half-arguments-and-returns -emit-llvm -o - %s \
+// RUN: -disable-O0-optnone -fallow-half-arguments-and-returns -emit-llvm -o - %s \
// RUN: | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
@@ -911,7 +911,7 @@ float32x4_t test_vrev64q_f32(float32x4_t a) {
}
// CHECK-LABEL: @test_vpaddl_s8(
-// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.saddlp.v4i16.v8i8(<8 x i8> %a) #2
+// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.saddlp.v4i16.v8i8(<8 x i8> %a)
// CHECK: ret <4 x i16> [[VPADDL_I]]
int16x4_t test_vpaddl_s8(int8x8_t a) {
return vpaddl_s8(a);
@@ -919,7 +919,7 @@ int16x4_t test_vpaddl_s8(int8x8_t a) {
// CHECK-LABEL: @test_vpaddl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.saddlp.v2i32.v4i16(<4 x i16> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.saddlp.v2i32.v4i16(<4 x i16> %a)
// CHECK: ret <2 x i32> [[VPADDL1_I]]
int32x2_t test_vpaddl_s16(int16x4_t a) {
return vpaddl_s16(a);
@@ -927,14 +927,14 @@ int32x2_t test_vpaddl_s16(int16x4_t a) {
// CHECK-LABEL: @test_vpaddl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.saddlp.v1i64.v2i32(<2 x i32> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.saddlp.v1i64.v2i32(<2 x i32> %a)
// CHECK: ret <1 x i64> [[VPADDL1_I]]
int64x1_t test_vpaddl_s32(int32x2_t a) {
return vpaddl_s32(a);
}
// CHECK-LABEL: @test_vpaddl_u8(
-// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uaddlp.v4i16.v8i8(<8 x i8> %a) #2
+// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uaddlp.v4i16.v8i8(<8 x i8> %a)
// CHECK: ret <4 x i16> [[VPADDL_I]]
uint16x4_t test_vpaddl_u8(uint8x8_t a) {
return vpaddl_u8(a);
@@ -942,7 +942,7 @@ uint16x4_t test_vpaddl_u8(uint8x8_t a) {
// CHECK-LABEL: @test_vpaddl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uaddlp.v2i32.v4i16(<4 x i16> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uaddlp.v2i32.v4i16(<4 x i16> %a)
// CHECK: ret <2 x i32> [[VPADDL1_I]]
uint32x2_t test_vpaddl_u16(uint16x4_t a) {
return vpaddl_u16(a);
@@ -950,14 +950,14 @@ uint32x2_t test_vpaddl_u16(uint16x4_t a) {
// CHECK-LABEL: @test_vpaddl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uaddlp.v1i64.v2i32(<2 x i32> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uaddlp.v1i64.v2i32(<2 x i32> %a)
// CHECK: ret <1 x i64> [[VPADDL1_I]]
uint64x1_t test_vpaddl_u32(uint32x2_t a) {
return vpaddl_u32(a);
}
// CHECK-LABEL: @test_vpaddlq_s8(
-// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.saddlp.v8i16.v16i8(<16 x i8> %a) #2
+// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.saddlp.v8i16.v16i8(<16 x i8> %a)
// CHECK: ret <8 x i16> [[VPADDL_I]]
int16x8_t test_vpaddlq_s8(int8x16_t a) {
return vpaddlq_s8(a);
@@ -965,7 +965,7 @@ int16x8_t test_vpaddlq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vpaddlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.saddlp.v4i32.v8i16(<8 x i16> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.saddlp.v4i32.v8i16(<8 x i16> %a)
// CHECK: ret <4 x i32> [[VPADDL1_I]]
int32x4_t test_vpaddlq_s16(int16x8_t a) {
return vpaddlq_s16(a);
@@ -973,14 +973,14 @@ int32x4_t test_vpaddlq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vpaddlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.saddlp.v2i64.v4i32(<4 x i32> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.saddlp.v2i64.v4i32(<4 x i32> %a)
// CHECK: ret <2 x i64> [[VPADDL1_I]]
int64x2_t test_vpaddlq_s32(int32x4_t a) {
return vpaddlq_s32(a);
}
// CHECK-LABEL: @test_vpaddlq_u8(
-// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uaddlp.v8i16.v16i8(<16 x i8> %a) #2
+// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uaddlp.v8i16.v16i8(<16 x i8> %a)
// CHECK: ret <8 x i16> [[VPADDL_I]]
uint16x8_t test_vpaddlq_u8(uint8x16_t a) {
return vpaddlq_u8(a);
@@ -988,7 +988,7 @@ uint16x8_t test_vpaddlq_u8(uint8x16_t a) {
// CHECK-LABEL: @test_vpaddlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uaddlp.v4i32.v8i16(<8 x i16> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uaddlp.v4i32.v8i16(<8 x i16> %a)
// CHECK: ret <4 x i32> [[VPADDL1_I]]
uint32x4_t test_vpaddlq_u16(uint16x8_t a) {
return vpaddlq_u16(a);
@@ -996,7 +996,7 @@ uint32x4_t test_vpaddlq_u16(uint16x8_t a) {
// CHECK-LABEL: @test_vpaddlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uaddlp.v2i64.v4i32(<4 x i32> %a) #2
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uaddlp.v2i64.v4i32(<4 x i32> %a)
// CHECK: ret <2 x i64> [[VPADDL1_I]]
uint64x2_t test_vpaddlq_u32(uint32x4_t a) {
return vpaddlq_u32(a);
@@ -1004,7 +1004,7 @@ uint64x2_t test_vpaddlq_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vpadal_s8(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADAL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.saddlp.v4i16.v8i8(<8 x i8> %b) #2
+// CHECK: [[VPADAL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.saddlp.v4i16.v8i8(<8 x i8> %b)
// CHECK: [[TMP1:%.*]] = add <4 x i16> [[VPADAL_I]], %a
// CHECK: ret <4 x i16> [[TMP1]]
int16x4_t test_vpadal_s8(int16x4_t a, int8x8_t b) {
@@ -1014,7 +1014,7 @@ int16x4_t test_vpadal_s8(int16x4_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpadal_s16(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.saddlp.v2i32.v4i16(<4 x i16> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.saddlp.v2i32.v4i16(<4 x i16> %b)
// CHECK: [[TMP2:%.*]] = add <2 x i32> [[VPADAL1_I]], %a
// CHECK: ret <2 x i32> [[TMP2]]
int32x2_t test_vpadal_s16(int32x2_t a, int16x4_t b) {
@@ -1024,7 +1024,7 @@ int32x2_t test_vpadal_s16(int32x2_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpadal_s32(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.saddlp.v1i64.v2i32(<2 x i32> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.saddlp.v1i64.v2i32(<2 x i32> %b)
// CHECK: [[TMP2:%.*]] = add <1 x i64> [[VPADAL1_I]], %a
// CHECK: ret <1 x i64> [[TMP2]]
int64x1_t test_vpadal_s32(int64x1_t a, int32x2_t b) {
@@ -1033,7 +1033,7 @@ int64x1_t test_vpadal_s32(int64x1_t a, int32x2_t b) {
// CHECK-LABEL: @test_vpadal_u8(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADAL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uaddlp.v4i16.v8i8(<8 x i8> %b) #2
+// CHECK: [[VPADAL_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uaddlp.v4i16.v8i8(<8 x i8> %b)
// CHECK: [[TMP1:%.*]] = add <4 x i16> [[VPADAL_I]], %a
// CHECK: ret <4 x i16> [[TMP1]]
uint16x4_t test_vpadal_u8(uint16x4_t a, uint8x8_t b) {
@@ -1043,7 +1043,7 @@ uint16x4_t test_vpadal_u8(uint16x4_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpadal_u16(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uaddlp.v2i32.v4i16(<4 x i16> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uaddlp.v2i32.v4i16(<4 x i16> %b)
// CHECK: [[TMP2:%.*]] = add <2 x i32> [[VPADAL1_I]], %a
// CHECK: ret <2 x i32> [[TMP2]]
uint32x2_t test_vpadal_u16(uint32x2_t a, uint16x4_t b) {
@@ -1053,7 +1053,7 @@ uint32x2_t test_vpadal_u16(uint32x2_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpadal_u32(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uaddlp.v1i64.v2i32(<2 x i32> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <1 x i64> @llvm.aarch64.neon.uaddlp.v1i64.v2i32(<2 x i32> %b)
// CHECK: [[TMP2:%.*]] = add <1 x i64> [[VPADAL1_I]], %a
// CHECK: ret <1 x i64> [[TMP2]]
uint64x1_t test_vpadal_u32(uint64x1_t a, uint32x2_t b) {
@@ -1062,7 +1062,7 @@ uint64x1_t test_vpadal_u32(uint64x1_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpadalq_s8(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADAL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.saddlp.v8i16.v16i8(<16 x i8> %b) #2
+// CHECK: [[VPADAL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.saddlp.v8i16.v16i8(<16 x i8> %b)
// CHECK: [[TMP1:%.*]] = add <8 x i16> [[VPADAL_I]], %a
// CHECK: ret <8 x i16> [[TMP1]]
int16x8_t test_vpadalq_s8(int16x8_t a, int8x16_t b) {
@@ -1072,7 +1072,7 @@ int16x8_t test_vpadalq_s8(int16x8_t a, int8x16_t b) {
// CHECK-LABEL: @test_vpadalq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.saddlp.v4i32.v8i16(<8 x i16> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.saddlp.v4i32.v8i16(<8 x i16> %b)
// CHECK: [[TMP2:%.*]] = add <4 x i32> [[VPADAL1_I]], %a
// CHECK: ret <4 x i32> [[TMP2]]
int32x4_t test_vpadalq_s16(int32x4_t a, int16x8_t b) {
@@ -1082,7 +1082,7 @@ int32x4_t test_vpadalq_s16(int32x4_t a, int16x8_t b) {
// CHECK-LABEL: @test_vpadalq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.saddlp.v2i64.v4i32(<4 x i32> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.saddlp.v2i64.v4i32(<4 x i32> %b)
// CHECK: [[TMP2:%.*]] = add <2 x i64> [[VPADAL1_I]], %a
// CHECK: ret <2 x i64> [[TMP2]]
int64x2_t test_vpadalq_s32(int64x2_t a, int32x4_t b) {
@@ -1091,7 +1091,7 @@ int64x2_t test_vpadalq_s32(int64x2_t a, int32x4_t b) {
// CHECK-LABEL: @test_vpadalq_u8(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADAL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uaddlp.v8i16.v16i8(<16 x i8> %b) #2
+// CHECK: [[VPADAL_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.uaddlp.v8i16.v16i8(<16 x i8> %b)
// CHECK: [[TMP1:%.*]] = add <8 x i16> [[VPADAL_I]], %a
// CHECK: ret <8 x i16> [[TMP1]]
uint16x8_t test_vpadalq_u8(uint16x8_t a, uint8x16_t b) {
@@ -1101,7 +1101,7 @@ uint16x8_t test_vpadalq_u8(uint16x8_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vpadalq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uaddlp.v4i32.v8i16(<8 x i16> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.uaddlp.v4i32.v8i16(<8 x i16> %b)
// CHECK: [[TMP2:%.*]] = add <4 x i32> [[VPADAL1_I]], %a
// CHECK: ret <4 x i32> [[TMP2]]
uint32x4_t test_vpadalq_u16(uint32x4_t a, uint16x8_t b) {
@@ -1111,7 +1111,7 @@ uint32x4_t test_vpadalq_u16(uint32x4_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vpadalq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPADAL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uaddlp.v2i64.v4i32(<4 x i32> %b) #2
+// CHECK: [[VPADAL1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.uaddlp.v2i64.v4i32(<4 x i32> %b)
// CHECK: [[TMP2:%.*]] = add <2 x i64> [[VPADAL1_I]], %a
// CHECK: ret <2 x i64> [[TMP2]]
uint64x2_t test_vpadalq_u32(uint64x2_t a, uint32x4_t b) {
@@ -1119,14 +1119,14 @@ uint64x2_t test_vpadalq_u32(uint64x2_t a, uint32x4_t b) {
}
// CHECK-LABEL: @test_vqabs_s8(
-// CHECK: [[VQABS_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqabs.v8i8(<8 x i8> %a) #2
+// CHECK: [[VQABS_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqabs.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VQABS_V_I]]
int8x8_t test_vqabs_s8(int8x8_t a) {
return vqabs_s8(a);
}
// CHECK-LABEL: @test_vqabsq_s8(
-// CHECK: [[VQABSQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqabs.v16i8(<16 x i8> %a) #2
+// CHECK: [[VQABSQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqabs.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VQABSQ_V_I]]
int8x16_t test_vqabsq_s8(int8x16_t a) {
return vqabsq_s8(a);
@@ -1134,7 +1134,7 @@ int8x16_t test_vqabsq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vqabs_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VQABS_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqabs.v4i16(<4 x i16> %a) #2
+// CHECK: [[VQABS_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqabs.v4i16(<4 x i16> %a)
// CHECK: [[VQABS_V2_I:%.*]] = bitcast <4 x i16> [[VQABS_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQABS_V1_I]]
int16x4_t test_vqabs_s16(int16x4_t a) {
@@ -1143,7 +1143,7 @@ int16x4_t test_vqabs_s16(int16x4_t a) {
// CHECK-LABEL: @test_vqabsq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQABSQ_V1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqabs.v8i16(<8 x i16> %a) #2
+// CHECK: [[VQABSQ_V1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqabs.v8i16(<8 x i16> %a)
// CHECK: [[VQABSQ_V2_I:%.*]] = bitcast <8 x i16> [[VQABSQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQABSQ_V1_I]]
int16x8_t test_vqabsq_s16(int16x8_t a) {
@@ -1152,7 +1152,7 @@ int16x8_t test_vqabsq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqabs_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VQABS_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqabs.v2i32(<2 x i32> %a) #2
+// CHECK: [[VQABS_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqabs.v2i32(<2 x i32> %a)
// CHECK: [[VQABS_V2_I:%.*]] = bitcast <2 x i32> [[VQABS_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQABS_V1_I]]
int32x2_t test_vqabs_s32(int32x2_t a) {
@@ -1161,7 +1161,7 @@ int32x2_t test_vqabs_s32(int32x2_t a) {
// CHECK-LABEL: @test_vqabsq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQABSQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqabs.v4i32(<4 x i32> %a) #2
+// CHECK: [[VQABSQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqabs.v4i32(<4 x i32> %a)
// CHECK: [[VQABSQ_V2_I:%.*]] = bitcast <4 x i32> [[VQABSQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQABSQ_V1_I]]
int32x4_t test_vqabsq_s32(int32x4_t a) {
@@ -1170,7 +1170,7 @@ int32x4_t test_vqabsq_s32(int32x4_t a) {
// CHECK-LABEL: @test_vqabsq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQABSQ_V1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqabs.v2i64(<2 x i64> %a) #2
+// CHECK: [[VQABSQ_V1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqabs.v2i64(<2 x i64> %a)
// CHECK: [[VQABSQ_V2_I:%.*]] = bitcast <2 x i64> [[VQABSQ_V1_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQABSQ_V1_I]]
int64x2_t test_vqabsq_s64(int64x2_t a) {
@@ -1178,14 +1178,14 @@ int64x2_t test_vqabsq_s64(int64x2_t a) {
}
// CHECK-LABEL: @test_vqneg_s8(
-// CHECK: [[VQNEG_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqneg.v8i8(<8 x i8> %a) #2
+// CHECK: [[VQNEG_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqneg.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VQNEG_V_I]]
int8x8_t test_vqneg_s8(int8x8_t a) {
return vqneg_s8(a);
}
// CHECK-LABEL: @test_vqnegq_s8(
-// CHECK: [[VQNEGQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqneg.v16i8(<16 x i8> %a) #2
+// CHECK: [[VQNEGQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.sqneg.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VQNEGQ_V_I]]
int8x16_t test_vqnegq_s8(int8x16_t a) {
return vqnegq_s8(a);
@@ -1193,7 +1193,7 @@ int8x16_t test_vqnegq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vqneg_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VQNEG_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqneg.v4i16(<4 x i16> %a) #2
+// CHECK: [[VQNEG_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqneg.v4i16(<4 x i16> %a)
// CHECK: [[VQNEG_V2_I:%.*]] = bitcast <4 x i16> [[VQNEG_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQNEG_V1_I]]
int16x4_t test_vqneg_s16(int16x4_t a) {
@@ -1202,7 +1202,7 @@ int16x4_t test_vqneg_s16(int16x4_t a) {
// CHECK-LABEL: @test_vqnegq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQNEGQ_V1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqneg.v8i16(<8 x i16> %a) #2
+// CHECK: [[VQNEGQ_V1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.sqneg.v8i16(<8 x i16> %a)
// CHECK: [[VQNEGQ_V2_I:%.*]] = bitcast <8 x i16> [[VQNEGQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQNEGQ_V1_I]]
int16x8_t test_vqnegq_s16(int16x8_t a) {
@@ -1211,7 +1211,7 @@ int16x8_t test_vqnegq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqneg_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VQNEG_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqneg.v2i32(<2 x i32> %a) #2
+// CHECK: [[VQNEG_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqneg.v2i32(<2 x i32> %a)
// CHECK: [[VQNEG_V2_I:%.*]] = bitcast <2 x i32> [[VQNEG_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQNEG_V1_I]]
int32x2_t test_vqneg_s32(int32x2_t a) {
@@ -1220,7 +1220,7 @@ int32x2_t test_vqneg_s32(int32x2_t a) {
// CHECK-LABEL: @test_vqnegq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQNEGQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqneg.v4i32(<4 x i32> %a) #2
+// CHECK: [[VQNEGQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqneg.v4i32(<4 x i32> %a)
// CHECK: [[VQNEGQ_V2_I:%.*]] = bitcast <4 x i32> [[VQNEGQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQNEGQ_V1_I]]
int32x4_t test_vqnegq_s32(int32x4_t a) {
@@ -1229,7 +1229,7 @@ int32x4_t test_vqnegq_s32(int32x4_t a) {
// CHECK-LABEL: @test_vqnegq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQNEGQ_V1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqneg.v2i64(<2 x i64> %a) #2
+// CHECK: [[VQNEGQ_V1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.sqneg.v2i64(<2 x i64> %a)
// CHECK: [[VQNEGQ_V2_I:%.*]] = bitcast <2 x i64> [[VQNEGQ_V1_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQNEGQ_V1_I]]
int64x2_t test_vqnegq_s64(int64x2_t a) {
@@ -1307,14 +1307,14 @@ float64x2_t test_vnegq_f64(float64x2_t a) {
}
// CHECK-LABEL: @test_vabs_s8(
-// CHECK: [[VABS_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.abs.v8i8(<8 x i8> %a) #2
+// CHECK: [[VABS_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.abs.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VABS_I]]
int8x8_t test_vabs_s8(int8x8_t a) {
return vabs_s8(a);
}
// CHECK-LABEL: @test_vabsq_s8(
-// CHECK: [[VABS_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.abs.v16i8(<16 x i8> %a) #2
+// CHECK: [[VABS_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.abs.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VABS_I]]
int8x16_t test_vabsq_s8(int8x16_t a) {
return vabsq_s8(a);
@@ -1322,7 +1322,7 @@ int8x16_t test_vabsq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vabs_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.abs.v4i16(<4 x i16> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.abs.v4i16(<4 x i16> %a)
// CHECK: ret <4 x i16> [[VABS1_I]]
int16x4_t test_vabs_s16(int16x4_t a) {
return vabs_s16(a);
@@ -1330,7 +1330,7 @@ int16x4_t test_vabs_s16(int16x4_t a) {
// CHECK-LABEL: @test_vabsq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.abs.v8i16(<8 x i16> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.abs.v8i16(<8 x i16> %a)
// CHECK: ret <8 x i16> [[VABS1_I]]
int16x8_t test_vabsq_s16(int16x8_t a) {
return vabsq_s16(a);
@@ -1338,7 +1338,7 @@ int16x8_t test_vabsq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vabs_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.abs.v2i32(<2 x i32> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.abs.v2i32(<2 x i32> %a)
// CHECK: ret <2 x i32> [[VABS1_I]]
int32x2_t test_vabs_s32(int32x2_t a) {
return vabs_s32(a);
@@ -1346,7 +1346,7 @@ int32x2_t test_vabs_s32(int32x2_t a) {
// CHECK-LABEL: @test_vabsq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.abs.v4i32(<4 x i32> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.abs.v4i32(<4 x i32> %a)
// CHECK: ret <4 x i32> [[VABS1_I]]
int32x4_t test_vabsq_s32(int32x4_t a) {
return vabsq_s32(a);
@@ -1354,7 +1354,7 @@ int32x4_t test_vabsq_s32(int32x4_t a) {
// CHECK-LABEL: @test_vabsq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.abs.v2i64(<2 x i64> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.abs.v2i64(<2 x i64> %a)
// CHECK: ret <2 x i64> [[VABS1_I]]
int64x2_t test_vabsq_s64(int64x2_t a) {
return vabsq_s64(a);
@@ -1362,7 +1362,7 @@ int64x2_t test_vabsq_s64(int64x2_t a) {
// CHECK-LABEL: @test_vabs_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VABS1_I]]
float32x2_t test_vabs_f32(float32x2_t a) {
return vabs_f32(a);
@@ -1370,7 +1370,7 @@ float32x2_t test_vabs_f32(float32x2_t a) {
// CHECK-LABEL: @test_vabsq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <4 x float> @llvm.fabs.v4f32(<4 x float> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <4 x float> @llvm.fabs.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VABS1_I]]
float32x4_t test_vabsq_f32(float32x4_t a) {
return vabsq_f32(a);
@@ -1378,21 +1378,21 @@ float32x4_t test_vabsq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vabsq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <2 x double> @llvm.fabs.v2f64(<2 x double> %a) #2
+// CHECK: [[VABS1_I:%.*]] = call <2 x double> @llvm.fabs.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VABS1_I]]
float64x2_t test_vabsq_f64(float64x2_t a) {
return vabsq_f64(a);
}
// CHECK-LABEL: @test_vuqadd_s8(
-// CHECK: [[VUQADD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.suqadd.v8i8(<8 x i8> %a, <8 x i8> %b) #2
+// CHECK: [[VUQADD_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.suqadd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VUQADD_I]]
int8x8_t test_vuqadd_s8(int8x8_t a, int8x8_t b) {
return vuqadd_s8(a, b);
}
// CHECK-LABEL: @test_vuqaddq_s8(
-// CHECK: [[VUQADD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.suqadd.v16i8(<16 x i8> %a, <16 x i8> %b) #2
+// CHECK: [[VUQADD_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.suqadd.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VUQADD_I]]
int8x16_t test_vuqaddq_s8(int8x16_t a, int8x16_t b) {
return vuqaddq_s8(a, b);
@@ -1401,7 +1401,7 @@ int8x16_t test_vuqaddq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vuqadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VUQADD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.suqadd.v4i16(<4 x i16> %a, <4 x i16> %b) #2
+// CHECK: [[VUQADD2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.suqadd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i16> [[VUQADD2_I]]
int16x4_t test_vuqadd_s16(int16x4_t a, int16x4_t b) {
return vuqadd_s16(a, b);
@@ -1410,7 +1410,7 @@ int16x4_t test_vuqadd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vuqaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VUQADD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.suqadd.v8i16(<8 x i16> %a, <8 x i16> %b) #2
+// CHECK: [[VUQADD2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.suqadd.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i16> [[VUQADD2_I]]
int16x8_t test_vuqaddq_s16(int16x8_t a, int16x8_t b) {
return vuqaddq_s16(a, b);
@@ -1419,7 +1419,7 @@ int16x8_t test_vuqaddq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vuqadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VUQADD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.suqadd.v2i32(<2 x i32> %a, <2 x i32> %b) #2
+// CHECK: [[VUQADD2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.suqadd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i32> [[VUQADD2_I]]
int32x2_t test_vuqadd_s32(int32x2_t a, int32x2_t b) {
return vuqadd_s32(a, b);
@@ -1428,7 +1428,7 @@ int32x2_t test_vuqadd_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vuqaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VUQADD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.suqadd.v4i32(<4 x i32> %a, <4 x i32> %b) #2
+// CHECK: [[VUQADD2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.suqadd.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: ret <4 x i32> [[VUQADD2_I]]
int32x4_t test_vuqaddq_s32(int32x4_t a, int32x4_t b) {
return vuqaddq_s32(a, b);
@@ -1437,21 +1437,21 @@ int32x4_t test_vuqaddq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vuqaddq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VUQADD2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.suqadd.v2i64(<2 x i64> %a, <2 x i64> %b) #2
+// CHECK: [[VUQADD2_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.suqadd.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: ret <2 x i64> [[VUQADD2_I]]
int64x2_t test_vuqaddq_s64(int64x2_t a, int64x2_t b) {
return vuqaddq_s64(a, b);
}
// CHECK-LABEL: @test_vcls_s8(
-// CHECK: [[VCLS_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.cls.v8i8(<8 x i8> %a) #2
+// CHECK: [[VCLS_V_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.cls.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCLS_V_I]]
int8x8_t test_vcls_s8(int8x8_t a) {
return vcls_s8(a);
}
// CHECK-LABEL: @test_vclsq_s8(
-// CHECK: [[VCLSQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.cls.v16i8(<16 x i8> %a) #2
+// CHECK: [[VCLSQ_V_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.cls.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCLSQ_V_I]]
int8x16_t test_vclsq_s8(int8x16_t a) {
return vclsq_s8(a);
@@ -1459,7 +1459,7 @@ int8x16_t test_vclsq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vcls_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VCLS_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.cls.v4i16(<4 x i16> %a) #2
+// CHECK: [[VCLS_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.cls.v4i16(<4 x i16> %a)
// CHECK: [[VCLS_V2_I:%.*]] = bitcast <4 x i16> [[VCLS_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLS_V1_I]]
int16x4_t test_vcls_s16(int16x4_t a) {
@@ -1468,7 +1468,7 @@ int16x4_t test_vcls_s16(int16x4_t a) {
// CHECK-LABEL: @test_vclsq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VCLSQ_V1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.cls.v8i16(<8 x i16> %a) #2
+// CHECK: [[VCLSQ_V1_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.cls.v8i16(<8 x i16> %a)
// CHECK: [[VCLSQ_V2_I:%.*]] = bitcast <8 x i16> [[VCLSQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VCLSQ_V1_I]]
int16x8_t test_vclsq_s16(int16x8_t a) {
@@ -1477,7 +1477,7 @@ int16x8_t test_vclsq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vcls_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VCLS_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.cls.v2i32(<2 x i32> %a) #2
+// CHECK: [[VCLS_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.cls.v2i32(<2 x i32> %a)
// CHECK: [[VCLS_V2_I:%.*]] = bitcast <2 x i32> [[VCLS_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLS_V1_I]]
int32x2_t test_vcls_s32(int32x2_t a) {
@@ -1486,7 +1486,7 @@ int32x2_t test_vcls_s32(int32x2_t a) {
// CHECK-LABEL: @test_vclsq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VCLSQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.cls.v4i32(<4 x i32> %a) #2
+// CHECK: [[VCLSQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.cls.v4i32(<4 x i32> %a)
// CHECK: [[VCLSQ_V2_I:%.*]] = bitcast <4 x i32> [[VCLSQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VCLSQ_V1_I]]
int32x4_t test_vclsq_s32(int32x4_t a) {
@@ -1494,14 +1494,14 @@ int32x4_t test_vclsq_s32(int32x4_t a) {
}
// CHECK-LABEL: @test_vclz_s8(
-// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false) #2
+// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false)
// CHECK: ret <8 x i8> [[VCLZ_V_I]]
int8x8_t test_vclz_s8(int8x8_t a) {
return vclz_s8(a);
}
// CHECK-LABEL: @test_vclzq_s8(
-// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false) #2
+// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false)
// CHECK: ret <16 x i8> [[VCLZQ_V_I]]
int8x16_t test_vclzq_s8(int8x16_t a) {
return vclzq_s8(a);
@@ -1509,7 +1509,7 @@ int8x16_t test_vclzq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vclz_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false) #2
+// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <4 x i16> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLZ_V1_I]]
int16x4_t test_vclz_s16(int16x4_t a) {
@@ -1518,7 +1518,7 @@ int16x4_t test_vclz_s16(int16x4_t a) {
// CHECK-LABEL: @test_vclzq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false) #2
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <8 x i16> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VCLZQ_V1_I]]
int16x8_t test_vclzq_s16(int16x8_t a) {
@@ -1527,7 +1527,7 @@ int16x8_t test_vclzq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vclz_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false) #2
+// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <2 x i32> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLZ_V1_I]]
int32x2_t test_vclz_s32(int32x2_t a) {
@@ -1536,7 +1536,7 @@ int32x2_t test_vclz_s32(int32x2_t a) {
// CHECK-LABEL: @test_vclzq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false) #2
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <4 x i32> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VCLZQ_V1_I]]
int32x4_t test_vclzq_s32(int32x4_t a) {
@@ -1544,14 +1544,14 @@ int32x4_t test_vclzq_s32(int32x4_t a) {
}
// CHECK-LABEL: @test_vclz_u8(
-// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false) #2
+// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false)
// CHECK: ret <8 x i8> [[VCLZ_V_I]]
uint8x8_t test_vclz_u8(uint8x8_t a) {
return vclz_u8(a);
}
// CHECK-LABEL: @test_vclzq_u8(
-// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false) #2
+// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false)
// CHECK: ret <16 x i8> [[VCLZQ_V_I]]
uint8x16_t test_vclzq_u8(uint8x16_t a) {
return vclzq_u8(a);
@@ -1559,7 +1559,7 @@ uint8x16_t test_vclzq_u8(uint8x16_t a) {
// CHECK-LABEL: @test_vclz_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false) #2
+// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <4 x i16> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLZ_V1_I]]
uint16x4_t test_vclz_u16(uint16x4_t a) {
@@ -1568,7 +1568,7 @@ uint16x4_t test_vclz_u16(uint16x4_t a) {
// CHECK-LABEL: @test_vclzq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false) #2
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <8 x i16> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VCLZQ_V1_I]]
uint16x8_t test_vclzq_u16(uint16x8_t a) {
@@ -1577,7 +1577,7 @@ uint16x8_t test_vclzq_u16(uint16x8_t a) {
// CHECK-LABEL: @test_vclz_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false) #2
+// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <2 x i32> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLZ_V1_I]]
uint32x2_t test_vclz_u32(uint32x2_t a) {
@@ -1586,7 +1586,7 @@ uint32x2_t test_vclz_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vclzq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false) #2
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <4 x i32> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VCLZQ_V1_I]]
uint32x4_t test_vclzq_u32(uint32x4_t a) {
@@ -1594,42 +1594,42 @@ uint32x4_t test_vclzq_u32(uint32x4_t a) {
}
// CHECK-LABEL: @test_vcnt_s8(
-// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a) #2
+// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCNT_V_I]]
int8x8_t test_vcnt_s8(int8x8_t a) {
return vcnt_s8(a);
}
// CHECK-LABEL: @test_vcntq_s8(
-// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a) #2
+// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCNTQ_V_I]]
int8x16_t test_vcntq_s8(int8x16_t a) {
return vcntq_s8(a);
}
// CHECK-LABEL: @test_vcnt_u8(
-// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a) #2
+// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCNT_V_I]]
uint8x8_t test_vcnt_u8(uint8x8_t a) {
return vcnt_u8(a);
}
// CHECK-LABEL: @test_vcntq_u8(
-// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a) #2
+// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCNTQ_V_I]]
uint8x16_t test_vcntq_u8(uint8x16_t a) {
return vcntq_u8(a);
}
// CHECK-LABEL: @test_vcnt_p8(
-// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a) #2
+// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCNT_V_I]]
poly8x8_t test_vcnt_p8(poly8x8_t a) {
return vcnt_p8(a);
}
// CHECK-LABEL: @test_vcntq_p8(
-// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a) #2
+// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCNTQ_V_I]]
poly8x16_t test_vcntq_p8(poly8x16_t a) {
return vcntq_p8(a);
@@ -1734,42 +1734,42 @@ poly8x16_t test_vmvnq_p8(poly8x16_t a) {
}
// CHECK-LABEL: @test_vrbit_s8(
-// CHECK: [[VRBIT_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rbit.v8i8(<8 x i8> %a) #2
+// CHECK: [[VRBIT_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rbit.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VRBIT_I]]
int8x8_t test_vrbit_s8(int8x8_t a) {
return vrbit_s8(a);
}
// CHECK-LABEL: @test_vrbitq_s8(
-// CHECK: [[VRBIT_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.rbit.v16i8(<16 x i8> %a) #2
+// CHECK: [[VRBIT_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.rbit.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VRBIT_I]]
int8x16_t test_vrbitq_s8(int8x16_t a) {
return vrbitq_s8(a);
}
// CHECK-LABEL: @test_vrbit_u8(
-// CHECK: [[VRBIT_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rbit.v8i8(<8 x i8> %a) #2
+// CHECK: [[VRBIT_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rbit.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VRBIT_I]]
uint8x8_t test_vrbit_u8(uint8x8_t a) {
return vrbit_u8(a);
}
// CHECK-LABEL: @test_vrbitq_u8(
-// CHECK: [[VRBIT_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.rbit.v16i8(<16 x i8> %a) #2
+// CHECK: [[VRBIT_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.rbit.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VRBIT_I]]
uint8x16_t test_vrbitq_u8(uint8x16_t a) {
return vrbitq_u8(a);
}
// CHECK-LABEL: @test_vrbit_p8(
-// CHECK: [[VRBIT_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rbit.v8i8(<8 x i8> %a) #2
+// CHECK: [[VRBIT_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.rbit.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VRBIT_I]]
poly8x8_t test_vrbit_p8(poly8x8_t a) {
return vrbit_p8(a);
}
// CHECK-LABEL: @test_vrbitq_p8(
-// CHECK: [[VRBIT_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.rbit.v16i8(<16 x i8> %a) #2
+// CHECK: [[VRBIT_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.rbit.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VRBIT_I]]
poly8x16_t test_vrbitq_p8(poly8x16_t a) {
return vrbitq_p8(a);
@@ -1879,7 +1879,7 @@ int32x4_t test_vmovn_high_u64(int32x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vqmovun_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtun.v8i8(<8 x i16> %a) #2
+// CHECK: [[VQMOVUN_V1_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtun.v8i8(<8 x i16> %a)
// CHECK: ret <8 x i8> [[VQMOVUN_V1_I]]
int8x8_t test_vqmovun_s16(int16x8_t a) {
return vqmovun_s16(a);
@@ -1887,7 +1887,7 @@ int8x8_t test_vqmovun_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqmovun_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> %a) #2
+// CHECK: [[VQMOVUN_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> %a)
// CHECK: [[VQMOVUN_V2_I:%.*]] = bitcast <4 x i16> [[VQMOVUN_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQMOVUN_V1_I]]
int16x4_t test_vqmovun_s32(int32x4_t a) {
@@ -1896,7 +1896,7 @@ int16x4_t test_vqmovun_s32(int32x4_t a) {
// CHECK-LABEL: @test_vqmovun_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtun.v2i32(<2 x i64> %a) #2
+// CHECK: [[VQMOVUN_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtun.v2i32(<2 x i64> %a)
// CHECK: [[VQMOVUN_V2_I:%.*]] = bitcast <2 x i32> [[VQMOVUN_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQMOVUN_V1_I]]
int32x2_t test_vqmovun_s64(int64x2_t a) {
@@ -1905,7 +1905,7 @@ int32x2_t test_vqmovun_s64(int64x2_t a) {
// CHECK-LABEL: @test_vqmovun_high_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtun.v8i8(<8 x i16> %b) #2
+// CHECK: [[VQMOVUN_V1_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtun.v8i8(<8 x i16> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> [[VQMOVUN_V1_I_I]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: ret <16 x i8> [[SHUFFLE_I_I]]
int8x16_t test_vqmovun_high_s16(int8x8_t a, int16x8_t b) {
@@ -1914,7 +1914,7 @@ int8x16_t test_vqmovun_high_s16(int8x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqmovun_high_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> %b) #2
+// CHECK: [[VQMOVUN_V1_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtun.v4i16(<4 x i32> %b)
// CHECK: [[VQMOVUN_V2_I_I:%.*]] = bitcast <4 x i16> [[VQMOVUN_V1_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> %a, <4 x i16> [[VQMOVUN_V1_I_I]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
// CHECK: ret <8 x i16> [[SHUFFLE_I_I]]
@@ -1924,7 +1924,7 @@ int16x8_t test_vqmovun_high_s32(int16x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqmovun_high_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtun.v2i32(<2 x i64> %b) #2
+// CHECK: [[VQMOVUN_V1_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtun.v2i32(<2 x i64> %b)
// CHECK: [[VQMOVUN_V2_I_I:%.*]] = bitcast <2 x i32> [[VQMOVUN_V1_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> %a, <2 x i32> [[VQMOVUN_V1_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x i32> [[SHUFFLE_I_I]]
@@ -1934,7 +1934,7 @@ int32x4_t test_vqmovun_high_s64(int32x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vqmovn_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtn.v8i8(<8 x i16> %a) #2
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtn.v8i8(<8 x i16> %a)
// CHECK: ret <8 x i8> [[VQMOVN_V1_I]]
int8x8_t test_vqmovn_s16(int16x8_t a) {
return vqmovn_s16(a);
@@ -1942,7 +1942,7 @@ int8x8_t test_vqmovn_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqmovn_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %a) #2
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <4 x i16> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQMOVN_V1_I]]
int16x4_t test_vqmovn_s32(int32x4_t a) {
@@ -1951,7 +1951,7 @@ int16x4_t test_vqmovn_s32(int32x4_t a) {
// CHECK-LABEL: @test_vqmovn_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtn.v2i32(<2 x i64> %a) #2
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtn.v2i32(<2 x i64> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <2 x i32> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQMOVN_V1_I]]
int32x2_t test_vqmovn_s64(int64x2_t a) {
@@ -1960,7 +1960,7 @@ int32x2_t test_vqmovn_s64(int64x2_t a) {
// CHECK-LABEL: @test_vqmovn_high_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtn.v8i8(<8 x i16> %b) #2
+// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.sqxtn.v8i8(<8 x i16> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> [[VQMOVN_V1_I_I]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: ret <16 x i8> [[SHUFFLE_I_I]]
int8x16_t test_vqmovn_high_s16(int8x8_t a, int16x8_t b) {
@@ -1969,7 +1969,7 @@ int8x16_t test_vqmovn_high_s16(int8x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqmovn_high_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %b) #2
+// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqxtn.v4i16(<4 x i32> %b)
// CHECK: [[VQMOVN_V2_I_I:%.*]] = bitcast <4 x i16> [[VQMOVN_V1_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> %a, <4 x i16> [[VQMOVN_V1_I_I]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
// CHECK: ret <8 x i16> [[SHUFFLE_I_I]]
@@ -1979,7 +1979,7 @@ int16x8_t test_vqmovn_high_s32(int16x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqmovn_high_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtn.v2i32(<2 x i64> %b) #2
+// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.sqxtn.v2i32(<2 x i64> %b)
// CHECK: [[VQMOVN_V2_I_I:%.*]] = bitcast <2 x i32> [[VQMOVN_V1_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> %a, <2 x i32> [[VQMOVN_V1_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x i32> [[SHUFFLE_I_I]]
@@ -1989,7 +1989,7 @@ int32x4_t test_vqmovn_high_s64(int32x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vqmovn_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16> %a) #2
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16> %a)
// CHECK: ret <8 x i8> [[VQMOVN_V1_I]]
uint8x8_t test_vqmovn_u16(uint16x8_t a) {
return vqmovn_u16(a);
@@ -1997,7 +1997,7 @@ uint8x8_t test_vqmovn_u16(uint16x8_t a) {
// CHECK-LABEL: @test_vqmovn_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqxtn.v4i16(<4 x i32> %a) #2
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqxtn.v4i16(<4 x i32> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <4 x i16> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQMOVN_V1_I]]
uint16x4_t test_vqmovn_u32(uint32x4_t a) {
@@ -2006,7 +2006,7 @@ uint16x4_t test_vqmovn_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vqmovn_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqxtn.v2i32(<2 x i64> %a) #2
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqxtn.v2i32(<2 x i64> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <2 x i32> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQMOVN_V1_I]]
uint32x2_t test_vqmovn_u64(uint64x2_t a) {
@@ -2015,7 +2015,7 @@ uint32x2_t test_vqmovn_u64(uint64x2_t a) {
// CHECK-LABEL: @test_vqmovn_high_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16> %b) #2
+// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.uqxtn.v8i8(<8 x i16> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> [[VQMOVN_V1_I_I]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
// CHECK: ret <16 x i8> [[SHUFFLE_I_I]]
uint8x16_t test_vqmovn_high_u16(uint8x8_t a, uint16x8_t b) {
@@ -2024,7 +2024,7 @@ uint8x16_t test_vqmovn_high_u16(uint8x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vqmovn_high_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqxtn.v4i16(<4 x i32> %b) #2
+// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.uqxtn.v4i16(<4 x i32> %b)
// CHECK: [[VQMOVN_V2_I_I:%.*]] = bitcast <4 x i16> [[VQMOVN_V1_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x i16> %a, <4 x i16> [[VQMOVN_V1_I_I]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
// CHECK: ret <8 x i16> [[SHUFFLE_I_I]]
@@ -2034,7 +2034,7 @@ uint16x8_t test_vqmovn_high_u32(uint16x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vqmovn_high_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqxtn.v2i32(<2 x i64> %b) #2
+// CHECK: [[VQMOVN_V1_I_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.uqxtn.v2i32(<2 x i64> %b)
// CHECK: [[VQMOVN_V2_I_I:%.*]] = bitcast <2 x i32> [[VQMOVN_V1_I_I]] to <8 x i8>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i32> %a, <2 x i32> [[VQMOVN_V1_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x i32> [[SHUFFLE_I_I]]
@@ -2162,7 +2162,7 @@ uint64x2_t test_vshll_high_n_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vcvt_f16_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVT_F16_F321_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2hf(<4 x float> %a) #2
+// CHECK: [[VCVT_F16_F321_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2hf(<4 x float> %a)
// CHECK: [[VCVT_F16_F322_I:%.*]] = bitcast <4 x i16> [[VCVT_F16_F321_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[VCVT_F16_F322_I]] to <4 x half>
// CHECK: ret <4 x half> [[TMP1]]
@@ -2172,7 +2172,7 @@ float16x4_t test_vcvt_f16_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvt_high_f16_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VCVT_F16_F321_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2hf(<4 x float> %b) #2
+// CHECK: [[VCVT_F16_F321_I_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2hf(<4 x float> %b)
// CHECK: [[VCVT_F16_F322_I_I:%.*]] = bitcast <4 x i16> [[VCVT_F16_F321_I_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[VCVT_F16_F322_I_I]] to <4 x half>
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x half> %a, <4 x half> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
@@ -2200,7 +2200,7 @@ float32x4_t test_vcvt_high_f32_f64(float32x2_t a, float64x2_t b) {
// CHECK-LABEL: @test_vcvtx_f32_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTX_F32_V1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fcvtxn.v2f32.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTX_F32_V1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fcvtxn.v2f32.v2f64(<2 x double> %a)
// CHECK: ret <2 x float> [[VCVTX_F32_V1_I]]
float32x2_t test_vcvtx_f32_f64(float64x2_t a) {
return vcvtx_f32_f64(a);
@@ -2208,7 +2208,7 @@ float32x2_t test_vcvtx_f32_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvtx_high_f32_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %b to <16 x i8>
-// CHECK: [[VCVTX_F32_V1_I_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fcvtxn.v2f32.v2f64(<2 x double> %b) #2
+// CHECK: [[VCVTX_F32_V1_I_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fcvtxn.v2f32.v2f64(<2 x double> %b)
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x float> %a, <2 x float> [[VCVTX_F32_V1_I_I]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// CHECK: ret <4 x float> [[SHUFFLE_I_I]]
float32x4_t test_vcvtx_high_f32_f64(float32x2_t a, float64x2_t b) {
@@ -2218,7 +2218,7 @@ float32x4_t test_vcvtx_high_f32_f64(float32x2_t a, float64x2_t b) {
// CHECK-LABEL: @test_vcvt_f32_f16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
// CHECK: [[VCVT_F32_F16_I:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16>
-// CHECK: [[VCVT_F32_F161_I:%.*]] = call <4 x float> @llvm.aarch64.neon.vcvthf2fp(<4 x i16> [[VCVT_F32_F16_I]]) #2
+// CHECK: [[VCVT_F32_F161_I:%.*]] = call <4 x float> @llvm.aarch64.neon.vcvthf2fp(<4 x i16> [[VCVT_F32_F16_I]])
// CHECK: [[VCVT_F32_F162_I:%.*]] = bitcast <4 x float> [[VCVT_F32_F161_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VCVT_F32_F161_I]]
float32x4_t test_vcvt_f32_f16(float16x4_t a) {
@@ -2229,7 +2229,7 @@ float32x4_t test_vcvt_f32_f16(float16x4_t a) {
// CHECK: [[SHUFFLE_I_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %a, <4 x i32> <i32 4, i32 5, i32 6, i32 7>
// CHECK: [[TMP0:%.*]] = bitcast <4 x half> [[SHUFFLE_I_I]] to <8 x i8>
// CHECK: [[VCVT_F32_F16_I_I:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16>
-// CHECK: [[VCVT_F32_F161_I_I:%.*]] = call <4 x float> @llvm.aarch64.neon.vcvthf2fp(<4 x i16> [[VCVT_F32_F16_I_I]]) #2
+// CHECK: [[VCVT_F32_F161_I_I:%.*]] = call <4 x float> @llvm.aarch64.neon.vcvthf2fp(<4 x i16> [[VCVT_F32_F16_I_I]])
// CHECK: [[VCVT_F32_F162_I_I:%.*]] = bitcast <4 x float> [[VCVT_F32_F161_I_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VCVT_F32_F161_I_I]]
float32x4_t test_vcvt_high_f32_f16(float16x8_t a) {
@@ -2255,7 +2255,7 @@ float64x2_t test_vcvt_high_f64_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndn_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRNDN1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frintn.v2f32(<2 x float> %a) #2
+// CHECK: [[VRNDN1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frintn.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRNDN1_I]]
float32x2_t test_vrndn_f32(float32x2_t a) {
return vrndn_f32(a);
@@ -2263,7 +2263,7 @@ float32x2_t test_vrndn_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrndnq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRNDN1_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frintn.v4f32(<4 x float> %a) #2
+// CHECK: [[VRNDN1_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frintn.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRNDN1_I]]
float32x4_t test_vrndnq_f32(float32x4_t a) {
return vrndnq_f32(a);
@@ -2271,7 +2271,7 @@ float32x4_t test_vrndnq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndnq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRNDN1_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frintn.v2f64(<2 x double> %a) #2
+// CHECK: [[VRNDN1_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frintn.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRNDN1_I]]
float64x2_t test_vrndnq_f64(float64x2_t a) {
return vrndnq_f64(a);
@@ -2279,7 +2279,7 @@ float64x2_t test_vrndnq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrnda_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRNDA1_I:%.*]] = call <2 x float> @llvm.round.v2f32(<2 x float> %a) #2
+// CHECK: [[VRNDA1_I:%.*]] = call <2 x float> @llvm.round.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRNDA1_I]]
float32x2_t test_vrnda_f32(float32x2_t a) {
return vrnda_f32(a);
@@ -2287,7 +2287,7 @@ float32x2_t test_vrnda_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrndaq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRNDA1_I:%.*]] = call <4 x float> @llvm.round.v4f32(<4 x float> %a) #2
+// CHECK: [[VRNDA1_I:%.*]] = call <4 x float> @llvm.round.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRNDA1_I]]
float32x4_t test_vrndaq_f32(float32x4_t a) {
return vrndaq_f32(a);
@@ -2295,7 +2295,7 @@ float32x4_t test_vrndaq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndaq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRNDA1_I:%.*]] = call <2 x double> @llvm.round.v2f64(<2 x double> %a) #2
+// CHECK: [[VRNDA1_I:%.*]] = call <2 x double> @llvm.round.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRNDA1_I]]
float64x2_t test_vrndaq_f64(float64x2_t a) {
return vrndaq_f64(a);
@@ -2303,7 +2303,7 @@ float64x2_t test_vrndaq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrndp_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRNDP1_I:%.*]] = call <2 x float> @llvm.ceil.v2f32(<2 x float> %a) #2
+// CHECK: [[VRNDP1_I:%.*]] = call <2 x float> @llvm.ceil.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRNDP1_I]]
float32x2_t test_vrndp_f32(float32x2_t a) {
return vrndp_f32(a);
@@ -2311,7 +2311,7 @@ float32x2_t test_vrndp_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrndpq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRNDP1_I:%.*]] = call <4 x float> @llvm.ceil.v4f32(<4 x float> %a) #2
+// CHECK: [[VRNDP1_I:%.*]] = call <4 x float> @llvm.ceil.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRNDP1_I]]
float32x4_t test_vrndpq_f32(float32x4_t a) {
return vrndpq_f32(a);
@@ -2319,7 +2319,7 @@ float32x4_t test_vrndpq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndpq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRNDP1_I:%.*]] = call <2 x double> @llvm.ceil.v2f64(<2 x double> %a) #2
+// CHECK: [[VRNDP1_I:%.*]] = call <2 x double> @llvm.ceil.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRNDP1_I]]
float64x2_t test_vrndpq_f64(float64x2_t a) {
return vrndpq_f64(a);
@@ -2327,7 +2327,7 @@ float64x2_t test_vrndpq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrndm_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRNDM1_I:%.*]] = call <2 x float> @llvm.floor.v2f32(<2 x float> %a) #2
+// CHECK: [[VRNDM1_I:%.*]] = call <2 x float> @llvm.floor.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRNDM1_I]]
float32x2_t test_vrndm_f32(float32x2_t a) {
return vrndm_f32(a);
@@ -2335,7 +2335,7 @@ float32x2_t test_vrndm_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrndmq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRNDM1_I:%.*]] = call <4 x float> @llvm.floor.v4f32(<4 x float> %a) #2
+// CHECK: [[VRNDM1_I:%.*]] = call <4 x float> @llvm.floor.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRNDM1_I]]
float32x4_t test_vrndmq_f32(float32x4_t a) {
return vrndmq_f32(a);
@@ -2343,7 +2343,7 @@ float32x4_t test_vrndmq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndmq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRNDM1_I:%.*]] = call <2 x double> @llvm.floor.v2f64(<2 x double> %a) #2
+// CHECK: [[VRNDM1_I:%.*]] = call <2 x double> @llvm.floor.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRNDM1_I]]
float64x2_t test_vrndmq_f64(float64x2_t a) {
return vrndmq_f64(a);
@@ -2351,7 +2351,7 @@ float64x2_t test_vrndmq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrndx_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRNDX1_I:%.*]] = call <2 x float> @llvm.rint.v2f32(<2 x float> %a) #2
+// CHECK: [[VRNDX1_I:%.*]] = call <2 x float> @llvm.rint.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRNDX1_I]]
float32x2_t test_vrndx_f32(float32x2_t a) {
return vrndx_f32(a);
@@ -2359,7 +2359,7 @@ float32x2_t test_vrndx_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrndxq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRNDX1_I:%.*]] = call <4 x float> @llvm.rint.v4f32(<4 x float> %a) #2
+// CHECK: [[VRNDX1_I:%.*]] = call <4 x float> @llvm.rint.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRNDX1_I]]
float32x4_t test_vrndxq_f32(float32x4_t a) {
return vrndxq_f32(a);
@@ -2367,7 +2367,7 @@ float32x4_t test_vrndxq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndxq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRNDX1_I:%.*]] = call <2 x double> @llvm.rint.v2f64(<2 x double> %a) #2
+// CHECK: [[VRNDX1_I:%.*]] = call <2 x double> @llvm.rint.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRNDX1_I]]
float64x2_t test_vrndxq_f64(float64x2_t a) {
return vrndxq_f64(a);
@@ -2375,7 +2375,7 @@ float64x2_t test_vrndxq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrnd_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRNDZ1_I:%.*]] = call <2 x float> @llvm.trunc.v2f32(<2 x float> %a) #2
+// CHECK: [[VRNDZ1_I:%.*]] = call <2 x float> @llvm.trunc.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRNDZ1_I]]
float32x2_t test_vrnd_f32(float32x2_t a) {
return vrnd_f32(a);
@@ -2383,7 +2383,7 @@ float32x2_t test_vrnd_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrndq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRNDZ1_I:%.*]] = call <4 x float> @llvm.trunc.v4f32(<4 x float> %a) #2
+// CHECK: [[VRNDZ1_I:%.*]] = call <4 x float> @llvm.trunc.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRNDZ1_I]]
float32x4_t test_vrndq_f32(float32x4_t a) {
return vrndq_f32(a);
@@ -2391,7 +2391,7 @@ float32x4_t test_vrndq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRNDZ1_I:%.*]] = call <2 x double> @llvm.trunc.v2f64(<2 x double> %a) #2
+// CHECK: [[VRNDZ1_I:%.*]] = call <2 x double> @llvm.trunc.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRNDZ1_I]]
float64x2_t test_vrndq_f64(float64x2_t a) {
return vrndq_f64(a);
@@ -2399,7 +2399,7 @@ float64x2_t test_vrndq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrndi_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRNDI1_I:%.*]] = call <2 x float> @llvm.nearbyint.v2f32(<2 x float> %a) #2
+// CHECK: [[VRNDI1_I:%.*]] = call <2 x float> @llvm.nearbyint.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRNDI1_I]]
float32x2_t test_vrndi_f32(float32x2_t a) {
return vrndi_f32(a);
@@ -2407,7 +2407,7 @@ float32x2_t test_vrndi_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrndiq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRNDI1_I:%.*]] = call <4 x float> @llvm.nearbyint.v4f32(<4 x float> %a) #2
+// CHECK: [[VRNDI1_I:%.*]] = call <4 x float> @llvm.nearbyint.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRNDI1_I]]
float32x4_t test_vrndiq_f32(float32x4_t a) {
return vrndiq_f32(a);
@@ -2415,7 +2415,7 @@ float32x4_t test_vrndiq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrndiq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRNDI1_I:%.*]] = call <2 x double> @llvm.nearbyint.v2f64(<2 x double> %a) #2
+// CHECK: [[VRNDI1_I:%.*]] = call <2 x double> @llvm.nearbyint.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRNDI1_I]]
float64x2_t test_vrndiq_f64(float64x2_t a) {
return vrndiq_f64(a);
@@ -2471,7 +2471,7 @@ uint64x2_t test_vcvtq_u64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvtn_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtns.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTN1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtns.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTN1_I]]
int32x2_t test_vcvtn_s32_f32(float32x2_t a) {
return vcvtn_s32_f32(a);
@@ -2479,7 +2479,7 @@ int32x2_t test_vcvtn_s32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtnq_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtns.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTN1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtns.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTN1_I]]
int32x4_t test_vcvtnq_s32_f32(float32x4_t a) {
return vcvtnq_s32_f32(a);
@@ -2487,7 +2487,7 @@ int32x4_t test_vcvtnq_s32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtnq_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtns.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTN1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtns.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTN1_I]]
int64x2_t test_vcvtnq_s64_f64(float64x2_t a) {
return vcvtnq_s64_f64(a);
@@ -2495,7 +2495,7 @@ int64x2_t test_vcvtnq_s64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvtn_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtnu.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTN1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtnu.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTN1_I]]
uint32x2_t test_vcvtn_u32_f32(float32x2_t a) {
return vcvtn_u32_f32(a);
@@ -2503,7 +2503,7 @@ uint32x2_t test_vcvtn_u32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtnq_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtnu.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTN1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtnu.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTN1_I]]
uint32x4_t test_vcvtnq_u32_f32(float32x4_t a) {
return vcvtnq_u32_f32(a);
@@ -2511,7 +2511,7 @@ uint32x4_t test_vcvtnq_u32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtnq_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTN1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtnu.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTN1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtnu.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTN1_I]]
uint64x2_t test_vcvtnq_u64_f64(float64x2_t a) {
return vcvtnq_u64_f64(a);
@@ -2519,7 +2519,7 @@ uint64x2_t test_vcvtnq_u64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvtp_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtps.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTP1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtps.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTP1_I]]
int32x2_t test_vcvtp_s32_f32(float32x2_t a) {
return vcvtp_s32_f32(a);
@@ -2527,7 +2527,7 @@ int32x2_t test_vcvtp_s32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtpq_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtps.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTP1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtps.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTP1_I]]
int32x4_t test_vcvtpq_s32_f32(float32x4_t a) {
return vcvtpq_s32_f32(a);
@@ -2535,7 +2535,7 @@ int32x4_t test_vcvtpq_s32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtpq_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtps.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTP1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtps.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTP1_I]]
int64x2_t test_vcvtpq_s64_f64(float64x2_t a) {
return vcvtpq_s64_f64(a);
@@ -2543,7 +2543,7 @@ int64x2_t test_vcvtpq_s64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvtp_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtpu.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTP1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtpu.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTP1_I]]
uint32x2_t test_vcvtp_u32_f32(float32x2_t a) {
return vcvtp_u32_f32(a);
@@ -2551,7 +2551,7 @@ uint32x2_t test_vcvtp_u32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtpq_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtpu.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTP1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtpu.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTP1_I]]
uint32x4_t test_vcvtpq_u32_f32(float32x4_t a) {
return vcvtpq_u32_f32(a);
@@ -2559,7 +2559,7 @@ uint32x4_t test_vcvtpq_u32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtpq_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTP1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtpu.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTP1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtpu.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTP1_I]]
uint64x2_t test_vcvtpq_u64_f64(float64x2_t a) {
return vcvtpq_u64_f64(a);
@@ -2567,7 +2567,7 @@ uint64x2_t test_vcvtpq_u64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvtm_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtms.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTM1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtms.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTM1_I]]
int32x2_t test_vcvtm_s32_f32(float32x2_t a) {
return vcvtm_s32_f32(a);
@@ -2575,7 +2575,7 @@ int32x2_t test_vcvtm_s32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtmq_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtms.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTM1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtms.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTM1_I]]
int32x4_t test_vcvtmq_s32_f32(float32x4_t a) {
return vcvtmq_s32_f32(a);
@@ -2583,7 +2583,7 @@ int32x4_t test_vcvtmq_s32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtmq_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtms.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTM1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtms.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTM1_I]]
int64x2_t test_vcvtmq_s64_f64(float64x2_t a) {
return vcvtmq_s64_f64(a);
@@ -2591,7 +2591,7 @@ int64x2_t test_vcvtmq_s64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvtm_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtmu.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTM1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtmu.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTM1_I]]
uint32x2_t test_vcvtm_u32_f32(float32x2_t a) {
return vcvtm_u32_f32(a);
@@ -2599,7 +2599,7 @@ uint32x2_t test_vcvtm_u32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtmq_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtmu.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTM1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtmu.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTM1_I]]
uint32x4_t test_vcvtmq_u32_f32(float32x4_t a) {
return vcvtmq_u32_f32(a);
@@ -2607,7 +2607,7 @@ uint32x4_t test_vcvtmq_u32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtmq_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTM1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtmu.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTM1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtmu.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTM1_I]]
uint64x2_t test_vcvtmq_u64_f64(float64x2_t a) {
return vcvtmq_u64_f64(a);
@@ -2615,7 +2615,7 @@ uint64x2_t test_vcvtmq_u64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvta_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtas.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTA1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtas.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTA1_I]]
int32x2_t test_vcvta_s32_f32(float32x2_t a) {
return vcvta_s32_f32(a);
@@ -2623,7 +2623,7 @@ int32x2_t test_vcvta_s32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtaq_s32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtas.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTA1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtas.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTA1_I]]
int32x4_t test_vcvtaq_s32_f32(float32x4_t a) {
return vcvtaq_s32_f32(a);
@@ -2631,7 +2631,7 @@ int32x4_t test_vcvtaq_s32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtaq_s64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtas.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTA1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtas.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTA1_I]]
int64x2_t test_vcvtaq_s64_f64(float64x2_t a) {
return vcvtaq_s64_f64(a);
@@ -2639,7 +2639,7 @@ int64x2_t test_vcvtaq_s64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vcvta_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtau.v2i32.v2f32(<2 x float> %a) #2
+// CHECK: [[VCVTA1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.fcvtau.v2i32.v2f32(<2 x float> %a)
// CHECK: ret <2 x i32> [[VCVTA1_I]]
uint32x2_t test_vcvta_u32_f32(float32x2_t a) {
return vcvta_u32_f32(a);
@@ -2647,7 +2647,7 @@ uint32x2_t test_vcvta_u32_f32(float32x2_t a) {
// CHECK-LABEL: @test_vcvtaq_u32_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtau.v4i32.v4f32(<4 x float> %a) #2
+// CHECK: [[VCVTA1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.fcvtau.v4i32.v4f32(<4 x float> %a)
// CHECK: ret <4 x i32> [[VCVTA1_I]]
uint32x4_t test_vcvtaq_u32_f32(float32x4_t a) {
return vcvtaq_u32_f32(a);
@@ -2655,7 +2655,7 @@ uint32x4_t test_vcvtaq_u32_f32(float32x4_t a) {
// CHECK-LABEL: @test_vcvtaq_u64_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VCVTA1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtau.v2i64.v2f64(<2 x double> %a) #2
+// CHECK: [[VCVTA1_I:%.*]] = call <2 x i64> @llvm.aarch64.neon.fcvtau.v2i64.v2f64(<2 x double> %a)
// CHECK: ret <2 x i64> [[VCVTA1_I]]
uint64x2_t test_vcvtaq_u64_f64(float64x2_t a) {
return vcvtaq_u64_f64(a);
@@ -2663,7 +2663,7 @@ uint64x2_t test_vcvtaq_u64_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrsqrte_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frsqrte.v2f32(<2 x float> %a) #2
+// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frsqrte.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRSQRTE_V1_I]]
float32x2_t test_vrsqrte_f32(float32x2_t a) {
return vrsqrte_f32(a);
@@ -2671,7 +2671,7 @@ float32x2_t test_vrsqrte_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrsqrteq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frsqrte.v4f32(<4 x float> %a) #2
+// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frsqrte.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRSQRTEQ_V1_I]]
float32x4_t test_vrsqrteq_f32(float32x4_t a) {
return vrsqrteq_f32(a);
@@ -2679,7 +2679,7 @@ float32x4_t test_vrsqrteq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrsqrteq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frsqrte.v2f64(<2 x double> %a) #2
+// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frsqrte.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRSQRTEQ_V1_I]]
float64x2_t test_vrsqrteq_f64(float64x2_t a) {
return vrsqrteq_f64(a);
@@ -2687,7 +2687,7 @@ float64x2_t test_vrsqrteq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrecpe_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frecpe.v2f32(<2 x float> %a) #2
+// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x float> @llvm.aarch64.neon.frecpe.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRECPE_V1_I]]
float32x2_t test_vrecpe_f32(float32x2_t a) {
return vrecpe_f32(a);
@@ -2695,7 +2695,7 @@ float32x2_t test_vrecpe_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrecpeq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frecpe.v4f32(<4 x float> %a) #2
+// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x float> @llvm.aarch64.neon.frecpe.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRECPEQ_V1_I]]
float32x4_t test_vrecpeq_f32(float32x4_t a) {
return vrecpeq_f32(a);
@@ -2703,7 +2703,7 @@ float32x4_t test_vrecpeq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrecpeq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VRECPEQ_V1_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frecpe.v2f64(<2 x double> %a) #2
+// CHECK: [[VRECPEQ_V1_I:%.*]] = call <2 x double> @llvm.aarch64.neon.frecpe.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VRECPEQ_V1_I]]
float64x2_t test_vrecpeq_f64(float64x2_t a) {
return vrecpeq_f64(a);
@@ -2711,7 +2711,7 @@ float64x2_t test_vrecpeq_f64(float64x2_t a) {
// CHECK-LABEL: @test_vrecpe_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.urecpe.v2i32(<2 x i32> %a) #2
+// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.urecpe.v2i32(<2 x i32> %a)
// CHECK: ret <2 x i32> [[VRECPE_V1_I]]
uint32x2_t test_vrecpe_u32(uint32x2_t a) {
return vrecpe_u32(a);
@@ -2719,7 +2719,7 @@ uint32x2_t test_vrecpe_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vrecpeq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.urecpe.v4i32(<4 x i32> %a) #2
+// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.urecpe.v4i32(<4 x i32> %a)
// CHECK: ret <4 x i32> [[VRECPEQ_V1_I]]
uint32x4_t test_vrecpeq_u32(uint32x4_t a) {
return vrecpeq_u32(a);
@@ -2727,7 +2727,7 @@ uint32x4_t test_vrecpeq_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vsqrt_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VSQRT_I:%.*]] = call <2 x float> @llvm.sqrt.v2f32(<2 x float> %a) #2
+// CHECK: [[VSQRT_I:%.*]] = call <2 x float> @llvm.sqrt.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VSQRT_I]]
float32x2_t test_vsqrt_f32(float32x2_t a) {
return vsqrt_f32(a);
@@ -2735,7 +2735,7 @@ float32x2_t test_vsqrt_f32(float32x2_t a) {
// CHECK-LABEL: @test_vsqrtq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VSQRT_I:%.*]] = call <4 x float> @llvm.sqrt.v4f32(<4 x float> %a) #2
+// CHECK: [[VSQRT_I:%.*]] = call <4 x float> @llvm.sqrt.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VSQRT_I]]
float32x4_t test_vsqrtq_f32(float32x4_t a) {
return vsqrtq_f32(a);
@@ -2743,7 +2743,7 @@ float32x4_t test_vsqrtq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vsqrtq_f64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8>
-// CHECK: [[VSQRT_I:%.*]] = call <2 x double> @llvm.sqrt.v2f64(<2 x double> %a) #2
+// CHECK: [[VSQRT_I:%.*]] = call <2 x double> @llvm.sqrt.v2f64(<2 x double> %a)
// CHECK: ret <2 x double> [[VSQRT_I]]
float64x2_t test_vsqrtq_f64(float64x2_t a) {
return vsqrtq_f64(a);
diff --git a/test/CodeGen/aarch64-neon-perm.c b/test/CodeGen/aarch64-neon-perm.c
index 5b8a99c993..471017a99b 100644
--- a/test/CodeGen/aarch64-neon-perm.c
+++ b/test/CodeGen/aarch64-neon-perm.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
#include <arm_neon.h>
diff --git a/test/CodeGen/aarch64-neon-scalar-copy.c b/test/CodeGen/aarch64-neon-scalar-copy.c
index 90fceb44ed..28cff5fbf3 100644
--- a/test/CodeGen/aarch64-neon-scalar-copy.c
+++ b/test/CodeGen/aarch64-neon-scalar-copy.c
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
-
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c b/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
index ac5a090fd2..e85b918d5a 100644
--- a/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
+++ b/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-cpu cyclone \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
@@ -59,7 +59,7 @@ float64x1_t test_vmul_n_f64(float64x1_t a, float64_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x float>
// CHECK: [[VGET_LANE:%.*]] = extractelement <2 x float> [[TMP1]], i32 1
-// CHECK: [[VMULXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmulx.f32(float %a, float [[VGET_LANE]]) #2
+// CHECK: [[VMULXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmulx.f32(float %a, float [[VGET_LANE]])
// CHECK: ret float [[VMULXS_F32_I]]
float32_t test_vmulxs_lane_f32(float32_t a, float32x2_t b) {
return vmulxs_lane_f32(a, b, 1);
@@ -69,7 +69,7 @@ float32_t test_vmulxs_lane_f32(float32_t a, float32x2_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x float>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <4 x float> [[TMP1]], i32 3
-// CHECK: [[VMULXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmulx.f32(float %a, float [[VGETQ_LANE]]) #2
+// CHECK: [[VMULXS_F32_I:%.*]] = call float @llvm.aarch64.neon.fmulx.f32(float %a, float [[VGETQ_LANE]])
// CHECK: ret float [[VMULXS_F32_I]]
float32_t test_vmulxs_laneq_f32(float32_t a, float32x4_t b) {
return vmulxs_laneq_f32(a, b, 3);
@@ -79,7 +79,7 @@ float32_t test_vmulxs_laneq_f32(float32_t a, float32x4_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <1 x double> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <1 x double>
// CHECK: [[VGET_LANE:%.*]] = extractelement <1 x double> [[TMP1]], i32 0
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double %a, double [[VGET_LANE]]) #2
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double %a, double [[VGET_LANE]])
// CHECK: ret double [[VMULXD_F64_I]]
float64_t test_vmulxd_lane_f64(float64_t a, float64x1_t b) {
return vmulxd_lane_f64(a, b, 0);
@@ -89,7 +89,7 @@ float64_t test_vmulxd_lane_f64(float64_t a, float64x1_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x double> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <2 x double>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <2 x double> [[TMP1]], i32 1
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double %a, double [[VGETQ_LANE]]) #2
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double %a, double [[VGETQ_LANE]])
// CHECK: ret double [[VMULXD_F64_I]]
float64_t test_vmulxd_laneq_f64(float64_t a, float64x2_t b) {
return vmulxd_laneq_f64(a, b, 1);
@@ -102,7 +102,7 @@ float64_t test_vmulxd_laneq_f64(float64_t a, float64x2_t b) {
// CHECK: [[TMP2:%.*]] = bitcast <1 x double> %b to <8 x i8>
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <1 x double>
// CHECK: [[VGET_LANE6:%.*]] = extractelement <1 x double> [[TMP3]], i32 0
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGET_LANE6]]) #2
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGET_LANE6]])
// CHECK: [[TMP4:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP4]] to <1 x double>
// CHECK: [[VSET_LANE:%.*]] = insertelement <1 x double> [[TMP5]], double [[VMULXD_F64_I]], i32 0
@@ -119,7 +119,7 @@ float64x1_t test_vmulx_lane_f64(float64x1_t a, float64x1_t b) {
// CHECK: [[TMP2:%.*]] = bitcast <2 x double> %b to <16 x i8>
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP2]] to <2 x double>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <2 x double> [[TMP3]], i32 0
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGETQ_LANE]]) #2
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGETQ_LANE]])
// CHECK: [[TMP4:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP4]] to <1 x double>
// CHECK: [[VSET_LANE:%.*]] = insertelement <1 x double> [[TMP5]], double [[VMULXD_F64_I]], i32 0
@@ -135,7 +135,7 @@ float64x1_t test_vmulx_laneq_f64_0(float64x1_t a, float64x2_t b) {
// CHECK: [[TMP2:%.*]] = bitcast <2 x double> %b to <16 x i8>
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP2]] to <2 x double>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <2 x double> [[TMP3]], i32 1
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGETQ_LANE]]) #2
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGETQ_LANE]])
// CHECK: [[TMP4:%.*]] = bitcast <1 x double> %a to <8 x i8>
// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP4]] to <1 x double>
// CHECK: [[VSET_LANE:%.*]] = insertelement <1 x double> [[TMP5]], double [[VMULXD_F64_I]], i32 0
@@ -252,7 +252,7 @@ float64x1_t test_vfms_laneq_f64(float64x1_t a, float64x1_t b, float64x2_t v) {
// CHECK: [[VGET_LANE:%.*]] = extractelement <4 x i16> [[TMP1]], i32 3
// CHECK: [[TMP2:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[VGET_LANE]], i64 0
-// CHECK: [[VQDMULLH_S16_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]]) #2
+// CHECK: [[VQDMULLH_S16_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]])
// CHECK: [[TMP4:%.*]] = extractelement <4 x i32> [[VQDMULLH_S16_I]], i64 0
// CHECK: ret i32 [[TMP4]]
int32_t test_vqdmullh_lane_s16(int16_t a, int16x4_t b) {
@@ -263,7 +263,7 @@ int32_t test_vqdmullh_lane_s16(int16_t a, int16x4_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32>
// CHECK: [[VGET_LANE:%.*]] = extractelement <2 x i32> [[TMP1]], i32 1
-// CHECK: [[VQDMULLS_S32_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %a, i32 [[VGET_LANE]]) #2
+// CHECK: [[VQDMULLS_S32_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %a, i32 [[VGET_LANE]])
// CHECK: ret i64 [[VQDMULLS_S32_I]]
int64_t test_vqdmulls_lane_s32(int32_t a, int32x2_t b) {
return vqdmulls_lane_s32(a, b, 1);
@@ -275,7 +275,7 @@ int64_t test_vqdmulls_lane_s32(int32_t a, int32x2_t b) {
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <8 x i16> [[TMP1]], i32 7
// CHECK: [[TMP2:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[VGETQ_LANE]], i64 0
-// CHECK: [[VQDMULLH_S16_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]]) #2
+// CHECK: [[VQDMULLH_S16_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.sqdmull.v4i32(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]])
// CHECK: [[TMP4:%.*]] = extractelement <4 x i32> [[VQDMULLH_S16_I]], i64 0
// CHECK: ret i32 [[TMP4]]
int32_t test_vqdmullh_laneq_s16(int16_t a, int16x8_t b) {
@@ -286,7 +286,7 @@ int32_t test_vqdmullh_laneq_s16(int16_t a, int16x8_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <4 x i32> [[TMP1]], i32 3
-// CHECK: [[VQDMULLS_S32_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %a, i32 [[VGETQ_LANE]]) #2
+// CHECK: [[VQDMULLS_S32_I:%.*]] = call i64 @llvm.aarch64.neon.sqdmulls.scalar(i32 %a, i32 [[VGETQ_LANE]])
// CHECK: ret i64 [[VQDMULLS_S32_I]]
int64_t test_vqdmulls_laneq_s32(int32_t a, int32x4_t b) {
return vqdmulls_laneq_s32(a, b, 3);
@@ -298,7 +298,7 @@ int64_t test_vqdmulls_laneq_s32(int32_t a, int32x4_t b) {
// CHECK: [[VGET_LANE:%.*]] = extractelement <4 x i16> [[TMP1]], i32 3
// CHECK: [[TMP2:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[VGET_LANE]], i64 0
-// CHECK: [[VQDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]]) #2
+// CHECK: [[VQDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]])
// CHECK: [[TMP4:%.*]] = extractelement <4 x i16> [[VQDMULHH_S16_I]], i64 0
// CHECK: ret i16 [[TMP4]]
int16_t test_vqdmulhh_lane_s16(int16_t a, int16x4_t b) {
@@ -309,7 +309,7 @@ int16_t test_vqdmulhh_lane_s16(int16_t a, int16x4_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32>
// CHECK: [[VGET_LANE:%.*]] = extractelement <2 x i32> [[TMP1]], i32 1
-// CHECK: [[VQDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqdmulh.i32(i32 %a, i32 [[VGET_LANE]]) #2
+// CHECK: [[VQDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqdmulh.i32(i32 %a, i32 [[VGET_LANE]])
// CHECK: ret i32 [[VQDMULHS_S32_I]]
int32_t test_vqdmulhs_lane_s32(int32_t a, int32x2_t b) {
return vqdmulhs_lane_s32(a, b, 1);
@@ -322,7 +322,7 @@ int32_t test_vqdmulhs_lane_s32(int32_t a, int32x2_t b) {
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <8 x i16> [[TMP1]], i32 7
// CHECK: [[TMP2:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[VGETQ_LANE]], i64 0
-// CHECK: [[VQDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]]) #2
+// CHECK: [[VQDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]])
// CHECK: [[TMP4:%.*]] = extractelement <4 x i16> [[VQDMULHH_S16_I]], i64 0
// CHECK: ret i16 [[TMP4]]
int16_t test_vqdmulhh_laneq_s16(int16_t a, int16x8_t b) {
@@ -334,7 +334,7 @@ int16_t test_vqdmulhh_laneq_s16(int16_t a, int16x8_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <4 x i32> [[TMP1]], i32 3
-// CHECK: [[VQDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqdmulh.i32(i32 %a, i32 [[VGETQ_LANE]]) #2
+// CHECK: [[VQDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqdmulh.i32(i32 %a, i32 [[VGETQ_LANE]])
// CHECK: ret i32 [[VQDMULHS_S32_I]]
int32_t test_vqdmulhs_laneq_s32(int32_t a, int32x4_t b) {
return vqdmulhs_laneq_s32(a, b, 3);
@@ -346,7 +346,7 @@ int32_t test_vqdmulhs_laneq_s32(int32_t a, int32x4_t b) {
// CHECK: [[VGET_LANE:%.*]] = extractelement <4 x i16> [[TMP1]], i32 3
// CHECK: [[TMP2:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[VGET_LANE]], i64 0
-// CHECK: [[VQRDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]]) #2
+// CHECK: [[VQRDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]])
// CHECK: [[TMP4:%.*]] = extractelement <4 x i16> [[VQRDMULHH_S16_I]], i64 0
// CHECK: ret i16 [[TMP4]]
int16_t test_vqrdmulhh_lane_s16(int16_t a, int16x4_t b) {
@@ -357,7 +357,7 @@ int16_t test_vqrdmulhh_lane_s16(int16_t a, int16x4_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <2 x i32>
// CHECK: [[VGET_LANE:%.*]] = extractelement <2 x i32> [[TMP1]], i32 1
-// CHECK: [[VQRDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 %a, i32 [[VGET_LANE]]) #2
+// CHECK: [[VQRDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 %a, i32 [[VGET_LANE]])
// CHECK: ret i32 [[VQRDMULHS_S32_I]]
int32_t test_vqrdmulhs_lane_s32(int32_t a, int32x2_t b) {
return vqrdmulhs_lane_s32(a, b, 1);
@@ -370,7 +370,7 @@ int32_t test_vqrdmulhs_lane_s32(int32_t a, int32x2_t b) {
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <8 x i16> [[TMP1]], i32 7
// CHECK: [[TMP2:%.*]] = insertelement <4 x i16> undef, i16 %a, i64 0
// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[VGETQ_LANE]], i64 0
-// CHECK: [[VQRDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]]) #2
+// CHECK: [[VQRDMULHH_S16_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.sqrdmulh.v4i16(<4 x i16> [[TMP2]], <4 x i16> [[TMP3]])
// CHECK: [[TMP4:%.*]] = extractelement <4 x i16> [[VQRDMULHH_S16_I]], i64 0
// CHECK: ret i16 [[TMP4]]
int16_t test_vqrdmulhh_laneq_s16(int16_t a, int16x8_t b) {
@@ -382,7 +382,7 @@ int16_t test_vqrdmulhh_laneq_s16(int16_t a, int16x8_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <4 x i32>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <4 x i32> [[TMP1]], i32 3
-// CHECK: [[VQRDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 %a, i32 [[VGETQ_LANE]]) #2
+// CHECK: [[VQRDMULHS_S32_I:%.*]] = call i32 @llvm.aarch64.neon.sqrdmulh.i32(i32 %a, i32 [[VGETQ_LANE]])
// CHECK: ret i32 [[VQRDMULHS_S32_I]]
int32_t test_vqrdmulhs_laneq_s32(int32_t a, int32x4_t b) {
return vqrdmulhs_laneq_s32(a, b, 3);
@@ -497,7 +497,7 @@ int64_t test_vqdmlsls_laneq_s32(int64_t a, int32_t b, int32x4_t c) {
// CHECK: [[TMP4:%.*]] = bitcast <1 x double> [[TMP1]] to <8 x i8>
// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP4]] to <1 x double>
// CHECK: [[VGET_LANE7:%.*]] = extractelement <1 x double> [[TMP5]], i32 0
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGET_LANE7]]) #2
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGET_LANE7]])
// CHECK: [[TMP6:%.*]] = bitcast <1 x double> [[TMP0]] to <8 x i8>
// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP6]] to <1 x double>
// CHECK: [[VSET_LANE:%.*]] = insertelement <1 x double> [[TMP7]], double [[VMULXD_F64_I]], i32 0
@@ -523,7 +523,7 @@ float64x1_t test_vmulx_lane_f64_0() {
// CHECK: [[TMP4:%.*]] = bitcast <2 x double> [[SHUFFLE_I]] to <16 x i8>
// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP4]] to <2 x double>
// CHECK: [[VGETQ_LANE:%.*]] = extractelement <2 x double> [[TMP5]], i32 1
-// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGETQ_LANE]]) #2
+// CHECK: [[VMULXD_F64_I:%.*]] = call double @llvm.aarch64.neon.fmulx.f64(double [[VGET_LANE]], double [[VGETQ_LANE]])
// CHECK: [[TMP6:%.*]] = bitcast <1 x double> [[TMP0]] to <8 x i8>
// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP6]] to <1 x double>
// CHECK: [[VSET_LANE:%.*]] = insertelement <1 x double> [[TMP7]], double [[VMULXD_F64_I]], i32 0
diff --git a/test/CodeGen/aarch64-neon-shifts.c b/test/CodeGen/aarch64-neon-shifts.c
index 66449f7fef..e9a679bc69 100644
--- a/test/CodeGen/aarch64-neon-shifts.c
+++ b/test/CodeGen/aarch64-neon-shifts.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -ffp-contract=fast -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -ffp-contract=fast -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/aarch64-neon-tbl.c b/test/CodeGen/aarch64-neon-tbl.c
index 0cc66453ac..28881830bf 100644
--- a/test/CodeGen/aarch64-neon-tbl.c
+++ b/test/CodeGen/aarch64-neon-tbl.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-vcombine.c b/test/CodeGen/aarch64-neon-vcombine.c
index 482463cacf..f27017404d 100644
--- a/test/CodeGen/aarch64-neon-vcombine.c
+++ b/test/CodeGen/aarch64-neon-vcombine.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -fallow-half-arguments-and-returns -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -fallow-half-arguments-and-returns -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-vget-hilo.c b/test/CodeGen/aarch64-neon-vget-hilo.c
index f66bac6a6a..cc4d46dd69 100644
--- a/test/CodeGen/aarch64-neon-vget-hilo.c
+++ b/test/CodeGen/aarch64-neon-vget-hilo.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -fallow-half-arguments-and-returns -emit-llvm -o - %s \
+// RUN: -fallow-half-arguments-and-returns -disable-O0-optnone -emit-llvm -o - %s \
// RUN: | opt -S -mem2reg | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-vget.c b/test/CodeGen/aarch64-neon-vget.c
index 87afcee9c8..ac7bc2d68a 100644
--- a/test/CodeGen/aarch64-neon-vget.c
+++ b/test/CodeGen/aarch64-neon-vget.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-apple-darwin -target-feature +neon \
-// RUN: -fallow-half-arguments-and-returns -emit-llvm -o - %s \
+// RUN: -fallow-half-arguments-and-returns -disable-O0-optnone -emit-llvm -o - %s \
// RUN: | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/aarch64-poly128.c b/test/CodeGen/aarch64-poly128.c
index 01c509035f..d33d936717 100644
--- a/test/CodeGen/aarch64-poly128.c
+++ b/test/CodeGen/aarch64-poly128.c
@@ -1,6 +1,6 @@
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -ffp-contract=fast -emit-llvm -o - %s | opt -S -mem2reg \
+// RUN: -disable-O0-optnone -ffp-contract=fast -emit-llvm -o - %s | opt -S -mem2reg \
// RUN: | FileCheck %s
// Test new aarch64 intrinsics with poly128
diff --git a/test/CodeGen/aarch64-poly64.c b/test/CodeGen/aarch64-poly64.c
index eadeda6404..3fb8048fb3 100644
--- a/test/CodeGen/aarch64-poly64.c
+++ b/test/CodeGen/aarch64-poly64.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
-// RUN: -ffp-contract=fast -emit-llvm -o - %s | opt -S -mem2reg \
+// RUN: -ffp-contract=fast -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg \
// RUN: | FileCheck %s
// Test new aarch64 intrinsics with poly64
diff --git a/test/CodeGen/aarch64-type-sizes.c b/test/CodeGen/aarch64-type-sizes.c
index ce8b51fc40..195e8968ec 100644
--- a/test/CodeGen/aarch64-type-sizes.c
+++ b/test/CodeGen/aarch64-type-sizes.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple aarch64_be-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=CHECK %s
+// RUN: %clang_cc1 -triple aarch64_be-none-linux-gnu -emit-llvm -w -o - %s | FileCheck %s
// char by definition has size 1
// CHECK: target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
diff --git a/test/CodeGen/aarch64-varargs-ms.c b/test/CodeGen/aarch64-varargs-ms.c
new file mode 100644
index 0000000000..f3ff9603c9
--- /dev/null
+++ b/test/CodeGen/aarch64-varargs-ms.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple arm64-windows-msvc -emit-llvm -o - %s | FileCheck %s
+
+#include <stdarg.h>
+
+int simple_int(va_list ap) {
+// CHECK-LABEL: define i32 @simple_int
+ return va_arg(ap, int);
+// CHECK: [[ADDR:%[a-z_0-9]+]] = bitcast i8* %argp.cur to i32*
+// CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, i32* [[ADDR]]
+// CHECK: ret i32 [[RESULT]]
+}
diff --git a/test/CodeGen/adc-builtins.c b/test/CodeGen/adc-builtins.c
index 0d8d6fa034..d41fa8f446 100644
--- a/test/CodeGen/adc-builtins.c
+++ b/test/CodeGen/adc-builtins.c
@@ -1,6 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
-
-#define __MM_MALLOC_H
+// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
#include <x86intrin.h>
diff --git a/test/CodeGen/address-safety-attr-kasan.cpp b/test/CodeGen/address-safety-attr-kasan.cpp
index 4d8333d2ff..603134db69 100644
--- a/test/CodeGen/address-safety-attr-kasan.cpp
+++ b/test/CodeGen/address-safety-attr-kasan.cpp
@@ -1,9 +1,9 @@
// Make sure the sanitize_address attribute is emitted when using both ASan and KASan.
// Also document that __attribute__((no_sanitize_address)) doesn't disable KASan instrumentation.
-/// RUN: %clang_cc1 -triple i386-unknown-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NOASAN %s
-/// RUN: %clang_cc1 -triple i386-unknown-linux -fsanitize=address -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-ASAN %s
-/// RUN: %clang_cc1 -triple i386-unknown-linux -fsanitize=kernel-address -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-KASAN %s
+/// RUN: %clang_cc1 -triple i386-unknown-linux -disable-O0-optnone -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NOASAN %s
+/// RUN: %clang_cc1 -triple i386-unknown-linux -fsanitize=address -disable-O0-optnone -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-ASAN %s
+/// RUN: %clang_cc1 -triple i386-unknown-linux -fsanitize=kernel-address -disable-O0-optnone -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-KASAN %s
int HasSanitizeAddress() {
return 1;
diff --git a/test/CodeGen/address-safety-attr.cpp b/test/CodeGen/address-safety-attr.cpp
index 60faeddbd4..9862240929 100644
--- a/test/CodeGen/address-safety-attr.cpp
+++ b/test/CodeGen/address-safety-attr.cpp
@@ -3,16 +3,16 @@ int DefinedInDifferentFile(int *a);
// RUN: echo "struct S { S(){} ~S(){} };" >> %t.extra-source.cpp
// RUN: echo "S glob_array[5];" >> %t.extra-source.cpp
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp | FileCheck -check-prefix=WITHOUT %s
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address | FileCheck -check-prefix=ASAN %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -disable-O0-optnone -emit-llvm -o - %s -include %t.extra-source.cpp | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -disable-O0-optnone -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address | FileCheck -check-prefix=ASAN %s
// RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -disable-O0-optnone -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
// The blacklist file uses regexps, so escape backslashes, which are common in
// Windows paths.
// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t.file.blacklist
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin -disable-O0-optnone -emit-llvm -o - %s -include %t.extra-source.cpp -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
// The sanitize_address attribute should be attached to functions
// when AddressSanitizer is enabled, unless no_sanitize_address attribute
diff --git a/test/CodeGen/address-space.c b/test/CodeGen/address-space.c
index 61deb26253..28b3954ab7 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,X86,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,AMDGIZ,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,13 @@ 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
+// X86: load i32 addrspace(2)*, i32 addrspace(2)** @B
+// AMDGIZ: load i32 addrspace(2)*, i32 addrspace(2)** addrspacecast (i32 addrspace(2)* addrspace(1)* @B to i32 addrspace(2)**)
+// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* addrspacecast (i32 addrspace(2)* addrspace(1)* @B to i32 addrspace(2)* addrspace(4)*)
// CHECK: load i32, i32 addrspace(2)*
-// CHECK: load i32 addrspace(2)*, i32 addrspace(2)** @A
+// X86: load i32 addrspace(2)*, i32 addrspace(2)** @A
+// AMDGIZ: load i32 addrspace(2)*, i32 addrspace(2)** addrspacecast (i32 addrspace(2)* addrspace(1)* @A to i32 addrspace(2)**)
+// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* addrspacecast (i32 addrspace(2)* addrspace(1)* @A to i32 addrspace(2)* addrspace(4)*)
// CHECK: store i32 {{.*}}, i32 addrspace(2)*
void test3() {
*A = *B;
@@ -33,8 +42,10 @@ typedef struct {
} MyStruct;
// CHECK-LABEL: define void @test4(
-// CHECK: call void @llvm.memcpy.p0i8.p2i8
-// CHECK: call void @llvm.memcpy.p2i8.p0i8
+// GIZ: call void @llvm.memcpy.p0i8.p2i8
+// GIZ: call void @llvm.memcpy.p2i8.p0i8
+// PIZ: call void @llvm.memcpy.p4i8.p2i8
+// PIZ: call void @llvm.memcpy.p2i8.p4i8
void test4(MyStruct __attribute__((address_space(2))) *pPtr) {
MyStruct s = pPtr[0];
pPtr[0] = s;
diff --git a/test/CodeGen/alloc-align-attr.c b/test/CodeGen/alloc-align-attr.c
new file mode 100644
index 0000000000..b7cfcf76d4
--- /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 1e503f0579..1c98b6874d 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-ct.c b/test/CodeGen/altivec-ct.c
new file mode 100644
index 0000000000..1a3e14dc1f
--- /dev/null
+++ b/test/CodeGen/altivec-ct.c
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -S -O0 -o - %s -target-feature +altivec -target-feature +vsx | FileCheck %s -check-prefix=CHECK -check-prefix=VSX
+// RUN: %clang_cc1 -triple powerpc-linux-gnu -S -O0 -o - %s -target-feature +altivec -target-feature -vsx | FileCheck %s
+
+// REQUIRES: powerpc-registered-target
+
+#include <altivec.h>
+
+// CHECK-LABEL: test1
+// CHECK: vcfsx
+vector float test1(vector int x) {
+ return vec_ctf(x, 0);
+}
+
+// CHECK-LABEL: test2
+// CHECK: vcfux
+vector float test2(vector unsigned int x) {
+ return vec_ctf(x, 0);
+}
+
+#ifdef __VSX__
+// VSX-LABEL: test3
+vector double test3(vector signed long long x) {
+ return vec_ctf(x, 0);
+}
+
+// VSX-LABEL: test4
+vector double test4(vector unsigned long long x) {
+ return vec_ctf(x, 0);
+}
+#endif
+
+// CHECK-LABEL: test5
+// CHECK: vcfsx
+vector float test5(vector int x) {
+ return vec_vcfsx(x, 0);
+}
+
+// CHECK-LABEL: test6
+// CHECK: vcfux
+vector float test6(vector unsigned int x) {
+ return vec_vcfux(x, 0);
+}
+
+// CHECK-LABEL: test7
+// CHECK: vctsxs
+vector int test7(vector float x) {
+ return vec_cts(x, 0);
+}
+
+#ifdef __VSX__
+// VSX-LABEL: test8
+vector signed long long test8(vector double x) {
+ return vec_cts(x, 0);
+}
+
+#endif
+
+// CHECK-LABEL: test9
+// CHECK: vctsxs
+vector int test9(vector float x) {
+ return vec_vctsxs(x, 0);
+}
+
+// CHECK-LABEL: test10
+// CHECK: vctuxs
+vector unsigned test10(vector float x) {
+ return vec_ctu(x, 0);
+}
+
+#ifdef __VSX__
+// VSX-LABEL: test11
+vector unsigned long long test11(vector double x) {
+ return vec_ctu(x, 0);
+}
+
+#endif
+
+// CHECK-LABEL: test12
+// CHECK: vctuxs
+vector unsigned test12(vector float x) {
+ return vec_vctuxs(x, 0);
+}
diff --git a/test/CodeGen/altivec.c b/test/CodeGen/altivec.c
index 29823031b5..a4d38fa23b 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/arm-crc32.c b/test/CodeGen/arm-crc32.c
index 8a70d8c78a..c9aa549cbb 100644
--- a/test/CodeGen/arm-crc32.c
+++ b/test/CodeGen/arm-crc32.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple armv8-none-linux-gnueabi \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
int crc32b(int a, char b)
{
diff --git a/test/CodeGen/arm-execute-only.c b/test/CodeGen/arm-execute-only.c
new file mode 100644
index 0000000000..6d88ff611d
--- /dev/null
+++ b/test/CodeGen/arm-execute-only.c
@@ -0,0 +1,78 @@
+// RUN: %clang -target armv6t2-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv6t2-eabi -### -mexecute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv6t2-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv7m-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv7m-eabi -### -mexecute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv7m-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.base-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.base-eabi -### -mexecute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.base-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.main-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.main-eabi -### -mexecute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.main-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+
+// -mpure-code flag for GCC compatibility
+// RUN: %clang -target armv6t2-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv6t2-eabi -### -mpure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv6t2-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv7m-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv7m-eabi -### -mpure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv7m-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.base-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.base-eabi -### -mpure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.base-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.main-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.main-eabi -### -mpure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
+
+// RUN: %clang -target armv8m.main-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
+
+// CHECK-NO-EXECUTE-ONLY-NOT: "+execute-only"
+// CHECK-EXECUTE-ONLY: "+execute-only"
+
+void a() {}
diff --git a/test/CodeGen/arm-float-helpers.c b/test/CodeGen/arm-float-helpers.c
new file mode 100644
index 0000000000..30363304bc
--- /dev/null
+++ b/test/CodeGen/arm-float-helpers.c
@@ -0,0 +1,233 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabihf %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi -target-feature "+soft-float" -target-feature "+soft-float-abi" %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi -target-feature "+soft-float" %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-eabi %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-eabi -meabi gnu %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-eabi %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-eabi -target-feature "+soft-float" -target-feature "+soft-float-abi" -meabi gnu %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-eabi -target-feature "+soft-float" -meabi gnu %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-eabihf %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-eabihf -meabi gnu %s | FileCheck %s
+
+// The Runtime ABI for the ARM Architecture IHI0043 section 4.1.2 The
+// floating-point helper functions to always use the base AAPCS (soft-float)
+// calling convention.
+//
+// These helper functions such as __aeabi_fadd are not explicitly called by
+// clang, instead they are generated by the ARMISelLowering when they are
+// needed; clang relies on llvm to use the base AAPCS.
+//
+// In this test we check that clang is not directly calling the __aeabi_
+// functions. We rely on llvm to test that the base AAPCS is used for any
+// __aeabi_ function from 4.1.2 that is used.
+//
+// When compiled to an object file with -mfloat-abi=soft each function F
+// below should result in a call to __aeabi_F. If clang is changed to call any
+// of these functions directly the test will need to be altered to check that
+// arm_aapcscc is used.
+//
+// Note that it is only the functions in 4.1.2 that must use the base AAPCS,
+// other runtime functions such as the _Complex helper routines are not covered.
+
+float fadd(float a, float b) { return a + b; }
+// CHECK-LABEL: define float @fadd(float %a, float %b)
+// CHECK-NOT: __aeabi_fadd
+// CHECK: %add = fadd float {{.*}}, {{.*}}
+
+float fdiv(float a, float b) { return a / b; }
+// CHECK-LABEL: define float @fdiv(float %a, float %b)
+// CHECK-NOT: __aeabi_fdiv
+// CHECK: %div = fdiv float {{.*}}, {{.*}}
+
+float fmul(float a, float b) { return a * b; }
+// CHECK-LABEL: define float @fmul(float %a, float %b)
+// CHECK-NOT: __aeabi_fmul
+// CHECK: %mul = fmul float {{.*}}, {{.*}}
+
+float fsub(float a, float b) { return a - b; }
+// CHECK-LABEL: define float @fsub(float %a, float %b)
+// CHECK-NOT: __aeabi_fsub
+// CHECK: %sub = fsub float {{.*}}, {{.*}}
+
+int fcmpeq(float a, float b) { return a == b; }
+// CHECK-LABEL: define i32 @fcmpeq(float %a, float %b)
+// CHECK-NOT: __aeabi_fcmpeq
+// CHECK: %cmp = fcmp oeq float {{.*}}, {{.*}}
+
+int fcmplt(float a, float b) { return a < b; }
+// CHECK-LABEL: define i32 @fcmplt(float %a, float %b)
+// CHECK-NOT: __aeabi_fcmplt
+// CHECK: %cmp = fcmp olt float {{.*}}, {{.*}}
+
+int fcmple(float a, float b) { return a <= b; }
+// CHECK-LABEL: define i32 @fcmple(float %a, float %b)
+// CHECK-NOT: __aeabi_fcmple
+// CHECK: %cmp = fcmp ole float {{.*}}, {{.*}}
+
+int fcmpge(float a, float b) { return a >= b; }
+// CHECK-LABEL: define i32 @fcmpge(float %a, float %b)
+// CHECK-NOT: __aeabi_fcmpge
+// CHECK: %cmp = fcmp oge float {{.*}}, {{.*}}
+
+int fcmpgt(float a, float b) { return a > b; }
+// CHECK-LABEL: define i32 @fcmpgt(float %a, float %b)
+// CHECK-NOT: __aeabi_fcmpgt
+// CHECK: %cmp = fcmp ogt float {{.*}}, {{.*}}
+
+int fcmpun(float a, float b) { return __builtin_isunordered(a, b); }
+// CHECK-LABEL: define i32 @fcmpun(float %a, float %b)
+// CHECK-NOT: __aeabi_fcmpun
+// CHECK: %cmp = fcmp uno double %conv, %conv1
+
+double dadd(double a, double b) { return a + b; }
+// CHECK-LABEL: define double @dadd(double %a, double %b)
+// CHECK-NOT: __aeabi_dadd
+// CHECK: %add = fadd double {{.*}}, {{.*}}
+
+double ddiv(double a, double b) { return a / b; }
+// CHECK-LABEL: define double @ddiv(double %a, double %b)
+// CHECK-NOT: __aeabi_ddiv
+// CHECK: %div = fdiv double {{.*}}, {{.*}}
+
+double dmul(double a, double b) { return a * b; }
+// CHECK-LABEL: define double @dmul(double %a, double %b)
+// CHECK-NOT: __aeabi_dmul
+// CHECK: %mul = fmul double {{.*}}, {{.*}}
+
+double dsub(double a, double b) { return a - b; }
+// CHECK-LABEL: define double @dsub(double %a, double %b)
+// CHECK-NOT: __aeabi_dsub
+// CHECK: %sub = fsub double {{.*}}, {{.*}}
+
+int dcmpeq(double a, double b) { return a == b; }
+// CHECK-LABEL: define i32 @dcmpeq(double %a, double %b)
+// CHECK-NOT: __aeabi_dcmpeq
+// CHECK: %cmp = fcmp oeq double {{.*}}, {{.*}}
+
+int dcmplt(double a, double b) { return a < b; }
+// CHECK-LABEL: define i32 @dcmplt(double %a, double %b)
+// CHECK-NOT: __aeabi_dcmplt
+// CHECK: %cmp = fcmp olt double {{.*}}, {{.*}}
+
+int dcmple(double a, double b) { return a <= b; }
+// CHECK-LABEL: define i32 @dcmple(double %a, double %b)
+// CHECK-NOT: __aeabi_dcmple
+// CHECK: %cmp = fcmp ole double {{.*}}, {{.*}}
+
+int dcmpge(double a, double b) { return a >= b; }
+// CHECK-LABEL: define i32 @dcmpge(double %a, double %b)
+// CHECK-NOT: __aeabi_dcmpge
+// CHECK: %cmp = fcmp oge double {{.*}}, {{.*}}
+
+int dcmpgt(double a, double b) { return a > b; }
+// CHECK-LABEL: define i32 @dcmpgt(double %a, double %b)
+// CHECK-NOT: __aeabi_dcmpgt
+// CHECK: %cmp = fcmp ogt double {{.*}}, {{.*}}
+
+int dcmpun(double a, double b) { return __builtin_isunordered(a, b); }
+// CHECK-LABEL: define i32 @dcmpun(double %a, double %b)
+// CHECK-NOT: __aeabi_dcmpun
+// CHECK: %cmp = fcmp uno double {{.*}}, {{.*}}
+
+int d2iz(double a) { return (int)a; }
+// CHECK-LABEL: define i32 @d2iz(double %a)
+// CHECK-NOT: __aeabi_d2iz
+// CHECK: %conv = fptosi double {{.*}} to i32
+
+unsigned int d2uiz(double a) { return (unsigned int)a; }
+// CHECK-LABEL: define i32 @d2uiz(double %a)
+// CHECK-NOT: __aeabi_d2uiz
+// CHECK: %conv = fptoui double {{.*}} to i32
+
+long long d2lz(double a) { return (long long)a; }
+// CHECK-LABEL: define i64 @d2lz(double %a)
+// CHECK-NOT: __aeabi_d2lz
+// CHECK: %conv = fptosi double {{.*}} to i64
+
+unsigned long long d2ulz(double a) { return (unsigned long long)a; }
+// CHECK-LABEL: define i64 @d2ulz(double %a)
+// CHECK-NOT: __aeabi_d2ulz
+// CHECK: %conv = fptoui double {{.*}} to i64
+
+int f2iz(float a) { return (int)a; }
+// CHECK-LABEL: define i32 @f2iz(float %a)
+// CHECK-NOT: __aeabi_f2iz
+// CHECK: %conv = fptosi float {{.*}} to i32
+
+unsigned int f2uiz(float a) { return (unsigned int)a; }
+// CHECK-LABEL: define i32 @f2uiz(float %a)
+// CHECK-NOT: __aeabi_f2uiz
+// CHECK: %conv = fptoui float {{.*}} to i32
+
+long long f2lz(float a) { return (long long)a; }
+// CHECK-LABEL: define i64 @f2lz(float %a)
+// CHECK-NOT: __aeabi_f2lz
+// CHECK: %conv = fptosi float {{.*}} to i64
+
+unsigned long long f2ulz(float a) { return (unsigned long long)a; }
+// CHECK-LABEL: define i64 @f2ulz(float %a)
+// CHECK-NOT: __aeabi_f2ulz
+// CHECK: %conv = fptoui float {{.*}} to i64
+
+float d2f(double a) { return (float)a; }
+// CHECK-LABEL: define float @d2f(double %a)
+// CHECK-NOT: __aeabi_d2f
+// CHECK: %conv = fptrunc double {{.*}} to float
+
+double f2d(float a) { return (double)a; }
+// CHECK-LABEL: define double @f2d(float %a)
+// CHECK-NOT: __aeabi_f2d
+// CHECK: %conv = fpext float {{.*}} to double
+
+double i2d(int a) { return (double)a; }
+// CHECK-LABEL: define double @i2d(i32 %a)
+// CHECK-NOT: __aeabi_i2d
+// CHECK: %conv = sitofp i32 {{.*}} to double
+
+double ui2d(unsigned int a) { return (double)a; }
+// CHECK-LABEL: define double @ui2d(i32 %a)
+// CHECK-NOT: __aeabi_ui2d
+// CHECK: %conv = uitofp i32 {{.*}} to double
+
+double l2d(long long a) { return (double)a; }
+// CHECK-LABEL: define double @l2d(i64 %a)
+// CHECK-NOT: __aeabi_l2d
+// CHECK: %conv = sitofp i64 {{.*}} to double
+
+double ul2d(unsigned long long a) { return (unsigned long long)a; }
+// CHECK-LABEL: define double @ul2d(i64 %a)
+// CHECK-NOT: __aeabi_ul2d
+// CHECK: %conv = uitofp i64 {{.*}} to double
+
+float i2f(int a) { return (int)a; }
+// CHECK-LABEL: define float @i2f(i32 %a)
+// CHECK-NOT: __aeabi_i2f
+// CHECK: %conv = sitofp i32 {{.*}} to float
+
+float ui2f(unsigned int a) { return (unsigned int)a; }
+// CHECK-LABEL: define float @ui2f(i32 %a)
+// CHECK-NOT: __aeabi_ui2f
+// CHECK: %conv = uitofp i32 {{.*}} to float
+
+float l2f(long long a) { return (long long)a; }
+// CHECK-LABEL: define float @l2f(i64 %a)
+// CHECK-NOT: __aeabi_l2f
+// CHECK: %conv = sitofp i64 {{.*}} to float
+
+float ul2f(unsigned long long a) { return (unsigned long long)a; }
+// CHECK-LABEL: define float @ul2f(i64 %a)
+// CHECK-NOT: __aeabi_ul2f
+// CHECK: %conv = uitofp i64 {{.*}} to float
+
+// Functions in section 4.1.2 not used by llvm and don't easily map directly to
+// C source code.
+// cfcmpeq
+// cfcmple
+// cfrcmple
+// cdcmpeq
+// cdcmple
+// cdrcmple
+// frsub
+// drsub
diff --git a/test/CodeGen/arm-long-calls.c b/test/CodeGen/arm-long-calls.c
index fdd7babe9f..cff2d66071 100644
--- a/test/CodeGen/arm-long-calls.c
+++ b/test/CodeGen/arm-long-calls.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple thumbv7-apple-ios5 -target-feature +long-calls -emit-llvm -o - %s | FileCheck -check-prefix=LONGCALL %s
// RUN: %clang_cc1 -triple thumbv7-apple-ios5 -emit-llvm -o - %s | FileCheck -check-prefix=NOLONGCALL %s
-// LONGCALL: attributes #0 = { {{.*}} "target-features"="+long-calls"
-// NOLONGCALL-NOT: attributes #0 = { {{.*}} "target-features"="+long-calls"
+// LONGCALL: attributes #0 = { {{.*}} "target-features"="+long-calls,+thumb-mode"
+// NOLONGCALL-NOT: attributes #0 = { {{.*}} "target-features"="+long-calls,+thumb-mode"
int foo1(int a) { return a; }
diff --git a/test/CodeGen/arm-metadata.c b/test/CodeGen/arm-metadata.c
index 1f7756cc8d..4f3e2dba21 100644
--- a/test/CodeGen/arm-metadata.c
+++ b/test/CodeGen/arm-metadata.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s | FileCheck -check-prefix=DEFAULT %s
// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s -fshort-enums | FileCheck -check-prefix=SHORT-ENUM %s
-// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s -fshort-wchar | FileCheck -check-prefix=SHORT-WCHAR %s
+// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s -fwchar-type=short -fno-signed-wchar | FileCheck -check-prefix=SHORT-WCHAR %s
// DEFAULT: !{{[0-9]+}} = !{i32 1, !"wchar_size", i32 4}
// DEFAULT: !{{[0-9]+}} = !{i32 1, !"min_enum_size", i32 4}
diff --git a/test/CodeGen/arm-neon-directed-rounding.c b/test/CodeGen/arm-neon-directed-rounding.c
index 7471b1c230..b06808a77c 100644
--- a/test/CodeGen/arm-neon-directed-rounding.c
+++ b/test/CodeGen/arm-neon-directed-rounding.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -emit-llvm %s -o - | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -disable-O0-optnone -emit-llvm %s -o - | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm-neon-fma.c b/test/CodeGen/arm-neon-fma.c
index 9311f6be68..b5184c195e 100644
--- a/test/CodeGen/arm-neon-fma.c
+++ b/test/CodeGen/arm-neon-fma.c
@@ -3,7 +3,7 @@
// RUN: -target-cpu cortex-a7 \
// RUN: -mfloat-abi hard \
// RUN: -ffreestanding \
-// RUN: -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm-neon-numeric-maxmin.c b/test/CodeGen/arm-neon-numeric-maxmin.c
index 38f020a756..d4f5674cd9 100644
--- a/test/CodeGen/arm-neon-numeric-maxmin.c
+++ b/test/CodeGen/arm-neon-numeric-maxmin.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -emit-llvm %s -o - | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -disable-O0-optnone -emit-llvm %s -o - | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm-neon-shifts.c b/test/CodeGen/arm-neon-shifts.c
index ebaa97fe38..ec059738ec 100644
--- a/test/CodeGen/arm-neon-shifts.c
+++ b/test/CodeGen/arm-neon-shifts.c
@@ -1,5 +1,6 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -triple thumbv7-apple-darwin \
+// RUN: -disable-O0-optnone \
// RUN: -target-cpu cortex-a8 \
// RUN: -ffreestanding \
// RUN: -emit-llvm -w -o - %s | opt -S -mem2reg | FileCheck %s
diff --git a/test/CodeGen/arm-neon-vcvtX.c b/test/CodeGen/arm-neon-vcvtX.c
index 4ea8fa874e..43d48a0a4f 100644
--- a/test/CodeGen/arm-neon-vcvtX.c
+++ b/test/CodeGen/arm-neon-vcvtX.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -emit-llvm %s -o - | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -ffreestanding -disable-O0-optnone -emit-llvm %s -o - | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm-neon-vget.c b/test/CodeGen/arm-neon-vget.c
index 3bf8905f39..841cf0396d 100644
--- a/test/CodeGen/arm-neon-vget.c
+++ b/test/CodeGen/arm-neon-vget.c
@@ -4,7 +4,7 @@
// RUN: -mfloat-abi soft \
// RUN: -target-feature +soft-float-abi \
// RUN: -ffreestanding \
-// RUN: -emit-llvm -w -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -emit-llvm -w -o - %s | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm-no-movt.c b/test/CodeGen/arm-no-movt.c
index 0773941fb3..f61f224864 100644
--- a/test/CodeGen/arm-no-movt.c
+++ b/test/CodeGen/arm-no-movt.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple thumbv7-apple-ios5 -target-feature +no-movt -emit-llvm -o - %s | FileCheck -check-prefix=NO-MOVT %s
// RUN: %clang_cc1 -triple thumbv7-apple-ios5 -emit-llvm -o - %s | FileCheck -check-prefix=MOVT %s
-// NO-MOVT: attributes #0 = { {{.*}} "target-features"="+no-movt"
-// MOVT-NOT: attributes #0 = { {{.*}} "target-features"="+no-movt"
+// NO-MOVT: attributes #0 = { {{.*}} "target-features"="+no-movt,+thumb-mode"
+// MOVT-NOT: attributes #0 = { {{.*}} "target-features"="+no-movt,+thumb-mode"
int foo1(int a) { return a; }
diff --git a/test/CodeGen/arm-swiftcall.c b/test/CodeGen/arm-swiftcall.c
index 5a7e17068b..f5c33845e2 100644
--- a/test/CodeGen/arm-swiftcall.c
+++ b/test/CodeGen/arm-swiftcall.c
@@ -57,6 +57,7 @@ SWIFTCALL void context_error_2(short s, CONTEXT int *self, ERROR float **error)
/********************************** LOWERING *********************************/
/*****************************************************************************/
+typedef float float3 __attribute__((ext_vector_type(3)));
typedef float float4 __attribute__((ext_vector_type(4)));
typedef float float8 __attribute__((ext_vector_type(8)));
typedef double double2 __attribute__((ext_vector_type(2)));
@@ -1013,3 +1014,10 @@ typedef struct {
TEST(struct_vf81)
// CHECK-LABEL: define swiftcc { <4 x float>, <4 x float> } @return_struct_vf81()
// CHECK-LABEL: define swiftcc void @take_struct_vf81(<4 x float>, <4 x float>)
+
+typedef struct {
+ float3 f3;
+} struct_v1f3;
+TEST(struct_v1f3)
+// CHECK-LABEL: define swiftcc { <2 x float>, float } @return_struct_v1f3()
+// CHECK-LABEL: define swiftcc void @take_struct_v1f3(<2 x float>, float)
diff --git a/test/CodeGen/arm-target-attr.c b/test/CodeGen/arm-target-attr.c
new file mode 100644
index 0000000000..42fe8d15aa
--- /dev/null
+++ b/test/CodeGen/arm-target-attr.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple thumb-apple-darwin -emit-llvm -o - %s | FileCheck --check-prefix CHECKPOS %s
+// RUN: %clang_cc1 -triple thumb-apple-darwin -emit-llvm -o - %s | FileCheck --check-prefix CHECKNEG %s
+// RUN: %clang_cc1 -triple arm-apple-darwin -emit-llvm -o - %s | FileCheck --check-prefix CHECKPOS %s
+// RUN: %clang_cc1 -triple arm-apple-darwin -emit-llvm -o - %s | FileCheck --check-prefix CHECKNEG %s
+
+__attribute__((target("arm"))) void test_target_arm() {
+ // CHECKPOS: define void @test_target_arm() [[ARM_ATTRS:#[0-9]+]]
+ // CHECKNEG: define void @test_target_arm() [[ARM_ATTRS:#[0-9]+]]
+}
+
+__attribute__((target("thumb"))) void test_target_thumb() {
+ // CHECKPOS: define void @test_target_thumb() [[THUMB_ATTRS:#[0-9]+]]
+ // CHECKNEG: define void @test_target_thumb() [[THUMB_ATTRS:#[0-9]+]]
+}
+
+// CHECKPOS: attributes [[ARM_ATTRS]] = { {{.*}} "target-features"="{{.*}}-thumb-mode{{.*}}"
+// CHECKPOS: attributes [[THUMB_ATTRS]] = { {{.*}} "target-features"="{{.*}}+thumb-mode{{.*}}"
+// CHECKNEG-NOT: attributes [[ARM_ATTRS]] = { {{.*}} "target-features"="{{.*}}+thumb-mode{{.*}}"
+// CHECKNEG-NOT: attributes [[THUMB_ATTRS]] = { {{.*}} "target-features"="{{.*}}-thumb-mode{{.*}}"
diff --git a/test/CodeGen/arm-target-features.c b/test/CodeGen/arm-target-features.c
index 7437fb0e4e..e5591a28ad 100644
--- a/test/CodeGen/arm-target-features.c
+++ b/test/CodeGen/arm-target-features.c
@@ -1,65 +1,63 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabihf -target-cpu cortex-a8 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP3
-// CHECK-VFP3: "target-features"="+dsp,+neon,+vfp3"
-
-
-// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-a9 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP3-FP16
-// CHECK-VFP3-FP16: "target-features"="+dsp,+fp16,+neon,+vfp3"
+// CHECK-VFP3: "target-features"="+dsp,+neon,+thumb-mode
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabihf -target-cpu cortex-a5 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4
-// CHECK-VFP4: "target-features"="+dsp,+neon,+vfp4"
+// CHECK-VFP4: "target-features"="+dsp,+neon,+thumb-mode,+vfp4"
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabihf -target-cpu cortex-a7 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-a12 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV
-// RUN: %clang_cc1 -triple armv7-linux-gnueabihf -target-cpu cortex-a15 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV
-// RUN: %clang_cc1 -triple armv7-linux-gnueabihf -target-cpu cortex-a17 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV
// RUN: %clang_cc1 -triple thumbv7s-linux-gnueabi -target-cpu swift -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabihf -target-cpu krait -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV
-// CHECK-VFP4-DIV: "target-features"="+dsp,+hwdiv,+hwdiv-arm,+neon,+vfp4"
+// CHECK-VFP4-DIV: "target-features"="+dsp,+hwdiv,+hwdiv-arm,+neon,+thumb-mode,+vfp4"
+// RUN: %clang_cc1 -triple armv7-linux-gnueabihf -target-cpu cortex-a15 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV-ARM
+// RUN: %clang_cc1 -triple armv7-linux-gnueabihf -target-cpu cortex-a17 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-DIV-ARM
+// CHECK-VFP4-DIV-ARM: "target-features"="+dsp,+hwdiv,+hwdiv-arm,+neon,+vfp4,-thumb-mode"
// RUN: %clang_cc1 -triple thumbv7s-apple-ios7.0 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a32 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a35 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
-// RUN: %clang_cc1 -triple armv8-linux-gnueabi -target-cpu cortex-a53 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a57 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a72 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu cortex-a73 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu exynos-m1 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu exynos-m2 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
// RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu exynos-m3 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8
-// CHECK-BASIC-V8: "target-features"="+crc,+crypto,+dsp,+fp-armv8,+hwdiv,+hwdiv-arm,+neon"
+// CHECK-BASIC-V8: "target-features"="+crc,+crypto,+dsp,+fp-armv8,+hwdiv,+hwdiv-arm,+neon,+thumb-mode"
+// RUN: %clang_cc1 -triple armv8-linux-gnueabi -target-cpu cortex-a53 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8-ARM
+// CHECK-BASIC-V8-ARM: "target-features"="+crc,+crypto,+dsp,+fp-armv8,+hwdiv,+hwdiv-arm,+neon,-thumb-mode"
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-r5 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP3-D16-DIV
-// CHECK-VFP3-D16-DIV: "target-features"="+d16,+dsp,+hwdiv,+hwdiv-arm,+vfp3"
+// CHECK-VFP3-D16-DIV: "target-features"="+d16,+dsp,+hwdiv,+hwdiv-arm,+thumb-mode,+vfp3"
// RUN: %clang_cc1 -triple armv7-linux-gnueabi -target-cpu cortex-r4f -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP3-D16-THUMB-DIV
-// CHECK-VFP3-D16-THUMB-DIV: "target-features"="+d16,+dsp,+hwdiv,+vfp3"
+// CHECK-VFP3-D16-THUMB-DIV: "target-features"="+d16,+dsp,+hwdiv,+vfp3,-thumb-mode"
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-r7 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP3-D16-FP16-DIV
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-r8 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP3-D16-FP16-DIV
-// CHECK-VFP3-D16-FP16-DIV: "target-features"="+d16,+dsp,+fp16,+hwdiv,+hwdiv-arm,+vfp3"
+// CHECK-VFP3-D16-FP16-DIV: "target-features"="+d16,+dsp,+fp16,+hwdiv,+hwdiv-arm,+thumb-mode,+vfp3"
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-m4 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP4-D16-SP-THUMB-DIV
-// CHECK-VFP4-D16-SP-THUMB-DIV: "target-features"="+d16,+dsp,+fp-only-sp,+hwdiv,+vfp4"
+// CHECK-VFP4-D16-SP-THUMB-DIV: "target-features"="+d16,+dsp,+fp-only-sp,+hwdiv,+thumb-mode,+vfp4"
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-m7 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-VFP5-D16-THUMB-DIV
-// CHECK-VFP5-D16-THUMB-DIV: "target-features"="+d16,+dsp,+fp-armv8,+hwdiv"
+// CHECK-VFP5-D16-THUMB-DIV: "target-features"="+d16,+dsp,+fp-armv8,+hwdiv,+thumb-mode"
// RUN: %clang_cc1 -triple armv7-linux-gnueabi -target-cpu cortex-r4 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-THUMB-DIV
-// CHECK-THUMB-DIV: "target-features"="+dsp,+hwdiv"
+// CHECK-THUMB-DIV: "target-features"="+dsp,+hwdiv,-thumb-mode"
// RUN: %clang_cc1 -triple thumbv7-linux-gnueabi -target-cpu cortex-m3 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-THUMB-DIV-M3
-// CHECK-THUMB-DIV-M3: "target-features"="+hwdiv"
+// CHECK-THUMB-DIV-M3: "target-features"="+hwdiv,+thumb-mode"
void foo() {}
diff --git a/test/CodeGen/arm-thumb-mode-target-feature.c b/test/CodeGen/arm-thumb-mode-target-feature.c
new file mode 100644
index 0000000000..5c41d0b16f
--- /dev/null
+++ b/test/CodeGen/arm-thumb-mode-target-feature.c
@@ -0,0 +1,33 @@
+// REQUIRES: arm-registered-target
+
+// RUN: %clang_cc1 -triple thumbv7-linux-gnueabihf -emit-llvm -o - %s | FileCheck --check-prefix THUMB %s
+// RUN: %clang_cc1 -triple thumbv7eb-linux-gnueabihf -emit-llvm -o - %s | FileCheck --check-prefix THUMB %s
+// RUN: %clang -target armv7-linux-gnueabihf -mthumb -S -emit-llvm -o - %s | FileCheck --check-prefix THUMB-CLANG %s
+// RUN: %clang_cc1 -triple armv7-linux-gnueabihf -emit-llvm -o - %s | FileCheck --check-prefix ARM %s
+// RUN: %clang_cc1 -triple armv7eb-linux-gnueabihf -emit-llvm -o - %s | FileCheck --check-prefix ARM %s
+
+void t1() {}
+
+ __attribute__((target("no-thumb-mode")))
+void t2() {}
+
+ __attribute__((target("thumb-mode")))
+void t3() {}
+
+// THUMB: void @t1() [[ThumbAttr:#[0-7]]]
+// THUMB: void @t2() [[NoThumbAttr:#[0-7]]]
+// THUMB: void @t3() [[ThumbAttr:#[0-7]]]
+// THUMB: attributes [[ThumbAttr]] = { {{.*}} "target-features"="+thumb-mode"
+// THUMB: attributes [[NoThumbAttr]] = { {{.*}} "target-features"="-thumb-mode"
+//
+// THUMB-CLANG: void @t1() [[ThumbAttr:#[0-7]]]
+// THUMB-CLANG: void @t2() [[NoThumbAttr:#[0-7]]]
+// THUMB-CLANG: void @t3() [[ThumbAttr:#[0-7]]]
+// THUMB-CLANG: attributes [[ThumbAttr]] = { {{.*}} "target-features"="{{.*}}+thumb-mode
+// THUMB-CLANG: attributes [[NoThumbAttr]] = { {{.*}} "target-features"="{{.*}}-thumb-mode
+
+// ARM: void @t1() [[NoThumbAtr:#[0-7]]]
+// ARM: void @t2() [[NoThumbAttr:#[0-7]]]
+// ARM: void @t3() [[ThumbAttr:#[0-7]]]
+// ARM: attributes [[NoThumbAttr]] = { {{.*}} "target-features"="-thumb-mode"
+// ARM: attributes [[ThumbAttr]] = { {{.*}} "target-features"="+thumb-mode"
diff --git a/test/CodeGen/arm-v8.1a-neon-intrinsics.c b/test/CodeGen/arm-v8.1a-neon-intrinsics.c
index 7888831004..6f5867b6c1 100644
--- a/test/CodeGen/arm-v8.1a-neon-intrinsics.c
+++ b/test/CodeGen/arm-v8.1a-neon-intrinsics.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple armv8.1a-linux-gnu -target-feature +neon \
+// RUN: %clang_cc1 -triple armv8.1a-linux-gnu -target-abi apcs-gnu -target-feature +neon \
// RUN: -S -emit-llvm -o - %s \
// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
diff --git a/test/CodeGen/arm64-crc32.c b/test/CodeGen/arm64-crc32.c
index efb51ed407..2d913fb123 100644
--- a/test/CodeGen/arm64-crc32.c
+++ b/test/CodeGen/arm64-crc32.c
@@ -1,6 +1,6 @@
// REQUIRES: aarch64-registered-target
// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
-// RUN: -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: -disable-O0-optnone -S -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
int crc32b(int a, char b)
{
diff --git a/test/CodeGen/arm64-lanes.c b/test/CodeGen/arm64-lanes.c
index ea47bae69f..fde5f848b9 100644
--- a/test/CodeGen/arm64-lanes.c
+++ b/test/CodeGen/arm64-lanes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
-// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -target-feature +neon -ffreestanding -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s --check-prefix CHECK-BE
+// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -target-feature +neon -ffreestanding -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s --check-prefix CHECK-BE
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64-microsoft-intrinsics.c b/test/CodeGen/arm64-microsoft-intrinsics.c
new file mode 100644
index 0000000000..ff802e7f9b
--- /dev/null
+++ b/test/CodeGen/arm64-microsoft-intrinsics.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple arm64-windows -fms-compatibility -emit-llvm -o - %s \
+// RUN: | FileCheck %s -check-prefix CHECK-MSVC
+
+// RUN: not %clang_cc1 -triple arm64-linux -Werror -S -o /dev/null %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-LINUX
+
+void check__dmb(void) {
+ __dmb(0);
+}
+
+// CHECK-MSVC: @llvm.aarch64.dmb(i32 0)
+// CHECK-LINUX: error: implicit declaration of function '__dmb'
+
+void check__dsb(void) {
+ __dsb(0);
+}
+
+// CHECK-MSVC: @llvm.aarch64.dsb(i32 0)
+// CHECK-LINUX: error: implicit declaration of function '__dsb'
+
+void check__isb(void) {
+ __isb(0);
+}
+
+// CHECK-MSVC: @llvm.aarch64.isb(i32 0)
+// CHECK-LINUX: error: implicit declaration of function '__isb'
diff --git a/test/CodeGen/arm64_vcopy.c b/test/CodeGen/arm64_vcopy.c
index 4c0143016f..fc2ad3746b 100644
--- a/test/CodeGen/arm64_vcopy.c
+++ b/test/CodeGen/arm64_vcopy.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -disable-O0-optnone -emit-llvm %s | opt -S -mem2reg | FileCheck %s
// Test ARM64 SIMD copy vector element to vector element: vcopyq_lane*
diff --git a/test/CodeGen/arm64_vdupq_n_f64.c b/test/CodeGen/arm64_vdupq_n_f64.c
index 58cc7f020e..e9e814e92a 100644
--- a/test/CodeGen/arm64_vdupq_n_f64.c
+++ b/test/CodeGen/arm64_vdupq_n_f64.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -fallow-half-arguments-and-returns -S -o - -emit-llvm %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -fallow-half-arguments-and-returns -S -o - -disable-O0-optnone -emit-llvm %s | opt -S -mem2reg | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm_acle.c b/test/CodeGen/arm_acle.c
index b4f39bef15..7c8a5aa8ad 100644
--- a/test/CodeGen/arm_acle.c
+++ b/test/CodeGen/arm_acle.c
@@ -76,7 +76,7 @@ void test_dbg(void) {
// AArch32: call i32 @llvm.arm.strex
// AArch64: call i64 @llvm.aarch64.ldxr
// AArch64: call i32 @llvm.aarch64.stxr
-uint32_t test_swp(uint32_t x, volatile void *p) {
+void test_swp(uint32_t x, volatile void *p) {
__swp(x, p);
}
@@ -118,6 +118,7 @@ void test_nop(void) {
}
/* 9 DATA-PROCESSING INTRINSICS */
+
/* 9.2 Miscellaneous data-processing intrinsics */
// ARM-LABEL: test_ror
// ARM: lshr
@@ -266,8 +267,7 @@ uint64_t test_rbitll(uint64_t t) {
}
/* 9.4 Saturating intrinsics */
-#ifdef __ARM_32BIT_STATE
-
+#ifdef __ARM_FEATURE_SAT
/* 9.4.1 Width-specified saturation intrinsics */
// AArch32-LABEL: test_ssat
// AArch32: call i32 @llvm.arm.ssat(i32 %t, i32 1)
@@ -277,11 +277,13 @@ int32_t test_ssat(int32_t t) {
// AArch32-LABEL: test_usat
// AArch32: call i32 @llvm.arm.usat(i32 %t, i32 2)
-int32_t test_usat(int32_t t) {
+uint32_t test_usat(int32_t t) {
return __usat(t, 2);
}
+#endif
/* 9.4.2 Saturating addition and subtraction intrinsics */
+#ifdef __ARM_FEATURE_DSP
// AArch32-LABEL: test_qadd
// AArch32: call i32 @llvm.arm.qadd(i32 %a, i32 %b)
int32_t test_qadd(int32_t a, int32_t b) {
@@ -304,6 +306,389 @@ int32_t test_qdbl() {
}
#endif
+/*
+ * 9.3 16-bit multiplications
+ */
+#if __ARM_FEATURE_DSP
+// AArch32-LABEL: test_smulbb
+// AArch32: call i32 @llvm.arm.smulbb
+int32_t test_smulbb(int32_t a, int32_t b) {
+ return __smulbb(a, b);
+}
+// AArch32-LABEL: test_smulbt
+// AArch32: call i32 @llvm.arm.smulbt
+int32_t test_smulbt(int32_t a, int32_t b) {
+ return __smulbt(a, b);
+}
+// AArch32-LABEL: test_smultb
+// AArch32: call i32 @llvm.arm.smultb
+int32_t test_smultb(int32_t a, int32_t b) {
+ return __smultb(a, b);
+}
+// AArch32-LABEL: test_smultt
+// AArch32: call i32 @llvm.arm.smultt
+int32_t test_smultt(int32_t a, int32_t b) {
+ return __smultt(a, b);
+}
+// AArch32-LABEL: test_smulwb
+// AArch32: call i32 @llvm.arm.smulwb
+int32_t test_smulwb(int32_t a, int32_t b) {
+ return __smulwb(a, b);
+}
+// AArch32-LABEL: test_smulwt
+// AArch32: call i32 @llvm.arm.smulwt
+int32_t test_smulwt(int32_t a, int32_t b) {
+ return __smulwt(a, b);
+}
+#endif
+
+/* 9.4.3 Accumultating multiplications */
+#if __ARM_FEATURE_DSP
+// AArch32-LABEL: test_smlabb
+// AArch32: call i32 @llvm.arm.smlabb(i32 %a, i32 %b, i32 %c)
+int32_t test_smlabb(int32_t a, int32_t b, int32_t c) {
+ return __smlabb(a, b, c);
+}
+// AArch32-LABEL: test_smlabt
+// AArch32: call i32 @llvm.arm.smlabt(i32 %a, i32 %b, i32 %c)
+int32_t test_smlabt(int32_t a, int32_t b, int32_t c) {
+ return __smlabt(a, b, c);
+}
+// AArch32-LABEL: test_smlatb
+// AArch32: call i32 @llvm.arm.smlatb(i32 %a, i32 %b, i32 %c)
+int32_t test_smlatb(int32_t a, int32_t b, int32_t c) {
+ return __smlatb(a, b, c);
+}
+// AArch32-LABEL: test_smlatt
+// AArch32: call i32 @llvm.arm.smlatt(i32 %a, i32 %b, i32 %c)
+int32_t test_smlatt(int32_t a, int32_t b, int32_t c) {
+ return __smlatt(a, b, c);
+}
+// AArch32-LABEL: test_smlawb
+// AArch32: call i32 @llvm.arm.smlawb(i32 %a, i32 %b, i32 %c)
+int32_t test_smlawb(int32_t a, int32_t b, int32_t c) {
+ return __smlawb(a, b, c);
+}
+// AArch32-LABEL: test_smlawt
+// AArch32: call i32 @llvm.arm.smlawt(i32 %a, i32 %b, i32 %c)
+int32_t test_smlawt(int32_t a, int32_t b, int32_t c) {
+ return __smlawt(a, b, c);
+}
+#endif
+
+/* 9.5.4 Parallel 16-bit saturation */
+#if __ARM_FEATURE_SIMD32
+// AArch32-LABEL: test_ssat16
+// AArch32: call i32 @llvm.arm.ssat16
+int16x2_t test_ssat16(int16x2_t a) {
+ return __ssat16(a, 15);
+}
+// AArch32-LABEL: test_usat16
+// AArch32: call i32 @llvm.arm.usat16
+uint16x2_t test_usat16(int16x2_t a) {
+ return __usat16(a, 15);
+}
+#endif
+
+/* 9.5.5 Packing and unpacking */
+#if __ARM_FEATURE_SIMD32
+// AArch32-LABEL: test_sxtab16
+// AArch32: call i32 @llvm.arm.sxtab16
+int16x2_t test_sxtab16(int16x2_t a, int8x4_t b) {
+ return __sxtab16(a, b);
+}
+// AArch32-LABEL: test_sxtb16
+// AArch32: call i32 @llvm.arm.sxtb16
+int16x2_t test_sxtb16(int8x4_t a) {
+ return __sxtb16(a);
+}
+// AArch32-LABEL: test_uxtab16
+// AArch32: call i32 @llvm.arm.uxtab16
+int16x2_t test_uxtab16(int16x2_t a, int8x4_t b) {
+ return __uxtab16(a, b);
+}
+// AArch32-LABEL: test_uxtb16
+// AArch32: call i32 @llvm.arm.uxtb16
+int16x2_t test_uxtb16(int8x4_t a) {
+ return __uxtb16(a);
+}
+#endif
+
+/* 9.5.6 Parallel selection */
+#if __ARM_FEATURE_SIMD32
+// AArch32-LABEL: test_sel
+// AArch32: call i32 @llvm.arm.sel
+uint8x4_t test_sel(uint8x4_t a, uint8x4_t b) {
+ return __sel(a, b);
+}
+#endif
+
+/* 9.5.7 Parallel 8-bit addition and subtraction */
+#if __ARM_FEATURE_SIMD32
+// AArch32-LABEL: test_qadd8
+// AArch32: call i32 @llvm.arm.qadd8
+int16x2_t test_qadd8(int8x4_t a, int8x4_t b) {
+ return __qadd8(a, b);
+}
+// AArch32-LABEL: test_qsub8
+// AArch32: call i32 @llvm.arm.qsub8
+int8x4_t test_qsub8(int8x4_t a, int8x4_t b) {
+ return __qsub8(a, b);
+}
+// AArch32-LABEL: test_sadd8
+// AArch32: call i32 @llvm.arm.sadd8
+int8x4_t test_sadd8(int8x4_t a, int8x4_t b) {
+ return __sadd8(a, b);
+}
+// AArch32-LABEL: test_shadd8
+// AArch32: call i32 @llvm.arm.shadd8
+int8x4_t test_shadd8(int8x4_t a, int8x4_t b) {
+ return __shadd8(a, b);
+}
+// AArch32-LABEL: test_shsub8
+// AArch32: call i32 @llvm.arm.shsub8
+int8x4_t test_shsub8(int8x4_t a, int8x4_t b) {
+ return __shsub8(a, b);
+}
+// AArch32-LABEL: test_ssub8
+// AArch32: call i32 @llvm.arm.ssub8
+int8x4_t test_ssub8(int8x4_t a, int8x4_t b) {
+ return __ssub8(a, b);
+}
+// AArch32-LABEL: test_uadd8
+// AArch32: call i32 @llvm.arm.uadd8
+uint8x4_t test_uadd8(uint8x4_t a, uint8x4_t b) {
+ return __uadd8(a, b);
+}
+// AArch32-LABEL: test_uhadd8
+// AArch32: call i32 @llvm.arm.uhadd8
+uint8x4_t test_uhadd8(uint8x4_t a, uint8x4_t b) {
+ return __uhadd8(a, b);
+}
+// AArch32-LABEL: test_uhsub8
+// AArch32: call i32 @llvm.arm.uhsub8
+uint8x4_t test_uhsub8(uint8x4_t a, uint8x4_t b) {
+ return __uhsub8(a, b);
+}
+// AArch32-LABEL: test_uqadd8
+// AArch32: call i32 @llvm.arm.uqadd8
+uint8x4_t test_uqadd8(uint8x4_t a, uint8x4_t b) {
+ return __uqadd8(a, b);
+}
+// AArch32-LABEL: test_uqsub8
+// AArch32: call i32 @llvm.arm.uqsub8
+uint8x4_t test_uqsub8(uint8x4_t a, uint8x4_t b) {
+ return __uqsub8(a, b);
+}
+// AArch32-LABEL: test_usub8
+// AArch32: call i32 @llvm.arm.usub8
+uint8x4_t test_usub8(uint8x4_t a, uint8x4_t b) {
+ return __usub8(a, b);
+}
+#endif
+
+/* 9.5.8 Sum of 8-bit absolute differences */
+#if __ARM_FEATURE_SIMD32
+// AArch32-LABEL: test_usad8
+// AArch32: call i32 @llvm.arm.usad8
+uint32_t test_usad8(uint8x4_t a, uint8x4_t b) {
+ return __usad8(a, b);
+}
+// AArch32-LABEL: test_usada8
+// AArch32: call i32 @llvm.arm.usada8
+uint32_t test_usada8(uint8_t a, uint8_t b, uint8_t c) {
+ return __usada8(a, b, c);
+}
+#endif
+
+/* 9.5.9 Parallel 16-bit addition and subtraction */
+#if __ARM_FEATURE_SIMD32
+// AArch32-LABEL: test_qadd16
+// AArch32: call i32 @llvm.arm.qadd16
+int16x2_t test_qadd16(int16x2_t a, int16x2_t b) {
+ return __qadd16(a, b);
+}
+// AArch32-LABEL: test_qasx
+// AArch32: call i32 @llvm.arm.qasx
+int16x2_t test_qasx(int16x2_t a, int16x2_t b) {
+ return __qasx(a, b);
+}
+// AArch32-LABEL: test_qsax
+// AArch32: call i32 @llvm.arm.qsax
+int16x2_t test_qsax(int16x2_t a, int16x2_t b) {
+ return __qsax(a, b);
+}
+// AArch32-LABEL: test_qsub16
+// AArch32: call i32 @llvm.arm.qsub16
+int16x2_t test_qsub16(int16x2_t a, int16x2_t b) {
+ return __qsub16(a, b);
+}
+// AArch32-LABEL: test_sadd16
+// AArch32: call i32 @llvm.arm.sadd16
+int16x2_t test_sadd16(int16x2_t a, int16x2_t b) {
+ return __sadd16(a, b);
+}
+// AArch32-LABEL: test_sasx
+// AArch32: call i32 @llvm.arm.sasx
+int16x2_t test_sasx(int16x2_t a, int16x2_t b) {
+ return __sasx(a, b);
+}
+// AArch32-LABEL: test_shadd16
+// AArch32: call i32 @llvm.arm.shadd16
+int16x2_t test_shadd16(int16x2_t a, int16x2_t b) {
+ return __shadd16(a, b);
+}
+// AArch32-LABEL: test_shasx
+// AArch32: call i32 @llvm.arm.shasx
+int16x2_t test_shasx(int16x2_t a, int16x2_t b) {
+ return __shasx(a, b);
+}
+// AArch32-LABEL: test_shsax
+// AArch32: call i32 @llvm.arm.shsax
+int16x2_t test_shsax(int16x2_t a, int16x2_t b) {
+ return __shsax(a, b);
+}
+// AArch32-LABEL: test_shsub16
+// AArch32: call i32 @llvm.arm.shsub16
+int16x2_t test_shsub16(int16x2_t a, int16x2_t b) {
+ return __shsub16(a, b);
+}
+// AArch32-LABEL: test_ssax
+// AArch32: call i32 @llvm.arm.ssax
+int16x2_t test_ssax(int16x2_t a, int16x2_t b) {
+ return __ssax(a, b);
+}
+// AArch32-LABEL: test_ssub16
+// AArch32: call i32 @llvm.arm.ssub16
+int16x2_t test_ssub16(int16x2_t a, int16x2_t b) {
+ return __ssub16(a, b);
+}
+// AArch32-LABEL: test_uadd16
+// AArch32: call i32 @llvm.arm.uadd16
+uint16x2_t test_uadd16(uint16x2_t a, uint16x2_t b) {
+ return __uadd16(a, b);
+}
+// AArch32-LABEL: test_uasx
+// AArch32: call i32 @llvm.arm.uasx
+uint16x2_t test_uasx(uint16x2_t a, uint16x2_t b) {
+ return __uasx(a, b);
+}
+// AArch32-LABEL: test_uhadd16
+// AArch32: call i32 @llvm.arm.uhadd16
+uint16x2_t test_uhadd16(uint16x2_t a, uint16x2_t b) {
+ return __uhadd16(a, b);
+}
+// AArch32-LABEL: test_uhasx
+// AArch32: call i32 @llvm.arm.uhasx
+uint16x2_t test_uhasx(uint16x2_t a, uint16x2_t b) {
+ return __uhasx(a, b);
+}
+// AArch32-LABEL: test_uhsax
+// AArch32: call i32 @llvm.arm.uhsax
+uint16x2_t test_uhsax(uint16x2_t a, uint16x2_t b) {
+ return __uhsax(a, b);
+}
+// AArch32-LABEL: test_uhsub16
+// AArch32: call i32 @llvm.arm.uhsub16
+uint16x2_t test_uhsub16(uint16x2_t a, uint16x2_t b) {
+ return __uhsub16(a, b);
+}
+// AArch32-LABEL: test_uqadd16
+// AArch32: call i32 @llvm.arm.uqadd16
+uint16x2_t test_uqadd16(uint16x2_t a, uint16x2_t b) {
+ return __uqadd16(a, b);
+}
+// AArch32-LABEL: test_uqasx
+// AArch32: call i32 @llvm.arm.uqasx
+uint16x2_t test_uqasx(uint16x2_t a, uint16x2_t b) {
+ return __uqasx(a, b);
+}
+// AArch32-LABEL: test_uqsax
+// AArch32: call i32 @llvm.arm.uqsax
+uint16x2_t test_uqsax(uint16x2_t a, uint16x2_t b) {
+ return __uqsax(a, b);
+}
+// AArch32-LABEL: test_uqsub16
+// AArch32: call i32 @llvm.arm.uqsub16
+uint16x2_t test_uqsub16(uint16x2_t a, uint16x2_t b) {
+ return __uqsub16(a, b);
+}
+// AArch32-LABEL: test_usax
+// AArch32: call i32 @llvm.arm.usax
+uint16x2_t test_usax(uint16x2_t a, uint16x2_t b) {
+ return __usax(a, b);
+}
+// AArch32-LABEL: test_usub16
+// AArch32: call i32 @llvm.arm.usub16
+uint16x2_t test_usub16(uint16x2_t a, uint16x2_t b) {
+ return __usub16(a, b);
+}
+#endif
+
+/* 9.5.10 Parallel 16-bit multiplications */
+#if __ARM_FEATURE_SIMD32
+// AArch32-LABEL: test_smlad
+// AArch32: call i32 @llvm.arm.smlad
+int32_t test_smlad(int16x2_t a, int16x2_t b, int32_t c) {
+ return __smlad(a, b, c);
+}
+// AArch32-LABEL: test_smladx
+// AArch32: call i32 @llvm.arm.smladx
+int32_t test_smladx(int16x2_t a, int16x2_t b, int32_t c) {
+ return __smladx(a, b, c);
+}
+// AArch32-LABEL: test_smlald
+// AArch32: call i64 @llvm.arm.smlald
+int64_t test_smlald(int16x2_t a, int16x2_t b, int64_t c) {
+ return __smlald(a, b, c);
+}
+// AArch32-LABEL: test_smlaldx
+// AArch32: call i64 @llvm.arm.smlaldx
+int64_t test_smlaldx(int16x2_t a, int16x2_t b, int64_t c) {
+ return __smlaldx(a, b, c);
+}
+// AArch32-LABEL: test_smlsd
+// AArch32: call i32 @llvm.arm.smlsd
+int32_t test_smlsd(int16x2_t a, int16x2_t b, int32_t c) {
+ return __smlsd(a, b, c);
+}
+// AArch32-LABEL: test_smlsdx
+// AArch32: call i32 @llvm.arm.smlsdx
+int32_t test_smlsdx(int16x2_t a, int16x2_t b, int32_t c) {
+ return __smlsdx(a, b, c);
+}
+// AArch32-LABEL: test_smlsld
+// AArch32: call i64 @llvm.arm.smlsld
+int64_t test_smlsld(int16x2_t a, int16x2_t b, int64_t c) {
+ return __smlsld(a, b, c);
+}
+// AArch32-LABEL: test_smlsldx
+// AArch32: call i64 @llvm.arm.smlsldx
+int64_t test_smlsldx(int16x2_t a, int16x2_t b, int64_t c) {
+ return __smlsldx(a, b, c);
+}
+// AArch32-LABEL: test_smuad
+// AArch32: call i32 @llvm.arm.smuad
+int32_t test_smuad(int16x2_t a, int16x2_t b) {
+ return __smuad(a, b);
+}
+// AArch32-LABEL: test_smuadx
+// AArch32: call i32 @llvm.arm.smuadx
+int32_t test_smuadx(int16x2_t a, int16x2_t b) {
+ return __smuadx(a, b);
+}
+// AArch32-LABEL: test_smusd
+// AArch32: call i32 @llvm.arm.smusd
+int32_t test_smusd(int16x2_t a, int16x2_t b) {
+ return __smusd(a, b);
+}
+// AArch32-LABEL: test_smusdx
+// AArch32: call i32 @llvm.arm.smusdx
+int32_t test_smusdx(int16x2_t a, int16x2_t b) {
+ return __smusdx(a, b);
+}
+#endif
+
/* 9.7 CRC32 intrinsics */
// ARM-LABEL: test_crc32b
// AArch32: call i32 @llvm.arm.crc32b
diff --git a/test/CodeGen/arm_neon_intrinsics.c b/test/CodeGen/arm_neon_intrinsics.c
index ad8587b0db..62888dd733 100644
--- a/test/CodeGen/arm_neon_intrinsics.c
+++ b/test/CodeGen/arm_neon_intrinsics.c
@@ -1,13 +1,12 @@
// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi apcs-gnu\
-// RUN: -target-cpu swift -fallow-half-arguments-and-returns -ffreestanding -emit-llvm -o - %s \
+// RUN: -target-cpu swift -fallow-half-arguments-and-returns -ffreestanding \
+// RUN: -disable-O0-optnone -emit-llvm -o - %s \
// RUN: | opt -S -mem2reg | FileCheck %s
-// REQUIRES: long-tests
-
#include <arm_neon.h>
// CHECK-LABEL: @test_vaba_s8(
-// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <8 x i8> %a, [[VABD_V_I_I]]
// CHECK: ret <8 x i8> [[ADD_I]]
int8x8_t test_vaba_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
@@ -17,7 +16,7 @@ int8x8_t test_vaba_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
// CHECK-LABEL: @test_vaba_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[ADD_I:%.*]] = add <4 x i16> %a, [[VABD_V2_I_I]]
// CHECK: ret <4 x i16> [[ADD_I]]
@@ -28,7 +27,7 @@ int16x4_t test_vaba_s16(int16x4_t a, int16x4_t b, int16x4_t c) {
// CHECK-LABEL: @test_vaba_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[ADD_I:%.*]] = add <2 x i32> %a, [[VABD_V2_I_I]]
// CHECK: ret <2 x i32> [[ADD_I]]
@@ -37,7 +36,7 @@ int32x2_t test_vaba_s32(int32x2_t a, int32x2_t b, int32x2_t c) {
}
// CHECK-LABEL: @test_vaba_u8(
-// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <8 x i8> %a, [[VABD_V_I_I]]
// CHECK: ret <8 x i8> [[ADD_I]]
uint8x8_t test_vaba_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
@@ -47,7 +46,7 @@ uint8x8_t test_vaba_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK-LABEL: @test_vaba_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[ADD_I:%.*]] = add <4 x i16> %a, [[VABD_V2_I_I]]
// CHECK: ret <4 x i16> [[ADD_I]]
@@ -58,7 +57,7 @@ uint16x4_t test_vaba_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK-LABEL: @test_vaba_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[ADD_I:%.*]] = add <2 x i32> %a, [[VABD_V2_I_I]]
// CHECK: ret <2 x i32> [[ADD_I]]
@@ -67,7 +66,7 @@ uint32x2_t test_vaba_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
}
// CHECK-LABEL: @test_vabaq_s8(
-// CHECK: [[VABDQ_V_I_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabds.v16i8(<16 x i8> %b, <16 x i8> %c) #4
+// CHECK: [[VABDQ_V_I_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabds.v16i8(<16 x i8> %b, <16 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <16 x i8> %a, [[VABDQ_V_I_I]]
// CHECK: ret <16 x i8> [[ADD_I]]
int8x16_t test_vabaq_s8(int8x16_t a, int8x16_t b, int8x16_t c) {
@@ -77,7 +76,7 @@ int8x16_t test_vabaq_s8(int8x16_t a, int8x16_t b, int8x16_t c) {
// CHECK-LABEL: @test_vabaq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %c to <16 x i8>
-// CHECK: [[VABDQ_V2_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabds.v8i16(<8 x i16> %b, <8 x i16> %c) #4
+// CHECK: [[VABDQ_V2_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabds.v8i16(<8 x i16> %b, <8 x i16> %c)
// CHECK: [[VABDQ_V3_I_I:%.*]] = bitcast <8 x i16> [[VABDQ_V2_I_I]] to <16 x i8>
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VABDQ_V2_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
@@ -88,7 +87,7 @@ int16x8_t test_vabaq_s16(int16x8_t a, int16x8_t b, int16x8_t c) {
// CHECK-LABEL: @test_vabaq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %c to <16 x i8>
-// CHECK: [[VABDQ_V2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabds.v4i32(<4 x i32> %b, <4 x i32> %c) #4
+// CHECK: [[VABDQ_V2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabds.v4i32(<4 x i32> %b, <4 x i32> %c)
// CHECK: [[VABDQ_V3_I_I:%.*]] = bitcast <4 x i32> [[VABDQ_V2_I_I]] to <16 x i8>
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VABDQ_V2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
@@ -97,7 +96,7 @@ int32x4_t test_vabaq_s32(int32x4_t a, int32x4_t b, int32x4_t c) {
}
// CHECK-LABEL: @test_vabaq_u8(
-// CHECK: [[VABDQ_V_I_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabdu.v16i8(<16 x i8> %b, <16 x i8> %c) #4
+// CHECK: [[VABDQ_V_I_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabdu.v16i8(<16 x i8> %b, <16 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <16 x i8> %a, [[VABDQ_V_I_I]]
// CHECK: ret <16 x i8> [[ADD_I]]
uint8x16_t test_vabaq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
@@ -107,7 +106,7 @@ uint8x16_t test_vabaq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
// CHECK-LABEL: @test_vabaq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %c to <16 x i8>
-// CHECK: [[VABDQ_V2_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabdu.v8i16(<8 x i16> %b, <8 x i16> %c) #4
+// CHECK: [[VABDQ_V2_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabdu.v8i16(<8 x i16> %b, <8 x i16> %c)
// CHECK: [[VABDQ_V3_I_I:%.*]] = bitcast <8 x i16> [[VABDQ_V2_I_I]] to <16 x i8>
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VABDQ_V2_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
@@ -118,7 +117,7 @@ uint16x8_t test_vabaq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c) {
// CHECK-LABEL: @test_vabaq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %b to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %c to <16 x i8>
-// CHECK: [[VABDQ_V2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabdu.v4i32(<4 x i32> %b, <4 x i32> %c) #4
+// CHECK: [[VABDQ_V2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabdu.v4i32(<4 x i32> %b, <4 x i32> %c)
// CHECK: [[VABDQ_V3_I_I:%.*]] = bitcast <4 x i32> [[VABDQ_V2_I_I]] to <16 x i8>
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VABDQ_V2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
@@ -127,7 +126,7 @@ uint32x4_t test_vabaq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
}
// CHECK-LABEL: @test_vabal_s8(
-// CHECK: [[VABD_V_I_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VABD_V_I_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <8 x i8> [[VABD_V_I_I_I]] to <8 x i16>
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMOVL_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
@@ -138,7 +137,7 @@ int16x8_t test_vabal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
// CHECK-LABEL: @test_vabal_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VABD_V2_I_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[VABD_V3_I_I_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <4 x i16> [[VABD_V2_I_I_I]] to <4 x i32>
@@ -151,7 +150,7 @@ int32x4_t test_vabal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK-LABEL: @test_vabal_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VABD_V2_I_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[VABD_V3_I_I_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <2 x i32> [[VABD_V2_I_I_I]] to <2 x i64>
@@ -162,7 +161,7 @@ int64x2_t test_vabal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
}
// CHECK-LABEL: @test_vabal_u8(
-// CHECK: [[VABD_V_I_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VABD_V_I_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <8 x i8> [[VABD_V_I_I_I]] to <8 x i16>
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMOVL_I_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
@@ -173,7 +172,7 @@ uint16x8_t test_vabal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK-LABEL: @test_vabal_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VABD_V2_I_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[VABD_V3_I_I_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <4 x i16> [[VABD_V2_I_I_I]] to <4 x i32>
@@ -186,7 +185,7 @@ uint32x4_t test_vabal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK-LABEL: @test_vabal_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VABD_V2_I_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VABD_V2_I_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[VABD_V3_I_I_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I_I:%.*]] = zext <2 x i32> [[VABD_V2_I_I_I]] to <2 x i64>
@@ -197,7 +196,7 @@ uint64x2_t test_vabal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
}
// CHECK-LABEL: @test_vabd_s8(
-// CHECK: [[VABD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VABD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VABD_V_I]]
int8x8_t test_vabd_s8(int8x8_t a, int8x8_t b) {
return vabd_s8(a, b);
@@ -206,7 +205,7 @@ int8x8_t test_vabd_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vabd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VABD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VABD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VABD_V3_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VABD_V2_I]]
int16x4_t test_vabd_s16(int16x4_t a, int16x4_t b) {
@@ -216,7 +215,7 @@ int16x4_t test_vabd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vabd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VABD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VABD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VABD_V3_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VABD_V2_I]]
int32x2_t test_vabd_s32(int32x2_t a, int32x2_t b) {
@@ -224,7 +223,7 @@ int32x2_t test_vabd_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vabd_u8(
-// CHECK: [[VABD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VABD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VABD_V_I]]
uint8x8_t test_vabd_u8(uint8x8_t a, uint8x8_t b) {
return vabd_u8(a, b);
@@ -233,7 +232,7 @@ uint8x8_t test_vabd_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vabd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VABD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VABD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VABD_V3_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VABD_V2_I]]
uint16x4_t test_vabd_u16(uint16x4_t a, uint16x4_t b) {
@@ -243,7 +242,7 @@ uint16x4_t test_vabd_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vabd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VABD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VABD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VABD_V3_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VABD_V2_I]]
uint32x2_t test_vabd_u32(uint32x2_t a, uint32x2_t b) {
@@ -253,7 +252,7 @@ uint32x2_t test_vabd_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vabd_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VABD_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vabds.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VABD_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vabds.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VABD_V3_I:%.*]] = bitcast <2 x float> [[VABD_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VABD_V2_I]]
float32x2_t test_vabd_f32(float32x2_t a, float32x2_t b) {
@@ -261,7 +260,7 @@ float32x2_t test_vabd_f32(float32x2_t a, float32x2_t b) {
}
// CHECK-LABEL: @test_vabdq_s8(
-// CHECK: [[VABDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabds.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VABDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabds.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VABDQ_V_I]]
int8x16_t test_vabdq_s8(int8x16_t a, int8x16_t b) {
return vabdq_s8(a, b);
@@ -270,7 +269,7 @@ int8x16_t test_vabdq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vabdq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VABDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabds.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VABDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabds.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VABDQ_V3_I:%.*]] = bitcast <8 x i16> [[VABDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VABDQ_V2_I]]
int16x8_t test_vabdq_s16(int16x8_t a, int16x8_t b) {
@@ -280,7 +279,7 @@ int16x8_t test_vabdq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vabdq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VABDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabds.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VABDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabds.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VABDQ_V3_I:%.*]] = bitcast <4 x i32> [[VABDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VABDQ_V2_I]]
int32x4_t test_vabdq_s32(int32x4_t a, int32x4_t b) {
@@ -288,7 +287,7 @@ int32x4_t test_vabdq_s32(int32x4_t a, int32x4_t b) {
}
// CHECK-LABEL: @test_vabdq_u8(
-// CHECK: [[VABDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabdu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VABDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabdu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VABDQ_V_I]]
uint8x16_t test_vabdq_u8(uint8x16_t a, uint8x16_t b) {
return vabdq_u8(a, b);
@@ -297,7 +296,7 @@ uint8x16_t test_vabdq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vabdq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VABDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabdu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VABDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabdu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VABDQ_V3_I:%.*]] = bitcast <8 x i16> [[VABDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VABDQ_V2_I]]
uint16x8_t test_vabdq_u16(uint16x8_t a, uint16x8_t b) {
@@ -307,7 +306,7 @@ uint16x8_t test_vabdq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vabdq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VABDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabdu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VABDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabdu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VABDQ_V3_I:%.*]] = bitcast <4 x i32> [[VABDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VABDQ_V2_I]]
uint32x4_t test_vabdq_u32(uint32x4_t a, uint32x4_t b) {
@@ -317,7 +316,7 @@ uint32x4_t test_vabdq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vabdq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VABDQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vabds.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VABDQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vabds.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: [[VABDQ_V3_I:%.*]] = bitcast <4 x float> [[VABDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VABDQ_V2_I]]
float32x4_t test_vabdq_f32(float32x4_t a, float32x4_t b) {
@@ -325,7 +324,7 @@ float32x4_t test_vabdq_f32(float32x4_t a, float32x4_t b) {
}
// CHECK-LABEL: @test_vabdl_s8(
-// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabds.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: [[VMOVL_I_I:%.*]] = zext <8 x i8> [[VABD_V_I_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[VMOVL_I_I]]
int16x8_t test_vabdl_s8(int8x8_t a, int8x8_t b) {
@@ -335,7 +334,7 @@ int16x8_t test_vabdl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vabdl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabds.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <4 x i16> [[VABD_V2_I_I]] to <4 x i32>
@@ -347,7 +346,7 @@ int32x4_t test_vabdl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vabdl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabds.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <2 x i32> [[VABD_V2_I_I]] to <2 x i64>
@@ -357,7 +356,7 @@ int64x2_t test_vabdl_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vabdl_u8(
-// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VABD_V_I_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabdu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: [[VMOVL_I_I:%.*]] = zext <8 x i8> [[VABD_V_I_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[VMOVL_I_I]]
uint16x8_t test_vabdl_u8(uint8x8_t a, uint8x8_t b) {
@@ -367,7 +366,7 @@ uint16x8_t test_vabdl_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vabdl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabdu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <4 x i16> [[VABD_V2_I_I]] to <4 x i32>
@@ -379,7 +378,7 @@ uint32x4_t test_vabdl_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vabdl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VABD_V2_I_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabdu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VABD_V3_I_I:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VABD_V2_I_I]] to <8 x i8>
// CHECK: [[VMOVL_I_I:%.*]] = zext <2 x i32> [[VABD_V2_I_I]] to <2 x i64>
@@ -389,7 +388,7 @@ uint64x2_t test_vabdl_u32(uint32x2_t a, uint32x2_t b) {
}
// CHECK-LABEL: @test_vabs_s8(
-// CHECK: [[VABS_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabs.v8i8(<8 x i8> %a) #4
+// CHECK: [[VABS_I:%.*]] = call <8 x i8> @llvm.arm.neon.vabs.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VABS_I]]
int8x8_t test_vabs_s8(int8x8_t a) {
return vabs_s8(a);
@@ -397,7 +396,7 @@ int8x8_t test_vabs_s8(int8x8_t a) {
// CHECK-LABEL: @test_vabs_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabs.v4i16(<4 x i16> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vabs.v4i16(<4 x i16> %a)
// CHECK: ret <4 x i16> [[VABS1_I]]
int16x4_t test_vabs_s16(int16x4_t a) {
return vabs_s16(a);
@@ -405,7 +404,7 @@ int16x4_t test_vabs_s16(int16x4_t a) {
// CHECK-LABEL: @test_vabs_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabs.v2i32(<2 x i32> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vabs.v2i32(<2 x i32> %a)
// CHECK: ret <2 x i32> [[VABS1_I]]
int32x2_t test_vabs_s32(int32x2_t a) {
return vabs_s32(a);
@@ -413,14 +412,14 @@ int32x2_t test_vabs_s32(int32x2_t a) {
// CHECK-LABEL: @test_vabs_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VABS1_I]]
float32x2_t test_vabs_f32(float32x2_t a) {
return vabs_f32(a);
}
// CHECK-LABEL: @test_vabsq_s8(
-// CHECK: [[VABS_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabs.v16i8(<16 x i8> %a) #4
+// CHECK: [[VABS_I:%.*]] = call <16 x i8> @llvm.arm.neon.vabs.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VABS_I]]
int8x16_t test_vabsq_s8(int8x16_t a) {
return vabsq_s8(a);
@@ -428,7 +427,7 @@ int8x16_t test_vabsq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vabsq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabs.v8i16(<8 x i16> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vabs.v8i16(<8 x i16> %a)
// CHECK: ret <8 x i16> [[VABS1_I]]
int16x8_t test_vabsq_s16(int16x8_t a) {
return vabsq_s16(a);
@@ -436,7 +435,7 @@ int16x8_t test_vabsq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vabsq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabs.v4i32(<4 x i32> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vabs.v4i32(<4 x i32> %a)
// CHECK: ret <4 x i32> [[VABS1_I]]
int32x4_t test_vabsq_s32(int32x4_t a) {
return vabsq_s32(a);
@@ -444,7 +443,7 @@ int32x4_t test_vabsq_s32(int32x4_t a) {
// CHECK-LABEL: @test_vabsq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VABS1_I:%.*]] = call <4 x float> @llvm.fabs.v4f32(<4 x float> %a) #4
+// CHECK: [[VABS1_I:%.*]] = call <4 x float> @llvm.fabs.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VABS1_I]]
float32x4_t test_vabsq_f32(float32x4_t a) {
return vabsq_f32(a);
@@ -997,7 +996,7 @@ uint64x2_t test_vbicq_u64(uint64x2_t a, uint64x2_t b) {
}
// CHECK-LABEL: @test_vbsl_s8(
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c)
// CHECK: ret <8 x i8> [[VBSL_V_I]]
int8x8_t test_vbsl_s8(uint8x8_t a, int8x8_t b, int8x8_t c) {
return vbsl_s8(a, b, c);
@@ -1007,7 +1006,7 @@ int8x8_t test_vbsl_s8(uint8x8_t a, int8x8_t b, int8x8_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <4 x i16>
// CHECK: ret <4 x i16> [[TMP3]]
int16x4_t test_vbsl_s16(uint16x4_t a, int16x4_t b, int16x4_t c) {
@@ -1018,7 +1017,7 @@ int16x4_t test_vbsl_s16(uint16x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <2 x i32>
// CHECK: ret <2 x i32> [[TMP3]]
int32x2_t test_vbsl_s32(uint32x2_t a, int32x2_t b, int32x2_t c) {
@@ -1029,7 +1028,7 @@ int32x2_t test_vbsl_s32(uint32x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <1 x i64> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <1 x i64>
// CHECK: ret <1 x i64> [[TMP3]]
int64x1_t test_vbsl_s64(uint64x1_t a, int64x1_t b, int64x1_t c) {
@@ -1037,7 +1036,7 @@ int64x1_t test_vbsl_s64(uint64x1_t a, int64x1_t b, int64x1_t c) {
}
// CHECK-LABEL: @test_vbsl_u8(
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c)
// CHECK: ret <8 x i8> [[VBSL_V_I]]
uint8x8_t test_vbsl_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
return vbsl_u8(a, b, c);
@@ -1047,7 +1046,7 @@ uint8x8_t test_vbsl_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <4 x i16>
// CHECK: ret <4 x i16> [[TMP3]]
uint16x4_t test_vbsl_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
@@ -1058,7 +1057,7 @@ uint16x4_t test_vbsl_u16(uint16x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <2 x i32>
// CHECK: ret <2 x i32> [[TMP3]]
uint32x2_t test_vbsl_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
@@ -1069,7 +1068,7 @@ uint32x2_t test_vbsl_u32(uint32x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <1 x i64> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <1 x i64>
// CHECK: ret <1 x i64> [[TMP3]]
uint64x1_t test_vbsl_u64(uint64x1_t a, uint64x1_t b, uint64x1_t c) {
@@ -1080,7 +1079,7 @@ uint64x1_t test_vbsl_u64(uint64x1_t a, uint64x1_t b, uint64x1_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x float> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <2 x float>
// CHECK: ret <2 x float> [[TMP3]]
float32x2_t test_vbsl_f32(uint32x2_t a, float32x2_t b, float32x2_t c) {
@@ -1088,7 +1087,7 @@ float32x2_t test_vbsl_f32(uint32x2_t a, float32x2_t b, float32x2_t c) {
}
// CHECK-LABEL: @test_vbsl_p8(
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c)
// CHECK: ret <8 x i8> [[VBSL_V_I]]
poly8x8_t test_vbsl_p8(uint8x8_t a, poly8x8_t b, poly8x8_t c) {
return vbsl_p8(a, b, c);
@@ -1098,7 +1097,7 @@ poly8x8_t test_vbsl_p8(uint8x8_t a, poly8x8_t b, poly8x8_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP0]], <8 x i8> [[TMP1]], <8 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <4 x i16>
// CHECK: ret <4 x i16> [[TMP3]]
poly16x4_t test_vbsl_p16(uint16x4_t a, poly16x4_t b, poly16x4_t c) {
@@ -1106,7 +1105,7 @@ poly16x4_t test_vbsl_p16(uint16x4_t a, poly16x4_t b, poly16x4_t c) {
}
// CHECK-LABEL: @test_vbslq_s8(
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> %a, <16 x i8> %b, <16 x i8> %c) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> %a, <16 x i8> %b, <16 x i8> %c)
// CHECK: ret <16 x i8> [[VBSLQ_V_I]]
int8x16_t test_vbslq_s8(uint8x16_t a, int8x16_t b, int8x16_t c) {
return vbslq_s8(a, b, c);
@@ -1116,7 +1115,7 @@ int8x16_t test_vbslq_s8(uint8x16_t a, int8x16_t b, int8x16_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[TMP3]]
int16x8_t test_vbslq_s16(uint16x8_t a, int16x8_t b, int16x8_t c) {
@@ -1127,7 +1126,7 @@ int16x8_t test_vbslq_s16(uint16x8_t a, int16x8_t b, int16x8_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <4 x i32>
// CHECK: ret <4 x i32> [[TMP3]]
int32x4_t test_vbslq_s32(uint32x4_t a, int32x4_t b, int32x4_t c) {
@@ -1138,7 +1137,7 @@ int32x4_t test_vbslq_s32(uint32x4_t a, int32x4_t b, int32x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i64> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <2 x i64>
// CHECK: ret <2 x i64> [[TMP3]]
int64x2_t test_vbslq_s64(uint64x2_t a, int64x2_t b, int64x2_t c) {
@@ -1146,7 +1145,7 @@ int64x2_t test_vbslq_s64(uint64x2_t a, int64x2_t b, int64x2_t c) {
}
// CHECK-LABEL: @test_vbslq_u8(
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> %a, <16 x i8> %b, <16 x i8> %c) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> %a, <16 x i8> %b, <16 x i8> %c)
// CHECK: ret <16 x i8> [[VBSLQ_V_I]]
uint8x16_t test_vbslq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
return vbslq_u8(a, b, c);
@@ -1156,7 +1155,7 @@ uint8x16_t test_vbslq_u8(uint8x16_t a, uint8x16_t b, uint8x16_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[TMP3]]
uint16x8_t test_vbslq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c) {
@@ -1167,7 +1166,7 @@ uint16x8_t test_vbslq_u16(uint16x8_t a, uint16x8_t b, uint16x8_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <4 x i32>
// CHECK: ret <4 x i32> [[TMP3]]
uint32x4_t test_vbslq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
@@ -1178,7 +1177,7 @@ uint32x4_t test_vbslq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i64> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <2 x i64>
// CHECK: ret <2 x i64> [[TMP3]]
uint64x2_t test_vbslq_u64(uint64x2_t a, uint64x2_t b, uint64x2_t c) {
@@ -1189,7 +1188,7 @@ uint64x2_t test_vbslq_u64(uint64x2_t a, uint64x2_t b, uint64x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x float> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <4 x float>
// CHECK: ret <4 x float> [[TMP3]]
float32x4_t test_vbslq_f32(uint32x4_t a, float32x4_t b, float32x4_t c) {
@@ -1197,7 +1196,7 @@ float32x4_t test_vbslq_f32(uint32x4_t a, float32x4_t b, float32x4_t c) {
}
// CHECK-LABEL: @test_vbslq_p8(
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> %a, <16 x i8> %b, <16 x i8> %c) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> %a, <16 x i8> %b, <16 x i8> %c)
// CHECK: ret <16 x i8> [[VBSLQ_V_I]]
poly8x16_t test_vbslq_p8(uint8x16_t a, poly8x16_t b, poly8x16_t c) {
return vbslq_p8(a, b, c);
@@ -1207,7 +1206,7 @@ poly8x16_t test_vbslq_p8(uint8x16_t a, poly8x16_t b, poly8x16_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %c to <16 x i8>
-// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]]) #4
+// CHECK: [[VBSLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vbsl.v16i8(<16 x i8> [[TMP0]], <16 x i8> [[TMP1]], <16 x i8> [[TMP2]])
// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[VBSLQ_V_I]] to <8 x i16>
// CHECK: ret <8 x i16> [[TMP3]]
poly16x8_t test_vbslq_p16(uint16x8_t a, poly16x8_t b, poly16x8_t c) {
@@ -1217,7 +1216,7 @@ poly16x8_t test_vbslq_p16(uint16x8_t a, poly16x8_t b, poly16x8_t c) {
// CHECK-LABEL: @test_vcage_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VCAGE_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacge.v2i32.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VCAGE_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacge.v2i32.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x i32> [[VCAGE_V2_I]]
uint32x2_t test_vcage_f32(float32x2_t a, float32x2_t b) {
return vcage_f32(a, b);
@@ -1226,7 +1225,7 @@ uint32x2_t test_vcage_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vcageq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VCAGEQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacge.v4i32.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VCAGEQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacge.v4i32.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x i32> [[VCAGEQ_V2_I]]
uint32x4_t test_vcageq_f32(float32x4_t a, float32x4_t b) {
return vcageq_f32(a, b);
@@ -1235,7 +1234,7 @@ uint32x4_t test_vcageq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vcagt_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VCAGT_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacgt.v2i32.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VCAGT_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacgt.v2i32.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: ret <2 x i32> [[VCAGT_V2_I]]
uint32x2_t test_vcagt_f32(float32x2_t a, float32x2_t b) {
return vcagt_f32(a, b);
@@ -1244,7 +1243,7 @@ uint32x2_t test_vcagt_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vcagtq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VCAGTQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacgt.v4i32.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VCAGTQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacgt.v4i32.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: ret <4 x i32> [[VCAGTQ_V2_I]]
uint32x4_t test_vcagtq_f32(float32x4_t a, float32x4_t b) {
return vcagtq_f32(a, b);
@@ -1253,7 +1252,7 @@ uint32x4_t test_vcagtq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vcale_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VCALE_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacge.v2i32.v2f32(<2 x float> %b, <2 x float> %a) #4
+// CHECK: [[VCALE_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacge.v2i32.v2f32(<2 x float> %b, <2 x float> %a)
// CHECK: ret <2 x i32> [[VCALE_V2_I]]
uint32x2_t test_vcale_f32(float32x2_t a, float32x2_t b) {
return vcale_f32(a, b);
@@ -1262,7 +1261,7 @@ uint32x2_t test_vcale_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vcaleq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VCALEQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacge.v4i32.v4f32(<4 x float> %b, <4 x float> %a) #4
+// CHECK: [[VCALEQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacge.v4i32.v4f32(<4 x float> %b, <4 x float> %a)
// CHECK: ret <4 x i32> [[VCALEQ_V2_I]]
uint32x4_t test_vcaleq_f32(float32x4_t a, float32x4_t b) {
return vcaleq_f32(a, b);
@@ -1271,7 +1270,7 @@ uint32x4_t test_vcaleq_f32(float32x4_t a, float32x4_t b) {
// CHECK-LABEL: @test_vcalt_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VCALT_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacgt.v2i32.v2f32(<2 x float> %b, <2 x float> %a) #4
+// CHECK: [[VCALT_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vacgt.v2i32.v2f32(<2 x float> %b, <2 x float> %a)
// CHECK: ret <2 x i32> [[VCALT_V2_I]]
uint32x2_t test_vcalt_f32(float32x2_t a, float32x2_t b) {
return vcalt_f32(a, b);
@@ -1280,7 +1279,7 @@ uint32x2_t test_vcalt_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vcaltq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VCALTQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacgt.v4i32.v4f32(<4 x float> %b, <4 x float> %a) #4
+// CHECK: [[VCALTQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vacgt.v4i32.v4f32(<4 x float> %b, <4 x float> %a)
// CHECK: ret <4 x i32> [[VCALTQ_V2_I]]
uint32x4_t test_vcaltq_f32(float32x4_t a, float32x4_t b) {
return vcaltq_f32(a, b);
@@ -1751,7 +1750,7 @@ uint32x4_t test_vcleq_u32(uint32x4_t a, uint32x4_t b) {
}
// CHECK-LABEL: @test_vcls_s8(
-// CHECK: [[VCLS_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vcls.v8i8(<8 x i8> %a) #4
+// CHECK: [[VCLS_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vcls.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCLS_V_I]]
int8x8_t test_vcls_s8(int8x8_t a) {
return vcls_s8(a);
@@ -1759,7 +1758,7 @@ int8x8_t test_vcls_s8(int8x8_t a) {
// CHECK-LABEL: @test_vcls_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VCLS_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vcls.v4i16(<4 x i16> %a) #4
+// CHECK: [[VCLS_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vcls.v4i16(<4 x i16> %a)
// CHECK: [[VCLS_V2_I:%.*]] = bitcast <4 x i16> [[VCLS_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLS_V1_I]]
int16x4_t test_vcls_s16(int16x4_t a) {
@@ -1768,7 +1767,7 @@ int16x4_t test_vcls_s16(int16x4_t a) {
// CHECK-LABEL: @test_vcls_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VCLS_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vcls.v2i32(<2 x i32> %a) #4
+// CHECK: [[VCLS_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vcls.v2i32(<2 x i32> %a)
// CHECK: [[VCLS_V2_I:%.*]] = bitcast <2 x i32> [[VCLS_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLS_V1_I]]
int32x2_t test_vcls_s32(int32x2_t a) {
@@ -1776,7 +1775,7 @@ int32x2_t test_vcls_s32(int32x2_t a) {
}
// CHECK-LABEL: @test_vclsq_s8(
-// CHECK: [[VCLSQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vcls.v16i8(<16 x i8> %a) #4
+// CHECK: [[VCLSQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vcls.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCLSQ_V_I]]
int8x16_t test_vclsq_s8(int8x16_t a) {
return vclsq_s8(a);
@@ -1784,7 +1783,7 @@ int8x16_t test_vclsq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vclsq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VCLSQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vcls.v8i16(<8 x i16> %a) #4
+// CHECK: [[VCLSQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vcls.v8i16(<8 x i16> %a)
// CHECK: [[VCLSQ_V2_I:%.*]] = bitcast <8 x i16> [[VCLSQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VCLSQ_V1_I]]
int16x8_t test_vclsq_s16(int16x8_t a) {
@@ -1793,7 +1792,7 @@ int16x8_t test_vclsq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vclsq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VCLSQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vcls.v4i32(<4 x i32> %a) #4
+// CHECK: [[VCLSQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vcls.v4i32(<4 x i32> %a)
// CHECK: [[VCLSQ_V2_I:%.*]] = bitcast <4 x i32> [[VCLSQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VCLSQ_V1_I]]
int32x4_t test_vclsq_s32(int32x4_t a) {
@@ -1913,7 +1912,7 @@ uint32x4_t test_vcltq_u32(uint32x4_t a, uint32x4_t b) {
}
// CHECK-LABEL: @test_vclz_s8(
-// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false) #4
+// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false)
// CHECK: ret <8 x i8> [[VCLZ_V_I]]
int8x8_t test_vclz_s8(int8x8_t a) {
return vclz_s8(a);
@@ -1921,7 +1920,7 @@ int8x8_t test_vclz_s8(int8x8_t a) {
// CHECK-LABEL: @test_vclz_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <4 x i16> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLZ_V1_I]]
int16x4_t test_vclz_s16(int16x4_t a) {
@@ -1930,7 +1929,7 @@ int16x4_t test_vclz_s16(int16x4_t a) {
// CHECK-LABEL: @test_vclz_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <2 x i32> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLZ_V1_I]]
int32x2_t test_vclz_s32(int32x2_t a) {
@@ -1938,7 +1937,7 @@ int32x2_t test_vclz_s32(int32x2_t a) {
}
// CHECK-LABEL: @test_vclz_u8(
-// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false) #4
+// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> %a, i1 false)
// CHECK: ret <8 x i8> [[VCLZ_V_I]]
uint8x8_t test_vclz_u8(uint8x8_t a) {
return vclz_u8(a);
@@ -1946,7 +1945,7 @@ uint8x8_t test_vclz_u8(uint8x8_t a) {
// CHECK-LABEL: @test_vclz_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <4 x i16> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLZ_V1_I]]
uint16x4_t test_vclz_u16(uint16x4_t a) {
@@ -1955,7 +1954,7 @@ uint16x4_t test_vclz_u16(uint16x4_t a) {
// CHECK-LABEL: @test_vclz_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %a, i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <2 x i32> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLZ_V1_I]]
uint32x2_t test_vclz_u32(uint32x2_t a) {
@@ -1963,7 +1962,7 @@ uint32x2_t test_vclz_u32(uint32x2_t a) {
}
// CHECK-LABEL: @test_vclzq_s8(
-// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false) #4
+// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false)
// CHECK: ret <16 x i8> [[VCLZQ_V_I]]
int8x16_t test_vclzq_s8(int8x16_t a) {
return vclzq_s8(a);
@@ -1971,7 +1970,7 @@ int8x16_t test_vclzq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vclzq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false) #4
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <8 x i16> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VCLZQ_V1_I]]
int16x8_t test_vclzq_s16(int16x8_t a) {
@@ -1980,7 +1979,7 @@ int16x8_t test_vclzq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vclzq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false) #4
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <4 x i32> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VCLZQ_V1_I]]
int32x4_t test_vclzq_s32(int32x4_t a) {
@@ -1988,7 +1987,7 @@ int32x4_t test_vclzq_s32(int32x4_t a) {
}
// CHECK-LABEL: @test_vclzq_u8(
-// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false) #4
+// CHECK: [[VCLZQ_V_I:%.*]] = call <16 x i8> @llvm.ctlz.v16i8(<16 x i8> %a, i1 false)
// CHECK: ret <16 x i8> [[VCLZQ_V_I]]
uint8x16_t test_vclzq_u8(uint8x16_t a) {
return vclzq_u8(a);
@@ -1996,7 +1995,7 @@ uint8x16_t test_vclzq_u8(uint8x16_t a) {
// CHECK-LABEL: @test_vclzq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false) #4
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <8 x i16> @llvm.ctlz.v8i16(<8 x i16> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <8 x i16> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VCLZQ_V1_I]]
uint16x8_t test_vclzq_u16(uint16x8_t a) {
@@ -2005,7 +2004,7 @@ uint16x8_t test_vclzq_u16(uint16x8_t a) {
// CHECK-LABEL: @test_vclzq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false) #4
+// CHECK: [[VCLZQ_V1_I:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %a, i1 false)
// CHECK: [[VCLZQ_V2_I:%.*]] = bitcast <4 x i32> [[VCLZQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VCLZQ_V1_I]]
uint32x4_t test_vclzq_u32(uint32x4_t a) {
@@ -2013,42 +2012,42 @@ uint32x4_t test_vclzq_u32(uint32x4_t a) {
}
// CHECK-LABEL: @test_vcnt_u8(
-// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a) #4
+// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCNT_V_I]]
uint8x8_t test_vcnt_u8(uint8x8_t a) {
return vcnt_u8(a);
}
// CHECK-LABEL: @test_vcnt_s8(
-// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a) #4
+// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCNT_V_I]]
int8x8_t test_vcnt_s8(int8x8_t a) {
return vcnt_s8(a);
}
// CHECK-LABEL: @test_vcnt_p8(
-// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a) #4
+// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VCNT_V_I]]
poly8x8_t test_vcnt_p8(poly8x8_t a) {
return vcnt_p8(a);
}
// CHECK-LABEL: @test_vcntq_u8(
-// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a) #4
+// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCNTQ_V_I]]
uint8x16_t test_vcntq_u8(uint8x16_t a) {
return vcntq_u8(a);
}
// CHECK-LABEL: @test_vcntq_s8(
-// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a) #4
+// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCNTQ_V_I]]
int8x16_t test_vcntq_s8(int8x16_t a) {
return vcntq_s8(a);
}
// CHECK-LABEL: @test_vcntq_p8(
-// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a) #4
+// CHECK: [[VCNTQ_V_I:%.*]] = call <16 x i8> @llvm.ctpop.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VCNTQ_V_I]]
poly8x16_t test_vcntq_p8(poly8x16_t a) {
return vcntq_p8(a);
@@ -2140,7 +2139,7 @@ poly16x8_t test_vcombine_p16(poly16x4_t a, poly16x4_t b) {
// CHECK-LABEL: @test_vcreate_s8(
// CHECK: [[TMP0:%.*]] = bitcast i64 %a to <8 x i8>
-// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> [[TMP0]], i1 false) #4
+// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> [[TMP0]], i1 false)
// CHECK: ret <8 x i8> [[VCLZ_V_I]]
int8x8_t test_vcreate_s8(uint64_t a) {
return vclz_s8(vcreate_s8(a));
@@ -2149,7 +2148,7 @@ int8x8_t test_vcreate_s8(uint64_t a) {
// CHECK-LABEL: @test_vcreate_s16(
// CHECK: [[TMP0:%.*]] = bitcast i64 %a to <4 x i16>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> [[TMP0]], i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> [[TMP0]], i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <4 x i16> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLZ_V1_I]]
int16x4_t test_vcreate_s16(uint64_t a) {
@@ -2159,7 +2158,7 @@ int16x4_t test_vcreate_s16(uint64_t a) {
// CHECK-LABEL: @test_vcreate_s32(
// CHECK: [[TMP0:%.*]] = bitcast i64 %a to <2 x i32>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[TMP0]] to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[TMP0]], i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[TMP0]], i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <2 x i32> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLZ_V1_I]]
int32x2_t test_vcreate_s32(uint64_t a) {
@@ -2182,7 +2181,7 @@ float32x2_t test_vcreate_f32(uint64_t a) {
// CHECK-LABEL: @test_vcreate_u8(
// CHECK: [[TMP0:%.*]] = bitcast i64 %a to <8 x i8>
-// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> [[TMP0]], i1 false) #4
+// CHECK: [[VCLZ_V_I:%.*]] = call <8 x i8> @llvm.ctlz.v8i8(<8 x i8> [[TMP0]], i1 false)
// CHECK: ret <8 x i8> [[VCLZ_V_I]]
uint8x8_t test_vcreate_u8(uint64_t a) {
return vclz_s8(vcreate_u8(a));
@@ -2191,7 +2190,7 @@ uint8x8_t test_vcreate_u8(uint64_t a) {
// CHECK-LABEL: @test_vcreate_u16(
// CHECK: [[TMP0:%.*]] = bitcast i64 %a to <4 x i16>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> [[TMP0]], i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <4 x i16> @llvm.ctlz.v4i16(<4 x i16> [[TMP0]], i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <4 x i16> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VCLZ_V1_I]]
uint16x4_t test_vcreate_u16(uint64_t a) {
@@ -2201,7 +2200,7 @@ uint16x4_t test_vcreate_u16(uint64_t a) {
// CHECK-LABEL: @test_vcreate_u32(
// CHECK: [[TMP0:%.*]] = bitcast i64 %a to <2 x i32>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[TMP0]] to <8 x i8>
-// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[TMP0]], i1 false) #4
+// CHECK: [[VCLZ_V1_I:%.*]] = call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[TMP0]], i1 false)
// CHECK: [[VCLZ_V2_I:%.*]] = bitcast <2 x i32> [[VCLZ_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VCLZ_V1_I]]
uint32x2_t test_vcreate_u32(uint64_t a) {
@@ -2219,7 +2218,7 @@ uint64x1_t test_vcreate_u64(uint64_t a) {
// CHECK-LABEL: @test_vcreate_p8(
// CHECK: [[TMP0:%.*]] = bitcast i64 %a to <8 x i8>
-// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> [[TMP0]]) #4
+// CHECK: [[VCNT_V_I:%.*]] = call <8 x i8> @llvm.ctpop.v8i8(<8 x i8> [[TMP0]])
// CHECK: ret <8 x i8> [[VCNT_V_I]]
poly8x8_t test_vcreate_p8(uint64_t a) {
return vcnt_p8(vcreate_p8(a));
@@ -2230,7 +2229,7 @@ poly8x8_t test_vcreate_p8(uint64_t a) {
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8>
// CHECK: [[TMP3:%.*]] = bitcast <4 x i16> [[TMP0]] to <8 x i8>
-// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP1]], <8 x i8> [[TMP2]], <8 x i8> [[TMP3]]) #4
+// CHECK: [[VBSL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vbsl.v8i8(<8 x i8> [[TMP1]], <8 x i8> [[TMP2]], <8 x i8> [[TMP3]])
// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[VBSL_V_I]] to <4 x i16>
// CHECK: ret <4 x i16> [[TMP4]]
poly16x4_t test_vcreate_p16(uint64_t a) {
@@ -2249,7 +2248,7 @@ int64x1_t test_vcreate_s64(uint64_t a) {
// CHECK-LABEL: @test_vcvt_f16_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VCVT_F16_F321_I:%.*]] = call <4 x i16> @llvm.arm.neon.vcvtfp2hf(<4 x float> %a) #4
+// CHECK: [[VCVT_F16_F321_I:%.*]] = call <4 x i16> @llvm.arm.neon.vcvtfp2hf(<4 x float> %a)
// CHECK: [[VCVT_F16_F322_I:%.*]] = bitcast <4 x i16> [[VCVT_F16_F321_I]] to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[VCVT_F16_F322_I]] to <4 x half>
// CHECK: ret <4 x half> [[TMP1]]
@@ -2292,7 +2291,7 @@ float32x4_t test_vcvtq_f32_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vcvt_f32_f16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
// CHECK: [[VCVT_F32_F16_I:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16>
-// CHECK: [[VCVT_F32_F161_I:%.*]] = call <4 x float> @llvm.arm.neon.vcvthf2fp(<4 x i16> [[VCVT_F32_F16_I]]) #4
+// CHECK: [[VCVT_F32_F161_I:%.*]] = call <4 x float> @llvm.arm.neon.vcvthf2fp(<4 x i16> [[VCVT_F32_F16_I]])
// CHECK: [[VCVT_F32_F162_I:%.*]] = bitcast <4 x float> [[VCVT_F32_F161_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VCVT_F32_F161_I]]
float32x4_t test_vcvt_f32_f16(float16x4_t a) {
@@ -3189,7 +3188,7 @@ float32x4_t test_vextq_f32(float32x4_t a, float32x4_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x float> %c to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> %b, <2 x float> %c, <2 x float> %a) #4
+// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> %b, <2 x float> %c, <2 x float> %a)
// CHECK: ret <2 x float> [[TMP3]]
float32x2_t test_vfma_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
return vfma_f32(a, b, c);
@@ -3199,7 +3198,7 @@ float32x2_t test_vfma_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x float> %c to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %b, <4 x float> %c, <4 x float> %a) #4
+// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %b, <4 x float> %c, <4 x float> %a)
// CHECK: ret <4 x float> [[TMP3]]
float32x4_t test_vfmaq_f32(float32x4_t a, float32x4_t b, float32x4_t c) {
return vfmaq_f32(a, b, c);
@@ -3210,7 +3209,7 @@ float32x4_t test_vfmaq_f32(float32x4_t a, float32x4_t b, float32x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> [[SUB_I]] to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x float> %c to <8 x i8>
-// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[SUB_I]], <2 x float> %c, <2 x float> %a) #4
+// CHECK: [[TMP3:%.*]] = call <2 x float> @llvm.fma.v2f32(<2 x float> [[SUB_I]], <2 x float> %c, <2 x float> %a)
// CHECK: ret <2 x float> [[TMP3]]
float32x2_t test_vfms_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
return vfms_f32(a, b, c);
@@ -3221,7 +3220,7 @@ float32x2_t test_vfms_f32(float32x2_t a, float32x2_t b, float32x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> [[SUB_I]] to <16 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x float> %c to <16 x i8>
-// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> [[SUB_I]], <4 x float> %c, <4 x float> %a) #4
+// CHECK: [[TMP3:%.*]] = call <4 x float> @llvm.fma.v4f32(<4 x float> [[SUB_I]], <4 x float> %c, <4 x float> %a)
// CHECK: ret <4 x float> [[TMP3]]
float32x4_t test_vfmsq_f32(float32x4_t a, float32x4_t b, float32x4_t c) {
return vfmsq_f32(a, b, c);
@@ -3618,7 +3617,7 @@ poly16x4_t test_vget_low_p16(poly16x8_t a) {
}
// CHECK-LABEL: @test_vhadd_s8(
-// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhadds.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhadds.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VHADD_V_I]]
int8x8_t test_vhadd_s8(int8x8_t a, int8x8_t b) {
return vhadd_s8(a, b);
@@ -3627,7 +3626,7 @@ int8x8_t test_vhadd_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vhadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhadds.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhadds.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <4 x i16> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHADD_V2_I]]
int16x4_t test_vhadd_s16(int16x4_t a, int16x4_t b) {
@@ -3637,7 +3636,7 @@ int16x4_t test_vhadd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vhadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhadds.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhadds.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <2 x i32> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHADD_V2_I]]
int32x2_t test_vhadd_s32(int32x2_t a, int32x2_t b) {
@@ -3645,7 +3644,7 @@ int32x2_t test_vhadd_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vhadd_u8(
-// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhaddu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhaddu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VHADD_V_I]]
uint8x8_t test_vhadd_u8(uint8x8_t a, uint8x8_t b) {
return vhadd_u8(a, b);
@@ -3654,7 +3653,7 @@ uint8x8_t test_vhadd_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vhadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhaddu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhaddu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <4 x i16> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHADD_V2_I]]
uint16x4_t test_vhadd_u16(uint16x4_t a, uint16x4_t b) {
@@ -3664,7 +3663,7 @@ uint16x4_t test_vhadd_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vhadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhaddu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhaddu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VHADD_V3_I:%.*]] = bitcast <2 x i32> [[VHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHADD_V2_I]]
uint32x2_t test_vhadd_u32(uint32x2_t a, uint32x2_t b) {
@@ -3672,7 +3671,7 @@ uint32x2_t test_vhadd_u32(uint32x2_t a, uint32x2_t b) {
}
// CHECK-LABEL: @test_vhaddq_s8(
-// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhadds.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhadds.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VHADDQ_V_I]]
int8x16_t test_vhaddq_s8(int8x16_t a, int8x16_t b) {
return vhaddq_s8(a, b);
@@ -3681,7 +3680,7 @@ int8x16_t test_vhaddq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vhaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhadds.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhadds.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHADDQ_V2_I]]
int16x8_t test_vhaddq_s16(int16x8_t a, int16x8_t b) {
@@ -3691,7 +3690,7 @@ int16x8_t test_vhaddq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vhaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhadds.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhadds.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHADDQ_V2_I]]
int32x4_t test_vhaddq_s32(int32x4_t a, int32x4_t b) {
@@ -3699,7 +3698,7 @@ int32x4_t test_vhaddq_s32(int32x4_t a, int32x4_t b) {
}
// CHECK-LABEL: @test_vhaddq_u8(
-// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhaddu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhaddu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VHADDQ_V_I]]
uint8x16_t test_vhaddq_u8(uint8x16_t a, uint8x16_t b) {
return vhaddq_u8(a, b);
@@ -3708,7 +3707,7 @@ uint8x16_t test_vhaddq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vhaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhaddu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhaddu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHADDQ_V2_I]]
uint16x8_t test_vhaddq_u16(uint16x8_t a, uint16x8_t b) {
@@ -3718,7 +3717,7 @@ uint16x8_t test_vhaddq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vhaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhaddu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhaddu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHADDQ_V2_I]]
uint32x4_t test_vhaddq_u32(uint32x4_t a, uint32x4_t b) {
@@ -3726,7 +3725,7 @@ uint32x4_t test_vhaddq_u32(uint32x4_t a, uint32x4_t b) {
}
// CHECK-LABEL: @test_vhsub_s8(
-// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhsubs.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhsubs.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VHSUB_V_I]]
int8x8_t test_vhsub_s8(int8x8_t a, int8x8_t b) {
return vhsub_s8(a, b);
@@ -3735,7 +3734,7 @@ int8x8_t test_vhsub_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vhsub_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhsubs.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhsubs.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <4 x i16> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHSUB_V2_I]]
int16x4_t test_vhsub_s16(int16x4_t a, int16x4_t b) {
@@ -3745,7 +3744,7 @@ int16x4_t test_vhsub_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vhsub_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhsubs.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhsubs.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <2 x i32> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHSUB_V2_I]]
int32x2_t test_vhsub_s32(int32x2_t a, int32x2_t b) {
@@ -3753,7 +3752,7 @@ int32x2_t test_vhsub_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vhsub_u8(
-// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhsubu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VHSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vhsubu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VHSUB_V_I]]
uint8x8_t test_vhsub_u8(uint8x8_t a, uint8x8_t b) {
return vhsub_u8(a, b);
@@ -3762,7 +3761,7 @@ uint8x8_t test_vhsub_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vhsub_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhsubu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vhsubu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <4 x i16> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VHSUB_V2_I]]
uint16x4_t test_vhsub_u16(uint16x4_t a, uint16x4_t b) {
@@ -3772,7 +3771,7 @@ uint16x4_t test_vhsub_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vhsub_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhsubu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VHSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vhsubu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VHSUB_V3_I:%.*]] = bitcast <2 x i32> [[VHSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VHSUB_V2_I]]
uint32x2_t test_vhsub_u32(uint32x2_t a, uint32x2_t b) {
@@ -3780,7 +3779,7 @@ uint32x2_t test_vhsub_u32(uint32x2_t a, uint32x2_t b) {
}
// CHECK-LABEL: @test_vhsubq_s8(
-// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhsubs.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhsubs.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VHSUBQ_V_I]]
int8x16_t test_vhsubq_s8(int8x16_t a, int8x16_t b) {
return vhsubq_s8(a, b);
@@ -3789,7 +3788,7 @@ int8x16_t test_vhsubq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vhsubq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhsubs.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhsubs.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHSUBQ_V2_I]]
int16x8_t test_vhsubq_s16(int16x8_t a, int16x8_t b) {
@@ -3799,7 +3798,7 @@ int16x8_t test_vhsubq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vhsubq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhsubs.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhsubs.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHSUBQ_V2_I]]
int32x4_t test_vhsubq_s32(int32x4_t a, int32x4_t b) {
@@ -3807,7 +3806,7 @@ int32x4_t test_vhsubq_s32(int32x4_t a, int32x4_t b) {
}
// CHECK-LABEL: @test_vhsubq_u8(
-// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhsubu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VHSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vhsubu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VHSUBQ_V_I]]
uint8x16_t test_vhsubq_u8(uint8x16_t a, uint8x16_t b) {
return vhsubq_u8(a, b);
@@ -3816,7 +3815,7 @@ uint8x16_t test_vhsubq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vhsubq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhsubu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vhsubu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VHSUBQ_V2_I]]
uint16x8_t test_vhsubq_u16(uint16x8_t a, uint16x8_t b) {
@@ -3826,7 +3825,7 @@ uint16x8_t test_vhsubq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vhsubq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhsubu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VHSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vhsubu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VHSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VHSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VHSUBQ_V2_I]]
uint32x4_t test_vhsubq_u32(uint32x4_t a, uint32x4_t b) {
@@ -7002,7 +7001,7 @@ poly16x4x4_t test_vld4_lane_p16(poly16_t const * a, poly16x4x4_t b) {
}
// CHECK-LABEL: @test_vmax_s8(
-// CHECK: [[VMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmaxs.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmaxs.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMAX_V_I]]
int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) {
return vmax_s8(a, b);
@@ -7011,7 +7010,7 @@ int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vmax_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vmaxs.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vmaxs.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VMAX_V3_I:%.*]] = bitcast <4 x i16> [[VMAX_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VMAX_V2_I]]
int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) {
@@ -7021,7 +7020,7 @@ int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vmax_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vmaxs.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vmaxs.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VMAX_V3_I:%.*]] = bitcast <2 x i32> [[VMAX_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VMAX_V2_I]]
int32x2_t test_vmax_s32(int32x2_t a, int32x2_t b) {
@@ -7029,7 +7028,7 @@ int32x2_t test_vmax_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vmax_u8(
-// CHECK: [[VMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmaxu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmaxu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMAX_V_I]]
uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) {
return vmax_u8(a, b);
@@ -7038,7 +7037,7 @@ uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vmax_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vmaxu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vmaxu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VMAX_V3_I:%.*]] = bitcast <4 x i16> [[VMAX_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VMAX_V2_I]]
uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) {
@@ -7048,7 +7047,7 @@ uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vmax_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vmaxu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vmaxu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VMAX_V3_I:%.*]] = bitcast <2 x i32> [[VMAX_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VMAX_V2_I]]
uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) {
@@ -7058,7 +7057,7 @@ uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vmax_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VMAX_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vmaxs.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VMAX_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vmaxs.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VMAX_V3_I:%.*]] = bitcast <2 x float> [[VMAX_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VMAX_V2_I]]
float32x2_t test_vmax_f32(float32x2_t a, float32x2_t b) {
@@ -7066,7 +7065,7 @@ float32x2_t test_vmax_f32(float32x2_t a, float32x2_t b) {
}
// CHECK-LABEL: @test_vmaxq_s8(
-// CHECK: [[VMAXQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmaxs.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMAXQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmaxs.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMAXQ_V_I]]
int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) {
return vmaxq_s8(a, b);
@@ -7075,7 +7074,7 @@ int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vmaxq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMAXQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmaxs.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMAXQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmaxs.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VMAXQ_V3_I:%.*]] = bitcast <8 x i16> [[VMAXQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VMAXQ_V2_I]]
int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) {
@@ -7085,7 +7084,7 @@ int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vmaxq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMAXQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmaxs.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMAXQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmaxs.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VMAXQ_V3_I:%.*]] = bitcast <4 x i32> [[VMAXQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VMAXQ_V2_I]]
int32x4_t test_vmaxq_s32(int32x4_t a, int32x4_t b) {
@@ -7093,7 +7092,7 @@ int32x4_t test_vmaxq_s32(int32x4_t a, int32x4_t b) {
}
// CHECK-LABEL: @test_vmaxq_u8(
-// CHECK: [[VMAXQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmaxu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMAXQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmaxu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMAXQ_V_I]]
uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) {
return vmaxq_u8(a, b);
@@ -7102,7 +7101,7 @@ uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vmaxq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMAXQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmaxu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMAXQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmaxu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VMAXQ_V3_I:%.*]] = bitcast <8 x i16> [[VMAXQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VMAXQ_V2_I]]
uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) {
@@ -7112,7 +7111,7 @@ uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vmaxq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMAXQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmaxu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMAXQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmaxu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VMAXQ_V3_I:%.*]] = bitcast <4 x i32> [[VMAXQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VMAXQ_V2_I]]
uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) {
@@ -7122,7 +7121,7 @@ uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vmaxq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VMAXQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vmaxs.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VMAXQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vmaxs.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: [[VMAXQ_V3_I:%.*]] = bitcast <4 x float> [[VMAXQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VMAXQ_V2_I]]
float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) {
@@ -7130,7 +7129,7 @@ float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) {
}
// CHECK-LABEL: @test_vmin_s8(
-// CHECK: [[VMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmins.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmins.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMIN_V_I]]
int8x8_t test_vmin_s8(int8x8_t a, int8x8_t b) {
return vmin_s8(a, b);
@@ -7139,7 +7138,7 @@ int8x8_t test_vmin_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vmin_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vmins.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vmins.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VMIN_V3_I:%.*]] = bitcast <4 x i16> [[VMIN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VMIN_V2_I]]
int16x4_t test_vmin_s16(int16x4_t a, int16x4_t b) {
@@ -7149,7 +7148,7 @@ int16x4_t test_vmin_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vmin_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vmins.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vmins.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VMIN_V3_I:%.*]] = bitcast <2 x i32> [[VMIN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VMIN_V2_I]]
int32x2_t test_vmin_s32(int32x2_t a, int32x2_t b) {
@@ -7157,7 +7156,7 @@ int32x2_t test_vmin_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vmin_u8(
-// CHECK: [[VMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vminu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vminu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMIN_V_I]]
uint8x8_t test_vmin_u8(uint8x8_t a, uint8x8_t b) {
return vmin_u8(a, b);
@@ -7166,7 +7165,7 @@ uint8x8_t test_vmin_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vmin_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vminu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vminu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VMIN_V3_I:%.*]] = bitcast <4 x i16> [[VMIN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VMIN_V2_I]]
uint16x4_t test_vmin_u16(uint16x4_t a, uint16x4_t b) {
@@ -7176,7 +7175,7 @@ uint16x4_t test_vmin_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vmin_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vminu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vminu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VMIN_V3_I:%.*]] = bitcast <2 x i32> [[VMIN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VMIN_V2_I]]
uint32x2_t test_vmin_u32(uint32x2_t a, uint32x2_t b) {
@@ -7186,7 +7185,7 @@ uint32x2_t test_vmin_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vmin_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VMIN_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vmins.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VMIN_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vmins.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VMIN_V3_I:%.*]] = bitcast <2 x float> [[VMIN_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VMIN_V2_I]]
float32x2_t test_vmin_f32(float32x2_t a, float32x2_t b) {
@@ -7194,7 +7193,7 @@ float32x2_t test_vmin_f32(float32x2_t a, float32x2_t b) {
}
// CHECK-LABEL: @test_vminq_s8(
-// CHECK: [[VMINQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmins.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMINQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmins.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMINQ_V_I]]
int8x16_t test_vminq_s8(int8x16_t a, int8x16_t b) {
return vminq_s8(a, b);
@@ -7203,7 +7202,7 @@ int8x16_t test_vminq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vminq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMINQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmins.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMINQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmins.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VMINQ_V3_I:%.*]] = bitcast <8 x i16> [[VMINQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VMINQ_V2_I]]
int16x8_t test_vminq_s16(int16x8_t a, int16x8_t b) {
@@ -7213,7 +7212,7 @@ int16x8_t test_vminq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vminq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMINQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmins.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMINQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmins.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VMINQ_V3_I:%.*]] = bitcast <4 x i32> [[VMINQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VMINQ_V2_I]]
int32x4_t test_vminq_s32(int32x4_t a, int32x4_t b) {
@@ -7221,7 +7220,7 @@ int32x4_t test_vminq_s32(int32x4_t a, int32x4_t b) {
}
// CHECK-LABEL: @test_vminq_u8(
-// CHECK: [[VMINQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vminu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMINQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vminu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMINQ_V_I]]
uint8x16_t test_vminq_u8(uint8x16_t a, uint8x16_t b) {
return vminq_u8(a, b);
@@ -7230,7 +7229,7 @@ uint8x16_t test_vminq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vminq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VMINQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vminu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VMINQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vminu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VMINQ_V3_I:%.*]] = bitcast <8 x i16> [[VMINQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VMINQ_V2_I]]
uint16x8_t test_vminq_u16(uint16x8_t a, uint16x8_t b) {
@@ -7240,7 +7239,7 @@ uint16x8_t test_vminq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vminq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VMINQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vminu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VMINQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vminu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VMINQ_V3_I:%.*]] = bitcast <4 x i32> [[VMINQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VMINQ_V2_I]]
uint32x4_t test_vminq_u32(uint32x4_t a, uint32x4_t b) {
@@ -7250,7 +7249,7 @@ uint32x4_t test_vminq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vminq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VMINQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vmins.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VMINQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vmins.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: [[VMINQ_V3_I:%.*]] = bitcast <4 x float> [[VMINQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VMINQ_V2_I]]
float32x4_t test_vminq_f32(float32x4_t a, float32x4_t b) {
@@ -7370,7 +7369,7 @@ uint32x4_t test_vmlaq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
}
// CHECK-LABEL: @test_vmlal_s8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmulls.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmulls.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
int16x8_t test_vmlal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
@@ -7380,7 +7379,7 @@ int16x8_t test_vmlal_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
// CHECK-LABEL: @test_vmlal_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
int32x4_t test_vmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
@@ -7390,7 +7389,7 @@ int32x4_t test_vmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK-LABEL: @test_vmlal_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
int64x2_t test_vmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
@@ -7398,7 +7397,7 @@ int64x2_t test_vmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
}
// CHECK-LABEL: @test_vmlal_u8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[ADD_I:%.*]] = add <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[ADD_I]]
uint16x8_t test_vmlal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
@@ -7408,7 +7407,7 @@ uint16x8_t test_vmlal_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK-LABEL: @test_vmlal_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
uint32x4_t test_vmlal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
@@ -7418,7 +7417,7 @@ uint32x4_t test_vmlal_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK-LABEL: @test_vmlal_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
uint64x2_t test_vmlal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
@@ -7429,7 +7428,7 @@ uint64x2_t test_vmlal_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %c, <4 x i16> %c, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
int32x4_t test_vmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
@@ -7440,7 +7439,7 @@ int32x4_t test_vmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %c, <2 x i32> %c, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
int64x2_t test_vmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
@@ -7451,7 +7450,7 @@ int64x2_t test_vmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %c, <4 x i16> %c, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[ADD]]
uint32x4_t test_vmlal_lane_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
@@ -7462,7 +7461,7 @@ uint32x4_t test_vmlal_lane_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %c, <2 x i32> %c, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[ADD:%.*]] = add <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[ADD]]
uint64x2_t test_vmlal_lane_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
@@ -7476,7 +7475,7 @@ uint64x2_t test_vmlal_lane_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
int32x4_t test_vmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
@@ -7488,7 +7487,7 @@ int32x4_t test_vmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
int64x2_t test_vmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
@@ -7502,7 +7501,7 @@ int64x2_t test_vmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[ADD_I:%.*]] = add <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[ADD_I]]
uint32x4_t test_vmlal_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
@@ -7514,7 +7513,7 @@ uint32x4_t test_vmlal_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[ADD_I:%.*]] = add <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[ADD_I]]
uint64x2_t test_vmlal_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
@@ -7846,7 +7845,7 @@ uint32x4_t test_vmlsq_u32(uint32x4_t a, uint32x4_t b, uint32x4_t c) {
}
// CHECK-LABEL: @test_vmlsl_s8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmulls.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmulls.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[SUB_I:%.*]] = sub <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[SUB_I]]
int16x8_t test_vmlsl_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
@@ -7856,7 +7855,7 @@ int16x8_t test_vmlsl_s8(int16x8_t a, int8x8_t b, int8x8_t c) {
// CHECK-LABEL: @test_vmlsl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
int32x4_t test_vmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
@@ -7866,7 +7865,7 @@ int32x4_t test_vmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK-LABEL: @test_vmlsl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
int64x2_t test_vmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
@@ -7874,7 +7873,7 @@ int64x2_t test_vmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
}
// CHECK-LABEL: @test_vmlsl_u8(
-// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VMULL_I_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %b, <8 x i8> %c)
// CHECK: [[SUB_I:%.*]] = sub <8 x i16> %a, [[VMULL_I_I]]
// CHECK: ret <8 x i16> [[SUB_I]]
uint16x8_t test_vmlsl_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
@@ -7884,7 +7883,7 @@ uint16x8_t test_vmlsl_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) {
// CHECK-LABEL: @test_vmlsl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> %c)
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
uint32x4_t test_vmlsl_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
@@ -7894,7 +7893,7 @@ uint32x4_t test_vmlsl_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK-LABEL: @test_vmlsl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> %c) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> %c)
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
uint64x2_t test_vmlsl_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
@@ -7905,7 +7904,7 @@ uint64x2_t test_vmlsl_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %c, <4 x i16> %c, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
int32x4_t test_vmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
@@ -7916,7 +7915,7 @@ int32x4_t test_vmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %c, <2 x i32> %c, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
int64x2_t test_vmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
@@ -7927,7 +7926,7 @@ int64x2_t test_vmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %c, <4 x i16> %c, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <4 x i32> %a, [[VMULL2_I]]
// CHECK: ret <4 x i32> [[SUB]]
uint32x4_t test_vmlsl_lane_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
@@ -7938,7 +7937,7 @@ uint32x4_t test_vmlsl_lane_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %c, <2 x i32> %c, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
// CHECK: [[SUB:%.*]] = sub <2 x i64> %a, [[VMULL2_I]]
// CHECK: ret <2 x i64> [[SUB]]
uint64x2_t test_vmlsl_lane_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
@@ -7952,7 +7951,7 @@ uint64x2_t test_vmlsl_lane_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
int32x4_t test_vmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
@@ -7964,7 +7963,7 @@ int32x4_t test_vmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
int64x2_t test_vmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
@@ -7978,7 +7977,7 @@ int64x2_t test_vmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
// CHECK: [[SUB_I:%.*]] = sub <4 x i32> %a, [[VMULL2_I_I]]
// CHECK: ret <4 x i32> [[SUB_I]]
uint32x4_t test_vmlsl_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
@@ -7990,7 +7989,7 @@ uint32x4_t test_vmlsl_n_u16(uint32x4_t a, uint16x4_t b, uint16_t c) {
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VMULL2_I_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
// CHECK: [[SUB_I:%.*]] = sub <2 x i64> %a, [[VMULL2_I_I]]
// CHECK: ret <2 x i64> [[SUB_I]]
uint64x2_t test_vmlsl_n_u32(uint64x2_t a, uint32x2_t b, uint32_t c) {
@@ -8696,7 +8695,7 @@ uint32x4_t test_vmulq_u32(uint32x4_t a, uint32x4_t b) {
}
// CHECK-LABEL: @test_vmull_s8(
-// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmulls.v8i16(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmulls.v8i16(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i16> [[VMULL_I]]
int16x8_t test_vmull_s8(int8x8_t a, int8x8_t b) {
return vmull_s8(a, b);
@@ -8705,7 +8704,7 @@ int16x8_t test_vmull_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vmull_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_s16(int16x4_t a, int16x4_t b) {
return vmull_s16(a, b);
@@ -8714,14 +8713,14 @@ int32x4_t test_vmull_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vmull_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_s32(int32x2_t a, int32x2_t b) {
return vmull_s32(a, b);
}
// CHECK-LABEL: @test_vmull_u8(
-// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i16> [[VMULL_I]]
uint16x8_t test_vmull_u8(uint8x8_t a, uint8x8_t b) {
return vmull_u8(a, b);
@@ -8730,7 +8729,7 @@ uint16x8_t test_vmull_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vmull_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %a, <4 x i16> %b)
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_u16(uint16x4_t a, uint16x4_t b) {
return vmull_u16(a, b);
@@ -8739,14 +8738,14 @@ uint32x4_t test_vmull_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vmull_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %a, <2 x i32> %b)
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_u32(uint32x2_t a, uint32x2_t b) {
return vmull_u32(a, b);
}
// CHECK-LABEL: @test_vmull_p8(
-// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullp.v8i16(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMULL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vmullp.v8i16(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i16> [[VMULL_I]]
poly16x8_t test_vmull_p8(poly8x8_t a, poly8x8_t b) {
return vmull_p8(a, b);
@@ -8756,7 +8755,7 @@ poly16x8_t test_vmull_p8(poly8x8_t a, poly8x8_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %b, <4 x i16> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
int32x4_t test_vmull_lane_s16(int16x4_t a, int16x4_t b) {
return vmull_lane_s16(a, b, 3);
@@ -8766,7 +8765,7 @@ int32x4_t test_vmull_lane_s16(int16x4_t a, int16x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %b, <2 x i32> %b, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
int64x2_t test_vmull_lane_s32(int32x2_t a, int32x2_t b) {
return vmull_lane_s32(a, b, 1);
@@ -8776,7 +8775,7 @@ int64x2_t test_vmull_lane_s32(int32x2_t a, int32x2_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %b, <4 x i16> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: ret <4 x i32> [[VMULL2_I]]
uint32x4_t test_vmull_lane_u16(uint16x4_t a, uint16x4_t b) {
return vmull_lane_u16(a, b, 3);
@@ -8786,7 +8785,7 @@ uint32x4_t test_vmull_lane_u16(uint16x4_t a, uint16x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %b, <2 x i32> %b, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VMULL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: ret <2 x i64> [[VMULL2_I]]
uint64x2_t test_vmull_lane_u32(uint32x2_t a, uint32x2_t b) {
return vmull_lane_u32(a, b, 1);
@@ -8799,7 +8798,7 @@ uint64x2_t test_vmull_lane_u32(uint32x2_t a, uint32x2_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmulls.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: ret <4 x i32> [[VMULL5_I]]
int32x4_t test_vmull_n_s16(int16x4_t a, int16_t b) {
return vmull_n_s16(a, b);
@@ -8810,7 +8809,7 @@ int32x4_t test_vmull_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmulls.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: ret <2 x i64> [[VMULL3_I]]
int64x2_t test_vmull_n_s32(int32x2_t a, int32_t b) {
return vmull_n_s32(a, b);
@@ -8823,7 +8822,7 @@ int64x2_t test_vmull_n_s32(int32x2_t a, int32_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VMULL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vmullu.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: ret <4 x i32> [[VMULL5_I]]
uint32x4_t test_vmull_n_u16(uint16x4_t a, uint16_t b) {
return vmull_n_u16(a, b);
@@ -8834,21 +8833,21 @@ uint32x4_t test_vmull_n_u16(uint16x4_t a, uint16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VMULL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vmullu.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: ret <2 x i64> [[VMULL3_I]]
uint64x2_t test_vmull_n_u32(uint32x2_t a, uint32_t b) {
return vmull_n_u32(a, b);
}
// CHECK-LABEL: @test_vmul_p8(
-// CHECK: [[VMUL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmulp.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VMUL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vmulp.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VMUL_V_I]]
poly8x8_t test_vmul_p8(poly8x8_t a, poly8x8_t b) {
return vmul_p8(a, b);
}
// CHECK-LABEL: @test_vmulq_p8(
-// CHECK: [[VMULQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmulp.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VMULQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vmulp.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VMULQ_V_I]]
poly8x16_t test_vmulq_p8(poly8x16_t a, poly8x16_t b) {
return vmulq_p8(a, b);
@@ -9442,7 +9441,7 @@ uint64x2_t test_vorrq_u64(uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vpadal_s8(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADAL_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadals.v4i16.v8i8(<4 x i16> %a, <8 x i8> %b) #4
+// CHECK: [[VPADAL_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadals.v4i16.v8i8(<4 x i16> %a, <8 x i8> %b)
// CHECK: ret <4 x i16> [[VPADAL_V1_I]]
int16x4_t test_vpadal_s8(int16x4_t a, int8x8_t b) {
return vpadal_s8(a, b);
@@ -9451,7 +9450,7 @@ int16x4_t test_vpadal_s8(int16x4_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpadal_s16(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADAL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadals.v2i32.v4i16(<2 x i32> %a, <4 x i16> %b) #4
+// CHECK: [[VPADAL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadals.v2i32.v4i16(<2 x i32> %a, <4 x i16> %b)
// CHECK: ret <2 x i32> [[VPADAL_V2_I]]
int32x2_t test_vpadal_s16(int32x2_t a, int16x4_t b) {
return vpadal_s16(a, b);
@@ -9460,7 +9459,7 @@ int32x2_t test_vpadal_s16(int32x2_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpadal_s32(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADAL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpadals.v1i64.v2i32(<1 x i64> %a, <2 x i32> %b) #4
+// CHECK: [[VPADAL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpadals.v1i64.v2i32(<1 x i64> %a, <2 x i32> %b)
// CHECK: ret <1 x i64> [[VPADAL_V2_I]]
int64x1_t test_vpadal_s32(int64x1_t a, int32x2_t b) {
return vpadal_s32(a, b);
@@ -9468,7 +9467,7 @@ int64x1_t test_vpadal_s32(int64x1_t a, int32x2_t b) {
// CHECK-LABEL: @test_vpadal_u8(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADAL_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadalu.v4i16.v8i8(<4 x i16> %a, <8 x i8> %b) #4
+// CHECK: [[VPADAL_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadalu.v4i16.v8i8(<4 x i16> %a, <8 x i8> %b)
// CHECK: ret <4 x i16> [[VPADAL_V1_I]]
uint16x4_t test_vpadal_u8(uint16x4_t a, uint8x8_t b) {
return vpadal_u8(a, b);
@@ -9477,7 +9476,7 @@ uint16x4_t test_vpadal_u8(uint16x4_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpadal_u16(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADAL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadalu.v2i32.v4i16(<2 x i32> %a, <4 x i16> %b) #4
+// CHECK: [[VPADAL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadalu.v2i32.v4i16(<2 x i32> %a, <4 x i16> %b)
// CHECK: ret <2 x i32> [[VPADAL_V2_I]]
uint32x2_t test_vpadal_u16(uint32x2_t a, uint16x4_t b) {
return vpadal_u16(a, b);
@@ -9486,7 +9485,7 @@ uint32x2_t test_vpadal_u16(uint32x2_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpadal_u32(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADAL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpadalu.v1i64.v2i32(<1 x i64> %a, <2 x i32> %b) #4
+// CHECK: [[VPADAL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpadalu.v1i64.v2i32(<1 x i64> %a, <2 x i32> %b)
// CHECK: ret <1 x i64> [[VPADAL_V2_I]]
uint64x1_t test_vpadal_u32(uint64x1_t a, uint32x2_t b) {
return vpadal_u32(a, b);
@@ -9494,7 +9493,7 @@ uint64x1_t test_vpadal_u32(uint64x1_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpadalq_s8(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADALQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpadals.v8i16.v16i8(<8 x i16> %a, <16 x i8> %b) #4
+// CHECK: [[VPADALQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpadals.v8i16.v16i8(<8 x i16> %a, <16 x i8> %b)
// CHECK: ret <8 x i16> [[VPADALQ_V1_I]]
int16x8_t test_vpadalq_s8(int16x8_t a, int8x16_t b) {
return vpadalq_s8(a, b);
@@ -9503,7 +9502,7 @@ int16x8_t test_vpadalq_s8(int16x8_t a, int8x16_t b) {
// CHECK-LABEL: @test_vpadalq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPADALQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpadals.v4i32.v8i16(<4 x i32> %a, <8 x i16> %b) #4
+// CHECK: [[VPADALQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpadals.v4i32.v8i16(<4 x i32> %a, <8 x i16> %b)
// CHECK: ret <4 x i32> [[VPADALQ_V2_I]]
int32x4_t test_vpadalq_s16(int32x4_t a, int16x8_t b) {
return vpadalq_s16(a, b);
@@ -9512,7 +9511,7 @@ int32x4_t test_vpadalq_s16(int32x4_t a, int16x8_t b) {
// CHECK-LABEL: @test_vpadalq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPADALQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpadals.v2i64.v4i32(<2 x i64> %a, <4 x i32> %b) #4
+// CHECK: [[VPADALQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpadals.v2i64.v4i32(<2 x i64> %a, <4 x i32> %b)
// CHECK: ret <2 x i64> [[VPADALQ_V2_I]]
int64x2_t test_vpadalq_s32(int64x2_t a, int32x4_t b) {
return vpadalq_s32(a, b);
@@ -9520,7 +9519,7 @@ int64x2_t test_vpadalq_s32(int64x2_t a, int32x4_t b) {
// CHECK-LABEL: @test_vpadalq_u8(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADALQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpadalu.v8i16.v16i8(<8 x i16> %a, <16 x i8> %b) #4
+// CHECK: [[VPADALQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpadalu.v8i16.v16i8(<8 x i16> %a, <16 x i8> %b)
// CHECK: ret <8 x i16> [[VPADALQ_V1_I]]
uint16x8_t test_vpadalq_u8(uint16x8_t a, uint8x16_t b) {
return vpadalq_u8(a, b);
@@ -9529,7 +9528,7 @@ uint16x8_t test_vpadalq_u8(uint16x8_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vpadalq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VPADALQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpadalu.v4i32.v8i16(<4 x i32> %a, <8 x i16> %b) #4
+// CHECK: [[VPADALQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpadalu.v4i32.v8i16(<4 x i32> %a, <8 x i16> %b)
// CHECK: ret <4 x i32> [[VPADALQ_V2_I]]
uint32x4_t test_vpadalq_u16(uint32x4_t a, uint16x8_t b) {
return vpadalq_u16(a, b);
@@ -9538,14 +9537,14 @@ uint32x4_t test_vpadalq_u16(uint32x4_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vpadalq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VPADALQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpadalu.v2i64.v4i32(<2 x i64> %a, <4 x i32> %b) #4
+// CHECK: [[VPADALQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpadalu.v2i64.v4i32(<2 x i64> %a, <4 x i32> %b)
// CHECK: ret <2 x i64> [[VPADALQ_V2_I]]
uint64x2_t test_vpadalq_u32(uint64x2_t a, uint32x4_t b) {
return vpadalq_u32(a, b);
}
// CHECK-LABEL: @test_vpadd_s8(
-// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpadd.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpadd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPADD_V_I]]
int8x8_t test_vpadd_s8(int8x8_t a, int8x8_t b) {
return vpadd_s8(a, b);
@@ -9554,7 +9553,7 @@ int8x8_t test_vpadd_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadd.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <4 x i16> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPADD_V2_I]]
int16x4_t test_vpadd_s16(int16x4_t a, int16x4_t b) {
@@ -9564,7 +9563,7 @@ int16x4_t test_vpadd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadd.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <2 x i32> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPADD_V2_I]]
int32x2_t test_vpadd_s32(int32x2_t a, int32x2_t b) {
@@ -9572,7 +9571,7 @@ int32x2_t test_vpadd_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vpadd_u8(
-// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpadd.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpadd.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPADD_V_I]]
uint8x8_t test_vpadd_u8(uint8x8_t a, uint8x8_t b) {
return vpadd_u8(a, b);
@@ -9581,7 +9580,7 @@ uint8x8_t test_vpadd_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadd.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpadd.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <4 x i16> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPADD_V2_I]]
uint16x4_t test_vpadd_u16(uint16x4_t a, uint16x4_t b) {
@@ -9591,7 +9590,7 @@ uint16x4_t test_vpadd_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadd.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpadd.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <2 x i32> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPADD_V2_I]]
uint32x2_t test_vpadd_u32(uint32x2_t a, uint32x2_t b) {
@@ -9601,7 +9600,7 @@ uint32x2_t test_vpadd_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpadd_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPADD_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vpadd.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPADD_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vpadd.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VPADD_V3_I:%.*]] = bitcast <2 x float> [[VPADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VPADD_V2_I]]
float32x2_t test_vpadd_f32(float32x2_t a, float32x2_t b) {
@@ -9609,7 +9608,7 @@ float32x2_t test_vpadd_f32(float32x2_t a, float32x2_t b) {
}
// CHECK-LABEL: @test_vpaddl_s8(
-// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpaddls.v4i16.v8i8(<8 x i8> %a) #4
+// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpaddls.v4i16.v8i8(<8 x i8> %a)
// CHECK: ret <4 x i16> [[VPADDL_I]]
int16x4_t test_vpaddl_s8(int8x8_t a) {
return vpaddl_s8(a);
@@ -9617,7 +9616,7 @@ int16x4_t test_vpaddl_s8(int8x8_t a) {
// CHECK-LABEL: @test_vpaddl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpaddls.v2i32.v4i16(<4 x i16> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpaddls.v2i32.v4i16(<4 x i16> %a)
// CHECK: ret <2 x i32> [[VPADDL1_I]]
int32x2_t test_vpaddl_s16(int16x4_t a) {
return vpaddl_s16(a);
@@ -9625,14 +9624,14 @@ int32x2_t test_vpaddl_s16(int16x4_t a) {
// CHECK-LABEL: @test_vpaddl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpaddls.v1i64.v2i32(<2 x i32> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpaddls.v1i64.v2i32(<2 x i32> %a)
// CHECK: ret <1 x i64> [[VPADDL1_I]]
int64x1_t test_vpaddl_s32(int32x2_t a) {
return vpaddl_s32(a);
}
// CHECK-LABEL: @test_vpaddl_u8(
-// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpaddlu.v4i16.v8i8(<8 x i8> %a) #4
+// CHECK: [[VPADDL_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpaddlu.v4i16.v8i8(<8 x i8> %a)
// CHECK: ret <4 x i16> [[VPADDL_I]]
uint16x4_t test_vpaddl_u8(uint8x8_t a) {
return vpaddl_u8(a);
@@ -9640,7 +9639,7 @@ uint16x4_t test_vpaddl_u8(uint8x8_t a) {
// CHECK-LABEL: @test_vpaddl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpaddlu.v2i32.v4i16(<4 x i16> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpaddlu.v2i32.v4i16(<4 x i16> %a)
// CHECK: ret <2 x i32> [[VPADDL1_I]]
uint32x2_t test_vpaddl_u16(uint16x4_t a) {
return vpaddl_u16(a);
@@ -9648,14 +9647,14 @@ uint32x2_t test_vpaddl_u16(uint16x4_t a) {
// CHECK-LABEL: @test_vpaddl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpaddlu.v1i64.v2i32(<2 x i32> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <1 x i64> @llvm.arm.neon.vpaddlu.v1i64.v2i32(<2 x i32> %a)
// CHECK: ret <1 x i64> [[VPADDL1_I]]
uint64x1_t test_vpaddl_u32(uint32x2_t a) {
return vpaddl_u32(a);
}
// CHECK-LABEL: @test_vpaddlq_s8(
-// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpaddls.v8i16.v16i8(<16 x i8> %a) #4
+// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpaddls.v8i16.v16i8(<16 x i8> %a)
// CHECK: ret <8 x i16> [[VPADDL_I]]
int16x8_t test_vpaddlq_s8(int8x16_t a) {
return vpaddlq_s8(a);
@@ -9663,7 +9662,7 @@ int16x8_t test_vpaddlq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vpaddlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpaddls.v4i32.v8i16(<8 x i16> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpaddls.v4i32.v8i16(<8 x i16> %a)
// CHECK: ret <4 x i32> [[VPADDL1_I]]
int32x4_t test_vpaddlq_s16(int16x8_t a) {
return vpaddlq_s16(a);
@@ -9671,14 +9670,14 @@ int32x4_t test_vpaddlq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vpaddlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpaddls.v2i64.v4i32(<4 x i32> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpaddls.v2i64.v4i32(<4 x i32> %a)
// CHECK: ret <2 x i64> [[VPADDL1_I]]
int64x2_t test_vpaddlq_s32(int32x4_t a) {
return vpaddlq_s32(a);
}
// CHECK-LABEL: @test_vpaddlq_u8(
-// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpaddlu.v8i16.v16i8(<16 x i8> %a) #4
+// CHECK: [[VPADDL_I:%.*]] = call <8 x i16> @llvm.arm.neon.vpaddlu.v8i16.v16i8(<16 x i8> %a)
// CHECK: ret <8 x i16> [[VPADDL_I]]
uint16x8_t test_vpaddlq_u8(uint8x16_t a) {
return vpaddlq_u8(a);
@@ -9686,7 +9685,7 @@ uint16x8_t test_vpaddlq_u8(uint8x16_t a) {
// CHECK-LABEL: @test_vpaddlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpaddlu.v4i32.v8i16(<8 x i16> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vpaddlu.v4i32.v8i16(<8 x i16> %a)
// CHECK: ret <4 x i32> [[VPADDL1_I]]
uint32x4_t test_vpaddlq_u16(uint16x8_t a) {
return vpaddlq_u16(a);
@@ -9694,14 +9693,14 @@ uint32x4_t test_vpaddlq_u16(uint16x8_t a) {
// CHECK-LABEL: @test_vpaddlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpaddlu.v2i64.v4i32(<4 x i32> %a) #4
+// CHECK: [[VPADDL1_I:%.*]] = call <2 x i64> @llvm.arm.neon.vpaddlu.v2i64.v4i32(<4 x i32> %a)
// CHECK: ret <2 x i64> [[VPADDL1_I]]
uint64x2_t test_vpaddlq_u32(uint32x4_t a) {
return vpaddlq_u32(a);
}
// CHECK-LABEL: @test_vpmax_s8(
-// CHECK: [[VPMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpmaxs.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpmaxs.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMAX_V_I]]
int8x8_t test_vpmax_s8(int8x8_t a, int8x8_t b) {
return vpmax_s8(a, b);
@@ -9710,7 +9709,7 @@ int8x8_t test_vpmax_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpmax_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpmaxs.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpmaxs.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPMAX_V3_I:%.*]] = bitcast <4 x i16> [[VPMAX_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPMAX_V2_I]]
int16x4_t test_vpmax_s16(int16x4_t a, int16x4_t b) {
@@ -9720,7 +9719,7 @@ int16x4_t test_vpmax_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpmax_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpmaxs.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpmaxs.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPMAX_V3_I:%.*]] = bitcast <2 x i32> [[VPMAX_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPMAX_V2_I]]
int32x2_t test_vpmax_s32(int32x2_t a, int32x2_t b) {
@@ -9728,7 +9727,7 @@ int32x2_t test_vpmax_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vpmax_u8(
-// CHECK: [[VPMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpmaxu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMAX_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpmaxu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMAX_V_I]]
uint8x8_t test_vpmax_u8(uint8x8_t a, uint8x8_t b) {
return vpmax_u8(a, b);
@@ -9737,7 +9736,7 @@ uint8x8_t test_vpmax_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpmax_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpmaxu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMAX_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpmaxu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPMAX_V3_I:%.*]] = bitcast <4 x i16> [[VPMAX_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPMAX_V2_I]]
uint16x4_t test_vpmax_u16(uint16x4_t a, uint16x4_t b) {
@@ -9747,7 +9746,7 @@ uint16x4_t test_vpmax_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpmax_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpmaxu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMAX_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpmaxu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPMAX_V3_I:%.*]] = bitcast <2 x i32> [[VPMAX_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPMAX_V2_I]]
uint32x2_t test_vpmax_u32(uint32x2_t a, uint32x2_t b) {
@@ -9757,7 +9756,7 @@ uint32x2_t test_vpmax_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpmax_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPMAX_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vpmaxs.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPMAX_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vpmaxs.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VPMAX_V3_I:%.*]] = bitcast <2 x float> [[VPMAX_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VPMAX_V2_I]]
float32x2_t test_vpmax_f32(float32x2_t a, float32x2_t b) {
@@ -9765,7 +9764,7 @@ float32x2_t test_vpmax_f32(float32x2_t a, float32x2_t b) {
}
// CHECK-LABEL: @test_vpmin_s8(
-// CHECK: [[VPMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpmins.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpmins.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMIN_V_I]]
int8x8_t test_vpmin_s8(int8x8_t a, int8x8_t b) {
return vpmin_s8(a, b);
@@ -9774,7 +9773,7 @@ int8x8_t test_vpmin_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vpmin_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpmins.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpmins.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPMIN_V3_I:%.*]] = bitcast <4 x i16> [[VPMIN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPMIN_V2_I]]
int16x4_t test_vpmin_s16(int16x4_t a, int16x4_t b) {
@@ -9784,7 +9783,7 @@ int16x4_t test_vpmin_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vpmin_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpmins.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpmins.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPMIN_V3_I:%.*]] = bitcast <2 x i32> [[VPMIN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPMIN_V2_I]]
int32x2_t test_vpmin_s32(int32x2_t a, int32x2_t b) {
@@ -9792,7 +9791,7 @@ int32x2_t test_vpmin_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vpmin_u8(
-// CHECK: [[VPMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpminu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VPMIN_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vpminu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VPMIN_V_I]]
uint8x8_t test_vpmin_u8(uint8x8_t a, uint8x8_t b) {
return vpmin_u8(a, b);
@@ -9801,7 +9800,7 @@ uint8x8_t test_vpmin_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vpmin_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VPMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpminu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VPMIN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vpminu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VPMIN_V3_I:%.*]] = bitcast <4 x i16> [[VPMIN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VPMIN_V2_I]]
uint16x4_t test_vpmin_u16(uint16x4_t a, uint16x4_t b) {
@@ -9811,7 +9810,7 @@ uint16x4_t test_vpmin_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vpmin_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VPMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpminu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VPMIN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vpminu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VPMIN_V3_I:%.*]] = bitcast <2 x i32> [[VPMIN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VPMIN_V2_I]]
uint32x2_t test_vpmin_u32(uint32x2_t a, uint32x2_t b) {
@@ -9821,7 +9820,7 @@ uint32x2_t test_vpmin_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vpmin_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VPMIN_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vpmins.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VPMIN_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vpmins.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VPMIN_V3_I:%.*]] = bitcast <2 x float> [[VPMIN_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VPMIN_V2_I]]
float32x2_t test_vpmin_f32(float32x2_t a, float32x2_t b) {
@@ -9829,7 +9828,7 @@ float32x2_t test_vpmin_f32(float32x2_t a, float32x2_t b) {
}
// CHECK-LABEL: @test_vqabs_s8(
-// CHECK: [[VQABS_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqabs.v8i8(<8 x i8> %a) #4
+// CHECK: [[VQABS_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqabs.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VQABS_V_I]]
int8x8_t test_vqabs_s8(int8x8_t a) {
return vqabs_s8(a);
@@ -9837,7 +9836,7 @@ int8x8_t test_vqabs_s8(int8x8_t a) {
// CHECK-LABEL: @test_vqabs_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VQABS_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqabs.v4i16(<4 x i16> %a) #4
+// CHECK: [[VQABS_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqabs.v4i16(<4 x i16> %a)
// CHECK: [[VQABS_V2_I:%.*]] = bitcast <4 x i16> [[VQABS_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQABS_V1_I]]
int16x4_t test_vqabs_s16(int16x4_t a) {
@@ -9846,7 +9845,7 @@ int16x4_t test_vqabs_s16(int16x4_t a) {
// CHECK-LABEL: @test_vqabs_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VQABS_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqabs.v2i32(<2 x i32> %a) #4
+// CHECK: [[VQABS_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqabs.v2i32(<2 x i32> %a)
// CHECK: [[VQABS_V2_I:%.*]] = bitcast <2 x i32> [[VQABS_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQABS_V1_I]]
int32x2_t test_vqabs_s32(int32x2_t a) {
@@ -9854,7 +9853,7 @@ int32x2_t test_vqabs_s32(int32x2_t a) {
}
// CHECK-LABEL: @test_vqabsq_s8(
-// CHECK: [[VQABSQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqabs.v16i8(<16 x i8> %a) #4
+// CHECK: [[VQABSQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqabs.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VQABSQ_V_I]]
int8x16_t test_vqabsq_s8(int8x16_t a) {
return vqabsq_s8(a);
@@ -9862,7 +9861,7 @@ int8x16_t test_vqabsq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vqabsq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQABSQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqabs.v8i16(<8 x i16> %a) #4
+// CHECK: [[VQABSQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqabs.v8i16(<8 x i16> %a)
// CHECK: [[VQABSQ_V2_I:%.*]] = bitcast <8 x i16> [[VQABSQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQABSQ_V1_I]]
int16x8_t test_vqabsq_s16(int16x8_t a) {
@@ -9871,7 +9870,7 @@ int16x8_t test_vqabsq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqabsq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQABSQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqabs.v4i32(<4 x i32> %a) #4
+// CHECK: [[VQABSQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqabs.v4i32(<4 x i32> %a)
// CHECK: [[VQABSQ_V2_I:%.*]] = bitcast <4 x i32> [[VQABSQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQABSQ_V1_I]]
int32x4_t test_vqabsq_s32(int32x4_t a) {
@@ -9879,7 +9878,7 @@ int32x4_t test_vqabsq_s32(int32x4_t a) {
}
// CHECK-LABEL: @test_vqadd_s8(
-// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqadds.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqadds.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQADD_V_I]]
int8x8_t test_vqadd_s8(int8x8_t a, int8x8_t b) {
return vqadd_s8(a, b);
@@ -9888,7 +9887,7 @@ int8x8_t test_vqadd_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqadds.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqadds.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <4 x i16> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQADD_V2_I]]
int16x4_t test_vqadd_s16(int16x4_t a, int16x4_t b) {
@@ -9898,7 +9897,7 @@ int16x4_t test_vqadd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqadds.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqadds.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <2 x i32> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQADD_V2_I]]
int32x2_t test_vqadd_s32(int32x2_t a, int32x2_t b) {
@@ -9908,7 +9907,7 @@ int32x2_t test_vqadd_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqadd_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqadds.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqadds.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <1 x i64> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQADD_V2_I]]
int64x1_t test_vqadd_s64(int64x1_t a, int64x1_t b) {
@@ -9916,7 +9915,7 @@ int64x1_t test_vqadd_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqadd_u8(
-// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqaddu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqaddu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQADD_V_I]]
uint8x8_t test_vqadd_u8(uint8x8_t a, uint8x8_t b) {
return vqadd_u8(a, b);
@@ -9925,7 +9924,7 @@ uint8x8_t test_vqadd_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vqadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqaddu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqaddu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <4 x i16> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQADD_V2_I]]
uint16x4_t test_vqadd_u16(uint16x4_t a, uint16x4_t b) {
@@ -9935,7 +9934,7 @@ uint16x4_t test_vqadd_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vqadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqaddu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqaddu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <2 x i32> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQADD_V2_I]]
uint32x2_t test_vqadd_u32(uint32x2_t a, uint32x2_t b) {
@@ -9945,7 +9944,7 @@ uint32x2_t test_vqadd_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vqadd_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqaddu.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQADD_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqaddu.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQADD_V3_I:%.*]] = bitcast <1 x i64> [[VQADD_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQADD_V2_I]]
uint64x1_t test_vqadd_u64(uint64x1_t a, uint64x1_t b) {
@@ -9953,7 +9952,7 @@ uint64x1_t test_vqadd_u64(uint64x1_t a, uint64x1_t b) {
}
// CHECK-LABEL: @test_vqaddq_s8(
-// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqadds.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqadds.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQADDQ_V_I]]
int8x16_t test_vqaddq_s8(int8x16_t a, int8x16_t b) {
return vqaddq_s8(a, b);
@@ -9962,7 +9961,7 @@ int8x16_t test_vqaddq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqadds.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqadds.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQADDQ_V2_I]]
int16x8_t test_vqaddq_s16(int16x8_t a, int16x8_t b) {
@@ -9972,7 +9971,7 @@ int16x8_t test_vqaddq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQADDQ_V2_I]]
int32x4_t test_vqaddq_s32(int32x4_t a, int32x4_t b) {
@@ -9982,7 +9981,7 @@ int32x4_t test_vqaddq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqaddq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <2 x i64> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQADDQ_V2_I]]
int64x2_t test_vqaddq_s64(int64x2_t a, int64x2_t b) {
@@ -9990,7 +9989,7 @@ int64x2_t test_vqaddq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqaddq_u8(
-// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqaddu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqaddu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQADDQ_V_I]]
uint8x16_t test_vqaddq_u8(uint8x16_t a, uint8x16_t b) {
return vqaddq_u8(a, b);
@@ -9999,7 +9998,7 @@ uint8x16_t test_vqaddq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vqaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqaddu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqaddu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQADDQ_V2_I]]
uint16x8_t test_vqaddq_u16(uint16x8_t a, uint16x8_t b) {
@@ -10009,7 +10008,7 @@ uint16x8_t test_vqaddq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vqaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqaddu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqaddu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQADDQ_V2_I]]
uint32x4_t test_vqaddq_u32(uint32x4_t a, uint32x4_t b) {
@@ -10019,7 +10018,7 @@ uint32x4_t test_vqaddq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vqaddq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqaddu.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQADDQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqaddu.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQADDQ_V3_I:%.*]] = bitcast <2 x i64> [[VQADDQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQADDQ_V2_I]]
uint64x2_t test_vqaddq_u64(uint64x2_t a, uint64x2_t b) {
@@ -10030,8 +10029,8 @@ uint64x2_t test_vqaddq_u64(uint64x2_t a, uint64x2_t b) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> %c)
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
return vqdmlal_s16(a, b, c);
@@ -10041,8 +10040,8 @@ int32x4_t test_vqdmlal_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> %c)
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
return vqdmlal_s32(a, b, c);
@@ -10053,8 +10052,8 @@ int64x2_t test_vqdmlal_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #4
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V3_I]]
int32x4_t test_vqdmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
return vqdmlal_lane_s16(a, b, c, 3);
@@ -10065,8 +10064,8 @@ int32x4_t test_vqdmlal_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #4
-// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLAL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V3_I]]
int64x2_t test_vqdmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
return vqdmlal_lane_s32(a, b, c, 1);
@@ -10080,8 +10079,8 @@ int64x2_t test_vqdmlal_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %c, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #4
-// CHECK: [[VQDMLAL_V6_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]]) #4
+// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
+// CHECK: [[VQDMLAL_V6_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqadds.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]])
// CHECK: ret <4 x i32> [[VQDMLAL_V6_I]]
int32x4_t test_vqdmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
return vqdmlal_n_s16(a, b, c);
@@ -10093,8 +10092,8 @@ int32x4_t test_vqdmlal_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %c, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #4
-// CHECK: [[VQDMLAL_V4_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]]) #4
+// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
+// CHECK: [[VQDMLAL_V4_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqadds.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]])
// CHECK: ret <2 x i64> [[VQDMLAL_V4_I]]
int64x2_t test_vqdmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
return vqdmlal_n_s32(a, b, c);
@@ -10104,8 +10103,8 @@ int64x2_t test_vqdmlal_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> %c) #4
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> %c)
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
return vqdmlsl_s16(a, b, c);
@@ -10115,8 +10114,8 @@ int32x4_t test_vqdmlsl_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %c to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> %c) #4
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> %c)
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
return vqdmlsl_s32(a, b, c);
@@ -10127,8 +10126,8 @@ int64x2_t test_vqdmlsl_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]]) #4
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL2_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V3_I]]
int32x4_t test_vqdmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
return vqdmlsl_lane_s16(a, b, c, 3);
@@ -10139,8 +10138,8 @@ int32x4_t test_vqdmlsl_lane_s16(int32x4_t a, int16x4_t b, int16x4_t c) {
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]]) #4
-// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]]) #4
+// CHECK: [[VQDMLAL2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[SHUFFLE]])
+// CHECK: [[VQDMLSL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL2_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V3_I]]
int64x2_t test_vqdmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
return vqdmlsl_lane_s32(a, b, c, 1);
@@ -10154,8 +10153,8 @@ int64x2_t test_vqdmlsl_lane_s32(int64x2_t a, int32x2_t b, int32x2_t c) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %c, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %c, i32 3
// CHECK: [[TMP2:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]]) #4
-// CHECK: [[VQDMLSL_V6_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]]) #4
+// CHECK: [[VQDMLAL5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %b, <4 x i16> [[VECINIT3_I]])
+// CHECK: [[VQDMLSL_V6_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> [[VQDMLAL5_I]])
// CHECK: ret <4 x i32> [[VQDMLSL_V6_I]]
int32x4_t test_vqdmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
return vqdmlsl_n_s16(a, b, c);
@@ -10167,8 +10166,8 @@ int32x4_t test_vqdmlsl_n_s16(int32x4_t a, int16x4_t b, int16_t c) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %c, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %c, i32 1
// CHECK: [[TMP2:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]]) #4
-// CHECK: [[VQDMLSL_V4_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]]) #4
+// CHECK: [[VQDMLAL3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %b, <2 x i32> [[VECINIT1_I]])
+// CHECK: [[VQDMLSL_V4_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> [[VQDMLAL3_I]])
// CHECK: ret <2 x i64> [[VQDMLSL_V4_I]]
int64x2_t test_vqdmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
return vqdmlsl_n_s32(a, b, c);
@@ -10177,7 +10176,7 @@ int64x2_t test_vqdmlsl_n_s32(int64x2_t a, int32x2_t b, int32_t c) {
// CHECK-LABEL: @test_vqdmulh_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqdmulh.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqdmulh.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V2_I]]
int16x4_t test_vqdmulh_s16(int16x4_t a, int16x4_t b) {
@@ -10187,7 +10186,7 @@ int16x4_t test_vqdmulh_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqdmulh_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqdmulh.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqdmulh.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V2_I]]
int32x2_t test_vqdmulh_s32(int32x2_t a, int32x2_t b) {
@@ -10197,7 +10196,7 @@ int32x2_t test_vqdmulh_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqdmulhq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqdmulh.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqdmulh.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V2_I]]
int16x8_t test_vqdmulhq_s16(int16x8_t a, int16x8_t b) {
@@ -10207,7 +10206,7 @@ int16x8_t test_vqdmulhq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqdmulhq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmulh.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmulh.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V2_I]]
int32x4_t test_vqdmulhq_s32(int32x4_t a, int32x4_t b) {
@@ -10218,7 +10217,7 @@ int32x4_t test_vqdmulhq_s32(int32x4_t a, int32x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %b, <4 x i16> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V2_I]]
int16x4_t test_vqdmulh_lane_s16(int16x4_t a, int16x4_t b) {
@@ -10229,7 +10228,7 @@ int16x4_t test_vqdmulh_lane_s16(int16x4_t a, int16x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %b, <2 x i32> %b, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VQDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V2_I]]
int32x2_t test_vqdmulh_lane_s32(int32x2_t a, int32x2_t b) {
@@ -10240,7 +10239,7 @@ int32x2_t test_vqdmulh_lane_s32(int32x2_t a, int32x2_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %b, <4 x i16> %b, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V2_I]]
int16x8_t test_vqdmulhq_lane_s16(int16x8_t a, int16x4_t b) {
@@ -10251,7 +10250,7 @@ int16x8_t test_vqdmulhq_lane_s16(int16x8_t a, int16x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %b, <2 x i32> %b, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VQDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V2_I]]
int32x4_t test_vqdmulhq_lane_s32(int32x4_t a, int32x2_t b) {
@@ -10265,7 +10264,7 @@ int32x4_t test_vqdmulhq_lane_s32(int32x4_t a, int32x2_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMULH_V5_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VQDMULH_V5_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: [[VQDMULH_V6_I:%.*]] = bitcast <4 x i16> [[VQDMULH_V5_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQDMULH_V5_I]]
int16x4_t test_vqdmulh_n_s16(int16x4_t a, int16_t b) {
@@ -10277,7 +10276,7 @@ int16x4_t test_vqdmulh_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMULH_V3_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VQDMULH_V3_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: [[VQDMULH_V4_I:%.*]] = bitcast <2 x i32> [[VQDMULH_V3_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQDMULH_V3_I]]
int32x2_t test_vqdmulh_n_s32(int32x2_t a, int32_t b) {
@@ -10295,7 +10294,7 @@ int32x2_t test_vqdmulh_n_s32(int32x2_t a, int32_t b) {
// CHECK: [[VECINIT6_I:%.*]] = insertelement <8 x i16> [[VECINIT5_I]], i16 %b, i32 6
// CHECK: [[VECINIT7_I:%.*]] = insertelement <8 x i16> [[VECINIT6_I]], i16 %b, i32 7
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[VECINIT7_I]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]]) #4
+// CHECK: [[VQDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]])
// CHECK: [[VQDMULHQ_V10_I:%.*]] = bitcast <8 x i16> [[VQDMULHQ_V9_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQDMULHQ_V9_I]]
int16x8_t test_vqdmulhq_n_s16(int16x8_t a, int16_t b) {
@@ -10309,7 +10308,7 @@ int16x8_t test_vqdmulhq_n_s16(int16x8_t a, int16_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i32> [[VECINIT1_I]], i32 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i32> [[VECINIT2_I]], i32 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[VECINIT3_I]] to <16 x i8>
-// CHECK: [[VQDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]]) #4
+// CHECK: [[VQDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]])
// CHECK: [[VQDMULHQ_V6_I:%.*]] = bitcast <4 x i32> [[VQDMULHQ_V5_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULHQ_V5_I]]
int32x4_t test_vqdmulhq_n_s32(int32x4_t a, int32_t b) {
@@ -10319,7 +10318,7 @@ int32x4_t test_vqdmulhq_n_s32(int32x4_t a, int32_t b) {
// CHECK-LABEL: @test_vqdmull_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_s16(int16x4_t a, int16x4_t b) {
@@ -10329,7 +10328,7 @@ int32x4_t test_vqdmull_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqdmull_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_s32(int32x2_t a, int32x2_t b) {
@@ -10340,7 +10339,7 @@ int64x2_t test_vqdmull_s32(int32x2_t a, int32x2_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %b, <4 x i16> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V2_I]]
int32x4_t test_vqdmull_lane_s16(int16x4_t a, int16x4_t b) {
@@ -10351,7 +10350,7 @@ int32x4_t test_vqdmull_lane_s16(int16x4_t a, int16x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %b, <2 x i32> %b, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VQDMULL_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQDMULL_V3_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V2_I]]
int64x2_t test_vqdmull_lane_s32(int32x2_t a, int32x2_t b) {
@@ -10365,7 +10364,7 @@ int64x2_t test_vqdmull_lane_s32(int32x2_t a, int32x2_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VQDMULL_V5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqdmull.v4i32(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: [[VQDMULL_V6_I:%.*]] = bitcast <4 x i32> [[VQDMULL_V5_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQDMULL_V5_I]]
int32x4_t test_vqdmull_n_s16(int16x4_t a, int16_t b) {
@@ -10377,7 +10376,7 @@ int32x4_t test_vqdmull_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQDMULL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VQDMULL_V3_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqdmull.v2i64(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: [[VQDMULL_V4_I:%.*]] = bitcast <2 x i64> [[VQDMULL_V3_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQDMULL_V3_I]]
int64x2_t test_vqdmull_n_s32(int32x2_t a, int32_t b) {
@@ -10386,7 +10385,7 @@ int64x2_t test_vqdmull_n_s32(int32x2_t a, int32_t b) {
// CHECK-LABEL: @test_vqmovn_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqmovns.v8i8(<8 x i16> %a) #4
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqmovns.v8i8(<8 x i16> %a)
// CHECK: ret <8 x i8> [[VQMOVN_V1_I]]
int8x8_t test_vqmovn_s16(int16x8_t a) {
return vqmovn_s16(a);
@@ -10394,7 +10393,7 @@ int8x8_t test_vqmovn_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqmovn_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqmovns.v4i16(<4 x i32> %a) #4
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqmovns.v4i16(<4 x i32> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <4 x i16> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQMOVN_V1_I]]
int16x4_t test_vqmovn_s32(int32x4_t a) {
@@ -10403,7 +10402,7 @@ int16x4_t test_vqmovn_s32(int32x4_t a) {
// CHECK-LABEL: @test_vqmovn_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqmovns.v2i32(<2 x i64> %a) #4
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqmovns.v2i32(<2 x i64> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <2 x i32> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQMOVN_V1_I]]
int32x2_t test_vqmovn_s64(int64x2_t a) {
@@ -10412,7 +10411,7 @@ int32x2_t test_vqmovn_s64(int64x2_t a) {
// CHECK-LABEL: @test_vqmovn_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqmovnu.v8i8(<8 x i16> %a) #4
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqmovnu.v8i8(<8 x i16> %a)
// CHECK: ret <8 x i8> [[VQMOVN_V1_I]]
uint8x8_t test_vqmovn_u16(uint16x8_t a) {
return vqmovn_u16(a);
@@ -10420,7 +10419,7 @@ uint8x8_t test_vqmovn_u16(uint16x8_t a) {
// CHECK-LABEL: @test_vqmovn_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqmovnu.v4i16(<4 x i32> %a) #4
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqmovnu.v4i16(<4 x i32> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <4 x i16> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQMOVN_V1_I]]
uint16x4_t test_vqmovn_u32(uint32x4_t a) {
@@ -10429,7 +10428,7 @@ uint16x4_t test_vqmovn_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vqmovn_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqmovnu.v2i32(<2 x i64> %a) #4
+// CHECK: [[VQMOVN_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqmovnu.v2i32(<2 x i64> %a)
// CHECK: [[VQMOVN_V2_I:%.*]] = bitcast <2 x i32> [[VQMOVN_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQMOVN_V1_I]]
uint32x2_t test_vqmovn_u64(uint64x2_t a) {
@@ -10438,7 +10437,7 @@ uint32x2_t test_vqmovn_u64(uint64x2_t a) {
// CHECK-LABEL: @test_vqmovun_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqmovnsu.v8i8(<8 x i16> %a) #4
+// CHECK: [[VQMOVUN_V1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqmovnsu.v8i8(<8 x i16> %a)
// CHECK: ret <8 x i8> [[VQMOVUN_V1_I]]
uint8x8_t test_vqmovun_s16(int16x8_t a) {
return vqmovun_s16(a);
@@ -10446,7 +10445,7 @@ uint8x8_t test_vqmovun_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqmovun_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqmovnsu.v4i16(<4 x i32> %a) #4
+// CHECK: [[VQMOVUN_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqmovnsu.v4i16(<4 x i32> %a)
// CHECK: [[VQMOVUN_V2_I:%.*]] = bitcast <4 x i16> [[VQMOVUN_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQMOVUN_V1_I]]
uint16x4_t test_vqmovun_s32(int32x4_t a) {
@@ -10455,7 +10454,7 @@ uint16x4_t test_vqmovun_s32(int32x4_t a) {
// CHECK-LABEL: @test_vqmovun_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
-// CHECK: [[VQMOVUN_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqmovnsu.v2i32(<2 x i64> %a) #4
+// CHECK: [[VQMOVUN_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqmovnsu.v2i32(<2 x i64> %a)
// CHECK: [[VQMOVUN_V2_I:%.*]] = bitcast <2 x i32> [[VQMOVUN_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQMOVUN_V1_I]]
uint32x2_t test_vqmovun_s64(int64x2_t a) {
@@ -10463,7 +10462,7 @@ uint32x2_t test_vqmovun_s64(int64x2_t a) {
}
// CHECK-LABEL: @test_vqneg_s8(
-// CHECK: [[VQNEG_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqneg.v8i8(<8 x i8> %a) #4
+// CHECK: [[VQNEG_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqneg.v8i8(<8 x i8> %a)
// CHECK: ret <8 x i8> [[VQNEG_V_I]]
int8x8_t test_vqneg_s8(int8x8_t a) {
return vqneg_s8(a);
@@ -10471,7 +10470,7 @@ int8x8_t test_vqneg_s8(int8x8_t a) {
// CHECK-LABEL: @test_vqneg_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
-// CHECK: [[VQNEG_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqneg.v4i16(<4 x i16> %a) #4
+// CHECK: [[VQNEG_V1_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqneg.v4i16(<4 x i16> %a)
// CHECK: [[VQNEG_V2_I:%.*]] = bitcast <4 x i16> [[VQNEG_V1_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQNEG_V1_I]]
int16x4_t test_vqneg_s16(int16x4_t a) {
@@ -10480,7 +10479,7 @@ int16x4_t test_vqneg_s16(int16x4_t a) {
// CHECK-LABEL: @test_vqneg_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VQNEG_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqneg.v2i32(<2 x i32> %a) #4
+// CHECK: [[VQNEG_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqneg.v2i32(<2 x i32> %a)
// CHECK: [[VQNEG_V2_I:%.*]] = bitcast <2 x i32> [[VQNEG_V1_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQNEG_V1_I]]
int32x2_t test_vqneg_s32(int32x2_t a) {
@@ -10488,7 +10487,7 @@ int32x2_t test_vqneg_s32(int32x2_t a) {
}
// CHECK-LABEL: @test_vqnegq_s8(
-// CHECK: [[VQNEGQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqneg.v16i8(<16 x i8> %a) #4
+// CHECK: [[VQNEGQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqneg.v16i8(<16 x i8> %a)
// CHECK: ret <16 x i8> [[VQNEGQ_V_I]]
int8x16_t test_vqnegq_s8(int8x16_t a) {
return vqnegq_s8(a);
@@ -10496,7 +10495,7 @@ int8x16_t test_vqnegq_s8(int8x16_t a) {
// CHECK-LABEL: @test_vqnegq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
-// CHECK: [[VQNEGQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqneg.v8i16(<8 x i16> %a) #4
+// CHECK: [[VQNEGQ_V1_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqneg.v8i16(<8 x i16> %a)
// CHECK: [[VQNEGQ_V2_I:%.*]] = bitcast <8 x i16> [[VQNEGQ_V1_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQNEGQ_V1_I]]
int16x8_t test_vqnegq_s16(int16x8_t a) {
@@ -10505,7 +10504,7 @@ int16x8_t test_vqnegq_s16(int16x8_t a) {
// CHECK-LABEL: @test_vqnegq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VQNEGQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqneg.v4i32(<4 x i32> %a) #4
+// CHECK: [[VQNEGQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqneg.v4i32(<4 x i32> %a)
// CHECK: [[VQNEGQ_V2_I:%.*]] = bitcast <4 x i32> [[VQNEGQ_V1_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQNEGQ_V1_I]]
int32x4_t test_vqnegq_s32(int32x4_t a) {
@@ -10515,7 +10514,7 @@ int32x4_t test_vqnegq_s32(int32x4_t a) {
// CHECK-LABEL: @test_vqrdmulh_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V2_I]]
int16x4_t test_vqrdmulh_s16(int16x4_t a, int16x4_t b) {
@@ -10525,7 +10524,7 @@ int16x4_t test_vqrdmulh_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqrdmulh_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V2_I]]
int32x2_t test_vqrdmulh_s32(int32x2_t a, int32x2_t b) {
@@ -10535,7 +10534,7 @@ int32x2_t test_vqrdmulh_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqrdmulhq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V2_I]]
int16x8_t test_vqrdmulhq_s16(int16x8_t a, int16x8_t b) {
@@ -10545,7 +10544,7 @@ int16x8_t test_vqrdmulhq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqrdmulhq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V2_I]]
int32x4_t test_vqrdmulhq_s32(int32x4_t a, int32x4_t b) {
@@ -10556,7 +10555,7 @@ int32x4_t test_vqrdmulhq_s32(int32x4_t a, int32x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %b, <4 x i16> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V2_I]]
int16x4_t test_vqrdmulh_lane_s16(int16x4_t a, int16x4_t b) {
@@ -10567,7 +10566,7 @@ int16x4_t test_vqrdmulh_lane_s16(int16x4_t a, int16x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %b, <2 x i32> %b, <2 x i32> <i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[SHUFFLE]] to <8 x i8>
-// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VQRDMULH_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULH_V3_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V2_I]]
int32x2_t test_vqrdmulh_lane_s32(int32x2_t a, int32x2_t b) {
@@ -10578,7 +10577,7 @@ int32x2_t test_vqrdmulh_lane_s32(int32x2_t a, int32x2_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <4 x i16> %b, <4 x i16> %b, <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]]) #4
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V2_I]]
int16x8_t test_vqrdmulhq_lane_s16(int16x8_t a, int16x4_t b) {
@@ -10589,7 +10588,7 @@ int16x8_t test_vqrdmulhq_lane_s16(int16x8_t a, int16x4_t b) {
// CHECK: [[SHUFFLE:%.*]] = shufflevector <2 x i32> %b, <2 x i32> %b, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[SHUFFLE]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]]) #4
+// CHECK: [[VQRDMULHQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[SHUFFLE]])
// CHECK: [[VQRDMULHQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V2_I]]
int32x4_t test_vqrdmulhq_lane_s32(int32x4_t a, int32x2_t b) {
@@ -10603,7 +10602,7 @@ int32x4_t test_vqrdmulhq_lane_s32(int32x4_t a, int32x2_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i16> [[VECINIT1_I]], i16 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i16> [[VECINIT2_I]], i16 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VECINIT3_I]] to <8 x i8>
-// CHECK: [[VQRDMULH_V5_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]]) #4
+// CHECK: [[VQRDMULH_V5_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrdmulh.v4i16(<4 x i16> %a, <4 x i16> [[VECINIT3_I]])
// CHECK: [[VQRDMULH_V6_I:%.*]] = bitcast <4 x i16> [[VQRDMULH_V5_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRDMULH_V5_I]]
int16x4_t test_vqrdmulh_n_s16(int16x4_t a, int16_t b) {
@@ -10615,7 +10614,7 @@ int16x4_t test_vqrdmulh_n_s16(int16x4_t a, int16_t b) {
// CHECK: [[VECINIT_I:%.*]] = insertelement <2 x i32> undef, i32 %b, i32 0
// CHECK: [[VECINIT1_I:%.*]] = insertelement <2 x i32> [[VECINIT_I]], i32 %b, i32 1
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> [[VECINIT1_I]] to <8 x i8>
-// CHECK: [[VQRDMULH_V3_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]]) #4
+// CHECK: [[VQRDMULH_V3_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrdmulh.v2i32(<2 x i32> %a, <2 x i32> [[VECINIT1_I]])
// CHECK: [[VQRDMULH_V4_I:%.*]] = bitcast <2 x i32> [[VQRDMULH_V3_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRDMULH_V3_I]]
int32x2_t test_vqrdmulh_n_s32(int32x2_t a, int32_t b) {
@@ -10633,7 +10632,7 @@ int32x2_t test_vqrdmulh_n_s32(int32x2_t a, int32_t b) {
// CHECK: [[VECINIT6_I:%.*]] = insertelement <8 x i16> [[VECINIT5_I]], i16 %b, i32 6
// CHECK: [[VECINIT7_I:%.*]] = insertelement <8 x i16> [[VECINIT6_I]], i16 %b, i32 7
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[VECINIT7_I]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]]) #4
+// CHECK: [[VQRDMULHQ_V9_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrdmulh.v8i16(<8 x i16> %a, <8 x i16> [[VECINIT7_I]])
// CHECK: [[VQRDMULHQ_V10_I:%.*]] = bitcast <8 x i16> [[VQRDMULHQ_V9_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRDMULHQ_V9_I]]
int16x8_t test_vqrdmulhq_n_s16(int16x8_t a, int16_t b) {
@@ -10647,7 +10646,7 @@ int16x8_t test_vqrdmulhq_n_s16(int16x8_t a, int16_t b) {
// CHECK: [[VECINIT2_I:%.*]] = insertelement <4 x i32> [[VECINIT1_I]], i32 %b, i32 2
// CHECK: [[VECINIT3_I:%.*]] = insertelement <4 x i32> [[VECINIT2_I]], i32 %b, i32 3
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> [[VECINIT3_I]] to <16 x i8>
-// CHECK: [[VQRDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]]) #4
+// CHECK: [[VQRDMULHQ_V5_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrdmulh.v4i32(<4 x i32> %a, <4 x i32> [[VECINIT3_I]])
// CHECK: [[VQRDMULHQ_V6_I:%.*]] = bitcast <4 x i32> [[VQRDMULHQ_V5_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRDMULHQ_V5_I]]
int32x4_t test_vqrdmulhq_n_s32(int32x4_t a, int32_t b) {
@@ -10655,7 +10654,7 @@ int32x4_t test_vqrdmulhq_n_s32(int32x4_t a, int32_t b) {
}
// CHECK-LABEL: @test_vqrshl_s8(
-// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqrshifts.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqrshifts.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQRSHL_V_I]]
int8x8_t test_vqrshl_s8(int8x8_t a, int8x8_t b) {
return vqrshl_s8(a, b);
@@ -10664,7 +10663,7 @@ int8x8_t test_vqrshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqrshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrshifts.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrshifts.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRSHL_V2_I]]
int16x4_t test_vqrshl_s16(int16x4_t a, int16x4_t b) {
@@ -10674,7 +10673,7 @@ int16x4_t test_vqrshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqrshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrshifts.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrshifts.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRSHL_V2_I]]
int32x2_t test_vqrshl_s32(int32x2_t a, int32x2_t b) {
@@ -10684,7 +10683,7 @@ int32x2_t test_vqrshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqrshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqrshifts.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqrshifts.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQRSHL_V2_I]]
int64x1_t test_vqrshl_s64(int64x1_t a, int64x1_t b) {
@@ -10692,7 +10691,7 @@ int64x1_t test_vqrshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqrshl_u8(
-// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqrshiftu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqrshiftu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQRSHL_V_I]]
uint8x8_t test_vqrshl_u8(uint8x8_t a, int8x8_t b) {
return vqrshl_u8(a, b);
@@ -10701,7 +10700,7 @@ uint8x8_t test_vqrshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqrshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrshiftu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqrshiftu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQRSHL_V2_I]]
uint16x4_t test_vqrshl_u16(uint16x4_t a, int16x4_t b) {
@@ -10711,7 +10710,7 @@ uint16x4_t test_vqrshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqrshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrshiftu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqrshiftu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQRSHL_V2_I]]
uint32x2_t test_vqrshl_u32(uint32x2_t a, int32x2_t b) {
@@ -10721,7 +10720,7 @@ uint32x2_t test_vqrshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqrshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqrshiftu.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqrshiftu.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQRSHL_V2_I]]
uint64x1_t test_vqrshl_u64(uint64x1_t a, int64x1_t b) {
@@ -10729,7 +10728,7 @@ uint64x1_t test_vqrshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqrshlq_s8(
-// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqrshifts.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqrshifts.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQRSHLQ_V_I]]
int8x16_t test_vqrshlq_s8(int8x16_t a, int8x16_t b) {
return vqrshlq_s8(a, b);
@@ -10738,7 +10737,7 @@ int8x16_t test_vqrshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqrshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrshifts.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrshifts.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRSHLQ_V2_I]]
int16x8_t test_vqrshlq_s16(int16x8_t a, int16x8_t b) {
@@ -10748,7 +10747,7 @@ int16x8_t test_vqrshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqrshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrshifts.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrshifts.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRSHLQ_V2_I]]
int32x4_t test_vqrshlq_s32(int32x4_t a, int32x4_t b) {
@@ -10758,7 +10757,7 @@ int32x4_t test_vqrshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqrshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqrshifts.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqrshifts.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQRSHLQ_V2_I]]
int64x2_t test_vqrshlq_s64(int64x2_t a, int64x2_t b) {
@@ -10766,7 +10765,7 @@ int64x2_t test_vqrshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqrshlq_u8(
-// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqrshiftu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqrshiftu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQRSHLQ_V_I]]
uint8x16_t test_vqrshlq_u8(uint8x16_t a, int8x16_t b) {
return vqrshlq_u8(a, b);
@@ -10775,7 +10774,7 @@ uint8x16_t test_vqrshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqrshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrshiftu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqrshiftu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQRSHLQ_V2_I]]
uint16x8_t test_vqrshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -10785,7 +10784,7 @@ uint16x8_t test_vqrshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqrshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrshiftu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqrshiftu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQRSHLQ_V2_I]]
uint32x4_t test_vqrshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -10795,7 +10794,7 @@ uint32x4_t test_vqrshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqrshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqrshiftu.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqrshiftu.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQRSHLQ_V2_I]]
uint64x2_t test_vqrshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -10884,7 +10883,7 @@ uint32x2_t test_vqrshrun_n_s64(int64x2_t a) {
}
// CHECK-LABEL: @test_vqshl_s8(
-// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqshifts.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqshifts.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSHL_V_I]]
int8x8_t test_vqshl_s8(int8x8_t a, int8x8_t b) {
return vqshl_s8(a, b);
@@ -10893,7 +10892,7 @@ int8x8_t test_vqshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqshifts.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqshifts.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSHL_V2_I]]
int16x4_t test_vqshl_s16(int16x4_t a, int16x4_t b) {
@@ -10903,7 +10902,7 @@ int16x4_t test_vqshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqshifts.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqshifts.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSHL_V2_I]]
int32x2_t test_vqshl_s32(int32x2_t a, int32x2_t b) {
@@ -10913,7 +10912,7 @@ int32x2_t test_vqshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqshifts.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqshifts.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSHL_V2_I]]
int64x1_t test_vqshl_s64(int64x1_t a, int64x1_t b) {
@@ -10921,7 +10920,7 @@ int64x1_t test_vqshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqshl_u8(
-// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqshiftu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqshiftu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSHL_V_I]]
uint8x8_t test_vqshl_u8(uint8x8_t a, int8x8_t b) {
return vqshl_u8(a, b);
@@ -10930,7 +10929,7 @@ uint8x8_t test_vqshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqshiftu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqshiftu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <4 x i16> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSHL_V2_I]]
uint16x4_t test_vqshl_u16(uint16x4_t a, int16x4_t b) {
@@ -10940,7 +10939,7 @@ uint16x4_t test_vqshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqshiftu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqshiftu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <2 x i32> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSHL_V2_I]]
uint32x2_t test_vqshl_u32(uint32x2_t a, int32x2_t b) {
@@ -10950,7 +10949,7 @@ uint32x2_t test_vqshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqshiftu.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqshiftu.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSHL_V3_I:%.*]] = bitcast <1 x i64> [[VQSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSHL_V2_I]]
uint64x1_t test_vqshl_u64(uint64x1_t a, int64x1_t b) {
@@ -10958,7 +10957,7 @@ uint64x1_t test_vqshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqshlq_s8(
-// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqshifts.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqshifts.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSHLQ_V_I]]
int8x16_t test_vqshlq_s8(int8x16_t a, int8x16_t b) {
return vqshlq_s8(a, b);
@@ -10967,7 +10966,7 @@ int8x16_t test_vqshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqshifts.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqshifts.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSHLQ_V2_I]]
int16x8_t test_vqshlq_s16(int16x8_t a, int16x8_t b) {
@@ -10977,7 +10976,7 @@ int16x8_t test_vqshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqshifts.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqshifts.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSHLQ_V2_I]]
int32x4_t test_vqshlq_s32(int32x4_t a, int32x4_t b) {
@@ -10987,7 +10986,7 @@ int32x4_t test_vqshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqshifts.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqshifts.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSHLQ_V2_I]]
int64x2_t test_vqshlq_s64(int64x2_t a, int64x2_t b) {
@@ -10995,7 +10994,7 @@ int64x2_t test_vqshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqshlq_u8(
-// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqshiftu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqshiftu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSHLQ_V_I]]
uint8x16_t test_vqshlq_u8(uint8x16_t a, int8x16_t b) {
return vqshlq_u8(a, b);
@@ -11004,7 +11003,7 @@ uint8x16_t test_vqshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqshiftu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqshiftu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSHLQ_V2_I]]
uint16x8_t test_vqshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -11014,7 +11013,7 @@ uint16x8_t test_vqshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqshiftu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqshiftu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSHLQ_V2_I]]
uint32x4_t test_vqshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -11024,7 +11023,7 @@ uint32x4_t test_vqshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqshiftu.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqshiftu.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSHLQ_V2_I]]
uint64x2_t test_vqshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -11317,7 +11316,7 @@ uint32x2_t test_vqshrun_n_s64(int64x2_t a) {
}
// CHECK-LABEL: @test_vqsub_s8(
-// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqsubs.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqsubs.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSUB_V_I]]
int8x8_t test_vqsub_s8(int8x8_t a, int8x8_t b) {
return vqsub_s8(a, b);
@@ -11326,7 +11325,7 @@ int8x8_t test_vqsub_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vqsub_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqsubs.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqsubs.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <4 x i16> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSUB_V2_I]]
int16x4_t test_vqsub_s16(int16x4_t a, int16x4_t b) {
@@ -11336,7 +11335,7 @@ int16x4_t test_vqsub_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vqsub_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqsubs.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqsubs.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <2 x i32> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSUB_V2_I]]
int32x2_t test_vqsub_s32(int32x2_t a, int32x2_t b) {
@@ -11346,7 +11345,7 @@ int32x2_t test_vqsub_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vqsub_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqsubs.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqsubs.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <1 x i64> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSUB_V2_I]]
int64x1_t test_vqsub_s64(int64x1_t a, int64x1_t b) {
@@ -11354,7 +11353,7 @@ int64x1_t test_vqsub_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vqsub_u8(
-// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqsubu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VQSUB_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vqsubu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VQSUB_V_I]]
uint8x8_t test_vqsub_u8(uint8x8_t a, uint8x8_t b) {
return vqsub_u8(a, b);
@@ -11363,7 +11362,7 @@ uint8x8_t test_vqsub_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vqsub_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqsubu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vqsubu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <4 x i16> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VQSUB_V2_I]]
uint16x4_t test_vqsub_u16(uint16x4_t a, uint16x4_t b) {
@@ -11373,7 +11372,7 @@ uint16x4_t test_vqsub_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vqsub_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqsubu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vqsubu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <2 x i32> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VQSUB_V2_I]]
uint32x2_t test_vqsub_u32(uint32x2_t a, uint32x2_t b) {
@@ -11383,7 +11382,7 @@ uint32x2_t test_vqsub_u32(uint32x2_t a, uint32x2_t b) {
// CHECK-LABEL: @test_vqsub_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqsubu.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VQSUB_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vqsubu.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VQSUB_V3_I:%.*]] = bitcast <1 x i64> [[VQSUB_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VQSUB_V2_I]]
uint64x1_t test_vqsub_u64(uint64x1_t a, uint64x1_t b) {
@@ -11391,7 +11390,7 @@ uint64x1_t test_vqsub_u64(uint64x1_t a, uint64x1_t b) {
}
// CHECK-LABEL: @test_vqsubq_s8(
-// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqsubs.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqsubs.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSUBQ_V_I]]
int8x16_t test_vqsubq_s8(int8x16_t a, int8x16_t b) {
return vqsubq_s8(a, b);
@@ -11400,7 +11399,7 @@ int8x16_t test_vqsubq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vqsubq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqsubs.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqsubs.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSUBQ_V2_I]]
int16x8_t test_vqsubq_s16(int16x8_t a, int16x8_t b) {
@@ -11410,7 +11409,7 @@ int16x8_t test_vqsubq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vqsubq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubs.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSUBQ_V2_I]]
int32x4_t test_vqsubq_s32(int32x4_t a, int32x4_t b) {
@@ -11420,7 +11419,7 @@ int32x4_t test_vqsubq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vqsubq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubs.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSUBQ_V2_I]]
int64x2_t test_vqsubq_s64(int64x2_t a, int64x2_t b) {
@@ -11428,7 +11427,7 @@ int64x2_t test_vqsubq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vqsubq_u8(
-// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqsubu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VQSUBQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vqsubu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VQSUBQ_V_I]]
uint8x16_t test_vqsubq_u8(uint8x16_t a, uint8x16_t b) {
return vqsubq_u8(a, b);
@@ -11437,7 +11436,7 @@ uint8x16_t test_vqsubq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vqsubq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqsubu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vqsubu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <8 x i16> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VQSUBQ_V2_I]]
uint16x8_t test_vqsubq_u16(uint16x8_t a, uint16x8_t b) {
@@ -11447,7 +11446,7 @@ uint16x8_t test_vqsubq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vqsubq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vqsubu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <4 x i32> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VQSUBQ_V2_I]]
uint32x4_t test_vqsubq_u32(uint32x4_t a, uint32x4_t b) {
@@ -11457,7 +11456,7 @@ uint32x4_t test_vqsubq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vqsubq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubu.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VQSUBQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vqsubu.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VQSUBQ_V3_I:%.*]] = bitcast <2 x i64> [[VQSUBQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VQSUBQ_V2_I]]
uint64x2_t test_vqsubq_u64(uint64x2_t a, uint64x2_t b) {
@@ -11467,7 +11466,7 @@ uint64x2_t test_vqsubq_u64(uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vraddhn_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vraddhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vraddhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRADDHN_V2_I]]
int8x8_t test_vraddhn_s16(int16x8_t a, int16x8_t b) {
return vraddhn_s16(a, b);
@@ -11476,7 +11475,7 @@ int8x8_t test_vraddhn_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vraddhn_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vraddhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vraddhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <4 x i16> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRADDHN_V2_I]]
int16x4_t test_vraddhn_s32(int32x4_t a, int32x4_t b) {
@@ -11486,7 +11485,7 @@ int16x4_t test_vraddhn_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vraddhn_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vraddhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vraddhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <2 x i32> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRADDHN_V2_I]]
int32x2_t test_vraddhn_s64(int64x2_t a, int64x2_t b) {
@@ -11496,7 +11495,7 @@ int32x2_t test_vraddhn_s64(int64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vraddhn_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vraddhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vraddhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRADDHN_V2_I]]
uint8x8_t test_vraddhn_u16(uint16x8_t a, uint16x8_t b) {
return vraddhn_u16(a, b);
@@ -11505,7 +11504,7 @@ uint8x8_t test_vraddhn_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vraddhn_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vraddhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vraddhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <4 x i16> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRADDHN_V2_I]]
uint16x4_t test_vraddhn_u32(uint32x4_t a, uint32x4_t b) {
@@ -11515,7 +11514,7 @@ uint16x4_t test_vraddhn_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vraddhn_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vraddhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRADDHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vraddhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRADDHN_V3_I:%.*]] = bitcast <2 x i32> [[VRADDHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRADDHN_V2_I]]
uint32x2_t test_vraddhn_u64(uint64x2_t a, uint64x2_t b) {
@@ -11524,7 +11523,7 @@ uint32x2_t test_vraddhn_u64(uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vrecpe_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x float> @llvm.arm.neon.vrecpe.v2f32(<2 x float> %a) #4
+// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x float> @llvm.arm.neon.vrecpe.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRECPE_V1_I]]
float32x2_t test_vrecpe_f32(float32x2_t a) {
return vrecpe_f32(a);
@@ -11532,7 +11531,7 @@ float32x2_t test_vrecpe_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrecpe_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrecpe.v2i32(<2 x i32> %a) #4
+// CHECK: [[VRECPE_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrecpe.v2i32(<2 x i32> %a)
// CHECK: ret <2 x i32> [[VRECPE_V1_I]]
uint32x2_t test_vrecpe_u32(uint32x2_t a) {
return vrecpe_u32(a);
@@ -11540,7 +11539,7 @@ uint32x2_t test_vrecpe_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vrecpeq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x float> @llvm.arm.neon.vrecpe.v4f32(<4 x float> %a) #4
+// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x float> @llvm.arm.neon.vrecpe.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRECPEQ_V1_I]]
float32x4_t test_vrecpeq_f32(float32x4_t a) {
return vrecpeq_f32(a);
@@ -11548,7 +11547,7 @@ float32x4_t test_vrecpeq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrecpeq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrecpe.v4i32(<4 x i32> %a) #4
+// CHECK: [[VRECPEQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrecpe.v4i32(<4 x i32> %a)
// CHECK: ret <4 x i32> [[VRECPEQ_V1_I]]
uint32x4_t test_vrecpeq_u32(uint32x4_t a) {
return vrecpeq_u32(a);
@@ -11557,7 +11556,7 @@ uint32x4_t test_vrecpeq_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vrecps_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VRECPS_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vrecps.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VRECPS_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vrecps.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VRECPS_V3_I:%.*]] = bitcast <2 x float> [[VRECPS_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VRECPS_V2_I]]
float32x2_t test_vrecps_f32(float32x2_t a, float32x2_t b) {
@@ -11567,7 +11566,7 @@ float32x2_t test_vrecps_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vrecpsq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VRECPSQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vrecps.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VRECPSQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vrecps.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: [[VRECPSQ_V3_I:%.*]] = bitcast <4 x float> [[VRECPSQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VRECPSQ_V2_I]]
float32x4_t test_vrecpsq_f32(float32x4_t a, float32x4_t b) {
@@ -13643,7 +13642,7 @@ float32x4_t test_vrev64q_f32(float32x4_t a) {
}
// CHECK-LABEL: @test_vrhadd_s8(
-// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrhadds.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrhadds.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VRHADD_V_I]]
int8x8_t test_vrhadd_s8(int8x8_t a, int8x8_t b) {
return vrhadd_s8(a, b);
@@ -13652,7 +13651,7 @@ int8x8_t test_vrhadd_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vrhadd_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrhadds.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrhadds.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <4 x i16> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRHADD_V2_I]]
int16x4_t test_vrhadd_s16(int16x4_t a, int16x4_t b) {
@@ -13662,7 +13661,7 @@ int16x4_t test_vrhadd_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vrhadd_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrhadds.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrhadds.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <2 x i32> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRHADD_V2_I]]
int32x2_t test_vrhadd_s32(int32x2_t a, int32x2_t b) {
@@ -13670,7 +13669,7 @@ int32x2_t test_vrhadd_s32(int32x2_t a, int32x2_t b) {
}
// CHECK-LABEL: @test_vrhadd_u8(
-// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrhaddu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VRHADD_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrhaddu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VRHADD_V_I]]
uint8x8_t test_vrhadd_u8(uint8x8_t a, uint8x8_t b) {
return vrhadd_u8(a, b);
@@ -13679,7 +13678,7 @@ uint8x8_t test_vrhadd_u8(uint8x8_t a, uint8x8_t b) {
// CHECK-LABEL: @test_vrhadd_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrhaddu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrhaddu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <4 x i16> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRHADD_V2_I]]
uint16x4_t test_vrhadd_u16(uint16x4_t a, uint16x4_t b) {
@@ -13689,7 +13688,7 @@ uint16x4_t test_vrhadd_u16(uint16x4_t a, uint16x4_t b) {
// CHECK-LABEL: @test_vrhadd_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrhaddu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VRHADD_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrhaddu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VRHADD_V3_I:%.*]] = bitcast <2 x i32> [[VRHADD_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRHADD_V2_I]]
uint32x2_t test_vrhadd_u32(uint32x2_t a, uint32x2_t b) {
@@ -13697,7 +13696,7 @@ uint32x2_t test_vrhadd_u32(uint32x2_t a, uint32x2_t b) {
}
// CHECK-LABEL: @test_vrhaddq_s8(
-// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrhadds.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrhadds.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VRHADDQ_V_I]]
int8x16_t test_vrhaddq_s8(int8x16_t a, int8x16_t b) {
return vrhaddq_s8(a, b);
@@ -13706,7 +13705,7 @@ int8x16_t test_vrhaddq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vrhaddq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrhadds.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrhadds.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRHADDQ_V2_I]]
int16x8_t test_vrhaddq_s16(int16x8_t a, int16x8_t b) {
@@ -13716,7 +13715,7 @@ int16x8_t test_vrhaddq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrhaddq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrhadds.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrhadds.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRHADDQ_V2_I]]
int32x4_t test_vrhaddq_s32(int32x4_t a, int32x4_t b) {
@@ -13724,7 +13723,7 @@ int32x4_t test_vrhaddq_s32(int32x4_t a, int32x4_t b) {
}
// CHECK-LABEL: @test_vrhaddq_u8(
-// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrhaddu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VRHADDQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrhaddu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VRHADDQ_V_I]]
uint8x16_t test_vrhaddq_u8(uint8x16_t a, uint8x16_t b) {
return vrhaddq_u8(a, b);
@@ -13733,7 +13732,7 @@ uint8x16_t test_vrhaddq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK-LABEL: @test_vrhaddq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrhaddu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrhaddu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <8 x i16> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRHADDQ_V2_I]]
uint16x8_t test_vrhaddq_u16(uint16x8_t a, uint16x8_t b) {
@@ -13743,7 +13742,7 @@ uint16x8_t test_vrhaddq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vrhaddq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrhaddu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRHADDQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrhaddu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRHADDQ_V3_I:%.*]] = bitcast <4 x i32> [[VRHADDQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRHADDQ_V2_I]]
uint32x4_t test_vrhaddq_u32(uint32x4_t a, uint32x4_t b) {
@@ -13751,7 +13750,7 @@ uint32x4_t test_vrhaddq_u32(uint32x4_t a, uint32x4_t b) {
}
// CHECK-LABEL: @test_vrshl_s8(
-// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrshifts.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrshifts.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VRSHL_V_I]]
int8x8_t test_vrshl_s8(int8x8_t a, int8x8_t b) {
return vrshl_s8(a, b);
@@ -13760,7 +13759,7 @@ int8x8_t test_vrshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vrshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrshifts.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrshifts.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSHL_V2_I]]
int16x4_t test_vrshl_s16(int16x4_t a, int16x4_t b) {
@@ -13770,7 +13769,7 @@ int16x4_t test_vrshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vrshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrshifts.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrshifts.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSHL_V2_I]]
int32x2_t test_vrshl_s32(int32x2_t a, int32x2_t b) {
@@ -13780,7 +13779,7 @@ int32x2_t test_vrshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vrshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vrshifts.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vrshifts.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VRSHL_V2_I]]
int64x1_t test_vrshl_s64(int64x1_t a, int64x1_t b) {
@@ -13788,7 +13787,7 @@ int64x1_t test_vrshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vrshl_u8(
-// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrshiftu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VRSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrshiftu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VRSHL_V_I]]
uint8x8_t test_vrshl_u8(uint8x8_t a, int8x8_t b) {
return vrshl_u8(a, b);
@@ -13797,7 +13796,7 @@ uint8x8_t test_vrshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vrshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrshiftu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrshiftu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <4 x i16> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSHL_V2_I]]
uint16x4_t test_vrshl_u16(uint16x4_t a, int16x4_t b) {
@@ -13807,7 +13806,7 @@ uint16x4_t test_vrshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vrshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrshiftu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrshiftu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <2 x i32> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSHL_V2_I]]
uint32x2_t test_vrshl_u32(uint32x2_t a, int32x2_t b) {
@@ -13817,7 +13816,7 @@ uint32x2_t test_vrshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vrshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vrshiftu.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VRSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vrshiftu.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VRSHL_V3_I:%.*]] = bitcast <1 x i64> [[VRSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VRSHL_V2_I]]
uint64x1_t test_vrshl_u64(uint64x1_t a, int64x1_t b) {
@@ -13825,7 +13824,7 @@ uint64x1_t test_vrshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vrshlq_s8(
-// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrshifts.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrshifts.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VRSHLQ_V_I]]
int8x16_t test_vrshlq_s8(int8x16_t a, int8x16_t b) {
return vrshlq_s8(a, b);
@@ -13834,7 +13833,7 @@ int8x16_t test_vrshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vrshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrshifts.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrshifts.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRSHLQ_V2_I]]
int16x8_t test_vrshlq_s16(int16x8_t a, int16x8_t b) {
@@ -13844,7 +13843,7 @@ int16x8_t test_vrshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrshifts.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrshifts.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRSHLQ_V2_I]]
int32x4_t test_vrshlq_s32(int32x4_t a, int32x4_t b) {
@@ -13854,7 +13853,7 @@ int32x4_t test_vrshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vrshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vrshifts.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vrshifts.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VRSHLQ_V2_I]]
int64x2_t test_vrshlq_s64(int64x2_t a, int64x2_t b) {
@@ -13862,7 +13861,7 @@ int64x2_t test_vrshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vrshlq_u8(
-// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrshiftu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VRSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vrshiftu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VRSHLQ_V_I]]
uint8x16_t test_vrshlq_u8(uint8x16_t a, int8x16_t b) {
return vrshlq_u8(a, b);
@@ -13871,7 +13870,7 @@ uint8x16_t test_vrshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vrshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrshiftu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vrshiftu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VRSHLQ_V2_I]]
uint16x8_t test_vrshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -13881,7 +13880,7 @@ uint16x8_t test_vrshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrshiftu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrshiftu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VRSHLQ_V2_I]]
uint32x4_t test_vrshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -13891,7 +13890,7 @@ uint32x4_t test_vrshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vrshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vrshiftu.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vrshiftu.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VRSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VRSHLQ_V2_I]]
uint64x2_t test_vrshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -14090,7 +14089,7 @@ uint64x2_t test_vrshrq_n_u64(uint64x2_t a) {
// CHECK-LABEL: @test_vrsqrte_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
-// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x float> @llvm.arm.neon.vrsqrte.v2f32(<2 x float> %a) #4
+// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x float> @llvm.arm.neon.vrsqrte.v2f32(<2 x float> %a)
// CHECK: ret <2 x float> [[VRSQRTE_V1_I]]
float32x2_t test_vrsqrte_f32(float32x2_t a) {
return vrsqrte_f32(a);
@@ -14098,7 +14097,7 @@ float32x2_t test_vrsqrte_f32(float32x2_t a) {
// CHECK-LABEL: @test_vrsqrte_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
-// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrsqrte.v2i32(<2 x i32> %a) #4
+// CHECK: [[VRSQRTE_V1_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrsqrte.v2i32(<2 x i32> %a)
// CHECK: ret <2 x i32> [[VRSQRTE_V1_I]]
uint32x2_t test_vrsqrte_u32(uint32x2_t a) {
return vrsqrte_u32(a);
@@ -14106,7 +14105,7 @@ uint32x2_t test_vrsqrte_u32(uint32x2_t a) {
// CHECK-LABEL: @test_vrsqrteq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
-// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x float> @llvm.arm.neon.vrsqrte.v4f32(<4 x float> %a) #4
+// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x float> @llvm.arm.neon.vrsqrte.v4f32(<4 x float> %a)
// CHECK: ret <4 x float> [[VRSQRTEQ_V1_I]]
float32x4_t test_vrsqrteq_f32(float32x4_t a) {
return vrsqrteq_f32(a);
@@ -14114,7 +14113,7 @@ float32x4_t test_vrsqrteq_f32(float32x4_t a) {
// CHECK-LABEL: @test_vrsqrteq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
-// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrsqrte.v4i32(<4 x i32> %a) #4
+// CHECK: [[VRSQRTEQ_V1_I:%.*]] = call <4 x i32> @llvm.arm.neon.vrsqrte.v4i32(<4 x i32> %a)
// CHECK: ret <4 x i32> [[VRSQRTEQ_V1_I]]
uint32x4_t test_vrsqrteq_u32(uint32x4_t a) {
return vrsqrteq_u32(a);
@@ -14123,7 +14122,7 @@ uint32x4_t test_vrsqrteq_u32(uint32x4_t a) {
// CHECK-LABEL: @test_vrsqrts_f32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8>
-// CHECK: [[VRSQRTS_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vrsqrts.v2f32(<2 x float> %a, <2 x float> %b) #4
+// CHECK: [[VRSQRTS_V2_I:%.*]] = call <2 x float> @llvm.arm.neon.vrsqrts.v2f32(<2 x float> %a, <2 x float> %b)
// CHECK: [[VRSQRTS_V3_I:%.*]] = bitcast <2 x float> [[VRSQRTS_V2_I]] to <8 x i8>
// CHECK: ret <2 x float> [[VRSQRTS_V2_I]]
float32x2_t test_vrsqrts_f32(float32x2_t a, float32x2_t b) {
@@ -14133,7 +14132,7 @@ float32x2_t test_vrsqrts_f32(float32x2_t a, float32x2_t b) {
// CHECK-LABEL: @test_vrsqrtsq_f32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8>
-// CHECK: [[VRSQRTSQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vrsqrts.v4f32(<4 x float> %a, <4 x float> %b) #4
+// CHECK: [[VRSQRTSQ_V2_I:%.*]] = call <4 x float> @llvm.arm.neon.vrsqrts.v4f32(<4 x float> %a, <4 x float> %b)
// CHECK: [[VRSQRTSQ_V3_I:%.*]] = bitcast <4 x float> [[VRSQRTSQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x float> [[VRSQRTSQ_V2_I]]
float32x4_t test_vrsqrtsq_f32(float32x4_t a, float32x4_t b) {
@@ -14319,7 +14318,7 @@ uint64x2_t test_vrsraq_n_u64(uint64x2_t a, uint64x2_t b) {
// CHECK-LABEL: @test_vrsubhn_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrsubhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrsubhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRSUBHN_V2_I]]
int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
return vrsubhn_s16(a, b);
@@ -14328,7 +14327,7 @@ int8x8_t test_vrsubhn_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vrsubhn_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrsubhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrsubhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSUBHN_V2_I]]
int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
@@ -14338,7 +14337,7 @@ int16x4_t test_vrsubhn_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vrsubhn_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrsubhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrsubhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSUBHN_V2_I]]
int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
@@ -14348,7 +14347,7 @@ int32x2_t test_vrsubhn_s64(int64x2_t a, int64x2_t b) {
// CHECK-LABEL: @test_vrsubhn_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrsubhn.v8i8(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vrsubhn.v8i8(<8 x i16> %a, <8 x i16> %b)
// CHECK: ret <8 x i8> [[VRSUBHN_V2_I]]
uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
return vrsubhn_u16(a, b);
@@ -14357,7 +14356,7 @@ uint8x8_t test_vrsubhn_u16(uint16x8_t a, uint16x8_t b) {
// CHECK-LABEL: @test_vrsubhn_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrsubhn.v4i16(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vrsubhn.v4i16(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <4 x i16> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VRSUBHN_V2_I]]
uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
@@ -14367,7 +14366,7 @@ uint16x4_t test_vrsubhn_u32(uint32x4_t a, uint32x4_t b) {
// CHECK-LABEL: @test_vrsubhn_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrsubhn.v2i32(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VRSUBHN_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vrsubhn.v2i32(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VRSUBHN_V3_I:%.*]] = bitcast <2 x i32> [[VRSUBHN_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VRSUBHN_V2_I]]
uint32x2_t test_vrsubhn_u64(uint64x2_t a, uint64x2_t b) {
@@ -14605,7 +14604,7 @@ uint64x2_t test_vsetq_lane_u64(uint64_t a, uint64x2_t b) {
}
// CHECK-LABEL: @test_vshl_s8(
-// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vshifts.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vshifts.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VSHL_V_I]]
int8x8_t test_vshl_s8(int8x8_t a, int8x8_t b) {
return vshl_s8(a, b);
@@ -14614,7 +14613,7 @@ int8x8_t test_vshl_s8(int8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vshl_s16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vshifts.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vshifts.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <4 x i16> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VSHL_V2_I]]
int16x4_t test_vshl_s16(int16x4_t a, int16x4_t b) {
@@ -14624,7 +14623,7 @@ int16x4_t test_vshl_s16(int16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vshl_s32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vshifts.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vshifts.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <2 x i32> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VSHL_V2_I]]
int32x2_t test_vshl_s32(int32x2_t a, int32x2_t b) {
@@ -14634,7 +14633,7 @@ int32x2_t test_vshl_s32(int32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vshl_s64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vshifts.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vshifts.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <1 x i64> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VSHL_V2_I]]
int64x1_t test_vshl_s64(int64x1_t a, int64x1_t b) {
@@ -14642,7 +14641,7 @@ int64x1_t test_vshl_s64(int64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vshl_u8(
-// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vshiftu.v8i8(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VSHL_V_I:%.*]] = call <8 x i8> @llvm.arm.neon.vshiftu.v8i8(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VSHL_V_I]]
uint8x8_t test_vshl_u8(uint8x8_t a, int8x8_t b) {
return vshl_u8(a, b);
@@ -14651,7 +14650,7 @@ uint8x8_t test_vshl_u8(uint8x8_t a, int8x8_t b) {
// CHECK-LABEL: @test_vshl_u16(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vshiftu.v4i16(<4 x i16> %a, <4 x i16> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <4 x i16> @llvm.arm.neon.vshiftu.v4i16(<4 x i16> %a, <4 x i16> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <4 x i16> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <4 x i16> [[VSHL_V2_I]]
uint16x4_t test_vshl_u16(uint16x4_t a, int16x4_t b) {
@@ -14661,7 +14660,7 @@ uint16x4_t test_vshl_u16(uint16x4_t a, int16x4_t b) {
// CHECK-LABEL: @test_vshl_u32(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vshiftu.v2i32(<2 x i32> %a, <2 x i32> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <2 x i32> @llvm.arm.neon.vshiftu.v2i32(<2 x i32> %a, <2 x i32> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <2 x i32> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <2 x i32> [[VSHL_V2_I]]
uint32x2_t test_vshl_u32(uint32x2_t a, int32x2_t b) {
@@ -14671,7 +14670,7 @@ uint32x2_t test_vshl_u32(uint32x2_t a, int32x2_t b) {
// CHECK-LABEL: @test_vshl_u64(
// CHECK: [[TMP0:%.*]] = bitcast <1 x i64> %a to <8 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <1 x i64> %b to <8 x i8>
-// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vshiftu.v1i64(<1 x i64> %a, <1 x i64> %b) #4
+// CHECK: [[VSHL_V2_I:%.*]] = call <1 x i64> @llvm.arm.neon.vshiftu.v1i64(<1 x i64> %a, <1 x i64> %b)
// CHECK: [[VSHL_V3_I:%.*]] = bitcast <1 x i64> [[VSHL_V2_I]] to <8 x i8>
// CHECK: ret <1 x i64> [[VSHL_V2_I]]
uint64x1_t test_vshl_u64(uint64x1_t a, int64x1_t b) {
@@ -14679,7 +14678,7 @@ uint64x1_t test_vshl_u64(uint64x1_t a, int64x1_t b) {
}
// CHECK-LABEL: @test_vshlq_s8(
-// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vshifts.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vshifts.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VSHLQ_V_I]]
int8x16_t test_vshlq_s8(int8x16_t a, int8x16_t b) {
return vshlq_s8(a, b);
@@ -14688,7 +14687,7 @@ int8x16_t test_vshlq_s8(int8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vshlq_s16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vshifts.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vshifts.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VSHLQ_V2_I]]
int16x8_t test_vshlq_s16(int16x8_t a, int16x8_t b) {
@@ -14698,7 +14697,7 @@ int16x8_t test_vshlq_s16(int16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vshlq_s32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vshifts.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vshifts.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VSHLQ_V2_I]]
int32x4_t test_vshlq_s32(int32x4_t a, int32x4_t b) {
@@ -14708,7 +14707,7 @@ int32x4_t test_vshlq_s32(int32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vshlq_s64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vshifts.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vshifts.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VSHLQ_V2_I]]
int64x2_t test_vshlq_s64(int64x2_t a, int64x2_t b) {
@@ -14716,7 +14715,7 @@ int64x2_t test_vshlq_s64(int64x2_t a, int64x2_t b) {
}
// CHECK-LABEL: @test_vshlq_u8(
-// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vshiftu.v16i8(<16 x i8> %a, <16 x i8> %b) #4
+// CHECK: [[VSHLQ_V_I:%.*]] = call <16 x i8> @llvm.arm.neon.vshiftu.v16i8(<16 x i8> %a, <16 x i8> %b)
// CHECK: ret <16 x i8> [[VSHLQ_V_I]]
uint8x16_t test_vshlq_u8(uint8x16_t a, int8x16_t b) {
return vshlq_u8(a, b);
@@ -14725,7 +14724,7 @@ uint8x16_t test_vshlq_u8(uint8x16_t a, int8x16_t b) {
// CHECK-LABEL: @test_vshlq_u16(
// CHECK: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vshiftu.v8i16(<8 x i16> %a, <8 x i16> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <8 x i16> @llvm.arm.neon.vshiftu.v8i16(<8 x i16> %a, <8 x i16> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <8 x i16> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <8 x i16> [[VSHLQ_V2_I]]
uint16x8_t test_vshlq_u16(uint16x8_t a, int16x8_t b) {
@@ -14735,7 +14734,7 @@ uint16x8_t test_vshlq_u16(uint16x8_t a, int16x8_t b) {
// CHECK-LABEL: @test_vshlq_u32(
// CHECK: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vshiftu.v4i32(<4 x i32> %a, <4 x i32> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <4 x i32> @llvm.arm.neon.vshiftu.v4i32(<4 x i32> %a, <4 x i32> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <4 x i32> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <4 x i32> [[VSHLQ_V2_I]]
uint32x4_t test_vshlq_u32(uint32x4_t a, int32x4_t b) {
@@ -14745,7 +14744,7 @@ uint32x4_t test_vshlq_u32(uint32x4_t a, int32x4_t b) {
// CHECK-LABEL: @test_vshlq_u64(
// CHECK: [[TMP0:%.*]] = bitcast <2 x i64> %a to <16 x i8>
// CHECK: [[TMP1:%.*]] = bitcast <2 x i64> %b to <16 x i8>
-// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vshiftu.v2i64(<2 x i64> %a, <2 x i64> %b) #4
+// CHECK: [[VSHLQ_V2_I:%.*]] = call <2 x i64> @llvm.arm.neon.vshiftu.v2i64(<2 x i64> %a, <2 x i64> %b)
// CHECK: [[VSHLQ_V3_I:%.*]] = bitcast <2 x i64> [[VSHLQ_V2_I]] to <16 x i8>
// CHECK: ret <2 x i64> [[VSHLQ_V2_I]]
uint64x2_t test_vshlq_u64(uint64x2_t a, int64x2_t b) {
@@ -19937,21 +19936,21 @@ uint64x2_t test_vsubw_u32(uint64x2_t a, uint32x2_t b) {
}
// CHECK-LABEL: @test_vtbl1_u8(
-// CHECK: [[VTBL1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl1(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VTBL1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl1(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL1_I]]
uint8x8_t test_vtbl1_u8(uint8x8_t a, uint8x8_t b) {
return vtbl1_u8(a, b);
}
// CHECK-LABEL: @test_vtbl1_s8(
-// CHECK: [[VTBL1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl1(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VTBL1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl1(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL1_I]]
int8x8_t test_vtbl1_s8(int8x8_t a, int8x8_t b) {
return vtbl1_s8(a, b);
}
// CHECK-LABEL: @test_vtbl1_p8(
-// CHECK: [[VTBL1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl1(<8 x i8> %a, <8 x i8> %b) #4
+// CHECK: [[VTBL1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl1(<8 x i8> %a, <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL1_I]]
poly8x8_t test_vtbl1_p8(poly8x8_t a, uint8x8_t b) {
return vtbl1_p8(a, b);
@@ -19975,7 +19974,7 @@ poly8x8_t test_vtbl1_p8(poly8x8_t a, uint8x8_t b) {
// CHECK: [[VAL1_I:%.*]] = getelementptr inbounds %struct.uint8x8x2_t, %struct.uint8x8x2_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX2_I:%.*]] = getelementptr inbounds [2 x <8 x i8>], [2 x <8 x i8>]* [[VAL1_I]], i32 0, i32 1
// CHECK: [[TMP5:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX2_I]], align 8
-// CHECK: [[VTBL2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl2(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %b) #4
+// CHECK: [[VTBL2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl2(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL2_I]]
uint8x8_t test_vtbl2_u8(uint8x8x2_t a, uint8x8_t b) {
return vtbl2_u8(a, b);
@@ -19999,7 +19998,7 @@ uint8x8_t test_vtbl2_u8(uint8x8x2_t a, uint8x8_t b) {
// CHECK: [[VAL1_I:%.*]] = getelementptr inbounds %struct.int8x8x2_t, %struct.int8x8x2_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX2_I:%.*]] = getelementptr inbounds [2 x <8 x i8>], [2 x <8 x i8>]* [[VAL1_I]], i32 0, i32 1
// CHECK: [[TMP5:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX2_I]], align 8
-// CHECK: [[VTBL2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl2(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %b) #4
+// CHECK: [[VTBL2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl2(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL2_I]]
int8x8_t test_vtbl2_s8(int8x8x2_t a, int8x8_t b) {
return vtbl2_s8(a, b);
@@ -20023,7 +20022,7 @@ int8x8_t test_vtbl2_s8(int8x8x2_t a, int8x8_t b) {
// CHECK: [[VAL1_I:%.*]] = getelementptr inbounds %struct.poly8x8x2_t, %struct.poly8x8x2_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX2_I:%.*]] = getelementptr inbounds [2 x <8 x i8>], [2 x <8 x i8>]* [[VAL1_I]], i32 0, i32 1
// CHECK: [[TMP5:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX2_I]], align 8
-// CHECK: [[VTBL2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl2(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %b) #4
+// CHECK: [[VTBL2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl2(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL2_I]]
poly8x8_t test_vtbl2_p8(poly8x8x2_t a, uint8x8_t b) {
return vtbl2_p8(a, b);
@@ -20050,7 +20049,7 @@ poly8x8_t test_vtbl2_p8(poly8x8x2_t a, uint8x8_t b) {
// CHECK: [[VAL3_I:%.*]] = getelementptr inbounds %struct.uint8x8x3_t, %struct.uint8x8x3_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX4_I:%.*]] = getelementptr inbounds [3 x <8 x i8>], [3 x <8 x i8>]* [[VAL3_I]], i32 0, i32 2
// CHECK: [[TMP6:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX4_I]], align 8
-// CHECK: [[VTBL3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl3(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %b) #4
+// CHECK: [[VTBL3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl3(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL3_I]]
uint8x8_t test_vtbl3_u8(uint8x8x3_t a, uint8x8_t b) {
return vtbl3_u8(a, b);
@@ -20077,7 +20076,7 @@ uint8x8_t test_vtbl3_u8(uint8x8x3_t a, uint8x8_t b) {
// CHECK: [[VAL3_I:%.*]] = getelementptr inbounds %struct.int8x8x3_t, %struct.int8x8x3_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX4_I:%.*]] = getelementptr inbounds [3 x <8 x i8>], [3 x <8 x i8>]* [[VAL3_I]], i32 0, i32 2
// CHECK: [[TMP6:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX4_I]], align 8
-// CHECK: [[VTBL3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl3(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %b) #4
+// CHECK: [[VTBL3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl3(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL3_I]]
int8x8_t test_vtbl3_s8(int8x8x3_t a, int8x8_t b) {
return vtbl3_s8(a, b);
@@ -20104,7 +20103,7 @@ int8x8_t test_vtbl3_s8(int8x8x3_t a, int8x8_t b) {
// CHECK: [[VAL3_I:%.*]] = getelementptr inbounds %struct.poly8x8x3_t, %struct.poly8x8x3_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX4_I:%.*]] = getelementptr inbounds [3 x <8 x i8>], [3 x <8 x i8>]* [[VAL3_I]], i32 0, i32 2
// CHECK: [[TMP6:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX4_I]], align 8
-// CHECK: [[VTBL3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl3(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %b) #4
+// CHECK: [[VTBL3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl3(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL3_I]]
poly8x8_t test_vtbl3_p8(poly8x8x3_t a, uint8x8_t b) {
return vtbl3_p8(a, b);
@@ -20134,7 +20133,7 @@ poly8x8_t test_vtbl3_p8(poly8x8x3_t a, uint8x8_t b) {
// CHECK: [[VAL5_I:%.*]] = getelementptr inbounds %struct.uint8x8x4_t, %struct.uint8x8x4_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX6_I:%.*]] = getelementptr inbounds [4 x <8 x i8>], [4 x <8 x i8>]* [[VAL5_I]], i32 0, i32 3
// CHECK: [[TMP7:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX6_I]], align 8
-// CHECK: [[VTBL4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl4(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %b) #4
+// CHECK: [[VTBL4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl4(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL4_I]]
uint8x8_t test_vtbl4_u8(uint8x8x4_t a, uint8x8_t b) {
return vtbl4_u8(a, b);
@@ -20164,7 +20163,7 @@ uint8x8_t test_vtbl4_u8(uint8x8x4_t a, uint8x8_t b) {
// CHECK: [[VAL5_I:%.*]] = getelementptr inbounds %struct.int8x8x4_t, %struct.int8x8x4_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX6_I:%.*]] = getelementptr inbounds [4 x <8 x i8>], [4 x <8 x i8>]* [[VAL5_I]], i32 0, i32 3
// CHECK: [[TMP7:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX6_I]], align 8
-// CHECK: [[VTBL4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl4(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %b) #4
+// CHECK: [[VTBL4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl4(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL4_I]]
int8x8_t test_vtbl4_s8(int8x8x4_t a, int8x8_t b) {
return vtbl4_s8(a, b);
@@ -20194,28 +20193,28 @@ int8x8_t test_vtbl4_s8(int8x8x4_t a, int8x8_t b) {
// CHECK: [[VAL5_I:%.*]] = getelementptr inbounds %struct.poly8x8x4_t, %struct.poly8x8x4_t* [[__P0_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX6_I:%.*]] = getelementptr inbounds [4 x <8 x i8>], [4 x <8 x i8>]* [[VAL5_I]], i32 0, i32 3
// CHECK: [[TMP7:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX6_I]], align 8
-// CHECK: [[VTBL4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl4(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %b) #4
+// CHECK: [[VTBL4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbl4(<8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %b)
// CHECK: ret <8 x i8> [[VTBL4_I]]
poly8x8_t test_vtbl4_p8(poly8x8x4_t a, uint8x8_t b) {
return vtbl4_p8(a, b);
}
// CHECK-LABEL: @test_vtbx1_u8(
-// CHECK: [[VTBX1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx1(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VTBX1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx1(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX1_I]]
uint8x8_t test_vtbx1_u8(uint8x8_t a, uint8x8_t b, uint8x8_t c) {
return vtbx1_u8(a, b, c);
}
// CHECK-LABEL: @test_vtbx1_s8(
-// CHECK: [[VTBX1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx1(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VTBX1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx1(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX1_I]]
int8x8_t test_vtbx1_s8(int8x8_t a, int8x8_t b, int8x8_t c) {
return vtbx1_s8(a, b, c);
}
// CHECK-LABEL: @test_vtbx1_p8(
-// CHECK: [[VTBX1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx1(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c) #4
+// CHECK: [[VTBX1_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx1(<8 x i8> %a, <8 x i8> %b, <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX1_I]]
poly8x8_t test_vtbx1_p8(poly8x8_t a, poly8x8_t b, uint8x8_t c) {
return vtbx1_p8(a, b, c);
@@ -20239,7 +20238,7 @@ poly8x8_t test_vtbx1_p8(poly8x8_t a, poly8x8_t b, uint8x8_t c) {
// CHECK: [[VAL1_I:%.*]] = getelementptr inbounds %struct.uint8x8x2_t, %struct.uint8x8x2_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX2_I:%.*]] = getelementptr inbounds [2 x <8 x i8>], [2 x <8 x i8>]* [[VAL1_I]], i32 0, i32 1
// CHECK: [[TMP5:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX2_I]], align 8
-// CHECK: [[VTBX2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx2(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %c) #4
+// CHECK: [[VTBX2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx2(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX2_I]]
uint8x8_t test_vtbx2_u8(uint8x8_t a, uint8x8x2_t b, uint8x8_t c) {
return vtbx2_u8(a, b, c);
@@ -20263,7 +20262,7 @@ uint8x8_t test_vtbx2_u8(uint8x8_t a, uint8x8x2_t b, uint8x8_t c) {
// CHECK: [[VAL1_I:%.*]] = getelementptr inbounds %struct.int8x8x2_t, %struct.int8x8x2_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX2_I:%.*]] = getelementptr inbounds [2 x <8 x i8>], [2 x <8 x i8>]* [[VAL1_I]], i32 0, i32 1
// CHECK: [[TMP5:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX2_I]], align 8
-// CHECK: [[VTBX2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx2(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %c) #4
+// CHECK: [[VTBX2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx2(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX2_I]]
int8x8_t test_vtbx2_s8(int8x8_t a, int8x8x2_t b, int8x8_t c) {
return vtbx2_s8(a, b, c);
@@ -20287,7 +20286,7 @@ int8x8_t test_vtbx2_s8(int8x8_t a, int8x8x2_t b, int8x8_t c) {
// CHECK: [[VAL1_I:%.*]] = getelementptr inbounds %struct.poly8x8x2_t, %struct.poly8x8x2_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX2_I:%.*]] = getelementptr inbounds [2 x <8 x i8>], [2 x <8 x i8>]* [[VAL1_I]], i32 0, i32 1
// CHECK: [[TMP5:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX2_I]], align 8
-// CHECK: [[VTBX2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx2(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %c) #4
+// CHECK: [[VTBX2_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx2(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX2_I]]
poly8x8_t test_vtbx2_p8(poly8x8_t a, poly8x8x2_t b, uint8x8_t c) {
return vtbx2_p8(a, b, c);
@@ -20314,7 +20313,7 @@ poly8x8_t test_vtbx2_p8(poly8x8_t a, poly8x8x2_t b, uint8x8_t c) {
// CHECK: [[VAL3_I:%.*]] = getelementptr inbounds %struct.uint8x8x3_t, %struct.uint8x8x3_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX4_I:%.*]] = getelementptr inbounds [3 x <8 x i8>], [3 x <8 x i8>]* [[VAL3_I]], i32 0, i32 2
// CHECK: [[TMP6:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX4_I]], align 8
-// CHECK: [[VTBX3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx3(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %c) #4
+// CHECK: [[VTBX3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx3(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX3_I]]
uint8x8_t test_vtbx3_u8(uint8x8_t a, uint8x8x3_t b, uint8x8_t c) {
return vtbx3_u8(a, b, c);
@@ -20341,7 +20340,7 @@ uint8x8_t test_vtbx3_u8(uint8x8_t a, uint8x8x3_t b, uint8x8_t c) {
// CHECK: [[VAL3_I:%.*]] = getelementptr inbounds %struct.int8x8x3_t, %struct.int8x8x3_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX4_I:%.*]] = getelementptr inbounds [3 x <8 x i8>], [3 x <8 x i8>]* [[VAL3_I]], i32 0, i32 2
// CHECK: [[TMP6:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX4_I]], align 8
-// CHECK: [[VTBX3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx3(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %c) #4
+// CHECK: [[VTBX3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx3(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX3_I]]
int8x8_t test_vtbx3_s8(int8x8_t a, int8x8x3_t b, int8x8_t c) {
return vtbx3_s8(a, b, c);
@@ -20368,7 +20367,7 @@ int8x8_t test_vtbx3_s8(int8x8_t a, int8x8x3_t b, int8x8_t c) {
// CHECK: [[VAL3_I:%.*]] = getelementptr inbounds %struct.poly8x8x3_t, %struct.poly8x8x3_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX4_I:%.*]] = getelementptr inbounds [3 x <8 x i8>], [3 x <8 x i8>]* [[VAL3_I]], i32 0, i32 2
// CHECK: [[TMP6:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX4_I]], align 8
-// CHECK: [[VTBX3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx3(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %c) #4
+// CHECK: [[VTBX3_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx3(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX3_I]]
poly8x8_t test_vtbx3_p8(poly8x8_t a, poly8x8x3_t b, uint8x8_t c) {
return vtbx3_p8(a, b, c);
@@ -20398,7 +20397,7 @@ poly8x8_t test_vtbx3_p8(poly8x8_t a, poly8x8x3_t b, uint8x8_t c) {
// CHECK: [[VAL5_I:%.*]] = getelementptr inbounds %struct.uint8x8x4_t, %struct.uint8x8x4_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX6_I:%.*]] = getelementptr inbounds [4 x <8 x i8>], [4 x <8 x i8>]* [[VAL5_I]], i32 0, i32 3
// CHECK: [[TMP7:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX6_I]], align 8
-// CHECK: [[VTBX4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx4(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %c) #4
+// CHECK: [[VTBX4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx4(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX4_I]]
uint8x8_t test_vtbx4_u8(uint8x8_t a, uint8x8x4_t b, uint8x8_t c) {
return vtbx4_u8(a, b, c);
@@ -20428,7 +20427,7 @@ uint8x8_t test_vtbx4_u8(uint8x8_t a, uint8x8x4_t b, uint8x8_t c) {
// CHECK: [[VAL5_I:%.*]] = getelementptr inbounds %struct.int8x8x4_t, %struct.int8x8x4_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX6_I:%.*]] = getelementptr inbounds [4 x <8 x i8>], [4 x <8 x i8>]* [[VAL5_I]], i32 0, i32 3
// CHECK: [[TMP7:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX6_I]], align 8
-// CHECK: [[VTBX4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx4(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %c) #4
+// CHECK: [[VTBX4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx4(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX4_I]]
int8x8_t test_vtbx4_s8(int8x8_t a, int8x8x4_t b, int8x8_t c) {
return vtbx4_s8(a, b, c);
@@ -20458,7 +20457,7 @@ int8x8_t test_vtbx4_s8(int8x8_t a, int8x8x4_t b, int8x8_t c) {
// CHECK: [[VAL5_I:%.*]] = getelementptr inbounds %struct.poly8x8x4_t, %struct.poly8x8x4_t* [[__P1_I]], i32 0, i32 0
// CHECK: [[ARRAYIDX6_I:%.*]] = getelementptr inbounds [4 x <8 x i8>], [4 x <8 x i8>]* [[VAL5_I]], i32 0, i32 3
// CHECK: [[TMP7:%.*]] = load <8 x i8>, <8 x i8>* [[ARRAYIDX6_I]], align 8
-// CHECK: [[VTBX4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx4(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %c) #4
+// CHECK: [[VTBX4_I:%.*]] = call <8 x i8> @llvm.arm.neon.vtbx4(<8 x i8> %a, <8 x i8> [[TMP4]], <8 x i8> [[TMP5]], <8 x i8> [[TMP6]], <8 x i8> [[TMP7]], <8 x i8> %c)
// CHECK: ret <8 x i8> [[VTBX4_I]]
poly8x8_t test_vtbx4_p8(poly8x8_t a, poly8x8x4_t b, uint8x8_t c) {
return vtbx4_p8(a, b, c);
@@ -20475,7 +20474,7 @@ poly8x8_t test_vtbx4_p8(poly8x8_t a, poly8x8x4_t b, uint8x8_t c) {
// CHECK: store <8 x i8> [[VTRN1_I]], <8 x i8>* [[TMP2]], !noalias !3
// CHECK: [[TMP3:%.*]] = bitcast %struct.int8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.int8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
int8x8x2_t test_vtrn_s8(int8x8_t a, int8x8_t b) {
return vtrn_s8(a, b);
@@ -20494,7 +20493,7 @@ int8x8x2_t test_vtrn_s8(int8x8_t a, int8x8_t b) {
// CHECK: store <4 x i16> [[VTRN1_I]], <4 x i16>* [[TMP4]], !noalias !6
// CHECK: [[TMP5:%.*]] = bitcast %struct.int16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
int16x4x2_t test_vtrn_s16(int16x4_t a, int16x4_t b) {
return vtrn_s16(a, b);
@@ -20513,7 +20512,7 @@ int16x4x2_t test_vtrn_s16(int16x4_t a, int16x4_t b) {
// CHECK: store <2 x i32> [[VTRN1_I]], <2 x i32>* [[TMP4]], !noalias !9
// CHECK: [[TMP5:%.*]] = bitcast %struct.int32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
int32x2x2_t test_vtrn_s32(int32x2_t a, int32x2_t b) {
return vtrn_s32(a, b);
@@ -20530,7 +20529,7 @@ int32x2x2_t test_vtrn_s32(int32x2_t a, int32x2_t b) {
// CHECK: store <8 x i8> [[VTRN1_I]], <8 x i8>* [[TMP2]], !noalias !12
// CHECK: [[TMP3:%.*]] = bitcast %struct.uint8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.uint8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint8x8x2_t test_vtrn_u8(uint8x8_t a, uint8x8_t b) {
return vtrn_u8(a, b);
@@ -20549,7 +20548,7 @@ uint8x8x2_t test_vtrn_u8(uint8x8_t a, uint8x8_t b) {
// CHECK: store <4 x i16> [[VTRN1_I]], <4 x i16>* [[TMP4]], !noalias !15
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint16x4x2_t test_vtrn_u16(uint16x4_t a, uint16x4_t b) {
return vtrn_u16(a, b);
@@ -20568,7 +20567,7 @@ uint16x4x2_t test_vtrn_u16(uint16x4_t a, uint16x4_t b) {
// CHECK: store <2 x i32> [[VTRN1_I]], <2 x i32>* [[TMP4]], !noalias !18
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint32x2x2_t test_vtrn_u32(uint32x2_t a, uint32x2_t b) {
return vtrn_u32(a, b);
@@ -20587,7 +20586,7 @@ uint32x2x2_t test_vtrn_u32(uint32x2_t a, uint32x2_t b) {
// CHECK: store <2 x float> [[VTRN1_I]], <2 x float>* [[TMP4]], !noalias !21
// CHECK: [[TMP5:%.*]] = bitcast %struct.float32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.float32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
float32x2x2_t test_vtrn_f32(float32x2_t a, float32x2_t b) {
return vtrn_f32(a, b);
@@ -20604,7 +20603,7 @@ float32x2x2_t test_vtrn_f32(float32x2_t a, float32x2_t b) {
// CHECK: store <8 x i8> [[VTRN1_I]], <8 x i8>* [[TMP2]], !noalias !24
// CHECK: [[TMP3:%.*]] = bitcast %struct.poly8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.poly8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
poly8x8x2_t test_vtrn_p8(poly8x8_t a, poly8x8_t b) {
return vtrn_p8(a, b);
@@ -20623,7 +20622,7 @@ poly8x8x2_t test_vtrn_p8(poly8x8_t a, poly8x8_t b) {
// CHECK: store <4 x i16> [[VTRN1_I]], <4 x i16>* [[TMP4]], !noalias !27
// CHECK: [[TMP5:%.*]] = bitcast %struct.poly16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.poly16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
poly16x4x2_t test_vtrn_p16(poly16x4_t a, poly16x4_t b) {
return vtrn_p16(a, b);
@@ -20640,7 +20639,7 @@ poly16x4x2_t test_vtrn_p16(poly16x4_t a, poly16x4_t b) {
// CHECK: store <16 x i8> [[VTRN1_I]], <16 x i8>* [[TMP2]], !noalias !30
// CHECK: [[TMP3:%.*]] = bitcast %struct.int8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.int8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
int8x16x2_t test_vtrnq_s8(int8x16_t a, int8x16_t b) {
return vtrnq_s8(a, b);
@@ -20659,7 +20658,7 @@ int8x16x2_t test_vtrnq_s8(int8x16_t a, int8x16_t b) {
// CHECK: store <8 x i16> [[VTRN1_I]], <8 x i16>* [[TMP4]], !noalias !33
// CHECK: [[TMP5:%.*]] = bitcast %struct.int16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
int16x8x2_t test_vtrnq_s16(int16x8_t a, int16x8_t b) {
return vtrnq_s16(a, b);
@@ -20678,7 +20677,7 @@ int16x8x2_t test_vtrnq_s16(int16x8_t a, int16x8_t b) {
// CHECK: store <4 x i32> [[VTRN1_I]], <4 x i32>* [[TMP4]], !noalias !36
// CHECK: [[TMP5:%.*]] = bitcast %struct.int32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
int32x4x2_t test_vtrnq_s32(int32x4_t a, int32x4_t b) {
return vtrnq_s32(a, b);
@@ -20695,7 +20694,7 @@ int32x4x2_t test_vtrnq_s32(int32x4_t a, int32x4_t b) {
// CHECK: store <16 x i8> [[VTRN1_I]], <16 x i8>* [[TMP2]], !noalias !39
// CHECK: [[TMP3:%.*]] = bitcast %struct.uint8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.uint8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint8x16x2_t test_vtrnq_u8(uint8x16_t a, uint8x16_t b) {
return vtrnq_u8(a, b);
@@ -20714,7 +20713,7 @@ uint8x16x2_t test_vtrnq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK: store <8 x i16> [[VTRN1_I]], <8 x i16>* [[TMP4]], !noalias !42
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint16x8x2_t test_vtrnq_u16(uint16x8_t a, uint16x8_t b) {
return vtrnq_u16(a, b);
@@ -20733,7 +20732,7 @@ uint16x8x2_t test_vtrnq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK: store <4 x i32> [[VTRN1_I]], <4 x i32>* [[TMP4]], !noalias !45
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint32x4x2_t test_vtrnq_u32(uint32x4_t a, uint32x4_t b) {
return vtrnq_u32(a, b);
@@ -20752,7 +20751,7 @@ uint32x4x2_t test_vtrnq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK: store <4 x float> [[VTRN1_I]], <4 x float>* [[TMP4]], !noalias !48
// CHECK: [[TMP5:%.*]] = bitcast %struct.float32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.float32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
float32x4x2_t test_vtrnq_f32(float32x4_t a, float32x4_t b) {
return vtrnq_f32(a, b);
@@ -20769,7 +20768,7 @@ float32x4x2_t test_vtrnq_f32(float32x4_t a, float32x4_t b) {
// CHECK: store <16 x i8> [[VTRN1_I]], <16 x i8>* [[TMP2]], !noalias !51
// CHECK: [[TMP3:%.*]] = bitcast %struct.poly8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.poly8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
poly8x16x2_t test_vtrnq_p8(poly8x16_t a, poly8x16_t b) {
return vtrnq_p8(a, b);
@@ -20788,7 +20787,7 @@ poly8x16x2_t test_vtrnq_p8(poly8x16_t a, poly8x16_t b) {
// CHECK: store <8 x i16> [[VTRN1_I]], <8 x i16>* [[TMP4]], !noalias !54
// CHECK: [[TMP5:%.*]] = bitcast %struct.poly16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.poly16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
poly16x8x2_t test_vtrnq_p16(poly16x8_t a, poly16x8_t b) {
return vtrnq_p16(a, b);
@@ -20969,7 +20968,7 @@ uint16x8_t test_vtstq_p16(poly16x8_t a, poly16x8_t b) {
// CHECK: store <8 x i8> [[VUZP1_I]], <8 x i8>* [[TMP2]], !noalias !57
// CHECK: [[TMP3:%.*]] = bitcast %struct.int8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.int8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
int8x8x2_t test_vuzp_s8(int8x8_t a, int8x8_t b) {
return vuzp_s8(a, b);
@@ -20988,7 +20987,7 @@ int8x8x2_t test_vuzp_s8(int8x8_t a, int8x8_t b) {
// CHECK: store <4 x i16> [[VUZP1_I]], <4 x i16>* [[TMP4]], !noalias !60
// CHECK: [[TMP5:%.*]] = bitcast %struct.int16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
int16x4x2_t test_vuzp_s16(int16x4_t a, int16x4_t b) {
return vuzp_s16(a, b);
@@ -21007,7 +21006,7 @@ int16x4x2_t test_vuzp_s16(int16x4_t a, int16x4_t b) {
// CHECK: store <2 x i32> [[VUZP1_I]], <2 x i32>* [[TMP4]], !noalias !63
// CHECK: [[TMP5:%.*]] = bitcast %struct.int32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
int32x2x2_t test_vuzp_s32(int32x2_t a, int32x2_t b) {
return vuzp_s32(a, b);
@@ -21024,7 +21023,7 @@ int32x2x2_t test_vuzp_s32(int32x2_t a, int32x2_t b) {
// CHECK: store <8 x i8> [[VUZP1_I]], <8 x i8>* [[TMP2]], !noalias !66
// CHECK: [[TMP3:%.*]] = bitcast %struct.uint8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.uint8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint8x8x2_t test_vuzp_u8(uint8x8_t a, uint8x8_t b) {
return vuzp_u8(a, b);
@@ -21043,7 +21042,7 @@ uint8x8x2_t test_vuzp_u8(uint8x8_t a, uint8x8_t b) {
// CHECK: store <4 x i16> [[VUZP1_I]], <4 x i16>* [[TMP4]], !noalias !69
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint16x4x2_t test_vuzp_u16(uint16x4_t a, uint16x4_t b) {
return vuzp_u16(a, b);
@@ -21062,7 +21061,7 @@ uint16x4x2_t test_vuzp_u16(uint16x4_t a, uint16x4_t b) {
// CHECK: store <2 x i32> [[VUZP1_I]], <2 x i32>* [[TMP4]], !noalias !72
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint32x2x2_t test_vuzp_u32(uint32x2_t a, uint32x2_t b) {
return vuzp_u32(a, b);
@@ -21081,7 +21080,7 @@ uint32x2x2_t test_vuzp_u32(uint32x2_t a, uint32x2_t b) {
// CHECK: store <2 x float> [[VUZP1_I]], <2 x float>* [[TMP4]], !noalias !75
// CHECK: [[TMP5:%.*]] = bitcast %struct.float32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.float32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
float32x2x2_t test_vuzp_f32(float32x2_t a, float32x2_t b) {
return vuzp_f32(a, b);
@@ -21098,7 +21097,7 @@ float32x2x2_t test_vuzp_f32(float32x2_t a, float32x2_t b) {
// CHECK: store <8 x i8> [[VUZP1_I]], <8 x i8>* [[TMP2]], !noalias !78
// CHECK: [[TMP3:%.*]] = bitcast %struct.poly8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.poly8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
poly8x8x2_t test_vuzp_p8(poly8x8_t a, poly8x8_t b) {
return vuzp_p8(a, b);
@@ -21117,7 +21116,7 @@ poly8x8x2_t test_vuzp_p8(poly8x8_t a, poly8x8_t b) {
// CHECK: store <4 x i16> [[VUZP1_I]], <4 x i16>* [[TMP4]], !noalias !81
// CHECK: [[TMP5:%.*]] = bitcast %struct.poly16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.poly16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
poly16x4x2_t test_vuzp_p16(poly16x4_t a, poly16x4_t b) {
return vuzp_p16(a, b);
@@ -21134,7 +21133,7 @@ poly16x4x2_t test_vuzp_p16(poly16x4_t a, poly16x4_t b) {
// CHECK: store <16 x i8> [[VUZP1_I]], <16 x i8>* [[TMP2]], !noalias !84
// CHECK: [[TMP3:%.*]] = bitcast %struct.int8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.int8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
int8x16x2_t test_vuzpq_s8(int8x16_t a, int8x16_t b) {
return vuzpq_s8(a, b);
@@ -21153,7 +21152,7 @@ int8x16x2_t test_vuzpq_s8(int8x16_t a, int8x16_t b) {
// CHECK: store <8 x i16> [[VUZP1_I]], <8 x i16>* [[TMP4]], !noalias !87
// CHECK: [[TMP5:%.*]] = bitcast %struct.int16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
int16x8x2_t test_vuzpq_s16(int16x8_t a, int16x8_t b) {
return vuzpq_s16(a, b);
@@ -21172,7 +21171,7 @@ int16x8x2_t test_vuzpq_s16(int16x8_t a, int16x8_t b) {
// CHECK: store <4 x i32> [[VUZP1_I]], <4 x i32>* [[TMP4]], !noalias !90
// CHECK: [[TMP5:%.*]] = bitcast %struct.int32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
int32x4x2_t test_vuzpq_s32(int32x4_t a, int32x4_t b) {
return vuzpq_s32(a, b);
@@ -21189,7 +21188,7 @@ int32x4x2_t test_vuzpq_s32(int32x4_t a, int32x4_t b) {
// CHECK: store <16 x i8> [[VUZP1_I]], <16 x i8>* [[TMP2]], !noalias !93
// CHECK: [[TMP3:%.*]] = bitcast %struct.uint8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.uint8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint8x16x2_t test_vuzpq_u8(uint8x16_t a, uint8x16_t b) {
return vuzpq_u8(a, b);
@@ -21208,7 +21207,7 @@ uint8x16x2_t test_vuzpq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK: store <8 x i16> [[VUZP1_I]], <8 x i16>* [[TMP4]], !noalias !96
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint16x8x2_t test_vuzpq_u16(uint16x8_t a, uint16x8_t b) {
return vuzpq_u16(a, b);
@@ -21227,7 +21226,7 @@ uint16x8x2_t test_vuzpq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK: store <4 x i32> [[VUZP1_I]], <4 x i32>* [[TMP4]], !noalias !99
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint32x4x2_t test_vuzpq_u32(uint32x4_t a, uint32x4_t b) {
return vuzpq_u32(a, b);
@@ -21246,7 +21245,7 @@ uint32x4x2_t test_vuzpq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK: store <4 x float> [[VUZP1_I]], <4 x float>* [[TMP4]], !noalias !102
// CHECK: [[TMP5:%.*]] = bitcast %struct.float32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.float32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
float32x4x2_t test_vuzpq_f32(float32x4_t a, float32x4_t b) {
return vuzpq_f32(a, b);
@@ -21263,7 +21262,7 @@ float32x4x2_t test_vuzpq_f32(float32x4_t a, float32x4_t b) {
// CHECK: store <16 x i8> [[VUZP1_I]], <16 x i8>* [[TMP2]], !noalias !105
// CHECK: [[TMP3:%.*]] = bitcast %struct.poly8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.poly8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
poly8x16x2_t test_vuzpq_p8(poly8x16_t a, poly8x16_t b) {
return vuzpq_p8(a, b);
@@ -21282,7 +21281,7 @@ poly8x16x2_t test_vuzpq_p8(poly8x16_t a, poly8x16_t b) {
// CHECK: store <8 x i16> [[VUZP1_I]], <8 x i16>* [[TMP4]], !noalias !108
// CHECK: [[TMP5:%.*]] = bitcast %struct.poly16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.poly16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
poly16x8x2_t test_vuzpq_p16(poly16x8_t a, poly16x8_t b) {
return vuzpq_p16(a, b);
@@ -21299,7 +21298,7 @@ poly16x8x2_t test_vuzpq_p16(poly16x8_t a, poly16x8_t b) {
// CHECK: store <8 x i8> [[VZIP1_I]], <8 x i8>* [[TMP2]], !noalias !111
// CHECK: [[TMP3:%.*]] = bitcast %struct.int8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.int8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
int8x8x2_t test_vzip_s8(int8x8_t a, int8x8_t b) {
return vzip_s8(a, b);
@@ -21318,7 +21317,7 @@ int8x8x2_t test_vzip_s8(int8x8_t a, int8x8_t b) {
// CHECK: store <4 x i16> [[VZIP1_I]], <4 x i16>* [[TMP4]], !noalias !114
// CHECK: [[TMP5:%.*]] = bitcast %struct.int16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
int16x4x2_t test_vzip_s16(int16x4_t a, int16x4_t b) {
return vzip_s16(a, b);
@@ -21337,7 +21336,7 @@ int16x4x2_t test_vzip_s16(int16x4_t a, int16x4_t b) {
// CHECK: store <2 x i32> [[VZIP1_I]], <2 x i32>* [[TMP4]], !noalias !117
// CHECK: [[TMP5:%.*]] = bitcast %struct.int32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
int32x2x2_t test_vzip_s32(int32x2_t a, int32x2_t b) {
return vzip_s32(a, b);
@@ -21354,7 +21353,7 @@ int32x2x2_t test_vzip_s32(int32x2_t a, int32x2_t b) {
// CHECK: store <8 x i8> [[VZIP1_I]], <8 x i8>* [[TMP2]], !noalias !120
// CHECK: [[TMP3:%.*]] = bitcast %struct.uint8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.uint8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint8x8x2_t test_vzip_u8(uint8x8_t a, uint8x8_t b) {
return vzip_u8(a, b);
@@ -21373,7 +21372,7 @@ uint8x8x2_t test_vzip_u8(uint8x8_t a, uint8x8_t b) {
// CHECK: store <4 x i16> [[VZIP1_I]], <4 x i16>* [[TMP4]], !noalias !123
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint16x4x2_t test_vzip_u16(uint16x4_t a, uint16x4_t b) {
return vzip_u16(a, b);
@@ -21392,7 +21391,7 @@ uint16x4x2_t test_vzip_u16(uint16x4_t a, uint16x4_t b) {
// CHECK: store <2 x i32> [[VZIP1_I]], <2 x i32>* [[TMP4]], !noalias !126
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
uint32x2x2_t test_vzip_u32(uint32x2_t a, uint32x2_t b) {
return vzip_u32(a, b);
@@ -21411,7 +21410,7 @@ uint32x2x2_t test_vzip_u32(uint32x2_t a, uint32x2_t b) {
// CHECK: store <2 x float> [[VZIP1_I]], <2 x float>* [[TMP4]], !noalias !129
// CHECK: [[TMP5:%.*]] = bitcast %struct.float32x2x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.float32x2x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
float32x2x2_t test_vzip_f32(float32x2_t a, float32x2_t b) {
return vzip_f32(a, b);
@@ -21428,7 +21427,7 @@ float32x2x2_t test_vzip_f32(float32x2_t a, float32x2_t b) {
// CHECK: store <8 x i8> [[VZIP1_I]], <8 x i8>* [[TMP2]], !noalias !132
// CHECK: [[TMP3:%.*]] = bitcast %struct.poly8x8x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.poly8x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 16, i32 8, i1 false)
// CHECK: ret void
poly8x8x2_t test_vzip_p8(poly8x8_t a, poly8x8_t b) {
return vzip_p8(a, b);
@@ -21447,7 +21446,7 @@ poly8x8x2_t test_vzip_p8(poly8x8_t a, poly8x8_t b) {
// CHECK: store <4 x i16> [[VZIP1_I]], <4 x i16>* [[TMP4]], !noalias !135
// CHECK: [[TMP5:%.*]] = bitcast %struct.poly16x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.poly16x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 16, i32 8, i1 false)
// CHECK: ret void
poly16x4x2_t test_vzip_p16(poly16x4_t a, poly16x4_t b) {
return vzip_p16(a, b);
@@ -21464,7 +21463,7 @@ poly16x4x2_t test_vzip_p16(poly16x4_t a, poly16x4_t b) {
// CHECK: store <16 x i8> [[VZIP1_I]], <16 x i8>* [[TMP2]], !noalias !138
// CHECK: [[TMP3:%.*]] = bitcast %struct.int8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.int8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
int8x16x2_t test_vzipq_s8(int8x16_t a, int8x16_t b) {
return vzipq_s8(a, b);
@@ -21483,7 +21482,7 @@ int8x16x2_t test_vzipq_s8(int8x16_t a, int8x16_t b) {
// CHECK: store <8 x i16> [[VZIP1_I]], <8 x i16>* [[TMP4]], !noalias !141
// CHECK: [[TMP5:%.*]] = bitcast %struct.int16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
int16x8x2_t test_vzipq_s16(int16x8_t a, int16x8_t b) {
return vzipq_s16(a, b);
@@ -21502,7 +21501,7 @@ int16x8x2_t test_vzipq_s16(int16x8_t a, int16x8_t b) {
// CHECK: store <4 x i32> [[VZIP1_I]], <4 x i32>* [[TMP4]], !noalias !144
// CHECK: [[TMP5:%.*]] = bitcast %struct.int32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.int32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
int32x4x2_t test_vzipq_s32(int32x4_t a, int32x4_t b) {
return vzipq_s32(a, b);
@@ -21519,7 +21518,7 @@ int32x4x2_t test_vzipq_s32(int32x4_t a, int32x4_t b) {
// CHECK: store <16 x i8> [[VZIP1_I]], <16 x i8>* [[TMP2]], !noalias !147
// CHECK: [[TMP3:%.*]] = bitcast %struct.uint8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.uint8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint8x16x2_t test_vzipq_u8(uint8x16_t a, uint8x16_t b) {
return vzipq_u8(a, b);
@@ -21538,7 +21537,7 @@ uint8x16x2_t test_vzipq_u8(uint8x16_t a, uint8x16_t b) {
// CHECK: store <8 x i16> [[VZIP1_I]], <8 x i16>* [[TMP4]], !noalias !150
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint16x8x2_t test_vzipq_u16(uint16x8_t a, uint16x8_t b) {
return vzipq_u16(a, b);
@@ -21557,7 +21556,7 @@ uint16x8x2_t test_vzipq_u16(uint16x8_t a, uint16x8_t b) {
// CHECK: store <4 x i32> [[VZIP1_I]], <4 x i32>* [[TMP4]], !noalias !153
// CHECK: [[TMP5:%.*]] = bitcast %struct.uint32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.uint32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
uint32x4x2_t test_vzipq_u32(uint32x4_t a, uint32x4_t b) {
return vzipq_u32(a, b);
@@ -21576,7 +21575,7 @@ uint32x4x2_t test_vzipq_u32(uint32x4_t a, uint32x4_t b) {
// CHECK: store <4 x float> [[VZIP1_I]], <4 x float>* [[TMP4]], !noalias !156
// CHECK: [[TMP5:%.*]] = bitcast %struct.float32x4x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.float32x4x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
float32x4x2_t test_vzipq_f32(float32x4_t a, float32x4_t b) {
return vzipq_f32(a, b);
@@ -21593,7 +21592,7 @@ float32x4x2_t test_vzipq_f32(float32x4_t a, float32x4_t b) {
// CHECK: store <16 x i8> [[VZIP1_I]], <16 x i8>* [[TMP2]], !noalias !159
// CHECK: [[TMP3:%.*]] = bitcast %struct.poly8x16x2_t* %agg.result to i8*
// CHECK: [[TMP4:%.*]] = bitcast %struct.poly8x16x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP3]], i8* [[TMP4]], i32 32, i32 16, i1 false)
// CHECK: ret void
poly8x16x2_t test_vzipq_p8(poly8x16_t a, poly8x16_t b) {
return vzipq_p8(a, b);
@@ -21612,7 +21611,7 @@ poly8x16x2_t test_vzipq_p8(poly8x16_t a, poly8x16_t b) {
// CHECK: store <8 x i16> [[VZIP1_I]], <8 x i16>* [[TMP4]], !noalias !162
// CHECK: [[TMP5:%.*]] = bitcast %struct.poly16x8x2_t* %agg.result to i8*
// CHECK: [[TMP6:%.*]] = bitcast %struct.poly16x8x2_t* [[__RET_I]] to i8*
-// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false) #4
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[TMP5]], i8* [[TMP6]], i32 32, i32 16, i1 false)
// CHECK: ret void
poly16x8x2_t test_vzipq_p16(poly16x8_t a, poly16x8_t b) {
return vzipq_p16(a, b);
diff --git a/test/CodeGen/asan-globals-gc.cpp b/test/CodeGen/asan-globals-gc.cpp
new file mode 100644
index 0000000000..58ce5f0675
--- /dev/null
+++ b/test/CodeGen/asan-globals-gc.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fdata-sections -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITH-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fno-integrated-as -fdata-sections -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fno-integrated-as -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+// RUN: %clang_cc1 -fsanitize=address -fdata-sections -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fno-data-sections -emit-llvm -o - -triple x86_64-windows-msvc %s | FileCheck %s --check-prefix=WITH-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fdata-sections -emit-llvm -o - -triple x86_64-windows-msvc %s | FileCheck %s --check-prefix=WITH-GC
+// RUN: %clang_cc1 -fsanitize=address -fdata-sections -emit-llvm -o - -triple x86_64-windows-msvc %s | FileCheck %s --check-prefix=WITHOUT-GC
+
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fno-data-sections -emit-llvm -o - -triple x86_64-apple-macosx11 %s | FileCheck %s --check-prefix=WITH-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fdata-sections -emit-llvm -o - -triple x86_64-apple-macosx11 %s | FileCheck %s --check-prefix=WITH-GC
+// RUN: %clang_cc1 -fsanitize=address -fdata-sections -emit-llvm -o - -triple x86_64-apple-macosx11 %s | FileCheck %s --check-prefix=WITHOUT-GC
+
+int global;
+
+// WITH-GC-NOT: call void @__asan_register_globals
+// WITHOUT-GC: call void @__asan_register_globals
diff --git a/test/CodeGen/asan-no-globals-no-comdat.cpp b/test/CodeGen/asan-no-globals-no-comdat.cpp
new file mode 100644
index 0000000000..4637346f9c
--- /dev/null
+++ b/test/CodeGen/asan-no-globals-no-comdat.cpp
@@ -0,0 +1,11 @@
+// Test that on Linux asan constructor is placed in a comdat iff globals-gc is on.
+// Even if there are no globals in the module.
+
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fdata-sections -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITH-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fno-integrated-as -fdata-sections -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+// RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fno-integrated-as -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+// RUN: %clang_cc1 -fsanitize=address -fdata-sections -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
+
+// WITH-GC: define internal void @asan.module_ctor() comdat {
+// WITHOUT-GC: define internal void @asan.module_ctor() {
diff --git a/test/CodeGen/atomic-ops-libcall.c b/test/CodeGen/atomic-ops-libcall.c
index 0093a8cbbb..c673b07f8e 100644
--- a/test/CodeGen/atomic-ops-libcall.c
+++ b/test/CodeGen/atomic-ops-libcall.c
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 < %s -triple armv5e-none-linux-gnueabi -emit-llvm -O1 | FileCheck %s
+// FIXME: This file should not be checking -O1 output.
+// Ie, it is testing many IR optimizer passes as part of front-end verification.
+
enum memory_order {
memory_order_relaxed, memory_order_consume, memory_order_acquire,
memory_order_release, memory_order_acq_rel, memory_order_seq_cst
@@ -110,7 +113,8 @@ int test_atomic_xor_fetch(int *p) {
int test_atomic_nand_fetch(int *p) {
// CHECK: test_atomic_nand_fetch
// CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_nand_4(i8* {{%[0-9]+}}, i32 55, i32 5)
- // CHECK: [[OR:%[^ ]*]] = or i32 [[CALL]], -56
- // CHECK: {{%[^ ]*}} = xor i32 [[OR]], 55
+ // FIXME: We should not be checking optimized IR. It changes independently of clang.
+ // FIXME-CHECK: [[AND:%[^ ]*]] = and i32 [[CALL]], 55
+ // FIXME-CHECK: {{%[^ ]*}} = xor i32 [[AND]], -1
return __atomic_nand_fetch(p, 55, memory_order_seq_cst);
}
diff --git a/test/CodeGen/attr-availability.c b/test/CodeGen/attr-availability.c
index ccbbb62f8c..87e137cfe9 100644
--- a/test/CodeGen/attr-availability.c
+++ b/test/CodeGen/attr-availability.c
@@ -8,9 +8,9 @@
void f2();
void f2() { }
-// CHECK-10_4-LABEL: define void @f3
-// CHECK-10_5-LABEL: define void @f3
-// CHECK-10_6-LABEL: define void @f3
+// CHECK-10_4-LABEL: define hidden void @f3
+// CHECK-10_5-LABEL: define hidden void @f3
+// CHECK-10_6-LABEL: define hidden void @f3
void f3() __attribute__((availability(macosx,introduced=10.5)));
void f3() { }
diff --git a/test/CodeGen/attr-coldhot.c b/test/CodeGen/attr-coldhot.c
index ec54edde9d..24e1feb77b 100644
--- a/test/CodeGen/attr-coldhot.c
+++ b/test/CodeGen/attr-coldhot.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s -check-prefixes=CHECK,O0
+// RUN: %clang_cc1 -emit-llvm %s -o - -O1 -disable-llvm-passes | FileCheck %s -check-prefixes=CHECK,O1
int test1() __attribute__((__cold__)) {
return 42;
@@ -8,4 +9,5 @@ int test1() __attribute__((__cold__)) {
// CHECK: ret
}
-// CHECK: attributes [[ATTR]] = { {{.*}}cold{{.*}}optsize{{.*}} }
+// O0: attributes [[ATTR]] = { {{.*}}cold{{.*}}optnone{{.*}} }
+// O1: attributes [[ATTR]] = { {{.*}}cold{{.*}}optsize{{.*}} }
diff --git a/test/CodeGen/attr-naked.c b/test/CodeGen/attr-naked.c
index 270fc7959f..34e745b374 100644
--- a/test/CodeGen/attr-naked.c
+++ b/test/CodeGen/attr-naked.c
@@ -4,14 +4,14 @@ void t1() __attribute__((naked));
// Basic functionality check
// (Note that naked needs to imply noinline to work properly.)
-// CHECK: define void @t1() [[NAKED:#[0-9]+]] {
+// CHECK: define void @t1() [[NAKED_OPTNONE:#[0-9]+]] {
void t1()
{
}
// Make sure this doesn't explode in the verifier.
// (It doesn't really make sense, but it isn't invalid.)
-// CHECK: define void @t2() [[NAKED]] {
+// CHECK: define void @t2() [[NAKED:#[0-9]+]] {
__attribute((naked, always_inline)) void t2() {
}
@@ -23,4 +23,5 @@ __attribute((naked)) void t3(int x) {
// CHECK: unreachable
}
+// CHECK: attributes [[NAKED_OPTNONE]] = { naked noinline nounwind optnone{{.*}} }
// CHECK: attributes [[NAKED]] = { naked noinline nounwind{{.*}} }
diff --git a/test/CodeGen/attr-target-x86.c b/test/CodeGen/attr-target-x86.c
index 7557ec7acd..6ec2d6578d 100644
--- a/test/CodeGen/attr-target-x86.c
+++ b/test/CodeGen/attr-target-x86.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -target-cpu x86-64 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i686-linux-gnu -target-cpu i686 -emit-llvm %s -o - | FileCheck %s
int baz(int a) { return 4; }
@@ -10,6 +10,7 @@ int __attribute__((target("fpmath=387"))) koala(int a) { return 4; }
int __attribute__((target("no-sse2"))) echidna(int a) { return 4; }
int __attribute__((target("sse4"))) panda(int a) { return 4; }
+int __attribute__((target("no-sse4"))) narwhal(int a) { return 4; }
int bar(int a) { return baz(a) + foo(a); }
@@ -18,7 +19,7 @@ int __attribute__((target("no-aes, arch=ivybridge"))) qax(int a) { return 4; }
int __attribute__((target("no-mmx"))) qq(int a) { return 40; }
-int __attribute__((target("arch=lakemont"))) lake(int a) { return 4; }
+int __attribute__((target("arch=lakemont,mmx"))) lake(int a) { return 4; }
// Check that we emit the additional subtarget and cpu features for foo and not for baz or bar.
// CHECK: baz{{.*}} #0
@@ -29,15 +30,17 @@ int __attribute__((target("arch=lakemont"))) lake(int a) { return 4; }
// CHECK: koala{{.*}} #0
// CHECK: echidna{{.*}} #2
// CHECK: panda{{.*}} #3
+// CHECK: narwhal{{.*}} #4
// CHECK: bar{{.*}} #0
// CHECK: qux{{.*}} #1
-// CHECK: qax{{.*}} #4
-// CHECK: qq{{.*}} #5
-// CHECK: lake{{.*}} #6
-// CHECK: #0 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87"
+// CHECK: qax{{.*}} #5
+// CHECK: qq{{.*}} #6
+// CHECK: lake{{.*}} #7
+// CHECK: #0 = {{.*}}"target-cpu"="i686" "target-features"="+x87"
// CHECK: #1 = {{.*}}"target-cpu"="ivybridge" "target-features"="+aes,+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"
-// CHECK: #2 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+x87,-aes,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-f16c,-fma,-fma4,-pclmul,-sha,-sse2,-sse3,-sse4.1,-sse4.2,-sse4a,-ssse3,-xop,-xsave,-xsaveopt"
-// CHECK: #3 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"
-// CHECK: #4 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt,-aes"
-// CHECK: #5 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+sse,+sse2,+x87,-3dnow,-3dnowa,-mmx"
-// CHECK: #6 = {{.*}}"target-cpu"="lakemont" "target-features"="+mmx,+sse,+sse2"
+// CHECK: #2 = {{.*}}"target-cpu"="i686" "target-features"="+x87,-aes,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-pclmul,-sha,-sse2,-sse3,-sse4.1,-sse4.2,-sse4a,-ssse3,-xop,-xsave,-xsaveopt"
+// CHECK: #3 = {{.*}}"target-cpu"="i686" "target-features"="+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"
+// CHECK: #4 = {{.*}}"target-cpu"="i686" "target-features"="+x87,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-sse4.1,-sse4.2,-xop,-xsave,-xsaveopt"
+// CHECK: #5 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt,-aes"
+// CHECK: #6 = {{.*}}"target-cpu"="i686" "target-features"="+x87,-3dnow,-3dnowa,-mmx"
+// CHECK: #7 = {{.*}}"target-cpu"="lakemont" "target-features"="+mmx"
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
index 9e5fa9f906..34833a2469 100644
--- a/test/CodeGen/attributes.c
+++ b/test/CodeGen/attributes.c
@@ -56,6 +56,13 @@ void t4() {}
void t7() __attribute__((noreturn, nothrow));
void t7() { while (1) {} }
+// CHECK: define void @t72() [[COLDDEF:#[0-9]+]] {
+void t71(void) __attribute__((cold));
+void t72() __attribute__((cold));
+void t72() { t71(); }
+// CHECK: call void @t71() [[COLDSITE:#[0-9]+]]
+// CHECK: declare void @t71() [[COLDDECL:#[0-9]+]]
+
// CHECK: define void @t10() [[NUW]] section "SECT" {
void t10(void) __attribute__((section("SECT")));
void t10(void) {}
@@ -92,3 +99,6 @@ void __attribute__((section(".bar"))) t22(void) {}
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }
// CHECK: attributes [[NR]] = { noinline noreturn nounwind{{.*}} }
+// CHECK: attributes [[COLDDEF]] = { cold {{.*}}}
+// CHECK: attributes [[COLDDECL]] = { cold {{.*}}}
+// CHECK: attributes [[COLDSITE]] = { cold {{.*}}}
diff --git a/test/CodeGen/avx-builtins.c b/test/CodeGen/avx-builtins.c
index 4832664081..4e77ad166c 100644
--- a/test/CodeGen/avx-builtins.c
+++ b/test/CodeGen/avx-builtins.c
@@ -678,19 +678,19 @@ __m256 test_mm256_permute_ps(__m256 A) {
__m256d test_mm256_permute2f128_pd(__m256d A, __m256d B) {
// CHECK-LABEL: test_mm256_permute2f128_pd
- // CHECK: call <4 x double> @llvm.x86.avx.vperm2f128.pd.256(<4 x double> %{{.*}}, <4 x double> %{{.*}}, i8 49)
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
return _mm256_permute2f128_pd(A, B, 0x31);
}
__m256 test_mm256_permute2f128_ps(__m256 A, __m256 B) {
// CHECK-LABEL: test_mm256_permute2f128_ps
- // CHECK: call <8 x float> @llvm.x86.avx.vperm2f128.ps.256(<8 x float> %{{.*}}, <8 x float> %{{.*}}, i8 19)
+ // CHECK: shufflevector <8 x float> %{{.*}}, <8 x float> %{{.*}}, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 12, i32 13, i32 14, i32 15>
return _mm256_permute2f128_ps(A, B, 0x13);
}
__m256i test_mm256_permute2f128_si256(__m256i A, __m256i B) {
// CHECK-LABEL: test_mm256_permute2f128_si256
- // CHECK: call <8 x i32> @llvm.x86.avx.vperm2f128.si.256(<8 x i32> %{{.*}}, <8 x i32> %{{.*}}, i8 32)
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11>
return _mm256_permute2f128_si256(A, B, 0x20);
}
@@ -1386,6 +1386,27 @@ void test_mm256_zeroupper() {
return _mm256_zeroupper();
}
+__m256d test_mm256_zextpd128_pd256(__m128d A) {
+ // CHECK-LABEL: test_mm256_zextpd128_pd256
+ // CHECK: store <2 x double> zeroinitializer
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ return _mm256_zextpd128_pd256(A);
+}
+
+__m256 test_mm256_zextps128_ps256(__m128 A) {
+ // CHECK-LABEL: test_mm256_zextps128_ps256
+ // CHECK: store <4 x float> zeroinitializer
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return _mm256_zextps128_ps256(A);
+}
+
+__m256i test_mm256_zextsi128_si256(__m128i A) {
+ // CHECK-LABEL: test_mm256_zextsi128_si256
+ // CHECK: store <2 x i64> zeroinitializer
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ return _mm256_zextsi128_si256(A);
+}
+
double test_mm256_cvtsd_f64(__m256d __a)
{
// CHECK-LABEL: @test_mm256_cvtsd_f64
@@ -1406,3 +1427,51 @@ float test_mm256_cvtss_f32(__m256 __a)
// CHECK: extractelement <8 x float> %{{.*}}, i32 0
return _mm256_cvtss_f32(__a);
}
+
+__m256 test_mm256_cmp_ps_true(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_ps_true
+ // CHECK: store <8 x float> <float 0xFFFFFFFFE0000000,
+ return _mm256_cmp_ps(a, b, _CMP_TRUE_UQ);
+}
+
+__m256 test_mm256_cmp_pd_true(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_pd_true
+ // CHECK: store <4 x double> <double 0xFFFFFFFFFFFFFFFF,
+ return _mm256_cmp_pd(a, b, _CMP_TRUE_UQ);
+}
+
+__m256 test_mm256_cmp_ps_false(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_ps_false
+ // CHECK: store <8 x float> zeroinitializer, <8 x float>* %tmp, align 32
+ return _mm256_cmp_ps(a, b, _CMP_FALSE_OQ);
+}
+
+__m256 test_mm256_cmp_pd_false(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_pd_false
+ // CHECK: store <4 x double> zeroinitializer, <4 x double>* %tmp, align 32
+ return _mm256_cmp_pd(a, b, _CMP_FALSE_OQ);
+}
+
+__m256 test_mm256_cmp_ps_strue(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_ps_strue
+ // CHECK: store <8 x float> <float 0xFFFFFFFFE0000000,
+ return _mm256_cmp_ps(a, b, _CMP_TRUE_US);
+}
+
+__m256 test_mm256_cmp_pd_strue(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_pd_strue
+ // CHECK: store <4 x double> <double 0xFFFFFFFFFFFFFFFF,
+ return _mm256_cmp_pd(a, b, _CMP_TRUE_US);
+}
+
+__m256 test_mm256_cmp_ps_sfalse(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_ps_sfalse
+ // CHECK: store <8 x float> zeroinitializer, <8 x float>* %tmp, align 32
+ return _mm256_cmp_ps(a, b, _CMP_FALSE_OS);
+}
+
+__m256 test_mm256_cmp_pd_sfalse(__m256 a, __m256 b) {
+ // CHECK-LABEL: @test_mm256_cmp_pd_sfalse
+ // CHECK: store <4 x double> zeroinitializer, <4 x double>* %tmp, align 32
+ return _mm256_cmp_pd(a, b, _CMP_FALSE_OS);
+}
diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c
index 31b02ac14e..f79f60e6db 100644
--- a/test/CodeGen/avx2-builtins.c
+++ b/test/CodeGen/avx2-builtins.c
@@ -8,19 +8,25 @@
__m256i test_mm256_abs_epi8(__m256i a) {
// CHECK-LABEL: test_mm256_abs_epi8
- // CHECK: call <32 x i8> @llvm.x86.avx2.pabs.b(<32 x i8> %{{.*}})
+ // CHECK: [[SUB:%.*]] = sub <32 x i8> zeroinitializer, %{{.*}}
+ // CHECK: [[CMP:%.*]] = icmp sgt <32 x i8> %{{.*}}, zeroinitializer
+ // CHECK: select <32 x i1> [[CMP]], <32 x i8> %{{.*}}, <32 x i8> [[SUB]]
return _mm256_abs_epi8(a);
}
__m256i test_mm256_abs_epi16(__m256i a) {
// CHECK-LABEL: test_mm256_abs_epi16
- // CHECK: call <16 x i16> @llvm.x86.avx2.pabs.w(<16 x i16> %{{.*}})
+ // CHECK: [[SUB:%.*]] = sub <16 x i16> zeroinitializer, %{{.*}}
+ // CHECK: [[CMP:%.*]] = icmp sgt <16 x i16> %{{.*}}, zeroinitializer
+ // CHECK: select <16 x i1> [[CMP]], <16 x i16> %{{.*}}, <16 x i16> [[SUB]]
return _mm256_abs_epi16(a);
}
__m256i test_mm256_abs_epi32(__m256i a) {
// CHECK-LABEL: test_mm256_abs_epi32
- // CHECK: call <8 x i32> @llvm.x86.avx2.pabs.d(<8 x i32> %{{.*}})
+ // CHECK: [[SUB:%.*]] = sub <8 x i32> zeroinitializer, %{{.*}}
+ // CHECK: [[CMP:%.*]] = icmp sgt <8 x i32> %{{.*}}, zeroinitializer
+ // CHECK: select <8 x i1> [[CMP]], <8 x i32> %{{.*}}, <8 x i32> [[SUB]]
return _mm256_abs_epi32(a);
}
@@ -99,13 +105,25 @@ __m256i test_mm256_andnot_si256(__m256i a, __m256i b) {
__m256i test_mm256_avg_epu8(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_avg_epu8
- // CHECK: call <32 x i8> @llvm.x86.avx2.pavg.b(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
+ // CHECK-NOT: call <32 x i8> @llvm.x86.avx2.pavg.b(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
+ // CHECK: zext <32 x i8> %{{.*}} to <32 x i16>
+ // CHECK: zext <32 x i8> %{{.*}} to <32 x i16>
+ // CHECK: add <32 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <32 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <32 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <32 x i16> %{{.*}} to <32 x i8>
return _mm256_avg_epu8(a, b);
}
__m256i test_mm256_avg_epu16(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_avg_epu16
- // CHECK: call <16 x i16> @llvm.x86.avx2.pavg.w(<16 x i16> %{{.*}}, <16 x i16> %{{.*}})
+ // CHECK-NOT: call <16 x i16> @llvm.x86.avx2.pavg.w(<16 x i16> %{{.*}}, <16 x i16> %{{.*}})
+ // CHECK: zext <16 x i16> %{{.*}} to <16 x i32>
+ // CHECK: zext <16 x i16> %{{.*}} to <16 x i32>
+ // CHECK: add <16 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <16 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <16 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <16 x i32> %{{.*}} to <16 x i16>
return _mm256_avg_epu16(a, b);
}
@@ -889,8 +907,8 @@ __m256i test_mm256_packs_epu32(__m256i a, __m256i b) {
__m256i test_mm256_permute2x128_si256(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_permute2x128_si256
- // CHECK: call <4 x i64> @llvm.x86.avx2.vperm2i128(<4 x i64> %{{.*}}, <4 x i64> %{{.*}}, i8 49)
- return _mm256_permute2x128_si256(a, b, 0x31);
+ // CHECK: shufflevector <4 x i64> zeroinitializer, <4 x i64> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 6, i32 7>
+ return _mm256_permute2x128_si256(a, b, 0x38);
}
__m256i test_mm256_permute4x64_epi64(__m256i a) {
@@ -1117,7 +1135,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 993e2964a1..2081cef754 100644
--- a/test/CodeGen/avx512-reduceMinMaxIntrin.c
+++ b/test/CodeGen/avx512-reduceMinMaxIntrin.c
@@ -1,439 +1,2611 @@
-// 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
+// RUN: %clang_cc1 -ffreestanding %s -O0 -triple=x86_64-apple-darwin -target-cpu skylake-avx512 -emit-llvm -o - -Wall -Werror | FileCheck %s
#include <immintrin.h>
+// CHECK-LABEL: define i64 @test_mm512_reduce_max_epi64(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I8_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP1]], <8 x i64> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP3]], <8 x i64> [[TMP4]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = icmp sgt <8 x i64> [[TMP5]], [[TMP6]]
+// CHECK: [[TMP9:%.*]] = select <8 x i1> [[TMP8]], <8 x i64> [[TMP5]], <8 x i64> [[TMP6]]
+// CHECK: store <8 x i64> [[TMP9]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <8 x i64> [[TMP10]], <8 x i64> [[TMP11]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP12]], <8 x i64> [[TMP13]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE2_I]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP17:%.*]] = icmp sgt <8 x i64> [[TMP14]], [[TMP15]]
+// CHECK: [[TMP18:%.*]] = select <8 x i1> [[TMP17]], <8 x i64> [[TMP14]], <8 x i64> [[TMP15]]
+// CHECK: store <8 x i64> [[TMP18]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <8 x i64> [[TMP19]], <8 x i64> [[TMP20]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP21]], <8 x i64> [[TMP22]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE5_I]], <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP26:%.*]] = icmp sgt <8 x i64> [[TMP23]], [[TMP24]]
+// CHECK: [[TMP27:%.*]] = select <8 x i1> [[TMP26]], <8 x i64> [[TMP23]], <8 x i64> [[TMP24]]
+// CHECK: store <8 x i64> [[TMP27]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP28]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
long long test_mm512_reduce_max_epi64(__m512i __W){
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %__W, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp = icmp slt <8 x i64> %shuffle1.i, %__W
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> %shuffle1.i
- // CHECK: %shuffle3.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp sgt <8 x i64> %tmp1, %shuffle3.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp sgt <8 x i64> %tmp3, %shuffle6.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp4, i32 0
- // CHECK: %.elt20.i = extractelement <8 x i64> %tmp3, i32 0
- // CHECK: %shuffle6.elt.i = extractelement <8 x i64> %tmp3, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt20.i, i64 %shuffle6.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_reduce_max_epi64(__W);
}
+// CHECK-LABEL: define i64 @test_mm512_reduce_max_epu64(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I8_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP1]], <8 x i64> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP3]], <8 x i64> [[TMP4]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = icmp ugt <8 x i64> [[TMP5]], [[TMP6]]
+// CHECK: [[TMP9:%.*]] = select <8 x i1> [[TMP8]], <8 x i64> [[TMP5]], <8 x i64> [[TMP6]]
+// CHECK: store <8 x i64> [[TMP9]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <8 x i64> [[TMP10]], <8 x i64> [[TMP11]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP12]], <8 x i64> [[TMP13]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE2_I]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP17:%.*]] = icmp ugt <8 x i64> [[TMP14]], [[TMP15]]
+// CHECK: [[TMP18:%.*]] = select <8 x i1> [[TMP17]], <8 x i64> [[TMP14]], <8 x i64> [[TMP15]]
+// CHECK: store <8 x i64> [[TMP18]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <8 x i64> [[TMP19]], <8 x i64> [[TMP20]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP21]], <8 x i64> [[TMP22]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE5_I]], <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP26:%.*]] = icmp ugt <8 x i64> [[TMP23]], [[TMP24]]
+// CHECK: [[TMP27:%.*]] = select <8 x i1> [[TMP26]], <8 x i64> [[TMP23]], <8 x i64> [[TMP24]]
+// CHECK: store <8 x i64> [[TMP27]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP28]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
unsigned long long test_mm512_reduce_max_epu64(__m512i __W){
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %__W, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp = icmp ult <8 x i64> %shuffle1.i, %__W
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> %shuffle1.i
- // CHECK: %shuffle3.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp ugt <8 x i64> %tmp1, %shuffle3.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp ugt <8 x i64> %tmp3, %shuffle6.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp4, i32 0
- // CHECK: %.elt20.i = extractelement <8 x i64> %tmp3, i32 0
- // CHECK: %shuffle6.elt.i = extractelement <8 x i64> %tmp3, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt20.i, i64 %shuffle6.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_reduce_max_epu64(__W);
}
+// CHECK-LABEL: define double @test_mm512_reduce_max_pd(<8 x double> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I8_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I9_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I10_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x double>, align 64
+// CHECK: store <8 x double> %__W, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x double>, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: store <8 x double> [[TMP0]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x double> [[TMP1]], <8 x double> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x double> [[TMP3]], <8 x double> [[TMP4]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE_I]], <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE1_I]], <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> [[TMP5]], <8 x double> [[TMP6]], <8 x double> [[TMP7]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP8]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <8 x double> [[TMP9]], <8 x double> [[TMP10]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP11:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x double> [[TMP11]], <8 x double> [[TMP12]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE2_I]], <8 x double>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE3_I]], <8 x double>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP16:%.*]] = call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> [[TMP13]], <8 x double> [[TMP14]], <8 x double> [[TMP15]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP16]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP17:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <8 x double> [[TMP17]], <8 x double> [[TMP18]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP19:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x double> [[TMP19]], <8 x double> [[TMP20]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE5_I]], <8 x double>* [[__A_ADDR_I9_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE6_I]], <8 x double>* [[__B_ADDR_I10_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I9_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I10_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP24:%.*]] = call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> [[TMP21]], <8 x double> [[TMP22]], <8 x double> [[TMP23]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP24]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x double> [[TMP25]], i32 0
+// CHECK: ret double [[VECEXT_I]]
double test_mm512_reduce_max_pd(__m512d __W){
- // CHECK: %shuffle1.i = shufflevector <8 x double> %__W, <8 x double> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp = tail call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> %__W, <8 x double> %shuffle1.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle3.i = shufflevector <8 x double> %tmp, <8 x double> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp1 = tail call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> %tmp, <8 x double> %shuffle3.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle6.i = shufflevector <8 x double> %tmp1, <8 x double> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = tail call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> %tmp1, <8 x double> %shuffle6.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <8 x double> %tmp2, i32 0
- // CHECK: ret double %vecext.i
return _mm512_reduce_max_pd(__W);
}
+// CHECK-LABEL: define i64 @test_mm512_reduce_min_epi64(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I8_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP1]], <8 x i64> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP3]], <8 x i64> [[TMP4]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = icmp sgt <8 x i64> [[TMP5]], [[TMP6]]
+// CHECK: [[TMP9:%.*]] = select <8 x i1> [[TMP8]], <8 x i64> [[TMP5]], <8 x i64> [[TMP6]]
+// CHECK: store <8 x i64> [[TMP9]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <8 x i64> [[TMP10]], <8 x i64> [[TMP11]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP12]], <8 x i64> [[TMP13]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE2_I]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP17:%.*]] = icmp sgt <8 x i64> [[TMP14]], [[TMP15]]
+// CHECK: [[TMP18:%.*]] = select <8 x i1> [[TMP17]], <8 x i64> [[TMP14]], <8 x i64> [[TMP15]]
+// CHECK: store <8 x i64> [[TMP18]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <8 x i64> [[TMP19]], <8 x i64> [[TMP20]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP21]], <8 x i64> [[TMP22]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE5_I]], <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP26:%.*]] = icmp sgt <8 x i64> [[TMP23]], [[TMP24]]
+// CHECK: [[TMP27:%.*]] = select <8 x i1> [[TMP26]], <8 x i64> [[TMP23]], <8 x i64> [[TMP24]]
+// CHECK: store <8 x i64> [[TMP27]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP28]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
long long test_mm512_reduce_min_epi64(__m512i __W){
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %__W, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp = icmp slt <8 x i64> %shuffle1.i, %__W
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> %shuffle1.i
- // CHECK: %shuffle3.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp sgt <8 x i64> %tmp1, %shuffle3.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp sgt <8 x i64> %tmp3, %shuffle6.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp4, i32 0
- // CHECK: %.elt20.i = extractelement <8 x i64> %tmp3, i32 0
- // CHECK: %shuffle6.elt.i = extractelement <8 x i64> %tmp3, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt20.i, i64 %shuffle6.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_reduce_max_epi64(__W);
}
+// CHECK-LABEL: define i64 @test_mm512_reduce_min_epu64(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I8_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP1]], <8 x i64> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP3]], <8 x i64> [[TMP4]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = icmp ugt <8 x i64> [[TMP5]], [[TMP6]]
+// CHECK: [[TMP9:%.*]] = select <8 x i1> [[TMP8]], <8 x i64> [[TMP5]], <8 x i64> [[TMP6]]
+// CHECK: store <8 x i64> [[TMP9]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <8 x i64> [[TMP10]], <8 x i64> [[TMP11]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP12]], <8 x i64> [[TMP13]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE2_I]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP17:%.*]] = icmp ugt <8 x i64> [[TMP14]], [[TMP15]]
+// CHECK: [[TMP18:%.*]] = select <8 x i1> [[TMP17]], <8 x i64> [[TMP14]], <8 x i64> [[TMP15]]
+// CHECK: store <8 x i64> [[TMP18]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <8 x i64> [[TMP19]], <8 x i64> [[TMP20]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP21]], <8 x i64> [[TMP22]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE5_I]], <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I9_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP26:%.*]] = icmp ugt <8 x i64> [[TMP23]], [[TMP24]]
+// CHECK: [[TMP27:%.*]] = select <8 x i1> [[TMP26]], <8 x i64> [[TMP23]], <8 x i64> [[TMP24]]
+// CHECK: store <8 x i64> [[TMP27]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP28]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
unsigned long long test_mm512_reduce_min_epu64(__m512i __W){
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %__W, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp = icmp ult <8 x i64> %shuffle1.i, %__W
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> %shuffle1.i
- // CHECK: %shuffle3.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp ugt <8 x i64> %tmp1, %shuffle3.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp ugt <8 x i64> %tmp3, %shuffle6.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp4, i32 0
- // CHECK: %.elt20.i = extractelement <8 x i64> %tmp3, i32 0
- // CHECK: %shuffle6.elt.i = extractelement <8 x i64> %tmp3, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt20.i, i64 %shuffle6.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_reduce_max_epu64(__W);
}
+// CHECK-LABEL: define double @test_mm512_reduce_min_pd(<8 x double> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I8_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I9_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I10_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x double>, align 64
+// CHECK: store <8 x double> %__W, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x double>, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: store <8 x double> [[TMP0]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x double> [[TMP1]], <8 x double> [[TMP2]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x double> [[TMP3]], <8 x double> [[TMP4]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE_I]], <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE1_I]], <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> [[TMP5]], <8 x double> [[TMP6]], <8 x double> [[TMP7]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP8]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <8 x double> [[TMP9]], <8 x double> [[TMP10]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP11:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x double> [[TMP11]], <8 x double> [[TMP12]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE2_I]], <8 x double>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE3_I]], <8 x double>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP16:%.*]] = call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> [[TMP13]], <8 x double> [[TMP14]], <8 x double> [[TMP15]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP16]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP17:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <8 x double> [[TMP17]], <8 x double> [[TMP18]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP19:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x double> [[TMP19]], <8 x double> [[TMP20]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE5_I]], <8 x double>* [[__A_ADDR_I9_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE6_I]], <8 x double>* [[__B_ADDR_I10_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I9_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I10_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I8_I]], align 64
+// CHECK: [[TMP24:%.*]] = call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> [[TMP21]], <8 x double> [[TMP22]], <8 x double> [[TMP23]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP24]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x double> [[TMP25]], i32 0
+// CHECK: ret double [[VECEXT_I]]
double test_mm512_reduce_min_pd(__m512d __W){
- // CHECK: %shuffle1.i = shufflevector <8 x double> %__W, <8 x double> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp = tail call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> %__W, <8 x double> %shuffle1.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle3.i = shufflevector <8 x double> %tmp, <8 x double> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp1 = tail call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> %tmp, <8 x double> %shuffle3.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle6.i = shufflevector <8 x double> %tmp1, <8 x double> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = tail call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> %tmp1, <8 x double> %shuffle6.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <8 x double> %tmp2, i32 0
- // CHECK: ret double %vecext.i
return _mm512_reduce_min_pd(__W);
}
+// CHECK-LABEL: define i64 @test_mm512_mask_reduce_max_epi64(i8 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__D_ADDR_I_I:%.*]] = alloca i64, align 8
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i8, align 1
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i8, align 1
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i8 %__M, i8* [[__M_ADDR]], align 1
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i8, i8* [[__M_ADDR]], align 1
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i8 [[TMP0]], i8* [[__M_ADDR_I]], align 1
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i8, i8* [[__M_ADDR_I]], align 1
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: store i64 -9223372036854775808, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[TMP4:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <8 x i64> undef, i64 [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <8 x i64> [[VECINIT_I_I]], i64 [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <8 x i64> [[VECINIT1_I_I]], i64 [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <8 x i64> [[VECINIT2_I_I]], i64 [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <8 x i64> [[VECINIT3_I_I]], i64 [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <8 x i64> [[VECINIT4_I_I]], i64 [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <8 x i64> [[VECINIT5_I_I]], i64 [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <8 x i64> [[VECINIT6_I_I]], i64 [[TMP11]], i32 7
+// CHECK: store <8 x i64> [[VECINIT7_I_I]], <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP13:%.*]] = bitcast i8 [[TMP2]] to <8 x i1>
+// CHECK: [[TMP14:%.*]] = select <8 x i1> [[TMP13]], <8 x i64> [[TMP3]], <8 x i64> [[TMP12]]
+// CHECK: store <8 x i64> [[TMP14]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP15]], <8 x i64> [[TMP16]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP17:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP17]], <8 x i64> [[TMP18]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP22:%.*]] = icmp sgt <8 x i64> [[TMP19]], [[TMP20]]
+// CHECK: [[TMP23:%.*]] = select <8 x i1> [[TMP22]], <8 x i64> [[TMP19]], <8 x i64> [[TMP20]]
+// CHECK: store <8 x i64> [[TMP23]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP24]], <8 x i64> [[TMP25]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <8 x i64> [[TMP26]], <8 x i64> [[TMP27]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE4_I]], <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP31:%.*]] = icmp sgt <8 x i64> [[TMP28]], [[TMP29]]
+// CHECK: [[TMP32:%.*]] = select <8 x i1> [[TMP31]], <8 x i64> [[TMP28]], <8 x i64> [[TMP29]]
+// CHECK: store <8 x i64> [[TMP32]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP33]], <8 x i64> [[TMP34]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP35:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <8 x i64> [[TMP35]], <8 x i64> [[TMP36]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE7_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP40:%.*]] = icmp sgt <8 x i64> [[TMP37]], [[TMP38]]
+// CHECK: [[TMP41:%.*]] = select <8 x i1> [[TMP40]], <8 x i64> [[TMP37]], <8 x i64> [[TMP38]]
+// CHECK: store <8 x i64> [[TMP41]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP42]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
long long test_mm512_mask_reduce_max_epi64(__mmask8 __M, __m512i __W){
- // CHECK: %tmp = bitcast i8 %__M to <8 x i1>
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> <i64 -9223372036854775808, i64 -9223372036854775808, i64 -9223372036854775808, i64 -9223372036854775808, i64 -9223372036854775808, i64 -9223372036854775808, i64 -9223372036854775808, i64 -9223372036854775808>
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp sgt <8 x i64> %tmp1, %shuffle1.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp sgt <8 x i64> %tmp3, %shuffle4.i
- // CHECK: %tmp5 = select <8 x i1> %tmp4, <8 x i64> %tmp3, <8 x i64> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <8 x i64> %tmp5, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp6 = icmp sgt <8 x i64> %tmp5, %shuffle7.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp6, i32 0
- // CHECK: %.elt22.i = extractelement <8 x i64> %tmp5, i32 0
- // CHECK: %shuffle7.elt.i = extractelement <8 x i64> %tmp5, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt22.i, i64 %shuffle7.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_mask_reduce_max_epi64(__M, __W);
}
+// CHECK-LABEL: define i64 @test_mm512_mask_reduce_max_epu64(i8 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__D_ADDR_I_I:%.*]] = alloca i64, align 8
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i8, align 1
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i8, align 1
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i8 %__M, i8* [[__M_ADDR]], align 1
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i8, i8* [[__M_ADDR]], align 1
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i8 [[TMP0]], i8* [[__M_ADDR_I]], align 1
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i8, i8* [[__M_ADDR_I]], align 1
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: store i64 0, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[TMP4:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <8 x i64> undef, i64 [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <8 x i64> [[VECINIT_I_I]], i64 [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <8 x i64> [[VECINIT1_I_I]], i64 [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <8 x i64> [[VECINIT2_I_I]], i64 [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <8 x i64> [[VECINIT3_I_I]], i64 [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <8 x i64> [[VECINIT4_I_I]], i64 [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <8 x i64> [[VECINIT5_I_I]], i64 [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <8 x i64> [[VECINIT6_I_I]], i64 [[TMP11]], i32 7
+// CHECK: store <8 x i64> [[VECINIT7_I_I]], <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP13:%.*]] = bitcast i8 [[TMP2]] to <8 x i1>
+// CHECK: [[TMP14:%.*]] = select <8 x i1> [[TMP13]], <8 x i64> [[TMP3]], <8 x i64> [[TMP12]]
+// CHECK: store <8 x i64> [[TMP14]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP15]], <8 x i64> [[TMP16]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP17:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP17]], <8 x i64> [[TMP18]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP22:%.*]] = icmp ugt <8 x i64> [[TMP19]], [[TMP20]]
+// CHECK: [[TMP23:%.*]] = select <8 x i1> [[TMP22]], <8 x i64> [[TMP19]], <8 x i64> [[TMP20]]
+// CHECK: store <8 x i64> [[TMP23]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP24]], <8 x i64> [[TMP25]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <8 x i64> [[TMP26]], <8 x i64> [[TMP27]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE4_I]], <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP31:%.*]] = icmp ugt <8 x i64> [[TMP28]], [[TMP29]]
+// CHECK: [[TMP32:%.*]] = select <8 x i1> [[TMP31]], <8 x i64> [[TMP28]], <8 x i64> [[TMP29]]
+// CHECK: store <8 x i64> [[TMP32]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP33]], <8 x i64> [[TMP34]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP35:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <8 x i64> [[TMP35]], <8 x i64> [[TMP36]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE7_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP40:%.*]] = icmp ugt <8 x i64> [[TMP37]], [[TMP38]]
+// CHECK: [[TMP41:%.*]] = select <8 x i1> [[TMP40]], <8 x i64> [[TMP37]], <8 x i64> [[TMP38]]
+// CHECK: store <8 x i64> [[TMP41]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP42]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
unsigned long test_mm512_mask_reduce_max_epu64(__mmask8 __M, __m512i __W){
- // CHECK: %tmp = bitcast i8 %__M to <8 x i1>
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> zeroinitializer
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp ugt <8 x i64> %tmp1, %shuffle1.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp ugt <8 x i64> %tmp3, %shuffle4.i
- // CHECK: %tmp5 = select <8 x i1> %tmp4, <8 x i64> %tmp3, <8 x i64> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <8 x i64> %tmp5, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp6 = icmp ugt <8 x i64> %tmp5, %shuffle7.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp6, i32 0
- // CHECK: %.elt22.i = extractelement <8 x i64> %tmp5, i32 0
- // CHECK: %shuffle7.elt.i = extractelement <8 x i64> %tmp5, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt22.i, i64 %shuffle7.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_mask_reduce_max_epu64(__M, __W);
}
+// CHECK-LABEL: define i64 @test_mm512_mask_reduce_max_pd(i8 zeroext %__M, <8 x double> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I9_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I10_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I11_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__W_ADDR_I_I:%.*]] = alloca double, align 8
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i8, align 1
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i8, align 1
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x double>, align 64
+// CHECK: store i8 %__M, i8* [[__M_ADDR]], align 1
+// CHECK: store <8 x double> %__W, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i8, i8* [[__M_ADDR]], align 1
+// CHECK: [[TMP1:%.*]] = load <8 x double>, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: store i8 [[TMP0]], i8* [[__M_ADDR_I]], align 1
+// CHECK: store <8 x double> [[TMP1]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i8, i8* [[__M_ADDR_I]], align 1
+// CHECK: [[TMP3:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: store double 0x7FF0000000000000, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[TMP4:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <8 x double> undef, double [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <8 x double> [[VECINIT_I_I]], double [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <8 x double> [[VECINIT1_I_I]], double [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <8 x double> [[VECINIT2_I_I]], double [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <8 x double> [[VECINIT3_I_I]], double [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <8 x double> [[VECINIT4_I_I]], double [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <8 x double> [[VECINIT5_I_I]], double [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <8 x double> [[VECINIT6_I_I]], double [[TMP11]], i32 7
+// CHECK: store <8 x double> [[VECINIT7_I_I]], <8 x double>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[SUB_I:%.*]] = fsub <8 x double> <double -0.000000e+00, double -0.000000e+00, double -0.000000e+00, double -0.000000e+00, double -0.000000e+00, double -0.000000e+00, double -0.000000e+00, double -0.000000e+00>, [[TMP12]]
+// CHECK: [[TMP13:%.*]] = bitcast i8 [[TMP2]] to <8 x i1>
+// CHECK: [[TMP14:%.*]] = select <8 x i1> [[TMP13]], <8 x double> [[TMP3]], <8 x double> [[SUB_I]]
+// CHECK: store <8 x double> [[TMP14]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x double> [[TMP15]], <8 x double> [[TMP16]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP17:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x double> [[TMP17]], <8 x double> [[TMP18]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE_I]], <8 x double>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE1_I]], <8 x double>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP22:%.*]] = call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> [[TMP19]], <8 x double> [[TMP20]], <8 x double> [[TMP21]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP22]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x double> [[TMP23]], <8 x double> [[TMP24]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP25:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <8 x double> [[TMP25]], <8 x double> [[TMP26]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE3_I]], <8 x double>* [[__A_ADDR_I10_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE4_I]], <8 x double>* [[__B_ADDR_I11_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I10_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I11_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP30:%.*]] = call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> [[TMP27]], <8 x double> [[TMP28]], <8 x double> [[TMP29]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP30]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP31:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x double> [[TMP31]], <8 x double> [[TMP32]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP33:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <8 x double> [[TMP33]], <8 x double> [[TMP34]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE6_I]], <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE7_I]], <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP35:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP38:%.*]] = call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> [[TMP35]], <8 x double> [[TMP36]], <8 x double> [[TMP37]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP38]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x double> [[TMP39]], i32 0
+// CHECK: [[CONV:%.*]] = fptosi double [[VECEXT_I]] to i64
+// CHECK: ret i64 [[CONV]]
long long test_mm512_mask_reduce_max_pd(__mmask8 __M, __m512d __W){
- // CHECK: %tmp = bitcast i8 %__M to <8 x i1>
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x double> %__W, <8 x double> <double 0xFFF0000000000000, double 0xFFF0000000000000, double 0xFFF0000000000000, double 0xFFF0000000000000, double 0xFFF0000000000000, double 0xFFF0000000000000, double 0xFFF0000000000000, double 0xFFF0000000000000>
- // CHECK: %shuffle1.i = shufflevector <8 x double> %tmp1, <8 x double> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = tail call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> %tmp1, <8 x double> %shuffle1.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle4.i = shufflevector <8 x double> %tmp2, <8 x double> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp3 = tail call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> %tmp2, <8 x double> %shuffle4.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle7.i = shufflevector <8 x double> %tmp3, <8 x double> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = tail call <8 x double> @llvm.x86.avx512.mask.max.pd.512(<8 x double> %tmp3, <8 x double> %shuffle7.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <8 x double> %tmp4, i32 0
- // CHECK: %conv = fptosi double %vecext.i to i64
- // CHECK: ret i64 %conv
return _mm512_mask_reduce_max_pd(__M, __W);
}
+// CHECK-LABEL: define i64 @test_mm512_mask_reduce_min_epi64(i8 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__D_ADDR_I_I:%.*]] = alloca i64, align 8
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i8, align 1
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i8, align 1
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i8 %__M, i8* [[__M_ADDR]], align 1
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i8, i8* [[__M_ADDR]], align 1
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i8 [[TMP0]], i8* [[__M_ADDR_I]], align 1
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i8, i8* [[__M_ADDR_I]], align 1
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: store i64 9223372036854775807, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[TMP4:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <8 x i64> undef, i64 [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <8 x i64> [[VECINIT_I_I]], i64 [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <8 x i64> [[VECINIT1_I_I]], i64 [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <8 x i64> [[VECINIT2_I_I]], i64 [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <8 x i64> [[VECINIT3_I_I]], i64 [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <8 x i64> [[VECINIT4_I_I]], i64 [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <8 x i64> [[VECINIT5_I_I]], i64 [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <8 x i64> [[VECINIT6_I_I]], i64 [[TMP11]], i32 7
+// CHECK: store <8 x i64> [[VECINIT7_I_I]], <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP13:%.*]] = bitcast i8 [[TMP2]] to <8 x i1>
+// CHECK: [[TMP14:%.*]] = select <8 x i1> [[TMP13]], <8 x i64> [[TMP3]], <8 x i64> [[TMP12]]
+// CHECK: store <8 x i64> [[TMP14]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP15]], <8 x i64> [[TMP16]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP17:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP17]], <8 x i64> [[TMP18]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP22:%.*]] = icmp slt <8 x i64> [[TMP19]], [[TMP20]]
+// CHECK: [[TMP23:%.*]] = select <8 x i1> [[TMP22]], <8 x i64> [[TMP19]], <8 x i64> [[TMP20]]
+// CHECK: store <8 x i64> [[TMP23]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP24]], <8 x i64> [[TMP25]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <8 x i64> [[TMP26]], <8 x i64> [[TMP27]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE4_I]], <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP31:%.*]] = icmp slt <8 x i64> [[TMP28]], [[TMP29]]
+// CHECK: [[TMP32:%.*]] = select <8 x i1> [[TMP31]], <8 x i64> [[TMP28]], <8 x i64> [[TMP29]]
+// CHECK: store <8 x i64> [[TMP32]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP33]], <8 x i64> [[TMP34]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP35:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <8 x i64> [[TMP35]], <8 x i64> [[TMP36]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE7_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP40:%.*]] = icmp slt <8 x i64> [[TMP37]], [[TMP38]]
+// CHECK: [[TMP41:%.*]] = select <8 x i1> [[TMP40]], <8 x i64> [[TMP37]], <8 x i64> [[TMP38]]
+// CHECK: store <8 x i64> [[TMP41]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP42]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
long long test_mm512_mask_reduce_min_epi64(__mmask8 __M, __m512i __W){
- // CHECK: %tmp = bitcast i8 %__M to <8 x i1>
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> <i64 9223372036854775807, i64 9223372036854775807, i64 9223372036854775807, i64 9223372036854775807, i64 9223372036854775807, i64 9223372036854775807, i64 9223372036854775807, i64 9223372036854775807>
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp slt <8 x i64> %tmp1, %shuffle1.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp slt <8 x i64> %tmp3, %shuffle4.i
- // CHECK: %tmp5 = select <8 x i1> %tmp4, <8 x i64> %tmp3, <8 x i64> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <8 x i64> %tmp5, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp6 = icmp slt <8 x i64> %tmp5, %shuffle7.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp6, i32 0
- // CHECK: %.elt22.i = extractelement <8 x i64> %tmp5, i32 0
- // CHECK: %shuffle7.elt.i = extractelement <8 x i64> %tmp5, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt22.i, i64 %shuffle7.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_mask_reduce_min_epi64(__M, __W);
}
+// CHECK-LABEL: define i64 @test_mm512_mask_reduce_min_epu64(i8 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I9_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I10_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__D_ADDR_I_I:%.*]] = alloca i64, align 8
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i8, align 1
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i8, align 1
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i8 %__M, i8* [[__M_ADDR]], align 1
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i8, i8* [[__M_ADDR]], align 1
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i8 [[TMP0]], i8* [[__M_ADDR_I]], align 1
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i8, i8* [[__M_ADDR_I]], align 1
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: store i64 0, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[TMP4:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <8 x i64> undef, i64 [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <8 x i64> [[VECINIT_I_I]], i64 [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <8 x i64> [[VECINIT1_I_I]], i64 [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <8 x i64> [[VECINIT2_I_I]], i64 [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <8 x i64> [[VECINIT3_I_I]], i64 [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <8 x i64> [[VECINIT4_I_I]], i64 [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <8 x i64> [[VECINIT5_I_I]], i64 [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load i64, i64* [[__D_ADDR_I_I]], align 8
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <8 x i64> [[VECINIT6_I_I]], i64 [[TMP11]], i32 7
+// CHECK: store <8 x i64> [[VECINIT7_I_I]], <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP13:%.*]] = bitcast i8 [[TMP2]] to <8 x i1>
+// CHECK: [[TMP14:%.*]] = select <8 x i1> [[TMP13]], <8 x i64> [[TMP3]], <8 x i64> [[TMP12]]
+// CHECK: store <8 x i64> [[TMP14]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x i64> [[TMP15]], <8 x i64> [[TMP16]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP17:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x i64> [[TMP17]], <8 x i64> [[TMP18]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE_I]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE1_I]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP22:%.*]] = icmp ugt <8 x i64> [[TMP19]], [[TMP20]]
+// CHECK: [[TMP23:%.*]] = select <8 x i1> [[TMP22]], <8 x i64> [[TMP19]], <8 x i64> [[TMP20]]
+// CHECK: store <8 x i64> [[TMP23]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x i64> [[TMP24]], <8 x i64> [[TMP25]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <8 x i64> [[TMP26]], <8 x i64> [[TMP27]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE3_I]], <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE4_I]], <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I10_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I11_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP31:%.*]] = icmp ugt <8 x i64> [[TMP28]], [[TMP29]]
+// CHECK: [[TMP32:%.*]] = select <8 x i1> [[TMP31]], <8 x i64> [[TMP28]], <8 x i64> [[TMP29]]
+// CHECK: store <8 x i64> [[TMP32]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x i64> [[TMP33]], <8 x i64> [[TMP34]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP35:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <8 x i64> [[TMP35]], <8 x i64> [[TMP36]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x i64> [[SHUFFLE6_I]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[SHUFFLE7_I]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP40:%.*]] = icmp ugt <8 x i64> [[TMP37]], [[TMP38]]
+// CHECK: [[TMP41:%.*]] = select <8 x i1> [[TMP40]], <8 x i64> [[TMP37]], <8 x i64> [[TMP38]]
+// CHECK: store <8 x i64> [[TMP41]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP42]], i32 0
+// CHECK: ret i64 [[VECEXT_I]]
long long test_mm512_mask_reduce_min_epu64(__mmask8 __M, __m512i __W){
- // CHECK: %tmp = bitcast i8 %__M to <8 x i1>
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x i64> %__W, <8 x i64> zeroinitializer
- // CHECK: %shuffle1.i = shufflevector <8 x i64> %tmp1, <8 x i64> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = icmp ugt <8 x i64> %tmp1, %shuffle1.i
- // CHECK: %tmp3 = select <8 x i1> %tmp2, <8 x i64> %tmp1, <8 x i64> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <8 x i64> %tmp3, <8 x i64> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = icmp ugt <8 x i64> %tmp3, %shuffle4.i
- // CHECK: %tmp5 = select <8 x i1> %tmp4, <8 x i64> %tmp3, <8 x i64> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <8 x i64> %tmp5, <8 x i64> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp6 = icmp ugt <8 x i64> %tmp5, %shuffle7.i
- // CHECK: %.elt.i = extractelement <8 x i1> %tmp6, i32 0
- // CHECK: %.elt22.i = extractelement <8 x i64> %tmp5, i32 0
- // CHECK: %shuffle7.elt.i = extractelement <8 x i64> %tmp5, i32 1
- // CHECK: %vecext.i = select i1 %.elt.i, i64 %.elt22.i, i64 %shuffle7.elt.i
- // CHECK: ret i64 %vecext.i
return _mm512_mask_reduce_max_epu64(__M, __W);
}
+// CHECK-LABEL: define double @test_mm512_mask_reduce_min_pd(i8 zeroext %__M, <8 x double> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I9_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I10_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I11_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__W_ADDR_I_I:%.*]] = alloca double, align 8
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i8, align 1
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x double>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i8, align 1
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x double>, align 64
+// CHECK: store i8 %__M, i8* [[__M_ADDR]], align 1
+// CHECK: store <8 x double> %__W, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i8, i8* [[__M_ADDR]], align 1
+// CHECK: [[TMP1:%.*]] = load <8 x double>, <8 x double>* [[__W_ADDR]], align 64
+// CHECK: store i8 [[TMP0]], i8* [[__M_ADDR_I]], align 1
+// CHECK: store <8 x double> [[TMP1]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i8, i8* [[__M_ADDR_I]], align 1
+// CHECK: [[TMP3:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: store double 0x7FF0000000000000, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[TMP4:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <8 x double> undef, double [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <8 x double> [[VECINIT_I_I]], double [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <8 x double> [[VECINIT1_I_I]], double [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <8 x double> [[VECINIT2_I_I]], double [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <8 x double> [[VECINIT3_I_I]], double [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <8 x double> [[VECINIT4_I_I]], double [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <8 x double> [[VECINIT5_I_I]], double [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load double, double* [[__W_ADDR_I_I]], align 8
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <8 x double> [[VECINIT6_I_I]], double [[TMP11]], i32 7
+// CHECK: store <8 x double> [[VECINIT7_I_I]], <8 x double>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP13:%.*]] = bitcast i8 [[TMP2]] to <8 x i1>
+// CHECK: [[TMP14:%.*]] = select <8 x i1> [[TMP13]], <8 x double> [[TMP3]], <8 x double> [[TMP12]]
+// CHECK: store <8 x double> [[TMP14]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP16:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x double> [[TMP15]], <8 x double> [[TMP16]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP17:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <8 x double> [[TMP17]], <8 x double> [[TMP18]], <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE_I]], <8 x double>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE1_I]], <8 x double>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP19:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP22:%.*]] = call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> [[TMP19]], <8 x double> [[TMP20]], <8 x double> [[TMP21]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP22]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <8 x double> [[TMP23]], <8 x double> [[TMP24]], <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP25:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <8 x double> [[TMP25]], <8 x double> [[TMP26]], <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE3_I]], <8 x double>* [[__A_ADDR_I10_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE4_I]], <8 x double>* [[__B_ADDR_I11_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I10_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I11_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I9_I]], align 64
+// CHECK: [[TMP30:%.*]] = call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> [[TMP27]], <8 x double> [[TMP28]], <8 x double> [[TMP29]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP30]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP31:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <8 x double> [[TMP31]], <8 x double> [[TMP32]], <8 x i32> <i32 0, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP33:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <8 x double> [[TMP33]], <8 x double> [[TMP34]], <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: store <8 x double> [[SHUFFLE6_I]], <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x double> [[SHUFFLE7_I]], <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP35:%.*]] = load <8 x double>, <8 x double>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x double>, <8 x double>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <8 x double> zeroinitializer, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <8 x double>, <8 x double>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP38:%.*]] = call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> [[TMP35]], <8 x double> [[TMP36]], <8 x double> [[TMP37]], i8 -1, i32 4) #2
+// CHECK: store <8 x double> [[TMP38]], <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x double>, <8 x double>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x double> [[TMP39]], i32 0
+// CHECK: ret double [[VECEXT_I]]
double test_mm512_mask_reduce_min_pd(__mmask8 __M, __m512d __W){
- // CHECK: %tmp = bitcast i8 %__M to <8 x i1>
- // CHECK: %tmp1 = select <8 x i1> %tmp, <8 x double> %__W, <8 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000, double 0x7FF0000000000000, double 0x7FF0000000000000, double 0x7FF0000000000000, double 0x7FF0000000000000, double 0x7FF0000000000000, double 0x7FF0000000000000>
- // CHECK: %shuffle1.i = shufflevector <8 x double> %tmp1, <8 x double> undef, <8 x i32> <i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp2 = tail call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> %tmp1, <8 x double> %shuffle1.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle4.i = shufflevector <8 x double> %tmp2, <8 x double> undef, <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp3 = tail call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> %tmp2, <8 x double> %shuffle4.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %shuffle7.i = shufflevector <8 x double> %tmp3, <8 x double> undef, <8 x i32> <i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // CHECK: %tmp4 = tail call <8 x double> @llvm.x86.avx512.mask.min.pd.512(<8 x double> %tmp3, <8 x double> %shuffle7.i, <8 x double> zeroinitializer, i8 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <8 x double> %tmp4, i32 0
- // CHECK: ret double %vecext.i
return _mm512_mask_reduce_min_pd(__M, __W);
}
+// CHECK-LABEL: define i32 @test_mm512_reduce_max_epi32(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[A_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i64> [[TMP1]] to <16 x i32>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP2]], <16 x i32> [[TMP4]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP7:%.*]] = bitcast <8 x i64> [[TMP6]] to <16 x i32>
+// CHECK: [[TMP8:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i64> [[TMP8]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP7]], <16 x i32> [[TMP9]], <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: [[TMP10:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP5]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP10]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i64> [[TMP11]] to <16 x i32>
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i64> [[TMP13]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP16:%.*]] = bitcast <8 x i64> [[TMP15]] to <16 x i32>
+// CHECK: [[TMP17:%.*]] = icmp sgt <16 x i32> [[TMP12]], [[TMP14]]
+// CHECK: [[TMP18:%.*]] = select <16 x i1> [[TMP17]], <16 x i32> [[TMP12]], <16 x i32> [[TMP14]]
+// CHECK: [[TMP19:%.*]] = bitcast <16 x i32> [[TMP18]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP19]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP21:%.*]] = bitcast <8 x i64> [[TMP20]] to <16 x i32>
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = bitcast <8 x i64> [[TMP22]] to <16 x i32>
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <16 x i32> [[TMP21]], <16 x i32> [[TMP23]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP24:%.*]] = bitcast <16 x i32> [[SHUFFLE2_I]] to <8 x i64>
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = bitcast <8 x i64> [[TMP25]] to <16 x i32>
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = bitcast <8 x i64> [[TMP27]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP26]], <16 x i32> [[TMP28]], <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: [[TMP29:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP24]], <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: store <8 x i64> [[TMP29]], <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: [[TMP31:%.*]] = bitcast <8 x i64> [[TMP30]] to <16 x i32>
+// CHECK: [[TMP32:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP33:%.*]] = bitcast <8 x i64> [[TMP32]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP35:%.*]] = bitcast <8 x i64> [[TMP34]] to <16 x i32>
+// CHECK: [[TMP36:%.*]] = icmp sgt <16 x i32> [[TMP31]], [[TMP33]]
+// CHECK: [[TMP37:%.*]] = select <16 x i1> [[TMP36]], <16 x i32> [[TMP31]], <16 x i32> [[TMP33]]
+// CHECK: [[TMP38:%.*]] = bitcast <16 x i32> [[TMP37]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP38]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP40:%.*]] = bitcast <8 x i64> [[TMP39]] to <16 x i32>
+// CHECK: [[TMP41:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = bitcast <8 x i64> [[TMP41]] to <16 x i32>
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <16 x i32> [[TMP40]], <16 x i32> [[TMP42]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP43:%.*]] = bitcast <16 x i32> [[SHUFFLE5_I]] to <8 x i64>
+// CHECK: [[TMP44:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = bitcast <8 x i64> [[TMP44]] to <16 x i32>
+// CHECK: [[TMP46:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP47:%.*]] = bitcast <8 x i64> [[TMP46]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP45]], <16 x i32> [[TMP47]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP48:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP43]], <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: store <8 x i64> [[TMP48]], <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP49:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: [[TMP50:%.*]] = bitcast <8 x i64> [[TMP49]] to <16 x i32>
+// CHECK: [[TMP51:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP52:%.*]] = bitcast <8 x i64> [[TMP51]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP53:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP54:%.*]] = bitcast <8 x i64> [[TMP53]] to <16 x i32>
+// CHECK: [[TMP55:%.*]] = icmp sgt <16 x i32> [[TMP50]], [[TMP52]]
+// CHECK: [[TMP56:%.*]] = select <16 x i1> [[TMP55]], <16 x i32> [[TMP50]], <16 x i32> [[TMP52]]
+// CHECK: [[TMP57:%.*]] = bitcast <16 x i32> [[TMP56]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP57]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP58:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP59:%.*]] = bitcast <8 x i64> [[TMP58]] to <16 x i32>
+// CHECK: [[TMP60:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP61:%.*]] = bitcast <8 x i64> [[TMP60]] to <16 x i32>
+// CHECK: [[SHUFFLE8_I:%.*]] = shufflevector <16 x i32> [[TMP59]], <16 x i32> [[TMP61]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP62:%.*]] = bitcast <16 x i32> [[SHUFFLE8_I]] to <8 x i64>
+// CHECK: [[TMP63:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = bitcast <8 x i64> [[TMP63]] to <16 x i32>
+// CHECK: [[TMP65:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP66:%.*]] = bitcast <8 x i64> [[TMP65]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP64]], <16 x i32> [[TMP66]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP67:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP62]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[TMP67]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP68:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP69:%.*]] = bitcast <8 x i64> [[TMP68]] to <16 x i32>
+// CHECK: [[TMP70:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP71:%.*]] = bitcast <8 x i64> [[TMP70]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP72:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP73:%.*]] = bitcast <8 x i64> [[TMP72]] to <16 x i32>
+// CHECK: [[TMP74:%.*]] = icmp sgt <16 x i32> [[TMP69]], [[TMP71]]
+// CHECK: [[TMP75:%.*]] = select <16 x i1> [[TMP74]], <16 x i32> [[TMP69]], <16 x i32> [[TMP71]]
+// CHECK: [[TMP76:%.*]] = bitcast <16 x i32> [[TMP75]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP76]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP77:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP77]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
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 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
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <16 x i32> %tmp4, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp5 = icmp sgt <16 x i32> %tmp4, %shuffle6.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle6.i
- // CHECK: %shuffle9.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp7 = icmp sgt <16 x i32> %tmp6, %shuffle9.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle9.i
- // CHECK: %tmp9 = bitcast <16 x i32> %tmp8 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp9, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_reduce_max_epi32(__W);
}
+// CHECK-LABEL: define i32 @test_mm512_reduce_max_epu32(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[A_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i64> [[TMP1]] to <16 x i32>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP2]], <16 x i32> [[TMP4]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP7:%.*]] = bitcast <8 x i64> [[TMP6]] to <16 x i32>
+// CHECK: [[TMP8:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i64> [[TMP8]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP7]], <16 x i32> [[TMP9]], <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: [[TMP10:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP5]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP10]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i64> [[TMP11]] to <16 x i32>
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i64> [[TMP13]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP16:%.*]] = bitcast <8 x i64> [[TMP15]] to <16 x i32>
+// CHECK: [[TMP17:%.*]] = icmp ugt <16 x i32> [[TMP12]], [[TMP14]]
+// CHECK: [[TMP18:%.*]] = select <16 x i1> [[TMP17]], <16 x i32> [[TMP12]], <16 x i32> [[TMP14]]
+// CHECK: [[TMP19:%.*]] = bitcast <16 x i32> [[TMP18]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP19]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP21:%.*]] = bitcast <8 x i64> [[TMP20]] to <16 x i32>
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = bitcast <8 x i64> [[TMP22]] to <16 x i32>
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <16 x i32> [[TMP21]], <16 x i32> [[TMP23]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP24:%.*]] = bitcast <16 x i32> [[SHUFFLE2_I]] to <8 x i64>
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = bitcast <8 x i64> [[TMP25]] to <16 x i32>
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = bitcast <8 x i64> [[TMP27]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP26]], <16 x i32> [[TMP28]], <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: [[TMP29:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP24]], <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: store <8 x i64> [[TMP29]], <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: [[TMP31:%.*]] = bitcast <8 x i64> [[TMP30]] to <16 x i32>
+// CHECK: [[TMP32:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP33:%.*]] = bitcast <8 x i64> [[TMP32]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP35:%.*]] = bitcast <8 x i64> [[TMP34]] to <16 x i32>
+// CHECK: [[TMP36:%.*]] = icmp ugt <16 x i32> [[TMP31]], [[TMP33]]
+// CHECK: [[TMP37:%.*]] = select <16 x i1> [[TMP36]], <16 x i32> [[TMP31]], <16 x i32> [[TMP33]]
+// CHECK: [[TMP38:%.*]] = bitcast <16 x i32> [[TMP37]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP38]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP40:%.*]] = bitcast <8 x i64> [[TMP39]] to <16 x i32>
+// CHECK: [[TMP41:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = bitcast <8 x i64> [[TMP41]] to <16 x i32>
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <16 x i32> [[TMP40]], <16 x i32> [[TMP42]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP43:%.*]] = bitcast <16 x i32> [[SHUFFLE5_I]] to <8 x i64>
+// CHECK: [[TMP44:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = bitcast <8 x i64> [[TMP44]] to <16 x i32>
+// CHECK: [[TMP46:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP47:%.*]] = bitcast <8 x i64> [[TMP46]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP45]], <16 x i32> [[TMP47]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP48:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP43]], <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: store <8 x i64> [[TMP48]], <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP49:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: [[TMP50:%.*]] = bitcast <8 x i64> [[TMP49]] to <16 x i32>
+// CHECK: [[TMP51:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP52:%.*]] = bitcast <8 x i64> [[TMP51]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP53:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP54:%.*]] = bitcast <8 x i64> [[TMP53]] to <16 x i32>
+// CHECK: [[TMP55:%.*]] = icmp ugt <16 x i32> [[TMP50]], [[TMP52]]
+// CHECK: [[TMP56:%.*]] = select <16 x i1> [[TMP55]], <16 x i32> [[TMP50]], <16 x i32> [[TMP52]]
+// CHECK: [[TMP57:%.*]] = bitcast <16 x i32> [[TMP56]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP57]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP58:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP59:%.*]] = bitcast <8 x i64> [[TMP58]] to <16 x i32>
+// CHECK: [[TMP60:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP61:%.*]] = bitcast <8 x i64> [[TMP60]] to <16 x i32>
+// CHECK: [[SHUFFLE8_I:%.*]] = shufflevector <16 x i32> [[TMP59]], <16 x i32> [[TMP61]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP62:%.*]] = bitcast <16 x i32> [[SHUFFLE8_I]] to <8 x i64>
+// CHECK: [[TMP63:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = bitcast <8 x i64> [[TMP63]] to <16 x i32>
+// CHECK: [[TMP65:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP66:%.*]] = bitcast <8 x i64> [[TMP65]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP64]], <16 x i32> [[TMP66]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP67:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP62]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[TMP67]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP68:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP69:%.*]] = bitcast <8 x i64> [[TMP68]] to <16 x i32>
+// CHECK: [[TMP70:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP71:%.*]] = bitcast <8 x i64> [[TMP70]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP72:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP73:%.*]] = bitcast <8 x i64> [[TMP72]] to <16 x i32>
+// CHECK: [[TMP74:%.*]] = icmp ugt <16 x i32> [[TMP69]], [[TMP71]]
+// CHECK: [[TMP75:%.*]] = select <16 x i1> [[TMP74]], <16 x i32> [[TMP69]], <16 x i32> [[TMP71]]
+// CHECK: [[TMP76:%.*]] = bitcast <16 x i32> [[TMP75]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP76]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP77:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP77]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
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 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
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <16 x i32> %tmp4, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp5 = icmp ugt <16 x i32> %tmp4, %shuffle6.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle6.i
- // CHECK: %shuffle9.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp7 = icmp ugt <16 x i32> %tmp6, %shuffle9.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle9.i
- // CHECK: %tmp9 = bitcast <16 x i32> %tmp8 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp9, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_reduce_max_epu32(__W);
}
+// CHECK-LABEL: define float @test_mm512_reduce_max_ps(<16 x float> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I17_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I18_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I19_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I14_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I15_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I16_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[A_ADDR_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <16 x float>, align 64
+// CHECK: store <16 x float> %__W, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <16 x float>, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: store <16 x float> [[TMP0]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x float> [[TMP1]], <16 x float> [[TMP2]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x float> [[TMP3]], <16 x float> [[TMP4]], <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: store <16 x float> [[SHUFFLE_I]], <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE1_I]], <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP5]], <16 x float> [[TMP6]], <16 x float> [[TMP7]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP8]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <16 x float> [[TMP9]], <16 x float> [[TMP10]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP11:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x float> [[TMP11]], <16 x float> [[TMP12]], <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: store <16 x float> [[SHUFFLE2_I]], <16 x float>* [[__A_ADDR_I18_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE3_I]], <16 x float>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I18_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I19_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP16:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP13]], <16 x float> [[TMP14]], <16 x float> [[TMP15]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP16]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP17:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <16 x float> [[TMP17]], <16 x float> [[TMP18]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP19:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x float> [[TMP19]], <16 x float> [[TMP20]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE5_I]], <16 x float>* [[__A_ADDR_I15_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE6_I]], <16 x float>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I15_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I16_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP24:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP21]], <16 x float> [[TMP22]], <16 x float> [[TMP23]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP24]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE8_I:%.*]] = shufflevector <16 x float> [[TMP25]], <16 x float> [[TMP26]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP27:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x float> [[TMP27]], <16 x float> [[TMP28]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE8_I]], <16 x float>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE9_I]], <16 x float>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP31:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP32:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP29]], <16 x float> [[TMP30]], <16 x float> [[TMP31]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP32]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP33:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <16 x float> [[TMP33]], i32 0
+// CHECK: ret float [[VECEXT_I]]
float test_mm512_reduce_max_ps(__m512 __W){
- // CHECK: %shuffle1.i = shufflevector <16 x float> %__W, <16 x float> 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: %tmp = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %__W, <16 x float> %shuffle1.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle3.i = shufflevector <16 x float> %tmp, <16 x float> 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: %tmp1 = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %tmp, <16 x float> %shuffle3.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle6.i = shufflevector <16 x float> %tmp1, <16 x float> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp2 = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %tmp1, <16 x float> %shuffle6.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle9.i = shufflevector <16 x float> %tmp2, <16 x float> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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 = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %tmp2, <16 x float> %shuffle9.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <16 x float> %tmp3, i32 0
- // CHECK: ret float %vecext.i
return _mm512_reduce_max_ps(__W);
}
+// CHECK-LABEL: define i32 @test_mm512_reduce_min_epi32(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[A_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i64> [[TMP1]] to <16 x i32>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP2]], <16 x i32> [[TMP4]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP7:%.*]] = bitcast <8 x i64> [[TMP6]] to <16 x i32>
+// CHECK: [[TMP8:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i64> [[TMP8]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP7]], <16 x i32> [[TMP9]], <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: [[TMP10:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP5]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP10]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i64> [[TMP11]] to <16 x i32>
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i64> [[TMP13]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP16:%.*]] = bitcast <8 x i64> [[TMP15]] to <16 x i32>
+// CHECK: [[TMP17:%.*]] = icmp slt <16 x i32> [[TMP12]], [[TMP14]]
+// CHECK: [[TMP18:%.*]] = select <16 x i1> [[TMP17]], <16 x i32> [[TMP12]], <16 x i32> [[TMP14]]
+// CHECK: [[TMP19:%.*]] = bitcast <16 x i32> [[TMP18]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP19]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP21:%.*]] = bitcast <8 x i64> [[TMP20]] to <16 x i32>
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = bitcast <8 x i64> [[TMP22]] to <16 x i32>
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <16 x i32> [[TMP21]], <16 x i32> [[TMP23]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP24:%.*]] = bitcast <16 x i32> [[SHUFFLE2_I]] to <8 x i64>
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = bitcast <8 x i64> [[TMP25]] to <16 x i32>
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = bitcast <8 x i64> [[TMP27]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP26]], <16 x i32> [[TMP28]], <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: [[TMP29:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP24]], <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: store <8 x i64> [[TMP29]], <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: [[TMP31:%.*]] = bitcast <8 x i64> [[TMP30]] to <16 x i32>
+// CHECK: [[TMP32:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP33:%.*]] = bitcast <8 x i64> [[TMP32]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP35:%.*]] = bitcast <8 x i64> [[TMP34]] to <16 x i32>
+// CHECK: [[TMP36:%.*]] = icmp slt <16 x i32> [[TMP31]], [[TMP33]]
+// CHECK: [[TMP37:%.*]] = select <16 x i1> [[TMP36]], <16 x i32> [[TMP31]], <16 x i32> [[TMP33]]
+// CHECK: [[TMP38:%.*]] = bitcast <16 x i32> [[TMP37]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP38]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP40:%.*]] = bitcast <8 x i64> [[TMP39]] to <16 x i32>
+// CHECK: [[TMP41:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = bitcast <8 x i64> [[TMP41]] to <16 x i32>
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <16 x i32> [[TMP40]], <16 x i32> [[TMP42]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP43:%.*]] = bitcast <16 x i32> [[SHUFFLE5_I]] to <8 x i64>
+// CHECK: [[TMP44:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = bitcast <8 x i64> [[TMP44]] to <16 x i32>
+// CHECK: [[TMP46:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP47:%.*]] = bitcast <8 x i64> [[TMP46]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP45]], <16 x i32> [[TMP47]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP48:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP43]], <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: store <8 x i64> [[TMP48]], <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP49:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: [[TMP50:%.*]] = bitcast <8 x i64> [[TMP49]] to <16 x i32>
+// CHECK: [[TMP51:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP52:%.*]] = bitcast <8 x i64> [[TMP51]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP53:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP54:%.*]] = bitcast <8 x i64> [[TMP53]] to <16 x i32>
+// CHECK: [[TMP55:%.*]] = icmp slt <16 x i32> [[TMP50]], [[TMP52]]
+// CHECK: [[TMP56:%.*]] = select <16 x i1> [[TMP55]], <16 x i32> [[TMP50]], <16 x i32> [[TMP52]]
+// CHECK: [[TMP57:%.*]] = bitcast <16 x i32> [[TMP56]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP57]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP58:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP59:%.*]] = bitcast <8 x i64> [[TMP58]] to <16 x i32>
+// CHECK: [[TMP60:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP61:%.*]] = bitcast <8 x i64> [[TMP60]] to <16 x i32>
+// CHECK: [[SHUFFLE8_I:%.*]] = shufflevector <16 x i32> [[TMP59]], <16 x i32> [[TMP61]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP62:%.*]] = bitcast <16 x i32> [[SHUFFLE8_I]] to <8 x i64>
+// CHECK: [[TMP63:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = bitcast <8 x i64> [[TMP63]] to <16 x i32>
+// CHECK: [[TMP65:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP66:%.*]] = bitcast <8 x i64> [[TMP65]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP64]], <16 x i32> [[TMP66]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP67:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP62]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[TMP67]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP68:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP69:%.*]] = bitcast <8 x i64> [[TMP68]] to <16 x i32>
+// CHECK: [[TMP70:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP71:%.*]] = bitcast <8 x i64> [[TMP70]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP72:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP73:%.*]] = bitcast <8 x i64> [[TMP72]] to <16 x i32>
+// CHECK: [[TMP74:%.*]] = icmp slt <16 x i32> [[TMP69]], [[TMP71]]
+// CHECK: [[TMP75:%.*]] = select <16 x i1> [[TMP74]], <16 x i32> [[TMP69]], <16 x i32> [[TMP71]]
+// CHECK: [[TMP76:%.*]] = bitcast <16 x i32> [[TMP75]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP76]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP77:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP77]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
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 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
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <16 x i32> %tmp4, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp5 = icmp slt <16 x i32> %tmp4, %shuffle6.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle6.i
- // CHECK: %shuffle9.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp7 = icmp slt <16 x i32> %tmp6, %shuffle9.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle9.i
- // CHECK: %tmp9 = bitcast <16 x i32> %tmp8 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp9, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_reduce_min_epi32(__W);
}
+// CHECK-LABEL: define i32 @test_mm512_reduce_min_epu32(<8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[A_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store <8 x i64> [[TMP0]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i64> [[TMP1]] to <16 x i32>
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP2]], <16 x i32> [[TMP4]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP6:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP7:%.*]] = bitcast <8 x i64> [[TMP6]] to <16 x i32>
+// CHECK: [[TMP8:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i64> [[TMP8]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP7]], <16 x i32> [[TMP9]], <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: [[TMP10:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP5]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP10]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP11:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i64> [[TMP11]] to <16 x i32>
+// CHECK: [[TMP13:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i64> [[TMP13]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP16:%.*]] = bitcast <8 x i64> [[TMP15]] to <16 x i32>
+// CHECK: [[TMP17:%.*]] = icmp ult <16 x i32> [[TMP12]], [[TMP14]]
+// CHECK: [[TMP18:%.*]] = select <16 x i1> [[TMP17]], <16 x i32> [[TMP12]], <16 x i32> [[TMP14]]
+// CHECK: [[TMP19:%.*]] = bitcast <16 x i32> [[TMP18]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP19]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP21:%.*]] = bitcast <8 x i64> [[TMP20]] to <16 x i32>
+// CHECK: [[TMP22:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = bitcast <8 x i64> [[TMP22]] to <16 x i32>
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <16 x i32> [[TMP21]], <16 x i32> [[TMP23]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP24:%.*]] = bitcast <16 x i32> [[SHUFFLE2_I]] to <8 x i64>
+// CHECK: [[TMP25:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = bitcast <8 x i64> [[TMP25]] to <16 x i32>
+// CHECK: [[TMP27:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = bitcast <8 x i64> [[TMP27]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP26]], <16 x i32> [[TMP28]], <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: [[TMP29:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP24]], <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: store <8 x i64> [[TMP29]], <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I18_I]], align 64
+// CHECK: [[TMP31:%.*]] = bitcast <8 x i64> [[TMP30]] to <16 x i32>
+// CHECK: [[TMP32:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP33:%.*]] = bitcast <8 x i64> [[TMP32]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP35:%.*]] = bitcast <8 x i64> [[TMP34]] to <16 x i32>
+// CHECK: [[TMP36:%.*]] = icmp ult <16 x i32> [[TMP31]], [[TMP33]]
+// CHECK: [[TMP37:%.*]] = select <16 x i1> [[TMP36]], <16 x i32> [[TMP31]], <16 x i32> [[TMP33]]
+// CHECK: [[TMP38:%.*]] = bitcast <16 x i32> [[TMP37]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP38]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP40:%.*]] = bitcast <8 x i64> [[TMP39]] to <16 x i32>
+// CHECK: [[TMP41:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = bitcast <8 x i64> [[TMP41]] to <16 x i32>
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <16 x i32> [[TMP40]], <16 x i32> [[TMP42]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP43:%.*]] = bitcast <16 x i32> [[SHUFFLE5_I]] to <8 x i64>
+// CHECK: [[TMP44:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = bitcast <8 x i64> [[TMP44]] to <16 x i32>
+// CHECK: [[TMP46:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP47:%.*]] = bitcast <8 x i64> [[TMP46]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP45]], <16 x i32> [[TMP47]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP48:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP43]], <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: store <8 x i64> [[TMP48]], <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP49:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I15_I]], align 64
+// CHECK: [[TMP50:%.*]] = bitcast <8 x i64> [[TMP49]] to <16 x i32>
+// CHECK: [[TMP51:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP52:%.*]] = bitcast <8 x i64> [[TMP51]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP53:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP54:%.*]] = bitcast <8 x i64> [[TMP53]] to <16 x i32>
+// CHECK: [[TMP55:%.*]] = icmp ult <16 x i32> [[TMP50]], [[TMP52]]
+// CHECK: [[TMP56:%.*]] = select <16 x i1> [[TMP55]], <16 x i32> [[TMP50]], <16 x i32> [[TMP52]]
+// CHECK: [[TMP57:%.*]] = bitcast <16 x i32> [[TMP56]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP57]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP58:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP59:%.*]] = bitcast <8 x i64> [[TMP58]] to <16 x i32>
+// CHECK: [[TMP60:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP61:%.*]] = bitcast <8 x i64> [[TMP60]] to <16 x i32>
+// CHECK: [[SHUFFLE8_I:%.*]] = shufflevector <16 x i32> [[TMP59]], <16 x i32> [[TMP61]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP62:%.*]] = bitcast <16 x i32> [[SHUFFLE8_I]] to <8 x i64>
+// CHECK: [[TMP63:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = bitcast <8 x i64> [[TMP63]] to <16 x i32>
+// CHECK: [[TMP65:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP66:%.*]] = bitcast <8 x i64> [[TMP65]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP64]], <16 x i32> [[TMP66]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP67:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP62]], <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <8 x i64> [[TMP67]], <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP68:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP69:%.*]] = bitcast <8 x i64> [[TMP68]] to <16 x i32>
+// CHECK: [[TMP70:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP71:%.*]] = bitcast <8 x i64> [[TMP70]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP72:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP73:%.*]] = bitcast <8 x i64> [[TMP72]] to <16 x i32>
+// CHECK: [[TMP74:%.*]] = icmp ult <16 x i32> [[TMP69]], [[TMP71]]
+// CHECK: [[TMP75:%.*]] = select <16 x i1> [[TMP74]], <16 x i32> [[TMP69]], <16 x i32> [[TMP71]]
+// CHECK: [[TMP76:%.*]] = bitcast <16 x i32> [[TMP75]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP76]], <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP77:%.*]] = load <8 x i64>, <8 x i64>* [[A_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP77]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
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 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
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle3.i
- // CHECK: %shuffle6.i = shufflevector <16 x i32> %tmp4, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp5 = icmp ult <16 x i32> %tmp4, %shuffle6.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle6.i
- // CHECK: %shuffle9.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp7 = icmp ult <16 x i32> %tmp6, %shuffle9.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle9.i
- // CHECK: %tmp9 = bitcast <16 x i32> %tmp8 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp9, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_reduce_min_epu32(__W);
}
+// CHECK-LABEL: define float @test_mm512_reduce_min_ps(<16 x float> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I17_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I18_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I19_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I14_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I15_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I16_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I11_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I12_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I13_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[A_ADDR_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__W_ADDR:%.*]] = alloca <16 x float>, align 64
+// CHECK: store <16 x float> %__W, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load <16 x float>, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: store <16 x float> [[TMP0]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP1:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x float> [[TMP1]], <16 x float> [[TMP2]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP3:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x float> [[TMP3]], <16 x float> [[TMP4]], <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: store <16 x float> [[SHUFFLE_I]], <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE1_I]], <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP5:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP6:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP7:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP8:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP5]], <16 x float> [[TMP6]], <16 x float> [[TMP7]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP8]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP9:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP10:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE2_I:%.*]] = shufflevector <16 x float> [[TMP9]], <16 x float> [[TMP10]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP11:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP12:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x float> [[TMP11]], <16 x float> [[TMP12]], <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: store <16 x float> [[SHUFFLE2_I]], <16 x float>* [[__A_ADDR_I18_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE3_I]], <16 x float>* [[__B_ADDR_I19_I]], align 64
+// CHECK: [[TMP13:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I18_I]], align 64
+// CHECK: [[TMP14:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I19_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP15:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I17_I]], align 64
+// CHECK: [[TMP16:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP13]], <16 x float> [[TMP14]], <16 x float> [[TMP15]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP16]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP17:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP18:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE5_I:%.*]] = shufflevector <16 x float> [[TMP17]], <16 x float> [[TMP18]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP19:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x float> [[TMP19]], <16 x float> [[TMP20]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE5_I]], <16 x float>* [[__A_ADDR_I15_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE6_I]], <16 x float>* [[__B_ADDR_I16_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I15_I]], align 64
+// CHECK: [[TMP22:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I16_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I14_I]], align 64
+// CHECK: [[TMP24:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP21]], <16 x float> [[TMP22]], <16 x float> [[TMP23]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP24]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP25:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE8_I:%.*]] = shufflevector <16 x float> [[TMP25]], <16 x float> [[TMP26]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP27:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x float> [[TMP27]], <16 x float> [[TMP28]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE8_I]], <16 x float>* [[__A_ADDR_I12_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE9_I]], <16 x float>* [[__B_ADDR_I13_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I12_I]], align 64
+// CHECK: [[TMP30:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I13_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP31:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I11_I]], align 64
+// CHECK: [[TMP32:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP29]], <16 x float> [[TMP30]], <16 x float> [[TMP31]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP32]], <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[TMP33:%.*]] = load <16 x float>, <16 x float>* [[A_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <16 x float> [[TMP33]], i32 0
+// CHECK: ret float [[VECEXT_I]]
float test_mm512_reduce_min_ps(__m512 __W){
- // CHECK: %shuffle1.i = shufflevector <16 x float> %__W, <16 x float> 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: %tmp = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %__W, <16 x float> %shuffle1.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle3.i = shufflevector <16 x float> %tmp, <16 x float> 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: %tmp1 = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %tmp, <16 x float> %shuffle3.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle6.i = shufflevector <16 x float> %tmp1, <16 x float> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp2 = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %tmp1, <16 x float> %shuffle6.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle9.i = shufflevector <16 x float> %tmp2, <16 x float> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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 = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %tmp2, <16 x float> %shuffle9.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <16 x float> %tmp3, i32 0
- // CHECK: ret float %vecext.i
return _mm512_reduce_min_ps(__W);
}
+// CHECK-LABEL: define i32 @test_mm512_mask_reduce_max_epi32(i16 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I20_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__S_ADDR_I_I:%.*]] = alloca i32, align 4
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <16 x i32>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i16, align 2
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i16, align 2
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i16 %__M, i16* [[__M_ADDR]], align 2
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i16, i16* [[__M_ADDR]], align 2
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i16 [[TMP0]], i16* [[__M_ADDR_I]], align 2
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i16, i16* [[__M_ADDR_I]], align 2
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: store i32 -2147483648, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[TMP5:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <16 x i32> undef, i32 [[TMP5]], i32 0
+// CHECK: [[TMP6:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <16 x i32> [[VECINIT_I_I]], i32 [[TMP6]], i32 1
+// CHECK: [[TMP7:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <16 x i32> [[VECINIT1_I_I]], i32 [[TMP7]], i32 2
+// CHECK: [[TMP8:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <16 x i32> [[VECINIT2_I_I]], i32 [[TMP8]], i32 3
+// CHECK: [[TMP9:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <16 x i32> [[VECINIT3_I_I]], i32 [[TMP9]], i32 4
+// CHECK: [[TMP10:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <16 x i32> [[VECINIT4_I_I]], i32 [[TMP10]], i32 5
+// CHECK: [[TMP11:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <16 x i32> [[VECINIT5_I_I]], i32 [[TMP11]], i32 6
+// CHECK: [[TMP12:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <16 x i32> [[VECINIT6_I_I]], i32 [[TMP12]], i32 7
+// CHECK: [[TMP13:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT8_I_I:%.*]] = insertelement <16 x i32> [[VECINIT7_I_I]], i32 [[TMP13]], i32 8
+// CHECK: [[TMP14:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT9_I_I:%.*]] = insertelement <16 x i32> [[VECINIT8_I_I]], i32 [[TMP14]], i32 9
+// CHECK: [[TMP15:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT10_I_I:%.*]] = insertelement <16 x i32> [[VECINIT9_I_I]], i32 [[TMP15]], i32 10
+// CHECK: [[TMP16:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT11_I_I:%.*]] = insertelement <16 x i32> [[VECINIT10_I_I]], i32 [[TMP16]], i32 11
+// CHECK: [[TMP17:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT12_I_I:%.*]] = insertelement <16 x i32> [[VECINIT11_I_I]], i32 [[TMP17]], i32 12
+// CHECK: [[TMP18:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT13_I_I:%.*]] = insertelement <16 x i32> [[VECINIT12_I_I]], i32 [[TMP18]], i32 13
+// CHECK: [[TMP19:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT14_I_I:%.*]] = insertelement <16 x i32> [[VECINIT13_I_I]], i32 [[TMP19]], i32 14
+// CHECK: [[TMP20:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT15_I_I:%.*]] = insertelement <16 x i32> [[VECINIT14_I_I]], i32 [[TMP20]], i32 15
+// CHECK: store <16 x i32> [[VECINIT15_I_I]], <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <16 x i32>, <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP22:%.*]] = bitcast <16 x i32> [[TMP21]] to <8 x i64>
+// CHECK: [[TMP23:%.*]] = bitcast i16 [[TMP2]] to <16 x i1>
+// CHECK: [[TMP24:%.*]] = select <16 x i1> [[TMP23]], <16 x i32> [[TMP4]], <16 x i32> [[TMP21]]
+// CHECK: [[TMP25:%.*]] = bitcast <16 x i32> [[TMP24]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP25]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = bitcast <8 x i64> [[TMP26]] to <16 x i32>
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP29:%.*]] = bitcast <8 x i64> [[TMP28]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP27]], <16 x i32> [[TMP29]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP30:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP31:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = bitcast <8 x i64> [[TMP31]] to <16 x i32>
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = bitcast <8 x i64> [[TMP33]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP32]], <16 x i32> [[TMP34]], <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: [[TMP35:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP30]], <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: store <8 x i64> [[TMP35]], <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: [[TMP37:%.*]] = bitcast <8 x i64> [[TMP36]] to <16 x i32>
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP39:%.*]] = bitcast <8 x i64> [[TMP38]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP40:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP41:%.*]] = bitcast <8 x i64> [[TMP40]] to <16 x i32>
+// CHECK: [[TMP42:%.*]] = icmp sgt <16 x i32> [[TMP37]], [[TMP39]]
+// CHECK: [[TMP43:%.*]] = select <16 x i1> [[TMP42]], <16 x i32> [[TMP37]], <16 x i32> [[TMP39]]
+// CHECK: [[TMP44:%.*]] = bitcast <16 x i32> [[TMP43]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP44]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP46:%.*]] = bitcast <8 x i64> [[TMP45]] to <16 x i32>
+// CHECK: [[TMP47:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP48:%.*]] = bitcast <8 x i64> [[TMP47]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP46]], <16 x i32> [[TMP48]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP49:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: [[TMP50:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP51:%.*]] = bitcast <8 x i64> [[TMP50]] to <16 x i32>
+// CHECK: [[TMP52:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP53:%.*]] = bitcast <8 x i64> [[TMP52]] to <16 x i32>
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <16 x i32> [[TMP51]], <16 x i32> [[TMP53]], <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: [[TMP54:%.*]] = bitcast <16 x i32> [[SHUFFLE4_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP49]], <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: store <8 x i64> [[TMP54]], <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP55:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: [[TMP56:%.*]] = bitcast <8 x i64> [[TMP55]] to <16 x i32>
+// CHECK: [[TMP57:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP58:%.*]] = bitcast <8 x i64> [[TMP57]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP59:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP60:%.*]] = bitcast <8 x i64> [[TMP59]] to <16 x i32>
+// CHECK: [[TMP61:%.*]] = icmp sgt <16 x i32> [[TMP56]], [[TMP58]]
+// CHECK: [[TMP62:%.*]] = select <16 x i1> [[TMP61]], <16 x i32> [[TMP56]], <16 x i32> [[TMP58]]
+// CHECK: [[TMP63:%.*]] = bitcast <16 x i32> [[TMP62]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP63]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP65:%.*]] = bitcast <8 x i64> [[TMP64]] to <16 x i32>
+// CHECK: [[TMP66:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP67:%.*]] = bitcast <8 x i64> [[TMP66]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP65]], <16 x i32> [[TMP67]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP68:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: [[TMP69:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP70:%.*]] = bitcast <8 x i64> [[TMP69]] to <16 x i32>
+// CHECK: [[TMP71:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP72:%.*]] = bitcast <8 x i64> [[TMP71]] to <16 x i32>
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <16 x i32> [[TMP70]], <16 x i32> [[TMP72]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP73:%.*]] = bitcast <16 x i32> [[SHUFFLE7_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP68]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[TMP73]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP74:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP75:%.*]] = bitcast <8 x i64> [[TMP74]] to <16 x i32>
+// CHECK: [[TMP76:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP77:%.*]] = bitcast <8 x i64> [[TMP76]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP78:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP79:%.*]] = bitcast <8 x i64> [[TMP78]] to <16 x i32>
+// CHECK: [[TMP80:%.*]] = icmp sgt <16 x i32> [[TMP75]], [[TMP77]]
+// CHECK: [[TMP81:%.*]] = select <16 x i1> [[TMP80]], <16 x i32> [[TMP75]], <16 x i32> [[TMP77]]
+// CHECK: [[TMP82:%.*]] = bitcast <16 x i32> [[TMP81]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP82]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP83:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP84:%.*]] = bitcast <8 x i64> [[TMP83]] to <16 x i32>
+// CHECK: [[TMP85:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP86:%.*]] = bitcast <8 x i64> [[TMP85]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP84]], <16 x i32> [[TMP86]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP87:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: [[TMP88:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP89:%.*]] = bitcast <8 x i64> [[TMP88]] to <16 x i32>
+// CHECK: [[TMP90:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP91:%.*]] = bitcast <8 x i64> [[TMP90]] to <16 x i32>
+// CHECK: [[SHUFFLE10_I:%.*]] = shufflevector <16 x i32> [[TMP89]], <16 x i32> [[TMP91]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP92:%.*]] = bitcast <16 x i32> [[SHUFFLE10_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP87]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP92]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP93:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP94:%.*]] = bitcast <8 x i64> [[TMP93]] to <16 x i32>
+// CHECK: [[TMP95:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP96:%.*]] = bitcast <8 x i64> [[TMP95]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP97:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP98:%.*]] = bitcast <8 x i64> [[TMP97]] to <16 x i32>
+// CHECK: [[TMP99:%.*]] = icmp sgt <16 x i32> [[TMP94]], [[TMP96]]
+// CHECK: [[TMP100:%.*]] = select <16 x i1> [[TMP99]], <16 x i32> [[TMP94]], <16 x i32> [[TMP96]]
+// CHECK: [[TMP101:%.*]] = bitcast <16 x i32> [[TMP100]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP101]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP102:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP102]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
int test_mm512_mask_reduce_max_epi32(__mmask16 __M, __m512i __W){
- // CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
- // CHECK: %tmp1 = bitcast i16 %__M to <16 x i1>
- // CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648>
- // CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp2, <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: %tmp3 = icmp sgt <16 x i32> %tmp2, %shuffle1.i
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <16 x i32> %tmp4, <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: %tmp5 = icmp sgt <16 x i32> %tmp4, %shuffle4.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp7 = icmp sgt <16 x i32> %tmp6, %shuffle7.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle7.i
- // CHECK: %shuffle10.i = shufflevector <16 x i32> %tmp8, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp9 = icmp sgt <16 x i32> %tmp8, %shuffle10.i
- // CHECK: %tmp10 = select <16 x i1> %tmp9, <16 x i32> %tmp8, <16 x i32> %shuffle10.i
- // CHECK: %tmp11 = bitcast <16 x i32> %tmp10 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp11, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_mask_reduce_max_epi32(__M, __W);
}
+// CHECK-LABEL: define i32 @test_mm512_mask_reduce_max_epu32(i16 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I20_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__S_ADDR_I_I:%.*]] = alloca i32, align 4
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <16 x i32>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i16, align 2
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i16, align 2
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i16 %__M, i16* [[__M_ADDR]], align 2
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i16, i16* [[__M_ADDR]], align 2
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i16 [[TMP0]], i16* [[__M_ADDR_I]], align 2
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i16, i16* [[__M_ADDR_I]], align 2
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: store i32 0, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[TMP5:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <16 x i32> undef, i32 [[TMP5]], i32 0
+// CHECK: [[TMP6:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <16 x i32> [[VECINIT_I_I]], i32 [[TMP6]], i32 1
+// CHECK: [[TMP7:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <16 x i32> [[VECINIT1_I_I]], i32 [[TMP7]], i32 2
+// CHECK: [[TMP8:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <16 x i32> [[VECINIT2_I_I]], i32 [[TMP8]], i32 3
+// CHECK: [[TMP9:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <16 x i32> [[VECINIT3_I_I]], i32 [[TMP9]], i32 4
+// CHECK: [[TMP10:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <16 x i32> [[VECINIT4_I_I]], i32 [[TMP10]], i32 5
+// CHECK: [[TMP11:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <16 x i32> [[VECINIT5_I_I]], i32 [[TMP11]], i32 6
+// CHECK: [[TMP12:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <16 x i32> [[VECINIT6_I_I]], i32 [[TMP12]], i32 7
+// CHECK: [[TMP13:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT8_I_I:%.*]] = insertelement <16 x i32> [[VECINIT7_I_I]], i32 [[TMP13]], i32 8
+// CHECK: [[TMP14:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT9_I_I:%.*]] = insertelement <16 x i32> [[VECINIT8_I_I]], i32 [[TMP14]], i32 9
+// CHECK: [[TMP15:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT10_I_I:%.*]] = insertelement <16 x i32> [[VECINIT9_I_I]], i32 [[TMP15]], i32 10
+// CHECK: [[TMP16:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT11_I_I:%.*]] = insertelement <16 x i32> [[VECINIT10_I_I]], i32 [[TMP16]], i32 11
+// CHECK: [[TMP17:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT12_I_I:%.*]] = insertelement <16 x i32> [[VECINIT11_I_I]], i32 [[TMP17]], i32 12
+// CHECK: [[TMP18:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT13_I_I:%.*]] = insertelement <16 x i32> [[VECINIT12_I_I]], i32 [[TMP18]], i32 13
+// CHECK: [[TMP19:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT14_I_I:%.*]] = insertelement <16 x i32> [[VECINIT13_I_I]], i32 [[TMP19]], i32 14
+// CHECK: [[TMP20:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT15_I_I:%.*]] = insertelement <16 x i32> [[VECINIT14_I_I]], i32 [[TMP20]], i32 15
+// CHECK: store <16 x i32> [[VECINIT15_I_I]], <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <16 x i32>, <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP22:%.*]] = bitcast <16 x i32> [[TMP21]] to <8 x i64>
+// CHECK: [[TMP23:%.*]] = bitcast i16 [[TMP2]] to <16 x i1>
+// CHECK: [[TMP24:%.*]] = select <16 x i1> [[TMP23]], <16 x i32> [[TMP4]], <16 x i32> [[TMP21]]
+// CHECK: [[TMP25:%.*]] = bitcast <16 x i32> [[TMP24]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP25]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = bitcast <8 x i64> [[TMP26]] to <16 x i32>
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP29:%.*]] = bitcast <8 x i64> [[TMP28]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP27]], <16 x i32> [[TMP29]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP30:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP31:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = bitcast <8 x i64> [[TMP31]] to <16 x i32>
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = bitcast <8 x i64> [[TMP33]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP32]], <16 x i32> [[TMP34]], <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: [[TMP35:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP30]], <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: store <8 x i64> [[TMP35]], <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: [[TMP37:%.*]] = bitcast <8 x i64> [[TMP36]] to <16 x i32>
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP39:%.*]] = bitcast <8 x i64> [[TMP38]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP40:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP41:%.*]] = bitcast <8 x i64> [[TMP40]] to <16 x i32>
+// CHECK: [[TMP42:%.*]] = icmp ugt <16 x i32> [[TMP37]], [[TMP39]]
+// CHECK: [[TMP43:%.*]] = select <16 x i1> [[TMP42]], <16 x i32> [[TMP37]], <16 x i32> [[TMP39]]
+// CHECK: [[TMP44:%.*]] = bitcast <16 x i32> [[TMP43]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP44]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP46:%.*]] = bitcast <8 x i64> [[TMP45]] to <16 x i32>
+// CHECK: [[TMP47:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP48:%.*]] = bitcast <8 x i64> [[TMP47]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP46]], <16 x i32> [[TMP48]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP49:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: [[TMP50:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP51:%.*]] = bitcast <8 x i64> [[TMP50]] to <16 x i32>
+// CHECK: [[TMP52:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP53:%.*]] = bitcast <8 x i64> [[TMP52]] to <16 x i32>
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <16 x i32> [[TMP51]], <16 x i32> [[TMP53]], <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: [[TMP54:%.*]] = bitcast <16 x i32> [[SHUFFLE4_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP49]], <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: store <8 x i64> [[TMP54]], <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP55:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: [[TMP56:%.*]] = bitcast <8 x i64> [[TMP55]] to <16 x i32>
+// CHECK: [[TMP57:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP58:%.*]] = bitcast <8 x i64> [[TMP57]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP59:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP60:%.*]] = bitcast <8 x i64> [[TMP59]] to <16 x i32>
+// CHECK: [[TMP61:%.*]] = icmp ugt <16 x i32> [[TMP56]], [[TMP58]]
+// CHECK: [[TMP62:%.*]] = select <16 x i1> [[TMP61]], <16 x i32> [[TMP56]], <16 x i32> [[TMP58]]
+// CHECK: [[TMP63:%.*]] = bitcast <16 x i32> [[TMP62]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP63]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP65:%.*]] = bitcast <8 x i64> [[TMP64]] to <16 x i32>
+// CHECK: [[TMP66:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP67:%.*]] = bitcast <8 x i64> [[TMP66]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP65]], <16 x i32> [[TMP67]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP68:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: [[TMP69:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP70:%.*]] = bitcast <8 x i64> [[TMP69]] to <16 x i32>
+// CHECK: [[TMP71:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP72:%.*]] = bitcast <8 x i64> [[TMP71]] to <16 x i32>
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <16 x i32> [[TMP70]], <16 x i32> [[TMP72]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP73:%.*]] = bitcast <16 x i32> [[SHUFFLE7_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP68]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[TMP73]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP74:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP75:%.*]] = bitcast <8 x i64> [[TMP74]] to <16 x i32>
+// CHECK: [[TMP76:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP77:%.*]] = bitcast <8 x i64> [[TMP76]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP78:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP79:%.*]] = bitcast <8 x i64> [[TMP78]] to <16 x i32>
+// CHECK: [[TMP80:%.*]] = icmp ugt <16 x i32> [[TMP75]], [[TMP77]]
+// CHECK: [[TMP81:%.*]] = select <16 x i1> [[TMP80]], <16 x i32> [[TMP75]], <16 x i32> [[TMP77]]
+// CHECK: [[TMP82:%.*]] = bitcast <16 x i32> [[TMP81]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP82]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP83:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP84:%.*]] = bitcast <8 x i64> [[TMP83]] to <16 x i32>
+// CHECK: [[TMP85:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP86:%.*]] = bitcast <8 x i64> [[TMP85]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP84]], <16 x i32> [[TMP86]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP87:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: [[TMP88:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP89:%.*]] = bitcast <8 x i64> [[TMP88]] to <16 x i32>
+// CHECK: [[TMP90:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP91:%.*]] = bitcast <8 x i64> [[TMP90]] to <16 x i32>
+// CHECK: [[SHUFFLE10_I:%.*]] = shufflevector <16 x i32> [[TMP89]], <16 x i32> [[TMP91]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP92:%.*]] = bitcast <16 x i32> [[SHUFFLE10_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP87]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP92]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP93:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP94:%.*]] = bitcast <8 x i64> [[TMP93]] to <16 x i32>
+// CHECK: [[TMP95:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP96:%.*]] = bitcast <8 x i64> [[TMP95]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP97:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP98:%.*]] = bitcast <8 x i64> [[TMP97]] to <16 x i32>
+// CHECK: [[TMP99:%.*]] = icmp ugt <16 x i32> [[TMP94]], [[TMP96]]
+// CHECK: [[TMP100:%.*]] = select <16 x i1> [[TMP99]], <16 x i32> [[TMP94]], <16 x i32> [[TMP96]]
+// CHECK: [[TMP101:%.*]] = bitcast <16 x i32> [[TMP100]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP101]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP102:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP102]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
unsigned int test_mm512_mask_reduce_max_epu32(__mmask16 __M, __m512i __W){
- // CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
- // CHECK: %tmp1 = bitcast i16 %__M to <16 x i1>
- // CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> zeroinitializer
- // CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp2, <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: %tmp3 = icmp ugt <16 x i32> %tmp2, %shuffle1.i
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <16 x i32> %tmp4, <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: %tmp5 = icmp ugt <16 x i32> %tmp4, %shuffle4.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp7 = icmp ugt <16 x i32> %tmp6, %shuffle7.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle7.i
- // CHECK: %shuffle10.i = shufflevector <16 x i32> %tmp8, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp9 = icmp ugt <16 x i32> %tmp8, %shuffle10.i
- // CHECK: %tmp10 = select <16 x i1> %tmp9, <16 x i32> %tmp8, <16 x i32> %shuffle10.i
- // CHECK: %tmp11 = bitcast <16 x i32> %tmp10 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp11, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_mask_reduce_max_epu32(__M, __W);
}
+// CHECK-LABEL: define float @test_mm512_mask_reduce_max_ps(i16 zeroext %__M, <16 x float> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I18_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I19_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I20_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I15_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I16_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I17_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__W_ADDR_I_I:%.*]] = alloca float, align 4
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i16, align 2
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i16, align 2
+// CHECK: [[__W_ADDR:%.*]] = alloca <16 x float>, align 64
+// CHECK: store i16 %__M, i16* [[__M_ADDR]], align 2
+// CHECK: store <16 x float> %__W, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i16, i16* [[__M_ADDR]], align 2
+// CHECK: [[TMP1:%.*]] = load <16 x float>, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: store i16 [[TMP0]], i16* [[__M_ADDR_I]], align 2
+// CHECK: store <16 x float> [[TMP1]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i16, i16* [[__M_ADDR_I]], align 2
+// CHECK: [[TMP3:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: store float 0x7FF0000000000000, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[TMP4:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <16 x float> undef, float [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <16 x float> [[VECINIT_I_I]], float [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <16 x float> [[VECINIT1_I_I]], float [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <16 x float> [[VECINIT2_I_I]], float [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <16 x float> [[VECINIT3_I_I]], float [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <16 x float> [[VECINIT4_I_I]], float [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <16 x float> [[VECINIT5_I_I]], float [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <16 x float> [[VECINIT6_I_I]], float [[TMP11]], i32 7
+// CHECK: [[TMP12:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT8_I_I:%.*]] = insertelement <16 x float> [[VECINIT7_I_I]], float [[TMP12]], i32 8
+// CHECK: [[TMP13:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT9_I_I:%.*]] = insertelement <16 x float> [[VECINIT8_I_I]], float [[TMP13]], i32 9
+// CHECK: [[TMP14:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT10_I_I:%.*]] = insertelement <16 x float> [[VECINIT9_I_I]], float [[TMP14]], i32 10
+// CHECK: [[TMP15:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT11_I_I:%.*]] = insertelement <16 x float> [[VECINIT10_I_I]], float [[TMP15]], i32 11
+// CHECK: [[TMP16:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT12_I_I:%.*]] = insertelement <16 x float> [[VECINIT11_I_I]], float [[TMP16]], i32 12
+// CHECK: [[TMP17:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT13_I_I:%.*]] = insertelement <16 x float> [[VECINIT12_I_I]], float [[TMP17]], i32 13
+// CHECK: [[TMP18:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT14_I_I:%.*]] = insertelement <16 x float> [[VECINIT13_I_I]], float [[TMP18]], i32 14
+// CHECK: [[TMP19:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT15_I_I:%.*]] = insertelement <16 x float> [[VECINIT14_I_I]], float [[TMP19]], i32 15
+// CHECK: store <16 x float> [[VECINIT15_I_I]], <16 x float>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[SUB_I:%.*]] = fsub <16 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[TMP20]]
+// CHECK: [[TMP21:%.*]] = bitcast i16 [[TMP2]] to <16 x i1>
+// CHECK: [[TMP22:%.*]] = select <16 x i1> [[TMP21]], <16 x float> [[TMP3]], <16 x float> [[SUB_I]]
+// CHECK: store <16 x float> [[TMP22]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x float> [[TMP23]], <16 x float> [[TMP24]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP25:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x float> [[TMP25]], <16 x float> [[TMP26]], <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: store <16 x float> [[SHUFFLE_I]], <16 x float>* [[__A_ADDR_I19_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE1_I]], <16 x float>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I19_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I20_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP30:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP27]], <16 x float> [[TMP28]], <16 x float> [[TMP29]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP30]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP31:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x float> [[TMP31]], <16 x float> [[TMP32]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP33:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <16 x float> [[TMP33]], <16 x float> [[TMP34]], <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: store <16 x float> [[SHUFFLE3_I]], <16 x float>* [[__A_ADDR_I16_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE4_I]], <16 x float>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP35:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I16_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I17_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP38:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP35]], <16 x float> [[TMP36]], <16 x float> [[TMP37]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP38]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP40:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x float> [[TMP39]], <16 x float> [[TMP40]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP41:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <16 x float> [[TMP41]], <16 x float> [[TMP42]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE6_I]], <16 x float>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE7_I]], <16 x float>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP43:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP44:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP45:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP46:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP43]], <16 x float> [[TMP44]], <16 x float> [[TMP45]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP46]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP47:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP48:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x float> [[TMP47]], <16 x float> [[TMP48]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP49:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP50:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE10_I:%.*]] = shufflevector <16 x float> [[TMP49]], <16 x float> [[TMP50]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE9_I]], <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE10_I]], <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP51:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP52:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP53:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP54:%.*]] = call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> [[TMP51]], <16 x float> [[TMP52]], <16 x float> [[TMP53]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP54]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP55:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <16 x float> [[TMP55]], i32 0
+// CHECK: ret float [[VECEXT_I]]
float test_mm512_mask_reduce_max_ps(__mmask16 __M, __m512 __W){
- // CHECK: %tmp = bitcast i16 %__M to <16 x i1>
- // CHECK: %tmp1 = select <16 x i1> %tmp, <16 x float> %__W, <16 x float> <float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000, float 0xFFF0000000000000>
- // CHECK: %shuffle1.i = shufflevector <16 x float> %tmp1, <16 x float> 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: %tmp2 = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %tmp1, <16 x float> %shuffle1.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle4.i = shufflevector <16 x float> %tmp2, <16 x float> 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 = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %tmp2, <16 x float> %shuffle4.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle7.i = shufflevector <16 x float> %tmp3, <16 x float> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp4 = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %tmp3, <16 x float> %shuffle7.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle10.i = shufflevector <16 x float> %tmp4, <16 x float> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp5 = tail call <16 x float> @llvm.x86.avx512.mask.max.ps.512(<16 x float> %tmp4, <16 x float> %shuffle10.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <16 x float> %tmp5, i32 0
- // CHECK: ret float %vecext.i
return _mm512_mask_reduce_max_ps(__M, __W);
}
+// CHECK-LABEL: define i32 @test_mm512_mask_reduce_min_epi32(i16 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I20_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__S_ADDR_I_I:%.*]] = alloca i32, align 4
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <16 x i32>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i16, align 2
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i16, align 2
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i16 %__M, i16* [[__M_ADDR]], align 2
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i16, i16* [[__M_ADDR]], align 2
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i16 [[TMP0]], i16* [[__M_ADDR_I]], align 2
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i16, i16* [[__M_ADDR_I]], align 2
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: store i32 2147483647, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[TMP5:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <16 x i32> undef, i32 [[TMP5]], i32 0
+// CHECK: [[TMP6:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <16 x i32> [[VECINIT_I_I]], i32 [[TMP6]], i32 1
+// CHECK: [[TMP7:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <16 x i32> [[VECINIT1_I_I]], i32 [[TMP7]], i32 2
+// CHECK: [[TMP8:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <16 x i32> [[VECINIT2_I_I]], i32 [[TMP8]], i32 3
+// CHECK: [[TMP9:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <16 x i32> [[VECINIT3_I_I]], i32 [[TMP9]], i32 4
+// CHECK: [[TMP10:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <16 x i32> [[VECINIT4_I_I]], i32 [[TMP10]], i32 5
+// CHECK: [[TMP11:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <16 x i32> [[VECINIT5_I_I]], i32 [[TMP11]], i32 6
+// CHECK: [[TMP12:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <16 x i32> [[VECINIT6_I_I]], i32 [[TMP12]], i32 7
+// CHECK: [[TMP13:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT8_I_I:%.*]] = insertelement <16 x i32> [[VECINIT7_I_I]], i32 [[TMP13]], i32 8
+// CHECK: [[TMP14:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT9_I_I:%.*]] = insertelement <16 x i32> [[VECINIT8_I_I]], i32 [[TMP14]], i32 9
+// CHECK: [[TMP15:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT10_I_I:%.*]] = insertelement <16 x i32> [[VECINIT9_I_I]], i32 [[TMP15]], i32 10
+// CHECK: [[TMP16:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT11_I_I:%.*]] = insertelement <16 x i32> [[VECINIT10_I_I]], i32 [[TMP16]], i32 11
+// CHECK: [[TMP17:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT12_I_I:%.*]] = insertelement <16 x i32> [[VECINIT11_I_I]], i32 [[TMP17]], i32 12
+// CHECK: [[TMP18:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT13_I_I:%.*]] = insertelement <16 x i32> [[VECINIT12_I_I]], i32 [[TMP18]], i32 13
+// CHECK: [[TMP19:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT14_I_I:%.*]] = insertelement <16 x i32> [[VECINIT13_I_I]], i32 [[TMP19]], i32 14
+// CHECK: [[TMP20:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT15_I_I:%.*]] = insertelement <16 x i32> [[VECINIT14_I_I]], i32 [[TMP20]], i32 15
+// CHECK: store <16 x i32> [[VECINIT15_I_I]], <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <16 x i32>, <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP22:%.*]] = bitcast <16 x i32> [[TMP21]] to <8 x i64>
+// CHECK: [[TMP23:%.*]] = bitcast i16 [[TMP2]] to <16 x i1>
+// CHECK: [[TMP24:%.*]] = select <16 x i1> [[TMP23]], <16 x i32> [[TMP4]], <16 x i32> [[TMP21]]
+// CHECK: [[TMP25:%.*]] = bitcast <16 x i32> [[TMP24]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP25]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = bitcast <8 x i64> [[TMP26]] to <16 x i32>
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP29:%.*]] = bitcast <8 x i64> [[TMP28]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP27]], <16 x i32> [[TMP29]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP30:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP31:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = bitcast <8 x i64> [[TMP31]] to <16 x i32>
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = bitcast <8 x i64> [[TMP33]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP32]], <16 x i32> [[TMP34]], <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: [[TMP35:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP30]], <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: store <8 x i64> [[TMP35]], <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: [[TMP37:%.*]] = bitcast <8 x i64> [[TMP36]] to <16 x i32>
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP39:%.*]] = bitcast <8 x i64> [[TMP38]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP40:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP41:%.*]] = bitcast <8 x i64> [[TMP40]] to <16 x i32>
+// CHECK: [[TMP42:%.*]] = icmp slt <16 x i32> [[TMP37]], [[TMP39]]
+// CHECK: [[TMP43:%.*]] = select <16 x i1> [[TMP42]], <16 x i32> [[TMP37]], <16 x i32> [[TMP39]]
+// CHECK: [[TMP44:%.*]] = bitcast <16 x i32> [[TMP43]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP44]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP46:%.*]] = bitcast <8 x i64> [[TMP45]] to <16 x i32>
+// CHECK: [[TMP47:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP48:%.*]] = bitcast <8 x i64> [[TMP47]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP46]], <16 x i32> [[TMP48]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP49:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: [[TMP50:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP51:%.*]] = bitcast <8 x i64> [[TMP50]] to <16 x i32>
+// CHECK: [[TMP52:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP53:%.*]] = bitcast <8 x i64> [[TMP52]] to <16 x i32>
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <16 x i32> [[TMP51]], <16 x i32> [[TMP53]], <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: [[TMP54:%.*]] = bitcast <16 x i32> [[SHUFFLE4_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP49]], <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: store <8 x i64> [[TMP54]], <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP55:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: [[TMP56:%.*]] = bitcast <8 x i64> [[TMP55]] to <16 x i32>
+// CHECK: [[TMP57:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP58:%.*]] = bitcast <8 x i64> [[TMP57]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP59:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP60:%.*]] = bitcast <8 x i64> [[TMP59]] to <16 x i32>
+// CHECK: [[TMP61:%.*]] = icmp slt <16 x i32> [[TMP56]], [[TMP58]]
+// CHECK: [[TMP62:%.*]] = select <16 x i1> [[TMP61]], <16 x i32> [[TMP56]], <16 x i32> [[TMP58]]
+// CHECK: [[TMP63:%.*]] = bitcast <16 x i32> [[TMP62]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP63]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP65:%.*]] = bitcast <8 x i64> [[TMP64]] to <16 x i32>
+// CHECK: [[TMP66:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP67:%.*]] = bitcast <8 x i64> [[TMP66]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP65]], <16 x i32> [[TMP67]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP68:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: [[TMP69:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP70:%.*]] = bitcast <8 x i64> [[TMP69]] to <16 x i32>
+// CHECK: [[TMP71:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP72:%.*]] = bitcast <8 x i64> [[TMP71]] to <16 x i32>
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <16 x i32> [[TMP70]], <16 x i32> [[TMP72]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP73:%.*]] = bitcast <16 x i32> [[SHUFFLE7_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP68]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[TMP73]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP74:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP75:%.*]] = bitcast <8 x i64> [[TMP74]] to <16 x i32>
+// CHECK: [[TMP76:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP77:%.*]] = bitcast <8 x i64> [[TMP76]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP78:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP79:%.*]] = bitcast <8 x i64> [[TMP78]] to <16 x i32>
+// CHECK: [[TMP80:%.*]] = icmp slt <16 x i32> [[TMP75]], [[TMP77]]
+// CHECK: [[TMP81:%.*]] = select <16 x i1> [[TMP80]], <16 x i32> [[TMP75]], <16 x i32> [[TMP77]]
+// CHECK: [[TMP82:%.*]] = bitcast <16 x i32> [[TMP81]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP82]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP83:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP84:%.*]] = bitcast <8 x i64> [[TMP83]] to <16 x i32>
+// CHECK: [[TMP85:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP86:%.*]] = bitcast <8 x i64> [[TMP85]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP84]], <16 x i32> [[TMP86]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP87:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: [[TMP88:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP89:%.*]] = bitcast <8 x i64> [[TMP88]] to <16 x i32>
+// CHECK: [[TMP90:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP91:%.*]] = bitcast <8 x i64> [[TMP90]] to <16 x i32>
+// CHECK: [[SHUFFLE10_I:%.*]] = shufflevector <16 x i32> [[TMP89]], <16 x i32> [[TMP91]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP92:%.*]] = bitcast <16 x i32> [[SHUFFLE10_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP87]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP92]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP93:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP94:%.*]] = bitcast <8 x i64> [[TMP93]] to <16 x i32>
+// CHECK: [[TMP95:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP96:%.*]] = bitcast <8 x i64> [[TMP95]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP97:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP98:%.*]] = bitcast <8 x i64> [[TMP97]] to <16 x i32>
+// CHECK: [[TMP99:%.*]] = icmp slt <16 x i32> [[TMP94]], [[TMP96]]
+// CHECK: [[TMP100:%.*]] = select <16 x i1> [[TMP99]], <16 x i32> [[TMP94]], <16 x i32> [[TMP96]]
+// CHECK: [[TMP101:%.*]] = bitcast <16 x i32> [[TMP100]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP101]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP102:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP102]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
int test_mm512_mask_reduce_min_epi32(__mmask16 __M, __m512i __W){
- // CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
- // CHECK: %tmp1 = bitcast i16 %__M to <16 x i1>
- // CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> <i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647>
- // CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp2, <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: %tmp3 = icmp slt <16 x i32> %tmp2, %shuffle1.i
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <16 x i32> %tmp4, <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: %tmp5 = icmp slt <16 x i32> %tmp4, %shuffle4.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp7 = icmp slt <16 x i32> %tmp6, %shuffle7.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle7.i
- // CHECK: %shuffle10.i = shufflevector <16 x i32> %tmp8, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp9 = icmp slt <16 x i32> %tmp8, %shuffle10.i
- // CHECK: %tmp10 = select <16 x i1> %tmp9, <16 x i32> %tmp8, <16 x i32> %shuffle10.i
- // CHECK: %tmp11 = bitcast <16 x i32> %tmp10 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp11, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_mask_reduce_min_epi32(__M, __W);
}
+// CHECK-LABEL: define i32 @test_mm512_mask_reduce_min_epu32(i16 zeroext %__M, <8 x i64> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I18_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I19_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I20_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I15_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I16_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I17_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__S_ADDR_I_I:%.*]] = alloca i32, align 4
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <16 x i32>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i16, align 2
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <8 x i64>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i16, align 2
+// CHECK: [[__W_ADDR:%.*]] = alloca <8 x i64>, align 64
+// CHECK: store i16 %__M, i16* [[__M_ADDR]], align 2
+// CHECK: store <8 x i64> %__W, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i16, i16* [[__M_ADDR]], align 2
+// CHECK: [[TMP1:%.*]] = load <8 x i64>, <8 x i64>* [[__W_ADDR]], align 64
+// CHECK: store i16 [[TMP0]], i16* [[__M_ADDR_I]], align 2
+// CHECK: store <8 x i64> [[TMP1]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i16, i16* [[__M_ADDR_I]], align 2
+// CHECK: [[TMP3:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i64> [[TMP3]] to <16 x i32>
+// CHECK: store i32 -1, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[TMP5:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <16 x i32> undef, i32 [[TMP5]], i32 0
+// CHECK: [[TMP6:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <16 x i32> [[VECINIT_I_I]], i32 [[TMP6]], i32 1
+// CHECK: [[TMP7:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <16 x i32> [[VECINIT1_I_I]], i32 [[TMP7]], i32 2
+// CHECK: [[TMP8:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <16 x i32> [[VECINIT2_I_I]], i32 [[TMP8]], i32 3
+// CHECK: [[TMP9:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <16 x i32> [[VECINIT3_I_I]], i32 [[TMP9]], i32 4
+// CHECK: [[TMP10:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <16 x i32> [[VECINIT4_I_I]], i32 [[TMP10]], i32 5
+// CHECK: [[TMP11:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <16 x i32> [[VECINIT5_I_I]], i32 [[TMP11]], i32 6
+// CHECK: [[TMP12:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <16 x i32> [[VECINIT6_I_I]], i32 [[TMP12]], i32 7
+// CHECK: [[TMP13:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT8_I_I:%.*]] = insertelement <16 x i32> [[VECINIT7_I_I]], i32 [[TMP13]], i32 8
+// CHECK: [[TMP14:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT9_I_I:%.*]] = insertelement <16 x i32> [[VECINIT8_I_I]], i32 [[TMP14]], i32 9
+// CHECK: [[TMP15:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT10_I_I:%.*]] = insertelement <16 x i32> [[VECINIT9_I_I]], i32 [[TMP15]], i32 10
+// CHECK: [[TMP16:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT11_I_I:%.*]] = insertelement <16 x i32> [[VECINIT10_I_I]], i32 [[TMP16]], i32 11
+// CHECK: [[TMP17:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT12_I_I:%.*]] = insertelement <16 x i32> [[VECINIT11_I_I]], i32 [[TMP17]], i32 12
+// CHECK: [[TMP18:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT13_I_I:%.*]] = insertelement <16 x i32> [[VECINIT12_I_I]], i32 [[TMP18]], i32 13
+// CHECK: [[TMP19:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT14_I_I:%.*]] = insertelement <16 x i32> [[VECINIT13_I_I]], i32 [[TMP19]], i32 14
+// CHECK: [[TMP20:%.*]] = load i32, i32* [[__S_ADDR_I_I]], align 4
+// CHECK: [[VECINIT15_I_I:%.*]] = insertelement <16 x i32> [[VECINIT14_I_I]], i32 [[TMP20]], i32 15
+// CHECK: store <16 x i32> [[VECINIT15_I_I]], <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP21:%.*]] = load <16 x i32>, <16 x i32>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP22:%.*]] = bitcast <16 x i32> [[TMP21]] to <8 x i64>
+// CHECK: [[TMP23:%.*]] = bitcast i16 [[TMP2]] to <16 x i1>
+// CHECK: [[TMP24:%.*]] = select <16 x i1> [[TMP23]], <16 x i32> [[TMP4]], <16 x i32> [[TMP21]]
+// CHECK: [[TMP25:%.*]] = bitcast <16 x i32> [[TMP24]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP25]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP27:%.*]] = bitcast <8 x i64> [[TMP26]] to <16 x i32>
+// CHECK: [[TMP28:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP29:%.*]] = bitcast <8 x i64> [[TMP28]] to <16 x i32>
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x i32> [[TMP27]], <16 x i32> [[TMP29]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP30:%.*]] = bitcast <16 x i32> [[SHUFFLE_I]] to <8 x i64>
+// CHECK: [[TMP31:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = bitcast <8 x i64> [[TMP31]] to <16 x i32>
+// CHECK: [[TMP33:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = bitcast <8 x i64> [[TMP33]] to <16 x i32>
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x i32> [[TMP32]], <16 x i32> [[TMP34]], <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: [[TMP35:%.*]] = bitcast <16 x i32> [[SHUFFLE1_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP30]], <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: store <8 x i64> [[TMP35]], <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I19_I]], align 64
+// CHECK: [[TMP37:%.*]] = bitcast <8 x i64> [[TMP36]] to <16 x i32>
+// CHECK: [[TMP38:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP39:%.*]] = bitcast <8 x i64> [[TMP38]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP40:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP41:%.*]] = bitcast <8 x i64> [[TMP40]] to <16 x i32>
+// CHECK: [[TMP42:%.*]] = icmp ult <16 x i32> [[TMP37]], [[TMP39]]
+// CHECK: [[TMP43:%.*]] = select <16 x i1> [[TMP42]], <16 x i32> [[TMP37]], <16 x i32> [[TMP39]]
+// CHECK: [[TMP44:%.*]] = bitcast <16 x i32> [[TMP43]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP44]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP45:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP46:%.*]] = bitcast <8 x i64> [[TMP45]] to <16 x i32>
+// CHECK: [[TMP47:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP48:%.*]] = bitcast <8 x i64> [[TMP47]] to <16 x i32>
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x i32> [[TMP46]], <16 x i32> [[TMP48]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP49:%.*]] = bitcast <16 x i32> [[SHUFFLE3_I]] to <8 x i64>
+// CHECK: [[TMP50:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP51:%.*]] = bitcast <8 x i64> [[TMP50]] to <16 x i32>
+// CHECK: [[TMP52:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP53:%.*]] = bitcast <8 x i64> [[TMP52]] to <16 x i32>
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <16 x i32> [[TMP51]], <16 x i32> [[TMP53]], <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: [[TMP54:%.*]] = bitcast <16 x i32> [[SHUFFLE4_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP49]], <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: store <8 x i64> [[TMP54]], <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP55:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I16_I]], align 64
+// CHECK: [[TMP56:%.*]] = bitcast <8 x i64> [[TMP55]] to <16 x i32>
+// CHECK: [[TMP57:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP58:%.*]] = bitcast <8 x i64> [[TMP57]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP59:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP60:%.*]] = bitcast <8 x i64> [[TMP59]] to <16 x i32>
+// CHECK: [[TMP61:%.*]] = icmp ult <16 x i32> [[TMP56]], [[TMP58]]
+// CHECK: [[TMP62:%.*]] = select <16 x i1> [[TMP61]], <16 x i32> [[TMP56]], <16 x i32> [[TMP58]]
+// CHECK: [[TMP63:%.*]] = bitcast <16 x i32> [[TMP62]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP63]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP64:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP65:%.*]] = bitcast <8 x i64> [[TMP64]] to <16 x i32>
+// CHECK: [[TMP66:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP67:%.*]] = bitcast <8 x i64> [[TMP66]] to <16 x i32>
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x i32> [[TMP65]], <16 x i32> [[TMP67]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP68:%.*]] = bitcast <16 x i32> [[SHUFFLE6_I]] to <8 x i64>
+// CHECK: [[TMP69:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP70:%.*]] = bitcast <8 x i64> [[TMP69]] to <16 x i32>
+// CHECK: [[TMP71:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP72:%.*]] = bitcast <8 x i64> [[TMP71]] to <16 x i32>
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <16 x i32> [[TMP70]], <16 x i32> [[TMP72]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: [[TMP73:%.*]] = bitcast <16 x i32> [[SHUFFLE7_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP68]], <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <8 x i64> [[TMP73]], <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP74:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP75:%.*]] = bitcast <8 x i64> [[TMP74]] to <16 x i32>
+// CHECK: [[TMP76:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP77:%.*]] = bitcast <8 x i64> [[TMP76]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP78:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP79:%.*]] = bitcast <8 x i64> [[TMP78]] to <16 x i32>
+// CHECK: [[TMP80:%.*]] = icmp ult <16 x i32> [[TMP75]], [[TMP77]]
+// CHECK: [[TMP81:%.*]] = select <16 x i1> [[TMP80]], <16 x i32> [[TMP75]], <16 x i32> [[TMP77]]
+// CHECK: [[TMP82:%.*]] = bitcast <16 x i32> [[TMP81]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP82]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP83:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP84:%.*]] = bitcast <8 x i64> [[TMP83]] to <16 x i32>
+// CHECK: [[TMP85:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP86:%.*]] = bitcast <8 x i64> [[TMP85]] to <16 x i32>
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x i32> [[TMP84]], <16 x i32> [[TMP86]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP87:%.*]] = bitcast <16 x i32> [[SHUFFLE9_I]] to <8 x i64>
+// CHECK: [[TMP88:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP89:%.*]] = bitcast <8 x i64> [[TMP88]] to <16 x i32>
+// CHECK: [[TMP90:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP91:%.*]] = bitcast <8 x i64> [[TMP90]] to <16 x i32>
+// CHECK: [[SHUFFLE10_I:%.*]] = shufflevector <16 x i32> [[TMP89]], <16 x i32> [[TMP91]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: [[TMP92:%.*]] = bitcast <16 x i32> [[SHUFFLE10_I]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP87]], <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <8 x i64> [[TMP92]], <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP93:%.*]] = load <8 x i64>, <8 x i64>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP94:%.*]] = bitcast <8 x i64> [[TMP93]] to <16 x i32>
+// CHECK: [[TMP95:%.*]] = load <8 x i64>, <8 x i64>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP96:%.*]] = bitcast <8 x i64> [[TMP95]] to <16 x i32>
+// CHECK: store <8 x i64> zeroinitializer, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP97:%.*]] = load <8 x i64>, <8 x i64>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP98:%.*]] = bitcast <8 x i64> [[TMP97]] to <16 x i32>
+// CHECK: [[TMP99:%.*]] = icmp ult <16 x i32> [[TMP94]], [[TMP96]]
+// CHECK: [[TMP100:%.*]] = select <16 x i1> [[TMP99]], <16 x i32> [[TMP94]], <16 x i32> [[TMP96]]
+// CHECK: [[TMP101:%.*]] = bitcast <16 x i32> [[TMP100]] to <8 x i64>
+// CHECK: store <8 x i64> [[TMP101]], <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP102:%.*]] = load <8 x i64>, <8 x i64>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <8 x i64> [[TMP102]], i32 0
+// CHECK: [[CONV_I:%.*]] = trunc i64 [[VECEXT_I]] to i32
+// CHECK: ret i32 [[CONV_I]]
unsigned int test_mm512_mask_reduce_min_epu32(__mmask16 __M, __m512i __W){
- // CHECK: %tmp = bitcast <8 x i64> %__W to <16 x i32>
- // CHECK: %tmp1 = bitcast i16 %__M to <16 x i1>
- // CHECK: %tmp2 = select <16 x i1> %tmp1, <16 x i32> %tmp, <16 x i32> <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1>
- // CHECK: %shuffle1.i = shufflevector <16 x i32> %tmp2, <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: %tmp3 = icmp ult <16 x i32> %tmp2, %shuffle1.i
- // CHECK: %tmp4 = select <16 x i1> %tmp3, <16 x i32> %tmp2, <16 x i32> %shuffle1.i
- // CHECK: %shuffle4.i = shufflevector <16 x i32> %tmp4, <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: %tmp5 = icmp ult <16 x i32> %tmp4, %shuffle4.i
- // CHECK: %tmp6 = select <16 x i1> %tmp5, <16 x i32> %tmp4, <16 x i32> %shuffle4.i
- // CHECK: %shuffle7.i = shufflevector <16 x i32> %tmp6, <16 x i32> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp7 = icmp ult <16 x i32> %tmp6, %shuffle7.i
- // CHECK: %tmp8 = select <16 x i1> %tmp7, <16 x i32> %tmp6, <16 x i32> %shuffle7.i
- // CHECK: %shuffle10.i = shufflevector <16 x i32> %tmp8, <16 x i32> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp9 = icmp ult <16 x i32> %tmp8, %shuffle10.i
- // CHECK: %tmp10 = select <16 x i1> %tmp9, <16 x i32> %tmp8, <16 x i32> %shuffle10.i
- // CHECK: %tmp11 = bitcast <16 x i32> %tmp10 to <8 x i64>
- // CHECK: %vecext.i = extractelement <8 x i64> %tmp11, i32 0
- // CHECK: %conv.i = trunc i64 %vecext.i to i32
- // CHECK: ret i32 %conv.i
return _mm512_mask_reduce_min_epu32(__M, __W);
}
+// CHECK-LABEL: define float @test_mm512_mask_reduce_min_ps(i16 zeroext %__M, <16 x float> %__W) #0 {
+// CHECK: [[_COMPOUNDLITERAL_I_I18_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I19_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I20_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I15_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I16_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I17_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I12_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I13_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I14_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[_COMPOUNDLITERAL_I_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__A_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__B_ADDR_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__W_ADDR_I_I:%.*]] = alloca float, align 4
+// CHECK: [[_COMPOUNDLITERAL_I_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__M_ADDR_I:%.*]] = alloca i16, align 2
+// CHECK: [[__V_ADDR_I:%.*]] = alloca <16 x float>, align 64
+// CHECK: [[__M_ADDR:%.*]] = alloca i16, align 2
+// CHECK: [[__W_ADDR:%.*]] = alloca <16 x float>, align 64
+// CHECK: store i16 %__M, i16* [[__M_ADDR]], align 2
+// CHECK: store <16 x float> %__W, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: [[TMP0:%.*]] = load i16, i16* [[__M_ADDR]], align 2
+// CHECK: [[TMP1:%.*]] = load <16 x float>, <16 x float>* [[__W_ADDR]], align 64
+// CHECK: store i16 [[TMP0]], i16* [[__M_ADDR_I]], align 2
+// CHECK: store <16 x float> [[TMP1]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP2:%.*]] = load i16, i16* [[__M_ADDR_I]], align 2
+// CHECK: [[TMP3:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: store float 0x7FF0000000000000, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[TMP4:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT_I_I:%.*]] = insertelement <16 x float> undef, float [[TMP4]], i32 0
+// CHECK: [[TMP5:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT1_I_I:%.*]] = insertelement <16 x float> [[VECINIT_I_I]], float [[TMP5]], i32 1
+// CHECK: [[TMP6:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT2_I_I:%.*]] = insertelement <16 x float> [[VECINIT1_I_I]], float [[TMP6]], i32 2
+// CHECK: [[TMP7:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT3_I_I:%.*]] = insertelement <16 x float> [[VECINIT2_I_I]], float [[TMP7]], i32 3
+// CHECK: [[TMP8:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT4_I_I:%.*]] = insertelement <16 x float> [[VECINIT3_I_I]], float [[TMP8]], i32 4
+// CHECK: [[TMP9:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT5_I_I:%.*]] = insertelement <16 x float> [[VECINIT4_I_I]], float [[TMP9]], i32 5
+// CHECK: [[TMP10:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT6_I_I:%.*]] = insertelement <16 x float> [[VECINIT5_I_I]], float [[TMP10]], i32 6
+// CHECK: [[TMP11:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT7_I_I:%.*]] = insertelement <16 x float> [[VECINIT6_I_I]], float [[TMP11]], i32 7
+// CHECK: [[TMP12:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT8_I_I:%.*]] = insertelement <16 x float> [[VECINIT7_I_I]], float [[TMP12]], i32 8
+// CHECK: [[TMP13:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT9_I_I:%.*]] = insertelement <16 x float> [[VECINIT8_I_I]], float [[TMP13]], i32 9
+// CHECK: [[TMP14:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT10_I_I:%.*]] = insertelement <16 x float> [[VECINIT9_I_I]], float [[TMP14]], i32 10
+// CHECK: [[TMP15:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT11_I_I:%.*]] = insertelement <16 x float> [[VECINIT10_I_I]], float [[TMP15]], i32 11
+// CHECK: [[TMP16:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT12_I_I:%.*]] = insertelement <16 x float> [[VECINIT11_I_I]], float [[TMP16]], i32 12
+// CHECK: [[TMP17:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT13_I_I:%.*]] = insertelement <16 x float> [[VECINIT12_I_I]], float [[TMP17]], i32 13
+// CHECK: [[TMP18:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT14_I_I:%.*]] = insertelement <16 x float> [[VECINIT13_I_I]], float [[TMP18]], i32 14
+// CHECK: [[TMP19:%.*]] = load float, float* [[__W_ADDR_I_I]], align 4
+// CHECK: [[VECINIT15_I_I:%.*]] = insertelement <16 x float> [[VECINIT14_I_I]], float [[TMP19]], i32 15
+// CHECK: store <16 x float> [[VECINIT15_I_I]], <16 x float>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP20:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I]], align 64
+// CHECK: [[TMP21:%.*]] = bitcast i16 [[TMP2]] to <16 x i1>
+// CHECK: [[TMP22:%.*]] = select <16 x i1> [[TMP21]], <16 x float> [[TMP3]], <16 x float> [[TMP20]]
+// CHECK: store <16 x float> [[TMP22]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP23:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP24:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <16 x float> [[TMP23]], <16 x float> [[TMP24]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
+// CHECK: [[TMP25:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP26:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE1_I:%.*]] = shufflevector <16 x float> [[TMP25]], <16 x float> [[TMP26]], <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: store <16 x float> [[SHUFFLE_I]], <16 x float>* [[__A_ADDR_I19_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE1_I]], <16 x float>* [[__B_ADDR_I20_I]], align 64
+// CHECK: [[TMP27:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I19_I]], align 64
+// CHECK: [[TMP28:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I20_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP29:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I18_I]], align 64
+// CHECK: [[TMP30:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP27]], <16 x float> [[TMP28]], <16 x float> [[TMP29]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP30]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP31:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP32:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE3_I:%.*]] = shufflevector <16 x float> [[TMP31]], <16 x float> [[TMP32]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, 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: [[TMP33:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP34:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE4_I:%.*]] = shufflevector <16 x float> [[TMP33]], <16 x float> [[TMP34]], <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: store <16 x float> [[SHUFFLE3_I]], <16 x float>* [[__A_ADDR_I16_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE4_I]], <16 x float>* [[__B_ADDR_I17_I]], align 64
+// CHECK: [[TMP35:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I16_I]], align 64
+// CHECK: [[TMP36:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I17_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP37:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I15_I]], align 64
+// CHECK: [[TMP38:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP35]], <16 x float> [[TMP36]], <16 x float> [[TMP37]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP38]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP39:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP40:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE6_I:%.*]] = shufflevector <16 x float> [[TMP39]], <16 x float> [[TMP40]], <16 x i32> <i32 0, i32 1, i32 undef, i32 undef, 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: [[TMP41:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP42:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE7_I:%.*]] = shufflevector <16 x float> [[TMP41]], <16 x float> [[TMP42]], <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE6_I]], <16 x float>* [[__A_ADDR_I13_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE7_I]], <16 x float>* [[__B_ADDR_I14_I]], align 64
+// CHECK: [[TMP43:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I13_I]], align 64
+// CHECK: [[TMP44:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I14_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP45:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I12_I]], align 64
+// CHECK: [[TMP46:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP43]], <16 x float> [[TMP44]], <16 x float> [[TMP45]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP46]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP47:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP48:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE9_I:%.*]] = shufflevector <16 x float> [[TMP47]], <16 x float> [[TMP48]], <16 x i32> <i32 0, i32 undef, i32 undef, i32 undef, 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: [[TMP49:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP50:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[SHUFFLE10_I:%.*]] = shufflevector <16 x float> [[TMP49]], <16 x float> [[TMP50]], <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: store <16 x float> [[SHUFFLE9_I]], <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: store <16 x float> [[SHUFFLE10_I]], <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: [[TMP51:%.*]] = load <16 x float>, <16 x float>* [[__A_ADDR_I_I]], align 64
+// CHECK: [[TMP52:%.*]] = load <16 x float>, <16 x float>* [[__B_ADDR_I_I]], align 64
+// CHECK: store <16 x float> zeroinitializer, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP53:%.*]] = load <16 x float>, <16 x float>* [[_COMPOUNDLITERAL_I_I_I]], align 64
+// CHECK: [[TMP54:%.*]] = call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> [[TMP51]], <16 x float> [[TMP52]], <16 x float> [[TMP53]], i16 -1, i32 4) #2
+// CHECK: store <16 x float> [[TMP54]], <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[TMP55:%.*]] = load <16 x float>, <16 x float>* [[__V_ADDR_I]], align 64
+// CHECK: [[VECEXT_I:%.*]] = extractelement <16 x float> [[TMP55]], i32 0
+// CHECK: ret float [[VECEXT_I]]
float test_mm512_mask_reduce_min_ps(__mmask16 __M, __m512 __W){
- // CHECK: %tmp = bitcast i16 %__M to <16 x i1>
- // CHECK: %tmp1 = select <16 x i1> %tmp, <16 x float> %__W, <16 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000, float 0x7FF0000000000000>
- // CHECK: %shuffle1.i = shufflevector <16 x float> %tmp1, <16 x float> 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: %tmp2 = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %tmp1, <16 x float> %shuffle1.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle4.i = shufflevector <16 x float> %tmp2, <16 x float> 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 = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %tmp2, <16 x float> %shuffle4.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle7.i = shufflevector <16 x float> %tmp3, <16 x float> undef, <16 x i32> <i32 2, i32 3, i32 undef, i32 undef, 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: %tmp4 = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %tmp3, <16 x float> %shuffle7.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %shuffle10.i = shufflevector <16 x float> %tmp4, <16 x float> undef, <16 x i32> <i32 1, i32 undef, i32 undef, i32 undef, 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: %tmp5 = tail call <16 x float> @llvm.x86.avx512.mask.min.ps.512(<16 x float> %tmp4, <16 x float> %shuffle10.i, <16 x float> zeroinitializer, i16 -1, i32 4) #3
- // CHECK: %vecext.i = extractelement <16 x float> %tmp5, i32 0
- // CHECK: ret float %vecext.i
return _mm512_mask_reduce_min_ps(__M, __W);
}
diff --git a/test/CodeGen/avx512bw-builtins.c b/test/CodeGen/avx512bw-builtins.c
index 4d45f29f14..eb7b2a5cb5 100644
--- a/test/CodeGen/avx512bw-builtins.c
+++ b/test/CodeGen/avx512bw-builtins.c
@@ -480,32 +480,48 @@ __m512i test_mm512_mask_blend_epi16(__mmask32 __U, __m512i __A, __m512i __W) {
}
__m512i test_mm512_abs_epi8(__m512i __A) {
// CHECK-LABEL: @test_mm512_abs_epi8
- // CHECK: @llvm.x86.avx512.mask.pabs.b.512
+ // CHECK: [[SUB:%.*]] = sub <64 x i8> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <64 x i8> [[A]], zeroinitializer
+ // CHECK: select <64 x i1> [[CMP]], <64 x i8> [[A]], <64 x i8> [[SUB]]
return _mm512_abs_epi8(__A);
}
__m512i test_mm512_mask_abs_epi8(__m512i __W, __mmask64 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_mask_abs_epi8
- // CHECK: @llvm.x86.avx512.mask.pabs.b.512
+ // CHECK: [[SUB:%.*]] = sub <64 x i8> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <64 x i8> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <64 x i1> [[CMP]], <64 x i8> [[A]], <64 x i8> [[SUB]]
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> [[SEL]], <64 x i8> %{{.*}}
return _mm512_mask_abs_epi8(__W,__U,__A);
}
__m512i test_mm512_maskz_abs_epi8(__mmask64 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_maskz_abs_epi8
- // CHECK: @llvm.x86.avx512.mask.pabs.b.512
+ // CHECK: [[SUB:%.*]] = sub <64 x i8> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <64 x i8> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <64 x i1> [[CMP]], <64 x i8> [[A]], <64 x i8> [[SUB]]
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> [[SEL]], <64 x i8> %{{.*}}
return _mm512_maskz_abs_epi8(__U,__A);
}
__m512i test_mm512_abs_epi16(__m512i __A) {
// CHECK-LABEL: @test_mm512_abs_epi16
- // CHECK: @llvm.x86.avx512.mask.pabs.w.512
+ // CHECK: [[SUB:%.*]] = sub <32 x i16> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <32 x i16> [[A]], zeroinitializer
+ // CHECK: select <32 x i1> [[CMP]], <32 x i16> [[A]], <32 x i16> [[SUB]]
return _mm512_abs_epi16(__A);
}
__m512i test_mm512_mask_abs_epi16(__m512i __W, __mmask32 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_mask_abs_epi16
- // CHECK: @llvm.x86.avx512.mask.pabs.w.512
+ // CHECK: [[SUB:%.*]] = sub <32 x i16> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <32 x i16> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <32 x i1> [[CMP]], <32 x i16> [[A]], <32 x i16> [[SUB]]
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> [[SEL]], <32 x i16> %{{.*}}
return _mm512_mask_abs_epi16(__W,__U,__A);
}
__m512i test_mm512_maskz_abs_epi16(__mmask32 __U, __m512i __A) {
// CHECK-LABEL: @test_mm512_maskz_abs_epi16
- // CHECK: @llvm.x86.avx512.mask.pabs.w.512
+ // CHECK: [[SUB:%.*]] = sub <32 x i16> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <32 x i16> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <32 x i1> [[CMP]], <32 x i16> [[A]], <32 x i16> [[SUB]]
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> [[SEL]], <32 x i16> %{{.*}}
return _mm512_maskz_abs_epi16(__U,__A);
}
__m512i test_mm512_packs_epi32(__m512i __A, __m512i __B) {
@@ -638,32 +654,74 @@ __m512i test_mm512_maskz_adds_epu16(__mmask32 __U, __m512i __A, __m512i __B) {
}
__m512i test_mm512_avg_epu8(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_avg_epu8
- // CHECK: @llvm.x86.avx512.mask.pavg.b.512
+ // CHECK-NOT: @llvm.x86.avx512.mask.pavg.b.512
+ // CHECK: zext <64 x i8> %{{.*}} to <64 x i16>
+ // CHECK: zext <64 x i8> %{{.*}} to <64 x i16>
+ // CHECK: add <64 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <64 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <64 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <64 x i16> %{{.*}} to <64 x i8>
return _mm512_avg_epu8(__A,__B);
}
__m512i test_mm512_mask_avg_epu8(__m512i __W, __mmask64 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_avg_epu8
- // CHECK: @llvm.x86.avx512.mask.pavg.b.512
+ // CHECK-NOT: @llvm.x86.avx512.mask.pavg.b.512
+ // CHECK: zext <64 x i8> %{{.*}} to <64 x i16>
+ // CHECK: zext <64 x i8> %{{.*}} to <64 x i16>
+ // CHECK: add <64 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <64 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <64 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <64 x i16> %{{.*}} to <64 x i8>
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_mask_avg_epu8(__W,__U,__A,__B);
}
__m512i test_mm512_maskz_avg_epu8(__mmask64 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_avg_epu8
- // CHECK: @llvm.x86.avx512.mask.pavg.b.512
+ // CHECK-NOT: @llvm.x86.avx512.mask.pavg.b.512
+ // CHECK: zext <64 x i8> %{{.*}} to <64 x i16>
+ // CHECK: zext <64 x i8> %{{.*}} to <64 x i16>
+ // CHECK: add <64 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <64 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <64 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <64 x i16> %{{.*}} to <64 x i8>
+ // CHECK: store <64 x i8> zeroinitializer
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_maskz_avg_epu8(__U,__A,__B);
}
__m512i test_mm512_avg_epu16(__m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_avg_epu16
- // CHECK: @llvm.x86.avx512.mask.pavg.w.512
+ // CHECK-NOT: @llvm.x86.avx512.mask.pavg.w.512
+ // CHECK: zext <32 x i16> %{{.*}} to <32 x i32>
+ // CHECK: zext <32 x i16> %{{.*}} to <32 x i32>
+ // CHECK: add <32 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <32 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <32 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <32 x i32> %{{.*}} to <32 x i16>
return _mm512_avg_epu16(__A,__B);
}
__m512i test_mm512_mask_avg_epu16(__m512i __W, __mmask32 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_mask_avg_epu16
- // CHECK: @llvm.x86.avx512.mask.pavg.w.512
+ // CHECK-NOT: @llvm.x86.avx512.mask.pavg.w.512
+ // CHECK: zext <32 x i16> %{{.*}} to <32 x i32>
+ // CHECK: zext <32 x i16> %{{.*}} to <32 x i32>
+ // CHECK: add <32 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <32 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <32 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <32 x i32> %{{.*}} to <32 x i16>
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_mask_avg_epu16(__W,__U,__A,__B);
}
__m512i test_mm512_maskz_avg_epu16(__mmask32 __U, __m512i __A, __m512i __B) {
// CHECK-LABEL: @test_mm512_maskz_avg_epu16
- // CHECK: @llvm.x86.avx512.mask.pavg.w.512
+ // CHECK-NOT: @llvm.x86.avx512.mask.pavg.w.512
+ // CHECK: zext <32 x i16> %{{.*}} to <32 x i32>
+ // CHECK: zext <32 x i16> %{{.*}} to <32 x i32>
+ // CHECK: add <32 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <32 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <32 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <32 x i32> %{{.*}} to <32 x i16>
+ // CHECK: store <32 x i16> zeroinitializer
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_avg_epu16(__U,__A,__B);
}
__m512i test_mm512_max_epi8(__m512i __A, __m512i __B) {
@@ -1432,13 +1490,139 @@ __m512i test_mm512_maskz_mov_epi8(__mmask64 __U, __m512i __A) {
__m512i test_mm512_mask_set1_epi8(__m512i __O, __mmask64 __M, char __A) {
// CHECK-LABEL: @test_mm512_mask_set1_epi8
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.b.gpr.512
+ // CHECK: insertelement <64 x i8> undef, i8 %{{.*}}, i32 0
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 1
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 2
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 3
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 4
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 5
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 6
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 7
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 8
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 9
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 10
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 11
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 12
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 13
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 14
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 15
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 16
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 17
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 18
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 19
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 20
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 21
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 22
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 23
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 24
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 25
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 26
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 27
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 28
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 29
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 30
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 31
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 34
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 35
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 36
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 37
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 38
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 39
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 40
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 41
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 42
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 43
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 44
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 45
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 46
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 47
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 48
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 49
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 50
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 51
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 52
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 53
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 54
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 55
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 56
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 57
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 58
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 59
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 60
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 61
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 62
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 63
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_mask_set1_epi8(__O, __M, __A);
}
__m512i test_mm512_maskz_set1_epi8(__mmask64 __M, char __A) {
// CHECK-LABEL: @test_mm512_maskz_set1_epi8
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.b.gpr.512
+ // CHECK: insertelement <64 x i8> undef, i8 %{{.*}}, i32 0
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 1
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 2
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 3
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 4
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 5
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 6
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 7
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 8
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 9
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 10
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 11
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 12
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 13
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 14
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 15
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 16
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 17
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 18
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 19
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 20
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 21
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 22
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 23
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 24
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 25
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 26
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 27
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 28
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 29
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 30
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 31
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 32
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 33
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 34
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 35
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 36
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 37
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 38
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 39
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 40
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 41
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 42
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 43
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 44
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 45
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 46
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 47
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 48
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 49
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 50
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 51
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 52
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 53
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 54
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 55
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 56
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 57
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 58
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 59
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 60
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 61
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 62
+ // CHECK: insertelement <64 x i8> %{{.*}}, i8 %{{.*}}, i32 63
+ // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}}
return _mm512_maskz_set1_epi8(__M, __A);
}
@@ -1543,13 +1727,15 @@ __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);
}
@@ -1595,13 +1781,77 @@ __m512i test_mm512_maskz_broadcastw_epi16(__mmask32 __M, __m128i __A) {
__m512i test_mm512_mask_set1_epi16(__m512i __O, __mmask32 __M, short __A) {
// CHECK-LABEL: @test_mm512_mask_set1_epi16
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.w.gpr.512
+ // CHECK: insertelement <32 x i16> undef, i16 %{{.*}}, i32 0
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 1
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 2
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 3
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 4
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 5
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 6
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 7
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 8
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 9
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 10
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 11
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 12
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 13
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 14
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 15
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 16
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 17
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 18
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 19
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 20
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 21
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 22
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 23
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 24
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 25
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 26
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 27
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 28
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 29
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 30
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 31
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_mask_set1_epi16(__O, __M, __A);
}
__m512i test_mm512_maskz_set1_epi16(__mmask32 __M, short __A) {
// CHECK-LABEL: @test_mm512_maskz_set1_epi16
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.w.gpr.512
+ // CHECK: insertelement <32 x i16> undef, i16 %{{.*}}, i32 0
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 1
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 2
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 3
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 4
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 5
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 6
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 7
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 8
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 9
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 10
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 11
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 12
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 13
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 14
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 15
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 16
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 17
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 18
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 19
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 20
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 21
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 22
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 23
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 24
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 25
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 26
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 27
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 28
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 29
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 30
+ // CHECK: insertelement <32 x i16> %{{.*}}, i16 %{{.*}}, i32 31
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_set1_epi16(__M, __A);
}
__m512i test_mm512_permutexvar_epi16(__m512i __A, __m512i __B) {
@@ -1677,19 +1927,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 b4166ad7c4..1b21ca3c43 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);
}
@@ -947,19 +949,21 @@ __mmask8 test_mm512_movepi64_mask(__m512i __A) {
__m512 test_mm512_broadcast_f32x2(__m128 __A) {
// CHECK-LABEL: @test_mm512_broadcast_f32x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x2
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
return _mm512_broadcast_f32x2(__A);
}
__m512 test_mm512_mask_broadcast_f32x2(__m512 __O, __mmask16 __M, __m128 __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_f32x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x2
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
return _mm512_mask_broadcast_f32x2(__O, __M, __A);
}
__m512 test_mm512_maskz_broadcast_f32x2(__mmask16 __M, __m128 __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_f32x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x2
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x float> %{{.*}}, <16 x float> %{{.*}}
return _mm512_maskz_broadcast_f32x2(__M, __A);
}
@@ -1005,19 +1009,21 @@ __m512d test_mm512_maskz_broadcast_f64x2(__mmask8 __M, double const* __A) {
__m512i test_mm512_broadcast_i32x2(__m128i __A) {
// CHECK-LABEL: @test_mm512_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
return _mm512_broadcast_i32x2(__A);
}
__m512i test_mm512_mask_broadcast_i32x2(__m512i __O, __mmask16 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_mask_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
return _mm512_mask_broadcast_i32x2(__O, __M, __A);
}
__m512i test_mm512_maskz_broadcast_i32x2(__mmask16 __M, __m128i __A) {
// CHECK-LABEL: @test_mm512_maskz_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
return _mm512_maskz_broadcast_i32x2(__M, __A);
}
diff --git a/test/CodeGen/avx512f-builtins.c b/test/CodeGen/avx512f-builtins.c
index 67e2d4389e..b154bca7cb 100644
--- a/test/CodeGen/avx512f-builtins.c
+++ b/test/CodeGen/avx512f-builtins.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +avx512f -emit-llvm -o - -Wall -Werror | FileCheck %s
-// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +avx512f -O2 -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=O2
#include <immintrin.h>
@@ -6251,7 +6250,13 @@ 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);
+}
+
+__m512i test_mm512_stream_load_si512_const(void const *__P) {
+ // CHECK-LABEL: @test_mm512_stream_load_si512_const
+ // CHECK: load <8 x i64>, <8 x i64>* %{{.*}}, align 64, !nontemporal
return _mm512_stream_load_si512(__P);
}
@@ -7259,6 +7264,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
@@ -7707,11 +7724,178 @@ __m512i test_mm512_maskz_min_epu64 (__mmask8 __M, __m512i __A, __m512i __B)
__m512i test_mm512_mask_set1_epi32 (__m512i __O, __mmask16 __M, int __A)
{
- //CHECK-LABEL: @test_mm512_mask_set1_epi32
- //CHECK: @llvm.x86.avx512.mask.pbroadcast.d.gpr.512
+ // CHECK-LABEL: @test_mm512_mask_set1_epi32
+ // CHECK: insertelement <16 x i32> undef, i32 %{{.*}}, i32 0
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 1
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 2
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 3
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 4
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 5
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 6
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 7
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 8
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 9
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 10
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 11
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 12
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 13
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 14
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 15
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
return _mm512_mask_set1_epi32 ( __O, __M, __A);
}
+__m512i test_mm512_maskz_set1_epi32(__mmask16 __M, int __A)
+{
+ // CHECK-LABEL: @test_mm512_maskz_set1_epi32
+ // CHECK: insertelement <16 x i32> undef, i32 %{{.*}}, i32 0
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 1
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 2
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 3
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 4
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 5
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 6
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 7
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 8
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 9
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 10
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 11
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 12
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 13
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 14
+ // CHECK: insertelement <16 x i32> %{{.*}}, i32 %{{.*}}, i32 15
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
+ return _mm512_maskz_set1_epi32(__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,
@@ -7719,21 +7903,21 @@ __m512i test_mm512_set_epi32 (int __A, int __B, int __C, int __D,
{
//CHECK-LABEL: @test_mm512_set_epi32
//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 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
return _mm512_set_epi32( __A, __B, __C, __D,__E, __F, __G, __H,
__I, __J, __K, __L,__M, __N, __O, __P);
}
@@ -7743,39 +7927,39 @@ __m512i test_mm512_setr_epi32 (int __A, int __B, int __C, int __D,
int __I, int __J, int __K, int __L,
int __M, int __N, int __O, int __P)
{
- //CHECK-LABEL: @test_mm512_setr_epi32
- //CHECK: load{{.*}}%__P.addr, align 4
- //CHECK: load{{.*}}%__O.addr, align 4
- //CHECK: load{{.*}}%__N.addr, align 4
- //CHECK: load{{.*}}%__M.addr, align 4
- //CHECK: load{{.*}}%__L.addr, align 4
- //CHECK: load{{.*}}%__K.addr, align 4
- //CHECK: load{{.*}}%__J.addr, align 4
- //CHECK: load{{.*}}%__I.addr, align 4
- //CHECK: load{{.*}}%__H.addr, align 4
- //CHECK: load{{.*}}%__G.addr, align 4
- //CHECK: load{{.*}}%__F.addr, align 4
- //CHECK: load{{.*}}%__E.addr, align 4
- //CHECK: load{{.*}}%__D.addr, align 4
- //CHECK: load{{.*}}%__C.addr, align 4
- //CHECK: load{{.*}}%__B.addr, align 4
- //CHECK: load{{.*}}%__A.addr, align 4
- //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-LABEL: @test_mm512_setr_epi32
+ //CHECK: load{{.*}}%__P.addr, align 4
+ //CHECK: load{{.*}}%__O.addr, align 4
+ //CHECK: load{{.*}}%__N.addr, align 4
+ //CHECK: load{{.*}}%__M.addr, align 4
+ //CHECK: load{{.*}}%__L.addr, align 4
+ //CHECK: load{{.*}}%__K.addr, align 4
+ //CHECK: load{{.*}}%__J.addr, align 4
+ //CHECK: load{{.*}}%__I.addr, align 4
+ //CHECK: load{{.*}}%__H.addr, align 4
+ //CHECK: load{{.*}}%__G.addr, align 4
+ //CHECK: load{{.*}}%__F.addr, align 4
+ //CHECK: load{{.*}}%__E.addr, align 4
+ //CHECK: load{{.*}}%__D.addr, align 4
+ //CHECK: load{{.*}}%__C.addr, align 4
+ //CHECK: load{{.*}}%__B.addr, align 4
+ //CHECK: load{{.*}}%__A.addr, align 4
+ //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
return _mm512_setr_epi32( __A, __B, __C, __D,__E, __F, __G, __H,
__I, __J, __K, __L,__M, __N, __O, __P);
}
@@ -7783,12 +7967,36 @@ __m512i test_mm512_setr_epi32 (int __A, int __B, int __C, int __D,
#ifdef __x86_64__
__m512i test_mm512_mask_set1_epi64 (__m512i __O, __mmask8 __M, long long __A)
{
- //CHECK-LABEL: @test_mm512_mask_set1_epi64
- //CHECK: @llvm.x86.avx512.mask.pbroadcast.q.gpr.512
+ // CHECK-LABEL: @test_mm512_mask_set1_epi64
+ // CHECK: insertelement <8 x i64> undef, i64 %{{.*}}, i32 0
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 1
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 2
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 3
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 4
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 5
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 6
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 7
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
return _mm512_mask_set1_epi64 (__O, __M, __A);
}
+
+__m512i test_mm512_maskz_set1_epi64 (__mmask8 __M, long long __A)
+{
+ // CHECK-LABEL: @test_mm512_maskz_set1_epi64
+ // CHECK: insertelement <8 x i64> undef, i64 %{{.*}}, i32 0
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 1
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 2
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 3
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 4
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 5
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 6
+ // CHECK: insertelement <8 x i64> %{{.*}}, i64 %{{.*}}, i32 7
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}}
+ return _mm512_maskz_set1_epi64 (__M, __A);
+}
#endif
+
__m512i test_mm512_set_epi64 (long long __A, long long __B, long long __C,
long long __D, long long __E, long long __F,
long long __G, long long __H)
@@ -7896,28 +8104,40 @@ __m512 test_mm512_set_ps (float __A, float __B, float __C, float __D,
__m512i test_mm512_mask_abs_epi64 (__m512i __W, __mmask8 __U, __m512i __A)
{
// CHECK-LABEL: @test_mm512_mask_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.512
+ // CHECK: [[SUB:%.*]] = sub <8 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <8 x i64> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x i64> [[A]], <8 x i64> [[SUB]]
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> [[SEL]], <8 x i64> %{{.*}}
return _mm512_mask_abs_epi64 (__W,__U,__A);
}
__m512i test_mm512_maskz_abs_epi64 (__mmask8 __U, __m512i __A)
{
// CHECK-LABEL: @test_mm512_maskz_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.512
+ // CHECK: [[SUB:%.*]] = sub <8 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <8 x i64> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x i64> [[A]], <8 x i64> [[SUB]]
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i64> [[SEL]], <8 x i64> %{{.*}}
return _mm512_maskz_abs_epi64 (__U,__A);
}
__m512i test_mm512_mask_abs_epi32 (__m512i __W, __mmask16 __U, __m512i __A)
{
// CHECK-LABEL: @test_mm512_mask_abs_epi32
- // CHECK: @llvm.x86.avx512.mask.pabs.d.512
+ // CHECK: [[SUB:%.*]] = sub <16 x i32> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <16 x i32> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <16 x i1> [[CMP]], <16 x i32> [[A]], <16 x i32> [[SUB]]
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> [[SEL]], <16 x i32> %{{.*}}
return _mm512_mask_abs_epi32 (__W,__U,__A);
}
__m512i test_mm512_maskz_abs_epi32 (__mmask16 __U, __m512i __A)
{
// CHECK-LABEL: @test_mm512_maskz_abs_epi32
- // CHECK: @llvm.x86.avx512.mask.pabs.d.512
+ // CHECK: [[SUB:%.*]] = sub <16 x i32> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <16 x i32> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <16 x i1> [[CMP]], <16 x i32> [[A]], <16 x i32> [[SUB]]
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i32> [[SEL]], <16 x i32> %{{.*}}
return _mm512_maskz_abs_epi32 (__U,__A);
}
@@ -8085,138 +8305,95 @@ __m512d test_mm512_setzero_pd()
__mmask16 test_mm512_int2mask(int __a)
{
- // O2-LABEL: test_mm512_int2mask
- // O2: trunc i32 %__a to i16
+ // CHECK-LABEL: test_mm512_int2mask
+ // CHECK: trunc i32 %{{.*}} to i16
return _mm512_int2mask(__a);
}
int test_mm512_mask2int(__mmask16 __a)
{
- // O2-LABEL: test_mm512_mask2int
- // O2: zext i16 %__a to i32
+ // CHECK-LABEL: test_mm512_mask2int
+ // CHECK: zext i16 %{{.*}} to i32
return _mm512_mask2int(__a);
}
__m128 test_mm_mask_move_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B)
{
- // O2-LABEL: @test_mm_mask_move_ss
- // O2: %[[M:.*]] = and i8 %__U, 1
- // O2: %[[M2:.*]] = icmp ne i8 %[[M]], 0
- // O2: %[[ELM1:.*]] = extractelement <4 x float> %__B, i32 0
- // O2: %[[ELM2:.*]] = extractelement <4 x float> %__W, i32 0
- // O2: %[[SEL:.*]] = select i1 %[[M2]], float %[[ELM1]], float %[[ELM2]]
- // O2: %[[RES:.*]] = insertelement <4 x float> %__A, float %[[SEL]], i32 0
- // O2: ret <4 x float> %[[RES]]
+ // CHECK-LABEL: @test_mm_mask_move_ss
+ // CHECK: extractelement <4 x float> %{{.*}}, i32 0
+ // CHECK: extractelement <4 x float> %{{.*}}, i32 0
+ // CHECK: phi float [ %{{.*}}, %{{.*}} ], [ %{{.*}}, %{{.*}} ]
+ // CHECK: insertelement <4 x float> %{{.*}}, float %cond.i, i32 0
return _mm_mask_move_ss ( __W, __U, __A, __B);
}
__m128 test_mm_maskz_move_ss (__mmask8 __U, __m128 __A, __m128 __B)
{
- // O2-LABEL: @test_mm_maskz_move_ss
- // O2: %[[M:.*]] = and i8 %__U, 1
- // O2: %[[M2:.*]] = icmp ne i8 %[[M]], 0
- // O2: %[[ELM1:.*]] = extractelement <4 x float> %__B, i32 0
- // O2: %[[SEL:.*]] = select i1 %[[M2]], float %[[ELM1]], float 0.0
- // O2: %[[RES:.*]] = insertelement <4 x float> %__A, float %[[SEL]], i32 0
- // O2: ret <4 x float> %[[RES]]
+ // CHECK-LABEL: @test_mm_maskz_move_ss
+ // CHECK: extractelement <4 x float> %{{.*}}, i32 0
+ // CHECK: phi float [ %{{.*}}, %{{.*}} ], [ 0.000000e+00, %{{.*}} ]
+ // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0
return _mm_maskz_move_ss (__U, __A, __B);
}
__m128d test_mm_mask_move_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B)
{
- // O2-LABEL: @test_mm_mask_move_sd
- // O2: %[[M:.*]] = and i8 %__U, 1
- // O2: %[[M2:.*]] = icmp ne i8 %[[M]], 0
- // O2: %[[ELM1:.*]] = extractelement <2 x double> %__B, i32 0
- // O2: %[[ELM2:.*]] = extractelement <2 x double> %__W, i32 0
- // O2: %[[SEL:.*]] = select i1 %[[M2]], double %[[ELM1]], double %[[ELM2]]
- // O2: %[[RES:.*]] = insertelement <2 x double> %__A, double %[[SEL]], i32 0
- // O2: ret <2 x double> %[[RES]]
+ // CHECK-LABEL: @test_mm_mask_move_sd
+ // CHECK: extractelement <2 x double> %{{.*}}, i32 0
+ // CHECK: extractelement <2 x double> %{{.*}}, i32 0
+ // CHECK: phi double [ %{{.*}}, %{{.*}} ], [ %{{.*}}, %{{.*}} ]
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0
return _mm_mask_move_sd ( __W, __U, __A, __B);
}
__m128d test_mm_maskz_move_sd (__mmask8 __U, __m128d __A, __m128d __B)
{
- // O2-LABEL: @test_mm_maskz_move_sd
- // O2: %[[M:.*]] = and i8 %__U, 1
- // O2: %[[M2:.*]] = icmp ne i8 %[[M]], 0
- // O2: %[[ELM1:.*]] = extractelement <2 x double> %__B, i32 0
- // O2: %[[SEL:.*]] = select i1 %[[M2]], double %[[ELM1]], double 0.0
- // O2: %[[RES:.*]] = insertelement <2 x double> %__A, double %[[SEL]], i32 0
- // O2: ret <2 x double> %[[RES]]
+ // CHECK-LABEL: @test_mm_maskz_move_sd
+ // CHECK: extractelement <2 x double> %{{.*}}, i32 0
+ // CHECK: phi double [ %{{.*}}, %{{.*}} ], [ 0.000000e+00, %{{.*}} ]
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0
return _mm_maskz_move_sd (__U, __A, __B);
}
void test_mm_mask_store_ss(float * __P, __mmask8 __U, __m128 __A)
{
- // O2-LABEL: @test_mm_mask_store_ss
- // O2: %[[CAST:.*]] = bitcast float* %__P to <16 x float>*
- // O2: %[[SHUFFLE:.*]] = shufflevector <4 x float> %__A, <4 x float> undef, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // O2: %[[MASK1:.*]] = and i8 %__U, 1
- // O2: %[[MASK2:.*]] = zext i8 %[[MASK1]] to i16
- // O2: %[[MASK3:.*]] = bitcast i16 %[[MASK2]] to <16 x i1>
- // O2: tail call void @llvm.masked.store.v16f32.p0v16f32(<16 x float> %[[SHUFFLE]], <16 x float>* %[[CAST]], i32 16, <16 x i1> %[[MASK3]])
+ // CHECK-LABEL: @test_mm_mask_store_ss
+ // CHECK: call void @llvm.masked.store.v16f32.p0v16f32(
_mm_mask_store_ss(__P, __U, __A);
}
void test_mm_mask_store_sd(double * __P, __mmask8 __U, __m128d __A)
{
- // O2-LABEL: @test_mm_mask_store_sd
- // O2: %[[CAST:.*]] = bitcast double* %__P to <8 x double>*
- // O2: %[[SHUFFLE:.*]] = shufflevector <2 x double> %__A, <2 x double> undef, <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // O2: %[[MASK1:.*]] = and i8 %__U, 1
- // O2: %[[MASK2:.*]] = bitcast i8 %[[MASK1]] to <8 x i1>
- // O2: tail call void @llvm.masked.store.v8f64.p0v8f64(<8 x double> %[[SHUFFLE]], <8 x double>* %[[CAST]], i32 16, <8 x i1> %[[MASK2]])
+ // CHECK-LABEL: @test_mm_mask_store_sd
+ // CHECK: call void @llvm.masked.store.v8f64.p0v8f64(
_mm_mask_store_sd(__P, __U, __A);
}
__m128 test_mm_mask_load_ss(__m128 __A, __mmask8 __U, const float* __W)
{
- // O2-LABEL: @test_mm_mask_load_ss
- // O2: %[[SHUF:.*]] = shufflevector <4 x float> %__A, <4 x float> <float 0.000000e+00, float undef, float undef, float undef>, <4 x i32> <i32 0, i32 4, i32 4, i32 4>
- // O2: %[[PTR:.*]] = bitcast float* %__W to <16 x float>*
- // O2: %[[SHUF2:.*]] = shufflevector <4 x float> %[[SHUF]], <4 x float> undef, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // O2: %[[AND:.*]] = and i8 %__U, 1
- // O2: %[[MASK:.*]] = zext i8 %[[AND]] to i16
- // O2: %[[MASK2:.*]] = bitcast i16 %[[MASK]] to <16 x i1>
- // O2: %[[RES:.*]] = tail call <16 x float> @llvm.masked.load.v16f32.p0v16f32(<16 x float>* %[[PTR]], i32 16, <16 x i1> %[[MASK2]], <16 x float> %[[SHUF2]])
- // O2: shufflevector <16 x float> %[[RES]], <16 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK-LABEL: @test_mm_mask_load_ss
+ // CHECK: call <16 x float> @llvm.masked.load.v16f32.p0v16f32(
return _mm_mask_load_ss(__A, __U, __W);
}
__m128 test_mm_maskz_load_ss (__mmask8 __U, const float * __W)
{
- // O2-LABEL: @test_mm_maskz_load_ss
- // O2: %[[PTR:.*]] = bitcast float* %__W to <16 x float>*
- // O2: %[[AND:.*]] = and i8 %__U, 1
- // O2: %[[MASK:.*]] = zext i8 %[[AND]] to i16
- // O2: %[[MASK2:.*]] = bitcast i16 %[[MASK]] to <16 x i1>
- // O2: %[[RES:.*]] = tail call <16 x float> @llvm.masked.load.v16f32.p0v16f32(<16 x float>* %[[PTR]], i32 16, <16 x i1> %[[MASK2]], <16 x float> zeroinitializer)
- // O2: shufflevector <16 x float> %[[RES]], <16 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK-LABEL: @test_mm_maskz_load_ss
+ // CHECK: call <16 x float> @llvm.masked.load.v16f32.p0v16f32(
return _mm_maskz_load_ss (__U, __W);
}
__m128d test_mm_mask_load_sd (__m128d __A, __mmask8 __U, const double * __W)
{
- // O2-LABEL: @test_mm_mask_load_sd
- // O2: %[[SHUF:.*]] = insertelement <2 x double> %__A, double 0.000000e+00, i32 1
- // O2: %[[PTR:.*]] = bitcast double* %__W to <8 x double>*
- // O2: %[[SHUF2:.*]] = shufflevector <2 x double> %[[SHUF]], <2 x double> undef, <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
- // O2: %[[AND:.*]] = and i8 %__U, 1
- // O2: %[[MASK:.*]] = bitcast i8 %[[AND]] to <8 x i1>
- // O2: %[[RES:.*]] = tail call <8 x double> @llvm.masked.load.v8f64.p0v8f64(<8 x double>* %[[PTR]], i32 16, <8 x i1> %[[MASK]], <8 x double> %[[SHUF2]])
- // O2: shufflevector <8 x double> %[[RES]], <8 x double> undef, <2 x i32> <i32 0, i32 1>
+ // CHECK-LABEL: @test_mm_mask_load_sd
+ // CHECK: call <8 x double> @llvm.masked.load.v8f64.p0v8f64(
return _mm_mask_load_sd (__A, __U, __W);
}
__m128d test_mm_maskz_load_sd (__mmask8 __U, const double * __W)
{
- // O2-LABEL: @test_mm_maskz_load_sd
- // O2: %[[PTR:.*]] = bitcast double* %__W to <8 x double>*
- // O2: %[[AND:.*]] = and i8 %__U, 1
- // O2: %[[MASK:.*]] = bitcast i8 %[[AND]] to <8 x i1>
- // O2: %[[RES:.*]] = tail call <8 x double> @llvm.masked.load.v8f64.p0v8f64(<8 x double>* %[[PTR]], i32 16, <8 x i1> %[[MASK]], <8 x double> zeroinitializer)
- // O2: shufflevector <8 x double> %[[RES]], <8 x double> undef, <2 x i32> <i32 0, i32 1>
+ // CHECK-LABEL: @test_mm_maskz_load_sd
+ // CHECK: call <8 x double> @llvm.masked.load.v8f64.p0v8f64(
return _mm_maskz_load_sd (__U, __W);
}
@@ -8248,3 +8425,44 @@ __m512 test_mm512_mask_abs_ps(__m512 __W, __mmask16 __U, __m512 __A){
return _mm512_mask_abs_ps( __W, __U, __A);
}
+__m512d test_mm512_zextpd128_pd512(__m128d A) {
+ // CHECK-LABEL: test_mm512_zextpd128_pd512
+ // CHECK: store <2 x double> zeroinitializer
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 2, i32 3, i32 2, i32 3>
+ return _mm512_zextpd128_pd512(A);
+}
+
+__m512d test_mm512_zextpd256_pd512(__m256d A) {
+ // CHECK-LABEL: test_mm512_zextpd256_pd512
+ // CHECK: store <4 x double> zeroinitializer
+ // CHECK: shufflevector <4 x double> %{{.*}}, <4 x double> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return _mm512_zextpd256_pd512(A);
+}
+
+__m512 test_mm512_zextps128_ps512(__m128 A) {
+ // CHECK-LABEL: test_mm512_zextps128_ps512
+ // CHECK: store <4 x float> zeroinitializer
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 4, i32 5, i32 6, i32 7, i32 4, i32 5, i32 6, i32 7>
+ return _mm512_zextps128_ps512(A);
+}
+
+__m512 test_mm512_zextps256_ps512(__m256 A) {
+ // CHECK-LABEL: test_mm512_zextps256_ps512
+ // CHECK: store <8 x float> zeroinitializer
+ // 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 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ return _mm512_zextps256_ps512(A);
+}
+
+__m512i test_mm512_zextsi128_si512(__m128i A) {
+ // CHECK-LABEL: test_mm512_zextsi128_si512
+ // CHECK: store <2 x i64> zeroinitializer
+ // CHECK: shufflevector <2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 2, i32 3, i32 2, i32 3>
+ return _mm512_zextsi128_si512(A);
+}
+
+__m512i test_mm512_zextsi256_si512(__m256i A) {
+ // CHECK-LABEL: test_mm512_zextsi256_si512
+ // CHECK: store <4 x i64> zeroinitializer
+ // CHECK: shufflevector <4 x i64> %{{.*}}, <4 x i64> %{{.*}}, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ return _mm512_zextsi256_si512(A);
+}
diff --git a/test/CodeGen/avx512ifmavl-builtins.c b/test/CodeGen/avx512ifmavl-builtins.c
index c59af0ec6d..4aeec336ad 100644
--- a/test/CodeGen/avx512ifmavl-builtins.c
+++ b/test/CodeGen/avx512ifmavl-builtins.c
@@ -1,6 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +avx512ifma -target-feature +avx512vl -emit-llvm -o - -Wall -Werror | FileCheck %s
-
-#define __MM_MALLOC_H
+// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-apple-darwin -target-feature +avx512ifma -target-feature +avx512vl -emit-llvm -o - -Wall -Werror | FileCheck %s
#include <immintrin.h>
diff --git a/test/CodeGen/avx512pf-builtins.c b/test/CodeGen/avx512pf-builtins.c
index 19ee083eae..b35d90ca63 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 c64b7bcec2..b489033807 100644
--- a/test/CodeGen/avx512vl-builtins.c
+++ b/test/CodeGen/avx512vl-builtins.c
@@ -2502,56 +2502,82 @@ __m256 test_mm256_maskz_mul_ps(__mmask8 __U, __m256 __A, __m256 __B) {
}
__m128i test_mm_mask_abs_epi32(__m128i __W, __mmask8 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_mask_abs_epi32
- // CHECK: @llvm.x86.ssse3.pabs.d.128
- // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <4 x i32> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <4 x i32> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <4 x i1> [[CMP]], <4 x i32> [[A]], <4 x i32> [[SUB]]
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i32> [[SEL]], <4 x i32> %{{.*}}
return _mm_mask_abs_epi32(__W,__U,__A);
}
__m128i test_mm_maskz_abs_epi32(__mmask8 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_maskz_abs_epi32
- // CHECK: @llvm.x86.ssse3.pabs.d.128
- // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <4 x i32> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <4 x i32> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <4 x i1> [[CMP]], <4 x i32> [[A]], <4 x i32> [[SUB]]
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i32> [[SEL]], <4 x i32> %{{.*}}
return _mm_maskz_abs_epi32(__U,__A);
}
__m256i test_mm256_mask_abs_epi32(__m256i __W, __mmask8 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_mask_abs_epi32
- // CHECK: @llvm.x86.avx2.pabs.d
- // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <8 x i32> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <8 x i32> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x i32> [[A]], <8 x i32> [[SUB]]
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i32> [[SEL]], <8 x i32> %{{.*}}
return _mm256_mask_abs_epi32(__W,__U,__A);
}
__m256i test_mm256_maskz_abs_epi32(__mmask8 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_maskz_abs_epi32
- // CHECK: @llvm.x86.avx2.pabs.d
- // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <8 x i32> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <8 x i32> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x i32> [[A]], <8 x i32> [[SUB]]
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i32> [[SEL]], <8 x i32> %{{.*}}
return _mm256_maskz_abs_epi32(__U,__A);
}
__m128i test_mm_abs_epi64(__m128i __A) {
// CHECK-LABEL: @test_mm_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.128
+ // CHECK: [[SUB:%.*]] = sub <2 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <2 x i64> [[A]], zeroinitializer
+ // CHECK: select <2 x i1> [[CMP]], <2 x i64> [[A]], <2 x i64> [[SUB]]
+
return _mm_abs_epi64(__A);
}
__m128i test_mm_mask_abs_epi64(__m128i __W, __mmask8 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_mask_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.128
+ // CHECK: [[SUB:%.*]] = sub <2 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <2 x i64> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i64> [[A]], <2 x i64> [[SUB]]
+ // CHECK: select <2 x i1> %{{.*}}, <2 x i64> [[SEL]], <2 x i64> %{{.*}}
+
return _mm_mask_abs_epi64(__W,__U,__A);
}
__m128i test_mm_maskz_abs_epi64(__mmask8 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_maskz_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.128
+ // CHECK: [[SUB:%.*]] = sub <2 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <2 x i64> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i64> [[A]], <2 x i64> [[SUB]]
+ // CHECK: select <2 x i1> %{{.*}}, <2 x i64> [[SEL]], <2 x i64> %{{.*}}
return _mm_maskz_abs_epi64(__U,__A);
}
__m256i test_mm256_abs_epi64(__m256i __A) {
// CHECK-LABEL: @test_mm256_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.256
+ // CHECK: [[SUB:%.*]] = sub <4 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <4 x i64> [[A]], zeroinitializer
+ // CHECK: select <4 x i1> [[CMP]], <4 x i64> [[A]], <4 x i64> [[SUB]]
return _mm256_abs_epi64(__A);
}
__m256i test_mm256_mask_abs_epi64(__m256i __W, __mmask8 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_mask_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.256
+ // CHECK: [[SUB:%.*]] = sub <4 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <4 x i64> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <4 x i1> [[CMP]], <4 x i64> [[A]], <4 x i64> [[SUB]]
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i64> [[SEL]], <4 x i64> %{{.*}}
return _mm256_mask_abs_epi64(__W,__U,__A);
}
__m256i test_mm256_maskz_abs_epi64(__mmask8 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_maskz_abs_epi64
- // CHECK: @llvm.x86.avx512.mask.pabs.q.256
+ // CHECK: [[SUB:%.*]] = sub <4 x i64> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <4 x i64> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <4 x i1> [[CMP]], <4 x i64> [[A]], <4 x i64> [[SUB]]
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i64> [[SEL]], <4 x i64> %{{.*}}
return _mm256_maskz_abs_epi64(__U,__A);
}
__m128i test_mm_maskz_max_epi32(__mmask8 __M, __m128i __A, __m128i __B) {
@@ -4486,50 +4512,92 @@ __m256d test_mm256_maskz_movedup_pd(__mmask8 __U, __m256d __A) {
__m128i test_mm_mask_set1_epi32(__m128i __O, __mmask8 __M) {
// CHECK-LABEL: @test_mm_mask_set1_epi32
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.d.gpr.128
+ // CHECK: insertelement <4 x i32> undef, i32 %{{.*}}, i32 0
+ // CHECK: insertelement <4 x i32> %{{.*}}32 1
+ // CHECK: insertelement <4 x i32> %{{.*}}32 2
+ // CHECK: insertelement <4 x i32> %{{.*}}32 3
+ // CHECK: shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}
return _mm_mask_set1_epi32(__O, __M, 5);
}
__m128i test_mm_maskz_set1_epi32(__mmask8 __M) {
// CHECK-LABEL: @test_mm_maskz_set1_epi32
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.d.gpr.128
+ // CHECK: insertelement <4 x i32> undef, i32 %{{.*}}, i32 0
+ // CHECK: insertelement <4 x i32> %{{.*}}32 1
+ // CHECK: insertelement <4 x i32> %{{.*}}32 2
+ // CHECK: insertelement <4 x i32> %{{.*}}32 3
+ // CHECK: shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}
return _mm_maskz_set1_epi32(__M, 5);
}
__m256i test_mm256_mask_set1_epi32(__m256i __O, __mmask8 __M) {
// CHECK-LABEL: @test_mm256_mask_set1_epi32
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.d.gpr.256
+ // CHECK: insertelement <8 x i32> undef, i32 %{{.*}}, i32 0
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 1
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 2
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 3
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 4
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 5
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 6
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 7
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}}
return _mm256_mask_set1_epi32(__O, __M, 5);
}
__m256i test_mm256_maskz_set1_epi32(__mmask8 __M) {
// CHECK-LABEL: @test_mm256_maskz_set1_epi32
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.d.gpr.256
+ // CHECK: insertelement <8 x i32> undef, i32 %{{.*}}, i32 0
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 1
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 2
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 3
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 4
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 5
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 6
+ // CHECK: insertelement <8 x i32> %{{.*}}, i32 %{{.*}}, i32 7
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}}
return _mm256_maskz_set1_epi32(__M, 5);
}
#ifdef __x86_64__
__m128i test_mm_mask_set1_epi64(__m128i __O, __mmask8 __M, long long __A) {
// CHECK-LABEL: @test_mm_mask_set1_epi64
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.q.gpr.128
+ // CHECK: insertelement <2 x i64> undef, i64 %{{.*}}, i32 0
+ // CHECK: insertelement <2 x i64> %{{.*}}, i64 %{{.*}}, i32 1
+ // CHECK: shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <2 x i32> <i32 0, i32 1>
+ // CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}
return _mm_mask_set1_epi64(__O, __M, __A);
}
__m128i test_mm_maskz_set1_epi64(__mmask8 __M, long long __A) {
// CHECK-LABEL: @test_mm_maskz_set1_epi64
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.q.gpr.128
+ // CHECK: insertelement <2 x i64> undef, i64 %{{.*}}, i32 0
+ // CHECK: insertelement <2 x i64> %{{.*}}, i64 %{{.*}}, i32 1
+ // CHECK: shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <2 x i32> <i32 0, i32 1>
+ // CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}}
return _mm_maskz_set1_epi64(__M, __A);
}
__m256i test_mm256_mask_set1_epi64(__m256i __O, __mmask8 __M, long long __A) {
// CHECK-LABEL: @test_mm256_mask_set1_epi64
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.q.gpr.256
+ // CHECK: insertelement <4 x i64> undef, i64 %{{.*}}, i32 0
+ // CHECK: insertelement <4 x i64> %{{.*}}, i64 %{{.*}}, i32 1
+ // CHECK: insertelement <4 x i64> %{{.*}}, i64 %{{.*}}, i32 2
+ // CHECK: insertelement <4 x i64> %{{.*}}, i64 %{{.*}}, i32 3
+ // CHECK: shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
return _mm256_mask_set1_epi64(__O, __M, __A);
}
__m256i test_mm256_maskz_set1_epi64(__mmask8 __M, long long __A) {
// CHECK-LABEL: @test_mm256_maskz_set1_epi64
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.q.gpr.256
+ // CHECK: insertelement <4 x i64> undef, i64 %{{.*}}, i32 0
+ // CHECK: insertelement <4 x i64> %{{.*}}, i64 %{{.*}}, i32 1
+ // CHECK: insertelement <4 x i64> %{{.*}}, i64 %{{.*}}, i32 2
+ // CHECK: insertelement <4 x i64> %{{.*}}, i64 %{{.*}}, i32 3
+ // CHECK: shufflevector <8 x i1> %{{.*}}, <8 x i1> %{{.*}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}}
return _mm256_maskz_set1_epi64(__M, __A);
}
#endif
diff --git a/test/CodeGen/avx512vlbw-builtins.c b/test/CodeGen/avx512vlbw-builtins.c
index fe363c9ffd..ff34d8feed 100644
--- a/test/CodeGen/avx512vlbw-builtins.c
+++ b/test/CodeGen/avx512vlbw-builtins.c
@@ -898,57 +898,73 @@ __m256i test_mm256_mask_blend_epi16(__mmask16 __U, __m256i __A, __m256i __W) {
__m128i test_mm_mask_abs_epi8(__m128i __W, __mmask16 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_mask_abs_epi8
- // CHECK: @llvm.x86.ssse3.pabs.b
- // CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <16 x i8> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <16 x i8> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <16 x i1> [[CMP]], <16 x i8> [[A]], <16 x i8> [[SUB]]
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i8> [[SEL]], <16 x i8> %{{.*}}
return _mm_mask_abs_epi8(__W,__U,__A);
}
__m128i test_mm_maskz_abs_epi8(__mmask16 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_maskz_abs_epi8
- // CHECK: @llvm.x86.ssse3.pabs.b
- // CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <16 x i8> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <16 x i8> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <16 x i1> [[CMP]], <16 x i8> [[A]], <16 x i8> [[SUB]]
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i8> [[SEL]], <16 x i8> %{{.*}}
return _mm_maskz_abs_epi8(__U,__A);
}
__m256i test_mm256_mask_abs_epi8(__m256i __W, __mmask32 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_mask_abs_epi8
- // CHECK: @llvm.x86.avx2.pabs.b
- // CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <32 x i8> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <32 x i8> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <32 x i1> [[CMP]], <32 x i8> [[A]], <32 x i8> [[SUB]]
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i8> [[SEL]], <32 x i8> %{{.*}}
return _mm256_mask_abs_epi8(__W,__U,__A);
}
__m256i test_mm256_maskz_abs_epi8(__mmask32 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_maskz_abs_epi8
- // CHECK: @llvm.x86.avx2.pabs.b
- // CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <32 x i8> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <32 x i8> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <32 x i1> [[CMP]], <32 x i8> [[A]], <32 x i8> [[SUB]]
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i8> [[SEL]], <32 x i8> %{{.*}}
return _mm256_maskz_abs_epi8(__U,__A);
}
__m128i test_mm_mask_abs_epi16(__m128i __W, __mmask8 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_mask_abs_epi16
- // CHECK: @llvm.x86.ssse3.pabs.w
- // CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <8 x i16> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <8 x i16> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x i16> [[A]], <8 x i16> [[SUB]]
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i16> [[SEL]], <8 x i16> %{{.*}}
return _mm_mask_abs_epi16(__W,__U,__A);
}
__m128i test_mm_maskz_abs_epi16(__mmask8 __U, __m128i __A) {
// CHECK-LABEL: @test_mm_maskz_abs_epi16
- // CHECK: @llvm.x86.ssse3.pabs.w
- // CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <8 x i16> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <8 x i16> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <8 x i1> [[CMP]], <8 x i16> [[A]], <8 x i16> [[SUB]]
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i16> [[SEL]], <8 x i16> %{{.*}}
return _mm_maskz_abs_epi16(__U,__A);
}
__m256i test_mm256_mask_abs_epi16(__m256i __W, __mmask16 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_mask_abs_epi16
- // CHECK: @llvm.x86.avx2.pabs.w
- // CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <16 x i16> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <16 x i16> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <16 x i1> [[CMP]], <16 x i16> [[A]], <16 x i16> [[SUB]]
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i16> [[SEL]], <16 x i16> %{{.*}}
return _mm256_mask_abs_epi16(__W,__U,__A);
}
__m256i test_mm256_maskz_abs_epi16(__mmask16 __U, __m256i __A) {
// CHECK-LABEL: @test_mm256_maskz_abs_epi16
- // CHECK: @llvm.x86.avx2.pabs.w
- // CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
+ // CHECK: [[SUB:%.*]] = sub <16 x i16> zeroinitializer, [[A:%.*]]
+ // CHECK: [[CMP:%.*]] = icmp sgt <16 x i16> [[A]], zeroinitializer
+ // CHECK: [[SEL:%.*]] = select <16 x i1> [[CMP]], <16 x i16> [[A]], <16 x i16> [[SUB]]
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i16> [[SEL]], <16 x i16> %{{.*}}
return _mm256_maskz_abs_epi16(__U,__A);
}
@@ -1155,49 +1171,101 @@ __m256i test_mm256_maskz_adds_epu16(__mmask16 __U, __m256i __A, __m256i __B) {
}
__m128i test_mm_mask_avg_epu8(__m128i __W, __mmask16 __U, __m128i __A, __m128i __B) {
// CHECK-LABEL: @test_mm_mask_avg_epu8
- // CHECK: @llvm.x86.sse2.pavg.b
+ // CHECK-NOT: @llvm.x86.sse2.pavg.b
+ // CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
+ // CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
+ // CHECK: add <16 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <16 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <16 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <16 x i16> %{{.*}} to <16 x i8>
// CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}
return _mm_mask_avg_epu8(__W,__U,__A,__B);
}
__m128i test_mm_maskz_avg_epu8(__mmask16 __U, __m128i __A, __m128i __B) {
// CHECK-LABEL: @test_mm_maskz_avg_epu8
- // CHECK: @llvm.x86.sse2.pavg.b
+ // CHECK-NOT: @llvm.x86.sse2.pavg.b
+ // CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
+ // CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
+ // CHECK: add <16 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <16 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <16 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <16 x i16> %{{.*}} to <16 x i8>
+ // CHECK: store <2 x i64> zeroinitializer
// CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}
return _mm_maskz_avg_epu8(__U,__A,__B);
}
__m256i test_mm256_mask_avg_epu8(__m256i __W, __mmask32 __U, __m256i __A, __m256i __B) {
// CHECK-LABEL: @test_mm256_mask_avg_epu8
- // CHECK: @llvm.x86.avx2.pavg.b
+ // CHECK-NOT: @llvm.x86.avx2.pavg.b
+ // CHECK: zext <32 x i8> %{{.*}} to <32 x i16>
+ // CHECK: zext <32 x i8> %{{.*}} to <32 x i16>
+ // CHECK: add <32 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <32 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <32 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <32 x i16> %{{.*}} to <32 x i8>
// CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}}
return _mm256_mask_avg_epu8(__W,__U,__A,__B);
}
__m256i test_mm256_maskz_avg_epu8(__mmask32 __U, __m256i __A, __m256i __B) {
// CHECK-LABEL: @test_mm256_maskz_avg_epu8
- // CHECK: @llvm.x86.avx2.pavg.b
+ // CHECK-NOT: @llvm.x86.avx2.pavg.b
+ // CHECK: zext <32 x i8> %{{.*}} to <32 x i16>
+ // CHECK: zext <32 x i8> %{{.*}} to <32 x i16>
+ // CHECK: add <32 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <32 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <32 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: trunc <32 x i16> %{{.*}} to <32 x i8>
+ // CHECK: store <4 x i64> zeroinitializer
// CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}}
return _mm256_maskz_avg_epu8(__U,__A,__B);
}
__m128i test_mm_mask_avg_epu16(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) {
// CHECK-LABEL: @test_mm_mask_avg_epu16
- // CHECK: @llvm.x86.sse2.pavg.w
+ // CHECK-NOT: @llvm.x86.sse2.pavg.w
+ // CHECK: zext <8 x i16> %{{.*}} to <8 x i32>
+ // CHECK: zext <8 x i16> %{{.*}} to <8 x i32>
+ // CHECK: add <8 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <8 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <8 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <8 x i32> %{{.*}} to <8 x i16>
// CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}
return _mm_mask_avg_epu16(__W,__U,__A,__B);
}
__m128i test_mm_maskz_avg_epu16(__mmask8 __U, __m128i __A, __m128i __B) {
// CHECK-LABEL: @test_mm_maskz_avg_epu16
- // CHECK: @llvm.x86.sse2.pavg.w
+ // CHECK-NOT: @llvm.x86.sse2.pavg.w
+ // CHECK: zext <8 x i16> %{{.*}} to <8 x i32>
+ // CHECK: zext <8 x i16> %{{.*}} to <8 x i32>
+ // CHECK: add <8 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <8 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <8 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <8 x i32> %{{.*}} to <8 x i16>
+ // CHECK: store <2 x i64> zeroinitializer
// CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}
return _mm_maskz_avg_epu16(__U,__A,__B);
}
__m256i test_mm256_mask_avg_epu16(__m256i __W, __mmask16 __U, __m256i __A, __m256i __B) {
// CHECK-LABEL: @test_mm256_mask_avg_epu16
- // CHECK: @llvm.x86.avx2.pavg.w
+ // CHECK-NOT: @llvm.x86.avx2.pavg.w
+ // CHECK: zext <16 x i16> %{{.*}} to <16 x i32>
+ // CHECK: zext <16 x i16> %{{.*}} to <16 x i32>
+ // CHECK: add <16 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <16 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <16 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <16 x i32> %{{.*}} to <16 x i16>
// CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
return _mm256_mask_avg_epu16(__W,__U,__A,__B);
}
__m256i test_mm256_maskz_avg_epu16(__mmask16 __U, __m256i __A, __m256i __B) {
// CHECK-LABEL: @test_mm256_maskz_avg_epu16
- // CHECK: @llvm.x86.avx2.pavg.w
+ // CHECK-NOT: @llvm.x86.avx2.pavg.w
+ // CHECK: zext <16 x i16> %{{.*}} to <16 x i32>
+ // CHECK: zext <16 x i16> %{{.*}} to <16 x i32>
+ // CHECK: add <16 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <16 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <16 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <16 x i32> %{{.*}} to <16 x i16>
+ // CHECK: store <4 x i64> zeroinitializer
// CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
return _mm256_maskz_avg_epu16(__U,__A,__B);
}
@@ -2521,25 +2589,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);
}
@@ -2598,28 +2670,195 @@ __m256i test_mm256_maskz_broadcastw_epi16(__mmask16 __M, __m128i __A) {
// CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
return _mm256_maskz_broadcastw_epi16(__M, __A);
}
+__m128i test_mm_mask_set1_epi8 (__m128i __O, __mmask16 __M, char __A){
+ // CHECK-LABEL: @test_mm_mask_set1_epi8
+ // CHECK: insertelement <16 x i8> undef, i8 %{{.*}}, i32 0
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 1
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 2
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 3
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 4
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 5
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 6
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 7
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 8
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 9
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 10
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 11
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 12
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 13
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 14
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 15
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}
+ return _mm_mask_set1_epi8(__O, __M, __A);
+}
+__m128i test_mm_maskz_set1_epi8 ( __mmask16 __M, char __A){
+ // CHECK-LABEL: @test_mm_maskz_set1_epi8
+ // CHECK: insertelement <16 x i8> undef, i8 %{{.*}}, i32 0
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 1
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 2
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 3
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 4
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 5
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 6
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 7
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 8
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 9
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 10
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 11
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 12
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 13
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 14
+ // CHECK: insertelement <16 x i8> %{{.*}}, i8 %{{.*}}, i32 15
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}
+ return _mm_maskz_set1_epi8( __M, __A);
+}
+
+__m256i test_mm256_mask_set1_epi8(__m256i __O, __mmask32 __M, char __A) {
+ // CHECK-LABEL: @test_mm256_mask_set1_epi8
+ // CHECK: insertelement <32 x i8> undef, i8 %{{.*}}, i32 0
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 1
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 2
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 3
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 4
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 5
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 6
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 7
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 8
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 9
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 10
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 11
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 12
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 13
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 14
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 15
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 16
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 17
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 18
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 19
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 20
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 21
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 22
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 23
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 24
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 25
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 26
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 27
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 28
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 29
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 30
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 31
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}}
+ return _mm256_mask_set1_epi8(__O, __M, __A);
+}
+
+__m256i test_mm256_maskz_set1_epi8( __mmask32 __M, char __A) {
+ // CHECK-LABEL: @test_mm256_maskz_set1_epi8
+ // CHECK: insertelement <32 x i8> undef, i8 %{{.*}}, i32 0
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 1
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 2
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 3
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 4
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 5
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 6
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 7
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 8
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 9
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 10
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 11
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 12
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 13
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 14
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 15
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 16
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 17
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 18
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 19
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 20
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 21
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 22
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 23
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 24
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 25
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 26
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 27
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 28
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 29
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 30
+ // CHECK: insertelement <32 x i8> %{{.*}}, i8 %{{.*}}, i32 31
+ // CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}}
+ return _mm256_maskz_set1_epi8( __M, __A);
+}
+
__m256i test_mm256_mask_set1_epi16(__m256i __O, __mmask16 __M, short __A) {
// CHECK-LABEL: @test_mm256_mask_set1_epi16
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.w.gpr.256
+ // CHECK: insertelement <16 x i16> undef, i16 %{{.*}}, i32 0
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 1
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 2
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 3
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 4
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 5
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 6
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 7
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 8
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 9
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 10
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 11
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 12
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 13
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 14
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 15
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
return _mm256_mask_set1_epi16(__O, __M, __A);
}
__m256i test_mm256_maskz_set1_epi16(__mmask16 __M, short __A) {
// CHECK-LABEL: @test_mm256_maskz_set1_epi16
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.w.gpr.256
+ // CHECK: insertelement <16 x i16> undef, i16 %{{.*}}, i32 0
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 1
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 2
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 3
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 4
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 5
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 6
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 7
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 8
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 9
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 10
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 11
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 12
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 13
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 14
+ // CHECK: insertelement <16 x i16> %{{.*}}, i16 %{{.*}}, i32 15
+ // CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
return _mm256_maskz_set1_epi16(__M, __A);
}
__m128i test_mm_mask_set1_epi16(__m128i __O, __mmask8 __M, short __A) {
// CHECK-LABEL: @test_mm_mask_set1_epi16
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.w.gpr.128
+ // CHECK: insertelement <8 x i16> undef, i16 %{{.*}}, i32 0
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 1
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 2
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 3
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 4
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 5
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 6
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 7
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}
return _mm_mask_set1_epi16(__O, __M, __A);
}
__m128i test_mm_maskz_set1_epi16(__mmask8 __M, short __A) {
// CHECK-LABEL: @test_mm_maskz_set1_epi16
- // CHECK: @llvm.x86.avx512.mask.pbroadcast.w.gpr.128
+ // CHECK: insertelement <8 x i16> undef, i16 %{{.*}}, i32 0
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 1
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 2
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 3
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 4
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 5
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 6
+ // CHECK: insertelement <8 x i16> %{{.*}}, i16 %{{.*}}, i32 7
+ // CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}}
return _mm_maskz_set1_epi16(__M, __A);
}
__m128i test_mm_permutexvar_epi16(__m128i __A, __m128i __B) {
diff --git a/test/CodeGen/avx512vldq-builtins.c b/test/CodeGen/avx512vldq-builtins.c
index a36892465b..3ca4b2135e 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);
}
@@ -902,19 +909,21 @@ __mmask8 test_mm256_movepi64_mask(__m256i __A) {
__m256 test_mm256_broadcast_f32x2(__m128 __A) {
// CHECK-LABEL: @test_mm256_broadcast_f32x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x2
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
return _mm256_broadcast_f32x2(__A);
}
__m256 test_mm256_mask_broadcast_f32x2(__m256 __O, __mmask8 __M, __m128 __A) {
// CHECK-LABEL: @test_mm256_mask_broadcast_f32x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x2
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <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 float> %{{.*}}, <8 x float> %{{.*}}
return _mm256_mask_broadcast_f32x2(__O, __M, __A);
}
__m256 test_mm256_maskz_broadcast_f32x2(__mmask8 __M, __m128 __A) {
// CHECK-LABEL: @test_mm256_maskz_broadcast_f32x2
- // CHECK: @llvm.x86.avx512.mask.broadcastf32x2
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> zeroinitializer, <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 float> %{{.*}}, <8 x float> %{{.*}}
return _mm256_maskz_broadcast_f32x2(__M, __A);
}
@@ -940,37 +949,41 @@ __m256d test_mm256_maskz_broadcast_f64x2(__mmask8 __M, double const* __A) {
__m128i test_mm_broadcast_i32x2(__m128i __A) {
// CHECK-LABEL: @test_mm_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
return _mm_broadcast_i32x2(__A);
}
__m128i test_mm_mask_broadcast_i32x2(__m128i __O, __mmask8 __M, __m128i __A) {
// CHECK-LABEL: @test_mm_mask_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}
return _mm_mask_broadcast_i32x2(__O, __M, __A);
}
__m128i test_mm_maskz_broadcast_i32x2(__mmask8 __M, __m128i __A) {
// CHECK-LABEL: @test_mm_maskz_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+ // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}}
return _mm_maskz_broadcast_i32x2(__M, __A);
}
__m256i test_mm256_broadcast_i32x2(__m128i __A) {
// CHECK-LABEL: @test_mm256_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 0, i32 1, i32 0, i32 1, i32 0, i32 1>
return _mm256_broadcast_i32x2(__A);
}
__m256i test_mm256_mask_broadcast_i32x2(__m256i __O, __mmask8 __M, __m128i __A) {
// CHECK-LABEL: @test_mm256_mask_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <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 i32> %{{.*}}, <8 x i32> %{{.*}}
return _mm256_mask_broadcast_i32x2(__O, __M, __A);
}
__m256i test_mm256_maskz_broadcast_i32x2(__mmask8 __M, __m128i __A) {
// CHECK-LABEL: @test_mm256_maskz_broadcast_i32x2
- // CHECK: @llvm.x86.avx512.mask.broadcasti32x2
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> zeroinitializer, <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 i32> %{{.*}}, <8 x i32> %{{.*}}
return _mm256_maskz_broadcast_i32x2(__M, __A);
}
diff --git a/test/CodeGen/avx512vpopcntdqintrin.c b/test/CodeGen/avx512vpopcntdqintrin.c
new file mode 100644
index 0000000000..e7c797c195
--- /dev/null
+++ b/test/CodeGen/avx512vpopcntdqintrin.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +avx512vpopcntdq -emit-llvm -o - -Wall -Werror | FileCheck %s
+
+#include <immintrin.h>
+
+__m512i test_mm512_popcnt_epi64(__m512i __A) {
+ // CHECK-LABEL: @test_mm512_popcnt_epi64
+ // CHECK: @llvm.ctpop.v8i64
+ return _mm512_popcnt_epi64(__A);
+}
+__m512i test_mm512_mask_popcnt_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_mask_popcnt_epi64
+ // CHECK: @llvm.ctpop.v8i64
+ // CHECK: select <8 x i1> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}}, <8 x i64> {{.*}}
+ return _mm512_mask_popcnt_epi64(__W, __U, __A);
+}
+__m512i test_mm512_maskz_popcnt_epi64(__mmask8 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_maskz_popcnt_epi64
+ // CHECK: @llvm.ctpop.v8i64
+ // CHECK: select <8 x i1> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}}, <8 x i64> {{.*}}
+ return _mm512_maskz_popcnt_epi64(__U, __A);
+}
+__m512i test_mm512_popcnt_epi32(__m512i __A) {
+ // CHECK-LABEL: @test_mm512_popcnt_epi32
+ // CHECK: @llvm.ctpop.v16i32
+ return _mm512_popcnt_epi32(__A);
+}
+__m512i test_mm512_mask_popcnt_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_mask_popcnt_epi32
+ // CHECK: @llvm.ctpop.v16i32
+ // CHECK: select <16 x i1> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}}, <16 x i32> {{.*}}
+ return _mm512_mask_popcnt_epi32(__W, __U, __A);
+}
+__m512i test_mm512_maskz_popcnt_epi32(__mmask16 __U, __m512i __A) {
+ // CHECK-LABEL: @test_mm512_maskz_popcnt_epi32
+ // CHECK: @llvm.ctpop.v16i32
+ // CHECK: select <16 x i1> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}}, <16 x i32> {{.*}}
+ return _mm512_maskz_popcnt_epi32(__U, __A);
+}
diff --git a/test/CodeGen/bitscan-builtins.c b/test/CodeGen/bitscan-builtins.c
index 71e49845f8..5fd3f13fbc 100644
--- a/test/CodeGen/bitscan-builtins.c
+++ b/test/CodeGen/bitscan-builtins.c
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// PR33722
+// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown -D_MSC_VER -emit-llvm -o - %s | FileCheck %s
+
#include <immintrin.h>
int test_bit_scan_forward(int a) {
diff --git a/test/CodeGen/blocks-opencl.cl b/test/CodeGen/blocks-opencl.cl
deleted file mode 100644
index 12513331e9..0000000000
--- a/test/CodeGen/blocks-opencl.cl
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_cc1 -O0 %s -ffake-address-space-map -emit-llvm -o - -fblocks -triple x86_64-unknown-unknown | FileCheck %s
-// This used to crash due to trying to generate a bitcase from a cstring
-// in the constant address space to i8* in AS0.
-
-void dummy(float (^const op)(float)) {
-}
-
-// CHECK: i8 addrspace(2)* getelementptr inbounds ([9 x i8], [9 x i8] addrspace(2)* @.str, i32 0, i32 0)
-
-kernel void test_block()
-{
- float (^const X)(float) = ^(float x) {
- return x + 42.0f;
- };
- dummy(X);
-}
-
diff --git a/test/CodeGen/builtin-clflushopt.c b/test/CodeGen/builtin-clflushopt.c
index 93861164c4..f82ac4638f 100644
--- a/test/CodeGen/builtin-clflushopt.c
+++ b/test/CodeGen/builtin-clflushopt.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +clflushopt -emit-llvm -o - -Wall -Werror | FileCheck %s
-#define __MM_MALLOC_H
+// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-apple-darwin -target-feature +clflushopt -emit-llvm -o - -Wall -Werror | FileCheck %s
+
+#include <x86intrin.h>
-#include <immintrin.h>
void test_mm_clflushopt(char * __m) {
//CHECK-LABEL: @test_mm_clflushopt
//CHECK: @llvm.x86.clflushopt
diff --git a/test/CodeGen/builtin-clwb.c b/test/CodeGen/builtin-clwb.c
new file mode 100644
index 0000000000..96d00a6a7c
--- /dev/null
+++ b/test/CodeGen/builtin-clwb.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-apple-darwin -target-feature +clwb -emit-llvm -o - -Wall -Werror | FileCheck %s
+
+#include <x86intrin.h>
+
+void test_mm_clwb(const void *__m) {
+ //CHECK-LABEL: @test_mm_clwb
+ //CHECK: @llvm.x86.clwb
+ _mm_clwb(__m);
+}
diff --git a/test/CodeGen/builtin-clzero.c b/test/CodeGen/builtin-clzero.c
index c9960ced12..f9ecb9ddb5 100644
--- a/test/CodeGen/builtin-clzero.c
+++ b/test/CodeGen/builtin-clzero.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -target-feature +clzero -emit-llvm -o - -Wall -Werror | FileCheck %s
-#define __MM_MALLOC_H
+// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-apple-darwin -target-feature +clzero -emit-llvm -o - -Wall -Werror | FileCheck %s
#include <x86intrin.h>
+
void test_mm_clzero(void * __m) {
//CHECK-LABEL: @test_mm_clzero
//CHECK: @llvm.x86.clzero
diff --git a/test/CodeGen/builtin-cpu-is.c b/test/CodeGen/builtin-cpu-is.c
new file mode 100644
index 0000000000..f2a5f54a0c
--- /dev/null
+++ b/test/CodeGen/builtin-cpu-is.c
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm < %s| FileCheck %s
+
+// Test that we have the structure definition, the gep offsets, the name of the
+// global, the bit grab, and the icmp correct.
+extern void a(const char *);
+
+void intel() {
+ if (__builtin_cpu_is("intel"))
+ a("intel");
+
+ // CHECK: [[LOAD:%[^ ]+]] = load i32, i32* getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, { i32, i32, i32, [1 x i32] }* @__cpu_model, i32 0, i32 0)
+ // CHECK: = icmp eq i32 [[LOAD]], 1
+}
+
+void amd() {
+ if (__builtin_cpu_is("amd"))
+ a("amd");
+
+ // CHECK: [[LOAD:%[^ ]+]] = load i32, i32* getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, { i32, i32, i32, [1 x i32] }* @__cpu_model, i32 0, i32 0)
+ // CHECK: = icmp eq i32 [[LOAD]], 2
+}
+
+void atom() {
+ if (__builtin_cpu_is("atom"))
+ a("atom");
+
+ // CHECK: [[LOAD:%[^ ]+]] = load i32, i32* getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, { i32, i32, i32, [1 x i32] }* @__cpu_model, i32 0, i32 1)
+ // CHECK: = icmp eq i32 [[LOAD]], 1
+}
+
+void amdfam10h() {
+ if (__builtin_cpu_is("amdfam10h"))
+ a("amdfam10h");
+
+ // CHECK: [[LOAD:%[^ ]+]] = load i32, i32* getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, { i32, i32, i32, [1 x i32] }* @__cpu_model, i32 0, i32 1)
+ // CHECK: = icmp eq i32 [[LOAD]], 4
+}
+
+void barcelona() {
+ if (__builtin_cpu_is("barcelona"))
+ a("barcelona");
+
+ // CHECK: [[LOAD:%[^ ]+]] = load i32, i32* getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, { i32, i32, i32, [1 x i32] }* @__cpu_model, i32 0, i32 2)
+ // CHECK: = icmp eq i32 [[LOAD]], 4
+}
+
+void nehalem() {
+ if (__builtin_cpu_is("nehalem"))
+ a("nehalem");
+
+ // CHECK: [[LOAD:%[^ ]+]] = load i32, i32* getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, { i32, i32, i32, [1 x i32] }* @__cpu_model, i32 0, i32 2)
+ // CHECK: = icmp eq i32 [[LOAD]], 1
+}
diff --git a/test/CodeGen/builtin-cpu-supports.c b/test/CodeGen/builtin-cpu-supports.c
index 96813923f2..b70f4aca9d 100644
--- a/test/CodeGen/builtin-cpu-supports.c
+++ b/test/CodeGen/builtin-cpu-supports.c
@@ -5,6 +5,10 @@
extern void a(const char *);
int main() {
+ __builtin_cpu_init();
+
+ // CHECK: call void @__cpu_indicator_init
+
if (__builtin_cpu_supports("sse4.2"))
a("sse4.2");
diff --git a/test/CodeGen/builtin-sqrt.c b/test/CodeGen/builtin-sqrt.c
new file mode 100644
index 0000000000..f93c5926d5
--- /dev/null
+++ b/test/CodeGen/builtin-sqrt.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fmath-errno -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=HAS_ERRNO
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=NO_ERRNO
+
+// FIXME: If a builtin is supposed to have identical semantics to its libm twin, then it
+// should not be marked "constant" in Builtins.def because that means it can't set errno.
+// Note that both runs have 'readnone' on the libcall here.
+
+float foo(float X) {
+ // HAS_ERRNO: call float @sqrtf(float
+ // NO_ERRNO: call float @sqrtf(float
+ return __builtin_sqrtf(X);
+}
+
+// HAS_ERRNO: declare float @sqrtf(float) [[ATTR:#[0-9]+]]
+// HAS_ERRNO: attributes [[ATTR]] = { nounwind readnone {{.*}}}
+
+// NO_ERRNO: declare float @sqrtf(float) [[ATTR:#[0-9]+]]
+// NO_ERRNO: attributes [[ATTR]] = { nounwind readnone {{.*}}}
+
diff --git a/test/CodeGen/builtins-arm-exclusive.c b/test/CodeGen/builtins-arm-exclusive.c
index b0bc2b82d3..56d7798a5e 100644
--- a/test/CodeGen/builtins-arm-exclusive.c
+++ b/test/CodeGen/builtins-arm-exclusive.c
@@ -1,6 +1,5 @@
-// RUN: %clang_cc1 -Wall -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
-// RUN: %clang_cc1 -Wall -Werror -triple arm64-apple-ios7.0 -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s --check-prefix=CHECK-ARM64
-
+// RUN: %clang_cc1 -Wall -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -Wall -Werror -triple arm64-apple-ios7.0 -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s --check-prefix=CHECK-ARM64
struct Simple {
char a, b;
diff --git a/test/CodeGen/builtins-arm.c b/test/CodeGen/builtins-arm.c
index 0dc4c7dd77..e04349f1a3 100644
--- a/test/CodeGen/builtins-arm.c
+++ b/test/CodeGen/builtins-arm.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wall -Werror -triple thumbv7-eabi -target-cpu cortex-a8 -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -Wall -Werror -triple thumbv7-eabi -target-cpu cortex-a8 -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
#include <stdint.h>
diff --git a/test/CodeGen/builtins-arm64.c b/test/CodeGen/builtins-arm64.c
index dc5fb6f31c..7027a6e220 100644
--- a/test/CodeGen/builtins-arm64.c
+++ b/test/CodeGen/builtins-arm64.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-unknown-linux -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-unknown-linux -disable-O0-optnone -emit-llvm -o - %s | opt -S -mem2reg | FileCheck %s
void f0(void *a, void *b) {
__clear_cache(a,b);
diff --git a/test/CodeGen/builtins-hexagon.c b/test/CodeGen/builtins-hexagon.c
index e2eda2afaf..f9f5d495d0 100644
--- a/test/CodeGen/builtins-hexagon.c
+++ b/test/CodeGen/builtins-hexagon.c
@@ -2962,4 +2962,16 @@ void foo() {
// CHECK: @llvm.hexagon.V6.vzh.128B
__builtin_HEXAGON_V6_vzh(v16);
// CHECK: @llvm.hexagon.V6.vzh
+ __builtin_HEXAGON_Y2_dccleana(0);
+ // CHECK: @llvm.hexagon.Y2.dccleana
+ __builtin_HEXAGON_Y2_dccleaninva(0);
+ // CHECK: @llvm.hexagon.Y2.dccleaninva
+ __builtin_HEXAGON_Y2_dcinva(0);
+ // CHECK: @llvm.hexagon.Y2.dcinva
+ __builtin_HEXAGON_Y2_dczeroa(0);
+ // CHECK: @llvm.hexagon.Y2.dczeroa
+ __builtin_HEXAGON_Y4_l2fetch(0, 0);
+ // CHECK: @llvm.hexagon.Y4.l2fetch
+ __builtin_HEXAGON_Y5_l2fetch(0, 0);
+ // CHECK: @llvm.hexagon.Y5.l2fetch
}
diff --git a/test/CodeGen/builtins-mips-msa-error.c b/test/CodeGen/builtins-mips-msa-error.c
index 7aba8ff9b0..11750922bb 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}}
@@ -310,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}}
diff --git a/test/CodeGen/builtins-mips-msa.c b/test/CodeGen/builtins-mips-msa.c
index 2e46bfd995..9d09a42090 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(
diff --git a/test/CodeGen/builtins-nvptx-ptx60.cu b/test/CodeGen/builtins-nvptx-ptx60.cu
new file mode 100644
index 0000000000..11db9ac46e
--- /dev/null
+++ b/test/CodeGen/builtins-nvptx-ptx60.cu
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -target-cpu sm_60 \
+// RUN: -fcuda-is-device -target-feature +ptx60 \
+// RUN: -S -emit-llvm -o - -x cuda %s \
+// RUN: | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_60 \
+// RUN: -fcuda-is-device -S -o /dev/null -x cuda -verify %s
+
+#define __device__ __attribute__((device))
+#define __global__ __attribute__((global))
+#define __shared__ __attribute__((shared))
+#define __constant__ __attribute__((constant))
+
+typedef unsigned long long uint64_t;
+
+// We have to keep all builtins that depend on particular target feature in the
+// same function, because the codegen will stop after the very first function
+// that encounters an error, so -verify will not be able to find errors in
+// subsequent functions.
+
+// CHECK-LABEL: nvvm_sync
+__device__ void nvvm_sync(unsigned mask, int i, float f, int a, int b,
+ bool pred, uint64_t i64) {
+
+ // CHECK: call void @llvm.nvvm.bar.warp.sync(i32
+ // expected-error@+1 {{'__nvvm_bar_warp_sync' needs target feature ptx60}}
+ __nvvm_bar_warp_sync(mask);
+ // CHECK: call void @llvm.nvvm.barrier.sync(i32
+ // expected-error@+1 {{'__nvvm_barrier_sync' needs target feature ptx60}}
+ __nvvm_barrier_sync(mask);
+ // CHECK: call void @llvm.nvvm.barrier.sync.cnt(i32
+ // expected-error@+1 {{'__nvvm_barrier_sync_cnt' needs target feature ptx60}}
+ __nvvm_barrier_sync_cnt(mask, i);
+
+ //
+ // SHFL.SYNC
+ //
+ // CHECK: call i32 @llvm.nvvm.shfl.sync.down.i32(i32 {{%[0-9]+}}, i32
+ // expected-error@+1 {{'__nvvm_shfl_sync_down_i32' needs target feature ptx60}}
+ __nvvm_shfl_sync_down_i32(mask, i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.sync.down.f32(i32 {{%[0-9]+}}, float
+ // expected-error@+1 {{'__nvvm_shfl_sync_down_f32' needs target feature ptx60}}
+ __nvvm_shfl_sync_down_f32(mask, f, a, b);
+ // CHECK: call i32 @llvm.nvvm.shfl.sync.up.i32(i32 {{%[0-9]+}}, i32
+ // expected-error@+1 {{'__nvvm_shfl_sync_up_i32' needs target feature ptx60}}
+ __nvvm_shfl_sync_up_i32(mask, i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.sync.up.f32(i32 {{%[0-9]+}}, float
+ // expected-error@+1 {{'__nvvm_shfl_sync_up_f32' needs target feature ptx60}}
+ __nvvm_shfl_sync_up_f32(mask, f, a, b);
+ // CHECK: call i32 @llvm.nvvm.shfl.sync.bfly.i32(i32 {{%[0-9]+}}, i32
+ // expected-error@+1 {{'__nvvm_shfl_sync_bfly_i32' needs target feature ptx60}}
+ __nvvm_shfl_sync_bfly_i32(mask, i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.sync.bfly.f32(i32 {{%[0-9]+}}, float
+ // expected-error@+1 {{'__nvvm_shfl_sync_bfly_f32' needs target feature ptx60}}
+ __nvvm_shfl_sync_bfly_f32(mask, f, a, b);
+ // CHECK: call i32 @llvm.nvvm.shfl.sync.idx.i32(i32 {{%[0-9]+}}, i32
+ // expected-error@+1 {{'__nvvm_shfl_sync_idx_i32' needs target feature ptx60}}
+ __nvvm_shfl_sync_idx_i32(mask, i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.sync.idx.f32(i32 {{%[0-9]+}}, float
+ // expected-error@+1 {{'__nvvm_shfl_sync_idx_f32' needs target feature ptx60}}
+ __nvvm_shfl_sync_idx_f32(mask, f, a, b);
+
+ //
+ // VOTE.SYNC
+ //
+
+ // CHECK: call i1 @llvm.nvvm.vote.all.sync(i32
+ // expected-error@+1 {{'__nvvm_vote_all_sync' needs target feature ptx60}}
+ __nvvm_vote_all_sync(mask, pred);
+ // CHECK: call i1 @llvm.nvvm.vote.any.sync(i32
+ // expected-error@+1 {{'__nvvm_vote_any_sync' needs target feature ptx60}}
+ __nvvm_vote_any_sync(mask, pred);
+ // CHECK: call i1 @llvm.nvvm.vote.uni.sync(i32
+ // expected-error@+1 {{'__nvvm_vote_uni_sync' needs target feature ptx60}}
+ __nvvm_vote_uni_sync(mask, pred);
+ // CHECK: call i32 @llvm.nvvm.vote.ballot.sync(i32
+ // expected-error@+1 {{'__nvvm_vote_ballot_sync' needs target feature ptx60}}
+ __nvvm_vote_ballot_sync(mask, pred);
+
+ //
+ // MATCH.{ALL,ANY}.SYNC
+ //
+
+ // CHECK: call i32 @llvm.nvvm.match.any.sync.i32(i32
+ // expected-error@+1 {{'__nvvm_match_any_sync_i32' needs target feature ptx60}}
+ __nvvm_match_any_sync_i32(mask, i);
+ // CHECK: call i64 @llvm.nvvm.match.any.sync.i64(i32
+ // expected-error@+1 {{'__nvvm_match_any_sync_i64' needs target feature ptx60}}
+ __nvvm_match_any_sync_i64(mask, i64);
+ // CHECK: call { i32, i1 } @llvm.nvvm.match.all.sync.i32p(i32
+ // expected-error@+1 {{'__nvvm_match_all_sync_i32p' needs target feature ptx60}}
+ __nvvm_match_all_sync_i32p(mask, i, &i);
+ // CHECK: call { i64, i1 } @llvm.nvvm.match.all.sync.i64p(i32
+ // expected-error@+1 {{'__nvvm_match_all_sync_i64p' needs target feature ptx60}}
+ __nvvm_match_all_sync_i64p(mask, i64, &i);
+
+ // CHECK: ret void
+}
diff --git a/test/CodeGen/builtins-nvptx-sm_70.cu b/test/CodeGen/builtins-nvptx-sm_70.cu
new file mode 100644
index 0000000000..09e5b6ba7a
--- /dev/null
+++ b/test/CodeGen/builtins-nvptx-sm_70.cu
@@ -0,0 +1,166 @@
+// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -target-cpu sm_70 \
+// RUN: -fcuda-is-device -target-feature +ptx60 \
+// RUN: -S -emit-llvm -o - -x cuda %s \
+// RUN: | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_60 \
+// RUN: -fcuda-is-device -S -o /dev/null -x cuda -verify %s
+
+#if !defined(CUDA_VERSION)
+#define __device__ __attribute__((device))
+#define __global__ __attribute__((global))
+#define __shared__ __attribute__((shared))
+#define __constant__ __attribute__((constant))
+
+typedef unsigned long long uint64_t;
+#endif
+// We have to keep all builtins that depend on particular target feature in the
+// same function, because the codegen will stop after the very first function
+// that encounters an error, so -verify will not be able to find errors in
+// subsequent functions.
+
+// CHECK-LABEL: nvvm_wmma
+__device__ void nvvm_wmma(int *src, int *dst,
+ float *fsrc, float *fdst,
+ int ldm) {
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.a.sync.row.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_a' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_a(dst, src, ldm, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.a.sync.col.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_a' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_a(dst, src+1, ldm, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.b.sync.row.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_b' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_b(dst, src, ldm, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.b.sync.col.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_b' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_b(dst, src+2, ldm, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.c.sync.row.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_c_f16' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_c_f16(dst, src, ldm, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.c.sync.col.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_c_f16' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_c_f16(dst, src, ldm, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.c.sync.row.m16n16k16.stride.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_c_f32' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_c_f32(fdst, fsrc, ldm, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.load.c.sync.col.m16n16k16.stride.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_ld_c_f32' needs target feature ptx60}}
+ __hmma_m16n16k16_ld_c_f32(fdst, fsrc, ldm, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.store.d.sync.row.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_st_c_f16' needs target feature ptx60}}
+ __hmma_m16n16k16_st_c_f16(dst, src, ldm, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.store.d.sync.col.m16n16k16.stride.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_st_c_f16' needs target feature ptx60}}
+ __hmma_m16n16k16_st_c_f16(dst, src, ldm, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.store.d.sync.row.m16n16k16.stride.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_st_c_f32' needs target feature ptx60}}
+ __hmma_m16n16k16_st_c_f32(fdst, fsrc, ldm, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.store.d.sync.col.m16n16k16.stride.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_st_c_f32' needs target feature ptx60}}
+ __hmma_m16n16k16_st_c_f32(fdst, fsrc, ldm, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f16.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 0, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f16.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 0, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f16.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 1, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f16.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 1, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f16.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 2, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f16.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 2, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f16.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 3, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f16.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f16(dst, src, src, src, 3, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f16.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 0, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f16.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 0, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f16.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 1, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f16.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 1, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f16.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 2, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f16.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 2, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f16.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 3, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f16.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f16f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f16f32(dst, src, src, fsrc, 3, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f32.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 0, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f32.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 0, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f32.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 1, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f32.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 1, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f32.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 2, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f32.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 2, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f32.f16
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 3, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f32.f16.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f16' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f16(fdst, src, src, src, 3, 1);
+
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f32.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 0, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.row.m16n16k16.f32.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 0, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f32.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 1, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.row.col.m16n16k16.f32.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 1, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f32.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 2, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.row.m16n16k16.f32.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 2, 1);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f32.f32
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 3, 0);
+ // CHECK: call {{.*}} @llvm.nvvm.wmma.mma.sync.col.col.m16n16k16.f32.f32.satfinite
+ // expected-error@+1 {{'__hmma_m16n16k16_mma_f32f32' needs target feature ptx60}}
+ __hmma_m16n16k16_mma_f32f32(fdst, src, src, fsrc, 3, 1);
+}
diff --git a/test/CodeGen/builtins-nvptx.c b/test/CodeGen/builtins-nvptx.c
index b0d646a51f..89a982377a 100644
--- a/test/CodeGen/builtins-nvptx.c
+++ b/test/CodeGen/builtins-nvptx.c
@@ -636,3 +636,36 @@ __device__ void nvvm_ldg(const void *p) {
typedef double double2 __attribute__((ext_vector_type(2)));
__nvvm_ldg_d2((const double2 *)p);
}
+
+// CHECK-LABEL: nvvm_shfl
+__device__ void nvvm_shfl(int i, float f, int a, int b) {
+ // CHECK: call i32 @llvm.nvvm.shfl.down.i32(i32
+ __nvvm_shfl_down_i32(i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.down.f32(float
+ __nvvm_shfl_down_f32(f, a, b);
+ // CHECK: call i32 @llvm.nvvm.shfl.up.i32(i32
+ __nvvm_shfl_up_i32(i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.up.f32(float
+ __nvvm_shfl_up_f32(f, a, b);
+ // CHECK: call i32 @llvm.nvvm.shfl.bfly.i32(i32
+ __nvvm_shfl_bfly_i32(i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.bfly.f32(float
+ __nvvm_shfl_bfly_f32(f, a, b);
+ // CHECK: call i32 @llvm.nvvm.shfl.idx.i32(i32
+ __nvvm_shfl_idx_i32(i, a, b);
+ // CHECK: call float @llvm.nvvm.shfl.idx.f32(float
+ __nvvm_shfl_idx_f32(f, a, b);
+ // CHECK: ret void
+}
+
+__device__ void nvvm_vote(int pred) {
+ // CHECK: call i1 @llvm.nvvm.vote.all(i1
+ __nvvm_vote_all(pred);
+ // CHECK: call i1 @llvm.nvvm.vote.any(i1
+ __nvvm_vote_any(pred);
+ // CHECK: call i1 @llvm.nvvm.vote.uni(i1
+ __nvvm_vote_uni(pred);
+ // CHECK: call i32 @llvm.nvvm.vote.ballot(i1
+ __nvvm_vote_ballot(pred);
+ // CHECK: ret void
+}
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index d54a69802f..99cf3c2538 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 \
diff --git a/test/CodeGen/builtins-ppc-crypto-disabled.c b/test/CodeGen/builtins-ppc-crypto-disabled.c
index e6a8a9337a..e0b9da0647 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 eaf568b09f..04f06f4d67 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 5860c4f9e7..29eebf2861 100644
--- a/test/CodeGen/builtins-ppc-error.c
+++ b/test/CodeGen/builtins-ppc-error.c
@@ -1,20 +1,69 @@
// 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
#include <altivec.h>
extern vector signed int vsi;
+extern vector signed int vui;
+extern vector float vf;
extern vector unsigned char vuc;
-void testInsertWord1(void) {
+void testInsertWord(void) {
int index = 5;
vector unsigned char v1 = vec_insert4b(vsi, vuc, index); // expected-error {{argument to '__builtin_vsx_insertword' must be a constant integer}}
vector unsigned long long v2 = vec_extract4b(vuc, index); // expected-error {{argument to '__builtin_vsx_extractuword' must be a constant integer}}
}
+
+void testXXPERMDI(int index) {
+ vec_xxpermdi(vsi); //expected-error {{too few arguments to function call, expected at least 3, have 1}}
+ vec_xxpermdi(vsi, vsi, 2, 4); //expected-error {{too many arguments to function call, expected at most 3, have 4}}
+ vec_xxpermdi(vsi, vsi, index); //expected-error {{argument 3 to '__builtin_vsx_xxpermdi' must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)}}
+ vec_xxpermdi(1, 2, 3); //expected-error {{first two arguments to '__builtin_vsx_xxpermdi' must be vectors}}
+ vec_xxpermdi(vsi, vuc, 2); //expected-error {{first two arguments to '__builtin_vsx_xxpermdi' must have the same type}}
+}
+
+void testXXSLDWI(int index) {
+ vec_xxsldwi(vsi); //expected-error {{too few arguments to function call, expected at least 3, have 1}}
+ vec_xxsldwi(vsi, vsi, 2, 4); //expected-error {{too many arguments to function call, expected at most 3, have 4}}
+ vec_xxsldwi(vsi, vsi, index); //expected-error {{argument 3 to '__builtin_vsx_xxsldwi' must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)}}
+ vec_xxsldwi(1, 2, 3); //expected-error {{first two arguments to '__builtin_vsx_xxsldwi' must be vectors}}
+ vec_xxsldwi(vsi, vuc, 2); //expected-error {{first two arguments to '__builtin_vsx_xxsldwi' must have the same type}}
+}
+
+void testCTF(int index) {
+ vec_ctf(vsi, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}}
+ vec_ctf(vui, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}}
+}
+
+void testVCFSX(int index) {
+ vec_vcfsx(vsi, index); //expected-error {{argument to '__builtin_altivec_vcfsx' must be a constant integer}}
+}
+
+void testVCFUX(int index) {
+ vec_vcfux(vui, index); //expected-error {{argument to '__builtin_altivec_vcfux' must be a constant integer}}
+}
+
+void testCTS(int index) {
+ vec_cts(vf, index); //expected-error {{argument to '__builtin_altivec_vctsxs' must be a constant integer}}
+
+}
+
+void testVCTSXS(int index) {
+ vec_vctsxs(vf, index); //expected-error {{argument to '__builtin_altivec_vctsxs' must be a constant integer}}
+}
+
+void testCTU(int index) {
+ vec_ctu(vf, index); //expected-error {{argument to '__builtin_altivec_vctuxs' must be a constant integer}}
+
+}
+
+void testVCTUXS(int index) {
+ vec_vctuxs(vf, index); //expected-error {{argument to '__builtin_altivec_vctuxs' must be a constant integer}}
+}
diff --git a/test/CodeGen/builtins-ppc-htm.c b/test/CodeGen/builtins-ppc-htm.c
index 87baa77af8..d7e7a9148e 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 97a663c2f2..9f2913847e 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 42316970d8..f92df86561 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 3e168c8b1b..7d014db613 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 16c72c404d..6dda19d5d9 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,
@@ -1691,4 +1691,115 @@ vec_xst_be(vd, sll, ad);
res_vd = vec_neg(vd);
// CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, {{%[0-9]+}}
// CHECK-LE: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, {{%[0-9]+}}
+
+res_vd = vec_xxpermdi(vd, vd, 0);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 2>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 1>
+
+res_vf = vec_xxpermdi(vf, vf, 1);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 3>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 1>
+
+res_vsll = vec_xxpermdi(vsll, vsll, 2);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 2>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 0>
+
+res_vull = vec_xxpermdi(vull, vull, 3);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 3>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 0>
+
+res_vsi = vec_xxpermdi(vsi, vsi, 0);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 2>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 1>
+
+res_vui = vec_xxpermdi(vui, vui, 1);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 3>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 1>
+
+res_vss = vec_xxpermdi(vss, vss, 2);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 2>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 0>
+
+res_vus = vec_xxpermdi(vus, vus, 3);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 3>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 0>
+
+res_vsc = vec_xxpermdi(vsc, vsc, 0);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 2>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 1>
+
+res_vuc = vec_xxpermdi(vuc, vuc, 1);
+// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 3>
+// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 1>
+
+res_vd = vec_xxsldwi(vd, vd, 0);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+
+res_vf = vec_xxsldwi(vf, vf, 1);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 1, i32 2, i32 3, i32 4>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 7, i32 0, i32 1, i32 2>
+
+res_vsll = vec_xxsldwi(vsll, vsll, 2);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 6, i32 7, i32 0, i32 1>
+
+res_vull = vec_xxsldwi(vull, vull, 3);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 3, i32 4, i32 5, i32 6>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 5, i32 6, i32 7, i32 0>
+
+res_vsi = vec_xxsldwi(vsi, vsi, 0);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+
+res_vui = vec_xxsldwi(vui, vui, 1);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 1, i32 2, i32 3, i32 4>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 7, i32 0, i32 1, i32 2>
+
+res_vss = vec_xxsldwi(vss, vss, 2);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 2, i32 3, i32 4, i32 5>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 6, i32 7, i32 0, i32 1>
+
+
+res_vus = vec_xxsldwi(vus, vus, 3);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 3, i32 4, i32 5, i32 6>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 5, i32 6, i32 7, i32 0>
+
+res_vsc = vec_xxsldwi(vsc, vsc, 0);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+
+res_vuc = vec_xxsldwi(vuc, vuc, 1);
+// CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 1, i32 2, i32 3, i32 4>
+// CHECK-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 7, i32 0, i32 1, i32 2>
+}
+
+// The return type of the call expression may be different from the return type of the shufflevector.
+// Wrong implementation could crash the compiler, add this test case to check that and avoid ICE.
+vector int xxpermdi_should_not_assert(vector int a, vector int b) {
+ return vec_xxpermdi(a, b, 0);
+// CHECK-LABEL: xxpermdi_should_not_assert
+// CHECK: bitcast <4 x i32> %{{[0-9]+}} to <2 x i64>
+// CHECK-NEXT: bitcast <4 x i32> %{{[0-9]+}} to <2 x i64>
+// CHECK-NEXT: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 2>
+// CHECK-NEXT: bitcast <2 x i64> %{{[0-9]+}} to <4 x i32>
+
+// CHECK-LE: bitcast <4 x i32> %{{[0-9]+}} to <2 x i64>
+// CHECK-LE-NEXT: bitcast <4 x i32> %{{[0-9]+}} to <2 x i64>
+// CHECK-LE-NEXT: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 1>
+// CHECK-LE-NEXT: bitcast <2 x i64> %{{[0-9]+}} to <4 x i32>
+}
+
+vector double xxsldwi_should_not_assert(vector double a, vector double b) {
+ return vec_xxsldwi(a, b, 0);
+// CHECK-LABEL: xxsldwi_should_not_assert
+// CHECK: bitcast <2 x double> %{{[0-9]+}} to <4 x i32>
+// CHECK-NEXT: bitcast <2 x double> %{{[0-9]+}} to <4 x i32>
+// CHECK-NEXT: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+// CHECK-NEXT: bitcast <4 x i32> %{{[0-9]+}} to <2 x double>
+
+// CHECK-LE: bitcast <2 x double> %{{[0-9]+}} to <4 x i32>
+// CHECK-NEXT-LE: bitcast <2 x double> %{{[0-9]+}} to <4 x i32>
+// CHECK-NEXT-LE: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}}, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+// CHECK-NEXT-LE: bitcast <4 x i32> %{{[0-9]+}} to <2 x double>
}
diff --git a/test/CodeGen/builtins-systemz-vector2-error.c b/test/CodeGen/builtins-systemz-vector2-error.c
new file mode 100644
index 0000000000..ceebaf8cc7
--- /dev/null
+++ b/test/CodeGen/builtins-systemz-vector2-error.c
@@ -0,0 +1,61 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu z14 -triple s390x-unknown-unknown \
+// RUN: -Wall -Wno-unused -Werror -fsyntax-only -verify %s
+
+typedef __attribute__((vector_size(16))) signed char vec_schar;
+typedef __attribute__((vector_size(16))) signed short vec_sshort;
+typedef __attribute__((vector_size(16))) signed int vec_sint;
+typedef __attribute__((vector_size(16))) signed long long vec_slong;
+typedef __attribute__((vector_size(16))) unsigned char vec_uchar;
+typedef __attribute__((vector_size(16))) unsigned short vec_ushort;
+typedef __attribute__((vector_size(16))) unsigned int vec_uint;
+typedef __attribute__((vector_size(16))) unsigned long long vec_ulong;
+typedef __attribute__((vector_size(16))) double vec_double;
+typedef __attribute__((vector_size(16))) float vec_float;
+
+volatile vec_schar vsc;
+volatile vec_sshort vss;
+volatile vec_sint vsi;
+volatile vec_slong vsl;
+volatile vec_uchar vuc;
+volatile vec_ushort vus;
+volatile vec_uint vui;
+volatile vec_ulong vul;
+volatile vec_double vd;
+volatile vec_float vf;
+
+volatile unsigned int len;
+int cc;
+
+void test_integer(void) {
+ __builtin_s390_vmslg(vul, vul, vuc, -1); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vmslg(vul, vul, vuc, 16); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vmslg(vul, vul, vuc, len); // expected-error {{must be a constant integer}}
+}
+
+void test_float(void) {
+ __builtin_s390_vfmaxdb(vd, vd, -1); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfmaxdb(vd, vd, 16); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfmaxdb(vd, vd, len); // expected-error {{must be a constant integer}}
+ __builtin_s390_vfmindb(vd, vd, -1); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfmindb(vd, vd, 16); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfmindb(vd, vd, len); // expected-error {{must be a constant integer}}
+
+ __builtin_s390_vftcisb(vf, -1, &cc); // expected-error {{argument should be a value from 0 to 4095}}
+ __builtin_s390_vftcisb(vf, 4096, &cc); // expected-error {{argument should be a value from 0 to 4095}}
+ __builtin_s390_vftcisb(vf, len, &cc); // expected-error {{must be a constant integer}}
+
+ __builtin_s390_vfisb(vf, -1, 0); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfisb(vf, 16, 0); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfisb(vf, len, 0); // expected-error {{must be a constant integer}}
+ __builtin_s390_vfisb(vf, 0, -1); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfisb(vf, 0, 16); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfisb(vf, 0, len); // expected-error {{must be a constant integer}}
+
+ __builtin_s390_vfmaxsb(vf, vf, -1); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfmaxsb(vf, vf, 16); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfmaxsb(vf, vf, len); // expected-error {{must be a constant integer}}
+ __builtin_s390_vfminsb(vf, vf, -1); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfminsb(vf, vf, 16); // expected-error {{argument should be a value from 0 to 15}}
+ __builtin_s390_vfminsb(vf, vf, len); // expected-error {{must be a constant integer}}
+}
diff --git a/test/CodeGen/builtins-systemz-vector2.c b/test/CodeGen/builtins-systemz-vector2.c
new file mode 100644
index 0000000000..8f0b8aee8c
--- /dev/null
+++ b/test/CodeGen/builtins-systemz-vector2.c
@@ -0,0 +1,136 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu z14 -triple s390x-ibm-linux -fno-lax-vector-conversions \
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+
+typedef __attribute__((vector_size(16))) signed char vec_schar;
+typedef __attribute__((vector_size(16))) signed short vec_sshort;
+typedef __attribute__((vector_size(16))) signed int vec_sint;
+typedef __attribute__((vector_size(16))) signed long long vec_slong;
+typedef __attribute__((vector_size(16))) unsigned char vec_uchar;
+typedef __attribute__((vector_size(16))) unsigned short vec_ushort;
+typedef __attribute__((vector_size(16))) unsigned int vec_uint;
+typedef __attribute__((vector_size(16))) unsigned long long vec_ulong;
+typedef __attribute__((vector_size(16))) double vec_double;
+typedef __attribute__((vector_size(16))) float vec_float;
+
+volatile vec_schar vsc;
+volatile vec_sshort vss;
+volatile vec_sint vsi;
+volatile vec_slong vsl;
+volatile vec_uchar vuc;
+volatile vec_ushort vus;
+volatile vec_uint vui;
+volatile vec_ulong vul;
+volatile vec_double vd;
+volatile vec_float vf;
+
+volatile unsigned int len;
+const void * volatile cptr;
+void * volatile ptr;
+int cc;
+
+void test_core(void) {
+ vul = __builtin_s390_vbperm(vuc, vuc);
+ // CHECK: call <2 x i64> @llvm.s390.vbperm(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+
+ vsc = __builtin_s390_vlrl(len, cptr);
+ // CHECK: call <16 x i8> @llvm.s390.vlrl(i32 %{{.*}}, i8* %{{.*}})
+
+ __builtin_s390_vstrl(vsc, len, ptr);
+ // CHECK: call void @llvm.s390.vstrl(<16 x i8> %{{.*}}, i32 %{{.*}}, i8* %{{.*}})
+}
+
+void test_integer(void) {
+ vuc = __builtin_s390_vmslg(vul, vul, vuc, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vmslg(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vuc = __builtin_s390_vmslg(vul, vul, vuc, 15);
+ // CHECK: call <16 x i8> @llvm.s390.vmslg(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
+}
+
+void test_float(void) {
+ vd = __builtin_s390_vfmaxdb(vd, vd, 4);
+ // CHECK: call <2 x double> @llvm.maxnum.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+ vd = __builtin_s390_vfmaxdb(vd, vd, 0);
+ // CHECK: call <2 x double> @llvm.s390.vfmaxdb(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i32 0)
+ vd = __builtin_s390_vfmaxdb(vd, vd, 15);
+ // CHECK: call <2 x double> @llvm.s390.vfmaxdb(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i32 15)
+
+ vd = __builtin_s390_vfmindb(vd, vd, 4);
+ // CHECK: call <2 x double> @llvm.minnum.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+ vd = __builtin_s390_vfmindb(vd, vd, 0);
+ // CHECK: call <2 x double> @llvm.s390.vfmindb(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i32 0)
+ vd = __builtin_s390_vfmindb(vd, vd, 15);
+ // CHECK: call <2 x double> @llvm.s390.vfmindb(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i32 15)
+
+ vd = __builtin_s390_vfnmadb(vd, vd, vd);
+ // CHECK: [[RES:%[^ ]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}})
+ // CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[RES]]
+ vd = __builtin_s390_vfnmsdb(vd, vd, vd);
+ // CHECK: [[NEG:%[^ ]+]] = fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %{{.*}}
+ // CHECK: [[RES:%[^ ]+]] = call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[NEG]])
+ // CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[RES]]
+
+ vsi = __builtin_s390_vfcesbs(vf, vf, &cc);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfcesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ vsi = __builtin_s390_vfchsbs(vf, vf, &cc);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ vsi = __builtin_s390_vfchesbs(vf, vf, &cc);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+
+ vsi = __builtin_s390_vftcisb(vf, 0, &cc);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 0)
+ vsi = __builtin_s390_vftcisb(vf, 4095, &cc);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 4095)
+
+ vf = __builtin_s390_vfmaxsb(vf, vf, 4);
+ // CHECK: call <4 x float> @llvm.maxnum.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ vf = __builtin_s390_vfmaxsb(vf, vf, 0);
+ // CHECK: call <4 x float> @llvm.s390.vfmaxsb(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i32 0)
+ vf = __builtin_s390_vfmaxsb(vf, vf, 15);
+ // CHECK: call <4 x float> @llvm.s390.vfmaxsb(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i32 15)
+
+ vf = __builtin_s390_vfminsb(vf, vf, 4);
+ // CHECK: call <4 x float> @llvm.minnum.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ vf = __builtin_s390_vfminsb(vf, vf, 0);
+ // CHECK: call <4 x float> @llvm.s390.vfminsb(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i32 0)
+ vf = __builtin_s390_vfminsb(vf, vf, 15);
+ // CHECK: call <4 x float> @llvm.s390.vfminsb(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i32 15)
+
+ vf = __builtin_s390_vfsqsb(vf);
+ // CHECK: call <4 x float> @llvm.sqrt.v4f32(<4 x float> %{{.*}})
+
+ vf = __builtin_s390_vfmasb(vf, vf, vf);
+ // CHECK: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
+ vf = __builtin_s390_vfmssb(vf, vf, vf);
+ // CHECK: [[NEG:%[^ ]+]] = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{.*}}
+ // CHECK: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[NEG]])
+ vf = __builtin_s390_vfnmasb(vf, vf, vf);
+ // CHECK: [[RES:%[^ ]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
+ // CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[RES]]
+ vf = __builtin_s390_vfnmssb(vf, vf, vf);
+ // CHECK: [[NEG:%[^ ]+]] = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{.*}}
+ // CHECK: [[RES:%[^ ]+]] = call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[NEG]])
+ // CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[RES]]
+
+ vf = __builtin_s390_vflpsb(vf);
+ // CHECK: call <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
+ vf = __builtin_s390_vflnsb(vf);
+ // CHECK: [[ABS:%[^ ]+]] = call <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
+ // CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[ABS]]
+
+ vf = __builtin_s390_vfisb(vf, 0, 0);
+ // CHECK: call <4 x float> @llvm.rint.v4f32(<4 x float> %{{.*}})
+ vf = __builtin_s390_vfisb(vf, 4, 0);
+ // CHECK: call <4 x float> @llvm.nearbyint.v4f32(<4 x float> %{{.*}})
+ vf = __builtin_s390_vfisb(vf, 4, 1);
+ // CHECK: call <4 x float> @llvm.round.v4f32(<4 x float> %{{.*}})
+ vf = __builtin_s390_vfisb(vf, 4, 5);
+ // CHECK: call <4 x float> @llvm.trunc.v4f32(<4 x float> %{{.*}})
+ vf = __builtin_s390_vfisb(vf, 4, 6);
+ // CHECK: call <4 x float> @llvm.ceil.v4f32(<4 x float> %{{.*}})
+ vf = __builtin_s390_vfisb(vf, 4, 7);
+ // CHECK: call <4 x float> @llvm.floor.v4f32(<4 x float> %{{.*}})
+ vf = __builtin_s390_vfisb(vf, 4, 4);
+ // CHECK: call <4 x float> @llvm.s390.vfisb(<4 x float> %{{.*}}, i32 4, i32 4)
+}
+
diff --git a/test/CodeGen/builtins-systemz-zvector-error.c b/test/CodeGen/builtins-systemz-zvector-error.c
index b28e8d9bc1..8d5aaabfba 100644
--- a/test/CodeGen/builtins-systemz-zvector-error.c
+++ b/test/CodeGen/builtins-systemz-zvector-error.c
@@ -446,43 +446,43 @@ void test_integer(void) {
// expected-note@vecintrin.h:* 1 {{must be a constant integer}}
vsc = vec_sld(vsc, vsc, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 12 {{candidate function not viable}}
// expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
vsc = vec_sld(vsc, vsc, -1); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 12 {{candidate function not viable}}
// expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
vsc = vec_sld(vsc, vsc, 16); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 12 {{candidate function not viable}}
// expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
vuc = vec_sld(vuc, vuc, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
- // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+ // expected-note@vecintrin.h:* 11 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 2 {{must be a constant integer from 0 to 15}}
vuc = vec_sld(vuc, vuc, -1); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
- // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+ // expected-note@vecintrin.h:* 11 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 2 {{must be a constant integer from 0 to 15}}
vuc = vec_sld(vuc, vuc, 16); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
- // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+ // expected-note@vecintrin.h:* 11 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 2 {{must be a constant integer from 0 to 15}}
vss = vec_sld(vss, vss, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 12 {{candidate function not viable}}
// expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
vus = vec_sld(vus, vus, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
- // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+ // expected-note@vecintrin.h:* 11 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 2 {{must be a constant integer from 0 to 15}}
vsi = vec_sld(vsi, vsi, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 12 {{candidate function not viable}}
// expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
vui = vec_sld(vui, vui, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
- // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+ // expected-note@vecintrin.h:* 11 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 2 {{must be a constant integer from 0 to 15}}
vsl = vec_sld(vsl, vsl, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 12 {{candidate function not viable}}
// expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
vul = vec_sld(vul, vul, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
- // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+ // expected-note@vecintrin.h:* 11 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 2 {{must be a constant integer from 0 to 15}}
vd = vec_sld(vd, vd, idx); // expected-error {{no matching function}}
- // expected-note@vecintrin.h:* 8 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 12 {{candidate function not viable}}
// expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
vsc = vec_sldw(vsc, vsc, idx); // expected-error {{no matching function}}
diff --git a/test/CodeGen/builtins-systemz-zvector.c b/test/CodeGen/builtins-systemz-zvector.c
index 6d554af44e..a8adbd717e 100644
--- a/test/CodeGen/builtins-systemz-zvector.c
+++ b/test/CodeGen/builtins-systemz-zvector.c
@@ -294,6 +294,16 @@ void test_core(void) {
vec_scatter_element(vd, vul, ptrd, 0);
vec_scatter_element(vd, vul, ptrd, 1);
+ vsc = vec_xl(idx, cptrsc);
+ vuc = vec_xl(idx, cptruc);
+ vss = vec_xl(idx, cptrss);
+ vus = vec_xl(idx, cptrus);
+ vsi = vec_xl(idx, cptrsi);
+ vui = vec_xl(idx, cptrui);
+ vsl = vec_xl(idx, cptrsl);
+ vul = vec_xl(idx, cptrul);
+ vd = vec_xl(idx, cptrd);
+
vsc = vec_xld2(idx, cptrsc);
vuc = vec_xld2(idx, cptruc);
vss = vec_xld2(idx, cptrss);
@@ -311,6 +321,16 @@ void test_core(void) {
vsi = vec_xlw4(idx, cptrsi);
vui = vec_xlw4(idx, cptrui);
+ vec_xst(vsc, idx, ptrsc);
+ vec_xst(vuc, idx, ptruc);
+ vec_xst(vss, idx, ptrss);
+ vec_xst(vus, idx, ptrus);
+ vec_xst(vsi, idx, ptrsi);
+ vec_xst(vui, idx, ptrui);
+ vec_xst(vsl, idx, ptrsl);
+ vec_xst(vul, idx, ptrul);
+ vec_xst(vd, idx, ptrd);
+
vec_xstd2(vsc, idx, ptrsc);
vec_xstd2(vuc, idx, ptruc);
vec_xstd2(vss, idx, ptrss);
@@ -1841,6 +1861,10 @@ void test_integer(void) {
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vuc = vec_sld(vuc, vuc, 15);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
+ vbc = vec_sld(vbc, vbc, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vbc = vec_sld(vbc, vbc, 15);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
vss = vec_sld(vss, vss, 0);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vss = vec_sld(vss, vss, 15);
@@ -1849,6 +1873,10 @@ void test_integer(void) {
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vus = vec_sld(vus, vus, 15);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
+ vbs = vec_sld(vbs, vbs, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vbs = vec_sld(vbs, vbs, 15);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
vsi = vec_sld(vsi, vsi, 0);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vsi = vec_sld(vsi, vsi, 15);
@@ -1857,6 +1885,10 @@ void test_integer(void) {
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vui = vec_sld(vui, vui, 15);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
+ vbi = vec_sld(vbi, vbi, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vbi = vec_sld(vbi, vbi, 15);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
vsl = vec_sld(vsl, vsl, 0);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vsl = vec_sld(vsl, vsl, 15);
@@ -1865,6 +1897,10 @@ void test_integer(void) {
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vul = vec_sld(vul, vul, 15);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
+ vbl = vec_sld(vbl, vbl, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vbl = vec_sld(vbl, vbl, 15);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
vd = vec_sld(vd, vd, 0);
// CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
vd = vec_sld(vd, vd, 15);
@@ -2943,6 +2979,16 @@ void test_float(void) {
// CHECK: [[VAL:%[^ ]+]] = fmul <2 x double> %{{.*}}, <double 0x41E0000000000000, double 0x41E0000000000000>
// CHECK: fptoui <2 x double> [[VAL]] to <2 x i64>
+ vd = vec_double(vsl);
+ // CHECK: sitofp <2 x i64> %{{.*}} to <2 x double>
+ vd = vec_double(vul);
+ // CHECK: uitofp <2 x i64> %{{.*}} to <2 x double>
+
+ vsl = vec_signed(vd);
+ // CHECK: fptosi <2 x double> %{{.*}} to <2 x i64>
+ vul = vec_unsigned(vd);
+ // CHECK: fptoui <2 x double> %{{.*}} to <2 x i64>
+
vd = vec_roundp(vd);
// CHECK: call <2 x double> @llvm.ceil.v2f64(<2 x double> %{{.*}})
vd = vec_ceil(vd);
@@ -2957,6 +3003,8 @@ void test_float(void) {
// CHECK: call <2 x double> @llvm.trunc.v2f64(<2 x double> %{{.*}})
vd = vec_roundc(vd);
// CHECK: call <2 x double> @llvm.nearbyint.v2f64(<2 x double> %{{.*}})
+ vd = vec_rint(vd);
+ // CHECK: call <2 x double> @llvm.rint.v2f64(<2 x double> %{{.*}})
vd = vec_round(vd);
// CHECK: call <2 x double> @llvm.s390.vfidb(<2 x double> %{{.*}}, i32 4, i32 4)
@@ -2964,4 +3012,44 @@ void test_float(void) {
// CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 0)
vbl = vec_fp_test_data_class(vd, 4095, &cc);
// CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 4095)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_ZERO_P, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 2048)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_ZERO_N, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 1024)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_ZERO, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 3072)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_NORMAL_P, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 512)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_NORMAL_N, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 256)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_NORMAL, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 768)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_SUBNORMAL_P, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 128)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_SUBNORMAL_N, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 64)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_SUBNORMAL, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 192)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_INFINITY_P, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 32)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_INFINITY_N, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 16)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_INFINITY, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 48)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_QNAN_P, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 8)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_QNAN_N, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 4)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_QNAN, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 12)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_SNAN_P, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 2)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_SNAN_N, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 1)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_SNAN, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 3)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_NAN, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 15)
+ vbl = vec_fp_test_data_class(vd, __VEC_CLASS_FP_NOT_NORMAL, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 3327)
}
diff --git a/test/CodeGen/builtins-systemz-zvector2-error.c b/test/CodeGen/builtins-systemz-zvector2-error.c
new file mode 100644
index 0000000000..823d6374dc
--- /dev/null
+++ b/test/CodeGen/builtins-systemz-zvector2-error.c
@@ -0,0 +1,153 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
+// RUN: -fzvector -fno-lax-vector-conversions \
+// RUN: -Wall -Wno-unused -Werror -fsyntax-only -verify %s
+
+#include <vecintrin.h>
+
+volatile vector signed char vsc;
+volatile vector signed short vss;
+volatile vector signed int vsi;
+volatile vector signed long long vsl;
+volatile vector unsigned char vuc;
+volatile vector unsigned short vus;
+volatile vector unsigned int vui;
+volatile vector unsigned long long vul;
+volatile vector bool char vbc;
+volatile vector bool short vbs;
+volatile vector bool int vbi;
+volatile vector bool long long vbl;
+volatile vector float vf;
+volatile vector double vd;
+
+volatile signed char sc;
+volatile signed short ss;
+volatile signed int si;
+volatile signed long long sl;
+volatile unsigned char uc;
+volatile unsigned short us;
+volatile unsigned int ui;
+volatile unsigned long long ul;
+volatile float f;
+volatile double d;
+
+const void * volatile cptr;
+const signed char * volatile cptrsc;
+const signed short * volatile cptrss;
+const signed int * volatile cptrsi;
+const signed long long * volatile cptrsl;
+const unsigned char * volatile cptruc;
+const unsigned short * volatile cptrus;
+const unsigned int * volatile cptrui;
+const unsigned long long * volatile cptrul;
+const float * volatile cptrf;
+const double * volatile cptrd;
+
+void * volatile ptr;
+signed char * volatile ptrsc;
+signed short * volatile ptrss;
+signed int * volatile ptrsi;
+signed long long * volatile ptrsl;
+unsigned char * volatile ptruc;
+unsigned short * volatile ptrus;
+unsigned int * volatile ptrui;
+unsigned long long * volatile ptrul;
+float * volatile ptrf;
+double * volatile ptrd;
+
+volatile unsigned int len;
+volatile int idx;
+int cc;
+
+void test_core(void) {
+ vf = vec_gather_element(vf, vui, cptrf, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vf = vec_gather_element(vf, vui, cptrf, -1); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vf = vec_gather_element(vf, vui, cptrf, 4); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vd = vec_gather_element(vd, vul, cptrd, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+ vd = vec_gather_element(vd, vul, cptrd, -1); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+ vd = vec_gather_element(vd, vul, cptrd, 2); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+
+ vec_scatter_element(vf, vui, ptrf, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vec_scatter_element(vf, vui, ptrf, -1); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vec_scatter_element(vf, vui, ptrf, 4); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vec_scatter_element(vd, vul, ptrd, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+ vec_scatter_element(vd, vul, ptrd, -1); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+ vec_scatter_element(vd, vul, ptrd, 2); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 7 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+
+ vf = vec_splat(vf, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vf = vec_splat(vf, -1); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vf = vec_splat(vf, 4); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 3}}
+ vd = vec_splat(vd, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+ vd = vec_splat(vd, -1); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+ vd = vec_splat(vd, 2); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 1}}
+}
+
+void test_integer(void) {
+ vf = vec_sld(vf, vf, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+ vd = vec_sld(vd, vd, idx); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 13 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 15}}
+
+ vuc = vec_msum_u128(vul, vul, vuc, idx); // expected-error {{must be a constant integer}}
+ vuc = vec_msum_u128(vul, vul, vuc, -1); // expected-error {{should be a value from 0 to 15}}
+ vuc = vec_msum_u128(vul, vul, vuc, 16); // expected-error {{should be a value from 0 to 15}}
+}
+
+void test_float(void) {
+ vbi = vec_fp_test_data_class(vf, idx, &cc); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 1 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 4095}}
+ vbi = vec_fp_test_data_class(vf, -1, &cc); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 1 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 4095}}
+ vbi = vec_fp_test_data_class(vf, 4096, &cc); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 1 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 4095}}
+ vbl = vec_fp_test_data_class(vd, idx, &cc); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 1 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 4095}}
+ vbl = vec_fp_test_data_class(vd, -1, &cc); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 1 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 4095}}
+ vbl = vec_fp_test_data_class(vd, 4096, &cc); // expected-error {{no matching function}}
+ // expected-note@vecintrin.h:* 1 {{candidate function not viable}}
+ // expected-note@vecintrin.h:* 1 {{must be a constant integer from 0 to 4095}}
+}
diff --git a/test/CodeGen/builtins-systemz-zvector2.c b/test/CodeGen/builtins-systemz-zvector2.c
new file mode 100644
index 0000000000..d9607b3a87
--- /dev/null
+++ b/test/CodeGen/builtins-systemz-zvector2.c
@@ -0,0 +1,545 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
+// RUN: -O -fzvector -fno-lax-vector-conversions \
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+
+#include <vecintrin.h>
+
+volatile vector signed char vsc;
+volatile vector signed short vss;
+volatile vector signed int vsi;
+volatile vector signed long long vsl;
+volatile vector unsigned char vuc;
+volatile vector unsigned short vus;
+volatile vector unsigned int vui;
+volatile vector unsigned long long vul;
+volatile vector bool char vbc;
+volatile vector bool short vbs;
+volatile vector bool int vbi;
+volatile vector bool long long vbl;
+volatile vector float vf;
+volatile vector double vd;
+
+volatile signed char sc;
+volatile signed short ss;
+volatile signed int si;
+volatile signed long long sl;
+volatile unsigned char uc;
+volatile unsigned short us;
+volatile unsigned int ui;
+volatile unsigned long long ul;
+volatile float f;
+volatile double d;
+
+const void * volatile cptr;
+const signed char * volatile cptrsc;
+const signed short * volatile cptrss;
+const signed int * volatile cptrsi;
+const signed long long * volatile cptrsl;
+const unsigned char * volatile cptruc;
+const unsigned short * volatile cptrus;
+const unsigned int * volatile cptrui;
+const unsigned long long * volatile cptrul;
+const float * volatile cptrf;
+const double * volatile cptrd;
+
+void * volatile ptr;
+signed char * volatile ptrsc;
+signed short * volatile ptrss;
+signed int * volatile ptrsi;
+signed long long * volatile ptrsl;
+unsigned char * volatile ptruc;
+unsigned short * volatile ptrus;
+unsigned int * volatile ptrui;
+unsigned long long * volatile ptrul;
+float * volatile ptrf;
+double * volatile ptrd;
+
+volatile unsigned int len;
+volatile int idx;
+int cc;
+
+void test_core(void) {
+ f = vec_extract(vf, idx);
+ // CHECK: extractelement <4 x float> %{{.*}}, i32 %{{.*}}
+ d = vec_extract(vd, idx);
+ // CHECK: extractelement <2 x double> %{{.*}}, i32 %{{.*}}
+
+ vf = vec_insert(d, vf, idx);
+ // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 %{{.*}}
+ vd = vec_insert(f, vd, idx);
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 %{{.*}}
+
+ vf = vec_promote(f, idx);
+ // CHECK: insertelement <4 x float> undef, float %{{.*}}, i32 %{{.*}}
+ vd = vec_promote(d, idx);
+ // CHECK: insertelement <2 x double> undef, double %{{.*}}, i32 %{{.*}}
+
+ vf = vec_insert_and_zero(cptrf);
+ // CHECK: insertelement <4 x float> <float undef, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00>, float %{{.*}}, i32 0
+ vd = vec_insert_and_zero(cptrd);
+ // CHECK: insertelement <2 x double> <double undef, double 0.000000e+00>, double %{{.*}}, i32 0
+
+ vf = vec_perm(vf, vf, vuc);
+ // CHECK: call <16 x i8> @llvm.s390.vperm(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vd = vec_perm(vd, vd, vuc);
+ // CHECK: call <16 x i8> @llvm.s390.vperm(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+
+ vul = vec_bperm_u128(vuc, vuc);
+ // CHECK: call <2 x i64> @llvm.s390.vbperm(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+
+ vf = vec_sel(vf, vf, vui);
+ vf = vec_sel(vf, vf, vbi);
+ vd = vec_sel(vd, vd, vul);
+ vd = vec_sel(vd, vd, vbl);
+
+ vf = vec_gather_element(vf, vui, cptrf, 0);
+ vf = vec_gather_element(vf, vui, cptrf, 1);
+ vf = vec_gather_element(vf, vui, cptrf, 2);
+ vf = vec_gather_element(vf, vui, cptrf, 3);
+ vd = vec_gather_element(vd, vul, cptrd, 0);
+ vd = vec_gather_element(vd, vul, cptrd, 1);
+
+ vec_scatter_element(vf, vui, ptrf, 0);
+ vec_scatter_element(vf, vui, ptrf, 1);
+ vec_scatter_element(vf, vui, ptrf, 2);
+ vec_scatter_element(vf, vui, ptrf, 3);
+ vec_scatter_element(vd, vul, ptrd, 0);
+ vec_scatter_element(vd, vul, ptrd, 1);
+
+ vf = vec_xl(idx, cptrf);
+ vd = vec_xl(idx, cptrd);
+
+ vec_xst(vf, idx, ptrf);
+ vec_xst(vd, idx, ptrd);
+
+ vd = vec_load_bndry(cptrd, 64);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 0)
+ vf = vec_load_bndry(cptrf, 64);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 0)
+ vf = vec_load_bndry(cptrf, 128);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 1)
+ vf = vec_load_bndry(cptrf, 256);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 2)
+ vf = vec_load_bndry(cptrf, 512);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 3)
+ vf = vec_load_bndry(cptrf, 1024);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 4)
+ vf = vec_load_bndry(cptrf, 2048);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 5)
+ vf = vec_load_bndry(cptrf, 4096);
+ // CHECK: call <16 x i8> @llvm.s390.vlbb(i8* %{{.*}}, i32 6)
+
+ vf = vec_load_len(cptrf, idx);
+ // CHECK: call <16 x i8> @llvm.s390.vll(i32 %{{.*}}, i8* %{{.*}})
+ vd = vec_load_len(cptrd, idx);
+ // CHECK: call <16 x i8> @llvm.s390.vll(i32 %{{.*}}, i8* %{{.*}})
+
+ vec_store_len(vf, ptrf, idx);
+ // CHECK: call void @llvm.s390.vstl(<16 x i8> %{{.*}}, i32 %{{.*}}, i8* %{{.*}})
+ vec_store_len(vd, ptrd, idx);
+ // CHECK: call void @llvm.s390.vstl(<16 x i8> %{{.*}}, i32 %{{.*}}, i8* %{{.*}})
+
+ vuc = vec_load_len_r(cptruc, idx);
+ // CHECK: call <16 x i8> @llvm.s390.vlrl(i32 %{{.*}}, i8* %{{.*}})
+
+ vec_store_len_r(vuc, ptruc, idx);
+ // CHECK: call void @llvm.s390.vstrl(<16 x i8> %{{.*}}, i32 %{{.*}}, i8* %{{.*}})
+
+ vf = vec_splat(vf, 0);
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <4 x i32> zeroinitializer
+ vf = vec_splat(vf, 1);
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+ vd = vec_splat(vd, 0);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <2 x i32> zeroinitializer
+ vd = vec_splat(vd, 1);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <2 x i32> <i32 1, i32 1>
+
+ vf = vec_splats(f);
+ // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> undef, <4 x i32> zeroinitializer
+ vd = vec_splats(d);
+ // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> undef, <2 x i32> zeroinitializer
+
+ vf = vec_mergeh(vf, vf);
+ // shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> <i32 0, i32 4, i32 1, i32 5>
+ vd = vec_mergeh(vd, vd);
+ // shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 0, i32 2>
+
+ vf = vec_mergel(vf, vf);
+ // shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <i32 2, i32 6, i32 3, i32 7>
+ vd = vec_mergel(vd, vd);
+ // shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <i32 1, i32 3>
+}
+
+void test_compare(void) {
+ vbi = vec_cmpeq(vf, vf);
+ // CHECK: fcmp oeq <4 x float> %{{.*}}, %{{.*}}
+ vbl = vec_cmpeq(vd, vd);
+ // CHECK: fcmp oeq <2 x double> %{{.*}}, %{{.*}}
+
+ vbi = vec_cmpge(vf, vf);
+ // CHECK: fcmp oge <4 x float> %{{.*}}, %{{.*}}
+ vbl = vec_cmpge(vd, vd);
+ // CHECK: fcmp oge <2 x double> %{{.*}}, %{{.*}}
+
+ vbi = vec_cmpgt(vf, vf);
+ // CHECK: fcmp ogt <4 x float> %{{.*}}, %{{.*}}
+ vbl = vec_cmpgt(vd, vd);
+ // CHECK: fcmp ogt <2 x double> %{{.*}}, %{{.*}}
+
+ vbi = vec_cmple(vf, vf);
+ // CHECK: fcmp ole <4 x float> %{{.*}}, %{{.*}}
+ vbl = vec_cmple(vd, vd);
+ // CHECK: fcmp ole <2 x double> %{{.*}}, %{{.*}}
+
+ vbi = vec_cmplt(vf, vf);
+ // CHECK: fcmp olt <4 x float> %{{.*}}, %{{.*}}
+ vbl = vec_cmplt(vd, vd);
+ // CHECK: fcmp olt <2 x double> %{{.*}}, %{{.*}}
+
+ idx = vec_all_eq(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfcesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_eq(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfcedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_ne(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfcesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_ne(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfcedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_ge(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_ge(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_gt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_gt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_le(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_le(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_lt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_lt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_nge(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+ idx = vec_all_nge(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_ngt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_ngt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_nle(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_nle(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_nlt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_all_nlt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_all_nan(vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 15)
+ idx = vec_all_nan(vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 15)
+
+ idx = vec_all_numeric(vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 15)
+ idx = vec_all_numeric(vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 15)
+
+ idx = vec_any_eq(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfcesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_eq(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfcedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_ne(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfcesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_ne(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfcedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_ge(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_ge(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_gt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_gt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_le(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_le(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_lt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_lt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_nge(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_nge(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_ngt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_ngt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_nle(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchesbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_nle(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchedbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_nlt(vf, vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vfchsbs(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+ idx = vec_any_nlt(vd, vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vfchdbs(<2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ idx = vec_any_nan(vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 15)
+ idx = vec_any_nan(vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 15)
+
+ idx = vec_any_numeric(vf);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 15)
+ idx = vec_any_numeric(vd);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 15)
+}
+
+void test_integer(void) {
+ vf = vec_andc(vf, vf);
+ vd = vec_andc(vd, vd);
+
+ vf = vec_nor(vf, vf);
+ vd = vec_nor(vd, vd);
+
+ vsc = vec_nand(vsc, vsc);
+ vuc = vec_nand(vuc, vuc);
+ vbc = vec_nand(vbc, vbc);
+ vss = vec_nand(vss, vss);
+ vus = vec_nand(vus, vus);
+ vbs = vec_nand(vbs, vbs);
+ vsi = vec_nand(vsi, vsi);
+ vui = vec_nand(vui, vui);
+ vbi = vec_nand(vbi, vbi);
+ vsl = vec_nand(vsl, vsl);
+ vul = vec_nand(vul, vul);
+ vbl = vec_nand(vbl, vbl);
+ vf = vec_nand(vf, vf);
+ vd = vec_nand(vd, vd);
+
+ vsc = vec_orc(vsc, vsc);
+ vuc = vec_orc(vuc, vuc);
+ vbc = vec_orc(vbc, vbc);
+ vss = vec_orc(vss, vss);
+ vus = vec_orc(vus, vus);
+ vbs = vec_orc(vbs, vbs);
+ vsi = vec_orc(vsi, vsi);
+ vui = vec_orc(vui, vui);
+ vbi = vec_orc(vbi, vbi);
+ vsl = vec_orc(vsl, vsl);
+ vul = vec_orc(vul, vul);
+ vbl = vec_orc(vbl, vbl);
+ vf = vec_orc(vf, vf);
+ vd = vec_orc(vd, vd);
+
+ vsc = vec_eqv(vsc, vsc);
+ vuc = vec_eqv(vuc, vuc);
+ vbc = vec_eqv(vbc, vbc);
+ vss = vec_eqv(vss, vss);
+ vus = vec_eqv(vus, vus);
+ vbs = vec_eqv(vbs, vbs);
+ vsi = vec_eqv(vsi, vsi);
+ vui = vec_eqv(vui, vui);
+ vbi = vec_eqv(vbi, vbi);
+ vsl = vec_eqv(vsl, vsl);
+ vul = vec_eqv(vul, vul);
+ vbl = vec_eqv(vbl, vbl);
+ vf = vec_eqv(vf, vf);
+ vd = vec_eqv(vd, vd);
+
+ vf = vec_slb(vf, vsi);
+ // CHECK: call <16 x i8> @llvm.s390.vslb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vf = vec_slb(vf, vui);
+ // CHECK: call <16 x i8> @llvm.s390.vslb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vd = vec_slb(vd, vsl);
+ // CHECK: call <16 x i8> @llvm.s390.vslb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vd = vec_slb(vd, vul);
+ // CHECK: call <16 x i8> @llvm.s390.vslb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+
+ vf = vec_sld(vf, vf, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vf = vec_sld(vf, vf, 15);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
+ vd = vec_sld(vd, vd, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vd = vec_sld(vd, vd, 15);
+ // CHECK: call <16 x i8> @llvm.s390.vsldb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}}, i32 15)
+
+ vf = vec_srab(vf, vsi);
+ // CHECK: call <16 x i8> @llvm.s390.vsrab(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vf = vec_srab(vf, vui);
+ // CHECK: call <16 x i8> @llvm.s390.vsrab(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vd = vec_srab(vd, vsl);
+ // CHECK: call <16 x i8> @llvm.s390.vsrab(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vd = vec_srab(vd, vul);
+ // CHECK: call <16 x i8> @llvm.s390.vsrab(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+
+ vf = vec_srb(vf, vsi);
+ // CHECK: call <16 x i8> @llvm.s390.vsrlb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vf = vec_srb(vf, vui);
+ // CHECK: call <16 x i8> @llvm.s390.vsrlb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vd = vec_srb(vd, vsl);
+ // CHECK: call <16 x i8> @llvm.s390.vsrlb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ vd = vec_srb(vd, vul);
+ // CHECK: call <16 x i8> @llvm.s390.vsrlb(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+
+ idx = vec_test_mask(vf, vui);
+ // CHECK: call i32 @llvm.s390.vtm(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ idx = vec_test_mask(vd, vul);
+ // CHECK: call i32 @llvm.s390.vtm(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+
+ vuc = vec_msum_u128(vul, vul, vuc, 0);
+ // CHECK: call <16 x i8> @llvm.s390.vmslg(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <16 x i8> %{{.*}}, i32 0)
+ vuc = vec_msum_u128(vul, vul, vuc, 4);
+ // CHECK: call <16 x i8> @llvm.s390.vmslg(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <16 x i8> %{{.*}}, i32 4)
+ vuc = vec_msum_u128(vul, vul, vuc, 8);
+ // CHECK: call <16 x i8> @llvm.s390.vmslg(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <16 x i8> %{{.*}}, i32 8)
+ vuc = vec_msum_u128(vul, vul, vuc, 12);
+ // CHECK: call <16 x i8> @llvm.s390.vmslg(<2 x i64> %{{.*}}, <2 x i64> %{{.*}}, <16 x i8> %{{.*}}, i32 12)
+}
+
+void test_float(void) {
+ vf = vec_abs(vf);
+ // CHECK: call <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
+ vd = vec_abs(vd);
+ // CHECK: call <2 x double> @llvm.fabs.v2f64(<2 x double> %{{.*}})
+
+ vf = vec_nabs(vf);
+ // CHECK: [[ABS:%[^ ]+]] = tail call <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
+ // CHECK-NEXT: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[ABS]]
+ vd = vec_nabs(vd);
+ // CHECK: [[ABS:%[^ ]+]] = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %{{.*}})
+ // CHECK-NEXT: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[ABS]]
+
+ vf = vec_max(vf, vf);
+ // CHECK: call <4 x float> @llvm.s390.vfmaxsb(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i32 0)
+ vd = vec_max(vd, vd);
+ // CHECK: call <2 x double> @llvm.s390.vfmaxdb(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i32 0)
+
+ vf = vec_min(vf, vf);
+ // CHECK: call <4 x float> @llvm.s390.vfminsb(<4 x float> %{{.*}}, <4 x float> %{{.*}}, i32 0)
+ vd = vec_min(vd, vd);
+ // CHECK: call <2 x double> @llvm.s390.vfmindb(<2 x double> %{{.*}}, <2 x double> %{{.*}}, i32 0)
+
+ vf = vec_madd(vf, vf, vf);
+ // CHECK: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
+ vd = vec_madd(vd, vd, vd);
+ // CHECK: call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}})
+
+ vf = vec_msub(vf, vf, vf);
+ // CHECK: [[NEG:%[^ ]+]] = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{.*}}
+ // CHECK: call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[NEG]])
+ vd = vec_msub(vd, vd, vd);
+ // CHECK: [[NEG:%[^ ]+]] = fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %{{.*}}
+ // CHECK: call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[NEG]])
+
+ vf = vec_nmadd(vf, vf, vf);
+ // CHECK: [[RES:%[^ ]+]] = tail call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
+ // CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[RES]]
+ vd = vec_nmadd(vd, vd, vd);
+ // CHECK: [[RES:%[^ ]+]] = tail call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}})
+ // CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[RES]]
+
+ vf = vec_nmsub(vf, vf, vf);
+ // CHECK: [[NEG:%[^ ]+]] = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %{{.*}}
+ // CHECK: [[RES:%[^ ]+]] = tail call <4 x float> @llvm.fma.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> [[NEG]])
+ // CHECK: fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[RES]]
+ vd = vec_nmsub(vd, vd, vd);
+ // CHECK: [[NEG:%[^ ]+]] = fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, %{{.*}}
+ // CHECK: [[RES:%[^ ]+]] = tail call <2 x double> @llvm.fma.v2f64(<2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x double> [[NEG]])
+ // CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[RES]]
+
+ vf = vec_sqrt(vf);
+ // CHECK: call <4 x float> @llvm.sqrt.v4f32(<4 x float> %{{.*}})
+ vd = vec_sqrt(vd);
+ // CHECK: call <2 x double> @llvm.sqrt.v2f64(<2 x double> %{{.*}})
+
+ vd = vec_doublee(vf);
+ // CHECK: fpext <2 x float> %{{.*}} to <2 x double>
+ vf = vec_floate(vd);
+ // CHECK: fptrunc <2 x double> %{{.*}} to <2 x float>
+
+ vd = vec_double(vsl);
+ // CHECK: sitofp <2 x i64> %{{.*}} to <2 x double>
+ vd = vec_double(vul);
+ // CHECK: uitofp <2 x i64> %{{.*}} to <2 x double>
+
+ vsl = vec_signed(vd);
+ // CHECK: fptosi <2 x double> %{{.*}} to <2 x i64>
+ vul = vec_unsigned(vd);
+ // CHECK: fptoui <2 x double> %{{.*}} to <2 x i64>
+
+ vf = vec_roundp(vf);
+ // CHECK: call <4 x float> @llvm.ceil.v4f32(<4 x float> %{{.*}})
+ vf = vec_ceil(vf);
+ // CHECK: call <4 x float> @llvm.ceil.v4f32(<4 x float> %{{.*}})
+ vd = vec_roundp(vd);
+ // CHECK: call <2 x double> @llvm.ceil.v2f64(<2 x double> %{{.*}})
+ vd = vec_ceil(vd);
+ // CHECK: call <2 x double> @llvm.ceil.v2f64(<2 x double> %{{.*}})
+
+ vf = vec_roundm(vf);
+ // CHECK: call <4 x float> @llvm.floor.v4f32(<4 x float> %{{.*}})
+ vf = vec_floor(vf);
+ // CHECK: call <4 x float> @llvm.floor.v4f32(<4 x float> %{{.*}})
+ vd = vec_roundm(vd);
+ // CHECK: call <2 x double> @llvm.floor.v2f64(<2 x double> %{{.*}})
+ vd = vec_floor(vd);
+ // CHECK: call <2 x double> @llvm.floor.v2f64(<2 x double> %{{.*}})
+
+ vf = vec_roundz(vf);
+ // CHECK: call <4 x float> @llvm.trunc.v4f32(<4 x float> %{{.*}})
+ vf = vec_trunc(vf);
+ // CHECK: call <4 x float> @llvm.trunc.v4f32(<4 x float> %{{.*}})
+ vd = vec_roundz(vd);
+ // CHECK: call <2 x double> @llvm.trunc.v2f64(<2 x double> %{{.*}})
+ vd = vec_trunc(vd);
+ // CHECK: call <2 x double> @llvm.trunc.v2f64(<2 x double> %{{.*}})
+
+ vf = vec_roundc(vf);
+ // CHECK: call <4 x float> @llvm.nearbyint.v4f32(<4 x float> %{{.*}})
+ vd = vec_roundc(vd);
+ // CHECK: call <2 x double> @llvm.nearbyint.v2f64(<2 x double> %{{.*}})
+
+ vf = vec_rint(vf);
+ // CHECK: call <4 x float> @llvm.rint.v4f32(<4 x float> %{{.*}})
+ vd = vec_rint(vd);
+ // CHECK: call <2 x double> @llvm.rint.v2f64(<2 x double> %{{.*}})
+
+ vf = vec_round(vf);
+ // CHECK: call <4 x float> @llvm.s390.vfisb(<4 x float> %{{.*}}, i32 4, i32 4)
+ vd = vec_round(vd);
+ // CHECK: call <2 x double> @llvm.s390.vfidb(<2 x double> %{{.*}}, i32 4, i32 4)
+
+ vbi = vec_fp_test_data_class(vf, 0, &cc);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 0)
+ vbi = vec_fp_test_data_class(vf, 4095, &cc);
+ // CHECK: call { <4 x i32>, i32 } @llvm.s390.vftcisb(<4 x float> %{{.*}}, i32 4095)
+ vbl = vec_fp_test_data_class(vd, 0, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 0)
+ vbl = vec_fp_test_data_class(vd, 4095, &cc);
+ // CHECK: call { <2 x i64>, i32 } @llvm.s390.vftcidb(<2 x double> %{{.*}}, i32 4095)
+}
diff --git a/test/CodeGen/builtins-wasm.c b/test/CodeGen/builtins-wasm.c
index 0c0b87945d..e0f72d2e50 100644
--- a/test/CodeGen/builtins-wasm.c
+++ b/test/CodeGen/builtins-wasm.c
@@ -14,3 +14,15 @@ __SIZE_TYPE__ f2(__SIZE_TYPE__ delta) {
// WEBASSEMBLY32: call i32 @llvm.wasm.grow.memory.i32(i32 %{{.*}})
// WEBASSEMBLY64: call i64 @llvm.wasm.grow.memory.i64(i64 %{{.*}})
}
+
+void f3(unsigned int tag, void *obj) {
+ return __builtin_wasm_throw(tag, obj);
+// WEBASSEMBLY32: call void @llvm.wasm.throw(i32 %{{.*}}, i8* %{{.*}})
+// WEBASSEMBLY64: call void @llvm.wasm.throw(i32 %{{.*}}, i8* %{{.*}})
+}
+
+void f4() {
+ return __builtin_wasm_rethrow();
+// WEBASSEMBLY32: call void @llvm.wasm.rethrow()
+// WEBASSEMBLY64: call void @llvm.wasm.rethrow()
+}
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index 0086f7079d..5df0e01c25 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -160,8 +160,6 @@ void f0() {
tmp_V4s = __builtin_ia32_psubusw(tmp_V4s, tmp_V4s);
tmp_V4s = __builtin_ia32_pmulhw(tmp_V4s, tmp_V4s);
tmp_V4s = __builtin_ia32_pmulhuw(tmp_V4s, tmp_V4s);
- tmp_V8c = __builtin_ia32_pavgb(tmp_V8c, tmp_V8c);
- tmp_V4s = __builtin_ia32_pavgw(tmp_V4s, tmp_V4s);
tmp_V8c = __builtin_ia32_pcmpeqb(tmp_V8c, tmp_V8c);
tmp_V4s = __builtin_ia32_pcmpeqw(tmp_V4s, tmp_V4s);
tmp_V2i = __builtin_ia32_pcmpeqd(tmp_V2i, tmp_V2i);
@@ -201,8 +199,6 @@ void f0() {
tmp_V16c = __builtin_ia32_psubusb128(tmp_V16c, tmp_V16c);
tmp_V8s = __builtin_ia32_psubusw128(tmp_V8s, tmp_V8s);
tmp_V8s = __builtin_ia32_pmulhw128(tmp_V8s, tmp_V8s);
- tmp_V16c = __builtin_ia32_pavgb128(tmp_V16c, tmp_V16c);
- tmp_V8s = __builtin_ia32_pavgw128(tmp_V8s, tmp_V8s);
tmp_V16c = __builtin_ia32_pmaxub128(tmp_V16c, tmp_V16c);
tmp_V8s = __builtin_ia32_pmaxsw128(tmp_V8s, tmp_V8s);
tmp_V16c = __builtin_ia32_pminub128(tmp_V16c, tmp_V16c);
diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c
index 390c2e35bf..86bee451ec 100644
--- a/test/CodeGen/builtins.c
+++ b/test/CodeGen/builtins.c
@@ -317,6 +317,15 @@ void test_float_builtin_ops(float F, double D, long double LD) {
resld = __builtin_floorl(LD);
// CHECK: call x86_fp80 @llvm.floor.f80
+ resf = __builtin_sqrtf(F);
+ // CHECK: call float @sqrtf(
+
+ resd = __builtin_sqrt(D);
+ // CHECK: call double @sqrt(
+
+ resld = __builtin_sqrtl(LD);
+ // CHECK: call x86_fp80 @sqrtl(
+
resf = __builtin_truncf(F);
// CHECK: call float @llvm.trunc.f32
@@ -378,229 +387,385 @@ long long test_builtin_readcyclecounter() {
#ifdef __x86_64__
// CHECK-LABEL: define void @test_builtin_os_log
-// CHECK: (i8* [[BUF:%.*]], i32 [[I:%.*]], i8* [[DATA:%.*]])
+// CHECK: (i8* %[[BUF:.*]], i32 %[[I:.*]], i8* %[[DATA:.*]])
void test_builtin_os_log(void *buf, int i, const char *data) {
volatile int len;
- // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
- // CHECK: store i32 [[I]], i32* [[I_ADDR:%.*]], align 4
- // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8
-
- // CHECK: store volatile i32 34
+ // CHECK: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[I_ADDR:.*]] = alloca i32, align 4
+ // CHECK: %[[DATA_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[LEN:.*]] = alloca i32, align 4
+ // CHECK: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+ // CHECK: store i32 %[[I]], i32* %[[I_ADDR]], align 4
+ // CHECK: store i8* %[[DATA]], i8** %[[DATA_ADDR]], align 8
+
+ // CHECK: store volatile i32 34, i32* %[[LEN]]
len = __builtin_os_log_format_buffer_size("%d %{public}s %{private}.16P", i, data, data);
- // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
- // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
- // CHECK: store i8 3, i8* [[SUMMARY]]
- // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
- // CHECK: store i8 4, i8* [[NUM_ARGS]]
- //
- // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
- // CHECK: store i8 0, i8* [[ARG1_DESC]]
- // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
- // CHECK: store i8 4, i8* [[ARG1_SIZE]]
- // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
- // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32*
- // CHECK: [[I2:%.*]] = load i32, i32* [[I_ADDR]]
- // CHECK: store i32 [[I2]], i32* [[ARG1_INT]]
-
- // CHECK: [[ARG2_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 8
- // CHECK: store i8 34, i8* [[ARG2_DESC]]
- // CHECK: [[ARG2_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 9
- // CHECK: store i8 8, i8* [[ARG2_SIZE]]
- // CHECK: [[ARG2:%.*]] = getelementptr i8, i8* [[BUF2]], i64 10
- // CHECK: [[ARG2_PTR:%.*]] = bitcast i8* [[ARG2]] to i8**
- // CHECK: [[DATA2:%.*]] = load i8*, i8** [[DATA_ADDR]]
- // CHECK: store i8* [[DATA2]], i8** [[ARG2_PTR]]
-
- // CHECK: [[ARG3_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 18
- // CHECK: store i8 17, i8* [[ARG3_DESC]]
- // CHECK: [[ARG3_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 19
- // CHECK: store i8 4, i8* [[ARG3_SIZE]]
- // CHECK: [[ARG3:%.*]] = getelementptr i8, i8* [[BUF2]], i64 20
- // CHECK: [[ARG3_INT:%.*]] = bitcast i8* [[ARG3]] to i32*
- // CHECK: store i32 16, i32* [[ARG3_INT]]
-
- // CHECK: [[ARG4_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 24
- // CHECK: store i8 49, i8* [[ARG4_DESC]]
- // CHECK: [[ARG4_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 25
- // CHECK: store i8 8, i8* [[ARG4_SIZE]]
- // CHECK: [[ARG4:%.*]] = getelementptr i8, i8* [[BUF2]], i64 26
- // CHECK: [[ARG4_PTR:%.*]] = bitcast i8* [[ARG4]] to i8**
- // CHECK: [[DATA3:%.*]] = load i8*, i8** [[DATA_ADDR]]
- // CHECK: store i8* [[DATA3]], i8** [[ARG4_PTR]]
-
+ // CHECK: %[[V1:.*]] = load i8*, i8** %[[BUF_ADDR]]
+ // CHECK: %[[V2:.*]] = load i32, i32* %[[I_ADDR]]
+ // CHECK: %[[V3:.*]] = load i8*, i8** %[[DATA_ADDR]]
+ // CHECK: %[[V4:.*]] = ptrtoint i8* %[[V3]] to i64
+ // CHECK: %[[V5:.*]] = load i8*, i8** %[[DATA_ADDR]]
+ // CHECK: %[[V6:.*]] = ptrtoint i8* %[[V5]] to i64
+ // CHECK: call void @__os_log_helper_1_3_4_4_0_8_34_4_17_8_49(i8* %[[V1]], i32 %[[V2]], i64 %[[V4]], i32 16, i64 %[[V6]])
__builtin_os_log_format(buf, "%d %{public}s %{private}.16P", i, data, data);
}
-// CHECK-LABEL: define void @test_builtin_os_log_errno
-// CHECK: (i8* [[BUF:%.*]], i8* [[DATA:%.*]])
-void test_builtin_os_log_errno(void *buf, const char *data) {
- volatile int len;
- // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
- // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8
-
- // CHECK: store volatile i32 2
- len = __builtin_os_log_format_buffer_size("%S");
-
- // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
- // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
- // CHECK: store i8 2, i8* [[SUMMARY]]
- // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
- // CHECK: store i8 1, i8* [[NUM_ARGS]]
-
- // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
- // CHECK: store i8 96, i8* [[ARG1_DESC]]
- // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
- // CHECK: store i8 0, i8* [[ARG1_SIZE]]
- // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
- // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32*
- // CHECK: store i32 0, i32* [[ARG1_INT]]
-
- __builtin_os_log_format(buf, "%m");
-}
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_3_4_4_0_8_34_4_17_8_49
+// CHECK: (i8* %[[BUFFER:.*]], i32 %[[ARG0:.*]], i64 %[[ARG1:.*]], i32 %[[ARG2:.*]], i64 %[[ARG3:.*]])
+
+// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[ARG0_ADDR:.*]] = alloca i32, align 4
+// CHECK: %[[ARG1_ADDR:.*]] = alloca i64, align 8
+// CHECK: %[[ARG2_ADDR:.*]] = alloca i32, align 4
+// CHECK: %[[ARG3_ADDR:.*]] = alloca i64, align 8
+// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK: store i32 %[[ARG0]], i32* %[[ARG0_ADDR]], align 4
+// CHECK: store i64 %[[ARG1]], i64* %[[ARG1_ADDR]], align 8
+// CHECK: store i32 %[[ARG2]], i32* %[[ARG2_ADDR]], align 4
+// CHECK: store i64 %[[ARG3]], i64* %[[ARG3_ADDR]], align 8
+// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK: store i8 3, i8* %[[SUMMARY]], align 1
+// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK: store i8 4, i8* %[[NUMARGS]], align 1
+// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK: store i8 0, i8* %[[ARGDESCRIPTOR]], align 1
+// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK: store i8 4, i8* %[[ARGSIZE]], align 1
+// CHECK: %[[ARGDATA:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+// CHECK: %[[ARGDATACAST:.*]] = bitcast i8* %[[ARGDATA]] to i32*
+// CHECK: %[[V0:.*]] = load i32, i32* %[[ARG0_ADDR]], align 4
+// CHECK: store i32 %[[V0]], i32* %[[ARGDATACAST]], align 1
+// CHECK: %[[ARGDESCRIPTOR1:.*]] = getelementptr i8, i8* %[[BUF]], i64 8
+// CHECK: store i8 34, i8* %[[ARGDESCRIPTOR1]], align 1
+// CHECK: %[[ARGSIZE2:.*]] = getelementptr i8, i8* %[[BUF]], i64 9
+// CHECK: store i8 8, i8* %[[ARGSIZE2]], align 1
+// CHECK: %[[ARGDATA3:.*]] = getelementptr i8, i8* %[[BUF]], i64 10
+// CHECK: %[[ARGDATACAST4:.*]] = bitcast i8* %[[ARGDATA3]] to i64*
+// CHECK: %[[V1:.*]] = load i64, i64* %[[ARG1_ADDR]], align 8
+// CHECK: store i64 %[[V1]], i64* %[[ARGDATACAST4]], align 1
+// CHECK: %[[ARGDESCRIPTOR5:.*]] = getelementptr i8, i8* %[[BUF]], i64 18
+// CHECK: store i8 17, i8* %[[ARGDESCRIPTOR5]], align 1
+// CHECK: %[[ARGSIZE6:.*]] = getelementptr i8, i8* %[[BUF]], i64 19
+// CHECK: store i8 4, i8* %[[ARGSIZE6]], align 1
+// CHECK: %[[ARGDATA7:.*]] = getelementptr i8, i8* %[[BUF]], i64 20
+// CHECK: %[[ARGDATACAST8:.*]] = bitcast i8* %[[ARGDATA7]] to i32*
+// CHECK: %[[V2:.*]] = load i32, i32* %[[ARG2_ADDR]], align 4
+// CHECK: store i32 %[[V2]], i32* %[[ARGDATACAST8]], align 1
+// CHECK: %[[ARGDESCRIPTOR9:.*]] = getelementptr i8, i8* %[[BUF]], i64 24
+// CHECK: store i8 49, i8* %[[ARGDESCRIPTOR9]], align 1
+// CHECK: %[[ARGSIZE10:.*]] = getelementptr i8, i8* %[[BUF]], i64 25
+// CHECK: store i8 8, i8* %[[ARGSIZE10]], align 1
+// CHECK: %[[ARGDATA11:.*]] = getelementptr i8, i8* %[[BUF]], i64 26
+// CHECK: %[[ARGDATACAST12:.*]] = bitcast i8* %[[ARGDATA11]] to i64*
+// CHECK: %[[V3:.*]] = load i64, i64* %[[ARG3_ADDR]], align 8
+// CHECK: store i64 %[[V3]], i64* %[[ARGDATACAST12]], align 1
// CHECK-LABEL: define void @test_builtin_os_log_wide
-// CHECK: (i8* [[BUF:%.*]], i8* [[DATA:%.*]], i32* [[STR:%.*]])
+// CHECK: (i8* %[[BUF:.*]], i8* %[[DATA:.*]], i32* %[[STR:.*]])
typedef int wchar_t;
void test_builtin_os_log_wide(void *buf, const char *data, wchar_t *str) {
volatile int len;
- // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
- // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8
- // CHECK: store i32* [[STR]], i32** [[STR_ADDR:%.*]],
- // CHECK: store volatile i32 12
+ // CHECK: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[DATA_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[STR_ADDR:.*]] = alloca i32*, align 8
+ // CHECK: %[[LEN:.*]] = alloca i32, align 4
+ // CHECK: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+ // CHECK: store i8* %[[DATA]], i8** %[[DATA_ADDR]], align 8
+ // CHECK: store i32* %[[STR]], i32** %[[STR_ADDR]], align 8
+
+ // CHECK: store volatile i32 12, i32* %[[LEN]], align 4
len = __builtin_os_log_format_buffer_size("%S", str);
- // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
- // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
- // CHECK: store i8 2, i8* [[SUMMARY]]
- // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
- // CHECK: store i8 1, i8* [[NUM_ARGS]]
-
- // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
- // CHECK: store i8 80, i8* [[ARG1_DESC]]
- // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
- // CHECK: store i8 8, i8* [[ARG1_SIZE]]
- // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
- // CHECK: [[ARG1_PTR:%.*]] = bitcast i8* [[ARG1]] to i32**
- // CHECK: [[STR2:%.*]] = load i32*, i32** [[STR_ADDR]]
- // CHECK: store i32* [[STR2]], i32** [[ARG1_PTR]]
+ // CHECK: %[[V1:.*]] = load i8*, i8** %[[BUF_ADDR]], align 8
+ // CHECK: %[[V2:.*]] = load i32*, i32** %[[STR_ADDR]], align 8
+ // CHECK: %[[V3:.*]] = ptrtoint i32* %[[V2]] to i64
+ // CHECK: call void @__os_log_helper_1_2_1_8_80(i8* %[[V1]], i64 %[[V3]])
__builtin_os_log_format(buf, "%S", str);
}
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_2_1_8_80
+// CHECK: (i8* %[[BUFFER:.*]], i64 %[[ARG0:.*]])
+
+// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[ARG0_ADDR:.*]] = alloca i64, align 8
+// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK: store i64 %[[ARG0]], i64* %[[ARG0_ADDR]], align 8
+// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK: store i8 2, i8* %[[SUMMARY]], align 1
+// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK: store i8 1, i8* %[[NUMARGS]], align 1
+// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK: store i8 80, i8* %[[ARGDESCRIPTOR]], align 1
+// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK: store i8 8, i8* %[[ARGSIZE]], align 1
+// CHECK: %[[ARGDATA:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+// CHECK: %[[ARGDATACAST:.*]] = bitcast i8* %[[ARGDATA]] to i64*
+// CHECK: %[[V0:.*]] = load i64, i64* %[[ARG0_ADDR]], align 8
+// CHECK: store i64 %[[V0]], i64* %[[ARGDATACAST]], align 1
+
// CHECK-LABEL: define void @test_builtin_os_log_precision_width
-// CHECK: (i8* [[BUF:%.*]], i8* [[DATA:%.*]], i32 [[PRECISION:%.*]], i32 [[WIDTH:%.*]])
+// CHECK: (i8* %[[BUF:.*]], i8* %[[DATA:.*]], i32 %[[PRECISION:.*]], i32 %[[WIDTH:.*]])
void test_builtin_os_log_precision_width(void *buf, const char *data,
int precision, int width) {
volatile int len;
- // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
- // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8
- // CHECK: store i32 [[PRECISION]], i32* [[PRECISION_ADDR:%.*]], align 4
- // CHECK: store i32 [[WIDTH]], i32* [[WIDTH_ADDR:%.*]], align 4
-
- // CHECK: store volatile i32 24,
+ // CHECK: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[DATA_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[PRECISION_ADDR:.*]] = alloca i32, align 4
+ // CHECK: %[[WIDTH_ADDR:.*]] = alloca i32, align 4
+ // CHECK: %[[LEN:.*]] = alloca i32, align 4
+ // CHECK: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+ // CHECK: store i8* %[[DATA]], i8** %[[DATA_ADDR]], align 8
+ // CHECK: store i32 %[[PRECISION]], i32* %[[PRECISION_ADDR]], align 4
+ // CHECK: store i32 %[[WIDTH]], i32* %[[WIDTH_ADDR]], align 4
+
+ // CHECK: store volatile i32 24, i32* %[[LEN]], align 4
len = __builtin_os_log_format_buffer_size("Hello %*.*s World", precision, width, data);
- // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
- // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
- // CHECK: store i8 2, i8* [[SUMMARY]]
- // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
- // CHECK: store i8 3, i8* [[NUM_ARGS]]
-
- // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
- // CHECK: store i8 0, i8* [[ARG1_DESC]]
- // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
- // CHECK: store i8 4, i8* [[ARG1_SIZE]]
- // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
- // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32*
- // CHECK: [[ARG1_VAL:%.*]] = load i32, i32* [[PRECISION_ADDR]]
- // CHECK: store i32 [[ARG1_VAL]], i32* [[ARG1_INT]]
-
- // CHECK: [[ARG2_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 8
- // CHECK: store i8 16, i8* [[ARG2_DESC]]
- // CHECK: [[ARG2_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 9
- // CHECK: store i8 4, i8* [[ARG2_SIZE]]
- // CHECK: [[ARG2:%.*]] = getelementptr i8, i8* [[BUF2]], i64 10
- // CHECK: [[ARG2_INT:%.*]] = bitcast i8* [[ARG2]] to i32*
- // CHECK: [[ARG2_VAL:%.*]] = load i32, i32* [[WIDTH_ADDR]]
- // CHECK: store i32 [[ARG2_VAL]], i32* [[ARG2_INT]]
-
- // CHECK: [[ARG3_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 14
- // CHECK: store i8 32, i8* [[ARG3_DESC]]
- // CHECK: [[ARG3_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 15
- // CHECK: store i8 8, i8* [[ARG3_SIZE]]
- // CHECK: [[ARG3:%.*]] = getelementptr i8, i8* [[BUF2]], i64 16
- // CHECK: [[ARG3_PTR:%.*]] = bitcast i8* [[ARG3]] to i8**
- // CHECK: [[DATA2:%.*]] = load i8*, i8** [[DATA_ADDR]]
- // CHECK: store i8* [[DATA2]], i8** [[ARG3_PTR]]
-
+ // CHECK: %[[V1:.*]] = load i8*, i8** %[[BUF_ADDR]], align 8
+ // CHECK: %[[V2:.*]] = load i32, i32* %[[PRECISION_ADDR]], align 4
+ // CHECK: %[[V3:.*]] = load i32, i32* %[[WIDTH_ADDR]], align 4
+ // CHECK: %[[V4:.*]] = load i8*, i8** %[[DATA_ADDR]], align 8
+ // CHECK: %[[V5:.*]] = ptrtoint i8* %[[V4]] to i64
+ // CHECK: call void @__os_log_helper_1_2_3_4_0_4_16_8_32(i8* %[[V1]], i32 %[[V2]], i32 %[[V3]], i64 %[[V5]])
__builtin_os_log_format(buf, "Hello %*.*s World", precision, width, data);
}
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_2_3_4_0_4_16_8_32
+// CHECK: (i8* %[[BUFFER:.*]], i32 %[[ARG0:.*]], i32 %[[ARG1:.*]], i64 %[[ARG2:.*]])
+
+// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[ARG0_ADDR:.*]] = alloca i32, align 4
+// CHECK: %[[ARG1_ADDR:.*]] = alloca i32, align 4
+// CHECK: %[[ARG2_ADDR:.*]] = alloca i64, align 8
+// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK: store i32 %[[ARG0]], i32* %[[ARG0_ADDR]], align 4
+// CHECK: store i32 %[[ARG1]], i32* %[[ARG1_ADDR]], align 4
+// CHECK: store i64 %[[ARG2]], i64* %[[ARG2_ADDR]], align 8
+// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK: store i8 2, i8* %[[SUMMARY]], align 1
+// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK: store i8 3, i8* %[[NUMARGS]], align 1
+// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK: store i8 0, i8* %[[ARGDESCRIPTOR]], align 1
+// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK: store i8 4, i8* %[[ARGSIZE]], align 1
+// CHECK: %[[ARGDATA:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+// CHECK: %[[ARGDATACAST:.*]] = bitcast i8* %[[ARGDATA]] to i32*
+// CHECK: %[[V0:.*]] = load i32, i32* %[[ARG0_ADDR]], align 4
+// CHECK: store i32 %[[V0]], i32* %[[ARGDATACAST]], align 1
+// CHECK: %[[ARGDESCRIPTOR1:.*]] = getelementptr i8, i8* %[[BUF]], i64 8
+// CHECK: store i8 16, i8* %[[ARGDESCRIPTOR1]], align 1
+// CHECK: %[[ARGSIZE2:.*]] = getelementptr i8, i8* %[[BUF]], i64 9
+// CHECK: store i8 4, i8* %[[ARGSIZE2]], align 1
+// CHECK: %[[ARGDATA3:.*]] = getelementptr i8, i8* %[[BUF]], i64 10
+// CHECK: %[[ARGDATACAST4:.*]] = bitcast i8* %[[ARGDATA3]] to i32*
+// CHECK: %[[V1:.*]] = load i32, i32* %[[ARG1_ADDR]], align 4
+// CHECK: store i32 %[[V1]], i32* %[[ARGDATACAST4]], align 1
+// CHECK: %[[ARGDESCRIPTOR5:.*]] = getelementptr i8, i8* %[[BUF]], i64 14
+// CHECK: store i8 32, i8* %[[ARGDESCRIPTOR5]], align 1
+// CHECK: %[[ARGSIZE6:.*]] = getelementptr i8, i8* %[[BUF]], i64 15
+// CHECK: store i8 8, i8* %[[ARGSIZE6]], align 1
+// CHECK: %[[ARGDATA7:.*]] = getelementptr i8, i8* %[[BUF]], i64 16
+// CHECK: %[[ARGDATACAST8:.*]] = bitcast i8* %[[ARGDATA7]] to i64*
+// CHECK: %[[V2:.*]] = load i64, i64* %[[ARG2_ADDR]], align 8
+// CHECK: store i64 %[[V2]], i64* %[[ARGDATACAST8]], align 1
+
// CHECK-LABEL: define void @test_builtin_os_log_invalid
-// CHECK: (i8* [[BUF:%.*]], i32 [[DATA:%.*]])
+// CHECK: (i8* %[[BUF:.*]], i32 %[[DATA:.*]])
void test_builtin_os_log_invalid(void *buf, int data) {
volatile int len;
- // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
- // CHECK: store i32 [[DATA]], i32* [[DATA_ADDR:%.*]]
+ // CHECK: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[DATA_ADDR:.*]] = alloca i32, align 4
+ // CHECK: %[[LEN:.*]] = alloca i32, align 4
+ // CHECK: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+ // CHECK: store i32 %[[DATA]], i32* %[[DATA_ADDR]], align 4
- // CHECK: store volatile i32 8,
+ // CHECK: store volatile i32 8, i32* %[[LEN]], align 4
len = __builtin_os_log_format_buffer_size("invalid specifier %: %d even a trailing one%", data);
- // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
- // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
- // CHECK: store i8 0, i8* [[SUMMARY]]
- // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
- // CHECK: store i8 1, i8* [[NUM_ARGS]]
-
- // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
- // CHECK: store i8 0, i8* [[ARG1_DESC]]
- // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
- // CHECK: store i8 4, i8* [[ARG1_SIZE]]
- // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
- // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32*
- // CHECK: [[ARG1_VAL:%.*]] = load i32, i32* [[DATA_ADDR]]
- // CHECK: store i32 [[ARG1_VAL]], i32* [[ARG1_INT]]
+ // CHECK: %[[V1:.*]] = load i8*, i8** %[[BUF_ADDR]], align 8
+ // CHECK: %[[V2:.*]] = load i32, i32* %[[DATA_ADDR]], align 4
+ // CHECK: call void @__os_log_helper_1_0_1_4_0(i8* %[[V1]], i32 %[[V2]])
__builtin_os_log_format(buf, "invalid specifier %: %d even a trailing one%", data);
}
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_0_1_4_0
+// CHECK: (i8* %[[BUFFER:.*]], i32 %[[ARG0:.*]])
+
+// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[ARG0_ADDR:.*]] = alloca i32, align 4
+// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK: store i32 %[[ARG0]], i32* %[[ARG0_ADDR]], align 4
+// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK: store i8 0, i8* %[[SUMMARY]], align 1
+// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK: store i8 1, i8* %[[NUMARGS]], align 1
+// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK: store i8 0, i8* %[[ARGDESCRIPTOR]], align 1
+// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK: store i8 4, i8* %[[ARGSIZE]], align 1
+// CHECK: %[[ARGDATA:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+// CHECK: %[[ARGDATACAST:.*]] = bitcast i8* %[[ARGDATA]] to i32*
+// CHECK: %[[V0:.*]] = load i32, i32* %[[ARG0_ADDR]], align 4
+// CHECK: store i32 %[[V0]], i32* %[[ARGDATACAST]], align 1
+
// CHECK-LABEL: define void @test_builtin_os_log_percent
-// CHECK: (i8* [[BUF:%.*]], i8* [[DATA1:%.*]], i8* [[DATA2:%.*]])
+// CHECK: (i8* %[[BUF:.*]], i8* %[[DATA1:.*]], i8* %[[DATA2:.*]])
// Check that the %% which does not consume any argument is correctly handled
void test_builtin_os_log_percent(void *buf, const char *data1, const char *data2) {
volatile int len;
- // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
- // CHECK: store i8* [[DATA1]], i8** [[DATA1_ADDR:%.*]], align 8
- // CHECK: store i8* [[DATA2]], i8** [[DATA2_ADDR:%.*]], align 8
- // CHECK: store volatile i32 22
+ // CHECK: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[DATA1_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[DATA2_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[LEN:.*]] = alloca i32, align 4
+ // CHECK: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+ // CHECK: store i8* %[[DATA1]], i8** %[[DATA1_ADDR]], align 8
+ // CHECK: store i8* %[[DATA2]], i8** %[[DATA2_ADDR]], align 8
+ // CHECK: store volatile i32 22, i32* %[[LEN]], align 4
+
len = __builtin_os_log_format_buffer_size("%s %% %s", data1, data2);
- // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
- // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
- // CHECK: store i8 2, i8* [[SUMMARY]]
- // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
- // CHECK: store i8 2, i8* [[NUM_ARGS]]
- //
- // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
- // CHECK: store i8 32, i8* [[ARG1_DESC]]
- // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
- // CHECK: store i8 8, i8* [[ARG1_SIZE]]
- // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
- // CHECK: [[ARG1_PTR:%.*]] = bitcast i8* [[ARG1]] to i8**
- // CHECK: [[DATA1:%.*]] = load i8*, i8** [[DATA1_ADDR]]
- // CHECK: store i8* [[DATA1]], i8** [[ARG1_PTR]]
- //
- // CHECK: [[ARG2_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 12
- // CHECK: store i8 32, i8* [[ARG2_DESC]]
- // CHECK: [[ARG2_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 13
- // CHECK: store i8 8, i8* [[ARG2_SIZE]]
- // CHECK: [[ARG2:%.*]] = getelementptr i8, i8* [[BUF2]], i64 14
- // CHECK: [[ARG2_PTR:%.*]] = bitcast i8* [[ARG2]] to i8**
- // CHECK: [[DATA2:%.*]] = load i8*, i8** [[DATA2_ADDR]]
- // CHECK: store i8* [[DATA2]], i8** [[ARG2_PTR]]
+ // CHECK: %[[V1:.*]] = load i8*, i8** %[[BUF_ADDR]], align 8
+ // CHECK: %[[V2:.*]] = load i8*, i8** %[[DATA1_ADDR]], align 8
+ // CHECK: %[[V3:.*]] = ptrtoint i8* %[[V2]] to i64
+ // CHECK: %[[V4:.*]] = load i8*, i8** %[[DATA2_ADDR]], align 8
+ // CHECK: %[[V5:.*]] = ptrtoint i8* %[[V4]] to i64
+ // CHECK: call void @__os_log_helper_1_2_2_8_32_8_32(i8* %[[V1]], i64 %[[V3]], i64 %[[V5]])
+
__builtin_os_log_format(buf, "%s %% %s", data1, data2);
}
-#endif \ No newline at end of file
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_2_2_8_32_8_32
+// CHECK: (i8* %[[BUFFER:.*]], i64 %[[ARG0:.*]], i64 %[[ARG1:.*]])
+
+// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[ARG0_ADDR:.*]] = alloca i64, align 8
+// CHECK: %[[ARG1_ADDR:.*]] = alloca i64, align 8
+// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK: store i64 %[[ARG0]], i64* %[[ARG0_ADDR]], align 8
+// CHECK: store i64 %[[ARG1]], i64* %[[ARG1_ADDR]], align 8
+// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK: store i8 2, i8* %[[SUMMARY]], align 1
+// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK: store i8 2, i8* %[[NUMARGS]], align 1
+// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK: store i8 32, i8* %[[ARGDESCRIPTOR]], align 1
+// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK: store i8 8, i8* %[[ARGSIZE]], align 1
+// CHECK: %[[ARGDATA:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+// CHECK: %[[ARGDATACAST:.*]] = bitcast i8* %[[ARGDATA]] to i64*
+// CHECK: %[[V0:.*]] = load i64, i64* %[[ARG0_ADDR]], align 8
+// CHECK: store i64 %[[V0]], i64* %[[ARGDATACAST]], align 1
+// CHECK: %[[ARGDESCRIPTOR1:.*]] = getelementptr i8, i8* %[[BUF]], i64 12
+// CHECK: store i8 32, i8* %[[ARGDESCRIPTOR1]], align 1
+// CHECK: %[[ARGSIZE2:.*]] = getelementptr i8, i8* %[[BUF]], i64 13
+// CHECK: store i8 8, i8* %[[ARGSIZE2]], align 1
+// CHECK: %[[ARGDATA3:.*]] = getelementptr i8, i8* %[[BUF]], i64 14
+// CHECK: %[[ARGDATACAST4:.*]] = bitcast i8* %[[ARGDATA3]] to i64*
+// CHECK: %[[V1:.*]] = load i64, i64* %[[ARG1_ADDR]], align 8
+// CHECK: store i64 %[[V1]], i64* %[[ARGDATACAST4]], align 1
+
+// Check that the following two functions call the same helper function.
+
+// CHECK-LABEL: define void @test_builtin_os_log_merge_helper0
+// CHECK: call void @__os_log_helper_1_0_2_4_0_8_0(
+void test_builtin_os_log_merge_helper0(void *buf, int i, double d) {
+ __builtin_os_log_format(buf, "%d %f", i, d);
+}
+
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_0_2_4_0_8_0(
+
+// CHECK-LABEL: define void @test_builtin_os_log_merge_helper1
+// CHECK: call void @__os_log_helper_1_0_2_4_0_8_0(
+void test_builtin_os_log_merge_helper1(void *buf, unsigned u, long long ll) {
+ __builtin_os_log_format(buf, "%u %lld", u, ll);
+}
+
+// Check that this function doesn't write past the end of array 'buf'.
+
+// CHECK-LABEL: define void @test_builtin_os_log_errno
+void test_builtin_os_log_errno() {
+ // CHECK: %[[VLA:.*]] = alloca i8, i64 4, align 16
+ // CHECK: call void @__os_log_helper_16_2_1_0_96(i8* %[[VLA]])
+
+ char buf[__builtin_os_log_format_buffer_size("%m")];
+ __builtin_os_log_format(buf, "%m");
+}
+
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_16_2_1_0_96
+// CHECK: (i8* %[[BUFFER:.*]])
+
+// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK: store i8 2, i8* %[[SUMMARY]], align 16
+// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK: store i8 1, i8* %[[NUMARGS]], align 1
+// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 2
+// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK: store i8 0, i8* %[[ARGSIZE]], align 1
+// CHECK-NEXT: ret void
+
+// CHECK-LABEL: define void @test_builtin_os_log_long_double
+// CHECK: (i8* %[[BUF:.*]], x86_fp80 %[[LD:.*]])
+void test_builtin_os_log_long_double(void *buf, long double ld) {
+ // CHECK: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+ // CHECK: %[[LD_ADDR:.*]] = alloca x86_fp80, align 16
+ // CHECK: %[[COERCE:.*]] = alloca i128, align 16
+ // CHECK: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+ // CHECK: store x86_fp80 %[[LD]], x86_fp80* %[[LD_ADDR]], align 16
+ // CHECK: %[[V0:.*]] = load i8*, i8** %[[BUF_ADDR]], align 8
+ // CHECK: %[[V1:.*]] = load x86_fp80, x86_fp80* %[[LD_ADDR]], align 16
+ // CHECK: %[[V2:.*]] = bitcast x86_fp80 %[[V1]] to i80
+ // CHECK: %[[V3:.*]] = zext i80 %[[V2]] to i128
+ // CHECK: store i128 %[[V3]], i128* %[[COERCE]], align 16
+ // CHECK: %[[V4:.*]] = bitcast i128* %[[COERCE]] to { i64, i64 }*
+ // CHECK: %[[V5:.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %[[V4]], i32 0, i32 0
+ // CHECK: %[[V6:.*]] = load i64, i64* %[[V5]], align 16
+ // CHECK: %[[V7:.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %[[V4]], i32 0, i32 1
+ // CHECK: %[[V8:.*]] = load i64, i64* %[[V7]], align 8
+ // CHECK: call void @__os_log_helper_1_0_1_16_0(i8* %[[V0]], i64 %[[V6]], i64 %[[V8]])
+
+ __builtin_os_log_format(buf, "%Lf", ld);
+}
+
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_0_1_16_0
+// CHECK: (i8* %[[BUFFER:.*]], i64 %[[ARG0_COERCE0:.*]], i64 %[[ARG0_COERCE1:.*]])
+
+// CHECK: %[[ARG0:.*]] = alloca i128, align 16
+// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK: %[[ARG0_ADDR:.*]] = alloca i128, align 16
+// CHECK: %[[V0:.*]] = bitcast i128* %[[ARG0]] to { i64, i64 }*
+// CHECK: %[[V1:.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %[[V0]], i32 0, i32 0
+// CHECK: store i64 %[[ARG0_COERCE0]], i64* %[[V1]], align 16
+// CHECK: %[[V2:.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %[[V0]], i32 0, i32 1
+// CHECK: store i64 %[[ARG0_COERCE1]], i64* %[[V2]], align 8
+// CHECK: %[[ARG01:.*]] = load i128, i128* %[[ARG0]], align 16
+// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK: store i128 %[[ARG01]], i128* %[[ARG0_ADDR]], align 16
+// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK: store i8 0, i8* %[[SUMMARY]], align 1
+// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK: store i8 1, i8* %[[NUMARGS]], align 1
+// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK: store i8 0, i8* %[[ARGDESCRIPTOR]], align 1
+// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK: store i8 16, i8* %[[ARGSIZE]], align 1
+// CHECK: %[[ARGDATA:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+// CHECK: %[[ARGDATACAST:.*]] = bitcast i8* %[[ARGDATA]] to i128*
+// CHECK: %[[V3:.*]] = load i128, i128* %[[ARG0_ADDR]], align 16
+// CHECK: store i128 %[[V3]], i128* %[[ARGDATACAST]], align 1
+
+#endif
diff --git a/test/CodeGen/captured-statements.c b/test/CodeGen/captured-statements.c
index 607ec8e55f..68ff2517be 100644
--- a/test/CodeGen/captured-statements.c
+++ b/test/CodeGen/captured-statements.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o %t
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o %t -debug-info-kind=limited
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-GLOBALS
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2
@@ -98,3 +98,8 @@ void dont_capture_global() {
// CHECK-GLOBALS: load i32, i32* @global
// CHECK-GLOBALS: load i32, i32* @
// CHECK-GLOBALS: load i32, i32* @e
+
+// CHECK-GLOBALS-NOT: DIFlagObjectPointer
+// CHECK-1-NOT: DIFlagObjectPointer
+// CHECK-2-NOT: DIFlagObjectPointer
+// CHECK-3-NOT: DIFlagObjectPointer
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index d3fc17620c..7915ed9db1 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -35,14 +35,8 @@ void foo() {
union { int i; } u;
// 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: %[[CHECK0:.*]] = icmp uge i64 %[[SIZE]], 4
-
- // CHECK-COMMON: %[[PTRTOINT:.*]] = ptrtoint {{.*}}* %[[PTR]] to i64
- // CHECK-COMMON-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
- // CHECK-COMMON-NEXT: %[[CHECK1:.*]] = icmp eq i64 %[[MISALIGN]], 0
-
- // CHECK-COMMON: %[[OK:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
+ // CHECK-COMMON-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* %[[I8PTR]], i1 false, i1 false)
+ // CHECK-COMMON-NEXT: %[[OK:.*]] = icmp uge i64 %[[SIZE]], 4
// CHECK-UBSAN: br i1 %[[OK]], {{.*}} !prof ![[WEIGHT_MD:.*]], !nosanitize
// CHECK-TRAP: br i1 %[[OK]], {{.*}}
@@ -65,8 +59,7 @@ int bar(int *a) {
// CHECK-COMMON-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
// CHECK-COMMON-NEXT: icmp eq i64 %[[MISALIGN]], 0
- // CHECK-UBSAN: %[[ARG:.*]] = ptrtoint
- // CHECK-UBSAN-NEXT: call void @__ubsan_handle_type_mismatch_v1(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), i64 %[[ARG]])
+ // CHECK-UBSAN: call void @__ubsan_handle_type_mismatch_v1(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), i64 %[[PTRINT]])
// CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
// CHECK-TRAP-NEXT: unreachable
diff --git a/test/CodeGen/cfi-check-fail.c b/test/CodeGen/cfi-check-fail.c
index b850193b54..0eb786ab96 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/cfi-icall-cross-dso.c b/test/CodeGen/cfi-icall-cross-dso.c
index 636a9e4aed..43ab0e73b1 100644
--- a/test/CodeGen/cfi-icall-cross-dso.c
+++ b/test/CodeGen/cfi-icall-cross-dso.c
@@ -46,7 +46,7 @@ void caller(void (*f)()) {
// Check that we emit both string and hash based type entries for static void g(),
// and don't emit them for the declaration of h().
-// CHECK: define internal void @g({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_ID:![0-9]+]]
+// CHECK: define internal void @g({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_GENERALIZED:![0-9]+]] !type [[TVOID_ID:![0-9]+]]
static void g(void) {}
// CHECK: declare void @h({{[^!]*$}}
@@ -60,9 +60,9 @@ Fn h1() {
return &h;
}
-// CHECK: define void @bar({{.*}} !type [[TNOPROTO:![0-9]+]] !type [[TNOPROTO_ID:![0-9]+]]
+// CHECK: define void @bar({{.*}} !type [[TNOPROTO:![0-9]+]] !type [[TNOPROTO_GENERALIZED:![0-9]+]] !type [[TNOPROTO_ID:![0-9]+]]
// ITANIUM: define available_externally void @foo({{[^!]*$}}
-// MS: define linkonce_odr void @foo({{.*}} !type [[TNOPROTO]] !type [[TNOPROTO_ID]]
+// MS: define linkonce_odr void @foo({{.*}} !type [[TNOPROTO]] !type [[TNOPROTO_GENERALIZED:![0-9]+]] !type [[TNOPROTO_ID]]
inline void foo() {}
void bar() { foo(); }
@@ -71,11 +71,15 @@ void bar() { foo(); }
// Check that the type entries are correct.
// ITANIUM: [[TVOID]] = !{i64 0, !"_ZTSFvvE"}
+// ITANIUM: [[TVOID_GENERALIZED]] = !{i64 0, !"_ZTSFvvE.generalized"}
// ITANIUM: [[TVOID_ID]] = !{i64 0, i64 9080559750644022485}
// ITANIUM: [[TNOPROTO]] = !{i64 0, !"_ZTSFvE"}
+// ITANIUM: [[TNOPROTO_GENERALIZED]] = !{i64 0, !"_ZTSFvE.generalized"}
// ITANIUM: [[TNOPROTO_ID]] = !{i64 0, i64 6588678392271548388}
// MS: [[TVOID]] = !{i64 0, !"?6AXXZ"}
+// MS: [[TVOID_GENERALIZED]] = !{i64 0, !"?6AXXZ.generalized"}
// MS: [[TVOID_ID]] = !{i64 0, i64 5113650790573562461}
// MS: [[TNOPROTO]] = !{i64 0, !"?6AX@Z"}
+// MS: [[TNOPROTO_GENERALIZED]] = !{i64 0, !"?6AX@Z.generalized"}
// MS: [[TNOPROTO_ID]] = !{i64 0, i64 4195979634929632483}
diff --git a/test/CodeGen/cfi-icall-generalize.c b/test/CodeGen/cfi-icall-generalize.c
new file mode 100644
index 0000000000..c7c7b30a7a
--- /dev/null
+++ b/test/CodeGen/cfi-icall-generalize.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=UNGENERALIZED %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fsanitize-cfi-icall-generalize-pointers -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GENERALIZED %s
+
+// Test that const char* is generalized to const void* and that const char** is
+// generalized to void*
+
+// CHECK: define i32** @f({{.*}} !type [[TYPE:![0-9]+]] !type [[TYPE_GENERALIZED:![0-9]+]]
+int** f(const char *a, const char **b) {
+ return (int**)0;
+}
+
+void g(int** (*fp)(const char *, const char **)) {
+ // UNGENERALIZED: call i1 @llvm.type.test(i8* {{.*}}, metadata !"_ZTSFPPiPKcPS2_E")
+ // GENERALIZED: call i1 @llvm.type.test(i8* {{.*}}, metadata !"_ZTSFPvPKvS_E.generalized")
+ fp(0, 0);
+}
+
+// CHECK: [[TYPE]] = !{i64 0, !"_ZTSFPPiPKcPS2_E"}
+// CHECK: [[TYPE_GENERALIZED]] = !{i64 0, !"_ZTSFPvPKvS_E.generalized"}
diff --git a/test/CodeGen/cfi-icall.c b/test/CodeGen/cfi-icall.c
index ed34f4f44b..5f346b66e8 100644
--- a/test/CodeGen/cfi-icall.c
+++ b/test/CodeGen/cfi-icall.c
@@ -3,22 +3,26 @@
// Tests that we assign appropriate identifiers to unprototyped functions.
-// CHECK: define void @f({{.*}} !type [[TVOID:![0-9]+]]
+// CHECK: define void @f({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_GENERALIZED:![0-9]+]]
void f() {
}
void xf();
-// CHECK: define void @g({{.*}} !type [[TINT:![0-9]+]]
+// CHECK: define void @g({{.*}} !type [[TINT:![0-9]+]] !type [[TINT_GENERALIZED:![0-9]+]]
void g(int b) {
void (*fp)() = b ? f : xf;
// ITANIUM: call i1 @llvm.type.test(i8* {{.*}}, metadata !"_ZTSFvE")
fp();
}
-// CHECK: declare !type [[TVOID:![0-9]+]] void @xf({{.*}}
+// CHECK: declare !type [[TVOID]] !type [[TVOID_GENERALIZED]] void @xf({{.*}}
// ITANIUM-DAG: [[TVOID]] = !{i64 0, !"_ZTSFvE"}
+// ITANIUM-DAG: [[TVOID_GENERALIZED]] = !{i64 0, !"_ZTSFvE.generalized"}
// ITANIUM-DAG: [[TINT]] = !{i64 0, !"_ZTSFviE"}
+// ITANIUM-DAG: [[TINT_GENERALIZED]] = !{i64 0, !"_ZTSFviE.generalized"}
// MS-DAG: [[TVOID]] = !{i64 0, !"?6AX@Z"}
+// MS-DAG: [[TVOID_GENERALIZED]] = !{i64 0, !"?6AX@Z.generalized"}
// MS-DAG: [[TINT]] = !{i64 0, !"?6AXH@Z"}
+// MS-DAG: [[TINT_GENERALIZED]] = !{i64 0, !"?6AXH@Z.generalized"}
diff --git a/test/CodeGen/cfi-unrelated-cast.cpp b/test/CodeGen/cfi-unrelated-cast.cpp
new file mode 100644
index 0000000000..d01cdf00b7
--- /dev/null
+++ b/test/CodeGen/cfi-unrelated-cast.cpp
@@ -0,0 +1,37 @@
+// STL allocators should not have unrelated-cast tests applied
+// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-unrelated-cast -emit-llvm -o - %s | FileCheck %s
+
+#include <stddef.h>
+
+template<class T>
+class myalloc {
+ public:
+ // CHECK: define{{.*}}allocateE{{.}}
+ // CHECK-NOT: llvm.type.test
+ T *allocate(size_t sz) {
+ return (T*)::operator new(sz);
+ }
+
+ // CHECK: define{{.*}}allocateE{{.}}PKv
+ // CHECK-NOT: llvm.type.test
+ T *allocate(size_t sz, const void *ptr) {
+ return (T*)::operator new(sz);
+ }
+
+ // CHECK: define{{.*}}differentName
+ // CHECK: llvm.type.test
+ T *differentName(size_t sz, const void *ptr) {
+ return (T*)::operator new(sz);
+ }
+};
+
+class C1 {
+ virtual void f() {}
+};
+
+C1 *f1() {
+ myalloc<C1> allocator;
+ (void)allocator.allocate(16);
+ (void)allocator.allocate(16, 0);
+ (void)allocator.differentName(16, 0);
+}
diff --git a/test/CodeGen/cleanup-destslot-simple.c b/test/CodeGen/cleanup-destslot-simple.c
index 848a8dc847..e7067e7b04 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/coff-aarch64-type-sizes.c b/test/CodeGen/coff-aarch64-type-sizes.c
new file mode 100644
index 0000000000..1d8a645204
--- /dev/null
+++ b/test/CodeGen/coff-aarch64-type-sizes.c
@@ -0,0 +1,88 @@
+// RUN: %clang_cc1 -triple aarch64-windows -emit-llvm -w -o - %s | FileCheck %s
+
+// CHECK: target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
+// CHECK: target triple = "aarch64--windows-msvc"
+
+int check_short() {
+ return sizeof(short);
+// CHECK: ret i32 2
+}
+
+int check_int() {
+ return sizeof(int);
+// CHECK: ret i32 4
+}
+
+int check_long() {
+ return sizeof(long);
+// CHECK: ret i32 4
+}
+
+int check_longlong() {
+ return sizeof(long long);
+// CHECK: ret i32 8
+}
+
+int check_int128() {
+ return sizeof(__int128);
+// CHECK: ret i32 16
+}
+
+int check_fp16() {
+ return sizeof(__fp16);
+// CHECK: ret i32 2
+}
+
+int check_float() {
+ return sizeof(float);
+// CHECK: ret i32 4
+}
+
+int check_double() {
+ return sizeof(double);
+// CHECK: ret i32 8
+}
+
+int check_longdouble() {
+ return sizeof(long double);
+// CHECK: ret i32 8
+}
+
+int check_floatComplex() {
+ return sizeof(float _Complex);
+// CHECK: ret i32 8
+}
+
+int check_doubleComplex() {
+ return sizeof(double _Complex);
+// CHECK: ret i32 16
+}
+
+int check_longdoubleComplex() {
+ return sizeof(long double _Complex);
+// CHECK: ret i32 16
+}
+
+int check_bool() {
+ return sizeof(_Bool);
+// CHECK: ret i32 1
+}
+
+int check_wchar() {
+ return sizeof(__WCHAR_TYPE__);
+// CHECK: ret i32 2
+}
+
+int check_wchar_unsigned() {
+ return (__WCHAR_TYPE__)-1 > (__WCHAR_TYPE__)0;
+// CHECK: ret i32 1
+}
+
+enum Small {
+ Item
+};
+
+int foo() {
+ return sizeof(enum Small);
+// CHECK: ret i32 4
+}
diff --git a/test/CodeGen/complex-math.c b/test/CodeGen/complex-math.c
index 96c7ad9cdb..8792ca14b9 100644
--- a/test/CodeGen/complex-math.c
+++ b/test/CodeGen/complex-math.c
@@ -2,7 +2,8 @@
// RUN: %clang_cc1 %s -O1 -emit-llvm -triple x86_64-pc-win64 -o - | FileCheck %s --check-prefix=X86
// RUN: %clang_cc1 %s -O1 -emit-llvm -triple i686-unknown-unknown -o - | FileCheck %s --check-prefix=X86
// RUN: %clang_cc1 %s -O1 -emit-llvm -triple powerpc-unknown-unknown -o - | FileCheck %s --check-prefix=PPC
-// RUN: %clang_cc1 %s -O1 -emit-llvm -triple armv7-none-linux-gnueabihf -o - | FileCheck %s --check-prefix=ARM
+// RUN %clang_cc1 %s -O1 -emit-llvm -triple armv7-none-linux-gnueabi -o - | FileCheck %s --check-prefix=ARM
+// RUN: %clang_cc1 %s -O1 -emit-llvm -triple armv7-none-linux-gnueabihf -o - | FileCheck %s --check-prefix=ARMHF
// RUN: %clang_cc1 %s -O1 -emit-llvm -triple thumbv7k-apple-watchos2.0 -o - -target-abi aapcs16 | FileCheck %s --check-prefix=ARM7K
float _Complex add_float_rr(float a, float b) {
@@ -476,8 +477,15 @@ _Bool ne_float_cc(float _Complex a, float _Complex b) {
// Check that the libcall will obtain proper calling convention on ARM
_Complex double foo(_Complex double a, _Complex double b) {
+ // These functions are not defined as floating point helper functions in
+ // Run-time ABI for the ARM architecture document so they must not always
+ // use the base AAPCS.
+
// ARM-LABEL: @foo(
- // ARM: call arm_aapcscc { double, double } @__muldc3
+ // ARM: call void { double, double } @__muldc3
+
+ // ARMHF-LABEL: @foo(
+ // ARMHF: call { double, double } @__muldc3
// ARM7K-LABEL: @foo(
// ARM7K: call { double, double } @__muldc3
diff --git a/test/CodeGen/darwin-ppc-varargs.c b/test/CodeGen/darwin-ppc-varargs.c
new file mode 100644
index 0000000000..c2a0d19223
--- /dev/null
+++ b/test/CodeGen/darwin-ppc-varargs.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple powerpc-apple-macosx10.5.0 -target-feature +altivec -Os -emit-llvm -o - %s | FileCheck %s
+
+int f(__builtin_va_list args) { return __builtin_va_arg(args, int); }
+
+// CHECK: @f(i8* {{.*}}[[PARAM:%[a-zA-Z0-9]+]])
+// CHECK: [[BITCAST:%[0-9]+]] = bitcast i8* [[PARAM]] to i32*
+// CHECK: [[VALUE:%[0-9]+]] = load i32, i32* [[BITCAST]], align 4
+// CHECK: ret i32 [[VALUE]]
+
+void h(vector int);
+int g(__builtin_va_list args) {
+ int i = __builtin_va_arg(args, int);
+ h(__builtin_va_arg(args, vector int));
+ int j = __builtin_va_arg(args, int);
+ return i + j;
+}
+
+// CHECK: @g(i8* {{.*}}[[PARAM:%[a-zA-Z0-9]+]])
+// CHECK: [[NEXT:%[-_.a-zA-Z0-9]+]] = getelementptr inbounds i8, i8* [[PARAM]], i32 4
+// CHECK: [[BITCAST:%[0-9]+]] = bitcast i8* [[PARAM]] to i32*
+// CHECK: [[LOAD:%[0-9]+]] = load i32, i32* [[BITCAST]], align 4
+// CHECK: [[PTRTOINT:%[0-9]+]] = ptrtoint i8* [[NEXT]] to i32
+// CHECK: [[ADD:%[0-9]+]] = add i32 [[PTRTOINT]], 15
+// CHECK: [[AND:%[0-9]+]] = and i32 [[ADD]], -16
+// CHECK: [[INTTOPTR:%[0-9]+]] = inttoptr i32 [[AND]] to <4 x i32>*
+// CHECK: [[ARG:%[0-9]]] = load <4 x i32>, <4 x i32>* [[INTTOPTR]], align 16
+// CHECK: call void @h(<4 x i32> [[ARG]]
+
diff --git a/test/CodeGen/debug-info-attributed-stmt.c b/test/CodeGen/debug-info-attributed-stmt.c
new file mode 100644
index 0000000000..b60aaf66ff
--- /dev/null
+++ b/test/CodeGen/debug-info-attributed-stmt.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -debug-info-kind=limited -emit-llvm %s -o - | FileCheck %s
+
+void f(_Bool b)
+{
+#pragma nounroll
+ while (b);
+}
+
+// CHECK: br label {{.*}}, !dbg ![[NUM:[0-9]+]]
+// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !dbg ![[NUM]]
+// CHECK: br label {{.*}}, !dbg ![[NUM]], !llvm.loop
+// CHECK: ![[NUM]] = !DILocation(line: 6,
diff --git a/test/CodeGen/debug-info-block-vars.c b/test/CodeGen/debug-info-block-vars.c
new file mode 100644
index 0000000000..e0bb61e5e8
--- /dev/null
+++ b/test/CodeGen/debug-info-block-vars.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O0 \
+// RUN: -triple x86_64-apple-darwin -o - %s | FileCheck %s
+// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O1 \
+// RUN: -triple x86_64-apple-darwin -o - %s \
+// RUN: | FileCheck --check-prefix=CHECK-OPT %s
+
+// CHECK: define internal void @__f_block_invoke(i8* %.block_descriptor)
+// CHECK: %.block_descriptor.addr = alloca i8*, align 8
+// CHECK: %block.addr = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*, align 8
+// CHECK: store i8* %.block_descriptor, i8** %.block_descriptor.addr, align 8
+// CHECK: call void @llvm.dbg.declare(metadata i8** %.block_descriptor.addr,
+// CHECK-SAME: metadata !DIExpression())
+// CHECK-OPT-NOT: alloca
+// CHECK-OPT: call void @llvm.dbg.value(metadata i8* %.block_descriptor,
+// CHECK-OPT-SAME: metadata !DIExpression())
+void f() {
+ a(^{
+ b();
+ });
+}
diff --git a/test/CodeGen/debug-info-global-constant.c b/test/CodeGen/debug-info-global-constant.c
index 4175f24675..8cb7f44ff3 100644
--- a/test/CodeGen/debug-info-global-constant.c
+++ b/test/CodeGen/debug-info-global-constant.c
@@ -5,11 +5,10 @@
// exactly once.
// CHECK: @i = internal constant i32 1, align 4, !dbg ![[I:[0-9]+]]
-// CHECK: ![[I]] = !DIGlobalVariableExpression(var: ![[VAR:.*]], expr: ![[EXPR:[0-9]+]])
+// CHECK: ![[I]] = !DIGlobalVariableExpression(var: ![[VAR:.*]], expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value))
// CHECK: ![[VAR]] = distinct !DIGlobalVariable(name: "i",
// CHECK: !DICompileUnit({{.*}}globals: ![[GLOBALS:[0-9]+]])
// CHECK: ![[GLOBALS]] = !{![[I]]}
-// CHECK: ![[EXPR]] = !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)
static const int i = 1;
void g(const int *, int);
diff --git a/test/CodeGen/debug-info-imported-entity.cpp b/test/CodeGen/debug-info-imported-entity.cpp
index c7935eda48..398536e581 100644
--- a/test/CodeGen/debug-info-imported-entity.cpp
+++ b/test/CodeGen/debug-info-imported-entity.cpp
@@ -5,5 +5,6 @@ using std::A; using ::A;
// CHECK: [[CompileUnit:![0-9]+]] = distinct !DICompileUnit({{.+}} imports: [[Imports:![0-9]+]]
// CHECK: [[Imports]] = !{[[ImportedEntity:![0-9]+]]}
-// CHECK: [[ImportedEntity]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CompileUnit]], entity: [[STDA:![0-9]+]], line: 4)
+// CHECK: [[ImportedEntity]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CompileUnit]], entity: [[STDA:![0-9]+]], file: [[FILE:![0-9]+]], line: 4)
// CHECK: [[STDA]] = !DICompositeType(tag: DW_TAG_class_type, name: "A",
+// CHECK: [[FILE]] = !DIFile(filename: {{.*}}debug-info-imported-entity.cpp
diff --git a/test/CodeGen/debug-info-lto.c b/test/CodeGen/debug-info-lto.c
new file mode 100644
index 0000000000..5dab0a1264
--- /dev/null
+++ b/test/CodeGen/debug-info-lto.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -flto -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
+// RUN: %clang_cc1 -flto=thin -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s
+// The "o" in LTO stands for optimization!
+// CHECK: !DICompileUnit({{.*}} isOptimized: true
diff --git a/test/CodeGen/debug-info-preprocessed-file.i b/test/CodeGen/debug-info-preprocessed-file.i
new file mode 100644
index 0000000000..d231b45d67
--- /dev/null
+++ b/test/CodeGen/debug-info-preprocessed-file.i
@@ -0,0 +1,11 @@
+# 1 "/foo/bar/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 -g -c -S -emit-llvm -o - %s | FileCheck %s
+// CHECK: !DICompileUnit(language: DW_LANG_C99, file: ![[FILE:[0-9]+]]
+// CHECK: ![[FILE]] = !DIFile(filename: "/foo/bar/preprocessed-input.c"
diff --git a/test/CodeGen/debug-info-static-const-fp.c b/test/CodeGen/debug-info-static-const-fp.c
index 4dfe057f2b..1b1da09f9e 100644
--- a/test/CodeGen/debug-info-static-const-fp.c
+++ b/test/CodeGen/debug-info-static-const-fp.c
@@ -33,22 +33,19 @@ int main() {
return hVal + fVal + dVal + ldVal;
}
-// CHECK: !DIGlobalVariableExpression(var: [[HVAL:.*]], expr: [[HEXPR:.*]])
+// CHECK: !DIGlobalVariableExpression(var: [[HVAL:.*]], expr: !DIExpression(DW_OP_constu, 16502, DW_OP_stack_value))
// CHECK: [[HVAL]] = distinct !DIGlobalVariable(name: "hVal",
// CHECK-SAME: isLocal: true, isDefinition: true
-// CHECK: [[HEXPR]] = !DIExpression(DW_OP_constu, 16502, DW_OP_stack_value)
-// CHECK: !DIGlobalVariableExpression(var: [[FVAL:.*]], expr: [[FEXPR:.*]])
+// CHECK: !DIGlobalVariableExpression(var: [[FVAL:.*]], expr: !DIExpression(DW_OP_constu, 3238681178, DW_OP_stack_value))
// CHECK: [[FVAL]] = distinct !DIGlobalVariable(name: "fVal",
// CHECK-SAME: isLocal: true, isDefinition: true
-// CHECK: [[FEXPR]] = !DIExpression(DW_OP_constu, 3238681178, DW_OP_stack_value)
-// CHECK: !DIGlobalVariableExpression(var: [[DVAL:.*]], expr: [[DEXPR:.*]])
+// CHECK: !DIGlobalVariableExpression(var: [[DVAL:.*]], expr: !DIExpression(DW_OP_constu, 4658387303597904457, DW_OP_stack_value))
// CHECK: [[DVAL]] = distinct !DIGlobalVariable(name: "dVal",
// CHECK-SAME: isLocal: true, isDefinition: true
-// CHECK: [[DEXPR]] = !DIExpression(DW_OP_constu, 4658387303597904457, DW_OP_stack_value)
// CHECK-LDlg-DAG: [[LDVAL:.*]] = distinct !DIGlobalVariable(name: "ldVal", {{.*}}, isLocal: true, isDefinition: true)
-// CHECK-LDlg-DAG: !DIGlobalVariableExpression(var: [[LDVAL]])
+// CHECK-LDlg-DAG: !DIGlobalVariableExpression(var: [[LDVAL]], expr: !DIExpression())
// CHECK-LDsm-DAG: [[LDVAL:.*]] = distinct !DIGlobalVariable(name: "ldVal", {{.*}}, isLocal: true, isDefinition: true)
// CHECK-LDsm-DAG: !DIGlobalVariableExpression(var: [[LDVAL]], expr:
diff --git a/test/CodeGen/debug-info-static.c b/test/CodeGen/debug-info-static.c
index 016f1e6e6c..d6ade2aee5 100644
--- a/test/CodeGen/debug-info-static.c
+++ b/test/CodeGen/debug-info-static.c
@@ -2,7 +2,7 @@
// CHECK: @f.xyzzy = internal global i32 0, align 4, !dbg [[XYZZY:![0-9]+]]
-// CHECK: [[XYZZY]] = !DIGlobalVariableExpression(var: [[VAR:.*]])
+// CHECK: [[XYZZY]] = !DIGlobalVariableExpression(var: [[VAR:.*]], expr: !DIExpression())
// CHECK: [[VAR]] = distinct !DIGlobalVariable
void f(void)
{
diff --git a/test/CodeGen/debug-info-vla.c b/test/CodeGen/debug-info-vla.c
index 371d106022..7928ca7613 100644
--- a/test/CodeGen/debug-info-vla.c
+++ b/test/CodeGen/debug-info-vla.c
@@ -3,9 +3,8 @@
void testVLAwithSize(int s)
{
// CHECK: dbg.declare
-// CHECK: dbg.declare({{.*}}, metadata ![[VAR:.*]], metadata ![[EXPR:.*]])
-// CHECK: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+2]]
-// CHECK: ![[EXPR]] = !DIExpression(DW_OP_deref)
+// CHECK: dbg.declare({{.*}}, metadata ![[VAR:.*]], metadata !DIExpression())
+// CHECK: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+1]]
int vla[s];
int i;
for (i = 0; i < s; i++) {
diff --git a/test/CodeGen/default-address-space.c b/test/CodeGen/default-address-space.c
new file mode 100644
index 0000000000..b7f40585b2
--- /dev/null
+++ b/test/CodeGen/default-address-space.c
@@ -0,0 +1,61 @@
+// 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(1) global i32 0
+// CHECK-DAG: @foo = common addrspace(1) global i32 0
+int foo;
+
+// PIZ-DAG: @ban = common addrspace(1) global [10 x i32] zeroinitializer
+// CHECK-DAG: @ban = common addrspace(1) global [10 x i32] zeroinitializer
+int ban[10];
+
+// PIZ-DAG: @A = common addrspace(1) global i32 addrspace(4)* null
+// PIZ-DAG: @B = common addrspace(1) global i32 addrspace(4)* null
+// CHECK-DAG: @A = common addrspace(1) global i32* null
+// CHECK-DAG: @B = common addrspace(1) global i32* null
+int *A;
+int *B;
+
+// COM-LABEL: define i32 @test1()
+// PIZ: load i32, i32 addrspace(4)* addrspacecast{{[^@]+}} @foo
+// CHECK: load i32, i32* addrspacecast{{[^@]+}} @foo
+int test1() { return foo; }
+
+// COM-LABEL: define i32 @test2(i32 %i)
+// COM: %[[addr:.*]] = getelementptr
+// PIZ: load i32, i32 addrspace(4)* %[[addr]]
+// PIZ-NEXT: ret i32
+// CHECK: load i32, i32* %[[addr]]
+// 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)* addrspacecast{{[^@]+}} @B
+// PIZ: load i32, i32 addrspace(4)*
+// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* addrspacecast{{[^@]+}} @A
+// PIZ: store i32 {{.*}}, i32 addrspace(4)*
+// CHECK: load i32*, i32** addrspacecast{{.*}} @B
+// CHECK: load i32, i32*
+// CHECK: load i32*, i32** addrspacecast{{.*}} @A
+// CHECK: store i32 {{.*}}, i32*
+void test3() {
+ *A = *B;
+}
+
+// PIZ-LABEL: define void @test4(i32 addrspace(4)* %a)
+// PIZ: %[[alloca:.*]] = alloca i32 addrspace(4)*
+// PIZ: %[[a_addr:.*]] = addrspacecast{{.*}} %[[alloca]] to i32 addrspace(4)* addrspace(4)*
+// PIZ: store i32 addrspace(4)* %a, i32 addrspace(4)* addrspace(4)* %[[a_addr]]
+// PIZ: %[[r0:.*]] = load i32 addrspace(4)*, i32 addrspace(4)* 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: %[[alloca:.*]] = alloca i32*, align 8, addrspace(5)
+// CHECK: %[[a_addr:.*]] = addrspacecast{{.*}} %[[alloca]] to i32**
+// CHECK: store i32* %a, i32** %[[a_addr]]
+// CHECK: %[[r0:.*]] = load i32*, i32** %[[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/dependent-lib.c b/test/CodeGen/dependent-lib.c
index 9cf49c88d7..7178a29692 100644
--- a/test/CodeGen/dependent-lib.c
+++ b/test/CodeGen/dependent-lib.c
@@ -3,14 +3,10 @@
// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple x86_64-pc-win32 -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s --dependent-lib=msvcrt -triple i686-pc-linux -emit-llvm -o - | FileCheck -check-prefix LINUX %s
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
+// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]]}
// CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"}
-// LINUX: !llvm.module.flags = !{{{.*}}}
-// LINUX: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
-// LINUX: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
+// LINUX: !llvm.linker.options = !{![[msvcrt:[0-9]+]]}
// LINUX: ![[msvcrt]] = !{!"-lmsvcrt"}
int f();
diff --git a/test/CodeGen/ffp-contract-fast-option.cpp b/test/CodeGen/ffp-contract-fast-option.cpp
new file mode 100644
index 0000000000..3db93de107
--- /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 61913b0aa3..52b7507959 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 0000000000..c2e52f070e
--- /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-asm.c b/test/CodeGen/fp-contract-on-asm.c
new file mode 100644
index 0000000000..01a1bd14a0
--- /dev/null
+++ b/test/CodeGen/fp-contract-on-asm.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -O3 -triple=aarch64-apple-ios -S -o - %s | FileCheck %s
+// REQUIRES: aarch64-registered-target
+
+float fma_test1(float a, float b, float c) {
+#pragma STDC FP_CONTRACT ON
+// CHECK-LABEL: fma_test1:
+// CHECK: fmadd
+ float x = a * b + c;
+ return x;
+}
+
+float fma_test2(float a, float b, float c) {
+// CHECK-LABEL: fma_test2:
+// CHECK: fmul
+// CHECK: fadd
+ float x = a * b + c;
+ return x;
+}
diff --git a/test/CodeGen/fp-contract-on-pragma.cpp b/test/CodeGen/fp-contract-on-pragma.cpp
new file mode 100644
index 0000000000..812a7176b5
--- /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/fp16vec-ops.c b/test/CodeGen/fp16vec-ops.c
new file mode 100644
index 0000000000..a99be4154b
--- /dev/null
+++ b/test/CodeGen/fp16vec-ops.c
@@ -0,0 +1,162 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -triple arm64-apple-ios9 -emit-llvm -o - -fallow-half-arguments-and-returns %s | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -triple armv7-apple-ios9 -emit-llvm -o - -fallow-half-arguments-and-returns %s | FileCheck %s --check-prefix=CHECK
+
+typedef __fp16 half4 __attribute__ ((vector_size (8)));
+typedef short short4 __attribute__ ((vector_size (8)));
+
+half4 hv0, hv1;
+short4 sv0;
+
+// CHECK-LABEL: testFP16Vec0
+// CHECK: %[[V0:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV:.*]] = fpext <4 x half> %[[V0]] to <4 x float>
+// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV1:.*]] = fpext <4 x half> %[[V1]] to <4 x float>
+// CHECK: %[[ADD:.*]] = fadd <4 x float> %[[CONV]], %[[CONV1]]
+// CHECK: %[[CONV2:.*]] = fptrunc <4 x float> %[[ADD]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV2]], <4 x half>* @hv0, align 8
+// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV3:.*]] = fpext <4 x half> %[[V2]] to <4 x float>
+// CHECK: %[[V3:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV4:.*]] = fpext <4 x half> %[[V3]] to <4 x float>
+// CHECK: %[[SUB:.*]] = fsub <4 x float> %[[CONV3]], %[[CONV4]]
+// CHECK: %[[CONV5:.*]] = fptrunc <4 x float> %[[SUB]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV5]], <4 x half>* @hv0, align 8
+// CHECK: %[[V4:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV6:.*]] = fpext <4 x half> %[[V4]] to <4 x float>
+// CHECK: %[[V5:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV7:.*]] = fpext <4 x half> %[[V5]] to <4 x float>
+// CHECK: %[[MUL:.*]] = fmul <4 x float> %[[CONV6]], %[[CONV7]]
+// CHECK: %[[CONV8:.*]] = fptrunc <4 x float> %[[MUL]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV8]], <4 x half>* @hv0, align 8
+// CHECK: %[[V6:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV9:.*]] = fpext <4 x half> %[[V6]] to <4 x float>
+// CHECK: %[[V7:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV10:.*]] = fpext <4 x half> %[[V7]] to <4 x float>
+// CHECK: %[[DIV:.*]] = fdiv <4 x float> %[[CONV9]], %[[CONV10]]
+// CHECK: %[[CONV11:.*]] = fptrunc <4 x float> %[[DIV]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV11]], <4 x half>* @hv0, align 8
+
+void testFP16Vec0() {
+ hv0 = hv0 + hv1;
+ hv0 = hv0 - hv1;
+ hv0 = hv0 * hv1;
+ hv0 = hv0 / hv1;
+}
+
+// CHECK-LABEL: testFP16Vec1
+// CHECK: %[[V0:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV:.*]] = fpext <4 x half> %[[V0]] to <4 x float>
+// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV1:.*]] = fpext <4 x half> %[[V1]] to <4 x float>
+// CHECK: %[[ADD:.*]] = fadd <4 x float> %[[CONV1]], %[[CONV]]
+// CHECK: %[[CONV2:.*]] = fptrunc <4 x float> %[[ADD]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV2]], <4 x half>* @hv0, align 8
+// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV3:.*]] = fpext <4 x half> %[[V2]] to <4 x float>
+// CHECK: %[[V3:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV4:.*]] = fpext <4 x half> %[[V3]] to <4 x float>
+// CHECK: %[[SUB:.*]] = fsub <4 x float> %[[CONV4]], %[[CONV3]]
+// CHECK: %[[CONV5:.*]] = fptrunc <4 x float> %[[SUB]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV5]], <4 x half>* @hv0, align 8
+// CHECK: %[[V4:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV6:.*]] = fpext <4 x half> %[[V4]] to <4 x float>
+// CHECK: %[[V5:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV7:.*]] = fpext <4 x half> %[[V5]] to <4 x float>
+// CHECK: %[[MUL:.*]] = fmul <4 x float> %[[CONV7]], %[[CONV6]]
+// CHECK: %[[CONV8:.*]] = fptrunc <4 x float> %[[MUL]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV8]], <4 x half>* @hv0, align 8
+// CHECK: %[[V6:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV9:.*]] = fpext <4 x half> %[[V6]] to <4 x float>
+// CHECK: %[[V7:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV10:.*]] = fpext <4 x half> %[[V7]] to <4 x float>
+// CHECK: %[[DIV:.*]] = fdiv <4 x float> %[[CONV10]], %[[CONV9]]
+// CHECK: %[[CONV11:.*]] = fptrunc <4 x float> %[[DIV]] to <4 x half>
+// CHECK: store <4 x half> %[[CONV11]], <4 x half>* @hv0, align 8
+
+void testFP16Vec1() {
+ hv0 += hv1;
+ hv0 -= hv1;
+ hv0 *= hv1;
+ hv0 /= hv1;
+}
+
+// CHECK-LABEL: testFP16Vec2
+// CHECK: %[[CADDR:.*]] = alloca i32, align 4
+// CHECK: store i32 %[[C:.*]], i32* %[[CADDR]], align 4
+// CHECK: %[[V0:.*]] = load i32, i32* %[[CADDR]], align 4
+// CHECK: %[[TOBOOL:.*]] = icmp ne i32 %[[V0]], 0
+// CHECK: br i1 %[[TOBOOL]], label %{{.*}}, label %{{.*}}
+//
+// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: br label %{{.*}}
+//
+// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: br label %{{.*}}
+//
+// CHECK: %[[COND:.*]] = phi <4 x half> [ %[[V1]], %{{.*}} ], [ %[[V2]], %{{.*}} ]
+// CHECK: store <4 x half> %[[COND]], <4 x half>* @hv0, align 8
+
+void testFP16Vec2(int c) {
+ hv0 = c ? hv0 : hv1;
+}
+
+// CHECK-LABEL: testFP16Vec3
+// CHECK: %[[V0:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV:.*]] = fpext <4 x half> %[[V0]] to <4 x float>
+// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV1:.*]] = fpext <4 x half> %[[V1]] to <4 x float>
+// CHECK: %[[CMP:.*]] = fcmp oeq <4 x float> %[[CONV]], %[[CONV1]]
+// CHECK: %[[SEXT:.*]] = sext <4 x i1> %[[CMP]] to <4 x i32>
+// CHECK: %[[CONV2:.*]] = trunc <4 x i32> %[[SEXT]] to <4 x i16>
+// CHECK: store <4 x i16> %[[CONV2]], <4 x i16>* @sv0, align 8
+// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV3:.*]] = fpext <4 x half> %[[V2]] to <4 x float>
+// CHECK: %[[V3:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV4:.*]] = fpext <4 x half> %[[V3]] to <4 x float>
+// CHECK: %[[CMP5:.*]] = fcmp une <4 x float> %[[CONV3]], %[[CONV4]]
+// CHECK: %[[SEXT6:.*]] = sext <4 x i1> %[[CMP5]] to <4 x i32>
+// CHECK: %[[CONV7:.*]] = trunc <4 x i32> %[[SEXT6]] to <4 x i16>
+// CHECK: store <4 x i16> %[[CONV7]], <4 x i16>* @sv0, align 8
+// CHECK: %[[V4:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV8:.*]] = fpext <4 x half> %[[V4]] to <4 x float>
+// CHECK: %[[V5:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV9:.*]] = fpext <4 x half> %[[V5]] to <4 x float>
+// CHECK: %[[CMP10:.*]] = fcmp olt <4 x float> %[[CONV8]], %[[CONV9]]
+// CHECK: %[[SEXT11:.*]] = sext <4 x i1> %[[CMP10]] to <4 x i32>
+// CHECK: %[[CONV12:.*]] = trunc <4 x i32> %[[SEXT11]] to <4 x i16>
+// CHECK: store <4 x i16> %[[CONV12]], <4 x i16>* @sv0, align 8
+// CHECK: %[[V6:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV13:.*]] = fpext <4 x half> %[[V6]] to <4 x float>
+// CHECK: %[[V7:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV14:.*]] = fpext <4 x half> %[[V7]] to <4 x float>
+// CHECK: %[[CMP15:.*]] = fcmp ogt <4 x float> %[[CONV13]], %[[CONV14]]
+// CHECK: %[[SEXT16:.*]] = sext <4 x i1> %[[CMP15]] to <4 x i32>
+// CHECK: %[[CONV17:.*]] = trunc <4 x i32> %[[SEXT16]] to <4 x i16>
+// CHECK: store <4 x i16> %[[CONV17]], <4 x i16>* @sv0, align 8
+// CHECK: %[[V8:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV18:.*]] = fpext <4 x half> %[[V8]] to <4 x float>
+// CHECK: %[[V9:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV19:.*]] = fpext <4 x half> %[[V9]] to <4 x float>
+// CHECK: %[[CMP20:.*]] = fcmp ole <4 x float> %[[CONV18]], %[[CONV19]]
+// CHECK: %[[SEXT21:.*]] = sext <4 x i1> %[[CMP20]] to <4 x i32>
+// CHECK: %[[CONV22:.*]] = trunc <4 x i32> %[[SEXT21]] to <4 x i16>
+// CHECK: store <4 x i16> %[[CONV22]], <4 x i16>* @sv0, align 8
+// CHECK: %[[V10:.*]] = load <4 x half>, <4 x half>* @hv0, align 8
+// CHECK: %[[CONV23:.*]] = fpext <4 x half> %[[V10]] to <4 x float>
+// CHECK: %[[V11:.*]] = load <4 x half>, <4 x half>* @hv1, align 8
+// CHECK: %[[CONV24:.*]] = fpext <4 x half> %[[V11]] to <4 x float>
+// CHECK: %[[CMP25:.*]] = fcmp oge <4 x float> %[[CONV23]], %[[CONV24]]
+// CHECK: %[[SEXT26:.*]] = sext <4 x i1> %[[CMP25]] to <4 x i32>
+// CHECK: %[[CONV27:.*]] = trunc <4 x i32> %[[SEXT26]] to <4 x i16>
+// CHECK: store <4 x i16> %[[CONV27]], <4 x i16>* @sv0, align 8
+
+void testFP16Vec3() {
+ sv0 = hv0 == hv1;
+ sv0 = hv0 != hv1;
+ sv0 = hv0 < hv1;
+ sv0 = hv0 > hv1;
+ sv0 = hv0 <= hv1;
+ sv0 = hv0 >= hv1;
+}
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 2139f6fe65..e143974401 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-passes -Os -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-passes -Os -std=c99 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-llvm-passes -Os -std=c99 -o - %s | FileCheck %s
// CHECK: define signext i8 @f0(i32 %x) [[NUW:#[0-9]+]]
// CHECK: define zeroext i8 @f1(i32 %x) [[NUW]]
// CHECK: define void @f2(i8 signext %x) [[NUW]]
diff --git a/test/CodeGen/function-sections.c b/test/CodeGen/function-sections.c
index 7994acf4dc..c34216dec6 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/hexagon-inline-asm.c b/test/CodeGen/hexagon-inline-asm.c
index cda3d0dcb6..3de3f58baf 100644
--- a/test/CodeGen/hexagon-inline-asm.c
+++ b/test/CodeGen/hexagon-inline-asm.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple hexagon-unknown-elf -target-feature +hvx -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple hexagon-unknown-elf -target-feature +hvx -target-feature +hvx-length64b -emit-llvm -o - %s | FileCheck %s
typedef int v64 __attribute__((__vector_size__(64)))
__attribute__((aligned(64)));
@@ -15,3 +15,9 @@ void foo(v64 v0, v64 v1, v64 *p) {
asm ("%0 = memw(##%1)" : "=r"(r) : "s"(&g));
// CHECK: call i32 asm "$0 = memw(##$1)", "=r,s"(i32* @g)
}
+
+void fred(unsigned *p, unsigned m, unsigned v) {
+ asm ("memw(%0++%1) = %2" : : "r"(p),"a"(m),"r"(v) : "memory");
+// CHECK: call void asm sideeffect "memw($0++$1) = $2", "r,a,r,~{memory}"(i32* %{{.*}}, i32 %{{.*}}, i32 %{{.*}})
+}
+
diff --git a/test/CodeGen/libcall-declarations.c b/test/CodeGen/libcall-declarations.c
index 5a0b2ba0e6..8a93b402ab 100644
--- a/test/CodeGen/libcall-declarations.c
+++ b/test/CodeGen/libcall-declarations.c
@@ -312,314 +312,310 @@ void *use[] = {
F(__cospif), F(__tanpi), F(__tanpif), F(__exp10), F(__exp10f)
};
-// CHECK-NOERRNO: declare double @atan2(double, double) [[NUW:#[0-9]+]]
-// CHECK-NOERRNO: declare float @atan2f(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare i32 @abs(i32) [[NUW]]
-// CHECK-NOERRNO: declare i64 @labs(i64) [[NUW]]
-// CHECK-NOERRNO: declare i64 @llabs(i64) [[NUW]]
-// CHECK-NOERRNO: declare double @copysign(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @copysignf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @fabs(double) [[NUW]]
-// CHECK-NOERRNO: declare float @fabsf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @fabsl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @fmod(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @fmodf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @fmodl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @ldexp(double, i32) [[NUW]]
-// CHECK-NOERRNO: declare float @ldexpf(float, i32) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @ldexpl(x86_fp80, i32) [[NUW]]
-// CHECK-NOERRNO: declare double @nan(i8*) [[NUW]]
-// CHECK-NOERRNO: declare float @nanf(i8*) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @nanl(i8*) [[NUW]]
-// CHECK-NOERRNO: declare double @pow(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @powf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @powl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @acos(double) [[NUW]]
-// CHECK-NOERRNO: declare float @acosf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @acosl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @acosh(double) [[NUW]]
-// CHECK-NOERRNO: declare float @acoshf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @acoshl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @asin(double) [[NUW]]
-// CHECK-NOERRNO: declare float @asinf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @asinl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @asinh(double) [[NUW]]
-// CHECK-NOERRNO: declare float @asinhf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @asinhl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @atan(double) [[NUW]]
-// CHECK-NOERRNO: declare float @atanf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @atanl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @atanh(double) [[NUW]]
-// CHECK-NOERRNO: declare float @atanhf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @atanhl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @cbrt(double) [[NUW]]
-// CHECK-NOERRNO: declare float @cbrtf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @ceil(double) [[NUW]]
-// CHECK-NOERRNO: declare float @ceilf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @cos(double) [[NUW]]
-// CHECK-NOERRNO: declare float @cosf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @cosl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @cosh(double) [[NUW]]
-// CHECK-NOERRNO: declare float @coshf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @coshl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @erf(double) [[NUW]]
-// CHECK-NOERRNO: declare float @erff(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @erfl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @erfc(double) [[NUW]]
-// CHECK-NOERRNO: declare float @erfcf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @erfcl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @exp(double) [[NUW]]
-// CHECK-NOERRNO: declare float @expf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @expl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @exp2(double) [[NUW]]
-// CHECK-NOERRNO: declare float @exp2f(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @exp2l(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @expm1(double) [[NUW]]
-// CHECK-NOERRNO: declare float @expm1f(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @expm1l(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @fdim(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @fdimf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @fdiml(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @floor(double) [[NUW]]
-// CHECK-NOERRNO: declare float @floorf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @floorl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @fma(double, double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @fmaf(float, float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @fmax(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @fmaxf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @fmin(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @fminf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @hypot(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @hypotf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @hypotl(x86_fp80, x86_fp80) [[NUW]]
-// 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 @atan2(double, double) [[NUWRN:#[0-9]+]]
+// CHECK-NOERRNO: declare float @atan2f(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare i32 @abs(i32) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @labs(i64) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @llabs(i64) [[NUWRN]]
+// CHECK-NOERRNO: declare double @copysign(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @copysignf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @fabs(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @fabsf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @fabsl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @fmod(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @fmodf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @fmodl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @ldexp(double, i32) [[NUWRN]]
+// CHECK-NOERRNO: declare float @ldexpf(float, i32) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @ldexpl(x86_fp80, i32) [[NUWRN]]
+// CHECK-NOERRNO: declare double @nan(i8*) [[NUWRO:#[0-9]+]]
+// CHECK-NOERRNO: declare float @nanf(i8*) [[NUWRO]]
+// CHECK-NOERRNO: declare x86_fp80 @nanl(i8*) [[NUWRO]]
+// CHECK-NOERRNO: declare double @pow(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @powf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @powl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @acos(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @acosf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @acosl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @acosh(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @acoshf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @acoshl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @asin(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @asinf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @asinl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @asinh(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @asinhf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @asinhl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @atan(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @atanf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @atanl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @atanh(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @atanhf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @atanhl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @cbrt(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @cbrtf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @ceil(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @ceilf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @cos(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @cosf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @cosl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @cosh(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @coshf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @coshl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @erf(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @erff(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @erfl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @erfc(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @erfcf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @erfcl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @exp(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @expf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @expl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @exp2(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @exp2f(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @exp2l(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @expm1(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @expm1f(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @expm1l(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @fdim(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @fdimf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @fdiml(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @floor(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @floorf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @floorl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @fma(double, double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @fmaf(float, float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @fmax(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @fmaxf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @fmin(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @fminf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @hypot(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @hypotf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @hypotl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare i32 @ilogb(double) [[NUWRN]]
+// CHECK-NOERRNO: declare i32 @ilogbf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare i32 @ilogbl(x86_fp80) [[NUWRN]]
// 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]]
-// CHECK-NOERRNO: declare i64 @llround(double) [[NUW]]
-// CHECK-NOERRNO: declare i64 @llroundf(float) [[NUW]]
-// CHECK-NOERRNO: declare i64 @llroundl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @log(double) [[NUW]]
-// CHECK-NOERRNO: declare float @logf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @logl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @log10(double) [[NUW]]
-// CHECK-NOERRNO: declare float @log10f(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @log10l(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @log1p(double) [[NUW]]
-// CHECK-NOERRNO: declare float @log1pf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @log1pl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @log2(double) [[NUW]]
-// CHECK-NOERRNO: declare float @log2f(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @log2l(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @logb(double) [[NUW]]
-// CHECK-NOERRNO: declare float @logbf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @logbl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare i64 @lrint(double) [[NUW]]
-// CHECK-NOERRNO: declare i64 @lrintf(float) [[NUW]]
-// CHECK-NOERRNO: declare i64 @lrintl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare i64 @lround(double) [[NUW]]
-// CHECK-NOERRNO: declare i64 @lroundf(float) [[NUW]]
-// CHECK-NOERRNO: declare i64 @lroundl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @nearbyint(double) [[NUW]]
-// CHECK-NOERRNO: declare float @nearbyintf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @nearbyintl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @nextafter(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @nextafterf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @nextafterl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @nexttoward(double, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare float @nexttowardf(float, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @nexttowardl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @remainder(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @remainderf(float, float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @remainderl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @rint(double) [[NUW]]
-// CHECK-NOERRNO: declare float @rintf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @rintl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @round(double) [[NUW]]
-// CHECK-NOERRNO: declare float @roundf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @roundl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @scalbln(double, i64) [[NUW]]
-// CHECK-NOERRNO: declare float @scalblnf(float, i64) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @scalblnl(x86_fp80, i64) [[NUW]]
-// CHECK-NOERRNO: declare double @scalbn(double, i32) [[NUW]]
-// CHECK-NOERRNO: declare float @scalbnf(float, i32) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @scalbnl(x86_fp80, i32) [[NUW]]
-// CHECK-NOERRNO: declare double @sin(double) [[NUW]]
-// CHECK-NOERRNO: declare float @sinf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @sinl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @sinh(double) [[NUW]]
-// CHECK-NOERRNO: declare float @sinhf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @sinhl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @sqrt(double) [[NUW]]
-// CHECK-NOERRNO: declare float @sqrtf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @sqrtl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @tan(double) [[NUW]]
-// CHECK-NOERRNO: declare float @tanf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @tanl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @tanh(double) [[NUW]]
-// CHECK-NOERRNO: declare float @tanhf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @tanhl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @tgamma(double) [[NUW]]
-// CHECK-NOERRNO: declare float @tgammaf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @tgammal(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @trunc(double) [[NUW]]
-// CHECK-NOERRNO: declare float @truncf(float) [[NUW]]
-// CHECK-NOERRNO: declare x86_fp80 @truncl(x86_fp80) [[NUW]]
-// CHECK-NOERRNO: declare double @cabs(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @cabsf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @cacos(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @cacosf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @cacosh(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @cacoshf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare double @carg(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @cargf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @casin(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @casinf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @casinh(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @casinhf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @catan(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @catanf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @catanh(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @catanhf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @ccos(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @ccosf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @ccosh(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @ccoshf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @cexp(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @cexpf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare double @cimag(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @cimagf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @conj(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @conjf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @clog(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @clogf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @cproj(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @cprojf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @cpow(double, double, double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @cpowf(<2 x float>, <2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare double @creal(double, double) [[NUW]]
-// CHECK-NOERRNO: declare float @crealf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @csin(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @csinf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @csinh(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @csinhf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @csqrt(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @csqrtf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @ctan(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @ctanf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare { double, double } @ctanh(double, double) [[NUW]]
-// CHECK-NOERRNO: declare <2 x float> @ctanhf(<2 x float>) [[NUW]]
-// CHECK-NOERRNO: declare double @__sinpi(double) [[NUW]]
-// CHECK-NOERRNO: declare float @__sinpif(float) [[NUW]]
-// CHECK-NOERRNO: declare double @__cospi(double) [[NUW]]
-// CHECK-NOERRNO: declare float @__cospif(float) [[NUW]]
-// CHECK-NOERRNO: declare double @__tanpi(double) [[NUW]]
-// CHECK-NOERRNO: declare float @__tanpif(float) [[NUW]]
-// CHECK-NOERRNO: declare double @__exp10(double) [[NUW]]
-// CHECK-NOERRNO: declare float @__exp10f(float) [[NUW]]
+// CHECK-NOERRNO: declare i64 @llrint(double) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @llrintf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @llrintl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @llround(double) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @llroundf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @llroundl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @log(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @logf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @logl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @log10(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @log10f(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @log10l(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @log1p(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @log1pf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @log1pl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @log2(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @log2f(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @log2l(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @logb(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @logbf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @logbl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @lrint(double) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @lrintf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @lrintl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @lround(double) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @lroundf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare i64 @lroundl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @nearbyint(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @nearbyintf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @nearbyintl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @nextafter(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @nextafterf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @nextafterl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @nexttoward(double, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare float @nexttowardf(float, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @nexttowardl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @remainder(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @remainderf(float, float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @remainderl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @rint(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @rintf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @rintl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @round(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @roundf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @roundl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @scalbln(double, i64) [[NUWRN]]
+// CHECK-NOERRNO: declare float @scalblnf(float, i64) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @scalblnl(x86_fp80, i64) [[NUWRN]]
+// CHECK-NOERRNO: declare double @scalbn(double, i32) [[NUWRN]]
+// CHECK-NOERRNO: declare float @scalbnf(float, i32) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @scalbnl(x86_fp80, i32) [[NUWRN]]
+// CHECK-NOERRNO: declare double @sin(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @sinf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @sinl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @sinh(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @sinhf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @sinhl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @sqrt(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @sqrtf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @sqrtl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @tan(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @tanf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @tanl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @tanh(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @tanhf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @tanhl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @tgamma(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @tgammaf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @tgammal(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @trunc(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @truncf(float) [[NUWRN]]
+// CHECK-NOERRNO: declare x86_fp80 @truncl(x86_fp80) [[NUWRN]]
+// CHECK-NOERRNO: declare double @cabs(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @cabsf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @cacos(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @cacosf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @cacosh(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @cacoshf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare double @carg(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @cargf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @casin(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @casinf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @casinh(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @casinhf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @catan(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @catanf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @catanh(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @catanhf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @ccos(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @ccosf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @ccosh(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @ccoshf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @cexp(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @cexpf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare double @cimag(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @cimagf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @conj(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @conjf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @clog(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @clogf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @cproj(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @cprojf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @cpow(double, double, double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @cpowf(<2 x float>, <2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare double @creal(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @crealf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @csin(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @csinf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @csinh(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @csinhf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @csqrt(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @csqrtf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @ctan(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @ctanf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare { double, double } @ctanh(double, double) [[NUWRN]]
+// CHECK-NOERRNO: declare <2 x float> @ctanhf(<2 x float>) [[NUWRN]]
+// CHECK-NOERRNO: declare double @__sinpi(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @__sinpif(float) [[NUWRN]]
+// CHECK-NOERRNO: declare double @__cospi(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @__cospif(float) [[NUWRN]]
+// CHECK-NOERRNO: declare double @__tanpi(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @__tanpif(float) [[NUWRN]]
+// CHECK-NOERRNO: declare double @__exp10(double) [[NUWRN]]
+// CHECK-NOERRNO: declare float @__exp10f(float) [[NUWRN]]
-// CHECK-ERRNO: declare i32 @abs(i32) [[NUW:#[0-9]+]]
-// CHECK-ERRNO: declare i64 @labs(i64) [[NUW]]
-// CHECK-ERRNO: declare i64 @llabs(i64) [[NUW]]
-// CHECK-ERRNO: declare double @copysign(double, double) [[NUW]]
-// CHECK-ERRNO: declare float @copysignf(float, float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare double @fabs(double) [[NUW]]
-// CHECK-ERRNO: declare float @fabsf(float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @fabsl(x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare double @nan(i8*) [[NUW]]
-// CHECK-ERRNO: declare float @nanf(i8*) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @nanl(i8*) [[NUW]]
-// CHECK-ERRNO: declare double @ceil(double) [[NUW]]
-// CHECK-ERRNO: declare float @ceilf(float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare double @floor(double) [[NUW]]
-// CHECK-ERRNO: declare float @floorf(float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @floorl(x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare double @fmax(double, double) [[NUW]]
-// CHECK-ERRNO: declare float @fmaxf(float, float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[NUW]]
-// 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 i32 @abs(i32) [[NUWRN:#[0-9]+]]
+// CHECK-ERRNO: declare i64 @labs(i64) [[NUWRN]]
+// CHECK-ERRNO: declare i64 @llabs(i64) [[NUWRN]]
+// CHECK-ERRNO: declare double @copysign(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare float @copysignf(float, float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @fabs(double) [[NUWRN]]
+// CHECK-ERRNO: declare float @fabsf(float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @fabsl(x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @nan(i8*) [[NUWRO:#[0-9]+]]
+// CHECK-ERRNO: declare float @nanf(i8*) [[NUWRO]]
+// CHECK-ERRNO: declare x86_fp80 @nanl(i8*) [[NUWRO]]
+// CHECK-ERRNO: declare double @ceil(double) [[NUWRN]]
+// CHECK-ERRNO: declare float @ceilf(float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @floor(double) [[NUWRN]]
+// CHECK-ERRNO: declare float @floorf(float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @floorl(x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @fmax(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare float @fmaxf(float, float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @fmin(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare float @fminf(float, float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUWRN]]
// 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]]
-// CHECK-ERRNO: declare double @rint(double) [[NUW]]
-// CHECK-ERRNO: declare float @rintf(float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @rintl(x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare double @round(double) [[NUW]]
-// CHECK-ERRNO: declare float @roundf(float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @roundl(x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare double @trunc(double) [[NUW]]
-// CHECK-ERRNO: declare float @truncf(float) [[NUW]]
-// CHECK-ERRNO: declare x86_fp80 @truncl(x86_fp80) [[NUW]]
-// CHECK-ERRNO: declare double @cabs(double, double) [[NUW]]
-// CHECK-ERRNO: declare float @cabsf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @cacos(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @cacosf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @cacosh(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @cacoshf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare double @carg(double, double) [[NUW]]
-// CHECK-ERRNO: declare float @cargf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @casin(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @casinf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @casinh(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @casinhf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @catan(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @catanf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @catanh(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @catanhf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @ccos(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @ccosf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @ccosh(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @ccoshf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @cexp(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @cexpf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare double @cimag(double, double) [[NUW]]
-// CHECK-ERRNO: declare float @cimagf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @conj(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @conjf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @clog(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @clogf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @cproj(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @cprojf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @cpow(double, double, double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @cpowf(<2 x float>, <2 x float>) [[NUW]]
-// CHECK-ERRNO: declare double @creal(double, double) [[NUW]]
-// CHECK-ERRNO: declare float @crealf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @csin(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @csinf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @csinh(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @csinhf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @csqrt(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @csqrtf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @ctan(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @ctanf(<2 x float>) [[NUW]]
-// CHECK-ERRNO: declare { double, double } @ctanh(double, double) [[NUW]]
-// CHECK-ERRNO: declare <2 x float> @ctanhf(<2 x float>) [[NUW]]
+// CHECK-ERRNO: declare double @nearbyint(double) [[NUWRN]]
+// CHECK-ERRNO: declare float @nearbyintf(float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @nearbyintl(x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @rint(double) [[NUWRN]]
+// CHECK-ERRNO: declare float @rintf(float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @rintl(x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @round(double) [[NUWRN]]
+// CHECK-ERRNO: declare float @roundf(float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @roundl(x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @trunc(double) [[NUWRN]]
+// CHECK-ERRNO: declare float @truncf(float) [[NUWRN]]
+// CHECK-ERRNO: declare x86_fp80 @truncl(x86_fp80) [[NUWRN]]
+// CHECK-ERRNO: declare double @cabs(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare float @cabsf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @cacos(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @cacosf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @cacosh(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @cacoshf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare double @carg(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare float @cargf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @casin(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @casinf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @casinh(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @casinhf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @catan(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @catanf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @catanh(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @catanhf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @ccos(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @ccosf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @ccosh(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @ccoshf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @cexp(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @cexpf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare double @cimag(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare float @cimagf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @conj(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @conjf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @clog(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @clogf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @cproj(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @cprojf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @cpow(double, double, double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @cpowf(<2 x float>, <2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare double @creal(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare float @crealf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @csin(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @csinf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @csinh(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @csinhf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @csqrt(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @csqrtf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @ctan(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @ctanf(<2 x float>) [[NUWRN]]
+// CHECK-ERRNO: declare { double, double } @ctanh(double, double) [[NUWRN]]
+// CHECK-ERRNO: declare <2 x float> @ctanhf(<2 x float>) [[NUWRN]]
-// CHECK-NOERRNO: attributes [[NUW]] = { nounwind readnone{{.*}} }
-// CHECK-NOERRNO: attributes [[NONCONST]] = {
-// CHECK-NOERRNO-NOT: readnone
-// CHECK-NOERRNO-SAME: nounwind{{.*}} }
+// CHECK-NOERRNO: attributes [[NUWRN]] = { nounwind readnone{{.*}} }
+// CHECK-NOERRNO: attributes [[NUWRO]] = { nounwind readonly{{.*}} }
-// CHECK-ERRNO: attributes [[NONCONST]] = {
-// CHECK-ERRNO-NOT: readnone
-// CHECK-ERRNO-SAME: nounwind{{.*}} }
-// CHECK-ERRNO: attributes [[NUW]] = { nounwind readnone{{.*}} }
+// CHECK-ERRNO: attributes [[NUWRN]] = { nounwind readnone{{.*}} }
+// CHECK-ERRNO: attributes [[NUWRO]] = { nounwind readonly{{.*}} }
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index 8120b75256..0a1bcc605c 100644
--- a/test/CodeGen/libcalls.c
+++ b/test/CodeGen/libcalls.c
@@ -6,29 +6,28 @@
// CHECK-NO-LABEL: define void @test_sqrt
// CHECK-FAST-LABEL: define void @test_sqrt
void test_sqrt(float a0, double a1, long double a2) {
- // Following llvm-gcc's lead, we never emit these as intrinsics;
- // no-math-errno isn't good enough. We could probably use intrinsics
- // with appropriate guards if it proves worthwhile.
-
// CHECK-YES: call float @sqrtf
- // CHECK-NO: call float @sqrtf
+ // CHECK-NO: call float @llvm.sqrt.f32(float
+ // CHECK-FAST: call float @llvm.sqrt.f32(float
float l0 = sqrtf(a0);
// CHECK-YES: call double @sqrt
- // CHECK-NO: call double @sqrt
+ // CHECK-NO: call double @llvm.sqrt.f64(double
+ // CHECK-FAST: call double @llvm.sqrt.f64(double
double l1 = sqrt(a1);
// CHECK-YES: call x86_fp80 @sqrtl
- // CHECK-NO: call x86_fp80 @sqrtl
+ // CHECK-NO: call x86_fp80 @llvm.sqrt.f80(x86_fp80
+ // CHECK-FAST: call x86_fp80 @llvm.sqrt.f80(x86_fp80
long double l2 = sqrtl(a2);
}
// CHECK-YES: declare float @sqrtf(float)
// CHECK-YES: declare double @sqrt(double)
// CHECK-YES: declare x86_fp80 @sqrtl(x86_fp80)
-// CHECK-NO: declare float @sqrtf(float) [[NUW_RN:#[0-9]+]]
-// CHECK-NO: declare double @sqrt(double) [[NUW_RN]]
-// CHECK-NO: declare x86_fp80 @sqrtl(x86_fp80) [[NUW_RN]]
+// CHECK-NO: declare float @llvm.sqrt.f32(float)
+// CHECK-NO: declare double @llvm.sqrt.f64(double)
+// CHECK-NO: declare x86_fp80 @llvm.sqrt.f80(x86_fp80)
// CHECK-FAST: declare float @llvm.sqrt.f32(float)
// CHECK-FAST: declare double @llvm.sqrt.f64(double)
// CHECK-FAST: declare x86_fp80 @llvm.sqrt.f80(x86_fp80)
@@ -86,7 +85,7 @@ void test_builtins(double d, float f, long double ld) {
double atan_ = atan(d);
long double atanl_ = atanl(ld);
float atanf_ = atanf(f);
-// CHECK-NO: declare double @atan(double) [[NUW_RN]]
+// CHECK-NO: declare double @atan(double) [[NUW_RN:#[0-9]+]]
// CHECK-NO: declare x86_fp80 @atanl(x86_fp80) [[NUW_RN]]
// CHECK-NO: declare float @atanf(float) [[NUW_RN]]
// CHECK-YES-NOT: declare double @atan(double) [[NUW_RN]]
@@ -124,7 +123,7 @@ void test_builtins(double d, float f, long double ld) {
// CHECK-YES-NOT: declare float @logf(float) [[NUW_RN]]
}
-// CHECK-YES: attributes [[NUW_RN]] = { nounwind readnone }
+// CHECK-YES: attributes [[NUW_RN]] = { nounwind readnone speculatable }
-// CHECK-NO: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
-// CHECK-NO: attributes [[NUW_RNI]] = { nounwind readnone }
+// CHECK-NO-DAG: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
+// CHECK-NO-DAG: attributes [[NUW_RNI]] = { nounwind readnone speculatable }
diff --git a/test/CodeGen/lifetime-asan.c b/test/CodeGen/lifetime-asan.c
index 5f0c66d513..c5f25a2eaf 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 55c6d91ad0..fcdcff3601 100644
--- a/test/CodeGen/lifetime2.c
+++ b/test/CodeGen/lifetime2.c
@@ -21,7 +21,7 @@ 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);
@@ -29,14 +29,14 @@ l1:
bar(y, 5);
goto l1;
// Infinite loop
- // O2-NOT: @llvm.lifetime.end(
+ // 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);
@@ -48,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;
@@ -69,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;
@@ -93,8 +93,8 @@ L:
// O2-LABEL: @jump_backward_over_declaration(
// O2: %[[p:.*]] = alloca i32*
// O2: %[[v0:.*]] = bitcast i32** %[[p]] to i8*
-// O2: call void @llvm.lifetime.start(i64 {{.*}}, i8* %[[v0]])
-// O2-NOT: call void @llvm.lifetime.start(
+// O2: call void @llvm.lifetime.start.p0i8(i64 {{.*}}, i8* %[[v0]])
+// O2-NOT: call void @llvm.lifetime.start.p0i8(
extern void foo2(int p);
diff --git a/test/CodeGen/linker-option.c b/test/CodeGen/linker-option.c
index b1b2ec461c..13bd981179 100644
--- a/test/CodeGen/linker-option.c
+++ b/test/CodeGen/linker-option.c
@@ -1,8 +1,6 @@
// RUN: %clang_cc1 %s --linker-option=/include:foo -triple i686-pc-win32 -emit-llvm -o - | FileCheck %s
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]]}
+// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]]}
// CHECK: ![[msvcrt]] = !{!"/include:foo"}
int f();
diff --git a/test/CodeGen/linux-arm-atomic.c b/test/CodeGen/linux-arm-atomic.c
index 116925a585..b8535f8248 100644
--- a/test/CodeGen/linux-arm-atomic.c
+++ b/test/CodeGen/linux-arm-atomic.c
@@ -2,7 +2,6 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv6-unknown-linux | FileCheck %s
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-unknown-linux | FileCheck %s
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv6-unknown-freebsd | FileCheck %s
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv6-unknown-bitrig | FileCheck %s
typedef int _Atomic_word;
_Atomic_word exchange_and_add(volatile _Atomic_word *__mem, int __val) {
diff --git a/test/CodeGen/long-call-attr.c b/test/CodeGen/long-call-attr.c
new file mode 100644
index 0000000000..82433caf76
--- /dev/null
+++ b/test/CodeGen/long-call-attr.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple mips-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple mips64-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+void __attribute__((long_call)) foo1 (void);
+void __attribute__((short_call)) foo4 (void);
+
+void __attribute__((far)) foo2 (void) {}
+
+// CHECK: define void @foo2() [[FAR:#[0-9]+]]
+
+void __attribute__((near)) foo3 (void) { foo1(); foo4(); }
+
+// CHECK: define void @foo3() [[NEAR:#[0-9]+]]
+
+// CHECK: declare void @foo1() [[LONGDECL:#[0-9]+]]
+// CHECK: declare void @foo4() [[SHORTDECL:#[0-9]+]]
+
+// CHECK: attributes [[FAR]] = { {{.*}} "long-call" {{.*}} }
+// CHECK: attributes [[NEAR]] = { {{.*}} "short-call" {{.*}} }
+// CHECK: attributes [[LONGDECL]] = { {{.*}} "long-call" {{.*}} }
+// CHECK: attributes [[SHORTDECL]] = { {{.*}} "short-call" {{.*}} }
diff --git a/test/CodeGen/lto-newpm-pipeline.c b/test/CodeGen/lto-newpm-pipeline.c
new file mode 100644
index 0000000000..10112da6d5
--- /dev/null
+++ b/test/CodeGen/lto-newpm-pipeline.c
@@ -0,0 +1,53 @@
+// REQUIRES: x86-registered-target
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=full -O0 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-FULL-O0
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=thin -O0 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-THIN-O0
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=full -O1 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-FULL-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=thin -O1 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-THIN-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=full -O2 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-FULL-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=thin -O2 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-THIN-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=full -O3 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-FULL-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=thin -O3 %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-THIN-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=full -Os %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-FULL-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=thin -Os %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-THIN-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=full -Oz %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-FULL-OPTIMIZED
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null -fexperimental-new-pass-manager -fdebug-pass-manager -flto=thin -Oz %s 2>&1 | FileCheck %s \
+// RUN: -check-prefix=CHECK-THIN-OPTIMIZED
+
+// CHECK-FULL-O0: Starting llvm::Module pass manager run.
+// CHECK-FULL-O0: Running pass: AlwaysInlinerPass
+// CHECK-FULL-O0-NEXT: Running pass: BitcodeWriterPass
+// CHECK-FULL-O0: Finished llvm::Module pass manager run.
+
+// CHECK-THIN-O0: Starting llvm::Module pass manager run.
+// CHECK-THIN-O0: Running pass: AlwaysInlinerPass
+// CHECK-THIN-O0-NEXT: Running pass: NameAnonGlobalPass
+// CHECK-THIN-O0-NEXT: Running pass: ThinLTOBitcodeWriterPass
+// CHECK-THIN-O0: Finished llvm::Module pass manager run.
+
+// TODO: The LTO pre-link pipeline currently invokes
+// buildPerModuleDefaultPipeline(), which contains LoopVectorizePass.
+// This may change as the pipeline gets implemented.
+// CHECK-FULL-OPTIMIZED: Starting llvm::Function pass manager run.
+// CHECK-FULL-OPTIMIZED: Running pass: LoopVectorizePass
+// CHECK-FULL-OPTIMIZED: Running pass: BitcodeWriterPass
+
+// The ThinLTO pre-link pipeline shouldn't contain passes like
+// LoopVectorizePass.
+// CHECK-THIN-OPTIMIZED: Starting llvm::Function pass manager run.
+// CHECK-THIN-OPTIMIZED-NOT: Running pass: LoopVectorizePass
+// CHECK-THIN-OPTIMIZED: Running pass: NameAnonGlobalPass
+// CHECK-THIN-OPTIMIZED: Running pass: ThinLTOBitcodeWriterPass
+
+void Foo() {}
diff --git a/test/CodeGen/lwp-builtins.c b/test/CodeGen/lwp-builtins.c
new file mode 100644
index 0000000000..c689c3974d
--- /dev/null
+++ b/test/CodeGen/lwp-builtins.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +lwp -emit-llvm -o - -Wall -Werror | FileCheck %s
+
+#include <x86intrin.h>
+
+void test_llwpcb(void *ptr) {
+ // CHECK-LABEL: @test_llwpcb
+ // CHECK: call void @llvm.x86.llwpcb(i8* %{{.*}})
+ __llwpcb(ptr);
+}
+
+void* test_slwpcb() {
+ // CHECK-LABEL: @test_slwpcb
+ // CHECK: call i8* @llvm.x86.slwpcb()
+ return __slwpcb();
+}
+
+unsigned char test_lwpins32(unsigned val2, unsigned val1) {
+ // CHECK-LABEL: @test_lwpins32
+ // CHECK: call i8 @llvm.x86.lwpins32(i32
+ return __lwpins32(val2, val1, 0x01234);
+}
+
+unsigned char test_lwpins64(unsigned long long val2, unsigned val1) {
+ // CHECK-LABEL: @test_lwpins64
+ // CHECK: call i8 @llvm.x86.lwpins64(i64
+ return __lwpins64(val2, val1, 0x56789);
+}
+
+void test_lwpval32(unsigned val2, unsigned val1) {
+ // CHECK-LABEL: @test_lwpval32
+ // CHECK: call void @llvm.x86.lwpval32(i32
+ __lwpval32(val2, val1, 0x01234);
+}
+
+void test_lwpval64(unsigned long long val2, unsigned val1) {
+ // CHECK-LABEL: @test_lwpval64
+ // CHECK: call void @llvm.x86.lwpval64(i64
+ __lwpval64(val2, val1, 0xABCDEF);
+}
diff --git a/test/CodeGen/mangle-blocks.c b/test/CodeGen/mangle-blocks.c
index e8de92d8b4..4ea5a550c8 100644
--- a/test/CodeGen/mangle-blocks.c
+++ b/test/CodeGen/mangle-blocks.c
@@ -12,12 +12,12 @@ void (^mangle(void))(void) {
}
// CHECK: @__func__.__mangle_block_invoke_2 = private unnamed_addr constant [22 x i8] c"mangle_block_invoke_2\00", align 1
-// CHECK: @.str = private unnamed_addr constant {{.*}}, align 1
-// CHECK: @.str.1 = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
+// CHECK: @.str{{.*}} = private unnamed_addr constant {{.*}}, align 1
+// CHECK: @.str[[STR1:.*]] = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
// CHECK: define internal void @__mangle_block_invoke(i8* %.block_descriptor)
// CHECK: define internal void @__mangle_block_invoke_2(i8* %.block_descriptor){{.*}}{
-// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @__func__.__mangle_block_invoke_2, i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 9, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0))
+// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @__func__.__mangle_block_invoke_2, i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 9, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str[[STR1]], i32 0, i32 0))
// CHECK: }
diff --git a/test/CodeGen/mangle-ms.c b/test/CodeGen/mangle-ms.c
index 0ad43d5e06..042c72e6d7 100644
--- a/test/CodeGen/mangle-ms.c
+++ b/test/CodeGen/mangle-ms.c
@@ -2,3 +2,12 @@
// CHECK: define void @"\01?f@@$$J0YAXP6AX@Z@Z"
__attribute__((overloadable)) void f(void (*x)()) {}
+
+// CHECK: define void @f
+void f(void (*x)(int)) {}
+
+// CHECK: define void @g
+void g(void (*x)(int)) {}
+
+// CHECK: define void @"\01?g@@$$J0YAXP6AX@Z@Z"
+__attribute__((overloadable)) void g(void (*x)()) {}
diff --git a/test/CodeGen/mangle.c b/test/CodeGen/mangle.c
index 46ef512f69..f94139bc5e 100644
--- a/test/CodeGen/mangle.c
+++ b/test/CodeGen/mangle.c
@@ -9,6 +9,10 @@ void __attribute__((__overloadable__)) f0(int a) {}
// CHECK: @_Z2f0l
void __attribute__((__overloadable__)) f0(long b) {}
+// Unless it's unmarked.
+// CHECK: @f0
+void f0(float b) {}
+
// CHECK: @bar
// These should get merged.
diff --git a/test/CodeGen/mcount.c b/test/CodeGen/mcount.c
index 7f91584195..2284acac0f 100644
--- a/test/CodeGen/mcount.c
+++ b/test/CodeGen/mcount.c
@@ -1,18 +1,22 @@
// RUN: %clang_cc1 -pg -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -pg -triple i386-unknown-unknown -emit-llvm -O2 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -pg -triple powerpc-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64le-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple i386-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple x86_64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple arm-netbsd-eabi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple aarch64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple mips-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64le-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple sparc-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple sparc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple powerpc-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64le-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple i386-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple x86_64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple arm-netbsd-eabi -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple aarch64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple mips-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple mips-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple mipsel-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple mips64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple mips64el-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64le-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple sparc-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple sparc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s -check-prefix=NO-MCOUNT
int bar(void) {
@@ -23,10 +27,17 @@ int foo(void) {
return bar();
}
-int main(void) {
+int __attribute__((no_instrument_function)) no_instrument(void) {
return foo();
}
-// CHECK: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
-// CHECK-PREFIXED: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="_mcount"{{.*}} }
+int main(void) {
+ return no_instrument();
+}
+
+// CHECK: attributes #0 = { {{.*}}"counting-function"="mcount"{{.*}} }
+// CHECK: attributes #1 = { {{.*}} }
+// CHECK-PREFIXED: attributes #0 = { {{.*}}"counting-function"="_mcount"{{.*}} }
+// CHECK-PREFIXED: attributes #1 = { {{.*}} }
// NO-MCOUNT-NOT: attributes #{{[0-9]}} = { {{.*}}"counting-function"={{.*}} }
+// NO-MCOUNT1-NOT: attributes #1 = { {{.*}}"counting-function"={{.*}} }
diff --git a/test/CodeGen/micromips-attr.c b/test/CodeGen/micromips-attr.c
new file mode 100644
index 0000000000..96ba774afc
--- /dev/null
+++ b/test/CodeGen/micromips-attr.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple mips-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+void __attribute__((micromips)) foo (void) {}
+
+// CHECK: define void @foo() [[MICROMIPS:#[0-9]+]]
+
+void __attribute__((nomicromips)) nofoo (void) {}
+
+// CHECK: define void @nofoo() [[NOMICROMIPS:#[0-9]+]]
+
+// CHECK: attributes [[MICROMIPS]] = { noinline nounwind {{.*}} "micromips" {{.*}} }
+// CHECK: attributes [[NOMICROMIPS]] = { noinline nounwind {{.*}} "nomicromips" {{.*}} }
diff --git a/test/CodeGen/mips-debug-info-bitfield.c b/test/CodeGen/mips-debug-info-bitfield.c
new file mode 100644
index 0000000000..a0e2ed9cde
--- /dev/null
+++ b/test/CodeGen/mips-debug-info-bitfield.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple mips-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+struct fields
+{
+ unsigned a : 4;
+ unsigned b : 4;
+} flags;
+
+// CHECK: !DIDerivedType(tag: DW_TAG_member,
+// CHECK-SAME: {{.*}}name: "a"
+// CHECK-NOT: {{.*}}offset:
+// CHECK-SAME: {{.*}}flags: DIFlagBitField
+
+// CHECK: !DIDerivedType(tag: DW_TAG_member,
+// CHECK-SAME: {{.*}}name: "b"
+// CHECK-SAME: {{.*}}offset: 4
+// CHECK-SAME: {{.*}}flags: DIFlagBitField
diff --git a/test/CodeGen/mips-madd4.c b/test/CodeGen/mips-madd4.c
new file mode 100644
index 0000000000..bc7bb593f9
--- /dev/null
+++ b/test/CodeGen/mips-madd4.c
@@ -0,0 +1,87 @@
+// REQUIRES: mips-registered-target
+// RUN: %clang --target=mips64-unknown-linux -S -mmadd4 %s -o -| FileCheck %s -check-prefix=MADD4
+// RUN: %clang --target=mips64-unknown-linux -S -mno-madd4 %s -o -| FileCheck %s -check-prefix=NOMADD4
+// RUN: %clang --target=mips64-unknown-linux -S -mmadd4 -fno-honor-nans %s -o -| FileCheck %s -check-prefix=MADD4-NONAN
+// RUN: %clang --target=mips64-unknown-linux -S -mno-madd4 -fno-honor-nans %s -o -| FileCheck %s -check-prefix=NOMADD4-NONAN
+
+float madd_s (float f, float g, float h)
+{
+ return (f * g) + h;
+}
+// MADD4: madd.s
+// NOMADD4: mul.s
+// NOMADD4: add.s
+
+float msub_s (float f, float g, float h)
+{
+ return (f * g) - h;
+}
+// MADD4: msub.s
+// NOMADD4: mul.s
+// NOMADD4: sub.s
+
+double madd_d (double f, double g, double h)
+{
+ return (f * g) + h;
+}
+// MADD4: madd.d
+// NOMADD4: mul.d
+// NOMADD4: add.d
+
+double msub_d (double f, double g, double h)
+{
+ return (f * g) - h;
+}
+// MADD4: msub.d
+// NOMADD4: mul.d
+// NOMADD4: sub.d
+
+
+float nmadd_s (float f, float g, float h)
+{
+ // FIXME: Zero has been explicitly placed to force generation of a positive
+ // zero in IR until pattern used to match this instruction is changed to
+ // comply with negative zero as well.
+ return 0-((f * g) + h);
+}
+// MADD4-NONAN: nmadd.s
+// NOMADD4-NONAN: mul.s
+// NOMADD4-NONAN: add.s
+// NOMADD4-NONAN: sub.s
+
+float nmsub_s (float f, float g, float h)
+{
+ // FIXME: Zero has been explicitly placed to force generation of a positive
+ // zero in IR until pattern used to match this instruction is changed to
+ // comply with negative zero as well.
+ return 0-((f * g) - h);
+}
+// MADD4-NONAN: nmsub.s
+// NOMADD4-NONAN: mul.s
+// NOMADD4-NONAN: sub.s
+// NOMADD4-NONAN: sub.s
+
+double nmadd_d (double f, double g, double h)
+{
+ // FIXME: Zero has been explicitly placed to force generation of a positive
+ // zero in IR until pattern used to match this instruction is changed to
+ // comply with negative zero as well.
+ return 0-((f * g) + h);
+}
+// MADD4-NONAN: nmadd.d
+// NOMADD4-NONAN: mul.d
+// NOMADD4-NONAN: add.d
+// NOMADD4-NONAN: sub.d
+
+double nmsub_d (double f, double g, double h)
+{
+ // FIXME: Zero has been explicitly placed to force generation of a positive
+ // zero in IR until pattern used to match this instruction is changed to
+ // comply with negative zero as well.
+ return 0-((f * g) - h);
+}
+// MADD4-NONAN: nmsub.d
+// NOMADD4-NONAN: mul.d
+// NOMADD4-NONAN: sub.d
+// NOMADD4-NONAN: sub.d
+
diff --git a/test/CodeGen/mips-varargs.c b/test/CodeGen/mips-varargs.c
index 0d656dcfba..343914ad8d 100644
--- a/test/CodeGen/mips-varargs.c
+++ b/test/CodeGen/mips-varargs.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple mips-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
-// RUN: %clang_cc1 -triple mipsel-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=O32
-// RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm -target-abi n32 %s | FileCheck %s -check-prefix=ALL -check-prefix=N32 -check-prefix=NEW
-// RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm -target-abi n32 %s | FileCheck %s -check-prefix=ALL -check-prefix=N32 -check-prefix=NEW
-// RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NEW
-// RUN: %clang_cc1 -triple mips64el-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NEW
+// RUN: %clang_cc1 -triple mips-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,O32 -enable-var-scope
+// RUN: %clang_cc1 -triple mipsel-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,O32 -enable-var-scope
+// RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm -target-abi n32 %s | FileCheck %s -check-prefixes=ALL,N32,NEW -enable-var-scope
+// RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm -target-abi n32 %s | FileCheck %s -check-prefixes=ALL,N32,NEW -enable-var-scope
+// RUN: %clang_cc1 -triple mips64-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,N64,NEW -enable-var-scope
+// RUN: %clang_cc1 -triple mips64el-unknown-linux -o - -emit-llvm %s | FileCheck %s -check-prefixes=ALL,N64,NEW -enable-var-scope
#include <stdarg.h>
@@ -21,19 +21,19 @@ int test_i32(char *fmt, ...) {
// ALL-LABEL: define i32 @test_i32(i8*{{.*}} %fmt, ...)
//
-// O32: %va = alloca i8*, align [[PTRALIGN:4]]
-// N32: %va = alloca i8*, align [[PTRALIGN:4]]
-// N64: %va = alloca i8*, align [[PTRALIGN:8]]
+// O32: %va = alloca i8*, align [[$PTRALIGN:4]]
+// N32: %va = alloca i8*, align [[$PTRALIGN:4]]
+// N64: %va = alloca i8*, align [[$PTRALIGN:8]]
// ALL: [[V:%.*]] = alloca i32, align 4
// NEW: [[PROMOTION_TEMP:%.*]] = alloca i32, align 4
//
// ALL: [[VA:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_start(i8* [[VA]])
-// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[PTRALIGN]]
-// O32: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[INTPTR_T:i32]] [[CHUNKSIZE:4]]
-// NEW: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[INTPTR_T:i32|i64]] [[CHUNKSIZE:8]]
+// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
+// O32: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T:i32]] [[$CHUNKSIZE:4]]
+// NEW: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T:i32|i64]] [[$CHUNKSIZE:8]]
//
-// ALL: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// ALL: store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
//
// O32: [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to [[CHUNK_T:i32]]*
// O32: [[ARG:%.+]] = load i32, i32* [[AP_CAST]], align [[CHUNKALIGN:4]]
@@ -63,10 +63,10 @@ long long test_i64(char *fmt, ...) {
// ALL-LABEL: define i64 @test_i64(i8*{{.*}} %fmt, ...)
//
-// ALL: %va = alloca i8*, align [[PTRALIGN]]
+// ALL: %va = alloca i8*, align [[$PTRALIGN]]
// ALL: [[VA:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_start(i8* [[VA]])
-// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[PTRALIGN]]
+// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
//
// i64 is 8-byte aligned, while this is within O32's stack alignment there's no
// guarantee that the offset is still 8-byte aligned after earlier reads.
@@ -75,8 +75,8 @@ long long test_i64(char *fmt, ...) {
// O32: [[TMP3:%.+]] = and i32 [[TMP2]], -8
// O32: [[AP_CUR:%.+]] = inttoptr i32 [[TMP3]] to i8*
//
-// ALL: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[INTPTR_T]] 8
-// ALL: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// ALL: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T]] 8
+// ALL: store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
//
// ALL: [[AP_CAST:%.*]] = bitcast i8* [[AP_CUR]] to i64*
// ALL: [[ARG:%.+]] = load i64, i64* [[AP_CAST]], align 8
@@ -97,14 +97,14 @@ char *test_ptr(char *fmt, ...) {
// ALL-LABEL: define i8* @test_ptr(i8*{{.*}} %fmt, ...)
//
-// ALL: %va = alloca i8*, align [[PTRALIGN]]
-// ALL: [[V:%.*]] = alloca i8*, align [[PTRALIGN]]
+// ALL: %va = alloca i8*, align [[$PTRALIGN]]
+// ALL: [[V:%.*]] = alloca i8*, align [[$PTRALIGN]]
// N32: [[AP_CAST:%.+]] = alloca i8*, align 4
// ALL: [[VA:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_start(i8* [[VA]])
-// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[PTRALIGN]]
-// ALL: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[INTPTR_T]] [[CHUNKSIZE]]
-// ALL: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
+// ALL: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T]] [[$CHUNKSIZE]]
+// ALL: store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
//
// When the chunk size matches the pointer size, this is easy.
// O32: [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to i8**
@@ -116,8 +116,8 @@ char *test_ptr(char *fmt, ...) {
// N32: [[PTR:%.+]] = inttoptr i32 [[TMP3]] to i8*
// N32: store i8* [[PTR]], i8** [[AP_CAST]], align 4
//
-// ALL: [[ARG:%.+]] = load i8*, i8** [[AP_CAST]], align [[PTRALIGN]]
-// ALL: store i8* [[ARG]], i8** [[V]], align [[PTRALIGN]]
+// ALL: [[ARG:%.+]] = load i8*, i8** [[AP_CAST]], align [[$PTRALIGN]]
+// ALL: store i8* [[ARG]], i8** [[V]], align [[$PTRALIGN]]
//
// ALL: [[VA1:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_end(i8* [[VA1]])
@@ -135,11 +135,11 @@ int test_v4i32(char *fmt, ...) {
// ALL-LABEL: define i32 @test_v4i32(i8*{{.*}} %fmt, ...)
//
-// ALL: %va = alloca i8*, align [[PTRALIGN]]
-// ALL: [[V]] = alloca <4 x i32>, align 16
+// ALL: %va = alloca i8*, align [[$PTRALIGN]]
+// ALL: [[V:%.+]] = alloca <4 x i32>, align 16
// ALL: [[VA1:%.+]] = bitcast i8** %va to i8*
// ALL: call void @llvm.va_start(i8* [[VA1]])
-// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[PTRALIGN]]
+// ALL: [[AP_CUR:%.+]] = load i8*, i8** %va, align [[$PTRALIGN]]
//
// Vectors are 16-byte aligned, however the O32 ABI has a maximum alignment of
// 8-bytes since the base of the stack is 8-byte aligned.
@@ -148,17 +148,18 @@ int test_v4i32(char *fmt, ...) {
// O32: [[TMP3:%.+]] = and i32 [[TMP2]], -8
// O32: [[AP_CUR:%.+]] = inttoptr i32 [[TMP3]] to i8*
//
-// NEW: [[TMP1:%.+]] = ptrtoint i8* [[AP_CUR]] to [[INTPTR_T]]
-// NEW: [[TMP2:%.+]] = add [[INTPTR_T]] [[TMP1]], 15
-// NEW: [[TMP3:%.+]] = and [[INTPTR_T]] [[TMP2]], -16
-// NEW: [[AP_CUR:%.+]] = inttoptr [[INTPTR_T]] [[TMP3]] to i8*
+// NEW: [[TMP1:%.+]] = ptrtoint i8* [[AP_CUR]] to [[$INTPTR_T]]
+// NEW: [[TMP2:%.+]] = add [[$INTPTR_T]] [[TMP1]], 15
+// NEW: [[TMP3:%.+]] = and [[$INTPTR_T]] [[TMP2]], -16
+// NEW: [[AP_CUR:%.+]] = inttoptr [[$INTPTR_T]] [[TMP3]] to i8*
//
-// ALL: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[INTPTR_T]] 16
-// ALL: store i8* [[AP_NEXT]], i8** %va, align [[PTRALIGN]]
+// ALL: [[AP_NEXT:%.+]] = getelementptr inbounds i8, i8* [[AP_CUR]], [[$INTPTR_T]] 16
+// ALL: store i8* [[AP_NEXT]], i8** %va, align [[$PTRALIGN]]
//
// ALL: [[AP_CAST:%.+]] = bitcast i8* [[AP_CUR]] to <4 x i32>*
// O32: [[ARG:%.+]] = load <4 x i32>, <4 x i32>* [[AP_CAST]], align 8
// N64: [[ARG:%.+]] = load <4 x i32>, <4 x i32>* [[AP_CAST]], align 16
+// N32: [[ARG:%.+]] = load <4 x i32>, <4 x i32>* [[AP_CAST]], align 16
// ALL: store <4 x i32> [[ARG]], <4 x i32>* [[V]], align 16
//
// ALL: [[VA1:%.+]] = bitcast i8** %va to i8*
diff --git a/test/CodeGen/mmx-builtins.c b/test/CodeGen/mmx-builtins.c
index ddc6f66548..cd725e22b8 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/mozilla-ms-inline-asm.c b/test/CodeGen/mozilla-ms-inline-asm.c
index 3335a87fef..0774c8cb30 100644
--- a/test/CodeGen/mozilla-ms-inline-asm.c
+++ b/test/CodeGen/mozilla-ms-inline-asm.c
@@ -18,25 +18,25 @@ void invoke(void* that, unsigned methodIndex,
// CHECK: store i32 %2, i32* %7, align 4
// CHECK: store i8* %3, i8** %8, align 4
// CHECK: call void asm sideeffect inteldialect
-// CHECK: mov edx,dword ptr $1
-// CHECK: test edx,edx
-// CHECK: jz {{[^_]*}}__MSASMLABEL_.${:uid}__noparams
-// ^ Can't use {{.*}} here because the matching is greedy.
-// CHECK: mov eax,edx
-// CHECK: shl eax,$$3
-// CHECK: sub esp,eax
-// CHECK: mov ecx,esp
-// CHECK: push dword ptr $0
-// CHECK: call dword ptr $2
-// CHECK: {{.*}}__MSASMLABEL_.${:uid}__noparams:
-// CHECK: mov ecx,dword ptr $3
-// CHECK: push ecx
-// CHECK: mov edx,[ecx]
-// CHECK: mov eax,dword ptr $4
-// CHECK: call dword ptr[edx+eax*$$4]
-// CHECK: mov esp,ebp
-// CHECK: pop ebp
-// CHECK: ret
+// CHECK-SAME: mov edx,$1
+// CHECK-SAME: test edx,edx
+// CHECK-SAME: jz {{[^_]*}}__MSASMLABEL_.${:uid}__noparams
+// ^ Can't use {{.*}} here because the matching is greedy.
+// CHECK-SAME: mov eax,edx
+// CHECK-SAME: shl eax,$$3
+// CHECK-SAME: sub esp,eax
+// CHECK-SAME: mov ecx,esp
+// CHECK-SAME: push $0
+// CHECK-SAME: call dword ptr $2
+// CHECK-SAME: {{.*}}__MSASMLABEL_.${:uid}__noparams:
+// CHECK-SAME: mov ecx,$3
+// CHECK-SAME: push ecx
+// CHECK-SAME: mov edx,[ecx]
+// CHECK-SAME: mov eax,$4
+// CHECK-SAME: call dword ptr[edx + eax * $$4]
+// CHECK-SAME: mov esp,ebp
+// CHECK-SAME: pop ebp
+// CHECK-SAME: ret
// CHECK: "=*m,*m,*m,*m,*m,~{eax},~{ebp},~{ecx},~{edx},~{flags},~{esp},~{dirflag},~{fpsr},~{flags}"
// CHECK: (i8** %8, i32* %7, void (...)* bitcast (void ()* @invoke_copy_to_stack to void (...)*), i8** %5, i32* %6)
// CHECK: ret void
diff --git a/test/CodeGen/ms-annotation.c b/test/CodeGen/ms-annotation.c
new file mode 100644
index 0000000000..6f4a20c7b1
--- /dev/null
+++ b/test/CodeGen/ms-annotation.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple i686-windows %s -fms-extensions -emit-llvm -o - | FileCheck %s
+//
+// Test that LLVM optimizations leave these intrinsics alone, for the most part.
+// RUN: %clang_cc1 -O2 -triple i686-windows %s -fms-extensions -emit-llvm -o - | FileCheck %s
+
+void test1(void) {
+ __annotation(L"a1");
+ __annotation(L"a1", L"a2");
+ __annotation(L"a1", L"a2", L"a3");
+ __annotation(L"multi " L"part " L"string");
+ __annotation(L"unicode: \u0ca0_\u0ca0");
+}
+
+// CHECK-LABEL: define void @test1()
+// CHECK: call void @llvm.codeview.annotation(metadata ![[A1:[0-9]+]])
+// CHECK: call void @llvm.codeview.annotation(metadata ![[A2:[0-9]+]])
+// CHECK: call void @llvm.codeview.annotation(metadata ![[A3:[0-9]+]])
+// CHECK: call void @llvm.codeview.annotation(metadata ![[A4:[0-9]+]])
+// CHECK: call void @llvm.codeview.annotation(metadata ![[A5:[0-9]+]])
+// CHECK: ret void
+
+// CHECK: ![[A1]] = !{!"a1"}
+// CHECK: ![[A2]] = !{!"a1", !"a2"}
+// CHECK: ![[A3]] = !{!"a1", !"a2", !"a3"}
+// CHECK: ![[A4]] = !{!"multi part string"}
+// CHECK: ![[A5]] = !{!"unicode: \E0\B2\A0_\E0\B2\A0"}
diff --git a/test/CodeGen/ms-barriers-intrinsics.c b/test/CodeGen/ms-barriers-intrinsics.c
index b0dfc3042a..c7da50cd0d 100644
--- a/test/CodeGen/ms-barriers-intrinsics.c
+++ b/test/CodeGen/ms-barriers-intrinsics.c
@@ -13,19 +13,19 @@ typedef __SIZE_TYPE__ size_t;
void test_ReadWriteBarrier() { _ReadWriteBarrier(); }
// CHECK-LABEL: define void @test_ReadWriteBarrier
-// CHECK: fence singlethread seq_cst
+// CHECK: fence syncscope("singlethread") seq_cst
// CHECK: ret void
// CHECK: }
void test_ReadBarrier() { _ReadBarrier(); }
// CHECK-LABEL: define void @test_ReadBarrier
-// CHECK: fence singlethread seq_cst
+// CHECK: fence syncscope("singlethread") seq_cst
// CHECK: ret void
// CHECK: }
void test_WriteBarrier() { _WriteBarrier(); }
// CHECK-LABEL: define void @test_WriteBarrier
-// CHECK: fence singlethread seq_cst
+// CHECK: fence syncscope("singlethread") seq_cst
// CHECK: ret void
// CHECK: }
diff --git a/test/CodeGen/ms-inline-asm-64.c b/test/CodeGen/ms-inline-asm-64.c
index d6f6e2ee0e..5b144eb7bb 100644
--- a/test/CodeGen/ms-inline-asm-64.c
+++ b/test/CodeGen/ms-inline-asm-64.c
@@ -5,14 +5,18 @@ void t1() {
int var = 10;
__asm mov rax, offset var ; rax = address of myvar
// CHECK: t1
-// CHECK: call void asm sideeffect inteldialect "mov rax, $0", "r,~{rax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: mov rax, $0
+// CHECK-SAME: "r,~{rax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
}
void t2() {
int var = 10;
__asm mov [eax], offset var
// CHECK: t2
-// CHECK: call void asm sideeffect inteldialect "mov [eax], $0", "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: mov [eax], $0
+// CHECK-SAME: "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
}
struct t3_type { int a, b; };
@@ -28,7 +32,11 @@ int t3() {
}
return foo.b;
// CHECK: t3
-// CHECK: call void asm sideeffect inteldialect "lea ebx, qword ptr $0\0A\09mov eax, [ebx].0\0A\09mov [ebx].4, ecx", "*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(%struct.t3_type* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: lea ebx, $0
+// CHECK-SAME: mov eax, [ebx]
+// CHECK-SAME: mov [ebx + $$4], ecx
+// CHECK-SAME: "*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(%struct.t3_type* %{{.*}})
}
int t4() {
@@ -44,5 +52,9 @@ int t4() {
}
return foo.b;
// CHECK: t4
-// CHECK: call void asm sideeffect inteldialect "lea ebx, qword ptr $0\0A\09mov eax, [ebx].0\0A\09mov [ebx].4, ecx", "*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(%struct.t3_type* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: lea ebx, $0
+// CHECK-SAME: mov eax, [ebx]
+// CHECK-SAME: mov [ebx + $$4], ecx
+// CHECK-SAME: "*m,~{eax},~{ebx},~{dirflag},~{fpsr},~{flags}"(%struct.t3_type* %{{.*}})
}
diff --git a/test/CodeGen/ms-inline-asm-EVEN.c b/test/CodeGen/ms-inline-asm-EVEN.c
new file mode 100644
index 0000000000..a188af3091
--- /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-avx512.c b/test/CodeGen/ms-inline-asm-avx512.c
index c1b783a210..6189e50d21 100644
--- a/test/CodeGen/ms-inline-asm-avx512.c
+++ b/test/CodeGen/ms-inline-asm-avx512.c
@@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 %s -triple x86_64-pc-windows-msvc -target-cpu knl -fasm-blocks -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-pc-windows-msvc -target-cpu skylake-avx512 -fasm-blocks -emit-llvm -o - | FileCheck %s
void t1() {
// CHECK: @t1
@@ -19,3 +19,16 @@ void t2() {
vaddpd zmm8 {k1}, zmm27, zmm6
}
}
+
+void ignore_fe_size() {
+ // CHECK-LABEL: define void @ignore_fe_size()
+ char c;
+ // CHECK: vaddps xmm1, xmm2, $1{1to4}
+ __asm vaddps xmm1, xmm2, [c]{1to4}
+ // CHECK: vaddps xmm1, xmm2, $2
+ __asm vaddps xmm1, xmm2, [c]
+ // CHECK: mov eax, $3
+ __asm mov eax, [c]
+ // CHECK: mov $0, rax
+ __asm mov [c], rax
+}
diff --git a/test/CodeGen/ms-inline-asm-enums.cpp b/test/CodeGen/ms-inline-asm-enums.cpp
new file mode 100644
index 0000000000..4e9225ab47
--- /dev/null
+++ b/test/CodeGen/ms-inline-asm-enums.cpp
@@ -0,0 +1,55 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 %s -fasm-blocks -triple i386-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+namespace x {
+ enum { A = 12 };
+ struct y_t {
+ enum { A = 17 };
+ int r;
+ } y;
+}
+
+// CHECK-LABEL: t1
+void t1() {
+ enum { A = 1 };
+ // CHECK: call void asm
+ // CHECK-SAME: mov eax, $$12
+ __asm mov eax, x::A
+ // CHECK-SAME: mov eax, $$17
+ __asm mov eax, x::y_t::A
+ // CHECK-NEXT: call void asm
+ // CHECK-SAME: mov eax, $$1
+ __asm {mov eax, A}
+}
+
+// CHECK-LABEL: t2
+void t2() {
+ enum { A = 1, B };
+ // CHECK: call void asm
+ // CHECK-SAME: mov eax, $$21
+ __asm mov eax, (A + 9) * 2 + A
+ // CHECK-SAME: mov eax, $$4
+ __asm mov eax, A << 2
+ // CHECK-SAME: mov eax, $$2
+ __asm mov eax, B & 3
+ // CHECK-SAME: mov eax, $$5
+ __asm mov eax, 3 + (B & 3)
+ // CHECK-SAME: mov eax, $$8
+ __asm mov eax, 2 << A * B
+}
+
+// CHECK-LABEL: t3
+void t3() {
+ int arr[4];
+ enum { A = 4, B };
+ // CHECK: call void asm
+ // CHECK-SAME: mov eax, [eax + $$47]
+ __asm { mov eax, [(x::A + 9) + A * B + 3 + 3 + eax] }
+ // CHECK-NEXT: call void asm
+ // CHECK-SAME: mov eax, dword ptr $0[$$4]
+ __asm { mov eax, dword ptr [arr + A] }
+ // CHECK-NEXT: call void asm
+ // CHECK-SAME: mov eax, dword ptr $0[$$8]
+ __asm { mov eax, dword ptr A[arr + A] }
+}
+
diff --git a/test/CodeGen/ms-inline-asm-variables.c b/test/CodeGen/ms-inline-asm-variables.c
new file mode 100644
index 0000000000..f8fd227610
--- /dev/null
+++ b/test/CodeGen/ms-inline-asm-variables.c
@@ -0,0 +1,35 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 %s -fasm-blocks -triple i386-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+int gVar;
+void t1() {
+ // CHECK: add eax, dword ptr gVar[eax]
+ __asm add eax, dword ptr gVar[eax]
+ // CHECK: add dword ptr gVar[eax], eax
+ __asm add dword ptr [eax+gVar], eax
+ // CHECK: add ebx, dword ptr gVar[ebx + $$270]
+ __asm add ebx, dword ptr gVar[271 - 82 + 81 + ebx]
+ // CHECK: add dword ptr gVar[ebx + $$828], ebx
+ __asm add dword ptr [ebx + gVar + 828], ebx
+ // CHECK: add ecx, dword ptr gVar[ecx + ecx * $$4 + $$4590]
+ __asm add ecx, dword ptr gVar[4590 + ecx + ecx*4]
+ // CHECK: add dword ptr gVar[ecx + ecx * $$8 + $$73], ecx
+ __asm add dword ptr [gVar + ecx + 45 + 23 - 53 + 60 - 2 + ecx*8], ecx
+ // CHECK: add gVar[ecx + ebx + $$7], eax
+ __asm add 1 + 1 + 2 + 3[gVar + ecx + ebx], eax
+}
+
+void t2() {
+ int lVar;
+ // CHECK: mov eax, dword ptr ${{[0-9]}}[eax]
+ __asm mov eax, dword ptr lVar[eax]
+ // CHECK: mov dword ptr ${{[0-9]}}[eax], eax
+ __asm mov dword ptr [eax+lVar], eax
+ // CHECK: mov ebx, dword ptr ${{[0-9]}}[ebx + $$270]
+ __asm mov ebx, dword ptr lVar[271 - 82 + 81 + ebx]
+ // CHECK: mov dword ptr ${{[0-9]}}[ebx + $$828], ebx
+ __asm mov dword ptr [ebx + lVar + 828], ebx
+ // CHECK: mov ${{[0-9]}}[ebx + $$47], eax
+ __asm mov 5 + 8 + 13 + 21[lVar + ebx], eax
+}
+
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index 69b732c9ac..c03f0deb05 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -42,7 +42,7 @@ void t5(void) {
void t6(void) {
__asm int 0x2c
// CHECK: t6
-// CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "int $$44", "~{dirflag},~{fpsr},~{flags}"()
}
void t7() {
@@ -61,7 +61,7 @@ void t7() {
mov eax, ebx
}
// CHECK: t7
-// CHECK: call void asm sideeffect inteldialect "int $$0x2cU", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "int $$44", "~{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}"()
}
@@ -92,7 +92,11 @@ void t9() {
__asm { pop ebx }
}
// CHECK: t9
-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx\0A\09", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: push ebx
+// CHECK-SAME: mov ebx, $$7
+// CHECK-SAME: pop ebx
+// CHECK-SAME: "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
unsigned t10(void) {
@@ -107,7 +111,10 @@ unsigned t10(void) {
// CHECK: [[I:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: [[J:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: store i32 1, i32* [[I]], align 4
-// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $2\0A\09mov dword ptr $0, eax", "=*m,={eax},*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}})
+// CHECK: call i32 asm sideeffect inteldialect
+// CHECK-SAME: mov eax, $2
+// CHECK-SAME: mov $0, eax
+// CHECK-SAME: "=*m,={eax},*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}})
// CHECK: [[RET:%[a-zA-Z0-9]+]] = load i32, i32* [[J]], align 4
// CHECK: ret i32 [[RET]]
}
@@ -128,7 +135,12 @@ unsigned t12(void) {
}
return j + m;
// CHECK: t12
-// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $3\0A\09mov dword ptr $0, eax\0A\09mov eax, dword ptr $4\0A\09mov dword ptr $1, eax", "=*m,=*m,={eax},*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}})
+// CHECK: call i32 asm sideeffect inteldialect
+// CHECK-SAME: mov eax, $3
+// CHECK-SAME: mov $0, eax
+// CHECK-SAME: mov eax, $4
+// CHECK-SAME: mov $1, eax
+// CHECK-SAME: "=*m,=*m,={eax},*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}}, i32* %{{.*}})
}
void t13() {
@@ -136,8 +148,23 @@ void t13() {
short j = 2;
__asm movzx eax, i
__asm movzx eax, j
-// CHECK: t13
-// CHECK: call void asm sideeffect inteldialect "movzx eax, byte ptr $0\0A\09movzx eax, word ptr $1", "*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i8* %{{.*}}i, i16* %{{.*}}j)
+// CHECK-LABEL: define void @t13()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: movzx eax, byte ptr $0
+// CHECK-SAME: movzx eax, word ptr $1
+// CHECK-SAME: "*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i8* %{{.*}}i, i16* %{{.*}}j)
+}
+
+void t13_brac() {
+ char i = 1;
+ short j = 2;
+ __asm movzx eax, [i]
+ __asm movzx eax, [j]
+// CHECK-LABEL: define void @t13_brac()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: movzx eax, byte ptr $0
+// CHECK-SAME: movzx eax, word ptr $1
+// CHECK-SAME: "*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i8* %{{.*}}i, i16* %{{.*}}j)
}
void t14() {
@@ -150,7 +177,7 @@ void t14() {
.endif
}
// CHECK: t14
-// CHECK: call void asm sideeffect inteldialect ".if 1\0A\09mov eax, dword ptr $0\0A\09.else\0A\09mov ebx, j\0A\09.endif", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect ".if 1\0A\09mov eax, $0\0A\09.else\0A\09mov ebx, j\0A\09.endif", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
}
int gvar = 10;
@@ -158,7 +185,7 @@ void t15() {
// CHECK: t15
int lvar = 10;
__asm mov eax, lvar ; eax = 10
-// CHECK: mov eax, dword ptr $0
+// CHECK: mov eax, $0
__asm mov eax, offset lvar ; eax = address of lvar
// CHECK: mov eax, $1
__asm mov eax, offset gvar ; eax = address of gvar
@@ -201,6 +228,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 + $$4]
__asm mov eax, TYPE foo
// CHECK: mov eax, $$4
@@ -210,6 +239,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 + $$16]
__asm mov eax, SIZE foo
// CHECK: mov eax, $$4
@@ -217,9 +248,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 + $$64]
__asm mov eax, SIZE _bar
// CHECK: mov eax, $$2
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
+
}
void t21() {
@@ -229,7 +263,11 @@ void t21() {
__asm pop ebx
}
// CHECK: t21
-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$07H\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: push ebx
+// CHECK-SAME: mov ebx, $$7
+// CHECK-SAME: pop ebx
+// CHECK-SAME: "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
extern void t22_helper(int x);
@@ -245,9 +283,15 @@ void t22() {
__asm pop ebx
}
// CHECK: t22
-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, esp", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: push ebx
+// CHECK-SAME: mov ebx, esp
+// CHECK-SAME: "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void @t22_helper
-// CHECK: call void asm sideeffect inteldialect "mov esp, ebx\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: mov esp, ebx
+// CHECK-SAME: pop ebx
+// CHECK-SAME: "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
void t23() {
@@ -268,13 +312,13 @@ void t24() {
void t25() {
// CHECK: t25
__asm mov eax, 0ffffffffh
-// CHECK: mov eax, $$0ffffffffh
+// CHECK: mov eax, $$4294967295
__asm mov eax, 0fhU
// CHECK: mov eax, $$15
__asm mov eax, 0a2h
-// CHECK: mov eax, $$0a2h
+// CHECK: mov eax, $$162
__asm mov eax, 10100010b
-// CHECK: mov eax, $$10100010b
+// CHECK: mov eax, $$162
__asm mov eax, 10100010BU
// CHECK: mov eax, $$162
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
@@ -300,7 +344,7 @@ void t26() {
void t27() {
__asm mov eax, fs:[0h]
// CHECK: t27
-// CHECK: call void asm sideeffect inteldialect "mov eax, fs:[$$0h]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, fs:[$$0]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t28() {
@@ -335,9 +379,9 @@ int *t30()
{
int *res;
__asm lea edi, results
-// CHECK: lea edi, dword ptr $2
+// CHECK: lea edi, $2
__asm mov res, edi
-// CHECK: mov dword ptr $0, edi
+// CHECK: mov $0, edi
return res;
// CHECK: "=*m,={eax},*m,~{edi},~{dirflag},~{fpsr},~{flags}"(i32** %{{.*}}, [2 x i32]* @{{.*}})
}
@@ -355,7 +399,7 @@ void t32() {
// CHECK: t32
int i;
__asm mov eax, i
-// CHECK: mov eax, dword ptr $0
+// CHECK: mov eax, $0
__asm mov eax, dword ptr i
// CHECK: mov eax, dword ptr $1
__asm mov ax, word ptr i
@@ -369,7 +413,7 @@ void t33() {
// CHECK: t33
int i;
__asm mov eax, [i]
-// CHECK: mov eax, dword ptr $0
+// CHECK: mov eax, $0
__asm mov eax, dword ptr [i]
// CHECK: mov eax, dword ptr $1
__asm mov ax, word ptr [i]
@@ -382,18 +426,18 @@ void t33() {
void t34() {
// CHECK: t34
__asm prefetchnta 64[eax]
-// CHECK: prefetchnta $$64[eax]
+// CHECK: prefetchnta [eax + $$64]
__asm mov eax, dword ptr 4[eax]
-// CHECK: mov eax, dword ptr $$4[eax]
+// CHECK: mov eax, dword ptr [eax + $$4]
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t35() {
// CHECK: t35
__asm prefetchnta [eax + (200*64)]
-// CHECK: prefetchnta [eax + ($$200*$$64)]
+// CHECK: prefetchnta [eax + $$12800]
__asm mov eax, dword ptr [eax + (200*64)]
-// CHECK: mov eax, dword ptr [eax + ($$200*$$64)]
+// CHECK: mov eax, dword ptr [eax + $$12800]
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
@@ -402,31 +446,31 @@ void t36() {
int arr[4];
// Work around PR20368: These should be single line blocks
__asm { mov eax, 4[arr] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 4[arr + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$8]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 8[arr + 4 + 32*2 - 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$72$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$72]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 12[4 + arr] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$16$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$16]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 4[4 + arr + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$12$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$12]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 4[64 + arr + (2*32)] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$132$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$132]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 4[64 + arr - 2*32] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, [arr + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, [arr + 4 + 32*2 - 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$64$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$64]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, [4 + arr] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, [4 + arr + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$8]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, [64 + arr + (2*32)] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$128$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$128]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, [64 + arr - 2*32] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
}
void t37() {
@@ -440,13 +484,13 @@ void t37() {
__asm mov eax, (4 + 4) * 16
// CHECK: mov eax, $$128
__asm mov eax, 4 + 8 * -16
-// CHECK: mov eax, $$4294967172
+// CHECK: mov eax, $$-124
__asm mov eax, 4 + 16 / -8
// CHECK: mov eax, $$2
__asm mov eax, (16 + 16) / -8
-// CHECK: mov eax, $$4294967292
+// CHECK: mov eax, $$-4
__asm mov eax, ~15
-// CHECK: mov eax, $$4294967280
+// CHECK: mov eax, $$-16
__asm mov eax, 6 ^ 3
// CHECK: mov eax, $$5
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
@@ -457,21 +501,21 @@ void t38() {
int arr[4];
// Work around PR20368: These should be single line blocks
__asm { mov eax, 4+4[arr] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$8]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, (4+4)[arr + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$12$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$12]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 8*2[arr + 4 + 32*2 - 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$80$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$80]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 12+20[4 + arr] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$36$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$36]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 4*16+4[4 + arr + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$76$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$76]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 4*4[64 + arr + (2*32)] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$144$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$144]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 4*(4-2)[64 + arr - 2*32] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$8]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
__asm { mov eax, 32*(4-2)[arr - 2*32] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$0$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"([4 x i32]* %{{.*}})
}
void cpuid() {
@@ -483,7 +527,7 @@ void cpuid() {
typedef struct {
int a;
int b;
-} A;
+} A, *pA;
typedef struct {
int b1;
@@ -495,24 +539,28 @@ typedef struct {
A c2;
int c3;
B c4;
-} C;
+} C, *pC;
void t39() {
// CHECK-LABEL: define void @t39
__asm mov eax, [eax].A.b
-// CHECK: mov eax, [eax].4
+// CHECK: mov eax, [eax + $$4]
__asm mov eax, [eax] A.b
-// CHECK: mov eax, [eax] .4
+// CHECK: mov eax, [eax + $$4]
+ __asm mov eax, [eax] pA.b
+// CHECK: mov eax, [eax + $$4]
__asm mov eax, fs:[0] A.b
-// CHECK: mov eax, fs:[$$0] .4
+// CHECK: mov eax, fs:[$$4]
__asm mov eax, [eax].B.b2.a
-// CHECK: mov eax, [eax].4
+// CHECK: mov eax, [eax + $$4]
__asm mov eax, [eax] B.b2.b
-// CHECK: mov eax, [eax] .8
+// CHECK: mov eax, [eax + $$8]
__asm mov eax, fs:[0] C.c2.b
-// CHECK: mov eax, fs:[$$0] .8
+// CHECK: mov eax, fs:[$$8]
__asm mov eax, [eax]C.c4.b2.b
-// CHECK: mov eax, [eax].24
+// CHECK: mov eax, [eax + $$24]
+ __asm mov eax, [eax]pC.c4.b2.b
+// CHECK: mov eax, [eax + $$24]
// CHECK: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
@@ -547,7 +595,7 @@ void t42() {
// CHECK-LABEL: define void @t42
int flags;
__asm mov flags, eax
-// CHECK: mov dword ptr $0, eax
+// CHECK: mov $0, eax
// CHECK: "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %flags)
}
@@ -556,31 +604,67 @@ void t43() {
C strct;
// Work around PR20368: These should be single line blocks
__asm { mov eax, 4[strct.c1] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, 4[strct.c3 + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$8]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, 8[strct.c2.a + 4 + 32*2 - 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$72$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$72]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, 12[4 + strct.c2.b] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$16$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$16]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, 4[4 + strct.c4.b2.b + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$12$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$12]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, 4[64 + strct.c1 + (2*32)] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$132$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$132]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, 4[64 + strct.c2.a - 2*32] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, [strct.c4.b1 + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, [strct.c4.b2.a + 4 + 32*2 - 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$64$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$64]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, [4 + strct.c1] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$4]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, [4 + strct.c2.b + 4] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$8$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$8]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, [64 + strct.c3 + (2*32)] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$128$0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0[$$128]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
__asm { mov eax, [64 + strct.c4.b2.b - 2*32] }
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+}
+
+void t44() {
+ // CHECK-LABEL: define void @t44
+ __asm {
+ mov cr0, eax
+ mov cr2, ebx
+ mov cr3, ecx
+ mov cr4, edx
+ }
+ // CHECK: call void asm sideeffect inteldialect "mov cr0, eax\0A\09mov cr2, ebx\0A\09mov cr3, ecx\0A\09mov cr4, edx", "~{cr0},~{cr2},~{cr3},~{cr4},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t45() {
+ // CHECK-LABEL: define void @t45
+ __asm {
+ mov dr0, eax
+ mov dr1, ebx
+ mov dr2, ebx
+ mov dr3, ecx
+ mov dr6, edx
+ mov dr7, ecx
+ }
+ // CHECK: call void asm sideeffect inteldialect "mov dr0, eax\0A\09mov dr1, ebx\0A\09mov dr2, ebx\0A\09mov dr3, ecx\0A\09mov dr6, edx\0A\09mov dr7, ecx", "~{dr0},~{dr1},~{dr2},~{dr3},~{dr6},~{dr7},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t46() {
+ // CHECK-LABEL: define void @t46
+ __asm add eax, -128[eax]
+ // CHECK: call void asm sideeffect inteldialect "add eax, [eax + $$-128]", "~{eax},~{flags},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void dot_operator(){
+ // CHECK-LABEL: define void @dot_operator
+ __asm { mov eax, 3[ebx]A.b}
+ // CHECK: call void asm sideeffect inteldialect "mov eax, [ebx + $$7]", "~{eax},~{dirflag},~{fpsr},~{flags}"
}
void call_clobber() {
@@ -643,10 +727,12 @@ void label5() {
void label6(){
__asm {
jmp short label
+ jc short label
+ jz short label
label:
}
// CHECK-LABEL: define void @label6
- // CHECK: call void asm sideeffect inteldialect "jmp {{.*}}__MSASMLABEL_.${:uid}__label\0A\09{{.*}}__MSASMLABEL_.${:uid}__label:", "~{dirflag},~{fpsr},~{flags}"()
+ // CHECK: jmp {{.*}}__MSASMLABEL_.${:uid}__label\0A\09jc {{.*}}__MSASMLABEL_.${:uid}__label\0A\09jz {{.*}}__MSASMLABEL_.${:uid}__label\0A\09{{.*}}__MSASMLABEL_.${:uid}__label:"
}
// Don't include mxcsr in the clobber list.
@@ -655,7 +741,7 @@ void mxcsr() {
__asm fxrstor buf
}
// CHECK-LABEL: define void @mxcsr
-// CHECK: call void asm sideeffect inteldialect "fxrstor byte ptr $0", "=*m,~{dirflag},~{fpsr},~{flags}"
+// CHECK: call void asm sideeffect inteldialect "fxrstor $0", "=*m,~{dirflag},~{fpsr},~{flags}"
typedef union _LARGE_INTEGER {
struct {
@@ -673,7 +759,7 @@ int test_indirect_field(LARGE_INTEGER LargeInteger) {
__asm mov eax, LargeInteger.LowPart
}
// CHECK-LABEL: define i32 @test_indirect_field(
-// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $1",
+// CHECK: call i32 asm sideeffect inteldialect "mov eax, $1",
// MS ASM containing labels must not be duplicated (PR23715).
// CHECK: attributes [[ATTR1]] = {
diff --git a/test/CodeGen/ms-inline-asm.cpp b/test/CodeGen/ms-inline-asm.cpp
index 424c1992cc..039cde9e10 100644
--- a/test/CodeGen/ms-inline-asm.cpp
+++ b/test/CodeGen/ms-inline-asm.cpp
@@ -14,15 +14,21 @@ struct Foo {
};
void t1() {
+// CHECK-LABEL: define void @_Z2t1v()
Foo::ptr = (int *)0xDEADBEEF;
Foo::Bar::ptr = (int *)0xDEADBEEF;
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: mov eax, $0
+// CHECK-SAME: mov eax, $1
+// CHECK-SAME: mov eax, $2
+// CHECK-SAME: mov eax, dword ptr $3
+// CHECK-SAME: mov eax, dword ptr $4
+// CHECK-SAME: "*m,*m,*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE)
__asm mov eax, Foo ::ptr
__asm mov eax, Foo :: Bar :: ptr
__asm mov eax, [Foo:: ptr]
__asm mov eax, dword ptr [Foo :: ptr]
__asm mov eax, dword ptr [Foo :: ptr]
-// CHECK: @_Z2t1v
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0\0A\09mov eax, dword ptr $1\0A\09mov eax, dword ptr $2\0A\09mov eax, dword ptr $3\0A\09mov eax, dword ptr $4", "*m,*m,*m,*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3ptrE)
}
int gvar = 10;
@@ -30,8 +36,11 @@ void t2() {
int lvar = 10;
__asm mov eax, offset Foo::ptr
__asm mov eax, offset Foo::Bar::ptr
-// CHECK: t2
-// CHECK: call void asm sideeffect inteldialect "mov eax, $0\0A\09mov eax, $1", "r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE)
+// CHECK-LABEL: define void @_Z2t2v()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: mov eax, $0
+// CHECK-SAME: mov eax, $1
+// CHECK-SAME: "r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE)
}
// CHECK-LABEL: define void @_Z2t3v()
@@ -50,7 +59,20 @@ void t3() {
__asm mov eax, SIZE Foo::Bar::ptr
__asm mov eax, SIZE Foo::arr
__asm mov eax, SIZE Foo::Bar::arr
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1\0A\09mov eax, $$1\0A\09mov eax, $$4\0A\09mov eax, $$2\0A\09mov eax, $$4\0A\09mov eax, $$4\0A\09mov eax, $$4\0A\09mov eax, $$1\0A\09mov eax, $$4\0A\09mov eax, $$4\0A\09mov eax, $$16\0A\09mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: mov eax, $$1
+// CHECK-SAME: mov eax, $$1
+// CHECK-SAME: mov eax, $$4
+// CHECK-SAME: mov eax, $$2
+// CHECK-SAME: mov eax, $$4
+// CHECK-SAME: mov eax, $$4
+// CHECK-SAME: mov eax, $$4
+// CHECK-SAME: mov eax, $$1
+// CHECK-SAME: mov eax, $$4
+// CHECK-SAME: mov eax, $$4
+// CHECK-SAME: mov eax, $$16
+// CHECK-SAME: mov eax, $$2
+// CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
@@ -67,7 +89,10 @@ void T4::test() {
// CHECK: [[X:%.*]] = getelementptr inbounds [[T4]], [[T4]]* [[THIS]], i32 0, i32 0
__asm mov eax, x;
__asm mov y, eax;
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $1\0A\09mov dword ptr $0, eax", "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* @_ZN2T41yE, i32* {{.*}})
+// CHECK: call void asm sideeffect inteldialect
+// CHECK-SAME: mov eax, $1
+// CHECK-SAME: mov $0, eax
+// CHECK-SAME: "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* @_ZN2T41yE, i32* {{.*}})
}
template <class T> struct T5 {
@@ -82,7 +107,11 @@ void test5() {
__asm push y
__asm call T5<int>::create<float>
__asm mov x, eax
- // CHECK: call void asm sideeffect inteldialect "push dword ptr $0\0A\09call dword ptr $2\0A\09mov dword ptr $1, eax", "=*m,=*m,*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %y, i32* %x, i32 (float)* @_ZN2T5IiE6createIfEEiT_)
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: push $0
+ // CHECK-SAME: call dword ptr $2
+ // CHECK-SAME: mov $1, eax
+ // CHECK-SAME: "=*m,=*m,*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %y, i32* %x, i32 (float)* @_ZN2T5IiE6createIfEEiT_)
}
// Just verify this doesn't emit an error.
@@ -100,7 +129,9 @@ void t7_struct() {
};
__asm mov eax, [eax].A.b
// CHECK-LABEL: define void @_Z9t7_structv
- // CHECK: call void asm sideeffect inteldialect "mov eax, [eax].4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: mov eax, [eax + $$4]
+ // CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t7_typedef() {
@@ -110,7 +141,9 @@ void t7_typedef() {
} A;
__asm mov eax, [eax].A.b
// CHECK-LABEL: define void @_Z10t7_typedefv
- // CHECK: call void asm sideeffect inteldialect "mov eax, [eax].4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: mov eax, [eax + $$4]
+ // CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t7_using() {
@@ -120,22 +153,46 @@ void t7_using() {
};
__asm mov eax, [eax].A.b
// CHECK-LABEL: define void @_Z8t7_usingv
- // CHECK: call void asm sideeffect inteldialect "mov eax, [eax].4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: mov eax, [eax + $$4]
+ // CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t8() {
__asm some_label:
// CHECK-LABEL: define void @_Z2t8v()
- // CHECK: call void asm sideeffect inteldialect "L__MSASMLABEL_.${:uid}__some_label:", "~{dirflag},~{fpsr},~{flags}"()
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: L__MSASMLABEL_.${:uid}__some_label:
+ // CHECK-SAME: "~{dirflag},~{fpsr},~{flags}"()
struct A {
static void g() {
__asm jmp some_label ; This should jump forwards
__asm some_label:
__asm nop
// CHECK-LABEL: define internal void @_ZZ2t8vEN1A1gEv()
- // CHECK: call void asm sideeffect inteldialect "jmp L__MSASMLABEL_.${:uid}__some_label\0A\09L__MSASMLABEL_.${:uid}__some_label:\0A\09nop", "~{dirflag},~{fpsr},~{flags}"()
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: jmp L__MSASMLABEL_.${:uid}__some_label
+ // CHECK-SAME: L__MSASMLABEL_.${:uid}__some_label:
+ // CHECK-SAME: nop
+ // CHECK-SAME: "~{dirflag},~{fpsr},~{flags}"()
}
};
A::g();
}
+void t9() {
+ // CHECK-LABEL: define void @_Z2t9v()
+ struct A {
+ int a;
+ int b;
+ void g() {
+ __asm mov eax, dword ptr [eax]this.b
+ // CHECK: call void asm sideeffect inteldialect
+ // CHECK-SAME: mov eax, dword ptr [eax + $$4]
+ // CHECK-SAME: "~{eax},~{dirflag},~{fpsr},~{flags}"()
+ }
+ };
+ A AA;
+ AA.g();
+}
+
diff --git a/test/CodeGen/ms-intrinsics-other.c b/test/CodeGen/ms-intrinsics-other.c
new file mode 100644
index 0000000000..d23bc73018
--- /dev/null
+++ b/test/CodeGen/ms-intrinsics-other.c
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -ffreestanding -fms-extensions \
+// RUN: -triple x86_64--darwin -Oz -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding -fms-extensions \
+// RUN: -triple x86_64--linux -Oz -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+// LP64 targets use 'long' as 'int' for MS intrinsics (-fms-extensions)
+#ifdef __LP64__
+#define LONG int
+#else
+#define LONG long
+#endif
+
+unsigned char test_BitScanForward(unsigned LONG *Index, unsigned LONG Mask) {
+ return _BitScanForward(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanForward(i32* {{[a-z_ ]*}}%Index, i32 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[a-z0-9._]+]] = icmp eq i32 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[INDEX:%[0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %Mask, i1 true)
+// CHECK: store i32 [[INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+
+unsigned char test_BitScanReverse(unsigned LONG *Index, unsigned LONG Mask) {
+ return _BitScanReverse(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanReverse(i32* {{[a-z_ ]*}}%Index, i32 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[0-9]+]] = icmp eq i32 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[REVINDEX:%[0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %Mask, i1 true)
+// CHECK: [[INDEX:%[0-9]+]] = xor i32 [[REVINDEX]], 31
+// CHECK: store i32 [[INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+
+#if defined(__x86_64__)
+unsigned char test_BitScanForward64(unsigned LONG *Index, unsigned __int64 Mask) {
+ return _BitScanForward64(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanForward64(i32* {{[a-z_ ]*}}%Index, i64 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[a-z0-9._]+]] = icmp eq i64 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[INDEX:%[0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %Mask, i1 true)
+// CHECK: [[TRUNC_INDEX:%[0-9]+]] = trunc i64 [[INDEX]] to i32
+// CHECK: store i32 [[TRUNC_INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+
+unsigned char test_BitScanReverse64(unsigned LONG *Index, unsigned __int64 Mask) {
+ return _BitScanReverse64(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanReverse64(i32* {{[a-z_ ]*}}%Index, i64 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[0-9]+]] = icmp eq i64 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[REVINDEX:%[0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %Mask, i1 true)
+// CHECK: [[TRUNC_REVINDEX:%[0-9]+]] = trunc i64 [[REVINDEX]] to i32
+// CHECK: [[INDEX:%[0-9]+]] = xor i32 [[TRUNC_REVINDEX]], 63
+// CHECK: store i32 [[INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+#endif
+
+LONG test_InterlockedExchange(LONG volatile *value, LONG mask) {
+ return _InterlockedExchange(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedExchange(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw xchg i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedExchangeAdd(LONG volatile *value, LONG mask) {
+ return _InterlockedExchangeAdd(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedExchangeAdd(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw add i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedExchangeSub(LONG volatile *value, LONG mask) {
+ return _InterlockedExchangeSub(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedExchangeSub(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw sub i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedOr(LONG volatile *value, LONG mask) {
+ return _InterlockedOr(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedOr(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw or i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedXor(LONG volatile *value, LONG mask) {
+ return _InterlockedXor(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedXor(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw xor i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedAnd(LONG volatile *value, LONG mask) {
+ return _InterlockedAnd(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedAnd(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw and i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) {
+ return _InterlockedCompareExchange(Destination, Exchange, Comperand);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedCompareExchange(i32*{{[a-z_ ]*}}%Destination, i32{{[a-z_ ]*}}%Exchange, i32{{[a-z_ ]*}}%Comperand){{.*}}{
+// CHECK: [[TMP:%[0-9]+]] = cmpxchg volatile i32* %Destination, i32 %Comperand, i32 %Exchange seq_cst seq_cst
+// CHECK: [[RESULT:%[0-9]+]] = extractvalue { i32, i1 } [[TMP]], 0
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+LONG test_InterlockedIncrement(LONG volatile *Addend) {
+ return _InterlockedIncrement(Addend);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedIncrement(i32*{{[a-z_ ]*}}%Addend){{.*}}{
+// CHECK: [[TMP:%[0-9]+]] = atomicrmw add i32* %Addend, i32 1 seq_cst
+// CHECK: [[RESULT:%[0-9]+]] = add i32 [[TMP]], 1
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+LONG test_InterlockedDecrement(LONG volatile *Addend) {
+ return _InterlockedDecrement(Addend);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedDecrement(i32*{{[a-z_ ]*}}%Addend){{.*}}{
+// CHECK: [[TMP:%[0-9]+]] = atomicrmw sub i32* %Addend, i32 1 seq_cst
+// CHECK: [[RESULT:%[0-9]+]] = add i32 [[TMP]], -1
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+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]]
diff --git a/test/CodeGen/ms-intrinsics-rotations.c b/test/CodeGen/ms-intrinsics-rotations.c
index 65d25cbe85..9533e6c3c6 100644
--- a/test/CodeGen/ms-intrinsics-rotations.c
+++ b/test/CodeGen/ms-intrinsics-rotations.c
@@ -1,181 +1,169 @@
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple i686--windows -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple thumbv7--windows -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple x86_64--windows -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple i686--linux -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple x86_64--linux -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-64BIT-LONG
-
-// rotate left
-
-unsigned char test_rotl8(unsigned char value, unsigned char shift) {
- return _rotl8(value, shift);
-}
-// CHECK: i8 @test_rotl8
-// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
-// CHECK: ret i8 [[RESULT]]
-// CHECK }
-
-unsigned short test_rotl16(unsigned short value, unsigned char shift) {
- return _rotl16(value, shift);
-}
-// CHECK: i16 @test_rotl16
-// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
-// CHECK: ret i16 [[RESULT]]
-// CHECK }
-
-unsigned int test_rotl(unsigned int value, int shift) {
- return _rotl(value, shift);
-}
-// CHECK: i32 @test_rotl
-// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK: ret i32 [[RESULT]]
-// CHECK }
-
-unsigned long test_lrotl(unsigned long value, int shift) {
- return _lrotl(value, shift);
-}
-// CHECK-32BIT-LONG: i32 @test_lrotl
-// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK-32BIT-LONG: ret i32 [[RESULT]]
-// CHECK-32BIT-LONG }
-
-// CHECK-64BIT-LONG: i64 @test_lrotl
-// CHECK-64BIT-LONG: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK-64BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK-64BIT-LONG: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-64BIT-LONG: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK-64BIT-LONG: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK-64BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK-64BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK-64BIT-LONG: ret i64 [[RESULT]]
-// CHECK-64BIT-LONG }
-
-unsigned __int64 test_rotl64(unsigned __int64 value, int shift) {
- return _rotl64(value, shift);
-}
-// CHECK: i64 @test_rotl64
-// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK: ret i64 [[RESULT]]
-// CHECK }
-
-// rotate right
-
-unsigned char test_rotr8(unsigned char value, unsigned char shift) {
- return _rotr8(value, shift);
-}
-// CHECK: i8 @test_rotr8
-// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
-// CHECK: ret i8 [[RESULT]]
-// CHECK }
-
-unsigned short test_rotr16(unsigned short value, unsigned char shift) {
- return _rotr16(value, shift);
-}
-// CHECK: i16 @test_rotr16
-// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
-// CHECK: ret i16 [[RESULT]]
-// CHECK }
-
-unsigned int test_rotr(unsigned int value, int shift) {
- return _rotr(value, shift);
-}
-// CHECK: i32 @test_rotr
-// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK: ret i32 [[RESULT]]
-// CHECK }
-
-unsigned long test_lrotr(unsigned long value, int shift) {
- return _lrotr(value, shift);
-}
-// CHECK-32BIT-LONG: i32 @test_lrotr
-// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK-32BIT-LONG: ret i32 [[RESULT]]
-// CHECK-32BIT-LONG }
-
-// CHECK-64BIT-LONG: i64 @test_lrotr
-// CHECK-64BIT-LONG: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK-64BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK-64BIT-LONG: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-64BIT-LONG: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK-64BIT-LONG: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK-64BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK-64BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK-64BIT-LONG: ret i64 [[RESULT]]
-// CHECK-64BIT-LONG }
-
-unsigned __int64 test_rotr64(unsigned __int64 value, int shift) {
- return _rotr64(value, shift);
-}
-// CHECK: i64 @test_rotr64
-// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK: ret i64 [[RESULT]]
-// CHECK }
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: %clang_cc1 -ffreestanding -fms-extensions \
+// RUN: -triple x86_64--darwin -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+
+// LP64 targets use 'long' as 'int' for MS intrinsics (-fms-extensions)
+#ifdef __LP64__
+#define LONG int
+#else
+#define LONG long
+#endif
+
+// rotate left
+
+unsigned char test_rotl8(unsigned char value, unsigned char shift) {
+ return _rotl8(value, shift);
+}
+// CHECK: i8 @test_rotl8
+// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
+// CHECK: ret i8 [[RESULT]]
+// CHECK }
+
+unsigned short test_rotl16(unsigned short value, unsigned char shift) {
+ return _rotl16(value, shift);
+}
+// CHECK: i16 @test_rotl16
+// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
+// CHECK: ret i16 [[RESULT]]
+// CHECK }
+
+unsigned int test_rotl(unsigned int value, int shift) {
+ return _rotl(value, shift);
+}
+// CHECK: i32 @test_rotl
+// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK: ret i32 [[RESULT]]
+// CHECK }
+
+unsigned LONG test_lrotl(unsigned LONG value, int shift) {
+ return _lrotl(value, shift);
+}
+// CHECK-32BIT-LONG: i32 @test_lrotl
+// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK-32BIT-LONG: ret i32 [[RESULT]]
+// CHECK-32BIT-LONG }
+
+unsigned __int64 test_rotl64(unsigned __int64 value, int shift) {
+ return _rotl64(value, shift);
+}
+// CHECK: i64 @test_rotl64
+// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
+// CHECK: ret i64 [[RESULT]]
+// CHECK }
+
+// rotate right
+
+unsigned char test_rotr8(unsigned char value, unsigned char shift) {
+ return _rotr8(value, shift);
+}
+// CHECK: i8 @test_rotr8
+// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
+// CHECK: ret i8 [[RESULT]]
+// CHECK }
+
+unsigned short test_rotr16(unsigned short value, unsigned char shift) {
+ return _rotr16(value, shift);
+}
+// CHECK: i16 @test_rotr16
+// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
+// CHECK: ret i16 [[RESULT]]
+// CHECK }
+
+unsigned int test_rotr(unsigned int value, int shift) {
+ return _rotr(value, shift);
+}
+// CHECK: i32 @test_rotr
+// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK: ret i32 [[RESULT]]
+// CHECK }
+
+unsigned LONG test_lrotr(unsigned LONG value, int shift) {
+ return _lrotr(value, shift);
+}
+// CHECK-32BIT-LONG: i32 @test_lrotr
+// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK-32BIT-LONG: ret i32 [[RESULT]]
+// CHECK-32BIT-LONG }
+
+unsigned __int64 test_rotr64(unsigned __int64 value, int shift) {
+ return _rotr64(value, shift);
+}
+// CHECK: i64 @test_rotr64
+// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
+// CHECK: ret i64 [[RESULT]]
+// CHECK }
diff --git a/test/CodeGen/ms-intrinsics.c b/test/CodeGen/ms-intrinsics.c
index 2d4ca5c272..818be7fd7f 100644
--- a/test/CodeGen/ms-intrinsics.c
+++ b/test/CodeGen/ms-intrinsics.c
@@ -434,6 +434,17 @@ __int64 test_InterlockedDecrement64(__int64 volatile *Addend) {
#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);
}
diff --git a/test/CodeGen/ms-x86-intrinsics.c b/test/CodeGen/ms-x86-intrinsics.c
index e635220e8c..51520d1f65 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/ms_abi.c b/test/CodeGen/ms_abi.c
index 97f66b29c5..407087e409 100644
--- a/test/CodeGen/ms_abi.c
+++ b/test/CodeGen/ms_abi.c
@@ -15,20 +15,20 @@ void f3(void) {
// FREEBSD-LABEL: define void @f3()
// WIN64-LABEL: define void @f3()
f1();
- // FREEBSD: call x86_64_win64cc void @f1()
+ // FREEBSD: call win64cc void @f1()
// WIN64: call void @f1()
f2();
// FREEBSD: call void @f2()
// WIN64: call x86_64_sysvcc void @f2()
}
-// FREEBSD: declare x86_64_win64cc void @f1()
+// FREEBSD: declare win64cc void @f1()
// FREEBSD: declare void @f2()
// WIN64: declare void @f1()
// WIN64: declare x86_64_sysvcc void @f2()
// Win64 ABI varargs
void __attribute__((ms_abi)) f4(int a, ...) {
- // FREEBSD-LABEL: define x86_64_win64cc void @f4
+ // FREEBSD-LABEL: define win64cc void @f4
// WIN64-LABEL: define void @f4
__builtin_ms_va_list ap;
__builtin_ms_va_start(ap, a);
diff --git a/test/CodeGen/ms_abi_aarch64.c b/test/CodeGen/ms_abi_aarch64.c
new file mode 100644
index 0000000000..4aa93f0085
--- /dev/null
+++ b/test/CodeGen/ms_abi_aarch64.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm < %s | FileCheck -check-prefix=LINUX %s
+// RUN: %clang_cc1 -triple aarch64-pc-win32 -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s
+
+void __attribute__((ms_abi)) f1(void);
+void f2(void);
+void f3(void) {
+ // LINUX-LABEL: define void @f3()
+ // WIN64-LABEL: define void @f3()
+ f1();
+ // LINUX: call win64cc void @f1()
+ // WIN64: call void @f1()
+ f2();
+ // LINUX: call void @f2()
+ // WIN64: call void @f2()
+}
+// LINUX: declare win64cc void @f1()
+// LINUX: declare void @f2()
+// WIN64: declare void @f1()
+// WIN64: declare void @f2()
+
+// Win64 ABI varargs
+void __attribute__((ms_abi)) f4(int a, ...) {
+ // LINUX-LABEL: define win64cc void @f4
+ // WIN64-LABEL: define void @f4
+ __builtin_ms_va_list ap;
+ __builtin_ms_va_start(ap, a);
+ // LINUX: %[[AP:.*]] = alloca i8*
+ // LINUX: call void @llvm.va_start
+ // WIN64: %[[AP:.*]] = alloca i8*
+ // WIN64: call void @llvm.va_start
+ int b = __builtin_va_arg(ap, int);
+ // LINUX: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+ // LINUX-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
+ // LINUX-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+ // LINUX-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+ // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
+ // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+ // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+ __builtin_ms_va_list ap2;
+ __builtin_ms_va_copy(ap2, ap);
+ // LINUX: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
+ // LINUX-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
+ // WIN64: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
+ __builtin_ms_va_end(ap);
+ // LINUX: call void @llvm.va_end
+ // WIN64: call void @llvm.va_end
+}
+
+// Let's verify that normal va_lists work right on Win64, too.
+void f5(int a, ...) {
+ // WIN64-LABEL: define void @f5
+ __builtin_va_list ap;
+ __builtin_va_start(ap, a);
+ // WIN64: %[[AP:.*]] = alloca i8*
+ // WIN64: call void @llvm.va_start
+ int b = __builtin_va_arg(ap, int);
+ // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
+ // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+ // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+ __builtin_va_list ap2;
+ __builtin_va_copy(ap2, ap);
+ // WIN64: call void @llvm.va_copy
+ __builtin_va_end(ap);
+ // WIN64: call void @llvm.va_end
+}
diff --git a/test/CodeGen/named_reg_global.c b/test/CodeGen/named_reg_global.c
index 1da6257468..232b74de1c 100644
--- a/test/CodeGen/named_reg_global.c
+++ b/test/CodeGen/named_reg_global.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X86-64
// RUN: %clang_cc1 -triple arm64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
-// RUN: %clang_cc1 -triple armv7-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
+// RUN: %clang_cc1 -triple armv7-linux-gnu -target-abi apcs-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM
// CHECK-NOT: @sp = common global
diff --git a/test/CodeGen/neon-aapcs-align.c b/test/CodeGen/neon-aapcs-align.c
new file mode 100644
index 0000000000..4b7e5ff4d3
--- /dev/null
+++ b/test/CodeGen/neon-aapcs-align.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple armv7a-none-eabi -target-feature +neon -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=AAPCS
+// RUN: %clang_cc1 -triple armv7a-none-gnueabi -target-feature +neon -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=AAPCS
+// RUN: %clang_cc1 -triple armv7a-none-freebsd -target-feature +neon -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=AAPCS
+
+// RUN: %clang_cc1 -triple armv7a-apple-ios -target-feature +neon -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=DEFAULT
+// RUN: %clang_cc1 -triple armv7a-none-android -target-feature +neon -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=DEFAULT
+// RUN: %clang_cc1 -triple armv7a-none-androideabi -target-feature +neon -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=DEFAULT
+
+#include <arm_neon.h>
+// Neon types have 64-bit alignment
+int32x4_t gl_b;
+void t3(int32x4_t *src) {
+// CHECK: @t3
+ gl_b = *src;
+// AAPCS: store <4 x i32> {{%.*}}, <4 x i32>* @gl_b, align 8
+// DEFAULT: store <4 x i32> {{%.*}}, <4 x i32>* @gl_b, align 16
+}
diff --git a/test/CodeGen/neon-immediate-ubsan.c b/test/CodeGen/neon-immediate-ubsan.c
index c3e1ce2330..aacf76a633 100644
--- a/test/CodeGen/neon-immediate-ubsan.c
+++ b/test/CodeGen/neon-immediate-ubsan.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple armv7s-linux-gnu -emit-llvm -o - %s \
+// RUN: %clang_cc1 -triple armv7s-linux-gnu -target-abi apcs-gnu -emit-llvm -o - %s \
// RUN: -target-feature +neon -target-cpu cortex-a8 \
// RUN: -fsanitize=signed-integer-overflow \
// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ARMV7
diff --git a/test/CodeGen/no-devirt.cpp b/test/CodeGen/no-devirt.cpp
new file mode 100644
index 0000000000..544b1394f4
--- /dev/null
+++ b/test/CodeGen/no-devirt.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 %s -DUSEIT -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+
+// Test with decls and template defs in pch, and just use in .cpp
+// RUN: %clang_cc1 %s -DTMPL_DEF_IN_HEADER -triple %itanium_abi_triple -emit-pch -o %t
+// RUN: %clang_cc1 %s -DTMPL_DEF_IN_HEADER -DUSEIT -triple %itanium_abi_triple -include-pch %t -emit-llvm -o - | FileCheck %s
+
+// Test with A in pch, and B and C in main
+// Test with just decls in pch, and template defs and use in .cpp
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -emit-pch -o %t
+// RUN: %clang_cc1 %s -DUSEIT -triple %itanium_abi_triple -include-pch %t -emit-llvm -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+template < typename T, int N = 0 > class TmplWithArray {
+public:
+ virtual T& operator [] (int idx);
+ virtual T& func1 (int idx);
+ virtual T& func2 (int idx);
+ T ar[N+1];
+};
+struct Wrapper {
+ TmplWithArray<bool, 10> data;
+ bool indexIt(int a) {
+ if (a > 6) return data[a] ; // Should devirtualize
+ if (a > 4) return data.func1(a); // Should devirtualize
+ return data.func2(a); // Should devirtualize
+ }
+};
+
+#ifdef TMPL_DEF_IN_HEADER
+template <typename T, int N> T& TmplWithArray<T, N >::operator[](int idx) {
+ return ar[idx];
+}
+template <typename T, int N> T& TmplWithArray<T, N >::func1(int idx) {
+ return ar[idx];
+}
+#endif // TMPL_DEF_IN_HEADER
+#endif // HEADER
+
+#ifdef USEIT
+#ifndef TMPL_DEF_IN_HEADER
+template <typename T, int N> T& TmplWithArray<T, N >::operator[](int idx) {
+ return ar[idx];
+}
+template <typename T, int N> T& TmplWithArray<T, N >::func1(int idx) {
+ return ar[idx];
+}
+#endif // !TMPL_DEF_IN_HEADER
+extern Wrapper ew;
+bool stuff(int p)
+{
+ return ew.indexIt(p);
+}
+#endif
+
+// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi
+// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func1Ei
+// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func2Ei
+
diff --git a/test/CodeGen/nobuiltin.c b/test/CodeGen/nobuiltin.c
index f80c3c332a..543918f674 100644
--- a/test/CodeGen/nobuiltin.c
+++ b/test/CodeGen/nobuiltin.c
@@ -4,6 +4,10 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fno-builtin -O1 -S -o - %s | FileCheck -check-prefix=NOSTRCPY -check-prefix=NOMEMSET %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fno-builtin-memset -O1 -S -o - %s | FileCheck -check-prefix=STRCPY -check-prefix=NOMEMSET %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -O1 -fexperimental-new-pass-manager -S -o - %s | FileCheck -check-prefix=STRCPY -check-prefix=MEMSET %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fno-builtin -O1 -fexperimental-new-pass-manager -S -o - %s | FileCheck -check-prefix=NOSTRCPY -check-prefix=NOMEMSET %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fno-builtin-memset -O1 -fexperimental-new-pass-manager -S -o - %s | FileCheck -check-prefix=STRCPY -check-prefix=NOMEMSET %s
+
void PR13497() {
char content[2];
// make sure we don't optimize this call to strcpy()
diff --git a/test/CodeGen/noduplicate-cxx11-test.cpp b/test/CodeGen/noduplicate-cxx11-test.cpp
index 01278632bf..bcec05f72a 100644
--- a/test/CodeGen/noduplicate-cxx11-test.cpp
+++ b/test/CodeGen/noduplicate-cxx11-test.cpp
@@ -17,4 +17,4 @@ int main() {
}
-// CHECK: attributes [[NI]] = { noduplicate nounwind{{.*}} }
+// CHECK: attributes [[NI]] = { noduplicate {{.*}}nounwind{{.*}} }
diff --git a/test/CodeGen/nullptr-arithmetic.c b/test/CodeGen/nullptr-arithmetic.c
new file mode 100644
index 0000000000..ce9c9765b0
--- /dev/null
+++ b/test/CodeGen/nullptr-arithmetic.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -S %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -S %s -emit-llvm -triple i686-unknown-unknown -o - | FileCheck %s
+// RUN: %clang_cc1 -S %s -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s
+
+#include <stdint.h>
+
+// This test is meant to verify code that handles the 'p = nullptr + n' idiom
+// used by some versions of glibc and gcc. This is undefined behavior but
+// it is intended there to act like a conversion from a pointer-sized integer
+// to a pointer, and we would like to tolerate that.
+
+#define NULLPTRI8 ((int8_t*)0)
+
+// This should get the inttoptr instruction.
+int8_t *test1(intptr_t n) {
+ return NULLPTRI8 + n;
+}
+// CHECK-LABEL: test1
+// CHECK: inttoptr
+// CHECK-NOT: getelementptr
+
+// This doesn't meet the idiom because the element type is larger than a byte.
+int16_t *test2(intptr_t n) {
+ return (int16_t*)0 + n;
+}
+// CHECK-LABEL: test2
+// CHECK: getelementptr
+// CHECK-NOT: inttoptr
+
+// This doesn't meet the idiom because the offset is subtracted.
+int8_t* test3(intptr_t n) {
+ return NULLPTRI8 - n;
+}
+// CHECK-LABEL: test3
+// CHECK: getelementptr
+// CHECK-NOT: inttoptr
+
+// This checks the case where the offset isn't pointer-sized.
+// The front end will implicitly cast the offset to an integer, so we need to
+// make sure that doesn't cause problems on targets where integers and pointers
+// are not the same size.
+int8_t *test4(int8_t b) {
+ return NULLPTRI8 + b;
+}
+// CHECK-LABEL: test4
+// CHECK: inttoptr
+// CHECK-NOT: getelementptr
diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c
index a824f554b5..a1095798c1 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 81b44a55a4..725c49214d 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/pascal-wchar-string.c b/test/CodeGen/pascal-wchar-string.c
index 626fc99f15..ac36e4028f 100644
--- a/test/CodeGen/pascal-wchar-string.c
+++ b/test/CodeGen/pascal-wchar-string.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s -fpascal-strings -fshort-wchar | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -fpascal-strings -fwchar-type=short -fno-signed-wchar | FileCheck %s
// rdar://8020384
#include <stddef.h>
diff --git a/test/CodeGen/pause.c b/test/CodeGen/pause.c
new file mode 100644
index 0000000000..1a8e10aec0
--- /dev/null
+++ b/test/CodeGen/pause.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -ffreestanding %s -triple=i386-pc-win32 -target-feature -sse2 -emit-llvm -o - -Wall -Werror | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding %s -triple=i386-pc-win32 -target-feature +sse2 -emit-llvm -o - -Wall -Werror | FileCheck %s
+
+
+#include <x86intrin.h>
+
+void test_mm_pause() {
+ // CHECK-LABEL: test_mm_pause
+ // CHECK: call void @llvm.x86.sse2.pause()
+ return _mm_pause();
+}
diff --git a/test/CodeGen/pgo-sample-thinlto-summary.c b/test/CodeGen/pgo-sample-thinlto-summary.c
new file mode 100644
index 0000000000..7045db08f2
--- /dev/null
+++ b/test/CodeGen/pgo-sample-thinlto-summary.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -O2 -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=SAMPLEPGO
+// 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
+// RUN: %clang_cc1 -O2 -fexperimental-new-pass-manager -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=SAMPLEPGO
+// RUN: %clang_cc1 -O2 -fexperimental-new-pass-manager -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);
+}
+
+// SAMPLEPGO-LABEL: define void @bar
+// THINLTO-LABEL: define void @bar
+// SAMPLEPGO-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.
+// SAMPLEPGO-LABEL: define void @unroll
+// THINLTO-LABEL: define void @unroll
+// SAMPLEPGO: call{{.*}}baz
+// SAMPLEPGO: call{{.*}}baz
+// THINLTO: call{{.*}}baz
+// THINLTO-NOT: call{{.*}}baz
+void unroll() {
+ for (int i = 0; i < 2; i++)
+ baz(i);
+}
+
+// Checks that icp is not invoked for ThinLTO, but invoked for normal samplepgo.
+// SAMPLEPGO-LABEL: define void @icp
+// THINLTO-LABEL: define void @icp
+// SAMPLEPGO: if.true.direct_targ
+// FIXME: the following condition needs to be reversed once
+// LTOPreLinkDefaultPipeline is customized.
+// THINLTO-NOT: if.true.direct_targ
+void icp(void (*p)()) {
+ p();
+}
diff --git a/test/CodeGen/piclevels.c b/test/CodeGen/piclevels.c
index 54744e2efa..f050af96ff 100644
--- a/test/CodeGen/piclevels.c
+++ b/test/CodeGen/piclevels.c
@@ -1,7 +1,12 @@
-// RUN: %clang_cc1 -emit-llvm -pic-level 2 %s -o - | FileCheck %s -check-prefix=CHECK-BIGPIC
-// RUN: %clang_cc1 -emit-llvm -pic-level 1 %s -o - | FileCheck %s -check-prefix=CHECK-SMALLPIC
+// RUN: %clang_cc1 -emit-llvm -pic-level 2 %s -o - | FileCheck %s -check-prefix=CHECK-BIGPIC -check-prefix=CHECK-NOPIE
+// RUN: %clang_cc1 -emit-llvm -pic-level 1 %s -o - | FileCheck %s -check-prefix=CHECK-SMALLPIC -check-prefix=CHECK-NOPIE
+// RUN: %clang_cc1 -emit-llvm -pic-level 2 -pic-is-pie %s -o - | FileCheck %s -check-prefix=CHECK-BIGPIC -check-prefix=CHECK-BIGPIE
+// RUN: %clang_cc1 -emit-llvm -pic-level 1 -pic-is-pie %s -o - | FileCheck %s -check-prefix=CHECK-SMALLPIC -check-prefix=CHECK-SMALLPIE
// CHECK-BIGPIC: !llvm.module.flags = !{{{.*}}}
-// CHECK-BIGPIC: !{{[0-9]+}} = !{i32 1, !"PIC Level", i32 2}
+// CHECK-BIGPIC: !{{[0-9]+}} = !{i32 7, !"PIC Level", i32 2}
// CHECK-SMALLPIC: !llvm.module.flags = !{{{.*}}}
-// CHECK-SMALLPIC: !{{[0-9]+}} = !{i32 1, !"PIC Level", i32 1}
+// CHECK-SMALLPIC: !{{[0-9]+}} = !{i32 7, !"PIC Level", i32 1}
+// CHECK-NOPIE-NOT: PIE Level
+// CHECK-BIGPIE: !{{[0-9]+}} = !{i32 7, !"PIE Level", i32 2}
+// CHECK-SMALLPIE: !{{[0-9]+}} = !{i32 7, !"PIE Level", i32 1}
diff --git a/test/CodeGen/ppc-vector-compare.cc b/test/CodeGen/ppc-vector-compare.cc
new file mode 100644
index 0000000000..e1c92bb6be
--- /dev/null
+++ b/test/CodeGen/ppc-vector-compare.cc
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -target-feature +vsx -triple powerpc64-unknown-unknown -emit-llvm %s \
+// RUN: -o - | FileCheck %s
+
+#include <altivec.h>
+
+// CHECK-LABEL: @_Z5test1Dv8_tS_
+// CHECK: @llvm.ppc.altivec.vcmpequh.p
+bool test1(vector unsigned short v1, vector unsigned short v2) {
+ return v1 == v2;
+}
+
+// CHECK-LABEL: @_Z5test2Dv2_mS_Dv2_lS0_Dv2_yS1_Dv2_xS2_Dv2_dS3_
+bool test2(vector unsigned long v1, vector unsigned long v2,
+ vector long v3, vector long v4,
+ vector unsigned long long v5, vector unsigned long long v6,
+ vector long long v7, vector long long v8,
+ vector double v9, vector double v10) {
+ // CHECK: @llvm.ppc.altivec.vcmpequd.p
+ bool res = v1 == v2;
+
+ // CHECK: @llvm.ppc.altivec.vcmpequd.p
+ res |= v3 == v4;
+
+ // CHECK: @llvm.ppc.altivec.vcmpequd.p
+ res |= v5 == v6;
+
+ // CHECK: @llvm.ppc.altivec.vcmpequd.p
+ res |= v7 == v8;
+
+ // CHECK: @llvm.ppc.vsx.xvcmpeqdp.p
+ res |= v9 == v10;
+ return res;
+}
+
diff --git a/test/CodeGen/ppc64-align-struct.c b/test/CodeGen/ppc64-align-struct.c
index 6a04d0cd84..5894a6aeb3 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-vector.c b/test/CodeGen/ppc64-vector.c
index f0211f0ec1..87deb0f585 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 04d2fb4766..f78f26a592 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/pr26099.c b/test/CodeGen/pr26099.c
new file mode 100644
index 0000000000..15b73b832e
--- /dev/null
+++ b/test/CodeGen/pr26099.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -ffreestanding %s -triple=i686-apple-darwin -target-feature +mmx -emit-llvm -o - -Wall -Werror
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +mmx -emit-llvm -o - -Wall -Werror
+// REQUIRES: asserts
+
+#include <x86intrin.h>
+
+int __attribute__ ((__vector_size__ (8))) b;
+
+void bar(int a)
+{
+ b = __builtin_ia32_vec_init_v2si (0, a);
+} \ No newline at end of file
diff --git a/test/CodeGen/pr27892.c b/test/CodeGen/pr27892.c
deleted file mode 100644
index 57722c4671..0000000000
--- a/test/CodeGen/pr27892.c
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fms-extensions %s -emit-llvm -o - | FileCheck %s
-
-long test1(long *p) {
- return _InterlockedIncrement(p);
-}
-// CHECK-DAG: define i64 @test1(
-// CHECK: %[[p_addr:.*]] = alloca i64*, align 8
-// CHECK: store i64* %p, i64** %[[p_addr]], align 8
-// CHECK: %[[p_load:.*]] = load i64*, i64** %[[p_addr]], align 8
-// CHECK: %[[atomic_add:.*]] = atomicrmw add i64* %[[p_load]], i64 1 seq_cst
-// CHECK: %[[res:.*]] = add i64 %[[atomic_add]], 1
-// CHECK: ret i64 %[[res]]
-
-long test2(long *p) {
- return _InterlockedDecrement(p);
-}
-// CHECK-DAG: define i64 @test2(
-// CHECK: %[[p_addr:.*]] = alloca i64*, align 8
-// CHECK: store i64* %p, i64** %[[p_addr]], align 8
-// CHECK: %[[p_load:.*]] = load i64*, i64** %[[p_addr]], align 8
-// CHECK: %[[atomic_sub:.*]] = atomicrmw sub i64* %[[p_load]], i64 1 seq_cst
-// CHECK: %[[res:.*]] = sub i64 %[[atomic_sub]], 1
-// CHECK: ret i64 %[[res]]
diff --git a/test/CodeGen/pr34021.c b/test/CodeGen/pr34021.c
new file mode 100644
index 0000000000..3c7a75a95a
--- /dev/null
+++ b/test/CodeGen/pr34021.c
@@ -0,0 +1,25 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -fms-extensions %s -triple=i686-unknown-unknown -emit-llvm -o - | FileCheck %s --check-prefix=X86
+// RUN: %clang_cc1 -fms-extensions %s -triple=x86_64-unknown-unknown -emit-llvm -o - | FileCheck %s --check-prefix=X64
+
+typedef int v4si __attribute__ ((vector_size (16)));
+v4si rep() {
+// X86-LABEL: define <4 x i32> @rep
+// X86: %[[ALLOCA0:.*]] = alloca <4 x i32>, align 16
+// X86: %[[ALLOCA1:.*]] = alloca <4 x i32>, align 16
+// X86: %[[BITCAST:.*]] = bitcast <4 x i32>* %[[ALLOCA0]] to i128*
+// X86: %[[ASM:.*]] = call i64 asm sideeffect inteldialect "", "=A,~{dirflag},~{fpsr},~{flags}"()
+// X86: %[[ZEXT:.*]] = zext i64 %[[ASM]] to i128
+// X86: store i128 %[[ZEXT]], i128* %[[BITCAST]], align 16
+// X86: %[[LOAD:.*]] = load <4 x i32>, <4 x i32>* %[[ALLOCA1]], align 16
+// X86: ret <4 x i32> %[[LOAD]]
+//
+// X64-LABEL: define <4 x i32> @rep
+// X64: %[[ALLOCA:.*]] = alloca <4 x i32>, align 16
+// X64: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"()
+// X64: %[[LOAD:.*]] = load <4 x i32>, <4 x i32>* %[[ALLOCA]], align 16
+// X64: ret <4 x i32> %[[LOAD]]
+ v4si res;
+ __asm {}
+ return res;
+}
diff --git a/test/CodeGen/pr3997.c b/test/CodeGen/pr3997.c
new file mode 100644
index 0000000000..814144cd14
--- /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/pragma-comment.c b/test/CodeGen/pragma-comment.c
index 71a7dfc0b0..fae9b8fb9e 100644
--- a/test/CodeGen/pragma-comment.c
+++ b/test/CodeGen/pragma-comment.c
@@ -4,6 +4,7 @@
// RUN: %clang_cc1 %s -triple thumbv7-linux-gnueabihf -fms-extensions -emit-llvm -o - | FileCheck -check-prefix LINUX %s
// RUN: %clang_cc1 %s -triple i686-pc-linux -fms-extensions -emit-llvm -o - | FileCheck -check-prefix LINUX %s
// RUN: %clang_cc1 %s -triple x86_64-scei-ps4 -fms-extensions -emit-llvm -o - | FileCheck -check-prefix PS4 %s
+// RUN: %clang_cc1 %s -triple aarch64-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s
#pragma comment(lib, "msvcrt.lib")
#pragma comment(lib, "kernel32")
@@ -14,9 +15,7 @@
#pragma comment(linker," /bar=" BAR)
#pragma comment(linker," /foo=\"foo bar\"")
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[space:[0-9]+]], ![[bar:[0-9]+]], ![[foo:[0-9]+]]}
+// CHECK: !llvm.linker.options = !{![[msvcrt:[0-9]+]], ![[kernel32:[0-9]+]], ![[USER32:[0-9]+]], ![[space:[0-9]+]], ![[bar:[0-9]+]], ![[foo:[0-9]+]]}
// CHECK: ![[msvcrt]] = !{!"/DEFAULTLIB:msvcrt.lib"}
// CHECK: ![[kernel32]] = !{!"/DEFAULTLIB:kernel32.lib"}
// CHECK: ![[USER32]] = !{!"/DEFAULTLIB:USER32.LIB"}
diff --git a/test/CodeGen/pragma-detect_mismatch.c b/test/CodeGen/pragma-detect_mismatch.c
index 08259fc6be..066183d312 100644
--- a/test/CodeGen/pragma-detect_mismatch.c
+++ b/test/CodeGen/pragma-detect_mismatch.c
@@ -6,8 +6,6 @@
#define BAR "2"
#pragma detect_mismatch("test2", BAR)
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = !{![[test:[0-9]+]], ![[test2:[0-9]+]]}
+// CHECK: !llvm.linker.options = !{![[test:[0-9]+]], ![[test2:[0-9]+]]}
// CHECK: ![[test]] = !{!"/FAILIFMISMATCH:\22test=1\22"}
// CHECK: ![[test2]] = !{!"/FAILIFMISMATCH:\22test2=2\22"}
diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c
index 36abca5de3..d1f7ab6c3e 100644
--- a/test/CodeGen/pragma-weak.c
+++ b/test/CodeGen/pragma-weak.c
@@ -189,4 +189,4 @@ void zzz(void){}
int correct_linkage;
// CHECK: attributes [[NI]] = { noinline nounwind{{.*}} }
-// CHECK: attributes [[RN]] = { noinline nounwind readnone{{.*}} }
+// CHECK: attributes [[RN]] = { noinline nounwind optnone readnone{{.*}} }
diff --git a/test/CodeGen/preserve-call-conv.c b/test/CodeGen/preserve-call-conv.c
index 6e91a8489b..b67e29f392 100644
--- a/test/CodeGen/preserve-call-conv.c
+++ b/test/CodeGen/preserve-call-conv.c
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm < %s | FileCheck %s
// RUN: %clang_cc1 -triple arm64-unknown-unknown -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -emit-llvm %s -o - | FileCheck %s
+
// Check that the preserve_most calling convention attribute at the source level
// is lowered to the corresponding calling convention attrribute at the LLVM IR
// level.
diff --git a/test/CodeGen/profile-sample-accurate.c b/test/CodeGen/profile-sample-accurate.c
new file mode 100644
index 0000000000..556cad753c
--- /dev/null
+++ b/test/CodeGen/profile-sample-accurate.c
@@ -0,0 +1,7 @@
+// Test to ensure -emit-llvm profile-sample-accurate is honored by clang.
+// RUN: %clang -S -emit-llvm %s -fprofile-sample-accurate -o - | FileCheck %s
+
+// CHECK: define{{.*}} void @foo()
+// CHECK: attributes{{.*}} "profile-sample-accurate"
+void foo() {
+}
diff --git a/test/CodeGen/sanitize-recover.c b/test/CodeGen/sanitize-recover.c
index 6cf7af84ba..6358d9d04a 100644
--- a/test/CodeGen/sanitize-recover.c
+++ b/test/CodeGen/sanitize-recover.c
@@ -7,30 +7,22 @@
void test() {
extern volatile unsigned x, y, z;
- // RECOVER: uadd.with.overflow.i32
- // RECOVER: ubsan_handle_add_overflow(
+ // RECOVER: uadd.with.overflow.i32{{.*}}, !nosanitize
+ // RECOVER: ubsan_handle_add_overflow({{.*}}, !nosanitize
// RECOVER-NOT: unreachable
- // ABORT: uadd.with.overflow.i32
- // ABORT: ubsan_handle_add_overflow_abort(
- // ABORT: unreachable
+ // ABORT: uadd.with.overflow.i32{{.*}}, !nosanitize
+ // ABORT: ubsan_handle_add_overflow_abort({{.*}}, !nosanitize
+ // ABORT: unreachable{{.*}}, !nosanitize
x = y + z;
}
void foo() {
union { int i; } u;
u.i=1;
- // PARTIAL: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
+ // 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: %[[CHECK1:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // PARTIAL: br i1 %[[CHECK0]], {{.*}} !nosanitize
- // PARTIAL: %[[CHECK01:.*]] = and i1 %[[CHECK1]], %[[CHECK0]]
-
- // PARTIAL: br i1 %[[CHECK01]], {{.*}} !nosanitize
- // PARTIAL: br i1 %[[CHECK1]], {{.*}} !nosanitize
-
- // 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/sanitizer-special-case-list.c b/test/CodeGen/sanitizer-special-case-list.c
new file mode 100644
index 0000000000..45cfecd7ef
--- /dev/null
+++ b/test/CodeGen/sanitizer-special-case-list.c
@@ -0,0 +1,26 @@
+// Verify that blacklist sections correctly select sanitizers to apply blacklist entries to.
+//
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized1.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized2.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized3.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized4.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+//
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.sanitized.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=SANITIZED
+
+unsigned i;
+
+// SANITIZED: @overflow
+// UNSANITIZED: @overflow
+unsigned overflow() {
+ // SANITIZED: call {{.*}}void @__ubsan
+ // UNSANITIZED-NOT: call {{.*}}void @__ubsan
+ return i * 37;
+}
+
+// SANITIZED: @cfi
+// UNSANITIZED: @cfi
+void cfi(void (*fp)()) {
+ // SANITIZED: llvm.type.test
+ // UNSANITIZED-NOT: llvm.type.test
+ fp();
+}
diff --git a/test/CodeGen/sparcv8-inline-asm.c b/test/CodeGen/sparcv8-inline-asm.c
new file mode 100644
index 0000000000..711a2a0afb
--- /dev/null
+++ b/test/CodeGen/sparcv8-inline-asm.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple sparc-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: define float @fabsf(float %a)
+// CHECK: %{{.*}} = call float asm sideeffect "fabss $1, $0;", "=e,f"(float %{{.*}}) #1
+float fabsf(float a) {
+ float res;
+ __asm __volatile__("fabss %1, %0;"
+ : /* reg out*/ "=e"(res)
+ : /* reg in */ "f"(a));
+ return res;
+}
diff --git a/test/CodeGen/split-debug-filename.c b/test/CodeGen/split-debug-filename.c
index 43daeada96..9ca7b0f328 100644
--- a/test/CodeGen/split-debug-filename.c
+++ b/test/CodeGen/split-debug-filename.c
@@ -1,7 +1,12 @@
// RUN: %clang_cc1 -debug-info-kind=limited -split-dwarf-file foo.dwo -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -debug-info-kind=limited -enable-split-dwarf -split-dwarf-file foo.dwo -S -emit-llvm -o - %s | FileCheck --check-prefix=VANILLA %s
int main (void) {
return 0;
}
// Testing to ensure that the dwo name gets output into the compile unit.
// CHECK: !DICompileUnit({{.*}}, splitDebugFilename: "foo.dwo"
+
+// Testing to ensure that the dwo name is not output into the compile unit if
+// it's for vanilla split-dwarf rather than split-dwarf for implicit modules.
+// VANILLA-NOT: splitDebugFilename
diff --git a/test/CodeGen/sse2-builtins.c b/test/CodeGen/sse2-builtins.c
index a140a6ce55..c2279cb881 100644
--- a/test/CodeGen/sse2-builtins.c
+++ b/test/CodeGen/sse2-builtins.c
@@ -97,13 +97,25 @@ __m128i test_mm_andnot_si128(__m128i A, __m128i B) {
__m128i test_mm_avg_epu8(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_avg_epu8
- // CHECK: call <16 x i8> @llvm.x86.sse2.pavg.b(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ // CHECK-NOT: call <16 x i8> @llvm.x86.sse2.pavg.b(<16 x i8> %{{.*}}, <16 x i8> %{{.*}})
+ // CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
+ // CHECK: zext <16 x i8> %{{.*}} to <16 x i16>
+ // CHECK: add <16 x i16> %{{.*}}, %{{.*}}
+ // CHECK: add <16 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK: lshr <16 x i16> %{{.*}}, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1>
+ // CHECK:trunc <16 x i16> %{{.*}} to <16 x i8>
return _mm_avg_epu8(A, B);
}
__m128i test_mm_avg_epu16(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_avg_epu16
- // CHECK: call <8 x i16> @llvm.x86.sse2.pavg.w(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ // CHECK-NOT: call <8 x i16> @llvm.x86.sse2.pavg.w(<8 x i16> %{{.*}}, <8 x i16> %{{.*}})
+ // CHECK: zext <8 x i16> %{{.*}} to <8 x i32>
+ // CHECK: zext <8 x i16> %{{.*}} to <8 x i32>
+ // CHECK: add <8 x i32> %{{.*}}, %{{.*}}
+ // CHECK: add <8 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: lshr <8 x i32> %{{.*}}, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
+ // CHECK: trunc <8 x i32> %{{.*}} to <8 x i16>
return _mm_avg_epu16(A, B);
}
@@ -951,6 +963,13 @@ __m128d test_mm_set_pd(double A, double B) {
return _mm_set_pd(A, B);
}
+__m128d test_mm_set_pd1(double A) {
+ // CHECK-LABEL: test_mm_set_pd1
+ // CHECK: insertelement <2 x double> undef, double %{{.*}}, i32 0
+ // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 1
+ return _mm_set_pd1(A);
+}
+
__m128d test_mm_set_sd(double A) {
// CHECK-LABEL: test_mm_set_sd
// CHECK: insertelement <2 x double> undef, double %{{.*}}, i32 0
diff --git a/test/CodeGen/sse41-builtins.c b/test/CodeGen/sse41-builtins.c
index adf9609b68..b48b73ec18 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/ssse3-builtins.c b/test/CodeGen/ssse3-builtins.c
index b2279e277c..4fd22aa79b 100644
--- a/test/CodeGen/ssse3-builtins.c
+++ b/test/CodeGen/ssse3-builtins.c
@@ -7,19 +7,25 @@
__m128i test_mm_abs_epi8(__m128i a) {
// CHECK-LABEL: test_mm_abs_epi8
- // CHECK: call <16 x i8> @llvm.x86.ssse3.pabs.b.128(<16 x i8> %{{.*}})
+ // CHECK: [[SUB:%.+]] = sub <16 x i8> zeroinitializer, [[A:%.+]]
+ // CHECK: [[CMP:%.+]] = icmp sgt <16 x i8> [[A]], zeroinitializer
+ // CHECK: %{{.*}} = select <16 x i1> [[CMP]], <16 x i8> [[A]], <16 x i8> [[SUB]]
return _mm_abs_epi8(a);
}
__m128i test_mm_abs_epi16(__m128i a) {
// CHECK-LABEL: test_mm_abs_epi16
- // CHECK: call <8 x i16> @llvm.x86.ssse3.pabs.w.128(<8 x i16> %{{.*}})
+ // CHECK: [[SUB:%.+]] = sub <8 x i16> zeroinitializer, [[A:%.+]]
+ // CHECK: [[CMP:%.+]] = icmp sgt <8 x i16> [[A]], zeroinitializer
+ // CHECK: %{{.*}} = select <8 x i1> [[CMP]], <8 x i16> [[A]], <8 x i16> [[SUB]]
return _mm_abs_epi16(a);
}
__m128i test_mm_abs_epi32(__m128i a) {
// CHECK-LABEL: test_mm_abs_epi32
- // CHECK: call <4 x i32> @llvm.x86.ssse3.pabs.d.128(<4 x i32> %{{.*}})
+ // CHECK: [[SUB:%.+]] = sub <4 x i32> zeroinitializer, [[A:%.+]]
+ // CHECK: [[CMP:%.+]] = icmp sgt <4 x i32> [[A]], zeroinitializer
+ // CHECK: %{{.*}} = select <4 x i1> [[CMP]], <4 x i32> [[A]], <4 x i32> [[SUB]]
return _mm_abs_epi32(a);
}
diff --git a/test/CodeGen/string-literal-short-wstring.c b/test/CodeGen/string-literal-short-wstring.c
index 01de6a4d80..fb1fe0cad0 100644
--- a/test/CodeGen/string-literal-short-wstring.c
+++ b/test/CodeGen/string-literal-short-wstring.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -x c++ -triple %itanium_abi_triple -emit-llvm -fshort-wchar %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=ITANIUM
-// RUN: %clang_cc1 -x c++ -triple %ms_abi_triple -emit-llvm -fshort-wchar %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=MSABI
+// RUN: %clang_cc1 -x c++ -triple %itanium_abi_triple -emit-llvm -fwchar-type=short -fno-signed-wchar %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=ITANIUM
+// RUN: %clang_cc1 -x c++ -triple %ms_abi_triple -emit-llvm -fwchar-type=short -fno-signed-wchar %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=MSABI
// Runs in c++ mode so that wchar_t is available.
// XFAIL: hexagon
diff --git a/test/CodeGen/string-literal-unicode-conversion.c b/test/CodeGen/string-literal-unicode-conversion.c
index 23205b80b0..71286b1fed 100644
--- a/test/CodeGen/string-literal-unicode-conversion.c
+++ b/test/CodeGen/string-literal-unicode-conversion.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
// RUN: %clang_cc1 -x c++ -std=c++0x -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-CPP0X %s
-// RUN: %clang_cc1 -x c++ -std=c++0x -fshort-wchar -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-SHORTWCHAR %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -fwchar-type=short -fno-signed-wchar -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-SHORTWCHAR %s
// This file contains a mix of ISO-8859-1 and UTF-8 encoded data.
// the literal assigned to 'aa' should be the ISO-8859-1 encoding for the code
diff --git a/test/CodeGen/systemz-abi-vector.c b/test/CodeGen/systemz-abi-vector.c
index 455e3bbcce..191c2321bb 100644
--- a/test/CodeGen/systemz-abi-vector.c
+++ b/test/CodeGen/systemz-abi-vector.c
@@ -6,6 +6,10 @@
// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch11 \
// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z14 \
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch12 \
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s
// Vector types
diff --git a/test/CodeGen/systemz-abi.c b/test/CodeGen/systemz-abi.c
index 17fdb9e322..de5dce54b5 100644
--- a/test/CodeGen/systemz-abi.c
+++ b/test/CodeGen/systemz-abi.c
@@ -6,6 +6,10 @@
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch11 \
// RUN: -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z14 \
+// RUN: -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch12 \
+// RUN: -emit-llvm -o - %s | FileCheck %s
// Scalar types
diff --git a/test/CodeGen/target-builtin-noerror.c b/test/CodeGen/target-builtin-noerror.c
index 2a7d69f108..63fc7c965d 100644
--- a/test/CodeGen/target-builtin-noerror.c
+++ b/test/CodeGen/target-builtin-noerror.c
@@ -72,4 +72,40 @@ void verifyfeaturestrings() {
(void)__builtin_cpu_supports("avx512pf");
(void)__builtin_cpu_supports("avx512vbmi");
(void)__builtin_cpu_supports("avx512ifma");
+ (void)__builtin_cpu_supports("avx5124vnniw");
+ (void)__builtin_cpu_supports("avx5124fmaps");
+ (void)__builtin_cpu_supports("avx512vpopcntdq");
+}
+
+void verifycpustrings() {
+ (void)__builtin_cpu_is("amd");
+ (void)__builtin_cpu_is("amdfam10h");
+ (void)__builtin_cpu_is("amdfam15h");
+ (void)__builtin_cpu_is("amdfam17h");
+ (void)__builtin_cpu_is("atom");
+ (void)__builtin_cpu_is("barcelona");
+ (void)__builtin_cpu_is("bdver1");
+ (void)__builtin_cpu_is("bdver2");
+ (void)__builtin_cpu_is("bdver3");
+ (void)__builtin_cpu_is("bdver4");
+ (void)__builtin_cpu_is("bonnell");
+ (void)__builtin_cpu_is("broadwell");
+ (void)__builtin_cpu_is("btver1");
+ (void)__builtin_cpu_is("btver2");
+ (void)__builtin_cpu_is("core2");
+ (void)__builtin_cpu_is("corei7");
+ (void)__builtin_cpu_is("haswell");
+ (void)__builtin_cpu_is("intel");
+ (void)__builtin_cpu_is("istanbul");
+ (void)__builtin_cpu_is("ivybridge");
+ (void)__builtin_cpu_is("knl");
+ (void)__builtin_cpu_is("nehalem");
+ (void)__builtin_cpu_is("sandybridge");
+ (void)__builtin_cpu_is("shanghai");
+ (void)__builtin_cpu_is("silvermont");
+ (void)__builtin_cpu_is("skylake");
+ (void)__builtin_cpu_is("skylake-avx512");
+ (void)__builtin_cpu_is("slm");
+ (void)__builtin_cpu_is("westmere");
+ (void)__builtin_cpu_is("znver1");
}
diff --git a/test/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 1e8ce6a2fd..3869afec78 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -116,11 +116,11 @@
// RUN: %clang_cc1 -triple nvptx-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=NVPTX
-// NVPTX: target datalayout = "e-p:32:32-i64:64-v16:16-v32:32-n16:32:64"
+// NVPTX: target datalayout = "e-p:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64"
// RUN: %clang_cc1 -triple nvptx64-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=NVPTX64
-// NVPTX64: target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
+// NVPTX64: target datalayout = "e-i64:64-i128:128-v16:16-v32:32-n16:32:64"
// RUN: %clang_cc1 -triple r600-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=R600
@@ -171,11 +171,15 @@
// RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR
// RUN: %clang_cc1 -triple s390x-unknown -target-cpu arch11 -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR
+// RUN: %clang_cc1 -triple s390x-unknown -target-cpu z14 -o - -emit-llvm %s | \
+// RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR
+// RUN: %clang_cc1 -triple s390x-unknown -target-cpu arch12 -o - -emit-llvm %s | \
+// RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR
// SYSTEMZ-VECTOR: target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
// RUN: %clang_cc1 -triple msp430-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=MSP430
-// MSP430: target datalayout = "e-m:e-p:16:16-i32:16:32-a:16-n8:16"
+// MSP430: target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"
// RUN: %clang_cc1 -triple tce-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=TCE
diff --git a/test/CodeGen/tbaa-array.cpp b/test/CodeGen/tbaa-array.cpp
new file mode 100644
index 0000000000..86ca5ccb40
--- /dev/null
+++ b/test/CodeGen/tbaa-array.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s \
+// RUN: -emit-llvm -o - | FileCheck %s
+//
+// Check that we generate correct TBAA information for accesses to array
+// elements.
+
+struct A { int i; };
+struct B { A a[1]; };
+
+int foo(B *b) {
+// CHECK-LABEL: _Z3fooP1B
+// CHECK: load i32, {{.*}}, !tbaa [[TAG_A_i:!.*]]
+ return b->a->i;
+}
+
+// CHECK-DAG: [[TAG_A_i]] = !{[[TYPE_A:!.*]], [[TYPE_int:!.*]], i64 0}
+// CHECK-DAG: [[TYPE_A]] = !{!"_ZTS1A", !{{.*}}, i64 0}
+// CHECK-DAG: [[TYPE_int]] = !{!"int", !{{.*}}, i64 0}
diff --git a/test/CodeGen/tbaa-cast.cpp b/test/CodeGen/tbaa-cast.cpp
new file mode 100644
index 0000000000..2b9e310866
--- /dev/null
+++ b/test/CodeGen/tbaa-cast.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s \
+// RUN: -emit-llvm -o - | FileCheck %s
+//
+// Check that we generate correct TBAA information for lvalues constructed
+// with use of casts.
+
+struct V {
+ unsigned n;
+};
+
+struct S {
+ char bytes[4];
+};
+
+void foo(S *p) {
+// CHECK-LABEL: _Z3fooP1S
+// CHECK: store i32 5, {{.*}}, !tbaa [[TAG_V_n:!.*]]
+ ((V*)p->bytes)->n = 5;
+}
+
+// CHECK-DAG: [[TAG_V_n]] = !{[[TYPE_V:!.*]], [[TYPE_int:!.*]], i64 0}
+// CHECK-DAG: [[TYPE_V]] = !{!"_ZTS1V", !{{.*}}, i64 0}
+// CHECK-DAG: [[TYPE_int]] = !{!"int", !{{.*}}, i64 0}
diff --git a/test/CodeGen/tbaa-for-vptr.cpp b/test/CodeGen/tbaa-for-vptr.cpp
index 7b8ae2099e..6136874cbf 100644
--- a/test/CodeGen/tbaa-for-vptr.cpp
+++ b/test/CodeGen/tbaa-for-vptr.cpp
@@ -23,12 +23,12 @@ void CallFoo(A *a, int (A::*fp)() const) {
}
// CHECK-LABEL: @_Z7CallFoo
-// CHECK: %{{.*}} = load {{.*}} !tbaa ![[NUM:[0-9]+]]
+// CHECK: %{{.*}} = load i32 (%struct.A*)**, {{.*}} !tbaa ![[NUM:[0-9]+]]
// CHECK: br i1
-// CHECK: load {{.*}}, !tbaa ![[NUM]]
+// CHECK: load i8*, {{.*}}, !tbaa ![[NUM]]
//
// CHECK-LABEL: @_ZN1AC2Ev
-// CHECK: store {{.*}} !tbaa ![[NUM]]
+// CHECK: store i32 (...)** {{.*}}, !tbaa ![[NUM]]
//
// CHECK: [[NUM]] = !{[[TYPE:!.*]], [[TYPE]], i64 0}
// CHECK: [[TYPE]] = !{!"vtable pointer", !{{.*}}
diff --git a/test/CodeGen/tbaa-reference.cpp b/test/CodeGen/tbaa-reference.cpp
new file mode 100644
index 0000000000..ecdbfbee7f
--- /dev/null
+++ b/test/CodeGen/tbaa-reference.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s
+//
+// Check that we generate correct TBAA information for reference accesses.
+
+struct S;
+
+struct B {
+ S &s;
+ B(S &s);
+ S &get();
+};
+
+B::B(S &s) : s(s) {
+// CHECK-LABEL: _ZN1BC2ER1S
+// Check initialization of the reference parameter.
+// CHECK: store %struct.S* {{.*}}, %struct.S** {{.*}}, !tbaa [[TAG_pointer:!.*]]
+
+// Check loading of the reference parameter.
+// CHECK: load %struct.S*, %struct.S** {{.*}}, !tbaa [[TAG_pointer]]
+
+// Check initialization of the reference member.
+// CHECK: store %struct.S* {{.*}}, %struct.S** {{.*}}, !tbaa [[TAG_pointer]]
+}
+
+S &B::get() {
+// CHECK-LABEL: _ZN1B3getEv
+// Check that we access the reference as a structure member.
+// CHECK: load %struct.S*, %struct.S** {{.*}}, !tbaa [[TAG_B_s:!.*]]
+ return s;
+}
+
+// CHECK-DAG: [[TAG_pointer]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0}
+// CHECK-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_pointer]], i64 0}
+//
+// CHECK-DAG: [[TYPE_B]] = !{!"_ZTS1B", [[TYPE_pointer]], i64 0}
+// CHECK-DAG: [[TYPE_pointer]] = !{!"any pointer", [[TYPE_char:!.*]], i64 0}
+// CHECK-DAG: [[TYPE_char]] = !{!"omnipotent char", {{!.*}}, i64 0}
diff --git a/test/CodeGen/tbaa-vec.cpp b/test/CodeGen/tbaa-vec.cpp
new file mode 100644
index 0000000000..5f61b934f0
--- /dev/null
+++ b/test/CodeGen/tbaa-vec.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s
+// Test TBAA metadata generated by front-end (vector types are always treated as mayalias).
+
+typedef float __m128 __attribute__ ((__vector_size__ (16)));
+
+struct A {
+ __m128 a, b;
+};
+
+void foo(A *a, __m128 v) {
+ // CHECK-LABEL: define void @_Z3fooP1ADv4_f
+ a->a = v;
+ // CHECK: store <4 x float> %v, <4 x float>* %{{.*}}, align 16, !tbaa [[TAG_char:!.*]]
+ // CHECK: store <4 x float> %{{.*}}, <4 x float>* %{{.*}}, align 16, !tbaa [[TAG_char]]
+}
+
+// CHECK: [[TYPE_char:!.*]] = !{!"omnipotent char", [[TAG_cxx_tbaa:!.*]],
+// CHECK: [[TAG_cxx_tbaa]] = !{!"Simple C++ TBAA"}
+// CHECK: [[TAG_char]] = !{[[TYPE_char]], [[TYPE_char]], i64 0}
+
diff --git a/test/CodeGen/tbm-builtins.c b/test/CodeGen/tbm-builtins.c
index 8e031408a4..136a1d41c4 100644
--- a/test/CodeGen/tbm-builtins.c
+++ b/test/CodeGen/tbm-builtins.c
@@ -1,8 +1,4 @@
-// RUN: %clang_cc1 -ffreestanding %s -O3 -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s
-// FIXME: The code generation checks for add/sub and/or are depending on the optimizer.
-// The REQUIRES keyword will be removed when the FIXME is complete.
-// REQUIRES: x86-registered-target
-
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s
#include <x86intrin.h>
@@ -28,134 +24,136 @@ unsigned long long test__bextri_u64_bigint(unsigned long long a) {
unsigned int test__blcfill_u32(unsigned int a) {
// CHECK-LABEL: test__blcfill_u32
- // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], 1
- // CHECK-NEXT: %{{.*}} = and i32 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = add i32 %{{.*}}, 1
+ // CHECK: %{{.*}} = and i32 %{{.*}}, [[TMP]]
return __blcfill_u32(a);
}
unsigned long long test__blcfill_u64(unsigned long long a) {
// CHECK-LABEL: test__blcfill_u64
- // CHECK: [[TMPT:%.*]] = add i64 [[SRC:%.*]], 1
- // CHECK-NEXT: %{{.*}} = and i64 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = add i64 %{{.*}}, 1
+ // CHECK: %{{.*}} = and i64 %{{.*}}, [[TMP]]
return __blcfill_u64(a);
}
unsigned int test__blci_u32(unsigned int a) {
// CHECK-LABEL: test__blci_u32
- // CHECK: [[TMP:%.*]] = sub i32 -2, [[SRC:%.*]]
- // CHECK-NEXT: %{{.*}} = or i32 [[TMP]], [[SRC]]
+ // CHECK: [[TMP1:%.*]] = add i32 %{{.*}}, 1
+ // CHECK: [[TMP2:%.*]] = xor i32 [[TMP1]], -1
+ // CHECK: %{{.*}} = or i32 %{{.*}}, [[TMP2]]
return __blci_u32(a);
}
unsigned long long test__blci_u64(unsigned long long a) {
// CHECK-LABEL: test__blci_u64
- // CHECK: [[TMP:%.*]] = sub i64 -2, [[SRC:%.*]]
- // CHECK-NEXT: %{{.*}} = or i64 [[TMP]], [[SRC]]
+ // CHECK: [[TMP1:%.*]] = add i64 %{{.*}}, 1
+ // CHECK: [[TMP2:%.*]] = xor i64 [[TMP1]], -1
+ // CHECK: %{{.*}} = or i64 %{{.*}}, [[TMP2]]
return __blci_u64(a);
}
unsigned int test__blcic_u32(unsigned int a) {
// CHECK-LABEL: test__blcic_u32
- // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC]], 1
- // CHECK-NEXT: {{.*}} = and i32 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i32 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = add i32 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = and i32 [[TMP1]], [[TMP2]]
return __blcic_u32(a);
}
unsigned long long test__blcic_u64(unsigned long long a) {
// CHECK-LABEL: test__blcic_u64
- // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC]], 1
- // CHECK-NEXT: {{.*}} = and i64 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i64 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = add i64 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = and i64 [[TMP1]], [[TMP2]]
return __blcic_u64(a);
}
unsigned int test__blcmsk_u32(unsigned int a) {
// CHECK-LABEL: test__blcmsk_u32
- // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], 1
- // CHECK-NEXT: {{.*}} = xor i32 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = add i32 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = xor i32 %{{.*}}, [[TMP]]
return __blcmsk_u32(a);
}
unsigned long long test__blcmsk_u64(unsigned long long a) {
// CHECK-LABEL: test__blcmsk_u64
- // CHECK: [[TMP:%.*]] = add i64 [[SRC:%.*]], 1
- // CHECK-NEXT: {{.*}} = xor i64 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = add i64 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = xor i64 %{{.*}}, [[TMP]]
return __blcmsk_u64(a);
}
unsigned int test__blcs_u32(unsigned int a) {
// CHECK-LABEL: test__blcs_u32
- // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], 1
- // CHECK-NEXT: {{.*}} = or i32 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = add i32 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i32 %{{.*}}, [[TMP]]
return __blcs_u32(a);
}
unsigned long long test__blcs_u64(unsigned long long a) {
// CHECK-LABEL: test__blcs_u64
- // CHECK: [[TMP:%.*]] = add i64 [[SRC:%.*]], 1
- // CHECK-NEXT: {{.*}} = or i64 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = add i64 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i64 %{{.*}}, [[TMP]]
return __blcs_u64(a);
}
unsigned int test__blsfill_u32(unsigned int a) {
// CHECK-LABEL: test__blsfill_u32
- // CHECK: [[TMP:%.*]] = add i32 [[SRC:%.*]], -1
- // CHECK-NEXT: {{.*}} = or i32 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = sub i32 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i32 %{{.*}}, [[TMP]]
return __blsfill_u32(a);
}
unsigned long long test__blsfill_u64(unsigned long long a) {
// CHECK-LABEL: test__blsfill_u64
- // CHECK: [[TMP:%.*]] = add i64 [[SRC:%.*]], -1
- // CHECK-NEXT: {{.*}} = or i64 [[TMP]], [[SRC]]
+ // CHECK: [[TMP:%.*]] = sub i64 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i64 %{{.*}}, [[TMP]]
return __blsfill_u64(a);
}
unsigned int test__blsic_u32(unsigned int a) {
// CHECK-LABEL: test__blsic_u32
- // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC:%.*]], -1
- // CHECK-NEXT: {{.*}} = or i32 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i32 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = sub i32 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i32 [[TMP1]], [[TMP2]]
return __blsic_u32(a);
}
unsigned long long test__blsic_u64(unsigned long long a) {
// CHECK-LABEL: test__blsic_u64
- // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC:%.*]], -1
- // CHECK-NEXT: {{.*}} = or i64 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i64 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = sub i64 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i64 [[TMP1]], [[TMP2]]
return __blsic_u64(a);
}
unsigned int test__t1mskc_u32(unsigned int a) {
// CHECK-LABEL: test__t1mskc_u32
- // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC:%.*]], 1
- // CHECK-NEXT: {{.*}} = or i32 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i32 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = add i32 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i32 [[TMP1]], [[TMP2]]
return __t1mskc_u32(a);
}
unsigned long long test__t1mskc_u64(unsigned long long a) {
// CHECK-LABEL: test__t1mskc_u64
- // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC:%.*]], 1
- // CHECK-NEXT: {{.*}} = or i64 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i64 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = add i64 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = or i64 [[TMP1]], [[TMP2]]
return __t1mskc_u64(a);
}
unsigned int test__tzmsk_u32(unsigned int a) {
// CHECK-LABEL: test__tzmsk_u32
- // CHECK: [[TMP1:%.*]] = xor i32 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i32 [[SRC:%.*]], -1
- // CHECK-NEXT: {{.*}} = and i32 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i32 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = sub i32 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = and i32 [[TMP1]], [[TMP2]]
return __tzmsk_u32(a);
}
unsigned long long test__tzmsk_u64(unsigned long long a) {
// CHECK-LABEL: test__tzmsk_u64
- // CHECK: [[TMP1:%.*]] = xor i64 [[SRC:%.*]], -1
- // CHECK-NEXT: [[TMP2:%.*]] = add i64 [[SRC:%.*]], -1
- // CHECK-NEXT: {{.*}} = and i64 [[TMP2]], [[TMP1]]
+ // CHECK: [[TMP1:%.*]] = xor i64 %{{.*}}, -1
+ // CHECK: [[TMP2:%.*]] = sub i64 %{{.*}}, 1
+ // CHECK-NEXT: {{.*}} = and i64 [[TMP1]], [[TMP2]]
return __tzmsk_u64(a);
}
diff --git a/test/CodeGen/temporary-lifetime-exceptions.cpp b/test/CodeGen/temporary-lifetime-exceptions.cpp
index f435560c97..1dc1c40dc6 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 f105a441a3..309b4e52da 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 0000000000..52c5715ba5
--- /dev/null
+++ b/test/CodeGen/thin_link_bitcode.c
@@ -0,0 +1,14 @@
+// REQUIRES: x86-registered-target
+//
+// 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
+// RUN: %clang_cc1 -o %t.newpm -flto=thin -fexperimental-new-pass-manager -fthin-link-bitcode=%t.newpm.nodebug -triple x86_64-unknown-linux-gnu -emit-llvm-bc -debug-info-kind=limited %s
+// RUN: llvm-bcanalyzer -dump %t.newpm | FileCheck %s
+// RUN: llvm-bcanalyzer -dump %t.newpm.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-backend-option.ll b/test/CodeGen/thinlto-backend-option.ll
new file mode 100644
index 0000000000..4fcdd079df
--- /dev/null
+++ b/test/CodeGen/thinlto-backend-option.ll
@@ -0,0 +1,15 @@
+; Test to ensure -backend-options work when invoking the ThinLTO backend path.
+
+; This test uses a non-existent backend option to test that backend options are
+; being parsed. While it's more important that the existing options are parsed
+; than that this error is produced, this provides a reliable way to test this
+; scenario independent of any particular backend options that may exist now or
+; in the future.
+
+; RUN: %clang -flto=thin -c -o %t.o %s
+; RUN: llvm-lto -thinlto -o %t %t.o
+; RUN: not %clang_cc1 -x ir %t.o -fthinlto-index=%t.thinlto.bc -backend-option -nonexistent -emit-obj -o /dev/null 2>&1 | FileCheck %s -check-prefix=UNKNOWN
+; UNKNOWN: clang: Unknown command line argument '-nonexistent'
+
+; RUN: not %clang_cc1 -flto=thinfoo 2>&1 | FileCheck %s -check-prefix=INVALID
+; INVALID: error: invalid value 'thinfoo' in '-flto=thinfoo'
diff --git a/test/CodeGen/thinlto-emit-llvm.c b/test/CodeGen/thinlto-emit-llvm.c
new file mode 100644
index 0000000000..d6ef665024
--- /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
index 21d28cf44d..385d98c74d 100644
--- a/test/CodeGen/thinlto-multi-module.ll
+++ b/test/CodeGen/thinlto-multi-module.ll
@@ -3,8 +3,8 @@
; 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: opt -module-summary -o %t2.o %S/Inputs/thinlto-multi-module.ll
+; RUN: llvm-cat -b -o %t1cat.o %t2.o %t1.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
diff --git a/test/CodeGen/thinlto_backend.ll b/test/CodeGen/thinlto_backend.ll
index ac0b3b76ef..86f30c0374 100644
--- a/test/CodeGen/thinlto_backend.ll
+++ b/test/CodeGen/thinlto_backend.ll
@@ -12,10 +12,10 @@
; RUN: %clang -O2 -o %t4.o -x ir %t1.o -c -fthinlto-index=bad.thinlto.bc 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR1
; CHECK-ERROR1: Error loading index file 'bad.thinlto.bc'
-; Ensure we ignore empty index file under -ignore-empty-index-file, and run
-; non-ThinLTO compilation which would not import f2
+; Ensure we ignore empty index file, and run non-ThinLTO compilation which
+; would not import f2
; RUN: touch %t4.thinlto.bc
-; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t4.o -x ir %t1.o -c -fthinlto-index=%t4.thinlto.bc -mllvm -ignore-empty-index-file
+; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t4.o -x ir %t1.o -c -fthinlto-index=%t4.thinlto.bc
; RUN: llvm-nm %t4.o | FileCheck --check-prefix=CHECK-OBJ-IGNORE-EMPTY %s
; CHECK-OBJ-IGNORE-EMPTY: T f1
; CHECK-OBJ-IGNORE-EMPTY: U f2
@@ -35,8 +35,12 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
declare void @f2()
+declare i8* @f3()
define void @f1() {
call void @f2()
+ ; Make sure that the backend can handle undefined references.
+ ; Do an indirect call so that the undefined ref shows up in the combined index.
+ call void bitcast (i8*()* @f3 to void()*)()
ret void
}
diff --git a/test/CodeGen/ubsan-builtin-checks.c b/test/CodeGen/ubsan-builtin-checks.c
new file mode 100644
index 0000000000..9733b0e047
--- /dev/null
+++ b/test/CodeGen/ubsan-builtin-checks.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -w -emit-llvm -o - %s -fsanitize=builtin | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -w -emit-llvm -o - %s -fsanitize=builtin | FileCheck %s --check-prefix=NOT-UB
+
+// NOT-UB-NOT: __ubsan_handle_invalid_builtin
+
+// CHECK: define void @check_ctz
+void check_ctz(int n) {
+ // CHECK: [[NOT_ZERO:%.*]] = icmp ne i32 [[N:%.*]], 0, !nosanitize
+ // CHECK-NEXT: br i1 [[NOT_ZERO]]
+ //
+ // Handler block:
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ // CHECK-NEXT: unreachable
+ //
+ // Continuation block:
+ // CHECK: call i32 @llvm.cttz.i32(i32 [[N]], i1 true)
+ __builtin_ctz(n);
+
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ __builtin_ctzl(n);
+
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ __builtin_ctzll(n);
+}
+
+// CHECK: define void @check_clz
+void check_clz(int n) {
+ // CHECK: [[NOT_ZERO:%.*]] = icmp ne i32 [[N:%.*]], 0, !nosanitize
+ // CHECK-NEXT: br i1 [[NOT_ZERO]]
+ //
+ // Handler block:
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ // CHECK-NEXT: unreachable
+ //
+ // Continuation block:
+ // CHECK: call i32 @llvm.ctlz.i32(i32 [[N]], i1 true)
+ __builtin_clz(n);
+
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ __builtin_clzl(n);
+
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ __builtin_clzll(n);
+}
diff --git a/test/CodeGen/ubsan-pointer-overflow.m b/test/CodeGen/ubsan-pointer-overflow.m
new file mode 100644
index 0000000000..977e245838
--- /dev/null
+++ b/test/CodeGen/ubsan-pointer-overflow.m
@@ -0,0 +1,220 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -w -emit-llvm -o - %s -fsanitize=pointer-overflow | FileCheck %s
+
+// CHECK-LABEL: define void @unary_arith
+void unary_arith(char *p) {
+ // CHECK: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 1, !nosanitize
+ // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
+ // CHECK-NEXT: br i1 [[POSVALID]]{{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
+ ++p;
+
+ // CHECK: ptrtoint i8* {{.*}} to i64, !nosanitize
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 {{.*}}, -1, !nosanitize
+ // CHECK: [[NEGVALID:%.*]] = icmp ule i64 [[COMPGEP]], {{.*}}, !nosanitize
+ // CHECK-NOT: select
+ // CHECK: br i1 [[NEGVALID]]{{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ --p;
+
+ // CHECK: icmp uge i64
+ // CHECK-NOT: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ p++;
+
+ // CHECK: icmp ule i64
+ // CHECK-NOT: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ p--;
+}
+
+// CHECK-LABEL: define void @binary_arith
+void binary_arith(char *p, int i) {
+ // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize
+ // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize
+ // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize
+ // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize
+ // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize
+ // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
+ // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize
+ // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize
+ // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize
+ // CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize
+ // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
+ p + i;
+
+ // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}}
+ // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]]
+ // CHECK: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ p - i;
+}
+
+// CHECK-LABEL: define void @binary_arith_unsigned
+void binary_arith_unsigned(char *p, unsigned i) {
+ // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize
+ // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize
+ // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize
+ // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize
+ // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize
+ // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
+ // CHECK: [[VALID:%.*]] = and i1 [[POSVALID]], [[OFFSETVALID]], !nosanitize
+ // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
+ p + i;
+
+ // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}}
+ // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]]
+ // CHECK: icmp ule i64
+ // CHECK-NOT: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ p - i;
+}
+
+// CHECK-LABEL: define void @fixed_len_array
+void fixed_len_array(int k) {
+ // CHECK: getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* [[ARR:%.*]], i64 0, i64 [[IDXPROM:%.*]]
+ // CHECK-NEXT: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 40, i64 [[IDXPROM]]), !nosanitize
+ // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize
+ // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize
+ // CHECK-NEXT: [[BASE:%.*]] = ptrtoint [10 x [10 x i32]]* [[ARR]] to i64, !nosanitize
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize
+ // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize
+ // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize
+ // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize
+ // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize
+ // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize
+ // CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize
+ // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
+
+ // CHECK: getelementptr inbounds [10 x i32], [10 x i32]* {{.*}}, i64 0, i64 [[IDXPROM1:%.*]]
+ // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM1]]), !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+
+ int arr[10][10];
+ arr[k][k];
+}
+
+// CHECK-LABEL: define void @variable_len_array
+void variable_len_array(int n, int k) {
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]]
+ // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]), !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM1:%.*]]
+ // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM1]]), !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+
+ int arr[n][n];
+ arr[k][k];
+}
+
+// CHECK-LABEL: define void @pointer_array
+void pointer_array(int **arr, int k) {
+ // CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+
+ // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 {{.*}}), !nosanitize
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+
+ arr[k][k];
+}
+
+// CHECK-LABEL: define void @pointer_array_unsigned_indices
+void pointer_array_unsigned_indices(int **arr, unsigned k) {
+ // CHECK: icmp uge
+ // CHECK-NOT: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ // CHECK: icmp uge
+ // CHECK-NOT: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ arr[k][k];
+}
+
+// CHECK-LABEL: define void @pointer_array_mixed_indices
+void pointer_array_mixed_indices(int **arr, int i, unsigned j) {
+ // CHECK: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ // CHECK-NOT: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ arr[i][j];
+}
+
+struct S1 {
+ int pad1;
+ union {
+ char leaf;
+ struct S1 *link;
+ } u;
+ struct S1 *arr;
+};
+
+// TODO: Currently, structure GEPs are not checked, so there are several
+// potentially unsafe GEPs here which we don't instrument.
+//
+// CHECK-LABEL: define void @struct_index
+void struct_index(struct S1 *p) {
+ // CHECK: getelementptr inbounds %struct.S1, %struct.S1* [[P:%.*]], i64 10
+ // CHECK-NEXT: [[BASE:%.*]] = ptrtoint %struct.S1* [[P]] to i64, !nosanitize
+ // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 240, !nosanitize
+ // CHECK: select
+ // CHECK: @__ubsan_handle_pointer_overflow{{.*}} i64 [[BASE]], i64 [[COMPGEP]]) {{.*}}, !nosanitize
+
+ // CHECK-NOT: @__ubsan_handle_pointer_overflow
+
+ p->arr[10].u.link->u.leaf;
+}
+
+typedef void (*funcptr_t)(void);
+
+// CHECK-LABEL: define void @function_pointer_arith
+void function_pointer_arith(funcptr_t *p, int k) {
+ // CHECK: add i64 {{.*}}, 8, !nosanitize
+ // CHECK-NOT: select
+ // CHECK: @__ubsan_handle_pointer_overflow{{.*}}
+ ++p;
+
+ // CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize
+ // CHECK: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ p + k;
+}
+
+// CHECK-LABEL: define void @variable_len_array_arith
+void variable_len_array_arith(int n, int k) {
+ int vla[n];
+ int (*p)[n] = &vla;
+
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[INC:%.*]]
+ // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[INC]]), !nosanitize
+ // CHECK-NOT: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ ++p;
+
+ // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]]
+ // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]), !nosanitize
+ // CHECK: select
+ // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
+ p + k;
+}
+
+// CHECK-LABEL: define void @objc_id
+void objc_id(id *p) {
+ // CHECK: add i64 {{.*}}, 8, !nosanitize
+ // CHECK-NOT: select
+ // CHECK: @__ubsan_handle_pointer_overflow{{.*}}
+ p++;
+}
+
+// CHECK-LABEL: define void @dont_emit_checks_for_no_op_GEPs
+// CHECK-NOT: __ubsan_handle_pointer_overflow
+void dont_emit_checks_for_no_op_GEPs(char *p) {
+ &p[0];
+
+ int arr[10][10];
+ &arr[0][0];
+}
diff --git a/test/CodeGen/ubsan-volatile.c b/test/CodeGen/ubsan-volatile.c
new file mode 100644
index 0000000000..ce54aada81
--- /dev/null
+++ b/test/CodeGen/ubsan-volatile.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=null,alignment,object-size,vptr -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: @volatile_null_deref
+void volatile_null_deref(volatile int *p) {
+ // CHECK-NOT: call{{.*}}ubsan
+ *p;
+}
diff --git a/test/CodeGen/union-align.c b/test/CodeGen/union-align.c
index 89a9456e60..2055d93d8e 100644
--- a/test/CodeGen/union-align.c
+++ b/test/CodeGen/union-align.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep load | grep "4 x float" | not grep "align 4"
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep load | grep "4 x float" | grep "align 16"
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | grep load | grep "4 x float" | not grep "align 4"
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | grep load | grep "4 x float" | grep "align 16"
// PR3432
// rdar://6536377
diff --git a/test/CodeGen/union-tbaa1.c b/test/CodeGen/union-tbaa1.c
new file mode 100644
index 0000000000..07f5fcfeb4
--- /dev/null
+++ b/test/CodeGen/union-tbaa1.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 %s -triple hexagon-unknown-elf -O2 -emit-llvm -o - | FileCheck %s
+
+typedef union __attribute__((aligned(4))) {
+ unsigned short uh[2];
+ unsigned uw;
+} vect32;
+
+void bar(vect32 p[][2]);
+
+// CHECK-LABEL: define void @fred
+void fred(unsigned Num, int Vec[2], int *Index, int Arr[4][2]) {
+ vect32 Tmp[4][2];
+// Generate tbaa for the load of Index:
+// CHECK: load i32, i32* %Index{{.*}}tbaa
+// But no tbaa for the two stores:
+// CHECK: %uw[[UW1:[0-9]*]] = getelementptr
+// CHECK: store{{.*}}%uw[[UW1]]
+// CHECK: tbaa ![[OCPATH:[0-9]+]]
+// There will be a load after the store, and it will use tbaa. Make sure
+// the check-not above doesn't find it:
+// CHECK: load
+ Tmp[*Index][0].uw = Arr[*Index][0] * Num;
+// CHECK: %uw[[UW2:[0-9]*]] = getelementptr
+// CHECK: store{{.*}}%uw[[UW2]]
+// CHECK: tbaa ![[OCPATH]]
+ Tmp[*Index][1].uw = Arr[*Index][1] * Num;
+// Same here, don't generate tbaa for the loads:
+// CHECK: %uh[[UH1:[0-9]*]] = bitcast %union.vect32
+// CHECK: %arrayidx[[AX1:[0-9]*]] = getelementptr{{.*}}%uh[[UH1]]
+// CHECK: load i16, i16* %arrayidx[[AX1]]
+// CHECK: tbaa ![[OCPATH]]
+// CHECK: store
+ Vec[0] = Tmp[*Index][0].uh[1];
+// CHECK: %uh[[UH2:[0-9]*]] = bitcast %union.vect32
+// CHECK: %arrayidx[[AX2:[0-9]*]] = getelementptr{{.*}}%uh[[UH2]]
+// CHECK: load i16, i16* %arrayidx[[AX2]]
+// CHECK: tbaa ![[OCPATH]]
+// CHECK: store
+ Vec[1] = Tmp[*Index][1].uh[1];
+ bar(Tmp);
+}
+
+// CHECK-DAG: ![[CHAR:[0-9]+]] = !{!"omnipotent char"
+// CHECK-DAG: ![[OCPATH]] = !{![[CHAR]], ![[CHAR]], i64 0}
diff --git a/test/CodeGen/unsigned-overflow-minimal.c b/test/CodeGen/unsigned-overflow-minimal.c
new file mode 100644
index 0000000000..d4b89664f8
--- /dev/null
+++ b/test/CodeGen/unsigned-overflow-minimal.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=unsigned-integer-overflow -fsanitize-minimal-runtime %s -emit-llvm -o - | FileCheck %s
+
+unsigned long li, lj, lk;
+
+// CHECK-LABEL: define void @testlongadd()
+void testlongadd() {
+ // CHECK: call void @__ubsan_handle_add_overflow_minimal_abort()
+ li = lj + lk;
+}
+
+// CHECK-LABEL: define void @testlongsub()
+void testlongsub() {
+ // CHECK: call void @__ubsan_handle_sub_overflow_minimal_abort()
+ li = lj - lk;
+}
+
+// CHECK-LABEL: define void @testlongmul()
+void testlongmul() {
+ // CHECK: call void @__ubsan_handle_mul_overflow_minimal_abort()
+ li = lj * lk;
+}
diff --git a/test/CodeGen/unwind-attr.c b/test/CodeGen/unwind-attr.c
index 2065653e0d..9979235003 100644
--- a/test/CodeGen/unwind-attr.c
+++ b/test/CodeGen/unwind-attr.c
@@ -23,7 +23,7 @@ __attribute__((weak)) int test2(void) {
return 0;
}
-// CHECK: attributes [[TF]] = { noinline "{{.*}} }
+// CHECK: attributes [[TF]] = { noinline optnone "{{.*}} }
// CHECK: attributes [[NUW]] = { noinline nounwind{{.*}} }
// CHECK-NOEXC: attributes [[NUW]] = { noinline nounwind{{.*}} }
diff --git a/test/CodeGen/vectorcall.c b/test/CodeGen/vectorcall.c
index 167f72ca2c..fa244fb908 100644
--- a/test/CodeGen/vectorcall.c
+++ b/test/CodeGen/vectorcall.c
@@ -100,8 +100,19 @@ void __vectorcall odd_size_hva(struct OddSizeHVA a) {}
// X32: define x86_vectorcallcc void @"\01odd_size_hva@@32"(%struct.OddSizeHVA inreg %a.coerce)
// X64: define x86_vectorcallcc void @"\01odd_size_hva@@32"(%struct.OddSizeHVA inreg %a.coerce)
-// The Vectorcall ABI only allows passing the first 6 items in registers, so this shouldn't
+// The Vectorcall ABI only allows passing the first 6 items in registers in x64, so this shouldn't
// consider 'p7' as a register. Instead p5 gets put into the register on the second pass.
-struct HFA2 __vectorcall AddParticles(struct HFA2 p1, float p2, struct HFA4 p3, int p4, struct HFA2 p5, float p6, float p7){ return p1;}
-// X32: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@80"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* inreg %p3, i32 inreg %p4, %struct.HFA2 inreg %p5.coerce, float %p6, float %p7)
-// X64: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@96"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* %p3, i32 %p4, %struct.HFA2 inreg %p5.coerce, float %p6, float %p7)
+// x86 should pass p2, p6 and p7 in registers, then p1 in the second pass.
+struct HFA2 __vectorcall AddParticles(struct HFA2 p1, float p2, struct HFA4 p3, int p4, struct HFA2 p5, float p6, float p7, int p8){ return p1;}
+// X32: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@84"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* inreg %p3, i32 inreg %p4, %struct.HFA2* %p5, float %p6, float %p7, i32 %p8)
+// X64: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@104"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* %p3, i32 %p4, %struct.HFA2 inreg %p5.coerce, float %p6, float %p7, i32 %p8)
+
+// Vectorcall in both architectures allows passing of an HVA as long as there is room,
+// even if it is not one of the first 6 arguments. First pass puts p4 into a
+// register on both. p9 ends up in a register in x86 only. Second pass puts p1
+// in a register, does NOT put p7 in a register (since theres no room), then puts
+// p8 in a register.
+void __vectorcall HVAAnywhere(struct HFA2 p1, int p2, int p3, float p4, int p5, int p6, struct HFA4 p7, struct HFA2 p8, float p9){}
+// X32: define x86_vectorcallcc void @"\01HVAAnywhere@@88"(%struct.HFA2 inreg %p1.coerce, i32 inreg %p2, i32 inreg %p3, float %p4, i32 %p5, i32 %p6, %struct.HFA4* %p7, %struct.HFA2 inreg %p8.coerce, float %p9)
+// X64: define x86_vectorcallcc void @"\01HVAAnywhere@@112"(%struct.HFA2 inreg %p1.coerce, i32 %p2, i32 %p3, float %p4, i32 %p5, i32 %p6, %struct.HFA4* %p7, %struct.HFA2 inreg %p8.coerce, float %p9)
+
diff --git a/test/CodeGen/verify-debuginfo.ll b/test/CodeGen/verify-debuginfo.ll
new file mode 100644
index 0000000000..0a1858544f
--- /dev/null
+++ b/test/CodeGen/verify-debuginfo.ll
@@ -0,0 +1,17 @@
+; REQUIRES: x86-registered-target
+; RUN: %clang_cc1 -triple i386-apple-darwin -disable-llvm-optzns -S %s -o - 2>&1 \
+; RUN: | FileCheck %s
+; CHECK: invalid global variable ref
+; CHECK: warning: ignoring invalid debug info in {{.*}}.ll
+
+@global = common global i32 0, align 4, !dbg !2
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!5, !6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "adrian", emissionKind: FullDebug, globals: !{!3})
+!1 = !DIFile(filename: "broken.c", directory: "/")
+!2 = !DIGlobalVariableExpression(var: !3, expr: !DIExpression())
+!3 = !DIGlobalVariable(name: "g", scope: !0, file: !1, line: 1, type: !1, isLocal: false, isDefinition: true)
+!5 = !{i32 2, !"Dwarf Version", i32 4}
+!6 = !{i32 1, !"Debug Info Version", i32 3}
diff --git a/test/CodeGen/wchar-size.c b/test/CodeGen/wchar-size.c
new file mode 100644
index 0000000000..28cd5d14d7
--- /dev/null
+++ b/test/CodeGen/wchar-size.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s -check-prefix=LONG-WCHAR
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -emit-llvm -o - %s | FileCheck %s -check-prefix=SHORT-WCHAR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - -fwchar-type=short -fno-signed-wchar %s | FileCheck %s -check-prefix=SHORT-WCHAR
+// Note: -fno-short-wchar implies the target default is used; so there is no
+// need to test this separately here.
+
+// LONG-WCHAR: !{{[0-9]+}} = !{i32 {{[0-9]+}}, !"wchar_size", i32 4}
+// SHORT-WCHAR: !{{[0-9]+}} = !{i32 {{[0-9]+}}, !"wchar_size", i32 2}
diff --git a/test/CodeGen/x86-GCC-inline-asm-Y-constraints.c b/test/CodeGen/x86-GCC-inline-asm-Y-constraints.c
new file mode 100644
index 0000000000..0e1e69cd24
--- /dev/null
+++ b/test/CodeGen/x86-GCC-inline-asm-Y-constraints.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -ffreestanding -triple=x86_64-apple-darwin -target-cpu skx %s -emit-llvm -o - | FileCheck %s
+#include <xmmintrin.h>
+// This test is complimented by the .ll test under llvm/test/MC/X86/.
+// At this level we can only check if the constarints are passed correctly
+// from inline asm to llvm IR.
+
+// CHECK-LABEL: @f_Ym
+void f_Ym(__m64 m)
+ {
+ // CHECK: movq $0, %mm1
+ // CHECK-SAME: "=^Ym,~{dirflag},~{fpsr},~{flags}"
+ __asm__ volatile ("movq %0, %%mm1\n\t"
+ :"=Ym" (m));
+}
+
+// CHECK-LABEL: f_Yi
+void f_Yi(__m128 x, __m128 y, __m128 z)
+ {
+ // CHECK: vpaddq
+ // CHECK-SAME: "=^Yi,^Yi,^Yi,~{dirflag},~{fpsr},~{flags}"
+ __asm__ volatile ("vpaddq %0, %1, %2\n\t"
+ :"=Yi" (x)
+ :"Yi" (y),"Yi"(z));
+}
+
+// CHECK-LABEL: f_Yt
+void f_Yt(__m128 x, __m128 y, __m128 z)
+ {
+ // CHECK: vpaddq
+ // CHECK-SAME: "=^Yt,^Yt,^Yt,~{dirflag},~{fpsr},~{flags}"
+ __asm__ volatile ("vpaddq %0, %1, %2\n\t"
+ :"=Yt" (x)
+ :"Yt" (y),"Yt"(z));
+}
+
+// CHECK-LABEL: f_Y2
+void f_Y2(__m128 x, __m128 y, __m128 z)
+ {
+ // CHECK: vpaddq
+ // CHECK-SAME: "=^Y2,^Y2,^Y2,~{dirflag},~{fpsr},~{flags}"
+ __asm__ volatile ("vpaddq %0, %1, %2\n\t"
+ :"=Y2" (x)
+ :"Y2" (y),"Y2"(z));
+}
+
+// CHECK-LABEL: f_Yz
+void f_Yz(__m128 x, __m128 y, __m128 z)
+ {
+ // CHECK: vpaddq
+ // CHECK-SAME: vpaddq
+ // CHECK-SAME: "=^Yi,=^Yz,^Yi,0,~{dirflag},~{fpsr},~{flags}"
+ __asm__ volatile ("vpaddq %0,%2,%1\n\t"
+ "vpaddq %1,%0,%2\n\t"
+ :"+Yi"(z),"=Yz" (x)
+ :"Yi" (y) );
+}
+
+// CHECK-LABEL: f_Y0
+void f_Y0(__m128 x, __m128 y, __m128 z)
+ {
+ // CHECK: vpaddq
+ // CHECK-SAME: "=^Yi,=^Y0,^Yi,0,~{dirflag},~{fpsr},~{flags}"
+ __asm__ volatile ("vpaddq %0,%2,%1\n\t"
+ "vpaddq %1,%0,%2\n\t"
+ :"+Yi"(z),"=Y0" (x)
+ :"Yi" (y) );
+}
+
diff --git a/test/CodeGen/x86-nontemporal.c b/test/CodeGen/x86-nontemporal.c
new file mode 100644
index 0000000000..5e9e42c9f2
--- /dev/null
+++ b/test/CodeGen/x86-nontemporal.c
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -target-feature +avx -target-feature +avx2 -target-feature +avx512f -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -target-feature +avx -target-feature +avx2 -target-feature +avx512f -fno-signed-char -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefix=CHECK
+
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -target-feature +avx -target-feature +avx2 -target-feature +avx512f -emit-llvm -o - -Wall -Werror -fmax-type-align=16 | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +sse4.1 -target-feature +avx -target-feature +avx2 -target-feature +avx512f -fno-signed-char -emit-llvm -o - -Wall -Werror -fmax-type-align=16 | FileCheck %s --check-prefix=CHECK
+
+#include <x86intrin.h>
+
+// (PR33830) Tests ensure the correct alignment of non-temporal load/stores on darwin targets where fmax-type-align is set to 16.
+
+//
+// 128-bit vectors
+//
+
+void test_mm_stream_pd(double* A, __m128d B) {
+ // CHECK-LABEL: test_mm_stream_pd
+ // CHECK: store <2 x double> %{{.*}}, <2 x double>* %{{.*}}, align 16, !nontemporal
+ _mm_stream_pd(A, B);
+}
+
+void test_mm_stream_ps(float* A, __m128 B) {
+ // CHECK16-LABEL: test_mm_stream_ps
+ // CHECK16: store <4 x float> %{{.*}}, <4 x float>* %{{.*}}, align 16, !nontemporal
+ _mm_stream_ps(A, B);
+}
+
+void test_mm_stream_si128(__m128i* A, __m128i B) {
+ // CHECK-LABEL: test_mm_stream_si128
+ // CHECK: store <2 x i64> %{{.*}}, <2 x i64>* %{{.*}}, align 16, !nontemporal
+ _mm_stream_si128(A, B);
+}
+
+__m128i test_mm_stream_load_si128(__m128i const *A) {
+ // CHECK-LABEL: test_mm_stream_load_si128
+ // CHECK: load <2 x i64>, <2 x i64>* %{{.*}}, align 16, !nontemporal
+ return _mm_stream_load_si128(A);
+}
+
+//
+// 256-bit vectors
+//
+
+void test_mm256_stream_pd(double* A, __m256d B) {
+ // CHECK-LABEL: test_mm256_stream_pd
+ // CHECK: store <4 x double> %{{.*}}, <4 x double>* %{{.*}}, align 32, !nontemporal
+ _mm256_stream_pd(A, B);
+}
+
+void test_mm256_stream_ps(float* A, __m256 B) {
+ // CHECK-LABEL: test_mm256_stream_ps
+ // CHECK: store <8 x float> %{{.*}}, <8 x float>* %{{.*}}, align 32, !nontemporal
+ _mm256_stream_ps(A, B);
+}
+
+void test_mm256_stream_si256(__m256i* A, __m256i B) {
+ // CHECK-LABEL: test_mm256_stream_si256
+ // CHECK: store <4 x i64> %{{.*}}, <4 x i64>* %{{.*}}, align 32, !nontemporal
+ _mm256_stream_si256(A, B);
+}
+
+__m256i test_mm256_stream_load_si256(__m256i const *A) {
+ // CHECK-LABEL: test_mm256_stream_load_si256
+ // CHECK: load <4 x i64>, <4 x i64>* %{{.*}}, align 32, !nontemporal
+ return _mm256_stream_load_si256(A);
+}
+
+//
+// 512-bit vectors
+//
+
+void test_mm512_stream_pd(double* A, __m512d B) {
+ // CHECK-LABEL: test_mm512_stream_pd
+ // CHECK: store <8 x double> %{{.*}}, <8 x double>* %{{.*}}, align 64, !nontemporal
+ _mm512_stream_pd(A, B);
+}
+
+void test_mm512_stream_ps(float* A, __m512 B) {
+ // CHECK-LABEL: test_mm512_stream_ps
+ // CHECK: store <16 x float> %{{.*}}, <16 x float>* %{{.*}}, align 64, !nontemporal
+ _mm512_stream_ps(A, B);
+}
+
+void test_mm512_stream_si512(__m512i* A, __m512i B) {
+ // CHECK-LABEL: test_mm512_stream_si512
+ // CHECK: store <8 x i64> %{{.*}}, <8 x i64>* %{{.*}}, align 64, !nontemporal
+ _mm512_stream_si512(A, B);
+}
+
+__m512i test_mm512_stream_load_si512(void *A) {
+ // CHECK-LABEL: test_mm512_stream_load_si512
+ // CHECK: load <8 x i64>, <8 x i64>* %{{.*}}, align 64, !nontemporal
+ return _mm512_stream_load_si512(A);
+}
diff --git a/test/CodeGen/x86_32-xsave.c b/test/CodeGen/x86_32-xsave.c
index b475d63fb3..f5d84e2d92 100644
--- a/test/CodeGen/x86_32-xsave.c
+++ b/test/CodeGen/x86_32-xsave.c
@@ -15,57 +15,57 @@ void test() {
void* tmp_vp = 0;
#ifdef TEST_XSAVE
-// XSAVE: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVE: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVE: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVE: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVE: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVE: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVE: call void @llvm.x86.xsave(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsave(tmp_vp, tmp_ULLi);
-// XSAVE: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVE: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVE: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVE: [[tmp_vp_3:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_3:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVE: [[high32_3:%[0-9a-zA-Z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVE: [[low32_3:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
// XSAVE: call void @llvm.x86.xrstor(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
(void)__builtin_ia32_xrstor(tmp_vp, tmp_ULLi);
#endif
#ifdef TEST_XSAVEOPT
-// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEOPT: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEOPT: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEOPT: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEOPT: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEOPT: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEOPT: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVEOPT: call void @llvm.x86.xsaveopt(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsaveopt(tmp_vp, tmp_ULLi);
#endif
#ifdef TEST_XSAVEC
-// XSAVEC: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEC: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEC: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEC: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEC: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEC: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEC: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEC: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVEC: call void @llvm.x86.xsavec(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsavec(tmp_vp, tmp_ULLi);
#endif
#ifdef TEST_XSAVES
-// XSAVES: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVES: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVES: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVES: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVES: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVES: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVES: call void @llvm.x86.xsaves(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsaves(tmp_vp, tmp_ULLi);
-// XSAVES: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 4
-// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVES: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVES: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVES: [[tmp_vp_3:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 4
+// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_3:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVES: [[high32_3:%[0-9a-zA-Z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVES: [[low32_3:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
// XSAVES: call void @llvm.x86.xrstors(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
(void)__builtin_ia32_xrstors(tmp_vp, tmp_ULLi);
#endif
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 9f375d780c..d24ea4dbab 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -460,7 +460,7 @@ void test54() {
test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
}
// AVX: @test54_helper(<8 x float> {{%[a-zA-Z0-9]+}}, <8 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double {{%[a-zA-Z0-9]+}}, double {{%[a-zA-Z0-9]+}})
-// AVX: @test54_helper(<8 x float> {{%[a-zA-Z0-9]+}}, <8 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[a-zA-Z0-9]+}})
+// AVX: @test54_helper(<8 x float> {{%[a-zA-Z0-9]+}}, <8 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[^)]+}})
typedef float __m512 __attribute__ ((__vector_size__ (64)));
typedef struct {
@@ -529,7 +529,7 @@ void f63(__m512 *m, __builtin_va_list argList) {
}
// AVX512: @f64_helper(<16 x float> {{%[a-zA-Z0-9]+}}, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double {{%[a-zA-Z0-9]+}}, double {{%[a-zA-Z0-9]+}})
-// AVX512: @f64_helper(<16 x float> {{%[a-zA-Z0-9]+}}, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[a-zA-Z0-9]+}})
+// AVX512: @f64_helper(<16 x float> {{%[a-zA-Z0-9]+}}, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[^)]+}})
void f64_helper(__m512, ...);
__m512 x64;
void f64() {
diff --git a/test/CodeGen/x86_64-mno-sse.c b/test/CodeGen/x86_64-mno-sse.c
new file mode 100644
index 0000000000..43a695ae3c
--- /dev/null
+++ b/test/CodeGen/x86_64-mno-sse.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-linux -target-feature -sse -target-feature -sse2 -S -o /dev/null -verify %s
+// REQUIRES: x86-registered-target
+
+double f1(void) { // expected-error {{SSE register return with SSE disabled}}
+ return 1.4;
+}
+extern double g;
+void f2(void) { // expected-error {{SSE register return with SSE disabled}}
+ g = f1();
+}
+void take_double(double);
+void pass_double(void) {
+ // FIXME: Still asserts.
+ //take_double(1.5);
+}
diff --git a/test/CodeGen/x86_64-xsave.c b/test/CodeGen/x86_64-xsave.c
index 496e982b99..beb775c0e4 100644
--- a/test/CodeGen/x86_64-xsave.c
+++ b/test/CodeGen/x86_64-xsave.c
@@ -15,105 +15,105 @@ void test() {
void* tmp_vp = 0;
#ifdef TEST_XSAVE
-// XSAVE: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVE: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVE: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVE: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVE: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVE: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVE: call void @llvm.x86.xsave(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsave(tmp_vp, tmp_ULLi);
-// XSAVE: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVE: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVE: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVE: [[tmp_vp_2:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_2:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_2:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVE: [[high32_2:%[0-9a-zA-Z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVE: [[low32_2:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
// XSAVE: call void @llvm.x86.xsave64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
(void)__builtin_ia32_xsave64(tmp_vp, tmp_ULLi);
-// XSAVE: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVE: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVE: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVE: [[tmp_vp_3:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_3:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_3:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVE: [[high32_3:%[0-9a-zA-Z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVE: [[low32_3:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
// XSAVE: call void @llvm.x86.xrstor(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
(void)__builtin_ia32_xrstor(tmp_vp, tmp_ULLi);
-// XSAVE: [[tmp_vp_4:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVE: [[tmp_ULLi_4:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVE: [[high64_4:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_4]], 32
-// XSAVE: [[high32_4:%[0-9a-zA-z]+]] = trunc i64 [[high64_4]] to i32
-// XSAVE: [[low32_4:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
+// XSAVE: [[tmp_vp_4:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVE: [[tmp_ULLi_4:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVE: [[high64_4:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_4]], 32
+// XSAVE: [[high32_4:%[0-9a-zA-Z]+]] = trunc i64 [[high64_4]] to i32
+// XSAVE: [[low32_4:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
// XSAVE: call void @llvm.x86.xrstor64(i8* [[tmp_vp_4]], i32 [[high32_4]], i32 [[low32_4]])
(void)__builtin_ia32_xrstor64(tmp_vp, tmp_ULLi);
#endif
#ifdef TEST_XSAVEOPT
-// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEOPT: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEOPT: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEOPT: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEOPT: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEOPT: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEOPT: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEOPT: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEOPT: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVEOPT: call void @llvm.x86.xsaveopt(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsaveopt(tmp_vp, tmp_ULLi);
-// XSAVEOPT: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEOPT: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEOPT: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVEOPT: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVEOPT: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVEOPT: [[tmp_vp_2:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEOPT: [[tmp_ULLi_2:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEOPT: [[high64_2:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVEOPT: [[high32_2:%[0-9a-zA-Z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVEOPT: [[low32_2:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
// XSAVEOPT: call void @llvm.x86.xsaveopt64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
(void)__builtin_ia32_xsaveopt64(tmp_vp, tmp_ULLi);
#endif
#ifdef TEST_XSAVEC
-// XSAVEC: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEC: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVEC: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVEC: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVEC: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEC: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEC: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVEC: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVEC: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVEC: call void @llvm.x86.xsavec(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsavec(tmp_vp, tmp_ULLi);
-// XSAVEC: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVEC: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVEC: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVEC: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVEC: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVEC: [[tmp_vp_2:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVEC: [[tmp_ULLi_2:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVEC: [[high64_2:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVEC: [[high32_2:%[0-9a-zA-Z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVEC: [[low32_2:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
// XSAVEC: call void @llvm.x86.xsavec64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
(void)__builtin_ia32_xsavec64(tmp_vp, tmp_ULLi);
#endif
#ifdef TEST_XSAVES
-// XSAVES: [[tmp_vp_1:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_1:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_1]], 32
-// XSAVES: [[high32_1:%[0-9a-zA-z]+]] = trunc i64 [[high64_1]] to i32
-// XSAVES: [[low32_1:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
+// XSAVES: [[tmp_vp_1:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_1:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_1:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_1]], 32
+// XSAVES: [[high32_1:%[0-9a-zA-Z]+]] = trunc i64 [[high64_1]] to i32
+// XSAVES: [[low32_1:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_1]] to i32
// XSAVES: call void @llvm.x86.xsaves(i8* [[tmp_vp_1]], i32 [[high32_1]], i32 [[low32_1]])
(void)__builtin_ia32_xsaves(tmp_vp, tmp_ULLi);
-// XSAVES: [[tmp_vp_2:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_2:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_2:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_2]], 32
-// XSAVES: [[high32_2:%[0-9a-zA-z]+]] = trunc i64 [[high64_2]] to i32
-// XSAVES: [[low32_2:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
+// XSAVES: [[tmp_vp_2:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_2:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_2:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_2]], 32
+// XSAVES: [[high32_2:%[0-9a-zA-Z]+]] = trunc i64 [[high64_2]] to i32
+// XSAVES: [[low32_2:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_2]] to i32
// XSAVES: call void @llvm.x86.xsaves64(i8* [[tmp_vp_2]], i32 [[high32_2]], i32 [[low32_2]])
(void)__builtin_ia32_xsaves64(tmp_vp, tmp_ULLi);
-// XSAVES: [[tmp_vp_3:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_3:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_3]], 32
-// XSAVES: [[high32_3:%[0-9a-zA-z]+]] = trunc i64 [[high64_3]] to i32
-// XSAVES: [[low32_3:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
+// XSAVES: [[tmp_vp_3:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_3:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_3:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_3]], 32
+// XSAVES: [[high32_3:%[0-9a-zA-Z]+]] = trunc i64 [[high64_3]] to i32
+// XSAVES: [[low32_3:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_3]] to i32
// XSAVES: call void @llvm.x86.xrstors(i8* [[tmp_vp_3]], i32 [[high32_3]], i32 [[low32_3]])
(void)__builtin_ia32_xrstors(tmp_vp, tmp_ULLi);
-// XSAVES: [[tmp_vp_4:%[0-9a-zA-z]+]] = load i8*, i8** %tmp_vp, align 8
-// XSAVES: [[tmp_ULLi_4:%[0-9a-zA-z]+]] = load i64, i64* %tmp_ULLi, align 8
-// XSAVES: [[high64_4:%[0-9a-zA-z]+]] = lshr i64 [[tmp_ULLi_4]], 32
-// XSAVES: [[high32_4:%[0-9a-zA-z]+]] = trunc i64 [[high64_4]] to i32
-// XSAVES: [[low32_4:%[0-9a-zA-z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
+// XSAVES: [[tmp_vp_4:%[0-9a-zA-Z]+]] = load i8*, i8** %tmp_vp, align 8
+// XSAVES: [[tmp_ULLi_4:%[0-9a-zA-Z]+]] = load i64, i64* %tmp_ULLi, align 8
+// XSAVES: [[high64_4:%[0-9a-zA-Z]+]] = lshr i64 [[tmp_ULLi_4]], 32
+// XSAVES: [[high32_4:%[0-9a-zA-Z]+]] = trunc i64 [[high64_4]] to i32
+// XSAVES: [[low32_4:%[0-9a-zA-Z]+]] = trunc i64 [[tmp_ULLi_4]] to i32
// XSAVES: call void @llvm.x86.xrstors64(i8* [[tmp_vp_4]], i32 [[high32_4]], i32 [[low32_4]])
(void)__builtin_ia32_xrstors64(tmp_vp, tmp_ULLi);
#endif
diff --git a/test/CodeGen/xop-builtins-cmp.c b/test/CodeGen/xop-builtins-cmp.c
new file mode 100644
index 0000000000..a805352ad3
--- /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/xray-always-instrument.cpp b/test/CodeGen/xray-always-instrument.cpp
new file mode 100644
index 0000000000..60d8595699
--- /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.cpp b/test/CodeGen/xray-attributes-supported.cpp
index 860efb276f..21a5dde53a 100644
--- a/test/CodeGen/xray-attributes-supported.cpp
+++ b/test/CodeGen/xray-attributes-supported.cpp
@@ -1,5 +1,5 @@
// 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 arm-unknown-linux-gnu -target-abi apcs-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
diff --git a/test/CodeGen/xray-customevent.cpp b/test/CodeGen/xray-customevent.cpp
new file mode 100644
index 0000000000..359d92df93
--- /dev/null
+++ b/test/CodeGen/xray-customevent.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fxray-instrument -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: @_Z16alwaysInstrumentv
+[[clang::xray_always_instrument]] void alwaysInstrument() {
+ static constexpr char kPhase[] = "instrument";
+ __xray_customevent(kPhase, 10);
+ // CHECK: call void @llvm.xray.customevent(i8*{{.*}}, i32 10)
+}
+
+// CHECK-LABEL: @_Z15neverInstrumentv
+[[clang::xray_never_instrument]] void neverInstrument() {
+ static constexpr char kPhase[] = "never";
+ __xray_customevent(kPhase, 5);
+ // CHECK-NOT: call void @llvm.xray.customevent(i8*{{.*}}, i32 5)
+}
+
+// CHECK-LABEL: @_Z21conditionalInstrumenti
+[[clang::xray_always_instrument]] void conditionalInstrument(int v) {
+ static constexpr char kTrue[] = "true";
+ static constexpr char kUntrue[] = "untrue";
+ if (v % 2)
+ __xray_customevent(kTrue, 4);
+ else
+ __xray_customevent(kUntrue, 6);
+
+ // CHECK: call void @llvm.xray.customevent(i8*{{.*}}, i32 4)
+ // CHECK: call void @llvm.xray.customevent(i8*{{.*}}, i32 6)
+}
diff --git a/test/CodeGen/xray-imbue-arg1.cpp b/test/CodeGen/xray-imbue-arg1.cpp
new file mode 100644
index 0000000000..eb272b97ea
--- /dev/null
+++ b/test/CodeGen/xray-imbue-arg1.cpp
@@ -0,0 +1,12 @@
+// RUN: echo "fun:*arg1*=arg1" >> %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() {}
+
+void arg1(void*) {}
+
+// CHECK: define void @_Z3foov() #[[FOO:[0-9]+]] {
+// CHECK: define void {{.*}}arg1{{.*}} #[[ALWAYSARG1:[0-9]+]] {
+
+// CHECK: attributes #[[FOO]] = {{.*}}
+// CHECK: attributes #[[ALWAYSARG1]] = {{.*}} "function-instrument"="xray-always" {{.*}} "xray-log-args"="1"
diff --git a/test/CodeGen/xray-instruction-threshold.cpp b/test/CodeGen/xray-instruction-threshold.cpp
new file mode 100644
index 0000000000..b5f4489bd9
--- /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/zvector2.c b/test/CodeGen/zvector2.c
new file mode 100644
index 0000000000..909b3fd765
--- /dev/null
+++ b/test/CodeGen/zvector2.c
@@ -0,0 +1,194 @@
+// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z14 -fzvector \
+// RUN: -O -emit-llvm -o - -W -Wall -Werror %s | FileCheck %s
+
+volatile vector float ff, ff2;
+volatile vector bool int bi;
+
+void test_assign (void)
+{
+// CHECK-LABEL: test_assign
+// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: store volatile <4 x float> [[VAL]], <4 x float>* @ff
+ ff = ff2;
+}
+
+void test_pos (void)
+{
+// CHECK-LABEL: test_pos
+// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: store volatile <4 x float> [[VAL]], <4 x float>* @ff
+ ff = +ff2;
+}
+
+void test_neg (void)
+{
+// CHECK-LABEL: test_neg
+// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[VAL]]
+ ff = -ff2;
+}
+
+void test_preinc (void)
+{
+// CHECK-LABEL: test_preinc
+// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fadd <4 x float> [[VAL]], <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+ ++ff2;
+}
+
+void test_postinc (void)
+{
+// CHECK-LABEL: test_postinc
+// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fadd <4 x float> [[VAL]], <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+ ff2++;
+}
+
+void test_predec (void)
+{
+// CHECK-LABEL: test_predec
+// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fadd <4 x float> [[VAL]], <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
+ --ff2;
+}
+
+void test_postdec (void)
+{
+// CHECK-LABEL: test_postdec
+// CHECK: [[VAL:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fadd <4 x float> [[VAL]], <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
+ ff2--;
+}
+
+void test_add (void)
+{
+// CHECK-LABEL: test_add
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fadd <4 x float> [[VAL1]], [[VAL2]]
+ ff = ff + ff2;
+}
+
+void test_add_assign (void)
+{
+// CHECK-LABEL: test_add_assign
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: %{{.*}} = fadd <4 x float> [[VAL2]], [[VAL1]]
+ ff += ff2;
+}
+
+void test_sub (void)
+{
+// CHECK-LABEL: test_sub
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fsub <4 x float> [[VAL1]], [[VAL2]]
+ ff = ff - ff2;
+}
+
+void test_sub_assign (void)
+{
+// CHECK-LABEL: test_sub_assign
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: %{{.*}} = fsub <4 x float> [[VAL1]], [[VAL2]]
+ ff -= ff2;
+}
+
+void test_mul (void)
+{
+// CHECK-LABEL: test_mul
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fmul <4 x float> [[VAL1]], [[VAL2]]
+ ff = ff * ff2;
+}
+
+void test_mul_assign (void)
+{
+// CHECK-LABEL: test_mul_assign
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: %{{.*}} = fmul <4 x float> [[VAL2]], [[VAL1]]
+ ff *= ff2;
+}
+
+void test_div (void)
+{
+// CHECK-LABEL: test_div
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: %{{.*}} = fdiv <4 x float> [[VAL1]], [[VAL2]]
+ ff = ff / ff2;
+}
+
+void test_div_assign (void)
+{
+// CHECK-LABEL: test_div_assign
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: %{{.*}} = fdiv <4 x float> [[VAL1]], [[VAL2]]
+ ff /= ff2;
+}
+
+void test_cmpeq (void)
+{
+// CHECK-LABEL: test_cmpeq
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[CMP:%[^ ]+]] = fcmp oeq <4 x float> [[VAL1]], [[VAL2]]
+// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
+ bi = ff == ff2;
+}
+
+void test_cmpne (void)
+{
+// CHECK-LABEL: test_cmpne
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[CMP:%[^ ]+]] = fcmp une <4 x float> [[VAL1]], [[VAL2]]
+// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
+ bi = ff != ff2;
+}
+
+void test_cmpge (void)
+{
+// CHECK-LABEL: test_cmpge
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[CMP:%[^ ]+]] = fcmp oge <4 x float> [[VAL1]], [[VAL2]]
+// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
+ bi = ff >= ff2;
+}
+
+void test_cmpgt (void)
+{
+// CHECK-LABEL: test_cmpgt
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[CMP:%[^ ]+]] = fcmp ogt <4 x float> [[VAL1]], [[VAL2]]
+// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
+ bi = ff > ff2;
+}
+
+void test_cmple (void)
+{
+// CHECK-LABEL: test_cmple
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[CMP:%[^ ]+]] = fcmp ole <4 x float> [[VAL1]], [[VAL2]]
+// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
+ bi = ff <= ff2;
+}
+
+void test_cmplt (void)
+{
+// CHECK-LABEL: test_cmplt
+// CHECK: [[VAL1:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff
+// CHECK: [[VAL2:%[^ ]+]] = load volatile <4 x float>, <4 x float>* @ff2
+// CHECK: [[CMP:%[^ ]+]] = fcmp olt <4 x float> [[VAL1]], [[VAL2]]
+// CHECK: %{{.*}} = sext <4 x i1> [[CMP]] to <4 x i32>
+ bi = ff < ff2;
+}
+
diff --git a/test/CodeGenCUDA/flush-denormals.cu b/test/CodeGenCUDA/flush-denormals.cu
index e528d7b102..94285f1f33 100644
--- a/test/CodeGenCUDA/flush-denormals.cu
+++ b/test/CodeGenCUDA/flush-denormals.cu
@@ -18,8 +18,8 @@ extern "C" __device__ void foo() {}
// FTZ: attributes #0 = {{.*}} "nvptx-f32ftz"="true"
// NOFTZ-NOT: attributes #0 = {{.*}} "nvptx-f32ftz"
-// FTZ:!llvm.module.flags = !{[[MODFLAG:![0-9]+]]}
+// FTZ:!llvm.module.flags = !{{{.*}}[[MODFLAG:![0-9]+]]}
// FTZ:[[MODFLAG]] = !{i32 4, !"nvvm-reflect-ftz", i32 1}
-// NOFTZ:!llvm.module.flags = !{[[MODFLAG:![0-9]+]]}
+// NOFTZ:!llvm.module.flags = !{{{.*}}[[MODFLAG:![0-9]+]]}
// NOFTZ:[[MODFLAG]] = !{i32 4, !"nvvm-reflect-ftz", i32 0}
diff --git a/test/CodeGenCUDA/fp-contract.cu b/test/CodeGenCUDA/fp-contract.cu
index 070ebaea44..96de5c451b 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/CodeGenCXX/amdgcn-automatic-variable.cpp b/test/CodeGenCXX/amdgcn-automatic-variable.cpp
new file mode 100644
index 0000000000..9830a7845e
--- /dev/null
+++ b/test/CodeGenCXX/amdgcn-automatic-variable.cpp
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -O0 -triple amdgcn---amdgiz -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-LABEL: define void @_Z5func1Pi(i32* %x)
+void func1(int *x) {
+ // CHECK: %[[x_addr:.*]] = alloca i32*{{.*}}addrspace(5)
+ // CHECK: %[[r0:.*]] = addrspacecast i32* addrspace(5)* %[[x_addr]] to i32**
+ // CHECK: store i32* %x, i32** %[[r0]]
+ // CHECK: %[[r1:.*]] = load i32*, i32** %[[r0]]
+ // CHECK: store i32 1, i32* %[[r1]]
+ *x = 1;
+}
+
+// CHECK-LABEL: define void @_Z5func2v()
+void func2(void) {
+ // CHECK: %lv1 = alloca i32, align 4, addrspace(5)
+ // CHECK: %[[r0:.*]] = addrspacecast i32 addrspace(5)* %lv1 to i32*
+ // CHECK: %lv2 = alloca i32, align 4, addrspace(5)
+ // CHECK: %[[r1:.*]] = addrspacecast i32 addrspace(5)* %lv2 to i32*
+ // CHECK: %la = alloca [100 x i32], align 4, addrspace(5)
+ // CHECK: %[[r2:.*]] = addrspacecast [100 x i32] addrspace(5)* %la to [100 x i32]*
+ // CHECK: %lp1 = alloca i32*, align 8, addrspace(5)
+ // CHECK: %[[r3:.*]] = addrspacecast i32* addrspace(5)* %lp1 to i32**
+ // CHECK: %lp2 = alloca i32*, align 8, addrspace(5)
+ // CHECK: %[[r4:.*]] = addrspacecast i32* addrspace(5)* %lp2 to i32**
+ // CHECK: %lvc = alloca i32, align 4, addrspace(5)
+ // CHECK: %[[r5:.*]] = addrspacecast i32 addrspace(5)* %lvc to i32*
+
+ // CHECK: store i32 1, i32* %[[r0]]
+ int lv1;
+ lv1 = 1;
+ // CHECK: store i32 2, i32* %[[r1]]
+ int lv2 = 2;
+
+ // CHECK: %[[arrayidx:.*]] = getelementptr inbounds [100 x i32], [100 x i32]* %[[r2]], i64 0, i64 0
+ // CHECK: store i32 3, i32* %[[arrayidx]], align 4
+ int la[100];
+ la[0] = 3;
+
+ // CHECK: store i32* %[[r0]], i32** %[[r3]], align 8
+ int *lp1 = &lv1;
+
+ // CHECK: %[[arraydecay:.*]] = getelementptr inbounds [100 x i32], [100 x i32]* %[[r2]], i32 0, i32 0
+ // CHECK: store i32* %[[arraydecay]], i32** %[[r4]], align 8
+ int *lp2 = la;
+
+ // CHECK: call void @_Z5func1Pi(i32* %[[r0]])
+ func1(&lv1);
+
+ // CHECK: store i32 4, i32* %[[r5]]
+ // CHECK: store i32 4, i32* %[[r0]]
+ const int lvc = 4;
+ lv1 = lvc;
+}
+
+void destroy(int x);
+
+class A {
+int x;
+public:
+ A():x(0) {}
+ ~A() {
+ destroy(x);
+ }
+};
+
+// CHECK-LABEL: define void @_Z5func3v
+void func3() {
+ // CHECK: %[[a:.*]] = alloca %class.A, align 4, addrspace(5)
+ // CHECK: %[[r0:.*]] = addrspacecast %class.A addrspace(5)* %[[a]] to %class.A*
+ // CHECK: call void @_ZN1AC1Ev(%class.A* %[[r0]])
+ // CHECK: call void @_ZN1AD1Ev(%class.A* %[[r0]])
+ A a;
+}
+
+// CHECK-LABEL: define void @_Z5func4i
+void func4(int x) {
+ // CHECK: %[[x_addr:.*]] = alloca i32, align 4, addrspace(5)
+ // CHECK: %[[r0:.*]] = addrspacecast i32 addrspace(5)* %[[x_addr]] to i32*
+ // CHECK: store i32 %x, i32* %[[r0]], align 4
+ // CHECK: call void @_Z5func1Pi(i32* %[[r0]])
+ func1(&x);
+}
+
+// CHECK-LABEL: define void @_Z5func5v
+void func5() {
+ return;
+ int x = 0;
+}
+
+// CHECK-LABEL: define void @_Z5func6v
+void func6() {
+ return;
+ int x;
+}
+
+// CHECK-LABEL: define void @_Z5func7v
+extern void use(int *);
+void func7() {
+ goto later;
+ int x;
+later:
+ use(&x);
+}
+
+// CHECK-NOT: !opencl.ocl.version
diff --git a/test/CodeGenCXX/anonymous-namespaces.cpp b/test/CodeGenCXX/anonymous-namespaces.cpp
index abc700fef6..b2857ff417 100644
--- a/test/CodeGenCXX/anonymous-namespaces.cpp
+++ b/test/CodeGenCXX/anonymous-namespaces.cpp
@@ -6,7 +6,8 @@ int f();
namespace {
// CHECK-1: @_ZN12_GLOBAL__N_11bE = internal global i32 0
- // CHECK-1: @_ZN12_GLOBAL__N_1L1cE = internal global i32 0
+ // CHECK-1: @_ZN12_GLOBAL__N_11cE = internal global i32 0
+ // CHECK-1: @_ZN12_GLOBAL__N_12c2E = internal global i32 0
// CHECK-1: @_ZN12_GLOBAL__N_11D1dE = internal global i32 0
// CHECK-1: @_ZN12_GLOBAL__N_11aE = internal global i32 0
int a = 0;
@@ -15,6 +16,12 @@ namespace {
static int c = f();
+ // Note, we can't use an 'L' mangling for c or c2 (like GCC does) based on
+ // the 'static' specifier, because the variable can be redeclared without it.
+ extern int c2;
+ int g() { return c2; }
+ static int c2 = f();
+
class D {
static int d;
};
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
index 69fa61c215..e8c4480b49 100644
--- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -80,37 +80,37 @@ namespace PR10512 {
};
// CHECK-LABEL: define void @_ZN7PR105121AC2Ev
- // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
- // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]]
- // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]*, [[A]]** [[THISADDR]]
+ // CHECK: [[THISADDR:%[a-zA-Z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
+ // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-Z0-9.]+]], [[A]]** [[THISADDR]]
+ // CHECK-NEXT: [[THIS1:%[a-zA-Z0-9.]+]] = load [[A]]*, [[A]]** [[THISADDR]]
// CHECK-NEXT: ret void
A::A() {}
// CHECK-LABEL: define void @_ZN7PR105121AC2Ei
- // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
- // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i32
- // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]]
- // CHECK-NEXT: store i32 [[X:%[a-zA-z0-9.]+]], i32* [[XADDR]]
- // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]*, [[A]]** [[THISADDR]]
+ // CHECK: [[THISADDR:%[a-zA-Z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
+ // CHECK-NEXT: [[XADDR:%[a-zA-Z0-9.]+]] = alloca i32
+ // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-Z0-9.]+]], [[A]]** [[THISADDR]]
+ // CHECK-NEXT: store i32 [[X:%[a-zA-Z0-9.]+]], i32* [[XADDR]]
+ // CHECK-NEXT: [[THIS1:%[a-zA-Z0-9.]+]] = load [[A]]*, [[A]]** [[THISADDR]]
// CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
// CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
// CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
- // CHECK-NEXT: [[TMP:%[a-zA-z0-9.]+]] = load i32, i32* [[XADDR]]
+ // CHECK-NEXT: [[TMP:%[a-zA-Z0-9.]+]] = load i32, i32* [[XADDR]]
// CHECK-NEXT: store i32 [[TMP]]
// CHECK-NEXT: ret void
A::A(int x) : x(x) { }
// CHECK-LABEL: define void @_ZN7PR105121AC2El
- // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
- // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i64
- // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]]
- // CHECK-NEXT: store i64 [[X:%[a-zA-z0-9.]+]], i64* [[XADDR]]
- // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]*, [[A]]** [[THISADDR]]
+ // CHECK: [[THISADDR:%[a-zA-Z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]]
+ // CHECK-NEXT: [[XADDR:%[a-zA-Z0-9.]+]] = alloca i64
+ // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-Z0-9.]+]], [[A]]** [[THISADDR]]
+ // CHECK-NEXT: store i64 [[X:%[a-zA-Z0-9.]+]], i64* [[XADDR]]
+ // CHECK-NEXT: [[THIS1:%[a-zA-Z0-9.]+]] = load [[A]]*, [[A]]** [[THISADDR]]
// CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
// CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 1}}
// CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}}
- // CHECK-NEXT: [[TMP:%[a-zA-z0-9.]+]] = load i64, i64* [[XADDR]]
- // CHECK-NEXT: [[CONV:%[a-zA-z0-9.]+]] = trunc i64 [[TMP]] to i32
+ // CHECK-NEXT: [[TMP:%[a-zA-Z0-9.]+]] = load i64, i64* [[XADDR]]
+ // CHECK-NEXT: [[CONV:%[a-zA-Z0-9.]+]] = trunc i64 [[TMP]] to i32
// CHECK-NEXT: store i32 [[CONV]]
// CHECK-NEXT: ret void
A::A(long y) : y(y) { }
diff --git a/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp b/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp
index 4cfa88d994..3f26cb4067 100644
--- a/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp
+++ b/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -disable-O0-optnone -emit-llvm -o - %s | FileCheck %s
// CHECK: @_ZTV5TemplIiE = internal unnamed_addr constant { [7 x i8*] } { [7 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.Templ*)* @_ZN5TemplIiED1Ev to i8*), i8* bitcast (void (%struct.Templ*)* @_ZN5TemplIiED0Ev to i8*), i8* bitcast (void (%struct.Templ*)* @_ZN5TemplIiE1fEv to i8*), i8* bitcast (void (%struct.Templ*)* @_ZN5TemplIiE1gEv to i8*), i8* null] }
diff --git a/test/CodeGenCXX/apple-kext-no-staticinit-section.cpp b/test/CodeGenCXX/apple-kext-no-staticinit-section.cpp
index 0401d49179..5d258f6a61 100644
--- a/test/CodeGenCXX/apple-kext-no-staticinit-section.cpp
+++ b/test/CodeGenCXX/apple-kext-no-staticinit-section.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -disable-O0-optnone -emit-llvm -o - %s | FileCheck %s
// rdar://8825235
/**
1) Normally, global object construction code ends up in __StaticInit segment of text section
diff --git a/test/CodeGenCXX/arm64-constructor-return.cpp b/test/CodeGenCXX/arm64-constructor-return.cpp
index 3adc1b7a28..cbe66ab0e2 100644
--- a/test/CodeGenCXX/arm64-constructor-return.cpp
+++ b/test/CodeGenCXX/arm64-constructor-return.cpp
@@ -13,7 +13,7 @@ S::S() {
// CHECK: %struct.S* @_ZN1SC2Ev(%struct.S* returned %this)
// CHECK: %struct.S* @_ZN1SC1Ev(%struct.S* returned %this)
-// CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca %struct.S*
+// CHECK: [[THISADDR:%[a-zA-Z0-9.]+]] = alloca %struct.S*
// CHECK: store %struct.S* %this, %struct.S** [[THISADDR]]
// CHECK: [[THIS1:%.*]] = load %struct.S*, %struct.S** [[THISADDR]]
// CHECK: ret %struct.S* [[THIS1]]
diff --git a/test/CodeGenCXX/array-default-argument.cpp b/test/CodeGenCXX/array-default-argument.cpp
new file mode 100644
index 0000000000..a07e390839
--- /dev/null
+++ b/test/CodeGenCXX/array-default-argument.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple %itanium_abi_triple | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple %itanium_abi_triple -std=c++98 -fexceptions -fcxx-exceptions | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EH
+
+struct A {
+ A();
+ ~A();
+};
+
+struct B {
+ B(A = A());
+ ~B();
+};
+
+void f();
+// CHECK-LABEL: define void @_Z1gv()
+void g() {
+ // CHECK: br label %[[LOOP:.*]]
+
+ // [[LOOP]]:
+ // CHECK: {{call|invoke}} {{.*}} @_ZN1AC1Ev([[TEMPORARY:.*]])
+ // CHECK-EH: unwind label %[[PARTIAL_ARRAY_LPAD:.*]]
+ // CHECK: {{call|invoke}} {{.*}} @_ZN1BC1E1A({{.*}}, [[TEMPORARY]])
+ // CHECK-EH: unwind label %[[A_AND_PARTIAL_ARRAY_LPAD:.*]]
+ // CHECK: {{call|invoke}} {{.*}} @_ZN1AD1Ev([[TEMPORARY]])
+ // CHECK-EH: unwind label %[[PARTIAL_ARRAY_LPAD]]
+ // CHECK: getelementptr {{.*}}, i{{[0-9]*}} 1
+ // CHECK: icmp eq
+ // CHECK: br i1 {{.*}} label %[[LOOP]]
+ B b[5];
+
+ // CHECK: {{call|invoke}} void @_Z1fv()
+ f();
+
+ // CHECK-NOT: @_ZN1AD1Ev(
+ // CHECK: {{call|invoke}} {{.*}} @_ZN1BD1Ev(
+}
diff --git a/test/CodeGenCXX/atomic-align.cpp b/test/CodeGenCXX/atomic-align.cpp
new file mode 100644
index 0000000000..9852ac38a6
--- /dev/null
+++ b/test/CodeGenCXX/atomic-align.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - -triple=x86_64-linux-gnu | FileCheck %s
+
+struct AM {
+ int f1, f2;
+};
+alignas(8) AM m;
+AM load1() {
+ AM am;
+ // m is declared to align to 8bytes, so generate load atomic instead
+ // of libcall.
+ // CHECK-LABEL: @_Z5load1v
+ // CHECK: load atomic {{.*}} monotonic
+ __atomic_load(&m, &am, 0);
+ return am;
+}
+
+struct BM {
+ int f1;
+ alignas(8) AM f2;
+};
+BM bm;
+AM load2() {
+ AM am;
+ // BM::f2 is declared to align to 8bytes, so generate load atomic instead
+ // of libcall.
+ // CHECK-LABEL: @_Z5load2v
+ // CHECK: load atomic {{.*}} monotonic
+ __atomic_load(&bm.f2, &am, 0);
+ return am;
+}
diff --git a/test/CodeGenCXX/atomic-inline.cpp b/test/CodeGenCXX/atomic-inline.cpp
new file mode 100644
index 0000000000..fe727589d2
--- /dev/null
+++ b/test/CodeGenCXX/atomic-inline.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - -triple=x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - -triple=x86_64-linux-gnu -target-cpu core2 | FileCheck %s --check-prefix=CORE2
+// Check the atomic code generation for cpu targets w/wo cx16 support.
+
+struct alignas(8) AM8 {
+ int f1, f2;
+};
+AM8 m8;
+AM8 load8() {
+ AM8 am;
+ // CHECK-LABEL: @_Z5load8v
+ // CHECK: load atomic i64, {{.*}} monotonic
+ // CORE2-LABEL: @_Z5load8v
+ // CORE2: load atomic i64, {{.*}} monotonic
+ __atomic_load(&m8, &am, 0);
+ return am;
+}
+
+AM8 s8;
+void store8() {
+ // CHECK-LABEL: @_Z6store8v
+ // CHECK: store atomic i64 {{.*}} monotonic
+ // CORE2-LABEL: @_Z6store8v
+ // CORE2: store atomic i64 {{.*}} monotonic
+ __atomic_store(&m8, &s8, 0);
+}
+
+bool cmpxchg8() {
+ AM8 am;
+ // CHECK-LABEL: @_Z8cmpxchg8v
+ // CHECK: cmpxchg i64* {{.*}} monotonic
+ // CORE2-LABEL: @_Z8cmpxchg8v
+ // CORE2: cmpxchg i64* {{.*}} monotonic
+ return __atomic_compare_exchange(&m8, &s8, &am, 0, 0, 0);
+}
+
+struct alignas(16) AM16 {
+ long f1, f2;
+};
+
+AM16 m16;
+AM16 load16() {
+ AM16 am;
+ // CHECK-LABEL: @_Z6load16v
+ // CHECK: call void @__atomic_load
+ // CORE2-LABEL: @_Z6load16v
+ // CORE2: load atomic i128, {{.*}} monotonic
+ __atomic_load(&m16, &am, 0);
+ return am;
+}
+
+AM16 s16;
+void store16() {
+ // CHECK-LABEL: @_Z7store16v
+ // CHECK: call void @__atomic_store
+ // CORE2-LABEL: @_Z7store16v
+ // CORE2: store atomic i128 {{.*}} monotonic
+ __atomic_store(&m16, &s16, 0);
+}
+
+bool cmpxchg16() {
+ AM16 am;
+ // CHECK-LABEL: @_Z9cmpxchg16v
+ // CHECK: call zeroext i1 @__atomic_compare_exchange
+ // CORE2-LABEL: @_Z9cmpxchg16v
+ // CORE2: cmpxchg i128* {{.*}} monotonic
+ return __atomic_compare_exchange(&m16, &s16, &am, 0, 0, 0);
+}
+
diff --git a/test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp b/test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp
new file mode 100644
index 0000000000..c032e38f31
--- /dev/null
+++ b/test/CodeGenCXX/attr-x86-no_caller_saved_registers.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-win32 %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: foo{{[^#]*}}#[[ATTRS:[0-9]+]]
+__attribute__((no_caller_saved_registers)) void foo() {}
+namespace S {
+// CHECK: bar{{[^#]*}}#[[ATTRS]]
+__attribute__((no_caller_saved_registers)) void bar(int *a) { foo(); }
+}
+
+struct St {
+ static void baz(int *a) __attribute__((no_caller_saved_registers)) { S::bar(a); }
+};
+
+__attribute((no_caller_saved_registers)) void (*foobar)(void);
+
+// CHECK-LABEL: @main
+int main(int argc, char **argv) {
+ St::baz(&argc);
+ // CHECK: [[FOOBAR:%.+]] = load void ()*, void ()** @{{.*}}foobar{{.*}},
+ // CHECK-NEXT: call void [[FOOBAR]]() #[[ATTRS1:.+]]
+ foobar();
+ return 0;
+}
+
+// CHECK: baz{{[^#]*}}#[[ATTRS]]
+
+// CHECK: attributes #[[ATTRS]] = {
+// CHECK-SAME: "no_caller_saved_registers"
+// CHECK-SAME: }
+// CHECK: attributes #[[ATTRS1]] = { "no_caller_saved_registers" }
diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index 5b7c7e6e46..37219d3f7a 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -122,7 +122,6 @@ namespace test4 {
// CHECK-LABEL: define internal void @___ZN5test44testEv_block_invoke
// CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
// CHECK-NEXT: store i8* [[BLOCKDESC:%.*]], i8** {{.*}}, align 8
- // CHECK-NEXT: load i8*, i8**
// CHECK-NEXT: bitcast i8* [[BLOCKDESC]] to <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*
// CHECK: call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
// CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
diff --git a/test/CodeGenCXX/captured-statements.cpp b/test/CodeGenCXX/captured-statements.cpp
index 4b95503ad7..95e73e5483 100644
--- a/test/CodeGenCXX/captured-statements.cpp
+++ b/test/CodeGenCXX/captured-statements.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm %s -o %t
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm %s -o %t -debug-info-kind=limited
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3
@@ -194,3 +194,18 @@ inline int test_captured_linkage() {
void call_test_captured_linkage() {
test_captured_linkage();
}
+
+// CHECK-1-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer)
+// CHECK-1-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)
+// CHECK-2-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer)
+// CHECK-2-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)
+// CHECK-3-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer)
+// CHECK-3-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)
+// CHECK-4-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer)
+// CHECK-4-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)
+// CHECK-5-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer)
+// CHECK-5-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)
+// CHECK-6-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer)
+// CHECK-6-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)
+// CHECK-7-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer)
+// CHECK-7-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)
diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp
index 179c334122..e828753898 100644
--- a/test/CodeGenCXX/catch-undef-behavior.cpp
+++ b/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -16,6 +16,10 @@ struct S {
// Check that type mismatch handler is not modified by ASan.
// CHECK-ASAN: private unnamed_addr global { { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }*, i8*, i8 } { {{.*}}, { i16, i16, [4 x i8] }* [[TYPE_DESCR]], {{.*}} }
+// CHECK: [[IndirectRTTI_ZTIFvPFviEE:@.+]] = private constant i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*)
+// CHECK-X86: [[IndirectRTTI_ZTIFvPFviEE:@.+]] = private constant i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*)
+// CHECK-X32: [[IndirectRTTI_ZTIFvPFviEE:@.+]] = private constant i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*)
+
struct T : S {};
// CHECK-LABEL: @_Z17reference_binding
@@ -395,26 +399,93 @@ void downcast_reference(B &b) {
// CHECK-NEXT: br i1 [[AND]]
}
-// CHECK-LABEL: @_Z22indirect_function_callPFviE({{.*}} prologue <{ i32, i8* }> <{ i32 1413876459, i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*) }>
-// CHECK-X32: @_Z22indirect_function_callPFviE({{.*}} prologue <{ i32, i8* }> <{ i32 1413875435, i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*) }>
-// CHECK-X86: @_Z22indirect_function_callPFviE({{.*}} prologue <{ i32, i8* }> <{ i32 1413875435, i8* bitcast ({ i8*, i8* }* @_ZTIFvPFviEE to i8*) }>
+//
+// CHECK-LABEL: @_Z22indirect_function_callPFviE({{.*}} prologue <{ i32, i32 }> <{ i32 846595819, i32 trunc (i64 sub (i64 ptrtoint (i8** {{.*}} to i64), i64 ptrtoint (void (void (i32)*)* @_Z22indirect_function_callPFviE to i64)) to i32) }>
+// CHECK-X32: @_Z22indirect_function_callPFviE({{.*}} prologue <{ i32, i32 }> <{ i32 846595819, i32 sub (i32 ptrtoint (i8** [[IndirectRTTI_ZTIFvPFviEE]] to i32), i32 ptrtoint (void (void (i32)*)* @_Z22indirect_function_callPFviE to i32)) }>
+// CHECK-X86: @_Z22indirect_function_callPFviE({{.*}} prologue <{ i32, i32 }> <{ i32 846595819, i32 sub (i32 ptrtoint (i8** [[IndirectRTTI_ZTIFvPFviEE]] to i32), i32 ptrtoint (void (void (i32)*)* @_Z22indirect_function_callPFviE to i32)) }>
void indirect_function_call(void (*p)(int)) {
- // CHECK: [[PTR:%.+]] = bitcast void (i32)* {{.*}} to <{ i32, i8* }>*
+ // CHECK: [[PTR:%.+]] = bitcast void (i32)* {{.*}} to <{ i32, i32 }>*
// Signature check
- // CHECK-NEXT: [[SIGPTR:%.+]] = getelementptr <{ i32, i8* }>, <{ i32, i8* }>* [[PTR]], i32 0, i32 0
+ // CHECK-NEXT: [[SIGPTR:%.+]] = getelementptr <{ i32, i32 }>, <{ i32, i32 }>* [[PTR]], i32 0, i32 0
// CHECK-NEXT: [[SIG:%.+]] = load i32, i32* [[SIGPTR]]
- // CHECK-NEXT: [[SIGCMP:%.+]] = icmp eq i32 [[SIG]], 1413876459
+ // CHECK-NEXT: [[SIGCMP:%.+]] = icmp eq i32 [[SIG]], 846595819
// CHECK-NEXT: br i1 [[SIGCMP]]
// RTTI pointer check
- // CHECK: [[RTTIPTR:%.+]] = getelementptr <{ i32, i8* }>, <{ i32, i8* }>* [[PTR]], i32 0, i32 1
- // CHECK-NEXT: [[RTTI:%.+]] = load i8*, i8** [[RTTIPTR]]
+ // CHECK: [[RTTIPTR:%.+]] = getelementptr <{ i32, i32 }>, <{ i32, i32 }>* [[PTR]], i32 0, i32 1
+ // CHECK-NEXT: [[RTTIEncIntTrunc:%.+]] = load i32, i32* [[RTTIPTR]]
+ // CHECK-NEXT: [[RTTIEncInt:%.+]] = sext i32 [[RTTIEncIntTrunc]] to i64
+ // CHECK-NEXT: [[FuncAddrInt:%.+]] = ptrtoint void (i32)* {{.*}} to i64
+ // CHECK-NEXT: [[IndirectGVInt:%.+]] = add i64 [[RTTIEncInt]], [[FuncAddrInt]]
+ // CHECK-NEXT: [[IndirectGV:%.+]] = inttoptr i64 [[IndirectGVInt]] to i8**
+ // CHECK-NEXT: [[RTTI:%.+]] = load i8*, i8** [[IndirectGV]], align 8
// CHECK-NEXT: [[RTTICMP:%.+]] = icmp eq i8* [[RTTI]], bitcast ({ i8*, i8* }* @_ZTIFviE to i8*)
// CHECK-NEXT: br i1 [[RTTICMP]]
+
p(42);
}
+namespace FunctionSanitizerVirtualCalls {
+struct A {
+ virtual void f() {}
+ virtual void g() {}
+ void h() {}
+};
+
+struct B : virtual A {
+ virtual void b() {}
+ virtual void f();
+ void g() final {}
+ static void q() {}
+};
+
+void B::f() {}
+
+void force_irgen() {
+ A a;
+ a.g();
+ a.h();
+
+ B b;
+ b.f();
+ b.b();
+ b.g();
+ B::q();
+}
+
+// CHECK-LABEL: define void @_ZN29FunctionSanitizerVirtualCalls1B1fEv
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define void @_ZTv0_n24_N29FunctionSanitizerVirtualCalls1B1fEv
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define void @_ZN29FunctionSanitizerVirtualCalls11force_irgenEv()
+// CHECK: prologue
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN29FunctionSanitizerVirtualCalls1AC1Ev
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN29FunctionSanitizerVirtualCalls1A1gEv
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN29FunctionSanitizerVirtualCalls1A1hEv
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN29FunctionSanitizerVirtualCalls1BC1Ev
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN29FunctionSanitizerVirtualCalls1B1bEv
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN29FunctionSanitizerVirtualCalls1B1gEv
+// CHECK-NOT: prologue
+//
+// CHECK-LABEL: define linkonce_odr void @_ZN29FunctionSanitizerVirtualCalls1B1qEv
+// CHECK: prologue
+
+}
+
namespace UpcastPointerTest {
struct S {};
struct T : S { double d; };
@@ -449,6 +520,28 @@ void upcast_to_vbase() {
}
}
+struct ThisAlign {
+ void this_align_lambda();
+ void this_align_lambda_2();
+};
+void ThisAlign::this_align_lambda() {
+ // CHECK-LABEL: define internal %struct.ThisAlign* @"_ZZN9ThisAlign17this_align_lambdaEvENK3$_0clEv"
+ // CHECK-SAME: (%{{.*}}* %[[this:[^)]*]])
+ // CHECK: %[[this_addr:.*]] = alloca
+ // CHECK: store %{{.*}}* %[[this]], %{{.*}}** %[[this_addr]],
+ // CHECK: %[[this_inner:.*]] = load %{{.*}}*, %{{.*}}** %[[this_addr]],
+ // CHECK: %[[this_outer_addr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %[[this_inner]], i32 0, i32 0
+ // CHECK: %[[this_outer:.*]] = load %{{.*}}*, %{{.*}}** %[[this_outer_addr]],
+ //
+ // CHECK: %[[this_inner_isnonnull:.*]] = icmp ne %{{.*}}* %[[this_inner]], null
+ // CHECK: %[[this_inner_asint:.*]] = ptrtoint %{{.*}}* %[[this_inner]] to i
+ // CHECK: %[[this_inner_misalignment:.*]] = and i{{32|64}} %[[this_inner_asint]], {{3|7}},
+ // CHECK: %[[this_inner_isaligned:.*]] = icmp eq i{{32|64}} %[[this_inner_misalignment]], 0
+ // CHECK: %[[this_inner_valid:.*]] = and i1 %[[this_inner_isnonnull]], %[[this_inner_isaligned]],
+ // CHECK: br i1 %[[this_inner_valid:.*]]
+ [&] { return this; } ();
+}
+
namespace CopyValueRepresentation {
// CHECK-LABEL: define {{.*}} @_ZN23CopyValueRepresentation2S3aSERKS0_
// CHECK-NOT: call {{.*}} @__ubsan_handle_load_invalid_value
@@ -532,4 +625,18 @@ namespace CopyValueRepresentation {
}
}
+void ThisAlign::this_align_lambda_2() {
+ // CHECK-LABEL: define internal void @"_ZZN9ThisAlign19this_align_lambda_2EvENK3$_1clEv"
+ // CHECK-SAME: (%{{.*}}* %[[this:[^)]*]])
+ // CHECK: %[[this_addr:.*]] = alloca
+ // CHECK: store %{{.*}}* %[[this]], %{{.*}}** %[[this_addr]],
+ // CHECK: %[[this_inner:.*]] = load %{{.*}}*, %{{.*}}** %[[this_addr]],
+ //
+ // Do not perform a null check on the 'this' pointer if the function might be
+ // called from a static invoker.
+ // CHECK-NOT: icmp ne %{{.*}}* %[[this_inner]], null
+ auto *p = +[] {};
+ p();
+}
+
// CHECK: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CodeGenCXX/cfi-blacklist.cpp b/test/CodeGenCXX/cfi-blacklist.cpp
index af8a10601d..c01e5fcd92 100644
--- a/test/CodeGenCXX/cfi-blacklist.cpp
+++ b/test/CodeGenCXX/cfi-blacklist.cpp
@@ -1,6 +1,18 @@
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
-// RUN: echo "type:std::*" > %t.txt
-// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+
+// Check that blacklisting cfi and cfi-vcall work correctly
+// RUN: echo "[cfi-vcall]" > %t.vcall.txt
+// RUN: echo "type:std::*" >> %t.vcall.txt
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.vcall.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+//
+// RUN: echo "[cfi]" > %t.cfi.txt
+// RUN: echo "type:std::*" >> %t.cfi.txt
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.cfi.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+
+// Check that blacklisting non-vcall modes does not affect vcalls
+// RUN: echo "[cfi-icall|cfi-nvcall|cfi-cast-strict|cfi-derived-cast|cfi-unrelated-cast]" > %t.other.txt
+// RUN: echo "type:std::*" >> %t.other.txt
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.other.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
struct S1 {
virtual void f();
diff --git a/test/CodeGenCXX/cfi-icall.cpp b/test/CodeGenCXX/cfi-icall.cpp
index c3c6ed309c..5f5778fc1f 100644
--- a/test/CodeGenCXX/cfi-icall.cpp
+++ b/test/CodeGenCXX/cfi-icall.cpp
@@ -8,19 +8,22 @@ namespace {
struct S {};
-void f(S *s) {
+void f(S s) {
}
}
void g() {
- void (*fp)(S *) = f;
- // CHECK: call i1 @llvm.type.test(i8* {{.*}}, metadata [[VOIDS:![0-9]+]])
- fp(0);
+ struct S s;
+ void (*fp)(S) = f;
+ // CHECK: call i1 @llvm.type.test(i8* {{.*}}, metadata [[VOIDS1:![0-9]+]])
+ fp(s);
}
-// ITANIUM: define internal void @_ZN12_GLOBAL__N_11fEPNS_1SE({{.*}} !type [[TS:![0-9]+]]
-// MS: define internal void @"\01?f@?A@@YAXPEAUS@?A@@@Z"({{.*}} !type [[TS:![0-9]+]]
+// ITANIUM: define internal void @_ZN12_GLOBAL__N_11fENS_1SE({{.*}} !type [[TS1:![0-9]+]] !type [[TS2:![0-9]+]]
+// MS: define internal void @"\01?f@?A@@YAXUS@?A@@@Z"({{.*}} !type [[TS1:![0-9]+]] !type [[TS2:![0-9]+]]
-// CHECK: [[VOIDS]] = distinct !{}
-// CHECK: [[TS]] = !{i64 0, [[VOIDS]]}
+// CHECK: [[VOIDS1]] = distinct !{}
+// CHECK: [[TS1]] = !{i64 0, [[VOIDS1]]}
+// CHECK: [[TS2]] = !{i64 0, [[VOIDS2:![0-9]+]]}
+// CHECK: [[VOIDS2]] = distinct !{}
diff --git a/test/CodeGenCXX/cfi-vcall-no-trap.cpp b/test/CodeGenCXX/cfi-vcall-no-trap.cpp
new file mode 100644
index 0000000000..b7ef1426a9
--- /dev/null
+++ b/test/CodeGenCXX/cfi-vcall-no-trap.cpp
@@ -0,0 +1,15 @@
+// Only output llvm.assume(llvm.type.test()) if cfi-vcall is disabled and whole-program-vtables is enabled
+// RUN: %clang_cc1 -flto -fvisibility hidden -fsanitize=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CFI %s
+// RUN: %clang_cc1 -flto -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOCFI %s
+
+struct S1 {
+ virtual void f();
+};
+
+// CHECK: define{{.*}}s1f
+// CHECK: llvm.type.test
+// CFI-NOT: llvm.assume
+// NOCFI: llvm.assume
+void s1f(S1 *s1) {
+ s1->f();
+}
diff --git a/test/CodeGenCXX/clang-abi-compat.cpp b/test/CodeGenCXX/clang-abi-compat.cpp
new file mode 100644
index 0000000000..409c72108f
--- /dev/null
+++ b/test/CodeGenCXX/clang-abi-compat.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefix=PRE39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefix=PRE39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=V5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=V5 %s
+
+typedef __attribute__((vector_size(8))) long long v1xi64;
+void clang39(v1xi64) {}
+// PRE39: @_Z7clang39Dv1_x(i64
+// V39: @_Z7clang39Dv1_x(double
+
+struct A {
+ A(const A&) = default;
+ A(A&&);
+};
+void clang5(A) {}
+// PRE5: @_Z6clang51A()
+// V5: @_Z6clang51A(%{{.*}}*
diff --git a/test/CodeGenCXX/clang-sections-tentative.c b/test/CodeGenCXX/clang-sections-tentative.c
new file mode 100644
index 0000000000..e663079b9a
--- /dev/null
+++ b/test/CodeGenCXX/clang-sections-tentative.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -x c -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s
+
+// Test that section attributes are attached to C tentative definitions as per
+// '#pragma clang section' directives.
+
+#pragma clang section bss = ".bss.1"
+int x; // bss.1
+
+#pragma clang section bss = ""
+int x; // stays in .bss.1
+int y; // not assigned a section attribute
+int z; // not assigned a section attribute
+
+#pragma clang section bss = ".bss.2"
+int x; // stays in .bss.1
+int y; // .bss.2
+
+// Test the same for `const` declarations.
+#pragma clang section rodata = ".rodata.1"
+const int cx; // rodata.1
+
+#pragma clang section rodata = ""
+const int cx; // stays in .rodata.1
+const int cy; // not assigned a section attribute
+const int cz; // not assigned a rodata section attribute
+
+#pragma clang section rodata = ".rodata.2"
+const int cx; // stays in .rodata.1
+const int cy; // .rodata.2
+
+// CHECK: @x = global i32 0, align 4 #0
+// CHECK: @y = global i32 0, align 4 #1
+// CHECK: @z = common global i32 0, align 4
+// CHECK: @cx = constant i32 0, align 4 #2
+// CHECK: @cy = constant i32 0, align 4 #3
+// CHECK: @cz = constant i32 0, align 4 #1
+
+// CHECK: attributes #0 = { "bss-section"=".bss.1" }
+// CHECK: attributes #1 = { "bss-section"=".bss.2" }
+// CHECK: attributes #2 = { "bss-section"=".bss.2" "rodata-section"=".rodata.1" }
+// CHECK: attributes #3 = { "bss-section"=".bss.2" "rodata-section"=".rodata.2" }
diff --git a/test/CodeGenCXX/clang-sections.cpp b/test/CodeGenCXX/clang-sections.cpp
new file mode 100644
index 0000000000..4fe42eaf77
--- /dev/null
+++ b/test/CodeGenCXX/clang-sections.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s
+// Test that global variables, statics and functions are attached section-attributes
+// as per '#pragma clang section' directives.
+
+extern "C" {
+// test with names for each section
+#pragma clang section bss="my_bss.1" data="my_data.1" rodata="my_rodata.1"
+#pragma clang section text="my_text.1"
+int a; // my_bss.1
+int b = 1; // my_data.1
+int c[4]; // my_bss.1
+short d[5] = {0}; // my_bss.1
+short e[6] = {0, 0, 1}; // my_data.1
+extern const int f;
+const int f = 2; // my_rodata.1
+int foo(void) { // my_text.1
+ return b;
+}
+static int g[2]; // my_bss.1
+#pragma clang section bss=""
+int h; // default - .bss
+#pragma clang section data="" bss="my_bss.2" text="my_text.2"
+int i = 0; // my_bss.2
+extern const int j;
+const int j = 4; // default - .rodata
+int k; // my_bss.2
+extern int zoo(int *x, int *y);
+int goo(void) { // my_text.2
+ static int lstat_h; // my_bss.2
+ return zoo(g, &lstat_h);
+}
+#pragma clang section rodata="my_rodata.2" data="my_data.2"
+int l = 5; // my_data.2
+extern const int m;
+const int m = 6; // my_rodata.2
+#pragma clang section rodata="" data="" bss="" text=""
+int n; // default
+int o = 6; // default
+extern const int p;
+const int p = 7; // default
+int hoo(void) {
+ return b;
+}
+}
+//CHECK: @a = global i32 0, align 4 #0
+//CHECK: @b = global i32 1, align 4 #0
+//CHECK: @c = global [4 x i32] zeroinitializer, align 4 #0
+//CHECK: @d = global [5 x i16] zeroinitializer, align 2 #0
+//CHECK: @e = global [6 x i16] [i16 0, i16 0, i16 1, i16 0, i16 0, i16 0], align 2 #0
+//CHECK: @f = constant i32 2, align 4 #0
+
+//CHECK: @h = global i32 0, align 4 #1
+//CHECK: @i = global i32 0, align 4 #2
+//CHECK: @j = constant i32 4, align 4 #2
+//CHECK: @k = global i32 0, align 4 #2
+//CHECK: @_ZZ3gooE7lstat_h = internal global i32 0, align 4 #2
+//CHECK: @_ZL1g = internal global [2 x i32] zeroinitializer, align 4 #0
+
+//CHECK: @l = global i32 5, align 4 #3
+//CHECK: @m = constant i32 6, align 4 #3
+
+//CHECK: @n = global i32 0, align 4
+//CHECK: @o = global i32 6, align 4
+//CHECK: @p = constant i32 7, align 4
+
+//CHECK: define i32 @foo() #4 {
+//CHECK: define i32 @goo() #5 {
+//CHECK: declare i32 @zoo(i32*, i32*) #6
+//CHECK: define i32 @hoo() #7 {
+
+//CHECK: attributes #0 = { "bss-section"="my_bss.1" "data-section"="my_data.1" "rodata-section"="my_rodata.1" }
+//CHECK: attributes #1 = { "data-section"="my_data.1" "rodata-section"="my_rodata.1" }
+//CHECK: attributes #2 = { "bss-section"="my_bss.2" "rodata-section"="my_rodata.1" }
+//CHECK: attributes #3 = { "bss-section"="my_bss.2" "data-section"="my_data.2" "rodata-section"="my_rodata.2" }
+//CHECK: attributes #4 = { {{.*"implicit-section-name"="my_text.1".*}} }
+//CHECK: attributes #5 = { {{.*"implicit-section-name"="my_text.2".*}} }
+//CHECK-NOT: attributes #6 = { {{.*"implicit-section-name".*}} }
+//CHECK-NOT: attributes #7 = { {{.*"implicit-section-name".*}} }
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index 7bab11488a..67215ef48f 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefixes=X86,CHECK %s
+// RUN: %clang_cc1 -std=c++11 -triple amdgcn-amd-amdhsa-amdgiz -DNO_TLS -emit-llvm -o - %s | FileCheck -check-prefixes=AMD,CHECK %s
namespace std {
typedef decltype(sizeof(int)) size_t;
@@ -46,54 +47,72 @@ struct wantslist1 {
wantslist1(std::initializer_list<destroyme1>);
~wantslist1();
};
-
-// CHECK: @_ZGR15globalInitList1_ = internal constant [3 x i32] [i32 1, i32 2, i32 3]
-// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32], [3 x i32]* @_ZGR15globalInitList1_, i32 0, i32 0), i{{32|64}} 3 }
+// X86: @_ZGR15globalInitList1_ = internal constant [3 x i32] [i32 1, i32 2, i32 3]
+// X86: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32], [3 x i32]* @_ZGR15globalInitList1_, i32 0, i32 0), i{{32|64}} 3 }
+// AMD: @_ZGR15globalInitList1_ = internal addrspace(1) constant [3 x i32] [i32 1, i32 2, i32 3]
+// AMD: @globalInitList1 = addrspace(1) global %{{[^ ]+}} { i32* addrspacecast (i32 addrspace(1)* getelementptr inbounds ([3 x i32], [3 x i32] addrspace(1)* @_ZGR15globalInitList1_, i32 0, i32 0) to i32*), i{{32|64}} 3 }
std::initializer_list<int> globalInitList1 = {1, 2, 3};
+#ifndef NO_TLS
namespace thread_local_global_array {
- // FIXME: We should be able to constant-evaluate this even though the
- // initializer is not a constant expression (pointers to thread_local
- // objects aren't really a problem).
- //
- // CHECK: @_ZN25thread_local_global_array1xE = thread_local global
- // CHECK: @_ZGRN25thread_local_global_array1xE_ = internal thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
- std::initializer_list<int> thread_local x = { 1, 2, 3, 4 };
+// FIXME: We should be able to constant-evaluate this even though the
+// initializer is not a constant expression (pointers to thread_local
+// objects aren't really a problem).
+//
+// X86: @_ZN25thread_local_global_array1xE = thread_local global
+// X86: @_ZGRN25thread_local_global_array1xE_ = internal thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
+std::initializer_list<int> thread_local x = {1, 2, 3, 4};
}
-
-// CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
-// CHECK: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
-
-// CHECK: @_ZN15partly_constant1kE = global i32 0, align 4
-// CHECK: @_ZN15partly_constant2ilE = global {{.*}} null, align 8
-// CHECK: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8
-// CHECK: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8
-// CHECK: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4
-// CHECK: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4
-// CHECK: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
-
-// CHECK: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4
-// CHECK: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4
+#endif
+
+// X86: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
+// X86: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
+// AMD: @globalInitList2 = addrspace(1) global %{{[^ ]+}} zeroinitializer
+// AMD: @_ZGR15globalInitList2_ = internal addrspace(1) global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
+
+// X86: @_ZN15partly_constant1kE = global i32 0, align 4
+// X86: @_ZN15partly_constant2ilE = global {{.*}} null, align 8
+// X86: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8
+// X86: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8
+// X86: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4
+// X86: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4
+// X86: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
+// AMD: @_ZN15partly_constant1kE = addrspace(1) global i32 0, align 4
+// AMD: @_ZN15partly_constant2ilE = addrspace(2) global {{.*}} null, align 8
+// AMD: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global {{.*}} zeroinitializer, align 8
+// AMD: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global [3 x {{.*}}] zeroinitializer, align 8
+// AMD: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) constant [3 x i32] [i32 1, i32 2, i32 3], align 4
+// AMD: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global [2 x i32] zeroinitializer, align 4
+// AMD: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
+
+// X86: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4
+// X86: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4
+// AMD: @[[REFTMP1:.*]] = private addrspace(2) constant [2 x i32] [i32 42, i32 43], align 4
+// AMD: @[[REFTMP2:.*]] = private addrspace(2) constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4
// CHECK: appending global
-
// thread_local initializer:
-// CHECK-LABEL: define internal void
-// CHECK: store i32* getelementptr inbounds ([4 x i32], [4 x i32]* @_ZGRN25thread_local_global_array1xE_, i64 0, i64 0),
-// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8
-// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8
-
-
-// CHECK-LABEL: define internal void
-// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 0
-// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 1
-// CHECK: __cxa_atexit
-// CHECK: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i64 0, i64 0),
-// CHECK: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 0), align 8
-// CHECK: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 1), align 8
-// CHECK: call void @_ZN10destroyme1D1Ev
+// X86-LABEL: define internal void @__cxx_global_var_init
+// X86: store i32* getelementptr inbounds ([4 x i32], [4 x i32]* @_ZGRN25thread_local_global_array1xE_, i64 0, i64 0),
+// X86: i32** getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8
+// X86: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8
+
+// CHECK-LABEL: define internal void @__cxx_global_var_init
+// X86: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 0
+// X86: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 1
+// AMD: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i{{32|64}} 0, i{{32|64}} 0
+// AMD: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i{{32|64}} 0, i{{32|64}} 1
+// CHECK: call i32 @__cxa_atexit
+// X86: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i64 0, i64 0),
+// X86: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 0), align 8
+// X86: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 1), align 8
+// AMD: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i64 0, i64 0),
+// AMD: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* addrspacecast ({{[^@]+}} @globalInitList2 {{[^)]+}}), i32 0, i32 0), align 8
+// AMD: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* addrspacecast ({{[^@]+}} @globalInitList2 {{[^)]+}}), i32 0, i32 1), align 8
// CHECK: call void @_ZN10destroyme1D1Ev
+// CHECK-NEXT: call void @_ZN10destroyme1D1Ev
+// CHECK-NEXT: ret void
std::initializer_list<witharg1> globalInitList2 = {
witharg1(destroyme1()), witharg1(destroyme1())
};
@@ -101,7 +120,9 @@ std::initializer_list<witharg1> globalInitList2 = {
void fn1(int i) {
// CHECK-LABEL: define void @_Z3fn1i
// temporary array
- // CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
+ // X86: [[array:%[^ ]+]] = alloca [3 x i32]
+ // AMD: [[alloca:%[^ ]+]] = alloca [3 x i32], align 4, addrspace(5)
+ // AMD: [[array:%[^ ]+]] = addrspacecast [3 x i32] addrspace(5)* [[alloca]] to [3 x i32]*
// CHECK: getelementptr inbounds [3 x i32], [3 x i32]* [[array]], i{{32|64}} 0
// CHECK-NEXT: store i32 1, i32*
// CHECK-NEXT: getelementptr
@@ -175,7 +196,6 @@ void fn6() {
destroyme2 dm2;
// CHECK: call void @_ZN10destroyme2D1Ev
}
-
void fn7() {
// CHECK-LABEL: define void @_Z3fn7v
// temps should be destroyed before dm2
@@ -366,37 +386,36 @@ namespace partly_constant {
std::initializer_list<std::initializer_list<int>> &&il = { { 1, 2, 3 }, { 4, k }, { 5, 6, 7, 8 } };
// First init list.
// CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]],
- // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_FIRST]], i64 0, i64 0),
- // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 0)
- // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 1)
+ // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_FIRST]]{{.*}}, i64 0, i64 0),
+ // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0, i32 0)
+ // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0, i32 1)
// CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]],
//
// Second init list array (non-constant).
- // CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0)
- // CHECK: load i32, i32* @_ZN15partly_constant1kE
- // CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 1)
+ // CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 0)
+ // CHECK: load i32, i32* {{.*}}@_ZN15partly_constant1kE
+ // CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 1)
//
// Second init list.
- // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0),
- // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 0)
- // CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 1)
+ // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 0),
+ // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 1, i32 0)
+ // CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 1, i32 1)
//
// Third init list.
// CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],
- // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_THIRD]], i64 0, i64 0),
- // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 2, i32 0)
- // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZGRN15partly_constant2ilE4_, i64 0, i64 2, i32 1)
+ // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_THIRD]]{{.*}}, i64 0, i64 0),
+ // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 2, i32 0)
+ // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@_ZGRN15partly_constant2ilE4_{{.*}}, i64 0, i64 2, i32 1)
// CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],
//
// Outer init list.
- // CHECK: store {{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0),
- // CHECK: {{.*}}** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 0)
- // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 1)
+ // CHECK: store {{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0),
+ // CHECK: {{.*}}** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, i32 0, i32 0)
+ // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, i32 0, i32 1)
//
// 'il' reference.
- // CHECK: store {{.*}}* @[[PARTLY_CONSTANT_OUTER]], {{.*}}** @_ZN15partly_constant2ilE, align 8
+ // CHECK: store {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, {{.*}}** {{.*}}@_ZN15partly_constant2ilE{{.*}}, align 8
}
-
namespace nested {
struct A { A(); ~A(); };
struct B { const A &a; ~B(); };
@@ -463,7 +482,7 @@ namespace PR20445 {
template<int x> void f() { new MyClass({42, 43}); }
template void f<0>();
// CHECK-LABEL: define {{.*}} @_ZN7PR204451fILi0EEEvv(
- // CHECK: store i32* getelementptr inbounds ([2 x i32], [2 x i32]* @[[REFTMP1]], i64 0, i64 0)
+ // CHECK: store i32* getelementptr inbounds ([2 x i32], [2 x i32]* {{.*}}@[[REFTMP1]]{{.*}}, i64 0, i64 0)
// CHECK: call void @_ZN7PR204456vectorC1ESt16initializer_listIiE(
// CHECK: call void @_ZN7PR204457MyClassC1ERKNS_6vectorE(
}
@@ -476,9 +495,9 @@ namespace ConstExpr {
};
void f(std::initializer_list<C>);
void g() {
-// CHECK-LABEL: _ZN9ConstExpr1gEv
-// CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"], [3 x %"class.ConstExpr::C"]* @[[REFTMP2]], i64 0, i64 0)
-// CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE
+ // CHECK-LABEL: _ZN9ConstExpr1gEv
+ // CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"], [3 x %"class.ConstExpr::C"]* {{.*}}@[[REFTMP2]]{{.*}}, i64 0, i64 0)
+ // CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE
f({C(1), C(2), C(3)});
}
}
@@ -498,11 +517,13 @@ namespace B19773010 {
void f1() {
// CHECK-LABEL: @_ZN9B197730102f1Ev
testcase a{{"", ENUM_CONSTANT}};
- // CHECK: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8
+ // X86: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8
+ // AMD: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* addrspacecast{{.*}} bitcast ([1 x { i8*, i32 }] addrspace(2)* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"] addrspace(2)*){{.*}}, i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8
}
void f2() {
// CHECK-LABEL: @_ZN9B197730102f2Ev
- // CHECK: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* @_ZZN9B197730102f2EvE1p, i64 0, i64 1, i32 0), align 16
+ // X86: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* @_ZZN9B197730102f2EvE1p, i64 0, i64 1, i32 0), align 16
+ // AMD: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* addrspacecast{{.*}} bitcast ([1 x { i8*, i32 }] addrspace(1)* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"] addrspace(1)*){{.*}}, i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* addrspacecast{{.*}}@_ZZN9B197730102f2EvE1p{{.*}}, i64 0, i64 1, i32 0), align 8
static std::initializer_list<pair<const char *, E>> a, p[2] =
{a, {{"", ENUM_CONSTANT}}};
}
diff --git a/test/CodeGenCXX/cxx11-extern-constexpr.cpp b/test/CodeGenCXX/cxx11-extern-constexpr.cpp
new file mode 100644
index 0000000000..6c520038e9
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-extern-constexpr.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK --check-prefix=CXX11
+// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK --check-prefix=CXX17
+
+struct A {
+ static const int Foo = 123;
+};
+// CHECK: @_ZN1A3FooE = constant i32 123, align 4
+const int *p = &A::Foo; // emit available_externally
+const int A::Foo; // convert to full definition
+
+struct PODWithInit {
+ int g = 42;
+ char h = 43;
+};
+struct CreatePOD {
+ // Deferred initialization of the structure here requires changing
+ // the type of the global variable: the initializer list does not include
+ // the tail padding.
+ // CXX11: @_ZN9CreatePOD3podE = available_externally constant { i32, i8 } { i32 42, i8 43 },
+ static constexpr PODWithInit pod{};
+};
+const int *p_pod = &CreatePOD::pod.g;
+
+struct Bar {
+ int b;
+};
+
+struct MutableBar {
+ mutable int b;
+};
+
+struct Foo {
+ // CXX11: @_ZN3Foo21ConstexprStaticMemberE = available_externally constant i32 42,
+ // CXX17: @_ZN3Foo21ConstexprStaticMemberE = linkonce_odr constant i32 42,
+ static constexpr int ConstexprStaticMember = 42;
+ // CHECK: @_ZN3Foo17ConstStaticMemberE = available_externally constant i32 43,
+ static const int ConstStaticMember = 43;
+
+ // CXX11: @_ZN3Foo23ConstStaticStructMemberE = available_externally constant %struct.Bar { i32 44 },
+ // CXX17: @_ZN3Foo23ConstStaticStructMemberE = linkonce_odr constant %struct.Bar { i32 44 },
+ static constexpr Bar ConstStaticStructMember = {44};
+
+ // CXX11: @_ZN3Foo34ConstexprStaticMutableStructMemberE = external global %struct.MutableBar,
+ // CXX17: @_ZN3Foo34ConstexprStaticMutableStructMemberE = linkonce_odr global %struct.MutableBar { i32 45 },
+ static constexpr MutableBar ConstexprStaticMutableStructMember = {45};
+};
+// CHECK: @_ZL15ConstStaticexpr = internal constant i32 46,
+static constexpr int ConstStaticexpr = 46;
+// CHECK: @_ZL9ConstExpr = internal constant i32 46, align 4
+static const int ConstExpr = 46;
+
+// CHECK: @_ZL21ConstexprStaticStruct = internal constant %struct.Bar { i32 47 },
+static constexpr Bar ConstexprStaticStruct = {47};
+
+// CHECK: @_ZL28ConstexprStaticMutableStruct = internal global %struct.MutableBar { i32 48 },
+static constexpr MutableBar ConstexprStaticMutableStruct = {48};
+
+void use(const int &);
+void foo() {
+ use(Foo::ConstexprStaticMember);
+ use(Foo::ConstStaticMember);
+ use(Foo::ConstStaticStructMember.b);
+ use(Foo::ConstexprStaticMutableStructMember.b);
+ use(ConstStaticexpr);
+ use(ConstExpr);
+ use(ConstexprStaticStruct.b);
+ use(ConstexprStaticMutableStruct.b);
+}
diff --git a/test/CodeGenCXX/cxx1z-class-deduction.cpp b/test/CodeGenCXX/cxx1z-class-deduction.cpp
new file mode 100644
index 0000000000..0761f2129b
--- /dev/null
+++ b/test/CodeGenCXX/cxx1z-class-deduction.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++1z %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+
+template<typename T> struct A {
+ A(T = 0);
+ A(void*);
+};
+
+template<typename T> A(T*) -> A<long>;
+A() -> A<int>;
+
+// CHECK-LABEL: @_Z1fPi(
+void f(int *p) {
+ // CHECK: @_ZN1AIiEC
+ A a{};
+
+ // CHECK: @_ZN1AIlEC
+ A b = p;
+
+ // CHECK: @_ZN1AIxEC
+ A c = 123LL;
+}
diff --git a/test/CodeGenCXX/cxx1z-copy-omission.cpp b/test/CodeGenCXX/cxx1z-copy-omission.cpp
index 234e4b1258..b33a218081 100644
--- a/test/CodeGenCXX/cxx1z-copy-omission.cpp
+++ b/test/CodeGenCXX/cxx1z-copy-omission.cpp
@@ -6,6 +6,8 @@ struct A {
A(const A&);
~A();
+ operator bool();
+
int arr[10];
};
@@ -79,3 +81,27 @@ void i() {
// CHECK-LABEL: }
}
+
+// CHECK-LABEL: define {{.*}} @_Z1jv(
+void j() {
+ // CHECK: alloca %{{.*}}*
+ // CHECK: %[[OUTERTEMP:.*]] = alloca %{{.*}}
+ // CHECK: %[[INNERTEMP:.*]] = alloca %{{.*}}
+ // CHECK: call void @_ZN1AC1Ei(%{{.*}} %[[INNERTEMP]], i32 1)
+ // CHECK: call zeroext i1 @_ZN1AcvbEv(%{{.*}} %[[INNERTEMP]])
+ // CHECK: br i1
+ //
+ // CHECK: call void @_ZN1AC1EOS_(%{{.*}} %[[OUTERTEMP]], %{{.*}} %[[INNERTEMP]])
+ // CHECK: br label
+ //
+ // CHECK: call void @_ZN1AC1Ei(%{{.*}} %[[OUTERTEMP]], i32 2)
+ // CHECK: br label
+ //
+ // CHECK: call void @_ZN1AD1Ev(%{{.*}} %[[INNERTEMP]])
+ A &&a = A(1) ?: A(2);
+
+ // CHECK: call void @_Z1iv()
+ i();
+
+ // CHECK: call void @_ZN1AD1Ev(%{{.*}} %[[OUTERTEMP]])
+}
diff --git a/test/CodeGenCXX/cxx1z-inline-variables.cpp b/test/CodeGenCXX/cxx1z-inline-variables.cpp
index 183709373d..0d2ec92a7a 100644
--- a/test/CodeGenCXX/cxx1z-inline-variables.cpp
+++ b/test/CodeGenCXX/cxx1z-inline-variables.cpp
@@ -31,18 +31,28 @@ struct compat {
static constexpr int b = 2;
static constexpr int c = 3;
static inline constexpr int d = 4;
+ static const int e = 5;
+ static const int f = 6;
+ static const int g = 7;
};
const int &compat_use_before_redecl = compat::b;
const int compat::a;
const int compat::b;
const int compat::c;
const int compat::d;
+const int compat::e;
+constexpr int compat::f;
+constexpr inline int compat::g;
const int &compat_use_after_redecl1 = compat::c;
const int &compat_use_after_redecl2 = compat::d;
-// CHECK: @_ZN6compat1bE = weak_odr constant i32 2
-// CHECK: @_ZN6compat1aE = weak_odr constant i32 1
-// CHECK: @_ZN6compat1cE = weak_odr constant i32 3
-// CHECK: @_ZN6compat1dE = linkonce_odr constant i32 4
+const int &compat_use_after_redecl3 = compat::g;
+// CHECK-DAG: @_ZN6compat1bE = weak_odr constant i32 2
+// CHECK-DAG: @_ZN6compat1aE = weak_odr constant i32 1
+// CHECK-DAG: @_ZN6compat1cE = weak_odr constant i32 3
+// CHECK-DAG: @_ZN6compat1dE = linkonce_odr constant i32 4
+// CHECK-DAG: @_ZN6compat1eE = constant i32 5
+// CHECK-DAG: @_ZN6compat1fE = weak_odr constant i32 6
+// CHECK-DAG: @_ZN6compat1gE = linkonce_odr constant i32 7
template<typename T> struct X {
static int a;
diff --git a/test/CodeGenCXX/cxx2a-destroying-delete.cpp b/test/CodeGenCXX/cxx2a-destroying-delete.cpp
new file mode 100644
index 0000000000..2e4d40715e
--- /dev/null
+++ b/test/CodeGenCXX/cxx2a-destroying-delete.cpp
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -std=c++2a -emit-llvm %s -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ITANIUM
+// RUN: %clang_cc1 -std=c++2a -emit-llvm %s -triple x86_64-windows -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MSABI
+
+namespace std {
+ using size_t = decltype(sizeof(0));
+ enum class align_val_t : size_t;
+ struct destroying_delete_t {};
+}
+
+struct A {
+ void *data;
+ ~A();
+ void operator delete(A*, std::destroying_delete_t);
+};
+void delete_A(A *a) { delete a; }
+// CHECK-LABEL: define {{.*}}delete_A
+// CHECK: %[[a:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[a]], null
+// CHECK: br i1
+//
+// Ensure that we call the destroying delete and not the destructor.
+// CHECK-NOT: call
+// CHECK-ITANIUM: call void @_ZN1AdlEPS_St19destroying_delete_t(%{{.*}}* %[[a]])
+// CHECK-MSABI: call void @"\01??3A@@SAXPEAU0@Udestroying_delete_t@std@@@Z"(%{{.*}}* %[[a]], i8
+// CHECK-NOT: call
+// CHECK: }
+
+struct B {
+ virtual ~B();
+ void operator delete(B*, std::destroying_delete_t);
+};
+void delete_B(B *b) { delete b; }
+// CHECK-LABEL: define {{.*}}delete_B
+// CHECK: %[[b:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[b]], null
+// CHECK: br i1
+//
+// Ensure that we call the virtual destructor and not the operator delete.
+// CHECK-NOT: call
+// CHECK: %[[VTABLE:.*]] = load
+// CHECK: %[[DTOR:.*]] = load
+// CHECK: call {{void|i8\*}} %[[DTOR]](%{{.*}}* %[[b]]
+// CHECK-MSABI-SAME: , i32 1)
+// CHECK-NOT: call
+// CHECK: }
+
+struct Padding {
+ virtual void f();
+};
+
+struct C : Padding, A {};
+void delete_C(C *c) { delete c; }
+// Check that we perform a derived-to-base conversion on the parameter to 'operator delete'.
+// CHECK-LABEL: define {{.*}}delete_C
+// CHECK: %[[c:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[c]], null
+// CHECK: br i1
+//
+// CHECK: %[[base:.*]] = getelementptr {{.*}}, i64 8
+// CHECK: %[[castbase:.*]] = bitcast {{.*}} %[[base]]
+//
+// CHECK: %[[a:.*]] = phi {{.*}} %[[castbase]]
+// CHECK: icmp eq %{{.*}} %[[a]], null
+// CHECK: br i1
+//
+// CHECK-NOT: call
+// CHECK-ITANIUM: call void @_ZN1AdlEPS_St19destroying_delete_t(%{{.*}}* %[[a]])
+// CHECK-MSABI: call void @"\01??3A@@SAXPEAU0@Udestroying_delete_t@std@@@Z"(%{{.*}}* %[[a]], i8
+// CHECK-NOT: call
+// CHECK: }
+
+struct VDel { virtual ~VDel(); };
+struct D : Padding, VDel, B {};
+void delete_D(D *d) { delete d; }
+// CHECK-LABEL: define {{.*}}delete_D
+// CHECK: %[[d:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[d]], null
+// CHECK: br i1
+//
+// CHECK-NOT: call
+// CHECK: %[[VTABLE:.*]] = load
+// CHECK: %[[DTOR:.*]] = load
+//
+// For MS, we don't add a new vtable slot to the primary vtable for the virtual
+// destructor. Instead we cast to the VDel base class.
+// CHECK-MSABI: bitcast {{.*}} %[[d]]
+// CHECK-MSABI-NEXT: getelementptr {{.*}}, i64 8
+// CHECK-MSABI-NEXT: %[[d:.*]] = bitcast i8*
+//
+// CHECK: call {{void|i8\*}} %[[DTOR]](%{{.*}}* %[[d]]
+// CHECK-MSABI-SAME: , i32 1)
+// CHECK-NOT: call
+// CHECK: }
+
+struct E { void *data; };
+struct F { void operator delete(F *, std::destroying_delete_t, std::size_t, std::align_val_t); void *data; };
+struct alignas(16) G : E, F { void *data; };
+
+void delete_G(G *g) { delete g; }
+// CHECK-LABEL: define {{.*}}delete_G
+// CHECK-NOT: call
+// CHECK-ITANIUM: call void @_ZN1FdlEPS_St19destroying_delete_tmSt11align_val_t(%{{.*}}* %[[a]], i64 32, i64 16)
+// CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"(%{{.*}}* %[[a]], i8 {{[^,]*}}, i64 32, i64 16)
+// CHECK-NOT: call
+// CHECK: }
+
+void call_in_dtor();
+
+struct H : G { virtual ~H(); } h;
+H::~H() { call_in_dtor(); }
+// CHECK-ITANIUM-LABEL: define void @_ZN1HD0Ev(
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: getelementptr {{.*}}, i64 24
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: call void @_ZN1FdlEPS_St19destroying_delete_tmSt11align_val_t({{.*}}, i64 48, i64 16)
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: }
+
+// CHECK-MSABI: define {{.*}} @"\01??_GH@@UEAAPEAXI@Z"(
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: load i32
+// CHECK-MSABI: icmp eq i32 {{.*}}, 0
+// CHECK-MSABI: br i1
+//
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: getelementptr {{.*}}, i64 24
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 48, i64 16)
+// CHECK-MSABI: br label %[[RETURN:.*]]
+//
+// CHECK-MSABI: call void @"\01??_DH@@QEAAXXZ"(
+// CHECK-MSABI: br label %[[RETURN]]
+//
+// CHECK-MSABI: }
+
+struct I : H { virtual ~I(); alignas(32) char buffer[32]; } i;
+I::~I() { call_in_dtor(); }
+// CHECK-ITANIUM-LABEL: define void @_ZN1ID0Ev(
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: getelementptr {{.*}}, i64 24
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: call void @_ZN1FdlEPS_St19destroying_delete_tmSt11align_val_t({{.*}}, i64 96, i64 32)
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: }
+
+// CHECK-MSABI: define {{.*}} @"\01??_GI@@UEAAPEAXI@Z"(
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: load i32
+// CHECK-MSABI: icmp eq i32 {{.*}}, 0
+// CHECK-MSABI: br i1
+//
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: getelementptr {{.*}}, i64 24
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 96, i64 32)
+// CHECK-MSABI: br label %[[RETURN:.*]]
+//
+// CHECK-MSABI: call void @"\01??_DI@@QEAAXXZ"(
+// CHECK-MSABI: br label %[[RETURN]]
+//
+// CHECK-MSABI: }
diff --git a/test/CodeGenCXX/debug-info-anon-namespace.cpp b/test/CodeGenCXX/debug-info-anon-namespace.cpp
index 79298deaf8..56c8528abd 100644
--- a/test/CodeGenCXX/debug-info-anon-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-anon-namespace.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-scei-ps4 -O0 %s -o - | FileCheck --check-prefix=PS4 %s
-// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -triple x86_64-unknown-linux-gnu -O0 %s -o - | FileCheck --check-prefix=NON-PS4 %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -dwarf-explicit-import -O0 %s -o - | FileCheck --check-prefix=IMPORT %s
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -O0 %s -o - | FileCheck --check-prefix=NOIMPORT %s
namespace
{
@@ -17,11 +17,9 @@ namespace
int *b1 = &a1;
int *b2 = &a2;
-
-// PS4: [[NS:![0-9]+]] = !DINamespace
-// PS4: [[CU:![0-9]+]] = distinct !DICompileUnit
-// PS4: [[NS2:![0-9]+]] = !DINamespace
-// PS4: !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[NS]])
-// PS4: !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[NS]], entity: [[NS2]], line: {{[0-9]+}})
-// NON-PS4-NOT: !DIImportedEntity
-
+// IMPORT: [[NS:![0-9]+]] = !DINamespace
+// IMPORT: [[CU:![0-9]+]] = distinct !DICompileUnit
+// IMPORT: [[NS2:![0-9]+]] = !DINamespace
+// IMPORT: !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[NS]], file: {{![0-9]+}})
+// IMPORT: !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[NS]], entity: [[NS2]], file: {{![0-9]+}}, line: {{[0-9]+}})
+// NOIMPORT-NOT: !DIImportedEntity
diff --git a/test/CodeGenCXX/debug-info-codeview-display-name.cpp b/test/CodeGenCXX/debug-info-codeview-display-name.cpp
index b1b5a1e9ac..17049d506f 100644
--- a/test/CodeGenCXX/debug-info-codeview-display-name.cpp
+++ b/test/CodeGenCXX/debug-info-codeview-display-name.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fblocks -debug-info-kind=limited -gcodeview -emit-llvm %s \
// RUN: -o - -triple=x86_64-pc-win32 -std=c++98 | \
-// RUN: grep 'DISubprogram' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | \
+// RUN: grep 'DISubprogram\|DICompositeType' | sed -e 's/.*name: "\([^"]*\)".*/"\1"/' | \
// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=UNQUAL
// RUN: %clang_cc1 -fblocks -debug-info-kind=line-tables-only -gcodeview -emit-llvm %s \
// RUN: -o - -triple=x86_64-pc-win32 -std=c++98 | \
@@ -91,3 +91,8 @@ void fn_tmpl() {}
template void fn_tmpl<int, freefunc>();
// CHECK-DAG: "fn_tmpl<int,&freefunc>"
+
+template <typename A, typename B, typename C> struct ClassTemplate { A a; B b; C c; };
+ClassTemplate<char, short, ClassTemplate<int, int, int> > f;
+// This will only show up in normal debug builds.
+// UNQUAL-DAG: "ClassTemplate<char,short,ClassTemplate<int,int,int> >"
diff --git a/test/CodeGenCXX/debug-info-codeview-nested-types.cpp b/test/CodeGenCXX/debug-info-codeview-nested-types.cpp
new file mode 100644
index 0000000000..7c8f78e7a0
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-codeview-nested-types.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-pc-windows-msvc -debug-info-kind=limited -gcodeview -emit-llvm -o - | FileCheck %s
+
+struct HasNested {
+ enum InnerEnum { _BUF_SIZE = 1 };
+ typedef int InnerTypedef;
+ enum { InnerEnumerator = 2 };
+ struct InnerStruct { };
+};
+HasNested f;
+
+// CHECK: ![[INNERENUM:[0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "InnerEnum", {{.*}})
+// CHECK: ![[HASNESTED:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "HasNested",
+// CHECK-SAME: elements: ![[MEMBERS:[0-9]+]],
+//
+// CHECK: ![[MEMBERS]] = !{![[INNERENUM]], ![[INNERTYPEDEF:[0-9]+]], ![[UNNAMEDENUM:[0-9]+]], ![[INNERSTRUCT:[0-9]+]]}
+//
+// CHECK: ![[INNERTYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "InnerTypedef", scope: ![[HASNESTED]]{{.*}})
+//
+// CHECK: ![[UNNAMEDENUM]] = !DICompositeType(tag: DW_TAG_enumeration_type, scope: ![[HASNESTED]],
+// CHECK-SAME: elements: ![[UNNAMEDMEMBERS:[0-9]+]],
+// CHECK: ![[UNNAMEDMEMBERS]] = !{![[INNERENUMERATOR:[0-9]+]]}
+// CHECK: ![[INNERENUMERATOR]] = !DIEnumerator(name: "InnerEnumerator", value: 2)
+//
+// CHECK: ![[INNERSTRUCT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "InnerStruct"
+// CHECK-SAME: flags: DIFlagFwdDecl
diff --git a/test/CodeGenCXX/debug-info-fwd-template-param.cpp b/test/CodeGenCXX/debug-info-fwd-template-param.cpp
new file mode 100644
index 0000000000..2983f84274
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-fwd-template-param.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -triple=%itanium_abi_triple -debug-info-kind=limited -debug-forward-template-params -emit-llvm -o - | FileCheck --check-prefix=CHILD %s
+// RUN: %clang_cc1 %s -triple=%itanium_abi_triple -debug-info-kind=limited -emit-llvm -o - | FileCheck --check-prefix=NONE %s
+// A DWARF forward declaration of a template instantiation should have template
+// parameter children (if we ask for them).
+
+template<typename T> class A;
+A<int> *p;
+
+// CHILD: !DICompositeType(tag: DW_TAG_class_type, name: "A<int>"
+// CHILD-SAME: flags: DIFlagFwdDecl
+// CHILD-SAME: templateParams: [[PARAM_LIST:![0-9]*]]
+// CHILD: [[PARAM_LIST]] = !{[[PARAM:![0-9]*]]}
+// CHILD: [[PARAM]] = !DITemplateTypeParameter(name: "T",
+// CHILD-SAME: type: [[BTYPE:![0-9]*]]
+// CHILD: [[BTYPE]] = !DIBasicType(name: "int"
+
+// NONE: !DICompositeType(tag: DW_TAG_class_type, name: "A<int>"
+// NONE-SAME: flags: DIFlagFwdDecl
+// NONE-NOT: templateParams:
+// NONE-SAME: )
diff --git a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
index 4c61cf78cc..7b57c08a10 100644
--- a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
+++ b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 %s -debug-info-kind=limited -triple %itanium_abi_triple -fno-use-cxa-atexit -S -emit-llvm -o - \
+// RUN: %clang_cc1 %s -debug-info-kind=limited -triple %itanium_abi_triple -fno-use-cxa-atexit -S -disable-O0-optnone -emit-llvm -o - \
// RUN: | FileCheck %s --check-prefix=CHECK-NOKEXT
-// RUN: %clang_cc1 %s -debug-info-kind=limited -triple %itanium_abi_triple -fno-use-cxa-atexit -fapple-kext -S -emit-llvm -o - \
+// RUN: %clang_cc1 %s -debug-info-kind=limited -triple %itanium_abi_triple -fno-use-cxa-atexit -fapple-kext -S -disable-O0-optnone -emit-llvm -o - \
// RUN: | FileCheck %s --check-prefix=CHECK-KEXT
class A {
diff --git a/test/CodeGenCXX/debug-info-inheriting-constructor.cpp b/test/CodeGenCXX/debug-info-inheriting-constructor.cpp
index e3708e2080..8e47a0da6d 100644
--- a/test/CodeGenCXX/debug-info-inheriting-constructor.cpp
+++ b/test/CodeGenCXX/debug-info-inheriting-constructor.cpp
@@ -13,7 +13,7 @@ A::A(int i, ...) {}
// 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-SAME: metadata ![[THIS:[0-9]+]], metadata !DIExpression()), !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"
diff --git a/test/CodeGenCXX/debug-info-inlined.cpp b/test/CodeGenCXX/debug-info-inlined.cpp
new file mode 100644
index 0000000000..53e2cc9289
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-inlined.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-windows-msvc19.0.24213 -gcodeview -debug-info-kind=limited -std=c++14 %s -o - | FileCheck %s
+// PR33997.
+struct WithDtor {
+ ~WithDtor();
+};
+struct Base {
+ Base(WithDtor);
+};
+class Forward : Base {
+ using Base::Base;
+};
+class A : Forward {
+ A();
+};
+class B : Forward {
+ B();
+};
+A::A() : Forward(WithDtor()) {}
+
+B::B() : Forward(WithDtor()) {}
+
+// CHECK: define{{.*}}A
+// CHECK-NOT: {{ ret }}
+// CHECK: store %class.Forward* %
+// CHECK-SAME: %class.Forward** %
+// CHECK-SAME: !dbg ![[INL:[0-9]+]]
+
+// CHECK: ![[INL]] = !DILocation(line: 10, scope: ![[SP:[0-9]+]], inlinedAt:
+// CHECK: ![[SP]] = distinct !DISubprogram(name: "Base", {{.*}}isDefinition: true
diff --git a/test/CodeGenCXX/debug-info-method.cpp b/test/CodeGenCXX/debug-info-method.cpp
index e0f9a284f2..af7103e575 100644
--- a/test/CodeGenCXX/debug-info-method.cpp
+++ b/test/CodeGenCXX/debug-info-method.cpp
@@ -20,6 +20,7 @@ union {
class A {
protected:
void foo(int, A, decltype(u));
+ void bar();
};
void A::foo(int, A, decltype(u)) {
@@ -29,3 +30,5 @@ A a;
int A::*x = 0;
int (A::*y)(int) = 0;
+
+void A::bar() { foo(0, *this, u); }
diff --git a/test/CodeGenCXX/debug-info-ms-abi.cpp b/test/CodeGenCXX/debug-info-ms-abi.cpp
index 1bf8bab5f4..e83d7e9423 100644
--- a/test/CodeGenCXX/debug-info-ms-abi.cpp
+++ b/test/CodeGenCXX/debug-info-ms-abi.cpp
@@ -6,6 +6,7 @@ struct Foo {
virtual void f();
virtual void g();
virtual void h();
+ static void i(int, int);
struct Nested {};
};
Foo f;
@@ -18,7 +19,7 @@ Foo::Nested n;
// CHECK-SAME: elements: ![[elements:[0-9]+]]
// CHECK-SAME: identifier: ".?AUFoo@@"
-// CHECK: ![[elements]] = !{![[vshape:[0-9]+]], ![[vptr:[0-9]+]], ![[Nested]], ![[f:[0-9]+]], ![[g:[0-9]+]], ![[h:[0-9]+]]}
+// CHECK: ![[elements]] = !{![[vshape:[0-9]+]], ![[vptr:[0-9]+]], ![[Nested]], ![[f:[0-9]+]], ![[g:[0-9]+]], ![[h:[0-9]+]], ![[i:[0-9]+]]}
// CHECK: ![[vshape]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: null, size: 96)
@@ -38,3 +39,9 @@ Foo::Nested n;
// CHECK: ![[h]] = !DISubprogram(name: "h",
// CHECK-SAME: containingType: ![[Foo]], virtuality: DW_VIRTUALITY_virtual, virtualIndex: 2,
// CHECK-SAME: flags: DIFlagPrototyped | DIFlagIntroducedVirtual,
+
+// CHECK: ![[i]] = !DISubprogram(name: "i",
+// CHECK-SAME: flags: DIFlagPrototyped | DIFlagStaticMember
+// CHECK-NEXT: ![[dummy:[0-9]+]] = !DISubroutineType(types: ![[Signature:[0-9]+]])
+// CHECK: ![[Signature]] = !{null, ![[BasicInt:[0-9]+]], ![[BasicInt]]}
+// CHECK: ![[BasicInt]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index c75c40766a..296c99efc8 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -53,35 +53,45 @@ inline namespace I {
int var_i;
}
}
-void B::func_fwd() {}
+namespace {
+int anonymous;
+}
+void B::func_fwd() {
+ anonymous = 0;
+}
+
+namespace C {
+ void c();
+}
+void C::c() {}
// This should work even if 'i' and 'func' were declarations & not definitions,
// but it doesn't yet.
// CHECK: [[I:![0-9]+]] = distinct !DIGlobalVariable(name: "i",{{.*}} scope: [[NS:![0-9]+]],
-// CHECK: [[NS]] = !DINamespace(name: "B", scope: [[CTXT:![0-9]+]], file: [[FOOCPP:![0-9]+]], line: 1)
-// CHECK: [[FOOCPP]] = !DIFile(filename: "foo.cpp"
-// CHECK: [[CTXT]] = !DINamespace(name: "A", scope: null, file: [[FILE:![0-9]+]], line: 5)
-// CHECK: [[FILE]] = !DIFile(filename: "{{.*}}debug-info-namespace.cpp",
+// CHECK: [[NS]] = !DINamespace(name: "B", scope: [[CTXT:![0-9]+]])
+// CHECK: [[CTXT]] = !DINamespace(name: "A", scope: null)
+// CHECK: [[FOOCPP:.*]] = !DIFile(filename: "foo.cpp"
// CHECK: [[VAR_FWD:![0-9]+]] = distinct !DIGlobalVariable(name: "var_fwd",{{.*}} scope: [[NS]],
// CHECK-SAME: line: 44
// CHECK-SAME: isDefinition: true
// CHECK: distinct !DIGlobalVariable(name: "var_i",{{.*}} scope: [[INLINE:![0-9]+]],
-// CHECK: [[INLINE]] = !DINamespace(name: "I", scope: [[CTXT]], file: [[FOOCPP]], line: 46, exportSymbols: true)
+// CHECK: [[INLINE]] = !DINamespace(name: "I", scope: [[CTXT]], exportSymbols: true)
+// CHECK: !DINamespace(scope: null)
// CHECK: [[CU:![0-9]+]] = distinct !DICompileUnit(
// CHECK-SAME: imports: [[MODULES:![0-9]*]]
-// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]}
-// CHECK: [[M1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CTXT]], entity: [[NS]], line: 15)
+// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]
+// CHECK: [[M1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CTXT]], entity: [[NS]], file: [[FOOCPP]], line: 15)
// CHECK: [[M2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[CTXT]],
-// CHECK: [[M3]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "E", scope: [[CU]], entity: [[CTXT]], line: 19)
-// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], line: 23)
+// CHECK: [[M3]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "E", scope: [[CU]], entity: [[CTXT]], file: [[FOOCPP]], line: 19)
+// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], file: [[FOOCPP]], line: 23)
// CHECK: [[LEX2]] = distinct !DILexicalBlock(scope: [[LEX1:![0-9]+]], file: [[FOOCPP]],
// CHECK: [[LEX1]] = distinct !DILexicalBlock(scope: [[FUNC:![0-9]+]], file: [[FOOCPP]],
// CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} isDefinition: true
// CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT:![0-9]+]],
-// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], line: 27)
+// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], file: [[FOOCPP]], line: 27)
// CHECK: [[FOO]] = !DICompositeType(tag: DW_TAG_structure_type, name: "foo",
// CHECK-SAME: line: 5
// CHECK-SAME: DIFlagFwdDecl
@@ -106,8 +116,10 @@ void B::func_fwd() {}
// CHECK-SAME: scope: [[NS]], file: [[FOOCPP]], line: 9
// CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]]
// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
-// CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 50,{{.*}} isDefinition: true
+// CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 53,{{.*}} isDefinition: true
// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
+// CHECK: distinct !DISubprogram(name: "c",{{.*}}, scope: ![[C:[0-9]+]],{{.*}}, line: 60,{{.*}} isDefinition: true
+// CHECK: ![[C]] = !DINamespace(name: "C",
// CHECK-GMLT: [[CU:![0-9]+]] = distinct !DICompileUnit(
// CHECK-GMLT-SAME: emissionKind: LineTablesOnly,
diff --git a/test/CodeGenCXX/debug-info-nested-exprs.cpp b/test/CodeGenCXX/debug-info-nested-exprs.cpp
new file mode 100644
index 0000000000..bd70373e22
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-nested-exprs.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-windows-msvc -debug-info-kind=limited \
+// RUN: -std=c++11 -gcodeview -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=NONEST %s
+// RUN: %clang_cc1 -triple=x86_64-pc-windows-msvc -debug-info-kind=limited \
+// RUN: -std=c++11 -gcodeview -dwarf-column-info -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=COLUMNS %s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -debug-info-kind=limited \
+// RUN: -std=c++11 -emit-llvm -o - %s | FileCheck -check-prefix=NESTED %s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -debug-info-kind=limited \
+// RUN: -std=c++11 -dwarf-column-info -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=COLUMNS %s
+
+class Foo {
+public:
+ static Foo create();
+ void func();
+ int *begin();
+ int *end();
+};
+
+int bar(int x, int y);
+int baz(int x, int y);
+int qux(int x, int y);
+int onearg(int x);
+int noargs();
+int noargs1();
+Foo range(int x);
+
+int foo(int x, int y, int z) {
+ int a = bar(x, y) +
+ baz(x, z) +
+ qux(y, z);
+ // NONEST: call i32 @{{.*}}bar{{.*}}, !dbg ![[LOC:[0-9]+]]
+ // NONEST: call i32 @{{.*}}baz{{.*}}, !dbg ![[LOC]]
+ // NONEST: call i32 @{{.*}}qux{{.*}}, !dbg ![[LOC]]
+ // NONEST: store i32 {{.*}}, i32* %a,{{.*}} !dbg ![[LOC]]
+ // NESTED: call i32 @{{.*}}bar{{.*}}, !dbg ![[BAR:[0-9]+]]
+ // NESTED: call i32 @{{.*}}baz{{.*}}, !dbg ![[BAZ:[0-9]+]]
+ // NESTED: call i32 @{{.*}}qux{{.*}}, !dbg ![[QUX:[0-9]+]]
+ // NESTED: store i32 {{.*}}, i32* %a,{{.*}} !dbg ![[BAR]]
+ // COLUMNS: call i32 @{{.*}}bar{{.*}}, !dbg ![[BAR:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}baz{{.*}}, !dbg ![[BAZ:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}qux{{.*}}, !dbg ![[QUX:[0-9]+]]
+ // COLUMNS: store i32 {{.*}}, i32* %a,{{.*}} !dbg ![[DECLA:[0-9]+]]
+
+ int i = 1, b = 0, c = 0;
+ // NONEST: store i32 1, i32* %i,{{.*}} !dbg ![[ILOC:[0-9]+]]
+ // NONEST: store i32 0, i32* %b,{{.*}} !dbg ![[ILOC]]
+ // NONEST: store i32 0, i32* %c,{{.*}} !dbg ![[ILOC]]
+ // NESTED: store i32 1, i32* %i,{{.*}} !dbg ![[ILOC:[0-9]+]]
+ // NESTED: store i32 0, i32* %b,{{.*}} !dbg ![[ILOC]]
+ // NESTED: store i32 0, i32* %c,{{.*}} !dbg ![[ILOC]]
+ // COLUMNS: store i32 1, i32* %i,{{.*}} !dbg ![[ILOC:[0-9]+]]
+ // COLUMNS: store i32 0, i32* %b,{{.*}} !dbg ![[BLOC:[0-9]+]]
+ // COLUMNS: store i32 0, i32* %c,{{.*}} !dbg ![[CLOC:[0-9]+]]
+
+ while (i > 0) {
+ b = bar(a, b);
+ --i;
+ }
+ // NONEST: call i32 @{{.*}}bar{{.*}}, !dbg ![[WHILE1:[0-9]+]]
+ // NONEST: store i32 %{{[^,]+}}, i32* %i,{{.*}} !dbg ![[WHILE2:[0-9]+]]
+ // NESTED: call i32 @{{.*}}bar{{.*}}, !dbg ![[WHILE1:[0-9]+]]
+ // NESTED: store i32 %{{[^,]+}}, i32* %i,{{.*}} !dbg ![[WHILE2:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}bar{{.*}}, !dbg ![[WHILE1:[0-9]+]]
+ // COLUMNS: store i32 %{{[^,]+}}, i32* %i,{{.*}} !dbg ![[WHILE2:[0-9]+]]
+
+ for (i = 0; i < 1; i++) {
+ b = bar(a, b);
+ c = qux(a, c);
+ }
+ // NONEST: call i32 @{{.*}}bar{{.*}}, !dbg ![[FOR1:[0-9]+]]
+ // NONEST: call i32 @{{.*}}qux{{.*}}, !dbg ![[FOR2:[0-9]+]]
+ // NESTED: call i32 @{{.*}}bar{{.*}}, !dbg ![[FOR1:[0-9]+]]
+ // NESTED: call i32 @{{.*}}qux{{.*}}, !dbg ![[FOR2:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}bar{{.*}}, !dbg ![[FOR1:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}qux{{.*}}, !dbg ![[FOR2:[0-9]+]]
+
+ if (a < b) {
+ int t = a;
+ a = b;
+ b = t;
+ }
+ // NONEST: store i32 %{{[^,]+}}, i32* %t,{{.*}} !dbg ![[IF1:[0-9]+]]
+ // NONEST: store i32 %{{[^,]+}}, i32* %a,{{.*}} !dbg ![[IF2:[0-9]+]]
+ // NONEST: store i32 %{{[^,]+}}, i32* %b,{{.*}} !dbg ![[IF3:[0-9]+]]
+ // NESTED: store i32 %{{[^,]+}}, i32* %t,{{.*}} !dbg ![[IF1:[0-9]+]]
+ // NESTED: store i32 %{{[^,]+}}, i32* %a,{{.*}} !dbg ![[IF2:[0-9]+]]
+ // NESTED: store i32 %{{[^,]+}}, i32* %b,{{.*}} !dbg ![[IF3:[0-9]+]]
+ // COLUMNS: store i32 %{{[^,]+}}, i32* %t,{{.*}} !dbg ![[IF1:[0-9]+]]
+ // COLUMNS: store i32 %{{[^,]+}}, i32* %a,{{.*}} !dbg ![[IF2:[0-9]+]]
+ // COLUMNS: store i32 %{{[^,]+}}, i32* %b,{{.*}} !dbg ![[IF3:[0-9]+]]
+
+ int d = onearg(
+ noargs());
+ // NONEST: call i32 @{{.*}}noargs{{.*}}, !dbg ![[DECLD:[0-9]+]]
+ // NONEST: call i32 @{{.*}}onearg{{.*}}, !dbg ![[DECLD]]
+ // NONEST: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[DECLD]]
+ // NESTED: call i32 @{{.*}}noargs{{.*}}, !dbg ![[DNOARGS:[0-9]+]]
+ // NESTED: call i32 @{{.*}}onearg{{.*}}, !dbg ![[DECLD:[0-9]+]]
+ // NESTED: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[DECLD]]
+ // COLUMNS: call i32 @{{.*}}noargs{{.*}}, !dbg ![[DNOARGS:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}onearg{{.*}}, !dbg ![[DONEARG:[0-9]+]]
+ // COLUMNS: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[DECLD:[0-9]+]]
+
+ d = onearg(noargs());
+ // NONEST: call i32 @{{.*}}noargs{{.*}}, !dbg ![[SETD:[0-9]+]]
+ // NONEST: call i32 @{{.*}}onearg{{.*}}, !dbg ![[SETD]]
+ // NONEST: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[SETD]]
+ // NESTED: call i32 @{{.*}}noargs{{.*}}, !dbg ![[SETD:[0-9]+]]
+ // NESTED: call i32 @{{.*}}onearg{{.*}}, !dbg ![[SETD]]
+ // NESTED: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[SETD]]
+ // COLUMNS: call i32 @{{.*}}noargs{{.*}}, !dbg ![[SETDNOARGS:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}onearg{{.*}}, !dbg ![[SETDONEARG:[0-9]+]]
+ // COLUMNS: store i32 %{{[^,]+}}, i32* %d,{{.*}} !dbg ![[SETD:[0-9]+]]
+
+ for (const auto x : range(noargs())) noargs1();
+ // NONEST: call i32 @{{.*}}noargs{{.*}}, !dbg ![[RANGEFOR:[0-9]+]]
+ // NONEST: call {{.+}} @{{.*}}range{{.*}}, !dbg ![[RANGEFOR]]
+ // NONEST: call i32 @{{.*}}noargs1{{.*}}, !dbg ![[RANGEFOR_BODY:[0-9]+]]
+ // NESTED: call i32 @{{.*}}noargs{{.*}}, !dbg ![[RANGEFOR:[0-9]+]]
+ // NESTED: call {{.+}} @{{.*}}range{{.*}}, !dbg ![[RANGEFOR]]
+ // NESTED: call i32 @{{.*}}noargs1{{.*}}, !dbg ![[RANGEFOR_BODY:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}noargs{{.*}}, !dbg ![[RANGEFOR_NOARGS:[0-9]+]]
+ // COLUMNS: call {{.+}} @{{.*}}range{{.*}}, !dbg ![[RANGEFOR_RANGE:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}noargs1{{.*}}, !dbg ![[RANGEFOR_BODY:[0-9]+]]
+
+ if (noargs() && noargs1()) {
+ Foo::create().func();
+ }
+ // NONEST: call i32 @{{.*}}noargs{{.*}}, !dbg ![[AND:[0-9]+]]
+ // NONEST: call i32 @{{.*}}noargs1{{.*}}, !dbg ![[AND]]
+ // NONEST: call {{.+}} @{{.*}}create{{.*}}, !dbg ![[AND_BODY:[0-9]+]]
+ // NONEST: call void @{{.*}}func{{.*}}, !dbg ![[AND_BODY]]
+ // NESTED: call i32 @{{.*}}noargs{{.*}}, !dbg ![[AND:[0-9]+]]
+ // NESTED: call i32 @{{.*}}noargs1{{.*}}, !dbg ![[AND]]
+ // NESTED: call {{.+}} @{{.*}}create{{.*}}, !dbg ![[AND_BODY:[0-9]+]]
+ // NESTED: call void @{{.*}}func{{.*}}, !dbg ![[AND_BODY]]
+ // COLUMNS: call i32 @{{.*}}noargs{{.*}}, !dbg ![[ANDLHS:[0-9]+]]
+ // COLUMNS: call i32 @{{.*}}noargs1{{.*}}, !dbg ![[ANDRHS:[0-9]+]]
+ // COLUMNS: call {{.+}} @{{.*}}create{{.*}}, !dbg ![[AND_CREATE:[0-9]+]]
+ // COLUMNS: call void @{{.*}}func{{.*}}, !dbg ![[AND_FUNC:[0-9]+]]
+
+ return a -
+ (b * z);
+ // NONEST: mul nsw i32 {{.*}}, !dbg ![[RETLOC:[0-9]+]]
+ // NONEST: sub nsw i32 {{.*}}, !dbg ![[RETLOC]]
+ // NONEST: ret i32 {{.*}}, !dbg ![[RETLOC]]
+ // NESTED: mul nsw i32 {{.*}}, !dbg ![[RETMUL:[0-9]+]]
+ // NESTED: sub nsw i32 {{.*}}, !dbg ![[RETSUB:[0-9]+]]
+ // NESTED: ret i32 {{.*}}, !dbg !
+ // COLUMNS: mul nsw i32 {{.*}}, !dbg ![[RETMUL:[0-9]+]]
+ // COLUMNS: sub nsw i32 {{.*}}, !dbg ![[RETSUB:[0-9]+]]
+ // COLUMNS: ret i32 {{.*}}, !dbg !
+}
+
+// NONEST: ![[WHILE1]] = !DILocation(
+// NONEST: ![[WHILE2]] = !DILocation(
+// NONEST: ![[FOR1]] = !DILocation(
+// NONEST: ![[FOR2]] = !DILocation(
+// NONEST: ![[IF1]] = !DILocation(
+// NONEST: ![[IF2]] = !DILocation(
+// NONEST: ![[IF3]] = !DILocation(
+// NONEST: ![[RANGEFOR]] = !DILocation(
+// NONEST-SAME: line: [[RANGEFOR_LINE:[0-9]+]]
+// NONEST: ![[RANGEFOR_BODY]] = !DILocation(
+// NONEST-SAME: line: [[RANGEFOR_LINE]]
+
+// NESTED: ![[BAR]] = !DILocation(
+// NESTED: ![[BAZ]] = !DILocation(
+// NESTED: ![[QUX]] = !DILocation(
+// NESTED: ![[DECLD]] = !DILocation
+// NESTED: ![[DNOARGS]] = !DILocation
+// NESTED: ![[RANGEFOR]] = !DILocation(
+// NESTED-SAME: line: [[RANGEFOR_LINE:[0-9]+]]
+// NESTED: ![[RANGEFOR_BODY]] = !DILocation(
+// NESTED-SAME: line: [[RANGEFOR_LINE]]
+// NESTED: ![[RETSUB]] = !DILocation(
+// NESTED: ![[RETMUL]] = !DILocation(
+
+// COLUMNS: ![[DECLA]] = !DILocation(
+// COLUMNS: ![[BAR]] = !DILocation(
+// COLUMNS: ![[BAZ]] = !DILocation(
+// COLUMNS: ![[QUX]] = !DILocation(
+// COLUMNS: ![[ILOC]] = !DILocation(
+// COLUMNS: ![[BLOC]] = !DILocation(
+// COLUMNS: ![[CLOC]] = !DILocation(
+// COLUMNS: ![[DECLD]] = !DILocation(
+// COLUMNS: ![[DNOARGS]] = !DILocation(
+// COLUMNS: ![[DONEARG]] = !DILocation(
+// COLUMNS: ![[SETDNOARGS]] = !DILocation(
+// COLUMNS: ![[SETDONEARG]] = !DILocation(
+// COLUMNS: ![[SETD]] = !DILocation(
+// COLUMNS: ![[RANGEFOR_NOARGS]] = !DILocation(
+// COLUMNS: ![[RANGEFOR_RANGE]] = !DILocation(
+// COLUMNS: ![[RANGEFOR_BODY]] = !DILocation(
+// COLUMNS: ![[ANDLHS]] = !DILocation
+// COLUMNS: ![[ANDRHS]] = !DILocation
+// COLUMNS: ![[AND_CREATE]] = !DILocation
+// COLUMNS: ![[AND_FUNC]] = !DILocation
+// COLUNMS: ![[RETSUB]] = !DILocation(
+// COLUMNS: ![[RETMUL]] = !DILocation(
diff --git a/test/CodeGenCXX/debug-info-static-member.cpp b/test/CodeGenCXX/debug-info-static-member.cpp
index c777ccb2ab..3537754ced 100644
--- a/test/CodeGenCXX/debug-info-static-member.cpp
+++ b/test/CodeGenCXX/debug-info-static-member.cpp
@@ -32,7 +32,7 @@ public:
// why the definition of "a" comes before the declarations while
// "b" and "c" come after.
-// CHECK: [[A]] = !DIGlobalVariableExpression(var: [[AV:.*]])
+// CHECK: [[A]] = !DIGlobalVariableExpression(var: [[AV:.*]], expr: !DIExpression())
// CHECK: [[AV]] = distinct !DIGlobalVariable(name: "a",
// CHECK-SAME: declaration: ![[DECL_A:[0-9]+]])
//
@@ -45,7 +45,7 @@ public:
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "static_decl_templ_var"
int C::a = 4;
-// CHECK: [[B]] = !DIGlobalVariableExpression(var: [[BV:.*]])
+// CHECK: [[B]] = !DIGlobalVariableExpression(var: [[BV:.*]], expr: !DIExpression())
// CHECK: [[BV]] = distinct !DIGlobalVariable(name: "b",
// CHECK-SAME: declaration: ![[DECL_B:[0-9]+]])
// CHECK: ![[DECL_B]] = !DIDerivedType(tag: DW_TAG_member, name: "b"
@@ -93,7 +93,7 @@ int C::a = 4;
// CHECK-SAME: flags: DIFlagPublic | DIFlagStaticMember)
int C::b = 2;
-// CHECK: [[C]] = !DIGlobalVariableExpression(var: [[CV:.*]])
+// CHECK: [[C]] = !DIGlobalVariableExpression(var: [[CV:.*]], expr: !DIExpression())
// CHECK: [[CV]] = distinct !DIGlobalVariable(name: "c", {{.*}} declaration: ![[DECL_C]])
int C::c = 1;
diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp
index 2b840745ff..a6aa1a05a2 100644
--- a/test/CodeGenCXX/debug-info-template-member.cpp
+++ b/test/CodeGenCXX/debug-info-template-member.cpp
@@ -19,7 +19,7 @@ inline int add3(int x) {
}
// The compile unit pulls in the global variables first.
-// CHECK: [[X]] = !DIGlobalVariableExpression(var: [[XV:.*]])
+// CHECK: [[X]] = !DIGlobalVariableExpression(var: [[XV:.*]], expr: !DIExpression())
// CHECK: [[XV]] = distinct !DIGlobalVariable(name: "x",
// CHECK-SAME: type: ![[OUTER_FOO_INNER_ID:[0-9]+]]
diff --git a/test/CodeGenCXX/debug-info-template.cpp b/test/CodeGenCXX/debug-info-template.cpp
index 54fac0b36e..0c34145162 100644
--- a/test/CodeGenCXX/debug-info-template.cpp
+++ b/test/CodeGenCXX/debug-info-template.cpp
@@ -25,7 +25,7 @@ struct TC {
int glb;
void func();
-// CHECK: [[TCI]] = !DIGlobalVariableExpression(var: [[TCIV:.*]])
+// CHECK: [[TCI]] = !DIGlobalVariableExpression(var: [[TCIV:.*]], expr: !DIExpression())
// CHECK: [[TCIV]] = distinct !DIGlobalVariable(name: "tci",
// CHECK-SAME: type: ![[TCNESTED:[0-9]+]]
// CHECK: ![[TCNESTED]] ={{.*}}!DICompositeType(tag: DW_TAG_structure_type, name: "nested",
@@ -84,7 +84,7 @@ TC
// CHECK: [[TCARG7_3]] = !DITemplateValueParameter(type: [[INT]], value: i32 3)
3>::nested tci;
-// CHECK: [[TCN]] = !DIGlobalVariableExpression(var: [[TCNV:.*]])
+// CHECK: [[TCN]] = !DIGlobalVariableExpression(var: [[TCNV:.*]], expr: !DIExpression())
// CHECK: [[TCNV]] = distinct !DIGlobalVariable(name: "tcn"
// CHECK-SAME: type: ![[TCNT:[0-9]+]]
TC
@@ -125,7 +125,7 @@ template <template <typename> class tmpl, int &lvr, int &&rvr>
struct NN {
};
-// CHECK: [[NN]] = !DIGlobalVariableExpression(var: [[NNV:.*]])
+// CHECK: [[NN]] = !DIGlobalVariableExpression(var: [[NNV:.*]], expr: !DIExpression())
// CHECK: [[NNV]] = distinct !DIGlobalVariable(name: "nn"
// CHECK-SAME: type: ![[NNT:[0-9]+]]
diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp
index 9575a5129e..6d6d0c7d19 100644
--- a/test/CodeGenCXX/debug-info.cpp
+++ b/test/CodeGenCXX/debug-info.cpp
@@ -4,11 +4,11 @@
// CHECK: @_ZN6pr96081xE = global [3 x i8]* null, align 8, !dbg [[X:![0-9]+]]
// CHECK: define void @_ZN7pr147634funcENS_3fooE
-// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[F:[0-9]+]], metadata ![[EXPR:[0-9]+]])
+// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[F:[0-9]+]], metadata !DIExpression())
// !llvm.dbg.cu pulls in globals and their types first.
// CHECK-NOT: !DIGlobalVariable(name: "c"
-// CHECK: [[X]] = !DIGlobalVariableExpression(var: [[XV:!.*]])
+// CHECK: [[X]] = !DIGlobalVariableExpression(var: [[XV:!.*]], expr: !DIExpression())
// CHECK: [[XV]] = distinct !DIGlobalVariable(name: "x", linkageName: "_ZN6pr96081xE"
// CHECK-SAME: type: [[INCARRAYPTR:![0-9]*]]
// CHECK: [[INCARRAYPTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[INCARRAY:![0-9]+]]
@@ -117,7 +117,6 @@ struct foo {
// For some reason function arguments ended up down here
// CHECK: ![[F]] = !DILocalVariable(name: "f", arg: 1, scope: ![[FUNC]]
// CHECK-SAME: type: ![[FOO]]
-// CHECK: ![[EXPR]] = !DIExpression(DW_OP_deref)
foo func(foo f) {
return f; // reference 'f' for now because otherwise we hit another bug
}
diff --git a/test/CodeGenCXX/default_calling_conv.cpp b/test/CodeGenCXX/default_calling_conv.cpp
index 95c214a223..15eedc8e31 100644
--- a/test/CodeGenCXX/default_calling_conv.cpp
+++ b/test/CodeGenCXX/default_calling_conv.cpp
@@ -10,6 +10,13 @@
// VECTORCALL: define x86_vectorcallcc void @_Z5test1v
void test1() {}
+// fastcall, stdcall, and vectorcall all do not support variadic functions.
+// CDECL: define void @_Z12testVariadicz
+// FASTCALL: define void @_Z12testVariadicz
+// STDCALL: define void @_Z12testVariadicz
+// VECTORCALL: define void @_Z12testVariadicz
+void testVariadic(...){}
+
// ALL: define void @_Z5test2v
void __attribute__((cdecl)) test2() {}
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index b082908b2c..180e82de9f 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/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
index b90620ab60..2ab2f759cf 100644
--- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
+++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
@@ -241,3 +241,53 @@ namespace Test10 {
return static_cast<A *>(b)->f();
}
}
+
+namespace Test11 {
+ // Check that the definitions of Derived's operators are emitted.
+
+ // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(
+ // CHECK: call void @_ZN6Test111SIiE7DerivedclEv(
+ // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+ // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+ // CHECK: call dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+ // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(
+ // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
+ // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
+ // CHECK: define linkonce_odr dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
+ class Base {
+ public:
+ virtual void operator()() {}
+ virtual bool operator==(const Base &other) { return false; }
+ virtual bool operator!() { return false; }
+ virtual Base &operator[](int i) { return *this; }
+ };
+
+ template<class T>
+ struct S {
+ class Derived final : public Base {
+ public:
+ void operator()() override {}
+ bool operator==(const Base &other) override { return true; }
+ bool operator!() override { return true; }
+ Base &operator[](int i) override { return *this; }
+ };
+
+ Derived *ptr = nullptr, *ptr2 = nullptr;
+
+ void foo1() {
+ if (ptr && ptr2) {
+ // These calls get devirtualized. Linkage fails if the definitions of
+ // the called functions are not emitted.
+ (*ptr)();
+ (void)(*ptr == *ptr2);
+ (void)(!(*ptr));
+ (void)((*ptr)[1]);
+ }
+ }
+ };
+
+ void foo2() {
+ S<int> *s = new S<int>;
+ s->foo1();
+ }
+}
diff --git a/test/CodeGenCXX/dllexport-dtor-thunks.cpp b/test/CodeGenCXX/dllexport-dtor-thunks.cpp
new file mode 100644
index 0000000000..52f9901620
--- /dev/null
+++ b/test/CodeGenCXX/dllexport-dtor-thunks.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -mconstructor-aliases -fms-extensions %s -emit-llvm -o - -triple x86_64-windows-msvc | FileCheck %s
+
+struct __declspec(dllexport) A { virtual ~A(); };
+struct __declspec(dllexport) B { virtual ~B(); };
+struct __declspec(dllexport) C : A, B { virtual ~C(); };
+C::~C() {}
+
+// This thunk should *not* be dllexport.
+// CHECK: define linkonce_odr i8* @"\01??_EC@@W7EAAPEAXI@Z"
+// CHECK: define dllexport void @"\01??1C@@UEAA@XZ"
diff --git a/test/CodeGenCXX/dllexport-vtable-thunks.cpp b/test/CodeGenCXX/dllexport-vtable-thunks.cpp
new file mode 100644
index 0000000000..81811ace2e
--- /dev/null
+++ b/test/CodeGenCXX/dllexport-vtable-thunks.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -fdeclspec -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-windows-itanium -fdeclspec -emit-llvm -o - %s | FileCheck %s
+
+struct __declspec(dllexport) A {
+ virtual void m();
+};
+struct __declspec(dllexport) B {
+ virtual void m();
+};
+struct __declspec(dllexport) C : A, B {
+ virtual void m();
+};
+void C::m() {}
+// CHECK: define dllexport void @_ZThn8_N1C1mEv
+
+struct Base {
+ virtual void m();
+};
+struct __declspec(dllexport) Derived : virtual Base {
+ virtual void m();
+};
+void Derived::m() {}
+// CHECK: define dllexport void @_ZTv0_n24_N7Derived1mEv
diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp
index 33e524cc9b..1c96de9b6c 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
@@ -831,6 +831,21 @@ template <typename T> struct ExplicitInstantiationTwoAttributes { void f() {} };
template struct __declspec(dllexport) __declspec(dllimport) ExplicitInstantiationTwoAttributes<int>;
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ExplicitInstantiationTwoAttributes@H@@QAEXXZ"
+namespace pr34849 {
+// Specializations of exported class template member functions get exported.
+template <typename> struct __declspec(dllexport) ExportedClassTemplate { void foo(); };
+template<> void ExportedClassTemplate<int>::foo() {}
+template struct ExportedClassTemplate<int>;
+// M32-DAG: define dllexport x86_thiscallcc void @"\01?foo@?$ExportedClassTemplate@H@pr34849@@QAEXXZ"
+
+// Specializations of exported class member template functions do not get exported.
+struct __declspec(dllexport) ExportedClass { template <typename> void bar() ; };
+template<> void ExportedClass::bar<int>() {}
+// M32-DAG: define x86_thiscallcc void @"\01??$bar@H@ExportedClass@pr34849@@QAEXXZ"
+template <typename> struct __declspec(dllexport) ExportedClassTemplate2 { template <typename> void baz(); };
+template<> template<> void ExportedClassTemplate2<int>::baz<int>() {}
+// M32-DAG: define x86_thiscallcc void @"\01??$baz@H@?$ExportedClassTemplate2@H@pr34849@@QAEXXZ"
+}
//===----------------------------------------------------------------------===//
// Classes with template base classes
diff --git a/test/CodeGenCXX/dllimport-dtor-thunks.cpp b/test/CodeGenCXX/dllimport-dtor-thunks.cpp
new file mode 100644
index 0000000000..b381fff450
--- /dev/null
+++ b/test/CodeGenCXX/dllimport-dtor-thunks.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -mconstructor-aliases %s -triple x86_64-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s
+
+// FIXME: We should really consider removing -mconstructor-aliases for MS C++
+// ABI. The risk of bugs introducing ABI incompatibility under
+// -mno-constructor-aliases is too high.
+
+// PR32990
+
+// Introduces the virtual destructor. We should use the base destructor
+// directly, no thunk needed.
+struct __declspec(dllimport) ImportIntroVDtor {
+ virtual ~ImportIntroVDtor() {}
+};
+
+struct BaseClass {
+ virtual ~BaseClass() {}
+};
+
+// Non-virtually inherits from a non-dllimport base class. We should again call
+// the derived base constructor directly. No need for the complete (aka vbase)
+// destructor.
+struct __declspec(dllimport) ImportOverrideVDtor : public BaseClass {
+ virtual ~ImportOverrideVDtor() {}
+};
+
+// Virtually inherits from a non-dllimport base class. This time we need to call
+// the complete destructor and emit it inline. It's not exported from the DLL,
+// and it must be emitted.
+struct __declspec(dllimport) ImportVBaseOverrideVDtor
+ : public virtual BaseClass {
+ virtual ~ImportVBaseOverrideVDtor() {}
+};
+
+extern "C" void testit() {
+ ImportIntroVDtor t1;
+ ImportOverrideVDtor t2;
+ ImportVBaseOverrideVDtor t3;
+}
+
+// The destructors are called in reverse order of construction. Only the third
+// needs the complete destructor (_D).
+// CHECK-LABEL: define void @testit()
+// CHECK: call void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ"(%struct.ImportVBaseOverrideVDtor* %{{.*}})
+// CHECK: call void @"\01??1ImportOverrideVDtor@@UEAA@XZ"(%struct.ImportOverrideVDtor* %{{.*}})
+// CHECK: call void @"\01??1ImportIntroVDtor@@UEAA@XZ"(%struct.ImportIntroVDtor* %{{.*}})
+
+// CHECK-LABEL: define linkonce_odr void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ"
+// CHECK-LABEL: declare dllimport void @"\01??1ImportOverrideVDtor@@UEAA@XZ"
+// CHECK-LABEL: declare dllimport void @"\01??1ImportIntroVDtor@@UEAA@XZ"
diff --git a/test/CodeGenCXX/dllimport-members.cpp b/test/CodeGenCXX/dllimport-members.cpp
index 19d9e1dfe7..ff7868382d 100644
--- a/test/CodeGenCXX/dllimport-members.cpp
+++ b/test/CodeGenCXX/dllimport-members.cpp
@@ -836,7 +836,7 @@ USEMV(MemVarTmpl, ImportedStaticVar<ImplicitInst_Imported>)
// Import explicit instantiation declaration of an imported member variable
// template.
-// MSC-DAG: @"\01??$ImportedStaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = external dllimport constant i32
+// MSC-DAG: @"\01??$ImportedStaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = available_externally dllimport constant i32 1
// GNU-DAG: @_ZN10MemVarTmpl17ImportedStaticVarI21ExplicitDecl_ImportedEE = external dllimport constant i32
extern template const int MemVarTmpl::ImportedStaticVar<ExplicitDecl_Imported>;
USEMV(MemVarTmpl, ImportedStaticVar<ExplicitDecl_Imported>)
@@ -861,7 +861,7 @@ USEMV(MemVarTmpl, ImportedStaticVar<ExplicitSpec_NotImported>)
// Import explicit instantiation declaration of a non-imported member variable
// template.
-// MSC-DAG: @"\01??$StaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = external dllimport constant i32
+// MSC-DAG: @"\01??$StaticVar@UExplicitDecl_Imported@@@MemVarTmpl@@2HB" = available_externally dllimport constant i32 1
// GNU-DAG: @_ZN10MemVarTmpl9StaticVarI21ExplicitDecl_ImportedEE = external dllimport constant i32
extern template __declspec(dllimport) const int MemVarTmpl::StaticVar<ExplicitDecl_Imported>;
USEMV(MemVarTmpl, StaticVar<ExplicitDecl_Imported>)
diff --git a/test/CodeGenCXX/dllimport-memptr-global.cpp b/test/CodeGenCXX/dllimport-memptr-global.cpp
new file mode 100644
index 0000000000..e64537b8b9
--- /dev/null
+++ b/test/CodeGenCXX/dllimport-memptr-global.cpp
@@ -0,0 +1,58 @@
+// Also check that -Wglobal-constructors does the right thing. Strictly
+// speaking, this is a Sema test, but this avoids test case duplication.
+// RUN: %clang_cc1 -Wglobal-constructors %s -verify -triple i686-windows-msvc -fms-extensions -std=c++11
+//
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple i686-windows-msvc -fms-extensions -std=c++11 | FileCheck %s
+
+struct __declspec(dllimport) Single {
+ void nonvirt();
+ virtual void virt();
+};
+
+struct A { int a; };
+struct B { int b; };
+struct __declspec(dllimport) Multi : A, B {
+ void nonvirt();
+ virtual void virt();
+};
+
+struct __declspec(dllimport) Virtual : virtual A {
+ void nonvirt();
+ virtual void virt();
+};
+
+struct General;
+static_assert(sizeof(void (General::*)()) == 16, "force general memptr model");
+struct __declspec(dllimport) General {
+ void nonvirt();
+ virtual void virt();
+};
+
+auto mp_single_nv = &Single::nonvirt; // expected-warning {{global constructor}}
+auto mp_multi_nv = &Multi::nonvirt; // expected-warning {{global constructor}}
+auto mp_virtual_nv = &Virtual::nonvirt; // expected-warning {{global constructor}}
+auto mp_general_nv = &General::nonvirt; // expected-warning {{global constructor}}
+
+auto mp_single_v = &Single::virt;
+auto mp_multi_v = &Multi::virt;
+auto mp_virtual_v = &Virtual::virt;
+auto mp_general_v = &General::virt;
+
+// All of the non-virtual globals need dynamic initializers.
+
+// CHECK: @"\01?mp_single_nv@@3P8Single@@AEXXZQ1@" = global i8* null, align 4
+// CHECK: @"\01?mp_multi_nv@@3P8Multi@@AEXXZQ1@" = global { i8*, i32 } zeroinitializer, align 4
+// CHECK: @"\01?mp_virtual_nv@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } zeroinitializer, align 4
+// CHECK: @"\01?mp_general_nv@@3P8General@@AEXXZQ1@" = global { i8*, i32, i32, i32 } zeroinitializer, align 4
+
+// CHECK: @"\01?mp_single_v@@3P8Single@@AEXXZQ1@" = global i8* bitcast (void (%struct.Single*, ...)* @"\01??_9Single@@$BA@AE" to i8*), align 4
+// CHECK: @"\01?mp_multi_v@@3P8Multi@@AEXXZQ1@" = global { i8*, i32 } { i8* bitcast (void (%struct.Multi*, ...)* @"\01??_9Multi@@$BA@AE" to i8*), i32 0 }, align 4
+// CHECK: @"\01?mp_virtual_v@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } { i8* bitcast (void (%struct.Virtual*, ...)* @"\01??_9Virtual@@$BA@AE" to i8*), i32 0, i32 0 }, align 4
+// CHECK: @"\01?mp_general_v@@3P8General@@AEXXZQ1@" = global { i8*, i32, i32, i32 } { i8* bitcast (void (%struct.General*, ...)* @"\01??_9General@@$BA@AE" to i8*), i32 0, i32 0, i32 0 }, align 4
+
+// CHECK: define internal void @_GLOBAL__sub_I{{.*}}() {{.*}} {
+// CHECK: call void @"\01??__Emp_single_nv@@YAXXZ"()
+// CHECK: call void @"\01??__Emp_multi_nv@@YAXXZ"()
+// CHECK: call void @"\01??__Emp_virtual_nv@@YAXXZ"()
+// CHECK: call void @"\01??__Emp_general_nv@@YAXXZ"()
+// CHECK: }
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index db0576a1ba..dfbe48c372 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -461,12 +461,12 @@ class DerivedException: public BaseException {
int foo() {
throw DerivedException();
- // The alignment passed to memset is 8, not 16, on Darwin.
+ // The alignment passed to memset is 16 on Darwin.
// CHECK: [[T0:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to %"class.test17::DerivedException"*
// CHECK-NEXT: [[T2:%.*]] = bitcast %"class.test17::DerivedException"* [[T1]] to i8*
- // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T2]], i8 0, i64 16, i32 8, i1 false)
+ // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T2]], i8 0, i64 16, i32 16, i1 false)
}
}
diff --git a/test/CodeGenCXX/exceptions-seh.cpp b/test/CodeGenCXX/exceptions-seh.cpp
index 4f7eacd667..fa2d834c1e 100644
--- a/test/CodeGenCXX/exceptions-seh.cpp
+++ b/test/CodeGenCXX/exceptions-seh.cpp
@@ -76,6 +76,27 @@ extern "C" void use_seh() {
// CHECK: [[cont]]
// CHECK: br label %[[ret]]
+extern "C" void nested_finally() {
+ __try {
+ might_throw();
+ } __finally {
+ __try {
+ might_throw();
+ } __finally {
+ }
+ }
+}
+
+// CHECK-LABEL: define void @nested_finally() #{{[0-9]+}}
+// CHECK-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK: invoke void @might_throw()
+// CHECK: call void @"\01?fin$0@0@nested_finally@@"(i8 1, i8* {{.*}})
+
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested_finally@@"
+// CHECK-SAME: personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+// CHECK: invoke void @might_throw()
+// CHECK: call void @"\01?fin$1@0@nested_finally@@"(i8 1, i8* {{.*}})
+
void use_seh_in_lambda() {
([]() {
__try {
diff --git a/test/CodeGenCXX/extern-section-attribute.cpp b/test/CodeGenCXX/extern-section-attribute.cpp
new file mode 100644
index 0000000000..fa0227e6fe
--- /dev/null
+++ b/test/CodeGenCXX/extern-section-attribute.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-linux-gnu | FileCheck %s
+
+extern int aa __attribute__((section(".sdata")));
+// CHECK-DAG: @aa = external global i32, section ".sdata", align 4
+
+extern int bb __attribute__((section(".sdata"))) = 1;
+// CHECK-DAG: @bb = global i32 1, section ".sdata", align 4
+
+int foo() {
+ return aa + bb;
+}
diff --git a/test/CodeGenCXX/finegrain-bitfield-access.cpp b/test/CodeGenCXX/finegrain-bitfield-access.cpp
new file mode 100644
index 0000000000..2973f9f73c
--- /dev/null
+++ b/test/CodeGenCXX/finegrain-bitfield-access.cpp
@@ -0,0 +1,162 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffine-grained-bitfield-accesses \
+// RUN: -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffine-grained-bitfield-accesses \
+// RUN: -emit-llvm -fsanitize=address -o - %s | FileCheck %s --check-prefix=SANITIZE
+// Check -fsplit-bitfields will be ignored since sanitizer is enabled.
+
+struct S1 {
+ unsigned f1:2;
+ unsigned f2:6;
+ unsigned f3:8;
+ unsigned f4:4;
+ unsigned f5:8;
+};
+
+S1 a1;
+unsigned read8_1() {
+ // CHECK-LABEL: @_Z7read8_1v
+ // CHECK: %bf.load = load i8, i8* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 1), align 1
+ // CHECK-NEXT: %bf.cast = zext i8 %bf.load to i32
+ // CHECK-NEXT: ret i32 %bf.cast
+ // SANITIZE-LABEL: @_Z7read8_1v
+ // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4
+ // SANITIZE: %bf.lshr = lshr i32 %bf.load, 8
+ // SANITIZE: %bf.clear = and i32 %bf.lshr, 255
+ // SANITIZE: ret i32 %bf.clear
+ return a1.f3;
+}
+void write8_1() {
+ // CHECK-LABEL: @_Z8write8_1v
+ // CHECK: store i8 3, i8* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 1), align 1
+ // CHECK-NEXT: ret void
+ // SANITIZE-LABEL: @_Z8write8_1v
+ // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4
+ // SANITIZE-NEXT: %bf.clear = and i32 %bf.load, -65281
+ // SANITIZE-NEXT: %bf.set = or i32 %bf.clear, 768
+ // SANITIZE-NEXT: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4
+ // SANITIZE-NEXT: ret void
+ a1.f3 = 3;
+}
+
+unsigned read8_2() {
+ // CHECK-LABEL: @_Z7read8_2v
+ // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2
+ // CHECK-NEXT: %bf.lshr = lshr i16 %bf.load, 4
+ // CHECK-NEXT: %bf.clear = and i16 %bf.lshr, 255
+ // CHECK-NEXT: %bf.cast = zext i16 %bf.clear to i32
+ // CHECK-NEXT: ret i32 %bf.cast
+ // SANITIZE-LABEL: @_Z7read8_2v
+ // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4
+ // SANITIZE-NEXT: %bf.lshr = lshr i32 %bf.load, 20
+ // SANITIZE-NEXT: %bf.clear = and i32 %bf.lshr, 255
+ // SANITIZE-NEXT: ret i32 %bf.clear
+ return a1.f5;
+}
+void write8_2() {
+ // CHECK-LABEL: @_Z8write8_2v
+ // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2
+ // CHECK-NEXT: %bf.clear = and i16 %bf.load, -4081
+ // CHECK-NEXT: %bf.set = or i16 %bf.clear, 48
+ // CHECK-NEXT: store i16 %bf.set, i16* getelementptr inbounds (%struct.S1, %struct.S1* @a1, i32 0, i32 2), align 2
+ // CHECK-NEXT: ret void
+ // SANITIZE-LABEL: @_Z8write8_2v
+ // SANITIZE: %bf.load = load i32, i32* getelementptr inbounds {{.*}}, align 4
+ // SANITIZE-NEXT: %bf.clear = and i32 %bf.load, -267386881
+ // SANITIZE-NEXT: %bf.set = or i32 %bf.clear, 3145728
+ // SANITIZE-NEXT: store i32 %bf.set, i32* getelementptr inbounds {{.*}}, align 4
+ // SANITIZE-NEXT: ret void
+ a1.f5 = 3;
+}
+
+struct S2 {
+ unsigned long f1:16;
+ unsigned long f2:16;
+ unsigned long f3:6;
+};
+
+S2 a2;
+unsigned read16_1() {
+ // CHECK-LABEL: @_Z8read16_1v
+ // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 0), align 8
+ // CHECK-NEXT: %bf.cast = zext i16 %bf.load to i64
+ // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32
+ // CHECK-NEXT: ret i32 %conv
+ // SANITIZE-LABEL: @_Z8read16_1v
+ // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8
+ // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, 65535
+ // SANITIZE-NEXT: %conv = trunc i64 %bf.clear to i32
+ // SANITIZE-NEXT: ret i32 %conv
+ return a2.f1;
+}
+unsigned read16_2() {
+ // CHECK-LABEL: @_Z8read16_2v
+ // CHECK: %bf.load = load i16, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 1), align 2
+ // CHECK-NEXT: %bf.cast = zext i16 %bf.load to i64
+ // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32
+ // CHECK-NEXT: ret i32 %conv
+ // SANITIZE-LABEL: @_Z8read16_2v
+ // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8
+ // SANITIZE-NEXT: %bf.lshr = lshr i64 %bf.load, 16
+ // SANITIZE-NEXT: %bf.clear = and i64 %bf.lshr, 65535
+ // SANITIZE-NEXT: %conv = trunc i64 %bf.clear to i32
+ // SANITIZE-NEXT: ret i32 %conv
+ return a2.f2;
+}
+
+void write16_1() {
+ // CHECK-LABEL: @_Z9write16_1v
+ // CHECK: store i16 5, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 0), align 8
+ // CHECK-NEXT: ret void
+ // SANITIZE-LABEL: @_Z9write16_1v
+ // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8
+ // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, -65536
+ // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 5
+ // SANITIZE-NEXT: store i64 %bf.set, i64* bitcast {{.*}}, align 8
+ // SANITIZE-NEXT: ret void
+ a2.f1 = 5;
+}
+void write16_2() {
+ // CHECK-LABEL: @_Z9write16_2v
+ // CHECK: store i16 5, i16* getelementptr inbounds (%struct.S2, %struct.S2* @a2, i32 0, i32 1), align 2
+ // CHECK-NEXT: ret void
+ // SANITIZE-LABEL: @_Z9write16_2v
+ // SANITIZE: %bf.load = load i64, i64* bitcast {{.*}}, align 8
+ // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, -4294901761
+ // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 327680
+ // SANITIZE-NEXT: store i64 %bf.set, i64* bitcast {{.*}}, align 8
+ // SANITIZE-NEXT: ret void
+ a2.f2 = 5;
+}
+
+struct S3 {
+ unsigned long f1:14;
+ unsigned long f2:18;
+ unsigned long f3:32;
+};
+
+S3 a3;
+unsigned read32_1() {
+ // CHECK-LABEL: @_Z8read32_1v
+ // CHECK: %bf.load = load i32, i32* getelementptr inbounds (%struct.S3, %struct.S3* @a3, i32 0, i32 1), align 4
+ // CHECK-NEXT: %bf.cast = zext i32 %bf.load to i64
+ // CHECK-NEXT: %conv = trunc i64 %bf.cast to i32
+ // CHECK-NEXT: ret i32 %conv
+ // SANITIZE-LABEL: @_Z8read32_1v
+ // SANITIZE: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8
+ // SANITIZE-NEXT: %bf.lshr = lshr i64 %bf.load, 32
+ // SANITIZE-NEXT: %conv = trunc i64 %bf.lshr to i32
+ // SANITIZE-NEXT: ret i32 %conv
+ return a3.f3;
+}
+void write32_1() {
+ // CHECK-LABEL: @_Z9write32_1v
+ // CHECK: store i32 5, i32* getelementptr inbounds (%struct.S3, %struct.S3* @a3, i32 0, i32 1), align 4
+ // CHECK-NEXT: ret void
+ // SANITIZE-LABEL: @_Z9write32_1v
+ // SANITIZE: %bf.load = load i64, i64* getelementptr inbounds {{.*}}, align 8
+ // SANITIZE-NEXT: %bf.clear = and i64 %bf.load, 4294967295
+ // SANITIZE-NEXT: %bf.set = or i64 %bf.clear, 21474836480
+ // SANITIZE-NEXT: store i64 %bf.set, i64* getelementptr inbounds {{.*}}, align 8
+ // SANITIZE-NEXT: ret void
+ a3.f3 = 5;
+}
diff --git a/test/CodeGenCXX/float16-declarations.cpp b/test/CodeGenCXX/float16-declarations.cpp
new file mode 100644
index 0000000000..b97f9aa852
--- /dev/null
+++ b/test/CodeGenCXX/float16-declarations.cpp
@@ -0,0 +1,156 @@
+// RUN: %clang -std=c++11 --target=aarch64-arm--eabi -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH64
+// RUN: %clang -std=c++11 --target=x86_64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X86
+
+/* Various contexts where type _Float16 can appear. */
+
+
+/* Namespace */
+
+namespace {
+ _Float16 f1n;
+// CHECK-DAG: @_ZN12_GLOBAL__N_13f1nE = internal global half 0xH0000, align 2
+
+ _Float16 f2n = 33.f16;
+// CHECK-AARCH64-DAG: @_ZN12_GLOBAL__N_13f2nE = internal global half 0xH5020, align 2
+// CHECK-X86-DAG: @_ZN12_GLOBAL__N_13f2nE = internal global i16 20512, align 2
+
+ _Float16 arr1n[10];
+// CHECK-AARCH64-DAG: @_ZN12_GLOBAL__N_15arr1nE = internal global [10 x half] zeroinitializer, align 2
+// CHECK-X86-DAG: @_ZN12_GLOBAL__N_15arr1nE = internal global [10 x half] zeroinitializer, align 16
+
+ _Float16 arr2n[] = { 1.2, 3.0, 3.e4 };
+// CHECK-AARCH64-DAG: @_ZN12_GLOBAL__N_15arr2nE = internal global [3 x half] [half 0xH3CCD, half 0xH4200, half 0xH7753], align 2
+// CHECK-X86-DAG: @_ZN12_GLOBAL__N_15arr2nE = internal global [3 x i16] [i16 15565, i16 16896, i16 30547], align 2
+
+ const volatile _Float16 func1n(const _Float16 &arg) {
+ return arg + f2n + arr1n[4] - arr2n[1];
+ }
+}
+
+
+/* File */
+
+_Float16 f1f;
+// CHECK-AARCH64-DAG: @f1f = global half 0xH0000, align 2
+// CHECK-X86-DAG: @f1f = global half 0xH0000, align 2
+
+_Float16 f2f = 32.4;
+// CHECK-AARCH64-DAG: @f2f = global half 0xH500D, align 2
+// CHECK-X86-DAG: @f2f = global i16 20493, align 2
+
+_Float16 arr1f[10];
+// CHECK-AARCH64-DAG: @arr1f = global [10 x half] zeroinitializer, align 2
+// CHECK-X86-DAG: @arr1f = global [10 x half] zeroinitializer, align 16
+
+_Float16 arr2f[] = { -1.2, -3.0, -3.e4 };
+// CHECK-AARCH64-DAG: @arr2f = global [3 x half] [half 0xHBCCD, half 0xHC200, half 0xHF753], align 2
+// CHECK-X86-DAG: @arr2f = global [3 x i16] [i16 -17203, i16 -15872, i16 -2221], align 2
+
+_Float16 func1f(_Float16 arg);
+
+
+/* Class */
+
+class C1 {
+ _Float16 f1c;
+
+ static const _Float16 f2c;
+// CHECK-DAG: @_ZN2C13f2cE = external constant half, align 2
+
+ volatile _Float16 f3c;
+
+public:
+ C1(_Float16 arg) : f1c(arg), f3c(arg) { }
+// Check that we mangle _Float16 to DF16_
+// CHECK-DAG: define linkonce_odr void @_ZN2C1C2EDF16_(%class.C1*{{.*}}, half{{.*}})
+
+ _Float16 func1c(_Float16 arg ) {
+ return f1c + arg;
+ }
+// CHECK-DAG: define linkonce_odr half @_ZN2C16func1cEDF16_(%class.C1*{{.*}}, half{{.*}})
+
+ static _Float16 func2c(_Float16 arg) {
+ return arg * C1::f2c;
+ }
+// CHECK-DAG: define linkonce_odr half @_ZN2C16func2cEDF16_(half{{.*}})
+};
+
+/* Template */
+
+template <class C> C func1t(C arg) {
+ return arg * 2.f16;
+}
+// CHECK-DAG: define linkonce_odr half @_Z6func1tIDF16_ET_S0_(half{{.*}})
+
+template <class C> struct S1 {
+ C mem1;
+};
+
+template <> struct S1<_Float16> {
+ _Float16 mem2;
+};
+
+
+/* Local */
+
+extern int printf (const char *__restrict __format, ...);
+
+int main(void) {
+ _Float16 f1l = 1e3f16;
+// CHECK-DAG: store half 0xH63D0, half* %{{.*}}, align 2
+
+ _Float16 f2l = -0.f16;
+// CHECK-DAG: store half 0xH8000, half* %{{.*}}, align 2
+
+ _Float16 f3l = 1.000976562;
+// CHECK-DAG: store half 0xH3C01, half* %{{.*}}, align 2
+
+ C1 c1(f1l);
+// CHECK-DAG: [[F1L:%[a-z0-9]+]] = load half, half* %{{.*}}, align 2
+// CHECK-DAG: call void @_ZN2C1C2EDF16_(%class.C1* %{{.*}}, half %{{.*}})
+
+ S1<_Float16> s1 = { 132.f16 };
+// CHECK-AARCH64-DAG: @_ZZ4mainE2s1 = private unnamed_addr constant %struct.S1 { half 0xH5820 }, align 2
+// CHECK-X86-DAG: @_ZZ4mainE2s1 = private unnamed_addr constant { i16 } { i16 22560 }, align 2
+// CHECK-DAG: [[S1:%[0-9]+]] = bitcast %struct.S1* %{{.*}} to i8*
+// CHECK-AARCH64-DAG: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[S1]], i8* bitcast (%struct.S1* @_ZZ4mainE2s1 to i8*), i64 2, i32 2, i1 false)
+// CHECK-X86-DAG: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* bitcast ({ i16 }* @_ZZ4mainE2s1 to i8*), i64 2, i32 2, i1 false)
+
+ _Float16 f4l = func1n(f1l) + func1f(f2l) + c1.func1c(f3l) + c1.func2c(f1l) +
+ func1t(f1l) + s1.mem2 - f1n + f2n;
+
+ auto f5l = -1.f16, *f6l = &f2l, f7l = func1t(f3l);
+// CHECK-DAG: store half 0xHBC00, half* %{{.*}}, align 2
+// CHECK-DAG: store half* %{{.*}}, half** %{{.*}}, align 8
+
+ _Float16 f8l = f4l++;
+// CHECK-DAG: %{{.*}} = load half, half* %{{.*}}, align 2
+// CHECK-DAG: [[INC:%[a-z0-9]+]] = fadd half {{.*}}, 0xH3C00
+// CHECK-DAG: store half [[INC]], half* %{{.*}}, align 2
+
+ _Float16 arr1l[] = { -1.f16, -0.f16, -11.f16 };
+// CHECK-AARCH64-DAG: @_ZZ4mainE5arr1l = private unnamed_addr constant [3 x half] [half 0xHBC00, half 0xH8000, half 0xHC980], align 2
+// CHECK-X86-DAG: @_ZZ4mainE5arr1l = private unnamed_addr constant [3 x i16] [i16 -17408, i16 -32768, i16 -13952], align 2
+
+ float cvtf = f2n;
+//CHECK-DAG: [[H2F:%[a-z0-9]+]] = fpext half {{%[0-9]+}} to float
+//CHECK-DAG: store float [[H2F]], float* %{{.*}}, align 4
+
+ double cvtd = f2n;
+//CHECK-DAG: [[H2D:%[a-z0-9]+]] = fpext half {{%[0-9]+}} to double
+//CHECK-DAG: store double [[H2D]], double* %{{.*}}, align 8
+
+
+ long double cvtld = f2n;
+//CHECK-AARCh64-DAG: [[H2LD:%[a-z0-9]+]] = fpext half {{%[0-9]+}} to fp128
+//CHECK-AARCh64-DAG: store fp128 [[H2LD]], fp128* %{{.*}}, align 16
+//CHECK-X86-DAG: [[H2LD:%[a-z0-9]+]] = fpext half {{%[0-9]+}} to x86_fp80
+//CHECK-X86-DAG: store x86_fp80 [[H2LD]], x86_fp80* %{{.*}}, align 16
+
+ _Float16 f2h = 42.0f;
+//CHECK-DAG: store half 0xH5140, half* %{{.*}}, align 2
+ _Float16 d2h = 42.0;
+//CHECK-DAG: store half 0xH5140, half* %{{.*}}, align 2
+ _Float16 ld2h = 42.0l;
+//CHECK-DAG:store half 0xH5140, half* %{{.*}}, align 2
+}
diff --git a/test/CodeGenCXX/implicit-exception-spec.cpp b/test/CodeGenCXX/implicit-exception-spec.cpp
index cf363bd685..e1a969ab27 100644
--- a/test/CodeGenCXX/implicit-exception-spec.cpp
+++ b/test/CodeGenCXX/implicit-exception-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck %s
struct A {
A();
diff --git a/test/CodeGenCXX/inline-dllexport-member.cpp b/test/CodeGenCXX/inline-dllexport-member.cpp
index 66ef459bd8..a98f5601d3 100644
--- a/test/CodeGenCXX/inline-dllexport-member.cpp
+++ b/test/CodeGenCXX/inline-dllexport-member.cpp
@@ -7,7 +7,7 @@ struct __declspec(dllexport) s {
static const unsigned int ui = 0;
};
-// CHECK: [[UI]] = !DIGlobalVariableExpression(var: [[UIV:.*]])
+// CHECK: [[UI]] = !DIGlobalVariableExpression(var: [[UIV:.*]], expr: !DIExpression())
// CHECK: [[UIV]] = distinct !DIGlobalVariable(name: "ui", linkageName: "\01?ui@s@@2IB", scope: ![[SCOPE:[0-9]+]],
// CHECK: ![[SCOPE]] = distinct !DICompileUnit(
diff --git a/test/CodeGenCXX/invariant.group-for-vptrs.cpp b/test/CodeGenCXX/invariant.group-for-vptrs.cpp
index 5c76353808..4e5d9b49d9 100644
--- a/test/CodeGenCXX/invariant.group-for-vptrs.cpp
+++ b/test/CodeGenCXX/invariant.group-for-vptrs.cpp
@@ -12,15 +12,15 @@ struct D : A {
void testExternallyVisible() {
A *a = new A;
- // CHECK: load {{.*}} !invariant.group ![[A_MD:[0-9]+]]
+ // CHECK: load {{.*}} !invariant.group ![[MD:[0-9]+]]
a->foo();
D *d = new D;
// CHECK: call void @_ZN1DC1Ev(
- // CHECK: load {{.*}} !invariant.group ![[D_MD:[0-9]+]]
+ // CHECK: load {{.*}} !invariant.group ![[MD]]
d->foo();
A *a2 = d;
- // CHECK: load {{.*}} !invariant.group ![[A_MD]]
+ // CHECK: load {{.*}} !invariant.group ![[MD]]
a2->foo();
}
// CHECK-LABEL: {{^}}}
@@ -40,35 +40,32 @@ struct C : B {
// CHECK-LABEL: define void @_Z21testInternallyVisibleb(
void testInternallyVisible(bool p) {
B *b = new B;
- // CHECK: = load {{.*}}, !invariant.group ![[B_MD:[0-9]+]]
+ // CHECK: = load {{.*}}, !invariant.group ![[MD]]
b->bar();
// CHECK: call void @_ZN12_GLOBAL__N_11CC1Ev(
C *c = new C;
- // CHECK: = load {{.*}}, !invariant.group ![[C_MD:[0-9]+]]
+ // CHECK: = load {{.*}}, !invariant.group ![[MD]]
c->bar();
}
// Checking A::A()
// CHECK-LABEL: define linkonce_odr void @_ZN1AC2Ev(
-// CHECK: store {{.*}}, !invariant.group ![[A_MD]]
+// CHECK: store {{.*}}, !invariant.group ![[MD]]
// CHECK-LABEL: {{^}}}
// Checking D::D()
// CHECK-LABEL: define linkonce_odr void @_ZN1DC2Ev(
// CHECK: = call i8* @llvm.invariant.group.barrier(i8*
// CHECK: call void @_ZN1AC2Ev(%struct.A*
-// CHECK: store {{.*}} !invariant.group ![[D_MD]]
+// CHECK: store {{.*}} !invariant.group ![[MD]]
// Checking B::B()
// CHECK-LABEL: define internal void @_ZN12_GLOBAL__N_11BC2Ev(
-// CHECK: store {{.*}}, !invariant.group ![[B_MD]]
+// CHECK: store {{.*}}, !invariant.group ![[MD]]
// Checking C::C()
// CHECK-LABEL: define internal void @_ZN12_GLOBAL__N_11CC2Ev(
-// CHECK: store {{.*}}, !invariant.group ![[C_MD]]
+// CHECK: store {{.*}}, !invariant.group ![[MD]]
-// CHECK: ![[A_MD]] = !{!"_ZTS1A"}
-// CHECK: ![[D_MD]] = !{!"_ZTS1D"}
-// CHECK: ![[B_MD]] = distinct !{}
-// CHECK: ![[C_MD]] = distinct !{}
+// CHECK: ![[MD]] = !{}
diff --git a/test/CodeGenCXX/linetable-virtual-variadic.cpp b/test/CodeGenCXX/linetable-virtual-variadic.cpp
index 6f96641686..cd746cdfdf 100644
--- a/test/CodeGenCXX/linetable-virtual-variadic.cpp
+++ b/test/CodeGenCXX/linetable-virtual-variadic.cpp
@@ -12,8 +12,10 @@ void Derived::VariadicFunction(...) { }
// CHECK: define void @_ZN7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP:[0-9]+]]
// CHECK: ret void, !dbg ![[LOC:[0-9]+]]
-// CHECK-LABEL: define void @_ZT{{.+}}N7Derived16VariadicFunctionEz(
-// CHECK: ret void, !dbg ![[LOC:[0-9]+]]
+// CHECK: define void @_ZT{{.+}}N7Derived16VariadicFunctionEz({{.*}} !dbg ![[SP_I:[0-9]+]]
+// CHECK: ret void, !dbg ![[LOC_I:[0-9]+]]
//
// CHECK: ![[SP]] = distinct !DISubprogram(name: "VariadicFunction"
// CHECK: ![[LOC]] = !DILocation({{.*}}scope: ![[SP]])
+// CHECK: ![[SP_I]] = distinct !DISubprogram(name: "VariadicFunction"
+// CHECK: ![[LOC_I]] = !DILocation({{.*}}scope: ![[SP_I]])
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index ee7594b2fd..6c46402694 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -314,6 +314,19 @@ namespace test7 {
template<class T> decltype(F{{1,2}},T()) fF1(T t) {}
template<class T> decltype(F({1,2}),T()) fF2(T t) {}
+ template<class T> decltype(T{}) fT1(T t) {}
+ template<class T> decltype(T()) fT2(T t) {}
+ template<class T> decltype(T{1}) fT3(T t) {}
+ template<class T> decltype(T(1)) fT4(T t) {}
+ template<class T> decltype(T{1,2}) fT5(T t) {}
+ template<class T> decltype(T(1,2)) fT6(T t) {}
+ template<class T> decltype(T{{}}) fT7(T t) {}
+ template<class T> decltype(T({})) fT8(T t) {}
+ template<class T> decltype(T{{1}}) fT9(T t) {}
+ template<class T> decltype(T({1})) fTA(T t) {}
+ template<class T> decltype(T{{1,2}}) fTB(T t) {}
+ template<class T> decltype(T({1,2})) fTC(T t) {}
+
int main() {
fA1(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fA1IiEEDTcmtlNS_1AELi1ELi2EEcvT__EES2_
fA2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fA2IiEEDTcmcvNS_1AEilLi1ELi2EEcvT__EES2_
@@ -327,6 +340,18 @@ namespace test7 {
fE2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fE2IiEEDTcmcvNS_1EEilLi1ELi2EEcvT__EES2_
fF1(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fF1IiEEDTcmtlNS_1FEilLi1ELi2EEEcvT__EES2_
fF2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fF2IiEEDTcmcvNS_1FEilLi1ELi2EEcvT__EES2_
+ fT1(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fT1IiEEDTtlT_EES1_(
+ fT2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fT2IiEEDTcvT__EES1_(
+ fT3(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fT3IiEEDTtlT_Li1EEES1_(
+ fT4(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fT4IiEEDTcvT_Li1EES1_(
+ fT5(b); // CHECK-LABEL: define {{.*}} @_ZN5test73fT5INS_1BEEEDTtlT_Li1ELi2EEES2_(
+ fT6(b); // CHECK-LABEL: define {{.*}} @_ZN5test73fT6INS_1BEEEDTcvT__Li1ELi2EEES2_(
+ fT7(A{}); // CHECK-LABEL: define {{.*}} @_ZN5test73fT7INS_1AEEEDTtlT_ilEEES2_(
+ fT8(A{}); // CHECK-LABEL: define {{.*}} @_ZN5test73fT8INS_1AEEEDTcvT_ilEES2_(
+ fT9(A{}); // CHECK-LABEL: define {{.*}} @_ZN5test73fT9INS_1AEEEDTtlT_ilLi1EEEES2_(
+ fTA(A{}); // CHECK-LABEL: define {{.*}} @_ZN5test73fTAINS_1AEEEDTcvT_ilLi1EEES2_(
+ fTB<C>(b); // CHECK-LABEL: define {{.*}} @_ZN5test73fTBINS_1CEEEDTtlT_ilLi1ELi2EEEES2_(
+ fTC<C>(b); // CHECK-LABEL: define {{.*}} @_ZN5test73fTCINS_1CEEEDTcvT_ilLi1ELi2EEES2_(
}
}
@@ -341,3 +366,10 @@ namespace test8 {
// CHECK-LABEL: define weak_odr i32 @_ZNK5test81XIiE3barIiEEDTcl3fooIT_EEEv
template int X<int>::bar<int>() const;
}
+
+namespace designated_init {
+ struct A { struct B { int b[5][5]; } a; };
+ // CHECK-LABEL: define {{.*}} @_ZN15designated_init1fINS_1AEEEvDTtlT_di1adi1bdxLi3EdXLi1ELi4ELi9EEE(
+ template<typename T> void f(decltype(T{.a.b[3][1 ... 4] = 9}) x) {}
+ void use_f(A a) { f<A>(a); }
+}
diff --git a/test/CodeGenCXX/mangle-fail.cpp b/test/CodeGenCXX/mangle-fail.cpp
index 02548964ef..b588d57749 100644
--- a/test/CodeGenCXX/mangle-fail.cpp
+++ b/test/CodeGenCXX/mangle-fail.cpp
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=1
// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=2
-// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=3
struct A { int a; };
@@ -14,11 +13,6 @@ template void test<int>(int (&)[sizeof(int)]);
template<class T> void test(int (&)[sizeof((A){}, T())]) {} // expected-error {{cannot yet mangle}}
template void test<int>(int (&)[sizeof(A)]);
-#elif N == 3
-// DesignatedInitExpr
-template<class T> void test(int (&)[sizeof(A{.a = 10}, T())]) {} // expected-error {{cannot yet mangle}}
-template void test<int>(int (&)[sizeof(A)]);
-
// FIXME: There are several more cases we can't yet mangle.
#else
diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp
index 15987ebe46..d49ed4b2a5 100644
--- a/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/test/CodeGenCXX/mangle-lambdas.cpp
@@ -26,6 +26,24 @@ void call_inline_func() {
inline_func(17);
}
+// CHECK-LABEL: define linkonce_odr i32* @_ZNK10inline_varMUlvE_clEv(
+// CHECK: @_ZZNK10inline_varMUlvE_clEvE1n
+inline auto inline_var = [] {
+ static int n = 5;
+ return &n;
+};
+
+int *use_inline_var = inline_var();
+
+// CHECK-LABEL: define linkonce_odr i32* @_ZNK12var_templateIiEMUlvE_clEv(
+// CHECK: @_ZZNK12var_templateIiEMUlvE_clEvE1n
+template<typename T> auto var_template = [] {
+ static int n = 9;
+ return &n;
+};
+
+int *use_var_template = var_template<int>();
+
struct S {
void f(int = []{return 1;}()
+ []{return 2;}(),
@@ -118,7 +136,7 @@ T StaticMembers<T>::z = accept_lambda([]{return 4;});
template<typename T>
int (*StaticMembers<T>::f)() = []{return 5;};
-// CHECK-LABEL: define internal void @__cxx_global_var_init()
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv
// CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv
// CHECK-NEXT: add nsw
@@ -128,23 +146,23 @@ int (*StaticMembers<T>::f)() = []{return 5;};
// CHECK: ret i32 2
template float StaticMembers<float>::x;
-// CHECK-LABEL: define internal void @__cxx_global_var_init.1()
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
// CHECK-LABEL: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
// CHECK: ret i32 3
template float StaticMembers<float>::y;
-// CHECK-LABEL: define internal void @__cxx_global_var_init.2()
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_
// CHECK: declare i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_()
template float StaticMembers<float>::z;
-// CHECK-LABEL: define internal void @__cxx_global_var_init.3()
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call {{.*}} @_ZNK13StaticMembersIfE1fMUlvE_cvPFivEEv
// CHECK-LABEL: define linkonce_odr i32 ()* @_ZNK13StaticMembersIfE1fMUlvE_cvPFivEEv
template int (*StaticMembers<float>::f)();
-// CHECK-LABEL: define internal void @__cxx_global_var_init.4
+// CHECK-LABEL: define internal void @__cxx_global_var_init
// CHECK: call i32 @"_ZNK13StaticMembersIdE3$_2clEv"
// CHECK-LABEL: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv"
// CHECK: ret i32 42
diff --git a/test/CodeGenCXX/mangle-ms-cxx11.cpp b/test/CodeGenCXX/mangle-ms-cxx11.cpp
index 819b0d9c9d..b22c04698e 100644
--- a/test/CodeGenCXX/mangle-ms-cxx11.cpp
+++ b/test/CodeGenCXX/mangle-ms-cxx11.cpp
@@ -160,6 +160,8 @@ struct { } a;
decltype(a) fun(decltype(a) x, decltype(a)) { return x; }
// CHECK-DAG: @"\01?fun@PR18022@@YA?AU<unnamed-type-a>@1@U21@0@Z"
+void use_fun() { fun(a, a); }
+
}
inline int define_lambda() {
@@ -280,7 +282,7 @@ void g() {
namespace PR18204 {
template <typename T>
-int f(T *);
+int f(T *) { return 0; }
static union {
int n = f(this);
};
@@ -346,4 +348,5 @@ int call_it = (A::default_args(), 1);
enum { enumerator };
void f(decltype(enumerator)) {}
-// CHECK-DAG: define void @"\01?f@@YAXW4<unnamed-enum-enumerator>@@@Z"(
+// CHECK-DAG: define internal void @"\01?f@@YAXW4<unnamed-enum-enumerator>@@@Z"(
+void use_f() { f(enumerator); }
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index ee0f50e5e2..7e2f17f27a 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -399,6 +399,13 @@ template void fn_tmpl<extern_c_func>();
extern "C" void __attribute__((overloadable)) overloaded_fn() {}
// CHECK-DAG: @"\01?overloaded_fn@@$$J0YAXXZ"
+extern "C" void overloaded_fn2() {}
+// CHECK-DAG: @overloaded_fn2
+//
+extern "C" void __attribute__((overloadable)) overloaded_fn3();
+extern "C" void overloaded_fn3() {}
+// CHECK-DAG: @overloaded_fn3
+
namespace UnnamedType {
struct S {
typedef struct {} *T1[1];
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 91fe6aeef2..919f8afb16 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -893,7 +893,8 @@ namespace test39 {
struct {} a;
} *foo;
template<typename T> void func(T) {}
- void test(foo x) {
+ void test() {
+ foo x;
func(x->a);
}
}
diff --git a/test/CodeGenCXX/member-expr-references-variable.cpp b/test/CodeGenCXX/member-expr-references-variable.cpp
new file mode 100644
index 0000000000..8c1dded800
--- /dev/null
+++ b/test/CodeGenCXX/member-expr-references-variable.cpp
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+struct Agg { const char * x; const char * y; constexpr Agg() : x(0), y(0) {} };
+
+struct Struct {
+ constexpr static const char *name = "foo";
+
+ constexpr static __complex float complexValue = 42.0;
+
+ static constexpr const Agg &agg = Agg();
+
+ Struct();
+ Struct(int x);
+};
+
+void use(int n, const char *c);
+
+Struct *getPtr();
+
+// CHECK: @[[STR:.*]] = private unnamed_addr constant [4 x i8] c"foo\00", align 1
+
+void scalarStaticVariableInMemberExpr(Struct *ptr, Struct &ref) {
+ use(1, Struct::name);
+// CHECK: call void @_Z3useiPKc(i32 1, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0))
+ Struct s;
+ use(2, s.name);
+// CHECK: call void @_Z3useiPKc(i32 2, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0))
+ use(3, ptr->name);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: call void @_Z3useiPKc(i32 3, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0))
+ use(4, ref.name);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: call void @_Z3useiPKc(i32 4, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0))
+ use(5, Struct(2).name);
+// CHECK: call void @_ZN6StructC1Ei(%struct.Struct* %{{.*}}, i32 2)
+// CHECK: call void @_Z3useiPKc(i32 5, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0))
+ use(6, getPtr()->name);
+// CHECK: call %struct.Struct* @_Z6getPtrv()
+// CHECK: call void @_Z3useiPKc(i32 6, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[STR]], i32 0, i32 0))
+}
+
+void use(int n, __complex float v);
+
+void complexStaticVariableInMemberExpr(Struct *ptr, Struct &ref) {
+ use(1, Struct::complexValue);
+// CHECK: store float 4.200000e+01, float* %[[coerce0:.*]].{{.*}}, align 4
+// CHECK: store float 0.000000e+00, float* %[[coerce0]].{{.*}}, align 4
+// CHECK: %[[cast0:.*]] = bitcast { float, float }* %[[coerce0]] to <2 x float>*
+// CHECK: %[[vector0:.*]] = load <2 x float>, <2 x float>* %[[cast0]], align 4
+// CHECK: call void @_Z3useiCf(i32 1, <2 x float> %[[vector0]])
+ Struct s;
+ use(2, s.complexValue);
+// CHECK: store float 4.200000e+01, float* %[[coerce1:.*]].{{.*}}, align 4
+// CHECK: store float 0.000000e+00, float* %[[coerce1]].{{.*}}, align 4
+// CHECK: %[[cast1:.*]] = bitcast { float, float }* %[[coerce1]] to <2 x float>*
+// CHECK: %[[vector1:.*]] = load <2 x float>, <2 x float>* %[[cast1]], align 4
+// CHECK: call void @_Z3useiCf(i32 2, <2 x float> %[[vector1]])
+ use(3, ptr->complexValue);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: store float 4.200000e+01, float* %[[coerce2:.*]].{{.*}}, align 4
+// CHECK: store float 0.000000e+00, float* %[[coerce2]].{{.*}}, align 4
+// CHECK: %[[cast2:.*]] = bitcast { float, float }* %[[coerce2]] to <2 x float>*
+// CHECK: %[[vector2:.*]] = load <2 x float>, <2 x float>* %[[cast2]], align 4
+// CHECK: call void @_Z3useiCf(i32 3, <2 x float> %[[vector2]])
+ use(4, ref.complexValue);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: store float 4.200000e+01, float* %[[coerce3:.*]].{{.*}}, align 4
+// CHECK: store float 0.000000e+00, float* %[[coerce3]].{{.*}}, align 4
+// CHECK: %[[cast3:.*]] = bitcast { float, float }* %[[coerce3]] to <2 x float>*
+// CHECK: %[[vector3:.*]] = load <2 x float>, <2 x float>* %[[cast3]], align 4
+// CHECK: call void @_Z3useiCf(i32 4, <2 x float> %[[vector3]])
+ use(5, Struct(2).complexValue);
+// CHECK: call void @_ZN6StructC1Ei(%struct.Struct* %{{.*}}, i32 2)
+// CHECK: store float 4.200000e+01, float* %[[coerce4:.*]].{{.*}}, align 4
+// CHECK: store float 0.000000e+00, float* %[[coerce4]].{{.*}}, align 4
+// CHECK: %[[cast4:.*]] = bitcast { float, float }* %[[coerce4]] to <2 x float>*
+// CHECK: %[[vector4:.*]] = load <2 x float>, <2 x float>* %[[cast4]], align 4
+// CHECK: call void @_Z3useiCf(i32 5, <2 x float> %[[vector4]])
+ use(6, getPtr()->complexValue);
+// CHECK: call %struct.Struct* @_Z6getPtrv()
+// CHECK: store float 4.200000e+01, float* %[[coerce5:.*]].{{.*}}, align 4
+// CHECK: store float 0.000000e+00, float* %[[coerce5]].{{.*}}, align 4
+// CHECK: %[[cast5:.*]] = bitcast { float, float }* %[[coerce5]] to <2 x float>*
+// CHECK: %[[vector5:.*]] = load <2 x float>, <2 x float>* %[[cast5]], align 4
+// CHECK: call void @_Z3useiCf(i32 6, <2 x float> %[[vector5]])
+}
+
+void aggregateRefInMemberExpr(Struct *ptr, Struct &ref) {
+ use(1, Struct::agg.x);
+// CHECK: %[[value0:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 1, i8* %[[value0]])
+ Struct s;
+ use(2, s.agg.x);
+// CHECK: %[[value1:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 2, i8* %[[value1]])
+ use(3, ptr->agg.x);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: %[[value2:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 3, i8* %[[value2]])
+ use(4, ref.agg.x);
+// CHECK: load %struct.Struct*, %struct.Struct** %{{.*}}, align 8
+// CHECK: %[[value3:.*]] = load i8*, i8** getelementptr inbounds (%struct.Agg, %struct.Agg* @_ZGRN6Struct3aggE_, i32 0, i32 0), align 8
+// CHECK: call void @_Z3useiPKc(i32 4, i8* %[[value3]])
+}
diff --git a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
index f3e43079c3..8d75ed4d9d 100644
--- a/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
+++ b/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
@@ -78,7 +78,7 @@ T* test6(B* x) { return dynamic_cast<T*>(x); }
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32, i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8, i8* [[CAST]], i32 [[DELTA]]
-// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[DELTA]], i8* {{.*}}bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUB@@@8" to i8*), i8* {{.*}}bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUT@@@8" to i8*), i32 0)
+// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* nonnull [[ADJ]], i32 [[DELTA]], i8* {{.*}}bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUB@@@8" to i8*), i8* {{.*}}bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUT@@@8" to i8*), i32 0)
// CHECK-NEXT: [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*
// CHECK-NEXT: br label
// CHECK: [[RET:%.*]] = phi %struct.T*
@@ -117,7 +117,7 @@ void* test9(B* x) { return dynamic_cast<void*>(x); }
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32, i32* [[VBOFFP]], align 4
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8, i8* [[CAST]], i32 [[DELTA]]
-// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTCastToVoid(i8* [[ADJ]])
+// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTCastToVoid(i8* nonnull [[ADJ]])
// CHECK-NEXT: br label
// CHECK: [[RET:%.*]] = phi i8*
// CHECK-NEXT: ret i8* [[RET]]
diff --git a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
index 79ac1e1217..96b4fa3478 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-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
index 57a72d4e2a..0b84f07e11 100644
--- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
@@ -146,7 +146,7 @@ inline S &getS() {
// CHECK-LABEL: define linkonce_odr dereferenceable({{[0-9]+}}) %struct.S* @"\01?getS@@YAAAUS@@XZ"() {{.*}} comdat
// CHECK: load i32, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51"
// CHECK: and i32 {{.*}}, 1
-// CHECK: icmp ne i32 {{.*}}, 0
+// CHECK: icmp eq i32 {{.*}}, 0
// CHECK: br i1
// init:
// CHECK: or i32 {{.*}}, 1
diff --git a/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp b/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp
index 0202586c8a..3f53e631c9 100644
--- a/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp
+++ b/test/CodeGenCXX/microsoft-abi-thread-safe-statics.cpp
@@ -24,8 +24,8 @@ extern inline S &f() {
static thread_local S s;
// CHECK: %[[guard:.*]] = load i32, i32* @"\01??__J?1??f@@YAAAUS@@XZ@51"
// CHECK-NEXT: %[[mask:.*]] = and i32 %[[guard]], 1
-// CHECK-NEXT: %[[cmp:.*]] = icmp ne i32 %[[mask]], 0
-// CHECK-NEXT: br i1 %[[cmp]], label %[[init_end:.*]], label %[[init:.*]]
+// CHECK-NEXT: %[[cmp:.*]] = icmp eq i32 %[[mask]], 0
+// CHECK-NEXT: br i1 %[[cmp]], label %[[init:.*]], label %[[init_end:.*]], !prof ![[unlikely_threadlocal:.*]]
//
// CHECK: [[init]]:
// CHECK-NEXT: %[[or:.*]] = or i32 %[[guard]], 1
@@ -56,7 +56,7 @@ extern inline S &g() {
// CHECK: %[[guard:.*]] = load atomic i32, i32* @"\01?$TSS0@?1??g@@YAAAUS@@XZ@4HA" unordered, align 4
// CHECK-NEXT: %[[epoch:.*]] = load i32, i32* @_Init_thread_epoch
// CHECK-NEXT: %[[cmp:.*]] = icmp sgt i32 %[[guard]], %[[epoch]]
-// CHECK-NEXT: br i1 %[[cmp]], label %[[init_attempt:.*]], label %[[init_end:.*]]
+// CHECK-NEXT: br i1 %[[cmp]], label %[[init_attempt:.*]], label %[[init_end:.*]], !prof ![[unlikely_staticlocal:.*]]
//
// CHECK: [[init_attempt]]:
// CHECK-NEXT: call void @_Init_thread_header(i32* @"\01?$TSS0@?1??g@@YAAAUS@@XZ@4HA")
@@ -95,3 +95,6 @@ int g1() {
static int i = f1();
return i;
}
+
+// CHECK-DAG: ![[unlikely_threadlocal]] = !{!"branch_weights", i32 1, i32 1023}
+// CHECK-DAG: ![[unlikely_staticlocal]] = !{!"branch_weights", i32 1, i32 1048575}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp b/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp
index 2bf7da58ea..feba91c505 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-return-thunks.cpp
@@ -201,3 +201,18 @@ D::D() {}
// GLOBALS: @"\01?fn@D@test3@@$4PPPPPPPM@A@AEPAUB@2@XZ"
// GLOBALS: @"\01?fn@D@test3@@$4PPPPPPPM@A@AEPAU12@XZ"
}
+
+namespace pr34302 {
+// C::f is lives in the vftable inside its virtual B subobject. In the MS ABI,
+// covariant return type virtual methods extend vftables from virtual bases,
+// even though that can make it impossible to implement certain diamond
+// hierarchies correctly.
+struct A { virtual ~A(); };
+struct B : A { virtual B *f(); };
+struct C : virtual B { C *f(); };
+C c;
+// VFTABLES-LABEL: VFTable indices for 'pr34302::C' (2 entries).
+// VFTABLES-NEXT: -- accessible via vbtable index 1, vfptr at offset 0 --
+// VFTABLES-NEXT: 0 | pr34302::C::~C() [scalar deleting]
+// VFTABLES-NEXT: 2 | pr34302::C *pr34302::C::f()
+}
diff --git a/test/CodeGenCXX/microsoft-inaccessible-base.cpp b/test/CodeGenCXX/microsoft-inaccessible-base.cpp
new file mode 100644
index 0000000000..2c0d124eb0
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-inaccessible-base.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fms-compatibility -triple x86_64-windows-msvc %s -emit-llvm -o - | FileCheck %s
+
+// Make sure we choose the *direct* base path when doing these conversions.
+
+// CHECK: %struct.C = type { %struct.A, %struct.B }
+// CHECK: %struct.D = type { %struct.B, %struct.A }
+
+struct A { int a; };
+struct B : A { int b; };
+
+struct C : A, B { };
+extern "C" A *a_from_c(C *p) { return p; }
+// CHECK-LABEL: define %struct.A* @a_from_c(%struct.C* %{{.*}})
+// CHECK: bitcast %struct.C* %{{.*}} to %struct.A*
+
+struct D : B, A { };
+extern "C" A *a_from_d(D *p) { return p; }
+// CHECK-LABEL: define %struct.A* @a_from_d(%struct.D* %{{.*}})
+// CHECK: %[[p_i8:[^ ]*]] = bitcast %struct.D* %{{.*}} to i8*
+// CHECK: getelementptr inbounds i8, i8* %[[p_i8]], i64 8
diff --git a/test/CodeGenCXX/ms-inline-asm-fields.cpp b/test/CodeGenCXX/ms-inline-asm-fields.cpp
index 6f329330bd..5ee6acf574 100644
--- a/test/CodeGenCXX/ms-inline-asm-fields.cpp
+++ b/test/CodeGenCXX/ms-inline-asm-fields.cpp
@@ -17,14 +17,14 @@ A a_global;
extern "C" int test_param_field(A p) {
// CHECK: define i32 @test_param_field(%struct.A* byval align 4 %p)
// CHECK: getelementptr inbounds %struct.A, %struct.A* %p, i32 0, i32 0
-// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $1"
+// CHECK: call i32 asm sideeffect inteldialect "mov eax, $1"
// CHECK: ret i32
__asm mov eax, p.a1
}
extern "C" int test_namespace_global() {
// CHECK: define i32 @test_namespace_global()
-// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $1", "{{.*}}"(i32* getelementptr inbounds (%struct.A, %struct.A* @_ZN4asdf8a_globalE, i32 0, i32 2, i32 1))
+// CHECK: call i32 asm sideeffect inteldialect "mov eax, $1", "{{.*}}"(i32* getelementptr inbounds (%struct.A, %struct.A* @_ZN4asdf8a_globalE, i32 0, i32 2, i32 1))
// CHECK: ret i32
__asm mov eax, asdf::a_global.a3.b2
}
diff --git a/test/CodeGenCXX/ms-inline-asm-return.cpp b/test/CodeGenCXX/ms-inline-asm-return.cpp
index 51671c0bcd..837f1b437a 100644
--- a/test/CodeGenCXX/ms-inline-asm-return.cpp
+++ b/test/CodeGenCXX/ms-inline-asm-return.cpp
@@ -70,7 +70,7 @@ FourChars f_s4() {
}
}
// CHECK-LABEL: define i32 @f_s4()
-// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, $$0x01010101", "={eax},~{eax},{{.*}}"
+// CHECK: %[[r:[^ ]*]] = call i32 asm sideeffect inteldialect "mov eax, $$16843009", "={eax},~{eax},{{.*}}"
// CHECK: store i32 %[[r]], i32* %{{.*}}
// CHECK: %[[r_i32:[^ ]*]] = load i32, i32* %{{.*}}
// CHECK: ret i32 %[[r_i32]]
@@ -85,7 +85,7 @@ EightChars f_s8() {
}
}
// CHECK-LABEL: define i64 @f_s8()
-// CHECK: %[[r:[^ ]*]] = call i64 asm sideeffect inteldialect "mov eax, $$01010101h\0A\09mov edx, $$01010101b", "=A,~{eax},{{.*}}"
+// CHECK: %[[r:[^ ]*]] = call i64 asm sideeffect inteldialect "mov eax, $$16843009\0A\09mov edx, $$85", "=A,~{eax},{{.*}}"
// CHECK: store i64 %[[r]], i64* %{{.*}}
// CHECK: %[[r_i64:[^ ]*]] = load i64, i64* %{{.*}}
// CHECK: ret i64 %[[r_i64]]
diff --git a/test/CodeGenCXX/ms-thread_local.cpp b/test/CodeGenCXX/ms-thread_local.cpp
index 5183ab5c32..dc7958d6ea 100644
--- a/test/CodeGenCXX/ms-thread_local.cpp
+++ b/test/CodeGenCXX/ms-thread_local.cpp
@@ -27,7 +27,5 @@ A f() {
return c;
}
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[link_opts:[0-9]+]]}
-// CHECK: ![[link_opts]] = !{![[dyn_tls_init:[0-9]+]]}
+// CHECK: !llvm.linker.options = !{![[dyn_tls_init:[0-9]+]]}
// CHECK: ![[dyn_tls_init]] = !{!"/include:___dyn_tls_init@12"}
diff --git a/test/CodeGenCXX/msabi-blocks.cpp b/test/CodeGenCXX/msabi-blocks.cpp
new file mode 100644
index 0000000000..bee59d9ed5
--- /dev/null
+++ b/test/CodeGenCXX/msabi-blocks.cpp
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -std=c++11 -fblocks -S -o - -emit-llvm %s | FileCheck %s -check-prefix CHECK-X86
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -std=c++11 -fblocks -S -o - -emit-llvm %s | FileCheck %s -check-prefix CHECK-X64
+
+extern int e(void);
+
+void (^b)() = ^{
+ static int i = 0;
+};
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke@@YAXPAU__block_literal@@@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke@@YAXPEAU__block_literal@@@Z@4HA" ={{.*}} global i32 0
+
+void f(void) {
+ static int i = 0;
+ ^{ static int i = e(); }();
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0
+
+ ^{ static int i = e(); }();
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_2@@YAXPAU__block_literal_2@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_2@@YAXPEAU__block_literal_2@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0
+
+ ^{ ^{ static int i = e(); }(); }();
+
+// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_3@@YAXPAU__block_literal_3@@@Z?1??_block_invoke_4@@YAXPAU__block_literal_4@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_3@@YAXPEAU__block_literal_3@@@Z?1??_block_invoke_4@@YAXPEAU__block_literal_4@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0
+}
+
+
+template <typename>
+void g(void) {
+ ^{ static int i = e(); }();
+}
+
+template void g<char>(void);
+
+// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2???$g@D@@YAXXZ@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2???$g@D@@YAXXZ@4HA" ={{.*}} global i32 0
+
+template void g<int>(void);
+
+// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2???$g@H@@YAXXZ@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2???$g@H@@YAXXZ@4HA" ={{.*}} global i32 0
+
+inline void h(void) {
+ ^{ static int i = e(); }();
+}
+
+// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2??h@@YAXXZ@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2??h@@YAXXZ@4HA" ={{.*}} global i32 0
+
+struct s {
+ int i = ^{ static int i = e(); return ++i; }();
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1@0s@@YAXPAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1@0s@@YAXPEAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0
+
+ int j = ^{ static int i = e(); return ++i; }();
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1@j@s@@YAXPAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1@j@s@@YAXPEAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0
+
+ void m(int i = ^{ static int i = e(); return ++i; }(),
+ int j = ^{ static int i = e(); return ++i; }()) {}
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPAU__block_literal_1_1@@@Z?0??m@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPAU__block_literal_1_2@@@Z?0??m@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPEAU__block_literal_1_1@@@Z?0??m@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPEAU__block_literal_1_2@@@Z?0??m@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0
+
+ void n(int = ^{ static int i = e(); return ++i; }(),
+ int = ^{ static int i = e(); return ++i; }()) {}
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPAU__block_literal_1_1@@@Z?0??n@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPAU__block_literal_1_2@@@Z?0??n@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPEAU__block_literal_1_1@@@Z?0??n@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPEAU__block_literal_1_2@@@Z?0??n@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0
+
+};
+
+struct t {
+ struct u {
+ int i = ^{ static int i = e(); return ++i; }();
+
+// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1@0u@t@@YAXPAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0
+// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1@0u@t@@YAXPEAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0
+
+ };
+};
+
+void j(void) {
+ h();
+ struct s s;
+ s.m();
+ s.n();
+ struct t::u t;
+}
+
+#if 0
+template <typename T>
+struct v {
+ static T i;
+};
+
+template <typename T>
+T v<T>::i = ^{ static T i = T(); return i; }();
+
+template class v<char>;
+template class v<int>;
+#endif
+
diff --git a/test/CodeGenCXX/noescape.cpp b/test/CodeGenCXX/noescape.cpp
new file mode 100644
index 0000000000..90d24de3da
--- /dev/null
+++ b/test/CodeGenCXX/noescape.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+struct S {
+ int a[4];
+ S(int *, int * __attribute__((noescape)));
+ S &operator=(int * __attribute__((noescape)));
+ void m0(int *, int * __attribute__((noescape)));
+ virtual void vm1(int *, int * __attribute__((noescape)));
+};
+
+// CHECK: define void @_ZN1SC2EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture)
+// CHECK: define void @_ZN1SC1EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture) {{.*}} {
+// CHECK: call void @_ZN1SC2EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}})
+
+S::S(int *, int * __attribute__((noescape))) {}
+
+// CHECK: define {{.*}} %struct.S* @_ZN1SaSEPi(%struct.S* {{.*}}, {{.*}} nocapture)
+S &S::operator=(int * __attribute__((noescape))) { return *this; }
+
+// CHECK: define void @_ZN1S2m0EPiS0_(%struct.S* {{.*}}, {{.*}} nocapture)
+void S::m0(int *, int * __attribute__((noescape))) {}
+
+// CHECK: define void @_ZN1S3vm1EPiS0_(%struct.S* {{.*}}, {{.*}} nocapture)
+void S::vm1(int *, int * __attribute__((noescape))) {}
+
+// CHECK-LABEL: define void @_Z5test0P1SPiS1_(
+// CHECK: call void @_ZN1SC1EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}})
+// CHECK: call {{.*}} %struct.S* @_ZN1SaSEPi(%struct.S* {{.*}}, {{.*}} nocapture {{.*}})
+// CHECK: call void @_ZN1S2m0EPiS0_(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}})
+// CHECK: call void {{.*}}(%struct.S* {{.*}}, {{.*}}, {{.*}} nocapture {{.*}})
+void test0(S *s, int *p0, int *p1) {
+ S t(p0, p1);
+ t = p1;
+ s->m0(p0, p1);
+ s->vm1(p0, p1);
+}
+
+namespace std {
+ typedef decltype(sizeof(0)) size_t;
+}
+
+// CHECK: define {{.*}} @_ZnwmPv({{.*}}, {{.*}} nocapture {{.*}})
+void *operator new(std::size_t, void * __attribute__((noescape)) p) {
+ return p;
+}
+
+// CHECK-LABEL: define i8* @_Z5test1Pv(
+// CHECK : %call = call {{.*}} @_ZnwmPv({{.*}}, {{.*}} nocapture {{.*}})
+void *test1(void *p0) {
+ return ::operator new(16, p0);
+}
+
+// CHECK-LABEL: define void @_Z5test2PiS_(
+// CHECK: call void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, {{.*}} nocapture {{.*}})
+// CHECK: define internal void @"_ZZ5test2PiS_ENK3$_0clES_S_"({{.*}}, {{.*}}, {{.*}} nocapture)
+void test2(int *p0, int *p1) {
+ auto t = [](int *, int * __attribute__((noescape))){};
+ t(p0, p1);
+}
+
+// CHECK-LABEL: define void @_Z5test3PFvU8noescapePiES_(
+// CHECK: call void {{.*}}(i32* nocapture {{.*}})
+typedef void (*NoEscapeFunc)(__attribute__((noescape)) int *);
+
+void test3(NoEscapeFunc f, int *p) {
+ f(p);
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index d02206abae..0f359b9c90 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-templates.cpp b/test/CodeGenCXX/optnone-templates.cpp
index 9f97d832c1..7884fa3989 100644
--- a/test/CodeGenCXX/optnone-templates.cpp
+++ b/test/CodeGenCXX/optnone-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple %itanium_abi_triple -std=c++11 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -std=c++11 -disable-O0-optnone -emit-llvm -o - | FileCheck %s
// Test optnone on template instantiations.
diff --git a/test/CodeGenCXX/pr29160.cpp b/test/CodeGenCXX/pr29160.cpp
new file mode 100644
index 0000000000..09cf2a6370
--- /dev/null
+++ b/test/CodeGenCXX/pr29160.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm
+//
+// This test's failure mode is running ~forever. (For some value of "forever"
+// that's greater than 25 minutes on my machine)
+
+template <typename... Ts>
+struct Foo {
+ template <typename... T>
+ static void ignore() {}
+ Foo() { ignore<Ts...>(); }
+};
+
+struct Base {
+ Base();
+ ~Base();
+};
+
+#define STAMP(thiz, prev) using thiz = Foo< \
+ prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, \
+ prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, \
+ prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev, prev \
+ >;
+STAMP(A, Base);
+STAMP(B, A);
+STAMP(C, B);
+STAMP(D, C);
+STAMP(E, D);
+STAMP(F, E);
+STAMP(G, F);
+STAMP(H, G);
+STAMP(I, H);
+STAMP(J, I);
+STAMP(K, J);
+STAMP(L, K);
+STAMP(M, L);
+STAMP(N, M);
+STAMP(O, N);
+STAMP(P, O);
+STAMP(Q, P);
+
+int main() { Q q; }
diff --git a/test/CodeGenCXX/pr33080.cpp b/test/CodeGenCXX/pr33080.cpp
new file mode 100644
index 0000000000..a744bca189
--- /dev/null
+++ b/test/CodeGenCXX/pr33080.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fms-extensions -emit-llvm -o- %s | FileCheck %s
+
+void fa(__unaligned struct A *) {}
+// CHECK: define void @_Z2faPU11__unaligned1A(
+
+void ga(struct A *, struct A *) {}
+// CHECK: define void @_Z2gaP1AS0_(
+
+void gb(__unaligned struct A *, struct A *) {}
+// CHECK: define void @_Z2gbPU11__unaligned1APS_(
+
+void gc(struct A *, __unaligned struct A *) {}
+// CHECK: define void @_Z2gcP1APU11__unalignedS_(
+
+void gd(__unaligned struct A *, __unaligned struct A *) {}
+// CHECK: define void @_Z2gdPU11__unaligned1AS1_(
+
+void hb(__unaligned struct A *, __unaligned const struct A *) {}
+// CHECK: define void @_Z2hbPU11__unaligned1APU11__unalignedKS_(
+
+void ja(__unaligned struct A *, __unaligned struct A *__unaligned *, __unaligned struct A *__unaligned *__unaligned *) {}
+// CHECK: define void @_Z2jaPU11__unaligned1APU11__unalignedS1_PU11__unalignedS3_(
+
+void jb(__unaligned struct A *, __unaligned struct A **, __unaligned struct A *__unaligned *__unaligned *) {}
+// CHECK: @_Z2jbPU11__unaligned1APS1_PU11__unalignedPU11__unalignedS1_(
+
+template <typename T, typename Q>
+void ta(T &, Q *) {}
+
+void ia(__unaligned struct A &a) {
+ ta(a, &a);
+}
+// CHECK: @_Z2taIU11__unaligned1AS1_EvRT_PT0_(
diff --git a/test/CodeGenCXX/pr34163.cpp b/test/CodeGenCXX/pr34163.cpp
new file mode 100644
index 0000000000..a200a0f509
--- /dev/null
+++ b/test/CodeGenCXX/pr34163.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -triple x86_64-linux-gnu -o - -x c++ %s | FileCheck %s
+
+void f(struct X *) {}
+
+// CHECK: @_ZTV1X =
+struct X {
+ void a() { delete this; }
+ virtual ~X() {}
+ virtual void key_function();
+};
+
+// CHECK: define {{.*}} @_ZN1X12key_functionEv(
+void X::key_function() {}
diff --git a/test/CodeGenCXX/regcall.cpp b/test/CodeGenCXX/regcall.cpp
index 0ff6fdf12a..2b7b9e2a6e 100644
--- a/test/CodeGenCXX/regcall.cpp
+++ b/test/CodeGenCXX/regcall.cpp
@@ -73,8 +73,8 @@ bool __regcall operator ==(const test_class&, const test_class&){ --x; return fa
// CHECK-WIN64-DAG: define x86_regcallcc zeroext i1 @"\01??8@Yw_NAEBVtest_class@@0@Z"
// CHECK-WIN32-DAG: define x86_regcallcc zeroext i1 @"\01??8@Yw_NABVtest_class@@0@Z"
-test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};}
-// CHECK-LIN64-DAG: define x86_regcallcc %class.test_class @_Zli11_test_classy(i64)
+test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};}
+// CHECK-LIN64-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* noalias sret %agg.result, i64)
// CHECK-LIN32-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* inreg noalias sret %agg.result, i64)
// CHECK-WIN64-DAG: \01??__K_test_class@@Yw?AVtest_class@@_K@Z"
// CHECK-WIN32-DAG: \01??__K_test_class@@Yw?AVtest_class@@_K@Z"
@@ -95,3 +95,11 @@ void force_gen() {
freeTempFunc(1);
t3.do_thing();
}
+
+long double _Complex __regcall foo(long double _Complex f) {
+ return f;
+}
+// CHECK-LIN64-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval align 16 %f)
+// CHECK-LIN32-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* inreg noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval align 4 %f)
+// CHECK-WIN64-DAG: define x86_regcallcc { double, double } @"\01?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1)
+// CHECK-WIN32-DAG: define x86_regcallcc { double, double } @"\01?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1)
diff --git a/test/CodeGenCXX/rtti-mingw64.cpp b/test/CodeGenCXX/rtti-mingw64.cpp
index 818b11b64b..9f3e03961e 100644
--- a/test/CodeGenCXX/rtti-mingw64.cpp
+++ b/test/CodeGenCXX/rtti-mingw64.cpp
@@ -2,7 +2,12 @@
struct A { int a; };
struct B : virtual A { int b; };
B b;
+class C {
+ virtual ~C();
+};
+C::~C() {}
+// CHECK: @_ZTI1C = linkonce_odr
// CHECK: @_ZTI1B = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64 }
// CHECK-SAME: i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*),
// CHECK-SAME: i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0),
diff --git a/test/CodeGenCXX/sanitize-dtor-callback.cpp b/test/CodeGenCXX/sanitize-dtor-callback.cpp
index e208a6f7e5..ecb0f2b2d1 100644
--- a/test/CodeGenCXX/sanitize-dtor-callback.cpp
+++ b/test/CodeGenCXX/sanitize-dtor-callback.cpp
@@ -55,16 +55,19 @@ Defaulted_Non_Trivial def_non_trivial;
// to confirm that all invoked dtors have member poisoning
// instrumentation inserted.
// CHECK-LABEL: define {{.*}}SimpleD2Ev
+// CHECK-NOT: store i{{[0-9]+}} 0, {{.*}}@__msan_param_tls
// CHECK: call void @__sanitizer_dtor_callback
// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
// CHECK-LABEL: define {{.*}}InlinedD2Ev
+// CHECK-NOT: store i{{[0-9]+}} 0, {{.*}}@__msan_param_tls
// CHECK: call void @__sanitizer_dtor_callback
// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
// CHECK-LABEL: define {{.*}}Defaulted_Non_TrivialD2Ev
+// CHECK-NOT: store i{{[0-9]+}} 0, {{.*}}@__msan_param_tls
// CHECK: call void @__sanitizer_dtor_callback
// CHECK-NOT: call void @__sanitizer_dtor_callback
// CHECK: ret void
diff --git a/test/CodeGenCXX/static-init-wasm.cpp b/test/CodeGenCXX/static-init-wasm.cpp
index 2d187b5c05..5f2f94fd85 100644
--- a/test/CodeGenCXX/static-init-wasm.cpp
+++ b/test/CodeGenCXX/static-init-wasm.cpp
@@ -20,7 +20,7 @@ void g() {
// WEBASSEMBLY32: %[[R0:.+]] = load atomic i8, i8* bitcast (i32* @_ZGVZ1gvE1a to i8*) acquire, align 4
// WEBASSEMBLY32-NEXT: %[[R1:.+]] = and i8 %[[R0]], 1
// WEBASSEMBLY32-NEXT: %[[R2:.+]] = icmp eq i8 %[[R1]], 0
-// WEBASSEMBLY32-NEXT: br i1 %[[R2]], label %[[CHECK:.+]], label %[[END:.+]]
+// WEBASSEMBLY32-NEXT: br i1 %[[R2]], label %[[CHECK:.+]], label %[[END:.+]],
// WEBASSEMBLY32: [[CHECK]]
// WEBASSEMBLY32: call i32 @__cxa_guard_acquire
// WEBASSEMBLY32: [[END]]
@@ -30,7 +30,7 @@ void g() {
// WEBASSEMBLY64: %[[R0:.+]] = load atomic i8, i8* bitcast (i64* @_ZGVZ1gvE1a to i8*) acquire, align 8
// WEBASSEMBLY64-NEXT: %[[R1:.+]] = and i8 %[[R0]], 1
// WEBASSEMBLY64-NEXT: %[[R2:.+]] = icmp eq i8 %[[R1]], 0
-// WEBASSEMBLY64-NEXT: br i1 %[[R2]], label %[[CHECK:.+]], label %[[END:.+]]
+// WEBASSEMBLY64-NEXT: br i1 %[[R2]], label %[[CHECK:.+]], label %[[END:.+]],
// WEBASSEMBLY64: [[CHECK]]
// WEBASSEMBLY64: call i32 @__cxa_guard_acquire
// WEBASSEMBLY64: [[END]]
@@ -43,12 +43,12 @@ struct A {
A theA;
-// WEBASSEMBLY32: define internal void @__cxx_global_var_init() #0 section ".text.__startup" {
+// WEBASSEMBLY32: define internal void @__cxx_global_var_init() #3 section ".text.__startup" {
// WEBASSEMBLY32: call %struct.A* @_ZN1AC1Ev(%struct.A* @theA)
-// WEBASSEMBLY32: define internal void @_GLOBAL__sub_I_static_init_wasm.cpp() #0 section ".text.__startup" {
+// WEBASSEMBLY32: define internal void @_GLOBAL__sub_I_static_init_wasm.cpp() #3 section ".text.__startup" {
// WEBASSEMBLY32: call void @__cxx_global_var_init()
//
-// WEBASSEMBLY64: define internal void @__cxx_global_var_init() #0 section ".text.__startup" {
+// WEBASSEMBLY64: define internal void @__cxx_global_var_init() #3 section ".text.__startup" {
// WEBASSEMBLY64: call %struct.A* @_ZN1AC1Ev(%struct.A* @theA)
-// WEBASSEMBLY64: define internal void @_GLOBAL__sub_I_static_init_wasm.cpp() #0 section ".text.__startup" {
+// WEBASSEMBLY64: define internal void @_GLOBAL__sub_I_static_init_wasm.cpp() #3 section ".text.__startup" {
// WEBASSEMBLY64: call void @__cxx_global_var_init()
diff --git a/test/CodeGenCXX/static-initializer-branch-weights.cpp b/test/CodeGenCXX/static-initializer-branch-weights.cpp
new file mode 100644
index 0000000000..f9e7781271
--- /dev/null
+++ b/test/CodeGenCXX/static-initializer-branch-weights.cpp
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -emit-llvm -std=c++1z %s -o - -triple=x86_64-linux-gnu | FileCheck %s
+
+struct S { S(); ~S(); };
+
+// CHECK-LABEL: define {{.*}}global_var_init
+// CHECK-NOT: br
+// CHECK: call void @_ZN1SC1Ev({{.*}}* @global)
+S global;
+
+// CHECK-LABEL: define {{.*}}global_var_init
+// FIXME: Do we really need thread-safe initialization here? We don't run
+// global ctors on multiple threads. (If we were to do so, we'd need thread-safe
+// init for B<int>::member and B<int>::inline_member too.)
+// CHECK: load atomic i8, i8* bitcast (i64* @_ZGV13inline_global to i8*) acquire,
+// CHECK: icmp eq i8 {{.*}}, 0
+// CHECK: br i1
+// CHECK-NOT: !prof
+// CHECK: call void @_ZN1SC1Ev({{.*}}* @inline_global)
+inline S inline_global;
+
+// CHECK-LABEL: define {{.*}}global_var_init
+// CHECK-NOT: br
+// CHECK: call void @_ZN1SC1Ev({{.*}}* @thread_local_global)
+thread_local S thread_local_global;
+
+// CHECK-LABEL: define {{.*}}global_var_init
+// CHECK: load i8, i8* bitcast (i64* @_ZGV26thread_local_inline_global to i8*)
+// CHECK: icmp eq i8 {{.*}}, 0
+// CHECK: br i1
+// CHECK-NOT: !prof
+// CHECK: call void @_ZN1SC1Ev({{.*}}* @thread_local_inline_global)
+thread_local inline S thread_local_inline_global;
+
+struct A {
+ static S member;
+ static thread_local S thread_local_member;
+
+ // CHECK-LABEL: define {{.*}}global_var_init
+ // CHECK: load atomic i8, i8* bitcast (i64* @_ZGVN1A13inline_memberE to i8*) acquire,
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1
+ // CHECK-NOT: !prof
+ // CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1A13inline_memberE)
+ static inline S inline_member;
+
+ // CHECK-LABEL: define {{.*}}global_var_init
+ // CHECK: load i8, i8* bitcast (i64* @_ZGVN1A26thread_local_inline_memberE to i8*)
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1
+ // CHECK-NOT: !prof
+ // CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1A26thread_local_inline_memberE)
+ static thread_local inline S thread_local_inline_member;
+};
+
+// CHECK-LABEL: define void @_Z1fv()
+void f() {
+ // CHECK: load atomic i8, i8* bitcast (i64* @_ZGVZ1fvE12static_local to i8*) acquire,
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1 {{.*}}, !prof ![[WEIGHTS_LOCAL:[0-9]*]]
+ static S static_local;
+
+ // CHECK: load i8, i8* @_ZGVZ1fvE19static_thread_local,
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1 {{.*}}, !prof ![[WEIGHTS_THREAD_LOCAL:[0-9]*]]
+ static thread_local S static_thread_local;
+}
+
+// CHECK-LABEL: define {{.*}}global_var_init
+// CHECK-NOT: br
+// CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1A6memberE)
+S A::member;
+
+// CHECK-LABEL: define {{.*}}global_var_init
+// CHECK-NOT: br
+// CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1A19thread_local_memberE)
+thread_local S A::thread_local_member;
+
+template <typename T> struct B {
+ // CHECK-LABEL: define {{.*}}global_var_init
+ // CHECK: load i8, i8* bitcast (i64* @_ZGVN1BIiE6memberE to i8*)
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1
+ // CHECK-NOT: !prof
+ // CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1BIiE6memberE)
+ static S member;
+
+ // CHECK-LABEL: define {{.*}}global_var_init
+ // CHECK: load i8, i8* bitcast (i64* @_ZGVN1BIiE13inline_memberE to i8*)
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1
+ // CHECK-NOT: !prof
+ // CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1BIiE13inline_memberE)
+ static inline S inline_member;
+
+ // CHECK-LABEL: define {{.*}}global_var_init
+ // CHECK: load i8, i8* bitcast (i64* @_ZGVN1BIiE19thread_local_memberE to i8*)
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1
+ // CHECK-NOT: !prof
+ // CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1BIiE19thread_local_memberE)
+ static thread_local S thread_local_member;
+
+ // CHECK-LABEL: define {{.*}}global_var_init
+ // CHECK: load i8, i8* bitcast (i64* @_ZGVN1BIiE26thread_local_inline_memberE to i8*)
+ // CHECK: icmp eq i8 {{.*}}, 0
+ // CHECK: br i1
+ // CHECK-NOT: !prof
+ // CHECK: call void @_ZN1SC1Ev({{.*}}* @_ZN1BIiE26thread_local_inline_memberE)
+ static thread_local inline S thread_local_inline_member;
+};
+template<typename T> S B<T>::member;
+template<typename T> thread_local S B<T>::thread_local_member;
+
+template<typename ...T> void use(T &...);
+void use_b() {
+ use(B<int>::member, B<int>::inline_member, B<int>::thread_local_member,
+ B<int>::thread_local_inline_member);
+}
+
+// CHECK-LABEL: define {{.*}}tls_init()
+// CHECK: load i8, i8* @__tls_guard, align 1
+// CHECK: icmp eq i8 {{.*}}, 0
+// CHECK: br i1 {{.*}}, !prof ![[WEIGHTS_THREAD_LOCAL]]
+
+// CHECK-DAG: ![[WEIGHTS_THREAD_LOCAL]] = !{!"branch_weights", i32 1, i32 1023}
+// CHECK-DAG: ![[WEIGHTS_LOCAL]] = !{!"branch_weights", i32 1, i32 1048575}
diff --git a/test/CodeGenCXX/std-byte.cpp b/test/CodeGenCXX/std-byte.cpp
new file mode 100644
index 0000000000..a3cc634221
--- /dev/null
+++ b/test/CodeGenCXX/std-byte.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++1z -Werror -triple i386-unknown-unknown -emit-llvm -O1 -disable-llvm-passes -o - %s | FileCheck %s
+
+// std::byte should be considered equivalent to char for aliasing.
+
+namespace std {
+enum byte : unsigned char {};
+}
+
+// CHECK-LABEL: define void @test0(
+extern "C" void test0(std::byte *sb, int *i) {
+ // CHECK: store i8 0, i8* %{{.*}} !tbaa [[TAG_CHAR:!.*]]
+ *sb = std::byte{0};
+
+ // CHECK: store i32 1, i32* %{{.*}} !tbaa [[TAG_INT:!.*]]
+ *i = 1;
+}
+
+enum byte : unsigned char {};
+namespace my {
+enum byte : unsigned char {};
+namespace std {
+enum byte : unsigned char {};
+} // namespace std
+} // namespace my
+
+// Make sure we don't get confused with other enums named 'byte'.
+
+// CHECK-LABEL: define void @test1(
+extern "C" void test1(::byte *b, ::my::byte *mb, ::my::std::byte *msb) {
+ *b = ::byte{0};
+ *mb = ::my::byte{0};
+ *msb = ::my::std::byte{0};
+ // CHECK-NOT: store i8 0, i8* %{{.*}} !tbaa [[TAG_CHAR]]
+}
+
+// CHECK: !"any pointer", [[TYPE_CHAR:!.*]],
+// CHECK: [[TYPE_CHAR]] = !{!"omnipotent char", [[TAG_CXX_TBAA:!.*]],
+// CHECK: [[TAG_CXX_TBAA]] = !{!"Simple C++ TBAA"}
+// CHECK: [[TAG_CHAR]] = !{[[TYPE_CHAR:!.*]], [[TYPE_CHAR]], i64 0}
+// CHECK: [[TAG_INT]] = !{[[TYPE_INT:!.*]], [[TYPE_INT]], i64 0}
+// CHECK: [[TYPE_INT]] = !{!"int", [[TYPE_CHAR]]
diff --git a/test/CodeGenCXX/stmtexpr.cpp b/test/CodeGenCXX/stmtexpr.cpp
index 5885a1663e..4586a3c38f 100644
--- a/test/CodeGenCXX/stmtexpr.cpp
+++ b/test/CodeGenCXX/stmtexpr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -Wno-unused-value -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Wno-unused-value -triple i686-linux-gnu -emit-llvm -o - %s | FileCheck %s
// rdar: //8540501
extern "C" int printf(...);
extern "C" void abort();
@@ -139,13 +139,41 @@ extern "C" int cleanup_exit_lvalue(bool cond) {
// CHECK: %[[v:[^ ]*]] = load i32*, i32** %[[tmp]]
// CHECK-NEXT: store i32* %[[v]], i32** %r
+// Bind the reference to a byval argument. It is not an instruction or Constant,
+// so it's a bit of a corner case.
+struct ByVal { int x[3]; };
+extern "C" int cleanup_exit_lvalue_byval(bool cond, ByVal arg) {
+ ByVal &r = (A(1), ({ if (cond) return 0; (void)ByVal(); }), arg);
+ return r.x[0];
+}
+// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue_byval({{.*}}, %struct.ByVal* byval align 4 %arg)
+// CHECK: call {{.*}} @_ZN1AC1Ei
+// CHECK: call {{.*}} @_ZN1AD1Ev
+// CHECK: switch
+// CHECK: store %struct.ByVal* %arg, %struct.ByVal** %r
+
+// Bind the reference to a local variable. We don't need to spill it. Binding a
+// reference to it doesn't generate any instructions.
+extern "C" int cleanup_exit_lvalue_local(bool cond) {
+ int local = 42;
+ int &r = (A(1), ({ if (cond) return 0; (void)0; }), local);
+ return r;
+}
+// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue_local({{.*}})
+// CHECK: %local = alloca i32
+// CHECK: store i32 42, i32* %local
+// CHECK: call {{.*}} @_ZN1AC1Ei
+// CHECK-NOT: store i32* %local
+// CHECK: call {{.*}} @_ZN1AD1Ev
+// CHECK: switch
+// CHECK: store i32* %local, i32** %r, align 4
// 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;
+ return (float)v;
}
// CHECK-LABEL: define{{.*}} i32 @cleanup_exit_complex({{.*}})
diff --git a/test/CodeGenCXX/strict-vtable-pointers.cpp b/test/CodeGenCXX/strict-vtable-pointers.cpp
index 21f85b1c57..c3798920ab 100644
--- a/test/CodeGenCXX/strict-vtable-pointers.cpp
+++ b/test/CodeGenCXX/strict-vtable-pointers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fstrict-vtable-pointers -disable-llvm-passes -O2 -emit-llvm -o %t.ll
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fstrict-vtable-pointers -std=c++11 -disable-llvm-passes -O2 -emit-llvm -o %t.ll
// RUN: FileCheck --check-prefix=CHECK-CTORS %s < %t.ll
// RUN: FileCheck --check-prefix=CHECK-NEW %s < %t.ll
// RUN: FileCheck --check-prefix=CHECK-DTORS %s < %t.ll
@@ -180,6 +180,119 @@ struct DynamicFromStatic;
// CHECK-CTORS-NOT: @llvm.invariant.group.barrier(
// CHECK-CTORS-LABEL: {{^}}}
+struct A {
+ virtual void foo();
+};
+struct B : A {
+ virtual void foo();
+};
+
+union U {
+ A a;
+ B b;
+};
+
+void changeToB(U *u);
+void changeToA(U *u);
+
+void g2(A *a) {
+ a->foo();
+}
+// We have to guard access to union fields with invariant.group, because
+// it is very easy to skip the barrier with unions. In this example the inlined
+// g2 will produce loads with the same !invariant.group metadata, and
+// u->a and u->b would use the same pointer.
+// CHECK-NEW-LABEL: define void @_Z14UnionsBarriersP1U
+void UnionsBarriers(U *u) {
+ // CHECK-NEW: call void @_Z9changeToBP1U(
+ changeToB(u);
+ // CHECK-NEW: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: call void @_Z2g2P1A(%struct.A*
+ g2(&u->b);
+ // CHECK-NEW: call void @_Z9changeToAP1U(%union.U*
+ changeToA(u);
+ // CHECK-NEW: call i8* @llvm.invariant.group.barrier(i8*
+ // call void @_Z2g2P1A(%struct.A* %a)
+ g2(&u->a);
+ // CHECK-NEW-NOT: call i8* @llvm.invariant.group.barrier(i8*
+}
+
+struct HoldingVirtuals {
+ A a;
+};
+
+struct Empty {};
+struct AnotherEmpty {
+ Empty e;
+};
+union NoVptrs {
+ int a;
+ AnotherEmpty empty;
+};
+void take(AnotherEmpty &);
+
+// CHECK-NEW-LABEL: noBarriers
+void noBarriers(NoVptrs &noVptrs) {
+ // CHECK-NEW-NOT: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: 42
+ noVptrs.a += 42;
+ // CHECK-NEW-NOT: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: call void @_Z4takeR12AnotherEmpty(
+ take(noVptrs.empty);
+}
+
+union U2 {
+ HoldingVirtuals h;
+ int z;
+};
+void take(HoldingVirtuals &);
+
+// CHECK-NEW-LABEL: define void @_Z15UnionsBarriers2R2U2
+void UnionsBarriers2(U2 &u) {
+ // CHECK-NEW-NOT: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: 42
+ u.z += 42;
+ // CHECK-NEW: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: call void @_Z4takeR15HoldingVirtuals(
+ take(u.h);
+}
+
+struct VirtualInBase : HoldingVirtuals, Empty {
+};
+
+struct VirtualInVBase : virtual Empty, virtual HoldingVirtuals {
+};
+
+// It has vtable by virtual inheritance.
+struct VirtualInheritance : virtual Empty {
+};
+
+union U3 {
+ VirtualInBase v1;
+ VirtualInBase v2;
+ VirtualInheritance v3;
+ int z;
+};
+
+void take(VirtualInBase &);
+void take(VirtualInVBase &);
+void take(VirtualInheritance &);
+
+void UnionsBarrier3(U3 &u) {
+ // CHECK-NEW-NOT: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: 42
+ u.z += 42;
+ // CHECK-NEW: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: call void @_Z4takeR13VirtualInBase(
+ take(u.v1);
+ // CHECK-NEW: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: call void @_Z4takeR13VirtualInBase(
+ take(u.v2);
+
+ // CHECK-NEW: call i8* @llvm.invariant.group.barrier(i8*
+ // CHECK-NEW: call void @_Z4takeR18VirtualInheritance(
+ take(u.v3);
+}
/** DTORS **/
// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN10StaticBaseD2Ev(
@@ -211,7 +324,7 @@ struct DynamicFromStatic;
// CHECK-DTORS-LABEL: {{^}}}
-// CHECK-LINK-REQ: !llvm.module.flags = !{![[FIRST:.*]], ![[SEC:.*]]{{.*}}}
+// CHECK-LINK-REQ: !llvm.module.flags = !{![[FIRST:[0-9]+]], ![[SEC:[0-9]+]]{{.*}}}
// CHECK-LINK-REQ: ![[FIRST]] = !{i32 1, !"StrictVTablePointers", i32 1}
// CHECK-LINK-REQ: ![[SEC]] = !{i32 3, !"StrictVTablePointersRequirement", ![[META:.*]]}
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
index 26e166c7bf..b4a0f9072e 100644
--- a/test/CodeGenCXX/thunks.cpp
+++ b/test/CodeGenCXX/thunks.cpp
@@ -401,5 +401,5 @@ D::~D() {}
// CHECK-OPT-LABEL: define linkonce_odr void @_ZN6Test101C3fooEv
// CHECK-OPT-LABEL: define linkonce_odr void @_ZThn8_N6Test101C3fooEv
-// CHECK-NONOPT: attributes [[NUW]] = { noinline nounwind uwtable{{.*}} }
+// CHECK-NONOPT: attributes [[NUW]] = { noinline nounwind optnone uwtable{{.*}} }
// CHECK-OPT: attributes [[NUW]] = { nounwind uwtable{{.*}} }
diff --git a/test/CodeGenCXX/tmp-md-nodes1.cpp b/test/CodeGenCXX/tmp-md-nodes1.cpp
new file mode 100644
index 0000000000..41a0159b0f
--- /dev/null
+++ b/test/CodeGenCXX/tmp-md-nodes1.cpp
@@ -0,0 +1,18 @@
+// REQUIRES: asserts
+// RUN: %clang_cc1 -O0 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm %s -o - | \
+// RUN: FileCheck %s
+
+// This test simply checks that the varargs thunk is created. The failing test
+// case asserts.
+
+struct Alpha {
+ virtual void bravo(...);
+};
+struct Charlie {
+ virtual ~Charlie() {}
+};
+struct CharlieImpl : Charlie, Alpha {
+ void bravo(...) {}
+} delta;
+
+// CHECK: define {{.*}} void @_ZThn{{[48]}}_N11CharlieImpl5bravoEz(
diff --git a/test/CodeGenCXX/tmp-md-nodes2.cpp b/test/CodeGenCXX/tmp-md-nodes2.cpp
new file mode 100644
index 0000000000..e50220cfb7
--- /dev/null
+++ b/test/CodeGenCXX/tmp-md-nodes2.cpp
@@ -0,0 +1,33 @@
+// REQUIRES: asserts
+// RUN: %clang_cc1 -O0 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm %s -o - | \
+// RUN: FileCheck %s
+
+// This test simply checks that the varargs thunk is created. The failing test
+// case asserts.
+
+typedef signed char __int8_t;
+typedef int BOOL;
+class CMsgAgent;
+
+class CFs {
+public:
+ typedef enum {} CACHE_HINT;
+ virtual BOOL ReqCacheHint( CMsgAgent* p_ma, CACHE_HINT hint, ... ) ;
+};
+
+typedef struct {} _Lldiv_t;
+
+class CBdVfs {
+public:
+ virtual ~CBdVfs( ) {}
+};
+
+class CBdVfsImpl : public CBdVfs, public CFs {
+ BOOL ReqCacheHint( CMsgAgent* p_ma, CACHE_HINT hint, ... );
+};
+
+BOOL CBdVfsImpl::ReqCacheHint( CMsgAgent* p_ma, CACHE_HINT hint, ... ) {
+ return true;
+}
+
+// CHECK: define {{.*}} @_ZThn{{[48]}}_N10CBdVfsImpl12ReqCacheHintEP9CMsgAgentN3CFs10CACHE_HINTEz(
diff --git a/test/CodeGenCXX/ubsan-devirtualized-calls.cpp b/test/CodeGenCXX/ubsan-devirtualized-calls.cpp
index bc8861aa83..f4ccdbf647 100644
--- a/test/CodeGenCXX/ubsan-devirtualized-calls.cpp
+++ b/test/CodeGenCXX/ubsan-devirtualized-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm -fsanitize=vptr %s -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s
struct Base1 {
virtual void f1() {}
@@ -64,6 +64,11 @@ void t4() {
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED3]] {{.*}}, i{{[0-9]+}} %[[P1]]
static_cast<Base1 *>(badp)->f1(); //< No devirt, test 'badp isa Base1'.
+ // We were able to skip the null check on the first type check because 'p'
+ // is backed by an alloca. We can't skip the second null check because 'badp'
+ // is a (bitcast (load ...)).
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ //
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint %struct.Base1* {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_BASE1]] {{.*}}, i{{[0-9]+}} %[[BADP1]]
}
@@ -76,6 +81,8 @@ void t5() {
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_1]] {{.*}}, i{{[0-9]+}} %[[P1]]
static_cast<Base1 *>(badp)->f1(); //< Devirt Base1::f1 to Derived4::f1.
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ //
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint %struct.Derived4* {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_2]] {{.*}}, i{{[0-9]+}} %[[BADP1]]
}
diff --git a/test/CodeGenCXX/ubsan-global-alignment.cpp b/test/CodeGenCXX/ubsan-global-alignment.cpp
new file mode 100644
index 0000000000..67fcfd469a
--- /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-nullability-assign.cpp b/test/CodeGenCXX/ubsan-nullability-assign.cpp
new file mode 100644
index 0000000000..3f85c88d6e
--- /dev/null
+++ b/test/CodeGenCXX/ubsan-nullability-assign.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -x c++ -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=nullability-assign | FileCheck %s
+
+struct S1 {
+ int *_Nonnull p;
+};
+
+struct S2 {
+ S1 s1;
+};
+
+union U1 {
+ S1 s1;
+ S2 s2;
+};
+
+// CHECK-LABEL: define void @{{.*}}f1
+void f1(int *p) {
+ U1 u;
+
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}} !nosanitize
+ // CHECK: store
+ u.s1.p = p;
+
+ // CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
+ // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_type_mismatch{{.*}} !nosanitize
+ // CHECK: store
+ u.s2.s1.p = p;
+
+ // CHECK-NOT: __ubsan_handle_type_mismatch
+ // CHECK-NOT: store
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/ubsan-suppress-checks.cpp b/test/CodeGenCXX/ubsan-suppress-checks.cpp
new file mode 100644
index 0000000000..fa7ea29d94
--- /dev/null
+++ b/test/CodeGenCXX/ubsan-suppress-checks.cpp
@@ -0,0 +1,244 @@
+// 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
+
+// CHECK-LABEL: define void @_Z22load_non_null_pointersv
+void load_non_null_pointers() {
+ int var;
+ var = *&var;
+
+ int arr[1];
+ arr[0] = arr[0];
+
+ char c = "foo"[0];
+
+ // CHECK-NOT: and i64 {{.*}}, !nosanitize
+ // CHECK-NOT: icmp ne {{.*}}, null, !nosanitize
+ // CHECK: ret void
+}
+
+// CHECK-LABEL: define void @_Z31use_us16_aligned_array_elementsv
+void use_us16_aligned_array_elements() {
+ static const unsigned short Arr[] = {0, 1, 2};
+ auto use_array = [](const unsigned short(&X)[3]) -> void {};
+ use_array(Arr);
+
+ // CHECK-NOT: br i1 true
+ // ALIGN-NOT: call void @__ubsan_handle_type_mismatch
+ // CHECK: ret void
+}
+
+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-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_memberEPS_
+ static int load_member(B *bp) {
+ // 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
+ return static_cast<A *>(*bp)->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(nullptr);
+
+ Base *b = new Derived;
+ b->load_member_1();
+
+ Derived *d;
+ d->load_member_2();
+ d->load_member_3();
+
+ load_non_null_pointers();
+ use_us16_aligned_array_elements();
+}
diff --git a/test/CodeGenCXX/ubsan-suppress-null-checks.cpp b/test/CodeGenCXX/ubsan-suppress-null-checks.cpp
deleted file mode 100644
index 967c08195f..0000000000
--- a/test/CodeGenCXX/ubsan-suppress-null-checks.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null -DCHECK_LAMBDA | FileCheck %s --check-prefix=LAMBDA
-
-struct A {
- int foo;
-
- // CHECK-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv
- void do_nothing() {
- // CHECK: icmp ne %struct.A* %[[THIS1:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.A* %[[THIS1]] to i64, !nosanitize
- // CHECK-NEXT: 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: ptrtoint %struct.A* %[[THIS2]] to i64, !nosanitize
- // LAMBDA-NEXT: call void @__ubsan_handle_type_mismatch
-
- auto f = [&] {
- foo = 0;
- };
- f();
-
- // 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() {
- // CHECK: icmp ne %struct.A* %[[THIS3:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.A* %[[THIS3]] to i64, !nosanitize
- // CHECK-NEXT: 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() {
- // CHECK: icmp ne %struct.A* %[[THIS4:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.A* %[[THIS4]] to i64, !nosanitize
- // CHECK-NEXT: 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() {
- // CHECK: icmp ne %struct.A* %[[THIS5:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.A* %[[THIS5]] to i64, !nosanitize
- // CHECK-NEXT: 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() {
- // CHECK: icmp ne %struct.A* %[[THIS6:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.A* %[[THIS6]] to i64, !nosanitize
- // CHECK-NEXT: 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 {
- // CHECK: icmp ne %struct.A* %[[THIS7:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.A* %[[THIS7]] to i64, !nosanitize
- // CHECK-NEXT: 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) {
- // CHECK-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() {
- // Null-check &b before converting it to an A*.
- // CHECK: call void @__ubsan_handle_type_mismatch
- //
- // Null-check the result of the conversion before using it.
- // CHECK: 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() {
- // CHECK: icmp ne %struct.Derived* %[[THIS8:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.Derived* %[[THIS8]] to i64, !nosanitize
- // CHECK-NEXT: call void @__ubsan_handle_type_mismatch
- //
- // Null-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() {
- // CHECK: icmp ne %struct.Derived* %[[THIS9:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.Derived* %[[THIS9]] to i64, !nosanitize
- // CHECK-NEXT: 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 {
- // CHECK: icmp ne %struct.Derived* %[[THIS10:[a-z0-9]+]], null, !nosanitize
- // CHECK: ptrtoint %struct.Derived* %[[THIS10]] to i64, !nosanitize
- // CHECK-NEXT: 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
index b2cd475a6c..e53ab2466e 100644
--- a/test/CodeGenCXX/ubsan-type-checks.cpp
+++ b/test/CodeGenCXX/ubsan-type-checks.cpp
@@ -1,12 +1,13 @@
// 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
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null,vptr | FileCheck %s -check-prefixes=VPTR
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=vptr | FileCheck %s -check-prefixes=VPTR_NO_NULL
struct A {
// COMMON-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv
void do_nothing() {
// ALIGN-NOT: ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
- // ALIGN-NOT: and i64 %{{.*}}, 7, !nosanitize
// NULL: icmp ne %struct.A* %{{.*}}, null, !nosanitize
@@ -14,7 +15,71 @@ struct A {
}
};
-void force_irgen() {
+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
+ // OBJSIZE: ret void
+ }
+};
+
+struct Animal {
+ virtual const char *speak() = 0;
+};
+
+struct Cat : Animal {
+ const char *speak() override { return "meow"; }
+};
+
+struct Dog : Animal {
+ const char *speak() override { return "woof"; }
+};
+
+// VPTR-LABEL: define void @_Z12invalid_castP3Cat
+void invalid_cast(Cat *cat = nullptr) {
+ // If -fsanitize=null is available, we'll reuse its check:
+ //
+ // VPTR: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null
+ // VPTR-NEXT: br i1 [[ICMP]]
+ // VPTR: call void @__ubsan_handle_type_mismatch
+ // VPTR-NOT: icmp ne %struct.Dog* {{.*}}, null
+ // VPTR: br i1 [[ICMP]]
+ // VPTR: call void @__ubsan_handle_dynamic_type_cache_miss
+ //
+ // Fall back to the vptr sanitizer's null check when -fsanitize=null isn't
+ // available.
+ //
+ // VPTR_NO_NULL-NOT: call void @__ubsan_handle_type_mismatch
+ // VPTR_NO_NULL: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null
+ // VPTR_NO_NULL-NEXT: br i1 [[ICMP]]
+ // VPTR_NO_NULL: call void @__ubsan_handle_dynamic_type_cache_miss
+ auto *badDog = reinterpret_cast<Dog *>(cat);
+ badDog->speak();
+}
+
+// VPTR_NO_NULL-LABEL: define void @_Z13invalid_cast2v
+void invalid_cast2() {
+ // We've got a pointer to an alloca, so there's no run-time null check needed.
+ // VPTR_NO_NULL-NOT: call void @__ubsan_handle_type_mismatch
+ // VPTR_NO_NULL: call void @__ubsan_handle_dynamic_type_cache_miss
+ Cat cat;
+ cat.speak();
+}
+
+int main() {
A a;
a.do_nothing();
+
+ B b;
+ b.do_nothing();
+
+ invalid_cast();
+ return 0;
}
diff --git a/test/CodeGenCXX/ubsan-vtable-checks.cpp b/test/CodeGenCXX/ubsan-vtable-checks.cpp
index e684ae9180..5e17913a2c 100644
--- a/test/CodeGenCXX/ubsan-vtable-checks.cpp
+++ b/test/CodeGenCXX/ubsan-vtable-checks.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NULL --check-prefix=ITANIUM
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NULL --check-prefix=MSABI
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=vptr %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VPTR --check-prefix=ITANIUM
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=vptr %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VPTR --check-prefix=MSABI
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VPTR --check-prefix=ITANIUM
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VPTR --check-prefix=MSABI
struct T {
virtual ~T() {}
virtual int v() { return 1; }
diff --git a/test/CodeGenCXX/unaligned-member-qualifier.cpp b/test/CodeGenCXX/unaligned-member-qualifier.cpp
new file mode 100644
index 0000000000..0d326a6668
--- /dev/null
+++ b/test/CodeGenCXX/unaligned-member-qualifier.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fms-extensions -emit-llvm %s -o- | FileCheck %s
+
+struct A {
+ void foo() __unaligned;
+ void foo() const __unaligned;
+ void foo() volatile __unaligned;
+ void foo() const volatile __unaligned;
+};
+
+void A::foo() __unaligned {}
+// CHECK: define [[THISCALL:(x86_thiscallcc )?]]void @_ZNU11__unaligned1A3fooEv(
+
+void A::foo() const __unaligned {}
+// CHECK: define [[THISCALL]]void @_ZNU11__unalignedK1A3fooEv(
+
+void A::foo() volatile __unaligned {}
+// CHECK: define [[THISCALL]]void @_ZNU11__unalignedV1A3fooEv(
+
+void A::foo() const volatile __unaligned {}
+// CHECK: define [[THISCALL]]void @_ZNU11__unalignedVK1A3fooEv(
diff --git a/test/CodeGenCXX/uncopyable-args.cpp b/test/CodeGenCXX/uncopyable-args.cpp
index 307a5cf11b..66d67e4a34 100644
--- a/test/CodeGenCXX/uncopyable-args.cpp
+++ b/test/CodeGenCXX/uncopyable-args.cpp
@@ -1,5 +1,8 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s | FileCheck %s -check-prefix=WIN64
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=NEWABI
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=OLDABI
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-scei-ps4 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=OLDABI
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s -fms-compatibility -fms-compatibility-version=18 | FileCheck %s -check-prefix=WIN64 -check-prefix=WIN64-18
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s -fms-compatibility -fms-compatibility-version=19 | FileCheck %s -check-prefix=WIN64 -check-prefix=WIN64-19
namespace trivial {
// Trivial structs should be passed directly.
@@ -52,12 +55,13 @@ void foo(A);
void bar() {
foo({});
}
-// FIXME: The copy ctor is implicitly deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN9move_ctor3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
+// CHECK-LABEL: define void @_ZN9move_ctor3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// NEWABI: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
+// OLDABI: call void @_ZN9move_ctor3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
+// OLDABI-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(i8*)
// WIN64-LABEL: declare void @"\01?foo@move_ctor@@YAXUA@1@@Z"(%"struct.move_ctor::A"*)
}
@@ -73,12 +77,13 @@ void foo(A);
void bar() {
foo({});
}
-// FIXME: The copy ctor is deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN11all_deleted3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
+// CHECK-LABEL: define void @_ZN11all_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// NEWABI: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
+// OLDABI: call void @_ZN11all_deleted3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
+// OLDABI-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(i8*)
// WIN64-LABEL: declare void @"\01?foo@all_deleted@@YAXUA@1@@Z"(%"struct.all_deleted::A"*)
}
@@ -93,14 +98,17 @@ void foo(A);
void bar() {
foo({});
}
-// FIXME: The copy and move ctors are implicitly deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN18implicitly_deleted3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
-
-// WIN64-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)
+// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// NEWABI: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})
+// OLDABI: call void @_ZN18implicitly_deleted3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
+// OLDABI-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(i8*)
+
+// In MSVC 2013, the copy ctor is not deleted by a move assignment. In MSVC 2015, it is.
+// WIN64-18-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(i64
+// WIN64-19-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)
}
namespace one_deleted {
@@ -113,12 +121,13 @@ void foo(A);
void bar() {
foo({});
}
-// FIXME: The copy constructor is implicitly deleted.
-// CHECK-DISABLED-LABEL: define void @_ZN11one_deleted3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED-NOT: call
-// CHECK-DISABLED: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
+// CHECK-LABEL: define void @_ZN11one_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// NEWABI: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
+// OLDABI: call void @_ZN11one_deleted3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
+// OLDABI-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(i8*)
// WIN64-LABEL: declare void @"\01?foo@one_deleted@@YAXUA@1@@Z"(%"struct.one_deleted::A"*)
}
@@ -195,12 +204,12 @@ void foo(B);
void bar() {
foo({});
}
-// FIXME: This class has a non-trivial copy ctor and a trivial copy ctor. It's
-// not clear whether we should pass by address or in registers.
-// CHECK-DISABLED-LABEL: define void @_ZN14two_copy_ctors3barEv()
-// CHECK-DISABLED: call void @_Z{{.*}}C1Ev(
-// CHECK-DISABLED: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
-// CHECK-DISABLED-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
+// CHECK-LABEL: define void @_ZN14two_copy_ctors3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// NEWABI: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
+// OLDABI: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* byval
+// NEWABI-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
+// OLDABI-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* byval
// WIN64-LABEL: declare void @"\01?foo@two_copy_ctors@@YAXUB@1@@Z"(%"struct.two_copy_ctors::B"*)
}
@@ -212,6 +221,8 @@ struct A {
void *p;
};
void *foo(A a) { return a.p; }
+// NEWABI-LABEL: define i8* @_ZN15definition_only3fooENS_1AE(%"struct.definition_only::A"*
+// OLDABI-LABEL: define i8* @_ZN15definition_only3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@definition_only@@YAPEAXUA@1@@Z"(%"struct.definition_only::A"*
}
@@ -226,6 +237,8 @@ struct A {
B b;
};
void *foo(A a) { return a.b.p; }
+// NEWABI-LABEL: define i8* @_ZN17deleted_by_member3fooENS_1AE(%"struct.deleted_by_member::A"*
+// OLDABI-LABEL: define i8* @_ZN17deleted_by_member3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_member@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member::A"*
}
@@ -239,6 +252,8 @@ struct A : B {
A();
};
void *foo(A a) { return a.p; }
+// NEWABI-LABEL: define i8* @_ZN15deleted_by_base3fooENS_1AE(%"struct.deleted_by_base::A"*
+// OLDABI-LABEL: define i8* @_ZN15deleted_by_base3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_base@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base::A"*
}
@@ -253,6 +268,8 @@ struct A {
B b;
};
void *foo(A a) { return a.b.p; }
+// NEWABI-LABEL: define i8* @_ZN22deleted_by_member_copy3fooENS_1AE(%"struct.deleted_by_member_copy::A"*
+// OLDABI-LABEL: define i8* @_ZN22deleted_by_member_copy3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_member_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member_copy::A"*
}
@@ -266,6 +283,8 @@ struct A : B {
A();
};
void *foo(A a) { return a.p; }
+// NEWABI-LABEL: define i8* @_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*
+// OLDABI-LABEL: define i8* @_ZN20deleted_by_base_copy3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_base_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base_copy::A"*
}
@@ -275,6 +294,77 @@ struct A {
A(const A &o) = delete;
void *p;
};
+// NEWABI-LABEL: define i8* @_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*
+// OLDABI-LABEL: define i8* @_ZN15explicit_delete3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@explicit_delete@@YAPEAXUA@1@@Z"(%"struct.explicit_delete::A"*
void *foo(A a) { return a.p; }
}
+
+namespace implicitly_deleted_copy_ctor {
+struct A {
+ // No move ctor due to copy assignment.
+ A &operator=(const A&);
+ // Deleted copy ctor due to rvalue ref member.
+ int &&ref;
+};
+// NEWABI-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(%"struct.implicitly_deleted_copy_ctor::A"*
+// OLDABI-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(i32*
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAAEAHUA@1@@Z"(%"struct.implicitly_deleted_copy_ctor::A"*
+int &foo(A a) { return a.ref; }
+
+struct B {
+ // Passed direct: has non-deleted trivial copy ctor.
+ B &operator=(const B&);
+ int &ref;
+};
+int &foo(B b) { return b.ref; }
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1BE(i32*
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAAEAHUB@1@@Z"(i64
+
+struct X { X(const X&); };
+struct Y { Y(const Y&) = default; };
+
+union C {
+ C &operator=(const C&);
+ // Passed indirect: copy ctor deleted due to variant member with nontrivial copy ctor.
+ X x;
+ int n;
+};
+int foo(C c) { return c.n; }
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1CE(%"union.implicitly_deleted_copy_ctor::C"*
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHTC@1@@Z"(%"union.implicitly_deleted_copy_ctor::C"*
+
+struct D {
+ D &operator=(const D&);
+ // Passed indirect: copy ctor deleted due to variant member with nontrivial copy ctor.
+ union {
+ X x;
+ int n;
+ };
+};
+int foo(D d) { return d.n; }
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1DE(%"struct.implicitly_deleted_copy_ctor::D"*
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHUD@1@@Z"(%"struct.implicitly_deleted_copy_ctor::D"*
+
+union E {
+ // Passed direct: has non-deleted trivial copy ctor.
+ E &operator=(const E&);
+ Y y;
+ int n;
+};
+int foo(E e) { return e.n; }
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1EE(i32
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHTE@1@@Z"(i32
+
+struct F {
+ // Passed direct: has non-deleted trivial copy ctor.
+ F &operator=(const F&);
+ union {
+ Y y;
+ int n;
+ };
+};
+int foo(F f) { return f.n; }
+// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1FE(i32
+// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAHUF@1@@Z"(i32
+}
diff --git a/test/CodeGenCXX/union-tbaa2.cpp b/test/CodeGenCXX/union-tbaa2.cpp
new file mode 100644
index 0000000000..d3e37408c4
--- /dev/null
+++ b/test/CodeGenCXX/union-tbaa2.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 %s -O2 -std=c++11 -triple x86_64-unknown-linux-gnu -target-cpu x86-64 -target-feature +sse4.2 -target-feature +avx -emit-llvm -o - | FileCheck %s
+
+// Testcase from llvm.org/PR32056
+
+extern "C" int printf (const char *__restrict __format, ...);
+
+typedef double __m256d __attribute__((__vector_size__(32)));
+
+static __inline __m256d __attribute__((__always_inline__, __nodebug__,
+ __target__("avx")))
+_mm256_setr_pd(double __a, double __b, double __c, double __d) {
+ return (__m256d){ __a, __b, __c, __d };
+}
+
+struct A {
+ A () {
+// Check that the TBAA information generated for the stores to the
+// union members is based on the omnipotent char.
+// CHECK: store <4 x double>
+// CHECK: tbaa ![[OCPATH:[0-9]+]]
+// CHECK: store <4 x double>
+// CHECK: tbaa ![[OCPATH]]
+// CHECK: call
+ a = _mm256_setr_pd(0.0, 1.0, 2.0, 3.0);
+ b = _mm256_setr_pd(4.0, 5.0, 6.0, 7.0);
+ }
+
+ const double *begin() { return c; }
+ const double *end() { return c+8; }
+
+ union {
+ struct { __m256d a, b; };
+ double c[8];
+ };
+};
+
+int main(int argc, char *argv[]) {
+ A a;
+ for (double value : a)
+ printf("%f ", value);
+ return 0;
+}
+
+// CHECK-DAG: ![[CHAR:[0-9]+]] = !{!"omnipotent char"
+// CHECK-DAG: ![[OCPATH]] = !{![[CHAR]], ![[CHAR]], i64 0}
diff --git a/test/CodeGenCXX/virt-dtor-key.cpp b/test/CodeGenCXX/virt-dtor-key.cpp
index 40c5a537cc..d1055d4e30 100644
--- a/test/CodeGenCXX/virt-dtor-key.cpp
+++ b/test/CodeGenCXX/virt-dtor-key.cpp
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-windows-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MINGW
// CHECK: @_ZTI3foo = constant
+// CHECK-MINGW: @_ZTI3foo = linkonce_odr
class foo {
foo();
virtual ~foo();
diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp
index 6ea234807e..20e4a1f45e 100644
--- a/test/CodeGenCXX/visibility-inlines-hidden.cpp
+++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp
@@ -162,3 +162,16 @@ namespace test6 {
C::g();
}
}
+
+namespace PR34811 {
+ template <typename T> void tf() {}
+
+ // CHECK-LABEL: define linkonce_odr hidden i8* @_ZN7PR348111fEv(
+ inline void *f() {
+ auto l = []() {};
+ // CHECK-LABEL: define linkonce_odr hidden void @_ZN7PR348112tfIZNS_1fEvEUlvE_EEvv(
+ return (void *)&tf<decltype(l)>;
+ }
+
+ void *p = (void *)f;
+}
diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp
index 4e22bba7d7..b8652f8329 100644
--- a/test/CodeGenCXX/vla.cpp
+++ b/test/CodeGenCXX/vla.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck -check-prefixes=X64,CHECK %s
+// RUN: %clang_cc1 -std=c++11 -triple amdgcn---amdgiz %s -emit-llvm -o - | FileCheck -check-prefixes=AMD,CHECK %s
template<typename T>
struct S {
@@ -9,7 +10,7 @@ template<typename T> int S<T>::n = 5;
int f() {
// Make sure that the reference here is enough to trigger the instantiation of
// the static data member.
- // CHECK: @_ZN1SIiE1nE = linkonce_odr global i32 5
+ // CHECK: @_ZN1SIiE1nE = linkonce_odr{{.*}} global i32 5
int a[S<int>::n];
return sizeof a;
}
@@ -17,10 +18,18 @@ int f() {
// rdar://problem/9506377
void test0(void *array, int n) {
// CHECK-LABEL: define void @_Z5test0Pvi(
- // CHECK: [[ARRAY:%.*]] = alloca i8*, align 8
- // CHECK-NEXT: [[N:%.*]] = alloca i32, align 4
- // CHECK-NEXT: [[REF:%.*]] = alloca i16*, align 8
- // CHECK-NEXT: [[S:%.*]] = alloca i16, align 2
+ // X64: [[ARRAY:%.*]] = alloca i8*, align 8
+ // AMD: [[ARRAY0:%.*]] = alloca i8*, align 8, addrspace(5)
+ // AMD-NEXT: [[ARRAY:%.*]] = addrspacecast i8* addrspace(5)* [[ARRAY0]] to i8**
+ // X64-NEXT: [[N:%.*]] = alloca i32, align 4
+ // AMD: [[N0:%.*]] = alloca i32, align 4, addrspace(5)
+ // AMD-NEXT: [[N:%.*]] = addrspacecast i32 addrspace(5)* [[N0]] to i32*
+ // X64-NEXT: [[REF:%.*]] = alloca i16*, align 8
+ // AMD: [[REF0:%.*]] = alloca i16*, align 8, addrspace(5)
+ // AMD-NEXT: [[REF:%.*]] = addrspacecast i16* addrspace(5)* [[REF0]] to i16**
+ // X64-NEXT: [[S:%.*]] = alloca i16, align 2
+ // AMD: [[S0:%.*]] = alloca i16, align 2, addrspace(5)
+ // AMD-NEXT: [[S:%.*]] = addrspacecast i16 addrspace(5)* [[S0]] to i16*
// CHECK-NEXT: store i8*
// CHECK-NEXT: store i32
@@ -54,3 +63,66 @@ void test0(void *array, int n) {
// CHECK-NEXT: ret void
}
+
+
+void test2(int b) {
+ // CHECK-LABEL: define void {{.*}}test2{{.*}}(i32 %b)
+ int varr[b];
+ // AMD: %__end = alloca i32*, align 8, addrspace(5)
+ // AMD: [[END:%.*]] = addrspacecast i32* addrspace(5)* %__end to i32**
+ // get the address of %b by checking the first store that stores it
+ //CHECK: store i32 %b, i32* [[PTR_B:%.*]]
+
+ // get the size of the VLA by getting the first load of the PTR_B
+ //CHECK: [[VLA_NUM_ELEMENTS_PREZEXT:%.*]] = load i32, i32* [[PTR_B]]
+ //CHECK-NEXT: [[VLA_NUM_ELEMENTS_PRE:%.*]] = zext i32 [[VLA_NUM_ELEMENTS_PREZEXT]]
+
+ b = 15;
+ //CHECK: store i32 15, i32* [[PTR_B]]
+
+ // Now get the sizeof, and then divide by the element size
+
+
+ //CHECK: [[VLA_SIZEOF:%.*]] = mul nuw i64 4, [[VLA_NUM_ELEMENTS_PRE]]
+ //CHECK-NEXT: [[VLA_NUM_ELEMENTS_POST:%.*]] = udiv i64 [[VLA_SIZEOF]], 4
+ //CHECK-NEXT: [[VLA_END_PTR:%.*]] = getelementptr inbounds i32, i32* {{%.*}}, i64 [[VLA_NUM_ELEMENTS_POST]]
+ //X64-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+ //AMD-NEXT: store i32* [[VLA_END_PTR]], i32** [[END]]
+ for (int d : varr) 0;
+}
+
+void test3(int b, int c) {
+ // CHECK-LABEL: define void {{.*}}test3{{.*}}(i32 %b, i32 %c)
+ int varr[b][c];
+ // AMD: %__end = alloca i32*, align 8, addrspace(5)
+ // AMD: [[END:%.*]] = addrspacecast i32* addrspace(5)* %__end to i32**
+ // get the address of %b by checking the first store that stores it
+ //CHECK: store i32 %b, i32* [[PTR_B:%.*]]
+ //CHECK-NEXT: store i32 %c, i32* [[PTR_C:%.*]]
+
+ // get the size of the VLA by getting the first load of the PTR_B
+ //CHECK: [[VLA_DIM1_PREZEXT:%.*]] = load i32, i32* [[PTR_B]]
+ //CHECK-NEXT: [[VLA_DIM1_PRE:%.*]] = zext i32 [[VLA_DIM1_PREZEXT]]
+ //CHECK: [[VLA_DIM2_PREZEXT:%.*]] = load i32, i32* [[PTR_C]]
+ //CHECK-NEXT: [[VLA_DIM2_PRE:%.*]] = zext i32 [[VLA_DIM2_PREZEXT]]
+
+ b = 15;
+ c = 15;
+ //CHECK: store i32 15, i32* [[PTR_B]]
+ //CHECK: store i32 15, i32* [[PTR_C]]
+ // Now get the sizeof, and then divide by the element size
+
+ // multiply the two dimensions, then by the element type and then divide by the sizeof dim2
+ //CHECK: [[VLA_DIM1_X_DIM2:%.*]] = mul nuw i64 [[VLA_DIM1_PRE]], [[VLA_DIM2_PRE]]
+ //CHECK-NEXT: [[VLA_SIZEOF:%.*]] = mul nuw i64 4, [[VLA_DIM1_X_DIM2]]
+ //CHECK-NEXT: [[VLA_SIZEOF_DIM2:%.*]] = mul nuw i64 4, [[VLA_DIM2_PRE]]
+ //CHECK-NEXT: [[VLA_NUM_ELEMENTS:%.*]] = udiv i64 [[VLA_SIZEOF]], [[VLA_SIZEOF_DIM2]]
+ //CHECK-NEXT: [[VLA_END_INDEX:%.*]] = mul nsw i64 [[VLA_NUM_ELEMENTS]], [[VLA_DIM2_PRE]]
+ //CHECK-NEXT: [[VLA_END_PTR:%.*]] = getelementptr inbounds i32, i32* {{%.*}}, i64 [[VLA_END_INDEX]]
+ //X64-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+ //AMD-NEXT: store i32* [[VLA_END_PTR]], i32** [[END]]
+
+ for (auto &d : varr) 0;
+}
+
+
diff --git a/test/CodeGenCXX/vtable-available-externally.cpp b/test/CodeGenCXX/vtable-available-externally.cpp
index ae81959a75..2e2cdbbfef 100644
--- a/test/CodeGenCXX/vtable-available-externally.cpp
+++ b/test/CodeGenCXX/vtable-available-externally.cpp
@@ -12,6 +12,7 @@
// RUN: FileCheck --check-prefix=CHECK-TEST14 %s < %t.opt
// RUN: FileCheck --check-prefix=CHECK-TEST15 %s < %t.opt
// RUN: FileCheck --check-prefix=CHECK-TEST16 %s < %t.opt
+// RUN: FileCheck --check-prefix=CHECK-TEST17 %s < %t.opt
#include <typeinfo>
@@ -274,9 +275,8 @@ struct C {
virtual D& operator=(const D&);
};
-// Cannot emit B's vtable available_externally, because we cannot create
-// a reference to the inline virtual B::operator= function.
-// CHECK-TEST11: @_ZTVN6Test111DE = external unnamed_addr constant
+// Can emit D's vtable available_externally.
+// CHECK-TEST11: @_ZTVN6Test111DE = available_externally unnamed_addr constant
struct D : C {
virtual void key();
};
@@ -391,3 +391,30 @@ void test() {
}
}
+namespace Test17 {
+// This test checks if we emit vtables opportunistically.
+// CHECK-TEST17-DAG: @_ZTVN6Test171AE = available_externally
+// CHECK-TEST17-DAG: @_ZTVN6Test171BE = external
+
+struct A {
+ virtual void key();
+ virtual void bar() {}
+};
+
+// We won't gonna use deleting destructor for this type, which will disallow
+// emitting vtable as available_externally
+struct B {
+ virtual void key();
+ virtual ~B() {}
+};
+
+void testcaseA() {
+ A a;
+ a.bar(); // this forces to emit definition of bar
+}
+
+void testcaseB() {
+ B b; // This only forces emitting of complete object destructor
+}
+
+} // namespace Test17
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index c4ebf75b99..0c55eb26f7 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -145,12 +145,14 @@ void use_F() {
// F<int> is an explicit template instantiation declaration without a
// key function, so its vtable should have external linkage.
// CHECK-DAG: @_ZTV1FIiE = external unnamed_addr constant
-// CHECK-OPT-DAG: @_ZTV1FIiE = external unnamed_addr constant
+// CHECK-OPT-DAG: @_ZTV1FIiE = available_externally unnamed_addr constant
// E<int> is an explicit template instantiation declaration. It has a
// key function is not instantiated, so we know that vtable definition
// will be generated in TU where key function will be defined
-// so we can mark it as available_externally (only with optimizations)
+// so we can mark it as external (without optimizations) and
+// available_externally (with optimizations) because all of the inline
+// virtual functions have been emitted.
// CHECK-DAG: @_ZTV1EIiE = external unnamed_addr constant
// CHECK-OPT-DAG: @_ZTV1EIiE = available_externally unnamed_addr constant
diff --git a/test/CodeGenCXX/warn-padded-packed.cpp b/test/CodeGenCXX/warn-padded-packed.cpp
index f2af60865e..2cb0495373 100644
--- a/test/CodeGenCXX/warn-padded-packed.cpp
+++ b/test/CodeGenCXX/warn-padded-packed.cpp
@@ -17,7 +17,7 @@ struct S3 {
} __attribute__((packed));
struct S4 {
- int i; // expected-warning {{packed attribute is unnecessary for 'i'}}
+ int i;
char c;
} __attribute__((packed));
@@ -46,18 +46,18 @@ struct S8 : B {
int i; // expected-warning {{padding struct 'S8' with 3 bytes to align 'i'}}
};
-struct S9 { // expected-warning {{packed attribute is unnecessary for 'S9'}}
- int x; // expected-warning {{packed attribute is unnecessary for 'x'}}
- int y; // expected-warning {{packed attribute is unnecessary for 'y'}}
+struct S9 {
+ int x;
+ int y;
} __attribute__((packed));
-struct S10 { // expected-warning {{packed attribute is unnecessary for 'S10'}}
- int x; // expected-warning {{packed attribute is unnecessary for 'x'}}
+struct S10 {
+ int x;
char a,b,c,d;
} __attribute__((packed));
-struct S11 {
+struct S11 { // expected-warning {{packed attribute is unnecessary for 'S11'}}
bool x;
char a,b,c,d;
} __attribute__((packed));
@@ -72,5 +72,82 @@ struct S13 { // expected-warning {{padding size of 'S13' with 6 bits to alignmen
bool b : 10;
};
+struct S14 { // expected-warning {{packed attribute is unnecessary for 'S14'}}
+ char a,b,c,d;
+} __attribute__((packed));
+
+struct S15 { // expected-warning {{packed attribute is unnecessary for 'S15'}}
+ struct S14 s;
+ char a;
+} __attribute__((packed));
+
+struct S16 { // expected-warning {{padding size of 'S16' with 2 bytes to alignment boundary}} expected-warning {{packed attribute is unnecessary for 'S16'}}
+ char a,b;
+} __attribute__((packed, aligned(4)));
+
+struct S17 {
+ struct S16 s;
+ char a,b;
+} __attribute__((packed, aligned(2)));
+
+struct S18 { // expected-warning {{padding size of 'S18' with 2 bytes to alignment boundary}} expected-warning {{packed attribute is unnecessary for 'S18'}}
+ struct S16 s;
+ char a,b;
+} __attribute__((packed, aligned(4)));
+
+struct S19 { // expected-warning {{packed attribute is unnecessary for 'S19'}}
+ bool b;
+ char a;
+} __attribute__((packed, aligned(1)));
+
+struct S20 {
+ int i;
+ char a;
+} __attribute__((packed, aligned(1)));
+
+struct S21 { // expected-warning {{padding size of 'S21' with 4 bits to alignment boundary}}
+ unsigned char a : 6;
+ unsigned char b : 6;
+} __attribute__((packed, aligned(1)));
+
+struct S22 { // expected-warning {{packed attribute is unnecessary for 'S22'}}
+ unsigned char a : 4;
+ unsigned char b : 4;
+} __attribute__((packed));
+
+struct S23 { // expected-warning {{padding size of 'S23' with 4 bits to alignment boundary}} expected-warning {{packed attribute is unnecessary for 'S23'}}
+ unsigned char a : 2;
+ unsigned char b : 2;
+} __attribute__((packed));
+
+struct S24 {
+ unsigned char a : 6;
+ unsigned char b : 6;
+ unsigned char c : 6;
+ unsigned char d : 6;
+ unsigned char e : 6;
+ unsigned char f : 6;
+ unsigned char g : 6;
+ unsigned char h : 6;
+} __attribute__((packed));
+
+struct S25 { // expected-warning {{padding size of 'S25' with 7 bits to alignment boundary}} expected-warning {{packed attribute is unnecessary for 'S25'}}
+ unsigned char a;
+ unsigned char b : 1;
+} __attribute__((packed));
+
+struct S26 { // expected-warning {{packed attribute is unnecessary for 'S26'}}
+ unsigned char a : 1;
+ unsigned char b; //expected-warning {{padding struct 'S26' with 7 bits to align 'b'}}
+} __attribute__((packed));
+
+struct S27 { // expected-warning {{padding size of 'S27' with 7 bits to alignment boundary}}
+ unsigned char a : 1;
+ unsigned char b : 8;
+} __attribute__((packed));
+
+
// The warnings are emitted when the layout of the structs is computed, so we have to use them.
-void f(S1*, S2*, S3*, S4*, S5*, S6*, S7*, S8*, S9*, S10*, S11*, S12*, S13*) { }
+void f(S1*, S2*, S3*, S4*, S5*, S6*, S7*, S8*, S9*, S10*, S11*, S12*, S13*,
+ S14*, S15*, S16*, S17*, S18*, S19*, S20*, S21*, S22*, S23*, S24*, S25*,
+ S26*, S27*){}
diff --git a/test/CodeGenCXX/windows-itanium-dllexport.cpp b/test/CodeGenCXX/windows-itanium-dllexport.cpp
index 92cca24442..ff780c7778 100644
--- a/test/CodeGenCXX/windows-itanium-dllexport.cpp
+++ b/test/CodeGenCXX/windows-itanium-dllexport.cpp
@@ -1,5 +1,10 @@
// RUN: %clang_cc1 -emit-llvm -triple i686-windows-itanium -fdeclspec %s -o - | FileCheck %s
+#define JOIN2(x, y) x##y
+#define JOIN(x, y) JOIN2(x, y)
+#define UNIQ(name) JOIN(name, __LINE__)
+#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; }
+
struct __declspec(dllexport) s {
void f() {}
};
@@ -28,3 +33,23 @@ template class __declspec(dllexport) c<double>;
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
+
+template <class T>
+struct outer {
+ void f() {}
+ struct inner {
+ void f() {}
+ };
+};
+
+template class __declspec(dllexport) outer<int>;
+
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
+
+extern template class __declspec(dllimport) outer<char>;
+USEMEMFUNC(outer<char>, f)
+USEMEMFUNC(outer<char>::inner, f)
+
+// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv
+// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv
diff --git a/test/CodeGenCXX/windows-itanium-type-info.cpp b/test/CodeGenCXX/windows-itanium-type-info.cpp
index ad89318f59..285b59815d 100644
--- a/test/CodeGenCXX/windows-itanium-type-info.cpp
+++ b/test/CodeGenCXX/windows-itanium-type-info.cpp
@@ -32,9 +32,15 @@ void f() {
// CHECK-DAG: @_ZTV7derived = dllexport unnamed_addr constant
// CHECK-DAG: @_ZTI4base = external dllimport constant
-// CHECK-DAG: @_ZTS4base = external dllimport constant
-// CHECK-NOT: @_ZTV4base = external dllimport constant
// CHECK-EH-IMPORT: @_ZTS4base = linkonce_odr constant
// CHECK-EH-IMPORT: @_ZTI4base = linkonce_odr constant
+struct __declspec(dllimport) gatekeeper {};
+struct zuul : gatekeeper {
+ virtual ~zuul();
+};
+zuul::~zuul() {}
+
+// CHECK-DAG: @_ZTI10gatekeeper = linkonce_odr constant
+// CHECK-DAG: @_ZTS10gatekeeper = linkonce_odr constant
diff --git a/test/CodeGenCoroutines/Inputs/coroutine.h b/test/CodeGenCoroutines/Inputs/coroutine.h
new file mode 100644
index 0000000000..d58212b1d5
--- /dev/null
+++ b/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -0,0 +1,80 @@
+#pragma once
+
+namespace std { namespace experimental { inline namespace coroutines_v1 {
+
+template <typename R, typename...> struct coroutine_traits {
+ using promise_type = typename R::promise_type;
+};
+
+template <typename Promise = void> struct coroutine_handle;
+
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *addr) noexcept {
+ coroutine_handle me;
+ me.ptr = addr;
+ return me;
+ }
+ void operator()() { resume(); }
+ void *address() const { return ptr; }
+ void resume() const { __builtin_coro_resume(ptr); }
+ void destroy() const { __builtin_coro_destroy(ptr); }
+ bool done() const { return __builtin_coro_done(ptr); }
+ coroutine_handle &operator=(decltype(nullptr)) {
+ ptr = nullptr;
+ return *this;
+ }
+ coroutine_handle(decltype(nullptr)) : ptr(nullptr) {}
+ coroutine_handle() : ptr(nullptr) {}
+// void reset() { ptr = nullptr; } // add to P0057?
+ explicit operator bool() const { return ptr; }
+
+protected:
+ void *ptr;
+};
+
+template <typename Promise> struct coroutine_handle : coroutine_handle<> {
+ using coroutine_handle<>::operator=;
+
+ static coroutine_handle from_address(void *addr) noexcept {
+ coroutine_handle me;
+ me.ptr = addr;
+ return me;
+ }
+
+ Promise &promise() const {
+ return *reinterpret_cast<Promise *>(
+ __builtin_coro_promise(ptr, alignof(Promise), false));
+ }
+ static coroutine_handle from_promise(Promise &promise) {
+ coroutine_handle p;
+ p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true);
+ return p;
+ }
+};
+
+ template <typename _PromiseT>
+ bool operator==(coroutine_handle<_PromiseT> const& _Left,
+ coroutine_handle<_PromiseT> const& _Right) noexcept
+ {
+ return _Left.address() == _Right.address();
+ }
+
+ template <typename _PromiseT>
+ bool operator!=(coroutine_handle<_PromiseT> const& _Left,
+ coroutine_handle<_PromiseT> const& _Right) noexcept
+ {
+ return !(_Left == _Right);
+ }
+
+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() {}
+};
+
+}}}
diff --git a/test/CodeGenCoroutines/coro-alloc.cpp b/test/CodeGenCoroutines/coro-alloc.cpp
index c795e27326..820201db35 100644
--- a/test/CodeGenCoroutines/coro-alloc.cpp
+++ b/test/CodeGenCoroutines/coro-alloc.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \
+// RUN: -Wno-coroutine-missing-unhandled-exception -emit-llvm %s -o - -disable-llvm-passes \
+// RUN: | FileCheck %s
namespace std {
namespace experimental {
@@ -19,8 +21,19 @@ struct coroutine_handle<void> {
coroutine_handle(coroutine_handle<PromiseType>) {}
};
-}
-}
+} // end namespace experimental
+
+struct nothrow_t {};
+constexpr nothrow_t nothrow = {};
+
+} // end namespace std
+
+// Required when get_return_object_on_allocation_failure() is defined by
+// the promise.
+using SizeT = decltype(sizeof(int));
+void* operator new(SizeT __sz, const std::nothrow_t&) noexcept;
+void operator delete(void* __p, const std::nothrow_t&) noexcept;
+
struct suspend_always {
bool await_ready() { return false; }
@@ -40,15 +53,31 @@ 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: %[[NeedAlloc:.+]] = call i1 @llvm.coro.alloc(token %[[ID]])
+ // CHECK: br i1 %[[NeedAlloc]], label %[[AllocBB:.+]], label %[[InitBB:.+]]
+
+ // CHECK: [[AllocBB]]:
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
- // CHECK: call i8* @_Znwm(i64 %[[SIZE]])
+ // CHECK: %[[MEM:.+]] = call i8* @_Znwm(i64 %[[SIZE]])
+ // CHECK: br label %[[InitBB]]
+
+ // CHECK: [[InitBB]]:
+ // CHECK: %[[PHI:.+]] = phi i8* [ null, %{{.+}} ], [ %call, %[[AllocBB]] ]
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(token %[[ID]], i8* %[[PHI]])
- // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
+ // CHECK: %[[NeedDealloc:.+]] = icmp ne i8* %[[MEM]], null
+ // CHECK: br i1 %[[NeedDealloc]], label %[[FreeBB:.+]], label %[[Afterwards:.+]]
+
+ // CHECK: [[FreeBB]]:
// CHECK: call void @_ZdlPv(i8* %[[MEM]])
+ // CHECK: br label %[[Afterwards]]
+
+ // CHECK: [[Afterwards]]:
+ // CHECK: ret void
co_return;
}
@@ -65,13 +94,13 @@ 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()
// CHECK: call i8* @_ZNSt12experimental16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 %[[SIZE]])
- // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: call void @_ZdlPv(i8* %[[MEM]])
co_return;
@@ -90,13 +119,13 @@ 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()
// CHECK: call i8* @_Znwm(i64 %[[SIZE]])
- // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
// CHECK: call void @_ZNSt12experimental16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* %[[MEM]])
co_return;
@@ -121,9 +150,46 @@ extern "C" void f3(promise_sized_delete_tag) {
// CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
// CHECK: call i8* @_Znwm(i64 %[[SIZE]])
- // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
// 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_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() { return 0; }
+ 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: %[[RetVal:.+]] = alloca i32
+ // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
+ // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
+ // CHECK: %[[MEM:.+]] = call i8* @_ZnwmRKSt9nothrow_t(i64 %[[SIZE]], %"struct.std::nothrow_t"* dereferenceable(1) @_ZStL7nothrow)
+ // CHECK: %[[OK:.+]] = icmp ne i8* %[[MEM]], null
+ // CHECK: br i1 %[[OK]], label %[[OKBB:.+]], label %[[ERRBB:.+]]
+
+ // CHECK: [[ERRBB]]:
+ // CHECK: %[[FailRet:.+]] = call i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv(
+ // CHECK: store i32 %[[FailRet]], i32* %[[RetVal]]
+ // CHECK: br label %[[RetBB:.+]]
+
+ // CHECK: [[OKBB]]:
+ // CHECK: %[[OkRet:.+]] = call i32 @_ZNSt12experimental16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv(
+ // CHECK: store i32 %[[OkRet]], i32* %[[RetVal]]
+
+ // CHECK: [[RetBB]]:
+ // CHECK: %[[LoadRet:.+]] = load i32, i32* %[[RetVal]], align 4
+ // CHECK: ret i32 %[[LoadRet]]
+ co_return;
+}
diff --git a/test/CodeGenCoroutines/coro-await-domination.cpp b/test/CodeGenCoroutines/coro-await-domination.cpp
new file mode 100644
index 0000000000..5df22374a6
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-await-domination.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - | FileCheck %s
+#include "Inputs/coroutine.h"
+
+using namespace std::experimental;
+
+struct coro {
+ struct promise_type {
+ coro get_return_object();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ void return_void();
+ static void unhandled_exception();
+ };
+};
+
+struct A {
+ ~A();
+ bool await_ready();
+ int await_resume() { return 8; }
+ template <typename F> void await_suspend(F);
+};
+
+extern "C" void consume(int);
+
+// Verifies that domination is properly built during cleanup.
+// Without CGCleanup.cpp fix verifier was reporting:
+// Instruction does not dominate all uses!
+// %tmp.exprcleanup = alloca i32*, align 8
+// store i32* %x, i32** %tmp.exprcleanup, align 8
+
+
+// CHECK-LABEL: f(
+extern "C" coro f(int) {
+ int x = 42;
+ x = co_await A{};
+ consume(x);
+}
+
diff --git a/test/CodeGenCoroutines/coro-await.cpp b/test/CodeGenCoroutines/coro-await.cpp
new file mode 100644
index 0000000000..41881d7123
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,346 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 \
+// RUN: -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | 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 *);
+ void *address();
+};
+
+template <typename Promise>
+struct coroutine_handle : coroutine_handle<> {
+ static coroutine_handle from_address(void *);
+};
+
+}
+}
+
+struct init_susp {
+ bool await_ready();
+ void await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+struct final_susp {
+ bool await_ready();
+ void await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+
+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();
+ init_susp initial_suspend();
+ final_susp final_suspend();
+ void return_void();
+ };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
+
+ // See if initial_suspend was issued:
+ // ----------------------------------
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
+ // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
+ // CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save(
+ // CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false)
+
+ 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: 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]])
+
+ // See if final_suspend was issued:
+ // ----------------------------------
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
+ // CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
+ // CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save(
+ // CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true)
+}
+
+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();
+ init_susp initial_suspend();
+ final_susp final_suspend();
+ void return_void();
+ suspend_maybe yield_value(int);
+ };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+ // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits<void, int>::promise_type"
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
+ co_yield 42;
+ // 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: 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 %
+}
+
+// CHECK-LABEL: EndlessLoop(
+extern "C" void EndlessLoop() {
+ // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
+
+ // See if initial_suspend was issued:
+ // ----------------------------------
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
+ // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
+
+ for (;;)
+ co_await suspend_always{};
+
+ // Verify that final_suspend was NOT issued:
+ // ----------------------------------
+ // CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type13final_suspendEv(
+ // CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
+}
+
+// Verifies that we don't crash when awaiting on an lvalue.
+// CHECK-LABEL: @_Z11AwaitLValuev(
+void AwaitLValue() {
+ suspend_always lval;
+ co_await lval;
+}
+
+struct RefTag { };
+
+struct AwaitResumeReturnsLValue {
+ bool await_ready();
+ void await_suspend(std::experimental::coroutine_handle<>);
+ RefTag& await_resume();
+};
+
+
+template<>
+struct std::experimental::coroutine_traits<void,double> {
+ struct promise_type {
+ void get_return_object();
+ init_susp initial_suspend();
+ final_susp final_suspend();
+ void return_void();
+ AwaitResumeReturnsLValue yield_value(int);
+ };
+};
+
+// Verifies that we don't crash when returning an lvalue from an await_resume()
+// expression.
+// CHECK-LABEL: define void @_Z18AwaitReturnsLValued(double)
+void AwaitReturnsLValue(double) {
+ AwaitResumeReturnsLValue a;
+ // CHECK: %[[AVAR:.+]] = alloca %struct.AwaitResumeReturnsLValue,
+ // CHECK: %[[XVAR:.+]] = alloca %struct.RefTag*,
+
+ // CHECK: %[[YVAR:.+]] = alloca %struct.RefTag*,
+ // CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue,
+
+ // CHECK: %[[ZVAR:.+]] = alloca %struct.RefTag*,
+ // CHECK-NEXT: %[[TMP2:.+]] = alloca %struct.AwaitResumeReturnsLValue,
+
+ // CHECK: %[[RES1:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[AVAR]])
+ // CHECK-NEXT: store %struct.RefTag* %[[RES1]], %struct.RefTag** %[[XVAR]],
+ RefTag& x = co_await a;
+
+ // CHECK: %[[RES2:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP1]])
+ // CHECK-NEXT: store %struct.RefTag* %[[RES2]], %struct.RefTag** %[[YVAR]],
+
+ RefTag& y = co_await AwaitResumeReturnsLValue{};
+ // CHECK: %[[RES3:.+]] = call dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* %[[TMP2]])
+ // CHECK-NEXT: store %struct.RefTag* %[[RES3]], %struct.RefTag** %[[ZVAR]],
+ RefTag& z = co_yield 42;
+}
+
+struct TailCallAwait {
+ bool await_ready();
+ std::experimental::coroutine_handle<> await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+
+// CHECK-LABEL: @TestTailcall(
+extern "C" void TestTailcall() {
+ co_await TailCallAwait{};
+
+ // CHECK: %[[RESULT:.+]] = call i8* @_ZN13TailCallAwait13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.TailCallAwait*
+ // CHECK: %[[COERCE:.+]] = getelementptr inbounds %"struct.std::experimental::coroutine_handle", %"struct.std::experimental::coroutine_handle"* %[[TMP:.+]], i32 0, i32 0
+ // CHECK: store i8* %[[RESULT]], i8** %[[COERCE]]
+ // CHECK: %[[ADDR:.+]] = call i8* @_ZNSt12experimental16coroutine_handleIvE7addressEv(%"struct.std::experimental::coroutine_handle"* %[[TMP]])
+ // CHECK: call void @llvm.coro.resume(i8* %[[ADDR]])
+}
diff --git a/test/CodeGenCoroutines/coro-builtins.c b/test/CodeGenCoroutines/coro-builtins.c
index d18d5e730f..9ec2147642 100644
--- a/test/CodeGenCoroutines/coro-builtins.c
+++ b/test/CodeGenCoroutines/coro-builtins.c
@@ -2,7 +2,7 @@
void *myAlloc(long long);
-// CHECK-LABEL: f(
+// CHECK-LABEL: f(
void f(int n) {
// CHECK: %n.addr = alloca i32
// CHECK: %n_copy = alloca i32
@@ -19,31 +19,25 @@ void f(int n) {
// CHECK-NEXT: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
// CHECK-NEXT: %[[MEM:.+]] = call i8* @myAlloc(i64 %[[SIZE]])
- // CHECK-NEXT: %[[BEG:.+]] = call i8* @llvm.coro.begin(token %[[COROID]], i8* %[[MEM]])
+ // CHECK-NEXT: %[[FRAME:.+]] = call i8* @llvm.coro.begin(token %[[COROID]], i8* %[[MEM]])
__builtin_coro_begin(myAlloc(__builtin_coro_size()));
- // CHECK-NEXT: %[[FRAME1:.+]] = call i8* @llvm.coro.frame()
- // CHECK-NEXT: call void @llvm.coro.resume(i8* %[[FRAME1]])
+ // CHECK-NEXT: call void @llvm.coro.resume(i8* %[[FRAME]])
__builtin_coro_resume(__builtin_coro_frame());
- // CHECK-NEXT: %[[FRAME2:.+]] = call i8* @llvm.coro.frame()
- // CHECK-NEXT: call void @llvm.coro.destroy(i8* %[[FRAME2]])
+ // CHECK-NEXT: call void @llvm.coro.destroy(i8* %[[FRAME]])
__builtin_coro_destroy(__builtin_coro_frame());
- // CHECK-NEXT: %[[FRAME3:.+]] = call i8* @llvm.coro.frame()
- // CHECK-NEXT: call i1 @llvm.coro.done(i8* %[[FRAME3]])
+ // CHECK-NEXT: call i1 @llvm.coro.done(i8* %[[FRAME]])
__builtin_coro_done(__builtin_coro_frame());
- // CHECK-NEXT: %[[FRAME4:.+]] = call i8* @llvm.coro.frame()
- // CHECK-NEXT: call i8* @llvm.coro.promise(i8* %[[FRAME4]], i32 48, i1 false)
+ // CHECK-NEXT: call i8* @llvm.coro.promise(i8* %[[FRAME]], i32 48, i1 false)
__builtin_coro_promise(__builtin_coro_frame(), 48, 0);
- // CHECK-NEXT: %[[FRAME5:.+]] = call i8* @llvm.coro.frame()
- // CHECK-NEXT: call i8* @llvm.coro.free(token %[[COROID]], i8* %[[FRAME5]])
+ // CHECK-NEXT: call i8* @llvm.coro.free(token %[[COROID]], i8* %[[FRAME]])
__builtin_coro_free(__builtin_coro_frame());
- // CHECK-NEXT: %[[FRAME6:.+]] = call i8* @llvm.coro.frame()
- // CHECK-NEXT: call i1 @llvm.coro.end(i8* %[[FRAME6]], i1 false)
+ // CHECK-NEXT: call i1 @llvm.coro.end(i8* %[[FRAME]], 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 0000000000..ba1246979e
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-cleanup.cpp
@@ -0,0 +1,97 @@
+// 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 *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) noexcept;
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+}
+
+struct suspend_always {
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<void> {
+ struct promise_type {
+ void get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ promise_type();
+ ~promise_type();
+ void unhandled_exception() noexcept;
+ };
+};
+
+struct Cleanup { ~Cleanup(); };
+void may_throw();
+
+// CHECK-LABEL: 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:.+]]
+
+ // CHECK: [[DeallocPad]]:
+ // CHECK-NEXT: landingpad
+ // CHECK-NEXT: cleanup
+ // CHECK: br label %[[Dealloc:.+]]
+
+ 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 %[[CatchPad:.+]]
+
+ // CHECK: [[CatchPad]]:
+ // CHECK-NEXT: landingpad
+ // CHECK-NEXT: catch i8* null
+ // CHECK: call void @_ZN7CleanupD1Ev(
+ // CHECK: br label %[[Catch:.+]]
+
+ // CHECK: [[Catch]]:
+ // CHECK: call i8* @__cxa_begin_catch(
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type19unhandled_exceptionEv(
+ // CHECK: invoke void @__cxa_end_catch()
+ // CHECK-NEXT: to label %[[Cont:.+]] unwind
+
+ // CHECK: [[Cont]]:
+ // CHECK-NEXT: br label %[[Cont2:.+]]
+ // CHECK: [[Cont2]]:
+ // CHECK-NEXT: br label %[[Cleanup:.+]]
+
+ // CHECK: [[Cleanup]]:
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_typeD1Ev(
+ // CHECK: %[[Mem0:.+]] = call i8* @llvm.coro.free(
+ // CHECK: call void @_ZdlPv(i8* %[[Mem0]]
+
+ // CHECK: [[Dealloc]]:
+ // CHECK: %[[Mem:.+]] = call i8* @llvm.coro.free(
+ // CHECK: call void @_ZdlPv(i8* %[[Mem]])
+
+ co_return;
+}
+
+// CHECK-LABEL: define void @_Z1gv(
+void g() {
+ for (;;)
+ co_await suspend_always{};
+ // Since this is the endless loop there should be no fallthrough handler (call to 'return_void').
+ // CHECK-NOT: call void @_ZNSt12experimental16coroutine_traitsIJvEE12promise_type11return_voidEv
+}
diff --git a/test/CodeGenCoroutines/coro-eh-cleanup.cpp b/test/CodeGenCoroutines/coro-eh-cleanup.cpp
new file mode 100644
index 0000000000..5a3ecd1da4
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-eh-cleanup.cpp
@@ -0,0 +1,86 @@
+// 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 %{{.+}} unwind label %[[CATCHDISPATCH:.+]]
+
+// CHECK: [[CATCHDISPATCH]]:
+// CHECK: catchswitch within none [label %[[CATCHPAD:.+]]] unwind label %[[COROENDBB:.+]]
+// CHECK: [[CATCHPAD]]:
+// CHECK: call void @"\01?unhandled_exception@promise_type@coro_t@@QEAAXXZ"
+
+// 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: catch
+// CHECK-LPAD: call void @_ZN7CleanupD1Ev(
+// CHECK-LPAD: call i8* @__cxa_begin_catch
+// CHECK-LPAD: call void @_ZN6coro_t12promise_type19unhandled_exceptionEv
+// CHECK-LPAD: invoke void @__cxa_end_catch()
+// CHECK-LPAD: to label %{{.+}} unwind label %[[UNWINDBB:.+]]
+
+// CHECK-LPAD: [[UNWINDBB]]:
+// 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-gro.cpp b/test/CodeGenCoroutines/coro-gro.cpp
new file mode 100644
index 0000000000..95bf206972
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-gro.cpp
@@ -0,0 +1,86 @@
+// Verifies lifetime of __gro local variable
+// 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 -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 *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) noexcept;
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+}
+
+struct suspend_always {
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
+};
+
+struct GroType {
+ ~GroType();
+ operator int() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<int> {
+ struct promise_type {
+ GroType get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ promise_type();
+ ~promise_type();
+ void unhandled_exception() noexcept;
+ };
+};
+
+struct Cleanup { ~Cleanup(); };
+void doSomething() noexcept;
+
+// CHECK: define i32 @_Z1fv(
+int f() {
+ // CHECK: %[[RetVal:.+]] = alloca i32
+ // CHECK: %[[GroActive:.+]] = alloca i1
+
+ // CHECK: %[[Size:.+]] = call i64 @llvm.coro.size.i64()
+ // CHECK: call i8* @_Znwm(i64 %[[Size]])
+ // CHECK: store i1 false, i1* %[[GroActive]]
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeC1Ev(
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type17get_return_objectEv(
+ // CHECK: store i1 true, i1* %[[GroActive]]
+
+ Cleanup cleanup;
+ doSomething();
+ co_return;
+
+ // CHECK: call void @_Z11doSomethingv(
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_type11return_voidEv(
+ // CHECK: call void @_ZN7CleanupD1Ev(
+
+ // Destroy promise and free the memory.
+
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJiEE12promise_typeD1Ev(
+ // CHECK: %[[Mem:.+]] = call i8* @llvm.coro.free(
+ // CHECK: call void @_ZdlPv(i8* %[[Mem]])
+
+ // Initialize retval from Gro and destroy Gro
+
+ // CHECK: %[[Conv:.+]] = call i32 @_ZN7GroTypecviEv(
+ // CHECK: store i32 %[[Conv]], i32* %[[RetVal]]
+ // CHECK: %[[IsActive:.+]] = load i1, i1* %[[GroActive]]
+ // CHECK: br i1 %[[IsActive]], label %[[CleanupGro:.+]], label %[[Done:.+]]
+
+ // CHECK: [[CleanupGro]]:
+ // CHECK: call void @_ZN7GroTypeD1Ev(
+ // CHECK: br label %[[Done]]
+
+ // CHECK: [[Done]]:
+ // CHECK: %[[LoadRet:.+]] = load i32, i32* %[[RetVal]]
+ // CHECK: ret i32 %[[LoadRet]]
+}
diff --git a/test/CodeGenCoroutines/coro-lambda.cpp b/test/CodeGenCoroutines/coro-lambda.cpp
new file mode 100644
index 0000000000..cd3256dc07
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-lambda.cpp
@@ -0,0 +1,58 @@
+// Verify that we synthesized the coroutine for a lambda inside of a function template.
+// 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 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 Task {
+ struct promise_type {
+ Task get_return_object();
+ void return_void() {}
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void unhandled_exception() noexcept;
+ };
+};
+
+template <typename _AwrT> auto SyncAwait(_AwrT &&A) {
+ if (!A.await_ready()) {
+ auto AwaitAsync = [&]() -> Task {
+ try { (void)(co_await A); } catch (...) {}
+ };
+ Task t = AwaitAsync();
+ }
+ return A.await_resume();
+}
+
+void f() {
+ suspend_always test;
+ SyncAwait(test);
+}
+
+// Verify that we synthesized the coroutine for a lambda inside SyncAwait
+// CHECK-LABEL: define linkonce_odr void @_ZZ9SyncAwaitIR14suspend_alwaysEDaOT_ENKUlvE_clEv(
+// CHECK: alloca %"struct.Task::promise_type"
+// CHECK: call token @llvm.coro.id(
+// CHECK: call i8 @llvm.coro.suspend(
+// CHECK: call i1 @llvm.coro.end(
diff --git a/test/CodeGenCoroutines/coro-params.cpp b/test/CodeGenCoroutines/coro-params.cpp
new file mode 100644
index 0000000000..540f84585c
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-params.cpp
@@ -0,0 +1,129 @@
+// Verifies that parameters are copied with move constructors
+// Verifies that parameter copies are destroyed
+// Vefifies that parameter copies are used in the body of the coroutine
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -disable-llvm-passes -fexceptions | 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 *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) noexcept;
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+}
+
+struct suspend_always {
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
+};
+
+template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
+ struct promise_type {
+ void get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ promise_type();
+ ~promise_type() noexcept;
+ void unhandled_exception() noexcept;
+ };
+};
+
+// TODO: Not supported yet
+struct CopyOnly {
+ int val;
+ CopyOnly(const CopyOnly&) noexcept;
+ CopyOnly(CopyOnly&&) = delete;
+ ~CopyOnly();
+};
+
+struct MoveOnly {
+ int val;
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&) noexcept;
+ ~MoveOnly();
+};
+
+struct MoveAndCopy {
+ int val;
+ MoveAndCopy(const MoveAndCopy&)noexcept;
+ MoveAndCopy(MoveAndCopy&&) noexcept;
+ ~MoveAndCopy();
+};
+
+void consume(int,int,int) noexcept;
+
+// TODO: Add support for CopyOnly params
+// CHECK: define void @_Z1fi8MoveOnly11MoveAndCopy(i32 %val, %struct.MoveOnly* %[[MoParam:.+]], %struct.MoveAndCopy* %[[McParam:.+]]) #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*
+void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
+ // CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly
+ // CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy
+ // CHECK: store i32 %val, i32* %[[ValAddr:.+]]
+
+ // CHECK: call i8* @llvm.coro.begin(
+ // CHECK-NEXT: call void @_ZN8MoveOnlyC1EOS_(%struct.MoveOnly* %[[MoCopy]], %struct.MoveOnly* dereferenceable(4) %[[MoParam]])
+ // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(%struct.MoveAndCopy* %[[McCopy]], %struct.MoveAndCopy* dereferenceable(4) %[[McParam]]) #
+ // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeC1Ev(
+
+ // CHECK: call void @_ZN14suspend_always12await_resumeEv(
+ // CHECK: %[[IntParam:.+]] = load i32, i32* %val.addr
+ // CHECK: %[[MoGep:.+]] = getelementptr inbounds %struct.MoveOnly, %struct.MoveOnly* %[[MoCopy]], i32 0, i32 0
+ // CHECK: %[[MoVal:.+]] = load i32, i32* %[[MoGep]]
+ // CHECK: %[[McGep:.+]] = getelementptr inbounds %struct.MoveAndCopy, %struct.MoveAndCopy* %[[McCopy]], i32 0, i32 0
+ // CHECK: %[[McVal:.+]] = load i32, i32* %[[McGep]]
+ // CHECK: call void @_Z7consumeiii(i32 %[[IntParam]], i32 %[[MoVal]], i32 %[[McVal]])
+
+ consume(val, moParam.val, mcParam.val);
+ co_return;
+
+ // Skip to final suspend:
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_type13final_suspendEv(
+ // CHECK: call void @_ZN14suspend_always12await_resumeEv(
+
+ // Destroy promise, then parameter copies:
+ // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJvi8MoveOnly11MoveAndCopyEE12promise_typeD1Ev(%"struct.std::experimental::coroutine_traits<void, int, MoveOnly, MoveAndCopy>::promise_type"* %__promise) #2
+ // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(%struct.MoveAndCopy* %[[McCopy]])
+ // CHECK-NEXT: call void @_ZN8MoveOnlyD1Ev(%struct.MoveOnly* %[[MoCopy]]
+ // CHECK-NEXT: call i8* @llvm.coro.free(
+}
+
+// CHECK-LABEL: void @_Z16dependent_paramsI1A1BEvT_T0_S3_(%struct.A* %x, %struct.B*, %struct.B* %y)
+template <typename T, typename U>
+void dependent_params(T x, U, U y) {
+ // CHECK: %[[x_copy:.+]] = alloca %struct.A
+ // CHECK-NEXT: %[[unnamed_copy:.+]] = alloca %struct.B
+ // CHECK-NEXT: %[[y_copy:.+]] = alloca %struct.B
+
+ // CHECK: call i8* @llvm.coro.begin
+ // CHECK-NEXT: call void @_ZN1AC1EOS_(%struct.A* %[[x_copy]], %struct.A* dereferenceable(512) %x)
+ // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* %[[unnamed_copy]], %struct.B* dereferenceable(512) %0)
+ // CHECK-NEXT: call void @_ZN1BC1EOS_(%struct.B* %[[y_copy]], %struct.B* dereferenceable(512) %y)
+ // CHECK-NEXT: invoke void @_ZNSt12experimental16coroutine_traitsIJv1A1BS2_EE12promise_typeC1Ev(
+
+ co_return;
+}
+
+struct A {
+ int WontFitIntoRegisterForSure[128];
+ A();
+ A(A&&) noexcept;
+ ~A();
+};
+
+struct B {
+ int WontFitIntoRegisterForSure[128];
+ B();
+ B(B&&) noexcept;
+ ~B();
+};
+
+void call_dependent_params() {
+ dependent_params(A{}, B{}, B{});
+}
diff --git a/test/CodeGenCoroutines/coro-promise-dtor.cpp b/test/CodeGenCoroutines/coro-promise-dtor.cpp
new file mode 100644
index 0000000000..4142cebe61
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-promise-dtor.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-pc-windows-msvc18.0.0 -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s
+// -triple=x86_64-unknown-linux-gnu
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct coro_t {
+ void* p;
+ ~coro_t();
+ struct promise_type {
+ coro_t get_return_object();
+ coro::suspend_never initial_suspend();
+ coro::suspend_never final_suspend();
+ void return_void();
+ promise_type();
+ ~promise_type();
+ void unhandled_exception();
+ };
+};
+
+struct Cleanup { ~Cleanup(); };
+void may_throw();
+
+coro_t f() {
+ Cleanup cleanup;
+ may_throw();
+ co_return;
+}
+
+// CHECK-LABEL: define void @"\01?f@@YA?AUcoro_t@@XZ"(
+// CHECK: %gro.active = alloca i1
+// CHECK: store i1 false, i1* %gro.active
+
+// CHECK: invoke %"struct.coro_t::promise_type"* @"\01??0promise_type@coro_t@@QEAA@XZ"(
+// CHECK: invoke void @"\01?get_return_object@promise_type@coro_t@@QEAA?AU2@XZ"(
+// CHECK: store i1 true, i1* %gro.active
+
+// CHECK: %[[IS_ACTIVE:.+]] = load i1, i1* %gro.active
+// CHECK: br i1 %[[IS_ACTIVE]], label %[[CLEANUP1:.+]], label
+
+// CHECK: [[CLEANUP1]]:
+// CHECK: %[[NRVO:.+]] = load i1, i1* %nrvo
+// CHECK: br i1 %[[NRVO]], label %{{.+}}, label %[[DTOR:.+]]
+
+// CHECK: [[DTOR]]:
+// CHECK: call void @"\01??_Dcoro_t@@QEAAXXZ"(
diff --git a/test/CodeGenCoroutines/coro-ret-void.cpp b/test/CodeGenCoroutines/coro-ret-void.cpp
new file mode 100644
index 0000000000..6ebb44dfae
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-ret-void.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -std=c++14 -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct coro1 {
+ struct promise_type {
+ coro1 get_return_object();
+ coro::suspend_never initial_suspend();
+ coro::suspend_never final_suspend();
+ void return_void();
+ };
+};
+
+coro1 f() {
+ co_await coro::suspend_never{};
+}
+
+// CHECK-LABEL: define void @_Z1fv(
+// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(%"struct.std::experimental::coroutines_v1::suspend_never"*
+// CHECK: call void @_ZN5coro112promise_type11return_voidEv(%"struct.coro1::promise_type"* %__promise)
+
+struct A {
+ A();
+ ~A();
+};
+
+coro1 f2() {
+ co_return (void) A{};
+}
+
+// CHECK-LABEL: define void @_Z2f2v(
+// CHECK: call void @_ZN1AC1Ev(%struct.A* %[[AVar:.*]])
+// CHECK-NEXT: call void @_ZN1AD1Ev(%struct.A* %[[AVar]])
+// CHECK-NEXT: call void @_ZN5coro112promise_type11return_voidEv(%"struct.coro1::promise_type"*
+
+struct coro2 {
+ struct promise_type {
+ coro2 get_return_object();
+ coro::suspend_never initial_suspend();
+ coro::suspend_never final_suspend();
+ void return_value(int);
+ };
+};
+
+coro2 g() {
+ co_return 42;
+}
+
+// CHECK-LABEL: define void @_Z1gv(
+// CHECK: call void @_ZNSt12experimental13coroutines_v113suspend_never12await_resumeEv(%"struct.std::experimental::coroutines_v1::suspend_never"*
+// CHECK: call void @_ZN5coro212promise_type12return_valueEi(%"struct.coro2::promise_type"* %__promise, i32 42)
diff --git a/test/CodeGenCoroutines/coro-return.cpp b/test/CodeGenCoroutines/coro-return.cpp
index 26aaa90077..7577725909 100644
--- a/test/CodeGenCoroutines/coro-return.cpp
+++ b/test/CodeGenCoroutines/coro-return.cpp
@@ -1,25 +1,18 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+// 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 {
-namespace experimental {
-template <typename... T>
-struct coroutine_traits;
+namespace std::experimental {
+template <typename... T> struct coroutine_traits;
-template <class Promise = void>
-struct coroutine_handle {
+template <class Promise = void> struct coroutine_handle {
coroutine_handle() = default;
static coroutine_handle from_address(void *) { return {}; }
};
-
-template <>
-struct coroutine_handle<void> {
+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 {
@@ -28,8 +21,7 @@ struct suspend_always {
void await_resume();
};
-template<>
-struct std::experimental::coroutine_traits<void> {
+template <> struct std::experimental::coroutine_traits<void> {
struct promise_type {
void get_return_object();
suspend_always initial_suspend();
diff --git a/test/CodeGenCoroutines/coro-unhandled-exception.cpp b/test/CodeGenCoroutines/coro-unhandled-exception.cpp
new file mode 100644
index 0000000000..e26a51861d
--- /dev/null
+++ b/test/CodeGenCoroutines/coro-unhandled-exception.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -std=c++14 -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++14 -fcoroutines-ts -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck --check-prefix=CHECK-LPAD %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+namespace std {
+ using exception_ptr = int;
+ exception_ptr current_exception();
+}
+
+struct coro_t {
+ struct promise_type {
+ coro_t get_return_object() {
+ coro::coroutine_handle<promise_type>{};
+ return {};
+ }
+ coro::suspend_never initial_suspend() { return {}; }
+ coro::suspend_never final_suspend() { return {}; }
+ void return_void(){}
+ 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 %{{.+}} unwind label %[[EHCLEANUP:.+]]
+// CHECK: [[EHCLEANUP]]:
+// CHECK: %[[INNERPAD:.+]] = cleanuppad within none []
+// CHECK: call void @"\01??_DCleanup@@QEAAXXZ"(
+// CHECK: cleanupret from %[[INNERPAD]] unwind label %[[CATCHSW:.+]]
+// CHECK: [[CATCHSW]]:
+// CHECK: %[[CATCHSWTOK:.+]] = catchswitch within none [label %[[CATCH:.+]]] unwind label
+// CHECK: [[CATCH]]:
+// CHECK: %[[CATCHTOK:.+]] = catchpad within [[CATCHSWTOK:.+]]
+// CHECK: call void @"\01?unhandled_exception@promise_type@coro_t@@QEAAXXZ"
+// CHECK: catchret from %[[CATCHTOK]] to label %[[CATCHRETDEST:.+]]
+// CHECK: [[CATCHRETDEST]]:
+// CHECK-NEXT: br label %[[TRYCONT:.+]]
+// CHECK: [[TRYCONT]]:
+// CHECK-NEXT: br label %[[COROFIN:.+]]
+// CHECK: [[COROFIN]]:
+// CHECK-NEXT: invoke void @"\01?final_suspend@promise_type@coro_t@@QEAA?AUsuspend_never@coroutines_v1@experimental@std@@XZ"(
+
+// CHECK-LPAD: @_Z1fv(
+// CHECK-LPAD: invoke void @_Z9may_throwv()
+// CHECK-LPAD: to label %[[CONT:.+]] unwind label %[[CLEANUP:.+]]
+// CHECK-LPAD: [[CLEANUP]]:
+// CHECK-LPAD: call void @_ZN7CleanupD1Ev(%struct.Cleanup* %x) #2
+// CHECK-LPAD: br label %[[CATCH:.+]]
+
+// CHECK-LPAD: [[CATCH]]:
+// CHECK-LPAD: call i8* @__cxa_begin_catch
+// CHECK-LPAD: call void @_ZN6coro_t12promise_type19unhandled_exceptionEv(%"struct.coro_t::promise_type"* %__promise) #2
+// CHECK-LPAD: invoke void @__cxa_end_catch()
+// CHECK-LPAD-NEXT: to label %[[CATCHRETDEST:.+]] unwind label
+// CHECK-LPAD: [[CATCHRETDEST]]:
+// CHECK-LPAD-NEXT: br label %[[TRYCONT:.+]]
+// CHECK-LPAD: [[TRYCONT]]:
+// CHECK-LPAD-NEXT: br label %[[COROFIN:.+]]
+// CHECK-LPAD: [[COROFIN]]:
+// CHECK-LPAD-NEXT: invoke void @_ZN6coro_t12promise_type13final_suspendEv(
diff --git a/test/CodeGenObjC/NSFastEnumeration.m b/test/CodeGenObjC/NSFastEnumeration.m
new file mode 100644
index 0000000000..ba131fc4c7
--- /dev/null
+++ b/test/CodeGenObjC/NSFastEnumeration.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple i686-apple-ios10.3 -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK32
+// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK32
+// RUN: %clang_cc1 -triple x86_64-apple-ios10.3 -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK64
+// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK64
+
+void f(id a) {
+ for (id i in a)
+ (void)i;
+}
+
+// CHECK32: call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i32)*)
+// CHECK32: call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i32)*)
+
+// CHECK64: call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i64)*)
+// CHECK64: call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i64)*)
+
diff --git a/test/CodeGenObjC/arc-arm.m b/test/CodeGenObjC/arc-arm.m
index 8d5f0d5c4b..63c861f289 100644
--- a/test/CodeGenObjC/arc-arm.m
+++ b/test/CodeGenObjC/arc-arm.m
@@ -13,7 +13,7 @@ id test0(void) {
void test1(void) {
extern id test1_helper(void);
// CHECK: [[T0:%.*]] = call [[CC]]i8* @test1_helper()
- // CHECK-NEXT: call void asm sideeffect "mov
+ // CHECK-NEXT: call void asm sideeffect "mov\09{{fp, fp|r7, r7}}\09\09// marker for objc_retainAutoreleaseReturnValue"
// CHECK-NEXT: [[T1:%.*]] = call [[CC]]i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]],
// CHECK-NEXT: call [[CC]]void @objc_storeStrong(
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
index 06eb46b867..b84d141037 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]+}} {
@@ -298,15 +298,11 @@ void test7(void) {
// CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]*, [[TEST8]]** [[SELF]],
-// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
-// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
-// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]*
-// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]]
+// CHECK-NEXT: store %0* [[T1]], %0** [[T0]]
// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
// CHECK: call void @test8_helper(
-// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]*, [[TEST8]]** [[D0]]
-// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T2]])
+// CHECK-NEXT: [[T2:%.*]] = load [[TEST8]]*, [[TEST8]]** [[D0]]
+// CHECK-NEXT: call void (...) @clang.arc.use([[TEST8]]* [[T2]])
// CHECK: ret void
extern void test8_helper(void (^)(void));
@@ -506,7 +502,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 +528,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 +535,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 +562,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
}
@@ -741,5 +737,41 @@ void test19(void (^b)(void)) {
// CHECK-NEXT: ret void
}
+// CHECK-LABEL: define void @test20(
+// CHECK: [[XADDR:%.*]] = alloca i8*
+// CHECK-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]>
+// CHECK-NEXT: [[RETAINEDX:%.*]] = call i8* @objc_retain(i8* %{{.*}})
+// CHECK-NEXT: store i8* [[RETAINEDX]], i8** [[XADDR]]
+// CHECK-NEXT: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5
+// CHECK: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5
+// CHECK: [[CAPTURED:%.*]] = load i8*, i8** [[XADDR]]
+// CHECK: store i8* [[CAPTURED]], i8** [[BLOCKCAPTURED]]
+// CHECK: [[CAPTURE:%.*]] = load i8*, i8** [[CAPTUREFIELD]]
+// CHECK-NEXT: call void (...) @clang.arc.use(i8* [[CAPTURE]])
+// CHECK-NEXT: [[X:%.*]] = load i8*, i8** [[XADDR]]
+// CHECK-NEXT: call void @objc_release(i8* [[X]])
+// CHECK-NEXT: ret void
+
+// CHECK-UNOPT-LABEL: define void @test20(
+// CHECK-UNOPT: [[XADDR:%.*]] = alloca i8*
+// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]>
+// CHECK-UNOPT: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5
+// CHECK-UNOPT: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5
+// CHECK-UNOPT: [[CAPTURED:%.*]] = load i8*, i8** [[XADDR]]
+// CHECK-UNOPT: [[RETAINED:%.*]] = call i8* @objc_retain(i8* [[CAPTURED]])
+// CHECK-UNOPT: store i8* [[RETAINED]], i8** [[BLOCKCAPTURED]]
+// CHECK-UNOPT: call void @objc_storeStrong(i8** [[CAPTUREFIELD]], i8* null)
+
+// CHECK-LABEL: define internal void @__copy_helper_block
+// CHECK: [[BLOCKSOURCE:%.*]] = bitcast i8* %{{.*}} to <[[BLOCKTY]]>*
+// CHECK: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCKSOURCE]], i32 0, i32 5
+// CHECK: [[BLOCKCOPYSRC:%.*]] = load i8*, i8** [[CAPTUREFIELD]]
+// CHECK: call i8* @objc_retain(i8* [[BLOCKCOPYSRC]])
+
+void test20_callee(void (^)());
+void test20(const id x) {
+ test20_callee(^{ (void)x; });
+}
+
// CHECK: attributes [[NUW]] = { nounwind }
// CHECK-UNOPT: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-bridged-cast.m b/test/CodeGenObjC/arc-bridged-cast.m
index 97a45c5a2f..42795d5d80 100644
--- a/test/CodeGenObjC/arc-bridged-cast.m
+++ b/test/CodeGenObjC/arc-bridged-cast.m
@@ -97,3 +97,11 @@ void bridge_of_cf(int *i) {
// CHECK-NEXT: ret void
}
+// CHECK-LABEL: define %struct.__CFString* @bridge_of_paren_expr()
+CFStringRef bridge_of_paren_expr() {
+ // CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue(
+ // CHECK-NOT: call void @objc_release(
+ CFStringRef r = (__bridge CFStringRef)(CreateNSString());
+ r = (__bridge CFStringRef)((NSString *)(CreateNSString()));
+ return r;
+}
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index db150e88a5..77cb068187 100644
--- a/test/CodeGenObjC/arc-foreach.m
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -emit-llvm %s -o %t-64.s
-// RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -fobjc-arc -fobjc-runtime-has-weak -emit-llvm %s -o - | FileCheck -check-prefix CHECK-LP64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -O1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -emit-llvm %s -o - | FileCheck -check-prefix CHECK-LP64-OPT %s
// rdar://9503326
// rdar://9606600
@@ -29,6 +29,11 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: [[BUFFER:%.*]] = alloca [16 x i8*], align 8
// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+// CHECK-LP64-OPT-LABEL: define void @test0
+// CHECK-LP64-OPT: [[STATE:%.*]] = alloca [[STATE_T:%.*]], align 8
+// CHECK-LP64-OPT-NEXT: [[BUFFER:%.*]] = alloca [16 x i8*], align 8
+// CHECK-LP64-OPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
+
// Initialize 'array'.
// CHECK-LP64-NEXT: store [[ARRAY_T]]* null, [[ARRAY_T]]** [[ARRAY]]
// CHECK-LP64-NEXT: [[ZERO:%.*]] = bitcast [[ARRAY_T]]** [[ARRAY]] to i8**
@@ -65,9 +70,14 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: [[T1:%.*]] = load i8*, i8** [[X]]
// CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]]
-// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]]
-// CHECK-LP64: call void @use_block(
+// CHECK-LP64-NEXT: [[BLOCK1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]]
+// CHECK-LP64-NEXT: call void @use_block(void ()* [[BLOCK1]])
// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[D0]], i8* null)
+// CHECK-LP64-NOT: call void (...) @clang.arc.use(i8* [[CAPTURE]])
+
+// CHECK-LP64-OPT: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i64 0, i32 5
+// CHECK-LP64-OPT: [[CAPTURE:%.*]] = load i8*, i8** [[D0]]
+// CHECK-LP64-OPT: call void (...) @clang.arc.use(i8* [[CAPTURE]])
// CHECK-LP64: [[T0:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[ARRAY_T]]* [[SAVED_ARRAY]] to i8*
@@ -201,17 +211,24 @@ NSArray *array4;
// CHECK-LP64: [[BC:%.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [[TY]]* }>* [[BLOCK]], i32 0, i32 5
// CHECK-LP64: [[T1:%.*]] = load [[TY]]*, [[TY]]** [[SELF_ADDR]]
// CHECK-LP64: [[T2:%.*]] = bitcast [[TY]]* [[T1]] to i8*
-// CHECK-LP64: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
-// CHECK-LP64: [[T4:%.*]] = bitcast i8* [[T3]] to [[TY]]*
-// CHECK-LP64: store [[TY]]* [[T4]], [[TY]]** [[BC]]
+// CHECK-LP64: call i8* @objc_retain(i8* [[T2]])
+
+// CHECK-LP64-OPT-LABEL: define internal void @"\01-[I1 foo2]"(
+// CHECK-LP64-OPT: [[TY:%.*]]* %self
+// CHECK-LP64-OPT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
+// CHECK-LP64-OPT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i64 0, i32 5
// CHECK-LP64: [[T5:%.*]] = bitcast [[TY]]** [[T0]] to i8**
// CHECK-LP64: call void @objc_storeStrong(i8** [[T5]], i8* null)
+// CHECK-LP64-NOT: call void (...) @clang.arc.use([[TY]]* [[T5]])
// CHECK-LP64: switch i32 {{%.*}}, label %[[UNREACHABLE:.*]] [
// CHECK-LP64-NEXT: i32 0, label %[[CLEANUP_CONT:.*]]
// CHECK-LP64-NEXT: i32 2, label %[[FORCOLL_END:.*]]
// CHECK-LP64-NEXT: ]
+// CHECK-LP64-OPT: [[T5:%.*]] = load [[TY]]*, [[TY]]** [[T0]]
+// CHECK-LP64-OPT: call void (...) @clang.arc.use([[TY]]* [[T5]])
+
// CHECK-LP64: {{^|:}}[[CLEANUP_CONT]]
// CHECK-LP64-NEXT: br label %[[FORCOLL_END]]
diff --git a/test/CodeGenObjC/arc-precise-lifetime.m b/test/CodeGenObjC/arc-precise-lifetime.m
index eb3111c68a..a366c08bbb 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-property.m b/test/CodeGenObjC/arc-property.m
index b8dc18e872..edc4d1e853 100644
--- a/test/CodeGenObjC/arc-property.m
+++ b/test/CodeGenObjC/arc-property.m
@@ -131,4 +131,24 @@ void test3(Test3 *t) {
- (void) setCopyMachine: (id) x {}
@end
+// rdar://31579994
+// When synthesizing a property that's declared in multiple protocols, ensure
+// that the setter is emitted if any of these declarations is readwrite.
+@protocol ABC
+@property (copy, nonatomic, readonly) Test3 *someId;
+@end
+@protocol ABC__Mutable <ABC>
+@property (copy, nonatomic, readwrite) Test3 *someId;
+@end
+
+@interface ABC_Class <ABC, ABC__Mutable>
+@end
+
+@implementation ABC_Class
+@synthesize someId = _someId;
+// CHECK: define internal %{{.*}}* @"\01-[ABC_Class someId]"
+// CHECK: define internal void @"\01-[ABC_Class setSomeId:]"(
+@end
+
+
// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-ternary-op.m b/test/CodeGenObjC/arc-ternary-op.m
index 883fcd3666..3488d2c538 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 fc135af6d3..d34156ee34 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -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
diff --git a/test/CodeGenObjC/attr-callconv.m b/test/CodeGenObjC/attr-callconv.m
index b0a41f7438..8cf8d2bd71 100644
--- a/test/CodeGenObjC/attr-callconv.m
+++ b/test/CodeGenObjC/attr-callconv.m
@@ -9,5 +9,5 @@
// CHECK: define{{.*}}x86_stdcallcc{{.*}}Test test
- (void)test2 __attribute__((ms_abi)) {}
- // CHECK: define{{.*}}x86_64_win64cc{{.*}}Test test2
+ // CHECK: define{{.*}}win64cc{{.*}}Test test2
@end
diff --git a/test/CodeGenObjC/availability-cf-link-guard.m b/test/CodeGenObjC/availability-cf-link-guard.m
new file mode 100644
index 0000000000..6bd426476b
--- /dev/null
+++ b/test/CodeGenObjC/availability-cf-link-guard.m
@@ -0,0 +1,44 @@
+// 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: !llvm.linker.options = !{![[FRAMEWORK:[0-9]+]]
+// CHECK_LINK_OPT: ![[FRAMEWORK]] = !{!"-framework", !"CoreFoundation"}
+
+// CHECK_NO_GUARD-NOT: !llvm.linker.options
+// CHECK_NO_GUARD-NOT: CoreFoundation
diff --git a/test/CodeGenObjC/debug-info-block-captured-self.m b/test/CodeGenObjC/debug-info-block-captured-self.m
deleted file mode 100644
index e142a0bceb..0000000000
--- a/test/CodeGenObjC/debug-info-block-captured-self.m
+++ /dev/null
@@ -1,72 +0,0 @@
-// RUN: %clang_cc1 -fblocks -debug-info-kind=limited -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
-//
-// Test that debug location is generated for a captured "self" inside
-// a block.
-//
-// This test is split into two parts, this one for the frontend, and
-// then llvm/test/DebugInfo/debug-info-block-captured-self.ll to
-// ensure that DW_AT_location is generated for the captured self.
-@class T;
-@interface S
-@end
-@interface Mode
--(int) count;
-@end
-@interface Context
-@end
-@interface ViewController
-@property (nonatomic, readwrite, strong) Context *context;
-@end
-typedef enum {
- Unknown = 0,
-} State;
-@interface Main : ViewController
-{
- T * t1;
- T * t2;
-}
-@property(readwrite, nonatomic) State state;
-@end
-@implementation Main
-- (id) initWithContext:(Context *) context
-{
- t1 = [self.context withBlock:^(id obj){
- id *mode1;
- t2 = [mode1 withBlock:^(id object){
- Mode *mode2 = object;
- if ([mode2 count] != 0) {
- self.state = 0;
- }
- }];
- }];
-}
-@end
-// The important part of this test is that there is a dbg.value
-// intrinsic associated with the implicit .block_descriptor argument
-// of the block. We also test that this value gets alloca'd, so the
-// register llocator won't accidentally kill it.
-
-// outer block:
-// CHECK: define internal void {{.*}}_block_invoke{{.*}}
-
-// inner block:
-// CHECK: define internal void {{.*}}_block_invoke{{.*}}
-// CHECK: %[[MEM1:.*]] = alloca i8*, align 8
-// CHECK-NEXT: %[[MEM2:.*]] = alloca i8*, align 8
-// CHECK-NEXT: [[DBGADDR:%.*]] = alloca [[BLOCK_T:<{.*}>]]*, align 8
-// CHECK: store i8* [[BLOCK_DESC:%.*]], i8** %[[MEM1]], align 8
-// CHECK: %[[TMP0:.*]] = load i8*, i8** %[[MEM1]]
-// CHECK: call void @llvm.dbg.value(metadata i8* %[[TMP0]], i64 0, metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
-// CHECK: call void @llvm.dbg.declare(metadata i8* [[BLOCK_DESC]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
-// CHECK: store [[BLOCK_T]]* {{%.*}}, [[BLOCK_T]]** [[DBGADDR]], align 8
-// CHECK: call void @llvm.dbg.declare(metadata [[BLOCK_T]]** [[DBGADDR]], metadata ![[SELF:.*]], metadata !{{.*}})
-// make sure we are still in the same function
-// CHECK: define {{.*}}__copy_helper_block_
-// Metadata
-// CHECK: ![[MAIN:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Main"
-// CHECK-SAME: line: 23,
-// CHECK: ![[PMAIN:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[MAIN]],
-// CHECK: ![[BDMD]] = !DILocalVariable(name: ".block_descriptor", arg:
-// CHECK: ![[SELF]] = !DILocalVariable(name: "self"
-// CHECK-NOT: arg:
-// CHECK-SAME: line: 40,
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
index 0bf566395a..848e389f70 100644
--- a/test/CodeGenObjC/debug-info-blocks.m
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -10,23 +10,20 @@
// CHECK-NEXT: call void @llvm.dbg.declare(metadata <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]], metadata ![[SELF:[0-9]+]], metadata !{{.*}})
// CHECK-NEXT: call void @llvm.dbg.declare(metadata %1** %d, metadata ![[D:[0-9]+]], metadata !{{.*}})
-// rdar://problem/14386148
-// Test that we don't emit bogus line numbers for the helper functions.
-// Test that we do emit scope info for the helper functions.
+// Test that we do emit scope info for the helper functions, and that the
+// parameters to these functions are marked as artificial (so the debugger
+// doesn't accidentally step into the function).
// CHECK: define {{.*}} @__copy_helper_block_{{.*}}(i8*, i8*)
// CHECK-NOT: ret
// CHECK: call {{.*}}, !dbg ![[DBG_LINE:[0-9]+]]
// CHECK-NOT: ret
// CHECK: load {{.*}}, !dbg ![[COPY_LINE:[0-9]+]]
+// CHECK: ret void, !dbg ![[COPY_LINE]]
// CHECK: define {{.*}} @__destroy_helper_block_{{.*}}(i8*)
// CHECK-NOT: ret
// CHECK: load {{.*}}, !dbg ![[DESTROY_LINE:[0-9]+]]
+// CHECK: ret void, !dbg ![[DESTROY_LINE]]
-// CHECK-DAG: [[DBG_LINE]] = !DILocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
-// CHECK-DAG: [[COPY_LINE]] = !DILocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
-// CHECK-DAG: [[COPY_SP]] = distinct !DISubprogram(name: "__copy_helper_block_"
-// CHECK-DAG: [[DESTROY_LINE]] = !DILocation(line: 0, scope: ![[DESTROY_SP:[0-9]+]])
-// CHECK-DAG: [[DESTROY_SP]] = distinct !DISubprogram(name: "__destroy_helper_block_"
typedef unsigned int NSUInteger;
@protocol NSObject
@@ -60,6 +57,14 @@ static void run(void (^block)(void))
- (id)init
{
if ((self = [super init])) {
+ // CHECK-DAG: [[DBG_LINE]] = !DILocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
+ // CHECK-DAG: [[COPY_LINE]] = !DILocation(line: [[@LINE+7]], scope: ![[COPY_SP:[0-9]+]])
+ // CHECK-DAG: [[COPY_SP]] = distinct !DISubprogram(name: "__copy_helper_block_"
+ // CHECK-DAG: [[DESTROY_LINE]] = !DILocation(line: [[@LINE+5]], scope: ![[DESTROY_SP:[0-9]+]])
+ // CHECK-DAG: [[DESTROY_SP]] = distinct !DISubprogram(name: "__destroy_helper_block_"
+ // CHECK-DAG: !DILocalVariable(arg: 1, scope: ![[COPY_SP]], {{.*}}, flags: DIFlagArtificial)
+ // CHECK-DAG: !DILocalVariable(arg: 2, scope: ![[COPY_SP]], {{.*}}, flags: DIFlagArtificial)
+ // CHECK-DAG: !DILocalVariable(arg: 1, scope: ![[DESTROY_SP]], {{.*}}, flags: DIFlagArtificial)
run(^{
// CHECK-DAG: ![[SELF]] = !DILocalVariable(name: "self", scope:{{.*}}, line: [[@LINE+4]],
// CHECK-DAG: ![[D]] = !DILocalVariable(name: "d", scope:{{.*}}, line: [[@LINE+1]],
diff --git a/test/CodeGenObjC/dllstorage.m b/test/CodeGenObjC/dllstorage.m
index 4bdbd50915..a2665eefad 100644
--- a/test/CodeGenObjC/dllstorage.m
+++ b/test/CodeGenObjC/dllstorage.m
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fdeclspec -fobjc-runtime=ios -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s
// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=macosx -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s
// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=objfw -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-FW %s
@@ -114,6 +115,15 @@ __attribute__((__objc_exception__))
// CHECK-IR-DAG: @"OBJC_EHTYPE_$_P" = external global %struct._objc_typeinfo
+@interface Q : M
+@end
+
+id f(Q *q) {
+ return q->_ivar;
+}
+
+// CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32
+
int g() {
@autoreleasepool {
M *mi = [M new];
diff --git a/test/CodeGenObjC/empty-collection-literals.m b/test/CodeGenObjC/empty-collection-literals.m
new file mode 100644
index 0000000000..4b1d7f6ebe
--- /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__{{.*}}!invariant.load
+ // 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-asm-attribute.m b/test/CodeGenObjC/exceptions-asm-attribute.m
index 5719198f79..93e89b8e0a 100644
--- a/test/CodeGenObjC/exceptions-asm-attribute.m
+++ b/test/CodeGenObjC/exceptions-asm-attribute.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -Wno-objc-root-class -fexceptions -fobjc-exceptions -o %t %s
// RUN: FileCheck -check-prefix=CHECK-X86_64 < %t %s
// RUN: FileCheck -check-prefix=CHECK-EHTYPE < %t %s
// rdar://16462586
@@ -15,11 +15,11 @@
// CHECK-X86_64: @"OBJC_EHTYPE_$_MySecretNamespace.EH1" = weak global {{.*}}, align 8
// CHECK-X86_64: @"OBJC_EHTYPE_$_MySecretNamespace.EH2" = external global
// CHECK-X86_64: @"OBJC_EHTYPE_$_MySecretNamespace.EH3" = global {{.*}}, section "__DATA,__objc_const", align 8
-// CHECK-X86_64: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
+// CHECK-X86_64: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
// CHECK-X86_64: define internal void @"\01-[A im0]"
// CHECK-X86_64: define internal void @"\01-[A(Cat) im1]"
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-exceptions -fvisibility hidden -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -fobjc-exceptions -fvisibility hidden -emit-llvm -o %t %s
// RUN: FileCheck -check-prefix=CHECK-X86_64-HIDDEN < %t %s
// CHECK-X86_64-HIDDEN: @"OBJC_CLASS_$_MySecretNamespace.A" = hidden global {{.*}}, section "__DATA, __objc_data", align 8
@@ -30,7 +30,7 @@
// CHECK-X86_64-HIDDEN: define internal void @"\01-[A im0]"
// CHECK-X86_64-HIDDEN: define internal void @"\01-[A(Cat) im1]"
-// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -fobjc-exceptions -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -Wno-objc-root-class -fobjc-exceptions -emit-llvm -o %t %s
// RUN: FileCheck -check-prefix=CHECK-ARMV6 < %t %s
// CHECK-ARMV6: @"OBJC_CLASS_$_MySecretNamespace.A" = global {{.*}}, section "__DATA, __objc_data", align 4
@@ -39,7 +39,7 @@
// CHECK-ARMV6: @"OBJC_EHTYPE_$_MySecretNamespace.EH1" = weak global {{.*}}, align 4
// CHECK-ARMV6: @"OBJC_EHTYPE_$_MySecretNamespace.EH2" = external global
// CHECK-ARMV6: @"OBJC_EHTYPE_$_MySecretNamespace.EH3" = global {{.*}}, section "__DATA,__objc_const", align 4
-// CHECK-ARMV6: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 4
+// CHECK-ARMV6: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip", align 4
// CHECK-ARMV6: define internal void @"\01-[A im0]"
// CHECK-ARMV6: define internal void @"\01-[A(Cat) im1]"
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
index 28515c54f3..439b940148 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/gnu-exceptions.m b/test/CodeGenObjC/gnu-exceptions.m
index 2407f8fc6c..e24f5d892f 100644
--- a/test/CodeGenObjC/gnu-exceptions.m
+++ b/test/CodeGenObjC/gnu-exceptions.m
@@ -32,4 +32,4 @@ void test0() {
log(1);
}
-// CHECK: attributes [[TF]] = { noinline "{{.*}} }
+// CHECK: attributes [[TF]] = { noinline optnone "{{.*}} }
diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m
index 43fb125a4c..37156ed039 100644
--- a/test/CodeGenObjC/image-info.m
+++ b/test/CodeGenObjC/image-info.m
@@ -7,11 +7,11 @@
// CHECK-FRAGILE: !llvm.module.flags = !{{{.*}}}
// CHECK-FRAGILE: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 1}
// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0}
-// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC, __image_info,regular"}
+// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC,__image_info,regular"}
// CHECK-FRAGILE-NEXT: !{{[0-9]+}} = !{i32 4, !"Objective-C Garbage Collection", i32 0}
// CHECK-NONFRAGILE: !llvm.module.flags = !{{{.*}}}
// CHECK-NONFRAGILE: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 2}
// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0}
-// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
+// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
// CHECK-NONFRAGILE-NEXT: !{{[0-9]+}} = !{i32 4, !"Objective-C Garbage Collection", i32 0}
diff --git a/test/CodeGenObjC/ivar-layout-flexible-array.m b/test/CodeGenObjC/ivar-layout-flexible-array.m
new file mode 100644
index 0000000000..28849c86c2
--- /dev/null
+++ b/test/CodeGenObjC/ivar-layout-flexible-array.m
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -Wno-objc-root-class -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+// rdar://problem/21054495
+@interface FlexibleArrayMember {
+ char flexible_array[][4][2];
+}
+@end
+@implementation FlexibleArrayMember
+@end
+// CHECK: @OBJC_METH_VAR_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"flexible_array\00"
+// CHECK-NEXT: @OBJC_METH_VAR_TYPE_{{.*}} = private unnamed_addr constant {{.*}} c"^[4[2c]]\00"
+
+
+typedef char FlexibleArray[];
+
+struct Packet {
+ int size;
+ FlexibleArray data;
+};
+
+@interface VariableSizeIvar {
+ struct Packet flexible_struct;
+}
+@end
+@implementation VariableSizeIvar
+@end
+// CHECK: @OBJC_METH_VAR_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"flexible_struct\00"
+// CHECK-NEXT: @OBJC_METH_VAR_TYPE_{{.*}} = private unnamed_addr constant {{.*}} c"{Packet=\22size\22i\22data\22[0c]}\00"
diff --git a/test/CodeGenObjC/ivar-type-encoding.m b/test/CodeGenObjC/ivar-type-encoding.m
index ffa5e0d7af..2fd962cf07 100644
--- a/test/CodeGenObjC/ivar-type-encoding.m
+++ b/test/CodeGenObjC/ivar-type-encoding.m
@@ -33,3 +33,19 @@ int main() {
// 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"
+
+@interface Class1 {
+ int : 3;
+ short : 2;
+ long long ll;
+ char : 1;
+}
+@end
+
+@implementation Class1
+@end
+
+// CHECK: @{{.*}} = private unnamed_addr constant [5 x i8] c"b0i3\00"
+// CHECK: @{{.*}} = private unnamed_addr constant [5 x i8] c"b3s2\00"
+// CHECK: @{{.*}} = private unnamed_addr constant [2 x i8] c"q\00"
+// CHECK: @{{.*}} = private unnamed_addr constant [{{7|6}} x i8] c"b{{128|96}}c1\00"
diff --git a/test/CodeGenObjC/local-static-block.m b/test/CodeGenObjC/local-static-block.m
index 73c670f5c9..67ede63fc0 100644
--- a/test/CodeGenObjC/local-static-block.m
+++ b/test/CodeGenObjC/local-static-block.m
@@ -46,6 +46,17 @@ void FUNC()
}
}
+void FUNC2() {
+ static void (^const block1)(int) = ^(int a){
+ if (a--)
+ block1(a);
+ };
+}
+
+// CHECK-LABEL-LP64: define void @FUNC2(
+// CHECK: define internal void @_block_invoke{{.*}}(
+// CHECK: call void %{{.*}}(i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor* }* @__block_literal_global{{.*}} to i8*), i32 %{{.*}})
+
void FUNC1()
{
static NSArray *(^ArrayRecurs)(NSArray *addresses, unsigned long level) = ^(NSArray *addresses, unsigned long level) {
diff --git a/test/CodeGenObjC/mangle-blocks.m b/test/CodeGenObjC/mangle-blocks.m
index 4cc3204033..73522cd41c 100644
--- a/test/CodeGenObjC/mangle-blocks.m
+++ b/test/CodeGenObjC/mangle-blocks.m
@@ -18,11 +18,11 @@ void __assert_rtn(const char *, const char *, int, const char *);
@end
// CHECK: @"__func__.__14-[Test mangle]_block_invoke_2" = private unnamed_addr constant [30 x i8] c"-[Test mangle]_block_invoke_2\00", align 1
-// CHECK: @.str = private unnamed_addr constant {{.*}}, align 1
-// CHECK: @.str.1 = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
+// CHECK: @.str{{.*}} = private unnamed_addr constant {{.*}}, align 1
+// CHECK: @.str[[STR1:.*]] = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
// CHECK: define internal void @"__14-[Test mangle]_block_invoke"(i8* %.block_descriptor)
// CHECK: define internal void @"__14-[Test mangle]_block_invoke_2"(i8* %.block_descriptor){{.*}}{
-// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @"__func__.__14-[Test mangle]_block_invoke_2", i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 14, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0))
+// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @"__func__.__14-[Test mangle]_block_invoke_2", i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 14, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str[[STR1]], i32 0, i32 0))
// CHECK: }
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index 5139cd8fde..b94f1b6384 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -12,7 +12,7 @@
// CHECK: @"\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_P" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_PROTOCOL_CLASS_METHODS_P" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_PROTOCOL_$_P" = weak hidden global {{.*}}, align 8
-// CHECK: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = weak hidden global {{.*}} section "__DATA, __objc_protolist, coalesced, no_dead_strip", align 8
+// CHECK: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = weak hidden global {{.*}} section "__DATA,__objc_protolist,coalesced,no_dead_strip", align 8
// CHECK: @"\01l_OBJC_CLASS_PROTOCOLS_$_A" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_METACLASS_RO_$_A" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_INSTANCE_METHODS_A" = private global {{.*}} section "__DATA, __objc_const", align 8
@@ -23,14 +23,14 @@
// CHECK: @"\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_Cat" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_CATEGORY_CLASS_METHODS_A_$_Cat" = private global {{.*}} section "__DATA, __objc_const", align 8
// CHECK: @"\01l_OBJC_$_CATEGORY_A_$_Cat" = private global {{.*}} section "__DATA, __objc_const", align 8
-// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8
-// CHECK: @OBJC_SELECTOR_REFERENCES_ = private externally_initialized global {{.*}} section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"
-// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_{{[\.0-9]*}}" = private global {{.*}} section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_{{[0-9]*}}" = private global {{.*}} section "__DATA,__objc_superrefs,regular,no_dead_strip", align 8
+// CHECK: @OBJC_SELECTOR_REFERENCES_ = private externally_initialized global {{.*}} section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip"
+// CHECK: @"OBJC_CLASSLIST_SUP_REFS_$_{{[\.0-9]*}}" = private global {{.*}} section "__DATA,__objc_superrefs,regular,no_dead_strip", align 8
// CHECK: @"OBJC_CLASS_$_B" = external global
-// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_{{[0-9]*}}" = private global {{.*}} section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
-// CHECK: @"\01l_objc_msgSend_fixup_alloc" = weak hidden global {{.*}} section "__DATA, __objc_msgrefs, coalesced", align 16
-// CHECK: @"OBJC_LABEL_CLASS_$" = private global {{.*}} section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
-// CHECK: @"OBJC_LABEL_CATEGORY_$" = private global {{.*}} section "__DATA, __objc_catlist, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_{{[0-9]*}}" = private global {{.*}} section "__DATA,__objc_classrefs,regular,no_dead_strip", align 8
+// CHECK: @"\01l_objc_msgSend_fixup_alloc" = weak hidden global {{.*}} section "__DATA,__objc_msgrefs,coalesced", align 16
+// CHECK: @"OBJC_LABEL_CLASS_$" = private global {{.*}} section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+// CHECK: @"OBJC_LABEL_CATEGORY_$" = private global {{.*}} section "__DATA,__objc_catlist,regular,no_dead_strip", align 8
// CHECK: @objc_msgSend_fpret(
// CHECK: @objc_msgSend_fixup(
diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m
index 4c365a14f9..9aee55bb8e 100644
--- a/test/CodeGenObjC/metadata_symbols.m
+++ b/test/CodeGenObjC/metadata_symbols.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -Wno-objc-root-class -fexceptions -fobjc-exceptions -o %t %s
// RUN: FileCheck -check-prefix=CHECK-X86_64 < %t %s
// RUN: FileCheck -check-prefix=CHECK-EHTYPE < %t %s
@@ -14,11 +14,11 @@
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, align 8
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH2" = external global
// CHECK-X86_64: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 8
-// CHECK-X86_64: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
+// CHECK-X86_64: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
// CHECK-X86_64: define internal void @"\01-[A im0]"
// CHECK-X86_64: define internal void @"\01-[A(Cat) im1]"
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-exceptions -fvisibility hidden -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -fobjc-exceptions -fvisibility hidden -emit-llvm -o %t %s
// RUN: FileCheck -check-prefix=CHECK-X86_64-HIDDEN < %t %s
// CHECK-X86_64-HIDDEN: @"OBJC_CLASS_$_A" = hidden global {{.*}}, section "__DATA, __objc_data", align 8
@@ -29,7 +29,7 @@
// CHECK-X86_64-HIDDEN: define internal void @"\01-[A im0]"
// CHECK-X86_64-HIDDEN: define internal void @"\01-[A(Cat) im1]"
-// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -fobjc-exceptions -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -Wno-objc-root-class -fobjc-exceptions -emit-llvm -o %t %s
// RUN: FileCheck -check-prefix=CHECK-ARMV6 < %t %s
// CHECK-ARMV6: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
@@ -38,7 +38,7 @@
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, align 4
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH2" = external global
// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 4
-// CHECK-ARMV6: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 4
+// CHECK-ARMV6: @"OBJC_LABEL_CLASS_$" = private global {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip", align 4
// CHECK-ARMV6: define internal void @"\01-[A im0]"
// CHECK-ARMV6: define internal void @"\01-[A(Cat) im1]"
diff --git a/test/CodeGenObjC/noescape.m b/test/CodeGenObjC/noescape.m
new file mode 100644
index 0000000000..49bc0e4a7d
--- /dev/null
+++ b/test/CodeGenObjC/noescape.m
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+
+typedef void (^BlockTy)(void);
+
+union U {
+ int *i;
+ long long *ll;
+} __attribute__((transparent_union));
+
+void noescapeFunc0(id, __attribute__((noescape)) BlockTy);
+void noescapeFunc1(__attribute__((noescape)) int *);
+void noescapeFunc2(__attribute__((noescape)) id);
+void noescapeFunc3(__attribute__((noescape)) union U);
+
+// CHECK-LABEL: define void @test0(
+// CHECK: call void @noescapeFunc0({{.*}}, {{.*}} nocapture {{.*}})
+// CHECK: declare void @noescapeFunc0(i8*, {{.*}} nocapture)
+void test0(BlockTy b) {
+ noescapeFunc0(0, b);
+}
+
+// CHECK-LABEL: define void @test1(
+// CHECK: call void @noescapeFunc1({{.*}} nocapture {{.*}})
+// CHECK: declare void @noescapeFunc1({{.*}} nocapture)
+void test1(int *i) {
+ noescapeFunc1(i);
+}
+
+// CHECK-LABEL: define void @test2(
+// CHECK: call void @noescapeFunc2({{.*}} nocapture {{.*}})
+// CHECK: declare void @noescapeFunc2({{.*}} nocapture)
+void test2(id i) {
+ noescapeFunc2(i);
+}
+
+// CHECK-LABEL: define void @test3(
+// CHECK: call void @noescapeFunc3({{.*}} nocapture {{.*}})
+// CHECK: declare void @noescapeFunc3({{.*}} nocapture)
+void test3(union U u) {
+ noescapeFunc3(u);
+}
+
+// CHECK: define internal void @"\01-[C0 m0:]"({{.*}}, {{.*}}, {{.*}} nocapture {{.*}})
+
+// CHECK-LABEL: define void @test4(
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32*)*)(i8* {{.*}}, i8* {{.*}}, i32* nocapture {{.*}})
+
+@interface C0
+-(void) m0:(int*)__attribute__((noescape)) p0;
+@end
+
+@implementation C0
+-(void) m0:(int*)__attribute__((noescape)) p0 {
+}
+@end
+
+void test4(C0 *c0, int *p) {
+ [c0 m0:p];
+}
+
+// CHECK-LABEL: define void @test5(
+// CHECK: call void {{.*}}(i8* bitcast ({ i8**, i32, i32, i8*, {{.*}} }* @{{.*}} to i8*), i32* nocapture {{.*}})
+// CHECK: call void {{.*}}(i8* {{.*}}, i32* nocapture {{.*}})
+// CHECK: define internal void @{{.*}}(i8* {{.*}}, i32* nocapture {{.*}})
+
+typedef void (^BlockTy2)(__attribute__((noescape)) int *);
+
+void test5(BlockTy2 b, int *p) {
+ ^(int *__attribute__((noescape)) p0){}(p);
+ b(p);
+}
diff --git a/test/CodeGenObjC/non-lazy-classes.m b/test/CodeGenObjC/non-lazy-classes.m
index 400d3e9fdf..b04b020e20 100644
--- a/test/CodeGenObjC/non-lazy-classes.m
+++ b/test/CodeGenObjC/non-lazy-classes.m
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | \
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -emit-llvm -o - %s | \
// RUN: FileCheck %s
-// CHECK: @"OBJC_LABEL_NONLAZY_CLASS_$" = private global [1 x {{.*}}] {{.*}}@"OBJC_CLASS_$_A"{{.*}}, section "__DATA, __objc_nlclslist, regular, no_dead_strip", align 8
-// CHECK: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = private global [1 x {{.*}}] {{.*}}@"\01l_OBJC_$_CATEGORY_A_$_Cat"{{.*}}, section "__DATA, __objc_nlcatlist, regular, no_dead_strip", align 8
+// CHECK: @"OBJC_LABEL_NONLAZY_CLASS_$" = private global [1 x {{.*}}] {{.*}}@"OBJC_CLASS_$_A"{{.*}}, section "__DATA,__objc_nlclslist,regular,no_dead_strip", align 8
+// CHECK: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = private global [1 x {{.*}}] {{.*}}@"\01l_OBJC_$_CATEGORY_A_$_Cat"{{.*}}, section "__DATA,__objc_nlcatlist,regular,no_dead_strip", align 8
@interface A @end
@implementation A
diff --git a/test/CodeGenObjC/objc_copyStruct.m b/test/CodeGenObjC/objc_copyStruct.m
new file mode 100644
index 0000000000..7fa0ad54f3
--- /dev/null
+++ b/test/CodeGenObjC/objc_copyStruct.m
@@ -0,0 +1,16 @@
+// RUN: %clang -target x86_64-unknown-windows-msvc -fobjc-runtime=ios -Wno-objc-root-class -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang -target x86_64-apple-ios -fobjc-runtime=ios -Wno-objc-root-class -S -o - -emit-llvm %s | FileCheck %s
+
+struct S {
+ float f, g;
+};
+
+@interface I
+@property struct S s;
+@end
+
+@implementation I
+@end
+
+// CHECK: declare {{.*}}void @objc_copyStruct(i8*, i8*, i64, i1, i1)
+
diff --git a/test/CodeGenObjC/os_log.m b/test/CodeGenObjC/os_log.m
index 5d48783de4..1cf0c9f1f3 100644
--- a/test/CodeGenObjC/os_log.m
+++ b/test/CodeGenObjC/os_log.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-darwin-apple -fobjc-arc -O2 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-darwin-apple -fobjc-arc -O0 | FileCheck %s -check-prefix=CHECK-O0
// Make sure we emit clang.arc.use before calling objc_release as part of the
// cleanup. This way we make sure the object will not be released until the
@@ -12,28 +13,67 @@ extern __attribute__((visibility("default"))) NSString *GenString();
// Behavior of __builtin_os_log differs between platforms, so only test on X86
#ifdef __x86_64__
// CHECK-LABEL: define i8* @test_builtin_os_log
+// CHECK-O0-LABEL: define i8* @test_builtin_os_log
+// CHECK: (i8* returned %[[BUF:.*]])
+// CHECK-O0: (i8* %[[BUF:.*]])
void *test_builtin_os_log(void *buf) {
return __builtin_os_log_format(buf, "capabilities: %@", GenString());
- // CHECK: store i8 2, i8*
- // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* {{.*}}, i64 1
- // CHECK: store i8 1, i8* [[NUM_ARGS]]
- //
- // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* {{.*}}, i64 2
- // CHECK: store i8 64, i8* [[ARG1_DESC]]
- // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* {{.*}}, i64 3
- // CHECK: store i8 8, i8* [[ARG1_SIZE]]
- // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* {{.*}}, i64 4
- // CHECK: [[ARG1_CAST:%.*]] = bitcast i8* [[ARG1]] to
-
- // CHECK: [[STRING:%.*]] = {{.*}} call {{.*}} @GenString()
- // CHECK: [[STRING_CAST:%.*]] = bitcast {{.*}} [[STRING]] to
- // CHECK: call {{.*}} @objc_retainAutoreleasedReturnValue(i8* [[STRING_CAST]])
- // CHECK: store {{.*}} [[STRING]], {{.*}} [[ARG1_CAST]]
-
- // CHECK: call void (...) @clang.arc.use({{.*}} [[STRING]])
- // CHECK: call void @objc_release(i8* [[STRING_CAST]])
- // CHECK: ret i8*
+ // CHECK: %[[CALL:.*]] = tail call %[[TY0:.*]]* (...) @GenString()
+ // CHECK: %[[V0:.*]] = bitcast %[[TY0]]* %[[CALL]] to i8*
+ // CHECK: %[[V1:.*]] = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %[[V0]])
+ // CHECK: %[[V2:.*]] = ptrtoint %[[TY0]]* %[[CALL]] to i64
+ // CHECK: store i8 2, i8* %[[BUF]], align 1
+ // CHECK: %[[NUMARGS_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+ // CHECK: store i8 1, i8* %[[NUMARGS_I]], align 1
+ // CHECK: %[[ARGDESCRIPTOR_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+ // CHECK: store i8 64, i8* %[[ARGDESCRIPTOR_I]], align 1
+ // CHECK: %[[ARGSIZE_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+ // CHECK: store i8 8, i8* %[[ARGSIZE_I]], align 1
+ // CHECK: %[[ARGDATA_I:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+ // CHECK: %[[ARGDATACAST_I:.*]] = bitcast i8* %[[ARGDATA_I]] to i64*
+ // CHECK: store i64 %[[V2]], i64* %[[ARGDATACAST_I]], align 1
+ // CHECK: tail call void (...) @clang.arc.use(%[[TY0]]* %[[CALL]])
+ // CHECK: tail call void @objc_release(i8* %[[V0]])
+ // CHECK: ret i8* %[[BUF]]
+
+ // clang.arc.use is used and removed in IR optimizations. At O0, we should not
+ // emit clang.arc.use, since it will not be removed and we will have a link
+ // error.
+ // CHECK-O0: %[[BUF_ADDR:.*]] = alloca i8*, align 8
+ // CHECK-O0: store i8* %[[BUF]], i8** %[[BUF_ADDR]], align 8
+ // CHECK-O0: %[[V0:.*]] = load i8*, i8** %[[BUF_ADDR]], align 8
+ // CHECK-O0: %[[CALL:.*]] = call %[[TY0:.*]]* (...) @GenString()
+ // CHECK-O0: %[[V1:.*]] = bitcast %[[TY0]]* %[[CALL]] to i8*
+ // CHECK-O0: %[[V2:.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* %[[V1]])
+ // CHECK-O0: %[[V3:.*]] = bitcast i8* %[[V2]] to %[[TY0]]*
+ // CHECK-O0: %[[V4:.*]] = ptrtoint %[[TY0]]* %[[V3]] to i64
+ // CHECK-O0: call void @__os_log_helper_1_2_1_8_64(i8* %[[V0]], i64 %[[V4]])
+ // CHECK-O0: %[[V5:.*]] = bitcast %[[TY0]]* %[[V3]] to i8*
+ // CHECK-O0-NOT call void (...) @clang.arc.use({{.*}}
+ // CHECK-O0: call void @objc_release(i8* %[[V5]])
+ // CHECK-O0: ret i8* %[[V0]]
}
+// CHECK-O0-LABEL: define linkonce_odr hidden void @__os_log_helper_1_2_1_8_64
+// CHECK-O0: (i8* %[[BUFFER:.*]], i64 %[[ARG0:.*]])
+
+// CHECK-O0: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
+// CHECK-O0: %[[ARG0_ADDR:.*]] = alloca i64, align 8
+// CHECK-O0: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
+// CHECK-O0: store i64 %[[ARG0]], i64* %[[ARG0_ADDR]], align 8
+// CHECK-O0: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
+// CHECK-O0: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
+// CHECK-O0: store i8 2, i8* %[[SUMMARY]], align 1
+// CHECK-O0: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
+// CHECK-O0: store i8 1, i8* %[[NUMARGS]], align 1
+// CHECK-O0: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
+// CHECK-O0: store i8 64, i8* %[[ARGDESCRIPTOR]], align 1
+// CHECK-O0: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
+// CHECK-O0: store i8 8, i8* %[[ARGSIZE]], align 1
+// CHECK-O0: %[[ARGDATA:.*]] = getelementptr i8, i8* %[[BUF]], i64 4
+// CHECK-O0: %[[ARGDATACAST:.*]] = bitcast i8* %[[ARGDATA]] to i64*
+// CHECK-O0: %[[V0:.*]] = load i64, i64* %[[ARG0_ADDR]], align 8
+// CHECK-O0: store i64 %[[V0]], i64* %[[ARGDATACAST]], align 1
+
#endif
diff --git a/test/CodeGenObjC/parameterized_classes.m b/test/CodeGenObjC/parameterized_classes.m
index b75cf2e3ad..34aca35af3 100644
--- a/test/CodeGenObjC/parameterized_classes.m
+++ b/test/CodeGenObjC/parameterized_classes.m
@@ -68,3 +68,59 @@ void blockTest(NSMutableArray<void (^)(void)> *array, NSString *name) {
// CHECK: call i8* @objc_retainBlock
// CHECK: ret void
}
+
+// CHECK-LABEL: define internal void @"\01-[Derived setDest:]
+// CHECK: %[[SELFADDR:.*]] = alloca %[[SELFTY:.*]]*
+// CHECK: %[[AADDR:.*]] = alloca %[[IVARTY:.*]]*
+// CHECK: %[[V2:.*]] = load %[[IVARTY]]*, %[[IVARTY]]** %[[AADDR]]
+// CHECK: %[[V3:.*]] = load %[[SELFTY]]*, %[[SELFTY]]** %[[SELFADDR]]
+// CHECK: %[[IVAR:.*]] = load i64, i64* @"OBJC_IVAR_$_Base._destination"
+// CHECK: %[[V4:.*]] = bitcast %[[SELFTY]]* %[[V3]] to i8*
+// CHECK: %[[ADDPTR:.*]] = getelementptr inbounds i8, i8* %[[V4]], i64 %[[IVAR]]
+// CHECK: %[[V5:.*]] = bitcast i8* %[[ADDPTR]] to %[[IVARTY]]**
+// CHECK: %[[V6:.*]] = bitcast %[[IVARTY]]** %[[V5]] to i8**
+// CHECK: %[[V7:.*]] = bitcast %[[IVARTY]]* %[[V2]] to i8*
+// CHECK: call void @objc_storeStrong(i8** %[[V6]], i8* %[[V7]])
+
+@interface Base<DestType> : NSObject {
+ DestType _destination;
+}
+@end
+
+@interface Derived : Base<NSObject *>
+- (void)setDest:(NSObject *)a;
+@end
+
+@implementation Derived
+- (void)setDest:(NSObject *)a {
+ _destination = a;
+}
+@end
+
+// CHECK-LABEL: define internal void @"\01-[C0 foo1]"(
+// CHECK: {{.*}} = alloca
+// CHECK: {{.*}} = alloca
+// CHECK: %[[D:.*]] = alloca %[[TY:.*]]*
+// CHECK: %[[TEMP:.*]] = alloca %[[TY]]*
+// CHECK: %[[V4:.*]] = load %[[TY]]*, %[[TY]]** %[[D]]
+// CHECK: store %[[TY]]* %[[V4]], %[[TY]]** %[[TEMP]]
+// CHECK: %[[V7:.*]] = bitcast %[[TY]]** %[[TEMP]] to i8**
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8**)*)(i8* %{{.*}}, i8* %{{.*}}, i8** %[[V7]])
+
+@interface P0<ObjectType> : NSObject
+- (void)m0:(ObjectType *)first;
+@end
+
+@interface C0 : NSObject
+-(void)foo1;
+@end
+
+@implementation C0 {
+ P0<NSString *> *x;
+}
+
+-(void)foo1 {
+ NSString *d;
+ [x m0:&d];
+}
+@end
diff --git a/test/CodeGenObjC/protocol-comdat.m b/test/CodeGenObjC/protocol-comdat.m
index 65e1b9fa2c..a19ba8cf35 100644
--- a/test/CodeGenObjC/protocol-comdat.m
+++ b/test/CodeGenObjC/protocol-comdat.m
@@ -4,6 +4,9 @@
- (void) method;
@end
+@protocol Q;
+@protocol R;
+
@interface I<P>
@end
@@ -11,9 +14,14 @@
- (void) method { }
@end
+_Bool f(void) {
+ return @protocol(Q) == @protocol(R);
+}
// CHECK: $"\01l_OBJC_PROTOCOL_$_P" = comdat any
// CHECK: $"\01l_OBJC_LABEL_PROTOCOL_$_P" = comdat any
+// CHECK: $"\01l_OBJC_PROTOCOL_REFERENCE_$_Q" = comdat any
+// CHECK: $"\01l_OBJC_PROTOCOL_REFERENCE_$_R" = comdat any
// CHECK: @"\01l_OBJC_PROTOCOL_$_P" = {{.*}}, comdat
// CHECK: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, comdat
diff --git a/test/CodeGenObjC/sections.m b/test/CodeGenObjC/sections.m
new file mode 100644
index 0000000000..f98b7db073
--- /dev/null
+++ b/test/CodeGenObjC/sections.m
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-windows -fobjc-dispatch-method=mixed -fobjc-runtime=ios -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-COFF
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fobjc-dispatch-method=mixed -fobjc-runtime=ios -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-ELF
+// RUN: %clang_cc1 -triple x86_64-apple-ios -fobjc-dispatch-method=mixed -fobjc-runtime=ios -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-MACHO
+
+__attribute__((__objc_root_class__))
+@interface NSObject
++ (void)load;
++ (id)class;
+@end
+
+@protocol P
+@end
+
+@interface I<P> : NSObject
++ (void)load;
+@end
+
+@implementation I
++ (void)load; { }
+@end
+
+@implementation I(C)
++ (void)load; {
+ [super load];
+}
+@end
+
+@interface J : NSObject
+- (void)m;
+@end
+
+_Bool f(J *j) {
+ [j m];
+ return [I class] == @protocol(P);
+}
+
+// CHECK-COFF: @"OBJC_CLASSLIST_SUP_REFS_$_" = {{.*}}, section ".objc_superrefs$B"
+// CHECK-COFF: @OBJC_SELECTOR_REFERENCES_ = {{.*}}, section ".objc_selrefs$B"
+// CHECK-COFF: @"OBJC_CLASSLIST_REFERENCES_$_" = {{.*}}, section ".objc_classrefs$B"
+// CHECK-COFF: @"\01l_objc_msgSend_fixup_class" = {{.*}}, section ".objc_msgrefs$B"
+// CHECK-COFF: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, section ".objc_protolist$B"
+// CHECK-COFF: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P" = {{.*}}, section ".objc_protorefs$B"
+// CHECK-COFF: @"OBJC_LABEL_CLASS_$" = {{.*}}, section ".objc_classlist$B"
+// CHECK-COFF: @"OBJC_LABEL_NONLAZY_CLASS_$" = {{.*}}, section ".objc_nlclslist$B"
+// CHECK-COFF: @"OBJC_LABEL_CATEGORY_$" = {{.*}}, section ".objc_catlist$B"
+// CHECK-COFF: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = {{.*}}, section ".objc_nlcatlist$B"
+// CHECK-COFF: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !".objc_imageinfo$B"}
+
+// CHECK-ELF: @"OBJC_CLASSLIST_SUP_REFS_$_" = {{.*}}, section "objc_superrefs"
+// CHECK-ELF: @OBJC_SELECTOR_REFERENCES_ = {{.*}}, section "objc_selrefs"
+// CHECK-ELF: @"OBJC_CLASSLIST_REFERENCES_$_" = {{.*}}, section "objc_classrefs"
+// CHECK-ELF: @"\01l_objc_msgSend_fixup_class" = {{.*}}, section "objc_msgrefs"
+// CHECK-ELF: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, section "objc_protolist"
+// CHECK-ELF: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P" = {{.*}}, section "objc_protorefs"
+// CHECK-ELF: @"OBJC_LABEL_CLASS_$" = {{.*}}, section "objc_classlist"
+// CHECK-ELF: @"OBJC_LABEL_NONLAZY_CLASS_$" = {{.*}}, section "objc_nlclslist"
+// CHECK-ELF: @"OBJC_LABEL_CATEGORY_$" = {{.*}}, section "objc_catlist"
+// CHECK-ELF: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = {{.*}}, section "objc_nlcatlist"
+// CHECK-ELF: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"objc_imageinfo"}
+
+// CHECK-MACHO: @"OBJC_CLASSLIST_SUP_REFS_$_" = {{.*}}, section "__DATA,__objc_superrefs,regular,no_dead_strip"
+// CHECK-MACHO: @OBJC_SELECTOR_REFERENCES_ = {{.*}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip"
+// CHECK-MACHO: @"OBJC_CLASSLIST_REFERENCES_$_" = {{.*}}, section "__DATA,__objc_classrefs,regular,no_dead_strip"
+// CHECK-MACHO: @"\01l_objc_msgSend_fixup_class" = {{.*}}, section "__DATA,__objc_msgrefs,coalesced"
+// CHECK-MACHO: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, section "__DATA,__objc_protolist,coalesced,no_dead_strip"
+// CHECK-MACHO: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P" = {{.*}}, section "__DATA,__objc_protorefs,coalesced,no_dead_strip"
+// CHECK-MACHO: @"OBJC_LABEL_CLASS_$" = {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip"
+// CHECK-MACHO: @"OBJC_LABEL_NONLAZY_CLASS_$" = {{.*}}, section "__DATA,__objc_nlclslist,regular,no_dead_strip"
+// CHECK-MACHO: @"OBJC_LABEL_CATEGORY_$" = {{.*}}, section "__DATA,__objc_catlist,regular,no_dead_strip"
+// CHECK-MACHO: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = {{.*}}, section "__DATA,__objc_nlcatlist,regular,no_dead_strip"
+// CHECK-MACHO: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+
diff --git a/test/CodeGenObjC/stret-1.m b/test/CodeGenObjC/stret-1.m
index a7bcdda48b..2314d5a9ec 100644
--- a/test/CodeGenObjC/stret-1.m
+++ b/test/CodeGenObjC/stret-1.m
@@ -12,11 +12,20 @@ struct stret one = {{1}};
int main(int argc, const char **argv)
{
- [(id)(argc&~255) method];
+ struct stret s;
+ s = [(id)(argc&~255) method];
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T0:%[^,]+]]
// CHECK: [[T0P:%.*]] = bitcast %struct.stret* [[T0]] to i8*
// CHECK: call void @llvm.memset.p0i8.i64(i8* [[T0P]], i8 0, i64 400, i32 4, i1 false)
+ s = [Test method];
+ // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]]
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64(
+
+ [(id)(argc&~255) method];
+ // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]]
+ // CHECK-NOT: call void @llvm.memset.p0i8.i64(
+
[Test method];
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]]
// CHECK-NOT: call void @llvm.memset.p0i8.i64(
diff --git a/test/CodeGenObjC/stret-lifetime.m b/test/CodeGenObjC/stret-lifetime.m
new file mode 100644
index 0000000000..d81ef34aee
--- /dev/null
+++ b/test/CodeGenObjC/stret-lifetime.m
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple arm64-apple-darwin -S -emit-llvm -o - -O2 -disable-llvm-passes %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -S -emit-llvm -o - -O2 -disable-llvm-passes %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-darwin -fobjc-arc -S -emit-llvm -o - -O2 -disable-llvm-passes %s | FileCheck %s --check-prefixes=CHECK,ARC
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -S -emit-llvm -o - -O2 -disable-llvm-passes %s | FileCheck %s --check-prefixes=CHECK,ARC
+
+struct stret { int x[100]; };
+struct stret one = {{1}};
+
+@interface Test
++(struct stret) method;
++(struct stret) methodConsuming:(id __attribute__((ns_consumed)))consumed;
+@end
+
+void foo(id o, id p) {
+ [o method];
+ // CHECK: @llvm.lifetime.start
+ // CHECK: call void bitcast {{.*}} @objc_msgSend
+ // CHECK: @llvm.lifetime.end
+ // CHECK-NOT: call void @llvm.memset
+
+ [o methodConsuming:p];
+ // ARC: [[T0:%.*]] = icmp eq i8*
+ // ARC: br i1 [[T0]]
+
+ // CHECK: @llvm.lifetime.start
+ // CHECK: call void bitcast {{.*}} @objc_msgSend
+ // CHECK: @llvm.lifetime.end
+ // ARC: br label
+
+ // ARC: call void @objc_release
+ // ARC: br label
+
+ // CHECK-NOT: call void @llvm.memset
+}
diff --git a/test/CodeGenObjC/ubsan-nonnull-and-nullability.m b/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
index b927f55cd4..db6588dac3 100644
--- a/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
+++ b/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
@@ -7,16 +7,26 @@
// CHECK-LABEL: define nonnull i32* @f1
__attribute__((returns_nonnull)) int *_Nonnull f1(int *_Nonnull p) {
// CHECK: entry:
+ // CHECK-NEXT: [[SLOC_PTR:%.*]] = alloca i8*
// CHECK-NEXT: [[ADDR:%.*]] = alloca i32*
+ // CHECK-NEXT: store i8* null, i8** [[SLOC_PTR]]
// CHECK-NEXT: store i32* [[P:%.*]], i32** [[ADDR]]
+ // CHECK-NEXT: store {{.*}} [[SLOC_PTR]]
// CHECK-NEXT: [[ARG:%.*]] = load i32*, i32** [[ADDR]]
+ // CHECK-NEXT: [[SLOC:%.*]] = load {{.*}} [[SLOC_PTR]]
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC]], null
+ // CHECK-NEXT: br i1 [[SLOC_NONNULL]], label %nullcheck
+ //
+ // CHECK: nullcheck:
// 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: call void @__ubsan_handle_nonnull_return
// CHECK-NEXT: unreachable, !nosanitize
// CHECK: [[CONT]]:
- // CHECK-NEXT: ret i32*
+ // CHECK-NEXT: br label %no.nullcheck
+ // CHECK: no.nullcheck:
+ // CHECK-NEXT: ret i32* [[ARG]]
return p;
}
@@ -29,3 +39,23 @@ void call_f2() {
// CHECK-NOT: call void @__ubsan_handle_nonnull_arg_abort
f2((void *)0);
}
+
+// If the return value isn't meant to be checked, make sure we don't check it.
+// CHECK-LABEL: define i32* @f3
+int *f3(int *p) {
+ // CHECK-NOT: return.sloc
+ // CHECK-NOT: call{{.*}}ubsan
+ return p;
+}
+
+// Check for a valid "return" source location, even when there is no return
+// statement, to avoid accidentally calling the runtime.
+
+// CHECK-LABEL: define nonnull i32* @f4
+__attribute__((returns_nonnull)) int *f4() {
+ // CHECK: store i8* null, i8** [[SLOC_PTR:%.*]]
+ // CHECK: [[SLOC:%.*]] = load {{.*}} [[SLOC_PTR]]
+ // CHECK: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC]], null
+ // CHECK: br i1 [[SLOC_NONNULL]], label %nullcheck
+ // CHECK: nullcheck:
+}
diff --git a/test/CodeGenObjC/ubsan-nullability.m b/test/CodeGenObjC/ubsan-nullability.m
index d72b774ec7..eeb24b03c8 100644
--- a/test/CodeGenObjC/ubsan-nullability.m
+++ b/test/CodeGenObjC/ubsan-nullability.m
@@ -1,44 +1,44 @@
// 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
+// 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_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} 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_ASSIGN3_LOC:@.*]] = private unnamed_addr global {{.*}} i32 506, 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
+// CHECK: [[NONNULL_RV_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 800, i32 6
#define NULL ((void *)0)
+#define INULL ((int *)NULL)
+#define INNULL ((int *_Nonnull)NULL)
-// CHECK-LABEL: define i32* @nonnull_retval1
+// 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_nonnull_return{{.*}}[[NONNULL_RV_LOC1]]
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC1]]
return p;
- // CHECK: [[NONULL]]:
- // CHECK-NEXT: ret i32*
+ // CHECK: ret i32*
}
#line 190
void nonnull_arg(int *_Nonnull p) {}
-// CHECK-LABEL: define void @call_func_with_nonnull_arg
+// 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_nonnull_arg{{.*}}[[NONNULL_ARG_LOC]]
+ // CHECK: call void @__ubsan_handle_nullability_arg{{.*}}[[NONNULL_ARG_LOC]]
nonnull_arg(p);
}
-// CHECK-LABEL: define void @nonnull_assign1
+// CHECK-LABEL: define void @{{.*}}nonnull_assign1
#line 300
void nonnull_assign1(int *p) {
// CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
@@ -48,7 +48,7 @@ void nonnull_assign1(int *p) {
local = p;
}
-// CHECK-LABEL: define void @nonnull_assign2
+// CHECK-LABEL: define void @{{.*}}nonnull_assign2
#line 400
void nonnull_assign2(int *p) {
// CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
@@ -62,17 +62,18 @@ struct S1 {
int *_Nonnull mptr;
};
-// CHECK-LABEL: define void @nonnull_assign3
+// 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]]
+ // CHECK-NOT: call void @__ubsan_handle_type_mismatch
struct S1 s;
s.mptr = p;
}
-// CHECK-LABEL: define void @nonnull_init1
+// CHECK-LABEL: define void @{{.*}}nonnull_init1
#line 600
void nonnull_init1(int *p) {
// CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
@@ -81,7 +82,7 @@ void nonnull_init1(int *p) {
int *_Nonnull local = p;
}
-// CHECK-LABEL: define void @nonnull_init2
+// CHECK-LABEL: define void @{{.*}}nonnull_init2
#line 700
void nonnull_init2(int *p) {
// CHECK: [[ICMP:%.*]] = icmp ne i32* %{{.*}}, null, !nosanitize
@@ -93,7 +94,7 @@ void nonnull_init2(int *p) {
int *_Nonnull arr[] = {p, p};
}
-// CHECK-LABEL: define i32* @nonnull_retval2
+// CHECK-LABEL: define i32* @{{.*}}nonnull_retval2
#line 800
int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
int *_Nonnull arg2, //< Test this.
@@ -104,11 +105,14 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
// 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: [[SLOC_PTR:%.*]] = load i8*, i8** %return.sloc.ptr
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC_PTR]], null
+ // CHECK-NEXT: [[DO_RV_CHECK_3:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK_2]]
+ // CHECK: br i1 [[DO_RV_CHECK_3]], 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_nonnull_return{{.*}}[[NONNULL_RV_LOC2]]
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC2]]
return arg1;
// CHECK: [[NONULL]]:
// CHECK-NEXT: ret i32*
@@ -125,11 +129,14 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
+(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: [[SLOC_PTR:%.*]] = load i8*, i8** %return.sloc.ptr
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC_PTR]], null
+ // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK]]
+ // 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_nonnull_return{{.*}}
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_return{{.*}}
return arg1;
// CHECK: [[NONULL]]:
// CHECK-NEXT: ret i32*
@@ -139,28 +146,31 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
-(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: [[SLOC_PTR:%.*]] = load i8*, i8** %return.sloc.ptr
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC_PTR]], null
+ // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK]]
+ // 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_nonnull_return{{.*}}
+ // CHECK: 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
+// 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_nonnull_arg{{.*}} !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_nonnull_arg{{.*}} !nosanitize
+ // CHECK: call void @__ubsan_handle_nullability_arg{{.*}} !nosanitize
// CHECK: call i32* {{.*}} @objc_msgSend to i32* {{.*}}({{.*}}, i32* [[P2]])
[A objc_clsmethod: p];
}
@@ -168,15 +178,15 @@ void call_A(A *a, int *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);
+ nonnull_retval1(INULL);
+ nonnull_retval2(INNULL, INNULL, INULL, (int *_Nullable)NULL, 0, 0, 0, 0);
+ call_func_with_nonnull_arg(INNULL);
+ nonnull_assign1(INULL);
+ nonnull_assign2(INULL);
+ nonnull_assign3(INULL);
+ nonnull_init1(INULL);
+ nonnull_init2(INULL);
+ call_A((A *)NULL, INULL);
+ dont_crash(INNULL, NULL);
return 0;
}
diff --git a/test/CodeGenObjCXX/arc-indirect.mm b/test/CodeGenObjCXX/arc-indirect.mm
new file mode 100644
index 0000000000..6982bac041
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-indirect.mm
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++11 -triple i686-unknown-windows-msvc -fobjc-runtime=gnustep -fobjc-arc -Wno-objc-root-class -emit-llvm -o - %s | FileCheck -check-prefixes CHECK,CHECK-GNUSTEP %s
+// RUN: %clang_cc1 -std=c++11 -triple i686-unknown-windows-msvc -fobjc-runtime=macosx -fobjc-arc -Wno-objc-root-class -emit-llvm -o - %s | FileCheck -check-prefixes CHECK,CHECK-DARWIN %s
+// RUN: %clang_cc1 -std=c++11 -triple i686-unknown-windows-msvc -fobjc-runtime=ios -fobjc-arc -Wno-objc-root-class -emit-llvm -o - %s | FileCheck -check-prefixes CHECK,CHECK-DARWIN %s
+
+// non trivially copyable, forces inalloca
+struct S {
+ S(const S &s) {}
+};
+
+@interface C
+@end
+
+@implementation C
+- (void)object:(id)obj struct:(S)s {
+}
+@end
+
+// CHECK-GNUSTEP: define internal void @_i_C__object_struct_(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* inalloca)
+// CHECK-DARWIN: define internal void @"\01-[C object:struct:]"(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* inalloca)
+// CHECK: %obj = getelementptr inbounds <{ %0*, i8*, i8*, %struct.S, [3 x i8] }>, <{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* %0, i32 0, i32 2
+// CHECK: %[[INSTANCE:[0-9]+]] = load i8*, i8** %obj, align 4
+// CHECK: call void @objc_storeStrong(i8** %obj, i8* %[[INSTANCE]])
diff --git a/test/CodeGenObjCXX/arc-mangle.mm b/test/CodeGenObjCXX/arc-mangle.mm
index 82e37556ec..b39aa7bbbf 100644
--- a/test/CodeGenObjCXX/arc-mangle.mm
+++ b/test/CodeGenObjCXX/arc-mangle.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -triple %itanium_abi_triple -emit-llvm -fblocks -o - %s | FileCheck %s
+// RUN: %clang_cc1 -DTEST_UNALIGNED -fms-extensions -fobjc-arc -fobjc-runtime-has-weak -triple %itanium_abi_triple -emit-llvm -fblocks -o - %s | FileCheck %s --check-prefix=UNALIGNED
// CHECK-LABEL: define {{.*}}void @_Z1fPU8__strongP11objc_object(i8**)
void f(__strong id *) {}
@@ -32,3 +33,12 @@ template<unsigned N> struct unsigned_c { };
// CHECK-LABEL: define weak_odr {{.*}}void @_Z1gIKvEvP10unsigned_cIXplszv1U8__bridgecvPT_v1U8__bridgecvP11objc_objectcvS3_Li0ELi1EEE
template<typename T>void g(unsigned_c<sizeof((__bridge T*)(__bridge id)(T*)0) + 1>*) {}
template void g<const void>(unsigned_c<sizeof(id) + 1> *);
+
+#if TEST_UNALIGNED
+// UNALIGNED-LABEL: define {{.*}}void @_Z1gPU6__weakU11__unalignedP11objc_object(i8**)
+void g(__weak __unaligned id *) {}
+// UNALIGNED-LABEL: define {{.*}}void @_Z1gPU11__unalignedU8__strongP11objc_object(i8**)
+void g(__strong __unaligned id *) {}
+// UNALIGNED-LABEL: define {{.*}}void @_Z1gPU11__unalignedU15__autoreleasingP11objc_object(i8**)
+void g(__autoreleasing __unaligned id *) {}
+#endif // TEST_UNALIGNED
diff --git a/test/CodeGenObjCXX/arc-move.mm b/test/CodeGenObjCXX/arc-move.mm
index 7437d6b6c7..def2cea956 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 c62df4e49b..983b211dfb 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 b9d2c4de2f..5e66206ad5 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/boxing.mm b/test/CodeGenObjCXX/boxing.mm
new file mode 100644
index 0000000000..dc35360358
--- /dev/null
+++ b/test/CodeGenObjCXX/boxing.mm
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+@interface NSNumber
++ (id)numberWithInt:(int)n;
+@end
+
+int n = 1;
+int m = (@(n++), 0);
+
+// CHECK: define {{.*}} @__cxx_global_var_init()
+// CHECK: load i32, i32* @n
+// CHECK: store i32 %{{.*}}, i32* @n
diff --git a/test/CodeGenObjCXX/lambda-to-block.mm b/test/CodeGenObjCXX/lambda-to-block.mm
new file mode 100644
index 0000000000..a8d0718b12
--- /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 128601edd6..6a112312bd 100644
--- a/test/CodeGenObjCXX/literals.mm
+++ b/test/CodeGenObjCXX/literals.mm
@@ -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/mangle-blocks.mm b/test/CodeGenObjCXX/mangle-blocks.mm
index 283996d18a..bbe5c1f77f 100644
--- a/test/CodeGenObjCXX/mangle-blocks.mm
+++ b/test/CodeGenObjCXX/mangle-blocks.mm
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
-// CHECK: @_ZZZN26externally_visible_statics1S3fooEiEd_Ub0_E1k = linkonce_odr global i32 0
-// CHECK: @_ZZZN26externally_visible_statics10inlinefuncEvEUb0_E1i = linkonce_odr global i32 0
-// CHECK: @_ZZ26externally_visible_statics1S1xMUb0_E1j = linkonce_odr global i32 0
+// CHECK-DAG: @_ZZZN26externally_visible_statics1S3fooEiEd_Ub_E1k = linkonce_odr global i32 0
+// CHECK-DAG: @_ZZZN26externally_visible_statics10inlinefuncEvEUb_E1i = linkonce_odr global i32 0
+// CHECK-DAG: @_ZZZN26externally_visible_statics10inlinefuncEvEUb0_E1j = linkonce_odr global i32 0
+// CHECK-DAG: @_ZZ26externally_visible_statics1S1xMUb_E1j = linkonce_odr global i32 0
int f();
@@ -68,6 +69,9 @@ namespace externally_visible_statics {
^{
static int i = f();
}();
+ ^{
+ static int j = f();
+ }();
}
struct S {
int x = ^{
diff --git a/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm b/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm
index 0b01b27fa7..cb71bcf0aa 100644
--- a/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm
+++ b/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm
@@ -9,7 +9,7 @@ struct A {
// Verify that we destruct things from left to right in the MS C++ ABI: a, b, c, d.
//
-// CHECK-LABEL: define void @"\01?test_arc_order@@YAXUA@@PAAAPAUobjc_object@@01@Z"
+// CHECK-LABEL: define void @"\01?test_arc_order@@YAXUA@@PAUobjc_object@@01@Z"
// CHECK: (<{ %struct.A, i8*, %struct.A, i8* }>* inalloca)
void test_arc_order(A a, id __attribute__((ns_consumed)) b , A c, id __attribute__((ns_consumed)) d) {
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %{{.*}})
diff --git a/test/CodeGenObjCXX/msabi-objc-types.mm b/test/CodeGenObjCXX/msabi-objc-types.mm
new file mode 100644
index 0000000000..013a9c84da
--- /dev/null
+++ b/test/CodeGenObjCXX/msabi-objc-types.mm
@@ -0,0 +1,122 @@
+// RUN: %clang_cc1 -triple thumbv7-windows-msvc -fdeclspec -std=c++11 -fobjc-runtime=ios-6.0 -o - -emit-llvm %s | FileCheck %s
+
+@class I;
+
+id kid;
+// CHECK: @"\01?kid@@3PAUobjc_object@@A" = global
+
+Class klass;
+// CHECK: @"\01?klass@@3PAUobjc_class@@A" = global
+
+I *kI;
+// CHECK: @"\01?kI@@3PAUI@@A" = global
+
+void f(I *) {}
+// CHECK-LABEL: "\01?f@@YAXPAUI@@@Z"
+
+void f(const I *) {}
+// CHECK-LABEL: "\01?f@@YAXPBUI@@@Z"
+
+void f(I &) {}
+// CHECK-LABEL: "\01?f@@YAXAAUI@@@Z"
+
+void f(const I &) {}
+// CHECK-LABEL: "\01?f@@YAXABUI@@@Z"
+
+void f(const I &&) {}
+// CHECK-LABEL: "\01?f@@YAX$$QBUI@@@Z"
+
+void g(id) {}
+// CHECK-LABEL: "\01?g@@YAXPAUobjc_object@@@Z"
+
+void g(id &) {}
+// CHECK-LABEL: "\01?g@@YAXAAPAUobjc_object@@@Z"
+
+void g(const id &) {}
+// CHECK-LABEL: "\01?g@@YAXABPAUobjc_object@@@Z"
+
+void g(id &&) {}
+// CHECK-LABEL: "\01?g@@YAX$$QAPAUobjc_object@@@Z"
+
+void h(Class) {}
+// CHECK-LABEL: "\01?h@@YAXPAUobjc_class@@@Z"
+
+void h(Class &) {}
+// CHECK-LABEL: "\01?h@@YAXAAPAUobjc_class@@@Z"
+
+void h(const Class &) {}
+// CHECK-LABEL: "\01?h@@YAXABPAUobjc_class@@@Z"
+
+void h(Class &&) {}
+// CHECK-LABEL: "\01?h@@YAX$$QAPAUobjc_class@@@Z"
+
+I *i() { return nullptr; }
+// CHECK-LABEL: "\01?i@@YAPAUI@@XZ"
+
+const I *j() { return nullptr; }
+// CHECK-LABEL: "\01?j@@YAPBUI@@XZ"
+
+I &k() { return *kI; }
+// CHECK-LABEL: "\01?k@@YAAAUI@@XZ"
+
+const I &l() { return *kI; }
+// CHECK-LABEL: "\01?l@@YAABUI@@XZ"
+
+struct __declspec(dllexport) s {
+ struct s &operator=(const struct s &) = delete;
+
+ void m(I *) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXPAUI@@@Z"
+
+ void m(const I *) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXPBUI@@@Z"
+
+ void m(I &) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXAAUI@@@Z"
+
+ void m(const I &) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXABUI@@@Z"
+
+ void m(I &&) {}
+ // CHECK-LABEL: "\01?m@s@@QAAX$$QAUI@@@Z"
+
+ void m(const I &&) {}
+ // CHECK-LABEL: "\01?m@s@@QAAX$$QBUI@@@Z"
+
+ void m(id) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXPAUobjc_object@@@Z"
+
+ void m(id &) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXAAPAUobjc_object@@@Z"
+
+ void m(id &&) {}
+ // CHECK-LABEL: "\01?m@s@@QAAX$$QAPAUobjc_object@@@Z"
+
+ void m(const id &) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXABPAUobjc_object@@@Z"
+
+ void m(const id &&) {}
+ // CHECK-LABEL: "\01?m@s@@QAAX$$QBPAUobjc_object@@@Z"
+
+ void m(Class *) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXPAPAUobjc_class@@@Z"
+
+ void m(const Class *) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXPBPAUobjc_class@@@Z"
+
+ void m(Class) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXPAUobjc_class@@@Z"
+
+ void m(Class &) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXAAPAUobjc_class@@@Z"
+
+ void m(const Class &) {}
+ // CHECK-LABEL: "\01?m@s@@QAAXABPAUobjc_class@@@Z"
+
+ void m(Class &&) {}
+ // CHECK-LABEL: "\01?m@s@@QAAX$$QAPAUobjc_class@@@Z"
+
+ void m(const Class &&) {}
+ // CHECK-LABEL: "\01?m@s@@QAAX$$QBPAUobjc_class@@@Z"
+};
+
diff --git a/test/CodeGenObjCXX/objc-weak.mm b/test/CodeGenObjCXX/objc-weak.mm
new file mode 100644
index 0000000000..68c2d46111
--- /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 0000000000..2c3182f543
--- /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/addr-space-struct-arg.cl b/test/CodeGenOpenCL/addr-space-struct-arg.cl
index d711f78d4e..68fc8035b4 100644
--- a/test/CodeGenOpenCL/addr-space-struct-arg.cl
+++ b/test/CodeGenOpenCL/addr-space-struct-arg.cl
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -ffake-address-space-map -triple i686-pc-darwin | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -finclude-default-header -ffake-address-space-map -triple i686-pc-darwin | FileCheck -enable-var-scope -check-prefixes=COM,X86 %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -finclude-default-header -triple amdgcn-amdhsa-amd-amdgizcl | FileCheck -enable-var-scope -check-prefixes=COM,AMD %s
typedef struct {
int cells[9];
@@ -8,16 +9,125 @@ typedef struct {
int cells[16];
} Mat4X4;
+typedef struct {
+ int cells[1024];
+} Mat32X32;
+
+typedef struct {
+ int cells[4096];
+} Mat64X64;
+
+struct StructOneMember {
+ int2 x;
+};
+
+struct StructTwoMember {
+ int2 x;
+ int2 y;
+};
+
+struct LargeStructOneMember {
+ int2 x[100];
+};
+
+struct LargeStructTwoMember {
+ int2 x[40];
+ int2 y[20];
+};
+
+
+// X86-LABEL: define void @foo(%struct.Mat4X4* noalias sret %agg.result, %struct.Mat3X3* byval align 4 %in)
+// AMD-LABEL: define %struct.Mat4X4 @foo([9 x i32] %in.coerce)
Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) {
Mat4X4 out;
return out;
}
+// COM-LABEL: define {{.*}} void @ker
+// Expect two mem copies: one for the argument "in", and one for
+// the return value.
+// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
+// X86: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
+
+// AMD: load [9 x i32], [9 x i32] addrspace(1)*
+// AMD: call %struct.Mat4X4 @foo([9 x i32]
+// AMD: call void @llvm.memcpy.p1i8.p5i8.i64(i8 addrspace(1)*
kernel void ker(global Mat3X3 *in, global Mat4X4 *out) {
out[0] = foo(in[1]);
}
+// X86-LABEL: define void @foo_large(%struct.Mat64X64* noalias sret %agg.result, %struct.Mat32X32* byval align 4 %in)
+// AMD-LABEL: define void @foo_large(%struct.Mat64X64 addrspace(5)* noalias sret %agg.result, %struct.Mat32X32 addrspace(5)* byval align 4 %in)
+Mat64X64 __attribute__((noinline)) foo_large(Mat32X32 in) {
+ Mat64X64 out;
+ return out;
+}
+
+// COM-LABEL: define {{.*}} void @ker_large
// Expect two mem copies: one for the argument "in", and one for
// the return value.
-// CHECK: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
-// CHECK: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
+// X86: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
+// X86: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
+// AMD: call void @llvm.memcpy.p5i8.p1i8.i64(i8 addrspace(5)*
+// AMD: call void @llvm.memcpy.p1i8.p5i8.i64(i8 addrspace(1)*
+kernel void ker_large(global Mat32X32 *in, global Mat64X64 *out) {
+ out[0] = foo_large(in[1]);
+}
+
+// AMD-LABEL: define void @FuncOneMember(<2 x i32> %u.coerce)
+void FuncOneMember(struct StructOneMember u) {
+ u.x = (int2)(0, 0);
+}
+
+// AMD-LABEL: define void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %u)
+void FuncOneLargeMember(struct LargeStructOneMember u) {
+ u.x[0] = (int2)(0, 0);
+}
+
+// AMD-LABEL: define amdgpu_kernel void @KernelOneMember
+// AMD-SAME: (<2 x i32> %[[u_coerce:.*]])
+// AMD: %[[u:.*]] = alloca %struct.StructOneMember, align 8, addrspace(5)
+// AMD: %[[coerce_dive:.*]] = getelementptr inbounds %struct.StructOneMember, %struct.StructOneMember addrspace(5)* %[[u]], i32 0, i32 0
+// AMD: store <2 x i32> %[[u_coerce]], <2 x i32> addrspace(5)* %[[coerce_dive]]
+// AMD: call void @FuncOneMember(<2 x i32>
+kernel void KernelOneMember(struct StructOneMember u) {
+ FuncOneMember(u);
+}
+
+// AMD-LABEL: define amdgpu_kernel void @KernelLargeOneMember(
+// AMD: %[[U:.*]] = alloca %struct.LargeStructOneMember, align 8, addrspace(5)
+// AMD: store %struct.LargeStructOneMember %u.coerce, %struct.LargeStructOneMember addrspace(5)* %[[U]], align 8
+// AMD: call void @FuncOneLargeMember(%struct.LargeStructOneMember addrspace(5)* byval align 8 %[[U]])
+kernel void KernelLargeOneMember(struct LargeStructOneMember u) {
+ FuncOneLargeMember(u);
+}
+
+// AMD-LABEL: define void @FuncTwoMember(<2 x i32> %u.coerce0, <2 x i32> %u.coerce1)
+void FuncTwoMember(struct StructTwoMember u) {
+ u.y = (int2)(0, 0);
+}
+
+// AMD-LABEL: define void @FuncLargeTwoMember(%struct.LargeStructTwoMember addrspace(5)* byval align 8 %u)
+void FuncLargeTwoMember(struct LargeStructTwoMember u) {
+ u.y[0] = (int2)(0, 0);
+}
+
+
+// AMD-LABEL: define amdgpu_kernel void @KernelTwoMember
+// AMD-SAME: (%struct.StructTwoMember %[[u_coerce:.*]])
+// AMD: %[[u:.*]] = alloca %struct.StructTwoMember, align 8, addrspace(5)
+// AMD: %[[LD0:.*]] = load <2 x i32>, <2 x i32> addrspace(5)*
+// AMD: %[[LD1:.*]] = load <2 x i32>, <2 x i32> addrspace(5)*
+// AMD: call void @FuncTwoMember(<2 x i32> %[[LD0]], <2 x i32> %[[LD1]])
+kernel void KernelTwoMember(struct StructTwoMember u) {
+ FuncTwoMember(u);
+}
+
+// AMD-LABEL: define amdgpu_kernel void @KernelLargeTwoMember
+// AMD-SAME: (%struct.LargeStructTwoMember %[[u_coerce:.*]])
+// AMD: %[[u:.*]] = alloca %struct.LargeStructTwoMember, align 8, addrspace(5)
+// AMD: store %struct.LargeStructTwoMember %[[u_coerce]], %struct.LargeStructTwoMember addrspace(5)* %[[u]]
+// AMD: call void @FuncLargeTwoMember(%struct.LargeStructTwoMember addrspace(5)* byval align 8 %[[u]])
+kernel void KernelLargeTwoMember(struct LargeStructTwoMember u) {
+ FuncLargeTwoMember(u);
+}
diff --git a/test/CodeGenOpenCL/address-space-constant-initializers.cl b/test/CodeGenOpenCL/address-space-constant-initializers.cl
index 45c64c2f71..a03d939fae 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-mangling.cl b/test/CodeGenOpenCL/address-spaces-mangling.cl
index 3c74c718c2..b6e6b87d9e 100644
--- a/test/CodeGenOpenCL/address-spaces-mangling.cl
+++ b/test/CodeGenOpenCL/address-spaces-mangling.cl
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=yes -triple %itanium_abi_triple -emit-llvm -o - | FileCheck -check-prefix=ASMANG %s
-// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=no -triple %itanium_abi_triple -emit-llvm -o - | FileCheck -check-prefix=NOASMANG %s
+// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=yes -triple %itanium_abi_triple -emit-llvm -o - | FileCheck -check-prefixes=ASMANG,ASMAN10 %s
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -ffake-address-space-map -faddress-space-map-mangling=yes -triple %itanium_abi_triple -emit-llvm -o - | FileCheck -check-prefixes=ASMANG,ASMAN20 %s
+// RUN: %clang_cc1 %s -ffake-address-space-map -faddress-space-map-mangling=no -triple %itanium_abi_triple -emit-llvm -o - | FileCheck -check-prefixes=NOASMANG,NOASMAN10 %s
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -ffake-address-space-map -faddress-space-map-mangling=no -triple %itanium_abi_triple -emit-llvm -o - | FileCheck -check-prefixes=NOASMANG,NOASMAN20 %s
// We check that the address spaces are mangled the same in both version of OpenCL
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=CL2.0 -emit-llvm -o - | FileCheck -check-prefix=OCL-20 %s
@@ -10,15 +12,17 @@
// warnings, but we do want it for comparison purposes.
__attribute__((overloadable))
void ff(int *arg) { }
-// ASMANG: @_Z2ffPi
-// NOASMANG: @_Z2ffPi
+// ASMANG10: @_Z2ffPi
+// ASMANG20: @_Z2ffPU3AS4i
+// NOASMANG10: @_Z2ffPi
+// NOASMANG20: @_Z2ffPU9CLgenerici
// OCL-20-DAG: @_Z2ffPU3AS4i
// OCL-12-DAG: @_Z2ffPi
__attribute__((overloadable))
void f(private int *arg) { }
// ASMANG: @_Z1fPi
-// NOASMANG: @_Z1fPi
+// NOASMANG: @_Z1fPU9CLprivatei
// OCL-20-DAG: @_Z1fPi
// OCL-12-DAG: @_Z1fPi
@@ -42,3 +46,11 @@ void f(constant int *arg) { }
// NOASMANG: @_Z1fPU10CLconstanti
// OCL-20-DAG: @_Z1fPU3AS2i
// OCL-12-DAG: @_Z1fPU3AS2i
+
+#if __OPENCL_C_VERSION__ >= 200
+__attribute__((overloadable))
+void f(generic int *arg) { }
+// ASMANG20: @_Z1fPU3AS4i
+// NOASMANG20: @_Z1fPU9CLgenerici
+// OCL-20-DAG: @_Z1fPU3AS4i
+#endif
diff --git a/test/CodeGenOpenCL/address-spaces.cl b/test/CodeGenOpenCL/address-spaces.cl
index 3b34986d89..cb641f5937 100644
--- a/test/CodeGenOpenCL/address-spaces.cl
+++ b/test/CodeGenOpenCL/address-spaces.cl
@@ -1,7 +1,32 @@
-// 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
+// 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
+// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -emit-llvm -o - | FileCheck --check-prefixes=CHECK,SPIR %s
+// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -o - | FileCheck --check-prefixes=CHECK,SPIR %s
-// CHECK: i32* %arg
+// SPIR: %struct.S = type { i32, i32, i32* }
+// CL20SPIR: %struct.S = type { i32, i32, i32 addrspace(4)* }
+struct S {
+ int x;
+ int y;
+ int *z;
+};
+
+// CL20-DAG: @g_extern_var = external addrspace(1) global float
+// CL20-DAG: @l_extern_var = external addrspace(1) global float
+// CL20-DAG: @test_static.l_static_var = internal addrspace(1) global float 0.000000e+00
+// CL20-DAG: @g_static_var = internal addrspace(1) global float 0.000000e+00
+
+#ifdef CL20
+// CL20-DAG: @g_s = common addrspace(1) global %struct.S zeroinitializer
+struct S g_s;
+#endif
+
+// SPIR: i32* %arg
+// GIZ: i32 addrspace(5)* %arg
void f__p(__private int *arg) {}
// CHECK: i32 addrspace(1)* %arg
@@ -13,7 +38,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,19 +55,74 @@ 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;
// CL20-DAG: @f.ii = internal addrspace(1) global i32 0
#endif
}
+
+typedef int int_td;
+typedef int *intp_td;
+// SPIR: define void @test_typedef(i32 addrspace(1)* %x, i32 addrspace(2)* %y, i32* %z)
+void test_typedef(global int_td *x, constant int_td *y, intp_td z) {
+ *x = *y;
+ *z = 0;
+}
+
+// SPIR: define void @test_struct()
+void test_struct() {
+ // SPIR: %ps = alloca %struct.S*
+ // CL20SPIR: %ps = alloca %struct.S addrspace(4)*
+ struct S *ps;
+ // SPIR: store i32 0, i32* %x
+ // CL20SPIR: store i32 0, i32 addrspace(4)* %x
+ ps->x = 0;
+#ifdef CL20
+ // CL20SPIR: store i32 0, i32 addrspace(1)* getelementptr inbounds (%struct.S, %struct.S addrspace(1)* @g_s, i32 0, i32 0)
+ g_s.x = 0;
+#endif
+}
+
+// SPIR-LABEL: define void @test_void_par()
+void test_void_par(void) {}
+
+// On ppc64 returns signext i32.
+// SPIR-LABEL: define{{.*}} i32 @test_func_return_type()
+int test_func_return_type(void) {
+ return 0;
+}
+
+#ifdef CL20
+extern float g_extern_var;
+
+// CL20-LABEL: define {{.*}}void @test_extern(
+kernel void test_extern(global float *buf) {
+ extern float l_extern_var;
+ buf[0] += g_extern_var + l_extern_var;
+}
+
+static float g_static_var;
+
+// CL20-LABEL: define {{.*}}void @test_static(
+kernel void test_static(global float *buf) {
+ static float l_static_var;
+ buf[0] += g_static_var + l_static_var;
+}
+
+#endif
diff --git a/test/CodeGenOpenCL/amdgcn-automatic-variable.cl b/test/CodeGenOpenCL/amdgcn-automatic-variable.cl
new file mode 100644
index 0000000000..fefe1c4a41
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgcn-automatic-variable.cl
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -O0 -cl-std=CL1.2 -triple amdgcn---amdgizcl -emit-llvm %s -o - | FileCheck -check-prefixes=CHECK,CL12 %s
+// RUN: %clang_cc1 -O0 -cl-std=CL2.0 -triple amdgcn---amdgizcl -emit-llvm %s -o - | FileCheck -check-prefixes=CHECK,CL20 %s
+
+// CL12-LABEL: define void @func1(i32 addrspace(5)* %x)
+// CL20-LABEL: define void @func1(i32* %x)
+void func1(int *x) {
+ // CL12: %[[x_addr:.*]] = alloca i32 addrspace(5)*{{.*}}addrspace(5)
+ // CL12: store i32 addrspace(5)* %x, i32 addrspace(5)* addrspace(5)* %[[x_addr]]
+ // CL12: %[[r0:.*]] = load i32 addrspace(5)*, i32 addrspace(5)* addrspace(5)* %[[x_addr]]
+ // CL12: store i32 1, i32 addrspace(5)* %[[r0]]
+ // CL20: %[[x_addr:.*]] = alloca i32*{{.*}}addrspace(5)
+ // CL20: store i32* %x, i32* addrspace(5)* %[[x_addr]]
+ // CL20: %[[r0:.*]] = load i32*, i32* addrspace(5)* %[[x_addr]]
+ // CL20: store i32 1, i32* %[[r0]]
+ *x = 1;
+}
+
+// CHECK-LABEL: define void @func2()
+void func2(void) {
+ // CHECK: %lv1 = alloca i32, align 4, addrspace(5)
+ // CHECK: %lv2 = alloca i32, align 4, addrspace(5)
+ // CHECK: %la = alloca [100 x i32], align 4, addrspace(5)
+ // CL12: %lp1 = alloca i32 addrspace(5)*, align 4, addrspace(5)
+ // CL12: %lp2 = alloca i32 addrspace(5)*, align 4, addrspace(5)
+ // CL20: %lp1 = alloca i32*, align 8, addrspace(5)
+ // CL20: %lp2 = alloca i32*, align 8, addrspace(5)
+ // CHECK: %lvc = alloca i32, align 4, addrspace(5)
+
+ // CHECK: store i32 1, i32 addrspace(5)* %lv1
+ int lv1;
+ lv1 = 1;
+ // CHECK: store i32 2, i32 addrspace(5)* %lv2
+ int lv2 = 2;
+
+ // CHECK: %[[arrayidx:.*]] = getelementptr inbounds [100 x i32], [100 x i32] addrspace(5)* %la, i64 0, i64 0
+ // CHECK: store i32 3, i32 addrspace(5)* %[[arrayidx]], align 4
+ int la[100];
+ la[0] = 3;
+
+ // CL12: store i32 addrspace(5)* %lv1, i32 addrspace(5)* addrspace(5)* %lp1, align 4
+ // CL20: %[[r0:.*]] = addrspacecast i32 addrspace(5)* %lv1 to i32*
+ // CL20: store i32* %[[r0]], i32* addrspace(5)* %lp1, align 8
+ int *lp1 = &lv1;
+
+ // CHECK: %[[arraydecay:.*]] = getelementptr inbounds [100 x i32], [100 x i32] addrspace(5)* %la, i32 0, i32 0
+ // CL12: store i32 addrspace(5)* %[[arraydecay]], i32 addrspace(5)* addrspace(5)* %lp2, align 4
+ // CL20: %[[r1:.*]] = addrspacecast i32 addrspace(5)* %[[arraydecay]] to i32*
+ // CL20: store i32* %[[r1]], i32* addrspace(5)* %lp2, align 8
+ int *lp2 = la;
+
+ // CL12: call void @func1(i32 addrspace(5)* %lv1)
+ // CL20: %[[r2:.*]] = addrspacecast i32 addrspace(5)* %lv1 to i32*
+ // CL20: call void @func1(i32* %[[r2]])
+ func1(&lv1);
+
+ // CHECK: store i32 4, i32 addrspace(5)* %lvc
+ // CHECK: store i32 4, i32 addrspace(5)* %lv1
+ const int lvc = 4;
+ lv1 = lvc;
+}
+
+// CHECK-LABEL: define void @func3()
+// CHECK: %a = alloca [16 x [1 x float]], align 4, addrspace(5)
+// CHECK: %[[CAST:.+]] = bitcast [16 x [1 x float]] addrspace(5)* %a to i8 addrspace(5)*
+// CHECK: call void @llvm.memset.p5i8.i64(i8 addrspace(5)* %[[CAST]], i8 0, i64 64, i32 4, i1 false)
+void func3(void) {
+ float a[16][1] = {{0.}};
+}
diff --git a/test/CodeGenOpenCL/amdgcn-large-globals.cl b/test/CodeGenOpenCL/amdgcn-large-globals.cl
new file mode 100644
index 0000000000..ea9ea618a4
--- /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-abi-struct-coerce.cl b/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl
index 3c69d11f96..a9d74ab6de 100644
--- a/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl
+++ b/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl
@@ -2,12 +2,37 @@
// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple r600-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
-// CHECK-NOT: %struct.single_element_struct_arg = type { i32 }
+typedef __attribute__(( ext_vector_type(2) )) char char2;
+typedef __attribute__(( ext_vector_type(3) )) char char3;
+typedef __attribute__(( ext_vector_type(4) )) char char4;
+
+typedef __attribute__(( ext_vector_type(2) )) short short2;
+typedef __attribute__(( ext_vector_type(3) )) short short3;
+typedef __attribute__(( ext_vector_type(4) )) short short4;
+
+typedef __attribute__(( ext_vector_type(2) )) int int2;
+typedef __attribute__(( ext_vector_type(3) )) int int3;
+typedef __attribute__(( ext_vector_type(4) )) int int4;
+typedef __attribute__(( ext_vector_type(16) )) int int16;
+typedef __attribute__(( ext_vector_type(32) )) int int32;
+
+// CHECK: %struct.empty_struct = type {}
+typedef struct empty_struct
+{
+} empty_struct;
+
+// CHECK-NOT: %struct.single_element_struct_arg
typedef struct single_element_struct_arg
{
int i;
} single_element_struct_arg_t;
+// CHECK-NOT: %struct.nested_single_element_struct_arg
+typedef struct nested_single_element_struct_arg
+{
+ single_element_struct_arg_t i;
+} nested_single_element_struct_arg_t;
+
// CHECK: %struct.struct_arg = type { i32, float, i32 }
typedef struct struct_arg
{
@@ -16,6 +41,13 @@ typedef struct struct_arg
int i2;
} struct_arg_t;
+// CHECK: %struct.struct_padding_arg = type { i8, i64 }
+typedef struct struct_padding_arg
+{
+ char i1;
+ long f;
+} struct_padding_arg;
+
// CHECK: %struct.struct_of_arrays_arg = type { [2 x i32], float, [4 x i32], [3 x float], i32 }
typedef struct struct_of_arrays_arg
{
@@ -35,33 +67,457 @@ typedef struct struct_of_structs_arg
int i2;
} struct_of_structs_arg_t;
-// CHECK-LABEL: @test_single_element_struct_arg
-// CHECK: i32 %arg1.coerce
-__kernel void test_single_element_struct_arg(single_element_struct_arg_t arg1)
+// CHECK: %union.transparent_u = type { i32 }
+typedef union
{
+ int b1;
+ float b2;
+} transparent_u __attribute__((__transparent_union__));
+
+// CHECK: %struct.single_array_element_struct_arg = type { [4 x i32] }
+typedef struct single_array_element_struct_arg
+{
+ int i[4];
+} single_array_element_struct_arg_t;
+
+// CHECK: %struct.single_struct_element_struct_arg = type { %struct.inner }
+// CHECK: %struct.inner = type { i32, i64 }
+typedef struct single_struct_element_struct_arg
+{
+ struct inner {
+ int a;
+ long b;
+ } s;
+} single_struct_element_struct_arg_t;
+
+// CHECK: %struct.different_size_type_pair
+typedef struct different_size_type_pair {
+ long l;
+ int i;
+} different_size_type_pair;
+
+// CHECK: %struct.flexible_array = type { i32, [0 x i32] }
+typedef struct flexible_array
+{
+ int i;
+ int flexible[];
+} flexible_array;
+
+// CHECK: %struct.struct_arr16 = type { [16 x i32] }
+typedef struct struct_arr16
+{
+ int arr[16];
+} struct_arr16;
+
+// CHECK: %struct.struct_arr32 = type { [32 x i32] }
+typedef struct struct_arr32
+{
+ int arr[32];
+} struct_arr32;
+
+// CHECK: %struct.struct_arr33 = type { [33 x i32] }
+typedef struct struct_arr33
+{
+ int arr[33];
+} struct_arr33;
+
+// CHECK: %struct.struct_char_arr32 = type { [32 x i8] }
+typedef struct struct_char_arr32
+{
+ char arr[32];
+} struct_char_arr32;
+
+// CHECK-NOT: %struct.struct_char_x8
+typedef struct struct_char_x8 {
+ char x, y, z, w;
+ char a, b, c, d;
+} struct_char_x8;
+
+// CHECK-NOT: %struct.struct_char_x4
+typedef struct struct_char_x4 {
+ char x, y, z, w;
+} struct_char_x4;
+
+// CHECK-NOT: %struct.struct_char_x3
+typedef struct struct_char_x3 {
+ char x, y, z;
+} struct_char_x3;
+
+// CHECK-NOT: %struct.struct_char_x2
+typedef struct struct_char_x2 {
+ char x, y;
+} struct_char_x2;
+
+// CHECK-NOT: %struct.struct_char_x1
+typedef struct struct_char_x1 {
+ char x;
+} struct_char_x1;
+
+// 4 registers from fields, 5 if padding included.
+// CHECK: %struct.nested = type { i8, i64 }
+// CHECK: %struct.num_regs_nested_struct = type { i32, %struct.nested }
+typedef struct num_regs_nested_struct {
+ int x;
+ struct nested {
+ char z;
+ long y;
+ } inner;
+} num_regs_nested_struct;
+
+// CHECK: %struct.double_nested = type { %struct.inner_inner }
+// CHECK: %struct.inner_inner = type { i8, i32, i8 }
+// CHECK: %struct.double_nested_struct = type { i32, %struct.double_nested, i16 }
+typedef struct double_nested_struct {
+ int x;
+ struct double_nested {
+ struct inner_inner {
+ char y;
+ int q;
+ char z;
+ } inner_inner;
+ } inner;
+
+ short w;
+} double_nested_struct;
+
+// This is a large struct, but uses fewer registers than the limit.
+// CHECK: %struct.large_struct_padding = type { i8, i32, i8, i32, i8, i8, i16, i16, [3 x i8], i64, i32, i8, i32, i16, i8 }
+typedef struct large_struct_padding {
+ char e0;
+ int e1;
+ char e2;
+ int e3;
+ char e4;
+ char e5;
+ short e6;
+ short e7;
+ char e8[3];
+ long e9;
+ int e10;
+ char e11;
+ int e12;
+ short e13;
+ char e14;
+} large_struct_padding;
+
+// CHECK: %struct.int3_pair = type { <3 x i32>, <3 x i32> }
+// The number of registers computed should be 6, not 8.
+typedef struct int3_pair {
+ int3 dx;
+ int3 dy;
+} int3_pair;
+
+// CHECK: %struct.struct_4regs = type { i32, i32, i32, i32 }
+typedef struct struct_4regs
+{
+ int x;
+ int y;
+ int z;
+ int w;
+} struct_4regs;
+
+// CHECK: void @kernel_empty_struct_arg(%struct.empty_struct %s.coerce)
+__kernel void kernel_empty_struct_arg(empty_struct s) { }
+
+// CHECK: void @kernel_single_element_struct_arg(i32 %arg1.coerce)
+__kernel void kernel_single_element_struct_arg(single_element_struct_arg_t arg1) { }
+
+// CHECK: void @kernel_nested_single_element_struct_arg(i32 %arg1.coerce)
+__kernel void kernel_nested_single_element_struct_arg(nested_single_element_struct_arg_t arg1) { }
+
+// CHECK: void @kernel_struct_arg(%struct.struct_arg %arg1.coerce)
+__kernel void kernel_struct_arg(struct_arg_t arg1) { }
+
+// CHECK: void @kernel_struct_padding_arg(%struct.struct_padding_arg %arg1.coerce)
+__kernel void kernel_struct_padding_arg(struct_padding_arg arg1) { }
+
+// CHECK: void @kernel_test_struct_of_arrays_arg(%struct.struct_of_arrays_arg %arg1.coerce)
+__kernel void kernel_test_struct_of_arrays_arg(struct_of_arrays_arg_t arg1) { }
+
+// CHECK: void @kernel_struct_of_structs_arg(%struct.struct_of_structs_arg %arg1.coerce)
+__kernel void kernel_struct_of_structs_arg(struct_of_structs_arg_t arg1) { }
+
+// CHECK: void @test_kernel_transparent_union_arg(%union.transparent_u %u.coerce)
+__kernel void test_kernel_transparent_union_arg(transparent_u u) { }
+
+// CHECK: void @kernel_single_array_element_struct_arg(%struct.single_array_element_struct_arg %arg1.coerce)
+__kernel void kernel_single_array_element_struct_arg(single_array_element_struct_arg_t arg1) { }
+
+// CHECK: void @kernel_single_struct_element_struct_arg(%struct.single_struct_element_struct_arg %arg1.coerce)
+__kernel void kernel_single_struct_element_struct_arg(single_struct_element_struct_arg_t arg1) { }
+
+// CHECK: void @kernel_different_size_type_pair_arg(%struct.different_size_type_pair %arg1.coerce)
+__kernel void kernel_different_size_type_pair_arg(different_size_type_pair arg1) { }
+
+// CHECK: define void @func_f32_arg(float %arg)
+void func_f32_arg(float arg) { }
+
+// CHECK: define void @func_v2i16_arg(<2 x i16> %arg)
+void func_v2i16_arg(short2 arg) { }
+
+// CHECK: define void @func_v3i32_arg(<3 x i32> %arg)
+void func_v3i32_arg(int3 arg) { }
+
+// CHECK: define void @func_v4i32_arg(<4 x i32> %arg)
+void func_v4i32_arg(int4 arg) { }
+
+// CHECK: define void @func_v16i32_arg(<16 x i32> %arg)
+void func_v16i32_arg(int16 arg) { }
+
+// CHECK: define void @func_v32i32_arg(<32 x i32> %arg)
+void func_v32i32_arg(int32 arg) { }
+
+// CHECK: define void @func_empty_struct_arg()
+void func_empty_struct_arg(empty_struct empty) { }
+
+// CHECK: void @func_single_element_struct_arg(i32 %arg1.coerce)
+void func_single_element_struct_arg(single_element_struct_arg_t arg1) { }
+
+// CHECK: void @func_nested_single_element_struct_arg(i32 %arg1.coerce)
+void func_nested_single_element_struct_arg(nested_single_element_struct_arg_t arg1) { }
+
+// CHECK: void @func_struct_arg(i32 %arg1.coerce0, float %arg1.coerce1, i32 %arg1.coerce2)
+void func_struct_arg(struct_arg_t arg1) { }
+
+// CHECK: void @func_struct_padding_arg(i8 %arg1.coerce0, i64 %arg1.coerce1)
+void func_struct_padding_arg(struct_padding_arg arg1) { }
+
+// CHECK: define void @func_struct_char_x8([2 x i32] %arg.coerce)
+void func_struct_char_x8(struct_char_x8 arg) { }
+
+// CHECK: define void @func_struct_char_x4(i32 %arg.coerce)
+void func_struct_char_x4(struct_char_x4 arg) { }
+
+// CHECK: define void @func_struct_char_x3(i32 %arg.coerce)
+void func_struct_char_x3(struct_char_x3 arg) { }
+
+// CHECK: define void @func_struct_char_x2(i16 %arg.coerce)
+void func_struct_char_x2(struct_char_x2 arg) { }
+
+// CHECK: define void @func_struct_char_x1(i8 %arg.coerce)
+void func_struct_char_x1(struct_char_x1 arg) { }
+
+// CHECK: void @func_transparent_union_arg(i32 %u.coerce)
+void func_transparent_union_arg(transparent_u u) { }
+
+// CHECK: void @func_single_array_element_struct_arg([4 x i32] %arg1.coerce)
+void func_single_array_element_struct_arg(single_array_element_struct_arg_t arg1) { }
+
+// CHECK: void @func_single_struct_element_struct_arg(%struct.inner %arg1.coerce)
+void func_single_struct_element_struct_arg(single_struct_element_struct_arg_t arg1) { }
+
+// CHECK: void @func_different_size_type_pair_arg(i64 %arg1.coerce0, i32 %arg1.coerce1)
+void func_different_size_type_pair_arg(different_size_type_pair arg1) { }
+
+// CHECK: void @func_flexible_array_arg(%struct.flexible_array* byval nocapture align 4 %arg)
+void func_flexible_array_arg(flexible_array arg) { }
+
+// CHECK: define float @func_f32_ret()
+float func_f32_ret()
+{
+ return 0.0f;
+}
+
+// CHECK: define void @func_empty_struct_ret()
+empty_struct func_empty_struct_ret()
+{
+ empty_struct s = {};
+ return s;
+}
+
+// CHECK: define i32 @single_element_struct_ret()
+// CHECK: ret i32 0
+single_element_struct_arg_t single_element_struct_ret()
+{
+ single_element_struct_arg_t s = { 0 };
+ return s;
+}
+
+// CHECK: define i32 @nested_single_element_struct_ret()
+// CHECK: ret i32 0
+nested_single_element_struct_arg_t nested_single_element_struct_ret()
+{
+ nested_single_element_struct_arg_t s = { 0 };
+ return s;
+}
+
+// CHECK: define %struct.struct_arg @func_struct_ret()
+// CHECK: ret %struct.struct_arg zeroinitializer
+struct_arg_t func_struct_ret()
+{
+ struct_arg_t s = { 0 };
+ return s;
+}
+
+// CHECK: define %struct.struct_padding_arg @func_struct_padding_ret()
+// CHECK: ret %struct.struct_padding_arg zeroinitializer
+struct_padding_arg func_struct_padding_ret()
+{
+ struct_padding_arg s = { 0 };
+ return s;
+}
+
+// CHECK: define [2 x i32] @func_struct_char_x8_ret()
+// CHECK: ret [2 x i32] zeroinitializer
+struct_char_x8 func_struct_char_x8_ret()
+{
+ struct_char_x8 s = { 0 };
+ return s;
+}
+
+// CHECK: define i32 @func_struct_char_x4_ret()
+// CHECK: ret i32 0
+struct_char_x4 func_struct_char_x4_ret()
+{
+ struct_char_x4 s = { 0 };
+ return s;
+}
+
+// CHECK: define i32 @func_struct_char_x3_ret()
+// CHECK: ret i32 0
+struct_char_x3 func_struct_char_x3_ret()
+{
+ struct_char_x3 s = { 0 };
+ return s;
+}
+
+// CHECK: define i16 @func_struct_char_x2_ret()
+struct_char_x2 func_struct_char_x2_ret()
+{
+ struct_char_x2 s = { 0 };
+ return s;
}
-// CHECK-LABEL: @test_struct_arg
-// CHECK: %struct.struct_arg %arg1.coerce
-__kernel void test_struct_arg(struct_arg_t arg1)
+// CHECK: define i8 @func_struct_char_x1_ret()
+// CHECK: ret i8 0
+struct_char_x1 func_struct_char_x1_ret()
{
+ struct_char_x1 s = { 0 };
+ return s;
}
-// CHECK-LABEL: @test_struct_of_arrays_arg
-// CHECK: %struct.struct_of_arrays_arg %arg1.coerce
-__kernel void test_struct_of_arrays_arg(struct_of_arrays_arg_t arg1)
+// CHECK: define %struct.struct_arr16 @func_ret_struct_arr16()
+// CHECK: ret %struct.struct_arr16 zeroinitializer
+struct_arr16 func_ret_struct_arr16()
{
+ struct_arr16 s = { 0 };
+ return s;
}
-// CHECK-LABEL: @test_struct_of_structs_arg
-// CHECK: %struct.struct_of_structs_arg %arg1.coerce
-__kernel void test_struct_of_structs_arg(struct_of_structs_arg_t arg1)
+// CHECK: define void @func_ret_struct_arr32(%struct.struct_arr32* noalias nocapture sret %agg.result)
+struct_arr32 func_ret_struct_arr32()
{
+ struct_arr32 s = { 0 };
+ return s;
}
-// CHECK-LABEL: @test_non_kernel_struct_arg
-// CHECK-NOT: %struct.struct_arg %arg1.coerce
-// CHECK: %struct.struct_arg* byval
-void test_non_kernel_struct_arg(struct_arg_t arg1)
+// CHECK: define void @func_ret_struct_arr33(%struct.struct_arr33* noalias nocapture sret %agg.result)
+struct_arr33 func_ret_struct_arr33()
{
+ struct_arr33 s = { 0 };
+ return s;
}
+
+// CHECK: define %struct.struct_char_arr32 @func_ret_struct_char_arr32()
+struct_char_arr32 func_ret_struct_char_arr32()
+{
+ struct_char_arr32 s = { 0 };
+ return s;
+}
+
+// CHECK: define i32 @func_transparent_union_ret() local_unnamed_addr #0 {
+// CHECK: ret i32 0
+transparent_u func_transparent_union_ret()
+{
+ transparent_u u = { 0 };
+ return u;
+}
+
+// CHECK: define %struct.different_size_type_pair @func_different_size_type_pair_ret()
+different_size_type_pair func_different_size_type_pair_ret()
+{
+ different_size_type_pair s = { 0 };
+ return s;
+}
+
+// CHECK: define void @func_flexible_array_ret(%struct.flexible_array* noalias nocapture sret %agg.result)
+flexible_array func_flexible_array_ret()
+{
+ flexible_array s = { 0 };
+ return s;
+}
+
+// CHECK: define void @func_reg_state_lo(<4 x i32> %arg0, <4 x i32> %arg1, <4 x i32> %arg2, i32 %arg3, i32 %s.coerce0, float %s.coerce1, i32 %s.coerce2)
+void func_reg_state_lo(int4 arg0, int4 arg1, int4 arg2, int arg3, struct_arg_t s) { }
+
+// CHECK: define void @func_reg_state_hi(<4 x i32> %arg0, <4 x i32> %arg1, <4 x i32> %arg2, i32 %arg3, i32 %arg4, %struct.struct_arg* byval nocapture align 4 %s)
+void func_reg_state_hi(int4 arg0, int4 arg1, int4 arg2, int arg3, int arg4, struct_arg_t s) { }
+
+// XXX - Why don't the inner structs flatten?
+// CHECK: define void @func_reg_state_num_regs_nested_struct(<4 x i32> %arg0, i32 %arg1, i32 %arg2.coerce0, %struct.nested %arg2.coerce1, i32 %arg3.coerce0, %struct.nested %arg3.coerce1, %struct.num_regs_nested_struct* byval nocapture align 8 %arg4)
+void func_reg_state_num_regs_nested_struct(int4 arg0, int arg1, num_regs_nested_struct arg2, num_regs_nested_struct arg3, num_regs_nested_struct arg4) { }
+
+// CHECK: define void @func_double_nested_struct_arg(<4 x i32> %arg0, i32 %arg1, i32 %arg2.coerce0, %struct.double_nested %arg2.coerce1, i16 %arg2.coerce2)
+void func_double_nested_struct_arg(int4 arg0, int arg1, double_nested_struct arg2) { }
+
+// CHECK: define %struct.double_nested_struct @func_double_nested_struct_ret(<4 x i32> %arg0, i32 %arg1)
+double_nested_struct func_double_nested_struct_ret(int4 arg0, int arg1) {
+ double_nested_struct s = { 0 };
+ return s;
+}
+
+// CHECK: define void @func_large_struct_padding_arg_direct(i8 %arg.coerce0, i32 %arg.coerce1, i8 %arg.coerce2, i32 %arg.coerce3, i8 %arg.coerce4, i8 %arg.coerce5, i16 %arg.coerce6, i16 %arg.coerce7, [3 x i8] %arg.coerce8, i64 %arg.coerce9, i32 %arg.coerce10, i8 %arg.coerce11, i32 %arg.coerce12, i16 %arg.coerce13, i8 %arg.coerce14)
+void func_large_struct_padding_arg_direct(large_struct_padding arg) { }
+
+// CHECK: define void @func_large_struct_padding_arg_store(%struct.large_struct_padding addrspace(1)* nocapture %out, %struct.large_struct_padding* byval nocapture readonly align 8 %arg)
+void func_large_struct_padding_arg_store(global large_struct_padding* out, large_struct_padding arg) {
+ *out = arg;
+}
+
+// CHECK: define void @v3i32_reg_count(<3 x i32> %arg1, <3 x i32> %arg2, <3 x i32> %arg3, <3 x i32> %arg4, i32 %arg5.coerce0, float %arg5.coerce1, i32 %arg5.coerce2)
+void v3i32_reg_count(int3 arg1, int3 arg2, int3 arg3, int3 arg4, struct_arg_t arg5) { }
+
+// Function signature from blender, nothing should be passed byval. The v3i32
+// should not count as 4 passed registers.
+// CHECK: define void @v3i32_pair_reg_count(%struct.int3_pair* nocapture %arg0, <3 x i32> %arg1.coerce0, <3 x i32> %arg1.coerce1, <3 x i32> %arg2, <3 x i32> %arg3.coerce0, <3 x i32> %arg3.coerce1, <3 x i32> %arg4, float %arg5)
+void v3i32_pair_reg_count(int3_pair *arg0, int3_pair arg1, int3 arg2, int3_pair arg3, int3 arg4, float arg5) { }
+
+// Each short4 should fit pack into 2 registers.
+// CHECK: define void @v4i16_reg_count(<4 x i16> %arg0, <4 x i16> %arg1, <4 x i16> %arg2, <4 x i16> %arg3, <4 x i16> %arg4, <4 x i16> %arg5, i32 %arg6.coerce0, i32 %arg6.coerce1, i32 %arg6.coerce2, i32 %arg6.coerce3)
+void v4i16_reg_count(short4 arg0, short4 arg1, short4 arg2, short4 arg3,
+ short4 arg4, short4 arg5, struct_4regs arg6) { }
+
+// CHECK: define void @v4i16_pair_reg_count_over(<4 x i16> %arg0, <4 x i16> %arg1, <4 x i16> %arg2, <4 x i16> %arg3, <4 x i16> %arg4, <4 x i16> %arg5, <4 x i16> %arg6, %struct.struct_4regs* byval nocapture align 4 %arg7)
+void v4i16_pair_reg_count_over(short4 arg0, short4 arg1, short4 arg2, short4 arg3,
+ short4 arg4, short4 arg5, short4 arg6, struct_4regs arg7) { }
+
+// CHECK: define void @v3i16_reg_count(<3 x i16> %arg0, <3 x i16> %arg1, <3 x i16> %arg2, <3 x i16> %arg3, <3 x i16> %arg4, <3 x i16> %arg5, i32 %arg6.coerce0, i32 %arg6.coerce1, i32 %arg6.coerce2, i32 %arg6.coerce3)
+void v3i16_reg_count(short3 arg0, short3 arg1, short3 arg2, short3 arg3,
+ short3 arg4, short3 arg5, struct_4regs arg6) { }
+
+// CHECK: define void @v3i16_reg_count_over(<3 x i16> %arg0, <3 x i16> %arg1, <3 x i16> %arg2, <3 x i16> %arg3, <3 x i16> %arg4, <3 x i16> %arg5, <3 x i16> %arg6, %struct.struct_4regs* byval nocapture align 4 %arg7)
+void v3i16_reg_count_over(short3 arg0, short3 arg1, short3 arg2, short3 arg3,
+ short3 arg4, short3 arg5, short3 arg6, struct_4regs arg7) { }
+
+// CHECK: define void @v2i16_reg_count(<2 x i16> %arg0, <2 x i16> %arg1, <2 x i16> %arg2, <2 x i16> %arg3, <2 x i16> %arg4, <2 x i16> %arg5, <2 x i16> %arg6, <2 x i16> %arg7, <2 x i16> %arg8, <2 x i16> %arg9, <2 x i16> %arg10, <2 x i16> %arg11, i32 %arg13.coerce0, i32 %arg13.coerce1, i32 %arg13.coerce2, i32 %arg13.coerce3)
+void v2i16_reg_count(short2 arg0, short2 arg1, short2 arg2, short2 arg3,
+ short2 arg4, short2 arg5, short2 arg6, short2 arg7,
+ short2 arg8, short2 arg9, short2 arg10, short2 arg11,
+ struct_4regs arg13) { }
+
+// CHECK: define void @v2i16_reg_count_over(<2 x i16> %arg0, <2 x i16> %arg1, <2 x i16> %arg2, <2 x i16> %arg3, <2 x i16> %arg4, <2 x i16> %arg5, <2 x i16> %arg6, <2 x i16> %arg7, <2 x i16> %arg8, <2 x i16> %arg9, <2 x i16> %arg10, <2 x i16> %arg11, <2 x i16> %arg12, %struct.struct_4regs* byval nocapture align 4 %arg13)
+void v2i16_reg_count_over(short2 arg0, short2 arg1, short2 arg2, short2 arg3,
+ short2 arg4, short2 arg5, short2 arg6, short2 arg7,
+ short2 arg8, short2 arg9, short2 arg10, short2 arg11,
+ short2 arg12, struct_4regs arg13) { }
+
+// CHECK: define void @v2i8_reg_count(<2 x i8> %arg0, <2 x i8> %arg1, <2 x i8> %arg2, <2 x i8> %arg3, <2 x i8> %arg4, <2 x i8> %arg5, i32 %arg6.coerce0, i32 %arg6.coerce1, i32 %arg6.coerce2, i32 %arg6.coerce3)
+void v2i8_reg_count(char2 arg0, char2 arg1, char2 arg2, char2 arg3,
+ char2 arg4, char2 arg5, struct_4regs arg6) { }
+
+// CHECK: define void @v2i8_reg_count_over(<2 x i8> %arg0, <2 x i8> %arg1, <2 x i8> %arg2, <2 x i8> %arg3, <2 x i8> %arg4, <2 x i8> %arg5, i32 %arg6, %struct.struct_4regs* byval nocapture align 4 %arg7)
+void v2i8_reg_count_over(char2 arg0, char2 arg1, char2 arg2, char2 arg3,
+ char2 arg4, char2 arg5, int arg6, struct_4regs arg7) { }
+
+// CHECK: define void @num_regs_left_64bit_aggregate(<4 x i32> %arg0, <4 x i32> %arg1, <4 x i32> %arg2, <3 x i32> %arg3, [2 x i32] %arg4.coerce, i32 %arg5)
+void num_regs_left_64bit_aggregate(int4 arg0, int4 arg1, int4 arg2, int3 arg3, struct_char_x8 arg4, int arg5) { }
diff --git a/test/CodeGenOpenCL/amdgpu-alignment.cl b/test/CodeGenOpenCL/amdgpu-alignment.cl
index 35a8342eec..70a22c9f75 100644
--- a/test/CodeGenOpenCL/amdgpu-alignment.cl
+++ b/test/CodeGenOpenCL/amdgpu-alignment.cl
@@ -1,5 +1,6 @@
// REQUIRES: amdgpu-registered-target
// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -S -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown-opencl -S -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
diff --git a/test/CodeGenOpenCL/amdgpu-attrs.cl b/test/CodeGenOpenCL/amdgpu-attrs.cl
index 4ca85d3161..2696123f14 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"
@@ -141,26 +151,28 @@ kernel void flat_work_group_size_32_64_waves_per_eu_2_4_num_sgpr_32_num_vgpr_64(
// CHECK-NOT: "amdgpu-num-sgpr"="0"
// 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 [[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"
-// CHECK-DAG: attributes [[NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-vgpr"="64"
-
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2"
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2,4"
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_SGPR_32]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32"
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64"
-// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_SGPR_32]] = { noinline nounwind "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
-// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
-// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_SGPR_32]] = { noinline nounwind "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
-// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
-// CHECK-DAG: attributes [[NUM_SGPR_32_NUM_VGPR_64]] = { noinline nounwind "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64"
-
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
-
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
-// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32_NUM_VGPR_64]] = { noinline nounwind "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_64_64]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="64,64"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_16_128]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="16,128"
+// CHECK-DAG: attributes [[WAVES_PER_EU_2]] = { convergent noinline nounwind optnone "amdgpu-waves-per-eu"="2"
+// CHECK-DAG: attributes [[WAVES_PER_EU_2_4]] = { convergent noinline nounwind optnone "amdgpu-waves-per-eu"="2,4"
+// CHECK-DAG: attributes [[NUM_SGPR_32]] = { convergent noinline nounwind optnone "amdgpu-num-sgpr"="32"
+// CHECK-DAG: attributes [[NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-num-vgpr"="64"
+
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-waves-per-eu"="2,4"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_SGPR_32]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64"
+// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_SGPR_32]] = { convergent noinline nounwind optnone "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
+// CHECK-DAG: attributes [[WAVES_PER_EU_2_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
+// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_SGPR_32]] = { convergent noinline nounwind optnone "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
+// CHECK-DAG: attributes [[WAVES_PER_EU_2_4_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
+// CHECK-DAG: attributes [[NUM_SGPR_32_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64"
+
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-waves-per-eu"="2,4"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
+
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_NUM_SGPR_32_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2"
+// CHECK-DAG: attributes [[FLAT_WORK_GROUP_SIZE_32_64_WAVES_PER_EU_2_4_NUM_SGPR_32_NUM_VGPR_64]] = { convergent noinline nounwind optnone "amdgpu-flat-work-group-size"="32,64" "amdgpu-num-sgpr"="32" "amdgpu-num-vgpr"="64" "amdgpu-waves-per-eu"="2,4"
diff --git a/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl b/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
index c0b30095a6..952b25dec7 100644
--- a/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
+++ b/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
@@ -1,4 +1,5 @@
// RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -target amdgcn-amd-amdhsa -mcpu=fiji -o - %s | FileCheck %s
+// RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -target amdgcn-amd-amdhsa-opencl -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)
@@ -58,16 +59,16 @@ kernel void kernel1(
// 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: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+ global int *constant FuncVar5 = 0;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+ constant int *constant FuncVar6 = 0;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: true, isDefinition: true)
+ local int *constant FuncVar7 = 0;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: true, isDefinition: true)
+ private int *constant FuncVar8 = 0;
+ // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+ int *constant FuncVar9 = 0;
// 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;
diff --git a/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
index b02ad46224..4d46b40561 100644
--- a/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
+++ b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
@@ -1,131 +1,128 @@
// 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)
+// RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -target amdgcn-amd-amdhsa-opencl -mcpu=fiji -o - %s | FileCheck %s
// 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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR0]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR1]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR2]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR3]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR4]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR5]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR6]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR7]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR8]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR9]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR10]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR11]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR12]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR13]], expr: !DIExpression())
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]])
+// CHECK-DAG: !DIGlobalVariableExpression(var: ![[FILEVAR14]], expr: !DIExpression())
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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[KERNELARG0]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[KERNELARG1]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[KERNELARG2]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR0]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[FUNCVAR1]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[FUNCVAR2]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32** {{.*}}, metadata ![[FUNCVAR3]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(4)** {{.*}}, metadata ![[FUNCVAR4]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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: ![[FUNCVAR5:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR5]], expr: !DIExpression())
+ global int *constant FuncVar5 = 0;
+ // CHECK-DAG: ![[FUNCVAR6:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR6]], expr: !DIExpression())
+ constant int *constant FuncVar6 = 0;
+ // CHECK-DAG: ![[FUNCVAR7:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR7]], expr: !DIExpression())
+ local int *constant FuncVar7 = 0;
+ // CHECK-DAG: ![[FUNCVAR8:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR8]], expr: !DIExpression())
+ private int *constant FuncVar8 = 0;
+ // CHECK-DAG: ![[FUNCVAR9:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR9]], expr: !DIExpression())
+ int *constant FuncVar9 = 0;
// 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]])
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR10]], expr: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
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]])
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR11]], expr: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
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]])
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR12]], expr: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
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]])
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR13]], expr: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
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]])
+ // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR14]], expr: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR15]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[FUNCVAR16]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[FUNCVAR17]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32** {{.*}}, metadata ![[FUNCVAR18]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !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]+}}
+ // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(4)** {{.*}}, metadata ![[FUNCVAR19]], metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !{{[0-9]+}}
int *private FuncVar19 = Tmp1;
}
diff --git a/test/CodeGenOpenCL/amdgpu-enqueue-kernel.cl b/test/CodeGenOpenCL/amdgpu-enqueue-kernel.cl
new file mode 100644
index 0000000000..b2db4d7827
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgpu-enqueue-kernel.cl
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -O0 -emit-llvm -o - -triple amdgcn | FileCheck %s --check-prefix=CHECK
+
+typedef struct {int a;} ndrange_t;
+
+// CHECK-LABEL: define amdgpu_kernel void @test
+kernel void test(global char *a, char b, global long *c, long d) {
+ queue_t default_queue;
+ unsigned flags = 0;
+ ndrange_t ndrange;
+
+ enqueue_kernel(default_queue, flags, ndrange,
+ ^(void) {
+ a[0] = b;
+ });
+
+ enqueue_kernel(default_queue, flags, ndrange,
+ ^(void) {
+ a[0] = b;
+ c[0] = d;
+ });
+ enqueue_kernel(default_queue, flags, ndrange,
+ ^(local void *lp) {
+ a[0] = b;
+ c[0] = d;
+ ((local int*)lp)[0] = 1;
+ }, 100);
+}
+
+// CHECK-LABEL: define internal amdgpu_kernel void @__test_block_invoke_kernel(<{ i32, i32, i8 addrspace(4)*, i8 addrspace(1)*, i8 }>)
+// CHECK-SAME: #[[ATTR:[0-9]+]] !kernel_arg_addr_space !{{.*}} !kernel_arg_access_qual !{{.*}} !kernel_arg_type !{{.*}} !kernel_arg_base_type !{{.*}} !kernel_arg_type_qual !{{.*}}
+// CHECK: entry:
+// CHECK: %1 = alloca <{ i32, i32, i8 addrspace(4)*, i8 addrspace(1)*, i8 }>, align 8
+// CHECK: store <{ i32, i32, i8 addrspace(4)*, i8 addrspace(1)*, i8 }> %0, <{ i32, i32, i8 addrspace(4)*, i8 addrspace(1)*, i8 }>* %1, align 8
+// CHECK: %2 = addrspacecast <{ i32, i32, i8 addrspace(4)*, i8 addrspace(1)*, i8 }>* %1 to i8 addrspace(4)*
+// CHECK: call void @__test_block_invoke(i8 addrspace(4)* %2)
+// CHECK: ret void
+// CHECK:}
+
+// CHECK-LABEL: define internal amdgpu_kernel void @__test_block_invoke_2_kernel(<{ i32, i32, i8 addrspace(4)*, i8 addrspace(1)*, i64 addrspace(1)*, i64, i8 }>)
+// CHECK-SAME: #[[ATTR]] !kernel_arg_addr_space !{{.*}} !kernel_arg_access_qual !{{.*}} !kernel_arg_type !{{.*}} !kernel_arg_base_type !{{.*}} !kernel_arg_type_qual !{{.*}}
+
+// CHECK-LABEL: define internal amdgpu_kernel void @__test_block_invoke_3_kernel(<{ i32, i32, i8 addrspace(4)*, i8 addrspace(1)*, i64 addrspace(1)*, i64, i8 }>, i8 addrspace(3)*)
+// CHECK-SAME: #[[ATTR]] !kernel_arg_addr_space !{{.*}} !kernel_arg_access_qual !{{.*}} !kernel_arg_type !{{.*}} !kernel_arg_base_type !{{.*}} !kernel_arg_type_qual !{{.*}}
+
+// CHECK: attributes #[[ATTR]] = { nounwind "enqueued-block" }
diff --git a/test/CodeGenOpenCL/amdgpu-env-amdgiz.cl b/test/CodeGenOpenCL/amdgpu-env-amdgiz.cl
new file mode 100644
index 0000000000..4cb8d95fa0
--- /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 37c7469aa1..513d56c19d 100644
--- a/test/CodeGenOpenCL/amdgpu-nullptr.cl
+++ b/test/CodeGenOpenCL/amdgpu-nullptr.cl
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -include opencl-c.h -triple amdgcn -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s -O0 -cl-std=CL2.0 -include opencl-c.h -triple amdgcn -emit-llvm -o - | FileCheck --check-prefix=NOOPT %s
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -include opencl-c.h -triple amdgcn---opencl -emit-llvm -o - | FileCheck %s
typedef struct {
private char *p1;
@@ -26,13 +27,13 @@ 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
local char *local_p = 0;
-// CHECK: @global_p = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4
+// CHECK: @global_p = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 8
global char *global_p = 0;
-// CHECK: @constant_p = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4
+// CHECK: @constant_p = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 8
constant char *constant_p = 0;
-// CHECK: @generic_p = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4
+// CHECK: @generic_p = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 8
generic char *generic_p = 0;
// Test NULL as initializer.
@@ -43,19 +44,19 @@ 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
local char *local_p_NULL = NULL;
-// CHECK: @global_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4
+// CHECK: @global_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 8
global char *global_p_NULL = NULL;
-// CHECK: @constant_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4
+// CHECK: @constant_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 8
constant char *constant_p_NULL = NULL;
-// CHECK: @generic_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4
+// CHECK: @generic_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 8
generic char *generic_p_NULL = NULL;
// Test constant folding of null pointer.
// A null pointer should be folded to a null pointer in the target address space.
-// CHECK: @fold_generic = local_unnamed_addr addrspace(1) global i32 addrspace(4)* null, align 4
+// CHECK: @fold_generic = local_unnamed_addr addrspace(1) global i32 addrspace(4)* null, align 8
generic int *fold_generic = (global int*)(generic float*)(private char*)0;
// CHECK: @fold_priv = local_unnamed_addr addrspace(1) global i16* null, align 4
@@ -103,8 +104,8 @@ int fold_int5_local = (int) &((local StructTy1*)0)->p2;
// 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
+// 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 8
+// NOOPT: @test_static_var_private.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8
void test_static_var_private(void) {
static private char *sp1 = 0;
@@ -122,8 +123,8 @@ void test_static_var_private(void) {
// 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
+// 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 8
+// NOOPT: @test_static_var_local.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8
void test_static_var_local(void) {
static local char *sp1 = 0;
static local char *sp2 = NULL;
@@ -142,9 +143,9 @@ void test_static_var_local(void) {
// 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_private.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 8, 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)
+// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 8, i1 false)
void test_func_scope_var_private(void) {
private char *sp1 = 0;
private char *sp2 = NULL;
@@ -162,9 +163,9 @@ void test_func_scope_var_private(void) {
// 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: 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 8, 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)
+// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 8, i1 false)
void test_func_scope_var_local(void) {
local char *sp1 = 0;
local char *sp2 = NULL;
@@ -188,28 +189,28 @@ 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
local char *p2;
-// CHECK: @p3 = common local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4
+// CHECK: @p3 = common local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 8
constant char *p3;
-// CHECK: @p4 = common local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4
+// CHECK: @p4 = common local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 8
global char *p4;
-// CHECK: @p5 = common local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4
+// CHECK: @p5 = common local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 8
generic char *p5;
// Test default initialization of sturcture.
-// 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
+// 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 8
StructTy1 S1;
-// CHECK: @S2 = common local_unnamed_addr addrspace(1) global %struct.StructTy2 zeroinitializer, align 4
+// CHECK: @S2 = common local_unnamed_addr addrspace(1) global %struct.StructTy2 zeroinitializer, align 8
StructTy2 S2;
// Test default initialization of array.
-// 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
+// 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 8
StructTy1 A1[2];
-// CHECK: @A2 = common local_unnamed_addr addrspace(1) global [2 x %struct.StructTy2] zeroinitializer, align 4
+// CHECK: @A2 = common local_unnamed_addr addrspace(1) global [2 x %struct.StructTy2] zeroinitializer, align 8
StructTy2 A2[2];
// Test comparison with 0.
@@ -510,9 +511,9 @@ typedef struct {
// 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) {
+void test_memset_private(private StructTy3 *ptr) {
StructTy3 S3 = {0, 0, 0, 0, 0};
- return S3;
+ *ptr = S3;
}
// Test casting literal 0 to pointer.
@@ -596,7 +597,7 @@ int test_and_ptr(private char* p1, local char* p2) {
// Test folding of null pointer in function scope.
// NOOPT-LABEL: test_fold_private
// NOOPT: call void @test_fold_callee
-// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4
+// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 8
// NOOPT: %{{.*}} = sub i64 %{{.*}}, 0
// NOOPT: call void @test_fold_callee
// NOOPT: %{{.*}} = add nsw i64 %{{.*}}, 0
@@ -611,7 +612,7 @@ void test_fold_private(void) {
// NOOPT-LABEL: test_fold_local
// NOOPT: call void @test_fold_callee
-// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4
+// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 8
// 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)
diff --git a/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl b/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl
new file mode 100644
index 0000000000..a5d438933f
--- /dev/null
+++ b/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -triple r600 -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn-mesa-mesa3d -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn---opencl -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn---opencl -cl-std=CL2.0 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-std=CL2.0 %s -emit-llvm -o - | FileCheck %s
+
+#ifdef __AMDGCN__
+#define PTSIZE 8
+#else
+#define PTSIZE 4
+#endif
+
+#ifdef cl_khr_fp64
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+#endif
+#ifdef cl_khr_fp16
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+#endif
+
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef global void *global_ptr_t;
+typedef constant void *constant_ptr_t;
+typedef local void *local_ptr_t;
+typedef private void *private_ptr_t;
+
+void check(bool);
+
+void test() {
+ // CHECK-NOT: call void @check(i1 zeroext false)
+ check(sizeof(size_t) == PTSIZE);
+ check(__alignof__(size_t) == PTSIZE);
+ check(sizeof(intptr_t) == PTSIZE);
+ check(__alignof__(intptr_t) == PTSIZE);
+ check(sizeof(uintptr_t) == PTSIZE);
+ check(__alignof__(uintptr_t) == PTSIZE);
+ check(sizeof(ptrdiff_t) == PTSIZE);
+ check(__alignof__(ptrdiff_t) == PTSIZE);
+
+ check(sizeof(char) == 1);
+ check(__alignof__(char) == 1);
+ check(sizeof(short) == 2);
+ check(__alignof__(short) == 2);
+ check(sizeof(int) == 4);
+ check(__alignof__(int) == 4);
+ check(sizeof(long) == 8);
+ check(__alignof__(long) == 8);
+#ifdef cl_khr_fp16
+ check(sizeof(half) == 2);
+ check(__alignof__(half) == 2);
+#endif
+ check(sizeof(float) == 4);
+ check(__alignof__(float) == 4);
+#ifdef cl_khr_fp64
+ check(sizeof(double) == 8);
+ check(__alignof__(double) == 8);
+#endif
+
+ check(sizeof(void*) == (__OPENCL_C_VERSION__ >= 200 ? 8 : 4));
+ check(__alignof__(void*) == (__OPENCL_C_VERSION__ >= 200 ? 8 : 4));
+ check(sizeof(global_ptr_t) == PTSIZE);
+ check(__alignof__(global_ptr_t) == PTSIZE);
+ check(sizeof(constant_ptr_t) == PTSIZE);
+ check(__alignof__(constant_ptr_t) == PTSIZE);
+ check(sizeof(local_ptr_t) == 4);
+ check(__alignof__(private_ptr_t) == 4);
+}
diff --git a/test/CodeGenOpenCL/atomic-ops-libcall.cl b/test/CodeGenOpenCL/atomic-ops-libcall.cl
new file mode 100644
index 0000000000..a6f7e14f29
--- /dev/null
+++ b/test/CodeGenOpenCL/atomic-ops-libcall.cl
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 < %s -cl-std=CL2.0 -triple spir64 -emit-llvm | FileCheck -check-prefix=SPIR %s
+// RUN: %clang_cc1 < %s -cl-std=CL2.0 -triple armv5e-none-linux-gnueabi -emit-llvm | FileCheck -check-prefix=ARM %s
+typedef enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+typedef enum memory_scope {
+ memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM,
+ memory_scope_work_group = __OPENCL_MEMORY_SCOPE_WORK_GROUP,
+ memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE,
+ memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES,
+#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups)
+ memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP
+#endif
+} memory_scope;
+
+void f(atomic_int *i, global atomic_int *gi, local atomic_int *li, private atomic_int *pi, atomic_uint *ui, int cmp, int order, int scope) {
+ int x;
+ // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(i8 addrspace(4)* {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(i8* {{%[0-9]+}}, i32 5, i32 1)
+ x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: call void @__opencl_atomic_store_4(i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: %[[GP:[0-9]+]] = addrspacecast i8 addrspace(1)* {{%[0-9]+}} to i8 addrspace(4)*
+ // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* %[[GP]], i32 {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: call void @__opencl_atomic_store_4(i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ __opencl_atomic_store(gi, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: %[[GP:[0-9]+]] = addrspacecast i8 addrspace(3)* {{%[0-9]+}} to i8 addrspace(4)*
+ // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* %[[GP]], i32 {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: call void @__opencl_atomic_store_4(i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ __opencl_atomic_store(li, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: %[[GP:[0-9]+]] = addrspacecast i8* {{%[0-9]+}} to i8 addrspace(4)*
+ // SPIR: call void @__opencl_atomic_store_4(i8 addrspace(4)* %[[GP]], i32 {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: call void @__opencl_atomic_store_4(i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ __opencl_atomic_store(pi, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ x = __opencl_atomic_fetch_add(i, 3, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ x = __opencl_atomic_fetch_min(i, 3, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 1)
+ x = __opencl_atomic_fetch_min(ui, 3, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* {{%[0-9]+}}, i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 1)
+ // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* {{%[0-9]+}}, i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 1)
+ x = __opencl_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* {{%[0-9]+}}, i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 1)
+ // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* {{%[0-9]+}}, i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 1)
+ x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group);
+
+ // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* {{%[0-9]+}}, i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 2)
+ // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* {{%[0-9]+}}, i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 2)
+ x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_device);
+
+ // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* {{%[0-9]+}}, i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 3)
+ // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* {{%[0-9]+}}, i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 3)
+ x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_all_svm_devices);
+
+#ifdef cl_khr_subgroups
+ // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* {{%[0-9]+}}, i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 5, i32 5, i32 4)
+ x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_sub_group);
+#endif
+
+ // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8 addrspace(4)* {{%[0-9]+}}, i8 addrspace(4)* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}})
+ // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(i8* {{%[0-9]+}}, i8* {{%[0-9]+}}, i32 {{%[0-9]+}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}})
+ x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, order, order, scope);
+}
diff --git a/test/CodeGenOpenCL/atomic-ops.cl b/test/CodeGenOpenCL/atomic-ops.cl
new file mode 100644
index 0000000000..160f7fbd52
--- /dev/null
+++ b/test/CodeGenOpenCL/atomic-ops.cl
@@ -0,0 +1,291 @@
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -O0 -o - -triple=amdgcn-amd-amdhsa-amdgizcl | opt -instnamer -S | FileCheck %s
+
+// Also test serialization of atomic operations here, to avoid duplicating the test.
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-pch -O0 -o %t -triple=amdgcn-amd-amdhsa-amdgizcl
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -include-pch %t -O0 -triple=amdgcn-amd-amdhsa-amdgizcl -emit-llvm -o - | opt -instnamer -S | FileCheck %s
+
+#ifndef ALREADY_INCLUDED
+#define ALREADY_INCLUDED
+
+typedef __INTPTR_TYPE__ intptr_t;
+typedef int int8 __attribute__((ext_vector_type(8)));
+
+typedef enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+typedef enum memory_scope {
+ memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM,
+ memory_scope_work_group = __OPENCL_MEMORY_SCOPE_WORK_GROUP,
+ memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE,
+ memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES,
+#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups)
+ memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP
+#endif
+} memory_scope;
+
+atomic_int j;
+
+void fi1(atomic_int *i) {
+ // CHECK-LABEL: @fi1
+ // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ int x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group);
+
+ // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} syncscope("agent") seq_cst
+ x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_device);
+
+ // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} seq_cst
+ x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_all_svm_devices);
+
+ // CHECK: load atomic i32, i32* %{{[.0-9A-Z_a-z]+}} syncscope("subgroup") seq_cst
+ x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_sub_group);
+}
+
+void fi2(atomic_int *i) {
+ // CHECK-LABEL: @fi2
+ // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group);
+}
+
+void test_addr(global atomic_int *ig, private atomic_int *ip, local atomic_int *il) {
+ // CHECK-LABEL: @test_addr
+ // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32 addrspace(1)* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ __opencl_atomic_store(ig, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32 addrspace(5)* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ __opencl_atomic_store(ip, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // CHECK: store atomic i32 %{{[.0-9A-Z_a-z]+}}, i32 addrspace(3)* %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ __opencl_atomic_store(il, 1, memory_order_seq_cst, memory_scope_work_group);
+}
+
+void fi3(atomic_int *i, atomic_uint *ui) {
+ // CHECK-LABEL: @fi3
+ // CHECK: atomicrmw and i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ int x = __opencl_atomic_fetch_and(i, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // CHECK: atomicrmw min i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ x = __opencl_atomic_fetch_min(i, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // CHECK: atomicrmw max i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ x = __opencl_atomic_fetch_max(i, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // CHECK: atomicrmw umin i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ x = __opencl_atomic_fetch_min(ui, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ // CHECK: atomicrmw umax i32* %{{[.0-9A-Z_a-z]+}}, i32 %{{[.0-9A-Z_a-z]+}} syncscope("workgroup") seq_cst
+ x = __opencl_atomic_fetch_max(ui, 1, memory_order_seq_cst, memory_scope_work_group);
+}
+
+bool fi4(atomic_int *i) {
+ // CHECK-LABEL: @fi4(
+ // CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]] syncscope("workgroup") acquire acquire
+ // CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
+ // CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
+ // CHECK: br i1 [[CMP]], label %[[STORE_EXPECTED:[.0-9A-Z_a-z]+]], label %[[CONTINUE:[.0-9A-Z_a-z]+]]
+ // CHECK: store i32 [[OLD]]
+ int cmp = 0;
+ return __opencl_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_acquire, memory_order_acquire, memory_scope_work_group);
+}
+
+void fi5(atomic_int *i, int scope) {
+ // CHECK-LABEL: @fi5
+ // CHECK: switch i32 %{{.*}}, label %[[opencl_allsvmdevices:.*]] [
+ // CHECK-NEXT: i32 1, label %[[opencl_workgroup:.*]]
+ // CHECK-NEXT: i32 2, label %[[opencl_device:.*]]
+ // CHECK-NEXT: i32 4, label %[[opencl_subgroup:.*]]
+ // CHECK-NEXT: ]
+ // CHECK: [[opencl_workgroup]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup") seq_cst
+ // CHECK: br label %[[continue:.*]]
+ // CHECK: [[opencl_device]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent") seq_cst
+ // CHECK: br label %[[continue]]
+ // CHECK: [[opencl_allsvmdevices]]:
+ // CHECK: load atomic i32, i32* %{{.*}} seq_cst
+ // CHECK: br label %[[continue]]
+ // CHECK: [[opencl_subgroup]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("subgroup") seq_cst
+ // CHECK: br label %[[continue]]
+ // CHECK: [[continue]]:
+ int x = __opencl_atomic_load(i, memory_order_seq_cst, scope);
+}
+
+void fi6(atomic_int *i, int order, int scope) {
+ // CHECK-LABEL: @fi6
+ // CHECK: switch i32 %{{.*}}, label %[[monotonic:.*]] [
+ // CHECK-NEXT: i32 1, label %[[acquire:.*]]
+ // CHECK-NEXT: i32 2, label %[[acquire:.*]]
+ // CHECK-NEXT: i32 5, label %[[seqcst:.*]]
+ // CHECK-NEXT: ]
+ // CHECK: [[monotonic]]:
+ // CHECK: switch i32 %{{.*}}, label %[[MON_ALL:.*]] [
+ // CHECK-NEXT: i32 1, label %[[MON_WG:.*]]
+ // CHECK-NEXT: i32 2, label %[[MON_DEV:.*]]
+ // CHECK-NEXT: i32 4, label %[[MON_SUB:.*]]
+ // CHECK-NEXT: ]
+ // CHECK: [[acquire]]:
+ // CHECK: switch i32 %{{.*}}, label %[[ACQ_ALL:.*]] [
+ // CHECK-NEXT: i32 1, label %[[ACQ_WG:.*]]
+ // CHECK-NEXT: i32 2, label %[[ACQ_DEV:.*]]
+ // CHECK-NEXT: i32 4, label %[[ACQ_SUB:.*]]
+ // CHECK-NEXT: ]
+ // CHECK: [[seqcst]]:
+ // CHECK: switch i32 %{{.*}}, label %[[SEQ_ALL:.*]] [
+ // CHECK-NEXT: i32 1, label %[[SEQ_WG:.*]]
+ // CHECK-NEXT: i32 2, label %[[SEQ_DEV:.*]]
+ // CHECK-NEXT: i32 4, label %[[SEQ_SUB:.*]]
+ // CHECK-NEXT: ]
+ // CHECK: [[MON_WG]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup") monotonic
+ // CHECK: [[MON_DEV]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent") monotonic
+ // CHECK: [[MON_ALL]]:
+ // CHECK: load atomic i32, i32* %{{.*}} monotonic
+ // CHECK: [[MON_SUB]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("subgroup") monotonic
+ // CHECK: [[ACQ_WG]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup") acquire
+ // CHECK: [[ACQ_DEV]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent") acquire
+ // CHECK: [[ACQ_ALL]]:
+ // CHECK: load atomic i32, i32* %{{.*}} acquire
+ // CHECK: [[ACQ_SUB]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("subgroup") acquire
+ // CHECK: [[SEQ_WG]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("workgroup") seq_cst
+ // CHECK: [[SEQ_DEV]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("agent") seq_cst
+ // CHECK: [[SEQ_ALL]]:
+ // CHECK: load atomic i32, i32* %{{.*}} seq_cst
+ // CHECK: [[SEQ_SUB]]:
+ // CHECK: load atomic i32, i32* %{{.*}} syncscope("subgroup") seq_cst
+ int x = __opencl_atomic_load(i, order, scope);
+}
+
+float ff1(global atomic_float *d) {
+ // CHECK-LABEL: @ff1
+ // CHECK: load atomic i32, i32 addrspace(1)* {{.*}} syncscope("workgroup") monotonic
+ return __opencl_atomic_load(d, memory_order_relaxed, memory_scope_work_group);
+}
+
+void ff2(atomic_float *d) {
+ // CHECK-LABEL: @ff2
+ // CHECK: store atomic i32 {{.*}} syncscope("workgroup") release
+ __opencl_atomic_store(d, 1, memory_order_release, memory_scope_work_group);
+}
+
+float ff3(atomic_float *d) {
+ // CHECK-LABEL: @ff3
+ // CHECK: atomicrmw xchg i32* {{.*}} syncscope("workgroup") seq_cst
+ return __opencl_atomic_exchange(d, 2, memory_order_seq_cst, memory_scope_work_group);
+}
+
+// CHECK-LABEL: @atomic_init_foo
+void atomic_init_foo()
+{
+ // CHECK-NOT: atomic
+ // CHECK: store
+ __opencl_atomic_init(&j, 42);
+
+ // CHECK-NOT: atomic
+ // CHECK: }
+}
+
+// CHECK-LABEL: @failureOrder
+void failureOrder(atomic_int *ptr, int *ptr2) {
+ // CHECK: cmpxchg i32* {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup") acquire monotonic
+ __opencl_atomic_compare_exchange_strong(ptr, ptr2, 43, memory_order_acquire, memory_order_relaxed, memory_scope_work_group);
+
+ // CHECK: cmpxchg weak i32* {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z._]+}}, i32 {{%[0-9A-Za-z_.]+}} syncscope("workgroup") seq_cst acquire
+ __opencl_atomic_compare_exchange_weak(ptr, ptr2, 43, memory_order_seq_cst, memory_order_acquire, memory_scope_work_group);
+}
+
+// CHECK-LABEL: @generalFailureOrder
+void generalFailureOrder(atomic_int *ptr, int *ptr2, int success, int fail) {
+ __opencl_atomic_compare_exchange_strong(ptr, ptr2, 42, success, fail, memory_scope_work_group);
+ // CHECK: switch i32 {{.*}}, label %[[MONOTONIC:[0-9a-zA-Z._]+]] [
+ // CHECK-NEXT: i32 1, label %[[ACQUIRE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: i32 2, label %[[ACQUIRE]]
+ // CHECK-NEXT: i32 3, label %[[RELEASE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: i32 4, label %[[ACQREL:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: i32 5, label %[[SEQCST:[0-9a-zA-Z._]+]]
+
+ // CHECK: [[MONOTONIC]]
+ // CHECK: switch {{.*}}, label %[[MONOTONIC_MONOTONIC:[0-9a-zA-Z._]+]] [
+ // CHECK-NEXT: ]
+
+ // CHECK: [[ACQUIRE]]
+ // CHECK: switch {{.*}}, label %[[ACQUIRE_MONOTONIC:[0-9a-zA-Z._]+]] [
+ // CHECK-NEXT: i32 1, label %[[ACQUIRE_ACQUIRE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: i32 2, label %[[ACQUIRE_ACQUIRE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: ]
+
+ // CHECK: [[RELEASE]]
+ // CHECK: switch {{.*}}, label %[[RELEASE_MONOTONIC:[0-9a-zA-Z._]+]] [
+ // CHECK-NEXT: ]
+
+ // CHECK: [[ACQREL]]
+ // CHECK: switch {{.*}}, label %[[ACQREL_MONOTONIC:[0-9a-zA-Z._]+]] [
+ // CHECK-NEXT: i32 1, label %[[ACQREL_ACQUIRE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: i32 2, label %[[ACQREL_ACQUIRE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: ]
+
+ // CHECK: [[SEQCST]]
+ // CHECK: switch {{.*}}, label %[[SEQCST_MONOTONIC:[0-9a-zA-Z._]+]] [
+ // CHECK-NEXT: i32 1, label %[[SEQCST_ACQUIRE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: i32 2, label %[[SEQCST_ACQUIRE:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: i32 5, label %[[SEQCST_SEQCST:[0-9a-zA-Z._]+]]
+ // CHECK-NEXT: ]
+
+ // CHECK: [[MONOTONIC_MONOTONIC]]
+ // CHECK: cmpxchg {{.*}} monotonic monotonic
+ // CHECK: br
+
+ // CHECK: [[ACQUIRE_MONOTONIC]]
+ // CHECK: cmpxchg {{.*}} acquire monotonic
+ // CHECK: br
+
+ // CHECK: [[ACQUIRE_ACQUIRE]]
+ // CHECK: cmpxchg {{.*}} acquire acquire
+ // CHECK: br
+
+ // CHECK: [[ACQREL_MONOTONIC]]
+ // CHECK: cmpxchg {{.*}} acq_rel monotonic
+ // CHECK: br
+
+ // CHECK: [[ACQREL_ACQUIRE]]
+ // CHECK: cmpxchg {{.*}} acq_rel acquire
+ // CHECK: br
+
+ // CHECK: [[SEQCST_MONOTONIC]]
+ // CHECK: cmpxchg {{.*}} seq_cst monotonic
+ // CHECK: br
+
+ // CHECK: [[SEQCST_ACQUIRE]]
+ // CHECK: cmpxchg {{.*}} seq_cst acquire
+ // CHECK: br
+
+ // CHECK: [[SEQCST_SEQCST]]
+ // CHECK: cmpxchg {{.*}} seq_cst seq_cst
+ // CHECK: br
+}
+
+int test_volatile(volatile atomic_int *i) {
+ // CHECK-LABEL: @test_volatile
+ // CHECK: %[[i_addr:.*]] = alloca i32
+ // CHECK-NEXT: %[[atomicdst:.*]] = alloca i32
+ // CHECK-NEXT: store i32* %i, i32* addrspace(5)* %[[i_addr]]
+ // CHECK-NEXT: %[[addr:.*]] = load i32*, i32* addrspace(5)* %[[i_addr]]
+ // CHECK-NEXT: %[[res:.*]] = load atomic volatile i32, i32* %[[addr]] syncscope("workgroup") seq_cst
+ // CHECK-NEXT: store i32 %[[res]], i32 addrspace(5)* %[[atomicdst]]
+ // CHECK-NEXT: %[[retval:.*]] = load i32, i32 addrspace(5)* %[[atomicdst]]
+ // CHECK-NEXT: ret i32 %[[retval]]
+ return __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group);
+}
+
+#endif
diff --git a/test/CodeGenOpenCL/blocks.cl b/test/CodeGenOpenCL/blocks.cl
index 5f0cceaf6c..146d9dc113 100644
--- a/test/CodeGenOpenCL/blocks.cl
+++ b/test/CodeGenOpenCL/blocks.cl
@@ -1,17 +1,54 @@
-// 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
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck -check-prefixes=COMMON,SPIR %s
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -O0 -triple amdgcn-amd-amdhsa-opencl | FileCheck -check-prefixes=COMMON,AMD %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
+// COMMON: %struct.__opencl_block_literal_generic = type { i32, i32, i8 addrspace(4)* }
+// SPIR: @__block_literal_global = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 12, i32 4, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* @block_A_block_invoke to i8*) to i8 addrspace(4)*) }
+// AMD: @__block_literal_global = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 16, i32 8, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* @block_A_block_invoke to i8*) to i8 addrspace(4)*) }
+// COMMON-NOT: .str
+
+// COMMON-LABEL: define internal {{.*}}void @block_A_block_invoke(i8 addrspace(4)* %.block_descriptor, i8 addrspace(3)* %a)
void (^block_A)(local void *) = ^(local void *a) {
return;
};
+// COMMON-LABEL: define {{.*}}void @foo()
void foo(){
int i;
-// Checking for null instead of @_NSConcreteStackBlock symbol
-// COMMON: store i8* null, i8** %block.isa
+ // COMMON-NOT: %block.isa
+ // COMMON-NOT: %block.flags
+ // COMMON-NOT: %block.reserved
+ // COMMON-NOT: %block.descriptor
+ // COMMON: %[[block_size:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %block, i32 0, i32 0
+ // SPIR: store i32 16, i32* %[[block_size]]
+ // AMD: store i32 20, i32* %[[block_size]]
+ // COMMON: %[[block_align:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %block, i32 0, i32 1
+ // SPIR: store i32 4, i32* %[[block_align]]
+ // AMD: store i32 8, i32* %[[block_align]]
+ // COMMON: %[[block_invoke:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %[[block:.*]], i32 0, i32 2
+ // COMMON: store i8 addrspace(4)* addrspacecast (i8* bitcast (i32 (i8 addrspace(4)*)* @__foo_block_invoke to i8*) to i8 addrspace(4)*), i8 addrspace(4)** %[[block_invoke]]
+ // COMMON: %[[block_captured:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }>* %[[block]], i32 0, i32 3
+ // COMMON: %[[i_value:.*]] = load i32, i32* %i
+ // COMMON: store i32 %[[i_value]], i32* %[[block_captured]],
+ // COMMON: %[[blk_ptr:.*]] = bitcast <{ i32, i32, i8 addrspace(4)*, i32 }>* %[[block]] to i32 ()*
+ // COMMON: %[[blk_gen_ptr:.*]] = addrspacecast i32 ()* %[[blk_ptr]] to i32 () addrspace(4)*
+ // COMMON: store i32 () addrspace(4)* %[[blk_gen_ptr]], i32 () addrspace(4)** %[[block_B:.*]],
+ // COMMON: %[[blk_gen_ptr:.*]] = load i32 () addrspace(4)*, i32 () addrspace(4)** %[[block_B]]
+ // COMMON: %[[block_literal:.*]] = bitcast i32 () addrspace(4)* %[[blk_gen_ptr]] to %struct.__opencl_block_literal_generic addrspace(4)*
+ // COMMON: %[[invoke_addr:.*]] = getelementptr inbounds %struct.__opencl_block_literal_generic, %struct.__opencl_block_literal_generic addrspace(4)* %[[block_literal]], i32 0, i32 2
+ // COMMON: %[[blk_gen_ptr:.*]] = bitcast %struct.__opencl_block_literal_generic addrspace(4)* %[[block_literal]] to i8 addrspace(4)*
+ // COMMON: %[[invoke_func_ptr:.*]] = load i8 addrspace(4)*, i8 addrspace(4)* addrspace(4)* %[[invoke_addr]]
+ // COMMON: %[[invoke_func:.*]] = addrspacecast i8 addrspace(4)* %[[invoke_func_ptr]] to i32 (i8 addrspace(4)*)*
+ // COMMON: call {{.*}}i32 %[[invoke_func]](i8 addrspace(4)* %[[blk_gen_ptr]])
+
int (^ block_B)(void) = ^{
return i;
};
+ block_B();
}
+
+// COMMON-LABEL: define internal {{.*}}i32 @__foo_block_invoke(i8 addrspace(4)* %.block_descriptor)
+// COMMON: %[[block:.*]] = bitcast i8 addrspace(4)* %.block_descriptor to <{ i32, i32, i8 addrspace(4)*, i32 }> addrspace(4)*
+// COMMON: %[[block_capture_addr:.*]] = getelementptr inbounds <{ i32, i32, i8 addrspace(4)*, i32 }>, <{ i32, i32, i8 addrspace(4)*, i32 }> addrspace(4)* %[[block]], i32 0, i32 3
+// COMMON: %[[block_capture:.*]] = load i32, i32 addrspace(4)* %[[block_capture_addr]]
+
+// COMMON-NOT: define{{.*}}@__foo_block_invoke_kernel
diff --git a/test/CodeGenOpenCL/bool_cast.cl b/test/CodeGenOpenCL/bool_cast.cl
index 8c86b06577..72926eb141 100644
--- a/test/CodeGenOpenCL/bool_cast.cl
+++ b/test/CodeGenOpenCL/bool_cast.cl
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -O0 | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -o - -O0 | FileCheck %s
typedef unsigned char uchar4 __attribute((ext_vector_type(4)));
typedef unsigned int int4 __attribute((ext_vector_type(4)));
typedef float float4 __attribute((ext_vector_type(4)));
-// CHECK-LABEL: define void @ker()
+// CHECK-LABEL: define spir_kernel void @ker()
void kernel ker() {
bool t = true;
int4 vec4 = (int4)t;
diff --git a/test/CodeGenOpenCL/builtins-amdgcn.cl b/test/CodeGenOpenCL/builtins-amdgcn.cl
index a19ce2f1ed..9f036547bf 100644
--- a/test/CodeGenOpenCL/builtins-amdgcn.cl
+++ b/test/CodeGenOpenCL/builtins-amdgcn.cl
@@ -1,5 +1,6 @@
// REQUIRES: amdgpu-registered-target
// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple amdgcn-unknown-unknown-opencl -S -emit-llvm -o - %s | FileCheck %s
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
@@ -420,6 +421,25 @@ void test_read_exec(global ulong* out) {
// CHECK: declare i64 @llvm.read_register.i64(metadata) #[[NOUNWIND_READONLY:[0-9]+]]
+// CHECK-LABEL: @test_read_exec_lo(
+// CHECK: call i32 @llvm.read_register.i32(metadata ![[EXEC_LO:[0-9]+]]) #[[READ_EXEC_ATTRS]]
+void test_read_exec_lo(global uint* out) {
+ *out = __builtin_amdgcn_read_exec_lo();
+}
+
+// CHECK-LABEL: @test_read_exec_hi(
+// CHECK: call i32 @llvm.read_register.i32(metadata ![[EXEC_HI:[0-9]+]]) #[[READ_EXEC_ATTRS]]
+void test_read_exec_hi(global uint* out) {
+ *out = __builtin_amdgcn_read_exec_hi();
+}
+
+// CHECK-LABEL: @test_dispatch_ptr
+// CHECK: call i8 addrspace(2)* @llvm.amdgcn.dispatch.ptr()
+void test_dispatch_ptr(__attribute__((address_space(2))) unsigned char ** out)
+{
+ *out = __builtin_amdgcn_dispatch_ptr();
+}
+
// CHECK-LABEL: @test_kernarg_segment_ptr
// CHECK: call i8 addrspace(2)* @llvm.amdgcn.kernarg.segment.ptr()
void test_kernarg_segment_ptr(__attribute__((address_space(2))) unsigned char ** out)
@@ -480,7 +500,16 @@ void test_fmed3_f32(global float* out, float a, float b, float c)
*out = __builtin_amdgcn_fmed3f(a, b, c);
}
+// CHECK-LABEL: @test_s_getpc
+// CHECK: call i64 @llvm.amdgcn.s.getpc()
+void test_s_getpc(global ulong* out)
+{
+ *out = __builtin_amdgcn_s_getpc();
+}
+
// CHECK-DAG: [[WI_RANGE]] = !{i32 0, i32 1024}
// CHECK-DAG: attributes #[[NOUNWIND_READONLY:[0-9]+]] = { nounwind readonly }
// CHECK-DAG: attributes #[[READ_EXEC_ATTRS]] = { convergent }
// CHECK-DAG: ![[EXEC]] = !{!"exec"}
+// CHECK-DAG: ![[EXEC_LO]] = !{!"exec_lo"}
+// CHECK-DAG: ![[EXEC_HI]] = !{!"exec_hi"}
diff --git a/test/CodeGenOpenCL/byval.cl b/test/CodeGenOpenCL/byval.cl
new file mode 100644
index 0000000000..90afdfab52
--- /dev/null
+++ b/test/CodeGenOpenCL/byval.cl
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn---opencl %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn---amdgizcl %s | FileCheck %s -check-prefix=AMDGIZ
+
+struct A {
+ int x[100];
+};
+
+int f(struct A a);
+
+int g() {
+ struct A a;
+ // CHECK: call i32 @f(%struct.A* byval{{.*}}%a)
+ // AMDGIZ: call i32 @f(%struct.A addrspace(5)* byval{{.*}}%a)
+ return f(a);
+}
+
+// CHECK: declare i32 @f(%struct.A* byval{{.*}})
+// AMDGIZ: declare i32 @f(%struct.A addrspace(5)* byval{{.*}})
diff --git a/test/CodeGenOpenCL/cl20-device-side-enqueue.cl b/test/CodeGenOpenCL/cl20-device-side-enqueue.cl
index def2906615..0bf87c25bd 100644
--- a/test/CodeGenOpenCL/cl20-device-side-enqueue.cl
+++ b/test/CodeGenOpenCL/cl20-device-side-enqueue.cl
@@ -1,13 +1,35 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -ffake-address-space-map -O0 -emit-llvm -o - -triple "spir-unknown-unknown" | FileCheck %s --check-prefix=COMMON --check-prefix=B32
// 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
+#pragma OPENCL EXTENSION cl_khr_subgroups : enable
+
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 = 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)*)
+// COMMON: %struct.__opencl_block_literal_generic = type { i32, i32, i8 addrspace(4)* }
+
+// For a block global variable, first emit the block literal as a global variable, then emit the block variable itself.
+// COMMON: [[BL_GLOBAL:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* [[INV_G:@[^ ]+]] to i8*) to i8 addrspace(4)*) }
+// COMMON: @block_G = addrspace(1) constant void (i8 addrspace(3)*) addrspace(4)* addrspacecast (void (i8 addrspace(3)*) addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BL_GLOBAL]] to void (i8 addrspace(3)*) addrspace(1)*) to void (i8 addrspace(3)*) addrspace(4)*)
+
+// For anonymous blocks without captures, emit block literals as global variable.
+// COMMON: [[BLG1:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG2:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG3:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG4:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG5:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG6:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*, i8 addrspace(3)*, i8 addrspace(3)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG7:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG8:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*)* [[INVG8:@[^ ]+]] to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG9:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*, i8 addrspace(3)*)* [[INVG9:@[^ ]+]] to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG10:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+// COMMON: [[BLG11:@__block_literal_global[^ ]*]] = internal addrspace(1) constant { i32, i32, i8 addrspace(4)* } { i32 {{[0-9]+}}, i32 {{[0-9]+}}, i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*)* {{@[^ ]+}} to i8*) to i8 addrspace(4)*) }
+
+// Emits block literal [[BL_GLOBAL]], invoke function [[INV_G]] and global block variable @block_G
+// COMMON: define internal spir_func void [[INV_G]](i8 addrspace(4)* %{{.*}}, i8 addrspace(3)* %{{.*}})
const bl_t block_G = (bl_t) ^ (local void *a) {};
+// COMMON-LABEL: define spir_kernel void @device_side_enqueue(i32 addrspace(1)* %{{.*}}, i32 addrspace(1)* %b, i32 %i)
kernel void device_side_enqueue(global int *a, global int *b, int i) {
// COMMON: %default_queue = alloca %opencl.queue_t*
queue_t default_queue;
@@ -22,73 +44,125 @@ 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};
+ // Emits block literal on stack and block kernel [[INVLK1]].
// 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: [[BL:%[0-9]+]] = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor addrspace(2)*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block to void ()*
+ // COMMON: store i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*)* [[INVL1:@__device_side_enqueue_block_invoke[^ ]*]] to i8*) to i8 addrspace(4)*), i8 addrspace(4)** %block.invoke
+ // B32: [[BL:%[0-9]+]] = bitcast <{ i32, i32, i8 addrspace(4)*, i32 addrspace(1)*, i32, i32 addrspace(1)* }>* %block to void ()*
+ // B64: [[BL:%[0-9]+]] = bitcast <{ i32, i32, i8 addrspace(4)*, i32 addrspace(1)*, i32 addrspace(1)*, i32 }>* %block to void ()*
// 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]])
+ // COMMON-LABEL: call i32 @__enqueue_kernel_basic(
+ // COMMON-SAME: %opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* byval [[NDR]]{{([0-9]+)?}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVLK1:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* [[BL_I8]])
enqueue_kernel(default_queue, flags, ndrange,
^(void) {
a[i] = b[i];
});
+ // Emits block literal on stack and block kernel [[INVLK2]].
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
// 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: store i8 addrspace(4)* addrspacecast (i8* bitcast (void (i8 addrspace(4)*)* [[INVL2:@__device_side_enqueue_block_invoke[^ ]*]] to i8*) to i8 addrspace(4)*), i8 addrspace(4)** %block.invoke
+ // COMMON: [[BL:%[0-9]+]] = bitcast <{ i32, i32, i8 addrspace(4)*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block3 to void ()*
// 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]])
+ // COMMON-LABEL: call i32 @__enqueue_kernel_basic_events
+ // COMMON-SAME: (%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]],
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVLK2:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* [[BL_I8]])
+
enqueue_kernel(default_queue, flags, ndrange, 2, &event_wait_list, &clk_event,
^(void) {
a[i] = b[i];
});
+ // Emits global block literal [[BLG1]] and block kernel [[INVGK1]].
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // 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)
+ // B32: %[[TMP:.*]] = alloca [1 x i32]
+ // B32: %[[TMP1:.*]] = getelementptr [1 x i32], [1 x i32]* %[[TMP]], i32 0, i32 0
+ // B32: store i32 256, i32* %[[TMP1]], align 4
+ // B64: %[[TMP:.*]] = alloca [1 x i64]
+ // B64: %[[TMP1:.*]] = getelementptr [1 x i64], [1 x i64]* %[[TMP]], i32 0, i32 0
+ // B64: store i64 256, i64* %[[TMP1]], align 8
+ // COMMON-LABEL: call i32 @__enqueue_kernel_vaargs(
+ // COMMON-SAME: %opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{([0-9]+)?}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK1:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG1]] to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1,
+ // B32-SAME: i32* %[[TMP1]])
+ // B64-SAME: i64* %[[TMP1]])
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
},
256);
char c;
+ // Emits global block literal [[BLG2]] and block kernel [[INVGK2]].
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // B32: [[SIZE:%[0-9]+]] = zext i8 {{%[0-9]+}} to i32
- // 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, %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]])
+ // B32: %[[TMP:.*]] = alloca [1 x i32]
+ // B32: %[[TMP1:.*]] = getelementptr [1 x i32], [1 x i32]* %[[TMP]], i32 0, i32 0
+ // B32: store i32 %{{.*}}, i32* %[[TMP1]], align 4
+ // B64: %[[TMP:.*]] = alloca [1 x i64]
+ // B64: %[[TMP1:.*]] = getelementptr [1 x i64], [1 x i64]* %[[TMP]], i32 0, i32 0
+ // B64: store i64 %{{.*}}, i64* %[[TMP1]], align 8
+ // COMMON-LABEL: call i32 @__enqueue_kernel_vaargs(
+ // COMMON-SAME: %opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{([0-9]+)?}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK2:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG2]] to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1,
+ // B32-SAME: i32* %[[TMP1]])
+ // B64-SAME: i64* %[[TMP1]])
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
},
c);
+ // Emits global block literal [[BLG3]] and block kernel [[INVGK3]].
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
// 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, %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)
+ // B32: %[[TMP:.*]] = alloca [1 x i32]
+ // B32: %[[TMP1:.*]] = getelementptr [1 x i32], [1 x i32]* %[[TMP]], i32 0, i32 0
+ // B32: store i32 256, i32* %[[TMP1]], align 4
+ // B64: %[[TMP:.*]] = alloca [1 x i64]
+ // B64: %[[TMP1:.*]] = getelementptr [1 x i64], [1 x i64]* %[[TMP]], i32 0, i32 0
+ // B64: store i64 256, i64* %[[TMP1]], align 8
+ // COMMON-LABEL: call i32 @__enqueue_kernel_events_vaargs
+ // COMMON-SAME: (%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* {{.*}}, i32 2, %opencl.clk_event_t{{.*}} [[WAIT_EVNT]], %opencl.clk_event_t{{.*}} [[EVNT]],
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK3:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG3]] to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1,
+ // B32-SAME: i32* %[[TMP1]])
+ // B64-SAME: i64* %[[TMP1]])
enqueue_kernel(default_queue, flags, ndrange, 2, event_wait_list2, &clk_event,
^(local void *p) {
return;
},
256);
+ // Emits global block literal [[BLG4]] and block kernel [[INVGK4]].
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
// 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, %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, %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]])
+ // B32: %[[TMP:.*]] = alloca [1 x i32]
+ // B32: %[[TMP1:.*]] = getelementptr [1 x i32], [1 x i32]* %[[TMP]], i32 0, i32 0
+ // B32: store i32 %{{.*}}, i32* %[[TMP1]], align 4
+ // B64: %[[TMP:.*]] = alloca [1 x i64]
+ // B64: %[[TMP1:.*]] = getelementptr [1 x i64], [1 x i64]* %[[TMP]], i32 0, i32 0
+ // B64: store i64 %{{.*}}, i64* %[[TMP1]], align 8
+ // COMMON-LABEL: call i32 @__enqueue_kernel_events_vaargs
+ // COMMON-SAME: (%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]],
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK4:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG4]] to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1,
+ // B32-SAME: i32* %[[TMP1]])
+ // B64-SAME: i64* %[[TMP1]])
enqueue_kernel(default_queue, flags, ndrange, 2, event_wait_list2, &clk_event,
^(local void *p) {
return;
@@ -96,46 +170,170 @@ kernel void device_side_enqueue(global int *a, global int *b, int i) {
c);
long l;
+ // Emits global block literal [[BLG5]] and block kernel [[INVGK5]].
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // B32: [[SIZE:%[0-9]+]] = trunc i64 {{%[0-9]+}} to i32
- // 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, %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]])
+ // B32: %[[TMP:.*]] = alloca [1 x i32]
+ // B32: %[[TMP1:.*]] = getelementptr [1 x i32], [1 x i32]* %[[TMP]], i32 0, i32 0
+ // B32: store i32 %{{.*}}, i32* %[[TMP1]], align 4
+ // B64: %[[TMP:.*]] = alloca [1 x i64]
+ // B64: %[[TMP1:.*]] = getelementptr [1 x i64], [1 x i64]* %[[TMP]], i32 0, i32 0
+ // B64: store i64 %{{.*}}, i64* %[[TMP1]], align 8
+ // COMMON-LABEL: call i32 @__enqueue_kernel_vaargs
+ // COMMON-SAME: (%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{([0-9]+)?}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK5:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG5]] to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1,
+ // B32-SAME: i32* %[[TMP1]])
+ // B64-SAME: i64* %[[TMP1]])
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
},
l);
+ // Emits global block literal [[BLG6]] and block kernel [[INVGK6]].
+ // COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
+ // COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
+ // B32: %[[TMP:.*]] = alloca [3 x i32]
+ // B32: %[[TMP1:.*]] = getelementptr [3 x i32], [3 x i32]* %[[TMP]], i32 0, i32 0
+ // B32: store i32 1, i32* %[[TMP1]], align 4
+ // B32: %[[TMP2:.*]] = getelementptr [3 x i32], [3 x i32]* %[[TMP]], i32 0, i32 1
+ // B32: store i32 2, i32* %[[TMP2]], align 4
+ // B32: %[[TMP3:.*]] = getelementptr [3 x i32], [3 x i32]* %[[TMP]], i32 0, i32 2
+ // B32: store i32 4, i32* %[[TMP3]], align 4
+ // B64: %[[TMP:.*]] = alloca [3 x i64]
+ // B64: %[[TMP1:.*]] = getelementptr [3 x i64], [3 x i64]* %[[TMP]], i32 0, i32 0
+ // B64: store i64 1, i64* %[[TMP1]], align 8
+ // B64: %[[TMP2:.*]] = getelementptr [3 x i64], [3 x i64]* %[[TMP]], i32 0, i32 1
+ // B64: store i64 2, i64* %[[TMP2]], align 8
+ // B64: %[[TMP3:.*]] = getelementptr [3 x i64], [3 x i64]* %[[TMP]], i32 0, i32 2
+ // B64: store i64 4, i64* %[[TMP3]], align 8
+ // COMMON-LABEL: call i32 @__enqueue_kernel_vaargs
+ // COMMON-SAME: (%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{([0-9]+)?}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK6:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG6]] to i8 addrspace(1)*) to i8 addrspace(4)*), i32 3,
+ // B32-SAME: i32* %[[TMP1]])
+ // B64-SAME: i64* %[[TMP1]])
+ enqueue_kernel(default_queue, flags, ndrange,
+ ^(local void *p1, local void *p2, local void *p3) {
+ return;
+ },
+ 1, 2, 4);
+
+ // Emits global block literal [[BLG7]] and block kernel [[INVGK7]].
// COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t*, %opencl.queue_t** %default_queue
// COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
- // 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)
+ // B32: %[[TMP:.*]] = alloca [1 x i32]
+ // B32: %[[TMP1:.*]] = getelementptr [1 x i32], [1 x i32]* %[[TMP]], i32 0, i32 0
+ // B32: store i32 0, i32* %[[TMP1]], align 4
+ // B64: %[[TMP:.*]] = alloca [1 x i64]
+ // B64: %[[TMP1:.*]] = getelementptr [1 x i64], [1 x i64]* %[[TMP]], i32 0, i32 0
+ // B64: store i64 4294967296, i64* %[[TMP1]], align 8
+ // COMMON-LABEL: call i32 @__enqueue_kernel_vaargs
+ // COMMON-SAME: (%opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* [[NDR]]{{([0-9]+)?}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK7:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG7]] to i8 addrspace(1)*) to i8 addrspace(4)*), i32 1,
+ // B32-SAME: i32* %[[TMP1]])
+ // B64-SAME: i64* %[[TMP1]])
enqueue_kernel(default_queue, flags, ndrange,
^(local void *p) {
return;
},
4294967296L);
+ // Emits global block literal [[BLG8]] and invoke function [[INVG8]].
// 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 () 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
+ // COMMON: store void () addrspace(4)* addrspacecast (void () addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] 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)*) 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
+ // Emits global block literal [[BLG9]] and invoke function [[INVG9]].
+ // COMMON: store void (i8 addrspace(3)*) addrspace(4)* addrspacecast (void (i8 addrspace(3)*) addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG9]] 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 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)*))
+ // Uses global block literal [[BLG8]] and invoke function [[INVG8]].
+ // COMMON: [[r1:%.*]] = load i8 addrspace(4)*, i8 addrspace(4)* addrspace(4)* getelementptr inbounds (%struct.__opencl_block_literal_generic, %struct.__opencl_block_literal_generic addrspace(4)* addrspacecast (%struct.__opencl_block_literal_generic addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] to %struct.__opencl_block_literal_generic addrspace(1)*) to %struct.__opencl_block_literal_generic addrspace(4)*), i32 0, i32 2)
+ // COMMON: [[r2:%.*]] = addrspacecast i8 addrspace(4)* [[r1]] to void (i8 addrspace(4)*)*
+ // COMMON: call spir_func void [[r2]](i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] to i8 addrspace(1)*) to i8 addrspace(4)*))
+ block_A();
+
+ // Emits global block literal [[BLG8]] and block kernel [[INVGK8]]. [[INVGK8]] calls [[INVG8]].
+ // COMMON: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t{{.*}}*, %opencl.queue_t{{.*}}** %default_queue
+ // COMMON: [[FLAGS:%[0-9]+]] = load i32, i32* %flags
+ // COMMON-LABEL: call i32 @__enqueue_kernel_basic(
+ // COMMON-SAME: %opencl.queue_t{{.*}}* [[DEF_Q]], i32 [[FLAGS]], %struct.ndrange_t* byval [[NDR]]{{([0-9]+)?}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK8:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] to i8 addrspace(1)*) to i8 addrspace(4)*))
+ enqueue_kernel(default_queue, flags, ndrange, block_A);
+
+ // Uses block kernel [[INVGK8]] and global block literal [[BLG8]].
+ // COMMON: call i32 @__get_kernel_work_group_size_impl(
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK8]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] 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 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)*))
+
+ // Uses global block literal [[BLG8]] and invoke function [[INVG8]]. Make sure no redundant block literal and invoke functions are emitted.
+ // COMMON: [[r1:%.*]] = load i8 addrspace(4)*, i8 addrspace(4)* addrspace(4)* getelementptr inbounds (%struct.__opencl_block_literal_generic, %struct.__opencl_block_literal_generic addrspace(4)* addrspacecast (%struct.__opencl_block_literal_generic addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] to %struct.__opencl_block_literal_generic addrspace(1)*) to %struct.__opencl_block_literal_generic addrspace(4)*), i32 0, i32 2)
+ // COMMON: [[r2:%.*]] = addrspacecast i8 addrspace(4)* [[r1]] to void (i8 addrspace(4)*)*
+ // COMMON: call spir_func void [[r2]](i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] to i8 addrspace(1)*) to i8 addrspace(4)*))
+ block_A();
+
+ // Emits global block literal [[BLG9]] and block kernel [[INVGK9]]. [[INVGK9]] calls [[INV9]].
+ // COMMON: call i32 @__get_kernel_work_group_size_impl(
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK9:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG9]] 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 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)*))
+
+ // Uses global block literal [[BLG8]] and block kernel [[INVGK8]]. Make sure no redundant block literal ind invoke functions are emitted.
+ // COMMON: call i32 @__get_kernel_preferred_work_group_multiple_impl(
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK8]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG8]] 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 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)*))
+
+ // Uses global block literal [[BL_GLOBAL]] and block kernel [[INV_G_K]]. [[INV_G_K]] calls [[INV_G]].
+ // COMMON: call i32 @__get_kernel_preferred_work_group_multiple_impl(
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INV_G_K:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BL_GLOBAL]] to i8 addrspace(1)*) to i8 addrspace(4)*))
size = get_kernel_preferred_work_group_size_multiple(block_G);
+
+ // Emits global block literal [[BLG10]] and block kernel [[INVGK10]].
+ // COMMON: call i32 @__get_kernel_max_sub_group_size_for_ndrange_impl(%struct.ndrange_t* {{[^,]+}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK10:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG10]] to i8 addrspace(1)*) to i8 addrspace(4)*))
+ size = get_kernel_max_sub_group_size_for_ndrange(ndrange, ^(){});
+
+ // Emits global block literal [[BLG11]] and block kernel [[INVGK11]].
+ // COMMON: call i32 @__get_kernel_sub_group_count_for_ndrange_impl(%struct.ndrange_t* {{[^,]+}},
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8* bitcast ({{.*}} [[INVGK11:[^ ]+_kernel]] to i8*) to i8 addrspace(4)*),
+ // COMMON-SAME: i8 addrspace(4)* addrspacecast (i8 addrspace(1)* bitcast ({ i32, i32, i8 addrspace(4)* } addrspace(1)* [[BLG11]] to i8 addrspace(1)*) to i8 addrspace(4)*))
+ size = get_kernel_sub_group_count_for_ndrange(ndrange, ^(){});
}
+
+// COMMON: define internal spir_kernel void [[INVLK1]](i8 addrspace(4)*) #{{[0-9]+}} {
+// COMMON: entry:
+// COMMON: call void @__device_side_enqueue_block_invoke(i8 addrspace(4)* %0)
+// COMMON: ret void
+// COMMON: }
+// COMMON: define internal spir_kernel void [[INVLK2]](i8 addrspace(4)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK1]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK2]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK3]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK4]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK5]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK6]](i8 addrspace(4)*, i8 addrspace(3)*, i8 addrspace(3)*, i8 addrspace(3)*) #{{[0-9]+}} {
+// COMMON: entry:
+// COMMON: call void @__device_side_enqueue_block_invoke_8(i8 addrspace(4)* %0, i8 addrspace(3)* %1, i8 addrspace(3)* %2, i8 addrspace(3)* %3)
+// COMMON: ret void
+// COMMON: }
+// COMMON: define internal spir_kernel void [[INVGK7]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_func void [[INVG8]](i8 addrspace(4)*{{.*}})
+// COMMON: define internal spir_func void [[INVG9]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)* %{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK8]](i8 addrspace(4)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK9]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_kernel void [[INV_G_K]](i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK10]](i8 addrspace(4)*{{.*}})
+// COMMON: define internal spir_kernel void [[INVGK11]](i8 addrspace(4)*{{.*}})
diff --git a/test/CodeGenOpenCL/constant-addr-space-globals.cl b/test/CodeGenOpenCL/constant-addr-space-globals.cl
index 4f0d1ea23e..7bb970527c 100644
--- a/test/CodeGenOpenCL/constant-addr-space-globals.cl
+++ b/test/CodeGenOpenCL/constant-addr-space-globals.cl
@@ -11,10 +11,11 @@ kernel void test(global float *out) {
// but create a copy in the original address space (unless a variable itself is
// in the constant address space).
-void foo(constant const int *p1, const int *p2, const int *p3);
+void foo(constant int* p, constant const int *p1, const int *p2, const int *p3);
// CHECK: @k.arr1 = internal addrspace(2) constant [3 x i32] [i32 1, i32 2, i32 3]
// CHECK: @k.arr2 = private unnamed_addr addrspace(2) constant [3 x i32] [i32 4, i32 5, i32 6]
// CHECK: @k.arr3 = private unnamed_addr addrspace(2) constant [3 x i32] [i32 7, i32 8, i32 9]
+// CHECK: @k.var1 = internal addrspace(2) constant i32 1
kernel void k(void) {
// CHECK-NOT: %arr1 = alloca [3 x i32]
constant const int arr1[] = {1, 2, 3};
@@ -23,5 +24,8 @@ kernel void k(void) {
// CHECK: %arr3 = alloca [3 x i32]
int arr3[] = {7, 8, 9};
- foo(arr1, arr2, arr3);
+ constant int var1 = 1;
+
+ // CHECK: call spir_func void @foo(i32 addrspace(2)* @k.var1, i32 addrspace(2)* getelementptr inbounds ([3 x i32], [3 x i32] addrspace(2)* @k.arr1, i32 0, i32 0)
+ foo(&var1, arr1, arr2, arr3);
}
diff --git a/test/CodeGenOpenCL/convergent.cl b/test/CodeGenOpenCL/convergent.cl
index c6bcb52a6d..c46205bb9b 100644
--- a/test/CodeGenOpenCL/convergent.cl
+++ b/test/CodeGenOpenCL/convergent.cl
@@ -1,9 +1,19 @@
-// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm %s -o - | opt -instnamer -S | FileCheck %s
+// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm %s -o - | opt -instnamer -S | FileCheck -enable-var-scope %s
+
+// This is initially assumed convergent, but can be deduced to not require it.
+
+// CHECK-LABEL: define spir_func void @non_convfun() local_unnamed_addr #0
+// CHECK: ret void
+__attribute__((noinline))
+void non_convfun(void) {
+ volatile int* p;
+ *p = 0;
+}
void convfun(void) __attribute__((convergent));
-void non_convfun(void);
void nodupfun(void) __attribute__((noduplicate));
+// External functions should be assumed convergent.
void f(void);
void g(void);
@@ -17,19 +27,23 @@ void g(void);
// non_convfun();
// }
//
-// CHECK: define spir_func void @test_merge_if(i32 %[[a:.+]])
-// CHECK: %[[tobool:.+]] = icmp eq i32 %[[a]], 0
+// CHECK-LABEL: define spir_func void @test_merge_if(i32 %a) local_unnamed_addr #1 {
+// CHECK: %[[tobool:.+]] = icmp eq i32 %a, 0
// CHECK: br i1 %[[tobool]], label %[[if_end3_critedge:.+]], label %[[if_then:.+]]
+
// CHECK: [[if_then]]:
// CHECK: tail call spir_func void @f()
// CHECK: tail call spir_func void @non_convfun()
// CHECK: tail call spir_func void @g()
+
// CHECK: br label %[[if_end3:.+]]
+
// CHECK: [[if_end3_critedge]]:
// CHECK: tail call spir_func void @non_convfun()
// CHECK: br label %[[if_end3]]
+
// CHECK: [[if_end3]]:
-// CHECK-LABEL: ret void
+// CHECK: ret void
void test_merge_if(int a) {
if (a) {
@@ -41,13 +55,13 @@ void test_merge_if(int a) {
}
}
-// CHECK-DAG: declare spir_func void @f()
-// CHECK-DAG: declare spir_func void @non_convfun()
-// CHECK-DAG: declare spir_func void @g()
+// CHECK-DAG: declare spir_func void @f() local_unnamed_addr #2
+// CHECK-DAG: declare spir_func void @g() local_unnamed_addr #2
+
// Test two if's are not merged.
-// CHECK: define spir_func void @test_no_merge_if(i32 %[[a:.+]])
-// CHECK: %[[tobool:.+]] = icmp eq i32 %[[a]], 0
+// CHECK-LABEL: define spir_func void @test_no_merge_if(i32 %a) local_unnamed_addr #1
+// CHECK: %[[tobool:.+]] = icmp eq i32 %a, 0
// CHECK: br i1 %[[tobool]], label %[[if_end:.+]], label %[[if_then:.+]]
// CHECK: [[if_then]]:
// CHECK: tail call spir_func void @f()
@@ -56,7 +70,7 @@ void test_merge_if(int a) {
// CHECK: br label %[[if_end]]
// CHECK: [[if_end]]:
// CHECK: %[[tobool_pr:.+]] = phi i1 [ true, %[[if_then]] ], [ false, %{{.+}} ]
-// CHECK: tail call spir_func void @convfun() #[[attr5:.+]]
+// CHECK: tail call spir_func void @convfun() #[[attr4:.+]]
// CHECK: br i1 %[[tobool_pr]], label %[[if_then2:.+]], label %[[if_end3:.+]]
// CHECK: [[if_then2]]:
// CHECK: tail call spir_func void @g()
@@ -74,20 +88,20 @@ void test_no_merge_if(int a) {
}
}
-// CHECK: declare spir_func void @convfun(){{[^#]*}} #[[attr2:[0-9]+]]
+// CHECK: declare spir_func void @convfun(){{[^#]*}} #2
// Test loop is unrolled for convergent function.
-// CHECK-LABEL: define spir_func void @test_unroll()
-// CHECK: tail call spir_func void @convfun() #[[attr5:[0-9]+]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
-// CHECK: tail call spir_func void @convfun() #[[attr5]]
+// CHECK-LABEL: define spir_func void @test_unroll() local_unnamed_addr #1
+// CHECK: tail call spir_func void @convfun() #[[attr4:[0-9]+]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
+// CHECK: tail call spir_func void @convfun() #[[attr4]]
// CHECK-LABEL: ret void
void test_unroll() {
@@ -101,7 +115,7 @@ void test_unroll() {
// CHECK: [[for_cond_cleanup:.+]]:
// CHECK: ret void
// CHECK: [[for_body]]:
-// CHECK: tail call spir_func void @nodupfun() #[[attr6:[0-9]+]]
+// CHECK: tail call spir_func void @nodupfun() #[[attr5:[0-9]+]]
// CHECK-NOT: call spir_func void @nodupfun()
// CHECK: br i1 %{{.+}}, label %[[for_body]], label %[[for_cond_cleanup]]
@@ -112,7 +126,9 @@ void test_not_unroll() {
// CHECK: declare spir_func void @nodupfun(){{[^#]*}} #[[attr3:[0-9]+]]
-// CHECK-DAG: attributes #[[attr2]] = { {{[^}]*}}convergent{{[^}]*}} }
-// CHECK-DAG: attributes #[[attr3]] = { {{[^}]*}}noduplicate{{[^}]*}} }
-// CHECK-DAG: attributes #[[attr5]] = { {{[^}]*}}convergent{{[^}]*}} }
-// CHECK-DAG: attributes #[[attr6]] = { {{[^}]*}}noduplicate{{[^}]*}} }
+// CHECK: attributes #0 = { noinline norecurse nounwind "
+// CHECK: attributes #1 = { {{[^}]*}}convergent{{[^}]*}} }
+// CHECK: attributes #2 = { {{[^}]*}}convergent{{[^}]*}} }
+// CHECK: attributes #3 = { {{[^}]*}}convergent noduplicate{{[^}]*}} }
+// CHECK: attributes #4 = { {{[^}]*}}convergent{{[^}]*}} }
+// CHECK: attributes #5 = { {{[^}]*}}convergent noduplicate{{[^}]*}} }
diff --git a/test/CodeGenOpenCL/func-call-dbg-loc.cl b/test/CodeGenOpenCL/func-call-dbg-loc.cl
new file mode 100644
index 0000000000..4ed082fa9f
--- /dev/null
+++ b/test/CodeGenOpenCL/func-call-dbg-loc.cl
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple amdgcn---amdgizcl -debug-info-kind=limited -O0 -emit-llvm -o - %s | FileCheck %s
+
+typedef struct
+{
+ int a;
+} Struct;
+
+Struct func1();
+
+void func2(Struct S);
+
+void func3()
+{
+ // CHECK: call i32 @func1() #{{[0-9]+}}, !dbg ![[LOC:[0-9]+]]
+ // CHECK: call void @func2(i32 %{{[0-9]+}}) #{{[0-9]+}}, !dbg ![[LOC]]
+ func2(func1());
+}
+
diff --git a/test/CodeGenOpenCL/gfx9-fp32-denorms.cl b/test/CodeGenOpenCL/gfx9-fp32-denorms.cl
new file mode 100644
index 0000000000..ccb4c6ddcf
--- /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/half.cl b/test/CodeGenOpenCL/half.cl
index 9acabf0a2a..a10ba4d7f9 100644
--- a/test/CodeGenOpenCL/half.cl
+++ b/test/CodeGenOpenCL/half.cl
@@ -21,3 +21,20 @@ half test_inc(half x)
{
return ++x;
}
+
+__attribute__((overloadable)) int min(int, int);
+__attribute__((overloadable)) half min(half, half);
+__attribute__((overloadable)) float min(float, float);
+
+__kernel void foo( __global half* buf, __global float* buf2 )
+{
+ buf[0] = min( buf[0], 1.5h );
+// CHECK: half 0xH3E00
+ buf[0] = min( buf2[0], 1.5f );
+// CHECK: float 1.500000e+00
+
+ const half one = 1.6666;
+ buf[1] = min( buf[1], one );
+// CHECK: half 0xH3EAB
+}
+
diff --git a/test/CodeGenOpenCL/kernel-arg-info.cl b/test/CodeGenOpenCL/kernel-arg-info.cl
index 32017f85df..fa48ad28f7 100644
--- a/test/CodeGenOpenCL/kernel-arg-info.cl
+++ b/test/CodeGenOpenCL/kernel-arg-info.cl
@@ -1,9 +1,24 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s
// 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) {
- *X = Y + anotherArg;
+kernel void foo(global int * globalintp, global int * restrict globalintrestrictp,
+ global const int * globalconstintp,
+ global const int * restrict globalconstintrestrictp,
+ constant int * constantintp, constant int * restrict constantintrestrictp,
+ global const volatile int * globalconstvolatileintp,
+ global const volatile int * restrict globalconstvolatileintrestrictp,
+ global volatile int * globalvolatileintp,
+ global volatile int * restrict globalvolatileintrestrictp,
+ local int * localintp, local int * restrict localintrestrictp,
+ local const int * localconstintp,
+ local const int * restrict localconstintrestrictp,
+ local const volatile int * localconstvolatileintp,
+ local const volatile int * restrict localconstvolatileintrestrictp,
+ local volatile int * localvolatileintp,
+ local volatile int * restrict localvolatileintrestrictp,
+ int X, const int constint, const volatile int constvolatileint,
+ volatile int volatileint) {
+ *globalintrestrictp = constint + volatileint;
}
// CHECK: define spir_kernel void @foo{{[^!]+}}
// CHECK: !kernel_arg_addr_space ![[MD11:[0-9]+]]
@@ -60,11 +75,30 @@ 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"}
+typedef char char16 __attribute__((ext_vector_type(16)));
+__kernel void foo6(__global char16 arg[]) {}
+// CHECK: !kernel_arg_type ![[MD61:[0-9]+]]
+// ARGINFO: !kernel_arg_name ![[MD62:[0-9]+]]
+
+typedef read_only image1d_t ROImage;
+typedef write_only image1d_t WOImage;
+typedef read_write image1d_t RWImage;
+kernel void foo7(ROImage ro, WOImage wo, RWImage rw) {
+}
+// CHECK: define spir_kernel void @foo7{{[^!]+}}
+// CHECK: !kernel_arg_addr_space ![[MD71:[0-9]+]]
+// CHECK: !kernel_arg_access_qual ![[MD72:[0-9]+]]
+// CHECK: !kernel_arg_type ![[MD73:[0-9]+]]
+// CHECK: !kernel_arg_base_type ![[MD74:[0-9]+]]
+// CHECK: !kernel_arg_type_qual ![[MD75:[0-9]+]]
+// CHECK-NOT: !kernel_arg_name
+// ARGINFO: !kernel_arg_name ![[MD76:[0-9]+]]
+
+// CHECK: ![[MD11]] = !{i32 1, i32 1, i32 1, i32 1, i32 2, i32 2, i32 1, i32 1, i32 1, i32 1, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 0, i32 0, i32 0, i32 0}
+// CHECK: ![[MD12]] = !{!"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none", !"none"}
+// CHECK: ![[MD13]] = !{!"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int*", !"int", !"int", !"int", !"int"}
+// CHECK: ![[MD14]] = !{!"", !"restrict", !"const", !"restrict const", !"const", !"restrict const", !"const volatile", !"restrict const volatile", !"volatile", !"restrict volatile", !"", !"restrict", !"const", !"restrict const", !"const volatile", !"restrict const volatile", !"volatile", !"restrict volatile", !"", !"", !"", !""}
+// ARGINFO: ![[MD15]] = !{!"globalintp", !"globalintrestrictp", !"globalconstintp", !"globalconstintrestrictp", !"constantintp", !"constantintrestrictp", !"globalconstvolatileintp", !"globalconstvolatileintrestrictp", !"globalvolatileintp", !"globalvolatileintrestrictp", !"localintp", !"localintrestrictp", !"localconstintp", !"localconstintrestrictp", !"localconstvolatileintp", !"localconstvolatileintrestrictp", !"localvolatileintp", !"localvolatileintrestrictp", !"X", !"constint", !"constvolatileint", !"volatileint"}
// 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"}
@@ -85,4 +119,12 @@ kernel void foo5(myImage img1, write_only image1d_t img2) {
// CHECK: ![[MD52]] = !{!"myImage", !"image1d_t"}
// CHECK: ![[MD53]] = !{!"image1d_t", !"image1d_t"}
// ARGINFO: ![[MD54]] = !{!"img1", !"img2"}
+// CHECK: ![[MD61]] = !{!"char16*"}
+// ARGINFO: ![[MD62]] = !{!"arg"}
+// CHECK: ![[MD71]] = !{i32 1, i32 1, i32 1}
+// CHECK: ![[MD72]] = !{!"read_only", !"write_only", !"read_write"}
+// CHECK: ![[MD73]] = !{!"ROImage", !"WOImage", !"RWImage"}
+// CHECK: ![[MD74]] = !{!"image1d_t", !"image1d_t", !"image1d_t"}
+// CHECK: ![[MD75]] = !{!"", !"", !""}
+// ARGINFO: ![[MD76]] = !{!"ro", !"wo", !"rw"}
diff --git a/test/CodeGenOpenCL/kernel-attributes.cl b/test/CodeGenOpenCL/kernel-attributes.cl
index 4a116dd085..eff2e57d8c 100644
--- a/test/CodeGenOpenCL/kernel-attributes.cl
+++ b/test/CodeGenOpenCL/kernel-attributes.cl
@@ -3,12 +3,16 @@
typedef unsigned int uint4 __attribute__((ext_vector_type(4)));
kernel __attribute__((vec_type_hint(int))) __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
-// CHECK: define void @kernel1(i32 {{[^%]*}}%a) {{[^{]+}} !vec_type_hint ![[MD1:[0-9]+]] !reqd_work_group_size ![[MD2:[0-9]+]]
+// CHECK: define spir_kernel void @kernel1(i32 {{[^%]*}}%a) {{[^{]+}} !vec_type_hint ![[MD1:[0-9]+]] !reqd_work_group_size ![[MD2:[0-9]+]]
kernel __attribute__((vec_type_hint(uint4))) __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {}
-// CHECK: define void @kernel2(i32 {{[^%]*}}%a) {{[^{]+}} !vec_type_hint ![[MD3:[0-9]+]] !work_group_size_hint ![[MD4:[0-9]+]]
+// CHECK: define spir_kernel void @kernel2(i32 {{[^%]*}}%a) {{[^{]+}} !vec_type_hint ![[MD3:[0-9]+]] !work_group_size_hint ![[MD4:[0-9]+]]
+
+kernel __attribute__((intel_reqd_sub_group_size(8))) void kernel3(int a) {}
+// CHECK: define spir_kernel void @kernel3(i32 {{[^%]*}}%a) {{[^{]+}} !intel_reqd_sub_group_size ![[MD5:[0-9]+]]
// CHECK: [[MD1]] = !{i32 undef, i32 1}
// CHECK: [[MD2]] = !{i32 1, i32 2, i32 4}
// CHECK: [[MD3]] = !{<4 x i32> undef, i32 0}
// CHECK: [[MD4]] = !{i32 8, i32 16, i32 32}
+// CHECK: [[MD5]] = !{i32 8}
diff --git a/test/CodeGenOpenCL/kernel-metadata.cl b/test/CodeGenOpenCL/kernel-metadata.cl
index 4165f1fa0c..95be43015a 100644
--- a/test/CodeGenOpenCL/kernel-metadata.cl
+++ b/test/CodeGenOpenCL/kernel-metadata.cl
@@ -6,5 +6,5 @@ void normal_function() {
__kernel void kernel_function() {
}
-// CHECK: define void @kernel_function() {{[^{]+}} !kernel_arg_addr_space ![[MD:[0-9]+]] !kernel_arg_access_qual ![[MD]] !kernel_arg_type ![[MD]] !kernel_arg_base_type ![[MD]] !kernel_arg_type_qual ![[MD]] {
+// CHECK: define spir_kernel void @kernel_function() {{[^{]+}} !kernel_arg_addr_space ![[MD:[0-9]+]] !kernel_arg_access_qual ![[MD]] !kernel_arg_type ![[MD]] !kernel_arg_base_type ![[MD]] !kernel_arg_type_qual ![[MD]] {
// CHECK: ![[MD]] = !{}
diff --git a/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl b/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl
new file mode 100644
index 0000000000..5bb52e9beb
--- /dev/null
+++ b/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 %s -cl-std=CL1.2 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s
+// RUN: %clang_cc1 %s -cl-std=CL1.2 -emit-llvm -triple amdgcn-unknown-unknown -o - | FileCheck -check-prefixes=AMDGCN %s
+// Test that the kernels always use the SPIR calling convention
+// to have unambiguous mapping of arguments to feasibly implement
+// clSetKernelArg().
+
+typedef struct int_single {
+ int a;
+} int_single;
+
+typedef struct int_pair {
+ long a;
+ long b;
+} int_pair;
+
+typedef struct test_struct {
+ int elementA;
+ int elementB;
+ long elementC;
+ char elementD;
+ long elementE;
+ float elementF;
+ short elementG;
+ double elementH;
+} test_struct;
+
+kernel void test_single(int_single input, global int* output) {
+// CHECK: spir_kernel
+// AMDGCN: define amdgpu_kernel void @test_single
+// CHECK: struct.int_single* byval nocapture
+// CHECK: i32* nocapture %output
+ output[0] = input.a;
+}
+
+kernel void test_pair(int_pair input, global int* output) {
+// CHECK: spir_kernel
+// AMDGCN: define amdgpu_kernel void @test_pair
+// CHECK: struct.int_pair* byval nocapture
+// CHECK: i32* nocapture %output
+ output[0] = (int)input.a;
+ output[1] = (int)input.b;
+}
+
+kernel void test_kernel(test_struct input, global int* output) {
+// CHECK: spir_kernel
+// AMDGCN: define amdgpu_kernel void @test_kernel
+// CHECK: struct.test_struct* byval nocapture
+// CHECK: i32* nocapture %output
+ output[0] = input.elementA;
+ output[1] = input.elementB;
+ output[2] = (int)input.elementC;
+ output[3] = (int)input.elementD;
+ output[4] = (int)input.elementE;
+ output[5] = (int)input.elementF;
+ output[6] = (int)input.elementG;
+ output[7] = (int)input.elementH;
+};
+
+void test_function(int_pair input, global int* output) {
+// CHECK-NOT: spir_kernel
+// AMDGCN-NOT: define amdgpu_kernel void @test_function
+// CHECK: i64 %input.coerce0, i64 %input.coerce1, i32* nocapture %output
+ output[0] = (int)input.a;
+ output[1] = (int)input.b;
+}
diff --git a/test/CodeGenOpenCL/lifetime.cl b/test/CodeGenOpenCL/lifetime.cl
new file mode 100644
index 0000000000..430e0582ae
--- /dev/null
+++ b/test/CodeGenOpenCL/lifetime.cl
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple amdgcn---amdgizcl %s | FileCheck %s -check-prefix=AMDGIZ
+
+void use(char *a);
+
+__attribute__((always_inline)) void helper_no_markers() {
+ char a;
+ use(&a);
+}
+
+void lifetime_test() {
+// CHECK: @llvm.lifetime.start.p0i
+// AMDGIZ: @llvm.lifetime.start.p5i
+ helper_no_markers();
+}
diff --git a/test/CodeGenOpenCL/no-half.cl b/test/CodeGenOpenCL/no-half.cl
new file mode 100644
index 0000000000..aee8f678f0
--- /dev/null
+++ b/test/CodeGenOpenCL/no-half.cl
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 %s -cl-std=cl2.0 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s
+// RUN: %clang_cc1 %s -cl-std=cl1.2 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s
+// RUN: %clang_cc1 %s -cl-std=cl1.1 -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s
+
+#pragma OPENCL EXTENSION cl_khr_fp64:enable
+
+// CHECK-LABEL: @test_store_float(float %foo, half addrspace({{.}}){{.*}} %bar)
+__kernel void test_store_float(float foo, __global half* bar)
+{
+ __builtin_store_halff(foo, bar);
+// CHECK: [[HALF_VAL:%.*]] = fptrunc float %foo to half
+// CHECK: store half [[HALF_VAL]], half addrspace({{.}})* %bar, align 2
+}
+
+// CHECK-LABEL: @test_store_double(double %foo, half addrspace({{.}}){{.*}} %bar)
+__kernel void test_store_double(double foo, __global half* bar)
+{
+ __builtin_store_half(foo, bar);
+// CHECK: [[HALF_VAL:%.*]] = fptrunc double %foo to half
+// CHECK: store half [[HALF_VAL]], half addrspace({{.}})* %bar, align 2
+}
+
+// CHECK-LABEL: @test_load_float(float addrspace({{.}}){{.*}} %foo, half addrspace({{.}}){{.*}} %bar)
+__kernel void test_load_float(__global float* foo, __global half* bar)
+{
+ foo[0] = __builtin_load_halff(bar);
+// CHECK: [[HALF_VAL:%.*]] = load half, half addrspace({{.}})* %bar
+// CHECK: [[FULL_VAL:%.*]] = fpext half [[HALF_VAL]] to float
+// CHECK: store float [[FULL_VAL]], float addrspace({{.}})* %foo
+}
+
+// CHECK-LABEL: @test_load_double(double addrspace({{.}}){{.*}} %foo, half addrspace({{.}}){{.*}} %bar)
+__kernel void test_load_double(__global double* foo, __global half* bar)
+{
+ foo[0] = __builtin_load_half(bar);
+// CHECK: [[HALF_VAL:%.*]] = load half, half addrspace({{.}})* %bar
+// CHECK: [[FULL_VAL:%.*]] = fpext half [[HALF_VAL]] to double
+// CHECK: store double [[FULL_VAL]], double addrspace({{.}})* %foo
+}
diff --git a/test/CodeGenOpenCL/opencl_types.cl b/test/CodeGenOpenCL/opencl_types.cl
index 73c57b7309..3501f9fd34 100644
--- a/test/CodeGenOpenCL/opencl_types.cl
+++ b/test/CodeGenOpenCL/opencl_types.cl
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple "spir-unknown-unknown" -emit-llvm -o - -O0 | FileCheck %s --check-prefix=CHECK-SPIR
-// RUN: %clang_cc1 %s -triple "amdgcn--amdhsa" -emit-llvm -o - -O0 | FileCheck %s --check-prefix=CHECK-AMDGCN
+// RUN: %clang_cc1 -cl-std=CL2.0 %s -triple "spir-unknown-unknown" -emit-llvm -o - -O0 | FileCheck %s --check-prefixes=CHECK-COM,CHECK-SPIR
+// RUN: %clang_cc1 -cl-std=CL2.0 %s -triple "amdgcn--amdhsa" -emit-llvm -o - -O0 | FileCheck %s --check-prefixes=CHECK-COM,CHECK-AMDGCN
#define CLK_ADDRESS_CLAMP_TO_EDGE 2
#define CLK_NORMALIZED_COORDS_TRUE 1
@@ -7,7 +7,7 @@
#define CLK_FILTER_LINEAR 0x20
constant sampler_t glb_smp = CLK_ADDRESS_CLAMP_TO_EDGE|CLK_NORMALIZED_COORDS_TRUE|CLK_FILTER_NEAREST;
-// CHECK-SPIR-NOT: constant i32
+// CHECK-COM-NOT: constant i32
void fnc1(image1d_t img) {}
// CHECK-SPIR: @fnc1(%opencl.image1d_ro_t addrspace(1)*
@@ -39,16 +39,29 @@ void fnc4smp(sampler_t s) {}
kernel void foo(image1d_t img) {
sampler_t smp = CLK_ADDRESS_CLAMP_TO_EDGE|CLK_NORMALIZED_COORDS_TRUE|CLK_FILTER_LINEAR;
- // CHECK-SPIR: alloca %opencl.sampler_t addrspace(2)*
+ // CHECK-COM: alloca %opencl.sampler_t addrspace(2)*
event_t evt;
- // CHECK-SPIR: alloca %opencl.event_t*
- // CHECK-SPIR: store %opencl.sampler_t addrspace(2)*
+ // CHECK-COM: alloca %opencl.event_t*
+ clk_event_t clk_evt;
+ // CHECK-SPIR: alloca %opencl.clk_event_t*
+ // CHECK-AMDGCN: alloca %opencl.clk_event_t addrspace(1)*
+ queue_t queue;
+ // CHECK-SPIR: alloca %opencl.queue_t*
+ // CHECK-AMDGCN: alloca %opencl.queue_t addrspace(1)*
+ reserve_id_t rid;
+ // CHECK-SPIR: alloca %opencl.reserve_id_t*
+ // CHECK-AMDGCN: alloca %opencl.reserve_id_t addrspace(1)*
+ // CHECK-COM: store %opencl.sampler_t addrspace(2)*
fnc4smp(smp);
- // CHECK-SPIR: call {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
+ // CHECK-COM: call {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
fnc4smp(glb_smp);
- // CHECK-SPIR: call {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
+ // CHECK-COM: call {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
}
+kernel void foo_pipe(read_only pipe int p) {}
+// CHECK-SPIR: @foo_pipe(%opencl.pipe_t addrspace(1)* %p)
+// CHECK_AMDGCN: @foo_pipe(%opencl.pipe_t addrspace(1)* %p)
+
void __attribute__((overloadable)) bad1(image1d_t b, image2d_t c, image2d_t d) {}
// CHECK-SPIR-LABEL: @{{_Z4bad114ocl_image1d_ro14ocl_image2d_roS0_|"\\01\?bad1@@\$\$J0YAXPAUocl_image1d_ro@@PAUocl_image2d_ro@@1@Z"}}
// CHECK-AMDGCN-LABEL: @{{_Z4bad114ocl_image1d_ro14ocl_image2d_roS0_|"\\01\?bad1@@\$\$J0YAXPAUocl_image1d_ro@@PAUocl_image2d_ro@@1@Z"}}(%opencl.image1d_ro_t addrspace(2)*{{.*}}%opencl.image2d_ro_t addrspace(2)*{{.*}}%opencl.image2d_ro_t addrspace(2)*{{.*}})
diff --git a/test/CodeGenOpenCL/overload.cl b/test/CodeGenOpenCL/overload.cl
new file mode 100644
index 0000000000..f182cb5fd2
--- /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/pipe_builtin.cl b/test/CodeGenOpenCL/pipe_builtin.cl
index a9b4ab630c..4b4b4ef97a 100644
--- a/test/CodeGenOpenCL/pipe_builtin.cl
+++ b/test/CodeGenOpenCL/pipe_builtin.cl
@@ -1,8 +1,10 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
// CHECK: %opencl.pipe_t = type opaque
// CHECK: %opencl.reserve_id_t = type opaque
+#pragma OPENCL EXTENSION cl_khr_subgroups : enable
+
void test1(read_only pipe int p, global int *ptr) {
// CHECK: call i32 @__read_pipe_2(%opencl.pipe_t* %{{.*}}, i8* %{{.*}}, i32 4, i32 4)
read_pipe(p, ptr);
diff --git a/test/CodeGenOpenCL/pipe_types.cl b/test/CodeGenOpenCL/pipe_types.cl
index f5b42e2a49..7c11f74ad7 100644
--- a/test/CodeGenOpenCL/pipe_types.cl
+++ b/test/CodeGenOpenCL/pipe_types.cl
@@ -28,7 +28,7 @@ void test5(read_only pipe int4 p) {
typedef read_only pipe int MyPipe;
kernel void test6(MyPipe p) {
-// CHECK: define void @test6(%opencl.pipe_t* %p)
+// CHECK: define spir_kernel void @test6(%opencl.pipe_t* %p)
}
struct Person {
diff --git a/test/CodeGenOpenCL/preserve_vec3.cl b/test/CodeGenOpenCL/preserve_vec3.cl
new file mode 100644
index 0000000000..6efbbb3d53
--- /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/ptx-calls.cl b/test/CodeGenOpenCL/ptx-calls.cl
index bde00bc3d7..2a3400371e 100644
--- a/test/CodeGenOpenCL/ptx-calls.cl
+++ b/test/CodeGenOpenCL/ptx-calls.cl
@@ -7,7 +7,7 @@ void device_function() {
__kernel void kernel_function() {
device_function();
}
-// CHECK-LABEL: define void @kernel_function()
+// CHECK-LABEL: define spir_kernel void @kernel_function()
// CHECK: call void @device_function()
// CHECK: !{{[0-9]+}} = !{void ()* @kernel_function, !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/ptx-kernels.cl b/test/CodeGenOpenCL/ptx-kernels.cl
index fc6de4f3d5..b9e1c224c7 100644
--- a/test/CodeGenOpenCL/ptx-kernels.cl
+++ b/test/CodeGenOpenCL/ptx-kernels.cl
@@ -6,6 +6,6 @@ void device_function() {
__kernel void kernel_function() {
}
-// CHECK-LABEL: define void @kernel_function()
+// CHECK-LABEL: define spir_kernel void @kernel_function()
// CHECK: !{{[0-9]+}} = !{void ()* @kernel_function, !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/relaxed-fpmath.cl b/test/CodeGenOpenCL/relaxed-fpmath.cl
index 6f302b1335..7676ee164c 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 6fc8c2c684..3a7319cd78 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/size_t.cl b/test/CodeGenOpenCL/size_t.cl
index ed941e0185..02950bb662 100644
--- a/test/CodeGenOpenCL/size_t.cl
+++ b/test/CodeGenOpenCL/size_t.cl
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple spir-unknown-unknown -o - | FileCheck --check-prefix=SZ32 %s
// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple spir64-unknown-unknown -o - | FileCheck --check-prefix=SZ64 --check-prefix=SZ64ONLY %s
-// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple amdgcn-- -o - | FileCheck --check-prefix=SZ64 --check-prefix=AMDONLY %s
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple amdgcn -o - | FileCheck --check-prefix=SZ64 --check-prefix=AMDONLY %s
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple amdgcn---opencl -o - | FileCheck --check-prefix=SZ64 --check-prefix=AMDONLY %s
//SZ32: define{{.*}} i32 @test_ptrtoint_private(i8* %x)
//SZ32: ptrtoint i8* %{{.*}} to i32
diff --git a/test/CodeGenOpenCL/spir_version.cl b/test/CodeGenOpenCL/spir_version.cl
index 8a191282b3..ac5b8e8c7f 100644
--- a/test/CodeGenOpenCL/spir_version.cl
+++ b/test/CodeGenOpenCL/spir_version.cl
@@ -10,17 +10,18 @@
// RUN: %clang_cc1 %s -triple "amdgcn--amdhsa" -emit-llvm -o - -cl-std=CL2.0 | FileCheck %s --check-prefix=CHECK-AMDGCN-CL20
kernel void foo() {}
+kernel void bar() {}
-// CHECK-SPIR-CL10: !opencl.spir.version = !{[[SPIR:![0-9]+]]}
-// CHECK-SPIR-CL10: !opencl.ocl.version = !{[[OCL:![0-9]+]]}
-// CHECK-SPIR-CL10: [[SPIR]] = !{i32 1, i32 2}
-// CHECK-SPIR-CL10: [[OCL]] = !{i32 1, i32 0}
-// CHECK-SPIR-CL12: !opencl.spir.version = !{[[VER:![0-9]+]]}
-// CHECK-SPIR-CL12: !opencl.ocl.version = !{[[VER]]}
+// CHECK-SPIR-CL10-DAG: !opencl.spir.version = !{[[SPIR:![0-9]+]]}
+// CHECK-SPIR-CL10-DAG: !opencl.ocl.version = !{[[OCL:![0-9]+]]}
+// CHECK-SPIR-CL10-DAG: [[SPIR]] = !{i32 1, i32 2}
+// CHECK-SPIR-CL10-DAG: [[OCL]] = !{i32 1, i32 0}
+// CHECK-SPIR-CL12-DAG: !opencl.spir.version = !{[[VER:![0-9]+]]}
+// CHECK-SPIR-CL12-DAG: !opencl.ocl.version = !{[[VER]]}
// CHECK-SPIR-CL12: [[VER]] = !{i32 1, i32 2}
-// CHECK-SPIR-CL20: !opencl.spir.version = !{[[VER:![0-9]+]]}
-// CHECK-SPIR-CL20: !opencl.ocl.version = !{[[VER]]}
+// CHECK-SPIR-CL20-DAG: !opencl.spir.version = !{[[VER:![0-9]+]]}
+// CHECK-SPIR-CL20-DAG: !opencl.ocl.version = !{[[VER]]}
// CHECK-SPIR-CL20: [[VER]] = !{i32 2, i32 0}
// CHECK-AMDGCN-CL10-NOT: !opencl.spir.version
diff --git a/test/CodeGenOpenCL/vectorLoadStore.cl b/test/CodeGenOpenCL/vectorLoadStore.cl
index 44bc7bd25d..cb35e6f468 100644
--- a/test/CodeGenOpenCL/vectorLoadStore.cl
+++ b/test/CodeGenOpenCL/vectorLoadStore.cl
@@ -1,9 +1,22 @@
-// RUN: %clang_cc1 %s -emit-llvm -O0 -o - | FileCheck %s
+// RUN: %clang_cc1 -cl-std=CL2.0 -triple "spir-unknown-unknown" %s -emit-llvm -O0 -o - | FileCheck %s
-typedef char char3 __attribute((ext_vector_type(3)));;
+typedef char char2 __attribute((ext_vector_type(2)));
+typedef char char3 __attribute((ext_vector_type(3)));
+typedef char char8 __attribute((ext_vector_type(8)));
+typedef float float4 __attribute((ext_vector_type(4)));
// Check for optimized vec3 load/store which treats vec3 as vec4.
void foo(char3 *P, char3 *Q) {
*P = *Q;
// CHECK: %{{.*}} = shufflevector <4 x i8> %{{.*}}, <4 x i8> undef, <3 x i32> <i32 0, i32 1, i32 2>
}
+
+// CHECK: define spir_func void @alignment()
+void alignment() {
+ __private char2 data_generic[100];
+ __private char8 data_private[100];
+
+ // CHECK: %{{.*}} = load <4 x float>, <4 x float> addrspace(4)* %{{.*}}, align 2
+ // CHECK: store <4 x float> %{{.*}}, <4 x float>* %{{.*}}, align 8
+ ((private float4 *)data_private)[1] = ((float4 *)data_generic)[2];
+}
diff --git a/test/CodeGenOpenCL/vla.cl b/test/CodeGenOpenCL/vla.cl
index cbf98445ce..5d3599fc3c 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/Coverage/ast-printing.c b/test/Coverage/ast-printing.c
index eb22f92e66..dfda6c676f 100644
--- a/test/Coverage/ast-printing.c
+++ b/test/Coverage/ast-printing.c
@@ -3,6 +3,7 @@
// RUN: %clang_cc1 -ast-print %t.1.c -o %t.2.c
// RUN: diff %t.1.c %t.2.c
// RUN: %clang_cc1 -ast-dump %s
+// RUN: %clang_cc1 -ast-dump-all %s
// RUN: %clang_cc1 -print-decl-contexts %s
#include "c-language-features.inc"
diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp
index e03c517353..bcd78be7d0 100644
--- a/test/Coverage/ast-printing.cpp
+++ b/test/Coverage/ast-printing.cpp
@@ -3,6 +3,7 @@
// RUN: %clang_cc1 -std=c++14 -ast-print %t.1.cpp -o %t.2.cpp
// RUN: diff %t.1.cpp %t.2.cpp
// RUN: %clang_cc1 -std=c++14 -ast-dump %s
+// RUN: %clang_cc1 -std=c++14 -ast-dump-all %s
// RUN: %clang_cc1 -std=c++14 -print-decl-contexts %s
// RUN: %clang_cc1 -std=c++14 -fdump-record-layouts %s
diff --git a/test/Coverage/html-diagnostics.c b/test/Coverage/html-diagnostics.c
index 045943ae8b..34b86cd982 100644
--- a/test/Coverage/html-diagnostics.c
+++ b/test/Coverage/html-diagnostics.c
@@ -1,11 +1,18 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t %s
// RUN: find %t -name "*.html" -exec cat "{}" ";" | FileCheck %s
+//
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -analyze -analyzer-output=html-single-file -analyzer-checker=core -o %t %s
+// RUN: find %t -name "*.html" -exec cat "{}" ";" | FileCheck %s
// REQUIRES: staticanalyzer
// CHECK: <h3>Annotated Source Code</h3>
+// Make sure it's not generated as a multi-file HTML output
+// CHECK-NOT: <h4 class=FileName>{{.*}}
+
// Without tweaking expr, the expr would hit to the line below
// emitted to the output as comment.
// CHECK: {{[D]ereference of null pointer}}
diff --git a/test/Coverage/html-multifile-diagnostics.c b/test/Coverage/html-multifile-diagnostics.c
new file mode 100644
index 0000000000..abd54ae839
--- /dev/null
+++ b/test/Coverage/html-multifile-diagnostics.c
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t %s
+// RUN: find %t -name "*.html" -exec cat "{}" ";" | FileCheck %s
+
+// REQUIRES: staticanalyzer
+
+// CHECK: <h3>Annotated Source Code</h3>
+
+// Make sure it's generated as multi-file HTML output
+// CHECK: <h4 class=FileName>{{.*}}html-multifile-diagnostics.c</h4>
+// CHECK: <h4 class=FileName>{{.*}}html-multifile-diagnostics.h</h4>
+
+// Without tweaking expr, the expr would hit to the line below
+// emitted to the output as comment.
+// CHECK: {{[D]ereference of null pointer}}
+
+#include "html-multifile-diagnostics.h"
+
+void f0() {
+ f1((int*)0);
+}
diff --git a/test/Coverage/html-multifile-diagnostics.h b/test/Coverage/html-multifile-diagnostics.h
new file mode 100644
index 0000000000..4a99ff0df9
--- /dev/null
+++ b/test/Coverage/html-multifile-diagnostics.h
@@ -0,0 +1,3 @@
+void f1(int *ptr) {
+ *ptr = 0;
+}
diff --git a/test/CoverageMapping/abspath.cpp b/test/CoverageMapping/abspath.cpp
index 667172e32c..4b92a3773d 100644
--- a/test/CoverageMapping/abspath.cpp
+++ b/test/CoverageMapping/abspath.cpp
@@ -4,7 +4,7 @@
// RMDOTS-NOT: Inputs
// RMDOTS: "
-// RUN: cd %T && mkdir -p test && cd test
+// RUN: mkdir -p %t/test && cd %t/test
// RUN: echo "void f1() {}" > f1.c
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -main-file-name abspath.cpp ../test/f1.c -o - | FileCheck -check-prefix=RELPATH %s
diff --git a/test/CoverageMapping/deferred-region.cpp b/test/CoverageMapping/deferred-region.cpp
new file mode 100644
index 0000000000..3504588a6c
--- /dev/null
+++ b/test/CoverageMapping/deferred-region.cpp
@@ -0,0 +1,193 @@
+// RUN: %clang_cc1 -std=c++11 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -fexceptions -fcxx-exceptions -emit-llvm-only -triple %itanium_abi_triple -main-file-name deferred-region.cpp %s | FileCheck %s
+
+#define IF if
+#define STMT(S) S
+
+// CHECK-LABEL: _Z3fooi:
+void foo(int x) {
+ if (x == 0) {
+ return;
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:2 = (#0 - #1)
+
+}
+
+// CHECK-NEXT: _Z4foooi:
+void fooo(int x) {
+ if (x == 0) {
+ return;
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ if (x == 1) {
+ return;
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:2 = ((#0 - #1) - #2)
+
+}
+
+// CHECK-LABEL: _Z3bazv:
+void baz() { // CHECK: [[@LINE]]:12 -> [[@LINE+2]]:2
+ return; // CHECK-NOT: File
+}
+
+// CHECK-LABEL: _Z3mazv:
+void maz() {
+ if (true)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ return; // CHECK-NOT: Gap
+}
+
+// CHECK-LABEL: _Z4maazv:
+void maaz() {
+ if (true)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11
+ else
+ return; // CHECK-NOT: Gap,File 0, [[@LINE]]
+}
+
+// CHECK-LABEL: _Z5maaazv:
+void maaaz() {
+ if (true) {
+ return;
+ } else { // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE]]:10
+ return; // CHECK-NOT: Gap,File 0, [[@LINE]]
+ }
+}
+
+// CHECK-LABEL: _Z3bari:
+void bar(int x) {
+ IF (x)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ IF (!x)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = ((#0 - #1) - #2)
+
+ foo(x);
+}
+
+// CHECK-LABEL: _Z4quuxi:
+// Deferred regions are not emitted within macro expansions.
+void quux(int x) {
+ STMT(
+ if (x == 0)
+ return;)
+
+ // CHECK-NOT: [[@LINE-2]]:{{.*}} -> [[@LINE+2]]
+
+ if (x == 1)
+ STMT(return;)
+
+ // CHECK-NOT: [[@LINE-2]]:{{.*}} -> [[@LINE+3]]
+
+ STMT(
+ if (x == 2)
+ return;
+
+ // CHECK-NOT: [[@LINE-2]]:{{.*}} -> [[@LINE+2]]
+
+ if (x == 3)
+ return;
+ )
+}
+
+// CHECK-LABEL: _Z8weird_ifv:
+void weird_if() {
+ int i = 0;
+
+ if (false)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ if (false)
+ i++;
+
+ if (i + 100 > 0) { // CHECK: [[@LINE]]:20 -> [[@LINE+6]]:4 = #3
+ if (false) // CHECK: [[@LINE+1]]:7 -> [[@LINE+1]]:13 = #4
+ return; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+2]]:5 = (#3 - #4)
+ // CHECK: [[@LINE+1]]:5 -> [[@LINE+3]]:4 = (#3 - #4)
+ return; // CHECK: Gap,File 0, [[@LINE]]:5 -> [[@LINE+4]]:3 = ((#0 - #1) - #3)
+
+ }
+
+ if (false)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:2
+}
+
+// CHECK-LABEL: _Z8for_loopv:
+void for_loop() {
+ if (false)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ for (int i = 0; i < 10; ++i) {
+ if (i % 2 == 0)
+ continue; // CHECK: Gap,File 0, [[@LINE]]:15 -> [[@LINE+2]]:5 = (#2 - #3)
+
+ if (i % 5 == 0)
+ break; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:5 = ((#2 - #3) - #4)
+
+ int x = i; // CHECK: [[@LINE]]:5 -> [[@LINE+3]]:4 = ((#2 - #3) - #4)
+ return; // CHECK-NOT: [[@LINE]]:11 -> [[@LINE+2]]
+
+ }
+}
+
+struct Error {};
+
+// CHECK-LABEL: _Z10while_loopv:
+void while_loop() {
+ if (false)
+ return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ int x = 0;
+ while (++x < 10) {
+ if (x == 1)
+ continue; // CHECK: Gap,File 0, [[@LINE]]:15 -> [[@LINE+2]]:5 = (#2 - #3)
+
+ while (++x < 4) {
+ if (x == 3)
+ break; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+2]]:7 = (#4 - #5)
+
+ while (++x < 5) {}
+ }
+
+ if (x == 0)
+ throw Error(); // CHECK: Gap,File 0, [[@LINE]]:20 -> [[@LINE+2]]:5 = ((#2 - #3) - #7)
+
+ while (++x < 9) {
+ if (x == 0)
+ break; // CHECK-NOT: [[@LINE]]:14 -> [[@LINE+2]]
+
+ }
+ }
+}
+
+// CHECK-LABEL: _Z5gotosv:
+void gotos() {
+ if (false)
+ goto out; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ return; // CHECK: [[@LINE]]:3 -> [[@LINE+4]]:2 = (#0 - #1)
+
+out:
+ return; // CHECK: Gap,File 0, [[@LINE]]:8 -> [[@LINE+1]]:2 = 0
+}
+
+int main() {
+ foo(0);
+ foo(1);
+ fooo(0);
+ fooo(1);
+ maz();
+ maaz();
+ maaaz();
+ baz();
+ bar(0);
+ bar(1);
+ quux(0);
+ quux(1);
+ quux(2);
+ quux(3);
+ weird_if();
+ for_loop();
+ while_loop();
+ gotos();
+ return 0;
+}
diff --git a/test/CoverageMapping/empty-destructor.cpp b/test/CoverageMapping/empty-destructor.cpp
new file mode 100644
index 0000000000..cfc29a75c6
--- /dev/null
+++ b/test/CoverageMapping/empty-destructor.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple i686-windows -emit-llvm-only -fcoverage-mapping -dump-coverage-mapping -fprofile-instrument=clang %s | FileCheck %s
+
+struct A {
+ virtual ~A();
+};
+
+// CHECK: ?PR32761@@YAXXZ:
+// CHECK-NEXT: File 0, [[@LINE+1]]:16 -> [[@LINE+3]]:2 = #0
+void PR32761() {
+ A a;
+}
diff --git a/test/CoverageMapping/header.cpp b/test/CoverageMapping/header.cpp
index 5e0b3111c1..d42c154446 100644
--- a/test/CoverageMapping/header.cpp
+++ b/test/CoverageMapping/header.cpp
@@ -2,6 +2,9 @@
// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-FUNC
// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-STATIC-FUNC
// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-STATIC-FUNC2
+//
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -mllvm -limited-coverage-experimental=true -dump-coverage-mapping -emit-llvm-only -main-file-name header.cpp %s > %tmapping.limited
+// RUN: FileCheck -input-file %tmapping.limited %s --check-prefix=CHECK-LIMITED
#include "Inputs/header1.h"
@@ -22,3 +25,5 @@ int main() {
// CHECK-STATIC-FUNC2: static_func2
// CHECK-STATIC-FUNC2: File 0, 21:33 -> 29:2 = 0
+
+// CHECK-LIMITED-NOT: static_func2
diff --git a/test/CoverageMapping/label.cpp b/test/CoverageMapping/label.cpp
index 1c5111a675..aec5e4f7eb 100644
--- a/test/CoverageMapping/label.cpp
+++ b/test/CoverageMapping/label.cpp
@@ -14,19 +14,22 @@ void func() { // CHECK-NEXT: File 0, [[@LINE]]:13 -> {{[0-9]+}}:2
int m = 2;
} else
goto x; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = (#1 - #2)
- int k = 3; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = #3
- }
- static int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+4]]:2 = ((#0 + #3) - #1)
+ int k = 3; // CHECK-NEXT: File 0, [[@LINE-1]]:13 -> [[@LINE]]:5 = #3
+ } // CHECK-NEXT: File 0, [[@LINE-1]]:5 -> [[@LINE]]:4 = #3
+ static int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+5]]:2 = ((#0 + #3) - #1)
++j;
if(j == 1) // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:12 = ((#0 + #3) - #1)
goto x; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #4
+ // CHECK-NEXT: File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:2 = (((#0 + #3) - #1) - #4)
}
// CHECK-NEXT: test1
void test1(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> {{[0-9]+}}:2 = #0
if(x == 0) // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:12 = #0
goto a; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #1
- goto b; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:9 = (#0 - #1)
+ // CHECK-NEXT: File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = (#0 - #1)
+ goto b; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+5]]:2 = (#0 - #1)
+ // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE+4]]:2 = #3
a: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+3]]:2 = #2
b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+2]]:2 = #3
x = x + 1;
@@ -36,9 +39,11 @@ b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+2]]:2
void test2(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> {{[0-9]+}}:2 = #0
if(x == 0) // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:12 = #0
goto a; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #1
- // CHECK-NEXT: File 0, [[@LINE+2]]:8 -> [[@LINE+2]]:25 = (#0 - #1)
+ // CHECK-NEXT: File 0, [[@LINE-1]]:11 -> [[@LINE+3]]:8 = #0
+ // CHECK-NEXT: File 0, [[@LINE+2]]:8 -> [[@LINE+3]]:11 = (#0 - #1)
// CHECK-NEXT: File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:17 = (#0 - #1)
- else if(x == 1) goto b; // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE]]:25 = #2
+ else if(x == 1) // CHECK-NEXT: File 0, [[@LINE+1]]:5 -> [[@LINE+1]]:11 = #2
+ goto b; // CHECK-NEXT: File 0, [[@LINE]]:11 -> [[@LINE+1]]:1 = #3
a: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+3]]:2 = #3
b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+2]]:2 = #4
x = x + 1;
@@ -47,11 +52,13 @@ b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+2]]:2
// CHECK-NEXT: main
int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> {{[0-9]+}}:2 = #0
int j = 0;
- for(int i = 0; i < 10; ++i) { // CHECK: File 0, [[@LINE]]:31 -> [[@LINE+11]]:4 = #1
- a: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+10]]:4 = #2
+ for(int i = 0; i < 10; ++i) { // CHECK: File 0, [[@LINE]]:31 -> [[@LINE+13]]:4 = #1
+ a: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+12]]:4 = #2
if(i < 3) // CHECK-NEXT: File 0, [[@LINE]]:8 -> [[@LINE]]:13 = #2
goto e; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #3
- goto c; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = (#2 - #3)
+ // CHECK-NEXT: File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = (#2 - #3)
+ goto c; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+8]]:4 = (#2 - #3)
+
b: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+6]]:4 = #4
j = 2;
c: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+4]]:4 = #5
diff --git a/test/CoverageMapping/logical.cpp b/test/CoverageMapping/logical.cpp
index 198cc60d99..bc7c785b7b 100644
--- a/test/CoverageMapping/logical.cpp
+++ b/test/CoverageMapping/logical.cpp
@@ -1,13 +1,18 @@
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name logical.cpp %s | FileCheck %s
-int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+10]]:2 = #0
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+15]]:2 = #0
bool bt = true;
bool bf = false;
- bool a = bt && bf; // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE]]:20 = #1
- a = bt &&
+ bool a = bt && bf; // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE]]:14 = #0
+ // CHECK-NEXT: File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:20 = #1
+
+ a = bt && // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
bf; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #2
- a = bf || bt; // CHECK-NEXT: File 0, [[@LINE]]:13 -> [[@LINE]]:15 = #3
- a = bf ||
+
+ a = bf || bt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
+ // CHECK-NEXT: File 0, [[@LINE-1]]:13 -> [[@LINE-1]]:15 = #3
+
+ a = bf || // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
bt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #4
return 0;
}
diff --git a/test/CoverageMapping/macro-expansion.c b/test/CoverageMapping/macro-expansion.c
index 3fca97584a..4e52558086 100644
--- a/test/CoverageMapping/macro-expansion.c
+++ b/test/CoverageMapping/macro-expansion.c
@@ -23,10 +23,12 @@
// CHECK-NEXT: Expansion,File 4, [[@LINE+2]]:20 -> [[@LINE+2]]:22 = (#0 + #8)
// CHECK-NEXT: File 4, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = (#0 + #8)
#define M3(x) do { M2(x); } while (0)
-// CHECK-NEXT: File 5, [[@LINE+2]]:15 -> [[@LINE+2]]:27 = #0
+// CHECK-NEXT: File 5, [[@LINE+3]]:15 -> [[@LINE+3]]:27 = #0
+// CHECK-NEXT: File 5, [[@LINE+2]]:16 -> [[@LINE+2]]:19 = #0
// CHECK-NEXT: File 5, [[@LINE+1]]:23 -> [[@LINE+1]]:26 = #12
#define M4(x) ((x) && (x))
-// CHECK-NEXT: File 6, [[@LINE+2]]:15 -> [[@LINE+2]]:27 = #0
+// CHECK-NEXT: File 6, [[@LINE+3]]:15 -> [[@LINE+3]]:27 = #0
+// CHECK-NEXT: File 6, [[@LINE+2]]:16 -> [[@LINE+2]]:19 = #0
// CHECK-NEXT: File 6, [[@LINE+1]]:23 -> [[@LINE+1]]:26 = #14
#define M5(x) ((x) || (x))
// CHECK-NEXT: File 7, [[@LINE+1]]:15 -> [[@LINE+1]]:26 = #0
diff --git a/test/CoverageMapping/md.cpp b/test/CoverageMapping/md.cpp
index 20c696c7df..5f2b2d6122 100644
--- a/test/CoverageMapping/md.cpp
+++ b/test/CoverageMapping/md.cpp
@@ -27,6 +27,17 @@ void foo(MD i) {
#include "Inputs/md.def"
}
+// CHECK: bar
+// CHECK-NEXT: File 0, [[@LINE+3]]:12 -> [[@LINE+8]]:2 = #0
+bool isVal1();
+bool isVal2();
+bool bar() {
+ #define HANDLE_MD(X) is##X() ||
+ return
+#include "Inputs/md.def"
+ 0;
+}
+
int main(int argc, const char *argv[]) {
foo(MD::Val1);
return 0;
diff --git a/test/CoverageMapping/moremacros.c b/test/CoverageMapping/moremacros.c
index 56662270d0..630b75d855 100644
--- a/test/CoverageMapping/moremacros.c
+++ b/test/CoverageMapping/moremacros.c
@@ -15,7 +15,7 @@ int main(int argc, const char *argv[]) {
if (!argc) LBRAC
return 0;
// CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = #2
- RBRAC
+ RBRAC // CHECK-NEXT: [[@LINE]]:8 -> [[@LINE+6]]:3 = (#0 - #2)
// CHECK-NEXT: File 0, [[@LINE+4]]:3 -> [[@LINE+15]]:2 = (#0 - #2)
// CHECK-NEXT: File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:12 = (#0 - #2)
@@ -23,7 +23,7 @@ int main(int argc, const char *argv[]) {
// CHECK-NEXT: File 0, [[@LINE+1]]:19 -> [[@LINE+3]]:4 = #3
if (!argc) LBRAC
return 0;
- }
+ } // CHECK-NEXT: [[@LINE]]:4 -> [[@LINE+5]]:3 = ((#0 - #2) - #3)
// CHECK-NEXT: File 0, [[@LINE+3]]:3 -> [[@LINE+7]]:2 = ((#0 - #2) - #3)
// CHECK-NEXT: File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:12 = ((#0 - #2) - #3)
@@ -31,7 +31,7 @@ int main(int argc, const char *argv[]) {
if (!argc) {
return 0;
// CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = #4
- RBRAC
+ RBRAC // CHECK-NEXT: [[@LINE]]:8 -> [[@LINE+1]]:2 = (((#0 - #2) - #3) - #4)
}
// CHECK-NEXT: File 1, 3:15 -> 3:16 = #2
diff --git a/test/CoverageMapping/pr32679.cpp b/test/CoverageMapping/pr32679.cpp
new file mode 100644
index 0000000000..eac3afb6ef
--- /dev/null
+++ b/test/CoverageMapping/pr32679.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -cc1 -triple i686-pc-windows-msvc19.0.0 -emit-obj -fprofile-instrument=clang -std=c++14 -fdelayed-template-parsing -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name pr32679.cpp -o - %s | FileCheck %s -check-prefix=MSABI -implicit-check-not=f2
+// RUN: %clang_cc1 -cc1 -triple %itanium_abi_triple -emit-obj -fprofile-instrument=clang -std=c++14 -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name pr32679.cpp -o - %s | FileCheck %s -check-prefix=ITANIUM -implicit-check-not=f2
+
+template <typename T, int S1>
+struct CreateSpecialization;
+
+template <typename T>
+struct CreateSpecialization<T, 0> {
+ static constexpr T f1() { return 0; }
+ static constexpr T f2() { return 0; }
+};
+
+int main() {
+ CreateSpecialization<int, 0>::f1();
+
+ // Don't emit coverage mapping info for functions in dependent contexts.
+ //
+ // E.g we never fully instantiate CreateSpecialization<T, 0>::f2(), so there
+ // should be no mapping for it.
+
+ return 0;
+}
+
+// MSABI: main:
+// MSABI-NEXT: File 0, [[@LINE-12]]:12 -> [[@LINE-3]]:2 = #0
+// MSABI-NEXT: ?f1@?$CreateSpecialization@H$0A@@@SAHXZ:
+// MSABI-NEXT: File 0, [[@LINE-18]]:27 -> [[@LINE-18]]:40 = #0
+
+// ITANIUM: main:
+// ITANIUM-NEXT: File 0, [[@LINE-17]]:12 -> [[@LINE-8]]:2 = #0
+// ITANIUM-NEXT: _ZN20CreateSpecializationIiLi0EE2f1Ev:
+// ITANIUM-NEXT: File 0, [[@LINE-23]]:27 -> [[@LINE-23]]:40 = #0
diff --git a/test/CoverageMapping/preprocessor.c b/test/CoverageMapping/preprocessor.c
index bd82b3939e..cce8b67999 100644
--- a/test/CoverageMapping/preprocessor.c
+++ b/test/CoverageMapping/preprocessor.c
@@ -3,36 +3,69 @@
// CHECK: func
void func() { // CHECK: File 0, [[@LINE]]:13 -> [[@LINE+5]]:2 = #0
int i = 0;
-#ifdef MACRO // CHECK-NEXT: Skipped,File 0, [[@LINE]]:2 -> [[@LINE+2]]:2 = 0
+#ifdef MACRO // CHECK-NEXT: Skipped,File 0, [[@LINE]]:1 -> [[@LINE+3]]:1 = 0
int x = i;
#endif
}
-#if 0
- int g = 0;
-
- void bar() { }
-#endif
-
// CHECK: main
int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> {{[0-9]+}}:2 = #0
int i = 0;
-#if 0 // CHECK-NEXT: Skipped,File 0, [[@LINE]]:2 -> [[@LINE+4]]:2 = 0
+# if 0 // CHECK-NEXT: Skipped,File 0, [[@LINE]]:1 -> [[@LINE+5]]:1 = 0
if(i == 0) {
i = 1;
}
-#endif
+# endif // Mark me skipped!
#if 1
// CHECK-NEXT: File 0, [[@LINE+1]]:6 -> [[@LINE+1]]:12 = #0
if(i == 0) { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+2]]:4 = #1
i = 1;
}
-#else // CHECK-NEXT: Skipped,File 0, [[@LINE]]:2 -> [[@LINE+5]]:2 = 0
+#else // CHECK-NEXT: Skipped,File 0, [[@LINE]]:1 -> [[@LINE+6]]:1 = 0
if(i == 1) {
i = 0;
}
}
#endif
+
+ // CHECK-NEXT: Skipped,File 0, [[@LINE+1]]:1 -> [[@LINE+5]]:1
+#\
+ if 0
+#\
+ endif // also skipped
+
+#if 1
+ // CHECK-NEXT: Skipped,File 0, [[@LINE+1]]:1 -> [[@LINE+4]]:1
+#\
+ elif 0
+#endif
+
+#if 1
+ // CHECK-NEXT: Skipped,File 0, [[@LINE+1]]:1 -> [[@LINE+4]]:1
+#\
+ else
+#endif
+
+ // CHECK-NEXT: Skipped,File 0, [[@LINE+1]]:1 -> [[@LINE+5]]:1
+#\
+ ifdef NOT_DEFINED
+#\
+ endif
+
+ // CHECK-NEXT: Skipped,File 0, [[@LINE+1]]:1 -> [[@LINE+5]]:1
+#\
+ ifndef __FILE__
+#\
+ endif
+
+ // CHECK-NEXT: Skipped,File 0, [[@LINE+1]]:1 -> [[@LINE+7]]:1
+#\
+ ifdef NOT_DEFINED
+#\
+ \
+ \
+ endif // also skipped
+
return 0;
}
diff --git a/test/CoverageMapping/return.c b/test/CoverageMapping/return.c
index 1b190b0eb7..3cc271b7ca 100644
--- a/test/CoverageMapping/return.c
+++ b/test/CoverageMapping/return.c
@@ -13,7 +13,7 @@ void func2() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> {{[0-9]+}
for(int i = 0; i < 10; ++i) { // CHECK-NEXT: File 0, [[@LINE]]:31 -> {{[0-9]+}}:4 = #1
// CHECK-NEXT: File 0, [[@LINE+1]]:8 -> [[@LINE+1]]:13 = #1
if(i > 2) { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+2]]:6 = #2
- return;
+ return; // CHECK-NEXT: File 0, [[@LINE+1]]:6 -> [[@LINE+3]]:5 = (#1 - #2)
} // CHECK-NEXT: File 0, [[@LINE+2]]:5 -> {{[0-9]+}}:4 = (#1 - #2)
// CHECK-NEXT: File 0, [[@LINE+1]]:8 -> [[@LINE+1]]:14 = (#1 - #2)
if(i == 3) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> [[@LINE+2]]:6 = #3
diff --git a/test/CoverageMapping/switch.cpp b/test/CoverageMapping/switch.cpp
index 312f26ca16..d347e663d1 100644
--- a/test/CoverageMapping/switch.cpp
+++ b/test/CoverageMapping/switch.cpp
@@ -3,10 +3,10 @@
// CHECK: foo
void foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+8]]:2 = #0
switch(i) {
- case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:10 = #2
+ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = #2
return;
case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #3
- break;
+ break; // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE+2]]:3 = #1
}
int x = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #1
}
@@ -48,23 +48,23 @@ void baz() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+5]]:2 = #0
int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+35]]:2 = #0
int i = 0;
switch(i) {
- case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+7]]:10 = #2
+ case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #2
i = 1;
break;
case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #3
i = 2;
break;
default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #4
- break;
+ break; // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE+2]]:3 = #1
}
switch(i) { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+23]]:2 = #1
- case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+6]]:10 = #6
+ case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #6
i = 1;
break;
case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:10 = #7
i = 2;
default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = (#7 + #8)
- break;
+ break; // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE+3]]:3 = #5
}
switch(i) { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+13]]:2 = #5
@@ -81,3 +81,32 @@ int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+35]]:2 = #0
baz();
return 0;
}
+
+// FIXME: End location for "case 1" shouldn't point at the end of the switch.
+ // CHECK: fallthrough
+int fallthrough(int i) { // CHECK-NEXT: File 0, [[@LINE]]:24 -> [[@LINE+12]]:2 = #0
+ switch(i) {
+ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+8]]:10 = #2
+ i = 23;
+ case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#2 + #3)
+ i = 11;
+ break;
+ case 3: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:10 = #4
+ case 4: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#4 + #5)
+ i = 99;
+ break;
+ }
+}
+
+void abort(void) __attribute((noreturn));
+ // CHECK: noret
+int noret(int x) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+9]]:2
+ switch (x) {
+ default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:12
+ abort();
+ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13
+ return 5;
+ case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:14
+ return 10;
+ }
+}
diff --git a/test/CoverageMapping/switchmacro.c b/test/CoverageMapping/switchmacro.c
index 55f93d8f60..8fb1b83d71 100644
--- a/test/CoverageMapping/switchmacro.c
+++ b/test/CoverageMapping/switchmacro.c
@@ -8,6 +8,7 @@ int foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> {{[0-9]+}}:2 = #0
default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> {{[0-9]+}}:11 = #2
if (i == 1) // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:15 = #2
return 0; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:15 = #3
+ // CHECK-NEXT: File 0, [[@LINE-1]]:15 -> [[@LINE+3]]:5 = (#2 - #3)
// CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:5 -> [[@LINE+2]]:8 = (#2 - #3) (Expanded file = 1)
// CHECK-NEXT: File 0, [[@LINE+1]]:8 -> {{[0-9]+}}:11 = (#2 - #3)
FOO(1);
diff --git a/test/CoverageMapping/trycatch.cpp b/test/CoverageMapping/trycatch.cpp
index 01d8fb9307..37b35d3098 100644
--- a/test/CoverageMapping/trycatch.cpp
+++ b/test/CoverageMapping/trycatch.cpp
@@ -18,7 +18,7 @@ void func(int i) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> {{[
// CHECK-NEXT: File 0, [[@LINE+1]]:10 -> [[@LINE+2]]:27 = (#0 - #1)
} else if(i == 8) // CHECK-NEXT: File 0, [[@LINE]]:13 -> [[@LINE]]:19 = (#0 - #1)
throw ImportantError(); // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:27 = #2
-}
+} // CHECK-NEXT: File 0, [[@LINE-1]]:27 -> [[@LINE]]:2 = ((#0 - #1) - #2)
// CHECK-NEXT: main
int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+13]]:2 = #0
diff --git a/test/CoverageMapping/unused_names.c b/test/CoverageMapping/unused_names.c
index 49fa1199d9..bf0134c41e 100644
--- a/test/CoverageMapping/unused_names.c
+++ b/test/CoverageMapping/unused_names.c
@@ -3,7 +3,7 @@
// RUN: FileCheck -check-prefix=SYSHEADER -input-file %t %s
// CHECK-DAG: @__profc_bar
-// CHECK-DAG: @__llvm_prf_nm = private constant {{.*}}, section "{{.*}}__llvm_prf_names"
+// CHECK-DAG: @__llvm_prf_nm = private constant {{.*}}, section "{{.*__llvm_prf_names|.*lprfn}}"
// These are never instantiated, so we shouldn't get counters for them.
//
diff --git a/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/bin/.keep b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/bin/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/bin/.keep
diff --git a/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/include/.keep b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/include/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/include/.keep
diff --git a/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib/.keep b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib/.keep
diff --git a/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib64/.keep b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib64/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA-nolibdevice/usr/local/cuda/lib64/.keep
diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/bin/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/bin/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA_90/usr/local/cuda/bin/.keep
diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/.keep
diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib/.keep
diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib64/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib64/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib64/.keep
diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/nvvm/libdevice/libdevice.10.bc b/test/Driver/Inputs/CUDA_90/usr/local/cuda/nvvm/libdevice/libdevice.10.bc
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/CUDA_90/usr/local/cuda/nvvm/libdevice/libdevice.10.bc
diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt b/test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt
new file mode 100644
index 0000000000..24e1fd4ece
--- /dev/null
+++ b/test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt
@@ -0,0 +1 @@
+CUDA Version 9.0.103
diff --git a/test/Driver/Inputs/baremetal_arm/include/c++/5.0.0/.keep b/test/Driver/Inputs/baremetal_arm/include/c++/5.0.0/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/baremetal_arm/include/c++/5.0.0/.keep
diff --git a/test/Driver/Inputs/baremetal_arm/include/c++/6.0.0/.keep b/test/Driver/Inputs/baremetal_arm/include/c++/6.0.0/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/baremetal_arm/include/c++/6.0.0/.keep
diff --git a/test/Driver/Inputs/baremetal_arm/include/c++/v1/.keep b/test/Driver/Inputs/baremetal_arm/include/c++/v1/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/baremetal_arm/include/c++/v1/.keep
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/i686-unknown-linux/lib/.keep b/test/Driver/Inputs/basic_linux_tree/usr/i686-unknown-linux/lib/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/i686-unknown-linux/lib/.keep
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i686-unknown-linux/4.6.0/crtbegin.o b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i686-unknown-linux/4.6.0/crtbegin.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/i686-unknown-linux/4.6.0/crtbegin.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crt1.o b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crt1.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crti.o b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crti.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crtn.o b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crtn.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtbegin.o b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtbegin.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtbegin.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtend.o b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtend.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv6hl_tree/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/crtend.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crt1.o b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crt1.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crt1.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crti.o b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crti.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crtn.o b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crtn.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/crtn.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtbegin.o b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtbegin.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtbegin.o
diff --git a/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtend.o b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtend.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/opensuse_tumbleweed_armv7hl_tree/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/crtend.o
diff --git a/test/Driver/Inputs/resource_dir/ubsan_blacklist.txt b/test/Driver/Inputs/resource_dir/ubsan_blacklist.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/ubsan_blacklist.txt
diff --git a/test/Driver/XRay/lit.local.cfg b/test/Driver/XRay/lit.local.cfg
index 34040d2261..7cc6c70dcb 100644
--- a/test/Driver/XRay/lit.local.cfg
+++ b/test/Driver/XRay/lit.local.cfg
@@ -1,2 +1,24 @@
target_triple_components = config.target_triple.split('-')
config.available_features.update(target_triple_components)
+
+# Only run the tests in platforms where XRay instrumentation is supported.
+supported_targets = [
+ 'x86_64', 'x86_64h', 'arm', 'aarch64', 'arm64', 'powerpc64le', 'mips',
+ 'mipsel', 'mips64', 'mips64el'
+]
+
+# Only on platforms we support.
+supported_oses = [
+ 'linux'
+]
+
+triple_set = set(target_triple_components)
+if len(triple_set.intersection(supported_targets)) == 0:
+ config.unsupported = True
+
+# Do not run for 'android' despite being linux.
+if len(triple_set.intersection(supported_oses)) == 0 or 'android' in triple_set:
+ config.unsupported = True
+
+if config.enable_shared:
+ config.available_features.update(['enable_shared'])
diff --git a/test/Driver/XRay/xray-shared-noxray.cpp b/test/Driver/XRay/xray-shared-noxray.cpp
new file mode 100644
index 0000000000..c279f93f3f
--- /dev/null
+++ b/test/Driver/XRay/xray-shared-noxray.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx -shared -o /dev/null -v -fxray-instrument %s -###
+// RUN: %clangxx -shared -o /dev/null -v -fxray-instrument %s -### 2>&1 | \
+// RUN: FileCheck %s --check-prefix=SHARED
+// RUN: %clangxx -static -o /dev/null -v -fxray-instrument %s -### -DMAIN
+// RUN: %clangxx -static -o /dev/null -v -fxray-instrument %s -### 2>&1 -DMAIN \
+// RUN: | FileCheck %s --check-prefix=STATIC
+//
+// SHARED-NOT: {{clang_rt\.xray-}}
+// STATIC: {{clang_rt\.xray-}}
+//
+// REQUIRES: linux, enable_shared
+int foo() { return 42; }
+
+#ifdef MAIN
+int main() { return foo(); }
+#endif
diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c
index 554c59d6bc..229484b257 100644
--- a/test/Driver/aarch64-cpus.c
+++ b/test/Driver/aarch64-cpus.c
@@ -11,7 +11,7 @@
// RUN: %clang -target arm64 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
// RUN: %clang -target arm64 -mcpu=generic -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
// RUN: %clang -target arm64 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
-// RUN: %clang -target arm64 -mlittle-endian -mcpu-generic -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=generic -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
// ARM64-GENERIC: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
@@ -21,138 +21,188 @@
// RUN: %clang -target aarch64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
-// RUN: %clang -target aarch64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-TUNE %s
// CA35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a35"
+// CA35-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
-// RUN: %clang -target arm64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s
+// RUN: %clang -target arm64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35-TUNE %s
// ARM64-CA35: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a35"
-
+// ARM64-CA35-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
-// RUN: %clang -target aarch64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-TUNE %s
// CA53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53"
+// CA53-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
-// RUN: %clang -target arm64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
+// RUN: %clang -target arm64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-TUNE %s
// ARM64-CA53: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a53"
+// ARM64-CA53-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target aarch64 -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-TUNE %s
+// CA55: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a55"
+// CA55-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target arm64 -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55 %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55 %s
+// RUN: %clang -target arm64 -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55-TUNE %s
+// ARM64-CA55: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a55"
+// ARM64-CA55-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
-// RUN: %clang -target aarch64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-TUNE %s
// CA57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57"
+// CA57-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
-// RUN: %clang -target arm64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
+// RUN: %clang -target arm64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-TUNE %s
// ARM64-CA57: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a57"
+// ARM64-CA57-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s
-// RUN: %clang -target aarch64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-TUNE %s
// CA72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a72"
+// CA72-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s
-// RUN: %clang -target arm64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s
+// RUN: %clang -target arm64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72-TUNE %s
// ARM64-CA72: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a72"
+// ARM64-CA72-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s
-// RUN: %clang -target aarch64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-TUNE %s
// CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a73"
+// CORTEX-A73-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s
-// RUN: %clang -target arm64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s
+// RUN: %clang -target arm64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73-TUNE %s
// ARM64-CORTEX-A73: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a73"
+// ARM64-CORTEX-A73-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target aarch64 -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75-TUNE %s
+// CORTEX-A75: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a75"
+// CORTEX-A75-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target arm64 -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75 %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75 %s
+// RUN: %clang -target arm64 -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75-TUNE %s
+// ARM64-CORTEX-A75: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a75"
+// ARM64-CORTEX-A75-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
-// RUN: %clang -target aarch64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s
+// RUN: %clang -target aarch64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-TUNE %s
// M1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "exynos-m1"
+// M1-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s
// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s
-// RUN: %clang -target aarch64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s
-// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s
+// RUN: %clang -target aarch64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-TUNE %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-TUNE %s
// M2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "exynos-m2"
+// M2-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s
-// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s
+// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-TUNE %s
// M3: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m3"
+// M3-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
-// RUN: %clang -target arm64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s
+// RUN: %clang -target arm64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1-TUNE %s
// ARM64-M1: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "exynos-m1"
+// ARM64-M1-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s
-// RUN: %clang -target arm64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s
+// RUN: %clang -target arm64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2-TUNE %s
// ARM64-M2: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "exynos-m2"
+// ARM64-M2-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s
-// RUN: %clang -target arm64 -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s
+// RUN: %clang -target arm64 -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3-TUNE %s
// ARM64-M3: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "exynos-m3"
+// ARM64-M3-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s
-// RUN: %clang -target aarch64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s
+// RUN: %clang -target aarch64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR-TUNE %s
// FALKOR: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "falkor"
+// FALKOR-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s
-// RUN: %clang -target arm64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s
+// RUN: %clang -target arm64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR-TUNE %s
// ARM64-FALKOR: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "falkor"
+// ARM64-FALKOR-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s
// RUN: %clang -target aarch64 -mlittle-endian -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s
-// RUN: %clang -target aarch64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s
-// RUN: %clang -target aarch64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s
+// RUN: %clang -target aarch64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO-TUNE %s
+// RUN: %clang -target aarch64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO-TUNE %s
// KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "kryo"
+// KRYO-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s
// RUN: %clang -target arm64 -mlittle-endian -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s
-// RUN: %clang -target arm64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s
-// RUN: %clang -target arm64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s
+// RUN: %clang -target arm64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO-TUNE %s
+// RUN: %clang -target arm64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO-TUNE %s
// ARM64-KRYO: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "kryo"
+// ARM64-KRYO-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// 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
@@ -161,7 +211,7 @@
// 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: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// THUNDERX2T99-TUNE-NOT: +v8.1a
// RUN: %clang -target arm64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99 %s
@@ -169,7 +219,7 @@
// 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: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// ARM64-THUNDERX2T99-TUNE-NOT: +v8.1a
// RUN: %clang -target aarch64_be -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
@@ -180,83 +230,104 @@
// RUN: %clang -target aarch64_be -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
-// RUN: %clang -target aarch64_be -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s
+// RUN: %clang -target aarch64_be -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE-TUNE %s
// CA35-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a35"
+// CA35-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
-// RUN: %clang -target aarch64_be -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
+// RUN: %clang -target aarch64_be -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE-TUNE %s
// CA53-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a53"
+// CA53-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target aarch64_be -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s
+// RUN: %clang -target aarch64_be -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE-TUNE %s
+// CA55-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a55"
+// CA55-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
-// RUN: %clang -target aarch64_be -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
+// RUN: %clang -target aarch64_be -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE-TUNE %s
// CA57-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a57"
+// CA57-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s
-// RUN: %clang -target aarch64_be -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s
+// RUN: %clang -target aarch64_be -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE-TUNE %s
// CA72-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a72"
+// CA72-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s
-// RUN: %clang -target aarch64_be -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s
+// RUN: %clang -target aarch64_be -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE-TUNE %s
// CORTEX-A73-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a73"
+// CORTEX-A73-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
-// RUN: %clang -target aarch64_be -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s
+// RUN: %clang -target aarch64_be -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE-TUNE %s
// M1-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m1"
+// M1-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s
-// RUN: %clang -target aarch64_be -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s
+// RUN: %clang -target aarch64_be -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE-TUNE %s
// M2-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m2"
+// M2-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64_be -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s
// RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s
// RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s
-// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s
-// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s
-// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s
+// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE-TUNE %s
// M3-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m3"
+// M3-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
// 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
+// RUN: %clang -target aarch64_be -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE-TUNE %s
+// RUN: %clang -target aarch64 -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE-TUNE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE-TUNE %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=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"
+// THUNDERX2T99-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target aarch64 -mcpu=cortex-a57 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A57 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A57 %s
+// RUN: %clang -target aarch64 -mcpu=cortex-a72 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A72 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A72 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A73 %s
+// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-THUNDERX2T99 %s
+// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-THUNDERX2T99 %s
+// MCPU-MTUNE-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57"
+// MCPU-MTUNE-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a72"
+// MCPU-MTUNE-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a73"
+// MCPU-MTUNE-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "thunderx2t99"
// RUN: %clang -target aarch64 -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
// RUN: %clang -target aarch64 -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s
@@ -307,17 +378,21 @@
// ================== Check whether -mcpu and -mtune accept mixed-case values.
// RUN: %clang -target aarch64 -mcpu=Cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA53 %s
-// RUN: %clang -target aarch64 -mtune=Cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA53 %s
+// RUN: %clang -target aarch64 -mtune=Cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA53-TUNE %s
// CASE-INSENSITIVE-CA53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53"
+// CASE-INSENSITIVE-CA53-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=cortex-A53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA53 %s
-// RUN: %clang -target arm64 -mtune=cortex-A53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA53 %s
+// RUN: %clang -target arm64 -mtune=cortex-A53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA53-TUNE %s
// CASE-INSENSITIVE-ARM64-CA53: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a53"
+// CASE-INSENSITIVE-ARM64-CA53-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target aarch64 -mcpu=CORTEX-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA57 %s
-// RUN: %clang -target aarch64 -mtune=CORTEX-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA57 %s
+// RUN: %clang -target aarch64 -mtune=CORTEX-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA57-TUNE %s
// CASE-INSENSITIVE-CA57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57"
+// CASE-INSENSITIVE-CA57-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm64 -mcpu=Cortex-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA57 %s
-// RUN: %clang -target arm64 -mtune=Cortex-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA57 %s
+// RUN: %clang -target arm64 -mtune=Cortex-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA57-TUNE %s
// CASE-INSENSITIVE-ARM64-CA57: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a57"
+// CASE-INSENSITIVE-ARM64-CA57-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
diff --git a/test/Driver/aarch64-dotprod.c b/test/Driver/aarch64-dotprod.c
new file mode 100644
index 0000000000..0262cc75b7
--- /dev/null
+++ b/test/Driver/aarch64-dotprod.c
@@ -0,0 +1,11 @@
+// RUN: %clang -### -target aarch64 %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// RUN: %clang -### -target aarch64 -march=armv8.1a %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// RUN: %clang -### -target aarch64 -march=armv8.2a %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// RUN: %clang -### -target aarch64 -march=armv8.3a %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// CHECK-NONE-NOT: "-target-feature" "+dotprod"
+
+// RUN: %clang -### -target aarch64 -march=armv8.2a+dotprod %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target aarch64 -march=armv8.3a+dotprod %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target aarch64 -mcpu=cortex-a75 %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target aarch64 -mcpu=cortex-a55 %s 2>&1 | FileCheck %s
+// CHECK: "+dotprod"
diff --git a/test/Driver/aarch64-ras.c b/test/Driver/aarch64-ras.c
index fe038eaf15..d4663a2f89 100644
--- a/test/Driver/aarch64-ras.c
+++ b/test/Driver/aarch64-ras.c
@@ -1,5 +1,7 @@
// RUN: %clang -target aarch64-none-none-eabi -march=armv8a+ras -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
// RUN: %clang -target aarch64-none-none-eabi -mcpu=generic+ras -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
+// RUN: %clang -target aarch64-none-none-eabi -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
+// RUN: %clang -target aarch64-none-none-eabi -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
// CHECK-RAS: "-target-feature" "+ras"
// RUN: %clang -target aarch64-none-none-eabi -march=armv8a+noras -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORAS %s
diff --git a/test/Driver/aarch64-rcpc.s b/test/Driver/aarch64-rcpc.s
new file mode 100644
index 0000000000..a3ddf69bd1
--- /dev/null
+++ b/test/Driver/aarch64-rcpc.s
@@ -0,0 +1,14 @@
+// RUN: %clang -### -target aarch64 %s 2>&1 | FileCheck --check-prefix=CHECK-NONE %s
+// RUN: %clang -### -target aarch64 -march=armv8.1a %s 2>&1 | FileCheck --check-prefix=CHECK-NONE %s
+// RUN: %clang -### -target aarch64 -march=armv8.2a %s 2>&1 | FileCheck --check-prefix=CHECK-NONE %s
+// CHECK-NONE-NOT: "-target-feature" "+rcpc"
+
+// RUN: %clang -### -target aarch64 -march=armv8.2a+rcpc %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target aarch64 -march=armv8.3a+rcpc %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target aarch64 -mcpu=cortex-a75 %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target aarch64 -mcpu=cortex-a55 %s 2>&1 | FileCheck %s
+// CHECK: "-target-feature" "+rcpc"
+
+// RUN: %clang -### -target aarch64 -mcpu=cortex-a75+norcpc %s 2>&1 | FileCheck --check-prefix=CHECK-NO-RCPC %s
+// RUN: %clang -### -target aarch64 -mcpu=cortex-a55+norcpc %s 2>&1 | FileCheck --check-prefix=CHECK-NO-RCPC %s
+// CHECK-NO-RCPC: "-rcpc"
diff --git a/test/Driver/aarch64-rdm.c b/test/Driver/aarch64-rdm.c
new file mode 100644
index 0000000000..4f6fb24b68
--- /dev/null
+++ b/test/Driver/aarch64-rdm.c
@@ -0,0 +1,9 @@
+// RUN: %clang -target aarch64-none-none-eabi -march=armv8a+rdm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
+// RUN: %clang -target aarch64-none-none-eabi -mcpu=generic+rdm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
+// RUN: %clang -target aarch64-none-none-eabi -mcpu=falkor -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
+// RUN: %clang -target aarch64-none-none-eabi -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
+// CHECK-RDM: "-target-feature" "+rdm"
+
+// RUN: %clang -target aarch64-none-none-eabi -march=armv8a+nordm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORDM %s
+// RUN: %clang -target aarch64-none-none-eabi -mcpu=generic+nordm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORDM %s
+// CHECK-NORDM: "-target-feature" "-rdm"
diff --git a/test/Driver/amdgpu-features.c b/test/Driver/amdgpu-features.c
index 235b88f13b..495cadb119 100644
--- a/test/Driver/amdgpu-features.c
+++ b/test/Driver/amdgpu-features.c
@@ -1,7 +1,7 @@
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kaveri -mamdgpu-debugger-abi=0.0 %s -o 2>&1 \
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kaveri -mamdgpu-debugger-abi=0.0 %s -o - 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-MAMDGPU-DEBUGGER-ABI-0-0 %s
// CHECK-MAMDGPU-DEBUGGER-ABI-0-0: the clang compiler does not support '-mamdgpu-debugger-abi=0.0'
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kaveri -mamdgpu-debugger-abi=1.0 %s -o 2>&1 \
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kaveri -mamdgpu-debugger-abi=1.0 %s -o - 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-MAMDGPU-DEBUGGER-ABI-1-0 %s
// CHECK-MAMDGPU-DEBUGGER-ABI-1-0: "-target-feature" "+amdgpu-debugger-insert-nops" "-target-feature" "+amdgpu-debugger-reserve-regs" "-target-feature" "+amdgpu-debugger-emit-prologue"
diff --git a/test/Driver/r600-mcpu.cl b/test/Driver/amdgpu-mcpu.cl
index b99cac3bd7..26137ac68a 100644
--- a/test/Driver/r600-mcpu.cl
+++ b/test/Driver/amdgpu-mcpu.cl
@@ -26,22 +26,6 @@ t// Check that -mcpu works for all supported GPUs
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=caicos %s -o - 2>&1 | FileCheck --check-prefix=CAICOS-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cayman %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=aruba %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=tahiti %s -o - 2>&1 | FileCheck --check-prefix=TAHITI-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=bonaire %s -o - 2>&1 | FileCheck --check-prefix=BONAIRE-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kabini %s -o - 2>&1 | FileCheck --check-prefix=KABINI-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kaveri %s -o - 2>&1 | FileCheck --check-prefix=KAVERI-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=hawaii %s -o - 2>&1 | FileCheck --check-prefix=HAWAII-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=mullins %s -o - 2>&1 | FileCheck --check-prefix=MULLINS-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=tonga %s -o - 2>&1 | FileCheck --check-prefix=TONGA-CHECK %s
-// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=iceland %s -o - 2>&1 | FileCheck --check-prefix=ICELAND-CHECK %s
-// 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"
@@ -58,19 +42,71 @@ t// Check that -mcpu works for all supported GPUs
// TURKS-CHECK: "-target-cpu" "turks"
// CAICOS-CHECK: "-target-cpu" "caicos"
// CAYMAN-CHECK: "-target-cpu" "cayman"
+
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx600 %s -o - 2>&1 | FileCheck --check-prefix=GFX600-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=tahiti %s -o - 2>&1 | FileCheck --check-prefix=TAHITI-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx601 %s -o - 2>&1 | FileCheck --check-prefix=GFX601-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=hainan %s -o - 2>&1 | FileCheck --check-prefix=HAINAN-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx700 %s -o - 2>&1 | FileCheck --check-prefix=GFX700-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=bonaire %s -o - 2>&1 | FileCheck --check-prefix=BONAIRE-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kaveri %s -o - 2>&1 | FileCheck --check-prefix=KAVERI-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx701 %s -o - 2>&1 | FileCheck --check-prefix=GFX701-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=hawaii %s -o - 2>&1 | FileCheck --check-prefix=HAWAII-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx702 %s -o - 2>&1 | FileCheck --check-prefix=GFX702-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx703 %s -o - 2>&1 | FileCheck --check-prefix=GFX703-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=kabini %s -o - 2>&1 | FileCheck --check-prefix=KABINI-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=mullins %s -o - 2>&1 | FileCheck --check-prefix=MULLINS-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx800 %s -o - 2>&1 | FileCheck --check-prefix=GFX800-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=iceland %s -o - 2>&1 | FileCheck --check-prefix=ICELAND-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx801 %s -o - 2>&1 | FileCheck --check-prefix=GFX801-CHECK %s
+// 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=gfx802 %s -o - 2>&1 | FileCheck --check-prefix=GFX802-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=tonga %s -o - 2>&1 | FileCheck --check-prefix=TONGA-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx803 %s -o - 2>&1 | FileCheck --check-prefix=GFX803-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=polaris10 %s -o - 2>&1 | FileCheck --check-prefix=POLARIS10-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=polaris11 %s -o - 2>&1 | FileCheck --check-prefix=POLARIS11-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx804 %s -o - 2>&1 | FileCheck --check-prefix=GFX804-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx810 %s -o - 2>&1 | FileCheck --check-prefix=GFX810-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
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx902 %s -o - 2>&1 | FileCheck --check-prefix=GFX902-CHECK %s
+// RUN: %clang -### -target amdgcn -x cl -S -emit-llvm -mcpu=gfx903 %s -o - 2>&1 | FileCheck --check-prefix=GFX903-CHECK %s
+
+// GFX600-CHECK: "-target-cpu" "gfx600"
// TAHITI-CHECK: "-target-cpu" "tahiti"
+// GFX601-CHECK: "-target-cpu" "gfx601"
// PITCAIRN-CHECK: "-target-cpu" "pitcairn"
// VERDE-CHECK: "-target-cpu" "verde"
// OLAND-CHECK: "-target-cpu" "oland"
+// HAINAN-CHECK: "-target-cpu" "hainan"
+// GFX700-CHECK: "-target-cpu" "gfx700"
// BONAIRE-CHECK: "-target-cpu" "bonaire"
-// KABINI-CHECK: "-target-cpu" "kabini"
// KAVERI-CHECK: "-target-cpu" "kaveri"
+// GFX701-CHECK: "-target-cpu" "gfx701"
// HAWAII-CHECK: "-target-cpu" "hawaii"
+// GFX702-CHECK: "-target-cpu" "gfx702"
+// GFX703-CHECK: "-target-cpu" "gfx703"
+// KABINI-CHECK: "-target-cpu" "kabini"
// MULLINS-CHECK: "-target-cpu" "mullins"
-// TONGA-CHECK: "-target-cpu" "tonga"
+// GFX800-CHECK: "-target-cpu" "gfx800"
// ICELAND-CHECK: "-target-cpu" "iceland"
+// GFX801-CHECK: "-target-cpu" "gfx801"
// CARRIZO-CHECK: "-target-cpu" "carrizo"
+// GFX802-CHECK: "-target-cpu" "gfx802"
+// TONGA-CHECK: "-target-cpu" "tonga"
+// GFX803-CHECK: "-target-cpu" "gfx803"
// FIJI-CHECK: "-target-cpu" "fiji"
+// POLARIS10-CHECK: "-target-cpu" "polaris10"
+// POLARIS11-CHECK: "-target-cpu" "polaris11"
+// GFX804-CHECK: "-target-cpu" "gfx804"
+// GFX810-CHECK: "-target-cpu" "gfx810"
// STONEY-CHECK: "-target-cpu" "stoney"
// GFX900-CHECK: "-target-cpu" "gfx900"
// GFX901-CHECK: "-target-cpu" "gfx901"
+// GFX902-CHECK: "-target-cpu" "gfx902"
+// GFX903-CHECK: "-target-cpu" "gfx903"
diff --git a/test/Driver/amdgpu-toolchain-opencl.cl b/test/Driver/amdgpu-toolchain-opencl.cl
new file mode 100644
index 0000000000..3994387f3e
--- /dev/null
+++ b/test/Driver/amdgpu-toolchain-opencl.cl
@@ -0,0 +1,19 @@
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -O0 %s 2>&1 | FileCheck -check-prefix=CHECK_O0 %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -O1 %s 2>&1 | FileCheck -check-prefix=CHECK_O1 %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -O2 %s 2>&1 | FileCheck -check-prefix=CHECK_O2 %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -O3 %s 2>&1 | FileCheck -check-prefix=CHECK_O3 %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -O4 %s 2>&1 | FileCheck -check-prefix=CHECK_O4 %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -O5 %s 2>&1 | FileCheck -check-prefix=CHECK_O5 %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -Og %s 2>&1 | FileCheck -check-prefix=CHECK_Og %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji -Ofast %s 2>&1 | FileCheck -check-prefix=CHECK_Ofast %s
+// RUN: %clang -### -target amdgcn-amd-amdhsa-opencl -x cl -c -emit-llvm -mcpu=fiji %s 2>&1 | FileCheck -check-prefix=CHECK_O_DEFAULT %s
+// CHECK_O0: clang{{.*}} "-O0"
+// CHECK_O1: clang{{.*}} "-O1"
+// CHECK_O2: clang{{.*}} "-O2"
+// CHECK_O3: clang{{.*}} "-O3"
+// CHECK_O4: clang{{.*}} "-O3"
+// CHECK_O5: clang{{.*}} "-O5"
+// CHECK_Og: clang{{.*}} "-Og"
+// CHECK_Ofast: {{.*}}clang{{.*}} "-Ofast"
+// CHECK_O_DEFAULT: clang{{.*}} "-O3"
+
diff --git a/test/Driver/ananas.c b/test/Driver/ananas.c
new file mode 100644
index 0000000000..2a5b35ed6c
--- /dev/null
+++ b/test/Driver/ananas.c
@@ -0,0 +1,9 @@
+// RUN: %clang -no-canonical-prefixes -target x86_64-unknown-ananas -static %s \
+// RUN: --sysroot=%S/Inputs/ananas-tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-STATIC %s
+// CHECK-STATIC: ld{{.*}}" "-Bstatic"
+// CHECK-STATIC: crt0.o
+// CHECK-STATIC: crti.o
+// CHECK-STATIC: crtbegin.o
+// CHECK-STATIC: crtend.o
+// CHECK-STATIC: crtn.o
diff --git a/test/Driver/android-ndk-standalone.cpp b/test/Driver/android-ndk-standalone.cpp
index 7fe6d3c3c2..86ab85269f 100644
--- a/test/Driver/android-ndk-standalone.cpp
+++ b/test/Driver/android-ndk-standalone.cpp
@@ -172,6 +172,20 @@
// CHECK-ARMV7THUMB-NOT: "-L{{.*}}/lib/gcc/arm-linux-androideabi/4.9/../{{[^ ]*}}/lib/armv7-a"
// CHECK-ARMV7THUMB-NOT: "-L{{.*}}/lib/gcc/arm-linux-androideabi/4.9/../{{[^ ]*}}/lib"
// CHECK-ARMV7THUMB: "-L{{.*}}/sysroot/usr/lib"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target arm-linux-androideabi -stdlib=libstdc++ \
+// RUN: -march=armv7-a -mthumb \
+// RUN: -B%S/Inputs/basic_android_ndk_tree \
+// RUN: --sysroot=%S/Inputs/basic_android_ndk_tree/sysroot \
+// RUN: -print-multi-lib \
+// RUN: | FileCheck --check-prefix=CHECK-ARM-MULTILIBS %s
+
+// CHECK-ARM-MULTILIBS: thumb;@mthumb
+// CHECK-ARM-MULTILIBS-NEXT: armv7-a;@march=armv7-a
+// CHECK-ARM-MULTILIBS-NEXT: armv7-a/thumb;@march=armv7-a@mthumb
+// CHECK-ARM-MULTILIBS-NEXT: .;
+
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target armv7a-none-linux-androideabi -stdlib=libstdc++ \
diff --git a/test/Driver/android-pie.c b/test/Driver/android-pie.c
new file mode 100644
index 0000000000..2569c55d58
--- /dev/null
+++ b/test/Driver/android-pie.c
@@ -0,0 +1,66 @@
+// NO-PIE-NOT: "-pie"
+// PIE: "-pie"
+
+// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-androideabi \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android14 \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android16 \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android14 \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android16 \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android14 \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android16 \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// RUN: %clang %s -### -o %t.o 2>&1 --target=aarch64-linux-android \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=aarch64-linux-android24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// RUN: %clang %s -### -o %t.o 2>&1 --target=arm64-linux-android \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=arm64-linux-android24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// RUN: %clang %s -### -o %t.o 2>&1 --target=mips64el-linux-android \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=mips64el-linux-android24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// RUN: %clang %s -### -o %t.o 2>&1 --target=x86_64-linux-android \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 --target=x86_64-linux-android24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// Override toolchain default setting.
+// RUN: %clang %s -### -o %t.o 2>&1 -pie --target=arm-linux-androideabi \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 -pie --target=arm-linux-androideabi14 \
+// RUN: | FileCheck --check-prefix=PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 -no-pie -pie --target=arm-linux-androideabi24 \
+// RUN: | FileCheck --check-prefix=PIE %s
+
+// RUN: %clang %s -### -o %t.o 2>&1 -no-pie --target=arm-linux-androideabi24 \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 -nopie --target=arm-linux-androideabi24 \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
+// RUN: %clang %s -### -o %t.o 2>&1 -pie -no-pie --target=arm-linux-androideabi24 \
+// RUN: | FileCheck --check-prefix=NO-PIE %s
diff --git a/test/Driver/arch-specific-libdir-rpath.c b/test/Driver/arch-specific-libdir-rpath.c
index e6a5da8752..4b210f2cb4 100644
--- a/test/Driver/arch-specific-libdir-rpath.c
+++ b/test/Driver/arch-specific-libdir-rpath.c
@@ -1,50 +1,85 @@
// Test that the driver adds an arch-specific subdirectory in
-// {RESOURCE_DIR}/lib/linux to the linker search path and to '-rpath' for native
-// compilations.
+// {RESOURCE_DIR}/lib/linux to the linker search path and to '-rpath'
//
-// -rpath only gets added during native compilation. To keep the test simple,
-// just test for x86_64-linux native compilation.
-// REQUIRES: x86_64-linux
+// 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 -fsanitize=undefined \
+// RUN: %clang %s -### 2>&1 -target x86_64-linux -fsanitize=undefined \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
-// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,NO-RPATH %s
+// 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: | FileCheck --check-prefixes=FILEPATH,LIBPATH,RPATH %s
+// 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: | FileCheck --check-prefixes=FILEPATH,LIBPATH,RPATH %s
+// 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 -fopenmp \
+// RUN: %clang %s -### 2>&1 -target x86_64-linux -fopenmp \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
-// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,RPATH %s
+// 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 \
+// RUN: %clang %s -### 2>&1 -fsanitize=undefined -target x86_64-linux \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
-// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,NO-RPATH %s
+// 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 \
+// RUN: %clang %s -### 2>&1 -target x86_64-linux \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \
-// RUN: | FileCheck --check-prefixes=FILEPATH,LIBPATH,NO-RPATH %s
+// 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 \
+// RUN: %clang %s -### 2>&1 -target x86_64-linux \
// RUN: -resource-dir=%S/Inputs/resource_dir \
-// RUN: | FileCheck --check-prefixes=FILEPATH,NO-LIBPATH,NO-RPATH %s
-//
+// RUN: -frtlib-add-rpath \
+// RUN: | FileCheck --check-prefixes=RESDIR,NO-LIBPATH,NO-RPATH %s
//
-// FILEPATH: "-x" "c" "[[FILE_PATH:.*]]/{{.*}}.c"
-// LIBPATH: -L[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64
-// RPATH: "-rpath" "[[FILE_PATH]]/Inputs/resource_dir_with_arch_subdir/lib/linux/x86_64"
-// NO-LIBPATH-NOT: -L{{.*}}Inputs/resource_dir
-// NO-RPATH-NOT: "-rpath" {{.*}}/Inputs/resource_dir
+// 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
index 3889b37131..519236858b 100644
--- a/test/Driver/arch-specific-libdir.c
+++ b/test/Driver/arch-specific-libdir.c
@@ -1,8 +1,6 @@
// Test that the driver adds an arch-specific subdirectory in
// {RESOURCE_DIR}/lib/linux to the search path.
//
-// REQUIRES: linux
-//
// 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
@@ -44,11 +42,11 @@
// 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
+// 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.
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
index c52e643f03..8f8178226d 100644
--- a/test/Driver/arm-cortex-cpus.c
+++ b/test/Driver/arm-cortex-cpus.c
@@ -120,11 +120,11 @@
// RUN: %clang -target armv7a-linux-gnueabi -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7A %s
// RUN: %clang -target arm-linux-gnueabi -march=armv7-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7A %s
-// CHECK-V7A: "-cc1"{{.*}} "-triple" "armv7-{{.*}} "-target-cpu" "cortex-a8"
+// CHECK-V7A: "-cc1"{{.*}} "-triple" "armv7-{{.*}} "-target-cpu" "generic"
// RUN: %clang -target armv7a-linux-gnueabi -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7A-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -march=armv7-a -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7A-THUMB %s
-// CHECK-V7A-THUMB: "-cc1"{{.*}} "-triple" "thumbv7-{{.*}} "-target-cpu" "cortex-a8"
+// CHECK-V7A-THUMB: "-cc1"{{.*}} "-triple" "thumbv7-{{.*}} "-target-cpu" "generic"
// RUN: %clang -target armv7r-linux-gnueabi -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7R %s
// RUN: %clang -target arm-linux-gnueabi -march=armv7-r -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7R %s
@@ -144,7 +144,7 @@
// RUN: %clang -target armv8a -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
// RUN: %clang -target arm -march=armv8a -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
// RUN: %clang -target arm -mlittle-endian -march=armv8-a -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
-// CHECK-V8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}" "-target-cpu" "cortex-a53"
+// CHECK-V8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target armv8r-linux-gnueabi -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8R %s
// RUN: %clang -target arm -march=armv8r -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8R %s
@@ -189,7 +189,7 @@
// RUN: %clang -target armv8a -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
// RUN: %clang -target arm -march=armebv8a -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
// RUN: %clang -target arm -march=armebv8-a -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
-// CHECK-BE-V8A: "-cc1"{{.*}} "-triple" "armebv8-{{.*}}" "-target-cpu" "cortex-a53"
+// CHECK-BE-V8A: "-cc1"{{.*}} "-triple" "armebv8-{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target armv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
// RUN: %clang -target arm -march=armv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
@@ -199,7 +199,7 @@
// RUN: %clang -target arm -march=armv8 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
// RUN: %clang -target armv8a -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
// RUN: %clang -target arm -march=armv8a -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
-// CHECK-V8A-THUMB: "-cc1"{{.*}} "-triple" "thumbv8-{{.*}}" "-target-cpu" "cortex-a53"
+// CHECK-V8A-THUMB: "-cc1"{{.*}} "-triple" "thumbv8-{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target armebv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
// RUN: %clang -target armeb -march=armebv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
@@ -209,7 +209,7 @@
// RUN: %clang -target arm -march=armebv8 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
// RUN: %clang -target armv8a -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
// RUN: %clang -target arm -march=armebv8a -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
-// CHECK-BE-V8A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv8-{{.*}}" "-target-cpu" "cortex-a53"
+// CHECK-BE-V8A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv8-{{.*}}" "-target-cpu" "generic"
// RUN: %clang -target arm -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A %s
// RUN: %clang -target armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A %s
@@ -507,6 +507,12 @@
// RUN: %clang -target arm -mcpu=exynos-m3 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// CHECK-CPUV8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}
+// RUN: %clang -target arm -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV82A %s
+// RUN: %clang -target arm -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV82A %s
+// RUN: %clang -target arm -mcpu=cortex-a55 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV82A %s
+// RUN: %clang -target arm -mcpu=cortex-a75 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV82A %s
+// CHECK-CPUV82A: "-cc1"{{.*}} "-triple" "armv8.2a-{{.*}}
+
// RUN: %clang -target armeb -mcpu=cortex-a32 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target armeb -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target armeb -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
@@ -527,6 +533,12 @@
// RUN: %clang -target arm -mcpu=exynos-m3 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// CHECK-BE-CPUV8A: "-cc1"{{.*}} "-triple" "armebv8-{{.*}}
+// RUN: %clang -target armeb -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A %s
+// RUN: %clang -target armeb -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A %s
+// RUN: %clang -target arm -mcpu=cortex-a55 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A %s
+// RUN: %clang -target arm -mcpu=cortex-a75 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A %s
+// CHECK-BE-CPUV82A: "-cc1"{{.*}} "-triple" "armebv8.2a-{{.*}}
+
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r52 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8R %s
// CHECK-CPUV8R: "-cc1"{{.*}} "-triple" "armv8r-{{.*}}
@@ -550,6 +562,12 @@
// RUN: %clang -target arm -mcpu=exynos-m3 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// CHECK-CPUV8A-THUMB: "-cc1"{{.*}} "-triple" "thumbv8-{{.*}}
+// RUN: %clang -target arm -mcpu=cortex-a55 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECKCPUV82A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a75 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECKCPUV82A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a55 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECKCPUV82A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a75 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECKCPUV82A-THUMB %s
+// CHECKCPUV82A-THUMB: "-cc1"{{.*}} "-triple" "thumbv8.2a-{{.*}}
+
// RUN: %clang -target armeb -mcpu=cortex-a32 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target armeb -mcpu=cortex-a35 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target armeb -mcpu=cortex-a53 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
@@ -570,6 +588,12 @@
// RUN: %clang -target arm -mcpu=exynos-m3 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// CHECK-BE-CPUV8A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv8-{{.*}}
+// RUN: %clang -target armeb -mcpu=cortex-a55 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A-THUMB %s
+// RUN: %clang -target armeb -mcpu=cortex-a75 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a55 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a75 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV82A-THUMB %s
+// CHECK-BE-CPUV82A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv8.2a-{{.*}}
+
// RUN: %clang -target armv8a-arm-none-eabi -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CORTEX-A73 %s
// RUN: %clang -target armv8a-arm-none-eabi -mcpu=cortex-a73 -mfpu=crypto-neon-fp-armv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CORTEX-A73-MFPU %s
// RUN: %clang -target armv8a-arm-none-eabi -mcpu=cortex-a73 -mfloat-abi=soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CORTEX-A73-SOFT %s
@@ -579,6 +603,15 @@
// CHECK-CORTEX-A73-SOFT: "-target-feature" "+soft-float"
// CHECK-CORTEX-A73-SOFT: "-target-feature" "+soft-float-abi"
+// RUN: %clang -target armv8a-arm-none-eabi -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CORTEX-A75 %s
+// RUN: %clang -target armv8a-arm-none-eabi -mcpu=cortex-a75 -mfpu=crypto-neon-fp-armv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CORTEX-A75-MFPU %s
+// RUN: %clang -target armv8a-arm-none-eabi -mcpu=cortex-a75 -mfloat-abi=soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CORTEX-A75-SOFT %s
+// CHECK-CORTEX-A75: "-cc1"{{.*}} "-triple" "armv8.2a-{{.*}} "-target-cpu" "cortex-a75"
+// CHECK-CORTEX-A75-MFPU: "-cc1"{{.*}} "-target-feature" "+fp-armv8"
+// CHECK-CORTEX-A75-MFPU: "-target-feature" "+crypto"
+// CHECK-CORTEX-A75-SOFT: "-target-feature" "+soft-float"
+// CHECK-CORTEX-A75-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-
diff --git a/test/Driver/arm-darwin-builtin.c b/test/Driver/arm-darwin-builtin.c
deleted file mode 100644
index be50b68987..0000000000
--- a/test/Driver/arm-darwin-builtin.c
+++ /dev/null
@@ -1,14 +0,0 @@
-// FIXME: Disable pending PR4941.
-// RUX: clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s 2> %t &&
-// RUX: grep -- "-fno-builtin-strcat" %t &&
-// RUX: grep -- "-fno-builtin-strcpy" %t &&
-
-// FIXME: Disable pending PR4941.
-// RUX: clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t &&
-// RUX: not grep -- "-fno-builtin-strcat" %t &&
-// RUX: not grep -- "-fno-builtin-strcpy" %t &&
-
-// RUN: %clang -target x86_64-apple-darwin9 -arch arm -### -fsyntax-only %s -fbuiltin-strcat -fbuiltin-strcpy 2> %t
-// RUN: not grep -- "-fno-builtin-strcat" %t
-// RUN: not grep -- "-fno-builtin-strcpy" %t
-
diff --git a/test/Driver/arm-default-build-attributes.s b/test/Driver/arm-default-build-attributes.s
new file mode 100644
index 0000000000..be2bf3c77b
--- /dev/null
+++ b/test/Driver/arm-default-build-attributes.s
@@ -0,0 +1,20 @@
+// Enabled by default for assembly
+// RUN: %clang -target armv7--none-eabi -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-ENABLED
+
+// Can be forced on or off for assembly.
+// RUN: %clang -target armv7--none-eabi -### %s 2>&1 -mno-default-build-attributes \
+// RUN: | FileCheck %s -check-prefix CHECK-DISABLED
+// RUN: %clang -target armv7--none-eabi -### %s 2>&1 -mdefault-build-attributes \
+// RUN: | FileCheck %s -check-prefix CHECK-ENABLED
+
+// Option ignored C/C++ (since we always emit hardware and ABI build attributes
+// during codegen).
+// RUN: %clang -target armv7--none-eabi -### -x c %s -mdefault-build-attributes 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-DISABLED
+// RUN: %clang -target armv7--none-eabi -### -x c++ %s -mdefault-build-attributes 2>&1 \
+// RUN: | FileCheck %s -check-prefix CHECK-DISABLED
+
+// CHECK-DISABLED-NOT: "-arm-add-build-attributes"
+// CHECK-ENABLED: "-arm-add-build-attributes"
+// expected-warning {{argument unused during compilation: '-mno-default-build-attributes'}}
diff --git a/test/Driver/arm-dotprod.c b/test/Driver/arm-dotprod.c
new file mode 100644
index 0000000000..a895d30dee
--- /dev/null
+++ b/test/Driver/arm-dotprod.c
@@ -0,0 +1,11 @@
+// RUN: %clang -### -target arm %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// RUN: %clang -### -target arm -march=armv8.1a %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// RUN: %clang -### -target arm -march=armv8.2a %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// RUN: %clang -### -target arm -march=armv8.3a %s 2>&1 | FileCheck %s --check-prefix=CHECK-NONE
+// CHECK-NONE-NOT: "-target-feature" "+dotprod"
+
+// RUN: %clang -### -target arm -march=armv8.2a+dotprod %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target arm -march=armv8.3a+dotprod %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target arm -mcpu=cortex-a75 %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target arm -mcpu=cortex-a55 %s 2>&1 | FileCheck %s
+// CHECK: "+dotprod"
diff --git a/test/Driver/arm-execute-only.c b/test/Driver/arm-execute-only.c
index a4854485e1..c226a7f3b4 100644
--- a/test/Driver/arm-execute-only.c
+++ b/test/Driver/arm-execute-only.c
@@ -1,39 +1,3 @@
-// RUN: %clang -target armv6t2-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv6t2-eabi -### -mexecute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv6t2-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv7m-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv7m-eabi -### -mexecute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv7m-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.base-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.base-eabi -### -mexecute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.base-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.main-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.main-eabi -### -mexecute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.main-eabi -### -mexecute-only -mno-execute-only %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
// RUN: not %clang -c -target thumbv6m-eabi -mexecute-only %s 2>&1 | \
// RUN: FileCheck --check-prefix CHECK-EXECUTE-ONLY-NOT-SUPPORTED %s
@@ -45,42 +9,6 @@
// -mpure-code flag for GCC compatibility
-// RUN: %clang -target armv6t2-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv6t2-eabi -### -mpure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv6t2-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv7m-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv7m-eabi -### -mpure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv7m-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.base-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.base-eabi -### -mpure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.base-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.main-eabi -### %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.main-eabi -### -mpure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY
-
-// RUN: %clang -target armv8m.main-eabi -### -mpure-code -mno-pure-code %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY
-
// RUN: not %clang -c -target thumbv6m-eabi -mpure-code %s 2>&1 | \
// RUN: FileCheck --check-prefix CHECK-EXECUTE-ONLY-NOT-SUPPORTED %s
diff --git a/test/Driver/arm-no-neg-immediates.c b/test/Driver/arm-no-neg-immediates.c
new file mode 100644
index 0000000000..f1e4d5f790
--- /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/arm-ras.c b/test/Driver/arm-ras.c
index 6d2168c160..076bb4b5e0 100644
--- a/test/Driver/arm-ras.c
+++ b/test/Driver/arm-ras.c
@@ -1,5 +1,7 @@
// RUN: %clang -target arm-none-none-eabi -march=armv8a+ras -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
// RUN: %clang -target arm-none-none-eabi -mcpu=generic+ras -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
+// RUN: %clang -target arm-none-none-eabi -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
+// RUN: %clang -target arm-none-none-eabi -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RAS %s
// CHECK-RAS: "-target-feature" "+ras"
// RUN: %clang -target arm-none-none-eabi -march=armv8a+noras -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORAS %s
diff --git a/test/Driver/arm-thumb-only-cores.c b/test/Driver/arm-thumb-only-cores.c
new file mode 100644
index 0000000000..cf40bf0ffa
--- /dev/null
+++ b/test/Driver/arm-thumb-only-cores.c
@@ -0,0 +1,12 @@
+// RUN: not %clang -target arm-unknown-linux -marm -mcpu=cortex-m0 %s -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix M0 %s
+// M0: error: CPU 'cortex-m0' does not support 'ARM' execution mode
+
+// RUN: not %clang -target arm-unknown-linux -marm -march=armv7m %s -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix ARMV7M %s
+// RUN: not %clang -target armv7m-unknown-linux -mno-thumb %s -o /dev/null 2>&1 \
+// RUN: | FileCheck --check-prefix ARMV7M %s
+// ARMV7M: error: Architecture 'armv7m' does not support 'ARM' execution mode
+//
+// RUN: %clang -S -emit-llvm -target arm-unknown-linux -mcpu=cortex-m0 %s -o /dev/null 2>&1
+// M-Profile CPUs default to Thumb mode even if arm triples are provided.
diff --git a/test/Driver/arm-wchar_t-defaults.c b/test/Driver/arm-wchar_t-defaults.c
new file mode 100644
index 0000000000..8b2ae29d00
--- /dev/null
+++ b/test/Driver/arm-wchar_t-defaults.c
@@ -0,0 +1,53 @@
+// RUN: %clang -### -target armv7-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target armv7-unknown-none-eabi -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-none-eabi -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target aarch64-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target aarch64_be-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64_be-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+
+// RUN: %clang -### -target armv7-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7-unknown-netbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-netbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64_be-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64_be-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+
+// RUN: %clang -### -target armv7-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7-unknown-openbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-openbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64_be-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64_be-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+
+// RUN: %clang -### -target armv7-unknown-windows-msvc -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-windows-msvc -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64-unknown-windows-msvc -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-windows-msvc -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+
+// CHECK-SHORT-NOT: "-fwchar-type=int"
+// CHECK-SHORT-NOT: "-fno-signed-wchar"
+
+// CHECK-LONG-UNSIGNED: "-fwchar-type=int"
+// CHECK-LONG-UNSIGNED: "-fno-signed-wchar"
+
+// CHECK-LONG-SIGNED: "-fwchar-type=int"
+// CHECK-LONG-SIGNED: "-fsigned-wchar"
+
diff --git a/test/Driver/autocomplete.c b/test/Driver/autocomplete.c
new file mode 100644
index 0000000000..8b6d6cfc89
--- /dev/null
+++ b/test/Driver/autocomplete.c
@@ -0,0 +1,112 @@
+// Test for the --autocompletion flag, which is an API used for shell
+// autocompletion. You may have to update tests in this file when you
+// add/modify flags, change HelpTexts or the values of some flags.
+
+// Some corner cases.
+// RUN: %clang --autocomplete= | FileCheck %s -check-prefix=ALL_FLAGS
+// RUN: %clang --autocomplete=# | FileCheck %s -check-prefix=ALL_FLAGS
+// Let's pick some example flags that are hopefully unlikely to change.
+// ALL_FLAGS: -fast
+// ALL_FLAGS: -fastcp
+// ALL_FLAGS: -fastf
+// Just test that this doesn't crash:
+// RUN: %clang --autocomplete=,
+// RUN: %clang --autocomplete==
+// RUN: %clang --autocomplete=,,
+// RUN: %clang --autocomplete=-
+
+// RUN: %clang --autocomplete=-fsyn | FileCheck %s -check-prefix=FSYN
+// FSYN: -fsyntax-only
+// RUN: %clang --autocomplete=-std= | FileCheck %s -check-prefix=STD
+// STD: -std= Language standard to compile for
+// RUN: %clang --autocomplete=foo | FileCheck %s -check-prefix=FOO
+// FOO-NOT: foo
+// RUN: %clang --autocomplete=-stdlib=,l | FileCheck %s -check-prefix=STDLIB
+// STDLIB: libc++
+// STDLIB-NEXT: libstdc++
+// RUN: %clang --autocomplete=-stdlib=, | FileCheck %s -check-prefix=STDLIBALL
+// STDLIBALL: libc++
+// STDLIBALL-NEXT: libstdc++
+// STDLIBALL-NEXT: platform
+// RUN: %clang --autocomplete=-meabi,d | FileCheck %s -check-prefix=MEABI
+// MEABI: default
+// RUN: %clang --autocomplete=-meabi, | FileCheck %s -check-prefix=MEABIALL
+// MEABIALL: 4
+// MEABIALL-NEXT: 5
+// MEABIALL-NEXT: default
+// MEABIALL-NEXT: gnu
+// RUN: %clang --autocomplete=-cl-std=,CL2 | FileCheck %s -check-prefix=CLSTD
+// CLSTD: CL2.0
+// RUN: %clang --autocomplete=-cl-std=, | FileCheck %s -check-prefix=CLSTDALL
+// CLSTDALL: cl
+// CLSTDALL-NEXT: CL
+// CLSTDALL-NEXT: cl1.1
+// CLSTDALL-NEXT: CL1.1
+// CLSTDALL-NEXT: cl1.2
+// CLSTDALL-NEXT: CL1.2
+// CLSTDALL-NEXT: cl2.0
+// CLSTDALL-NEXT: CL2.0
+// RUN: %clang --autocomplete=-fno-sanitize-coverage=,f | FileCheck %s -check-prefix=FNOSANICOVER
+// FNOSANICOVER: func
+// RUN: %clang --autocomplete=-fno-sanitize-coverage=, | FileCheck %s -check-prefix=FNOSANICOVERALL
+// FNOSANICOVERALL: 8bit-counters
+// FNOSANICOVERALL-NEXT: bb
+// FNOSANICOVERALL-NEXT: edge
+// FNOSANICOVERALL-NEXT: func
+// FNOSANICOVERALL-NEXT: indirect-calls
+// FNOSANICOVERALL-NEXT: inline-8bit-counters
+// FNOSANICOVERALL-NEXT: no-prune
+// FNOSANICOVERALL-NEXT: trace-bb
+// FNOSANICOVERALL-NEXT: trace-cmp
+// FNOSANICOVERALL-NEXT: trace-div
+// FNOSANICOVERALL-NEXT: trace-gep
+// FNOSANICOVERALL-NEXT: trace-pc
+// FNOSANICOVERALL-NEXT: trace-pc-guard
+// RUN: %clang --autocomplete=-ffp-contract=, | FileCheck %s -check-prefix=FFPALL
+// FFPALL: fast
+// FFPALL-NEXT: off
+// FFPALL-NEXT: on
+// RUN: %clang --autocomplete=-flto=, | FileCheck %s -check-prefix=FLTOALL
+// FLTOALL: full
+// FLTOALL-NEXT: thin
+// RUN: %clang --autocomplete=-fveclib=, | FileCheck %s -check-prefix=FVECLIBALL
+// FVECLIBALL: Accelerate
+// FVECLIBALL-NEXT: none
+// FVECLIBALL-NEXT: SVML
+// RUN: %clang --autocomplete=-fshow-overloads=, | FileCheck %s -check-prefix=FSOVERALL
+// FSOVERALL: all
+// FSOVERALL-NEXT: best
+// RUN: %clang --autocomplete=-fvisibility=, | FileCheck %s -check-prefix=FVISIBILITYALL
+// FVISIBILITYALL: default
+// FVISIBILITYALL-NEXT: hidden
+// RUN: %clang --autocomplete=-mfloat-abi=, | FileCheck %s -check-prefix=MFLOATABIALL
+// MFLOATABIALL: hard
+// MFLOATABIALL-NEXT: soft
+// MFLOATABIALL-NEXT: softfp
+// RUN: %clang --autocomplete=-mthread-model, | FileCheck %s -check-prefix=MTHREADMODELALL
+// MTHREADMODELALL: posix
+// MTHREADMODELALL-NEXT: single
+// RUN: %clang --autocomplete=-mrelocation-model, | FileCheck %s -check-prefix=MRELOCMODELALL
+// MRELOCMODELALL: dynamic-no-pic
+// MRELOCMODELALL-NEXT: pic
+// MRELOCMODELALL-NEXT: ropi
+// MRELOCMODELALL-NEXT: ropi-rwpi
+// MRELOCMODELALL-NEXT: rwpi
+// MRELOCMODELALL-NEXT: static
+// RUN: %clang --autocomplete=-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CLANG
+// MRELOCMODEL_CLANG-NOT: -mrelocation-model
+// RUN: %clang --autocomplete=#-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CC1
+// MRELOCMODEL_CC1: -mrelocation-model
+// RUN: %clang --autocomplete=-Wma | FileCheck %s -check-prefix=WARNING
+// WARNING: -Wmacro-redefined
+// WARNING-NEXT: -Wmain
+// WARNING-NEXT: -Wmain-return-type
+// WARNING-NEXT: -Wmalformed-warning-check
+// WARNING-NEXT: -Wmany-braces-around-scalar-init
+// WARNING-NEXT: -Wmax-unsigned-zero
+// RUN: %clang --autocomplete=-Wno-invalid-pp- | FileCheck %s -check-prefix=NOWARNING
+// NOWARNING: -Wno-invalid-pp-token
+// RUN: %clang --autocomplete=-analyzer-checker, | FileCheck %s -check-prefix=ANALYZER
+// ANALYZER: unix.Malloc
+// RUN: %clang --autocomplete=-std=, | FileCheck %s -check-prefix=STDVAL
+// STDVAL: c99
diff --git a/test/Driver/avr-mmcu.c b/test/Driver/avr-mmcu.c
new file mode 100644
index 0000000000..0d92ceb875
--- /dev/null
+++ b/test/Driver/avr-mmcu.c
@@ -0,0 +1,5 @@
+// A test for the propagation of the -mmcu option to -cc1 and -cc1as
+
+// RUN: %clang -### -target avr -no-canonical-prefixes -mmcu=atmega328p -save-temps %s 2>&1 | FileCheck %s
+// CHECK: clang{{.*}} "-cc1" {{.*}} "-target-cpu" "atmega328p"
+// CHECK: clang{{.*}} "-cc1as" {{.*}} "-target-cpu" "atmega328p"
diff --git a/test/Driver/baremetal.cpp b/test/Driver/baremetal.cpp
new file mode 100644
index 0000000000..a433e2df07
--- /dev/null
+++ b/test/Driver/baremetal.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target armv6m-none-eabi \
+// RUN: -T semihosted.lds \
+// RUN: -L some/directory/user/asked/for \
+// RUN: --sysroot=%S/Inputs/baremetal_arm \
+// RUN: | FileCheck --check-prefix=CHECK-V6M-C %s
+// CHECK-V6M-C: "[[PREFIX_DIR:.*]]{{[/\\]+}}{{[^/^\\]+}}{{[/\\]+}}clang{{.*}}" "-cc1" "-triple" "thumbv6m-none--eabi"
+// CHECK-V6M-C-SAME: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]"
+// CHECK-V6M-C-SAME: "-isysroot" "[[SYSROOT:[^"]*]]"
+// CHECK-V6M-C-SAME: "-internal-isystem" "[[SYSROOT]]{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1"
+// CHECk-V6M-C-SAME: "-internal-isystem" "[[SYSROOT]]{{[/\\]+}}include"
+// CHECK-V6M-C-SAME: "-x" "c++" "{{.*}}baremetal.cpp"
+// CHECK-V6M-C-NEXT: "{{[^"]*}}ld.lld{{(\.exe)?}}" "{{.*}}.o" "-Bstatic"
+// CHECK-V6M-C-SAME: "-L[[RESOURCE_DIR:[^"]+]]{{[/\\]+}}lib{{[/\\]+}}baremetal"
+// CHECK-V6M-C-SAME: "-T" "semihosted.lds" "-Lsome{{[/\\]+}}directory{{[/\\]+}}user{{[/\\]+}}asked{{[/\\]+}}for"
+// CHECK-V6M-C-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a"
+// CHECK-V6M-C-SAME: "-o" "{{.*}}.o"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target armv6m-none-eabi \
+// RUN: -nostdlibinc -nobuiltininc \
+// RUN: --sysroot=%S/Inputs/baremetal_arm \
+// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBINC %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target armv6m-none-eabi \
+// RUN: -nostdinc \
+// RUN: --sysroot=%S/Inputs/baremetal_arm \
+// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBINC %s
+// CHECK-V6M-LIBINC-NOT: "-internal-isystem"
+
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target armv6m-none-eabi \
+// RUN: --sysroot=%S/Inputs/baremetal_arm \
+// RUN: | FileCheck --check-prefix=CHECK-V6M-DEFAULTCXX %s
+// CHECK-V6M-DEFAULTCXX: "{{[^"]*}}ld.lld{{(\.exe)?}}" "{{.*}}.o" "-Bstatic"
+// CHECK-V6M-DEFAULTCXX-SAME: "-L{{[^"]*}}{{[/\\]+}}lib{{(64)?}}{{[/\\]+}}clang{{[/\\]+}}{{.*}}{{[/\\]+}}lib{{[/\\]+}}baremetal"
+// CHECK-V6M-DEFAULTCXX-SAME: "-lc++" "-lc++abi" "-lunwind"
+// CHECK-V6M-DEFAULTCXX-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a"
+// CHECK-V6M-DEFAULTCXX-SAME: "-o" "{{.*}}.o"
+
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target armv6m-none-eabi \
+// RUN: --sysroot=%S/Inputs/baremetal_arm \
+// RUN: -stdlib=libc++ \
+// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBCXX %s
+// CHECK-V6M-LIBCXX-NOT: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}{{[^v].*}}"
+// CHECK-V6M-LIBCXX: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1"
+// CHECK-V6M-LIBCXX: "{{[^"]*}}ld.lld{{(\.exe)?}}" "{{.*}}.o" "-Bstatic"
+// CHECK-V6M-LIBCXX-SAME: "-L{{[^"]*}}{{[/\\]+}}lib{{(64)?}}{{[/\\]+}}clang{{[/\\]+}}{{.*}}{{[/\\]+}}lib{{[/\\]+}}baremetal"
+// CHECK-V6M-LIBCXX-SAME: "-lc++" "-lc++abi" "-lunwind"
+// CHECK-V6M-LIBCXX-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a"
+// CHECK-V6M-LIBCXX-SAME: "-o" "{{.*}}.o"
+
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target armv6m-none-eabi \
+// RUN: --sysroot=%S/Inputs/baremetal_arm \
+// RUN: -stdlib=libstdc++ \
+// RUN: | FileCheck --check-prefix=CHECK-V6M-LIBSTDCXX %s
+// CHECK-V6M-LIBSTDCXX-NOT: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1"
+// CHECK-V6M-LIBSTDCXX: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}6.0.0"
+// CHECK-V6M-LIBSTDCXX: "{{[^"]*}}ld.lld{{(\.exe)?}}" "{{.*}}.o" "-Bstatic"
+// CHECK-V6M-LIBSTDCXX-SAME: "-L{{[^"]*}}{{[/\\]+}}lib{{(64)?}}{{[/\\]+}}clang{{[/\\]+}}{{.*}}{{[/\\]+}}lib{{[/\\]+}}baremetal"
+// CHECK-V6M-LIBSTDCXX-SAME: "-lstdc++" "-lsupc++" "-lunwind"
+// CHECK-V6M-LIBSTDCXX-SAME: "-lc" "-lm" "-lclang_rt.builtins-armv6m.a"
+// CHECK-V6M-LIBSTDCXX-SAME: "-o" "{{.*}}.o"
+
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target armv6m-none-eabi \
+// RUN: --sysroot=%S/Inputs/baremetal_arm \
+// RUN: -nodefaultlibs \
+// RUN: | FileCheck --check-prefix=CHECK-V6M-NDL %s
+// CHECK-V6M-NDL: "{{[^"]*}}ld.lld{{(\.exe)?}}" "{{.*}}.o" "-Bstatic"
+// CHECK-V6M-NDL-SAME: "-L{{[^"]*}}{{[/\\]+}}lib{{(64)?}}{{[/\\]+}}clang{{[/\\]+}}{{.*}}{{[/\\]+}}lib{{[/\\]+}}baremetal" "-o" "{{.*}}.o"
+
+// RUN: %clangxx -target arm-none-eabi -v 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-THREAD-MODEL
+// CHECK-THREAD-MODEL: Thread model: posix
+
+// RUN: %clangxx -target arm-none-eabi -mthread-model single -v 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-THREAD-MODEL-SINGLE
+// CHECK-THREAD-MODEL-SINGLE: Thread model: single
+
+// RUN: %clangxx -target arm-none-eabi -mthread-model posix -v 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-THREAD-MODEL-POSIX
+// CHECK-THREAD-MODEL-POSIX: Thread model: posix
diff --git a/test/Driver/bitrig.c b/test/Driver/bitrig.c
deleted file mode 100644
index a20a95aecd..0000000000
--- a/test/Driver/bitrig.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig %s -### 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-LD-C %s
-// CHECK-LD-C: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
-// CHECK-LD-C: ld{{.*}}" {{.*}} "-lc" "-lclang_rt.amd64"
-
-// RUN: %clangxx -stdlib=platform -no-canonical-prefixes -target amd64-pc-bitrig %s -### 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-LD-CXX-STDLIB %s
-// CHECK-LD-CXX-STDLIB: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
-// CHECK-LD-CXX-STDLIB: ld{{.*}}" {{.*}} "-lc++" "-lc++abi" "-lpthread" "-lm" "-lc" "-lclang_rt.amd64"
-
-// RUN: %clangxx -stdlib=libstdc++ -no-canonical-prefixes -target amd64-pc-bitrig %s -### 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-LD-CXX %s
-// CHECK-LD-CXX: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
-// CHECK-LD-CXX: ld{{.*}}" {{.*}} "-lstdc++" "-lm" "-lc" "-lclang_rt.amd64"
-
-// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig -pthread %s -### 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-PTHREAD %s
-// CHECK-PTHREAD: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
-// CHECK-PTHREAD: ld{{.*}}" {{.*}} "{{.*}}crtbegin.o" {{.*}}.o" "-lpthread" "-lc" "-lclang_rt.amd64" "{{.*}}crtend.o"
-
-// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig -pg -pthread %s -### 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-PG-PTHREAD %s
-// CHECK-PG-PTHREAD: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
-// CHECK-PG-PTHREAD: ld{{.*}}" {{.*}} "{{.*}}crtbegin.o" {{.*}}.o" "-lpthread_p" "-lc_p" "-lclang_rt.amd64" "{{.*}}crtend.o"
-
-// RUN: %clang -no-canonical-prefixes -target amd64-pc-bitrig -shared -pg -pthread %s -### 2>&1 \
-// RUN: | FileCheck --check-prefix=CHECK-PG-PTHREAD-SHARED %s
-// CHECK-PG-PTHREAD-SHARED: clang{{.*}}" "-cc1" "-triple" "amd64-pc-bitrig"
-// CHECK-PG-PTHREAD-SHARED: ld{{.*}}" {{.*}} "{{.*}}crtbeginS.o" {{.*}}.o" "-lpthread" "-lclang_rt.amd64" "{{.*}}crtendS.o"
diff --git a/test/Driver/cl-cc-flags.c b/test/Driver/cl-cc-flags.c
new file mode 100644
index 0000000000..76f116e199
--- /dev/null
+++ b/test/Driver/cl-cc-flags.c
@@ -0,0 +1,33 @@
+// Note: %s must be preceded by --, otherwise it may be interpreted as a
+// command-line option, e.g. on Mac where %s is commonly under /Users.
+
+// RUN: %clang_cl --target=i686-windows-msvc /Gd -### -- %s 2>&1 | FileCheck --check-prefix=CDECL %s
+// CDECL: -fdefault-calling-conv=cdecl
+
+// RUN: %clang_cl --target=i686-windows-msvc /Gr -### -- %s 2>&1 | FileCheck --check-prefix=FASTCALL %s
+// FASTCALL: -fdefault-calling-conv=fastcall
+
+// RUN: %clang_cl --target=i686-windows-msvc /Gz -### -- %s 2>&1 | FileCheck --check-prefix=STDCALL %s
+// STDCALL: -fdefault-calling-conv=stdcall
+
+// RUN: %clang_cl --target=i686-windows-msvc /Gv -### -- %s 2>&1 | FileCheck --check-prefix=VECTORCALL %s
+// VECTORCALL: -fdefault-calling-conv=vectorcall
+
+// Last one should win:
+
+// RUN: %clang_cl --target=i686-windows-msvc /Gd /Gv -### -- %s 2>&1 | FileCheck --check-prefix=LASTWINS_VECTOR %s
+// LASTWINS_VECTOR: -fdefault-calling-conv=vectorcall
+
+// RUN: %clang_cl --target=i686-windows-msvc /Gv /Gd -### -- %s 2>&1 | FileCheck --check-prefix=LASTWINS_CDECL %s
+// LASTWINS_CDECL: -fdefault-calling-conv=cdecl
+
+// No fastcall or stdcall on x86_64:
+
+// RUN: %clang_cl -Wno-msvc-not-found --target=x86_64-windows-msvc /Gr -### -- %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED %s
+// RUN: %clang_cl -Wno-msvc-not-found --target=x86_64-windows-msvc /Gz -### -- %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED %s
+// RUN: %clang_cl -Wno-msvc-not-found --target=thumbv7-windows-msvc /Gv -### -- %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED %s
+
+// UNSUPPORTED-NOT: error:
+// UNSUPPORTED-NOT: warning:
+// UNSUPPORTED-NOT: -fdefault-calling-conv=
+
diff --git a/test/Driver/cl-diagnostics.c b/test/Driver/cl-diagnostics.c
new file mode 100644
index 0000000000..975a8cf8bb
--- /dev/null
+++ b/test/Driver/cl-diagnostics.c
@@ -0,0 +1,28 @@
+// Note: %s must be preceded by --, otherwise it may be interpreted as a
+// command-line option, e.g. on Mac where %s is commonly under /Users.
+
+// RUN: %clang_cl /diagnostics:classic -### -- %s 2>&1 | FileCheck %s --check-prefix=CLASSIC
+// CLASSIC: -fno-caret-diagnostics
+// CLASSIC: -fno-show-column
+
+// RUN: %clang_cl /diagnostics:column -### -- %s 2>&1 | FileCheck %s --check-prefix=COLUMN
+// COLUMN: -fno-caret-diagnostics
+// COLUMN-NOT: -fno-show-column
+
+// RUN: %clang_cl /diagnostics:caret -### -- %s 2>&1 | FileCheck %s --check-prefix=CARET
+// CARET-NOT: -fno-caret-diagnostics
+// CARET-NOT: -fno-show-column
+
+// RUN: not %clang_cl -fms-compatibility-version=19 /diagnostics:classic /Zs -c -- %s 2>&1 | FileCheck %s --check-prefix=OUTPUT_CLASSIC
+
+// OUTPUT_CLASSIC: cl-diagnostics.c({{[0-9]+}}): error: "asdf"
+// OUTPUT_CLASSIC-NOT: #error
+
+// RUN: not %clang_cl -fms-compatibility-version=19 /diagnostics:caret /Zs -c -- %s 2>&1 | FileCheck %s --check-prefix=OUTPUT_CARET
+
+// OUTPUT_CARET: cl-diagnostics.c({{[0-9]+,[0-9]+}}): error: "asdf"
+// OUTPUT_CARET-NEXT: #error "asdf"
+// OUTPUT_CARET-NEXT: ^
+
+
+#error "asdf"
diff --git a/test/Driver/cl-include.c b/test/Driver/cl-include.c
new file mode 100644
index 0000000000..d3dc006e57
--- /dev/null
+++ b/test/Driver/cl-include.c
@@ -0,0 +1,14 @@
+// Note: %s must be preceded by --, otherwise it may be interpreted as a
+// command-line option, e.g. on Mac where %s is commonly under /Users.
+
+// RUN: %clang_cl -### -- %s 2>&1 | FileCheck %s --check-prefix=BUILTIN
+// BUILTIN: "-internal-isystem" "{{.*lib.*clang.*include}}"
+
+// RUN: %clang_cl -nobuiltininc -### -- %s 2>&1 | FileCheck %s --check-prefix=NOBUILTIN
+// NOBUILTIN-NOT: "-internal-isystem" "{{.*lib.*clang.*include}}"
+
+// RUN: env INCLUDE=/my/system/inc %clang_cl -### -- %s 2>&1 | FileCheck %s --check-prefix=STDINC
+// STDINC: "-internal-isystem" "/my/system/inc"
+
+// RUN: env INCLUDE=/my/system/inc %clang_cl -nostdinc -### -- %s 2>&1 | FileCheck %s --check-prefix=NOSTDINC
+// NOSTDINC-NOT: "-internal-isystem" "/my/system/inc"
diff --git a/test/Driver/cl-link-at-file.c b/test/Driver/cl-link-at-file.c
index 3a37e2f476..50ae07fadf 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 4cc170c1cb..142725fed8 100644
--- a/test/Driver/cl-link.c
+++ b/test/Driver/cl-link.c
@@ -56,4 +56,4 @@
// NONEXISTENT: nonexistent
// RUN: %clang_cl /Tc%s -fuse-ld=lld -### 2>&1 | FileCheck --check-prefix=USE_LLD %s
-// USE_LLD: lld-link.exe
+// USE_LLD: lld-link
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index c425e21dd7..2435ba2932 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -14,6 +14,9 @@
// C_P: "-E"
// C_P: "-C"
+// RUN: %clang_cl /d1reportAllClassLayout -### -- %s 2>&1 | FileCheck -check-prefix=d1reportAllClassLayout %s
+// d1reportAllClassLayout: -fdump-record-layouts
+
// RUN: %clang_cl /Dfoo=bar /D bar=baz /DMYDEF#value /DMYDEF2=foo#bar /DMYDEF3#a=b /DMYDEF4# \
// RUN: -### -- %s 2>&1 | FileCheck -check-prefix=D %s
// D: "-D" "foo=bar"
@@ -175,6 +178,9 @@
// Oy_2: -momit-leaf-frame-pointer
// Oy_2: -O2
+// RUN: %clang_cl --target=i686-pc-win32 -Werror /O2 /O2 -### -- %s 2>&1 | FileCheck -check-prefix=O2O2 %s
+// O2O2: "-O2"
+
// RUN: %clang_cl /Zs -Werror /Oy -- %s 2>&1
// RUN: %clang_cl --target=i686-pc-win32 -Werror /Oy- -### -- %s 2>&1 | FileCheck -check-prefix=Oy_ %s
@@ -191,8 +197,12 @@
// RUN: %clang_cl /E /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E %s
// RUN: %clang_cl /EP /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E %s
+// RUN: %clang_cl /E /EP /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E %s
// showIncludes_E: warning: argument unused during compilation: '--show-includes'
+// RUN: %clang_cl /EP /P /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E_And_P %s
+// showIncludes_E_And_P-NOT: warning: argument unused during compilation: '--show-includes'
+
// /source-charset: should warn on everything except UTF-8.
// RUN: %clang_cl /source-charset:utf-16 -### -- %s 2>&1 | FileCheck -check-prefix=source-charset-utf-16 %s
// source-charset-utf-16: invalid value 'utf-16'
@@ -296,11 +306,14 @@
// NOSTRICT: "-relaxed-aliasing"
// We recognize -f[no-]delayed-template-parsing.
+// /Zc:twoPhase[-] has the opposite meaning.
// RUN: %clang_cl -c -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDDEFAULT %s
// DELAYEDDEFAULT: "-fdelayed-template-parsing"
// RUN: %clang_cl -c -fdelayed-template-parsing -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDON %s
+// RUN: %clang_cl -c /Zc:twoPhase- -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDON %s
// DELAYEDON: "-fdelayed-template-parsing"
// RUN: %clang_cl -c -fno-delayed-template-parsing -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDOFF %s
+// RUN: %clang_cl -c /Zc:twoPhase -### -- %s 2>&1 | FileCheck -check-prefix=DELAYEDOFF %s
// DELAYEDOFF-NOT: "-fdelayed-template-parsing"
// For some warning ids, we can map from MSVC warning to Clang warning.
@@ -511,8 +524,11 @@
// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++14 -### -- %s 2>&1 | FileCheck -check-prefix=STDCXX14 %s
// STDCXX14: -std=c++14
+// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++17 -### -- %s 2>&1 | FileCheck -check-prefix=STDCXX17 %s
+// STDCXX17: -std=c++17
+
// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++latest -### -- %s 2>&1 | FileCheck -check-prefix=STDCXXLATEST %s
-// STDCXXLATEST: -std=c++1z
+// STDCXXLATEST: -std=c++2a
// RUN: env CL="/Gy" %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=ENV-CL %s
// ENV-CL: "-ffunction-sections"
@@ -558,6 +574,7 @@
// RUN: -fstandalone-debug \
// RUN: -flimit-debug-info \
// RUN: -flto \
+// RUN: --version \
// RUN: -Werror /Zs -- %s 2>&1
diff --git a/test/Driver/cl-outputs.c b/test/Driver/cl-outputs.c
index d79a577788..6e105e4685 100644
--- a/test/Driver/cl-outputs.c
+++ b/test/Driver/cl-outputs.c
@@ -73,7 +73,7 @@
// RUN: %clang_cl /c /o .. -### -- %s 2>&1 | FileCheck -check-prefix=oCRAZY2 %s
// oCRAZY2: "-o" "..obj"
-// RUN: %clang_cl /c %s -### /o 2>&1 | FileCheck -check-prefix=oMISSINGARG %s
+// RUN: not %clang_cl /c %s -### /o 2>&1 | FileCheck -check-prefix=oMISSINGARG %s
// oMISSINGARG: error: argument to '/o' is missing (expected 1 value)
// RUN: %clang_cl /c /omydir/ -### -- %s %s 2>&1 | FileCheck -check-prefix=CHECK-oMULTIPLESOURCEOK1 %s
@@ -208,7 +208,7 @@
// FeoDIRNAMEEXTDLL: "-out:foo.dir{{[/\\]+}}a.ext"
// FeoDIRNAMEEXTDLL: "-implib:foo.dir{{[/\\]+}}a.lib"
-// RUN: %clang_cl -### /o 2>&1 | FileCheck -check-prefix=FeoMISSINGARG %s
+// RUN: not %clang_cl -### /o 2>&1 | FileCheck -check-prefix=FeoMISSINGARG %s
// FeoMISSINGARG: error: argument to '/o' is missing (expected 1 value)
// RUN: %clang_cl /ofoo /o bar -### -- %s 2>&1 | FileCheck -check-prefix=FeoOVERRIDE %s
diff --git a/test/Driver/cl-zc.cpp b/test/Driver/cl-zc.cpp
index 2649629320..4414eb6ebb 100644
--- a/test/Driver/cl-zc.cpp
+++ b/test/Driver/cl-zc.cpp
@@ -53,6 +53,11 @@
// RUN: %clang_cl /c -### /Zc:inline- -- %s 2>&1 | FileCheck -check-prefix=INLINE-OFF %s
// INLINE-OFF: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:ternary -- %s 2>&1 | FileCheck -check-prefix=TERNARY-ON %s
+// TERNARY-ON-NOT: argument unused during compilation
+// RUN: %clang_cl /c -### /Zc:ternary- -- %s 2>&1 | FileCheck -check-prefix=TERNARY-OFF %s
+// TERNARY-OFF: argument unused during compilation
+
// These never warn, but don't have an effect yet.
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index 7c7b2f05f1..a09a60c9f3 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -69,12 +69,52 @@
// ARMV7_HARDFLOAT-NOT: "-msoft-float"
// ARMV7_HARDFLOAT: "-x" "c"
+// RUN: %clang -target arm64-apple-ios10 -### -S %s -arch arm64 2>&1 | \
+// RUN: FileCheck -check-prefix=ARM64-APPLE %s
+// ARM64-APPLE: -munwind-table
+
+// RUN: %clang -target arm64-apple-ios10 -### -ffreestanding -S %s -arch arm64 2>&1 | \
+// RUN: FileCheck -check-prefix=ARM64-FREESTANDING-APPLE %s
+//
+// RUN: %clang -target arm64-apple-ios10 -### -fno-unwind-tables -ffreestanding -S %s -arch arm64 2>&1 | \
+// RUN: FileCheck -check-prefix=ARM64-FREESTANDING-APPLE %s
+//
+// ARM64-FREESTANDING-APPLE-NOT: -munwind-table
+
+// RUN: %clang -target arm64-apple-ios10 -### -funwind-tables -S %s -arch arm64 2>&1 | \
+// RUN: FileCheck -check-prefix=ARM64-EXPLICIT-UWTABLE-APPLE %s
+//
+// RUN: %clang -target arm64-apple-ios10 -### -ffreestanding -funwind-tables -S %s -arch arm64 2>&1 | \
+// RUN: FileCheck -check-prefix=ARM64-EXPLICIT-UWTABLE-APPLE %s
+//
+// ARM64-EXPLICIT-UWTABLE-APPLE: -munwind-table
+
+// RUN: %clang -target arm64-apple-ios10 -fno-exceptions -### -S %s -arch arm64 2>&1 | \
+// RUN: FileCheck -check-prefix=ARM64-APPLE-EXCEP %s
+// ARM64-APPLE-EXCEP-NOT: -munwind-table
+
+// RUN: %clang -target armv7k-apple-watchos4.0 -### -S %s -arch armv7k 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMV7K-APPLE %s
+// ARMV7K-APPLE: -munwind-table
+
// RUN: %clang -target arm-linux -### -S %s -march=armv5e 2>&1 | \
// RUN: FileCheck -check-prefix=ARMV5E %s
// ARMV5E: clang
// ARMV5E: "-cc1"
// ARMV5E: "-target-cpu" "arm1022e"
+// RUN: %clang -target arm-linux -mtp=cp15 -### -S %s -arch armv7 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMv7_THREAD_POINTER-HARD %s
+// ARMv7_THREAD_POINTER-HARD: "-target-feature" "+read-tp-hard"
+
+// RUN: %clang -target arm-linux -mtp=soft -### -S %s -arch armv7 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMv7_THREAD_POINTER_SOFT %s
+// ARMv7_THREAD_POINTER_SOFT-NOT: "-target-feature" "+read-tp-hard"
+
+// RUN: %clang -target arm-linux -### -S %s -arch armv7 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMv7_THREAD_POINTER_NON %s
+// ARMv7_THREAD_POINTER_NON-NOT: "-target-feature" "+read-tp-hard"
+
// RUN: %clang -target powerpc64-unknown-linux-gnu \
// RUN: -### -S %s -mcpu=G5 2>&1 | FileCheck -check-prefix=PPCG5 %s
// PPCG5: clang
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 0261d93c49..b22f74fb55 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -1,7 +1,7 @@
// REQUIRES: clang-driver
// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fsplit-stack %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
-// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-asm -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-enums -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-asm -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-enums %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
// CHECK-OPTIONS1: -split-stacks
// CHECK-OPTIONS1: -fgnu-keywords
@@ -12,7 +12,6 @@
// CHECK-OPTIONS2: -fno-gnu-keywords
// CHECK-OPTIONS2: -fno-builtin
// CHECK-OPTIONS2: -fshort-enums
-// CHECK-OPTIONS2: -fshort-wchar
// CHECK-OPTIONS2: -fno-common
// CHECK-OPTIONS2: -fno-show-source-location
@@ -53,12 +52,22 @@
// CHECK-REROLL-LOOPS: "-freroll-loops"
// CHECK-NO-REROLL-LOOPS-NOT: "-freroll-loops"
+// RUN: %clang -### -S -fprofile-sample-accurate %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-SAMPLE-ACCURATE %s
+// CHECK-PROFILE-SAMPLE-ACCURATE: "-fprofile-sample-accurate"
+
// RUN: %clang -### -S -fprofile-sample-use=%S/Inputs/file.prof %s 2>&1 | FileCheck -check-prefix=CHECK-SAMPLE-PROFILE %s
// CHECK-SAMPLE-PROFILE: "-fprofile-sample-use={{.*}}/file.prof"
// 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
@@ -171,15 +180,8 @@
// CHECK-SLP-VECTORIZE: "-vectorize-slp"
// CHECK-NO-SLP-VECTORIZE-NOT: "-vectorize-slp"
-// RUN: %clang -### -S -fslp-vectorize-aggressive %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE-AGG %s
-// RUN: %clang -### -S -fno-slp-vectorize-aggressive -fslp-vectorize-aggressive %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE-AGG %s
-// RUN: %clang -### -S -fno-slp-vectorize-aggressive %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE-AGG %s
-// RUN: %clang -### -S -fslp-vectorize-aggressive -fno-slp-vectorize-aggressive %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE-AGG %s
-// CHECK-SLP-VECTORIZE-AGG: "-vectorize-slp-aggressive"
-// CHECK-NO-SLP-VECTORIZE-AGG-NOT: "-vectorize-slp-aggressive"
-
// RUN: %clang -### -S -fextended-identifiers %s 2>&1 | FileCheck -check-prefix=CHECK-EXTENDED-IDENTIFIERS %s
-// RUN: %clang -### -S -fno-extended-identifiers %s 2>&1 | FileCheck -check-prefix=CHECK-NO-EXTENDED-IDENTIFIERS %s
+// RUN: not %clang -### -S -fno-extended-identifiers %s 2>&1 | FileCheck -check-prefix=CHECK-NO-EXTENDED-IDENTIFIERS %s
// CHECK-EXTENDED-IDENTIFIERS: "-cc1"
// CHECK-EXTENDED-IDENTIFIERS-NOT: "-fextended-identifiers"
// CHECK-NO-EXTENDED-IDENTIFIERS: error: unsupported option '-fno-extended-identifiers'
@@ -356,6 +358,8 @@
// RUN: -ftree-vrp \
// RUN: -fno-devirtualize \
// RUN: -fno-devirtualize-speculatively \
+// RUN: -fslp-vectorize-aggressive \
+// RUN: -fno-slp-vectorize-aggressive \
// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
// CHECK-WARNING-DAG: optimization flag '-finline-limit=1000' is not supported
// CHECK-WARNING-DAG: optimization flag '-finline-limit' is not supported
@@ -422,6 +426,8 @@
// CHECK-WARNING-DAG: optimization flag '-ftree-vrp' is not supported
// CHECK-WARNING-DAG: optimization flag '-fno-devirtualize' is not supported
// CHECK-WARNING-DAG: optimization flag '-fno-devirtualize-speculatively' is not supported
+// CHECK-WARNING-DAG: the flag '-fslp-vectorize-aggressive' has been deprecated and will be ignored
+// CHECK-WARNING-DAG: the flag '-fno-slp-vectorize-aggressive' has been deprecated and will be ignored
// Test that we mute the warning on these
// RUN: %clang -### -finline-limit=1000 -Wno-invalid-command-line-argument \
@@ -459,15 +465,15 @@
// RUN: %clang -### -S -fno-unsigned-char %s 2>&1 | FileCheck -check-prefix=CHAR-SIGN4 %s
// CHAR-SIGN4-NOT: -fno-signed-char
-// RUN: %clang -### -fshort-wchar -fno-short-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-WCHAR1 -check-prefix=DELIMITERS %s
-// RUN: %clang -### -fno-short-wchar -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-WCHAR2 -check-prefix=DELIMITERS %s
+// RUN: %clang -target x86_64-unknown-none-none -### -fshort-wchar -fno-short-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-WCHAR1 -check-prefix=DELIMITERS %s
+// RUN: %clang -target x86_64-unknown-none-none -### -fno-short-wchar -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-WCHAR2 -check-prefix=DELIMITERS %s
// Make sure we don't match the -NOT lines with the linker invocation.
// Delimiters match the start of the cc1 and the start of the linker lines
// DELIMITERS: {{^ *"}}
-// CHECK-WCHAR1: -fno-short-wchar
-// CHECK-WCHAR1-NOT: -fshort-wchar
-// CHECK-WCHAR2: -fshort-wchar
-// CHECK-WCHAR2-NOT: -fno-short-wchar
+// CHECK-WCHAR1: -fwchar-type=int
+// CHECK-WCHAR1-NOT: -fwchar-type=short
+// CHECK-WCHAR2: -fwchar-type=short
+// CHECK-WCHAR2-NOT: -fwchar-type=int
// DELIMITERS: {{^ *"}}
// RUN: %clang -### -fno-experimental-new-pass-manager -fexperimental-new-pass-manager %s 2>&1 | FileCheck --check-prefix=CHECK-PM --check-prefix=CHECK-NEW-PM %s
@@ -487,3 +493,13 @@
// 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
+
+// RUN: %clang -### -S -fallow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-ALLOW-PLACEHOLDERS %s
+// RUN: %clang -### -S -fno-allow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-NO-ALLOW-PLACEHOLDERS %s
+// CHECK-ALLOW-PLACEHOLDERS: -fallow-editor-placeholders
+// CHECK-NO-ALLOW-PLACEHOLDERS-NOT: -fallow-editor-placeholders
+
+// RUN: %clang -### -target x86_64-unknown-windows-msvc -fno-short-wchar %s 2>&1 | FileCheck -check-prefix CHECK-WINDOWS-ISO10646 %s
+// CHECK-WINDOWS-ISO10646: "-fwchar-type=int"
+// CHECK-WINDOWS-ISO10646: "-fsigned-wchar"
+
diff --git a/test/Driver/compilation_database.c b/test/Driver/compilation_database.c
index d5bafd41a6..017178d60c 100644
--- a/test/Driver/compilation_database.c
+++ b/test/Driver/compilation_database.c
@@ -1,4 +1,4 @@
-// RUN: cd "%T"
+// RUN: mkdir -p %t && cd %t
// RUN: %clang -MD -MP --sysroot=somewhere -c -x c %s -xc++ %s -Wall -MJ - -no-canonical-prefixes 2>&1 | FileCheck %s
// RUN: not %clang -c -x c %s -MJ %s/non-existant -no-canonical-prefixes 2>&1 | FileCheck --check-prefix=ERROR %s
diff --git a/test/Driver/compress-noias.c b/test/Driver/compress-noias.c
new file mode 100644
index 0000000000..d20cf366b8
--- /dev/null
+++ b/test/Driver/compress-noias.c
@@ -0,0 +1,37 @@
+// REQUIRES: zlib
+// REQUIRES: x86-registered-target
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,-compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-_COMPRESS_DEBUG_SECTIONS %s
+// CHECK-_COMPRESS_DEBUG_SECTIONS: "-compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,--compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-__COMPRESS_DEBUG_SECTIONS %s
+// CHECK-__COMPRESS_DEBUG_SECTIONS: "--compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,--compress-debug-sections -Wa,--nocompress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-POSNEG %s
+// CHECK-POSNEG: "--compress-debug-sections"
+// CHECK-POSNEG: "--nocompress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,-compress-debug-sections -Wa,--compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-MULTIPLE %s
+// CHECK-MULTIPLE: "-compress-debug-sections"
+// CHECK-MULTIPLE: "--compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ %s
+// CHECK-OPT_GZ: "-compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=none -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_NONE %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=none -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_NONE %s
+// CHECK-OPT_GZ_EQ_NONE: "-compress-debug-sections=none"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB %s
+// CHECK-OPT_GZ_EQ_ZLIB: "-compress-debug-sections=zlib"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib-gnu -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB_GNU %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib-gnu -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB_GNU %s
+// CHECK-OPT_GZ_EQ_ZLIB_GNU: "-compress-debug-sections=zlib-gnu"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=invalid -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_INVALID %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=invalid -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_INVALID %s
+// CHECK-OPT_GZ_EQ_INVALID: error: unsupported argument 'invalid' to option 'gz='
+
diff --git a/test/Driver/compress.c b/test/Driver/compress.c
index 6cdc6b7224..a00ce91225 100644
--- a/test/Driver/compress.c
+++ b/test/Driver/compress.c
@@ -1,8 +1,36 @@
-// RUN: %clang -### -c -integrated-as -Wa,-compress-debug-sections %s 2>&1 | FileCheck --check-prefix=COMPRESS_DEBUG %s
-// RUN: %clang -### -c -integrated-as -Wa,--compress-debug-sections %s 2>&1 | FileCheck --check-prefix=COMPRESS_DEBUG %s
// REQUIRES: zlib
-// COMPRESS_DEBUG: "-compress-debug-sections"
+// RUN: %clang -### -fintegrated-as -Wa,-compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-_COMPRESS_DEBUG_SECTIONS %s
+// CHECK-_COMPRESS_DEBUG_SECTIONS: "-compress-debug-sections"
+
+// RUN: %clang -### -fintegrated-as -Wa,--compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-__COMPRESS_DEBUG_SECTIONS %s
+// CHECK-__COMPRESS_DEBUG_SECTIONS: "--compress-debug-sections"
+
+// RUN: %clang -### -fintegrated-as -Wa,--compress-debug-sections -Wa,--nocompress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-POSNEG %s
+// CHECK-POSNEG: "--compress-debug-sections"
+// CHECK-POSNEG: "--nocompress-debug-sections"
+
+// RUN: %clang -### -fintegrated-as -Wa,-compress-debug-sections -Wa,--compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-MULTIPLE %s
+// CHECK-MULTIPLE: "-compress-debug-sections"
+// CHECK-MULTIPLE: "--compress-debug-sections"
+
+// RUN: %clang -### -fintegrated-as -gz -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ %s
+// RUN: %clang -### -fintegrated-as -gz -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ %s
+// CHECK-OPT_GZ: "-compress-debug-sections"
+
+// RUN: %clang -### -fintegrated-as -gz=none -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_NONE %s
+// RUN: %clang -### -fintegrated-as -gz=none -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_NONE %s
+// CHECK-OPT_GZ_EQ_NONE: "-compress-debug-sections=none"
+
+// RUN: %clang -### -fintegrated-as -gz=zlib -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB %s
+// RUN: %clang -### -fintegrated-as -gz=zlib -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB %s
+// CHECK-OPT_GZ_EQ_ZLIB: "-compress-debug-sections=zlib"
+
+// RUN: %clang -### -fintegrated-as -gz=zlib-gnu -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB_GNU %s
+// RUN: %clang -### -fintegrated-as -gz=zlib-gnu -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB_GNU %s
+// CHECK-OPT_GZ_EQ_ZLIB_GNU: "-compress-debug-sections=zlib-gnu"
+
+// RUN: %clang -### -fintegrated-as -gz=invalid -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_INVALID %s
+// RUN: %clang -### -fintegrated-as -gz=invalid -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_INVALID %s
+// CHECK-OPT_GZ_EQ_INVALID: error: unsupported argument 'invalid' to option 'gz='
-// RUN: %clang -### -c -integrated-as -Wa,--compress-debug-sections -Wa,--nocompress-debug-sections %s 2>&1 | FileCheck --check-prefix=NOCOMPRESS_DEBUG %s
-// NOCOMPRESS_DEBUG-NOT: "-compress-debug-sections"
diff --git a/test/Driver/constructors.c b/test/Driver/constructors.c
index cd14ed736a..884fbe8466 100644
--- a/test/Driver/constructors.c
+++ b/test/Driver/constructors.c
@@ -6,6 +6,12 @@
//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/resource_dir \
+// RUN: --gcc-toolchain="" \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/fake_install_tree \
// RUN: --gcc-toolchain="" \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
@@ -74,3 +80,11 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target arm64-none-none-eabi \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target sparc-sun-solaris2.11 \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target i386-pc-solaris2.11 \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
diff --git a/test/Driver/cpath.c b/test/Driver/cpath.c
index ea6ba49d6d..7d63913810 100644
--- a/test/Driver/cpath.c
+++ b/test/Driver/cpath.c
@@ -1,20 +1,20 @@
-// RUN: mkdir -p %T/test1 %T/test2 %T/test3
+// RUN: mkdir -p %t/test1 %t/test2 %t/test3
-// RUN: env "CPATH=%T/test1%{pathsep}%T/test2" %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=CPATH
+// RUN: env "CPATH=%t/test1%{pathsep}%t/test2" %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=CPATH
// CPATH: -I{{.*}}/test1
// CPATH: -I{{.*}}/test2
// CPATH: search starts here
// CPATH: test1
// CPATH: test2
-// RUN: env "OBJC_INCLUDE_PATH=%T/test1%{pathsep}%T/test2" OBJCPLUS_INCLUDE_PATH=%T/test1 "CPLUS_INCLUDE_PATH=%T/test1%{pathsep}%t/test2" C_INCLUDE_PATH=%T/test3 %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=C_INCLUDE_PATH
+// RUN: env "OBJC_INCLUDE_PATH=%t/test1%{pathsep}%t/test2" OBJCPLUS_INCLUDE_PATH=%t/test1 "CPLUS_INCLUDE_PATH=%t/test1%{pathsep}%t/test2" C_INCLUDE_PATH=%t/test3 %clang -x c -E -v %s 2>&1 | FileCheck %s -check-prefix=C_INCLUDE_PATH
// C_INCLUDE_PATH: -c-isystem {{"?.*}}/test3{{"?}} -cxx-isystem {{"?.*}}/test1{{"?}} -cxx-isystem {{"?.*}}/test2{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objc-isystem {{"?.*}}/test2{{"?}} -objcxx-isystem {{"?.*}}/test1{{"?}}
// C_INCLUDE_PATH: search starts here
// C_INCLUDE_PATH-NOT: test1
// C_INCLUDE_PATH: test3
// C_INCLUDE_PATH-NOT: test1
-// RUN: env OBJC_INCLUDE_PATH=%T/test1 OBJCPLUS_INCLUDE_PATH=%T/test3 CPLUS_INCLUDE_PATH=%T/test3 C_INCLUDE_PATH=%T/test1 %clang -x objective-c++ -E -v %s 2>&1 | FileCheck %s -check-prefix=OBJCPLUS_INCLUDE_PATH
+// RUN: env OBJC_INCLUDE_PATH=%t/test1 OBJCPLUS_INCLUDE_PATH=%t/test3 CPLUS_INCLUDE_PATH=%t/test3 C_INCLUDE_PATH=%t/test1 %clang -x objective-c++ -E -v %s 2>&1 | FileCheck %s -check-prefix=OBJCPLUS_INCLUDE_PATH
// OBJCPLUS_INCLUDE_PATH: -c-isystem {{"?.*}}/test1{{"?}} -cxx-isystem {{"?.*}}/test3{{"?}} -objc-isystem {{"?.*}}/test1{{"?}} -objcxx-isystem {{"?.*}}/test3{{"?}}
// OBJCPLUS_INCLUDE_PATH: search starts here
// OBJCPLUS_INCLUDE_PATH-NOT: test1
diff --git a/test/Driver/crash-report-crashfile.m b/test/Driver/crash-report-crashfile.m
index 71f6e7a9e1..fbfb532703 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/crash report spaces.c b/test/Driver/crash-report-spaces.c
index 9bc4626b48..3e95a0de25 100644
--- a/test/Driver/crash report spaces.c
+++ b/test/Driver/crash-report-spaces.c
@@ -1,6 +1,7 @@
// RUN: rm -rf "%t"
// RUN: mkdir "%t"
-// RUN: not env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 %clang -fsyntax-only "%s" 2>&1 | FileCheck "%s"
+// RUN: cp "%s" "%t/crash report spaces.c"
+// RUN: not env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 %clang -fsyntax-only "%t/crash report spaces.c" 2>&1 | FileCheck "%s"
// RUN: cat "%t/crash report spaces"-*.c | FileCheck --check-prefix=CHECKSRC "%s"
// RUN: cat "%t/crash report spaces"-*.sh | FileCheck --check-prefix=CHECKSH "%s"
// REQUIRES: crash-recovery
diff --git a/test/Driver/cuda-arch-translation.cu b/test/Driver/cuda-arch-translation.cu
index 64ddb3178c..a26d3740ff 100644
--- a/test/Driver/cuda-arch-translation.cu
+++ b/test/Driver/cuda-arch-translation.cu
@@ -5,26 +5,36 @@
// REQUIRES: x86-registered-target
// REQUIRES: nvptx-registered-target
-// CHECK:fatbinary
-
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_20 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM20 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM20 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_21 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM21 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM21 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_30 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM30 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM30 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_32 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM32 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM32 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_35 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM35 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM35 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_37 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM37 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM37 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_50 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM50 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM50 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_52 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM52 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM52 %s
// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_53 %s 2>&1 \
-// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM53 %s
+// RUN: | FileCheck -check-prefixes=COMMON,SM53 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_60 %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=COMMON,SM60 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_61 %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=COMMON,SM61 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_62 %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=COMMON,SM62 %s
+// RUN: %clang -### -target x86_64-linux-gnu -c --cuda-gpu-arch=sm_70 %s 2>&1 \
+// RUN: | FileCheck -check-prefixes=COMMON,SM70 %s
+
+// COMMON: ptxas
+// COMMON-SAME: -m64
+// COMMON: fatbinary
// SM20:--image=profile=sm_20{{.*}}--image=profile=compute_20
// SM21:--image=profile=sm_21{{.*}}--image=profile=compute_20
@@ -35,3 +45,7 @@
// SM50:--image=profile=sm_50{{.*}}--image=profile=compute_50
// SM52:--image=profile=sm_52{{.*}}--image=profile=compute_52
// SM53:--image=profile=sm_53{{.*}}--image=profile=compute_53
+// SM60:--image=profile=sm_60{{.*}}--image=profile=compute_60
+// SM61:--image=profile=sm_61{{.*}}--image=profile=compute_61
+// SM62:--image=profile=sm_62{{.*}}--image=profile=compute_62
+// SM70:--image=profile=sm_70{{.*}}--image=profile=compute_70
diff --git a/test/Driver/cuda-bad-arch.cu b/test/Driver/cuda-bad-arch.cu
index cbc2d11f90..a6559b0c78 100644
--- a/test/Driver/cuda-bad-arch.cu
+++ b/test/Driver/cuda-bad-arch.cu
@@ -12,6 +12,12 @@
// BAD: error: Unsupported CUDA gpu architecture
+// RUN: %clang -### -v --target=x86_64-linux-gnu --cuda-gpu-arch=sm_21 \
+// RUN: --cuda-path=%S/Inputs/CUDA_90/usr/local/cuda %s 2>&1 \
+// RUN: | FileCheck -check-prefix BAD_CUDA9 %s
+
+// BAD_CUDA9: GPU arch sm_21 is supported by CUDA versions between 7.0 and 8.0
+
// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 -c %s 2>&1 \
// RUN: | FileCheck -check-prefix OK %s
// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_52 -c %s 2>&1 \
diff --git a/test/Driver/cuda-detect.cu b/test/Driver/cuda-detect.cu
index aaef89ac45..1db0cfbfa3 100644
--- a/test/Driver/cuda-detect.cu
+++ b/test/Driver/cuda-detect.cu
@@ -2,7 +2,7 @@
// REQUIRES: x86-registered-target
// REQUIRES: nvptx-registered-target
//
-// # Check that we properly detect CUDA installation.
+// Check that we properly detect CUDA installation.
// RUN: %clang -v --target=i386-unknown-linux \
// RUN: --sysroot=%S/no-cuda-there 2>&1 | FileCheck %s -check-prefix NOCUDA
// RUN: %clang -v --target=i386-apple-macosx \
@@ -18,6 +18,19 @@
// RUN: %clang -v --target=i386-apple-macosx \
// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda 2>&1 | FileCheck %s
+// Check that we don't find a CUDA installation without libdevice ...
+// RUN: %clang -v --target=i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NOCUDA
+// RUN: %clang -v --target=i386-apple-macosx \
+// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NOCUDA
+
+// ... unless the user doesn't need libdevice
+// RUN: %clang -v --target=i386-unknown-linux -nocudalib \
+// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE
+// RUN: %clang -v --target=i386-apple-macosx -nocudalib \
+// RUN: --sysroot=%S/Inputs/CUDA-nolibdevice 2>&1 | FileCheck %s -check-prefix NO-LIBDEVICE
+
+
// Make sure we map libdevice bitcode files to proper GPUs. These
// tests use Inputs/CUDA_80 which has full set of libdevice files.
// However, libdevice mapping only matches CUDA-7.x at the moment.
@@ -112,6 +125,7 @@
// RUN: | FileCheck %s --check-prefix CHECK-CXXINCLUDE
// CHECK: Found CUDA installation: {{.*}}/Inputs/CUDA/usr/local/cuda
+// NO-LIBDEVICE: Found CUDA installation: {{.*}}/Inputs/CUDA-nolibdevice/usr/local/cuda
// NOCUDA-NOT: Found CUDA installation:
// MISSINGLIBDEVICE: error: cannot find libdevice for sm_20.
diff --git a/test/Driver/cuda-external-tools.cu b/test/Driver/cuda-external-tools.cu
index f0f5c154c9..63b74fc06b 100644
--- a/test/Driver/cuda-external-tools.cu
+++ b/test/Driver/cuda-external-tools.cu
@@ -24,8 +24,8 @@
// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM20 -check-prefix DBG %s
// --no-cuda-noopt-device-debug overrides --cuda-noopt-device-debug.
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-noopt-debug \
-// RUN: --no-cuda-noopt-debug -O2 -c %s 2>&1 \
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-noopt-device-debug \
+// RUN: --no-cuda-noopt-device-debug -O2 -c %s 2>&1 \
// RUN: | FileCheck -check-prefix ARCH64 -check-prefix SM20 -check-prefix OPT2 %s
// Regular compile without -O. This should result in us passing -O0 to ptxas.
@@ -65,6 +65,10 @@
// RUN: %clang -### -target x86_32-apple-macosx -c %s 2>&1 \
// RUN: | FileCheck -check-prefix ARCH32 -check-prefix SM20 %s
+// Check that CLANG forwards the -v flag to PTXAS.
+// RUN: %clang -### -save-temps -no-canonical-prefixes -v %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-PTXAS-VERBOSE %s
+
// Match clang job that produces PTX assembly.
// CHECK: "-cc1" "-triple" "nvptx64-nvidia-cuda"
// SM20: "-target-cpu" "sm_20"
@@ -110,3 +114,5 @@
// Match the clang job for host compilation.
// CHECK: "-cc1" "-triple" "x86_64--linux-gnu"
// CHECK-SAME: "-fcuda-include-gpubinary" "[[FATBINARY]]"
+
+// CHK-PTXAS-VERBOSE: ptxas{{.*}}" "-v" \ No newline at end of file
diff --git a/test/Driver/cxa-atexit.cpp b/test/Driver/cxa-atexit.cpp
new file mode 100644
index 0000000000..01d4e20e77
--- /dev/null
+++ b/test/Driver/cxa-atexit.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang -### -target armv7-unknown-windows-msvc -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target armv7-unknown-windows-itanium -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target armv7-unknown-windows-gnu -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target armv7-unknown-windows-cygnus -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target i686-unknown-windows-msvc -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target i686-unknown-windows-itanium -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target i686-unknown-windows-gnu -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target i686-unknown-windows-cygnus -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target x86_64-unknown-windows-msvc -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target x86_64-unknown-windows-itanium -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target x86_64-unknown-windows-gnu -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target x86_64-unknown-windows-cygnus -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-WINDOWS
+// RUN: %clang -### -target hexagon-unknown-none -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-HEXAGON
+// RUN: %clang -### -target xcore-unknown-none -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-XCORE
+// RUN: %clang -### -target armv7-mti-none -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-MTI
+// RUN: %clang -### -target mips-unknown-none -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-MIPS
+// RUN: %clang -### -target mips-unknown-none-gnu -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-MIPS
+// RUN: %clang -### -target mips-mti-none-gnu -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-MIPS
+// RUN: %clang -### -target sparc-sun-solaris -c %s -o /dev/null 2>&1 | FileCheck %s -check-prefix CHECK-SOLARIS
+
+// CHECK-WINDOWS: "-fno-use-cxa-atexit"
+// CHECK-SOLARIS: "-fno-use-cxa-atexit"
+// CHECK-HEXAGON: "-fno-use-cxa-atexit"
+// CHECK-XCORE: "-fno-use-cxa-atexit"
+// CHECK-MTI: "-fno-use-cxa-atexit"
+// CHECK-MIPS-NOT: "-fno-use-cxa-atexit"
+
diff --git a/test/Driver/darwin-iphone-defaults.m b/test/Driver/darwin-iphone-defaults.m
index d98416d571..fe50bbda5a 100644
--- a/test/Driver/darwin-iphone-defaults.m
+++ b/test/Driver/darwin-iphone-defaults.m
@@ -26,4 +26,4 @@ void f1() {
[I1 alloc];
}
-// CHECK: attributes [[F0]] = { noinline ssp{{.*}} }
+// CHECK: attributes [[F0]] = { noinline optnone ssp{{.*}} }
diff --git a/test/Driver/darwin-ld-lto.c b/test/Driver/darwin-ld-lto.c
index 21c2214b77..2725df4f5f 100644
--- a/test/Driver/darwin-ld-lto.c
+++ b/test/Driver/darwin-ld-lto.c
@@ -2,11 +2,11 @@
// Check that ld gets "-lto_library".
-// RUN: mkdir -p %T/bin
-// RUN: mkdir -p %T/lib
-// RUN: touch %T/lib/libLTO.dylib
+// RUN: mkdir -p %t/bin
+// RUN: mkdir -p %t/lib
+// RUN: touch %t/lib/libLTO.dylib
// RUN: %clang -target x86_64-apple-darwin10 -### %s \
-// RUN: -ccc-install-dir %T/bin -mlinker-version=133 2> %t.log
+// RUN: -ccc-install-dir %t/bin -mlinker-version=133 2> %t.log
// RUN: FileCheck -check-prefix=LINK_LTOLIB_PATH %s -input-file %t.log
//
// LINK_LTOLIB_PATH: {{ld(.exe)?"}}
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 36e7ee5355..3ddba02a43 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -341,3 +341,27 @@
// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -### -o foo/bar.out 2> %t.log
// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS %s < %t.log
// PASS_REMARKS_WITH_HOTNESS: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-with-hotness"
+
+// RUN: %clang -target x86_64-apple-ios6.0 -miphoneos-version-min=6.0 -fprofile-instr-generate -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_PROFILE_FIRST %s < %t.log
+// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_PROFILE_FIRST %s < %t.log
+// RUN: %clang -target i386-apple-darwin9 -fprofile-instr-generate -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_PROFILE_FIRST %s < %t.log
+// RUN: %clang -target arm64-apple-ios5.0 -miphoneos-version-min=5.0 -fprofile-instr-generate -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=LINK_PROFILE_FIRST %s < %t.log
+// LINK_PROFILE_FIRST: {{ld(.exe)?"}} "{{[^"]+}}libclang_rt.profile_{{[a-z]+}}.a"
+
+// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -Wl,-exported_symbols_list,/dev/null -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=PROFILE_EXPORT %s < %t.log
+// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -Wl,-exported_symbol,foo -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=PROFILE_EXPORT %s < %t.log
+// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -Xlinker -exported_symbol -Xlinker foo -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=PROFILE_EXPORT %s < %t.log
+// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -Xlinker -exported_symbols_list -Xlinker /dev/null -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=PROFILE_EXPORT %s < %t.log
+// PROFILE_EXPORT: "-exported_symbol" "_VPMergeHook" "-exported_symbol" "___llvm_profile_filename" "-exported_symbol" "___llvm_profile_raw_version" "-exported_symbol" "_lprofCurFilename"
+//
+// RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -### %t.o 2> %t.log
+// RUN: FileCheck -check-prefix=NO_PROFILE_EXPORT %s < %t.log
+// NO_PROFILE_EXPORT-NOT: "-exported_symbol"
diff --git a/test/Driver/darwin-sdk-vs-os-version.c b/test/Driver/darwin-sdk-vs-os-version.c
new file mode 100644
index 0000000000..391f4d5a73
--- /dev/null
+++ b/test/Driver/darwin-sdk-vs-os-version.c
@@ -0,0 +1,10 @@
+// REQUIRES: system-darwin
+
+// Ensure that we never pick a version that's based on the SDK that's newer than
+// the system version:
+// RUN: rm -rf %t/SDKs/MacOSX10.99.99.sdk
+// RUN: mkdir -p %t/SDKs/MacOSX10.99.99.sdk
+// RUN: %clang -target x86_64-apple-darwin -isysroot %t/SDKs/MacOSX10.99.99.sdk %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MACOSX-SYSTEM-VERSION %s
+
+// CHECK-MACOSX-SYSTEM-VERSION-NOT: 10.99.99"
diff --git a/test/Driver/darwin-simulator-macro.c b/test/Driver/darwin-simulator-macro.c
new file mode 100644
index 0000000000..6971e9303a
--- /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/darwin-version.c b/test/Driver/darwin-version.c
index 009f8483a0..3ff49aca6c 100644
--- a/test/Driver/darwin-version.c
+++ b/test/Driver/darwin-version.c
@@ -10,6 +10,47 @@
// RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=3.0 -c %s -### 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS3 %s
// CHECK-VERSION-IOS3: "armv6k-apple-ios3.0.0"
+
+// RUN: env IPHONEOS_DEPLOYMENT_TARGET=11.0 \
+// RUN: %clang -target armv7-apple-ios9.0 -c -### %s 2> %t.err
+// RUN: FileCheck --input-file=%t.err --check-prefix=CHECK-VERSION-IOS4 %s
+// CHECK-VERSION-IOS4: invalid iOS deployment version 'IPHONEOS_DEPLOYMENT_TARGET=11.0'
+
+// RUN: %clang -target armv7-apple-ios9.0 -miphoneos-version-min=11.0 -c -### %s 2> %t.err
+// RUN: FileCheck --input-file=%t.err --check-prefix=CHECK-VERSION-IOS5 %s
+// CHECK-VERSION-IOS5: invalid iOS deployment version '-miphoneos-version-min=11.0'
+
+// RUN: %clang -target i386-apple-darwin -mios-simulator-version-min=11.0 -c -### %s 2> %t.err
+// RUN: FileCheck --input-file=%t.err --check-prefix=CHECK-VERSION-IOS6 %s
+// CHECK-VERSION-IOS6: invalid iOS deployment version '-mios-simulator-version-min=11.0'
+
+// RUN: %clang -target armv7-apple-ios11.1 -c -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS7 %s
+// RUN: %clang -target armv7-apple-ios9 -Wno-missing-sysroot -isysroot SDKs/iPhoneOS11.0.sdk -c -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS7 %s
+// CHECK-VERSION-IOS7: thumbv7-apple-ios10.99.99
+
+// RUN: env IPHONEOS_DEPLOYMENT_TARGET=11.0 \
+// RUN: %clang -target arm64-apple-ios11.0 -c -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS8 %s
+// CHECK-VERSION-IOS8: arm64-apple-ios11.0.0
+
+// RUN: %clang -target arm64-apple-ios11.0 -miphoneos-version-min=11.0 -c -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS9 %s
+// CHECK-VERSION-IOS9: arm64-apple-ios11.0.0
+
+// RUN: %clang -target x86_64-apple-darwin -mios-simulator-version-min=11.0 -c -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS10 %s
+// CHECK-VERSION-IOS10: x86_64-apple-ios11.0.0
+
+// RUN: %clang -target arm64-apple-ios11.1 -c -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS11 %s
+// CHECK-VERSION-IOS11: arm64-apple-ios11.1.0
+
+// RUN: %clang -target armv7-apple-ios9.0 -miphoneos-version-min=11.0 -c -Wno-invalid-ios-deployment-target -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS12 %s
+// CHECK-VERSION-IOS12: thumbv7-apple-ios11.0.0
+
// RUN: %clang -target i686-apple-darwin8 -c %s -### 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-VERSION-OSX4 %s
// RUN: %clang -target i686-apple-darwin9 -mmacosx-version-min=10.4 -c %s -### 2>&1 | \
@@ -29,9 +70,13 @@
// RUN: FileCheck --check-prefix=CHECK-VERSION-OSX10 %s
// RUN: %clang -target x86_64-apple-macosx -mmacosx-version-min=10.10 -c %s -### 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-VERSION-OSX10 %s
+// RUN: %clang -target x86_64-apple-macosx -mmacos-version-min=10.10 -c %s -### 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-OSX10 %s
// CHECK-VERSION-OSX10: "x86_64-apple-macosx10.10.0"
// RUN: %clang -target x86_64-apple-macosx -mmacosx-version-min= -c %s -### 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-VERSION-MISSING %s
+// RUN: %clang -target x86_64-apple-macosx -mmacos-version-min= -c %s -### 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-MISSING %s
// CHECK-VERSION-MISSING: invalid version number
// RUN: %clang -target armv7k-apple-darwin -mwatchos-version-min=2.0 -c %s -### 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-VERSION-WATCHOS20 %s
@@ -82,3 +127,15 @@
// RUN: %clang -target i386-apple-darwin9 -c %s -### 2>&1 | \
// RUN: FileCheck --check-prefix=CHECK-VERSION-WATCHOSSIM %s
// CHECK-VERSION-WATCHOSSIM: "i386-apple-watchos2.0.0"
+
+// RUN: %clang -target x86_64-apple-ios11.0.0 -c %s -### 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS-TARGET %s
+// CHECK-VERSION-IOS-TARGET: "x86_64-apple-ios11.0.0"
+
+// RUN: %clang -target x86_64-apple-tvos11.0 -c %s -### 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-TVOS-TARGET %s
+// CHECK-VERSION-TVOS-TARGET: "x86_64-apple-tvos11.0.0"
+
+// RUN: %clang -target x86_64-apple-watchos4.0 -c %s -### 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-VERSION-WATCHOS-TARGET %s
+// CHECK-VERSION-WATCHOS-TARGET: "x86_64-apple-watchos4.0.0"
diff --git a/test/Driver/debug-options.c b/test/Driver/debug-options.c
index be50ee8af7..3bec1e141d 100644
--- a/test/Driver/debug-options.c
+++ b/test/Driver/debug-options.c
@@ -76,11 +76,13 @@
// RUN: | FileCheck -check-prefix=NOCI %s
// RUN: %clang -### -c %s -g -gcolumn-info -target x86_64-scei-ps4 2>&1 \
// RUN: | FileCheck -check-prefix=CI %s
+// RUN: %clang -### -c %s -gsce -target x86_64-unknown-linux 2>&1 \
+// RUN: | FileCheck -check-prefix=NOCI %s
// RUN: %clang -### -c -gdwarf-2 %s 2>&1 \
// RUN: | FileCheck -check-prefix=G_ONLY_DWARF2 %s
//
-// RUN: %clang -### -c -gfoo %s 2>&1 | FileCheck -check-prefix=G_NO %s
+// RUN: not %clang -### -c -gfoo %s 2>&1 | FileCheck -check-prefix=G_ERR %s
// RUN: %clang -### -c -g -g0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
// RUN: %clang -### -c -ggdb0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
// RUN: %clang -### -c -glldb -g0 %s 2>&1 | FileCheck -check-prefix=G_NO %s
@@ -117,8 +119,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
@@ -161,6 +173,8 @@
// G_PS4: "-dwarf-version=
// G_PS4: "-generate-arange-section"
//
+// G_ERR: error: unknown argument:
+//
// G_NO: "-cc1"
// G_NO-NOT: -debug-info-kind=
//
@@ -194,9 +208,20 @@
// 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
+// GOPT: -ggnu-pubnames
//
// GARANGE: -generate-arange-section
//
diff --git a/test/Driver/emulated-tls.cpp b/test/Driver/emulated-tls.cpp
index a18c2e220b..38edc98ac8 100644
--- a/test/Driver/emulated-tls.cpp
+++ b/test/Driver/emulated-tls.cpp
@@ -1,5 +1,7 @@
-// Cygwin uses emutls. Clang should pass -femulated-tls to cc1 and cc1 should pass EmulatedTLS to LLVM CodeGen.
+// Cygwin and OpenBSD use emutls. Clang should pass -femulated-tls to cc1
+// and cc1 should pass EmulatedTLS to LLVM CodeGen.
// FIXME: Add more targets here to use emutls.
// RUN: %clang -### -std=c++11 -target i686-pc-cygwin %s 2>&1 | FileCheck %s
+// RUN: %clang -### -std=c++11 -target i686-pc-openbsd %s 2>&1 | FileCheck %s
// CHECK: "-cc1" {{.*}}"-femulated-tls"
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
index 025651d0a3..5094a5bc1a 100644
--- a/test/Driver/fast-math.c
+++ b/test/Driver/fast-math.c
@@ -93,6 +93,8 @@
// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
// RUN: %clang -### -target x86_64-unknown-dragonfly -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
+// RUN: %clang -### -target x86_64-fuchsia -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-MATH-ERRNO %s
//
// Check that -ffast-math disables -fmath-errno, and -fno-fast-math merely
// preserves the target default. Also check various flag set operations between
@@ -148,20 +150,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 +192,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 +207,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/flags.c b/test/Driver/flags.c
index ff60caf2e0..656ac41a94 100644
--- a/test/Driver/flags.c
+++ b/test/Driver/flags.c
@@ -24,3 +24,6 @@
// RUN: %clang -target armv7-apple-darwin10 -### -S -mno-implicit-float -mimplicit-float %s 2>&1 | FileCheck -check-prefix=TEST8 %s
// TEST8-NOT: "-no-implicit-float"
+
+// RUN: %clang -target x86_64-linux-gnu -### -c -fclang-abi-compat=3.2 %s 2>&1 | FileCheck -check-prefix=TEST9 %s
+// TEST9: "-fclang-abi-compat=3.2"
diff --git a/test/Driver/fopenmp.c b/test/Driver/fopenmp.c
index ea4284ef6e..ac0f1b44cb 100644
--- a/test/Driver/fopenmp.c
+++ b/test/Driver/fopenmp.c
@@ -18,7 +18,7 @@
// CHECK-CC1-NO-OPENMP-NOT: "-fopenmp"
//
// RUN: %clang -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
-// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP
+// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-RT
// RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
//
// RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
@@ -26,21 +26,25 @@
// RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
//
// RUN: %clang -target x86_64-darwin -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
-// RUN: %clang -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP
+// RUN: %clang -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT
// RUN: %clang -target x86_64-darwin -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
//
// RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
// RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP
// RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
//
-// RUN: %clang -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
-// RUN: %clang -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP
-// RUN: %clang -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
+// RUN: %clang -target x86_64-freebsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
+// RUN: %clang -target x86_64-freebsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT
+// RUN: %clang -target x86_64-freebsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
//
// RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
// RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP
// RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
//
+// RUN: %clang -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
+// RUN: %clang -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT
+// RUN: %clang -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
+//
// RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
// RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP
// RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
@@ -50,6 +54,8 @@
//
// CHECK-LD-GOMP: "{{.*}}ld{{(.exe)?}}"
// CHECK-LD-GOMP: "-lgomp"
+// CHECK-LD-GOMP-RT: "-lrt"
+// CHECK-LD-GOMP-NO-RT-NOT: "-lrt"
//
// CHECK-LD-IOMP5: "{{.*}}ld{{(.exe)?}}"
// CHECK-LD-IOMP5: "-liomp5"
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index f008b76b93..0f89d25ac4 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -127,7 +127,7 @@
// RUN: %clang -target x86_64-pc-freebsd8 %s -### -flto 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-LTO %s
-// CHECK-LTO: ld{{.*}}" "-plugin{{.*}}LLVMgold.so
+// CHECK-LTO: ld{{.*}}" "-plugin{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}
// RUN: %clang -target sparc-unknown-freebsd8 %s -### -fpic -no-integrated-as 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-SPARC-PIE %s
diff --git a/test/Driver/fsanitize-blacklist.c b/test/Driver/fsanitize-blacklist.c
index adf776fcae..9268bb2b48 100644
--- a/test/Driver/fsanitize-blacklist.c
+++ b/test/Driver/fsanitize-blacklist.c
@@ -23,6 +23,12 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-BLACKLIST --implicit-check-not=fdepfile-entry
// CHECK-DEFAULT-BLACKLIST: -fsanitize-blacklist={{.*}}asan_blacklist.txt
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=nullability -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=alignment -resource-dir=%S/Inputs/resource_dir %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DEFAULT-UBSAN-BLACKLIST --implicit-check-not=fdepfile-entry
+// CHECK-DEFAULT-UBSAN-BLACKLIST: -fsanitize-blacklist={{.*}}ubsan_blacklist.txt
+
// Ignore -fsanitize-blacklist flag if there is no -fsanitize flag.
// RUN: %clang -target x86_64-linux-gnu -fsanitize-blacklist=%t.good %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SANITIZE --check-prefix=DELIMITERS
// CHECK-NO-SANITIZE-NOT: -fsanitize-blacklist
diff --git a/test/Driver/fsanitize-coverage.c b/test/Driver/fsanitize-coverage.c
index b04e71e90c..cd05cfdb7a 100644
--- a/test/Driver/fsanitize-coverage.c
+++ b/test/Driver/fsanitize-coverage.c
@@ -4,12 +4,14 @@
// CHECK-SANITIZE-COVERAGE-0-NOT: fsanitize-coverage-type
// CHECK-SANITIZE-COVERAGE-0: -fsanitize=address
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=bool -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=dataflow -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=kernel-address -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=leak -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=bool -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=dataflow -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=func,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
// CHECK-SANITIZE-COVERAGE-FUNC: fsanitize-coverage-type=1
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-BB
@@ -23,34 +25,22 @@
// CHECK-SANITIZE-COVERAGE-FUNC_INDIR: fsanitize-coverage-indirect-calls
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-1
-// CHECK-SANITIZE-COVERAGE-1: warning: argument '-fsanitize-coverage=1' is deprecated, use '-fsanitize-coverage=func' instead
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=2 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-2
-// CHECK-SANITIZE-COVERAGE-2: warning: argument '-fsanitize-coverage=2' is deprecated, use '-fsanitize-coverage=bb' instead
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=3 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-3
-// CHECK-SANITIZE-COVERAGE-3: warning: argument '-fsanitize-coverage=3' is deprecated, use '-fsanitize-coverage=edge' instead
-//
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=5 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-5
-// CHECK-SANITIZE-COVERAGE-5: error: unsupported argument '5' to option 'fsanitize-coverage='
-
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-UNUSED
-// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FUNC
-// CHECK-SANITIZE-COVERAGE-UNUSED: argument unused during compilation: '-fsanitize-coverage=func'
-// CHECK-SANITIZE-COVERAGE-UNUSED-NOT: -fsanitize-coverage-type=1
-
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-SAN-DISABLED
-// CHECK-SANITIZE-COVERAGE-SAN-DISABLED-NOT: argument unused
-
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-bb,trace-pc,trace-cmp,8bit-counters,trace-div,trace-gep %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES
+// CHECK-SANITIZE-COVERAGE-1: warning: argument '-fsanitize-coverage=1' is deprecated, use '-fsanitize-coverage=trace-pc-guard' instead
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_FUNC_BB_EDGE_DEPRECATED
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_FUNC_BB_EDGE_DEPRECATED
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_FUNC_BB_EDGE_DEPRECATED
+// CHECK_FUNC_BB_EDGE_DEPRECATED: warning: argument '-fsanitize-coverage=[func|bb|edge]' is deprecated, use '-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]' instead
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-pc,trace-cmp,trace-div,trace-gep %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANITIZE-COVERAGE-FEATURES
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-type=3
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-indirect-calls
-// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-bb
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-cmp
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-div
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-gep
-// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-8bit-counters
// CHECK-SANITIZE-COVERAGE-FEATURES: -fsanitize-coverage-trace-pc
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,edge,indirect-calls,trace-bb,trace-cmp -fno-sanitize-coverage=edge,indirect-calls,trace-bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MASK
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func,edge,indirect-calls,trace-cmp -fno-sanitize-coverage=edge,indirect-calls %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MASK
// CHECK-MASK: -fsanitize-coverage-type=1
// CHECK-MASK: -fsanitize-coverage-trace-cmp
// CHECK-MASK-NOT: -fsanitize-coverage-
@@ -61,8 +51,10 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=func -fsanitize-coverage=edge %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INCOMPATIBLE
// CHECK-INCOMPATIBLE: error: invalid argument '-fsanitize-coverage=func' not allowed with '-fsanitize-coverage=edge'
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING-TYPE
-// CHECK-MISSING-TYPE: error: invalid argument '-fsanitize-coverage=8bit-counters' only allowed with '-fsanitize-coverage=(func|bb|edge)'
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-8BIT
+// CHECK-8BIT: warning: argument '-fsanitize-coverage=8bit-counters' is deprecated, use '-fsanitize-coverage=trace-pc-guard' instead
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE-BB
+// CHECK-TRACE-BB: warning: argument '-fsanitize-coverage=trace-bb' is deprecated, use '-fsanitize-coverage=trace-pc-guard' instead
// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE_PC_EDGE
// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=edge,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACE_PC_EDGE
@@ -80,6 +72,17 @@
// CHECK-TRACE_PC_GUARD_FUNC: -fsanitize-coverage-type=1
// CHECK-TRACE_PC_GUARD_FUNC: -fsanitize-coverage-trace-pc-guard
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=stack-depth %s \
+// RUN: -### 2>&1 | FileCheck %s --check-prefix=CHECK-STACK-DEPTH
+// RUN: %clang -target x86_64-linux-gnu \
+// RUN: -fsanitize-coverage=trace-pc-guard,stack-depth %s -### 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-STACK-DEPTH-PC-GUARD
+// CHECK-STACK-DEPTH: -fsanitize-coverage-type=1
+// CHECK-STACK-DEPTH: -fsanitize-coverage-stack-depth
+// CHECK-STACK-DEPTH-PC-GUARD: -fsanitize-coverage-type=3
+// CHECK-STACK-DEPTH-PC-GUARD: -fsanitize-coverage-trace-pc-guard
+// CHECK-STACK-DEPTH-PC-GUARD: -fsanitize-coverage-stack-depth
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-coverage=trace-cmp,indirect-calls %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TYPE-NECESSARY
// CHECK-NO-TYPE-NECESSARY-NOT: error:
// CHECK-NO-TYPE-NECESSARY: -fsanitize-coverage-indirect-calls
@@ -89,10 +92,35 @@
// CHECK-EXTEND-LEGACY: -fsanitize-coverage-type=1
// CHECK-EXTEND-LEGACY: -fsanitize-coverage-trace-cmp
-// RUN: %clang_cl --target=i386-pc-win32 -fsanitize=address -fsanitize-coverage=func -c -### -- %s 2>&1 | FileCheck %s -check-prefix=CLANG-CL-COVERAGE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=no-prune,trace-pc %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_NOPRUNE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=no-prune,func,trace-pc-guard %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_NOPRUNE
+// CHECK_NOPRUNE: -fsanitize-coverage-no-prune
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=inline-8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_INLINE8BIT
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=bb,inline-8bit-counters %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_INLINE8BIT
+// CHECK_INLINE8BIT-NOT: warning
+// CHECK_INLINE8BIT: -fsanitize-coverage-inline-8bit-counters
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=inline-8bit-counters,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-coverage=trace-pc-guard,pc-table %s -### 2>&1 | FileCheck %s --check-prefix=CHECK_PC_TABLE
+// CHECK_PC_TABLE: -fsanitize-coverage-pc-table
+
+// RUN: %clang_cl --target=i386-pc-win32 -fsanitize=address -fsanitize-coverage=func,trace-pc-guard -c -### -- %s 2>&1 | FileCheck %s -check-prefix=CLANG-CL-COVERAGE
// CLANG-CL-COVERAGE-NOT: error:
// CLANG-CL-COVERAGE-NOT: warning:
// CLANG-CL-COVERAGE-NOT: argument unused
// CLANG-CL-COVERAGE-NOT: unknown argument
// CLANG-CL-COVERAGE: -fsanitize-coverage-type=1
// CLANG-CL-COVERAGE: -fsanitize=address
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=safe-stack -fsanitize-coverage=trace-pc-guard %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VS-SAFESTACK
+// CHECK-VS-SAFESTACK: -fsanitize=safe-stack
+// CHECK-VS-SAFESTACK-NOT: -fsanitize-coverage-trace-pc-guard
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=safe-stack -fsanitize-coverage=trace-pc-guard -fno-sanitize=safe-stack %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SAFESTACK
+// CHECK-NO-SAFESTACK-NOT: error:
+// CHECK-NO-SAFESTACK-NOT: warning:
+// CHECK-NO-SAFESTACK-NOT: argument unused
+// CHECK-NO-SAFESTACK-NOT: unknown argument
+// CHECK-NO-SAFESTACK-NOT: -fsanitize=safe-stack
+// CHECK-NO-SAFESTACK: -fsanitize-coverage-trace-pc-guard
diff --git a/test/Driver/fsanitize-object-size.c b/test/Driver/fsanitize-object-size.c
new file mode 100644
index 0000000000..b96221e0fd
--- /dev/null
+++ b/test/Driver/fsanitize-object-size.c
@@ -0,0 +1,31 @@
+// Check that the object size check is disabled at -O0.
+//
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size %s -O0 -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=null,object-size %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-NO-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-NO-OSIZE-NO-WARNING
+
+// Check that the object size check is enabled at other optimization levels.
+//
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -O1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size -O2 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size -O3 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size -O4 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size -Ofast %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size -Os %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size -Oz %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=object-size -Og %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+
+// Use of trap mode shouldn't affect the object size check.
+//
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-trap=undefined -O1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -O1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -O1 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HAS-OSIZE
+
+// CHECK-HAS-OSIZE-NOT: warning: the object size sanitizer
+// CHECK-HAS-OSIZE: -fsanitize={{[^ ]*}}object-size
+
+// CHECK-NO-OSIZE: warning: the object size sanitizer has no effect at -O0, but is explicitly enabled: -fsanitize={{[^ ]*}}object-size
+// CHECK-NO-OSIZE-NOT: -fsanitize={{[^ ]*}}object-size
+
+// CHECK-NO-OSIZE-NO-WARNING-NOT: -fsanitize={{[^ ]*}}object-size
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index c5a8e11406..dcca96ff3a 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -3,18 +3,18 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
// RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
-// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
-// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
-// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
+// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){19}"}}
+// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
-// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
+// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){20}"}}
// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN
-// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
+// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
// RUN: %clang -target i386-unknown-openbsd -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-OPENBSD
-// CHECK-UNDEFINED-OPENBSD: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
+// CHECK-UNDEFINED-OPENBSD: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
// RUN: %clang -target i386-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32
// RUN: %clang -target i386-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN32 --check-prefix=CHECK-UNDEFINED-WIN-CXX
@@ -23,14 +23,14 @@
// CHECK-UNDEFINED-WIN32: "--dependent-lib={{[^"]*}}ubsan_standalone-i386.lib"
// CHECK-UNDEFINED-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone-x86_64.lib"
// CHECK-UNDEFINED-WIN-CXX: "--dependent-lib={{[^"]*}}ubsan_standalone_cxx{{[^"]*}}.lib"
-// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
+// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
// RUN: %clang -target i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COVERAGE-WIN32
// CHECK-COVERAGE-WIN32: "--dependent-lib={{[^"]*}}ubsan_standalone-i386.lib"
// RUN: %clang -target x86_64-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-COVERAGE-WIN64
// CHECK-COVERAGE-WIN64: "--dependent-lib={{[^"]*}}ubsan_standalone-x86_64.lib"
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER -implicit-check-not="-fsanitize-address-use-after-scope"
// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent),?){5}"}}
// RUN: %clang -fsanitize=bounds -### -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK-BOUNDS
@@ -42,8 +42,8 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,undefined -fno-sanitize=all -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FNO-SANITIZE-ALL
// CHECK-FNO-SANITIZE-ALL: "-fsanitize=thread"
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
-// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|object-size|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){15}"}}
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,builtin,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){15}"}}
// RUN: %clang -target x86_64-linux-gnu -fsanitize=shift -fno-sanitize=shift-base %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSANITIZE-SHIFT-PARTIAL
// CHECK-FSANITIZE-SHIFT-PARTIAL: "-fsanitize=shift-exponent"
@@ -109,19 +109,29 @@
// 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=address -fsanitize-address-globals-dead-stripping %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-GLOBALS
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ASAN-GLOBALS
+// RUN: %clang_cl --target=x86_64-windows-msvc -fsanitize=address -fsanitize-address-globals-dead-stripping -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-GLOBALS
+// RUN: %clang_cl --target=x86_64-windows-msvc -fsanitize=address -### -- %s 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-GLOBALS
+// CHECK-ASAN-GLOBALS: -cc1{{.*}}-fsanitize-address-globals-dead-stripping
+// CHECK-NO-ASAN-GLOBALS-NOT: -cc1{{.*}}-fsanitize-address-globals-dead-stripping
// 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'
@@ -162,8 +172,14 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins=3 -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TRACK-ORIGINS-3
// CHECK-TRACK-ORIGINS-3: error: invalid value '3' in '-fsanitize-memory-track-origins=3'
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-use-after-dtor -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-USE-AFTER-DTOR
-// CHECK-MSAN-USE-AFTER-DTOR: -cc1{{.*}}-fsanitize-memory-use-after-dtor
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-use-after-dtor %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-DTOR
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fno-sanitize-memory-use-after-dtor -fsanitize-memory-use-after-dtor %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-DTOR
+// CHECK-USE-AFTER-DTOR: -cc1{{.*}}-fsanitize-memory-use-after-dtor
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fno-sanitize-memory-use-after-dtor %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-DTOR-OFF
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-use-after-dtor -fno-sanitize-memory-use-after-dtor %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-DTOR-OFF
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-USE-AFTER-DTOR-OFF
+// CHECK-USE-AFTER-DTOR-OFF-NOT: -cc1{{.*}}memory-use-after-dtor
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-field-padding=0 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FIELD-PADDING-0
// CHECK-ASAN-FIELD-PADDING-0-NOT: -fsanitize-address-field-padding
@@ -186,7 +202,9 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE
// RUN: %clang -target x86_64-unknown-freebsd -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE
// RUN: %clang -target aarch64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE
-// RUN: %clang -target arm-linux-androideabi -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE
+// RUN: %clang -target arm-linux-androideabi -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIC-NO-PIE
+// RUN: %clang -target arm-linux-androideabi24 -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE
+// RUN: %clang -target aarch64-linux-android -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE
// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE
// RUN: %clang -target i386-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE
@@ -194,6 +212,10 @@
// CHECK-NO-PIE: "-mrelocation-model" "static"
// CHECK-NO-PIE-NOT: "-pie"
+// CHECK-PIC-NO-PIE-NOT: "-pie"
+// CHECK-PIC-NO-PIE: "-mrelocation-model" "pic"
+// CHECK-PIC-NO-PIE-NOT: "-pie"
+
// CHECK-PIE: "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie"
// CHECK-PIE: "-pie"
@@ -207,11 +229,11 @@
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fsanitize-recover=all -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
-// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute),?){17}"}}
+// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|vptr|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
// CHECK-NO-RECOVER-UBSAN-NOT: sanitize-recover
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined -fno-sanitize-recover=all -fsanitize-recover=object-size,shift-base -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER
-// CHECK-PARTIAL-RECOVER: "-fsanitize-recover={{((object-size|shift-base),?){2}"}}
+// CHECK-PARTIAL-RECOVER: "-fsanitize-recover={{((shift-base),?){1}"}}
// RUN: %clang -target x86_64-linux-gnu %s -fsanitize=address -fsanitize-recover=all -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER-ASAN
// CHECK-RECOVER-ASAN: "-fsanitize-recover=address"
@@ -237,6 +259,39 @@
// 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 mips-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-MIPS
+// CHECK-SANL-MIPS: unsupported option '-fsanitize=leak' for target 'mips-unknown-linux'
+
+// RUN: %clang -target powerpc64-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-PPC64
+// RUN: %clang -target powerpc64le-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-PPC64
+// CHECK-SANL-PPC64: "-fsanitize=leak"
+// RUN: %clang -target powerpc-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-PPC
+// CHECK-SANL-PPC: unsupported option '-fsanitize=leak' for target 'powerpc-unknown-linux'
+
// 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
@@ -314,10 +369,8 @@
// CHECK-TSAN-ATOMICS-BOTH-OFF: -cc1{{.*}}tsan-instrument-atomics=0
// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-DARWIN
-// CHECK-FSAN-DARWIN: unsupported option '-fsanitize=function' for target 'x86_64-apple-darwin10'
-
-// RUN: %clang -target x86_64-apple-darwin10 -fsanitize=function -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-UBSAN-DARWIN
-// CHECK-FSAN-UBSAN-DARWIN: unsupported option '-fsanitize=function' for target 'x86_64-apple-darwin10'
+// RUN: %clang -target i386-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-DARWIN
+// CHECK-FSAN-DARWIN: -cc1{{.*}}"-fsanitize=function" "-fsanitize-recover=function"
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.8 -fsanitize=vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-DARWIN-OLD
// CHECK-VPTR-DARWIN-OLD: unsupported option '-fsanitize=vptr' for target 'x86_64-apple-darwin10'
@@ -331,6 +384,27 @@
// RUN: %clang -target i386-pc-openbsd -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-OPENBSD
// CHECK-ASAN-OPENBSD: unsupported option '-fsanitize=address' for target 'i386-pc-openbsd'
+// RUN: %clang -target x86_64-apple-darwin -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-X86-64-DARWIN
+// CHECK-LSAN-X86-64-DARWIN-NOT: unsupported option
+
+// RUN: %clang -target x86_64-apple-iossimulator -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-X86-64-IOSSIMULATOR
+// CHECK-LSAN-X86-64-IOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang -target x86_64-apple-tvossimulator -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-X86-64-TVOSSIMULATOR
+// CHECK-LSAN-X86-64-TVOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang -target i386-apple-darwin -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-I386-DARWIN
+// CHECK-LSAN-I386-DARWIN-NOT: unsupported option
+
+// RUN: %clang -target arm-apple-ios -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-ARM-IOS
+// CHECK-LSAN-ARM-IOS-NOT: unsupported option
+
+// RUN: %clang -target i386-apple-iossimulator -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-I386-IOSSIMULATOR
+// CHECK-LSAN-I386-IOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang -target i386-apple-tvossimulator -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-LSAN-I386-TVOSSIMULATOR
+// CHECK-LSAN-I386-TVOSSIMULATOR-NOT: unsupported option
+
// RUN: %clang -target i686-linux-gnu -fsanitize=efficiency-cache-frag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-X86
// RUN: %clang -target i686-linux-gnu -fsanitize=efficiency-working-set %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ESAN-X86
// CHECK-ESAN-X86: error: unsupported option '-fsanitize=efficiency-{{.*}}' for target 'i686--linux-gnu'
@@ -406,6 +480,14 @@
// CHECK-CFI-NO-CROSS-DSO: -emit-llvm-bc
// CHECK-CFI-NO-CROSS-DSO-NOT: -fsanitize-cfi-cross-dso
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-icall-generalize-pointers -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-GENERALIZE-POINTERS
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-CFI-GENERALIZE-POINTERS
+// CHECK-CFI-GENERALIZE-POINTERS: -fsanitize-cfi-icall-generalize-pointers
+// CHECK-NO-CFI-GENERALIZE-POINTERS-NOT: -fsanitize-cfi-icall-generalize-pointers
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-icall-generalize-pointers -fsanitize-cfi-cross-dso -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-GENERALIZE-AND-CROSS-DSO
+// CHECK-CFI-GENERALIZE-AND-CROSS-DSO: error: invalid argument '-fsanitize-cfi-cross-dso' not allowed with '-fsanitize-cfi-icall-generalize-pointers'
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fsanitize-stats -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-STATS
// CHECK-CFI-STATS: -fsanitize-stats
@@ -455,6 +537,29 @@
// RUN: %clang -target x86_64-unknown-cloudabi -fsanitize=safe-stack %s -### 2>&1 | FileCheck %s -check-prefix=SAFESTACK-CLOUDABI
// SAFESTACK-CLOUDABI: "-fsanitize=safe-stack"
+// RUN: %clang -target i386--netbsd -fsanitize=address %s -### 2>&1 | FileCheck %s -check-prefix=ADDRESS-NETBSD
+// RUN: %clang -target x86_64--netbsd -fsanitize=address %s -### 2>&1 | FileCheck %s -check-prefix=ADDRESS-NETBSD
+// ADDRESS-NETBSD: "-fsanitize=address"
+
+// RUN: %clang -target i386--netbsd -fsanitize=vptr %s -### 2>&1 | FileCheck %s -check-prefix=VPTR-NETBSD
+// RUN: %clang -target x86_64--netbsd -fsanitize=vptr %s -### 2>&1 | FileCheck %s -check-prefix=VPTR-NETBSD
+// VPTR-NETBSD: "-fsanitize=vptr"
+
+// RUN: %clang -target i386--netbsd -fsanitize=safe-stack %s -### 2>&1 | FileCheck %s -check-prefix=SAFESTACK-NETBSD
+// RUN: %clang -target x86_64--netbsd -fsanitize=safe-stack %s -### 2>&1 | FileCheck %s -check-prefix=SAFESTACK-NETBSD
+// SAFESTACK-NETBSD: "-fsanitize=safe-stack"
+
+// RUN: %clang -target i386--netbsd -fsanitize=function %s -### 2>&1 | FileCheck %s -check-prefix=FUNCTION-NETBSD
+// RUN: %clang -target x86_64--netbsd -fsanitize=function %s -### 2>&1 | FileCheck %s -check-prefix=FUNCTION-NETBSD
+// FUNCTION-NETBSD: "-fsanitize=function"
+
+// RUN: %clang -target i386--netbsd -fsanitize=leak %s -### 2>&1 | FileCheck %s -check-prefix=LEAK-NETBSD
+// RUN: %clang -target x86_64--netbsd -fsanitize=leak %s -### 2>&1 | FileCheck %s -check-prefix=LEAK-NETBSD
+// LEAK-NETBSD: "-fsanitize=leak"
+
+// RUN: %clang -target x86_64--netbsd -fsanitize=thread %s -### 2>&1 | FileCheck %s -check-prefix=THREAD-NETBSD
+// THREAD-NETBSD: "-fsanitize=thread"
+
// RUN: %clang -target x86_64-scei-ps4 -fsanitize=function -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-UBSAN-PS4
// CHECK-FSAN-UBSAN-PS4: unsupported option '-fsanitize=function' for target 'x86_64-scei-ps4'
// RUN: %clang -target x86_64-scei-ps4 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-PS4
@@ -474,3 +579,32 @@
// Make sure there are no *.{o,bc} or -l passed before the ASan library.
// CHECK-ASAN-PS4-NOT: {{(\.(o|bc)"? |-l).*-lSceDbgAddressSanitizer_stub_weak}}
// CHECK-ASAN-PS4: -lSceDbgAddressSanitizer_stub_weak
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-MINIMAL
+// CHECK-ASAN-MINIMAL: error: invalid argument '-fsanitize-minimal-runtime' not allowed with '-fsanitize=address'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-MINIMAL
+// CHECK-TSAN-MINIMAL: error: invalid argument '-fsanitize-minimal-runtime' not allowed with '-fsanitize=thread'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL
+// CHECK-UBSAN-MINIMAL: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){19}"}}
+// CHECK-UBSAN-MINIMAL: "-fsanitize-minimal-runtime"
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize=vptr -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-VPTR-MINIMAL
+// CHECK-UBSAN-VPTR-MINIMAL: error: invalid argument '-fsanitize=vptr' not allowed with '-fsanitize-minimal-runtime'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-minimal-runtime -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-UBSAN-MINIMAL
+// CHECK-ASAN-UBSAN-MINIMAL: error: invalid argument '-fsanitize-minimal-runtime' not allowed with '-fsanitize=address'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -flto -fvisibility=hidden -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-MINIMAL
+// CHECK-CFI-MINIMAL: "-fsanitize=cfi-derived-cast,cfi-icall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall"
+// CHECK-CFI-MINIMAL: "-fsanitize-trap=cfi-derived-cast,cfi-icall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall"
+// CHECK-CFI-MINIMAL: "-fsanitize-minimal-runtime"
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fno-sanitize-trap=cfi-icall -flto -fvisibility=hidden -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOTRAP-MINIMAL
+// CHECK-CFI-NOTRAP-MINIMAL: error: invalid argument 'fsanitize-minimal-runtime' only allowed with 'fsanitize-trap=cfi'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fno-sanitize-trap=cfi-icall -fno-sanitize=cfi-icall -flto -fvisibility=hidden -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOICALL-MINIMAL
+// CHECK-CFI-NOICALL-MINIMAL: "-fsanitize=cfi-derived-cast,cfi-unrelated-cast,cfi-nvcall,cfi-vcall"
+// CHECK-CFI-NOICALL-MINIMAL: "-fsanitize-trap=cfi-derived-cast,cfi-unrelated-cast,cfi-nvcall,cfi-vcall"
+// CHECK-CFI-NOICALL-MINIMAL: "-fsanitize-minimal-runtime"
diff --git a/test/Driver/fuchsia.c b/test/Driver/fuchsia.c
index 58c2bbe533..3f5597c36e 100644
--- a/test/Driver/fuchsia.c
+++ b/test/Driver/fuchsia.c
@@ -1,19 +1,26 @@
// RUN: %clang %s -### -no-canonical-prefixes --target=x86_64-unknown-fuchsia \
-// RUN: --sysroot=%S/platform -fuse-ld=ld 2>&1 | FileCheck %s
+// RUN: --sysroot=%S/platform 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHECK,CHECK-X86_64 %s
+// RUN: %clang %s -### -no-canonical-prefixes --target=aarch64-unknown-fuchsia \
+// RUN: --sysroot=%S/platform 2>&1 \
+// RUN: | FileCheck -check-prefixes=CHECK,CHECK-AARCH64 %s
// CHECK: {{.*}}clang{{.*}}" "-cc1"
+// CHECK: "-munwind-tables"
// CHECK: "-fuse-init-array"
// CHECK: "-isysroot" "[[SYSROOT:[^"]+]]"
// CHECK: "-internal-externc-isystem" "[[SYSROOT]]{{/|\\\\}}include"
-// CHECK: {{.*}}lld{{.*}}" "-flavor" "gnu"
+// CHECK: {{.*}}ld.lld{{.*}}" "-z" "rodynamic"
// CHECK: "--sysroot=[[SYSROOT]]"
// CHECK: "-pie"
// CHECK: "--build-id"
+// CHECK: "--hash-style=gnu"
// CHECK: "-dynamic-linker" "ld.so.1"
// CHECK: Scrt1.o
// CHECK-NOT: crti.o
// CHECK-NOT: crtbegin.o
-// CHECK: "-L[[SYSROOT]]/lib"
-// CHECK: "{{.*[/\\]}}libclang_rt.builtins-x86_64.a"
+// CHECK: "-L[[SYSROOT]]{{/|\\\\}}lib"
+// CHECK-X86_64: "{{.*[/\\]}}libclang_rt.builtins-x86_64.a"
+// CHECK-AARCH64: "{{.*[/\\]}}libclang_rt.builtins-aarch64.a"
// CHECK: "-lc"
// CHECK-NOT: crtend.o
// CHECK-NOT: crtn.o
@@ -43,3 +50,31 @@
// RUN: -fsanitize=safe-stack 2>&1 \
// RUN: | FileCheck %s -check-prefix=CHECK-SAFESTACK
// CHECK-SAFESTACK: "-fsanitize=safe-stack"
+// CHECK-SAFESTACK-NOT: "{{.*[/\\]}}libclang_rt.safestack-x86_64.a"
+// CHECK-SAFESTACK-NOT: "__safestack_init"
+
+// RUN: %clang %s -### --target=x86_64-unknown-fuchsia \
+// RUN: -fsanitize=address 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ASAN-X86
+// CHECK-ASAN-X86: "-fsanitize=address"
+// CHECK-ASAN-X86: "-fsanitize-address-globals-dead-stripping"
+// CHECK-ASAN-X86: "-dynamic-linker" "asan/ld.so.1"
+// CHECK-ASAN-X86: "{{.*[/\\]}}libclang_rt.asan-x86_64.so"
+// CHECK-ASAN-X86: "{{.*[/\\]}}libclang_rt.asan-preinit-x86_64.a"
+
+// RUN: %clang %s -### --target=aarch64-fuchsia \
+// RUN: -fsanitize=address 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ASAN-AARCH64
+// CHECK-ASAN-AARCH64: "-fsanitize=address"
+// CHECK-ASAN-AARCH64: "-fsanitize-address-globals-dead-stripping"
+// CHECK-ASAN-AARCH64: "-dynamic-linker" "asan/ld.so.1"
+// CHECK-ASAN-AARCH64: "{{.*[/\\]}}libclang_rt.asan-aarch64.so"
+// CHECK-ASAN-AARCH64: "{{.*[/\\]}}libclang_rt.asan-preinit-aarch64.a"
+
+// RUN: %clang %s -### --target=x86_64-unknown-fuchsia \
+// RUN: -fsanitize=address -fPIC -shared 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ASAN-SHARED
+// CHECK-ASAN-SHARED: "-fsanitize=address"
+// CHECK-ASAN-SHARED: "-fsanitize-address-globals-dead-stripping"
+// CHECK-ASAN-SHARED: "{{.*[/\\]}}libclang_rt.asan-x86_64.so"
+// CHECK-ASAN-SHARED-NOT: "{{.*[/\\]}}libclang_rt.asan-preinit-x86_64.a"
diff --git a/test/Driver/fuchsia.cpp b/test/Driver/fuchsia.cpp
index 4490f94d07..cbd08adb44 100644
--- a/test/Driver/fuchsia.cpp
+++ b/test/Driver/fuchsia.cpp
@@ -1,11 +1,12 @@
// RUN: %clangxx %s -### -no-canonical-prefixes --target=x86_64-unknown-fuchsia \
-// RUN: --sysroot=%S/platform 2>&1 -fuse-ld=ld | FileCheck %s
+// RUN: --sysroot=%S/platform 2>&1 | FileCheck %s
// CHECK: {{.*}}clang{{.*}}" "-cc1"
+// CHECK: "-triple" "x86_64-fuchsia"
// CHECK: "-fuse-init-array"
// CHECK: "-isysroot" "[[SYSROOT:[^"]+]]"
-// CHECK: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1"
+// CHECK: "-internal-isystem" "{{.*[/\\]}}x86_64-fuchsia{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1"
// CHECK: "-internal-externc-isystem" "[[SYSROOT]]{{/|\\\\}}include"
-// CHECK: {{.*}}lld{{.*}}" "-flavor" "gnu"
+// CHECK: {{.*}}ld.lld{{.*}}" "-z" "rodynamic"
// CHECK: "--sysroot=[[SYSROOT]]"
// CHECK: "-pie"
// CHECK: "--build-id"
@@ -13,7 +14,7 @@
// CHECK: Scrt1.o
// CHECK-NOT: crti.o
// CHECK-NOT: crtbegin.o
-// CHECK: "-L[[SYSROOT]]/lib"
+// CHECK: "-L[[SYSROOT]]{{/|\\\\}}lib"
// CHECK: "-lc++" "-lc++abi" "-lunwind" "-lm"
// CHECK: "{{.*[/\\]}}libclang_rt.builtins-x86_64.a"
// CHECK: "-lc"
@@ -26,8 +27,8 @@
// RUN: %clangxx %s -### --target=x86_64-unknown-fuchsia -static-libstdc++ 2>&1 \
// RUN: | FileCheck %s -check-prefix=CHECK-STATIC
-// CHECK-STATIC: "-Bstatic"
+// CHECK-STATIC-NOT: "-Bstatic"
// CHECK-STATIC: "-lc++" "-lc++abi" "-lunwind"
-// CHECK-STATIC: "-Bdynamic"
+// CHECK-STATIC-NOT: "-Bdynamic"
// CHECK-STATIC: "-lm"
// CHECK-STATIC: "-lc"
diff --git a/test/Driver/fuzzer.c b/test/Driver/fuzzer.c
new file mode 100644
index 0000000000..3fdf5ab9c9
--- /dev/null
+++ b/test/Driver/fuzzer.c
@@ -0,0 +1,34 @@
+// Test flags inserted by -fsanitize=fuzzer.
+
+// RUN: %clang -fsanitize=fuzzer %s -target x86_64-apple-darwin14 -### 2>&1 | FileCheck --check-prefixes=CHECK-FUZZER-LIB,CHECK-COVERAGE-FLAGS %s
+//
+// CHECK-FUZZER-LIB: libclang_rt.fuzzer
+// CHECK-COVERAGE: -fsanitize-coverage-inline-8bit-counters
+// CHECK-COVERAGE-SAME: -fsanitize-coverage-indirect-calls
+// CHECK-COVERAGE-SAME: -fsanitize-coverage-trace-cmp
+// CHECK-COVERAGE-SAME: -fsanitize-coverage-pc-table
+
+// RUN: %clang -fsanitize=fuzzer -target i386-unknown-linux -stdlib=platform %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LIBCXX-LINUX %s
+//
+// CHECK-LIBCXX-LINUX: -lstdc++
+
+// RUN: %clang -target x86_64-apple-darwin14 -fsanitize=fuzzer %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LIBCXX-DARWIN %s
+//
+// CHECK-LIBCXX-DARWIN: -lc++
+
+
+// Check that we don't link in libFuzzer.a when producing a shared object.
+// RUN: %clang -fsanitize=fuzzer %s -shared -o %t.so -### 2>&1 | FileCheck --check-prefixes=CHECK-NOLIB-SO %s
+// CHECK-NOLIB-SO-NOT: libclang_rt.libfuzzer
+
+// Check that we don't link in libFuzzer when compiling with -fsanitize=fuzzer-no-link.
+// RUN: %clang -fsanitize=fuzzer-no-link %s -target x86_64-apple-darwin14 -### 2>&1 | FileCheck --check-prefixes=CHECK-NOLIB,CHECK-COV %s
+// CHECK-NOLIB-NOT: libclang_rt.libfuzzer
+// CHECK-COV: -fsanitize-coverage-inline-8bit-counters
+
+// RUN: %clang -fsanitize=fuzzer -fsanitize-coverage=trace-pc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-MSG %s
+// CHECK-MSG-NOT: argument unused during compilation
+
+int LLVMFuzzerTestOneInput(const char *Data, long Size) {
+ return 0;
+}
diff --git a/test/Driver/gfortran.f90 b/test/Driver/gfortran.f90
index e687e51b4d..d2f90b47a3 100644
--- a/test/Driver/gfortran.f90
+++ b/test/Driver/gfortran.f90
@@ -106,7 +106,6 @@
! RUN: -fsyntax-only \
! RUN: -funderscoring \
! RUN: -fwhole-file \
-! RUN: -fworking-directory \
! RUN: -imultilib \
! RUN: -iprefix \
! RUN: -iquote \
@@ -226,7 +225,6 @@
! CHECK: "-fstack-arrays"
! CHECK: "-funderscoring"
! CHECK: "-fwhole-file"
-! CHECK: "-fworking-directory"
! CHECK: "-imultilib"
! CHECK: "-iprefix"
! CHECK: "-iquote"
diff --git a/test/Driver/gold-lto-new-pass-man.c b/test/Driver/gold-lto-new-pass-man.c
new file mode 100644
index 0000000000..c2add0c73a
--- /dev/null
+++ b/test/Driver/gold-lto-new-pass-man.c
@@ -0,0 +1,7 @@
+// RUN: touch %t.o
+//
+// RUN: %clang -target ppc64le-unknown-linux -### %t.o -flto 2>&1 \
+// RUN: -Wl,-plugin-opt=foo -O3 \
+// RUN: -fexperimental-new-pass-manager \
+// RUN: | FileCheck %s
+// CHECK: "-plugin-opt=new-pass-manager"
diff --git a/test/Driver/gold-lto.c b/test/Driver/gold-lto.c
index 050b1ef18b..d16961eeda 100644
--- a/test/Driver/gold-lto.c
+++ b/test/Driver/gold-lto.c
@@ -3,14 +3,14 @@
// RUN: %clang -target x86_64-unknown-linux -### %t.o -flto 2>&1 \
// RUN: -Wl,-plugin-opt=foo -O3 \
// RUN: | FileCheck %s --check-prefix=CHECK-X86-64-BASIC
-// CHECK-X86-64-BASIC: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-X86-64-BASIC: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// CHECK-X86-64-BASIC: "-plugin-opt=O3"
// CHECK-X86-64-BASIC: "-plugin-opt=foo"
//
// RUN: %clang -target x86_64-unknown-linux -### %t.o -flto 2>&1 \
// RUN: -march=corei7 -Wl,-plugin-opt=foo -Ofast \
// RUN: | FileCheck %s --check-prefix=CHECK-X86-64-COREI7
-// CHECK-X86-64-COREI7: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-X86-64-COREI7: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// CHECK-X86-64-COREI7: "-plugin-opt=mcpu=corei7"
// CHECK-X86-64-COREI7: "-plugin-opt=O3"
// CHECK-X86-64-COREI7: "-plugin-opt=foo"
@@ -18,11 +18,11 @@
// RUN: %clang -target arm-unknown-linux -### %t.o -flto 2>&1 \
// RUN: -march=armv7a -Wl,-plugin-opt=foo -O0 \
// RUN: | FileCheck %s --check-prefix=CHECK-ARM-V7A
-// CHECK-ARM-V7A: "-plugin" "{{.*}}/LLVMgold.so"
-// CHECK-ARM-V7A: "-plugin-opt=mcpu=cortex-a8"
+// CHECK-ARM-V7A: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
+// CHECK-ARM-V7A: "-plugin-opt=mcpu=generic"
// CHECK-ARM-V7A: "-plugin-opt=O0"
// CHECK-ARM-V7A: "-plugin-opt=foo"
//
// RUN: %clang -target i686-linux-android -### %t.o -flto 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-X86-ANDROID
-// CHECK-X86-ANDROID: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-X86-ANDROID: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
diff --git a/test/Driver/hexagon-hvx.c b/test/Driver/hexagon-hvx.c
new file mode 100644
index 0000000000..f648e4970d
--- /dev/null
+++ b/test/Driver/hexagon-hvx.c
@@ -0,0 +1,90 @@
+// -----------------------------------------------------------------------------
+// Tests for the hvx features and warnings.
+// -----------------------------------------------------------------------------
+
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mhvx \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECKHVX162 %s
+// CHECKHVX162: "-target-feature" "+hvxv62"
+
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mhvx \
+// RUN: -mhvx-double 2>&1 | FileCheck -check-prefix=CHECKHVX2 %s
+
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mhvx \
+// RUN: -mhvx-length=128B 2>&1 | FileCheck -check-prefix=CHECKHVX2 %s
+// CHECKHVX2-NOT: "-target-feature" "+hvx-length64b"
+// CHECKHVX2: "-target-feature" "+hvx-length128b"
+
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECKHVX3 %s
+// CHECKHVX3-NOT: "-target-feature" "+hvx
+
+// -mhvx-double is deprecated.
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mhvx-double \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-DEPRECATED %s
+// CHECK-DEPRECATED: warning: argument '-mhvx-double' is deprecated, use '-mhvx-length=128B' instead [-Wdeprecated]
+
+// -mno-hvx-double is deprecated.
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mno-hvx-double \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-NODEPRECATED %s
+// CHECK-NODEPRECATED: warning: argument '-mno-hvx-double' is deprecated, use '-mno-hvx' instead [-Wdeprecated]
+
+// No hvx target feature must be added if -mno-hvx/-mno-hvx-double occurs last
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mno-hvx \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-NOHVX %s
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mhvx -mno-hvx \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-NOHVX %s
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mhvx -mno-hvx-double \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-NOHVX %s
+// CHECK-NOHVX-NOT: "-target-feature" "+hvx
+
+// Hvx target feature should be added if -mno-hvx doesnot occur last
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mno-hvx -mhvx\
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXFEAT %s
+// CHECK-HVXFEAT: "-target-feature" "+hvxv62"
+
+// With -mhvx, the version of hvx defaults to Cpu
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv60 -mhvx \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVX-DEFAULT %s
+// CHECK-HVX-DEFAULT: "-target-feature" "+hvxv60"
+
+// Test -mhvx= flag
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv60 -mhvx=v62 \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXEQ %s
+// CHECK-HVXEQ: "-target-feature" "+hvxv62"
+
+// Honor the last occured -mhvx=, -mhvx flag.
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv60 -mhvx=v62 -mhvx\
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXEQ-PRE %s
+// CHECK-HVXEQ-PRE-NOT: "-target-feature" "+hvxv62"
+// CHECK-HVXEQ-PRE: "-target-feature" "+hvxv60"
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv60 -mhvx -mhvx=v62\
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXEQ-PRE2 %s
+// CHECK-HVXEQ-PRE2-NOT: "-target-feature" "+hvxv60"
+// CHECK-HVXEQ-PRE2: "-target-feature" "+hvxv62"
+
+// Test -mhvx-length flag
+// The default mode on v60,v62 is 64B.
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv60 -mhvx \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-64B %s
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv60 -mhvx -mhvx-length=64B\
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-64B %s
+// CHECK-HVXLENGTH-64B: "-target-feature" "+hvx{{.*}}" "-target-feature" "+hvx-length64b"
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mv62 -mhvx -mhvx-length=128B\
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-128B %s
+// CHECK-HVXLENGTH-128B: "-target-feature" "+hvx{{.*}}" "-target-feature" "+hvx-length128b"
+
+// Bail out if -mhvx-length is specified without HVX enabled
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mhvx-length=64B \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-ERROR %s
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mhvx-length=128B \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-ERROR %s
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mhvx-double \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-ERROR %s
+// CHECK-HVXLENGTH-ERROR: error: -mhvx-length is not supported without a -mhvx/-mhvx= flag
+
+// Error out if an unsupported value is passed to -mhvx-length.
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mhvx -mhvx-length=B \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-VALUE-ERROR %s
+// RUN: %clang -c %s -### -target hexagon-unknown-elf -mhvx -mhvx-length=128 \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-HVXLENGTH-VALUE-ERROR %s
+// CHECK-HVXLENGTH-VALUE-ERROR: error: unsupported argument '{{.*}}' to option 'mhvx-length='
diff --git a/test/Driver/hexagon-toolchain-elf.c b/test/Driver/hexagon-toolchain-elf.c
index 827c19186b..98582450e3 100644
--- a/test/Driver/hexagon-toolchain-elf.c
+++ b/test/Driver/hexagon-toolchain-elf.c
@@ -89,6 +89,30 @@
// 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
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -O3 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK025 %s
+// CHECK025: "-ffp-contract=fast"
+// CHECK025: hexagon-link
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -O3 -ffp-contract=off \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK026 %s
+// CHECK026-NOT: "-ffp-contract=fast"
+// CHECK026: hexagon-link
+
// -----------------------------------------------------------------------------
// Test Linker related args
// -----------------------------------------------------------------------------
diff --git a/test/Driver/immediate-options.c b/test/Driver/immediate-options.c
index f50ccae642..935c948321 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 0000000000..2605eaead9
--- /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/linker-opts.c b/test/Driver/linker-opts.c
index 29ef136c8b..5fe29d7a13 100644
--- a/test/Driver/linker-opts.c
+++ b/test/Driver/linker-opts.c
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
//
-// RUN: env LIBRARY_PATH=%T/test1 %clang -x c %s -### 2>&1 | FileCheck %s
+// RUN: env LIBRARY_PATH=%t/test1 %clang -x c %s -### 2>&1 | FileCheck %s
// CHECK: "-L{{.*}}/test1"
// GCC driver is used as linker on cygming. It should be aware of LIBRARY_PATH.
@@ -10,8 +10,8 @@
// REQUIRES: native
// Make sure that LIBRARY_PATH works for both i386 and x86_64 on Darwin.
-// RUN: env LIBRARY_PATH=%T/test1 %clang -target x86_64-apple-darwin %s -### 2>&1 | FileCheck %s
-// RUN: env LIBRARY_PATH=%T/test1 %clang -target i386-apple-darwin %s -### 2>&1 | FileCheck %s
+// RUN: env LIBRARY_PATH=%t/test1 %clang -target x86_64-apple-darwin %s -### 2>&1 | FileCheck %s
+// RUN: env LIBRARY_PATH=%t/test1 %clang -target i386-apple-darwin %s -### 2>&1 | FileCheck %s
//
// Make sure that we don't warn on unused compiler arguments.
// RUN: %clang -Xclang -I. -x c %s -c -o %t/tmp.o
diff --git a/test/Driver/linux-as.c b/test/Driver/linux-as.c
index a07abc17e5..68cf403d97 100644
--- a/test/Driver/linux-as.c
+++ b/test/Driver/linux-as.c
@@ -100,6 +100,33 @@
// RUN: | FileCheck -check-prefix=CHECK-ARM-HARDFP %s
// CHECK-ARM-HARDFP: as{{(.exe)?}}" "-mfloat-abi=hard"
//
+// RUN: %clang -target aarch64-linux-gnu -mcpu=cortex-a53 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM64-MCPU %s
+// CHECK-ARM64-MCPU: as{{(.exe)?}}" "-mcpu=cortex-a53"
+//
+// RUN: %clang -target aarch64-linux-gnu -march=armv8-a -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM64-MARCH %s
+// CHECK-ARM64-MARCH: as{{(.exe)?}}" "-march=armv8-a"
+//
+// RUN: %clang -target aarch64-linux-gnu -mcpu=cortex-a53 -march=armv8-a -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM64-ALL %s
+// CHECK-ARM64-ALL: as{{(.exe)?}}" "-march=armv8-a" "-mcpu=cortex-a53"
+//
+// RUN: %clang -target aarch64_be-linux-gnu -mcpu=cortex-a53 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM64-MCPU %s
+//
+// RUN: %clang -target aarch64_be-linux-gnu -march=armv8-a -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM64-MARCH %s
+//
+// RUN: %clang -target aarch64_be-linux-gnu -mcpu=cortex-a53 -march=armv8-a -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-ARM64-ALL %s
+//
// RUN: %clang -target ppc-linux -mcpu=invalid-cpu -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-PPC-NO-MCPU %s
@@ -147,3 +174,18 @@
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-Z-ARCH-Z196 %s
// CHECK-Z-ARCH-Z196: as{{.*}} "-march=z196"
+//
+// RUN: %clang -target powerpc64le-linux -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-PPC64LE %s
+// CHECK-PPC64LE: as{{.*}} "-mpower8"
+//
+// RUN: %clang -target powerpc64-linux -mcpu=pwr7 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-PPC64 %s
+// CHECK-PPC64: as{{.*}} "-mpower7"
+//
+// RUN: %clang -target powerpc-linux -mcpu=pwr9 -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-PPC32 %s
+// CHECK-PPC32: as{{.*}} "-mpower9"
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index e5aa870866..662aabb867 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -71,6 +71,27 @@
// CHECK-LD-RT: libclang_rt.builtins-x86_64.a"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=i686-unknown-linux \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: --rtlib=compiler-rt \
+// RUN: | FileCheck --check-prefix=CHECK-LD-RT-I686 %s
+// CHECK-LD-RT-I686-NOT: warning:
+// CHECK-LD-RT-I686: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-RT-I686: "--eh-frame-hdr"
+// CHECK-LD-RT-I686: "-m" "elf_i386"
+// CHECK-LD-RT-I686: "-dynamic-linker"
+// CHECK-LD-RT-I686: "{{.*}}/usr/lib/gcc/i686-unknown-linux/4.6.0{{/|\\\\}}crtbegin.o"
+// CHECK-LD-RT-I686: "-L[[SYSROOT]]/usr/lib/gcc/i686-unknown-linux/4.6.0"
+// CHECK-LD-RT-I686: "-L[[SYSROOT]]/usr/lib/gcc/i686-unknown-linux/4.6.0/../../../../i686-unknown-linux/lib"
+// CHECK-LD-RT-I686: "-L[[SYSROOT]]/usr/lib/gcc/i686-unknown-linux/4.6.0/../../.."
+// CHECK-LD-RT-I686: "-L[[SYSROOT]]/lib"
+// CHECK-LD-RT-I686: "-L[[SYSROOT]]/usr/lib"
+// CHECK-LD-RT-I686: libclang_rt.builtins-i386.a"
+// CHECK-LD-RT-I686: "-lc"
+// CHECK-LD-RT-I686: libclang_rt.builtins-i386.a"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi \
// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
@@ -638,6 +659,46 @@
// CHECK-OPENSUSE-42-2-AARCH64: "{{.*}}/usr/lib64/gcc/aarch64-suse-linux/4.8{{/|\\\\}}crtend.o"
// CHECK-OPENSUSE-42-2-AARCH64: "{{.*}}/usr/lib64/gcc/aarch64-suse-linux/4.8/../../../../lib64{{/|\\\\}}crtn.o"
//
+// Check openSUSE Tumbleweed on armv6hl
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=armv6hl-suse-linux-gnueabi \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/opensuse_tumbleweed_armv6hl_tree \
+// RUN: | FileCheck --check-prefix=CHECK-OPENSUSE-TW-ARMV6HL %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=armv6hl-suse-linux-gnueabi \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/opensuse_tumbleweed_armv6hl_tree \
+// RUN: | FileCheck --check-prefix=CHECK-OPENSUSE-TW-ARMV6HL %s
+// CHECK-OPENSUSE-TW-ARMV6HL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-OPENSUSE-TW-ARMV6HL: "{{.*}}/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/../../../../lib{{/|\\\\}}crt1.o"
+// CHECK-OPENSUSE-TW-ARMV6HL: "{{.*}}/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/../../../../lib{{/|\\\\}}crti.o"
+// CHECK-OPENSUSE-TW-ARMV6HL: "{{.*}}/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5{{/|\\\\}}crtbegin.o"
+// CHECK-OPENSUSE-TW-ARMV6HL: "-L[[SYSROOT]]/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5"
+// CHECK-OPENSUSE-TW-ARMV6HL: "-L[[SYSROOT]]/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/../../../../lib"
+// CHECK-OPENSUSE-TW-ARMV6HL: "{{.*}}/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5{{/|\\\\}}crtend.o"
+// CHECK-OPENSUSE-TW-ARMV6HL: "{{.*}}/usr/lib/gcc/armv6hl-suse-linux-gnueabi/5/../../../../lib{{/|\\\\}}crtn.o"
+//
+// Check openSUSE Tumbleweed on armv7hl
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=armv7hl-suse-linux-gnueabi \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/opensuse_tumbleweed_armv7hl_tree \
+// RUN: | FileCheck --check-prefix=CHECK-OPENSUSE-TW-ARMV7HL %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=armv7hl-suse-linux-gnueabi \
+// RUN: --gcc-toolchain="" \
+// RUN: --sysroot=%S/Inputs/opensuse_tumbleweed_armv7hl_tree \
+// RUN: | FileCheck --check-prefix=CHECK-OPENSUSE-TW-ARMV7HL %s
+// CHECK-OPENSUSE-TW-ARMV7HL: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-OPENSUSE-TW-ARMV7HL: "{{.*}}/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/../../../../lib{{/|\\\\}}crt1.o"
+// CHECK-OPENSUSE-TW-ARMV7HL: "{{.*}}/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/../../../../lib{{/|\\\\}}crti.o"
+// CHECK-OPENSUSE-TW-ARMV7HL: "{{.*}}/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5{{/|\\\\}}crtbegin.o"
+// CHECK-OPENSUSE-TW-ARMV7HL: "-L[[SYSROOT]]/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5"
+// CHECK-OPENSUSE-TW-ARMV7HL: "-L[[SYSROOT]]/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/../../../../lib"
+// CHECK-OPENSUSE-TW-ARMV7HL: "{{.*}}/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5{{/|\\\\}}crtend.o"
+// CHECK-OPENSUSE-TW-ARMV7HL: "{{.*}}/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/../../../../lib{{/|\\\\}}crtn.o"
+//
// Check dynamic-linker for different archs
// RUN: %clang %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-gnueabi \
@@ -1072,6 +1133,7 @@
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-ANDROID: "--enable-new-dtags"
// CHECK-ANDROID: "{{.*}}{{/|\\\\}}crtbegin_dynamic.o"
// CHECK-ANDROID: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-NOT: "gcc_s"
@@ -1246,31 +1308,6 @@
// CHECK-ANDROID-PIE: "{{.*}}{{/|\\\\}}crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=arm-linux-androideabi \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=arm-linux-android \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=aarch64-linux-android \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=arm64-linux-android \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=mipsel-linux-android \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=mips64el-linux-android \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=i686-linux-android \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=x86_64-linux-android \
-// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s
-// CHECK-ANDROID-NO-DEFAULT-PIE-NOT: -pie
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: --target=arm-linux-androideabi \
// RUN: --gcc-toolchain="" \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-32 %s
diff --git a/test/Driver/lto-plugin-darwin.c b/test/Driver/lto-plugin-darwin.c
new file mode 100644
index 0000000000..2e9e6ba5b4
--- /dev/null
+++ b/test/Driver/lto-plugin-darwin.c
@@ -0,0 +1,6 @@
+// Check that Darwin uses LLVMgold.dylib.
+// REQUIRES: system-darwin
+// RUN: %clang -### %s -target x86_64-unknown-linux -flto 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-LTO-PLUGIN %s
+//
+// CHECK-LTO-PLUGIN: "-plugin" "{{.*}}/LLVMgold.dylib"
diff --git a/test/Driver/lto-plugin-linux.c b/test/Driver/lto-plugin-linux.c
new file mode 100644
index 0000000000..ac1eb14e2e
--- /dev/null
+++ b/test/Driver/lto-plugin-linux.c
@@ -0,0 +1,6 @@
+// Check that non-Windows, non-Darwin OSs use LLVMgold.so.
+// REQUIRES: !system-darwin && !system-windows
+// RUN: %clang -### %s -target x86_64-unknown-linux -flto 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-LTO-PLUGIN %s
+//
+// CHECK-LTO-PLUGIN: "-plugin" "{{.*}}/LLVMgold.so"
diff --git a/test/Driver/lto-plugin-windows.c b/test/Driver/lto-plugin-windows.c
new file mode 100644
index 0000000000..1b12702a98
--- /dev/null
+++ b/test/Driver/lto-plugin-windows.c
@@ -0,0 +1,6 @@
+// Check that Windows uses LLVMgold.dll.
+// REQUIRES: system-windows
+// RUN: %clang -### %s -target x86_64-unknown-linux -flto 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-LTO-PLUGIN %s
+//
+// CHECK-LTO-PLUGIN: "-plugin" "{{.*}}\\LLVMgold.dll"
diff --git a/test/Driver/lto-unit.c b/test/Driver/lto-unit.c
index 8a800fa4dc..1f1a286167 100644
--- a/test/Driver/lto-unit.c
+++ b/test/Driver/lto-unit.c
@@ -2,6 +2,8 @@
// 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
+// RUN: %clang -target x86_64-scei-ps4 -### %s -flto=full 2>&1 | FileCheck --check-prefix=UNIT %s
+// RUN: %clang -target x86_64-scei-ps4 -### %s -flto=thin 2>&1 | FileCheck --check-prefix=NOUNIT %s
// UNIT: "-flto-unit"
// NOUNIT-NOT: "-flto-unit"
diff --git a/test/Driver/lto.c b/test/Driver/lto.c
index d2f68f571a..570c80b941 100644
--- a/test/Driver/lto.c
+++ b/test/Driver/lto.c
@@ -36,19 +36,19 @@
// RUN: %clang -target x86_64-unknown-linux -### %s -flto 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-LTO-ACTION < %t %s
//
-// CHECK-LINK-LTO-ACTION: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-LINK-LTO-ACTION: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// -flto=full should cause link using gold plugin
// RUN: %clang -target x86_64-unknown-linux -### %s -flto=full 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-FULL-ACTION < %t %s
//
-// CHECK-LINK-FULL-ACTION: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-LINK-FULL-ACTION: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// Check that subsequent -fno-lto takes precedence
// RUN: %clang -target x86_64-unknown-linux -### %s -flto=full -fno-lto 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-NOLTO-ACTION < %t %s
//
-// CHECK-LINK-NOLTO-ACTION-NOT: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-LINK-NOLTO-ACTION-NOT: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// -flto passes along an explicit debugger tuning argument.
// RUN: %clang -target x86_64-unknown-linux -### %s -flto -glldb 2> %t
diff --git a/test/Driver/m_and_mm.c b/test/Driver/m_and_mm.c
index 18cf7abfa6..6e40c82cb1 100644
--- a/test/Driver/m_and_mm.c
+++ b/test/Driver/m_and_mm.c
@@ -1,3 +1,15 @@
// RUN: %clang -### \
// RUN: -M -MM %s 2> %t
// RUN: not grep '"-sys-header-deps"' %t
+
+// RUN: %clang -M -MM %s 2> %t
+// RUN: not grep "warning" %t
+
+// RUN: %clang -MMD -MD %s 2> %t || true
+// RUN: grep "warning" %t
+
+#warning "This warning shouldn't show up with -M and -MM"
+int main (void)
+{
+ return 0;
+}
diff --git a/test/Driver/mingw-msvcrt.c b/test/Driver/mingw-msvcrt.c
new file mode 100644
index 0000000000..b7c6584f95
--- /dev/null
+++ b/test/Driver/mingw-msvcrt.c
@@ -0,0 +1,5 @@
+// RUN: %clang -v -target i686-pc-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_DEFAULT %s
+// RUN: %clang -v -target i686-pc-windows-gnu -lmsvcr120 -### %s 2>&1 | FileCheck -check-prefix=CHECK_MSVCR120 %s
+
+// CHECK_DEFAULT: "-lmingwex" "-lmsvcrt" "-ladvapi32"
+// CHECK_MSVCR120: "-lmingwex" "-ladvapi32"
diff --git a/test/Driver/mips-abi.c b/test/Driver/mips-abi.c
index 8e3f7c0cd1..8591a45d3e 100644
--- a/test/Driver/mips-abi.c
+++ b/test/Driver/mips-abi.c
@@ -1,5 +1,7 @@
// Check passing Mips ABI options to the backend.
//
+// REQUIRES: mips-registered-target
+//
// RUN: %clang -target mips-linux-gnu -### -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS32R2-O32 %s
// RUN: %clang -target mips64-linux-gnu -mips32r2 -mabi=32 -### -c %s 2>&1 \
diff --git a/test/Driver/mips-abicalls-warning.c b/test/Driver/mips-abicalls-warning.c
new file mode 100644
index 0000000000..848a5bfce5
--- /dev/null
+++ b/test/Driver/mips-abicalls-warning.c
@@ -0,0 +1,9 @@
+// REQUIRES: mips-registered-target
+// RUN: %clang -### -c -target mips64-mti-elf -fno-PIC -mabicalls %s 2>&1 | FileCheck %s
+// CHECK: warning: ignoring '-mabicalls' option as it cannot be used with non position-independent code and the N64 ABI
+
+// RUN: %clang -### -c -target mips-mti-elf -mlong-calls %s 2>&1 | FileCheck -check-prefix=LONGCALL-IMP %s
+// LONGCALL-IMP: warning: ignoring '-mlong-calls' option as it is not currently supported with the implicit usage of -mabicalls
+
+// RUN: %clang -### -c -target mips-mti-elf -mlong-calls -mabicalls %s 2>&1 | FileCheck -check-prefix=LONGCALL-EXP %s
+// LONGCALL-EXP: warning: ignoring '-mlong-calls' option as it is not currently supported with -mabicalls
diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c
index 69fc20e1f2..a9db0f1017 100644
--- a/test/Driver/mips-features.c
+++ b/test/Driver/mips-features.c
@@ -10,6 +10,99 @@
// RUN: | FileCheck --check-prefix=CHECK-MNOABICALLS %s
// CHECK-MNOABICALLS: "-target-feature" "+noabicalls"
//
+// -mno-abicalls non-PIC N64
+// RUN: %clang -target mips64-linux-gnu -### -c -fno-PIC %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MNOABICALLS-N64NPIC %s
+// CHECK-MNOABICALLS-N64NPIC: "-target-feature" "+noabicalls"
+//
+// -mgpopt
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-gpopt -mgpopt -Wno-unsupported-gpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MGPOPT-DEF-ABICALLS %s
+// CHECK-MGPOPT-DEF-ABICALLS-NOT: "-mllvm" "-mgpopt"
+//
+// -mabicalls -mgpopt
+// RUN: %clang -target mips-linux-gnu -### -c %s -mabicalls -mno-gpopt -mgpopt -Wno-unsupported-gpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MGPOPT-EXPLICIT-ABICALLS %s
+// CHECK-MGPOPT-EXPLICIT-ABICALLS-NOT: "-mllvm" "-mgpopt"
+//
+// -mno-abicalls -mgpopt
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mno-gpopt -mgpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MGPOPT %s
+// CHECK-MGPOPT: "-mllvm" "-mgpopt"
+//
+// -mno-abicalls -mno-gpopt
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt -mno-gpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MNOGPOPT %s
+// CHECK-MNOGPOPT-NOT: "-mllvm" "-mgpopt"
+//
+// -mno-abicalls
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MGPOPTDEF %s
+// CHECK-MGPOPTDEF: "-mllvm" "-mgpopt"
+//
+// -mgpopt -mno-abicalls -mlocal-sdata
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mno-gpopt -mgpopt -mno-local-sdata -mlocal-sdata 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MLOCALSDATA %s
+// CHECK-MLOCALSDATA: "-mllvm" "-mlocal-sdata=1"
+//
+// -mgpopt -mno-abicalls -mno-local-sdata
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mno-gpopt -mgpopt -mlocal-sdata -mno-local-sdata 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MNOLOCALSDATA %s
+// CHECK-MNOLOCALSDATA: "-mllvm" "-mlocal-sdata=0"
+//
+// -mgpopt -mno-abicalls
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MLOCALSDATADEF %s
+// CHECK-MLOCALSDATADEF-NOT: "-mllvm" "-mlocal-sdata"
+//
+// -mno-abicalls -mgpopt -mextern-sdata
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt -mno-extern-sdata -mextern-sdata 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MEXTERNSDATA %s
+// CHECK-MEXTERNSDATA: "-mllvm" "-mextern-sdata=1"
+//
+// -mno-abicalls -mgpopt -mno-extern-sdata
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt -mextern-sdata -mno-extern-sdata 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MNOEXTERNSDATA %s
+// CHECK-MNOEXTERNSDATA: "-mllvm" "-mextern-sdata=0"
+//
+// -mno-abicalls -mgpopt
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MEXTERNSDATADEF %s
+// CHECK-MEXTERNSDATADEF-NOT: "-mllvm" "-mextern-sdata"
+//
+// -mno-abicalls -mgpopt -membedded-data
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt -mno-embedded-data -membedded-data 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MEMBEDDEDDATA %s
+// CHECK-MEMBEDDEDDATA: "-mllvm" "-membedded-data=1"
+//
+// -mno-abicalls -mgpopt -mno-embedded-data
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt -membedded-data -mno-embedded-data 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MNOEMBEDDEDDATA %s
+// CHECK-MNOEMBEDDEDDATA: "-mllvm" "-membedded-data=0"
+//
+// -mno-abicalls -mgpopt
+// RUN: %clang -target mips-linux-gnu -### -c %s -mno-abicalls -mgpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MEMBEDDEDDATADEF %s
+// CHECK-MEMBEDDEDDATADEF-NOT: "-mllvm" "-membedded-data"
+//
+// MIPS64 + N64: -fno-pic -> -mno-abicalls -mgpopt
+// RUN: %clang -target mips64-mti-elf -mabi=64 -### -c %s -fno-pic 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-N64-GPOPT %s
+// CHECK-N64-GPOPT: "-target-feature" "+noabicalls"
+// CHECK-N64-GPOPT: "-mllvm" "-mgpopt"
+//
+// MIPS64 + N64: -fno-pic -mno-gpopt
+// RUN: %clang -target mips64-mti-elf -mabi=64 -### -c %s -fno-pic -mno-gpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-N64-MNO-GPOPT %s
+// CHECK-N64-MNO-GPOPT: "-target-feature" "+noabicalls"
+// CHECK-N64-MNO-GPOPT-NOT: "-mllvm" "-mgpopt"
+//
+// MIPS64 + N64: -mgpopt (-fpic is implicit)
+// RUN: %clang -target mips64-mti-linux-gnu -mabi=64 -### -c %s -mgpopt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-N64-PIC-GPOPT %s
+// CHECK-N64-PIC-GPOPT-NOT: "-mllvm" "-mgpopt"
+// CHECK-N64-PIC-GPOPT: ignoring '-mgpopt' option as it cannot be used with the implicit usage of -mabicalls
+//
// -mips16
// RUN: %clang -target mips-linux-gnu -### -c %s \
// RUN: -mno-mips16 -mips16 2>&1 \
@@ -70,6 +163,18 @@
// RUN: | FileCheck --check-prefix=CHECK-NOMMSA %s
// CHECK-NOMMSA: "-target-feature" "-msa"
//
+// -mmt
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mno-mt -mmt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-MMT %s
+// CHECK-MMT: "-target-feature" "+mt"
+//
+// -mno-mt
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mmt -mno-mt 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOMMT %s
+// CHECK-NOMMT: "-target-feature" "-mt"
+//
// -modd-spreg
// RUN: %clang -target mips-linux-gnu -### -c %s -mno-odd-spreg -modd-spreg 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-MODDSPREG %s
@@ -116,6 +221,31 @@
// RUN: | FileCheck --check-prefix=CHECK-NANLEGACY %s
// CHECK-NANLEGACY: "-target-feature" "-nan2008"
//
+// -mabs=2008 on pre R2
+// RUN: %clang -target mips-linux-gnu -march=mips32 -### -c %s \
+// RUN: -mabs=2008 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ABSLEGACY %s
+//
+// -mabs=2008
+// RUN: %clang -target mips-linux-gnu -march=mips32r3 -### -c %s \
+// RUN: -mabs=2008 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ABS2008 %s
+//
+// -mabs=legacy
+// RUN: %clang -target mips-linux-gnu -march=mips32r3 -### -c %s \
+// RUN: -mabs=legacy 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ABSLEGACY %s
+//
+// -mabs=legacy on R6
+// RUN: %clang -target mips-linux-gnu -march=mips32r6 -### -c %s \
+// RUN: -mabs=legacy 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ABS2008 %s
+//
+// CHECK-ABSLEGACY: "-target-feature" "-abs2008"
+// CHECK-ABSLEGACY-NOT: "-target-feature" "+abs2008"
+// CHECK-ABS2008: "-target-feature" "+abs2008"
+// CHECK-ABS2008-NOT: "-target-feature" "-abs2008"
+//
// -mcompact-branches=never
// RUN: %clang -target mips-linux-gnu -march=mips32r6 -### -c %s \
// RUN: -mcompact-branches=never 2>&1 \
@@ -247,3 +377,28 @@
// RUN: | FileCheck --check-prefix=CHECK-IMG-SINGLEFLOAT-FPXX %s
// CHECK-IMG-SINGLEFLOAT-FPXX: "-target-feature" "+single-float"
// CHECK-IMG-SINGLEFLOAT-FPXX: "-target-feature" "+fpxx"
+
+// -mlong-call
+// RUN: %clang -target mips-img-linux-gnu -### -c %s \
+// RUN: -mno-abicalls -mlong-calls 2>&1 \
+// RUN: | FileCheck --check-prefix=LONG-CALLS-ON %s
+// RUN: %clang -target mips-img-linux-gnu -### -c %s \
+// RUN: -mno-abicalls -mno-long-calls 2>&1 \
+// RUN: | FileCheck --check-prefix=LONG-CALLS-OFF %s
+// RUN: %clang -target mips-img-linux-gnu -### -c %s 2>&1 \
+// RUN: | FileCheck --check-prefix=LONG-CALLS-DEF %s
+// RUN: %clang -target mips-img-linux-gnu -### -c %s -mlong-calls 2>&1 \
+// RUN: | FileCheck --check-prefix=LONG-CALLS-DEF %s
+// LONG-CALLS-ON: "-target-feature" "+long-calls"
+// LONG-CALLS-OFF: "-target-feature" "-long-calls"
+// LONG-CALLS-DEF-NOT: "long-calls"
+//
+// -mbranch-likely
+// RUN: %clang -target -mips-mti-linux-gnu -### -c %s -mbranch-likely 2>&1 \
+// RUN: | FileCheck --check-prefix=BRANCH-LIKELY %s
+// BRANCH-LIKELY: argument unused during compilation: '-mbranch-likely'
+//
+// -mno-branch-likely
+// RUN: %clang -target -mips-mti-linux-gnu -### -c %s -mno-branch-likely 2>&1 \
+// RUN: | FileCheck --check-prefix=NO-BRANCH-LIKELY %s
+// NO-BRANCH-LIKELY: argument unused during compilation: '-mno-branch-likely'
diff --git a/test/Driver/mips-gpopt-warning.c b/test/Driver/mips-gpopt-warning.c
new file mode 100644
index 0000000000..b667741372
--- /dev/null
+++ b/test/Driver/mips-gpopt-warning.c
@@ -0,0 +1,6 @@
+// REQUIRES: mips-registered-target
+// RUN: %clang -### -c -target mips-mti-elf %s -mgpopt 2>&1 | FileCheck -check-prefix=IMPLICIT %s
+// IMPLICIT: warning: ignoring '-mgpopt' option as it cannot be used with the implicit usage of -mabicalls
+
+// RUN: %clang -### -c -target mips-mti-elf %s -mgpopt -mabicalls 2>&1 | FileCheck -check-prefix=EXPLICIT %s
+// EXPLICIT: warning: ignoring '-mgpopt' option as it cannot be used with -mabicalls
diff --git a/test/Driver/mips-mabs-warning.c b/test/Driver/mips-mabs-warning.c
new file mode 100644
index 0000000000..93175be4cc
--- /dev/null
+++ b/test/Driver/mips-mabs-warning.c
@@ -0,0 +1,6 @@
+// REQUIRES: mips-registered-target
+// RUN: %clang -c -target mips-unknown-gnu -mcpu=mips32 -mabs=2008 %s 2>&1 | FileCheck -check-prefix=NO2008 %s
+// NO2008: warning: ignoring '-mabs=2008' option because the 'mips32' architecture does not support it [-Wunsupported-abs]
+
+// RUN: %clang -c -target mips-unknown-gnu -mcpu=mips32r6 -mabs=legacy %s 2>&1 | FileCheck -check-prefix=NOLEGACY %s
+// NOLEGACY: warning: ignoring '-mabs=legacy' option because the 'mips32r6' architecture does not support it [-Wunsupported-abs]
diff --git a/test/Driver/modules-ts.cpp b/test/Driver/modules-ts.cpp
index 0fdc61b6f9..3847b71f7b 100644
--- a/test/Driver/modules-ts.cpp
+++ b/test/Driver/modules-ts.cpp
@@ -1,10 +1,10 @@
// Check compiling a module interface to a .pcm file.
//
-// RUN: %clang -fmodules-ts -x c++-module --precompile %s -Dimplementation= -o %t.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
+// RUN: %clang -fmodules-ts -x c++-module --precompile %s -o %t.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
//
// CHECK-PRECOMPILE: -cc1 {{.*}} -emit-module-interface
// CHECK-PRECOMPILE-SAME: -o {{.*}}.pcm
-// CHECK-PRECOMPILE-SAME: -x c++-module
+// CHECK-PRECOMPILE-SAME: -x c++
// CHECK-PRECOMPILE-SAME: modules-ts.cpp
// Check compiling a .pcm file to a .o file.
@@ -18,7 +18,7 @@
// Check use of a .pcm file in another compilation.
//
-// RUN: %clang -fmodules-ts -fmodule-file=%t.pcm %s -c -o %t.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
+// RUN: %clang -fmodules-ts -fmodule-file=%t.pcm -Dexport= %s -c -o %t.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE
//
// CHECK-USE: -cc1
// CHECK-USE-SAME: -emit-obj
@@ -28,11 +28,11 @@
// Check combining precompile and compile steps works.
//
-// RUN: %clang -fmodules-ts -x c++-module %s -Dimplementation= -c -o %t.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE --check-prefix=CHECK-COMPILE
+// RUN: %clang -fmodules-ts -x c++-module %s -c -o %t.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE --check-prefix=CHECK-COMPILE
// Check that .cppm is treated as a module implicitly.
// RUN: cp %s %t.cppm
-// RUN: %clang -fmodules-ts --precompile %t.cppm -Dimplementation= -o %t.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
+// RUN: %clang -fmodules-ts --precompile %t.cppm -o %t.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
-// Note, we use -Dimplementation= to make this a valid module interface unit when building the interface.
-module implementation foo;
+// Note, we use -Dexport= to make this a module implementation unit when building the implementation.
+export module foo;
diff --git a/test/Driver/myriad-toolchain.c b/test/Driver/myriad-toolchain.c
index 971e5d3e69..7bd215bf1a 100644
--- a/test/Driver/myriad-toolchain.c
+++ b/test/Driver/myriad-toolchain.c
@@ -54,9 +54,11 @@
// -fno-split-dwarf-inlining is consumed but not passed to moviCompile.
// RUN: %clang -target shave-myriad -c -### %s -g -fno-inline-functions \
// RUN: -fno-inline-functions-called-once -Os -Wall -MF dep.d -fno-split-dwarf-inlining \
-// RUN: -ffunction-sections 2>&1 | FileCheck %s -check-prefix=PASSTHRU_OPTIONS
+// RUN: -ffunction-sections -Xclang -xclangflag -mllvm -llvm-flag 2>&1 \
+// RUN: | FileCheck %s -check-prefix=PASSTHRU_OPTIONS
// PASSTHRU_OPTIONS: "-g" "-fno-inline-functions" "-fno-inline-functions-called-once"
// PASSTHRU_OPTIONS: "-Os" "-Wall" "-MF" "dep.d" "-ffunction-sections"
+// PASSTHRU_OPTIONS: "-Xclang" "-xclangflag" "-mllvm" "-llvm-flag"
// RUN: %clang -target shave-myriad -c %s -o foo.o -### -MD -MF dep.d 2>&1 \
// RUN: | FileCheck %s -check-prefix=MDMF
diff --git a/test/Driver/nacl-direct.c b/test/Driver/nacl-direct.c
index f71e14f996..3c8e33b180 100644
--- a/test/Driver/nacl-direct.c
+++ b/test/Driver/nacl-direct.c
@@ -46,7 +46,7 @@
// RUN: | FileCheck --check-prefix=CHECK-ARM %s
// CHECK-ARM: {{.*}}clang{{.*}}" "-cc1"
// CHECK-ARM: "-fuse-init-array"
-// CHECK-ARM: "-target-cpu" "cortex-a8"
+// CHECK-ARM: "-target-cpu" "generic"
// CHECK-ARM: "-target-abi" "aapcs-linux"
// CHECK-ARM: "-mfloat-abi" "hard"
// CHECK-ARM: "-resource-dir" "foo"
diff --git a/test/Driver/nios2-cpu.c b/test/Driver/nios2-cpu.c
new file mode 100644
index 0000000000..d98f0384a6
--- /dev/null
+++ b/test/Driver/nios2-cpu.c
@@ -0,0 +1,26 @@
+// RUN: %clang -target nios2--- %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck %s
+
+// RUN: %clang -target nios2--- -mcpu=r1 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R1 %s
+// RUN: %clang -target nios2--- -mcpu=nios2r1 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R1 %s
+// RUN: %clang -target nios2--- -march=r1 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R1 %s
+// RUN: %clang -target nios2--- -march=nios2r1 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R1 %s
+
+// RUN: %clang -target nios2--- -mcpu=r2 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R2 %s
+// RUN: %clang -target nios2--- -mcpu=nios2r2 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R2 %s
+// RUN: %clang -target nios2--- -march=r2 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R2 %s
+// RUN: %clang -target nios2--- -march=nios2r2 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-R2 %s
+
+// CHECK: "-triple" "nios2---"
+// CHECK-R1: "-triple" "nios2---"
+// CHECK-R1: "-target-cpu" "nios2r1"
+// CHECK-R2: "-triple" "nios2---"
+// CHECK-R2: "-target-cpu" "nios2r2"
diff --git a/test/Driver/nostdlib.c b/test/Driver/nostdlib.c
index a9ef665c57..c9793d968c 100644
--- a/test/Driver/nostdlib.c
+++ b/test/Driver/nostdlib.c
@@ -27,5 +27,5 @@
//
// CHECK-LINUX-NOSTDLIB: warning: argument unused during compilation: '--rtlib=compiler-rt'
// CHECK-LINUX-NOSTDLIB: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
-// CHECK-LINUX-NOSTDLIB-NOT: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.builtins-i686.a"
+// CHECK-LINUX-NOSTDLIB-NOT: "{{.*}}/Inputs/resource_dir{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.builtins-i386.a"
// CHECK-MSVC-NOSTDLIB: warning: argument unused during compilation: '--rtlib=compiler-rt'
diff --git a/test/Driver/nostdlibxx.cpp b/test/Driver/nostdlibxx.cpp
new file mode 100644
index 0000000000..02bd62d96a
--- /dev/null
+++ b/test/Driver/nostdlibxx.cpp
@@ -0,0 +1,8 @@
+// RUN: %clangxx -target i686-pc-linux-gnu -### -nostdlib++ %s 2> %t
+// RUN: FileCheck < %t %s
+
+// We should still have -lm and the C standard libraries, but not -lstdc++.
+
+// CHECK-NOT: -lstdc++
+// CHECK-NOT: -lc++
+// CHECK: -lm
diff --git a/test/Driver/nozlibcompress.c b/test/Driver/nozlibcompress.c
index 9986c85d79..41e1794ad9 100644
--- a/test/Driver/nozlibcompress.c
+++ b/test/Driver/nozlibcompress.c
@@ -1,6 +1,7 @@
-// RUN: %clang -c %s -Wa,--compress-debug-sections 2>&1 | FileCheck %s
-// RUN: %clang -c %s -Wa,--compress-debug-sections -Wa,--nocompress-debug-sections 2>&1 | FileCheck --allow-empty --check-prefix=NOWARN %s
// REQUIRES: nozlib
-// CHECK: warning: cannot compress debug sections (zlib not installed)
-// NOWARN-NOT: warning: cannot compress debug sections (zlib not installed)
+// RUN: %clang -### -fintegrated-as -gz -c %s 2>&1 | FileCheck %s -check-prefix CHECK-WARN
+// RUN: %clang -### -fintegrated-as -gz=none -c %s 2>&1 | FileCheck -allow-empty -check-prefix CHECK-NOWARN %s
+
+// CHECK-WARN: warning: cannot compress debug sections (zlib not installed)
+// CHECK-NOWARN-NOT: warning: cannot compress debug sections (zlib not installed)
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index b4e2796c5d..2bcd703770 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -77,7 +77,9 @@
// Check linking against correct startup code when (not) using PIE
// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-PIE %s
-// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd %s -fno-pie %s -### 2>&1 \
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -pie %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-PIE-FLAG %s
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -fno-pie %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-PIE %s
// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -static %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-STATIC-PIE %s
@@ -93,6 +95,7 @@
// RUN: | FileCheck -check-prefix=CHECK-NOPIE %s
// CHECK-PIE: "{{.*}}crt0.o"
// CHECK-PIE-NOT: "-nopie"
+// CHECK-PIE-FLAG: "-pie"
// CHECK-STATIC-PIE: "{{.*}}rcrt0.o"
// CHECK-STATIC-PIE-NOT: "-nopie"
// CHECK-NOPIE: "-nopie" "{{.*}}crt0.o"
diff --git a/test/Driver/openmp-offload-gpu.c b/test/Driver/openmp-offload-gpu.c
new file mode 100644
index 0000000000..abef552a6e
--- /dev/null
+++ b/test/Driver/openmp-offload-gpu.c
@@ -0,0 +1,112 @@
+///
+/// Perform several driver tests for OpenMP offloading
+///
+
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: powerpc-registered-target
+// REQUIRES: nvptx-registered-target
+
+/// ###########################################################################
+
+/// Check -Xopenmp-target uses one of the archs provided when several archs are used.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target -march=sm_35 -Xopenmp-target -march=sm_60 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET-ARCHS %s
+
+// CHK-FOPENMP-TARGET-ARCHS: ptxas{{.*}}" "--gpu-name" "sm_60"
+// CHK-FOPENMP-TARGET-ARCHS: nvlink{{.*}}" "-arch" "sm_60"
+
+/// ###########################################################################
+
+/// Check -Xopenmp-target -march=sm_35 works as expected when two triples are present.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu,nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda -march=sm_35 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET-COMPILATION %s
+
+// CHK-FOPENMP-TARGET-COMPILATION: ptxas{{.*}}" "--gpu-name" "sm_35"
+// CHK-FOPENMP-TARGET-COMPILATION: nvlink{{.*}}" "-arch" "sm_35"
+
+/// ###########################################################################
+
+/// Check cubin file generation and usage by nvlink
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -save-temps %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-CUBIN %s
+
+// CHK-CUBIN: clang{{.*}}" "-o" "{{.*}}.s"
+// CHK-CUBIN-NEXT: ptxas{{.*}}" "--output-file" {{.*}}.cubin" {{.*}}.s"
+// CHK-CUBIN-NEXT: nvlink" {{.*}}.cubin"
+
+
+/// ###########################################################################
+
+/// Check cubin file generation and usage by nvlink when toolchain has BindArchAction
+// RUN: %clang -### -no-canonical-prefixes -target x86_64-apple-darwin17.0.0 -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-CUBIN-DARWIN %s
+
+// CHK-CUBIN-DARWIN: clang{{.*}}" "-o" "{{.*}}.s"
+// CHK-CUBIN-DARWIN-NEXT: ptxas{{.*}}" "--output-file" {{.*}}.cubin" {{.*}}.s"
+// CHK-CUBIN-DARWIN-NEXT: nvlink" {{.*}}.cubin"
+
+/// ###########################################################################
+
+/// Check cubin file generation and usage by nvlink
+// RUN: touch %t1.o
+// RUN: touch %t2.o
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda %t1.o %t2.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-TWOCUBIN %s
+
+// CHK-TWOCUBIN: nvlink{{.*}}openmp-offload-{{.*}}.cubin" "{{.*}}openmp-offload-{{.*}}.cubin"
+
+/// ###########################################################################
+
+/// Check cubin file generation and usage by nvlink when toolchain has BindArchAction
+// RUN: touch %t1.o
+// RUN: touch %t2.o
+// RUN: %clang -### -no-canonical-prefixes -target x86_64-apple-darwin17.0.0 -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda %t1.o %t2.o 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-TWOCUBIN-DARWIN %s
+
+// CHK-TWOCUBIN-DARWIN: nvlink{{.*}}openmp-offload-{{.*}}.cubin" "{{.*}}openmp-offload-{{.*}}.cubin"
+
+/// ###########################################################################
+
+/// Check PTXAS is passed -c flag when offloading to an NVIDIA device using OpenMP.
+// RUN: %clang -### -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -no-canonical-prefixes %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-PTXAS-DEFAULT %s
+
+// CHK-PTXAS-DEFAULT: ptxas{{.*}}" "-c"
+
+/// ###########################################################################
+
+/// PTXAS is passed -c flag by default when offloading to an NVIDIA device using OpenMP - disable it.
+// RUN: %clang -### -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -fnoopenmp-relocatable-target -save-temps -no-canonical-prefixes %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-PTXAS-NORELO %s
+
+// CHK-PTXAS-NORELO-NOT: ptxas{{.*}}" "-c"
+
+/// ###########################################################################
+
+/// PTXAS is passed -c flag by default when offloading to an NVIDIA device using OpenMP
+/// Check that the flag is passed when -fopenmp-relocatable-target is used.
+// RUN: %clang -### -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -fopenmp-relocatable-target -save-temps -no-canonical-prefixes %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-PTXAS-RELO %s
+
+// CHK-PTXAS-RELO: ptxas{{.*}}" "-c"
+
+/// ###########################################################################
+
+/// Check that error is not thrown by toolchain when no cuda lib flag is used.
+/// Check that the flag is passed when -fopenmp-relocatable-target is used.
+// RUN: %clang -### -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target -march=sm_60 \
+// RUN: -nocudalib -fopenmp-relocatable-target -save-temps -no-canonical-prefixes %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FLAG-NOLIBDEVICE %s
+
+// CHK-FLAG-NOLIBDEVICE-NOT: error:{{.*}}sm_60
+
+/// ###########################################################################
+
+/// Check that error is not thrown by toolchain when no cuda lib device is found when using -S.
+/// Check that the flag is passed when -fopenmp-relocatable-target is used.
+// RUN: %clang -### -S -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target -march=sm_60 \
+// RUN: -fopenmp-relocatable-target -save-temps -no-canonical-prefixes %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-NOLIBDEVICE %s
+
+// CHK-NOLIBDEVICE-NOT: error:{{.*}}sm_60
diff --git a/test/Driver/openmp-offload.c b/test/Driver/openmp-offload.c
index 097dc7d17f..67098c9022 100644
--- a/test/Driver/openmp-offload.c
+++ b/test/Driver/openmp-offload.c
@@ -39,6 +39,62 @@
/// ###########################################################################
+/// Check -Xopenmp-target=powerpc64le-ibm-linux-gnu -mcpu=pwr7 is passed when compiling for the device.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu -Xopenmp-target=powerpc64le-ibm-linux-gnu -mcpu=pwr7 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-EQ-TARGET %s
+
+// CHK-FOPENMP-EQ-TARGET: clang{{.*}} "-target-cpu" "pwr7" {{.*}}"-fopenmp-is-device"
+
+/// ###########################################################################
+
+/// Check -Xopenmp-target -mcpu=pwr7 is passed when compiling for the device.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu -Xopenmp-target -mcpu=pwr7 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET %s
+
+// CHK-FOPENMP-TARGET: clang{{.*}} "-target-cpu" "pwr7" {{.*}}"-fopenmp-is-device"
+
+/// ##########################################################################
+
+/// Check -mcpu=pwr7 is passed to the same triple.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu -target powerpc64le-ibm-linux-gnu -mcpu=pwr7 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-MCPU-TO-SAME-TRIPLE %s
+
+// CHK-FOPENMP-MCPU-TO-SAME-TRIPLE: clang{{.*}} "-target-cpu" "pwr7" {{.*}}"-fopenmp-is-device"
+
+/// ##########################################################################
+
+/// Check -march=pwr7 is NOT passed to nvptx64-nvidia-cuda.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda -target powerpc64le-ibm-linux-gnu -march=pwr7 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-MARCH-TO-GPU %s
+
+// CHK-FOPENMP-MARCH-TO-GPU-NOT: clang{{.*}} "-target-cpu" "pwr7" {{.*}}"-fopenmp-is-device"
+
+/// ###########################################################################
+
+/// Check -march=pwr7 is NOT passed to x86_64-unknown-linux-gnu.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=x86_64-unknown-linux-gnu -target powerpc64le-ibm-linux-gnu -march=pwr7 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-MARCH-TO-X86 %s
+
+// CHK-FOPENMP-MARCH-TO-X86-NOT: clang{{.*}} "-target-cpu" "pwr7" {{.*}}"-fopenmp-is-device"
+
+/// ###########################################################################
+
+/// Check -Xopenmp-target triggers error when multiple triples are used.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu,powerpc64le-unknown-linux-gnu -Xopenmp-target -mcpu=pwr8 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET-AMBIGUOUS-ERROR %s
+
+// CHK-FOPENMP-TARGET-AMBIGUOUS-ERROR: clang{{.*}} error: cannot deduce implicit triple value for -Xopenmp-target, specify triple using -Xopenmp-target=<triple>
+
+/// ###########################################################################
+
+/// Check -Xopenmp-target triggers error when an option requiring arguments is passed to it.
+// RUN: %clang -### -no-canonical-prefixes -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu -Xopenmp-target -Xopenmp-target -mcpu=pwr8 %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-TARGET-NESTED-ERROR %s
+
+// CHK-FOPENMP-TARGET-NESTED-ERROR: clang{{.*}} error: invalid -Xopenmp-target argument: '-Xopenmp-target -Xopenmp-target', options requiring arguments are unsupported
+
+/// ###########################################################################
+
/// Check the phases graph when using a single target, different from the host.
/// We should have an offload action joining the host compile and device
/// preprocessor and another one joining the device linking outputs to the host
@@ -210,14 +266,16 @@
// CHK-LKS-ST: INPUT([[T2BIN:.+\.out-openmp-x86_64-pc-linux-gnu]])
// CHK-LKS: SECTIONS
// CHK-LKS: {
-// CHK-LKS: .omp_offloading :
+// CHK-LKS: .omp_offloading.powerpc64le-ibm-linux-gnu :
// CHK-LKS: ALIGN(0x10)
// CHK-LKS: {
-// CHK-LKS: . = ALIGN(0x10);
// CHK-LKS: PROVIDE_HIDDEN(.omp_offloading.img_start.powerpc64le-ibm-linux-gnu = .);
// CHK-LKS: [[T1BIN]]
// CHK-LKS: PROVIDE_HIDDEN(.omp_offloading.img_end.powerpc64le-ibm-linux-gnu = .);
-// CHK-LKS: . = ALIGN(0x10);
+// CHK-LKS: }
+// CHK-LKS: .omp_offloading.x86_64-pc-linux-gnu :
+// CHK-LKS: ALIGN(0x10)
+// CHK-LKS: {
// CHK-LKS: PROVIDE_HIDDEN(.omp_offloading.img_start.x86_64-pc-linux-gnu = .);
// CHK-LKS: [[T2BIN]]
// CHK-LKS: PROVIDE_HIDDEN(.omp_offloading.img_end.x86_64-pc-linux-gnu = .);
@@ -248,15 +306,15 @@
//
// Compile for the powerpc device.
//
-// CHK-COMMANDS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-obj" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-SAME: [[T1OBJ:[^\\/]+\.o]]" "-x" "c" "{{.*}}[[INPUT]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
// CHK-COMMANDS: ld{{(\.exe)?}}" {{.*}}"-o" "
// CHK-COMMANDS-SAME: [[T1BIN:[^\\/]+\.out]]" {{.*}}"{{.*}}[[T1OBJ]]"
-// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T1PP:[^\\/]+\.i]]" "-x" "c" "{{.*}}[[INPUT]]"
-// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-llvm-bc" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T1BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T1PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T1ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T1BC]]"
// CHK-COMMANDS-ST: clang{{.*}}" "-cc1as" "-triple" "powerpc64le-ibm-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T1OBJ:[^\\/]+\.o]]" "{{.*}}[[T1ASM]]"
@@ -265,15 +323,15 @@
//
// Compile for the x86 device.
//
-// CHK-COMMANDS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-obj" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-SAME: [[T2OBJ:[^\\/]+\.o]]" "-x" "c" "{{.*}}[[INPUT]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
// CHK-COMMANDS: ld{{(\.exe)?}}" {{.*}}"-o" "
// CHK-COMMANDS-SAME: [[T2BIN:[^\\/]+\.out]]" {{.*}}"{{.*}}[[T2OBJ]]"
-// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T2PP:[^\\/]+\.i]]" "-x" "c" "{{.*}}[[INPUT]]"
-// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-llvm-bc" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-pic-level" "2" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T2BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T2PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-COMMANDS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T2ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T2BC]]"
// CHK-COMMANDS-ST: clang{{.*}}" "-cc1as" "-triple" "x86_64-pc-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-COMMANDS-ST-SAME: [[T2OBJ:[^\\/]+\.o]]" "{{.*}}[[T2ASM]]"
@@ -396,25 +454,25 @@
// CHK-BUJOBS-ST-SAME: [[HOSTBC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[HOSTPP]]" "-fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu"
// Create target 1 object.
-// CHK-BUJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-SAME: [[T1OBJ:[^\\/]+\.o]]" "-x" "c" "{{.*}}[[INPUT]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T1PP:[^\\/]+\.i]]" "-x" "c" "{{.*}}[[INPUT]]"
-// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T1BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T1PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T1ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T1BC]]"
// CHK-BUJOBS-ST: clang{{.*}}" "-cc1as" "-triple" "powerpc64le-ibm-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T1OBJ:[^\\/]+\.o]]" "{{.*}}[[T1ASM]]"
// Create target 2 object.
-// CHK-BUJOBS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-SAME: [[T2OBJ:[^\\/]+\.o]]" "-x" "c" "{{.*}}[[INPUT]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-E" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T2PP:[^\\/]+\.i]]" "-x" "c" "{{.*}}[[INPUT]]"
-// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T2BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T2PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-BUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T2ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T2BC]]"
// CHK-BUJOBS-ST: clang{{.*}}" "-cc1as" "-triple" "x86_64-pc-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-BUJOBS-ST-SAME: [[T2OBJ:[^\\/]+\.o]]" "{{.*}}[[T2ASM]]"
@@ -462,13 +520,13 @@
// CHK-UBJOBS-ST-SAME: [[HOSTBC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[HOSTPP]]" "-fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu"
// Create target 1 object.
-// CHK-UBJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBJOBS-SAME: [[T1OBJ:[^\\/]+\.o]]" "-x" "cpp-output" "{{.*}}[[T1PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
// CHK-UBJOBS: ld{{(\.exe)?}}" {{.*}}"-o" "
// CHK-UBJOBS-SAME: [[T1BIN:[^\\/]+\.out]]" {{.*}}"{{.*}}[[T1OBJ]]"
-// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBJOBS-ST-SAME: [[T1BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T1PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBJOBS-ST-SAME: [[T1ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T1BC]]"
// CHK-UBJOBS-ST: clang{{.*}}" "-cc1as" "-triple" "powerpc64le-ibm-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-UBJOBS-ST-SAME: [[T1OBJ:[^\\/]+\.o]]" "{{.*}}[[T1ASM]]"
@@ -476,13 +534,13 @@
// CHK-UBJOBS-ST-SAME: [[T1BIN:[^\\/]+\.out-openmp-powerpc64le-ibm-linux-gnu]]" {{.*}}"{{.*}}[[T1OBJ]]"
// Create target 2 object.
-// CHK-UBJOBS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBJOBS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBJOBS-SAME: [[T2OBJ:[^\\/]+\.o]]" "-x" "cpp-output" "{{.*}}[[T2PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
// CHK-UBJOBS: ld{{(\.exe)?}}" {{.*}}"-o" "
// CHK-UBJOBS-SAME: [[T2BIN:[^\\/]+\.out]]" {{.*}}"{{.*}}[[T2OBJ]]"
-// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBJOBS-ST-SAME: [[T2BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T2PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBJOBS-ST-SAME: [[T2ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T2BC]]"
// CHK-UBJOBS-ST: clang{{.*}}" "-cc1as" "-triple" "x86_64-pc-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-UBJOBS-ST-SAME: [[T2OBJ:[^\\/]+\.o]]" "{{.*}}[[T2ASM]]"
@@ -557,21 +615,21 @@
// CHK-UBUJOBS-ST-SAME: [[HOSTBC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[HOSTPP]]" "-fopenmp-targets=powerpc64le-ibm-linux-gnu,x86_64-pc-linux-gnu"
// Create target 1 object.
-// CHK-UBUJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBUJOBS: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBUJOBS-SAME: [[T1OBJ:[^\\/]+\.o]]" "-x" "cpp-output" "{{.*}}[[T1PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBUJOBS-ST-SAME: [[T1BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T1PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "powerpc64le-ibm-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBUJOBS-ST-SAME: [[T1ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T1BC]]"
// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1as" "-triple" "powerpc64le-ibm-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-UBUJOBS-ST-SAME: [[T1OBJ:[^\\/]+\.o]]" "{{.*}}[[T1ASM]]"
// Create target 2 object.
-// CHK-UBUJOBS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBUJOBS: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-obj" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBUJOBS-SAME: [[T2OBJ:[^\\/]+\.o]]" "-x" "cpp-output" "{{.*}}[[T2PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-emit-llvm-bc" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBUJOBS-ST-SAME: [[T2BC:[^\\/]+\.bc]]" "-x" "cpp-output" "{{.*}}[[T2PP]]" "-fopenmp-is-device" "-fopenmp-host-ir-file-path" "{{.*}}[[HOSTBC]]"
-// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
+// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1" "-triple" "x86_64-pc-linux-gnu" "-aux-triple" "powerpc64le--linux" "-S" {{.*}}"-fopenmp" {{.*}}"-o" "
// CHK-UBUJOBS-ST-SAME: [[T2ASM:[^\\/]+\.s]]" "-x" "ir" "{{.*}}[[T2BC]]"
// CHK-UBUJOBS-ST: clang{{.*}}" "-cc1as" "-triple" "x86_64-pc-linux-gnu" "-filetype" "obj" {{.*}}"-o" "
// CHK-UBUJOBS-ST-SAME: [[T2OBJ:[^\\/]+\.o]]" "{{.*}}[[T2ASM]]"
@@ -587,3 +645,11 @@
// CHK-UBUJOBS-ST-SAME: [[HOSTOBJ:[^\\/]+\.o]]" "{{.*}}[[HOSTASM]]"
// CHK-UBUJOBS-ST: clang-offload-bundler{{.*}}" "-type=o" "-targets=openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu,host-powerpc64le--linux" "-outputs=
// CHK-UBUJOBS-ST-SAME: [[RES:[^\\/]+\.o]]" "-inputs={{.*}}[[T1OBJ]],{{.*}}[[T2OBJ]],{{.*}}[[HOSTOBJ]]"
+
+/// ###########################################################################
+
+/// Check -fopenmp-is-device is passed when compiling for the device.
+// RUN: %clang -### -no-canonical-prefixes -target powerpc64le-linux -fopenmp=libomp -fopenmp-targets=powerpc64le-ibm-linux-gnu %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-FOPENMP-IS-DEVICE %s
+
+// CHK-FOPENMP-IS-DEVICE: clang{{.*}} "-aux-triple" "powerpc64le--linux" {{.*}}.c" "-fopenmp-is-device" "-fopenmp-host-ir-file-path"
diff --git a/test/Driver/opt-record.c b/test/Driver/opt-record.c
index 6e684878d4..5e8a28f5f8 100644
--- a/test/Driver/opt-record.c
+++ b/test/Driver/opt-record.c
@@ -1,6 +1,10 @@
// RUN: %clang -### -S -o FOO -fsave-optimization-record %s 2>&1 | FileCheck %s
// RUN: %clang -### -c -o FOO -fsave-optimization-record %s 2>&1 | FileCheck %s
+// RUN: %clang -### -c -o FOO.o -fsave-optimization-record %s 2>&1 | FileCheck %s
+// RUN: %clang -### -save-temps -S -o FOO -fsave-optimization-record %s 2>&1 | FileCheck %s
+// RUN: %clang -### -save-temps -c -o FOO.o -fsave-optimization-record %s 2>&1 | FileCheck %s
// RUN: %clang -### -c -fsave-optimization-record %s 2>&1 | FileCheck %s -check-prefix=CHECK-NO-O
+// RUN: %clang -### -save-temps -c -fsave-optimization-record %s 2>&1 | FileCheck %s -check-prefix=CHECK-NO-O
// RUN: %clang -### -fsave-optimization-record %s 2>&1 | FileCheck %s -check-prefix=CHECK-NO-O
// RUN: %clang -### -S -fsave-optimization-record -x cuda -nocudainc -nocudalib %s 2>&1 | FileCheck %s -check-prefix=CHECK-NO-O -check-prefix=CHECK-CUDA-DEV
// RUN: %clang -### -fsave-optimization-record -x cuda -nocudainc -nocudalib %s 2>&1 | FileCheck %s -check-prefix=CHECK-NO-O -check-prefix=CHECK-CUDA-DEV
diff --git a/test/Driver/output-file-cleanup.c b/test/Driver/output-file-cleanup.c
index 314af4d6d3..74d64b0c17 100644
--- a/test/Driver/output-file-cleanup.c
+++ b/test/Driver/output-file-cleanup.c
@@ -25,30 +25,34 @@
invalid C code
#endif
-// RUN: touch %t1.c
-// RUN: echo "invalid C code" > %t2.c
-// RUN: cd %T && not %clang -S %t1.c %t2.c
-// RUN: test -f %t1.s
-// RUN: test ! -f %t2.s
-
-// RUN: touch %t1.c
-// RUN: touch %t2.c
-// RUN: chmod -r %t2.c
-// RUN: cd %T && not %clang -S %t1.c %t2.c
-// RUN: test -f %t1.s
-// RUN: test ! -f %t2.s
+// RUN: rm -rf %t-dir
+// RUN: mkdir -p %t-dir
+// RUN: cd %t-dir
+
+// RUN: touch %t-dir/1.c
+// RUN: echo "invalid C code" > %t-dir/2.c
+// RUN: not %clang -S %t-dir/1.c %t-dir/2.c
+// RUN: test -f %t-dir/1.s
+// RUN: test ! -f %t-dir/2.s
+
+// RUN: touch %t-dir/1.c
+// RUN: touch %t-dir/2.c
+// RUN: chmod -r %t-dir/2.c
+// RUN: not %clang -S %t-dir/1.c %t-dir/2.c
+// RUN: test -f %t-dir/1.s
+// RUN: test ! -f %t-dir/2.s
// When given multiple .c files to compile, clang compiles them in order until
// it hits an error, at which point it stops.
//
-// RUN: touch %t1.c
-// RUN: echo "invalid C code" > %t2.c
-// RUN: touch %t3.c
-// RUN: echo "invalid C code" > %t4.c
-// RUN: touch %t5.c
-// RUN: cd %T && not %clang -S %t1.c %t2.c %t3.c %t4.c %t5.c
-// RUN: test -f %t1.s
-// RUN: test ! -f %t2.s
-// RUN: test ! -f %t3.s
-// RUN: test ! -f %t4.s
-// RUN: test ! -f %t5.s
+// RUN: touch %t-dir/1.c
+// RUN: echo "invalid C code" > %t-dir/2.c
+// RUN: touch %t-dir/3.c
+// RUN: echo "invalid C code" > %t-dir/4.c
+// RUN: touch %t-dir/5.c
+// RUN: not %clang -S %t-dir/1.c %t-dir/2.c %t-dir/3.c %t-dir/4.c %t-dir/5.c
+// RUN: test -f %t-dir/1.s
+// RUN: test ! -f %t-dir/2.s
+// RUN: test ! -f %t-dir/3.s
+// RUN: test ! -f %t-dir/4.s
+// RUN: test ! -f %t-dir/5.s
diff --git a/test/Driver/parse-progname.c b/test/Driver/parse-progname.c
index 33c6378223..c432b10e31 100644
--- a/test/Driver/parse-progname.c
+++ b/test/Driver/parse-progname.c
@@ -1,58 +1,58 @@
// REQUIRES: shell, arm-registered-target
-
-
-// RUN: ln -fs %clang %T/clang++
-// RUN: ln -fs %clang %T/clang++3.5.0
-// RUN: ln -fs %clang %T/clang++-3.5
-// RUN: ln -fs %clang %T/clang++-tot
-// RUN: ln -fs %clang %T/clang-c++
-// RUN: ln -fs %clang %T/clang-g++
-// RUN: ln -fs %clang %T/c++
-// RUN: ln -fs %clang %T/foo-clang++
-// RUN: ln -fs %clang %T/foo-clang++-3.5
-// RUN: ln -fs %clang %T/foo-clang++3.5
-// RUN: %T/clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/clang++3.5.0 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/clang++-tot -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/clang-c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/clang-g++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/foo-clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/foo-clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
-// RUN: %T/foo-clang++3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: mkdir -p %t
+
+// RUN: ln -fs %clang %t/clang++
+// RUN: ln -fs %clang %t/clang++3.5.0
+// RUN: ln -fs %clang %t/clang++-3.5
+// RUN: ln -fs %clang %t/clang++-tot
+// RUN: ln -fs %clang %t/clang-c++
+// RUN: ln -fs %clang %t/clang-g++
+// RUN: ln -fs %clang %t/c++
+// RUN: ln -fs %clang %t/foo-clang++
+// RUN: ln -fs %clang %t/foo-clang++-3.5
+// RUN: ln -fs %clang %t/foo-clang++3.5
+// RUN: %t/clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/clang++3.5.0 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/clang++-tot -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/clang-c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/clang-g++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/foo-clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/foo-clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
+// RUN: %t/foo-clang++3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s
// CXXMODE: "-x" "c++"
-// RUN: ln -fs %clang %T/clang-cl
-// RUN: ln -fs %clang %T/cl
-// RUN: ln -fs %clang %T/cl.exe
-// RUN: ln -fs %clang %T/clang-cl3.5
-// RUN: ln -fs %clang %T/clang-cl-3.5
+// RUN: ln -fs %clang %t/clang-cl
+// RUN: ln -fs %clang %t/cl
+// RUN: ln -fs %clang %t/cl.exe
+// RUN: ln -fs %clang %t/clang-cl3.5
+// RUN: ln -fs %clang %t/clang-cl-3.5
// Note: use -- in front of the filename so it's not mistaken for an option on
// filesystems that use slashes for dir separators.
-// RUN: %T/clang-cl -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
-// RUN: %T/cl -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
-// RUN: %T/cl.exe -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
-// RUN: %T/clang-cl3.5 -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
-// RUN: %T/clang-cl-3.5 -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %t/clang-cl -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %t/cl -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %t/cl.exe -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %t/clang-cl3.5 -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
+// RUN: %t/clang-cl-3.5 -### -- %s 2>&1 | FileCheck -check-prefix=CLMODE %s
// CLMODE: "-fdiagnostics-format" "msvc"
-// RUN: ln -fs %clang %T/clang-cpp
-// RUN: ln -fs %clang %T/cpp
-// RUN: %T/clang-cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s
-// RUN: %T/cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s
+// RUN: ln -fs %clang %t/clang-cpp
+// RUN: ln -fs %clang %t/cpp
+// RUN: %t/clang-cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s
+// RUN: %t/cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s
// CPPMODE: "-E"
-// RUN: ln -fs %clang %T/cl-clang
-// RUN: %T/cl-clang -### %s 2>&1 | FileCheck -check-prefix=CMODE %s
+// RUN: ln -fs %clang %t/cl-clang
+// RUN: %t/cl-clang -### %s 2>&1 | FileCheck -check-prefix=CMODE %s
// CMODE: "-x" "c"
// CMODE-NOT: "-fdiagnostics-format" "msvc"
-// RUN: ln -fs %clang %T/arm-linux-gnueabi-clang
-// RUN: %T/arm-linux-gnueabi-clang -### %s 2>&1 | FileCheck -check-prefix=TARGET %s
+// RUN: ln -fs %clang %t/arm-linux-gnueabi-clang
+// RUN: %t/arm-linux-gnueabi-clang -### %s 2>&1 | FileCheck -check-prefix=TARGET %s
// TARGET: Target: arm--linux-gnueabi
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index 9f9d09c54c..f2618eede3 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 \
@@ -243,18 +247,58 @@
// On OpenBSD, -nopie needs to be passed through to the linker.
// RUN: %clang %s -target i386-pc-openbsd -nopie -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NOPIE-LD
+// Try with the alias
+// RUN: %clang %s -target i386-pc-openbsd -no-pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NOPIE-LD
//
-// On Android PIC is enabled by default
+// On Android PIC is enabled by default, and PIE is enabled by default starting
+// with API16.
// RUN: %clang -c %s -target i686-linux-android -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i686-linux-android14 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC2
+// RUN: %clang -c %s -target i686-linux-android16 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target i686-linux-android24 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+//
// RUN: %clang -c %s -target arm-linux-androideabi -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: %clang -c %s -target arm-linux-androideabi14 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: %clang -c %s -target arm-linux-androideabi16 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target arm-linux-androideabi24 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+//
// RUN: %clang -c %s -target mipsel-linux-android -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
-// RUN: %clang -c %s -target aarch64-linux-android -### 2>&1 \
+// RUN: %clang -c %s -target mipsel-linux-android14 -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: %clang -c %s -target mipsel-linux-android16 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target mipsel-linux-android24 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+//
+// 64-bit Android targets are always PIE.
+// RUN: %clang -c %s -target aarch64-linux-android -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target aarch64-linux-android24 -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
// RUN: %clang -c %s -target arm64-linux-android -### 2>&1 \
-// RUN: | FileCheck %s --check-prefix=CHECK-PIC1
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+//
+// Default value of PIE can be overwritten, even on 64-bit targets.
+// RUN: %clang -c %s -target arm-linux-androideabi -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target i686-linux-android14 -fPIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-PIE2
+// RUN: %clang -c %s -target i686-linux-android16 -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target aarch64-linux-android -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target aarch64-linux-android24 -fno-PIE -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
//
// On Windows-X64 PIC is enabled by default
// RUN: %clang -c %s -target x86_64-pc-windows-msvc18.0.0 -### 2>&1 \
diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp
index e32a51a833..621c407d37 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"
@@ -182,8 +171,8 @@
// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o -no-integrated-as 2>&1 | FileCheck -check-prefix=CHECK_LE_AS_ARGS %s
// CHECK_LE_AS_ARGS: "-mppc64"
-// CHECK_LE_AS_ARGS: "-many"
// CHECK_LE_AS_ARGS: "-mlittle-endian"
+// CHECK_LE_AS_ARGS: "-mpower8"
// linker features
// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK_BE_LD_ARGS %s
diff --git a/test/Driver/print-libgcc-file-name-clangrt.c b/test/Driver/print-libgcc-file-name-clangrt.c
index 9f8120c31d..ce941dc4a1 100644
--- a/test/Driver/print-libgcc-file-name-clangrt.c
+++ b/test/Driver/print-libgcc-file-name-clangrt.c
@@ -6,6 +6,32 @@
// CHECK-CLANGRT-X8664: libclang_rt.builtins-x86_64.a
// RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \
+// RUN: --target=i386-pc-linux \
+// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-I386 %s
+// CHECK-CLANGRT-I386: libclang_rt.builtins-i386.a
+
+// Check whether alternate arch values map to the correct library.
+//
+// RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \
// RUN: --target=i686-pc-linux \
-// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-I686 %s
-// CHECK-CLANGRT-I686: libclang_rt.builtins-i686.a
+// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-I386 %s
+
+// RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \
+// RUN: --target=arm-linux-gnueabi \
+// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM %s
+// CHECK-CLANGRT-ARM: libclang_rt.builtins-arm.a
+
+// RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \
+// RUN: --target=arm-linux-androideabi \
+// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM-ANDROID %s
+// CHECK-CLANGRT-ARM-ANDROID: libclang_rt.builtins-arm-android.a
+
+// RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \
+// RUN: --target=arm-linux-gnueabihf \
+// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARMHF %s
+// CHECK-CLANGRT-ARMHF: libclang_rt.builtins-armhf.a
+
+// RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \
+// RUN: --target=arm-linux-gnueabi -mfloat-abi=hard \
+// RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM-ABI %s
+// CHECK-CLANGRT-ARM-ABI: libclang_rt.builtins-armhf.a
diff --git a/test/Driver/ps4-linker-non-win.c b/test/Driver/ps4-linker-non-win.c
index e2f8386b2c..3197292176 100644
--- a/test/Driver/ps4-linker-non-win.c
+++ b/test/Driver/ps4-linker-non-win.c
@@ -1,21 +1,21 @@
// UNSUPPORTED: system-windows
// REQUIRES: x86-registered-target
-// RUN: mkdir -p %T/Output
-// RUN: rm -f %T/Output/orbis-ld
-// RUN: touch %T/Output/orbis-ld
-// RUN: chmod +x %T/Output/orbis-ld
+// RUN: mkdir -p %t
+// RUN: rm -f %t/orbis-ld
+// RUN: touch %t/orbis-ld
+// RUN: chmod +x %t/orbis-ld
-// RUN: env "PATH=%T/Output:%PATH%" %clang -### -target x86_64-scei-ps4 %s -fuse-ld=gold 2>&1 \
+// RUN: env "PATH=%t:%PATH%" %clang -### -target x86_64-scei-ps4 %s -fuse-ld=gold 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-LINKER %s
-// RUN: env "PATH=%T/Output:%PATH%" %clang -### -target x86_64-scei-ps4 %s -shared 2>&1 \
+// RUN: env "PATH=%t:%PATH%" %clang -### -target x86_64-scei-ps4 %s -shared 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-LINKER %s
-// RUN: env "PATH=%T/Output:%PATH%" %clang -### -target x86_64-scei-ps4 %s 2>&1 \
+// RUN: env "PATH=%t:%PATH%" %clang -### -target x86_64-scei-ps4 %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-LINKER %s
-// RUN: env "PATH=%T/Output:%PATH%" %clang -### -target x86_64-scei-ps4 %s -fuse-ld=ps4 2>&1 \
+// RUN: env "PATH=%t:%PATH%" %clang -### -target x86_64-scei-ps4 %s -fuse-ld=ps4 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-LINKER %s
-// RUN: env "PATH=%T/Output:%PATH%" %clang -### -target x86_64-scei-ps4 %s -shared \
+// RUN: env "PATH=%t:%PATH%" %clang -### -target x86_64-scei-ps4 %s -shared \
// RUN: -fuse-ld=ps4 2>&1 | FileCheck --check-prefix=CHECK-PS4-LINKER %s
// CHECK-PS4-LINKER: /orbis-ld
diff --git a/test/Driver/ps4-linker-win.c b/test/Driver/ps4-linker-win.c
index 6fbd84bb6d..fafa579a07 100644
--- a/test/Driver/ps4-linker-win.c
+++ b/test/Driver/ps4-linker-win.c
@@ -7,19 +7,20 @@
// REQUIRES: system-windows, x86-registered-target
-// RUN: touch %T/orbis-ld.exe
-// RUN: touch %T/orbis-ld.gold.exe
+// RUN: mkdir -p %t
+// RUN: touch %t/orbis-ld.exe
+// RUN: touch %t/orbis-ld.gold.exe
-// RUN: env "PATH=%T;%PATH%;" %clang -target x86_64-scei-ps4 %s -fuse-ld=gold -### 2>&1 \
+// RUN: env "PATH=%t;%PATH%;" %clang -target x86_64-scei-ps4 %s -fuse-ld=gold -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-GOLD %s
-// RUN: env "PATH=%T;%PATH%;" %clang -target x86_64-scei-ps4 %s -shared -### 2>&1 \
+// RUN: env "PATH=%t;%PATH%;" %clang -target x86_64-scei-ps4 %s -shared -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-GOLD %s
-// RUN: env "PATH=%T;%PATH%;" %clang -target x86_64-scei-ps4 %s -### 2>&1 \
+// RUN: env "PATH=%t;%PATH%;" %clang -target x86_64-scei-ps4 %s -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-LINKER %s
-// RUN: env "PATH=%T;%PATH%;" %clang -target x86_64-scei-ps4 %s -fuse-ld=ps4 -### 2>&1 \
+// RUN: env "PATH=%t;%PATH%;" %clang -target x86_64-scei-ps4 %s -fuse-ld=ps4 -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-PS4-LINKER %s
-// RUN: env "PATH=%T;%PATH%;" %clang -target x86_64-scei-ps4 %s -shared \
+// RUN: env "PATH=%t;%PATH%;" %clang -target x86_64-scei-ps4 %s -shared \
// RUN: -fuse-ld=ps4 -### 2>&1 | FileCheck --check-prefix=CHECK-PS4-LINKER %s
// CHECK-PS4-GOLD: \\orbis-ld.gold
diff --git a/test/Driver/reloc-model.c b/test/Driver/reloc-model.c
new file mode 100644
index 0000000000..5d08eee89b
--- /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 bd336309ad..a7c5966c98 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/rewrite-legacy-objc.m b/test/Driver/rewrite-legacy-objc.m
index 6a2b44b8fb..8ac357c844 100644
--- a/test/Driver/rewrite-legacy-objc.m
+++ b/test/Driver/rewrite-legacy-objc.m
@@ -3,11 +3,11 @@
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fencode-extended-block-signature" "-fobjc-runtime=macosx-fragile" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
// TEST0: rewrite-legacy-objc.m"
// RUN: %clang -no-canonical-prefixes -target i386-apple-macosx10.9.0 -rewrite-legacy-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST1 %s
// RUN: %clang -no-canonical-prefixes -target i386-apple-macosx10.6.0 -rewrite-legacy-objc %s -o - -### 2>&1 | \
// RUN: FileCheck -check-prefix=TEST2 %s
-// TEST1: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fobjc-subscripting-legacy-runtime" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
-// TEST2: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
+// TEST1: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fencode-extended-block-signature" "-fobjc-runtime=macosx-fragile" "-fobjc-subscripting-legacy-runtime" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
+// TEST2: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fencode-extended-block-signature" "-fobjc-runtime=macosx-fragile" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index ca1e84042c..b8a1ffe8b8 100644
--- a/test/Driver/rewrite-objc.m
+++ b/test/Driver/rewrite-objc.m
@@ -3,4 +3,4 @@
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fobjc-runtime=macosx" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-fblocks" "-fencode-extended-block-signature" "-fobjc-runtime=macosx" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
index c4a6f4377b..f03714c4b5 100644
--- a/test/Driver/sanitizer-ld.c
+++ b/test/Driver/sanitizer-ld.c
@@ -17,10 +17,23 @@
// CHECK-ASAN-LINUX: "-ldl"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address -shared-libsan \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-SHARED-ASAN-LINUX %s
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address -shared-libasan \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-SHARED-ASAN-LINUX %s
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address \
+// RUN: -shared-libsan -static-libsan -shared-libasan \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-SHARED-ASAN-LINUX %s
//
// CHECK-SHARED-ASAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-SHARED-ASAN-LINUX-NOT: "-lc"
@@ -34,7 +47,7 @@
// CHECK-SHARED-ASAN-LINUX-NOT: "--dynamic-list"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.so -shared 2>&1 \
-// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address -shared-libasan \
+// RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=address -shared-libsan \
// RUN: -resource-dir=%S/Inputs/resource_dir \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-DSO-SHARED-ASAN-LINUX %s
@@ -127,18 +140,63 @@
//
// CHECK-ASAN-ANDROID: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-ASAN-ANDROID-NOT: "-lc"
-// CHECK-ASAN-ANDROID: "-pie"
+// CHECK-ASAN-ANDROID-NOT: "-pie"
// CHECK-ASAN-ANDROID-NOT: "-lpthread"
// CHECK-ASAN-ANDROID: libclang_rt.asan-arm-android.so"
// CHECK-ASAN-ANDROID-NOT: "-lpthread"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=address \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: -static-libsan \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-ANDROID-STATICLIBASAN %s
+//
+// CHECK-ASAN-ANDROID-STATICLIBASAN: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-ANDROID-STATICLIBASAN: libclang_rt.asan-arm-android.a"
+// CHECK-ASAN-ANDROID-STATICLIBASAN: "-lpthread"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=undefined \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-ANDROID %s
+//
+// CHECK-UBSAN-ANDROID: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-UBSAN-ANDROID-NOT: "-lc"
+// CHECK-UBSAN-ANDROID-NOT: "-pie"
+// CHECK-UBSAN-ANDROID-NOT: "-lpthread"
+// CHECK-UBSAN-ANDROID: libclang_rt.ubsan_standalone-arm-android.so"
+// CHECK-UBSAN-ANDROID-NOT: "-lpthread"
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=undefined \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: -static-libsan \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-ANDROID-STATICLIBASAN %s
+//
+// CHECK-UBSAN-ANDROID-STATICLIBASAN: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-UBSAN-ANDROID-STATICLIBASAN: libclang_rt.ubsan_standalone-arm-android.a"
+// CHECK-UBSAN-ANDROID-STATICLIBASAN: "-lpthread"
+
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i686-linux-android -fuse-ld=ld -fsanitize=address \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-ANDROID-X86 %s
+//
+// CHECK-ASAN-ANDROID-X86: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-ANDROID-X86-NOT: "-lc"
+// CHECK-ASAN-ANDROID-X86-NOT: "-pie"
+// CHECK-ASAN-ANDROID-X86-NOT: "-lpthread"
+// CHECK-ASAN-ANDROID-X86: libclang_rt.asan-i686-android.so"
+// CHECK-ASAN-ANDROID-X86-NOT: "-lpthread"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi -fsanitize=address \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
-// RUN: -shared-libasan \
+// RUN: -shared-libsan \
// RUN: | FileCheck --check-prefix=CHECK-ASAN-ANDROID-SHARED-LIBASAN %s
//
-// CHECK-ASAN-ANDROID-SHARED-LIBASAN-NOT: argument unused during compilation: '-shared-libasan'
+// CHECK-ASAN-ANDROID-SHARED-LIBASAN-NOT: argument unused during compilation: '-shared-libsan'
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=address \
@@ -202,6 +260,13 @@
// RUN: -target i386-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX %s
+
+// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: -static-libsan \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX %s
+
// CHECK-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-NOT: libclang_rt.ubsan_standalone_cxx
@@ -211,6 +276,27 @@
// CHECK-UBSAN-LINUX-NOT: "-lstdc++"
// CHECK-UBSAN-LINUX: "-lpthread"
+// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: -shared-libsan \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-SHAREDLIBASAN %s
+
+// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: -static-libsan -shared-libsan \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-SHAREDLIBASAN %s
+
+// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: -shared -shared-libsan \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-SHAREDLIBASAN %s
+
+// CHECK-UBSAN-LINUX-SHAREDLIBASAN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-LINUX-SHAREDLIBASAN: "{{.*}}libclang_rt.ubsan_standalone-i386.so{{.*}}"
+
// RUN: %clang -fsanitize=undefined -fsanitize-link-c++-runtime %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -234,6 +320,28 @@
// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
// CHECK-UBSAN-LINUX-CXX: "-lpthread"
+// RUN: %clang -fsanitize=undefined -fsanitize-minimal-runtime %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-MINIMAL-LINUX %s
+// CHECK-UBSAN-MINIMAL-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-MINIMAL-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan_minimal-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-MINIMAL-LINUX: "-lpthread"
+
+// RUN: %clang -fsanitize=undefined -fsanitize-minimal-runtime %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-apple-darwin -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-MINIMAL-DARWIN %s
+// CHECK-UBSAN-MINIMAL-DARWIN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-MINIMAL-DARWIN: "{{.*}}libclang_rt.ubsan_minimal_osx_dynamic.dylib"
+
+// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-apple-darwin -fuse-ld=ld -static-libsan \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-STATIC-DARWIN %s
+// CHECK-UBSAN-STATIC-DARWIN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-STATIC-DARWIN: "{{.*}}libclang_rt.ubsan_osx.a"
+
// RUN: %clang -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux -fuse-ld=ld \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -400,6 +508,24 @@
// CHECK-CFI-CROSS-DSO-DIAG-LINUX: "-whole-archive" "{{[^"]*}}libclang_rt.cfi_diag-x86_64.a" "-no-whole-archive"
// CHECK-CFI-CROSS-DSO-DIAG-LINUX: -export-dynamic
+// Cross-DSO CFI on Android does not link runtime libraries.
+// RUN: %clang -fsanitize=cfi -fsanitize-cfi-cross-dso %s -### -o %t.o 2>&1 \
+// RUN: -target aarch64-linux-android -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_android_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-CROSS-DSO-ANDROID %s
+// CHECK-CFI-CROSS-DSO-ANDROID: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-CROSS-DSO-ANDROID-NOT: libclang_rt.
+
+// Cross-DSO CFI with diagnostics on Android links just the UBSAN runtime.
+// RUN: %clang -fsanitize=cfi -fsanitize-cfi-cross-dso %s -### -o %t.o 2>&1 \
+// RUN: -fno-sanitize-trap=cfi -fsanitize-recover=cfi \
+// RUN: -target aarch64-linux-android -fuse-ld=ld \
+// RUN: --sysroot=%S/Inputs/basic_android_tree \
+// RUN: | FileCheck --check-prefix=CHECK-CFI-CROSS-DSO-DIAG-ANDROID %s
+// CHECK-CFI-CROSS-DSO-DIAG-ANDROID: "{{.*}}ld{{(.exe)?}}"
+// CHECK-CFI-CROSS-DSO-DIAG-ANDROID: "{{[^"]*}}libclang_rt.ubsan_standalone-aarch64-android.so"
+// CHECK-CFI-CROSS-DSO-DIAG-ANDROID: "-export-dynamic-symbol=__cfi_check"
+
// RUN: %clangxx -fsanitize=address %s -### -o %t.o 2>&1 \
// RUN: -mmacosx-version-min=10.6 \
// RUN: -target x86_64-apple-darwin13.4.0 -fuse-ld=ld -stdlib=platform \
@@ -409,6 +535,15 @@
// CHECK-ASAN-DARWIN106-CXX: libclang_rt.asan_osx_dynamic.dylib
// CHECK-ASAN-DARWIN106-CXX-NOT: -lc++abi
+// RUN: %clangxx -fsanitize=leak %s -### -o %t.o 2>&1 \
+// RUN: -mmacosx-version-min=10.6 \
+// RUN: -target x86_64-apple-darwin13.4.0 -fuse-ld=ld -stdlib=platform \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LSAN-DARWIN106-CXX %s
+// CHECK-LSAN-DARWIN106-CXX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LSAN-DARWIN106-CXX: libclang_rt.lsan_osx_dynamic.dylib
+// CHECK-LSAN-DARWIN106-CXX-NOT: -lc++abi
+
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-unknown-linux -fuse-ld=ld -fsanitize=safe-stack \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
@@ -479,26 +614,6 @@
// CHECK-SAFESTACK-ANDROID-AARCH64: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
// CHECK-SAFESTACK-ANDROID-AARCH64-NOT: libclang_rt.safestack
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=cfi \
-// RUN: --sysroot=%S/Inputs/basic_android_tree \
-// RUN: | FileCheck --check-prefix=CHECK-CFI-ANDROID %s
-//
-// CHECK-CFI-ANDROID: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
-// CHECK-CFI-ANDROID-NOT: libclang_rt.cfi
-// CHECK-CFI-ANDROID-NOT: __cfi_check
-
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// RUN: -target arm-linux-androideabi -fuse-ld=ld -fsanitize=cfi \
-// RUN: -fsanitize-cfi-cross-dso \
-// RUN: --sysroot=%S/Inputs/basic_android_tree \
-// RUN: | FileCheck --check-prefix=CHECK-CROSSDSO-CFI-ANDROID %s
-//
-// CHECK-CROSSDSO-CFI-ANDROID: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
-// CHECK-CROSSDSO-CFI-ANDROID-NOT: libclang_rt.cfi
-// CHECK-CROSSDSO-CFI-ANDROID: -export-dynamic-symbol=__cfi_check
-// CHECK-CROSSDSO-CFI-ANDROID-NOT: libclang_rt.cfi
-
// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
// RUN: -target x86_64-scei-ps4 -fuse-ld=ld \
// RUN: -shared \
diff --git a/test/Driver/split-debug.c b/test/Driver/split-debug.c
index eaa1e990c0..52f53d3e71 100644
--- a/test/Driver/split-debug.c
+++ b/test/Driver/split-debug.c
@@ -36,53 +36,60 @@
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -gmlt -fno-split-dwarf-inlining -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-GMLT-WITH-SPLIT < %t %s
//
-// CHECK-GMLT-WITH-SPLIT: "-split-dwarf=Enable"
+// CHECK-GMLT-WITH-SPLIT: "-enable-split-dwarf"
// CHECK-GMLT-WITH-SPLIT: "-debug-info-kind=line-tables-only"
// CHECK-GMLT-WITH-SPLIT: "-split-dwarf-file"
+// RUN: %clang -target x86_64-unknown-linux-gnu -g -fno-split-dwarf-inlining -S -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-NOINLINE-WITHOUT-SPLIT < %t %s
+//
+// CHECK-NOINLINE-WITHOUT-SPLIT-NOT: "-enable-split-dwarf"
+// CHECK-NOINLINE-WITHOUT-SPLIT: "-fno-split-dwarf-inlining"
+// CHECK-NOINLINE-WITHOUT-SPLIT: "-debug-info-kind=limited"
+
// RUN: %clang -target x86_64-unknown-linux-gnu -gmlt -gsplit-dwarf -fno-split-dwarf-inlining -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-SPLIT-WITH-GMLT < %t %s
//
-// CHECK-SPLIT-WITH-GMLT: "-split-dwarf=Enable"
+// CHECK-SPLIT-WITH-GMLT: "-enable-split-dwarf"
// CHECK-SPLIT-WITH-GMLT: "-debug-info-kind=line-tables-only"
// CHECK-SPLIT-WITH-GMLT: "-split-dwarf-file"
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -fno-split-dwarf-inlining -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-SPLIT-WITH-NOINL < %t %s
//
-// CHECK-SPLIT-WITH-NOINL: "-split-dwarf=Enable"
+// CHECK-SPLIT-WITH-NOINL: "-enable-split-dwarf"
// CHECK-SPLIT-WITH-NOINL: "-debug-info-kind=limited"
// CHECK-SPLIT-WITH-NOINL: "-split-dwarf-file"
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -gmlt -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-GMLT-OVER-SPLIT < %t %s
//
-// CHECK-GMLT-OVER-SPLIT-NOT: "-split-dwarf=Enable"
+// CHECK-GMLT-OVER-SPLIT-NOT: "-enable-split-dwarf"
// CHECK-GMLT-OVER-SPLIT: "-debug-info-kind=line-tables-only"
// CHECK-GMLT-OVER-SPLIT-NOT: "-split-dwarf-file"
// RUN: %clang -target x86_64-unknown-linux-gnu -gmlt -gsplit-dwarf -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-SPLIT-OVER-GMLT < %t %s
//
-// CHECK-SPLIT-OVER-GMLT: "-split-dwarf=Enable" "-debug-info-kind=limited"
+// CHECK-SPLIT-OVER-GMLT: "-enable-split-dwarf" "-debug-info-kind=limited"
// CHECK-SPLIT-OVER-GMLT: "-split-dwarf-file"
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -g0 -fno-split-dwarf-inlining -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-G0-OVER-SPLIT < %t %s
//
-// CHECK-G0-OVER-SPLIT-NOT: "-split-dwarf=Enable"
+// CHECK-G0-OVER-SPLIT-NOT: "-enable-split-dwarf"
// CHECK-G0-OVER-SPLIT-NOT: "-debug-info-kind
// CHECK-G0-OVER-SPLIT-NOT: "-split-dwarf-file"
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -g0 -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-G0-OVER-SPLIT < %t %s
//
-// CHECK-G0-OVER-SPLIT-NOT: "-split-dwarf=Enable"
+// CHECK-G0-OVER-SPLIT-NOT: "-enable-split-dwarf"
// CHECK-G0-OVER-SPLIT-NOT: "-debug-info-kind
// CHECK-G0-OVER-SPLIT-NOT: "-split-dwarf-file"
// RUN: %clang -target x86_64-unknown-linux-gnu -g0 -gsplit-dwarf -S -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-SPLIT-OVER-G0 < %t %s
//
-// CHECK-SPLIT-OVER-G0: "-split-dwarf=Enable" "-debug-info-kind=limited"
+// CHECK-SPLIT-OVER-G0: "-enable-split-dwarf" "-debug-info-kind=limited"
// CHECK-SPLIT-OVER-G0: "-split-dwarf-file"
diff --git a/test/Driver/split-debug.h b/test/Driver/split-debug.h
index bb05f30b67..a27ebb2e6f 100644
--- a/test/Driver/split-debug.h
+++ b/test/Driver/split-debug.h
@@ -3,13 +3,4 @@
// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -fmodules -### %s 2> %t
// RUN: FileCheck -check-prefix=CHECK-NO-ACTIONS < %t %s
//
-// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -fmodules -emit-module -fmodules-embed-all-files -fno-implicit-modules -fno-implicit-module-maps -### %s 2> %t
-// RUN: FileCheck -check-prefix=CHECK-NO-ACTIONS < %t %s
-//
-// FIXME: This should fail using clang, except that the type of the output for
-// an object output with modules is given as clang::driver::types::TY_PCH
-// rather than TY_Object.
-// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -fmodules -fmodule-format=obj -### %s 2> %t
-// RUN: FileCheck -check-prefix=CHECK-NO-ACTIONS < %t %s
-//
// CHECK-NO-ACTIONS-NOT: objcopy
diff --git a/test/Driver/stack-protector.c b/test/Driver/stack-protector.c
index 6769b65f63..a3e40b50ee 100644
--- a/test/Driver/stack-protector.c
+++ b/test/Driver/stack-protector.c
@@ -36,27 +36,20 @@
// Test default stack protector values for Darwin platforms
// RUN: %clang -target armv7k-apple-watchos2.0 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_WATCHOS
+// RUN: %clang -ffreestanding -target armv7k-apple-watchos2.0 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_WATCHOS
// SSP_WATCHOS: "-stack-protector" "1"
// RUN: %clang -target arm64-apple-ios8.0.0 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_IOS
+// RUN: %clang -ffreestanding -target arm64-apple-ios8.0.0 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_IOS
// SSP_IOS: "-stack-protector" "1"
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.6 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_MACOSX
+// RUN: %clang -ffreestanding -target x86_64-apple-darwin10 -mmacosx-version-min=10.6 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_MACOSX
// SSP_MACOSX: "-stack-protector" "1"
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.5 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_MACOSX_10_5
+// RUN: %clang -ffreestanding -target x86_64-apple-darwin10 -mmacosx-version-min=10.5 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_MACOSX_10_5
// SSP_MACOSX_10_5: "-stack-protector" "1"
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.5 -mkernel -### %s 2>&1 | FileCheck %s -check-prefix=SSP_MACOSX_KERNEL
// SSP_MACOSX_KERNEL-NOT: "-stack-protector"
// RUN: %clang -target x86_64-apple-darwin10 -mmacosx-version-min=10.6 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_MACOSX_10_6_KERNEL
+// RUN: %clang -ffreestanding -target x86_64-apple-darwin10 -mmacosx-version-min=10.6 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_MACOSX_10_6_KERNEL
// SSP_MACOSX_10_6_KERNEL: "-stack-protector" "1"
-// Test default stack protector values for Darwin platforms with -ffreestanding
-
-// RUN: %clang -ffreestanding -target armv7k-apple-watchos2.0 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_FREE_WATCHOS
-// SSP_FREE_WATCHOS-NOT: "-stack-protector"
-// RUN: %clang -ffreestanding -target arm64-apple-ios8.0.0 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_FREE_IOS
-// SSP_FREE_IOS-NOT: "-stack-protector"
-// RUN: %clang -ffreestanding -target x86_64-apple-darwin10 -mmacosx-version-min=10.6 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_FREE_MACOSX
-// SSP_FREE_MACOSX-NOT: "-stack-protector"
-// RUN: %clang -ffreestanding -target x86_64-apple-darwin10 -mmacosx-version-min=10.5 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_FREE_MACOSX_10_5
-// SSP_FREE_MACOSX_10_5-NOT: "-stack-protector"
-// RUN: %clang -ffreestanding -target x86_64-apple-darwin10 -mmacosx-version-min=10.6 -### %s 2>&1 | FileCheck %s -check-prefix=SSP_FREE_MACOSX_10_6_KERNEL
-// SSP_FREE_MACOSX_10_6_KERNEL-NOT: "-stack-protector"
diff --git a/test/Driver/std.cpp b/test/Driver/std.cpp
index aceda017a4..52b42ab9bd 100644
--- a/test/Driver/std.cpp
+++ b/test/Driver/std.cpp
@@ -9,6 +9,9 @@
// RUN: not %clang -std=gnu++1y %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX1Y %s
// RUN: not %clang -std=c++1z %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX1Z %s
// RUN: not %clang -std=gnu++1z %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX1Z %s
+// RUN: not %clang -std=c++2a %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CXX2A %s
+// RUN: not %clang -std=gnu++2a %s -fsyntax-only 2>&1 | FileCheck -check-prefix=GNUXX2A %s
+
void f(int n) {
typeof(n)();
@@ -38,3 +41,10 @@ void f(int n) {
// GNUXX1Z-NOT: undeclared identifier 'typeof'
// GNUXX1Z-NOT: undeclared identifier 'decltype'
+
+// CXX2A: undeclared identifier 'typeof'
+// CXX2A-NOT: undeclared identifier 'decltype'
+
+// GNUXX2A-NOT: undeclared identifier 'typeof'
+// GNUXX2A-NOT: undeclared identifier 'decltype'
+
diff --git a/test/Driver/systemz-march.c b/test/Driver/systemz-march.c
index a5df1f482d..2fe7f89d85 100644
--- a/test/Driver/systemz-march.c
+++ b/test/Driver/systemz-march.c
@@ -9,6 +9,8 @@
// RUN: %clang -target s390x -### -S -emit-llvm -march=arch10 %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH10 %s
// RUN: %clang -target s390x -### -S -emit-llvm -march=z13 %s 2>&1 | FileCheck --check-prefix=CHECK-Z13 %s
// RUN: %clang -target s390x -### -S -emit-llvm -march=arch11 %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH11 %s
+// RUN: %clang -target s390x -### -S -emit-llvm -march=z14 %s 2>&1 | FileCheck --check-prefix=CHECK-Z14 %s
+// RUN: %clang -target s390x -### -S -emit-llvm -march=arch12 %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH12 %s
// CHECK-Z9: error: unknown target CPU 'z9'
// CHECK-Z10: "-target-cpu" "z10"
@@ -19,5 +21,7 @@
// CHECK-ARCH10: "-target-cpu" "arch10"
// CHECK-Z13: "-target-cpu" "z13"
// CHECK-ARCH11: "-target-cpu" "arch11"
+// CHECK-Z14: "-target-cpu" "z14"
+// CHECK-ARCH12: "-target-cpu" "arch12"
int x;
diff --git a/test/Driver/target-override.c b/test/Driver/target-override.c
new file mode 100644
index 0000000000..49ca90fd6f
--- /dev/null
+++ b/test/Driver/target-override.c
@@ -0,0 +1,16 @@
+// REQUIRES: shell
+// REQUIRES: x86-registered-target
+
+// RUN: mkdir -p %T/testbin
+// RUN: [ ! -s %T/testbin/i386-clang ] || rm %T/testbin/i386-clang
+// RUN: ln -s %clang %T/testbin/i386-clang
+
+// Check if invocation of "foo-clang" adds option "-target foo".
+//
+// RUN: %T/testbin/i386-clang -c -no-canonical-prefixes %s -### 2>&1 | FileCheck -check-prefix CHECK-TG1 %s
+// CHECK-TG1: Target: i386
+
+// Check if invocation of "foo-clang -target bar" overrides option "-target foo".
+//
+// RUN: %T/testbin/i386-clang -c -no-canonical-prefixes -target x86_64 %s -### 2>&1 | FileCheck -check-prefix CHECK-TG2 %s
+// CHECK-TG2: Target: x86_64
diff --git a/test/Driver/thinlto.c b/test/Driver/thinlto.c
index 0369b78be0..bef7b2b0a6 100644
--- a/test/Driver/thinlto.c
+++ b/test/Driver/thinlto.c
@@ -19,19 +19,19 @@
// RUN: %clang -target x86_64-unknown-linux -### %s -flto=full -fno-lto -flto=thin 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-THIN-ACTION < %t %s
//
-// CHECK-LINK-THIN-ACTION: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-LINK-THIN-ACTION: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// CHECK-LINK-THIN-ACTION: "-plugin-opt=thinlto"
// Check that subsequent -flto=full takes precedence
// RUN: %clang -target x86_64-unknown-linux -### %s -flto=thin -flto=full 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-FULL-ACTION < %t %s
//
-// CHECK-LINK-FULL-ACTION: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-LINK-FULL-ACTION: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// CHECK-LINK-FULL-ACTION-NOT: "-plugin-opt=thinlto"
// Check that subsequent -fno-lto takes precedence
// RUN: %clang -target x86_64-unknown-linux -### %s -flto=thin -fno-lto 2> %t
// RUN: FileCheck -check-prefix=CHECK-LINK-NOLTO-ACTION < %t %s
//
-// CHECK-LINK-NOLTO-ACTION-NOT: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-LINK-NOLTO-ACTION-NOT: "-plugin" "{{.*}}{{[/\\]}}LLVMgold.{{dll|dylib|so}}"
// CHECK-LINK-NOLTO-ACTION-NOT: "-plugin-opt=thinlto"
diff --git a/test/Driver/unavailable_aligned_allocation.cpp b/test/Driver/unavailable_aligned_allocation.cpp
new file mode 100644
index 0000000000..cd75c08165
--- /dev/null
+++ b/test/Driver/unavailable_aligned_allocation.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang -target x86_64-apple-macosx10.12 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=UNAVAILABLE
+//
+// RUN: %clang -target arm64-apple-ios10 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=UNAVAILABLE
+//
+// RUN: %clang -target arm64-apple-tvos10 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=UNAVAILABLE
+//
+// RUN: %clang -target thumbv7-apple-watchos3 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=UNAVAILABLE
+//
+// RUN: %clang -target x86_64-apple-macosx10.13 -mios-simulator-version-min=10 \
+// RUN: -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=UNAVAILABLE
+//
+// RUN: %clang -target x86_64-apple-macosx10.13 -mtvos-simulator-version-min=10 \
+// RUN: -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=UNAVAILABLE
+//
+// RUN: %clang -target x86_64-apple-macosx10.13 -mwatchos-simulator-version-min=3 \
+// RUN: -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=UNAVAILABLE
+//
+// UNAVAILABLE: "-faligned-alloc-unavailable"
+
+// RUN: %clang -target x86_64-apple-macosx10.13 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// RUN: %clang -target arm64-apple-ios11 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// RUN: %clang -target arm64-apple-tvos11 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// RUN: %clang -target armv7k-apple-watchos4 -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// RUN: %clang -target x86_64-unknown-linux-gnu -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// RUN: %clang -target x86_64-apple-macosx10.12 -mios-simulator-version-min=11 \
+// RUN: -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// RUN: %clang -target x86_64-apple-macosx10.12 -mtvos-simulator-version-min=11 \
+// RUN: -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// RUN: %clang -target x86_64-apple-macosx10.12 -mwatchos-simulator-version-min=4 \
+// RUN: -c -### %s 2>&1 \
+// RUN: | FileCheck %s -check-prefix=AVAILABLE
+//
+// AVAILABLE-NOT: "-faligned-alloc-unavailable"
diff --git a/test/Driver/unknown-arg.c b/test/Driver/unknown-arg.c
index 755d29f108..9bba74a942 100644
--- a/test/Driver/unknown-arg.c
+++ b/test/Driver/unknown-arg.c
@@ -1,8 +1,8 @@
-// RUN: %clang %s -cake-is-lie -%0 -%d -HHHH -munknown-to-clang-option -print-stats -funknown-to-clang-option -### 2>&1 | \
+// RUN: not %clang %s -cake-is-lie -%0 -%d -HHHH -munknown-to-clang-option -print-stats -funknown-to-clang-option -### 2>&1 | \
// RUN: FileCheck %s
// RUN: %clang_cl -cake-is-lie -%0 -%d -HHHH -munknown-to-clang-option -print-stats -funknown-to-clang-option -### -c -- %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=CL
-// RUN: %clang_cl -cake-is-lie -%0 -%d -HHHH -munknown-to-clang-option -print-stats -funknown-to-clang-option -c -Werror=unknown-argument -### -- %s 2>&1 | \
+// RUN: not %clang_cl -cake-is-lie -%0 -%d -HHHH -munknown-to-clang-option -print-stats -funknown-to-clang-option -c -Werror=unknown-argument -### -- %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=CL-ERROR
// RUN: %clang_cl -cake-is-lie -%0 -%d -HHHH -munknown-to-clang-option -print-stats -funknown-to-clang-option -c -Wno-unknown-argument -### -- %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=SILENT
diff --git a/test/Driver/unknown-std.c b/test/Driver/unknown-std.c
index ba3035fd45..41736ec488 100644
--- a/test/Driver/unknown-std.c
+++ b/test/Driver/unknown-std.c
@@ -2,32 +2,18 @@
// 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
+// RUN: not %clang %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s
+// RUN: not %clang -x objective-c %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s
+// RUN: not %clang -x renderscript %s -std=foobar -c 2>&1 | 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 'c89', 'c90', or '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 'gnu89' or 'gnu90' for 'ISO C 1990 with GNU extensions' standard
+// CHECK-NEXT: note: use 'c99' or 'iso9899:1999' 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 'c11' or 'iso9899:2011' 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
index b87a8c881c..71c478afca 100644
--- a/test/Driver/unknown-std.cl
+++ b/test/Driver/unknown-std.cl
@@ -6,7 +6,7 @@
// 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.0' 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
diff --git a/test/Driver/unknown-std.cpp b/test/Driver/unknown-std.cpp
index faeb2cba8a..a7aae51122 100644
--- a/test/Driver/unknown-std.cpp
+++ b/test/Driver/unknown-std.cpp
@@ -2,24 +2,22 @@
// 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
+// RUN: not %clang %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s
+// RUN: not %clang -x objective-c++ %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s
+// RUN: not %clang -x cuda -nocudainc -nocudalib %s -std=foobar -c 2>&1 | FileCheck --match-full-lines --check-prefix=CHECK --check-prefix=CUDA %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++98' or 'c++03' for 'ISO C++ 1998 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++98' or 'gnu++03' for 'ISO C++ 1998 with amendments and GNU extensions' 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
+// CHECK-NEXT: note: use 'c++17' for 'ISO C++ 2017 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++17' for 'ISO C++ 2017 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'c++2a' for 'Working draft for ISO C++ 2020' standard
+// CHECK-NEXT: note: use 'gnu++2a' for 'Working draft for ISO C++ 2020 with GNU extensions' standard
+// CUDA-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 0000000000..f6a55bcd39
--- /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/warning-options.cpp b/test/Driver/warning-options.cpp
index 7b9d4ab53a..d836ad143a 100644
--- a/test/Driver/warning-options.cpp
+++ b/test/Driver/warning-options.cpp
@@ -4,5 +4,5 @@
// LARGE_VALUE_COPY_JOINED: -Wlarge-by-value-copy=128
// Check that -isysroot warns on nonexistent paths.
-// RUN: %clang -### -c -target i386-apple-darwin10 -isysroot %T/warning-options %s 2>&1 | FileCheck --check-prefix=CHECK-ISYSROOT %s
+// RUN: %clang -### -c -target i386-apple-darwin10 -isysroot %t/warning-options %s 2>&1 | FileCheck --check-prefix=CHECK-ISYSROOT %s
// CHECK-ISYSROOT: warning: no such sysroot directory: '{{.*}}/warning-options'
diff --git a/test/Driver/wasm-toolchain.c b/test/Driver/wasm-toolchain.c
index d0b0293038..e9862f0b7d 100644
--- a/test/Driver/wasm-toolchain.c
+++ b/test/Driver/wasm-toolchain.c
@@ -27,18 +27,10 @@
// RUN: %clang -### -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK %s
// LINK: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK: lld{{.*}}" "-flavor" "ld" "-L/foo/lib32" "crt1.o" "crti.o" "[[temp]]" "-lc" "-lcompiler_rt" "crtn.o" "-o" "a.out"
+// LINK: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "crt1.o" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
-// A basic C link command-line with optimization. WebAssembly is somewhat
-// special in enabling --gc-sections by default.
+// A basic C link command-line with optimization.
// RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK_OPT %s
// LINK_OPT: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK_OPT: lld{{.*}}" "-flavor" "ld" "--gc-sections" "-L/foo/lib32" "crt1.o" "crti.o" "[[temp]]" "-lc" "-lcompiler_rt" "crtn.o" "-o" "a.out"
-
-// Ditto, but ensure that a user --no-gc-sections comes after the
-// default --gc-sections.
-
-// RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo -Wl,--no-gc-sections %s 2>&1 | FileCheck -check-prefix=NO_GC_SECTIONS %s
-// NO_GC_SECTIONS: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// NO_GC_SECTIONS: lld{{.*}}" "-flavor" "ld" "--gc-sections" "-L/foo/lib32" "crt1.o" "crti.o" "--no-gc-sections" "[[temp]]" "-lc" "-lcompiler_rt" "crtn.o" "-o" "a.out"
+// LINK_OPT: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "crt1.o" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
diff --git a/test/Driver/whole-program-vtables.c b/test/Driver/whole-program-vtables.c
index 4ca985e6d7..de0c606594 100644
--- a/test/Driver/whole-program-vtables.c
+++ b/test/Driver/whole-program-vtables.c
@@ -1,2 +1,11 @@
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s
+// RUN: %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -### -- %s 2>&1 | FileCheck --check-prefix=NO-LTO %s
// NO-LTO: invalid argument '-fwhole-program-vtables' only allowed with '-flto'
+
+// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -flto -### %s 2>&1 | FileCheck --check-prefix=LTO %s
+// RUN: %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -flto -### -- %s 2>&1 | FileCheck --check-prefix=LTO %s
+// LTO: "-fwhole-program-vtables"
+
+// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -fno-whole-program-vtables -flto -### %s 2>&1 | FileCheck --check-prefix=LTO-DISABLE %s
+// RUN: %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -fno-whole-program-vtables -flto -### -- %s 2>&1 | FileCheck --check-prefix=LTO-DISABLE %s
+// LTO-DISABLE-NOT: "-fwhole-program-vtables"
diff --git a/test/Driver/windows-cross.c b/test/Driver/windows-cross.c
index 5a2fe52b09..4b52e99cee 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
+// 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=compiler-rt -o /dev/null %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-BASIC-LIBCXX
-// 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-LIBCXX: armv7-windows-itanium-ld" "--sysroot={{.*}}/Inputs/Windows/ARM/8.1" "-m" "thumb2pe" "-Bdynamic" "--entry" "mainCRTStartup" "--allow-multiple-definition" "-o" "{{[^"]*}}" "{{[^"]*}}.o" "-lmsvcrt"
// 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" "{{[^"]*}}" "{{.*}}.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
@@ -33,11 +33,6 @@
// CHECK-STANDALONE: 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"
-// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %/Inputs/Windows/ARM/8.1/usr/bin -stdlib=libstdc++ -shared -o shared.dll -x c++ %s 2>&1 \
-// RUN: | FileCheck %s --check-prefix CHECK-LIBSTDCXX
-
-// CHECK-LIBSTDCXX: "-internal-isystem" "{{.*}}/usr/include/c++" "-internal-isystem" "{{.*}}/usr/include/c++/armv7--windows-itanium" "-internal-isystem" "{{.*}}/usr/include/c++/backwards"
-
// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=lld-link2 -shared -o shared.dll -x c++ %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-FUSE-LD
@@ -59,7 +54,7 @@
// RUN: | FileCheck %s --check-prefix CHECK-SANITIZE-ADDRESS-EXE-X86
// CHECK-SANITIZE-ADDRESS-EXE-X86: "-fsanitize=address"
-// CHECK-SANITIZE-ADDRESS-EXE-X86: "{{.*}}clang_rt.asan_dynamic-i686.lib" "{{.*}}clang_rt.asan_dynamic_runtime_thunk-i686.lib" "--undefined" "___asan_seh_interceptor"
+// CHECK-SANITIZE-ADDRESS-EXE-X86: "{{.*}}clang_rt.asan_dynamic-i386.lib" "{{.*}}clang_rt.asan_dynamic_runtime_thunk-i386.lib" "--undefined" "___asan_seh_interceptor"
// RUN: %clang -### -target armv7-windows-itanium --sysroot %S/Inputs/Windows/ARM/8.1 -B %S/Inputs/Windows/ARM/8.1/usr/bin -fuse-ld=lld-link2 -shared -o shared.dll -fsanitize=tsan -x c++ %s 2>&1 \
// RUN: | FileCheck %s --check-prefix CHECK-SANITIZE-TSAN
@@ -75,3 +70,8 @@
// CHECK-ISYSTEM-AFTER: "-internal-isystem" "Windows Kits{{[/\\]}}10{{[/\\]}}Include{{[/\\]}}10.0.10586.0{{[/\\]}}um"
// CHECK-ISYSTEM-AFTER: "-internal-isystem" "Windows Kits{{[/\\]}}10{{[/\\]}}Include{{[/\\]}}10.0.10586.0{{[/\\]}}shared"
+// RUN: %clang -### -target armv7-windows-itanium -nostdinc -isystem-after "Windows Kits/10/Include/10.0.10586.0/ucrt" -c %s -o /dev/null 2>&1 \
+// RUN: | FileCheck %s --check-prefix CHECK-NOSTDINC-ISYSTEM-AFTER
+// CHECK-NOSTDINC-ISYSTEM-AFTER: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]"
+// CHECK-NOSTDINC-ISYSTEM-AFTER-NOT: "-internal-isystem" "[[RESOURCE_DIR]]{{(/|\\\\)}}include"
+// CHECK-NOSTDINC-ISYSTEM-AFTER: "-internal-isystem" "Windows Kits{{[/\\]}}10{{[/\\]}}Include{{[/\\]}}10.0.10586.0{{[/\\]}}ucrt"
diff --git a/test/Driver/x86-march.c b/test/Driver/x86-march.c
index b12bf405b0..8236b2f1ef 100644
--- a/test/Driver/x86-march.c
+++ b/test/Driver/x86-march.c
@@ -52,6 +52,10 @@
// RUN: | FileCheck %s -check-prefix=knl
// knl: "-target-cpu" "knl"
//
+// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=knm 2>&1 \
+// RUN: | FileCheck %s -check-prefix=knm
+// knm: "-target-cpu" "knm"
+//
// RUN: %clang -target x86_64-unknown-unknown -c -### %s -march=cannonlake 2>&1 \
// RUN: | FileCheck %s -check-prefix=cannonlake
// cannonlake: "-target-cpu" "cannonlake"
diff --git a/test/FixIt/Inputs/nullability-objc.h b/test/FixIt/Inputs/nullability-objc.h
new file mode 100644
index 0000000000..e3e6baafd6
--- /dev/null
+++ b/test/FixIt/Inputs/nullability-objc.h
@@ -0,0 +1,48 @@
+@class Item;
+@class Container<ObjectType>;
+@protocol Protocol;
+
+// rdar://problem/34260995
+// The first pointer in the file is handled in a different way so need
+// a separate test for this case even if the parameter type is the same as in
+// objcIdParameterWithProtocol.
+void objcIdParameterWithProtocolFirstInFile(id<Protocol> i); // expected-warning {{pointer is missing a nullability type specifier}}
+// expected-note@-1 {{insert '_Nullable'}}
+// expected-note@-2 {{insert '_Nonnull'}}
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:57-[[@LINE-3]]:57}:" _Nullable"
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:57-[[@LINE-4]]:57}:" _Nonnull"
+
+int * _Nonnull forceNullabilityWarningsObjC(void);
+
+void objcClassParameter(Item *i); // expected-warning {{pointer is missing a nullability type specifier}}
+// expected-note@-1 {{insert '_Nullable'}}
+// expected-note@-2 {{insert '_Nonnull'}}
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:31-[[@LINE-3]]:31}:" _Nullable "
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:31-[[@LINE-4]]:31}:" _Nonnull "
+
+void objcClassParameterWithProtocol(Item<Protocol> *i); // expected-warning {{pointer is missing a nullability type specifier}}
+// expected-note@-1 {{insert '_Nullable'}}
+// expected-note@-2 {{insert '_Nonnull'}}
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:53-[[@LINE-3]]:53}:" _Nullable "
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:53-[[@LINE-4]]:53}:" _Nonnull "
+
+// rdar://problem/34260995
+void objcIdParameterWithProtocol(id<Protocol> i); // expected-warning {{pointer is missing a nullability type specifier}}
+// expected-note@-1 {{insert '_Nullable'}}
+// expected-note@-2 {{insert '_Nonnull'}}
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:46-[[@LINE-3]]:46}:" _Nullable"
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:46-[[@LINE-4]]:46}:" _Nonnull"
+
+// Class parameters don't have nullability type specifier.
+void objcParameterizedClassParameter(Container<Item *> *c); // expected-warning {{pointer is missing a nullability type specifier}}
+// expected-note@-1 {{insert '_Nullable'}}
+// expected-note@-2 {{insert '_Nonnull'}}
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:57-[[@LINE-3]]:57}:" _Nullable "
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:57-[[@LINE-4]]:57}:" _Nonnull "
+
+// Class parameters don't have nullability type specifier.
+void objcParameterizedClassParameterWithProtocol(Container<id<Protocol>> *c); // expected-warning {{pointer is missing a nullability type specifier}}
+// expected-note@-1 {{insert '_Nullable'}}
+// expected-note@-2 {{insert '_Nonnull'}}
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-3]]:75-[[@LINE-3]]:75}:" _Nullable "
+// CHECK: fix-it:"{{.*}}nullability-objc.h":{[[@LINE-4]]:75-[[@LINE-4]]:75}:" _Nonnull "
diff --git a/test/FixIt/fixit-add-synthesize-to-property.m b/test/FixIt/fixit-add-synthesize-to-property.m
new file mode 100644
index 0000000000..19b2f4b73f
--- /dev/null
+++ b/test/FixIt/fixit-add-synthesize-to-property.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+@protocol P1
+
+@property int prop;
+
+@end
+
+@interface I <P1>
+
+@end
+
+@implementation I
+@end // CHECK: fix-it:{{.*}}:{[[@LINE]]:1-[[@LINE]]:1}:"@synthesize prop;\n\n"
diff --git a/test/FixIt/fixit-availability.c b/test/FixIt/fixit-availability.c
new file mode 100644
index 0000000000..4b3c8a4392
--- /dev/null
+++ b/test/FixIt/fixit-availability.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunguarded-availability -fdiagnostics-parseable-fixits -triple x86_64-apple-darwin9 %s 2>&1 | FileCheck %s
+
+__attribute__((availability(macos, introduced=10.12)))
+int function(void);
+
+void use() {
+ function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (__builtin_available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:14-[[@LINE-2]]:14}:"\n } else {\n // Fallback on earlier versions\n }"
+}
+
+__attribute__((availability(macos, introduced=10.12)))
+struct New { };
+
+struct NoFixit {
+ struct New field;
+};
+// CHECK-NOT: API_AVAILABLE
diff --git a/test/FixIt/fixit-availability.mm b/test/FixIt/fixit-availability.mm
new file mode 100644
index 0000000000..a566082532
--- /dev/null
+++ b/test/FixIt/fixit-availability.mm
@@ -0,0 +1,150 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunguarded-availability -fdiagnostics-parseable-fixits -triple x86_64-apple-darwin9 %s 2>&1 | FileCheck %s
+
+__attribute__((availability(macos, introduced=10.12)))
+int function(void);
+
+void anotherFunction(int function);
+
+int use() {
+ function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:14-[[@LINE-2]]:14}:"\n } else {\n // Fallback on earlier versions\n }"
+ int y = function(), x = 0;
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:29-[[@LINE-2]]:29}:"\n } else {\n // Fallback on earlier versions\n }"
+ x += function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:19-[[@LINE-2]]:19}:"\n } else {\n // Fallback on earlier versions\n }"
+ if (1) {
+ x = function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:20-[[@LINE-2]]:20}:"\n } else {\n // Fallback on earlier versions\n }"
+ }
+ anotherFunction(function());
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:31-[[@LINE-2]]:31}:"\n } else {\n // Fallback on earlier versions\n }"
+ if (function()) {
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE+1]]:4-[[@LINE+1]]:4}:"\n } else {\n // Fallback on earlier versions\n }"
+ }
+ while (function())
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+ // CHECK-NEXT: fix-it:{{.*}}:{[[@LINE+1]]:6-[[@LINE+1]]:6}:"\n } else {\n // Fallback on earlier versions\n }"
+ ;
+ do
+ function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"\n } else {\n // Fallback on earlier versions\n }"
+ while (1);
+ for (int i = 0; i < 10; ++i)
+ function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"\n } else {\n // Fallback on earlier versions\n }"
+ switch (x) {
+ case 0:
+ function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"\n } else {\n // Fallback on earlier versions\n }"
+ case 2:
+ anotherFunction(1);
+ function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"\n } else {\n // Fallback on earlier versions\n }"
+ break;
+ default:
+ function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"\n } else {\n // Fallback on earlier versions\n }"
+ break;
+ }
+ return function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:21-[[@LINE-2]]:21}:"\n } else {\n // Fallback on earlier versions\n }"
+}
+
+#define MYFUNCTION function
+
+#define MACRO_ARGUMENT(X) X
+#define MACRO_ARGUMENT_SEMI(X) X;
+#define MACRO_ARGUMENT_2(X) if (1) X;
+
+#define INNER_MACRO if (1) MACRO_ARGUMENT(function()); else ;
+
+void useInMacros() {
+ MYFUNCTION();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"\n } else {\n // Fallback on earlier versions\n }"
+
+ MACRO_ARGUMENT_SEMI(function())
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:34-[[@LINE-2]]:34}:"\n } else {\n // Fallback on earlier versions\n }"
+ MACRO_ARGUMENT(function());
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:30-[[@LINE-2]]:30}:"\n } else {\n // Fallback on earlier versions\n }"
+ MACRO_ARGUMENT_2(function());
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:32-[[@LINE-2]]:32}:"\n } else {\n // Fallback on earlier versions\n }"
+
+ INNER_MACRO
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:14-[[@LINE-2]]:14}:"\n } else {\n // Fallback on earlier versions\n }"
+}
+
+void wrapDeclStmtUses() {
+ int x = 0, y = function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE+13]]:22-[[@LINE+13]]:22}:"\n } else {\n // Fallback on earlier versions\n }"
+ {
+ int z = function();
+ if (z) {
+
+ }
+// CHECK: fix-it:{{.*}}:{[[@LINE-4]]:5-[[@LINE-4]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:6-[[@LINE-2]]:6}:"\n } else {\n // Fallback on earlier versions\n }"
+ }
+ if (y)
+ int z = function();
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:24-[[@LINE-2]]:24}:"\n } else {\n // Fallback on earlier versions\n }"
+ anotherFunction(y);
+ anotherFunction(x);
+
+ if (@available(macOS 10.1, *)) {
+ int z = function();
+ (void)z;
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"if (@available(macOS 10.12, *)) {\n "
+// CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:13-[[@LINE-2]]:13}:"\n } else {\n // Fallback on earlier versions\n }"
+ anotherFunction(x);
+ }
+}
+
+#define API_AVAILABLE(X) __attribute__((availability(macos, introduced=10.12))) // dummy macro
+
+API_AVAILABLE(macos(10.12))
+@interface NewClass
+@end
+
+@interface OldButOfferFixit
+@property(copy) NewClass *prop;
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:1-[[@LINE-2]]:1}:"API_AVAILABLE(macos(10.12))\n"
+
+- (NewClass *)fixitMe;
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:22-[[@LINE-1]]:22}:" API_AVAILABLE(macos(10.12))"
+@end
+
+void oldButOfferFixitFn(NewClass *) {
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"API_AVAILABLE(macos(10.12))\n"
+}
+
+template<typename T>
+struct OldButOfferFixitTag {
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:7-[[@LINE-1]]:7}:" API_AVAILABLE(macos(10.12))"
+ NewClass *x;
+};
+
+// Avoid a fixit for declarations that already have an attribute:
+__attribute__((availability(macos, introduced=10.11)))
+@interface WithoutFixit
+@property(copy) NewClass *prop;
+// CHECK-NOT: API_AVAILABLE
+@end
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 5aebcb3def..337b5d62be 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -54,7 +54,6 @@ struct S2 {
void S2::f(int i) {
(void)[&, &i, &i]{}; // expected-error 2{{'&' cannot precede a capture when the capture default is '&'}}
- (void)[=, this]{ this->g(5); }; // expected-error{{'this' cannot be explicitly captured}}
(void)[i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
(void)[&, i, i]{ }; // expected-error{{'i' can appear only once in a capture list}}
(void)[] mutable { }; // expected-error{{lambda requires '()' before 'mutable'}}
diff --git a/test/FixIt/fixit-format-darwin.m b/test/FixIt/fixit-format-darwin.m
new file mode 100644
index 0000000000..54d25d92c2
--- /dev/null
+++ b/test/FixIt/fixit-format-darwin.m
@@ -0,0 +1,86 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -Wformat -fixit %t
+// RUN: grep -v CHECK %t | FileCheck %s
+
+/* This is a test of code modifications created by darwin format fix-its hints
+ that are provided as part of warning */
+
+int printf(const char * restrict, ...);
+
+#if __LP64__
+typedef long CFIndex;
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+#else
+typedef int CFIndex;
+typedef int NSInteger;
+typedef unsigned int NSUInteger;
+#endif
+CFIndex getCFIndex();
+NSInteger getNSInteger();
+NSUInteger getNSUInteger();
+
+#define Log1(...) \
+do { \
+ printf(__VA_ARGS__); \
+} while (0)
+
+#define Log2(...) \
+do { \
+ printf(__VA_ARGS__); \
+ printf(__VA_ARGS__); \
+} while (0) \
+
+#define Log3(X, Y, Z) \
+do { \
+ printf(X, Y); \
+ printf(X, Z); \
+} while (0) \
+
+void test() {
+ printf("test 1: %s", getNSInteger());
+ // CHECK: printf("test 1: %ld", (long)getNSInteger());
+ printf("test 2: %s %s", getNSInteger(), getNSInteger());
+ // CHECK: printf("test 2: %ld %ld", (long)getNSInteger(), (long)getNSInteger());
+
+ Log1("test 3: %s", getNSInteger());
+ // CHECK: Log1("test 3: %ld", (long)getNSInteger());
+ Log1("test 4: %s %s", getNSInteger(), getNSInteger());
+ // CHECK: Log1("test 4: %ld %ld", (long)getNSInteger(), (long)getNSInteger());
+
+ Log2("test 5: %s", getNSInteger());
+ // CHECK: Log2("test 5: %ld", (long)getNSInteger());
+ Log2("test 6: %s %s", getNSInteger(), getNSInteger());
+ // CHECK: Log2("test 6: %ld %ld", (long)getNSInteger(), (long)getNSInteger());
+
+ // Artificial test to check that X (in Log3(X, Y, Z))
+ // is modified only according to the diagnostics
+ // for the first printf and the modification caused
+ // by the second printf is dropped.
+ Log3("test 7: %s", getNSInteger(), getNSUInteger());
+ // CHECK: Log3("test 7: %ld", (long)getNSInteger(), (unsigned long)getNSUInteger());
+}
+
+#define Outer1(...) \
+do { \
+ printf(__VA_ARGS__); \
+} while (0)
+
+#define Outer2(...) \
+do { \
+ Outer1(__VA_ARGS__); Outer1(__VA_ARGS__); \
+} while (0)
+
+void bug33447() {
+ Outer2("test 8: %s", getNSInteger());
+ // CHECK: Outer2("test 8: %ld", (long)getNSInteger());
+ Outer2("test 9: %s %s", getNSInteger(), getNSInteger());
+ // CHECK: Outer2("test 9: %ld %ld", (long)getNSInteger(), (long)getNSInteger());
+}
+
+void testCFIndex() {
+ printf("test 10: %s", getCFIndex());
+ // CHECK: printf("test 10: %ld", (long)getCFIndex());
+ printf("test 11: %s %s", getCFIndex(), getCFIndex());
+ // CHECK: printf("test 11: %ld %ld", (long)getCFIndex(), (long)getCFIndex());
+}
diff --git a/test/FixIt/fixit-format-ios.m b/test/FixIt/fixit-format-ios.m
new file mode 100644
index 0000000000..ef66430778
--- /dev/null
+++ b/test/FixIt/fixit-format-ios.m
@@ -0,0 +1,26 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -fsyntax-only -Wformat -fixit %t
+// RUN: grep -v CHECK %t | FileCheck %s
+
+int printf(const char * restrict, ...);
+typedef unsigned int NSUInteger;
+typedef int NSInteger;
+NSUInteger getNSUInteger();
+NSInteger getNSInteger();
+
+void test() {
+ // For thumbv7-apple-ios8.0.0 the underlying type of ssize_t is long
+ // and the underlying type of size_t is unsigned long.
+
+ printf("test 1: %zu", getNSUInteger());
+ // CHECK: printf("test 1: %lu", (unsigned long)getNSUInteger());
+
+ printf("test 2: %zu %zu", getNSUInteger(), getNSUInteger());
+ // CHECK: printf("test 2: %lu %lu", (unsigned long)getNSUInteger(), (unsigned long)getNSUInteger());
+
+ printf("test 3: %zd", getNSInteger());
+ // CHECK: printf("test 3: %ld", (long)getNSInteger());
+
+ printf("test 4: %zd %zd", getNSInteger(), getNSInteger());
+ // CHECK: printf("test 4: %ld %ld", (long)getNSInteger(), (long)getNSInteger());
+}
diff --git a/test/FixIt/fixit-include.c b/test/FixIt/fixit-include.c
index fd5d7a9ac1..455455687c 100644
--- a/test/FixIt/fixit-include.c
+++ b/test/FixIt/fixit-include.c
@@ -1,12 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -Wall -pedantic -verify %s
-// RUN: cp %s %t
-// RUN: cp %S/fixit-include.h %T
-// RUN: not %clang_cc1 -fsyntax-only -fixit %t
-// RUN: %clang_cc1 -Wall -pedantic %t
+// RUN: mkdir -p %t-dir
+// RUN: cp %s %t-dir/fixit-include.c
+// RUN: cp %S/fixit-include.h %t-dir/fixit-include.h
+// RUN: not %clang_cc1 -fsyntax-only -fixit %t-dir/fixit-include.c
+// RUN: %clang_cc1 -Wall -pedantic %t-dir/fixit-include.c
// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
#include <fixit-include.h> // expected-error {{'fixit-include.h' file not found with <angled> include; use "quotes" instead}}
-// CHECK: fix-it:{{.*}}:{8:10-8:27}
+// CHECK: fix-it:{{.*}}:{9:10-9:27}
#pragma does_not_exist // expected-warning {{unknown pragma ignored}}
diff --git a/test/FixIt/fixit-pragma-attribute.c b/test/FixIt/fixit-pragma-attribute.c
new file mode 100644
index 0000000000..f166eb2978
--- /dev/null
+++ b/test/FixIt/fixit-pragma-attribute.c
@@ -0,0 +1,6 @@
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// Verify that the suggested attribute subject match rules don't include the
+// rules that are not applicable in the current language mode.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to = any(record(unless(is_union)), variable, function)"
diff --git a/test/FixIt/fixit-pragma-attribute.cpp b/test/FixIt/fixit-pragma-attribute.cpp
new file mode 100644
index 0000000000..8e3f6d9392
--- /dev/null
+++ b/test/FixIt/fixit-pragma-attribute.cpp
@@ -0,0 +1,83 @@
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -Wno-pragma-clang-attribute %s 2>&1 | FileCheck %s
+
+#pragma clang attribute push (annotate)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:31-[[@LINE-1]]:31}:"__attribute__(("
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:39-[[@LINE-2]]:39}:"))"
+#pragma clang attribute push (annotate(("test")))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:31-[[@LINE-1]]:31}:"__attribute__(("
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:49-[[@LINE-2]]:49}:"))"
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( enum, function, function, namespace, function ))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:97-[[@LINE-1]]:107}:""
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:118-[[@LINE-2]]:127}:""
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_global), function, variable(is_global), variable(is_global) ))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:112-[[@LINE-1]]:133}:""
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:133-[[@LINE-2]]:153}:""
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global)))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:108-[[@LINE-1]]:132}:""
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:153-[[@LINE-2]]:172}:""
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions2"))), apply_to = any(function(is_member),function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:99-[[@LINE-1]]:119}:""
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions1"))), apply_to = any(variable(is_parameter), variable(unless(is_parameter))))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:130-[[@LINE-1]]:160}:""
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global)))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:106-[[@LINE-1]]:137}:""
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(enum, variable))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:77-[[@LINE-1]]:82}:""
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) apply_to=function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", "
+#pragma clang attribute push (__attribute__((abi_tag("a"))) = function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) any(function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:60}:", apply_to = "
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))) 22)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:63}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:69}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))) (function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:60-[[@LINE-1]]:71}:", apply_to = any(record(unless(is_union)), variable, function, namespace)"
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), )
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:62}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), = function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:61}:"apply_to"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), any(function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:61}:"apply_to = "
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), 22)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:64}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), 1, 2)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:66}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), function)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:70}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), (function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:61-[[@LINE-1]]:72}:"apply_to = any(record(unless(is_union)), variable, function, namespace)"
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to)
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:70-[[@LINE-1]]:70}:" = any(record(unless(is_union)), variable, function, namespace)"
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to any(function))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:70-[[@LINE-1]]:70}:" = "
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to 41 (22))
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:70-[[@LINE-1]]:78}:" = any(record(unless(is_union)), variable, function, namespace)"
+
+// Don't give fix-it to attributes without a strict subject set
+#pragma clang attribute push (__attribute__((annotate("a"))))
+// CHECK-NO: [[@LINE-1]]:61
diff --git a/test/FixIt/fixit-pragma-pack.c b/test/FixIt/fixit-pragma-pack.c
new file mode 100644
index 0000000000..acab4a8bb4
--- /dev/null
+++ b/test/FixIt/fixit-pragma-pack.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+#pragma pack (push, 1)
+#pragma pack()
+// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:14-[[@LINE-1]]:14}:"pop"
diff --git a/test/FixIt/fixit-vexing-parse.cpp b/test/FixIt/fixit-vexing-parse.cpp
index 71d3eff532..973c6961a0 100644
--- a/test/FixIt/fixit-vexing-parse.cpp
+++ b/test/FixIt/fixit-vexing-parse.cpp
@@ -106,3 +106,24 @@ namespace N {
wchar_t wc(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
}
}
+
+namespace RedundantParens {
+struct Y {
+ Y();
+ Y(int);
+ ~Y();
+};
+int n;
+
+void test() {
+ // CHECK: add a variable name
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+7]]:4-[[@LINE+7]]:4}:" varname"
+ // CHECK: add enclosing parentheses
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+5]]:3-[[@LINE+5]]:3}:"("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+4]]:7-[[@LINE+4]]:7}:")"
+ // CHECK: remove parentheses
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+2]]:4-[[@LINE+2]]:5}:" "
+ // CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:6-[[@LINE+1]]:7}:""
+ Y(n); // expected-warning {{declaration of variable named 'n'}} expected-note 3{{}}
+}
+}
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index 6443fe53c2..a46558c7fb 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -1,9 +1,8 @@
// RUN: %clang_cc1 -pedantic -Wunused-label -verify -x c %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -pedantic -Wunused-label -fixit -x c %t
-// RUN: grep -v CHECK %t > %t2
// RUN: %clang_cc1 -pedantic -Wunused-label -Werror -x c %t
-// RUN: FileCheck -input-file=%t2 %t
+// RUN: grep -v CHECK %t | FileCheck %t
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 0b7fc626ff..92c561a20a 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -216,7 +216,7 @@ template<class T> typedef Mystery<T>::type getMysteriousThing() { // \
}
template<template<typename> Foo, // expected-error {{template template parameter requires 'class' after the parameter list}}
- template<typename> typename Bar, // expected-warning {{template template parameter using 'typename' is a C++1z extension}}
+ template<typename> typename Bar, // expected-warning {{template template parameter using 'typename' is a C++17 extension}}
template<typename> struct Baz> // expected-error {{template template parameter requires 'class' after the parameter list}}
void func();
diff --git a/test/FixIt/format-darwin.m b/test/FixIt/format-darwin.m
index 170bb09fb9..fcc81036fc 100644
--- a/test/FixIt/format-darwin.m
+++ b/test/FixIt/format-darwin.m
@@ -7,13 +7,14 @@
int printf(const char * restrict, ...);
#if __LP64__
+typedef long CFIndex;
typedef long NSInteger;
typedef unsigned long NSUInteger;
typedef int SInt32;
typedef unsigned int UInt32;
#else
-
+typedef int CFIndex;
typedef int NSInteger;
typedef unsigned int NSUInteger;
typedef long SInt32;
@@ -27,6 +28,7 @@ typedef enum NSIntegerEnum : NSInteger {
EnumValueB
} NSIntegerEnum;
+CFIndex getCFIndex();
NSInteger getNSInteger();
NSUInteger getNSUInteger();
SInt32 getSInt32();
@@ -55,6 +57,11 @@ void testCorrectionInAllCases() {
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)"
+
+ printf("%s", getCFIndex()); // expected-warning{{values of type 'CFIndex' should not be used as format arguments; add an explicit cast to 'long' instead}}
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)"
}
@interface Foo {
@@ -120,6 +127,11 @@ void testWarn() {
// CHECK-64: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
// CHECK-64: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)"
+
+ printf("%d", getCFIndex()); // expected-warning{{values of type 'CFIndex' should not be used as format arguments; add an explicit cast to 'long' instead}}
+
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)"
}
void testPreserveHex() {
@@ -167,6 +179,10 @@ void testWarn() {
printf("%ld", getNSIntegerEnum()); // expected-warning{{enum values with underlying type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
// CHECK-32: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"(long)"
+
+ printf("%ld", getCFIndex()); // expected-warning{{values of type 'CFIndex' should not be used as format arguments; add an explicit cast to 'long' instead}}
+
+ // CHECK-32: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"(long)"
}
void testPreserveHex() {
@@ -218,6 +234,11 @@ void testCasts() {
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:31}:"(long)"
+
+ printf("%s", (CFIndex)0); // expected-warning{{values of type 'CFIndex' should not be used as format arguments; add an explicit cast to 'long' instead}}
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:25}:"(long)"
}
void testCapitals() {
diff --git a/test/FixIt/format.m b/test/FixIt/format.m
index 7af2cfdaf7..40655a0e80 100644
--- a/test/FixIt/format.m
+++ b/test/FixIt/format.m
@@ -229,6 +229,50 @@ void testSignedness(long i, unsigned long u) {
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:14}:"%+ld"
}
+void testSizeTypes() {
+ printf("%zu", 0.f); // expected-warning-re{{format specifies type 'size_t' (aka '{{.+}}') but the argument has type 'float'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
+
+ printf("%zd", 0.f); // expected-warning-re{{format specifies type 'ssize_t' (aka '{{.+}}') but the argument has type 'float'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
+
+ short x;
+ printf("%zn", &x); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'short *'}}
+ // PrintfSpecifier::fixType doesn't handle %n, so a fix-it is not emitted,
+ // see the comment in PrintfSpecifier::fixType in PrintfFormatString.cpp.
+}
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#define __UNSIGNED_PTRDIFF_TYPE__ \
+ __typeof__(_Generic((__PTRDIFF_TYPE__)0, \
+ long long int : (unsigned long long int)0, \
+ long int : (unsigned long int)0, \
+ int : (unsigned int)0, \
+ short : (unsigned short)0, \
+ signed char : (unsigned char)0))
+
+void testPtrDiffTypes() {
+ __UNSIGNED_PTRDIFF_TYPE__ p1 = 0;
+ printf("%tu", p1); // No warning.
+
+ printf("%tu", 0.f); // expected-warning-re{{format specifies type 'unsigned ptrdiff_t' (aka '{{.+}}') but the argument has type 'float'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
+
+ ptrdiff_t p2 = 0;
+ printf("%td", p2); // No warning.
+
+ printf("%td", 0.f); // expected-warning-re{{format specifies type 'ptrdiff_t' (aka '{{.+}}') but the argument has type 'float'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
+
+ ptrdiff_t p3 = 0;
+ printf("%tn", &p3); // No warning.
+
+ short x;
+ printf("%tn", &x); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'short *'}}
+ // PrintfSpecifier::fixType doesn't handle %n, so a fix-it is not emitted,
+ // see the comment in PrintfSpecifier::fixType in PrintfFormatString.cpp.
+}
+
void testEnum() {
typedef enum {
ImplicitA = 1,
diff --git a/test/FixIt/nullability.mm b/test/FixIt/nullability.mm
index 815c844192..a91ccc0f5f 100644
--- a/test/FixIt/nullability.mm
+++ b/test/FixIt/nullability.mm
@@ -2,8 +2,10 @@
// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -fblocks -std=gnu++11 -I %S/Inputs %s >%t.txt 2>&1
// RUN: FileCheck %s < %t.txt
// RUN: FileCheck %S/Inputs/nullability.h < %t.txt
+// RUN: FileCheck %S/Inputs/nullability-objc.h < %t.txt
#include "nullability.h"
+#include "nullability-objc.h"
#pragma clang assume_nonnull begin
diff --git a/test/Format/incomplete.cpp b/test/Format/incomplete.cpp
index 8a65fad657..f92d576193 100644
--- a/test/Format/incomplete.cpp
+++ b/test/Format/incomplete.cpp
@@ -1,6 +1,6 @@
// RUN: grep -Ev "// *[A-Z-]+:" %s | clang-format -style=LLVM -cursor=0 \
// RUN: | FileCheck -strict-whitespace %s
-// CHECK: {{"IncompleteFormat": true}}
+// CHECK: {{"IncompleteFormat": true, "Line": 2}}
// CHECK: {{^int\ \i;$}}
int i;
// CHECK: {{^f \( g \(;$}}
diff --git a/test/Format/style-on-command-line.cpp b/test/Format/style-on-command-line.cpp
index b2724353da..0e6078e2fd 100644
--- a/test/Format/style-on-command-line.cpp
+++ b/test/Format/style-on-command-line.cpp
@@ -2,20 +2,21 @@
// RUN: clang-format -style="{BasedOnStyle: LLVM, IndentWidth: 7}" %s | FileCheck -strict-whitespace -check-prefix=CHECK2 %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: 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: mkdir -p %t
+// 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: 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
+// 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
diff --git a/test/Format/verbose.cpp b/test/Format/verbose.cpp
new file mode 100644
index 0000000000..dd625e3f67
--- /dev/null
+++ b/test/Format/verbose.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-format %s 2> %t.stderr
+// RUN: not grep "Formatting" %t.stderr
+// RUN: clang-format %s -verbose 2> %t.stderr
+// RUN: grep -E "Formatting (.*)verbose.cpp(.*)" %t.stderr
+// RUN: clang-format %s -verbose=false 2> %t.stderr
+// RUN: not grep "Formatting" %t.stderr
+
+int a;
+// RUN: clang-format %s 2> %t.stderr
+// RUN: not grep "Formatting" %t.stderr
+// RUN: clang-format %s -verbose 2> %t.stderr
+// RUN: grep -E "Formatting (.*)verbose.cpp(.*)" %t.stderr
+// RUN: clang-format %s -verbose=false 2> %t.stderr
+// RUN: not grep "Formatting" %t.stderr
+
+int a;
diff --git a/test/Frontend/Inputs/SystemHeaderPrefix/line-directive-in-system.h b/test/Frontend/Inputs/SystemHeaderPrefix/line-directive-in-system.h
new file mode 100644
index 0000000000..c4c15e58e4
--- /dev/null
+++ b/test/Frontend/Inputs/SystemHeaderPrefix/line-directive-in-system.h
@@ -0,0 +1,2 @@
+#line 1 "foo.h"
+foo();
diff --git a/test/Frontend/Inputs/SystemHeaderPrefix/noline.h b/test/Frontend/Inputs/SystemHeaderPrefix/noline.h
new file mode 100644
index 0000000000..a280f9a5cc
--- /dev/null
+++ b/test/Frontend/Inputs/SystemHeaderPrefix/noline.h
@@ -0,0 +1 @@
+foo();
diff --git a/test/Frontend/Inputs/empty.h b/test/Frontend/Inputs/empty.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Frontend/Inputs/empty.h
diff --git a/test/Frontend/Inputs/line-directive.h b/test/Frontend/Inputs/line-directive.h
new file mode 100644
index 0000000000..e05e9f5167
--- /dev/null
+++ b/test/Frontend/Inputs/line-directive.h
@@ -0,0 +1,2 @@
+#line 10 "foo.h"
+foo(); // will warn if not treated as a system header
diff --git a/test/Frontend/Inputs/optimization-remark-with-hotness-sample.proftext b/test/Frontend/Inputs/optimization-remark-with-hotness-sample.proftext
new file mode 100644
index 0000000000..730dc4a0d5
--- /dev/null
+++ b/test/Frontend/Inputs/optimization-remark-with-hotness-sample.proftext
@@ -0,0 +1,7 @@
+foo:0:0
+ 0: 0
+bar:29:29
+ 9: foo:0
+main:0:0
+ 0: 0 bar:0
+
diff --git a/test/Frontend/clang-abi-compat.cpp b/test/Frontend/clang-abi-compat.cpp
new file mode 100644
index 0000000000..7ee94646b6
--- /dev/null
+++ b/test/Frontend/clang-abi-compat.cpp
@@ -0,0 +1,15 @@
+// RUN: not %clang_cc1 -fclang-abi-compat=banana %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=2.9 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=8 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=3.10 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=4.1 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=04 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=4. %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=4.00 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// INVALID: error: invalid value '{{.*}}' in '-fclang-abi-compat={{.*}}'
+//
+// RUN: %clang_cc1 -fclang-abi-compat=3.0 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=3.9 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=4 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=4.0 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=latest %s -fsyntax-only
diff --git a/test/Frontend/float16.cpp b/test/Frontend/float16.cpp
new file mode 100644
index 0000000000..febd6b8e36
--- /dev/null
+++ b/test/Frontend/float16.cpp
@@ -0,0 +1,326 @@
+// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace
+// RUN: %clang_cc1 -std=c++11 -ast-dump -fnative-half-type %s | FileCheck %s --check-prefix=CHECK-NATIVE --strict-whitespace
+
+/* Various contexts where type _Float16 can appear. */
+
+/* Namespace */
+namespace {
+ _Float16 f1n;
+ _Float16 f2n = 33.f16;
+ _Float16 arr1n[10];
+ _Float16 arr2n[] = { 1.2, 3.0, 3.e4 };
+ const volatile _Float16 func1n(const _Float16 &arg) {
+ return arg + f2n + arr1n[4] - arr2n[1];
+ }
+}
+
+//CHECK: |-NamespaceDecl
+//CHECK-NEXT: | |-VarDecl {{.*}} f1n '_Float16'
+//CHECK-NEXT: | |-VarDecl {{.*}} f2n '_Float16' cinit
+//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 3.300000e+01
+//CHECK-NEXT: | |-VarDecl {{.*}} arr1n '_Float16 [10]'
+//CHECK-NEXT: | |-VarDecl {{.*}} arr2n '_Float16 [3]' cinit
+//CHECK-NEXT: | | `-InitListExpr {{.*}} '_Float16 [3]'
+//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | | | `-FloatingLiteral {{.*}} 'double' 1.200000e+00
+//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | | | `-FloatingLiteral {{.*}} 'double' 3.000000e+00
+//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 3.000000e+04
+//CHECK-NEXT: | `-FunctionDecl {{.*}} func1n 'const volatile _Float16 (const _Float16 &)'
+
+/* File */
+_Float16 f1f;
+_Float16 f2f = 32.4;
+_Float16 arr1f[10];
+_Float16 arr2f[] = { -1.2, -3.0, -3.e4 };
+_Float16 func1f(_Float16 arg);
+
+//CHECK: |-VarDecl {{.*}} f1f '_Float16'
+//CHECK-NEXT: |-VarDecl {{.*}} f2f '_Float16' cinit
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 3.240000e+01
+//CHECK-NEXT: |-VarDecl {{.*}} arr1f '_Float16 [10]'
+//CHECK-NEXT: |-VarDecl {{.*}} arr2f '_Float16 [3]' cinit
+//CHECK-NEXT: | `-InitListExpr {{.*}} '_Float16 [3]'
+//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | | `-UnaryOperator {{.*}} 'double' prefix '-'
+//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 1.200000e+00
+//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | | `-UnaryOperator {{.*}} 'double' prefix '-'
+//CHECK-NEXT: | | `-FloatingLiteral {{.*}} 'double' 3.000000e+00
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | `-UnaryOperator {{.*}} 'double' prefix '-'
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 3.000000e+04
+//CHECK-NEXT: |-FunctionDecl {{.*}} func1f '_Float16 (_Float16)'
+//CHECK-NEXT: | `-ParmVarDecl {{.*}} arg '_Float16'
+
+
+// Mixing __fp16 and Float16 types:
+// The _Float16 type is first converted to __fp16 type and then the operation
+// is completed as if both operands were of __fp16 type.
+
+__fp16 B = -0.1;
+auto C = -1.0f16 + B;
+
+// When we do *not* have native half types, we expect __fp16 to be promoted to
+// float, and consequently also _Float16 promotions to float:
+
+//CHECK: -VarDecl {{.*}} used B '__fp16' cinit
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
+//CHECK-NEXT: | `-UnaryOperator {{.*}} 'double' prefix '-'
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 1.000000e-01
+//CHECK-NEXT: |-VarDecl {{.*}} C 'float':'float' cinit
+//CHECK-NEXT: | `-BinaryOperator {{.*}} 'float' '+'
+//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
+//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__fp16' <LValueToRValue>
+//CHECK-NEXT: | `-DeclRefExpr {{.*}} '__fp16' lvalue Var 0x{{.*}} 'B' '__fp16'
+
+// When do have native half types, we expect to see promotions to fp16:
+
+//CHECK-NATIVE: |-VarDecl {{.*}} used B '__fp16' cinit
+//CHECK-NATIVE: | `-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
+//CHECK-NATIVE: | `-UnaryOperator {{.*}} 'double' prefix '-'
+//CHECK-NATIVE: | `-FloatingLiteral {{.*}} 'double' 1.000000e-01
+//CHECK-NATIVE: |-VarDecl {{.*}} C '__fp16':'__fp16' cinit
+//CHECK-NATIVE: | `-BinaryOperator {{.*}} '__fp16' '+'
+//CHECK-NATIVE: | |-ImplicitCastExpr {{.*}} '__fp16' <FloatingCast>
+//CHECK-NATIVE: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
+//CHECK-NATIVE: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NATIVE: | `-ImplicitCastExpr {{.*}} '__fp16' <LValueToRValue>
+//CHECK-NATIVE: | `-DeclRefExpr {{.*}} '__fp16' lvalue Var 0x{{.*}} 'B' '__fp16'
+
+
+/* Class */
+
+class C1 {
+ _Float16 f1c;
+ static const _Float16 f2c;
+ volatile _Float16 f3c;
+public:
+ C1(_Float16 arg) : f1c(arg), f3c(arg) { }
+ _Float16 func1c(_Float16 arg ) {
+ return f1c + arg;
+ }
+ static _Float16 func2c(_Float16 arg) {
+ return arg * C1::f2c;
+ }
+};
+
+//CHECK: |-CXXRecordDecl {{.*}} referenced class C1 definition
+//CHECK: | |-CXXRecordDecl {{.*}} implicit referenced class C1
+//CHECK-NEXT: | |-FieldDecl {{.*}} referenced f1c '_Float16'
+//CHECK-NEXT: | |-VarDecl {{.*}} used f2c 'const _Float16' static
+//CHECK-NEXT: | |-FieldDecl {{.*}} f3c 'volatile _Float16'
+//CHECK-NEXT: | |-AccessSpecDecl
+//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} used C1 'void (_Float16)
+//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
+//CHECK-NEXT: | | |-CXXCtorInitializer Field {{.*}} 'f1c' '_Float16'
+//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
+//CHECK-NEXT: | | |-CXXCtorInitializer Field {{.*}} 'f3c' 'volatile _Float16'
+//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
+//CHECK-NEXT: | | `-CompoundStmt
+//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used func1c '_Float16 (_Float16)
+//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
+//CHECK-NEXT: | | `-CompoundStmt
+//CHECK-NEXT: | | `-ReturnStmt
+//CHECK-NEXT: | | `-BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | `-MemberExpr {{.*}} '_Float16' lvalue ->f1c 0x{{.*}}
+//CHECK-NEXT: | | | `-CXXThisExpr {{.*}} 'class C1 *' this
+//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
+//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used func2c '_Float16 (_Float16)' static
+//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used arg '_Float16'
+//CHECK-NEXT: | | `-CompoundStmt
+//CHECK-NEXT: | | `-ReturnStmt
+//CHECK-NEXT: | | `-BinaryOperator {{.*}} '_Float16' '*'
+//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '_Float16' lvalue ParmVar 0x{{.*}} 'arg' '_Float16'
+//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'const _Float16' lvalue Var 0x{{.*}} 'f2c' 'const _Float16'
+
+
+/* Template */
+
+template <class C> C func1t(C arg) {
+ return arg * 2.f16;
+}
+
+//CHECK: |-FunctionTemplateDecl {{.*}} func1t
+//CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} C
+//CHECK-NEXT: | |-FunctionDecl {{.*}} func1t 'C (C)'
+//CHECK-NEXT: | | |-ParmVarDecl {{.*}} referenced arg 'C'
+//CHECK-NEXT: | | `-CompoundStmt
+//CHECK-NEXT: | | `-ReturnStmt
+//CHECK-NEXT: | | `-BinaryOperator {{.*}} '<dependent type>' '*'
+//CHECK-NEXT: | | |-DeclRefExpr {{.*}} 'C' lvalue ParmVar {{.*}} 'arg' 'C'
+//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 2.000000e+00
+//CHECK-NEXT: | `-FunctionDecl {{.*}} used func1t '_Float16 (_Float16)'
+//CHECK-NEXT: | |-TemplateArgument type '_Float16'
+//CHECK-NEXT: | |-ParmVarDecl {{.*}} used arg '_Float16':'_Float16'
+//CHECK-NEXT: | `-CompoundStmt
+//CHECK-NEXT: | `-ReturnStmt
+//CHECK-NEXT: | `-BinaryOperator {{.*}} '_Float16' '*'
+//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16':'_Float16' <LValueToRValue>
+//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16':'_Float16' lvalue ParmVar {{.*}} 'arg' '_Float16':'_Float16'
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 2.000000e+00
+
+
+template <class C> struct S1 {
+ C mem1;
+};
+
+//CHECK: |-ClassTemplateDecl {{.*}} S1
+//CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} referenced class depth 0 index 0 C
+//CHECK-NEXT: | |-CXXRecordDecl {{.*}} struct S1 definition
+//CHECK: | | |-CXXRecordDecl {{.*}} implicit struct S1
+//CHECK-NEXT: | | `-FieldDecl {{.*}} mem1 'C'
+//CHECK-NEXT: | `-ClassTemplateSpecialization {{.*}} 'S1'
+
+template <> struct S1<_Float16> {
+ _Float16 mem2;
+};
+
+
+/* Local */
+
+extern int printf (const char *__restrict __format, ...);
+
+int main(void) {
+ _Float16 f1l = 1e3f16;
+//CHECK: | `-VarDecl {{.*}} used f1l '_Float16' cinit
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+03
+
+ _Float16 f2l = -0.f16;
+//CHECK: | `-VarDecl {{.*}} used f2l '_Float16' cinit
+//CHECK-NEXT: | `-UnaryOperator {{.*}} '_Float16' prefix '-'
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 0.000000e+00
+
+ _Float16 f3l = 1.000976562;
+//CHECK: | `-VarDecl {{.*}} used f3l '_Float16' cinit
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} 'double' 1.000977e+00
+
+ C1 c1(f1l);
+//CHECK: | `-VarDecl{{.*}} used c1 'class C1' callinit
+//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'class C1' 'void (_Float16)
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var 0x{{.*}} 'f1l' '_Float16'
+
+ S1<_Float16> s1 = { 132.f16 };
+//CHECK: | `-VarDecl {{.*}} used s1 'S1<_Float16>':'struct S1<_Float16>' cinit
+//CHECK-NEXT: | `-InitListExpr {{.*}} 'S1<_Float16>':'struct S1<_Float16>'
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.320000e+02
+
+ _Float16 f4l = func1n(f1l) + func1f(f2l) + c1.func1c(f3l) + c1.func2c(f1l) +
+ func1t(f1l) + s1.mem2 - f1n + f2n;
+//CHECK: | `-VarDecl {{.*}} used f4l '_Float16' cinit
+//CHECK-NEXT: | `-BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: | |-BinaryOperator {{.*}} '_Float16' '-'
+//CHECK-NEXT: | | |-BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: | | | |-BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: | | | | |-BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: | | | | | |-BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: | | | | | | |-BinaryOperator {{.*}} '_Float16' '+'
+//CHECK-NEXT: | | | | | | | |-CallExpr {{.*}} '_Float16'
+//CHECK-NEXT: | | | | | | | | |-ImplicitCastExpr {{.*}} 'const volatile _Float16 (*)(const _Float16 &)' <FunctionToPointerDecay>
+//CHECK-NEXT: | | | | | | | | | `-DeclRefExpr {{.*}} 'const volatile _Float16 (const _Float16 &)' lvalue Function {{.*}} 'func1n' 'const volatile _Float16 (const _Float16 &)'
+//CHECK-NEXT: | | | | | | | | `-ImplicitCastExpr {{.*}} 'const _Float16' lvalue <NoOp>
+//CHECK-NEXT: | | | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
+//CHECK-NEXT: | | | | | | | `-CallExpr {{.*}} '_Float16'
+//CHECK-NEXT: | | | | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
+//CHECK-NEXT: | | | | | | | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1f' '_Float16 (_Float16)'
+//CHECK-NEXT: | | | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2l' '_Float16'
+//CHECK-NEXT: | | | | | | `-CXXMemberCallExpr {{.*}} '_Float16'
+//CHECK-NEXT: | | | | | | |-MemberExpr {{.*}} '<bound member function type>' .func1c {{.*}}
+//CHECK-NEXT: | | | | | | | `-DeclRefExpr {{.*}} 'class C1' lvalue Var {{.*}} 'c1' 'class C1'
+//CHECK-NEXT: | | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f3l' '_Float16'
+//CHECK-NEXT: | | | | | `-CallExpr {{.*}} '_Float16'
+//CHECK-NEXT: | | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
+//CHECK-NEXT: | | | | | | `-MemberExpr {{.*}} '_Float16 (_Float16)' lvalue .func2c {{.*}}
+//CHECK-NEXT: | | | | | | `-DeclRefExpr {{.*}} 'class C1' lvalue Var {{.*}} 'c1' 'class C1'
+//CHECK-NEXT: | | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
+//CHECK-NEXT: | | | | `-CallExpr {{.*}} '_Float16':'_Float16'
+//CHECK-NEXT: | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
+//CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t')
+//CHECK-NEXT: | | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16'
+//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | | `-MemberExpr {{.*}} '_Float16' lvalue .mem2 {{.*}}
+//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'S1<_Float16>':'struct S1<_Float16>' lvalue Var {{.*}} 's1' 'S1<_Float16>':'struct S1<_Float16>'
+//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1n' '_Float16'
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
+
+ auto f5l = -1.f16, *f6l = &f2l, f7l = func1t(f3l);
+//CHECK: | |-VarDecl {{.*}} f5l '_Float16':'_Float16' cinit
+//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16' prefix '-'
+//CHECK-NEXT: | | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: | |-VarDecl {{.*}} f6l '_Float16 *' cinit
+//CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16 *' prefix '&'
+//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2l' '_Float16'
+//CHECK-NEXT: | `-VarDecl {{.*}} f7l '_Float16':'_Float16' cinit
+//CHECK-NEXT: | `-CallExpr {{.*}} '_Float16':'_Float16'
+//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' <FunctionToPointerDecay>
+//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t')
+//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f3l' '_Float16'
+
+ _Float16 f8l = f4l++;
+//CHECK: | `-VarDecl {{.*}} f8l '_Float16' cinit
+//CHECK-NEXT: | `-UnaryOperator {{.*}} '_Float16' postfix '++'
+//CHECK-NEXT: | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f4l' '_Float16'
+
+ _Float16 arr1l[] = { -1.f16, -0.f16, -11.f16 };
+//CHECK: `-VarDecl {{.*}} arr1l '_Float16 [3]' cinit
+//CHECK-NEXT: `-InitListExpr {{.*}} '_Float16 [3]'
+//CHECK-NEXT: |-UnaryOperator {{.*}} '_Float16' prefix '-'
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 1.000000e+00
+//CHECK-NEXT: |-UnaryOperator {{.*}} '_Float16' prefix '-'
+//CHECK-NEXT: | `-FloatingLiteral {{.*}} '_Float16' 0.000000e+00
+//CHECK-NEXT: `-UnaryOperator {{.*}} '_Float16' prefix '-'
+//CHECK-NEXT: `-FloatingLiteral {{.*}} '_Float16' 1.100000e+01
+
+ float cvtf = f2n;
+//CHECK: `-VarDecl {{.*}} cvtf 'float' cinit
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'float' <FloatingCast>
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
+
+ double cvtd = f2n;
+//CHECK: `-VarDecl {{.*}} cvtd 'double' cinit
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
+
+ long double cvtld = f2n;
+//CHECK: `-VarDecl {{.*}} cvtld 'long double' cinit
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'long double' <FloatingCast>
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <LValueToRValue>
+//CHECK-NEXT: `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2n' '_Float16'
+
+ _Float16 f2h = 42.0f;
+//CHECK: `-VarDecl {{.*}} f2h '_Float16' cinit
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: `-FloatingLiteral {{.*}} 'float' 4.200000e+01
+
+ _Float16 d2h = 42.0;
+//CHECK: `-VarDecl {{.*}} d2h '_Float16' cinit
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: `-FloatingLiteral {{.*}} 'double' 4.200000e+01
+
+ _Float16 ld2h = 42.0l;
+//CHECK: `-VarDecl {{.*}} ld2h '_Float16' cinit
+//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '_Float16' <FloatingCast>
+//CHECK-NEXT: `-FloatingLiteral {{.*}} 'long double' 4.200000e+01
+}
diff --git a/test/Frontend/gnu-inline.c b/test/Frontend/gnu-inline.c
index 0272df7e71..75d4fe6516 100644
--- a/test/Frontend/gnu-inline.c
+++ b/test/Frontend/gnu-inline.c
@@ -3,8 +3,10 @@
// RUN: %clang_cc1 -std=c99 -fgnu89-inline -fsyntax-only -x c -E -dM %s | FileCheck --check-prefix=GNU-INLINE %s
// RUN: %clang_cc1 -fsyntax-only -x c++ -E -dM %s | FileCheck --check-prefix=GNU-INLINE %s
// RUN: not %clang_cc1 -fgnu89-inline -fsyntax-only -x c++ %s 2>&1 | FileCheck --check-prefix=CXX %s
+// RUN: not %clang_cc1 -fgnu89-inline -fsyntax-only -x objective-c++ %s 2>&1 | FileCheck --check-prefix=OBJCXX %s
-// CXX: '-fgnu89-inline' not allowed with 'C++/ObjC++'
+// CXX: '-fgnu89-inline' not allowed with 'C++'
+// OBJCXX: '-fgnu89-inline' not allowed with 'Objective-C++'
// STDC-INLINE-NOT: __GNUC_GNU_INLINE__
// STDC-INLINE: #define __GNUC_STDC_INLINE__ 1
diff --git a/test/Frontend/gnu-mcount.c b/test/Frontend/gnu-mcount.c
index 508be14f35..9872c0d42f 100644
--- a/test/Frontend/gnu-mcount.c
+++ b/test/Frontend/gnu-mcount.c
@@ -1,9 +1,9 @@
// REQUIRES: arm-registered-target,aarch64-registered-target
-// RUN: %clang -target armv7-unknown-none-eabi -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI
-// RUN: %clang -target armv7-unknown-none-eabi -pg -meabi gnu -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-MEABI-GNU
-// RUN: %clang -target aarch64-unknown-none-eabi -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI
-// 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-none-eabi -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-BAREMETAL-EABI
+// RUN: %clang -target armv7-unknown-none-eabi -pg -meabi gnu -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-BAREMETAL-EABI-MEABI-GNU
+// RUN: %clang -target aarch64-unknown-none-eabi -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-BAREMETAL-EABI
+// RUN: %clang -target aarch64-unknown-none-eabi -pg -meabi gnu -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-BAREMETAL-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-LINUX
@@ -28,10 +28,6 @@
// RUN: %clang -target armv7-apple-ios -pg -meabi gnu -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-IOS
// RUN: %clang -target arm64-apple-ios -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-IOS
// RUN: %clang -target arm64-apple-ios -pg -meabi gnu -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-IOS
-// RUN: %clang -target armv7-unknown-bitrig-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-BIGRIG
-// RUN: %clang -target armv7-unknown-bitrig-gnueabihf -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-BIGRIG
-// RUN: %clang -target aarch64-unknown-bitrig-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-BITRIG
-// RUN: %clang -target aarch64-unknown-bitrig-gnueabihf -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-BITRIG
// RUN: %clang -target armv7-unknown-rtems-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-RTEMS
// RUN: %clang -target armv7-unknown-rtems-gnueabihf -meabi gnu -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM-EABI-RTEMS
// RUN: %clang -target aarch64-unknown-rtems-gnueabihf -pg -S -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-ARM64-EABI-RTEMS
@@ -46,6 +42,11 @@ int f() {
}
// CHECK-LABEL: f
+// TODO: add profiling support for arm-baremetal
+// CHECK-ARM-BAREMETAL-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01mcount"{{.*}} }
+// CHECK-ARM-BAREMETAL-EABI-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
+// CHECK-ARM64-BAREMETAL-EABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
+// CHECK-ARM64-BAREMETAL-EABI-MEABI-GNU: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01_mcount"{{.*}} }
// CHECK-ARM-IOS-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="_mcount"{{.*}} }
// CHECK-ARM-IOS-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
// CHECK-ARM-EABI: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01mcount"{{.*}} }
@@ -66,10 +67,6 @@ int f() {
// 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"{{.*}} }
-// CHECK-ARM-EABI-BITRIG: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="__mcount"{{.*}} }
-// CHECK-ARM-EABI-BITRIG-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
-// CHECK-ARM54-EABI-BITRIG: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
-// CHECK-ARM54-EABI-BITRIG-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
// CHECK-ARM-EABI-RTEMS: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
// CHECK-ARM-EABI-RTEMS-NOT: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="\01__gnu_mcount_nc"{{.*}} }
// CHECK-ARM64-EABI-RTEMS: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
diff --git a/test/Frontend/optimization-remark-extra-analysis.c b/test/Frontend/optimization-remark-extra-analysis.c
new file mode 100644
index 0000000000..1a8415e69c
--- /dev/null
+++ b/test/Frontend/optimization-remark-extra-analysis.c
@@ -0,0 +1,11 @@
+// Test that the is*RemarkEnabled overrides are working properly. This remark
+// requiring extra analysis is only conditionally enabled.
+
+// RUN: %clang_cc1 %s -Rpass-missed=gvn -O2 -emit-llvm-only -verify
+
+int foo(int *x, int *y) {
+ int a = *x;
+ *y = 2;
+ // expected-remark@+1 {{load of type i32 not eliminated}}
+ return a + *x;
+}
diff --git a/test/Frontend/optimization-remark-options.c b/test/Frontend/optimization-remark-options.c
index a2d717a242..38dbbfbacc 100644
--- a/test/Frontend/optimization-remark-options.c
+++ b/test/Frontend/optimization-remark-options.c
@@ -14,7 +14,7 @@ double foo(int N) {
// CHECK: {{.*}}:17:3: remark: loop not vectorized: cannot prove it is safe to reorder memory operations; allow reordering by specifying '#pragma clang loop vectorize(enable)' before the loop. If the arrays will always be independent specify '#pragma clang loop vectorize(assume_safety)' before the loop or provide the '__restrict__' qualifier with the independent array arguments. Erroneous results will occur if these options are incorrectly applied!
void foo2(int *dw, int *uw, int *A, int *B, int *C, int *D, int N) {
- for (int i = 0; i < N; i++) {
+ for (long i = 0; i < N; i++) {
dw[i] = A[i] + B[i - 1] + C[i - 2] + D[i - 3];
uw[i] = A[i] + B[i + 1] + C[i + 2] + D[i + 3];
}
diff --git a/test/Frontend/optimization-remark-with-hotness.c b/test/Frontend/optimization-remark-with-hotness.c
index 708f5ec8d4..5e31ce9f2b 100644
--- a/test/Frontend/optimization-remark-with-hotness.c
+++ b/test/Frontend/optimization-remark-with-hotness.c
@@ -1,16 +1,28 @@
+// Generate instrumentation and sampling profile data.
// RUN: llvm-profdata merge \
-// RUN: %S/Inputs/optimization-remark-with-hotness.proftext \
+// RUN: %S/Inputs/optimization-remark-with-hotness.proftext \
// RUN: -o %t.profdata
+// RUN: llvm-profdata merge -sample \
+// RUN: %S/Inputs/optimization-remark-with-hotness-sample.proftext \
+// RUN: -o %t-sample.profdata
+//
// 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 -Rpass-missed=inline \
// RUN: -fdiagnostics-show-hotness -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-sample-use=%t-sample.profdata -Rpass=inline \
+// RUN: -Rpass-analysis=inline -Rpass-missed=inline \
+// RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 \
+// RUN: -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 -Rpass-missed=inline \
-// RUN: -fdiagnostics-show-hotness -Xclang -verify
+// RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 \
+// RUN: -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 \
@@ -18,11 +30,18 @@
// 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 -Rno-pass-with-hotness 2>&1 | FileCheck \
+// RUN: -Rpass-analysis=inline -Rno-pass-with-hotness 2>&1 | FileCheck \
// RUN: -check-prefix=HOTNESS_OFF %s
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
// RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \
-// RUN: -Rpass=inline -Rpass-analysis=inline -fdiagnostics-show-hotness 2>&1 \
+// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \
+// RUN: -Rpass-analysis=inline -fdiagnostics-show-hotness \
+// RUN: -fdiagnostics-hotness-threshold=100 2>&1 \
+// RUN: | FileCheck -allow-empty -check-prefix=THRESHOLD %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
+// RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \
+// RUN: -Rpass=inline -Rpass-analysis=inline \
+// RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 2>&1 \
// RUN: | FileCheck -check-prefix=NO_PGO %s
int foo(int x, int y) __attribute__((always_inline));
@@ -33,9 +52,11 @@ int sum = 0;
void bar(int x) {
// HOTNESS_OFF: foo inlined into bar
// HOTNESS_OFF-NOT: hotness:
+ // THRESHOLD-NOT: inlined
+ // THRESHOLD-NOT: hotness
// NO_PGO: '-fdiagnostics-show-hotness' requires profile-guided optimization information
- // expected-remark@+2 {{foo should always be inlined (cost=always) (hotness: 30)}}
- // expected-remark@+1 {{foo inlined into bar (hotness: 30)}}
+ // NO_PGO: '-fdiagnostics-hotness-threshold=' requires profile-guided optimization information
+ // expected-remark@+1 {{foo inlined into bar with cost=always}}
sum += foo(x, x - 2);
}
diff --git a/test/Frontend/optimization-remark.c b/test/Frontend/optimization-remark.c
index 7c02233d68..29eaa03243 100644
--- a/test/Frontend/optimization-remark.c
+++ b/test/Frontend/optimization-remark.c
@@ -42,9 +42,8 @@ float foz(int x, int y) { return x * y; }
// twice.
//
int bar(int j) {
-// 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@+2 {{foz not inlined into bar because it should never be inlined (cost=never)}}
// expected-remark@+1 {{foo inlined into bar}}
return foo(j, j - 2) * foz(j - 2, j);
}
diff --git a/test/Frontend/pp-only-no-editor-placeholders.c b/test/Frontend/pp-only-no-editor-placeholders.c
new file mode 100644
index 0000000000..515d9893fd
--- /dev/null
+++ b/test/Frontend/pp-only-no-editor-placeholders.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -E -verify -o - %s | FileCheck %s
+// expected-no-diagnostics
+
+<#placeholder#>; // CHECK: <#placeholder#>;
diff --git a/test/Frontend/remove-file-on-signal.c b/test/Frontend/remove-file-on-signal.c
new file mode 100644
index 0000000000..95d9b105f0
--- /dev/null
+++ b/test/Frontend/remove-file-on-signal.c
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t && mkdir -p %t && cd %t
+// RUN: not --crash %clang_cc1 %s -emit-llvm -o foo.ll
+// RUN: ls . | FileCheck %s --allow-empty
+// CHECK-NOT: foo.ll
+
+#pragma clang __debug crash
+FOO
diff --git a/test/Frontend/rewrite-includes-filenotfound.c b/test/Frontend/rewrite-includes-filenotfound.c
new file mode 100644
index 0000000000..203dbde545
--- /dev/null
+++ b/test/Frontend/rewrite-includes-filenotfound.c
@@ -0,0 +1,6 @@
+// RUN: not %clang_cc1 -E -frewrite-includes %s -o - 2>&1 | FileCheck %s
+
+#include "this file does not exist.foo"
+#include "this file also does not exist.foo"
+
+CHECK: fatal error: {{.*}} file not found
diff --git a/test/Frontend/rewrite-includes-line-markers.c b/test/Frontend/rewrite-includes-line-markers.c
index 14692a19e9..f5fb627fec 100644
--- a/test/Frontend/rewrite-includes-line-markers.c
+++ b/test/Frontend/rewrite-includes-line-markers.c
@@ -3,6 +3,8 @@
#include "test.h"
int f() { return x; }
+#include "empty.h"
+
// GNU: {{^}}# 1 "{{.*}}rewrite-includes-line-markers.c"
// GNU: {{^}}#include "test.h"
// GNU: {{^}}# 1 "{{.*}}test.h"
@@ -11,6 +13,9 @@ int f() { return x; }
// GNU: {{^}}int x;
// GNU: {{^}}# 4 "{{.*}}rewrite-includes-line-markers.c" 2
// GNU: {{^}}int f() { return x; }
+// GNU: {{^}}
+// GNU: {{^}}# 1 "{{.*}}empty.h" 1
+// GNU: {{^}}# 7 "{{.*}}rewrite-includes-line-markers.c" 2
// LINE: {{^}}#line 1 "{{.*}}rewrite-includes-line-markers.c"
// LINE: {{^}}#include "test.h"
@@ -20,3 +25,6 @@ int f() { return x; }
// LINE: {{^}}int x;
// LINE: {{^}}#line 4 "{{.*}}rewrite-includes-line-markers.c"
// LINE: {{^}}int f() { return x; }
+// LINE: {{^}}
+// LINE: {{^}}#line 1 "{{.*}}empty.h"
+// LINE: {{^}}#line 7 "{{.*}}rewrite-includes-line-markers.c"
diff --git a/test/Frontend/rewrite-includes-modules.c b/test/Frontend/rewrite-includes-modules.c
index 613609dfce..e70fe0dbaf 100644
--- a/test/Frontend/rewrite-includes-modules.c
+++ b/test/Frontend/rewrite-includes-modules.c
@@ -1,22 +1,27 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c %s -F %S/../Modules/Inputs -E -frewrite-includes -o - | FileCheck %s
+// RUN: mkdir %t
+// RUN: echo 'extern int dummy;' > %t/dummy.h
+// RUN: echo 'module dummy { header "dummy.h" }' > %t/module.modulemap
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %s -I%t -E -frewrite-includes -o - | FileCheck %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c %s -I%t -E -frewrite-includes -o - | FileCheck %s
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ %s -I%t -E -frewrite-includes -o - | FileCheck %s
int bar();
-#include <Module/Module.h>
+#include "dummy.h"
int foo();
-#include <Module/Module.h>
+#include "dummy.h"
// CHECK: int bar();{{$}}
// CHECK-NEXT: #if 0 /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: #include <Module/Module.h>{{$}}
+// CHECK-NEXT: #include "dummy.h"{{$}}
// CHECK-NEXT: #endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: # 5 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
-// CHECK-NEXT: @import Module; /* clang -frewrite-includes: implicit import */{{$}}
-// CHECK-NEXT: # 6 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
+// CHECK-NEXT: # 10 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
+// CHECK-NEXT: #pragma clang module import dummy /* clang -frewrite-includes: implicit import */{{$}}
+// CHECK-NEXT: # 11 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
// CHECK-NEXT: int foo();{{$}}
// CHECK-NEXT: #if 0 /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: #include <Module/Module.h>{{$}}
+// CHECK-NEXT: #include "dummy.h"{{$}}
// CHECK-NEXT: #endif /* expanded by -frewrite-includes */{{$}}
-// CHECK-NEXT: # 7 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
-// CHECK-NEXT: @import Module; /* clang -frewrite-includes: implicit import */{{$}}
-// CHECK-NEXT: # 8 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
+// CHECK-NEXT: # 12 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
+// CHECK-NEXT: #pragma clang module import dummy /* clang -frewrite-includes: implicit import */{{$}}
+// CHECK-NEXT: # 13 "{{.*[/\\]}}rewrite-includes-modules.c"{{$}}
diff --git a/test/Frontend/system-header-line-directive-ms-lineendings.c b/test/Frontend/system-header-line-directive-ms-lineendings.c
new file mode 100644
index 0000000000..57b7a27ea4
--- /dev/null
+++ b/test/Frontend/system-header-line-directive-ms-lineendings.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -E -o - -I %S/Inputs -isystem %S/Inputs/SystemHeaderPrefix | FileCheck %s
+#include <noline.h>
+#include <line-directive-in-system.h>
+
+#include "line-directive.h"
+
+// This tests that the line numbers for the current file are correctly outputted
+// for the include-file-completed test case. This file should be CRLF.
+
+// CHECK: # 1 "{{.*}}system-header-line-directive-ms-lineendings.c" 2
+// CHECK: # 1 "{{.*}}noline.h" 1 3
+// CHECK: foo();
+// CHECK: # 3 "{{.*}}system-header-line-directive-ms-lineendings.c" 2
+// CHECK: # 1 "{{.*}}line-directive-in-system.h" 1 3
+// The "3" below indicates that "foo.h" is considered a system header.
+// CHECK: # 1 "foo.h" 3
+// CHECK: foo();
+// CHECK: # 4 "{{.*}}system-header-line-directive-ms-lineendings.c" 2
+// CHECK: # 1 "{{.*}}line-directive.h" 1
+// CHECK: # 10 "foo.h"{{$}}
+// CHECK: # 6 "{{.*}}system-header-line-directive-ms-lineendings.c" 2
diff --git a/test/Frontend/system-header-line-directive.c b/test/Frontend/system-header-line-directive.c
new file mode 100644
index 0000000000..9d4f09885f
--- /dev/null
+++ b/test/Frontend/system-header-line-directive.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -Wall %s -I %S/Inputs -isystem %S/Inputs/SystemHeaderPrefix -verify
+// RUN: %clang_cc1 %s -E -o - -I %S/Inputs -isystem %S/Inputs/SystemHeaderPrefix | FileCheck %s
+#include <noline.h>
+#include <line-directive-in-system.h>
+
+// expected-warning@line-directive.h:* {{type specifier missing, defaults to 'int'}}
+#include "line-directive.h"
+
+// This tests that "#line" directives in system headers preserve system
+// header-ness just like GNU line markers that don't have filenames. This was
+// PR30752.
+
+// CHECK: # {{[0-9]+}} "{{.*}}system-header-line-directive.c" 2
+// CHECK: # 1 "{{.*}}noline.h" 1 3
+// CHECK: foo();
+// CHECK: # 4 "{{.*}}system-header-line-directive.c" 2
+// CHECK: # 1 "{{.*}}line-directive-in-system.h" 1 3
+// The "3" below indicates that "foo.h" is considered a system header.
+// CHECK: # 1 "foo.h" 3
+// CHECK: foo();
+// CHECK: # {{[0-9]+}} "{{.*}}system-header-line-directive.c" 2
+// CHECK: # 1 "{{.*}}line-directive.h" 1
+// CHECK: # 10 "foo.h"{{$}}
diff --git a/test/Headers/Inputs/usr/include/math.h b/test/Headers/Inputs/usr/include/math.h
new file mode 100644
index 0000000000..4171d4febc
--- /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 0000000000..897962d9e1
--- /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 0ea9e2b52d..733ab5002a 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 7e6ea00987..c71b48da04 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/float16.c b/test/Headers/float16.c
new file mode 100644
index 0000000000..3b905adb33
--- /dev/null
+++ b/test/Headers/float16.c
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c89 -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c99 -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -x c++ -ffreestanding %s
+// expected-no-diagnostics
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+
+#ifndef FLT16_MIN_10_EXP
+ #error "Macro FLT16_MIN_10_EXP is missing."
+#elif FLT16_MIN_10_EXP > -13
+ #error "Macro FLT16_MIN_10_EXP is invalid."
+#endif
+
+_Static_assert(FLT16_MIN_10_EXP == __FLT16_MIN_10_EXP__, "");
+
+#ifndef FLT16_MIN_EXP
+ #error "Macro FLT16_MIN_EXP is missing."
+#elif FLT16_MIN_EXP > -14
+ #error "Macro FLT16_MIN_EXP is invalid."
+#endif
+
+_Static_assert(FLT16_MIN_EXP == __FLT16_MIN_EXP__, "");
+
+#ifndef FLT16_MAX_10_EXP
+ #error "Macro FLT16_MAX_10_EXP is missing."
+#elif FLT16_MAX_10_EXP < 4
+ #error "Macro FLT16_MAX_10_EXP is invalid."
+#endif
+
+_Static_assert(FLT16_MAX_10_EXP == __FLT16_MAX_10_EXP__, "");
+
+#ifndef FLT16_MAX_EXP
+ #error "Macro FLT16_MAX_EXP is missing."
+#elif FLT16_MAX_EXP < 15
+ #error "Macro FLT16_MAX_EXP is invalid."
+#endif
+
+_Static_assert(FLT16_MAX_EXP == __FLT16_MAX_EXP__, "");
+
+#ifndef FLT16_DECIMAL_DIG
+ #error "Macro FLT16_DECIMAL_DIG is missing."
+#elif FLT16_DECIMAL_DIG < 5
+ #error "Macro FLT16_DECIMAL_DIG is invalid."
+#endif
+
+_Static_assert(FLT16_DECIMAL_DIG == __FLT16_DECIMAL_DIG__, "");
+
+#ifndef FLT16_DIG
+ #error "Macro FLT16_DIG is missing."
+#elif FLT16_DIG < 3
+ #error "Macro FLT16_DIG is invalid."
+#endif
+
+_Static_assert(FLT16_DIG == __FLT16_DIG__, "");
+
+#ifndef FLT16_MANT_DIG
+ #error "Macro FLT16_MANT_DIG is missing."
+#elif FLT16_MANT_DIG < 11
+ #error "Macro FLT16_MANT_DIG is invalid."
+#endif
+
+_Static_assert(FLT16_MANT_DIG == __FLT16_MANT_DIG__, "");
+
diff --git a/test/Headers/htm-header.c b/test/Headers/htm-header.c
new file mode 100644
index 0000000000..35a14983be
--- /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/ms-cppoperkey.cpp b/test/Headers/ms-cppoperkey.cpp
new file mode 100644
index 0000000000..ca56ee17bc
--- /dev/null
+++ b/test/Headers/ms-cppoperkey.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 \
+// RUN: -fms-compatibility -x c++-cpp-output \
+// RUN: -ffreestanding -fsyntax-only -Werror \
+// RUN: %s -verify
+// expected-no-diagnostics
+# 1 "t.cpp"
+# 1 "query.h" 1 3
+// MS header <query.h> uses operator keyword as field name.
+// Compile without syntax errors.
+struct tagRESTRICTION
+ {
+ union _URes
+ {
+ int or; // Note use of cpp operator token
+ } res;
+ };
diff --git a/test/Headers/ms-cppoperkey1.cpp b/test/Headers/ms-cppoperkey1.cpp
new file mode 100644
index 0000000000..c03efc9dac
--- /dev/null
+++ b/test/Headers/ms-cppoperkey1.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 \
+// RUN: -fms-compatibility -x c++-cpp-output \
+// RUN: -ffreestanding -fsyntax-only -Werror \
+// RUN: %s -verify
+
+
+# 1 "t.cpp"
+# 1 "query.h" 1 3 4
+// MS header <query.h> uses operator keyword as field name.
+// Compile without syntax errors.
+struct tagRESTRICTION
+ {
+ union _URes
+ {
+ int or; // Note use of cpp operator token
+ } res;
+ };
+ ;
+
+int aa ( int x)
+{
+ // In system header code, treat operator keyword as identifier.
+ if ( // expected-note{{to match this '('}}
+ x>1 or x<0) return 1; // expected-error{{expected ')'}}
+ else return 0;
+}
+
diff --git a/test/Headers/ms-cppoperkey2.cpp b/test/Headers/ms-cppoperkey2.cpp
new file mode 100644
index 0000000000..2afed36b74
--- /dev/null
+++ b/test/Headers/ms-cppoperkey2.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple x86_64-pc-win32 -fms-compatibility \
+// RUN: -ffreestanding -fsyntax-only -Werror %s -verify
+// RUN: %clang_cc1 \
+// RUN: -ffreestanding -fsyntax-only -Werror %s -verify
+// expected-no-diagnostics
+int bb ( int x)
+{
+ // In user code, treat operator keyword as operator keyword.
+ if ( x>1 or x<0) return 1;
+ else return 0;
+}
diff --git a/test/Headers/ms-intrin.cpp b/test/Headers/ms-intrin.cpp
index d410b1d95f..b0fef9cc06 100644
--- a/test/Headers/ms-intrin.cpp
+++ b/test/Headers/ms-intrin.cpp
@@ -64,4 +64,8 @@ void f() {
#ifdef _M_ARM
__dmb(_ARM_BARRIER_ISHST);
#endif
+
+#ifdef _M_ARM64
+ __dmb(_ARM64_BARRIER_SY);
+#endif
}
diff --git a/test/Headers/stdarg.cpp b/test/Headers/stdarg.cpp
new file mode 100644
index 0000000000..502a0ddcb5
--- /dev/null
+++ b/test/Headers/stdarg.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple aarch64-linux -o - | FileCheck %s --check-prefix=AARCH64-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple aarch64-linux -o - | FileCheck %s --check-prefix=AARCH64-CXX
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple x86_64-linux -o - | FileCheck %s --check-prefix=X86_64-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple x86_64-linux -o - | FileCheck %s --check-prefix=X86_64-CXX
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple ppc64-linux -o - | FileCheck %s --check-prefix=PPC64-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple ppc64-linux -o - | FileCheck %s --check-prefix=PPC64-CXX
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple armv7-apple-darwin9 -target-abi aapcs -o - | FileCheck %s --check-prefix=AAPCS-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple armv7-apple-darwin9 -target-abi aapcs -o - | FileCheck %s --check-prefix=AAPCS-CXX
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple s390x-linux -o - | FileCheck %s --check-prefix=SYSTEMZ-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple s390x-linux -o - | FileCheck %s --check-prefix=SYSTEMZ-CXX
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple le32-nacl -o - | FileCheck %s --check-prefix=PNACL-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple le32-nacl -o - | FileCheck %s --check-prefix=PNACL-CXX
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple i686-linux -o - | FileCheck %s --check-prefix=CHARPTR-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple i686-linux -o - | FileCheck %s --check-prefix=CHARPTR-CXX
+// RUN: %clang_cc1 -emit-llvm -std=c99 -x c %s -triple xcore -o - | FileCheck %s --check-prefix=VOIDPTR-C
+// RUN: %clang_cc1 -emit-llvm -std=c++17 -x c++ %s -triple xcore -o - | FileCheck %s --check-prefix=VOIDPTR-CXX
+
+#include <stdarg.h>
+
+// AARCH64-C: define {{.*}} @f(i32 %n, %struct.__va_list* %list)
+// AARCH64-CXX: define {{.*}} @_Z1fiSt9__va_list(i32 %n, %"struct.std::__va_list"* %list)
+// X86_64-C: define {{.*}} @f(i32 %n, %struct.__va_list_tag* %list)
+// X86_64-CXX: define {{.*}} @_Z1fiP13__va_list_tag(i32 %n, %struct.__va_list_tag* %list)
+// PPC64-C: define {{.*}} @f(i32 signext %n, i8* %list)
+// PPC64-CXX: define {{.*}} @_Z1fiPc(i32 signext %n, i8* %list)
+// AAPCS-C: define {{.*}} @f(i32 %n, [1 x i32] %list.coerce)
+// AAPCS-CXX: define {{.*}} @_Z1fiSt9__va_list(i32 %n, [1 x i32] %list.coerce)
+// SYSTEMZ-C: define {{.*}} @f(i32 signext %n, %struct.__va_list_tag* %list)
+// SYSTEMZ-CXX: define {{.*}} @_Z1fiP13__va_list_tag(i32 signext %n, %struct.__va_list_tag* %list)
+// PNACL-C: define {{.*}} @f(i32 %n, i32* %list)
+// PNACL-CXX: define {{.*}} @_Z1fiPi(i32 %n, i32* %list)
+// CHARPTR-C: define {{.*}} @f(i32 %n, i8* %list)
+// CHARPTR-CXX: define {{.*}} @_Z1fiPc(i32 %n, i8* %list)
+// VOIDPTR-C: define {{.*}} @f(i32 %n, i8* %list)
+// VOIDPTR-CXX: define {{.*}} @_Z1fiPv(i32 %n, i8* %list)
+void f(int n, va_list list) {}
diff --git a/test/Headers/stdatomic.c b/test/Headers/stdatomic.c
index 76112cfe40..3643fd4245 100644
--- a/test/Headers/stdatomic.c
+++ b/test/Headers/stdatomic.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c11 -E %s | FileCheck %s
+// RUN: %clang_cc1 -std=c11 -fms-compatibility -E %s | FileCheck %s
#include <stdatomic.h>
int bool_lock_free = ATOMIC_BOOL_LOCK_FREE;
diff --git a/test/Headers/stdint-typeof-MINMAX.cpp b/test/Headers/stdint-typeof-MINMAX.cpp
new file mode 100644
index 0000000000..7014259c59
--- /dev/null
+++ b/test/Headers/stdint-typeof-MINMAX.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=aarch64-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=arm-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=i386-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=mips-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=mips64-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=msp430-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=powerpc64-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=powerpc64-none-netbsd
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=powerpc-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=s390x-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=sparc-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=tce-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=x86_64-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=x86_64-pc-linux-gnu
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=i386-mingw32
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only -triple=xcore-none-none
+// RUN: %clang_cc1 %s -ffreestanding -std=c++1z -fsyntax-only
+
+#include <stdint.h>
+#include <stddef.h>
+
+static_assert(__is_same(__typeof__(INTPTR_MIN), intptr_t));
+static_assert(__is_same(__typeof__(INTPTR_MAX), intptr_t));
+static_assert(__is_same(__typeof__(UINTPTR_MAX), uintptr_t));
+static_assert(__is_same(__typeof__(PTRDIFF_MIN), ptrdiff_t));
+static_assert(__is_same(__typeof__(PTRDIFF_MAX), ptrdiff_t));
+static_assert(__is_same(__typeof__(SIZE_MAX), size_t));
+static_assert(__is_same(__typeof__(INTMAX_MIN), intmax_t));
+static_assert(__is_same(__typeof__(INTMAX_MAX), intmax_t));
+static_assert(__is_same(__typeof__(UINTMAX_MAX), uintmax_t));
+static_assert(__is_same(__typeof__(INTMAX_C(5)), intmax_t));
+static_assert(__is_same(__typeof__(UINTMAX_C(5)), uintmax_t));
diff --git a/test/Headers/tgmath-darwin.c b/test/Headers/tgmath-darwin.c
new file mode 100644
index 0000000000..916605a718
--- /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/Headers/wchar_limits.cpp b/test/Headers/wchar_limits.cpp
index 35ae7affb5..7393e32745 100644
--- a/test/Headers/wchar_limits.cpp
+++ b/test/Headers/wchar_limits.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify %s
-// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -fshort-wchar %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -fwchar-type=short -fno-signed-wchar %s
// expected-no-diagnostics
#include <stdint.h>
diff --git a/test/Import/conflicting-struct/Inputs/S1.cpp b/test/Import/conflicting-struct/Inputs/S1.cpp
new file mode 100644
index 0000000000..a99dba8c78
--- /dev/null
+++ b/test/Import/conflicting-struct/Inputs/S1.cpp
@@ -0,0 +1,6 @@
+class T;
+
+class S {
+ T *t;
+ int a;
+};
diff --git a/test/Import/conflicting-struct/Inputs/S2.cpp b/test/Import/conflicting-struct/Inputs/S2.cpp
new file mode 100644
index 0000000000..de2cb6cd03
--- /dev/null
+++ b/test/Import/conflicting-struct/Inputs/S2.cpp
@@ -0,0 +1,7 @@
+class U {
+ int b;
+};
+
+class T {
+ U u;
+};
diff --git a/test/Import/conflicting-struct/test.cpp b/test/Import/conflicting-struct/test.cpp
new file mode 100644
index 0000000000..5aad567cd7
--- /dev/null
+++ b/test/Import/conflicting-struct/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test --import %S/Inputs/S1.cpp --import %S/Inputs/S2.cpp -expression %s
+void expr() {
+ S MyS;
+ T MyT;
+ MyS.a = 3;
+ MyT.u.b = 2;
+}
diff --git a/test/Import/direct/Inputs/S.c b/test/Import/direct/Inputs/S.c
new file mode 100644
index 0000000000..b0876d27df
--- /dev/null
+++ b/test/Import/direct/Inputs/S.c
@@ -0,0 +1,3 @@
+struct S {
+ int a;
+};
diff --git a/test/Import/direct/test.c b/test/Import/direct/test.c
new file mode 100644
index 0000000000..5fac24c015
--- /dev/null
+++ b/test/Import/direct/test.c
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -direct -import %S/Inputs/S.c -expression %s
+void expr() {
+ struct S MyS;
+ MyS.a = 3;
+}
diff --git a/test/Import/enum/Inputs/S.cpp b/test/Import/enum/Inputs/S.cpp
new file mode 100644
index 0000000000..8506c68512
--- /dev/null
+++ b/test/Import/enum/Inputs/S.cpp
@@ -0,0 +1,4 @@
+enum E {
+ a = 1,
+ b = 2
+};
diff --git a/test/Import/enum/test.cpp b/test/Import/enum/test.cpp
new file mode 100644
index 0000000000..aa68063cb2
--- /dev/null
+++ b/test/Import/enum/test.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-import-test -import %S/Inputs/S.cpp -expression %s
+void expr() {
+ static_assert(E::a + E::b == 3);
+}
diff --git a/test/Import/extern-c-function/Inputs/F.cpp b/test/Import/extern-c-function/Inputs/F.cpp
new file mode 100644
index 0000000000..c417d56302
--- /dev/null
+++ b/test/Import/extern-c-function/Inputs/F.cpp
@@ -0,0 +1,3 @@
+extern "C" {
+ void f(int arg);
+}
diff --git a/test/Import/extern-c-function/test.cpp b/test/Import/extern-c-function/test.cpp
new file mode 100644
index 0000000000..50227cdf9c
--- /dev/null
+++ b/test/Import/extern-c-function/test.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-import-test -import %S/Inputs/F.cpp -expression %s
+void expr() {
+ f(2);
+} \ No newline at end of file
diff --git a/test/Import/forward-declared-objc-class/Inputs/S1.m b/test/Import/forward-declared-objc-class/Inputs/S1.m
new file mode 100644
index 0000000000..b9305d7e89
--- /dev/null
+++ b/test/Import/forward-declared-objc-class/Inputs/S1.m
@@ -0,0 +1 @@
+@class MyClass; \ No newline at end of file
diff --git a/test/Import/forward-declared-objc-class/Inputs/S2.m b/test/Import/forward-declared-objc-class/Inputs/S2.m
new file mode 100644
index 0000000000..69d067a3bd
--- /dev/null
+++ b/test/Import/forward-declared-objc-class/Inputs/S2.m
@@ -0,0 +1,6 @@
+@interface MyClass {
+ int j;
+};
++(MyClass*)fromInteger:(int)_j;
+-(int)getInteger;
+@end \ No newline at end of file
diff --git a/test/Import/forward-declared-objc-class/Inputs/S3.m b/test/Import/forward-declared-objc-class/Inputs/S3.m
new file mode 100644
index 0000000000..b9305d7e89
--- /dev/null
+++ b/test/Import/forward-declared-objc-class/Inputs/S3.m
@@ -0,0 +1 @@
+@class MyClass; \ No newline at end of file
diff --git a/test/Import/forward-declared-objc-class/test.m b/test/Import/forward-declared-objc-class/test.m
new file mode 100644
index 0000000000..098818be3c
--- /dev/null
+++ b/test/Import/forward-declared-objc-class/test.m
@@ -0,0 +1,6 @@
+// RUN: clang-import-test -x objective-c++ -import %S/Inputs/S1.m --import %S/Inputs/S2.m --import %S/Inputs/S3.m -expression %s
+void expr() {
+ MyClass *c = [MyClass fromInteger:3];
+ const int i = [c getInteger];
+ const int j = c->j;
+}
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 0000000000..28377c2760
--- /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 0000000000..b0876d27df
--- /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/Inputs/S3.c b/test/Import/forward-declared-struct/Inputs/S3.c
new file mode 100644
index 0000000000..28377c2760
--- /dev/null
+++ b/test/Import/forward-declared-struct/Inputs/S3.c
@@ -0,0 +1 @@
+struct S;
diff --git a/test/Import/forward-declared-struct/test.c b/test/Import/forward-declared-struct/test.c
new file mode 100644
index 0000000000..8199aa267d
--- /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 --import %S/Inputs/S3.c -expression %s
+void expr() {
+ struct S MyS;
+ MyS.a = 3;
+}
diff --git a/test/Import/import-overrides/Inputs/Hierarchy.cpp b/test/Import/import-overrides/Inputs/Hierarchy.cpp
new file mode 100644
index 0000000000..3f91be765d
--- /dev/null
+++ b/test/Import/import-overrides/Inputs/Hierarchy.cpp
@@ -0,0 +1,9 @@
+class Base {
+public:
+ virtual void foo() {}
+};
+
+class Derived : public Base {
+public:
+ void foo() override {}
+};
diff --git a/test/Import/import-overrides/test.cpp b/test/Import/import-overrides/test.cpp
new file mode 100644
index 0000000000..ded29cded2
--- /dev/null
+++ b/test/Import/import-overrides/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -dump-ast -import %S/Inputs/Hierarchy.cpp -expression %s | FileCheck %s
+
+// CHECK: Overrides:{{.*}}Base::foo
+
+void foo() {
+ Derived d;
+}
diff --git a/test/Import/in-class-initializer/Inputs/S.cpp b/test/Import/in-class-initializer/Inputs/S.cpp
new file mode 100644
index 0000000000..28e6310235
--- /dev/null
+++ b/test/Import/in-class-initializer/Inputs/S.cpp
@@ -0,0 +1,3 @@
+struct S {
+ int a = 3;
+};
diff --git a/test/Import/in-class-initializer/test.cpp b/test/Import/in-class-initializer/test.cpp
new file mode 100644
index 0000000000..eaaac2ae57
--- /dev/null
+++ b/test/Import/in-class-initializer/test.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/S.cpp -expression %s
+void expr() {
+ S MyS;
+ int b = MyS.a + MyS.a;
+}
diff --git a/test/Import/indirect-struct-member-access/Inputs/S.c b/test/Import/indirect-struct-member-access/Inputs/S.c
new file mode 100644
index 0000000000..b0876d27df
--- /dev/null
+++ b/test/Import/indirect-struct-member-access/Inputs/S.c
@@ -0,0 +1,3 @@
+struct S {
+ int a;
+};
diff --git a/test/Import/indirect-struct-member-access/test.c b/test/Import/indirect-struct-member-access/test.c
new file mode 100644
index 0000000000..cbf7e65ec1
--- /dev/null
+++ b/test/Import/indirect-struct-member-access/test.c
@@ -0,0 +1,4 @@
+// RUN: clang-import-test -import %S/Inputs/S.c -expression %s
+void expr(struct S *MyS) {
+ MyS->a = 3;
+}
diff --git a/test/Import/local-struct-use-origins/Inputs/Callee.cpp b/test/Import/local-struct-use-origins/Inputs/Callee.cpp
new file mode 100644
index 0000000000..96cd2f22e4
--- /dev/null
+++ b/test/Import/local-struct-use-origins/Inputs/Callee.cpp
@@ -0,0 +1,12 @@
+struct Bar {
+ void bar(int _a, bool _b) {
+ {
+ struct S { int a; };
+ S s = { _a };
+ }
+ {
+ struct S { bool b; };
+ S t = { _b };
+ }
+ };
+};
diff --git a/test/Import/local-struct-use-origins/test.cpp b/test/Import/local-struct-use-origins/test.cpp
new file mode 100644
index 0000000000..abbdbd16d0
--- /dev/null
+++ b/test/Import/local-struct-use-origins/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -dump-ir -use-origins -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s
+// CHECK: %struct.S = type { i
+// CHECK: %struct.S.0 = type { i
+
+void foo() {
+ return Bar().bar(3, true);
+}
diff --git a/test/Import/local-struct/Inputs/Callee.cpp b/test/Import/local-struct/Inputs/Callee.cpp
new file mode 100644
index 0000000000..96cd2f22e4
--- /dev/null
+++ b/test/Import/local-struct/Inputs/Callee.cpp
@@ -0,0 +1,12 @@
+struct Bar {
+ void bar(int _a, bool _b) {
+ {
+ struct S { int a; };
+ S s = { _a };
+ }
+ {
+ struct S { bool b; };
+ S t = { _b };
+ }
+ };
+};
diff --git a/test/Import/local-struct/test.cpp b/test/Import/local-struct/test.cpp
new file mode 100644
index 0000000000..1e838477a0
--- /dev/null
+++ b/test/Import/local-struct/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s
+// CHECK: %struct.S = type { i
+// CHECK: %struct.S.0 = type { i
+
+void foo() {
+ return Bar().bar(3, true);
+}
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 0000000000..b0876d27df
--- /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 0000000000..bde2b60d27
--- /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 0000000000..28377c2760
--- /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 0000000000..28377c2760
--- /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 0000000000..fdaaaf6114
--- /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/objc-definitions-in-expression/Inputs/S.m b/test/Import/objc-definitions-in-expression/Inputs/S.m
new file mode 100644
index 0000000000..cf8ffaa602
--- /dev/null
+++ b/test/Import/objc-definitions-in-expression/Inputs/S.m
@@ -0,0 +1,4 @@
+@interface C {
+}
+-(int)m;
+@end
diff --git a/test/Import/objc-definitions-in-expression/test.m b/test/Import/objc-definitions-in-expression/test.m
new file mode 100644
index 0000000000..0c9984731d
--- /dev/null
+++ b/test/Import/objc-definitions-in-expression/test.m
@@ -0,0 +1,21 @@
+// RUN: clang-import-test -x objective-c++ -import %S/Inputs/S.m -expression %s
+@class D;
+
+@interface B {
+ int x;
+ int y;
+}
+@end
+
+@interface D : B {
+ int z;
+}
+-(int)n;
+@end
+
+void expr() {
+ C *c;
+ int i = [c m];
+ D *d;
+ int j = [d n] + d->x;
+}
diff --git a/test/Import/objc-method/Inputs/S.m b/test/Import/objc-method/Inputs/S.m
new file mode 100644
index 0000000000..cf8ffaa602
--- /dev/null
+++ b/test/Import/objc-method/Inputs/S.m
@@ -0,0 +1,4 @@
+@interface C {
+}
+-(int)m;
+@end
diff --git a/test/Import/objc-method/test.m b/test/Import/objc-method/test.m
new file mode 100644
index 0000000000..7707110d82
--- /dev/null
+++ b/test/Import/objc-method/test.m
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -x objective-c++ -import %S/Inputs/S.m -expression %s
+void expr() {
+ C *c;
+ int i = [c m];
+}
diff --git a/test/Import/overloaded-function/Inputs/F1.c b/test/Import/overloaded-function/Inputs/F1.c
new file mode 100644
index 0000000000..fb548b464f
--- /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 0000000000..937efe54d8
--- /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 0000000000..4f7781bc8e
--- /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-and-var/Inputs/S1.cpp b/test/Import/struct-and-var/Inputs/S1.cpp
new file mode 100644
index 0000000000..9678b94102
--- /dev/null
+++ b/test/Import/struct-and-var/Inputs/S1.cpp
@@ -0,0 +1 @@
+int F;
diff --git a/test/Import/struct-and-var/Inputs/S2.cpp b/test/Import/struct-and-var/Inputs/S2.cpp
new file mode 100644
index 0000000000..3f0ad8e160
--- /dev/null
+++ b/test/Import/struct-and-var/Inputs/S2.cpp
@@ -0,0 +1,3 @@
+struct F {
+ int a;
+};
diff --git a/test/Import/struct-and-var/test.cpp b/test/Import/struct-and-var/test.cpp
new file mode 100644
index 0000000000..76f539e41f
--- /dev/null
+++ b/test/Import/struct-and-var/test.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-import-test --import %S/Inputs/S1.cpp --import %S/Inputs/S2.cpp -expression %s
+void expr() {
+ struct F f;
+ int x = f.a;
+}
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 0000000000..ddb67a5162
--- /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 0000000000..ad97d5dd52
--- /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 0000000000..e0ec414674
--- /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 0000000000..fd14d82d17
--- /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/struct-layout/Inputs/Callee.cpp b/test/Import/struct-layout/Inputs/Callee.cpp
new file mode 100644
index 0000000000..62422af6c2
--- /dev/null
+++ b/test/Import/struct-layout/Inputs/Callee.cpp
@@ -0,0 +1,9 @@
+struct S {
+ int a;
+};
+
+struct Bar {
+ void bar(int _a) {
+ S s = { _a };
+ };
+};
diff --git a/test/Import/struct-layout/test.cpp b/test/Import/struct-layout/test.cpp
new file mode 100644
index 0000000000..698d0609fa
--- /dev/null
+++ b/test/Import/struct-layout/test.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s
+// CHECK: %struct.S = type { i
+
+void foo() {
+ return Bar().bar(3);
+}
diff --git a/test/Import/template-specialization/Inputs/T.cpp b/test/Import/template-specialization/Inputs/T.cpp
new file mode 100644
index 0000000000..b31e2439ef
--- /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 0000000000..43996c53a7
--- /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/Import/template/Inputs/T.cpp b/test/Import/template/Inputs/T.cpp
new file mode 100644
index 0000000000..2499936788
--- /dev/null
+++ b/test/Import/template/Inputs/T.cpp
@@ -0,0 +1,5 @@
+template <typename T> struct A {
+ struct B {
+ T f;
+ };
+};
diff --git a/test/Import/template/test.cpp b/test/Import/template/test.cpp
new file mode 100644
index 0000000000..89cbda8b92
--- /dev/null
+++ b/test/Import/template/test.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s
+void expr() {
+ A<int>::B b;
+}
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 0000000000..df0e39ed86
--- /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/external-source-symbol-attr.m b/test/Index/Core/external-source-symbol-attr.m
new file mode 100644
index 0000000000..cdc5296697
--- /dev/null
+++ b/test/Index/Core/external-source-symbol-attr.m
@@ -0,0 +1,104 @@
+// RUN: c-index-test core -print-source-symbols -- %s -target x86_64-apple-macosx10.7 | FileCheck %s
+
+#define EXT_DECL(mod_name) __attribute__((external_source_symbol(language="Swift", defined_in=mod_name)))
+#define GEN_DECL(mod_name) __attribute__((external_source_symbol(language="Swift", defined_in=mod_name, generated_declaration)))
+#define PUSH_GEN_DECL(mod_name) push(GEN_DECL(mod_name), apply_to=any(enum, objc_interface, objc_category, objc_protocol))
+
+// Forward declarations should not affect module namespacing below
+@class I1;
+@class I2;
+
+// This should not be indexed.
+GEN_DECL("some_module")
+@interface I1
+// CHECK-NOT: [[@LINE-1]]:12 |
+-(void)method;
+// CHECK-NOT: [[@LINE-1]]:8 |
+@end
+
+EXT_DECL("some_module")
+@interface I2
+// CHECK: [[@LINE-1]]:12 | class/Swift | I2 | c:@M@some_module@objc(cs)I2 | {{.*}} | Decl | rel: 0
+-(void)method;
+// CHECK: [[@LINE-1]]:8 | instance-method/Swift | method | c:@M@some_module@objc(cs)I2(im)method | -[I2 method] | Decl,Dyn,RelChild | rel: 1
+@end
+
+void test1(I1 *o) {
+// CHECK: [[@LINE-1]]:12 | class/Swift | I1 | c:@M@some_module@objc(cs)I1 |
+ [o method];
+ // CHECK: [[@LINE-1]]:6 | instance-method/Swift | method | c:@M@some_module@objc(cs)I1(im)method |
+}
+
+EXT_DECL("some_module")
+@protocol ExtProt
+// CHECK: [[@LINE-1]]:11 | protocol/Swift | ExtProt | c:@M@some_module@objc(pl)ExtProt |
+@end
+
+@interface I1(cat)
+// CHECK: [[@LINE-1]]:15 | extension/ObjC | cat | c:@M@some_module@objc(cy)I1@cat |
+-(void)cat_method;
+// CHECK: [[@LINE-1]]:8 | instance-method/ObjC | cat_method | c:@M@some_module@objc(cs)I1(im)cat_method
+@end
+
+EXT_DECL("cat_module")
+@interface I1(cat2)
+// CHECK: [[@LINE-1]]:15 | extension/Swift | cat2 | c:@CM@cat_module@some_module@objc(cy)I1@cat2 |
+-(void)cat_method2;
+// CHECK: [[@LINE-1]]:8 | instance-method/Swift | cat_method2 | c:@CM@cat_module@some_module@objc(cs)I1(im)cat_method2
+@end
+
+#define NS_ENUM(_name, _type) enum _name:_type _name; enum _name : _type
+
+#pragma clang attribute PUSH_GEN_DECL("modname")
+
+@interface I3
+// CHECK-NOT: [[@LINE-1]]:12 |
+-(void)meth;
+// CHECK-NOT: [[@LINE-1]]:8 |
+@end
+
+@interface I3(cat)
+// CHECK-NOT: [[@LINE-1]]:12 |
+// CHECK-NOT: [[@LINE-2]]:15 |
+-(void)meth2;
+// CHECK-NOT: [[@LINE-1]]:8 |
+@end
+
+@protocol ExtProt2
+// CHECK-NOT: [[@LINE-1]]:11 |
+-(void)meth;
+// CHECK-NOT: [[@LINE-1]]:8 |
+@end
+
+typedef NS_ENUM(SomeEnum, int) {
+// CHECK-NOT: [[@LINE-1]]:17 |
+ SomeEnumFirst = 0,
+ // CHECK-NOT: [[@LINE-1]]:3 |
+};
+
+#pragma clang attribute pop
+
+void test2(I3 *i3, id<ExtProt2> prot2, SomeEnum some) {
+ // CHECK: [[@LINE-1]]:12 | class/Swift | I3 | c:@M@modname@objc(cs)I3 |
+ // CHECK: [[@LINE-2]]:23 | protocol/Swift | ExtProt2 | c:@M@modname@objc(pl)ExtProt2 |
+ // CHECK: [[@LINE-3]]:40 | enum/Swift | SomeEnum | c:@M@modname@E@SomeEnum |
+ [i3 meth];
+ // CHECK: [[@LINE-1]]:7 | instance-method/Swift | meth | c:@M@modname@objc(cs)I3(im)meth |
+ [i3 meth2];
+ // CHECK: [[@LINE-1]]:7 | instance-method/Swift | meth2 | c:@CM@modname@objc(cs)I3(im)meth2 |
+ [prot2 meth];
+ // CHECK: [[@LINE-1]]:10 | instance-method/Swift | meth | c:@M@modname@objc(pl)ExtProt2(im)meth |
+ some = SomeEnumFirst;
+ // CHECK: [[@LINE-1]]:10 | enumerator/Swift | SomeEnumFirst | c:@M@modname@E@SomeEnum@SomeEnumFirst |
+}
+
+#pragma clang attribute PUSH_GEN_DECL("other_mod_for_cat")
+@interface I3(cat_other_mod)
+-(void)meth_other_mod;
+@end
+#pragma clang attribute pop
+
+void test3(I3 *i3) {
+ [i3 meth_other_mod];
+ // CHECK: [[@LINE-1]]:7 | instance-method/Swift | meth_other_mod | c:@CM@other_mod_for_cat@modname@objc(cs)I3(im)meth_other_mod |
+}
diff --git a/test/Index/Core/index-dependent-source.cpp b/test/Index/Core/index-dependent-source.cpp
new file mode 100644
index 0000000000..2e111339af
--- /dev/null
+++ b/test/Index/Core/index-dependent-source.cpp
@@ -0,0 +1,226 @@
+// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
+
+int invalid;
+
+class Base {
+ void baseFunction();
+
+ int baseField;
+
+ static void staticBaseFunction();
+};
+
+template<typename T>
+class BaseTemplate {
+public:
+ T baseTemplateFunction();
+
+ T baseTemplateField;
+
+ static T baseTemplateVariable;
+};
+
+template<typename T, typename S>
+class TemplateClass: public Base , public BaseTemplate<T> {
+public:
+ ~TemplateClass();
+
+ T function() { }
+
+ static void staticFunction() { }
+
+ T field;
+
+ static T variable;
+
+ struct Struct { };
+
+ enum Enum { EnumValue };
+
+ using TypeAlias = S;
+ typedef T Typedef;
+
+ void overload1(const T &);
+ void overload1(const S &);
+};
+
+template<typename T, typename S>
+void indexSimpleDependentDeclarations(const TemplateClass<T, S> &object) {
+ // Valid instance members:
+ object.function();
+// CHECK: [[@LINE-1]]:10 | instance-method/C++ | function | c:@ST>2#T#T@TemplateClass@F@function# | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+ object.field;
+// CHECK: [[@LINE-1]]:10 | field/C++ | field | c:@ST>2#T#T@TemplateClass@FI@field | <no-cgname> | Ref,RelCont | rel: 1
+ object.baseFunction();
+// CHECK: [[@LINE-1]]:10 | instance-method/C++ | baseFunction | c:@S@Base@F@baseFunction# | __ZN4Base12baseFunctionEv | Ref,Call,RelCall,RelCont | rel: 1
+ object.baseField;
+// CHECK: [[@LINE-1]]:10 | field/C++ | baseField | c:@S@Base@FI@baseField | <no-cgname> | Ref,RelCont | rel: 1
+ object.baseTemplateFunction();
+// CHECK: [[@LINE-1]]:10 | instance-method/C++ | baseTemplateFunction | c:@ST>1#T@BaseTemplate@F@baseTemplateFunction# | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+ object.baseTemplateField;
+// CHECK: [[@LINE-1]]:10 | field/C++ | baseTemplateField | c:@ST>1#T@BaseTemplate@FI@baseTemplateField | <no-cgname> | Ref,RelCont | rel: 1
+
+ // Invalid instance members:
+ object.variable;
+// CHECK-NOT: [[@LINE-1]]:10
+ object.staticFunction();
+// CHECK-NOT: [[@LINE-1]]:10
+ object.Struct;
+// CHECK-NOT: [[@LINE-1]]:10
+ object.EnumValue;
+// CHECK-NOT: [[@LINE-1]]:10
+
+ // Valid static members:
+ TemplateClass<T, S>::staticFunction();
+// CHECK: [[@LINE-1]]:24 | static-method/C++ | staticFunction | c:@ST>2#T#T@TemplateClass@F@staticFunction#S | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+ TemplateClass<T, S>::variable;
+// CHECK: [[@LINE-1]]:24 | static-property/C++ | variable | c:@ST>2#T#T@TemplateClass@variable | __ZN13TemplateClass8variableE | Ref,RelCont | rel: 1
+ TemplateClass<T, S>::staticBaseFunction();
+// CHECK: [[@LINE-1]]:24 | static-method/C++ | staticBaseFunction | c:@S@Base@F@staticBaseFunction#S | __ZN4Base18staticBaseFunctionEv | Ref,Call,RelCall,RelCont | rel: 1
+ TemplateClass<T, S>::baseTemplateVariable;
+// CHECK: [[@LINE-1]]:24 | static-property/C++ | baseTemplateVariable | c:@ST>1#T@BaseTemplate@baseTemplateVariable | __ZN12BaseTemplate20baseTemplateVariableE | Ref,RelCont | rel: 1
+ TemplateClass<T, S>::EnumValue;
+// CHECK: [[@LINE-1]]:24 | enumerator/C | EnumValue | c:@ST>2#T#T@TemplateClass@E@Enum@EnumValue | <no-cgname> | Ref,RelCont | rel: 1
+ TemplateClass<T, S>::Struct();
+// CHECK: [[@LINE-1]]:24 | struct/C | Struct | c:@ST>2#T#T@TemplateClass@S@Struct | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+
+ // Invalid static members:
+ TemplateClass<T, S>::field;
+// CHECK-NOT: [[@LINE-1]]:24
+ TemplateClass<T, S>::function();
+// CHECK-NOT: [[@LINE-1]]:24
+
+ // Valid type names:
+ typename TemplateClass<T, S>::Struct Val;
+// CHECK: [[@LINE-1]]:33 | struct/C | Struct | c:@ST>2#T#T@TemplateClass@S@Struct | <no-cgname> | Ref,RelCont | rel: 1
+ typename TemplateClass<T, S>::Enum EnumVal;
+// CHECK: [[@LINE-1]]:33 | enum/C | Enum | c:@ST>2#T#T@TemplateClass@E@Enum | <no-cgname> | Ref,RelCont | rel: 1
+ typename TemplateClass<T, S>::TypeAlias Val2;
+// CHECK: [[@LINE-1]]:33 | type-alias/C++ | TypeAlias | c:@ST>2#T#T@TemplateClass@TypeAlias | <no-cgname> | Ref,RelCont | rel: 1
+ typename TemplateClass<T, S>::Typedef Val3;
+// CHECK: [[@LINE-1]]:33 | type-alias/C | Typedef | c:{{.*}}index-dependent-source.cpp@ST>2#T#T@TemplateClass@T@Typedef | <no-cgname> | Ref,RelCont | rel: 1
+
+ // Invalid type names:
+ typename TemplateClass<T, S>::field Val4;
+// CHECK-NOT: [[@LINE-1]]:33
+ typename TemplateClass<T, S>::staticFunction Val5;
+// CHECK-NOT: [[@LINE-1]]:33
+
+
+ object.invalid;
+// CHECK-NOT: [[@LINE-1]]:10
+ TemplateClass<T, S>::invalid;
+// CHECK-NOT: [[@LINE-1]]:24
+}
+
+template<typename T, typename S, typename Y>
+void indexDependentOverloads(const TemplateClass<T, S> &object) {
+ object.overload1(T());
+// CHECK-NOT: [[@LINE-1]]
+ object.overload1(S());
+// CHECK-NOT: [[@LINE-1]]
+ object.overload1(Y());
+// CHECK-NOT: [[@LINE-1]]
+}
+
+template<typename T> struct UndefinedTemplateClass;
+
+template<typename T>
+void undefinedTemplateLookup(UndefinedTemplateClass<T> &x) {
+// Shouldn't crash!
+ x.lookup;
+ typename UndefinedTemplateClass<T>::Type y;
+}
+
+template<typename T>
+struct UserOfUndefinedTemplateClass: UndefinedTemplateClass<T> { };
+
+template<typename T>
+void undefinedTemplateLookup2(UserOfUndefinedTemplateClass<T> &x) {
+// Shouldn't crash!
+ x.lookup;
+ typename UserOfUndefinedTemplateClass<T>::Type y;
+}
+
+template<typename T> struct Dropper;
+
+template<typename T> struct Trait;
+
+template<typename T>
+struct Recurse : Trait<typename Dropper<T>::Type> { };
+
+template<typename T>
+struct Trait : Recurse<T> {
+};
+
+template<typename T>
+void infiniteTraitRecursion(Trait<T> &t) {
+// Shouldn't crash!
+ t.lookup;
+}
+
+template <typename T>
+struct UsingA {
+// CHECK: [[@LINE+1]]:15 | type-alias/C | Type | c:index-dependent-source.cpp@ST>1#T@UsingA@T@Type | <no-cgname> | Def,RelChild | rel: 1
+ typedef int Type;
+// CHECK: [[@LINE+1]]:15 | static-method/C++ | func | c:@ST>1#T@UsingA@F@func#S | <no-cgname> | Decl,RelChild | rel: 1
+ static void func();
+// CHECK: [[@LINE+1]]:8 | instance-method/C++ | operator() | c:@ST>1#T@UsingA@F@operator()#I# | <no-cgname> | Decl,RelChild | rel: 1
+ void operator()(int);
+// CHECK: [[@LINE+1]]:8 | instance-method/C++ | operator+ | c:@ST>1#T@UsingA@F@operator+#&1>@ST>1#T@UsingA1t0.0# | <no-cgname> | Decl,RelChild | rel: 1
+ void operator+(const UsingA &);
+};
+
+template <typename T>
+struct OtherUsing {};
+
+template <typename T>
+struct UsingB : public UsingA<T> {
+// CHECK: [[@LINE+2]]:40 | type-alias/C | TypeB | c:index-dependent-source.cpp@ST>1#T@UsingB@T@TypeB | <no-cgname> | Def,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:20 | struct(Gen)/C++ | OtherUsing | c:@ST>1#T@OtherUsing | <no-cgname> | Ref,RelCont | rel: 1
+ typedef typename OtherUsing<T>::Type TypeB;
+// CHECK: [[@LINE+2]]:29 | using/using-typename(Gen)/C++ | Type | c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:18 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
+ using typename UsingA<T>::Type;
+// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | func | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::func | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
+ using UsingA<T>::func;
+
+// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | operator() | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::operator() | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
+ using UsingA<T>::operator();
+// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | operator+ | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::operator+ | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
+ using UsingA<T>::operator+;
+};
+
+template <typename T>
+struct UsingC : public UsingB<T> {
+ static void test() {
+// CHECK: [[@LINE+2]]:25 | type-alias/C | TypeB | c:index-dependent-source.cpp@ST>1#T@UsingB@T@TypeB | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE+1]]:14 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | <no-cgname> | Ref,RelCont | rel: 1
+ typename UsingB<T>::TypeB value1;
+// CHECK: [[@LINE+2]]:25 | using/using-typename(Gen)/C++ | Type | c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE+1]]:14 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | <no-cgname> | Ref,RelCont | rel: 1
+ typename UsingB<T>::Type value2;
+// CHECK: [[@LINE+2]]:16 | using/using-value(Gen)/C++ | func | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::func | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+// CHECK: [[@LINE+1]]:5 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | <no-cgname> | Ref,RelCont | rel: 1
+ UsingB<T>::func();
+ }
+};
+
+template <typename T>
+struct UsingD {
+// CHECK: [[@LINE+1]]:8 | instance-method/C++ | foo | c:@ST>1#T@UsingD@F@foo#t0.0# | <no-cgname> | Decl,RelChild | rel: 1
+ void foo(T);
+};
+
+template <typename T, typename U>
+struct UsingE : public UsingD<T>, public UsingD<U> {
+// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | foo | c:index-dependent-source.cpp@ST>2#T#T@UsingE@UUV@UsingD<T>::foo | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingD | c:@ST>1#T@UsingD | <no-cgname> | Ref,RelCont | rel: 1
+ using UsingD<T>::foo;
+// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | foo | c:index-dependent-source.cpp@ST>2#T#T@UsingE@UUV@UsingD<U>::foo | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingD | c:@ST>1#T@UsingD | <no-cgname> | Ref,RelCont | rel: 1
+ using UsingD<U>::foo;
+};
diff --git a/test/Index/Core/index-instantiated-source.cpp b/test/Index/Core/index-instantiated-source.cpp
new file mode 100644
index 0000000000..7a810fbdf3
--- /dev/null
+++ b/test/Index/Core/index-instantiated-source.cpp
@@ -0,0 +1,88 @@
+// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
+// References to declarations in instantiations should be canonicalized:
+
+template<typename T>
+class BaseTemplate {
+public:
+ T baseTemplateFunction();
+// CHECK: [[@LINE-1]]:5 | instance-method/C++ | baseTemplateFunction | c:@ST>1#T@BaseTemplate@F@baseTemplateFunction#
+
+ T baseTemplateField;
+// CHECK: [[@LINE-1]]:5 | field/C++ | baseTemplateField | c:@ST>1#T@BaseTemplate@FI@baseTemplateField
+
+ struct NestedBaseType { };
+// CHECK: [[@LINE-1]]:10 | struct/C | NestedBaseType | c:@ST>1#T@BaseTemplate@S@NestedBaseType |
+};
+
+template<typename T, typename S>
+class TemplateClass: public BaseTemplate<T> {
+public:
+ T function() { return T(); }
+// CHECK: [[@LINE-1]]:5 | instance-method/C++ | function | c:@ST>2#T#T@TemplateClass@F@function#
+
+ static void staticFunction() { }
+// CHECK: [[@LINE-1]]:15 | static-method/C++ | staticFunction | c:@ST>2#T#T@TemplateClass@F@staticFunction#S
+
+ T field;
+// CHECK: [[@LINE-1]]:5 | field/C++ | field | c:@ST>2#T#T@TemplateClass@FI@field
+
+ struct NestedType {
+// CHECK: [[@LINE-1]]:10 | struct/C++ | NestedType | c:@ST>2#T#T@TemplateClass@S@NestedType |
+
+ T nestedField;
+// CHECK: [[@LINE-1]]:7 | field/C++ | nestedField | c:@ST>2#T#T@TemplateClass@S@NestedType@FI@nestedField |
+
+ class SubNestedType {
+// CHECK: [[@LINE-1]]:11 | class/C++ | SubNestedType | c:@ST>2#T#T@TemplateClass@S@NestedType@S@SubNestedType |
+ public:
+ SubNestedType(int);
+ };
+ using TypeAlias = T;
+// CHECK: [[@LINE-1]]:11 | type-alias/C++ | TypeAlias | c:@ST>2#T#T@TemplateClass@S@NestedType@TypeAlias |
+
+ typedef int Typedef;
+// CHECK: [[@LINE-1]]:17 | type-alias/C | Typedef | c:{{.*}}index-instantiated-source.cpp@ST>2#T#T@TemplateClass@S@NestedType@T@Typedef |
+
+ enum Enum {
+// CHECK: [[@LINE-1]]:10 | enum/C | Enum | c:@ST>2#T#T@TemplateClass@S@NestedType@E@Enum |
+ EnumCase
+// CHECK: [[@LINE-1]]:7 | enumerator/C | EnumCase | c:@ST>2#T#T@TemplateClass@S@NestedType@E@Enum@EnumCase |
+ };
+ };
+};
+
+void canonicalizeInstaniationReferences(TemplateClass<int, float> &object) {
+ (void)object.function();
+// CHECK: [[@LINE-1]]:16 | instance-method/C++ | function | c:@ST>2#T#T@TemplateClass@F@function# | <no-cgname>
+ (void)object.field;
+// CHECK: [[@LINE-1]]:16 | field/C++ | field | c:@ST>2#T#T@TemplateClass@FI@field | <no-cgname> | Ref,RelCont | rel: 1
+ (void)object.baseTemplateFunction();
+// CHECK: [[@LINE-1]]:16 | instance-method/C++ | baseTemplateFunction | c:@ST>1#T@BaseTemplate@F@baseTemplateFunction# | <no-cgname>
+ (void)object.baseTemplateField;
+// CHECK: [[@LINE-1]]:16 | field/C++ | baseTemplateField | c:@ST>1#T@BaseTemplate@FI@baseTemplateField | <no-cgname> | Ref,RelCont | rel: 1
+
+ TemplateClass<int, float>::staticFunction();
+// CHECK: [[@LINE-1]]:30 | static-method/C++ | staticFunction | c:@ST>2#T#T@TemplateClass@F@staticFunction#S | <no-cgname
+
+ TemplateClass<int, float>::NestedBaseType nestedBaseType;
+// CHECK: [[@LINE-1]]:30 | struct/C | NestedBaseType | c:@ST>1#T@BaseTemplate@S@NestedBaseType |
+ TemplateClass<int, float>::NestedType nestedSubType;
+// CHECK: [[@LINE-1]]:30 | struct/C++ | NestedType | c:@ST>2#T#T@TemplateClass@S@NestedType |
+ (void)nestedSubType.nestedField;
+// CHECK: [[@LINE-1]]:23 | field/C++ | nestedField | c:@ST>2#T#T@TemplateClass@S@NestedType@FI@nestedField |
+
+ typedef TemplateClass<int, float> TT;
+ TT::NestedType::SubNestedType subNestedType(0);
+// CHECK: [[@LINE-1]]:7 | struct/C++ | NestedType | c:@ST>2#T#T@TemplateClass@S@NestedType |
+// CHECK: [[@LINE-2]]:19 | class/C++ | SubNestedType | c:@ST>2#T#T@TemplateClass@S@NestedType@S@SubNestedType |
+
+ TT::NestedType::TypeAlias nestedTypeAlias;
+// CHECK: [[@LINE-1]]:19 | type-alias/C++ | TypeAlias | c:@ST>2#T#T@TemplateClass@S@NestedType@TypeAlias |
+ TT::NestedType::Typedef nestedTypedef;
+// CHECK: [[@LINE-1]]:19 | type-alias/C | Typedef | c:{{.*}}index-instantiated-source.cpp@ST>2#T#T@TemplateClass@S@NestedType@T@Typedef |
+
+ TT::NestedType::Enum nestedEnum;
+// CHECK: [[@LINE-1]]:19 | enum/C | Enum | c:@ST>2#T#T@TemplateClass@S@NestedType@E@Enum |
+ (void)TT::NestedType::Enum::EnumCase;
+// CHECK: [[@LINE-1]]:31 | enumerator/C | EnumCase | c:@ST>2#T#T@TemplateClass@S@NestedType@E@Enum@EnumCase |
+}
diff --git a/test/Index/Core/index-source-invalid-name.cpp b/test/Index/Core/index-source-invalid-name.cpp
new file mode 100644
index 0000000000..1b4b059cd1
--- /dev/null
+++ b/test/Index/Core/index-source-invalid-name.cpp
@@ -0,0 +1,13 @@
+// RUN: c-index-test core -print-source-symbols -- %s -std=c++1z -target x86_64-apple-macosx10.7 | FileCheck %s
+
+namespace rdar32474406 {
+// CHECK: [[@LINE+1]]:6 | function/C | foo | c:@N@rdar32474406@F@foo# | __ZN12rdar324744063fooEv | Decl,RelChild | rel: 1
+void foo();
+// CHECK: [[@LINE+1]]:16 | type-alias/C | Func_t | c:index-source-invalid-name.cpp@N@rdar32474406@T@Func_t | <no-cgname> | Def,RelChild | rel: 1
+typedef void (*Func_t)();
+// CHECK: [[@LINE+4]]:1 | type-alias/C | Func_t | c:index-source-invalid-name.cpp@N@rdar32474406@T@Func_t | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | rdar32474406 | c:@N@rdar32474406
+// CHECK: [[@LINE+2]]:14 | function/C | foo | c:@N@rdar32474406@F@foo# | __ZN12rdar324744063fooEv | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | rdar32474406 | c:@N@rdar32474406
+Func_t[] = { foo }; // invalid decomposition
+}
diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp
index ab7c6f4c06..f9c88d5ea6 100644
--- a/test/Index/Core/index-source.cpp
+++ b/test/Index/Core/index-source.cpp
@@ -1,14 +1,21 @@
-// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
+// RUN: c-index-test core -print-source-symbols -- %s -std=c++1z -target x86_64-apple-macosx10.7 | FileCheck %s
// 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
+class Cls { public:
+ // 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
@@ -24,6 +31,16 @@ typedef Cls ClsAlias;
// 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
@@ -33,6 +50,12 @@ public:
// CHECK-NEXT: RelChild | TemplCls | c:@ST>1#T@TemplCls
};
+template<>
+class TemplCls<double> {
+// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | TemplCls | c:@S@TemplCls>#d | <no-cgname> | Def,RelSpecialization | rel: 1
+// CHECK: RelSpecialization | TemplCls | c:@ST>1#T@TemplCls
+};
+
TemplCls<int> gtv(0);
// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | TemplCls | c:@ST>1#T@TemplCls | <no-cgname> | Ref,RelCont | rel: 1
@@ -74,3 +97,431 @@ int gvi = tmplVar<int>;
// CHECK: [[@LINE+2]]:5 | variable/C | gvf | c:@gvf | _gvf | Def | rel: 0
// CHECK: [[@LINE+1]]:11 | variable(Gen)/C++ | tmplVar | c:index-source.cpp@VT>1#T@tmplVar | __ZL7tmplVar | Ref,Read,RelCont | rel: 1
int gvf = tmplVar<float>;
+
+template<typename A, typename B>
+class PartialSpecilizationClass { };
+// CHECK: [[@LINE-1]]:7 | class(Gen)/C++ | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass | <no-cgname> | Def | rel: 0
+
+template<typename B>
+class PartialSpecilizationClass<int, B *> { };
+// CHECK: [[@LINE-1]]:7 | class(Gen,TPS)/C++ | PartialSpecilizationClass | c:@SP>1#T@PartialSpecilizationClass>#I#*t0.0 | <no-cgname> | Def,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass
+
+template<>
+class PartialSpecilizationClass<int, int> { };
+// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#I#I | <no-cgname> | Def,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass
+
+template<typename T, typename S>
+class PseudoOverridesInSpecializations {
+ void function() { }
+ void function(int) { }
+
+ static void staticFunction() { }
+
+ int field;
+ static int variable;
+
+ typedef T TypeDef;
+ using TypeAlias = T;
+
+ enum anEnum { };
+
+ struct Struct { };
+ union Union { };
+
+ using TypealiasOrRecord = void;
+
+ template<typename U> struct InnerTemplate { };
+ template<typename U> struct InnerTemplate <U*> { };
+
+ template<typename U>
+ class InnerClass { };
+};
+
+template<>
+class PseudoOverridesInSpecializations<double, int> {
+ void function() { }
+// CHECK: [[@LINE-1]]:8 | instance-method/C++ | function | c:@S@PseudoOverridesInSpecializations>#d#I@F@function# | __ZN32PseudoOverridesInSpecializationsIdiE8functionEv | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | function | c:@ST>2#T#T@PseudoOverridesInSpecializations@F@function#
+
+ void staticFunction() { }
+// CHECK: [[@LINE-1]]:8 | instance-method/C++ | staticFunction | c:@S@PseudoOverridesInSpecializations>#d#I@F@staticFunction# | __ZN32PseudoOverridesInSpecializationsIdiE14staticFunctionEv | Def,RelChild | rel: 1
+// CHECK-NOT: RelSpecialization
+
+ int notOverridingField = 0;
+
+// CHECK-LABEL: checLabelBreak
+ int checLabelBreak = 0;
+
+ int field = 0;
+// CHECK: [[@LINE-1]]:7 | field/C++ | field | c:@S@PseudoOverridesInSpecializations>#d#I@FI@field | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | field | c:@ST>2#T#T@PseudoOverridesInSpecializations@FI@field
+
+ static double variable;
+// CHECK: [[@LINE-1]]:17 | static-property/C++ | variable | c:@S@PseudoOverridesInSpecializations>#d#I@variable | __ZN32PseudoOverridesInSpecializationsIdiE8variableE | Decl,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | variable | c:@ST>2#T#T@PseudoOverridesInSpecializations@variable
+
+ typedef double TypeDef;
+// CHECK: [[@LINE-1]]:18 | type-alias/C | TypeDef | c:index-source.cpp@S@PseudoOverridesInSpecializations>#d#I@T@TypeDef | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | TypeDef | c:index-source.cpp@ST>2#T#T@PseudoOverridesInSpecializations@T@TypeDef
+
+ using TypeAlias = int;
+// CHECK: [[@LINE-1]]:9 | type-alias/C++ | TypeAlias | c:@S@PseudoOverridesInSpecializations>#d#I@TypeAlias | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | TypeAlias | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypeAlias
+
+ enum anEnum { };
+// CHECK: [[@LINE-1]]:8 | enum/C | anEnum | c:@S@PseudoOverridesInSpecializations>#d#I@E@anEnum | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | anEnum | c:@ST>2#T#T@PseudoOverridesInSpecializations@E@anEnum
+ class Struct { };
+// CHECK: [[@LINE-1]]:9 | class/C++ | Struct | c:@S@PseudoOverridesInSpecializations>#d#I@S@Struct | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | Struct | c:@ST>2#T#T@PseudoOverridesInSpecializations@S@Struct
+ union Union { };
+// CHECK: [[@LINE-1]]:9 | union/C | Union | c:@S@PseudoOverridesInSpecializations>#d#I@U@Union | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | Union | c:@ST>2#T#T@PseudoOverridesInSpecializations@U@Union
+
+ struct TypealiasOrRecord { };
+// CHECK: [[@LINE-1]]:10 | struct/C | TypealiasOrRecord | c:@S@PseudoOverridesInSpecializations>#d#I@S@TypealiasOrRecord | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypealiasOrRecord
+
+ template<typename U> struct InnerTemplate { };
+// CHECK: [[@LINE-1]]:31 | struct(Gen)/C++ | InnerTemplate | c:@S@PseudoOverridesInSpecializations>#d#I@ST>1#T@InnerTemplate | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | InnerTemplate | c:@ST>2#T#T@PseudoOverridesInSpecializations@ST>1#T@InnerTemplate
+ template<typename U> struct InnerTemplate <U*> { };
+
+ template<typename U>
+ class InnerClass;
+// CHECK: [[@LINE-1]]:9 | class(Gen)/C++ | InnerClass | c:@S@PseudoOverridesInSpecializations>#d#I@ST>1#T@InnerClass | <no-cgname> | Ref,RelCont,RelSpecialization | rel: 2
+// CHECK-NEXT: RelCont
+// CHECK-NEXT: RelSpecialization | InnerClass | c:@ST>2#T#T@PseudoOverridesInSpecializations@ST>1#T@InnerClass
+};
+
+template<typename U>
+class PseudoOverridesInSpecializations<double, int>::InnerClass {
+};
+// CHECK: [[@LINE-2]]:54 | class(Gen)/C++ | InnerClass | c:@S@PseudoOverridesInSpecializations>#d#I@ST>1#T@InnerClass | <no-cgname> | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild
+// CHECK: [[@LINE-4]]:7 | class(Gen)/C++ | PseudoOverridesInSpecializations | c:@ST>2#T#T@PseudoOverridesInSpecializations | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont
+
+template<typename S>
+class PseudoOverridesInSpecializations<float, S> {
+ typedef float TypealiasOrRecord;
+// CHECK: [[@LINE-1]]:17 | type-alias/C | TypealiasOrRecord | c:index-source.cpp@SP>1#T@PseudoOverridesInSpecializations>#f#t0.0@T@TypealiasOrRecord | <no-cgname> | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypealiasOrRecord
+};
+
+template<typename T, typename U>
+class ConflictingPseudoOverridesInSpecialization {
+ void foo(T x);
+ void foo(U x);
+};
+
+template<typename T>
+class ConflictingPseudoOverridesInSpecialization<int, T> {
+ void foo(T x);
+// CHECK: [[@LINE-1]]:8 | instance-method/C++ | foo | c:@SP>1#T@ConflictingPseudoOverridesInSpecialization>#I#t0.0@F@foo#S0_# | <no-cgname> | Decl,RelChild,RelSpecialization | rel: 3
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | foo | c:@ST>2#T#T@ConflictingPseudoOverridesInSpecialization@F@foo#t0.0#
+// CHECK-NEXT: RelSpecialization | foo | c:@ST>2#T#T@ConflictingPseudoOverridesInSpecialization@F@foo#t0.1#
+};
+
+template<typename T, typename U, int x>
+void functionSpecialization();
+
+template<typename T, typename U, int x>
+void functionSpecialization() { }
+// CHECK: [[@LINE-1]]:6 | function/C | functionSpecialization | c:@FT@>3#T#T#NIfunctionSpecialization#v# | <no-cgname> | Def | rel: 0
+
+template<>
+void functionSpecialization<int, int, 0>();
+// CHECK: [[@LINE-1]]:6 | function(Gen,TS)/C++ | functionSpecialization | c:@F@functionSpecialization<#I#I#VI0># | __Z22functionSpecializationIiiLi0EEvv | Decl,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | functionSpecialization | c:@FT@>3#T#T#NIfunctionSpecialization#v#
+
+template<>
+void functionSpecialization<int, int, 0>() { }
+// CHECK: [[@LINE-1]]:6 | function(Gen,TS)/C++ | functionSpecialization | c:@F@functionSpecialization<#I#I#VI0># | __Z22functionSpecializationIiiLi0EEvv | Def,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | functionSpecialization | c:@FT@>3#T#T#NIfunctionSpecialization#v#
+
+struct ContainsSpecializedMemberFunction {
+ template<typename T>
+ void memberSpecialization();
+};
+
+template<typename T>
+void ContainsSpecializedMemberFunction::memberSpecialization() {
+// CHECK: [[@LINE-1]]:41 | instance-method/C++ | memberSpecialization | c:@S@ContainsSpecializedMemberFunction@FT@>1#TmemberSpecialization#v# | <no-cgname> | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild
+}
+
+template<>
+void ContainsSpecializedMemberFunction::memberSpecialization<int>() {
+// CHECK: [[@LINE-1]]:41 | instance-method(Gen,TS)/C++ | memberSpecialization | c:@S@ContainsSpecializedMemberFunction@F@memberSpecialization<#I># | __ZN33ContainsSpecializedMemberFunction20memberSpecializationIiEEvv | Def,RelChild,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelSpecialization | memberSpecialization | c:@S@ContainsSpecializedMemberFunction@FT@>1#TmemberSpecialization#v#
+}
+
+template<typename T>
+class SpecializationDecl;
+// CHECK: [[@LINE-1]]:7 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref | rel: 0
+
+template<typename T>
+class SpecializationDecl { };
+// CHECK: [[@LINE-1]]:7 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Def | rel: 0
+
+template<>
+class SpecializationDecl<int>;
+// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#I | <no-cgname> | Decl,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | SpecializationDecl | c:@ST>1#T@SpecializationDecl
+// CHECK: [[@LINE-3]]:7 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref | rel: 0
+
+template<>
+class SpecializationDecl<int> { };
+// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#I | <no-cgname> | Def,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | SpecializationDecl | c:@ST>1#T@SpecializationDecl
+// CHECK-NEXT: [[@LINE-3]]:7 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref | rel: 0
+
+template<typename T>
+class PartialSpecilizationClass<Cls, T>;
+// CHECK: [[@LINE-1]]:7 | class(Gen,TPS)/C++ | PartialSpecilizationClass | c:@SP>1#T@PartialSpecilizationClass>#$@S@Cls#t0.0 | <no-cgname> | Decl,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass
+// CHECK: [[@LINE-3]]:7 | class(Gen)/C++ | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass | <no-cgname> | Ref | rel: 0
+// CHECK-NEXT: [[@LINE-4]]:33 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0
+
+template<>
+class PartialSpecilizationClass<Cls, Cls> : Cls { };
+// CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#$@S@Cls#S0_ | <no-cgname> | Def,RelSpecialization | rel: 1
+// CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass
+// CHECK-NEXT: [[@LINE-3]]:45 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#$@S@Cls#S0_
+// CHECK-NEXT: [[@LINE-5]]:7 | class(Gen)/C++ | PartialSpecilizationClass | c:@ST>2#T#T@PartialSpecilizationClass | <no-cgname> | Ref | rel: 0
+// CHECK-NEXT: [[@LINE-6]]:33 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0
+// CHECK-NEXT: [[@LINE-7]]:38 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0
+
+template<typename T, int x>
+void functionSp() { }
+
+struct Record {
+ constexpr static int C = 2;
+};
+
+template<>
+void functionSp<SpecializationDecl<Cls>, Record::C>() {
+// CHECK: [[@LINE-1]]:6 | function(Gen,TS)/C++ | functionSp | c:@F@functionSp<#$@S@SpecializationDecl>#$@S@Cls#VI2># | __Z10functionSpI18SpecializationDeclI3ClsELi2EEvv | Def,RelSpecialization | rel: 1
+// CHECK: RelSpecialization | functionSp | c:@FT@>2#T#NIfunctionSp#v#
+// CHECK: [[@LINE-3]]:17 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-4]]:36 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-5]]:50 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-6]]:42 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref,RelCont | rel: 1
+}
+
+template<typename T, int x>
+class ClassWithCorrectSpecialization { };
+
+template<>
+class ClassWithCorrectSpecialization<SpecializationDecl<Cls>, Record::C> { };
+// CHECK: [[@LINE-1]]:38 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref | rel: 0
+// CHECK: [[@LINE-2]]:57 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0
+// CHECK: [[@LINE-3]]:71 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,Read | rel: 0
+// CHECK: [[@LINE-4]]:63 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref | rel: 0
+
+namespace ns {
+// CHECK: [[@LINE-1]]:11 | namespace/C++ | ns | c:@N@ns | <no-cgname> | Decl | rel: 0
+namespace inner {
+// CHECK: [[@LINE-1]]:11 | namespace/C++ | inner | c:@N@ns@N@inner | <no-cgname> | Decl,RelChild | rel: 1
+void func();
+
+}
+namespace innerAlias = inner;
+// CHECK: [[@LINE-1]]:11 | namespace-alias/C++ | innerAlias | c:@N@ns@NA@innerAlias | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK: [[@LINE-2]]:24 | namespace/C++ | inner | c:@N@ns@N@inner | <no-cgname> | Ref,RelCont | rel: 1
+}
+
+namespace namespaceAlias = ::ns::innerAlias;
+// CHECK: [[@LINE-1]]:11 | namespace-alias/C++ | namespaceAlias | c:@NA@namespaceAlias | <no-cgname> | Decl | rel: 0
+// CHECK: [[@LINE-2]]:30 | namespace/C++ | ns | c:@N@ns | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-3]]:34 | namespace-alias/C++ | innerAlias | c:@N@ns@NA@innerAlias | <no-cgname> | Ref,RelCont | rel: 1
+
+void ::ns::inner::func() {
+// CHECK: [[@LINE-1]]:8 | namespace/C++ | ns | c:@N@ns | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:12 | namespace/C++ | inner | c:@N@ns@N@inner | <no-cgname> | Ref,RelCont | rel: 1
+ ns::innerAlias::func();
+// CHECK: [[@LINE-1]]:3 | namespace/C++ | ns | c:@N@ns | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:7 | namespace-alias/C++ | innerAlias | c:@N@ns@NA@innerAlias | <no-cgname> | Ref,RelCont | rel: 1
+}
+
+void innerUsingNamespace() {
+ using namespace ns;
+// CHECK: [[@LINE-1]]:19 | namespace/C++ | ns | c:@N@ns | <no-cgname> | Ref,RelCont | rel: 1
+ {
+ using namespace ns::innerAlias;
+// CHECK: [[@LINE-1]]:25 | namespace-alias/C++ | innerAlias | c:@N@ns@NA@innerAlias | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:21 | namespace/C++ | ns | c:@N@ns | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NOT: [[@LINE-3]]:21
+ }
+}
+
+void indexDefaultValueInDefn(Cls cls = Cls(gvi), Record param = Record()) {
+// CHECK: [[@LINE-1]]:40 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:44 | variable/C | gvi | c:@gvi | _gvi | Ref,Read,RelCont | rel: 1
+// CHECK-NOT: [[@LINE-3]]:44
+// CHECK: [[@LINE-4]]:65 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NOT: [[@LINE-5]]:65
+}
+
+template<template <typename> class T>
+struct IndexDefaultValue {
+ IndexDefaultValue(int k = Record::C) {
+// CHECK: [[@LINE-1]]:38 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,Read,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:30 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref,RelCont | rel: 1
+ }
+};
+
+struct DeletedMethods {
+ DeletedMethods(const DeletedMethods &) = delete;
+// CHECK: [[@LINE-1]]:3 | constructor/cxx-copy-ctor/C++ | DeletedMethods | c:@S@DeletedMethods@F@DeletedMethods#&1$@S@DeletedMethods# | __ZN14DeletedMethodsC1ERKS_ | Def,RelChild | rel: 1
+// CHECK: RelChild | DeletedMethods | c:@S@DeletedMethods
+// CHECK: [[@LINE-3]]:24 | struct/C++ | DeletedMethods | c:@S@DeletedMethods | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-4]]:3 | struct/C++ | DeletedMethods | c:@S@DeletedMethods | <no-cgname> | Ref,RelCont | rel: 1
+};
+
+namespace ns2 {
+template<typename T> struct ACollectionDecl { };
+}
+
+template<typename T = Cls,
+// CHECK: [[@LINE-1]]:23 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | TemplateDefaultValues | c:@ST>3#T#NI#t>1#T@TemplateDefaultValues
+ int x = Record::C,
+// CHECK: [[@LINE-1]]:26 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,Read,RelCont | rel: 1
+// CHECK-NEXT: RelCont | TemplateDefaultValues | c:@ST>3#T#NI#t>1#T@TemplateDefaultValues
+// CHECK: [[@LINE-3]]:18 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref,RelCont | rel: 1
+ template <typename> class Collection = ns2::ACollectionDecl>
+// CHECK: [[@LINE-1]]:49 | namespace/C++ | ns2 | c:@N@ns2 | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | TemplateDefaultValues | c:@ST>3#T#NI#t>1#T@TemplateDefaultValues
+// CHECK: [[@LINE-3]]:54 | struct(Gen)/C++ | ACollectionDecl | c:@N@ns2@ST>1#T@ACollectionDecl | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | TemplateDefaultValues | c:@ST>3#T#NI#t>1#T@TemplateDefaultValues
+struct TemplateDefaultValues { };
+
+template<typename T = Record,
+// CHECK: [[@LINE-1]]:23 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref,RelCont | rel: 1
+ int x = sizeof(Cls)>
+// CHECK: [[@LINE-1]]:25 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+void functionTemplateDefaultValues() { }
+
+namespace ensureDefaultTemplateParamsAreRecordedOnce {
+
+template<typename T = Cls>
+// CHECK: [[@LINE-1]]:23 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NOT: [[@LINE-2]]:23
+void functionDecl();
+
+template<typename T>
+void functionDecl() { }
+
+template<typename T = Cls>
+// CHECK: [[@LINE-1]]:23 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NOT: [[@LINE-2]]:23
+class TagDecl;
+
+template<typename T>
+class TagDecl;
+
+template<typename T>
+class TagDecl { };
+
+template<typename T = Cls>
+// CHECK: [[@LINE-1]]:23 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+using TypeAlias = TagDecl<T>;
+
+template<typename T = Cls>
+// CHECK: [[@LINE-1]]:23 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NOT: [[@LINE-2]]:23
+extern T varDecl;
+
+template<typename T>
+T varDecl = T();
+
+} // end namespace ensureDefaultTemplateParamsAreRecordedOnce
+
+struct StaticAssertRef {
+ static constexpr bool constVar = true;
+};
+
+static_assert(StaticAssertRef::constVar, "index static asserts");
+// CHECK: [[@LINE-1]]:32 | static-property/C++ | constVar | c:@S@StaticAssertRef@constVar | __ZN15StaticAssertRef8constVarE | Ref | rel: 0
+// CHECK: [[@LINE-2]]:15 | struct/C++ | StaticAssertRef | c:@S@StaticAssertRef | <no-cgname> | Ref | rel: 0
+
+void staticAssertInFn() {
+ static_assert(StaticAssertRef::constVar, "index static asserts");
+// CHECK: [[@LINE-1]]:34 | static-property/C++ | constVar | c:@S@StaticAssertRef@constVar | __ZN15StaticAssertRef8constVarE | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | staticAssertInFn | c:@F@staticAssertInFn#
+// CHECK: [[@LINE-3]]:17 | struct/C++ | StaticAssertRef | c:@S@StaticAssertRef | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | staticAssertInFn | c:@F@staticAssertInFn#
+}
+
+namespace cpp17structuredBinding {
+
+struct Cpp17StructuredBinding {
+ int x, y;
+
+ Cpp17StructuredBinding(int x, int y): x(x), y(y) { }
+};
+
+auto [structuredBinding1, structuredBinding2] = Cpp17StructuredBinding(Record::C, 0);
+// CHECK: [[@LINE-1]]:7 | variable/C++ | structuredBinding1 | c:@N@cpp17structuredBinding@structuredBinding1 | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | cpp17structuredBinding | c:@N@cpp17structuredBinding
+// CHECK: [[@LINE-3]]:27 | variable/C++ | structuredBinding2 | c:@N@cpp17structuredBinding@structuredBinding2 | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | cpp17structuredBinding | c:@N@cpp17structuredBinding
+
+void localStructuredBindingAndRef() {
+ int ref = structuredBinding1;
+// CHECK: [[@LINE-1]]:13 | variable/C++ | structuredBinding1 | c:@N@cpp17structuredBinding@structuredBinding1 | <no-cgname> | Ref,Read,RelCont | rel: 1
+// CHECK-NEXT: RelCont | localStructuredBindingAndRef | c:@N@cpp17structuredBinding@F@localStructuredBindingAndRef#
+ auto [localBinding1, localBinding2] = Cpp17StructuredBinding(ref, structuredBinding2);
+// CHECK: [[@LINE-1]]:69 | variable/C++ | structuredBinding2 | c:@N@cpp17structuredBinding@structuredBinding2 | <no-cgname> | Ref,Read,RelCont | rel: 1
+// CHECK-NEXT: RelCont | localStructuredBindingAndRef | c:@N@cpp17structuredBinding@F@localStructuredBindingAndRef#
+// CHECK-NOT: localBinding
+}
+
+}
+
+template<typename T>
+struct Guided { T t; };
+// CHECK: [[@LINE-1]]:8 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | <no-cgname> | Def | rel: 0
+// CHECK-NEXT: [[@LINE-2]]:19 | field/C++ | t | c:@ST>1#T@Guided@FI@t | <no-cgname> | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | Guided | c:@ST>1#T@Guided
+Guided(double) -> Guided<float>;
+// CHECK: [[@LINE-1]]:19 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | <no-cgname> | Ref | rel: 0
+// CHECK-NEXT: [[@LINE-2]]:1 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | <no-cgname> | Ref | rel: 0
+auto guided = Guided{1.0};
+// CHECK: [[@LINE-1]]:6 | variable/C | guided | c:@guided | _guided | Def | rel: 0
+// CHECK-NEXT: [[@LINE-2]]:15 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | guided | c:@guided
+
+namespace rd33122110 {
+
+struct Outer {
+ template<typename T>
+ struct Nested { };
+};
+
+}
+
+template<>
+struct rd33122110::Outer::Nested<int>;
+// CHECK: [[@LINE-1]]:8 | namespace/C++ | rd33122110 | c:@N@rd33122110 | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | Nested | c:@N@rd33122110@S@Outer@S@Nested>#I
+// CHECK: [[@LINE-3]]:20 | struct/C++ | Outer | c:@N@rd33122110@S@Outer | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | Nested | c:@N@rd33122110@S@Outer@S@Nested>#I
diff --git a/test/Index/Core/index-source.m b/test/Index/Core/index-source.m
index 2675edd026..2931e664ea 100644
--- a/test/Index/Core/index-source.m
+++ b/test/Index/Core/index-source.m
@@ -121,39 +121,79 @@ extern int setjmp(jmp_buf);
@end
@interface I2
-@property (readwrite) id prop;
+// CHECK: [[@LINE-1]]:12 | class/ObjC | I2 | [[I2_USR:.*]] | {{.*}} | Decl | rel: 0
-// 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) 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
+
+@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
@implementation I2
-// CHECK: [[@LINE+9]]:13 | instance-property/ObjC | prop | c:objc(cs)I2(py)prop | <no-cgname> | Def,RelChild,RelAcc | rel: 2
-// 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 | c:objc(cs)I2(im)prop | -[I2 prop] | Def,Impl,RelChild | rel: 1
-// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2
-// CHECK: [[@LINE+4]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I2(im)setProp: | -[I2 setProp:] | Def,Impl,RelChild | rel: 1
-// CHECK-NEXT: RelChild | I2 | c:objc(cs)I2
+// CHECK: [[@LINE+6]]:13 | instance-method/acc-get/ObjC | prop | [[I2_prop_getter_USR]] | -[I2 prop] | Def,Dyn,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,Dyn,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 | c:objc(cs)I2
+// CHECK-NEXT: RelChild | I2 | [[I2_USR]]
@synthesize prop = _prop;
-// CHECK: [[@LINE+11]]: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+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: | c:objc(cs)I2(im)doAction:foo:
+// 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: | c:objc(cs)I2(im)doAction:foo:
+// 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: | c:objc(cs)I2(im)doAction:foo:
--(IBAction)doAction:(I1 *)sender foo:(I1 *)bar {}
+// 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
@@ -174,8 +214,8 @@ extern int setjmp(jmp_buf);
// 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
+// CHECK: [[@LINE+2]]:13 | instance-method/acc-get/ObjC | prop | c:objc(cs)I3(im)prop | -[I3 prop] | Def,Dyn,Impl,RelChild | rel: 1
+// CHECK: [[@LINE+1]]:13 | instance-method/acc-set/ObjC | setProp: | c:objc(cs)I3(im)setProp: | -[I3 setProp:] | Def,Dyn,Impl,RelChild | rel: 1
@synthesize prop = _prop;
@end
@@ -235,9 +275,9 @@ typedef MyGenCls<Base *><MyEnumerating> MyEnumerator;
// 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: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I4(im)foo | -[I4 foo] | Def,Dyn,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: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I4(im)setFoo: | -[I4 setFoo:] | Def,Dyn,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
@@ -256,9 +296,9 @@ typedef MyGenCls<Base *><MyEnumerating> MyEnumerator;
// 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: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I5(im)foo | -[I5 foo] | Def,Dyn,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: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I5(im)setFoo: | -[I5 setFoo:] | Def,Dyn,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
@@ -277,9 +317,9 @@ typedef MyGenCls<Base *><MyEnumerating> MyEnumerator;
// 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: [[@LINE-4]]:13 | instance-method/acc-get/ObjC | foo | c:objc(cs)I6(im)foo | -[I6 foo] | Def,Dyn,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: [[@LINE-6]]:13 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I6(im)setFoo: | -[I6 setFoo:] | Def,Dyn,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
@@ -297,9 +337,9 @@ typedef MyGenCls<Base *><MyEnumerating> MyEnumerator;
// 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: [[@LINE-4]]:17 | instance-method/acc-get/ObjC | foo | c:objc(cs)I7(im)foo | -[I7 foo] | Def,Dyn,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: [[@LINE-6]]:17 | instance-method/acc-set/ObjC | setFoo: | c:objc(cs)I7(im)setFoo: | -[I7 setFoo:] | Def,Dyn,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
@@ -308,3 +348,127 @@ typedef MyGenCls<Base *><MyEnumerating> MyEnumerator;
// 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-NOT: [[@LINE-2]]:17 | {{.*}} | Ref
+// CHECK: [[@LINE-3]]:17 | enum/C | AnotherEnum | [[AnotherEnum_USR:.*]] | {{.*}} | Def | rel: 0
+ 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
+
+@interface ClassReceivers
+
+@property(class) int p1;
+// CHECK: [[@LINE-1]]:22 | class-method/acc-get/ObjC | p1 | c:objc(cs)ClassReceivers(cm)p1 | +[ClassReceivers p1] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | ClassReceivers | c:objc(cs)ClassReceivers
+// CHECK-NEXT: RelAcc | p1 | c:objc(cs)ClassReceivers(cpy)p1
+// CHECK: [[@LINE-4]]:22 | class-method/acc-set/ObjC | setP1: | c:objc(cs)ClassReceivers(cm)setP1: | +[ClassReceivers setP1:] | Decl,Dyn,Impl,RelChild,RelAcc | rel: 2
+// CHECK-NEXT: RelChild | ClassReceivers | c:objc(cs)ClassReceivers
+// CHECK-NEXT: RelAcc | p1 | c:objc(cs)ClassReceivers(cpy)p1
+// CHECK: [[@LINE-7]]:22 | instance-property/ObjC | p1 | c:objc(cs)ClassReceivers(cpy)p1 | <no-cgname> | Decl,RelChild | rel: 1
+// CHECK-NEXT: RelChild | ClassReceivers | c:objc(cs)ClassReceivers
+
++ (int)implicit;
++ (void)setImplicit:(int)x;
+
+@end
+
+void classReceivers() {
+ ClassReceivers.p1 = 0;
+// CHECK: [[@LINE-1]]:3 | class/ObjC | ClassReceivers | c:objc(cs)ClassReceivers | _OBJC_CLASS_$_ClassReceivers | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:18 | instance-property/ObjC | p1 | c:objc(cs)ClassReceivers(cpy)p1 | <no-cgname> | Ref,Writ,RelCont | rel: 1
+// CHECK-NEXT: RelCont | classReceivers | c:@F@classReceivers
+// CHECK: [[@LINE-4]]:18 | class-method/acc-set/ObjC | setP1: | c:objc(cs)ClassReceivers(cm)setP1: | +[ClassReceivers setP1:] | Ref,Call,Impl,RelCall,RelCont | rel: 1
+// CHECK-NEXT: RelCall,RelCont | classReceivers | c:@F@classReceivers
+ (void)ClassReceivers.p1;
+// CHECK: [[@LINE-1]]:9 | class/ObjC | ClassReceivers | c:objc(cs)ClassReceivers | _OBJC_CLASS_$_ClassReceivers | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:24 | instance-property/ObjC | p1 | c:objc(cs)ClassReceivers(cpy)p1 | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | classReceivers | c:@F@classReceivers
+// CHECK: [[@LINE-4]]:24 | class-method/acc-get/ObjC | p1 | c:objc(cs)ClassReceivers(cm)p1 | +[ClassReceivers p1] | Ref,Call,Impl,RelCall,RelCont | rel: 1
+// CHECK-NEXT: RelCall,RelCont | classReceivers | c:@F@classReceivers
+
+ ClassReceivers.implicit = 0;
+// CHECK: [[@LINE-1]]:3 | class/ObjC | ClassReceivers | c:objc(cs)ClassReceivers | _OBJC_CLASS_$_ClassReceivers | Ref,RelCont | rel: 1
+ (void)ClassReceivers.implicit;
+// CHECK: [[@LINE-1]]:9 | class/ObjC | ClassReceivers | c:objc(cs)ClassReceivers | _OBJC_CLASS_$_ClassReceivers | Ref,RelCont | rel: 1
+}
+
+@interface ImplicitProperties
+
+- (int)implicit;
+- (void)setImplicit:(int)x;
+
++ (int)classImplicit;
++ (void)setClassImplicit:(int)y;
+
+@end
+
+void testImplicitProperties(ImplicitProperties *c) {
+ c.implicit = 0;
+// CHECK: [[@LINE-1]]:5 | instance-method/ObjC | setImplicit: | c:objc(cs)ImplicitProperties(im)setImplicit: | -[ImplicitProperties setImplicit:] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties
+ c.implicit;
+// CHECK: [[@LINE-1]]:5 | instance-method/ObjC | implicit | c:objc(cs)ImplicitProperties(im)implicit | -[ImplicitProperties implicit] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties
+ ImplicitProperties.classImplicit = 1;
+// CHECK: [[@LINE-1]]:22 | class-method/ObjC | setClassImplicit: | c:objc(cs)ImplicitProperties(cm)setClassImplicit: | +[ImplicitProperties setClassImplicit:] | Ref,Call,RelCall,RelCont | rel: 1
+// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties
+ ImplicitProperties.classImplicit;
+// CHECK: [[@LINE-1]]:22 | class-method/ObjC | classImplicit | c:objc(cs)ImplicitProperties(cm)classImplicit | +[ImplicitProperties classImplicit] | Ref,Call,RelCall,RelCont | rel: 1
+// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties
+}
+
+@interface EmptySelectors
+
+- (int):(int)_; // CHECK: [[@LINE]]:8 | instance-method/ObjC | : | c:objc(cs)EmptySelectors(im): | -[EmptySelectors :]
+- (void)test: (int)x :(int)y; // CHECK: [[@LINE]]:9 | instance-method/ObjC | test:: | c:objc(cs)EmptySelectors(im)test:: | -[EmptySelectors test::]
+- (void):(int)_ :(int)m:(int)z; // CHECK: [[@LINE]]:9 | instance-method/ObjC | ::: | c:objc(cs)EmptySelectors(im)::: | -[EmptySelectors :::]
+
+@end
+
+@implementation EmptySelectors
+
+- (int):(int)_ { // CHECK: [[@LINE]]:8 | instance-method/ObjC | : | c:objc(cs)EmptySelectors(im): | -[EmptySelectors :]
+ [self :2]; // CHECK: [[@LINE]]:9 | instance-method/ObjC | : | c:objc(cs)EmptySelectors(im): | -[EmptySelectors :]
+ return 0;
+}
+
+- (void)test: (int)x :(int)y { // CHECK: [[@LINE]]:9 | instance-method/ObjC | test:: | c:objc(cs)EmptySelectors(im)test:: | -[EmptySelectors test::]
+}
+
+- (void) :(int)_ :(int)m :(int)z { // CHECK: [[@LINE]]:10 | instance-method/ObjC | ::: | c:objc(cs)EmptySelectors(im)::: | -[EmptySelectors :::]
+ [self test:0:1]; // CHECK: [[@LINE]]:9 | instance-method/ObjC | test:: | c:objc(cs)EmptySelectors(im)test:: | -[EmptySelectors test::]
+ [self: 0: 1: 2]; // CHECK: [[@LINE]]:8 | instance-method/ObjC | ::: | c:objc(cs)EmptySelectors(im)::: | -[EmptySelectors :::]
+}
+
+@end
diff --git a/test/Index/Core/index-system.mm b/test/Index/Core/index-system.mm
new file mode 100644
index 0000000000..2ad31fae71
--- /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/no-templated-canonical-decl.cpp b/test/Index/Core/no-templated-canonical-decl.cpp
new file mode 100644
index 0000000000..5434e9cb65
--- /dev/null
+++ b/test/Index/Core/no-templated-canonical-decl.cpp
@@ -0,0 +1,4 @@
+// RUN: c-index-test core -print-source-symbols -include-locals -- %s | FileCheck %s
+
+template <template <typename> class A> class B { typedef A<int> A_int; };
+// CHECK: [[@LINE-1]]:46 | class(Gen)/C++ | B | c:@ST>1#t>1#T@B | <no-cgname> | Def | rel: 0
diff --git a/test/Index/Inputs/empty.dia b/test/Index/Inputs/empty.dia
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Index/Inputs/empty.dia
diff --git a/test/Index/KeepGoingWithLotsOfErrors.mm b/test/Index/KeepGoingWithLotsOfErrors.mm
new file mode 100644
index 0000000000..078ea6e2ea
--- /dev/null
+++ b/test/Index/KeepGoingWithLotsOfErrors.mm
@@ -0,0 +1,29 @@
+// RUN: env CINDEXTEST_KEEP_GOING=1 c-index-test -code-completion-at=%s:25:1 %s
+// Shouldn't crash!
+// This is the minimized test that triggered an infinite recursion:
+
++(BOOL) onEntity {
+}
+
+-(const Object &) a_200 {
+}
+
+-(int) struct {
+}
+
+-(int) bar {
+}
+
+-(int) part {
+}
+
++(some_type_t) piece {
+}
+
++(void) z_Z_42 {
+ ([self onEntity: [] { 42];
+ } class: ^ { }
+];
+ [super];
+ BOOL struct;
+}
diff --git a/test/Index/USR/array-type.cpp b/test/Index/USR/array-type.cpp
new file mode 100644
index 0000000000..40ff20d388
--- /dev/null
+++ b/test/Index/USR/array-type.cpp
@@ -0,0 +1,11 @@
+// RUN: c-index-test core -print-source-symbols -- %s | FileCheck %s
+
+// Function template specializations differing in array type parameter should have unique USRs.
+
+template<class buffer> void foo(buffer);
+// CHECK: {{[0-9]+}}:17 | function(Gen,TS)/C++ | foo | c:@F@foo<#{n16C>#*C#
+template<> void foo<char[16]>(char[16]);
+// CHECK: {{[0-9]+}}:17 | function(Gen,TS)/C++ | foo | c:@F@foo<#{n32C>#*C#
+template<> void foo<char[32]>(char[32]);
+// CHECK: {{[0-9]+}}:17 | function(Gen,TS)/C++ | foo | c:@F@foo<#{n64C>#*C#
+template<> void foo<char[64]>(char[64]);
diff --git a/test/Index/USR/func-type.cpp b/test/Index/USR/func-type.cpp
new file mode 100644
index 0000000000..ff1cd37a7f
--- /dev/null
+++ b/test/Index/USR/func-type.cpp
@@ -0,0 +1,18 @@
+// RUN: c-index-test core -print-source-symbols -- %s | FileCheck %s
+
+// Functions taking function pointer parameters with different signatures should result in unique USRs.
+
+typedef void (*_VoidToVoidPtr_)();
+typedef void (*_IntToVoidPtr_)( int );
+typedef _VoidToVoidPtr_ (*IntTo_VoidToVoidPtr_Ptr)( int );
+typedef _IntToVoidPtr_ (*VoidTo_IntToVoidPtr_Ptr)();
+
+void Func( IntTo_VoidToVoidPtr_Ptr );
+// CHECK: {{[0-9]+}}:6 | function/C | Func | c:@F@Func#*F*Fv()(#I)# |
+void Func( VoidTo_IntToVoidPtr_Ptr );
+// CHECK: {{[0-9]+}}:6 | function/C | Func | c:@F@Func#*F*Fv(#I)()# |
+
+void Func( void (* (*)(int, int))(int, int) );
+// CHECK: {{[0-9]+}}:6 | function/C | Func | c:@F@Func#*F*Fv(#I#I)(#I#I)# |
+void Func( void (* (*)(int, int, int))(int) );
+// CHECK: {{[0-9]+}}:6 | function/C | Func | c:@F@Func#*F*Fv(#I)(#I#I#I)# |
diff --git a/test/Index/allow-editor-placeholders.cpp b/test/Index/allow-editor-placeholders.cpp
new file mode 100644
index 0000000000..5a7207d3f0
--- /dev/null
+++ b/test/Index/allow-editor-placeholders.cpp
@@ -0,0 +1,5 @@
+// RUN: c-index-test -test-load-source all %s 2>&1 | FileCheck %s
+
+<#placeholder#>;
+
+// CHECK-NOT: error
diff --git a/test/Index/annotate-attribute.cpp b/test/Index/annotate-attribute.cpp
index d822210e49..bf415fc8fe 100644
--- a/test/Index/annotate-attribute.cpp
+++ b/test/Index/annotate-attribute.cpp
@@ -16,6 +16,12 @@ protected:
void methodWithoutAttribute();
};
+template <typename T>
+class __attribute__((annotate("works"))) TemplateTest {};
+
+template <typename T>
+int templateFunction(T value) __attribute__((annotate("works")));
+
// CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2]
// CHECK-NEXT: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8]
// CHECK-NEXT: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60]
@@ -31,3 +37,9 @@ protected:
// CHECK-NEXT: CompoundStmt= Extent=[12:23 - 12:25]
// CHECK-NEXT: CXXAccessSpecifier=:14:1 (Definition) Extent=[14:1 - 14:11]
// CHECK-NEXT: CXXMethod=methodWithoutAttribute:16:8 Extent=[16:3 - 16:32]
+// CHECK: ClassTemplate=TemplateTest:20:42 (Definition) Extent=[19:1 - 20:57]
+// CHECK-NEXT: TemplateTypeParameter=T:19:20 (Definition) Extent=[19:11 - 19:21] [access=public]
+// CHECK-NEXT: attribute(annotate)=works Extent=[20:22 - 20:39]
+// CHECK: FunctionTemplate=templateFunction:23:5 Extent=[22:1 - 23:65]
+// CHECK-NEXT: TemplateTypeParameter=T:22:20 (Definition) Extent=[22:11 - 22:21] [access=public]
+// CHECK-NEXT: attribute(annotate)=works Extent=[23:46 - 23:63]
diff --git a/test/Index/availability.c b/test/Index/availability.c
index b9d2c6f449..206b8a2a71 100644
--- a/test/Index/availability.c
+++ b/test/Index/availability.c
@@ -8,13 +8,15 @@ enum {
enum {
old_enum_plat
-} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7)
+} __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7)));
-// RUN: c-index-test -test-load-source all %s > %t
-// RUN: FileCheck -check-prefix=CHECK-1 %s < %t
-// RUN: FileCheck -check-prefix=CHECK-2 %s < %t
-// CHECK-1: (ios, introduced=3.2, deprecated=4.1)
-// CHECK-2: (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
+void bar(void) __attribute__((availability(macosx,introduced=10.4))) __attribute__((availability(macosx,obsoleted=10.6))) __attribute__((availability(ios,introduced=3.2))) __attribute__((availability(macosx,deprecated=10.5,message="use foobar")));
-// CHECK-2: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
-// CHECK-2: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
+void bar2(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0))) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5,obsoleted=10.7))) __attribute__((availability(ios,introduced=3.2,deprecated=10.0)));
+
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+// CHECK: FunctionDecl=foo:3:6{{.*}}(ios, introduced=3.2, deprecated=4.1) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
+// CHECK: EnumConstantDecl=old_enum:6:3 (Definition) (deprecated)
+// CHECK: EnumConstantDecl=old_enum_plat:10:3 {{.*}} (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
+// CHECK: FunctionDecl=bar:13:6{{.*}}(ios, introduced=3.2) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.6, message="use foobar")
+// CHECK: FunctionDecl=bar2:15:6{{.*}}(ios, introduced=3.2, deprecated=10.0) (macos, introduced=10.4, deprecated=10.5, obsoleted=10.7)
diff --git a/test/Index/code-completion.cpp b/test/Index/code-completion.cpp
index 83aa943744..00f158f3d0 100644
--- a/test/Index/code-completion.cpp
+++ b/test/Index/code-completion.cpp
@@ -37,10 +37,20 @@ Z::operator int() const {
return 0;
}
+template <typename T>
+struct Foo { T member; };
+
+template<typename T> using Bar = Foo<T>;
+
+void test_template_alias() {
+ // RUN: env CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:47:1 %s | FileCheck -check-prefix=CHECK-TEMPLATE-ALIAS %s
+
+}
+
// CHECK-MEMBER: FieldDecl:{ResultType double}{TypedText member}
// CHECK-MEMBER: FieldDecl:{ResultType int}{Text X::}{TypedText member}
// CHECK-MEMBER: FieldDecl:{ResultType float}{Text Y::}{TypedText member}
-// CHECK-MEMBER: CXXMethod:{ResultType void}{Informative Y::}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )}
+// CHECK-MEMBER: CXXMethod:{ResultType void}{Informative Y::}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i = 17}}{RightParen )}
// CHECK-MEMBER: CXXConversion:{TypedText operator int}{LeftParen (}{RightParen )}{Informative const}
// CHECK-MEMBER: CXXMethod:{ResultType Z &}{TypedText operator=}{LeftParen (}{Placeholder const Z &}{RightParen )}
// CHECK-MEMBER: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )}
@@ -77,7 +87,7 @@ Z::operator int() const {
// CHECK-EXPR: FieldDecl:{ResultType double}{TypedText member} (17)
// CHECK-EXPR: FieldDecl:{ResultType int}{Text X::}{TypedText member} (9)
// CHECK-EXPR: FieldDecl:{ResultType float}{Text Y::}{TypedText member} (18)
-// CHECK-EXPR: CXXMethod:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} (37)
+// CHECK-EXPR: CXXMethod:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i = 17}}{RightParen )} (37)
// CHECK-EXPR: Namespace:{TypedText N}{Text ::} (75)
// CHECK-EXPR: Completion contexts:
// CHECK-EXPR-NEXT: Any type
@@ -88,3 +98,5 @@ Z::operator int() const {
// CHECK-EXPR-NEXT: Class name
// CHECK-EXPR-NEXT: Nested name specifier
// CHECK-EXPR-NEXT: Objective-C interface
+
+// CHECK-TEMPLATE-ALIAS: AliasTemplateDecl:{TypedText Bar}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)
diff --git a/test/Index/comment-cplus-decls.cpp b/test/Index/comment-cplus-decls.cpp
index 463aa9e792..6e32c60a22 100644
--- a/test/Index/comment-cplus-decls.cpp
+++ b/test/Index/comment-cplus-decls.cpp
@@ -102,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 {
@@ -115,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 {
@@ -129,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 {
@@ -149,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/comment-to-html-xml-conversion-with-original-literals.cpp b/test/Index/comment-to-html-xml-conversion-with-original-literals.cpp
new file mode 100644
index 0000000000..26ca223883
--- /dev/null
+++ b/test/Index/comment-to-html-xml-conversion-with-original-literals.cpp
@@ -0,0 +1,26 @@
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s -std=c++11 | FileCheck %s
+
+constexpr int value(float f) { return int(f); }
+
+enum MyEnum {
+hexadecimal = 0x10 //!< a
+// CHECK: <Declaration>hexadecimal = 0x10</Declaration>
+
+, withSuffix = 1u + 010 //!< b
+// CHECK: <Declaration>withSuffix = 1u + 010</Declaration>
+
+#define ARG(x) x
+, macroArg = ARG(0x1) //!< c
+// CHECK: <Declaration>macroArg = ARG(0x1)</Declaration>
+
+#define MACROCONCAT(x, y) 22##x##y
+, macroConcat = MACROCONCAT(3, 2) //!< d
+// CHECK: <Declaration>macroConcat = MACROCONCAT(3, 2)</Declaration>
+
+#define MACRO(a,n) = 0x##a##n
+, weirdMacros MACRO(2,1) //!< e
+// CHECK: <Declaration>weirdMacros = 33</Declaration>
+
+, floatLiteral = value(0.25e3) //!< f
+// CHECK: <Declaration>floatLiteral = value(0.25e3)</Declaration>
+};
diff --git a/test/Index/complete-access-checks.cpp b/test/Index/complete-access-checks.cpp
index c77a5d656a..7eec41ec56 100644
--- a/test/Index/complete-access-checks.cpp
+++ b/test/Index/complete-access-checks.cpp
@@ -41,12 +41,12 @@ void Y::doSomething() {
// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member1} (37)
// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member2} (37) (inaccessible)
// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member3} (37) (inaccessible)
-// CHECK-SUPER-ACCESS: CXXMethod:{ResultType Y &}{TypedText operator=}{LeftParen (}{Placeholder const Y &}{RightParen )} (34)
-// CHECK-SUPER-ACCESS: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (36)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType Y &}{TypedText operator=}{LeftParen (}{Placeholder const Y &}{RightParen )} (79)
+// CHECK-SUPER-ACCESS: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (81)
// CHECK-SUPER-ACCESS: StructDecl:{TypedText X}{Text ::} (77)
// CHECK-SUPER-ACCESS: StructDecl:{TypedText Y}{Text ::} (75)
-// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )} (36)
-// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Y}{LeftParen (}{RightParen )} (34)
+// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )} (81)
+// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Y}{LeftParen (}{RightParen )} (79)
// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func1}{LeftParen (}{RightParen )} (34)
// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) (inaccessible)
@@ -54,9 +54,9 @@ void Y::doSomething() {
// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member1} (35)
// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member2} (35) (inaccessible)
// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member3} (35) (inaccessible)
-// CHECK-ACCESS: CXXMethod:{ResultType Z &}{TypedText operator=}{LeftParen (}{Placeholder const Z &}{RightParen )} (34)
+// CHECK-ACCESS: CXXMethod:{ResultType Z &}{TypedText operator=}{LeftParen (}{Placeholder const Z &}{RightParen )} (79)
// CHECK-ACCESS: ClassDecl:{TypedText Z}{Text ::} (75)
-// CHECK-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )} (34)
+// CHECK-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )} (79)
class P {
protected:
@@ -76,14 +76,14 @@ void f(P x, Q y) {
}
// CHECK-USING-INACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35) (inaccessible)
-// CHECK-USING-INACCESSIBLE: CXXMethod:{ResultType P &}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (34)
+// CHECK-USING-INACCESSIBLE: CXXMethod:{ResultType P &}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (79)
// CHECK-USING-INACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (75)
-// CHECK-USING-INACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~P}{LeftParen (}{RightParen )} (34)
+// CHECK-USING-INACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~P}{LeftParen (}{RightParen )} (79)
// CHECK-USING-ACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35)
-// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType Q &}{TypedText operator=}{LeftParen (}{Placeholder const Q &}{RightParen )} (34)
-// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType P &}{Text P::}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (36)
+// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType Q &}{TypedText operator=}{LeftParen (}{Placeholder const Q &}{RightParen )} (79)
+// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType P &}{Text P::}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (81)
// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (77)
// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText Q}{Text ::} (75)
-// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{Informative P::}{TypedText ~P}{LeftParen (}{RightParen )} (36)
-// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~Q}{LeftParen (}{RightParen )} (34)
+// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{Informative P::}{TypedText ~P}{LeftParen (}{RightParen )} (81)
+// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~Q}{LeftParen (}{RightParen )} (79)
diff --git a/test/Index/complete-available.m b/test/Index/complete-available.m
new file mode 100644
index 0000000000..6c0a2622be
--- /dev/null
+++ b/test/Index/complete-available.m
@@ -0,0 +1,20 @@
+/* The run lines are below, because this test is line- and
+ column-number sensitive. */
+void atAvailable() {
+ if (@available(macOS 10.10, *)) {
+
+ }
+ if (__builtin_available(iOS 8, *)) {
+ }
+}
+
+// RUN: c-index-test -code-completion-at=%s:4:18 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:7:27 %s | FileCheck %s
+// CHECK: {TypedText iOS} (40)
+// CHECK: {TypedText iOSApplicationExtension} (40)
+// CHECK: {TypedText macOS} (40)
+// CHECK: {TypedText macOSApplicationExtension} (40)
+// CHECK: {TypedText tvOS} (40)
+// CHECK: {TypedText tvOSApplicationExtension} (40)
+// CHECK: {TypedText watchOS} (40)
+// CHECK: {TypedText watchOSApplicationExtension} (40)
diff --git a/test/Index/complete-call.cpp b/test/Index/complete-call.cpp
index 9750bd6f71..ca116485ac 100644
--- a/test/Index/complete-call.cpp
+++ b/test/Index/complete-call.cpp
@@ -94,6 +94,24 @@ int main() {
s.foo_7(42,);
}
+struct Bar {
+ static void foo_1();
+ void foo_1(float);
+ static void foo_1(int);
+};
+
+void test() {
+ Bar::foo_1();
+ Bar b;
+ b.foo_1();
+}
+
+struct Bar2 : public Bar {
+ Bar2() {
+ Bar::foo_1();
+ }
+};
+
// RUN: c-index-test -code-completion-at=%s:47:9 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
// CHECK-CC1: Completion contexts:
@@ -803,3 +821,46 @@ int main() {
// CHECK-CC59-NEXT: Class name
// CHECK-CC59-NEXT: Nested name specifier
// CHECK-CC59-NEXT: Objective-C interface
+
+// RUN: c-index-test -code-completion-at=%s:104:14 %s | FileCheck -check-prefix=CHECK-CC60 %s
+// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
+// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
+// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
+// CHECK-CC60: Completion contexts:
+// CHECK-CC60-NEXT: Any type
+// CHECK-CC60-NEXT: Any value
+// CHECK-CC60-NEXT: Enum tag
+// CHECK-CC60-NEXT: Union tag
+// CHECK-CC60-NEXT: Struct tag
+// CHECK-CC60-NEXT: Class name
+// CHECK-CC60-NEXT: Nested name specifier
+// CHECK-CC60-NEXT: Objective-C interface
+
+// RUN: c-index-test -code-completion-at=%s:106:11 %s | FileCheck -check-prefix=CHECK-CC61 %s
+// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
+// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
+// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
+// CHECK-CC61: Completion contexts:
+// CHECK-CC61-NEXT: Any type
+// CHECK-CC61-NEXT: Any value
+// CHECK-CC61-NEXT: Enum tag
+// CHECK-CC61-NEXT: Union tag
+// CHECK-CC61-NEXT: Struct tag
+// CHECK-CC61-NEXT: Class name
+// CHECK-CC61-NEXT: Nested name specifier
+// CHECK-CC61-NEXT: Objective-C interface
+
+// RUN: c-index-test -code-completion-at=%s:111:16 %s | FileCheck -check-prefix=CHECK-CC62 %s
+// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1)
+// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1)
+// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1)
+// CHECK-CC62: Completion contexts:
+// CHECK-CC62-NEXT: Any type
+// CHECK-CC62-NEXT: Any value
+// CHECK-CC62-NEXT: Enum tag
+// CHECK-CC62-NEXT: Union tag
+// CHECK-CC62-NEXT: Struct tag
+// CHECK-CC62-NEXT: Class name
+// CHECK-CC62-NEXT: Nested name specifier
+// CHECK-CC62-NEXT: Objective-C interface
+
diff --git a/test/Index/complete-constructor-params.cpp b/test/Index/complete-constructor-params.cpp
index 6685626a58..949077a214 100644
--- a/test/Index/complete-constructor-params.cpp
+++ b/test/Index/complete-constructor-params.cpp
@@ -18,6 +18,20 @@ int main() {
int(42);
}
+struct Foo {
+ Foo() = default;
+ Foo(const Foo&) = delete;
+};
+
+struct Bar {
+ Foo f;
+};
+
+void function() {
+ Bar b1;
+ Bar b2(b1);
+}
+
// RUN: c-index-test -code-completion-at=%s:11:10 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: OverloadCandidate:{Text S}{LeftParen (}{CurrentParameter const S<int> &}{RightParen )} (1)
// CHECK-CC1: OverloadCandidate:{Text S}{LeftParen (}{CurrentParameter int}{Comma , }{Placeholder U}{Comma , }{Placeholder U}{RightParen )} (1)
@@ -138,3 +152,6 @@ int main() {
// CHECK-CC10-NEXT: Class name
// CHECK-CC10-NEXT: Nested name specifier
// CHECK-CC10-NEXT: Objective-C interface
+
+// RUN: c-index-test -code-completion-at=%s:32:12 -std=c++11 %s | FileCheck -check-prefix=CHECK-CC11 %s
+// CHECK-CC11-NOT: OverloadCandidate:{Text Bar}{LeftParen (}{CurrentParameter const Bar &}{RightParen )} (1)
diff --git a/test/Index/complete-cxx-inline-methods.cpp b/test/Index/complete-cxx-inline-methods.cpp
index ee359f75e4..c0a4a8d75c 100644
--- a/test/Index/complete-cxx-inline-methods.cpp
+++ b/test/Index/complete-cxx-inline-methods.cpp
@@ -25,11 +25,11 @@ private:
// RUN: c-index-test -code-completion-at=%s:4:9 -std=c++98 %s | FileCheck %s
// RUN: c-index-test -code-completion-at=%s:13:7 -std=c++98 %s | FileCheck %s
-// CHECK: CXXMethod:{ResultType MyCls::Vec &}{TypedText operator=}{LeftParen (}{Placeholder const MyCls::Vec &}{RightParen )} (34)
+// CHECK: CXXMethod:{ResultType MyCls::Vec &}{TypedText operator=}{LeftParen (}{Placeholder const MyCls::Vec &}{RightParen )} (79)
// CHECK-NEXT: StructDecl:{TypedText Vec}{Text ::} (75)
// CHECK-NEXT: FieldDecl:{ResultType int}{TypedText x} (35)
// CHECK-NEXT: FieldDecl:{ResultType int}{TypedText y} (35)
-// CHECK-NEXT: CXXDestructor:{ResultType void}{TypedText ~Vec}{LeftParen (}{RightParen )} (34)
+// CHECK-NEXT: CXXDestructor:{ResultType void}{TypedText ~Vec}{LeftParen (}{RightParen )} (79)
// CHECK-NEXT: Completion contexts:
// CHECK-NEXT: Dot member access
// CHECK-NEXT: Container Kind: StructDecl
diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m
index 8a17142266..f561f81496 100644
--- a/test/Index/complete-method-decls.m
+++ b/test/Index/complete-method-decls.m
@@ -236,3 +236,25 @@ typedef A *MyObjectRef;
// RUN: c-index-test -code-completion-at=%s:107:2 %s -target x86_64-apple-macosx10.7 | FileCheck -check-prefix=CHECK-NULLABILITY2 %s
// CHECK-NULLABILITY2: ObjCInstanceMethodDecl:{LeftParen (}{Text instancetype}{RightParen )}{TypedText getI3} (40)
// CHECK-NULLABILITY2: ObjCInstanceMethodDecl:{LeftParen (}{Text I3 *}{RightParen )}{TypedText produceI3}{TypedText :}{LeftParen (}{Text I3 *}{RightParen )}{Text i3} (40)
+
+@interface CompleteWithoutLeadingPrefix
+
+- (void)aMethod;
++ (int)aClassMethod:(int)x;
+@property int p;
+
+@end
+
+@implementation CompleteWithoutLeadingPrefix
+
+
+
+@end
+
+// RUN: c-index-test -code-completion-at=%s:250:1 %s | FileCheck -check-prefix=CHECK-COMP-NO-PREFIX %s
+// CHECK-COMP-NO-PREFIX: NotImplemented:{TypedText @end} (40)
+// CHECK-COMP-NO-PREFIX: ObjCClassMethodDecl:{Text +}{HorizontalSpace }{LeftParen (}{Text int}{RightParen )}{TypedText aClassMethod}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x} (40)
+// CHECK-COMP-NO-PREFIX: ObjCInstanceMethodDecl:{Text -}{HorizontalSpace }{LeftParen (}{Text void}{RightParen )}{TypedText aMethod} (40)
+// CHECK-COMP-NO-PREFIX: ObjCInterfaceDecl:{TypedText I1}
+// CHECK-COMP-NO-PREFIX: ObjCInstanceMethodDecl:{Text -}{HorizontalSpace }{LeftParen (}{Text int}{RightParen )}{TypedText p} (40)
+// CHECK-COMP-NO-PREFIX: ObjCInstanceMethodDecl:{Text -}{HorizontalSpace }{LeftParen (}{Text void}{RightParen )}{TypedText setP}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text p} (40)
diff --git a/test/Index/complete-optional-params.cpp b/test/Index/complete-optional-params.cpp
index 88d8105024..1df2975300 100644
--- a/test/Index/complete-optional-params.cpp
+++ b/test/Index/complete-optional-params.cpp
@@ -6,15 +6,19 @@ void bar(int a, int b = 42, int c = 42);
void baz(int a = 42, ...);
struct S{ S(int a = 42, int = 42) {} };
+class Bar1 { public: Bar1() {} }; class Bar2;
+void foo_2(Bar1 b1 = Bar1(), Bar2 b2 = Bar2());
+
int main() {
foo(42, 42);
bar(42, 42, 42);
baz(42, 42, 42);
S s(42, 42);
+ foo_2();
}
-// RUN: c-index-test -code-completion-at=%s:10:9 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo}{LeftParen (}{Optional {CurrentParameter int a}{Optional {Comma , }{Placeholder int}}}{RightParen )} (1)
+// RUN: c-index-test -code-completion-at=%s:13:9 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo}{LeftParen (}{Optional {CurrentParameter int a = 42}{Optional {Comma , }{Placeholder int = 42}}}{RightParen )} (1)
// CHECK-CC1: Completion contexts:
// CHECK-CC1-NEXT: Any type
// CHECK-CC1-NEXT: Any value
@@ -25,8 +29,8 @@ int main() {
// CHECK-CC1-NEXT: Nested name specifier
// CHECK-CC1-NEXT: Objective-C interface
-// RUN: c-index-test -code-completion-at=%s:11:9 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{CurrentParameter int a}{Optional {Comma , }{Placeholder int b}{Optional {Comma , }{Placeholder int c}}}{RightParen )} (1)
+// RUN: c-index-test -code-completion-at=%s:14:9 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{CurrentParameter int a}{Optional {Comma , }{Placeholder int b = 42}{Optional {Comma , }{Placeholder int c = 42}}}{RightParen )} (1)
// CHECK-CC2: Completion contexts:
// CHECK-CC2-NEXT: Any type
// CHECK-CC2-NEXT: Any value
@@ -37,8 +41,8 @@ int main() {
// CHECK-CC2-NEXT: Nested name specifier
// CHECK-CC2-NEXT: Objective-C interface
-// RUN: c-index-test -code-completion-at=%s:11:16 %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{Placeholder int a}{Optional {Comma , }{Placeholder int b}{Optional {Comma , }{CurrentParameter int c}}}{RightParen )} (1)
+// RUN: c-index-test -code-completion-at=%s:14:16 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: OverloadCandidate:{ResultType void}{Text bar}{LeftParen (}{Placeholder int a}{Optional {Comma , }{Placeholder int b = 42}{Optional {Comma , }{CurrentParameter int c = 42}}}{RightParen )} (1)
// CHECK-CC3: Completion contexts:
// CHECK-CC3-NEXT: Any type
// CHECK-CC3-NEXT: Any value
@@ -49,8 +53,8 @@ int main() {
// CHECK-CC3-NEXT: Nested name specifier
// CHECK-CC3-NEXT: Objective-C interface
-// RUN: c-index-test -code-completion-at=%s:12:16 %s | FileCheck -check-prefix=CHECK-CC4 %s
-// CHECK-CC4: OverloadCandidate:{ResultType void}{Text baz}{LeftParen (}{Optional {Placeholder int a}{Optional {Comma , }{CurrentParameter ...}}}{RightParen )} (1)
+// RUN: c-index-test -code-completion-at=%s:15:16 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: OverloadCandidate:{ResultType void}{Text baz}{LeftParen (}{Optional {Placeholder int a = 42}{Optional {Comma , }{CurrentParameter ...}}}{RightParen )} (1)
// CHECK-CC4: Completion contexts:
// CHECK-CC4-NEXT: Any type
// CHECK-CC4-NEXT: Any value
@@ -61,8 +65,8 @@ int main() {
// CHECK-CC4-NEXT: Nested name specifier
// CHECK-CC4-NEXT: Objective-C interface
-// RUN: c-index-test -code-completion-at=%s:13:9 %s | FileCheck -check-prefix=CHECK-CC5 %s
-// CHECK-CC5: OverloadCandidate:{Text S}{LeftParen (}{Optional {CurrentParameter int a}{Optional {Comma , }{Placeholder int}}}{RightParen )} (1)
+// RUN: c-index-test -code-completion-at=%s:16:9 %s | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5: OverloadCandidate:{Text S}{LeftParen (}{Optional {CurrentParameter int a = 42}{Optional {Comma , }{Placeholder int = 42}}}{RightParen )} (1)
// CHECK-CC5: OverloadCandidate:{Text S}{LeftParen (}{CurrentParameter const S &}{RightParen )} (1)
// CHECK-CC5: Completion contexts:
// CHECK-CC5-NEXT: Any type
@@ -73,3 +77,15 @@ int main() {
// CHECK-CC5-NEXT: Class name
// CHECK-CC5-NEXT: Nested name specifier
// CHECK-CC5-NEXT: Objective-C interface
+
+// RUN: c-index-test -code-completion-at=%s:17:11 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-CC6: FunctionDecl:{ResultType void}{TypedText foo_2}{LeftParen (}{Optional {Placeholder Bar1 b1 = Bar1()}{Optional {Comma , }{Placeholder Bar2 b2}}}{RightParen )} (50)
+// CHECK-CC6: Completion contexts:
+// CHECK-CC6-NEXT: Any type
+// CHECK-CC6-NEXT: Any value
+// CHECK-CC6-NEXT: Enum tag
+// CHECK-CC6-NEXT: Union tag
+// CHECK-CC6-NEXT: Struct tag
+// CHECK-CC6-NEXT: Class name
+// CHECK-CC6-NEXT: Nested name specifier
+// CHECK-CC6-NEXT: Objective-C interface
diff --git a/test/Index/complete-qualified.cpp b/test/Index/complete-qualified.cpp
index a17ea25370..11abd53b86 100644
--- a/test/Index/complete-qualified.cpp
+++ b/test/Index/complete-qualified.cpp
@@ -17,4 +17,4 @@ void foo()
// CHECK-CC1: FieldDecl:{ResultType C<Foo, class Bar>}{TypedText c} (35)
// CHECK-CC1: ClassDecl:{TypedText Foo} (35)
// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )}
-// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (35)
+// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (80)
diff --git a/test/Index/complete-super.cpp b/test/Index/complete-super.cpp
index 9ffa7c8a40..92d3f7f585 100644
--- a/test/Index/complete-super.cpp
+++ b/test/Index/complete-super.cpp
@@ -40,3 +40,8 @@ void B::bar(float real) {
// CHECK-ACCESS-PATTERN: NotImplemented:{TypedText private}{Colon :} (40)
// CHECK-ACCESS-PATTERN: NotImplemented:{TypedText protected}{Colon :} (40)
// CHECK-ACCESS-PATTERN: NotImplemented:{TypedText public}{Colon :} (40)
+
+// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:10:12 %s | FileCheck -check-prefix=CHECK-INHERITANCE-PATTERN %s
+// CHECK-INHERITANCE-PATTERN: NotImplemented:{TypedText private} (40)
+// CHECK-INHERITANCE-PATTERN: NotImplemented:{TypedText protected} (40)
+// CHECK-INHERITANCE-PATTERN: NotImplemented:{TypedText public} (40)
diff --git a/test/Index/complete-with-annotations.cpp b/test/Index/complete-with-annotations.cpp
index afa8d9ed66..7bad8f1b7c 100644
--- a/test/Index/complete-with-annotations.cpp
+++ b/test/Index/complete-with-annotations.cpp
@@ -17,7 +17,7 @@ void X::doSomething() {
// CHECK: FieldDecl:{ResultType int}{TypedText field} (35) ("three", "two", "one")
// CHECK: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) ("some annotation")
// CHECK: FieldDecl:{ResultType int}{TypedText member2} (35) ("another annotation", "some annotation")
-// CHECK: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (34)
+// CHECK: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (79)
// CHECK: ClassDecl:{TypedText X}{Text ::} (75)
-// CHECK: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (34)
+// CHECK: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (79)
diff --git a/test/Index/crash-recovery-code-complete.c b/test/Index/crash-recovery-code-complete.c
index b2a1a9b3f9..dfb47316dc 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 3e7e8059aa..296416df97 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 baa6604b53..2e4b51a8ca 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 e8e84bc504..bf13c69eb1 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/ctor-init-source-loc.cpp b/test/Index/ctor-init-source-loc.cpp
new file mode 100644
index 0000000000..ff93e58092
--- /dev/null
+++ b/test/Index/ctor-init-source-loc.cpp
@@ -0,0 +1,117 @@
+// RUN: c-index-test -test-load-source all %s -fno-delayed-template-parsing | FileCheck %s
+template<typename MyBase>
+struct Derived: MyBase::InnerIterator
+{
+ Derived() : MyBase::InnerIterator() {}
+// CHECK: TypeRef=MyBase:2:19 Extent=[5:17 - 5:23]
+};
+
+template<typename MyBase>
+struct Derived2: MyBase::Deeper::InnerIterator
+{
+ Derived2() : MyBase::Deeper::InnerIterator() {}
+// CHECK: TypeRef=MyBase:9:19 Extent=[12:18 - 12:24]
+};
+
+template<typename Q>
+struct Templ;
+
+template<typename MyBase>
+struct Derived3: Templ<MyBase>::InnerIterator
+{
+ Derived3() : Templ<MyBase>::InnerIterator() {}
+// CHECK: TemplateRef=Templ:17:8 Extent=[22:18 - 22:23]
+// CHECK: TypeRef=MyBase:19:19 Extent=[22:24 - 22:30]
+};
+
+
+struct Outer {
+ template <typename Q>
+ struct Inner {
+ typedef Q Parm;
+ };
+};
+
+template<typename Q>
+struct Derived4: Outer::Inner<Q>::Parm
+{
+ Derived4() : Outer::Inner<Q>::Parm() {}
+// CHECK: TypeRef=struct Outer:28:8 Extent=[38:18 - 38:23]
+// CHECK: TemplateRef=Inner:30:12 Extent=[38:25 - 38:30]
+// CHECK: TypeRef=Q:35:19 Extent=[38:31 - 38:32]
+};
+
+template<typename Q>
+struct Derived5: Outer::Inner<Q>::Parm::InnerIterator
+{
+ Derived5() : Outer::Inner<Q>::Parm::InnerIterator() {}
+// CHECK: TypeRef=struct Outer:28:8 Extent=[47:18 - 47:23]
+// CHECK: TemplateRef=Inner:30:12 Extent=[47:25 - 47:30]
+// CHECK: TypeRef=Q:44:19 Extent=[47:31 - 47:32]
+};
+
+template<typename Q>
+struct Derived6: Outer::Inner<Q>
+{
+ Derived6() : Outer::Inner<Q>() {}
+// CHECK: TypeRef=struct Outer:28:8 Extent=[56:18 - 56:23]
+// CHECK: TemplateRef=Inner:30:12 Extent=[56:25 - 56:30]
+// CHECK: TypeRef=Q:53:19 Extent=[56:31 - 56:32]
+};
+
+struct Base {};
+
+struct Derived7: Outer::Inner<Base>::Parm
+{
+ Derived7() : Outer::Inner<Base>::Parm() {}
+// CHECK: TypeRef=struct Outer:28:8 Extent=[66:18 - 66:23]
+// CHECK: TemplateRef=Inner:30:12 Extent=[66:25 - 66:30]
+// CHECK: TypeRef=struct Base:62:8 Extent=[66:31 - 66:35]
+};
+
+struct Derived8: Outer::Inner<Base>
+{
+ Derived8() : Outer::Inner<Base>() {}
+// CHECK: TypeRef=struct Outer:28:8 Extent=[74:18 - 74:23]
+// CHECK: TemplateRef=Inner:30:12 Extent=[74:25 - 74:30]
+// CHECK: TypeRef=struct Base:62:8 Extent=[74:31 - 74:35]
+};
+
+namespace Namespace {
+ template<typename Q> struct Templ;
+
+ struct Outer {
+ template <typename Q>
+ struct Inner {
+ typedef Q Parm;
+ };
+ };
+}
+
+template<typename MyBase>
+struct Derived9: Namespace::Templ<MyBase>::InnerIterator
+{
+ Derived9() : Namespace::Templ<MyBase>::InnerIterator() {}
+// CHECK: NamespaceRef=Namespace:80:11 Extent=[94:18 - 94:27]
+// CHECK: TemplateRef=Templ:81:33 Extent=[94:29 - 94:34]
+// CHECK: TypeRef=MyBase:91:19 Extent=[94:35 - 94:41]
+};
+
+template<typename MyBase>
+struct Derived10: Namespace::Templ<MyBase>
+{
+ Derived10() : Namespace::Templ<MyBase>() {}
+// CHECK: NamespaceRef=Namespace:80:11 Extent=[103:19 - 103:28]
+// CHECK: TemplateRef=Templ:81:33 Extent=[103:30 - 103:35]
+// CHECK: TypeRef=MyBase:100:19 Extent=[103:36 - 103:42]
+};
+
+template<typename MyBase>
+struct Derived11: Namespace::Outer::Inner<MyBase>::Parm
+{
+ Derived11() : Namespace::Outer::Inner<MyBase>::Parm() {}
+// CHECK: NamespaceRef=Namespace:80:11 Extent=[112:19 - 112:28]
+// CHECK: TypeRef=struct Namespace::Outer:83:12 Extent=[112:30 - 112:35]
+// CHECK: TemplateRef=Inner:85:16 Extent=[112:37 - 112:42]
+// CHECK: TypeRef=MyBase:109:19 Extent=[112:43 - 112:49]
+};
diff --git a/test/Index/cursor-dynamic-call.mm b/test/Index/cursor-dynamic-call.mm
index a926c3d03d..33d1c68558 100644
--- a/test/Index/cursor-dynamic-call.mm
+++ b/test/Index/cursor-dynamic-call.mm
@@ -49,6 +49,14 @@ void test2() {
id o = [[Test alloc] init];
}
+@interface Test2 : NSObject
+@property (assign) id someProp;
+@end
+
+void test3(Test2 *o) {
+ id v = o.someProp;
+}
+
// RUN: c-index-test -cursor-at=%s:8:11 \
// RUN: -cursor-at=%s:9:11 \
// RUN: -cursor-at=%s:25:11 \
@@ -59,6 +67,7 @@ void test2() {
// RUN: -cursor-at=%s:36:9 \
// RUN: -cursor-at=%s:37:9 \
// RUN: -cursor-at=%s:49:26 \
+// RUN: -cursor-at=%s:57:12 \
// RUN: %s | FileCheck %s
// CHECK: 8:11 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call
@@ -67,9 +76,10 @@ void test2() {
// CHECK-NOT: 26:3 {{.*}} Dynamic-call
// CHECK-NOT: 29:3 {{.*}} Dynamic-call
// CHECK: 29:3 {{.*}} Receiver-type=ObjCInterface
-// CHECK: 34:7 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call
+// CHECK: 34:7 MemberRefExpr=meth:3:16 {{.*}} Dynamic-call Receiver-type=Pointer
// CHECK: 35:3 ObjCMessageExpr=meth:14:8 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer
// CHECK-NOT: 36:3 {{.*}} Dynamic-call
// CHECK: 36:3 {{.*}} Receiver-type=ObjCInterface
// CHECK: 37:3 ObjCMessageExpr=ClsMeth:15:8 {{.*}} Dynamic-call Receiver-type=ObjCClass
// CHECK-NOT: 49:10 {{.*}} Dynamic-call
+// CHECK: 57:12 MemberRefExpr=someProp:53:23 {{.*}} Dynamic-call Receiver-type=ObjCObjectPointer
diff --git a/test/Index/get-cursor.cpp b/test/Index/get-cursor.cpp
index 27f75938fe..8aa12d5bc3 100644
--- a/test/Index/get-cursor.cpp
+++ b/test/Index/get-cursor.cpp
@@ -145,6 +145,13 @@ void test(TestColl coll) {
const int operator""_toint(unsigned long long val) { return int(val); }
+// noexcept specifications
+void f_noexcept() noexcept;
+template <class T> void f_computed_noexcept(T t) noexcept(noexcept(t+t));
+void f_dynamic_noexcept_none() throw();
+void f_dynamic_noexcept() throw(int);
+void f_dynamic_noexcept_any() throw(...);
+
// RUN: c-index-test -cursor-at=%s:6:4 %s | FileCheck -check-prefix=CHECK-COMPLETION-1 %s
// CHECK-COMPLETION-1: CXXConstructor=X:6:3
// CHECK-COMPLETION-1-NEXT: Completion string: {TypedText X}{LeftParen (}{Placeholder int}{Comma , }{Placeholder int}{RightParen )}
@@ -209,11 +216,11 @@ const int operator""_toint(unsigned long long val) { return int(val); }
// RUN: c-index-test -cursor-at=%s:66:23 %s | FileCheck -check-prefix=CHECK-TEMPLSPEC %s
// CHECK-TEMPLSPEC: 66:23 ClassDecl=TC:66:23 (Definition) [Specialization of TC:59:7] Extent=[66:1 - 66:31] Spelling=TC ([66:23 - 66:25])
-// RUN: c-index-test -cursor-at=%s:69:3 -cursor-at=%s:70:11 -cursor-at=%s:73:6 -cursor-at=%s:74:6 -cursor-at=%s:77:8 -cursor-at=%s:78:8 -cursor-at=%s:79:8 -cursor-at=%s:80:8 -cursor-at=%s:81:8 -cursor-at=%s:82:8 -cursor-at=%s:85:6 -cursor-at=%s:86:6 -cursor-at=%s:87:6 -cursor-at=%s:88:6 -cursor-at=%s:91:5 -cursor-at=%s:92:5 -cursor-at=%s:93:5 -cursor-at=%s:94:5 -cursor-at=%s:95:5 -cursor-at=%s:96:5 -cursor-at=%s:97:5 -cursor-at=%s:98:5 -cursor-at=%s:100:5 -cursor-at=%s:101:5 -cursor-at=%s:104:6 -cursor-at=%s:105:6 -cursor-at=%s:106:6 -cursor-at=%s:107:6 -cursor-at=%s:108:6 -cursor-at=%s:109:6 -cursor-at=%s:110:6 -cursor-at=%s:111:6 -cursor-at=%s:113:6 -cursor-at=%s:114:6 -cursor-at=%s:117:8 -cursor-at=%s:118:8 -cursor-at=%s:120:8 -cursor-at=%s:121:8 -cursor-at=%s:122:8 -cursor-at=%s:123:8 -cursor-at=%s:124:8 -cursor-at=%s:125:8 -cursor-at=%s:128:6 -cursor-at=%s:129:6 -cursor-at=%s:130:6 -cursor-at=%s:132:3 -cursor-at=%s:146:15 -std=c++11 %s | FileCheck -check-prefix=CHECK-SPELLING %s
+// RUN: c-index-test -cursor-at=%s:69:3 -cursor-at=%s:70:11 -cursor-at=%s:73:6 -cursor-at=%s:74:6 -cursor-at=%s:77:8 -cursor-at=%s:78:8 -cursor-at=%s:79:8 -cursor-at=%s:80:8 -cursor-at=%s:81:8 -cursor-at=%s:82:8 -cursor-at=%s:85:6 -cursor-at=%s:86:6 -cursor-at=%s:87:6 -cursor-at=%s:88:6 -cursor-at=%s:91:5 -cursor-at=%s:92:5 -cursor-at=%s:93:5 -cursor-at=%s:94:5 -cursor-at=%s:95:5 -cursor-at=%s:96:5 -cursor-at=%s:97:5 -cursor-at=%s:98:5 -cursor-at=%s:100:5 -cursor-at=%s:101:5 -cursor-at=%s:104:6 -cursor-at=%s:105:6 -cursor-at=%s:106:6 -cursor-at=%s:107:6 -cursor-at=%s:108:6 -cursor-at=%s:109:6 -cursor-at=%s:110:6 -cursor-at=%s:111:6 -cursor-at=%s:113:6 -cursor-at=%s:114:6 -cursor-at=%s:117:8 -cursor-at=%s:118:8 -cursor-at=%s:120:8 -cursor-at=%s:121:8 -cursor-at=%s:122:8 -cursor-at=%s:123:8 -cursor-at=%s:124:8 -cursor-at=%s:125:8 -cursor-at=%s:128:6 -cursor-at=%s:129:6 -cursor-at=%s:130:6 -cursor-at=%s:132:3 -cursor-at=%s:146:15 -cursor-at=%s:149:6 -cursor-at=%s:150:25 -cursor-at=%s:151:6 -cursor-at=%s:152:6 -cursor-at=%s:153:6 -std=c++11 %s | FileCheck -check-prefix=CHECK-SPELLING %s
// CHECK-SPELLING: 69:3 CXXConstructor=A:69:3 (default constructor) Extent=[69:3 - 69:6] Spelling=A ([69:3 - 69:4])
// CHECK-SPELLING: 70:11 CXXDestructor=~A:70:11 (virtual) Extent=[70:3 - 70:15] Spelling=~A ([70:11 - 70:13])
// CHECK-SPELLING: 73:6 CXXMethod=operator=:73:6 Extent=[73:3 - 73:25] Spelling=operator= ([73:6 - 73:15])
-// CHECK-SPELLING: 74:6 CXXMethod=operator=:74:6 Extent=[74:3 - 74:29] Spelling=operator= ([74:6 - 74:15])
+// CHECK-SPELLING: 74:6 CXXMethod=operator=:74:6 (noexcept) Extent=[74:3 - 74:29] Spelling=operator= ([74:6 - 74:15])
// CHECK-SPELLING: 77:8 CXXMethod=operator+:77:8 (const) Extent=[77:3 - 77:25] Spelling=operator+ ([77:8 - 77:17])
// CHECK-SPELLING: 78:8 CXXMethod=operator-:78:8 (const) Extent=[78:3 - 78:25] Spelling=operator- ([78:8 - 78:17])
// CHECK-SPELLING: 79:8 CXXMethod=operator~:79:8 (const) Extent=[79:3 - 79:25] Spelling=operator~ ([79:8 - 79:17])
@@ -257,8 +264,14 @@ const int operator""_toint(unsigned long long val) { return int(val); }
// CHECK-SPELLING: 130:6 CXXMethod=operator():130:6 (const) Extent=[130:3 - 130:37] Spelling=operator() ([130:6 - 130:16])
// CHECK-SPELLING: 132:12 CXXConversion=operator bool:132:12 (const) Extent=[132:3 - 132:33] Spelling=operator bool ([132:12 - 132:25])
// CHECK-SPELLING: 146:11 FunctionDecl=operator""_toint:146:11 (Definition) Extent=[146:1 - 146:72] Spelling=operator""_toint ([146:11 - 146:27])
+// CHECK-SPELLING: 149:6 FunctionDecl=f_noexcept:149:6 (noexcept) Extent=[149:1 - 149:27] Spelling=f_noexcept ([149:6 - 149:16])
+// CHECK-SPELLING: 150:25 FunctionTemplate=f_computed_noexcept:150:25 (computed-noexcept) Extent=[150:1 - 150:73] Spelling=f_computed_noexcept ([150:25 - 150:44])
+// CHECK-SPELLING: 151:6 FunctionDecl=f_dynamic_noexcept_none:151:6 (noexcept dynamic none) Extent=[151:1 - 151:39] Spelling=f_dynamic_noexcept_none ([151:6 - 151:29])
+// CHECK-SPELLING: 152:6 FunctionDecl=f_dynamic_noexcept:152:6 (noexcept dynamic) Extent=[152:1 - 152:37] Spelling=f_dynamic_noexcept ([152:6 - 152:24])
+// CHECK-SPELLING: 153:6 FunctionDecl=f_dynamic_noexcept_any:153:6 (noexcept dynamic any) Extent=[153:1 - 153:41] Spelling=f_dynamic_noexcept_any ([153:6 - 153:28])
// RUN: c-index-test -cursor-at=%s:141:13 -cursor-at=%s:141:18 -cursor-at=%s:142:11 -std=c++11 %s | FileCheck -check-prefix=CHECK-FORRANGE %s
// CHECK-FORRANGE: 141:13 VarDecl=lv:141:13 (Definition) Extent=[141:8 - 141:17] Spelling=lv ([141:13 - 141:15])
// CHECK-FORRANGE: 141:18 DeclRefExpr=coll:140:20 Extent=[141:18 - 141:22] Spelling=coll ([141:18 - 141:22])
// CHECK-FORRANGE: 142:11 DeclRefExpr=lv:141:13 Extent=[142:11 - 142:13] Spelling=lv ([142:11 - 142:13])
+
diff --git a/test/Index/get-cursor.m b/test/Index/get-cursor.m
index d321233401..e85d49fb0c 100644
--- a/test/Index/get-cursor.m
+++ b/test/Index/get-cursor.m
@@ -129,6 +129,37 @@ 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;
+
+#define GEN_DECL(mod_name) __attribute__((external_source_symbol(language="Swift", defined_in=mod_name, generated_declaration)))
+
+GEN_DECL("some_module")
+@interface ExtCls
+-(void)method;
+@end
// 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 +224,16 @@ 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])
+
+// RUN: c-index-test -cursor-at=%s:160:12 -cursor-at=%s:161:8 %s | FileCheck -check-prefix=CHECK-EXTERNAL %s
+// CHECK-EXTERNAL: 160:12 ObjCInterfaceDecl=ExtCls:160:12 (external lang: Swift, defined: some_module, gen: 1)
+// CHECK-EXTERNAL: 161:8 ObjCInstanceMethodDecl=method:161:8 (external lang: Swift, defined: some_module, gen: 1)
+C \ No newline at end of file
diff --git a/test/Index/index-attrs.c b/test/Index/index-attrs.c
index d526721f5b..a1f1c37fae 100644
--- a/test/Index/index-attrs.c
+++ b/test/Index/index-attrs.c
@@ -1,16 +1,16 @@
-// RUN: c-index-test -index-file -check-prefix CHECK %s -target armv7-windows-gnu -fdeclspec
+// RUN: c-index-test -index-file %s -target armv7-windows-gnu -fdeclspec 2>&1 | FileCheck %s
void __declspec(dllexport) export_function(void) {}
-// CHECK: [indexDeclaraton]: kind: function | name: export_function | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: export_function | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllexport)
void __attribute__((dllexport)) export_gnu_attribute(void) {}
-// CHECK: [indexDeclaration] kind: function | name: export_gnu_attribute | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: export_gnu_attribute | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllexport)
void __declspec(dllimport) import_function(void);
-// CHECK: [indexDeclaration] kind: function | name: import_function | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: import_function | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllimport)
void __attribute__((dllimport)) import_gnu_attribute(void);
-// CHECK: [indexDeclaration] kind: function | name: import_gnu_function | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: import_gnu_attribute | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllimport)
diff --git a/test/Index/index-attrs.cpp b/test/Index/index-attrs.cpp
index b6100acf88..0758a422ca 100644
--- a/test/Index/index-attrs.cpp
+++ b/test/Index/index-attrs.cpp
@@ -1,4 +1,4 @@
-// RUN: c-index-test -index-file -check-prefix CHECK %s -target armv7-windows-gnu -fdeclspec
+// RUN: c-index-test -index-file %s -target armv7-windows-gnu -fdeclspec | FileCheck %s
struct __declspec(dllexport) export_s {
void m();
@@ -19,7 +19,7 @@ struct __declspec(dllimport) import_s {
class __attribute__((dllexport)) export_gnu_s {
void m();
};
-// CHECK: [indexDeclaration]: kind: struct | name: export_gnu_s | {{.*}} | lang: C++
+// CHECK: [indexDeclaration]: kind: c++-class | name: export_gnu_s | {{.*}} | lang: C++
// CHECK: <attribute>: attribute(dllexport)
// CHECK: [indexDeclaration]: kind: c++-instance-method | name: m | {{.*}} | lang: C++
// CHECK: <attribute>: attribute(dllexport)
@@ -27,24 +27,24 @@ class __attribute__((dllexport)) export_gnu_s {
class __attribute__((dllimport)) import_gnu_s {
void m();
};
-// CHECK: [indexDeclaration]: kind: struct | name: import_gnu_s | {{.*}} | lang: C++
+// CHECK: [indexDeclaration]: kind: c++-class | name: import_gnu_s | {{.*}} | lang: C++
// CHECK: <attribute>: attribute(dllimport)
// CHECK: [indexDeclaration]: kind: c++-instance-method | name: m | {{.*}} | lang: C++
// CHECK: <attribute>: attribute(dllimport)
extern "C" void __declspec(dllexport) export_function(void) {}
-// CHECK: [indexDeclaraton]: kind: function | name: export_function | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: export_function | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllexport)
extern "C" void __attribute__((dllexport)) export_gnu_function(void) {}
-// CHECK: [indexDeclaraton]: kind: function | name: export_gnu_function | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: export_gnu_function | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllexport)
extern "C" {
void __declspec(dllimport) import_function(void);
-// CHECK: [indexDeclaration] kind: function | name: import_function | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: import_function | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllimport)
void __attribute__((dllimport)) import_gnu_function(void);
-// CHECK: [indexDeclaration] kind: function | name: import_gnu_function | {{.*}} | lang: C
+// CHECK: [indexDeclaration]: kind: function | name: import_gnu_function | {{.*}} | lang: C
// CHECK: <attribute>: attribute(dllimport)
}
diff --git a/test/Index/index-module.m b/test/Index/index-module.m
index 51faea2d32..c6387fe867 100644
--- a/test/Index/index-module.m
+++ b/test/Index/index-module.m
@@ -27,8 +27,9 @@ int glob;
// CHECK-DMOD-NEXT: [ppIncludedFile]: {{.*}}/Modules/Inputs/Module.framework{{[/\\]}}Headers{{[/\\]}}Module.h | name: "Module/Module.h" | hash loc: {{.*}}/Modules/Inputs/DependsOnModule.framework{{[/\\]}}Headers{{[/\\]}}DependsOnModule.h:1:1 | isImport: 0 | isAngled: 1 | isModule: 1 | module: Module
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_OTHER_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]other\.h]] | {{.*}} | hash loc: <invalid> | {{.*}} | module: DependsOnModule
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_NOT_CXX_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]not_cxx\.h]] | {{.*}} | hash loc: <invalid> | {{.*}} | module: DependsOnModule.NotCXX
+// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_NOT_CORO_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Headers[/\\]not_coroutines\.h]] | {{.*}} | hash loc: <invalid> | {{.*}} | module: DependsOnModule.NotCoroutines
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_H:.*/Modules/Inputs/DependsOnModule\.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]SubFramework\.h]] | {{.*}} | hash loc: <invalid> | {{.*}} | module: DependsOnModule.SubFramework
-// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_OTHER_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]Frameworks/SubFramework\.framework/Headers/Other\.h]] | name: "SubFramework/Other.h" | hash loc: [[DMOD_SUB_H]]:1:1 | isImport: 0 | isAngled: 0 | isModule: 0 | module: DependsOnModule.SubFramework.Other
+// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_SUB_OTHER_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]Frameworks[/\\]SubFramework\.framework[/\\]Headers[/\\]Other\.h]] | name: "SubFramework/Other.h" | hash loc: [[DMOD_SUB_H]]:1:1 | isImport: 0 | isAngled: 0 | isModule: 0 | module: DependsOnModule.SubFramework.Other
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_PRIVATE_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]PrivateHeaders[/\\]DependsOnModulePrivate.h]] | {{.*}} | hash loc: <invalid> | {{.*}} | module: DependsOnModule.Private.DependsOnModule
// CHECK-DMOD-NEXT: [importedASTFile]: {{.*}}.cache{{(.sys)?[/\\]}}Module.pcm | loc: [[DMOD_MODULE_H]]:1:1 | name: "Module" | isImplicit: 1
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: depends_on_module_other | {{.*}} | loc: [[DMOD_OTHER_H]]:1:5
diff --git a/test/Index/index-pch.cpp b/test/Index/index-pch.cpp
index caab2d7f97..e86e446ef0 100644
--- a/test/Index/index-pch.cpp
+++ b/test/Index/index-pch.cpp
@@ -1,4 +1,4 @@
-// RUN: c-index-test -write-pch %t.pch -fshort-wchar %s
+// RUN: c-index-test -write-pch %t.pch -fwchar-type=short -fno-signed-wchar %s
// RUN: env LIBCLANG_NOTHREADS=1 c-index-test -index-tu %t.pch | FileCheck %s
// CHECK: [indexDeclaration]: kind: variable | name: wideStr
diff --git a/test/Index/index-refs.cpp b/test/Index/index-refs.cpp
index 5a1ba1e8b4..d8bede0b47 100644
--- a/test/Index/index-refs.cpp
+++ b/test/Index/index-refs.cpp
@@ -105,6 +105,7 @@ int ginitlist[] = {EnumVal};
// CHECK: [indexDeclaration]: kind: c++-class-template | name: TS | {{.*}} | loc: 47:8
// CHECK-NEXT: [indexDeclaration]: kind: struct-template-partial-spec | name: TS | USR: c:@SP>1#T@TS>#t0.0#I | {{.*}} | loc: 50:8
// CHECK-NEXT: [indexDeclaration]: kind: typedef | name: MyInt | USR: c:index-refs.cpp@SP>1#T@TS>#t0.0#I@T@MyInt | {{.*}} | loc: 51:15 | semantic-container: [TS:50:8] | lexical-container: [TS:50:8]
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class-template | name: TS | USR: c:@ST>2#T#T@TS | lang: C++ | cursor: TemplateRef=TS:47:8 | loc: 50:8 | <parent>:: <<NULL>> | container: [TU] | refkind: direct
/* when indexing implicit instantiations
[indexDeclaration]: kind: struct-template-spec | name: TS | USR: c:@S@TS>#I | {{.*}} | loc: 50:8
[indexDeclaration]: kind: typedef | name: MyInt | USR: c:index-refs.cpp@593@S@TS>#I@T@MyInt | {{.*}} | loc: 51:15 | semantic-container: [TS:50:8] | lexical-container: [TS:50:8]
diff --git a/test/Index/index-template-template-param.cpp b/test/Index/index-template-template-param.cpp
new file mode 100644
index 0000000000..af1c4634ad
--- /dev/null
+++ b/test/Index/index-template-template-param.cpp
@@ -0,0 +1,7 @@
+// RUN: c-index-test -index-file %s -x objective-c++ | FileCheck %s
+
+template <typename T> class Template1 {};
+
+template <template <class> class TMPL = Template1> class Template2;
+
+// CHECK: [indexEntityReference]: kind: c++-class-template | name: Template1 |
diff --git a/test/Index/index-templates.cpp b/test/Index/index-templates.cpp
index 966cc4f5ea..424a638ffb 100644
--- a/test/Index/index-templates.cpp
+++ b/test/Index/index-templates.cpp
@@ -219,6 +219,6 @@ using alias = T;
// CHECK-USRS: index-templates.cpp c:@ST>2#T#T@Y Extent=[27:1 - 31:2]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@443 Extent=[27:10 - 27:20]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@455 Extent=[27:22 - 27:32]
-// CHECK-USRS-NOT: type
+// CHECK-USRS: index-templates.cpp c:index-templates.cpp@ST>2#T#T@Y@UUT@T::type Extent=[29:3 - 29:25]
// CHECK-USRS: index-templates.cpp c:@S@Z3 Extent=[33:1 - 33:14]
// CHECK-USRS: index-templates.cpp c:@F@f#$@S@map>#$@S@Z4#$@S@Pair>#I#S1_#$@S@compare>#$@S@Pair>#S1_#S2_#$@S@allocator>#S4_#
diff --git a/test/Index/keep-going.cpp b/test/Index/keep-going.cpp
index 82987c6cf1..dbfcad32d3 100644
--- a/test/Index/keep-going.cpp
+++ b/test/Index/keep-going.cpp
@@ -25,5 +25,5 @@ class C : public A<float> { };
// CHECK: C++ base class specifier=A<float>:4:7 [access=public isVirtual=false] [type=A<float>] [typekind=Unexposed] [templateargs/1= [type=float] [typekind=Float]] [canonicaltype=A<float>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=float] [typekind=Float]] [isPOD=0] [nbFields=1]
// CHECK: TemplateRef=A:4:7 [type=] [typekind=Invalid] [isPOD=0]
-// CHECK-DIAG: keep-going.cpp:1:10: error: 'missing1.h' file not found
-// CHECK-DIAG: keep-going.cpp:8:10: error: 'missing2.h' file not found
+// CHECK-DIAG: keep-going.cpp:1:10: fatal error: 'missing1.h' file not found
+// CHECK-DIAG: keep-going.cpp:8:10: fatal error: 'missing2.h' file not found
diff --git a/test/Index/linkage.c b/test/Index/linkage.c
index ab006590b6..b0dcb30990 100644
--- a/test/Index/linkage.c
+++ b/test/Index/linkage.c
@@ -20,7 +20,7 @@ void f16(void) {
// CHECK: EnumDecl=Baz:3:6 (Definition)linkage=External
-// CHECK: EnumConstantDecl=Qux:3:12 (Definition)linkage=External
+// CHECK: EnumConstantDecl=Qux:3:12 (Definition)linkage=NoLinkage
// CHECK: VarDecl=x:4:5linkage=External
// CHECK: FunctionDecl=foo:5:6linkage=External
// CHECK: VarDecl=w:6:12linkage=Internal
diff --git a/test/Index/opencl-types.cl b/test/Index/opencl-types.cl
index f15bc745a8..fe0042aa20 100644
--- a/test/Index/opencl-types.cl
+++ b/test/Index/opencl-types.cl
@@ -1,4 +1,4 @@
-// RUN: c-index-test -test-print-type %s | FileCheck %s
+// RUN: c-index-test -test-print-type %s -cl-std=CL2.0 | FileCheck %s
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
@@ -22,3 +22,105 @@ void kernel testFloatTypes() {
// 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]
+
+#pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable
+
+void kernel OCLImage1dROTest(read_only image1d_t scalarOCLImage1dRO);
+void kernel OCLImage1dArrayROTest(read_only image1d_array_t scalarOCLImage1dArrayRO);
+void kernel OCLImage1dBufferROTest(read_only image1d_buffer_t scalarOCLImage1dBufferRO);
+void kernel OCLImage2dROTest(read_only image2d_t scalarOCLImage2dRO);
+void kernel OCLImage2dArrayROTest(read_only image2d_array_t scalarOCLImage2dArrayRO);
+void kernel OCLImage2dDepthROTest(read_only image2d_depth_t scalarOCLImage2dDepthRO);
+void kernel OCLImage2dArrayDepthROTest(read_only image2d_array_depth_t scalarOCLImage2dArrayDepthRO);
+void kernel OCLImage2dMSAAROTest(read_only image2d_msaa_t scalarOCLImage2dMSAARO);
+void kernel OCLImage2dArrayMSAAROTest(read_only image2d_array_msaa_t scalarOCLImage2dArrayMSAARO);
+void kernel OCLImage2dMSAADepthROTest(read_only image2d_msaa_depth_t scalarOCLImage2dMSAADepthRO);
+void kernel OCLImage2dArrayMSAADepthROTest(read_only image2d_array_msaa_depth_t scalarOCLImage2dArrayMSAADepthRO);
+void kernel OCLImage3dROTest(read_only image3d_t scalarOCLImage3dRO);
+
+// CHECK: ParmDecl=scalarOCLImage1dRO:28:50 (Definition) [type=__read_only image1d_t] [typekind=OCLImage1dRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage1dArrayRO:29:61 (Definition) [type=__read_only image1d_array_t] [typekind=OCLImage1dArrayRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage1dBufferRO:30:63 (Definition) [type=__read_only image1d_buffer_t] [typekind=OCLImage1dBufferRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dRO:31:50 (Definition) [type=__read_only image2d_t] [typekind=OCLImage2dRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayRO:32:61 (Definition) [type=__read_only image2d_array_t] [typekind=OCLImage2dArrayRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dDepthRO:33:61 (Definition) [type=__read_only image2d_depth_t] [typekind=OCLImage2dDepthRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayDepthRO:34:72 (Definition) [type=__read_only image2d_array_depth_t] [typekind=OCLImage2dArrayDepthRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAARO:35:59 (Definition) [type=__read_only image2d_msaa_t] [typekind=OCLImage2dMSAARO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAARO:36:70 (Definition) [type=__read_only image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAARO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAADepthRO:37:70 (Definition) [type=__read_only image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthRO:38:81 (Definition) [type=__read_only image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthRO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage3dRO:39:50 (Definition) [type=__read_only image3d_t] [typekind=OCLImage3dRO] [isPOD=1]
+
+void kernel OCLImage1dWOTest(write_only image1d_t scalarOCLImage1dWO);
+void kernel OCLImage1dArrayWOTest(write_only image1d_array_t scalarOCLImage1dArrayWO);
+void kernel OCLImage1dBufferWOTest(write_only image1d_buffer_t scalarOCLImage1dBufferWO);
+void kernel OCLImage2dWOTest(write_only image2d_t scalarOCLImage2dWO);
+void kernel OCLImage2dArrayWOTest(write_only image2d_array_t scalarOCLImage2dArrayWO);
+void kernel OCLImage2dDepthWOTest(write_only image2d_depth_t scalarOCLImage2dDepthWO);
+void kernel OCLImage2dArrayDepthWOTest(write_only image2d_array_depth_t scalarOCLImage2dArrayDepthWO);
+void kernel OCLImage2dMSAAWOTest(write_only image2d_msaa_t scalarOCLImage2dMSAAWO);
+void kernel OCLImage2dArrayMSAAWOTest(write_only image2d_array_msaa_t scalarOCLImage2dArrayMSAAWO);
+void kernel OCLImage2dMSAADepthWOTest(write_only image2d_msaa_depth_t scalarOCLImage2dMSAADepthWO);
+void kernel OCLImage2dArrayMSAADepthWOTest(write_only image2d_array_msaa_depth_t scalarOCLImage2dArrayMSAADepthWO);
+void kernel OCLImage3dWOTest(write_only image3d_t scalarOCLImage3dWO);
+
+// CHECK: ParmDecl=scalarOCLImage1dWO:54:51 (Definition) [type=__write_only image1d_t] [typekind=OCLImage1dWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage1dArrayWO:55:62 (Definition) [type=__write_only image1d_array_t] [typekind=OCLImage1dArrayWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage1dBufferWO:56:64 (Definition) [type=__write_only image1d_buffer_t] [typekind=OCLImage1dBufferWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dWO:57:51 (Definition) [type=__write_only image2d_t] [typekind=OCLImage2dWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayWO:58:62 (Definition) [type=__write_only image2d_array_t] [typekind=OCLImage2dArrayWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dDepthWO:59:62 (Definition) [type=__write_only image2d_depth_t] [typekind=OCLImage2dDepthWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayDepthWO:60:73 (Definition) [type=__write_only image2d_array_depth_t] [typekind=OCLImage2dArrayDepthWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAAWO:61:60 (Definition) [type=__write_only image2d_msaa_t] [typekind=OCLImage2dMSAAWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAAWO:62:71 (Definition) [type=__write_only image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAAWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAADepthWO:63:71 (Definition) [type=__write_only image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthWO:64:82 (Definition) [type=__write_only image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthWO] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage3dWO:65:51 (Definition) [type=__write_only image3d_t] [typekind=OCLImage3dWO] [isPOD=1]
+
+void kernel OCLImage1dRWTest(read_write image1d_t scalarOCLImage1dRW);
+void kernel OCLImage1dArrayRWTest(read_write image1d_array_t scalarOCLImage1dArrayRW);
+void kernel OCLImage1dBufferRWTest(read_write image1d_buffer_t scalarOCLImage1dBufferRW);
+void kernel OCLImage2dRWTest(read_write image2d_t scalarOCLImage2dRW);
+void kernel OCLImage2dArrayRWTest(read_write image2d_array_t scalarOCLImage2dArrayRW);
+void kernel OCLImage2dDepthRWTest(read_write image2d_depth_t scalarOCLImage2dDepthRW);
+void kernel OCLImage2dArrayDepthRWTest(read_write image2d_array_depth_t scalarOCLImage2dArrayDepthRW);
+void kernel OCLImage2dMSAARWTest(read_write image2d_msaa_t scalarOCLImage2dMSAARW);
+void kernel OCLImage2dArrayMSAARWTest(read_write image2d_array_msaa_t scalarOCLImage2dArrayMSAARW);
+void kernel OCLImage2dMSAADepthRWTest(read_write image2d_msaa_depth_t scalarOCLImage2dMSAADepthRW);
+void kernel OCLImage2dArrayMSAADepthRWTest(read_write image2d_array_msaa_depth_t scalarOCLImage2dArrayMSAADepthRW);
+void kernel OCLImage3dRWTest(read_write image3d_t scalarOCLImage3dRW);
+
+// CHECK: ParmDecl=scalarOCLImage1dRW:80:51 (Definition) [type=__read_write image1d_t] [typekind=OCLImage1dRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage1dArrayRW:81:62 (Definition) [type=__read_write image1d_array_t] [typekind=OCLImage1dArrayRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage1dBufferRW:82:64 (Definition) [type=__read_write image1d_buffer_t] [typekind=OCLImage1dBufferRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dRW:83:51 (Definition) [type=__read_write image2d_t] [typekind=OCLImage2dRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayRW:84:62 (Definition) [type=__read_write image2d_array_t] [typekind=OCLImage2dArrayRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dDepthRW:85:62 (Definition) [type=__read_write image2d_depth_t] [typekind=OCLImage2dDepthRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayDepthRW:86:73 (Definition) [type=__read_write image2d_array_depth_t] [typekind=OCLImage2dArrayDepthRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAARW:87:60 (Definition) [type=__read_write image2d_msaa_t] [typekind=OCLImage2dMSAARW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAARW:88:71 (Definition) [type=__read_write image2d_array_msaa_t] [typekind=OCLImage2dArrayMSAARW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dMSAADepthRW:89:71 (Definition) [type=__read_write image2d_msaa_depth_t] [typekind=OCLImage2dMSAADepthRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage2dArrayMSAADepthRW:90:82 (Definition) [type=__read_write image2d_array_msaa_depth_t] [typekind=OCLImage2dArrayMSAADepthRW] [isPOD=1]
+// CHECK: ParmDecl=scalarOCLImage3dRW:91:51 (Definition) [type=__read_write image3d_t] [typekind=OCLImage3dRW] [isPOD=1]
+
+void kernel intPipeTestRO(read_only pipe int scalarPipe);
+void kernel intPipeTestWO(write_only pipe int scalarPipe);
+
+// CHECK: ParmDecl=scalarPipe:106:46 (Definition) [type=read_only pipe int] [typekind=Pipe] [isPOD=0]
+// CHECK: ParmDecl=scalarPipe:107:47 (Definition) [type=write_only pipe int] [typekind=Pipe] [isPOD=0]
+
+#define CLK_ADDRESS_CLAMP_TO_EDGE 2
+#define CLK_NORMALIZED_COORDS_TRUE 1
+#define CLK_FILTER_NEAREST 0x10
+
+void kernel testMiscOpenCLTypes() {
+ const sampler_t scalarOCLSampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;
+ clk_event_t scalarOCLEvent;
+ queue_t scalarOCLQueue;
+ reserve_id_t scalarOCLReserveID;
+}
+
+// CHECK: VarDecl=scalarOCLSampler:117:19 (Definition) [type=const sampler_t] [typekind=Typedef] const [canonicaltype=const sampler_t] [canonicaltypekind=OCLSampler] [isPOD=1]
+// CHECK: VarDecl=scalarOCLEvent:118:15 (Definition) [type=clk_event_t] [typekind=Typedef] [canonicaltype=clk_event_t] [canonicaltypekind=Unexposed] [isPOD=1]
+// CHECK: VarDecl=scalarOCLQueue:119:11 (Definition) [type=queue_t] [typekind=Typedef] [canonicaltype=queue_t] [canonicaltypekind=OCLQueue] [isPOD=1]
+// CHECK: VarDecl=scalarOCLReserveID:120:16 (Definition) [type=reserve_id_t] [typekind=Typedef] [canonicaltype=reserve_id_t] [canonicaltypekind=OCLReserveID] [isPOD=1]
diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm
index d995e0eca7..824d055b16 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/pipe-size.cl b/test/Index/pipe-size.cl
new file mode 100644
index 0000000000..cfe97935ee
--- /dev/null
+++ b/test/Index/pipe-size.cl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -x cl -O0 -cl-std=CL2.0 -emit-llvm -triple x86_64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefix=X86
+// RUN: %clang_cc1 -x cl -O0 -cl-std=CL2.0 -emit-llvm -triple spir-unknown-unknown %s -o - | FileCheck %s --check-prefix=SPIR
+// RUN: %clang_cc1 -x cl -O0 -cl-std=CL2.0 -emit-llvm -triple spir64-unknown-unknown %s -o - | FileCheck %s --check-prefix=SPIR64
+// RUN: %clang_cc1 -x cl -O0 -cl-std=CL2.0 -emit-llvm -triple amdgcn-amd-amdhsa-amdgizcl %s -o - | FileCheck %s --check-prefix=AMD
+__kernel void testPipe( pipe int test )
+{
+ int s = sizeof(test);
+ // X86: store %opencl.pipe_t* %test, %opencl.pipe_t** %test.addr, align 8
+ // X86: store i32 8, i32* %s, align 4
+ // SPIR: store %opencl.pipe_t addrspace(1)* %test, %opencl.pipe_t addrspace(1)** %test.addr, align 4
+ // SPIR: store i32 4, i32* %s, align 4
+ // SPIR64: store %opencl.pipe_t addrspace(1)* %test, %opencl.pipe_t addrspace(1)** %test.addr, align 8
+ // SPIR64: store i32 8, i32* %s, align 4
+ // AMD: store %opencl.pipe_t addrspace(1)* %test, %opencl.pipe_t addrspace(1)* addrspace(5)* %test.addr, align 8
+ // AMD: store i32 8, i32 addrspace(5)* %s, align 4
+}
diff --git a/test/Index/preamble-conditionals-crash.cpp b/test/Index/preamble-conditionals-crash.cpp
new file mode 100644
index 0000000000..6b18c87d19
--- /dev/null
+++ b/test/Index/preamble-conditionals-crash.cpp
@@ -0,0 +1,12 @@
+#ifndef HEADER_GUARD
+
+#define FOO int aba;
+FOO
+
+#endif
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 \
+// RUN: local -std=c++14 %s 2>&1 \
+// RUN: | FileCheck %s --implicit-check-not "libclang: crash detected" \
+// RUN: --implicit-check-not "error:"
+// CHECK: macro expansion=FOO:3:9 Extent=[4:1 - 4:4]
+// CHECK: VarDecl=aba:4:1 (Definition) Extent=[4:1 - 4:4]
diff --git a/test/Index/preamble-conditionals-inverted-with-error.cpp b/test/Index/preamble-conditionals-inverted-with-error.cpp
new file mode 100644
index 0000000000..95b0695b87
--- /dev/null
+++ b/test/Index/preamble-conditionals-inverted-with-error.cpp
@@ -0,0 +1,8 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 \
+// RUN: local -std=c++14 %s 2>&1 \
+// RUN: | FileCheck %s
+#ifdef FOO_H
+
+void foo();
+
+// CHECK: preamble-conditionals-inverted-with-error.cpp:4:2: error: unterminated conditional directive
diff --git a/test/Index/preamble-conditionals-inverted.cpp b/test/Index/preamble-conditionals-inverted.cpp
new file mode 100644
index 0000000000..1d67ccb61a
--- /dev/null
+++ b/test/Index/preamble-conditionals-inverted.cpp
@@ -0,0 +1,8 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 \
+// RUN: local -std=c++14 %s 2>&1 \
+// RUN: | FileCheck %s --implicit-check-not "error:"
+#ifdef FOO_H
+
+void foo();
+
+#endif
diff --git a/test/Index/preamble-conditionals.cpp b/test/Index/preamble-conditionals.cpp
new file mode 100644
index 0000000000..81ef8265e8
--- /dev/null
+++ b/test/Index/preamble-conditionals.cpp
@@ -0,0 +1,8 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source local %s 2>&1 \
+// RUN: | FileCheck %s --implicit-check-not "error:"
+#ifndef FOO_H
+#define FOO_H
+
+void foo();
+
+#endif
diff --git a/test/Index/print-objc-manglings.m b/test/Index/print-objc-manglings.m
new file mode 100644
index 0000000000..1e7983ec61
--- /dev/null
+++ b/test/Index/print-objc-manglings.m
@@ -0,0 +1,18 @@
+// RUN: c-index-test -write-pch %t.macho.ast -target i686-apple-darwin %s
+// RUN: c-index-test -test-print-manglings %t.macho.ast | FileCheck --check-prefix=MACHO %s
+
+// RUN: c-index-test -write-pch %t.itanium.ast -target i686-pc-linux-gnu %s
+// RUN: c-index-test -test-print-manglings %t.itanium.ast | FileCheck --check-prefix=ITANIUM %s
+
+@interface C
+@end
+
+// MACHO: ObjCInterfaceDecl=C{{.*}} [mangled=_OBJC_CLASS_$_C] [mangled=_OBJC_METACLASS_$_C]
+// ITANIUM: ObjCInterfaceDecl=C{{.*}} [mangled=_OBJC_CLASS_C] [mangled=_OBJC_METACLASS_C]
+
+@implementation C
+@end
+
+// MACHO: ObjCImplementationDecl=C{{.*}} (Definition) [mangled=_OBJC_CLASS_$_C] [mangled=_OBJC_METACLASS_$_C]
+// ITANIUM: ObjCImplementationDecl=C{{.*}} (Definition) [mangled=_OBJC_CLASS_C] [mangled=_OBJC_METACLASS_C]
+
diff --git a/test/Index/print-type-declaration.cpp b/test/Index/print-type-declaration.cpp
index 31c0a73fcd..a0953d1e56 100644
--- a/test/Index/print-type-declaration.cpp
+++ b/test/Index/print-type-declaration.cpp
@@ -7,6 +7,13 @@ int main()
auto b = a;
}
+enum RegularEnum {};
+
+enum class ScopedEnum {};
+
// RUN: c-index-test -test-print-type-declaration -std=c++11 %s | FileCheck %s
// CHECK: VarDecl=a:6:8 (Definition) [typedeclaration=Test] [typekind=Record]
// CHECK: VarDecl=b:7:8 (Definition) [typedeclaration=Test] [typekind=Record]
+// CHECK: EnumDecl=RegularEnum:10:6 (Definition) [typedeclaration=RegularEnum] [typekind=Enum]
+// CHECK: EnumDecl=ScopedEnum:12:12 (Definition) (scoped) [typedeclaration=ScopedEnum] [typekind=Enum]
+
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
index 108ba53c80..e152a7ed3d 100644
--- a/test/Index/print-type.cpp
+++ b/test/Index/print-type.cpp
@@ -71,6 +71,10 @@ struct Specialization<int>;
Specialization<Specialization<bool>& > templRefParam;
auto autoTemplRefParam = templRefParam;
+template<typename T> struct A {};
+template<typename T> using C = T;
+using baz = C<A<void>>;
+
// RUN: c-index-test -test-print-type %s -std=c++14 | FileCheck %s
// CHECK: Namespace=outer:1:11 (Definition) [type=] [typekind=Invalid] [isPOD=0]
// CHECK: ClassTemplate=Foo:4:8 (Definition) [type=] [typekind=Invalid] [isPOD=0]
@@ -177,3 +181,4 @@ auto autoTemplRefParam = templRefParam;
// 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]
+// CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A<void>] [typekind=Unexposed]] [canonicaltype=A<void>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0]
diff --git a/test/Index/read-empty-diags.test b/test/Index/read-empty-diags.test
new file mode 100644
index 0000000000..cef751c920
--- /dev/null
+++ b/test/Index/read-empty-diags.test
@@ -0,0 +1,2 @@
+// RUN: not c-index-test -read-diagnostics %S/Inputs/empty.dia 2>&1 | FileCheck %s
+// CHECK: Trouble deserializing file (Invalid File): Invalid diagnostics signature
diff --git a/test/Index/recover-bad-code-rdar_7487294.c b/test/Index/recover-bad-code-rdar_7487294.c
index c2803006ac..bbbc035a0a 100644
--- a/test/Index/recover-bad-code-rdar_7487294.c
+++ b/test/Index/recover-bad-code-rdar_7487294.c
@@ -1,4 +1,4 @@
-// RUN: not %clang-cc1 -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
// IMPORTANT: This test case intentionally DOES NOT use --disable-free. It
// tests that we are properly reclaiming the ASTs and we do not have a double free.
diff --git a/test/Index/single-file-parse.m b/test/Index/single-file-parse.m
new file mode 100644
index 0000000000..f75b9bd0ee
--- /dev/null
+++ b/test/Index/single-file-parse.m
@@ -0,0 +1,121 @@
+// RUN: c-index-test -single-file-parse %s | FileCheck %s
+
+#include <stdint.h>
+
+// CHECK-NOT: TypedefDecl=intptr_t
+
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=MyCls
+@interface MyCls
+// CHECK: [[@LINE+1]]:8: ObjCInstanceMethodDecl=some_meth
+-(void)some_meth;
+@end
+
+#if 1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test1
+@interface Test1 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test2 @end
+#endif
+
+#if 0
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test3 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test4
+@interface Test4 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test5
+@interface Test5 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test6
+@interface Test6 @end
+#endif
+
+#define SOMETHING_DEFINED 1
+#if SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test7
+@interface Test7 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test8 @end
+#endif
+
+#if defined(SOMETHING_NOT_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test9
+@interface Test9 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test10
+@interface Test10 @end
+#endif
+
+#if defined(SOMETHING_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test11
+@interface Test11 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test12 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test13
+@interface Test13 @end
+#elif SOMETHING_NOT_DEFINED2
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test14
+@interface Test14 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test15
+@interface Test15 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test19
+@interface Test19 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test20
+@interface Test20 @end
+#endif
+
+#ifdef SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test21
+@interface Test21 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test22 @end
+#endif
+
+#ifndef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test23
+@interface Test23 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test24
+@interface Test24 @end
+#endif
+
+#ifndef SOMETHING_DEFINED
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test25 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test26
+@interface Test26 @end
+#endif
+
+#if 1 < SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test27
+@interface Test27 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test28
+@interface Test28 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test29
+@interface Test29 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test30
+@interface Test30 @end
+#endif
diff --git a/test/Index/skipped-ranges.c b/test/Index/skipped-ranges.c
index bd16fb3856..f6c6c7f638 100644
--- a/test/Index/skipped-ranges.c
+++ b/test/Index/skipped-ranges.c
@@ -20,6 +20,6 @@ int probably_hot = 1;
#endif // cool
// RUN: env CINDEXTEST_SHOW_SKIPPED_RANGES=1 c-index-test -test-annotate-tokens=%s:1:1:16:1 %s | FileCheck %s
-// CHECK: Skipping: [5:2 - 6:7]
-// CHECK: Skipping: [8:2 - 12:7]
-// CHECK: Skipping: [14:2 - 20:7]
+// CHECK: Skipping: [5:1 - 6:7]
+// CHECK: Skipping: [8:1 - 12:7]
+// CHECK: Skipping: [14:1 - 20:7]
diff --git a/test/Index/target-info.c b/test/Index/target-info.c
new file mode 100644
index 0000000000..98a3ca32b5
--- /dev/null
+++ b/test/Index/target-info.c
@@ -0,0 +1,6 @@
+// RUN: c-index-test -test-print-target-info %s --target=i386-unknown-linux-gnu | FileCheck %s
+// RUN: c-index-test -test-print-target-info %s --target=x86_64-unknown-linux-gnu | FileCheck --check-prefix=CHECK-1 %s
+// CHECK: TargetTriple: i386-unknown-linux-gnu
+// CHECK: PointerWidth: 32
+// CHECK-1: TargetTriple: x86_64-unknown-linux-gnu
+// CHECK-1: PointerWidth: 64
diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp
index 8ad17021b5..2bd5744371 100644
--- a/test/Index/usrs.cpp
+++ b/test/Index/usrs.cpp
@@ -95,6 +95,14 @@ class TC1 {
void meth(TC1);
};
+typedef __attribute__((__ext_vector_type__(3))) float float3;
+
+typedef float __m128 __attribute__((__vector_size__(16)));
+
+float3 vectorOverload(float3 f);
+
+__m128 vectorOverload(__m128 f);
+
// RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %s | FileCheck %s
// CHECK: usrs.cpp c:@N@foo Extent=[1:1 - 4:2]
// CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8]
@@ -172,3 +180,6 @@ class TC1 {
// CHECK: usrs.cpp c:usrs.cpp@S@usrs.cpp@1510@FI@x Extent=[91:10 - 91:15]
// CHECK: usrs.cpp c:@ST>1#T@TC1@F@meth#>@ST>1#T@TC11t0.0# Extent=[95:3 - 95:17]
+
+// CHECK: usrs.cpp c:@F@vectorOverload#]3f# Extent=[102:1 - 102:32]
+// CHECK: usrs.cpp c:@F@vectorOverload#[4f# Extent=[104:1 - 104:32]
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index 92c3a3fafe..d0a860e1af 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -119,7 +119,7 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:@SA@MyStruct Extent=[15:9 - 18:2]
// CHECK: usrs.m c:@SA@MyStruct@FI@wa Extent=[16:3 - 16:9]
// CHECK: usrs.m c:@SA@MyStruct@FI@moo Extent=[17:3 - 17:10]
-// CHECK: usrs.m c:usrs.m@T@MyStruct Extent=[15:1 - 18:11]
+// CHECK: usrs.m c:@T@MyStruct Extent=[15:1 - 18:11]
// CHECK: usrs.m c:@E@Pizza Extent=[20:1 - 23:2]
// CHECK: usrs.m c:@E@Pizza@CHEESE Extent=[21:3 - 21:9]
// CHECK: usrs.m c:@E@Pizza@MUSHROOMS Extent=[22:3 - 22:12]
diff --git a/test/Integration/carbon.c b/test/Integration/carbon.c
index 0498116dd1..3cae391226 100644
--- a/test/Integration/carbon.c
+++ b/test/Integration/carbon.c
@@ -1,4 +1,5 @@
// RUN: %clang -fsyntax-only %s
+// REQUIRES: macos-sdk-10.12
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#endif
diff --git a/test/Integration/cocoa-pch.m b/test/Integration/cocoa-pch.m
index 0159b32014..fa3ccea378 100644
--- a/test/Integration/cocoa-pch.m
+++ b/test/Integration/cocoa-pch.m
@@ -1,6 +1,7 @@
// RUN: %clang -arch x86_64 -x objective-c-header %s -o %t.h.pch
// RUN: touch %t.empty.m
// RUN: %clang -arch x86_64 -fsyntax-only %t.empty.m -include %t.h -Xclang -ast-dump 2>&1 > /dev/null
+// REQUIRES: macos-sdk-10.12
#ifdef __APPLE__
#include <Cocoa/Cocoa.h>
#endif
diff --git a/test/Integration/cocoa.m b/test/Integration/cocoa.m
index d814b3ee21..91d8682508 100644
--- a/test/Integration/cocoa.m
+++ b/test/Integration/cocoa.m
@@ -1,4 +1,5 @@
// RUN: %clang -arch x86_64 %s -fsyntax-only -Xclang -print-stats
+// REQUIRES: macos-sdk-10.12
#ifdef __APPLE__
#include <Cocoa/Cocoa.h>
#endif
diff --git a/test/Integration/thinlto_profile_sample_accurate.c b/test/Integration/thinlto_profile_sample_accurate.c
new file mode 100644
index 0000000000..ac7274cee2
--- /dev/null
+++ b/test/Integration/thinlto_profile_sample_accurate.c
@@ -0,0 +1,9 @@
+// Test to ensure -emit-llvm profile-sample-accurate is honored in ThinLTO.
+// RUN: %clang -O2 %s -flto=thin -fprofile-sample-accurate -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
+
+// CHECK: define{{.*}} void @foo()
+// CHECK: attributes{{.*}} "profile-sample-accurate"
+void foo() {
+}
diff --git a/test/Lexer/asm-preproc-no-unicode.s b/test/Lexer/asm-preproc-no-unicode.s
new file mode 100644
index 0000000000..d194a52fec
--- /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-ms.c b/test/Lexer/case-insensitive-include-ms.c
index 86bd8bba68..a7101544fe 100644
--- a/test/Lexer/case-insensitive-include-ms.c
+++ b/test/Lexer/case-insensitive-include-ms.c
@@ -1,10 +1,10 @@
// REQUIRES: case-insensitive-filesystem
-// RUN: mkdir -p %T/apath
-// RUN: cp %S/Inputs/case-insensitive-include.h %T
-// RUN: cd %T
-// RUN: %clang_cc1 -fsyntax-only -fms-compatibility %s -include %s -I %T -verify
-// RUN: %clang_cc1 -fsyntax-only -fms-compatibility -fdiagnostics-parseable-fixits %s -include %s -I %T 2>&1 | FileCheck %s
+// RUN: mkdir -p %t/Output/apath
+// RUN: cp %S/Inputs/case-insensitive-include.h %t/Output
+// RUN: cd %t/Output
+// RUN: %clang_cc1 -fsyntax-only -fms-compatibility %s -include %s -I %t/Output -verify
+// RUN: %clang_cc1 -fsyntax-only -fms-compatibility -fdiagnostics-parseable-fixits %s -include %s -I %t/Output 2>&1 | FileCheck %s
#include "..\Output\.\case-insensitive-include.h"
#include "..\Output\.\Case-Insensitive-Include.h" // expected-warning {{non-portable path}}
diff --git a/test/Lexer/case-insensitive-include-pr31836.sh b/test/Lexer/case-insensitive-include-pr31836.sh
index a419f26faf..e842badc7f 100644
--- a/test/Lexer/case-insensitive-include-pr31836.sh
+++ b/test/Lexer/case-insensitive-include-pr31836.sh
@@ -1,9 +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
+// 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/case-insensitive-include.c b/test/Lexer/case-insensitive-include.c
index 13e5b59942..099555de5f 100644
--- a/test/Lexer/case-insensitive-include.c
+++ b/test/Lexer/case-insensitive-include.c
@@ -1,12 +1,12 @@
// REQUIRES: case-insensitive-filesystem
-// RUN: mkdir -p %T/apath
-// RUN: mkdir -p %T/asystempath
-// RUN: cp %S/Inputs/case-insensitive-include.h %T
-// RUN: cp %S/Inputs/case-insensitive-include.h %T/asystempath/case-insensitive-include2.h
-// RUN: cd %T
-// RUN: %clang_cc1 -fsyntax-only %s -include %s -I %T -isystem %T/asystempath -verify
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s -include %s -I %T -isystem %T/asystempath 2>&1 | FileCheck %s
+// RUN: mkdir -p %t/Output/apath
+// RUN: mkdir -p %t/Output/asystempath
+// RUN: cp %S/Inputs/case-insensitive-include.h %t/Output
+// RUN: cp %S/Inputs/case-insensitive-include.h %t/Output/asystempath/case-insensitive-include2.h
+// RUN: cd %t/Output
+// RUN: %clang_cc1 -fsyntax-only %s -include %s -I %t/Output -isystem %t/Output/asystempath -verify
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s -include %s -I %t/Output -isystem %t/Output/asystempath 2>&1 | FileCheck %s
// Known standard header, so warn:
#include <StdDef.h> // expected-warning {{non-portable path}}
diff --git a/test/Lexer/case-insensitive-system-include.c b/test/Lexer/case-insensitive-system-include.c
index 9d5289cda2..20e0fc6456 100644
--- a/test/Lexer/case-insensitive-system-include.c
+++ b/test/Lexer/case-insensitive-system-include.c
@@ -1,10 +1,10 @@
// REQUIRES: case-insensitive-filesystem
-// RUN: mkdir -p %T/asystempath
-// RUN: cp %S/Inputs/case-insensitive-include.h %T/asystempath/
-// RUN: cd %T
-// RUN: %clang_cc1 -fsyntax-only %s -include %s -isystem %T/asystempath -verify -Wnonportable-system-include-path
-// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s -include %s -isystem %T/asystempath -Wnonportable-system-include-path 2>&1 | FileCheck %s
+// RUN: mkdir -p %t/asystempath
+// RUN: cp %S/Inputs/case-insensitive-include.h %t/asystempath/
+// RUN: cd %t
+// RUN: %clang_cc1 -fsyntax-only %s -include %s -isystem %t/asystempath -verify -Wnonportable-system-include-path
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s -include %s -isystem %t/asystempath -Wnonportable-system-include-path 2>&1 | FileCheck %s
#include "CASE-INSENSITIVE-INCLUDE.H" // expected-warning {{non-portable path}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:38}:"\"case-insensitive-include.h\""
diff --git a/test/Lexer/cxx-features.cpp b/test/Lexer/cxx-features.cpp
index d69ef08a59..04821bdb22 100644
--- a/test/Lexer/cxx-features.cpp
+++ b/test/Lexer/cxx-features.cpp
@@ -4,7 +4,7 @@
// RUN: %clang_cc1 -std=c++14 -fcxx-exceptions -fsized-deallocation -verify %s
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fsized-deallocation -verify %s
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fsized-deallocation -fconcepts-ts -DCONCEPTS_TS=1 -verify %s
-// RUN: %clang_cc1 -fno-rtti -verify %s -DNO_EXCEPTIONS -DNO_RTTI
+// RUN: %clang_cc1 -fno-rtti -fno-threadsafe-statics -verify %s -DNO_EXCEPTIONS -DNO_RTTI -DNO_THREADSAFE_STATICS
// RUN: %clang_cc1 -fcoroutines-ts -DNO_EXCEPTIONS -DCOROUTINES -verify %s
// expected-no-diagnostics
@@ -22,19 +22,15 @@
// --- C++17 features ---
-#if check(variadic_using, 0, 0, 0, 201611) // FIXME: provisional name
-#error "wrong value for __cpp_variadic_using"
-#endif
-
#if check(hex_float, 0, 0, 0, 201603)
#error "wrong value for __cpp_hex_float"
#endif
-#if check(inline_variables, 0, 0, 0, 201606) // FIXME: provisional name
+#if check(inline_variables, 0, 0, 0, 201606)
#error "wrong value for __cpp_inline_variables"
#endif
-#if check(aligned_new, 0, 0, 0, 201606) // FIXME: provisional name
+#if check(aligned_new, 0, 0, 0, 201606)
#error "wrong value for __cpp_aligned_new"
#endif
@@ -52,7 +48,7 @@
// constexpr checked below
-#if check(if_constexpr, 0, 0, 0, 201606) // FIXME: provisional name
+#if check(if_constexpr, 0, 0, 0, 201606)
#error "wrong value for __cpp_if_constexpr"
#endif
@@ -60,7 +56,11 @@
// static_assert checked below
-#if check(template_auto, 0, 0, 0, 201606) // FIXME: provisional name
+#if check(deduction_guides, 0, 0, 0, 201611)
+#error "wrong value for __cpp_deduction_guides"
+#endif
+
+#if check(template_auto, 0, 0, 0, 201606)
#error "wrong value for __cpp_template_auto"
#endif
@@ -80,6 +80,10 @@
// inheriting_constructors checked below
+#if check(variadic_using, 0, 0, 0, 201611)
+#error "wrong value for __cpp_variadic_using"
+#endif
+
#if check(aggregate_bases, 0, 0, 0, 201603)
#error "wrong value for __cpp_aggregate_bases"
#endif
@@ -96,10 +100,6 @@
#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)
@@ -163,6 +163,10 @@
#error "wrong value for __cpp_user_defined_literals"
#endif
+#if defined(NO_THREADSAFE_STATICS) ? check(threadsafe_static_init, 0, 0, 0, 0) : check(threadsafe_static_init, 200806, 200806, 200806, 200806)
+#error "wrong value for __cpp_threadsafe_static_init"
+#endif
+
#if check(lambdas, 0, 200907, 200907, 200907)
#error "wrong value for __cpp_lambdas"
#endif
@@ -235,6 +239,6 @@
#error "wrong value for __cpp_experimental_concepts"
#endif
-#if (COROUTINES && !__cpp_coroutines) || (!COROUTINES && __cpp_coroutines)
+#if defined(COROUTINES) ? check(coroutines, 201703L, 201703L, 201703L, 201703L) : check(coroutines, 0, 0, 0, 0)
#error "wrong value for __cpp_coroutines"
#endif
diff --git a/test/Lexer/cxx1z-trigraphs.cpp b/test/Lexer/cxx1z-trigraphs.cpp
index 0ea2adbe1e..08c45e51f8 100644
--- a/test/Lexer/cxx1z-trigraphs.cpp
+++ b/test/Lexer/cxx1z-trigraphs.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -std=c++1z %s -verify
-// RUN: %clang_cc1 -std=c++1z %s -ftrigraphs -fsyntax-only
+// RUN: %clang_cc1 -std=c++1z %s -ftrigraphs -fsyntax-only 2>&1 | FileCheck --check-prefix=TRIGRAPHS %s
??= define foo ; // expected-error {{}} expected-warning {{trigraph ignored}}
@@ -7,3 +7,8 @@ static_assert("??="[0] == '#', ""); // expected-error {{failed}} expected-warnin
// ??/
error here; // expected-error {{}}
+
+// Note, there is intentionally trailing whitespace two lines below.
+// TRIGRAPHS: :[[@LINE+1]]:{{.*}} backslash and newline separated by space
+// ??/
+error here; // expected-error {{}}
diff --git a/test/Lexer/cxx2a_keyword_as_cxx17.cpp b/test/Lexer/cxx2a_keyword_as_cxx17.cpp
new file mode 100644
index 0000000000..c6a821be0e
--- /dev/null
+++ b/test/Lexer/cxx2a_keyword_as_cxx17.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wc++2a-compat -std=c++17
+
+#define concept constexpr bool
+template<typename T>
+concept x = 0;
+#undef concept
+
+int concept = 0; // expected-warning {{'concept' is a keyword in C++2a}}
+int requires = 0; // expected-warning {{'requires' is a keyword in C++2a}}
diff --git a/test/Lexer/half-literal.cpp b/test/Lexer/half-literal.cpp
index 32af3faef9..b87eae4a15 100644
--- a/test/Lexer/half-literal.cpp
+++ b/test/Lexer/half-literal.cpp
@@ -1,3 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
float a = 1.0h; // expected-error{{invalid suffix 'h' on floating constant}}
float b = 1.0H; // expected-error{{invalid suffix 'H' on floating constant}}
+
+_Float16 c = 1.f166; // expected-error{{invalid suffix 'f166' on floating constant}}
+_Float16 d = 1.f1; // expected-error{{invalid suffix 'f1' on floating constant}}
diff --git a/test/Lexer/hexfloat.cpp b/test/Lexer/hexfloat.cpp
index 163db72f56..3241751a12 100644
--- a/test/Lexer/hexfloat.cpp
+++ b/test/Lexer/hexfloat.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify -pedantic %s
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -pedantic %s
double e = 0x.p0; // expected-error-re {{hexadecimal floating {{constant|literal}} requires a significand}}
float f = 0x1p+1;
@@ -9,10 +9,10 @@ double d = 0x.2p2;
float g = 0x1.2p2;
double h = 0x1.p2;
#if __cplusplus <= 201402L
-// expected-warning@-5 {{hexadecimal floating literals are a C++1z feature}}
-// expected-warning@-5 {{hexadecimal floating literals are a C++1z feature}}
-// expected-warning@-5 {{hexadecimal floating literals are a C++1z feature}}
-// expected-warning@-5 {{hexadecimal floating literals are a C++1z feature}}
+// expected-warning@-5 {{hexadecimal floating literals are a C++17 feature}}
+// expected-warning@-5 {{hexadecimal floating literals are a C++17 feature}}
+// expected-warning@-5 {{hexadecimal floating literals are a C++17 feature}}
+// expected-warning@-5 {{hexadecimal floating literals are a C++17 feature}}
#endif
// PR12717: In order to minimally diverge from the C++ standard, we do not lex
diff --git a/test/Lexer/keywords_test.cpp b/test/Lexer/keywords_test.cpp
index aba8d023c7..e7edf96d93 100644
--- a/test/Lexer/keywords_test.cpp
+++ b/test/Lexer/keywords_test.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -std=c++03 -fsyntax-only %s
// RUN: %clang_cc1 -std=c++11 -DCXX11 -fsyntax-only %s
// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -DCXX11 -DCONCEPTS -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++2a -DCXX11 -DCXX2A -fsyntax-only %s
// RUN: %clang_cc1 -std=c++03 -fdeclspec -DDECLSPEC -fsyntax-only %s
// RUN: %clang_cc1 -std=c++03 -fms-extensions -DDECLSPEC -fsyntax-only %s
// RUN: %clang_cc1 -std=c++03 -fborland-extensions -DDECLSPEC -fsyntax-only %s
@@ -19,7 +20,7 @@
#define NOT_KEYWORD(NAME) _Static_assert(__is_identifier(NAME), #NAME)
#define IS_TYPE(NAME) void is_##NAME##_type() { int f(NAME); }
-#ifdef CONCEPTS
+#if defined(CONCEPTS) || defined(CXX2A)
#define CONCEPTS_KEYWORD(NAME) IS_KEYWORD(NAME)
#else
#define CONCEPTS_KEYWORD(NAME) NOT_KEYWORD(NAME)
diff --git a/test/Lexer/newline-nul.c b/test/Lexer/newline-nul.c
new file mode 100644
index 0000000000..dd1b4199d4
--- /dev/null
+++ b/test/Lexer/newline-nul.c
Binary files differ
diff --git a/test/Lexer/preamble.c b/test/Lexer/preamble.c
index 5b2739abef..762271f2e3 100644
--- a/test/Lexer/preamble.c
+++ b/test/Lexer/preamble.c
@@ -9,15 +9,12 @@
#pragma unknown
#endif
#ifdef WIBBLE
-#include "honk"
-#else
-int foo();
+#include "foo"
+int bar;
#endif
// This test checks for detection of the preamble of a file, which
-// includes all of the starting comments and #includes. Note that any
-// changes to the preamble part of this file must be mirrored in
-// Inputs/preamble.txt, since we diff against it.
+// includes all of the starting comments and #includes.
// RUN: %clang_cc1 -print-preamble %s > %t
// RUN: echo END. >> %t
@@ -33,4 +30,6 @@ int foo();
// CHECK-NEXT: #endif
// CHECK-NEXT: #pragma unknown
// CHECK-NEXT: #endif
+// CHECK-NEXT: #ifdef WIBBLE
+// CHECK-NEXT: #include "foo"
// CHECK-NEXT: END.
diff --git a/test/Lexer/preamble2.c b/test/Lexer/preamble2.c
new file mode 100644
index 0000000000..499a9a22a5
--- /dev/null
+++ b/test/Lexer/preamble2.c
@@ -0,0 +1,19 @@
+// Preamble detection test: header with an include guard.
+#ifndef HEADER_H
+#define HEADER_H
+#include "foo"
+int bar;
+#endif
+
+// This test checks for detection of the preamble of a file, which
+// includes all of the starting comments and #includes.
+
+// RUN: %clang_cc1 -print-preamble %s > %t
+// RUN: echo END. >> %t
+// RUN: FileCheck < %t %s
+
+// CHECK: // Preamble detection test: header with an include guard.
+// CHECK-NEXT: #ifndef HEADER_H
+// CHECK-NEXT: #define HEADER_H
+// CHECK-NEXT: #include "foo"
+// CHECK-NEXT: END.
diff --git a/test/Lexer/wchar.c b/test/Lexer/wchar.c
index de00c02f13..47417382c9 100644
--- a/test/Lexer/wchar.c
+++ b/test/Lexer/wchar.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fshort-wchar -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fwchar-type=short -fno-signed-wchar -verify %s
void f() {
(void)L"\U00010000"; // unicode escape produces UTF-16 sequence, so no warning
diff --git a/test/Misc/Inputs/module.modulemap b/test/Misc/Inputs/module.modulemap
new file mode 100644
index 0000000000..a8ecb09390
--- /dev/null
+++ b/test/Misc/Inputs/module.modulemap
@@ -0,0 +1 @@
+module X {}
diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
index f18fbac7d7..bf942959a8 100644
--- a/test/Misc/ast-dump-attr.cpp
+++ b/test/Misc/ast-dump-attr.cpp
@@ -179,3 +179,33 @@ void TestExternalSourceSymbolAttr5()
__attribute__((external_source_symbol(generated_declaration, defined_in="module", language="Swift")));
// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5
// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration
+
+namespace TestNoEscape {
+ void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {}
+ // CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'
+ // CHECK-NEXT: ParmVarDecl
+ // CHECK-NEXT: ParmVarDecl
+ // CHECK-NEXT: NoEscapeAttr
+}
+
+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-c-attr.c b/test/Misc/ast-dump-c-attr.c
new file mode 100644
index 0000000000..701df78e61
--- /dev/null
+++ b/test/Misc/ast-dump-c-attr.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux -fdouble-square-bracket-attributes -Wno-deprecated-declarations -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
+
+int Test1 [[deprecated]];
+// CHECK: VarDecl{{.*}}Test1
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:13> "" ""
+
+enum [[deprecated("Frobble")]] Test2 {
+ Test3 [[deprecated]]
+};
+// CHECK: EnumDecl{{.*}}Test2
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:8, col:28> "Frobble" ""
+// CHECK-NEXT: EnumConstantDecl{{.*}}Test3
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:11> "" ""
+
+struct [[deprecated]] Test4 {
+ [[deprecated("Frobble")]] int Test5, Test6;
+ int Test7 [[deprecated]] : 12;
+};
+// CHECK: RecordDecl{{.*}}Test4
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:10> "" ""
+// CHECK-NEXT: FieldDecl{{.*}}Test5
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:5, col:25> "Frobble" ""
+// CHECK-NEXT: FieldDecl{{.*}}Test6
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:5, col:25> "Frobble" ""
+// CHECK-NEXT: FieldDecl{{.*}}Test7
+// CHECK-NEXT: IntegerLiteral{{.*}}'int' 12
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:15> "" ""
+
+struct [[deprecated]] Test8;
+// CHECK: RecordDecl{{.*}}Test8
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:10> "" ""
+
+[[deprecated]] void Test9(int Test10 [[deprecated]]);
+// CHECK: FunctionDecl{{.*}}Test9
+// CHECK-NEXT: ParmVarDecl{{.*}}Test10
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:40> "" ""
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:3> "" ""
+
+void Test11 [[deprecated]](void);
+// CHECK: FunctionDecl{{.*}}Test11
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:15> "" ""
+
+void Test12(void) [[deprecated]] {}
+// CHECK: FunctionDecl{{.*}}Test12
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: DeprecatedAttr 0x{{[^ ]*}} <col:21> "" ""
diff --git a/test/Misc/ast-dump-decl.c b/test/Misc/ast-dump-decl.c
index 45edea26b4..71b98c9443 100644
--- a/test/Misc/ast-dump-decl.c
+++ b/test/Misc/ast-dump-decl.c
@@ -1,8 +1,13 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix CHECK -strict-whitespace %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump %s | FileCheck -check-prefix CHECK-TU -strict-whitespace %s
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-name=X -triple x86_64-unknown-unknown -fmodule-map-file=%S/Inputs/module.modulemap -ast-dump -ast-dump-filter Test %s -DMODULES | FileCheck -check-prefix CHECK -check-prefix CHECK-MODULES -strict-whitespace %s
int TestLocation;
-// CHECK: VarDecl 0x{{[^ ]*}} <{{.*}}:4:1, col:5> col:5 TestLocation
+// CHECK: VarDecl 0x{{[^ ]*}} <{{.*}}:[[@LINE-1]]:1, col:5> col:5 TestLocation
+
+#ifdef MODULES
+#pragma clang module begin X
+#endif
struct TestIndent {
int x;
@@ -33,7 +38,7 @@ typedef int TestTypedefDecl;
// CHECK: TypedefDecl{{.*}} TestTypedefDecl 'int'
__module_private__ typedef int TestTypedefDeclPrivate;
-// CHECK: TypedefDecl{{.*}} TestTypedefDeclPrivate 'int' __module_private__
+// CHECK-MODULE: TypedefDecl{{.*}} TestTypedefDeclPrivate 'int' __module_private__
enum TestEnumDecl {
testEnumDecl
@@ -53,7 +58,7 @@ enum TestEnumDeclForward;
// CHECK: EnumDecl{{.*}} TestEnumDeclForward
__module_private__ enum TestEnumDeclPrivate;
-// CHECK: EnumDecl{{.*}} TestEnumDeclPrivate __module_private__
+// CHECK-MODULE: EnumDecl{{.*}} TestEnumDeclPrivate __module_private__
struct TestRecordDecl {
int i;
@@ -83,7 +88,7 @@ struct TestRecordDeclForward;
// CHECK: RecordDecl{{.*}} struct TestRecordDeclForward
__module_private__ struct TestRecordDeclPrivate;
-// CHECK: RecordDecl{{.*}} struct TestRecordDeclPrivate __module_private__
+// CHECK-MODULE: RecordDecl{{.*}} struct TestRecordDeclPrivate __module_private__
enum testEnumConstantDecl {
TestEnumConstantDecl,
@@ -136,7 +141,7 @@ struct testFieldDecl {
// CHECK: FieldDecl{{.*}} TestFieldDecl 'int'
// CHECK: FieldDecl{{.*}} TestFieldDeclWidth 'int'
// CHECK-NEXT: IntegerLiteral
-// CHECK: FieldDecl{{.*}} TestFieldDeclPrivate 'int' __module_private__
+// CHECK-MODULE: FieldDecl{{.*}} TestFieldDeclPrivate 'int' __module_private__
int TestVarDecl;
// CHECK: VarDecl{{.*}} TestVarDecl 'int'
@@ -148,7 +153,7 @@ __thread int TestVarDeclThread;
// CHECK: VarDecl{{.*}} TestVarDeclThread 'int' tls{{$}}
__module_private__ int TestVarDeclPrivate;
-// CHECK: VarDecl{{.*}} TestVarDeclPrivate 'int' __module_private__
+// CHECK-MODULE: VarDecl{{.*}} TestVarDeclPrivate 'int' __module_private__
int TestVarDeclInit = 0;
// CHECK: VarDecl{{.*}} TestVarDeclInit 'int'
@@ -156,3 +161,8 @@ int TestVarDeclInit = 0;
void testParmVarDecl(int TestParmVarDecl);
// CHECK: ParmVarDecl{{.*}} TestParmVarDecl 'int'
+
+#ifdef MODULES
+#pragma clang module end
+#endif
+
diff --git a/test/Misc/ast-dump-decl.cpp b/test/Misc/ast-dump-decl.cpp
index e1cdeb0995..0df8a5a2b8 100644
--- a/test/Misc/ast-dump-decl.cpp
+++ b/test/Misc/ast-dump-decl.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fms-extensions -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix CHECK -strict-whitespace %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fms-extensions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
class testEnumDecl {
enum class TestEnumDeclScoped;
@@ -73,6 +73,16 @@ namespace testTypeAliasTemplateDecl {
// CHECK-NEXT: TypeAliasDecl{{.*}} TestTypeAliasTemplateDecl 'A<T>'
namespace testCXXRecordDecl {
+ class TestEmpty {};
+// CHECK: CXXRecordDecl{{.*}} class TestEmpty
+// CHECK-NEXT: DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
+// CHECK-NEXT: DefaultConstructor exists trivial constexpr
+// CHECK-NEXT: CopyConstructor simple trivial has_const_param
+// CHECK-NEXT: MoveConstructor exists simple trivial
+// CHECK-NEXT: CopyAssignment trivial has_const_param
+// CHECK-NEXT: MoveAssignment exists simple trivial
+// CHECK-NEXT: Destructor simple irrelevant trivial
+
class A { };
class B { };
class TestCXXRecordDecl : virtual A, public B {
@@ -80,6 +90,13 @@ namespace testCXXRecordDecl {
};
}
// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDecl
+// CHECK-NEXT: DefinitionData{{$}}
+// CHECK-NEXT: DefaultConstructor exists non_trivial
+// CHECK-NEXT: CopyConstructor simple non_trivial has_const_param
+// CHECK-NEXT: MoveConstructor exists simple non_trivial
+// CHECK-NEXT: CopyAssignment non_trivial has_const_param
+// CHECK-NEXT: MoveAssignment exists simple non_trivial
+// CHECK-NEXT: Destructor simple irrelevant trivial
// CHECK-NEXT: virtual private 'class testCXXRecordDecl::A'
// CHECK-NEXT: public 'class testCXXRecordDecl::B'
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestCXXRecordDecl
@@ -89,23 +106,18 @@ template<class...T>
class TestCXXRecordDeclPack : public T... {
};
// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDeclPack
-// CHECK-NEXT: public 'T'...
+// CHECK: public 'T'...
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestCXXRecordDeclPack
thread_local int TestThreadLocalInt;
// CHECK: TestThreadLocalInt {{.*}} tls_dynamic
-__module_private__ class TestCXXRecordDeclPrivate;
-// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDeclPrivate __module_private__
-
class testCXXMethodDecl {
- __module_private__ void TestCXXMethodDeclPrivate();
virtual void TestCXXMethodDeclPure() = 0;
void TestCXXMethodDeclDelete() = delete;
void TestCXXMethodDeclThrow() throw();
void TestCXXMethodDeclThrowType() throw(int);
};
-// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclPrivate 'void (void)' __module_private__
// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclPure 'void (void)' virtual pure
// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclDelete 'void (void)' delete
// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclThrow 'void (void) throw()'
@@ -255,14 +267,14 @@ namespace testClassTemplateDecl {
// CHECK: ClassTemplateDecl{{.*}} TestClassTemplate
// CHECK-NEXT: TemplateTypeParmDecl
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
-// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+// CHECK: CXXRecordDecl{{.*}} class TestClassTemplate
// CHECK-NEXT: AccessSpecDecl{{.*}} public
// CHECK-NEXT: CXXConstructorDecl{{.*}} <line:{{.*}}:5, col:23>
// CHECK-NEXT: CXXDestructorDecl{{.*}} <line:{{.*}}:5, col:24>
// CHECK-NEXT: CXXMethodDecl{{.*}} <line:{{.*}}:5, col:11>
// CHECK-NEXT: FieldDecl{{.*}} i
// CHECK-NEXT: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
-// CHECK-NEXT: TemplateArgument{{.*}}A
+// CHECK: TemplateArgument{{.*}}A
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
// CHECK-NEXT: AccessSpecDecl{{.*}} public
// CHECK-NEXT: CXXConstructorDecl{{.*}} <line:{{.*}}:5, col:23>
@@ -274,12 +286,13 @@ namespace testClassTemplateDecl {
// CHECK-NEXT: ClassTemplateSpecialization{{.*}} 'TestClassTemplate'
// CHECK: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
-// CHECK-NEXT: TemplateArgument{{.*}}B
+// CHECK-NEXT: DefinitionData
+// CHECK: TemplateArgument{{.*}}B
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
// CHECK-NEXT: FieldDecl{{.*}} j
// CHECK: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
-// CHECK-NEXT: TemplateArgument{{.*}}C
+// CHECK: TemplateArgument{{.*}}C
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
// CHECK-NEXT: AccessSpecDecl{{.*}} public
// CHECK-NEXT: CXXConstructorDecl{{.*}} <line:{{.*}}:5, col:23>
@@ -288,7 +301,7 @@ namespace testClassTemplateDecl {
// CHECK-NEXT: FieldDecl{{.*}} i
// CHECK: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
-// CHECK-NEXT: TemplateArgument{{.*}}D
+// CHECK: TemplateArgument{{.*}}D
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
// CHECK-NEXT: AccessSpecDecl{{.*}} public
// CHECK-NEXT: CXXConstructorDecl{{.*}} <line:{{.*}}:5, col:23>
@@ -297,7 +310,7 @@ namespace testClassTemplateDecl {
// CHECK-NEXT: FieldDecl{{.*}} i
// CHECK: ClassTemplatePartialSpecializationDecl{{.*}} class TestClassTemplatePartial
-// CHECK-NEXT: TemplateArgument
+// CHECK: TemplateArgument
// CHECK-NEXT: TemplateArgument{{.*}}A
// CHECK-NEXT: TemplateTypeParmDecl
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplatePartial
@@ -331,13 +344,13 @@ namespace testCanonicalTemplate {
// CHECK: ClassTemplateDecl{{.*}} TestClassTemplate
// CHECK-NEXT: TemplateTypeParmDecl
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
- // CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+ // CHECK: CXXRecordDecl{{.*}} class TestClassTemplate
// CHECK-NEXT: FriendDecl
// CHECK-NEXT: ClassTemplateDecl{{.*}} TestClassTemplate
// CHECK-NEXT: TemplateTypeParmDecl
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
// CHECK-NEXT: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
- // CHECK-NEXT: TemplateArgument{{.*}}A
+ // CHECK: TemplateArgument{{.*}}A
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
}
@@ -389,27 +402,27 @@ namespace TestTemplateArgument {
template<typename> class testType { };
template class testType<int>;
// CHECK: ClassTemplateSpecializationDecl{{.*}} class testType
- // CHECK-NEXT: TemplateArgument{{.*}} type 'int'
+ // CHECK: TemplateArgument{{.*}} type 'int'
template<int fp(void)> class testDecl { };
template class testDecl<foo>;
// CHECK: ClassTemplateSpecializationDecl{{.*}} class testDecl
- // CHECK-NEXT: TemplateArgument{{.*}} decl
+ // CHECK: TemplateArgument{{.*}} decl
// CHECK-NEXT: Function{{.*}}foo
template class testDecl<nullptr>;
// CHECK: ClassTemplateSpecializationDecl{{.*}} class testDecl
- // CHECK-NEXT: TemplateArgument{{.*}} nullptr
+ // CHECK: TemplateArgument{{.*}} nullptr
template<int> class testIntegral { };
template class testIntegral<1>;
// CHECK: ClassTemplateSpecializationDecl{{.*}} class testIntegral
- // CHECK-NEXT: TemplateArgument{{.*}} integral 1
+ // CHECK: TemplateArgument{{.*}} integral 1
template<template<typename> class> class testTemplate { };
template class testTemplate<A>;
// CHECK: ClassTemplateSpecializationDecl{{.*}} class testTemplate
- // CHECK-NEXT: TemplateArgument{{.*}} A
+ // CHECK: TemplateArgument{{.*}} A
template<template<typename> class ...T> class C {
B<T...> testTemplateExpansion;
@@ -419,13 +432,13 @@ namespace TestTemplateArgument {
template<int, int = 0> class testExpr;
template<int I> class testExpr<I> { };
// CHECK: ClassTemplatePartialSpecializationDecl{{.*}} class testExpr
- // CHECK-NEXT: TemplateArgument{{.*}} expr
+ // CHECK: TemplateArgument{{.*}} expr
// CHECK-NEXT: DeclRefExpr{{.*}}I
template<int, int ...> class testPack { };
template class testPack<0, 1, 2>;
// CHECK: ClassTemplateSpecializationDecl{{.*}} class testPack
- // CHECK-NEXT: TemplateArgument{{.*}} integral 0
+ // CHECK: TemplateArgument{{.*}} integral 0
// CHECK-NEXT: TemplateArgument{{.*}} pack
// CHECK-NEXT: TemplateArgument{{.*}} integral 1
// CHECK-NEXT: TemplateArgument{{.*}} integral 2
@@ -472,7 +485,7 @@ private:
protected:
};
// CHECK: CXXRecordDecl{{.*}} class TestAccessSpecDecl
-// CHECK-NEXT: CXXRecordDecl{{.*}} class TestAccessSpecDecl
+// CHECK: CXXRecordDecl{{.*}} class TestAccessSpecDecl
// CHECK-NEXT: AccessSpecDecl{{.*}} public
// CHECK-NEXT: AccessSpecDecl{{.*}} private
// CHECK-NEXT: AccessSpecDecl{{.*}} protected
@@ -483,7 +496,7 @@ template<typename T> class TestFriendDecl {
friend T;
};
// CHECK: CXXRecord{{.*}} TestFriendDecl
-// CHECK-NEXT: CXXRecord{{.*}} TestFriendDecl
+// CHECK: CXXRecord{{.*}} TestFriendDecl
// CHECK-NEXT: FriendDecl
// CHECK-NEXT: FunctionDecl{{.*}} foo
// CHECK-NEXT: FriendDecl{{.*}} 'class A':'class A'
diff --git a/test/Misc/ast-dump-invalid.cpp b/test/Misc/ast-dump-invalid.cpp
index aa6cd52692..842b057a4a 100644
--- a/test/Misc/ast-dump-invalid.cpp
+++ b/test/Misc/ast-dump-invalid.cpp
@@ -51,7 +51,7 @@ double Str::foo1(double, invalid_type)
}
// CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidFunctionDecl
// CHECK-NEXT: |-CXXRecordDecl {{.*}} <line:46:1, line:48:1> line:46:8 struct Str definition
-// CHECK-NEXT: | |-CXXRecordDecl {{.*}} <col:1, col:8> col:8 implicit struct Str
+// CHECK: | |-CXXRecordDecl {{.*}} <col:1, col:8> col:8 implicit struct Str
// CHECK-NEXT: | `-CXXMethodDecl {{.*}} <line:47:4, col:36> col:11 invalid foo1 'double (double, int)'
// CHECK-NEXT: | |-ParmVarDecl {{.*}} <col:16> col:22 'double'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} <col:24, <invalid sloc>> col:36 invalid 'int'
diff --git a/test/Misc/ast-print-objectivec.m b/test/Misc/ast-print-objectivec.m
index e419237bbb..cb5aacc06a 100644
--- a/test/Misc/ast-print-objectivec.m
+++ b/test/Misc/ast-print-objectivec.m
@@ -17,25 +17,30 @@
@implementation I
- (void)MethP __attribute__((availability(macosx,introduced=10.1.0,deprecated=10.2))) {}
- (void)MethI __attribute__((availability(macosx,introduced=10.1.0,deprecated=10.2))) {}
+
+- (void)methodWithArg:(int)x andAnotherOne:(int)y { }
@end
// CHECK: @protocol P
-// CHECK: - (void) MethP __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2)));
+// CHECK: - (void)MethP __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2)));
// CHECK: @end
// CHECK: @interface I : NSObject<P>
-// CHECK: - (void) MethI __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2)));
+// CHECK: - (void)MethI __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2)));
// CHECK: @end
// CHECK: @interface I(CAT)
-// CHECK: - (void) MethCAT __attribute__((availability(macos, introduced=10_1_0, deprecated=10_2)));
+// CHECK: - (void)MethCAT __attribute__((availability(macos, introduced=10_1_0, deprecated=10_2)));
// CHECK: @end
// CHECK: @implementation I
-// CHECK: - (void) MethP __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2))) {
+// CHECK: - (void)MethP __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2))) {
+// CHECK: }
+
+// CHECK: - (void)MethI __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2))) {
// CHECK: }
-// CHECK: - (void) MethI __attribute__((availability(macos, introduced=10.1.0, deprecated=10.2))) {
+// CHECK: - (void)methodWithArg:(int)x andAnotherOne:(int)y {
// CHECK: }
// CHECK: @end
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 0000000000..7d42f1f403
--- /dev/null
+++ b/test/Misc/ast-print-out-of-line-func.cpp
@@ -0,0 +1,95 @@
+// 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()
+
+}
+
+template<int x, typename T>
+class TemplateRecord {
+ void function();
+ template<typename U> void functionTemplate(T, U);
+};
+
+template<int x, typename T>
+void TemplateRecord<x, T>::function() { }
+// CHECK: template <int x, typename T> void TemplateRecord<x, T>::function()
+
+template<int x, typename T>
+template<typename U>
+void TemplateRecord<x, T>::functionTemplate(T, U) { }
+// CHECK: template <int x, typename T> template <typename U> void TemplateRecord<x, T>::functionTemplate(T, U)
+
+template<>
+class TemplateRecord<0, int> {
+ void function();
+ template<typename U> void functionTemplate(int, U);
+};
+
+void TemplateRecord<0, int>::function() { }
+// CHECK: void TemplateRecord<0, int>::function()
+
+template<typename U>
+void TemplateRecord<0, int>::functionTemplate(int, U) { }
+// CHECK: template <typename U> void TemplateRecord<0, int>::functionTemplate(int, U)
+
+template<typename T>
+struct OuterTemplateRecord {
+ template<typename U>
+ struct Inner {
+ void function();
+ };
+};
+
+template<typename T>
+template<typename U>
+void OuterTemplateRecord<T>::Inner<U>::function() { }
+// CHECK: template <typename T> template <typename U> void OuterTemplateRecord<T>::Inner<U>::function()
diff --git a/test/Misc/backend-stack-frame-diagnostics.cpp b/test/Misc/backend-stack-frame-diagnostics.cpp
index a850f22539..bb5566f1a4 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/caret-diags-multiline.cpp b/test/Misc/caret-diags-multiline.cpp
new file mode 100644
index 0000000000..90b50ff398
--- /dev/null
+++ b/test/Misc/caret-diags-multiline.cpp
@@ -0,0 +1,239 @@
+// RUN: not %clang_cc1 -std=c++11 -fcaret-diagnostics-max-lines 5 -Wsometimes-uninitialized %s 2>&1 | FileCheck %s --strict-whitespace
+
+void line(int);
+
+// Check we expand the range as much as possible within the limit.
+
+// CHECK: warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}} return a;
+// CHECK-NEXT: {{^}} ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} } else {
+// CHECK-NEXT: {{^}}~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f1(int cond) {
+ int a;
+ if (cond) {
+ line(1);
+ } else {
+ a = 3;
+ }
+ return a;
+}
+
+// CHECK: warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}} return a;
+// CHECK-NEXT: {{^}} ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} } else {
+// CHECK-NEXT: {{^}}~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f2(int cond) {
+ int a;
+ if (cond) {
+ line(1);
+ line(2);
+ } else {
+ a = 3;
+ }
+ return a;
+}
+
+// CHECK: warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}} return a;
+// CHECK-NEXT: {{^}} ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(3);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} } else {
+// CHECK-NEXT: {{^}}~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f3(int cond) {
+ int a;
+ if (cond) {
+ line(1);
+ line(2);
+ line(3);
+ } else {
+ a = 3;
+ }
+ return a;
+}
+
+// CHECK: warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}} return a;
+// CHECK-NEXT: {{^}} ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(3);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(4);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f4(int cond) {
+ int a;
+ if (cond) {
+ line(1);
+ line(2);
+ line(3);
+ line(4);
+ } else {
+ a = 3;
+ }
+ return a;
+}
+
+// CHECK: warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}} return a;
+// CHECK-NEXT: {{^}} ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}} if (cond) {
+// CHECK-NEXT: {{^}} ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(3);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}} line(4);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f5(int cond) {
+ int a;
+ if (cond) {
+ line(1);
+ line(2);
+ line(3);
+ line(4);
+ line(5);
+ } else {
+ a = 3;
+ }
+ return a;
+}
+
+
+// Check that we don't include lines with no interesting code if we can't reach
+// the interesting part within the line limit.
+
+// CHECK: error: no matching function for call to 'g
+
+// CHECK: note: candidate template ignored: substitution failure
+// CHECK-NEXT: {{^}}decltype(T()
+// CHECK-NEXT: {{^}} ~{{$}}
+// CHECK-NEXT: {{^}} + 1
+// CHECK-NEXT: {{^}} + 2
+// CHECK-NEXT: {{^}} + 3
+// CHECK-NEXT: {{^}}void g();
+// CHECK-NEXT: {{^}} ^{{$}}
+template<typename T>
+decltype(T()
+ + 1
+ + 2
+ + 3)
+void g();
+
+// CHECK: note: candidate template ignored: substitution failure
+// CHECK-NEXT: {{^}}void g();
+// CHECK-NEXT: {{^}} ^{{$}}
+template<typename T>
+decltype(T()
+ + 1
+ + 2
+ + 3
+ + 4)
+void g();
+
+void h() { g<int()>(); }
+
+
+void multiple_ranges(int a, int b) {
+ // CHECK: error: invalid operands
+ // CHECK-NEXT: &(a)
+ // CHECK-NEXT: ~~~~
+ // CHECK-NEXT: +
+ // CHECK-NEXT: ^
+ // CHECK-NEXT: &(b)
+ // CHECK-NEXT: ~~~~
+ &(a)
+ +
+ &(b);
+
+ // CHECK-NEXT: error: invalid operands
+ // CHECK-NEXT: &(
+ // CHECK-NEXT: ~~
+ // CHECK-NEXT: a
+ // CHECK-NEXT: ~
+ // CHECK-NEXT: )
+ // CHECK-NEXT: ~
+ // CHECK-NEXT: +
+ // CHECK-NEXT: ^
+ // CHECK-NEXT: &(
+ // CHECK-NEXT: ~~
+ &(
+ a
+ )
+ +
+ &(
+ b
+ );
+
+ // CHECK-NEXT: error: invalid operands
+ // CHECK-NEXT: &(a
+ // CHECK-NEXT: ~~
+ // CHECK-NEXT: )
+ // CHECK-NEXT: ~
+ // CHECK-NEXT: +
+ // CHECK-NEXT: ^
+ // CHECK-NEXT: &(
+ // CHECK-NEXT: ~~
+ // CHECK-NEXT: b
+ // CHECK-NEXT: ~
+ &(a
+ )
+ +
+ &(
+ b
+ );
+}
+
+#define pr33902_a(b) #b
+#define pr33902_c(d) _Pragma(pr33902_a(d))
+#define pr33902_e(f) pr33902_c(GCC warning #f)
+pr33902_e() pr33902_e()
diff --git a/test/Misc/cc1as-compress.s b/test/Misc/cc1as-compress.s
new file mode 100644
index 0000000000..beba227138
--- /dev/null
+++ b/test/Misc/cc1as-compress.s
@@ -0,0 +1,8 @@
+// REQUIRES: zlib
+// REQUIRES: x86-registered-target
+
+// RUN: %clang -cc1as -triple i686 --compress-debug-sections -filetype asm %s -o /dev/null 2>&1 | FileCheck -allow-empty %s
+// RUN: %clang -cc1as -triple i686 -compress-debug-sections -filetype asm %s -o /dev/null 2>&1 | FileCheck -allow-empty %s
+
+// CHECK-NOT: error: unknown argument:
+
diff --git a/test/Misc/diag-mapping2.c b/test/Misc/diag-mapping2.c
index 672d0548ad..c3afea94b3 100644
--- a/test/Misc/diag-mapping2.c
+++ b/test/Misc/diag-mapping2.c
@@ -4,6 +4,7 @@
// This should not emit anything.
// RUN: %clang_cc1 %s -w 2>&1 | not grep diagnostic
// RUN: %clang_cc1 %s -Wno-#warnings 2>&1 | not grep diagnostic
+// RUN: %clang_cc1 %s -Wno-cpp 2>&1 | not grep diagnostic
// -Werror can map all warnings to error.
// RUN: not %clang_cc1 %s -Werror 2>&1 | grep "error: foo"
diff --git a/test/Misc/find-diagnostic-id.c b/test/Misc/find-diagnostic-id.c
new file mode 100644
index 0000000000..1cddde747f
--- /dev/null
+++ b/test/Misc/find-diagnostic-id.c
@@ -0,0 +1,7 @@
+// RUN: diagtool find-diagnostic-id warn_unused_variable > %t; FileCheck %s < %t
+// RUN: cat %t | xargs diagtool find-diagnostic-id | FileCheck %s --check-prefix=INVERSE
+// RUN: not diagtool find-diagnostic-id warn_unused_vars 2>&1 | FileCheck --check-prefix=ERROR %s
+
+// CHECK: {{^[0-9]+$}}
+// INVERSE: warn_unused_variable
+// ERROR: error: invalid diagnostic 'warn_unused_vars'
diff --git a/test/Misc/pr32207.c b/test/Misc/pr32207.c
new file mode 100644
index 0000000000..f738e41684
--- /dev/null
+++ b/test/Misc/pr32207.c
@@ -0,0 +1,4 @@
+// test for r305179
+// RUN: %clang_cc1 -emit-llvm -O -mllvm -print-after-all %s -o %t 2>&1 | FileCheck %s
+// CHECK: *** IR Dump After Function Integration/Inlining ***
+void foo() {}
diff --git a/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp b/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp
new file mode 100644
index 0000000000..18dfb43a38
--- /dev/null
+++ b/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=namespace" %s | FileCheck --check-prefix=CHECK-NAMESPACE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=type_alias" %s | FileCheck --check-prefix=CHECK-TYPE_ALIAS %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=enum" %s | FileCheck --check-prefix=CHECK-ENUM %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=enum_constant" %s | FileCheck --check-prefix=CHECK-ENUM_CONSTANT %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=record" %s | FileCheck --check-prefix=CHECK-RECORD %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=record(unless(is_union))" %s | FileCheck --check-prefix=CHECK-RECORD_UNLESS_IS_UNION %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=field" %s | FileCheck --check-prefix=CHECK-FIELD %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=function" %s | FileCheck --check-prefix=CHECK-FUNCTION %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=hasType(functionType)" %s | FileCheck --check-prefix=CHECK-HAS_TYPE_FUNCTION_TYPE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=function(is_member)" %s | FileCheck --check-prefix=CHECK-FUNCTION_IS_MEMBER %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable" %s | FileCheck --check-prefix=CHECK-VARIABLE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(is_global)" %s | FileCheck --check-prefix=CHECK-VARIABLE_IS_GLOBAL %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(is_parameter)" %s | FileCheck --check-prefix=CHECK-VARIABLE_IS_PARAMETER %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(unless(is_parameter))" %s | FileCheck --check-prefix=CHECK-VARIABLE_UNLESS_IS_PARAMETER %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(SUBJECT))
+
+namespace testNamespace {
+// CHECK-NAMESPACE: NamespaceDecl{{.*}} testNamespace
+// CHECK-NAMESPACE-NEXT: AnnotateAttr{{.*}} "test"
+
+typedef int testTypedef;
+// CHECK-TYPE_ALIAS: TypedefDecl{{.*}} testTypedef
+// CHECK-TYPE_ALIAS-NEXT: BuiltinType
+// CHECK-TYPE_ALIAS-NEXT: AnnotateAttr{{.*}} "test"
+
+using testTypeAlias = double;
+// CHECK-TYPE_ALIAS: TypeAliasDecl{{.*}} testTypeAlias
+// CHECK-TYPE_ALIAS-NEXT: BuiltinType
+// CHECK-TYPE_ALIAS-NEXT: AnnotateAttr{{.*}} "test"
+
+enum testEnum {
+ testEnumCase1,
+ testEnumCase2
+};
+// CHECK-ENUM: EnumDecl{{.*}} testEnum
+// CHECK-ENUM-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-ENUM_CONSTANT: EnumConstantDecl{{.*}} testEnumCase1
+// CHECK-ENUM_CONSTANT-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-ENUM_CONSTANT: EnumConstantDecl{{.*}} testEnumCase2
+// CHECK-ENUM_CONSTANT-NEXT: AnnotateAttr{{.*}} "test"
+
+struct testStructRecord {
+ int testStructRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testStructRecord
+// CHECK-RECORD: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testStructRecord
+// CHECK-RECORD_UNLESS_IS_UNION: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testStructRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+class testClassRecord {
+ int testClassRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testClassRecord
+// CHECK-RECORD: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testClassRecord
+// CHECK-RECORD_UNLESS_IS_UNION: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testClassRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+union testUnionRecord {
+ int testUnionRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testUnionRecord
+// CHECK-RECORD: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testUnionRecord
+// CHECK-RECORD_UNLESS_IS_UNION-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testUnionRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl
+void testFunctionDecl();
+// CHECK-FUNCTION: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+
+void testFunctionDecl() { }
+// CHECK-FUNCTION: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-FUNCTION-NEXT: CompoundStmt
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+
+void (*testFunctionVar)();
+// CHECK-HAS_TYPE_FUNCTION_TYPE: VarDecl{{.*}} testFunctionVar
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// 'function' should not apply to variables with a function type!
+// CHECK-FUNCTION: VarDecl{{.*}} testFunctionVar
+// CHECK-FUNCTION-NOT: AnnotateAttr{{.*}} "test"
+
+class testMethods {
+ testMethods();
+ void testMethod();
+};
+void testMethods::testMethod() { }
+void testFunctionNotMethod();
+// CHECK-FUNCTION-LABEL: CXXConstructorDecl{{.*}} testMethods
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXConstructorDecl{{.*}} testMethods
+// CHECK-FUNCTION_IS_MEMBER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXConstructorDecl{{.*}} testMethods
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION_IS_MEMBER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXMethodDecl{{.*}} testMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION-NEXT: CompoundStmt
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION_IS_MEMBER-NEXT: CompoundStmt
+// CHECK-CXX_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXMethodDecl{{.*}} testMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: FunctionDecl{{.*}} testFunctionNotMethod
+// CHECK-FUNCTION_IS_MEMBER-NOT: AnnotateAttr{{.*}} "test"
+
+int testVariable;
+// CHECK-VARIABLE: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_IS_GLOBAL-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+void testVarFunction(int testParam) {
+// CHECK-VARIABLE: VarDecl{{.*}} testParam
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_IS_GLOBAL-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+
+ int testLocalVariable;
+// CHECK-VARIABLE: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_IS_GLOBAL-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+}
+class testVarClass {
+ static int testStaticVar;
+};
+// CHECK-VARIABLE: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_IS_GLOBAL-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+
+
+}
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-cxx.cpp b/test/Misc/pragma-attribute-cxx.cpp
new file mode 100644
index 0000000000..a8a3bdebc6
--- /dev/null
+++ b/test/Misc/pragma-attribute-cxx.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump -ast-dump-filter test -std=c++11 -fcxx-exceptions %s | FileCheck %s
+// expected-no-diagnostics
+
+class testClass1 {
+};
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClass1
+// CHECK-NOT: AnnotateAttr
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to=any(record, field, variable, function, namespace, type_alias))
+
+class testClass2 {
+ void testMethod1(int param);
+
+ testClass2();
+
+ testClass2 *operator -> ();
+};
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClass2
+// CHECK: AnnotateAttr{{.*}} "test"
+// CHECK: CXXMethodDecl{{.*}} testMethod1
+// CHECK-NEXT: ParmVarDecl{{.*}} param
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CXXConstructorDecl
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CXXMethodDecl{{.*}} operator->
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+#pragma clang attribute push (__attribute__((annotate("method"))), apply_to=any(record, field, variable, function, namespace, type_alias))
+
+void testClass2::testMethod1(int param) {
+
+#pragma clang attribute pop
+}
+// CHECK-LABEL: CXXMethodDecl{{.*}}prev{{.*}} testMethod1
+// CHECK-NEXT: ParmVarDecl{{.*}} param
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "method"
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "method"
+
+namespace testNamespace {
+}
+// CHECK-LABEL: NamespaceDecl{{.*}} testNamespace
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+class testClassForward;
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClassForward
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+namespace testNamespaceAlias = testNamespace;
+// CHECK-LABEL: NamespaceAliasDecl{{.*}} testNamespaceAlias
+// CHECK-NOT: AnnotateAttr
+
+using testTypeAlias = testClass2;
+// CHECK-LABEL: TypeAliasDecl{{.*}} testTypeAlias
+// CHECK: AnnotateAttr{{.*}} "test"
+
+void testCatchVariable() {
+ try {
+ } catch (int testCatch) {
+ }
+ testCatchVariable();
+}
+// CHECK-LABEL: FunctionDecl{{.*}} testCatchVariable
+// CHECK: CXXCatchStmt
+// CHECK-NEXT: VarDecl{{.*}} testCatch
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+void testLambdaMethod() {
+ auto l = [] () { };
+ testLambdaMethod();
+}
+// CHECK-LABEL: FunctionDecl{{.*}} testLambdaMethod
+// CHECK: LambdaExpr
+// CHECK-NEXT: CXXRecordDecl
+// CHECK: CXXMethodDecl{{.*}} operator()
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((require_constant_initialization)), apply_to=variable(is_global))
+
+int testCI1 = 1;
+// CHECK-LABEL: VarDecl{{.*}} testCI1
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: RequireConstantInitAttr
+
+#pragma clang attribute pop
+
+int testNoCI = 0;
+// CHECK-LABEL: VarDecl{{.*}} testNoCI
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NOT: RequireConstantInitAttr
+
+// Check support for CXX11 style attributes
+#pragma clang attribute push ([[noreturn]], apply_to = function)
+
+void testNoReturn();
+// CHECK-LABEL: FunctionDecl{{.*}} testNoReturn
+// CHECK-NEXT: CXX11NoReturnAttr
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-objc-subject-match-rules.m b/test/Misc/pragma-attribute-objc-subject-match-rules.m
new file mode 100644
index 0000000000..09ab5e1f33
--- /dev/null
+++ b/test/Misc/pragma-attribute-objc-subject-match-rules.m
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump "-DSUBJECT=objc_interface" %s | FileCheck --check-prefix=CHECK-OBJC_INTERFACE %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_protocol" %s | FileCheck --check-prefix=CHECK-OBJC_PROTOCOL %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump "-DSUBJECT=objc_category" %s | FileCheck --check-prefix=CHECK-OBJC_CATEGORY %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_method" %s | FileCheck --check-prefix=CHECK-OBJC_METHOD %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_method(is_instance)" %s | FileCheck --check-prefix=CHECK-OBJC_METHOD_IS_INSTANCE %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=field" %s | FileCheck --check-prefix=CHECK-FIELD %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_property" %s | FileCheck --check-prefix=CHECK-OBJC_PROPERTY %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=block" %s | FileCheck --check-prefix=CHECK-BLOCK %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=hasType(functionType)" %s | FileCheck --check-prefix=CHECK-HAS_TYPE_FUNCTION_TYPE %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(SUBJECT))
+
+@interface testInterface
+@end
+// CHECK-OBJC_INTERFACE: ObjCInterfaceDecl{{.*}} testInterface
+// CHECK-OBJC_INTERFACE-NEXT: AnnotateAttr{{.*}} "test"
+
+@interface testInterface ()
+@end
+// CHECK-OBJC_INTERFACE: ObjCCategoryDecl
+// CHECK-OBJC_INTERFACE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_CATEGORY: ObjCCategoryDecl
+// CHECK-OBJC_CATEGORY-NEXT: ObjCInterface
+// CHECK-OBJC_CATEGORY-NEXT: AnnotateAttr{{.*}} "test"
+
+@interface testInterface (testCategory)
+@end
+// CHECK-OBJC_INTERFACE: ObjCCategoryDecl{{.*}} testCategory
+// CHECK-OBJC_INTERFACE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_CATEGORY: ObjCCategoryDecl{{.*}} testCategory
+// CHECK-OBJC_CATEGORY-NEXT: ObjCInterface
+// CHECK-OBJC_CATEGORY-NEXT: AnnotateAttr{{.*}} "test"
+
+// CHECK-OBJC_INTERFACE-LABEL: ObjCProtocolDecl
+@protocol testProtocol
+@end
+// CHECK-OBJC_PROTOCOL: ObjCProtocolDecl{{.*}} testProtocol
+// CHECK-OBJC_PROTOCOL-NEXT: AnnotateAttr{{.*}} "test"
+
+@interface methodContainer
+- (void) testInstanceMethod;
++ (void) testClassMethod;
+@end
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+
+@implementation methodContainer
+- (void) testInstanceMethod { }
++ (void) testClassMethod { }
+@end
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NOT: AnnotateAttr{{.*}} "test"
+
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+@interface propertyContainer {
+ int testIvar;
+// CHECK-FIELD: ObjCIvarDecl{{.*}} testIvar
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+}
+@property int testProperty;
+// CHECK-OBJC_PROPERTY: ObjCPropertyDecl{{.*}} testProperty
+// CHECK-OBJC_PROPERTY-NEXT: AnnotateAttr{{.*}} "test"
+
+@end
+
+void (^testBlockVar)();
+// CHECK-BLOCK: VarDecl{{.*}} testBlockVar
+// CHECK-BLOCK-NOT: AnnotateAttr{{.*}} "test"
+
+void testBlock() {
+ (void)(^ { });
+}
+// CHECK-BLOCK-LABEL: BlockDecl
+// CHECK-BLOCK-NEXT: CompoundStmt
+// CHECK-BLOCK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: FunctionDecl{{.*}} testBlock
+// CHECK-HAS_TYPE_FUNCTION_TYPE: BlockDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// The attribute applies to function, but not to block:
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-objc.m b/test/Misc/pragma-attribute-objc.m
new file mode 100644
index 0000000000..541cfa9ad3
--- /dev/null
+++ b/test/Misc/pragma-attribute-objc.m
@@ -0,0 +1,164 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -ast-dump -ast-dump-filter test %s | FileCheck %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(objc_interface, objc_protocol, objc_property, field, objc_method, variable))
+#pragma clang attribute push (__attribute__((objc_subclassing_restricted)), apply_to = objc_interface)
+
+@interface testInterface1
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface1
+// CHECK-NEXT: ObjCImplementation
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: ObjCSubclassingRestrictedAttr{{.*}}
+
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+{
+ int testIvar1;
+ // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar1
+ // CHECK-NEXT: AnnotateAttr{{.*}} "test"
+ // CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
+@property int testProp1;
+// CHECK-LABEL: ObjCPropertyDecl{{.*}} testProp1
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+- (void)testIm:(int) x;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testIm
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
++ (void)testCm;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testCm
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+// Implicit getters/setters shouldn't receive the attributes.
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testProp1
+// CHECK-NOT: AnnotateAttr
+// CHECK-LABEL: ObjCMethodDecl{{.*}}setTestProp1
+// CHECK-NOT: AnnotateAttr
+
+@end
+
+// @implementation can't receive explicit attributes, so don't add the pragma
+// attributes to them.
+@implementation testInterface1
+// CHECK-LABEL: ObjCImplementationDecl{{.*}}testInterface1
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+{
+ int testIvar2;
+ // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar2
+ // CHECK-NEXT: AnnotateAttr{{.*}} "test"
+ // CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
+// Don't add attributes to implicit parameters!
+- (void)testIm:(int) x {
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testIm
+// CHECK-NEXT: ImplicitParamDecl
+// CHECK-NEXT: ImplicitParamDecl
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
++ (void)testCm {
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testCm
+// CHECK: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+// CHECK-NOT: AnnotateAttr
+ _Pragma("clang attribute push (__attribute__((annotate(\"applied at container start\"))), apply_to=objc_interface)");
+}
+
+// Implicit ivars shouldn't receive the attributes.
+// CHECK-LABEL: ObjCIvarDecl{{.*}}_testProp1
+// CHECK-NOT: AnnotateAttr
+
+@end
+
+@implementation testImplWithoutInterface // expected-warning {{cannot find interface declaration for 'testImplWithoutInterface'}}
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testImplWithoutInterface
+// CHECK-NEXT: ObjCImplementation
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: ObjCSubclassingRestrictedAttr
+// CHECK-NEXT: AnnotateAttr{{.*}} "applied at container start"
+
+// CHECK-LABEL: ObjCImplementationDecl{{.*}}testImplWithoutInterface
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+#pragma clang attribute pop
+
+@protocol testProtocol
+// CHECK-LABEL: ObjCProtocolDecl{{.*}}testProtocol
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+// CHECK-NOT: AnnotateAttr
+
+- (void)testProtIm;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testProtIm
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+@protocol testForwardProtocol;
+// CHECK-LABEL: ObjCProtocolDecl{{.*}}testForwardProtocol
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+
+// Categories can't receive explicit attributes, so don't add pragma attributes
+// to them.
+@interface testInterface1(testCat)
+// CHECK-LABEL: ObjCCategoryDecl{{.*}}testCat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+@implementation testInterface1(testCat)
+// CHECK-LABEL: ObjCCategoryImplDecl{{.*}}testCat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+// @class/@compatibility_alias declarations can't receive explicit attributes,
+// so don't add pragma attributes to them.
+@class testClass;
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testClass
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@compatibility_alias testCompat testInterface1;
+// CHECK-LABEL: ObjCCompatibleAliasDecl{{.*}}testCompat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+#pragma clang attribute pop // objc_subclassing_restricted
+
+@interface testInterface3
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface3
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+@end
+
+#pragma clang attribute pop // annotate("test")
+
+@interface testInterface4
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface4
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+@end
diff --git a/test/Misc/pragma-attribute-strict-subjects.c b/test/Misc/pragma-attribute-strict-subjects.c
new file mode 100644
index 0000000000..ecd551bee6
--- /dev/null
+++ b/test/Misc/pragma-attribute-strict-subjects.c
@@ -0,0 +1,222 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-pragma-clang-attribute -verify %s
+// RUN: not %clang_cc1 -fsyntax-only -ast-dump -ast-dump-filter test %s | FileCheck %s
+
+// Check for contradictions in rules for attribute without a strict subject set:
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global)))
+// expected-error@-1 {{redundant attribute subject matcher sub-rule 'variable(is_parameter)'; 'variable' already matches those declarations}}
+// expected-error@-2 {{redundant attribute subject matcher sub-rule 'variable(is_global)'; 'variable' already matches those declarations}}
+
+// Ensure that we've recovered from the error:
+int testRecoverSubRuleContradiction = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverSubRuleContradiction
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AnnotateAttr{{.*}} "subRuleContradictions"
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global)))
+// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_global)'}}
+// We have just one error, don't error on 'variable(is_global)'
+
+// Ensure that we've recovered from the error:
+int testRecoverNegatedContradiction = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverNegatedContradiction
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AnnotateAttr{{.*}} "negatedSubRuleContradictions2"
+
+void testRecoverNegatedContradictionFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverNegatedContradictionFunc
+// CHECK-NEXT: AnnotateAttr{{.*}} "negatedSubRuleContradictions2"
+
+#pragma clang attribute pop
+
+// Verify the strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+int testRecoverStrictnessVar = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverStrictnessVar
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NOT: AbiTagAttr
+
+void testRecoverStrictnessFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverStrictnessFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testRecoverStrictnessStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testRecoverStrictnessStruct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), variable, enum))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+int testRecoverExtraVar = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverExtraVar
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AbiTagAttr
+
+void testRecoverExtraFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverExtraFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testRecoverExtraStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testRecoverExtraStruct
+// CHECK-NEXT: AbiTagAttr
+
+enum testNoEnumAbiTag { CaseCase };
+// CHECK-LABEL: EnumDecl{{.*}} testNoEnumAbiTag
+// CHECK-NO: AbiTagAttr
+
+#pragma clang attribute pop
+
+// Verify the non-strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+int testSubset1Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset1Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset1Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset1Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset1Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset1Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = variable)
+
+int testSubset2Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset2Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset2Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset2Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset2Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset2Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union))))
+
+int testSubset3Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset3Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset3Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset3Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset3Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset3Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable))
+
+int testSubset4Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset4Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset4Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset4Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset4Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset4Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union))))
+
+int testSubset5Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset5Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset5Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset5Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset5Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset5Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function))
+
+int testSubset6Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset6Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset6Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset6Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset6Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset6Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+
+int testSubset7Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset7Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset7Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset7Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset7Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset7Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable, enum, enum_constant))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum_constant', and 'enum'}}
+
+int testSubsetRecoverVar;
+// CHECK-LABEL: VarDecl{{.*}} testSubsetRecoverVar
+// CHECK-NEXT: AbiTagAttr
+
+void testSubsetRecoverFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubsetRecoverFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubsetRecoverStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubsetRecoverStruct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = enum)
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+int testSubsetNoVar;
+// CHECK-LABEL: VarDecl{{.*}} testSubsetNoVar
+// CHECK-NOT: AbiTagAttr
+
+void testSubsetNoFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubsetNoFunc
+// CHECK-NOT: AbiTagAttr
+
+struct testSubsetNoStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubsetNoStruct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-supported-attributes-list.test b/test/Misc/pragma-attribute-supported-attributes-list.test
new file mode 100644
index 0000000000..fcc2c5c2f8
--- /dev/null
+++ b/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -0,0 +1,71 @@
+// RUN: clang-tblgen -gen-clang-test-pragma-attribute-supported-attributes -I%src_include_dir %src_include_dir/clang/Basic/Attr.td -o - | FileCheck %s
+
+// The number of supported attributes should never go down!
+
+// CHECK: #pragma clang attribute supports 66 attributes:
+// CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUWavesPerEU (SubjectMatchRule_function)
+// CHECK-NEXT: AVRSignal (SubjectMatchRule_function)
+// CHECK-NEXT: AbiTag (SubjectMatchRule_record_not_is_union, SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_namespace)
+// CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias)
+// CHECK-NEXT: AllocSize (SubjectMatchRule_function)
+// CHECK-NEXT: Annotate ()
+// CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
+// CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function)
+// CHECK-NEXT: CallableWhen (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: Consumable (SubjectMatchRule_record)
+// CHECK-NEXT: Convergent (SubjectMatchRule_function)
+// CHECK-NEXT: DLLExport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
+// CHECK-NEXT: DLLImport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
+// CHECK-NEXT: DisableTailCalls (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: EnableIf (SubjectMatchRule_function)
+// CHECK-NEXT: EnumExtensibility (SubjectMatchRule_enum)
+// CHECK-NEXT: ExternalSourceSymbol ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
+// CHECK-NEXT: FlagEnum (SubjectMatchRule_enum)
+// CHECK-NEXT: Flatten (SubjectMatchRule_function)
+// CHECK-NEXT: IFunc (SubjectMatchRule_function)
+// CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
+// CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record)
+// CHECK-NEXT: MicroMips (SubjectMatchRule_function)
+// CHECK-NEXT: MipsLongCall (SubjectMatchRule_function)
+// CHECK-NEXT: MipsShortCall (SubjectMatchRule_function)
+// CHECK-NEXT: NoDebug (SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter)
+// CHECK-NEXT: NoDuplicate (SubjectMatchRule_function)
+// CHECK-NEXT: NoEscape (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: NoMicroMips (SubjectMatchRule_function)
+// CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: NoSplitStack (SubjectMatchRule_function)
+// CHECK-NEXT: NoThrow (SubjectMatchRule_function)
+// CHECK-NEXT: NotTailCalled (SubjectMatchRule_function)
+// CHECK-NEXT: ObjCBoxable (SubjectMatchRule_record)
+// CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCRequiresSuper (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCRuntimeName (SubjectMatchRule_objc_interface, SubjectMatchRule_objc_protocol)
+// CHECK-NEXT: ObjCRuntimeVisible (SubjectMatchRule_objc_interface)
+// CHECK-NEXT: ObjCSubclassingRestricted (SubjectMatchRule_objc_interface)
+// CHECK-NEXT: OpenCLIntelReqdSubGroupSize (SubjectMatchRule_function)
+// CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
+// CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
+// CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
+// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: SwiftContext (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: SwiftErrorResult (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: SwiftIndirectResult (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local)
+// CHECK-NEXT: Target (SubjectMatchRule_function)
+// CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType)
+// CHECK-NEXT: XRayInstrument (SubjectMatchRule_function_is_member, SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function_is_member, SubjectMatchRule_objc_method, SubjectMatchRule_function)
diff --git a/test/Misc/warning-flags-tree.c b/test/Misc/warning-flags-tree.c
index d71c9f618b..01ba4971ee 100644
--- a/test/Misc/warning-flags-tree.c
+++ b/test/Misc/warning-flags-tree.c
@@ -1,6 +1,6 @@
-// RUN: diagtool tree | FileCheck -strict-whitespace %s
-// RUN: diagtool tree -Weverything | FileCheck -strict-whitespace %s
-// RUN: diagtool tree everything | FileCheck -strict-whitespace %s
+// RUN: diagtool tree --internal | FileCheck -strict-whitespace %s
+// RUN: diagtool tree --internal -Weverything | FileCheck -strict-whitespace %s
+// RUN: diagtool tree --internal everything | FileCheck -strict-whitespace %s
//
// These three ways of running diagtool tree are the same:
// they produce a tree for every top-level diagnostic flag.
@@ -29,8 +29,7 @@
// RUN: not diagtool tree -Wthis-is-not-a-valid-flag
-
-// RUN: diagtool tree -Wgnu | FileCheck -strict-whitespace -check-prefix CHECK-GNU %s
+// RUN: diagtool tree --internal -Wgnu | FileCheck -strict-whitespace -check-prefix CHECK-GNU %s
// CHECK-GNU: -Wgnu
// CHECK-GNU: -Wgnu-designator
// CHECK-GNU: ext_gnu_array_range
@@ -40,7 +39,7 @@
// CHECK-GNU: ext_vla
// There are more GNU extensions but we don't need to check them all.
-// RUN: diagtool tree --flags-only -Wgnu | FileCheck -check-prefix CHECK-FLAGS-ONLY %s
+// RUN: diagtool tree -Wgnu | FileCheck -check-prefix CHECK-FLAGS-ONLY %s
// CHECK-FLAGS-ONLY: -Wgnu
// CHECK-FLAGS-ONLY: -Wgnu-designator
// CHECK-FLAGS-ONLY-NOT: ext_gnu_array_range
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index be02e12e2c..2c48fa4dbf 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -6,8 +6,8 @@ This test serves two purposes:
(1) It documents all existing warnings that currently have no associated -W flag,
and ensures that the list never grows.
- If take an existing warning and add a flag, this test will fail. To
- fix this test, simply remove that warning from the list below.
+ If you take an existing warning and add a flag, this test will fail.
+ To fix this test, simply remove that warning from the list below.
(2) It prevents us adding new warnings to Clang that have no -W flag. All
new warnings should have -W flags.
@@ -18,7 +18,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (78):
+CHECK: Warnings without flags (77):
CHECK-NEXT: ext_excess_initializers
CHECK-NEXT: ext_excess_initializers_in_char_array_initializer
CHECK-NEXT: ext_expected_semi_decl_list
@@ -94,7 +94,6 @@ CHECK-NEXT: warn_typecheck_function_qualifiers
CHECK-NEXT: warn_undef_interface
CHECK-NEXT: warn_undef_interface_suggest
CHECK-NEXT: warn_undef_protocolref
-CHECK-NEXT: warn_use_out_of_scope_declaration
CHECK-NEXT: warn_weak_identifier_undeclared
CHECK-NEXT: warn_weak_import
diff --git a/test/Modules/DebugInfoNamespace.cpp b/test/Modules/DebugInfoNamespace.cpp
new file mode 100644
index 0000000000..33add085d8
--- /dev/null
+++ b/test/Modules/DebugInfoNamespace.cpp
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -std=c++11 -debug-info-kind=standalone \
+// RUN: -dwarf-ext-refs -fmodules \
+// RUN: -fmodule-format=obj -fimplicit-module-maps \
+// RUN: -triple %itanium_abi_triple -fmodules-cache-path=%t \
+// RUN: %s -I %S/Inputs/DebugInfoNamespace -I %t -emit-llvm -o - \
+// RUN: | FileCheck %s
+
+#include "A.h"
+#include "B.h"
+using namespace N;
+B b;
+
+// Verify that the forward decl of B is in module B.
+//
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "B",
+// CHECK-SAME: scope: ![[N:[0-9]+]]
+// CHECK: ![[N]] = !DINamespace(name: "N", scope: ![[B:[0-9]+]])
+// CHECK: ![[B]] = !DIModule(scope: null, name: "B",
diff --git a/test/Modules/DebugInfoSubmoduleImport.c b/test/Modules/DebugInfoSubmoduleImport.c
index 1b31aada9c..b608d300d5 100644
--- a/test/Modules/DebugInfoSubmoduleImport.c
+++ b/test/Modules/DebugInfoSubmoduleImport.c
@@ -2,6 +2,11 @@
// RUN: %clang_cc1 -fmodules -fmodule-format=obj -debug-info-kind=limited -dwarf-ext-refs \
// RUN: -fimplicit-module-maps -x c -fmodules-cache-path=%t -I %S/Inputs \
// RUN: %s -emit-llvm -debugger-tuning=lldb -o - | FileCheck %s
+//
+// RUN: %clang_cc1 -fmodules -fmodule-format=obj -debug-info-kind=limited -dwarf-ext-refs \
+// RUN: -fimplicit-module-maps -x c -fmodules-cache-path=%t -I %S/Inputs \
+// RUN: -fmodules-local-submodule-visibility \
+// RUN: %s -emit-llvm -debugger-tuning=lldb -o - | FileCheck %s
#include "DebugSubmoduleA.h"
#include "DebugSubmoduleB.h"
diff --git a/test/Modules/DebugInfoTransitiveImport.m b/test/Modules/DebugInfoTransitiveImport.m
index 034a909333..08dfecfb78 100644
--- a/test/Modules/DebugInfoTransitiveImport.m
+++ b/test/Modules/DebugInfoTransitiveImport.m
@@ -12,9 +12,9 @@
// Definition of left:
// CHECK: !DICompileUnit({{.*}}dwoId:
-// CHECK: !DIFile({{.*}}diamond_left
+// CHECK: ![[LEFT:[0-9]+]] = !DIFile({{.*}}diamond_left.h
// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration,
-// CHECK-SAME: entity: ![[MODULE:.*]], line: 3)
+// CHECK-SAME: entity: ![[MODULE:.*]], file: ![[LEFT]], line: 3)
// CHECK: ![[MODULE]] = !DIModule(scope: null, name: "diamond_top"
// Skeleton for top:
diff --git a/test/Modules/ExtDebugInfo.cpp b/test/Modules/ExtDebugInfo.cpp
index c39bce9506..97386bc4d0 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
@@ -69,14 +69,18 @@ WithSpecializedBase<int> definedLocally4;
void foo() {
anon.i = GlobalStruct.i = GlobalUnion.i = GlobalEnum;
+ A a;
+ Virtual virt;
}
+// CHECK: ![[CPP:.*]] = !DIFile(filename: {{.*}}ExtDebugInfo.cpp"
+
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum",
// CHECK-SAME: scope: ![[NS:[0-9]+]],
// CHECK-SAME: flags: DIFlagFwdDecl,
// CHECK-SAME: identifier: "_ZTSN8DebugCXX4EnumE")
-// CHECK: ![[NS]] = !DINamespace(name: "DebugCXX", scope: ![[MOD:[0-9]+]],
+// CHECK: ![[NS]] = !DINamespace(name: "DebugCXX", scope: ![[MOD:[0-9]+]])
// CHECK: ![[MOD]] = !DIModule(scope: null, name: {{.*}}DebugCXX
// This type is anchored in the module by an explicit template instantiation.
@@ -201,10 +205,17 @@ void foo() {
// CHECK-SAME: name: "InAnonymousNamespace", {{.*}}DIFlagFwdDecl)
-// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !{{[0-9]+}}, entity: ![[STRUCT]], line: 27)
+// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !{{[0-9]+}}, entity: ![[STRUCT]], file: ![[CPP]], line: 27)
// CHECK: !DICompileUnit(
// CHECK-SAME: splitDebugFilename:
// CHECK-SAME: dwoId:
// CHECK-PCH: !DICompileUnit({{.*}}splitDebugFilename:
// CHECK-PCH: dwoId: 18446744073709551614
+
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A",
+// CHECK-SAME: DIFlagFwdDecl, identifier: "_ZTS1A")
+
+// There is a full definition of the type available in the module.
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Virtual",
+// CHECK-SAME: DIFlagFwdDecl, identifier: "_ZTS7Virtual")
diff --git a/test/Modules/Inputs/DebugCXX.h b/test/Modules/Inputs/DebugCXX.h
index c9cd68f30c..1ccf8d302f 100644
--- a/test/Modules/Inputs/DebugCXX.h
+++ b/test/Modules/Inputs/DebugCXX.h
@@ -54,9 +54,9 @@ namespace DebugCXX {
}
// Virtual class with a forward declaration.
-class FwdVirtual;
-class FwdVirtual {
- virtual ~FwdVirtual() {}
+struct Virtual;
+struct Virtual {
+ virtual ~Virtual() {}
};
struct PureForwardDecl;
diff --git a/test/Modules/Inputs/DebugInfoNamespace/A.h b/test/Modules/Inputs/DebugInfoNamespace/A.h
new file mode 100644
index 0000000000..dc5a1cd26a
--- /dev/null
+++ b/test/Modules/Inputs/DebugInfoNamespace/A.h
@@ -0,0 +1,3 @@
+namespace N {
+ struct A {};
+}
diff --git a/test/Modules/Inputs/DebugInfoNamespace/B.h b/test/Modules/Inputs/DebugInfoNamespace/B.h
new file mode 100644
index 0000000000..c9033a54d4
--- /dev/null
+++ b/test/Modules/Inputs/DebugInfoNamespace/B.h
@@ -0,0 +1,3 @@
+namespace N {
+ struct B {};
+}
diff --git a/test/Modules/Inputs/DebugInfoNamespace/module.modulemap b/test/Modules/Inputs/DebugInfoNamespace/module.modulemap
new file mode 100644
index 0000000000..9300fcf98c
--- /dev/null
+++ b/test/Modules/Inputs/DebugInfoNamespace/module.modulemap
@@ -0,0 +1,8 @@
+module A {
+ header "A.h"
+ export *
+}
+module B {
+ header "B.h"
+ export *
+}
diff --git a/test/Modules/Inputs/DebugObjCImport.h b/test/Modules/Inputs/DebugObjCImport.h
new file mode 100644
index 0000000000..b5ef366fca
--- /dev/null
+++ b/test/Modules/Inputs/DebugObjCImport.h
@@ -0,0 +1,2 @@
+@import Empty;
+struct DebugObjCImport {};
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/coroutines.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/coroutines.h
new file mode 100644
index 0000000000..85281f5a09
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/coroutines.h
@@ -0,0 +1,3 @@
+#ifndef __cpp_coroutines
+#error coroutines must be enabled
+#endif
diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/not_coroutines.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/not_coroutines.h
new file mode 100644
index 0000000000..9312b9ad89
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/not_coroutines.h
@@ -0,0 +1,3 @@
+#ifdef __cpp_coroutines
+#error coroutines must NOT be enabled
+#endif
diff --git a/test/Modules/Inputs/DependsOnModule.framework/module.map b/test/Modules/Inputs/DependsOnModule.framework/module.map
index b62308583d..4d468f2a8c 100644
--- a/test/Modules/Inputs/DependsOnModule.framework/module.map
+++ b/test/Modules/Inputs/DependsOnModule.framework/module.map
@@ -22,7 +22,14 @@ framework module DependsOnModule {
explicit module CustomReq2 {
requires custom_req2
}
-
+ explicit module Coroutines {
+ requires coroutines
+ header "coroutines.h"
+ }
+ explicit module NotCoroutines {
+ requires !coroutines
+ header "not_coroutines.h"
+ }
explicit framework module SubFramework {
umbrella header "SubFramework.h"
diff --git a/test/Modules/Inputs/F.framework/Headers/F.h b/test/Modules/Inputs/F.framework/Headers/F.h
new file mode 100644
index 0000000000..4f705f00e1
--- /dev/null
+++ b/test/Modules/Inputs/F.framework/Headers/F.h
@@ -0,0 +1 @@
+// F.h
diff --git a/test/Modules/Inputs/F.framework/Modules/module.modulemap b/test/Modules/Inputs/F.framework/Modules/module.modulemap
new file mode 100644
index 0000000000..e414776c53
--- /dev/null
+++ b/test/Modules/Inputs/F.framework/Modules/module.modulemap
@@ -0,0 +1,7 @@
+framework module F [extern_c] [system] {
+ umbrella header "F.h"
+ module * {
+ export *
+ }
+ export *
+}
diff --git a/test/Modules/Inputs/F.framework/Modules/module.private.modulemap b/test/Modules/Inputs/F.framework/Modules/module.private.modulemap
new file mode 100644
index 0000000000..69486a2a64
--- /dev/null
+++ b/test/Modules/Inputs/F.framework/Modules/module.private.modulemap
@@ -0,0 +1,7 @@
+module F.Private [system] {
+ explicit module NS {
+ header "NS.h"
+ export *
+ }
+ export *
+}
diff --git a/test/Modules/Inputs/F.framework/PrivateHeaders/NS.h b/test/Modules/Inputs/F.framework/PrivateHeaders/NS.h
new file mode 100644
index 0000000000..5e947ba905
--- /dev/null
+++ b/test/Modules/Inputs/F.framework/PrivateHeaders/NS.h
@@ -0,0 +1,19 @@
+struct NS {
+ int a;
+ int b;
+};
+
+enum NSE {
+ FST = 22,
+ SND = 43,
+ TRD = 55
+};
+
+#define NS_ENUM(_type, _name) \
+ enum _name : _type _name; \
+ enum _name : _type
+
+typedef NS_ENUM(int, NSMyEnum) {
+ MinX = 11,
+ MinXOther = MinX,
+};
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 0000000000..761540b09c
--- /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 0000000000..fd86e3cf87
--- /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 0000000000..4ab49b798c
--- /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 0000000000..f6ac6188d6
--- /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 0000000000..975f1f0437
--- /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 0000000000..cb8cc00a0c
--- /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 0000000000..9fab5d350f
--- /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 0000000000..54e8be79bf
--- /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 0000000000..6ac683c39c
--- /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 0000000000..68103017ad
--- /dev/null
+++ b/test/Modules/Inputs/Main.framework/PrivateHeaders/MainPriv.h
@@ -0,0 +1 @@
+#import "APriv.h"
diff --git a/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/Headers/B.h b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/Headers/B.h
new file mode 100644
index 0000000000..761540b09c
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/Headers/B.h
@@ -0,0 +1 @@
+// B.h
diff --git a/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/Headers/Sub.h b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/Headers/Sub.h
new file mode 100644
index 0000000000..fd86e3cf87
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/Headers/Sub.h
@@ -0,0 +1,2 @@
+// Sub.h
+#import "B.h"
diff --git a/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h
new file mode 100644
index 0000000000..4ab49b798c
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/BPriv.h
@@ -0,0 +1 @@
+// BPriv.h
diff --git a/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h
new file mode 100644
index 0000000000..f6ac6188d6
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h
@@ -0,0 +1 @@
+#import "BPriv.h"
diff --git a/test/Modules/Inputs/MainA.framework/Headers/A.h b/test/Modules/Inputs/MainA.framework/Headers/A.h
new file mode 100644
index 0000000000..975f1f0437
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Headers/A.h
@@ -0,0 +1 @@
+// A.h
diff --git a/test/Modules/Inputs/MainA.framework/Headers/Main.h b/test/Modules/Inputs/MainA.framework/Headers/Main.h
new file mode 100644
index 0000000000..cb8cc00a0c
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Headers/Main.h
@@ -0,0 +1,2 @@
+// Main.h
+#import "A.h"
diff --git a/test/Modules/Inputs/MainA.framework/Modules/module.modulemap b/test/Modules/Inputs/MainA.framework/Modules/module.modulemap
new file mode 100644
index 0000000000..4b0b5e9553
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Modules/module.modulemap
@@ -0,0 +1,12 @@
+framework module MainA {
+ umbrella header "Main.h"
+
+ module * { export * }
+ export *
+
+ framework module Sub {
+ umbrella header "Sub.h"
+ module * { export * }
+ export *
+ }
+}
diff --git a/test/Modules/Inputs/MainA.framework/Modules/module.private.modulemap b/test/Modules/Inputs/MainA.framework/Modules/module.private.modulemap
new file mode 100644
index 0000000000..a8dc5c2be5
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/Modules/module.private.modulemap
@@ -0,0 +1,12 @@
+framework module MainA_Private {
+ umbrella header "MainPriv.h"
+
+ module * { export * }
+ export *
+
+ explicit framework module Sub {
+ umbrella header "SubPriv.h"
+ module * { export * }
+ export *
+ }
+}
diff --git a/test/Modules/Inputs/MainA.framework/PrivateHeaders/APriv.h b/test/Modules/Inputs/MainA.framework/PrivateHeaders/APriv.h
new file mode 100644
index 0000000000..6ac683c39c
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/PrivateHeaders/APriv.h
@@ -0,0 +1 @@
+// APriv.h
diff --git a/test/Modules/Inputs/MainA.framework/PrivateHeaders/MainPriv.h b/test/Modules/Inputs/MainA.framework/PrivateHeaders/MainPriv.h
new file mode 100644
index 0000000000..68103017ad
--- /dev/null
+++ b/test/Modules/Inputs/MainA.framework/PrivateHeaders/MainPriv.h
@@ -0,0 +1 @@
+#import "APriv.h"
diff --git a/test/Modules/Inputs/SameHeader/A.h b/test/Modules/Inputs/SameHeader/A.h
new file mode 100644
index 0000000000..bebe9c31c2
--- /dev/null
+++ b/test/Modules/Inputs/SameHeader/A.h
@@ -0,0 +1,3 @@
+#ifndef __A_h__
+#define __A_h__
+#endif
diff --git a/test/Modules/Inputs/SameHeader/B.h b/test/Modules/Inputs/SameHeader/B.h
new file mode 100644
index 0000000000..c3fe49cd85
--- /dev/null
+++ b/test/Modules/Inputs/SameHeader/B.h
@@ -0,0 +1,4 @@
+#ifndef __B_h__
+#define __B_h__
+#include "C.h"
+#endif
diff --git a/test/Modules/Inputs/SameHeader/C.h b/test/Modules/Inputs/SameHeader/C.h
new file mode 100644
index 0000000000..33c3316a65
--- /dev/null
+++ b/test/Modules/Inputs/SameHeader/C.h
@@ -0,0 +1,12 @@
+#ifndef __C_h__
+#define __C_h__
+int c = 1;
+
+struct aaa {
+ int b;
+};
+
+typedef struct fd_set {
+ char c;
+};
+#endif
diff --git a/test/Modules/Inputs/SameHeader/module.modulemap b/test/Modules/Inputs/SameHeader/module.modulemap
new file mode 100644
index 0000000000..d0283a71ac
--- /dev/null
+++ b/test/Modules/Inputs/SameHeader/module.modulemap
@@ -0,0 +1,11 @@
+module X {
+ module A {
+ header "A.h"
+ export *
+ }
+ module B {
+ header "B.h"
+ export *
+ }
+ export *
+}
diff --git a/test/Modules/Inputs/check-for-sanitizer-feature/check.h b/test/Modules/Inputs/check-for-sanitizer-feature/check.h
new file mode 100644
index 0000000000..74b4628d12
--- /dev/null
+++ b/test/Modules/Inputs/check-for-sanitizer-feature/check.h
@@ -0,0 +1,5 @@
+#if __has_feature(address_sanitizer)
+#define HAS_ASAN 1
+#else
+#define HAS_ASAN 0
+#endif
diff --git a/test/Modules/Inputs/check-for-sanitizer-feature/map b/test/Modules/Inputs/check-for-sanitizer-feature/map
new file mode 100644
index 0000000000..95f2da9502
--- /dev/null
+++ b/test/Modules/Inputs/check-for-sanitizer-feature/map
@@ -0,0 +1,3 @@
+module check_feature {
+ header "check.h"
+}
diff --git a/test/Modules/Inputs/codegen-flags/foo.h b/test/Modules/Inputs/codegen-flags/foo.h
new file mode 100644
index 0000000000..7b9c1cd8e0
--- /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 0000000000..2e095d2794
--- /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 0000000000..378ff3124e
--- /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 0000000000..e7b20a512d
--- /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 0000000000..2e095d2794
--- /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/foo.h b/test/Modules/Inputs/codegen/foo.h
index 3fcab71857..bd3b6489e7 100644
--- a/test/Modules/Inputs/codegen/foo.h
+++ b/test/Modules/Inputs/codegen/foo.h
@@ -2,3 +2,31 @@ 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/use.cpp b/test/Modules/Inputs/codegen/use.cpp
new file mode 100644
index 0000000000..cd1a4a642d
--- /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/crash-typo-correction-visibility/module.h b/test/Modules/Inputs/crash-typo-correction-visibility/module.h
new file mode 100644
index 0000000000..6e73c3c729
--- /dev/null
+++ b/test/Modules/Inputs/crash-typo-correction-visibility/module.h
@@ -0,0 +1 @@
+struct member;
diff --git a/test/Modules/Inputs/crash-typo-correction-visibility/module.modulemap b/test/Modules/Inputs/crash-typo-correction-visibility/module.modulemap
new file mode 100644
index 0000000000..7310d6a2ef
--- /dev/null
+++ b/test/Modules/Inputs/crash-typo-correction-visibility/module.modulemap
@@ -0,0 +1,3 @@
+module "module" {
+ header "module.h"
+}
diff --git a/test/Modules/Inputs/diag_flags.h b/test/Modules/Inputs/diag_flags.h
new file mode 100644
index 0000000000..3b85c84c6c
--- /dev/null
+++ b/test/Modules/Inputs/diag_flags.h
@@ -0,0 +1 @@
+struct Padded { char x; int y; };
diff --git a/test/Modules/Inputs/diagnose-missing-import/a.h b/test/Modules/Inputs/diagnose-missing-import/a.h
new file mode 100644
index 0000000000..2121e968b3
--- /dev/null
+++ b/test/Modules/Inputs/diagnose-missing-import/a.h
@@ -0,0 +1,8 @@
+#ifndef A_h
+#define A_h
+
+@class NSString;
+static NSString * const xyzRiskyCloseOpenParam = @"riskyCloseParam";
+static inline void XYZLogEvent(NSString* eventName, NSString* params);
+
+#endif
diff --git a/test/Modules/Inputs/diagnose-missing-import/module.modulemap b/test/Modules/Inputs/diagnose-missing-import/module.modulemap
new file mode 100644
index 0000000000..690501e1ed
--- /dev/null
+++ b/test/Modules/Inputs/diagnose-missing-import/module.modulemap
@@ -0,0 +1,3 @@
+module NCI {
+ explicit module A { header "a.h" }
+}
diff --git a/test/Modules/Inputs/export_as_test.modulemap b/test/Modules/Inputs/export_as_test.modulemap
new file mode 100644
index 0000000000..4aaec4194e
--- /dev/null
+++ b/test/Modules/Inputs/export_as_test.modulemap
@@ -0,0 +1,9 @@
+module PrivateFoo {
+ export_as Foo
+ export_as Bar
+ export_as Bar
+
+ module Sub {
+ export_as Wibble
+ }
+}
diff --git a/test/Modules/Inputs/header-attribs/bar.h b/test/Modules/Inputs/header-attribs/bar.h
new file mode 100644
index 0000000000..796b4ebcc7
--- /dev/null
+++ b/test/Modules/Inputs/header-attribs/bar.h
@@ -0,0 +1 @@
+extern int b;
diff --git a/test/Modules/Inputs/header-attribs/baz.h b/test/Modules/Inputs/header-attribs/baz.h
new file mode 100644
index 0000000000..566a522b24
--- /dev/null
+++ b/test/Modules/Inputs/header-attribs/baz.h
@@ -0,0 +1 @@
+extern int c;
diff --git a/test/Modules/Inputs/header-attribs/foo.h b/test/Modules/Inputs/header-attribs/foo.h
new file mode 100644
index 0000000000..a54d4a7067
--- /dev/null
+++ b/test/Modules/Inputs/header-attribs/foo.h
@@ -0,0 +1 @@
+extern int a; \ No newline at end of file
diff --git a/test/Modules/Inputs/header-attribs/modular.modulemap b/test/Modules/Inputs/header-attribs/modular.modulemap
new file mode 100644
index 0000000000..945d7150fd
--- /dev/null
+++ b/test/Modules/Inputs/header-attribs/modular.modulemap
@@ -0,0 +1,5 @@
+module A {
+ header "foo.h" { size 13 }
+ header "bar.h" { size 1000 }
+ header "baz.h" { mtime 1 }
+}
diff --git a/test/Modules/Inputs/header-attribs/textual.modulemap b/test/Modules/Inputs/header-attribs/textual.modulemap
new file mode 100644
index 0000000000..b73f3698aa
--- /dev/null
+++ b/test/Modules/Inputs/header-attribs/textual.modulemap
@@ -0,0 +1,5 @@
+module A {
+ textual header "foo.h" { size 13 }
+ textual header "bar.h" { size 1000 }
+ textual header "baz.h" { mtime 1 }
+}
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 0000000000..0ed02bc793
--- /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 0000000000..825eb86038
--- /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/incomplete-umbrella/Foo.framework/Headers/Bar.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h
new file mode 100644
index 0000000000..fb5da09bac
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/Bar.h
@@ -0,0 +1 @@
+#define BAR_PUBLIC 1
diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h
new file mode 100644
index 0000000000..cbbb44f42c
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Headers/FooPublic.h
@@ -0,0 +1 @@
+// FooPublic.h
diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap
new file mode 100644
index 0000000000..af67e65740
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module Foo {
+ umbrella header "FooPublic.h"
+ requires objc
+ export *
+}
diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap
new file mode 100644
index 0000000000..f6d9dfdcab
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/Modules/module.private.modulemap
@@ -0,0 +1,5 @@
+explicit module Foo.Private {
+ umbrella header "Foo.h"
+ requires objc
+ export *
+}
diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h
new file mode 100644
index 0000000000..98064e0814
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Baz.h
@@ -0,0 +1 @@
+#define BAZ_PRIVATE 1
diff --git a/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h
new file mode 100644
index 0000000000..9381133344
--- /dev/null
+++ b/test/Modules/Inputs/incomplete-umbrella/Foo.framework/PrivateHeaders/Foo.h
@@ -0,0 +1 @@
+// Foo.h
diff --git a/test/Modules/Inputs/innerstructredef.h b/test/Modules/Inputs/innerstructredef.h
new file mode 100644
index 0000000000..600f44e41c
--- /dev/null
+++ b/test/Modules/Inputs/innerstructredef.h
@@ -0,0 +1,6 @@
+struct Outer {
+// This definition is actually hidden since only submodule 'one' is imported.
+struct Inner {
+ int x;
+} field;
+};
diff --git a/test/Modules/Inputs/lookup-assert-protocol/Base.h b/test/Modules/Inputs/lookup-assert-protocol/Base.h
new file mode 100644
index 0000000000..5c9506fa5c
--- /dev/null
+++ b/test/Modules/Inputs/lookup-assert-protocol/Base.h
@@ -0,0 +1,3 @@
+@protocol BaseProtocol
+- (void) test;
+@end
diff --git a/test/Modules/Inputs/lookup-assert-protocol/Derive.h b/test/Modules/Inputs/lookup-assert-protocol/Derive.h
new file mode 100644
index 0000000000..fdcde6158a
--- /dev/null
+++ b/test/Modules/Inputs/lookup-assert-protocol/Derive.h
@@ -0,0 +1,4 @@
+#include "Base.h"
+@protocol DerivedProtocol<BaseProtocol>
+- (void) test2;
+@end
diff --git a/test/Modules/Inputs/lookup-assert-protocol/H3.h b/test/Modules/Inputs/lookup-assert-protocol/H3.h
new file mode 100644
index 0000000000..3d8f878905
--- /dev/null
+++ b/test/Modules/Inputs/lookup-assert-protocol/H3.h
@@ -0,0 +1 @@
+#include "Base.h"
diff --git a/test/Modules/Inputs/lookup-assert-protocol/module.map b/test/Modules/Inputs/lookup-assert-protocol/module.map
new file mode 100644
index 0000000000..e8a89eb095
--- /dev/null
+++ b/test/Modules/Inputs/lookup-assert-protocol/module.map
@@ -0,0 +1,4 @@
+module X {
+ header "H3.h"
+ export *
+}
diff --git a/test/Modules/Inputs/malformed-overload/X.h b/test/Modules/Inputs/malformed-overload/X.h
new file mode 100644
index 0000000000..b659406e16
--- /dev/null
+++ b/test/Modules/Inputs/malformed-overload/X.h
@@ -0,0 +1,2 @@
+@class NSString;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))) __attribute__((not_tail_called));
diff --git a/test/Modules/Inputs/malformed-overload/module.modulemap b/test/Modules/Inputs/malformed-overload/module.modulemap
new file mode 100644
index 0000000000..8fe4c92a17
--- /dev/null
+++ b/test/Modules/Inputs/malformed-overload/module.modulemap
@@ -0,0 +1,4 @@
+module X {
+ header "X.h"
+ export *
+}
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index 2beb942861..4788daa431 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -261,10 +261,19 @@ module config {
config_macros [exhaustive] WANT_FOO, WANT_BAR
}
+module diag_flags {
+ header "diag_flags.h"
+}
+
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"
}
@@ -338,6 +347,12 @@ module DebugObjC {
header "DebugObjC.h"
}
+module DebugObjCImport {
+ module SubModule {
+ header "DebugObjCImport.h"
+ }
+}
+
module ImportNameInDir {
header "ImportNameInDir.h"
export *
@@ -432,3 +447,16 @@ module DebugNestedB {
header "DebugNestedB.h"
export *
}
+
+module objcAtKeywordMissingEnd {
+ header "objcAtKeywordMissingEnd.h"
+}
+
+module innerstructredef {
+ module one {
+ header "empty.h"
+ }
+ module two {
+ header "innerstructredef.h"
+ }
+}
diff --git a/test/Modules/Inputs/objc-desig-init/A.h b/test/Modules/Inputs/objc-desig-init/A.h
new file mode 100644
index 0000000000..02e0105f3a
--- /dev/null
+++ b/test/Modules/Inputs/objc-desig-init/A.h
@@ -0,0 +1 @@
+#import "A2.h"
diff --git a/test/Modules/Inputs/objc-desig-init/A2.h b/test/Modules/Inputs/objc-desig-init/A2.h
new file mode 100644
index 0000000000..5a4ceb495b
--- /dev/null
+++ b/test/Modules/Inputs/objc-desig-init/A2.h
@@ -0,0 +1,4 @@
+#import "Base.h"
+
+@interface A2 : Base
+@end
diff --git a/test/Modules/Inputs/objc-desig-init/Base.h b/test/Modules/Inputs/objc-desig-init/Base.h
new file mode 100644
index 0000000000..47184256b1
--- /dev/null
+++ b/test/Modules/Inputs/objc-desig-init/Base.h
@@ -0,0 +1,4 @@
+@class NSString;
+@interface Base
+- (id)initWithNibName:(NSString *)nibNameOrNil __attribute__((objc_designated_initializer));
+@end
diff --git a/test/Modules/Inputs/objc-desig-init/X.h b/test/Modules/Inputs/objc-desig-init/X.h
new file mode 100644
index 0000000000..cb46ba70a3
--- /dev/null
+++ b/test/Modules/Inputs/objc-desig-init/X.h
@@ -0,0 +1,4 @@
+#import "A2.h"
+
+@interface X : A2
+@end
diff --git a/test/Modules/Inputs/objc-desig-init/module.modulemap b/test/Modules/Inputs/objc-desig-init/module.modulemap
new file mode 100644
index 0000000000..0150efb8eb
--- /dev/null
+++ b/test/Modules/Inputs/objc-desig-init/module.modulemap
@@ -0,0 +1,9 @@
+module Base {
+ header "Base.h"
+ export *
+}
+
+module A {
+ header "A.h"
+ export *
+}
diff --git a/test/Modules/Inputs/objcAtKeywordMissingEnd.h b/test/Modules/Inputs/objcAtKeywordMissingEnd.h
new file mode 100644
index 0000000000..1196b87eef
--- /dev/null
+++ b/test/Modules/Inputs/objcAtKeywordMissingEnd.h
@@ -0,0 +1,3 @@
+@interface MissingEnd // expected-note {{class started here}}
+
+@ // expected-error {{expected an Objective-C directive after '@'}} expected-error {{missing '@end'}}
diff --git a/test/Modules/Inputs/outofdate-rebuild/AppKit.h b/test/Modules/Inputs/outofdate-rebuild/AppKit.h
new file mode 100644
index 0000000000..e357918fd4
--- /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 0000000000..d6311405f4
--- /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 0000000000..7ff0e23af1
--- /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 0000000000..bd249dcbb7
--- /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 0000000000..b2d053ad05
--- /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 0000000000..71c99e8196
--- /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/pragma_pack_set.h b/test/Modules/Inputs/pragma_pack_set.h
new file mode 100644
index 0000000000..b123c116ea
--- /dev/null
+++ b/test/Modules/Inputs/pragma_pack_set.h
@@ -0,0 +1,3 @@
+
+#pragma pack (1)
+
diff --git a/test/Modules/Inputs/preprocess-decluse/a.h b/test/Modules/Inputs/preprocess-decluse/a.h
new file mode 100644
index 0000000000..17ab46c848
--- /dev/null
+++ b/test/Modules/Inputs/preprocess-decluse/a.h
@@ -0,0 +1 @@
+// a.h
diff --git a/test/Modules/Inputs/preprocess-decluse/a.modulemap b/test/Modules/Inputs/preprocess-decluse/a.modulemap
new file mode 100644
index 0000000000..47105fe363
--- /dev/null
+++ b/test/Modules/Inputs/preprocess-decluse/a.modulemap
@@ -0,0 +1 @@
+module A { textual header "a.h" }
diff --git a/test/Modules/Inputs/preprocess-decluse/b.h b/test/Modules/Inputs/preprocess-decluse/b.h
new file mode 100644
index 0000000000..2243de1baf
--- /dev/null
+++ b/test/Modules/Inputs/preprocess-decluse/b.h
@@ -0,0 +1 @@
+#include "a.h"
diff --git a/test/Modules/Inputs/preprocess-decluse/b.modulemap b/test/Modules/Inputs/preprocess-decluse/b.modulemap
new file mode 100644
index 0000000000..bd0bdf0e2e
--- /dev/null
+++ b/test/Modules/Inputs/preprocess-decluse/b.modulemap
@@ -0,0 +1 @@
+module B { header "b.h" use A }
diff --git a/test/Modules/Inputs/preprocess-decluse/main.modulemap b/test/Modules/Inputs/preprocess-decluse/main.modulemap
new file mode 100644
index 0000000000..0392c846ce
--- /dev/null
+++ b/test/Modules/Inputs/preprocess-decluse/main.modulemap
@@ -0,0 +1 @@
+module Main { use B }
diff --git a/test/Modules/Inputs/preprocess/a.h b/test/Modules/Inputs/preprocess/a.h
new file mode 100644
index 0000000000..1292e99b4b
--- /dev/null
+++ b/test/Modules/Inputs/preprocess/a.h
@@ -0,0 +1,2 @@
+#include "c.h"
+T a();
diff --git a/test/Modules/Inputs/preprocess/b.h b/test/Modules/Inputs/preprocess/b.h
new file mode 100644
index 0000000000..e8a9f55968
--- /dev/null
+++ b/test/Modules/Inputs/preprocess/b.h
@@ -0,0 +1,2 @@
+#include "c.h"
+T b();
diff --git a/test/Modules/Inputs/preprocess/c.h b/test/Modules/Inputs/preprocess/c.h
new file mode 100644
index 0000000000..718f5dc182
--- /dev/null
+++ b/test/Modules/Inputs/preprocess/c.h
@@ -0,0 +1,4 @@
+#ifndef C_H
+#define C_H
+using T = int;
+#endif
diff --git a/test/Modules/Inputs/preprocess/file.h b/test/Modules/Inputs/preprocess/file.h
index 808ade5768..84cf22a337 100644
--- a/test/Modules/Inputs/preprocess/file.h
+++ b/test/Modules/Inputs/preprocess/file.h
@@ -1,3 +1,9 @@
+#include "other.h"
+
+#ifndef FILE_H
+#define FILE_H
struct __FILE;
#include "fwd.h"
typedef struct __FILE FILE;
+typedef foo bar;
+#endif
diff --git a/test/Modules/Inputs/preprocess/file2.h b/test/Modules/Inputs/preprocess/file2.h
new file mode 100644
index 0000000000..04bf796d1e
--- /dev/null
+++ b/test/Modules/Inputs/preprocess/file2.h
@@ -0,0 +1,2 @@
+#include "file.h"
+extern int file2;
diff --git a/test/Modules/Inputs/preprocess/fwd.h b/test/Modules/Inputs/preprocess/fwd.h
index 4a19c6d0c0..f6de1800c0 100644
--- a/test/Modules/Inputs/preprocess/fwd.h
+++ b/test/Modules/Inputs/preprocess/fwd.h
@@ -1 +1,2 @@
+typedef struct foo foo;
struct __FILE;
diff --git a/test/Modules/Inputs/preprocess/module.modulemap b/test/Modules/Inputs/preprocess/module.modulemap
index a5c5b61ddd..5be2e5c4ff 100644
--- a/test/Modules/Inputs/preprocess/module.modulemap
+++ b/test/Modules/Inputs/preprocess/module.modulemap
@@ -1,2 +1,7 @@
module fwd { header "fwd.h" export * }
-module file { header "file.h" export * }
+module file { header "file.h" header "file2.h" header "other.h" export * }
+module nested {
+ module a { header "a.h" }
+ module b { header "b.h" }
+ module c { header "c.h" }
+}
diff --git a/test/Modules/Inputs/preprocess/other.h b/test/Modules/Inputs/preprocess/other.h
new file mode 100644
index 0000000000..84c4d1d5eb
--- /dev/null
+++ b/test/Modules/Inputs/preprocess/other.h
@@ -0,0 +1 @@
+// other.h: empty
diff --git a/test/Modules/Inputs/submodule-visibility/b.h b/test/Modules/Inputs/submodule-visibility/b.h
index 67ef6529db..39df6a02cb 100644
--- a/test/Modules/Inputs/submodule-visibility/b.h
+++ b/test/Modules/Inputs/submodule-visibility/b.h
@@ -4,7 +4,11 @@ int m = n;
#include "c.h"
#if defined(A) && !defined(ALLOW_NAME_LEAKAGE)
-#error A is defined
+#warning A is defined
#endif
#define B
+
+template<typename T> void b_template() {
+ N::C::f(0);
+}
diff --git a/test/Modules/Inputs/submodule-visibility/other.h b/test/Modules/Inputs/submodule-visibility/other.h
index f40c757ca6..4b68c48915 100644
--- a/test/Modules/Inputs/submodule-visibility/other.h
+++ b/test/Modules/Inputs/submodule-visibility/other.h
@@ -1 +1,10 @@
#include "c.h"
+
+#ifndef OTHER_H
+#define OTHER_H
+namespace N {
+ struct C {
+ template<typename U> static void f(U) {}
+ };
+}
+#endif
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 0000000000..f26ce7e27d
--- /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 0000000000..90fe1bcc58
--- /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 0000000000..5db801a509
--- /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 0000000000..0c0f42a5d0
--- /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/template-default-args/a.h b/test/Modules/Inputs/template-default-args/a.h
index 532cbc8be0..1541d5f6a1 100644
--- a/test/Modules/Inputs/template-default-args/a.h
+++ b/test/Modules/Inputs/template-default-args/a.h
@@ -14,3 +14,16 @@ struct FriendL {
template<typename T> friend struct L;
};
END
+
+namespace DeferredLookup {
+ template<typename T, typename U = T> using X = U;
+ template<typename T> void f() { (void) X<T>(); }
+ template<typename T> int n = X<T>();
+ template<typename T> struct S { X<T> xt; enum E : int; };
+ template<typename T> enum S<T>::E : int { a = X<T>() };
+
+ namespace Indirect {
+ template<typename, bool = true> struct A {};
+ template<typename> struct B { template<typename T> using C = A<T>; };
+ }
+}
diff --git a/test/Modules/Inputs/template-default-args/d.h b/test/Modules/Inputs/template-default-args/d.h
index 5961c91a82..07ececc1f4 100644
--- a/test/Modules/Inputs/template-default-args/d.h
+++ b/test/Modules/Inputs/template-default-args/d.h
@@ -4,3 +4,10 @@ struct FriendL {
template<typename T> friend struct L;
};
END
+
+namespace DeferredLookup {
+ namespace Indirect {
+ template<typename, bool = true> struct A {};
+ template<typename> struct B { template<typename T> using C = A<T>; };
+ }
+}
diff --git a/test/Modules/Inputs/warning-mismatch/Mismatch.h b/test/Modules/Inputs/warning-mismatch/Mismatch.h
new file mode 100644
index 0000000000..a07b0ee31e
--- /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 0000000000..8e69e704c7
--- /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 0000000000..c22cde4597
--- /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/ModuleDebugInfo.cpp b/test/Modules/ModuleDebugInfo.cpp
index 71b05e5aeb..008b3e4f2b 100644
--- a/test/Modules/ModuleDebugInfo.cpp
+++ b/test/Modules/ModuleDebugInfo.cpp
@@ -86,10 +86,10 @@
// CHECK-SAME: flags: DIFlagFwdDecl
// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE")
-// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "FwdVirtual"
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Virtual"
// CHECK-SAME: elements:
-// CHECK-SAME: identifier: "_ZTS10FwdVirtual")
-// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$FwdVirtual"
+// CHECK-SAME: identifier: "_ZTS7Virtual")
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$Virtual"
// CHECK: !DICompositeType(tag: DW_TAG_union_type,
// CHECK-NOT: name:
@@ -111,6 +111,11 @@
// CHECK-SAME: name: "InAnonymousNamespace",
// CHECK-SAME: elements: !{{[0-9]+}})
+// CHECK: ![[A:.*]] = {{.*}}!DICompositeType(tag: DW_TAG_class_type, name: "A",
+// CHECK-SAME: elements:
+// CHECK-SAME: vtableHolder: ![[A]],
+// CHECK-SAME: identifier: "_ZTS1A")
+
// CHECK: ![[DERIVED:.*]] = {{.*}}!DICompositeType(tag: DW_TAG_class_type, name: "Derived",
// CHECK-SAME: identifier: "_ZTS7Derived")
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "B", scope: ![[DERIVED]],
diff --git a/test/Modules/ModuleDebugInfo.m b/test/Modules/ModuleDebugInfo.m
index d1a0e8d5e8..9289abe080 100644
--- a/test/Modules/ModuleDebugInfo.m
+++ b/test/Modules/ModuleDebugInfo.m
@@ -23,8 +23,10 @@
@import DebugObjC;
#endif
-// CHECK: distinct !DICompileUnit(language: DW_LANG_ObjC
-// CHECK-SAME: isOptimized: false,
+// CHECK: distinct !DICompileUnit(language: DW_LANG_ObjC, file: ![[FILE:[0-9]+]],
+// CHECK-SAME: isOptimized: false
+
+// CHECK: ![[FILE]] = !DIFile(filename: "{{DebugObjC|.*DebugObjC.h}}"
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
// CHECK-SAME: scope: ![[MODULE:[0-9]+]],
diff --git a/test/Modules/adl.cpp b/test/Modules/adl.cpp
new file mode 100644
index 0000000000..a1055a889d
--- /dev/null
+++ b/test/Modules/adl.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fmodules -verify -fno-modules-error-recovery -fno-spell-checking %s
+// RUN: %clang_cc1 -fmodules -verify -fno-modules-error-recovery -DONLY_Y %s
+
+#pragma clang module build a
+module a {
+ explicit module x {}
+ explicit module y {}
+}
+#pragma clang module contents
+#pragma clang module begin a.x
+namespace N {
+ template<typename T> extern int f(T) { return 0; }
+}
+#pragma clang module end
+
+#pragma clang module begin a.y
+#pragma clang module import a.x
+using N::f;
+#pragma clang module end
+#pragma clang module endbuild
+
+namespace N { struct A {}; }
+struct B {};
+
+#ifndef ONLY_Y
+#pragma clang module import a.x
+void test1() {
+ f(N::A());
+ f(B()); // expected-error {{use of undeclared identifier 'f'}}
+}
+#else
+// expected-no-diagnostics
+#endif
+
+#pragma clang module import a.y
+void test2() {
+ // These are OK even if a.x is not imported.
+ f(N::A());
+ f(B());
+}
diff --git a/test/Modules/anon-linkage.cpp b/test/Modules/anon-linkage.cpp
new file mode 100644
index 0000000000..590638292b
--- /dev/null
+++ b/test/Modules/anon-linkage.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s
+
+typedef struct {
+ int c;
+ union {
+ int n;
+ char c[4];
+ } v;
+} mbstate;
+
+export module M;
+export using ::mbstate;
diff --git a/test/Modules/autolink.m b/test/Modules/autolink.m
index 28b9e40678..6aee0e11b1 100644
--- a/test/Modules/autolink.m
+++ b/test/Modules/autolink.m
@@ -36,9 +36,7 @@ int use_autolink_sub3() {
// NOTE: "autolink_sub" is intentionally not linked.
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[AUTOLINK_OPTIONS:[0-9]+]]}
-// CHECK: ![[AUTOLINK_OPTIONS]] = !{![[AUTOLINK_PCH:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]], ![[AUTOLINK:[0-9]+]], ![[DEPENDSONMODULE:[0-9]+]], ![[MODULE:[0-9]+]], ![[NOUMBRELLA:[0-9]+]]}
+// CHECK: !llvm.linker.options = !{![[AUTOLINK_PCH:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]], ![[AUTOLINK:[0-9]+]], ![[DEPENDSONMODULE:[0-9]+]], ![[MODULE:[0-9]+]], ![[NOUMBRELLA:[0-9]+]]}
// CHECK: ![[AUTOLINK_PCH]] = !{!"{{(\\01|-l|/DEFAULTLIB:)}}autolink_from_pch{{(\.lib)?}}"}
// CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"autolink_framework"}
// CHECK: ![[AUTOLINK]] = !{!"{{(\\01|-l|/DEFAULTLIB:)}}autolink{{(\.lib)?}}"}
@@ -47,4 +45,4 @@ int use_autolink_sub3() {
// CHECK: ![[NOUMBRELLA]] = !{!"-framework", !"NoUmbrella"}
// CHECK-AUTOLINK-DISABLED: !llvm.module.flags
-// CHECK-AUTOLINK-DISABLED-NOT: "Linker Options"
+// CHECK-AUTOLINK-DISABLED-NOT: !llvm.linker.options
diff --git a/test/Modules/autolinkTBD.m b/test/Modules/autolinkTBD.m
index 6107952c3b..d6b9e997b2 100644
--- a/test/Modules/autolinkTBD.m
+++ b/test/Modules/autolinkTBD.m
@@ -8,10 +8,8 @@ int f() {
return foo();
}
-// CHECK: !llvm.module.flags = !{{{.*}}}
-// CHECK: !{{[0-9]+}} = !{i32 6, !"Linker Options", ![[AUTOLINK_OPTIONS:[0-9]+]]}
-// CHECK: ![[AUTOLINK_OPTIONS]] = !{![[AUTOLINK_FRAMEWORK:[0-9]+]]}
+// CHECK: !llvm.linker.options = !{![[AUTOLINK_FRAMEWORK:[0-9]+]]}
// CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"AutolinkTBD"}
// CHECK-AUTOLINK-DISABLED: !llvm.module.flags
-// CHECK-AUTOLINK-DISABLED-NOT: "Linker Options"
+// CHECK-AUTOLINK-DISABLED-NOT: !llvm.linker.options
diff --git a/test/Modules/builtin-import.mm b/test/Modules/builtin-import.mm
index 2536ac51c4..cbc312b059 100644
--- a/test/Modules/builtin-import.mm
+++ b/test/Modules/builtin-import.mm
@@ -1,7 +1,5 @@
-// REQUIRES: system-darwin
-
// RUN: rm -rf %t
-// RUN: %clang -cc1 -fsyntax-only -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s
+// RUN: %clang -cc1 -fsyntax-only -nobuiltininc -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -isystem %S/Inputs/libc-libcxx/sysroot/usr/include -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s
#include <stdio.h>
#include <stddef.h>
diff --git a/test/Modules/builtins.m b/test/Modules/builtins.m
index 2480e6379c..88a44e7b0a 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/check-for-sanitizer-feature.cpp b/test/Modules/check-for-sanitizer-feature.cpp
new file mode 100644
index 0000000000..40ae46c646
--- /dev/null
+++ b/test/Modules/check-for-sanitizer-feature.cpp
@@ -0,0 +1,66 @@
+// RUN: rm -rf %t.1 %t.2
+// RUN: mkdir %t.1 %t.2
+
+// Build and use an ASan-enabled module.
+// RUN: %clang_cc1 -fsanitize=address -fmodules -fmodules-cache-path=%t.1 \
+// RUN: -fmodule-map-file=%S/Inputs/check-for-sanitizer-feature/map \
+// RUN: -I %S/Inputs/check-for-sanitizer-feature -verify %s
+// RUN: ls %t.1 | count 2
+
+// Force a module rebuild by disabling ASan.
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t.1 \
+// RUN: -fmodule-map-file=%S/Inputs/check-for-sanitizer-feature/map \
+// RUN: -I %S/Inputs/check-for-sanitizer-feature -verify %s
+// RUN: ls %t.1 | count 3
+
+// Enable ASan again: check that there is no import failure, and no rebuild.
+// RUN: %clang_cc1 -fsanitize=address -fmodules -fmodules-cache-path=%t.1 \
+// RUN: -fmodule-map-file=%S/Inputs/check-for-sanitizer-feature/map \
+// RUN: -I %S/Inputs/check-for-sanitizer-feature -verify %s
+// RUN: ls %t.1 | count 3
+
+// Some sanitizers can not affect AST generation when enabled. Check that
+// module rebuilds don't occur when these sanitizers are enabled.
+//
+// First, build without any sanitization.
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t.2 \
+// RUN: -fmodule-map-file=%S/Inputs/check-for-sanitizer-feature/map \
+// RUN: -I %S/Inputs/check-for-sanitizer-feature -verify %s
+// RUN: ls %t.2 | count 2
+//
+// Next, build with sanitization, and check that a new module isn't built.
+// RUN: %clang_cc1 -fsanitize=cfi-vcall,unsigned-integer-overflow,nullability-arg,null -fmodules \
+// RUN: -fmodules-cache-path=%t.2 \
+// RUN: -fmodule-map-file=%S/Inputs/check-for-sanitizer-feature/map \
+// RUN: -I %S/Inputs/check-for-sanitizer-feature -verify %s
+// RUN: ls %t.2 | count 2
+
+// Finally, test that including enabled sanitizers in the module hash isn't
+// required to ensure correctness of module imports.
+//
+// Emit a PCH with ASan enabled.
+// RUN: %clang_cc1 -x c -fsanitize=address %S/Inputs/check-for-sanitizer-feature/check.h -emit-pch -o %t.asan_pch
+//
+// Import the PCH without ASan enabled (we expect an error).
+// RUN: not %clang_cc1 -x c -include-pch %t.asan_pch %s -verify 2>&1 | FileCheck %s --check-prefix=PCH_MISMATCH
+// PCH_MISMATCH: AST file was compiled with the target feature'-fsanitize=address' but the current translation unit is not
+//
+// Emit a PCH with UBSan enabled.
+// RUN: %clang_cc1 -x c -fsanitize=null %S/Inputs/check-for-sanitizer-feature/check.h -emit-pch -o %t.ubsan_pch
+//
+// Import the PCH without UBSan enabled (should work just fine).
+// RUN: %clang_cc1 -x c -include-pch %t.ubsan_pch %s -I %S/Inputs/check-for-sanitizer-feature -verify
+
+#include "check.h"
+
+#if __has_feature(address_sanitizer)
+#if HAS_ASAN != 1
+#error Module doesn't have the address_sanitizer feature, but main program does.
+#endif
+#else
+#if HAS_ASAN != 0
+#error Module has the address_sanitizer feature, but main program doesn't.
+#endif
+#endif
+
+// expected-no-diagnostics
diff --git a/test/Modules/codegen-flags.test b/test/Modules/codegen-flags.test
new file mode 100644
index 0000000000..4cc62e8735
--- /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 0000000000..9b718ca9a3
--- /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.test b/test/Modules/codegen.test
index f1823d55ba..1bdea5df43 100644
--- a/test/Modules/codegen.test
+++ b/test/Modules/codegen.test
@@ -1,10 +1,49 @@
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/foo.modulemap -o %t/foo.pcm
+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 -o - %t/foo.pcm | FileCheck %s
+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
-CHECK: $_Z2f1PKcz = comdat any
-CHECK: define weak_odr void @_Z2f1PKcz(i8* %fmt, ...) #{{[0-9]+}} comdat
-CHECK: call void @llvm.va_start(i8* %{{[a-zA-Z0-9]*}})
+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/const-var-init-update.cpp b/test/Modules/const-var-init-update.cpp
new file mode 100644
index 0000000000..61080eb839
--- /dev/null
+++ b/test/Modules/const-var-init-update.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++1z -fmodules %s -verify
+// expected-no-diagnostics
+
+#pragma clang module build std
+module std { module limits {} module other {} }
+#pragma clang module contents
+#pragma clang module begin std.limits
+template<typename T> struct numeric_limits {
+ static constexpr T __max = 5;
+ static constexpr T max() { return __max; }
+};
+#pragma clang module end
+#pragma clang module begin std.other
+inline void f() { numeric_limits<int> nl; }
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build module_b
+module module_b {}
+#pragma clang module contents
+#pragma clang module begin module_b
+#pragma clang module import std.limits
+constexpr int a = numeric_limits<int>::max();
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import std.limits
+#pragma clang module import module_b
+constexpr int b = a;
+static_assert(b == 5);
diff --git a/test/Modules/crash-typo-correction-visibility.cpp b/test/Modules/crash-typo-correction-visibility.cpp
new file mode 100644
index 0000000000..9f0ed3b7b1
--- /dev/null
+++ b/test/Modules/crash-typo-correction-visibility.cpp
@@ -0,0 +1,11 @@
+// RUN: mkdir -p %t
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-name=module -o %t/module.pcm -emit-module %S/Inputs/crash-typo-correction-visibility/module.modulemap
+// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-file=%t/module.pcm %s -verify
+
+struct S {
+ int member; // expected-note {{declared here}}
+};
+
+int f(...);
+
+int b = sizeof(f(member)); // expected-error {{undeclared identifier 'member'}}
diff --git a/test/Modules/crash-vfs-ivfsoverlay.m b/test/Modules/crash-vfs-ivfsoverlay.m
index abbc0151a8..85aaeaef67 100644
--- a/test/Modules/crash-vfs-ivfsoverlay.m
+++ b/test/Modules/crash-vfs-ivfsoverlay.m
@@ -7,6 +7,7 @@
// RUN: %S/../VFS/Inputs/vfsoverlay2.yaml > %t/srcvfs.yaml
// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \
+// RUN: ASAN_OPTIONS=detect_leaks=0 \
// RUN: %clang -fsyntax-only -nostdinc %s \
// RUN: -I %S/Inputs/crash-recovery/usr/include \
// RUN: -ivfsoverlay %t/srcvfs.yaml \
diff --git a/test/Modules/crash-vfs-path-emptydir-entries.m b/test/Modules/crash-vfs-path-emptydir-entries.m
index e44714bee7..d96adbbf99 100644
--- a/test/Modules/crash-vfs-path-emptydir-entries.m
+++ b/test/Modules/crash-vfs-path-emptydir-entries.m
@@ -27,7 +27,7 @@
// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECKSRC: @import cstd.stdio;
+// CHECKSRC: #pragma clang module import cstd.stdio
// CHECKSH: # Crash reproducer
// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
diff --git a/test/Modules/crash-vfs-path-symlink-component.m b/test/Modules/crash-vfs-path-symlink-component.m
index 5be492514a..4723a77c7e 100644
--- a/test/Modules/crash-vfs-path-symlink-component.m
+++ b/test/Modules/crash-vfs-path-symlink-component.m
@@ -28,7 +28,7 @@
// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECKSRC: @import cstd.stdio;
+// CHECKSRC: #pragma clang module import cstd.stdio
// CHECKSH: # Crash reproducer
// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
@@ -65,4 +65,4 @@
// RUN: -fmodules-cache-path=%t/m/ 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECKOVERLAY
-// CHECKOVERLAY: @import cstd.stdio; /* clang -E: implicit import for "/{{[^ ].*}}/i/usr/x/../stdio.h" */
+// CHECKOVERLAY: #pragma clang module import cstd.stdio /* clang -E: implicit import
diff --git a/test/Modules/crash-vfs-path-symlink-topheader.m b/test/Modules/crash-vfs-path-symlink-topheader.m
index 51a14c69c0..8e0c2d4c92 100644
--- a/test/Modules/crash-vfs-path-symlink-topheader.m
+++ b/test/Modules/crash-vfs-path-symlink-topheader.m
@@ -29,7 +29,7 @@
// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECKSRC: @import cstd.stdio;
+// CHECKSRC: #pragma clang module import cstd.stdio
// CHECKSH: # Crash reproducer
// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
diff --git a/test/Modules/crash-vfs-path-traversal.m b/test/Modules/crash-vfs-path-traversal.m
index cc56e53cf1..cd12cadcf1 100644
--- a/test/Modules/crash-vfs-path-traversal.m
+++ b/test/Modules/crash-vfs-path-traversal.m
@@ -25,7 +25,7 @@
// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECKSRC: @import cstd.stdio;
+// CHECKSRC: #pragma clang module import cstd.stdio
// CHECKSH: # Crash reproducer
// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
@@ -62,4 +62,4 @@
// RUN: -fmodules-cache-path=%t/m/ 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECKOVERLAY
-// CHECKOVERLAY: @import cstd.stdio; /* clang -E: implicit import for "/{{[^ ].*}}/usr/././//////include/../include/./././../include/stdio.h" */
+// CHECKOVERLAY: #pragma clang module import cstd.stdio /* clang -E: implicit import
diff --git a/test/Modules/crash-vfs-relative-incdir.m b/test/Modules/crash-vfs-relative-incdir.m
index 63cd9827c0..ed02de8d7e 100644
--- a/test/Modules/crash-vfs-relative-incdir.m
+++ b/test/Modules/crash-vfs-relative-incdir.m
@@ -21,7 +21,7 @@
// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECKSRC: @import cstd.stdio;
+// CHECKSRC: #pragma clang module import cstd.stdio
// CHECKSH: # Crash reproducer
// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
diff --git a/test/Modules/crash-vfs-relative-overlay.m b/test/Modules/crash-vfs-relative-overlay.m
index 54ba13bbca..e55f4c8f27 100644
--- a/test/Modules/crash-vfs-relative-overlay.m
+++ b/test/Modules/crash-vfs-relative-overlay.m
@@ -24,7 +24,7 @@
// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECKSRC: @import cstd.stdio;
+// CHECKSRC: #pragma clang module import cstd.stdio
// CHECKSH: # Crash reproducer
// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
@@ -58,4 +58,4 @@
// RUN: -fmodules-cache-path=%t/m/ 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECKOVERLAY
-// CHECKOVERLAY: @import cstd.stdio; /* clang -E: implicit import for "/{{[^ ].*}}/usr/include/stdio.h" */
+// CHECKOVERLAY: #pragma clang module import cstd.stdio /* clang -E: implicit import
diff --git a/test/Modules/crash-vfs-run-reproducer.m b/test/Modules/crash-vfs-run-reproducer.m
index 72771a2f94..eba56c53f6 100644
--- a/test/Modules/crash-vfs-run-reproducer.m
+++ b/test/Modules/crash-vfs-run-reproducer.m
@@ -21,7 +21,7 @@
// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
-// CHECKSRC: @import cstd.stdio;
+// CHECKSRC: #pragma clang module import cstd.stdio
// CHECKSH: # Crash reproducer
// CHECKSH-NEXT: # Driver args: "-fsyntax-only"
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
index 59e9136bd1..25f8a99925 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.
@@ -245,8 +251,22 @@ namespace Std {
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
+// CHECK-DUMP-NEXT: DefinitionData
+// CHECK-DUMP-NEXT: DefaultConstructor
+// CHECK-DUMP-NEXT: CopyConstructor
+// CHECK-DUMP-NEXT: MoveConstructor
+// CHECK-DUMP-NEXT: CopyAssignment
+// CHECK-DUMP-NEXT: MoveAssignment
+// CHECK-DUMP-NEXT: Destructor
// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
+// CHECK-DUMP-NEXT: DefinitionData
+// CHECK-DUMP-NEXT: DefaultConstructor
+// CHECK-DUMP-NEXT: CopyConstructor
+// CHECK-DUMP-NEXT: MoveConstructor
+// CHECK-DUMP-NEXT: CopyAssignment
+// CHECK-DUMP-NEXT: MoveAssignment
+// CHECK-DUMP-NEXT: Destructor
// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]'
diff --git a/test/Modules/cxx17-inline-variables.cpp b/test/Modules/cxx17-inline-variables.cpp
new file mode 100644
index 0000000000..be6a190a25
--- /dev/null
+++ b/test/Modules/cxx17-inline-variables.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fmodules %s
+
+#pragma clang module build a
+module a {}
+#pragma clang module contents
+#pragma clang module begin a
+
+template <class c, c e> struct ak { static constexpr c value = e; };
+ak<bool, true> instantiate_class_definition;
+
+#pragma clang module end /* a */
+#pragma clang module endbuild
+
+
+#pragma clang module build o
+module o {}
+#pragma clang module contents
+#pragma clang module begin o
+#pragma clang module import a
+
+inline int instantiate_var_definition() { return ak<bool, true>::value; }
+
+#pragma clang module end
+#pragma clang module endbuild
+
+
+#pragma clang module import o
+#pragma clang module import a
+
+int main() { return ak<bool, true>::value; }
diff --git a/test/Modules/debug-info-moduleimport-in-module.m b/test/Modules/debug-info-moduleimport-in-module.m
new file mode 100644
index 0000000000..cde46115d2
--- /dev/null
+++ b/test/Modules/debug-info-moduleimport-in-module.m
@@ -0,0 +1,21 @@
+// Test that an @import inside a module is not represented in the debug info.
+
+// REQUIRES: asserts
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fmodules -fmodule-format=obj \
+// RUN: -fimplicit-module-maps -fmodules-cache-path=%t %s \
+// RUN: -debugger-tuning=lldb -I %S/Inputs -emit-llvm -o %t.ll \
+// RUN: -mllvm -debug-only=pchcontainer &>%t-mod.ll
+// RUN: cat %t-mod.ll | FileCheck %s
+
+@import DebugObjCImport.SubModule;
+
+// CHECK: distinct !DICompileUnit(language: DW_LANG_ObjC
+// CHECK: DW_TAG_structure_type, name: "DebugObjCImport"
+// CHECK: ![[HEADER:.*]] = !DIFile(filename: {{.*}}DebugObjCImport.h"
+// CHECK: ![[SUBMOD:.*]] = !DIModule({{.*}}name: "SubModule"
+// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration,
+// CHECK-SAME: scope: ![[SUBMOD]], entity: ![[EMPTY:[0-9]+]],
+// CHECK-SAME: file: ![[HEADER]], line: 1)
+// CHECK: ![[EMPTY]] = !DIModule(scope: null, name: "Empty"
diff --git a/test/Modules/debug-info-moduleimport.m b/test/Modules/debug-info-moduleimport.m
index bf60690be4..16820baebe 100644
--- a/test/Modules/debug-info-moduleimport.m
+++ b/test/Modules/debug-info-moduleimport.m
@@ -10,12 +10,13 @@
// CHECK: ![[CU:.*]] = distinct !DICompileUnit
@import DebugObjC;
// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: ![[CU]],
-// CHECK-SAME: entity: ![[MODULE:.*]], line: [[@LINE-2]])
+// CHECK-SAME: entity: ![[MODULE:.*]], file: ![[F:[0-9]+]],
+// CHECK-SAME: line: [[@LINE-3]])
// CHECK: ![[MODULE]] = !DIModule(scope: null, name: "DebugObjC",
// CHECK-SAME: configMacros: "\22-DGREETING=Hello World\22 \22-UNDEBUG\22",
// CHECK-SAME: includePath: "{{.*}}test{{.*}}Modules{{.*}}Inputs",
// CHECK-SAME: isysroot: "/tmp/..")
-
+// CHECK: ![[F]] = !DIFile(filename: {{.*}}debug-info-moduleimport.m
// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \
// RUN: %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \
diff --git a/test/Modules/diag-flags.cpp b/test/Modules/diag-flags.cpp
new file mode 100644
index 0000000000..ada90d24b7
--- /dev/null
+++ b/test/Modules/diag-flags.cpp
@@ -0,0 +1,44 @@
+// RUN: rm -rf %t
+//
+// For an implicit module, all that matters are the warning flags in the user.
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodules-cache-path=%t -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -Wpadded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -Wpadded -Werror
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -Werror=padded
+//
+// For an explicit module, all that matters are the warning flags in the module build.
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/nodiag.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -fmodule-file=%t/nodiag.pcm -Wpadded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -fmodule-file=%t/nodiag.pcm -Werror -Wpadded
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/warning.pcm -Wpadded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/warning.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/warning.pcm -Werror=padded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/warning.pcm -Werror
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/werror-no-error.pcm -Werror -Wpadded -Wno-error=padded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/werror-no-error.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/werror-no-error.pcm -Wno-padded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DWARNING -fmodule-file=%t/werror-no-error.pcm -Werror=padded
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/error.pcm -Werror=padded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/error.pcm -Wno-padded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/error.pcm -Wno-error=padded
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -emit-module -fmodule-name=diag_flags -x c++ %S/Inputs/module.map -fmodules-ts -o %t/werror.pcm -Werror -Wpadded
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/werror.pcm -Wno-error
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fmodules -fimplicit-module-maps -verify -fmodules-cache-path=%t -I %S/Inputs %s -fmodules-ts -DERROR -fmodule-file=%t/werror.pcm -Wno-padded
+
+import diag_flags;
+
+// Diagnostic flags from the module user make no difference to diagnostics
+// emitted within the module when using an explicitly-loaded module.
+#if ERROR
+// expected-error@diag_flags.h:14 {{padding struct}}
+#elif WARNING
+// expected-warning@diag_flags.h:14 {{padding struct}}
+#else
+// expected-no-diagnostics
+#endif
+int arr[sizeof(Padded)];
diff --git a/test/Modules/diagnose-missing-import.m b/test/Modules/diagnose-missing-import.m
new file mode 100644
index 0000000000..e0c0457e63
--- /dev/null
+++ b/test/Modules/diagnose-missing-import.m
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/diagnose-missing-import \
+// RUN: -Werror=implicit-function-declaration -fsyntax-only \
+// RUN: -fimplicit-module-maps -verify %s
+@import NCI;
+
+void foo() {
+ XYZLogEvent(xyzRiskyCloseOpenParam, xyzRiskyCloseOpenParam); // expected-error {{implicit declaration of function 'XYZLogEvent'}} expected-error {{declaration of 'XYZLogEvent' must be imported}} expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}} expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}}
+}
+
+// expected-note@Inputs/diagnose-missing-import/a.h:5 {{previous declaration is here}}
+// expected-note@Inputs/diagnose-missing-import/a.h:5 {{previous declaration is here}}
+// expected-note@Inputs/diagnose-missing-import/a.h:6 {{previous declaration is here}}
+
diff --git a/test/Modules/diagnostics.modulemap b/test/Modules/diagnostics.modulemap
index 3b5b6a5c03..865892b53b 100644
--- a/test/Modules/diagnostics.modulemap
+++ b/test/Modules/diagnostics.modulemap
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/diagnostics-aux.modulemap -fmodule-map-file=%s -fsyntax-only -x c++ /dev/null 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/diagnostics-aux.modulemap -fmodule-map-file=%s -fsyntax-only -x c++ /dev/null 2>&1 | FileCheck %s --implicit-check-not error:
// CHECK: In file included from {{.*}}diagnostics-aux.modulemap:3:
// CHECK: diagnostics-aux-2.modulemap:2:3: error: expected
@@ -15,3 +15,15 @@ module bad_use {
// CHECK: diagnostics.modulemap:[[@LINE+1]]:22: error: use declarations are only allowed in top-level modules
module submodule { use foo }
}
+
+module header_attr {
+ // CHECK: diagnostics.modulemap:[[@LINE+1]]:20: error: expected a header attribute name
+ header "foo.h" { x }
+ // CHECK: diagnostics.modulemap:[[@LINE+1]]:27: error: header attribute 'size' specified multiple times
+ header "bar.h" { size 1 size 2 }
+ // CHECK: diagnostics.modulemap:[[@LINE+1]]:25: error: expected integer literal as value for header attribute 'size'
+ header "baz.h" { size "30 kilobytes" }
+
+ header "quux.h" { size 1 mtime 2 }
+ header "no_attrs.h" {}
+}
diff --git a/test/Modules/elaborated-type-specifier-from-hidden-module.m b/test/Modules/elaborated-type-specifier-from-hidden-module.m
index 0ca1c24bba..571ccb9d95 100644
--- a/test/Modules/elaborated-type-specifier-from-hidden-module.m
+++ b/test/Modules/elaborated-type-specifier-from-hidden-module.m
@@ -4,12 +4,11 @@
@import ElaboratedTypeStructs.Empty; // The structs are now hidden.
struct S1 *x;
struct S2 *y;
-// FIXME: compatible definition should not be an error.
-struct S2 { int x; }; // expected-error {{redefinition}}
+struct S2 { int x; };
struct S3 *z;
// Incompatible definition.
-struct S3 { float y; }; // expected-error {{redefinition}}
-// expected-note@elaborated-type-structs.h:* 2 {{previous definition is here}}
+struct S3 { float y; }; // expected-error {{has incompatible definitions}} // expected-note {{field has name}}
+// expected-note@Inputs/elaborated-type-structs.h:3 {{field has name}}
@import ElaboratedTypeStructs.Structs;
diff --git a/test/Modules/export_as_test.c b/test/Modules/export_as_test.c
new file mode 100644
index 0000000000..a73d6bfc46
--- /dev/null
+++ b/test/Modules/export_as_test.c
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/export_as_test.modulemap %s 2> %t.err
+// RUN: FileCheck %s < %t.err
+
+// CHECK: export_as_test.modulemap:3:13: error: conflicting re-export of module 'PrivateFoo' as 'Foo' or 'Bar'
+// CHECK: export_as_test.modulemap:4:13: warning: module 'PrivateFoo' already re-exported as 'Bar'
+// CHECK: export_as_test.modulemap:7:15: error: only top-level modules can be re-exported as public
+
+
diff --git a/test/Modules/extern_cxx.cpp b/test/Modules/extern_cxx.cpp
new file mode 100644
index 0000000000..97ec726de2
--- /dev/null
+++ b/test/Modules/extern_cxx.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -x c++-module-map -fmodule-name=A -verify %s -fmodules-local-submodule-visibility
+module A { module B {} module C {} }
+
+#pragma clang module contents
+
+#pragma clang module begin A.B
+extern "C++" {
+ #pragma clang module begin A.C
+ template<typename T> void f(T t);
+ #pragma clang module end
+
+ void g() { f(0); } // ok
+}
+
+extern "C++" {
+ #pragma clang module begin A.C
+ } // expected-error {{extraneous closing brace}}
+ #pragma clang module end
+
+ #pragma clang module begin A.C
+ extern "C++" { // expected-note {{to match this '{'}}
+ #pragma clang module end // expected-error {{expected '}' at end of module}}
+}
+
+#pragma clang module end
diff --git a/test/Modules/find-privateheaders.m b/test/Modules/find-privateheaders.m
new file mode 100644
index 0000000000..5720a73f9b
--- /dev/null
+++ b/test/Modules/find-privateheaders.m
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t.cache
+// RUN: %clang_cc1 -fmodules -fsyntax-only -F%S/Inputs -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t.cache -Wno-private-module -DBUILD_PUBLIC -verify %s
+// RUN: rm -rf %t.cache
+// RUN: %clang_cc1 -fmodules -fsyntax-only -F%S/Inputs -fimplicit-module-maps \
+// RUN: -fmodules-cache-path=%t.cache -Wno-private-module -verify %s
+//expected-no-diagnostics
+
+#ifdef BUILD_PUBLIC
+#import "Main/Main.h"
+#else
+#import "MainA/MainPriv.h"
+#endif
diff --git a/test/Modules/header-attribs.cpp b/test/Modules/header-attribs.cpp
new file mode 100644
index 0000000000..292a94561e
--- /dev/null
+++ b/test/Modules/header-attribs.cpp
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -I%S/Inputs/header-attribs -fmodule-map-file=%S/Inputs/header-attribs/textual.modulemap -fmodules-cache-path=%t -verify %s -fmodule-name=A -fmodules-strict-decluse
+// RUN: not %clang_cc1 -fmodules -I%S/Inputs/header-attribs -emit-module -x c++-module-map %S/Inputs/header-attribs/modular.modulemap -fmodules-cache-path=%t -fmodule-name=A 2>&1 | FileCheck %s --check-prefix BUILD-MODULAR
+
+#include "foo.h" // ok, stats match
+#include "bar.h" // expected-error {{does not depend on a module exporting 'bar.h'}}
+#include "baz.h" // expected-error {{does not depend on a module exporting 'baz.h'}}
+
+// FIXME: Explain why the 'bar.h' found on disk doesn't match the module map.
+// BUILD-MODULAR: error: header 'bar.h' not found
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 0000000000..9fb7a6bf0b
--- /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/import-syntax.c b/test/Modules/import-syntax.c
new file mode 100644
index 0000000000..a29e07aa1c
--- /dev/null
+++ b/test/Modules/import-syntax.c
@@ -0,0 +1,35 @@
+// RUN: rm -rf %t
+//
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c -DINCLUDE %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c -DINCLUDE %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c++ -DINCLUDE %s
+//
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c -DAT_IMPORT=1 %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c++ -DAT_IMPORT=1 %s
+//
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c++ -fmodules-ts -DIMPORT=1 %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c++ -fmodules-ts -DIMPORT=1 %s
+//
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c -DPRAGMA %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x objective-c -DPRAGMA %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c++ -DPRAGMA %s
+
+// expected-no-diagnostics
+
+// All forms of module import should make both declarations and macros visible.
+
+#if INCLUDE
+#include "dummy.h"
+#elif AT_IMPORT
+@import dummy;
+#elif IMPORT
+import dummy;
+#elif PRAGMA
+#pragma clang module import dummy
+#endif
+
+#ifndef DUMMY_H
+#error "macros not visible"
+#endif
+
+void *p = &dummy1;
diff --git a/test/Modules/incomplete-umbrella.m b/test/Modules/incomplete-umbrella.m
new file mode 100644
index 0000000000..8760b81571
--- /dev/null
+++ b/test/Modules/incomplete-umbrella.m
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -F%S/Inputs/incomplete-umbrella -fsyntax-only %s 2>&1 | FileCheck %s
+
+#import <Foo/Foo.h>
+#import <Foo/Bar.h>
+#import <Foo/Baz.h>
+@import Foo.Private;
+
+// CHECK: warning: umbrella header for module 'Foo' does not include header 'Bar.h'
+// CHECK: warning: umbrella header for module 'Foo.Private' does not include header 'Baz.h'
+int foo() {
+ int a = BAR_PUBLIC;
+ int b = BAZ_PRIVATE;
+ return 0;
+}
diff --git a/test/Modules/inner-struct-redefines-invisible.m b/test/Modules/inner-struct-redefines-invisible.m
new file mode 100644
index 0000000000..ecf6d808df
--- /dev/null
+++ b/test/Modules/inner-struct-redefines-invisible.m
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -I%S/Inputs -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify %s
+// expected-no-diagnostics
+
+@import innerstructredef.one;
+
+struct Outer {
+// Should set lexical context when parsing 'Inner' here, otherwise there's a crash:
+struct Inner {
+ int x;
+} field;
+};
diff --git a/test/Modules/interface-visibility.m b/test/Modules/interface-visibility.m
new file mode 100644
index 0000000000..2bb124ce09
--- /dev/null
+++ b/test/Modules/interface-visibility.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fmodules -fobjc-arc -x objective-c-module-map %s -fmodule-name=Foo -verify
+
+module Foo {}
+
+#pragma clang module contents
+#pragma clang module begin Foo
+
+// expected-no-diagnostics
+
+#pragma clang module build Foundation
+module Foundation {}
+#pragma clang module contents
+#pragma clang module begin Foundation
+@interface NSIndexSet
+@end
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import Foundation
+
+@interface NSIndexSet (Testing)
+- (int)foo;
+@end
+
+static inline int test(NSIndexSet *obj) {
+ return [obj foo];
+}
+
+#pragma clang module end
diff --git a/test/Modules/localsubmodulevis.m b/test/Modules/localsubmodulevis.m
new file mode 100644
index 0000000000..bf317651df
--- /dev/null
+++ b/test/Modules/localsubmodulevis.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t.a %t.b
+// 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/lookup-assert-protocol.m b/test/Modules/lookup-assert-protocol.m
new file mode 100644
index 0000000000..3c093f1bf1
--- /dev/null
+++ b/test/Modules/lookup-assert-protocol.m
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/lookup-assert-protocol %s -verify
+// expected-no-diagnostics
+
+#include "Derive.h"
+#import <H3.h>
+
+__attribute__((objc_root_class))
+@interface Thing<DerivedProtocol>
+@end
+
+@implementation Thing
+- (void)test {
+}
+- (void)test2 {
+}
+@end
diff --git a/test/Modules/lookup.m b/test/Modules/lookup.m
index edf70639e5..b22e41f845 100644
--- a/test/Modules/lookup.m
+++ b/test/Modules/lookup.m
@@ -14,7 +14,7 @@ void test(id x) {
// expected-note@Inputs/lookup_right.h:3{{also found}}
}
-// CHECK-PRINT: - (int) method;
-// CHECK-PRINT: - (double) method
+// CHECK-PRINT: - (int)method;
+// CHECK-PRINT: - (double)method
// CHECK-PRINT: void test(id x)
diff --git a/test/Modules/macro-redefinition.cpp b/test/Modules/macro-redefinition.cpp
new file mode 100644
index 0000000000..7b1c7b6586
--- /dev/null
+++ b/test/Modules/macro-redefinition.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fmodules -x c++-module-map %s -fmodule-name=__usr_include -verify
+// RUN: %clang_cc1 -fmodules -x c++-module-map %s -fmodule-name=__usr_include -verify -DIMPORT
+
+module __usr_include {
+ module stddef {}
+ module stdlib {}
+}
+
+#pragma clang module contents
+
+// expected-no-diagnostics
+
+#pragma clang module begin __usr_include.stddef
+ #define NULL 0
+#pragma clang module end
+
+#pragma clang module begin __usr_include.stdlib
+ #ifdef IMPORT
+ #pragma clang module import __usr_include.stddef
+ #else
+ #pragma clang module begin __usr_include.stddef
+ #define NULL 0
+ #pragma clang module end
+ #endif
+
+ void *f() { return NULL; } // ok, NULL is visible here
+#pragma clang module end
diff --git a/test/Modules/malformed-overload.m b/test/Modules/malformed-overload.m
new file mode 100644
index 0000000000..e080201d8e
--- /dev/null
+++ b/test/Modules/malformed-overload.m
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -I%S/Inputs/malformed-overload -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify %s
+NSLog(@"%@", path); // expected-error {{expected parameter declarator}} expected-error {{expected ')'}} expected-warning {{type specifier missing}} expected-warning {{incompatible redeclaration}} expected-note {{to match this '('}} expected-note {{'NSLog' is a builtin with type}}
+#import "X.h"
+
+@class NSString;
+void f(NSString *a) {
+ NSLog(@"***** failed to get URL for %@", a);
+}
diff --git a/test/Modules/merge-anon-in-extern_c.cpp b/test/Modules/merge-anon-in-extern_c.cpp
new file mode 100644
index 0000000000..1443251f7e
--- /dev/null
+++ b/test/Modules/merge-anon-in-extern_c.cpp
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -verify %s
+// expected-no-diagnostics
+
+#pragma clang module build sys_types
+module sys_types {}
+#pragma clang module contents
+#pragma clang module begin sys_types
+extern "C" {
+ typedef union { bool b; } pthread_mutex_t;
+}
+#pragma clang module end
+#pragma clang module endbuild
+
+typedef union { bool b; } pthread_mutex_t;
+#pragma clang module import sys_types
+
+const pthread_mutex_t *m;
+
diff --git a/test/Modules/missing-flag.cpp b/test/Modules/missing-flag.cpp
new file mode 100644
index 0000000000..560183be59
--- /dev/null
+++ b/test/Modules/missing-flag.cpp
@@ -0,0 +1,4 @@
+// RUN: not %clang_cc1 -x c++-module-map %s -emit-module -fmodule-name=Foo -o %t 2>&1 | FileCheck %s
+// CHECK: module compilation requires '-fmodules'
+module Foo {}
+#pragma clang module contents
diff --git a/test/Modules/module-impl-with-link.c b/test/Modules/module-impl-with-link.c
index 5e5ca83aaf..ffd388c56b 100644
--- a/test/Modules/module-impl-with-link.c
+++ b/test/Modules/module-impl-with-link.c
@@ -1,7 +1,6 @@
// 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
// an implementation of Clib.
-// CHECK: ![[LINK_OPTIONS]] = !{}
+// CHECK: !llvm.linker.options = !{}
diff --git a/test/Modules/modules-cache-path-canonicalization.m b/test/Modules/modules-cache-path-canonicalization.m
new file mode 100644
index 0000000000..a9d3e34786
--- /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-at-keyword.m b/test/Modules/objc-at-keyword.m
new file mode 100644
index 0000000000..0e058a3090
--- /dev/null
+++ b/test/Modules/objc-at-keyword.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify -x objective-c -fmodule-name=objcAtKeywordMissingEnd -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c -fmodule-name=Empty -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -verify -I %S/Inputs %s
+
+@interface X // expected-note {{class started here}}
+#pragma clang module import Empty // expected-error {{missing '@end'}}
diff --git a/test/Modules/objc-designated-init-mod.m b/test/Modules/objc-designated-init-mod.m
new file mode 100644
index 0000000000..15c25a3ec2
--- /dev/null
+++ b/test/Modules/objc-designated-init-mod.m
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/objc-desig-init %s -verify
+// expected-no-diagnostics
+
+#import "X.h"
+#import "Base.h"
+#import "A.h"
+
+@implementation X
+
+- (instancetype)initWithNibName:(NSString *)nibName {
+ if ((self = [super initWithNibName:nibName])) {
+ return self;
+ }
+ return self;
+}
+@end
diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp
index 7543670620..8ff95d2566 100644
--- a/test/Modules/odr_hash.cpp
+++ b/test/Modules/odr_hash.cpp
@@ -275,6 +275,33 @@ S11 s11;
// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with a different initializer}}
#endif
+#if defined(FIRST)
+struct S12 {
+ unsigned x[5];
+};
+#elif defined(SECOND)
+struct S12 {
+ unsigned x[7];
+};
+#else
+S12 s12;
+// expected-error@first.h:* {{'Field::S12::x' from module 'FirstModule' is not present in definition of 'Field::S12' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S13 {
+ unsigned x[7];
+};
+#elif defined(SECOND)
+struct S13 {
+ double x[7];
+};
+#else
+S13 s13;
+// expected-error@first.h:* {{'Field::S13::x' from module 'FirstModule' is not present in definition of 'Field::S13' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
} // namespace Field
namespace Method {
@@ -403,8 +430,178 @@ S8 s8;
// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is const}}
#endif
+#if defined(FIRST)
+struct S9 {
+ void A(int x) {}
+ void A(int x, int y) {}
+};
+#elif defined(SECOND)
+struct S9 {
+ void A(int x, int y) {}
+ void A(int x) {}
+};
+#else
+S9 s9;
+// expected-error@second.h:* {{'Method::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' that has 2 parameters}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' that has 1 parameter}}
+#endif
+
+#if defined(FIRST)
+struct S10 {
+ void A(int x) {}
+ void A(float x) {}
+};
+#elif defined(SECOND)
+struct S10 {
+ void A(float x) {}
+ void A(int x) {}
+};
+#else
+S10 s10;
+// expected-error@second.h:* {{'Method::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'float'}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int'}}
+#endif
+
+#if defined(FIRST)
+struct S11 {
+ void A(int x) {}
+};
+#elif defined(SECOND)
+struct S11 {
+ void A(int y) {}
+};
+#else
+S11 s11;
+// expected-error@second.h:* {{'Method::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter named 'y'}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter named 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S12 {
+ void A(int x) {}
+};
+#elif defined(SECOND)
+struct S12 {
+ void A(int x = 1) {}
+};
+#else
+S12 s12;
+// expected-error@second.h:* {{'Method::S12' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter without a default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a default argument}}
+#endif
+
+#if defined(FIRST)
+struct S13 {
+ void A(int x = 1 + 0) {}
+};
+#elif defined(SECOND)
+struct S13 {
+ void A(int x = 1) {}
+};
+#else
+S13 s13;
+// expected-error@second.h:* {{'Method::S13' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter with a default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a different default argument}}
+#endif
+
+#if defined(FIRST)
+struct S14 {
+ void A(int x[2]) {}
+};
+#elif defined(SECOND)
+struct S14 {
+ void A(int x[3]) {}
+};
+#else
+S14 s14;
+// expected-error@second.h:* {{'Method::S14' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [3]'}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [2]'}}
+#endif
+
+#if defined(FIRST)
+struct S15 {
+ int A() { return 0; }
+};
+#elif defined(SECOND)
+struct S15 {
+ long A() { return 0; }
+};
+#else
+S15 s15;
+// expected-error@first.h:* {{'Method::S15::A' from module 'FirstModule' is not present in definition of 'Method::S15' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'A' does not match}}
+#endif
} // namespace Method
+namespace Constructor {
+#if defined(FIRST)
+struct S1 {
+ S1() {}
+ void foo() {}
+};
+#elif defined(SECOND)
+struct S1 {
+ void foo() {}
+ S1() {}
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Constructor::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo'}}
+// expected-note@first.h:* {{but in 'FirstModule' found constructor}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ S2(int) {}
+ S2(int, int) {}
+};
+#elif defined(SECOND)
+struct S2 {
+ S2(int, int) {}
+ S2(int) {}
+};
+#else
+S2* s2;
+// expected-error@second.h:* {{'Constructor::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found constructor that has 2 parameters}}
+// expected-note@first.h:* {{but in 'FirstModule' found constructor that has 1 parameter}}
+#endif
+} // namespace Constructor
+
+namespace Destructor {
+#if defined(FIRST)
+struct S1 {
+ ~S1() {}
+ S1() {}
+};
+#elif defined(SECOND)
+struct S1 {
+ S1() {}
+ ~S1() {}
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Destructor::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found constructor}}
+// expected-note@first.h:* {{but in 'FirstModule' found destructor}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ virtual ~S2() {}
+ void foo() {}
+};
+#elif defined(SECOND)
+struct S2 {
+ ~S2() {}
+ virtual void foo() {}
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'Destructor::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found destructor is not virtual}}
+// expected-note@first.h:* {{but in 'FirstModule' found destructor is virtual}}
+#endif
+
+} // namespace Destructor
+
// 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 {
@@ -474,6 +671,57 @@ 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
+
+#if defined(FIRST)
+struct S4 {
+ typedef int a;
+ typedef int b;
+};
+#elif defined(SECOND)
+struct S4 {
+ typedef int b;
+ typedef int a;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'TypeDef::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef name 'b'}}
+// expected-note@first.h:* {{but in 'FirstModule' found typedef name 'a'}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+ typedef int a;
+ typedef int b;
+ int x;
+};
+#elif defined(SECOND)
+struct S5 {
+ int x;
+ typedef int b;
+ typedef int a;
+};
+#else
+S5 s5;
+// expected-error@second.h:* {{'TypeDef::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}}
+// expected-note@first.h:* {{but in 'FirstModule' found typedef}}
+#endif
+
+#if defined(FIRST)
+typedef float F;
+struct S6 {
+ typedef int a;
+ typedef F b;
+};
+#elif defined(SECOND)
+struct S6 {
+ typedef int a;
+ typedef float b;
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'TypeDef::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef 'b' with underlying type 'float'}}
+// expected-note@first.h:* {{but in 'FirstModule' found typedef 'b' with different underlying type 'TypeDef::F' (aka 'float')}}
+#endif
} // namespace TypeDef
namespace Using {
@@ -520,145 +768,990 @@ 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
+
+#if defined(FIRST)
+struct S4 {
+ using a = int;
+ using b = int;
+};
+#elif defined(SECOND)
+struct S4 {
+ using b = int;
+ using a = int;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Using::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias name 'b'}}
+// expected-note@first.h:* {{but in 'FirstModule' found type alias name 'a'}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+ using a = int;
+ using b = int;
+ int x;
+};
+#elif defined(SECOND)
+struct S5 {
+ int x;
+ using b = int;
+ using a = int;
+};
+#else
+S5 s5;
+// expected-error@second.h:* {{'Using::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}}
+// expected-note@first.h:* {{but in 'FirstModule' found type alias}}
+#endif
+
+#if defined(FIRST)
+typedef float F;
+struct S6 {
+ using a = int;
+ using b = F;
+};
+#elif defined(SECOND)
+struct S6 {
+ using a = int;
+ using b = float;
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'Using::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'b' with underlying type 'float'}}
+// expected-note@first.h:* {{but in 'FirstModule' found type alias 'b' with different underlying type 'Using::F' (aka 'float')}}
+#endif
} // namespace Using
+namespace RecordType {
+#if defined(FIRST)
+struct B1 {};
+struct S1 {
+ B1 x;
+};
+#elif defined(SECOND)
+struct A1 {};
+struct S1 {
+ A1 x;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'RecordType::S1::x' from module 'FirstModule' is not present in definition of 'RecordType::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
-// 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 {
+namespace DependentType {
#if defined(FIRST)
-typedef int INT;
-struct S {
- public:
- private:
- protected:
+template <class T>
+class S1 {
+ typename T::typeA x;
+};
+#elif defined(SECOND)
+template <class T>
+class S1 {
+ typename T::typeB x;
+};
+#else
+template<class T>
+using U1 = S1<T>;
+// expected-error@first.h:* {{'DependentType::S1::x' from module 'FirstModule' is not present in definition of 'S1<T>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
- static_assert(1 == 1, "Message");
- static_assert(2 == 2);
+namespace ElaboratedType {
+#if defined(FIRST)
+namespace N1 { using type = double; }
+struct S1 {
+ N1::type x;
+};
+#elif defined(SECOND)
+namespace N1 { using type = int; }
+struct S1 {
+ N1::type x;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'ElaboratedType::S1::x' from module 'FirstModule' is not present in definition of 'ElaboratedType::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
+
+namespace Enum {
+#if defined(FIRST)
+enum A1 {};
+struct S1 {
+ A1 x;
+};
+#elif defined(SECOND)
+enum A2 {};
+struct S1 {
+ A2 x;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'Enum::S1::x' from module 'FirstModule' is not present in definition of 'Enum::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+}
+namespace NestedNamespaceSpecifier {
+#if defined(FIRST)
+namespace LevelA1 {
+using Type = int;
+}
+
+struct S1 {
+ LevelA1::Type x;
+};
+# elif defined(SECOND)
+namespace LevelB1 {
+namespace LevelC1 {
+using Type = int;
+}
+}
+
+struct S1 {
+ LevelB1::LevelC1::Type x;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'LevelB1::LevelC1::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'LevelA1::Type' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+namespace LevelA2 { using Type = int; }
+struct S2 {
+ LevelA2::Type x;
+};
+# elif defined(SECOND)
+struct S2 {
int x;
- double y;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S2' 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 'LevelA2::Type' (aka 'int')}}
+#endif
- INT z;
+namespace LevelA3 { using Type = int; }
+namespace LevelB3 { using Type = int; }
+#if defined(FIRST)
+struct S3 {
+ LevelA3::Type x;
+};
+# elif defined(SECOND)
+struct S3 {
+ LevelB3::Type x;
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'LevelB3::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'LevelA3::Type' (aka 'int')}}
+#endif
- unsigned a : 1;
- unsigned b : 2*2 + 5/2;
+#if defined(FIRST)
+struct TA4 { using Type = int; };
+struct S4 {
+ TA4::Type x;
+};
+# elif defined(SECOND)
+struct TB4 { using Type = int; };
+struct S4 {
+ TB4::Type x;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'TB4::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'TA4::Type' (aka 'int')}}
+#endif
- mutable int c = sizeof(x + y);
+#if defined(FIRST)
+struct T5 { using Type = int; };
+struct S5 {
+ T5::Type x;
+};
+# elif defined(SECOND)
+namespace T5 { using Type = int; };
+struct S5 {
+ T5::Type x;
+};
+#else
+S5 s5;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'T5::Type' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'T5::Type' (aka 'int')}}
+#endif
- 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 {}
+#if defined(FIRST)
+namespace N6 {using I = int;}
+struct S6 {
+ NestedNamespaceSpecifier::N6::I x;
+};
+# elif defined(SECOND)
+using I = int;
+struct S6 {
+ ::NestedNamespaceSpecifier::I x;
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type '::NestedNamespaceSpecifier::I' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'NestedNamespaceSpecifier::N6::I' (aka 'int')}}
+#endif
- typedef int typedef_int;
- using using_int = int;
+#if defined(FIRST)
+template <class T, class U>
+class S7 {
+ typename T::type *x = {};
+ int z = x->T::foo();
};
#elif defined(SECOND)
-typedef int INT;
-struct S {
- public:
- private:
- protected:
+template <class T, class U>
+class S7 {
+ typename T::type *x = {};
+ int z = x->U::foo();
+};
+#else
+template <class T, class U>
+using U7 = S7<T, U>;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'z' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'z' with a different initializer}}
+#endif
- static_assert(1 == 1, "Message");
- static_assert(2 == 2);
+#if defined(FIRST)
+template <class T>
+class S8 {
+ int x = T::template X<int>::value;
+};
+#elif defined(SECOND)
+template <class T>
+class S8 {
+ int x = T::template Y<int>::value;
+};
+#else
+template <class T>
+using U8 = S8<T>;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S8' 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
- int x;
- double y;
+#if defined(FIRST)
+namespace N9 { using I = int; }
+namespace O9 = N9;
+struct S9 {
+ O9::I x;
+};
+#elif defined(SECOND)
+namespace N9 { using I = int; }
+namespace P9 = N9;
+struct S9 {
+ P9::I x;
+};
+#else
+S9 s9;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'P9::I' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'O9::I' (aka 'int')}}
+#endif
- INT z;
+namespace N10 {
+#if defined(FIRST)
+inline namespace A { struct X {}; }
+struct S10 {
+ A::X x;
+};
+#elif defined(SECOND)
+inline namespace B { struct X {}; }
+struct S10 {
+ B::X x;
+};
+#else
+S10 s10;
+// expected-error@second.h:* {{'NestedNamespaceSpecifier::N10::S10::x' from module 'SecondModule' is not present in definition of 'NestedNamespaceSpecifier::N10::S10' in module 'FirstModule'}}
+// expected-note@first.h:* {{declaration of 'x' does not match}}
+#endif
+}
+}
- unsigned a : 1;
- unsigned b : 2 * 2 + 5 / 2;
+namespace TemplateSpecializationType {
+#if defined(FIRST)
+template <class T1> struct U1 {};
+struct S1 {
+ U1<int> u;
+};
+#elif defined(SECOND)
+template <class T1, class T2> struct U1 {};
+struct S1 {
+ U1<int, int> u;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'TemplateSpecializationType::S1::u' from module 'FirstModule' is not present in definition of 'TemplateSpecializationType::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'u' does not match}}
+#endif
- mutable int c = sizeof(x + y);
+#if defined(FIRST)
+template <class T1> struct U2 {};
+struct S2 {
+ U2<int> u;
+};
+#elif defined(SECOND)
+template <class T1> struct V1 {};
+struct S2 {
+ V1<int> u;
+};
+#else
+S2 s2;
+// expected-error@first.h:* {{'TemplateSpecializationType::S2::u' from module 'FirstModule' is not present in definition of 'TemplateSpecializationType::S2' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'u' does not match}}
+#endif
+}
- 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 {}
+namespace TemplateArgument {
+#if defined(FIRST)
+template <class> struct U1{};
+struct S1 {
+ U1<int> x;
+};
+#elif defined(SECOND)
+template <int> struct U1{};
+struct S1 {
+ U1<1> x;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'TemplateArgument::S1::x' from module 'FirstModule' is not present in definition of 'TemplateArgument::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
- typedef int typedef_int;
- using using_int = int;
+#if defined(FIRST)
+template <int> struct U2{};
+struct S2 {
+ using T = U2<2>;
+};
+#elif defined(SECOND)
+template <int> struct U2{};
+struct S2 {
+ using T = U2<(2)>;
};
#else
-S *s;
+S2 s2;
+// expected-error@second.h:* {{'TemplateArgument::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'T' with underlying type 'U2<(2)>'}}
+// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'U2<2>'}}
#endif
#if defined(FIRST)
-typedef int INT;
-struct T {
- public:
- private:
- protected:
+template <int> struct U3{};
+struct S3 {
+ using T = U3<2>;
+};
+#elif defined(SECOND)
+template <int> struct U3{};
+struct S3 {
+ using T = U3<1 + 1>;
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'TemplateArgument::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'T' with underlying type 'U3<1 + 1>'}}
+// expected-note@first.h:* {{but in 'FirstModule' found type alias 'T' with different underlying type 'U3<2>'}}
+#endif
- static_assert(1 == 1, "Message");
- static_assert(2 == 2);
+#if defined(FIRST)
+template<class> struct T4a {};
+template <template <class> class T> struct U4 {};
+struct S4 {
+ U4<T4a> x;
+};
+#elif defined(SECOND)
+template<class> struct T4b {};
+template <template <class> class T> struct U4 {};
+struct S4 {
+ U4<T4b> x;
+};
+#else
+S4 s4;
+// expected-error@first.h:* {{'TemplateArgument::S4::x' from module 'FirstModule' is not present in definition of 'TemplateArgument::S4' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
- int x;
- double y;
+#if defined(FIRST)
+template <class T> struct U5 {};
+struct S5 {
+ U5<int> x;
+};
+#elif defined(SECOND)
+template <class T> struct U5 {};
+struct S5 {
+ U5<short> x;
+};
+#else
+S5 s5;
+// expected-error@first.h:* {{'TemplateArgument::S5::x' from module 'FirstModule' is not present in definition of 'TemplateArgument::S5' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
- INT z;
+#if defined(FIRST)
+template <class T> struct U6 {};
+struct S6 {
+ U6<int> x;
+ U6<short> y;
+};
+#elif defined(SECOND)
+template <class T> struct U6 {};
+struct S6 {
+ U6<short> y;
+ U6<int> x;
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'TemplateArgument::S6' 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
+}
- unsigned a : 1;
- unsigned b : 2 * 2 + 5 / 2;
+namespace TemplateTypeParmType {
+#if defined(FIRST)
+template <class T1, class T2>
+struct S1 {
+ T1 x;
+};
+#elif defined(SECOND)
+template <class T1, class T2>
+struct S1 {
+ T2 x;
+};
+#else
+using TemplateTypeParmType::S1;
+// expected-error@first.h:* {{'TemplateTypeParmType::S1::x' from module 'FirstModule' is not present in definition of 'S1<T1, T2>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+template <int ...Ts>
+struct U2 {};
+template <int T, int U>
+class S2 {
+ typedef U2<U, T> type;
+ type x;
+};
+#elif defined(SECOND)
+template <int ...Ts>
+struct U2 {};
+template <int T, int U>
+class S2 {
+ typedef U2<T, U> type;
+ type x;
+};
+#else
+using TemplateTypeParmType::S2;
+// expected-error@first.h:* {{'TemplateTypeParmType::S2::x' from module 'FirstModule' is not present in definition of 'S2<T, U>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+// expected-error@first.h:* {{'TemplateTypeParmType::S2::type' from module 'FirstModule' is not present in definition of 'S2<T, U>' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'type' does not match}}
+#endif
+}
- mutable int c = sizeof(x + y);
+namespace VarDecl {
+#if defined(FIRST)
+struct S1 {
+ static int x;
+ static int y;
+};
+#elif defined(SECOND)
+struct S1 {
+ static int y;
+ static int x;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'VarDecl::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member with name 'y'}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member with name 'x'}}
+#endif
- 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 {}
+#if defined(FIRST)
+struct S2 {
+ static int x;
+};
+#elif defined(SECOND)
+using I = int;
+struct S2 {
+ static I x;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'VarDecl::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with type 'VarDecl::I' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with different type 'int'}}
+#endif
- typedef int typedef_int;
- using using_int = int;
+#if defined(FIRST)
+struct S3 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S3 {
+ static const int x;
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'VarDecl::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' without an initializer}}
+#endif
- private:
+#if defined(FIRST)
+struct S4 {
+ static const int x = 1;
};
#elif defined(SECOND)
-typedef int INT;
-struct T {
- public:
- private:
- protected:
+struct S4 {
+ static const int x = 2;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'VarDecl::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' with a different initializer}}
+#endif
- static_assert(1 == 1, "Message");
- static_assert(2 == 2);
+#if defined(FIRST)
+struct S5 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S5 {
+ static constexpr int x = 1;
+};
+#else
+S5 s5;
+// expected-error@second.h:* {{'VarDecl::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' is not constexpr}}
+// expected-note@first.h:* {{but in 'FirstModule' found data member 'x' is constexpr}}
+#endif
- int x;
- double y;
+#if defined(FIRST)
+struct S6 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S6 {
+ static const int y = 1;
+};
+#else
+S6 s6;
+// expected-error@first.h:* {{'VarDecl::S6::x' from module 'FirstModule' is not present in definition of 'VarDecl::S6' in module 'SecondModule'}}
+// expected-note@second.h:* {{definition has no member 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S7 {
+ static const unsigned x = 1;
+};
+#else
+S7 s7;
+// expected-error@first.h:* {{'VarDecl::S7::x' from module 'FirstModule' is not present in definition of 'VarDecl::S7' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+public:
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S8 {
+ static const int x = 1;
+public:
+};
+#else
+S8 s8;
+// expected-error@second.h:* {{'VarDecl::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+
+#if defined(FIRST)
+struct S9 {
+ static const int x = 1;
+};
+#elif defined(SECOND)
+struct S9 {
+ static int x;
+};
+#else
+S9 s9;
+// expected-error@first.h:* {{'VarDecl::S9::x' from module 'FirstModule' is not present in definition of 'VarDecl::S9' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+template <typename T>
+struct S {
+ struct R {
+ void foo(T x = 0) {}
+ };
+};
+#elif defined(SECOND)
+template <typename T>
+struct S {
+ struct R {
+ void foo(T x = 1) {}
+ };
+};
+#else
+void run() {
+ S<int>::R().foo();
+}
+// expected-error@second.h:* {{'VarDecl::S::R' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo' with 1st parameter with a default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'foo' with 1st parameter with a different default argument}}
+#endif
- INT z;
+#if defined(FIRST)
+template <typename alpha> struct Bravo {
+ void charlie(bool delta = false) {}
+};
+typedef Bravo<char> echo;
+echo foxtrot;
+#elif defined(SECOND)
+template <typename alpha> struct Bravo {
+ void charlie(bool delta = (false)) {}
+};
+typedef Bravo<char> echo;
+echo foxtrot;
+#else
+Bravo<char> golf;
+// expected-error@second.h:* {{'VarDecl::Bravo' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'charlie' with 1st parameter with a default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'charlie' with 1st parameter with a different default argument}}
+#endif
+}
- unsigned a : 1;
- unsigned b : 2 * 2 + 5 / 2;
+namespace Friend {
+#if defined(FIRST)
+struct T1 {};
+struct S1 {
+ friend class T1;
+};
+#elif defined(SECOND)
+struct T1 {};
+struct S1 {
+ friend T1;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Friend::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'Friend::T1'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend 'class T1'}}
+#endif
- mutable int c = sizeof(x + y);
+#if defined(FIRST)
+struct T2 {};
+struct S2 {
+ friend class T2;
+};
+#elif defined(SECOND)
+struct T2 {};
+struct S2 {
+ friend struct T2;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'Friend::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'struct T2'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend 'class T2'}}
+#endif
- 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 {}
+#if defined(FIRST)
+struct T3 {};
+struct S3 {
+ friend const T3;
+};
+#elif defined(SECOND)
+struct T3 {};
+struct S3 {
+ friend T3;
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'Friend::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'Friend::T3'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend 'const Friend::T3'}}
+#endif
- typedef int typedef_int;
- using using_int = int;
+#if defined(FIRST)
+struct T4 {};
+struct S4 {
+ friend T4;
+};
+#elif defined(SECOND)
+struct S4 {
+ friend void T4();
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Friend::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend function}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend class}}
+#endif
- public:
+#if defined(FIRST)
+struct S5 {
+ friend void T5a();
+};
+#elif defined(SECOND)
+struct S5 {
+ friend void T5b();
};
#else
+S5 s5;
+// expected-error@second.h:* {{'Friend::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend function 'T5b'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend function 'T5a'}}
+#endif
+}
+
+namespace TemplateParameters {
+#if defined(FIRST)
+template <class A>
+struct S1 {};
+#elif defined(SECOND)
+template <class B>
+struct S1 {};
+#else
+using TemplateParameters::S1;
+// expected-error@second.h:* {{'TemplateParameters::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter 'B'}}
+// expected-note@first.h:* {{but in 'FirstModule' found template parameter 'A'}}
+#endif
+
+#if defined(FIRST)
+template <class A = double>
+struct S2 {};
+#elif defined(SECOND)
+template <class A = int>
+struct S2 {};
+#else
+using TemplateParameters::S2;
+// expected-error@second.h:* {{'TemplateParameters::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found template parameter with different default argument}}
+#endif
+
+#if defined(FIRST)
+template <class A = int>
+struct S3 {};
+#elif defined(SECOND)
+template <class A>
+struct S3 {};
+#else
+using TemplateParameters::S3;
+// expected-error@second.h:* {{'TemplateParameters::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with no default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found template parameter with default argument}}
+#endif
+
+#if defined(FIRST)
+template <int A>
+struct S4 {};
+#elif defined(SECOND)
+template <int A = 2>
+struct S4 {};
+#else
+using TemplateParameters::S4;
+// expected-error@second.h:* {{'TemplateParameters::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found template parameter with no default argument}}
+#endif
+
+#if defined(FIRST)
+template <int> class S5_first {};
+template <template<int> class A = S5_first>
+struct S5 {};
+#elif defined(SECOND)
+template <int> class S5_second {};
+template <template<int> class A = S5_second>
+struct S5 {};
+#else
+using TemplateParameters::S5;
+// expected-error@second.h:* {{'TemplateParameters::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with default argument}}
+// expected-note@first.h:* {{but in 'FirstModule' found template parameter with different default argument}}
+#endif
+
+#if defined(FIRST)
+template <class A>
+struct S6 {};
+#elif defined(SECOND)
+template <class>
+struct S6 {};
+#else
+using TemplateParameters::S6;
+// expected-error@second.h:* {{'TemplateParameters::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found unnamed template parameter}}
+// expected-note@first.h:* {{but in 'FirstModule' found template parameter 'A'}}
+#endif
+} // namespace TemplateParameters
+
+namespace BaseClass {
+#if defined(FIRST)
+struct B1 {};
+struct S1 : B1 {};
+#elif defined(SECOND)
+struct S1 {};
+#else
+S1 s1;
+// expected-error@second.h:* {{'BaseClass::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found 0 base classes}}
+// expected-note@first.h:* {{but in 'FirstModule' found 1 base class}}
+#endif
+
+#if defined(FIRST)
+struct S2 {};
+#elif defined(SECOND)
+struct B2 {};
+struct S2 : virtual B2 {};
+#else
+S2 s2;
+// expected-error@second.h:* {{'BaseClass::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 base class}}
+// expected-note@first.h:* {{but in 'FirstModule' found 0 base classes}}
+#endif
+
+#if defined(FIRST)
+struct B3a {};
+struct S3 : B3a {};
+#elif defined(SECOND)
+struct B3b {};
+struct S3 : virtual B3b {};
+#else
+S3 s3;
+// expected-error@second.h:* {{'BaseClass::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 virtual base class}}
+// expected-note@first.h:* {{but in 'FirstModule' found 0 virtual base classes}}
+#endif
+
+#if defined(FIRST)
+struct B4a {};
+struct S4 : B4a {};
+#elif defined(SECOND)
+struct B4b {};
+struct S4 : B4b {};
+#else
+S4 s4;
+// expected-error@second.h:* {{'BaseClass::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class with type 'BaseClass::B4b'}}
+// expected-note@first.h:* {{but in 'FirstModule' found 1st base class with different type 'BaseClass::B4a'}}
+#endif
+
+#if defined(FIRST)
+struct B5a {};
+struct S5 : virtual B5a {};
+#elif defined(SECOND)
+struct B5a {};
+struct S5 : B5a {};
+#else
+S5 s5;
+// expected-error@second.h:* {{'BaseClass::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found 0 virtual base classes}}
+// expected-note@first.h:* {{but in 'FirstModule' found 1 virtual base class}}
+#endif
+
+#if defined(FIRST)
+struct B6a {};
+struct S6 : B6a {};
+#elif defined(SECOND)
+struct B6a {};
+struct S6 : virtual B6a {};
+#else
+S6 s6;
+// expected-error@second.h:* {{'BaseClass::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 virtual base class}}
+// expected-note@first.h:* {{but in 'FirstModule' found 0 virtual base classes}}
+#endif
+
+#if defined(FIRST)
+struct B7a {};
+struct S7 : protected B7a {};
+#elif defined(SECOND)
+struct B7a {};
+struct S7 : B7a {};
+#else
+S7 s7;
+// expected-error@second.h:* {{'BaseClass::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B7a' with no access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B7a' with protected access specifier}}
+#endif
+
+#if defined(FIRST)
+struct B8a {};
+struct S8 : public B8a {};
+#elif defined(SECOND)
+struct B8a {};
+struct S8 : private B8a {};
+#else
+S8 s8;
+// expected-error@second.h:* {{'BaseClass::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B8a' with private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B8a' with public access specifier}}
+#endif
+
+#if defined(FIRST)
+struct B9a {};
+struct S9 : private B9a {};
+#elif defined(SECOND)
+struct B9a {};
+struct S9 : public B9a {};
+#else
+S9 s9;
+// expected-error@second.h:* {{'BaseClass::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B9a' with public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B9a' with private access specifier}}
+#endif
+
+#if defined(FIRST)
+struct B10a {};
+struct S10 : B10a {};
+#elif defined(SECOND)
+struct B10a {};
+struct S10 : protected B10a {};
+#else
+S10 s10;
+// expected-error@second.h:* {{'BaseClass::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B10a' with protected access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B10a' with no access specifier}}
+#endif
+} // namespace BaseClass
+
+// 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 {
+#define CREATE_ALL_DECL_STRUCT(NAME, ACCESS) \
+ typedef int INT; \
+ struct NAME { \
+ 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; \
+ \
+ void method_one_arg(int x) {} \
+ void method_one_arg_default_argument(int x = 5 + 5) {} \
+ void method_decayed_type(int x[5]) {} \
+ \
+ int constant_arr[5]; \
+ \
+ ACCESS: \
+ };
+
+#if defined(FIRST)
+CREATE_ALL_DECL_STRUCT(S, public)
+#elif defined(SECOND)
+CREATE_ALL_DECL_STRUCT(S, public)
+#else
+S *s;
+#endif
+
+#if defined(FIRST)
+CREATE_ALL_DECL_STRUCT(T, private)
+#elif defined(SECOND)
+CREATE_ALL_DECL_STRUCT(T, 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}}
@@ -944,6 +2037,159 @@ T t;
#endif
} // namespace StructWithForwardDeclarationNoDefinition
+namespace LateParsedDefaultArgument {
+#if defined(FIRST)
+template <typename T>
+struct S {
+ struct R {
+ void foo(T x = 0) {}
+ };
+};
+#elif defined(SECOND)
+#else
+void run() {
+ S<int>::R().foo();
+}
+#endif
+}
+
+namespace LateParsedDefaultArgument {
+#if defined(FIRST)
+template <typename alpha> struct Bravo {
+ void charlie(bool delta = false) {}
+};
+typedef Bravo<char> echo;
+echo foxtrot;
+
+Bravo<char> golf;
+#elif defined(SECOND)
+#else
+#endif
+}
+
+namespace DifferentParameterNameInTemplate {
+#if defined(FIRST) || defined(SECOND)
+template <typename T>
+struct S {
+ typedef T Type;
+
+ static void Run(const Type *name_one);
+};
+
+template <typename T>
+void S<T>::Run(const T *name_two) {}
+
+template <typename T>
+struct Foo {
+ ~Foo() { Handler::Run(nullptr); }
+ Foo() {}
+
+ class Handler : public S<T> {};
+
+ void Get(typename Handler::Type *x = nullptr) {}
+ void Add() { Handler::Run(nullptr); }
+};
+#endif
+
+#if defined(FIRST)
+struct Beta;
+
+struct Alpha {
+ Alpha();
+ void Go() { betas.Get(); }
+ Foo<Beta> betas;
+};
+
+#elif defined(SECOND)
+struct Beta {};
+
+struct BetaHelper {
+ void add_Beta() { betas.Add(); }
+ Foo<Beta> betas;
+};
+
+#else
+Alpha::Alpha() {}
+#endif
+}
+
+namespace ParameterTest {
+#if defined(FIRST)
+class X {};
+template <typename G>
+class S {
+ public:
+ typedef G Type;
+ static inline G *Foo(const G *a, int * = nullptr);
+};
+
+template<typename G>
+G* S<G>::Foo(const G* aaaa, int*) {}
+#elif defined(SECOND)
+template <typename G>
+class S {
+ public:
+ typedef G Type;
+ static inline G *Foo(const G *a, int * = nullptr);
+};
+
+template<typename G>
+G* S<G>::Foo(const G* asdf, int*) {}
+#else
+S<X> s;
+#endif
+}
+
+namespace MultipleTypedefs {
+#if defined(FIRST)
+typedef int B1;
+typedef B1 A1;
+struct S1 {
+ A1 x;
+};
+#elif defined(SECOND)
+typedef int A1;
+struct S1 {
+ A1 x;
+};
+#else
+S1 s1;
+#endif
+
+#if defined(FIRST)
+struct T2 { int x; };
+typedef T2 B2;
+typedef B2 A2;
+struct S2 {
+ T2 x;
+};
+#elif defined(SECOND)
+struct T2 { int x; };
+typedef T2 A2;
+struct S2 {
+ T2 x;
+};
+#else
+S2 s2;
+#endif
+
+#if defined(FIRST)
+using A3 = const int;
+using B3 = volatile A3;
+struct S3 {
+ B3 x = 1;
+};
+#elif defined(SECOND)
+using A3 = volatile const int;
+using B3 = A3;
+struct S3 {
+ B3 x = 1;
+};
+#else
+S3 s3;
+#endif
+}
+
// Keep macros contained to one file.
#ifdef FIRST
#undef FIRST
diff --git a/test/Modules/outofdate-rebuild.m b/test/Modules/outofdate-rebuild.m
new file mode 100644
index 0000000000..510325f62d
--- /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/path-resolution.modulemap b/test/Modules/path-resolution.modulemap
new file mode 100644
index 0000000000..72f5f142c3
--- /dev/null
+++ b/test/Modules/path-resolution.modulemap
@@ -0,0 +1,70 @@
+// RUN: rm -rf %t
+//
+// First, create two modules a and b, with a dependency b -> a, both within
+// the same directory p1.
+//
+// RUN: mkdir -p %t/p1
+// RUN: cd %t/p1
+//
+// RUN: grep "<AM>" %s > %t/p1/a.modulemap
+// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fmodule-map-file-home-is-cwd \
+// RUN: -fmodules-embed-all-files -fmodules-local-submodule-visibility \
+// RUN: -fmodule-name="a" -o a.pcm a.modulemap
+//
+// RUN: grep "<BM>" %s > %t/p1/b.modulemap
+// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fmodule-map-file-home-is-cwd \
+// RUN: -fmodules-embed-all-files -fmodules-local-submodule-visibility \
+// RUN: -fmodule-name="b" -o b.pcm b.modulemap
+//
+// Next, move the whole tree p1 -> p2.
+//
+// RUN: cd %t
+// RUN: mv %t/p1 %t/p2
+// RUN: cd %t/p2
+//
+// Compile a new module c in the newly generated tree that depends on b; c.pcm
+// has to be within a subdirectory so a.modulemap will be one step up (../) from
+// c.pcm.
+//
+// RUN: mkdir %t/p2/c
+// RUN: grep "<CM>" %s > %t/p2/c/c.modulemap
+// RUN: grep "<CH>" %s > %t/p2/c/c.h
+// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fmodule-map-file-home-is-cwd \
+// RUN: -fmodules-embed-all-files -fmodules-local-submodule-visibility \
+// RUN: -fmodule-name="c" -fmodule-file=b.pcm -o c/c.pcm c/c.modulemap
+//
+// Delete a.modulemap from its original location, and instead inject a different
+// (unrelated) a.modulemap in the path p2/p2.
+//
+// RUN: rm %t/p2/a.modulemap
+// RUN: mkdir -p %t/p2/p2
+// RUN: touch %t/p2/p2/a.modulemap
+//
+// Now compile a file c.cpp that uses c.h and the module c; it is important
+// to first load b.pcm and a.pcm before c.pcm on the command line to trigger
+// the right order of module loading. This used to trigger clang to find the
+// p2/p2/a.modulemap via the path c/../p2/a.modulemap, which is not the correct
+// relative path from c.
+//
+// RUN: grep "<CC>" %s > %t/p2/c/c.cpp
+// RUN: %clang_cc1 -I. -x c++ -fmodules \
+// RUN: -fmodule-file=b.pcm -fmodule-file=a.pcm -fmodule-file=c/c.pcm \
+// RUN: -o c/c.o -emit-obj c/c.cpp
+
+module "a" { // <AM>
+} // <AM>
+
+module "b" { // <BM>
+ use "a" // <BM>
+} // <BM>
+
+module "c" { // <CM>
+ header "c/c.h" // <CM>
+ use "a" // <CM>
+ use "b" // <CM>
+} // <CM>
+
+inline void c() {} // <CH>
+
+#include "c/c.h" // <CC>
+void foo() { c(); } // <CC>
diff --git a/test/Modules/pragma-pack.cpp b/test/Modules/pragma-pack.cpp
new file mode 100644
index 0000000000..96a880c630
--- /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/preprocess-build-diamond.m b/test/Modules/preprocess-build-diamond.m
new file mode 100644
index 0000000000..b031a0a914
--- /dev/null
+++ b/test/Modules/preprocess-build-diamond.m
@@ -0,0 +1,26 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -E -o %t/diamond.mi -frewrite-imports
+// RUN: FileCheck %s --input-file %t/diamond.mi
+// RUN: %clang_cc1 -fmodules %t/diamond.mi -I. -verify
+
+// CHECK: {{^}}#pragma clang module build diamond_top
+// CHECK: {{^}}module diamond_top {
+// CHECK: {{^}}#pragma clang module contents
+
+// FIXME: @import does not work under -frewrite-includes / -frewrite-imports
+// because we disable it when macro expansion is disabled.
+#include "diamond_bottom.h"
+
+// expected-no-diagnostics
+void test_diamond(int i, float f, double d, char c) {
+ top(&i);
+ left(&f);
+ right(&d);
+ bottom(&c);
+ top_left(&c);
+ left_and_right(&i);
+ struct left_and_right lr;
+ lr.left = 17;
+}
+
diff --git a/test/Modules/preprocess-build.cpp b/test/Modules/preprocess-build.cpp
new file mode 100644
index 0000000000..36a0740a0a
--- /dev/null
+++ b/test/Modules/preprocess-build.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++1z -fmodules %s -verify
+
+#pragma clang module build baz
+ module baz {}
+#pragma clang module endbuild // baz
+
+#pragma clang module build foo
+ module foo { module bar {} }
+#pragma clang module contents
+ #pragma clang module begin foo.bar
+
+ // Can import baz here even though it was created in an outer build.
+ #pragma clang module import baz
+
+ #pragma clang module build bar
+ module bar {}
+ #pragma clang module contents
+ #pragma clang module begin bar
+ extern int n;
+ #pragma clang module end
+ #pragma clang module endbuild // bar
+
+ #pragma clang module import bar
+
+ constexpr int *f() { return &n; }
+
+ #pragma clang module end
+#pragma clang module endbuild // foo
+
+#pragma clang module import bar
+#pragma clang module import foo.bar
+static_assert(f() == &n);
+
+#pragma clang module build // expected-error {{expected module name}}
+#pragma clang module build unterminated // expected-error {{no matching '#pragma clang module endbuild'}}
diff --git a/test/Modules/preprocess-decluse.cpp b/test/Modules/preprocess-decluse.cpp
new file mode 100644
index 0000000000..5c87e0ddda
--- /dev/null
+++ b/test/Modules/preprocess-decluse.cpp
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \
+// RUN: -fmodule-name=B -emit-module -o %t/b.pcm \
+// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/a.modulemap \
+// RUN: -x c++-module-map %S/Inputs/preprocess-decluse/b.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \
+// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/main.modulemap \
+// RUN: -fmodule-file=%t/b.pcm -fmodule-name=Main %s -verify
+// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \
+// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/main.modulemap \
+// RUN: -fmodule-file=%t/b.pcm -fmodule-name=Main %s \
+// RUN: -E -frewrite-imports -o %t/rewrite.ii
+// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \
+// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/main.modulemap \
+// RUN: -fmodule-name=Main %t/rewrite.ii -verify
+
+// expected-no-diagnostics
+#include "b.h"
diff --git a/test/Modules/preprocess-missing.modulemap b/test/Modules/preprocess-missing.modulemap
new file mode 100644
index 0000000000..300494672f
--- /dev/null
+++ b/test/Modules/preprocess-missing.modulemap
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fmodules -fmodule-name=A -x c++-module-map %s -emit-module -o /dev/null -verify
+module A {
+ header "does not exist" { size 12345 } // ok, do not need mtime for explicit module build
+ header "also does not exist" { mtime 12345 }
+}
+#pragma clang module contents
+// expected-error@4 {{cannot emit module A: size must be explicitly specified for missing header file "also does not exist"}}
diff --git a/test/Modules/preprocess-module.cpp b/test/Modules/preprocess-module.cpp
new file mode 100644
index 0000000000..b0cbac18e7
--- /dev/null
+++ b/test/Modules/preprocess-module.cpp
@@ -0,0 +1,159 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+
+// RUN: not %clang_cc1 -fmodules -fmodule-name=file -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E 2>&1 | FileCheck %s --check-prefix=MISSING-FWD
+// MISSING-FWD: module 'fwd' is needed
+
+// RUN: %clang_cc1 -fmodules -fmodule-name=fwd -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -emit-module -o %t/fwd.pcm
+
+// Check that we can preprocess modules, and get the expected output.
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E -o %t/no-rewrite.ii
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E -frewrite-includes -o %t/rewrite.ii
+//
+// RUN: FileCheck %s --input-file %t/no-rewrite.ii --check-prefix=CHECK --check-prefix=NO-REWRITE
+// RUN: FileCheck %s --input-file %t/rewrite.ii --check-prefix=CHECK --check-prefix=REWRITE
+
+// Check that we can build a module from the preprocessed output.
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -x c++-module-map-cpp-output %t/no-rewrite.ii -emit-module -o %t/no-rewrite.pcm
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -x c++-module-map-cpp-output %t/rewrite.ii -emit-module -o %t/rewrite.pcm
+
+// Check that we can load the original module map in the same compilation (this
+// could happen if we had a redundant -fmodule-map-file= in the original
+// build).
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -fmodule-map-file=%S/Inputs/preprocess/module.modulemap -x c++-module-map-cpp-output %t/rewrite.ii -emit-module -o /dev/null
+
+// Check the module we built works.
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.pcm %s -I%t -verify -fno-modules-error-recovery
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DREWRITE
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DINCLUDE -I%S/Inputs/preprocess
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DREWRITE -DINCLUDE -I%S/Inputs/preprocess
+
+// Now try building the module when the header files are missing.
+// RUN: cp %S/Inputs/preprocess/fwd.h %S/Inputs/preprocess/file.h %S/Inputs/preprocess/file2.h %S/Inputs/preprocess/other.h %S/Inputs/preprocess/module.modulemap %t
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -I%t -x c++-module-map %t/module.modulemap -E -frewrite-includes -o %t/copy.ii
+// RUN: rm %t/fwd.h %t/file.h %t/file2.h %t/other.h %t/module.modulemap
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -x c++-module-map-cpp-output %t/copy.ii -emit-module -o %t/copy.pcm
+
+// Check that our module contains correct mapping information for the headers.
+// RUN: cp %S/Inputs/preprocess/fwd.h %S/Inputs/preprocess/file.h %S/Inputs/preprocess/file2.h %S/Inputs/preprocess/other.h %S/Inputs/preprocess/module.modulemap %t
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/copy.pcm %s -I%t -verify -fno-modules-error-recovery -DCOPY -DINCLUDE
+// RUN: rm %t/fwd.h %t/file.h %t/file2.h %t/other.h %t/module.modulemap
+
+// Check that we can preprocess from a .pcm file and that we get the same result as preprocessing from the original sources.
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -emit-module -o %t/file.pcm
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -I%S/Inputs/preprocess %t/file.pcm -E -frewrite-includes -o %t/file.rewrite.ii
+// FIXME: This check fails on Windows targets, due to canonicalization of directory separators.
+// FIXME: cmp %t/rewrite.ii %t/file.rewrite.ii
+// FIXME: Instead, just check that the preprocessed output is functionally equivalent to the output when preprocessing from the original sources.
+// RUN: FileCheck %s --input-file %t/file.rewrite.ii --check-prefix=CHECK --check-prefix=REWRITE
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -x c++-module-map-cpp-output %t/file.rewrite.ii -emit-module -o %t/file.rewrite.pcm
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/file.rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DFILE_REWRITE
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/file.rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DFILE_REWRITE -DINCLUDE -I%S/Inputs/preprocess
+//
+// Check that we can preprocess this user of the .pcm file.
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/file.pcm %s -I%t -E -frewrite-imports -o %t/preprocess-module.ii
+// RUN: %clang_cc1 -fmodules %t/preprocess-module.ii -verify -fno-modules-error-recovery -DFILE_REWRITE_FULL
+//
+// Check that language / header search options are ignored when preprocessing from a .pcm file.
+// RUN: %clang_cc1 %t/file.pcm -E -frewrite-includes -o %t/file.rewrite.ii.2
+// RUN: cmp %t/file.rewrite.ii %t/file.rewrite.ii.2
+//
+// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm -I%S/Inputs/preprocess %t/file.pcm -E -o %t/file.no-rewrite.ii
+// RUN: %clang_cc1 %t/file.pcm -E -o %t/file.no-rewrite.ii.2 -Dstruct=error
+// RUN: cmp %t/file.no-rewrite.ii %t/file.no-rewrite.ii.2
+
+// == module map
+// CHECK: # 1 "{{.*}}module.modulemap"
+// CHECK: module file {
+// CHECK: header "file.h" { size
+// CHECK: header "file2.h" { size
+// CHECK: }
+
+// == file.h
+// CHECK: # 1 "<module-includes>"
+// REWRITE: #if 0
+// REWRITE: #include "file.h"
+// REWRITE: #endif
+//
+// FIXME: It would be preferable to consistently put the module begin/end in
+// the same file, but the relative ordering of PP callbacks and module
+// begin/end tokens makes that difficult.
+//
+// REWRITE: #pragma clang module begin file
+// CHECK: # 1 "{{.*}}file.h" 1
+// NO-REWRITE: #pragma clang module begin file
+//
+// REWRITE: #ifndef FILE_H
+// REWRITE: #define FILE_H
+//
+// CHECK: #pragma clang module import fwd /* clang {{-E|-frewrite-includes}}: implicit import
+// CHECK: typedef struct __FILE FILE;
+//
+// REWRITE: #endif
+//
+// REWRITE: #pragma clang module end
+// CHECK: # 2 "<module-includes>" 2
+// NO-REWRITE: #pragma clang module end
+
+// == file2.h
+// REWRITE: #if 0
+// REWRITE: #include "file2.h"
+// REWRITE: #endif
+//
+// REWRITE: #pragma clang module begin file
+// CHECK: # 1 "{{.*}}file2.h" 1
+// NO-REWRITE: #pragma clang module begin file
+//
+// ==== recursively re-enter file.h
+// REWRITE: #if 0
+// REWRITE: #include "file.h"
+// REWRITE: #endif
+//
+// REWRITE: #pragma clang module begin file
+// CHECK: # 1 "{{.*}}file.h" 1
+// NO-REWRITE: #pragma clang module begin file
+//
+// REWRITE: #ifndef FILE_H
+// REWRITE: #define FILE_H
+// REWRITE: #if 0
+// REWRITE: #include "fwd.h"
+// REWRITE: #endif
+// REWRITE-NOT: #pragma clang module import fwd
+// REWRITE: #endif
+//
+// NO-REWRITE-NOT: struct __FILE;
+//
+// REWRITE: #pragma clang module end
+// CHECK: # 2 "{{.*}}file2.h" 2
+// NO-REWRITE: #pragma clang module end
+// NO-REWRITE: # 2 "{{.*}}file2.h"{{$}}
+// ==== return to file2.h
+//
+// CHECK: extern int file2;
+//
+// REWRITE: #pragma clang module end
+// CHECK: # 3 "<module-includes>" 2
+// NO-REWRITE: #pragma clang module end
+
+
+__FILE *a; // expected-error-re {{{{declaration of '__FILE' must be imported|unknown type name '__FILE'}}}}
+#if FILE_REWRITE
+// expected-note@file.rewrite.ii:* {{here}}
+#elif FILE_REWRITE_FULL
+// No note diagnostic at all in this case: we've built the 'file' module but not loaded it into this compilation yet.
+#elif REWRITE
+// expected-note@rewrite.ii:* {{here}}
+#elif COPY
+// expected-note@copy.ii:* {{here}}
+#else
+// expected-note@no-rewrite.ii:* {{here}}
+#endif
+
+#ifdef INCLUDE
+#include "file.h"
+#else
+#pragma clang module import file
+#endif
+
+FILE *b;
+int x = file2; // ok, found in file2.h, even under -DINCLUDE
diff --git a/test/Modules/preprocess-nested.cpp b/test/Modules/preprocess-nested.cpp
new file mode 100644
index 0000000000..f26b65507e
--- /dev/null
+++ b/test/Modules/preprocess-nested.cpp
@@ -0,0 +1,57 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-name=nested -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E -o %t/no-rewrite.ii
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-name=nested -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E -frewrite-includes -o %t/rewrite.ii
+
+// RUN: FileCheck %s --input-file %t/no-rewrite.ii --check-prefix=CHECK --check-prefix=NO-REWRITE
+// RUN: FileCheck %s --input-file %t/rewrite.ii --check-prefix=CHECK --check-prefix=REWRITE
+
+// Check that we can build a module from the preprocessed output.
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-name=nested -x c++-module-map-cpp-output %t/no-rewrite.ii -emit-module -o %t/no-rewrite.pcm
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fmodule-name=nested -x c++-module-map-cpp-output %t/rewrite.ii -emit-module -o %t/rewrite.pcm
+
+// Check the module we built works.
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.pcm %s -I%t -verify -fno-modules-error-recovery
+// RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -I%t -verify -fno-modules-error-recovery -DREWRITE
+
+// == module map
+// CHECK: # 1 "{{.*}}module.modulemap"
+// CHECK: module nested {
+// CHECK: module a {
+// CHECK: header "a.h"
+// CHECK: }
+// CHECK: module b {
+// CHECK: header "b.h"
+// CHECK: }
+// CHECK: module c {
+// CHECK: header "c.h"
+// CHECK: }
+// CHECK: }
+
+// CHECK: #pragma clang module begin nested.a
+// CHECK: #pragma clang module begin nested.c
+// CHECK: using T = int;
+// CHECK: #pragma clang module end
+// CHECK: T a();
+// CHECK: #pragma clang module end
+
+// CHECK: #pragma clang module begin nested.b
+// CHECK: #pragma clang module import nested.c
+// CHECK-NOT: #pragma clang module begin nested.c
+// CHECK-NOT: using T = int;
+// CHECK-NOT: #pragma clang module end
+// CHECK: T b();
+// CHECK: #pragma clang module end
+
+// CHECK: #pragma clang module import nested.c
+
+#pragma clang module import nested.b
+
+int n = b();
+T c; // expected-error {{must be imported}}
+#ifdef REWRITE
+// expected-note@rewrite.ii:* {{declar}}
+#else
+// expected-note@no-rewrite.ii:* {{declar}}
+#endif
diff --git a/test/Modules/preprocess-unavailable.cpp b/test/Modules/preprocess-unavailable.cpp
new file mode 100644
index 0000000000..cfd18253da
--- /dev/null
+++ b/test/Modules/preprocess-unavailable.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -x c++-module-map %s -fmodule-name=a -verify -std=c++98
+module a {
+ module b {
+ requires cplusplus11
+ }
+}
+#pragma clang module contents
+// expected-error@3 {{module 'a.b' requires feature 'cplusplus11'}}
+#pragma clang module begin a.b // expected-note {{entering module 'a' due to this pragma}}
+int f();
+int g() { f(); }
+#pragma clang module end // expected-error {{no matching '#pragma clang module begin'}}
diff --git a/test/Modules/preprocess.cpp b/test/Modules/preprocess.cpp
index 0615331c8b..d855fed62d 100644
--- a/test/Modules/preprocess.cpp
+++ b/test/Modules/preprocess.cpp
@@ -1,24 +1,30 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x c++ -E %s | \
-// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=CXX --check-prefix=CXX-DASHE
+// RUN: FileCheck -strict-whitespace %s
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x objective-c -E %s | \
-// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=OBJC
+// RUN: FileCheck -strict-whitespace %s
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x c++ -E -frewrite-includes %s | \
-// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=CXX
+// RUN: FileCheck -strict-whitespace %s --check-prefix=REWRITE
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs -x objective-c -E -frewrite-includes %s | \
-// RUN: FileCheck -strict-whitespace %s --check-prefix=CHECK --check-prefix=OBJC
+// RUN: FileCheck -strict-whitespace %s --check-prefix=REWRITE
#include "dummy.h"
#include "dummy.h"
foo bar baz
-// The weird {{ }} here is to prevent the -frewrite-includes test from matching its own CHECK lines.
+// EOF marker to ensure -frewrite-includes doesn't match its own CHECK lines.
-// CXX: #include{{ }}"dummy.h"
-// CXX-DASHE-SAME: /* clang -E: implicit import for module dummy */
-// CXX: #include{{ }}"dummy.h"
-// CXX-DASHE-SAME: /* clang -E: implicit import for module dummy */
-// CXX: foo bar baz
+// REWRITE: #if 0
+// REWRITE: #include{{ }}"dummy.h"
+// REWRITE: #endif
-// OBJC: @import{{ }}dummy; /* clang
-// OBJC: @import{{ }}dummy; /* clang
-// OBJC: foo bar baz
+// CHECK: #pragma clang module import dummy /* clang {{.*}} implicit import
+
+// REWRITE: #if 0
+// REWRITE: #include{{ }}"dummy.h"
+// REWRITE: #endif
+
+// CHECK: #pragma clang module import dummy /* clang {{.*}} implicit import
+
+// CHECK: foo bar baz
+
+// REWRITE: // {{EOF}} marker
diff --git a/test/Modules/preprocess.m b/test/Modules/preprocess.m
index 8d740d1de2..37a68154d2 100644
--- a/test/Modules/preprocess.m
+++ b/test/Modules/preprocess.m
@@ -16,11 +16,11 @@ void test() {
// CHECK: int left_and_right(int *);{{$}}
-// CHECK-NEXT: @import diamond_left; /* clang -E: implicit import for "{{.*}}diamond_left.h" */{{$}}
+// CHECK-NEXT: #pragma clang module import diamond_left /* clang -E: implicit import for #import "diamond_left.h" */{{$}}
-// CHECK: @import diamond_right; /* clang -E: implicit import for "{{.*}}diamond_right.h" */{{$}}
-// CHECK: @import diamond_right; /* clang -E: implicit import for "{{.*}}diamond_right.h" */{{$}}
-// CHECK: @import file; /* clang -E: implicit import for "{{.*}}file.h" */{{$}}
+// CHECK: #pragma clang module import diamond_right /* clang -E: implicit import for #import "diamond_right.h" */{{$}}
+// CHECK: #pragma clang module import diamond_right /* clang -E: implicit import for #import "diamond_right.h" */{{$}}
+// CHECK: #pragma clang module import file /* clang -E: implicit import for #include "file.h" */{{$}}
// CHECK-NEXT: void test() {{{$}}
// CHECK-NEXT: top_left_before();{{$}}
// CHECK-NEXT: left_and_right();{{$}}
diff --git a/test/Modules/redefinition-c-tagtypes.m b/test/Modules/redefinition-c-tagtypes.m
new file mode 100644
index 0000000000..a01f11bd74
--- /dev/null
+++ b/test/Modules/redefinition-c-tagtypes.m
@@ -0,0 +1,48 @@
+// RUN: rm -rf %t.cache
+// RUN: %clang_cc1 -fsyntax-only %s -fmodules -fmodules-cache-path=%t.cache \
+// RUN: -fimplicit-module-maps -F%S/Inputs -verify
+// RUN: %clang_cc1 -fsyntax-only %s -fmodules -fmodules-cache-path=%t.cache \
+// RUN: -fimplicit-module-maps -F%S/Inputs -DCHANGE_TAGS -verify
+#include "F/F.h"
+
+#ifndef CHANGE_TAGS
+// expected-no-diagnostics
+#endif
+
+struct NS {
+ int a;
+#ifndef CHANGE_TAGS
+ int b;
+#else
+ int c; // expected-note {{field has name 'c' here}}
+ // expected-error@redefinition-c-tagtypes.m:12 {{type 'struct NS' has incompatible definitions}}
+ // expected-note@Inputs/F.framework/PrivateHeaders/NS.h:3 {{field has name 'b' here}}
+#endif
+};
+
+enum NSE {
+ FST = 22,
+#ifndef CHANGE_TAGS
+ SND = 43,
+#else
+ SND = 44, // expected-note {{enumerator 'SND' with value 44 here}}
+ // expected-error@redefinition-c-tagtypes.m:23 {{type 'enum NSE' has incompatible definitions}}
+ // expected-note@Inputs/F.framework/PrivateHeaders/NS.h:8 {{enumerator 'SND' with value 43 here}}
+#endif
+ TRD = 55
+};
+
+#define NS_ENUM(_type, _name) \
+ enum _name : _type _name; \
+ enum _name : _type
+
+typedef NS_ENUM(int, NSMyEnum) {
+ MinX = 11,
+#ifndef CHANGE_TAGS
+ MinXOther = MinX,
+#else
+ MinXOther = TRD, // expected-note {{enumerator 'MinXOther' with value 55 here}}
+ // expected-error@redefinition-c-tagtypes.m:39 {{type 'enum NSMyEnum' has incompatible definitions}}
+ // expected-note@Inputs/F.framework/PrivateHeaders/NS.h:18 {{enumerator 'MinXOther' with value 11 here}}
+#endif
+};
diff --git a/test/Modules/redefinition-same-header.m b/test/Modules/redefinition-same-header.m
new file mode 100644
index 0000000000..8c180f6432
--- /dev/null
+++ b/test/Modules/redefinition-same-header.m
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t.tmp
+// RUN: %clang_cc1 -fsyntax-only -I %S/Inputs/SameHeader -fmodules \
+// RUN: -fimplicit-module-maps -fmodules-cache-path=%t.tmp %s -verify
+
+// expected-error@Inputs/SameHeader/C.h:3 {{redefinition of 'c'}}
+// expected-note-re@Inputs/SameHeader/B.h:3 {{'{{.*}}C.h' included multiple times, additional include site in header from module 'X.B'}}
+// expected-note@Inputs/SameHeader/module.modulemap:6 {{X.B defined here}}
+// expected-note-re@redefinition-same-header.m:20 {{'{{.*}}C.h' included multiple times, additional include site here}}
+// expected-warning@Inputs/SameHeader/C.h:9 {{typedef requires a name}}
+
+#include "A.h" // maps to a modular
+#include "C.h" // textual include
diff --git a/test/Modules/relative-dep-gen.cpp b/test/Modules/relative-dep-gen.cpp
index e58dd6eb35..bfa9471859 100644
--- a/test/Modules/relative-dep-gen.cpp
+++ b/test/Modules/relative-dep-gen.cpp
@@ -2,17 +2,17 @@
// RUN: rm -rf %t
// RUN: mkdir %t
//
-// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen.modulemap -dependency-file %t/build.d -MT mod.pcm -o %t/mod.pcm
-// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen.modulemap -fmodule-file=%t/mod.pcm -dependency-file %t/use-explicit.d -MT use.o relative-dep-gen.cpp -fsyntax-only
-// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen.modulemap -dependency-file %t/use-implicit.d relative-dep-gen.cpp -MT use.o -fsyntax-only
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen.modulemap -dependency-file %t/build.d -MT mod.pcm -o %t/mod.pcm
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen.modulemap -fmodule-file=%t/mod.pcm -dependency-file %t/use-explicit.d -MT use.o relative-dep-gen.cpp -fsyntax-only
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=Inputs/relative-dep-gen.modulemap -dependency-file %t/use-implicit.d relative-dep-gen.cpp -MT use.o -fsyntax-only
//
// RUN: FileCheck --check-prefix=CHECK-BUILD %s < %t/build.d
-// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit.d
-// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-implicit.d
+// RUN: FileCheck --check-prefix=CHECK-USE --check-prefix=CHECK-EXPLICIT %s < %t/use-explicit.d
+// RUN: FileCheck --check-prefix=CHECK-USE --check-prefix=CHECK-IMPLICIT %s < %t/use-implicit.d
//
-// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/build-cwd.d -MT mod.pcm -o %t/mod-cwd.pcm -fmodule-map-file-home-is-cwd
-// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd
-// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/use-implicit-cwd.d relative-dep-gen.cpp -MT use.o -fsyntax-only -fmodule-map-file-home-is-cwd
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/build-cwd.d -MT mod.pcm -o %t/mod-cwd.pcm -fmodule-map-file-home-is-cwd
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/use-implicit-cwd.d relative-dep-gen.cpp -MT use.o -fsyntax-only -fmodule-map-file-home-is-cwd
//
// RUN: FileCheck --check-prefix=CHECK-BUILD %s < %t/build-cwd.d
// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit-cwd.d
@@ -23,7 +23,7 @@
// RUN: cp %S/Inputs/relative-dep-gen-1.h %t/Inputs
// RUN: cp %s %t
// RUN: cd %t
-// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-no-map-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd
+// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-no-map-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd
// RUN: cat %t/use-explicit-no-map-cwd.d
// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit-no-map-cwd.d
@@ -35,4 +35,5 @@
// CHECK-BUILD: {{[ \t]}}Inputs/relative-dep-gen-2.h
// CHECK-USE: use.o:
// CHECK-USE-DAG: {{[ \t]}}relative-dep-gen.cpp
-// CHECK-USE-DAG: {{[ \t]}}Inputs{{[/\\]}}relative-dep-gen-1.h
+// CHECK-EXPLICIT-DAG: mod.pcm
+// CHECK-IMPLICIT-DAG: {{[ \t]}}Inputs{{[/\\]}}relative-dep-gen-1.h
diff --git a/test/Modules/requires-coroutines.mm b/test/Modules/requires-coroutines.mm
new file mode 100644
index 0000000000..8e25a3c575
--- /dev/null
+++ b/test/Modules/requires-coroutines.mm
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs -I %S/Inputs/DependsOnModule.framework %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs -I %S/Inputs/DependsOnModule.framework %s -verify -fcoroutines-ts -DCOROUTINES
+
+#ifdef COROUTINES
+@import DependsOnModule.Coroutines;
+// expected-error@module.map:29 {{module 'DependsOnModule.NotCoroutines' is incompatible with feature 'coroutines'}}
+@import DependsOnModule.NotCoroutines; // expected-note {{module imported here}}
+#else
+@import DependsOnModule.NotCoroutines;
+// expected-error@module.map:25 {{module 'DependsOnModule.Coroutines' requires feature 'coroutines'}}
+@import DependsOnModule.Coroutines; // expected-note {{module imported here}}
+#endif
diff --git a/test/Modules/requires-gnuinlineasm.m b/test/Modules/requires-gnuinlineasm.m
index 80b1b18d07..e710b6bf8d 100644
--- a/test/Modules/requires-gnuinlineasm.m
+++ b/test/Modules/requires-gnuinlineasm.m
@@ -1,6 +1,7 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules \
// RUN: -fimplicit-module-maps -F %S/Inputs/GNUAsm %s \
+// RUN: -I %S/Inputs/GNUAsm \
// RUN: -fno-gnu-inline-asm -DNO_ASM_INLINE -verify
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules \
@@ -8,7 +9,8 @@
// RUN: -DASM_INLINE -verify
#ifdef NO_ASM_INLINE
-@import NeedsGNUInlineAsm.Asm; // expected-error{{module 'NeedsGNUInlineAsm.Asm' requires feature 'gnuinlineasm'}}
+// expected-error@NeedsGNUInlineAsm.framework/module.map:4 {{module 'NeedsGNUInlineAsm.Asm' requires feature 'gnuinlineasm'}}
+@import NeedsGNUInlineAsm.Asm; // expected-note {{module imported here}}
#endif
#ifdef ASM_INLINE
diff --git a/test/Modules/requires.m b/test/Modules/requires.m
index 1a01372710..d61de6bd48 100644
--- a/test/Modules/requires.m
+++ b/test/Modules/requires.m
@@ -1,12 +1,17 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s -verify -fmodule-feature custom_req1
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs -I %S/Inputs %s -verify -fmodule-feature custom_req1
-@import DependsOnModule.CXX; // expected-error{{module 'DependsOnModule.CXX' requires feature 'cplusplus'}}
+// expected-error@DependsOnModule.framework/module.map:7 {{module 'DependsOnModule.CXX' requires feature 'cplusplus'}}
+@import DependsOnModule.CXX; // expected-note {{module imported here}}
@import DependsOnModule.NotCXX;
-@import DependsOnModule.NotObjC; // expected-error{{module 'DependsOnModule.NotObjC' is incompatible with feature 'objc'}}
+// expected-error@DependsOnModule.framework/module.map:15 {{module 'DependsOnModule.NotObjC' is incompatible with feature 'objc'}}
+@import DependsOnModule.NotObjC; // expected-note {{module imported here}}
@import DependsOnModule.CustomReq1; // OK
-@import DependsOnModule.CustomReq2; // expected-error{{module 'DependsOnModule.CustomReq2' requires feature 'custom_req2'}}
+// expected-error@DependsOnModule.framework/module.map:22 {{module 'DependsOnModule.CustomReq2' requires feature 'custom_req2'}}
+@import DependsOnModule.CustomReq2; // expected-note {{module imported here}}
@import RequiresWithMissingHeader; // OK
-@import RequiresWithMissingHeader.HeaderBefore; // expected-error{{module 'RequiresWithMissingHeader.HeaderBefore' requires feature 'missing'}}
-@import RequiresWithMissingHeader.HeaderAfter; // expected-error{{module 'RequiresWithMissingHeader.HeaderAfter' requires feature 'missing'}}
+// expected-error@module.map:* {{module 'RequiresWithMissingHeader.HeaderBefore' requires feature 'missing'}}
+@import RequiresWithMissingHeader.HeaderBefore; // expected-note {{module imported here}}
+// expected-error@module.map:* {{module 'RequiresWithMissingHeader.HeaderAfter' requires feature 'missing'}}
+@import RequiresWithMissingHeader.HeaderAfter; // expected-note {{module imported here}}
diff --git a/test/Modules/requires.mm b/test/Modules/requires.mm
index cc64a500bd..f90622ece8 100644
--- a/test/Modules/requires.mm
+++ b/test/Modules/requires.mm
@@ -1,6 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs -I %S/Inputs/DependsOnModule.framework %s -verify
@import DependsOnModule.CXX;
-@import DependsOnModule.NotCXX; // expected-error{{module 'DependsOnModule.NotCXX' is incompatible with feature 'cplusplus'}}
-@import DependsOnModule.NotObjC; // expected-error{{module 'DependsOnModule.NotObjC' is incompatible with feature 'objc'}}
+// expected-error@module.map:11 {{module 'DependsOnModule.NotCXX' is incompatible with feature 'cplusplus'}}
+@import DependsOnModule.NotCXX; // expected-note {{module imported here}}
+// expected-error@module.map:15 {{module 'DependsOnModule.NotObjC' is incompatible with feature 'objc'}}
+@import DependsOnModule.NotObjC; // expected-note {{module imported here}}
diff --git a/test/Modules/string_names.cpp b/test/Modules/string_names.cpp
index 43068f13c0..a6503d048d 100644
--- a/test/Modules/string_names.cpp
+++ b/test/Modules/string_names.cpp
@@ -1,6 +1,10 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodules-decluse -I %S/Inputs/string_names %s -fmodule-name="my/module-a" -verify
+// Check that we can preprocess with string module names.
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/string_names %s -fmodule-name="my/module-a" -E -frewrite-imports -o %t/test.ii
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-decluse -I %S/Inputs/string_names %t/test.ii -fmodule-name="my/module-a"
+
#include "a.h"
#include "b.h" // expected-error {{does not depend on a module exporting}}
#include "c.h"
diff --git a/test/Modules/submodule-visibility.cpp b/test/Modules/submodule-visibility.cpp
index 345ae155bb..4c066e6ab9 100644
--- a/test/Modules/submodule-visibility.cpp
+++ b/test/Modules/submodule-visibility.cpp
@@ -3,6 +3,11 @@
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -I%S/Inputs/submodule-visibility -verify %s -DIMPORT
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -fmodule-name=x -I%S/Inputs/submodule-visibility -verify %s
// RUN: %clang_cc1 -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -I%S/Inputs/submodule-visibility -verify %s
+//
+// Explicit module builds.
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -emit-module -x c++-module-map %S/Inputs/submodule-visibility/module.modulemap -fmodule-name=other -o %t/other.pcm
+// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/submodule-visibility/module.modulemap -fmodules-local-submodule-visibility -fmodule-file=%t/other.pcm -verify -fmodule-name=x -I%S/Inputs/submodule-visibility %s
+// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/submodule-visibility/module.modulemap -fmodule-file=%t/other.pcm -verify -fmodule-name=x -I%S/Inputs/submodule-visibility %s -DALLOW_TEXTUAL_NAME_LEAKAGE
#include "a.h"
#include "b.h"
@@ -11,6 +16,8 @@
// expected-no-diagnostics
#elif IMPORT
// expected-error@-6 {{could not build module 'x'}}
+#elif ALLOW_TEXTUAL_NAME_LEAKAGE
+// expected-warning@b.h:7 {{A is defined}}
#else
// The use of -fmodule-name=x causes us to textually include the above headers.
// The submodule visibility rules are still applied in this case.
@@ -35,3 +42,5 @@ typedef struct {
int p;
void (*f)(int p);
} name_for_linkage;
+
+void g() { b_template<int>(); }
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 0000000000..e78df7b3b3
--- /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 b1bc360927..0000000000
--- 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/template-default-args.cpp b/test/Modules/template-default-args.cpp
index 9d16cbf434..c51cb28408 100644
--- a/test/Modules/template-default-args.cpp
+++ b/test/Modules/template-default-args.cpp
@@ -44,3 +44,20 @@ H<> h; // expected-error {{default argument of 'H' must be imported from module
I<> i;
L<> *l;
END
+
+namespace DeferredLookup {
+ template<typename T, typename U = T> using X = U;
+ template<typename T> void f() { (void) X<T>(); }
+ template<typename T> int n = X<T>(); // expected-warning {{extension}}
+ template<typename T> struct S { X<T> xt; enum E : int; };
+ template<typename T> enum S<T>::E : int { a = X<T>() };
+
+ void test() {
+ f<int>();
+ n<int> = 1;
+ S<int> s;
+ S<int>::E e = S<int>::E::a;
+
+ Indirect::B<int>::C<int> indirect;
+ }
+}
diff --git a/test/Modules/umbrella-header-include-builtin.mm b/test/Modules/umbrella-header-include-builtin.mm
index 75b9c905ff..b14c73705c 100644
--- a/test/Modules/umbrella-header-include-builtin.mm
+++ b/test/Modules/umbrella-header-include-builtin.mm
@@ -1,6 +1,12 @@
-// REQUIRES: system-darwin
-
// RUN: rm -rf %t
-// RUN: %clang -cc1 -fsyntax-only -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -F%S/Inputs/libc-libcxx/sysroot/Frameworks -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ %s
+// RUN: %clang -cc1 -fsyntax-only -nobuiltininc -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -isystem %S/Inputs/libc-libcxx/sysroot/usr/include -F%S/Inputs/libc-libcxx/sysroot/Frameworks -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ %s
#include <A/A.h>
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "module NonExistent1 { umbrella \"NonExistent\" }" > %t/modules.modulemap
+// RUN: echo "" > %t/A.h
+// RUN: echo "#include \"A.h\" int i;" > %t/T.cxx
+// RUN: %clang -I %t -fmodules -fsyntax-only %t/T.cxx
+// expected-warning {{ umbrella directory }}
diff --git a/test/Modules/using-decl-inheritance.cpp b/test/Modules/using-decl-inheritance.cpp
new file mode 100644
index 0000000000..eba9636b75
--- /dev/null
+++ b/test/Modules/using-decl-inheritance.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-local-submodule-visibility -fmodules-cache-path=%t %s -verify
+// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t %s -verify
+
+// expected-no-diagnostics
+
+#pragma clang module build A
+ module A { }
+#pragma clang module contents
+#pragma clang module begin A
+struct A {
+ virtual void Foo(double x) const;
+};
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build B
+ module B { }
+#pragma clang module contents
+#pragma clang module begin B
+#pragma clang module import A
+struct B : A {
+ using A::Foo;
+ virtual void Foo(double x) const;
+};
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import B
+
+int main() {
+ B b;
+ b.Foo(1.0);
+}
+
diff --git a/test/Modules/using-directive-redecl.cpp b/test/Modules/using-directive-redecl.cpp
new file mode 100644
index 0000000000..94772f30a3
--- /dev/null
+++ b/test/Modules/using-directive-redecl.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -verify %s
+// expected-no-diagnostics
+#pragma clang module build M
+module M { module TDFNodes {} module TDFInterface {} }
+#pragma clang module contents
+ // TDFNodes
+ #pragma clang module begin M.TDFNodes
+ namespace Detail {
+ namespace TDF {
+ class TLoopManager {};
+ }
+ }
+ namespace Internal {
+ namespace TDF {
+ using namespace Detail::TDF;
+ }
+ }
+ #pragma clang module end
+
+ // TDFInterface
+ #pragma clang module begin M.TDFInterface
+ #pragma clang module import M.TDFNodes
+ namespace Internal {
+ namespace TDF {
+ using namespace Detail::TDF;
+ }
+ }
+ #pragma clang module end
+
+#pragma clang module endbuild
+
+#pragma clang module import M.TDFNodes
+namespace Internal {
+ namespace TDF {
+ TLoopManager * use;
+ }
+}
diff --git a/test/Modules/using-directive.cpp b/test/Modules/using-directive.cpp
new file mode 100644
index 0000000000..6ca5c6eab4
--- /dev/null
+++ b/test/Modules/using-directive.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fno-modules-error-recovery -fno-spell-checking -verify %s
+
+#pragma clang module build a
+module a { explicit module b {} explicit module c {} }
+#pragma clang module contents
+
+#pragma clang module begin a.b
+namespace b { int n; }
+#pragma clang module end
+
+#pragma clang module begin a.c
+#pragma clang module import a.b
+namespace c { using namespace b; }
+#pragma clang module end
+
+#pragma clang module begin a
+#pragma clang module import a.c
+using namespace c;
+#pragma clang module end
+
+#pragma clang module endbuild
+
+#pragma clang module import a.b
+void use1() {
+ (void)n; // expected-error {{use of undeclared identifier}}
+ (void)::n; // expected-error {{no member named 'n' in the global namespace}}
+ (void)b::n;
+}
+namespace b {
+ void use1_in_b() { (void)n; }
+}
+namespace c {
+ void use1_in_c() { (void)n; } // expected-error {{use of undeclared identifier}}
+}
+
+#pragma clang module import a.c
+void use2() {
+ (void)n; // expected-error {{use of undeclared identifier}}
+ (void)::n; // expected-error {{no member named 'n' in the global namespace}}
+ (void)b::n;
+ (void)c::n;
+}
+namespace b {
+ void use2_in_b() { (void)n; }
+}
+namespace c {
+ void use2_in_c() { (void)n; }
+}
+
+#pragma clang module import a
+void use3() {
+ (void)n;
+ (void)::n;
+ (void)b::n;
+ (void)c::n;
+}
+namespace b {
+ void use3_in_b() { (void)n; }
+}
+namespace c {
+ void use3_in_c() { (void)n; }
+}
diff --git a/test/Modules/visibility-in-instantiation.cpp b/test/Modules/visibility-in-instantiation.cpp
new file mode 100644
index 0000000000..8689758a42
--- /dev/null
+++ b/test/Modules/visibility-in-instantiation.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -std=c++11 -fmodules %s -verify
+
+#pragma clang module build M
+ module M { module A {} module B {} module C {} }
+#pragma clang module contents
+
+ #pragma clang module begin M.A
+ template<typename U> struct X {
+ template<typename T> void f();
+ };
+ #pragma clang module end
+
+ #pragma clang module begin M.B
+ template<typename T, typename U = void> struct ST { static void f(); };
+ #pragma clang module end
+
+ #pragma clang module begin M.C
+ template<typename U> struct X;
+ void foo(X<int>);
+ #pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build N
+ module N {}
+#pragma clang module contents
+ #pragma clang module begin N
+ #pragma clang module import M.B // not re-exported
+
+ template<typename U> struct X {
+ template<typename T> void f();
+ template<typename T> void g();
+ };
+
+ template<typename U> template<typename T>
+ void X<U>::f() {
+ ST<T>::f(); // definition and default argument found in M.B
+ foo(*this); // found by ADL in M.C
+ };
+
+ #pragma clang module import M.C // not re-exported
+ #pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import N
+void g() {
+ X<int>().f<int>();
+
+ ST<int>::f(); // expected-error {{must be imported from module 'M.B'}}
+ foo(X<int>()); // expected-error {{must be imported from module 'M.C'}}
+ // expected-note@* 2{{previous declaration is here}}
+}
diff --git a/test/Modules/warning-mismatch.m b/test/Modules/warning-mismatch.m
new file mode 100644
index 0000000000..dd7c7f82ec
--- /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/atomic_capture_codegen.cpp b/test/OpenMP/atomic_capture_codegen.cpp
index 0a22e4276b..306b83f624 100644
--- a/test/OpenMP/atomic_capture_codegen.cpp
+++ b/test/OpenMP/atomic_capture_codegen.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
@@ -611,50 +611,6 @@ int main() {
// CHECK: store i8 [[DESIRED_I8]], i8* @{{.+}},
#pragma omp atomic capture
{bx = civ - bx; bv = bx;}
-// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0)
-// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1)
-// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic
-// CHECK: br label %[[CONT:.+]]
-// CHECK: [[CONT]]
-// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
-// CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32
-// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to float
-// <Skip checks for complex calculations>
-// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
-// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]]
-// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
-// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]]
-// CHECK: [[NEW:%.+]] = fptoui float [[X_RE]] to i16
-// CHECK: store i16 [[NEW]], i16* [[TEMP:%.+]],
-// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]],
-// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic
-// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0
-// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1
-// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
-// CHECK: [[EXIT]]
-// CHECK: store i16 [[NEW]], i16* @{{.+}},
-#pragma omp atomic capture
- usv = usx /= cfv;
-// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0)
-// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1)
-// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic
-// CHECK: br label %[[CONT:.+]]
-// CHECK: [[CONT]]
-// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
-// CHECK: [[X_RVAL:%.+]] = sitofp i64 [[EXPECTED]] to double
-// CHECK: [[ADD_RE:%.+]] = fadd double [[X_RVAL]], [[EXPR_RE]]
-// CHECK: [[ADD_IM:%.+]] = fadd double 0.000000e+00, [[EXPR_IM]]
-// CHECK: [[DESIRED:%.+]] = fptosi double [[ADD_RE]] to i64
-// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]],
-// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]],
-// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
-// CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0
-// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
-// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
-// CHECK: [[EXIT]]
-// CHECK: store i64 [[EXPECTED]], i64* @{{.+}},
-#pragma omp atomic capture
- {llv = llx; llx += cdv;}
// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}}
// CHECK: load i8, i8*
// CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32
diff --git a/test/OpenMP/atomic_read_codegen.c b/test/OpenMP/atomic_read_codegen.c
index 0cd46e3821..0cfb2d26f2 100644
--- a/test/OpenMP/atomic_read_codegen.c
+++ b/test/OpenMP/atomic_read_codegen.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics
// REQUIRES: x86-registered-target
#ifndef HEADER
diff --git a/test/OpenMP/atomic_update_codegen.cpp b/test/OpenMP/atomic_update_codegen.cpp
index 8c02a43d64..1343cd8ad2 100644
--- a/test/OpenMP/atomic_update_codegen.cpp
+++ b/test/OpenMP/atomic_update_codegen.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
@@ -554,48 +554,6 @@ int main() {
// CHECK: [[EXIT]]
#pragma omp atomic
bx = civ - bx;
-// CHECK: [[EXPR_RE:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 0)
-// CHECK: [[EXPR_IM:%.+]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @{{.+}}, i32 0, i32 1)
-// CHECK: [[X:%.+]] = load atomic i16, i16* [[X_ADDR:@.+]] monotonic
-// CHECK: br label %[[CONT:.+]]
-// CHECK: [[CONT]]
-// CHECK: [[EXPECTED:%.+]] = phi i16 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
-// CHECK: [[CONV:%.+]] = zext i16 [[EXPECTED]] to i32
-// CHECK: [[X_RVAL:%.+]] = sitofp i32 [[CONV]] to float
-// <Skip checks for complex calculations>
-// CHECK: [[X_RE_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP:%.+]], i32 0, i32 0
-// CHECK: [[X_RE:%.+]] = load float, float* [[X_RE_ADDR]]
-// CHECK: [[X_IM_ADDR:%.+]] = getelementptr inbounds { float, float }, { float, float }* [[TEMP]], i32 0, i32 1
-// CHECK: [[X_IM:%.+]] = load float, float* [[X_IM_ADDR]]
-// CHECK: [[DESIRED:%.+]] = fptoui float [[X_RE]] to i16
-// CHECK: store i16 [[DESIRED]], i16* [[TEMP:%.+]]
-// CHECK: [[DESIRED:%.+]] = load i16, i16* [[TEMP]]
-// CHECK: [[RES:%.+]] = cmpxchg i16* [[X_ADDR]], i16 [[EXPECTED]], i16 [[DESIRED]] monotonic monotonic
-// CHECK: [[OLD_X]] = extractvalue { i16, i1 } [[RES]], 0
-// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i16, i1 } [[RES]], 1
-// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
-// CHECK: [[EXIT]]
-#pragma omp atomic update
- usx /= cfv;
-// CHECK: [[EXPR_RE:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 0)
-// CHECK: [[EXPR_IM:%.+]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @{{.+}}, i32 0, i32 1)
-// CHECK: [[X:%.+]] = load atomic i64, i64* [[X_ADDR:@.+]] monotonic
-// CHECK: br label %[[CONT:.+]]
-// CHECK: [[CONT]]
-// CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ]
-// CHECK: [[X_RVAL:%.+]] = sitofp i64 [[EXPECTED]] to double
-// CHECK: [[ADD_RE:%.+]] = fadd double [[X_RVAL]], [[EXPR_RE]]
-// CHECK: [[ADD_IM:%.+]] = fadd double 0.000000e+00, [[EXPR_IM]]
-// CHECK: [[DESIRED:%.+]] = fptosi double [[ADD_RE]] to i64
-// CHECK: store i64 [[DESIRED]], i64* [[TEMP:%.+]]
-// CHECK: [[DESIRED:%.+]] = load i64, i64* [[TEMP]]
-// CHECK: [[RES:%.+]] = cmpxchg i64* [[X_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic
-// CHECK: [[OLD_X]] = extractvalue { i64, i1 } [[RES]], 0
-// CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i64, i1 } [[RES]], 1
-// CHECK: br i1 [[SUCCESS_FAIL]], label %[[EXIT:.+]], label %[[CONT]]
-// CHECK: [[EXIT]]
-#pragma omp atomic
- llx += cdv;
// CHECK: [[IDX:%.+]] = load i16, i16* @{{.+}}
// CHECK: load i8, i8*
// CHECK: [[VEC_ITEM_VAL:%.+]] = zext i1 %{{.+}} to i32
diff --git a/test/OpenMP/atomic_write_codegen.c b/test/OpenMP/atomic_write_codegen.c
index 050d7a5105..0c85b6e88a 100644
--- a/test/OpenMP/atomic_write_codegen.c
+++ b/test/OpenMP/atomic_write_codegen.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -target-cpu core2 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -target-cpu core2 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics
// REQUIRES: x86-registered-target
#ifndef HEADER
diff --git a/test/OpenMP/cancel_codegen_cleanup.cpp b/test/OpenMP/cancel_codegen_cleanup.cpp
new file mode 100644
index 0000000000..5a297bd377
--- /dev/null
+++ b/test/OpenMP/cancel_codegen_cleanup.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++11 -fopenmp -fopenmp-version=45 -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - %s | FileCheck %s
+
+//CHECK: call i32 @__kmpc_cancel
+//CHECK: br {{.*}}label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]]
+//CHECK: [[EXIT]]:
+//CHECK: store i32 [[EXIT_SLOT:[0-9]+]]
+//CHECK: br label %[[CLEANUP:.+]]
+//CHECK: [[CONTINUE]]:
+//CHECK: store i32 [[CONT_SLOT:[0-9]+]],
+//CHECK: br label %[[CLEANUP]]
+//CHECK: [[CLEANUP]]:
+//CHECK-NEXT: call void @_ZN3ObjD1Ev
+//CHECK: switch i32{{.*}}, label %[[UNREACHABLE:.+]] [
+//CHECK: i32 [[CONT_SLOT]], label %[[CLEANUPCONT:.+]]
+//CHECK: i32 [[EXIT_SLOT]], label %[[CANCELEXIT:.+]]
+//CHECK-NEXT: ]
+//CHECK: [[CLEANUPCONT]]:
+//CHECK: br label %[[CANCELCONT:.+]]
+//CHECK: [[CANCELCONT]]:
+//CHECK-NEXT: call void @__kmpc_barrier(
+//CHECK-NEXT: ret void
+//CHECK: [[UNREACHABLE]]:
+//CHECK-NEXT: unreachable
+//CHECK-NEXT: }
+
+struct Obj {
+ int a; Obj(); Obj(const Obj& r) = delete; Obj &operator=(const Obj& r);
+ ~Obj();
+};
+
+void foo() {
+ int i,count = 0;
+ Obj obj;
+
+ #pragma omp parallel private(i) num_threads(1)
+ {
+ #pragma omp for reduction(+:count) lastprivate(obj)
+ for (i=0; i<1000; i++) {
+ if(i==100) {
+ obj.a = 100;
+ #pragma omp cancel for
+ }
+ count++;
+ }
+ }
+}
diff --git a/test/OpenMP/capturing_in_templates.cpp b/test/OpenMP/capturing_in_templates.cpp
new file mode 100644
index 0000000000..a4dcbee8fa
--- /dev/null
+++ b/test/OpenMP/capturing_in_templates.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple powerpc64le-ibm-linux-gnu -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+template <typename T1, typename T2>
+struct pair {
+ T1 t1;
+ T2 t2;
+ pair(T1 t1, T2 t2) : t1(t1), t2(t2) {}
+};
+
+template <typename T1, typename T2>
+pair<T1, T2> make_pair(T1 &&t1, T2 &&t2) {
+ return {t1, t2};
+}
+
+// CHECK-LABEL: @main
+int main(int argc, char **argv) {
+// CHECK: call i32 @__tgt_target(i32 -1, i8* @{{.+}}.region_id, i32 0, i8** null, i8** null, i64* null, i32* null)
+#pragma omp target
+ {
+ for (int i = 0; i < 64; ++i) {
+ for (int j = 0; j < 64; ++j) {
+ auto foo = make_pair(i * i, j * j);
+ }
+ }
+ }
+ return 0;
+}
+
+// CHECK: call {{.+}} @{{.*}}make_pair
diff --git a/test/OpenMP/critical_codegen.cpp b/test/OpenMP/critical_codegen.cpp
index f4e449a223..964c91f45a 100644
--- a/test/OpenMP/critical_codegen.cpp
+++ b/test/OpenMP/critical_codegen.cpp
@@ -78,7 +78,7 @@ void critical_ref(S &s) {
void parallel_critical() {
#pragma omp parallel
#pragma omp critical
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: call void @__kmpc_critical({{.+}}), !dbg [[DBG_LOC_START:![0-9]+]]
// TERM_DEBUG: invoke void {{.*}}foo{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
diff --git a/test/OpenMP/declare_reduction_codegen.cpp b/test/OpenMP/declare_reduction_codegen.cpp
index 11ce430011..ae6e047d94 100644
--- a/test/OpenMP/declare_reduction_codegen.cpp
+++ b/test/OpenMP/declare_reduction_codegen.cpp
@@ -9,6 +9,26 @@
// CHECK: [[SSS_INT:.+]] = type { i32 }
// CHECK-LOAD: [[SSS_INT:.+]] = type { i32 }
+// CHECK: add
+void add(short &out, short &in) {}
+
+#pragma omp declare reduction(my_add : short : add(omp_out, omp_in))
+
+// CHECK: define internal void @.
+// CHECK: call void @{{.+}}add{{.+}}(
+// CHECK: ret void
+
+// CHECK: foo_reduction_array
+void foo_reduction_array() {
+ short y[1];
+ // CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(
+#pragma omp parallel for reduction(my_add : y)
+ for (int i = 0; i < 1; i++) {
+ }
+}
+
+// CHECK: define internal void @
+
#pragma omp declare reduction(+ : int, char : omp_out *= omp_in)
// CHECK: define internal {{.*}}void @{{[^(]+}}(i32* noalias, i32* noalias)
// CHECK: [[MUL:%.+]] = mul nsw i32
@@ -92,6 +112,22 @@ T foo(T a) {
return a;
}
+struct Summary {
+ void merge(const Summary& other) {}
+};
+
+template <typename K>
+void work() {
+ Summary global_summary;
+#pragma omp declare reduction(+ : Summary : omp_out.merge(omp_in))
+#pragma omp parallel for reduction(+ : global_summary)
+ for (int k = 1; k <= 100; ++k) {
+ }
+}
+
+struct A {};
+
+
// CHECK-LABEL: @main
int main() {
int i = 0;
@@ -110,6 +146,8 @@ int main() {
// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(
// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(
// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call({{[^@]*}} @{{[^@]*}}[[REGION:@[^ ]+]]
+ // CHECK-LABEL: work
+ work<A>();
// CHECK-LABEL: foo
return foo(15);
}
diff --git a/test/OpenMP/declare_reduction_messages.cpp b/test/OpenMP/declare_reduction_messages.cpp
index 198d7756d0..3e5a15ee3d 100644
--- a/test/OpenMP/declare_reduction_messages.cpp
+++ b/test/OpenMP/declare_reduction_messages.cpp
@@ -134,3 +134,21 @@ int main() {
}
return fun(15) + foo(15); // expected-note {{in instantiation of function template specialization 'foo<int>' requested here}}
}
+
+#if __cplusplus == 201103L
+struct A {
+ A() {}
+ // expected-note@+1 {{copy constructor is implicitly deleted because 'A' has a user-declared move assignment operator}}
+ A& operator=(A&&) = default;
+};
+
+int A_TEST() {
+ A test;
+// expected-error@+1 {{call to implicitly-deleted copy constructor of 'A'}}
+#pragma omp declare reduction(+ : A : omp_out) initializer(omp_priv = A())
+// expected-error@+1 {{invalid operands to binary expression ('A' and 'A')}}
+#pragma omp parallel reduction(+ : test)
+ {}
+ return 0;
+}
+#endif
diff --git a/test/OpenMP/declare_simd_messages.cpp b/test/OpenMP/declare_simd_messages.cpp
index 15971eb14d..af46283f9a 100644
--- a/test/OpenMP/declare_simd_messages.cpp
+++ b/test/OpenMP/declare_simd_messages.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++11 -fms-extensions %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++11 -fms-extensions -Wno-pragma-pack %s
// expected-error@+1 {{expected an OpenMP directive}}
#pragma omp declare
diff --git a/test/OpenMP/declare_target_ast_print.cpp b/test/OpenMP/declare_target_ast_print.cpp
index 591844b794..55f73cbc4e 100644
--- a/test/OpenMP/declare_target_ast_print.cpp
+++ b/test/OpenMP/declare_target_ast_print.cpp
@@ -124,6 +124,33 @@ void f3() {
// CHECK: void f3()
// CHECK: #pragma omp end declare target
+struct SSSt {
+#pragma omp declare target
+ static int a;
+ int b;
+#pragma omp end declare target
+};
+
+// CHECK: struct SSSt {
+// CHECK: #pragma omp declare target
+// CHECK: static int a;
+// CHECK: #pragma omp end declare target
+// CHECK: int b;
+
+template <class T>
+struct SSSTt {
+#pragma omp declare target
+ static T a;
+ int b;
+#pragma omp end declare target
+};
+
+// CHECK: template <class T> struct SSSTt {
+// CHECK: #pragma omp declare target
+// CHECK: static T a;
+// CHECK: #pragma omp end declare target
+// CHECK: int b;
+
int main (int argc, char **argv) {
foo();
foo_c();
diff --git a/test/OpenMP/declare_target_messages.cpp b/test/OpenMP/declare_target_messages.cpp
index b858d53c1e..bbffc0eeeb 100644
--- a/test/OpenMP/declare_target_messages.cpp
+++ b/test/OpenMP/declare_target_messages.cpp
@@ -28,16 +28,16 @@ typedef int sint;
extern int b;
int g;
-struct T { // expected-note {{mappable type cannot be polymorphic}}
+struct T {
int a;
virtual int method();
};
-class VC { // expected-note {{mappable type cannot be polymorphic}}
+class VC {
T member;
NonT member1;
public:
- virtual int method() { T a; return 0; } // expected-error {{type 'T' is not mappable to target}}
+ virtual int method() { T a; return 0; }
};
struct C {
@@ -56,7 +56,7 @@ void foo() {
b = 0; // expected-note {{used here}}
t = 1; // expected-error {{threadprivate variables cannot be used in target constructs}}
C object;
- VC object1; // expected-error {{type 'VC' is not mappable to target}}
+ VC object1;
g = object.method();
g += object.method1();
g += object1.method();
@@ -73,9 +73,9 @@ int C::method() {
}
struct S {
-#pragma omp declare target // expected-error {{directive must be at file or namespace scope}}
+#pragma omp declare target
int v;
-#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}}
+#pragma omp end declare target
};
int main (int argc, char **argv) {
diff --git a/test/OpenMP/distribute_codegen.cpp b/test/OpenMP/distribute_codegen.cpp
index 37f00f0917..7ea17b116c 100644
--- a/test/OpenMP/distribute_codegen.cpp
+++ b/test/OpenMP/distribute_codegen.cpp
@@ -23,6 +23,7 @@
// 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_0:@.+]] = 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: [[DEF_LOC_DISTRIBUTE_0:@.+]] = private unnamed_addr constant %ident_t { i32 0, i32 2050, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
// CHECK-LABEL: define {{.*void}} @{{.*}}without_schedule_clause{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
void without_schedule_clause(float *a, float *b, float *c, float *d) {
@@ -34,7 +35,7 @@ void without_schedule_clause(float *a, float *b, float *c, float *d) {
}
}
-// CHECK: define {{.*}}void @.omp_outlined.(i32* noalias [[GBL_TIDP:%.+]], i32* noalias [[BND_TID:%.+]], float** dereferenceable({{[0-9]+}}) [[APTR:%.+]], float** dereferenceable({{[0-9]+}}) [[BPTR:%.+]], float** dereferenceable({{[0-9]+}}) [[CPTR:%.+]], float** dereferenceable({{[0-9]+}}) [[DPTR:%.+]])
+// CHECK: define {{.*}}void @{{.+}}(i32* noalias [[GBL_TIDP:%.+]], i32* noalias [[BND_TID:%.+]], float** dereferenceable({{[0-9]+}}) [[APTR:%.+]], float** dereferenceable({{[0-9]+}}) [[BPTR:%.+]], float** dereferenceable({{[0-9]+}}) [[CPTR:%.+]], float** dereferenceable({{[0-9]+}}) [[DPTR:%.+]])
// CHECK: [[TID_ADDR:%.+]] = alloca i32*
// CHECK: [[IV:%.+iv]] = alloca i32
// CHECK: [[LB:%.+lb]] = alloca i32
@@ -48,7 +49,7 @@ void without_schedule_clause(float *a, float *b, float *c, float *d) {
// CHECK-DAG: store i32 0, i32* [[LAST]]
// CHECK-DAG: [[GBL_TID:%.+]] = load i32*, i32** [[TID_ADDR]]
// CHECK-DAG: [[GBL_TIDV:%.+]] = load i32, i32* [[GBL_TID]]
-// CHECK: call void @__kmpc_for_static_init_{{.+}}(%ident_t* [[DEF_LOC_0]], i32 [[GBL_TIDV]], i32 92, i32* %.omp.is_last, i32* %.omp.lb, i32* %.omp.ub, i32* %.omp.stride, i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_{{.+}}(%ident_t* [[DEF_LOC_DISTRIBUTE_0]], i32 [[GBL_TIDV]], i32 92, i32* %.omp.is_last, i32* %.omp.lb, i32* %.omp.ub, i32* %.omp.stride, i32 1, i32 1)
// CHECK-DAG: [[UBV0:%.+]] = load i32, i32* [[UB]]
// CHECK-DAG: [[USWITCH:%.+]] = icmp sgt i32 [[UBV0]], 4571423
// CHECK: br i1 [[USWITCH]], label %[[BBCT:.+]], label %[[BBCF:.+]]
@@ -82,7 +83,7 @@ void without_schedule_clause(float *a, float *b, float *c, float *d) {
// CHECK: [[BBINNEND]]:
// CHECK: br label %[[LPEXIT:.+]]
// CHECK: [[LPEXIT]]:
-// CHECK: call void @__kmpc_for_static_fini(%ident_t* [[DEF_LOC_0]], i32 [[GBL_TIDV]])
+// CHECK: call void @__kmpc_for_static_fini(%ident_t* [[DEF_LOC_DISTRIBUTE_0]], i32 [[GBL_TIDV]])
// CHECK: ret void
@@ -110,7 +111,7 @@ void static_not_chunked(float *a, float *b, float *c, float *d) {
// CHECK-DAG: store i32 0, i32* [[LAST]]
// CHECK-DAG: [[GBL_TID:%.+]] = load i32*, i32** [[TID_ADDR]]
// CHECK-DAG: [[GBL_TIDV:%.+]] = load i32, i32* [[GBL_TID]]
-// CHECK: call void @__kmpc_for_static_init_{{.+}}(%ident_t* [[DEF_LOC_0]], i32 [[GBL_TIDV]], i32 92, i32* %.omp.is_last, i32* %.omp.lb, i32* %.omp.ub, i32* %.omp.stride, i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_{{.+}}(%ident_t* [[DEF_LOC_DISTRIBUTE_0]], i32 [[GBL_TIDV]], i32 92, i32* %.omp.is_last, i32* %.omp.lb, i32* %.omp.ub, i32* %.omp.stride, i32 1, i32 1)
// CHECK-DAG: [[UBV0:%.+]] = load i32, i32* [[UB]]
// CHECK-DAG: [[USWITCH:%.+]] = icmp sgt i32 [[UBV0]], 4571423
// CHECK: br i1 [[USWITCH]], label %[[BBCT:.+]], label %[[BBCF:.+]]
@@ -144,7 +145,7 @@ void static_not_chunked(float *a, float *b, float *c, float *d) {
// CHECK: [[BBINNEND]]:
// CHECK: br label %[[LPEXIT:.+]]
// CHECK: [[LPEXIT]]:
-// CHECK: call void @__kmpc_for_static_fini(%ident_t* [[DEF_LOC_0]], i32 [[GBL_TIDV]])
+// CHECK: call void @__kmpc_for_static_fini(%ident_t* [[DEF_LOC_DISTRIBUTE_0]], i32 [[GBL_TIDV]])
// CHECK: ret void
@@ -172,7 +173,7 @@ void static_chunked(float *a, float *b, float *c, float *d) {
// CHECK-DAG: store i32 0, i32* [[LAST]]
// CHECK-DAG: [[GBL_TID:%.+]] = load i32*, i32** [[TID_ADDR]]
// CHECK-DAG: [[GBL_TIDV:%.+]] = load i32, i32* [[GBL_TID]]
-// CHECK: call void @__kmpc_for_static_init_{{.+}}(%ident_t* [[DEF_LOC_0]], i32 [[GBL_TIDV]], i32 91, i32* %.omp.is_last, i32* %.omp.lb, i32* %.omp.ub, i32* %.omp.stride, i32 1, i32 5)
+// CHECK: call void @__kmpc_for_static_init_{{.+}}(%ident_t* [[DEF_LOC_DISTRIBUTE_0]], i32 [[GBL_TIDV]], i32 91, i32* %.omp.is_last, i32* %.omp.lb, i32* %.omp.ub, i32* %.omp.stride, i32 1, i32 5)
// CHECK-DAG: [[UBV0:%.+]] = load i32, i32* [[UB]]
// CHECK-DAG: [[USWITCH:%.+]] = icmp ugt i32 [[UBV0]], 16908288
// CHECK: br i1 [[USWITCH]], label %[[BBCT:.+]], label %[[BBCF:.+]]
@@ -206,7 +207,7 @@ void static_chunked(float *a, float *b, float *c, float *d) {
// CHECK: [[BBINNEND]]:
// CHECK: br label %[[LPEXIT:.+]]
// CHECK: [[LPEXIT]]:
-// CHECK: call void @__kmpc_for_static_fini(%ident_t* [[DEF_LOC_0]], i32 [[GBL_TIDV]])
+// CHECK: call void @__kmpc_for_static_fini(%ident_t* [[DEF_LOC_DISTRIBUTE_0]], i32 [[GBL_TIDV]])
// CHECK: ret void
// CHECK-LABEL: test_precond
diff --git a/test/OpenMP/distribute_firstprivate_messages.cpp b/test/OpenMP/distribute_firstprivate_messages.cpp
index 5d371abbfa..a59c952809 100644
--- a/test/OpenMP/distribute_firstprivate_messages.cpp
+++ b/test/OpenMP/distribute_firstprivate_messages.cpp
@@ -135,11 +135,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo(); // expected-error {{loop iteration variable in the associated loop of 'omp distribute' directive may not be firstprivate, predetermined as private}}
#pragma omp target
#pragma omp teams private(argc) // expected-note {{defined as private}}
- #pragma omp distribute firstprivate(argc) // expected-error {{private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}}
+ #pragma omp distribute firstprivate(argc) // expected-error {{firstprivate variable must be shared}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams reduction(+:argc) // expected-note {{defined as reduction}}
- #pragma omp distribute firstprivate(argc) // expected-error {{reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}}
+ #pragma omp distribute firstprivate(argc) // expected-error {{firstprivate variable must be shared}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
@@ -147,11 +147,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
- #pragma omp distribute lastprivate(argc), firstprivate(argc) // expected-error {{lastprivate variable cannot be firstprivate in '#pragma omp distribute'}} expected-note{{defined as lastprivate}}
+ #pragma omp distribute lastprivate(argc), firstprivate(argc) // expected-error {{lastprivate variable cannot be firstprivate}} expected-note{{defined as lastprivate}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute firstprivate(argc), lastprivate(argc) // expected-error {{lastprivate variable cannot be firstprivate in '#pragma omp distribute'}} expected-note{{defined as firstprivate}}
+#pragma omp distribute firstprivate(argc), lastprivate(argc) // expected-error {{firstprivate variable cannot be lastprivate}} expected-note{{defined as firstprivate}}
for (i = 0; i < argc; ++i) foo();
return 0;
}
diff --git a/test/OpenMP/distribute_parallel_for_ast_print.cpp b/test/OpenMP/distribute_parallel_for_ast_print.cpp
index 874345b673..54a3649e57 100644
--- a/test/OpenMP/distribute_parallel_for_ast_print.cpp
+++ b/test/OpenMP/distribute_parallel_for_ast_print.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -verify -std=c++11 -fopenmp -fopenmp-version=45 -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// expected-no-diagnostics
@@ -109,6 +109,41 @@ T tmain(T argc) {
return T();
}
+void foo(int argc, char **argv) {
+ int b, c, d, e, f, h;
+ static int a;
+// CHECK: static int a;
+ static float g;
+#pragma omp threadprivate(g)
+ [&]() {
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a)
+ // CHECK: #pragma omp distribute parallel for schedule(guided, argc) default(none) copyin(g) dist_schedule(static, a) private(a)
+ for (int i = 0; i < 2; ++i)
+// CHECK: for (int i = 0; i < 2; ++i)
+ [&]() {
+ a = 2;
+ // CHECK: a = 2;
+ }();
+
+ }();
+ [&]() {
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) schedule(auto) if (argc) num_threads(a) default(shared) shared(e) reduction(+ : h) dist_schedule(static, b)
+ for (int i = 0; i < 10; ++i)
+ for (int j = 0; j < 10; ++j)
+ [&]() {
+ a++;
+ }();
+ // CHECK: #pragma omp distribute parallel for private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) schedule(auto) if(argc) num_threads(a) default(shared) shared(e) reduction(+: h) dist_schedule(static, b)
+ // CHECK-NEXT: for (int i = 0; i < 10; ++i)
+ // CHECK-NEXT: for (int j = 0; j < 10; ++j)
+ // CHECK: a++;
+ }();
+}
+
int main(int argc, char **argv) {
int b = argc, c, d, e, f, h;
static int a;
diff --git a/test/OpenMP/distribute_parallel_for_codegen.cpp b/test/OpenMP/distribute_parallel_for_codegen.cpp
new file mode 100644
index 0000000000..62c38f1888
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_codegen.cpp
@@ -0,0 +1,2260 @@
+// Test host code gen
+// RUN: %clang_cc1 -DLAMBDA -verify -fopenmp -fopenmp-version=45 -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 -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 -DLAMBDA -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 LAMBDA --check-prefix LAMBDA-64
+// RUN: %clang_cc1 -DLAMBDA -verify -fopenmp -fopenmp-version=45 -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 -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 -DLAMBDA -fopenmp -fopenmp-version=45 -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 -fopenmp-version=45 -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 -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++ -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 -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++ -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 <typename T>
+T tmain() {
+ T *a, *b, *c;
+ int n = 10000;
+ int ch = 100;
+
+ // no schedule clauses
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ }
+
+ // dist_schedule: static no chunk
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for dist_schedule(static)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ }
+
+ // dist_schedule: static chunk
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for dist_schedule(static, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ }
+
+ // schedule: static no chunk
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for schedule(static)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ }
+
+ // schedule: static chunk
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for schedule(static, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ }
+
+ // schedule: dynamic no chunk
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for schedule(dynamic)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ }
+
+ // schedule: dynamic chunk
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for schedule(dynamic, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ }
+
+ return T();
+}
+
+int main() {
+ double *a, *b, *c;
+ int n = 10000;
+ int ch = 100;
+
+#ifdef LAMBDA
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call{{.*}} void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN_1:@.+]](
+
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN_2:@.+]](
+
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN_3:@.+]](
+
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN_4:@.+]](
+
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN_5:@.+]](
+
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN_6:@.+]](
+
+ // LAMBDA: call i{{[0-9]+}} @__tgt_target_teams(
+ // LAMBDA: call void [[OFFLOADING_FUN_7:@.+]](
+
+ // no schedule clauses
+ #pragma omp target
+ #pragma omp teams
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN_1]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_1:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // LAMBDA: define{{.+}} void [[OMP_OUTLINED_1]](
+ // LAMBDA-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // LAMBDA-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // LAMBDA-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // LAMBDA-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+
+ // check EUB for distribute
+ // LAMBDA-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+ // LAMBDA: [[NUM_IT_1:%.+]] = load{{.+}},
+ // LAMBDA-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+ // LAMBDA: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+ // LAMBDA-DAG: [[EUB_TRUE]]:
+ // LAMBDA: [[NUM_IT_2:%.+]] = load{{.+}},
+ // LAMBDA: br label %[[EUB_END:.+]]
+ // LAMBDA-DAG: [[EUB_FALSE]]:
+ // LAMBDA: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+ // LAMBDA: br label %[[EUB_END]]
+ // LAMBDA-DAG: [[EUB_END]]:
+ // LAMBDA-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+ // LAMBDA: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+ // initialize omp.iv
+ // LAMBDA: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+ // LAMBDA: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[OMP_JUMP_BACK:.+]]
+
+ // check exit condition
+ // LAMBDA: [[OMP_JUMP_BACK]]:
+ // LAMBDA-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+ // LAMBDA: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+ // LAMBDA: br {{.+}} [[CMP_IV_UB]], label %[[DIST_BODY:.+]], label %[[DIST_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // LAMBDA: [[DIST_BODY]]:
+ // LAMBDA-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to
+ // LAMBDA-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to
+ // check that distlb and distub are properly passed to fork_call
+ // LAMBDA-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_1:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+ // LAMBDA-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_1:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+ // LAMBDA: br label %[[DIST_INC:.+]]
+
+ // increment by stride (distInc - 'parallel for' executes the whole chunk) and latch
+ // LAMBDA: [[DIST_INC]]:
+ // LAMBDA-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+ // LAMBDA: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_2]], [[OMP_ST_VAL_1]]
+ // LAMBDA: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[OMP_JUMP_BACK]]
+
+ // LAMBDA-DAG: call void @__kmpc_for_static_fini(
+ // LAMBDA: ret
+
+ // implementation of 'parallel for'
+ // LAMBDA: define{{.+}} void [[OMP_PARFOR_OUTLINED_1]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+ // LAMBDA-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // LAMBDA-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // LAMBDA-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+ // PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+ // In this case we use EUB
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+ // LAMBDA-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+ // LAMBDA: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // LAMBDA: [[PF_EUB_TRUE]]:
+ // LAMBDA: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+ // LAMBDA: br label %[[PF_EUB_END:.+]]
+ // LAMBDA-DAG: [[PF_EUB_FALSE]]:
+ // LAMBDA: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA: br label %[[PF_EUB_END]]
+ // LAMBDA-DAG: [[PF_EUB_END]]:
+ // LAMBDA-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+ // LAMBDA: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv
+ // LAMBDA: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+ // check exit condition
+ // LAMBDA: [[OMP_PF_JUMP_BACK]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+ // LAMBDA: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // LAMBDA: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // LAMBDA: [[PF_BODY]]:
+ // LAMBDA-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label {{.+}}
+
+ // check stride 1 for 'for' in 'distribute parallel for'
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+ // LAMBDA: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_JUMP_BACK]]
+
+ // LAMBDA-DAG: call void @__kmpc_for_static_fini(
+ // LAMBDA: ret
+
+ [&]() {
+ a[i] = b[i] + c[i];
+ }();
+ }
+
+ // dist_schedule: static no chunk (same sa default - no dist_schedule)
+ #pragma omp target
+ #pragma omp teams
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN_2]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_2:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for dist_schedule(static)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // LAMBDA: define{{.+}} void [[OMP_OUTLINED_2]](
+ // LAMBDA-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // LAMBDA-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // LAMBDA-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // LAMBDA-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+
+ // check EUB for distribute
+ // LAMBDA-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+ // LAMBDA: [[NUM_IT_1:%.+]] = load{{.+}},
+ // LAMBDA-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+ // LAMBDA: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+ // LAMBDA-DAG: [[EUB_TRUE]]:
+ // LAMBDA: [[NUM_IT_2:%.+]] = load{{.+}},
+ // LAMBDA: br label %[[EUB_END:.+]]
+ // LAMBDA-DAG: [[EUB_FALSE]]:
+ // LAMBDA: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+ // LAMBDA: br label %[[EUB_END]]
+ // LAMBDA-DAG: [[EUB_END]]:
+ // LAMBDA-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+ // LAMBDA: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+ // initialize omp.iv
+ // LAMBDA: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+ // LAMBDA: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[OMP_JUMP_BACK:.+]]
+
+ // check exit condition
+ // LAMBDA: [[OMP_JUMP_BACK]]:
+ // LAMBDA-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+ // LAMBDA: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+ // LAMBDA: br {{.+}} [[CMP_IV_UB]], label %[[DIST_BODY:.+]], label %[[DIST_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // LAMBDA: [[DIST_BODY]]:
+ // LAMBDA-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to
+ // LAMBDA-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to
+ // check that distlb and distub are properly passed to fork_call
+ // LAMBDA-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_2:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+ // LAMBDA-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_2:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+ // LAMBDA: br label %[[DIST_INC:.+]]
+
+ // increment by stride (distInc - 'parallel for' executes the whole chunk) and latch
+ // LAMBDA: [[DIST_INC]]:
+ // LAMBDA-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+ // LAMBDA: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_2]], [[OMP_ST_VAL_1]]
+ // LAMBDA: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[OMP_JUMP_BACK]]
+
+ // LAMBDA-DAG: call void @__kmpc_for_static_fini(
+ // LAMBDA: ret
+
+ // implementation of 'parallel for'
+ // LAMBDA: define{{.+}} void [[OMP_PARFOR_OUTLINED_2]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+ // LAMBDA-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // LAMBDA-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // LAMBDA-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+ // PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+ // In this case we use EUB
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+ // LAMBDA-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+ // LAMBDA: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // LAMBDA: [[PF_EUB_TRUE]]:
+ // LAMBDA: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+ // LAMBDA: br label %[[PF_EUB_END:.+]]
+ // LAMBDA-DAG: [[PF_EUB_FALSE]]:
+ // LAMBDA: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA: br label %[[PF_EUB_END]]
+ // LAMBDA-DAG: [[PF_EUB_END]]:
+ // LAMBDA-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+ // LAMBDA: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv
+ // LAMBDA: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+ // check exit condition
+ // LAMBDA: [[OMP_PF_JUMP_BACK]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+ // LAMBDA: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // LAMBDA: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // LAMBDA: [[PF_BODY]]:
+ // LAMBDA-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label {{.+}}
+
+ // check stride 1 for 'for' in 'distribute parallel for'
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+ // LAMBDA: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_JUMP_BACK]]
+
+ // LAMBDA-DAG: call void @__kmpc_for_static_fini(
+ // LAMBDA: ret
+ [&]() {
+ a[i] = b[i] + c[i];
+ }();
+ }
+
+ // dist_schedule: static chunk
+ #pragma omp target
+ #pragma omp teams
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN_3]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_3:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for dist_schedule(static, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // LAMBDA: define{{.+}} void [[OMP_OUTLINED_3]](
+ // LAMBDA-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // LAMBDA-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // LAMBDA-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // LAMBDA-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // unlike the previous tests, in this one we have a outer and inner loop for 'distribute'
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 91,
+ // LAMBDA: br label %[[DIST_OUTER_LOOP_HEADER:.+]]
+
+ // LAMBDA: [[DIST_OUTER_LOOP_HEADER]]:
+ // check EUB for distribute
+ // LAMBDA-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+ // LAMBDA: [[NUM_IT_1:%.+]] = load{{.+}},
+ // LAMBDA-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+ // LAMBDA: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+ // LAMBDA-DAG: [[EUB_TRUE]]:
+ // LAMBDA: [[NUM_IT_2:%.+]] = load{{.+}},
+ // LAMBDA: br label %[[EUB_END:.+]]
+ // LAMBDA-DAG: [[EUB_FALSE]]:
+ // LAMBDA: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+ // LAMBDA: br label %[[EUB_END]]
+ // LAMBDA-DAG: [[EUB_END]]:
+ // LAMBDA-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+ // LAMBDA: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+ // initialize omp.iv
+ // LAMBDA: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+ // LAMBDA: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+
+ // check exit condition
+ // LAMBDA-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+ // LAMBDA: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+ // LAMBDA: br {{.+}} [[CMP_IV_UB]], label %[[DIST_OUTER_LOOP_BODY:.+]], label %[[DIST_OUTER_LOOP_END:.+]]
+
+ // LAMBDA: [[DIST_OUTER_LOOP_BODY]]:
+ // LAMBDA: br label %[[DIST_INNER_LOOP_HEADER:.+]]
+
+ // LAMBDA: [[DIST_INNER_LOOP_HEADER]]:
+ // LAMBDA-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}} [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_UB_VAL_4:%.+]] = load {{.+}} [[OMP_UB]],
+ // LAMBDA: [[CMP_IV_UB_2:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_2]], [[OMP_UB_VAL_4]]
+ // LAMBDA: br{{.+}} [[CMP_IV_UB_2]], label %[[DIST_INNER_LOOP_BODY:.+]], label %[[DIST_INNER_LOOP_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // LAMBDA: [[DIST_INNER_LOOP_BODY]]:
+ // LAMBDA-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to {{.+}}
+ // LAMBDA-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to {{.+}}
+ // check that distlb and distub are properly passed to fork_call
+ // LAMBDA-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_3:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+ // LAMBDA-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_3:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+ // LAMBDA: br label %[[DIST_INNER_LOOP_INC:.+]]
+
+ // check DistInc
+ // LAMBDA: [[DIST_INNER_LOOP_INC]]:
+ // LAMBDA-DAG: [[OMP_IV_VAL_3:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+ // LAMBDA: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_3]], [[OMP_ST_VAL_1]]
+ // LAMBDA: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[DIST_INNER_LOOP_HEADER]]
+
+ // LAMBDA: [[DIST_INNER_LOOP_END]]:
+ // LAMBDA: br label %[[DIST_OUTER_LOOP_INC:.+]]
+
+ // LAMBDA: [[DIST_OUTER_LOOP_INC]]:
+ // check NextLB and NextUB
+ // LAMBDA-DAG: [[OMP_LB_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_LB]],
+ // LAMBDA-DAG: [[OMP_ST_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_ST]],
+ // LAMBDA-DAG: [[OMP_LB_NEXT:%.+]] = add{{.+}} [[OMP_LB_VAL_2]], [[OMP_ST_VAL_2]]
+ // LAMBDA: store{{.+}} [[OMP_LB_NEXT]], {{.+}}* [[OMP_LB]],
+ // LAMBDA-DAG: [[OMP_UB_VAL_5:%.+]] = load{{.+}}, {{.+}} [[OMP_UB]],
+ // LAMBDA-DAG: [[OMP_ST_VAL_3:%.+]] = load{{.+}}, {{.+}} [[OMP_ST]],
+ // LAMBDA-DAG: [[OMP_UB_NEXT:%.+]] = add{{.+}} [[OMP_UB_VAL_5]], [[OMP_ST_VAL_3]]
+ // LAMBDA: store{{.+}} [[OMP_UB_NEXT]], {{.+}}* [[OMP_UB]],
+ // LAMBDA: br label %[[DIST_OUTER_LOOP_HEADER]]
+
+ // outer loop exit
+ // LAMBDA: [[DIST_OUTER_LOOP_END]]:
+ // LAMBDA-DAG: call void @__kmpc_for_static_fini(
+ // LAMBDA: ret
+
+ // skip implementation of 'parallel for': using default scheduling and was tested above
+ [&]() {
+ a[i] = b[i] + c[i];
+ }();
+ }
+
+ // schedule: static no chunk
+ #pragma omp target
+ #pragma omp teams
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN_4]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_4:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(static)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // LAMBDA: define{{.+}} void [[OMP_OUTLINED_4]](
+ // LAMBDA-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // LAMBDA-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // LAMBDA-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // LAMBDA-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // LAMBDA: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_4:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // LAMBDA: ret
+
+ // 'parallel for' implementation is the same as the case without schedule clase (static no chunk is the default)
+ // LAMBDA: define{{.+}} void [[OMP_PARFOR_OUTLINED_4]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+ // LAMBDA-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // LAMBDA-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // LAMBDA-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+ // PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+ // In this case we use EUB
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+ // LAMBDA-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+ // LAMBDA: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // LAMBDA: [[PF_EUB_TRUE]]:
+ // LAMBDA: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+ // LAMBDA: br label %[[PF_EUB_END:.+]]
+ // LAMBDA-DAG: [[PF_EUB_FALSE]]:
+ // LAMBDA: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA: br label %[[PF_EUB_END]]
+ // LAMBDA-DAG: [[PF_EUB_END]]:
+ // LAMBDA-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+ // LAMBDA: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv
+ // LAMBDA: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+ // check exit condition
+ // LAMBDA: [[OMP_PF_JUMP_BACK]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+ // LAMBDA: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // LAMBDA: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // LAMBDA: [[PF_BODY]]:
+ // LAMBDA-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label {{.+}}
+
+ // check stride 1 for 'for' in 'distribute parallel for'
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+ // LAMBDA: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_JUMP_BACK]]
+
+ // LAMBDA-DAG: call void @__kmpc_for_static_fini(
+ // LAMBDA: ret
+
+ [&]() {
+ a[i] = b[i] + c[i];
+ }();
+ }
+
+ // schedule: static chunk
+ #pragma omp target
+ #pragma omp teams
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN_5]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_5:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(static, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // LAMBDA: define{{.+}} void [[OMP_OUTLINED_5]](
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // LAMBDA: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_5:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // LAMBDA: ret
+
+ // 'parallel for' implementation using outer and inner loops and PrevEUB
+ // LAMBDA: define{{.+}} void [[OMP_PARFOR_OUTLINED_5]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}})
+ // LAMBDA-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // LAMBDA-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // LAMBDA-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 33, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+ // check PrevEUB (using PrevUB instead of NumIt as upper bound)
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_HEADER]]:
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA-64-DAG: [[OMP_PF_UB_VAL_CONV:%.+]] = sext{{.+}} [[OMP_PF_UB_VAL_1]] to
+ // LAMBDA: [[PF_PREV_UB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA-64-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_CONV]], [[PF_PREV_UB_VAL_1]]
+ // LAMBDA-32-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_PREV_UB_VAL_1]]
+ // LAMBDA: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // LAMBDA: [[PF_EUB_TRUE]]:
+ // LAMBDA: [[PF_PREV_UB_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA: br label %[[PF_EUB_END:.+]]
+ // LAMBDA-DAG: [[PF_EUB_FALSE]]:
+ // LAMBDA: [[OMP_PF_UB_VAL_2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // LAMBDA-64: [[OMP_PF_UB_VAL_2_CONV:%.+]] = sext{{.+}} [[OMP_PF_UB_VAL_2]] to
+ // LAMBDA: br label %[[PF_EUB_END]]
+ // LAMBDA-DAG: [[PF_EUB_END]]:
+ // LAMBDA-64-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_PREV_UB_VAL_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL_2_CONV]], %[[PF_EUB_FALSE]] ]
+ // LAMBDA-32-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_PREV_UB_VAL_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL_2]], %[[PF_EUB_FALSE]] ]
+ // LAMBDA-64-DAG: [[PF_EUB_RES_CONV:%.+]] = trunc{{.+}} [[PF_EUB_RES]] to
+ // LAMBDA-64: store{{.+}} [[PF_EUB_RES_CONV]],{{.+}} [[OMP_PF_UB]],
+ // LAMBDA-32: store{{.+}} [[PF_EUB_RES]], {{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv (IV = LB)
+ // LAMBDA: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+
+ // outer loop: while (IV < UB) {
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: [[PF_CMP_IV_UB_1:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // LAMBDA: br{{.+}} [[PF_CMP_IV_UB_1]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_BODY]]:
+ // LAMBDA: br label %[[OMP_PF_INNER_FOR_HEADER:.+]]
+
+ // LAMBDA: [[OMP_PF_INNER_FOR_HEADER]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+ // LAMBDA: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+ // LAMBDA: [[OMP_PF_INNER_LOOP_BODY]]:
+ // LAMBDA-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // skip body branch
+ // LAMBDA: br{{.+}}
+ // LAMBDA: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+ // IV = IV + 1 and inner loop latch
+ // LAMBDA: [[OMP_PF_INNER_LOOP_INC]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+ // LAMBDA-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[OMP_PF_INNER_FOR_HEADER]]
+
+ // check NextLB and NextUB
+ // LAMBDA: [[OMP_PF_INNER_LOOP_END]]:
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_INC]]:
+ // LAMBDA-DAG: [[OMP_PF_LB_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA-DAG: [[OMP_PF_ST_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_ST]],
+ // LAMBDA-DAG: [[OMP_PF_LB_NEXT:%.+]] = add{{.+}} [[OMP_PF_LB_VAL_2]], [[OMP_PF_ST_VAL_1]]
+ // LAMBDA: store{{.+}} [[OMP_PF_LB_NEXT]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_5:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+ // LAMBDA-DAG: [[OMP_PF_ST_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_ST]],
+ // LAMBDA-DAG: [[OMP_PF_UB_NEXT:%.+]] = add{{.+}} [[OMP_PF_UB_VAL_5]], [[OMP_PF_ST_VAL_2]]
+ // LAMBDA: store{{.+}} [[OMP_PF_UB_NEXT]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_END]]:
+ // LAMBDA-DAG: call void @__kmpc_for_static_fini(
+ // LAMBDA: ret
+ [&]() {
+ a[i] = b[i] + c[i];
+ }();
+ }
+
+ // schedule: dynamic no chunk
+ #pragma omp target
+ #pragma omp teams
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN_6]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_6:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(dynamic)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // LAMBDA: define{{.+}} void [[OMP_OUTLINED_6]](
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // LAMBDA: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_6:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // LAMBDA: ret
+
+ // 'parallel for' implementation using outer and inner loops and PrevEUB
+ // LAMBDA: define{{.+}} void [[OMP_PARFOR_OUTLINED_6]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+ // LAMBDA-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // LAMBDA-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // LAMBDA-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-DAG: [[OMP_PF_LB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+ // LAMBDA: call void @__kmpc_dispatch_init_4({{.+}}, {{.+}}, {{.+}} 35, {{.+}} [[OMP_PF_LB_VAL]], {{.+}} [[OMP_PF_UB_VAL]], {{.+}}, {{.+}})
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_HEADER]]:
+ // LAMBDA: [[IS_FIN:%.+]] = call{{.+}} @__kmpc_dispatch_next_4({{.+}}, {{.+}}, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]], {{.+}}* [[OMP_PF_ST]])
+ // LAMBDA: [[IS_FIN_CMP:%.+]] = icmp{{.+}} [[IS_FIN]], 0
+ // LAMBDA: br{{.+}} [[IS_FIN_CMP]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+ // initialize omp.iv (IV = LB)
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_BODY]]:
+ // LAMBDA-DAG: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA-DAG: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_INNER_LOOP_HEADER:.+]]
+
+ // LAMBDA: [[OMP_PF_INNER_LOOP_HEADER]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+ // LAMBDA: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+ // LAMBDA: [[OMP_PF_INNER_LOOP_BODY]]:
+ // LAMBDA-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // skip body branch
+ // LAMBDA: br{{.+}}
+ // LAMBDA: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+ // IV = IV + 1 and inner loop latch
+ // LAMBDA: [[OMP_PF_INNER_LOOP_INC]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+ // LAMBDA-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[OMP_PF_INNER_LOOP_HEADER]]
+
+ // check NextLB and NextUB
+ // LAMBDA: [[OMP_PF_INNER_LOOP_END]]:
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_INC]]:
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_END]]:
+ // LAMBDA: ret
+ [&]() {
+ a[i] = b[i] + c[i];
+ }();
+ }
+
+ // schedule: dynamic chunk
+ #pragma omp target
+ #pragma omp teams
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN_7]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_7:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(dynamic, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // LAMBDA: define{{.+}} void [[OMP_OUTLINED_7]](
+ // LAMBDA: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // LAMBDA: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_7:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // LAMBDA: ret
+
+ // 'parallel for' implementation using outer and inner loops and PrevEUB
+ // LAMBDA: define{{.+}} void [[OMP_PARFOR_OUTLINED_7]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}})
+ // LAMBDA-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+ // LAMBDA-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // LAMBDA-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // LAMBDA-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // LAMBDA-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // LAMBDA-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // LAMBDA-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA-DAG: [[OMP_PF_LB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+ // LAMBDA: call void @__kmpc_dispatch_init_4({{.+}}, {{.+}}, {{.+}} 35, {{.+}} [[OMP_PF_LB_VAL]], {{.+}} [[OMP_PF_UB_VAL]], {{.+}}, {{.+}})
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_HEADER]]:
+ // LAMBDA: [[IS_FIN:%.+]] = call{{.+}} @__kmpc_dispatch_next_4({{.+}}, {{.+}}, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]], {{.+}}* [[OMP_PF_ST]])
+ // LAMBDA: [[IS_FIN_CMP:%.+]] = icmp{{.+}} [[IS_FIN]], 0
+ // LAMBDA: br{{.+}} [[IS_FIN_CMP]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+ // initialize omp.iv (IV = LB)
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_BODY]]:
+ // LAMBDA-DAG: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // LAMBDA-DAG: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA: br label %[[OMP_PF_INNER_LOOP_HEADER:.+]]
+
+ // LAMBDA: [[OMP_PF_INNER_LOOP_HEADER]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // LAMBDA-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // LAMBDA: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+ // LAMBDA: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+ // LAMBDA: [[OMP_PF_INNER_LOOP_BODY]]:
+ // LAMBDA-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // skip body branch
+ // LAMBDA: br{{.+}}
+ // LAMBDA: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+ // IV = IV + 1 and inner loop latch
+ // LAMBDA: [[OMP_PF_INNER_LOOP_INC]]:
+ // LAMBDA-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+ // LAMBDA-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+ // LAMBDA-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+ // LAMBDA: br label %[[OMP_PF_INNER_LOOP_HEADER]]
+
+ // check NextLB and NextUB
+ // LAMBDA: [[OMP_PF_INNER_LOOP_END]]:
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_INC]]:
+ // LAMBDA: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+ // LAMBDA: [[OMP_PF_OUTER_LOOP_END]]:
+ // LAMBDA: ret
+ [&]() {
+ a[i] = b[i] + c[i];
+ }();
+ }
+ }();
+ return 0;
+#else
+ // CHECK-LABEL: @main
+
+ // CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+ // CHECK: call void [[OFFLOADING_FUN_1:@.+]](
+
+ // CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+ // CHECK: call void [[OFFLOADING_FUN_2:@.+]](
+
+ // CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+ // CHECK: call void [[OFFLOADING_FUN_3:@.+]](
+
+ // CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+ // CHECK: call void [[OFFLOADING_FUN_4:@.+]](
+
+ // CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+ // CHECK: call void [[OFFLOADING_FUN_5:@.+]](
+
+ // CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+ // CHECK: call void [[OFFLOADING_FUN_6:@.+]](
+
+ // CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+ // CHECK: call void [[OFFLOADING_FUN_7:@.+]](
+
+ // CHECK: call{{.+}} [[TMAIN:@.+]]()
+
+ // no schedule clauses
+ #pragma omp target
+ #pragma omp teams
+ // CHECK: define internal void [[OFFLOADING_FUN_1]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_1:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_1]](
+ // CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+
+ // check EUB for distribute
+ // CHECK-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+ // CHECK: [[NUM_IT_1:%.+]] = load{{.+}},
+ // CHECK-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+ // CHECK: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+ // CHECK-DAG: [[EUB_TRUE]]:
+ // CHECK: [[NUM_IT_2:%.+]] = load{{.+}},
+ // CHECK: br label %[[EUB_END:.+]]
+ // CHECK-DAG: [[EUB_FALSE]]:
+ // CHECK: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+ // CHECK: br label %[[EUB_END]]
+ // CHECK-DAG: [[EUB_END]]:
+ // CHECK-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+ // CHECK: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+ // initialize omp.iv
+ // CHECK: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+ // CHECK: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[OMP_JUMP_BACK:.+]]
+
+ // check exit condition
+ // CHECK: [[OMP_JUMP_BACK]]:
+ // CHECK-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+ // CHECK-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+ // CHECK: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+ // CHECK: br {{.+}} [[CMP_IV_UB]], label %[[DIST_BODY:.+]], label %[[DIST_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // CHECK: [[DIST_BODY]]:
+ // CHECK-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to {{.+}}
+ // check that distlb and distub are properly passed to fork_call
+ // CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_1:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+ // CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_1:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+ // CHECK: br label %[[DIST_INC:.+]]
+
+ // increment by stride (distInc - 'parallel for' executes the whole chunk) and latch
+ // CHECK: [[DIST_INC]]:
+ // CHECK-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+ // CHECK-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+ // CHECK: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_2]], [[OMP_ST_VAL_1]]
+ // CHECK: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[OMP_JUMP_BACK]]
+
+ // CHECK-DAG: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+
+ // implementation of 'parallel for'
+ // CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_1]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+ // CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+ // PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+ // In this case we use EUB
+ // CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+ // CHECK-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+ // CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // CHECK: [[PF_EUB_TRUE]]:
+ // CHECK: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+ // CHECK: br label %[[PF_EUB_END:.+]]
+ // CHECK-DAG: [[PF_EUB_FALSE]]:
+ // CHECK: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK: br label %[[PF_EUB_END]]
+ // CHECK-DAG: [[PF_EUB_END]]:
+ // CHECK-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+ // CHECK: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv
+ // CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+ // check exit condition
+ // CHECK: [[OMP_PF_JUMP_BACK]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+ // CHECK: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // CHECK: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // CHECK: [[PF_BODY]]:
+ // CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label {{.+}}
+
+ // check stride 1 for 'for' in 'distribute parallel for'
+ // CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+ // CHECK: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_JUMP_BACK]]
+
+ // CHECK-DAG: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+ }
+
+ // dist_schedule: static no chunk
+ #pragma omp target
+ #pragma omp teams
+ // CHECK: define{{.+}} void [[OFFLOADING_FUN_2]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_2:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for dist_schedule(static)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_2]](
+ // CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+
+ // check EUB for distribute
+ // CHECK-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+ // CHECK: [[NUM_IT_1:%.+]] = load{{.+}},
+ // CHECK-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+ // CHECK: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+ // CHECK-DAG: [[EUB_TRUE]]:
+ // CHECK: [[NUM_IT_2:%.+]] = load{{.+}},
+ // CHECK: br label %[[EUB_END:.+]]
+ // CHECK-DAG: [[EUB_FALSE]]:
+ // CHECK: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+ // CHECK: br label %[[EUB_END]]
+ // CHECK-DAG: [[EUB_END]]:
+ // CHECK-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+ // CHECK: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+ // initialize omp.iv
+ // CHECK: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+ // CHECK: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[OMP_JUMP_BACK:.+]]
+
+ // check exit condition
+ // CHECK: [[OMP_JUMP_BACK]]:
+ // CHECK-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+ // CHECK-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+ // CHECK: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+ // CHECK: br {{.+}} [[CMP_IV_UB]], label %[[DIST_BODY:.+]], label %[[DIST_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // CHECK: [[DIST_BODY]]:
+ // CHECK-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to {{.+}}
+ // check that distlb and distub are properly passed to fork_call
+ // CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_2:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+ // CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_2:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+ // CHECK: br label %[[DIST_INC:.+]]
+
+ // increment by stride (distInc - 'parallel for' executes the whole chunk) and latch
+ // CHECK: [[DIST_INC]]:
+ // CHECK-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+ // CHECK-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+ // CHECK: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_2]], [[OMP_ST_VAL_1]]
+ // CHECK: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[OMP_JUMP_BACK]]
+
+ // CHECK-DAG: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+
+ // implementation of 'parallel for'
+ // CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_2]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+ // CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+ // PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+ // In this case we use EUB
+ // CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+ // CHECK-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+ // CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // CHECK: [[PF_EUB_TRUE]]:
+ // CHECK: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+ // CHECK: br label %[[PF_EUB_END:.+]]
+ // CHECK-DAG: [[PF_EUB_FALSE]]:
+ // CHECK: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK: br label %[[PF_EUB_END]]
+ // CHECK-DAG: [[PF_EUB_END]]:
+ // CHECK-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+ // CHECK: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv
+ // CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+ // check exit condition
+ // CHECK: [[OMP_PF_JUMP_BACK]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+ // CHECK: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // CHECK: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // CHECK: [[PF_BODY]]:
+ // CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label {{.+}}
+
+ // check stride 1 for 'for' in 'distribute parallel for'
+ // CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+ // CHECK: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_JUMP_BACK]]
+
+ // CHECK-DAG: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+ }
+
+ // dist_schedule: static chunk
+ #pragma omp target
+ #pragma omp teams
+ // CHECK: define{{.+}} void [[OFFLOADING_FUN_3]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_3:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for dist_schedule(static, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_3]](
+ // CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // unlike the previous tests, in this one we have a outer and inner loop for 'distribute'
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 91,
+ // CHECK: br label %[[DIST_OUTER_LOOP_HEADER:.+]]
+
+ // CHECK: [[DIST_OUTER_LOOP_HEADER]]:
+ // check EUB for distribute
+ // CHECK-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+ // CHECK: [[NUM_IT_1:%.+]] = load{{.+}},
+ // CHECK-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+ // CHECK: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+ // CHECK-DAG: [[EUB_TRUE]]:
+ // CHECK: [[NUM_IT_2:%.+]] = load{{.+}},
+ // CHECK: br label %[[EUB_END:.+]]
+ // CHECK-DAG: [[EUB_FALSE]]:
+ // CHECK: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+ // CHECK: br label %[[EUB_END]]
+ // CHECK-DAG: [[EUB_END]]:
+ // CHECK-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+ // CHECK: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+ // initialize omp.iv
+ // CHECK: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+ // CHECK: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+
+ // check exit condition
+ // CHECK-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+ // CHECK-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+ // CHECK: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+ // CHECK: br {{.+}} [[CMP_IV_UB]], label %[[DIST_OUTER_LOOP_BODY:.+]], label %[[DIST_OUTER_LOOP_END:.+]]
+
+ // CHECK: [[DIST_OUTER_LOOP_BODY]]:
+ // CHECK: br label %[[DIST_INNER_LOOP_HEADER:.+]]
+
+ // CHECK: [[DIST_INNER_LOOP_HEADER]]:
+ // CHECK-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}} [[OMP_IV]],
+ // CHECK-DAG: [[OMP_UB_VAL_4:%.+]] = load {{.+}} [[OMP_UB]],
+ // CHECK: [[CMP_IV_UB_2:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_2]], [[OMP_UB_VAL_4]]
+ // CHECK: br{{.+}} [[CMP_IV_UB_2]], label %[[DIST_INNER_LOOP_BODY:.+]], label %[[DIST_INNER_LOOP_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // CHECK: [[DIST_INNER_LOOP_BODY]]:
+ // CHECK-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to {{.+}}
+ // check that distlb and distub are properly passed to fork_call
+ // CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_3:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+ // CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_3:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+ // CHECK: br label %[[DIST_INNER_LOOP_INC:.+]]
+
+ // check DistInc
+ // CHECK: [[DIST_INNER_LOOP_INC]]:
+ // CHECK-DAG: [[OMP_IV_VAL_3:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+ // CHECK-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+ // CHECK: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_3]], [[OMP_ST_VAL_1]]
+ // CHECK: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[DIST_INNER_LOOP_HEADER]]
+
+ // CHECK: [[DIST_INNER_LOOP_END]]:
+ // CHECK: br label %[[DIST_OUTER_LOOP_INC:.+]]
+
+ // CHECK: [[DIST_OUTER_LOOP_INC]]:
+ // check NextLB and NextUB
+ // CHECK-DAG: [[OMP_LB_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_LB]],
+ // CHECK-DAG: [[OMP_ST_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_ST]],
+ // CHECK-DAG: [[OMP_LB_NEXT:%.+]] = add{{.+}} [[OMP_LB_VAL_2]], [[OMP_ST_VAL_2]]
+ // CHECK: store{{.+}} [[OMP_LB_NEXT]], {{.+}}* [[OMP_LB]],
+ // CHECK-DAG: [[OMP_UB_VAL_5:%.+]] = load{{.+}}, {{.+}} [[OMP_UB]],
+ // CHECK-DAG: [[OMP_ST_VAL_3:%.+]] = load{{.+}}, {{.+}} [[OMP_ST]],
+ // CHECK-DAG: [[OMP_UB_NEXT:%.+]] = add{{.+}} [[OMP_UB_VAL_5]], [[OMP_ST_VAL_3]]
+ // CHECK: store{{.+}} [[OMP_UB_NEXT]], {{.+}}* [[OMP_UB]],
+ // CHECK: br label %[[DIST_OUTER_LOOP_HEADER]]
+
+ // outer loop exit
+ // CHECK: [[DIST_OUTER_LOOP_END]]:
+ // CHECK-DAG: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+
+ // skip implementation of 'parallel for': using default scheduling and was tested above
+ }
+
+ // schedule: static no chunk
+ #pragma omp target
+ #pragma omp teams
+ // CHECK: define{{.+}} void [[OFFLOADING_FUN_4]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_4:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(static)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_4]](
+ // CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+ // CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+ // CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+ // CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_4:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // CHECK: ret
+
+ // 'parallel for' implementation is the same as the case without schedule clase (static no chunk is the default)
+ // CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_4]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+ // CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+ // PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+ // In this case we use EUB
+ // CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+ // CHECK-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+ // CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // CHECK: [[PF_EUB_TRUE]]:
+ // CHECK: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+ // CHECK: br label %[[PF_EUB_END:.+]]
+ // CHECK-DAG: [[PF_EUB_FALSE]]:
+ // CHECK: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK: br label %[[PF_EUB_END]]
+ // CHECK-DAG: [[PF_EUB_END]]:
+ // CHECK-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+ // CHECK: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv
+ // CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+ // check exit condition
+ // CHECK: [[OMP_PF_JUMP_BACK]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+ // CHECK: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // CHECK: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+ // check that PrevLB and PrevUB are passed to the 'for'
+ // CHECK: [[PF_BODY]]:
+ // CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label {{.+}}
+
+ // check stride 1 for 'for' in 'distribute parallel for'
+ // CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+ // CHECK: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_JUMP_BACK]]
+
+ // CHECK-DAG: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+ }
+
+ // schedule: static chunk
+ #pragma omp target
+ #pragma omp teams
+ // CHECK: define{{.+}} void [[OFFLOADING_FUN_5]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_5:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(static, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_5]](
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_5:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // CHECK: ret
+
+ // 'parallel for' implementation using outer and inner loops and PrevEUB
+ // CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_5]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}})
+ // CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 33, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+ // check PrevEUB (using PrevUB instead of NumIt as upper bound)
+ // CHECK: [[OMP_PF_OUTER_LOOP_HEADER]]:
+ // CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK-64-DAG: [[OMP_PF_UB_VAL_CONV:%.+]] = sext{{.+}} [[OMP_PF_UB_VAL_1]] to
+ // CHECK: [[PF_PREV_UB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK-64-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_CONV]], [[PF_PREV_UB_VAL_1]]
+ // CHECK-32-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_PREV_UB_VAL_1]]
+ // CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+ // CHECK: [[PF_EUB_TRUE]]:
+ // CHECK: [[PF_PREV_UB_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK: br label %[[PF_EUB_END:.+]]
+ // CHECK-DAG: [[PF_EUB_FALSE]]:
+ // CHECK: [[OMP_PF_UB_VAL_2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+ // CHECK-64: [[OMP_PF_UB_VAL_2_CONV:%.+]] = sext{{.+}} [[OMP_PF_UB_VAL_2]] to
+ // CHECK: br label %[[PF_EUB_END]]
+ // CHECK-DAG: [[PF_EUB_END]]:
+ // CHECK-64-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_PREV_UB_VAL_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL_2_CONV]], %[[PF_EUB_FALSE]] ]
+ // CHECK-32-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_PREV_UB_VAL_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL_2]], %[[PF_EUB_FALSE]] ]
+ // CHECK-64-DAG: [[PF_EUB_RES_CONV:%.+]] = trunc{{.+}} [[PF_EUB_RES]] to
+ // CHECK-64: store{{.+}} [[PF_EUB_RES_CONV]],{{.+}} [[OMP_PF_UB]],
+ // CHECK-32: store{{.+}} [[PF_EUB_RES]], {{.+}} [[OMP_PF_UB]],
+
+ // initialize omp.iv (IV = LB)
+ // CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+
+ // outer loop: while (IV < UB) {
+ // CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // CHECK: [[PF_CMP_IV_UB_1:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+ // CHECK: br{{.+}} [[PF_CMP_IV_UB_1]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_BODY]]:
+ // CHECK: br label %[[OMP_PF_INNER_FOR_HEADER:.+]]
+
+ // CHECK: [[OMP_PF_INNER_FOR_HEADER]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // CHECK: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+ // CHECK: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+ // CHECK: [[OMP_PF_INNER_LOOP_BODY]]:
+ // CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // skip body branch
+ // CHECK: br{{.+}}
+ // CHECK: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+ // IV = IV + 1 and inner loop latch
+ // CHECK: [[OMP_PF_INNER_LOOP_INC]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+ // CHECK-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+ // CHECK-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[OMP_PF_INNER_FOR_HEADER]]
+
+ // check NextLB and NextUB
+ // CHECK: [[OMP_PF_INNER_LOOP_END]]:
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_INC]]:
+ // CHECK-DAG: [[OMP_PF_LB_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK-DAG: [[OMP_PF_ST_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_ST]],
+ // CHECK-DAG: [[OMP_PF_LB_NEXT:%.+]] = add{{.+}} [[OMP_PF_LB_VAL_2]], [[OMP_PF_ST_VAL_1]]
+ // CHECK: store{{.+}} [[OMP_PF_LB_NEXT]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_5:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+ // CHECK-DAG: [[OMP_PF_ST_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_ST]],
+ // CHECK-DAG: [[OMP_PF_UB_NEXT:%.+]] = add{{.+}} [[OMP_PF_UB_VAL_5]], [[OMP_PF_ST_VAL_2]]
+ // CHECK: store{{.+}} [[OMP_PF_UB_NEXT]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_END]]:
+ // CHECK-DAG: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+ }
+
+ // schedule: dynamic no chunk
+ #pragma omp target
+ #pragma omp teams
+ // CHECK: define{{.+}} void [[OFFLOADING_FUN_6]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_6:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(dynamic)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_6]](
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_6:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // CHECK: ret
+
+ // 'parallel for' implementation using outer and inner loops and PrevEUB
+ // CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_6]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+ // CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-DAG: [[OMP_PF_LB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+ // CHECK: call void @__kmpc_dispatch_init_4({{.+}}, {{.+}}, {{.+}} 35, {{.+}} [[OMP_PF_LB_VAL]], {{.+}} [[OMP_PF_UB_VAL]], {{.+}}, {{.+}})
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_HEADER]]:
+ // CHECK: [[IS_FIN:%.+]] = call{{.+}} @__kmpc_dispatch_next_4({{.+}}, {{.+}}, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]], {{.+}}* [[OMP_PF_ST]])
+ // CHECK: [[IS_FIN_CMP:%.+]] = icmp{{.+}} [[IS_FIN]], 0
+ // CHECK: br{{.+}} [[IS_FIN_CMP]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+ // initialize omp.iv (IV = LB)
+ // CHECK: [[OMP_PF_OUTER_LOOP_BODY]]:
+ // CHECK-DAG: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK-DAG: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER:.+]]
+
+ // CHECK: [[OMP_PF_INNER_LOOP_HEADER]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // CHECK: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+ // CHECK: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+ // CHECK: [[OMP_PF_INNER_LOOP_BODY]]:
+ // CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // skip body branch
+ // CHECK: br{{.+}}
+ // CHECK: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+ // IV = IV + 1 and inner loop latch
+ // CHECK: [[OMP_PF_INNER_LOOP_INC]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+ // CHECK-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+ // CHECK-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER]]
+
+ // check NextLB and NextUB
+ // CHECK: [[OMP_PF_INNER_LOOP_END]]:
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_INC]]:
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_END]]:
+ // CHECK: ret
+ }
+
+ // schedule: dynamic chunk
+ #pragma omp target
+ #pragma omp teams
+ // CHECK: define{{.+}} void [[OFFLOADING_FUN_7]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_7:@.+]] to {{.+}})
+
+ #pragma omp distribute parallel for schedule(dynamic, ch)
+ for (int i = 0; i < n; ++i) {
+ a[i] = b[i] + c[i];
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_7]](
+ // CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+ // CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_7:@.+]] to {{.+}},
+ // skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+ // CHECK: ret
+
+ // 'parallel for' implementation using outer and inner loops and PrevEUB
+ // CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_7]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}})
+ // CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+ // CHECK-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+ // initialize lb and ub to PrevLB and PrevUB
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+ // CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+ // CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+ // CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+ // CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+ // CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+ // CHECK-DAG: [[OMP_PF_LB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+ // CHECK: call void @__kmpc_dispatch_init_4({{.+}}, {{.+}}, {{.+}} 35, {{.+}} [[OMP_PF_LB_VAL]], {{.+}} [[OMP_PF_UB_VAL]], {{.+}}, {{.+}})
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_HEADER]]:
+ // CHECK: [[IS_FIN:%.+]] = call{{.+}} @__kmpc_dispatch_next_4({{.+}}, {{.+}}, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]], {{.+}}* [[OMP_PF_ST]])
+ // CHECK: [[IS_FIN_CMP:%.+]] = icmp{{.+}} [[IS_FIN]], 0
+ // CHECK: br{{.+}} [[IS_FIN_CMP]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+ // initialize omp.iv (IV = LB)
+ // CHECK: [[OMP_PF_OUTER_LOOP_BODY]]:
+ // CHECK-DAG: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+ // CHECK-DAG: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+ // CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER:.+]]
+
+ // CHECK: [[OMP_PF_INNER_LOOP_HEADER]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // CHECK-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+ // CHECK: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+ // CHECK: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+ // CHECK: [[OMP_PF_INNER_LOOP_BODY]]:
+ // CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+ // skip body branch
+ // CHECK: br{{.+}}
+ // CHECK: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+ // IV = IV + 1 and inner loop latch
+ // CHECK: [[OMP_PF_INNER_LOOP_INC]]:
+ // CHECK-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+ // CHECK-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+ // CHECK-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+ // CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER]]
+
+ // check NextLB and NextUB
+ // CHECK: [[OMP_PF_INNER_LOOP_END]]:
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_INC]]:
+ // CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+ // CHECK: [[OMP_PF_OUTER_LOOP_END]]:
+ // CHECK: ret
+ }
+
+ return tmain<int>();
+#endif
+}
+
+// check code
+// CHECK: define{{.+}} [[TMAIN]]()
+
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_1:@.+]](
+
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_2:@.+]](
+
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_3:@.+]](
+
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_4:@.+]](
+
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_5:@.+]](
+
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_6:@.+]](
+
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_7:@.+]](
+
+// CHECK: define{{.+}} void [[OFFLOADING_FUN_1]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_1:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[OMP_OUTLINED_1]](
+// CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+// CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+// CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+// CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+
+// check EUB for distribute
+// CHECK-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+// CHECK: [[NUM_IT_1:%.+]] = load{{.+}},
+// CHECK-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+// CHECK: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+// CHECK-DAG: [[EUB_TRUE]]:
+// CHECK: [[NUM_IT_2:%.+]] = load{{.+}},
+// CHECK: br label %[[EUB_END:.+]]
+// CHECK-DAG: [[EUB_FALSE]]:
+// CHECK: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+// CHECK: br label %[[EUB_END]]
+// CHECK-DAG: [[EUB_END]]:
+// CHECK-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+// CHECK: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+// initialize omp.iv
+// CHECK: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+// CHECK: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[OMP_JUMP_BACK:.+]]
+
+// check exit condition
+// CHECK: [[OMP_JUMP_BACK]]:
+// CHECK-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+// CHECK-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+// CHECK: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+// CHECK: br {{.+}} [[CMP_IV_UB]], label %[[DIST_BODY:.+]], label %[[DIST_END:.+]]
+
+// check that PrevLB and PrevUB are passed to the 'for'
+// CHECK: [[DIST_BODY]]:
+// CHECK-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+// CHECK-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+// CHECK-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to {{.+}}
+// check that distlb and distub are properly passed to fork_call
+// CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_1:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+// CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_1:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+// CHECK: br label %[[DIST_INC:.+]]
+
+// increment by stride (distInc - 'parallel for' executes the whole chunk) and latch
+// CHECK: [[DIST_INC]]:
+// CHECK-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+// CHECK-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+// CHECK: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_2]], [[OMP_ST_VAL_1]]
+// CHECK: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[OMP_JUMP_BACK]]
+
+// CHECK-DAG: call void @__kmpc_for_static_fini(
+// CHECK: ret
+
+// implementation of 'parallel for'
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_1]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+// CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+// initialize lb and ub to PrevLB and PrevUB
+// CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+// CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+// CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+// PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+// In this case we use EUB
+// CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+// CHECK-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+// CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+// CHECK: [[PF_EUB_TRUE]]:
+// CHECK: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+// CHECK: br label %[[PF_EUB_END:.+]]
+// CHECK-DAG: [[PF_EUB_FALSE]]:
+// CHECK: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK: br label %[[PF_EUB_END]]
+// CHECK-DAG: [[PF_EUB_END]]:
+// CHECK-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+// CHECK: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+// initialize omp.iv
+// CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+// check exit condition
+// CHECK: [[OMP_PF_JUMP_BACK]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+// CHECK: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+// CHECK: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+// check that PrevLB and PrevUB are passed to the 'for'
+// CHECK: [[PF_BODY]]:
+// CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label {{.+}}
+
+// check stride 1 for 'for' in 'distribute parallel for'
+// CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+// CHECK: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_JUMP_BACK]]
+
+// CHECK-DAG: call void @__kmpc_for_static_fini(
+// CHECK: ret
+
+// CHECK: define{{.+}} void [[OFFLOADING_FUN_2]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_2:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[OMP_OUTLINED_2]](
+// CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+// CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+// CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+// CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+
+// check EUB for distribute
+// CHECK-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+// CHECK: [[NUM_IT_1:%.+]] = load{{.+}},
+// CHECK-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+// CHECK: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+// CHECK-DAG: [[EUB_TRUE]]:
+// CHECK: [[NUM_IT_2:%.+]] = load{{.+}},
+// CHECK: br label %[[EUB_END:.+]]
+// CHECK-DAG: [[EUB_FALSE]]:
+// CHECK: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+// CHECK: br label %[[EUB_END]]
+// CHECK-DAG: [[EUB_END]]:
+// CHECK-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+// CHECK: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+// initialize omp.iv
+// CHECK: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+// CHECK: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[OMP_JUMP_BACK:.+]]
+
+// check exit condition
+// CHECK: [[OMP_JUMP_BACK]]:
+// CHECK-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+// CHECK-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+// CHECK: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+// CHECK: br {{.+}} [[CMP_IV_UB]], label %[[DIST_BODY:.+]], label %[[DIST_END:.+]]
+
+// check that PrevLB and PrevUB are passed to the 'for'
+// CHECK: [[DIST_BODY]]:
+// CHECK-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+// CHECK-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+// CHECK-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to {{.+}}
+// check that distlb and distub are properly passed to fork_call
+// CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_2:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+// CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_2:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+// CHECK: br label %[[DIST_INC:.+]]
+
+// increment by stride (distInc - 'parallel for' executes the whole chunk) and latch
+// CHECK: [[DIST_INC]]:
+// CHECK-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+// CHECK-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+// CHECK: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_2]], [[OMP_ST_VAL_1]]
+// CHECK: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[OMP_JUMP_BACK]]
+
+// CHECK-DAG: call void @__kmpc_for_static_fini(
+// CHECK: ret
+
+// implementation of 'parallel for'
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_2]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+// CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+// initialize lb and ub to PrevLB and PrevUB
+// CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+// CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+// CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+// PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+// In this case we use EUB
+// CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+// CHECK-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+// CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+// CHECK: [[PF_EUB_TRUE]]:
+// CHECK: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+// CHECK: br label %[[PF_EUB_END:.+]]
+// CHECK-DAG: [[PF_EUB_FALSE]]:
+// CHECK: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK: br label %[[PF_EUB_END]]
+// CHECK-DAG: [[PF_EUB_END]]:
+// CHECK-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+// CHECK: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+// initialize omp.iv
+// CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+// check exit condition
+// CHECK: [[OMP_PF_JUMP_BACK]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+// CHECK: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+// CHECK: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+// check that PrevLB and PrevUB are passed to the 'for'
+// CHECK: [[PF_BODY]]:
+// CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label {{.+}}
+
+// check stride 1 for 'for' in 'distribute parallel for'
+// CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+// CHECK: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_JUMP_BACK]]
+
+// CHECK-DAG: call void @__kmpc_for_static_fini(
+// CHECK: ret
+
+// CHECK: define{{.+}} void [[OFFLOADING_FUN_3]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_3:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[OMP_OUTLINED_3]](
+// CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+// CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+// CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+// CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+// unlike the previous tests, in this one we have a outer and inner loop for 'distribute'
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 91,
+// CHECK: br label %[[DIST_OUTER_LOOP_HEADER:.+]]
+
+// CHECK: [[DIST_OUTER_LOOP_HEADER]]:
+// check EUB for distribute
+// CHECK-DAG: [[OMP_UB_VAL_1:%.+]] = load{{.+}} [[OMP_UB]],
+// CHECK: [[NUM_IT_1:%.+]] = load{{.+}},
+// CHECK-DAG: [[CMP_UB_NUM_IT:%.+]] = icmp sgt {{.+}} [[OMP_UB_VAL_1]], [[NUM_IT_1]]
+// CHECK: br {{.+}} [[CMP_UB_NUM_IT]], label %[[EUB_TRUE:.+]], label %[[EUB_FALSE:.+]]
+// CHECK-DAG: [[EUB_TRUE]]:
+// CHECK: [[NUM_IT_2:%.+]] = load{{.+}},
+// CHECK: br label %[[EUB_END:.+]]
+// CHECK-DAG: [[EUB_FALSE]]:
+// CHECK: [[OMP_UB_VAL2:%.+]] = load{{.+}} [[OMP_UB]],
+// CHECK: br label %[[EUB_END]]
+// CHECK-DAG: [[EUB_END]]:
+// CHECK-DAG: [[EUB_RES:%.+]] = phi{{.+}} [ [[NUM_IT_2]], %[[EUB_TRUE]] ], [ [[OMP_UB_VAL2]], %[[EUB_FALSE]] ]
+// CHECK: store{{.+}} [[EUB_RES]], {{.+}}* [[OMP_UB]],
+
+// initialize omp.iv
+// CHECK: [[OMP_LB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_LB]],
+// CHECK: store {{.+}} [[OMP_LB_VAL_1]], {{.+}}* [[OMP_IV]],
+
+// check exit condition
+// CHECK-DAG: [[OMP_IV_VAL_1:%.+]] = load {{.+}} [[OMP_IV]],
+// CHECK-DAG: [[OMP_UB_VAL_3:%.+]] = load {{.+}} [[OMP_UB]],
+// CHECK: [[CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_1]], [[OMP_UB_VAL_3]]
+// CHECK: br {{.+}} [[CMP_IV_UB]], label %[[DIST_OUTER_LOOP_BODY:.+]], label %[[DIST_OUTER_LOOP_END:.+]]
+
+// CHECK: [[DIST_OUTER_LOOP_BODY]]:
+// CHECK: br label %[[DIST_INNER_LOOP_HEADER:.+]]
+
+// CHECK: [[DIST_INNER_LOOP_HEADER]]:
+// CHECK-DAG: [[OMP_IV_VAL_2:%.+]] = load {{.+}} [[OMP_IV]],
+// CHECK-DAG: [[OMP_UB_VAL_4:%.+]] = load {{.+}} [[OMP_UB]],
+// CHECK: [[CMP_IV_UB_2:%.+]] = icmp sle {{.+}} [[OMP_IV_VAL_2]], [[OMP_UB_VAL_4]]
+// CHECK: br{{.+}} [[CMP_IV_UB_2]], label %[[DIST_INNER_LOOP_BODY:.+]], label %[[DIST_INNER_LOOP_END:.+]]
+
+// check that PrevLB and PrevUB are passed to the 'for'
+// CHECK: [[DIST_INNER_LOOP_BODY]]:
+// CHECK-DAG: [[OMP_PREV_LB:%.+]] = load {{.+}}, {{.+}} [[OMP_LB]],
+// CHECK-64-DAG: [[OMP_PREV_LB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_LB]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB:%.+]] = load {{.+}}, {{.+}} [[OMP_UB]],
+// CHECK-64-DAG: [[OMP_PREV_UB_EXT:%.+]] = zext {{.+}} [[OMP_PREV_UB]] to {{.+}}
+// check that distlb and distub are properly passed to fork_call
+// CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_3:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_EXT]], i{{[0-9]+}} [[OMP_PREV_UB_EXT]], {{.+}})
+// CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_3:@.+]] to {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB]], i{{[0-9]+}} [[OMP_PREV_UB]], {{.+}})
+// CHECK: br label %[[DIST_INNER_LOOP_INC:.+]]
+
+// check DistInc
+// CHECK: [[DIST_INNER_LOOP_INC]]:
+// CHECK-DAG: [[OMP_IV_VAL_3:%.+]] = load {{.+}}, {{.+}}* [[OMP_IV]],
+// CHECK-DAG: [[OMP_ST_VAL_1:%.+]] = load {{.+}}, {{.+}}* [[OMP_ST]],
+// CHECK: [[OMP_IV_INC:%.+]] = add{{.+}} [[OMP_IV_VAL_3]], [[OMP_ST_VAL_1]]
+// CHECK: store{{.+}} [[OMP_IV_INC]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[DIST_INNER_LOOP_HEADER]]
+
+// CHECK: [[DIST_INNER_LOOP_END]]:
+// CHECK: br label %[[DIST_OUTER_LOOP_INC:.+]]
+
+// CHECK: [[DIST_OUTER_LOOP_INC]]:
+// check NextLB and NextUB
+// CHECK-DAG: [[OMP_LB_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_LB]],
+// CHECK-DAG: [[OMP_ST_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_ST]],
+// CHECK-DAG: [[OMP_LB_NEXT:%.+]] = add{{.+}} [[OMP_LB_VAL_2]], [[OMP_ST_VAL_2]]
+// CHECK: store{{.+}} [[OMP_LB_NEXT]], {{.+}}* [[OMP_LB]],
+// CHECK-DAG: [[OMP_UB_VAL_5:%.+]] = load{{.+}}, {{.+}} [[OMP_UB]],
+// CHECK-DAG: [[OMP_ST_VAL_3:%.+]] = load{{.+}}, {{.+}} [[OMP_ST]],
+// CHECK-DAG: [[OMP_UB_NEXT:%.+]] = add{{.+}} [[OMP_UB_VAL_5]], [[OMP_ST_VAL_3]]
+// CHECK: store{{.+}} [[OMP_UB_NEXT]], {{.+}}* [[OMP_UB]],
+// CHECK: br label %[[DIST_OUTER_LOOP_HEADER]]
+
+// outer loop exit
+// CHECK: [[DIST_OUTER_LOOP_END]]:
+// CHECK-DAG: call void @__kmpc_for_static_fini(
+// CHECK: ret
+
+// skip implementation of 'parallel for': using default scheduling and was tested above
+
+// CHECK: define{{.+}} void [[OFFLOADING_FUN_4]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_4:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[OMP_OUTLINED_4]](
+// CHECK-DAG: [[OMP_IV:%.omp.iv]] = alloca
+// CHECK-DAG: [[OMP_LB:%.omp.comb.lb]] = alloca
+// CHECK-DAG: [[OMP_UB:%.omp.comb.ub]] = alloca
+// CHECK-DAG: [[OMP_ST:%.omp.stride]] = alloca
+
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_4:@.+]] to {{.+}},
+// skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+// CHECK: ret
+
+// 'parallel for' implementation is the same as the case without schedule clase (static no chunk is the default)
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_4]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+
+// CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+
+// initialize lb and ub to PrevLB and PrevUB
+// CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+// CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+// CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 34, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+
+// PrevEUB is only used when 'for' has a chunked schedule, otherwise EUB is used
+// In this case we use EUB
+// CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK: [[PF_NUM_IT_1:%.+]] = load{{.+}},
+// CHECK-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_NUM_IT_1]]
+// CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+// CHECK: [[PF_EUB_TRUE]]:
+// CHECK: [[PF_NUM_IT_2:%.+]] = load{{.+}},
+// CHECK: br label %[[PF_EUB_END:.+]]
+// CHECK-DAG: [[PF_EUB_FALSE]]:
+// CHECK: [[OMP_PF_UB_VAL2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK: br label %[[PF_EUB_END]]
+// CHECK-DAG: [[PF_EUB_END]]:
+// CHECK-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_NUM_IT_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL2]], %[[PF_EUB_FALSE]] ]
+// CHECK: store{{.+}} [[PF_EUB_RES]],{{.+}} [[OMP_PF_UB]],
+
+// initialize omp.iv
+// CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_JUMP_BACK:.+]]
+
+// check exit condition
+// CHECK: [[OMP_PF_JUMP_BACK]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load {{.+}} [[OMP_PF_IV]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load {{.+}} [[OMP_PF_UB]],
+// CHECK: [[PF_CMP_IV_UB:%.+]] = icmp sle {{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+// CHECK: br {{.+}} [[PF_CMP_IV_UB]], label %[[PF_BODY:.+]], label %[[PF_END:.+]]
+
+// check that PrevLB and PrevUB are passed to the 'for'
+// CHECK: [[PF_BODY]]:
+// CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label {{.+}}
+
+// check stride 1 for 'for' in 'distribute parallel for'
+// CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load {{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK: [[OMP_PF_IV_INC:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_2]], 1
+// CHECK: store{{.+}} [[OMP_PF_IV_INC]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_JUMP_BACK]]
+
+// CHECK-DAG: call void @__kmpc_for_static_fini(
+// CHECK: ret
+
+// CHECK: define{{.+}} void [[OFFLOADING_FUN_5]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_5:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[OMP_OUTLINED_5]](
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_5:@.+]] to {{.+}},
+// skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+// CHECK: ret
+
+// 'parallel for' implementation using outer and inner loops and PrevEUB
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_5]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}})
+// CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+// initialize lb and ub to PrevLB and PrevUB
+// CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+// CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+// CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, {{.+}} 33, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]],{{.+}})
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+// check PrevEUB (using PrevUB instead of NumIt as upper bound)
+// CHECK: [[OMP_PF_OUTER_LOOP_HEADER]]:
+// CHECK-DAG: [[OMP_PF_UB_VAL_1:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK-64-DAG: [[OMP_PF_UB_VAL_CONV:%.+]] = sext{{.+}} [[OMP_PF_UB_VAL_1]] to
+// CHECK: [[PF_PREV_UB_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK-64-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_CONV]], [[PF_PREV_UB_VAL_1]]
+// CHECK-32-DAG: [[PF_CMP_UB_NUM_IT:%.+]] = icmp{{.+}} [[OMP_PF_UB_VAL_1]], [[PF_PREV_UB_VAL_1]]
+// CHECK: br i1 [[PF_CMP_UB_NUM_IT]], label %[[PF_EUB_TRUE:.+]], label %[[PF_EUB_FALSE:.+]]
+// CHECK: [[PF_EUB_TRUE]]:
+// CHECK: [[PF_PREV_UB_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK: br label %[[PF_EUB_END:.+]]
+// CHECK-DAG: [[PF_EUB_FALSE]]:
+// CHECK: [[OMP_PF_UB_VAL_2:%.+]] = load{{.+}} [[OMP_PF_UB]],
+// CHECK-64: [[OMP_PF_UB_VAL_2_CONV:%.+]] = sext{{.+}} [[OMP_PF_UB_VAL_2]] to
+// CHECK: br label %[[PF_EUB_END]]
+// CHECK-DAG: [[PF_EUB_END]]:
+// CHECK-64-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_PREV_UB_VAL_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL_2_CONV]], %[[PF_EUB_FALSE]] ]
+// CHECK-32-DAG: [[PF_EUB_RES:%.+]] = phi{{.+}} [ [[PF_PREV_UB_VAL_2]], %[[PF_EUB_TRUE]] ], [ [[OMP_PF_UB_VAL_2]], %[[PF_EUB_FALSE]] ]
+// CHECK-64-DAG: [[PF_EUB_RES_CONV:%.+]] = trunc{{.+}} [[PF_EUB_RES]] to
+// CHECK-64: store{{.+}} [[PF_EUB_RES_CONV]],{{.+}} [[OMP_PF_UB]],
+// CHECK-32: store{{.+}} [[PF_EUB_RES]], {{.+}} [[OMP_PF_UB]],
+
+// initialize omp.iv (IV = LB)
+// CHECK: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+
+// outer loop: while (IV < UB) {
+// CHECK-DAG: [[OMP_PF_IV_VAL_1:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+// CHECK: [[PF_CMP_IV_UB_1:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_1]], [[OMP_PF_UB_VAL_3]]
+// CHECK: br{{.+}} [[PF_CMP_IV_UB_1]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_BODY]]:
+// CHECK: br label %[[OMP_PF_INNER_FOR_HEADER:.+]]
+
+// CHECK: [[OMP_PF_INNER_FOR_HEADER]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+// CHECK: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+// CHECK: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+// CHECK: [[OMP_PF_INNER_LOOP_BODY]]:
+// CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// skip body branch
+// CHECK: br{{.+}}
+// CHECK: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+// IV = IV + 1 and inner loop latch
+// CHECK: [[OMP_PF_INNER_LOOP_INC]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+// CHECK-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+// CHECK-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[OMP_PF_INNER_FOR_HEADER]]
+
+// check NextLB and NextUB
+// CHECK: [[OMP_PF_INNER_LOOP_END]]:
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_INC]]:
+// CHECK-DAG: [[OMP_PF_LB_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK-DAG: [[OMP_PF_ST_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_ST]],
+// CHECK-DAG: [[OMP_PF_LB_NEXT:%.+]] = add{{.+}} [[OMP_PF_LB_VAL_2]], [[OMP_PF_ST_VAL_1]]
+// CHECK: store{{.+}} [[OMP_PF_LB_NEXT]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_5:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+// CHECK-DAG: [[OMP_PF_ST_VAL_2:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_ST]],
+// CHECK-DAG: [[OMP_PF_UB_NEXT:%.+]] = add{{.+}} [[OMP_PF_UB_VAL_5]], [[OMP_PF_ST_VAL_2]]
+// CHECK: store{{.+}} [[OMP_PF_UB_NEXT]], {{.+}}* [[OMP_PF_UB]],
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_END]]:
+// CHECK-DAG: call void @__kmpc_for_static_fini(
+// CHECK: ret
+
+// CHECK: define{{.+}} void [[OFFLOADING_FUN_6]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED_6:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[OMP_OUTLINED_6]](
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_6:@.+]] to {{.+}},
+// skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+// CHECK: ret
+
+// 'parallel for' implementation using outer and inner loops and PrevEUB
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_6]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}})
+// CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+// initialize lb and ub to PrevLB and PrevUB
+// CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+// CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+// CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-DAG: [[OMP_PF_LB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK-DAG: [[OMP_PF_UB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+// CHECK: call void @__kmpc_dispatch_init_4({{.+}}, {{.+}}, {{.+}} 35, {{.+}} [[OMP_PF_LB_VAL]], {{.+}} [[OMP_PF_UB_VAL]], {{.+}}, {{.+}})
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_HEADER]]:
+// CHECK: [[IS_FIN:%.+]] = call{{.+}} @__kmpc_dispatch_next_4({{.+}}, {{.+}}, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]], {{.+}}* [[OMP_PF_ST]])
+// CHECK: [[IS_FIN_CMP:%.+]] = icmp{{.+}} [[IS_FIN]], 0
+// CHECK: br{{.+}} [[IS_FIN_CMP]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+// initialize omp.iv (IV = LB)
+// CHECK: [[OMP_PF_OUTER_LOOP_BODY]]:
+// CHECK-DAG: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK-DAG: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER:.+]]
+
+// CHECK: [[OMP_PF_INNER_LOOP_HEADER]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+// CHECK: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+// CHECK: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+// CHECK: [[OMP_PF_INNER_LOOP_BODY]]:
+// CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// skip body branch
+// CHECK: br{{.+}}
+// CHECK: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+// IV = IV + 1 and inner loop latch
+// CHECK: [[OMP_PF_INNER_LOOP_INC]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+// CHECK-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+// CHECK-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER]]
+
+// check NextLB and NextUB
+// CHECK: [[OMP_PF_INNER_LOOP_END]]:
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_INC]]:
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_END]]:
+// CHECK: ret
+
+// CHECK: define{{.+}} void [[OFFLOADING_FUN_7]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}}* [[OMP_OUTLINED_7:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[OMP_OUTLINED_7]](
+// CHECK: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92,
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_7:@.+]] to {{.+}},
+// skip rest of implementation of 'distribute' as it is tested above for default dist_schedule case
+// CHECK: ret
+
+// 'parallel for' implementation using outer and inner loops and PrevEUB
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_7]]({{.+}}, {{.+}}, i{{[0-9]+}} [[OMP_PREV_LB_IN:%.+]], i{{[0-9]+}} [[OMP_PREV_UB_IN:%.+]], {{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}})
+// CHECK-DAG: [[OMP_PF_LB:%.omp.lb]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_UB:%.omp.ub]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_IV:%.omp.iv]] = alloca{{.+}},
+// CHECK-DAG: [[OMP_PF_ST:%.omp.stride]] = alloca{{.+}},
+
+// initialize lb and ub to PrevLB and PrevUB
+// CHECK-DAG: store{{.+}} [[OMP_PREV_LB_IN]], {{.+}}* [[PREV_LB_ADDR:%.+]],
+// CHECK-DAG: store{{.+}} [[OMP_PREV_UB_IN]], {{.+}}* [[PREV_UB_ADDR:%.+]],
+// CHECK-DAG: [[OMP_PREV_LB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_LB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_LB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_LB_VAL]] to {{.+}}
+// CHECK-DAG: [[OMP_PREV_UB_VAL:%.+]] = load{{.+}}, {{.+}}* [[PREV_UB_ADDR]],
+// CHECK-64-DAG: [[OMP_PREV_UB_TRC:%.+]] = trunc{{.+}} [[OMP_PREV_UB_VAL]] to {{.+}}
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_LB_TRC]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-64-DAG: store{{.+}} [[OMP_PREV_UB_TRC]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_LB_VAL]], {{.+}}* [[OMP_PF_LB]],
+// CHECK-32-DAG: store{{.+}} [[OMP_PREV_UB_VAL]], {{.+}}* [[OMP_PF_UB]],
+// CHECK-DAG: [[OMP_PF_LB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK-DAG: [[OMP_PF_UB_VAL:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_UB]],
+// CHECK: call void @__kmpc_dispatch_init_4({{.+}}, {{.+}}, {{.+}} 35, {{.+}} [[OMP_PF_LB_VAL]], {{.+}} [[OMP_PF_UB_VAL]], {{.+}}, {{.+}})
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER:.+]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_HEADER]]:
+// CHECK: [[IS_FIN:%.+]] = call{{.+}} @__kmpc_dispatch_next_4({{.+}}, {{.+}}, {{.+}}, {{.+}}* [[OMP_PF_LB]], {{.+}}* [[OMP_PF_UB]], {{.+}}* [[OMP_PF_ST]])
+// CHECK: [[IS_FIN_CMP:%.+]] = icmp{{.+}} [[IS_FIN]], 0
+// CHECK: br{{.+}} [[IS_FIN_CMP]], label %[[OMP_PF_OUTER_LOOP_BODY:.+]], label %[[OMP_PF_OUTER_LOOP_END:.+]]
+
+// initialize omp.iv (IV = LB)
+// CHECK: [[OMP_PF_OUTER_LOOP_BODY]]:
+// CHECK-DAG: [[OMP_PF_LB_VAL_1:%.+]] = load{{.+}}, {{.+}} [[OMP_PF_LB]],
+// CHECK-DAG: store {{.+}} [[OMP_PF_LB_VAL_1]], {{.+}}* [[OMP_PF_IV]],
+// CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER:.+]]
+
+// CHECK: [[OMP_PF_INNER_LOOP_HEADER]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_2:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// CHECK-DAG: [[OMP_PF_UB_VAL_4:%.+]] = load{{.+}}, {{.+}}* [[OMP_PF_UB]],
+// CHECK: [[PF_CMP_IV_UB_2:%.+]] = icmp{{.+}} [[OMP_PF_IV_VAL_2]], [[OMP_PF_UB_VAL_4]]
+// CHECK: br{{.+}} [[PF_CMP_IV_UB_2]], label %[[OMP_PF_INNER_LOOP_BODY:.+]], label %[[OMP_PF_INNER_LOOP_END:.+]]
+
+// CHECK: [[OMP_PF_INNER_LOOP_BODY]]:
+// CHECK-DAG: {{.+}} = load{{.+}}, {{.+}}* [[OMP_PF_IV]],
+// skip body branch
+// CHECK: br{{.+}}
+// CHECK: br label %[[OMP_PF_INNER_LOOP_INC:.+]]
+
+// IV = IV + 1 and inner loop latch
+// CHECK: [[OMP_PF_INNER_LOOP_INC]]:
+// CHECK-DAG: [[OMP_PF_IV_VAL_3:%.+]] = load{{.+}}, {{.+}}* [[OMP_IV]],
+// CHECK-DAG: [[OMP_PF_NEXT_IV:%.+]] = add{{.+}} [[OMP_PF_IV_VAL_3]], 1
+// CHECK-DAG: store{{.+}} [[OMP_PF_NEXT_IV]], {{.+}}* [[OMP_IV]],
+// CHECK: br label %[[OMP_PF_INNER_LOOP_HEADER]]
+
+// check NextLB and NextUB
+// CHECK: [[OMP_PF_INNER_LOOP_END]]:
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_INC:.+]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_INC]]:
+// CHECK: br label %[[OMP_PF_OUTER_LOOP_HEADER]]
+
+// CHECK: [[OMP_PF_OUTER_LOOP_END]]:
+// CHECK: ret
+#endif
diff --git a/test/OpenMP/distribute_parallel_for_firstprivate_codegen.cpp b/test/OpenMP/distribute_parallel_for_firstprivate_codegen.cpp
new file mode 100644
index 0000000000..d12c0aa11c
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_firstprivate_codegen.cpp
@@ -0,0 +1,619 @@
+// RxUN: %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 parallel for 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({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED:@.+]] to {{.+}})
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for 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:%.+]])
+
+ // addr alloca's
+ // 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*,
+
+ // private alloca's
+ // LAMBDA: [[G_PRIV:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIV:%.+]] = alloca double,
+ // LAMBDA: [[TMP_PRIV:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_PRIV:%.+]] = alloca float,
+
+ // transfer input parameters into addr alloca's
+ // LAMBDA-DAG: store {{.+}} [[G_IN]], {{.+}} [[G_ADDR]],
+ // LAMBDA-DAG: store {{.+}} [[G1_IN]], {{.+}} [[G1_ADDR]],
+ // LAMBDA-DAG: store {{.+}} [[SVAR_IN]], {{.+}} [[SVAR_ADDR]],
+ // LAMBDA-DAG: store {{.+}} [[SFVAR_IN]], {{.+}} [[SFVAR_ADDR]],
+
+ // init private alloca's with addr alloca's
+ // g
+ // LAMBDA-64-DAG: [[G_CONV:%.+]] = bitcast {{.+}}* [[G_ADDR]] to
+ // LAMBDA-32-DAG: [[G_CONV:%.+]] = load {{.+}}*, {{.+}}** [[G_ADDR]]
+ // LAMBDA-DAG: [[G_ADDR_VAL:%.+]] = load {{.+}}, {{.+}}* [[G_CONV]],
+ // LAMBDA-DAG: store {{.+}} [[G_ADDR_VAL]], {{.+}}* [[G_PRIV]],
+
+ // g1
+ // LAMBDA-DAG: [[G1_CONV:%.+]] = bitcast {{.+}}* [[G1_ADDR]] to
+ // LAMBDA-DAG: store {{.+}}* [[G1_CONV]], {{.+}}** [[G1_REF]],
+ // LAMBDA-DAG: [[G1_REF_VAL:%.+]] = load {{.+}}*, {{.+}}** [[G1_REF]],
+ // LAMBDA-DAG: store {{.+}}* [[G1_REF_VAL]], {{.+}}** [[TMP]],
+ // LAMBDA-DAG: [[TMP_REF:%.+]] = load {{.+}}*, {{.+}}** [[TMP]],
+ // LAMBDA-DAG: [[TMP_VAL:%.+]] = load {{.+}}, {{.+}}* [[TMP_REF]],
+ // LAMBDA-DAG: store {{.+}} [[TMP_VAL]], {{.+}}* [[G1_PRIV]]
+ // LAMBDA-DAG: store {{.+}}* [[G1_PRIV]], {{.+}}** [[TMP_PRIV]],
+
+ // svar
+ // LAMBDA-64-DAG: [[SVAR_CONV:%.+]] = bitcast {{.+}}* [[SVAR_ADDR]] to
+ // LAMBDA-64-DAG: [[SVAR_VAL:%.+]] = load {{.+}}, {{.+}}* [[SVAR_CONV]],
+ // LAMBDA-32-DAG: [[SVAR_VAL:%.+]] = load {{.+}}, {{.+}}* [[SVAR_ADDR]],
+ // LAMBDA-DAG: store {{.+}} [[SVAR_VAL]], {{.+}}* [[SVAR_PRIV]],
+
+ // sfvar
+ // LAMBDA-DAG: [[SFVAR_CONV:%.+]] = bitcast {{.+}}* [[SFVAR_ADDR]] to
+ // LAMBDA-DAG: [[SFVAR_VAL:%.+]] = load {{.+}}, {{.+}}* [[SFVAR_CONV]],
+ // LAMBDA-DAG: store {{.+}} [[SFVAR_VAL]], {{.+}}* [[SFVAR_PRIV]],
+
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
+ // pass firstprivate parameters to parallel outlined function
+ // g
+ // LAMBDA-64-DAG: [[G_PRIV_VAL:%.+]] = load {{.+}}, {{.+}}* [[G_PRIV]],
+ // LAMBDA-64: [[G_CAST_CONV:%.+]] = bitcast {{.+}}* [[G_CAST:%.+]] to
+ // LAMBDA-64-DAG: store {{.+}} [[G_PRIV_VAL]], {{.+}}* [[G_CAST_CONV]],
+ // LAMBDA-64-DAG: [[G_PAR:%.+]] = load {{.+}}, {{.+}}* [[G_CAST]],
+
+ // g1
+ // LAMBDA-DAG: [[TMP_PRIV_VAL:%.+]] = load {{.+}}, {{.+}}* [[TMP_PRIV]],
+ // LAMBDA-DAG: [[G1_PRIV_VAL:%.+]] = load {{.+}}, {{.+}}* [[TMP_PRIV_VAL]],
+ // LAMBDA: [[G1_CAST_CONV:%.+]] = bitcast {{.+}}* [[G1_CAST:%.+]] to
+ // LAMBDA-DAG: store {{.+}} [[G1_PRIV_VAL]], {{.+}}* [[G1_CAST_CONV]],
+ // LAMBDA-DAG: [[G1_PAR:%.+]] = load {{.+}}, {{.+}}* [[G1_CAST]],
+
+ // svar
+ // LAMBDA: [[SVAR_VAL:%.+]] = load {{.+}}, {{.+}}* [[SVAR_PRIV]],
+ // LAMBDA-64-DAG: [[SVAR_CAST_CONV:%.+]] = bitcast {{.+}}* [[SVAR_CAST:%.+]] to
+ // LAMBDA-64-DAG: store {{.+}} [[SVAR_VAL]], {{.+}}* [[SVAR_CAST_CONV]],
+ // LAMBDA-32-DAG: store {{.+}} [[SVAR_VAL]], {{.+}}* [[SVAR_CAST:%.+]],
+ // LAMBDA-DAG: [[SVAR_PAR:%.+]] = load {{.+}}, {{.+}}* [[SVAR_CAST]],
+
+ // sfvar
+ // LAMBDA: [[SFVAR_VAL:%.+]] = load {{.+}}, {{.+}}* [[SFVAR_PRIV]],
+ // LAMBDA-DAG: [[SFVAR_CAST_CONV:%.+]] = bitcast {{.+}}* [[SFVAR_CAST:%.+]] to
+ // LAMBDA-DAG: store {{.+}} [[SFVAR_VAL]], {{.+}}* [[SFVAR_CAST_CONV]],
+ // LAMBDA-DAG: [[SFVAR_PAR:%.+]] = load {{.+}}, {{.+}}* [[SFVAR_CAST]],
+
+ // LAMBDA-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[G_PAR]], {{.+}} [[G1_PAR]], {{.+}} [[SVAR_PAR]], {{.+}} [[SFVAR_PAR]])
+ // LAMBDA-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[G_PRIV]], {{.+}} [[G1_PAR]], {{.+}} [[SVAR_PAR]], {{.+}} [[SFVAR_PAR]])
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+ // LAMBDA: ret void
+
+
+ // LAMBDA-64: define{{.+}} void [[OMP_PARFOR_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{{.+}} void [[OMP_PARFOR_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, {{.+}}, {{.+}}, double* {{.+}} [[G_IN:%.+]], i{{[0-9]+}} [[G1_IN:%.+]], i{{[0-9]+}} [[SVAR_IN:%.+]], i{{[0-9]+}} [[SFVAR_IN:%.+]])
+ // skip initial params
+ // LAMBDA: {{.+}} = alloca{{.+}},
+ // LAMBDA: {{.+}} = alloca{{.+}},
+ // LAMBDA: {{.+}} = alloca{{.+}},
+ // LAMBDA: {{.+}} = alloca{{.+}},
+
+ // addr alloca's
+ // 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*,
+
+ // private alloca's (only for 32-bit)
+ // LAMBDA-32: [[G_PRIV:%.+]] = alloca double,
+
+ // transfer input parameters into addr alloca's
+ // LAMBDA-DAG: store {{.+}} [[G_IN]], {{.+}} [[G_ADDR]],
+ // LAMBDA-DAG: store {{.+}} [[G1_IN]], {{.+}} [[G1_ADDR]],
+ // LAMBDA-DAG: store {{.+}} [[SVAR_IN]], {{.+}} [[SVAR_ADDR]],
+ // LAMBDA-DAG: store {{.+}} [[SFVAR_IN]], {{.+}} [[SFVAR_ADDR]],
+
+ // prepare parameters for lambda
+ // g
+ // LAMBDA-64-DAG: [[G_CONV:%.+]] = bitcast {{.+}}* [[G_ADDR]] to
+ // LAMBDA-32-DAG: [[G_ADDR_REF:%.+]] = load {{.+}}*, {{.+}}** [[G_ADDR]]
+ // LAMBDA-32-DAG: [[G_ADDR_VAL:%.+]] = load {{.+}}, {{.+}}* [[G_ADDR_REF]],
+ // LAMBDA-32-DAG: store {{.+}} [[G_ADDR_VAL]], {{.+}}* [[G_PRIV]],
+
+ // g1
+ // LAMBDA-DAG: [[G1_CONV:%.+]] = bitcast {{.+}}* [[G1_ADDR]] to
+ // LAMBDA-DAG: store {{.+}}* [[G1_CONV]], {{.+}}* [[G1_REF]],
+
+ // svar
+ // LAMBDA-64-DAG: [[SVAR_CONV:%.+]] = bitcast {{.+}}* [[SVAR_ADDR]] to
+
+ // sfvar
+ // LAMBDA-DAG: [[SFVAR_CONV:%.+]] = bitcast {{.+}}* [[SFVAR_ADDR]] to
+
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
+ g = 1;
+ g1 = 1;
+ svar = 3;
+ sfvar = 4.0;
+ // LAMBDA-64: store double 1.0{{.+}}, double* [[G_CONV]],
+ // LAMBDA-32: store double 1.0{{.+}}, double* [[G_PRIV]],
+ // LAMBDA: [[G1_REF_REF:%.+]] = load {{.+}}*, {{.+}}** [[G1_REF]],
+ // LAMBDA: store {{.+}} 1.0{{.+}}, {{.+}}* [[G1_REF_REF]],
+ // LAMBDA-64: store {{.+}} 3, {{.+}}* [[SVAR_CONV]],
+ // LAMBDA-32: store {{.+}} 3, {{.+}}* [[SVAR_ADDR]],
+ // LAMBDA: store {{.+}} 4.0{{.+}}, {{.+}}* [[SFVAR_CONV]],
+
+ // pass params to inner lambda
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA-64: store double* [[G_CONV]], double** [[G_PRIVATE_ADDR_REF]],
+ // LAMBDA-32: store double* [[G_PRIV]], double** [[G_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[G1_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF_REF:%.+]] = load double*, double** [[G1_REF]],
+ // LAMBDA: store double* [[G1_REF_REF]], double** [[G1_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[SVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA-64: store i{{[0-9]+}}* [[SVAR_CONV]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA-32: store i{{[0-9]+}}* [[SVAR_ADDR]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: store float* [[SFVAR_CONV]], float** [[SFVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+ // LAMBDA: ret void
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ g1 = 2;
+ svar = 4;
+ sfvar = 8.0;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]]
+
+ // LAMBDA: [[TMP_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load double*, double** [[TMP_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G1_REF]],
+ // LAMBDA: [[SVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SVAR_REF]]
+ // LAMBDA: [[SFVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: [[SFVAR_REF:%.+]] = load float*, float** [[SFVAR_PTR_REF]]
+ // LAMBDA: store float 8.0{{.+}}, 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 parallel for 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-LABEL: 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_0:@.+]](
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_DESTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+
+// CHECK: define{{.+}} [[OFFLOAD_FUN_0]](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: 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_0:@.+]] to void
+// CHECK: ret
+
+// CHECK: define internal void [[OMP_OUTLINED_0]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, 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:%.+]])
+
+// addr alloca's
+// 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]]*,
+
+// skip loop alloca's
+// CHECK: [[OMP_IV:.omp.iv+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_LB:.omp.comb.lb+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_UB:.omp.comb.ub+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_ST:.omp.stride+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:.omp.is_last+]] = alloca i{{[0-9]+}},
+
+// private alloca's
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[SVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+
+// init addr alloca's with input values
+// CHECK-DAG: store {{.+}} [[T_VAR_IN]], {{.+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[VEC_IN]], {{.+}} [[VEC_ADDR]],
+// CHECK-DAG: store {{.+}} [[S_ARR_IN]], {{.+}} [[S_ARR_ADDR]],
+// CHECK-DAG: store {{.+}} [[VAR_IN]], {{.+}} [[VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[SVAR_IN]], {{.+}} [[SVAR_ADDR]],
+
+// init private alloca's with addr alloca's
+// t-var
+// CHECK-64-DAG: [[T_VAR_CONV:%.+]] = bitcast {{.+}} [[T_VAR_ADDR]] to
+// CHECK-64-DAG: [[T_VAR_ADDR_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_CONV]],
+// CHECK-32-DAG: [[T_VAR_ADDR_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[T_VAR_ADDR_VAL]], {{.+}} [[T_VAR_PRIV]],
+
+// vec
+// CHECK-DAG: [[VEC_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[VEC_ADDR]],
+// CHECK-DAG: [[VEC_PRIV_BCAST:%.+]] = bitcast {{.+}} [[VEC_PRIV]] to
+// CHECK-DAG: [[VEC_ADDR_BCAST:%.+]] = bitcast {{.+}} [[VEC_ADDR_VAL]] to
+// CHECK-DAG: call void @llvm.memcpy{{.+}}({{.+}}* [[VEC_PRIV_BCAST]], {{.+}}* [[VEC_ADDR_BCAST]],
+
+// s_arr
+// CHECK-DAG: [[S_ARR_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[S_ARR_ADDR]],
+// CHECK-DAG: [[S_ARR_BGN:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_ADDR_BCAST:%.+]] = bitcast {{.+}}* [[S_ARR_ADDR_VAL]] to
+// CHECK-DAG: [[S_ARR_BGN_GEP:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_BGN]],
+// CHECK-DAG: [[S_ARR_EMPTY:%.+]] = icmp {{.+}} [[S_ARR_BGN]], [[S_ARR_BGN_GEP]]
+// CHECK-DAG: br {{.+}} [[S_ARR_EMPTY]], label %[[CPY_DONE:.+]], label %[[CPY_BODY:.+]]
+// CHECK-DAG: [[CPY_BODY]]:
+// CHECK-DAG: call void @llvm.memcpy{{.+}}(
+// CHECK-DAG: [[CPY_DONE]]:
+
+// var
+// CHECK-DAG: [[TMP_REF:%.+]] = load {{.+}}*, {{.+}}* [[TMP]],
+// CHECK-DAG: [[VAR_PRIV_BCAST:%.+]] = bitcast {{.+}}* [[VAR_PRIV]] to
+// CHECK-DAG: [[TMP_REF_BCAST:%.+]] = bitcast {{.+}}* [[TMP_REF]] to
+// CHECK-DAG: call void @llvm.memcpy.{{.+}}({{.+}}* [[VAR_PRIV_BCAST]], {{.+}}* [[TMP_REF_BCAST]],
+// CHECK-DAG: store {{.+}}* [[VAR_PRIV]], {{.+}}** [[TMP_PRIV]],
+
+// svar
+// CHECK-64-DAG: [[SVAR_CONV:%.+]] = bitcast {{.+}}* [[SVAR_ADDR]] to
+// CHECK-64-DAG: [[SVAR_CONV_VAL:%.+]] = load {{.+}}, {{.+}}* [[SVAR_CONV]],
+// CHECK-32-DAG: [[SVAR_CONV_VAL:%.+]] = load {{.+}}, {{.+}}* [[SVAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[SVAR_CONV_VAL]], {{.+}}* [[SVAR_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// pass private alloca's to fork
+// CHECK-DAG: [[T_VAR_PRIV_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_PRIV]],
+// not dag to distinguish with S_VAR_CAST
+// CHECK-64: [[T_VAR_CAST_CONV:%.+]] = bitcast {{.+}}* [[T_VAR_CAST:%.+]] to
+// CHECK-64-DAG: store {{.+}} [[T_VAR_PRIV_VAL]], {{.+}} [[T_VAR_CAST_CONV]],
+// CHECK-32: store {{.+}} [[T_VAR_PRIV_VAL]], {{.+}} [[T_VAR_CAST:%.+]],
+// CHECK-DAG: [[T_VAR_CAST_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_CAST]],
+// CHECK-DAG: [[TMP_PRIV_VAL:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP_PRIV]],
+// CHECK-DAG: [[SVAR_PRIV_VAL:%.+]] = load {{.+}}, {{.+}}* [[SVAR_PRIV]],
+// CHECK-64-DAG: [[SVAR_CAST_CONV:%.+]] = bitcast {{.+}}* [[SVAR_CAST:%.+]] to
+// CHECK-64-DAG: store {{.+}} [[SVAR_PRIV_VAL]], {{.+}}* [[SVAR_CAST_CONV]],
+// CHECK-32-DAG: store {{.+}} [[SVAR_PRIV_VAL]], {{.+}}* [[SVAR_CAST:%.+]],
+// CHECK-DAG: [[SVAR_CAST_VAL:%.+]] = load {{.+}}, {{.+}}* [[SVAR_CAST]],
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_0:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, [2 x i{{[0-9]+}}]* [[VEC_PRIV]], i{{[0-9]+}} [[T_VAR_CAST_VAL]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]], [[S_FLOAT_TY]]* [[TMP_PRIV_VAL]], i{{[0-9]+}} [[SVAR_CAST_VAL]])
+// CHECK: call void @__kmpc_for_static_fini(
+
+// call destructors: var..
+// CHECK-DAG: call {{.+}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+
+// ..and s_arr
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_EL_PAST:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = getelementptr {{.+}}, {{.+}} [[S_ARR_EL_PAST]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+
+// CHECK: ret void
+
+// By OpenMP specifications, 'firstprivate' applies to both distribute and parallel for.
+// However, the support for 'firstprivate' of 'parallel' is only used when 'parallel'
+// is found alone. Therefore we only have one 'firstprivate' support for 'parallel for'
+// in combination
+// CHECK: define internal void [[OMP_PARFOR_OUTLINED_0]]({{.+}}, {{.+}}, {{.+}}, {{.+}}, [2 x i{{[0-9]+}}]* {{.+}} [[VEC_IN:%.+]], i{{[0-9]+}} [[T_VAR_IN:%.+]], [2 x [[S_FLOAT_TY]]]* {{.+}} [[S_ARR_IN:%.+]], [[S_FLOAT_TY]]* {{.+}} [[VAR_IN:%.+]], i{{[0-9]+}} [[SVAR_IN:%.+]])
+
+// addr alloca's
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca 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]+}},
+
+// skip loop alloca's
+// CHECK: [[OMP_IV:.omp.iv+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_LB:.omp.lb+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_UB:.omp.ub+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_ST:.omp.stride+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:.omp.is_last+]] = alloca i{{[0-9]+}},
+
+// private alloca's
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_FLOAT_TY]]*,
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+
+// init addr alloca's with input values
+// CHECK-DAG: store {{.+}} [[VEC_IN]], {{.+}} [[VEC_ADDR]],
+// CHECK-DAG: store {{.+}} [[T_VAR_IN]], {{.+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[S_ARR_IN]], {{.+}} [[S_ARR_ADDR]],
+// CHECK-DAG: store {{.+}} [[VAR_IN]], {{.+}} [[VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[SVAR_IN]], {{.+}} [[SVAR_ADDR]],
+
+// init private alloca's with addr alloca's
+// vec
+// CHECK-DAG: [[VEC_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[VEC_ADDR]],
+// CHECK-DAG: [[VEC_PRIV_BCAST:%.+]] = bitcast {{.+}} [[VEC_PRIV]] to
+// CHECK-DAG: [[VEC_ADDR_BCAST:%.+]] = bitcast {{.+}} [[VEC_ADDR_VAL]] to
+// CHECK-DAG: call void @llvm.memcpy{{.+}}({{.+}}* [[VEC_PRIV_BCAST]], {{.+}}* [[VEC_ADDR_BCAST]],
+
+// s_arr
+// CHECK-DAG: [[S_ARR_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[S_ARR_ADDR]],
+// CHECK-DAG: [[S_ARR_BGN:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_ADDR_BCAST:%.+]] = bitcast {{.+}}* [[S_ARR_ADDR_VAL]] to
+// CHECK-DAG: [[S_ARR_BGN_GEP:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_BGN]],
+// CHECK-DAG: [[S_ARR_EMPTY:%.+]] = icmp {{.+}} [[S_ARR_BGN]], [[S_ARR_BGN_GEP]]
+// CHECK-DAG: br {{.+}} [[S_ARR_EMPTY]], label %[[CPY_DONE:.+]], label %[[CPY_BODY:.+]]
+// CHECK-DAG: [[CPY_BODY]]:
+// CHECK-DAG: call void @llvm.memcpy{{.+}}(
+// CHECK-DAG: [[CPY_DONE]]:
+
+// var
+// CHECK-DAG: [[VAR_ADDR_REF:%.+]] = load {{.+}}*, {{.+}}* [[VAR_ADDR]],
+// CHECK-DAG: [[VAR_PRIV_BCAST:%.+]] = bitcast {{.+}}* [[VAR_PRIV]] to
+// CHECK-DAG: [[VAR_ADDR_BCAST:%.+]] = bitcast {{.+}}* [[VAR_ADDR_REF]] to
+// CHECK-DAG: call void @llvm.memcpy.{{.+}}({{.+}}* [[VAR_PRIV_BCAST]], {{.+}}* [[VAR_ADDR_BCAST]],
+// CHECK-DAG: store {{.+}}* [[VAR_PRIV]], {{.+}}** [[TMP_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+
+// call destructors: var..
+// CHECK-DAG: call {{.+}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+
+// ..and s_arr
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_EL_PAST:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = getelementptr {{.+}}, {{.+}} [[S_ARR_EL_PAST]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+
+// CHECK: ret void
+
+// template tmain with S_INT_TY
+// CHECK-LABEL: define{{.*}} i{{[0-9]+}} @{{.+}}tmain{{.+}}()
+// 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_0:@.+]](
+// CHECK: call {{.*}} [[S_INT_TY_DEF_DESTR:@.+]]([[S_INT_TY]]* [[TEST]])
+
+// CHECK: define{{.+}} [[OFFLOAD_FUN_0]](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: 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_0:@.+]] to void
+// CHECK: ret
+
+// CHECK: define internal void [[OMP_OUTLINED_0]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, 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:%.+]])
+
+// addr alloca's
+// 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]]*,
+
+// skip loop alloca's
+// CHECK: [[OMP_IV:.omp.iv+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_LB:.omp.comb.lb+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_UB:.omp.comb.ub+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_ST:.omp.stride+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:.omp.is_last+]] = alloca i{{[0-9]+}},
+
+// private alloca's
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_INT_TY]]*,
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+
+// init addr alloca's with input values
+// CHECK-DAG: store {{.+}} [[T_VAR_IN]], {{.+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[VEC_IN]], {{.+}} [[VEC_ADDR]],
+// CHECK-DAG: store {{.+}} [[S_ARR_IN]], {{.+}} [[S_ARR_ADDR]],
+// CHECK-DAG: store {{.+}} [[VAR_IN]], {{.+}} [[VAR_ADDR]],
+
+// init private alloca's with addr alloca's
+// t-var
+// CHECK-64-DAG: [[T_VAR_CONV:%.+]] = bitcast {{.+}} [[T_VAR_ADDR]] to
+// CHECK-64-DAG: [[T_VAR_ADDR_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_CONV]],
+// CHECK-32-DAG: [[T_VAR_ADDR_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[T_VAR_ADDR_VAL]], {{.+}} [[T_VAR_PRIV]],
+
+// vec
+// CHECK-DAG: [[VEC_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[VEC_ADDR]],
+// CHECK-DAG: [[VEC_PRIV_BCAST:%.+]] = bitcast {{.+}} [[VEC_PRIV]] to
+// CHECK-DAG: [[VEC_ADDR_BCAST:%.+]] = bitcast {{.+}} [[VEC_ADDR_VAL]] to
+// CHECK-DAG: call void @llvm.memcpy{{.+}}({{.+}}* [[VEC_PRIV_BCAST]], {{.+}}* [[VEC_ADDR_BCAST]],
+
+// s_arr
+// CHECK-DAG: [[S_ARR_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[S_ARR_ADDR]],
+// CHECK-DAG: [[S_ARR_BGN:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_ADDR_BCAST:%.+]] = bitcast {{.+}}* [[S_ARR_ADDR_VAL]] to
+// CHECK-DAG: [[S_ARR_BGN_GEP:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_BGN]],
+// CHECK-DAG: [[S_ARR_EMPTY:%.+]] = icmp {{.+}} [[S_ARR_BGN]], [[S_ARR_BGN_GEP]]
+// CHECK-DAG: br {{.+}} [[S_ARR_EMPTY]], label %[[CPY_DONE:.+]], label %[[CPY_BODY:.+]]
+// CHECK-DAG: [[CPY_BODY]]:
+// CHECK-DAG: call void @llvm.memcpy{{.+}}(
+// CHECK-DAG: [[CPY_DONE]]:
+
+// var
+// CHECK-DAG: [[TMP_REF:%.+]] = load {{.+}}*, {{.+}}* [[TMP]],
+// CHECK-DAG: [[VAR_PRIV_BCAST:%.+]] = bitcast {{.+}}* [[VAR_PRIV]] to
+// CHECK-DAG: [[TMP_REF_BCAST:%.+]] = bitcast {{.+}}* [[TMP_REF]] to
+// CHECK-DAG: call void @llvm.memcpy.{{.+}}({{.+}}* [[VAR_PRIV_BCAST]], {{.+}}* [[TMP_REF_BCAST]],
+// CHECK-DAG: store {{.+}}* [[VAR_PRIV]], {{.+}}** [[TMP_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// pass private alloca's to fork
+// CHECK-DAG: [[T_VAR_PRIV_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_PRIV]],
+// not dag to distinguish with S_VAR_CAST
+// CHECK-64: [[T_VAR_CAST_CONV:%.+]] = bitcast {{.+}}* [[T_VAR_CAST:%.+]] to
+// CHECK-64-DAG: store {{.+}} [[T_VAR_PRIV_VAL]], {{.+}} [[T_VAR_CAST_CONV]],
+// CHECK-32: store {{.+}} [[T_VAR_PRIV_VAL]], {{.+}} [[T_VAR_CAST:%.+]],
+// CHECK-DAG: [[T_VAR_CAST_VAL:%.+]] = load {{.+}}, {{.+}}* [[T_VAR_CAST]],
+// CHECK-DAG: [[TMP_PRIV_VAL:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP_PRIV]],
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_0:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, [2 x i{{[0-9]+}}]* [[VEC_PRIV]], i{{[0-9]+}} [[T_VAR_CAST_VAL]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]], [[S_INT_TY]]* [[TMP_PRIV_VAL]])
+// CHECK: call void @__kmpc_for_static_fini(
+
+// call destructors: var..
+// CHECK-DAG: call {{.+}} [[S_INT_TY_DEF_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+
+// ..and s_arr
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_EL_PAST:%.+]] = phi [[S_INT_TY]]*
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = getelementptr {{.+}}, {{.+}} [[S_ARR_EL_PAST]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_DESTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+
+// CHECK: ret void
+
+// By OpenMP specifications, 'firstprivate' applies to both distribute and parallel for.
+// However, the support for 'firstprivate' of 'parallel' is only used when 'parallel'
+// is found alone. Therefore we only have one 'firstprivate' support for 'parallel for'
+// in combination
+// CHECK: define internal void [[OMP_PARFOR_OUTLINED_0]]({{.+}}, {{.+}}, {{.+}}, {{.+}}, [2 x i{{[0-9]+}}]* {{.+}} [[VEC_IN:%.+]], i{{[0-9]+}} [[T_VAR_IN:%.+]], [2 x [[S_INT_TY]]]* {{.+}} [[S_ARR_IN:%.+]], [[S_INT_TY]]* {{.+}} [[VAR_IN:%.+]])
+
+// addr alloca's
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[S_ARR_ADDR:%.+]] = alloca [2 x [[S_INT_TY]]]*,
+// CHECK: [[VAR_ADDR:%.+]] = alloca [[S_INT_TY]]*,
+
+// skip loop alloca's
+// CHECK: [[OMP_IV:.omp.iv+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_LB:.omp.lb+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_UB:.omp.ub+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_ST:.omp.stride+]] = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:.omp.is_last+]] = alloca i{{[0-9]+}},
+
+// private alloca's
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_INT_TY]]*,
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+
+// init addr alloca's with input values
+// CHECK-DAG: store {{.+}} [[VEC_IN]], {{.+}} [[VEC_ADDR]],
+// CHECK-DAG: store {{.+}} [[T_VAR_IN]], {{.+}}* [[T_VAR_ADDR]],
+// CHECK-DAG: store {{.+}} [[S_ARR_IN]], {{.+}} [[S_ARR_ADDR]],
+// CHECK-DAG: store {{.+}} [[VAR_IN]], {{.+}} [[VAR_ADDR]],
+
+// init private alloca's with addr alloca's
+// vec
+// CHECK-DAG: [[VEC_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[VEC_ADDR]],
+// CHECK-DAG: [[VEC_PRIV_BCAST:%.+]] = bitcast {{.+}} [[VEC_PRIV]] to
+// CHECK-DAG: [[VEC_ADDR_BCAST:%.+]] = bitcast {{.+}} [[VEC_ADDR_VAL]] to
+// CHECK-DAG: call void @llvm.memcpy{{.+}}({{.+}}* [[VEC_PRIV_BCAST]], {{.+}}* [[VEC_ADDR_BCAST]],
+
+// s_arr
+// CHECK-DAG: [[S_ARR_ADDR_VAL:%.+]] = load {{.+}}*, {{.+}}** [[S_ARR_ADDR]],
+// CHECK-DAG: [[S_ARR_BGN:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_ADDR_BCAST:%.+]] = bitcast {{.+}}* [[S_ARR_ADDR_VAL]] to
+// CHECK-DAG: [[S_ARR_BGN_GEP:%.+]] = getelementptr {{.+}}, {{.+}}* [[S_ARR_BGN]],
+// CHECK-DAG: [[S_ARR_EMPTY:%.+]] = icmp {{.+}} [[S_ARR_BGN]], [[S_ARR_BGN_GEP]]
+// CHECK-DAG: br {{.+}} [[S_ARR_EMPTY]], label %[[CPY_DONE:.+]], label %[[CPY_BODY:.+]]
+// CHECK-DAG: [[CPY_BODY]]:
+// CHECK-DAG: call void @llvm.memcpy{{.+}}(
+// CHECK-DAG: [[CPY_DONE]]:
+
+// var
+// CHECK-DAG: [[VAR_ADDR_REF:%.+]] = load {{.+}}*, {{.+}}* [[VAR_ADDR]],
+// CHECK-DAG: [[VAR_PRIV_BCAST:%.+]] = bitcast {{.+}}* [[VAR_PRIV]] to
+// CHECK-DAG: [[VAR_ADDR_BCAST:%.+]] = bitcast {{.+}}* [[VAR_ADDR_REF]] to
+// CHECK-DAG: call void @llvm.memcpy.{{.+}}({{.+}}* [[VAR_PRIV_BCAST]], {{.+}}* [[VAR_ADDR_BCAST]],
+// CHECK-DAG: store {{.+}}* [[VAR_PRIV]], {{.+}}** [[TMP_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+
+// call destructors: var..
+// CHECK-DAG: call {{.+}} [[S_INT_TY_DEF_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+
+// ..and s_arr
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_EL_PAST:%.+]] = phi [[S_INT_TY]]*
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = getelementptr {{.+}}, {{.+}} [[S_ARR_EL_PAST]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_DESTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+
+// CHECK: ret void
+
+#endif
diff --git a/test/OpenMP/distribute_parallel_for_if_codegen.cpp b/test/OpenMP/distribute_parallel_for_if_codegen.cpp
new file mode 100644
index 0000000000..9ee909e013
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_if_codegen.cpp
@@ -0,0 +1,192 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+void fn1();
+void fn2();
+void fn3();
+void fn4();
+void fn5();
+void fn6();
+
+int Arg;
+
+// CHECK-LABEL: define {{.*}}void @{{.+}}gtid_test
+void gtid_test() {
+#pragma omp target
+#pragma omp teams
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_0:@.+]](
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_1:@.+]](
+#pragma omp distribute parallel for
+ for(int i = 0 ; i < 100; i++) {}
+ // CHECK: define internal void [[OFFLOADING_FUN_0]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[OMP_TEAMS_OUTLINED_0:@.+]] to {{.+}})
+ // CHECK: define{{.+}} void [[OMP_TEAMS_OUTLINED_0]](
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 2, {{.+}}* [[OMP_OUTLINED_0:@.+]] to void
+ // CHECK: call void @__kmpc_for_static_fini(
+
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_0]](
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for if (parallel: false)
+ for(int i = 0 ; i < 100; i++) {
+ // CHECK: define internal void [[OFFLOADING_FUN_1]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[OMP_TEAMS_OUTLINED_1:@.+]] to {{.+}})
+ // CHECK: define{{.+}} void [[OMP_TEAMS_OUTLINED_1]](
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call void @__kmpc_serialized_parallel(
+ // CHECK: call void [[OMP_OUTLINED_1:@.+]](
+ // CHECK: call void @__kmpc_end_serialized_parallel(
+ // CHECK: call void @__kmpc_for_static_fini(
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_1]](
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call void @{{.+}}gtid_test
+ // CHECK: call void @__kmpc_for_static_fini(
+ // CHECK: ret
+ gtid_test();
+ }
+}
+
+
+template <typename T>
+int tmain(T Arg) {
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for if (true)
+ for(int i = 0 ; i < 100; i++) {
+ fn1();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for if (false)
+ for(int i = 0 ; i < 100; i++) {
+ fn2();
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for if (parallel: Arg)
+ for(int i = 0 ; i < 100; i++) {
+ fn3();
+ }
+ return 0;
+}
+
+// CHECK-LABEL: define {{.*}}i{{[0-9]+}} @main()
+int main() {
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_0:@.+]](
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_1:@.+]](
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_2:@.+]](
+// CHECK: = call {{.*}}i{{.+}} @{{.+}}tmain
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for if (true)
+ for(int i = 0 ; i < 100; i++) {
+ // CHECK: define internal void [[OFFLOADING_FUN_0]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[OMP_TEAMS_OUTLINED_0:@.+]] to {{.+}})
+ // CHECK: define{{.+}} void [[OMP_TEAMS_OUTLINED_0]](
+
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 2, {{.+}}* [[OMP_OUTLINED_2:@.+]] to void
+ // CHECK: call void @__kmpc_for_static_fini(
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_2]](
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call {{.*}}void @{{.+}}fn4
+ // CHECK: call void @__kmpc_for_static_fini(
+
+ fn4();
+ }
+
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for if (false)
+ for(int i = 0 ; i < 100; i++) {
+ // CHECK: define internal void [[OFFLOADING_FUN_1]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[OMP_TEAMS_OUTLINED_1:@.+]] to {{.+}})
+ // CHECK: define{{.+}} void [[OMP_TEAMS_OUTLINED_1]](
+
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call void @__kmpc_serialized_parallel(
+ // CHECK: call void [[OMP_OUTLINED_3:@.+]](
+ // CHECK: call void @__kmpc_end_serialized_parallel(
+ // CHECK: call void @__kmpc_for_static_fini(
+
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_3]](
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call {{.*}}void @{{.+}}fn5
+ // CHECK: call void @__kmpc_for_static_fini(
+ fn5();
+ }
+
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for if (Arg)
+ for(int i = 0 ; i < 100; i++) {
+ // CHECK: define internal void [[OFFLOADING_FUN_2]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}}* [[OMP_TEAMS_OUTLINED_2:@.+]] to {{.+}})
+ // CHECK: define{{.+}} void [[OMP_TEAMS_OUTLINED_2]](
+
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 2, {{.+}}* [[OMP_OUTLINED_4:@.+]] to void
+ // CHECK: call void @__kmpc_serialized_parallel(
+ // CHECK: call void [[OMP_OUTLINED_4:@.+]](
+ // CHECK: call void @__kmpc_end_serialized_parallel(
+ // CHECK: call void @__kmpc_for_static_fini(
+
+ // CHECK: define{{.+}} void [[OMP_OUTLINED_4]](
+ // CHECK: call void @__kmpc_for_static_init_4(
+ // CHECK: call {{.*}}void @{{.+}}fn6
+ // CHECK: call void @__kmpc_for_static_fini(
+ fn6();
+ }
+
+ return tmain(Arg);
+}
+
+// CHECK-LABEL: define {{.+}} @{{.+}}tmain
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 2, void {{.+}}* [[T_OUTLINE_FUN_1:@.+]] to void
+// CHECK: call void @__kmpc_for_static_fini(
+
+// CHECK: define internal {{.*}}void [[T_OUTLINE_FUN_1]]
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call {{.*}}void @{{.+}}fn1
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call {{.*}}void @__kmpc_serialized_parallel(
+// CHECK: call void [[T_OUTLINE_FUN_2:@.+]](
+// CHECK: call {{.*}}void @__kmpc_end_serialized_parallel(
+// CHECK: call void @__kmpc_for_static_fini(
+
+// CHECK: define internal {{.*}}void [[T_OUTLINE_FUN_2]]
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call {{.*}}void @{{.+}}fn2
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 2, void {{.+}}* [[T_OUTLINE_FUN_3:@.+]] to void
+// CHECK: call {{.*}}void @__kmpc_serialized_parallel(
+// call void [[T_OUTLINE_FUN_3:@.+]](
+// CHECK: call {{.*}}void @__kmpc_end_serialized_parallel(
+
+// CHECK: define internal {{.*}}void [[T_OUTLINE_FUN_3]]
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call {{.*}}void @{{.+}}fn3
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+#endif
diff --git a/test/OpenMP/distribute_parallel_for_lastprivate_codegen.cpp b/test/OpenMP/distribute_parallel_for_lastprivate_codegen.cpp
new file mode 100644
index 0000000000..2e8da79c03
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_lastprivate_codegen.cpp
@@ -0,0 +1,653 @@
+// 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 parallel for lastprivate(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({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED:@.+]] to {{.+}})
+ #pragma omp target
+ #pragma omp teams
+#pragma omp distribute parallel for lastprivate(g, g1, svar, sfvar)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, double*{{.+}} [[G_IN:%.+]], double*{{.+}} [[G1_IN:%.+]], i{{[0-9]+}}*{{.+}} [[SVAR_IN:%.+]], float*{{.+}} [[SFVAR_IN:%.+]])
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}*,
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR:%.+]] = alloca float*,
+ // LAMBDA: [[TMP_G1:%.+]] = alloca double*,
+ // loop variables
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[TMP_G1_PRIVATE:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_PRIVATE:%.+]] = alloca float,
+
+ // init addr alloca's
+ // LAMBDA: store double* [[G_IN]], double** [[G_PRIVATE_ADDR]],
+ // LAMBDA: store double* [[G1_IN]], double** [[G1_PRIVATE_ADDR]],
+ // LAMBDA: store i{{[0-9]+}}* [[SVAR_IN]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR]],
+ // LAMBDA: store float* [[SFVAR_IN]], float** [[SFVAR_PRIVATE_ADDR]],
+
+ // init private variables
+ // LAMBDA: [[G_IN_REF:%.+]] = load double*, double** [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[SVAR_IN_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR]],
+ // LAMBDA: [[SFVAR_IN_REF:%.+]] = load float*, float** [[SFVAR_PRIVATE_ADDR]],
+ // LAMBDA: [[G1_IN_REF:%.+]] = load double*, double** [[G1_PRIVATE_ADDR]],
+ // LAMBDA: store double* [[G1_IN_REF]], double** [[TMP_G1]],
+ // LAMBDA: [[TMP_G1_VAL:%.+]] = load double*, double** [[TMP_G1]],
+ // LAMBDA: store double* [[G1_PRIVATE]], double** [[TMP_G1_PRIVATE]],
+
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
+ // LAMBDA: [[G1_PAR:%.+]] = load{{.+}}, {{.+}} [[TMP_G1_PRIVATE]],
+ // LAMBDA-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[G_PRIVATE]], {{.+}} [[G1_PAR]], {{.+}} [[SVAR_PRIVATE]], {{.+}} [[SFVAR_PRIVATE]])
+ // LAMBDA-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[G_PRIVATE]], {{.+}} [[G1_PAR]], {{.+}} [[SVAR_PRIVATE]], {{.+}} [[SFVAR_PRIVATE]])
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+
+ // lastprivate
+ // LAMBDA: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+ // LAMBDA: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+ // LAMBDA: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+ // LAMBDA: [[OMP_LASTPRIV_BLOCK]]:
+ // LAMBDA: [[G_PRIV_VAL:%.+]] = load double, double* [[G_PRIVATE]],
+ // LAMBDA: store{{.*}} double [[G_PRIV_VAL]], double* [[G_IN_REF]],
+ // LAMBDA: [[TMP_G1_PRIV_REF:%.+]] = load double*, double** [[TMP_G1_PRIVATE]],
+ // LAMBDA: [[TMP_G1_PRIV_VAL:%.+]] = load double, double* [[TMP_G1_PRIV_REF]],
+ // LAMBDA: store{{.*}} double [[TMP_G1_PRIV_VAL]], double* [[TMP_G1_VAL]],
+
+ // LAMBDA: [[SVAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA: store i{{[0-9]+}} [[SVAR_PRIV_VAL]], i{{[0-9]+}}* [[SVAR_IN_REF]],
+ // LAMBDA: [[SFVAR_PRIV_VAL:%.+]] = load float, float* [[SFVAR_PRIVATE]],
+ // LAMBDA: store float [[SFVAR_PRIV_VAL]], float* [[SFVAR_IN_REF]],
+ // LAMBDA: br label %[[OMP_LASTPRIV_DONE]]
+ // LAMBDA: [[OMP_LASTPRIV_DONE]]:
+ // LAMBDA: ret
+
+ g = 1;
+ g1 = 1;
+ svar = 3;
+ sfvar = 4.0;
+ // outlined function for 'parallel for'
+ // LAMBDA-64: define{{.+}} void [[OMP_PARFOR_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, {{.+}}, {{.+}}, {{.+}} [[G_IN:%.+]], {{.+}} [[G1_IN:%.+]], {{.+}} [[SVAR_IN:%.+]], {{.+}} [[SFVAR_IN:%.+]])
+ // LAMBDA-32: define{{.+}} void [[OMP_PARFOR_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, {{.+}}, {{.+}}, {{.+}} [[G_IN:%.+]], {{.+}} [[G1_IN:%.+]], {{.+}} [[SVAR_IN:%.+]], {{.+}} [[SFVAR_IN:%.+]])
+
+ // addr alloca's
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}*,
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR:%.+]] = alloca float*,
+
+ // loop variables
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+
+ // private alloca's
+ // LAMBDA: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[TMP_G1_PRIVATE:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_PRIVATE:%.+]] = alloca float,
+
+ // init addr alloca's
+ // LAMBDA: store double* [[G_IN]], double** [[G_PRIVATE_ADDR]],
+ // LAMBDA: store double* [[G1_IN]], double** [[G1_PRIVATE_ADDR]],
+ // LAMBDA: store i{{[0-9]+}}* [[SVAR_IN]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR]],
+ // LAMBDA: store float* [[SFVAR_IN]], float** [[SFVAR_PRIVATE_ADDR]],
+
+ // init private variables
+ // LAMBDA: [[G_IN_REF:%.+]] = load double*, double** [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[SVAR_IN_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR]],
+ // LAMBDA: [[SFVAR_IN_REF:%.+]] = load float*, float** [[SFVAR_PRIVATE_ADDR]],
+
+ // LAMBDA: [[G1_IN_REF:%.+]] = load double*, double** [[G1_PRIVATE_ADDR]],
+ // LAMBDA: store double* [[G1_PRIVATE]], double** [[TMP_G1]],
+
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
+
+ // loop body
+ // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE]],
+ // LAMBDA: [[TMP_G1_REF:%.+]] = load double*, double** [[TMP_G1_PRIVATE]],
+ // LAMBDA: store{{.+}} double 1.0{{.+}}, double* [[TMP_G1_REF]],
+ // LAMBDA: store i{{[0-9]+}} 3, i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA: store float 4.0{{.+}}, float* [[SFVAR_PRIVATE]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store double* [[G_PRIVATE]], double** [[G_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[TMP_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR_FROM_TMP:%.+]] = load double*, double** [[TMP_G1_PRIVATE]],
+ // LAMBDA: store double* [[G1_PRIVATE_ADDR_FROM_TMP]], double** [[TMP_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[SVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: store i{{[0-9]+}}* [[SVAR_PRIVATE]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: store float* [[SFVAR_PRIVATE]], float** [[SFVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+
+ // lastprivate
+ // LAMBDA: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+ // LAMBDA: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+ // LAMBDA: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+ // LAMBDA: [[OMP_LASTPRIV_BLOCK]]:
+ // LAMBDA: [[G_PRIV_VAL:%.+]] = load double, double* [[G_PRIVATE]],
+ // LAMBDA: store{{.*}} double [[G_PRIV_VAL]], double* [[G_IN_REF]],
+ // LAMBDA: [[TMP_G1_PRIV_REF:%.+]] = load double*, double** [[TMP_G1_PRIVATE]],
+ // LAMBDA: [[TMP_G1_PRIV_VAL:%.+]] = load double, double* [[TMP_G1_PRIV_REF]],
+ // LAMBDA: store{{.*}} double [[TMP_G1_PRIV_VAL]], double* [[G1_IN_REF]],
+ // LAMBDA: [[SVAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA: store i{{[0-9]+}} [[SVAR_PRIV_VAL]], i{{[0-9]+}}* [[SVAR_IN_REF]],
+ // LAMBDA: [[SFVAR_PRIV_VAL:%.+]] = load float, float* [[SFVAR_PRIVATE]],
+ // LAMBDA: store float [[SFVAR_PRIV_VAL]], float* [[SFVAR_IN_REF]],
+ // LAMBDA: br label %[[OMP_LASTPRIV_DONE]]
+ // LAMBDA: [[OMP_LASTPRIV_DONE]]:
+ // LAMBDA: ret
+
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ g1 = 2;
+ svar = 4;
+ sfvar = 8.0;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]]
+
+ // LAMBDA: [[TMP_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load double*, double** [[TMP_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G1_REF]],
+ // LAMBDA: [[SVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SVAR_REF]]
+ // LAMBDA: [[SFVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: [[SFVAR_REF:%.+]] = load float*, float** [[SFVAR_PTR_REF]]
+ // LAMBDA: store float 8.0{{.+}}, 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 parallel for lastprivate(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;
+ }
+ int i;
+
+ 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:@.+]](i{{[0-9]+}} {{.+}}, [2 x i{{[0-9]+}}]* {{.+}}, [2 x [[S_FLOAT_TY]]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, i{{[0-9]+}} {{.+}})
+// CHECK: ret
+
+// CHECK: define{{.+}} [[OFFLOAD_FUN]](i{{[0-9]+}} {{.+}}, [2 x i{{[0-9]+}}]*{{.+}} {{.+}}, [2 x [[S_FLOAT_TY]]]*{{.+}} {{.+}}, [[S_FLOAT_TY]]*{{.+}} {{.+}}, i{{[0-9]+}} {{.+}})
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(
+// CHECK: ret
+//
+// CHECK: define internal void [[OMP_OUTLINED:@.+]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, 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]+}}*{{.*}} [[S_VAR_IN:%.+]])
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// 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]]*,
+// skip loop variables
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[S_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+
+// copy from parameters to local address variables
+// 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]+}}* [[S_VAR_IN]], i{{[0-9]+}}** [[SVAR_ADDR]],
+
+// load content of local address variables
+// CHECK: [[T_VAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_ADDR]],
+// CHECK: [[VEC_ADDR_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: [[S_ARR_ADDR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: [[SVAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_ADDR]],
+// CHECK: [[VAR_ADDR_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_ADDR]],
+// CHECK: store [[S_FLOAT_TY]]* [[VAR_ADDR_REF]], [[S_FLOAT_TY]]** [[TMP]],
+// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[OMP_IS_LAST]],
+
+// call constructor for s_arr
+// CHECK: [[S_ARR_BGN:%.+]] = getelementptr{{.+}} [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]],
+// CHECK: [[S_ARR_END:%.+]] = getelementptr {{.+}} [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_BGN]],
+// CHECK: br label %[[S_ARR_CST_LOOP:.+]]
+// CHECK: [[S_ARR_CST_LOOP]]:
+// CHECK: [[S_ARR_CTOR:%.+]] = phi {{.+}}
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_CTOR]])
+// CHECK: [[S_ARR_NEXT:%.+]] = getelementptr {{.+}} [[S_ARR_CTOR]],
+// CHECK: [[S_ARR_DONE:%.+]] = icmp {{.+}} [[S_ARR_NEXT]], [[S_ARR_END]]
+// CHECK: br i1 [[S_ARR_DONE]], label %[[S_ARR_CST_END:.+]], label %[[S_ARR_CST_LOOP]]
+// CHECK: [[S_ARR_CST_END]]:
+// CHECK: [[TMP_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP]],
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK: store [[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]** [[TMP_PRIV]],
+
+// the distribute loop
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: [[TMP_PRIV_VAL:%.+]] = load {{.+}}, {{.+}} [[TMP_PRIV]],
+// CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[VEC_PRIV]], {{.+}} [[T_VAR_PRIV]], {{.+}} [[S_ARR_PRIV]], {{.+}} [[TMP_PRIV_VAL]], {{.+}} [[S_VAR_PRIV]])
+// CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[VEC_PRIV]], {{.+}} [[T_VAR_PRIV]], {{.+}} [[S_ARR_PRIV]], {{.+}} [[TMP_PRIV_VAL]], {{.+}} [[S_VAR_PRIV]])
+
+// CHECK: call void @__kmpc_for_static_fini(
+
+// lastprivates
+// CHECK: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+// CHECK: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+// CHECK: [[OMP_LASTPRIV_BLOCK]]:
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_ADDR_REF]],
+// CHECK: [[BCAST_VEC_ADDR_REF:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_REF]] to i8*
+// CHECK: [[BCAST_VEC_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[BCAST_VEC_ADDR_REF]], i8* [[BCAST_VEC_PRIV]],
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_ADDR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BCAST:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]] to [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_BEGIN_GEP:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_COPY_DONE:.+]], label %[[S_ARR_COPY_BLOCK:.+]]
+// CHECK: [[S_ARR_COPY_BLOCK]]:
+// CHECK: [[S_ARR_SRC_EL:%.+]] = phi [[S_FLOAT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_EL:%.+]] = phi [[S_FLOAT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_DST_EL]] to i8*
+// CHECK: [[S_ARR_SRC_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_SRC_EL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_DST_BCAST]], i8* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK: [[S_ARR_DST_NEXT:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_DST_EL]], i{{[0-9]+}} 1
+// CHECK: [[S_ARR_SRC_NEXT:%.+]] = getelementptr{{.+}}
+// CHECK: [[CPY_IS_FINISHED:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_DST_NEXT]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[CPY_IS_FINISHED]], label %[[S_ARR_COPY_DONE]], label %[[S_ARR_COPY_BLOCK]]
+// CHECK: [[S_ARR_COPY_DONE]]:
+// CHECK: [[TMP_VAL1:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP_PRIV]],
+// CHECK: [[VAR_ADDR_REF_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[TMP_REF]] to i8*
+// CHECK: [[TMP_VAL1_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[TMP_VAL1]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VAR_ADDR_REF_BCAST]], i8* [[TMP_VAL1_BCAST]],{{.+}})
+// CHECK: [[SVAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[S_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[SVAR_VAL]], i{{[0-9]+}}* [[SVAR_ADDR_REF]],
+// CHECK: ret void
+
+// outlined function for 'parallel for'
+// CHECK-64: define{{.+}} void [[OMP_PARFOR_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, {{.+}}, {{.+}}, {{.+}} [[VEC_IN:%.+]], {{.+}} [[T_VAR_IN:%.+]], {{.+}} [[S_ARR_IN:%.+]], {{.+}} [[VAR_IN:%.+]], {{.+}} [[SVAR_IN:%.+]])
+// CHECK-32: define{{.+}} void [[OMP_PARFOR_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, {{.+}}, {{.+}}, {{.+}} [[VEC_IN:%.+]], {{.+}} [[T_VAR_IN:%.+]], {{.+}} [[S_ARR_IN:%.+]], {{.+}} [[VAR_IN:%.+]], {{.+}} [[SVAR_IN:%.+]])
+
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca 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]+}}*,
+// skip loop variables
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[S_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+
+// copy from parameters to local address variables
+// CHECK: store [2 x i{{[0-9]+}}]* [[VEC_IN]], [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: store i{{[0-9]+}}* [[T_VAR_IN]], i{{[0-9]+}}** [[T_VAR_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]+}}* [[S_VAR_IN]], i{{[0-9]+}}** [[SVAR_ADDR]],
+
+// load content of local address variables
+// CHECK: [[VEC_ADDR_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: [[T_VAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_ADDR]],
+// CHECK: [[S_ARR_ADDR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: [[SVAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_ADDR]],
+// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[OMP_IS_LAST]],
+
+// call constructor for s_arr
+// CHECK: [[S_ARR_BGN:%.+]] = getelementptr{{.+}} [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]],
+// CHECK: [[S_ARR_END:%.+]] = getelementptr {{.+}} [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_BGN]],
+// CHECK: br label %[[S_ARR_CST_LOOP:.+]]
+// CHECK: [[S_ARR_CST_LOOP]]:
+// CHECK: [[S_ARR_CTOR:%.+]] = phi {{.+}}
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_CTOR]])
+// CHECK: [[S_ARR_NEXT:%.+]] = getelementptr {{.+}} [[S_ARR_CTOR]],
+// CHECK: [[S_ARR_DONE:%.+]] = icmp {{.+}} [[S_ARR_NEXT]], [[S_ARR_END]]
+// CHECK: br i1 [[S_ARR_DONE]], label %[[S_ARR_CST_END:.+]], label %[[S_ARR_CST_LOOP]]
+// CHECK: [[S_ARR_CST_END]]:
+// CHECK: [[VAR_ADDR_REF:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_ADDR]],
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK: store [[S_FLOAT_TY]]* [[VAR_PRIV]], [[S_FLOAT_TY]]** [[TMP_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+
+// loop body
+// assignment: vec[i] = t_var;
+// 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]],
+
+// assignment: s_arr[i] = var;
+// CHECK-DAG: [[S_ARR_PTR:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[TMP_VAL:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP_PRIV]],
+// CHECK-DAG: [[S_ARR_PTR_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_PTR]] to i8*
+// CHECK-DAG: [[TMP_VAL_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[TMP_VAL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_PTR_BCAST]], i8* [[TMP_VAL_BCAST]],
+
+// CHECK: call void @__kmpc_for_static_fini(
+
+// lastprivates
+// CHECK: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+// CHECK: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+// CHECK: [[OMP_LASTPRIV_BLOCK]]:
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_ADDR_REF]],
+// CHECK: [[BCAST_VEC_ADDR_REF:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_REF]] to i8*
+// CHECK: [[BCAST_VEC_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[BCAST_VEC_ADDR_REF]], i8* [[BCAST_VEC_PRIV]],
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_ADDR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BCAST:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]] to [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_BEGIN_GEP:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_COPY_DONE:.+]], label %[[S_ARR_COPY_BLOCK:.+]]
+// CHECK: [[S_ARR_COPY_BLOCK]]:
+// CHECK: [[S_ARR_SRC_EL:%.+]] = phi [[S_FLOAT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_EL:%.+]] = phi [[S_FLOAT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_DST_EL]] to i8*
+// CHECK: [[S_ARR_SRC_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_SRC_EL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_DST_BCAST]], i8* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK: [[S_ARR_DST_NEXT:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_DST_EL]], i{{[0-9]+}} 1
+// CHECK: [[S_ARR_SRC_NEXT:%.+]] = getelementptr{{.+}}
+// CHECK: [[CPY_IS_FINISHED:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_DST_NEXT]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[CPY_IS_FINISHED]], label %[[S_ARR_COPY_DONE]], label %[[S_ARR_COPY_BLOCK]]
+// CHECK: [[S_ARR_COPY_DONE]]:
+// CHECK: [[TMP_VAL1:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP_PRIV]],
+// CHECK: [[VAR_ADDR_REF_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_ADDR_REF]] to i8*
+// CHECK: [[TMP_VAL1_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[TMP_VAL1]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VAR_ADDR_REF_BCAST]], i8* [[TMP_VAL1_BCAST]],{{.+}})
+// CHECK: [[SVAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[S_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[SVAR_VAL]], i{{[0-9]+}}* [[SVAR_ADDR_REF]],
+// CHECK: ret void
+
+// template tmain
+// 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:@.+]](i{{[0-9]+}} {{.+}}, [2 x i{{[0-9]+}}]* {{.+}}, [2 x [[S_INT_TY]]]* {{.+}}, [[S_INT_TY]]* {{.+}})
+// CHECK: ret
+
+// CHECK: define internal void [[OFFLOAD_FUN_1]](
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4,
+// CHECK: ret
+
+// CHECK: define internal void [[OMP_OUTLINED_1:@.+]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, 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:%.+]])
+// skip alloca of global_tid and bound_tid
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// 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]]*,
+// skip loop variables
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_INT_TY]]*,
+
+// skip init of bound and global tid
+// CHECK: store i{{[0-9]+}}* {{.*}},
+// CHECK: store i{{[0-9]+}}* {{.*}},
+// copy from parameters to local address variables
+// 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]],
+
+// load content of local address variables
+// CHECK: [[T_VAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_ADDR]],
+// CHECK: [[VEC_ADDR_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: [[S_ARR_ADDR_REF:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: [[VAR_ADDR_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_ADDR]],
+// CHECK-DAG: store [[S_INT_TY]]* [[VAR_ADDR_REF]], [[S_INT_TY]]** [[TMP]],
+// CHECK-DAG: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[OMP_IS_LAST]],
+// CHECK-DAG: [[TMP_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: [[TMP_PRIV_VAL:%.+]] = load {{.+}}, {{.+}} [[TMP_PRIV]],
+// CHECK-64: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[VEC_PRIV]], {{.+}} [[T_VAR_PRIV]], {{.+}} [[S_ARR_PRIV]], {{.+}} [[TMP_PRIV_VAL]])
+// CHECK-32: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to void ({{.+}})*), {{.+}}, {{.+}}, {{.+}} [[VEC_PRIV]], {{.+}} [[T_VAR_PRIV]], {{.+}} [[S_ARR_PRIV]], {{.+}} [[TMP_PRIV_VAL]])
+
+// CHECK: call void @__kmpc_for_static_fini(
+
+// lastprivates
+// CHECK: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+// CHECK: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+// CHECK: [[OMP_LASTPRIV_BLOCK]]:
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_ADDR_REF]],
+// CHECK: [[BCAST_VEC_ADDR_REF:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_REF]] to i8*
+// CHECK: [[BCAST_VEC_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[BCAST_VEC_ADDR_REF]], i8* [[BCAST_VEC_PRIV]],
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_ADDR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BCAST:%.+]] = bitcast [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]] to [[S_INT_TY]]*
+// CHECK: [[S_ARR_BEGIN_GEP:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_COPY_DONE:.+]], label %[[S_ARR_COPY_BLOCK:.+]]
+// CHECK: [[S_ARR_COPY_BLOCK]]:
+// CHECK: [[S_ARR_SRC_EL:%.+]] = phi [[S_INT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_EL:%.+]] = phi [[S_INT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_DST_EL]] to i8*
+// CHECK: [[S_ARR_SRC_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_SRC_EL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_DST_BCAST]], i8* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK: [[S_ARR_DST_NEXT:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_DST_EL]], i{{[0-9]+}} 1
+// CHECK: [[S_ARR_SRC_NEXT:%.+]] = getelementptr{{.+}}
+// CHECK: [[CPY_IS_FINISHED:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_DST_NEXT]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[CPY_IS_FINISHED]], label %[[S_ARR_COPY_DONE]], label %[[S_ARR_COPY_BLOCK]]
+// CHECK: [[S_ARR_COPY_DONE]]:
+// CHECK: [[TMP_VAL:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP_PRIV]],
+// CHECK: [[VAR_ADDR_REF_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[TMP_REF]] to i8*
+// CHECK: [[TMP_VAL_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[TMP_VAL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VAR_ADDR_REF_BCAST]], i8* [[TMP_VAL_BCAST]],{{.+}})
+// CHECK: ret void
+
+// outlined function for 'parallel for'
+// CHECK-64: define{{.+}} void [[OMP_PARFOR_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, {{.+}}, {{.+}}, {{.+}} [[VEC_IN:%.+]], {{.+}} [[T_VAR_IN:%.+]], {{.+}} [[S_ARR_IN:%.+]], {{.+}} [[VAR_IN:%.+]])
+// CHECK-32: define{{.+}} void [[OMP_PARFOR_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, {{.+}}, {{.+}}, {{.+}} [[VEC_IN:%.+]], {{.+}} [[T_VAR_IN:%.+]], {{.+}} [[S_ARR_IN:%.+]], {{.+}} [[VAR_IN:%.+]])
+
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca i{{[0-9]+}}*,
+// CHECK: [[S_ARR_ADDR:%.+]] = alloca [2 x [[S_INT_TY]]]*,
+// CHECK: [[VAR_ADDR:%.+]] = alloca [[S_INT_TY]]*,
+// skip loop variables
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_INT_TY]]*,
+
+// copy from parameters to local address variables
+// CHECK: store [2 x i{{[0-9]+}}]* [[VEC_IN]], [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: store i{{[0-9]+}}* [[T_VAR_IN]], i{{[0-9]+}}** [[T_VAR_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]],
+
+// load content of local address variables
+// CHECK: [[VEC_ADDR_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: [[T_VAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_ADDR]],
+// CHECK: [[S_ARR_ADDR_REF:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[OMP_IS_LAST]],
+
+// call constructor for s_arr
+// CHECK: [[S_ARR_BGN:%.+]] = getelementptr{{.+}} [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]],
+// CHECK: [[S_ARR_END:%.+]] = getelementptr {{.+}} [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_BGN]],
+// CHECK: br label %[[S_ARR_CST_LOOP:.+]]
+// CHECK: [[S_ARR_CST_LOOP]]:
+// CHECK: [[S_ARR_CTOR:%.+]] = phi {{.+}}
+// CHECK: call void [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_CTOR]])
+// CHECK: [[S_ARR_NEXT:%.+]] = getelementptr {{.+}} [[S_ARR_CTOR]],
+// CHECK: [[S_ARR_DONE:%.+]] = icmp {{.+}} [[S_ARR_NEXT]], [[S_ARR_END]]
+// CHECK: br i1 [[S_ARR_DONE]], label %[[S_ARR_CST_END:.+]], label %[[S_ARR_CST_LOOP]]
+// CHECK: [[S_ARR_CST_END]]:
+// CHECK: [[VAR_ADDR_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_ADDR]],
+// CHECK: call void [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK: store [[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]** [[TMP_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+
+// assignment: vec[i] = t_var;
+// 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]],
+
+// assignment: s_arr[i] = var;
+// CHECK-DAG: [[S_ARR_PTR:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[TMP_VAL:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP_PRIV]],
+// CHECK-DAG: [[S_ARR_PTR_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_PTR]] to i8*
+// CHECK-DAG: [[TMP_VAL_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[TMP_VAL]] to i8*
+// CHECK-DAG: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_PTR_BCAST]], i8* [[TMP_VAL_BCAST]],
+
+// CHECK: call void @__kmpc_for_static_fini(
+
+// lastprivates
+// CHECK: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+// CHECK: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+// CHECK: [[OMP_LASTPRIV_BLOCK]]:
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_ADDR_REF]],
+// CHECK: [[BCAST_VEC_ADDR_REF:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_REF]] to i8*
+// CHECK: [[BCAST_VEC_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[BCAST_VEC_ADDR_REF]], i8* [[BCAST_VEC_PRIV]],
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_ADDR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BCAST:%.+]] = bitcast [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]] to [[S_INT_TY]]*
+// CHECK: [[S_ARR_BEGIN_GEP:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_COPY_DONE:.+]], label %[[S_ARR_COPY_BLOCK:.+]]
+// CHECK: [[S_ARR_COPY_BLOCK]]:
+// CHECK: [[S_ARR_SRC_EL:%.+]] = phi [[S_INT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_EL:%.+]] = phi [[S_INT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_DST_EL]] to i8*
+// CHECK: [[S_ARR_SRC_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_SRC_EL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_DST_BCAST]], i8* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK: [[S_ARR_DST_NEXT:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_DST_EL]], i{{[0-9]+}} 1
+// CHECK: [[S_ARR_SRC_NEXT:%.+]] = getelementptr{{.+}}
+// CHECK: [[CPY_IS_FINISHED:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_DST_NEXT]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[CPY_IS_FINISHED]], label %[[S_ARR_COPY_DONE]], label %[[S_ARR_COPY_BLOCK]]
+// CHECK: [[S_ARR_COPY_DONE]]:
+// CHECK: [[TMP_VAL1:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP_PRIV]],
+// CHECK: [[VAR_ADDR_REF_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[VAR_ADDR_REF]] to i8*
+// CHECK: [[TMP_VAL1_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[TMP_VAL1]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VAR_ADDR_REF_BCAST]], i8* [[TMP_VAL1_BCAST]],{{.+}})
+// CHECK: ret void
+
+#endif
diff --git a/test/OpenMP/distribute_parallel_for_lastprivate_messages.cpp b/test/OpenMP/distribute_parallel_for_lastprivate_messages.cpp
index 745007fc48..ebc7a66673 100644
--- a/test/OpenMP/distribute_parallel_for_lastprivate_messages.cpp
+++ b/test/OpenMP/distribute_parallel_for_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/distribute_parallel_for_messages.cpp b/test/OpenMP/distribute_parallel_for_messages.cpp
new file mode 100644
index 0000000000..35a61df39e
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_messages.cpp
@@ -0,0 +1,118 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s
+
+void foo() {
+}
+
+#pragma omp distribute parallel for // expected-error {{unexpected OpenMP directive '#pragma omp distribute parallel for'}}
+
+int main(int argc, char **argv) {
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for { // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for ( // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for[ // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for] // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for) // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for } // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for unknown() // expected-warning {{extra tokens at the end of '#pragma omp distribute parallel for' are ignored}}
+ for (int i = 0; i < argc; ++i)
+ foo();
+L1:
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for
+ for (int i = 0; i < argc; ++i)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for
+ for (int i = 0; i < argc; ++i) {
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ argc++;
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ switch (argc) {
+ case (0):
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for
+ for (int i = 0; i < argc; ++i) {
+ foo();
+ break; // expected-error {{'break' statement cannot be used in OpenMP for loop}}
+ continue;
+ }
+ default:
+ break;
+ }
+ }
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for default(none)
+ for (int i = 0; i < 10; ++i)
+ ++argc; // expected-error {{variable 'argc' must have explicitly specified data sharing attributes}}
+
+ goto L2; // expected-error {{use of undeclared label 'L2'}}
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for
+ for (int i = 0; i < argc; ++i)
+ L2:
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for
+ for (int i = 0; i < argc; ++i) {
+ return 1; // expected-error {{cannot return from OpenMP region}}
+ }
+
+ [[]] // expected-error {{an attribute list cannot appear here}}
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for
+ for (int n = 0; n < 100; ++n) {
+ }
+
+ return 0;
+}
+
+void test_ordered() {
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for collapse(2) collapse(3) // expected-error {{directive '#pragma omp distribute parallel for' cannot contain more than one 'collapse' clause}}
+ for (int i = 0; i < 16; ++i)
+ for (int j = 0; j < 16; ++j)
+ ;
+}
+
diff --git a/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp b/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp
new file mode 100644
index 0000000000..89e9905044
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp
@@ -0,0 +1,121 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple %itanium_abi_triple -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -std=c++11 -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -fopenmp-targets=powerpc64le-ibm-linux-gnu -x c++ -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+// CHECK-DAG: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[S_TY:%.+]] = type { [[INTPTR_T_TY:i[0-9]+]], [[INTPTR_T_TY]], [[INTPTR_T_TY]] }
+// CHECK-DAG: [[STR:@.+]] = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00"
+// CHECK-DAG: [[DEF_LOC_2:@.+]] = private unnamed_addr constant [[IDENT_T_TY]] { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+void foo();
+
+struct S {
+ intptr_t a, b, c;
+ S(intptr_t a) : a(a) {}
+ operator char() { return a; }
+ ~S() {}
+};
+
+template <typename T, int C>
+int tmain() {
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for num_threads(C)
+ for (int i = 0; i < 100; i++)
+ foo();
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for num_threads(T(23))
+ for (int i = 0; i < 100; i++)
+ foo();
+ return 0;
+}
+
+int main() {
+ S s(0);
+ char a = s;
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_0:@.+]](
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[OFFLOADING_FUN_1:@.+]](
+// CHECK: invoke{{.+}} [[TMAIN_5:@.+]]()
+// CHECK: invoke{{.+}} [[TMAIN_1:@.+]]()
+#pragma omp target
+#pragma omp teams
+ // CHECK: define internal void [[OFFLOADING_FUN_0]](
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[OMP_TEAMS_OUTLINED_0:@.+]] to {{.+}})
+#pragma omp distribute parallel for num_threads(2)
+ for (int i = 0; i < 100; i++) {
+ // CHECK: define{{.+}} void [[OMP_TEAMS_OUTLINED_0]](
+ // CHECK: call {{.*}}void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 {{.+}}, i32 2)
+ // CHECK: call {{.*}}void {{.*}} @__kmpc_fork_call(
+ foo();
+ }
+#pragma omp target
+#pragma omp teams
+ // CHECK: define internal void [[OFFLOADING_FUN_1]](
+
+ // CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}}* [[OMP_TEAMS_OUTLINED_1:@.+]] to {{.+}})
+#pragma omp distribute parallel for num_threads(a)
+ for (int i = 0; i < 100; i++) {
+ // CHECK: define{{.+}} void [[OMP_TEAMS_OUTLINED_1]](
+ // CHECK-DAG: [[A_ADDR:%.+]] = alloca i8*,
+ // CHECK-DAG: [[A_REF:%.+]] = load i8*, i8** [[A_ADDR]],
+ // CHECK-DAG: [[A_VAL:%.+]] = load i8, i8* [[A_REF]],
+ // CHECK-DAG: [[A_EXT:%.+]] = sext i8 [[A_VAL]] to {{.+}}
+ // CHECK: call {{.*}}void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 {{.+}}, i32 [[A_EXT]])
+ // CHECK: call {{.*}}void {{.*}} @__kmpc_fork_call(
+ foo();
+ }
+ return a + tmain<char, 5>() + tmain<S, 1>();
+}
+
+// tmain 5
+// CHECK-DAG: define {{.*}}i{{[0-9]+}} [[TMAIN_5]]()
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[T_OFFLOADING_FUN_0:@.+]](
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[T_OFFLOADING_FUN_1:@.+]](
+
+// tmain 1
+// CHECK-DAG: define {{.*}}i{{[0-9]+}} [[TMAIN_1]]()
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[T_OFFLOADING_FUN_2:@.+]](
+// CHECK: call i{{[0-9]+}} @__tgt_target_teams(
+// CHECK: call void [[T_OFFLOADING_FUN_3:@.+]](
+
+// CHECK: define internal void [[T_OFFLOADING_FUN_0]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[T_OMP_TEAMS_OUTLINED_0:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[T_OMP_TEAMS_OUTLINED_0]](
+// CHECK: call {{.*}}void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 {{.+}}, i32 5)
+// CHECK: call {{.*}}void {{.*}} @__kmpc_fork_call(
+
+// CHECK: define internal void [[T_OFFLOADING_FUN_1]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[T_OMP_TEAMS_OUTLINED_1:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[T_OMP_TEAMS_OUTLINED_1]](
+// CHECK: call {{.*}}void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 {{.+}}, i32 23)
+// CHECK: call {{.*}}void {{.*}} @__kmpc_fork_call(
+
+// CHECK: define internal void [[T_OFFLOADING_FUN_2]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[T_OMP_TEAMS_OUTLINED_2:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[T_OMP_TEAMS_OUTLINED_2]](
+// CHECK: call {{.*}}void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 {{.+}}, i32 1)
+// CHECK: call {{.*}}void {{.*}} @__kmpc_fork_call(
+
+// CHECK: define internal void [[T_OFFLOADING_FUN_3]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}}* [[T_OMP_TEAMS_OUTLINED_3:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} void [[T_OMP_TEAMS_OUTLINED_3]](
+// CHECK-DAG: [[CALL_RES:%.+]] = invoke{{.*}} i8 [[S_TY_CHAR_OP:@.+]]([[S_TY]]* {{.+}})
+// CHECK-DAG: [[CALL_RES_SEXT:%.+]] = sext i8 [[CALL_RES]] to {{.+}}
+// CHECK: call {{.*}}void @__kmpc_push_num_threads([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 {{.+}}, i32 [[CALL_RES_SEXT]])
+// CHECK: call {{.*}}void {{.*}} @__kmpc_fork_call(
+#endif
diff --git a/test/OpenMP/distribute_parallel_for_private_codegen.cpp b/test/OpenMP/distribute_parallel_for_private_codegen.cpp
new file mode 100644
index 0000000000..d8d8a9a1ed
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_private_codegen.cpp
@@ -0,0 +1,297 @@
+// 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 parallel for private(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({{.+}}, i32 0, {{.+}}* [[OMP_OUTLINED:@.+]] to {{.+}})
+ #pragma omp target
+ #pragma omp teams
+ #pragma omp distribute parallel for private(g, g1, svar, sfvar)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}})
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca double,
+ // LAMBDA: [[TMP_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR:%.+]] = alloca float,
+ // LAMBDA: store double* [[G1_PRIVATE_ADDR]], double** [[TMP_PRIVATE_ADDR]],
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
+ // LAMBDA: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED:@.+]] to {{.+}},
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+ // LAMBDA: ret void
+
+ // LAMBDA: define{{.+}} void [[OMP_PARFOR_OUTLINED]](
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca double,
+ // LAMBDA: [[TMP_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR:%.+]] = alloca float,
+
+ g = 1;
+ g1 = 1;
+ svar = 3;
+ sfvar = 4.0;
+ // LAMBDA: store double* [[G1_PRIVATE_ADDR]], double** [[TMP_PRIVATE_ADDR]],
+ // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]],
+ // LAMBDA: store i{{[0-9]+}} 3, i{{[0-9]+}}* [[SVAR_PRIVATE_ADDR]],
+ // LAMBDA: store float 4.0{{.+}}, float* [[SFVAR_PRIVATE_ADDR]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store double* [[G_PRIVATE_ADDR]], double** [[G_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[TMP_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR_FROM_TMP:%.+]] = load double*, double** [[TMP_PRIVATE_ADDR]],
+ // LAMBDA: store double* [[G1_PRIVATE_ADDR_FROM_TMP]], double** [[TMP_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[SVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: store i{{[0-9]+}}* [[SVAR_PRIVATE_ADDR]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: store float* [[SFVAR_PRIVATE_ADDR]], float** [[SFVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+ // LAMBDA: ret void
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ g1 = 2;
+ svar = 4;
+ sfvar = 8.0;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]]
+
+ // LAMBDA: [[TMP_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load double*, double** [[TMP_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G1_REF]],
+ // LAMBDA: [[SVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SVAR_REF]]
+ // LAMBDA: [[SFVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: [[SFVAR_REF:%.+]] = load float*, float** [[SFVAR_PTR_REF]]
+ // LAMBDA: store float 8.0{{.+}}, 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 parallel for private(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_0:@.+]](
+
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_DESTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: ret
+
+// CHECK: define{{.+}} [[OFFLOAD_FUN_0]]()
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(%{{.+}}* @{{.+}}, i{{[0-9]+}} 0, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*)* [[OMP_OUTLINED_0:@.+]] to void
+// CHECK: ret
+//
+// CHECK: define internal void [[OMP_OUTLINED_0]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK-NOT: alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK-NOT: alloca [[S_FLOAT_TY]],
+// CHECK: [[S_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// this is the ctor loop
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_0:@.+]] to {{.+}},
+// CHECK: call void @__kmpc_for_static_fini(
+
+// call destructors: var..
+// CHECK-DAG: call {{.+}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+
+// ..and s_arr
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_EL_PAST:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = getelementptr {{.+}}, {{.+}} [[S_ARR_EL_PAST]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+
+// CHECK: ret void
+
+// By OpenMP specifications, private applies to both distribute and parallel for.
+// However, the support for 'private' of 'parallel' is only used when 'parallel'
+// is found alone. Therefore we only have one 'private' support for 'parallel for'
+// in combination
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_0]](
+// CHECK: [[T_VAR_PRIV:%t_var+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%vec+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%s_arr+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK-NOT: alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%var+]] = alloca [[S_FLOAT_TY]],
+// CHECK-NOT: alloca [[S_FLOAT_TY]],
+// CHECK: [[S_VAR_PRIV:%svar+]] = alloca i{{[0-9]+}},
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// this is the ctor loop
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+
+// call destructors: var..
+// CHECK-DAG: call {{.+}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+
+// ..and s_arr
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_EL_PAST:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = getelementptr {{.+}}, {{.+}} [[S_ARR_EL_PAST]],
+// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_DESTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+
+// CHECK: ret void
+
+// template tmain with S_INT_TY
+// 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: call {{.*}} [[S_INT_TY_DEF_DESTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: ret
+
+// CHECK: ret
+
+// CHECK: define internal void [[OFFLOAD_FUN_1]]()
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(%{{.+}}* @{{.+}}, i{{[0-9]+}} 0, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*)* [[OMP_OUTLINED_1:@.+]] to void
+// CHECK: ret
+//
+// CHECK: define internal void [[OMP_OUTLINED_1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK-NOT: alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK-NOT: alloca [[S_INT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_INT_TY]]*
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call{{.+}} @__kmpc_fork_call({{.+}}, {{.+}}, {{.+}}[[OMP_PARFOR_OUTLINED_1:@.+]] to {{.+}},
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+// CHECK: define{{.+}} void [[OMP_PARFOR_OUTLINED_1]](
+// CHECK: [[T_VAR_PRIV:%t_var+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%vec+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%s_arr+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK-NOT: alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%var+]] = alloca [[S_INT_TY]],
+// CHECK-NOT: alloca [[S_INT_TY]],
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// this is the ctor loop
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_INT_TY]]*
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: call void @__kmpc_for_static_fini(
+
+// call destructors: var..
+// CHECK-DAG: call {{.+}} [[S_INT_TY_DEF_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+
+// ..and s_arr
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_EL_PAST:%.+]] = phi [[S_INT_TY]]*
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = getelementptr {{.+}}, {{.+}} [[S_ARR_EL_PAST]],
+// CHECK: call {{.*}} [[S_INT_TY_DEF_DESTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+
+// CHECK: ret void
+
+#endif
diff --git a/test/OpenMP/distribute_parallel_for_proc_bind_codegen.cpp b/test/OpenMP/distribute_parallel_for_proc_bind_codegen.cpp
new file mode 100644
index 0000000000..958b4e782f
--- /dev/null
+++ b/test/OpenMP/distribute_parallel_for_proc_bind_codegen.cpp
@@ -0,0 +1,93 @@
+// add -fopenmp-targets
+
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -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
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+// CHECK-DAG: [[IDENT_T_TY:%.+]] = 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_2:@.+]] = private unnamed_addr constant [[IDENT_T_TY]] { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[STR]], i32 0, i32 0) }
+
+void foo();
+
+struct S {
+ intptr_t a, b, c;
+ S(intptr_t a) : a(a) {}
+ operator char() { return a; }
+ ~S() {}
+};
+
+template <typename T>
+T tmain() {
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for proc_bind(master)
+ for(int i = 0; i < 1000; i++) {}
+ return T();
+}
+
+int main() {
+ // CHECK-LABEL: @main
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for proc_bind(spread)
+ for(int i = 0; i < 1000; i++) {}
+#pragma omp target
+#pragma omp teams
+#pragma omp distribute parallel for proc_bind(close)
+ for(int i = 0; i < 1000; i++) {}
+ return tmain<int>();
+}
+
+// CHECK: call {{.*}}@__tgt_target_teams({{.+}})
+// CHECK: call void [[OFFL1:@.+]]()
+// CHECK: call {{.*}}@__tgt_target_teams({{.+}})
+// CHECK: call void [[OFFL2:@.+]]()
+// CHECK: [[CALL_RET:%.+]] = call{{.+}} i32 [[TMAIN:@.+]]()
+// CHECK: ret i32 [[CALL_RET]]
+
+// CHECK: define{{.+}} void [[OFFL1]](
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}}* [[OMP_OUTLINED_1:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} [[OMP_OUTLINED_1]](i32* {{.+}} [[GTID_IN:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = alloca i32*,
+// CHECK: store i32* [[GTID_IN]], i32** [[GTID_ADDR]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_ADDR]],
+// CHECK: [[GTID_VAL:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.*}}void @__kmpc_push_proc_bind([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID_VAL]], i32 4)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(
+// CHECK: ret void
+
+// CHECK: define{{.+}} [[OFFL2]]()
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}}* [[OMP_OUTLINED_1:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} [[OMP_OUTLINED_1]](i32* {{.+}} [[GTID_IN:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = alloca i32*,
+// CHECK: store i32* [[GTID_IN]], i32** [[GTID_ADDR]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_ADDR]],
+// CHECK: [[GTID_VAL:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.*}}void @__kmpc_push_proc_bind([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID_VAL]], i32 3)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(
+// CHECK: ret void
+
+// CHECK: define{{.+}} [[TMAIN]]()
+// CHECK: call {{.*}}@__tgt_target_teams({{.+}})
+// CHECK: call void [[OFFL3:@.+]]()
+
+// CHECK: define{{.+}} [[OFFL3]]()
+// CHECK: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, {{.+}}, {{.+}}* [[OMP_OUTLINED_3:@.+]] to {{.+}})
+
+// CHECK: define{{.+}} [[OMP_OUTLINED_3]](i32* {{.+}} [[GTID_IN:%.+]],
+// CHECK: [[GTID_ADDR:%.+]] = alloca i32*,
+// CHECK: store i32* [[GTID_IN]], i32** [[GTID_ADDR]],
+// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_ADDR]],
+// CHECK: [[GTID_VAL:%.+]] = load i32, i32* [[GTID_REF]],
+// CHECK: call {{.*}}void @__kmpc_push_proc_bind([[IDENT_T_TY]]* [[DEF_LOC_2]], i32 [[GTID_VAL]], i32 2)
+// CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(
+// CHECK: ret void
+#endif
diff --git a/test/OpenMP/distribute_parallel_for_reduction_messages.cpp b/test/OpenMP/distribute_parallel_for_reduction_messages.cpp
index 95654a9e50..0bf1bc0472 100644
--- a/test/OpenMP/distribute_parallel_for_reduction_messages.cpp
+++ b/test/OpenMP/distribute_parallel_for_reduction_messages.cpp
@@ -27,9 +27,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp
index f865e0be42..2d99d7d8f4 100644
--- a/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp
+++ b/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp
@@ -134,9 +134,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target
diff --git a/test/OpenMP/distribute_parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/distribute_parallel_for_simd_lastprivate_messages.cpp
index 109fde0577..e54089d318 100644
--- a/test/OpenMP/distribute_parallel_for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/distribute_parallel_for_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/distribute_parallel_for_simd_loop_messages.cpp b/test/OpenMP/distribute_parallel_for_simd_loop_messages.cpp
index 6c322e6f60..1fedb3c02d 100644
--- a/test/OpenMP/distribute_parallel_for_simd_loop_messages.cpp
+++ b/test/OpenMP/distribute_parallel_for_simd_loop_messages.cpp
@@ -702,7 +702,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/distribute_parallel_for_simd_reduction_messages.cpp b/test/OpenMP/distribute_parallel_for_simd_reduction_messages.cpp
index 6ad41d72bf..94e4541b90 100644
--- a/test/OpenMP/distribute_parallel_for_simd_reduction_messages.cpp
+++ b/test/OpenMP/distribute_parallel_for_simd_reduction_messages.cpp
@@ -27,9 +27,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/distribute_private_messages.cpp b/test/OpenMP/distribute_private_messages.cpp
index 518b64d9e9..0aa1e47969 100644
--- a/test/OpenMP/distribute_private_messages.cpp
+++ b/test/OpenMP/distribute_private_messages.cpp
@@ -87,7 +87,7 @@ int main(int argc, char **argv) {
#pragma omp teams
{
int i; // expected-note {{predetermined as private}}
- #pragma omp distribute firstprivate(i), private(i) // expected-error {{private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'}}
+ #pragma omp distribute firstprivate(i) // expected-error {{firstprivate variable must be shared}}
for (int k = 0; k < argc; ++k) ++k;
}
#pragma omp target
diff --git a/test/OpenMP/distribute_simd_aligned_messages.cpp b/test/OpenMP/distribute_simd_aligned_messages.cpp
index 10beb7198a..21b1bc9da1 100644
--- a/test/OpenMP/distribute_simd_aligned_messages.cpp
+++ b/test/OpenMP/distribute_simd_aligned_messages.cpp
@@ -134,9 +134,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target
diff --git a/test/OpenMP/distribute_simd_lastprivate_messages.cpp b/test/OpenMP/distribute_simd_lastprivate_messages.cpp
index 0f96cb4c3e..a8914350bf 100644
--- a/test/OpenMP/distribute_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/distribute_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/distribute_simd_loop_messages.cpp b/test/OpenMP/distribute_simd_loop_messages.cpp
index b69005578f..59fafda45f 100644
--- a/test/OpenMP/distribute_simd_loop_messages.cpp
+++ b/test/OpenMP/distribute_simd_loop_messages.cpp
@@ -691,7 +691,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/distribute_simd_reduction_messages.cpp b/test/OpenMP/distribute_simd_reduction_messages.cpp
index fca3e85a71..ddedcb0892 100644
--- a/test/OpenMP/distribute_simd_reduction_messages.cpp
+++ b/test/OpenMP/distribute_simd_reduction_messages.cpp
@@ -27,9 +27,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/dump.cpp b/test/OpenMP/dump.cpp
index 378b53ce5b..5ec202cc30 100644
--- a/test/OpenMP/dump.cpp
+++ b/test/OpenMP/dump.cpp
@@ -52,11 +52,11 @@ struct S {
// CHECK-NEXT: | |-OMPScheduleClause {{.+}} <col:61, col:79>
// CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:78> 'int' <LValueToRValue>
// CHECK-NEXT: | | `-DeclRefExpr {{.+}} <col:78> 'int' lvalue OMPCapturedExpr {{.+}} '.capture_expr.' 'int'
-// CHECK-NEXT: | |-CapturedStmt {{.+}} <line:40:5, <invalid sloc>>
+// CHECK-NEXT: | |-CapturedStmt {{.+}} <line:40:5, line:41:9>
// CHECK-NEXT: | | |-CapturedDecl {{.+}} <<invalid sloc>> <invalid sloc>
-// CHECK-NEXT: | | | |-ForStmt {{.+}} <col:5, <invalid sloc>>
-// CHECK: | | | | `-UnaryOperator {{.+}} <line:41:7, <invalid sloc>> 'int' lvalue prefix '++'
-// CHECK-NEXT: | | | | `-DeclRefExpr {{.+}} <<invalid sloc>> 'int' lvalue OMPCapturedExpr {{.+}} 'a' 'int &'
+// CHECK-NEXT: | | | |-ForStmt {{.+}} <line:40:5, line:41:9>
+// CHECK: | | | | `-UnaryOperator {{.+}} <line:41:7, col:9> 'int' lvalue prefix '++'
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.+}} <col:9> 'int' lvalue OMPCapturedExpr {{.+}} 'a' 'int &'
#pragma omp declare simd
#pragma omp declare simd inbranch
diff --git a/test/OpenMP/for_codegen.cpp b/test/OpenMP/for_codegen.cpp
index b27bd7b1db..0d5972f7d0 100644
--- a/test/OpenMP/for_codegen.cpp
+++ b/test/OpenMP/for_codegen.cpp
@@ -11,6 +11,7 @@
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
// CHECK-DAG: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+// CHECK-DAG: [[LOOP_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 514, i32 0, i32 0, i8*
// CHECK-DAG: [[I:@.+]] = global i8 1,
// CHECK-DAG: [[J:@.+]] = global i8 2,
// CHECK-DAG: [[K:@.+]] = global i8 3,
@@ -19,7 +20,7 @@
void without_schedule_clause(float *a, float *b, float *c, float *d) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
#pragma omp for nowait
-// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
// UB = min(UB, GlobalUB)
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
@@ -51,7 +52,7 @@ void without_schedule_clause(float *a, float *b, float *c, float *d) {
// CHECK-NEXT: br label %{{.+}}
}
// CHECK: [[LOOP1_END]]
-// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]])
// CHECK-NOT: __kmpc_barrier
// CHECK: ret void
}
@@ -60,7 +61,7 @@ void without_schedule_clause(float *a, float *b, float *c, float *d) {
void static_not_chunked(float *a, float *b, float *c, float *d) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
#pragma omp for schedule(static)
-// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
// UB = min(UB, GlobalUB)
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
@@ -92,7 +93,7 @@ void static_not_chunked(float *a, float *b, float *c, float *d) {
// CHECK-NEXT: br label %{{.+}}
}
// CHECK: [[LOOP1_END]]
-// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]])
// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -101,7 +102,7 @@ void static_not_chunked(float *a, float *b, float *c, float *d) {
void static_chunked(float *a, float *b, float *c, float *d) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]])
#pragma omp for schedule(monotonic: static, 5)
-// CHECK: call void @__kmpc_for_static_init_4u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 536870945, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 5)
+// CHECK: call void @__kmpc_for_static_init_4u([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]], i32 536870945, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 5)
// UB = min(UB, GlobalUB)
// CHECK: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
// CHECK-NEXT: [[UBCMP:%.+]] = icmp ugt i32 [[UB]], 16908288
@@ -152,7 +153,7 @@ void static_chunked(float *a, float *b, float *c, float *d) {
// CHECK-NEXT: store i32 [[ADD_UB]], i32* [[OMP_UB]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]])
// CHECK: call {{.+}} @__kmpc_barrier([[IDENT_T_TY]]* [[IMPLICIT_BARRIER_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -354,7 +355,7 @@ int foo() {return 0;};
void parallel_for(float *a) {
#pragma omp parallel
#pragma omp for schedule(static, 5)
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: call void @__kmpc_for_static_init_4u({{.+}}), !dbg [[DBG_LOC_START:![0-9]+]]
// TERM_DEBUG: invoke i32 {{.*}}foo{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
@@ -484,6 +485,18 @@ void loop_with_It(It<char> begin, It<char> end) {
// CHECK: call void @__kmpc_for_static_init_8(
// CHECK: call void @__kmpc_for_static_fini(
+void loop_with_It_plus(It<char> begin, It<char> end) {
+#pragma omp for
+ for (It<char> it = begin; it < end; it+=1u) {
+ *it = 0;
+ }
+}
+
+// CHECK-LABEL: loop_with_It_plus
+// CHECK: call i32 @__kmpc_global_thread_num(
+// CHECK: call void @__kmpc_for_static_init_8(
+// CHECK: call void @__kmpc_for_static_fini(
+
void loop_with_stmt_expr() {
#pragma omp for
for (int i = __extension__({float b = 0;b; }); i < __extension__({double c = 1;c; }); i += __extension__({char d = 1; d; }))
diff --git a/test/OpenMP/for_firstprivate_codegen.cpp b/test/OpenMP/for_firstprivate_codegen.cpp
index 1e1d404b48..590739203f 100644
--- a/test/OpenMP/for_firstprivate_codegen.cpp
+++ b/test/OpenMP/for_firstprivate_codegen.cpp
@@ -83,6 +83,7 @@ int main() {
// LAMBDA: alloca i{{[0-9]+}},
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
// LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G1_PRIVATE_REF:%.+]] = alloca i{{[0-9]+}}*,
// LAMBDA: [[SIVAR2_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
// LAMBDA: store i{{[0-9]+}}* [[SIVAR_REF]], i{{[0-9]+}}** %{{.+}},
@@ -91,20 +92,26 @@ int main() {
// LAMBDA: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}, i{{[0-9]+}}* [[G]]
// LAMBDA: store i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]]
+ // LAMBDA: store i{{[0-9]+}}* [[G1_PRIVATE_ADDR]], i{{[0-9]+}}** [[G1_PRIVATE_REF]],
// LAMBDA: [[SIVAR2_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIVAR2_PRIVATE_ADDR_REF]]
// LAMBDA: store i{{[0-9]+}} [[SIVAR2_VAL]], i{{[0-9]+}}* [[SIVAR2_PRIVATE_ADDR]]
// LAMBDA-NOT: call void @__kmpc_barrier(
g = 1;
- g1 = 1;
- sivar = 2;
+ g1 = 2;
+ sivar = 3;
// LAMBDA: call void @__kmpc_for_static_init_4(
// LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
- // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[SIVAR2_PRIVATE_ADDR]],
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PRIVATE_REF]],
+ // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G1_PRIVATE_ADDR]],
+ // LAMBDA: store i{{[0-9]+}} 3, i{{[0-9]+}}* [[SIVAR2_PRIVATE_ADDR]],
// LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
- // LAMBDA: [[SIVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PRIVATE_REF]],
+ // LAMBDA: store i{{[0-9]+}}* [[G1_PRIVATE_ADDR]], i{{[0-9]+}}** [[G1_PRIVATE_ADDR_REF]]
+ // LAMBDA: [[SIVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// LAMBDA: store i{{[0-9]+}}* [[SIVAR2_PRIVATE_ADDR]], i{{[0-9]+}}** [[SIVAR_PRIVATE_ADDR_REF]]
// LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
// LAMBDA: call void @__kmpc_for_static_fini(
@@ -112,17 +119,20 @@ int main() {
[&]() {
// LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
// LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
- g = 2;
- g1 = 2;
- sivar = 4;
+ g = 4;
+ g1 = 5;
+ sivar = 6;
// LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
// LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]]
- // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
- // LAMBDA: [[SIVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[G_REF]]
+ // LAMBDA: [[G1_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 5, i{{[0-9]+}}* [[G1_REF]]
+ // LAMBDA: [[SIVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// LAMBDA: [[SIVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SIVAR_PTR_REF]]
- // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SIVAR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 6, i{{[0-9]+}}* [[SIVAR_REF]]
}();
}
}();
diff --git a/test/OpenMP/for_lastprivate_codegen.cpp b/test/OpenMP/for_lastprivate_codegen.cpp
index f0fba042c5..47c24ed102 100644
--- a/test/OpenMP/for_lastprivate_codegen.cpp
+++ b/test/OpenMP/for_lastprivate_codegen.cpp
@@ -246,6 +246,7 @@ int main() {
// LAMBDA: alloca i{{[0-9]+}},
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, align 128
// LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G1_PRIVATE_REF:%.+]] = alloca i{{[0-9]+}}*,
// LAMBDA: [[SIVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
// LAMBDA: [[SIVAR_PRIVATE_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %{{.+}},
@@ -254,10 +255,15 @@ int main() {
// LAMBDA: call {{.+}} @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_ADDR:%.+]], i32* %{{.+}}, i32* %{{.+}}, i32* %{{.+}}, i32 1, i32 1)
// LAMBDA: store i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PRIVATE_REF]],
+ // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G1_PRIVATE_ADDR]],
// LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[SIVAR_PRIVATE_ADDR]],
// LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]]
- // LAMBDA: [[SIVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PRIVATE_REF]],
+ // LAMBDA: store i{{[0-9]+}}* [[G1_PRIVATE_ADDR]], i{{[0-9]+}}** [[G1_PRIVATE_ADDR_REF]]
+ // LAMBDA: [[SIVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// LAMBDA: store i{{[0-9]+}}* [[SIVAR_PRIVATE_ADDR]], i{{[0-9]+}}** [[SIVAR_PRIVATE_ADDR_REF]]
// LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
// LAMBDA: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
@@ -291,7 +297,10 @@ int main() {
// LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]]
// LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
- // LAMBDA: [[SIVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G1_REF]]
+ // LAMBDA: [[SIVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// LAMBDA: [[SIVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SIVAR_PTR_REF]]
// LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SIVAR_REF]]
}();
diff --git a/test/OpenMP/for_lastprivate_messages.cpp b/test/OpenMP/for_lastprivate_messages.cpp
index 79912b6efb..13ef35e925 100644
--- a/test/OpenMP/for_lastprivate_messages.cpp
+++ b/test/OpenMP/for_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/for_linear_codegen.cpp b/test/OpenMP/for_linear_codegen.cpp
index acadccbce3..16a67c0b91 100644
--- a/test/OpenMP/for_linear_codegen.cpp
+++ b/test/OpenMP/for_linear_codegen.cpp
@@ -422,6 +422,7 @@ int main() {
// CHECK: [[A_PRIV:%.+]] = alloca i{{[0-9]+}},
// CHECK: [[B_PRIV:%.+]] = alloca i{{[0-9]+}},
// CHECK: [[C_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: call void @__kmpc_barrier(
// CHECK: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]],
// CHECK: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]],
// CHECK: call void @__kmpc_for_static_init_4(
diff --git a/test/OpenMP/for_loop_messages.cpp b/test/OpenMP/for_loop_messages.cpp
index bb58a77e5a..01cc6020b8 100644
--- a/test/OpenMP/for_loop_messages.cpp
+++ b/test/OpenMP/for_loop_messages.cpp
@@ -660,7 +660,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/for_private_codegen.cpp b/test/OpenMP/for_private_codegen.cpp
index 5bad8d0068..f1416d75b6 100644
--- a/test/OpenMP/for_private_codegen.cpp
+++ b/test/OpenMP/for_private_codegen.cpp
@@ -52,6 +52,8 @@ int main() {
for (int i = 0; i < 2; ++i) {
// LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* noalias %{{.+}}, i32* noalias %{{.+}})
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE_REF:%.+]] = alloca double*,
// LAMBDA: [[SVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
// LAMBDA: [[SFVAR_PRIVATE_ADDR:%.+]] = alloca float,
g = 1;
@@ -60,13 +62,18 @@ int main() {
sfvar = 4.0;
// LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
// LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = load double*, double** [[G1_PRIVATE_REF]],
+ // LAMBDA: store volatile double 1.0{{.+}}, double* [[G1_PRIVATE_ADDR]],
// LAMBDA: store i{{[0-9]+}} 3, i{{[0-9]+}}* [[SVAR_PRIVATE_ADDR]],
// LAMBDA: store float 4.0{{.+}}, float* [[SFVAR_PRIVATE_ADDR]],
// LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: store double* [[G_PRIVATE_ADDR]], double** [[G_PRIVATE_ADDR_REF]]
- // LAMBDA: [[SVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = load double*, double** [[G1_PRIVATE_REF]],
+ // LAMBDA: store double* [[G1_PRIVATE_ADDR]], double** [[G1_PRIVATE_ADDR_REF]]
+ // LAMBDA: [[SVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// LAMBDA: store i{{[0-9]+}}* [[SVAR_PRIVATE_ADDR]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR_REF]]
- // LAMBDA: [[SFVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
// LAMBDA: store float* [[SFVAR_PRIVATE_ADDR]], float** [[SFVAR_PRIVATE_ADDR_REF]]
// LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
// LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
@@ -81,10 +88,13 @@ int main() {
// LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]]
// LAMBDA: store double 2.0{{.+}}, double* [[G_REF]]
- // LAMBDA: [[SVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load double*, double** [[G1_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G1_REF]]
+ // LAMBDA: [[SVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// LAMBDA: [[SVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PTR_REF]]
// LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SVAR_REF]]
- // LAMBDA: [[SFVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SFVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
// LAMBDA: [[SFVAR_REF:%.+]] = load float*, float** [[SFVAR_PTR_REF]]
// LAMBDA: store float 8.0{{.+}}, float* [[SFVAR_REF]]
}();
diff --git a/test/OpenMP/for_reduction_codegen.cpp b/test/OpenMP/for_reduction_codegen.cpp
index 274546b065..ac4c6ffcac 100644
--- a/test/OpenMP/for_reduction_codegen.cpp
+++ b/test/OpenMP/for_reduction_codegen.cpp
@@ -27,7 +27,7 @@ struct S {
// CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer
-template <typename T>
+template <typename T, int length>
T tmain() {
T t;
S<T> test;
@@ -36,6 +36,7 @@ T tmain() {
S<T> s_arr[] = {1, 2};
S<T> &var = test;
S<T> var1;
+ S<T> arr[length];
#pragma omp parallel
#pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) nowait
for (int i = 0; i < 2; ++i) {
@@ -48,6 +49,12 @@ T tmain() {
vec[i] = t_var;
s_arr[i] = var;
}
+#pragma omp parallel
+#pragma omp for reduction(+ : arr[1:length-2])
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
return T();
}
@@ -180,12 +187,12 @@ int main() {
S<float> test;
float t_var = 0, t_var1;
int vec[] = {1, 2};
- S<float> s_arr[] = {1, 2};
+ S<float> s_arr[] = {1, 2, 3, 4};
S<float> &var = test;
S<float> var1, arrs[10][4];
S<float> **var2 = foo();
- S<float> vvar2[2];
- S<float> (&var3)[2] = s_arr;
+ S<float> vvar2[5];
+ S<float> (&var3)[4] = s_arr;
#pragma omp parallel
#pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1)
for (int i = 0; i < 2; ++i) {
@@ -205,6 +212,18 @@ int main() {
for (int i = 0; i < 10; ++i)
;
#pragma omp parallel
+#pragma omp for reduction(& : var2[1][1 : 6])
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for reduction(& : var2[1 : 1][1 : 6])
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
+#pragma omp for reduction(& : var2[1 : 1][1])
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
#pragma omp for reduction(& : vvar2[0 : 5])
for (int i = 0; i < 10; ++i)
;
@@ -213,28 +232,42 @@ int main() {
for (int i = 0; i < 10; ++i)
;
#pragma omp parallel
+#pragma omp for reduction(& : var3[ : 2])
+ for (int i = 0; i < 10; ++i)
+ ;
+ // TODO: The compiler should also be able to generate a constant sized array in this case!
+#pragma omp parallel
+#pragma omp for reduction(& : var3[2 : ])
+ for (int i = 0; i < 10; ++i)
+ ;
+#pragma omp parallel
#pragma omp for reduction(& : var3)
for (int i = 0; i < 10; ++i)
;
- return tmain<int>();
+ return tmain<int, 42>();
#endif
}
// CHECK: define {{.*}}i{{[0-9]+}} @main()
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void
-// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK4:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK5:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK6:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK7:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK8:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK9:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK10:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK11:@.+]] to void
+// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]()
// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
// CHECK: ret
//
-// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}})
// CHECK: [[T_VAR_PRIV:%.+]] = alloca float,
// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
@@ -491,21 +524,18 @@ int main() {
// CHECK: store float [[UP]], float* [[T_VAR1_LHS]],
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}})
// Reduction list for runtime.
// CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: store i{{[0-9]+}}* %{{.+}}, i{{[0-9]+}}**
+// CHECK: store i{{[0-9]+}}* %{{.+}}, i{{[0-9]+}}** [[ARR_ADDR:%.+]],
+// CHECK: [[ARR:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[ARR_ADDR]],
-// CHECK: [[IDX1:%.+]] = mul nsw i64 1, %{{.+}}
-// CHECK: [[LB1:%.+]] = getelementptr inbounds i32, i32* %{{.+}}, i64 [[IDX1]]
-// CHECK: [[LB1_0:%.+]] = getelementptr inbounds i32, i32* [[LB1]], i64 0
-// CHECK: [[IDX1:%.+]] = mul nsw i64 1, %{{.+}}
-// CHECK: [[UB1:%.+]] = getelementptr inbounds i32, i32* %{{.+}}, i64 [[IDX1]]
-// CHECK: [[UB1_UP:%.+]] = getelementptr inbounds i32, i32* [[UB1]], i64 %
-// CHECK: [[UB_CAST:%.+]] = ptrtoint i32* [[UB1_UP]] to i64
-// CHECK: [[LB_CAST:%.+]] = ptrtoint i32* [[LB1_0]] to i64
+// CHECK: [[UB_CAST:%.+]] = ptrtoint i32* [[UB1_UP:%.+]] to i64
+// CHECK: [[LB_CAST:%.+]] = ptrtoint i32* [[LB1_0:%.+]] to i64
// CHECK: [[DIFF:%.+]] = sub i64 [[UB_CAST]], [[LB_CAST]]
// CHECK: [[SIZE_1:%.+]] = sdiv exact i64 [[DIFF]], ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64)
// CHECK: [[ARR_SIZE:%.+]] = add nuw i64 [[SIZE_1]], 1
@@ -695,7 +725,7 @@ int main() {
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}})
// CHECK: [[ARRS_PRIV:%.+]] = alloca [10 x [4 x [[S_FLOAT_TY]]]],
@@ -704,7 +734,7 @@ int main() {
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
-// CHECK: [[ARR_SIZE:%.+]] = mul nuw i64 %{{.+}}, 4
+// CHECK: [[ARR_SIZE:%.+]] = udiv exact i64
// CHECK: call i8* @llvm.stacksave()
// CHECK: [[ARR_PRIV:%.+]] = alloca i32, i64 [[ARR_SIZE]],
@@ -718,7 +748,6 @@ int main() {
// CHECK: br i1 [[DONE]],
// Check initialization of private copy.
-// CHECK: [[LHS_BEGIN:%.+]] = bitcast [10 x [4 x [[S_FLOAT_TY]]]]* %{{.+}} to [[S_FLOAT_TY]]*
// CHECK: [[BEGIN:%.+]] = getelementptr inbounds [10 x [4 x [[S_FLOAT_TY]]]], [10 x [4 x [[S_FLOAT_TY]]]]* [[ARRS_PRIV]], i32 0, i32 0, i32 0
// CHECK: [[END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[BEGIN]], i64 40
// CHECK: [[ISEMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[BEGIN]], [[END]]
@@ -727,6 +756,7 @@ int main() {
// CHECK: call void @_ZN1SIfEC1Ev([[S_FLOAT_TY]]* %
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[END]]
// CHECK: br i1 [[DONE]],
+// CHECK: [[LHS_BEGIN:%.+]] = bitcast [10 x [4 x [[S_FLOAT_TY]]]]* %{{.+}} to [[S_FLOAT_TY]]*
// CHECK: [[ARRS_PRIV_BEGIN:%.+]] = bitcast [10 x [4 x [[S_FLOAT_TY]]]]* [[ARRS_PRIV]] to [[S_FLOAT_TY]]*
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
@@ -895,23 +925,15 @@ int main() {
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]],
-// CHECK: load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
-// CHECK: getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %{{.+}}, i64 0
-// CHECK: load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %
-// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 1
-// CHECK: load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
-// CHECK: getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %{{.+}}, i64 4
-// CHECK: load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %
-// CHECK: getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 6
-// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
-// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]],
// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64
-// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64
// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]]
// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1
// CHECK: call i8* @llvm.stacksave()
// CHECK: [[VAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]],
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]],
// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
@@ -921,94 +943,231 @@ int main() {
// CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]]
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}})
-// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***,
+// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]],
// Reduction list for runtime.
-// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*],
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
-// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]],
+// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]],
-// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0
-// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 4
-// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]*
-// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64
-// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
-// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]]
-// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
-// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1
-// CHECK: call i8* @llvm.stacksave()
-// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]],
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]],
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]],
// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
-// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]]
-// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]*
+// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]]
+// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** %
+// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]*
+// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]]
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}})
-// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***,
+// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]],
// Reduction list for runtime.
-// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*],
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]],
+
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]],
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]],
+// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
+// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
+// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]]
+// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** %
+// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]*
+// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]]
+// CHECK: ret void
+
+// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}})
+
+// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***,
+// CHECK: [[VAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]],
+
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]],
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]],
+// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
+// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
+// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR2_PRIV]], i64 [[OFFSET]]
+// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** %
+// CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]]
+// CHECK: ret void
+
+// CHECK: define internal void [[MAIN_MICROTASK7]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(20) %{{.+}})
+
+// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]],
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]],
+
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0
+// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]*
+// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
+// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
+// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]]
+// CHECK: ret void
+
+// CHECK: define internal void [[MAIN_MICROTASK8]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}})
+
+// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
+// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
+// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
+// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]]
+// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]*
+
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** %
+
+// CHECK: ret void
+
+// CHECK: define internal void [[MAIN_MICROTASK9]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}})
+
+// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 0
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
+// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
+// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
+// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]]
+// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]*
+
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** %
+
+// CHECK: ret void
+
+// CHECK: define internal void [[MAIN_MICROTASK10]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}})
+
+// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*,
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*],
+
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 2
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64
-// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64
// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]]
// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1
// CHECK: call i8* @llvm.stacksave()
// CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]]
-// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]*
+// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]*
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** %
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** %
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK11]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}})
-// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
-// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]],
// Reduction list for runtime.
// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
-// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0
-// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0
+// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** %
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** %
+// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
// CHECK: ret void
-// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]()
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// Not interested in this one:
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4,
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void
// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
// CHECK: ret
//
@@ -1242,5 +1401,27 @@ int main() {
// CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_LHS]],
// CHECK: ret void
+// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(168) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(8) %{{.*}}, [[S_INT_TY]]* dereferenceable(4) %{{.*}})
+
+// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*,
+// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]],
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]],
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1
+// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]*
+// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64
+// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64
+// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
+// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64)
+// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]]
+// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]*
+
+// CHECK: ret void
+
#endif
diff --git a/test/OpenMP/for_reduction_codegen_UDR.cpp b/test/OpenMP/for_reduction_codegen_UDR.cpp
index 699e06dda8..f5ec656048 100644
--- a/test/OpenMP/for_reduction_codegen_UDR.cpp
+++ b/test/OpenMP/for_reduction_codegen_UDR.cpp
@@ -40,7 +40,7 @@ void init_plus(BaseS1&, const BaseS1&);
// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer
#pragma omp declare reduction(operator&& : int : omp_out = 111 & omp_in)
-template <typename T>
+template <typename T, int length>
T tmain() {
T t;
S<T> test;
@@ -49,6 +49,7 @@ T tmain() {
S<T> s_arr[] = {1, 2};
S<T> &var = test;
S<T> var1;
+ S<T> arr[length];
#pragma omp declare reduction(operator& : T : omp_out = 15 + omp_in)
#pragma omp declare reduction(operator+ : T : omp_out = 1513 + omp_in) initializer(omp_priv = 321)
#pragma omp declare reduction(min : T : omp_out = 47 - omp_in) initializer(omp_priv = 432 / omp_orig)
@@ -66,6 +67,12 @@ T tmain() {
vec[i] = t_var;
s_arr[i] = var;
}
+#pragma omp parallel
+#pragma omp for reduction(+ : arr[1:length-2])
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
return T();
}
@@ -78,12 +85,12 @@ int main() {
S<float> test;
float t_var = 0, t_var1;
int vec[] = {1, 2};
- S<float> s_arr[] = {1, 2};
+ S<float> s_arr[] = {1, 2, 3, 4};
S<float> &var = test;
S<float> var1, arrs[10][4];
S<float> **var2 = foo();
- S<float> vvar2[2];
- S<float>(&var3)[2] = s_arr;
+ S<float> vvar2[5];
+ S<float>(&var3)[4] = s_arr;
#pragma omp declare reduction(operator+ : int : omp_out = 555 * omp_in) initializer(omp_priv = 888)
#pragma omp parallel
#pragma omp for reduction(+ : t_var) reduction(& : var) reduction(&& : var1) reduction(min : t_var1)
@@ -115,24 +122,24 @@ int main() {
#pragma omp for reduction(& : var3)
for (int i = 0; i < 10; ++i)
;
- return tmain<int>();
+ return tmain<int, 42>();
}
// CHECK: define {{.*}}i{{[0-9]+}} @main()
// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void
-// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void
-// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void
+// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]()
// CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
// CHECK: ret
//
-// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}})
// CHECK: [[T_VAR_PRIV:%.+]] = alloca float,
// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
// CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
@@ -300,21 +307,18 @@ int main() {
// CHECK: fadd float 5.550000e+02, %
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}})
// Reduction list for runtime.
// CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+// CHECK: store i{{[0-9]+}}* %{{.+}}, i{{[0-9]+}}**
+// CHECK: store i{{[0-9]+}}* %{{.+}}, i{{[0-9]+}}** [[ARR_ADDR:%.+]],
+// CHECK: [[ARR:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[ARR_ADDR]],
-// CHECK: [[IDX1:%.+]] = mul nsw i64 1, %{{.+}}
-// CHECK: [[LB1:%.+]] = getelementptr inbounds i32, i32* %{{.+}}, i64 [[IDX1]]
-// CHECK: [[LB1_0:%.+]] = getelementptr inbounds i32, i32* [[LB1]], i64 0
-// CHECK: [[IDX1:%.+]] = mul nsw i64 1, %{{.+}}
-// CHECK: [[UB1:%.+]] = getelementptr inbounds i32, i32* %{{.+}}, i64 [[IDX1]]
-// CHECK: [[UB1_UP:%.+]] = getelementptr inbounds i32, i32* [[UB1]], i64 %
-// CHECK: [[UB_CAST:%.+]] = ptrtoint i32* [[UB1_UP]] to i64
-// CHECK: [[LB_CAST:%.+]] = ptrtoint i32* [[LB1_0]] to i64
+// CHECK: [[UB_CAST:%.+]] = ptrtoint i32* [[UB1_UP:%.+]] to i64
+// CHECK: [[LB_CAST:%.+]] = ptrtoint i32* [[LB1_0:%.+]] to i64
// CHECK: [[DIFF:%.+]] = sub i64 [[UB_CAST]], [[LB_CAST]]
// CHECK: [[SIZE_1:%.+]] = sdiv exact i64 [[DIFF]], ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64)
// CHECK: [[ARR_SIZE:%.+]] = add nuw i64 [[SIZE_1]], 1
@@ -499,7 +503,7 @@ int main() {
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}})
// CHECK: [[ARRS_PRIV:%.+]] = alloca [10 x [4 x [[S_FLOAT_TY]]]],
@@ -508,7 +512,7 @@ int main() {
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
-// CHECK: [[ARR_SIZE:%.+]] = mul nuw i64 %{{.+}}, 4
+// CHECK: [[ARR_SIZE:%.+]] = udiv exact i64
// CHECK: call i8* @llvm.stacksave()
// CHECK: [[ARR_PRIV:%.+]] = alloca i32, i64 [[ARR_SIZE]],
@@ -522,8 +526,8 @@ int main() {
// CHECK: br i1 [[DONE]],
// Check initialization of private copy.
-// CHECK: [[LHS_BEGIN:%.+]] = bitcast [10 x [4 x [[S_FLOAT_TY]]]]* %{{.+}} to [[S_FLOAT_TY]]*
// CHECK: [[BEGIN:%.+]] = getelementptr inbounds [10 x [4 x [[S_FLOAT_TY]]]], [10 x [4 x [[S_FLOAT_TY]]]]* [[ARRS_PRIV]], i32 0, i32 0, i32 0
+// CHECK: [[LHS_BEGIN:%.+]] = bitcast [10 x [4 x [[S_FLOAT_TY]]]]* %{{.+}} to [[S_FLOAT_TY]]*
// CHECK: [[END:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[BEGIN]], i64 40
// CHECK: [[ISEMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[BEGIN]], [[END]]
// CHECK: br i1 [[ISEMPTY]],
@@ -531,6 +535,7 @@ int main() {
// CHECK: call void @_Z4initR6BaseS1RKS_(%
// CHECK: [[DONE:%.+]] = icmp eq [[S_FLOAT_TY]]* %{{.+}}, [[END]]
// CHECK: br i1 [[DONE]],
+// CHECK: [[LHS_BEGIN:%.+]] = bitcast [10 x [4 x [[S_FLOAT_TY]]]]* %{{.+}} to [[S_FLOAT_TY]]*
// CHECK: [[ARRS_PRIV_BEGIN:%.+]] = bitcast [10 x [4 x [[S_FLOAT_TY]]]]* [[ARRS_PRIV]] to [[S_FLOAT_TY]]*
// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[GTID_ADDR_ADDR]]
@@ -695,23 +700,15 @@ int main() {
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]],
-// CHECK: load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
-// CHECK: getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %{{.+}}, i64 0
-// CHECK: load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %
-// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 1
-// CHECK: load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
-// CHECK: getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %{{.+}}, i64 4
-// CHECK: load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** %
-// CHECK: getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 6
-// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
-// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]],
// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64
-// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
+// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64
// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]]
// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64)
// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1
// CHECK: call i8* @llvm.stacksave()
// CHECK: [[VAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]],
+// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]],
+// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]],
// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
@@ -721,94 +718,85 @@ int main() {
// CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]]
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(60) %{{.+}})
-// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]],
// Reduction list for runtime.
-// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*],
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
-// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]],
+// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]],
-// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0
-// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 4
-// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]*
-// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64
-// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
-// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]]
-// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64)
-// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1
-// CHECK: call i8* @llvm.stacksave()
-// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]],
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0
+// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]*
// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64)
-// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]]
-// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]*
+// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]]
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}})
-// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
// Reduction list for runtime.
-// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*],
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 2
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
-// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64
-// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
-// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]]
-// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64)
-// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1
-// CHECK: call i8* @llvm.stacksave()
-// CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64
// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64
// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64)
-// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]]
-// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]*
+// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]]
+// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]*
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** %
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** %
// CHECK: ret void
-// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}})
+// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}})
-// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
-// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]],
// Reduction list for runtime.
// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
-// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
-// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
-// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0
-// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]],
+// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]],
+// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0
+// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]*
+// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4
-// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** %
+// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** %
// CHECK: ret void
-// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]()
// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
// CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// Not interested in this one:
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4,
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void
+// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
// CHECK: ret
//
@@ -979,5 +967,27 @@ int main() {
// CHECK: sub nsw i32 47, %
// CHECK: ret void
+// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(504) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(24) %{{.*}}, [[S_INT_TY]]* dereferenceable(12) %{{.*}})
+
+// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*,
+// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]],
+
+// Reduction list for runtime.
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*],
+
+// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]],
+
+// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]],
+// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1
+// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]*
+// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64
+// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64
+// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]]
+// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_INT_TY]]* getelementptr ([[S_INT_TY]], [[S_INT_TY]]* null, i32 1) to i64)
+// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]]
+// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]*
+
+// CHECK: ret void
+
#endif
diff --git a/test/OpenMP/for_reduction_messages.cpp b/test/OpenMP/for_reduction_messages.cpp
index bb70ecc2b2..d4f4a795fe 100644
--- a/test/OpenMP/for_reduction_messages.cpp
+++ b/test/OpenMP/for_reduction_messages.cpp
@@ -26,9 +26,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/for_simd_aligned_messages.cpp b/test/OpenMP/for_simd_aligned_messages.cpp
index 1d0918e449..3ff25870e5 100644
--- a/test/OpenMP/for_simd_aligned_messages.cpp
+++ b/test/OpenMP/for_simd_aligned_messages.cpp
@@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp for simd aligned // expected-error {{expected '(' after 'aligned'}}
for (I k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/for_simd_codegen.cpp b/test/OpenMP/for_simd_codegen.cpp
index 89f779db33..e33bfe4a57 100644
--- a/test/OpenMP/for_simd_codegen.cpp
+++ b/test/OpenMP/for_simd_codegen.cpp
@@ -673,7 +673,7 @@ int bar() {return 0;};
void parallel_simd(float *a) {
#pragma omp parallel
#pragma omp for simd
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: invoke i32 {{.*}}bar{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
// TERM_DEBUG-NOT: __kmpc_global_thread_num
diff --git a/test/OpenMP/for_simd_lastprivate_messages.cpp b/test/OpenMP/for_simd_lastprivate_messages.cpp
index d48c07d92b..a176a2d70e 100644
--- a/test/OpenMP/for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/for_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
S2 &operator =(const S2&);
const S2 &operator =(const S2&) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/for_simd_loop_messages.cpp b/test/OpenMP/for_simd_loop_messages.cpp
index e9729a8fc2..ea17a836cf 100644
--- a/test/OpenMP/for_simd_loop_messages.cpp
+++ b/test/OpenMP/for_simd_loop_messages.cpp
@@ -624,7 +624,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/for_simd_reduction_messages.cpp b/test/OpenMP/for_simd_reduction_messages.cpp
index 485070e758..a77ab754ef 100644
--- a/test/OpenMP/for_simd_reduction_messages.cpp
+++ b/test/OpenMP/for_simd_reduction_messages.cpp
@@ -26,9 +26,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/is_initial_device.c b/test/OpenMP/is_initial_device.c
new file mode 100644
index 0000000000..0521f0bd53
--- /dev/null
+++ b/test/OpenMP/is_initial_device.c
@@ -0,0 +1,36 @@
+// REQUIRES: powerpc-registered-target
+
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-unknown-unknown \
+// RUN: -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -verify -fopenmp -x ir -triple powerpc64le-unknown-unknown -emit-llvm \
+// RUN: %t-ppc-host.bc -o - | FileCheck %s -check-prefixes HOST,OUTLINED
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple powerpc64le-unknown-unknown -emit-llvm -fopenmp-is-device \
+// RUN: %s -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -check-prefixes DEVICE,OUTLINED
+
+// expected-no-diagnostics
+int check() {
+ int host = omp_is_initial_device();
+ int device;
+#pragma omp target map(tofrom: device)
+ {
+ device = omp_is_initial_device();
+ }
+
+ return host + device;
+}
+
+// The host should get a value of 1:
+// HOST: define{{.*}} @check()
+// HOST: [[HOST:%.*]] = alloca i32
+// HOST: store i32 1, i32* [[HOST]]
+
+// OUTLINED: define{{.*}} @{{.*}}omp_offloading{{.*}}(i32*{{.*}} [[DEVICE_ARGUMENT:%.*]])
+// OUTLINED: [[DEVICE_ADDR_STORAGE:%.*]] = alloca i32*
+// OUTLINED: store i32* [[DEVICE_ARGUMENT]], i32** [[DEVICE_ADDR_STORAGE]]
+// OUTLINED: [[DEVICE_ADDR:%.*]] = load i32*, i32** [[DEVICE_ADDR_STORAGE]]
+
+// The outlined function that is called as fallback also runs on the host:
+// HOST: store i32 1, i32* [[DEVICE_ADDR]]
+
+// The device should get a value of 0:
+// DEVICE: store i32 0, i32* [[DEVICE_ADDR]]
diff --git a/test/OpenMP/master_codegen.cpp b/test/OpenMP/master_codegen.cpp
index ad92a13e14..d61b476756 100644
--- a/test/OpenMP/master_codegen.cpp
+++ b/test/OpenMP/master_codegen.cpp
@@ -49,7 +49,7 @@ int main() {
void parallel_master() {
#pragma omp parallel
#pragma omp master
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: call i32 @__kmpc_master({{.+}}), !dbg [[DBG_LOC_START:![0-9]+]]
// TERM_DEBUG: invoke void {{.*}}foo{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
diff --git a/test/OpenMP/nvptx_param_translate.c b/test/OpenMP/nvptx_param_translate.c
new file mode 100644
index 0000000000..ec123ce381
--- /dev/null
+++ b/test/OpenMP/nvptx_param_translate.c
@@ -0,0 +1,19 @@
+// 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
+// expected-no-diagnostics
+
+// CHECK: [[MAP_FN:%.+]] = load void (i8*, ...)*, void (i8*, ...)** %
+// CHECK: call void (i8*, ...) [[MAP_FN]](i8* %
+int main() {
+ double a, b;
+
+#pragma omp target map(tofrom \
+ : a) map(to \
+ : b)
+ {
+#pragma omp taskgroup
+#pragma omp task shared(a)
+ a = b;
+ }
+ return 0;
+}
diff --git a/test/OpenMP/nvptx_target_codegen.cpp b/test/OpenMP/nvptx_target_codegen.cpp
index dab0c5a082..d7ce7dc7d1 100644
--- a/test/OpenMP/nvptx_target_codegen.cpp
+++ b/test/OpenMP/nvptx_target_codegen.cpp
@@ -9,12 +9,14 @@
#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
+// CHECK-DAG: {{@__omp_offloading_.+l100}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l177}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l287}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l324}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l342}}_exec_mode = weak constant i8 1
+// CHECK-DAG: {{@__omp_offloading_.+l307}}_exec_mode = weak constant i8 1
+
+__thread int id;
template<typename tx, typename ty>
struct TT{
@@ -31,7 +33,7 @@ int foo(int n) {
double cn[5][n];
TT<long long, char> d;
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l98}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l100}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -62,7 +64,7 @@ int foo(int n) {
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T1:@__omp_offloading_.+foo.+l98]]()
+ // CHECK: define {{.*}}void [[T1:@__omp_offloading_.+foo.+l100]]()
// 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()
@@ -104,7 +106,7 @@ int foo(int n) {
{
}
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l175}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l177}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -135,7 +137,7 @@ int foo(int n) {
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T2:@__omp_offloading_.+foo.+l175]](i[[SZ:32|64]] [[ARG1:%[a-zA-Z_]+]])
+ // CHECK: define {{.*}}void [[T2:@__omp_offloading_.+foo.+l177]](i[[SZ:32|64]] [[ARG1:%[a-zA-Z_]+]], i[[SZ:32|64]] [[ID:%[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*
@@ -175,9 +177,10 @@ int foo(int n) {
#pragma omp target if(1)
{
aa += 1;
+ id = aa;
}
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l284}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+foo.+l287}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -208,7 +211,7 @@ int foo(int n) {
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T3:@__omp_offloading_.+foo.+l284]](i[[SZ]]
+ // CHECK: define {{.*}}void [[T3:@__omp_offloading_.+foo.+l287]](i[[SZ]]
// Create local storage for each capture.
// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
// CHECK: [[LOCAL_B:%.+]] = alloca [10 x float]*
@@ -361,7 +364,7 @@ int bar(int n){
return a;
}
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+static.+321}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+static.+324}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -392,7 +395,7 @@ int bar(int n){
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T4:@__omp_offloading_.+static.+l321]](i[[SZ]]
+ // CHECK: define {{.*}}void [[T4:@__omp_offloading_.+static.+l324]](i[[SZ]]
// Create local storage for each capture.
// CHECK: [[LOCAL_A:%.+]] = alloca i[[SZ]]
// CHECK: [[LOCAL_AA:%.+]] = alloca i[[SZ]]
@@ -447,7 +450,7 @@ int bar(int n){
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+S1.+l339}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+S1.+l342}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -478,7 +481,7 @@ int bar(int n){
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T5:@__omp_offloading_.+S1.+l339]](
+ // CHECK: define {{.*}}void [[T5:@__omp_offloading_.+S1.+l342]](
// Create local storage for each capture.
// CHECK: [[LOCAL_THIS:%.+]] = alloca [[S1:%struct.*]]*
// CHECK: [[LOCAL_B:%.+]] = alloca i[[SZ]]
@@ -537,7 +540,7 @@ int bar(int n){
- // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l304}}_worker()
+ // CHECK-LABEL: define {{.*}}void {{@__omp_offloading_.+template.+l307}}_worker()
// CHECK-DAG: [[OMP_EXEC_STATUS:%.+]] = alloca i8,
// CHECK-DAG: [[OMP_WORK_FN:%.+]] = alloca i8*,
// CHECK: store i8* null, i8** [[OMP_WORK_FN]],
@@ -568,7 +571,7 @@ int bar(int n){
// CHECK: [[EXIT]]
// CHECK: ret void
- // CHECK: define {{.*}}void [[T6:@__omp_offloading_.+template.+l304]](i[[SZ]]
+ // CHECK: define {{.*}}void [[T6:@__omp_offloading_.+template.+l307]](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_firstprivate_codegen.cpp b/test/OpenMP/nvptx_target_firstprivate_codegen.cpp
index 5dcff8e548..f750be03e0 100644
--- a/test/OpenMP/nvptx_target_firstprivate_codegen.cpp
+++ b/test/OpenMP/nvptx_target_firstprivate_codegen.cpp
@@ -1,15 +1,14 @@
-
// 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 TCHECK --check-prefix TCHECK-64
+// RUN: %clang_cc1 -debug-info-kind=limited -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 TCHECK --check-prefix TCHECK-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 TCHECK --check-prefix TCHECK-32
+// RUN: %clang_cc1 -debug-info-kind=limited -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 TCHECK --check-prefix TCHECK-32
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
-template<typename tx, typename ty>
-struct TT{
+template <typename tx, typename ty>
+struct TT {
tx X;
ty Y;
};
@@ -23,29 +22,32 @@ int foo(int n, double *ptr) {
float b[10];
double c[5][10];
TT<long long, char> d;
-
- #pragma omp target firstprivate(a)
+
+#pragma omp target firstprivate(a) map(tofrom \
+ : b)
{
+ b[a] = a;
}
-
- // TCHECK: define void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A_IN:%.+]])
+
+ // TCHECK: define {{.*}}void @__omp_offloading_{{.+}}([10 x float] addrspace(1)* noalias [[B_IN:%.+]], i{{[0-9]+}} [[A_IN:%.+]])
// TCHECK: [[A_ADDR:%.+]] = alloca i{{[0-9]+}},
// TCHECK-NOT: alloca i{{[0-9]+}},
+ // TCHECK-64: call void @llvm.dbg.declare(metadata [10 x float] addrspace(1)** %{{.+}}, metadata !{{[0-9]+}}, metadata !DIExpression())
// TCHECK: store i{{[0-9]+}} [[A_IN]], i{{[0-9]+}}* [[A_ADDR]],
- // TCHECK: ret void
+ // TCHECK: ret void
-#pragma omp target firstprivate(aa,b,c,d)
+#pragma omp target firstprivate(aa, b, c, d)
{
aa += 1;
b[2] = 1.0;
c[1][2] = 1.0;
d.X = 1;
- d.Y = 1;
+ d.Y = 1;
}
-
+
// make sure that firstprivate variables are generated in all cases and that we use those instances for operations inside the
// target region
- // TCHECK: define void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A2_IN:%.+]], [10 x float]* {{.+}} [[B_IN:%.+]], [5 x [10 x double]]* {{.+}} [[C_IN:%.+]], [[TT]]* {{.+}} [[D_IN:%.+]])
+ // TCHECK: define {{.*}}void @__omp_offloading_{{.+}}(i{{[0-9]+}}{{.*}} [[A2_IN:%.+]], [10 x float]*{{.*}} [[B_IN:%.+]], [5 x [10 x double]]*{{.*}} [[C_IN:%.+]], [[TT]]*{{.*}} [[D_IN:%.+]])
// TCHECK: [[A2_ADDR:%.+]] = alloca i{{[0-9]+}},
// TCHECK: [[B_ADDR:%.+]] = alloca [10 x float]*,
// TCHECK: [[C_ADDR:%.+]] = alloca [5 x [10 x double]]*,
@@ -58,10 +60,12 @@ int foo(int n, double *ptr) {
// TCHECK: store [10 x float]* [[B_IN]], [10 x float]** [[B_ADDR]],
// TCHECK: store [5 x [10 x double]]* [[C_IN]], [5 x [10 x double]]** [[C_ADDR]],
// TCHECK: store [[TT]]* [[D_IN]], [[TT]]** [[D_ADDR]],
- // TCHECK: [[CONV_A2ADDR:%.+]] = bitcast i{{[0-9]+}}* [[A2_ADDR]] to i{{[0-9]+}}*
// TCHECK: [[B_ADDR_REF:%.+]] = load [10 x float]*, [10 x float]** [[B_ADDR]],
+ // TCHECK: [[B_ADDR_REF:%.+]] = load [10 x float]*, [10 x float]** %
// TCHECK: [[C_ADDR_REF:%.+]] = load [5 x [10 x double]]*, [5 x [10 x double]]** [[C_ADDR]],
+ // TCHECK: [[C_ADDR_REF:%.+]] = load [5 x [10 x double]]*, [5 x [10 x double]]** %
// TCHECK: [[D_ADDR_REF:%.+]] = load [[TT]]*, [[TT]]** [[D_ADDR]],
+ // TCHECK: [[D_ADDR_REF:%.+]] = load [[TT]]*, [[TT]]** %
// firstprivate(aa): a_priv = a_in
@@ -74,16 +78,15 @@ int foo(int n, double *ptr) {
// TCHECK: [[C_PRIV_BCAST:%.+]] = bitcast [5 x [10 x double]]* [[C_PRIV]] to i8*
// TCHECK: [[C_IN_BCAST:%.+]] = bitcast [5 x [10 x double]]* [[C_ADDR_REF]] to i8*
// TCHECK: call void @llvm.memcpy.{{.+}}(i8* [[C_PRIV_BCAST]], i8* [[C_IN_BCAST]],{{.+}})
-
+
// firstprivate(d)
// TCHECK: [[D_PRIV_BCAST:%.+]] = bitcast [[TT]]* [[D_PRIV]] to i8*
// TCHECK: [[D_IN_BCAST:%.+]] = bitcast [[TT]]* [[D_ADDR_REF]] to i8*
// TCHECK: call void @llvm.memcpy.{{.+}}(i8* [[D_PRIV_BCAST]], i8* [[D_IN_BCAST]],{{.+}})
- // TCHECK: load i16, i16* [[CONV_A2ADDR]],
+ // TCHECK: load i16, i16* [[A2_ADDR]],
-
- #pragma omp target firstprivate(ptr)
+#pragma omp target firstprivate(ptr)
{
ptr[0]++;
}
@@ -98,13 +101,12 @@ int foo(int n, double *ptr) {
return a;
}
-
-template<typename tx>
+template <typename tx>
tx ftemplate(int n) {
tx a = 0;
tx b[10];
-#pragma omp target firstprivate(a,b)
+#pragma omp target firstprivate(a, b)
{
a += 1;
b[2] += 1;
@@ -113,13 +115,12 @@ tx ftemplate(int n) {
return a;
}
-static
-int fstatic(int n) {
+static int fstatic(int n) {
int a = 0;
char aaa = 0;
int b[10];
-#pragma omp target firstprivate(a,aaa,b)
+#pragma omp target firstprivate(a, aaa, b)
{
a += 1;
aaa += 1;
@@ -129,7 +130,7 @@ int fstatic(int n) {
return a;
}
-// TCHECK: define void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A_IN:%.+]], i{{[0-9]+}} [[A3_IN:%.+]], [10 x i{{[0-9]+}}]*{{.+}} [[B_IN:%.+]])
+// TCHECK: define {{.*}}void @__omp_offloading_{{.+}}(i{{[0-9]+}}{{.*}} [[A_IN:%.+]], i{{[0-9]+}}{{.*}} [[A3_IN:%.+]], [10 x i{{[0-9]+}}]*{{.+}} [[B_IN:%.+]])
// TCHECK: [[A_ADDR:%.+]] = alloca i{{[0-9]+}},
// TCHECK: [[A3_ADDR:%.+]] = alloca i{{[0-9]+}},
// TCHECK: [[B_ADDR:%.+]] = alloca [10 x i{{[0-9]+}}]*,
@@ -138,9 +139,8 @@ int fstatic(int n) {
// TCHECK: store i{{[0-9]+}} [[A_IN]], i{{[0-9]+}}* [[A_ADDR]],
// TCHECK: store i{{[0-9]+}} [[A3_IN]], i{{[0-9]+}}* [[A3_ADDR]],
// TCHECK: store [10 x i{{[0-9]+}}]* [[B_IN]], [10 x i{{[0-9]+}}]** [[B_ADDR]],
-// TCHECK-64: [[A_CONV:%.+]] = bitcast i{{[0-9]+}}* [[A_ADDR]] to i{{[0-9]+}}*
-// TCHECK: [[A3_CONV:%.+]] = bitcast i{{[0-9]+}}* [[A3_ADDR]] to i8*
// TCHECK: [[B_ADDR_REF:%.+]] = load [10 x i{{[0-9]+}}]*, [10 x i{{[0-9]+}}]** [[B_ADDR]],
+// TCHECK: [[B_ADDR_REF:%.+]] = load [10 x i{{[0-9]+}}]*, [10 x i{{[0-9]+}}]** %
// firstprivate(a): a_priv = a_in
@@ -158,8 +158,8 @@ int fstatic(int n) {
struct S1 {
double a;
- int r1(int n){
- int b = n+1;
+ int r1(int n) {
+ int b = n + 1;
#pragma omp target firstprivate(b)
{
@@ -169,7 +169,7 @@ struct S1 {
return (int)b;
}
- // TCHECK: define void @__omp_offloading_{{.+}}([[S1]]* [[TH:%.+]], i{{[0-9]+}} [[B_IN:%.+]])
+ // TCHECK: define internal void @__omp_offloading_{{.+}}([[S1]]* [[TH:%.+]], i{{[0-9]+}} [[B_IN:%.+]])
// TCHECK: [[TH_ADDR:%.+]] = alloca [[S1]]*,
// TCHECK: [[B_ADDR:%.+]] = alloca i{{[0-9]+}},
// TCHECK-NOT: alloca i{{[0-9]+}},
@@ -185,9 +185,7 @@ struct S1 {
// TCHECK: ret void
};
-
-
-int bar(int n, double *ptr){
+int bar(int n, double *ptr) {
int a = 0;
a += foo(n, ptr);
S1 S;
@@ -200,15 +198,15 @@ int bar(int n, double *ptr){
// template
-// TCHECK: define void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A_IN:%.+]], [10 x i{{[0-9]+}}]*{{.+}} [[B_IN:%.+]])
+// TCHECK: define internal void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A_IN:%.+]], [10 x i{{[0-9]+}}]*{{.+}} [[B_IN:%.+]])
// TCHECK: [[A_ADDR:%.+]] = alloca i{{[0-9]+}},
// TCHECK: [[B_ADDR:%.+]] = alloca [10 x i{{[0-9]+}}]*,
// TCHECK-NOT: alloca i{{[0-9]+}},
// TCHECK: [[B_PRIV:%.+]] = alloca [10 x i{{[0-9]+}}],
// TCHECK: store i{{[0-9]+}} [[A_IN]], i{{[0-9]+}}* [[A_ADDR]],
// TCHECK: store [10 x i{{[0-9]+}}]* [[B_IN]], [10 x i{{[0-9]+}}]** [[B_ADDR]],
-// TCHECK-64: [[A_ADDR_CONV:%.+]] = bitcast i{{[0-9]+}}* [[A_ADDR]] to i{{[0-9]+}}*
// TCHECK: [[B_ADDR_REF:%.+]] = load [10 x i{{[0-9]+}}]*, [10 x i{{[0-9]+}}]** [[B_ADDR]],
+// TCHECK: [[B_ADDR_REF:%.+]] = load [10 x i{{[0-9]+}}]*, [10 x i{{[0-9]+}}]** %
// firstprivate(a)
// TCHECK-NOT: store i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}*
diff --git a/test/OpenMP/openmp_offload_codegen.cpp b/test/OpenMP/openmp_offload_codegen.cpp
new file mode 100644
index 0000000000..f89bccf3b5
--- /dev/null
+++ b/test/OpenMP/openmp_offload_codegen.cpp
@@ -0,0 +1,36 @@
+// Test device for mapping codegen.
+///==========================================================================///
+
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -S -emit-llvm %s -o - 2>&1 \
+// RUN: | FileCheck -check-prefix=CK1 %s
+
+// RUN: %clang_cc1 -DCK1 -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 -DCK1 -verify -fopenmp -x c++ -triple powerpc64le-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 CK1-DEVICE
+
+// expected-no-diagnostics
+
+#ifdef CK1
+
+void target_maps_parallel_integer(int a){
+ int ParamToKernel = a;
+#pragma omp target map(tofrom: ParamToKernel)
+ {
+ ParamToKernel += 1;
+ }
+}
+
+// CK1-DEVICE: {{.*}}void @__omp_offloading_{{.*}}(i32* dereferenceable(4){{.*}}
+
+// CK1: {{.*}}void {{.*}}target_maps_parallel_integer{{.*}} {
+
+// CK1: [[GEPOBP:%.+]] = getelementptr inbounds {{.*}}
+// CK1: [[GEPOBPBIT:%.+]] = bitcast i8** [[GEPOBP]]
+// CK1: store i32* %ParamToKernel, i32** [[GEPOBPBIT]]
+// CK1: [[GEPOP:%.+]] = getelementptr inbounds {{.*}}
+// CK1: [[GEPOPBIT:%.+]] = bitcast i8** [[GEPOP]]
+// CK1: store i32* %ParamToKernel, i32** [[GEPOPBIT]]
+// CK1: [[GEPOBPARG:%.+]] = getelementptr inbounds {{.*}}
+// CK1: [[GEPOPARG:%.+]] = getelementptr inbounds {{.*}}
+// CK1: call {{.*}}tgt_target({{.*}}i8** [[GEPOBPARG]], i8** [[GEPOPARG]]
+
+#endif \ No newline at end of file
diff --git a/test/OpenMP/ordered_codegen.cpp b/test/OpenMP/ordered_codegen.cpp
index bd7c07051b..af6a872243 100644
--- a/test/OpenMP/ordered_codegen.cpp
+++ b/test/OpenMP/ordered_codegen.cpp
@@ -216,7 +216,7 @@ float f[10];
// CHECK-LABEL: foo_simd
void foo_simd(int low, int up) {
// CHECK: store float 0.000000e+00, float* %{{.+}}, align {{[0-9]+}}, !llvm.mem.parallel_loop_access !
- // CHECK-NEXT: call void [[CAP_FUNC:@.+]](i32* %{{.+}}) #{{[0-9]+}}, !llvm.mem.parallel_loop_access !
+ // CHECK-NEXT: call void [[CAP_FUNC:@.+]](i32* %{{.+}}), !llvm.mem.parallel_loop_access !
#pragma omp simd
for (int i = low; i < up; ++i) {
f[i] = 0.0;
@@ -224,7 +224,7 @@ void foo_simd(int low, int up) {
f[i] = 1.0;
}
// CHECK: store float 0.000000e+00, float* %{{.+}}, align {{[0-9]+}}
- // CHECK-NEXT: call void [[CAP_FUNC:@.+]](i32* %{{.+}}) #{{[0-9]+}}
+ // CHECK-NEXT: call void [[CAP_FUNC:@.+]](i32* %{{.+}})
#pragma omp for simd ordered
for (int i = low; i < up; ++i) {
f[i] = 0.0;
diff --git a/test/OpenMP/ordered_messages.cpp b/test/OpenMP/ordered_messages.cpp
index eb2c18e469..2e3d55ca83 100644
--- a/test/OpenMP/ordered_messages.cpp
+++ b/test/OpenMP/ordered_messages.cpp
@@ -270,5 +270,13 @@ int k;
}
}
+#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
+ for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
+#pragma omp ordered depend(sink : i)
+ int j;
+#pragma omp ordered depend(sink : i, j) // expected-error {{expected loop iteration variable}}
+ foo();
+ }
+
return foo<int>(); // expected-note {{in instantiation of function template specialization 'foo<int>' requested here}}
}
diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp
index c43533c6c1..77e8efded6 100644
--- a/test/OpenMP/parallel_codegen.cpp
+++ b/test/OpenMP/parallel_codegen.cpp
@@ -53,7 +53,7 @@ int main (int argc, char **argv) {
// CHECK-DEBUG: ret i32
// CHECK-DEBUG-NEXT: }
-// CHECK: define internal {{.*}}void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i{{[0-9]+}}{{.*}} [[VLA_SIZE:%.+]], i32* [[VLA_ADDR:%[^)]+]])
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i{{[0-9]+}}{{.*}} [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]])
// CHECK-SAME: #[[FN_ATTRS:[0-9]+]]
// CHECK: store i32* [[VLA_ADDR]], i32** [[VLA_PTR_ADDR:%.+]],
// CHECK: [[VLA_REF:%.+]] = load i32*, i32** [[VLA_PTR_ADDR]]
@@ -64,7 +64,7 @@ int main (int argc, char **argv) {
// CHECK: call {{.*}}void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG: define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* [[VLA_ADDR:%[^)]+]])
+// CHECK-DEBUG: define internal void [[OMP_OUTLINED_DEBUG:@.+]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]])
// CHECK-DEBUG-SAME: #[[FN_ATTRS:[0-9]+]]
// CHECK-DEBUG: store i32* [[VLA_ADDR]], i32** [[VLA_PTR_ADDR:%.+]],
// CHECK-DEBUG: [[VLA_REF:%.+]] = load i32*, i32** [[VLA_PTR_ADDR]]
@@ -80,6 +80,8 @@ int main (int argc, char **argv) {
// CHECK-DAG: declare {{.*}}void @__kmpc_fork_call(%ident_t*, i32, void (i32*, i32*, ...)*, ...)
// CHECK-DEBUG-DAG: define linkonce_odr void [[FOO]](i32 %argc)
// CHECK-DEBUG-DAG: declare void @__kmpc_fork_call(%ident_t*, i32, void (i32*, i32*, ...)*, ...)
+// CHECK-DEBUG-DAG: define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]])
+// CHECK-DEBUG-DAG: call void [[OMP_OUTLINED_DEBUG]]
// CHECK: define linkonce_odr {{[a-z\_\b]*[ ]?i32}} [[TMAIN]](i8** %argc)
// CHECK: store i8** %argc, i8*** [[ARGC_ADDR:%.+]],
@@ -107,7 +109,7 @@ int main (int argc, char **argv) {
// CHECK: call {{.*}}void @{{.+terminate.*|abort}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG: define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i8*** dereferenceable({{4|8}}) %argc)
+// CHECK-DEBUG: define internal void [[OMP_OUTLINED_DEBUG:@.+]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i8*** dereferenceable({{4|8}}) %argc)
// CHECK-DEBUG: store i8*** %argc, i8**** [[ARGC_PTR_ADDR:%.+]],
// CHECK-DEBUG: [[ARGC_REF:%.+]] = load i8***, i8**** [[ARGC_PTR_ADDR]]
// CHECK-DEBUG-NEXT: [[ARGC:%.+]] = load i8**, i8*** [[ARGC_REF]]
@@ -118,7 +120,9 @@ int main (int argc, char **argv) {
// CHECK-DEBUG-NEXT: }
// CHECK: define linkonce_odr {{.*}}void [[FOO1]](i8** %argc)
-// CHECK-DEBUG: define linkonce_odr void [[FOO1]](i8** %argc)
+// CHECK-DEBUG-DAG: define linkonce_odr void [[FOO1]](i8** %argc)
+// CHECK-DEBUG-DAG: define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i8*** dereferenceable({{4|8}}) %argc)
+// CHECK-DEBUG-DAG: call void [[OMP_OUTLINED_DEBUG]]({{[^)]+}}){{[^,]*}}, !dbg
// CHECK: attributes #[[FN_ATTRS]] = {{.+}} nounwind
// CHECK-DEBUG: attributes #[[FN_ATTRS]] = {{.+}} nounwind
diff --git a/test/OpenMP/parallel_for_codegen.cpp b/test/OpenMP/parallel_for_codegen.cpp
index 1324ee67b6..bc04532bd1 100644
--- a/test/OpenMP/parallel_for_codegen.cpp
+++ b/test/OpenMP/parallel_for_codegen.cpp
@@ -8,6 +8,7 @@
#define HEADER
// CHECK-DAG: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
+// CHECK-DAG: [[LOOP_LOC:@.+]] = private unnamed_addr constant [[IDENT_T_TY]] { i32 0, i32 514, i32 0, i32 0, i8*
// CHECK-LABEL: with_var_schedule
void with_var_schedule() {
@@ -19,8 +20,8 @@ void with_var_schedule() {
// CHECK: [[CHUNK:%.+]] = load i8*, i8** %
// CHECK: [[CHUNK_VAL:%.+]] = load i8, i8* [[CHUNK]],
// CHECK: [[CHUNK_SIZE:%.+]] = sext i8 [[CHUNK_VAL]] to i64
-// CHECK: call void @__kmpc_for_static_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC:@[^,]+]], i32 [[GTID:%[^,]+]], i32 33, i32* [[IS_LAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]], i64 1, i64 [[CHUNK_SIZE]])
-// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_init_8u([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID:%[^,]+]], i32 33, i32* [[IS_LAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]], i64 1, i64 [[CHUNK_SIZE]])
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]])
#pragma omp parallel for schedule(static, char(a))
for (unsigned long long i = 1; i < 2; ++i) {
}
@@ -32,9 +33,7 @@ void without_schedule_clause(float *a, float *b, float *c, float *d) {
// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, float**, float**, float**, float**)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*),
// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* noalias [[GTID_PARAM_ADDR:%.+]], i32* noalias %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}})
// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID:%.+]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
// UB = min(UB, GlobalUB)
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
@@ -65,7 +64,7 @@ void without_schedule_clause(float *a, float *b, float *c, float *d) {
// CHECK-NEXT: br label %{{.+}}
}
// CHECK: [[LOOP1_END]]
-// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -75,9 +74,7 @@ void static_not_chunked(float *a, float *b, float *c, float *d) {
// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, float**, float**, float**, float**)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*),
// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* noalias [[GTID_PARAM_ADDR:%.+]], i32* noalias %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}})
// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_4([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID:%.+]], i32 34, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 1)
// UB = min(UB, GlobalUB)
// CHECK-NEXT: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
// CHECK-NEXT: [[UBCMP:%.+]] = icmp sgt i32 [[UB]], 4571423
@@ -108,7 +105,7 @@ void static_not_chunked(float *a, float *b, float *c, float *d) {
// CHECK-NEXT: br label %{{.+}}
}
// CHECK: [[LOOP1_END]]
-// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -118,9 +115,7 @@ void static_chunked(float *a, float *b, float *c, float *d) {
// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, float**, float**, float**, float**)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*),
// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* noalias [[GTID_PARAM_ADDR:%.+]], i32* noalias %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}})
// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_for_static_init_4u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 33, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 5)
+// CHECK: call void @__kmpc_for_static_init_4u([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID:%.+]], i32 33, i32* [[IS_LAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]], i32 1, i32 5)
// UB = min(UB, GlobalUB)
// CHECK: [[UB:%.+]] = load i32, i32* [[OMP_UB]]
// CHECK-NEXT: [[UBCMP:%.+]] = icmp ugt i32 [[UB]], 16908288
@@ -170,7 +165,7 @@ void static_chunked(float *a, float *b, float *c, float *d) {
// CHECK-NEXT: store i32 [[ADD_UB]], i32* [[OMP_UB]]
// CHECK: [[O_LOOP1_END]]
-// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_fini([[IDENT_T_TY]]* [[LOOP_LOC]], i32 [[GTID]])
// CHECK: ret void
}
@@ -180,9 +175,7 @@ void dynamic1(float *a, float *b, float *c, float *d) {
// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, float**, float**, float**, float**)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*),
// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* noalias [[GTID_PARAM_ADDR:%.+]], i32* noalias %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}})
// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_dispatch_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 35, i64 0, i64 16908287, i64 1, i64 1)
+// CHECK: call void @__kmpc_dispatch_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID:%.+]], i32 35, i64 0, i64 16908287, i64 1, i64 1)
//
// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
@@ -224,9 +217,7 @@ void guided7(float *a, float *b, float *c, float *d) {
// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, float**, float**, float**, float**)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*),
// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* noalias [[GTID_PARAM_ADDR:%.+]], i32* noalias %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}})
// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_dispatch_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 36, i64 0, i64 16908287, i64 1, i64 7)
+// CHECK: call void @__kmpc_dispatch_init_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID:%.+]], i32 36, i64 0, i64 16908287, i64 1, i64 7)
//
// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8u([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
@@ -270,12 +261,8 @@ void test_auto(float *a, float *b, float *c, float *d) {
// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 6, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i32*, float**, float**, float**, float**)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*),
// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* noalias [[GTID_PARAM_ADDR:%.+]], i32* noalias %{{.+}}, i32* dereferenceable(4) %{{.+}}, i32* dereferenceable(4) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}})
// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_dispatch_init_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 38, i64 0, i64 [[LAST_ITER:%[^,]+]], i64 1, i64 1)
+// CHECK: call void @__kmpc_dispatch_init_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID:%.+]], i32 38, i64 0, i64 [[LAST_ITER:%[^,]+]], i64 1, i64 1)
//
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_8([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i64* [[OMP_LB:%[^,]+]], i64* [[OMP_UB:%[^,]+]], i64* [[OMP_ST:%[^,]+]])
// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
// CHECK-NEXT: br i1 [[O_CMP]], label %[[O_LOOP1_BODY:[^,]+]], label %[[O_LOOP1_END:[^,]+]]
@@ -318,9 +305,7 @@ void runtime(float *a, float *b, float *c, float *d) {
// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* [[DEFAULT_LOC:[@%].+]], i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, float**, float**, float**, float**)* [[OMP_PARALLEL_FUNC:@.+]] to void (i32*, i32*, ...)*),
// CHECK: define internal void [[OMP_PARALLEL_FUNC]](i32* noalias [[GTID_PARAM_ADDR:%.+]], i32* noalias %{{.+}}, i32* dereferenceable(4) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}}, float** dereferenceable(8) %{{.+}})
// CHECK: store i32* [[GTID_PARAM_ADDR]], i32** [[GTID_REF_ADDR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_dispatch_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 37, i32 0, i32 199, i32 1, i32 1)
+// CHECK: call void @__kmpc_dispatch_init_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID:%.+]], i32 37, i32 0, i32 199, i32 1, i32 1)
//
// CHECK: [[HASWORK:%.+]] = call i32 @__kmpc_dispatch_next_4([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32* [[OMP_ISLAST:%[^,]+]], i32* [[OMP_LB:%[^,]+]], i32* [[OMP_UB:%[^,]+]], i32* [[OMP_ST:%[^,]+]])
// CHECK-NEXT: [[O_CMP:%.+]] = icmp ne i32 [[HASWORK]], 0
@@ -363,7 +348,7 @@ int foo() {return 0;};
void parallel_for(float *a, int n) {
float arr[n];
#pragma omp parallel for schedule(static, 5) private(arr)
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: call void @__kmpc_for_static_init_4u({{.+}}), !dbg [[DBG_LOC_START:![0-9]+]]
// TERM_DEBUG: invoke i32 {{.*}}foo{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
diff --git a/test/OpenMP/parallel_for_lastprivate_messages.cpp b/test/OpenMP/parallel_for_lastprivate_messages.cpp
index ccfe2ea407..134100bc17 100644
--- a/test/OpenMP/parallel_for_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
S2 &operator=(const S2 &);
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/parallel_for_loop_messages.cpp b/test/OpenMP/parallel_for_loop_messages.cpp
index 7e136e7586..cf1f6195cc 100644
--- a/test/OpenMP/parallel_for_loop_messages.cpp
+++ b/test/OpenMP/parallel_for_loop_messages.cpp
@@ -539,7 +539,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/parallel_for_reduction_messages.cpp b/test/OpenMP/parallel_for_reduction_messages.cpp
index 57ab1fac9c..6499ef593a 100644
--- a/test/OpenMP/parallel_for_reduction_messages.cpp
+++ b/test/OpenMP/parallel_for_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
@@ -61,6 +61,12 @@ class S5 {
public:
S5(int v) : a(v) {}
+ void foo() {
+#pragma omp parallel private(a) // expected-note {{defined as private}}
+#pragma omp for reduction(+:a) // expected-error {{reduction variable must be shared}}
+ for (int i = 0; i < 10; ++i)
+ ::foo();
+ }
};
class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
#if __cplusplus >= 201103L // C++11 or later
diff --git a/test/OpenMP/parallel_for_simd_aligned_messages.cpp b/test/OpenMP/parallel_for_simd_aligned_messages.cpp
index fc0f88cc38..eed8017003 100644
--- a/test/OpenMP/parallel_for_simd_aligned_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_aligned_messages.cpp
@@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp parallel for simd aligned // expected-error {{expected '(' after 'aligned'}}
for (I k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/parallel_for_simd_codegen.cpp b/test/OpenMP/parallel_for_simd_codegen.cpp
index 06d96353ee..9112635855 100644
--- a/test/OpenMP/parallel_for_simd_codegen.cpp
+++ b/test/OpenMP/parallel_for_simd_codegen.cpp
@@ -114,6 +114,7 @@ void simple(float *a, float *b, float *c, float *d) {
int lin = 12;
#pragma omp parallel for simd linear(lin : get_val()), linear(g_ptr)
+// CHECK: alloca i32,
// Init linear private var.
// CHECK: [[LIN_VAR:%.+]] = load i32*, i32** %
// CHECK: [[LIN_LOAD:%.+]] = load i32, i32* [[LIN_VAR]]
@@ -667,7 +668,7 @@ int bar() {return 0;};
// TERM_DEBUG-LABEL: parallel_simd
void parallel_simd(float *a) {
#pragma omp parallel for simd
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: invoke i32 {{.*}}bar{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
// TERM_DEBUG-NOT: __kmpc_global_thread_num
diff --git a/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
index bd1a6d5055..8670e55c6e 100644
--- a/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_lastprivate_messages.cpp
@@ -17,9 +17,9 @@ public:
S2(S2 &s2) : a(s2.a) {}
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/parallel_for_simd_loop_messages.cpp b/test/OpenMP/parallel_for_simd_loop_messages.cpp
index 403e951d53..7feb4b0eb6 100644
--- a/test/OpenMP/parallel_for_simd_loop_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_loop_messages.cpp
@@ -540,7 +540,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/parallel_for_simd_reduction_messages.cpp b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
index 60a947dd5f..8ff246e35f 100644
--- a/test/OpenMP/parallel_for_simd_reduction_messages.cpp
+++ b/test/OpenMP/parallel_for_simd_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/parallel_if_codegen.cpp b/test/OpenMP/parallel_if_codegen.cpp
index af154c0e36..87dcf1dde9 100644
--- a/test/OpenMP/parallel_if_codegen.cpp
+++ b/test/OpenMP/parallel_if_codegen.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s
-// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK %s
+// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
diff --git a/test/OpenMP/parallel_reduction_codegen.cpp b/test/OpenMP/parallel_reduction_codegen.cpp
index e42776c740..c4c0ff473a 100644
--- a/test/OpenMP/parallel_reduction_codegen.cpp
+++ b/test/OpenMP/parallel_reduction_codegen.cpp
@@ -80,6 +80,14 @@ struct SST {
// CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8*
// CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer
+//CHECK: foo_array_sect
+//CHECK: call void {{.+}}@__kmpc_fork_call(
+//CHECK: ret void
+void foo_array_sect(short x[1]) {
+#pragma omp parallel reduction(+ : x[:])
+ {}
+}
+
template <typename T>
T tmain() {
T t;
diff --git a/test/OpenMP/parallel_reduction_messages.cpp b/test/OpenMP/parallel_reduction_messages.cpp
index 947353fc2d..96f4b58ec8 100644
--- a/test/OpenMP/parallel_reduction_messages.cpp
+++ b/test/OpenMP/parallel_reduction_messages.cpp
@@ -24,9 +24,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/parallel_sections_codegen.cpp b/test/OpenMP/parallel_sections_codegen.cpp
index 6fc687d0c5..afbc6e4d5e 100644
--- a/test/OpenMP/parallel_sections_codegen.cpp
+++ b/test/OpenMP/parallel_sections_codegen.cpp
@@ -28,9 +28,7 @@ int main() {
{
// CHECK: store i32 0, i32* [[LB_PTR:%.+]],
// CHECK: store i32 1, i32* [[UB_PTR:%.+]],
-// CHECK: [[GTID_REF:%.+]] = load i32*, i32** [[GTID_REF_ADDR]],
-// CHECK: [[GTID:%.+]] = load i32, i32* [[GTID_REF]],
-// CHECK: call void @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_PTR:%.+]], i32* [[LB_PTR]], i32* [[UB_PTR]], i32* [[STRIDE_PTR:%.+]], i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID:%.+]], i32 34, i32* [[IS_LAST_PTR:%.+]], i32* [[LB_PTR]], i32* [[UB_PTR]], i32* [[STRIDE_PTR:%.+]], i32 1, i32 1)
// <<UB = min(UB, GlobalUB);>>
// CHECK: [[UB:%.+]] = load i32, i32* [[UB_PTR]]
// CHECK: [[CMP:%.+]] = icmp slt i32 [[UB]], 1
@@ -76,7 +74,7 @@ int main() {
// CHECK-LABEL: tmain
// CHECK: call void {{.*}} @__kmpc_fork_call(
-// CHECK-NOT: __kmpc_global_thread_num
+// CHECK: __kmpc_global_thread_num
// CHECK: call void @__kmpc_for_static_init_4(
// CHECK: invoke void @{{.*}}foo{{.*}}()
// CHECK-NEXT: unwind label %[[TERM_LPAD:.+]]
diff --git a/test/OpenMP/parallel_sections_lastprivate_messages.cpp b/test/OpenMP/parallel_sections_lastprivate_messages.cpp
index af3c5e2a57..eccbfc5e7e 100644
--- a/test/OpenMP/parallel_sections_lastprivate_messages.cpp
+++ b/test/OpenMP/parallel_sections_lastprivate_messages.cpp
@@ -17,9 +17,9 @@ public:
S2(S2 &s2) : a(s2.a) {}
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/parallel_sections_reduction_messages.cpp b/test/OpenMP/parallel_sections_reduction_messages.cpp
index 05cc7f0f6c..26b3a5355c 100644
--- a/test/OpenMP/parallel_sections_reduction_messages.cpp
+++ b/test/OpenMP/parallel_sections_reduction_messages.cpp
@@ -26,9 +26,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/report_default_DSA.cpp b/test/OpenMP/report_default_DSA.cpp
new file mode 100644
index 0000000000..d14cd5cbe9
--- /dev/null
+++ b/test/OpenMP/report_default_DSA.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 %s
+
+void foo(int x, int n) {
+ double vec[n];
+ for (int iter = 0; iter < x; iter++) {
+#pragma omp target teams distribute parallel for map( \
+ from \
+ : vec [0:n]) default(none)
+ // expected-error@+1 {{variable 'n' must have explicitly specified data sharing attributes}}
+ for (int ii = 0; ii < n; ii++) {
+ // expected-error@+3 {{variable 'iter' must have explicitly specified data sharing attributes}}
+ // expected-error@+2 {{variable 'vec' must have explicitly specified data sharing attributes}}
+ // expected-error@+1 {{variable 'x' must have explicitly specified data sharing attributes}}
+ vec[ii] = iter + ii + x;
+ }
+ }
+}
+
diff --git a/test/OpenMP/sections_codegen.cpp b/test/OpenMP/sections_codegen.cpp
index 65747e7b91..0ed87e4035 100644
--- a/test/OpenMP/sections_codegen.cpp
+++ b/test/OpenMP/sections_codegen.cpp
@@ -4,7 +4,8 @@
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
-// CHECK: [[IMPLICIT_BARRIER_SECTIONS_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 194, i32 0, i32 0, i8*
+// CHECK-DAG: [[IMPLICIT_BARRIER_SECTIONS_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 194, i32 0, i32 0, i8*
+// CHECK-DAG: [[SECTIONS_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 1026, i32 0, i32 0, i8*
// CHECK-LABEL: foo
void foo() {};
// CHECK-LABEL: bar
@@ -29,7 +30,7 @@ int main() {
{
// CHECK: store i32 0, i32* [[LB_PTR:%.+]],
// CHECK: store i32 1, i32* [[UB_PTR:%.+]],
-// CHECK: call void @__kmpc_for_static_init_4(%{{.+}}* @{{.+}}, i32 [[GTID]], i32 34, i32* [[IS_LAST_PTR:%.+]], i32* [[LB_PTR]], i32* [[UB_PTR]], i32* [[STRIDE_PTR:%.+]], i32 1, i32 1)
+// CHECK: call void @__kmpc_for_static_init_4(%{{.+}}* [[SECTIONS_LOC]], i32 [[GTID]], i32 34, i32* [[IS_LAST_PTR:%.+]], i32* [[LB_PTR]], i32* [[UB_PTR]], i32* [[STRIDE_PTR:%.+]], i32 1, i32 1)
// <<UB = min(UB, GlobalUB);>>
// CHECK: [[UB:%.+]] = load i32, i32* [[UB_PTR]]
// CHECK: [[CMP:%.+]] = icmp slt i32 [[UB]], 1
@@ -69,7 +70,7 @@ int main() {
// CHECK-NEXT: br label %[[INNER_FOR_COND]]
// CHECK: [[INNER_LOOP_END]]
}
-// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* @{{.+}}, i32 [[GTID]])
+// CHECK: call void @__kmpc_for_static_fini(%{{.+}}* [[SECTIONS_LOC]], i32 [[GTID]])
// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_SECTIONS_LOC]],
#pragma omp sections nowait
{
@@ -83,7 +84,7 @@ int main() {
// CHECK-LABEL: tmain
// CHECK: call void {{.*}} @__kmpc_fork_call(
-// CHECK-NOT: __kmpc_global_thread_num
+// CHECK: __kmpc_global_thread_num
// CHECK: call void @__kmpc_for_static_init_4(
// CHECK: invoke void @{{.*}}foo{{.*}}()
// CHECK-NEXT: unwind label %[[TERM_LPAD:.+]]
diff --git a/test/OpenMP/sections_lastprivate_messages.cpp b/test/OpenMP/sections_lastprivate_messages.cpp
index 5f6b420cb8..01bb13de55 100644
--- a/test/OpenMP/sections_lastprivate_messages.cpp
+++ b/test/OpenMP/sections_lastprivate_messages.cpp
@@ -17,9 +17,9 @@ public:
S2(S2 &s2) : a(s2.a) {}
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/sections_reduction_messages.cpp b/test/OpenMP/sections_reduction_messages.cpp
index f13c5b3f28..58b22a5a61 100644
--- a/test/OpenMP/sections_reduction_messages.cpp
+++ b/test/OpenMP/sections_reduction_messages.cpp
@@ -27,9 +27,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/simd_aligned_messages.cpp b/test/OpenMP/simd_aligned_messages.cpp
index 81aec960f2..d936fed014 100644
--- a/test/OpenMP/simd_aligned_messages.cpp
+++ b/test/OpenMP/simd_aligned_messages.cpp
@@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp simd aligned // expected-error {{expected '(' after 'aligned'}}
for (I k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/simd_lastprivate_messages.cpp b/test/OpenMP/simd_lastprivate_messages.cpp
index 16223db71a..349d6a5b90 100644
--- a/test/OpenMP/simd_lastprivate_messages.cpp
+++ b/test/OpenMP/simd_lastprivate_messages.cpp
@@ -17,9 +17,9 @@ public:
S2(S2 &s2) : a(s2.a) {}
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/simd_loop_messages.cpp b/test/OpenMP/simd_loop_messages.cpp
index 96b4cafc6b..a47ccbc872 100644
--- a/test/OpenMP/simd_loop_messages.cpp
+++ b/test/OpenMP/simd_loop_messages.cpp
@@ -527,7 +527,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/simd_reduction_messages.cpp b/test/OpenMP/simd_reduction_messages.cpp
index 1e1a233ec4..bdf429d196 100644
--- a/test/OpenMP/simd_reduction_messages.cpp
+++ b/test/OpenMP/simd_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/single_codegen.cpp b/test/OpenMP/single_codegen.cpp
index 892e160324..4feb3bdac3 100644
--- a/test/OpenMP/single_codegen.cpp
+++ b/test/OpenMP/single_codegen.cpp
@@ -190,7 +190,7 @@ int main() {
void parallel_single() {
#pragma omp parallel
#pragma omp single
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: call i32 @__kmpc_single({{.+}}), !dbg [[DBG_LOC_START:![0-9]+]]
// TERM_DEBUG: invoke void {{.*}}foo{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
diff --git a/test/OpenMP/target_ast_print.cpp b/test/OpenMP/target_ast_print.cpp
index 032a39fe5e..d004f738fc 100644
--- a/test/OpenMP/target_ast_print.cpp
+++ b/test/OpenMP/target_ast_print.cpp
@@ -10,7 +10,7 @@ void foo() {}
template <typename T, int C>
T tmain(T argc, T *argv) {
- T i, j, a[20];
+ T i, j, a[20], always;
#pragma omp target
foo();
#pragma omp target if (target:argc > 0)
@@ -25,6 +25,12 @@ T tmain(T argc, T *argv) {
foo();
#pragma omp target map(always,alloc: i)
foo();
+#pragma omp target map(always from: i)
+ foo();
+#pragma omp target map(always)
+ {always++;}
+#pragma omp target map(always,i)
+ {always++;i++;}
#pragma omp target nowait
foo();
#pragma omp target depend(in : argc, argv[i:argc], a[:])
@@ -50,6 +56,17 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target map(always,alloc: i)
// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(always,from: i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: always)
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp target map(tofrom: always,i)
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: i++;
+// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp target nowait
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target depend(in : argc,argv[i:argc],a[:])
@@ -72,6 +89,17 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target map(always,alloc: i)
// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(always,from: i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: always)
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp target map(tofrom: always,i)
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: i++;
+// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp target nowait
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target depend(in : argc,argv[i:argc],a[:])
@@ -94,6 +122,17 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target map(always,alloc: i)
// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(always,from: i)
+// CHECK-NEXT: foo()
+// CHECK-NEXT: #pragma omp target map(tofrom: always)
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: }
+// CHECK-NEXT: #pragma omp target map(tofrom: always,i)
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: i++;
+// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp target nowait
// CHECK-NEXT: foo()
// CHECK-NEXT: #pragma omp target depend(in : argc,argv[i:argc],a[:])
@@ -103,7 +142,7 @@ T tmain(T argc, T *argv) {
// CHECK-LABEL: int main(int argc, char **argv) {
int main (int argc, char **argv) {
- int i, j, a[20];
+ int i, j, a[20], always;
// CHECK-NEXT: int i, j, a[20]
#pragma omp target
// CHECK-NEXT: #pragma omp target
@@ -139,6 +178,26 @@ int main (int argc, char **argv) {
foo();
// CHECK-NEXT: foo();
+#pragma omp target map(always from: i)
+// CHECK-NEXT: #pragma omp target map(always,from: i)
+ foo();
+// CHECK-NEXT: foo();
+
+#pragma omp target map(always)
+// CHECK-NEXT: #pragma omp target map(tofrom: always)
+ {always++;}
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: }
+
+#pragma omp target map(always,i)
+// CHECK-NEXT: #pragma omp target map(tofrom: always,i)
+ {always++;i++;}
+// CHECK-NEXT: {
+// CHECK-NEXT: always++;
+// CHECK-NEXT: i++;
+// CHECK-NEXT: }
+
#pragma omp target nowait
// CHECK-NEXT: #pragma omp target nowait
foo();
diff --git a/test/OpenMP/target_codegen.cpp b/test/OpenMP/target_codegen.cpp
index b5e4b07cce..d98242623f 100644
--- a/test/OpenMP/target_codegen.cpp
+++ b/test/OpenMP/target_codegen.cpp
@@ -28,20 +28,24 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// 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: [[SIZET:@.+]] = private unnamed_addr constant [2 x i[[SZ]]] [i[[SZ]] 0, i[[SZ]] 4]
+// CHECK-DAG: [[MAPT:@.+]] = private unnamed_addr constant [2 x i32] [i32 32, i32 288]
+// CHECK-DAG: [[SIZET2:@.+]] = private unnamed_addr constant [1 x i{{32|64}}] [i[[SZ]] 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: [[MAPT4:@.+]] = private unnamed_addr constant [9 x i32] [i32 288, i32 547, i32 288, i32 547, i32 547, i32 288, i32 288, i32 547, i32 547]
// 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: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 288, i32 288, i32 547]
// 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: [[MAPT6:@.+]] = private unnamed_addr constant [4 x i32] [i32 288, i32 288, i32 288, i32 547]
+// CHECK-DAG: [[MAPT7:@.+]] = private unnamed_addr constant [5 x i32] [i32 547, i32 288, i32 288, i32 288, i32 547]
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -57,6 +61,7 @@
// TCHECK: @{{.+}} = constant [[ENTTY]]
// TCHECK: @{{.+}} = constant [[ENTTY]]
// TCHECK: @{{.+}} = constant [[ENTTY]]
+// TCHECK: @{{.+}} = {{.*}}constant [[ENTTY]]
// TCHECK-NOT: @{{.+}} = constant [[ENTTY]]
// Check if offloading descriptor is created.
@@ -64,11 +69,11 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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 }]
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
template<typename tx, typename ty>
@@ -77,6 +82,9 @@ struct TT{
ty Y;
};
+int global;
+extern int global;
+
// CHECK: define {{.*}}[[FOO:@.+]](
int foo(int n) {
int a = 0;
@@ -86,28 +94,59 @@ int foo(int n) {
double c[5][10];
double cn[5][n];
TT<long long, char> d;
+ static long *plocal;
- // CHECK: [[RET:%.+]] = call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 0, i8** null, i8** null, i[[SZ]]* null, i32* null)
- // 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: [[ADD:%.+]] = add nsw i32
+ // CHECK: store i32 [[ADD]], i32* [[CAPTURE:%.+]],
+ // CHECK: [[LD:%.+]] = load i32, i32* [[CAPTURE]],
+ // CHECK: [[RET:%.+]] = call i32 @__tgt_target(i32 [[LD]], i8* @{{[^,]+}}, i32 0, i8** null, i8** null, i[[SZ]]* null, i32* null)
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET]], 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
+ #pragma omp target device(global + a)
{
}
- // 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: [[ADD:%.+]] = add nsw i32
+ // CHECK: store i32 [[ADD]], i32* [[CAPTURE:%.+]],
+ // CHECK-DAG: [[LD:%.+]] = load i32, i32* [[CAPTURE]],
+ // CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target(i32 [[LD]], i8* @{{[^,]+}}, i32 2, i8** [[BPR:%[^,]+]], i8** [[PR:%[^,]+]], i[[SZ]]* getelementptr inbounds ([2 x i[[SZ]]], [2 x i[[SZ]]]* [[SIZET]], i32 0, i32 0), i32* getelementptr inbounds ([2 x i32], [2 x i32]* [[MAPT]], 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]**
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]**
+ // CHECK-DAG: store i[[SZ]]* [[BP0:%[^,]+]], i[[SZ]]** [[CBPADDR0]]
+ // CHECK-DAG: store i[[SZ]]* [[BP0]], i[[SZ]]** [[CPADDR0]]
+
+ // 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: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[BP1:%[^,]+]], i[[SZ]]* [[CBPADDR1]]
+ // CHECK-DAG: store i[[SZ]] [[BP1]], i[[SZ]]* [[CPADDR1]]
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
+ // CHECK: [[FAIL]]
+ // CHECK: call void [[HVT0_:@.+]](i[[SZ]]* [[BP0]], i[[SZ]] [[BP1]])
+ // CHECK-NEXT: br label %[[END]]
+ // CHECK: [[END]]
+ #pragma omp target device(global + a)
+ {
+ static int local1;
+ *plocal = global;
+ local1 = global;
+ }
+
// CHECK: call void [[HVT1:@.+]](i[[SZ]] {{[^,]+}})
- #pragma omp target if(0)
+ #pragma omp target if(0) firstprivate(global)
{
- a += 1;
+ global += 1;
}
// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target(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))
@@ -115,14 +154,12 @@ int foo(int n) {
// 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-DAG: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[BP0:%[^,]+]], i[[SZ]]* [[CBPADDR0]]
+ // CHECK-DAG: store i[[SZ]] [[P0:%[^,]+]], i[[SZ]]* [[CPADDR0]]
+
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT2:@.+]](i[[SZ]] {{[^,]+}})
@@ -142,32 +179,29 @@ int foo(int n) {
// 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[BP0:%[^,]+]], i[[SZ]]* [[CBPADDR0]]
+ // CHECK-DAG: store i[[SZ]] [[P0:%[^,]+]], i[[SZ]]* [[CPADDR0]]
// 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-DAG: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[BP1:%[^,]+]], i[[SZ]]* [[CBPADDR1]]
+ // CHECK-DAG: store i[[SZ]] [[P1:%[^,]+]], i[[SZ]]* [[CPADDR1]]
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT3:@.+]]({{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+ // CHECK: [[IFELSE]]
+ // CHECK: call void [[HVT3]]({{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[IFEND]]
+
+ // CHECK: [[IFEND]]
#pragma omp target if(n>10)
{
a += 1;
@@ -189,104 +223,109 @@ int foo(int n) {
// CHECK: [[CNSIZE:%.+]] = mul nuw i[[SZ]] [[CNELEMSIZE2]], 8
// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 20
- // CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[FAIL:[^,]+]]
+ // CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[IFELSE:[^,]+]]
// CHECK: [[TRY]]
// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target(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))
// 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: [[SADDR0:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX0:0]]
// 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: [[SADDR1:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX1:1]]
// 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: [[SADDR2:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX2:2]]
// 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: [[SADDR3:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX3:3]]
// 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: [[SADDR4:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX4:4]]
// 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: [[SADDR5:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX5:5]]
// 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: [[SADDR6:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX6:6]]
// 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: [[SADDR7:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX7:7]]
// 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: [[SADDR8:%.+]] = getelementptr inbounds [9 x i[[SZ]]], [9 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX8:8]]
// 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-DAG: [[CBPADDR2:%.+]] = bitcast i8** [[BPADDR2]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR2:%.+]] = bitcast i8** [[PADDR2]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CBPADDR2]]
+ // CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CPADDR2]]
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* [[SADDR2]]
+
+ // CHECK-DAG: [[CBPADDR6:%.+]] = bitcast i8** [[BPADDR6]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR6:%.+]] = bitcast i8** [[PADDR6]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[VLA1]], i[[SZ]]* [[CBPADDR6]]
+ // CHECK-DAG: store i[[SZ]] [[VLA1]], i[[SZ]]* [[CPADDR6]]
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* [[SADDR6]]
+
+ // CHECK-DAG: [[CBPADDR5:%.+]] = bitcast i8** [[BPADDR5]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR5:%.+]] = bitcast i8** [[PADDR5]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] 5, i[[SZ]]* [[CBPADDR5]]
+ // CHECK-DAG: store i[[SZ]] 5, i[[SZ]]* [[CPADDR5]]
+ // CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* [[SADDR5]]
+
+ // CHECK-DAG: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[A_CVAL]], i[[SZ]]* [[CBPADDR0]]
+ // CHECK-DAG: store i[[SZ]] [[A_CVAL]], i[[SZ]]* [[CPADDR0]]
+ // CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* [[SADDR0]]
+
+ // CHECK-DAG: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to [10 x float]**
+ // CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to [10 x float]**
+ // CHECK-DAG: store [10 x float]* %{{.+}}, [10 x float]** [[CBPADDR1]]
+ // CHECK-DAG: store [10 x float]* %{{.+}}, [10 x float]** [[CPADDR1]]
+ // CHECK-DAG: store i[[SZ]] 40, i[[SZ]]* [[SADDR1]]
+
+ // CHECK-DAG: [[CBPADDR3:%.+]] = bitcast i8** [[BPADDR3]] to float**
+ // CHECK-DAG: [[CPADDR3:%.+]] = bitcast i8** [[PADDR3]] to float**
+ // CHECK-DAG: store float* %{{.+}}, float** [[CBPADDR3]]
+ // CHECK-DAG: store float* %{{.+}}, float** [[CPADDR3]]
+ // CHECK-DAG: store i[[SZ]] [[BNSIZE]], i[[SZ]]* [[SADDR3]]
+
+ // CHECK-DAG: [[CBPADDR4:%.+]] = bitcast i8** [[BPADDR4]] to [5 x [10 x double]]**
+ // CHECK-DAG: [[CPADDR4:%.+]] = bitcast i8** [[PADDR4]] to [5 x [10 x double]]**
+ // CHECK-DAG: store [5 x [10 x double]]* %{{.+}}, [5 x [10 x double]]** [[CBPADDR4]]
+ // CHECK-DAG: store [5 x [10 x double]]* %{{.+}}, [5 x [10 x double]]** [[CPADDR4]]
+ // CHECK-DAG: store i[[SZ]] 400, i[[SZ]]* [[SADDR4]]
+
+ // CHECK-DAG: [[CBPADDR7:%.+]] = bitcast i8** [[BPADDR7]] to double**
+ // CHECK-DAG: [[CPADDR7:%.+]] = bitcast i8** [[PADDR7]] to double**
+ // CHECK-DAG: store double* %{{.+}}, double** [[CBPADDR7]]
+ // CHECK-DAG: store double* %{{.+}}, double** [[CPADDR7]]
+ // CHECK-DAG: store i[[SZ]] [[CNSIZE]], i[[SZ]]* [[SADDR7]]
+
+ // CHECK-DAG: [[CBPADDR8:%.+]] = bitcast i8** [[BPADDR8]] to [[TT]]**
+ // CHECK-DAG: [[CPADDR8:%.+]] = bitcast i8** [[PADDR8]] to [[TT]]**
+ // CHECK-DAG: store [[TT]]* %{{.+}}, [[TT]]** [[CBPADDR8]]
+ // CHECK-DAG: store [[TT]]* %{{.+}}, [[TT]]** [[CPADDR8]]
+ // CHECK-DAG: store i[[SZ]] {{12|16}}, i[[SZ]]* [[SADDR8]]
+
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
+ // CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT4:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+ // CHECK: [[IFELSE]]
+ // CHECK: call void [[HVT4]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[IFEND]]
+
+ // CHECK: [[IFEND]]
#pragma omp target if(n>20)
{
a += 1;
@@ -460,64 +499,72 @@ int bar(int n){
// CHECK: [[CSIZE:%.+]] = mul nuw i[[SZ]] [[CELEMSIZE2]], 2
// CHECK: [[IF:%.+]] = icmp sgt i32 {{[^,]+}}, 60
-// CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[FAIL:[^,]+]]
+// CHECK: br i1 [[IF]], label %[[TRY:[^,]+]], label %[[IFELSE:[^,]+]]
// CHECK: [[TRY]]
// CHECK-DAG: [[RET:%.+]] = call i32 @__tgt_target(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))
// 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]]
+// CHECK-DAG: [[SADDR0:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX0:0]]
+// CHECK-DAG: [[BPADDR0:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 0, i32 [[IDX0]]
+// CHECK-DAG: [[PADDR0:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 0, i32 [[IDX0]]
+// CHECK-DAG: [[SADDR1:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX1:1]]
+// CHECK-DAG: [[BPADDR1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 0, i32 [[IDX1]]
+// CHECK-DAG: [[PADDR1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 0, i32 [[IDX1]]
+// CHECK-DAG: [[SADDR2:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX2:2]]
+// CHECK-DAG: [[BPADDR2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 0, i32 [[IDX2]]
+// CHECK-DAG: [[PADDR2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 0, i32 [[IDX2]]
+// CHECK-DAG: [[SADDR3:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX3:3]]
+// CHECK-DAG: [[BPADDR3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 0, i32 [[IDX3]]
+// CHECK-DAG: [[PADDR3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 0, i32 [[IDX3]]
+// CHECK-DAG: [[SADDR4:%.+]] = getelementptr inbounds [5 x i[[SZ]]], [5 x i[[SZ]]]* [[S]], i32 0, i32 [[IDX4:4]]
+// CHECK-DAG: [[BPADDR4:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BP]], i32 0, i32 [[IDX4]]
+// CHECK-DAG: [[PADDR4:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[P]], i32 0, i32 [[IDX4]]
// 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-DAG: [[CBPADDR3:%.+]] = bitcast i8** [[BPADDR3]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR3:%.+]] = bitcast i8** [[PADDR3]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CBPADDR3]]
+// CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CPADDR3]]
+// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* [[SADDR3]]
+
+// CHECK-DAG: [[CBPADDR2:%.+]] = bitcast i8** [[BPADDR2]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR2:%.+]] = bitcast i8** [[PADDR2]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] 2, i[[SZ]]* [[CBPADDR2]]
+// CHECK-DAG: store i[[SZ]] 2, i[[SZ]]* [[CPADDR2]]
+// CHECK-DAG: store i[[SZ]] {{4|8}}, i[[SZ]]* [[SADDR2]]
+
+// CHECK-DAG: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[B_CVAL]], i[[SZ]]* [[CBPADDR1]]
+// CHECK-DAG: store i[[SZ]] [[B_CVAL]], i[[SZ]]* [[CPADDR1]]
+// CHECK-DAG: store i[[SZ]] 4, i[[SZ]]* [[SADDR1]]
+
+// CHECK-DAG: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to [[S1]]**
+// CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to double**
+// CHECK-DAG: store [[S1]]* %{{.+}}, [[S1]]** [[CBPADDR0]]
+// CHECK-DAG: store double* %{{.+}}, double** [[CPADDR0]]
+// CHECK-DAG: store i[[SZ]] 8, i[[SZ]]* [[SADDR0]]
+
+// CHECK-DAG: [[CBPADDR4:%.+]] = bitcast i8** [[BPADDR4]] to i16**
+// CHECK-DAG: [[CPADDR4:%.+]] = bitcast i8** [[PADDR4]] to i16**
+// CHECK-DAG: store i16* %{{.+}}, i16** [[CBPADDR4]]
+// CHECK-DAG: store i16* %{{.+}}, i16** [[CPADDR4]]
+// CHECK-DAG: store i[[SZ]] [[CSIZE]], i[[SZ]]* [[SADDR4]]
+
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT7:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IFELSE]]
+// CHECK: call void [[HVT7]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[IFEND]]
+
+// CHECK: [[IFEND]]
//
// CHECK: define {{.*}}[[FSTATIC]]
@@ -531,45 +578,44 @@ int bar(int n){
// 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL0:%[^,]+]], i[[SZ]]* [[CBPADDR0]]
+// CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0]]
// 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: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL1:%[^,]+]], i[[SZ]]* [[CBPADDR1]]
+// CHECK-DAG: store i[[SZ]] [[VAL1]], i[[SZ]]* [[CPADDR1]]
// 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: [[CBPADDR2:%.+]] = bitcast i8** [[BPADDR2]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR2:%.+]] = bitcast i8** [[PADDR2]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL2:%[^,]+]], i[[SZ]]* [[CBPADDR2]]
+// CHECK-DAG: store i[[SZ]] [[VAL2]], i[[SZ]]* [[CPADDR2]]
// 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-DAG: [[CBPADDR3:%.+]] = bitcast i8** [[BPADDR3]] to [10 x i32]**
+// CHECK-DAG: [[CPADDR3:%.+]] = bitcast i8** [[PADDR3]] to [10 x i32]**
+// CHECK-DAG: store [10 x i32]* [[VAL3:%[^,]+]], [10 x i32]** [[CBPADDR3]]
+// CHECK-DAG: store [10 x i32]* [[VAL3]], [10 x i32]** [[CPADDR3]]
-// CHECK: [[IFEND]]
-// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
-// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT6:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IFELSE]]
+// CHECK: call void [[HVT6]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[IFEND]]
+
+// CHECK: [[IFEND]]
//
// CHECK: define {{.*}}[[FTEMPLATE]]
@@ -583,41 +629,37 @@ int bar(int n){
// 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL0:%[^,]+]], i[[SZ]]* [[CBPADDR0]]
+// CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0]]
// 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: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL1:%[^,]+]], i[[SZ]]* [[CBPADDR1]]
+// CHECK-DAG: store i[[SZ]] [[VAL1]], i[[SZ]]* [[CPADDR1]]
// 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-DAG: [[CBPADDR2:%.+]] = bitcast i8** [[BPADDR2]] to [10 x i32]**
+// CHECK-DAG: [[CPADDR2:%.+]] = bitcast i8** [[PADDR2]] to [10 x i32]**
+// CHECK-DAG: store [10 x i32]* [[VAL2:%[^,]+]], [10 x i32]** [[CBPADDR2]]
+// CHECK-DAG: store [10 x i32]* [[VAL2]], [10 x i32]** [[CPADDR2]]
-// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT5:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IFELSE]]
+// CHECK: call void [[HVT5]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
// Check that the offloading functions are emitted and that the arguments are
diff --git a/test/OpenMP/target_codegen_global_capture.cpp b/test/OpenMP/target_codegen_global_capture.cpp
index b08bf10f9f..eb34082b29 100644
--- a/test/OpenMP/target_codegen_global_capture.cpp
+++ b/test/OpenMP/target_codegen_global_capture.cpp
@@ -36,10 +36,10 @@ double Gd = 4.0;
// CHECK-SAME: i16 {{[^,]*}}[[B:%[^,]+]],
// CHECK-SAME: i16 {{[^,]*}}[[C:%[^,]+]],
// CHECK-SAME: i16 {{[^,]*}}[[D:%[^,]+]])
-// CHECK: [[LA:%.+]] = alloca i16
-// CHECK: [[LB:%.+]] = alloca i16
-// CHECK: [[LC:%.+]] = alloca i16
-// CHECK: [[LD:%.+]] = alloca i16
+// CHECK: [[LA:%.+]] = alloca i16,
+// CHECK: [[LB:%.+]] = alloca i16,
+// CHECK: [[LC:%.+]] = alloca i16,
+// CHECK: [[LD:%.+]] = alloca i16,
int foo(short a, short b, short c, short d){
static float Sa = 5.0;
static float Sb = 6.0;
@@ -61,22 +61,22 @@ int foo(short a, short b, short c, short d){
// CHECK-DAG: store i16 [[VALLB]], i16* [[CONVLB:%.+]],
// CHECK-DAG: [[CONVLB]] = bitcast i[[sz:64|32]]* [[CADDRLB:%.+]] to i16*
// CHECK-DAG: [[CVALLB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLB]],
- // CHECK-DAG: [[CPTRLB:%.+]] = inttoptr i[[sz]] [[CVALLB]] to i8*
- // CHECK-DAG: store i8* [[CPTRLB]], i8** [[GEPLB:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLB:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store i16 [[VALLC]], i16* [[CONVLC:%.+]],
// CHECK-DAG: [[CONVLC]] = bitcast i[[sz]]* [[CADDRLC:%.+]] to i16*
// CHECK-DAG: [[CVALLC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLC]],
- // CHECK-DAG: [[CPTRLC:%.+]] = inttoptr i[[sz]] [[CVALLC]] to i8*
- // CHECK-DAG: store i8* [[CPTRLC]], i8** [[GEPLC:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLC:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store i16 [[VALLD]], i16* [[CONVLD:%.+]],
// CHECK-DAG: [[CONVLD]] = bitcast i[[sz]]* [[CADDRLD:%.+]] to i16*
// CHECK-DAG: [[CVALLD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLD]],
- // CHECK-DAG: [[CPTRLD:%.+]] = inttoptr i[[sz]] [[CVALLD]] to i8*
- // CHECK-DAG: store i8* [[CPTRLD]], i8** [[GEPLD:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLD:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// 3 static vars being captured.
@@ -84,22 +84,22 @@ int foo(short a, short b, short c, short d){
// CHECK-DAG: store float [[VALFB]], float* [[CONVFB:%.+]],
// CHECK-DAG: [[CONVFB]] = bitcast i[[sz]]* [[CADDRFB:%.+]] to float*
// CHECK-DAG: [[CVALFB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFB]],
- // CHECK-DAG: [[CPTRFB:%.+]] = inttoptr i[[sz]] [[CVALFB]] to i8*
- // CHECK-DAG: store i8* [[CPTRFB]], i8** [[GEPFB:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFB:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store float [[VALFC]], float* [[CONVFC:%.+]],
// CHECK-DAG: [[CONVFC]] = bitcast i[[sz]]* [[CADDRFC:%.+]] to float*
// CHECK-DAG: [[CVALFC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFC]],
- // CHECK-DAG: [[CPTRFC:%.+]] = inttoptr i[[sz]] [[CVALFC]] to i8*
- // CHECK-DAG: store i8* [[CPTRFC]], i8** [[GEPFC:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFC:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store float [[VALFD]], float* [[CONVFD:%.+]],
// CHECK-DAG: [[CONVFD]] = bitcast i[[sz]]* [[CADDRFD:%.+]] to float*
// CHECK-DAG: [[CVALFD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFD]],
- // CHECK-DAG: [[CPTRFD:%.+]] = inttoptr i[[sz]] [[CVALFD]] to i8*
- // CHECK-DAG: store i8* [[CPTRFD]], i8** [[GEPFD:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFD:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// 3 static global vars being captured.
@@ -107,25 +107,28 @@ int foo(short a, short b, short c, short d){
// CHECK-64-DAG: store double [[VALGB]], double* [[CONVGB:%.+]],
// CHECK-64-DAG: [[CONVGB]] = bitcast i[[sz]]* [[CADDRGB:%.+]] to double*
// CHECK-64-DAG: [[CVALGB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGB]],
- // CHECK-64-DAG: [[CPTRGB:%.+]] = inttoptr i[[sz]] [[CVALGB]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGB]], i8** [[GEPGB:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gb to i8*), i8** [[GEPGB:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGB:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gb, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGB:%.+]] to double**
// CHECK-DAG: [[GEPGB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-64-DAG: store double [[VALGC]], double* [[CONVGC:%.+]],
// CHECK-64-DAG: [[CONVGC]] = bitcast i[[sz]]* [[CADDRGC:%.+]] to double*
// CHECK-64-DAG: [[CVALGC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGC]],
- // CHECK-64-DAG: [[CPTRGC:%.+]] = inttoptr i[[sz]] [[CVALGC]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGC]], i8** [[GEPGC:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gc to i8*), i8** [[GEPGC:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGC:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gc, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGC:%.+]] to double**
// CHECK-DAG: [[GEPGC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-64-DAG: store double [[VALGD]], double* [[CONVGD:%.+]],
// CHECK-64-DAG: [[CONVGD]] = bitcast i[[sz]]* [[CADDRGD:%.+]] to double*
// CHECK-64-DAG: [[CVALGD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGD]],
- // CHECK-64-DAG: [[CPTRGD:%.+]] = inttoptr i[[sz]] [[CVALGD]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGD]], i8** [[GEPGD:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gd to i8*), i8** [[GEPGD:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGD:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gd, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGD:%.+]] to double**
// CHECK-DAG: [[GEPGD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK: call i32 @__tgt_target
@@ -197,22 +200,22 @@ int bar(short a, short b, short c, short d){
// CHECK-DAG: store i16 [[VALLB]], i16* [[CONVLB:%.+]],
// CHECK-DAG: [[CONVLB]] = bitcast i[[sz:64|32]]* [[CADDRLB:%.+]] to i16*
// CHECK-DAG: [[CVALLB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLB]],
- // CHECK-DAG: [[CPTRLB:%.+]] = inttoptr i[[sz]] [[CVALLB]] to i8*
- // CHECK-DAG: store i8* [[CPTRLB]], i8** [[GEPLB:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLB:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store i16 [[VALLC]], i16* [[CONVLC:%.+]],
// CHECK-DAG: [[CONVLC]] = bitcast i[[sz]]* [[CADDRLC:%.+]] to i16*
// CHECK-DAG: [[CVALLC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLC]],
- // CHECK-DAG: [[CPTRLC:%.+]] = inttoptr i[[sz]] [[CVALLC]] to i8*
- // CHECK-DAG: store i8* [[CPTRLC]], i8** [[GEPLC:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLC:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store i16 [[VALLD]], i16* [[CONVLD:%.+]],
// CHECK-DAG: [[CONVLD]] = bitcast i[[sz]]* [[CADDRLD:%.+]] to i16*
// CHECK-DAG: [[CVALLD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLD]],
- // CHECK-DAG: [[CPTRLD:%.+]] = inttoptr i[[sz]] [[CVALLD]] to i8*
- // CHECK-DAG: store i8* [[CPTRLD]], i8** [[GEPLD:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLD:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// 3 static vars being captured.
@@ -220,22 +223,22 @@ int bar(short a, short b, short c, short d){
// CHECK-DAG: store float [[VALFB]], float* [[CONVFB:%.+]],
// CHECK-DAG: [[CONVFB]] = bitcast i[[sz]]* [[CADDRFB:%.+]] to float*
// CHECK-DAG: [[CVALFB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFB]],
- // CHECK-DAG: [[CPTRFB:%.+]] = inttoptr i[[sz]] [[CVALFB]] to i8*
- // CHECK-DAG: store i8* [[CPTRFB]], i8** [[GEPFB:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFB:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store float [[VALFC]], float* [[CONVFC:%.+]],
// CHECK-DAG: [[CONVFC]] = bitcast i[[sz]]* [[CADDRFC:%.+]] to float*
// CHECK-DAG: [[CVALFC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFC]],
- // CHECK-DAG: [[CPTRFC:%.+]] = inttoptr i[[sz]] [[CVALFC]] to i8*
- // CHECK-DAG: store i8* [[CPTRFC]], i8** [[GEPFC:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFC:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store float [[VALFD]], float* [[CONVFD:%.+]],
// CHECK-DAG: [[CONVFD]] = bitcast i[[sz]]* [[CADDRFD:%.+]] to float*
// CHECK-DAG: [[CVALFD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFD]],
- // CHECK-DAG: [[CPTRFD:%.+]] = inttoptr i[[sz]] [[CVALFD]] to i8*
- // CHECK-DAG: store i8* [[CPTRFD]], i8** [[GEPFD:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFD:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// 3 static global vars being captured.
@@ -243,25 +246,28 @@ int bar(short a, short b, short c, short d){
// CHECK-64-DAG: store double [[VALGB]], double* [[CONVGB:%.+]],
// CHECK-64-DAG: [[CONVGB]] = bitcast i[[sz]]* [[CADDRGB:%.+]] to double*
// CHECK-64-DAG: [[CVALGB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGB]],
- // CHECK-64-DAG: [[CPTRGB:%.+]] = inttoptr i[[sz]] [[CVALGB]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGB]], i8** [[GEPGB:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gb to i8*), i8** [[GEPGB:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGB:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gb, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGB:%.+]] to double**
// CHECK-DAG: [[GEPGB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-64-DAG: store double [[VALGC]], double* [[CONVGC:%.+]],
// CHECK-64-DAG: [[CONVGC]] = bitcast i[[sz]]* [[CADDRGC:%.+]] to double*
// CHECK-64-DAG: [[CVALGC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGC]],
- // CHECK-64-DAG: [[CPTRGC:%.+]] = inttoptr i[[sz]] [[CVALGC]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGC]], i8** [[GEPGC:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gc to i8*), i8** [[GEPGC:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGC:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gc, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGC:%.+]] to double**
// CHECK-DAG: [[GEPGC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-64-DAG: store double [[VALGD]], double* [[CONVGD:%.+]],
// CHECK-64-DAG: [[CONVGD]] = bitcast i[[sz]]* [[CADDRGD:%.+]] to double*
// CHECK-64-DAG: [[CVALGD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGD]],
- // CHECK-64-DAG: [[CPTRGD:%.+]] = inttoptr i[[sz]] [[CVALGD]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGD]], i8** [[GEPGD:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gd to i8*), i8** [[GEPGD:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGD:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gd, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGD:%.+]] to double**
// CHECK-DAG: [[GEPGD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK: call i32 @__tgt_target
@@ -339,22 +345,22 @@ int tbar(T a, T b, T c, T d){
// CHECK-DAG: store i16 [[VALLB]], i16* [[CONVLB:%.+]],
// CHECK-DAG: [[CONVLB]] = bitcast i[[sz:64|32]]* [[CADDRLB:%.+]] to i16*
// CHECK-DAG: [[CVALLB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLB]],
- // CHECK-DAG: [[CPTRLB:%.+]] = inttoptr i[[sz]] [[CVALLB]] to i8*
- // CHECK-DAG: store i8* [[CPTRLB]], i8** [[GEPLB:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLB:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store i16 [[VALLC]], i16* [[CONVLC:%.+]],
// CHECK-DAG: [[CONVLC]] = bitcast i[[sz]]* [[CADDRLC:%.+]] to i16*
// CHECK-DAG: [[CVALLC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLC]],
- // CHECK-DAG: [[CPTRLC:%.+]] = inttoptr i[[sz]] [[CVALLC]] to i8*
- // CHECK-DAG: store i8* [[CPTRLC]], i8** [[GEPLC:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLC:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store i16 [[VALLD]], i16* [[CONVLD:%.+]],
// CHECK-DAG: [[CONVLD]] = bitcast i[[sz]]* [[CADDRLD:%.+]] to i16*
// CHECK-DAG: [[CVALLD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRLD]],
- // CHECK-DAG: [[CPTRLD:%.+]] = inttoptr i[[sz]] [[CVALLD]] to i8*
- // CHECK-DAG: store i8* [[CPTRLD]], i8** [[GEPLD:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALLD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPLD:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPLD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// 3 static vars being captured.
@@ -362,22 +368,22 @@ int tbar(T a, T b, T c, T d){
// CHECK-DAG: store float [[VALFB]], float* [[CONVFB:%.+]],
// CHECK-DAG: [[CONVFB]] = bitcast i[[sz]]* [[CADDRFB:%.+]] to float*
// CHECK-DAG: [[CVALFB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFB]],
- // CHECK-DAG: [[CPTRFB:%.+]] = inttoptr i[[sz]] [[CVALFB]] to i8*
- // CHECK-DAG: store i8* [[CPTRFB]], i8** [[GEPFB:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFB:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store float [[VALFC]], float* [[CONVFC:%.+]],
// CHECK-DAG: [[CONVFC]] = bitcast i[[sz]]* [[CADDRFC:%.+]] to float*
// CHECK-DAG: [[CVALFC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFC]],
- // CHECK-DAG: [[CPTRFC:%.+]] = inttoptr i[[sz]] [[CVALFC]] to i8*
- // CHECK-DAG: store i8* [[CPTRFC]], i8** [[GEPFC:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFC:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-DAG: store float [[VALFD]], float* [[CONVFD:%.+]],
// CHECK-DAG: [[CONVFD]] = bitcast i[[sz]]* [[CADDRFD:%.+]] to float*
// CHECK-DAG: [[CVALFD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRFD]],
- // CHECK-DAG: [[CPTRFD:%.+]] = inttoptr i[[sz]] [[CVALFD]] to i8*
- // CHECK-DAG: store i8* [[CPTRFD]], i8** [[GEPFD:%.+]],
+ // CHECK-DAG: store i[[sz]] [[CVALFD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-DAG: [[CBP]] = bitcast i8** [[GEPFD:%.+]] to i[[sz]]*
// CHECK-DAG: [[GEPFD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// 3 static global vars being captured.
@@ -385,25 +391,28 @@ int tbar(T a, T b, T c, T d){
// CHECK-64-DAG: store double [[VALGB]], double* [[CONVGB:%.+]],
// CHECK-64-DAG: [[CONVGB]] = bitcast i[[sz]]* [[CADDRGB:%.+]] to double*
// CHECK-64-DAG: [[CVALGB:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGB]],
- // CHECK-64-DAG: [[CPTRGB:%.+]] = inttoptr i[[sz]] [[CVALGB]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGB]], i8** [[GEPGB:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gb to i8*), i8** [[GEPGB:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGB]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGB:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gb, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGB:%.+]] to double**
// CHECK-DAG: [[GEPGB]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-64-DAG: store double [[VALGC]], double* [[CONVGC:%.+]],
// CHECK-64-DAG: [[CONVGC]] = bitcast i[[sz]]* [[CADDRGC:%.+]] to double*
// CHECK-64-DAG: [[CVALGC:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGC]],
- // CHECK-64-DAG: [[CPTRGC:%.+]] = inttoptr i[[sz]] [[CVALGC]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGC]], i8** [[GEPGC:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gc to i8*), i8** [[GEPGC:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGC]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGC:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gc, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGC:%.+]] to double**
// CHECK-DAG: [[GEPGC]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK-64-DAG: store double [[VALGD]], double* [[CONVGD:%.+]],
// CHECK-64-DAG: [[CONVGD]] = bitcast i[[sz]]* [[CADDRGD:%.+]] to double*
// CHECK-64-DAG: [[CVALGD:%.+]] = load i[[sz]], i[[sz]]* [[CADDRGD]],
- // CHECK-64-DAG: [[CPTRGD:%.+]] = inttoptr i[[sz]] [[CVALGD]] to i8*
- // CHECK-64-DAG: store i8* [[CPTRGD]], i8** [[GEPGD:%.+]],
- // CHECK-32-DAG: store i8* bitcast (double* @Gd to i8*), i8** [[GEPGD:%.+]],
+ // CHECK-64-DAG: store i[[sz]] [[CVALGD]], i[[sz]]* [[CBP:%.+]],
+ // CHECK-64-DAG: [[CBP]] = bitcast i8** [[GEPGD:%.+]] to i[[sz]]*
+ // CHECK-32-DAG: store double* @Gd, double** [[CBP:%.+]],
+ // CHECK-32-DAG: [[CBP]] = bitcast i8** [[GEPGD:%.+]] to double**
// CHECK-DAG: [[GEPGD]] = getelementptr inbounds [9 x i8*], [9 x i8*]* %{{.+}}, i32 0, i32 {{[0-8]}}
// CHECK: call i32 @__tgt_target
diff --git a/test/OpenMP/target_codegen_registration.cpp b/test/OpenMP/target_codegen_registration.cpp
index f2721b77fe..064c15b8d8 100644
--- a/test/OpenMP/target_codegen_registration.cpp
+++ b/test/OpenMP/target_codegen_registration.cpp
@@ -36,6 +36,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// CHECK-DAG: [[A1:@.+]] = internal global [[SA]]
// CHECK-DAG: [[A2:@.+]] = global [[SA]]
// CHECK-DAG: [[B1:@.+]] = global [[SB]]
@@ -153,15 +155,15 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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-SAME: { i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
// CHECK-NTARGET: @llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
@@ -364,14 +366,16 @@ struct ST {
// Check registration and unregistration
-//CHECK: define internal void [[UNREGFN:@.+]](i8*)
+//CHECK: define internal void @[[UNREGFN:.+]](i8*)
+//CHECK-SAME: comdat($[[REGFN]]) {
//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: define linkonce hidden void @[[REGFN]](i8*)
+//CHECK-SAME: comdat {
//CHECK: call i32 @__tgt_register_lib([[DSCTY]]* [[DESC]])
-//CHECK: call i32 @__cxa_atexit(void (i8*)* [[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
+//CHECK: call i32 @__cxa_atexit(void (i8*)* @[[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
//CHECK: ret void
//CHECK: declare i32 @__tgt_register_lib([[DSCTY]]*)
@@ -407,31 +411,31 @@ int bar(int a){
// 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]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 195, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 245, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 261, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 267, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 406, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 290, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 290, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 220, 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]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 195, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 245, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 261, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 267, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 406, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 290, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 290, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 220, i32 {{[0-9]+}}}
#endif
diff --git a/test/OpenMP/target_data_codegen.cpp b/test/OpenMP/target_data_codegen.cpp
index a149ba9332..7e5e267d13 100644
--- a/test/OpenMP/target_data_codegen.cpp
+++ b/test/OpenMP/target_data_codegen.cpp
@@ -45,8 +45,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x double]**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [100 x double]**
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[CBP0]]
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[CP0]]
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
@@ -71,10 +73,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK1-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK1-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK1: br label %[[IFEND:[^,]+]]
// CK1: [[IFELSE]]
@@ -103,11 +105,11 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK1-DAG: store float* [[VAR0:%.+]], float** [[CBP0]]
+ // CK1-DAG: store float* [[VAR0]], float** [[CP0]]
// CK1-DAG: store i[[sz]] [[CSVAL0:%[^,]+]], i[[sz]]* [[S0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast float* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast float* [[VAR0]] to i8*
// CK1-DAG: [[CSVAL0]] = mul nuw i[[sz]] %{{[^,]+}}, 4
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
@@ -128,15 +130,18 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([[ST]]* @gb to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+ // CK1-DAG: store [[ST]]* @gb, [[ST]]** [[CBP0]]
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CP0]]
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[BP1]]
- // CK1-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK1-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%.+]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CBP1]]
+ // CK1-DAG: store double* [[SEC1:%.+]], double** [[CP1]]
// CK1-DAG: [[SEC1]] = getelementptr inbounds {{.+}}double* [[SEC11:%[^,]+]], i{{.+}} 0
// CK1-DAG: [[SEC11]] = load double*, double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1),
@@ -191,19 +196,19 @@ int bar(int arg){
// CK2-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK2-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK2-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK2-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK2-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
-// CK2-DAG: [[CPVAL0]] = bitcast double** [[SEC0:%[^,]+]] to i8*
+// CK2-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+// CK2-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+// CK2-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+// CK2-DAG: store double** [[SEC0:%.+]], double*** [[CP0]]
// CK2-DAG: [[SEC0]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK2-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK2-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK2-DAG: [[CBPVAL1]] = bitcast double** [[SEC0]] to i8*
-// CK2-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%[^,]+]] to i8*
+// CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+// CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+// CK2-DAG: store double** [[SEC0]], double*** [[CBP1]]
+// CK2-DAG: store double* [[SEC1:%.+]], double** [[CP1]]
// CK2-DAG: [[SEC1]] = getelementptr inbounds {{.*}}double* [[SEC11:%[^,]+]], i{{.+}} 1
// CK2-DAG: [[SEC11]] = load double*, double** [[SEC111:%[^,]+]],
// CK2-DAG: [[SEC111]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
diff --git a/test/OpenMP/target_data_messages.c b/test/OpenMP/target_data_messages.c
index 153b437729..fd41e7df2a 100644
--- a/test/OpenMP/target_data_messages.c
+++ b/test/OpenMP/target_data_messages.c
@@ -4,7 +4,7 @@ void foo() { }
int main(int argc, char **argv) {
int a;
- #pragma omp target data // expected-error {{expected at least one map clause for '#pragma omp target data'}}
+ #pragma omp target data // expected-error {{expected at least one 'map' or 'use_device_ptr' clause for '#pragma omp target data'}}
{}
L1:
foo();
diff --git a/test/OpenMP/target_data_use_device_ptr_codegen.cpp b/test/OpenMP/target_data_use_device_ptr_codegen.cpp
index c4b389a4cb..5e27556517 100644
--- a/test/OpenMP/target_data_use_device_ptr_codegen.cpp
+++ b/test/OpenMP/target_data_use_device_ptr_codegen.cpp
@@ -33,12 +33,11 @@ void foo(float *&lr, T *&tr) {
float *l;
T *t;
- // CK1-DAG: [[RVAL:%.+]] = bitcast double* [[T:%.+]] to i8*
- // CK1-DAG: [[T]] = load double*, double** [[DECL:@g]],
+ // CK1: [[T:%.+]] = load double*, double** [[DECL:@g]],
// CK1: [[BP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE00]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to double**
+ // CK1: store double* [[T]], double** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE00]]
// CK1: [[VAL:%.+]] = load double*, double** [[CBP]],
// CK1-NOT: store double* [[VAL]], double** [[DECL]],
// CK1: store double* [[VAL]], double** [[PVT:%.+]],
@@ -53,12 +52,11 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds double, double* [[TTT]], i32 1
++g;
- // CK1-DAG: [[RVAL:%.+]] = bitcast float* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load float*, float** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load float*, float** [[DECL:%.+]],
// CK1: [[BP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE01]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to float**
+ // CK1: store float* [[T1]], float** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE01]]
// CK1: [[VAL:%.+]] = load float*, float** [[CBP]],
// CK1-NOT: store float* [[VAL]], float** [[DECL]],
// CK1: store float* [[VAL]], float** [[PVT:%.+]],
@@ -85,12 +83,11 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds float, float* [[TTT]], i32 1
++l;
- // CK1-DAG: [[RVAL:%.+]] = bitcast float* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load float*, float** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load float*, float** [[DECL:%.+]],
// CK1: [[BP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE03]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to float**
+ // CK1: store float* [[T1]], float** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE03]]
// CK1: [[VAL:%.+]] = load float*, float** [[CBP]],
// CK1-NOT: store float* [[VAL]], float** [[DECL]],
// CK1: store float* [[VAL]], float** [[PVT:%.+]],
@@ -109,12 +106,11 @@ void foo(float *&lr, T *&tr) {
// CK1: br i1 [[CMP]], label %[[BTHEN:.+]], label %[[BELSE:.+]]
// CK1: [[BTHEN]]:
- // CK1-DAG: [[RVAL:%.+]] = bitcast float* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load float*, float** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load float*, float** [[DECL:%.+]],
// CK1: [[BP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE04]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to float**
+ // CK1: store float* [[T1]], float** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE04]]
// CK1: [[VAL:%.+]] = load float*, float** [[CBP]],
// CK1-NOT: store float* [[VAL]], float** [[DECL]],
// CK1: store float* [[VAL]], float** [[PVT:%.+]],
@@ -146,13 +142,12 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds float, float* [[TTT]], i32 1
++l;
- // CK1-DAG: [[RVAL:%.+]] = bitcast float* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load float*, float** [[T2:%.+]],
- // CK1-DAG: [[T2]] = load float**, float*** [[DECL:%.+]],
+ // CK1: [[T2:%.+]] = load float**, float*** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load float*, float** [[T2]],
// CK1: [[BP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE05]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to float**
+ // CK1: store float* [[T1]], float** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE05]]
// CK1: [[VAL:%.+]] = load float*, float** [[CBP]],
// CK1: store float* [[VAL]], float** [[PVTV:%.+]],
// CK1-NOT: store float** [[PVTV]], float*** [[DECL]],
@@ -170,12 +165,11 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds float, float* [[TTTT]], i32 1
++lr;
- // CK1-DAG: [[RVAL:%.+]] = bitcast i32* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load i32*, i32** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load i32*, i32** [[DECL:%.+]],
// CK1: [[BP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE06]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to i32**
+ // CK1: store i32* [[T1]], i32** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE06]]
// CK1: [[VAL:%.+]] = load i32*, i32** [[CBP]],
// CK1-NOT: store i32* [[VAL]], i32** [[DECL]],
// CK1: store i32* [[VAL]], i32** [[PVT:%.+]],
@@ -190,13 +184,12 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds i32, i32* [[TTT]], i32 1
++t;
- // CK1-DAG: [[RVAL:%.+]] = bitcast i32* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load i32*, i32** [[T2:%.+]],
- // CK1-DAG: [[T2]] = load i32**, i32*** [[DECL:%.+]],
+ // CK1: [[T2:%.+]] = load i32**, i32*** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load i32*, i32** [[T2]],
// CK1: [[BP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE07]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to i32**
+ // CK1: store i32* [[T1]], i32** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE07]]
// CK1: [[VAL:%.+]] = load i32*, i32** [[CBP]],
// CK1: store i32* [[VAL]], i32** [[PVTV:%.+]],
// CK1-NOT: store i32** [[PVTV]], i32*** [[DECL]],
@@ -214,12 +207,11 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds i32, i32* [[TTTT]], i32 1
++tr;
- // CK1-DAG: [[RVAL:%.+]] = bitcast float* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load float*, float** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load float*, float** [[DECL:%.+]],
// CK1: [[BP:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %{{.+}}, i32 0, i32
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE08]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to float**
+ // CK1: store float* [[T1]], float** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE08]]
// CK1: [[VAL:%.+]] = load float*, float** [[CBP]],
// CK1-NOT: store float* [[VAL]], float** [[DECL]],
// CK1: store float* [[VAL]], float** [[PVT:%.+]],
@@ -235,11 +227,11 @@ void foo(float *&lr, T *&tr) {
++l; ++t;
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE09]]
// CK1: [[_CBP:%.+]] = bitcast i8** {{%.+}} to float**
+ // CK1: [[CBP:%.+]] = bitcast i8** {{%.+}} to i32**
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE09]]
// CK1: [[_VAL:%.+]] = load float*, float** [[_CBP]],
// CK1: store float* [[_VAL]], float** [[_PVT:%.+]],
- // CK1: [[CBP:%.+]] = bitcast i8** {{%.+}} to i32**
// CK1: [[VAL:%.+]] = load i32*, i32** [[CBP]],
// CK1: store i32* [[VAL]], i32** [[PVT:%.+]],
// CK1: [[_TT1:%.+]] = load float*, float** [[_PVT]],
@@ -257,11 +249,11 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds i32, i32* [[TTT]], i32 1
++l; ++t;
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE10]]
// CK1: [[_CBP:%.+]] = bitcast i8** {{%.+}} to float**
+ // CK1: [[CBP:%.+]] = bitcast i8** {{%.+}} to i32**
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE10]]
// CK1: [[_VAL:%.+]] = load float*, float** [[_CBP]],
// CK1: store float* [[_VAL]], float** [[_PVT:%.+]],
- // CK1: [[CBP:%.+]] = bitcast i8** {{%.+}} to i32**
// CK1: [[VAL:%.+]] = load i32*, i32** [[CBP]],
// CK1: store i32* [[VAL]], i32** [[PVT:%.+]],
// CK1: [[_TT1:%.+]] = load float*, float** [[_PVT]],
@@ -279,12 +271,11 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds i32, i32* [[TTT]], i32 1
++l; ++t;
- // CK1-DAG: [[RVAL:%.+]] = bitcast i32* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load i32*, i32** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load i32*, i32** [[DECL:%.+]],
// CK1: [[BP:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE11]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to i32**
+ // CK1: store i32* [[T1]], i32** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE11]]
// CK1: [[VAL:%.+]] = load i32*, i32** [[CBP]],
// CK1-NOT: store i32* [[VAL]], i32** [[DECL]],
// CK1: store i32* [[VAL]], i32** [[PVT:%.+]],
@@ -299,13 +290,12 @@ void foo(float *&lr, T *&tr) {
// CK1: getelementptr inbounds i32, i32* [[TTT]], i32 1
++l; ++t;
- // CK1-DAG: [[RVAL:%.+]] = bitcast i32* [[T1:%.+]] to i8*
- // CK1-DAG: [[T1]] = load i32*, i32** [[T2:%.+]],
- // CK1-DAG: [[T2]] = load i32**, i32*** [[DECL:%.+]],
+ // CK1: [[T2:%.+]] = load i32**, i32*** [[DECL:%.+]],
+ // CK1: [[T1:%.+]] = load i32*, i32** [[T2]],
// CK1: [[BP:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %{{.+}}, i32 0, i32 0
- // CK1: store i8* [[RVAL]], i8** [[BP]],
- // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE12]]
// CK1: [[CBP:%.+]] = bitcast i8** [[BP]] to i32**
+ // CK1: store i32* [[T1]], i32** [[CBP]],
+ // CK1: call void @__tgt_target_data_begin{{.+}}[[MTYPE12]]
// CK1: [[VAL:%.+]] = load i32*, i32** [[CBP]],
// CK1: store i32* [[VAL]], i32** [[PVTV:%.+]],
// CK1-NOT: store i32** [[PVTV]], i32*** [[DECL]],
@@ -356,10 +346,11 @@ struct ST {
int *la = 0;
// CK2: [[BP:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %{{.+}}, i32 0, i32 1
- // CK2: store i8* [[RVAL:%.+]], i8** [[BP]],
+ // CK2: [[CBP:%.+]] = bitcast i8** [[BP]] to double***
+ // CK2: store double** [[RVAL:%.+]], double*** [[CBP]],
// CK2: call void @__tgt_target_data_begin{{.+}}[[MTYPE00]]
- // CK2: [[CBP:%.+]] = bitcast i8** [[BP]] to double**
- // CK2: [[VAL:%.+]] = load double*, double** [[CBP]],
+ // CK2: [[CBP1:%.+]] = bitcast double*** [[CBP]] to double**
+ // CK2: [[VAL:%.+]] = load double*, double** [[CBP1]],
// CK2: store double* [[VAL]], double** [[PVT:%.+]],
// CK2: store double** [[PVT]], double*** [[PVT2:%.+]],
// CK2: [[TT1:%.+]] = load double**, double*** [[PVT2]],
@@ -376,10 +367,11 @@ struct ST {
a++;
// CK2: [[BP:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* %{{.+}}, i32 0, i32 2
- // CK2: store i8* [[RVAL:%.+]], i8** [[BP]],
+ // CK2: [[CBP:%.+]] = bitcast i8** [[BP]] to double***
+ // CK2: store double** [[RVAL:%.+]], double*** [[CBP]],
// CK2: call void @__tgt_target_data_begin{{.+}}[[MTYPE01]]
- // CK2: [[CBP:%.+]] = bitcast i8** [[BP]] to double**
- // CK2: [[VAL:%.+]] = load double*, double** [[CBP]],
+ // CK2: [[CBP1:%.+]] = bitcast double*** [[CBP]] to double**
+ // CK2: [[VAL:%.+]] = load double*, double** [[CBP1]],
// CK2: store double* [[VAL]], double** [[PVT:%.+]],
// CK2: store double** [[PVT]], double*** [[PVT2:%.+]],
// CK2: [[TT1:%.+]] = load double**, double*** [[PVT2]],
@@ -397,9 +389,9 @@ struct ST {
b++;
// CK2: [[BP:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %{{.+}}, i32 0, i32 0
- // CK2: store i8* [[RVAL:%.+]], i8** [[BP]],
- // CK2: call void @__tgt_target_data_begin{{.+}}[[MTYPE02]]
// CK2: [[CBP:%.+]] = bitcast i8** [[BP]] to double**
+ // CK2: store double* [[RVAL:%.+]], double** [[CBP]],
+ // CK2: call void @__tgt_target_data_begin{{.+}}[[MTYPE02]]
// CK2: [[VAL:%.+]] = load double*, double** [[CBP]],
// CK2: store double* [[VAL]], double** [[PVT:%.+]],
// CK2: store double** [[PVT]], double*** [[PVT2:%.+]],
@@ -419,16 +411,17 @@ struct ST {
la++;
// CK2: [[BP:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* %{{.+}}, i32 0, i32 0
- // CK2: store i8* [[RVAL:%.+]], i8** [[BP]],
+ // CK2: [[CBP:%.+]] = bitcast i8** [[BP]] to double**
+ // CK2: store double* [[RVAL:%.+]], double** [[CBP]],
// CK2: [[_BP:%.+]] = getelementptr inbounds [4 x i8*], [4 x i8*]* %{{.+}}, i32 0, i32 3
- // CK2: store i8* [[_RVAL:%.+]], i8** [[_BP]],
+ // CK2: [[_CBP:%.+]] = bitcast i8** [[_BP]] to double***
+ // CK2: store double** [[_RVAL:%.+]], double*** [[_CBP]],
// CK2: call void @__tgt_target_data_begin{{.+}}[[MTYPE03]]
- // CK2: [[CBP:%.+]] = bitcast i8** [[BP]] to double**
// CK2: [[VAL:%.+]] = load double*, double** [[CBP]],
// CK2: store double* [[VAL]], double** [[PVT:%.+]],
// CK2: store double** [[PVT]], double*** [[PVT2:%.+]],
- // CK2: [[_CBP:%.+]] = bitcast i8** [[_BP]] to double**
- // CK2: [[_VAL:%.+]] = load double*, double** [[_CBP]],
+ // CK2: [[_CBP1:%.+]] = bitcast double*** [[_CBP]] to double**
+ // CK2: [[_VAL:%.+]] = load double*, double** [[_CBP1]],
// CK2: store double* [[_VAL]], double** [[_PVT:%.+]],
// CK2: store double** [[_PVT]], double*** [[_PVT2:%.+]],
// CK2: [[TT1:%.+]] = load double**, double*** [[PVT2]],
diff --git a/test/OpenMP/target_depend_messages.cpp b/test/OpenMP/target_depend_messages.cpp
index 48bd94180c..3eb3af132d 100644
--- a/test/OpenMP/target_depend_messages.cpp
+++ b/test/OpenMP/target_depend_messages.cpp
@@ -36,21 +36,21 @@ int main(int argc, char **argv, char *env[]) {
foo();
#pragma omp target depend (out: ) // expected-error {{expected expression}}
foo();
- #pragma omp target depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
foo();
#pragma omp target depend (out :S1) // expected-error {{'S1' does not refer to a value}}
foo();
- #pragma omp target depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target depend(in : argv[1][1] = '2')
foo();
- #pragma omp target depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target depend (in : argv[0])
foo();
#pragma omp target depend (in : ) // expected-error {{expected expression}}
foo();
- #pragma omp target depend (in : main) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target depend (in : main)
foo();
- #pragma omp target depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
foo();
diff --git a/test/OpenMP/target_enter_data_codegen.cpp b/test/OpenMP/target_enter_data_codegen.cpp
index 152cd46b4a..683cd976d3 100644
--- a/test/OpenMP/target_enter_data_codegen.cpp
+++ b/test/OpenMP/target_enter_data_codegen.cpp
@@ -45,8 +45,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x double]**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [100 x double]**
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[CBP0]]
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[CP0]]
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
// CK1-NOT: __tgt_target_data_end
@@ -67,10 +69,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK1-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK1-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK1: br label %[[IFEND:[^,]+]]
// CK1: [[IFELSE]]
@@ -93,11 +95,11 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK1-DAG: store float* [[VAR0:%.+]], float** [[CBP0]]
+ // CK1-DAG: store float* [[VAR0]], float** [[CP0]]
// CK1-DAG: store i[[sz]] [[CSVAL0:%[^,]+]], i[[sz]]* [[S0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast float* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast float* [[VAR0]] to i8*
// CK1-DAG: [[CSVAL0]] = mul nuw i[[sz]] %{{[^,]+}}, 4
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
// CK1-NOT: __tgt_target_data_end
@@ -114,15 +116,18 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([[ST]]* @gb to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+ // CK1-DAG: store [[ST]]* @gb, [[ST]]** [[CBP0]]
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CP0]]
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[BP1]]
- // CK1-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK1-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%.+]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CBP1]]
+ // CK1-DAG: store double* [[SEC1:%.+]], double** [[CP1]]
// CK1-DAG: [[SEC1]] = getelementptr inbounds {{.+}}double* [[SEC11:%[^,]+]], i{{.+}} 0
// CK1-DAG: [[SEC11]] = load double*, double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1),
@@ -174,19 +179,19 @@ int bar(int arg){
// CK2-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK2-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK2-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK2-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK2-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
-// CK2-DAG: [[CPVAL0]] = bitcast double** [[SEC0:%[^,]+]] to i8*
+// CK2-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+// CK2-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+// CK2-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+// CK2-DAG: store double** [[SEC0:%.+]], double*** [[CP0]]
// CK2-DAG: [[SEC0]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK2-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK2-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK2-DAG: [[CBPVAL1]] = bitcast double** [[SEC0]] to i8*
-// CK2-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%[^,]+]] to i8*
+// CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+// CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+// CK2-DAG: store double** [[SEC0]], double*** [[CBP1]]
+// CK2-DAG: store double* [[SEC1:%.+]], double** [[CP1]]
// CK2-DAG: [[SEC1]] = getelementptr inbounds {{.*}}double* [[SEC11:%[^,]+]], i{{.+}} 1
// CK2-DAG: [[SEC11]] = load double*, double** [[SEC111:%[^,]+]],
// CK2-DAG: [[SEC111]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
diff --git a/test/OpenMP/target_enter_data_depend_messages.cpp b/test/OpenMP/target_enter_data_depend_messages.cpp
index 4aa122355b..77e7039e8e 100644
--- a/test/OpenMP/target_enter_data_depend_messages.cpp
+++ b/test/OpenMP/target_enter_data_depend_messages.cpp
@@ -38,21 +38,21 @@ int tmain(T argc, S **argv, R *env[]) {
foo();
#pragma omp target enter data map(to: i) depend (out: ) // expected-error {{expected expression}}
foo();
- #pragma omp target enter data map(to: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target enter data map(to: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
foo();
#pragma omp target enter data map(to: i) depend (out :S1) // expected-error {{'S1' does not refer to a value}}
foo();
- #pragma omp target enter data map(to: i) depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend(in : argv[1][1] = '2') // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
- #pragma omp target enter data map(to: i) depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target enter data map(to: i) depend (in : argv[0])
foo();
#pragma omp target enter data map(to: i) depend (in : ) // expected-error {{expected expression}}
foo();
- #pragma omp target enter data map(to: i) depend (in : tmain) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend (in : tmain)
foo();
- #pragma omp target enter data map(to: i) depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target enter data map(to: i) depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
foo();
@@ -113,21 +113,21 @@ int main(int argc, char **argv, char *env[]) {
foo();
#pragma omp target enter data map(to: i) depend (out: ) // expected-error {{expected expression}}
foo();
- #pragma omp target enter data map(to: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target enter data map(to: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
foo();
#pragma omp target enter data map(to: i) depend (out :S1) // expected-error {{'S1' does not refer to a value}}
foo();
- #pragma omp target enter data map(to: i) depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend(in : argv[1][1] = '2')
foo();
- #pragma omp target enter data map(to: i) depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target enter data map(to: i) depend (in : argv[0])
foo();
#pragma omp target enter data map(to: i) depend (in : ) // expected-error {{expected expression}}
foo();
- #pragma omp target enter data map(to: i) depend (in : main) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend (in : main)
foo();
- #pragma omp target enter data map(to: i) depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target enter data map(to: i) depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target enter data map(to: i) depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
foo();
diff --git a/test/OpenMP/target_enter_data_map_messages.c b/test/OpenMP/target_enter_data_map_messages.c
index 6f5aad1ef6..8a7de3b96e 100644
--- a/test/OpenMP/target_enter_data_map_messages.c
+++ b/test/OpenMP/target_enter_data_map_messages.c
@@ -4,7 +4,7 @@
int main(int argc, char **argv) {
int r;
- #pragma omp target enter data // expected-error {{expected at least one map clause for '#pragma omp target enter data'}}
+ #pragma omp target enter data // expected-error {{expected at least one 'map' clause for '#pragma omp target enter data'}}
#pragma omp target enter data map(r) // expected-error {{map type must be specified for '#pragma omp target enter data'}}
#pragma omp target enter data map(tofrom: r) // expected-error {{map type 'tofrom' is not allowed for '#pragma omp target enter data'}}
diff --git a/test/OpenMP/target_enter_data_nowait_messages.cpp b/test/OpenMP/target_enter_data_nowait_messages.cpp
index e682e8c47d..508b1b2549 100644
--- a/test/OpenMP/target_enter_data_nowait_messages.cpp
+++ b/test/OpenMP/target_enter_data_nowait_messages.cpp
@@ -6,7 +6,7 @@ int main(int argc, char **argv) {
#pragma omp nowait target enter data map(to: i) // expected-error {{expected an OpenMP directive}}
#pragma omp target nowait enter data map(to: i) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
#pragma omp target enter nowait data map(to: i) // expected-error {{expected an OpenMP directive}}
- #pragma omp target enter data nowait() map(to: i) // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} expected-error {{expected at least one map clause for '#pragma omp target enter data'}}
+ #pragma omp target enter data nowait() map(to: i) // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}} expected-error {{expected at least one 'map' clause for '#pragma omp target enter data'}}
#pragma omp target enter data map(to: i) nowait( // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
#pragma omp target enter data map(to: i) nowait (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target enter data' are ignored}}
#pragma omp target enter data map(to: i) nowait device (-10u)
diff --git a/test/OpenMP/target_exit_data_codegen.cpp b/test/OpenMP/target_exit_data_codegen.cpp
index d3a38592a6..a82c1c6c4a 100644
--- a/test/OpenMP/target_exit_data_codegen.cpp
+++ b/test/OpenMP/target_exit_data_codegen.cpp
@@ -46,8 +46,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[P0]]
+ // CK1-DAG: [[BPC0:%.+]] = bitcast i8** [[BP0]] to [100 x double]**
+ // CK1-DAG: [[PC0:%.+]] = bitcast i8** [[P0]] to [100 x double]**
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[BPC0]]
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[PC0]]
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
#pragma omp target exit data if(1+3-5) device(arg) map(from: gc)
@@ -68,10 +70,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK1-DAG: store i32* [[VAL0:%[^,]+]], i32** [[CBP0]]
+ // CK1-DAG: store i32* [[VAL0]], i32** [[CP0]]
// CK1: br label %[[IFEND:[^,]+]]
// CK1: [[IFELSE]]
@@ -94,11 +96,11 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK1-DAG: store float* [[VAL0:%[^,]+]], float** [[CBP0]]
+ // CK1-DAG: store float* [[VAL0]], float** [[CP0]]
// CK1-DAG: store i[[sz]] [[CSVAL0:%[^,]+]], i[[sz]]* [[S0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast float* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast float* [[VAR0]] to i8*
// CK1-DAG: [[CSVAL0]] = mul nuw i[[sz]] %{{[^,]+}}, 4
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
#pragma omp target exit data map(always, from: lb)
@@ -115,15 +117,18 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([[ST]]* @gb to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+ // CK1-DAG: store [[ST]]* @gb, [[ST]]** [[CBP0]]
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CP0]]
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[BP1]]
- // CK1-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK1-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%.+]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CBP1]]
+ // CK1-DAG: store double* [[SEC1:%[^,]+]], double** [[CP1]]
// CK1-DAG: [[SEC1]] = getelementptr inbounds {{.+}}double* [[SEC11:%[^,]+]], i{{.+}} 0
// CK1-DAG: [[SEC11]] = load double*, double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1),
@@ -175,19 +180,19 @@ int bar(int arg){
// CK2-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK2-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK2-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK2-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK2-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
-// CK2-DAG: [[CPVAL0]] = bitcast double** [[SEC0:%[^,]+]] to i8*
+// CK2-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+// CK2-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+// CK2-DAG: store [[ST]]* [[VAR0:%[^,]+]], [[ST]]** [[CBP0]]
+// CK2-DAG: store double** [[SEC0:%[^,]+]], double*** [[CP0]]
// CK2-DAG: [[SEC0]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK2-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK2-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK2-DAG: [[CBPVAL1]] = bitcast double** [[SEC0]] to i8*
-// CK2-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%[^,]+]] to i8*
+// CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+// CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+// CK2-DAG: store double** [[SEC0]], double*** [[CBP1]]
+// CK2-DAG: store double* [[SEC1:%[^,]+]], double** [[CP1]]
// CK2-DAG: [[SEC1]] = getelementptr inbounds {{.*}}double* [[SEC11:%[^,]+]], i{{.+}} 1
// CK2-DAG: [[SEC11]] = load double*, double** [[SEC111:%[^,]+]],
// CK2-DAG: [[SEC111]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
diff --git a/test/OpenMP/target_exit_data_depend_messages.cpp b/test/OpenMP/target_exit_data_depend_messages.cpp
index cdefbeed08..ce8d237f75 100644
--- a/test/OpenMP/target_exit_data_depend_messages.cpp
+++ b/test/OpenMP/target_exit_data_depend_messages.cpp
@@ -38,21 +38,21 @@ int tmain(T argc, S **argv, R *env[]) {
foo();
#pragma omp target exit data map(from: i) depend (out: ) // expected-error {{expected expression}}
foo();
- #pragma omp target exit data map(from: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target exit data map(from: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
foo();
#pragma omp target exit data map(from: i) depend (out :S1) // expected-error {{'S1' does not refer to a value}}
foo();
- #pragma omp target exit data map(from: i) depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend(in : argv[1][1] = '2') // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
- #pragma omp target exit data map(from: i) depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target exit data map(from: i) depend (in : argv[0])
foo();
#pragma omp target exit data map(from: i) depend (in : ) // expected-error {{expected expression}}
foo();
- #pragma omp target exit data map(from: i) depend (in : tmain) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend (in : tmain)
foo();
- #pragma omp target exit data map(from: i) depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target exit data map(from: i) depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
foo();
@@ -113,21 +113,21 @@ int main(int argc, char **argv, char *env[]) {
foo();
#pragma omp target exit data map(from: i) depend (out: ) // expected-error {{expected expression}}
foo();
- #pragma omp target exit data map(from: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target exit data map(from: i) depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
foo();
#pragma omp target exit data map(from: i) depend (out :S1) // expected-error {{'S1' does not refer to a value}}
foo();
- #pragma omp target exit data map(from: i) depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend(in : argv[1][1] = '2')
foo();
- #pragma omp target exit data map(from: i) depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target exit data map(from: i) depend (in : argv[0])
foo();
#pragma omp target exit data map(from: i) depend (in : ) // expected-error {{expected expression}}
foo();
- #pragma omp target exit data map(from: i) depend (in : main) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend (in : main)
foo();
- #pragma omp target exit data map(from: i) depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target exit data map(from: i) depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target exit data map(from: i) depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
foo();
diff --git a/test/OpenMP/target_exit_data_map_messages.c b/test/OpenMP/target_exit_data_map_messages.c
index a9953fbbb4..84bd7e79fd 100644
--- a/test/OpenMP/target_exit_data_map_messages.c
+++ b/test/OpenMP/target_exit_data_map_messages.c
@@ -4,7 +4,7 @@
int main(int argc, char **argv) {
int r;
- #pragma omp target exit data // expected-error {{expected at least one map clause for '#pragma omp target exit data'}}
+ #pragma omp target exit data // expected-error {{expected at least one 'map' clause for '#pragma omp target exit data'}}
#pragma omp target exit data map(r) // expected-error {{map type must be specified for '#pragma omp target exit data'}}
#pragma omp target exit data map(tofrom: r) // expected-error {{map type 'tofrom' is not allowed for '#pragma omp target exit data'}}
diff --git a/test/OpenMP/target_exit_data_nowait_messages.cpp b/test/OpenMP/target_exit_data_nowait_messages.cpp
index cd743d8927..d0286031f3 100644
--- a/test/OpenMP/target_exit_data_nowait_messages.cpp
+++ b/test/OpenMP/target_exit_data_nowait_messages.cpp
@@ -6,7 +6,7 @@ int main(int argc, char **argv) {
#pragma omp nowait target exit data map(from: i) // expected-error {{expected an OpenMP directive}}
#pragma omp target nowait exit data map(from: i) // expected-warning {{extra tokens at the end of '#pragma omp target' are ignored}}
#pragma omp target exit nowait data map(from: i) // expected-error {{expected an OpenMP directive}}
- #pragma omp target exit data nowait() map(from: i) // expected-warning {{extra tokens at the end of '#pragma omp target exit data' are ignored}} expected-error {{expected at least one map clause for '#pragma omp target exit data'}}
+ #pragma omp target exit data nowait() map(from: i) // expected-warning {{extra tokens at the end of '#pragma omp target exit data' are ignored}} expected-error {{expected at least one 'map' clause for '#pragma omp target exit data'}}
#pragma omp target exit data map(from: i) nowait( // expected-warning {{extra tokens at the end of '#pragma omp target exit data' are ignored}}
#pragma omp target exit data map(from: i) nowait (argc)) // expected-warning {{extra tokens at the end of '#pragma omp target exit data' are ignored}}
#pragma omp target exit data map(from: i) nowait device (-10u)
diff --git a/test/OpenMP/target_firstprivate_codegen.cpp b/test/OpenMP/target_firstprivate_codegen.cpp
index a9af2d02f2..8eef475814 100644
--- a/test/OpenMP/target_firstprivate_codegen.cpp
+++ b/test/OpenMP/target_firstprivate_codegen.cpp
@@ -37,7 +37,7 @@ struct TT{
// CHECK-DAG: [[MAPT2:@.+]] = private unnamed_addr constant [9 x i32] [i32 288, i32 161, i32 288, i32 161, i32 161, i32 288, i32 288, i32 161, i32 161]
// CHECK-DAG: [[SIZET3:@.+]] = private unnamed_addr constant [1 x i{{32|64}}] zeroinitializer
// CHECK-DAG: [[MAPT3:@.+]] = private unnamed_addr constant [1 x i32] [i32 32]
-// CHECK-DAG: [[MAPT4:@.+]] = private unnamed_addr constant [5 x i32] [i32 35, i32 288, i32 288, i32 288, i32 161]
+// CHECK-DAG: [[MAPT4:@.+]] = private unnamed_addr constant [5 x i32] [i32 547, i32 288, i32 288, i32 288, i32 161]
// CHECK-DAG: [[SIZET5:@.+]] = private unnamed_addr constant [3 x i{{32|64}}] [i[[SZ]] 4, i[[SZ]] 1, i[[SZ]] 40]
// CHECK-DAG: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 288, i32 288, i32 161]
// CHECK-DAG: [[SIZET6:@.+]] = private unnamed_addr constant [2 x i{{32|64}}] [i[[SZ]] 4, i[[SZ]] 40]
@@ -68,7 +68,6 @@ int foo(int n, double *ptr) {
// CHECK: [[C:%.+]] = alloca [5 x [10 x double]],
// CHECK: [[D:%.+]] = alloca [[TT]],
// CHECK: [[ACAST:%.+]] = alloca i{{[0-9]+}},
- // CHECK: {{.+}} = alloca i{{[0-9]+}},
// CHECK: [[BASE_PTR_ARR:%.+]] = alloca [1 x i8*],
// CHECK: [[PTR_ARR:%.+]] = alloca [1 x i8*],
// CHECK: [[A2CAST:%.+]] = alloca i{{[0-9]+}},
@@ -93,12 +92,12 @@ int foo(int n, double *ptr) {
// CHECK-64: store i{{[0-9]+}} [[AVAL]], i{{[0-9]+}}* [[CONV]],
// CHECK-32: store i{{[0-9]+}} [[AVAL]], i{{[0-9]+}}* [[ACAST]],
// CHECK: [[ACAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[ACAST]],
- // CHECK: [[ACAST_TOPTR:%.+]] = inttoptr i{{[0-9]+}} [[ACAST_VAL]] to i8*
// CHECK: [[BASE_PTR_GEP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BASE_PTR_ARR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[ACAST_TOPTR]], i8** [[BASE_PTR_GEP]],
- // CHECK: [[ACAST_TOPTR2:%.+]] = inttoptr i{{[0-9]+}} [[ACAST_VAL]] to i8*
+ // CHECK: [[ACAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[ACAST_VAL]], i{{[0-9]+}}* [[ACAST_TOPTR]],
// CHECK: [[PTR_GEP:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PTR_ARR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[ACAST_TOPTR2]], i8** [[PTR_GEP]],
+ // CHECK: [[ACAST_TOPTR2:%.+]] = bitcast i8** [[PTR_GEP]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[ACAST_VAL]], i{{[0-9]+}}* [[ACAST_TOPTR2]],
// CHECK: [[BASE_PTR_GEP_ARG:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BASE_PTR_ARR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: [[PTR_GEP_ARG:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PTR_ARR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: {{.+}} = call i32 @__tgt_target(i32 -1, {{.+}}, i32 1, i8** [[BASE_PTR_GEP_ARG]], i8** [[PTR_GEP_ARG]], i[[SZ]]* getelementptr inbounds ([1 x i[[SZ]]], [1 x i[[SZ]]]* [[SIZET]], i32 0, i32 0), i32* getelementptr inbounds ([1 x i32], [1 x i32]* [[MAPT]], i32 0, i32 0))
@@ -132,85 +131,87 @@ int foo(int n, double *ptr) {
// CHECK: [[CN_SIZE_2:%.+]] = mul{{.+}} i{{[0-9]+}} [[CN_SIZE_1]], 8
// firstprivate(aa) --> base_ptr = aa, ptr = aa, size = 2 (short)
- // CHECK: [[A2CAST_TO_INT:%.+]] = inttoptr i{{[0-9]+}} [[A2CAST_VAL]] to i8*
// CHECK: [[BASE_PTR_GEP2_0:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[A2CAST_TO_INT]], i8** [[BASE_PTR_GEP2_0]],
- // CHECK: [[A2CAST_TO_INT_2:%.+]] = inttoptr i{{[0-9]+}} [[A2CAST_VAL]] to i8*
+ // CHECK: [[ACAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_0]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[A2CAST_VAL]], i{{[0-9]+}}* [[ACAST_TOPTR]],
// CHECK: [[PTR_GEP2_0:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[A2CAST_TO_INT_2]], i8** [[PTR_GEP2_0]],
+ // CHECK: [[ACAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_0]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[A2CAST_VAL]], i{{[0-9]+}}* [[ACAST_TOPTR]],
// CHECK: [[SIZE_GEPA2:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[SIZE_GEPA2]],
// firstprivate(b): base_ptr = &b[0], ptr = &b[0], size = 40 (sizeof(float)*10)
- // CHECK: [[BCAST:%.+]] = bitcast [10 x float]* [[B]] to i8*
// CHECK: [[BASE_PTR_GEP2_1:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
- // CHECK: store i8* [[BCAST]], i8** [[BASE_PTR_GEP2_1]],
- // CHECK: [[BCAST2:%.+]] = bitcast [10 x float]* [[B]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_1]] to [10 x float]**
+ // CHECK: store [10 x float]* [[B]], [10 x float]** [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP2_1:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
- // CHECK: store i8* [[BCAST2]], i8** [[PTR_GEP2_1]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_1]] to [10 x float]**
+ // CHECK: store [10 x float]* [[B]], [10 x float]** [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPB:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
// CHECK: store i{{[0-9]+}} 40, i{{[0-9]+}}* [[SIZE_GEPB]],
// firstprivate(bn), 2 entries, n and bn: (1) base_ptr = n, ptr = n, size = 8 ; (2) base_ptr = &c[0], ptr = &c[0], size = n*sizeof(float)
- // CHECK-64: [[N_EXT3_1:%.+]] = inttoptr i{{[0-9]+}} [[N_EXT]] to i8*
- // CHECK-32: [[N_EXT3_1:%.+]] = inttoptr i{{[0-9]+}} [[N_ADDR_VAL]] to i8*
// CHECK: [[BASE_PTR_GEP2_2:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
- // CHECK: store i8* [[N_EXT3_1]], i8** [[BASE_PTR_GEP2_2]],
- // CHECK-64: [[N_EXT3_2:%.+]] = inttoptr i{{[0-9]+}} [[N_EXT]] to i8*
- // CHECK-32: [[N_EXT3_2:%.+]] = inttoptr i{{[0-9]+}} [[N_ADDR_VAL]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_2]] to i{{[0-9]+}}*
+ // CHECK-64: store i{{[0-9]+}} [[N_EXT]], i{{[0-9]+}}* [[BCAST_TOPTR]],
+ // CHECK-32: store i{{[0-9]+}} [[N_ADDR_VAL]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP2_2:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
- // CHECK: store i8* [[N_EXT3_2]], i8** [[PTR_GEP2_2]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_2]] to i{{[0-9]+}}*
+ // CHECK-64: store i{{[0-9]+}} [[N_EXT]], i{{[0-9]+}}* [[BCAST_TOPTR]],
+ // CHECK-32: store i{{[0-9]+}} [[N_ADDR_VAL]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPBN_1:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK: store i{{[0-9]+}} {{[0-9]}}, i{{[0-9]+}}* [[SIZE_GEPBN_1]],
- // CHECK: [[VLABN_BCAST:%.+]] = bitcast float* [[BN_VLA]] to i8*
// CHECK: [[BASE_PTR_GEP2_3:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
- // CHECK: store i8* [[VLABN_BCAST]], i8** [[BASE_PTR_GEP2_3]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_3]] to float**
+ // CHECK: store float* [[BN_VLA]], float** [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPBN_3:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
// CHECK: store i{{[0-9]+}} [[BN_SIZE]], i{{[0-9]+}}* [[SIZE_GEPBN_3]]
// firstprivate(c): base_ptr = &c[0], ptr = &c[0], size = 400 (5*10*sizeof(double))
- // CHECK: [[C_BCAST:%.+]] = bitcast [5 x [10 x double]]* [[C]] to i8*
// CHECK: [[BASE_PTR_GEP2_4:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
- // CHECK: store i8* [[C_BCAST]], i8** [[BASE_PTR_GEP2_4]],
- // CHECK: [[C_BCAST2:%.+]] = bitcast [5 x [10 x double]]* [[C]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_4]] to [5 x [10 x double]]**
+ // CHECK: store [5 x [10 x double]]* [[C]], [5 x [10 x double]]** [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP2_4:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
- // CHECK: store i8* [[C_BCAST2]], i8** [[PTR_GEP2_4]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_4]] to [5 x [10 x double]]**
+ // CHECK: store [5 x [10 x double]]* [[C]], [5 x [10 x double]]** [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPC_4:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
// CHECK: store i{{[0-9]+}} 400, i{{[0-9]+}}* [[SIZE_GEPC_4]],
// firstprivate(cn), 3 entries, 5, n, cn: (1) base_ptr = 5, ptr = 5, size = 8; (2) (1) base_ptr = n, ptr = n, size = 8; (3) base_ptr = &cn[0], ptr = &cn[0], size = 5*n*sizeof(double)
// CHECK: [[BASE_PTR_GEP2_5:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 5
- // CHECK: store i8* inttoptr (i{{[0-9]+}} 5 to i8*), i8** [[BASE_PTR_GEP2_5]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_5]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} 5, i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP2_5:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 5
- // CHECK: store i8* inttoptr (i{{[0-9]+}} 5 to i8*), i8** [[PTR_GEP2_5]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_5]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} 5, i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPCN_5:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 5
// CHECK: store i{{[0-9]+}} {{[0-9]}}, i{{[0-9]+}}* [[SIZE_GEPCN_5]],
- // CHECK-64: [[CN_SZ_2_1:%.+]] = inttoptr i{{[0-9]+}} [[N_EXT2]] to i8*
- // CHECK-32: [[CN_SZ_2_1:%.+]] = inttoptr i{{[0-9]+}} [[N_ADDR_VAL2]] to i8*
// CHECK: [[BASE_PTR_GEP2_6:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 6
- // CHECK: store i8* [[CN_SZ_2_1]], i8** [[BASE_PTR_GEP2_6]],
- // CHECK-64: [[CN_SZ_2_2:%.+]] = inttoptr i{{[0-9]+}} [[N_EXT2]] to i8*
- // CHECK-32: [[CN_SZ_2_2:%.+]] = inttoptr i{{[0-9]+}} [[N_ADDR_VAL2]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_6]] to i{{[0-9]+}}*
+ // CHECK-64: store i{{[0-9]+}} [[N_EXT2]], i{{[0-9]+}}* [[BCAST_TOPTR]],
+ // CHECK-32: store i{{[0-9]+}} [[N_ADDR_VAL2]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP2_6:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 6
- // CHECK: store i8* [[CN_SZ_2_2]], i8** [[PTR_GEP2_6]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_6]] to i{{[0-9]+}}*
+ // CHECK-64: store i{{[0-9]+}} [[N_EXT2]], i{{[0-9]+}}* [[BCAST_TOPTR]],
+ // CHECK-32: store i{{[0-9]+}} [[N_ADDR_VAL2]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPCN_6:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 6
// CHECK: store i{{[0-9]+}} {{[0-9]}}, i{{[0-9]+}}* [[SIZE_GEPCN_6]],
- // CHECK: [[VLA_CN_BCAST:%.+]] = bitcast double* [[CN_VLA]] to i8*
// CHECK: [[BASE_PTR_GEP2_7:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 7
- // CHECK: store i8* [[VLA_CN_BCAST]], i8** [[BASE_PTR_GEP2_7]],
- // CHECK: [[VLA_CN_BCAST2:%.+]] = bitcast double* [[CN_VLA]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_7]] to double**
+ // CHECK: store double* [[CN_VLA]], double** [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP2_7:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 7
- // CHECK: store i8* [[VLA_CN_BCAST2]], i8** [[PTR_GEP2_7]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_7]] to double**
+ // CHECK: store double* [[CN_VLA]], double** [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPCN_7:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 7
// CHECK: store i{{[0-9]+}} [[CN_SIZE_2]], i{{[0-9]+}}* [[SIZE_GEPCN_7]],
// firstprivate(d): base_ptr = &d, ptr = &d, size = 16
- // CHECK: [[D_REF:%.+]] = bitcast [[TT]]* [[D]] to i8*
// CHECK: [[BASE_PTR_GEP2_8:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[BASE_PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 8
- // CHECK: store i8* [[D_REF]], i8** [[BASE_PTR_GEP2_8]],
- // CHECK: [[D_REF2:%.+]] = bitcast [[TT]]* [[D]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP2_8]] to [[TT]]**
+ // CHECK: store [[TT]]* [[D]], [[TT]]** [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP2_8:%.+]] = getelementptr inbounds [9 x i8*], [9 x i8*]* [[PTR_ARR2]], i{{[0-9]+}} 0, i{{[0-9]+}} 8
- // CHECK: store i8* [[D_REF2]], i8** [[PTR_GEP2_8]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP2_8]] to [[TT]]**
+ // CHECK: store [[TT]]* [[D]], [[TT]]** [[BCAST_TOPTR]],
// CHECK: [[SIZE_GEPCN_8:%.+]] = getelementptr inbounds [9 x i{{[0-9]+}}], [9 x i{{[0-9]+}}]* [[SIZET2]], i{{[0-9]+}} 0, i{{[0-9]+}} 8
// CHECK: store i{{[0-9]+}} {{[0-9]+}}, i{{[0-9]+}}* [[SIZE_GEPCN_8]],
@@ -222,7 +223,7 @@ int foo(int n, double *ptr) {
// make sure that firstprivate variables are generated in all cases and that we use those instances for operations inside the
// target region
- // TCHECK: define {{.*}}void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A2_IN:%.+]], [10 x float]* {{.+}} [[B_IN:%.+]], i{{[0-9]+}} [[BN_SZ:%.+]], float* [[BN_IN:%.+]], [5 x [10 x double]]* {{.+}} [[C_IN:%.+]], i{{[0-9]+}} [[CN_SZ1:%.+]], i{{[0-9]+}} [[CN_SZ2:%.+]], double* [[CN_IN:%.+]], [[TT]]* {{.+}} [[D_IN:%.+]])
+ // TCHECK: define {{.*}}void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A2_IN:%.+]], [10 x float]* {{.+}} [[B_IN:%.+]], i{{[0-9]+}} [[BN_SZ:%.+]], float* {{.+}} [[BN_IN:%.+]], [5 x [10 x double]]* {{.+}} [[C_IN:%.+]], i{{[0-9]+}} [[CN_SZ1:%.+]], i{{[0-9]+}} [[CN_SZ2:%.+]], double* {{.+}} [[CN_IN:%.+]], [[TT]]* {{.+}} [[D_IN:%.+]])
// TCHECK: [[A2_ADDR:%.+]] = alloca i{{[0-9]+}},
// TCHECK: [[B_ADDR:%.+]] = alloca [10 x float]*,
// TCHECK: [[VLA_ADDR:%.+]] = alloca i{{[0-9]+}},
@@ -299,13 +300,13 @@ int foo(int n, double *ptr) {
ptr[0]++;
}
// CHECK: [[PTR_ADDR_REF:%.+]] = load double*, double** [[PTR_ADDR]],
- // CHECK: [[PTR_ADDR_BCAST:%.+]] = bitcast double* [[PTR_ADDR_REF]] to i8*
// CHECK: [[BASE_PTR_GEP3_0:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BASE_PTR_ARR3]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[PTR_ADDR_BCAST]], i8** [[BASE_PTR_GEP3_0]],
- // CHECK: [[PTR_ADDR_BCAST2:%.+]] = bitcast double* [[PTR_ADDR_REF]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTR_GEP3_0]] to double**
+ // CHECK: store double* [[PTR_ADDR_REF]], double** [[BCAST_TOPTR]],
// CHECK: [[PTR_GEP3_0:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PTR_ARR3]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[PTR_ADDR_BCAST2]], i8** [[PTR_GEP3_0]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTR_GEP3_0]] to double**
+ // CHECK: store double* [[PTR_ADDR_REF]], double** [[BCAST_TOPTR]],
// CHECK: [[BASE_PTR_GEP_ARG3:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[BASE_PTR_ARR3]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
// CHECK: [[PTR_GEP_ARG3:%.+]] = getelementptr inbounds [1 x i8*], [1 x i8*]* [[PTR_ARR3]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
@@ -407,38 +408,40 @@ struct S1 {
// CHECK: store {{.+}}, {{.+}}
// firstprivate(b): base_ptr = b, ptr = b, size = 4 (pass by-value)
- // CHECK: [[B_CAST_PTR:%.+]] = inttoptr i{{[0-9]+}} [[B_CAST:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP4_1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BASE_PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
- // CHECK: store i8* [[B_CAST_PTR]], i8** [[BASE_PTRS_GEP4_1]],
- // CHECK: [[B_CAST_PTR2:%.+]] = inttoptr i{{[0-9]+}} [[B_CAST:%.+]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP4_1]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[B_CAST:%.+]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP4_1:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
- // CHECK: store i8* [[B_CAST_PTR2]], i8** [[PTRS_GEP4_1]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP4_1]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[B_CAST]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[SIZES_GEP4_1:%.+]] = getelementptr inbounds [5 x i{{[0-9]+}}], [5 x i{{[0-9]+}}]* [[SIZET4]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
// CHECK: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SIZES_GEP4_1]],
// firstprivate(c), 3 entries: 2, n, c
// CHECK: [[BASE_PTRS_GEP4_2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BASE_PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
- // CHECK: store i8* inttoptr (i{{[0-9]+}} 2 to i8*), i8** [[BASE_PTRS_GEP4_2]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP4_2]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP4_2:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
- // CHECK: store i8* inttoptr (i{{[0-9]+}} 2 to i8*), i8** [[PTRS_GEP4_2]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP4_2]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[SIZES_GEP4_2:%.+]] = getelementptr inbounds [5 x i{{[0-9]+}}], [5 x i{{[0-9]+}}]* [[SIZET4]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
// CHECK-64: store i{{[0-9]+}} 8, i{{[0-9]+}}* [[SIZES_GEP4_2]],
// CHECK-32: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SIZES_GEP4_2]],
- // CHECK: [[N_PTR:%.+]] = inttoptr i{{[0-9]+}} [[N:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP4_3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BASE_PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
- // CHECK: store i8* [[N_PTR]], i8** [[BASE_PTRS_GEP4_3]],
- // CHECK: [[N_PTR2:%.+]] = inttoptr i{{[0-9]+}} [[N:%.+]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP4_3]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[N:%.+]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP4_3:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
- // CHECK: store i8* [[N_PTR2]], i8** [[PTRS_GEP4_3]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP4_3]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[N]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[SIZES_GEP4_3:%.+]] = getelementptr inbounds [5 x i{{[0-9]+}}], [5 x i{{[0-9]+}}]* [[SIZET4]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
// CHECK-64: store i{{[0-9]+}} 8, i{{[0-9]+}}* [[SIZES_GEP4_3]],
// CHECK-32: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SIZES_GEP4_3]],
- // CHECK: [[B_BCAST:%.+]] = bitcast i{{[0-9]+}}* [[B:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP4_4:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[BASE_PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
- // CHECK: store i8* [[B_BCAST]], i8** [[BASE_PTRS_GEP4_4]],
- // CHECK: [[B_BCAST2:%.+]] = bitcast i{{[0-9]+}}* [[B:%.+]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP4_4]] to i{{[0-9]+}}**
+ // CHECK: store i{{[0-9]+}}* [[B:%.+]], i{{[0-9]+}}** [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP4_4:%.+]] = getelementptr inbounds [5 x i8*], [5 x i8*]* [[PTRS4]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
- // CHECK: store i8* [[B_BCAST2]], i8** [[PTRS_GEP4_4]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP4_4]] to i{{[0-9]+}}**
+ // CHECK: store i{{[0-9]+}}* [[B]], i{{[0-9]+}}** [[BCAST_TOPTR]],
// CHECK: [[SIZES_GEP4_4:%.+]] = getelementptr inbounds [5 x i{{[0-9]+}}], [5 x i{{[0-9]+}}]* [[SIZET4]], i{{[0-9]+}} 0, i{{[0-9]+}} 4
// CHECK: store i{{[0-9]+}} [[B_SIZE:%.+]], i{{[0-9]+}}* [[SIZES_GEP4_4]],
@@ -492,28 +495,28 @@ struct S1 {
// CHECK: [[PTRS5:%.+]] = alloca [3 x i8*],
// firstprivate(a): by value
- // CHECK: [[A_CAST_PTR:%.+]] = inttoptr i{{[0-9]+}} [[A_CAST:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP5_0:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BASE_PTRS5]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[A_CAST_PTR]], i8** [[BASE_PTRS_GEP5_0]],
- // CHECK: [[A_CAST_PTR2:%.+]] = inttoptr i{{[0-9]+}} [[A_CAST:%.+]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP5_0]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[A_CAST:%.+]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP5_0:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[PTRS5]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
- // CHECK: store i8* [[A_CAST_PTR2]], i8** [[PTRS_GEP5_0]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP5_0]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[A_CAST]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// firstprivate(aaa): by value
- // CHECK: [[A3_CAST_PTR:%.+]] = inttoptr i{{[0-9]+}} [[A3_CAST:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP5_1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BASE_PTRS5]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
- // CHECK: store i8* [[A3_CAST_PTR]], i8** [[BASE_PTRS_GEP5_1]],
- // CHECK: [[A3_CAST_PTR2:%.+]] = inttoptr i{{[0-9]+}} [[A3_CAST:%.+]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP5_1]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[A3_CAST:%.+]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP5_1:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[PTRS5]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
- // CHECK: store i8* [[A3_CAST_PTR2]], i8** [[PTRS_GEP5_1]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP5_1]] to i{{[0-9]+}}*
+ // CHECK: store i{{[0-9]+}} [[A3_CAST]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// firstprivate(b): base_ptr = &b[0], ptr= &b[0]
- // CHECK: [[B_BCAST:%.+]] = bitcast [10 x i{{[0-9]+}}]* [[B:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP5_2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[BASE_PTRS5]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
- // CHECK: store i8* [[B_BCAST]], i8** [[BASE_PTRS_GEP5_2]],
- // CHECK: [[B_BCAST2:%.+]] = bitcast [10 x i{{[0-9]+}}]* [[B:%.+]] to i8*
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP5_2]] to [10 x i{{[0-9]+}}]**
+ // CHECK: store [10 x i{{[0-9]+}}]* [[B:%.+]], [10 x i{{[0-9]+}}]** [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP5_2:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[PTRS5]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
- // CHECK: store i8* [[B_BCAST2]], i8** [[PTRS_GEP5_2]],
+ // CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP5_2]] to [10 x i{{[0-9]+}}]**
+ // CHECK: store [10 x i{{[0-9]+}}]* [[B]], [10 x i{{[0-9]+}}]** [[BCAST_TOPTR]],
// only check that the right sizes and map types are used
// CHECK: call i32 @__tgt_target(i32 -1, {{.+}}, i32 3, i8** {{.+}}, i8** {{.+}}, 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))
@@ -539,20 +542,20 @@ int bar(int n, double *ptr){
// CHECK: [[PTRS6:%.+]] = alloca [2 x i8*],
// firstprivate(a): by value
-// CHECK: [[AT_CAST_PTR:%.+]] = inttoptr i{{[0-9]+}} [[AT_CAST:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP6_0:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BASE_PTRS6]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
-// CHECK: store i8* [[AT_CAST_PTR]], i8** [[BASE_PTRS_GEP6_0]],
-// CHECK: [[AT_CAST_PTR2:%.+]] = inttoptr i{{[0-9]+}} [[AT_CAST:%.+]] to i8*
+// CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP6_0]] to i{{[0-9]+}}*
+// CHECK: store i{{[0-9]+}} [[AT_CAST:%.+]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP6_0:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[PTRS6]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
-// CHECK: store i8* [[AT_CAST_PTR2]], i8** [[PTRS_GEP6_0]],
+// CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP6_0]] to i{{[0-9]+}}*
+// CHECK: store i{{[0-9]+}} [[AT_CAST]], i{{[0-9]+}}* [[BCAST_TOPTR]],
// firstprivate(b): pointer
-// CHECK: [[B_BCAST:%.+]] = bitcast [10 x i{{[0-9]+}}]* [[B:%.+]] to i8*
// CHECK: [[BASE_PTRS_GEP6_1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[BASE_PTRS6]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
-// CHECK: store i8* [[B_BCAST]], i8** [[BASE_PTRS_GEP6_1]],
-// CHECK: [[B_BCAST2:%.+]] = bitcast [10 x i{{[0-9]+}}]* [[B:%.+]] to i8*
+// CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[BASE_PTRS_GEP6_1]] to [10 x i{{[0-9]+}}]**
+// CHECK: store [10 x i{{[0-9]+}}]* [[B:%.+]], [10 x i{{[0-9]+}}]** [[BCAST_TOPTR]],
// CHECK: [[PTRS_GEP6_1:%.+]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[PTRS6]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
-// CHECK: store i8* [[B_BCAST2]], i8** [[PTRS_GEP6_1]],
+// CHECK: [[BCAST_TOPTR:%.+]] = bitcast i8** [[PTRS_GEP6_1]] to [10 x i{{[0-9]+}}]**
+// CHECK: store [10 x i{{[0-9]+}}]* [[B]], [10 x i{{[0-9]+}}]** [[BCAST_TOPTR]],
// CHECK: call i32 @__tgt_target(i32 -1, {{.+}}, i32 2, i8** {{.+}}, i8** {{.+}}, i[[SZ]]* getelementptr inbounds ([2 x i[[SZ]]], [2 x i[[SZ]]]* [[SIZET6]], i32 0, i32 0), i32* getelementptr inbounds ([2 x i32], [2 x i32]* [[MAPT6]], i32 0, i32 0))
diff --git a/test/OpenMP/target_is_device_ptr_codegen.cpp b/test/OpenMP/target_is_device_ptr_codegen.cpp
index 6c80729483..1a54aa18c0 100644
--- a/test/OpenMP/target_is_device_ptr_codegen.cpp
+++ b/test/OpenMP/target_is_device_ptr_codegen.cpp
@@ -46,10 +46,10 @@ void foo(float *&lr, T *&tr) {
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = bitcast double* [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = bitcast double* [[VAL]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double**
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK1-DAG: store double* [[VAL:%.+]], double** [[CBP1]]
+ // CK1-DAG: store double* [[VAL]], double** [[CP1]]
// CK1-DAG: [[VAL]] = load double*, double** [[ADDR:@g]],
// CK1: call void [[KERNEL:@.+]](double* [[VAL]])
@@ -63,10 +63,10 @@ void foo(float *&lr, T *&tr) {
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = bitcast float* [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = bitcast float* [[VAL]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to float**
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to float**
+ // CK1-DAG: store float* [[VAL:%.+]], float** [[CBP1]]
+ // CK1-DAG: store float* [[VAL]], float** [[CP1]]
// CK1-DAG: [[VAL]] = load float*, float** [[ADDR:%.+]],
// CK1: call void [[KERNEL:@.+]](float* [[VAL]])
@@ -80,10 +80,10 @@ void foo(float *&lr, T *&tr) {
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = bitcast i32* [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = bitcast i32* [[VAL]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK1-DAG: store i32* [[VAL:%.+]], i32** [[CBP1]]
+ // CK1-DAG: store i32* [[VAL]], i32** [[CP1]]
// CK1-DAG: [[VAL]] = load i32*, i32** [[ADDR:%.+]],
// CK1: call void [[KERNEL:@.+]](i32* [[VAL]])
@@ -97,10 +97,10 @@ void foo(float *&lr, T *&tr) {
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = bitcast float* [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = bitcast float* [[VAL]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to float**
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to float**
+ // CK1-DAG: store float* [[VAL:%.+]], float** [[CBP1]]
+ // CK1-DAG: store float* [[VAL]], float** [[CP1]]
// CK1-DAG: [[VAL]] = load float*, float** [[ADDR:%.+]],
// CK1-DAG: [[ADDR]] = load float**, float*** [[ADDR2:%.+]],
@@ -115,10 +115,10 @@ void foo(float *&lr, T *&tr) {
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = bitcast i32* [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = bitcast i32* [[VAL]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK1-DAG: store i32* [[VAL:%.+]], i32** [[CBP1]]
+ // CK1-DAG: store i32* [[VAL]], i32** [[CP1]]
// CK1-DAG: [[VAL]] = load i32*, i32** [[ADDR:%.+]],
// CK1-DAG: [[ADDR]] = load i32**, i32*** [[ADDR2:%.+]],
@@ -133,10 +133,10 @@ void foo(float *&lr, T *&tr) {
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = bitcast i32* [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = bitcast i32* [[VAL]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK1-DAG: store i32* [[VAL:%.+]], i32** [[CBP1]]
+ // CK1-DAG: store i32* [[VAL]], i32** [[CP1]]
// CK1-DAG: [[VAL]] = load i32*, i32** [[ADDR:%.+]],
// CK1-DAG: [[ADDR]] = load i32**, i32*** [[ADDR2:%.+]],
@@ -151,19 +151,19 @@ void foo(float *&lr, T *&tr) {
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = bitcast i32* [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = bitcast i32* [[VAL]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK1-DAG: store i32* [[VAL:%.+]], i32** [[CBP1]]
+ // CK1-DAG: store i32* [[VAL]], i32** [[CP1]]
// CK1-DAG: [[VAL]] = load i32*, i32** [[ADDR:%.+]],
// CK1-DAG: [[ADDR]] = load i32**, i32*** [[ADDR2:%.+]],
// CK1-DAG: [[_BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
// CK1-DAG: [[_P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
- // CK1-DAG: store i8* [[_VALBP:%.+]], i8** [[_BP1]],
- // CK1-DAG: store i8* [[_VALP:%.+]], i8** [[_P1]],
- // CK1-DAG: [[_VALBP]] = bitcast float* [[_VAL:%.+]] to i8*
- // CK1-DAG: [[_VALP]] = bitcast float* [[_VAL]] to i8*
+ // CK1-DAG: [[_CBP1:%.+]] = bitcast i8** [[_BP1]] to float**
+ // CK1-DAG: [[_CP1:%.+]] = bitcast i8** [[_P1]] to float**
+ // CK1-DAG: store float* [[_VAL:%.+]], float** [[_CBP1]]
+ // CK1-DAG: store float* [[_VAL]], float** [[_CP1]]
// CK1-DAG: [[_VAL]] = load float*, float** [[_ADDR:%.+]],
// CK1-DAG: [[_ADDR]] = load float**, float*** [[_ADDR2:%.+]],
@@ -215,10 +215,10 @@ struct ST {
// CK2-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK2-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK2-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK2-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK2-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK2-DAG: [[CPVAL0]] = bitcast double** [[SEC0:%.+]] to i8*
+ // CK2-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK2-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+ // CK2-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK2-DAG: store double** [[SEC0:%.+]], double*** [[CP0]]
// CK2-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[VAR0]], i{{.+}} 0, i{{.+}} 0
#pragma omp target is_device_ptr(a)
{
@@ -231,18 +231,18 @@ struct ST {
// CK2-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK2-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK2-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK2-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK2-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK2-DAG: [[CPVAL0]] = bitcast double*** [[SEC0:%.+]] to i8*
+ // CK2-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK2-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double****
+ // CK2-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK2-DAG: store double*** [[SEC0:%.+]], double**** [[CP0]]
// CK2-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK2-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK2-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK2-DAG: [[CBPVAL1]] = bitcast double*** [[SEC0]] to i8*
- // CK2-DAG: [[CPVAL1]] = bitcast double** [[SEC1:%.+]] to i8*
+ // CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double****
+ // CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double***
+ // CK2-DAG: store double*** [[SEC0]], double**** [[CBP1]]
+ // CK2-DAG: store double** [[SEC1:%.+]], double*** [[CP1]]
// CK2-DAG: [[SEC1]] = load double**, double*** [[SEC0]]
#pragma omp target is_device_ptr(b)
{
@@ -255,26 +255,26 @@ struct ST {
// CK2-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK2-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK2-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK2-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK2-DAG: [[CPVAL0]] = bitcast double*** [[SEC0:%.+]] to i8*
+ // CK2-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK2-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double****
+ // CK2-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK2-DAG: store double*** [[SEC0:%.+]], double**** [[CP0]]
// CK2-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK2-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK2-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK2-DAG: [[CBPVAL1]] = bitcast double*** [[SEC0]] to i8*
- // CK2-DAG: [[CPVAL1]] = bitcast double** [[SEC1:%.+]] to i8*
+ // CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double****
+ // CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double***
+ // CK2-DAG: store double*** [[SEC0]], double**** [[CBP1]]
+ // CK2-DAG: store double** [[SEC1:%.+]], double*** [[CP1]]
// CK2-DAG: [[SEC1]] = load double**, double*** [[SEC0]]
// CK2-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK2-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK2-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK2-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK2-DAG: [[CBPVAL2]] = bitcast [[ST]]* [[VAR2:%.+]] to i8*
- // CK2-DAG: [[CPVAL2]] = bitcast double** [[SEC2:%.+]] to i8*
+ // CK2-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [[ST]]**
+ // CK2-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to double***
+ // CK2-DAG: store [[ST]]* [[VAR2:%.+]], [[ST]]** [[CBP2]]
+ // CK2-DAG: store double** [[SEC2:%.+]], double*** [[CP2]]
// CK2-DAG: [[SEC2]] = getelementptr {{.*}}[[ST]]* [[VAR2]], i{{.+}} 0, i{{.+}} 0
#pragma omp target is_device_ptr(a, b)
{
diff --git a/test/OpenMP/target_map_codegen.cpp b/test/OpenMP/target_map_codegen.cpp
index 72c7257a0e..72589b530f 100644
--- a/test/OpenMP/target_map_codegen.cpp
+++ b/test/OpenMP/target_map_codegen.cpp
@@ -15,12 +15,30 @@
// RUN: %clang_cc1 -fopenmp -fopenmp-targets=i386-pc-linux-gnu -x c++ -triple i386-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-32
#ifdef CK1
+class B {
+public:
+ static double VAR;
+ B() {
+ }
+
+ static void modify(int &res) {
+#pragma omp target map(tofrom \
+ : res)
+ {
+ res = B::VAR;
+ }
+ }
+};
+double B::VAR = 1.0;
+
// CK1-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 4]
// Map types: OMP_MAP_PRIVATE_VAL | OMP_MAP_IS_FIRST = 288
// CK1-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 288]
// CK1-LABEL: implicit_maps_integer
void implicit_maps_integer (int a){
+ // CK1: call void{{.*}}modify
+ B::modify(a);
int i = a;
// CK1-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 1, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
@@ -28,10 +46,10 @@ void implicit_maps_integer (int a){
// CK1-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK1-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK1-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK1-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK1-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK1-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK1-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK1-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK1-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK1-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -75,10 +93,10 @@ void implicit_maps_reference (int a, int *b){
// CK2-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK2-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK2-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK2-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK2-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK2-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK2-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK2-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK2-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK2-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -95,10 +113,10 @@ void implicit_maps_reference (int a, int *b){
// CK2-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK2-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK2-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK2-DAG: [[VALBP]] = bitcast i32* [[VAL:%.+]] to i8*
- // CK2-DAG: [[VALP]] = bitcast i32* [[VAL]] to i8*
+ // CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK2-DAG: store i32* [[VAL:%[^,]+]], i32** [[CBP1]]
+ // CK2-DAG: store i32* [[VAL]], i32** [[CP1]]
// CK2-DAG: [[VAL]] = load i32*, i32** [[ADDR:%.+]],
// CK2-DAG: [[ADDR]] = load i32**, i32*** [[ADDR2:%.+]],
@@ -151,10 +169,10 @@ void implicit_maps_parameter (int a){
// CK3-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK3-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK3-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK3-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK3-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK3-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK3-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK3-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK3-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK3-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK3-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK3-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK3-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK3-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -203,10 +221,10 @@ void implicit_maps_nested_integer (int a){
// CK4-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK4-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK4-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK4-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK4-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK4-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK4-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK4-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK4-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK4-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK4-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK4-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK4-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK4-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -257,10 +275,10 @@ void implicit_maps_nested_integer_and_enum (int a){
// CK5-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK5-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK5-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK5-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK5-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK5-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK5-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK5-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK5-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK5-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK5-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK5-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK5-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK5-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -302,10 +320,10 @@ void implicit_maps_host_global (int a){
// CK6-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK6-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK6-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK6-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK6-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK6-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK6-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK6-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK6-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK6-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK6-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK6-64-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK6-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK6-64-DAG: store i32 [[GBLVAL:%.+]], i32* [[CADDR]],
@@ -342,8 +360,8 @@ void implicit_maps_host_global (int a){
// CK7-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 8]
// Map types: OMP_MAP_PRIVATE_VAL | OMP_MAP_IS_FIRST = 288
// CK7-64-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 288]
-// Map types: OMP_MAP_TO | OMP_MAP_IS_FIRST = 33
-// CK7-32-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 33]
+// Map types: OMP_MAP_TO | OMP_MAP_PRIVATE_PTR | OMP_MAP_FIRST_REF = 161
+// CK7-32-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 161]
// CK7-LABEL: implicit_maps_double
void implicit_maps_double (int a){
@@ -355,18 +373,18 @@ void implicit_maps_double (int a){
// CK7-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK7-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK7-64-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK7-64-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK7-64-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK7-64-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK7-64-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK7-64-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK7-64-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK7-64-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK7-64-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK7-64-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to double*
// CK7-64-64-DAG: store double {{.+}}, double* [[CADDR]],
- // CK7-32-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK7-32-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK7-32-DAG: [[VALBP]] = bitcast double* [[DECL:%.+]] to i8*
- // CK7-32-DAG: [[VALP]] = bitcast double* [[DECL]] to i8*
+ // CK7-32-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double**
+ // CK7-32-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK7-32-DAG: store double* [[DECL:%[^,]+]], double** [[CBP1]]
+ // CK7-32-DAG: store double* [[DECL]], double** [[CP1]]
// CK7-64: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
// CK7-32: call void [[KERNEL:@.+]](double* [[DECL]])
@@ -411,10 +429,10 @@ void implicit_maps_float (int a){
// CK8-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK8-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK8-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK8-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK8-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK8-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK8-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK8-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK8-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK8-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK8-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK8-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK8-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to float*
// CK8-DAG: store float {{.+}}, float* [[CADDR]],
@@ -443,8 +461,8 @@ void implicit_maps_float (int a){
#ifdef CK9
// CK9-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 16]
-// Map types: OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST = 35
-// CK9-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 35]
+// Map types: OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST + OMP_MAP_IMPLICIT = 547
+// CK9-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 547]
// CK9-LABEL: implicit_maps_array
void implicit_maps_array (int a){
@@ -455,10 +473,10 @@ void implicit_maps_array (int a){
// CK9-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK9-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK9-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK9-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK9-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK9-DAG: [[VALBP]] = bitcast [2 x double]* [[DECL:%.+]] to i8*
- // CK9-DAG: [[VALP]] = bitcast [2 x double]* [[DECL]] to i8*
+ // CK9-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [2 x double]**
+ // CK9-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to [2 x double]**
+ // CK9-DAG: store [2 x double]* [[DECL:%[^,]+]], [2 x double]** [[CBP1]]
+ // CK9-DAG: store [2 x double]* [[DECL]], [2 x double]** [[CP1]]
// CK9: call void [[KERNEL:@.+]]([2 x double]* [[DECL]])
#pragma omp target
@@ -496,10 +514,10 @@ void implicit_maps_pointer (){
// CK10-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK10-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK10-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK10-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK10-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK10-DAG: [[VALBP]] = bitcast double* [[PTR:%.+]] to i8*
- // CK10-DAG: [[VALP]] = bitcast double* [[PTR]] to i8*
+ // CK10-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double**
+ // CK10-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK10-DAG: store double* [[PTR:%[^,]+]], double** [[CBP1]]
+ // CK10-DAG: store double* [[PTR]], double** [[CP1]]
// CK10: call void [[KERNEL:@.+]](double* [[PTR]])
#pragma omp target
@@ -526,8 +544,8 @@ void implicit_maps_pointer (){
#ifdef CK11
// CK11-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 16]
-// Map types: OMP_MAP_TO + OMP_MAP_IS_FIRST = 33
-// CK11-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 33]
+// Map types: OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST + OMP_MAP_IMPLICIT = 547
+// CK11-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 547]
// CK11-LABEL: implicit_maps_double_complex
void implicit_maps_double_complex (int a){
@@ -538,13 +556,13 @@ void implicit_maps_double_complex (int a){
// CK11-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK11-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK11-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK11-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK11-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK11-DAG: [[VALBP]] = bitcast { double, double }* [[PTR:%.+]] to i8*
- // CK11-DAG: [[VALP]] = bitcast { double, double }* [[PTR]] to i8*
+ // CK11-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to { double, double }**
+ // CK11-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to { double, double }**
+ // CK11-DAG: store { double, double }* [[PTR:%[^,]+]], { double, double }** [[CBP1]]
+ // CK11-DAG: store { double, double }* [[PTR]], { double, double }** [[CP1]]
// CK11: call void [[KERNEL:@.+]]({ double, double }* [[PTR]])
- #pragma omp target
+ #pragma omp target defaultmap(tofrom:scalar)
{
dc *= dc;
}
@@ -571,8 +589,8 @@ void implicit_maps_double_complex (int a){
// CK12-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} 8]
// Map types: OMP_MAP_PRIVATE_VAL + OMP_MAP_IS_FIRST = 288
// CK12-64-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 288]
-// Map types: OMP_MAP_TO + OMP_MAP_IS_FIRST = 33
-// CK12-32-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 33]
+// Map types: OMP_MAP_TO | OMP_MAP_PRIVATE_PTR | OMP_MAP_FIRST_REF = 161
+// CK12-32-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 161]
// CK12-LABEL: implicit_maps_float_complex
void implicit_maps_float_complex (int a){
@@ -584,18 +602,18 @@ void implicit_maps_float_complex (int a){
// CK12-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK12-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK12-64-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK12-64-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK12-64-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK12-64-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK12-64-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK12-64-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK12-64-DAG: store i[[sz]] [[VAL:%[^,]+]], i[[sz]]* [[CBP1]]
+ // CK12-64-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK12-64-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK12-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to { float, float }*
// CK12-64-DAG: store { float, float } {{.+}}, { float, float }* [[CADDR]],
- // CK12-32-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK12-32-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK12-32-DAG: [[VALBP]] = bitcast { float, float }* [[DECL:%.+]] to i8*
- // CK12-32-DAG: [[VALP]] = bitcast { float, float }* [[DECL]] to i8*
+ // CK12-32-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to { float, float }**
+ // CK12-32-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to { float, float }**
+ // CK12-32-DAG: store { float, float }* [[DECL:%[^,]+]], { float, float }** [[CBP1]]
+ // CK12-32-DAG: store { float, float }* [[DECL]], { float, float }** [[CP1]]
// CK12-64: call void [[KERNEL:@.+]](i[[sz]] [[VAL]])
// CK12-32: call void [[KERNEL:@.+]]({ float, float }* [[DECL]])
@@ -630,8 +648,8 @@ void implicit_maps_float_complex (int a){
// Map types:
// - OMP_MAP_PRIVATE_VAL + OMP_MAP_IS_FIRST = 288 (vla size)
// - OMP_MAP_PRIVATE_VAL + OMP_MAP_IS_FIRST = 288 (vla size)
-// - OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST = 35
-// CK13-DAG: [[TYPES:@.+]] = {{.+}}constant [3 x i32] [i32 288, i32 288, i32 35]
+// - OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST + OMP_IMPICIT_MAP = 547
+// CK13-DAG: [[TYPES:@.+]] = {{.+}}constant [3 x i32] [i32 288, i32 288, i32 547]
// CK13-LABEL: implicit_maps_variable_length_array
void implicit_maps_variable_length_array (int a){
@@ -645,27 +663,29 @@ void implicit_maps_variable_length_array (int a){
// CK13-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK13-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
// CK13-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[SS]], i32 0, i32 0
- // CK13-DAG: store i8* inttoptr (i[[sz]] 2 to i8*), i8** [[BP0]],
- // CK13-DAG: store i8* inttoptr (i[[sz]] 2 to i8*), i8** [[P0]],
+ // CK13-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[sz]]*
+ // CK13-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[sz]]*
+ // CK13-DAG: store i[[sz]] 2, i[[sz]]* [[CBP0]]
+ // CK13-DAG: store i[[sz]] 2, i[[sz]]* [[CP0]]
// CK13-DAG: store i[[sz]] {{8|4}}, i[[sz]]* [[S0]],
// CK13-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
// CK13-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
// CK13-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[SS]], i32 0, i32 1
- // CK13-DAG: store i8* [[VALBP1:%.+]], i8** [[BP1]],
- // CK13-DAG: store i8* [[VALP1:%.+]], i8** [[P1]],
- // CK13-DAG: [[VALBP1]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK13-DAG: [[VALP1]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK13-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK13-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK13-DAG: store i[[sz]] [[VAL:%.+]], i[[sz]]* [[CBP1]]
+ // CK13-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK13-DAG: store i[[sz]] {{8|4}}, i[[sz]]* [[S1]],
// CK13-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 2
// CK13-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 2
// CK13-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[SS]], i32 0, i32 2
- // CK13-DAG: store i8* [[VALBP2:%.+]], i8** [[BP2]],
- // CK13-DAG: store i8* [[VALP2:%.+]], i8** [[P2]],
+ // CK13-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to double**
+ // CK13-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to double**
+ // CK13-DAG: store double* [[DECL:%.+]], double** [[CBP2]]
+ // CK13-DAG: store double* [[DECL]], double** [[CP2]]
// CK13-DAG: store i[[sz]] [[VALS2:%.+]], i[[sz]]* [[S2]],
- // CK13-DAG: [[VALBP2]] = bitcast double* [[DECL:%.+]] to i8*
- // CK13-DAG: [[VALP2]] = bitcast double* [[DECL]] to i8*
// CK13-DAG: [[VALS2]] = mul nuw i[[sz]] %{{.+}}, 8
// CK13: call void [[KERNEL:@.+]](i[[sz]] {{.+}}, i[[sz]] {{.+}}, double* [[DECL]])
@@ -697,11 +717,12 @@ void implicit_maps_variable_length_array (int a){
#ifdef CK14
// CK14-DAG: [[ST:%.+]] = type { i32, double }
-// CK14-DAG: [[SIZES:@.+]] = {{.+}}constant [2 x i[[sz:64|32]]] [i{{64|32}} {{16|12}}, i{{64|32}} 4]
+// CK14-DAG: [[SIZES:@.+]] = {{.+}}constant [3 x i[[sz:64|32]]] [i{{64|32}} 4, i{{64|32}} 8, i{{64|32}} 4]
// Map types:
-// - OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST = 35
+// - OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST + OMP_IMPLICIT_MAP = 547
+// - OMP_MAP_TO + OMP_MAP_FROM + OMP_IMPLICIT_MAP = 515
// - OMP_MAP_PRIVATE_VAL + OMP_MAP_IS_FIRST = 288
-// CK14-DAG: [[TYPES:@.+]] = {{.+}}constant [2 x i32] [i32 35, i32 288]
+// CK14-DAG: [[TYPES:@.+]] = {{.+}}constant [3 x i32] [i32 547, i32 515, i32 288]
class SSS {
public:
@@ -724,23 +745,30 @@ void implicit_maps_class (int a){
SSS sss(a, (double)a);
// CK14: define {{.*}}void @{{.+}}foo{{.+}}([[ST]]* {{[^,]+}}, i32 {{[^,]+}})
- // CK14-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 2, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK14-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 3, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
// CK14-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
// CK14-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK14-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK14-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK14-DAG: store i8* [[VALBP0:%.+]], i8** [[BP0]],
- // CK14-DAG: store i8* [[VALP0:%.+]], i8** [[P0]],
- // CK14-DAG: [[VALBP0]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
- // CK14-DAG: [[VALP0]] = bitcast [[ST]]* [[DECL]] to i8*
+ // CK14-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK14-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK14-DAG: store [[ST]]* [[DECL:%.+]], [[ST]]** [[CBP0]]
+ // CK14-DAG: store i32* %{{.+}}, i32** [[CP0]]
// CK14-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
// CK14-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
- // CK14-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK14-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK14-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK14-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK14-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[ST]]**
+ // CK14-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK14-DAG: store [[ST]]* [[DECL]], [[ST]]** [[CBP1]]
+ // CK14-DAG: store double* %{{.+}}, double** [[CP1]]
+
+ // CK14-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 2
+ // CK14-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 2
+ // CK14-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK14-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK14-DAG: store i[[sz]] [[VAL:%.+]], i[[sz]]* [[CBP1]]
+ // CK14-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK14-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK14-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK14-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -771,17 +799,17 @@ void implicit_maps_class (int a){
#ifdef CK15
// CK15: [[ST:%.+]] = type { i32, double, i32* }
-// CK15: [[SIZES:@.+]] = {{.+}}constant [2 x i[[sz:64|32]]] [i{{64|32}} {{24|16}}, i{{64|32}} 4]
+// CK15: [[SIZES:@.+]] = {{.+}}constant [5 x i[[sz:64|32]]] [i{{64|32}} 4, i{{64|32}} 8, i{{64|32}} {{8|4}}, i{{64|32}} 4, i{{64|32}} 4]
// Map types:
-// - OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST = 35
+// - OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST + OMP_MAP_IMPLICIT = 547
// - OMP_MAP_PRIVATE_VAL + OMP_MAP_IS_FIRST = 288
-// CK15: [[TYPES:@.+]] = {{.+}}constant [2 x i32] [i32 35, i32 288]
+// CK15: [[TYPES:@.+]] = {{.+}}constant [5 x i32] [i32 547, i32 515, i32 512, i32 531, i32 288]
-// CK15: [[SIZES2:@.+]] = {{.+}}constant [2 x i[[sz]]] [i{{64|32}} {{24|16}}, i{{64|32}} 4]
+// CK15: [[SIZES2:@.+]] = {{.+}}constant [5 x i[[sz]]] [i{{64|32}} 4, i{{64|32}} 8, i{{64|32}} {{8|4}}, i{{64|32}} 4, i{{64|32}} 4]
// Map types:
// - OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST = 35
// - OMP_MAP_PRIVATE_VAL + OMP_MAP_IS_FIRST = 288
-// CK15: [[TYPES2:@.+]] = {{.+}}constant [2 x i32] [i32 35, i32 288]
+// CK15: [[TYPES2:@.+]] = {{.+}}constant [5 x i32] [i32 547, i32 515, i32 512, i32 531, i32 288]
template<int x>
class SSST {
@@ -816,23 +844,44 @@ void implicit_maps_templated_class (int a){
SSST<123> ssst(a, (double)a, a);
// CK15: define {{.*}}void @{{.+}}foo{{.+}}([[ST]]* {{[^,]+}}, i32 {{[^,]+}})
- // CK15-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 2, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
+ // CK15-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 5, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES]]{{.+}}, {{.+}}[[TYPES]]{{.+}})
// CK15-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
// CK15-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK15-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK15-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK15-DAG: store i8* [[VALBP0:%.+]], i8** [[BP0]],
- // CK15-DAG: store i8* [[VALP0:%.+]], i8** [[P0]],
- // CK15-DAG: [[VALBP0]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
- // CK15-DAG: [[VALP0]] = bitcast [[ST]]* [[DECL]] to i8*
+ // CK15-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK15-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK15-DAG: store [[ST]]* [[DECL:%.+]], [[ST]]** [[CBP0]]
+ // CK15-DAG: store i32* %{{.+}}, i32** [[CP0]]
// CK15-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
// CK15-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
- // CK15-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK15-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK15-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK15-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK15-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[ST]]**
+ // CK15-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK15-DAG: store [[ST]]* [[DECL]], [[ST]]** [[CBP1]]
+ // CK15-DAG: store double* %{{.+}}, double** [[CP1]]
+
+ // CK15-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 2
+ // CK15-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 2
+ // CK15-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [[ST]]**
+ // CK15-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to i32***
+ // CK15-DAG: store [[ST]]* [[DECL]], [[ST]]** [[CBP2]]
+ // CK15-DAG: store i32** %{{.+}}, i32*** [[CP2]]
+
+ // CK15-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 3
+ // CK15-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 3
+ // CK15-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to i32***
+ // CK15-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to i32**
+ // CK15-DAG: store i32** %{{.+}}, i32*** [[CBP3]]
+ // CK15-DAG: store i32* %{{.+}}, i32** [[CP3]]
+
+ // CK15-DAG: [[BP4:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 4
+ // CK15-DAG: [[P4:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 4
+ // CK15-DAG: [[CBP4:%.+]] = bitcast i8** [[BP4]] to i[[sz]]*
+ // CK15-DAG: [[CP4:%.+]] = bitcast i8** [[P4]] to i[[sz]]*
+ // CK15-DAG: store i[[sz]] [[VAL:%.+]], i[[sz]]* [[CBP4]]
+ // CK15-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP4]]
// CK15-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK15-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK15-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -841,23 +890,44 @@ void implicit_maps_templated_class (int a){
ssst.foo(456);
// CK15: define {{.*}}void @{{.+}}bar{{.+}}([[ST]]* {{[^,]+}}, i32 {{[^,]+}})
- // CK15-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 2, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES2]]{{.+}}, {{.+}}[[TYPES2]]{{.+}})
+ // CK15-DAG: call i32 @__tgt_target(i32 {{.+}}, i8* {{.+}}, i32 5, i8** [[BPGEP:%[0-9]+]], i8** [[PGEP:%[0-9]+]], {{.+}}[[SIZES2]]{{.+}}, {{.+}}[[TYPES2]]{{.+}})
// CK15-DAG: [[BPGEP]] = getelementptr inbounds {{.+}}[[BPS:%[^,]+]], i32 0, i32 0
// CK15-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK15-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK15-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK15-DAG: store i8* [[VALBP0:%.+]], i8** [[BP0]],
- // CK15-DAG: store i8* [[VALP0:%.+]], i8** [[P0]],
- // CK15-DAG: [[VALBP0]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
- // CK15-DAG: [[VALP0]] = bitcast [[ST]]* [[DECL]] to i8*
+ // CK15-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK15-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK15-DAG: store [[ST]]* [[DECL]], [[ST]]** [[CBP0]]
+ // CK15-DAG: store i32* %{{.+}}, i32** [[CP0]]
// CK15-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 1
// CK15-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 1
- // CK15-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK15-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK15-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK15-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK15-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[ST]]**
+ // CK15-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK15-DAG: store [[ST]]* [[DECL]], [[ST]]** [[CBP1]]
+ // CK15-DAG: store double* %{{.+}}, double** [[CP1]]
+
+ // CK15-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 2
+ // CK15-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 2
+ // CK15-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [[ST]]**
+ // CK15-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to i32***
+ // CK15-DAG: store [[ST]]* [[DECL]], [[ST]]** [[CBP2]]
+ // CK15-DAG: store i32** %{{.+}}, i32*** [[CP2]]
+
+ // CK15-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 3
+ // CK15-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 3
+ // CK15-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to i32***
+ // CK15-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to i32**
+ // CK15-DAG: store i32** %{{.+}}, i32*** [[CBP3]]
+ // CK15-DAG: store i32* %{{.+}}, i32** [[CP3]]
+
+ // CK15-DAG: [[BP4:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 4
+ // CK15-DAG: [[P4:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 4
+ // CK15-DAG: [[CBP4:%.+]] = bitcast i8** [[BP4]] to i[[sz]]*
+ // CK15-DAG: [[CP4:%.+]] = bitcast i8** [[P4]] to i[[sz]]*
+ // CK15-DAG: store i[[sz]] [[VAL:%.+]], i[[sz]]* [[CBP4]]
+ // CK15-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP4]]
// CK15-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK15-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK15-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -923,10 +993,10 @@ void implicit_maps_templated_function (int a){
// CK16-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK16-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK16-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK16-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK16-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK16-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK16-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK16-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK16-DAG: store i[[sz]] [[VAL:%.+]], i[[sz]]* [[CBP1]]
+ // CK16-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK16-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK16-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK16-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -953,8 +1023,8 @@ void implicit_maps_templated_function (int a){
// CK17-DAG: [[ST:%.+]] = type { i32, double }
// CK17-DAG: [[SIZES:@.+]] = {{.+}}constant [1 x i[[sz:64|32]]] [i{{64|32}} {{16|12}}]
-// Map types: OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST = 35
-// CK17-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 35]
+// Map types: OMP_MAP_TO + OMP_MAP_FROM + OMP_MAP_IS_FIRST + OMP_MAP_IMPLICIT = 547
+// CK17-DAG: [[TYPES:@.+]] = {{.+}}constant [1 x i32] [i32 547]
class SSS {
public:
@@ -971,10 +1041,10 @@ void implicit_maps_struct (int a){
// CK17-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK17-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK17-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK17-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK17-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK17-DAG: [[VALBP]] = bitcast [[ST]]* [[DECL:%.+]] to i8*
- // CK17-DAG: [[VALP]] = bitcast [[ST]]* [[DECL]] to i8*
+ // CK17-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[ST]]**
+ // CK17-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to [[ST]]**
+ // CK17-DAG: store [[ST]]* [[DECL:%.+]], [[ST]]** [[CBP1]]
+ // CK17-DAG: store [[ST]]* [[DECL]], [[ST]]** [[CP1]]
// CK17: call void [[KERNEL:@.+]]([[ST]]* [[DECL]])
#pragma omp target
@@ -1023,10 +1093,10 @@ void implicit_maps_template_type_capture (int a){
// CK18-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK18-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK18-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK18-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK18-DAG: [[VALBP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
- // CK18-DAG: [[VALP]] = inttoptr i[[sz]] [[VAL:%.+]] to i8*
+ // CK18-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[sz]]*
+ // CK18-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[sz]]*
+ // CK18-DAG: store i[[sz]] [[VAL:%.+]], i[[sz]]* [[CBP1]]
+ // CK18-DAG: store i[[sz]] [[VAL]], i[[sz]]* [[CP1]]
// CK18-DAG: [[VAL]] = load i[[sz]], i[[sz]]* [[ADDR:%.+]],
// CK18-64-DAG: [[CADDR:%.+]] = bitcast i[[sz]]* [[ADDR]] to i32*
// CK18-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -1054,6 +1124,9 @@ void implicit_maps_template_type_capture (int a){
// CK19: [[SIZE00:@.+]] = private {{.*}}constant [1 x i[[Z:64|32]]] [i[[Z:64|32]] 4]
// CK19: [[MTYPE00:@.+]] = private {{.*}}constant [1 x i32] [i32 32]
+// CK19: [[SIZE00n:@.+]] = private {{.*}}constant [1 x i[[Z:64|32]]] [i[[Z:64|32]] 4]
+// CK19: [[MTYPE00n:@.+]] = private {{.*}}constant [1 x i32] [i32 32]
+
// CK19: [[SIZE01:@.+]] = private {{.*}}constant [1 x i[[Z]]] [i[[Z]] 400]
// CK19: [[MTYPE01:@.+]] = private {{.*}}constant [1 x i32] [i32 33]
@@ -1181,10 +1254,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK19: call void [[CALL00:@.+]](i32* {{[^,]+}})
#pragma omp target map(alloc:a)
@@ -1192,6 +1265,28 @@ void explicit_maps_single (int ii){
++a;
}
+ // Map of a scalar in nested region.
+ int b = a;
+
+ // Region 00n
+ // CK19-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 1, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[SIZE00n]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[MTYPE00n]]{{.+}})
+ // CK19-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
+ // CK19-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
+
+ // CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
+ // CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[VAR0]], i32** [[CP0]]
+
+ // CK19: call void [[CALL00n:@.+]](i32* {{[^,]+}})
+ #pragma omp target map(alloc:b)
+ #pragma omp parallel
+ {
+ ++b;
+ }
+
// Map of an array.
int arra[100];
@@ -1202,10 +1297,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [100 x i32]* [[VAR0]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [100 x i32]**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store [100 x i32]* [[VAR0]], [100 x i32]** [[CP0]]
// CK19: call void [[CALL01:@.+]]([100 x i32]* {{[^,]+}})
#pragma omp target map(to:arra)
@@ -1220,10 +1315,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%[^,]+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[100 x i32]* [[VAR0]], i{{.+}} 0, i{{.+}} 20
// CK19: call void [[CALL02:@.+]]([100 x i32]* {{[^,]+}})
@@ -1239,10 +1334,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%[^,]+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[100 x i32]* [[VAR0]], i{{.+}} 0, i{{.+}} 0
// CK19: call void [[CALL03:@.+]]([100 x i32]* {{[^,]+}})
@@ -1258,10 +1353,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%[^,]+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[100 x i32]* [[VAR0]], i{{.+}} 0, i{{.+}} 0
// CK19: call void [[CALL04:@.+]]([100 x i32]* {{[^,]+}})
@@ -1277,10 +1372,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%[^,]+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[100 x i32]* [[VAR0]], i{{.+}} 0, i{{.+}} 15
// CK19: call void [[CALL05:@.+]]([100 x i32]* {{[^,]+}})
@@ -1298,11 +1393,11 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%[^,]+]], i32** [[CP0]]
// CK19-DAG: store i{{.+}} [[CSVAL0:%[^,]+]], i{{.+}}* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
// CK19-DAG: [[CSVAL0]] = mul nuw i{{.+}} %{{.*}}, 4
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[100 x i32]* [[VAR0]], i{{.+}} 0, i{{.+}} %{{.*}}
@@ -1321,11 +1416,11 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%[^,]+]], i32** [[CP0]]
// CK19-DAG: store i{{.+}} [[CSVAL0:%[^,]+]], i{{.+}}* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
// CK19-DAG: [[CSVAL0]] = mul nuw i{{.+}} %{{.*}}, 4
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[100 x i32]* [[VAR0]], i{{.+}} 0, i{{.+}} 0
@@ -1342,10 +1437,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [100 x i32]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [100 x i32]* [[VAR0:%.+]], [100 x i32]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%[^,]+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[100 x i32]* [[VAR0]], i{{.+}} 0, i{{.+}} %{{.*}}
// CK19: call void [[CALL08:@.+]]([100 x i32]* {{[^,]+}})
@@ -1364,10 +1459,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32** [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32** [[VAR0]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32***
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32***
+ // CK19-DAG: store i32** [[VAR0:%.+]], i32*** [[CBP0]]
+ // CK19-DAG: store i32** [[VAR0]], i32*** [[CP0]]
// CK19: call void [[CALL09:@.+]](i32** {{[^,]+}})
#pragma omp target map(from:pa)
@@ -1382,10 +1477,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 20
// CK19-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -1403,10 +1498,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 0
// CK19-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -1424,10 +1519,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 15
// CK19-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -1447,11 +1542,11 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: store i{{.+}} [[CSVAL0:%[^,]+]], i{{.+}}* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
// CK19-DAG: [[CSVAL0]] = mul nuw i{{.+}} %{{.*}}, 4
// CK19-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} %{{.*}}
@@ -1472,11 +1567,11 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: store i{{.+}} [[CSVAL0:%[^,]+]], i{{.+}}* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
// CK19-DAG: [[CSVAL0]] = mul nuw i{{.+}} %{{.*}}, 4
// CK19-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 0
@@ -1495,10 +1590,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} %{{.*}}
// CK19-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -1521,20 +1616,20 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CP0]]
// CK19-DAG: store i{{.+}} {{8|4}}, i{{.+}}* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = inttoptr i[[Z]] %{{.+}} to i8*
- // CK19-DAG: [[CPVAL0]] = inttoptr i[[Z]] %{{.+}}to i8*
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK19-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK19-DAG: store i32* [[VAR1]], i32** [[CP1]]
// CK19-DAG: store i{{.+}} [[CSVAL1:%[^,]+]], i{{.+}}* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32* [[VAR1]] to i8*
// CK19-DAG: [[CSVAL1]] = mul nuw i{{.+}} %{{.*}}, 4
// CK19: call void [[CALL16:@.+]](i{{.+}} {{[^,]+}}, i32* {{[^,]+}})
@@ -1550,17 +1645,17 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = inttoptr i[[Z]] %{{.+}} to i8*
- // CK19-DAG: [[CPVAL0]] = inttoptr i[[Z]] %{{.+}}to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CP0]]
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK19-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK19-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32* [[VAR1]], i{{.+}} 20
// CK19: call void [[CALL17:@.+]](i{{.+}} {{[^,]+}}, i32* {{[^,]+}})
@@ -1576,17 +1671,17 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = inttoptr i[[Z]] %{{.+}} to i8*
- // CK19-DAG: [[CPVAL0]] = inttoptr i[[Z]] %{{.+}}to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CP0]]
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK19-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK19-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32* [[VAR1]], i{{.+}} 0
// CK19: call void [[CALL18:@.+]](i{{.+}} {{[^,]+}}, i32* {{[^,]+}})
@@ -1604,20 +1699,20 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CP0]]
// CK19-DAG: store i{{.+}} {{8|4}}, i{{.+}}* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = inttoptr i[[Z]] %{{.+}} to i8*
- // CK19-DAG: [[CPVAL0]] = inttoptr i[[Z]] %{{.+}}to i8*
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK19-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK19-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK19-DAG: store i{{.+}} [[CSVAL1:%[^,]+]], i{{.+}}* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
// CK19-DAG: [[CSVAL1]] = mul nuw i{{.+}} %{{.*}}, 4
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32* [[VAR1]], i{{.+}} 0
@@ -1634,17 +1729,17 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = inttoptr i[[Z]] %{{.+}} to i8*
- // CK19-DAG: [[CPVAL0]] = inttoptr i[[Z]] %{{.+}}to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CP0]]
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK19-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK19-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32* [[VAR1]], i{{.+}} 15
// CK19: call void [[CALL20:@.+]](i{{.+}} {{[^,]+}}, i32* {{[^,]+}})
@@ -1662,20 +1757,20 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CP0]]
// CK19-DAG: store i{{.+}} {{8|4}}, i{{.+}}* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = inttoptr i[[Z]] %{{.+}} to i8*
- // CK19-DAG: [[CPVAL0]] = inttoptr i[[Z]] %{{.+}}to i8*
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK19-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK19-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK19-DAG: store i{{.+}} [[CSVAL1:%[^,]+]], i{{.+}}* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
// CK19-DAG: [[CSVAL1]] = mul nuw i{{.+}} %{{.*}}, 4
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32* [[VAR1]], i{{.+}} %{{.+}}
@@ -1692,17 +1787,17 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = inttoptr i[[Z]] %{{.+}} to i8*
- // CK19-DAG: [[CPVAL0]] = inttoptr i[[Z]] %{{.+}}to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] {{%.+}}, i[[Z]]* [[CP0]]
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK19-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK19-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32* [[VAR1]], i{{.+}} %{{.+}}
// CK19: call void [[CALL22:@.+]](i{{.+}} {{[^,]+}}, i32* {{[^,]+}})
@@ -1719,10 +1814,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK19-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK19: call void [[CALL23:@.+]](i32* {{[^,]+}})
#pragma omp target map(always, tofrom: a)
@@ -1741,10 +1836,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [4 x [5 x [6 x i32]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [4 x [5 x [6 x i32]]]* [[VAR0]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [4 x [5 x [6 x i32]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [4 x [5 x [6 x i32]]]**
+ // CK19-DAG: store [4 x [5 x [6 x i32]]]* [[VAR0:%.+]], [4 x [5 x [6 x i32]]]** [[CBP0]]
+ // CK19-DAG: store [4 x [5 x [6 x i32]]]* [[VAR0]], [4 x [5 x [6 x i32]]]** [[CP0]]
// CK19: call void [[CALL24:@.+]]([4 x [5 x [6 x i32]]]* {{[^,]+}})
#pragma omp target map(tofrom: marr)
@@ -1759,10 +1854,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [4 x [5 x [6 x i32]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [4 x [5 x [6 x i32]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [4 x [5 x [6 x i32]]]* [[VAR0:%.+]], [4 x [5 x [6 x i32]]]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[6 x i32]* [[SEC00:[^,]+]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[SEC00]] = getelementptr {{.*}}[5 x [6 x i32]]* [[SEC000:[^,]+]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[SEC000]] = getelementptr {{.*}}[4 x [5 x [6 x i32]]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
@@ -1780,10 +1875,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [4 x [5 x [6 x i32]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [4 x [5 x [6 x i32]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [4 x [5 x [6 x i32]]]* [[VAR0:%.+]], [4 x [5 x [6 x i32]]]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[6 x i32]* [[SEC00:[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[SEC00]] = getelementptr {{.*}}[5 x [6 x i32]]* [[SEC000:[^,]+]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[SEC000]] = getelementptr {{.*}}[4 x [5 x [6 x i32]]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
@@ -1801,10 +1896,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [4 x [5 x [6 x i32]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [4 x [5 x [6 x i32]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK19-DAG: store [4 x [5 x [6 x i32]]]* [[VAR0:%.+]], [4 x [5 x [6 x i32]]]** [[CBP0]]
+ // CK19-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}[6 x i32]* [[SEC00:[^,]+]], i{{.+}} 0, i{{.+}} 3
// CK19-DAG: [[SEC00]] = getelementptr {{.*}}[5 x [6 x i32]]* [[SEC000:[^,]+]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[SEC000]] = getelementptr {{.*}}[4 x [5 x [6 x i32]]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
@@ -1822,20 +1917,20 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32*** [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32*** [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32****
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32****
+ // CK19-DAG: store i32*** [[VAR0:%.+]], i32**** [[CBP0]]
+ // CK19-DAG: store i32*** [[SEC0:%.+]], i32**** [[CP0]]
// CK19-DAG: [[VAR0]] = load i32***, i32**** [[PTR:%[^,]+]],
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32*** [[SEC00:[^,]+]], i{{.+}} 1
// CK19-DAG: [[SEC00]] = load i32***, i32**** [[PTR]],
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32*** [[SEC0]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32** [[SEC1:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32****
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32***
+ // CK19-DAG: store i32*** [[SEC0]], i32**** [[CBP1]]
+ // CK19-DAG: store i32** [[SEC1:%.+]], i32*** [[CP1]]
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32** [[SEC11:[^,]+]], i{{.+}} 2
// CK19-DAG: [[SEC11]] = load i32**, i32*** [[SEC111:%[^,]+]],
// CK19-DAG: [[SEC111]] = getelementptr {{.*}}i32*** [[SEC1111:[^,]+]], i{{.+}} 1
@@ -1843,10 +1938,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast i32** [[SEC1]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast i32* [[SEC2:%.+]] to i8*
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to i32***
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to i32**
+ // CK19-DAG: store i32** [[SEC1]], i32*** [[CBP2]]
+ // CK19-DAG: store i32* [[SEC2:%.+]], i32** [[CP2]]
// CK19-DAG: [[SEC2]] = getelementptr {{.*}}i32* [[SEC22:[^,]+]], i{{.+}} 2
// CK19-DAG: [[SEC22]] = load i32*, i32** [[SEC222:%[^,]+]],
// CK19-DAG: [[SEC222]] = getelementptr {{.*}}i32** [[SEC2222:[^,]+]], i{{.+}} 2
@@ -1867,20 +1962,20 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast i32*** [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast i32*** [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32****
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32****
+ // CK19-DAG: store i32*** [[VAR0:%.+]], i32**** [[CBP0]]
+ // CK19-DAG: store i32*** [[SEC0:%.+]], i32**** [[CP0]]
// CK19-DAG: [[VAR0]] = load i32***, i32**** [[PTR:%[^,]+]],
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}i32*** [[SEC00:[^,]+]], i{{.+}} 1
// CK19-DAG: [[SEC00]] = load i32***, i32**** [[PTR]],
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast i32*** [[SEC0]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast i32** [[SEC1:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32****
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32***
+ // CK19-DAG: store i32*** [[SEC0]], i32**** [[CBP1]]
+ // CK19-DAG: store i32** [[SEC1:%.+]], i32*** [[CP1]]
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}i32** [[SEC11:[^,]+]], i{{.+}} 2
// CK19-DAG: [[SEC11]] = load i32**, i32*** [[SEC111:%[^,]+]],
// CK19-DAG: [[SEC111]] = getelementptr {{.*}}i32*** [[SEC1111:[^,]+]], i{{.+}} 1
@@ -1888,10 +1983,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast i32** [[SEC1]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast i32* [[SEC2:%.+]] to i8*
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to i32***
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to i32**
+ // CK19-DAG: store i32** [[SEC1]], i32*** [[CBP2]]
+ // CK19-DAG: store i32* [[SEC2:%.+]], i32** [[CP2]]
// CK19-DAG: [[SEC2]] = getelementptr {{.*}}i32* [[SEC22:[^,]+]], i{{.+}} 3
// CK19-DAG: [[SEC22]] = load i32*, i32** [[SEC222:%[^,]+]],
// CK19-DAG: [[SEC222]] = getelementptr {{.*}}i32** [[SEC2222:[^,]+]], i{{.+}} 2
@@ -1917,40 +2012,42 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* inttoptr (i[[Z]] 23 to i8*), i8** [[BP0]]
- // CK19-DAG: store i8* inttoptr (i[[Z]] 23 to i8*), i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] 23, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] 23, i[[Z]]* [[CP0]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S0]]
//
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR1:%.+]], i[[Z]]* [[CBP1]]
+ // CK19-DAG: store i[[Z]] [[VAR11:%.+]], i[[Z]]* [[CP1]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = inttoptr i[[Z]] [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = inttoptr i[[Z]] [[VAR11:%.+]] to i8*
// CK19-64-DAG: [[VAR1]] = zext i32 %{{[^,]+}} to i64
// CK19-64-DAG: [[VAR11]] = zext i32 %{{[^,]+}} to i64
//
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to i[[Z]]*
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR2:%.+]], i[[Z]]* [[CBP2]]
+ // CK19-DAG: store i[[Z]] [[VAR22:%.+]], i[[Z]]* [[CP2]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S2]]
- // CK19-DAG: [[CBPVAL2]] = inttoptr i[[Z]] [[VAR2:%.+]] to i8*
- // CK19-DAG: [[CPVAL2]] = inttoptr i[[Z]] [[VAR22:%.+]] to i8*
// CK19-64-DAG: [[VAR2]] = zext i32 %{{[^,]+}} to i64
// CK19-64-DAG: [[VAR22]] = zext i32 %{{[^,]+}} to i64
//
// CK19-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3
// CK19-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3
// CK19-DAG: [[S3:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 3
- // CK19-DAG: store i8* [[CBPVAL3:%[^,]+]], i8** [[BP3]]
- // CK19-DAG: store i8* [[CPVAL3:%[^,]+]], i8** [[P3]]
+ // CK19-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to double**
+ // CK19-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to double**
+ // CK19-DAG: store double* [[VAR3:%.+]], double** [[CBP3]]
+ // CK19-DAG: store double* [[VAR3]], double** [[CP3]]
// CK19-DAG: store i[[Z]] [[CSVAL3:%[^,]+]], i[[Z]]* [[S3]]
- // CK19-DAG: [[CBPVAL3]] = bitcast double* [[VAR3:%.+]] to i8*
- // CK19-DAG: [[CPVAL3]] = bitcast double* [[VAR3]] to i8*
// CK19-DAG: [[CSVAL3]] = mul nuw i[[Z]] %{{[^,]+}}, {{8|4}}
// CK19: call void [[CALL30:@.+]](i[[Z]] 23, i[[Z]] %{{[^,]+}}, i[[Z]] %{{[^,]+}}, double* %{{[^,]+}})
@@ -1966,29 +2063,31 @@ void explicit_maps_single (int ii){
//
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* inttoptr (i[[Z]] 23 to i8*), i8** [[BP0]]
- // CK19-DAG: store i8* inttoptr (i[[Z]] 23 to i8*), i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] 23, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] 23, i[[Z]]* [[CP0]]
//
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = inttoptr i[[Z]] [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = inttoptr i[[Z]] [[VAR11:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR1:%.+]], i[[Z]]* [[CBP1]]
+ // CK19-DAG: store i[[Z]] [[VAR11:%.+]], i[[Z]]* [[CP1]]
//
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK19-DAG: [[CBPVAL2]] = inttoptr i[[Z]] [[VAR2:%.+]] to i8*
- // CK19-DAG: [[CPVAL2]] = inttoptr i[[Z]] [[VAR22:%.+]] to i8*
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to i[[Z]]*
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR2:%.+]], i[[Z]]* [[CBP2]]
+ // CK19-DAG: store i[[Z]] [[VAR22:%.+]], i[[Z]]* [[CP2]]
//
// CK19-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3
// CK19-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3
- // CK19-DAG: store i8* [[CBPVAL3:%[^,]+]], i8** [[BP3]]
- // CK19-DAG: store i8* [[CPVAL3:%[^,]+]], i8** [[P3]]
- // CK19-DAG: [[CBPVAL3]] = bitcast double* [[VAR3:%.+]] to i8*
- // CK19-DAG: [[CPVAL3]] = bitcast double* [[SEC3:%.+]] to i8*
+ // CK19-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to double**
+ // CK19-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to double**
+ // CK19-DAG: store double* [[VAR3:%.+]], double** [[CBP3]]
+ // CK19-DAG: store double* [[SEC3:%.+]], double** [[CP3]]
// CK19-DAG: [[SEC3]] = getelementptr {{.*}}double* [[SEC33:%.+]], i[[Z]] 0
// CK19-DAG: [[SEC33]] = getelementptr {{.*}}double* [[SEC333:%.+]], i[[Z]] [[IDX3:%.+]]
// CK19-DAG: [[IDX3]] = mul nsw i[[Z]] %{{[^,]+}}, %{{[^,]+}}
@@ -2013,10 +2112,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [11 x [12 x [13 x double]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [11 x [12 x [13 x double]]]* [[VAR0]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [11 x [12 x [13 x double]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [11 x [12 x [13 x double]]]**
+ // CK19-DAG: store [11 x [12 x [13 x double]]]* [[VAR0:%.+]], [11 x [12 x [13 x double]]]** [[CBP0]]
+ // CK19-DAG: store [11 x [12 x [13 x double]]]* [[VAR0]], [11 x [12 x [13 x double]]]** [[CP0]]
// CK19: call void [[CALL32:@.+]]([11 x [12 x [13 x double]]]* {{[^,]+}})
#pragma omp target map(marras)
@@ -2031,10 +2130,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [11 x [12 x [13 x double]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [12 x [13 x double]]* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [11 x [12 x [13 x double]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [12 x [13 x double]]**
+ // CK19-DAG: store [11 x [12 x [13 x double]]]* [[VAR0:%.+]], [11 x [12 x [13 x double]]]** [[CBP0]]
+ // CK19-DAG: store [12 x [13 x double]]* [[SEC0:%.+]], [12 x [13 x double]]** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.+}}[11 x [12 x [13 x double]]]* [[VAR0]], i[[Z]] 0, i[[Z]] 0
// CK19: call void [[CALL33:@.+]]([11 x [12 x [13 x double]]]* {{[^,]+}})
@@ -2050,10 +2149,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [11 x [12 x [13 x double]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [12 x [13 x double]]* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [11 x [12 x [13 x double]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [12 x [13 x double]]**
+ // CK19-DAG: store [11 x [12 x [13 x double]]]* [[VAR0:%.+]], [11 x [12 x [13 x double]]]** [[CBP0]]
+ // CK19-DAG: store [12 x [13 x double]]* [[SEC0:%.+]], [12 x [13 x double]]** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.+}}[11 x [12 x [13 x double]]]* [[VAR0]], i[[Z]] 0, i[[Z]] 0
// CK19: call void [[CALL34:@.+]]([11 x [12 x [13 x double]]]* {{[^,]+}})
@@ -2072,11 +2171,11 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [11 x [12 x [13 x double]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [13 x double]**
+ // CK19-DAG: store [11 x [12 x [13 x double]]]* [[VAR0:%.+]], [11 x [12 x [13 x double]]]** [[CBP0]]
+ // CK19-DAG: store [13 x double]* [[SEC0:%.+]], [13 x double]** [[CP0]]
// CK19-DAG: store i[[Z]] [[CSVAL0:%[^,]+]], i[[Z]]* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [11 x [12 x [13 x double]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [13 x double]* [[SEC0:%.+]] to i8*
// CK19-DAG: [[SEC0]] = getelementptr {{.+}}[12 x [13 x double]]* [[SEC00:%[^,]+]], i[[Z]] 0, i[[Z]] 0
// CK19-DAG: [[SEC00]] = getelementptr {{.+}}[11 x [12 x [13 x double]]]* [[VAR0]], i[[Z]] 0, i[[Z]] 1
// CK19-DAG: [[CSVAL0]] = mul nuw i[[Z]] %{{[^,]+}}, 104
@@ -2094,10 +2193,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [11 x [12 x [13 x double]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [13 x double]* [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [11 x [12 x [13 x double]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [13 x double]**
+ // CK19-DAG: store [11 x [12 x [13 x double]]]* [[VAR0:%.+]], [11 x [12 x [13 x double]]]** [[CBP0]]
+ // CK19-DAG: store [13 x double]* [[SEC0:%.+]], [13 x double]** [[CP0]]
// CK19-DAG: [[SEC0]] = getelementptr {{.+}}[13 x double]* [[SEC00:%[^,]+]], i{{.+}} 0
// CK19-DAG: [[SEC00]] = getelementptr {{.+}}[12 x [13 x double]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[SEC000]] = getelementptr {{.+}}[11 x [12 x [13 x double]]]* [[VAR0]], i{{.+}} 0, i{{.+}} 0
@@ -2117,27 +2216,29 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[BP0]]
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CP0]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S0]]
//
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR1:%.+]], i[[Z]]* [[CBP1]]
+ // CK19-DAG: store i[[Z]] [[VAR11:%.+]], i[[Z]]* [[CP1]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = inttoptr i[[Z]] [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = inttoptr i[[Z]] [[VAR11:%.+]] to i8*
//
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [13 x double]**
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to [13 x double]**
+ // CK19-DAG: store [13 x double]* [[VAR2:%.+]], [13 x double]** [[CBP2]]
+ // CK19-DAG: store [13 x double]* [[VAR2]], [13 x double]** [[CP2]]
// CK19-DAG: store i[[Z]] [[CSVAL2:%[^,]+]], i[[Z]]* [[S2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast [13 x double]* [[VAR2:%.+]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast [13 x double]* [[VAR2]] to i8*
// CK19-DAG: [[CSVAL2]] = mul nuw i[[Z]] %{{[^,]+}}, 104
// CK19: call void [[CALL37:@.+]](i[[Z]] 11, i[[Z]] %{{[^,]+}}, [13 x double]* %{{[^,]+}})
@@ -2155,27 +2256,29 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[BP0]]
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CP0]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S0]]
//
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR1:%.+]], i[[Z]]* [[CBP1]]
+ // CK19-DAG: store i[[Z]] [[VAR11:%.+]], i[[Z]]* [[CP1]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = inttoptr i[[Z]] [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = inttoptr i[[Z]] [[VAR11:%.+]] to i8*
//
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [13 x double]**
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to [13 x double]**
+ // CK19-DAG: store [13 x double]* [[VAR2:%.+]], [13 x double]** [[CBP2]]
+ // CK19-DAG: store [13 x double]* [[SEC2:%.+]], [13 x double]** [[CP2]]
// CK19-DAG: store i[[Z]] [[CSVAL2:%[^,]+]], i[[Z]]* [[S2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast [13 x double]* [[VAR2:%.+]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast [13 x double]* [[SEC2:%.+]] to i8*
// CK19-DAG: [[SEC2]] = getelementptr {{.+}}[13 x double]* [[VAR2]], i[[Z]] [[SEC22:%[^,]+]]
// CK19-DAG: [[SEC22]] = mul nsw i[[Z]] 0, %{{[^,]+}}
// CK19-DAG: [[CSVAL2]] = mul nuw i[[Z]] %{{[^,]+}}, 104
@@ -2195,27 +2298,29 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[BP0]]
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CP0]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S0]]
//
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR1:%.+]], i[[Z]]* [[CBP1]]
+ // CK19-DAG: store i[[Z]] [[VAR11:%.+]], i[[Z]]* [[CP1]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = inttoptr i[[Z]] [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = inttoptr i[[Z]] [[VAR11:%.+]] to i8*
//
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [13 x double]**
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to [13 x double]**
+ // CK19-DAG: store [13 x double]* [[VAR2:%.+]], [13 x double]** [[CBP2]]
+ // CK19-DAG: store [13 x double]* [[SEC2:%.+]], [13 x double]** [[CP2]]
// CK19-DAG: store i[[Z]] [[CSVAL2:%[^,]+]], i[[Z]]* [[S2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast [13 x double]* [[VAR2:%.+]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast [13 x double]* [[SEC2:%.+]] to i8*
// CK19-DAG: [[SEC2]] = getelementptr {{.+}}[13 x double]* [[VAR2]], i[[Z]] [[SEC22:%[^,]+]]
// CK19-DAG: [[SEC22]] = mul nsw i[[Z]] 0, %{{[^,]+}}
// CK19-DAG: [[CSVAL2]] = mul nuw i[[Z]] %{{[^,]+}}, 104
@@ -2235,27 +2340,29 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[BP0]]
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CP0]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S0]]
//
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[S1:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR1:%.+]], i[[Z]]* [[CBP1]]
+ // CK19-DAG: store i[[Z]] [[VAR11:%.+]], i[[Z]]* [[CP1]]
// CK19-DAG: store i[[Z]] {{8|4}}, i[[Z]]* [[S1]]
- // CK19-DAG: [[CBPVAL1]] = inttoptr i[[Z]] [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = inttoptr i[[Z]] [[VAR11:%.+]] to i8*
//
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[S2:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [13 x double]**
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to [13 x double]**
+ // CK19-DAG: store [13 x double]* [[VAR2:%.+]], [13 x double]** [[CBP2]]
+ // CK19-DAG: store [13 x double]* [[SEC2:%.+]], [13 x double]** [[CP2]]
// CK19-DAG: store i[[Z]] [[CSVAL2:%[^,]+]], i[[Z]]* [[S2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast [13 x double]* [[VAR2:%.+]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast [13 x double]* [[SEC2:%.+]] to i8*
// CK19-DAG: [[SEC2]] = getelementptr {{.+}}[13 x double]* [[SEC22:%[^,]+]], i[[Z]] 0
// CK19-DAG: [[SEC22]] = getelementptr {{.+}}[13 x double]* [[VAR2]], i[[Z]] [[SEC222:%[^,]+]]
// CK19-DAG: [[SEC222]] = mul nsw i[[Z]] 1, %{{[^,]+}}
@@ -2273,22 +2380,24 @@ void explicit_maps_single (int ii){
//
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[BP0]]
- // CK19-DAG: store i8* inttoptr (i[[Z]] 11 to i8*), i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i[[Z]]*
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CBP0]]
+ // CK19-DAG: store i[[Z]] 11, i[[Z]]* [[CP0]]
//
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = inttoptr i[[Z]] [[VAR1:%.+]] to i8*
- // CK19-DAG: [[CPVAL1]] = inttoptr i[[Z]] [[VAR11:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK19-DAG: store i[[Z]] [[VAR1:%.+]], i[[Z]]* [[CBP1]]
+ // CK19-DAG: store i[[Z]] [[VAR11:%.+]], i[[Z]]* [[CP1]]
//
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast [13 x double]* [[VAR2:%.+]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast [13 x double]* [[SEC2:%.+]] to i8*
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [13 x double]**
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to [13 x double]**
+ // CK19-DAG: store [13 x double]* [[VAR2:%.+]], [13 x double]** [[CBP2]]
+ // CK19-DAG: store [13 x double]* [[SEC2:%.+]], [13 x double]** [[CP2]]
// CK19-DAG: [[SEC2]] = getelementptr {{.+}}[13 x double]* [[SEC22:%[^,]+]], i[[Z]] 0
// CK19-DAG: [[SEC22]] = getelementptr {{.+}}[13 x double]* [[VAR2]], i[[Z]] [[SEC222:%[^,]+]]
// CK19-DAG: [[SEC222]] = mul nsw i[[Z]] 0, %{{[^,]+}}
@@ -2306,20 +2415,20 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast double*** [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast double*** [[SEC0:%.+]] to i8*
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to double****
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double****
+ // CK19-DAG: store double*** [[VAR0:%.+]], double**** [[CBP0]]
+ // CK19-DAG: store double*** [[SEC0:%.+]], double**** [[CP0]]
// CK19-DAG: [[VAR0]] = load double***, double**** [[PTR:%[^,]+]],
// CK19-DAG: [[SEC0]] = getelementptr {{.*}}double*** [[SEC00:[^,]+]], i{{.+}} 0
// CK19-DAG: [[SEC00]] = load double***, double**** [[PTR]],
// CK19-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK19-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK19-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK19-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK19-DAG: [[CBPVAL1]] = bitcast double*** [[SEC0]] to i8*
- // CK19-DAG: [[CPVAL1]] = bitcast double** [[SEC1:%.+]] to i8*
+ // CK19-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double****
+ // CK19-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double***
+ // CK19-DAG: store double*** [[SEC0]], double**** [[CBP1]]
+ // CK19-DAG: store double** [[SEC1:%.+]], double*** [[CP1]]
// CK19-DAG: [[SEC1]] = getelementptr {{.*}}double** [[SEC11:[^,]+]], i{{.+}} 2
// CK19-DAG: [[SEC11]] = load double**, double*** [[SEC111:%[^,]+]],
// CK19-DAG: [[SEC111]] = getelementptr {{.*}}double*** [[SEC1111:[^,]+]], i{{.+}} 0
@@ -2327,10 +2436,10 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK19-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK19-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK19-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK19-DAG: [[CBPVAL2]] = bitcast double** [[SEC1]] to i8*
- // CK19-DAG: [[CPVAL2]] = bitcast double* [[SEC2:%.+]] to i8*
+ // CK19-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to double***
+ // CK19-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to double**
+ // CK19-DAG: store double** [[SEC1]], double*** [[CBP2]]
+ // CK19-DAG: store double* [[SEC2:%.+]], double** [[CP2]]
// CK19-DAG: [[SEC2]] = getelementptr {{.*}}double* [[SEC22:[^,]+]], i{{.+}} 0
// CK19-DAG: [[SEC22]] = load double*, double** [[SEC222:%[^,]+]],
// CK19-DAG: [[SEC222]] = getelementptr {{.*}}double** [[SEC2222:[^,]+]], i{{.+}} 2
@@ -2354,11 +2463,11 @@ void explicit_maps_single (int ii){
// CK19-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK19-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK19-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK19-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK19-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [11 x [12 x [13 x double]]]**
+ // CK19-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [13 x double]**
+ // CK19-DAG: store [11 x [12 x [13 x double]]]* [[VAR0:%.+]], [11 x [12 x [13 x double]]]** [[CBP0]]
+ // CK19-DAG: store [13 x double]* [[SEC0:%.+]], [13 x double]** [[CP0]]
// CK19-DAG: store i[[Z]] [[CSVAL0:%[^,]+]], i[[Z]]* [[S0]]
- // CK19-DAG: [[CBPVAL0]] = bitcast [11 x [12 x [13 x double]]]* [[VAR0:%.+]] to i8*
- // CK19-DAG: [[CPVAL0]] = bitcast [13 x double]* [[SEC0:%.+]] to i8*
// CK19-DAG: [[SEC0]] = getelementptr {{.+}}[12 x [13 x double]]* [[SEC00:%[^,]+]], i[[Z]] 0, i[[Z]] 0
// CK19-DAG: [[SEC00]] = getelementptr {{.+}}[11 x [12 x [13 x double]]]* [[VAR0]], i[[Z]] 0, i[[Z]] 1
// CK19-DAG: [[CSVAL0]] = mul nuw i[[Z]] %{{[^,]+}}, 104
@@ -2372,6 +2481,7 @@ void explicit_maps_single (int ii){
}
// CK19: define {{.+}}[[CALL00]]
+// CK19: define {{.+}}[[CALL00n]]
// CK19: define {{.+}}[[CALL01]]
// CK19: define {{.+}}[[CALL02]]
// CK19: define {{.+}}[[CALL03]]
@@ -2453,10 +2563,10 @@ void explicit_maps_references_and_function_args (int a, float b, int (&c)[10], f
// CK20-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK20-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK20-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK20-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK20-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK20-DAG: [[CPVAL0]] = bitcast i32* [[RVAR00:%.+]] to i8*
+ // CK20-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK20-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK20-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK20-DAG: store i32* [[RVAR00:%.+]], i32** [[CP0]]
// CK20-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK20-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -2473,10 +2583,10 @@ void explicit_maps_references_and_function_args (int a, float b, int (&c)[10], f
// CK20-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK20-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK20-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK20-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK20-DAG: [[CBPVAL0]] = bitcast [10 x i32]* [[RVAR0:%.+]] to i8*
- // CK20-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK20-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [10 x i32]**
+ // CK20-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK20-DAG: store [10 x i32]* [[RVAR0:%.+]], [10 x i32]** [[CBP0]]
+ // CK20-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK20-DAG: [[SEC0]] = getelementptr {{.*}}[10 x i32]* [[RVAR00:%.+]], i{{.+}} 0, i{{.+}} 0
// CK20-DAG: [[RVAR0]] = load [10 x i32]*, [10 x i32]** [[VAR0:%[^,]+]]
// CK20-DAG: [[RVAR00]] = load [10 x i32]*, [10 x i32]** [[VAR0]]
@@ -2494,10 +2604,10 @@ void explicit_maps_references_and_function_args (int a, float b, int (&c)[10], f
// CK20-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK20-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK20-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK20-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK20-DAG: [[CBPVAL0]] = bitcast float* [[VAR0:%.+]] to i8*
- // CK20-DAG: [[CPVAL0]] = bitcast float* [[VAR0]] to i8*
+ // CK20-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK20-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK20-DAG: store float* [[VAR0:%.+]], float** [[CBP0]]
+ // CK20-DAG: store float* [[VAR0]], float** [[CP0]]
// CK20: call void [[CALL02:@.+]](float* {{[^,]+}})
#pragma omp target map(from:b)
@@ -2512,10 +2622,10 @@ void explicit_maps_references_and_function_args (int a, float b, int (&c)[10], f
// CK20-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK20-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK20-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK20-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK20-DAG: [[CBPVAL0]] = bitcast float* [[RVAR0:%.+]] to i8*
- // CK20-DAG: [[CPVAL0]] = bitcast float* [[SEC0:%.+]] to i8*
+ // CK20-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK20-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK20-DAG: store float* [[RVAR0:%.+]], float** [[CBP0]]
+ // CK20-DAG: store float* [[SEC0:%.+]], float** [[CP0]]
// CK20-DAG: [[RVAR0]] = load float*, float** [[VAR0:%[^,]+]]
// CK20-DAG: [[SEC0]] = getelementptr {{.*}}float* [[RVAR00:%.+]], i{{.+}} 2
// CK20-DAG: [[RVAR00]] = load float*, float** [[VAR0]]
@@ -2580,10 +2690,10 @@ struct CC {
// CK21-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK21-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK21-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK21-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK21-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK21-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK21-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK21-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK21-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK21-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK21-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[VAR0:%.+]], i{{.+}} 0, i{{.+}} 0
// CK21: call void [[CALL00:@.+]]([[ST]]* {{[^,]+}})
@@ -2599,10 +2709,10 @@ struct CC {
// CK21-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK21-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK21-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK21-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK21-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK21-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK21-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK21-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK21-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK21-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK21-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK21-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 0
// CK21-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -2620,18 +2730,18 @@ struct CC {
// CK21-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK21-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK21-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK21-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK21-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK21-DAG: [[CPVAL0]] = bitcast float** [[SEC0:%.+]] to i8*
+ // CK21-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK21-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float***
+ // CK21-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK21-DAG: store float** [[SEC0:%.+]], float*** [[CP0]]
// CK21-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
// CK21-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK21-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK21-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK21-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK21-DAG: [[CBPVAL1]] = bitcast float** [[SEC0]] to i8*
- // CK21-DAG: [[CPVAL1]] = bitcast float* [[SEC1:%.+]] to i8*
+ // CK21-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to float***
+ // CK21-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to float**
+ // CK21-DAG: store float** [[SEC0]], float*** [[CBP1]]
+ // CK21-DAG: store float* [[SEC1:%.+]], float** [[CP1]]
// CK21-DAG: [[SEC1]] = getelementptr {{.*}}float* [[RVAR1:%[^,]+]], i{{.+}} 123
// CK21-DAG: [[RVAR1]] = load float*, float** [[SEC1_:%[^,]+]]
// CK21-DAG: [[SEC1_]] = getelementptr {{.*}}[[ST]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
@@ -2649,10 +2759,10 @@ struct CC {
// CK21-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK21-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK21-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK21-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK21-DAG: [[CBPVAL0]] = bitcast [123 x float]* [[VAR0:%.+]] to i8*
- // CK21-DAG: [[CPVAL0]] = bitcast [123 x float]* [[VAR0]] to i8*
+ // CK21-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [123 x float]**
+ // CK21-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [123 x float]**
+ // CK21-DAG: store [123 x float]* [[VAR0:%.+]], [123 x float]** [[CBP0]]
+ // CK21-DAG: store [123 x float]* [[VAR0]], [123 x float]** [[CP0]]
// CK21: call void [[CALL03:@.+]]([123 x float]* {{[^,]+}})
#pragma omp target map(from:la)
@@ -2667,10 +2777,10 @@ struct CC {
// CK21-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK21-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK21-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK21-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK21-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK21-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK21-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK21-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK21-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK21-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK21: call void [[CALL04:@.+]](i32* {{[^,]+}})
#pragma omp target map(from:arg)
@@ -2686,18 +2796,18 @@ struct CC {
// CK21-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK21-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK21-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK21-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK21-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK21-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK21-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK21-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK21-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK21-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK21-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[VAR0]], i{{.+}} 0, i{{.+}} 0
// CK21-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK21-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK21-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK21-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK21-DAG: [[CBPVAL1]] = bitcast [[ST]]* [[VAR1:%.+]] to i8*
- // CK21-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+ // CK21-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[ST]]**
+ // CK21-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK21-DAG: store [[ST]]* [[VAR1:%.+]], [[ST]]** [[CBP1]]
+ // CK21-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK21-DAG: [[SEC1]] = getelementptr {{.*}}[[ST]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
// CK21: call void [[CALL05:@.+]]([[ST]]* {{[^,]+}})
@@ -2809,8 +2919,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast (i32* @a to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast (i32* @a to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK22-DAG: store i32* @a, i32** [[CBP0]]
+ // CK22-DAG: store i32* @a, i32** [[CP0]]
// CK22: call void [[CALL00:@.+]](i32* {{[^,]+}})
#pragma omp target map(a)
@@ -2823,8 +2935,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([100 x i32]* @c to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([100 x i32]* @c to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [100 x i32]**
+ // CK22-DAG: store [100 x i32]* @c, [100 x i32]** [[CBP0]]
+ // CK22-DAG: store [100 x i32]* @c, [100 x i32]** [[CP0]]
// CK22: call void [[CALL01:@.+]]([100 x i32]* {{[^,]+}})
#pragma omp target map(c)
@@ -2837,8 +2951,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast (i32** @d to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast (i32** @d to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32***
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32***
+ // CK22-DAG: store i32** @d, i32*** [[CBP0]]
+ // CK22-DAG: store i32** @d, i32*** [[CP0]]
// CK22: call void [[CALL02:@.+]](i32** {{[^,]+}})
#pragma omp target map(d)
@@ -2851,8 +2967,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([100 x i32]* @c to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast (i32* getelementptr inbounds ([100 x i32], [100 x i32]* @c, i{{.+}} 0, i{{.+}} 1) to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x i32]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK22-DAG: store [100 x i32]* @c, [100 x i32]** [[CBP0]]
+ // CK22-DAG: store i32* getelementptr inbounds ([100 x i32], [100 x i32]* @c, i{{.+}} 0, i{{.+}} 1), i32** [[CP0]]
// CK22: call void [[CALL03:@.+]]([100 x i32]* {{[^,]+}})
#pragma omp target map(c[1:4])
@@ -2865,10 +2983,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK22-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK22-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK22-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK22-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK22-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK22-DAG: [[RVAR0]] = load i32*, i32** @d
// CK22-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 2
// CK22-DAG: [[RVAR00]] = load i32*, i32** @d
@@ -2884,8 +3002,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([[ST]]* @sa to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([[ST]]* @sa to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]**
+ // CK22-DAG: store [[ST]]* @sa, [[ST]]** [[CBP0]]
+ // CK22-DAG: store [[ST]]* @sa, [[ST]]** [[CP0]]
// CK22: call void [[CALL05:@.+]]([[ST]]* {{[^,]+}})
#pragma omp target map(sa)
@@ -2898,8 +3018,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([100 x [[ST]]]* @sc to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([100 x [[ST]]]* @sc to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x [[ST]]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [100 x [[ST]]]**
+ // CK22-DAG: store [100 x [[ST]]]* @sc, [100 x [[ST]]]** [[CBP0]]
+ // CK22-DAG: store [100 x [[ST]]]* @sc, [100 x [[ST]]]** [[CP0]]
// CK22: call void [[CALL06:@.+]]([100 x [[ST]]]* {{[^,]+}})
#pragma omp target map(sc)
@@ -2912,8 +3034,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([[ST]]** @sd to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([[ST]]** @sd to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]***
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]***
+ // CK22-DAG: store [[ST]]** @sd, [[ST]]*** [[CBP0]]
+ // CK22-DAG: store [[ST]]** @sd, [[ST]]*** [[CP0]]
// CK22: call void [[CALL07:@.+]]([[ST]]** {{[^,]+}})
#pragma omp target map(sd)
@@ -2926,8 +3050,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([100 x [[ST]]]* @sc to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([[ST]]* getelementptr inbounds ([100 x [[ST]]], [100 x [[ST]]]* @sc, i{{.+}} 0, i{{.+}} 1) to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x [[ST]]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]**
+ // CK22-DAG: store [100 x [[ST]]]* @sc, [100 x [[ST]]]** [[CBP0]]
+ // CK22-DAG: store [[ST]]* getelementptr inbounds ([100 x [[ST]]], [100 x [[ST]]]* @sc, i{{.+}} 0, i{{.+}} 1), [[ST]]** [[CP0]]
// CK22: call void [[CALL08:@.+]]([100 x [[ST]]]* {{[^,]+}})
#pragma omp target map(sc[1:4])
@@ -2940,10 +3066,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK22-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK22-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[RVAR0:%.+]] to i8*
- // CK22-DAG: [[CPVAL0]] = bitcast [[ST]]* [[SEC0:%.+]] to i8*
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]**
+ // CK22-DAG: store [[ST]]* [[RVAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK22-DAG: store [[ST]]* [[SEC0:%.+]], [[ST]]** [[CP0]]
// CK22-DAG: [[RVAR0]] = load [[ST]]*, [[ST]]** @sd
// CK22-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[RVAR00:%.+]], i{{.+}} 2
// CK22-DAG: [[RVAR00]] = load [[ST]]*, [[ST]]** @sd
@@ -2959,8 +3085,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([[STT]]* @sta to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([[STT]]* @sta to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[STT]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[STT]]**
+ // CK22-DAG: store [[STT]]* @sta, [[STT]]** [[CBP0]]
+ // CK22-DAG: store [[STT]]* @sta, [[STT]]** [[CP0]]
// CK22: call void [[CALL10:@.+]]([[STT]]* {{[^,]+}})
#pragma omp target map(sta)
@@ -2973,8 +3101,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([100 x [[STT]]]* @stc to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([100 x [[STT]]]* @stc to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x [[STT]]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [100 x [[STT]]]**
+ // CK22-DAG: store [100 x [[STT]]]* @stc, [100 x [[STT]]]** [[CBP0]]
+ // CK22-DAG: store [100 x [[STT]]]* @stc, [100 x [[STT]]]** [[CP0]]
// CK22: call void [[CALL11:@.+]]([100 x [[STT]]]* {{[^,]+}})
#pragma omp target map(stc)
@@ -2987,8 +3117,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([[STT]]** @std to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([[STT]]** @std to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[STT]]***
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[STT]]***
+ // CK22-DAG: store [[STT]]** @std, [[STT]]*** [[CBP0]]
+ // CK22-DAG: store [[STT]]** @std, [[STT]]*** [[CP0]]
// CK22: call void [[CALL12:@.+]]([[STT]]** {{[^,]+}})
#pragma omp target map(std)
@@ -3001,8 +3133,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* bitcast ([100 x [[STT]]]* @stc to i8*), i8** [[BP0]]
- // CK22-DAG: store i8* bitcast ([[STT]]* getelementptr inbounds ([100 x [[STT]]], [100 x [[STT]]]* @stc, i{{.+}} 0, i{{.+}} 1) to i8*), i8** [[P0]]
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x [[STT]]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[STT]]**
+ // CK22-DAG: store [100 x [[STT]]]* @stc, [100 x [[STT]]]** [[CBP0]]
+ // CK22-DAG: store [[STT]]* getelementptr inbounds ([100 x [[STT]]], [100 x [[STT]]]* @stc, i{{.+}} 0, i{{.+}} 1), [[STT]]** [[CP0]]
// CK22: call void [[CALL13:@.+]]([100 x [[STT]]]* {{[^,]+}})
#pragma omp target map(stc[1:4])
@@ -3015,10 +3149,10 @@ int explicit_maps_globals(void){
// CK22-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK22-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK22-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK22-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK22-DAG: [[CBPVAL0]] = bitcast [[STT]]* [[RVAR0:%.+]] to i8*
- // CK22-DAG: [[CPVAL0]] = bitcast [[STT]]* [[SEC0:%.+]] to i8*
+ // CK22-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[STT]]**
+ // CK22-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[STT]]**
+ // CK22-DAG: store [[STT]]* [[RVAR0:%.+]], [[STT]]** [[CBP0]]
+ // CK22-DAG: store [[STT]]* [[SEC0:%.+]], [[STT]]** [[CP0]]
// CK22-DAG: [[RVAR0]] = load [[STT]]*, [[STT]]** @std
// CK22-DAG: [[SEC0]] = getelementptr {{.*}}[[STT]]* [[RVAR00:%.+]], i{{.+}} 2
// CK22-DAG: [[RVAR00]] = load [[STT]]*, [[STT]]** @std
@@ -3088,10 +3222,10 @@ int explicit_maps_inside_captured(int a){
// CK23-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK23-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK23-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK23-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK23-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK23-DAG: [[CPVAL0]] = bitcast i32* [[VAR00:%.+]] to i8*
+ // CK23-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK23-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK23-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK23-DAG: store i32* [[VAR00:%.+]], i32** [[CP0]]
// CK23-DAG: [[VAR0]] = load i32*, i32** [[CAP0:%[^,]+]]
// CK23-DAG: [[CAP0]] = getelementptr inbounds [[SA]], [[SA]]
// CK23-DAG: [[VAR00]] = load i32*, i32** [[CAP00:%[^,]+]]
@@ -3107,10 +3241,10 @@ int explicit_maps_inside_captured(int a){
// CK23-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK23-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK23-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK23-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK23-DAG: [[CBPVAL0]] = bitcast float* [[VAR0:%.+]] to i8*
- // CK23-DAG: [[CPVAL0]] = bitcast float* [[VAR00:%.+]] to i8*
+ // CK23-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK23-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK23-DAG: store float* [[VAR0:%.+]], float** [[CBP0]]
+ // CK23-DAG: store float* [[VAR00:%.+]], float** [[CP0]]
// CK23-DAG: [[VAR0]] = load float*, float** [[CAP0:%[^,]+]]
// CK23-DAG: [[CAP0]] = getelementptr inbounds [[SA]], [[SA]]
// CK23-DAG: [[VAR00]] = load float*, float** [[CAP00:%[^,]+]]
@@ -3126,10 +3260,10 @@ int explicit_maps_inside_captured(int a){
// CK23-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK23-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK23-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK23-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK23-DAG: [[CBPVAL0]] = bitcast [100 x float]* [[VAR0:%.+]] to i8*
- // CK23-DAG: [[CPVAL0]] = bitcast [100 x float]* [[VAR00:%.+]] to i8*
+ // CK23-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x float]**
+ // CK23-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [100 x float]**
+ // CK23-DAG: store [100 x float]* [[VAR0:%.+]], [100 x float]** [[CBP0]]
+ // CK23-DAG: store [100 x float]* [[VAR00:%.+]], [100 x float]** [[CP0]]
// CK23-DAG: [[VAR0]] = load [100 x float]*, [100 x float]** [[CAP0:%[^,]+]]
// CK23-DAG: [[CAP0]] = getelementptr inbounds [[SA]], [[SA]]
// CK23-DAG: [[VAR00]] = load [100 x float]*, [100 x float]** [[CAP00:%[^,]+]]
@@ -3146,10 +3280,10 @@ int explicit_maps_inside_captured(int a){
// CK23-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK23-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK23-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK23-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK23-DAG: [[CBPVAL0]] = bitcast float** [[VAR0:%.+]] to i8*
- // CK23-DAG: [[CPVAL0]] = bitcast float** [[VAR00:%.+]] to i8*
+ // CK23-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float***
+ // CK23-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float***
+ // CK23-DAG: store float** [[VAR0:%.+]], float*** [[CBP0]]
+ // CK23-DAG: store float** [[VAR00:%.+]], float*** [[CP0]]
// CK23-DAG: [[VAR0]] = load float**, float*** [[CAP0:%[^,]+]]
// CK23-DAG: [[CAP0]] = getelementptr inbounds [[SA]], [[SA]]
// CK23-DAG: [[VAR00]] = load float**, float*** [[CAP00:%[^,]+]]
@@ -3165,10 +3299,10 @@ int explicit_maps_inside_captured(int a){
// CK23-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK23-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK23-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK23-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK23-DAG: [[CBPVAL0]] = bitcast [100 x float]* [[VAR0:%.+]] to i8*
- // CK23-DAG: [[CPVAL0]] = bitcast float* [[SEC0:%.+]] to i8*
+ // CK23-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [100 x float]**
+ // CK23-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK23-DAG: store [100 x float]* [[VAR0:%.+]], [100 x float]** [[CBP0]]
+ // CK23-DAG: store float* [[SEC0:%.+]], float** [[CP0]]
// CK23-DAG: [[SEC0]] = getelementptr {{.*}}[100 x float]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 2
// CK23-DAG: [[VAR0]] = load [100 x float]*, [100 x float]** [[CAP0:%[^,]+]]
// CK23-DAG: [[CAP0]] = getelementptr inbounds [[SA]], [[SA]]
@@ -3186,10 +3320,10 @@ int explicit_maps_inside_captured(int a){
// CK23-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK23-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK23-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK23-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK23-DAG: [[CBPVAL0]] = bitcast float* [[RVAR0:%.+]] to i8*
- // CK23-DAG: [[CPVAL0]] = bitcast float* [[SEC0:%.+]] to i8*
+ // CK23-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK23-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK23-DAG: store float* [[RVAR0:%.+]], float** [[CBP0]]
+ // CK23-DAG: store float* [[SEC0:%.+]], float** [[CP0]]
// CK23-DAG: [[RVAR0]] = load float*, float** [[VAR0:%[^,]+]]
// CK23-DAG: [[SEC0]] = getelementptr {{.*}}float* [[RVAR00:%.+]], i{{.+}} 2
// CK23-DAG: [[RVAR00]] = load float*, float** [[VAR00:%[^,]+]]
@@ -3247,39 +3381,6 @@ struct SC{
// CK24: [[SIZE01:@.+]] = private {{.*}}constant [1 x i[[Z:64|32]]] [i[[Z:64|32]] 4]
// CK24: [[MTYPE01:@.+]] = private {{.*}}constant [1 x i32] [i32 35]
-// CK24: [[SIZE02:@.+]] = private {{.*}}constant [1 x i[[Z]]] [i[[Z]] {{56|48}}]
-// CK24: [[MTYPE02:@.+]] = private {{.*}}constant [1 x i32] [i32 35]
-
-// CK24: [[SIZE03:@.+]] = private {{.*}}constant [1 x i[[Z]]] [i[[Z]] 4]
-// CK24: [[MTYPE03:@.+]] = private {{.*}}constant [1 x i32] [i32 35]
-
-// CK24: [[SIZE04:@.+]] = private {{.*}}constant [1 x i[[Z]]] [i[[Z]] 20]
-// CK24: [[MTYPE04:@.+]] = private {{.*}}constant [1 x i32] [i32 35]
-
-// CK24: [[SIZE05:@.+]] = private {{.*}}constant [2 x i[[Z]]] [i[[Z]] {{8|4}}, i[[Z]] {{3560|2880}}]
-// CK24: [[MTYPE05:@.+]] = private {{.*}}constant [2 x i32] [i32 35, i32 19]
-
-// CK24: [[SIZE06:@.+]] = private {{.*}}constant [1 x i[[Z]]] [i[[Z]] 4]
-// CK24: [[MTYPE06:@.+]] = private {{.*}}constant [1 x i32] [i32 35]
-
-// CK24: [[SIZE07:@.+]] = private {{.*}}constant [2 x i[[Z]]] [i[[Z]] {{8|4}}, i[[Z]] 4]
-// CK24: [[MTYPE07:@.+]] = private {{.*}}constant [2 x i32] [i32 35, i32 19]
-
-// CK24: [[SIZE08:@.+]] = private {{.*}}constant [2 x i[[Z]]] [i[[Z]] {{8|4}}, i[[Z]] 4]
-// CK24: [[MTYPE08:@.+]] = private {{.*}}constant [2 x i32] [i32 35, i32 19]
-
-// CK24: [[SIZE09:@.+]] = private {{.*}}constant [2 x i[[Z]]] [i[[Z]] {{8|4}}, i[[Z]] 4]
-// CK24: [[MTYPE09:@.+]] = private {{.*}}constant [2 x i32] [i32 35, i32 19]
-
-// CK24: [[SIZE10:@.+]] = private {{.*}}constant [1 x i[[Z]]] [i[[Z]] 8]
-// CK24: [[MTYPE10:@.+]] = private {{.*}}constant [1 x i32] [i32 35]
-
-// CK24: [[SIZE11:@.+]] = private {{.*}}constant [2 x i[[Z]]] [i[[Z]] {{8|4}}, i[[Z]] {{8|4}}]
-// CK24: [[MTYPE11:@.+]] = private {{.*}}constant [2 x i32] [i32 35, i32 19]
-
-// CK24: [[SIZE12:@.+]] = private {{.*}}constant [4 x i[[Z]]] [i[[Z]] {{8|4}}, i[[Z]] {{8|4}}, i[[Z]] {{8|4}}, i[[Z]] 4]
-// CK24: [[MTYPE12:@.+]] = private {{.*}}constant [4 x i32] [i32 35, i32 19, i32 19, i32 19]
-
// CK24: [[SIZE13:@.+]] = private {{.*}}constant [1 x i[[Z]]] [i[[Z]] 4]
// CK24: [[MTYPE13:@.+]] = private {{.*}}constant [1 x i32] [i32 35]
@@ -3328,308 +3429,16 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 0
// CK24: call void [[CALL01:@.+]]([[SC]]* {{[^,]+}})
#pragma omp target map(s.a)
{ s.a++; }
-// Region 02
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 1, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[SIZE02]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[MTYPE02]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]* [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SB]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24: call void [[CALL02:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.s.s)
- { s.a++; }
-
-// Region 03
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 1, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[SIZE03]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[MTYPE03]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SA]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SB]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24: call void [[CALL03:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.s.s.a)
- { s.a++; }
-
-// Region 04
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 1, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[SIZE04]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[MTYPE04]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[10 x i32]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 3
-
-// CK24: call void [[CALL04:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.b[:5])
- { s.a++; }
-
-// Region 05
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 2, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[SIZE05]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[MTYPE05]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SB]]** [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SB]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast [[SB]]* [[SEC1:%.+]] to i8*
-// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SB]]* [[SEC11:%[^,]+]], i{{.+}} 0
-// CK24-DAG: [[SEC11]] = load [[SB]]*, [[SB]]** [[SEC111:%[^,]+]],
-// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24: call void [[CALL05:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.p[:5])
- { s.a++; }
-
-// Region 06
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 1, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[SIZE06]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[MTYPE06]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SA]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[10 x [[SA]]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SB]]* [[SEC0000:%[^,]+]], i{{.+}} 0, i{{.+}} 2
-// CK24-DAG: [[SEC0000]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24: call void [[CALL06:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.s.sa[3].a)
- { s.a++; }
-
-// Region 07
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 2, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[SIZE07]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[MTYPE07]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]** [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[10 x [[SA]]*]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SB]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SA]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
-// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SA]]* [[SEC11:%[^,]+]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[SEC11]] = load [[SA]]*, [[SA]]** [[SEC111:%[^,]+]],
-// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[10 x [[SA]]*]* [[SEC1111:%[^,]+]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: [[SEC1111]] = getelementptr {{.*}}[[SB]]* [[SEC11111:%[^,]+]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: [[SEC11111]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24: call void [[CALL07:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.s.sp[3]->a)
- { s.a++; }
-
-// Region 08
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 2, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[SIZE08]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[MTYPE08]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SB]]** [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SB]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
-// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SB]]* [[SEC11:%[^,]+]], i{{.+}} 0
-// CK24-DAG: [[SEC11]] = load [[SB]]*, [[SB]]** [[SEC111:%[^,]+]],
-// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24: call void [[CALL08:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.p->a)
- { s.a++; }
-
-// Region 09
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 2, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[SIZE09]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[MTYPE09]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]** [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SB]]* [[SEC00:[^,]+]], i{{.+}} 0, i{{.+}} 4
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SA]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
-// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SA]]* [[SEC11:%[^,]+]], i{{.+}} 0
-// CK24-DAG: [[SEC11]] = load [[SA]]*, [[SA]]** [[SEC111:%[^,]+]],
-// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SB]]* [[SEC1111:[^,]+]], i{{.+}} 0, i{{.+}} 4
-// CK24-DAG: [[SEC1111]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24: call void [[CALL09:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.s.p->a)
- { s.a++; }
-
-// Region 10
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 1, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[SIZE10]], {{.+}}getelementptr {{.+}}[1 x i{{.+}}]* [[MTYPE10]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[10 x i32]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SA]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 2
-// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SB]]* [[SEC0000:%[^,]+]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[SEC0000]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24: call void [[CALL10:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.s.s.b[:2])
- { s.a++; }
-
-// Region 11
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 2, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[SIZE11]], {{.+}}getelementptr {{.+}}[2 x i{{.+}}]* [[MTYPE11]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]** [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SB]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 4
-// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SA]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
-// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[10 x i32]* [[SEC11:%[^,]+]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[SEC11]] = getelementptr {{.*}}[[SA]]* [[SEC111:%[^,]+]], i{{.+}} 0, i{{.+}} 2
-// CK24-DAG: [[SEC111]] = load [[SA]]*, [[SA]]** [[SEC1111:%[^,]+]],
-// CK24-DAG: [[SEC1111]] = getelementptr {{.*}}[[SB]]* [[SEC11111:%[^,]+]], i{{.+}} 0, i{{.+}} 4
-// CK24-DAG: [[SEC11111]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 1
-
-// CK24: call void [[CALL11:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.s.p->b[:2])
- { s.a++; }
-
-// Region 12
-// CK24-DAG: call i32 @__tgt_target(i32 {{[^,]+}}, i8* {{[^,]+}}, i32 4, i8** [[GEPBP:%.+]], i8** [[GEPP:%.+]], {{.+}}getelementptr {{.+}}[4 x i{{.+}}]* [[SIZE12]], {{.+}}getelementptr {{.+}}[4 x i{{.+}}]* [[MTYPE12]]{{.+}})
-// CK24-DAG: [[GEPBP]] = getelementptr inbounds {{.+}}[[BP:%[^,]+]]
-// CK24-DAG: [[GEPP]] = getelementptr inbounds {{.+}}[[P:%[^,]+]]
-
-// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SB]]** [[SEC0:%.+]] to i8*
-// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SB]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast [[SA]]** [[SEC1:%.+]] to i8*
-// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SB]]* [[SEC11:%[^,]+]], i{{.+}} 0, i{{.+}} 4
-// CK24-DAG: [[SEC11]] = load [[SB]]*, [[SB]]** [[SEC111:%[^,]+]],
-// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
-// CK24-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
-// CK24-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
-// CK24-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
-// CK24-DAG: [[CBPVAL2]] = bitcast [[SA]]** [[SEC1]] to i8*
-// CK24-DAG: [[CPVAL2]] = bitcast [[SA]]** [[SEC2:%.+]] to i8*
-// CK24-DAG: [[SEC2]] = getelementptr {{.*}}[[SA]]* [[SEC22:%[^,]+]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[SEC22]] = load [[SA]]*, [[SA]]** [[SEC222:%[^,]+]],
-// CK24-DAG: [[SEC222]] = getelementptr {{.*}}[[SB]]* [[SEC2222:%[^,]+]], i{{.+}} 0, i{{.+}} 4
-// CK24-DAG: [[SEC2222]] = load [[SB]]*, [[SB]]** [[SEC22222:%[^,]+]],
-// CK24-DAG: [[SEC22222]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: store i8* [[CBPVAL3:%[^,]+]], i8** [[BP3]]
-// CK24-DAG: store i8* [[CPVAL3:%[^,]+]], i8** [[P3]]
-// CK24-DAG: [[CBPVAL3]] = bitcast [[SA]]** [[SEC2]] to i8*
-// CK24-DAG: [[CPVAL3]] = bitcast i32* [[SEC3:%.+]] to i8*
-// CK24-DAG: [[SEC3]] = getelementptr {{.*}}[[SA]]* [[SEC33:%[^,]+]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: [[SEC33]] = load [[SA]]*, [[SA]]** [[SEC333:%[^,]+]],
-// CK24-DAG: [[SEC333]] = getelementptr {{.*}}[[SA]]* [[SEC3333:%[^,]+]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: [[SEC3333]] = load [[SA]]*, [[SA]]** [[SEC33333:%[^,]+]],
-// CK24-DAG: [[SEC33333]] = getelementptr {{.*}}[[SB]]* [[SEC333333:%[^,]+]], i{{.+}} 0, i{{.+}} 4
-// CK24-DAG: [[SEC333333]] = load [[SB]]*, [[SB]]** [[SEC3333333:%[^,]+]],
-// CK24-DAG: [[SEC3333333]] = getelementptr {{.*}}[[SC]]* [[VAR0]], i{{.+}} 0, i{{.+}} 2
-
-// CK24: call void [[CALL12:@.+]]([[SC]]* {{[^,]+}})
-#pragma omp target map(s.p->p->p->a)
- { s.a++; }
-
//
// Same thing but starting from a pointer.
//
@@ -3640,10 +3449,10 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[VAR0]] = load [[SC]]*, [[SC]]** %{{.+}}
@@ -3660,10 +3469,10 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]* [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SA]]**
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store [[SA]]* [[SEC0:%.+]], [[SA]]** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SB]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 1
@@ -3681,10 +3490,10 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SA]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SB]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 1
@@ -3703,10 +3512,10 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[10 x i32]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 3
@@ -3724,18 +3533,18 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SB]]** [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SB]]***
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store [[SB]]** [[SEC0:%.+]], [[SB]]*** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 2
// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SB]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast [[SB]]* [[SEC1:%.+]] to i8*
+// CK24-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SB]]***
+// CK24-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to [[SB]]**
+// CK24-DAG: store [[SB]]** [[SEC0]], [[SB]]*** [[CBP1]]
+// CK24-DAG: store [[SB]]* [[SEC1:%.+]], [[SB]]** [[CP1]]
// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SB]]* [[SEC11:%[^,]+]], i{{.+}} 0
// CK24-DAG: [[SEC11]] = load [[SB]]*, [[SB]]** [[SEC111:%[^,]+]],
// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SC]]* [[VAR000:%.+]], i{{.+}} 0, i{{.+}} 2
@@ -3755,10 +3564,10 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SA]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[10 x [[SA]]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 3
// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SB]]* [[SEC0000:%[^,]+]], i{{.+}} 0, i{{.+}} 2
@@ -3778,20 +3587,20 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]** [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SA]]***
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store [[SA]]** [[SEC0:%.+]], [[SA]]*** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[10 x [[SA]]*]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 3
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SB]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 3
// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SA]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+// CK24-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SA]]***
+// CK24-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+// CK24-DAG: store [[SA]]** [[SEC0]], [[SA]]*** [[CBP1]]
+// CK24-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SA]]* [[SEC11:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[SEC11]] = load [[SA]]*, [[SA]]** [[SEC111:%[^,]+]],
// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[10 x [[SA]]*]* [[SEC1111:%[^,]+]], i{{.+}} 0, i{{.+}} 3
@@ -3813,18 +3622,18 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SB]]** [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SB]]***
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store [[SB]]** [[SEC0:%.+]], [[SB]]*** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 2
// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SB]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+// CK24-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SB]]***
+// CK24-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+// CK24-DAG: store [[SB]]** [[SEC0]], [[SB]]*** [[CBP1]]
+// CK24-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SB]]* [[SEC11:%[^,]+]], i{{.+}} 0
// CK24-DAG: [[SEC11]] = load [[SB]]*, [[SB]]** [[SEC111:%[^,]+]],
// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SC]]* [[VAR000:%.+]], i{{.+}} 0, i{{.+}} 2
@@ -3844,19 +3653,19 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]** [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SA]]***
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store [[SA]]** [[SEC0:%.+]], [[SA]]*** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SB]]* [[SEC00:[^,]+]], i{{.+}} 0, i{{.+}} 4
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SA]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+// CK24-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SA]]***
+// CK24-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+// CK24-DAG: store [[SA]]** [[SEC0]], [[SA]]*** [[CBP1]]
+// CK24-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SA]]* [[SEC11:%[^,]+]], i{{.+}} 0
// CK24-DAG: [[SEC11]] = load [[SA]]*, [[SA]]** [[SEC111:%[^,]+]],
// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SB]]* [[SEC1111:[^,]+]], i{{.+}} 0, i{{.+}} 4
@@ -3877,10 +3686,10 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[10 x i32]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SA]]* [[SEC000:%[^,]+]], i{{.+}} 0, i{{.+}} 2
// CK24-DAG: [[SEC000]] = getelementptr {{.*}}[[SB]]* [[SEC0000:%[^,]+]], i{{.+}} 0, i{{.+}} 1
@@ -3900,19 +3709,19 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SA]]** [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SA]]***
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store [[SA]]** [[SEC0:%.+]], [[SA]]*** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SB]]* [[SEC00:%[^,]+]], i{{.+}} 0, i{{.+}} 4
// CK24-DAG: [[SEC00]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SA]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+// CK24-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SA]]***
+// CK24-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+// CK24-DAG: store [[SA]]** [[SEC0]], [[SA]]*** [[CBP1]]
+// CK24-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[10 x i32]* [[SEC11:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[SEC11]] = getelementptr {{.*}}[[SA]]* [[SEC111:%[^,]+]], i{{.+}} 0, i{{.+}} 2
// CK24-DAG: [[SEC111]] = load [[SA]]*, [[SA]]** [[SEC1111:%[^,]+]],
@@ -3934,28 +3743,28 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK24-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK24-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK24-DAG: [[CBPVAL0]] = bitcast [[SC]]* [[VAR0:%.+]] to i8*
-// CK24-DAG: [[CPVAL0]] = bitcast [[SB]]** [[SEC0:%.+]] to i8*
+// CK24-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SC]]**
+// CK24-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SB]]***
+// CK24-DAG: store [[SC]]* [[VAR0:%.+]], [[SC]]** [[CBP0]]
+// CK24-DAG: store [[SB]]** [[SEC0:%.+]], [[SB]]*** [[CP0]]
// CK24-DAG: [[SEC0]] = getelementptr {{.*}}[[SC]]* [[VAR00:%.+]], i{{.+}} 0, i{{.+}} 2
// CK24-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK24-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK24-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK24-DAG: [[CBPVAL1]] = bitcast [[SB]]** [[SEC0]] to i8*
-// CK24-DAG: [[CPVAL1]] = bitcast [[SA]]** [[SEC1:%.+]] to i8*
+// CK24-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SB]]***
+// CK24-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to [[SA]]***
+// CK24-DAG: store [[SB]]** [[SEC0]], [[SB]]*** [[CBP1]]
+// CK24-DAG: store [[SA]]** [[SEC1:%.+]], [[SA]]*** [[CP1]]
// CK24-DAG: [[SEC1]] = getelementptr {{.*}}[[SB]]* [[SEC11:%[^,]+]], i{{.+}} 0, i{{.+}} 4
// CK24-DAG: [[SEC11]] = load [[SB]]*, [[SB]]** [[SEC111:%[^,]+]],
// CK24-DAG: [[SEC111]] = getelementptr {{.*}}[[SC]]* [[VAR000:%.+]], i{{.+}} 0, i{{.+}} 2
// CK24-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK24-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
-// CK24-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
-// CK24-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
-// CK24-DAG: [[CBPVAL2]] = bitcast [[SA]]** [[SEC1]] to i8*
-// CK24-DAG: [[CPVAL2]] = bitcast [[SA]]** [[SEC2:%.+]] to i8*
+// CK24-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [[SA]]***
+// CK24-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to [[SA]]***
+// CK24-DAG: store [[SA]]** [[SEC1]], [[SA]]*** [[CBP2]]
+// CK24-DAG: store [[SA]]** [[SEC2:%.+]], [[SA]]*** [[CP2]]
// CK24-DAG: [[SEC2]] = getelementptr {{.*}}[[SA]]* [[SEC22:%[^,]+]], i{{.+}} 0, i{{.+}} 1
// CK24-DAG: [[SEC22]] = load [[SA]]*, [[SA]]** [[SEC222:%[^,]+]],
// CK24-DAG: [[SEC222]] = getelementptr {{.*}}[[SB]]* [[SEC2222:%[^,]+]], i{{.+}} 0, i{{.+}} 4
@@ -3964,10 +3773,10 @@ int explicit_maps_struct_fields(int a){
// CK24-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3
// CK24-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3
-// CK24-DAG: store i8* [[CBPVAL3:%[^,]+]], i8** [[BP3]]
-// CK24-DAG: store i8* [[CPVAL3:%[^,]+]], i8** [[P3]]
-// CK24-DAG: [[CBPVAL3]] = bitcast [[SA]]** [[SEC2]] to i8*
-// CK24-DAG: [[CPVAL3]] = bitcast i32* [[SEC3:%.+]] to i8*
+// CK24-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to [[SA]]***
+// CK24-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to i32**
+// CK24-DAG: store [[SA]]** [[SEC2]], [[SA]]*** [[CBP3]]
+// CK24-DAG: store i32* [[SEC3:%.+]], i32** [[CP3]]
// CK24-DAG: [[SEC3]] = getelementptr {{.*}}[[SA]]* [[SEC33:%[^,]+]], i{{.+}} 0, i{{.+}} 0
// CK24-DAG: [[SEC33]] = load [[SA]]*, [[SA]]** [[SEC333:%[^,]+]],
// CK24-DAG: [[SEC333]] = getelementptr {{.*}}[[SA]]* [[SEC3333:%[^,]+]], i{{.+}} 0, i{{.+}} 1
@@ -3990,17 +3799,6 @@ int explicit_maps_struct_fields(int a){
}
// CK24: define {{.+}}[[CALL01]]
-// CK24: define {{.+}}[[CALL02]]
-// CK24: define {{.+}}[[CALL03]]
-// CK24: define {{.+}}[[CALL04]]
-// CK24: define {{.+}}[[CALL05]]
-// CK24: define {{.+}}[[CALL06]]
-// CK24: define {{.+}}[[CALL07]]
-// CK24: define {{.+}}[[CALL08]]
-// CK24: define {{.+}}[[CALL09]]
-// CK24: define {{.+}}[[CALL10]]
-// CK24: define {{.+}}[[CALL11]]
-// CK24: define {{.+}}[[CALL12]]
// CK24: define {{.+}}[[CALL13]]
// CK24: define {{.+}}[[CALL14]]
// CK24: define {{.+}}[[CALL15]]
@@ -4047,10 +3845,10 @@ struct CC {
// CK25-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK25-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK25-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK25-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK25-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK25-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK25-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK25-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK25-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK25-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK25-DAG: [[SEC0]] = getelementptr {{.*}}[[ST]]* [[VAR0:%.+]], i{{.+}} 0, i{{.+}} 0
// CK25: call void [[CALL00:@.+]]([[ST]]* {{[^,]+}})
@@ -4068,10 +3866,10 @@ struct CC {
// CK25-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK25-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK25-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK25-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK25-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK25-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK25-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK25-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK25-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK25-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK25: call void [[CALL01:@.+]](i32* {{[^,]+}})
#pragma omp target map(to:arg)
@@ -4151,17 +3949,17 @@ struct CC {
// CK26-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK26-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK26-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK26-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK26-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK26-DAG: [[CPVAL0]] = bitcast [[ST]]* [[VAR0]] to i8*
+ // CK26-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK26-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]**
+ // CK26-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK26-DAG: store [[ST]]* [[VAR0]], [[ST]]** [[CP0]]
// CK26-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK26-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK26-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK26-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK26-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK26-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+ // CK26-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK26-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK26-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK26-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK26-DAG: [[VAR1]] = load i32*, i32** [[PVT:%.+]],
// CK26-DAG: [[SEC1]] = load i32*, i32** [[PVT]],
@@ -4178,17 +3976,17 @@ struct CC {
// CK26-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK26-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK26-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK26-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK26-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK26-DAG: [[CPVAL0]] = bitcast [[ST]]* [[VAR0]] to i8*
+ // CK26-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK26-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]**
+ // CK26-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK26-DAG: store [[ST]]* [[VAR0]], [[ST]]** [[CP0]]
// CK26-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK26-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK26-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK26-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK26-DAG: [[CBPVAL1]] = bitcast float* [[VAR1:%.+]] to i8*
- // CK26-DAG: [[CPVAL1]] = bitcast float* [[SEC1:%.+]] to i8*
+ // CK26-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to float**
+ // CK26-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to float**
+ // CK26-DAG: store float* [[VAR1:%.+]], float** [[CBP1]]
+ // CK26-DAG: store float* [[SEC1:%.+]], float** [[CP1]]
// CK26-DAG: [[VAR1]] = load float*, float** [[PVT:%.+]],
// CK26-DAG: [[SEC1]] = load float*, float** [[PVT]],
@@ -4205,17 +4003,17 @@ struct CC {
// CK26-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK26-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK26-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK26-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK26-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK26-DAG: [[CPVAL0]] = bitcast [[ST]]* [[VAR0]] to i8*
+ // CK26-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK26-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]**
+ // CK26-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK26-DAG: store [[ST]]* [[VAR0]], [[ST]]** [[CP0]]
// CK26-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK26-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK26-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK26-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK26-DAG: [[CBPVAL1]] = bitcast i32* [[VAR1:%.+]] to i8*
- // CK26-DAG: [[CPVAL1]] = bitcast i32* [[SEC1:%.+]] to i8*
+ // CK26-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i32**
+ // CK26-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i32**
+ // CK26-DAG: store i32* [[VAR1:%.+]], i32** [[CBP1]]
+ // CK26-DAG: store i32* [[SEC1:%.+]], i32** [[CP1]]
// CK26-DAG: [[VAR1]] = load i32*, i32** [[PVT:%.+]],
// CK26-DAG: [[SEC1]] = load i32*, i32** [[PVT]],
@@ -4232,17 +4030,17 @@ struct CC {
// CK26-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK26-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK26-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK26-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK26-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
- // CK26-DAG: [[CPVAL0]] = bitcast [[ST]]* [[VAR0]] to i8*
+ // CK26-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK26-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[ST]]**
+ // CK26-DAG: store [[ST]]* [[VAR0:%.+]], [[ST]]** [[CBP0]]
+ // CK26-DAG: store [[ST]]* [[VAR0]], [[ST]]** [[CP0]]
// CK26-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK26-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK26-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK26-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK26-DAG: [[CBPVAL1]] = bitcast float* [[VAR1:%.+]] to i8*
- // CK26-DAG: [[CPVAL1]] = bitcast float* [[SEC1:%.+]] to i8*
+ // CK26-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to float**
+ // CK26-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to float**
+ // CK26-DAG: store float* [[VAR1:%.+]], float** [[CBP1]]
+ // CK26-DAG: store float* [[SEC1:%.+]], float** [[CP1]]
// CK26-DAG: [[VAR1]] = load float*, float** [[PVT:%.+]],
// CK26-DAG: [[SEC1]] = load float*, float** [[PVT]],
@@ -4335,10 +4133,10 @@ void zero_size_section_and_private_maps (int ii){
// CK27-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK27-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK27-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK27-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK27-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK27-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK27-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK27-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK27-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK27-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK27: call void [[CALL00:@.+]](i32* {{[^,]+}})
#pragma omp target
@@ -4353,10 +4151,10 @@ void zero_size_section_and_private_maps (int ii){
// CK27-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK27-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK27-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK27-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK27-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK27-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK27-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK27-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK27-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK27-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK27-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK27-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 0
// CK27-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -4374,10 +4172,10 @@ void zero_size_section_and_private_maps (int ii){
// CK27-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK27-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK27-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK27-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK27-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK27-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK27-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK27-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK27-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK27-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK27-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK27-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} 0
// CK27-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -4395,10 +4193,10 @@ void zero_size_section_and_private_maps (int ii){
// CK27-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK27-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK27-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK27-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK27-DAG: [[CBPVAL0]] = bitcast i32* [[RVAR0:%.+]] to i8*
- // CK27-DAG: [[CPVAL0]] = bitcast i32* [[SEC0:%.+]] to i8*
+ // CK27-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK27-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK27-DAG: store i32* [[RVAR0:%.+]], i32** [[CBP0]]
+ // CK27-DAG: store i32* [[SEC0:%.+]], i32** [[CP0]]
// CK27-DAG: [[RVAR0]] = load i32*, i32** [[VAR0:%[^,]+]]
// CK27-DAG: [[SEC0]] = getelementptr {{.*}}i32* [[RVAR00:%.+]], i{{.+}} %{{.+}}
// CK27-DAG: [[RVAR00]] = load i32*, i32** [[VAR0]]
@@ -4428,10 +4226,10 @@ void zero_size_section_and_private_maps (int ii){
// CK27-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK27-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK27-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK27-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK27-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK27-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK27-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK27-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK27-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK27-DAG: store i32* [[VAR0]], i32** [[CP0]]
// CK27: call void [[CALL05:@.+]](i32* {{[^,]+}})
#pragma omp target firstprivate(pvtPtr)
@@ -4453,10 +4251,10 @@ void zero_size_section_and_private_maps (int ii){
// CK27-DAG: [[PGEP]] = getelementptr inbounds {{.+}}[[PS:%[^,]+]], i32 0, i32 0
// CK27-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BPS]], i32 0, i32 0
// CK27-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[PS]], i32 0, i32 0
- // CK27-DAG: store i8* [[VALBP:%.+]], i8** [[BP1]],
- // CK27-DAG: store i8* [[VALP:%.+]], i8** [[P1]],
- // CK27-DAG: [[VALBP]] = inttoptr i[[Z]] [[VAL:%.+]] to i8*
- // CK27-DAG: [[VALP]] = inttoptr i[[Z]] [[VAL:%.+]] to i8*
+ // CK27-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to i[[Z]]*
+ // CK27-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to i[[Z]]*
+ // CK27-DAG: store i[[Z]] [[VAL:%.+]], i[[Z]]* [[CBP1]]
+ // CK27-DAG: store i[[Z]] [[VAL]], i[[Z]]* [[CP1]]
// CK27-DAG: [[VAL]] = load i[[Z]], i[[Z]]* [[ADDR:%.+]],
// CK27-64-DAG: [[CADDR:%.+]] = bitcast i[[Z]]* [[ADDR]] to i32*
// CK27-64-DAG: store i32 {{.+}}, i32* [[CADDR]],
@@ -4482,10 +4280,10 @@ void zero_size_section_and_private_maps (int ii){
// CK27-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK27-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK27-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK27-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK27-DAG: [[CBPVAL0]] = bitcast [10 x i32]* [[VAR0:%.+]] to i8*
- // CK27-DAG: [[CPVAL0]] = bitcast [10 x i32]* [[VAR0]] to i8*
+ // CK27-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [10 x i32]**
+ // CK27-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [10 x i32]**
+ // CK27-DAG: store [10 x i32]* [[VAR0:%.+]], [10 x i32]** [[CBP0]]
+ // CK27-DAG: store [10 x i32]* [[VAR0]], [10 x i32]** [[CP0]]
// CK27: call void [[CALL09:@.+]]([10 x i32]* {{[^,]+}})
#pragma omp target firstprivate(pvtArr)
@@ -4529,10 +4327,10 @@ void explicit_maps_pointer_references (int *p){
// CK28-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK28-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK28-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK28-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK28-DAG: [[CBPVAL0]] = bitcast i32** [[VAR0:%.+]] to i8*
- // CK28-DAG: [[CPVAL0]] = bitcast i32** [[VAR1:%.+]] to i8*
+ // CK28-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32***
+ // CK28-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32***
+ // CK28-DAG: store i32** [[VAR0:%.+]], i32*** [[CBP0]]
+ // CK28-DAG: store i32** [[VAR1:%.+]], i32*** [[CP0]]
// CK28-DAG: [[VAR0]] = load i32**, i32*** [[VAR00:%.+]],
// CK28-DAG: [[VAR1]] = load i32**, i32*** [[VAR11:%.+]],
@@ -4549,10 +4347,10 @@ void explicit_maps_pointer_references (int *p){
// CK28-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK28-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK28-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK28-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK28-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK28-DAG: [[CPVAL0]] = bitcast i32* [[VAR1:%.+]] to i8*
+ // CK28-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK28-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK28-DAG: store i32* [[VAR0:%.+]], i32** [[CBP0]]
+ // CK28-DAG: store i32* [[VAR1:%.+]], i32** [[CP0]]
// CK28-DAG: [[VAR0]] = load i32*, i32** [[VAR00:%.+]],
// CK28-DAG: [[VAR00]] = load i32**, i32*** [[VAR000:%.+]],
// CK28-DAG: [[VAR1]] = getelementptr inbounds i32, i32* [[VAR11:%.+]], i{{64|32}} 2
@@ -4609,36 +4407,36 @@ struct SSB{
// CK29-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK29-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK29-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK29-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK29-DAG: [[CBPVAL0]] = bitcast [[SSB]]* [[VAR0:%.+]] to i8*
- // CK29-DAG: [[CPVAL0]] = bitcast [[SSA]]** [[VAR00:%.+]] to i8*
+ // CK29-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SSB]]**
+ // CK29-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SSA]]**
+ // CK29-DAG: store [[SSB]]* [[VAR0:%.+]], [[SSB]]** [[CBP0]]
+ // CK29-DAG: store [[SSA]]** [[VAR00:%.+]], [[SSA]]*** [[CP0]]
// CK29-DAG: [[VAR0]] = load [[SSB]]*, [[SSB]]** %
// CK29-DAG: [[VAR00]] = getelementptr inbounds [[SSB]], [[SSB]]* [[VAR0]], i32 0, i32 0
// CK29-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK29-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK29-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK29-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK29-DAG: [[CBPVAL1]] = bitcast [[SSA]]** [[VAR00]] to i8*
- // CK29-DAG: [[CPVAL1]] = bitcast double*** [[VAR1:%.+]] to i8*
+ // CK29-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SSA]]***
+ // CK29-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double****
+ // CK29-DAG: store [[SSA]]** [[VAR00]], [[SSA]]*** [[CBP1]]
+ // CK29-DAG: store double*** [[VAR1:%.+]], double**** [[CP1]]
// CK29-DAG: [[VAR1]] = getelementptr inbounds [[SSA]], [[SSA]]* %{{.+}}, i32 0, i32 1
// CK29-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK29-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK29-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK29-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK29-DAG: [[CBPVAL2]] = bitcast double*** [[VAR1]] to i8*
- // CK29-DAG: [[CPVAL2]] = bitcast double** [[VAR2:%.+]] to i8*
+ // CK29-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to double****
+ // CK29-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to double***
+ // CK29-DAG: store double*** [[VAR1]], double**** [[CBP2]]
+ // CK29-DAG: store double** [[VAR2:%.+]], double*** [[CP2]]
// CK29-DAG: [[VAR2]] = load double**, double*** [[VAR22:%.+]],
// CK29-DAG: [[VAR22]] = getelementptr inbounds [[SSA]], [[SSA]]* %{{.+}}, i32 0, i32 1
// CK29-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3
// CK29-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3
- // CK29-DAG: store i8* [[CBPVAL3:%[^,]+]], i8** [[BP3]]
- // CK29-DAG: store i8* [[CPVAL3:%[^,]+]], i8** [[P3]]
- // CK29-DAG: [[CBPVAL3]] = bitcast double** [[VAR2]] to i8*
- // CK29-DAG: [[CPVAL3]] = bitcast double* [[VAR3:%.+]] to i8*
+ // CK29-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to double***
+ // CK29-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to double**
+ // CK29-DAG: store double** [[VAR2]], double*** [[CBP3]]
+ // CK29-DAG: store double* [[VAR3:%.+]], double** [[CP3]]
// CK29-DAG: [[VAR3]] = getelementptr inbounds double, double* [[VAR33:%.+]], i{{.+}} 0
// CK29-DAG: [[VAR33]] = load double*, double** %{{.+}},
@@ -4656,34 +4454,34 @@ struct SSB{
// CK29-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK29-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK29-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK29-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK29-DAG: [[CBPVAL0]] = bitcast [[SSB]]* [[VAR0:%.+]] to i8*
- // CK29-DAG: [[CPVAL0]] = bitcast [[SSA]]*** [[VAR00:%.+]] to i8*
+ // CK29-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SSB]]**
+ // CK29-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SSA]]****
+ // CK29-DAG: store [[SSB]]* [[VAR0:%.+]], [[SSB]]** [[CBP0]]
+ // CK29-DAG: store [[SSA]]*** [[VAR00:%.+]], [[SSA]]**** [[CP0]]
// CK29-DAG: [[VAR00]] = getelementptr inbounds [[SSB]], [[SSB]]* [[VAR0]], i32 0, i32 1
// CK29-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK29-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK29-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK29-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK29-DAG: [[CBPVAL1]] = bitcast [[SSA]]*** [[VAR00]] to i8*
- // CK29-DAG: [[CPVAL1]] = bitcast [[SSA]]** [[VAR1:%.+]] to i8*
+ // CK29-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SSA]]****
+ // CK29-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to [[SSA]]***
+ // CK29-DAG: store [[SSA]]*** [[VAR00]], [[SSA]]**** [[CBP1]]
+ // CK29-DAG: store [[SSA]]** [[VAR1:%.+]], [[SSA]]*** [[CP1]]
// CK29-DAG: [[VAR1]] = load [[SSA]]**, [[SSA]]*** [[VAR00]],
// CK29-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK29-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK29-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK29-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK29-DAG: [[CBPVAL2]] = bitcast [[SSA]]** [[VAR1]] to i8*
- // CK29-DAG: [[CPVAL2]] = bitcast double** [[VAR2:%.+]] to i8*
+ // CK29-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [[SSA]]***
+ // CK29-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to double***
+ // CK29-DAG: store [[SSA]]** [[VAR1]], [[SSA]]*** [[CBP2]]
+ // CK29-DAG: store double** [[VAR2:%.+]], double*** [[CP2]]
// CK29-DAG: [[VAR2]] = getelementptr inbounds [[SSA]], [[SSA]]* %{{.+}}, i32 0, i32 0
// CK29-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3
// CK29-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3
- // CK29-DAG: store i8* [[CBPVAL3:%[^,]+]], i8** [[BP3]]
- // CK29-DAG: store i8* [[CPVAL3:%[^,]+]], i8** [[P3]]
- // CK29-DAG: [[CBPVAL3]] = bitcast double** [[VAR2]] to i8*
- // CK29-DAG: [[CPVAL3]] = bitcast double* [[VAR3:%.+]] to i8*
+ // CK29-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to double***
+ // CK29-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to double**
+ // CK29-DAG: store double** [[VAR2]], double*** [[CBP3]]
+ // CK29-DAG: store double* [[VAR3:%.+]], double** [[CP3]]
// CK29-DAG: [[VAR3]] = getelementptr inbounds double, double* [[VAR33:%.+]], i{{.+}} 0
// CK29-DAG: [[VAR33]] = load double*, double** %{{.+}},
@@ -4701,42 +4499,42 @@ struct SSB{
// CK29-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK29-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK29-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK29-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK29-DAG: [[CBPVAL0]] = bitcast [[SSB]]* [[VAR0:%.+]] to i8*
- // CK29-DAG: [[CPVAL0]] = bitcast [[SSA]]*** [[VAR00:%.+]] to i8*
+ // CK29-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[SSB]]**
+ // CK29-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to [[SSA]]****
+ // CK29-DAG: store [[SSB]]* [[VAR0:%.+]], [[SSB]]** [[CBP0]]
+ // CK29-DAG: store [[SSA]]*** [[VAR00:%.+]], [[SSA]]**** [[CP0]]
// CK29-DAG: [[VAR00]] = getelementptr inbounds [[SSB]], [[SSB]]* [[VAR0]], i32 0, i32 1
// CK29-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK29-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK29-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
- // CK29-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK29-DAG: [[CBPVAL1]] = bitcast [[SSA]]*** [[VAR00]] to i8*
- // CK29-DAG: [[CPVAL1]] = bitcast [[SSA]]** [[VAR1:%.+]] to i8*
+ // CK29-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to [[SSA]]****
+ // CK29-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to [[SSA]]***
+ // CK29-DAG: store [[SSA]]*** [[VAR00]], [[SSA]]**** [[CBP1]]
+ // CK29-DAG: store [[SSA]]** [[VAR1:%.+]], [[SSA]]*** [[CP1]]
// CK29-DAG: [[VAR1]] = load [[SSA]]**, [[SSA]]*** [[VAR00]],
// CK29-DAG: [[BP2:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 2
// CK29-DAG: [[P2:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 2
- // CK29-DAG: store i8* [[CBPVAL2:%[^,]+]], i8** [[BP2]]
- // CK29-DAG: store i8* [[CPVAL2:%[^,]+]], i8** [[P2]]
- // CK29-DAG: [[CBPVAL2]] = bitcast [[SSA]]** [[VAR1]] to i8*
- // CK29-DAG: [[CPVAL2]] = bitcast double*** [[VAR2:%.+]] to i8*
+ // CK29-DAG: [[CBP2:%.+]] = bitcast i8** [[BP2]] to [[SSA]]***
+ // CK29-DAG: [[CP2:%.+]] = bitcast i8** [[P2]] to double****
+ // CK29-DAG: store [[SSA]]** [[VAR1]], [[SSA]]*** [[CBP2]]
+ // CK29-DAG: store double*** [[VAR2:%.+]], double**** [[CP2]]
// CK29-DAG: [[VAR2]] = getelementptr inbounds [[SSA]], [[SSA]]* %{{.+}}, i32 0, i32 1
// CK29-DAG: [[BP3:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 3
// CK29-DAG: [[P3:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 3
- // CK29-DAG: store i8* [[CBPVAL3:%[^,]+]], i8** [[BP3]]
- // CK29-DAG: store i8* [[CPVAL3:%[^,]+]], i8** [[P3]]
- // CK29-DAG: [[CBPVAL3]] = bitcast double*** [[VAR2]] to i8*
- // CK29-DAG: [[CPVAL3]] = bitcast double** [[VAR3:%.+]] to i8*
+ // CK29-DAG: [[CBP3:%.+]] = bitcast i8** [[BP3]] to double****
+ // CK29-DAG: [[CP3:%.+]] = bitcast i8** [[P3]] to double***
+ // CK29-DAG: store double*** [[VAR2]], double**** [[CBP3]]
+ // CK29-DAG: store double** [[VAR3:%.+]], double*** [[CP3]]
// CK29-DAG: [[VAR3]] = load double**, double*** [[VAR2]],
// CK29-DAG: [[BP4:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 4
// CK29-DAG: [[P4:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 4
- // CK29-DAG: store i8* [[CBPVAL4:%[^,]+]], i8** [[BP4]]
- // CK29-DAG: store i8* [[CPVAL4:%[^,]+]], i8** [[P4]]
- // CK29-DAG: [[CBPVAL4]] = bitcast double** [[VAR3]] to i8*
- // CK29-DAG: [[CPVAL4]] = bitcast double* [[VAR4:%.+]] to i8*
+ // CK29-DAG: [[CBP4:%.+]] = bitcast i8** [[BP4]] to double***
+ // CK29-DAG: [[CP4:%.+]] = bitcast i8** [[P4]] to double**
+ // CK29-DAG: store double** [[VAR3]], double*** [[CBP4]]
+ // CK29-DAG: store double* [[VAR4:%.+]], double** [[CP4]]
// CK29-DAG: [[VAR4]] = getelementptr inbounds double, double* [[VAR44:%.+]], i{{.+}} 0
// CK29-DAG: [[VAR44]] = load double*, double**
diff --git a/test/OpenMP/target_map_messages.cpp b/test/OpenMP/target_map_messages.cpp
index 93f0216dd2..f607dcf369 100644
--- a/test/OpenMP/target_map_messages.cpp
+++ b/test/OpenMP/target_map_messages.cpp
@@ -66,6 +66,8 @@ struct SA {
{}
#pragma omp target map(always, tofrom: c,f[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
{}
+ #pragma omp target map(always) // expected-error {{use of undeclared identifier 'always'}}
+ {}
return;
}
};
@@ -317,8 +319,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -351,7 +353,7 @@ template <class T>
struct S6;
template<>
-struct S6<int> // expected-note {{mappable type cannot be polymorphic}}
+struct S6<int>
{
virtual void foo();
};
@@ -418,8 +420,8 @@ T tmain(T argc) {
#pragma omp target data map(tofrom: argc > 0 ? x : y) // expected-error 2 {{expected expression containing only member accesses and/or array sections based on named variables}}
#pragma omp target data map(argc)
#pragma omp target data map(S1) // expected-error {{'S1' does not refer to a value}}
-#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
-#pragma omp target data map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
+#pragma omp target data map(ba)
#pragma omp target data map(ca)
#pragma omp target data map(da)
#pragma omp target data map(S2::S2s)
@@ -452,6 +454,25 @@ T tmain(T argc) {
return 0;
}
+struct SA1{
+ int a;
+ struct SA1 *p;
+ int b[10];
+};
+struct SB1{
+ int a;
+ struct SA1 s;
+ struct SA1 sa[10];
+ struct SA1 *sp[10];
+ struct SA1 *p;
+};
+struct SC1{
+ int a;
+ struct SB1 s;
+ struct SB1 *p;
+ int b[10];
+};
+
int main(int argc, char **argv) {
const int d = 5;
const int da[5] = { 0 };
@@ -465,7 +486,9 @@ int main(int argc, char **argv) {
int y;
int to, tofrom, always;
const int (&l)[5] = da;
-#pragma omp target data map // expected-error {{expected '(' after 'map'}} expected-error {{expected at least one map clause for '#pragma omp target data'}}
+ SC1 s;
+ SC1 *p;
+#pragma omp target data map // expected-error {{expected '(' after 'map'}} expected-error {{expected at least one 'map' or 'use_device_ptr' clause for '#pragma omp target data'}}
#pragma omp target data map( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
#pragma omp target data map() // expected-error {{expected expression}}
#pragma omp target data map(alloc) // expected-error {{use of undeclared identifier 'alloc'}}
@@ -487,9 +510,9 @@ int main(int argc, char **argv) {
#pragma omp target data map(tofrom: argc > 0 ? argv[1] : argv[2]) // expected-error {{xpected expression containing only member accesses and/or array sections based on named variables}}
#pragma omp target data map(argc)
#pragma omp target data map(S1) // expected-error {{'S1' does not refer to a value}}
-#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
#pragma omp target data map(argv[1])
-#pragma omp target data map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target data map(ba)
#pragma omp target data map(ca)
#pragma omp target data map(da)
#pragma omp target data map(S2::S2s)
@@ -523,8 +546,55 @@ int main(int argc, char **argv) {
{}
#pragma omp target firstprivate(j) map(j) // expected-error {{firstprivate variable cannot be in a map clause in '#pragma omp target' directive}} expected-note {{defined as firstprivate}}
{}
-#pragma omp target map(m) // expected-error {{type 'S6<int>' is not mappable to target}}
- {}
+#pragma omp target map(m)
+ {}
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.s.s)
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.s.s.a)
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.b[:5])
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.p[:5])
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.s.sa[3].a)
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.s.sp[3]->a)
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.p->a)
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.s.p->a)
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.s.s.b[:2])
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.s.p->b[:2])
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+// expected-note@+1 {{used here}}
+#pragma omp target map(s.p->p->p->a)
+// expected-error@+1 {{variable already marked as mapped in current construct}}
+ { s.a++; }
+#pragma omp target map(s.s.s.b[:2])
+ { s.s.s.b[0]++; }
+
return tmain<int, 3>(argc)+tmain<from, 4>(argc); // expected-note {{in instantiation of function template specialization 'tmain<int, 3>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<int, 4>' requested here}}
}
#endif
diff --git a/test/OpenMP/target_messages.cpp b/test/OpenMP/target_messages.cpp
index 6f79f44627..77d8084937 100644
--- a/test/OpenMP/target_messages.cpp
+++ b/test/OpenMP/target_messages.cpp
@@ -4,6 +4,8 @@
// RUN: not %clang_cc1 -fopenmp -std=c++11 -triple nvptx64-nvidia-cuda -o - %s 2>&1 | FileCheck --check-prefix CHECK-UNSUPPORTED-HOST-TARGET %s
// RUN: not %clang_cc1 -fopenmp -std=c++11 -triple nvptx-nvidia-cuda -o - %s 2>&1 | FileCheck --check-prefix CHECK-UNSUPPORTED-HOST-TARGET %s
// CHECK-UNSUPPORTED-HOST-TARGET: error: The target '{{nvptx64-nvidia-cuda|nvptx-nvidia-cuda}}' is not a supported OpenMP host target.
+// RUN: not %clang_cc1 -fopenmp -std=c++11 -fopenmp-targets=hexagon-linux-gnu -o - %s 2>&1 | FileCheck --check-prefix CHECK-UNSUPPORTED-DEVICE-TARGET %s
+// CHECK-UNSUPPORTED-DEVICE-TARGET: OpenMP target is invalid: 'hexagon-linux-gnu'
void foo() {
}
diff --git a/test/OpenMP/target_parallel_codegen.cpp b/test/OpenMP/target_parallel_codegen.cpp
index c7acb27cab..968e2fb9a7 100644
--- a/test/OpenMP/target_parallel_codegen.cpp
+++ b/test/OpenMP/target_parallel_codegen.cpp
@@ -32,6 +32,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// 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.
@@ -40,12 +42,12 @@
// 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: [[MAPT4:@.+]] = private unnamed_addr constant [9 x i32] [i32 288, i32 547, i32 288, i32 547, i32 547, i32 288, i32 288, i32 547, i32 547]
// 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: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 288, i32 288, i32 547]
// 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: [[MAPT6:@.+]] = private unnamed_addr constant [4 x i32] [i32 288, i32 288, i32 288, i32 547]
+// CHECK-DAG: [[MAPT7:@.+]] = private unnamed_addr constant [5 x i32] [i32 547, i32 288, i32 288, i32 288, i32 547]
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -68,11 +70,11 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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 }]
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
template<typename tx, typename ty>
@@ -92,9 +94,7 @@ int foo(int 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT0:@.+]]()
@@ -104,10 +104,6 @@ int foo(int n) {
{
}
- // 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)
{
@@ -119,14 +115,12 @@ int foo(int n) {
// 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-DAG: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[VAL0:%.+]], i[[SZ]]* [[CBPADDR0]],
+ // CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0]],
+
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT2:@.+]](i[[SZ]] {{[^,]+}})
@@ -146,32 +140,29 @@ int foo(int n) {
// 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[VAL0:%.+]], i[[SZ]]* [[CBPADDR0]],
+ // CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0]],
// 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-DAG: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] [[VAL1:%.+]], i[[SZ]]* [[CBPADDR1]],
+ // CHECK-DAG: store i[[SZ]] [[VAL1]], i[[SZ]]* [[CPADDR1]],
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT3:@.+]]({{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+ // CHECK: [[IFELSE]]
+ // CHECK: call void [[HVT3]]({{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[IFEND]]
+ // CHECK: [[IFEND]]
+
#pragma omp target parallel if(target: n>10)
{
a += 1;
@@ -230,61 +221,61 @@ int foo(int n) {
// 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]] [[VLA0]], i[[SZ]]* [[CBPADDR0:%.+]],
+ // CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CPADDR0:%.+]],
+ // CHECK-DAG: [[CBPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] [[VLA1]], i[[SZ]]* [[CBPADDR1:%.+]],
+ // CHECK-DAG: store i[[SZ]] [[VLA1]], i[[SZ]]* [[CPADDR1:%.+]],
+ // CHECK-DAG: [[CBPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] 5, i[[SZ]]* [[CBPADDR2:%.+]],
+ // CHECK-DAG: store i[[SZ]] 5, i[[SZ]]* [[CPADDR2:%.+]],
+ // CHECK-DAG: [[CBPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] [[A_CVAL]], i[[SZ]]* [[CBPADDR3:%.+]],
+ // CHECK-DAG: store i[[SZ]] [[A_CVAL]], i[[SZ]]* [[CPADDR3:%.+]],
+ // CHECK-DAG: [[CBPADDR3]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR3]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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 [10 x float]* %{{.+}}, [10 x float]** [[CBPADDR4:%.+]],
+ // CHECK-DAG: store [10 x float]* %{{.+}}, [10 x float]** [[CPADDR4:%.+]],
+ // CHECK-DAG: [[CBPADDR4]] = bitcast i8** {{%[^,]+}} to [10 x float]**
+ // CHECK-DAG: [[CPADDR4]] = bitcast i8** {{%[^,]+}} to [10 x float]**
// 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 float* %{{.+}}, float** [[CBPADDR5:%.+]],
+ // CHECK-DAG: store float* %{{.+}}, float** [[CPADDR5:%.+]],
+ // CHECK-DAG: [[CBPADDR5]] = bitcast i8** {{%[^,]+}} to float**
+ // CHECK-DAG: [[CPADDR5]] = bitcast i8** {{%[^,]+}} to float**
// 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 [5 x [10 x double]]* %{{.+}}, [5 x [10 x double]]** [[CBPADDR6:%.+]],
+ // CHECK-DAG: store [5 x [10 x double]]* %{{.+}}, [5 x [10 x double]]** [[CPADDR6:%.+]],
+ // CHECK-DAG: [[CBPADDR6]] = bitcast i8** {{%[^,]+}} to [5 x [10 x double]]**
+ // CHECK-DAG: [[CPADDR6]] = bitcast i8** {{%[^,]+}} to [5 x [10 x double]]**
// 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 double* %{{.+}}, double** [[CBPADDR7:%.+]],
+ // CHECK-DAG: store double* %{{.+}}, double** [[CPADDR7:%.+]],
+ // CHECK-DAG: [[CBPADDR7]] = bitcast i8** {{%[^,]+}} to double**
+ // CHECK-DAG: [[CPADDR7]] = bitcast i8** {{%[^,]+}} to double**
// 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 [[TT]]* %{{.+}}, [[TT]]** [[CBPADDR8:%.+]],
+ // CHECK-DAG: store [[TT]]* %{{.+}}, [[TT]]** [[CPADDR8:%.+]],
+ // CHECK-DAG: [[CBPADDR8]] = bitcast i8** {{%[^,]+}} to [[TT]]**
+ // CHECK-DAG: [[CPADDR8]] = bitcast i8** {{%[^,]+}} to [[TT]]**
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
@@ -437,7 +428,7 @@ int foo(int n) {
// 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]]* {{.+}})
+// 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>
@@ -548,37 +539,37 @@ int bar(int n){
// 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]] [[VLA0]], i[[SZ]]* [[CBPADDR0:%.+]],
+// CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CPADDR0:%.+]],
+// CHECK-DAG: [[CBPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] 2, i[[SZ]]* [[CBPADDR1:%.+]],
+// CHECK-DAG: store i[[SZ]] 2, i[[SZ]]* [[CPADDR1:%.+]],
+// CHECK-DAG: [[CBPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] [[B_CVAL]], i[[SZ]]* [[CBPADDR2:%.+]],
+// CHECK-DAG: store i[[SZ]] [[B_CVAL]], i[[SZ]]* [[CPADDR2:%.+]],
+// CHECK-DAG: [[CBPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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 [[S1]]* %{{.+}}, [[S1]]** [[CBPADDR3:%.+]],
+// CHECK-DAG: store [[S1]]* %{{.+}}, [[S1]]** [[CPADDR3:%.+]],
+// CHECK-DAG: [[CBPADDR3]] = bitcast i8** {{%[^,]+}} to [[S1]]**
+// CHECK-DAG: [[CPADDR3]] = bitcast i8** {{%[^,]+}} to [[S1]]**
// 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 i16* %{{.+}}, i16** [[CBPADDR4:%.+]],
+// CHECK-DAG: store i16* %{{.+}}, i16** [[CPADDR4:%.+]],
+// CHECK-DAG: [[CBPADDR4]] = bitcast i8** {{%[^,]+}} to i16**
+// CHECK-DAG: [[CPADDR4]] = bitcast i8** {{%[^,]+}} to i16**
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
@@ -598,45 +589,43 @@ int bar(int n){
// 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL0:%.+]], i[[SZ]]* [[CBPADDR0]],
+// CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0]],
// 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: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL1:%.+]], i[[SZ]]* [[CBPADDR1]],
+// CHECK-DAG: store i[[SZ]] [[VAL1]], i[[SZ]]* [[CPADDR1]],
// 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: [[CBPADDR2:%.+]] = bitcast i8** [[BPADDR2]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR2:%.+]] = bitcast i8** [[PADDR2]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL2:%.+]], i[[SZ]]* [[CBPADDR2]],
+// CHECK-DAG: store i[[SZ]] [[VAL2]], i[[SZ]]* [[CPADDR2]],
// 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-DAG: [[CBPADDR3:%.+]] = bitcast i8** [[BPADDR3]] to [10 x i32]**
+// CHECK-DAG: [[CPADDR3:%.+]] = bitcast i8** [[PADDR3]] to [10 x i32]**
+// CHECK-DAG: store [10 x i32]* [[VAL3:%.+]], [10 x i32]** [[CBPADDR3]],
+// CHECK-DAG: store [10 x i32]* [[VAL3]], [10 x i32]** [[CPADDR3]],
-// CHECK: [[IFEND]]
-// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
-// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT6:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IFELSE]]
+// CHECK: call void [[HVT6]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
//
// CHECK: define {{.*}}[[FTEMPLATE]]
@@ -650,42 +639,36 @@ int bar(int n){
// 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL0:%.+]], i[[SZ]]* [[CBPADDR0]],
+// CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0]],
// 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: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+// CHECK-DAG: store i[[SZ]] [[VAL1:%.+]], i[[SZ]]* [[CBPADDR1]],
+// CHECK-DAG: store i[[SZ]] [[VAL1]], i[[SZ]]* [[CPADDR1]],
// 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-DAG: [[CBPADDR2:%.+]] = bitcast i8** [[BPADDR2]] to [10 x i32]**
+// CHECK-DAG: [[CPADDR2:%.+]] = bitcast i8** [[PADDR2]] to [10 x i32]**
+// CHECK-DAG: store [10 x i32]* [[VAL2:%.+]], [10 x i32]** [[CBPADDR2]],
+// CHECK-DAG: store [10 x i32]* [[VAL2]], [10 x i32]** [[CPADDR2]],
-// CHECK: [[IFEND]]
-// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
-// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT5:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
-
-
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IFELSE]]
+// CHECK: call void [[HVT:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
// 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().
@@ -720,7 +703,7 @@ int bar(int n){
// 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* %{{.+}})
+// 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.
diff --git a/test/OpenMP/target_parallel_codegen_registration.cpp b/test/OpenMP/target_parallel_codegen_registration.cpp
index 6ba137ff10..2511bc4c9d 100644
--- a/test/OpenMP/target_parallel_codegen_registration.cpp
+++ b/test/OpenMP/target_parallel_codegen_registration.cpp
@@ -36,6 +36,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// CHECK-DAG: [[A1:@.+]] = internal global [[SA]]
// CHECK-DAG: [[A2:@.+]] = global [[SA]]
// CHECK-DAG: [[B1:@.+]] = global [[SB]]
@@ -153,15 +155,15 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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-SAME: { i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
// CHECK-NTARGET: @llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
@@ -364,14 +366,16 @@ struct ST {
// Check registration and unregistration
-//CHECK: define internal void [[UNREGFN:@.+]](i8*)
+//CHECK: define internal void @[[UNREGFN:.+]](i8*)
+//CHECK-SAME: comdat($[[REGFN]]) {
//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: define linkonce hidden void @[[REGFN]](i8*)
+//CHECK-SAME: comdat {
//CHECK: call i32 @__tgt_register_lib([[DSCTY]]* [[DESC]])
-//CHECK: call i32 @__cxa_atexit(void (i8*)* [[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
+//CHECK: call i32 @__cxa_atexit(void (i8*)* @[[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
//CHECK: ret void
//CHECK: declare i32 @__tgt_register_lib([[DSCTY]]*)
@@ -407,31 +411,31 @@ int bar(int a){
// 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]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 195, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 245, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 261, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 267, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 406, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 290, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 290, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 220, 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]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 195, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 245, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 261, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 267, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 406, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 290, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 290, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 220, i32 {{[0-9]+}}}
#endif
diff --git a/test/OpenMP/target_parallel_debug_codegen.cpp b/test/OpenMP/target_parallel_debug_codegen.cpp
new file mode 100644
index 0000000000..cd19a8fdbc
--- /dev/null
+++ b/test/OpenMP/target_parallel_debug_codegen.cpp
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -DCK1 -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 -DCK1 -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 - -debug-info-kind=limited | FileCheck %s
+// expected-no-diagnostics
+
+int main() {
+ /* int(*b)[a]; */
+ /* int *(**c)[a]; */
+ bool bb;
+ int a;
+ int b[10][10];
+ int c[10][10][10];
+#pragma omp target parallel firstprivate(a, b) map(tofrom \
+ : c) map(tofrom \
+ : bb) if (a)
+ {
+ int &f = c[1][1][1];
+ int &g = a;
+ int &h = b[1][1];
+ int d = 15;
+ a = 5;
+ b[0][a] = 10;
+ c[0][0][a] = 11;
+ b[0][a] = c[0][0][a];
+ bb |= b[0][a];
+ }
+#pragma omp target parallel firstprivate(a) map(tofrom \
+ : c, b) map(to \
+ : bb)
+ {
+ int &f = c[1][1][1];
+ int &g = a;
+ int &h = b[1][1];
+ int d = 15;
+ a = 5;
+ b[0][a] = 10;
+ c[0][0][a] = 11;
+ b[0][a] = c[0][0][a];
+ d = bb;
+ }
+#pragma omp target parallel map(tofrom \
+ : a, c, b) map(from \
+ : bb)
+ {
+ int &f = c[1][1][1];
+ int &g = a;
+ int &h = b[1][1];
+ int d = 15;
+ a = 5;
+ b[0][a] = 10;
+ c[0][0][a] = 11;
+ b[0][a] = c[0][0][a];
+ bb = b[0][a];
+ }
+ return 0;
+}
+
+// CHECK: define internal void @__omp_offloading{{[^(]+}}([10 x [10 x [10 x i32]]] addrspace(1)* {{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]]* {{[^,]+}}, i8 addrspace(1)* noalias{{[^,]+}}, i1 {{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]] addrspace(1)* %{{.+}} to [10 x [10 x [10 x i32]]]*
+// CHECK: call void [[NONDEBUG_WRAPPER:.+]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]]* {{[^,]+}}, i64 {{[^,]+}}, [10 x [10 x i32]]* {{[^,]+}}, i8* {{[^)]+}})
+
+// CHECK: define internal void [[DEBUG_PARALLEL:@.+]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]] addrspace(1)* noalias{{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]]* noalias{{[^,]+}}, i8 addrspace(1)* noalias{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]] addrspace(1)* %{{.+}} to [10 x [10 x [10 x i32]]]*
+
+// CHECK: define internal void [[NONDEBUG_WRAPPER]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]]* dereferenceable{{[^,]+}}, i64 {{[^,]+}}, [10 x [10 x i32]]* dereferenceable{{[^,]+}}, i8* dereferenceable{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]]* %{{.+}} to [10 x [10 x [10 x i32]]] addrspace(1)*
+// CHECK: call void [[DEBUG_PARALLEL]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]] addrspace(1)* {{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]]* {{[^,]+}}, i8 addrspace(1)* {{[^)]+}})
+
+// CHECK: define void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]]* dereferenceable{{[^,]+}}, i64 {{[^,]+}}, [10 x [10 x i32]]* dereferenceable{{[^,]+}}, i8* dereferenceable{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]]* %{{.+}} to [10 x [10 x [10 x i32]]] addrspace(1)*
+// CHECK: call void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]] addrspace(1)* {{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]]* {{[^,]+}}, i8 addrspace(1)* {{[^)]+}})
+
+// CHECK: define internal void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]] addrspace(1)* noalias{{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]] addrspace(1)* noalias{{[^,]+}}, i8 addrspace(1)* noalias{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]] addrspace(1)* %{{.+}} to [10 x [10 x [10 x i32]]]*
+// CHECK: addrspacecast [10 x [10 x i32]] addrspace(1)* %{{.+}} to [10 x [10 x i32]]*
+// CHECK: call void [[NONDEBUG_WRAPPER:.+]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]]* {{[^,]+}}, i64 {{[^,]+}}, [10 x [10 x i32]]* {{[^,]+}}, i8* {{[^)]+}})
+
+// CHECK: define internal void [[DEBUG_PARALLEL:@.+]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]] addrspace(1)* noalias{{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]] addrspace(1)* noalias{{[^,]+}}, i8 addrspace(1)* {{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]] addrspace(1)* %{{.+}} to [10 x [10 x [10 x i32]]]*
+// CHECK: addrspacecast [10 x [10 x i32]] addrspace(1)* %{{.+}} to [10 x [10 x i32]]*
+
+// CHECK: define internal void [[NONDEBUG_WRAPPER]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]]* dereferenceable{{[^,]+}}, i64 {{[^,]+}}, [10 x [10 x i32]]* dereferenceable{{[^,]+}}, i8* dereferenceable{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]]* %{{.+}} to [10 x [10 x [10 x i32]]] addrspace(1)*
+// CHECK: addrspacecast [10 x [10 x i32]]* %{{.+}} to [10 x [10 x i32]] addrspace(1)*
+// CHECK: call void [[DEBUG_PARALLEL]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]] addrspace(1)* {{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]] addrspace(1)* {{[^,]+}}, i8 addrspace(1)* {{[^)]+}})
+
+// CHECK: define void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]]* dereferenceable{{[^,]+}}, i64 {{[^,]+}}, [10 x [10 x i32]]* dereferenceable{{[^,]+}}, i8* dereferenceable{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]]* %{{.+}} to [10 x [10 x [10 x i32]]] addrspace(1)*
+// CHECK: addrspacecast [10 x [10 x i32]]* %{{.+}} to [10 x [10 x i32]] addrspace(1)*
+// CHECK: call void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]] addrspace(1)* {{[^,]+}}, i32 {{[^,]+}}, [10 x [10 x i32]] addrspace(1)* {{[^,]+}}, i8 addrspace(1)* {{[^)]+}})
+
+// CHECK: define internal void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]] addrspace(1)* noalias{{[^,]+}}, i32 addrspace(1)* noalias{{[^,]+}}, [10 x [10 x i32]] addrspace(1)* noalias{{[^,]+}}, i8 addrspace(1)* noalias{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]] addrspace(1)* %{{.+}} to [10 x [10 x [10 x i32]]]*
+// CHECK: addrspacecast i32 addrspace(1)* %{{.+}} to i32*
+// CHECK: addrspacecast [10 x [10 x i32]] addrspace(1)* %{{.+}} to [10 x [10 x i32]]*
+// CHECK: call void [[NONDEBUG_WRAPPER:@.+]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]]* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x i32]]* {{[^,]+}}, i8* {{[^)]+}})
+
+// CHECK: define internal void [[DEBUG_PARALLEL:@.+]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]] addrspace(1)* noalias{{[^,]+}}, i32 addrspace(1)* noalias{{[^,]+}}, [10 x [10 x i32]] addrspace(1)* noalias{{[^,]+}}, i8 addrspace(1)* noalias{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]] addrspace(1)* %{{.+}} to [10 x [10 x [10 x i32]]]*
+// CHECK: addrspacecast i32 addrspace(1)* %{{.+}} to i32*
+// CHECK: addrspacecast [10 x [10 x i32]] addrspace(1)* %{{.+}} to [10 x [10 x i32]]*
+
+// CHECK: define internal void [[NONDEBUG_WRAPPER]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]]* dereferenceable{{[^,]+}}, i32* dereferenceable{{[^,]+}}, [10 x [10 x i32]]* dereferenceable{{[^,]+}}, i8* dereferenceable{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]]* %{{.+}} to [10 x [10 x [10 x i32]]] addrspace(1)*
+// CHECK: addrspacecast i32* %{{.+}} to i32 addrspace(1)*
+// CHECK: addrspacecast [10 x [10 x i32]]* %{{.+}} to [10 x [10 x i32]] addrspace(1)*
+// CHECK: call void [[DEBUG_PARALLEL]](i32* {{[^,]+}}, i32* {{[^,]+}}, [10 x [10 x [10 x i32]]] addrspace(1)* {{[^,]+}}, i32 addrspace(1)* {{[^,]+}}, [10 x [10 x i32]] addrspace(1)* {{[^,]+}}, i8 addrspace(1)* {{[^)]+}})
+
+// CHECK: define void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]]* dereferenceable{{[^,]+}}, i32* dereferenceable{{[^,]+}}, [10 x [10 x i32]]* dereferenceable{{[^,]+}}, i8* dereferenceable{{[^)]+}})
+// CHECK: addrspacecast [10 x [10 x [10 x i32]]]* %{{.+}} to [10 x [10 x [10 x i32]]] addrspace(1)*
+// CHECK: addrspacecast i32* %{{.+}} to i32 addrspace(1)*
+// CHECK: addrspacecast [10 x [10 x i32]]* %{{.+}} to [10 x [10 x i32]] addrspace(1)*
+// CHECK: call void @__omp_offloading_{{[^(]+}}([10 x [10 x [10 x i32]]] addrspace(1)* {{[^,]+}}, i32 addrspace(1)* {{[^,]+}}, [10 x [10 x i32]] addrspace(1)* {{[^,]+}}, i8 addrspace(1)* {{[^)]+}})
+
diff --git a/test/OpenMP/target_parallel_depend_messages.cpp b/test/OpenMP/target_parallel_depend_messages.cpp
index fde940be1a..24c69e95cc 100644
--- a/test/OpenMP/target_parallel_depend_messages.cpp
+++ b/test/OpenMP/target_parallel_depend_messages.cpp
@@ -36,21 +36,21 @@ int main(int argc, char **argv, char *env[]) {
foo();
#pragma omp target parallel depend (out: ) // expected-error {{expected expression}}
foo();
- #pragma omp target parallel depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target parallel depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
foo();
#pragma omp target parallel depend (out :S1) // expected-error {{'S1' does not refer to a value}}
foo();
- #pragma omp target parallel depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel depend(in : argv[1][1] = '2')
foo();
- #pragma omp target parallel depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target parallel depend (in : argv[0])
foo();
#pragma omp target parallel depend (in : ) // expected-error {{expected expression}}
foo();
- #pragma omp target parallel depend (in : main) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel depend (in : main)
foo();
- #pragma omp target parallel depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target parallel depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target parallel depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
foo();
diff --git a/test/OpenMP/target_parallel_for_codegen.cpp b/test/OpenMP/target_parallel_for_codegen.cpp
new file mode 100644
index 0000000000..1b72c0a563
--- /dev/null
+++ b/test/OpenMP/target_parallel_for_codegen.cpp
@@ -0,0 +1,232 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+long long get_val() { return 0; }
+double *g_ptr;
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}simple{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void simple(float *a, float *b, float *c, float *d) {
+ // CHECK: store i32 3, i32* %
+ // CHECK: icmp slt i32 %{{.+}}, 32
+ // CHECK: fmul float
+ // CHECK: fmul float
+ // CHECK: add nsw i32 %{{.+}}, 5
+ #pragma omp target parallel for device((int)*a)
+ for (int i = 3; i < 32; i += 5) {
+ a[i] = b[i] * c[i] * d[i];
+ }
+
+ // CHECK: call i{{.+}} @{{.+}}get_val{{.+}}()
+ // CHECK: store i32 10, i32* %
+ // CHECK: icmp sgt i32 %{{.+}}, 1
+ // CHECK: fadd float %{{.+}}, 1.000000e+00
+ // CHECK: add nsw {{.+}} %{{.+}}, 3
+ // CHECK: add nsw i32 %{{.+}}, -1
+ long long k = get_val();
+ #pragma omp target parallel for linear(k : 3) schedule(dynamic)
+ for (int i = 10; i > 1; i--) {
+ a[k]++;
+ k = k + 3;
+ }
+
+ // CHECK: store i32 12, i32* %
+ // CHECK: store i{{.+}} 2000, i{{.+}}* %
+ // CHECK: icmp uge i{{.+}} %{{.+}}, 600
+ // CHECK: store double 0.000000e+00,
+ // CHECK: fadd float %{{.+}}, 1.000000e+00
+ // CHECK: sub i{{.+}} %{{.+}}, 400
+ int lin = 12;
+ #pragma omp target parallel for linear(lin : get_val()), linear(g_ptr)
+ for (unsigned long long it = 2000; it >= 600; it-=400) {
+ *g_ptr++ = 0.0;
+ a[it + lin]++;
+ }
+
+ // CHECK: store i{{.+}} 6, i{{.+}}* %
+ // CHECK: icmp sle i{{.+}} %{{.+}}, 20
+ // CHECK: sub nsw i{{.+}} %{{.+}}, -4
+ #pragma omp target parallel for
+ for (short it = 6; it <= 20; it-=-4) {
+ }
+
+ // CHECK: store i8 122, i8* %
+ // CHECK: icmp sge i32 %{{.+}}, 97
+ // CHECK: add nsw i32 %{{.+}}, -1
+ #pragma omp target parallel for
+ for (unsigned char it = 'z'; it >= 'a'; it+=-1) {
+ }
+
+ // CHECK: store i32 100, i32* %
+ // CHECK: icmp ult i32 %{{.+}}, 10
+ // CHECK: add i32 %{{.+}}, 10
+ #pragma omp target parallel for
+ for (unsigned i=100; i<10; i+=10) {
+ }
+
+ int A;
+ {
+ A = -1;
+ // CHECK: store i{{.+}} -10, i{{.+}}* %
+ // CHECK: icmp slt i{{.+}} %{{.+}}, 10
+ // CHECK: add nsw i{{.+}} %{{.+}}, 3
+ #pragma omp target parallel for lastprivate(A)
+ for (long long i = -10; i < 10; i += 3) {
+ A = i;
+ }
+ }
+ int R;
+ {
+ R = -1;
+ // CHECK: store i{{.+}} -10, i{{.+}}* %
+ // CHECK: icmp slt i{{.+}} %{{.+}}, 10
+ // CHECK: add nsw i{{.+}} %{{.+}}, 3
+ #pragma omp target parallel for reduction(*:R)
+ for (long long i = -10; i < 10; i += 3) {
+ R *= i;
+ }
+ }
+}
+
+template <class T, unsigned K> T tfoo(T a) { return a + K; }
+
+template <typename T, unsigned N>
+int templ1(T a, T *z) {
+ #pragma omp target parallel for collapse(N)
+ for (int i = 0; i < N * 2; i++) {
+ for (long long j = 0; j < (N + N + N + N); j += 2) {
+ z[i + j] = a + tfoo<T, N>(i + j);
+ }
+ }
+ return 0;
+}
+
+// Instatiation templ1<float,2>
+// CHECK-LABEL: define {{.*i32}} @{{.*}}templ1{{.*}}(float {{.+}}, float* {{.+}})
+void inst_templ1() {
+ float a;
+ float z[100];
+ templ1<float,2> (a, z);
+}
+
+
+typedef int MyIdx;
+
+class IterDouble {
+ double *Ptr;
+public:
+ IterDouble operator++ () const {
+ IterDouble n;
+ n.Ptr = Ptr + 1;
+ return n;
+ }
+ bool operator < (const IterDouble &that) const {
+ return Ptr < that.Ptr;
+ }
+ double & operator *() const {
+ return *Ptr;
+ }
+ MyIdx operator - (const IterDouble &that) const {
+ return (MyIdx) (Ptr - that.Ptr);
+ }
+ IterDouble operator + (int Delta) {
+ IterDouble re;
+ re.Ptr = Ptr + Delta;
+ return re;
+ }
+
+ ///~IterDouble() {}
+};
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}iter_simple{{.*}}
+void iter_simple(IterDouble ia, IterDouble ib, IterDouble ic) {
+//
+// Calculate number of iterations before the loop body.
+// CHECK: invoke {{.*}}i32 @{{.*}}IterDouble{{.*}}
+ #pragma omp target parallel for
+ for (IterDouble i = ia; i < ib; ++i) {
+// Call of operator+ (i, IV).
+// CHECK: {{%.+}} = invoke {{.+}} @{{.*}}IterDouble{{.*}}
+// ... loop body ...
+ *i = *ic * 0.5;
+// Float multiply and save result.
+// CHECK: [[MULR:%.+]] = fmul double {{%.+}}, 5.000000e-01
+// CHECK-NEXT: invoke {{.+}} @{{.*}}IterDouble{{.*}}
+// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]]
+ ++ic;
+ }
+// CHECK: ret void
+}
+
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}collapsed{{.*}}
+void collapsed(float *a, float *b, float *c, float *d) {
+ int i; // outer loop counter
+ unsigned j; // middle loop couter, leads to unsigned icmp in loop header.
+ // k declared in the loop init below
+ short l; // inner loop counter
+//
+ #pragma omp target parallel for collapse(4)
+ for (i = 1; i < 3; i++) // 2 iterations
+ for (j = 2u; j < 5u; j++) //3 iterations
+ for (int k = 3; k <= 6; k++) // 4 iterations
+ for (l = 4; l < 9; ++l) // 5 iterations
+ {
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
+ float res = b[j] * c[k];
+ a[i] = res * d[l];
+ }
+// CHECK: ret void
+}
+
+extern char foo();
+extern double globalfloat;
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}widened{{.*}}
+void widened(float *a, float *b, float *c, float *d) {
+ int i; // outer loop counter
+ short j; // inner loop counter
+ globalfloat = 1.0;
+ int localint = 1;
+// CHECK: store double {{.+}}, double* [[GLOBALFLOAT:@.+]],
+ #pragma omp target parallel for collapse(2) private(globalfloat, localint)
+ for (i = 1; i < 3; i++) // 2 iterations
+ for (j = 0; j < foo(); j++) // foo() iterations
+ {
+// ... loop body ...
+//
+// Here we expect store into private double var, not global
+// CHECK: store double {{.+}}, double* [[GLOBALFLOAT]]
+ globalfloat = (float)j/i;
+ float res = b[j] * c[j];
+// Store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
+ a[i] = res * d[i];
+// Then there's a store into private var localint:
+// CHECK: store i32 {{.+}}, i32* [[LOCALINT:%[^,]+]]
+ localint = (int)j;
+ }
+//
+// Here we expect store into original localint, not its privatized version.
+// CHECK: store i32 {{.+}}, i32* [[LOCALINT]]
+ localint = (int)j;
+// CHECK: ret void
+}
+
+// TERM_DEBUG-LABEL: bar
+int bar() {return 0;};
+
+// TERM_DEBUG-LABEL: parallel_simd
+void parallel_simd(float *a) {
+#pragma omp target parallel for
+ for (unsigned i = 131071; i <= 2147483647; i += 127)
+ a[i] += bar();
+}
+#endif // HEADER
+
diff --git a/test/OpenMP/target_parallel_for_depend_messages.cpp b/test/OpenMP/target_parallel_for_depend_messages.cpp
index cf17d7a5de..1987256616 100644
--- a/test/OpenMP/target_parallel_for_depend_messages.cpp
+++ b/test/OpenMP/target_parallel_for_depend_messages.cpp
@@ -37,21 +37,21 @@ int main(int argc, char **argv, char *env[]) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for depend (out: ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target parallel for depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for depend (out :S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel for depend(in : argv[1][1] = '2')
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel for depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for depend (in : argv[0])
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for depend (in : ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for depend (in : main) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel for depend (in : main)
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target parallel for depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_parallel_for_lastprivate_messages.cpp b/test/OpenMP/target_parallel_for_lastprivate_messages.cpp
index c001b7f0d1..ee703a1ce3 100644
--- a/test/OpenMP/target_parallel_for_lastprivate_messages.cpp
+++ b/test/OpenMP/target_parallel_for_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
S2 &operator=(const S2 &);
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/target_parallel_for_loop_messages.cpp b/test/OpenMP/target_parallel_for_loop_messages.cpp
index 0e8eab10b5..d7c189116b 100644
--- a/test/OpenMP/target_parallel_for_loop_messages.cpp
+++ b/test/OpenMP/target_parallel_for_loop_messages.cpp
@@ -539,7 +539,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/target_parallel_for_map_messages.cpp b/test/OpenMP/target_parallel_for_map_messages.cpp
index f0019f94f4..f3e1c616b4 100644
--- a/test/OpenMP/target_parallel_for_map_messages.cpp
+++ b/test/OpenMP/target_parallel_for_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -116,9 +116,9 @@ T tmain(T argc) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for map(ca)
for (i = 0; i < argc; ++i) foo();
@@ -222,11 +222,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for map(argv[1])
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for map(ca)
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_parallel_for_reduction_messages.cpp b/test/OpenMP/target_parallel_for_reduction_messages.cpp
index 234b71aec2..9f1f68f25f 100644
--- a/test/OpenMP/target_parallel_for_reduction_messages.cpp
+++ b/test/OpenMP/target_parallel_for_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp
index 538d65b82b..655f90642f 100644
--- a/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp
+++ b/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp
@@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target parallel for simd aligned // expected-error {{expected '(' after 'aligned'}}
for (I k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/target_parallel_for_simd_codegen.cpp b/test/OpenMP/target_parallel_for_simd_codegen.cpp
new file mode 100644
index 0000000000..c822ad5c28
--- /dev/null
+++ b/test/OpenMP/target_parallel_for_simd_codegen.cpp
@@ -0,0 +1,232 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -debug-info-kind=limited -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+long long get_val() { return 0; }
+double *g_ptr;
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}simple{{.*}}(float* {{.+}}, float* {{.+}}, float* {{.+}}, float* {{.+}})
+void simple(float *a, float *b, float *c, float *d) {
+ // CHECK: store i32 3, i32* %
+ // CHECK: icmp slt i32 %{{.+}}, 32
+ // CHECK: fmul float
+ // CHECK: fmul float
+ // CHECK: add nsw i32 %{{.+}}, 5
+ #pragma omp target parallel for simd device((int)*a)
+ for (int i = 3; i < 32; i += 5) {
+ a[i] = b[i] * c[i] * d[i];
+ }
+
+ // CHECK: call i{{.+}} @{{.+}}get_val{{.+}}()
+ // CHECK: store i32 10, i32* %
+ // CHECK: icmp sgt i32 %{{.+}}, 1
+ // CHECK: fadd float %{{.+}}, 1.000000e+00
+ // CHECK: add nsw {{.+}} %{{.+}}, 3
+ // CHECK: add nsw i32 %{{.+}}, -1
+ long long k = get_val();
+ #pragma omp target parallel for simd linear(k : 3) schedule(dynamic)
+ for (int i = 10; i > 1; i--) {
+ a[k]++;
+ k = k + 3;
+ }
+
+ // CHECK: store i32 12, i32* %
+ // CHECK: store i{{.+}} 2000, i{{.+}}* %
+ // CHECK: icmp uge i{{.+}} %{{.+}}, 600
+ // CHECK: store double 0.000000e+00,
+ // CHECK: fadd float %{{.+}}, 1.000000e+00
+ // CHECK: sub i{{.+}} %{{.+}}, 400
+ int lin = 12;
+ #pragma omp target parallel for simd linear(lin : get_val()), linear(g_ptr)
+ for (unsigned long long it = 2000; it >= 600; it-=400) {
+ *g_ptr++ = 0.0;
+ a[it + lin]++;
+ }
+
+ // CHECK: store i{{.+}} 6, i{{.+}}* %
+ // CHECK: icmp sle i{{.+}} %{{.+}}, 20
+ // CHECK: sub nsw i{{.+}} %{{.+}}, -4
+ #pragma omp target parallel for simd
+ for (short it = 6; it <= 20; it-=-4) {
+ }
+
+ // CHECK: store i8 122, i8* %
+ // CHECK: icmp sge i32 %{{.+}}, 97
+ // CHECK: add nsw i32 %{{.+}}, -1
+ #pragma omp target parallel for simd
+ for (unsigned char it = 'z'; it >= 'a'; it+=-1) {
+ }
+
+ // CHECK: store i32 100, i32* %
+ // CHECK: icmp ult i32 %{{.+}}, 10
+ // CHECK: add i32 %{{.+}}, 10
+ #pragma omp target parallel for simd
+ for (unsigned i=100; i<10; i+=10) {
+ }
+
+ int A;
+ {
+ A = -1;
+ // CHECK: store i{{.+}} -10, i{{.+}}* %
+ // CHECK: icmp slt i{{.+}} %{{.+}}, 10
+ // CHECK: add nsw i{{.+}} %{{.+}}, 3
+ #pragma omp target parallel for simd lastprivate(A)
+ for (long long i = -10; i < 10; i += 3) {
+ A = i;
+ }
+ }
+ int R;
+ {
+ R = -1;
+ // CHECK: store i{{.+}} -10, i{{.+}}* %
+ // CHECK: icmp slt i{{.+}} %{{.+}}, 10
+ // CHECK: add nsw i{{.+}} %{{.+}}, 3
+ #pragma omp target parallel for simd reduction(*:R)
+ for (long long i = -10; i < 10; i += 3) {
+ R *= i;
+ }
+ }
+}
+
+template <class T, unsigned K> T tfoo(T a) { return a + K; }
+
+template <typename T, unsigned N>
+int templ1(T a, T *z) {
+ #pragma omp target parallel for simd collapse(N)
+ for (int i = 0; i < N * 2; i++) {
+ for (long long j = 0; j < (N + N + N + N); j += 2) {
+ z[i + j] = a + tfoo<T, N>(i + j);
+ }
+ }
+ return 0;
+}
+
+// Instatiation templ1<float,2>
+// CHECK-LABEL: define {{.*i32}} @{{.*}}templ1{{.*}}(float {{.+}}, float* {{.+}})
+void inst_templ1() {
+ float a;
+ float z[100];
+ templ1<float,2> (a, z);
+}
+
+
+typedef int MyIdx;
+
+class IterDouble {
+ double *Ptr;
+public:
+ IterDouble operator++ () const {
+ IterDouble n;
+ n.Ptr = Ptr + 1;
+ return n;
+ }
+ bool operator < (const IterDouble &that) const {
+ return Ptr < that.Ptr;
+ }
+ double & operator *() const {
+ return *Ptr;
+ }
+ MyIdx operator - (const IterDouble &that) const {
+ return (MyIdx) (Ptr - that.Ptr);
+ }
+ IterDouble operator + (int Delta) {
+ IterDouble re;
+ re.Ptr = Ptr + Delta;
+ return re;
+ }
+
+ ///~IterDouble() {}
+};
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}iter_simple{{.*}}
+void iter_simple(IterDouble ia, IterDouble ib, IterDouble ic) {
+//
+// Calculate number of iterations before the loop body.
+// CHECK: invoke {{.*}}i32 @{{.*}}IterDouble{{.*}}
+ #pragma omp target parallel for simd
+ for (IterDouble i = ia; i < ib; ++i) {
+// Call of operator+ (i, IV).
+// CHECK: {{%.+}} = invoke {{.+}} @{{.*}}IterDouble{{.*}}
+// ... loop body ...
+ *i = *ic * 0.5;
+// Float multiply and save result.
+// CHECK: [[MULR:%.+]] = fmul double {{%.+}}, 5.000000e-01
+// CHECK-NEXT: invoke {{.+}} @{{.*}}IterDouble{{.*}}
+// CHECK: store double [[MULR:%.+]], double* [[RESULT_ADDR:%.+]]
+ ++ic;
+ }
+// CHECK: ret void
+}
+
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}collapsed{{.*}}
+void collapsed(float *a, float *b, float *c, float *d) {
+ int i; // outer loop counter
+ unsigned j; // middle loop couter, leads to unsigned icmp in loop header.
+ // k declared in the loop init below
+ short l; // inner loop counter
+//
+ #pragma omp target parallel for simd collapse(4)
+ for (i = 1; i < 3; i++) // 2 iterations
+ for (j = 2u; j < 5u; j++) //3 iterations
+ for (int k = 3; k <= 6; k++) // 4 iterations
+ for (l = 4; l < 9; ++l) // 5 iterations
+ {
+// ... loop body ...
+// End of body: store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
+ float res = b[j] * c[k];
+ a[i] = res * d[l];
+ }
+// CHECK: ret void
+}
+
+extern char foo();
+extern double globalfloat;
+
+// CHECK-LABEL: define {{.*void}} @{{.*}}widened{{.*}}
+void widened(float *a, float *b, float *c, float *d) {
+ int i; // outer loop counter
+ short j; // inner loop counter
+ globalfloat = 1.0;
+ int localint = 1;
+// CHECK: store double {{.+}}, double* [[GLOBALFLOAT:@.+]],
+ #pragma omp target parallel for simd collapse(2) private(globalfloat, localint)
+ for (i = 1; i < 3; i++) // 2 iterations
+ for (j = 0; j < foo(); j++) // foo() iterations
+ {
+// ... loop body ...
+//
+// Here we expect store into private double var, not global
+// CHECK: store double {{.+}}, double* [[GLOBALFLOAT]]
+ globalfloat = (float)j/i;
+ float res = b[j] * c[j];
+// Store into a[i]:
+// CHECK: store float [[RESULT:%.+]], float* [[RESULT_ADDR:%.+]]
+ a[i] = res * d[i];
+// Then there's a store into private var localint:
+// CHECK: store i32 {{.+}}, i32* [[LOCALINT:%[^,]+]]
+ localint = (int)j;
+ }
+//
+// Here we expect store into original localint, not its privatized version.
+// CHECK: store i32 {{.+}}, i32* [[LOCALINT]]
+ localint = (int)j;
+// CHECK: ret void
+}
+
+// TERM_DEBUG-LABEL: bar
+int bar() {return 0;};
+
+// TERM_DEBUG-LABEL: parallel_simd
+void parallel_simd(float *a) {
+#pragma omp target parallel for simd
+ for (unsigned i = 131071; i <= 2147483647; i += 127)
+ a[i] += bar();
+}
+#endif // HEADER
+
diff --git a/test/OpenMP/target_parallel_for_simd_depend_messages.cpp b/test/OpenMP/target_parallel_for_simd_depend_messages.cpp
index a8b4de7ff7..4375941036 100644
--- a/test/OpenMP/target_parallel_for_simd_depend_messages.cpp
+++ b/test/OpenMP/target_parallel_for_simd_depend_messages.cpp
@@ -37,21 +37,21 @@ int main(int argc, char **argv, char *env[]) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd depend (out: ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target parallel for simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd depend (out :S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for simd depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel for simd depend(in : argv[1][1] = '2')
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for simd depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel for simd depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd depend (in : argv[0])
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd depend (in : ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for simd depend (in : main) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target parallel for simd depend (in : main)
for (i = 0; i < argc; ++i) foo();
- #pragma omp target parallel for simd depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target parallel for simd depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/target_parallel_for_simd_lastprivate_messages.cpp
index 51fc72464c..b41dc87a3d 100644
--- a/test/OpenMP/target_parallel_for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/target_parallel_for_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
S2 &operator=(const S2 &);
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/target_parallel_for_simd_loop_messages.cpp b/test/OpenMP/target_parallel_for_simd_loop_messages.cpp
index c0dceeded4..ed184a5e41 100644
--- a/test/OpenMP/target_parallel_for_simd_loop_messages.cpp
+++ b/test/OpenMP/target_parallel_for_simd_loop_messages.cpp
@@ -539,7 +539,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/target_parallel_for_simd_map_messages.cpp b/test/OpenMP/target_parallel_for_simd_map_messages.cpp
index 195b39c595..7e95e10ae5 100644
--- a/test/OpenMP/target_parallel_for_simd_map_messages.cpp
+++ b/test/OpenMP/target_parallel_for_simd_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -116,9 +116,9 @@ T tmain(T argc) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd map(ca)
for (i = 0; i < argc; ++i) foo();
@@ -222,11 +222,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd map(argv[1])
for (i = 0; i < argc; ++i) foo();
-#pragma omp target parallel for simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel for simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target parallel for simd map(ca)
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_parallel_for_simd_reduction_messages.cpp b/test/OpenMP/target_parallel_for_simd_reduction_messages.cpp
index 289b5b2641..72e2130f3d 100644
--- a/test/OpenMP/target_parallel_for_simd_reduction_messages.cpp
+++ b/test/OpenMP/target_parallel_for_simd_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_parallel_if_codegen.cpp b/test/OpenMP/target_parallel_if_codegen.cpp
index 02c69b95e1..215d8f9656 100644
--- a/test/OpenMP/target_parallel_if_codegen.cpp
+++ b/test/OpenMP/target_parallel_if_codegen.cpp
@@ -31,6 +31,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// We have 6 target regions
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -52,11 +54,11 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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 }]
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
template<typename tx>
@@ -128,8 +130,6 @@ int bar(int n){
return a;
}
-
-
//
// CHECK: define {{.*}}[[FS1]]([[S1]]* {{%.+}}, i32 {{[^%]*}}[[PARM:%.+]])
//
@@ -146,9 +146,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -174,27 +172,17 @@ int bar(int n){
//
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT2:@.+]]([[S1]]* {{%.+}}, i[[SZ]] [[ARG]])
-// CHECK: br label {{%?}}[[END]]
+// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
-
-
-
-
-
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IF_ELSE]]
+// CHECK: call void [[HVT2]]([[S1]]* {{%.+}}, i[[SZ]] [[ARG]])
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
//
// CHECK: define {{.*}}[[FSTATIC]](i32 {{[^%]*}}[[PARM:%.+]])
@@ -216,22 +204,17 @@ int bar(int n){
//
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT3:@.+]](i[[SZ]] [[ARG]])
-// CHECK: br label {{%?}}[[END]]
+// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IF_ELSE]]
+// CHECK: call void [[HVT3]](i[[SZ]] [[ARG]])
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
//
//
//
@@ -242,22 +225,17 @@ int bar(int n){
//
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
+// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT4:@.+]]()
-// CHECK: br label {{%?}}[[END]]
+// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IF_ELSE]]
+// CHECK: call void [[HVT4]]()
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
@@ -268,9 +246,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -282,9 +258,7 @@ int bar(int n){
//
//
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
diff --git a/test/OpenMP/target_parallel_map_messages.cpp b/test/OpenMP/target_parallel_map_messages.cpp
index ca794cecf4..d3cc742dec 100644
--- a/test/OpenMP/target_parallel_map_messages.cpp
+++ b/test/OpenMP/target_parallel_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -116,9 +116,9 @@ T tmain(T argc) {
foo();
#pragma omp target parallel map(S1) // expected-error {{'S1' does not refer to a value}}
foo();
-#pragma omp target parallel map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
foo();
-#pragma omp target parallel map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel map(ba)
foo();
#pragma omp target parallel map(ca)
foo();
@@ -221,11 +221,11 @@ int main(int argc, char **argv) {
foo();
#pragma omp target parallel map(S1) // expected-error {{'S1' does not refer to a value}}
foo();
-#pragma omp target parallel map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
foo();
#pragma omp target parallel map(argv[1])
foo();
-#pragma omp target parallel map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target parallel map(ba)
foo();
#pragma omp target parallel map(ca)
foo();
diff --git a/test/OpenMP/target_parallel_no_exceptions.cpp b/test/OpenMP/target_parallel_no_exceptions.cpp
new file mode 100644
index 0000000000..95189a3ade
--- /dev/null
+++ b/test/OpenMP/target_parallel_no_exceptions.cpp
@@ -0,0 +1,18 @@
+/// Make sure no exception messages are inclided in the llvm output.
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -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 CHK-EXCEPTION
+
+void test_increment() {
+#pragma omp target
+ {
+ []() { return; }();
+ }
+}
+
+int main() {
+ test_increment();
+ return 0;
+}
+
+//CHK-EXCEPTION-NOT: invoke
+
diff --git a/test/OpenMP/target_parallel_num_threads_codegen.cpp b/test/OpenMP/target_parallel_num_threads_codegen.cpp
index de6a13d087..e2bddaed09 100644
--- a/test/OpenMP/target_parallel_num_threads_codegen.cpp
+++ b/test/OpenMP/target_parallel_num_threads_codegen.cpp
@@ -31,6 +31,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// We have 6 target regions
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -52,11 +54,11 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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 }]
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
template<typename tx>
@@ -146,9 +148,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -159,9 +159,7 @@ int bar(int n){
//
//
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -189,9 +187,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -212,9 +208,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -232,9 +226,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -256,9 +248,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
diff --git a/test/OpenMP/target_parallel_reduction_messages.cpp b/test/OpenMP/target_parallel_reduction_messages.cpp
index 52338ee71c..038f099c5a 100644
--- a/test/OpenMP/target_parallel_reduction_messages.cpp
+++ b/test/OpenMP/target_parallel_reduction_messages.cpp
@@ -24,9 +24,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_simd_aligned_messages.cpp b/test/OpenMP/target_simd_aligned_messages.cpp
index ae2859d5b6..76a37f6498 100644
--- a/test/OpenMP/target_simd_aligned_messages.cpp
+++ b/test/OpenMP/target_simd_aligned_messages.cpp
@@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target simd aligned // expected-error {{expected '(' after 'aligned'}}
for (I k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/target_simd_depend_messages.cpp b/test/OpenMP/target_simd_depend_messages.cpp
index 3fc46f4c08..89184f25d7 100644
--- a/test/OpenMP/target_simd_depend_messages.cpp
+++ b/test/OpenMP/target_simd_depend_messages.cpp
@@ -37,21 +37,21 @@ int main(int argc, char **argv, char *env[]) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd depend (out: ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd depend (out :S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target simd depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target simd depend(in : argv[1][1] = '2')
for (i = 0; i < argc; ++i) foo();
- #pragma omp target simd depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target simd depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd depend (in : argv[0])
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd depend (in : ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
- #pragma omp target simd depend (in : main) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target simd depend (in : main)
for (i = 0; i < argc; ++i) foo();
- #pragma omp target simd depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target simd depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_simd_lastprivate_messages.cpp b/test/OpenMP/target_simd_lastprivate_messages.cpp
index afb38d9c92..9a6eb24172 100644
--- a/test/OpenMP/target_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/target_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
S2 &operator=(const S2 &);
const S2 &operator=(const S2 &) const;
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/target_simd_loop_messages.cpp b/test/OpenMP/target_simd_loop_messages.cpp
index 67201fb73f..d33f1f4cdc 100644
--- a/test/OpenMP/target_simd_loop_messages.cpp
+++ b/test/OpenMP/target_simd_loop_messages.cpp
@@ -541,7 +541,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/target_simd_map_messages.cpp b/test/OpenMP/target_simd_map_messages.cpp
index 63bbdde772..2473bbb49b 100644
--- a/test/OpenMP/target_simd_map_messages.cpp
+++ b/test/OpenMP/target_simd_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -112,9 +112,9 @@ T tmain(T argc) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd map(ca)
for (i = 0; i < argc; ++i) foo();
@@ -214,11 +214,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd map(argv[1])
for (i = 0; i < argc; ++i) foo();
-#pragma omp target simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target simd map(ca)
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_simd_reduction_messages.cpp b/test/OpenMP/target_simd_reduction_messages.cpp
index ca14acb229..9e1bb0521d 100644
--- a/test/OpenMP/target_simd_reduction_messages.cpp
+++ b/test/OpenMP/target_simd_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_teams_codegen.cpp b/test/OpenMP/target_teams_codegen.cpp
index 6bac4e6e58..50ac5a1ced 100644
--- a/test/OpenMP/target_teams_codegen.cpp
+++ b/test/OpenMP/target_teams_codegen.cpp
@@ -32,6 +32,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// 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.
@@ -40,12 +42,12 @@
// 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: [[MAPT4:@.+]] = private unnamed_addr constant [9 x i32] [i32 288, i32 547, i32 288, i32 547, i32 547, i32 288, i32 288, i32 547, i32 547]
// 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: [[MAPT5:@.+]] = private unnamed_addr constant [3 x i32] [i32 288, i32 288, i32 547]
// 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: [[MAPT6:@.+]] = private unnamed_addr constant [4 x i32] [i32 288, i32 288, i32 288, i32 547]
+// CHECK-DAG: [[MAPT7:@.+]] = private unnamed_addr constant [5 x i32] [i32 547, i32 288, i32 288, i32 288, i32 547]
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -68,11 +70,11 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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 }]
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
template<typename tx, typename ty>
@@ -81,6 +83,8 @@ struct TT{
ty Y;
};
+int global;
+
// CHECK: define {{.*}}[[FOO:@.+]](
int foo(int n) {
int a = 0;
@@ -92,9 +96,7 @@ int foo(int 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT0:@.+]]()
@@ -104,10 +106,6 @@ int foo(int n) {
{
}
- // 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)
{
@@ -119,14 +117,12 @@ int foo(int n) {
// 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-DAG: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[CBPADDR0]]
+ // CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[CPADDR0]]
+
+ // CHECK-NEXT: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT2:@.+]](i[[SZ]] {{[^,]+}})
@@ -146,36 +142,33 @@ int foo(int n) {
// 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: [[CBPADDR0:%.+]] = bitcast i8** [[BPADDR0]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0:%.+]] = bitcast i8** [[PADDR0]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[CBPADDR0]]
+ // CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[CPADDR0]]
// 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-DAG: [[CBPADDR1:%.+]] = bitcast i8** [[BPADDR1]] to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR1:%.+]] = bitcast i8** [[PADDR1]] to i[[SZ]]*
+ // CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[CBPADDR1]]
+ // CHECK-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[CPADDR1]]
+ // CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT3:@.+]]({{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+ // CHECK-NEXT: br label %[[IFEND:.+]]
+ // CHECK: [[IFELSE]]
+ // CHECK: call void [[HVT3]]({{[^,]+}}, {{[^,]+}})
+ // CHECK-NEXT: br label %[[IFEND]]
+ // CHECK: [[IFEND]]
#pragma omp target teams if(target: n>10)
{
a += 1;
aa += 1;
+ global += 1;
}
// We capture 3 VLA sizes in this target region
@@ -230,61 +223,61 @@ int foo(int n) {
// 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]] [[VLA0]], i[[SZ]]* [[CBPADDR0:%.+]],
+ // CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CPADDR0:%.+]],
+ // CHECK-DAG: [[CBPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] [[VLA1]], i[[SZ]]* [[CBPADDR1:%.+]],
+ // CHECK-DAG: store i[[SZ]] [[VLA1]], i[[SZ]]* [[CPADDR1:%.+]],
+ // CHECK-DAG: [[CBPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] 5, i[[SZ]]* [[CBPADDR2:%.+]],
+ // CHECK-DAG: store i[[SZ]] 5, i[[SZ]]* [[CPADDR2:%.+]],
+ // CHECK-DAG: [[CBPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] [[A_CVAL]], i[[SZ]]* [[CBPADDR3:%.+]],
+ // CHECK-DAG: store i[[SZ]] [[A_CVAL]], i[[SZ]]* [[CPADDR3:%.+]],
+ // CHECK-DAG: [[CBPADDR3]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+ // CHECK-DAG: [[CPADDR3]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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 [10 x float]* %{{.+}}, [10 x float]** [[CBPADDR4:%.+]],
+ // CHECK-DAG: store [10 x float]* %{{.+}}, [10 x float]** [[CPADDR4:%.+]],
+ // CHECK-DAG: [[CBPADDR4]] = bitcast i8** {{%[^,]+}} to [10 x float]**
+ // CHECK-DAG: [[CPADDR4]] = bitcast i8** {{%[^,]+}} to [10 x float]**
// 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 float* %{{.+}}, float** [[CBPADDR5:%.+]],
+ // CHECK-DAG: store float* %{{.+}}, float** [[CPADDR5:%.+]],
+ // CHECK-DAG: [[CBPADDR5]] = bitcast i8** {{%[^,]+}} to float**
+ // CHECK-DAG: [[CPADDR5]] = bitcast i8** {{%[^,]+}} to float**
// 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 [5 x [10 x double]]* %{{.+}}, [5 x [10 x double]]** [[CBPADDR6:%.+]],
+ // CHECK-DAG: store [5 x [10 x double]]* %{{.+}}, [5 x [10 x double]]** [[CPADDR6:%.+]],
+ // CHECK-DAG: [[CBPADDR6]] = bitcast i8** {{%[^,]+}} to [5 x [10 x double]]**
+ // CHECK-DAG: [[CPADDR6]] = bitcast i8** {{%[^,]+}} to [5 x [10 x double]]**
// 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 double* %{{.+}}, double** [[CBPADDR7:%.+]],
+ // CHECK-DAG: store double* %{{.+}}, double** [[CPADDR7:%.+]],
+ // CHECK-DAG: [[CBPADDR7]] = bitcast i8** {{%[^,]+}} to double**
+ // CHECK-DAG: [[CPADDR7]] = bitcast i8** {{%[^,]+}} to double**
// 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 [[TT]]* %{{.+}}, [[TT]]** [[CBPADDR8:%.+]],
+ // CHECK-DAG: store [[TT]]* %{{.+}}, [[TT]]** [[CPADDR8:%.+]],
+ // CHECK-DAG: [[CBPADDR8]] = bitcast i8** {{%[^,]+}} to [[TT]]**
+ // CHECK-DAG: [[CPADDR8]] = bitcast i8** {{%[^,]+}} to [[TT]]**
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
@@ -368,6 +361,7 @@ int foo(int n) {
// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
// CHECK: [[A_CASTED:%.+]] = alloca i[[SZ]], align
// CHECK: [[AA_CASTED:%.+]] = alloca i[[SZ]], align
+// CHECK: [[GLOBAL_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*
@@ -380,18 +374,28 @@ int foo(int n) {
// 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: [[GLOBAL:%.+]] = load i32, i32* @global, align
+// CHECK-64-DAG:[[GLOBAL_C:%.+]] = bitcast i[[SZ]]* [[GLOBAL_CASTED]] to i32*
+// CHECK-64-DAG:store i32 [[GLOBAL]], i32* [[GLOBAL_C]], align
+// CHECK-32-DAG:store i32 [[GLOBAL]], i32* [[GLOBAL_CASTED]], 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-DAG: [[PARAM3:%.+]] = load i[[SZ]], i[[SZ]]* [[GLOBAL_CASTED]], align
+// CHECK-DAG: 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]], i[[SZ]])* [[OMP_OUTLINED3:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[PARAM1]], i[[SZ]] [[PARAM2]], i[[SZ]] [[PARAM3]])
//
//
-// CHECK: define internal {{.*}}void [[OMP_OUTLINED3]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}})
+// CHECK: define internal {{.*}}void [[OMP_OUTLINED3]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}})
// CHECK: [[A_ADDR:%.+]] = alloca i[[SZ]], align
// CHECK: [[AA_ADDR:%.+]] = alloca i[[SZ]], align
+// CHECK: [[GLOBAL_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-DAG: store i[[SZ]] %{{.+}}, i[[SZ]]* [[GLOBAL_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:[[GLOBAL_CADDR:%.+]] = bitcast i[[SZ]]* [[GLOBAL_ADDR]] to i32*
+// CHECK-64: store i32 {{.+}}, i32* [[GLOBAL_CADDR]],
+// CHECK-32: store i32 {{.+}}, i32* [[GLOBAL_ADDR]],
// CHECK: ret void
// CHECK-NEXT: }
@@ -437,7 +441,7 @@ int foo(int n) {
// 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]]* {{.+}})
+// 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>
@@ -548,37 +552,37 @@ int bar(int n){
// 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]] [[VLA0]], i[[SZ]]* [[CBPADDR0:%.+]],
+// CHECK-DAG: store i[[SZ]] [[VLA0]], i[[SZ]]* [[CPADDR0:%.+]],
+// CHECK-DAG: [[CBPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] 2, i[[SZ]]* [[CBPADDR1:%.+]],
+// CHECK-DAG: store i[[SZ]] 2, i[[SZ]]* [[CPADDR1:%.+]],
+// CHECK-DAG: [[CBPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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]] [[B_CVAL]], i[[SZ]]* [[CBPADDR2:%.+]],
+// CHECK-DAG: store i[[SZ]] [[B_CVAL]], i[[SZ]]* [[CPADDR2:%.+]],
+// CHECK-DAG: [[CBPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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 [[S1]]* %{{.+}}, [[S1]]** [[CBPADDR3:%.+]],
+// CHECK-DAG: store [[S1]]* %{{.+}}, [[S1]]** [[CPADDR3:%.+]],
+// CHECK-DAG: [[CBPADDR3]] = bitcast i8** {{%[^,]+}} to [[S1]]**
+// CHECK-DAG: [[CPADDR3]] = bitcast i8** {{%[^,]+}} to [[S1]]**
// 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 i16* %{{.+}}, i16** [[CBPADDR4:%.+]],
+// CHECK-DAG: store i16* %{{.+}}, i16** [[CPADDR4:%.+]],
+// CHECK-DAG: [[CBPADDR4]] = bitcast i8** {{%[^,]+}} to i16**
+// CHECK-DAG: [[CPADDR4]] = bitcast i8** {{%[^,]+}} to i16**
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:[^,]+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
@@ -598,45 +602,43 @@ int bar(int n){
// 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: store i[[SZ]] [[VAL0:%.+]], i[[SZ]]* [[CBPADDR0:%.+]],
+// CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0:%.+]],
+// CHECK-DAG: [[CBPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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: store i[[SZ]] [[VAL1:%.+]], i[[SZ]]* [[CBPADDR1:%.+]],
+// CHECK-DAG: store i[[SZ]] [[VAL1]], i[[SZ]]* [[CPADDR1:%.+]],
+// CHECK-DAG: [[CBPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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: store i[[SZ]] [[VAL2:%.+]], i[[SZ]]* [[CBPADDR2:%.+]],
+// CHECK-DAG: store i[[SZ]] [[VAL2]], i[[SZ]]* [[CPADDR2:%.+]],
+// CHECK-DAG: [[CBPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR2]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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-DAG: store [10 x i32]* %{{.+}}, [10 x i32]** [[CBPADDR3:%.+]],
+// CHECK-DAG: store [10 x i32]* %{{.+}}, [10 x i32]** [[CPADDR3:%.+]],
+// CHECK-DAG: [[CBPADDR3]] = bitcast i8** {{%[^,]+}} to [10 x i32]**
+// CHECK-DAG: [[CPADDR3]] = bitcast i8** {{%[^,]+}} to [10 x i32]**
-// CHECK: [[IFEND]]
-// CHECK: [[RET2:%.+]] = load i32, i32* [[RHV]], align 4
-// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET2]], 0
+// CHECK: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT6:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IFELSE]]
+// CHECK: call void [[HVT6]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
//
// CHECK: define {{.*}}[[FTEMPLATE]]
@@ -650,40 +652,36 @@ int bar(int n){
// 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: store i[[SZ]] [[VAL0:%.+]], i[[SZ]]* [[CBPADDR0:%.+]],
+// CHECK-DAG: store i[[SZ]] [[VAL0]], i[[SZ]]* [[CPADDR0:%.+]],
+// CHECK-DAG: [[CBPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR0]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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: store i[[SZ]] [[VAL1:%.+]], i[[SZ]]* [[CBPADDR1:%.+]],
+// CHECK-DAG: store i[[SZ]] [[VAL1]], i[[SZ]]* [[CPADDR1:%.+]],
+// CHECK-DAG: [[CBPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
+// CHECK-DAG: [[CPADDR1]] = bitcast i8** {{%[^,]+}} to i[[SZ]]*
// 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-DAG: store [10 x i32]* [[VAL2:%.+]], [10 x i32]** [[CBPADDR2:%.+]],
+// CHECK-DAG: store [10 x i32]* [[VAL2]], [10 x i32]** [[CPADDR2:%.+]],
+// CHECK-DAG: [[CBPADDR2]] = bitcast i8** {{%[^,]+}} to [10 x i32]**
+// CHECK-DAG: [[CPADDR2]] = bitcast i8** {{%[^,]+}} to [10 x i32]**
-// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
// CHECK: [[FAIL]]
// CHECK: call void [[HVT5:@.+]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
// CHECK-NEXT: br label %[[END]]
// CHECK: [[END]]
+// CHECK-NEXT: br label %[[IFEND:.+]]
+// CHECK: [[IFELSE]]
+// CHECK: call void [[HVT5]]({{[^,]+}}, {{[^,]+}}, {{[^,]+}})
+// CHECK-NEXT: br label %[[IFEND]]
+// CHECK: [[IFEND]]
@@ -720,7 +718,7 @@ int bar(int n){
// 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* %{{.+}})
+// 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.
diff --git a/test/OpenMP/target_teams_codegen_registration.cpp b/test/OpenMP/target_teams_codegen_registration.cpp
index f65c701d7a..b8154538df 100644
--- a/test/OpenMP/target_teams_codegen_registration.cpp
+++ b/test/OpenMP/target_teams_codegen_registration.cpp
@@ -36,6 +36,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i[[SZ:32|64]], i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// CHECK-DAG: [[A1:@.+]] = internal global [[SA]]
// CHECK-DAG: [[A2:@.+]] = global [[SA]]
// CHECK-DAG: [[B1:@.+]] = global [[SB]]
@@ -153,15 +155,15 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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-SAME: { i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
// CHECK-NTARGET: @llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [
@@ -364,14 +366,16 @@ struct ST {
// Check registration and unregistration
-//CHECK: define internal void [[UNREGFN:@.+]](i8*)
+//CHECK: define internal void @[[UNREGFN:.+]](i8*)
+//CHECK-SAME: comdat($[[REGFN]]) {
//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: define linkonce hidden void @[[REGFN]](i8*)
+//CHECK-SAME: comdat {
//CHECK: call i32 @__tgt_register_lib([[DSCTY]]* [[DESC]])
-//CHECK: call i32 @__cxa_atexit(void (i8*)* [[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
+//CHECK: call i32 @__cxa_atexit(void (i8*)* @[[UNREGFN]], i8* bitcast ([[DSCTY]]* [[DESC]] to i8*),
//CHECK: ret void
//CHECK: declare i32 @__tgt_register_lib([[DSCTY]]*)
@@ -407,31 +411,31 @@ int bar(int a){
// 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]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 195, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 245, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 261, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 267, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 406, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 290, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 290, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 220, 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]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 195, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 245, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 261, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 267, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 406, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 290, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 284, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 290, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 278, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 220, i32 {{[0-9]+}}}
#endif
diff --git a/test/OpenMP/target_teams_depend_messages.cpp b/test/OpenMP/target_teams_depend_messages.cpp
index 9308e89728..57983eec88 100644
--- a/test/OpenMP/target_teams_depend_messages.cpp
+++ b/test/OpenMP/target_teams_depend_messages.cpp
@@ -36,21 +36,21 @@ int main(int argc, char **argv, char *env[]) {
foo();
#pragma omp target teams depend (out: ) // expected-error {{expected expression}}
foo();
-#pragma omp target teams depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+#pragma omp target teams depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
foo();
#pragma omp target teams depend (out :S1) // expected-error {{'S1' does not refer to a value}}
foo();
-#pragma omp target teams depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams depend(in : argv[1][1] = '2')
foo();
-#pragma omp target teams depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target teams depend (in : argv[0])
foo();
#pragma omp target teams depend (in : ) // expected-error {{expected expression}}
foo();
-#pragma omp target teams depend (in : main) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams depend (in : main)
foo();
-#pragma omp target teams depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+#pragma omp target teams depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
foo();
#pragma omp target teams depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
foo();
diff --git a/test/OpenMP/target_teams_distribute_depend_messages.cpp b/test/OpenMP/target_teams_distribute_depend_messages.cpp
index b3e7331410..fbdd49590f 100644
--- a/test/OpenMP/target_teams_distribute_depend_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_depend_messages.cpp
@@ -37,21 +37,21 @@ int main(int argc, char **argv, char *env[]) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute depend (out: ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+#pragma omp target teams distribute depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute depend (out :S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute depend(in : argv[1][1] = '2')
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute depend (in : argv[0])
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute depend (in : ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute depend (in : main) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute depend (in : main)
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+#pragma omp target teams distribute depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_lastprivate_messages.cpp b/test/OpenMP/target_teams_distribute_lastprivate_messages.cpp
index 8d594e94b0..5cfe7825c8 100644
--- a/test/OpenMP/target_teams_distribute_lastprivate_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/target_teams_distribute_loop_messages.cpp b/test/OpenMP/target_teams_distribute_loop_messages.cpp
index cb243a66b1..441abcba00 100644
--- a/test/OpenMP/target_teams_distribute_loop_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_loop_messages.cpp
@@ -525,7 +525,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/target_teams_distribute_map_messages.cpp b/test/OpenMP/target_teams_distribute_map_messages.cpp
index 5d815de85b..eafdccb66b 100644
--- a/test/OpenMP/target_teams_distribute_map_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -116,9 +116,9 @@ T tmain(T argc) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute map(ca)
for (i = 0; i < argc; ++i) foo();
@@ -222,11 +222,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute map(argv[1])
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute map(ca)
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_depend_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_depend_messages.cpp
index ca7241a16c..c4688958e5 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_depend_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_depend_messages.cpp
@@ -37,21 +37,21 @@ int main(int argc, char **argv, char *env[]) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for depend (out: ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+#pragma omp target teams distribute parallel for depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for depend (out :S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for depend(in : argv[1][1] = '2')
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for depend (in : argv[0])
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for depend (in : ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for depend (in : main) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for depend (in : main)
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_lastprivate_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_lastprivate_messages.cpp
index d31acef003..ccecb638ca 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_lastprivate_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_loop_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_loop_messages.cpp
index 83c78f2aac..d912737a21 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_loop_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_loop_messages.cpp
@@ -523,7 +523,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_map_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_map_messages.cpp
index 326db95f90..1fb466ee55 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_map_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -116,9 +116,9 @@ T tmain(T argc) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for map(ca)
for (i = 0; i < argc; ++i) foo();
@@ -222,11 +222,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for map(argv[1])
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for map(ca)
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_reduction_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_reduction_messages.cpp
index ba9586a1ce..59b35417d4 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_reduction_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_reduction_messages.cpp
@@ -19,9 +19,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp
index df5468c826..f121512733 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_simd_aligned_messages.cpp
@@ -110,9 +110,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target teams distribute parallel for simd aligned // expected-error {{expected '(' after 'aligned'}}
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_simd_depend_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_simd_depend_messages.cpp
index 2dc9979cdc..4a9bf01e40 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_simd_depend_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_simd_depend_messages.cpp
@@ -37,21 +37,21 @@ int main(int argc, char **argv, char *env[]) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd depend (out: ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+#pragma omp target teams distribute parallel for simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd depend (out :S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for simd depend(in : argv[1][1] = '2')
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for simd depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd depend (in : argv[0])
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd depend (in : ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd depend (in : main) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for simd depend (in : main)
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+#pragma omp target teams distribute parallel for simd depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_simd_lastprivate_messages.cpp
index 954830eb19..7f17d679e0 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_simd_loop_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_simd_loop_messages.cpp
index a6b6dd8173..0ed57baa5c 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_simd_loop_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_simd_loop_messages.cpp
@@ -526,7 +526,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_simd_map_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_simd_map_messages.cpp
index 8f9c3e7e07..b230d9ab24 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_simd_map_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_simd_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -116,9 +116,9 @@ T tmain(T argc) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd map(ca)
for (i = 0; i < argc; ++i) foo();
@@ -222,11 +222,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd map(argv[1])
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute parallel for simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute parallel for simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute parallel for simd map(ca)
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_parallel_for_simd_reduction_messages.cpp b/test/OpenMP/target_teams_distribute_parallel_for_simd_reduction_messages.cpp
index cadccbf5cd..63744c77fb 100644
--- a/test/OpenMP/target_teams_distribute_parallel_for_simd_reduction_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_parallel_for_simd_reduction_messages.cpp
@@ -19,9 +19,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_teams_distribute_reduction_messages.cpp b/test/OpenMP/target_teams_distribute_reduction_messages.cpp
index d52ee07613..3cfb08651a 100644
--- a/test/OpenMP/target_teams_distribute_reduction_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_reduction_messages.cpp
@@ -24,9 +24,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp b/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp
index e9df563ded..d91cfa9b54 100644
--- a/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_simd_aligned_messages.cpp
@@ -110,9 +110,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target teams distribute simd aligned // expected-error {{expected '(' after 'aligned'}}
diff --git a/test/OpenMP/target_teams_distribute_simd_depend_messages.cpp b/test/OpenMP/target_teams_distribute_simd_depend_messages.cpp
index 39d12d8d4d..c24c7438b0 100644
--- a/test/OpenMP/target_teams_distribute_simd_depend_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_simd_depend_messages.cpp
@@ -37,21 +37,21 @@ int main(int argc, char **argv, char *env[]) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd depend (out: ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+#pragma omp target teams distribute simd depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd depend (out :S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute simd depend(in : argv[1][1] = '2')
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute simd depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd depend (in : argv[0])
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd depend (in : ) // expected-error {{expected expression}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd depend (in : main) // expected-error {{expected variable name, array element or array section}}
+#pragma omp target teams distribute simd depend (in : main)
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+#pragma omp target teams distribute simd depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_simd_lastprivate_messages.cpp b/test/OpenMP/target_teams_distribute_simd_lastprivate_messages.cpp
index 3b533e2e54..b8b1916f1e 100644
--- a/test/OpenMP/target_teams_distribute_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/target_teams_distribute_simd_loop_messages.cpp b/test/OpenMP/target_teams_distribute_simd_loop_messages.cpp
index 3ddabce5e8..aae00a4433 100644
--- a/test/OpenMP/target_teams_distribute_simd_loop_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_simd_loop_messages.cpp
@@ -525,7 +525,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/target_teams_distribute_simd_map_messages.cpp b/test/OpenMP/target_teams_distribute_simd_map_messages.cpp
index 414f6f83de..29d48d958a 100644
--- a/test/OpenMP/target_teams_distribute_simd_map_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_simd_map_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -116,9 +116,9 @@ T tmain(T argc) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd map(ca)
for (i = 0; i < argc; ++i) foo();
@@ -222,11 +222,11 @@ int main(int argc, char **argv) {
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd map(S1) // expected-error {{'S1' does not refer to a value}}
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute simd map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd map(argv[1])
for (i = 0; i < argc; ++i) foo();
-#pragma omp target teams distribute simd map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target teams distribute simd map(ba)
for (i = 0; i < argc; ++i) foo();
#pragma omp target teams distribute simd map(ca)
for (i = 0; i < argc; ++i) foo();
diff --git a/test/OpenMP/target_teams_distribute_simd_reduction_messages.cpp b/test/OpenMP/target_teams_distribute_simd_reduction_messages.cpp
index 1c0283285a..35d4e12dc3 100644
--- a/test/OpenMP/target_teams_distribute_simd_reduction_messages.cpp
+++ b/test/OpenMP/target_teams_distribute_simd_reduction_messages.cpp
@@ -19,9 +19,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_teams_map_messages.cpp b/test/OpenMP/target_teams_map_messages.cpp
index 15839b8485..ae5f7bcdbc 100644
--- a/test/OpenMP/target_teams_map_messages.cpp
+++ b/test/OpenMP/target_teams_map_messages.cpp
@@ -312,8 +312,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -346,7 +346,7 @@ template <class T>
struct S6;
template<>
-struct S6<int> // expected-note {{mappable type cannot be polymorphic}}
+struct S6<int>
{
virtual void foo();
};
@@ -414,8 +414,8 @@ T tmain(T argc) {
#pragma omp target data map(tofrom: argc > 0 ? x : y) // expected-error 2 {{expected expression containing only member accesses and/or array sections based on named variables}}
#pragma omp target data map(argc)
#pragma omp target data map(S1) // expected-error {{'S1' does not refer to a value}}
-#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
-#pragma omp target data map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
+#pragma omp target data map(ba)
#pragma omp target data map(ca)
#pragma omp target data map(da)
#pragma omp target data map(S2::S2s)
@@ -464,7 +464,7 @@ int main(int argc, char **argv) {
int y;
int to, tofrom, always;
const int (&l)[5] = da;
-#pragma omp target data map // expected-error {{expected '(' after 'map'}} expected-error {{expected at least one map clause for '#pragma omp target data'}}
+#pragma omp target data map // expected-error {{expected '(' after 'map'}} expected-error {{expected at least one 'map' or 'use_device_ptr' clause for '#pragma omp target data'}}
#pragma omp target data map( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{expected expression}}
#pragma omp target data map() // expected-error {{expected expression}}
#pragma omp target data map(alloc) // expected-error {{use of undeclared identifier 'alloc'}}
@@ -488,9 +488,9 @@ int main(int argc, char **argv) {
#pragma omp target data map(tofrom: argc > 0 ? argv[1] : argv[2]) // expected-error {{xpected expression containing only member accesses and/or array sections based on named variables}}
#pragma omp target data map(argc)
#pragma omp target data map(S1) // expected-error {{'S1' does not refer to a value}}
-#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target data map(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
#pragma omp target data map(argv[1])
-#pragma omp target data map(ba) // expected-error 2 {{type 'S2' is not mappable to target}}
+#pragma omp target data map(ba)
#pragma omp target data map(ca)
#pragma omp target data map(da)
#pragma omp target data map(S2::S2s)
@@ -530,7 +530,7 @@ int main(int argc, char **argv) {
#pragma omp target teams firstprivate(j) map(j) // expected-error {{firstprivate variable cannot be in a map clause in '#pragma omp target teams' directive}} expected-note {{defined as firstprivate}}
{}
-#pragma omp target teams map(m) // expected-error {{type 'S6<int>' is not mappable to target}}
+#pragma omp target teams map(m)
{}
return tmain<int, 3>(argc)+tmain<from, 4>(argc); // expected-note {{in instantiation of function template specialization 'tmain<int, 3>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<int, 4>' requested here}}
diff --git a/test/OpenMP/target_teams_num_teams_codegen.cpp b/test/OpenMP/target_teams_num_teams_codegen.cpp
index 6fcfa38e9b..068f76e3dc 100644
--- a/test/OpenMP/target_teams_num_teams_codegen.cpp
+++ b/test/OpenMP/target_teams_num_teams_codegen.cpp
@@ -31,6 +31,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// We have 6 target regions
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -52,11 +54,11 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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 }]
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
template<typename tx>
@@ -146,9 +148,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -159,9 +159,7 @@ int bar(int n){
//
//
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -189,9 +187,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -212,9 +208,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -232,9 +226,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -256,9 +248,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
diff --git a/test/OpenMP/target_teams_reduction_messages.cpp b/test/OpenMP/target_teams_reduction_messages.cpp
index 48fa310253..b5876b1085 100644
--- a/test/OpenMP/target_teams_reduction_messages.cpp
+++ b/test/OpenMP/target_teams_reduction_messages.cpp
@@ -24,9 +24,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/target_teams_thread_limit_codegen.cpp b/test/OpenMP/target_teams_thread_limit_codegen.cpp
index b2fe1bf60e..c56d142660 100644
--- a/test/OpenMP/target_teams_thread_limit_codegen.cpp
+++ b/test/OpenMP/target_teams_thread_limit_codegen.cpp
@@ -31,6 +31,8 @@
// TCHECK: [[ENTTY:%.+]] = type { i8*, i8*, i{{32|64}}, i32, i32 }
+// CHECK-DAG: $[[REGFN:\.omp_offloading\..+]] = comdat
+
// We have 6 target regions
// CHECK-DAG: @{{.*}} = private constant i8 0
@@ -52,11 +54,11 @@
// 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: [[IMAGES:@.+]] = internal unnamed_addr constant [1 x [[DEVTY]]] [{{.+}} { i8* [[DEVBEGIN]], i8* [[DEVEND]], [[ENTTY]]* [[ENTBEGIN]], [[ENTTY]]* [[ENTEND]] }], comdat($[[REGFN]])
+// 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]] }, comdat($[[REGFN]])
// 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 }]
+// CHECK: appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* bitcast (void (i8*)* @[[REGFN]] to void ()*), i8* bitcast (void (i8*)* @[[REGFN]] to i8*) }]
template<typename tx>
@@ -146,9 +148,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -159,9 +159,7 @@ int bar(int n){
//
//
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -198,9 +196,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -221,9 +217,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -241,9 +235,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK-NEXT: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
@@ -265,9 +257,7 @@ int bar(int n){
// 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: [[ERROR:%.+]] = icmp ne i32 [[RET]], 0
// CHECK: br i1 [[ERROR]], label %[[FAIL:.+]], label %[[END:[^,]+]]
//
// CHECK: [[FAIL]]
diff --git a/test/OpenMP/target_update_codegen.cpp b/test/OpenMP/target_update_codegen.cpp
index f74ed49975..f1e61a54c6 100644
--- a/test/OpenMP/target_update_codegen.cpp
+++ b/test/OpenMP/target_update_codegen.cpp
@@ -45,8 +45,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast ([100 x double]* @gc to i8*), i8** [[P0]]
+ // CK1-DAG: [[BPC0:%.+]] = bitcast i8** [[BP0]] to [100 x double]**
+ // CK1-DAG: [[PC0:%.+]] = bitcast i8** [[P0]] to [100 x double]**
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[BPC0]]
+ // CK1-DAG: store [100 x double]* @gc, [100 x double]** [[PC0]]
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
#pragma omp target update if(1+3-5) device(arg) from(gc)
@@ -66,10 +68,10 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast i32* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast i32* [[VAR0]] to i8*
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to i32**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to i32**
+ // CK1-DAG: store i32* [[VAL0:%[^,]+]], i32** [[CBP0]]
+ // CK1-DAG: store i32* [[VAL0]], i32** [[CP0]]
// CK1: br label %[[IFEND:[^,]+]]
// CK1: [[IFELSE]]
@@ -91,11 +93,11 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[S0:%.+]] = getelementptr inbounds {{.+}}[[S]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
- // CK1-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to float**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to float**
+ // CK1-DAG: store float* [[VAL0:%[^,]+]], float** [[CBP0]]
+ // CK1-DAG: store float* [[VAL0]], float** [[CP0]]
// CK1-DAG: store i[[sz]] [[CSVAL0:%[^,]+]], i[[sz]]* [[S0]]
- // CK1-DAG: [[CBPVAL0]] = bitcast float* [[VAR0:%.+]] to i8*
- // CK1-DAG: [[CPVAL0]] = bitcast float* [[VAR0]] to i8*
// CK1-DAG: [[CSVAL0]] = mul nuw i[[sz]] %{{[^,]+}}, 4
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
// CK1-NOT: __tgt_target_data_end
@@ -112,16 +114,19 @@ void foo(int arg) {
// CK1-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK1-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
- // CK1-DAG: store i8* bitcast ([[ST]]* @gb to i8*), i8** [[BP0]]
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[P0]]
+ // CK1-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+ // CK1-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+ // CK1-DAG: store [[ST]]* @gb, [[ST]]** [[CBP0]]
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CP0]]
// CK1-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK1-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
- // CK1-DAG: store i8* bitcast (double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1) to i8*), i8** [[BP1]]
- // CK1-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
- // CK1-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%.+]] to i8*
- // CK1-DAG: [[SEC1]] = getelementptr inbounds {{.+}}double* [[SEC11:%[^,]+]], i{{.+}} 0
+ // CK1-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+ // CK1-DAG: store double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1), double*** [[CBP1]]
+ // CK1-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+ // CK1-DAG: store double* [[VAL1:%[^,]+]], double** [[CP1]]
+ // CK1-DAG: [[VAL1]] = getelementptr inbounds {{.+}}double* [[SEC11:%.+]], i{{.+}} 0
// CK1-DAG: [[SEC11]] = load double*, double** getelementptr inbounds ([[ST]], [[ST]]* @gb, i32 0, i32 1),
// CK1: %{{.+}} = add nsw i32 %{{[^,]+}}, 1
@@ -172,19 +177,19 @@ int bar(int arg){
// CK2-DAG: [[BP0:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 0
// CK2-DAG: [[P0:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 0
-// CK2-DAG: store i8* [[CBPVAL0:%[^,]+]], i8** [[BP0]]
-// CK2-DAG: store i8* [[CPVAL0:%[^,]+]], i8** [[P0]]
-// CK2-DAG: [[CBPVAL0]] = bitcast [[ST]]* [[VAR0:%.+]] to i8*
-// CK2-DAG: [[CPVAL0]] = bitcast double** [[SEC0:%[^,]+]] to i8*
+// CK2-DAG: [[CBP0:%.+]] = bitcast i8** [[BP0]] to [[ST]]**
+// CK2-DAG: [[CP0:%.+]] = bitcast i8** [[P0]] to double***
+// CK2-DAG: store [[ST]]* [[VAR0:%[^,]+]], [[ST]]** [[CBP0]]
+// CK2-DAG: store double** [[SEC0:%[^,]+]], double*** [[CP0]]
// CK2-DAG: [[SEC0]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
// CK2-DAG: [[BP1:%.+]] = getelementptr inbounds {{.+}}[[BP]], i{{.+}} 0, i{{.+}} 1
// CK2-DAG: [[P1:%.+]] = getelementptr inbounds {{.+}}[[P]], i{{.+}} 0, i{{.+}} 1
-// CK2-DAG: store i8* [[CBPVAL1:%[^,]+]], i8** [[BP1]]
-// CK2-DAG: store i8* [[CPVAL1:%[^,]+]], i8** [[P1]]
-// CK2-DAG: [[CBPVAL1]] = bitcast double** [[SEC0]] to i8*
-// CK2-DAG: [[CPVAL1]] = bitcast double* [[SEC1:%[^,]+]] to i8*
+// CK2-DAG: [[CBP1:%.+]] = bitcast i8** [[BP1]] to double***
+// CK2-DAG: [[CP1:%.+]] = bitcast i8** [[P1]] to double**
+// CK2-DAG: store double** [[CBPVAL1:%[^,]+]], double*** [[CBP1]]
+// CK2-DAG: store double* [[SEC1:%[^,]+]], double** [[CP1]]
// CK2-DAG: [[SEC1]] = getelementptr inbounds {{.*}}double* [[SEC11:%[^,]+]], i{{.+}} 1
// CK2-DAG: [[SEC11]] = load double*, double** [[SEC111:%[^,]+]],
// CK2-DAG: [[SEC111]] = getelementptr inbounds {{.*}}[[ST]]* [[VAR0]], i32 0, i32 1
diff --git a/test/OpenMP/target_update_depend_messages.cpp b/test/OpenMP/target_update_depend_messages.cpp
index 64383a0491..59e159e99f 100644
--- a/test/OpenMP/target_update_depend_messages.cpp
+++ b/test/OpenMP/target_update_depend_messages.cpp
@@ -35,14 +35,14 @@ int tmain(T argc, S **argv, R *env[]) {
#pragma omp target update to(z) depend(source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp target update to(z) depend(in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp target update' are ignored}}
#pragma omp target update to(z) depend(out: ) // expected-error {{expected expression}}
- #pragma omp target update to(z) depend(inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target update to(z) depend(inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
#pragma omp target update to(z) depend(out :S1) // expected-error {{'S1' does not refer to a value}}
- #pragma omp target update to(z) depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
- #pragma omp target update to(z) depend(in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target update to(z) depend(in : argv[1][1] = '2') // expected-error {{expected addressable lvalue expression, array element or array section}}
+ #pragma omp target update to(z) depend(in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
#pragma omp target update to(z) depend(in : argv[0])
#pragma omp target update to(z) depend(in : ) // expected-error {{expected expression}}
- #pragma omp target update to(z) depend(in : tmain) // expected-error {{expected variable name, array element or array section}}
- #pragma omp target update to(z) depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target update to(z) depend(in : tmain)
+ #pragma omp target update to(z) depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
#pragma omp target update to(z) depend(in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
#pragma omp target update to(z) depend(in : argv[ // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
#pragma omp target update to(z) depend(in : argv[: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
@@ -83,14 +83,14 @@ int main(int argc, char **argv, char *env[]) {
#pragma omp target update to(z) depend(source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp target update to(z) depend(in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp target update' are ignored}}
#pragma omp target update to(z) depend(out: ) // expected-error {{expected expression}}
- #pragma omp target update to(z) depend(inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp target update to(z) depend(inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
#pragma omp target update to(z) depend(out :S1) // expected-error {{'S1' does not refer to a value}}
- #pragma omp target update to(z) depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
- #pragma omp target update to(z) depend(in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp target update to(z) depend(in : argv[1][1] = '2')
+ #pragma omp target update to(z) depend(in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
#pragma omp target update to(z) depend(in : argv[0])
#pragma omp target update to(z) depend(in : ) // expected-error {{expected expression}}
- #pragma omp target update to(z) depend(in : main) // expected-error {{expected variable name, array element or array section}}
- #pragma omp target update to(z) depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp target update to(z) depend(in : main)
+ #pragma omp target update to(z) depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
#pragma omp target update to(z) depend(in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
#pragma omp target update to(z) depend(in : argv[ // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
#pragma omp target update to(z) depend(in : argv[: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
diff --git a/test/OpenMP/target_update_from_messages.cpp b/test/OpenMP/target_update_from_messages.cpp
index 6aff083b6a..c42bd12f75 100644
--- a/test/OpenMP/target_update_from_messages.cpp
+++ b/test/OpenMP/target_update_from_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -94,8 +94,8 @@ T tmain(T argc) {
#pragma omp target update from(y x) // expected-error {{expected ',' or ')' in 'from' clause}}
#pragma omp target update from(argc > 0 ? x : y) // expected-error 2 {{expected expression containing only member accesses and/or array sections based on named variables}}
#pragma omp target update from(S1) // expected-error {{'S1' does not refer to a value}}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
-#pragma omp target update from(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
-#pragma omp target update from(ba) // expected-error 2 {{type 'S2' is not mappable to target}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+#pragma omp target update from(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
+#pragma omp target update from(ba)
#pragma omp target update from(h) // expected-error {{threadprivate variables are not allowed in 'from' clause}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
#pragma omp target update from(k), to(k) // expected-error 2 {{variable can appear only once in OpenMP 'target update' construct}} expected-note 2 {{used here}}
#pragma omp target update from(t), from(t[:5]) // expected-error 2 {{variable can appear only once in OpenMP 'target update' construct}} expected-note 2 {{used here}}
@@ -148,8 +148,8 @@ int main(int argc, char **argv) {
#pragma omp target update from(y x) // expected-error {{expected ',' or ')' in 'from' clause}}
#pragma omp target update from(argc > 0 ? x : y) // expected-error {{expected expression containing only member accesses and/or array sections based on named variables}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
#pragma omp target update from(S1) // expected-error {{'S1' does not refer to a value}}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
-#pragma omp target update from(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
-#pragma omp target update from(ba) // expected-error 2 {{type 'S2' is not mappable to target}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+#pragma omp target update from(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
+#pragma omp target update from(ba)
#pragma omp target update from(h) // expected-error {{threadprivate variables are not allowed in 'from' clause}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
#pragma omp target update from(k), to(k) // expected-error {{variable can appear only once in OpenMP 'target update' construct}} expected-note {{used here}}
#pragma omp target update from(t), from(t[:5]) // expected-error {{variable can appear only once in OpenMP 'target update' construct}} expected-note {{used here}}
diff --git a/test/OpenMP/target_update_to_messages.cpp b/test/OpenMP/target_update_to_messages.cpp
index 641d0bd949..9bde51e983 100644
--- a/test/OpenMP/target_update_to_messages.cpp
+++ b/test/OpenMP/target_update_to_messages.cpp
@@ -14,8 +14,8 @@ class S2 {
public:
S2():a(0) { }
S2(S2 &s2):a(s2.a) { }
- static float S2s; // expected-note 4 {{mappable type cannot contain static members}}
- static const float S2sc; // expected-note 4 {{mappable type cannot contain static members}}
+ static float S2s;
+ static const float S2sc;
};
const float S2::S2sc = 0;
const S2 b;
@@ -94,8 +94,8 @@ T tmain(T argc) {
#pragma omp target update to(y x) // expected-error {{expected ',' or ')' in 'to' clause}}
#pragma omp target update to(argc > 0 ? x : y) // expected-error 2 {{expected expression containing only member accesses and/or array sections based on named variables}}
#pragma omp target update to(S1) // expected-error {{'S1' does not refer to a value}}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
-#pragma omp target update to(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
-#pragma omp target update to(ba) // expected-error 2 {{type 'S2' is not mappable to target}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+#pragma omp target update to(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
+#pragma omp target update to(ba)
#pragma omp target update to(h) // expected-error {{threadprivate variables are not allowed in 'to' clause}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
#pragma omp target update to(k), from(k) // expected-error 2 {{variable can appear only once in OpenMP 'target update' construct}} expected-note 2 {{used here}}
#pragma omp target update to(t), to(t[:5]) // expected-error 2 {{variable can appear only once in OpenMP 'target update' construct}} expected-note 2 {{used here}}
@@ -147,8 +147,8 @@ int main(int argc, char **argv) {
#pragma omp target update to(y x) // expected-error {{expected ',' or ')' in 'to' clause}}
#pragma omp target update to(argc > 0 ? x : y) // expected-error {{expected expression containing only member accesses and/or array sections based on named variables}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
#pragma omp target update to(S1) // expected-error {{'S1' does not refer to a value}}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
-#pragma omp target update to(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}} expected-error 2 {{type 'S2' is not mappable to target}}
-#pragma omp target update to(ba) // expected-error 2 {{type 'S2' is not mappable to target}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
+#pragma omp target update to(a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
+#pragma omp target update to(ba)
#pragma omp target update to(h) // expected-error {{threadprivate variables are not allowed in 'to' clause}} expected-error {{expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'}}
#pragma omp target update to(k), from(k) // expected-error {{variable can appear only once in OpenMP 'target update' construct}} expected-note {{used here}}
#pragma omp target update to(t), to(t[:5]) // expected-error {{variable can appear only once in OpenMP 'target update' construct}} expected-note {{used here}}
diff --git a/test/OpenMP/task_ast_print.cpp b/test/OpenMP/task_ast_print.cpp
index 9a7d64ee54..54c05d8ed4 100644
--- a/test/OpenMP/task_ast_print.cpp
+++ b/test/OpenMP/task_ast_print.cpp
@@ -13,17 +13,19 @@ struct S1 {
S1(int v) : a(v) {}
int a;
typedef int type;
+ S1 operator +(const S1&);
};
template <typename T>
class S7 : public T {
protected:
- T a;
+ T a, b;
S7() : a(0) {}
public:
S7(typename T::type v) : a(v) {
-#pragma omp task private(a) private(this->a) private(T::a)
+#pragma omp taskgroup task_reduction(+:b)
+#pragma omp task private(a) private(this->a) private(T::a) in_reduction(+:this->b)
for (int k = 0; k < a.a; ++k)
++this->a.a;
}
@@ -35,7 +37,8 @@ public:
}
};
-// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a)
+// CHECK: #pragma omp taskgroup task_reduction(+: this->b)
+// CHECK: #pragma omp task private(this->a) private(this->a) private(T::a) in_reduction(+: this->b)
// CHECK: #pragma omp task private(this->a) private(this->a)
// CHECK: #pragma omp task private(this->a) private(this->a) private(this->S1::a)
@@ -89,7 +92,8 @@ T tmain(T argc, T *argv) {
a = 2;
#pragma omp task default(none), private(argc, b) firstprivate(argv) shared(d) if (argc > 0) final(S<T>::TS > 0) priority(argc)
foo();
-#pragma omp task if (C) mergeable priority(C)
+#pragma omp taskgroup task_reduction(-: argc)
+#pragma omp task if (C) mergeable priority(C) in_reduction(-: argc)
foo();
return 0;
}
@@ -103,7 +107,8 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<T>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
-// CHECK-NEXT: #pragma omp task if(C) mergeable priority(C)
+// CHECK-NEXT: #pragma omp taskgroup task_reduction(-: argc)
+// CHECK-NEXT: #pragma omp task if(C) mergeable priority(C) in_reduction(-: argc)
// CHECK-NEXT: foo()
// CHECK: template<> int tmain<int, 5>(int argc, int *argv) {
// CHECK-NEXT: int b = argc, c, d, e, f, g;
@@ -114,7 +119,8 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<int>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
-// CHECK-NEXT: #pragma omp task if(5) mergeable priority(5)
+// CHECK-NEXT: #pragma omp taskgroup task_reduction(-: argc)
+// CHECK-NEXT: #pragma omp task if(5) mergeable priority(5) in_reduction(-: argc)
// CHECK-NEXT: foo()
// CHECK: template<> long tmain<long, 1>(long argc, long *argv) {
// CHECK-NEXT: long b = argc, c, d, e, f, g;
@@ -125,7 +131,8 @@ T tmain(T argc, T *argv) {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) final(S<long>::TS > 0) priority(argc)
// CHECK-NEXT: foo()
-// CHECK-NEXT: #pragma omp task if(1) mergeable priority(1)
+// CHECK-NEXT: #pragma omp taskgroup task_reduction(-: argc)
+// CHECK-NEXT: #pragma omp task if(1) mergeable priority(1) in_reduction(-: argc)
// CHECK-NEXT: foo()
enum Enum {};
@@ -134,7 +141,7 @@ int main(int argc, char **argv) {
long x;
int b = argc, c, d, e, f, g;
static int a;
- int arr[10];
+ int arr[10], arr1[argc];
#pragma omp threadprivate(a)
Enum ee;
// CHECK: Enum ee;
@@ -142,8 +149,18 @@ int main(int argc, char **argv) {
// CHECK-NEXT: #pragma omp task untied mergeable depend(out : argv[:a][1],(arr)[0:]) if(task: argc > 0) priority(f)
a = 2;
// CHECK-NEXT: a = 2;
-#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a]) priority(23)
- // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a]) priority(23)
+#pragma omp taskgroup task_reduction(min: arr1)
+#pragma omp task default(none), private(argc, b) firstprivate(argv) if (argc > 0) final(a > 0) depend(inout : a, argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1)
+ // CHECK-NEXT: #pragma omp taskgroup task_reduction(min: arr1)
+ // CHECK-NEXT: #pragma omp task default(none) private(argc,b) firstprivate(argv) if(argc > 0) final(a > 0) depend(inout : a,argv[:argc],arr[:a]) priority(23) in_reduction(min: arr1)
+ foo();
+ // CHECK-NEXT: foo();
+#pragma omp taskgroup task_reduction(min: arr1)
+#pragma omp parallel reduction(+:arr1)
+#pragma omp task in_reduction(min: arr1)
+ // CHECK-NEXT: #pragma omp taskgroup task_reduction(min: arr1)
+ // CHECK-NEXT: #pragma omp parallel reduction(+: arr1)
+ // CHECK-NEXT: #pragma omp task in_reduction(min: arr1)
foo();
// CHECK-NEXT: foo();
return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
diff --git a/test/OpenMP/task_codegen.c b/test/OpenMP/task_codegen.c
new file mode 100644
index 0000000000..579a6f1b92
--- /dev/null
+++ b/test/OpenMP/task_codegen.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+void foo();
+
+// CHECK-LABEL: @main
+int main() {
+ // CHECK: call i32 @__kmpc_global_thread_num(
+ // CHECK: call i8* @__kmpc_omp_task_alloc(
+ // CHECK: call i32 @__kmpc_omp_task(
+#pragma omp task
+ {
+#pragma omp taskgroup
+ {
+#pragma omp task
+ foo();
+ }
+ }
+ // CHECK: ret i32 0
+ return 0;
+}
+// CHECK: call void @__kmpc_taskgroup(
+// CHECK: call i8* @__kmpc_omp_task_alloc(
+// CHECK: call i32 @__kmpc_omp_task(
+// CHECK: call void @__kmpc_end_taskgroup(
+#endif
diff --git a/test/OpenMP/task_depend_messages.cpp b/test/OpenMP/task_depend_messages.cpp
index 576738ceac..1e51b479dd 100644
--- a/test/OpenMP/task_depend_messages.cpp
+++ b/test/OpenMP/task_depend_messages.cpp
@@ -28,14 +28,14 @@ int main(int argc, char **argv, char *env[]) {
#pragma omp task depend (source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp task depend (in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
#pragma omp task depend (out: ) // expected-error {{expected expression}}
- #pragma omp task depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
+ #pragma omp task depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected addressable lvalue expression, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}
#pragma omp task depend (out :S1) // expected-error {{'S1' does not refer to a value}}
- #pragma omp task depend(in : argv[1][1] = '2') // expected-error {{expected variable name, array element or array section}}
- #pragma omp task depend (in : vec[1]) // expected-error {{expected variable name, array element or array section}}
+ #pragma omp task depend(in : argv[1][1] = '2')
+ #pragma omp task depend (in : vec[1]) // expected-error {{expected addressable lvalue expression, array element or array section}}
#pragma omp task depend (in : argv[0])
#pragma omp task depend (in : ) // expected-error {{expected expression}}
- #pragma omp task depend (in : main) // expected-error {{expected variable name, array element or array section}}
- #pragma omp task depend(in : a[0]) // expected-error{{expected variable name, array element or array section}}
+ #pragma omp task depend (in : main)
+ #pragma omp task depend(in : a[0]) // expected-error{{expected addressable lvalue expression, array element or array section}}
#pragma omp task depend (in : vec[1:2]) // expected-error {{ value is not an array or pointer}}
#pragma omp task depend (in : argv[ // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
#pragma omp task depend (in : argv[: // expected-error {{expected expression}} expected-error {{expected ']'}} expected-error {{expected ')'}} expected-note {{to match this '['}} expected-note {{to match this '('}}
diff --git a/test/OpenMP/task_in_reduction_codegen.cpp b/test/OpenMP/task_in_reduction_codegen.cpp
new file mode 100644
index 0000000000..2ad013a14a
--- /dev/null
+++ b/test/OpenMP/task_in_reduction_codegen.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c++ -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[PRIVATES:%.+]] = type { i8*, i8* }
+
+struct S {
+ int a;
+ S() : a(0) {}
+ S(const S&) {}
+ S& operator=(const S&) {return *this;}
+ ~S() {}
+ friend S operator+(const S&a, const S&b) {return a;}
+};
+
+
+int main(int argc, char **argv) {
+ int a;
+ float b;
+ S c[5];
+ short d[argc];
+#pragma omp taskgroup task_reduction(+: a, b, argc)
+ {
+#pragma omp taskgroup task_reduction(-:c, d)
+#pragma omp parallel
+#pragma omp task in_reduction(+:a) in_reduction(-:d)
+ a += d[a];
+ }
+ return 0;
+}
+
+// CHECK-LABEL: @main
+// CHECK: void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID:%.+]])
+// CHECK: [[TD1:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 3, i8* %
+// CHECK-NEXT: store i8* [[TD1]], i8** [[TD1_ADDR:%[^,]+]],
+// CHECK-NEXT: call void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID]])
+// CHECK: [[TD2:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 2, i8* %
+// CHECK-NEXT: store i8* [[TD2]], i8** [[TD2_ADDR:%[^,]+]],
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* @0, i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i16*, i8**, i8**)* [[OMP_PARALLEL:@.+]] to void (i32*, i32*, ...)*), i32* %{{.+}}, i64 %{{.+}}, i16* %{{.+}}, i8** [[TD1_ADDR]], i8** [[TD2_ADDR]])
+// CHECK-NEXT: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]])
+// CHECK-NEXT: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]])
+
+// CHECK: define internal void [[OMP_PARALLEL]](
+// CHECK: [[TASK_T:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* @0, i32 [[GTID:%.+]], i32 1, i64 56, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[T:%.+]]*)* [[OMP_TASK:@.+]] to i32 (i32, i8*)*))
+// CHECK-NEXT: [[TASK_T_WITH_PRIVS:%.+]] = bitcast i8* [[TASK_T]] to [[T]]*
+// CHECK: [[PRIVS:%.+]] = getelementptr inbounds [[T]], [[T]]* [[TASK_T_WITH_PRIVS]], i32 0, i32 1
+// CHECK: [[TD1_REF:%.+]] = getelementptr inbounds [[PRIVATES]], [[PRIVATES]]* [[PRIVS]], i32 0, i32 0
+// CHECK-NEXT: [[TD1_SHAR:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[TD1_ADDR:%.+]] = load i8**, i8*** [[TD1_SHAR]],
+// CHECK-NEXT: [[TD1:%.+]] = load i8*, i8** [[TD1_ADDR]],
+// CHECK-NEXT: store i8* [[TD1]], i8** [[TD1_REF]],
+// CHECK-NEXT: [[TD2_REF:%.+]] = getelementptr inbounds [[PRIVATES]], [[PRIVATES]]* [[PRIVS]], i32 0, i32 1
+// CHECK-NEXT: [[TD2_SHAR:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[TD2_ADDR:%.+]] = load i8**, i8*** [[TD2_SHAR]],
+// CHECK-NEXT: [[TD2:%.+]] = load i8*, i8** [[TD2_ADDR]],
+// CHECK-NEXT: store i8* [[TD2]], i8** [[TD2_REF]],
+// CHECK-NEXT: call i32 @__kmpc_omp_task(%ident_t* @0, i32 [[GTID]], i8* [[TASK_T]])
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal {{.*}} [[OMP_TASK]](
+// CHECK: call void (i8*, ...) %{{[^(]+}}(i8* %{{.+}}, i8*** [[TD1_REF:%[^,]+]], i8*** [[TD2_REF:%[^,]+]])
+// CHECK-NEXT: [[TD1_ADDR:%.+]] = load i8**, i8*** [[TD1_REF]],
+// CHECK-NEXT: [[TD2_ADDR:%.+]] = load i8**, i8*** [[TD2_REF]],
+// CHECK-NEXT: [[A_REF:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[A_ADDR:%.+]] = load i32*, i32** [[A_REF]],
+// CHECK-NEXT: [[TD1:%.+]] = load i8*, i8** [[TD1_ADDR]],
+// CHECK-NEXT: [[GTID:%.+]] = load i32, i32* %
+// CHECK-NEXT: [[A_PTR:%.+]] = bitcast i32* [[A_ADDR]] to i8*
+// CHECK-NEXT: call i8* @__kmpc_task_reduction_get_th_data(i32 [[GTID]], i8* [[TD1]], i8* [[A_PTR]])
+// CHECK: [[D_REF:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[D_ADDR:%.+]] = load i16*, i16** [[D_REF]],
+// CHECK: [[TD2:%.+]] = load i8*, i8** [[TD2_ADDR]],
+// CHECK-NEXT: [[D_PTR:%.+]] = bitcast i16* [[D_ADDR]] to i8*
+// CHECK-NEXT: call i8* @__kmpc_task_reduction_get_th_data(i32 [[GTID]], i8* [[TD2]], i8* [[D_PTR]])
+// CHECK: add nsw i32
+// CHECK: store i32 %
+#endif
diff --git a/test/OpenMP/task_in_reduction_message.cpp b/test/OpenMP/task_in_reduction_message.cpp
new file mode 100644
index 0000000000..e176dc9305
--- /dev/null
+++ b/test/OpenMP/task_in_reduction_message.cpp
@@ -0,0 +1,308 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+void foobar(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref)
+#pragma omp task in_reduction(+:ref)
+ foo();
+}
+
+void foobar1(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref)
+#pragma omp task in_reduction(-:ref)
+ foo();
+}
+
+#pragma omp declare reduction (red:int:omp_out += omp_in)
+
+void foobar2(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref) // expected-note {{previously marked as task_reduction with different reduction operation}}
+#pragma omp task in_reduction(red:ref) // expected-error{{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ foo();
+}
+
+void foobar3(int &ref) {
+#pragma omp taskgroup task_reduction(red:ref) // expected-note {{previously marked as task_reduction with different reduction operation}}
+#pragma omp task in_reduction(min:ref) // expected-error{{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ foo();
+}
+
+void foobar4(int &ref) {
+#pragma omp task in_reduction(min:ref) // expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ foo();
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}}
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
+};
+const float S2::S2sc = 0;
+S2 b; // expected-note 3 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ int b;
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+(const S3 &arg1) { return arg1; }
+};
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 3 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+ S4(const S4 &s4);
+ S4 &operator+(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o;
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) {
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i];
+ T fl;
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp task in_reduction // expected-error {{expected '(' after 'in_reduction'}}
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp task in_reduction + // expected-error {{expected '(' after 'in_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp task in_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp task in_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp task in_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp task in_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp task in_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(&:argc) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+#pragma omp task in_reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ foo();
+#pragma omp taskgroup task_reduction(|:argc) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+#pragma omp task in_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ foo();
+#pragma omp task in_reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}}
+ foo();
+#pragma omp task in_reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}}
+ foo();
+#pragma omp taskgroup task_reduction(&&:argc)
+#pragma omp task in_reduction(&& : argc)
+ foo();
+#pragma omp task in_reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ foo();
+#pragma omp taskgroup task_reduction(+:c)
+#pragma omp task in_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}} expected-error 2 {{in_reduction variable must appear in a task_reduction clause}}
+ foo();
+#pragma omp task in_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'in_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ foo();
+#pragma omp task in_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ foo();
+#pragma omp task in_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(+:k)
+#pragma omp task in_reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(+ : o) // expected-error 2 {{no viable overloaded '='}}
+ foo();
+#pragma omp parallel private(k)
+#pragma omp task in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp taskgroup task_reduction(+:p)
+#pragma omp task in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'in_reduction' clause}} expected-note 2 {{previously referenced here}}
+ foo();
+#pragma omp task in_reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp task in_reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp task in_reduction(+ : fl)
+ foo();
+#pragma omp parallel
+#pragma omp for reduction(- : fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp task in_reduction(+ : fl)
+ foo();
+
+ return T();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i];
+ float fl;
+#pragma omp task in_reduction // expected-error {{expected '(' after 'in_reduction'}}
+ foo();
+#pragma omp task in_reduction + // expected-error {{expected '(' after 'in_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
+ foo();
+#pragma omp task in_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp task in_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp task in_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp task in_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp task in_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp task in_reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ foo();
+#pragma omp taskgroup task_reduction(|:argc)
+{
+#pragma omp taskgroup task_reduction(+:argc) // expected-note {{previously marked as task_reduction with different reduction operation}}
+{
+#pragma omp task in_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ foo();
+}
+#pragma omp task in_reduction(| : argc)
+ foo();
+}
+#pragma omp task in_reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}}
+ foo();
+#pragma omp task in_reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ foo();
+#pragma omp taskgroup task_reduction(&&:argc)
+#pragma omp task in_reduction(&& : argc)
+ foo();
+#pragma omp task in_reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+#pragma omp taskgroup task_reduction(+:c)
+#pragma omp task in_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ foo();
+#pragma omp task in_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'in_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ foo();
+#pragma omp task in_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ foo();
+#pragma omp task in_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{nvalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
+ foo();
+#pragma omp taskgroup task_reduction(+:k)
+#pragma omp task in_reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
+ foo();
+#pragma omp task in_reduction(+ : o) // expected-error {{no viable overloaded '='}}
+ foo();
+#pragma omp parallel private(k)
+#pragma omp task in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp taskgroup task_reduction(+:p)
+#pragma omp task in_reduction(+ : p), in_reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'in_reduction' clause}} expected-note {{previously referenced here}}
+ foo();
+#pragma omp task in_reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp task in_reduction(max : j) // expected-error {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp parallel
+#pragma omp for private(fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp task in_reduction(+ : fl)
+ foo();
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp task in_reduction(+ : fl)
+ foo();
+ static int m;
+#pragma omp taskgroup task_reduction(+:m)
+#pragma omp task in_reduction(+ : m) // OK
+ m++;
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/taskgroup_ast_print.cpp b/test/OpenMP/taskgroup_ast_print.cpp
index 683141e686..4292eedfb5 100644
--- a/test/OpenMP/taskgroup_ast_print.cpp
+++ b/test/OpenMP/taskgroup_ast_print.cpp
@@ -8,6 +8,62 @@
void foo() {}
+struct S1 {
+ S1(): a(0) {}
+ S1(int v) : a(v) {}
+ int a;
+ typedef int type;
+ S1& operator +(const S1&);
+ S1& operator *(const S1&);
+ S1& operator &&(const S1&);
+ S1& operator ^(const S1&);
+};
+
+template <typename T>
+class S7 : public T {
+protected:
+ T a;
+ T b[100];
+ S7() : a(0) {}
+
+public:
+ S7(typename T::type v) : a(v) {
+#pragma omp taskgroup task_reduction(+ : a) task_reduction(*: b[:])
+ for (int k = 0; k < a.a; ++k)
+ ++this->a.a;
+ }
+ S7 &operator=(S7 &s) {
+#pragma omp taskgroup task_reduction(&& : this->a) task_reduction(^: b[s.a.a])
+ for (int k = 0; k < s.a.a; ++k)
+ ++s.a.a;
+ return *this;
+ }
+};
+
+// CHECK: #pragma omp taskgroup task_reduction(+: this->a) task_reduction(*: this->b[:])
+// CHECK: #pragma omp taskgroup task_reduction(&&: this->a) task_reduction(^: this->b[s.a.a])
+// CHECK: #pragma omp taskgroup task_reduction(+: this->a) task_reduction(*: this->b[:])
+
+class S8 : public S7<S1> {
+ S8() {}
+
+public:
+ S8(int v) : S7<S1>(v){
+#pragma omp taskgroup task_reduction(^ : S7 < S1 > ::a) task_reduction(+ : S7 < S1 > ::b[ : S7 < S1 > ::a.a])
+ for (int k = 0; k < a.a; ++k)
+ ++this->a.a;
+ }
+ S8 &operator=(S8 &s) {
+#pragma omp taskgroup task_reduction(* : this->a) task_reduction(&&:this->b[a.a:])
+ for (int k = 0; k < s.a.a; ++k)
+ ++s.a.a;
+ return *this;
+ }
+};
+
+// CHECK: #pragma omp taskgroup task_reduction(^: this->S7<S1>::a) task_reduction(+: this->S7<S1>::b[:this->S7<S1>::a.a])
+// CHECK: #pragma omp taskgroup task_reduction(*: this->a) task_reduction(&&: this->b[this->a.a:])
+
int main (int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
@@ -18,9 +74,9 @@ int main (int argc, char **argv) {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: ++a;
++a;
-#pragma omp taskgroup
+#pragma omp taskgroup task_reduction(min: a)
foo();
-// CHECK-NEXT: #pragma omp taskgroup
+// CHECK-NEXT: #pragma omp taskgroup task_reduction(min: a)
// CHECK-NEXT: foo();
// CHECK-NEXT: return 0;
return 0;
diff --git a/test/OpenMP/taskgroup_codegen.cpp b/test/OpenMP/taskgroup_codegen.cpp
index 4b7d89e703..3dd41a1f82 100644
--- a/test/OpenMP/taskgroup_codegen.cpp
+++ b/test/OpenMP/taskgroup_codegen.cpp
@@ -40,7 +40,7 @@ int main() {
void parallel_taskgroup() {
#pragma omp parallel
#pragma omp taskgroup
- // TERM_DEBUG-NOT: __kmpc_global_thread_num
+ // TERM_DEBUG: __kmpc_global_thread_num
// TERM_DEBUG: call void @__kmpc_taskgroup({{.+}}), !dbg [[DBG_LOC_START:![0-9]+]]
// TERM_DEBUG: invoke void {{.*}}foo{{.*}}()
// TERM_DEBUG: unwind label %[[TERM_LPAD:.+]],
diff --git a/test/OpenMP/taskgroup_messages.cpp b/test/OpenMP/taskgroup_messages.cpp
index e893da4be3..23820734a5 100644
--- a/test/OpenMP/taskgroup_messages.cpp
+++ b/test/OpenMP/taskgroup_messages.cpp
@@ -63,5 +63,7 @@ int foo() {
foo();
}
+#pragma omp taskgroup init // expected-warning {{extra tokens at the end of '#pragma omp taskgroup' are ignored}}
+ ;
return 0;
}
diff --git a/test/OpenMP/taskgroup_task_reduction_codegen.cpp b/test/OpenMP/taskgroup_task_reduction_codegen.cpp
new file mode 100644
index 0000000000..63e0151824
--- /dev/null
+++ b/test/OpenMP/taskgroup_task_reduction_codegen.cpp
@@ -0,0 +1,212 @@
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c++ -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ %s -verify -debug-info-kind=limited -emit-llvm -o - -triple x86_64-apple-darwin10 | FileCheck %s --check-prefix=CHECK --check-prefix=DEBUG
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+struct S {
+ int a;
+ S() : a(0) {}
+ S(const S&) {}
+ S& operator=(const S&) {return *this;}
+ ~S() {}
+ friend S operator+(const S&a, const S&b) {return a;}
+};
+
+
+int main(int argc, char **argv) {
+ int a;
+ float b;
+ S c[5];
+ short d[argc];
+#pragma omp taskgroup task_reduction(+: a, b, argc)
+ {
+#pragma omp taskgroup task_reduction(-:c, d)
+ ;
+ }
+ return 0;
+}
+// CHECK-LABEL: @main
+// CHECK: alloca i32,
+// CHECK: [[ARGC_ADDR:%.+]] = alloca i32,
+// CHECK: [[ARGV_ADDR:%.+]] = alloca i8**,
+// CHECK: [[A:%.+]] = alloca i32,
+// CHECK: [[B:%.+]] = alloca float,
+// CHECK: [[C:%.+]] = alloca [5 x %struct.S],
+// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t*
+// CHECK: [[RD_IN1:%.+]] = alloca [3 x [[T1:%[^,]+]]],
+// CHECK: [[TD1:%.+]] = alloca i8*,
+// CHECK: [[RD_IN2:%.+]] = alloca [2 x [[T2:%[^,]+]]],
+// CHECK: [[TD2:%.+]] = alloca i8*,
+
+// CHECK: [[VLA:%.+]] = alloca i16, i64 [[VLA_SIZE:%[^,]+]],
+
+// CHECK: call void @__kmpc_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]])
+// CHECK-DAG: [[BC_A:%.+]] = bitcast i32* [[A]] to i8*
+// CHECK-DAG: store i8* [[BC_A]], i8** [[A_REF:[^,]+]],
+// CHECK-DAG: [[A_REF]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPA:%[^,]+]], i32 0, i32 0
+// CHECK-DAG: [[GEPA]] = getelementptr inbounds [3 x [[T1]]], [3 x [[T1]]]* [[RD_IN1]], i64 0, i64
+// CHECK-DAG: [[TMP6:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPA]], i32 0, i32 1
+// CHECK-DAG: store i64 4, i64* [[TMP6]],
+// CHECK-DAG: [[TMP7:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPA]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[AINIT:@.+]] to i8*), i8** [[TMP7]],
+// CHECK-DAG: [[TMP8:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPA]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP8]],
+// CHECK-DAG: [[TMP9:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPA]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[ACOMB:@.+]] to i8*), i8** [[TMP9]],
+// CHECK-DAG: [[TMP10:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPA]], i32 0, i32 5
+// CHECK-DAG: [[TMP11:%.+]] = bitcast i32* [[TMP10]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP11]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[TMP13:%.+]] = bitcast float* [[B]] to i8*
+// CHECK-DAG: store i8* [[TMP13]], i8** [[TMP12:%[^,]+]],
+// CHECK-DAG: [[TMP12]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPB:%[^,]+]], i32 0, i32 0
+// CHECK-DAG: [[GEPB]] = getelementptr inbounds [3 x [[T1]]], [3 x [[T1]]]* [[RD_IN1]], i64 0, i64
+// CHECK-DAG: [[TMP14:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPB]], i32 0, i32 1
+// CHECK-DAG: store i64 4, i64* [[TMP14]],
+// CHECK-DAG: [[TMP15:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPB]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[BINIT:@.+]] to i8*), i8** [[TMP15]],
+// CHECK-DAG: [[TMP16:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPB]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP16]],
+// CHECK-DAG: [[TMP17:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPB]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[BCOMB:@.+]] to i8*), i8** [[TMP17]],
+// CHECK-DAG: [[TMP18:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPB]], i32 0, i32 5
+// CHECK-DAG: [[TMP19:%.+]] = bitcast i32* [[TMP18]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP19]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[TMP21:%.+]] = bitcast i32* [[ARGC_ADDR]] to i8*
+// CHECK-DAG: store i8* [[TMP21]], i8** [[TMP20:%[^,]+]],
+// CHECK-DAG: [[TMP20]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPARGC:%[^,]+]], i32 0, i32 0
+// CHECK-DAG: [[GEPARGC]] = getelementptr inbounds [3 x [[T1]]], [3 x [[T1]]]* [[RD_IN1]], i64 0, i64
+// CHECK-DAG: [[TMP22:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPARGC]], i32 0, i32 1
+// CHECK-DAG: store i64 4, i64* [[TMP22]],
+// CHECK-DAG: [[TMP23:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPARGC]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[ARGCINIT:@.+]] to i8*), i8** [[TMP23]],
+// CHECK-DAG: [[TMP24:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPARGC]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP24]],
+// CHECK-DAG: [[TMP25:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPARGC]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[ARGCCOMB:@.+]] to i8*), i8** [[TMP25]],
+// CHECK-DAG: [[TMP26:%.+]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPARGC]], i32 0, i32 5
+// CHECK-DAG: [[TMP27:%.+]] = bitcast i32* [[TMP26]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP27]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[TMP28:%.+]] = bitcast [3 x [[T1]]]* [[RD_IN1]] to i8*
+// CHECK-DAG: [[TMP29:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 3, i8* [[TMP28]])
+// DEBUG-DAG: call void @llvm.dbg.declare(metadata i8** [[TD1]],
+// CHECK-DAG: store i8* [[TMP29]], i8** [[TD1]],
+// CHECK-DAG: call void @__kmpc_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]])
+// CHECK-DAG: [[TMP31:%.+]] = bitcast [5 x %struct.S]* [[C]] to i8*
+// CHECK-DAG: store i8* [[TMP31]], i8** [[TMP30:%[^,]+]],
+// CHECK-DAG: [[TMP30]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPC:%[^,]+]], i32 0, i32 0
+// CHECK-DAG: [[GEPC]] = getelementptr inbounds [2 x [[T2]]], [2 x [[T2]]]* [[RD_IN2]], i64 0, i64
+// CHECK-DAG: [[TMP32:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPC]], i32 0, i32 1
+// CHECK-DAG: store i64 20, i64* [[TMP32]],
+// CHECK-DAG: [[TMP33:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPC]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[CINIT:@.+]] to i8*), i8** [[TMP33]],
+// CHECK-DAG: [[TMP34:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPC]], i32 0, i32 3
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[CFINI:@.+]] to i8*), i8** [[TMP34]],
+// CHECK-DAG: [[TMP35:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPC]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[CCOMB:@.+]] to i8*), i8** [[TMP35]],
+// CHECK-DAG: [[TMP36:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPC]], i32 0, i32 5
+// CHECK-DAG: [[TMP37:%.+]] = bitcast i32* [[TMP36]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP37]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[TMP39:%.+]] = bitcast i16* [[VLA]] to i8*
+// CHECK-DAG: store i8* [[TMP39]], i8** [[TMP38:%[^,]+]],
+// CHECK-DAG: [[TMP38]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPVLA:%[^,]+]], i32 0, i32 0
+// CHECK-DAG: [[GEPVLA]] = getelementptr inbounds [2 x [[T2]]], [2 x [[T2]]]* [[RD_IN2]], i64 0, i64
+// CHECK-DAG: [[TMP40:%.+]] = mul nuw i64 [[VLA_SIZE]], 2
+// CHECK-DAG: [[TMP41:%.+]] = udiv exact i64 [[TMP40]], ptrtoint (i16* getelementptr (i16, i16* null, i32 1) to i64)
+// CHECK-DAG: [[TMP42:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPVLA]], i32 0, i32 1
+// CHECK-DAG: store i64 [[TMP40]], i64* [[TMP42]],
+// CHECK-DAG: [[TMP43:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPVLA]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[VLAINIT:@.+]] to i8*), i8** [[TMP43]],
+// CHECK-DAG: [[TMP44:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPVLA]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP44]],
+// CHECK-DAG: [[TMP45:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPVLA]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[VLACOMB:@.+]] to i8*), i8** [[TMP45]],
+// CHECK-DAG: [[TMP46:%.+]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPVLA]], i32 0, i32 5
+// CHECK-DAG: store i32 1, i32* [[TMP46]],
+// CHECK: [[TMP47:%.+]] = bitcast [2 x [[T2]]]* [[RD_IN2]] to i8*
+// CHECK: [[TMP48:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 2, i8* [[TMP47]])
+// CHECK: store i8* [[TMP48]], i8** [[TD2]],
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]])
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]])
+
+// CHECK-DAG: define internal void [[AINIT]](i8*)
+// CHECK-DAG: store i32 0, i32* %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[ACOMB]](i8*, i8*)
+// CHECK-DAG: add nsw i32 %
+// CHECK-DAG: store i32 %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[BINIT]](i8*)
+// CHECK-DAG: store float 0.000000e+00, float* %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[BCOMB]](i8*, i8*)
+// CHECK-DAG: fadd float %
+// CHECK-DAG: store float %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[ARGCINIT]](i8*)
+// CHECK-DAG: store i32 0, i32* %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[ARGCCOMB]](i8*, i8*)
+// CHECK-DAG: add nsw i32 %
+// CHECK-DAG: store i32 %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[CINIT]](i8*)
+// CHECK-DAG: phi %struct.S* [
+// CHECK-DAG: call {{.+}}(%struct.S* {{.+}})
+// CHECK-DAG: br i1 %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[CFINI]](i8*)
+// CHECK-DAG: phi %struct.S* [
+// CHECK-DAG: call {{.+}}(%struct.S* {{.+}})
+// CHECK-DAG: br i1 %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[CCOMB]](i8*, i8*)
+// CHECK-DAG: phi %struct.S* [
+// CHECK-DAG: phi %struct.S* [
+// CHECK-DAG: call {{.+}}(%struct.S* {{.+}}, %struct.S* {{.+}}, %struct.S* {{.+}})
+// CHECK-DAG: call {{.+}}(%struct.S* {{.+}}, %struct.S* {{.+}})
+// CHECK-DAG: call {{.+}}(%struct.S* {{.+}})
+// CHECK-DAG: br i1 %
+// CHECK-DAG: ret void
+// CHECK_DAG: }
+
+// CHECK-DAG: define internal void [[VLAINIT]](i8*)
+// CHECK-DAG: call i32 @__kmpc_global_thread_num(%ident_t* {{[^,]+}})
+// CHECK-DAG: call i8* @__kmpc_threadprivate_cached(%ident_t*
+// CHECK-DAG: phi i16* [
+// CHECK-DAG: store i16 0, i16* %
+// CHECK-DAG: br i1 %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+
+// CHECK-DAG: define internal void [[VLACOMB]](i8*, i8*)
+// CHECK-DAG: call i32 @__kmpc_global_thread_num(%ident_t* {{[^,]+}})
+// CHECK-DAG: call i8* @__kmpc_threadprivate_cached(%ident_t*
+// CHECK-DAG: phi i16* [
+// CHECK-DAG: phi i16* [
+// CHECK-DAG: sext i16 %{{.+}} to i32
+// CHECK-DAG: add nsw i32 %
+// CHECK-DAG: trunc i32 %{{.+}} to i16
+// CHECK-DAG: store i16 %
+// CHECK_DAG: br i1 %
+// CHECK-DAG: ret void
+// CHECK-DAG: }
+#endif
diff --git a/test/OpenMP/taskgroup_task_reduction_messages.cpp b/test/OpenMP/taskgroup_task_reduction_messages.cpp
new file mode 100644
index 0000000000..819dc5bdaf
--- /dev/null
+++ b/test/OpenMP/taskgroup_task_reduction_messages.cpp
@@ -0,0 +1,258 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+void foobar(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref)
+ foo();
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}}
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
+};
+const float S2::S2sc = 0;
+S2 b; // expected-note 3 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ int b;
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+(const S3 &arg1) { return arg1; }
+};
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 3 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+ S4(const S4 &s4);
+ S4 &operator+(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o;
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) {
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i];
+ T fl;
+#pragma omp taskgroup task_reduction // expected-error {{expected '(' after 'task_reduction'}}
+ foo();
+#pragma omp taskgroup task_reduction + // expected-error {{expected '(' after 'task_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskgroup' are ignored}}
+ foo();
+#pragma omp taskgroup task_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp taskgroup task_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp taskgroup task_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ foo();
+#pragma omp taskgroup task_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ foo();
+#pragma omp taskgroup task_reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}}
+ foo();
+#pragma omp taskgroup task_reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}}
+ foo();
+#pragma omp taskgroup task_reduction(&& : argc)
+ foo();
+#pragma omp taskgroup task_reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}}
+ foo();
+#pragma omp taskgroup task_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'task_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ foo();
+#pragma omp taskgroup task_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : o) // expected-error 2 {{no viable overloaded '='}}
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskgroup task_reduction(+ : p), task_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'task_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : p), task_reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'task_reduction' clause}} expected-note 2 {{previously referenced here}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskgroup task_reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'task_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp parallel
+#pragma omp for private(fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+ : fl)
+ foo();
+#pragma omp parallel
+#pragma omp for reduction(- : fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+ : fl)
+ foo();
+
+ return T();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i];
+ float fl;
+#pragma omp taskgroup task_reduction // expected-error {{expected '(' after 'task_reduction'}}
+ foo();
+#pragma omp taskgroup task_reduction + // expected-error {{expected '(' after 'task_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskgroup' are ignored}}
+ foo();
+#pragma omp taskgroup task_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp taskgroup task_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp taskgroup task_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ foo();
+#pragma omp taskgroup task_reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ foo();
+#pragma omp taskgroup task_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ foo();
+#pragma omp taskgroup task_reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}}
+ foo();
+#pragma omp taskgroup task_reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ foo();
+#pragma omp taskgroup task_reduction(&& : argc)
+ foo();
+#pragma omp taskgroup task_reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
+ foo();
+#pragma omp taskgroup task_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'task_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ foo();
+#pragma omp taskgroup task_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{nvalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : o) // expected-error {{no viable overloaded '='}}
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskgroup task_reduction(+ : p), task_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'task_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : p), task_reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'task_reduction' clause}} expected-note {{previously referenced here}}
+ foo();
+#pragma omp taskgroup task_reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}}
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskgroup task_reduction(max : j) // expected-error {{argument of OpenMP clause 'task_reduction' must reference the same object in all threads}}
+ foo();
+#pragma omp parallel
+#pragma omp for private(fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+ : fl)
+ foo();
+#pragma omp parallel
+#pragma omp for reduction(- : fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+ : fl)
+ foo();
+ static int m;
+#pragma omp taskgroup task_reduction(+ : m) // OK
+ m++;
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/taskloop_ast_print.cpp b/test/OpenMP/taskloop_ast_print.cpp
index d2fae3fe0f..891b31dce4 100644
--- a/test/OpenMP/taskloop_ast_print.cpp
+++ b/test/OpenMP/taskloop_ast_print.cpp
@@ -13,8 +13,10 @@ T tmain(T argc) {
T b = argc, c, d, e, f, g;
static T a;
// CHECK: static T a;
-#pragma omp taskloop if(taskloop: argc > N) default(shared) untied priority(N) grainsize(N)
- // CHECK-NEXT: #pragma omp taskloop if(taskloop: argc > N) default(shared) untied priority(N) grainsize(N)
+#pragma omp taskgroup task_reduction(+: d)
+#pragma omp taskloop if(taskloop: argc > N) default(shared) untied priority(N) grainsize(N) reduction(+:g) in_reduction(+: d)
+ // CHECK-NEXT: #pragma omp taskgroup task_reduction(+: d)
+ // CHECK-NEXT: #pragma omp taskloop if(taskloop: argc > N) default(shared) untied priority(N) grainsize(N) reduction(+: g) in_reduction(+: d)
for (int i = 0; i < 2; ++i)
a = 2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
@@ -53,19 +55,21 @@ int main(int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
// CHECK: static int a;
-#pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) nogroup num_tasks(argc)
- // CHECK-NEXT: #pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) nogroup num_tasks(argc)
+#pragma omp taskgroup task_reduction(+: d)
+#pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) num_tasks(argc) reduction(*: g) in_reduction(+:d)
+ // CHECK-NEXT: #pragma omp taskgroup task_reduction(+: d)
+ // CHECK-NEXT: #pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) num_tasks(argc) reduction(*: g) in_reduction(+: d)
for (int i = 0; i < 2; ++i)
a = 2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
#pragma omp parallel
-#pragma omp taskloop private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) shared(g) if(argc) mergeable priority(argc) grainsize(argc)
+#pragma omp taskloop private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) shared(g) if(argc) mergeable priority(argc) grainsize(argc) reduction(max: a, e)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
foo();
// CHECK-NEXT: #pragma omp parallel
- // CHECK-NEXT: #pragma omp taskloop private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) shared(g) if(argc) mergeable priority(argc) grainsize(argc)
+ // CHECK-NEXT: #pragma omp taskloop private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) shared(g) if(argc) mergeable priority(argc) grainsize(argc) reduction(max: a,e)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: foo();
diff --git a/test/OpenMP/taskloop_codegen.cpp b/test/OpenMP/taskloop_codegen.cpp
index bc7367ce02..94cf5365d8 100644
--- a/test/OpenMP/taskloop_codegen.cpp
+++ b/test/OpenMP/taskloop_codegen.cpp
@@ -8,7 +8,12 @@
// CHECK-LABEL: @main
int main(int argc, char **argv) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* [[DEFLOC:@.+]])
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 33, i64 72, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK1:@.+]] to i32 (i32, i8*)*))
+// CHECK: call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]],
+// CHECK: call i32 @__kmpc_omp_task(%ident_t* [[DEFLOC]], i32 [[GTID]],
+#pragma omp task
+ ;
+// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 33, i64 80, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK1:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[DOWN:%.+]] = getelementptr inbounds [[TD_TY:%.+]], [[TD_TY]]* [[TASK_DATA]], i32 0, i32 5
@@ -19,10 +24,11 @@ int main(int argc, char **argv) {
// CHECK: store i64 1, i64* [[ST]],
// CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]],
// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 0, i64 0, i8* null)
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
#pragma omp taskloop priority(argc)
for (int i = 0; i < 10; ++i)
;
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK2:@.+]] to i32 (i32, i8*)*))
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 80, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK2:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[DOWN:%.+]] = getelementptr inbounds [[TD_TY:%.+]], [[TD_TY]]* [[TASK_DATA]], i32 0, i32 5
@@ -33,11 +39,12 @@ int main(int argc, char **argv) {
// CHECK: store i64 1, i64* [[ST]],
// CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]],
// CHECK: [[GRAINSIZE:%.+]] = zext i32 %{{.+}} to i64
-// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 1, i32 1, i64 [[GRAINSIZE]], i8* null)
+// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 1, i64 [[GRAINSIZE]], i8* null)
#pragma omp taskloop nogroup grainsize(argc)
for (int i = 0; i < 10; ++i)
;
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 24, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK3:@.+]] to i32 (i32, i8*)*))
+// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 80, i64 24, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK3:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[IF:%.+]] = icmp ne i32 %{{.+}}, 0
@@ -50,6 +57,7 @@ int main(int argc, char **argv) {
// CHECK: store i64 1, i64* [[ST]],
// CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]],
// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 [[IF_INT]], i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 2, i64 4, i8* null)
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
int i;
#pragma omp taskloop if(argc) shared(argc, argv) collapse(2) num_tasks(4)
for (i = 0; i < argc; ++i)
@@ -140,7 +148,7 @@ struct S {
int a;
S(int c) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* [[DEFLOC:@.+]])
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK4:@.+]] to i32 (i32, i8*)*))
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 80, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK4:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[DOWN:%.+]] = getelementptr inbounds [[TD_TY:%.+]], [[TD_TY]]* [[TASK_DATA]], i32 0, i32 5
diff --git a/test/OpenMP/taskloop_firstprivate_codegen.cpp b/test/OpenMP/taskloop_firstprivate_codegen.cpp
index f4358db99b..6e84530509 100644
--- a/test/OpenMP/taskloop_firstprivate_codegen.cpp
+++ b/test/OpenMP/taskloop_firstprivate_codegen.cpp
@@ -23,7 +23,7 @@ struct S {
volatile double g;
-// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32 }
+// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32, i8* }
// CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double }
// CHECK-DAG: [[PRIVATES_MAIN_TY:%.+]] = type {{.?}}{ [2 x [[S_DOUBLE_TY]]], [[S_DOUBLE_TY]], i32, [2 x i32]
// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type {{.*}}{ [2 x i32]*, i32, {{.*}}[2 x [[S_DOUBLE_TY]]]*, [[S_DOUBLE_TY]]*, i{{[0-9]+}}
@@ -57,7 +57,7 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
- // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// LAMBDA: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0
// LAMBDA: [[G_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 0
@@ -101,7 +101,7 @@ int main() {
// BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
- // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// BLOCKS: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// BLOCKS: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0
// BLOCKS: [[G_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 0
@@ -190,7 +190,7 @@ int main() {
// [[KMP_TASK_T]] task_data;
// [[KMP_TASK_MAIN_TY]] privates;
// };
-// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 112, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 120, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_MAIN_TY]]*
// Fill kmp_task_t->shareds by copying from original capture argument.
diff --git a/test/OpenMP/taskloop_firstprivate_messages.cpp b/test/OpenMP/taskloop_firstprivate_messages.cpp
index fe22311f65..e63d6a678b 100644
--- a/test/OpenMP/taskloop_firstprivate_messages.cpp
+++ b/test/OpenMP/taskloop_firstprivate_messages.cpp
@@ -295,9 +295,9 @@ int main(int argc, char **argv) {
#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}}
for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}}
foo();
-#pragma omp parallel reduction(+ : i) // expected-note 4 {{defined as reduction}}
+#pragma omp parallel reduction(+ : i) // expected-note 2 {{defined as reduction}}
#pragma omp taskloop firstprivate(i) //expected-error {{argument of a reduction clause of a parallel construct must not appear in a firstprivate clause on a task construct}}
- for (i = 0; i < argc; ++i) // expected-error 3 {{reduction variables may not be accessed in an explicit task}}
+ for (i = 0; i < argc; ++i) // expected-error {{reduction variables may not be accessed in an explicit task}}
foo();
#pragma omp parallel
#pragma omp taskloop firstprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
diff --git a/test/OpenMP/taskloop_in_reduction_codegen.cpp b/test/OpenMP/taskloop_in_reduction_codegen.cpp
new file mode 100644
index 0000000000..e9ee9a32b9
--- /dev/null
+++ b/test/OpenMP/taskloop_in_reduction_codegen.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c++ -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[PRIVATES:%.+]] = type { i8*, i8* }
+
+struct S {
+ int a;
+ S() : a(0) {}
+ S(const S&) {}
+ S& operator=(const S&) {return *this;}
+ ~S() {}
+ friend S operator+(const S&a, const S&b) {return a;}
+};
+
+
+int main(int argc, char **argv) {
+ int a;
+ float b;
+ S c[5];
+ short d[argc];
+#pragma omp taskgroup task_reduction(+: a, b, argc)
+ {
+#pragma omp taskgroup task_reduction(-:c, d)
+#pragma omp parallel
+#pragma omp taskloop in_reduction(+:a) in_reduction(-:d)
+ for (int i = 0; i < 5; ++i)
+ a += d[a];
+ }
+ return 0;
+}
+
+// CHECK-LABEL: @main
+// CHECK: void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID:%.+]])
+// CHECK: [[TD1:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 3, i8* %
+// CHECK-NEXT: store i8* [[TD1]], i8** [[TD1_ADDR:%[^,]+]],
+// CHECK-NEXT: call void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID]])
+// CHECK: [[TD2:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 2, i8* %
+// CHECK-NEXT: store i8* [[TD2]], i8** [[TD2_ADDR:%[^,]+]],
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* @0, i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i16*, i8**, i8**)* [[OMP_PARALLEL:@.+]] to void (i32*, i32*, ...)*), i32* %{{.+}}, i64 %{{.+}}, i16* %{{.+}}, i8** [[TD1_ADDR]], i8** [[TD2_ADDR]])
+// CHECK-NEXT: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]])
+// CHECK-NEXT: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]])
+
+// CHECK: define internal void [[OMP_PARALLEL]](
+// CHECK: [[TASK_T:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* @0, i32 [[GTID:%.+]], i32 1, i64 96, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[T:%.+]]*)* [[OMP_TASK:@.+]] to i32 (i32, i8*)*))
+// CHECK-NEXT: [[TASK_T_WITH_PRIVS:%.+]] = bitcast i8* [[TASK_T]] to [[T]]*
+// CHECK: [[PRIVS:%.+]] = getelementptr inbounds [[T]], [[T]]* [[TASK_T_WITH_PRIVS]], i32 0, i32 1
+// CHECK: [[TD1_REF:%.+]] = getelementptr inbounds [[PRIVATES]], [[PRIVATES]]* [[PRIVS]], i32 0, i32 0
+// CHECK-NEXT: [[TD1_SHAR:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[TD1_ADDR:%.+]] = load i8**, i8*** [[TD1_SHAR]],
+// CHECK-NEXT: [[TD1:%.+]] = load i8*, i8** [[TD1_ADDR]],
+// CHECK-NEXT: store i8* [[TD1]], i8** [[TD1_REF]],
+// CHECK-NEXT: [[TD2_REF:%.+]] = getelementptr inbounds [[PRIVATES]], [[PRIVATES]]* [[PRIVS]], i32 0, i32 1
+// CHECK-NEXT: [[TD2_SHAR:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[TD2_ADDR:%.+]] = load i8**, i8*** [[TD2_SHAR]],
+// CHECK-NEXT: [[TD2:%.+]] = load i8*, i8** [[TD2_ADDR]],
+// CHECK-NEXT: store i8* [[TD2]], i8** [[TD2_REF]],
+// CHECK: call void @__kmpc_taskloop(%ident_t* @0, i32 [[GTID]], i8* [[TASK_T]], i32 1,
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal {{.*}} [[OMP_TASK]](
+// CHECK: call void (i8*, ...) %{{[^(]+}}(i8* %{{.+}}, i8*** [[TD1_REF:%[^,]+]], i8*** [[TD2_REF:%[^,]+]])
+// CHECK-NEXT: [[TD1_ADDR:%.+]] = load i8**, i8*** [[TD1_REF]],
+// CHECK-NEXT: [[TD2_ADDR:%.+]] = load i8**, i8*** [[TD2_REF]],
+// CHECK-NEXT: [[A_REF:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[A_ADDR:%.+]] = load i32*, i32** [[A_REF]],
+// CHECK-NEXT: [[TD1:%.+]] = load i8*, i8** [[TD1_ADDR]],
+// CHECK-NEXT: [[GTID:%.+]] = load i32, i32* %
+// CHECK-NEXT: [[A_PTR:%.+]] = bitcast i32* [[A_ADDR]] to i8*
+// CHECK-NEXT: call i8* @__kmpc_task_reduction_get_th_data(i32 [[GTID]], i8* [[TD1]], i8* [[A_PTR]])
+// CHECK: [[D_REF:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[D_ADDR:%.+]] = load i16*, i16** [[D_REF]],
+// CHECK: [[TD2:%.+]] = load i8*, i8** [[TD2_ADDR]],
+// CHECK-NEXT: [[D_PTR:%.+]] = bitcast i16* [[D_ADDR]] to i8*
+// CHECK-NEXT: call i8* @__kmpc_task_reduction_get_th_data(i32 [[GTID]], i8* [[TD2]], i8* [[D_PTR]])
+// CHECK: add nsw i32
+// CHECK: store i32 %
+#endif
diff --git a/test/OpenMP/taskloop_in_reduction_messages.cpp b/test/OpenMP/taskloop_in_reduction_messages.cpp
new file mode 100644
index 0000000000..409975565a
--- /dev/null
+++ b/test/OpenMP/taskloop_in_reduction_messages.cpp
@@ -0,0 +1,376 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+void foobar(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref)
+#pragma omp taskloop in_reduction(+:ref)
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+void foobar1(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref)
+#pragma omp taskloop in_reduction(-:ref)
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+#pragma omp declare reduction (red:int:omp_out += omp_in)
+
+void foobar2(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref) // expected-note {{previously marked as task_reduction with different reduction operation}}
+#pragma omp taskloop in_reduction(red:ref) // expected-error{{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+void foobar3(int &ref) {
+#pragma omp taskgroup task_reduction(red:ref) // expected-note {{previously marked as task_reduction with different reduction operation}}
+#pragma omp taskloop in_reduction(min:ref) // expected-error{{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+void foobar4(int &ref) {
+#pragma omp taskloop in_reduction(min:ref) // expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}}
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
+};
+const float S2::S2sc = 0;
+S2 b; // expected-note 3 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ int b;
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+(const S3 &arg1) { return arg1; }
+};
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 3 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+ S4(const S4 &s4);
+ S4 &operator+(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o;
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) {
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i];
+ T fl;
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop in_reduction // expected-error {{expected '(' after 'in_reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop in_reduction + // expected-error {{expected '(' after 'in_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop in_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop in_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop in_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop in_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop in_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(&:argc) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+#pragma omp taskloop in_reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(|:argc) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+#pragma omp taskloop in_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(&&:argc)
+#pragma omp taskloop in_reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:c)
+#pragma omp taskloop in_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}} expected-error 2 {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'in_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:k)
+#pragma omp taskloop in_reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(+ : o) // expected-error 2 {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:p)
+#pragma omp taskloop in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'in_reduction' clause}} expected-note 2 {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop in_reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:fl)
+{
+#pragma omp taskloop in_reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(*:fl) // expected-note 2 {{previously marked as task_reduction with different reduction operation}}
+{
+#pragma omp taskloop in_reduction(+ : fl) // expected-error 2 {{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+}
+#pragma omp parallel
+#pragma omp for reduction(- : fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp taskloop in_reduction(+ : fl)
+ for (int j = 0; j < 10; ++j)
+ foo();
+
+ return T();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i];
+ float fl;
+#pragma omp taskloop in_reduction // expected-error {{expected '(' after 'in_reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction + // expected-error {{expected '(' after 'in_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(|:argc)
+#pragma omp taskloop in_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(&&:argc)
+#pragma omp taskloop in_reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:c)
+#pragma omp taskloop in_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'in_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{nvalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:k)
+#pragma omp taskloop in_reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(+ : o) // expected-error {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:p)
+#pragma omp taskloop in_reduction(+ : p), in_reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'in_reduction' clause}} expected-note {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop in_reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop in_reduction(max : j) // expected-error {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for private(fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp taskloop in_reduction(+ : fl)
+ for (int j = 0; j < 10; ++j)
+ foo();
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp taskloop in_reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ static int m;
+#pragma omp taskgroup task_reduction(+:m)
+#pragma omp taskloop in_reduction(+ : m) // OK
+ for (int i = 0; i < 10; ++i)
+ m++;
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/taskloop_lastprivate_codegen.cpp b/test/OpenMP/taskloop_lastprivate_codegen.cpp
index e689feba20..837977eb57 100644
--- a/test/OpenMP/taskloop_lastprivate_codegen.cpp
+++ b/test/OpenMP/taskloop_lastprivate_codegen.cpp
@@ -23,7 +23,7 @@ struct S {
volatile double g;
-// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32 }
+// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32, i8* }
// CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double }
// CHECK-DAG: [[PRIVATES_MAIN_TY:%.+]] = type {{.?}}{ [2 x [[S_DOUBLE_TY]]], [[S_DOUBLE_TY]], i32, [2 x i32]
// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i32]*, i32*, [2 x [[S_DOUBLE_TY]]]*, [[S_DOUBLE_TY]]*, i{{[0-9]+}}* }
@@ -57,7 +57,7 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
- // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// LAMBDA: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// LAMBDA: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* bitcast (void ([[KMP_TASK_MAIN_TY:%[^*]+]]*, [[KMP_TASK_MAIN_TY]]*, i32)* [[MAIN_DUP:@.+]] to i8*))
@@ -98,7 +98,7 @@ int main() {
// BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
- // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// BLOCKS: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// BLOCKS: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* bitcast (void ([[KMP_TASK_MAIN_TY:%[^*]+]]*, [[KMP_TASK_MAIN_TY]]*, i32)* [[MAIN_DUP:@.+]] to i8*))
// BLOCKS: ret
@@ -182,7 +182,7 @@ int main() {
// [[KMP_TASK_T]] task_data;
// [[KMP_TASK_MAIN_TY]] privates;
// };
-// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 112, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 120, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_MAIN_TY]]*
// Fill kmp_task_t->shareds by copying from original capture argument.
diff --git a/test/OpenMP/taskloop_lastprivate_messages.cpp b/test/OpenMP/taskloop_lastprivate_messages.cpp
index e436444815..1d238ea083 100644
--- a/test/OpenMP/taskloop_lastprivate_messages.cpp
+++ b/test/OpenMP/taskloop_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/taskloop_loop_messages.cpp b/test/OpenMP/taskloop_loop_messages.cpp
index 291cbdbe71..edfc2a8dcd 100644
--- a/test/OpenMP/taskloop_loop_messages.cpp
+++ b/test/OpenMP/taskloop_loop_messages.cpp
@@ -644,7 +644,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/taskloop_private_codegen.cpp b/test/OpenMP/taskloop_private_codegen.cpp
index dad9a17767..6ca7c402a1 100644
--- a/test/OpenMP/taskloop_private_codegen.cpp
+++ b/test/OpenMP/taskloop_private_codegen.cpp
@@ -23,7 +23,7 @@ struct S {
volatile double g;
-// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32 }
+// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32, i8* }
// CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double }
// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { i8 }
// CHECK-DAG: [[PRIVATES_MAIN_TY:%.+]] = type {{.?}}{ [2 x [[S_DOUBLE_TY]]], [[S_DOUBLE_TY]], i32, [2 x i32]
@@ -55,7 +55,7 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
- // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// LAMBDA: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// LAMBDA: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* null)
// LAMBDA: ret
@@ -91,7 +91,7 @@ int main() {
// BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
- // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// BLOCKS: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// BLOCKS: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* null)
// BLOCKS: ret
@@ -157,7 +157,7 @@ int main() {
// [[KMP_TASK_T_TY]] task_data;
// [[KMP_TASK_MAIN_TY]] privates;
// };
-// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 112, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 120, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_MAIN_TY]]*
// CHECK: [[TASK:%.+]] = getelementptr inbounds [[KMP_TASK_MAIN_TY]], [[KMP_TASK_MAIN_TY]]* [[RES_KMP_TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
diff --git a/test/OpenMP/taskloop_reduction_codegen.cpp b/test/OpenMP/taskloop_reduction_codegen.cpp
new file mode 100644
index 0000000000..10cbf97163
--- /dev/null
+++ b/test/OpenMP/taskloop_reduction_codegen.cpp
@@ -0,0 +1,198 @@
+// RUN: %clang_cc1 -fopenmp -x c++ %s -verify -debug-info-kind=limited -emit-llvm -o - -triple powerpc64le-unknown-linux-gnu | FileCheck %s
+// expected-no-diagnostics
+
+struct S {
+ float a;
+ S() : a(0.0f) {}
+ ~S() {}
+};
+
+#pragma omp declare reduction(+:S:omp_out.a += omp_in.a) initializer(omp_priv = omp_orig)
+
+float g;
+
+int a;
+#pragma omp threadprivate(a)
+int main (int argc, char *argv[])
+{
+int i, n;
+float a[100], b[100], sum, e[argc + 100];
+S c[100];
+float &d = g;
+
+/* Some initializations */
+n = 100;
+for (i=0; i < n; i++)
+ a[i] = b[i] = i * 1.0;
+sum = 0.0;
+
+#pragma omp taskloop reduction(+:sum, c[:n], d, e)
+ for (i=0; i < n; i++) {
+ sum = sum + (a[i] * b[i]);
+ c[i].a = i*i;
+ d += i*i;
+ e[i] = i;
+ }
+
+}
+
+// CHECK-LABEL: @main(
+// CHECK: [[RETVAL:%.*]] = alloca i32,
+// CHECK: [[ARGC_ADDR:%.*]] = alloca i32,
+// CHECK: [[ARGV_ADDR:%.*]] = alloca i8**,
+// CHECK: [[I:%.*]] = alloca i32,
+// CHECK: [[N:%.*]] = alloca i32,
+// CHECK: [[A:%.*]] = alloca [100 x float],
+// CHECK: [[B:%.*]] = alloca [100 x float],
+// CHECK: [[SUM:%.*]] = alloca float,
+// CHECK: [[SAVED_STACK:%.*]] = alloca i8*,
+// CHECK: [[C:%.*]] = alloca [100 x %struct.S],
+// CHECK: [[D:%.*]] = alloca float*,
+// CHECK: [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON:%.*]],
+// CHECK: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%ident_t*
+// CHECK: [[DOTRD_INPUT_:%.*]] = alloca [4 x %struct.kmp_task_red_input_t],
+// CHECK: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32,
+// CHECK: [[DOTCAPTURE_EXPR_9:%.*]] = alloca i32,
+// CHECK: store i32 0, i32* [[RETVAL]],
+// CHECK: store i32 [[ARGC:%.*]], i32* [[ARGC_ADDR]],
+// CHECK: store i8** [[ARGV:%.*]], i8*** [[ARGV_ADDR]],
+// CHECK: [[TMP1:%.*]] = load i32, i32* [[ARGC_ADDR]],
+// CHECK: [[ADD:%.*]] = add nsw i32 [[TMP1]], 100
+// CHECK: [[TMP2:%.*]] = zext i32 [[ADD]] to i64
+// CHECK: [[VLA:%.+]] = alloca float, i64 %
+
+// CHECK: call void @__kmpc_taskgroup(%ident_t*
+// CHECK-DAG: [[TMP21:%.*]] = bitcast float* [[SUM]] to i8*
+// CHECK-DAG: store i8* [[TMP21]], i8** [[TMP20:%[^,]+]],
+// CHECK-DAG: [[TMP20]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T:%.+]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 1
+// CHECK-DAG: store i64 4, i64* [[TMP22]],
+// CHECK-DAG: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT1:@.+]] to i8*), i8** [[TMP23]],
+// CHECK-DAG: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP24]],
+// CHECK-DAG: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB1:@.+]] to i8*), i8** [[TMP25]],
+// CHECK-DAG: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 5
+// CHECK-DAG: [[TMP27:%.*]] = bitcast i32* [[TMP26]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP27]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[ARRAYIDX5:%.*]] = getelementptr inbounds [100 x %struct.S], [100 x %struct.S]* [[C]], i64 0, i64 0
+// CHECK-DAG: [[LB_ADD_LEN:%.*]] = add nsw i64 -1, %
+// CHECK-DAG: [[ARRAYIDX6:%.*]] = getelementptr inbounds [100 x %struct.S], [100 x %struct.S]* [[C]], i64 0, i64 [[LB_ADD_LEN]]
+// CHECK-DAG: [[TMP31:%.*]] = bitcast %struct.S* [[ARRAYIDX5]] to i8*
+// CHECK-DAG: store i8* [[TMP31]], i8** [[TMP28:%[^,]+]],
+// CHECK-DAG: [[TMP28]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP32:%.*]] = ptrtoint %struct.S* [[ARRAYIDX6]] to i64
+// CHECK-DAG: [[TMP33:%.*]] = ptrtoint %struct.S* [[ARRAYIDX5]] to i64
+// CHECK-DAG: [[TMP34:%.*]] = sub i64 [[TMP32]], [[TMP33]]
+// CHECK-DAG: [[TMP35:%.*]] = sdiv exact i64 [[TMP34]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK-DAG: [[TMP36:%.*]] = add nuw i64 [[TMP35]], 1
+// CHECK-DAG: [[TMP37:%.*]] = mul nuw i64 [[TMP36]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK-DAG: store i64 [[TMP37]], i64* [[TMP38:%[^,]+]],
+// CHECK-DAG: [[TMP38]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 1
+// CHECK-DAG: [[TMP39:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT2:@.+]] to i8*), i8** [[TMP39]],
+// CHECK-DAG: [[TMP40:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 3
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_FINI2:@.+]] to i8*), i8** [[TMP40]],
+// CHECK-DAG: [[TMP41:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB2:@.+]] to i8*), i8** [[TMP41]],
+// CHECK-DAG: [[TMP42:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 5
+// CHECK-DAG: store i32 1, i32* [[TMP42]],
+// CHECK-DAG: [[TMP44:%.*]] = load float*, float** [[D]],
+// CHECK-DAG: [[TMP45:%.*]] = bitcast float* [[TMP44]] to i8*
+// CHECK-DAG: store i8* [[TMP45]], i8** [[TMP43:%[^,]+]],
+// CHECK-DAG: [[TMP43]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP46:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 1
+// CHECK-DAG: store i64 4, i64* [[TMP46]],
+// CHECK-DAG: [[TMP47:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT3:@.+]] to i8*), i8** [[TMP47]],
+// CHECK-DAG: [[TMP48:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP48]],
+// CHECK-DAG: [[TMP49:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB3:@.+]] to i8*), i8** [[TMP49]],
+// CHECK-DAG: [[TMP50:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 5
+// CHECK-DAG: [[TMP51:%.*]] = bitcast i32* [[TMP50]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP51]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[TMP53:%.*]] = bitcast float* [[VLA]] to i8*
+// CHECK-DAG: store i8* [[TMP53]], i8** [[TMP52:%[^,]+]],
+// CHECK-DAG: [[TMP52]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP54:%.*]] = mul nuw i64 [[TMP2]], 4
+// CHECK-DAG: [[TMP55:%.*]] = udiv exact i64 [[TMP54]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK-DAG: store i64 [[TMP54]], i64* [[TMP56:%[^,]+]],
+// CHECK-DAG: [[TMP56]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 1
+// CHECK-DAG: [[TMP57:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT4:@.+]] to i8*), i8** [[TMP57]],
+// CHECK-DAG: [[TMP58:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP58]],
+// CHECK-DAG: [[TMP59:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB4:@.+]] to i8*), i8** [[TMP59]],
+// CHECK-DAG: [[TMP60:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 5
+// CHECK-DAG: store i32 1, i32* [[TMP60]],
+// CHECK-DAG: [[DOTRD_INPUT_GEP_]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK-DAG: [[DOTRD_INPUT_GEP_4]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK-DAG: [[DOTRD_INPUT_GEP_7]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK-DAG: [[DOTRD_INPUT_GEP_8]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK: [[TMP61:%.*]] = bitcast [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]] to i8*
+// CHECK: [[TMP62:%.*]] = call i8* @__kmpc_task_reduction_init(i32 [[TMP0]], i32 4, i8* [[TMP61]])
+// CHECK: [[TMP63:%.*]] = load i32, i32* [[N]],
+// CHECK: store i32 [[TMP63]], i32* [[DOTCAPTURE_EXPR_]],
+// CHECK: [[TMP64:%.*]] = load i32, i32* [[DOTCAPTURE_EXPR_]],
+// CHECK: [[SUB:%.*]] = sub nsw i32 [[TMP64]], 0
+// CHECK: [[SUB10:%.*]] = sub nsw i32 [[SUB]], 1
+// CHECK: [[ADD11:%.*]] = add nsw i32 [[SUB10]], 1
+// CHECK: [[DIV:%.*]] = sdiv i32 [[ADD11]], 1
+// CHECK: [[SUB12:%.*]] = sub nsw i32 [[DIV]], 1
+// CHECK: store i32 [[SUB12]], i32* [[DOTCAPTURE_EXPR_9]],
+// CHECK: [[TMP65:%.*]] = call i8* @__kmpc_omp_task_alloc(%ident_t* %{{.+}}, i32 [[TMP0]], i32 1, i64 888, i64 72, i32 (i32, i8*)* bitcast (i32 (i32, %struct.kmp_task_t_with_privates*)* @[[TASK:.+]] to i32 (i32, i8*)*))
+// CHECK: call void @__kmpc_taskloop(%ident_t* %{{.+}}, i32 [[TMP0]], i8* [[TMP65]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* null)
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t*
+
+// CHECK: ret i32
+
+// CHECK: define internal void [[RED_INIT1]](i8*)
+// CHECK: store float 0.000000e+00, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB1]](i8*, i8*)
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_INIT2]](i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_FINI2]](i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: call void @
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB2]](i8*, i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_INIT3]](i8*)
+// CHECK: store float 0.000000e+00, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB3]](i8*, i8*)
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_INIT4]](i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: store float 0.000000e+00, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB4]](i8*, i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
+// CHECK: distinct !DISubprogram(linkageName: "[[TASK]]", scope: !
diff --git a/test/OpenMP/taskloop_reduction_messages.cpp b/test/OpenMP/taskloop_reduction_messages.cpp
new file mode 100644
index 0000000000..23f70b5685
--- /dev/null
+++ b/test/OpenMP/taskloop_reduction_messages.cpp
@@ -0,0 +1,331 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+void foobar(int &ref) {
+#pragma omp taskloop reduction(+:ref)
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}}
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
+};
+const float S2::S2sc = 0;
+S2 b; // expected-note 3 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ int b;
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+(const S3 &arg1) { return arg1; }
+};
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 3 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+ S4(const S4 &s4);
+ S4 &operator+(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a:32;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o;
+
+struct S7 {
+ int a: 32;
+ S7() {
+#pragma omp taskloop reduction(+:a) // expected-error {{expected addressable reduction item for the task-based directives}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+};
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) {
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 4 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
+ T fl;
+#pragma omp taskloop reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : o) // expected-error 2 {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 2 {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl)
+#pragma omp taskloop reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl)
+#pragma omp taskloop reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return T();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i]; // expected-note {{'q' defined here}}
+ float fl;
+#pragma omp taskloop reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : o) // expected-error {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl)
+#pragma omp taskloop reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl)
+#pragma omp taskloop reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ static int m;
+#pragma omp taskloop reduction(+ : m) // OK
+ for (int i = 0; i < 10; ++i)
+ m++;
+#pragma omp taskloop nogroup reduction(+ : m) // expected-error {{'reduction' clause cannot be used with 'nogroup' clause}}
+ for (int i = 0; i < 10; ++i)
+ m++;
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/taskloop_simd_aligned_messages.cpp b/test/OpenMP/taskloop_simd_aligned_messages.cpp
index 6085660b70..c4c41ebbaf 100644
--- a/test/OpenMP/taskloop_simd_aligned_messages.cpp
+++ b/test/OpenMP/taskloop_simd_aligned_messages.cpp
@@ -107,9 +107,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp taskloop simd aligned // expected-error {{expected '(' after 'aligned'}}
for (I k = 0; k < argc; ++k) ++k;
diff --git a/test/OpenMP/taskloop_simd_ast_print.cpp b/test/OpenMP/taskloop_simd_ast_print.cpp
index f16b470a30..6f13c7e0ba 100644
--- a/test/OpenMP/taskloop_simd_ast_print.cpp
+++ b/test/OpenMP/taskloop_simd_ast_print.cpp
@@ -14,8 +14,10 @@ T tmain(T argc) {
T *ptr;
static T a;
// CHECK: static T a;
-#pragma omp taskloop simd if(taskloop: argc > N) default(shared) untied priority(N) safelen(N) linear(c) aligned(ptr) grainsize(N)
- // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: argc > N) default(shared) untied priority(N) safelen(N) linear(c) aligned(ptr) grainsize(N)
+#pragma omp taskgroup task_reduction(+: d)
+#pragma omp taskloop simd if(taskloop: argc > N) default(shared) untied priority(N) safelen(N) linear(c) aligned(ptr) grainsize(N) reduction(+:g) in_reduction(+: d)
+ // CHECK-NEXT: #pragma omp taskgroup task_reduction(+: d)
+ // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: argc > N) default(shared) untied priority(N) safelen(N) linear(c) aligned(ptr) grainsize(N) reduction(+: g) in_reduction(+: d)
for (int i = 0; i < 2; ++i)
a = 2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
@@ -54,19 +56,21 @@ int main(int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
// CHECK: static int a;
-#pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b), aligned(argv) nogroup num_tasks(argc)
- // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b) aligned(argv) nogroup num_tasks(argc)
+#pragma omp taskgroup task_reduction(+: d)
+#pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b), aligned(argv) num_tasks(argc) reduction(*: g) in_reduction(+: d)
+ // CHECK-NEXT: #pragma omp taskgroup task_reduction(+: d)
+ // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b) aligned(argv) num_tasks(argc) reduction(*: g) in_reduction(+: d)
for (int i = 0; i < 2; ++i)
a = 2;
// CHECK-NEXT: for (int i = 0; i < 2; ++i)
// CHECK-NEXT: a = 2;
#pragma omp parallel
-#pragma omp taskloop simd private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) shared(g) if(argc) mergeable priority(argc) simdlen(16) grainsize(argc)
+#pragma omp taskloop simd private(argc, b), firstprivate(argv, c), lastprivate(d, f) collapse(2) shared(g) if(argc) mergeable priority(argc) simdlen(16) grainsize(argc) reduction(max: a, e)
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
foo();
// CHECK-NEXT: #pragma omp parallel
- // CHECK-NEXT: #pragma omp taskloop simd private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) shared(g) if(argc) mergeable priority(argc) simdlen(16) grainsize(argc)
+ // CHECK-NEXT: #pragma omp taskloop simd private(argc,b) firstprivate(argv,c) lastprivate(d,f) collapse(2) shared(g) if(argc) mergeable priority(argc) simdlen(16) grainsize(argc) reduction(max: a,e)
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: for (int j = 0; j < 10; ++j)
// CHECK-NEXT: foo();
diff --git a/test/OpenMP/taskloop_simd_codegen.cpp b/test/OpenMP/taskloop_simd_codegen.cpp
index 60ba5f2212..f787689688 100644
--- a/test/OpenMP/taskloop_simd_codegen.cpp
+++ b/test/OpenMP/taskloop_simd_codegen.cpp
@@ -8,7 +8,8 @@
// CHECK-LABEL: @main
int main(int argc, char **argv) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* [[DEFLOC:@.+]])
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 33, i64 72, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK1:@.+]] to i32 (i32, i8*)*))
+// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 33, i64 80, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK1:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[DOWN:%.+]] = getelementptr inbounds [[TD_TY:%.+]], [[TD_TY]]* [[TASK_DATA]], i32 0, i32 5
@@ -19,10 +20,11 @@ int main(int argc, char **argv) {
// CHECK: store i64 1, i64* [[ST]],
// CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]],
// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 0, i64 0, i8* null)
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
#pragma omp taskloop simd priority(argc)
for (int i = 0; i < 10; ++i)
;
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK2:@.+]] to i32 (i32, i8*)*))
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 80, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK2:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[DOWN:%.+]] = getelementptr inbounds [[TD_TY:%.+]], [[TD_TY]]* [[TASK_DATA]], i32 0, i32 5
@@ -33,11 +35,12 @@ int main(int argc, char **argv) {
// CHECK: store i64 1, i64* [[ST]],
// CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]],
// CHECK: [[GRAINSIZE:%.+]] = zext i32 %{{.+}} to i64
-// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 1, i32 1, i64 [[GRAINSIZE]], i8* null)
+// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 1, i64 [[GRAINSIZE]], i8* null)
#pragma omp taskloop simd nogroup grainsize(argc) simdlen(4)
for (int i = 0; i < 10; ++i)
;
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 24, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK3:@.+]] to i32 (i32, i8*)*))
+// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 80, i64 24, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK3:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[IF:%.+]] = icmp ne i32 %{{.+}}, 0
@@ -50,6 +53,7 @@ int main(int argc, char **argv) {
// CHECK: store i64 1, i64* [[ST]],
// CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]],
// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 [[IF_INT]], i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 2, i64 4, i8* null)
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]])
int i;
#pragma omp taskloop simd if(argc) shared(argc, argv) collapse(2) num_tasks(4) safelen(32)
for (i = 0; i < argc; ++i)
@@ -142,7 +146,7 @@ struct S {
int a;
S(int c) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* [[DEFLOC:@.+]])
-// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK4:@.+]] to i32 (i32, i8*)*))
+// CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 80, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK4:@.+]] to i32 (i32, i8*)*))
// CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]*
// CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0
// CHECK: [[DOWN:%.+]] = getelementptr inbounds [[TD_TY:%.+]], [[TD_TY]]* [[TASK_DATA]], i32 0, i32 5
diff --git a/test/OpenMP/taskloop_simd_firstprivate_codegen.cpp b/test/OpenMP/taskloop_simd_firstprivate_codegen.cpp
index 230ef980e6..9e268d8a17 100644
--- a/test/OpenMP/taskloop_simd_firstprivate_codegen.cpp
+++ b/test/OpenMP/taskloop_simd_firstprivate_codegen.cpp
@@ -23,7 +23,7 @@ struct S {
volatile double g;
-// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32 }
+// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32, i8* }
// CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double }
// CHECK-DAG: [[PRIVATES_MAIN_TY:%.+]] = type {{.?}}{ [2 x [[S_DOUBLE_TY]]], [[S_DOUBLE_TY]], i32, [2 x i32]
// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type {{.*}}{ [2 x i32]*, i32, {{.*}}[2 x [[S_DOUBLE_TY]]]*, [[S_DOUBLE_TY]]*, i{{[0-9]+}}
@@ -57,7 +57,7 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
- // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// LAMBDA: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0
// LAMBDA: [[G_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 0
@@ -101,7 +101,7 @@ int main() {
// BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
- // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// BLOCKS: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// BLOCKS: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0
// BLOCKS: [[G_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 0
@@ -190,7 +190,7 @@ int main() {
// [[KMP_TASK_T]] task_data;
// [[KMP_TASK_MAIN_TY]] privates;
// };
-// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 112, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 120, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_MAIN_TY]]*
// Fill kmp_task_t->shareds by copying from original capture argument.
diff --git a/test/OpenMP/taskloop_simd_firstprivate_messages.cpp b/test/OpenMP/taskloop_simd_firstprivate_messages.cpp
index 18cefc1bee..176dcd7f8f 100644
--- a/test/OpenMP/taskloop_simd_firstprivate_messages.cpp
+++ b/test/OpenMP/taskloop_simd_firstprivate_messages.cpp
@@ -295,9 +295,9 @@ int main(int argc, char **argv) {
#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}}
for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}}
foo();
-#pragma omp parallel reduction(+ : i) // expected-note 4 {{defined as reduction}}
+#pragma omp parallel reduction(+ : i) // expected-note 2 {{defined as reduction}}
#pragma omp taskloop simd firstprivate(i) // expected-error {{argument of a reduction clause of a parallel construct must not appear in a firstprivate clause on a task construct}}
- for (i = 0; i < argc; ++i) // expected-error 3 {{reduction variables may not be accessed in an explicit task}}
+ for (i = 0; i < argc; ++i) // expected-error {{reduction variables may not be accessed in an explicit task}}
foo();
#pragma omp parallel
#pragma omp taskloop simd firstprivate(B::x) // expected-error {{threadprivate or thread local variable cannot be firstprivate}}
diff --git a/test/OpenMP/taskloop_simd_in_reduction_codegen.cpp b/test/OpenMP/taskloop_simd_in_reduction_codegen.cpp
new file mode 100644
index 0000000000..d894943cc3
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_in_reduction_codegen.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c++ -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// CHECK: [[PRIVATES:%.+]] = type { i8*, i8* }
+
+struct S {
+ int a;
+ S() : a(0) {}
+ S(const S&) {}
+ S& operator=(const S&) {return *this;}
+ ~S() {}
+ friend S operator+(const S&a, const S&b) {return a;}
+};
+
+
+int main(int argc, char **argv) {
+ int a;
+ float b;
+ S c[5];
+ short d[argc];
+#pragma omp taskgroup task_reduction(+: a, b, argc)
+ {
+#pragma omp taskgroup task_reduction(-:c, d)
+#pragma omp parallel
+#pragma omp taskloop simd in_reduction(+:a) in_reduction(-:d)
+ for (int i = 0; i < 5; ++i)
+ a += d[a];
+ }
+ return 0;
+}
+
+// CHECK-LABEL: @main
+// CHECK: void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID:%.+]])
+// CHECK: [[TD1:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 3, i8* %
+// CHECK-NEXT: store i8* [[TD1]], i8** [[TD1_ADDR:%[^,]+]],
+// CHECK-NEXT: call void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID]])
+// CHECK: [[TD2:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 2, i8* %
+// CHECK-NEXT: store i8* [[TD2]], i8** [[TD2_ADDR:%[^,]+]],
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* @0, i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i16*, i8**, i8**)* [[OMP_PARALLEL:@.+]] to void (i32*, i32*, ...)*), i32* %{{.+}}, i64 %{{.+}}, i16* %{{.+}}, i8** [[TD1_ADDR]], i8** [[TD2_ADDR]])
+// CHECK-NEXT: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]])
+// CHECK-NEXT: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]])
+
+// CHECK: define internal void [[OMP_PARALLEL]](
+// CHECK: [[TASK_T:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* @0, i32 [[GTID:%.+]], i32 1, i64 96, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[T:%.+]]*)* [[OMP_TASK:@.+]] to i32 (i32, i8*)*))
+// CHECK-NEXT: [[TASK_T_WITH_PRIVS:%.+]] = bitcast i8* [[TASK_T]] to [[T]]*
+// CHECK: [[PRIVS:%.+]] = getelementptr inbounds [[T]], [[T]]* [[TASK_T_WITH_PRIVS]], i32 0, i32 1
+// CHECK: [[TD1_REF:%.+]] = getelementptr inbounds [[PRIVATES]], [[PRIVATES]]* [[PRIVS]], i32 0, i32 0
+// CHECK-NEXT: [[TD1_SHAR:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[TD1_ADDR:%.+]] = load i8**, i8*** [[TD1_SHAR]],
+// CHECK-NEXT: [[TD1:%.+]] = load i8*, i8** [[TD1_ADDR]],
+// CHECK-NEXT: store i8* [[TD1]], i8** [[TD1_REF]],
+// CHECK-NEXT: [[TD2_REF:%.+]] = getelementptr inbounds [[PRIVATES]], [[PRIVATES]]* [[PRIVS]], i32 0, i32 1
+// CHECK-NEXT: [[TD2_SHAR:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[TD2_ADDR:%.+]] = load i8**, i8*** [[TD2_SHAR]],
+// CHECK-NEXT: [[TD2:%.+]] = load i8*, i8** [[TD2_ADDR]],
+// CHECK-NEXT: store i8* [[TD2]], i8** [[TD2_REF]],
+// CHECK: call void @__kmpc_taskloop(%ident_t* @0, i32 [[GTID]], i8* [[TASK_T]], i32 1,
+// CHECK: ret void
+// CHECK-NEXT: }
+
+// CHECK: define internal {{.*}} [[OMP_TASK]](
+// CHECK: call void (i8*, ...) %{{[^(]+}}(i8* %{{.+}}, i8*** [[TD1_REF:%[^,]+]], i8*** [[TD2_REF:%[^,]+]])
+// CHECK-NEXT: [[TD1_ADDR:%.+]] = load i8**, i8*** [[TD1_REF]],
+// CHECK-NEXT: [[TD2_ADDR:%.+]] = load i8**, i8*** [[TD2_REF]],
+// CHECK-NEXT: [[A_REF:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[A_ADDR:%.+]] = load i32*, i32** [[A_REF]],
+// CHECK-NEXT: [[TD1:%.+]] = load i8*, i8** [[TD1_ADDR]],
+// CHECK-NEXT: [[GTID:%.+]] = load i32, i32* %
+// CHECK-NEXT: [[A_PTR:%.+]] = bitcast i32* [[A_ADDR]] to i8*
+// CHECK-NEXT: call i8* @__kmpc_task_reduction_get_th_data(i32 [[GTID]], i8* [[TD1]], i8* [[A_PTR]])
+// CHECK: [[D_REF:%.+]] = getelementptr inbounds %
+// CHECK-NEXT: [[D_ADDR:%.+]] = load i16*, i16** [[D_REF]],
+// CHECK: [[TD2:%.+]] = load i8*, i8** [[TD2_ADDR]],
+// CHECK-NEXT: [[D_PTR:%.+]] = bitcast i16* [[D_ADDR]] to i8*
+// CHECK-NEXT: call i8* @__kmpc_task_reduction_get_th_data(i32 [[GTID]], i8* [[TD2]], i8* [[D_PTR]])
+// CHECK: add nsw i32
+// CHECK: store i32 %
+#endif
diff --git a/test/OpenMP/taskloop_simd_in_reduction_messages.cpp b/test/OpenMP/taskloop_simd_in_reduction_messages.cpp
new file mode 100644
index 0000000000..f3b1a855e3
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_in_reduction_messages.cpp
@@ -0,0 +1,376 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+void foobar(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref)
+#pragma omp taskloop simd in_reduction(+:ref)
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+void foobar1(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref)
+#pragma omp taskloop simd in_reduction(-:ref)
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+#pragma omp declare reduction (red:int:omp_out += omp_in)
+
+void foobar2(int &ref) {
+#pragma omp taskgroup task_reduction(+:ref) // expected-note {{previously marked as task_reduction with different reduction operation}}
+#pragma omp taskloop simd in_reduction(red:ref) // expected-error{{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+void foobar3(int &ref) {
+#pragma omp taskgroup task_reduction(red:ref) // expected-note {{previously marked as task_reduction with different reduction operation}}
+#pragma omp taskloop simd in_reduction(min:ref) // expected-error{{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+void foobar4(int &ref) {
+#pragma omp taskloop simd in_reduction(min:ref) // expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}}
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
+};
+const float S2::S2sc = 0;
+S2 b; // expected-note 3 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ int b;
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+(const S3 &arg1) { return arg1; }
+};
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 3 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+ S4(const S4 &s4);
+ S4 &operator+(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o;
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) {
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i];
+ T fl;
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop simd in_reduction // expected-error {{expected '(' after 'in_reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop simd in_reduction + // expected-error {{expected '(' after 'in_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop simd in_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop simd in_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop simd in_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop simd in_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:argc)
+#pragma omp taskloop simd in_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(&:argc) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+#pragma omp taskloop simd in_reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(|:argc) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+#pragma omp taskloop simd in_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(&&:argc)
+#pragma omp taskloop simd in_reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:c)
+#pragma omp taskloop simd in_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}} expected-error 2 {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'in_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:k)
+#pragma omp taskloop simd in_reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(+ : o) // expected-error 2 {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop simd in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:p)
+#pragma omp taskloop simd in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'in_reduction' clause}} expected-note 2 {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop simd in_reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:fl)
+{
+#pragma omp taskloop simd in_reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(*:fl) // expected-note 2 {{previously marked as task_reduction with different reduction operation}}
+{
+#pragma omp taskloop simd in_reduction(+ : fl) // expected-error 2 {{in_reduction variable must have the same reduction operation as in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+}
+#pragma omp parallel
+#pragma omp for reduction(- : fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp taskloop simd in_reduction(+ : fl)
+ for (int j = 0; j < 10; ++j)
+ foo();
+
+ return T();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i];
+ float fl;
+#pragma omp taskloop simd in_reduction // expected-error {{expected '(' after 'in_reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction + // expected-error {{expected '(' after 'in_reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(|:argc)
+#pragma omp taskloop simd in_reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(&&:argc)
+#pragma omp taskloop simd in_reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:c)
+#pragma omp taskloop simd in_reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} expected-error {{in_reduction variable must appear in a task_reduction clause}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'in_reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{nvalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:k)
+#pragma omp taskloop simd in_reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(+ : o) // expected-error {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop simd in_reduction(+ : p), in_reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskgroup task_reduction(+:p)
+#pragma omp taskloop simd in_reduction(+ : p), in_reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'in_reduction' clause}} expected-note {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd in_reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop simd in_reduction(max : j) // expected-error {{argument of OpenMP clause 'in_reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel
+#pragma omp for private(fl)
+ for (int i = 0; i < 10; ++i)
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp taskloop simd in_reduction(+ : fl)
+ for (int j = 0; j < 10; ++j)
+ foo();
+#pragma omp taskgroup task_reduction(+:fl)
+#pragma omp taskloop simd in_reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ static int m;
+#pragma omp taskgroup task_reduction(+:m)
+#pragma omp taskloop simd in_reduction(+ : m) // OK
+ for (int i = 0; i < 10; ++i)
+ m++;
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/taskloop_simd_lastprivate_codegen.cpp b/test/OpenMP/taskloop_simd_lastprivate_codegen.cpp
index 41f04f9bdb..8d5ebb2168 100644
--- a/test/OpenMP/taskloop_simd_lastprivate_codegen.cpp
+++ b/test/OpenMP/taskloop_simd_lastprivate_codegen.cpp
@@ -23,7 +23,7 @@ struct S {
volatile double g;
-// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32 }
+// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32, i8* }
// CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double }
// CHECK-DAG: [[PRIVATES_MAIN_TY:%.+]] = type {{.?}}{ [2 x [[S_DOUBLE_TY]]], [[S_DOUBLE_TY]], i32, [2 x i32]
// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i32]*, i32*, [2 x [[S_DOUBLE_TY]]]*, [[S_DOUBLE_TY]]*, i{{[0-9]+}}* }
@@ -57,7 +57,7 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
- // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// LAMBDA: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// LAMBDA: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* bitcast (void ([[KMP_TASK_MAIN_TY:%[^*]+]]*, [[KMP_TASK_MAIN_TY]]*, i32)* [[MAIN_DUP:@.+]] to i8*))
@@ -98,7 +98,7 @@ int main() {
// BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
- // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 16, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// BLOCKS: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// BLOCKS: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* bitcast (void ([[KMP_TASK_MAIN_TY:%[^*]+]]*, [[KMP_TASK_MAIN_TY]]*, i32)* [[MAIN_DUP:@.+]] to i8*))
// BLOCKS: ret
@@ -182,7 +182,7 @@ int main() {
// [[KMP_TASK_T]] task_data;
// [[KMP_TASK_MAIN_TY]] privates;
// };
-// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 112, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 120, i64 40, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_MAIN_TY]]*
// Fill kmp_task_t->shareds by copying from original capture argument.
diff --git a/test/OpenMP/taskloop_simd_lastprivate_messages.cpp b/test/OpenMP/taskloop_simd_lastprivate_messages.cpp
index ed1bdf5a6e..e5cba6c64b 100644
--- a/test/OpenMP/taskloop_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/taskloop_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/taskloop_simd_loop_messages.cpp b/test/OpenMP/taskloop_simd_loop_messages.cpp
index 3326e6ff61..502224629a 100644
--- a/test/OpenMP/taskloop_simd_loop_messages.cpp
+++ b/test/OpenMP/taskloop_simd_loop_messages.cpp
@@ -645,7 +645,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/taskloop_simd_private_codegen.cpp b/test/OpenMP/taskloop_simd_private_codegen.cpp
index 493137ade6..3833b5ea9f 100644
--- a/test/OpenMP/taskloop_simd_private_codegen.cpp
+++ b/test/OpenMP/taskloop_simd_private_codegen.cpp
@@ -23,7 +23,7 @@ struct S {
volatile double g;
-// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32 }
+// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, %union{{.+}}, %union{{.+}}, i64, i64, i64, i32, i8* }
// CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double }
// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { i8 }
// CHECK-DAG: [[PRIVATES_MAIN_TY:%.+]] = type {{.?}}{ [2 x [[S_DOUBLE_TY]]], [[S_DOUBLE_TY]], i32, [2 x i32]
@@ -55,7 +55,7 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() {
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
- // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// LAMBDA: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// LAMBDA: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* null)
// LAMBDA: ret
@@ -91,7 +91,7 @@ int main() {
// BLOCKS: call void {{%.+}}(i8
^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
- // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 88, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+ // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 96, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// BLOCKS: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// BLOCKS: call void @__kmpc_taskloop(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* null)
// BLOCKS: ret
@@ -157,7 +157,7 @@ int main() {
// [[KMP_TASK_T_TY]] task_data;
// [[KMP_TASK_MAIN_TY]] privates;
// };
-// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 112, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
+// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 9, i64 120, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*))
// CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_MAIN_TY]]*
// CHECK: [[TASK:%.+]] = getelementptr inbounds [[KMP_TASK_MAIN_TY]], [[KMP_TASK_MAIN_TY]]* [[RES_KMP_TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
diff --git a/test/OpenMP/taskloop_simd_reduction_codegen.cpp b/test/OpenMP/taskloop_simd_reduction_codegen.cpp
new file mode 100644
index 0000000000..b96c8d50a3
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_reduction_codegen.cpp
@@ -0,0 +1,197 @@
+// RUN: %clang_cc1 -fopenmp -x c++ %s -verify -debug-info-kind=limited -emit-llvm -o - -triple powerpc64le-unknown-linux-gnu | FileCheck %s
+// expected-no-diagnostics
+
+struct S {
+ float a;
+ S() : a(0.0f) {}
+ ~S() {}
+};
+
+#pragma omp declare reduction(+:S:omp_out.a += omp_in.a) initializer(omp_priv = omp_orig)
+
+float g;
+
+int a;
+#pragma omp threadprivate(a)
+int main (int argc, char *argv[])
+{
+int i, n;
+float a[100], b[100], sum, e[argc + 100];
+S c[100];
+float &d = g;
+
+/* Some initializations */
+n = 100;
+for (i=0; i < n; i++)
+ a[i] = b[i] = i * 1.0;
+sum = 0.0;
+
+#pragma omp taskloop simd reduction(+:sum, c[:n], d, e)
+ for (i=0; i < n; i++) {
+ sum = sum + (a[i] * b[i]);
+ c[i].a = i*i;
+ d += i*i;
+ e[i] = i;
+ }
+
+}
+
+// CHECK-LABEL: @main(
+// CHECK: [[RETVAL:%.*]] = alloca i32,
+// CHECK: [[ARGC_ADDR:%.*]] = alloca i32,
+// CHECK: [[ARGV_ADDR:%.*]] = alloca i8**,
+// CHECK: [[I:%.*]] = alloca i32,
+// CHECK: [[N:%.*]] = alloca i32,
+// CHECK: [[A:%.*]] = alloca [100 x float],
+// CHECK: [[B:%.*]] = alloca [100 x float],
+// CHECK: [[SUM:%.*]] = alloca float,
+// CHECK: [[SAVED_STACK:%.*]] = alloca i8*,
+// CHECK: [[C:%.*]] = alloca [100 x %struct.S],
+// CHECK: [[D:%.*]] = alloca float*,
+// CHECK: [[AGG_CAPTURED:%.*]] = alloca [[STRUCT_ANON:%.*]],
+// CHECK: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%ident_t*
+// CHECK: [[DOTRD_INPUT_:%.*]] = alloca [4 x %struct.kmp_task_red_input_t],
+// CHECK: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32,
+// CHECK: [[DOTCAPTURE_EXPR_9:%.*]] = alloca i32,
+// CHECK: store i32 0, i32* [[RETVAL]],
+// CHECK: store i32 [[ARGC:%.*]], i32* [[ARGC_ADDR]],
+// CHECK: store i8** [[ARGV:%.*]], i8*** [[ARGV_ADDR]],
+// CHECK: [[TMP1:%.*]] = load i32, i32* [[ARGC_ADDR]],
+// CHECK: [[ADD:%.*]] = add nsw i32 [[TMP1]], 100
+// CHECK: [[TMP2:%.*]] = zext i32 [[ADD]] to i64
+// CHECK: [[VLA:%.+]] = alloca float, i64 %
+
+// CHECK: call void @__kmpc_taskgroup(%ident_t*
+// CHECK-DAG: [[TMP21:%.*]] = bitcast float* [[SUM]] to i8*
+// CHECK-DAG: store i8* [[TMP21]], i8** [[TMP20:%[^,]+]],
+// CHECK-DAG: [[TMP20]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T:%.+]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 1
+// CHECK-DAG: store i64 4, i64* [[TMP22]],
+// CHECK-DAG: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT1:@.+]] to i8*), i8** [[TMP23]],
+// CHECK-DAG: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP24]],
+// CHECK-DAG: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB1:@.+]] to i8*), i8** [[TMP25]],
+// CHECK-DAG: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_]], i32 0, i32 5
+// CHECK-DAG: [[TMP27:%.*]] = bitcast i32* [[TMP26]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP27]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[ARRAYIDX5:%.*]] = getelementptr inbounds [100 x %struct.S], [100 x %struct.S]* [[C]], i64 0, i64 0
+// CHECK-DAG: [[LB_ADD_LEN:%.*]] = add nsw i64 -1, %
+// CHECK-DAG: [[ARRAYIDX6:%.*]] = getelementptr inbounds [100 x %struct.S], [100 x %struct.S]* [[C]], i64 0, i64 [[LB_ADD_LEN]]
+// CHECK-DAG: [[TMP31:%.*]] = bitcast %struct.S* [[ARRAYIDX5]] to i8*
+// CHECK-DAG: store i8* [[TMP31]], i8** [[TMP28:%[^,]+]],
+// CHECK-DAG: [[TMP28]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP32:%.*]] = ptrtoint %struct.S* [[ARRAYIDX6]] to i64
+// CHECK-DAG: [[TMP33:%.*]] = ptrtoint %struct.S* [[ARRAYIDX5]] to i64
+// CHECK-DAG: [[TMP34:%.*]] = sub i64 [[TMP32]], [[TMP33]]
+// CHECK-DAG: [[TMP35:%.*]] = sdiv exact i64 [[TMP34]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK-DAG: [[TMP36:%.*]] = add nuw i64 [[TMP35]], 1
+// CHECK-DAG: [[TMP37:%.*]] = mul nuw i64 [[TMP36]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK-DAG: store i64 [[TMP37]], i64* [[TMP38:%[^,]+]],
+// CHECK-DAG: [[TMP38]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 1
+// CHECK-DAG: [[TMP39:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT2:@.+]] to i8*), i8** [[TMP39]],
+// CHECK-DAG: [[TMP40:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 3
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_FINI2:@.+]] to i8*), i8** [[TMP40]],
+// CHECK-DAG: [[TMP41:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB2:@.+]] to i8*), i8** [[TMP41]],
+// CHECK-DAG: [[TMP42:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_4]], i32 0, i32 5
+// CHECK-DAG: store i32 1, i32* [[TMP42]],
+// CHECK-DAG: [[TMP44:%.*]] = load float*, float** [[D]],
+// CHECK-DAG: [[TMP45:%.*]] = bitcast float* [[TMP44]] to i8*
+// CHECK-DAG: store i8* [[TMP45]], i8** [[TMP43:%[^,]+]],
+// CHECK-DAG: [[TMP43]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP46:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 1
+// CHECK-DAG: store i64 4, i64* [[TMP46]],
+// CHECK-DAG: [[TMP47:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT3:@.+]] to i8*), i8** [[TMP47]],
+// CHECK-DAG: [[TMP48:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP48]],
+// CHECK-DAG: [[TMP49:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB3:@.+]] to i8*), i8** [[TMP49]],
+// CHECK-DAG: [[TMP50:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_7]], i32 0, i32 5
+// CHECK-DAG: [[TMP51:%.*]] = bitcast i32* [[TMP50]] to i8*
+// CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP51]], i8 0, i64 4, i32 8, i1 false)
+// CHECK-DAG: [[TMP53:%.*]] = bitcast float* [[VLA]] to i8*
+// CHECK-DAG: store i8* [[TMP53]], i8** [[TMP52:%[^,]+]],
+// CHECK-DAG: [[TMP52]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8:%.+]], i32 0, i32 0
+// CHECK-DAG: [[TMP54:%.*]] = mul nuw i64 [[TMP2]], 4
+// CHECK-DAG: [[TMP55:%.*]] = udiv exact i64 [[TMP54]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64)
+// CHECK-DAG: store i64 [[TMP54]], i64* [[TMP56:%[^,]+]],
+// CHECK-DAG: [[TMP56]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 1
+// CHECK-DAG: [[TMP57:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 2
+// CHECK-DAG: store i8* bitcast (void (i8*)* [[RED_INIT4:@.+]] to i8*), i8** [[TMP57]],
+// CHECK-DAG: [[TMP58:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 3
+// CHECK-DAG: store i8* null, i8** [[TMP58]],
+// CHECK-DAG: [[TMP59:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 4
+// CHECK-DAG: store i8* bitcast (void (i8*, i8*)* [[RED_COMB4:@.+]] to i8*), i8** [[TMP59]],
+// CHECK-DAG: [[TMP60:%.*]] = getelementptr inbounds [[STRUCT_KMP_TASK_RED_INPUT_T]], %struct.kmp_task_red_input_t* [[DOTRD_INPUT_GEP_8]], i32 0, i32 5
+// CHECK-DAG: store i32 1, i32* [[TMP60]],
+// CHECK-DAG: [[DOTRD_INPUT_GEP_]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK-DAG: [[DOTRD_INPUT_GEP_4]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK-DAG: [[DOTRD_INPUT_GEP_7]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK-DAG: [[DOTRD_INPUT_GEP_8]] = getelementptr inbounds [4 x %struct.kmp_task_red_input_t], [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]], i64 0, i64
+// CHECK: [[TMP61:%.*]] = bitcast [4 x %struct.kmp_task_red_input_t]* [[DOTRD_INPUT_]] to i8*
+// CHECK: [[TMP62:%.*]] = call i8* @__kmpc_task_reduction_init(i32 [[TMP0]], i32 4, i8* [[TMP61]])
+// CHECK: [[TMP63:%.*]] = load i32, i32* [[N]],
+// CHECK: store i32 [[TMP63]], i32* [[DOTCAPTURE_EXPR_]],
+// CHECK: [[TMP64:%.*]] = load i32, i32* [[DOTCAPTURE_EXPR_]],
+// CHECK: [[SUB:%.*]] = sub nsw i32 [[TMP64]], 0
+// CHECK: [[SUB10:%.*]] = sub nsw i32 [[SUB]], 1
+// CHECK: [[ADD11:%.*]] = add nsw i32 [[SUB10]], 1
+// CHECK: [[DIV:%.*]] = sdiv i32 [[ADD11]], 1
+// CHECK: [[SUB12:%.*]] = sub nsw i32 [[DIV]], 1
+// CHECK: store i32 [[SUB12]], i32* [[DOTCAPTURE_EXPR_9]],
+// CHECK: [[TMP65:%.*]] = call i8* @__kmpc_omp_task_alloc(%ident_t* %{{.+}}, i32 [[TMP0]], i32 1, i64 888, i64 72, i32 (i32, i8*)* bitcast (i32 (i32, %struct.kmp_task_t_with_privates*)* @{{.+}} to i32 (i32, i8*)*))
+// CHECK: call void @__kmpc_taskloop(%ident_t* %{{.+}}, i32 [[TMP0]], i8* [[TMP65]], i32 1, i64* %{{.+}}, i64* %{{.+}}, i64 %{{.+}}, i32 0, i32 0, i64 0, i8* null)
+// CHECK: call void @__kmpc_end_taskgroup(%ident_t*
+
+// CHECK: ret i32
+
+// CHECK: define internal void [[RED_INIT1]](i8*)
+// CHECK: store float 0.000000e+00, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB1]](i8*, i8*)
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_INIT2]](i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_FINI2]](i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: call void @
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB2]](i8*, i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_INIT3]](i8*)
+// CHECK: store float 0.000000e+00, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB3]](i8*, i8*)
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_INIT4]](i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: store float 0.000000e+00, float* %
+// CHECK: ret void
+
+// CHECK: define internal void [[RED_COMB4]](i8*, i8*)
+// CHECK: call i8* @__kmpc_threadprivate_cached(
+// CHECK: fadd float %
+// CHECK: store float %{{.+}}, float* %
+// CHECK: ret void
+
diff --git a/test/OpenMP/taskloop_simd_reduction_messages.cpp b/test/OpenMP/taskloop_simd_reduction_messages.cpp
new file mode 100644
index 0000000000..886b685f63
--- /dev/null
+++ b/test/OpenMP/taskloop_simd_reduction_messages.cpp
@@ -0,0 +1,331 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s
+
+void foo() {
+}
+
+bool foobool(int argc) {
+ return argc;
+}
+
+void foobar(int &ref) {
+#pragma omp taskloop simd reduction(+:ref)
+ for (int i = 0; i < 10; ++i)
+ foo();
+}
+
+struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+ S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}}
+
+public:
+ S2() : a(0) {}
+ S2(S2 &s2) : a(s2.a) {}
+ static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
+};
+const float S2::S2sc = 0;
+S2 b; // expected-note 3 {{'b' defined here}}
+const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
+class S3 {
+ int a;
+
+public:
+ int b;
+ S3() : a(0) {}
+ S3(const S3 &s3) : a(s3.a) {}
+ S3 operator+(const S3 &arg1) { return arg1; }
+};
+int operator+(const S3 &arg1, const S3 &arg2) { return 5; }
+S3 c; // expected-note 3 {{'c' defined here}}
+const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
+extern const int f; // expected-note 4 {{'f' declared here}}
+class S4 {
+ int a;
+ S4(); // expected-note {{implicitly declared private here}}
+ S4(const S4 &s4);
+ S4 &operator+(const S4 &arg) { return (*this); }
+
+public:
+ S4(int v) : a(v) {}
+};
+S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; }
+class S5 {
+ int a;
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
+ S5(const S5 &s5) : a(s5.a) {}
+ S5 &operator+(const S5 &arg);
+
+public:
+ S5(int v) : a(v) {}
+};
+class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}}
+#if __cplusplus >= 201103L // C++11 or later
+// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}}
+#endif
+ int a;
+
+public:
+ S6() : a(6) {}
+ operator int() { return 6; }
+} o;
+
+struct S7 {
+ int a: 32;
+ S7() {
+#pragma omp taskloop reduction(+:a) // expected-error {{expected addressable reduction item for the task-based directives}}
+ for (int i = 0; i < 10; ++i)
+ ++a;
+ }
+};
+
+S3 h, k;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template <class T> // expected-note {{declared here}}
+T tmain(T argc) {
+ const T d = T(); // expected-note 4 {{'d' defined here}}
+ const T da[5] = {T()}; // expected-note 2 {{'da' defined here}}
+ T qa[5] = {T()};
+ T i;
+ T &j = i; // expected-note 4 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
+ T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
+ T fl;
+#pragma omp taskloop simd reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(^ : T) // expected-error {{'T' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : o) // expected-error 2 {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 2 {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop simd reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl)
+#pragma omp taskloop simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl)
+#pragma omp taskloop simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+
+ return T();
+}
+
+namespace A {
+double x;
+#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}}
+}
+namespace B {
+using A::x;
+}
+
+int main(int argc, char **argv) {
+ const int d = 5; // expected-note 2 {{'d' defined here}}
+ const int da[5] = {0}; // expected-note {{'da' defined here}}
+ int qa[5] = {0};
+ S4 e(4);
+ S5 g(5);
+ int i;
+ int &j = i; // expected-note 2 {{'j' defined here}}
+ S3 &p = k; // expected-note 2 {{'p' defined here}}
+ const int &r = da[i]; // expected-note {{'r' defined here}}
+ int &q = qa[i]; // expected-note {{'q' defined here}}
+ float fl;
+#pragma omp taskloop simd reduction // expected-error {{expected '(' after 'reduction'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(~ : argc) // expected-error {{expected unqualified-id}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(&& : argc)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(max : h.b) // expected-error {{expected variable name, array element or array section}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : o) // expected-error {{no viable overloaded '='}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(k)
+#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp taskloop simd reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel shared(i)
+#pragma omp parallel reduction(min : i)
+#pragma omp taskloop simd reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel private(fl)
+#pragma omp taskloop simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+#pragma omp parallel reduction(* : fl)
+#pragma omp taskloop simd reduction(+ : fl)
+ for (int i = 0; i < 10; ++i)
+ foo();
+ static int m;
+#pragma omp taskloop simd reduction(+ : m) // OK
+ for (int i = 0; i < 10; ++i)
+ m++;
+#pragma omp taskloop simd reduction(+ : m) nogroup // expected-error {{'reduction' clause cannot be used with 'nogroup' clause}}
+ for (int i = 0; i < 10; ++i)
+ m++;
+
+ return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
+}
diff --git a/test/OpenMP/teams_distribute_codegen.cpp b/test/OpenMP/teams_distribute_codegen.cpp
new file mode 100644
index 0000000000..a1b98a3f51
--- /dev/null
+++ b/test/OpenMP/teams_distribute_codegen.cpp
@@ -0,0 +1,241 @@
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+// Test host codegen.
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK1 -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 CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-32
+// RUN: %clang_cc1 -DCK1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK1 -fopenmp -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 CK1 --check-prefix CK1-32
+#ifdef CK1
+
+int a[100];
+
+// CK1: define {{.*}}i32 @{{.+}}teams_argument_globali(
+int teams_argument_global(int n){
+ int te = n / 128;
+ int th = 128;
+ // discard n_addr
+ // CK1: alloca i32,
+ // CK1: [[TE:%.+]] = alloca i32,
+ // CK1: [[TH:%.+]] = alloca i32,
+ // CK1: [[TE_CAST:%.+]] = alloca i{{32|64}},
+ // CK1: [[TH_CAST:%.+]] = alloca i{{32|64}},
+ // CK1: [[TE_PAR:%.+]] = load{{.+}}, {{.+}} [[TE_CAST]],
+ // CK1: [[TH_PAR:%.+]] = load{{.+}}, {{.+}} [[TH_CAST]],
+
+ // CK1: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 4, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+
+ // CK1: call void @[[OFFL1:.+]](i{{32|64}} [[TE_PAR]], i{{32|64}} [[TH_PAR]],
+ #pragma omp target
+ #pragma omp teams distribute num_teams(te), thread_limit(th)
+ for(int i = 0; i < n; i++) {
+ a[i] = 0;
+ }
+
+ // CK1: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 2, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+ // CK1: call void @[[OFFL2:.+]](i{{64|32}} %{{.+}})
+ #pragma omp target
+ {{{
+ #pragma omp teams distribute
+ for(int i = 0; i < n; i++) {
+ a[i] = 0;
+ }
+ }}}
+
+ // outlined target regions
+ // CK1: define internal void @[[OFFL1]](i{{32|64}} [[TE_ARG:%.+]], i{{32|64}} [[TH_ARG:%.+]], i{{32|64}} {{.+}}, {{.+}})
+ // CK1: [[TE_ADDR:%.+]] = alloca i{{32|64}},
+ // CK1: [[TH_ADDR:%.+]] = alloca i{{32|64}},
+ // CK1: store{{.+}} [[TE_ARG]], {{.+}} [[TE_ADDR]],
+ // CK1: store{{.+}} [[TH_ARG]], {{.+}} [[TH_ADDR]],
+ // CK1-64: [[TE_CONV:%.+]] = bitcast{{.+}} [[TE_ADDR]] to
+ // CK1-64: [[TH_CONV:%.+]] = bitcast{{.+}} [[TH_ADDR]] to
+ // CK1-64: [[TE_VAL:%.+]] = load i32, i32* [[TE_CONV]],
+ // CK1-64: [[TH_VAL:%.+]] = load i32, i32* [[TH_CONV]],
+ // CK1-32: [[TE_VAL:%.+]] = load i32, i32* [[TE_ADDR]],
+ // CK1-32: [[TH_VAL:%.+]] = load i32, i32* [[TH_ADDR]],
+ // CK1: {{%.+}} = call i32 @__kmpc_push_num_teams({{.+}}, {{.+}}, i32 [[TE_VAL]], i32 [[TH_VAL]])
+ // CK1: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 2, {{.+}} @[[OUTL1:.+]] to {{.+}}, {{.+}}, {{.+}})
+ // CK1: ret void
+
+ // CK1: define internal void @[[OUTL1]]({{.+}})
+ // CK1: call void @__kmpc_for_static_init_4(
+ // CK1: call void @__kmpc_for_static_fini(
+ // CK1: ret void
+
+ // CK1: define internal void @[[OFFL2]]({{.+}}, {{.+}})
+ // CK1: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 2, {{.+}} @[[OUTL2:.+]] to {{.+}}, {{.+}}, {{.+}})
+ // CK1: ret void
+
+ // CK1: define internal void @[[OUTL2]]({{.+}})
+ // CK1: call void @__kmpc_for_static_init_4(
+ // CK1: call void @__kmpc_for_static_fini(
+ // CK1: ret void
+
+ return a[0];
+}
+
+#endif // CK1
+
+// Test host codegen.
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK2 -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 CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-32
+// RUN: %clang_cc1 -DCK2 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK2 -fopenmp -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 CK2 --check-prefix CK2-32
+#ifdef CK2
+
+// CK2: define {{.*}}i32 @{{.+}}teams_local_argv(
+int teams_local_arg(void) {
+ int n = 100;
+ int a[n];
+
+ // CK2: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 3, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}, i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+ // CK2: call void @[[OFFL1:.+]](i{{64|32}} %{{.+}})
+ #pragma omp target
+ #pragma omp teams distribute
+ for(int i = 0; i < n; i++) {
+ a[i] = 0;
+ }
+
+ // outlined target region
+ // CK2: define internal void @[[OFFL1]]({{.+}}, {{.+}})
+ // CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 3, {{.+}} @[[OUTL1:.+]] to {{.+}}, {{.+}}, {{.+}})
+ // CK2: ret void
+
+ // CK2: define internal void @[[OUTL1]]({{.+}})
+ // CK2: call void @__kmpc_for_static_init_4(
+ // CK2: call void @__kmpc_for_static_fini(
+ // CK2: ret void
+
+ return a[0];
+}
+#endif // CK2
+
+// Test host codegen.
+// RUN: %clang_cc1 -DCK3 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK3 --check-prefix CK3-64
+// RUN: %clang_cc1 -DCK3 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK3 -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 CK3 --check-prefix CK3-64
+// RUN: %clang_cc1 -DCK3 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK3 --check-prefix CK3-32
+// RUN: %clang_cc1 -DCK3 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK3 -fopenmp -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 CK3 --check-prefix CK3-32
+#ifdef CK3
+
+// CK3: [[SSI:%.+]] = type { [{{.+}} x i32], float }
+
+template <typename T, int X, long long Y>
+struct SS{
+ T a[X];
+ float b;
+ // CK3: define {{.*}}i32 @{{.+}}foo{{.+}}(
+ int foo(void) {
+
+ // CK3: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 1, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+ // CK3: call void @[[OFFL1:.+]]([[SSI]]* %{{.+}})
+ #pragma omp target
+ #pragma omp teams distribute
+ for(int i = 0; i < X; i++) {
+ a[i] = (T)0;
+ }
+
+ // outlined target region
+ // CK3: define internal void @[[OFFL1]]([[SSI]]* {{.+}})
+ // CK3: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTL1:.+]] to {{.+}}, {{.+}}, {{.+}})
+ // CK3: ret void
+
+ // CK3: define internal void @[[OUTL1]]({{.+}})
+ // CK3: call void @__kmpc_for_static_init_4(
+ // CK3: call void @__kmpc_for_static_fini(
+ // CK3: ret void
+
+ return a[0];
+ }
+};
+
+int teams_template_struct(void) {
+ SS<int, 123, 456> V;
+ return V.foo();
+
+}
+#endif // CK3
+
+// Test host codegen.
+// RUN: %clang_cc1 -DCK4 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK4 --check-prefix CK4-64
+// RUN: %clang_cc1 -DCK4 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK4 -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 CK4 --check-prefix CK4-64
+// RUN: %clang_cc1 -DCK4 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK4 --check-prefix CK4-32
+// RUN: %clang_cc1 -DCK4 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK4 -fopenmp -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 CK4 --check-prefix CK4-32
+
+#ifdef CK4
+
+template <typename T, int n>
+int tmain(T argc) {
+ T a[n];
+ int te = n/128;
+ int th = 128;
+#pragma omp target
+#pragma omp teams distribute num_teams(te) thread_limit(th)
+ for(int i = 0; i < n; i++) {
+ a[i] = (T)0;
+ }
+ return 0;
+}
+
+int main (int argc, char **argv) {
+ int n = 100;
+ int a[n];
+#pragma omp target
+#pragma omp teams distribute
+ for(int i = 0; i < n; i++) {
+ a[i] = 0;
+ }
+ return tmain<int, 10>(argc);
+}
+
+// CK4: define {{.*}}i32 @{{[^,]+}}(i{{.+}}{{.+}} %[[ARGC:.+]], {{.+}})
+// CK4: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 3, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}, i32* {{.+}}@{{[^,]+}}, i32 0, i32 0)
+// CK4: call void @[[OFFL1:.+]]({{.+}})
+// CK4: {{%.+}} = call{{.*}} i32 @[[TMAIN:.+]]({{.+}})
+// CK4: ret
+
+// CK4: define {{.*}}void @[[OFFL1]]({{.+}})
+// CK4: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 3, {{.+}} @[[OUTL1:.+]] to {{.+}}, {{.+}}, {{.+}})
+// CK4: ret void
+
+// CK4: define internal void @[[OUTL1]]({{.+}})
+// CK4: call void @__kmpc_for_static_init_4(
+// CK4: call void @__kmpc_for_static_fini(
+// CK4: ret void
+
+// CK4: define {{.*}}i32 @[[TMAIN]]({{.+}})
+// CK4: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 3, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+// CK4: call void @[[OFFLT:.+]]({{.+}})
+// CK4: ret
+// CK4-NEXT: }
+
+// CK4: define {{.*}}void @[[OFFLT]](i{{32|64}} [[TE_ARG:%.+]], i{{32|64}} [[TH_ARG:%.+]], {{.+}})
+// CK4: [[TE_ADDR:%.+]] = alloca i{{32|64}},
+// CK4: [[TH_ADDR:%.+]] = alloca i{{32|64}},
+// CK4: store{{.+}} [[TE_ARG]], {{.+}} [[TE_ADDR]],
+// CK4: store{{.+}} [[TH_ARG]], {{.+}} [[TH_ADDR]],
+// CK4-64: [[TE_CONV:%.+]] = bitcast{{.+}} [[TE_ADDR]] to
+// CK4-64: [[TH_CONV:%.+]] = bitcast{{.+}} [[TH_ADDR]] to
+// CK4-64: [[TE_VAL:%.+]] = load i32, i32* [[TE_CONV]],
+// CK4-64: [[TH_VAL:%.+]] = load i32, i32* [[TH_CONV]],
+// CK4-32: [[TE_VAL:%.+]] = load i32, i32* [[TE_ADDR]],
+// CK4-32: [[TH_VAL:%.+]] = load i32, i32* [[TH_ADDR]],
+// CK4: {{%.+}} = call i32 @__kmpc_push_num_teams({{.+}}, {{.+}}, i32 [[TE_VAL]], i32 [[TH_VAL]])
+// CK4: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTLT:.+]] to {{.+}}, {{.+}}, {{.+}})
+// CK4: ret void
+
+// CK4: define internal void @[[OUTLT]]({{.+}})
+// CK4: call void @__kmpc_for_static_init_4(
+// CK4: call void @__kmpc_for_static_fini(
+// CK4: ret void
+
+#endif // CK4
+#endif
diff --git a/test/OpenMP/teams_distribute_collapse_codegen.cpp b/test/OpenMP/teams_distribute_collapse_codegen.cpp
new file mode 100644
index 0000000000..e9160771e0
--- /dev/null
+++ b/test/OpenMP/teams_distribute_collapse_codegen.cpp
@@ -0,0 +1,126 @@
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Test host codegen.
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK1 -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 CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-32
+// RUN: %clang_cc1 -DCK1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK1 -fopenmp -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 CK1 --check-prefix CK1-32
+#ifdef CK1
+
+template <typename T, int X, long long Y>
+struct SS{
+ T a[X][Y];
+
+ // CK1: define {{.*}}i32 @{{.+}}foo{{.+}}(
+ int foo(void) {
+
+ // CK1: call i32 @__tgt_target(
+ // CK1: call void @[[OFFL1:.+]](
+ #pragma omp target
+ #pragma omp teams distribute collapse(2)
+ for(int i = 0; i < X; i++) {
+ for(int j = 0; j < Y; j++) {
+ a[i][j] = (T)0;
+ }
+ }
+ // CK1: define internal void @[[OFFL1]](
+ // CK1: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTL1:.+]] to {{.+}},
+ // CK1: ret void
+
+ // CK1: define internal void @[[OUTL1]]({{.+}})
+ // discard loop variables not needed here
+ // CK1: = alloca i32,
+ // CK1: = alloca i32,
+ // CK1: [[OMP_UB:%.+]] = alloca i32,
+ // CK1: store i32 56087, i32* [[OMP_UB]],
+ // CK1: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92, {{.+}}, {{.+}}, i32* [[OMP_UB]],
+ // CK1: call void @__kmpc_for_static_fini(
+ // CK1: ret void
+
+ return a[0][0];
+ }
+};
+
+int teams_template_struct(void) {
+ SS<int, 123, 456> V;
+ return V.foo();
+
+}
+#endif // CK1
+
+// Test host codegen.
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK2 -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 CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-32
+// RUN: %clang_cc1 -DCK2 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK2 -fopenmp -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 CK2 --check-prefix CK2-32
+#ifdef CK2
+
+template <typename T, int n, int m>
+int tmain(T argc) {
+ T a[n][m];
+ #pragma omp target
+ #pragma omp teams distribute collapse(2)
+ for(int i = 0; i < n; i++) {
+ for(int j = 0; j < m; j++) {
+ a[i][j] = (T)0;
+ }
+ }
+ return 0;
+}
+
+int main (int argc, char **argv) {
+ int n = 100;
+ int m = 2;
+ int a[n][m];
+ #pragma omp target
+ #pragma omp teams distribute collapse(2)
+ for(int i = 0; i < n; i++) {
+ for(int j = 0; j < m; j++) {
+ a[i][j] = 0;
+ }
+ }
+ return tmain<int, 10, 2>(argc);
+}
+
+// CK2: define {{.*}}i32 @{{[^,]+}}(i{{.+}}{{.+}} %[[ARGC:.+]], {{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFL1:.+]]({{.+}})
+// CK2: {{%.+}} = call{{.*}} i32 @[[TMAIN:.+]]({{.+}})
+// CK2: ret
+
+// CK2: define {{.*}}void @[[OFFL1]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}} @[[OUTL1:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTL1]]({{.+}})
+// CK2: [[OMP_UB:%.omp.ub]] = alloca i64,
+// CK2: store i64 {{.+}}, i64* [[OMP_UB]],
+// CK2: call void @__kmpc_for_static_init_8({{.+}}, {{.+}}, i32 92, {{.+}}, {{.+}}, i64* [[OMP_UB]],
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+// CK2: define {{.*}}i32 @[[TMAIN]]({{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFLT1:.+]]({{.+}})
+// CK2: ret
+// CK2-NEXT: }
+
+// CK2: define {{.*}}void @[[OFFLT1]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTLT1:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTLT1]]({{.+}})
+// discard loop variables not needed here
+// CK2: [[OMP_UB:%.omp.ub]] = alloca i32,
+// CK2: store i32 {{.+}}, i32* [[OMP_UB]],
+// CK2: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92, {{.+}}, {{.+}}, i32* [[OMP_UB]],
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+
+#endif // CK2
+#endif // #ifndef HEADER
diff --git a/test/OpenMP/teams_distribute_dist_schedule_codegen.cpp b/test/OpenMP/teams_distribute_dist_schedule_codegen.cpp
new file mode 100644
index 0000000000..685180c26b
--- /dev/null
+++ b/test/OpenMP/teams_distribute_dist_schedule_codegen.cpp
@@ -0,0 +1,206 @@
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+// Test host codegen.
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK1 -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 CK1 --check-prefix CK1-64
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK1 --check-prefix CK1-32
+// RUN: %clang_cc1 -DCK1 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK1 -fopenmp -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 CK1 --check-prefix CK1-32
+#ifdef CK1
+
+template <typename T, int X, long long Y>
+struct SS{
+ T a[X];
+ float b;
+ // CK1: define {{.*}}i32 @{{.+}}foo{{.+}}(
+ int foo(void) {
+
+ // CK1: call i32 @__tgt_target(
+ // CK1: call void @[[OFFL1:.+]](
+ #pragma omp target
+ #pragma omp teams distribute
+ for(int i = 0; i < X; i++) {
+ a[i] = (T)0;
+ }
+ // CK1: call i32 @__tgt_target(
+ // CK1: call void @[[OFFL2:.+]](
+ #pragma omp target
+ #pragma omp teams distribute dist_schedule(static)
+ for(int i = 0; i < X; i++) {
+ a[i] = (T)0;
+ }
+ // CK1: call i32 @__tgt_target(
+ // CK1: call void @[[OFFL3:.+]](
+ #pragma omp target
+ #pragma omp teams distribute dist_schedule(static, X/2)
+ for(int i = 0; i < X; i++) {
+ a[i] = (T)0;
+ }
+ // CK1: define internal void @[[OFFL1]](
+ // CK1: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTL1:.+]] to {{.+}},
+ // CK1: ret void
+
+ // CK1: define internal void @[[OUTL1]]({{.+}})
+ // CK1: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92
+ // CK1: call void @__kmpc_for_static_fini(
+ // CK1: ret void
+
+ // CK1: define internal void @[[OFFL2]](
+ // CK1: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTL2:.+]] to {{.+}},
+ // CK1: ret void
+
+ // CK1: define internal void @[[OUTL2]]({{.+}})
+ // CK1: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92
+ // CK1: call void @__kmpc_for_static_fini(
+ // CK1: ret void
+
+ // CK1: define internal void @[[OFFL3]](
+ // CK1: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTL3:.+]] to {{.+}},
+ // CK1: ret void
+
+ // CK1: define internal void @[[OUTL3]]({{.+}})
+ // CK1: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 91
+ // CK1: call void @__kmpc_for_static_fini(
+ // CK1: ret void
+
+ return a[0];
+ }
+};
+
+int teams_template_struct(void) {
+ SS<int, 123, 456> V;
+ return V.foo();
+
+}
+#endif // CK1
+
+// Test host codegen.
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK2 -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 CK2 --check-prefix CK2-64
+// RUN: %clang_cc1 -DCK2 -verify -fopenmp -x c++ -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix CK2 --check-prefix CK2-32
+// RUN: %clang_cc1 -DCK2 -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCK2 -fopenmp -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 CK2 --check-prefix CK2-32
+#ifdef CK2
+
+template <typename T, int n>
+int tmain(T argc) {
+ T a[n];
+#pragma omp target
+#pragma omp teams distribute
+ for(int i = 0; i < n; i++) {
+ a[i] = (T)0;
+ }
+#pragma omp target
+#pragma omp teams distribute dist_schedule(static)
+ for(int i = 0; i < n; i++) {
+ a[i] = (T)0;
+ }
+#pragma omp target
+#pragma omp teams distribute dist_schedule(static, n)
+ for(int i = 0; i < n; i++) {
+ a[i] = (T)0;
+ }
+ return 0;
+}
+
+int main (int argc, char **argv) {
+ int n = 100;
+ int a[n];
+#pragma omp target
+#pragma omp teams distribute
+ for(int i = 0; i < n; i++) {
+ a[i] = 0;
+ }
+#pragma omp target
+#pragma omp teams distribute dist_schedule(static)
+ for(int i = 0; i < n; i++) {
+ a[i] = 0;
+ }
+#pragma omp target
+#pragma omp teams distribute dist_schedule(static, n)
+ for(int i = 0; i < n; i++) {
+ a[i] = 0;
+ }
+ return tmain<int, 10>(argc);
+}
+
+// CK2: define {{.*}}i32 @{{[^,]+}}(i{{.+}}{{.+}} %[[ARGC:.+]], {{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFL1:.+]]({{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFL2:.+]]({{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFL3:.+]]({{.+}})
+// CK2: {{%.+}} = call{{.*}} i32 @[[TMAIN:.+]]({{.+}})
+// CK2: ret
+
+// CK2: define {{.*}}void @[[OFFL1]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 3, {{.+}} @[[OUTL1:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTL1]]({{.+}})
+// CK2: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+
+// CK2: define {{.*}}void @[[OFFL2]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 3, {{.+}} @[[OUTL2:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTL2]]({{.+}})
+// CK2: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+
+// CK2: define {{.*}}void @[[OFFL3]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}} @[[OUTL3:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTL3]]({{.+}})
+// CK2: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 91
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+
+// CK2: define {{.*}}i32 @[[TMAIN]]({{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFLT1:.+]]({{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFLT2:.+]]({{.+}})
+// CK2: call i32 @__tgt_target(
+// CK2: call void @[[OFFLT3:.+]]({{.+}})
+// CK2: ret
+// CK2-NEXT: }
+
+// CK2: define {{.*}}void @[[OFFLT1]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTLT1:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTLT1]]({{.+}})
+// CK2: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+
+// CK2: define {{.*}}void @[[OFFLT2]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTLT2:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTLT2]]({{.+}})
+// CK2: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 92
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+
+// CK2: define {{.*}}void @[[OFFLT3]]({{.+}})
+// CK2: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTLT3:.+]] to {{.+}},
+// CK2: ret void
+
+// CK2: define internal void @[[OUTLT3]]({{.+}})
+// CK2: call void @__kmpc_for_static_init_4({{.+}}, {{.+}}, i32 91
+// CK2: call void @__kmpc_for_static_fini(
+// CK2: ret void
+
+#endif // CK2
+#endif // #ifndef HEADER
diff --git a/test/OpenMP/teams_distribute_firstprivate_codegen.cpp b/test/OpenMP/teams_distribute_firstprivate_codegen.cpp
new file mode 100644
index 0000000000..aef288d11b
--- /dev/null
+++ b/test/OpenMP/teams_distribute_firstprivate_codegen.cpp
@@ -0,0 +1,336 @@
+// RUN: %clang_cc1 -DCHECK -verify -fopenmp -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 -DCHECK -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCHECK -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 -DCHECK -verify -fopenmp -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 -DCHECK -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCHECK -fopenmp -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
+
+// 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++ -std=c++11 -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
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+struct St {
+ int a, b;
+ St() : a(0), b(0) {}
+ St(const St &st) : a(st.a + st.b), b(0) {}
+ ~St() {}
+};
+
+volatile int g = 1212;
+volatile int &g1 = g;
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a + g) {}
+ S() : f(g) {}
+ S(const S &s, St t = St()) : f(s.f + t.a) {}
+ operator T() { return T(); }
+ ~S() {}
+};
+
+// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
+// CHECK-DAG: [[ST_TY:%.+]] = type { i{{[0-9]+}}, 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 distribute firstprivate(t_var, vec, s_arr, var)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+ return T();
+}
+
+// CHECK-DAG: [[TEST:@.+]] = global [[S_FLOAT_TY]] zeroinitializer,
+S<float> test;
+// CHECK-DAG: [[T_VAR:@.+]] = global i{{[0-9]+}} 333,
+int t_var = 333;
+// CHECK-DAG: [[VEC:@.+]] = global [2 x i{{[0-9]+}}] [i{{[0-9]+}} 1, i{{[0-9]+}} 2],
+int vec[] = {1, 2};
+// CHECK-DAG: [[S_ARR:@.+]] = global [2 x [[S_FLOAT_TY]]] zeroinitializer,
+S<float> s_arr[] = {1, 2};
+// CHECK-DAG: [[VAR:@.+]] = global [[S_FLOAT_TY]] zeroinitializer,
+S<float> var(3);
+// CHECK-DAG: [[SIVAR:@.+]] = internal global i{{[0-9]+}} 0,
+
+int main() {
+ static int sivar;
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 3, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+ // LAMBDA: call void @[[LOFFL1:.+]](i{{64|32}} %{{.+}})
+ // LAMBDA: ret
+#pragma omp target
+#pragma omp teams distribute firstprivate(g, g1, sivar)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void @[[LOFFL1]](i{{64|32}} {{%.+}}, i{{64|32}} {{%.+}})
+ // LAMBDA: {{%.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{%.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{%.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: [[G_CAST:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G1_CAST:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SIVAR_CAST:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA-DAG: [[G_CAST_VAL:%.+]] = load{{.+}} [[G_CAST]],
+ // LAMBDA-DAG: [[G1_CAST_VAL:%.+]] = load{{.+}} [[G1_CAST]],
+ // LAMBDA-DAG: [[SIVAR_CAST_VAL:%.+]] = load{{.+}} [[SIVAR_CAST]],
+ // LAMBDA: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 3, {{.+}} @[[LOUTL1:.+]] to {{.+}}, {{.+}} [[G_CAST_VAL]], {{.+}} [[G1_CAST_VAL]], {{.+}} [[SIVAR_CAST_VAL]])
+ // LAMBDA: ret void
+
+ // LAMBDA: define internal void @[[LOUTL1]]({{.+}})
+ // Skip global and bound tid vars
+ // LAMBDA: {{.+}} = alloca i32*,
+ // LAMBDA: {{.+}} = alloca i32*,
+ // LAMBDA: [[G_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G1_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SIVAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G1_TMP:%.+]] = alloca i32*,
+ // skip loop vars
+ // LAMBDA-DAG: store {{.+}}, {{.+}} [[G_ADDR]],
+ // LAMBDA-DAG: store {{.+}}, {{.+}} [[G1_ADDR]],
+ // LAMBDA-DAG: store {{.+}}, {{.+}} [[SIVAR_ADDR]],
+ // LAMBDA-DAG: [[G_CONV:%.+]] = bitcast {{.+}} [[G_ADDR]] to
+ // LAMBDA-DAG: [[G1_CONV:%.+]] = bitcast {{.+}} [[G1_ADDR]] to
+ // LAMBDA-DAG: [[SIVAR_CONV:%.+]] = bitcast {{.+}} [[SIVAR_ADDR]] to
+ // LAMBDA-DAG: store{{.+}} [[G1_CONV]], {{.+}} [[G1_TMP]],
+ g = 1;
+ g1 = 1;
+ sivar = 2;
+ // LAMBDA: call void @__kmpc_for_static_init_4(
+ // LAMBDA-DAG: store{{.+}} 1, {{.+}} [[G_CONV]],
+ // LAMBDA-DAG: [[G1:%.+]] = load{{.+}}, {{.+}}* [[G1_TMP]]
+ // LAMBDA-DAG: store{{.+}} 1, {{.+}} [[G1]],
+ // LAMBDA-DAG: store{{.+}} 2, {{.+}} [[SIVAR_CONV]],
+ // LAMBDA-DAG: [[G1_REF:%.+]] = load{{.+}}, {{.+}} [[G1_TMP]],
+ // LAMBDA-DAG: store{{.+}} 1, {{.+}} [[G1_REF]],
+ // 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;
+ sivar = 4;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
+ // LAMBDA: [[G1_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G1_REF]]
+ // LAMBDA: [[SIVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SIVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SIVAR_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SIVAR_REF]]
+ }();
+ }
+ }();
+ return 0;
+#else
+#pragma omp target
+#pragma omp teams distribute firstprivate(t_var, vec, s_arr, var, sivar)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ sivar += i;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: define {{.*}}i{{[0-9]+}} @main()
+// CHECK: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 5, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+// CHECK: call void @[[OFFL1:.+]](i{{64|32}} %{{.+}})
+// CHECK: {{%.+}} = call{{.*}} i32 @[[TMAIN_INT:.+]]()
+// CHECK: ret
+
+// CHECK: define{{.*}} void @[[OFFL1]]({{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[SIVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_CAST:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[SIVAR_CAST:%.+]] = alloca i{{[0-9]+}},
+
+// CHECK-DAG: [[VEC_TE_PAR:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_PRIV]],
+// CHECK-DAG: [[T_VAR_TE_PAR:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_CAST]],
+// CHECK-DAG: [[S_ARR_TE_PAR:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_PRIV]],
+// CHECK-DAG: [[VAR_TE_PAR:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[VAR_PRIV]],
+// CHECK-DAG: [[SIVAR_TE_PAR:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIVAR_CAST]],
+
+// CHECK: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 5, {{.+}} @[[OUTL1:.+]] to {{.+}}, [2 x i{{[0-9]+}}]* [[VEC_TE_PAR]], i{{[0-9]+}} [[T_VAR_TE_PAR]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_TE_PAR]], [[S_FLOAT_TY]]* [[VAR_TE_PAR]], i{{[0-9]+}} [[SIVAR_TE_PAR]])
+// CHECK: ret void
+
+// CHECK: define internal void @[[OUTL1]]({{.+}})
+// Skip global and bound tid vars
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[S_ARR_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*,
+// CHECK: [[VAR_ADDR:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[SIVAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+// Skip temp vars for loop
+// 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: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[AGG_TMP1:%.+]] = alloca [[ST_TY]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[AGG_TMP2:%.+]] = alloca [[ST_TY]],
+
+// param copy
+// CHECK: store [2 x i{{[0-9]+}}]* {{.+}}, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: store i{{[0-9]+}} {{.+}}, i{{[0-9]+}}* [[T_VAR_ADDR]],
+// CHECK: store [2 x [[S_FLOAT_TY]]]* {{.+}}, [2 x [[S_FLOAT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: store [[S_FLOAT_TY]]* {{.+}}, [[S_FLOAT_TY]]** [[VAR_ADDR]],
+// CHECK: store i{{[0-9]+}} {{.+}}, i{{[0-9]+}}* [[SIVAR_ADDR]],
+
+// T_VAR and SIVAR
+// CHECK-DAG-64: [[CONV_TVAR:%.+]] = bitcast i64* [[T_VAR_ADDR]] to i32*
+// CHECK-DAG-64: [[CONV_SIVAR:%.+]] = bitcast i64* [[SIVAR_ADDR]] to i32*
+
+// preparation vars
+// CHECK-DAG: [[VEC_ADDR_VAL:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK-DAG: [[S_ARR_ADDR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_ADDR]],
+// CHECK-DAG: [[VAR_ADDR_REF:%.+]] = load{{.+}} [[VAR_ADDR]],
+
+// firstprivate vec(vec): copy from *_addr into priv1 and then from priv1 into priv2
+// CHECK-DAG: [[VEC_DEST_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK-DAG: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_VAL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST_PRIV]], i8* [[VEC_SRC]], {{.+}})
+
+// firstprivate(s_arr)
+// CHECK-DAG: [[S_ARR_PRIV_BGN:%.+]] = getelementptr{{.*}} [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_ADDR_BGN:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[S_ARR_ADDR_REF]] to
+// CHECK-DAG: [[S_ARR_FIN:%.+]] = icmp{{.+}} [[S_ARR_PRIV_BGN]],
+// CHECK-DAG: [[S_ARR_SRC_COPY:%.+]] = phi{{.+}} [ [[S_ARR_ADDR_BGN]], {{.+}} ], [ [[S_ARR_SRC:%.+]], {{.+}} ]
+// CHECK-DAG: [[S_ARR_DST_COPY:%.+]] = phi{{.+}} [ [[S_ARR_PRIV_BGN]], {{.+}}], [ [[S_ARR_DST:%.+]], {{.+}} ]
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP1]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[S_ARR_DST_COPY]], {{.+}} [[S_ARR_SRC_COPY]], {{.+}} [[AGG_TMP1]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP1]])
+// CHECK-DAG: [[S_ARR_DST]] = getelementptr {{.+}} [[S_ARR_DST_COPY]],
+// CHECK-DAG: [[S_ARR_SRC]] = getelementptr {{.+}} [[S_ARR_SRC_COPY]],
+
+// firstprivate(var)
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP2]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[VAR_PRIV]], {{.+}} [[VAR_ADDR_REF]], {{.+}} [[AGG_TMP2]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP2]])
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK-DAG-32: {{.+}} = {{.+}} [[T_VAR_ADDR]]
+// CHECK-DAG-64: {{.+}} = {{.+}} [[CONV_TVAR]]
+// CHECK-DAG: {{.+}} = {{.+}} [[VEC_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[S_ARR_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[VAR_PRIV]]
+// CHECK-DAG-32: {{.+}} = {{.+}} [[SIVAR_ADDR]]
+// CHECK-DAG-64: {{.+}} = {{.+}} [[CONV_SIVAR]]
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+// CHECK: define{{.*}} i{{[0-9]+}} @[[TMAIN_INT]]()
+// CHECK: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 4, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+// CHECK: call void @[[TOFFL1:.+]](i{{64|32}} %{{.+}})
+// CHECK: ret
+
+// CHECK: define {{.*}}void @[[TOFFL1]]({{.+}})
+// CHECK: [[TT_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[TVEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[TS_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]]*,
+// CHECK: [[TVAR_PRIV:%.+]] = alloca [[S_INT_TY]]*,
+// CHECK: [[TT_VAR_CAST:%.+]] = alloca i{{[0-9]+}},
+
+// CHECK-DAG: [[TVEC_TE_PAR:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[TVEC_PRIV]],
+// CHECK-DAG: [[TT_VAR_TE_PAR:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[TT_VAR_CAST]],
+// CHECK-DAG: [[TS_ARR_TE_PAR:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[TS_ARR_PRIV]],
+// CHECK-DAG: [[TVAR_TE_PAR:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TVAR_PRIV]],
+
+// CHECK: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}} @[[TOUTL1:.+]] to {{.+}}, [2 x i{{[0-9]+}}]* [[TVEC_TE_PAR]], i{{[0-9]+}} [[TT_VAR_TE_PAR]], [2 x [[S_INT_TY]]]* [[TS_ARR_TE_PAR]], [[S_INT_TY]]* [[TVAR_TE_PAR]])
+// CHECK: ret void
+
+// CHECK: define internal void @[[TOUTL1]]({{.+}})
+// Skip global and bound tid vars
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[S_ARR_ADDR:%.+]] = alloca [2 x [[S_INT_TY]]]*,
+// CHECK: [[VAR_ADDR:%.+]] = alloca [[S_INT_TY]]*,
+// Skip temp vars for loop
+// 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: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[AGG_TMP1:%.+]] = alloca [[ST_TY]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[AGG_TMP2:%.+]] = alloca [[ST_TY]],
+// CHECK: [[TMP:%.+]] = alloca [[S_INT_TY]]*,
+
+// param copy
+// CHECK: store [2 x i{{[0-9]+}}]* {{.+}}, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: store i{{[0-9]+}} {{.+}}, i{{[0-9]+}}* [[T_VAR_ADDR]],
+// CHECK: store [2 x [[S_INT_TY]]]* {{.+}}, [2 x [[S_INT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: store [[S_INT_TY]]* {{.+}}, [[S_INT_TY]]** [[VAR_ADDR]],
+
+
+// T_VAR and preparation variables
+// CHECK: [[VEC_ADDR_VAL:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK-64: [[CONV_TVAR:%.+]] = bitcast i64* [[T_VAR_ADDR]] to i32*
+// CHECK: [[S_ARR_ADDR_REF:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_ADDR]],
+
+// firstprivate vec(vec): copy from *_addr into priv1 and then from priv1 into priv2
+// CHECK-DAG: [[VEC_DEST_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK-DAG: [[VEC_SRC:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_VAL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VEC_DEST_PRIV]], i8* [[VEC_SRC]], {{.+}})
+
+// firstprivate(s_arr)
+// CHECK-DAG: [[S_ARR_PRIV_BGN:%.+]] = getelementptr{{.*}} [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_ADDR_BGN:%.+]] = bitcast [2 x [[S_INT_TY]]]* [[S_ARR_ADDR_REF]] to
+// CHECK-DAG: [[S_ARR_FIN:%.+]] = icmp{{.+}} [[S_ARR_PRIV_BGN]],
+// CHECK-DAG: [[S_ARR_SRC_COPY:%.+]] = phi{{.+}} [ [[S_ARR_ADDR_BGN]], {{.+}} ], [ [[S_ARR_SRC:%.+]], {{.+}} ]
+// CHECK-DAG: [[S_ARR_DST_COPY:%.+]] = phi{{.+}} [ [[S_ARR_PRIV_BGN]], {{.+}} ], [ [[S_ARR_DST:%.+]], {{.+}} ]
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP1]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[S_ARR_DST_COPY]], {{.+}} [[S_ARR_SRC_COPY]], {{.+}} [[AGG_TMP1]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP1]])
+// CHECK-DAG: [[S_ARR_DST]] = getelementptr {{.+}} [[S_ARR_DST_COPY]],
+// CHECK-DAG: [[S_ARR_SRC]] = getelementptr {{.+}} [[S_ARR_SRC_COPY]],
+
+// firstprivate(var)
+// CHECK-DAG: [[VAR_ADDR_REF:%.+]] = load{{.+}} [[VAR_ADDR]],
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP2]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[VAR_PRIV]], {{.+}} [[VAR_ADDR_REF]], {{.+}} [[AGG_TMP2]])
+// CHECK-DAG: call void @{{.+}}({{.+}} [[AGG_TMP2]])
+// CHECK-DAG: store [[S_INT_TY]]* [[VAR_PRIV]], [[S_INT_TY]]** [[TMP]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK-DAG-32: {{.+}} = {{.+}} [[T_VAR_ADDR]]
+// CHECK-DAG-64: {{.+}} = {{.+}} [[CONV_TVAR]]
+// CHECK-DAG: {{.+}} = {{.+}} [[VEC_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[TMP]]
+// CHECK-DAG: {{.+}} = {{.+}} [[S_ARR_PRIV]]
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+#endif
diff --git a/test/OpenMP/teams_distribute_lastprivate_codegen.cpp b/test/OpenMP/teams_distribute_lastprivate_codegen.cpp
new file mode 100644
index 0000000000..cc48ee1109
--- /dev/null
+++ b/test/OpenMP/teams_distribute_lastprivate_codegen.cpp
@@ -0,0 +1,366 @@
+// 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 distribute lastprivate(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(
+ // LAMBDA: call void [[OFFLOADING_FUN:@.+]](
+
+ // LAMBDA: define{{.+}} void [[OFFLOADING_FUN]](
+ // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_teams({{.+}}, i32 4, {{.+}}* [[OMP_OUTLINED:@.+]] to {{.+}})
+ #pragma omp target
+ #pragma omp teams distribute lastprivate(g, g1, svar, sfvar)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, double*{{.+}} [[G_IN:%.+]], double*{{.+}} [[G1_IN:%.+]], i{{[0-9]+}}*{{.+}} [[SVAR_IN:%.+]], float*{{.+}} [[SFVAR_IN:%.+]])
+ // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[G1_PRIVATE_ADDR:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}*,
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR:%.+]] = alloca float*,
+ // loop variables
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: {{.+}} = alloca i{{[0-9]+}},
+ // LAMBDA: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[G1_PRIVATE:%.+]] = alloca double,
+ // LAMBDA: [[TMP_G1_PRIVATE:%.+]] = alloca double*,
+ // LAMBDA: [[SVAR_PRIVATE:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[SFVAR_PRIVATE:%.+]] = alloca float,
+ // LAMBDA: store double* [[G_IN]], double** [[G_PRIVATE_ADDR]],
+ // LAMBDA: store double* [[G1_IN]], double** [[G1_PRIVATE_ADDR]],
+ // LAMBDA: store i{{[0-9]+}}* [[SVAR_IN]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR]],
+ // LAMBDA: store float* [[SFVAR_IN]], float** [[SFVAR_PRIVATE_ADDR]],
+
+ // init private variables
+ // LAMBDA: [[G_IN_REF:%.+]] = load double*, double** [[G_PRIVATE_ADDR]],
+ // LAMBDA: [[SVAR_IN_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR]],
+ // LAMBDA: [[SFVAR_IN_REF:%.+]] = load float*, float** [[SFVAR_PRIVATE_ADDR]],
+ // LAMBDA: [[G1_IN_REF:%.+]] = load double*, double** [[G1_PRIVATE_ADDR]],
+ // LAMBDA: store double* [[G1_PRIVATE]], double** [[TMP_G1_PRIVATE]],
+ g = 1;
+ g1 = 1;
+ svar = 3;
+ sfvar = 4.0;
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_init_4(
+ // LAMBDA: store double 1.0{{.+}}, double* [[G_PRIVATE]],
+ // LAMBDA: [[TMP_G1_REF:%.+]] = load double*, double** [[TMP_G1_PRIVATE]],
+ // LAMBDA: store{{.+}} double 1.0{{.+}}, double* [[TMP_G1_REF]],
+ // LAMBDA: store i{{[0-9]+}} 3, i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA: store float 4.0{{.+}}, float* [[SFVAR_PRIVATE]],
+ // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: store double* [[G_PRIVATE]], double** [[G_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[TMP_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_PRIVATE_ADDR_FROM_TMP:%.+]] = load double*, double** [[TMP_G1_PRIVATE]],
+ // LAMBDA: store double* [[G1_PRIVATE_ADDR_FROM_TMP]], double** [[TMP_PRIVATE_ADDR_REF]],
+ // LAMBDA: [[SVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: store i{{[0-9]+}}* [[SVAR_PRIVATE]], i{{[0-9]+}}** [[SVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: [[SFVAR_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: store float* [[SFVAR_PRIVATE]], float** [[SFVAR_PRIVATE_ADDR_REF]]
+ // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]])
+ // LAMBDA: call {{.*}}void @__kmpc_for_static_fini(
+ // LAMBDA: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+ // LAMBDA: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+ // LAMBDA: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+ // LAMBDA: [[OMP_LASTPRIV_BLOCK]]:
+ // LAMBDA: [[G_PRIV_VAL:%.+]] = load double, double* [[G_PRIVATE]],
+ // LAMBDA: store{{.*}} double [[G_PRIV_VAL]], double* [[G_IN_REF]],
+ // LAMBDA: [[TMP_G1_PRIV_REF:%.+]] = load double*, double** [[TMP_G1_PRIVATE]],
+ // LAMBDA: [[TMP_G1_PRIV_VAL:%.+]] = load double, double* [[TMP_G1_PRIV_REF]],
+ // LAMBDA: store{{.*}} double [[TMP_G1_PRIV_VAL]], double* [[G1_IN_REF]],
+
+ // LAMBDA: [[SVAR_PRIV_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SVAR_PRIVATE]],
+ // LAMBDA: store i{{[0-9]+}} [[SVAR_PRIV_VAL]], i{{[0-9]+}}* [[SVAR_IN_REF]],
+ // LAMBDA: [[SFVAR_PRIV_VAL:%.+]] = load float, float* [[SFVAR_PRIVATE]],
+ // LAMBDA: store float [[SFVAR_PRIV_VAL]], float* [[SFVAR_IN_REF]],
+ // LAMBDA: br label %[[OMP_LASTPRIV_DONE]]
+ // LAMBDA: [[OMP_LASTPRIV_DONE]]:
+ // LAMBDA: ret
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+ g = 2;
+ g1 = 2;
+ svar = 4;
+ sfvar = 8.0;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load double*, double** [[G_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G_REF]]
+
+ // LAMBDA: [[TMP_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load double*, double** [[TMP_PTR_REF]]
+ // LAMBDA: store double 2.0{{.+}}, double* [[G1_REF]],
+ // LAMBDA: [[SVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SVAR_REF]]
+ // LAMBDA: [[SFVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 3
+ // LAMBDA: [[SFVAR_REF:%.+]] = load float*, float** [[SFVAR_PTR_REF]]
+ // LAMBDA: store float 8.0{{.+}}, 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 distribute lastprivate(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;
+ }
+ int i;
+
+ 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(
+// CHECK: call void [[OFFLOAD_FUN:@.+]](i{{[0-9]+}} {{.+}}, [2 x i{{[0-9]+}}]* {{.+}}, [2 x [[S_FLOAT_TY]]]* {{.+}}, [[S_FLOAT_TY]]* {{.+}}, i{{[0-9]+}} {{.+}})
+// CHECK: ret
+
+// CHECK: define{{.+}} [[OFFLOAD_FUN]](i{{[0-9]+}} {{.+}}, [2 x i{{[0-9]+}}]*{{.+}} {{.+}}, [2 x [[S_FLOAT_TY]]]*{{.+}} {{.+}}, [[S_FLOAT_TY]]*{{.+}} {{.+}}, i{{[0-9]+}} {{.+}})
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(
+// CHECK: ret
+//
+// CHECK: define internal void [[OMP_OUTLINED:@.+]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x i{{[0-9]+}}]*{{.+}} [[VEC_IN:%.+]], i{{[0-9]+}}*{{.+}} [[T_VAR_IN:%.+]], [2 x [[S_FLOAT_TY]]]*{{.+}} [[S_ARR_IN:%.+]], [[S_FLOAT_TY]]*{{.+}} [[VAR_IN:%.+]], i{{[0-9]+}}*{{.*}} [[S_VAR_IN:%.+]])
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: [[VEC_ADDR:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR:%.+]] = alloca 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]+}}*,
+// skip loop variables
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[TMP_PRIV:%.+]] = alloca [[S_FLOAT_TY]]*,
+// CHECK: [[S_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+
+// copy from parameters to local address variables
+// CHECK: store [2 x i{{[0-9]+}}]* [[VEC_IN]], [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: store i{{[0-9]+}}* [[T_VAR_IN]], i{{[0-9]+}}** [[T_VAR_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]+}}* [[S_VAR_IN]], i{{[0-9]+}}** [[SVAR_ADDR]],
+
+// load content of local address variables
+// CHECK: [[VEC_ADDR_REF:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR]],
+// CHECK: [[T_VAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_ADDR]],
+// CHECK: [[S_ARR_ADDR_REF:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[S_ARR_ADDR]],
+// CHECK: [[SVAR_ADDR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SVAR_ADDR]],
+// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[OMP_IS_LAST]],
+// CHECK: [[VAR_ADDR_REF:%.+]] = load {{.+}}, {{.+}} [[VAR_ADDR]],
+// the distribute loop
+// CHECK: call void @__kmpc_for_static_init_4(
+// assignment: vec[i] = t_var;
+// 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]],
+
+// assignment: s_arr[i] = var;
+// CHECK-DAG: [[S_ARR_PTR:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[TMP_VAL:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP_PRIV]],
+// CHECK-DAG: [[S_ARR_PTR_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_PTR]] to i8*
+// CHECK-DAG: [[TMP_VAL_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[TMP_VAL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_PTR_BCAST]], i8* [[TMP_VAL_BCAST]],
+// CHECK: call void @__kmpc_for_static_fini(
+
+// lastprivates
+// CHECK: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST]],
+// CHECK: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+// CHECK: [[OMP_LASTPRIV_BLOCK]]:
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_ADDR_REF]],
+// CHECK: [[BCAST_VEC_ADDR_REF:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_REF]] to i8*
+// CHECK: [[BCAST_VEC_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[BCAST_VEC_ADDR_REF]], i8* [[BCAST_VEC_PRIV]],
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_ADDR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BCAST:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]] to [[S_FLOAT_TY]]*
+// CHECK: [[S_ARR_BEGIN_GEP:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_COPY_DONE:.+]], label %[[S_ARR_COPY_BLOCK:.+]]
+// CHECK: [[S_ARR_COPY_BLOCK]]:
+// CHECK: [[S_ARR_SRC_EL:%.+]] = phi [[S_FLOAT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_EL:%.+]] = phi [[S_FLOAT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_DST_EL]] to i8*
+// CHECK: [[S_ARR_SRC_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[S_ARR_SRC_EL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_DST_BCAST]], i8* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK: [[S_ARR_DST_NEXT:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[S_ARR_DST_EL]], i{{[0-9]+}} 1
+// CHECK: [[S_ARR_SRC_NEXT:%.+]] = getelementptr{{.+}}
+// CHECK: [[CPY_IS_FINISHED:%.+]] = icmp eq [[S_FLOAT_TY]]* [[S_ARR_DST_NEXT]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[CPY_IS_FINISHED]], label %[[S_ARR_COPY_DONE]], label %[[S_ARR_COPY_BLOCK]]
+// CHECK: [[S_ARR_COPY_DONE]]:
+// CHECK: [[TMP_VAL1:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[TMP_PRIV]],
+// CHECK: [[VAR_ADDR_REF_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[VAR_ADDR_REF]] to i8*
+// CHECK: [[TMP_VAL1_BCAST:%.+]] = bitcast [[S_FLOAT_TY]]* [[TMP_VAL1]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VAR_ADDR_REF_BCAST]], i8* [[TMP_VAL1_BCAST]],{{.+}})
+// CHECK: [[SVAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[S_VAR_PRIV]],
+// CHECK: store i{{[0-9]+}} [[SVAR_VAL]], i{{[0-9]+}}* [[SVAR_ADDR_REF]],
+// CHECK: ret void
+
+// template tmain
+// 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(
+// CHECK: call void [[OFFLOAD_FUN_1:@.+]](i{{[0-9]+}} {{.+}}, [2 x i{{[0-9]+}}]* {{.+}}, [2 x [[S_INT_TY]]]* {{.+}}, [[S_INT_TY]]* {{.+}})
+// CHECK: ret
+
+
+// CHECK: define internal void [[OFFLOAD_FUN_1]](
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_teams(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4,
+// CHECK: ret
+
+// CHECK: define internal void [[OMP_OUTLINED_1:@.+]](i{{[0-9]+}}* noalias [[GTID_ADDR1:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x i{{[0-9]+}}]*{{.+}} [[VEC_IN1:%.+]], i{{[0-9]+}}*{{.+}} [[T_VAR_IN1:%.+]], [2 x [[S_INT_TY]]]*{{.+}} [[S_ARR_IN1:%.+]], [[S_INT_TY]]*{{.+}} [[VAR_IN1:%.+]])
+// skip alloca of global_tid and bound_tid
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: {{.+}} = alloca i{{[0-9]+}}*,
+// CHECK: [[VEC_ADDR1:%.+]] = alloca [2 x i{{[0-9]+}}]*,
+// CHECK: [[T_VAR_ADDR1:%.+]] = alloca i{{[0-9]+}}*,
+// CHECK: [[S_ARR_ADDR1:%.+]] = alloca [2 x [[S_INT_TY]]]*,
+// CHECK: [[VAR_ADDR1:%.+]] = alloca [[S_INT_TY]]*,
+// skip loop variables
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: {{.+}} = alloca i{{[0-9]+}},
+// CHECK: [[OMP_IS_LAST1:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[T_VAR_PRIV1:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV1:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV1:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV1:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[TMP_PRIV1:%.+]] = alloca [[S_INT_TY]]*,
+
+// skip init of bound and global tid
+// CHECK: store i{{[0-9]+}}* {{.*}},
+// CHECK: store i{{[0-9]+}}* {{.*}},
+// copy from parameters to local address variables
+// CHECK: store [2 x i{{[0-9]+}}]* [[VEC_IN1]], [2 x i{{[0-9]+}}]** [[VEC_ADDR1]],
+// CHECK: store i{{[0-9]+}}* [[T_VAR_IN1]], i{{[0-9]+}}** [[T_VAR_ADDR1]],
+// CHECK: store [2 x [[S_INT_TY]]]* [[S_ARR_IN1]], [2 x [[S_INT_TY]]]** [[S_ARR_ADDR1]],
+// CHECK: store [[S_INT_TY]]* [[VAR_IN1]], [[S_INT_TY]]** [[VAR_ADDR1]],
+
+// load content of local address variables
+// CHECK: [[VEC_ADDR_REF1:%.+]] = load [2 x i{{[0-9]+}}]*, [2 x i{{[0-9]+}}]** [[VEC_ADDR1]],
+// CHECK: [[T_VAR_ADDR_REF1:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[T_VAR_ADDR1]],
+// CHECK: [[S_ARR_ADDR_REF1:%.+]] = load [2 x [[S_INT_TY]]]*, [2 x [[S_INT_TY]]]** [[S_ARR_ADDR1]],
+// CHECK-DAG: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[OMP_IS_LAST1]],
+// CHECK: [[VAR_ADDR1_REF:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[VAR_ADDR1]],
+// CHECK-DAG: store [[S_INT_TY]]* [[VAR_PRIV1]], [[S_INT_TY]]** [[TMP_PRIV1]],
+// CHECK: call void @__kmpc_for_static_init_4(
+// assignment: vec[i] = t_var;
+// CHECK: [[IV_VAL1:%.+]] =
+// CHECK: [[T_VAR_PRIV_VAL1:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV1]],
+// CHECK: [[VEC_PTR1:%.+]] = getelementptr inbounds [2 x i{{[0-9]+}}], [2 x i{{[0-9]+}}]* [[VEC_PRIV1]], i{{[0-9]+}} 0, i{{[0-9]+}} {{.+}}
+// CHECK: store i{{[0-9]+}} [[T_VAR_PRIV_VAL1]], i{{[0-9]+}}* [[VEC_PTR1]],
+
+// assignment: s_arr[i] = var;
+// CHECK-DAG: [[S_ARR_PTR1:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV1]],
+// CHECK-DAG: [[TMP_VAL1:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP_PRIV1]],
+// CHECK-DAG: [[S_ARR_PTR_BCAST1:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_PTR1]] to i8*
+// CHECK-DAG: [[TMP_VAL_BCAST1:%.+]] = bitcast [[S_INT_TY]]* [[TMP_VAL1]] to i8*
+// CHECK-DAG: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_PTR_BCAST1]], i8* [[TMP_VAL_BCAST1]],
+// CHECK: call void @__kmpc_for_static_fini(
+
+// lastprivates
+// CHECK: [[OMP_IS_LAST_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[OMP_IS_LAST1]],
+// CHECK: [[IS_LAST_IT:%.+]] = icmp ne i{{[0-9]+}} [[OMP_IS_LAST_VAL]], 0
+// CHECK: br i1 [[IS_LAST_IT]], label %[[OMP_LASTPRIV_BLOCK:.+]], label %[[OMP_LASTPRIV_DONE:.+]]
+
+// CHECK: [[OMP_LASTPRIV_BLOCK]]:
+// CHECK: [[T_VAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[T_VAR_PRIV1]],
+// CHECK: store i{{[0-9]+}} [[T_VAR_VAL]], i{{[0-9]+}}* [[T_VAR_ADDR_REF1]],
+// CHECK: [[BCAST_VEC_ADDR_REF:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_ADDR_REF1]] to i8*
+// CHECK: [[BCAST_VEC_PRIV:%.+]] = bitcast [2 x i{{[0-9]+}}]* [[VEC_PRIV1]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[BCAST_VEC_ADDR_REF]], i8* [[BCAST_VEC_PRIV]],
+// CHECK: [[S_ARR_BEGIN:%.+]] = getelementptr inbounds [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_ADDR_REF]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[S_ARR_PRIV_BCAST:%.+]] = bitcast [2 x [[S_INT_TY]]]* [[S_ARR_PRIV1]] to [[S_INT_TY]]*
+// CHECK: [[S_ARR_BEGIN_GEP:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_BEGIN]], i{{[0-9]+}} 2
+// CHECK: [[S_ARR_IS_EMPTY:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_BEGIN]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[S_ARR_IS_EMPTY]], label %[[S_ARR_COPY_DONE:.+]], label %[[S_ARR_COPY_BLOCK:.+]]
+// CHECK: [[S_ARR_COPY_BLOCK]]:
+// CHECK: [[S_ARR_SRC_EL:%.+]] = phi [[S_INT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_EL:%.+]] = phi [[S_INT_TY]]*{{.+}}
+// CHECK: [[S_ARR_DST_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_DST_EL]] to i8*
+// CHECK: [[S_ARR_SRC_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[S_ARR_SRC_EL]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[S_ARR_DST_BCAST]], i8* [[S_ARR_SRC_BCAST]]{{.+}})
+// CHECK: [[S_ARR_DST_NEXT:%.+]] = getelementptr [[S_INT_TY]], [[S_INT_TY]]* [[S_ARR_DST_EL]], i{{[0-9]+}} 1
+// CHECK: [[S_ARR_SRC_NEXT:%.+]] = getelementptr{{.+}}
+// CHECK: [[CPY_IS_FINISHED:%.+]] = icmp eq [[S_INT_TY]]* [[S_ARR_DST_NEXT]], [[S_ARR_BEGIN_GEP]]
+// CHECK: br i1 [[CPY_IS_FINISHED]], label %[[S_ARR_COPY_DONE]], label %[[S_ARR_COPY_BLOCK]]
+// CHECK: [[S_ARR_COPY_DONE]]:
+// CHECK: [[TMP_VAL1:%.+]] = load [[S_INT_TY]]*, [[S_INT_TY]]** [[TMP_PRIV1]],
+// CHECK: [[VAR_ADDR_REF_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[VAR_ADDR1_REF]] to i8*
+// CHECK: [[TMP_VAL1_BCAST:%.+]] = bitcast [[S_INT_TY]]* [[TMP_VAL1]] to i8*
+// CHECK: call void @llvm.memcpy.{{.+}}(i8* [[VAR_ADDR_REF_BCAST]], i8* [[TMP_VAL1_BCAST]],{{.+}})
+// CHECK: ret void
+#endif
diff --git a/test/OpenMP/teams_distribute_lastprivate_messages.cpp b/test/OpenMP/teams_distribute_lastprivate_messages.cpp
index b892141d50..6941197bee 100644
--- a/test/OpenMP/teams_distribute_lastprivate_messages.cpp
+++ b/test/OpenMP/teams_distribute_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/teams_distribute_loop_messages.cpp b/test/OpenMP/teams_distribute_loop_messages.cpp
index dbfd9ef03c..ea2604eebf 100644
--- a/test/OpenMP/teams_distribute_loop_messages.cpp
+++ b/test/OpenMP/teams_distribute_loop_messages.cpp
@@ -607,7 +607,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/teams_distribute_parallel_for_lastprivate_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_lastprivate_messages.cpp
index 5691af71f7..c5f457a0b2 100644
--- a/test/OpenMP/teams_distribute_parallel_for_lastprivate_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/teams_distribute_parallel_for_loop_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_loop_messages.cpp
index ea392fb93e..e0c315f513 100644
--- a/test/OpenMP/teams_distribute_parallel_for_loop_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_loop_messages.cpp
@@ -605,7 +605,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/teams_distribute_parallel_for_reduction_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_reduction_messages.cpp
index 73661618d2..889efd76cc 100644
--- a/test/OpenMP/teams_distribute_parallel_for_reduction_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_reduction_messages.cpp
@@ -19,9 +19,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/teams_distribute_parallel_for_shared_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_shared_messages.cpp
index 8edcd36643..1a1af09aa2 100644
--- a/test/OpenMP/teams_distribute_parallel_for_shared_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_shared_messages.cpp
@@ -84,7 +84,7 @@ int main(int argc, char **argv) {
#pragma omp teams distribute parallel for shared (S1) // expected-error {{'S1' does not refer to a value}}
for (int j=0; j<100; j++) foo();
#pragma omp target
- #pragma omp teams distribute parallel for shared (a, b, c, d, f)
+ #pragma omp teams distribute parallel for shared (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (int j=0; j<100; j++) foo();
#pragma omp target
#pragma omp teams distribute parallel for shared (argv[1]) // expected-error {{expected variable name}}
diff --git a/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp
index 674057712e..97b200bb16 100644
--- a/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_simd_aligned_messages.cpp
@@ -123,9 +123,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target
diff --git a/test/OpenMP/teams_distribute_parallel_for_simd_lastprivate_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_simd_lastprivate_messages.cpp
index fce59b924f..62f8559add 100644
--- a/test/OpenMP/teams_distribute_parallel_for_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/teams_distribute_parallel_for_simd_loop_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_simd_loop_messages.cpp
index 675ecb407f..0332562350 100644
--- a/test/OpenMP/teams_distribute_parallel_for_simd_loop_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_simd_loop_messages.cpp
@@ -607,7 +607,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/teams_distribute_parallel_for_simd_reduction_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_simd_reduction_messages.cpp
index 47494b94ff..b0522e8f69 100644
--- a/test/OpenMP/teams_distribute_parallel_for_simd_reduction_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_simd_reduction_messages.cpp
@@ -19,9 +19,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/teams_distribute_parallel_for_simd_shared_messages.cpp b/test/OpenMP/teams_distribute_parallel_for_simd_shared_messages.cpp
index f13146641a..1089555889 100644
--- a/test/OpenMP/teams_distribute_parallel_for_simd_shared_messages.cpp
+++ b/test/OpenMP/teams_distribute_parallel_for_simd_shared_messages.cpp
@@ -84,7 +84,7 @@ int main(int argc, char **argv) {
#pragma omp teams distribute parallel for simd shared (S1) // expected-error {{'S1' does not refer to a value}}
for (int j=0; j<100; j++) foo();
#pragma omp target
- #pragma omp teams distribute parallel for simd shared (a, b, c, d, f)
+ #pragma omp teams distribute parallel for simd shared (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (int j=0; j<100; j++) foo();
#pragma omp target
#pragma omp teams distribute parallel for simd shared (argv[1]) // expected-error {{expected variable name}}
diff --git a/test/OpenMP/teams_distribute_private_codegen.cpp b/test/OpenMP/teams_distribute_private_codegen.cpp
new file mode 100644
index 0000000000..06ec35a662
--- /dev/null
+++ b/test/OpenMP/teams_distribute_private_codegen.cpp
@@ -0,0 +1,236 @@
+// RUN: %clang_cc1 -DCHECK -verify -fopenmp -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 -DCHECK -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCHECK -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 -DCHECK -verify -fopenmp -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 -DCHECK -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCHECK -fopenmp -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
+
+// 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++ -std=c++11 -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
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+struct St {
+ int a, b;
+ St() : a(0), b(0) {}
+ St(const St &st) : a(st.a + st.b), b(0) {}
+ ~St() {}
+};
+
+volatile int g = 1212;
+volatile int &g1 = g;
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a + g) {}
+ S() : f(g) {}
+ S(const S &s, St t = St()) : f(s.f + t.a) {}
+ operator T() { return T(); }
+ ~S() {}
+};
+
+// CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float }
+// CHECK-DAG: [[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 distribute private(t_var, vec, s_arr, var)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ }
+ return T();
+}
+
+// CHECK-DAG: [[TEST:@.+]] = global [[S_FLOAT_TY]] zeroinitializer,
+S<float> test;
+// CHECK-DAG: [[T_VAR:@.+]] = global i{{[0-9]+}} 333,
+int t_var = 333;
+// CHECK-DAG: [[VEC:@.+]] = global [2 x i{{[0-9]+}}] [i{{[0-9]+}} 1, i{{[0-9]+}} 2],
+int vec[] = {1, 2};
+// CHECK-DAG: [[S_ARR:@.+]] = global [2 x [[S_FLOAT_TY]]] zeroinitializer,
+S<float> s_arr[] = {1, 2};
+// CHECK-DAG: [[VAR:@.+]] = global [[S_FLOAT_TY]] zeroinitializer,
+S<float> var(3);
+// CHECK-DAG: [[SIVAR:@.+]] = internal global i{{[0-9]+}} 0,
+
+int main() {
+ static int sivar;
+#ifdef LAMBDA
+ // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 3, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+ // LAMBDA: call void @[[LOFFL1:.+]](
+ // LAMBDA: ret
+#pragma omp target
+#pragma omp teams distribute private(g, g1, sivar)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void @[[LOFFL1]](i{{64|32}} {{%.+}}, i{{64|32}} {{%.+}})
+ // LAMBDA: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}} @[[LOUTL1:.+]] to {{.+}})
+ // LAMBDA: ret void
+
+ // LAMBDA: define internal void @[[LOUTL1]]({{.+}})
+ // Skip global, bound tid and loop vars
+ // LAMBDA: {{.+}} = alloca i32*,
+ // LAMBDA: {{.+}} = alloca i32*,
+ // LAMBDA: alloca i32,
+ // LAMBDA: alloca i32,
+ // LAMBDA: alloca i32,
+ // LAMBDA: alloca i32,
+ // LAMBDA: alloca i32,
+ // LAMBDA: [[G_PRIV:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: [[G1_PRIV:%.+]] = alloca i{{[0-9]+}}
+ // LAMBDA: [[TMP:%.+]] = alloca i{{[0-9]+}}*,
+ // LAMBDA: [[SIVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+ // LAMBDA: store{{.+}} [[G1_PRIV]], {{.+}} [[TMP]],
+
+ g = 1;
+ g1 = 1;
+ sivar = 2;
+ // LAMBDA: call void @__kmpc_for_static_init_4(
+ // LAMBDA-DAG: store{{.+}} 1, {{.+}} [[G_PRIV]],
+ // LAMBDA-DAG: store{{.+}} 2, {{.+}} [[SIVAR_PRIV]],
+ // LAMBDA-DAG: [[G1_REF:%.+]] = load{{.+}}, {{.+}} [[TMP]],
+ // LAMBDA-DAG: store{{.+}} 1, {{.+}} [[G1_REF]],
+ // 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;
+ sivar = 4;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+
+ // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]]
+ // LAMBDA: [[G1_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // LAMBDA: [[G1_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[G1_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 2, i{{[0-9]+}}* [[G1_REF]]
+ // LAMBDA: [[SIVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+ // LAMBDA: [[SIVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SIVAR_PTR_REF]]
+ // LAMBDA: store i{{[0-9]+}} 4, i{{[0-9]+}}* [[SIVAR_REF]]
+ }();
+ }
+ }();
+ return 0;
+#else
+#pragma omp target
+#pragma omp teams distribute private(t_var, vec, s_arr, var, sivar)
+ for (int i = 0; i < 2; ++i) {
+ vec[i] = t_var;
+ s_arr[i] = var;
+ sivar += i;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: define {{.*}}i{{[0-9]+}} @main()
+// CHECK: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 5, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+// CHECK: call void @[[OFFL1:.+]](i{{64|32}} %{{.+}})
+// CHECK: {{%.+}} = call{{.*}} i32 @[[TMAIN_INT:.+]]()
+// CHECK: ret
+
+// CHECK: define{{.*}} void @[[OFFL1]]({{.+}})
+// CHECK: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}} @[[OUTL1:.+]] to {{.+}})
+// CHECK: ret void
+
+// CHECK: define internal void @[[OUTL1]]({{.+}})
+// Skip global, bound tid and loop vars
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: {{.+}} = alloca i32,
+// CHECK: {{.+}} = alloca i32,
+// CHECK: {{.+}} = alloca i32,
+// CHECK: {{.+}} = alloca i32,
+// CHECK: {{.+}} = alloca i32,
+// 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: [[SIVAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: alloca i32,
+
+// private(s_arr)
+// CHECK-DAG: [[S_ARR_PRIV_BGN:%.+]] = getelementptr{{.*}} [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_PTR_ALLOC:%.+]] = phi{{.+}} [ [[S_ARR_PRIV_BGN]], {{.+}} ], [ [[S_ARR_NEXT:%.+]], {{.+}} ]
+// CHECK-DAG: call void @{{.+}}({{.+}} [[S_ARR_PTR_ALLOC]])
+// CHECK-DAG: [[S_ARR_NEXT]] = getelementptr {{.+}} [[S_ARR_PTR_ALLOC]],
+
+// private(var)
+// CHECK-DAG: call void @{{.+}}({{.+}} [[VAR_PRIV]])
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK-DAG: {{.+}} = {{.+}} [[T_VAR_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[VEC_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[S_ARR_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[VAR_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[SIVAR_PRIV]]
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+
+// CHECK: define{{.*}} i{{[0-9]+}} @[[TMAIN_INT]]()
+// CHECK: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 0,
+// CHECK: call void @[[TOFFL1:.+]]()
+// CHECK: ret
+
+// CHECK: define {{.*}}void @[[TOFFL1]]()
+// CHECK: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 0, {{.+}} @[[TOUTL1:.+]] to {{.+}})
+// CHECK: ret void
+
+// CHECK: define internal void @[[TOUTL1]]({{.+}})
+// Skip global, bound tid and loop vars
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: {{.+}} = alloca i32*,
+// 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: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[TMP:%.+]] = alloca [[S_INT_TY]]*,
+// CHECK: alloca i32,
+
+// private(s_arr)
+// CHECK-DAG: [[S_ARR_PRIV_BGN:%.+]] = getelementptr{{.*}} [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_PTR_ALLOC:%.+]] = phi{{.+}} [ [[S_ARR_PRIV_BGN]], {{.+}} ], [ [[S_ARR_NEXT:%.+]], {{.+}} ]
+// CHECK-DAG: call void @{{.+}}({{.+}} [[S_ARR_PTR_ALLOC]])
+// CHECK-DAG: [[S_ARR_NEXT]] = getelementptr {{.+}} [[S_ARR_PTR_ALLOC]],
+
+// CHECK-DAG: [[S_ARR_PRIV_BGN:%.+]] = getelementptr{{.*}} [2 x [[S_INT_TY]]], [2 x [[S_INT_TY]]]* [[S_ARR_PRIV]],
+// CHECK-DAG: [[S_ARR_PTR_ALLOC:%.+]] = phi{{.+}} [ [[S_ARR_PRIV_BGN]], {{.+}} ], [ [[S_ARR_NEXT:%.+]], {{.+}} ]
+// CHECK-DAG: call void @{{.+}}({{.+}} [[S_ARR_PTR_ALLOC]])
+// CHECK-DAG: [[S_ARR_NEXT]] = getelementptr {{.+}} [[S_ARR_PTR_ALLOC]],
+
+// private(var)
+// CHECK-DAG: call void @{{.+}}({{.+}} [[VAR_PRIV]])
+// CHECK-DAG: store{{.+}} [[VAR_PRIV]], {{.+}} [[TMP]]
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK-DAG: {{.+}} = {{.+}} [[T_VAR_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[VEC_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[S_ARR_PRIV]]
+// CHECK-DAG: {{.+}} = {{.+}} [[TMP]]
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: ret void
+
+#endif
diff --git a/test/OpenMP/teams_distribute_reduction_codegen.cpp b/test/OpenMP/teams_distribute_reduction_codegen.cpp
new file mode 100644
index 0000000000..3688b10a95
--- /dev/null
+++ b/test/OpenMP/teams_distribute_reduction_codegen.cpp
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 -DCHECK -verify -fopenmp -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 -DCHECK -fopenmp -x c++ -std=c++11 -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCHECK -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 -DCHECK -verify -fopenmp -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 -DCHECK -fopenmp -x c++ -std=c++11 -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -DCHECK -fopenmp -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
+
+// 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++ -std=c++11 -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
+
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+template <typename T>
+T tmain() {
+ T t_var = T();
+ T vec[] = {1, 2};
+#pragma omp target
+#pragma omp teams distribute reduction(+: t_var)
+ for (int i = 0; i < 2; ++i) {
+ t_var += (T) i;
+ }
+ return T();
+}
+
+int main() {
+ static int sivar;
+#ifdef LAMBDA
+ // LAMBDA: [[RED_VAR:@.+]] = common global [8 x {{.+}}] zeroinitializer
+
+ // LAMBDA-LABEL: @main
+ // LAMBDA: call void [[OUTER_LAMBDA:@.+]](
+ [&]() {
+ // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
+ // LAMBDA: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 1, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+ // LAMBDA: call void @[[LOFFL1:.+]](
+ // LAMBDA: ret
+#pragma omp target
+#pragma omp teams distribute reduction(+: sivar)
+ for (int i = 0; i < 2; ++i) {
+ // LAMBDA: define{{.*}} internal{{.*}} void @[[LOFFL1]](i{{64|32}} [[SIVAR_ARG:%.+]])
+ // LAMBDA: [[SIVAR_ADDR:%.+]] = alloca i{{.+}},
+ // LAMBDA: store{{.+}} [[SIVAR_ARG]], {{.+}} [[SIVAR_ADDR]],
+ // LAMBDA: [[SIVAR_CONV:%.+]] = bitcast{{.+}} [[SIVAR_ADDR]] to
+ // LAMBDA: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[LOUTL1:.+]] to {{.+}}, {{.+}} [[SIVAR_CONV]])
+ // LAMBDA: ret void
+
+ // LAMBDA: define internal void @[[LOUTL1]]({{.+}}, {{.+}}, {{.+}} [[SIVAR_ARG:%.+]])
+ // Skip global and bound tid vars
+ // LAMBDA: {{.+}} = alloca i32*,
+ // LAMBDA: {{.+}} = alloca i32*,
+ // LAMBDA: [[SIVAR_ADDR:%.+]] = alloca i{{.+}}*,
+ // LAMBDA: [[SIVAR_PRIV:%.+]] = alloca i{{.+}},
+ // LAMBDA: [[RED_LIST:%.+]] = alloca [1 x {{.+}}],
+ // LAMBDA: store{{.+}} [[SIVAR_ARG]], {{.+}} [[SIVAR_ADDR]],
+ // LAMBDA: [[SIVAR_REF:%.+]] = load{{.+}}, {{.+}} [[SIVAR_ADDR]]
+ // LAMBDA: store{{.+}} 0, {{.+}} [[SIVAR_PRIV]],
+
+ // LAMBDA: call void @__kmpc_for_static_init_4(
+ // LAMBDA: store{{.+}}, {{.+}} [[SIVAR_PRIV]],
+ // LAMBDA: call void [[INNER_LAMBDA:@.+]](
+ // LAMBDA: call void @__kmpc_for_static_fini(
+ // LAMBDA: [[RED_LIST_GEP:%.+]] = getelementptr{{.+}} [[RED_LIST]],
+ // LAMBDA: [[SIVAR_PRIV_CAST:%.+]] = bitcast{{.+}} [[SIVAR_PRIV]] to
+ // LAMBDA: store{{.+}} [[SIVAR_PRIV_CAST]], {{.+}} [[RED_LIST_GEP]],
+ // LAMBDA: [[RED_LIST_BCAST:%.+]] = bitcast{{.+}} [[RED_LIST]] to
+ // LAMBDA: [[K_RED_RET:%.+]] = call{{.+}} @__kmpc_reduce({{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}} [[RED_LIST_BCAST]], {{.+}} [[RED_FUN:@.+]], {{.+}} [[RED_VAR]])
+ // LAMBDA: switch{{.+}} [[K_RED_RET]], label{{.+}} [
+ // LAMBDA: {{.+}}, label %[[CASE1:.+]]
+ // LAMBDA: {{.+}}, label %[[CASE2:.+]]
+ // LAMBDA: ]
+ // LAMBDA: [[CASE1]]:
+ // LAMBDA-DAG: [[SIVAR_VAL:%.+]] = load{{.+}}, {{.+}} [[SIVAR_REF]],
+ // LAMBDA-DAG: [[SIVAR_PRIV_VAL:%.+]] = load{{.+}}, {{.+}} [[SIVAR_PRIV]],
+ // LAMBDA-DAG: [[SIVAR_INC:%.+]] = add{{.+}} [[SIVAR_VAL]], [[SIVAR_PRIV_VAL]]
+ // LAMBDA: store{{.+}} [[SIVAR_INC]], {{.+}} [[SIVAR_REF]],
+ // LAMBDA: call void @__kmpc_end_reduce({{.+}}, {{.+}}, {{.+}} [[RED_VAR]])
+ // LAMBDA: br
+ // LAMBDA: [[CASE2]]:
+ // LAMBDA-DAG: [[SIVAR_PRIV_VAL:%.+]] = load{{.+}}, {{.+}} [[SIVAR_PRIV]],
+ // LAMBDA-DAG: [[ATOMIC_RES:%.+]] = atomicrmw add{{.+}} [[SIVAR_REF]], {{.+}} [[SIVAR_PRIV_VAL]]
+ // LAMBDA: call void @__kmpc_end_reduce({{.+}}, {{.+}}, {{.+}} [[RED_VAR]])
+ // LAMBDA: br
+
+ sivar += i;
+
+ [&]() {
+ // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
+ // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
+
+ sivar += 4;
+ // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
+
+ // LAMBDA: [[SIVAR_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // LAMBDA: [[SIVAR_REF:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[SIVAR_PTR_REF]]
+ // LAMBDA: [[SIVAR_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[SIVAR_REF]]
+ // LAMBDA: [[SIVAR_INC:%.+]] = add{{.+}} [[SIVAR_VAL]], 4
+ // LAMBDA: store i{{[0-9]+}} [[SIVAR_INC]], i{{[0-9]+}}* [[SIVAR_REF]]
+ }();
+ }
+ }();
+ return 0;
+#else
+#pragma omp target
+#pragma omp teams distribute reduction(+: sivar)
+ for (int i = 0; i < 2; ++i) {
+ sivar += i;
+ }
+ return tmain<int>();
+#endif
+}
+
+// CHECK: [[RED_VAR:@.+]] = common global [8 x {{.+}}] zeroinitializer
+
+// CHECK: define {{.*}}i{{[0-9]+}} @main()
+// CHECK: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 1, i8** %{{[^,]+}}, i8** %{{[^,]+}}, i{{64|32}}* {{.+}}@{{[^,]+}}, i32 0, i32 0), i32* {{.+}}@{{[^,]+}}, i32 0, i32 0))
+// CHECK: call void @[[OFFL1:.+]](i{{64|32}} %{{.+}})
+// CHECK: {{%.+}} = call{{.*}} i32 @[[TMAIN_INT:.+]]()
+// CHECK: ret
+
+// CHECK: define{{.*}} void @[[OFFL1]](i{{64|32}} [[SIVAR_ARG:%.+]])
+// CHECK: [[SIVAR_ADDR:%.+]] = alloca i{{.+}},
+// CHECK: store{{.+}} [[SIVAR_ARG]], {{.+}} [[SIVAR_ADDR]],
+// CHECK-64: [[SIVAR_CONV:%.+]] = bitcast{{.+}} [[SIVAR_ADDR]] to
+// CHECK-64: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTL1:.+]] to {{.+}}, {{.+}} [[SIVAR_CONV]])
+// CHECK-32: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[OUTL1:.+]] to {{.+}}, {{.+}} [[SIVAR_ADDR]])
+// CHECK: ret void
+
+// CHECK: define internal void @[[OUTL1]]({{.+}}, {{.+}}, {{.+}} [[SIVAR_ARG:%.+]])
+// Skip global and bound tid vars
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: [[SIVAR_ADDR:%.+]] = alloca i{{.+}}*,
+// CHECK: [[SIVAR_PRIV:%.+]] = alloca i{{.+}},
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x {{.+}}],
+// CHECK: store{{.+}} [[SIVAR_ARG]], {{.+}} [[SIVAR_ADDR]],
+// CHECK: [[SIVAR_REF:%.+]] = load{{.+}}, {{.+}} [[SIVAR_ADDR]]
+// CHECK: store{{.+}} 0, {{.+}} [[SIVAR_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: store{{.+}}, {{.+}} [[SIVAR_PRIV]],
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: [[RED_LIST_GEP:%.+]] = getelementptr{{.+}} [[RED_LIST]],
+// CHECK: [[SIVAR_PRIV_CAST:%.+]] = bitcast{{.+}} [[SIVAR_PRIV]] to
+// CHECK: store{{.+}} [[SIVAR_PRIV_CAST]], {{.+}} [[RED_LIST_GEP]],
+// CHECK: [[RED_LIST_BCAST:%.+]] = bitcast{{.+}} [[RED_LIST]] to
+// CHECK: [[K_RED_RET:%.+]] = call{{.+}} @__kmpc_reduce({{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}} [[RED_LIST_BCAST]], {{.+}} [[RED_FUN:@.+]], {{.+}} [[RED_VAR]])
+// CHECK: switch{{.+}} [[K_RED_RET]], label{{.+}} [
+// CHECK: {{.+}}, label %[[CASE1:.+]]
+// CHECK: {{.+}}, label %[[CASE2:.+]]
+// CHECK: ]
+// CHECK: [[CASE1]]:
+// CHECK-DAG: [[SIVAR_VAL:%.+]] = load{{.+}}, {{.+}} [[SIVAR_REF]],
+// CHECK-DAG: [[SIVAR_PRIV_VAL:%.+]] = load{{.+}}, {{.+}} [[SIVAR_PRIV]],
+// CHECK-DAG: [[SIVAR_INC:%.+]] = add{{.+}} [[SIVAR_VAL]], [[SIVAR_PRIV_VAL]]
+// CHECK: store{{.+}} [[SIVAR_INC]], {{.+}} [[SIVAR_REF]],
+// CHECK: call void @__kmpc_end_reduce({{.+}}, {{.+}}, {{.+}} [[RED_VAR]])
+// CHECK: br
+// CHECK: [[CASE2]]:
+// CHECK-DAG: [[SIVAR_PRIV_VAL:%.+]] = load{{.+}}, {{.+}} [[SIVAR_PRIV]],
+// CHECK-DAG: [[ATOMIC_RES:%.+]] = atomicrmw add{{.+}} [[SIVAR_REF]], {{.+}} [[SIVAR_PRIV_VAL]]
+// CHECK: call void @__kmpc_end_reduce({{.+}}, {{.+}}, {{.+}} [[RED_VAR]])
+// CHECK: br
+
+
+// CHECK: define{{.*}} i{{[0-9]+}} @[[TMAIN_INT]]()
+// CHECK: call i32 @__tgt_target(i32 -1, i8* @{{[^,]+}}, i32 1,
+// CHECK: call void @[[TOFFL1:.+]]({{.+}})
+// CHECK: ret
+
+// CHECK: define{{.*}} void @[[TOFFL1]](i{{64|32}} [[TVAR_ARG:%.+]])
+// CHECK: [[TVAR_ADDR:%.+]] = alloca i{{.+}},
+// CHECK: store{{.+}} [[TVAR_ARG]], {{.+}} [[TVAR_ADDR]],
+// CHECK-64: [[TVAR_CONV:%.+]] = bitcast{{.+}} [[TVAR_ADDR]] to
+// CHECK-64: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[TOUTL1:.+]] to {{.+}}, {{.+}} [[TVAR_CONV]])
+// CHECK-32: call void {{.+}} @__kmpc_fork_teams({{.+}}, i32 1, {{.+}} @[[TOUTL1:.+]] to {{.+}}, {{.+}} [[TVAR_ADDR]])
+// CHECK: ret void
+
+// CHECK: define internal void @[[TOUTL1]]({{.+}}, {{.+}}, {{.+}} [[TVAR_ARG:%.+]])
+// Skip global and bound tid vars
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: {{.+}} = alloca i32*,
+// CHECK: [[TVAR_ADDR:%.+]] = alloca i{{.+}}*,
+// CHECK: [[TVAR_PRIV:%.+]] = alloca i{{.+}},
+// CHECK: [[RED_LIST:%.+]] = alloca [1 x {{.+}}],
+// CHECK: store{{.+}} [[TVAR_ARG]], {{.+}} [[TVAR_ADDR]],
+// CHECK: [[TVAR_REF:%.+]] = load{{.+}}, {{.+}} [[TVAR_ADDR]]
+// CHECK: store{{.+}} 0, {{.+}} [[TVAR_PRIV]],
+
+// CHECK: call void @__kmpc_for_static_init_4(
+// CHECK: store{{.+}}, {{.+}} [[TVAR_PRIV]],
+// CHECK: call void @__kmpc_for_static_fini(
+// CHECK: [[RED_LIST_GEP:%.+]] = getelementptr{{.+}} [[RED_LIST]],
+// CHECK: [[TVAR_PRIV_CAST:%.+]] = bitcast{{.+}} [[TVAR_PRIV]] to
+// CHECK: store{{.+}} [[TVAR_PRIV_CAST]], {{.+}} [[RED_LIST_GEP]],
+// CHECK: [[RED_LIST_BCAST:%.+]] = bitcast{{.+}} [[RED_LIST]] to
+// CHECK: [[K_RED_RET:%.+]] = call{{.+}} @__kmpc_reduce({{.+}}, {{.+}}, {{.+}}, {{.+}}, {{.+}} [[RED_LIST_BCAST]], {{.+}} [[RED_FUN:@.+]], {{.+}} [[RED_VAR]])
+// CHECK: switch{{.+}} [[K_RED_RET]], label{{.+}} [
+// CHECK: {{.+}}, label %[[CASE1:.+]]
+// CHECK: {{.+}}, label %[[CASE2:.+]]
+// CHECK: ]
+// CHECK: [[CASE1]]:
+// CHECK-DAG: [[TVAR_VAL:%.+]] = load{{.+}}, {{.+}} [[TVAR_REF]],
+// CHECK-DAG: [[TVAR_PRIV_VAL:%.+]] = load{{.+}}, {{.+}} [[TVAR_PRIV]],
+// CHECK-DAG: [[TVAR_INC:%.+]] = add{{.+}} [[TVAR_VAL]], [[TVAR_PRIV_VAL]]
+// CHECK: store{{.+}} [[TVAR_INC]], {{.+}} [[TVAR_REF]],
+// CHECK: call void @__kmpc_end_reduce({{.+}}, {{.+}}, {{.+}} [[RED_VAR]])
+// CHECK: br
+// CHECK: [[CASE2]]:
+// CHECK-DAG: [[TVAR_PRIV_VAL:%.+]] = load{{.+}}, {{.+}} [[TVAR_PRIV]],
+// CHECK-DAG: [[ATOMIC_RES:%.+]] = atomicrmw add{{.+}} [[TVAR_REF]], {{.+}} [[TVAR_PRIV_VAL]]
+// CHECK: call void @__kmpc_end_reduce({{.+}}, {{.+}}, {{.+}} [[RED_VAR]])
+// CHECK: br
+
+#endif
diff --git a/test/OpenMP/teams_distribute_reduction_messages.cpp b/test/OpenMP/teams_distribute_reduction_messages.cpp
index d0a6d296c0..f11236f0ce 100644
--- a/test/OpenMP/teams_distribute_reduction_messages.cpp
+++ b/test/OpenMP/teams_distribute_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/teams_distribute_shared_messages.cpp b/test/OpenMP/teams_distribute_shared_messages.cpp
index b9e096ce1c..ecf6f2e036 100644
--- a/test/OpenMP/teams_distribute_shared_messages.cpp
+++ b/test/OpenMP/teams_distribute_shared_messages.cpp
@@ -84,7 +84,7 @@ int main(int argc, char **argv) {
#pragma omp teams distribute shared (S1) // expected-error {{'S1' does not refer to a value}}
for (int j=0; j<100; j++) foo();
#pragma omp target
- #pragma omp teams distribute shared (a, b, c, d, f)
+ #pragma omp teams distribute shared (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (int j=0; j<100; j++) foo();
#pragma omp target
#pragma omp teams distribute shared (argv[1]) // expected-error {{expected variable name}}
diff --git a/test/OpenMP/teams_distribute_simd_aligned_messages.cpp b/test/OpenMP/teams_distribute_simd_aligned_messages.cpp
index 95a85b2d0d..885432bb9a 100644
--- a/test/OpenMP/teams_distribute_simd_aligned_messages.cpp
+++ b/test/OpenMP/teams_distribute_simd_aligned_messages.cpp
@@ -123,9 +123,8 @@ S3 h; // expected-note 2 {{'h' defined here}}
template<class I, class C> int foomain(I argc, C **argv) {
I e(argc);
I g(argc);
- int i; // expected-note {{declared here}} expected-note {{'i' defined here}}
- // expected-note@+2 {{declared here}}
- // expected-note@+1 {{reference to 'i' is not a constant expression}}
+ int i; // expected-note {{'i' defined here}}
+ // expected-note@+1 {{declared here}}
int &j = i;
#pragma omp target
diff --git a/test/OpenMP/teams_distribute_simd_lastprivate_messages.cpp b/test/OpenMP/teams_distribute_simd_lastprivate_messages.cpp
index 4c715bf2ce..8bdb3805ab 100644
--- a/test/OpenMP/teams_distribute_simd_lastprivate_messages.cpp
+++ b/test/OpenMP/teams_distribute_simd_lastprivate_messages.cpp
@@ -18,9 +18,9 @@ public:
const S2 &operator =(const S2&) const;
S2 &operator =(const S2&);
static float S2s; // expected-note {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note {{static data member is predetermined as shared}}
};
-const float S2::S2sc = 0; // expected-note {{static data member is predetermined as shared}}
+const float S2::S2sc = 0;
const S2 b;
const S2 ba[5];
class S3 {
diff --git a/test/OpenMP/teams_distribute_simd_loop_messages.cpp b/test/OpenMP/teams_distribute_simd_loop_messages.cpp
index 742bc7451e..81fbfe860a 100644
--- a/test/OpenMP/teams_distribute_simd_loop_messages.cpp
+++ b/test/OpenMP/teams_distribute_simd_loop_messages.cpp
@@ -607,7 +607,7 @@ void test_with_template() {
t1.dotest_lt(begin, end);
t2.dotest_lt(begin, end); // expected-note {{in instantiation of member function 'TC<GoodIter, -100>::dotest_lt' requested here}}
dotest_gt(begin, end); // expected-note {{in instantiation of function template specialization 'dotest_gt<GoodIter, 0>' requested here}}
- dotest_gt<unsigned, -10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, -10>' requested here}}
+ dotest_gt<unsigned, 10>(0, 100); // expected-note {{in instantiation of function template specialization 'dotest_gt<unsigned int, 10>' requested here}}
}
void test_loop_break() {
diff --git a/test/OpenMP/teams_distribute_simd_reduction_messages.cpp b/test/OpenMP/teams_distribute_simd_reduction_messages.cpp
index 879ec688dc..09d22bd4bd 100644
--- a/test/OpenMP/teams_distribute_simd_reduction_messages.cpp
+++ b/test/OpenMP/teams_distribute_simd_reduction_messages.cpp
@@ -19,9 +19,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/teams_distribute_simd_shared_messages.cpp b/test/OpenMP/teams_distribute_simd_shared_messages.cpp
index cd963e8469..6b06f5b6f2 100644
--- a/test/OpenMP/teams_distribute_simd_shared_messages.cpp
+++ b/test/OpenMP/teams_distribute_simd_shared_messages.cpp
@@ -84,7 +84,7 @@ int main(int argc, char **argv) {
#pragma omp teams distribute simd shared (S1) // expected-error {{'S1' does not refer to a value}}
for (int j=0; j<100; j++) foo();
#pragma omp target
- #pragma omp teams distribute simd shared (a, b, c, d, f)
+ #pragma omp teams distribute simd shared (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
for (int j=0; j<100; j++) foo();
#pragma omp target
#pragma omp teams distribute simd shared (argv[1]) // expected-error {{expected variable name}}
diff --git a/test/OpenMP/teams_reduction_messages.cpp b/test/OpenMP/teams_reduction_messages.cpp
index 9974c147b7..7aef97730d 100644
--- a/test/OpenMP/teams_reduction_messages.cpp
+++ b/test/OpenMP/teams_reduction_messages.cpp
@@ -25,9 +25,9 @@ public:
S2() : a(0) {}
S2(S2 &s2) : a(s2.a) {}
static float S2s; // expected-note 2 {{static data member is predetermined as shared}}
- static const float S2sc;
+ static const float S2sc; // expected-note 2 {{'S2sc' declared here}}
};
-const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
+const float S2::S2sc = 0;
S2 b; // expected-note 3 {{'b' defined here}}
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
class S3 {
diff --git a/test/OpenMP/teams_shared_messages.cpp b/test/OpenMP/teams_shared_messages.cpp
index e14ba1e32f..6b013d099d 100644
--- a/test/OpenMP/teams_shared_messages.cpp
+++ b/test/OpenMP/teams_shared_messages.cpp
@@ -84,7 +84,7 @@ int main(int argc, char **argv) {
#pragma omp teams shared (S1) // expected-error {{'S1' does not refer to a value}}
foo();
#pragma omp target
- #pragma omp teams shared (a, b, c, d, f)
+ #pragma omp teams shared (a, b, c, d, f) // expected-error {{incomplete type 'S1' where a complete type is required}}
foo();
#pragma omp target
#pragma omp teams shared (argv[1]) // expected-error {{expected variable name}}
diff --git a/test/OpenMP/varargs.cpp b/test/OpenMP/varargs.cpp
new file mode 100644
index 0000000000..7738f83fab
--- /dev/null
+++ b/test/OpenMP/varargs.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -verify -fopenmp %s
+void f(int a, ...) {
+#pragma omp parallel for
+ for (int i = 0; i < 100; ++i) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, a); // expected-error {{'va_start' cannot be used in a captured statement}}
+ }
+};
diff --git a/test/OpenMP/vla_crash.c b/test/OpenMP/vla_crash.c
new file mode 100644
index 0000000000..0dcba5503e
--- /dev/null
+++ b/test/OpenMP/vla_crash.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -verify -triple powerpc64le-unknown-linux-gnu -fopenmp -x c -emit-llvm %s -o - | FileCheck %s
+
+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**** {{[^,]+}})
+
+// CHECK-LABEL: bar
+void bar(int n, int *a) {
+ // CHECK: [[N:%.+]] = alloca i32,
+ // CHECK: [[A:%.+]] = alloca i32*,
+ // CHECK: [[P:%.+]] = alloca i32*,
+ // CHECK: @__kmpc_global_thread_num
+ // CHECK: [[BC:%.+]] = bitcast i32** [[A]] to i32*
+ // CHECK: store i32* [[BC]], i32** [[P]],
+ // CHECK: call void @__kmpc_serialized_parallel
+ // CHECK: call void [[OUTLINED:@[^(]+]](i32* %{{[^,]+}}, i32* %{{[^,]+}}, i64 %{{[^,]+}}, i32** [[P]], i32** [[A]])
+ // CHECK: call void @__kmpc_end_serialized_parallel
+ // CHECK: ret void
+ // expected-warning@+1 {{incompatible pointer types initializing 'int (*)[n]' with an expression of type 'int **'}}
+ int(*p)[n] = &a;
+#pragma omp parallel if(0)
+ // expected-warning@+1 {{comparison of distinct pointer types ('int (*)[n]' and 'int **')}}
+ if (p == &a) {
+ }
+}
+
+// CHECK: define internal void [[OUTLINED]](i32* {{[^,]+}}, i32* {{[^,]+}}, i64 {{[^,]+}}, i32** {{[^,]+}}, i32** {{[^,]+}})
diff --git a/test/PCH/attrs.c b/test/PCH/attrs.c
index 3f34d4d009..3bf660cf28 100644
--- a/test/PCH/attrs.c
+++ b/test/PCH/attrs.c
@@ -13,8 +13,9 @@ int g(int) __attribute__((abi_tag("foo", "bar", "baz"), no_sanitize("address", "
#else
+float f(float);
double f(double); // expected-error{{overloadable}}
- // expected-note@11{{previous overload}}
+ // expected-note@-2{{previous unmarked overload}}
void h() { g(0); }
#endif
diff --git a/test/PCH/case-insensitive-include.c b/test/PCH/case-insensitive-include.c
index 1dcda273c2..c721225397 100644
--- a/test/PCH/case-insensitive-include.c
+++ b/test/PCH/case-insensitive-include.c
@@ -1,18 +1,19 @@
// REQUIRES: case-insensitive-filesystem
// Test this without pch.
-// RUN: cp %S/Inputs/case-insensitive-include.h %T
-// RUN: %clang_cc1 -Wno-nonportable-include-path -fsyntax-only %s -include %s -I %T -verify
+// RUN: mkdir -p %t-dir
+// RUN: cp %S/Inputs/case-insensitive-include.h %t-dir
+// RUN: %clang_cc1 -Wno-nonportable-include-path -fsyntax-only %s -include %s -I %t-dir -verify
// Test with pch.
-// RUN: %clang_cc1 -emit-pch -o %t.pch %s -I %T
+// RUN: %clang_cc1 -emit-pch -o %t.pch %s -I %t-dir
// Modify inode of the header.
-// RUN: cp %T/case-insensitive-include.h %t.copy
-// RUN: touch -r %T/case-insensitive-include.h %t.copy
-// RUN: mv %t.copy %T/case-insensitive-include.h
+// RUN: cp %t-dir/case-insensitive-include.h %t.copy
+// RUN: touch -r %t-dir/case-insensitive-include.h %t.copy
+// RUN: mv %t.copy %t-dir/case-insensitive-include.h
-// RUN: %clang_cc1 -fsyntax-only %s -include-pch %t.pch -I %T -verify
+// RUN: %clang_cc1 -fsyntax-only %s -include-pch %t.pch -I %t-dir -verify
// expected-no-diagnostics
diff --git a/test/PCH/coroutines.cpp b/test/PCH/coroutines.cpp
new file mode 100644
index 0000000000..46a2872420
--- /dev/null
+++ b/test/PCH/coroutines.cpp
@@ -0,0 +1,77 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %s -verify -std=c++1z -fcoroutines-ts %s
+
+// Test with pch.
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t -verify -std=c++1z -fcoroutines-ts %s
+
+#ifndef HEADER
+#define HEADER
+
+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 *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) noexcept;
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+}
+
+struct suspend_always {
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
+};
+
+template <typename... Args> struct std::experimental::coroutine_traits<void, Args...> {
+ struct promise_type {
+ void get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ suspend_always yield_value(int) noexcept;
+ promise_type();
+ ~promise_type() noexcept;
+ void unhandled_exception() noexcept;
+ };
+};
+
+template <typename... Args> struct std::experimental::coroutine_traits<int, Args...> {
+ struct promise_type {
+ int get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_value(int) noexcept;
+ promise_type();
+ ~promise_type() noexcept;
+ void unhandled_exception() noexcept;
+ };
+};
+
+template <typename T>
+void f(T x) { // checks coawait_expr and coroutine_body_stmt
+ co_yield 42; // checks coyield_expr
+ co_await x; // checks dependent_coawait
+ co_return; // checks coreturn_stmt
+}
+
+template <typename T>
+int f2(T x) { // checks coawait_expr and coroutine_body_stmt
+ co_return x; // checks coreturn_stmt with expr
+}
+
+#else
+
+// expected-no-diagnostics
+void g() {
+ f(suspend_always{});
+ f2(42);
+}
+
+#endif
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 0000000000..29c06f7cc7
--- /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-templates.cpp b/test/PCH/cxx-templates.cpp
index d50eee0623..e241701f50 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -108,3 +108,11 @@ namespace cyclic_module_load {
template int local_extern::f<int[]>(); // expected-note {{in instantiation of}}
#endif
template int local_extern::g<int[]>();
+
+namespace MemberSpecializationLocation {
+#ifndef NO_ERRORS
+ // expected-note@cxx-templates.h:* {{previous}}
+ template<> float A<int>::n; // expected-error {{redeclaration of 'n' with a different type}}
+#endif
+ int k = A<int>::n;
+}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index c4a8447276..68b252e797 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -358,3 +358,6 @@ namespace rdar15468709c {
}
}
+namespace MemberSpecializationLocation {
+ template<typename T> struct A { static int n; };
+}
diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp
index b0f1d9d2c3..01b9e9302d 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 1d7d40450f..0a4bd09c36 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/cxx11-lambdas.mm b/test/PCH/cxx11-lambdas.mm
index 1f568f05e1..9628d12aa1 100644
--- a/test/PCH/cxx11-lambdas.mm
+++ b/test/PCH/cxx11-lambdas.mm
@@ -39,7 +39,7 @@ int init_capture(T t) {
}
struct X {
- template <typename T> X(T);
+ template <typename T> X(T) {}
};
struct Y { Y(const X &x = [] {}); };
diff --git a/test/PCH/cxx2a-bitfield-init.cpp b/test/PCH/cxx2a-bitfield-init.cpp
new file mode 100644
index 0000000000..344f3cb912
--- /dev/null
+++ b/test/PCH/cxx2a-bitfield-init.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++2a -include %s -verify %s
+// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s -DPCH
+
+#ifndef HEADER
+#define HEADER
+
+struct S {
+ unsigned int n : 5 = 49; // expected-warning {{changes value}}
+};
+
+int a;
+template<bool B> struct T {
+ int m : B ? 8 : a = 42;
+};
+
+#else
+
+// expected-error@-5 {{constant expression}} expected-note@-5 {{cannot modify}}
+
+static_assert(S().n == 17);
+static_assert(T<true>().m == 0);
+int q = T<false>().m; // expected-note {{instantiation of}}
+
+#endif
diff --git a/test/PCH/emit-dependencies.c b/test/PCH/emit-dependencies.c
new file mode 100644
index 0000000000..c4bccf8bb1
--- /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/include-timestamp.cpp b/test/PCH/include-timestamp.cpp
index d7d0fab13a..36b887aee8 100644
--- a/test/PCH/include-timestamp.cpp
+++ b/test/PCH/include-timestamp.cpp
@@ -1,23 +1,25 @@
// Test that the timestamp is not included in the produced pch file with
// -fno-pch-timestamp.
+// RUN: mkdir -p %t-dir
+
// Copying files allow for read-only checkouts to run this test.
-// RUN: cp %S/Inputs/pragma-once2-pch.h %T
-// RUN: cp %S/Inputs/pragma-once2.h %T
-// RUN: cp %s %t1.cpp
+// RUN: cp %S/Inputs/pragma-once2-pch.h %t-dir
+// RUN: cp %S/Inputs/pragma-once2.h %t-dir
+// RUN: cp %s %t-dir/1.cpp
// Check timestamp is included by default.
-// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %T/pragma-once2-pch.h
-// RUN: touch -m -a -t 201008011501 %T/pragma-once2.h
-// RUN: not %clang_cc1 -include-pch %t %t1.cpp 2>&1 | FileCheck -check-prefix=CHECK-TIMESTAMP %s
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %t-dir/pragma-once2-pch.h
+// RUN: touch -m -a -t 201008011501 %t-dir/pragma-once2.h
+// RUN: not %clang_cc1 -include-pch %t %t-dir/1.cpp 2>&1 | FileCheck -check-prefix=CHECK-TIMESTAMP %s
// Check bitcode output as well.
// RUN: llvm-bcanalyzer -dump %t | FileCheck -check-prefix=CHECK-BITCODE-TIMESTAMP-ON %s
// Check timestamp inclusion is disabled by -fno-pch-timestamp.
-// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %T/pragma-once2-pch.h -fno-pch-timestamp
-// RUN: touch -m -a -t 201008011502 %T/pragma-once2.h
-// RUN: %clang_cc1 -include-pch %t %t1.cpp 2>&1
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %t-dir/pragma-once2-pch.h -fno-pch-timestamp
+// RUN: touch -m -a -t 201008011502 %t-dir/pragma-once2.h
+// RUN: %clang_cc1 -include-pch %t %t-dir/1.cpp 2>&1
// Check bitcode output as well.
// RUN: llvm-bcanalyzer -dump %t | FileCheck -check-prefix=CHECK-BITCODE-TIMESTAMP-OFF %s
diff --git a/test/PCH/pragma-pack.c b/test/PCH/pragma-pack.c
new file mode 100644
index 0000000000..7b45e045b3
--- /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 -Wno-pragma-pack -DSET
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DRESET
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH_POP
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -include %s -verify -fsyntax-only -Wno-pragma-pack -DPUSH_POP_LABEL
+
+// Test with pch.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DSET -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DSET -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DRESET -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DRESET -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP -verify -include-pch %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -DPUSH_POP_LABEL -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -Wno-pragma-pack -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/PCH/suspicious-pragma-pack.c b/test/PCH/suspicious-pragma-pack.c
new file mode 100644
index 0000000000..ac48ad3a89
--- /dev/null
+++ b/test/PCH/suspicious-pragma-pack.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -verify -emit-pch -o %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -verify -include-pch %t
+
+#ifndef HEADER
+#define HEADER
+#pragma pack (push, 1)
+#else
+#pragma pack (2)
+#endif
+// expected-warning@-4 {{unterminated '#pragma pack (push, ...)' at end of file}}
diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp
index 830412ed47..c796eded1f 100644
--- a/test/Parser/MicrosoftExtensions.cpp
+++ b/test/Parser/MicrosoftExtensions.cpp
@@ -60,7 +60,7 @@ struct struct_without_uuid { };
struct __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
struct_with_uuid2;
-[uuid("000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid3;
+[uuid("000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid3; // expected-warning{{specifying 'uuid' as an ATL attribute is deprecated; use __declspec instead}}
struct
struct_with_uuid2 {} ;
@@ -261,9 +261,7 @@ int __identifier(else} = __identifier(for); // expected-error {{missing ')' afte
#define identifier_weird(x) __identifier(x
int k = identifier_weird(if)); // expected-error {{use of undeclared identifier 'if'}}
-// This is a bit weird, but the alternative tokens aren't keywords, and this
-// behavior matches MSVC. FIXME: Consider supporting this anyway.
-extern int __identifier(and) r; // expected-error {{cannot convert '&&' token to an identifier}}
+extern int __identifier(and);
void f() {
__identifier(() // expected-error {{cannot convert '(' token to an identifier}}
diff --git a/test/Parser/altivec-csk-bool.c b/test/Parser/altivec-csk-bool.c
index c1c253958c..dc7fa1da39 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 4d3a7730c3..769b4dec98 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/arm-windows-calling-convention-handling.c b/test/Parser/arm-windows-calling-convention-handling.c
index ee25e60193..13669b1963 100644
--- a/test/Parser/arm-windows-calling-convention-handling.c
+++ b/test/Parser/arm-windows-calling-convention-handling.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple thumbv7-windows -fms-compatibility -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-windows -fms-compatibility -fsyntax-only -verify %s
int __cdecl cdecl(int a, int b, int c, int d) { // expected-no-diagnostics
return a + b + c + d;
diff --git a/test/Parser/builtin_types_compatible.c b/test/Parser/builtin_types_compatible.c
index ac81e7b08d..d967a7023a 100644
--- a/test/Parser/builtin_types_compatible.c
+++ b/test/Parser/builtin_types_compatible.c
@@ -41,3 +41,20 @@ static void test()
}
+enum E1 { E1Foo };
+enum E2 { E2Foo };
+
+static void testGccCompatibility() {
+ _Static_assert(__builtin_types_compatible_p(const volatile int, int), "");
+ _Static_assert(__builtin_types_compatible_p(int[5], int[]), "");
+ _Static_assert(!__builtin_types_compatible_p(int[5], int[4]), "");
+ _Static_assert(!__builtin_types_compatible_p(int *, int **), "");
+ _Static_assert(!__builtin_types_compatible_p(const int *, int *), "");
+ _Static_assert(!__builtin_types_compatible_p(enum E1, enum E2), "");
+
+ // GCC's __builtin_types_compatible_p ignores qualifiers on arrays.
+ _Static_assert(__builtin_types_compatible_p(const int[4], int[4]), "");
+ _Static_assert(__builtin_types_compatible_p(int[4], const int[4]), "");
+ _Static_assert(__builtin_types_compatible_p(const int[5][4], int[][4]), "");
+ _Static_assert(!__builtin_types_compatible_p(const int(*)[], int(*)[]), "");
+}
diff --git a/test/Parser/c2x-attributes.c b/test/Parser/c2x-attributes.c
new file mode 100644
index 0000000000..1be69f1ca2
--- /dev/null
+++ b/test/Parser/c2x-attributes.c
@@ -0,0 +1,122 @@
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
+
+enum [[]] E {
+ One [[]],
+ Two,
+ Three [[]]
+};
+
+enum [[]] { Four };
+[[]] enum E2 { Five }; // expected-error {{an attribute list cannot appear here}}
+
+// FIXME: this diagnostic can be improved.
+enum { [[]] Six }; // expected-error {{expected identifier}}
+
+// FIXME: this diagnostic can be improved.
+enum E3 [[]] { Seven }; // expected-error {{expected identifier or '('}}
+
+struct [[]] S1 {
+ int i [[]];
+ int [[]] j;
+ int k[10] [[]];
+ int l[[]][10];
+ [[]] int m, n;
+ int o [[]] : 12;
+};
+
+[[]] struct S2 { int a; }; // expected-error {{an attribute list cannot appear here}}
+struct S3 [[]] { int a; }; // expected-error {{an attribute list cannot appear here}}
+
+union [[]] U {
+ double d [[]];
+ [[]] int i;
+};
+
+[[]] union U2 { double d; }; // expected-error {{an attribute list cannot appear here}}
+union U3 [[]] { double d; }; // expected-error {{an attribute list cannot appear here}}
+
+struct [[]] IncompleteStruct;
+union [[]] IncompleteUnion;
+enum [[]] IncompleteEnum;
+enum __attribute__((deprecated)) IncompleteEnum2;
+
+[[]] void f1(void);
+void [[]] f2(void);
+void f3 [[]] (void);
+void f4(void) [[]];
+
+void f5(int i [[]], [[]] int j, int [[]] k);
+
+void f6(a, b) [[]] int a; int b; { // expected-error {{an attribute list cannot appear here}}
+}
+
+// FIXME: technically, an attribute list cannot appear here, but we currently
+// parse it as part of the return type of the function, which is reasonable
+// behavior given that we *don't* want to parse it as part of the K&R parameter
+// declarations. It is disallowed to avoid a parsing ambiguity we already
+// handle well.
+int (*f7(a, b))(int, int) [[]] int a; int b; {
+ return 0;
+}
+
+[[]] int a, b;
+int c [[]], d [[]];
+
+void f8(void) [[]] {
+ [[]] int i, j;
+ int k, l [[]];
+}
+
+[[]] void f9(void) {
+ int i[10] [[]];
+ int (*fp1)(void)[[]];
+ int (*fp2 [[]])(void);
+
+ int * [[]] *ipp;
+}
+
+void f10(int j[static 10] [[]], int k[*] [[]]);
+
+void f11(void) {
+ [[]] {}
+ [[]] if (1) {}
+
+ [[]] switch (1) {
+ [[]] case 1: [[]] break;
+ [[]] default: break;
+ }
+
+ goto foo;
+ [[]] foo: (void)1;
+
+ [[]] for (;;);
+ [[]] while (1);
+ [[]] do [[]] { } while(1);
+
+ [[]] (void)1;
+
+ [[]];
+
+ (void)sizeof(int [4][[]]);
+ (void)sizeof(struct [[]] S3 { int a [[]]; });
+
+ [[]] return;
+}
+
+[[attr]] void f12(void); // expected-warning {{unknown attribute 'attr' ignored}}
+[[vendor::attr]] void f13(void); // expected-warning {{unknown attribute 'attr' ignored}}
+
+// Ensure that asm statements properly handle double colons.
+void test_asm(void) {
+ asm("ret" :::);
+ asm("foo" :: "r" (xx)); // expected-error {{use of undeclared identifier 'xx'}}
+}
+
+// Do not allow 'using' to introduce vendor attribute namespaces.
+[[using vendor: attr1, attr2]] void f14(void); // expected-error {{expected ']'}} \
+ // expected-warning {{unknown attribute 'vendor' ignored}} \
+ // expected-warning {{unknown attribute 'using' ignored}}
+
+struct [[]] S4 *s; // expected-error {{an attribute list cannot appear here}}
+struct S5 {};
+int c = sizeof(struct [[]] S5); // expected-error {{an attribute list cannot appear here}}
diff --git a/test/Parser/c2x-attributes.m b/test/Parser/c2x-attributes.m
new file mode 100644
index 0000000000..f4610416cd
--- /dev/null
+++ b/test/Parser/c2x-attributes.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
+// expected-no-diagnostics
+
+enum __attribute__((deprecated)) E1 : int; // ok
+enum [[deprecated]] E2 : int;
+
+@interface Base
+@end
+
+@interface S : Base
+- (void) bar;
+@end
+
+@interface T : Base
+- (S *) foo;
+@end
+
+
+void f(T *t) {
+ [[]][[t foo] bar];
+}
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
index 5b0da6c5e6..6395452010 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-bool.cpp b/test/Parser/cxx-bool.cpp
index a8a161edb1..21591d10e9 100644
--- a/test/Parser/cxx-bool.cpp
+++ b/test/Parser/cxx-bool.cpp
@@ -1,4 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
bool a = true;
bool b = false;
+
+namespace pr34273 {
+ char c = "clang"[true];
+ char d = true["clang"];
+}
+
diff --git a/test/Parser/cxx-modules-import.cpp b/test/Parser/cxx-modules-import.cpp
deleted file mode 100644
index 0600eddecb..0000000000
--- a/test/Parser/cxx-modules-import.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir -p %t
-// RUN: echo 'module x; int a, b;' > %t/x.cppm
-// RUN: echo 'module x.y; int c;' > %t/x.y.cppm
-//
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %t/x.cppm -o %t/x.pcm
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface -fmodule-file=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm
-//
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=1 -DMODULE_KIND=implementation -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=2 -DMODULE_KIND=implementation -DMODULE_NAME=x
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=3 -DMODULE_KIND= -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=4 -DMODULE_KIND=partition -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=5 -DMODULE_KIND=elderberry -DMODULE_NAME=z
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=1 -DMODULE_KIND=implementation -DMODULE_NAME='z [[]]'
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=6 -DMODULE_KIND=implementation -DMODULE_NAME='z [[fancy]]'
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \
-// RUN: -DTEST=7 -DMODULE_KIND=implementation -DMODULE_NAME='z [[maybe_unused]]'
-
-module MODULE_KIND MODULE_NAME;
-#if TEST == 3
-// expected-error@-2 {{'module' declaration found while not building module interface}}
-#elif TEST == 4
-// expected-error@-4 {{'module partition' declaration found while not building module interface}}
-#elif TEST == 5
-// expected-error@-6 {{unexpected module kind 'elderberry'}}
-#elif TEST == 6
-// expected-warning@-8 {{unknown attribute 'fancy' ignored}}
-#elif TEST == 7
-// expected-error-re@-10 {{'maybe_unused' attribute cannot be applied to a module{{$}}}}
-#endif
-
-int use_1 = a;
-#if TEST != 2
-// expected-error@-2 {{declaration of 'a' must be imported from module 'x' before it is required}}
-// expected-note@x.cppm:1 {{here}}
-#endif
-
-import x;
-
-int use_2 = b; // ok
-
-import x [[]];
-import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}
-import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}}
-import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'noreturn' ignored}}
-
-import x.y;
-import x.; // expected-error {{expected a module name after module import}}
-import .x; // expected-error {{expected a module name after module import}}
-
-import blarg; // expected-error {{module 'blarg' not found}}
diff --git a/test/Parser/cxx-modules-interface.cppm b/test/Parser/cxx-modules-interface.cppm
index f7835bd167..0e7c746833 100644
--- a/test/Parser/cxx-modules-interface.cppm
+++ b/test/Parser/cxx-modules-interface.cppm
@@ -1,13 +1,12 @@
// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DERRORS
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DERRORS
-module foo;
+export module foo;
#ifndef ERRORS
// expected-no-diagnostics
#else
-// expected-error@-4 {{expected module declaration at start of module interface}}
+// FIXME: diagnose missing module-declaration when building module interface
-// FIXME: support 'export module X;' and 'export { int n; module X; }'
// FIXME: proclaimed-ownership-declarations?
export {
diff --git a/test/Parser/cxx-template-argument.cpp b/test/Parser/cxx-template-argument.cpp
index 9b8ca985dd..963356eaab 100644
--- a/test/Parser/cxx-template-argument.cpp
+++ b/test/Parser/cxx-template-argument.cpp
@@ -10,7 +10,7 @@ template<typename T> struct A {};
// Check for template argument lists followed by junk
// FIXME: The diagnostics here aren't great...
A<int+> int x; // expected-error {{expected '>'}} expected-error {{expected unqualified-id}}
-A<int x; // expected-error {{type-id cannot have a name}} expected-error {{expected '>'}}
+A<int x; // expected-error {{expected '>'}}
// PR8912
template <bool> struct S {};
diff --git a/test/Parser/cxx0x-ambig.cpp b/test/Parser/cxx0x-ambig.cpp
index 4a1b4ad777..71d32b8f51 100644
--- a/test/Parser/cxx0x-ambig.cpp
+++ b/test/Parser/cxx0x-ambig.cpp
@@ -132,6 +132,32 @@ namespace ellipsis {
void l(int(*...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
void l(int(S<int>::*...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
};
+
+ struct CtorSink {
+ template <typename ...T> constexpr CtorSink(T &&...t) { }
+ constexpr operator int() const { return 42; }
+ };
+
+ template <unsigned ...N> struct UnsignedTmplArgSink;
+
+ template <typename ...T>
+ void foo(int x, T ...t) {
+ // Have a variety of cases where the syntax is technically unambiguous, but hinges on careful treatment of ellipses.
+ CtorSink(t ...), x; // ok, expression; expected-warning 2{{expression result unused}}
+
+ int x0(CtorSink(t ...)); // ok, declares object x0
+ int *p0 = &x0;
+ (void)p0;
+
+ CtorSink x1(int(t) ..., int(x)); // ok, declares object x1
+ CtorSink *p1 = &x1;
+ (void)p1;
+
+ UnsignedTmplArgSink<T(CtorSink(t ...)) ...> *t0; // ok
+ UnsignedTmplArgSink<((T *)0, 42u) ...> **t0p = &t0;
+ }
+
+ template void foo(int, int, int); // expected-note {{in instantiation of function template specialization 'ellipsis::foo<int, int>' requested here}}
}
namespace braced_init_list {
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 647762f165..a803085cd3 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++1z-extensions %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++17-extensions %s
// Need std::initializer_list
namespace std {
@@ -127,7 +127,7 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] using ns::i; // expected-error {{an attribute list cannot appear here}}
[[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}}
[[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions}}
-namespace [[]] ns2 {} // expected-warning {{attributes on a namespace declaration are incompatible with C++ standards before C++1z}}
+namespace [[]] ns2 {} // expected-warning {{attributes on a namespace declaration are a C++17 extension}}
using [[]] alignas(4) [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
using [[]] alignas(4) [[]] foobar = int; // expected-error {{an attribute list cannot appear here}} expected-error {{'alignas' attribute only applies to}}
@@ -179,7 +179,7 @@ enum [[]] E2; // expected-error {{forbids forward references}}
enum [[]] E1;
enum [[]] E3 : int;
enum [[]] {
- k_123 [[]] = 123 // expected-warning {{attributes on an enumerator declaration are incompatible with C++ standards before C++1z}}
+ k_123 [[]] = 123 // expected-warning {{attributes on an enumerator declaration are a C++17 extension}}
};
enum [[]] E1 e; // expected-error {{an attribute list cannot appear here}}
enum [[]] class E4 { }; // expected-error {{an attribute list cannot appear here}}
@@ -352,7 +352,7 @@ int fallthru(int n) {
switch (n) {
case 0:
n += 5;
- [[fallthrough]]; // expected-warning {{use of the 'fallthrough' attribute is a C++1z extension}}
+ [[fallthrough]]; // expected-warning {{use of the 'fallthrough' attribute is a C++17 extension}}
case 1:
n *= 2;
break;
diff --git a/test/Parser/cxx0x-condition.cpp b/test/Parser/cxx0x-condition.cpp
index 071e09e415..19d5a7395d 100644
--- a/test/Parser/cxx0x-condition.cpp
+++ b/test/Parser/cxx0x-condition.cpp
@@ -14,11 +14,11 @@ void f() {
for (; int x = ++a; ) ;
if (S(a)) {} // ok
- if (S(a) = 0) {} // ok
+ if (S(a) = 0) {} // expected-warning {{redundant parentheses}} expected-note 2{{}}
if (S(a) == 0) {} // ok
if (S(n)) {} // expected-error {{unexpected type name 'n': expected expression}}
- if (S(n) = 0) {} // ok
+ if (S(n) = 0) {} // expected-warning {{redundant parentheses}} expected-note 2{{}}
if (S(n) == 0) {} // expected-error {{unexpected type name 'n': expected expression}}
if (S b(a)) {} // expected-error {{variable declaration in condition cannot have a parenthesized initializer}}
diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp
index d912e19287..2b253c019c 100644
--- a/test/Parser/cxx0x-decl.cpp
+++ b/test/Parser/cxx0x-decl.cpp
@@ -123,6 +123,25 @@ namespace ColonColonDecltype {
::decltype(S())::T invalid; // expected-error {{expected unqualified-id}}
}
+namespace AliasDeclEndLocation {
+ template<typename T> struct A {};
+ // Ensure that we correctly determine the end of this declaration to be the
+ // end of the annotation token, not the beginning.
+ using B = AliasDeclEndLocation::A<int
+ > // expected-error {{expected ';' after alias declaration}}
+ +;
+ // FIXME: After splitting this >> into two > tokens, we incorrectly determine
+ // the end of the template-id to be after the *second* '>'.
+ // Perhaps we could synthesize an expansion FileID containing '> >' to fix this?
+ using C = AliasDeclEndLocation::A<int
+ >\
+> // expected-error {{expected ';' after alias declaration}}
+ ;
+ using D = AliasDeclEndLocation::A<int
+ > // expected-error {{expected ';' after alias declaration}}
+ B something_else;
+}
+
struct Base { virtual void f() = 0; virtual void g() = 0; virtual void h() = 0; };
struct MemberComponentOrder : Base {
void f() override __asm__("foobar") __attribute__(( )) {}
diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp
index 9374b58b1f..75fb37ea9f 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
index dac17dfbf4..b8f5a82d46 100644
--- a/test/Parser/cxx1z-class-template-argument-deduction.cpp
+++ b/test/Parser/cxx1z-class-template-argument-deduction.cpp
@@ -180,6 +180,7 @@ namespace typename_specifier {
{(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}}
+ // expected-warning@-1 {{disambiguated as redundant parentheses around declaration of variable named 'parens'}} expected-note@-1 {{add a variable name}} expected-note@-1{{remove parentheses}} expected-note@-1 {{add enclosing parentheses}}
{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}}
diff --git a/test/Parser/cxx1z-constexpr-lambdas.cpp b/test/Parser/cxx1z-constexpr-lambdas.cpp
index ea000e361c..4cf3d12211 100644
--- a/test/Parser/cxx1z-constexpr-lambdas.cpp
+++ b/test/Parser/cxx1z-constexpr-lambdas.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1z %s -verify
+// RUN: %clang_cc1 -std=c++17 %s -verify
// RUN: %clang_cc1 -std=c++14 %s -verify
// RUN: %clang_cc1 -std=c++11 %s -verify
@@ -23,9 +23,9 @@ auto XL16 = [] () constexpr
{ };
#else
-auto L = []() mutable constexpr {return 0; }; //expected-warning{{is a C++1z extension}}
-auto L2 = []() constexpr { return 0;};//expected-warning{{is a C++1z extension}}
-auto L4 = []() constexpr mutable { return 0; }; //expected-warning{{is a C++1z extension}}
+auto L = []() mutable constexpr {return 0; }; //expected-warning{{is a C++17 extension}}
+auto L2 = []() constexpr { return 0;};//expected-warning{{is a C++17 extension}}
+auto L4 = []() constexpr mutable { return 0; }; //expected-warning{{is a C++17 extension}}
#endif
diff --git a/test/Parser/cxx1z-fold-expressions.cpp b/test/Parser/cxx1z-fold-expressions.cpp
index b1f7318e41..342f11555f 100644
--- a/test/Parser/cxx1z-fold-expressions.cpp
+++ b/test/Parser/cxx1z-fold-expressions.cpp
@@ -43,3 +43,20 @@ template<typename ...T> void as_operand_of_cast(int a, T ...t) {
(int)(undeclared_junk + ...) + // expected-error {{undeclared}}
(int)(a + ...); // expected-error {{does not contain any unexpanded}}
}
+
+// fold-operator can be '>' or '>>'.
+template <int... N> constexpr bool greaterThan() { return (N > ...); }
+template <int... N> constexpr int rightShift() { return (N >> ...); }
+
+static_assert(greaterThan<2, 1>());
+static_assert(rightShift<10, 1>() == 5);
+
+template <auto V> constexpr auto Identity = V;
+
+// Support fold operators within templates.
+template <int... N> constexpr int nestedFoldOperator() {
+ return Identity<(Identity<0> >> ... >> N)> +
+ Identity<(N >> ... >> Identity<0>)>;
+}
+
+static_assert(nestedFoldOperator<3, 1>() == 1);
diff --git a/test/Parser/cxx1z-nested-namespace-definition.cpp b/test/Parser/cxx1z-nested-namespace-definition.cpp
index 96f34c540a..e5e809aa03 100644
--- a/test/Parser/cxx1z-nested-namespace-definition.cpp
+++ b/test/Parser/cxx1z-nested-namespace-definition.cpp
@@ -2,13 +2,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: not %clang_cc1 -x c++ -fixit %t -Werror -DFIXIT
// RUN: %clang_cc1 -x c++ %t -DFIXIT
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -Wc++14-compat
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++17 -Wc++14-compat
namespace foo1::foo2::foo3 {
#if __cplusplus <= 201400L
-// expected-warning@-2 {{nested namespace definition is a C++1z extension; define each namespace separately}}
+// expected-warning@-2 {{nested namespace definition is a C++17 extension; define each namespace separately}}
#else
-// expected-warning@-4 {{nested namespace definition is incompatible with C++ standards before C++1z}}
+// expected-warning@-4 {{nested namespace definition is incompatible with C++ standards before C++17}}
#endif
int foo(int x) { return x; }
}
diff --git a/test/Parser/cxx2a-bitfield-init.cpp b/test/Parser/cxx2a-bitfield-init.cpp
new file mode 100644
index 0000000000..83f1575c96
--- /dev/null
+++ b/test/Parser/cxx2a-bitfield-init.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+namespace std_example {
+ int a;
+ const int b = 0; // expected-note {{here}}
+ struct S {
+ int x1 : 8 = 42;
+ int x2 : 8 { 42 };
+ int y1 : true ? 8 : a = 42;
+ int y3 : (true ? 8 : b) = 42;
+ int z : 1 || new int { 1 };
+ };
+ static_assert(S{}.x1 == 42);
+ static_assert(S{}.x2 == 42);
+ static_assert(S{}.y1 == 0);
+ static_assert(S{}.y3 == 42);
+ static_assert(S{}.z == 0);
+
+ struct T {
+ int y2 : true ? 8 : b = 42; // expected-error {{cannot assign to variable 'b'}}
+ };
+}
diff --git a/test/Parser/editor-placeholder-recovery.cpp b/test/Parser/editor-placeholder-recovery.cpp
new file mode 100644
index 0000000000..d68e087d6f
--- /dev/null
+++ b/test/Parser/editor-placeholder-recovery.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fallow-editor-placeholders -DSUPPRESS -verify %s
+
+struct Struct {
+public:
+ void method(Struct &x);
+};
+
+struct <#struct name#> {
+ int <#field-name#>;
+#ifndef SUPPRESS
+ // expected-error@-3 {{editor placeholder in source file}}
+ // expected-error@-3 {{editor placeholder in source file}}
+#endif
+};
+
+typename <#typename#>::<#name#>;
+decltype(<#expression#>) foobar;
+typedef <#type#> <#name#>;
+#ifndef SUPPRESS
+ // expected-error@-4 2 {{editor placeholder in source file}}
+ // expected-error@-4 {{editor placeholder in source file}}
+ // expected-error@-4 2 {{editor placeholder in source file}}
+#endif
+
+namespace <#identifier#> {
+ <#declarations#>
+#ifndef SUPPRESS
+ // expected-error@-3 {{editor placeholder in source file}}
+ // expected-error@-3 {{editor placeholder in source file}}
+#endif
+
+}
+
+using <#qualifier#>::<#name#>;
+#ifndef SUPPRESS
+ // expected-error@-2 2 {{editor placeholder in source file}}
+#endif
+
+void avoidPlaceholderErrors(Struct &obj) {
+ static_cast< <#type#> >(<#expression#>);
+ while (<#condition#>) {
+ <#statements#>
+ }
+ obj.method(<#Struct &x#>);
+#ifndef SUPPRESS
+ // expected-error@-6 2 {{editor placeholder in source file}}
+ // expected-error@-6 {{editor placeholder in source file}}
+ // expected-error@-6 {{editor placeholder in source file}}
+ // expected-error@-5 {{editor placeholder in source file}}
+#endif
+ switch (<#expression#>) {
+ case <#constant#>:
+ <#statements#>
+#ifndef SUPPRESS
+ // expected-error@-4 {{editor placeholder in source file}}
+ // expected-error@-4 {{editor placeholder in source file}}
+ // expected-error@-4 {{editor placeholder in source file}}
+#endif
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}} expected-error {{C++ requires a type specifier for all declarations}}
+#ifndef SUPPRESS
+ // expected-error@-2 {{editor placeholder in source file}}
+#endif
+}
+
+void handleTrigraph() {
+ <??=placeholder#> // expected-error {{expected expression}} expected-error {{expected expression}} expected-warning {{trigraph converted to '#' character}}
+}
diff --git a/test/Parser/ms-square-bracket-attributes.mm b/test/Parser/ms-square-bracket-attributes.mm
index 98b2f6c2d3..a158cf7b2b 100644
--- a/test/Parser/ms-square-bracket-attributes.mm
+++ b/test/Parser/ms-square-bracket-attributes.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify -fms-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify -fms-extensions %s -Wno-deprecated-declarations
typedef struct _GUID {
unsigned long Data1;
diff --git a/test/Parser/objc-at-implementation-eof-crash.m b/test/Parser/objc-at-implementation-eof-crash.m
new file mode 100644
index 0000000000..76e56c1070
--- /dev/null
+++ b/test/Parser/objc-at-implementation-eof-crash.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
+
+@interface ClassA
+
+- (void)fileExistsAtPath:(int)x;
+
+@end
+
+@interface ClassB
+
+@end
+
+@implementation ClassB // expected-note {{implementation started here}}
+
+- (void) method:(ClassA *)mgr { // expected-note {{to match this '{'}}
+ [mgr fileExistsAtPath:0
+} // expected-error {{expected ']'}}
+
+@implementation ClassC // \
+ // expected-error {{missing '@end'}} \
+ // expected-error {{expected '}'}} \
+ // expected-warning {{cannot find interface declaration for 'ClassC'}}
+
+@end
diff --git a/test/Parser/objc-at-interface-eof-crash.m b/test/Parser/objc-at-interface-eof-crash.m
new file mode 100644
index 0000000000..2c7bfd688f
--- /dev/null
+++ b/test/Parser/objc-at-interface-eof-crash.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -verify -Wno-objc-root-class %s
+
+@interface ClassA
+
+- (void)fileExistsAtPath:(int)x;
+
+@end
+
+@interface ClassB
+
+@end
+
+@implementation ClassB // expected-note {{implementation started here}}
+
+- (void) method:(ClassA *)mgr { // expected-note {{to match this '{'}}
+ [mgr fileExistsAtPath:0
+} // expected-error {{expected ']'}}
+
+@interface ClassC // \
+ // expected-error {{missing '@end'}} \
+ // expected-error {{expected '}'}}
+
+@end
diff --git a/test/Parser/objc-available.m b/test/Parser/objc-available.m
index d18ac1f134..01d59f8f52 100644
--- a/test/Parser/objc-available.m
+++ b/test/Parser/objc-available.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunguarded-availability -triple x86_64-apple-macosx10.10.0 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunguarded-availability -Wno-unsupported-availability-guard -triple x86_64-apple-macosx10.10.0 -verify %s
void f() {
@@ -20,3 +20,14 @@ void f() {
(void)@available(macos); // expected-error{{expected a version}}
(void)@available; // expected-error{{expected '('}}
}
+
+void prettyPlatformNames() {
+ (void)@available(iOS 8, tvOS 10, watchOS 3, macOS 10.11, *);
+ (void)__builtin_available(iOSApplicationExtension 8, tvOSApplicationExtension 10,
+ watchOSApplicationExtension 3, macOSApplicationExtension 10.11, *);
+}
+
+#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 0000000000..6791f0d373
--- /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 65fb9d9b42..ad67db0bab 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/placeholder-recovery.m b/test/Parser/placeholder-recovery.m
index b43b0e4a57..4f22ea770d 100644
--- a/test/Parser/placeholder-recovery.m
+++ b/test/Parser/placeholder-recovery.m
@@ -1,11 +1,14 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+@protocol NSObject
+@end
+
+@protocol <#protocol name#> <NSObject> // expected-error {{editor placeholder in source file}}
+// expected-note@-1 {{protocol started here}}
+
// FIXME: We could do much better with this, if we recognized
// placeholders somehow. However, we're content with not generating
// bogus 'archaic' warnings with bad location info.
-@protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \
-// expected-error 2{{expected identifier}} \
-// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
-<#methods#>
+<#methods#> // expected-error {{editor placeholder in source file}}
-@end
+@end // expected-error {{prefix attribute must be followed by an interface or protocol}} expected-error {{missing '@end'}}
diff --git a/test/Parser/pragma-attribute-declspec.cpp b/test/Parser/pragma-attribute-declspec.cpp
new file mode 100644
index 0000000000..28785ba900
--- /dev/null
+++ b/test/Parser/pragma-attribute-declspec.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -verify -Wno-pragma-clang-attribute -fms-extensions -fms-compatibility %s
+
+#pragma clang attribute push(__declspec(dllexport), apply_to = function)
+
+void function();
+
+#pragma clang attribute pop
+
+#pragma clang attribute push(__declspec(dllexport, dllimport), apply_to = function) // expected-error {{more than one attribute specified in '#pragma clang attribute push'}}
+
+#pragma clang attribute push(__declspec(align), apply_to = variable) // expected-error {{attribute 'align' is not supported by '#pragma clang attribute'}}
+
+#pragma clang attribute push(__declspec(), apply_to = variable) // A noop
diff --git a/test/Parser/pragma-attribute.cpp b/test/Parser/pragma-attribute.cpp
new file mode 100644
index 0000000000..f0ebca2c53
--- /dev/null
+++ b/test/Parser/pragma-attribute.cpp
@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -Wno-pragma-clang-attribute -verify -std=c++11 %s
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = function)
+
+void function();
+
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(variable(is_parameter), function))
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = variable(unless(is_parameter)))
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(variable(unless(is_parameter))))
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a")))) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) apply_to=function) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) = function) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) any(function)) // expected-error {{expected ','}}
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))) 22) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) function) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))) (function)) // expected-error {{expected ','}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), ) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), = any(function)) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), = function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), any(function)) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply = any(function )) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), to = function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_only_to = function) // expected-error {{expected attribute subject set specifier 'apply_to'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to any(function)) // expected-error {{expected '='}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to function) // expected-error {{expected '='}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to) // expected-error {{expected '='}}
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to 41 (22)) // expected-error {{expected '='}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any {) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any function) // expected-error {{expected '('}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = { function, enum }) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(function ) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(function, )) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, enum ) // expected-error {{expected ')'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = () ) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( + ) ) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any()) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, 42 )) // expected-error {{expected an identifier that corresponds to an attribute subject rule}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( diag )) // expected-error {{unknown attribute subject rule 'diag'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( a )) // expected-error {{unknown attribute subject rule 'a'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, for)) // expected-error {{unknown attribute subject rule 'for'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function42, for )) // expected-error {{unknown attribute subject rule 'function42'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(hasType)) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = hasType) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = hasType(functionType)) // OK
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable( )) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable( ) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is ) )) // expected-error {{unknown attribute subject matcher sub-rule 'is'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_parameter, not) )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable is_parameter )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable ( ) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = variable ( // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (is ()) )) // expected-error {{unknown attribute subject matcher sub-rule 'is'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (42) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, namespace("test") )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'namespace' matcher does not support sub-rules}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable ("test" )) // expected-error {{expected ')'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = enum(is_parameter)) // expected-error {{invalid use of attribute subject matcher sub-rule 'is_parameter'; 'enum' matcher does not support sub-rules}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any(enum(is_parameter))) // expected-error {{invalid use of attribute subject matcher sub-rule 'is_parameter'; 'enum' matcher does not support sub-rules}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any (function, variable (unless) )) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any (function, variable (unless() )) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any ( function, variable (unless(is)) )) // expected-error {{unknown attribute subject matcher sub-rule 'unless(is)'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter, not)) )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter), not) ) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable unless is_parameter )) // expected-error {{expected ')'}} expected-note {{to match this '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless is_parameter) )) // expected-error {{expected '('}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (unless(42)) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, enum(unless("test")) )) // expected-error {{expected an identifier that corresponds to an attribute subject matcher sub-rule; 'enum' matcher does not support sub-rules}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, variable (unless(is_global)) )) // expected-error {{unknown attribute subject matcher sub-rule 'unless(is_global)'; 'variable' matcher supports the following sub-rules: 'is_thread_local', 'is_global', 'is_parameter', 'unless(is_parameter)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( enum(unless(is_parameter)) )) // expected-error {{invalid use of attribute subject matcher sub-rule 'unless(is_parameter)'; 'enum' matcher does not support sub-rules}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, function )) // expected-error {{duplicate attribute subject matcher 'function'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, function, function )) // expected-error 2 {{duplicate attribute subject matcher 'function'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( function, enum, function )) // expected-error {{duplicate attribute subject matcher 'function'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( enum, enum, function )) // expected-error {{duplicate attribute subject matcher 'enum'}}
+
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_global), variable(is_global) )) // expected-error {{duplicate attribute subject matcher 'variable(is_global)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(is_global), function, variable(is_global), variable(is_global) )) // expected-error 2 {{duplicate attribute subject matcher 'variable(is_global)'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter)), variable(unless(is_parameter)) )) // expected-error {{duplicate attribute subject matcher 'variable(unless(is_parameter))'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to = any( variable(unless(is_parameter)), variable(unless(is_parameter)), enum, variable(unless(is_parameter)) )) // expected-error 2 {{duplicate attribute subject matcher 'variable(unless(is_parameter))'}}
+
+#pragma clang attribute // expected-error {{expected 'push' or 'pop' after '#pragma clang attribute'}}
+#pragma clang attribute 42 // expected-error {{expected 'push' or 'pop' after '#pragma clang attribute'}}
+#pragma clang attribute pushpop // expected-error {{unexpected argument 'pushpop' to '#pragma clang attribute'; expected 'push' or 'pop'}}
+
+#pragma clang attribute push // expected-error {{expected '('}}
+#pragma clang attribute push ( // expected-error {{expected an attribute after '('}}
+#pragma clang attribute push (__attribute__((annotate)) // expected-error {{expected ')'}}
+#pragma clang attribute push () // expected-error {{expected an attribute after '('}}
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = function) () // expected-warning {{extra tokens at end of '#pragma clang attribute'}}
+// expected-error@-1 {{expected unqualified-id}}
+// expected-error@-2 {{unterminated '#pragma clang attribute push' at end of file}}
+
+#pragma clang attribute pop () // expected-warning {{extra tokens at end of '#pragma clang attribute'}}
+
+;
+
+#pragma clang attribute push (__attribute__((42))) // expected-error {{expected identifier that represents an attribute name}}
+
+#pragma clang attribute push (__attribute__((annotate)) foo) // expected-error {{expected ','}}
+#pragma clang attribute push (__attribute__((annotate)), apply_to=function foo) // expected-error {{extra tokens after attribute in a '#pragma clang attribute push'}}
+
+#pragma clang attribute push (__attribute__((objc_bridge_related)), apply_to=function)
+// expected-error@-1 {{attribute 'objc_bridge_related' is not supported by '#pragma clang attribute'}}
+#pragma clang attribute push (__attribute__((objc_bridge_related(1))), apply_to=function) // expected-error {{expected a related ObjectiveC class name, e.g., 'NSColor'}}
+
+#pragma clang attribute push (__attribute__((used)), apply_to=function) // expected-error {{attribute 'used' is not supported by '#pragma clang attribute'}}
+
+void statementPragmasAndPragmaExpression() {
+#pragma clang attribute push (__attribute__((annotate("hello"))), apply_to=variable)
+#pragma clang attribute pop
+int x = 0;
+_Pragma("clang attribute push (__attribute__((annotate(\"hi\"))), apply_to = function)");
+
+_Pragma("clang attribute push (__attribute__((annotate(\"hi\"))), apply_to = any(function(is_method ))"); // expected-error {{expected ')'}}
+}
+
+_Pragma("clang attribute pop");
+
+#pragma clang attribute push (__attribute__((address_space(0))), apply_to=variable) // expected-error {{attribute 'address_space' is not supported by '#pragma clang attribute'}}
+
+// Check support for CXX11 style attributes
+#pragma clang attribute push ([[noreturn]], apply_to = any(function))
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[clang::disable_tail_calls]], apply_to = function)
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[gnu::abi_tag]], apply_to=any(function))
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[clang::disable_tail_calls, noreturn]], apply_to = function) // expected-error {{more than one attribute specified in '#pragma clang attribute push'}}
+#pragma clang attribute push ([[clang::disable_tail_calls, noreturn]]) // expected-error {{more than one attribute specified in '#pragma clang attribute push'}}
+
+#pragma clang attribute push ([[gnu::abi_tag]], apply_to=namespace)
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[fallthrough]], apply_to=function) // expected-error {{attribute 'fallthrough' is not supported by '#pragma clang attribute'}}
+#pragma clang attribute push ([[clang::fallthrough]], apply_to=function) // expected-error {{attribute 'fallthrough' is not supported by '#pragma clang attribute'}}
+
+#pragma clang attribute push ([[]], apply_to = function) // A noop
+
+#pragma clang attribute push ([[noreturn ""]], apply_to=function) // expected-error {{expected ']'}}
+#pragma clang attribute pop
+#pragma clang attribute push ([[noreturn 42]]) // expected-error {{expected ']'}} expected-error {{expected ','}}
+
+#pragma clang attribute push(__attribute__, apply_to=function) // expected-error {{expected '(' after 'attribute'}}
+#pragma clang attribute push(__attribute__(), apply_to=function) // expected-error {{expected '(' after '('}}
+#pragma clang attribute push(__attribute__(()), apply_to=function) // expected-error {{expected identifier that represents an attribute name}}
+#pragma clang attribute push(__attribute__((annotate, apply_to=function))) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate("test"), apply_to=function))) // expected-error {{expected ')'}}
+#pragma clang attribute push(__attribute__((annotate), apply_to=function)) // expected-error {{expected ')'}}
+
+#pragma clang attribute push (42) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+#pragma clang attribute push (test) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+#pragma clang attribute push (annotate) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+// expected-note@-1 {{use the GNU '__attribute__' syntax}}
+#pragma clang attribute push (annotate("test")) // expected-error {{expected an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
+// expected-note@-1 {{use the GNU '__attribute__' syntax}}
diff --git a/test/Parser/pragma-fp.cpp b/test/Parser/pragma-fp.cpp
new file mode 100644
index 0000000000..00547bfb54
--- /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/pragma-options.c b/test/Parser/pragma-options.c
index d168a2751a..a35f0b087e 100644
--- a/test/Parser/pragma-options.c
+++ b/test/Parser/pragma-options.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -Wno-pragma-pack -fsyntax-only -verify %s
/* expected-warning {{expected 'align' following '#pragma options'}} */ #pragma options
/* expected-warning {{expected '=' following '#pragma options align'}} */ #pragma options align
diff --git a/test/Parser/pragma-options.cpp b/test/Parser/pragma-options.cpp
index 84cd38dfb3..8f5a2152c7 100644
--- a/test/Parser/pragma-options.cpp
+++ b/test/Parser/pragma-options.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -Wno-pragma-pack -fsyntax-only -verify %s
// expected-no-diagnostics
class C {
diff --git a/test/Parser/pragma-pack.c b/test/Parser/pragma-pack.c
index 0859f4157c..d2aefaa888 100644
--- a/test/Parser/pragma-pack.c
+++ b/test/Parser/pragma-pack.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-pragma-pack -verify %s
// Note that this puts the expected lines before the directives to work around
// limitations in the -verify mode.
diff --git a/test/Parser/vector-cast-define.cl b/test/Parser/vector-cast-define.cl
new file mode 100644
index 0000000000..ec4eba7a78
--- /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 ead09814c8..32bc934a7e 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/Inputs/nonportable-hmaps/foo.hmap b/test/Preprocessor/Inputs/nonportable-hmaps/foo.hmap
new file mode 100644
index 0000000000..9036f20871
--- /dev/null
+++ b/test/Preprocessor/Inputs/nonportable-hmaps/foo.hmap
Binary files differ
diff --git a/test/Preprocessor/Inputs/nonportable-hmaps/headers/foo/Foo.h b/test/Preprocessor/Inputs/nonportable-hmaps/headers/foo/Foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Preprocessor/Inputs/nonportable-hmaps/headers/foo/Foo.h
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
index c9c7f2dc4a..836d29866e 100644
--- a/test/Preprocessor/aarch64-target-features.c
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -37,6 +37,7 @@
// CHECK-NOT: __ARM_PCS_VFP 1
// CHECK-NOT: __ARM_SIZEOF_MINIMAL_ENUM 1
// CHECK-NOT: __ARM_SIZEOF_WCHAR_T 2
+// CHECK-NOT: __ARM_FEATURE_SVE
// RUN: %clang -target aarch64_be-eabi -x c -E -dM %s -o - | FileCheck %s -check-prefix CHECK-BIGENDIAN
// CHECK-BIGENDIAN: __ARM_BIG_ENDIAN 1
@@ -71,8 +72,9 @@
// CHECK-NEON: __ARM_NEON 1
// CHECK-NEON: __ARM_NEON_FP 0xE
-// RUN: %clang -target aarch64-none-eabi -march=armv8.1-a -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-V81A %s
-// CHECK-V81A: __ARM_FEATURE_QRDMX 1
+// RUN: %clang -target aarch64-none-eabi -march=armv8.1-a -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-QRDMX %s
+// RUN: %clang -target aarch64-none-eabi -march=armv8.2-a -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-QRDMX %s
+// CHECK-QRDMX: __ARM_FEATURE_QRDMX 1
// RUN: %clang -target aarch64 -march=arm64 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-ARCH-NOT-ACCEPT %s
// RUN: %clang -target aarch64 -march=aarch64 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-ARCH-NOT-ACCEPT %s
@@ -83,6 +85,10 @@
// CHECK-GENERIC: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon"
// RUN: %clang -target aarch64 -mtune=cyclone -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MTUNE-CYCLONE %s
+
+// RUN: %clang -target aarch64-none-linux-gnu -march=armv8-a+sve -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE %s
+// CHECK-SVE: __ARM_FEATURE_SVE 1
+
// ================== Check whether -mtune accepts mixed-case features.
// RUN: %clang -target aarch64 -mtune=CYCLONE -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MTUNE-CYCLONE %s
// CHECK-MTUNE-CYCLONE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+neon" "-target-feature" "+zcm" "-target-feature" "+zcz"
@@ -109,7 +115,7 @@
// 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"
+// CHECK-ARCH-ARM64: "-target-cpu" "cyclone" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+crypto" "-target-feature" "+zcm" "-target-feature" "+zcz"
// RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
// RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
diff --git a/test/Preprocessor/arm-target-features.c b/test/Preprocessor/arm-target-features.c
index 81dab475fc..b206e1cf36 100644
--- a/test/Preprocessor/arm-target-features.c
+++ b/test/Preprocessor/arm-target-features.c
@@ -441,4 +441,5 @@
// CHECK-V82A: #define __ARM_ARCH 8
// CHECK-V82A: #define __ARM_ARCH_8_2A__ 1
// CHECK-V82A: #define __ARM_ARCH_PROFILE 'A'
+// CHECK-V82A: #define __ARM_FEATURE_QRDMX 1
// CHECK-V82A: #define __ARM_FP 0xE
diff --git a/test/Preprocessor/cuda-types.cu b/test/Preprocessor/cuda-types.cu
index 5f7b91655c..4ad3e4d97a 100644
--- a/test/Preprocessor/cuda-types.cu
+++ b/test/Preprocessor/cuda-types.cu
@@ -5,42 +5,44 @@
// FIXME: We really should make __GCC_HAVE_SYNC_COMPARE_AND_SWAP identical on
// host and device, but architecturally this is difficult at the moment.
+// RUN: mkdir -p %t
+
// RUN: %clang --cuda-host-only -nocudainc -target i386-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-host-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/i386-host-defines-filtered
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target i386-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-device-defines-filtered
-// RUN: diff %T/i386-host-defines-filtered %T/i386-device-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/i386-device-defines-filtered
+// RUN: diff %t/i386-host-defines-filtered %t/i386-device-defines-filtered
// RUN: %clang --cuda-host-only -nocudainc -target x86_64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-host-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/x86_64-host-defines-filtered
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target x86_64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-device-defines-filtered
-// RUN: diff %T/x86_64-host-defines-filtered %T/x86_64-device-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/x86_64-device-defines-filtered
+// RUN: diff %t/x86_64-host-defines-filtered %t/x86_64-device-defines-filtered
// RUN: %clang --cuda-host-only -nocudainc -target powerpc64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/powerpc64-host-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/powerpc64-host-defines-filtered
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target powerpc64-unknown-linux-gnu -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/powerpc64-device-defines-filtered
-// RUN: diff %T/powerpc64-host-defines-filtered %T/powerpc64-device-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/powerpc64-device-defines-filtered
+// RUN: diff %t/powerpc64-host-defines-filtered %t/powerpc64-device-defines-filtered
// RUN: %clang --cuda-host-only -nocudainc -target i386-windows-msvc -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-msvc-host-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/i386-msvc-host-defines-filtered
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target i386-windows-msvc -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/i386-msvc-device-defines-filtered
-// RUN: diff %T/i386-msvc-host-defines-filtered %T/i386-msvc-device-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/i386-msvc-device-defines-filtered
+// RUN: diff %t/i386-msvc-host-defines-filtered %t/i386-msvc-device-defines-filtered
// RUN: %clang --cuda-host-only -nocudainc -target x86_64-windows-msvc -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-msvc-host-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/x86_64-msvc-host-defines-filtered
// RUN: %clang --cuda-device-only -nocudainc -nocudalib -target x86_64-windows-msvc -x cuda -E -dM -o - /dev/null \
// RUN: | grep 'define __[^ ]*\(TYPE\|MAX\|SIZEOF|WIDTH\)\|define __GCC_ATOMIC' \
-// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %T/x86_64-msvc-device-defines-filtered
-// RUN: diff %T/x86_64-msvc-host-defines-filtered %T/x86_64-msvc-device-defines-filtered
+// RUN: | grep -v '__LDBL\|_LONG_DOUBLE' > %t/x86_64-msvc-device-defines-filtered
+// RUN: diff %t/x86_64-msvc-host-defines-filtered %t/x86_64-msvc-device-defines-filtered
diff --git a/test/Preprocessor/cxx_oper_keyword.cpp b/test/Preprocessor/cxx_oper_keyword.cpp
index 89a094d073..a66e890497 100644
--- a/test/Preprocessor/cxx_oper_keyword.cpp
+++ b/test/Preprocessor/cxx_oper_keyword.cpp
@@ -29,3 +29,15 @@
#ifdef and
#warning and is defined
#endif
+
+#ifdef OPERATOR_NAMES
+//expected-error@+2 {{invalid token at start of a preprocessor expression}}
+#endif
+#if or
+#endif
+
+#ifdef OPERATOR_NAMES
+//expected-error@+2 {{invalid token at start of a preprocessor expression}}
+#endif
+#if and_eq
+#endif
diff --git a/test/Preprocessor/hexagon-predefines.c b/test/Preprocessor/hexagon-predefines.c
index 065ecc0694..857ef8fc8c 100644
--- a/test/Preprocessor/hexagon-predefines.c
+++ b/test/Preprocessor/hexagon-predefines.c
@@ -1,32 +1,43 @@
// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv5 %s | FileCheck %s -check-prefix CHECK-V5
-
// CHECK-V5: #define __HEXAGON_ARCH__ 5
// CHECK-V5: #define __HEXAGON_V5__ 1
+// CHECK-V5-NOT: #define __HVX_LENGTH__
+// CHECK-V5-NOT: #define __HVX__ 1
// CHECK-V5: #define __hexagon__ 1
// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv55 %s | FileCheck %s -check-prefix CHECK-V55
-
// CHECK-V55: #define __HEXAGON_ARCH__ 55
// CHECK-V55: #define __HEXAGON_V55__ 1
+// CHECK-V55-NOT: #define __HVX_LENGTH__
+// CHECK-V55-NOT: #define __HVX__ 1
// CHECK-V55: #define __hexagon__ 1
// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv60 %s | FileCheck %s -check-prefix CHECK-V60
-
// CHECK-V60: #define __HEXAGON_ARCH__ 60
// CHECK-V60: #define __HEXAGON_V60__ 1
+// CHECK-V60-NOT: #define __HVX_LENGTH__
+// CHECK-V60-NOT: #define __HVX__ 1
// CHECK-V60: #define __hexagon__ 1
-// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv60 -target-feature +hvx %s | FileCheck %s -check-prefix CHECK-V60HVX
-
-// CHECK-V60HVX: #define __HEXAGON_ARCH__ 60
-// CHECK-V60HVX: #define __HEXAGON_V60__ 1
-// CHECK-V60HVX: #define __HVX__ 1
-
-// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv60 -target-feature +hvx-double %s | FileCheck %s -check-prefix CHECK-V60HVXD
-
-// CHECK-V60HVXD: #define __HEXAGON_ARCH__ 60
-// CHECK-V60HVXD: #define __HEXAGON_V60__ 1
-// CHECK-V60HVXD: #define __HVXDBL__ 1
-// CHECK-V60HVXD: #define __HVX__ 1
-// CHECK-V60HVXD: #define __hexagon__ 1
-
+// The HVX flags are explicitly defined by the driver.
+// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv60 \
+// RUN: -target-feature +hvxv60 -target-feature +hvx-length64b %s | FileCheck \
+// RUN: %s -check-prefix CHECK-V60HVX-64B
+// CHECK-V60HVX-64B: #define __HEXAGON_ARCH__ 60
+// CHECK-V60HVX-64B: #define __HEXAGON_V60__ 1
+// CHECK-V60HVX-64B-NOT: #define __HVXDBL__ 1
+// CHECK-V60HVX-64B: #define __HVX_ARCH__ 60
+// CHECK-V60HVX-64B: #define __HVX_LENGTH__ 64
+// CHECK-V60HVX-64B: #define __HVX__ 1
+// CHECK-V60HVX-64B: #define __hexagon__ 1
+
+// RUN: %clang_cc1 -E -dM -triple hexagon-unknown-elf -target-cpu hexagonv60 \
+// RUN: -target-feature +hvxv60 -target-feature +hvx-length128b %s | FileCheck \
+// RUN: %s -check-prefix CHECK-V60HVX-128B
+// CHECK-V60HVX-128B: #define __HEXAGON_ARCH__ 60
+// CHECK-V60HVX-128B: #define __HEXAGON_V60__ 1
+// CHECK-V60HVX-128B: #define __HVXDBL__ 1
+// CHECK-V60HVX-128B: #define __HVX_ARCH__ 60
+// CHECK-V60HVX-128B: #define __HVX_LENGTH__ 128
+// CHECK-V60HVX-128B: #define __HVX__ 1
+// CHECK-V60HVX-128B: #define __hexagon__ 1
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index cae6aa042b..87a591923b 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -9,13 +9,22 @@
// BLOCKS:#define __block __attribute__((__blocks__(byref)))
//
//
+// RUN: %clang_cc1 -x c++ -std=c++2a -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX2A %s
+//
+// CXX2A:#define __GNUG__ {{.*}}
+// CXX2A:#define __GXX_EXPERIMENTAL_CXX0X__ 1
+// CXX2A:#define __GXX_RTTI 1
+// CXX2A:#define __GXX_WEAK__ 1
+// CXX2A:#define __cplusplus 201707L
+// CXX2A:#define __private_extern__ extern
+//
// RUN: %clang_cc1 -x c++ -std=c++1z -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX1Z %s
//
// CXX1Z:#define __GNUG__ {{.*}}
// 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
//
//
@@ -110,12 +119,19 @@
// RUN: %clang_cc1 -ffreestanding -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix FREESTANDING %s
// FREESTANDING:#define __STDC_HOSTED__ 0
//
+// RUN: %clang_cc1 -x c++ -std=gnu++2a -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX2A %s
+//
+// GXX2A:#define __GNUG__ {{.*}}
+// GXX2A:#define __GXX_WEAK__ 1
+// GXX2A:#define __cplusplus 201707L
+// GXX2A:#define __private_extern__ extern
+//
//
// RUN: %clang_cc1 -x c++ -std=gnu++1z -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX1Z %s
//
// GXX1Z:#define __GNUG__ {{.*}}
// GXX1Z:#define __GXX_WEAK__ 1
-// GXX1Z:#define __cplusplus 201406L
+// GXX1Z:#define __cplusplus 201703L
// GXX1Z:#define __private_extern__ extern
//
//
@@ -237,18 +253,18 @@
// SCHAR-NOT:#define __UNSIGNED_CHAR__
// SCHAR:#define __clang__ 1
//
-// RUN: %clang_cc1 -E -dM -fshort-wchar < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR %s
+// RUN: %clang_cc1 -E -dM -fwchar-type=short -fno-signed-wchar < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR %s
// wchar_t is u16 for targeting Win32.
-// FIXME: Implement and check x86_64-cygwin.
-// RUN: %clang_cc1 -E -dM -fno-short-wchar -triple=x86_64-w64-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR %s
+// RUN: %clang_cc1 -E -dM -fwchar-type=short -fno-signed-wchar -triple=x86_64-w64-mingw32 < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR %s
+// RUN: %clang_cc1 -dM -fwchar-type=short -fno-signed-wchar -triple=x86_64-unknown-windows-cygnus -E /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR %s
//
// SHORTWCHAR: #define __SIZEOF_WCHAR_T__ 2
// SHORTWCHAR: #define __WCHAR_MAX__ 65535
// SHORTWCHAR: #define __WCHAR_TYPE__ unsigned short
// SHORTWCHAR: #define __WCHAR_WIDTH__ 16
//
-// RUN: %clang_cc1 -E -dM -fno-short-wchar -triple=i686-unknown-unknown < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR2 %s
-// RUN: %clang_cc1 -E -dM -fno-short-wchar -triple=x86_64-unknown-unknown < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR2 %s
+// RUN: %clang_cc1 -E -dM -fwchar-type=int -triple=i686-unknown-unknown < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR2 %s
+// RUN: %clang_cc1 -E -dM -fwchar-type=int -triple=x86_64-unknown-unknown < /dev/null | FileCheck -match-full-lines -check-prefix SHORTWCHAR2 %s
//
// SHORTWCHAR2: #define __SIZEOF_WCHAR_T__ 4
// SHORTWCHAR2: #define __WCHAR_WIDTH__ 32
@@ -285,6 +301,20 @@
// AARCH64:#define __DBL_MIN_EXP__ (-1021)
// AARCH64:#define __DBL_MIN__ 2.2250738585072014e-308
// AARCH64:#define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__
+// AARCH64:#define __FLT16_DECIMAL_DIG__ 5
+// AARCH64:#define __FLT16_DENORM_MIN__ 5.9604644775390625e-8F16
+// AARCH64:#define __FLT16_DIG__ 3
+// AARCH64:#define __FLT16_EPSILON__ 9.765625e-4F16
+// AARCH64:#define __FLT16_HAS_DENORM__ 1
+// AARCH64:#define __FLT16_HAS_INFINITY__ 1
+// AARCH64:#define __FLT16_HAS_QUIET_NAN__ 1
+// AARCH64:#define __FLT16_MANT_DIG__ 11
+// AARCH64:#define __FLT16_MAX_10_EXP__ 4
+// AARCH64:#define __FLT16_MAX_EXP__ 15
+// AARCH64:#define __FLT16_MAX__ 6.5504e+4F16
+// AARCH64:#define __FLT16_MIN_10_EXP__ (-13)
+// AARCH64:#define __FLT16_MIN_EXP__ (-14)
+// AARCH64:#define __FLT16_MIN__ 6.103515625e-5F16
// AARCH64:#define __FLT_DENORM_MIN__ 1.40129846e-45F
// AARCH64:#define __FLT_DIG__ 6
// AARCH64:#define __FLT_EPSILON__ 1.19209290e-7F
@@ -930,7 +960,7 @@
// 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_LEAST32_TYPE__ int
// AARCH64-OPENBSD:#define __INT_LEAST64_FMTd__ "ld"
// AARCH64-OPENBSD:#define __INT_LEAST64_FMTi__ "li"
// AARCH64-OPENBSD:#define __INT_LEAST64_MAX__ 9223372036854775807L
@@ -1220,13 +1250,13 @@
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-apple-ios7.0 < /dev/null | FileCheck -match-full-lines -check-prefix AARCH64-DARWIN %s
//
// AARCH64-DARWIN: #define _LP64 1
-// AARCH64-NOT: #define __AARCH64EB__ 1
+// AARCH64-DARWIN-NOT: #define __AARCH64EB__ 1
// AARCH64-DARWIN: #define __AARCH64EL__ 1
-// AARCH64-NOT: #define __AARCH_BIG_ENDIAN 1
+// AARCH64-DARWIN-NOT: #define __AARCH_BIG_ENDIAN 1
// AARCH64-DARWIN: #define __ARM_64BIT_STATE 1
// AARCH64-DARWIN: #define __ARM_ARCH 8
// AARCH64-DARWIN: #define __ARM_ARCH_ISA_A64 1
-// AARCH64-NOT: #define __ARM_BIG_ENDIAN 1
+// AARCH64-DARWIN-NOT: #define __ARM_BIG_ENDIAN 1
// AARCH64-DARWIN: #define __BIGGEST_ALIGNMENT__ 8
// AARCH64-DARWIN: #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
// AARCH64-DARWIN: #define __CHAR16_TYPE__ unsigned short
@@ -1408,6 +1438,167 @@
// AARCH64-DARWIN: #define __WINT_WIDTH__ 32
// AARCH64-DARWIN: #define __aarch64__ 1
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-windows-msvc < /dev/null | FileCheck -match-full-lines -check-prefix AARCH64-MSVC %s
+//
+// AARCH64-MSVC: #define _INTEGRAL_MAX_BITS 64
+// AARCH64-MSVC-NOT: #define _LP64 1
+// AARCH64-MSVC: #define _M_ARM64 1
+// AARCH64-MSVC: #define _WIN32 1
+// AARCH64-MSVC: #define _WIN64 1
+// AARCH64-MSVC: #define __AARCH64EL__ 1
+// AARCH64-MSVC: #define __ARM_64BIT_STATE 1
+// AARCH64-MSVC: #define __ARM_ACLE 200
+// AARCH64-MSVC: #define __ARM_ALIGN_MAX_STACK_PWR 4
+// AARCH64-MSVC: #define __ARM_ARCH 8
+// AARCH64-MSVC: #define __ARM_ARCH_ISA_A64 1
+// AARCH64-MSVC: #define __ARM_ARCH_PROFILE 'A'
+// AARCH64-MSVC: #define __ARM_FEATURE_CLZ 1
+// AARCH64-MSVC: #define __ARM_FEATURE_DIRECTED_ROUNDING 1
+// AARCH64-MSVC: #define __ARM_FEATURE_DIV 1
+// AARCH64-MSVC: #define __ARM_FEATURE_FMA 1
+// AARCH64-MSVC: #define __ARM_FEATURE_IDIV 1
+// AARCH64-MSVC: #define __ARM_FEATURE_LDREX 0xF
+// AARCH64-MSVC: #define __ARM_FEATURE_NUMERIC_MAXMIN 1
+// AARCH64-MSVC: #define __ARM_FEATURE_UNALIGNED 1
+// AARCH64-MSVC: #define __ARM_FP 0xE
+// AARCH64-MSVC: #define __ARM_FP16_ARGS 1
+// AARCH64-MSVC: #define __ARM_FP16_FORMAT_IEEE 1
+// AARCH64-MSVC: #define __ARM_PCS_AAPCS64 1
+// AARCH64-MSVC: #define __ARM_SIZEOF_MINIMAL_ENUM 4
+// AARCH64-MSVC: #define __ARM_SIZEOF_WCHAR_T 4
+// AARCH64-MSVC: #define __BIGGEST_ALIGNMENT__ 16
+// AARCH64-MSVC: #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// AARCH64-MSVC: #define __CHAR16_TYPE__ unsigned short
+// AARCH64-MSVC: #define __CHAR32_TYPE__ unsigned int
+// AARCH64-MSVC: #define __CHAR_BIT__ 8
+// AARCH64-MSVC: #define __CONSTANT_CFSTRINGS__ 1
+// AARCH64-MSVC: #define __DBL_DECIMAL_DIG__ 17
+// AARCH64-MSVC: #define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// AARCH64-MSVC: #define __DBL_DIG__ 15
+// AARCH64-MSVC: #define __DBL_EPSILON__ 2.2204460492503131e-16
+// AARCH64-MSVC: #define __DBL_HAS_DENORM__ 1
+// AARCH64-MSVC: #define __DBL_HAS_INFINITY__ 1
+// AARCH64-MSVC: #define __DBL_HAS_QUIET_NAN__ 1
+// AARCH64-MSVC: #define __DBL_MANT_DIG__ 53
+// AARCH64-MSVC: #define __DBL_MAX_10_EXP__ 308
+// AARCH64-MSVC: #define __DBL_MAX_EXP__ 1024
+// AARCH64-MSVC: #define __DBL_MAX__ 1.7976931348623157e+308
+// AARCH64-MSVC: #define __DBL_MIN_10_EXP__ (-307)
+// AARCH64-MSVC: #define __DBL_MIN_EXP__ (-1021)
+// AARCH64-MSVC: #define __DBL_MIN__ 2.2250738585072014e-308
+// AARCH64-MSVC: #define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__
+// AARCH64-MSVC: #define __FINITE_MATH_ONLY__ 0
+// AARCH64-MSVC: #define __FLT_DECIMAL_DIG__ 9
+// AARCH64-MSVC: #define __FLT_DENORM_MIN__ 1.40129846e-45F
+// AARCH64-MSVC: #define __FLT_DIG__ 6
+// AARCH64-MSVC: #define __FLT_EPSILON__ 1.19209290e-7F
+// AARCH64-MSVC: #define __FLT_EVAL_METHOD__ 0
+// AARCH64-MSVC: #define __FLT_HAS_DENORM__ 1
+// AARCH64-MSVC: #define __FLT_HAS_INFINITY__ 1
+// AARCH64-MSVC: #define __FLT_HAS_QUIET_NAN__ 1
+// AARCH64-MSVC: #define __FLT_MANT_DIG__ 24
+// AARCH64-MSVC: #define __FLT_MAX_10_EXP__ 38
+// AARCH64-MSVC: #define __FLT_MAX_EXP__ 128
+// AARCH64-MSVC: #define __FLT_MAX__ 3.40282347e+38F
+// AARCH64-MSVC: #define __FLT_MIN_10_EXP__ (-37)
+// AARCH64-MSVC: #define __FLT_MIN_EXP__ (-125)
+// AARCH64-MSVC: #define __FLT_MIN__ 1.17549435e-38F
+// AARCH64-MSVC: #define __FLT_RADIX__ 2
+// AARCH64-MSVC: #define __INT_MAX__ 2147483647
+// AARCH64-MSVC: #define __LDBL_DECIMAL_DIG__ 17
+// AARCH64-MSVC: #define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L
+// AARCH64-MSVC: #define __LDBL_DIG__ 15
+// AARCH64-MSVC: #define __LDBL_EPSILON__ 2.2204460492503131e-16L
+// AARCH64-MSVC: #define __LDBL_HAS_DENORM__ 1
+// AARCH64-MSVC: #define __LDBL_HAS_INFINITY__ 1
+// AARCH64-MSVC: #define __LDBL_HAS_QUIET_NAN__ 1
+// AARCH64-MSVC: #define __LDBL_MANT_DIG__ 53
+// AARCH64-MSVC: #define __LDBL_MAX_10_EXP__ 308
+// AARCH64-MSVC: #define __LDBL_MAX_EXP__ 1024
+// AARCH64-MSVC: #define __LDBL_MAX__ 1.7976931348623157e+308L
+// AARCH64-MSVC: #define __LDBL_MIN_10_EXP__ (-307)
+// AARCH64-MSVC: #define __LDBL_MIN_EXP__ (-1021)
+// AARCH64-MSVC: #define __LDBL_MIN__ 2.2250738585072014e-308L
+// AARCH64-MSVC: #define __LITTLE_ENDIAN__ 1
+// AARCH64-MSVC: #define __LONG_LONG_MAX__ 9223372036854775807LL
+// AARCH64-MSVC: #define __LONG_MAX__ 2147483647L
+// AARCH64-MSVC-NOT: #define __LP64__ 1
+// AARCH64-MSVC: #define __NO_INLINE__ 1
+// AARCH64-MSVC: #define __OBJC_BOOL_IS_BOOL 0
+// AARCH64-MSVC: #define __ORDER_BIG_ENDIAN__ 4321
+// AARCH64-MSVC: #define __ORDER_LITTLE_ENDIAN__ 1234
+// AARCH64-MSVC: #define __ORDER_PDP_ENDIAN__ 3412
+// AARCH64-MSVC: #define __POINTER_WIDTH__ 64
+// AARCH64-MSVC: #define __PRAGMA_REDEFINE_EXTNAME 1
+// AARCH64-MSVC: #define __SCHAR_MAX__ 127
+// AARCH64-MSVC: #define __SHRT_MAX__ 32767
+// AARCH64-MSVC: #define __SIG_ATOMIC_MAX__ 2147483647
+// AARCH64-MSVC: #define __SIG_ATOMIC_WIDTH__ 32
+// AARCH64-MSVC: #define __SIZEOF_DOUBLE__ 8
+// AARCH64-MSVC: #define __SIZEOF_FLOAT__ 4
+// AARCH64-MSVC: #define __SIZEOF_INT128__ 16
+// AARCH64-MSVC: #define __SIZEOF_INT__ 4
+// AARCH64-MSVC: #define __SIZEOF_LONG_DOUBLE__ 8
+// AARCH64-MSVC: #define __SIZEOF_LONG_LONG__ 8
+// AARCH64-MSVC: #define __SIZEOF_LONG__ 4
+// AARCH64-MSVC: #define __SIZEOF_POINTER__ 8
+// AARCH64-MSVC: #define __SIZEOF_PTRDIFF_T__ 8
+// AARCH64-MSVC: #define __SIZEOF_SHORT__ 2
+// AARCH64-MSVC: #define __SIZEOF_SIZE_T__ 8
+// AARCH64-MSVC: #define __SIZEOF_WCHAR_T__ 2
+// AARCH64-MSVC: #define __SIZEOF_WINT_T__ 4
+// AARCH64-MSVC: #define __SIZE_MAX__ 18446744073709551615ULL
+// AARCH64-MSVC: #define __SIZE_TYPE__ long long unsigned int
+// AARCH64-MSVC: #define __SIZE_WIDTH__ 64
+// AARCH64-MSVC: #define __STDC_HOSTED__ 0
+// AARCH64-MSVC: #define __STDC_UTF_16__ 1
+// AARCH64-MSVC: #define __STDC_UTF_32__ 1
+// AARCH64-MSVC: #define __STDC_VERSION__ 201112L
+// AARCH64-MSVC: #define __STDC__ 1
+// AARCH64-MSVC: #define __UINT16_C_SUFFIX__
+// AARCH64-MSVC: #define __UINT16_MAX__ 65535
+// AARCH64-MSVC: #define __UINT16_TYPE__ unsigned short
+// AARCH64-MSVC: #define __UINT32_C_SUFFIX__ U
+// AARCH64-MSVC: #define __UINT32_MAX__ 4294967295U
+// AARCH64-MSVC: #define __UINT32_TYPE__ unsigned int
+// AARCH64-MSVC: #define __UINT64_C_SUFFIX__ ULL
+// AARCH64-MSVC: #define __UINT64_MAX__ 18446744073709551615ULL
+// AARCH64-MSVC: #define __UINT64_TYPE__ long long unsigned int
+// AARCH64-MSVC: #define __UINT8_C_SUFFIX__
+// AARCH64-MSVC: #define __UINT8_MAX__ 255
+// AARCH64-MSVC: #define __UINT8_TYPE__ unsigned char
+// AARCH64-MSVC: #define __UINTMAX_C_SUFFIX__ ULL
+// AARCH64-MSVC: #define __UINTMAX_MAX__ 18446744073709551615ULL
+// AARCH64-MSVC: #define __UINTMAX_TYPE__ long long unsigned int
+// AARCH64-MSVC: #define __UINTMAX_WIDTH__ 64
+// AARCH64-MSVC: #define __UINTPTR_MAX__ 18446744073709551615ULL
+// AARCH64-MSVC: #define __UINTPTR_TYPE__ long long unsigned int
+// AARCH64-MSVC: #define __UINTPTR_WIDTH__ 64
+// AARCH64-MSVC: #define __UINT_FAST16_MAX__ 65535
+// AARCH64-MSVC: #define __UINT_FAST16_TYPE__ unsigned short
+// AARCH64-MSVC: #define __UINT_FAST32_MAX__ 4294967295U
+// AARCH64-MSVC: #define __UINT_FAST32_TYPE__ unsigned int
+// AARCH64-MSVC: #define __UINT_FAST64_MAX__ 18446744073709551615ULL
+// AARCH64-MSVC: #define __UINT_FAST64_TYPE__ long long unsigned int
+// AARCH64-MSVC: #define __UINT_FAST8_MAX__ 255
+// AARCH64-MSVC: #define __UINT_FAST8_TYPE__ unsigned char
+// AARCH64-MSVC: #define __UINT_LEAST16_MAX__ 65535
+// AARCH64-MSVC: #define __UINT_LEAST16_TYPE__ unsigned short
+// AARCH64-MSVC: #define __UINT_LEAST32_MAX__ 4294967295U
+// AARCH64-MSVC: #define __UINT_LEAST32_TYPE__ unsigned int
+// AARCH64-MSVC: #define __UINT_LEAST64_MAX__ 18446744073709551615ULL
+// AARCH64-MSVC: #define __UINT_LEAST64_TYPE__ long long unsigned int
+// AARCH64-MSVC: #define __UINT_LEAST8_MAX__ 255
+// AARCH64-MSVC: #define __UINT_LEAST8_TYPE__ unsigned char
+// AARCH64-MSVC: #define __USER_LABEL_PREFIX__
+// AARCH64-MSVC: #define __WCHAR_MAX__ 65535
+// AARCH64-MSVC: #define __WCHAR_TYPE__ unsigned short
+// AARCH64-MSVC: #define __WCHAR_UNSIGNED__ 1
+// AARCH64-MSVC: #define __WCHAR_WIDTH__ 16
+// AARCH64-MSVC: #define __WINT_TYPE__ int
+// AARCH64-MSVC: #define __WINT_WIDTH__ 32
+// AARCH64-MSVC: #define __aarch64__ 1
+
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-none < /dev/null | FileCheck -match-full-lines -check-prefix ARM %s
// RUN: %clang_cc1 -x c++ -E -dM -ffreestanding -triple=arm-none-none < /dev/null | FileCheck -match-full-lines -check-prefix ARM -check-prefix ARM-CXX %s
//
@@ -1477,10 +1668,10 @@
// ARM:#define __INTMAX_MAX__ 9223372036854775807LL
// ARM:#define __INTMAX_TYPE__ long long int
// ARM:#define __INTMAX_WIDTH__ 64
-// ARM:#define __INTPTR_FMTd__ "ld"
-// ARM:#define __INTPTR_FMTi__ "li"
-// ARM:#define __INTPTR_MAX__ 2147483647L
-// ARM:#define __INTPTR_TYPE__ long int
+// ARM:#define __INTPTR_FMTd__ "d"
+// ARM:#define __INTPTR_FMTi__ "i"
+// ARM:#define __INTPTR_MAX__ 2147483647
+// ARM:#define __INTPTR_TYPE__ int
// ARM:#define __INTPTR_WIDTH__ 32
// ARM:#define __INT_FAST16_FMTd__ "hd"
// ARM:#define __INT_FAST16_FMTi__ "hi"
@@ -1572,8 +1763,8 @@
// ARM:#define __UINTMAX_MAX__ 18446744073709551615ULL
// ARM:#define __UINTMAX_TYPE__ long long unsigned int
// ARM:#define __UINTMAX_WIDTH__ 64
-// ARM:#define __UINTPTR_MAX__ 4294967295UL
-// ARM:#define __UINTPTR_TYPE__ long unsigned int
+// ARM:#define __UINTPTR_MAX__ 4294967295U
+// ARM:#define __UINTPTR_TYPE__ unsigned int
// ARM:#define __UINTPTR_WIDTH__ 32
// ARM:#define __UINT_FAST16_MAX__ 65535
// ARM:#define __UINT_FAST16_TYPE__ unsigned short
@@ -1600,6 +1791,11 @@
// ARM:#define __arm 1
// ARM:#define __arm__ 1
+// RUN: %clang_cc1 -dM -ffreestanding -triple arm-none-none -target-abi apcs-gnu -E /dev/null -o - | FileCheck -match-full-lines -check-prefix ARM-APCS-GNU %s
+// ARM-APCS-GNU: #define __INTPTR_TYPE__ int
+// ARM-APCS-GNU: #define __PTRDIFF_TYPE__ int
+// ARM-APCS-GNU: #define __SIZE_TYPE__ unsigned int
+
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=armeb-none-none < /dev/null | FileCheck -match-full-lines -check-prefix ARM-BE %s
//
// ARM-BE-NOT:#define _LP64
@@ -1669,10 +1865,10 @@
// ARM-BE:#define __INTMAX_MAX__ 9223372036854775807LL
// ARM-BE:#define __INTMAX_TYPE__ long long int
// ARM-BE:#define __INTMAX_WIDTH__ 64
-// ARM-BE:#define __INTPTR_FMTd__ "ld"
-// ARM-BE:#define __INTPTR_FMTi__ "li"
-// ARM-BE:#define __INTPTR_MAX__ 2147483647L
-// ARM-BE:#define __INTPTR_TYPE__ long int
+// ARM-BE:#define __INTPTR_FMTd__ "d"
+// ARM-BE:#define __INTPTR_FMTi__ "i"
+// ARM-BE:#define __INTPTR_MAX__ 2147483647
+// ARM-BE:#define __INTPTR_TYPE__ int
// ARM-BE:#define __INTPTR_WIDTH__ 32
// ARM-BE:#define __INT_FAST16_FMTd__ "hd"
// ARM-BE:#define __INT_FAST16_FMTi__ "hi"
@@ -1762,8 +1958,8 @@
// ARM-BE:#define __UINTMAX_MAX__ 18446744073709551615ULL
// ARM-BE:#define __UINTMAX_TYPE__ long long unsigned int
// ARM-BE:#define __UINTMAX_WIDTH__ 64
-// ARM-BE:#define __UINTPTR_MAX__ 4294967295UL
-// ARM-BE:#define __UINTPTR_TYPE__ long unsigned int
+// ARM-BE:#define __UINTPTR_MAX__ 4294967295U
+// ARM-BE:#define __UINTPTR_TYPE__ unsigned int
// ARM-BE:#define __UINTPTR_WIDTH__ 32
// ARM-BE:#define __UINT_FAST16_MAX__ 65535
// ARM-BE:#define __UINT_FAST16_TYPE__ unsigned short
@@ -1862,10 +2058,10 @@
// ARMEABISOFTFP:#define __INTMAX_MAX__ 9223372036854775807LL
// ARMEABISOFTFP:#define __INTMAX_TYPE__ long long int
// ARMEABISOFTFP:#define __INTMAX_WIDTH__ 64
-// ARMEABISOFTFP:#define __INTPTR_FMTd__ "ld"
-// ARMEABISOFTFP:#define __INTPTR_FMTi__ "li"
-// ARMEABISOFTFP:#define __INTPTR_MAX__ 2147483647L
-// ARMEABISOFTFP:#define __INTPTR_TYPE__ long int
+// ARMEABISOFTFP:#define __INTPTR_FMTd__ "d"
+// ARMEABISOFTFP:#define __INTPTR_FMTi__ "i"
+// ARMEABISOFTFP:#define __INTPTR_MAX__ 2147483647
+// ARMEABISOFTFP:#define __INTPTR_TYPE__ int
// ARMEABISOFTFP:#define __INTPTR_WIDTH__ 32
// ARMEABISOFTFP:#define __INT_FAST16_FMTd__ "hd"
// ARMEABISOFTFP:#define __INT_FAST16_FMTi__ "hi"
@@ -1957,8 +2153,8 @@
// ARMEABISOFTFP:#define __UINTMAX_MAX__ 18446744073709551615ULL
// ARMEABISOFTFP:#define __UINTMAX_TYPE__ long long unsigned int
// ARMEABISOFTFP:#define __UINTMAX_WIDTH__ 64
-// ARMEABISOFTFP:#define __UINTPTR_MAX__ 4294967295UL
-// ARMEABISOFTFP:#define __UINTPTR_TYPE__ long unsigned int
+// ARMEABISOFTFP:#define __UINTPTR_MAX__ 4294967295U
+// ARMEABISOFTFP:#define __UINTPTR_TYPE__ unsigned int
// ARMEABISOFTFP:#define __UINTPTR_WIDTH__ 32
// ARMEABISOFTFP:#define __UINT_FAST16_MAX__ 65535
// ARMEABISOFTFP:#define __UINT_FAST16_TYPE__ unsigned short
@@ -2057,10 +2253,10 @@
// ARMEABIHARDFP:#define __INTMAX_MAX__ 9223372036854775807LL
// ARMEABIHARDFP:#define __INTMAX_TYPE__ long long int
// ARMEABIHARDFP:#define __INTMAX_WIDTH__ 64
-// ARMEABIHARDFP:#define __INTPTR_FMTd__ "ld"
-// ARMEABIHARDFP:#define __INTPTR_FMTi__ "li"
-// ARMEABIHARDFP:#define __INTPTR_MAX__ 2147483647L
-// ARMEABIHARDFP:#define __INTPTR_TYPE__ long int
+// ARMEABIHARDFP:#define __INTPTR_FMTd__ "d"
+// ARMEABIHARDFP:#define __INTPTR_FMTi__ "i"
+// ARMEABIHARDFP:#define __INTPTR_MAX__ 2147483647
+// ARMEABIHARDFP:#define __INTPTR_TYPE__ int
// ARMEABIHARDFP:#define __INTPTR_WIDTH__ 32
// ARMEABIHARDFP:#define __INT_FAST16_FMTd__ "hd"
// ARMEABIHARDFP:#define __INT_FAST16_FMTi__ "hi"
@@ -2152,8 +2348,8 @@
// ARMEABIHARDFP:#define __UINTMAX_MAX__ 18446744073709551615ULL
// ARMEABIHARDFP:#define __UINTMAX_TYPE__ long long unsigned int
// ARMEABIHARDFP:#define __UINTMAX_WIDTH__ 64
-// ARMEABIHARDFP:#define __UINTPTR_MAX__ 4294967295UL
-// ARMEABIHARDFP:#define __UINTPTR_TYPE__ long unsigned int
+// ARMEABIHARDFP:#define __UINTPTR_MAX__ 4294967295U
+// ARMEABIHARDFP:#define __UINTPTR_TYPE__ unsigned int
// ARMEABIHARDFP:#define __UINTPTR_WIDTH__ 32
// ARMEABIHARDFP:#define __UINT_FAST16_MAX__ 65535
// ARMEABIHARDFP:#define __UINT_FAST16_TYPE__ unsigned short
@@ -2185,13 +2381,13 @@
// ARMV6-CLOUDABI:#define __CloudABI__ 1
// ARMV6-CLOUDABI:#define __arm__ 1
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-netbsd-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NETBSD %s
-//
+// RUN: %clang -E -dM -ffreestanding -target arm-netbsd-eabi %s -o - | FileCheck -match-full-lines -check-prefix ARM-NETBSD %s
+
// ARM-NETBSD-NOT:#define _LP64
// ARM-NETBSD:#define __APCS_32__ 1
// ARM-NETBSD-NOT:#define __ARMEB__ 1
// ARM-NETBSD:#define __ARMEL__ 1
-// ARM-NETBSD:#define __ARM_ARCH_4T__ 1
+// ARM-NETBSD:#define __ARM_ARCH_5TE__ 1
// ARM-NETBSD:#define __ARM_DWARF_EH__ 1
// ARM-NETBSD:#define __ARM_EABI__ 1
// ARM-NETBSD-NOT:#define __ARM_BIG_ENDIAN 1
@@ -2333,6 +2529,7 @@
// ARM-NETBSD:#define __SIZE_MAX__ 4294967295UL
// ARM-NETBSD:#define __SIZE_TYPE__ long unsigned int
// ARM-NETBSD:#define __SIZE_WIDTH__ 32
+// ARM-NETBSD:#define __SOFTFP__ 1
// ARM-NETBSD:#define __UINT16_C_SUFFIX__
// ARM-NETBSD:#define __UINT16_MAX__ 65535
// ARM-NETBSD:#define __UINT16_TYPE__ unsigned short
@@ -2377,7 +2574,15 @@
// ARM-NETBSD:#define __arm 1
// ARM-NETBSD:#define __arm__ 1
+// RUN: %clang -E -dM -ffreestanding -target arm-netbsd-eabihf %s -o - | FileCheck -match-full-lines -check-prefix ARMHF-NETBSD %s
+// ARMHF-NETBSD:#define __SIZE_WIDTH__ 32
+// ARMHF-NETBSD-NOT:#define __SOFTFP__ 1
+// ARMHF-NETBSD:#define __UINT16_C_SUFFIX__
+
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-eabihf < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-none-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-none-eabihf < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s
// ARM-NONE-EABI: #define __ELF__ 1
// No MachO targets use the full EABI, even if AAPCS is used.
@@ -2388,13 +2593,6 @@
// RUN: %clang -target x86_64-apple-darwin -arch armv7 -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=ARM-MACHO-NO-EABI %s
// ARM-MACHO-NO-EABI-NOT: #define __ARM_EABI__ 1
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=armv7-bitrig-gnueabihf < /dev/null | FileCheck -match-full-lines -check-prefix ARM-BITRIG %s
-// ARM-BITRIG:#define __ARM_DWARF_EH__ 1
-// ARM-BITRIG:#define __SIZEOF_SIZE_T__ 4
-// ARM-BITRIG:#define __SIZE_MAX__ 4294967295UL
-// ARM-BITRIG:#define __SIZE_TYPE__ long unsigned int
-// ARM-BITRIG:#define __SIZE_WIDTH__ 32
-
// Check that -mhwdiv works properly for targets which don't have the hwdiv feature enabled by default.
// RUN: %clang -target arm -mhwdiv=arm -x c -E -dM %s -o - | FileCheck -match-full-lines --check-prefix=ARMHWDIV-ARM %s
@@ -4661,6 +4859,16 @@
// RUN: | FileCheck -match-full-lines -check-prefix MIPS-MSA %s
// MIPS-MSA:#define __mips_msa 1
//
+// RUN: %clang_cc1 -target-feature +nomadd4 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MIPS-NOMADD4 %s
+// MIPS-NOMADD4:#define __mips_no_madd4 1
+//
+// RUN: %clang_cc1 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MIPS-MADD4 %s
+// MIPS-MADD4-NOT:#define __mips_no_madd4 1
+//
// RUN: %clang_cc1 -target-cpu mips32r3 -target-feature +nan2008 \
// RUN: -E -dM -triple=mips-none-none < /dev/null \
// RUN: | FileCheck -match-full-lines -check-prefix MIPS-NAN2008 %s
@@ -4671,6 +4879,16 @@
// RUN: | FileCheck -match-full-lines -check-prefix NOMIPS-NAN2008 %s
// NOMIPS-NAN2008-NOT:#define __mips_nan2008 1
//
+// RUN: %clang_cc1 -target-cpu mips32r3 -target-feature +abs2008 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MIPS-ABS2008 %s
+// MIPS-ABS2008:#define __mips_abs2008 1
+//
+// RUN: %clang_cc1 -target-cpu mips32r3 -target-feature -abs2008 \
+// RUN: -E -dM -triple=mips-none-none < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix NOMIPS-ABS2008 %s
+// NOMIPS-ABS2008-NOT:#define __mips_abs2008 1
+//
// RUN: %clang_cc1 -target-feature -fp64 \
// RUN: -E -dM -triple=mips-none-none < /dev/null \
// RUN: | FileCheck -match-full-lines -check-prefix MIPS32-MFP32 %s
@@ -5324,7 +5542,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
@@ -5436,6 +5654,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
@@ -5524,7 +5743,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
@@ -5560,6 +5779,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"
@@ -5637,6 +5857,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
@@ -5728,7 +5949,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
@@ -5763,6 +5984,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"
@@ -5841,6 +6063,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
@@ -6093,6 +6316,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
@@ -6141,8 +6367,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
@@ -6178,6 +6405,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"
@@ -6255,6 +6483,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
@@ -6343,12 +6572,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
@@ -6384,6 +6618,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"
@@ -6461,6 +6696,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
@@ -6539,7 +6775,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
@@ -6575,6 +6811,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"
@@ -6652,6 +6889,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
@@ -6727,6 +6965,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
@@ -6766,6 +7008,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"
@@ -6843,6 +7086,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
@@ -6922,7 +7166,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
//
@@ -8737,6 +8984,7 @@
// KFREEBSDI686-DEFINE:#define __GLIBC__ 1
//
// RUN: %clang_cc1 -x c++ -triple i686-pc-linux-gnu -fobjc-runtime=gcc -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GNUSOURCE %s
+// RUN: %clang_cc1 -x c++ -triple sparc-rtems-elf -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GNUSOURCE %s
// GNUSOURCE:#define _GNU_SOURCE 1
//
// RUN: %clang_cc1 -x c++ -std=c++98 -fno-rtti -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix NORTTI %s
@@ -8814,6 +9062,16 @@
// WEBASSEMBLY32-NEXT:#define __CHAR32_TYPE__ unsigned int
// WEBASSEMBLY32-NEXT:#define __CHAR_BIT__ 8
// WEBASSEMBLY32-NOT:#define __CHAR_UNSIGNED__
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_BOOL_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_CHAR16_T_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_CHAR32_T_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_CHAR_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_INT_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_LLONG_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_LONG_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_POINTER_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_SHORT_LOCK_FREE 2
+// WEBASSEMBLY32-NEXT:#define __CLANG_ATOMIC_WCHAR_T_LOCK_FREE 2
// WEBASSEMBLY32-NEXT:#define __CONSTANT_CFSTRINGS__ 1
// WEBASSEMBLY32-NEXT:#define __DBL_DECIMAL_DIG__ 17
// WEBASSEMBLY32-NEXT:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
@@ -8832,7 +9090,7 @@
// WEBASSEMBLY32-NEXT:#define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__
// WEBASSEMBLY32-NOT:#define __ELF__
// WEBASSEMBLY32-NEXT:#define __FINITE_MATH_ONLY__ 0
-// WEBASSEMBLY32-NEXT:#define __FLT_DECIMAL_DIG__ 9
+// WEBASSEMBLY32:#define __FLT_DECIMAL_DIG__ 9
// WEBASSEMBLY32-NEXT:#define __FLT_DENORM_MIN__ 1.40129846e-45F
// WEBASSEMBLY32-NEXT:#define __FLT_DIG__ 6
// WEBASSEMBLY32-NEXT:#define __FLT_EPSILON__ 1.19209290e-7F
@@ -8853,7 +9111,7 @@
// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2
// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_CHAR_LOCK_FREE 2
// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_INT_LOCK_FREE 2
-// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_LLONG_LOCK_FREE 1
+// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_LLONG_LOCK_FREE 2
// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_LONG_LOCK_FREE 2
// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_POINTER_LOCK_FREE 2
// WEBASSEMBLY32-NEXT:#define __GCC_ATOMIC_SHORT_LOCK_FREE 2
@@ -8949,6 +9207,11 @@
// WEBASSEMBLY32-NOT:#define __LP64__
// WEBASSEMBLY32-NEXT:#define __NO_INLINE__ 1
// WEBASSEMBLY32-NEXT:#define __OBJC_BOOL_IS_BOOL 0
+// WEBASSEMBLY32-NEXT:#define __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES 3
+// WEBASSEMBLY32-NEXT:#define __OPENCL_MEMORY_SCOPE_DEVICE 2
+// WEBASSEMBLY32-NEXT:#define __OPENCL_MEMORY_SCOPE_SUB_GROUP 4
+// WEBASSEMBLY32-NEXT:#define __OPENCL_MEMORY_SCOPE_WORK_GROUP 1
+// WEBASSEMBLY32-NEXT:#define __OPENCL_MEMORY_SCOPE_WORK_ITEM 0
// WEBASSEMBLY32-NEXT:#define __ORDER_BIG_ENDIAN__ 4321
// WEBASSEMBLY32-NEXT:#define __ORDER_LITTLE_ENDIAN__ 1234
// WEBASSEMBLY32-NEXT:#define __ORDER_PDP_ENDIAN__ 3412
@@ -9130,6 +9393,16 @@
// WEBASSEMBLY64-NEXT:#define __CHAR32_TYPE__ unsigned int
// WEBASSEMBLY64-NEXT:#define __CHAR_BIT__ 8
// WEBASSEMBLY64-NOT:#define __CHAR_UNSIGNED__
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_BOOL_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_CHAR16_T_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_CHAR32_T_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_CHAR_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_INT_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_LLONG_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_LONG_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_POINTER_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_SHORT_LOCK_FREE 2
+// WEBASSEMBLY64-NEXT:#define __CLANG_ATOMIC_WCHAR_T_LOCK_FREE 2
// WEBASSEMBLY64-NEXT:#define __CONSTANT_CFSTRINGS__ 1
// WEBASSEMBLY64-NEXT:#define __DBL_DECIMAL_DIG__ 17
// WEBASSEMBLY64-NEXT:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
@@ -9148,7 +9421,7 @@
// WEBASSEMBLY64-NEXT:#define __DECIMAL_DIG__ __LDBL_DECIMAL_DIG__
// WEBASSEMBLY64-NOT:#define __ELF__
// WEBASSEMBLY64-NEXT:#define __FINITE_MATH_ONLY__ 0
-// WEBASSEMBLY64-NEXT:#define __FLT_DECIMAL_DIG__ 9
+// WEBASSEMBLY64:#define __FLT_DECIMAL_DIG__ 9
// WEBASSEMBLY64-NEXT:#define __FLT_DENORM_MIN__ 1.40129846e-45F
// WEBASSEMBLY64-NEXT:#define __FLT_DIG__ 6
// WEBASSEMBLY64-NEXT:#define __FLT_EPSILON__ 1.19209290e-7F
@@ -9265,6 +9538,11 @@
// WEBASSEMBLY64-NEXT:#define __LP64__ 1
// WEBASSEMBLY64-NEXT:#define __NO_INLINE__ 1
// WEBASSEMBLY64-NEXT:#define __OBJC_BOOL_IS_BOOL 0
+// WEBASSEMBLY64-NEXT:#define __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES 3
+// WEBASSEMBLY64-NEXT:#define __OPENCL_MEMORY_SCOPE_DEVICE 2
+// WEBASSEMBLY64-NEXT:#define __OPENCL_MEMORY_SCOPE_SUB_GROUP 4
+// WEBASSEMBLY64-NEXT:#define __OPENCL_MEMORY_SCOPE_WORK_GROUP 1
+// WEBASSEMBLY64-NEXT:#define __OPENCL_MEMORY_SCOPE_WORK_ITEM 0
// WEBASSEMBLY64-NEXT:#define __ORDER_BIG_ENDIAN__ 4321
// WEBASSEMBLY64-NEXT:#define __ORDER_LITTLE_ENDIAN__ 1234
// WEBASSEMBLY64-NEXT:#define __ORDER_PDP_ENDIAN__ 3412
@@ -9605,3 +9883,107 @@
// AVR:#define __WCHAR_MAX__ 32767
// AVR:#define __WCHAR_TYPE__ int
// AVR:#define __WINT_TYPE__ int
+
+
+// RUN: %clang_cc1 -E -dM -ffreestanding \
+// RUN: -triple i686-windows-msvc -fms-compatibility < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MSVC-X32 %s
+
+// RUN: %clang_cc1 -E -dM -ffreestanding \
+// RUN: -triple x86_64-windows-msvc -fms-compatibility < /dev/null \
+// RUN: | FileCheck -match-full-lines -check-prefix MSVC-X64 %s
+
+// MSVC-X32:#define __CLANG_ATOMIC_BOOL_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_CHAR16_T_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_CHAR32_T_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_CHAR_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_INT_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_LLONG_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_LONG_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_POINTER_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_SHORT_LOCK_FREE 2
+// MSVC-X32-NEXT:#define __CLANG_ATOMIC_WCHAR_T_LOCK_FREE 2
+// MSVC-X32-NOT:#define __GCC_ATOMIC{{.*}}
+
+// MSVC-X64:#define __CLANG_ATOMIC_BOOL_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_CHAR16_T_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_CHAR32_T_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_CHAR_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_INT_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_LLONG_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_LONG_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_POINTER_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_SHORT_LOCK_FREE 2
+// MSVC-X64-NEXT:#define __CLANG_ATOMIC_WCHAR_T_LOCK_FREE 2
+// MSVC-X86-NOT:#define __GCC_ATOMIC{{.*}}
+
+// RUN: %clang_cc1 -E -dM -ffreestanding \
+// RUN: -triple=aarch64-apple-ios9 < /dev/null \
+// RUN: | FileCheck -check-prefix=DARWIN %s
+// RUN: %clang_cc1 -E -dM -ffreestanding \
+// RUN: -triple=aarch64-apple-macosx10.12 < /dev/null \
+// RUN: | FileCheck -check-prefix=DARWIN %s
+
+// DARWIN:#define __STDC_NO_THREADS__ 1
+
+// RUN: %clang_cc1 -triple i386-apple-macosx -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix MACOS-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix MACOS-64 %s
+
+// MACOS-32: #define __INTPTR_TYPE__ long int
+// MACOS-32: #define __PTRDIFF_TYPE__ int
+// MACOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// MACOS-64: #define __INTPTR_TYPE__ long int
+// MACOS-64: #define __PTRDIFF_TYPE__ long int
+// MACOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple i386-apple-ios-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-32 %s
+// RUN: %clang_cc1 -triple armv7-apple-ios -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-ios-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-64 %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-64 %s
+
+// IOS-32: #define __INTPTR_TYPE__ long int
+// IOS-32: #define __PTRDIFF_TYPE__ int
+// IOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// IOS-64: #define __INTPTR_TYPE__ long int
+// IOS-64: #define __PTRDIFF_TYPE__ long int
+// IOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple i386-apple-tvos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-32 %s
+// RUN: %clang_cc1 -triple armv7-apple-tvos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-tvos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-64 %s
+// RUN: %clang_cc1 -triple arm64-apple-tvos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-64 %s
+
+// TVOS-32: #define __INTPTR_TYPE__ long int
+// TVOS-32: #define __PTRDIFF_TYPE__ int
+// TVOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// TVOS-64: #define __INTPTR_TYPE__ long int
+// TVOS-64: #define __PTRDIFF_TYPE__ long int
+// TVOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple i386-apple-watchos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-32 %s
+// RUN: %clang_cc1 -triple armv7k-apple-watchos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-watchos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-64 %s
+// RUN: %clang_cc1 -triple arm64-apple-watchos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-64 %s
+
+// WATCHOS-32: #define __INTPTR_TYPE__ long int
+// WATCHOS-32: #define __PTRDIFF_TYPE__ int
+// WATCHOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// WATCHOS-64: #define __INTPTR_TYPE__ long int
+// WATCHOS-64: #define __PTRDIFF_TYPE__ long int
+// WATCHOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple armv7-apple-none-macho -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix ARM-DARWIN-BAREMETAL-32 %s
+// RUN: %clang_cc1 -triple arm64-apple-none-macho -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix ARM-DARWIN-BAREMETAL-64 %s
+
+// ARM-DARWIN-BAREMETAL-32: #define __INTPTR_TYPE__ long int
+// ARM-DARWIN-BAREMETAL-32: #define __PTRDIFF_TYPE__ int
+// ARM-DARWIN-BAREMETAL-32: #define __SIZE_TYPE__ long unsigned int
+
+// ARM-DARWIN-BAREMETAL-64: #define __INTPTR_TYPE__ long int
+// ARM-DARWIN-BAREMETAL-64: #define __PTRDIFF_TYPE__ long int
+// ARM-DARWIN-BAREMETAL-64: #define __SIZE_TYPE__ long unsigned int
+
diff --git a/test/Preprocessor/line-directive-output.c b/test/Preprocessor/line-directive-output.c
index 5c0aef8b32..caeb88dd85 100644
--- a/test/Preprocessor/line-directive-output.c
+++ b/test/Preprocessor/line-directive-output.c
@@ -76,3 +76,10 @@ extern int z;
// CHECK: # 50 "a\n.c"
# 50 "a\012.c"
+
+# 1 "system.h" 3
+# 2
+void sys_foo(void);
+// CHECK: # 1 "system.h" 3
+// CHECK-NEXT: # 2 "system.h" 3
+// CHECK-NEXT: void sys_foo(void);
diff --git a/test/Preprocessor/macro_paste_commaext.c b/test/Preprocessor/macro_paste_commaext.c
index fdb8f982a9..60418effe7 100644
--- a/test/Preprocessor/macro_paste_commaext.c
+++ b/test/Preprocessor/macro_paste_commaext.c
@@ -1,13 +1,20 @@
-// RUN: %clang_cc1 %s -E | grep 'V);'
-// RUN: %clang_cc1 %s -E | grep 'W, 1, 2);'
-// RUN: %clang_cc1 %s -E | grep 'X, 1, 2);'
-// RUN: %clang_cc1 %s -E | grep 'Y,);'
-// RUN: %clang_cc1 %s -E | grep 'Z,);'
+// RUN: %clang_cc1 %s -E | FileCheck --strict-whitespace --match-full-lines %s
+
+// In the following tests, note that the output is sensitive to the
+// whitespace *preceeding* the varargs argument, as well as to
+// interior whitespace. AFAIK, this is the only case where whitespace
+// preceeding an argument matters, and might be considered a bug in
+// GCC. Nevertheless, since this feature is a GCC extension in the
+// first place, we'll follow along.
#define debug(format, ...) format, ## __VA_ARGS__)
+// CHECK:V);
debug(V);
-debug(W, 1, 2);
+// CHECK:W,1, 2);
+debug(W,1, 2);
+// CHECK:X, 1, 2);
debug(X, 1, 2 );
+// CHECK:Y,);
debug(Y, );
+// CHECK:Z,);
debug(Z,);
-
diff --git a/test/Preprocessor/macro_vaopt_check.cpp b/test/Preprocessor/macro_vaopt_check.cpp
new file mode 100644
index 0000000000..fb52e9946a
--- /dev/null
+++ b/test/Preprocessor/macro_vaopt_check.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 %s -Eonly -verify -Wno-all -pedantic -std=c++2a
+
+//expected-error@+1{{missing '('}}
+#define V1(...) __VA_OPT__
+#undef V1
+// OK
+#define V1(...) __VA_OPT__ ()
+#undef V1
+
+//expected-warning@+1{{can only appear in the expansion of a variadic macro}}
+#define V2() __VA_OPT__(x)
+#undef V2
+
+//expected-error@+2{{missing ')' after}}
+//expected-note@+1{{to match this '('}}
+#define V3(...) __VA_OPT__(
+#undef V3
+
+#define V4(...) __VA_OPT__(__VA_ARGS__)
+#undef V4
+
+//expected-error@+1{{nested}}
+#define V5(...) __VA_OPT__(__VA_OPT__())
+#undef V5
+
+//expected-error@+1{{not followed by}}
+#define V1(...) __VA_OPT__ (#)
+#undef V1
+
+//expected-error@+1{{cannot appear at start}}
+#define V1(...) __VA_OPT__ (##)
+#undef V1
+
+//expected-error@+1{{cannot appear at start}}
+#define V1(...) __VA_OPT__ (## X) x
+#undef V1
+
+//expected-error@+1{{cannot appear at end}}
+#define V1(...) y __VA_OPT__ (X ##)
+#undef V1
+
+
+#define FOO(x,...) # __VA_OPT__(x) #x #__VA_OPT__(__VA_ARGS__) //OK
+
+//expected-error@+1{{not followed by a macro parameter}}
+#define V1(...) __VA_OPT__(#)
+#undef V1
+
+//expected-error@+1{{cannot appear at start}}
+#define V1(...) a __VA_OPT__(##) b
+#undef V1
+
+//expected-error@+1{{cannot appear at start}}
+#define V1(...) a __VA_OPT__(a ## b) b __VA_OPT__(##)
+#undef V1
+
+#define V1(x,...) # __VA_OPT__(b x) // OK
+#undef V1
+
+//expected-error@+2{{missing ')' after}}
+//expected-note@+1{{to match this '('}}
+#define V1(...) __VA_OPT__ ((())
+#undef V1
+
diff --git a/test/Preprocessor/macro_vaopt_expand.cpp b/test/Preprocessor/macro_vaopt_expand.cpp
new file mode 100644
index 0000000000..52f18afb4e
--- /dev/null
+++ b/test/Preprocessor/macro_vaopt_expand.cpp
@@ -0,0 +1,148 @@
+// RUN: %clang_cc1 -E %s -pedantic -std=c++2a | FileCheck -strict-whitespace %s
+
+#define LPAREN (
+#define RPAREN )
+
+#define A0 expandedA0
+#define A1 expandedA1 A0
+#define A2 expandedA2 A1
+#define A3 expandedA3 A2
+
+#define A() B LPAREN )
+#define B() C LPAREN )
+#define C() D LPAREN )
+
+
+#define F(x, y) x + y
+#define ELLIP_FUNC(...) __VA_OPT__(__VA_ARGS__)
+
+1: ELLIP_FUNC(F, LPAREN, 'a', 'b', RPAREN);
+2: ELLIP_FUNC(F LPAREN 'a', 'b' RPAREN);
+#undef F
+#undef ELLIP_FUNC
+
+// CHECK: 1: F, (, 'a', 'b', );
+// CHECK: 2: 'a' + 'b';
+
+#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
+3: F(a, b, c) // replaced by f(0, a, b, c)
+4: F() // replaced by f(0)
+
+// CHECK: 3: f(0 , a, b, c)
+// CHECK: 4: f(0 )
+#undef F
+
+#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)
+
+5: G(a, b, c) // replaced by f(0, a , b, c)
+6: G(a) // replaced by f(0, a)
+7: G(a,) // replaced by f(0, a)
+7.1: G(a,,)
+
+
+// CHECK: 5: f(0, a , b, c)
+// CHECK: 6: f(0, a )
+// CHECK: 7: f(0, a )
+// CHECK: 7.1: f(0, a , ,)
+#undef G
+
+#define HT_B() TONG
+
+#define F(x, ...) HT_ ## __VA_OPT__(x x A() #x)
+
+8: F(1)
+9: F(A(),1)
+
+// CHECK: 8: HT_
+// CHECK: 9: TONG C ( ) B ( ) "A()"
+#undef HT_B
+#undef F
+
+#define F(a,...) #__VA_OPT__(A1 a)
+
+10: F(A())
+11: F(A1 A(), 1)
+// CHECK: 10: ""
+// CHECK: 11: "A1 expandedA1 expandedA0 B ( )"
+#undef F
+
+
+#define F(a,...) a ## __VA_OPT__(A1 a) ## __VA_ARGS__ ## a
+12.0: F()
+12: F(,)
+13: F(B,)
+// CHECK: 12.0:
+// CHECK: 12:
+// CHECK: 13: BB
+#undef F
+
+#define F(...) #__VA_OPT__() X ## __VA_OPT__() #__VA_OPT__( )
+
+14: F()
+15: F(1)
+
+// CHECK: 14: "" X ""
+// CHECK: 15: "" X ""
+
+#undef F
+
+#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
+
+16: SDEF(foo); // replaced by S foo;
+17: SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 };
+
+// CHECK: 16: S foo ;
+// CHECK: 17: S bar = { 1, 2 };
+#undef SDEF
+
+#define F(a,...) A() #__VA_OPT__(A3 __VA_ARGS__ a ## __VA_ARGS__ ## a ## C A3) A()
+
+18: F()
+19: F(,)
+20: F(,A3)
+21: F(A3, A(),A0)
+
+
+// CHECK: 18: B ( ) "" B ( )
+// CHECK: 19: B ( ) "" B ( )
+// CHECK: 20: B ( ) "A3 expandedA3 expandedA2 expandedA1 expandedA0 A3C A3" B ( )
+// CHECK: 21: B ( ) "A3 B ( ),expandedA0 A3A(),A0A3C A3" B ( )
+
+#undef F
+
+#define F(a,...) A() #__VA_OPT__(A3 __VA_ARGS__ a ## __VA_ARGS__ ## a ## C A3) a __VA_OPT__(A0 __VA_ARGS__ a ## __VA_ARGS__ ## a ## C A0) A()
+
+22: F()
+23: F(,)
+24: F(,A0)
+25: F(A0, A(),A0)
+
+
+// CHECK: 22: B ( ) "" B ( )
+// CHECK: 23: B ( ) "" B ( )
+// CHECK: 24: B ( ) "A3 expandedA0 A0C A3" expandedA0 expandedA0 A0C expandedA0 B ( )
+// CHECK: 25: B ( ) "A3 B ( ),expandedA0 A0A(),A0A0C A3" expandedA0 expandedA0 C ( ),expandedA0 A0A(),A0A0C expandedA0 B ( )
+
+#undef F
+
+#define F(a,...) __VA_OPT__(B a ## a) ## 1
+#define G(a,...) __VA_OPT__(B a) ## 1
+26: F(,1)
+26_1: G(,1)
+// CHECK: 26: B1
+// CHECK: 26_1: B1
+#undef F
+#undef G
+
+#define F(a,...) B ## __VA_OPT__(a 1) ## 1
+#define G(a,...) B ## __VA_OPT__(a ## a 1) ## 1
+
+27: F(,1)
+27_1: F(A0,1)
+28: G(,1)
+// CHECK: 27: B11
+// CHECK: 27_1: BexpandedA0 11
+// CHECK: 28: B11
+
+#undef F
+#undef G
diff --git a/test/Preprocessor/nonportable-include-with-hmap.c b/test/Preprocessor/nonportable-include-with-hmap.c
new file mode 100644
index 0000000000..fc958e7e5e
--- /dev/null
+++ b/test/Preprocessor/nonportable-include-with-hmap.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -Eonly \
+// RUN: -I%S/Inputs/nonportable-hmaps/foo.hmap \
+// RUN: -I%S/Inputs/nonportable-hmaps \
+// RUN: %s -verify
+//
+// foo.hmap contains: Foo/Foo.h -> headers/foo/Foo.h
+//
+// Header search of "Foo/Foo.h" follows this path:
+// 1. Look for "Foo/Foo.h".
+// 2. Find "Foo/Foo.h" in "nonportable-hmaps/foo.hmap".
+// 3. Look for "headers/foo/Foo.h".
+// 4. Find "headers/foo/Foo.h" in "nonportable-hmaps".
+// 5. Return.
+//
+// There is nothing nonportable; -Wnonportable-include-path should not fire.
+#include "Foo/Foo.h" // expected-no-diagnostics
diff --git a/test/Preprocessor/pp-modules.c b/test/Preprocessor/pp-modules.c
index 09f3eee193..8c283c6271 100644
--- a/test/Preprocessor/pp-modules.c
+++ b/test/Preprocessor/pp-modules.c
@@ -3,13 +3,13 @@
// CHECK: int bar();
int bar();
-// CHECK: @import Module; /* clang -E: implicit import for "{{.*Headers[/\\]Module.h}}" */
+// CHECK: #pragma clang module import Module /* clang -E: implicit import for #include <Module/Module.h> */{{$}}
#include <Module/Module.h>
// CHECK: int foo();
int foo();
-// CHECK: @import Module; /* clang -E: implicit import for "{{.*Headers[/\\]Module.h}}" */
+// CHECK: #pragma clang module import Module /* clang -E: implicit import for #include <Module/Module.h> */{{$}}
#include <Module/Module.h>
#include "pp-modules.h" // CHECK: # 1 "{{.*}}pp-modules.h" 1
-// CHECK: @import Module; /* clang -E: implicit import for "{{.*}}Module.h" */{{$}}
+// CHECK: #pragma clang module import Module /* clang -E: implicit import for #include <Module/Module.h> */{{$}}
// CHECK: # 14 "{{.*}}pp-modules.c" 2
diff --git a/test/Preprocessor/pr19649-unsigned-wchar_t.c b/test/Preprocessor/pr19649-unsigned-wchar_t.c
index 4bbe1b57ce..0f0886b2e9 100644
--- a/test/Preprocessor/pr19649-unsigned-wchar_t.c
+++ b/test/Preprocessor/pr19649-unsigned-wchar_t.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple i386-pc-cygwin -E -x c %s
-// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -E -fshort-wchar -x c %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -E -fwchar-type=short -fno-signed-wchar -x c %s
#if (L'\0' - 1 < 0)
# error "Unexpected expression evaluation result"
diff --git a/test/Preprocessor/pragma_assume_nonnull.c b/test/Preprocessor/pragma_assume_nonnull.c
new file mode 100644
index 0000000000..4aa124113e
--- /dev/null
+++ b/test/Preprocessor/pragma_assume_nonnull.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -E %s | FileCheck %s
+
+// CHECK: #pragma clang assume_nonnull begin
+#pragma clang assume_nonnull begin
+
+int bar(int * ip) { return *ip; }
+
+// CHECK: #pragma clang assume_nonnull end
+#pragma clang assume_nonnull end
+
+int foo(int * _Nonnull ip) { return *ip; }
+
+int main() {
+ return bar(0) + foo(0); // expected-warning 2 {{null passed to a callee that requires a non-null argument}}
+}
diff --git a/test/Preprocessor/pragma_diagnostic.c b/test/Preprocessor/pragma_diagnostic.c
index 3970dbbc8e..63d5907c67 100644
--- a/test/Preprocessor/pragma_diagnostic.c
+++ b/test/Preprocessor/pragma_diagnostic.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-undef %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-undef -Wno-unknown-warning-option -DAVOID_UNKNOWN_WARNING %s
// rdar://2362963
#if FOO // ok.
@@ -28,8 +29,10 @@
#pragma GCC diagnostic error "-Wundef" 42 // expected-warning {{unexpected token in pragma diagnostic}}
#pragma GCC diagnostic error "invalid-name" // expected-warning {{pragma diagnostic expected option name (e.g. "-Wundef")}}
-#pragma GCC diagnostic error "-Winvalid-name" // expected-warning {{unknown warning group '-Winvalid-name', ignored}}
-
+#pragma GCC diagnostic error "-Winvalid-name"
+#ifndef AVOID_UNKNOWN_WARNING
+// expected-warning@-2 {{unknown warning group '-Winvalid-name', ignored}}
+#endif
// Testing pragma clang diagnostic with -Weverything
void ppo(){} // First test that we do not diagnose on this.
diff --git a/test/Preprocessor/pragma_module.c b/test/Preprocessor/pragma_module.c
new file mode 100644
index 0000000000..90aa9481fb
--- /dev/null
+++ b/test/Preprocessor/pragma_module.c
@@ -0,0 +1,52 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'module foo { module a {} module b {} } module bar {} module if {}' > %t/module.map
+// RUN: %clang -cc1 -fmodules -fmodule-name=if -x c %t/module.map -emit-module -o %t/if.pcm
+// RUN: %clang -cc1 -E -fmodules %s -fmodule-file=%t/if.pcm -verify -fmodule-name=foo -fmodule-map-file=%t/module.map
+// RUN: %clang -cc1 -E -fmodules %s -fmodule-file=%t/if.pcm -verify -fmodule-name=foo -fmodule-map-file=%t/module.map -fmodules-local-submodule-visibility -DLOCAL_VIS
+
+// Just checking the syntax here; the semantics are tested elsewhere.
+#pragma clang module import // expected-error {{expected module name}}
+#pragma clang module import ! // expected-error {{expected module name}}
+#pragma clang module import if // ok
+#pragma clang module import foo ? bar // expected-warning {{extra tokens at end of #pragma}}
+#pragma clang module import foo. // expected-error {{expected identifier after '.' in module name}}
+#pragma clang module import foo.bar.baz.quux // expected-error {{no submodule named 'bar' in module 'foo'}}
+
+#pragma clang module begin ! // expected-error {{expected module name}}
+
+#pragma clang module begin foo.a blah // expected-warning {{extra tokens}}
+ #pragma clang module begin foo.a // nesting is OK
+ #define X 1 // expected-note 0-1{{previous}}
+ #ifndef X
+ #error X should be defined here
+ #endif
+ #pragma clang module end
+
+ #ifndef X
+ #error X should still be defined
+ #endif
+#pragma clang module end foo.a // expected-warning {{extra tokens}}
+
+// #pragma clang module begin/end also import the module into the enclosing context
+#ifndef X
+#error X should still be defined
+#endif
+
+#pragma clang module begin foo.b
+ #if defined(X) && defined(LOCAL_VIS)
+ #error under -fmodules-local-submodule-visibility, X should not be defined
+ #endif
+
+ #if !defined(X) && !defined(LOCAL_VIS)
+ #error without -fmodules-local-submodule-visibility, X should still be defined
+ #endif
+
+ #pragma clang module import foo.a
+ #ifndef X
+ #error X should be defined here
+ #endif
+#pragma clang module end
+
+#pragma clang module end // expected-error {{no matching '#pragma clang module begin'}}
+#pragma clang module begin foo.a // expected-error {{no matching '#pragma clang module end'}}
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 73d0be6caa..d7c10cec58 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -156,6 +156,8 @@
// CHECK_I686_M32: #define __i686__ 1
// CHECK_I686_M32: #define __pentiumpro 1
// CHECK_I686_M32: #define __pentiumpro__ 1
+// CHECK_I686_M32: #define __tune_i686__ 1
+// CHECK_I686_M32: #define __tune_pentiumpro__ 1
// CHECK_I686_M32: #define i386 1
// RUN: not %clang -march=i686 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -525,7 +527,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 +556,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 +591,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 +622,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
@@ -787,6 +785,77 @@
// CHECK_KNL_M64: #define __tune_knl__ 1
// CHECK_KNL_M64: #define __x86_64 1
// CHECK_KNL_M64: #define __x86_64__ 1
+
+// RUN: %clang -march=knm -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_KNM_M32
+// CHECK_KNM_M32: #define __AES__ 1
+// CHECK_KNM_M32: #define __AVX2__ 1
+// CHECK_KNM_M32: #define __AVX512CD__ 1
+// CHECK_KNM_M32: #define __AVX512ER__ 1
+// CHECK_KNM_M32: #define __AVX512F__ 1
+// CHECK_KNM_M32: #define __AVX512PF__ 1
+// CHECK_KNM_M32: #define __AVX512VPOPCNTDQ__ 1
+// CHECK_KNM_M32: #define __AVX__ 1
+// CHECK_KNM_M32: #define __BMI2__ 1
+// CHECK_KNM_M32: #define __BMI__ 1
+// CHECK_KNM_M32: #define __F16C__ 1
+// CHECK_KNM_M32: #define __FMA__ 1
+// CHECK_KNM_M32: #define __LZCNT__ 1
+// CHECK_KNM_M32: #define __MMX__ 1
+// CHECK_KNM_M32: #define __PCLMUL__ 1
+// CHECK_KNM_M32: #define __POPCNT__ 1
+// CHECK_KNM_M32: #define __PREFETCHWT1__ 1
+// CHECK_KNM_M32: #define __RDRND__ 1
+// CHECK_KNM_M32: #define __RTM__ 1
+// CHECK_KNM_M32: #define __SSE2__ 1
+// CHECK_KNM_M32: #define __SSE3__ 1
+// CHECK_KNM_M32: #define __SSE4_1__ 1
+// CHECK_KNM_M32: #define __SSE4_2__ 1
+// CHECK_KNM_M32: #define __SSE__ 1
+// CHECK_KNM_M32: #define __SSSE3__ 1
+// CHECK_KNM_M32: #define __XSAVEOPT__ 1
+// CHECK_KNM_M32: #define __XSAVE__ 1
+// CHECK_KNM_M32: #define __i386 1
+// CHECK_KNM_M32: #define __i386__ 1
+// CHECK_KNM_M32: #define i386 1
+
+// RUN: %clang -march=knm -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_KNM_M64
+// CHECK_KNM_M64: #define __AES__ 1
+// CHECK_KNM_M64: #define __AVX2__ 1
+// CHECK_KNM_M64: #define __AVX512CD__ 1
+// CHECK_KNM_M64: #define __AVX512ER__ 1
+// CHECK_KNM_M64: #define __AVX512F__ 1
+// CHECK_KNM_M64: #define __AVX512PF__ 1
+// CHECK_KNM_M64: #define __AVX512VPOPCNTDQ__ 1
+// CHECK_KNM_M64: #define __AVX__ 1
+// CHECK_KNM_M64: #define __BMI2__ 1
+// CHECK_KNM_M64: #define __BMI__ 1
+// CHECK_KNM_M64: #define __F16C__ 1
+// CHECK_KNM_M64: #define __FMA__ 1
+// CHECK_KNM_M64: #define __LZCNT__ 1
+// CHECK_KNM_M64: #define __MMX__ 1
+// CHECK_KNM_M64: #define __PCLMUL__ 1
+// CHECK_KNM_M64: #define __POPCNT__ 1
+// CHECK_KNM_M64: #define __PREFETCHWT1__ 1
+// CHECK_KNM_M64: #define __RDRND__ 1
+// CHECK_KNM_M64: #define __RTM__ 1
+// CHECK_KNM_M64: #define __SSE2_MATH__ 1
+// CHECK_KNM_M64: #define __SSE2__ 1
+// CHECK_KNM_M64: #define __SSE3__ 1
+// CHECK_KNM_M64: #define __SSE4_1__ 1
+// CHECK_KNM_M64: #define __SSE4_2__ 1
+// CHECK_KNM_M64: #define __SSE_MATH__ 1
+// CHECK_KNM_M64: #define __SSE__ 1
+// CHECK_KNM_M64: #define __SSSE3__ 1
+// CHECK_KNM_M64: #define __XSAVEOPT__ 1
+// CHECK_KNM_M64: #define __XSAVE__ 1
+// CHECK_KNM_M64: #define __amd64 1
+// CHECK_KNM_M64: #define __amd64__ 1
+// CHECK_KNM_M64: #define __x86_64 1
+// CHECK_KNM_M64: #define __x86_64__ 1
//
// RUN: %clang -march=skylake-avx512 -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -990,6 +1059,67 @@
// CHECK_ATOM_M64: #define __x86_64 1
// CHECK_ATOM_M64: #define __x86_64__ 1
//
+// RUN: %clang -march=goldmont -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_GLM_M32
+// CHECK_GLM_M32: #define __AES__ 1
+// CHECK_GLM_M32: #define __CLFLUSHOPT__ 1
+// CHECK_GLM_M32: #define __FSGSBASE__ 1
+// CHECK_GLM_M32: #define __FXSR__ 1
+// CHECK_GLM_M32: #define __MMX__ 1
+// CHECK_GLM_M32: #define __MPX__ 1
+// CHECK_GLM_M32: #define __PCLMUL__ 1
+// CHECK_GLM_M32: #define __POPCNT__ 1
+// CHECK_GLM_M32: #define __RDRND__ 1
+// CHECK_GLM_M32: #define __RDSEED__ 1
+// CHECK_GLM_M32: #define __SHA__ 1
+// CHECK_GLM_M32: #define __SSE2__ 1
+// CHECK_GLM_M32: #define __SSE3__ 1
+// CHECK_GLM_M32: #define __SSE4_1__ 1
+// CHECK_GLM_M32: #define __SSE4_2__ 1
+// CHECK_GLM_M32: #define __SSE_MATH__ 1
+// CHECK_GLM_M32: #define __SSE__ 1
+// CHECK_GLM_M32: #define __SSSE3__ 1
+// CHECK_GLM_M32: #define __XSAVEC__ 1
+// CHECK_GLM_M32: #define __XSAVEOPT__ 1
+// CHECK_GLM_M32: #define __XSAVES__ 1
+// CHECK_GLM_M32: #define __XSAVE__ 1
+// CHECK_GLM_M32: #define __goldmont 1
+// CHECK_GLM_M32: #define __goldmont__ 1
+// CHECK_GLM_M32: #define __i386 1
+// CHECK_GLM_M32: #define __i386__ 1
+// CHECK_GLM_M32: #define __tune_goldmont__ 1
+// CHECK_GLM_M32: #define i386 1
+//
+// RUN: %clang -march=goldmont -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_GLM_M64
+// CHECK_GLM_M64: #define __AES__ 1
+// CHECK_GLM_M64: #define __CLFLUSHOPT__ 1
+// CHECK_GLM_M64: #define __FSGSBASE__ 1
+// CHECK_GLM_M64: #define __FXSR__ 1
+// CHECK_GLM_M64: #define __MMX__ 1
+// CHECK_GLM_M64: #define __MPX__ 1
+// CHECK_GLM_M64: #define __PCLMUL__ 1
+// CHECK_GLM_M64: #define __POPCNT__ 1
+// CHECK_GLM_M64: #define __RDRND__ 1
+// CHECK_GLM_M64: #define __RDSEED__ 1
+// CHECK_GLM_M64: #define __SSE2__ 1
+// CHECK_GLM_M64: #define __SSE3__ 1
+// CHECK_GLM_M64: #define __SSE4_1__ 1
+// CHECK_GLM_M64: #define __SSE4_2__ 1
+// CHECK_GLM_M64: #define __SSE__ 1
+// CHECK_GLM_M64: #define __SSSE3__ 1
+// CHECK_GLM_M64: #define __XSAVEC__ 1
+// CHECK_GLM_M64: #define __XSAVEOPT__ 1
+// CHECK_GLM_M64: #define __XSAVES__ 1
+// CHECK_GLM_M64: #define __XSAVE__ 1
+// CHECK_GLM_M64: #define __goldmont 1
+// CHECK_GLM_M64: #define __goldmont__ 1
+// CHECK_GLM_M64: #define __tune_goldmont__ 1
+// CHECK_GLM_M64: #define __x86_64 1
+// CHECK_GLM_M64: #define __x86_64__ 1
+//
// RUN: %clang -march=slm -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SLM_M32
@@ -1028,15 +1158,19 @@
//
// RUN: %clang -march=lakemont -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
-// RUN: | FileCheck %s -check-prefix=CHECK_LMT_M32
-// CHECK_LMT_M32: #define __i386 1
-// CHECK_LMT_M32: #define __i386__ 1
-// CHECK_LMT_M32: #define __tune_lakemont__ 1
-// CHECK_LMT_M32: #define i386 1
+// RUN: | FileCheck %s -check-prefix=CHECK_LAKEMONT_M32
+// CHECK_LAKEMONT_M32: #define __i386 1
+// CHECK_LAKEMONT_M32: #define __i386__ 1
+// CHECK_LAKEMONT_M32: #define __i586 1
+// CHECK_LAKEMONT_M32: #define __i586__ 1
+// CHECK_LAKEMONT_M32: #define __pentium 1
+// CHECK_LAKEMONT_M32: #define __pentium__ 1
+// CHECK_LAKEMONT_M32: #define __tune_lakemont__ 1
+// CHECK_LAKEMONT_M32: #define i386 1
// RUN: not %clang -march=lakemont -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
-// RUN: | FileCheck %s -check-prefix=CHECK_LMT_M64
-// CHECK_LMT_M64: error:
+// RUN: | FileCheck %s -check-prefix=CHECK_LAKEMONT_M64
+// CHECK_LAKEMONT_M64: error:
//
// RUN: %clang -march=geode -m32 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
@@ -1605,6 +1739,7 @@
// CHECK_BDVER1_M32: #define __AES__ 1
// CHECK_BDVER1_M32: #define __AVX__ 1
// CHECK_BDVER1_M32: #define __FMA4__ 1
+// CHECK_BDVER1_M32: #define __LWP__ 1
// CHECK_BDVER1_M32: #define __LZCNT__ 1
// CHECK_BDVER1_M32: #define __MMX__ 1
// CHECK_BDVER1_M32: #define __PCLMUL__ 1
@@ -1634,6 +1769,7 @@
// CHECK_BDVER1_M64: #define __AES__ 1
// CHECK_BDVER1_M64: #define __AVX__ 1
// CHECK_BDVER1_M64: #define __FMA4__ 1
+// CHECK_BDVER1_M64: #define __LWP__ 1
// CHECK_BDVER1_M64: #define __LZCNT__ 1
// CHECK_BDVER1_M64: #define __MMX__ 1
// CHECK_BDVER1_M64: #define __PCLMUL__ 1
@@ -1668,6 +1804,7 @@
// CHECK_BDVER2_M32: #define __F16C__ 1
// CHECK_BDVER2_M32: #define __FMA4__ 1
// CHECK_BDVER2_M32: #define __FMA__ 1
+// CHECK_BDVER2_M32: #define __LWP__ 1
// CHECK_BDVER2_M32: #define __LZCNT__ 1
// CHECK_BDVER2_M32: #define __MMX__ 1
// CHECK_BDVER2_M32: #define __PCLMUL__ 1
@@ -1701,6 +1838,7 @@
// CHECK_BDVER2_M64: #define __F16C__ 1
// CHECK_BDVER2_M64: #define __FMA4__ 1
// CHECK_BDVER2_M64: #define __FMA__ 1
+// CHECK_BDVER2_M64: #define __LWP__ 1
// CHECK_BDVER2_M64: #define __LZCNT__ 1
// CHECK_BDVER2_M64: #define __MMX__ 1
// CHECK_BDVER2_M64: #define __PCLMUL__ 1
@@ -1737,6 +1875,7 @@
// CHECK_BDVER3_M32: #define __FMA4__ 1
// CHECK_BDVER3_M32: #define __FMA__ 1
// CHECK_BDVER3_M32: #define __FSGSBASE__ 1
+// CHECK_BDVER3_M32: #define __LWP__ 1
// CHECK_BDVER3_M32: #define __LZCNT__ 1
// CHECK_BDVER3_M32: #define __MMX__ 1
// CHECK_BDVER3_M32: #define __PCLMUL__ 1
@@ -1772,6 +1911,7 @@
// CHECK_BDVER3_M64: #define __FMA4__ 1
// CHECK_BDVER3_M64: #define __FMA__ 1
// CHECK_BDVER3_M64: #define __FSGSBASE__ 1
+// CHECK_BDVER3_M64: #define __LWP__ 1
// CHECK_BDVER3_M64: #define __LZCNT__ 1
// CHECK_BDVER3_M64: #define __MMX__ 1
// CHECK_BDVER3_M64: #define __PCLMUL__ 1
@@ -1811,6 +1951,7 @@
// CHECK_BDVER4_M32: #define __FMA4__ 1
// CHECK_BDVER4_M32: #define __FMA__ 1
// CHECK_BDVER4_M32: #define __FSGSBASE__ 1
+// CHECK_BDVER4_M32: #define __LWP__ 1
// CHECK_BDVER4_M32: #define __LZCNT__ 1
// CHECK_BDVER4_M32: #define __MMX__ 1
// CHECK_BDVER4_M32: #define __PCLMUL__ 1
@@ -1847,6 +1988,7 @@
// CHECK_BDVER4_M64: #define __FMA4__ 1
// CHECK_BDVER4_M64: #define __FMA__ 1
// CHECK_BDVER4_M64: #define __FSGSBASE__ 1
+// CHECK_BDVER4_M64: #define __LWP__ 1
// CHECK_BDVER4_M64: #define __LZCNT__ 1
// CHECK_BDVER4_M64: #define __MMX__ 1
// CHECK_BDVER4_M64: #define __PCLMUL__ 1
@@ -1961,6 +2103,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
@@ -1984,6 +2134,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 \
@@ -2030,21 +2198,61 @@
// RUN: -target sparcel-unknown-linux \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SPARCEL
// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=myriad2 2>&1 \
-// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-1 -check-prefix=CHECK_SPARCEL
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=myriad2.1 2>&1 \
-// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-1 -check-prefix=CHECK_SPARCEL
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-1 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=myriad2.2 2>&1 \
-// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 -check-prefix=CHECK_SPARCEL
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=myriad2.3 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-3 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2100 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-1 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2150 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2155 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2450 2>&1 \
-// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 -check-prefix=CHECK_SPARCEL
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2455 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2x5x 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-2 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2080 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-3 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2085 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-3 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2480 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-3 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2485 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-3 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
+// RUN: %clang -E -dM %s -o - -target sparcel-myriad -mcpu=ma2x8x 2>&1 \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_MYRIAD2-3 \
+// RUN: -check-prefix=CHECK_SPARCEL -check-prefix=CHECK_MYRIAD2
// CHECK_SPARCEL: #define __LITTLE_ENDIAN__ 1
+// CHECK_MYRIAD2: #define __leon__ 1
// CHECK_MYRIAD2-1: #define __myriad2 1
// CHECK_MYRIAD2-1: #define __myriad2__ 1
// CHECK_MYRIAD2-2: #define __myriad2 2
// CHECK_MYRIAD2-2: #define __myriad2__ 2
+// CHECK_MYRIAD2-3: #define __myriad2 3
+// CHECK_MYRIAD2-3: #define __myriad2__ 3
// CHECK_SPARCEL: #define __sparc 1
// CHECK_SPARCEL: #define __sparc__ 1
-// CHECK_MYRIAD2-1: #define __sparc_v8__ 1
+// CHECK_MYRIAD2: #define __sparc_v8__ 1
// CHECK_SPARCEL: #define __sparcv8 1
//
// RUN: %clang -E -dM %s -o - 2>&1 \
@@ -2132,6 +2340,25 @@
// CHECK_SYSTEMZ_ARCH11: #define __s390x__ 1
// CHECK_SYSTEMZ_ARCH11: #define __zarch__ 1
//
+// RUN: %clang -march=arch12 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH12
+// RUN: %clang -march=z14 -E -dM %s -o - 2>&1 \
+// RUN: -target s390x-unknown-linux \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH12
+//
+// CHECK_SYSTEMZ_ARCH12: #define __ARCH__ 12
+// CHECK_SYSTEMZ_ARCH12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
+// CHECK_SYSTEMZ_ARCH12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
+// CHECK_SYSTEMZ_ARCH12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
+// CHECK_SYSTEMZ_ARCH12: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
+// CHECK_SYSTEMZ_ARCH12: #define __HTM__ 1
+// CHECK_SYSTEMZ_ARCH12: #define __LONG_DOUBLE_128__ 1
+// CHECK_SYSTEMZ_ARCH12: #define __VX__ 1
+// CHECK_SYSTEMZ_ARCH12: #define __s390__ 1
+// CHECK_SYSTEMZ_ARCH12: #define __s390x__ 1
+// CHECK_SYSTEMZ_ARCH12: #define __zarch__ 1
+//
// RUN: %clang -mhtm -E -dM %s -o - 2>&1 \
// RUN: -target s390x-unknown-linux \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_HTM
@@ -2151,7 +2378,7 @@
// RUN: -target s390x-unknown-linux \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ZVECTOR
//
-// CHECK_SYSTEMZ_ZVECTOR: #define __VEC__ 10301
+// CHECK_SYSTEMZ_ZVECTOR: #define __VEC__ 10302
// Begin amdgcn tests ----------------
//
@@ -2159,6 +2386,9 @@
// RUN: -target amdgcn-unknown-unknown \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_AMDGCN
// CHECK_AMDGCN: #define __AMDGCN__ 1
+// CHECK_AMDGCN: #define __HAS_FMAF__ 1
+// CHECK_AMDGCN: #define __HAS_FP64__ 1
+// CHECK_AMDGCN: #define __HAS_LDEXPF__ 1
// Begin r600 tests ----------------
//
@@ -2166,3 +2396,10 @@
// RUN: -target r600-unknown-unknown \
// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_R600
// CHECK_R600: #define __R600__ 1
+// CHECK_R600-NOT: #define __HAS_FMAF__ 1
+
+// RUN: %clang -march=amdgcn -mcpu=cypress -E -dM %s -o - 2>&1 \
+// RUN: -target r600-unknown-unknown \
+// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_R600_FP64
+// CHECK_R600_FP64-DAG: #define __R600__ 1
+// CHECK_R600_FP64-DAG: #define __HAS_FMAF__ 1
diff --git a/test/Preprocessor/predefined-macros.c b/test/Preprocessor/predefined-macros.c
index 7385cd2c93..94b0b30b44 100644
--- a/test/Preprocessor/predefined-macros.c
+++ b/test/Preprocessor/predefined-macros.c
@@ -185,3 +185,27 @@
// CHECK-CL20-NOT: #define __FAST_RELAXED_MATH__ 1
// CHECK-FRM: #define __FAST_RELAXED_MATH__ 1
+// RUN: %clang_cc1 %s -E -dM -o - -x cl \
+// RUN: | FileCheck %s --check-prefix=MSCOPE
+// MSCOPE:#define __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES 3
+// MSCOPE:#define __OPENCL_MEMORY_SCOPE_DEVICE 2
+// MSCOPE:#define __OPENCL_MEMORY_SCOPE_SUB_GROUP 4
+// MSCOPE:#define __OPENCL_MEMORY_SCOPE_WORK_GROUP 1
+// MSCOPE:#define __OPENCL_MEMORY_SCOPE_WORK_ITEM 0
+
+// RUN: %clang_cc1 -triple aarch64-windows %s -E -dM -o - \
+// RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-ARM64-WIN
+
+// CHECK-ARM64-WIN: #define _M_ARM64 1
+// CHECK-ARM64-WIN: #define _WIN32 1
+// CHECK-ARM64-WIN: #define _WIN64 1
+
+// RUN: %clang_cc1 -triple aarch64-windows-gnu %s -E -dM -o - \
+// RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-ARM64-MINGW
+
+// CHECK-ARM64-MINGW-NOT: #define _M_ARM64 1
+// CHECK-ARM64-MINGW: #define WIN32 1
+// CHECK-ARM64-MINGW: #define WIN64 1
+// CHECK-ARM64-MINGW: #define _WIN32 1
+// CHECK-ARM64-MINGW: #define _WIN64 1
+// CHECK-ARM64-MINGW: #define __aarch64__ 1
diff --git a/test/Preprocessor/print-assembler.s b/test/Preprocessor/print-assembler.s
new file mode 100644
index 0000000000..c4e2e031f2
--- /dev/null
+++ b/test/Preprocessor/print-assembler.s
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -E -x assembler-with-cpp %s -o - | FileCheck %s --strict-whitespace
+
+.intel_syntax noprefix
+.text
+ .global _main
+_main:
+# asdf
+# asdf
+ mov bogus_name, 20
+ mov rax, 5
+ ret
+
+// CHECK-LABEL: _main:
+// CHECK-NEXT: {{^}} # asdf
+// CHECK-NEXT: {{^}} # asdf
+// CHECK-NEXT: mov bogus_name, 20
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index 28ccfef9f4..3b32346d5e 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -28,8 +28,8 @@
// ARM:typedef int8_t int_fast8_t;
// ARM:typedef uint8_t uint_fast8_t;
//
-// ARM:typedef int32_t intptr_t;
-// ARM:typedef uint32_t uintptr_t;
+// ARM:typedef int intptr_t;
+// ARM:typedef unsigned int uintptr_t;
//
// ARM:typedef long long int intmax_t;
// ARM:typedef long long unsigned int uintmax_t;
@@ -136,8 +136,8 @@
// I386:typedef int8_t int_fast8_t;
// I386:typedef uint8_t uint_fast8_t;
//
-// I386:typedef int32_t intptr_t;
-// I386:typedef uint32_t uintptr_t;
+// I386:typedef int intptr_t;
+// I386:typedef unsigned int uintptr_t;
//
// I386:typedef long long int intmax_t;
// I386:typedef long long unsigned int uintmax_t;
@@ -243,8 +243,8 @@
// MIPS:typedef int8_t int_fast8_t;
// MIPS:typedef uint8_t uint_fast8_t;
//
-// MIPS:typedef int32_t intptr_t;
-// MIPS:typedef uint32_t uintptr_t;
+// MIPS:typedef long int intptr_t;
+// MIPS:typedef long unsigned int uintptr_t;
//
// MIPS:typedef long long int intmax_t;
// MIPS:typedef long long unsigned int uintmax_t;
@@ -289,9 +289,9 @@
// MIPS:INT_FAST64_MAX_ 9223372036854775807LL
// MIPS:UINT_FAST64_MAX_ 18446744073709551615ULL
//
-// MIPS:INTPTR_MIN_ (-2147483647 -1)
-// MIPS:INTPTR_MAX_ 2147483647
-// MIPS:UINTPTR_MAX_ 4294967295U
+// MIPS:INTPTR_MIN_ (-2147483647L -1)
+// MIPS:INTPTR_MAX_ 2147483647L
+// MIPS:UINTPTR_MAX_ 4294967295UL
// MIPS:PTRDIFF_MIN_ (-2147483647 -1)
// MIPS:PTRDIFF_MAX_ 2147483647
// MIPS:SIZE_MAX_ 4294967295U
@@ -350,8 +350,8 @@
// MIPS64:typedef int8_t int_fast8_t;
// MIPS64:typedef uint8_t uint_fast8_t;
//
-// MIPS64:typedef int64_t intptr_t;
-// MIPS64:typedef uint64_t uintptr_t;
+// MIPS64:typedef long int intptr_t;
+// MIPS64:typedef long unsigned int uintptr_t;
//
// MIPS64:typedef long int intmax_t;
// MIPS64:typedef long unsigned int uintmax_t;
@@ -450,8 +450,8 @@
// MSP430:typedef int8_t int_fast8_t;
// MSP430:typedef uint8_t uint_fast8_t;
//
-// MSP430:typedef int16_t intptr_t;
-// MSP430:typedef uint16_t uintptr_t;
+// MSP430:typedef int intptr_t;
+// MSP430:typedef unsigned int uintptr_t;
//
// MSP430:typedef long long int intmax_t;
// MSP430:typedef long long unsigned int uintmax_t;
@@ -557,8 +557,8 @@
// PPC64:typedef int8_t int_fast8_t;
// PPC64:typedef uint8_t uint_fast8_t;
//
-// PPC64:typedef int64_t intptr_t;
-// PPC64:typedef uint64_t uintptr_t;
+// PPC64:typedef long int intptr_t;
+// PPC64:typedef long unsigned int uintptr_t;
//
// PPC64:typedef long int intmax_t;
// PPC64:typedef long unsigned int uintmax_t;
@@ -664,8 +664,8 @@
// PPC64-NETBSD:typedef int8_t int_fast8_t;
// PPC64-NETBSD:typedef uint8_t uint_fast8_t;
//
-// PPC64-NETBSD:typedef int64_t intptr_t;
-// PPC64-NETBSD:typedef uint64_t uintptr_t;
+// PPC64-NETBSD:typedef long int intptr_t;
+// PPC64-NETBSD:typedef long unsigned int uintptr_t;
//
// PPC64-NETBSD:typedef long long int intmax_t;
// PPC64-NETBSD:typedef long long unsigned int uintmax_t;
@@ -710,12 +710,12 @@
// PPC64-NETBSD:INT_FAST64_MAX_ 9223372036854775807LL
// PPC64-NETBSD:UINT_FAST64_MAX_ 18446744073709551615ULL
//
-// PPC64-NETBSD:INTPTR_MIN_ (-9223372036854775807LL -1)
-// PPC64-NETBSD:INTPTR_MAX_ 9223372036854775807LL
-// PPC64-NETBSD:UINTPTR_MAX_ 18446744073709551615ULL
-// PPC64-NETBSD:PTRDIFF_MIN_ (-9223372036854775807LL -1)
-// PPC64-NETBSD:PTRDIFF_MAX_ 9223372036854775807LL
-// PPC64-NETBSD:SIZE_MAX_ 18446744073709551615ULL
+// PPC64-NETBSD:INTPTR_MIN_ (-9223372036854775807L -1)
+// PPC64-NETBSD:INTPTR_MAX_ 9223372036854775807L
+// PPC64-NETBSD:UINTPTR_MAX_ 18446744073709551615UL
+// PPC64-NETBSD:PTRDIFF_MIN_ (-9223372036854775807L -1)
+// PPC64-NETBSD:PTRDIFF_MAX_ 9223372036854775807L
+// PPC64-NETBSD:SIZE_MAX_ 18446744073709551615UL
//
// PPC64-NETBSD:INTMAX_MIN_ (-9223372036854775807LL -1)
// PPC64-NETBSD:INTMAX_MAX_ 9223372036854775807LL
@@ -772,8 +772,8 @@
// PPC:typedef int8_t int_fast8_t;
// PPC:typedef uint8_t uint_fast8_t;
//
-// PPC:typedef int32_t intptr_t;
-// PPC:typedef uint32_t uintptr_t;
+// PPC:typedef long int intptr_t;
+// PPC:typedef long unsigned int uintptr_t;
//
// PPC:typedef long long int intmax_t;
// PPC:typedef long long unsigned int uintmax_t;
@@ -818,12 +818,12 @@
// PPC:INT_FAST64_MAX_ 9223372036854775807LL
// PPC:UINT_FAST64_MAX_ 18446744073709551615ULL
//
-// PPC:INTPTR_MIN_ (-2147483647 -1)
-// PPC:INTPTR_MAX_ 2147483647
-// PPC:UINTPTR_MAX_ 4294967295U
-// PPC:PTRDIFF_MIN_ (-2147483647 -1)
-// PPC:PTRDIFF_MAX_ 2147483647
-// PPC:SIZE_MAX_ 4294967295U
+// PPC:INTPTR_MIN_ (-2147483647L -1)
+// PPC:INTPTR_MAX_ 2147483647L
+// PPC:UINTPTR_MAX_ 4294967295UL
+// PPC:PTRDIFF_MIN_ (-2147483647L -1)
+// PPC:PTRDIFF_MAX_ 2147483647L
+// PPC:SIZE_MAX_ 4294967295UL
//
// PPC:INTMAX_MIN_ (-9223372036854775807LL -1)
// PPC:INTMAX_MAX_ 9223372036854775807LL
@@ -879,8 +879,8 @@
// S390X:typedef int8_t int_fast8_t;
// S390X:typedef uint8_t uint_fast8_t;
//
-// S390X:typedef int64_t intptr_t;
-// S390X:typedef uint64_t uintptr_t;
+// S390X:typedef long int intptr_t;
+// S390X:typedef long unsigned int uintptr_t;
//
// S390X:typedef long int intmax_t;
// S390X:typedef long unsigned int uintmax_t;
@@ -986,8 +986,8 @@
// SPARC:typedef int8_t int_fast8_t;
// SPARC:typedef uint8_t uint_fast8_t;
//
-// SPARC:typedef int32_t intptr_t;
-// SPARC:typedef uint32_t uintptr_t;
+// SPARC:typedef int intptr_t;
+// SPARC:typedef unsigned int uintptr_t;
//
// SPARC:typedef long long int intmax_t;
// SPARC:typedef long long unsigned int uintmax_t;
@@ -1086,8 +1086,8 @@
// TCE:typedef int8_t int_fast8_t;
// TCE:typedef uint8_t uint_fast8_t;
//
-// TCE:typedef int32_t intptr_t;
-// TCE:typedef uint32_t uintptr_t;
+// TCE:typedef int intptr_t;
+// TCE:typedef unsigned int uintptr_t;
//
// TCE:typedef long int intmax_t;
// TCE:typedef long unsigned int uintmax_t;
@@ -1139,9 +1139,9 @@
// TCE:PTRDIFF_MAX_ 2147483647
// TCE:SIZE_MAX_ 4294967295U
//
-// TCE:INTMAX_MIN_ (-2147483647 -1)
-// TCE:INTMAX_MAX_ 2147483647
-// TCE:UINTMAX_MAX_ 4294967295U
+// TCE:INTMAX_MIN_ (-2147483647L -1)
+// TCE:INTMAX_MAX_ 2147483647L
+// TCE:UINTMAX_MAX_ 4294967295UL
//
// TCE:SIG_ATOMIC_MIN_ (-2147483647 -1)
// TCE:SIG_ATOMIC_MAX_ 2147483647
@@ -1194,8 +1194,8 @@
// X86_64:typedef int8_t int_fast8_t;
// X86_64:typedef uint8_t uint_fast8_t;
//
-// X86_64:typedef int64_t intptr_t;
-// X86_64:typedef uint64_t uintptr_t;
+// X86_64:typedef long int intptr_t;
+// X86_64:typedef long unsigned int uintptr_t;
//
// X86_64:typedef long int intmax_t;
// X86_64:typedef long unsigned int uintmax_t;
@@ -1314,8 +1314,8 @@
// XCORE:typedef int8_t int_fast8_t;
// XCORE:typedef uint8_t uint_fast8_t;
//
-// XCORE:typedef int32_t intptr_t;
-// XCORE:typedef uint32_t uintptr_t;
+// XCORE:typedef int intptr_t;
+// XCORE:typedef unsigned int uintptr_t;
//
// XCORE:typedef long long int intmax_t;
// XCORE:typedef long long unsigned int uintmax_t;
@@ -1398,9 +1398,14 @@
// the identifiers used in the operations (int, uint, _t, INT, UINT, _MIN,
// _MAX, and _C(v)) are themselves macros.
//
-// RUN: %clang_cc1 -E -ffreestanding -U__UINTMAX_TYPE__ -U__INTMAX_TYPE__ -Dint=a -Duint=b -D_t=c -DINT=d -DUINT=e -D_MIN=f -D_MAX=g '-D_C(v)=h' -triple=i386-none-none %s | FileCheck -check-prefix JOIN %s
-// JOIN:typedef int32_t intptr_t;
-// JOIN:typedef uint32_t uintptr_t;
+// RUN: %clang_cc1 -E -ffreestanding \
+// RUN: -U__UINTPTR_TYPE__ -U__INTPTR_TYPE__ \
+// RUN: -U__UINTMAX_TYPE__ -U__INTMAX_TYPE__ \
+// RUN: -Dint=a -Duint=b -D_t=c -DINT=d -DUINT=e -D_MIN=f -D_MAX=g \
+// RUN: '-D_C(v)=h' -triple=i386-none-none %s \
+// RUN: | FileCheck -check-prefix JOIN %s
+// JOIN:typedef __INTPTR_TYPE__ intptr_t;
+// JOIN:typedef __UINTPTR_TYPE__ uintptr_t;
// JOIN:typedef __INTMAX_TYPE__ intmax_t;
// JOIN:typedef __UINTMAX_TYPE__ uintmax_t;
// JOIN:INTPTR_MIN_ (-2147483647 -1)
diff --git a/test/Preprocessor/stringize_space.c b/test/Preprocessor/stringize_space.c
index ae70bf1818..cbc7386cd0 100644
--- a/test/Preprocessor/stringize_space.c
+++ b/test/Preprocessor/stringize_space.c
@@ -18,3 +18,14 @@ f(
1)
// CHECK: {{^}}"-1"
+
+#define paste(a,b) str(a<b##ld)
+paste(hello1, wor)
+paste(hello2,
+ wor)
+paste(hello3,
+wor)
+
+// CHECK: {{^}}"hello1<world"
+// CHECK: {{^}}"hello2<world"
+// CHECK: {{^}}"hello3<world"
diff --git a/test/Preprocessor/wchar_t.c b/test/Preprocessor/wchar_t.c
new file mode 100644
index 0000000000..6c47a2bb6a
--- /dev/null
+++ b/test/Preprocessor/wchar_t.c
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -triple i386-pc-solaris -dM -E %s -o - | FileCheck %s -check-prefix CHECK-SOLARIS
+// CHECK-SOLARIS-DAG: #define __WCHAR_MAX__ 2147483647
+// CHECK-SOLARIS-DAG: #define __WCHAR_TYPE__ int
+// CHECK-SOLARIS-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple avr-unknown-unknown -fwchar-type=int -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-AVR
+// CHECK-AVR-DAG: #define __WCHAR_MAX__ 32767
+// CHECK-AVR-DAG: #define __WCHAR_TYPE__ int
+// CHECK-AVR-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple arm-unknown-none-gnu -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-ARM-APCS
+// CHECK-ARM-APCS-DAG: #define __WCHAR_MAX__ 2147483647
+// CHECK-ARM-APCS-DAG: #define __WCHAR_TYPE__ int
+// CHECK-ARM-APCS-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple arm-unknown-netbsd-gnu -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-ARM-NETBSD-AAPCS
+// CHECK-ARM-NETBSD-AAPCS-DAG: #define __WCHAR_MAX__ 2147483647
+// CHECK-ARM-NETBSD-AAPCS-DAG: #define __WCHAR_TYPE__ int
+// CHECK-ARM-NETBSD-AAPCS-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple arm-unknown-openbsd -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-ARM-OPENBSD
+// CHECK-ARM-OPENBSD-DAG: #define __WCHAR_MAX__ 2147483647
+// CHECK-ARM-OPENBSD-DAG: #define __WCHAR_TYPE__ int
+// CHECK-ARM-OPENBSD-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple arm64-apple-ios -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-ARM64-DARWIN
+// CHECK-ARM64-DARWIN-DAG: #define __WCHAR_MAX__ 2147483647
+// CHECK-ARM64-DARWIN-DAG: #define __WCHAR_TYPE__ int
+// CHECK-ARM64-DARWIN-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple aarch64-unknown-netbsd -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-ARM64-NETBSD
+// CHECK-ARM64-NETBSD-DAG: #define __WCHAR_MAX__ 2147483647
+// CHECK-ARM64-NETBSD-DAG: #define __WCHAR_TYPE__ int
+// CHECK-ARM64-NETBSD-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple aarch64-unknown-openbsd -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-ARM64-OPENBSD
+// CHECK-ARM64-OPENBSD-DAG: #define __WCHAR_MAX__ 2147483647
+// CHECK-ARM64-OPENBSD-DAG: #define __WCHAR_TYPE__ int
+// CHECK-ARM64-OPENBSD-NOT: #define __WCHAR_UNSIGNED__ 0
+
+// RUN: %clang_cc1 -triple aarch64-unknown-none -fwchar-type=int -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-ARM64-AAPCS64
+// CHECK-ARM64-AAPCS64-DAG: #define __WCHAR_MAX__ 4294967295U
+// CHECK-ARM64-AAPCS64-DAG: #define __WCHAR_TYPE__ unsigned int
+// CHECK-ARM64-AAPCS64-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple xcore-unknown-unknown -fwchar-type=char -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-XCORE
+// CHECK-XCORE-DAG: #define __WCHAR_MAX__ 255
+// CHECK-XCORE-DAG: #define __WCHAR_TYPE__ unsigned char
+// CHECK-XCORE-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-cygnus -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-CYGWIN-X64
+// CHECK-CYGWIN-X64-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-CYGWIN-X64-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-CYGWIN-X64-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-MSVC-X64
+// CHECK-MSVC-X64-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-MSVC-X64-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-MSVC-X64-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple i686-unknown-windows-cygnus -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-CYGWIN-X86
+// CHECK-CYGWIN-X86-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-CYGWIN-X86-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-CYGWIN-X86-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-MSVC-X86
+// CHECK-MSVC-X86-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-MSVC-X86-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-MSVC-X86-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-PS4
+// CHECK-PS4-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-PS4-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-PS4-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple thumbv7-unknown-windows-cygnus -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-CYGWIN-ARM
+// CHECK-CYGWIN-ARM-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-CYGWIN-ARM-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-CYGWIN-ARM-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-MSVC-ARM
+// CHECK-MSVC-ARM-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-MSVC-ARM-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-MSVC-ARM-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fwchar-type=short -fno-signed-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-MSVC-ARM64
+// CHECK-MSVC-ARM64-DAG: #define __WCHAR_MAX__ 65535
+// CHECK-MSVC-ARM64-DAG: #define __WCHAR_TYPE__ unsigned short
+// CHECK-MSVC-ARM64-DAG: #define __WCHAR_UNSIGNED__ 1
+
+// RUN: %clang_cc1 -triple i386-apple-macosx -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple ppc64-apple-macosx -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple i386-apple-ios -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple x86_64-apple-ios -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple armv7-apple-ios -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple aarch64-apple-ios -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple i386-apple-tvos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple x86_64-apple-tvos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple armv7-apple-tvos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple aarch64-apple-tvos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple i386-apple-watchos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple x86_64-apple-watchos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple armv7-apple-watchos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// RUN: %clang_cc1 -triple aarch64-apple-watchos -dM -E %s -o - | FileCheck %s -check-prefix CHECK-DARWIN
+// CHECK-DARWIN: #define __WCHAR_TYPE__ int
+
+// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -fwchar-type=int -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-WINDOWS-ISO10646
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fwchar-type=int -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-WINDOWS-ISO10646
+// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fwchar-type=int -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-WINDOWS-ISO10646
+// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fwchar-type=int -fsigned-wchar -dM -E %s -o - | FileCheck %s -check-prefix CHECK-WINDOWS-ISO10646
+// CHECK-WINDOWS-ISO10646: #define __WCHAR_TYPE__ int
+
diff --git a/test/Preprocessor/woa-defaults.c b/test/Preprocessor/woa-defaults.c
index 6eab3b96f4..4eef863b23 100644
--- a/test/Preprocessor/woa-defaults.c
+++ b/test/Preprocessor/woa-defaults.c
@@ -10,9 +10,12 @@
// CHECK: #define _M_THUMB _M_ARM
// CHECK: #define _WIN32 1
+
// CHECK: #define __ARM_PCS 1
// CHECK: #define __ARM_PCS_VFP 1
// CHECK: #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// CHECK: #define __INTPTR_TYPE__ int
+// CHECK: #define __PTRDIFF_TYPE__ int
// CHECK: #define __SIZEOF_DOUBLE__ 8
// CHECK: #define __SIZEOF_FLOAT__ 4
// CHECK: #define __SIZEOF_INT__ 4
@@ -25,6 +28,8 @@
// CHECK: #define __SIZEOF_SIZE_T__ 4
// CHECK: #define __SIZEOF_WCHAR_T__ 2
// CHECK: #define __SIZEOF_WINT_T__ 4
+// CHECK: #define __SIZE_TYPE__ unsigned int
+// CHECK: #define __UINTPTR_TYPE__ unsigned int
// CHECK-NOT: __THUMB_INTERWORK__
// CHECK-NOT: __ARM_EABI__
diff --git a/test/Preprocessor/x86_target_features.c b/test/Preprocessor/x86_target_features.c
index a201900ba7..ce3835f91f 100644
--- a/test/Preprocessor/x86_target_features.c
+++ b/test/Preprocessor/x86_target_features.c
@@ -272,6 +272,14 @@
// AESNOSSE2-NOT: #define __SSE2__ 1
// AESNOSSE2-NOT: #define __SSE3__ 1
+// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -mlwp -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=LWP %s
+
+// LWP: #define __LWP__ 1
+
+// RUN: %clang -target i386-unknown-unknown -march=bdver1 -mno-lwp -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=NOLWP %s
+
+// NOLWP-NOT: #define __LWP__ 1
+
// RUN: %clang -target i386-unknown-unknown -march=pentiumpro -msha -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=SHA %s
// SHA: #define __SHA__ 1
diff --git a/test/Profile/Inputs/cxx-missing-bodies.proftext b/test/Profile/Inputs/cxx-missing-bodies.proftext
new file mode 100644
index 0000000000..c07f297f74
--- /dev/null
+++ b/test/Profile/Inputs/cxx-missing-bodies.proftext
@@ -0,0 +1,9 @@
+??_GA@@UAEPAXI@Z
+1
+1
+1
+
+??_DA@@QAEXXZ
+1
+1
+1
diff --git a/test/Profile/c-outdated-data.c b/test/Profile/c-outdated-data.c
index e61ad02d07..b686f94d80 100644
--- a/test/Profile/c-outdated-data.c
+++ b/test/Profile/c-outdated-data.c
@@ -4,23 +4,23 @@
// doesn't play well with warnings that have no line number.
// RUN: llvm-profdata merge %S/Inputs/c-outdated-data.proftext -o %t.profdata
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata -Wprofile-instr-dropped 2>&1 | FileCheck %s
-// CHECK: warning: profile data may be out of date: of 3 functions, 1 has no data and 1 has mismatched data that will be ignored
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=NO_MISSING
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -Wprofile-instr-missing -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=WITH_MISSING
+
+// NO_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored
+// NO_MISSING-NOT: 1 has no data
+
+// WITH_MISSING: warning: profile data may be out of date: of 3 functions, 1 has mismatched data that will be ignored
+// WITH_MISSING: warning: profile data may be incomplete: of 3 functions, 1 has no data
void no_usable_data() {
int i = 0;
if (i) {}
-
-#ifdef GENERATE_OUTDATED_DATA
- if (i) {}
-#endif
}
-#ifndef GENERATE_OUTDATED_DATA
void no_data() {
}
-#endif
int main(int argc, const char *argv[]) {
no_usable_data();
diff --git a/test/Profile/cxx-missing-bodies.cpp b/test/Profile/cxx-missing-bodies.cpp
new file mode 100644
index 0000000000..fe926b3b21
--- /dev/null
+++ b/test/Profile/cxx-missing-bodies.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm %s -std=c++11 -S -emit-llvm -o - -triple=i386-pc-win32 -fno-rtti -fprofile-instrument=clang | FileCheck %s --check-prefix=GEN
+//
+// Don't crash when presented profile data for functions without bodies:
+// RUN: llvm-profdata merge %S/Inputs/cxx-missing-bodies.proftext -o %t.profdata
+// RUN: %clang_cc1 -emit-llvm %s -std=c++11 -S -emit-llvm -o /dev/null -triple=i386-pc-win32 -fno-rtti -fprofile-instrument-use-path=%t.profdata -w
+
+// GEN-NOT: __profn{{.*}}??_GA@@UAEPAXI@Z
+// GEN-NOT: __profn{{.*}}??_DA@@QAEXXZ
+
+struct A {
+ virtual ~A();
+};
+struct B : A {
+ virtual ~B();
+};
+
+B::~B() {}
+
+void foo() {
+ B c;
+}
diff --git a/test/Profile/cxx-structors.cpp b/test/Profile/cxx-structors.cpp
index 8e0fac163d..1af01babf3 100644
--- a/test/Profile/cxx-structors.cpp
+++ b/test/Profile/cxx-structors.cpp
@@ -33,7 +33,7 @@ Baz baz;
Baz baz2(1);
Quux qux("fi", "fo", "fum");
-// Profile data for complete constructors and destructors must absent.
+// Profile data for complete constructors and destructors must be absent.
// INSTR: @__profc__ZN3BazC1Ev =
// INSTR: @__profc__ZN3BazC1Ei =
diff --git a/test/Refactor/Extract/ExtractExprIntoFunction.cpp b/test/Refactor/Extract/ExtractExprIntoFunction.cpp
new file mode 100644
index 0000000000..be610fc303
--- /dev/null
+++ b/test/Refactor/Extract/ExtractExprIntoFunction.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-refactor extract -selection=test:%s %s -- -std=c++11 2>&1 | grep -v CHECK | FileCheck %s
+
+
+void simpleExtractNoCaptures() {
+ int i = /*range=->+0:33*/1 + 2;
+}
+
+// CHECK: 1 '' results:
+// CHECK: static int extracted() {
+// CHECK-NEXT: return 1 + 2;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: void simpleExtractNoCaptures() {
+// CHECK-NEXT: int i = /*range=->+0:33*/extracted();{{$}}
+// CHECK-NEXT: }
+
+void simpleExtractStmtNoCaptures() {
+ /*range astatement=->+1:13*/int a = 1;
+ int b = 2;
+}
+// CHECK: 1 'astatement' results:
+// CHECK: static void extracted() {
+// CHECK-NEXT: int a = 1;
+// CHECK-NEXT: int b = 2;;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: void simpleExtractStmtNoCaptures() {
+// CHECK-NEXT: /*range astatement=->+1:13*/extracted(){{$}}
+// CHECK-NEXT: }
+
+
+void blankRangeNoExtraction() {
+ int i = /*range blank=*/1 + 2;
+}
+
+// CHECK: 1 'blank' results:
+// CHECK-NEXT: the provided selection does not overlap with the AST nodes of interest
+
+int outOfBodyCodeNoExtraction = /*range out_of_body_expr=->+0:72*/1 + 2;
+
+struct OutOfBodyStuff {
+ int FieldInit = /*range out_of_body_expr=->+0:58*/1 + 2;
+
+ void foo(int x =/*range out_of_body_expr=->+0:58*/1 + 2);
+};
+
+// CHECK: 3 'out_of_body_expr' results:
+// CHECK: the selected code is not a part of a function's / method's body
+
+void simpleExpressionNoExtraction() {
+ int i = /*range simple_expr=->+0:41*/1 + /*range simple_expr=->+0:76*/(2);
+ (void) /*range simple_expr=->+0:40*/i;
+ (void)/*range simple_expr=->+0:47*/"literal";
+ (void)/*range simple_expr=->+0:41*/'c';
+}
+
+// CHECK: 5 'simple_expr' results:
+// CHECK-NEXT: the selected expression is too simple to extract
diff --git a/test/Refactor/Extract/FromMethodToFunction.cpp b/test/Refactor/Extract/FromMethodToFunction.cpp
new file mode 100644
index 0000000000..86bec16edf
--- /dev/null
+++ b/test/Refactor/Extract/FromMethodToFunction.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-refactor extract -selection=test:%s %s -- -std=c++11 2>&1 | grep -v CHECK | FileCheck --check-prefixes=CHECK,CHECK-INNER %s
+// RUN: clang-refactor extract -selection=test:%s %s -- -std=c++11 -DMULTIPLE 2>&1 | grep -v CHECK | FileCheck --check-prefixes=CHECK,CHECK-OUTER %s
+
+#ifdef MULTIPLE
+class OuterClass {
+#define PREFIX OuterClass ::
+#else
+#define PREFIX
+#endif
+
+class AClass {
+
+ int method(int x) {
+ return /*range inner=->+0:38*/1 + 2 * 2;
+ }
+// CHECK-INNER: 1 'inner' results:
+// CHECK-INNER: static int extracted() {
+// CHECK-INNER-NEXT: return 1 + 2 * 2;{{$}}
+// CHECK-INNER-NEXT: }{{[[:space:]].*}}
+// CHECK-INNER-NEXT: class AClass {
+
+// CHECK-OUTER: 1 'inner' results:
+// CHECK-OUTER: static int extracted() {
+// CHECK-OUTER-NEXT: return 1 + 2 * 2;{{$}}
+// CHECK-OUTER-NEXT: }{{[[:space:]].*}}
+// CHECK-OUTER-NEXT: class OuterClass {
+
+ int otherMethod(int x);
+};
+
+#ifdef MULTIPLE
+};
+#endif
+
+int PREFIX AClass::otherMethod(int x) {
+ return /*range outofline=->+0:46*/2 * 2 - 1;
+}
+// CHECK: 1 'outofline' results:
+// CHECK: static int extracted() {
+// CHECK-NEXT: return 2 * 2 - 1;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: int PREFIX AClass::otherMethod
diff --git a/test/Refactor/Extract/ObjCProperty.m b/test/Refactor/Extract/ObjCProperty.m
new file mode 100644
index 0000000000..152ccb3484
--- /dev/null
+++ b/test/Refactor/Extract/ObjCProperty.m
@@ -0,0 +1,41 @@
+// RUN: clang-refactor extract -selection=test:%s %s -- 2>&1 | grep -v CHECK | FileCheck %s
+
+@interface HasProperty
+
+@property (strong) HasProperty *item;
+
+- (HasProperty *)implicitProp;
+
+- (void)setImplicitSetter:(HasProperty *)value;
+
+@end
+
+@implementation HasProperty
+
+- (void)allowGetterExtraction {
+ /*range allow_getter=->+0:42*/self.item;
+ /*range allow_imp_getter=->+0:54*/self.implicitProp;
+}
+// CHECK: 1 'allow_getter' results:
+// CHECK: extracted() {
+// CHECK-NEXT: return self.item;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: - (void)allowGetterExtraction {
+// CHECK-NEXT: extracted();
+
+// CHECK: 1 'allow_imp_getter' results:
+// CHECK: extracted() {
+// CHECK-NEXT: return self.implicitProp;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: - (void)allowGetterExtraction {
+// CHECK-NEXT: self.item;
+// CHECK-NEXT: extracted();
+
+- (void)prohibitSetterExtraction {
+ /*range prohibit_setter=->+0:45*/self.item = 0;
+ /*range prohibit_setter=->+0:55*/self.implicitSetter = 0;
+}
+// CHECK: 2 'prohibit_setter' results:
+// CHECK: the selected expression can't be extracted
+
+@end
diff --git a/test/Refactor/LocalRename/Field.cpp b/test/Refactor/LocalRename/Field.cpp
new file mode 100644
index 0000000000..e674401b96
--- /dev/null
+++ b/test/Refactor/LocalRename/Field.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-refactor local-rename -selection=test:%s -new-name=Bar %s -- | grep -v CHECK | FileCheck %s
+
+class Baz {
+ int /*range=*/Foo;
+ // CHECK: int /*range=*/Bar;
+public:
+ Baz();
+};
+
+Baz::Baz() : /*range=*/Foo(0) {}
+// CHECK: Baz::Baz() : /*range=*/Bar(0) {}
diff --git a/test/Refactor/LocalRename/NoSymbolSelectedError.cpp b/test/Refactor/LocalRename/NoSymbolSelectedError.cpp
new file mode 100644
index 0000000000..98de61a45f
--- /dev/null
+++ b/test/Refactor/LocalRename/NoSymbolSelectedError.cpp
@@ -0,0 +1,8 @@
+// RUN: not clang-refactor local-rename -selection=%s:4:1 -new-name=Bar %s -- 2>&1 | grep -v CHECK | FileCheck %s
+// RUN: clang-refactor local-rename -selection=test:%s -new-name=Bar %s -- 2>&1 | grep -v CHECK | FileCheck --check-prefix=TESTCHECK %s
+
+class Baz { // CHECK: [[@LINE]]:1: error: there is no symbol at the given location
+};
+/*range=*/;
+// TESTCHECK: 1 '' results:
+// TESTCHECK-NEXT: there is no symbol at the given location
diff --git a/test/Refactor/tool-apply-replacements.cpp b/test/Refactor/tool-apply-replacements.cpp
new file mode 100644
index 0000000000..59b0991dd2
--- /dev/null
+++ b/test/Refactor/tool-apply-replacements.cpp
@@ -0,0 +1,9 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-refactor local-rename -selection=%t.cpp:7:7 -new-name=test %t.cpp -- | FileCheck %s
+// RUN: clang-refactor local-rename -selection=%t.cpp:7:7-7:15 -new-name=test %t.cpp -- | FileCheck %s
+// RUN: clang-refactor local-rename -i -selection=%t.cpp:7:7 -new-name=test %t.cpp --
+// RUN: FileCheck -input-file=%t.cpp %s
+
+class RenameMe {
+// CHECK: class test {
+};
diff --git a/test/Refactor/tool-common-options.c b/test/Refactor/tool-common-options.c
new file mode 100644
index 0000000000..b41c8c701e
--- /dev/null
+++ b/test/Refactor/tool-common-options.c
@@ -0,0 +1,3 @@
+// RUN: not clang-refactor 2>&1 | FileCheck --check-prefix=MISSING_ACTION %s
+// MISSING_ACTION: error: no refactoring action given
+// MISSING_ACTION-NEXT: note: the following actions are supported:
diff --git a/test/Refactor/tool-selection-option.c b/test/Refactor/tool-selection-option.c
new file mode 100644
index 0000000000..f80457a067
--- /dev/null
+++ b/test/Refactor/tool-selection-option.c
@@ -0,0 +1,15 @@
+// RUN: rm -f %t.cp.c
+// RUN: cp %s %t.cp.c
+// RUN: clang-refactor local-rename -selection=%t.cp.c:6:5 -new-name=test -v %t.cp.c -- | FileCheck --check-prefix=CHECK1 %s
+// RUN: clang-refactor local-rename -selection=%t.cp.c:6:5-6:9 -new-name=test -v %t.cp.c -- | FileCheck --check-prefix=CHECK2 %s
+
+int test;
+
+// CHECK1: invoking action 'local-rename':
+// CHECK1-NEXT: -selection={{.*}}.cp.c:6:5 -> {{.*}}.cp.c:6:5
+
+// CHECK2: invoking action 'local-rename':
+// CHECK2-NEXT: -selection={{.*}}.cp.c:6:5 -> {{.*}}.cp.c:6:9
+
+// RUN: not clang-refactor local-rename -selection=%s:6:5 -new-name=test -v %t.cp.c -- 2>&1 | FileCheck --check-prefix=CHECK-FILE-ERR %s
+// CHECK-FILE-ERR: given file is not in the target TU
diff --git a/test/Refactor/tool-test-support.c b/test/Refactor/tool-test-support.c
new file mode 100644
index 0000000000..0e073f6e1c
--- /dev/null
+++ b/test/Refactor/tool-test-support.c
@@ -0,0 +1,46 @@
+// RUN: clang-refactor local-rename -selection=test:%s -new-name=test -v %s -- | FileCheck %s
+
+/*range=*/int test;
+
+/*range named=*/int test2;
+
+/*range= +1*/int test3;
+
+/* range = +100 */int test4;
+
+/*range named =+0*/int test5;
+
+/*range =->+0:22*/int test6;
+
+// CHECK: Test selection group '':
+// CHECK-NEXT: 105-105
+// CHECK-NEXT: 158-158
+// CHECK-NEXT: 197-197
+// CHECK-NEXT: 248-251
+// CHECK-NEXT: Test selection group 'named':
+// CHECK-NEXT: 132-132
+// CHECK-NEXT: 218-218
+
+// The following invocations are in the default group:
+
+// CHECK: invoking action 'local-rename':
+// CHECK-NEXT: -selection={{.*}}tool-test-support.c:3:11
+
+// CHECK: invoking action 'local-rename':
+// CHECK-NEXT: -selection={{.*}}tool-test-support.c:7:15
+
+// CHECK: invoking action 'local-rename':
+// CHECK-NEXT: -selection={{.*}}tool-test-support.c:9:29
+
+// CHECK: invoking action 'local-rename':
+// CHECK-NEXT: -selection={{.*}}tool-test-support.c:13:19 -> {{.*}}tool-test-support.c:13:22
+
+// The following invocations are in the 'named' group, and they follow
+// the default invocation even if some of their ranges occur prior to the
+// ranges from the default group because the groups are tested one-by-one:
+
+// CHECK: invoking action 'local-rename':
+// CHECK-NEXT: -selection={{.*}}tool-test-support.c:5:17
+
+// CHECK: invoking action 'local-rename':
+// CHECK-NEXT: -selection={{.*}}tool-test-support.c:11:20
diff --git a/test/Sema/128bitfloat.cpp b/test/Sema/128bitfloat.cpp
index 2449cb6b65..4a826b479d 100644
--- a/test/Sema/128bitfloat.cpp
+++ b/test/Sema/128bitfloat.cpp
@@ -1,7 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -std=gnu++11 %s
+// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple powerpc64-linux -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -verify -std=c++11 %s
-#ifdef __FLOAT128__
+#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
__float128 f;
template<typename> struct __is_floating_point_helper {};
template<> struct __is_floating_point_helper<__float128> {};
diff --git a/test/Sema/2010-05-31-palignr.c b/test/Sema/2010-05-31-palignr.c
index 12be29af95..d9bf8f68b7 100644
--- a/test/Sema/2010-05-31-palignr.c
+++ b/test/Sema/2010-05-31-palignr.c
@@ -1,13 +1,12 @@
-// RUN: not %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o /dev/null %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -ffreestanding -verify -fsyntax-only %s
#include <tmmintrin.h>
+#include <stdint.h>
extern int i;
int main ()
{
-#if defined( __SSSE3__ )
-
typedef int16_t vSInt16 __attribute__ ((__vector_size__ (16)));
short dtbl[] = {1,2,3,4,5,6,7,8};
@@ -15,8 +14,7 @@ int main ()
vSInt16 v0;
v0 = *vdtbl;
- v0 = _mm_alignr_epi8(v0, v0, i); // expected-error {{argument to '__builtin_ia32_palignr128' must be a constant integer}}
+ _mm_alignr_epi8(v0, v0, i); // expected-error {{argument to '__builtin_ia32_palignr128' must be a constant integer}}
return 0;
-#endif
}
diff --git a/test/Sema/Inputs/pragma-pack1.h b/test/Sema/Inputs/pragma-pack1.h
new file mode 100644
index 0000000000..abbf8a8609
--- /dev/null
+++ b/test/Sema/Inputs/pragma-pack1.h
@@ -0,0 +1,27 @@
+
+#ifndef NO_RECORD_1
+struct ReceivesPragma { };
+#endif
+
+#ifdef SET_FIRST_HEADER
+#pragma pack (16)
+#ifndef SET_SECOND_HEADER
+// expected-note@-2 2 {{previous '#pragma pack' directive that modifies alignment is here}}
+#else
+// expected-note@-4 1 {{previous '#pragma pack' directive that modifies alignment is here}}
+#endif
+// expected-warning@+3 {{non-default #pragma pack value changes the alignment of struct or union members in the included file}}
+#endif
+
+#include "pragma-pack2.h"
+
+#ifdef SET_SECOND_HEADER
+// expected-warning@-3 {{the current #pragma pack aligment value is modified in the included file}}
+#endif
+
+#ifdef PUSH_POP_FIRST_HEADER
+// This is fine, we don't change the current value.
+#pragma pack (push, 4)
+
+#pragma pack (pop)
+#endif
diff --git a/test/Sema/Inputs/pragma-pack2.h b/test/Sema/Inputs/pragma-pack2.h
new file mode 100644
index 0000000000..a41621544d
--- /dev/null
+++ b/test/Sema/Inputs/pragma-pack2.h
@@ -0,0 +1,8 @@
+
+#ifndef NO_RECORD_2
+struct S { int x; };
+#endif
+
+#ifdef SET_SECOND_HEADER
+#pragma pack (8) // expected-note 2 {{previous '#pragma pack' directive that modifies alignment is here}}
+#endif
diff --git a/test/Sema/address-packed.c b/test/Sema/address-packed.c
index 2799e19c48..b0519bacd7 100644
--- a/test/Sema/address-packed.c
+++ b/test/Sema/address-packed.c
@@ -329,3 +329,12 @@ void g13(void) {
uint32_t *p32;
p32 = &a[0].x; // no-warning
}
+
+struct Invalid0 {
+ void *x;
+ struct fwd f; // expected-error {{incomplete type}} expected-note {{forward declaration}}
+} __attribute__((packed));
+
+void *g14(struct Invalid0 *ivl) {
+ return &(ivl->x);
+}
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index 3fe9315545..018a8521bf 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/alloc-align-attr.c b/test/Sema/alloc-align-attr.c
new file mode 100644
index 0000000000..ae514343af
--- /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(int x, int y) __attribute__((alloc_align)); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto(int x, int y) __attribute__((alloc_align())); // expected-error {{'alloc_align' attribute takes one argument}}
+void *test_no_fn_proto(int x, int y) __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 973aab15d4..1c20450a6d 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 3a6cdbe0e0..60691ab7f8 100644
--- a/test/Sema/arm-interrupt-attr.c
+++ b/test/Sema/arm-interrupt-attr.c
@@ -1,7 +1,8 @@
-// RUN: %clang_cc1 %s -triple arm-apple-darwin -verify -fsyntax-only
-// RUN: %clang_cc1 %s -triple thumb-apple-darwin -verify -fsyntax-only
-// RUN: %clang_cc1 %s -triple armeb-none-eabi -verify -fsyntax-only
-// RUN: %clang_cc1 %s -triple thumbeb-none-eabi -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple arm-apple-darwin -target-feature +vfp2 -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple thumb-apple-darwin -target-feature +vfp3 -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple armeb-none-eabi -target-feature +vfp4 -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple thumbeb-none-eabi -target-feature +neon -verify -fsyntax-only
+// RUN: %clang_cc1 %s -triple thumbeb-none-eabi -target-feature +neon -target-feature +soft-float -DSOFT -verify -fsyntax-only
__attribute__((interrupt(IRQ))) void foo() {} // expected-error {{'interrupt' attribute requires a string}}
__attribute__((interrupt("irq"))) void foo1() {} // expected-warning {{'interrupt' attribute argument not supported: irq}}
@@ -24,6 +25,8 @@ void caller1() {
callee1();
callee2();
}
+
+#ifndef SOFT
__attribute__((interrupt("IRQ"))) void caller2() {
callee1(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers}}
callee2();
@@ -33,3 +36,14 @@ void (*callee3)();
__attribute__((interrupt("IRQ"))) void caller3() {
callee3(); // expected-warning {{call to function without interrupt attribute could clobber interruptee's VFP registers}}
}
+#else
+__attribute__((interrupt("IRQ"))) void caller2() {
+ callee1();
+ callee2();
+}
+
+void (*callee3)();
+__attribute__((interrupt("IRQ"))) void caller3() {
+ callee3();
+}
+#endif
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index e49a1663a8..04b7cb19eb 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -160,6 +160,41 @@ double test15() {
return ret;
}
+void iOutputConstraint(int x){
+ __asm ("nop" : "=ir" (x) : :); // no-error
+ __asm ("nop" : "=ri" (x) : :); // no-error
+ __asm ("nop" : "=ig" (x) : :); // no-error
+ __asm ("nop" : "=im" (x) : :); // no-error
+ __asm ("nop" : "=imr" (x) : :); // no-error
+ __asm ("nop" : "=i" (x) : :); // expected-error{{invalid output constraint '=i' in asm}}
+ __asm ("nop" : "+i" (x) : :); // expected-error{{invalid output constraint '+i' in asm}}
+ __asm ("nop" : "=ii" (x) : :); // expected-error{{invalid output constraint '=ii' in asm}}
+ __asm ("nop" : "=nr" (x) : :); // no-error
+ __asm ("nop" : "=rn" (x) : :); // no-error
+ __asm ("nop" : "=ng" (x) : :); // no-error
+ __asm ("nop" : "=nm" (x) : :); // no-error
+ __asm ("nop" : "=nmr" (x) : :); // no-error
+ __asm ("nop" : "=n" (x) : :); // expected-error{{invalid output constraint '=n' in asm}}
+ __asm ("nop" : "+n" (x) : :); // expected-error{{invalid output constraint '+n' in asm}}
+ __asm ("nop" : "=nn" (x) : :); // expected-error{{invalid output constraint '=nn' in asm}}
+ __asm ("nop" : "=Fr" (x) : :); // no-error
+ __asm ("nop" : "=rF" (x) : :); // no-error
+ __asm ("nop" : "=Fg" (x) : :); // no-error
+ __asm ("nop" : "=Fm" (x) : :); // no-error
+ __asm ("nop" : "=Fmr" (x) : :); // no-error
+ __asm ("nop" : "=F" (x) : :); // expected-error{{invalid output constraint '=F' in asm}}
+ __asm ("nop" : "+F" (x) : :); // expected-error{{invalid output constraint '+F' in asm}}
+ __asm ("nop" : "=FF" (x) : :); // expected-error{{invalid output constraint '=FF' in asm}}
+ __asm ("nop" : "=Er" (x) : :); // no-error
+ __asm ("nop" : "=rE" (x) : :); // no-error
+ __asm ("nop" : "=Eg" (x) : :); // no-error
+ __asm ("nop" : "=Em" (x) : :); // no-error
+ __asm ("nop" : "=Emr" (x) : :); // no-error
+ __asm ("nop" : "=E" (x) : :); // expected-error{{invalid output constraint '=E' in asm}}
+ __asm ("nop" : "+E" (x) : :); // expected-error{{invalid output constraint '+E' in asm}}
+ __asm ("nop" : "=EE" (x) : :); // expected-error{{invalid output constraint '=EE' in asm}}
+}
+
// PR19837
struct foo {
int a;
diff --git a/test/Sema/assign.c b/test/Sema/assign.c
index 1fff778644..5bdfa9a3a5 100644
--- a/test/Sema/assign.c
+++ b/test/Sema/assign.c
@@ -16,3 +16,46 @@ void test3() {
b[4] = 1; // expected-error {{read-only variable is not assignable}}
b2[4] = 1; // expected-error {{read-only variable is not assignable}}
}
+
+typedef struct I {
+ const int a; // expected-note 4{{nested data member 'a' declared const here}} \
+ expected-note 6{{data member 'a' declared const here}}
+} I;
+typedef struct J {
+ struct I i;
+} J;
+typedef struct K {
+ struct J *j;
+} K;
+
+void testI(struct I i1, struct I i2) {
+ i1 = i2; // expected-error {{cannot assign to variable 'i1' with const-qualified data member 'a'}}
+}
+void testJ1(struct J j1, struct J j2) {
+ j1 = j2; // expected-error {{cannot assign to variable 'j1' with nested const-qualified data member 'a'}}
+}
+void testJ2(struct J j, struct I i) {
+ j.i = i; // expected-error {{cannot assign to non-static data member 'i' with const-qualified data member 'a'}}
+}
+void testK1(struct K k, struct J j) {
+ *(k.j) = j; // expected-error {{cannot assign to lvalue with nested const-qualified data member 'a'}}
+}
+void testK2(struct K k, struct I i) {
+ k.j->i = i; // expected-error {{cannot assign to non-static data member 'i' with const-qualified data member 'a'}}
+}
+
+void testI_(I i1, I i2) {
+ i1 = i2; // expected-error {{cannot assign to variable 'i1' with const-qualified data member 'a'}}
+}
+void testJ1_(J j1, J j2) {
+ j1 = j2; // expected-error {{cannot assign to variable 'j1' with nested const-qualified data member 'a'}}
+}
+void testJ2_(J j, I i) {
+ j.i = i; // expected-error {{cannot assign to non-static data member 'i' with const-qualified data member 'a'}}
+}
+void testK1_(K k, J j) {
+ *(k.j) = j; // expected-error {{cannot assign to lvalue with nested const-qualified data member 'a'}}
+}
+void testK2_(K k, I i) {
+ k.j->i = i; // expected-error {{cannot assign to non-static data member 'i' with const-qualified data member 'a'}}
+}
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
index 8ebf3eaed4..eee1cda863 100644
--- a/test/Sema/atomic-ops.c
+++ b/test/Sema/atomic-ops.c
@@ -7,19 +7,29 @@
struct S { char c[3]; };
_Static_assert(__GCC_ATOMIC_BOOL_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_BOOL_LOCK_FREE == __CLANG_ATOMIC_BOOL_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_CHAR_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_CHAR_LOCK_FREE == __CLANG_ATOMIC_CHAR_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_CHAR16_T_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_CHAR16_T_LOCK_FREE == __CLANG_ATOMIC_CHAR16_T_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_CHAR32_T_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_CHAR32_T_LOCK_FREE == __CLANG_ATOMIC_CHAR32_T_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_WCHAR_T_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_WCHAR_T_LOCK_FREE == __CLANG_ATOMIC_WCHAR_T_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_SHORT_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_SHORT_LOCK_FREE == __CLANG_ATOMIC_SHORT_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_INT_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_INT_LOCK_FREE == __CLANG_ATOMIC_INT_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_LONG_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_LONG_LOCK_FREE == __CLANG_ATOMIC_LONG_LOCK_FREE, "");
#ifdef __i386__
_Static_assert(__GCC_ATOMIC_LLONG_LOCK_FREE == 1, "");
#else
_Static_assert(__GCC_ATOMIC_LLONG_LOCK_FREE == 2, "");
#endif
+_Static_assert(__GCC_ATOMIC_LLONG_LOCK_FREE == __CLANG_ATOMIC_LLONG_LOCK_FREE, "");
_Static_assert(__GCC_ATOMIC_POINTER_LOCK_FREE == 2, "");
+_Static_assert(__GCC_ATOMIC_POINTER_LOCK_FREE == __CLANG_ATOMIC_POINTER_LOCK_FREE, "");
_Static_assert(__c11_atomic_is_lock_free(1), "");
_Static_assert(__c11_atomic_is_lock_free(2), "");
diff --git a/test/Sema/attr-availability-app-extensions.c b/test/Sema/attr-availability-app-extensions.c
index 8f9dcbc763..c66c14ed1a 100644
--- a/test/Sema/attr-availability-app-extensions.c
+++ b/test/Sema/attr-availability-app-extensions.c
@@ -21,8 +21,19 @@ __attribute__((availability(ios,unavailable)))
#endif
void f1(int); // expected-note {{'f1' has been explicitly marked unavailable here}}
+#if __has_feature(attribute_availability_app_extension)
+ __attribute__((availability(macOSApplicationExtension,unavailable)))
+#ifndef TVOS
+ __attribute__((availability(iOSApplicationExtension,unavailable)))
+#else
+ __attribute__((availability(tvOSApplicationExtension,unavailable)))
+#endif
+#endif
+void f2(int); // expected-note {{'f2' has been explicitly marked unavailable here}}
+
void test() {
f0(1); // expected-error {{'f0' is unavailable: not available on}}
f1(1); // expected-error {{'f1' is unavailable}}
+ f2(2); // expected-error {{'f2' is unavailable: not available on}}
}
diff --git a/test/Sema/attr-availability-ios.c b/test/Sema/attr-availability-ios.c
index 6462d58bee..3f901bb33c 100644
--- a/test/Sema/attr-availability-ios.c
+++ b/test/Sema/attr-availability-ios.c
@@ -2,13 +2,13 @@
void f0(int) __attribute__((availability(ios,introduced=2.0,deprecated=2.1))); // expected-note {{'f0' has been explicitly marked deprecated here}}
void f1(int) __attribute__((availability(ios,introduced=2.1)));
-void f2(int) __attribute__((availability(ios,introduced=2.0,deprecated=3.0))); // expected-note {{'f2' has been explicitly marked deprecated here}}
+void f2(int) __attribute__((availability(iOS,introduced=2.0,deprecated=3.0))); // expected-note {{'f2' has been explicitly marked deprecated here}}
void f3(int) __attribute__((availability(ios,introduced=3.0)));
void f4(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(ios,introduced=2.0,deprecated=2.1,obsoleted=3.0))); // expected-note{{explicitly marked unavailable}}
void f5(int) __attribute__((availability(ios,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{'f5' has been explicitly marked deprecated here}}
void f6(int) __attribute__((availability(ios,deprecated=3.0)));
-void f6(int) __attribute__((availability(ios,introduced=2.0))); // expected-note {{'f6' has been explicitly marked deprecated here}}
+void f6(int) __attribute__((availability(iOS,introduced=2.0))); // expected-note {{'f6' has been explicitly marked deprecated here}}
void test() {
f0(0); // expected-warning{{'f0' is deprecated: first deprecated in iOS 2.1}}
diff --git a/test/Sema/attr-availability-macosx.c b/test/Sema/attr-availability-macosx.c
index f422811708..d390869850 100644
--- a/test/Sema/attr-availability-macosx.c
+++ b/test/Sema/attr-availability-macosx.c
@@ -10,7 +10,7 @@ void f2(int) __attribute__((availability(macosx,introduced=10.4,deprecated=10.5)
void f3(int) __attribute__((availability(macosx,introduced=10.6)));
void f4(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(ios,introduced=2.0,deprecated=3.0))); // expected-note{{explicitly marked unavailable}}
void f5(int) __attribute__((availability(ios,introduced=3.2), availability(macosx,unavailable))); // expected-note{{'f5' has been explicitly marked unavailable here}}
-void f6(int) __attribute__((availability(macosx,strict,introduced=10.6))); //expected-note{{'f6' has been explicitly marked unavailable here}}
+void f6(int) __attribute__((availability(macOS,strict,introduced=10.6))); //expected-note{{'f6' has been explicitly marked unavailable here}}
void test() {
f0(0);
@@ -47,7 +47,7 @@ enum __attribute__((availability(macosx,introduced=8.0,deprecated=9.0))) {
};
// Make sure the note is on the declaration with the actual availability attributes.
-struct __attribute__((availability(macosx,strict,introduced=10.9))) type_info // \
+struct __attribute__((availability(macOS,strict,introduced=10.9))) type_info // \
expected-note{{'type_info' has been explicitly marked unavailable here}}
{
};
diff --git a/test/Sema/attr-availability-tvos.c b/test/Sema/attr-availability-tvos.c
index 642246425b..d53d6ac8ed 100644
--- a/test/Sema/attr-availability-tvos.c
+++ b/test/Sema/attr-availability-tvos.c
@@ -36,7 +36,7 @@ void f10(int);
// Test tvOS specific attributes.
void f0_tvos(int) __attribute__((availability(tvos,introduced=2.0,deprecated=2.1))); // expected-note {{'f0_tvos' has been explicitly marked deprecated here}}
void f1_tvos(int) __attribute__((availability(tvos,introduced=2.1)));
-void f2_tvos(int) __attribute__((availability(tvos,introduced=2.0,deprecated=3.0))); // expected-note {{'f2_tvos' has been explicitly marked deprecated here}}
+void f2_tvos(int) __attribute__((availability(tvOS,introduced=2.0,deprecated=3.0))); // expected-note {{'f2_tvos' has been explicitly marked deprecated here}}
void f3_tvos(int) __attribute__((availability(tvos,introduced=3.0)));
void f4_tvos(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(tvos,introduced=2.0,deprecated=2.1,obsoleted=3.0))); // expected-note{{explicitly marked unavailable}}
void f5_tvos(int) __attribute__((availability(tvos,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0)));
@@ -44,7 +44,7 @@ void f5_attr_reversed_tvos(int) __attribute__((availability(ios, deprecated=3.0)
void f5b_tvos(int) __attribute__((availability(tvos,introduced=2.0))) __attribute__((availability(tvos,deprecated=3.0))); // expected-note {{'f5b_tvos' has been explicitly marked deprecated here}}
void f5c_tvos(int) __attribute__((availability(ios,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{'f5c_tvos' has been explicitly marked deprecated here}}
void f6_tvos(int) __attribute__((availability(tvos,deprecated=3.0)));
-void f6_tvos(int) __attribute__((availability(tvos,introduced=2.0))); // expected-note {{'f6_tvos' has been explicitly marked deprecated here}}
+void f6_tvos(int) __attribute__((availability(tvOS,introduced=2.0))); // expected-note {{'f6_tvos' has been explicitly marked deprecated here}}
void test_tvos() {
f0_tvos(0); // expected-warning{{'f0_tvos' is deprecated: first deprecated in tvOS 2.1}}
diff --git a/test/Sema/attr-availability-watchos.c b/test/Sema/attr-availability-watchos.c
index cb9f968bd6..ec7f3a7d3a 100644
--- a/test/Sema/attr-availability-watchos.c
+++ b/test/Sema/attr-availability-watchos.c
@@ -25,7 +25,7 @@ void test() {
// Test watchOS specific attributes.
void f0_watchos(int) __attribute__((availability(watchos,introduced=2.0,deprecated=2.1))); // expected-note {{'f0_watchos' has been explicitly marked deprecated here}}
void f1_watchos(int) __attribute__((availability(watchos,introduced=2.1)));
-void f2_watchos(int) __attribute__((availability(watchos,introduced=2.0,deprecated=3.0))); // expected-note {{'f2_watchos' has been explicitly marked deprecated here}}
+void f2_watchos(int) __attribute__((availability(watchOS,introduced=2.0,deprecated=3.0))); // expected-note {{'f2_watchos' has been explicitly marked deprecated here}}
void f3_watchos(int) __attribute__((availability(watchos,introduced=3.0)));
void f4_watchos(int) __attribute__((availability(macosx,introduced=10.1,deprecated=10.3,obsoleted=10.5), availability(watchos,introduced=2.0,deprecated=2.1,obsoleted=3.0))); // expected-note{{explicitly marked unavailable}}
void f5_watchos(int) __attribute__((availability(watchos,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0)));
@@ -33,7 +33,7 @@ void f5_attr_reversed_watchos(int) __attribute__((availability(ios, deprecated=3
void f5b_watchos(int) __attribute__((availability(watchos,introduced=2.0))) __attribute__((availability(watchos,deprecated=3.0))); // expected-note {{'f5b_watchos' has been explicitly marked deprecated here}}
void f5c_watchos(int) __attribute__((availability(ios,introduced=2.0))) __attribute__((availability(ios,deprecated=3.0))); // expected-note {{'f5c_watchos' has been explicitly marked deprecated here}}
void f6_watchos(int) __attribute__((availability(watchos,deprecated=3.0)));
-void f6_watchos(int) __attribute__((availability(watchos,introduced=2.0))); // expected-note {{'f6_watchos' has been explicitly marked deprecated here}}
+void f6_watchos(int) __attribute__((availability(watchOS,introduced=2.0))); // expected-note {{'f6_watchos' has been explicitly marked deprecated here}}
void test_watchos() {
f0_watchos(0); // expected-warning{{'f0_watchos' is deprecated: first deprecated in watchOS 2.1}}
diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c
index a4b40ff9e0..1b8cbd256c 100644
--- a/test/Sema/attr-availability.c
+++ b/test/Sema/attr-availability.c
@@ -21,6 +21,9 @@ ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduce
extern void
PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8)));
+#ifdef WARN_PARTIAL
+// expected-note@+2 2 {{marked partial here}}
+#endif
enum __attribute__((availability(macosx,introduced=10.8))) PartialEnum {
kPartialEnumConstant,
};
@@ -30,16 +33,24 @@ void test_10095131() {
ATSFontGetPostScriptName(100); // expected-error {{'ATSFontGetPostScriptName' is unavailable: obsoleted in macOS 9.0 - use ATSFontGetFullPostScriptName}}
#if defined(WARN_PARTIAL)
- // expected-warning@+2 {{is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'PartiallyAvailable' in an @available check to silence this warning}}
+ // expected-warning@+2 {{is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'PartiallyAvailable' in a __builtin_available check to silence this warning}}
#endif
PartiallyAvailable();
}
+#ifdef WARN_PARTIAL
+// FIXME: This note should point to the declaration with the availability
+// attribute.
+// expected-note@+2 {{marked partial here}}
+#endif
extern void PartiallyAvailable() ;
void with_redeclaration() {
- PartiallyAvailable(); // Don't warn.
-
- // enums should never warn.
+#ifdef WARN_PARTIAL
+ // expected-warning@+4 {{'PartiallyAvailable' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}}
+ // expected-warning@+4 {{'PartialEnum' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}}
+ // expected-warning@+3 {{'kPartialEnumConstant' is only available on macOS 10.8 or newer}} expected-note@+3 {{__builtin_available}}
+#endif
+ PartiallyAvailable();
enum PartialEnum p = kPartialEnumConstant;
}
@@ -74,7 +85,7 @@ extern int x;
void f8() {
int (^b)(int);
- b = ^ (int i) __attribute__((availability(macosx,introduced=10.2))) { return 1; }; // expected-warning {{'availability' attribute ignored}}
+ b = ^ (int i) __attribute__((availability(macosx,introduced=10.2))) { return 1; }; // expected-warning {{'availability' attribute only applies to named declarations}}
}
extern int x2 __attribute__((availability(macosx,introduced=10.2))); // expected-note {{previous attribute is here}}
@@ -86,13 +97,13 @@ enum Original {
OriginalUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'OriginalUnavailable' has been explicitly marked unavailable here}}
};
-enum AllDeprecated {
- AllDeprecatedCase, // expected-note + {{'AllDeprecatedCase' has been explicitly marked deprecated here}}
+enum AllDeprecated { // expected-note + {{'AllDeprecated' has been explicitly marked deprecated here}}
+ AllDeprecatedCase,
AllDeprecatedUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'AllDeprecatedUnavailable' has been explicitly marked unavailable here}}
} __attribute__((availability(macosx, deprecated=10.2)));
-enum AllUnavailable {
- AllUnavailableCase, // expected-note + {{'AllUnavailableCase' has been explicitly marked unavailable here}}
+enum AllUnavailable { // expected-note + {{'AllUnavailable' has been explicitly marked unavailable here}}
+ AllUnavailableCase,
} __attribute__((availability(macosx, unavailable)));
enum User {
diff --git a/test/Sema/attr-capabilities.c b/test/Sema/attr-capabilities.c
index 8996770486..88fdf306ac 100644
--- a/test/Sema/attr-capabilities.c
+++ b/test/Sema/attr-capabilities.c
@@ -37,9 +37,6 @@ void Func6(void) __attribute__((requires_shared_capability(BadCapability))) {}
void Func7(void) __attribute__((assert_capability(GUI))) {}
void Func8(void) __attribute__((assert_shared_capability(GUI))) {}
-void Func9(void) __attribute__((assert_capability())) {} // expected-error {{'assert_capability' attribute takes one argument}}
-void Func10(void) __attribute__((assert_shared_capability())) {} // expected-error {{'assert_shared_capability' attribute takes one argument}}
-
void Func11(void) __attribute__((acquire_capability(GUI))) {}
void Func12(void) __attribute__((acquire_shared_capability(GUI))) {}
diff --git a/test/Sema/attr-deprecated-c2x.c b/test/Sema/attr-deprecated-c2x.c
new file mode 100644
index 0000000000..2505f1294c
--- /dev/null
+++ b/test/Sema/attr-deprecated-c2x.c
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -fdouble-square-bracket-attributes
+
+int f() [[deprecated]]; // expected-note 2 {{'f' has been explicitly marked deprecated here}}
+void g() [[deprecated]];// expected-note {{'g' has been explicitly marked deprecated here}}
+void g();
+
+extern int var [[deprecated]]; // expected-note 2 {{'var' has been explicitly marked deprecated here}}
+
+int a() {
+ int (*ptr)() = f; // expected-warning {{'f' is deprecated}}
+ f(); // expected-warning {{'f' is deprecated}}
+
+ // test if attributes propagate to functions
+ g(); // expected-warning {{'g' is deprecated}}
+
+ return var; // expected-warning {{'var' is deprecated}}
+}
+
+// test if attributes propagate to variables
+extern int var;
+int w() {
+ return var; // expected-warning {{'var' is deprecated}}
+}
+
+int old_fn() [[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() {
+ return old_fn()+1; // no warning, deprecated functions can use deprecated symbols.
+}
+
+struct foo {
+ int x [[deprecated]]; // expected-note 3 {{'x' has been explicitly marked deprecated here}}
+};
+
+void test1(struct foo *F) {
+ ++F->x; // expected-warning {{'x' is deprecated}}
+ struct foo f1 = { .x = 17 }; // expected-warning {{'x' is deprecated}}
+ struct foo f2 = { 17 }; // expected-warning {{'x' is deprecated}}
+}
+
+typedef struct foo foo_dep [[deprecated]]; // expected-note {{'foo_dep' has been explicitly marked deprecated here}}
+foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}}
+
+struct [[deprecated, // expected-note {{'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}}
+
+[[deprecated("this is the message")]] int i; // expected-note {{'i' has been explicitly marked deprecated here}}
+void test4(void) {
+ i = 12; // expected-warning {{'i' is deprecated: this is the message}}
+}
diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c
index 8566a0e943..9eeef5aed5 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}}
@@ -102,9 +104,9 @@ foo_dep test17, // expected-warning {{'foo_dep' is deprecated}}
test19;
// rdar://problem/8518751
-enum __attribute__((deprecated)) Test20 { // expected-note {{'Test20' has been explicitly marked deprecated here}}
+enum __attribute__((deprecated)) Test20 { // expected-note 2 {{'Test20' has been explicitly marked deprecated here}}
test20_a __attribute__((deprecated)), // expected-note {{'test20_a' has been explicitly marked deprecated here}}
- test20_b // expected-note {{'test20_b' has been explicitly marked deprecated here}}
+ test20_b
};
void test20() {
enum Test20 f; // expected-warning {{'Test20' 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-long-call.c b/test/Sema/attr-long-call.c
new file mode 100644
index 0000000000..cd3de1bf9e
--- /dev/null
+++ b/test/Sema/attr-long-call.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple mips-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple mips64-linux-gnu -fsyntax-only -verify %s
+
+__attribute__((long_call(0))) void foo1(); // expected-error {{'long_call' attribute takes no arguments}}
+__attribute__((short_call(0))) void foo9(); // expected-error {{'short_call' attribute takes no arguments}}
+__attribute__((far(0))) void foo2(); // expected-error {{'far' attribute takes no arguments}}
+__attribute__((near(0))) void foo3(); // expected-error {{'near' attribute takes no arguments}}
+
+__attribute((long_call)) int a; // expected-warning {{attribute only applies to functions}}
+__attribute((short_call)) int d; // expected-warning {{attribute only applies to functions}}
+__attribute((far)) int a; // expected-warning {{attribute only applies to functions}}
+__attribute((near)) int a; // expected-warning {{attribute only applies to functions}}
+
+__attribute((long_call)) void foo4();
+__attribute((short_call)) void foo10();
+__attribute((far)) void foo5();
+__attribute((near)) void foo6();
+
+__attribute((long_call, far)) void foo7();
+__attribute((short_call, near)) void foo11();
+
+__attribute((far, near)) void foo8(); // expected-error {{'far' and 'near' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
+
+__attribute((short_call, long_call)) void foo12(); // expected-error {{'short_call' and 'long_call' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
diff --git a/test/Sema/attr-micromips.c b/test/Sema/attr-micromips.c
new file mode 100644
index 0000000000..fe587fa3db
--- /dev/null
+++ b/test/Sema/attr-micromips.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple mips-linux-gnu -fsyntax-only -verify %s
+
+__attribute__((nomicromips(0))) void foo1(); // expected-error {{'nomicromips' attribute takes no arguments}}
+__attribute__((micromips(1))) void foo2(); // expected-error {{'micromips' attribute takes no arguments}}
+
+__attribute((nomicromips)) int a; // expected-error {{attribute only applies to functions}}
+__attribute((micromips)) int b; // expected-error {{attribute only applies to functions}}
+
+__attribute__((micromips,mips16)) void foo5(); // expected-error {{'micromips' and 'mips16' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
+__attribute__((mips16,micromips)) void foo6(); // expected-error {{'mips16' and 'micromips' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
+
+__attribute((micromips)) void foo7();
+__attribute((nomicromips)) void foo8();
+__attribute__((mips16)) void foo9(void) __attribute__((micromips)); // expected-error {{'micromips' and 'mips16' attributes are not compatible}} \
+ // expected-note {{conflicting attribute is here}}
diff --git a/test/Sema/attr-section.c b/test/Sema/attr-section.c
index c64b10d80f..b361738e8e 100644
--- a/test/Sema/attr-section.c
+++ b/test/Sema/attr-section.c
@@ -19,3 +19,16 @@ void __attribute__((section("foo,zed"))) test2(void); // expected-note {{previou
void __attribute__((section("bar,zed"))) test2(void) {} // expected-warning {{section does not match previous declaration}}
enum __attribute__((section("NEAR,x"))) e { one }; // expected-error {{'section' attribute only applies to functions, methods, properties, and global variables}}
+
+extern int a; // expected-note {{previous declaration is here}}
+int *b = &a;
+extern int a __attribute__((section("foo,zed"))); // expected-warning {{section attribute is specified on redeclared variable}}
+
+// Not a warning.
+int c;
+int c __attribute__((section("foo,zed")));
+
+// Also OK.
+struct r_debug {};
+extern struct r_debug _r_debug;
+struct r_debug _r_debug __attribute__((nocommon, section(".r_debug,bar")));
diff --git a/test/Sema/attr-selectany.c b/test/Sema/attr-selectany.c
index 01cca7d7cf..9d574d524f 100644
--- a/test/Sema/attr-selectany.c
+++ b/test/Sema/attr-selectany.c
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fms-compatibility -fms-extensions -verify %s
+// RUN: %clang_cc1 -triple x86_64-win32 -fdeclspec -verify %s
+// RUN: %clang_cc1 -triple x86_64-mingw32 -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -verify -fdeclspec %s
+// RUN: %clang_cc1 -triple x86_64-win32-macho -verify -fdeclspec %s
extern __declspec(selectany) const int x1 = 1; // no warning, const means we need extern in C++
diff --git a/test/Sema/attr-target.c b/test/Sema/attr-target.c
index 6c6b461904..058bfc421a 100644
--- a/test/Sema/attr-target.c
+++ b/test/Sema/attr-target.c
@@ -2,7 +2,13 @@
int __attribute__((target("avx,sse4.2,arch=ivybridge"))) foo() { return 4; }
int __attribute__((target())) bar() { return 4; } //expected-error {{'target' attribute takes one argument}}
-int __attribute__((target("tune=sandybridge"))) baz() { return 4; } //expected-warning {{Ignoring unsupported 'tune=' in the target attribute string}}
-int __attribute__((target("fpmath=387"))) walrus() { return 4; } //expected-warning {{Ignoring unsupported 'fpmath=' in the target attribute string}}
+int __attribute__((target("tune=sandybridge"))) baz() { return 4; } //expected-warning {{ignoring unsupported 'tune=' in the target attribute string}}
+int __attribute__((target("fpmath=387"))) walrus() { return 4; } //expected-warning {{ignoring unsupported 'fpmath=' in the target attribute string}}
+int __attribute__((target("avx,sse4.2,arch=hiss"))) meow() { return 4; }//expected-warning {{ignoring unsupported architecture 'hiss' in the target attribute string}}
+int __attribute__((target("woof"))) bark() { return 4; }//expected-warning {{ignoring unsupported 'woof' in the target attribute string}}
+int __attribute__((target("arch="))) turtle() { return 4; } // no warning, same as saying 'nothing'.
+int __attribute__((target("arch=hiss,arch=woof"))) pine_tree() { return 4; } //expected-warning {{ignoring unsupported architecture 'hiss' in the target attribute string}}
+int __attribute__((target("arch=ivybridge,arch=haswell"))) oak_tree() { return 4; } //expected-warning {{ignoring duplicate 'arch=' in the target attribute string}}
+
diff --git a/test/Sema/attr-unavailable-message.c b/test/Sema/attr-unavailable-message.c
index 415cb2f079..70d5947086 100644
--- a/test/Sema/attr-unavailable-message.c
+++ b/test/Sema/attr-unavailable-message.c
@@ -36,13 +36,13 @@ void unavail(void) {
// rdar://10201690
enum foo {
- a = 1, // expected-note {{'a' has been explicitly marked deprecated here}}
+ a = 1,
b __attribute__((deprecated())) = 2, // expected-note {{'b' has been explicitly marked deprecated here}}
c = 3
-}__attribute__((deprecated()));
+}__attribute__((deprecated())); // expected-note {{'foo' has been explicitly marked deprecated here}}
-enum fee { // expected-note {{'fee' has been explicitly marked unavailable here}}
- r = 1, // expected-note {{'r' has been explicitly marked unavailable here}}
+enum fee { // expected-note 2 {{'fee' has been explicitly marked unavailable here}}
+ r = 1,
s = 2,
t = 3
}__attribute__((unavailable()));
diff --git a/test/Sema/block-args.c b/test/Sema/block-args.c
index c6beead391..69cf047a9e 100644
--- a/test/Sema/block-args.c
+++ b/test/Sema/block-args.c
@@ -37,7 +37,7 @@ void f0() {
// rdar://problem/8962770
void test4() {
- int (^f)() = ^((x)) { }; // expected-error {{expected ')'}} expected-warning {{type specifier missing}} expected-note {{to match this}}
+ int (^f)() = ^((x)) { }; // expected-warning {{type specifier missing}} expected-error {{type-id cannot have a name}}
}
// rdar://problem/9170609
diff --git a/test/Sema/builtin-cpu-supports.c b/test/Sema/builtin-cpu-supports.c
index c537b4140b..026b5b7e38 100644
--- a/test/Sema/builtin-cpu-supports.c
+++ b/test/Sema/builtin-cpu-supports.c
@@ -12,9 +12,15 @@ int main() {
if (__builtin_cpu_supports(str)) // expected-error {{expression is not a string literal}}
a(str);
+
+ if (__builtin_cpu_is("int")) // expected-error {{invalid cpu name for builtin}}
+ a("intel");
#else
if (__builtin_cpu_supports("vsx")) // expected-error {{use of unknown builtin}}
a("vsx");
+
+ if (__builtin_cpu_is("pwr9")) // expected-error {{use of unknown builtin}}
+ a("pwr9");
#endif
return 0;
diff --git a/test/Sema/builtins-ppc.c b/test/Sema/builtins-ppc.c
index 60872a614e..5c45d02b41 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 f7854381a3..074efe16ad 100644
--- a/test/Sema/builtins-x86.c
+++ b/test/Sema/builtins-x86.c
@@ -80,6 +80,6 @@ __m512i _mm512_mask_prefetch_i32gather_ps(__m512i index, __mmask16 mask, int con
}
__m512 _mm512_mask_prefetch_i32gather_ps_2(__m512i index, __mmask16 mask, int const *addr) {
- return __builtin_ia32_gatherpfdps(mask, index, addr, 1, 3); // expected-error {{argument should be a value from 1 to 2}}
+ 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/c2x-fallthrough.c b/test/Sema/c2x-fallthrough.c
new file mode 100644
index 0000000000..2fd69c4da0
--- /dev/null
+++ b/test/Sema/c2x-fallthrough.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
+
+void f(int n) {
+ switch (n) {
+ case 0:
+ n += 1;
+ [[fallthrough]]; // ok
+ case 1:
+ if (n) {
+ [[fallthrough]]; // ok
+ } else {
+ return;
+ }
+ case 2:
+ for (int n = 0; n != 10; ++n)
+ [[fallthrough]]; // expected-error {{does not directly precede switch label}}
+ case 3:
+ while (1)
+ [[fallthrough]]; // expected-error {{does not directly precede switch label}}
+ case 4:
+ while (0)
+ [[fallthrough]]; // expected-error {{does not directly precede switch label}}
+ case 5:
+ do [[fallthrough]]; while (1); // expected-error {{does not directly precede switch label}}
+ case 6:
+ do [[fallthrough]]; while (0); // expected-error {{does not directly precede switch label}}
+ case 7:
+ switch (n) {
+ case 0:
+ // FIXME: This should be an error, even though the next thing we do is to
+ // fall through in an outer switch statement.
+ [[fallthrough]];
+ }
+ case 8:
+ [[fallthrough]]; // expected-error {{does not directly precede switch label}}
+ goto label;
+ label:
+ case 9:
+ n += 1;
+ case 10: // no warning, -Wimplicit-fallthrough is not enabled in this test, and does not need to
+ // be enabled for these diagnostics to be produced.
+ break;
+ }
+}
+
+[[fallthrough]] typedef int n1; // expected-error {{'fallthrough' attribute cannot be applied to a declaration}}
+typedef int [[fallthrough]] n2; // expected-error {{'fallthrough' attribute cannot be applied to types}}
+typedef int n3 [[fallthrough]]; // expected-error {{'fallthrough' attribute cannot be applied to a declaration}}
+
+enum [[fallthrough]] E { // expected-error {{'fallthrough' attribute cannot be applied to a declaration}}
+ One
+};
+struct [[fallthrough]] S { // expected-error {{'fallthrough' attribute cannot be applied to a declaration}}
+ int i;
+};
+
+[[fallthrough]] // expected-error {{'fallthrough' attribute cannot be applied to a declaration}}
+void g(void) {
+ [[fallthrough]] int n; // expected-error {{'fallthrough' attribute cannot be applied to a declaration}}
+ [[fallthrough]] ++n; // expected-error-re {{{{^}}fallthrough attribute is only allowed on empty statements}}
+
+ switch (n) {
+ // FIXME: This should be an error.
+ [[fallthrough]];
+ return;
+
+ case 0:
+ [[fallthrough, fallthrough]]; // expected-error {{multiple times}}
+ case 1:
+ [[fallthrough(0)]]; // expected-error {{argument list}}
+ case 2:
+ break;
+ }
+}
+
diff --git a/test/Sema/c2x-maybe_unused-errors.c b/test/Sema/c2x-maybe_unused-errors.c
new file mode 100644
index 0000000000..68150dded9
--- /dev/null
+++ b/test/Sema/c2x-maybe_unused-errors.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused -fdouble-square-bracket-attributes -verify %s
+
+struct [[maybe_unused]] S1 { // ok
+ int a [[maybe_unused]];
+};
+struct [[maybe_unused maybe_unused]] S2 { // expected-error {{attribute 'maybe_unused' cannot appear multiple times in an attribute specifier}}
+ int a;
+};
+struct [[maybe_unused("Wrong")]] S3 { // expected-error {{'maybe_unused' cannot have an argument list}}
+ int a;
+};
+
diff --git a/test/Sema/c2x-maybe_unused.c b/test/Sema/c2x-maybe_unused.c
new file mode 100644
index 0000000000..816cf7835f
--- /dev/null
+++ b/test/Sema/c2x-maybe_unused.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused -fdouble-square-bracket-attributes -verify %s
+
+struct [[maybe_unused]] S1 { // ok
+ int a [[maybe_unused]];
+};
+
+enum [[maybe_unused]] E1 {
+ EnumVal [[maybe_unused]]
+};
+
+[[maybe_unused]] void unused_func([[maybe_unused]] int parm) {
+ typedef int maybe_unused_int [[maybe_unused]];
+ [[maybe_unused]] int I;
+}
+
+void f1(void) {
+ int x; // expected-warning {{unused variable}}
+ typedef int I; // expected-warning {{unused typedef 'I'}}
+
+ // Should not warn about these due to not being used.
+ [[maybe_unused]] int y;
+ typedef int maybe_unused_int [[maybe_unused]];
+
+ // Should not warn about these uses.
+ struct S1 s;
+ maybe_unused_int test;
+ y = 12;
+}
+
+void f2(void);
+[[maybe_unused]] void f2(void);
+
+void f2(void) {
+}
+
diff --git a/test/Sema/c2x-nodiscard.c b/test/Sema/c2x-nodiscard.c
new file mode 100644
index 0000000000..f128d3bb57
--- /dev/null
+++ b/test/Sema/c2x-nodiscard.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
+
+struct [[nodiscard]] S1 { // ok
+ int i;
+};
+struct [[nodiscard nodiscard]] S2 { // expected-error {{attribute 'nodiscard' cannot appear multiple times in an attribute specifier}}
+ int i;
+};
+struct [[nodiscard("Wrong")]] S3 { // expected-error {{'nodiscard' cannot have an argument list}}
+ int i;
+};
+
+[[nodiscard]] int f1(void);
+enum [[nodiscard]] E1 { One };
+
+[[nodiscard]] int i; // expected-warning {{'nodiscard' attribute only applies to functions, methods, enums, and classes}}
+
+struct [[nodiscard]] S4 {
+ int i;
+};
+struct S4 get_s(void);
+
+enum [[nodiscard]] E2 { Two };
+enum E2 get_e(void);
+
+[[nodiscard]] int get_i();
+
+void f2(void) {
+ get_s(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ get_i(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ get_e(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ // Okay, warnings are not encouraged
+ (void)get_s();
+ (void)get_i();
+ (void)get_e();
+}
+
+struct [[nodiscard]] error_info{
+ int i;
+};
+
+struct error_info enable_missile_safety_mode(void);
+void launch_missiles(void);
+void test_missiles(void) {
+ enable_missile_safety_mode(); // expected-warning {{ignoring return value of function declared with 'nodiscard'}}
+ launch_missiles();
+}
+
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 887bce0630..97586a7cc0 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -77,7 +77,7 @@ int ints(long a, unsigned long b) {
((int) a == (unsigned int) B) +
((short) a == (unsigned short) B) +
((signed char) a == (unsigned char) B) +
- (a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
+ (a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
(a < (unsigned int) B) +
(a < (unsigned short) B) +
(a < (unsigned char) B) +
@@ -85,8 +85,8 @@ int ints(long a, unsigned long b) {
((int) a < B) +
((short) a < B) +
((signed char) a < B) +
- ((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
- ((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}}
+ ((long) a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ ((int) a < (unsigned int) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
((short) a < (unsigned short) B) +
((signed char) a < (unsigned char) B) +
@@ -308,8 +308,59 @@ int rdar8414119_bar(unsigned x) {
int rdar8511238() {
enum A { A_foo, A_bar };
enum A a;
+
+ if (a == 0)
+ return 0;
+ if (a != 0)
+ return 0;
if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
- return 0;
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+
+ if (0 == a)
+ return 0;
+ if (0 != a)
+ return 0;
+ if (0 < a)
+ return 0;
+ if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (0 >= a)
+ return 0;
+
+ if (a == 0U)
+ return 0;
+ if (a != 0U)
+ return 0;
+ if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+
+ if (0U == a)
+ return 0;
+ if (0U != a)
+ return 0;
+ if (0U < a)
+ return 0;
+ if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (0U >= a)
+ return 0;
+
return 20;
}
diff --git a/test/Sema/declspec-naked.c b/test/Sema/declspec-naked.c
new file mode 100644
index 0000000000..ad40941a5f
--- /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 a4582deb17..43f3318824 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/diagnose_if.c b/test/Sema/diagnose_if.c
index 27689f49b4..38a3307d92 100644
--- a/test/Sema/diagnose_if.c
+++ b/test/Sema/diagnose_if.c
@@ -153,3 +153,7 @@ void runAlwaysWarnWithArg(int a) {
// Test that diagnose_if warnings generated in system headers are not ignored.
#include "Inputs/diagnose-if-warn-system-header.h"
+
+// Bug: we would complain about `a` being undeclared if this was spelled
+// __diagnose_if__.
+void underbarName(int a) __attribute__((__diagnose_if__(a, "", "warning")));
diff --git a/test/Sema/dllimport.c b/test/Sema/dllimport.c
index a7fb00e3f7..53bf372c65 100644
--- a/test/Sema/dllimport.c
+++ b/test/Sema/dllimport.c
@@ -2,6 +2,7 @@
// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -fms-extensions -verify -std=c11 -DMS %s
// RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -fms-extensions -verify -std=c11 -DGNU %s
// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions -verify -std=c99 -DGNU %s
+// RUN: %clang_cc1 -triple aarch64-win32 -fsyntax-only -fms-extensions -verify -std=c99 -DMS %s
// Invalid usage.
__declspec(dllimport) typedef int typedef1;
@@ -210,9 +211,14 @@ __declspec(dllimport) void redecl6();
void redecl7();
__declspec(dllimport) inline void redecl7() {}
-// PR31069: Don't crash trying to merge attributes for redeclaration of invalid decl.
+// PR31069: Don't crash trying to merge attributes for redeclaration of invalid
+// decl.
void __declspec(dllimport) redecl8(unknowntype X); // expected-error{{unknown type name 'unknowntype'}}
void redecl8(unknowntype X) { } // expected-error{{unknown type name 'unknowntype'}}
+// PR32021: Similarly, don't crash trying to merge attributes from a valid
+// decl to an invalid redeclaration.
+void __declspec(dllimport) redecl9(void); // expected-note{{previous declaration is here}}
+int redecl9(void) {} // expected-error{{conflicting types for 'redecl9'}}
// External linkage is required.
__declspec(dllimport) static int staticFunc(); // expected-error{{'staticFunc' must have external linkage when declared 'dllimport'}}
diff --git a/test/Sema/enum-attr.c b/test/Sema/enum-attr.c
new file mode 100644
index 0000000000..933d8ccdcd
--- /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/enum.c b/test/Sema/enum.c
index 3546bfe48f..f9e40690c6 100644
--- a/test/Sema/enum.c
+++ b/test/Sema/enum.c
@@ -123,3 +123,15 @@ int NegativeShortTest[NegativeShort == -1 ? 1 : -1];
// PR24610
enum Color { Red, Green, Blue }; // expected-note{{previous use is here}}
typedef struct Color NewColor; // expected-error {{use of 'Color' with tag type that does not match previous declaration}}
+
+// PR28903
+// In C it is valid to define tags inside enums.
+struct PR28903 {
+ enum {
+ PR28903_A = (enum {
+ PR28903_B,
+ PR28903_C = PR28903_B
+ })0
+ };
+ int makeStructNonEmpty;
+};
diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c
index 32bd0dfdd5..480871afad 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/ext_vector_ops.c b/test/Sema/ext_vector_ops.c
new file mode 100644
index 0000000000..af4df07e14
--- /dev/null
+++ b/test/Sema/ext_vector_ops.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wvector-conversion -triple x86_64-apple-darwin10
+
+typedef unsigned int v2u __attribute__ ((ext_vector_type(2)));
+typedef int v2s __attribute__ ((ext_vector_type(2)));
+typedef float v2f __attribute__ ((ext_vector_type(2)));
+
+void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
+ // Bitwise binary operators
+ (void)(v2ua & v2ua);
+ (void)(v2fa & v2fa); // expected-error{{invalid operands to binary expression}}
+
+ // Unary operators
+ (void)(~v2ua);
+ (void)(~v2fa); // expected-error{{invalid argument type 'v2f' (vector of 2 'float' values) to unary}}
+
+ // Comparison operators
+ 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];
+ // FIXME: error message below needs type!
+ (void)(array2[v2ua]); // expected-error{{array subscript is not an integer}}
+
+ v2u *v2u_ptr = 0;
+ v2s *v2s_ptr;
+}
diff --git a/test/Sema/format-strings-fixit-ssize_t.c b/test/Sema/format-strings-fixit-ssize_t.c
index 5208a294a4..f8893a14a4 100644
--- a/test/Sema/format-strings-fixit-ssize_t.c
+++ b/test/Sema/format-strings-fixit-ssize_t.c
@@ -1,7 +1,7 @@
// RUN: cp %s %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -pedantic -Wall -fixit %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -pedantic -Wall -Werror %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -E -o - %t | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c99 -pedantic -Wall -fixit %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c99 -fsyntax-only -pedantic -Wall -Werror %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c99 -E -o - %t | FileCheck %s
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -9,10 +9,14 @@
compile cleanly with -Werror -pedantic. */
int printf(char const *, ...);
+int scanf(const char *, ...);
void test() {
typedef signed long int ssize_t;
printf("%f", (ssize_t) 42);
+ ssize_t s;
+ scanf("%f", &s);
}
// CHECK: printf("%zd", (ssize_t) 42);
+// CHECK: scanf("%zd", &s)
diff --git a/test/Sema/format-strings-scanf.c b/test/Sema/format-strings-scanf.c
index 7a92842b24..b7cdd7dd4a 100644
--- a/test/Sema/format-strings-scanf.c
+++ b/test/Sema/format-strings-scanf.c
@@ -1,10 +1,28 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral %s
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wformat-nonliteral %s
// Test that -Wformat=0 works:
-// RUN: %clang_cc1 -fsyntax-only -Werror -Wformat=0 %s
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -Werror -Wformat=0 %s
#include <stdarg.h>
-typedef __typeof(sizeof(int)) size_t;
+typedef __SIZE_TYPE__ size_t;
+#define __SSIZE_TYPE__ \
+ __typeof__(_Generic((__SIZE_TYPE__)0, \
+ unsigned long long int : (long long int)0, \
+ unsigned long int : (long int)0, \
+ unsigned int : (int)0, \
+ unsigned short : (short)0, \
+ unsigned char : (signed char)0))
+typedef __SSIZE_TYPE__ ssize_t;
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#define __UNSIGNED_PTRDIFF_TYPE__ \
+ __typeof__(_Generic((__PTRDIFF_TYPE__)0, \
+ long long int : (unsigned long long int)0, \
+ long int : (unsigned long int)0, \
+ int : (unsigned int)0, \
+ short : (unsigned short)0, \
+ signed char : (unsigned char)0))
+
typedef struct _FILE FILE;
typedef __WCHAR_TYPE__ wchar_t;
@@ -172,6 +190,46 @@ void test_qualifiers(const int *cip, volatile int* vip,
scanf("%d", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
}
+void test_size_types() {
+ size_t s = 0;
+ scanf("%zu", &s); // No warning.
+
+ double d1 = 0.;
+ scanf("%zu", &d1); // expected-warning-re{{format specifies type 'size_t *' (aka '{{.+}}') but the argument has type 'double *'}}
+
+ ssize_t ss = 0;
+ scanf("%zd", &s); // No warning.
+
+ double d2 = 0.;
+ scanf("%zd", &d2); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'double *'}}
+
+ ssize_t sn = 0;
+ scanf("%zn", &sn); // No warning.
+
+ double d3 = 0.;
+ scanf("%zn", &d3); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'double *'}}
+}
+
+void test_ptrdiff_t_types() {
+ __UNSIGNED_PTRDIFF_TYPE__ p1 = 0;
+ scanf("%tu", &p1); // No warning.
+
+ double d1 = 0.;
+ scanf("%tu", &d1); // expected-warning-re{{format specifies type 'unsigned ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}
+
+ ptrdiff_t p2 = 0;
+ scanf("%td", &p2); // No warning.
+
+ double d2 = 0.;
+ scanf("%td", &d2); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}
+
+ ptrdiff_t p3 = 0;
+ scanf("%tn", &p3); // No warning.
+
+ double d3 = 0.;
+ scanf("%tn", &d3); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}
+}
+
void check_conditional_literal(char *s, int *i) {
scanf(0 ? "%s" : "%d", i); // no warning
scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char *'}}
diff --git a/test/Sema/fp16vec-sema.c b/test/Sema/fp16vec-sema.c
new file mode 100644
index 0000000000..aefb5f86a1
--- /dev/null
+++ b/test/Sema/fp16vec-sema.c
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef __fp16 half4 __attribute__ ((vector_size (8)));
+typedef float float4 __attribute__ ((vector_size (16)));
+typedef short short4 __attribute__ ((vector_size (8)));
+typedef int int4 __attribute__ ((vector_size (16)));
+
+half4 hv0, hv1;
+float4 fv0, fv1;
+short4 sv0;
+int4 iv0;
+
+void testFP16Vec(int c) {
+ hv0 = hv0 + hv1;
+ hv0 = hv0 - hv1;
+ hv0 = hv0 * hv1;
+ hv0 = hv0 / hv1;
+ hv0 = c ? hv0 : hv1;
+ hv0 += hv1;
+ hv0 -= hv1;
+ hv0 *= hv1;
+ hv0 /= hv1;
+ sv0 = hv0 == hv1;
+ sv0 = hv0 != hv1;
+ sv0 = hv0 < hv1;
+ sv0 = hv0 > hv1;
+ sv0 = hv0 <= hv1;
+ sv0 = hv0 >= hv1;
+ sv0 = hv0 || hv1; // expected-error{{logical expression with vector types 'half4' (vector of 4 '__fp16' values) and 'half4' is only supported in C++}}
+ sv0 = hv0 && hv1; // expected-error{{logical expression with vector types 'half4' (vector of 4 '__fp16' values) and 'half4' is only supported in C++}}
+
+ // Implicit conversion between half vectors and float vectors are not allowed.
+ hv0 = fv0; // expected-error{{assigning to}}
+ fv0 = hv0; // expected-error{{assigning to}}
+ hv0 = (half4)fv0; // expected-error{{invalid conversion between}}
+ fv0 = (float4)hv0; // expected-error{{invalid conversion between}}
+ hv0 = fv0 + fv1; // expected-error{{assigning to}}
+ fv0 = hv0 + hv1; // expected-error{{assigning to}}
+ hv0 = hv0 + fv1; // expected-error{{cannot convert between vector}}
+ hv0 = c ? hv0 : fv1; // expected-error{{cannot convert between vector}}
+ sv0 = hv0 == fv1; // expected-error{{cannot convert between vector}}
+ sv0 = hv0 < fv1; // expected-error{{cannot convert between vector}}
+ sv0 = hv0 || fv1; // expected-error{{cannot convert between vector}} expected-error{{invalid operands to binary expression}}
+ iv0 = hv0 == hv1; // expected-error{{assigning to}}
+
+ // FIXME: clang currently disallows using these operators on vectors, which is
+ // allowed by gcc.
+ sv0 = !hv0; // expected-error{{invalid argument type}}
+ hv0++; // expected-error{{cannot increment value of type}}
+ ++hv0; // expected-error{{cannot increment value of type}}
+}
diff --git a/test/Sema/implicit-decl-c90.c b/test/Sema/implicit-decl-c90.c
new file mode 100644
index 0000000000..6b3491cff7
--- /dev/null
+++ b/test/Sema/implicit-decl-c90.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 %s -std=c90 -verify -fsyntax-only
+void t0(int x) {
+ int explicit_decl();
+ int (*p)();
+ if(x > 0)
+ x = g() + 1; // expected-note {{previous implicit declaration}}
+ p = g;
+ if(x < 0) {
+ extern void u(int (*)[h()]);
+ int (*q)() = h;
+ }
+ p = h; /* expected-error {{use of undeclared identifier 'h'}} */
+}
+
+void t1(int x) {
+ int (*p)();
+ switch (x) {
+ g();
+ case 0:
+ x = h() + 1;
+ break;
+ case 1:
+ p = g;
+ p = h;
+ break;
+ }
+ p = g; /* expected-error {{use of undeclared identifier 'g'}} */
+ p = h; /* expected-error {{use of undeclared identifier 'h'}} */
+ explicit_decl();
+ p = explicit_decl;
+}
+
+int t2(int x) {
+ int y = ({ if (x > 0) x = g() + 1; 2*x; });
+ int (*p)() = g; /* expected-error {{use of undeclared identifier 'g'}} */
+ return y;
+}
+
+int PR34822() {
+ {int i = sizeof(PR34822_foo());} /* expected-note {{previous definition is here}} */
+ {extern int PR34822_foo;} /* expected-error {{redefinition of 'PR34822_foo' as different kind of symbol}} */
+
+ {extern int PR34822_bar;} /* expected-note {{previous declaration is here}} */
+ {int i = sizeof(PR34822_bar());} /* expected-warning {{use of out-of-scope declaration of 'PR34822_bar' whose type is not compatible with that of an implicit declaration}} expected-error {{called object type 'int' is not a function or function pointer}} */
+}
+
+int (*p)() = g; /* expected-error {{use of undeclared identifier 'g'}} */
+int (*q)() = h; /* expected-error {{use of undeclared identifier 'h'}} */
+
+float g(); /* expected-error {{conflicting types for 'g'}} */
diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c
index ffab9a6f91..a04bb0e22e 100644
--- a/test/Sema/implicit-decl.c
+++ b/test/Sema/implicit-decl.c
@@ -9,8 +9,7 @@ void func() {
int32_t *vector[16];
const char compDesc[16 + 1];
int32_t compCount = 0;
- if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-note {{previous implicit declaration is here}} \
- expected-error {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}}
+ if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-error {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}} expected-note {{previous implicit declaration}}
}
printg("Hello, World!\n"); // expected-error{{implicit declaration of function 'printg' is invalid in C99}} \
@@ -18,7 +17,7 @@ void func() {
__builtin_is_les(1, 3); // expected-error{{use of unknown builtin '__builtin_is_les'}}
}
-Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error{{conflicting types for '_CFCalendarDecomposeAbsoluteTimeV'}}
+Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error {{conflicting types}}
return 0;
}
diff --git a/test/Sema/inline-asm-validate-amdgpu.cl b/test/Sema/inline-asm-validate-amdgpu.cl
index d60b09e0ce..bc2580c573 100644
--- a/test/Sema/inline-asm-validate-amdgpu.cl
+++ b/test/Sema/inline-asm-validate-amdgpu.cl
@@ -1,6 +1,7 @@
// REQUIRES: amdgpu-registered-target
-// RUN: %clang_cc1 -x cl -triple amdgcn -fsyntax-only %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple amdgcn -fsyntax-only -verify %s
+
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
kernel void test () {
@@ -9,6 +10,67 @@ kernel void test () {
// sgpr constraints
__asm__ ("s_mov_b32 %0, %1" : "=s" (sgpr) : "s" (imm) : );
+ __asm__ ("s_mov_b32 %0, %1" : "={s1}" (sgpr) : "{exec}" (imm) : );
+ __asm__ ("s_mov_b32 %0, %1" : "={s1}" (sgpr) : "{exe" (imm) : ); // expected-error {{invalid input constraint '{exe' in asm}}
+ __asm__ ("s_mov_b32 %0, %1" : "={s1}" (sgpr) : "{exec" (imm) : ); // expected-error {{invalid input constraint '{exec' in asm}}
+ __asm__ ("s_mov_b32 %0, %1" : "={s1}" (sgpr) : "{exec}a" (imm) : ); // expected-error {{invalid input constraint '{exec}a' in asm}}
+
// vgpr constraints
__asm__ ("v_mov_b32 %0, %1" : "=v" (vgpr) : "v" (imm) : );
}
+
+__kernel void
+test_float(const __global float *a, const __global float *b, __global float *c, unsigned i)
+{
+ float ai = a[i];
+ float bi = b[i];
+ float ci;
+
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v1}"(ci) : "{v2}"(ai), "{v3}"(bi) : );
+ __asm("v_add_f32_e32 v1, v2, v3" : ""(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "="(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '=' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={a}"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={a}' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={}"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={}' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={v' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v1a}"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={v1a}' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={va}"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={va}' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v1}a"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={v1}a' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v1"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '={v1' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "=v1}"(ci) : "{v2}"(ai), "{v3}"(bi) : ); // expected-error {{invalid output constraint '=v1}' in asm}}
+
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v[1]}"(ci) : "{v[2]}"(ai), "{v[3]}"(bi) : );
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v[1}"(ci) : "{v[2]}"(ai), "{v[3]}"(bi) : ); // expected-error {{invalid output constraint '={v[1}' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v[1]"(ci) : "{v[2]}"(ai), "{v[3]}"(bi) : ); // expected-error {{invalid output constraint '={v[1]' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v[a]}"(ci) : "{v[2]}"(ai), "{v[3]}"(bi) : ); // expected-error {{invalid output constraint '={v[a]}' in asm}}
+
+ __asm("v_add_f32_e32 v1, v2, v3" : "=v"(ci) : "v"(ai), "v"(bi) : );
+ __asm("v_add_f32_e32 v1, v2, v3" : "=v1"(ci) : "v2"(ai), "v3"(bi) : ); /// expected-error {{invalid output constraint '=v1' in asm}}
+
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v1}"(ci) : "{a}"(ai), "{v3}"(bi) : ); // expected-error {{invalid input constraint '{a}' in asm}}
+ __asm("v_add_f32_e32 v1, v2, v3" : "={v1}"(ci) : "{v2}"(ai), "{a}"(bi) : ); // expected-error {{invalid input constraint '{a}' in asm}}
+ c[i] = ci;
+}
+
+__kernel void
+test_double(const __global double *a, const __global double *b, __global double *c, unsigned i)
+{
+ double ai = a[i];
+ double bi = b[i];
+ double ci;
+
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[1:2]}"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : );
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "=v{[1:2]}"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '=v{[1:2]}' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[1:2]a}"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[1:2]a}' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[1:2]}a"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[1:2]}a' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[1:"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[1:' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[1:]}"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[1:]}' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[:2]}"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[:2]}' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[1:2]"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[1:2]' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[1:2}"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[1:2}' in asm}}
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "={v[2:1]}"(ci) : "{v[3:4]}"(ai), "{v[5:6]}"(bi) : ); //expected-error {{invalid output constraint '={v[2:1]}' in asm}}
+
+ __asm("v_add_f64_e64 v[1:2], v[3:4], v[5:6]" : "=v[1:2]"(ci) : "v[3:4]"(ai), "v[5:6]"(bi) : ); //expected-error {{invalid output constraint '=v[1:2]' in asm}}
+
+ c[i] = ci;
+}
diff --git a/test/Sema/integer-overflow.c b/test/Sema/integer-overflow.c
index e74bc11979..44c2629ebf 100644
--- a/test/Sema/integer-overflow.c
+++ b/test/Sema/integer-overflow.c
@@ -147,6 +147,13 @@ uint64_t check_integer_overflows(int i) {
uint64_t a[10];
a[4608 * 1024 * 1024] = 1i;
+// expected-warning@+2 {{overflow in expression; result is 536870912 with type 'int'}}
+ uint64_t *b;
+ uint64_t b2 = b[4608 * 1024 * 1024] + 1;
+
+// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
+ (void)((i ? (4608 * 1024 * 1024) : (4608 * 1024 * 1024)) + 1);
+
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024)));
}
diff --git a/test/Sema/loop-control.c b/test/Sema/loop-control.c
index 6c33e8437b..1fc35d1021 100644
--- a/test/Sema/loop-control.c
+++ b/test/Sema/loop-control.c
@@ -119,3 +119,51 @@ void pr8880_23(int x, int y) {
for ( ; ({ ++y; break; y;}); ++y) {} // expected-warning{{'break' is bound to loop, GCC binds it to switch}}
}
}
+
+void pr32648_1(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ({ ++y; switch (y) { case 0: break; } y;}); ++y) {} // no warning
+ }
+}
+
+void pr32648_2(int x, int y) {
+ while(x) {
+ for ( ; ({ ++y; switch (y) { case 0: continue; } y;}); ++y) {} // expected-warning {{'continue' is bound to current loop, GCC binds it to the enclosing loop}}
+ }
+}
+
+void pr32648_3(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ({ ++y; for (; y; y++) { break; } y;}); ++y) {} // no warning
+ }
+}
+
+void pr32648_4(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ({ ++y; for (({ break; }); y; y++) { } y;}); ++y) {} // expected-warning{{'break' is bound to loop, GCC binds it to switch}}
+ }
+}
+
+void pr32648_5(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ({ ++y; while (({ break; y; })) {} y;}); ++y) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}}
+ }
+}
+
+void pr32648_6(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ({ ++y; do {} while (({ break; y; })); y;}); ++y) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}}
+ }
+}
+
+void pr32648_7(int x, int y) {
+ switch(x) {
+ case 1:
+ for ( ; ({ ++y; do { break; } while (y); y;}); ++y) {} // no warning
+ }
+}
diff --git a/test/Sema/ms-annotation.c b/test/Sema/ms-annotation.c
new file mode 100644
index 0000000000..9a2beebf06
--- /dev/null
+++ b/test/Sema/ms-annotation.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple i686-windows %s -verify -fms-extensions
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple i686-windows %s -verify -fms-extensions
+// RUN: %clang_cc1 -x c++ -std=c++14 -triple i686-windows %s -verify -fms-extensions
+
+void test1(void) {
+ __annotation(); // expected-error {{too few arguments to function call, expected at least 1, have 0}}
+ __annotation(1); // expected-error {{must be wide string constants}}
+ __annotation(L"a1");
+ __annotation(L"a1", L"a2");
+ __annotation(L"a1", L"a2", 42); // expected-error {{must be wide string constants}}
+ __annotation(L"a1", L"a2", L"a3");
+ __annotation(L"multi " L"part " L"string");
+}
diff --git a/test/Sema/ms-inline-asm.c b/test/Sema/ms-inline-asm.c
index abf10b67cc..3fc74fa99c 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}}
@@ -59,18 +59,13 @@ int t2(int *arr, int i) {
mov eax, arr[1 + (2 * 5) - 3 + 1<<1];
}
- // expected-error@+1 {{cannot use base register with variable reference}}
- __asm { mov eax, arr[ebp + 1 + (2 * 5) - 3 + 1<<1] }
- // expected-error@+1 {{cannot use index register with variable reference}}
- __asm { mov eax, arr[esi * 4] }
// expected-error@+1 {{cannot use more than one symbol in memory operand}}
__asm { mov eax, arr[i] }
// expected-error@+1 {{cannot use more than one symbol in memory operand}}
__asm { mov eax, global[i] }
- // FIXME: Why don't we diagnose this?
- // expected-Xerror@+1 {{cannot reference multiple local variables in assembly operand}}
- //__asm mov eax, [arr + i];
+ // expected-error@+1 {{cannot use more than one symbol in memory operand}}
+ __asm mov eax, [arr + i];
return 0;
}
@@ -98,7 +93,7 @@ void t4() {
__asm { mov eax, fs:[0] A.a }
__asm { mov eax, fs:[0].A.a }
__asm { mov eax, fs:[0].a } // expected-error {{Unable to lookup field reference!}}
- __asm { mov eax, fs:[0]. A.a } // expected-error {{Unexpected token type!}}
+ __asm { mov eax, fs:[0]. A.a } // expected-error {{unexpected token in argument list}}
}
void test_operand_size() {
diff --git a/test/Sema/noescape.c b/test/Sema/noescape.c
new file mode 100644
index 0000000000..39f3f6f542
--- /dev/null
+++ b/test/Sema/noescape.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void escapefunc(int *);
+void noescapefunc(__attribute__((noescape)) int *);
+void (*escapefuncptr)(int *);
+void (*noescapefuncptr)(__attribute__((noescape)) int *);
+
+void func_ne(__attribute__((noescape)) int *, int *);
+void func_en(int *, __attribute__((noescape)) int *);
+
+void (*funcptr_ee)(int *, int *);
+void (*funcptr_nn)(__attribute__((noescape)) int *, __attribute__((noescape)) int *);
+
+void test0(int c) {
+ escapefuncptr = &escapefunc;
+ escapefuncptr = &noescapefunc;
+ noescapefuncptr = &escapefunc; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}}
+ noescapefuncptr = &noescapefunc;
+
+ escapefuncptr = c ? &escapefunc : &noescapefunc;
+ noescapefuncptr = c ? &escapefunc : &noescapefunc; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *)' from 'void (*)(int *)'}}
+
+ funcptr_ee = c ? &func_ne : &func_en;
+ funcptr_nn = c ? &func_ne : &func_en; // expected-warning {{incompatible function pointer types assigning to 'void (*)(__attribute__((noescape)) int *, __attribute__((noescape)) int *)' from 'void (*)(int *, int *)'}}
+}
diff --git a/test/Sema/outof-range-constant-compare.c b/test/Sema/outof-range-constant-compare.c
index 4b1637c46c..ccb55e4a16 100644
--- a/test/Sema/outof-range-constant-compare.c
+++ b/test/Sema/outof-range-constant-compare.c
@@ -6,6 +6,7 @@ int value(void);
int main()
{
int a = value();
+
if (a == 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
return 0;
if (a != 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
@@ -74,6 +75,7 @@ int main()
return 0;
if (0x1234567812345678L >= s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
return 0;
+
long l = value();
if (l == 0x1234567812345678L)
return 0;
@@ -101,40 +103,6 @@ int main()
if (0x1234567812345678L >= l)
return 0;
- unsigned un = 0;
- if (un == 0x0000000000000000L)
- return 0;
- if (un != 0x0000000000000000L)
- return 0;
- if (un < 0x0000000000000000L)
- return 0;
- if (un <= 0x0000000000000000L)
- return 0;
- if (un > 0x0000000000000000L)
- return 0;
- if (un >= 0x0000000000000000L)
- return 0;
-
- if (0x0000000000000000L == un)
- return 0;
- if (0x0000000000000000L != un)
- return 0;
- if (0x0000000000000000L < un)
- return 0;
- if (0x0000000000000000L <= un)
- return 0;
- if (0x0000000000000000L > un)
- return 0;
- if (0x0000000000000000L >= un)
- return 0;
- float fl = 0;
- if (fl == 0x0000000000000000L) // no warning
- return 0;
-
- float dl = 0;
- if (dl == 0x0000000000000000L) // no warning
- return 0;
-
enum E {
yes,
no,
diff --git a/test/Sema/outof-range-enum-constant-compare.c b/test/Sema/outof-range-enum-constant-compare.c
new file mode 100644
index 0000000000..b9ce08f68c
--- /dev/null
+++ b/test/Sema/outof-range-enum-constant-compare.c
@@ -0,0 +1,379 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -Wno-tautological-constant-out-of-range-compare -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -Wno-tautological-constant-out-of-range-compare -verify %s
+
+int main() {
+ enum A { A_a = 2 };
+ enum A a;
+
+#ifdef SILENCE
+ // expected-no-diagnostics
+#endif
+
+#ifdef UNSIGNED
+#ifndef SILENCE
+ if (a < 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (4294967296 >= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a > 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (4294967296 <= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a <= 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (4294967296 > a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a >= 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (4294967296 < a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a == 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (4294967296 != a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a != 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (4294967296 == a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+
+ if (a < 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (4294967296U >= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a > 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (4294967296U <= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a <= 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (4294967296U > a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a >= 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (4294967296U < a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a == 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+ if (4294967296U != a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a != 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}}
+ return 0;
+ if (4294967296U == a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}}
+ return 0;
+#else // SILENCE
+ if (a < 4294967296)
+ return 0;
+ if (4294967296 >= a)
+ return 0;
+ if (a > 4294967296)
+ return 0;
+ if (4294967296 <= a)
+ return 0;
+ if (a <= 4294967296)
+ return 0;
+ if (4294967296 > a)
+ return 0;
+ if (a >= 4294967296)
+ return 0;
+ if (4294967296 < a)
+ return 0;
+ if (a == 4294967296)
+ return 0;
+ if (4294967296 != a)
+ return 0;
+ if (a != 4294967296)
+ return 0;
+ if (4294967296 == a)
+ return 0;
+
+ if (a < 4294967296U)
+ return 0;
+ if (4294967296U >= a)
+ return 0;
+ if (a > 4294967296U)
+ return 0;
+ if (4294967296U <= a)
+ return 0;
+ if (a <= 4294967296U)
+ return 0;
+ if (4294967296U > a)
+ return 0;
+ if (a >= 4294967296U)
+ return 0;
+ if (4294967296U < a)
+ return 0;
+ if (a == 4294967296U)
+ return 0;
+ if (4294967296U != a)
+ return 0;
+ if (a != 4294967296U)
+ return 0;
+ if (4294967296U == a)
+ return 0;
+#endif
+#elif defined(SIGNED)
+#ifndef SILENCE
+ if (a < -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}}
+ return 0;
+ if (-2147483649 >= a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a > -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}}
+ return 0;
+ if (-2147483649 <= a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a <= -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}}
+ return 0;
+ if (-2147483649 > a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a >= -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}}
+ return 0;
+ if (-2147483649 < a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a == -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}}
+ return 0;
+ if (-2147483649 != a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a != -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}}
+ return 0;
+ if (-2147483649 == a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}}
+ return 0;
+
+ if (a < 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}}
+ return 0;
+ if (2147483648 >= a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a > 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}}
+ return 0;
+ if (2147483648 <= a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a <= 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}}
+ return 0;
+ if (2147483648 > a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a >= 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}}
+ return 0;
+ if (2147483648 < a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}}
+ return 0;
+ if (a == 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}}
+ return 0;
+ if (2147483648 != a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}}
+ return 0;
+ if (a != 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}}
+ return 0;
+ if (2147483648 == a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}}
+ return 0;
+#else // SILENCE
+ if (a < -2147483649)
+ return 0;
+ if (-2147483649 >= a)
+ return 0;
+ if (a > -2147483649)
+ return 0;
+ if (-2147483649 <= a)
+ return 0;
+ if (a <= -2147483649)
+ return 0;
+ if (-2147483649 > a)
+ return 0;
+ if (a >= -2147483649)
+ return 0;
+ if (-2147483649 < a)
+ return 0;
+ if (a == -2147483649)
+ return 0;
+ if (-2147483649 != a)
+ return 0;
+ if (a != -2147483649)
+ return 0;
+ if (-2147483649 == a)
+ return 0;
+
+ if (a < 2147483648)
+ return 0;
+ if (2147483648 >= a)
+ return 0;
+ if (a > 2147483648)
+ return 0;
+ if (2147483648 <= a)
+ return 0;
+ if (a <= 2147483648)
+ return 0;
+ if (2147483648 > a)
+ return 0;
+ if (a >= 2147483648)
+ return 0;
+ if (2147483648 < a)
+ return 0;
+ if (a == 2147483648)
+ return 0;
+ if (2147483648 != a)
+ return 0;
+ if (a != 2147483648)
+ return 0;
+ if (2147483648 == a)
+ return 0;
+#endif
+#endif
+}
+
+// https://bugs.llvm.org/show_bug.cgi?id=35009
+int PR35009() {
+ enum A { A_a = 2 };
+ enum A a;
+
+ // in C, this should not warn.
+
+ if (a < 1)
+ return 0;
+ if (1 >= a)
+ return 0;
+ if (a > 1)
+ return 0;
+ if (1 <= a)
+ return 0;
+ if (a <= 1)
+ return 0;
+ if (1 > a)
+ return 0;
+ if (a >= 1)
+ return 0;
+ if (1 < a)
+ return 0;
+ if (a == 1)
+ return 0;
+ if (1 != a)
+ return 0;
+ if (a != 1)
+ return 0;
+ if (1 == a)
+ return 0;
+
+ if (a < 1U)
+ return 0;
+ if (1U >= a)
+ return 0;
+ if (a > 1U)
+ return 0;
+ if (1U <= a)
+ return 0;
+ if (a <= 1U)
+ return 0;
+ if (1U > a)
+ return 0;
+ if (a >= 1U)
+ return 0;
+ if (1U < a)
+ return 0;
+ if (a == 1U)
+ return 0;
+ if (1U != a)
+ return 0;
+ if (a != 1U)
+ return 0;
+ if (1U == a)
+ return 0;
+
+ if (a < 2)
+ return 0;
+ if (2 >= a)
+ return 0;
+ if (a > 2)
+ return 0;
+ if (2 <= a)
+ return 0;
+ if (a <= 2)
+ return 0;
+ if (2 > a)
+ return 0;
+ if (a >= 2)
+ return 0;
+ if (2 < a)
+ return 0;
+ if (a == 2)
+ return 0;
+ if (2 != a)
+ return 0;
+ if (a != 2)
+ return 0;
+ if (2 == a)
+ return 0;
+
+ if (a < 2U)
+ return 0;
+ if (2U >= a)
+ return 0;
+ if (a > 2U)
+ return 0;
+ if (2U <= a)
+ return 0;
+ if (a <= 2U)
+ return 0;
+ if (2U > a)
+ return 0;
+ if (a >= 2U)
+ return 0;
+ if (2U < a)
+ return 0;
+ if (a == 2U)
+ return 0;
+ if (2U != a)
+ return 0;
+ if (a != 2U)
+ return 0;
+ if (2U == a)
+ return 0;
+
+ if (a < 3)
+ return 0;
+ if (3 >= a)
+ return 0;
+ if (a > 3)
+ return 0;
+ if (3 <= a)
+ return 0;
+ if (a <= 3)
+ return 0;
+ if (3 > a)
+ return 0;
+ if (a >= 3)
+ return 0;
+ if (3 < a)
+ return 0;
+ if (a == 3)
+ return 0;
+ if (3 != a)
+ return 0;
+ if (a != 3)
+ return 0;
+ if (3 == a)
+ return 0;
+
+ if (a < 3U)
+ return 0;
+ if (3U >= a)
+ return 0;
+ if (a > 3U)
+ return 0;
+ if (3U <= a)
+ return 0;
+ if (a <= 3U)
+ return 0;
+ if (3U > a)
+ return 0;
+ if (a >= 3U)
+ return 0;
+ if (3U < a)
+ return 0;
+ if (a == 3U)
+ return 0;
+ if (3U != a)
+ return 0;
+ if (a != 3U)
+ return 0;
+ if (3U == a)
+ return 0;
+
+ return 1;
+}
diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c
index f5e17d2119..4bdec85f9c 100644
--- a/test/Sema/overloadable.c
+++ b/test/Sema/overloadable.c
@@ -3,12 +3,15 @@
int var __attribute__((overloadable)); // expected-error{{'overloadable' attribute only applies to functions}}
void params(void) __attribute__((overloadable(12))); // expected-error {{'overloadable' attribute takes no arguments}}
-int *f(int) __attribute__((overloadable)); // expected-note 2{{previous overload of function is here}}
-float *f(float); // expected-error{{overloaded function 'f' must have the 'overloadable' attribute}}
+int *f(int) __attribute__((overloadable)); // expected-note{{previous overload of function is here}}
+float *f(float);
int *f(int); // expected-error{{redeclaration of 'f' must have the 'overloadable' attribute}} \
// expected-note{{previous declaration is here}}
double *f(double) __attribute__((overloadable)); // okay, new
+// Ensure we don't complain about overloadable on implicitly declared functions.
+int isdigit(int) __attribute__((overloadable));
+
void test_f(int iv, float fv, double dv) {
int *ip = f(iv);
float *fp = f(fv);
@@ -71,19 +74,19 @@ void test() {
f1();
}
-void before_local_1(int) __attribute__((overloadable)); // expected-note {{here}}
+void before_local_1(int) __attribute__((overloadable));
void before_local_2(int); // expected-note {{here}}
void before_local_3(int) __attribute__((overloadable));
void local() {
- void before_local_1(char); // expected-error {{must have the 'overloadable' attribute}}
- void before_local_2(char) __attribute__((overloadable)); // expected-error {{conflicting types}}
+ void before_local_1(char);
+ void before_local_2(char); // expected-error {{conflicting types}}
void before_local_3(char) __attribute__((overloadable));
- void after_local_1(char); // expected-note {{here}}
- void after_local_2(char) __attribute__((overloadable)); // expected-note {{here}}
+ void after_local_1(char);
+ void after_local_2(char) __attribute__((overloadable));
void after_local_3(char) __attribute__((overloadable));
}
-void after_local_1(int) __attribute__((overloadable)); // expected-error {{conflicting types}}
-void after_local_2(int); // expected-error {{must have the 'overloadable' attribute}}
+void after_local_1(int) __attribute__((overloadable));
+void after_local_2(int);
void after_local_3(int) __attribute__((overloadable));
// Make sure we allow C-specific conversions in C.
@@ -106,8 +109,8 @@ void fn_type_conversions() {
void foo(char *c) __attribute__((overloadable));
void (*ptr1)(void *) = &foo;
void (*ptr2)(char *) = &foo;
- void (*ambiguous)(int *) = &foo; // expected-error{{initializing 'void (*)(int *)' with an expression of incompatible type '<overloaded function type>'}} expected-note@105{{candidate function}} expected-note@106{{candidate function}}
- void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible type '<overloaded function type>'}} expected-note@105{{candidate function}} expected-note@106{{candidate function}}
+ void (*ambiguous)(int *) = &foo; // expected-error{{initializing 'void (*)(int *)' with an expression of incompatible type '<overloaded function type>'}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
+ void *vp_ambiguous = &foo; // expected-error{{initializing 'void *' with an expression of incompatible type '<overloaded function type>'}} expected-note@-5{{candidate function}} expected-note@-4{{candidate function}}
void (*specific1)(int *) = (void (*)(void *))&foo; // expected-warning{{incompatible function pointer types initializing 'void (*)(int *)' with an expression of type 'void (*)(void *)'}}
void *specific2 = (void (*)(void *))&foo;
@@ -117,8 +120,8 @@ void fn_type_conversions() {
void disabled(char *c) __attribute__((overloadable, enable_if(1, "The function name lies.")));
// To be clear, these should all point to the last overload of 'disabled'
void (*dptr1)(char *c) = &disabled;
- void (*dptr2)(void *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note@115{{candidate function made ineligible by enable_if}} expected-note@116{{candidate function made ineligible by enable_if}} expected-note@117{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'char *')}}
- void (*dptr3)(int *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(int *)' with an expression of type '<overloaded function type>'}} expected-note@115{{candidate function made ineligible by enable_if}} expected-note@116{{candidate function made ineligible by enable_if}} expected-note@117{{candidate function has type mismatch at 1st parameter (expected 'int *' but has 'char *')}}
+ void (*dptr2)(void *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(void *)' with an expression of type '<overloaded function type>'}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function made ineligible by enable_if}} expected-note@-3{{candidate function has type mismatch at 1st parameter (expected 'void *' but has 'char *')}}
+ void (*dptr3)(int *c) = &disabled; // expected-warning{{incompatible pointer types initializing 'void (*)(int *)' with an expression of type '<overloaded function type>'}} expected-note@-6{{candidate function made ineligible by enable_if}} expected-note@-5{{candidate function made ineligible by enable_if}} expected-note@-4{{candidate function has type mismatch at 1st parameter (expected 'int *' but has 'char *')}}
void *specific_disabled = &disabled;
}
@@ -131,14 +134,14 @@ void incompatible_pointer_type_conversions() {
void foo(char *c) __attribute__((overloadable));
void foo(short *c) __attribute__((overloadable));
foo(charbuf);
- foo(ucharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@131{{candidate function}} expected-note@132{{candidate function}}
- foo(intbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@131{{candidate function}} expected-note@132{{candidate function}}
+ foo(ucharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-3{{candidate function}} expected-note@-2{{candidate function}}
+ foo(intbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
void bar(unsigned char *c) __attribute__((overloadable));
void bar(signed char *c) __attribute__((overloadable));
- bar(charbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@137{{candidate function}} expected-note@138{{candidate function}}
+ bar(charbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@-2{{candidate function}} expected-note@-1{{candidate function}}
bar(ucharbuf);
- bar(intbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@137{{candidate function}} expected-note@138{{candidate function}}
+ bar(intbuf); // expected-error{{call to 'bar' is ambiguous}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
}
void dropping_qualifiers_is_incompatible() {
@@ -148,6 +151,100 @@ void dropping_qualifiers_is_incompatible() {
void foo(char *c) __attribute__((overloadable));
void foo(const volatile unsigned char *c) __attribute__((overloadable));
- foo(ccharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@148{{candidate function}} expected-note@149{{candidate function}}
- foo(vcharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@148{{candidate function}} expected-note@149{{candidate function}}
+ foo(ccharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-3{{candidate function}} expected-note@-2{{candidate function}}
+ foo(vcharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@-4{{candidate function}} expected-note@-3{{candidate function}}
+}
+
+void overloadable_with_global() {
+ void wg_foo(void) __attribute__((overloadable)); // expected-note{{previous}}
+ void wg_foo(int) __attribute__((overloadable));
+}
+
+int wg_foo; // expected-error{{redefinition of 'wg_foo' as different kind of symbol}}
+
+#if !__has_extension(overloadable_unmarked)
+#error "We should have unmarked overload support"
+#endif
+
+void to_foo0(int);
+void to_foo0(double) __attribute__((overloadable)); // expected-note{{previous overload}}
+void to_foo0(int);
+void to_foo0(double); // expected-error{{must have the 'overloadable' attribute}}
+void to_foo0(int);
+
+void to_foo1(int) __attribute__((overloadable)); // expected-note 2{{previous overload}}
+void to_foo1(double);
+void to_foo1(int); // expected-error{{must have the 'overloadable' attribute}}
+void to_foo1(double);
+void to_foo1(int); // expected-error{{must have the 'overloadable' attribute}}
+
+void to_foo2(int); // expected-note{{previous unmarked overload}}
+void to_foo2(double) __attribute__((overloadable)); // expected-note 2{{previous overload}}
+void to_foo2(int) __attribute__((overloadable)); // expected-error {{must not have the 'overloadable' attribute}}
+void to_foo2(double); // expected-error{{must have the 'overloadable' attribute}}
+void to_foo2(int);
+void to_foo2(double); // expected-error{{must have the 'overloadable' attribute}}
+void to_foo2(int);
+
+void to_foo3(int);
+void to_foo3(double) __attribute__((overloadable)); // expected-note{{previous overload}}
+void to_foo3(int);
+void to_foo3(double); // expected-error{{must have the 'overloadable' attribute}}
+
+void to_foo4(int) __attribute__((overloadable)); // expected-note{{previous overload}}
+void to_foo4(int); // expected-error{{must have the 'overloadable' attribute}}
+void to_foo4(double) __attribute__((overloadable));
+
+void to_foo5(int);
+void to_foo5(int); // expected-note 3{{previous unmarked overload}}
+void to_foo5(float) __attribute__((overloadable));
+void to_foo5(double); // expected-error{{at most one overload for a given name may lack the 'overloadable' attribute}}
+void to_foo5(float) __attribute__((overloadable));
+void to_foo5(short); // expected-error{{at most one overload for a given name may lack the 'overloadable' attribute}}
+void to_foo5(long); // expected-error{{at most one overload for a given name may lack the 'overloadable' attribute}}
+void to_foo5(double) __attribute__((overloadable));
+
+void to_foo6(int) __attribute__((enable_if(1, ""), overloadable)); // expected-note{{previous overload}}
+void to_foo6(int) __attribute__((enable_if(1, ""))); // expected-error{{must have the 'overloadable' attribute}}
+void to_foo6(int) __attribute__((enable_if(1, ""), overloadable));
+
+void to_foo7(int) __attribute__((enable_if(1, ""))); // expected-note{{previous unmarked overload}}
+void to_foo7(int) __attribute__((enable_if(1, ""), overloadable)); // expected-error{{must not have the 'overloadable' attribute}}
+void to_foo7(int) __attribute__((enable_if(1, "")));
+
+void to_foo8(char *__attribute__((pass_object_size(0))))
+ __attribute__((enable_if(1, "")));
+void to_foo8(char *__attribute__((pass_object_size(0))))
+ __attribute__((overloadable));
+
+void to_foo9(int); // expected-note{{previous unmarked overload}}
+// FIXME: It would be nice if we did better with the "previous unmarked
+// overload" diag.
+void to_foo9(int) __attribute__((overloadable)); // expected-error{{must not have the 'overloadable' attribute}} expected-note{{previous declaration}} expected-note{{previous unmarked overload}}
+void to_foo9(float); // expected-error{{conflicting types for 'to_foo9'}}
+void to_foo9(float) __attribute__((overloadable));
+void to_foo9(double); // expected-error{{at most one overload for a given name may lack the 'overloadable' attribute}}
+void to_foo9(double) __attribute__((overloadable));
+
+void to_foo10(int) __attribute__((overloadable));
+void to_foo10(double); // expected-note{{previous unmarked overload}}
+// no "note: previous redecl" if no previous decl has `overloadable`
+// spelled out
+void to_foo10(float); // expected-error{{at most one overload for a given name may lack the 'overloadable' attribute}}
+void to_foo10(float); // expected-error{{must have the 'overloadable' attribute}}
+void to_foo10(float); // expected-error{{must have the 'overloadable' attribute}}
+
+// Bug: we used to treat `__typeof__(foo)` as though it was `__typeof__(&foo)`
+// if `foo` was overloaded with only one function that could have its address
+// taken.
+void typeof_function_is_not_a_pointer() {
+ void not_a_pointer(void *) __attribute__((overloadable));
+ void not_a_pointer(char *__attribute__((pass_object_size(1))))
+ __attribute__((overloadable));
+
+ __typeof__(not_a_pointer) *fn;
+
+ void take_fn(void (*)(void *));
+ // if take_fn is passed a void (**)(void *), we'll get a warning.
+ take_fn(fn);
}
diff --git a/test/Sema/pointer-addition.c b/test/Sema/pointer-addition.c
index c71e96114b..562f05340f 100644
--- a/test/Sema/pointer-addition.c
+++ b/test/Sema/pointer-addition.c
@@ -1,4 +1,8 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -std=c11
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -std=c11
+// RUN: %clang_cc1 %s -fsyntax-only -triple i686-unknown-unknown -verify -pedantic -Wextra -std=c11
+// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify -pedantic -Wextra -std=c11
+
+#include <stdint.h>
typedef struct S S; // expected-note 4 {{forward declaration of 'struct S'}}
extern _Atomic(S*) e;
@@ -20,4 +24,9 @@ void a(S* b, void* c) {
d -= 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}}
(void)(1 + d); // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' (aka 'void (struct S *, void *)') is a GNU extension}}
e++; // expected-error {{arithmetic on a pointer to an incomplete type}}
+ intptr_t i = (intptr_t)b;
+ char *f = (char*)0 + i; // expected-warning {{arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension}}
+ // Cases that don't match the GNU inttoptr idiom get a different warning.
+ f = (char*)0 - i; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}}
+ int *g = (int*)0 + i; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior}}
}
diff --git a/test/Sema/pragma-attribute-strict-subjects.c b/test/Sema/pragma-attribute-strict-subjects.c
new file mode 100644
index 0000000000..a84e2bde38
--- /dev/null
+++ b/test/Sema/pragma-attribute-strict-subjects.c
@@ -0,0 +1,153 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-pragmas -verify %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(function, variable))
+
+#pragma clang attribute pop
+
+// Check for contradictions in rules for attribute without a strict subject set:
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global)))
+// expected-error@-1 {{redundant attribute subject matcher sub-rule 'variable(is_parameter)'; 'variable' already matches those declarations}}
+// expected-error@-2 {{redundant attribute subject matcher sub-rule 'variable(is_global)'; 'variable' already matches those declarations}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions2"))), apply_to = any(function(is_member), function))
+// expected-error@-1 {{redundant attribute subject matcher sub-rule 'function(is_member)'; 'function' already matches those declarations}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions3"))), apply_to = any(variable, variable(unless(is_parameter))))
+// expected-error@-1 {{redundant attribute subject matcher sub-rule 'variable(unless(is_parameter))'; 'variable' already matches those declarations}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions1"))), apply_to = any(variable(is_parameter), variable(unless(is_parameter))))
+// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_parameter)'}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global)))
+// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_global)'}}
+// We have just one error, don't error on 'variable(is_global)'
+
+#pragma clang attribute pop
+
+// Verify the strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable, record(unless(is_union))))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union)), function))
+// No error
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), variable, enum))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(enum_constant, function, record(unless(is_union)), variable, variable(is_parameter)))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'variable(is_parameter)', and 'enum_constant'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), enum))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+#pragma clang attribute pop
+
+// Verify the non-strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = variable)
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union))))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union))))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function))
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+
+#pragma clang attribute pop
+
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable, enum, enum_constant))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum_constant', and 'enum'}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = enum)
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+#pragma clang attribute pop
+
+// Handle attributes whose subjects are supported only in other language modes:
+
+#pragma clang attribute push(__attribute__((abi_tag("b"))), apply_to = any(namespace, record(unless(is_union)), variable, function))
+// 'namespace' is accepted!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((abi_tag("b"))), apply_to = any(namespace))
+// 'namespace' is accepted!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = objc_interface)
+// No error!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = objc_interface)
+// No error!
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_interface, objc_protocol))
+// expected-error@-1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_protocol))
+// expected-error@-1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+// Don't report an error about missing 'objc_interface' as we aren't parsing
+// Objective-C.
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_interface, objc_protocol))
+// expected-error@-1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+#pragma clang attribute pop
+
+#pragma clang attribute push(__attribute__((objc_subclassing_restricted)), apply_to = any(objc_protocol))
+// expected-error@-1 {{attribute 'objc_subclassing_restricted' can't be applied to 'objc_protocol'}}
+// Don't report an error about missing 'objc_interface' as we aren't parsing
+// Objective-C.
+#pragma clang attribute pop
+
+// Use of matchers from other language modes should not cause for attributes
+// without subject list:
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = objc_method)
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(objc_interface, objc_protocol))
+
+#pragma clang attribute pop
diff --git a/test/Sema/pragma-attribute.c b/test/Sema/pragma-attribute.c
new file mode 100644
index 0000000000..d321f2ce4b
--- /dev/null
+++ b/test/Sema/pragma-attribute.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#pragma clang attribute pop // expected-error {{'#pragma clang attribute pop' with no matching '#pragma clang attribute push'}}
+
+// Don't verify unused attributes.
+#pragma clang attribute push (__attribute__((annotate)), apply_to = function) // expected-warning {{unused attribute 'annotate' in '#pragma clang attribute push' region}}
+#pragma clang attribute pop // expected-note {{'#pragma clang attribute push' regions ends here}}
+
+// Ensure we only report any errors once.
+#pragma clang attribute push (__attribute__((annotate)), apply_to = function) // expected-error 4 {{'annotate' attribute takes one argument}}
+
+void test5_begin(); // expected-note {{when applied to this declaration}}
+void test5_1(); // expected-note {{when applied to this declaration}}
+
+#pragma clang attribute push (__attribute__((annotate())), apply_to = function) // expected-error 2 {{'annotate' attribute takes one argument}}
+
+void test5_2(); // expected-note 2 {{when applied to this declaration}}
+
+#pragma clang attribute push (__attribute__((annotate("hello", "world"))), apply_to = function) // expected-error {{'annotate' attribute takes one argument}}
+
+void test5_3(); // expected-note 3 {{when applied to this declaration}}
+
+#pragma clang attribute pop
+#pragma clang attribute pop
+#pragma clang attribute pop
+
+// Verify that the warnings are reported for each receiver declaration
+
+#pragma clang attribute push (__attribute__((optnone)), apply_to = function) // expected-note 2 {{conflicting attribute is here}}
+
+__attribute__((always_inline)) void optnone1() { } // expected-warning {{'always_inline' attribute ignored}}
+// expected-note@-1 {{when applied to this declaration}}
+
+void optnone2() { }
+
+__attribute__((always_inline)) void optnone3() { } // expected-warning {{'always_inline' attribute ignored}}
+// expected-note@-1 {{when applied to this declaration}}
+
+#pragma clang attribute pop
+
+#pragma clang attribute push ([[]], apply_to = function) // A noop
+
+#pragma clang attribute pop // expected-error {{'#pragma clang attribute pop' with no matching '#pragma clang attribute push'}}
+
+#pragma clang attribute push (__attribute__((annotate("func"))), apply_to = function) // expected-error {{unterminated '#pragma clang attribute push' at end of file}}
+
+void function();
diff --git a/test/Sema/pragma-clang-section.c b/test/Sema/pragma-clang-section.c
new file mode 100644
index 0000000000..49463889d3
--- /dev/null
+++ b/test/Sema/pragma-clang-section.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm-none-eabi
+#pragma clang section bss="mybss.1" data="mydata.1" rodata="myrodata.1" text="mytext.1"
+#pragma clang section bss="" data="" rodata="" text=""
+#pragma clang section
+
+#pragma clang section dss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}}
+#pragma clang section deta="mydata.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}}
+#pragma clang section rodeta="rodata.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}}
+#pragma clang section taxt="text.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}}
+
+#pragma clang section section bss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}}
+
+#pragma clang section bss "mybss.2" // expected-error {{expected '=' following '#pragma clang section bss'}}
+#pragma clang section data "mydata.2" // expected-error {{expected '=' following '#pragma clang section data'}}
+#pragma clang section rodata "myrodata.2" // expected-error {{expected '=' following '#pragma clang section rodata'}}
+#pragma clang section bss="" data="" rodata="" text="" more //expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}}
+int a;
diff --git a/test/Sema/pragma-pack.c b/test/Sema/pragma-pack.c
index e93ce42148..2ed0874bfd 100644
--- a/test/Sema/pragma-pack.c
+++ b/test/Sema/pragma-pack.c
@@ -25,3 +25,8 @@
#pragma pack(pop, 16)
/* expected-warning {{value of #pragma pack(show) == 16}} */ #pragma pack(show)
+
+// Warn about unbalanced pushes.
+#pragma pack (push,4) // expected-warning {{unterminated '#pragma pack (push, ...)' at end of file}}
+#pragma pack (push) // expected-warning {{unterminated '#pragma pack (push, ...)' at end of file}}
+#pragma pack () // expected-note {{did you intend to use '#pragma pack (pop)' instead of '#pragma pack()'?}}
diff --git a/test/Sema/preserve-call-conv.c b/test/Sema/preserve-call-conv.c
index f258f45ac5..6bd049ffdc 100644
--- a/test/Sema/preserve-call-conv.c
+++ b/test/Sema/preserve-call-conv.c
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify
// RUN: %clang_cc1 %s -fsyntax-only -triple arm64-unknown-unknown -verify
+// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-windows-msvc -verify
+// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-unknown-windows-msvc -verify
+
typedef void typedef_fun_t(int);
void __attribute__((preserve_most)) foo(void *ptr) {
diff --git a/test/Sema/redefinition-same-header.c b/test/Sema/redefinition-same-header.c
new file mode 100644
index 0000000000..be5bd1d71c
--- /dev/null
+++ b/test/Sema/redefinition-same-header.c
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: echo 'int yyy = 42;' > %t/a.h
+// RUN: %clang_cc1 -fsyntax-only %s -I%t -verify
+
+// expected-error@a.h:1 {{redefinition of 'yyy'}}
+// expected-note@a.h:1 {{unguarded header; consider using #ifdef guards or #pragma once}}
+// expected-note-re@redefinition-same-header.c:11 {{'{{.*}}a.h' included multiple times, additional include site here}}
+// expected-note-re@redefinition-same-header.c:12 {{'{{.*}}a.h' included multiple times, additional include site here}}
+
+#include "a.h"
+#include "a.h"
+
+int foo() { return yyy; }
diff --git a/test/Sema/sign-compare-enum.c b/test/Sema/sign-compare-enum.c
new file mode 100644
index 0000000000..8661bd502f
--- /dev/null
+++ b/test/Sema/sign-compare-enum.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify -Wsign-compare %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify -Wsign-compare %s
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -verify %s
+
+int main() {
+ enum A { A_a = 0, A_b = 1 };
+ static const int message[] = {0, 1};
+ enum A a;
+
+ if (a < 2)
+ return 0;
+
+#if defined(SIGNED) && !defined(SILENCE)
+ if (a < sizeof(message)/sizeof(message[0])) // expected-warning {{comparison of integers of different signs: 'enum A' and 'unsigned long long'}}
+ return 0;
+#else
+ // expected-no-diagnostics
+ if (a < 2U)
+ return 0;
+ if (a < sizeof(message)/sizeof(message[0]))
+ return 0;
+#endif
+}
diff --git a/test/Sema/sizeof-struct-non-zero-as-member.cl b/test/Sema/sizeof-struct-non-zero-as-member.cl
index 0e13c61503..ecc545b4d8 100644
--- a/test/Sema/sizeof-struct-non-zero-as-member.cl
+++ b/test/Sema/sizeof-struct-non-zero-as-member.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -fsyntax-only -triple amdgcn -target-cpu verde -S -emit-llvm -o - %s
+// RUN: %clang_cc1 -verify -fsyntax-only -triple amdgcn--opencl -target-cpu verde -S -emit-llvm -o - %s
// expected-no-diagnostics
// Record lowering was crashing on SI and newer targets, because it
diff --git a/test/Sema/struct-packed-align.c b/test/Sema/struct-packed-align.c
index abdcd8e6b9..aeba8d6fd9 100644
--- a/test/Sema/struct-packed-align.c
+++ b/test/Sema/struct-packed-align.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
// RUN: %clang_cc1 %s -fsyntax-only -triple=x86_64-windows-coff -verify
+// RUN: %clang_cc1 %s -fsyntax-only -triple=x86_64-scei-ps4 -verify
// Packed structs.
struct s {
@@ -146,13 +147,24 @@ extern int n2[__alignof(struct nS) == 1 ? 1 : -1];
// See the documentation of -Wpacked-bitfield-compat for more information.
struct packed_chars {
char a:4;
+#ifdef __ORBIS__
+ // Test for pre-r254596 clang behavior on the PS4 target. PS4 must maintain
+ // ABI backwards compatibility.
+ char b:8 __attribute__ ((packed));
+ // expected-warning@-1 {{'packed' attribute ignored for field of type 'char'}}
+ char c:4;
+#else
char b:8 __attribute__ ((packed));
// expected-warning@-1 {{'packed' attribute was ignored on bit-fields with single-byte alignment in older versions of GCC and Clang}}
char c:4;
+#endif
};
-#if defined(_WIN32) && !defined(__declspec) // _MSC_VER is unavailable in cc1.
+#if (defined(_WIN32) || defined(__ORBIS__)) && !defined(__declspec) // _MSC_VER is unavailable in cc1.
// On Windows clang uses MSVC compatible layout in this case.
+//
+// Additionally, test for pre-r254596 clang behavior on the PS4 target. PS4
+// must maintain ABI backwards compatibility.
extern int o1[sizeof(struct packed_chars) == 3 ? 1 : -1];
extern int o2[__alignof(struct packed_chars) == 1 ? 1 : -1];
#else
diff --git a/test/Sema/suspicious-pragma-pack.c b/test/Sema/suspicious-pragma-pack.c
new file mode 100644
index 0000000000..d7c5faf069
--- /dev/null
+++ b/test/Sema/suspicious-pragma-pack.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DSAFE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DSAFE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DRESET_HERE -DSAFE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DSET_FIRST_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DRESET_HERE -DSET_FIRST_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -DSET_FIRST_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -DSET_SECOND_HEADER -DWARN_MODIFIED_HEADER -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_HERE -DPUSH_SET_HERE -DSET_FIRST_HEADER -DSET_SECOND_HEADER -DWARN_MODIFIED_HEADER -verify %s
+
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_POP_FIRST_HEADER -DSAFE -verify %s
+
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -I %S/Inputs -DPUSH_SET_HERE -DNO_RECORD_1 -DNO_RECORD_2 -DSAFE -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack-suspicious-include -I %S/Inputs -DPUSH_SET_HERE -DNO_RECORD_1 -verify %s
+// RUN: %clang_cc1 -triple i686-apple-darwin9 -fsyntax-only -Wpragma-pack -Wno-pragma-pack-suspicious-include -I %S/Inputs -DPUSH_SET_HERE -DNO_RECORD_1 -DSAFE -verify %s
+
+#ifdef SAFE
+// expected-no-diagnostics
+#endif
+
+#ifdef PUSH_HERE
+#pragma pack (push)
+#endif
+
+#ifdef PUSH_SET_HERE
+#pragma pack (push, 4)
+#ifndef SAFE
+// expected-note@-2 {{previous '#pragma pack' directive that modifies alignment is here}}
+// expected-warning@+9 {{non-default #pragma pack value changes the alignment of struct or union members in the included file}}
+#endif
+#endif
+
+#ifdef RESET_HERE
+#pragma pack (4)
+#pragma pack () // no warning after reset as the value is default.
+#endif
+
+#include "pragma-pack1.h"
+
+#ifdef WARN_MODIFIED_HEADER
+// expected-warning@-3 {{the current #pragma pack aligment value is modified in the included file}}
+#endif
+
+#ifdef PUSH_SET_HERE
+#pragma pack (pop)
+#endif
+
+#ifdef PUSH_HERE
+#pragma pack (pop)
+#endif
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
index 7aa695d7cb..a33300b41f 100644
--- a/test/Sema/switch.c
+++ b/test/Sema/switch.c
@@ -372,6 +372,7 @@ void switch_on_ExtendedEnum1(enum ExtendedEnum1 e) {
case EE1_b: break;
case EE1_c: break; // no-warning
case EE1_d: break; // expected-warning {{case value not in enumerated type 'enum ExtendedEnum1'}}
+ // expected-warning@-1 {{comparison of two values with different enumeration types in switch statement ('enum ExtendedEnum1' and 'const enum ExtendedEnum1_unrelated')}}
}
}
diff --git a/test/Sema/tautological-constant-compare.c b/test/Sema/tautological-constant-compare.c
new file mode 100644
index 0000000000..b9ade2a2db
--- /dev/null
+++ b/test/Sema/tautological-constant-compare.c
@@ -0,0 +1,514 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DTEST -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DTEST -verify -x c++ %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify -x c++ %s
+
+int value(void);
+
+#define macro(val) val
+
+#ifdef __cplusplus
+template<typename T>
+void TFunc() {
+ // Make sure that we do warn for normal variables in template functions !
+ unsigned char c = value();
+#ifdef TEST
+ if (c > 255) // expected-warning {{comparison 'unsigned char' > 255 is always false}}
+ return;
+#else
+ if (c > 255)
+ return;
+#endif
+
+ if (c > macro(255))
+ return;
+
+ T v = value();
+ if (v > 255)
+ return;
+ if (v > 32767)
+ return;
+}
+#endif
+
+int main()
+{
+#ifdef __cplusplus
+ TFunc<unsigned char>();
+ TFunc<signed short>();
+#endif
+
+ short s = value();
+
+#ifdef TEST
+ if (s == 32767)
+ return 0;
+ if (s != 32767)
+ return 0;
+ if (s < 32767)
+ return 0;
+ if (s <= 32767) // expected-warning {{comparison 'short' <= 32767 is always true}}
+ return 0;
+ if (s > 32767) // expected-warning {{comparison 'short' > 32767 is always false}}
+ return 0;
+ if (s >= 32767)
+ return 0;
+
+ if (32767 == s)
+ return 0;
+ if (32767 != s)
+ return 0;
+ if (32767 < s) // expected-warning {{comparison 32767 < 'short' is always false}}
+ return 0;
+ if (32767 <= s)
+ return 0;
+ if (32767 > s)
+ return 0;
+ if (32767 >= s) // expected-warning {{comparison 32767 >= 'short' is always true}}
+ return 0;
+
+ // FIXME: assumes two's complement
+ if (s == -32768)
+ return 0;
+ if (s != -32768)
+ return 0;
+ if (s < -32768) // expected-warning {{comparison 'short' < -32768 is always false}}
+ return 0;
+ if (s <= -32768)
+ return 0;
+ if (s > -32768)
+ return 0;
+ if (s >= -32768) // expected-warning {{comparison 'short' >= -32768 is always true}}
+ return 0;
+
+ if (-32768 == s)
+ return 0;
+ if (-32768 != s)
+ return 0;
+ if (-32768 < s)
+ return 0;
+ if (-32768 <= s) // expected-warning {{comparison -32768 <= 'short' is always true}}
+ return 0;
+ if (-32768 > s) // expected-warning {{comparison -32768 > 'short' is always false}}
+ return 0;
+ if (-32768 >= s)
+ return 0;
+
+ if (s == 32767UL)
+ return 0;
+ if (s != 32767UL)
+ return 0;
+ if (s < 32767UL)
+ return 0;
+ if (s <= 32767UL) // expected-warning {{comparison 'short' <= 32767 is always true}}
+ return 0;
+ if (s > 32767UL) // expected-warning {{comparison 'short' > 32767 is always false}}
+ return 0;
+ if (s >= 32767UL)
+ return 0;
+
+ if (32767UL == s)
+ return 0;
+ if (32767UL != s)
+ return 0;
+ if (32767UL < s) // expected-warning {{comparison 32767 < 'short' is always false}}
+ return 0;
+ if (32767UL <= s)
+ return 0;
+ if (32767UL > s)
+ return 0;
+ if (32767UL >= s) // expected-warning {{comparison 32767 >= 'short' is always true}}
+ return 0;
+
+ // FIXME: assumes two's complement
+ if (s == -32768L)
+ return 0;
+ if (s != -32768L)
+ return 0;
+ if (s < -32768L) // expected-warning {{comparison 'short' < -32768 is always false}}
+ return 0;
+ if (s <= -32768L)
+ return 0;
+ if (s > -32768L)
+ return 0;
+ if (s >= -32768L) // expected-warning {{comparison 'short' >= -32768 is always true}}
+ return 0;
+
+ if (-32768L == s)
+ return 0;
+ if (-32768L != s)
+ return 0;
+ if (-32768L < s)
+ return 0;
+ if (-32768L <= s) // expected-warning {{comparison -32768 <= 'short' is always true}}
+ return 0;
+ if (-32768L > s) // expected-warning {{comparison -32768 > 'short' is always false}}
+ return 0;
+ if (-32768L >= s)
+ return 0;
+#else
+ // expected-no-diagnostics
+ if (s == 32767)
+ return 0;
+ if (s != 32767)
+ return 0;
+ if (s < 32767)
+ return 0;
+ if (s <= 32767)
+ return 0;
+ if (s > 32767)
+ return 0;
+ if (s >= 32767)
+ return 0;
+
+ if (32767 == s)
+ return 0;
+ if (32767 != s)
+ return 0;
+ if (32767 < s)
+ return 0;
+ if (32767 <= s)
+ return 0;
+ if (32767 > s)
+ return 0;
+ if (32767 >= s)
+ return 0;
+
+ // FIXME: assumes two's complement
+ if (s == -32768)
+ return 0;
+ if (s != -32768)
+ return 0;
+ if (s < -32768)
+ return 0;
+ if (s <= -32768)
+ return 0;
+ if (s > -32768)
+ return 0;
+ if (s >= -32768)
+ return 0;
+
+ if (-32768 == s)
+ return 0;
+ if (-32768 != s)
+ return 0;
+ if (-32768 < s)
+ return 0;
+ if (-32768 <= s)
+ return 0;
+ if (-32768 > s)
+ return 0;
+ if (-32768 >= s)
+ return 0;
+
+ if (s == 32767UL)
+ return 0;
+ if (s != 32767UL)
+ return 0;
+ if (s < 32767UL)
+ return 0;
+ if (s <= 32767UL)
+ return 0;
+ if (s > 32767UL)
+ return 0;
+ if (s >= 32767UL)
+ return 0;
+
+ if (32767UL == s)
+ return 0;
+ if (32767UL != s)
+ return 0;
+ if (32767UL < s)
+ return 0;
+ if (32767UL <= s)
+ return 0;
+ if (32767UL > s)
+ return 0;
+ if (32767UL >= s)
+ return 0;
+
+ // FIXME: assumes two's complement
+ if (s == -32768L)
+ return 0;
+ if (s != -32768L)
+ return 0;
+ if (s < -32768L)
+ return 0;
+ if (s <= -32768L)
+ return 0;
+ if (s > -32768L)
+ return 0;
+ if (s >= -32768L)
+ return 0;
+
+ if (-32768L == s)
+ return 0;
+ if (-32768L != s)
+ return 0;
+ if (-32768L < s)
+ return 0;
+ if (-32768L <= s)
+ return 0;
+ if (-32768L > s)
+ return 0;
+ if (-32768L >= s)
+ return 0;
+#endif
+
+ if (s == 0)
+ return 0;
+ if (s != 0)
+ return 0;
+ if (s < 0)
+ return 0;
+ if (s <= 0)
+ return 0;
+ if (s > 0)
+ return 0;
+ if (s >= 0)
+ return 0;
+
+ if (0 == s)
+ return 0;
+ if (0 != s)
+ return 0;
+ if (0 < s)
+ return 0;
+ if (0 <= s)
+ return 0;
+ if (0 > s)
+ return 0;
+ if (0 >= s)
+ return 0;
+
+ // However the comparison with 0U would warn
+
+ unsigned short us = value();
+
+#ifdef TEST
+ if (us == 65535)
+ return 0;
+ if (us != 65535)
+ return 0;
+ if (us < 65535)
+ return 0;
+ if (us <= 65535) // expected-warning {{comparison 'unsigned short' <= 65535 is always true}}
+ return 0;
+ if (us > 65535) // expected-warning {{comparison 'unsigned short' > 65535 is always false}}
+ return 0;
+ if (us >= 65535)
+ return 0;
+
+ if (65535 == us)
+ return 0;
+ if (65535 != us)
+ return 0;
+ if (65535 < us) // expected-warning {{comparison 65535 < 'unsigned short' is always false}}
+ return 0;
+ if (65535 <= us)
+ return 0;
+ if (65535 > us)
+ return 0;
+ if (65535 >= us) // expected-warning {{comparison 65535 >= 'unsigned short' is always true}}
+ return 0;
+
+ if (us == 65535UL)
+ return 0;
+ if (us != 65535UL)
+ return 0;
+ if (us < 65535UL)
+ return 0;
+ if (us <= 65535UL) // expected-warning {{comparison 'unsigned short' <= 65535 is always true}}
+ return 0;
+ if (us > 65535UL) // expected-warning {{comparison 'unsigned short' > 65535 is always false}}
+ return 0;
+ if (us >= 65535UL)
+ return 0;
+
+ if (65535UL == us)
+ return 0;
+ if (65535UL != us)
+ return 0;
+ if (65535UL < us) // expected-warning {{comparison 65535 < 'unsigned short' is always false}}
+ return 0;
+ if (65535UL <= us)
+ return 0;
+ if (65535UL > us)
+ return 0;
+ if (65535UL >= us) // expected-warning {{comparison 65535 >= 'unsigned short' is always true}}
+ return 0;
+#else
+ // expected-no-diagnostics
+ if (us == 65535)
+ return 0;
+ if (us != 65535)
+ return 0;
+ if (us < 65535)
+ return 0;
+ if (us <= 65535)
+ return 0;
+ if (us > 65535)
+ return 0;
+ if (us >= 65535)
+ return 0;
+
+ if (65535 == us)
+ return 0;
+ if (65535 != us)
+ return 0;
+ if (65535 < us)
+ return 0;
+ if (65535 <= us)
+ return 0;
+ if (65535 > us)
+ return 0;
+ if (65535 >= us)
+ return 0;
+
+ if (us == 65535UL)
+ return 0;
+ if (us != 65535UL)
+ return 0;
+ if (us < 65535UL)
+ return 0;
+ if (us <= 65535UL)
+ return 0;
+ if (us > 65535UL)
+ return 0;
+ if (us >= 65535UL)
+ return 0;
+
+ if (65535UL == us)
+ return 0;
+ if (65535UL != us)
+ return 0;
+ if (65535UL < us)
+ return 0;
+ if (65535UL <= us)
+ return 0;
+ if (65535UL > us)
+ return 0;
+ if (65535UL >= us)
+ return 0;
+#endif
+
+ if (us == 32767)
+ return 0;
+ if (us != 32767)
+ return 0;
+ if (us < 32767)
+ return 0;
+ if (us <= 32767)
+ return 0;
+ if (us > 32767)
+ return 0;
+ if (us >= 32767)
+ return 0;
+
+ if (32767 == us)
+ return 0;
+ if (32767 != us)
+ return 0;
+ if (32767 < us)
+ return 0;
+ if (32767 <= us)
+ return 0;
+ if (32767 > us)
+ return 0;
+ if (32767 >= us)
+ return 0;
+
+ if (us == 32767UL)
+ return 0;
+ if (us != 32767UL)
+ return 0;
+ if (us < 32767UL)
+ return 0;
+ if (us <= 32767UL)
+ return 0;
+ if (us > 32767UL)
+ return 0;
+ if (us >= 32767UL)
+ return 0;
+
+ if (32767UL == us)
+ return 0;
+ if (32767UL != us)
+ return 0;
+ if (32767UL < us)
+ return 0;
+ if (32767UL <= us)
+ return 0;
+ if (32767UL > us)
+ return 0;
+ if (32767UL >= us)
+ return 0;
+
+#if __SIZEOF_INT128__
+ __int128 i128;
+ if (i128 == -1) // used to crash
+ return 0;
+#endif
+
+
+ enum E {
+ yes,
+ no,
+ maybe
+ };
+ enum E e;
+
+ if (e == yes)
+ return 0;
+ if (e != yes)
+ return 0;
+ if (e < yes)
+ return 0;
+ if (e <= yes)
+ return 0;
+ if (e > yes)
+ return 0;
+ if (e >= yes)
+ return 0;
+
+ if (yes == e)
+ return 0;
+ if (yes != e)
+ return 0;
+ if (yes < e)
+ return 0;
+ if (yes <= e)
+ return 0;
+ if (yes > e)
+ return 0;
+ if (yes >= e)
+ return 0;
+
+ if (e == maybe)
+ return 0;
+ if (e != maybe)
+ return 0;
+ if (e < maybe)
+ return 0;
+ if (e <= maybe)
+ return 0;
+ if (e > maybe)
+ return 0;
+ if (e >= maybe)
+ return 0;
+
+ if (maybe == e)
+ return 0;
+ if (maybe != e)
+ return 0;
+ if (maybe < e)
+ return 0;
+ if (maybe <= e)
+ return 0;
+ if (maybe > e)
+ return 0;
+ if (maybe >= e)
+ return 0;
+
+ return 1;
+}
diff --git a/test/Sema/tautological-constant-enum-compare.c b/test/Sema/tautological-constant-enum-compare.c
new file mode 100644
index 0000000000..1f09865f13
--- /dev/null
+++ b/test/Sema/tautological-constant-enum-compare.c
@@ -0,0 +1,419 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s
+
+int main() {
+ enum A { A_a = 2 };
+ enum A a;
+
+#ifdef SILENCE
+ // expected-no-diagnostics
+#endif
+
+#ifdef UNSIGNED
+#ifndef SILENCE
+ if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0 >= a)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0 < a)
+ return 0;
+
+ if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (a < 4294967295)
+ return 0;
+ if (4294967295 >= a) // expected-warning {{comparison 4294967295 >= 'enum A' is always true}}
+ return 0;
+ if (a > 4294967295) // expected-warning {{comparison 'enum A' > 4294967295 is always false}}
+ return 0;
+ if (4294967295 <= a)
+ return 0;
+ if (a <= 4294967295) // expected-warning {{comparison 'enum A' <= 4294967295 is always true}}
+ return 0;
+ if (4294967295 > a)
+ return 0;
+ if (a >= 4294967295)
+ return 0;
+ if (4294967295 < a) // expected-warning {{comparison 4294967295 < 'enum A' is always false}}
+ return 0;
+
+ if (a < 4294967295U)
+ return 0;
+ if (4294967295U >= a) // expected-warning {{comparison 4294967295 >= 'enum A' is always true}}
+ return 0;
+ if (a > 4294967295U) // expected-warning {{comparison 'enum A' > 4294967295 is always false}}
+ return 0;
+ if (4294967295U <= a)
+ return 0;
+ if (a <= 4294967295U) // expected-warning {{comparison 'enum A' <= 4294967295 is always true}}
+ return 0;
+ if (4294967295U > a)
+ return 0;
+ if (a >= 4294967295U)
+ return 0;
+ if (4294967295U < a) // expected-warning {{comparison 4294967295 < 'enum A' is always false}}
+ return 0;
+#else // SILENCE
+ if (a < 0)
+ return 0;
+ if (0 >= a)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (0 <= a)
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (0 > a)
+ return 0;
+ if (a >= 0)
+ return 0;
+ if (0 < a)
+ return 0;
+
+ if (a < 0U)
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a)
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a)
+ return 0;
+ if (a >= 0U)
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (a < 4294967295)
+ return 0;
+ if (4294967295 >= a)
+ return 0;
+ if (a > 4294967295)
+ return 0;
+ if (4294967295 <= a)
+ return 0;
+ if (a <= 4294967295)
+ return 0;
+ if (4294967295 > a)
+ return 0;
+ if (a >= 4294967295)
+ return 0;
+ if (4294967295 < a)
+ return 0;
+
+ if (a < 4294967295U)
+ return 0;
+ if (4294967295U >= a)
+ return 0;
+ if (a > 4294967295U)
+ return 0;
+ if (4294967295U <= a)
+ return 0;
+ if (a <= 4294967295U)
+ return 0;
+ if (4294967295U > a)
+ return 0;
+ if (a >= 4294967295U)
+ return 0;
+ if (4294967295U < a)
+ return 0;
+#endif
+#elif defined(SIGNED)
+#ifndef SILENCE
+ if (a < -2147483648) // expected-warning {{comparison 'enum A' < -2147483648 is always false}}
+ return 0;
+ if (-2147483648 >= a)
+ return 0;
+ if (a > -2147483648)
+ return 0;
+ if (-2147483648 <= a) // expected-warning {{comparison -2147483648 <= 'enum A' is always true}}
+ return 0;
+ if (a <= -2147483648)
+ return 0;
+ if (-2147483648 > a) // expected-warning {{comparison -2147483648 > 'enum A' is always false}}
+ return 0;
+ if (a >= -2147483648) // expected-warning {{comparison 'enum A' >= -2147483648 is always true}}
+ return 0;
+ if (-2147483648 < a)
+ return 0;
+
+ if (a < 2147483647)
+ return 0;
+ if (2147483647 >= a) // expected-warning {{comparison 2147483647 >= 'enum A' is always true}}
+ return 0;
+ if (a > 2147483647) // expected-warning {{comparison 'enum A' > 2147483647 is always false}}
+ return 0;
+ if (2147483647 <= a)
+ return 0;
+ if (a <= 2147483647) // expected-warning {{comparison 'enum A' <= 2147483647 is always true}}
+ return 0;
+ if (2147483647 > a)
+ return 0;
+ if (a >= 2147483647)
+ return 0;
+ if (2147483647 < a) // expected-warning {{comparison 2147483647 < 'enum A' is always false}}
+ return 0;
+
+ if (a < 2147483647U)
+ return 0;
+ if (2147483647U >= a) // expected-warning {{comparison 2147483647 >= 'enum A' is always true}}
+ return 0;
+ if (a > 2147483647U) // expected-warning {{comparison 'enum A' > 2147483647 is always false}}
+ return 0;
+ if (2147483647U <= a)
+ return 0;
+ if (a <= 2147483647U) // expected-warning {{comparison 'enum A' <= 2147483647 is always true}}
+ return 0;
+ if (2147483647U > a)
+ return 0;
+ if (a >= 2147483647U)
+ return 0;
+ if (2147483647U < a) // expected-warning {{comparison 2147483647 < 'enum A' is always false}}
+ return 0;
+#else // SILENCE
+ if (a < -2147483648)
+ return 0;
+ if (-2147483648 >= a)
+ return 0;
+ if (a > -2147483648)
+ return 0;
+ if (-2147483648 <= a)
+ return 0;
+ if (a <= -2147483648)
+ return 0;
+ if (-2147483648 > a)
+ return 0;
+ if (a >= -2147483648)
+ return 0;
+ if (-2147483648 < a)
+ return 0;
+
+ if (a < 2147483647)
+ return 0;
+ if (2147483647 >= a)
+ return 0;
+ if (a > 2147483647)
+ return 0;
+ if (2147483647 <= a)
+ return 0;
+ if (a <= 2147483647)
+ return 0;
+ if (2147483647 > a)
+ return 0;
+ if (a >= 2147483647)
+ return 0;
+ if (2147483647 < a)
+ return 0;
+
+ if (a < 2147483647U)
+ return 0;
+ if (2147483647U >= a)
+ return 0;
+ if (a > 2147483647U)
+ return 0;
+ if (2147483647U <= a)
+ return 0;
+ if (a <= 2147483647U)
+ return 0;
+ if (2147483647U > a)
+ return 0;
+ if (a >= 2147483647U)
+ return 0;
+ if (2147483647U < a)
+ return 0;
+#endif
+#endif
+
+ return 1;
+}
+
+// https://bugs.llvm.org/show_bug.cgi?id=35009
+int PR35009() {
+ enum A { A_a = 2 };
+ enum A a;
+
+ // in C, this should not warn.
+
+ if (a < 1)
+ return 0;
+ if (1 >= a)
+ return 0;
+ if (a > 1)
+ return 0;
+ if (1 <= a)
+ return 0;
+ if (a <= 1)
+ return 0;
+ if (1 > a)
+ return 0;
+ if (a >= 1)
+ return 0;
+ if (1 < a)
+ return 0;
+ if (a == 1)
+ return 0;
+ if (1 != a)
+ return 0;
+ if (a != 1)
+ return 0;
+ if (1 == a)
+ return 0;
+
+ if (a < 1U)
+ return 0;
+ if (1U >= a)
+ return 0;
+ if (a > 1U)
+ return 0;
+ if (1U <= a)
+ return 0;
+ if (a <= 1U)
+ return 0;
+ if (1U > a)
+ return 0;
+ if (a >= 1U)
+ return 0;
+ if (1U < a)
+ return 0;
+ if (a == 1U)
+ return 0;
+ if (1U != a)
+ return 0;
+ if (a != 1U)
+ return 0;
+ if (1U == a)
+ return 0;
+
+ if (a < 2)
+ return 0;
+ if (2 >= a)
+ return 0;
+ if (a > 2)
+ return 0;
+ if (2 <= a)
+ return 0;
+ if (a <= 2)
+ return 0;
+ if (2 > a)
+ return 0;
+ if (a >= 2)
+ return 0;
+ if (2 < a)
+ return 0;
+ if (a == 2)
+ return 0;
+ if (2 != a)
+ return 0;
+ if (a != 2)
+ return 0;
+ if (2 == a)
+ return 0;
+
+ if (a < 2U)
+ return 0;
+ if (2U >= a)
+ return 0;
+ if (a > 2U)
+ return 0;
+ if (2U <= a)
+ return 0;
+ if (a <= 2U)
+ return 0;
+ if (2U > a)
+ return 0;
+ if (a >= 2U)
+ return 0;
+ if (2U < a)
+ return 0;
+ if (a == 2U)
+ return 0;
+ if (2U != a)
+ return 0;
+ if (a != 2U)
+ return 0;
+ if (2U == a)
+ return 0;
+
+ if (a < 3)
+ return 0;
+ if (3 >= a)
+ return 0;
+ if (a > 3)
+ return 0;
+ if (3 <= a)
+ return 0;
+ if (a <= 3)
+ return 0;
+ if (3 > a)
+ return 0;
+ if (a >= 3)
+ return 0;
+ if (3 < a)
+ return 0;
+ if (a == 3)
+ return 0;
+ if (3 != a)
+ return 0;
+ if (a != 3)
+ return 0;
+ if (3 == a)
+ return 0;
+
+ if (a < 3U)
+ return 0;
+ if (3U >= a)
+ return 0;
+ if (a > 3U)
+ return 0;
+ if (3U <= a)
+ return 0;
+ if (a <= 3U)
+ return 0;
+ if (3U > a)
+ return 0;
+ if (a >= 3U)
+ return 0;
+ if (3U < a)
+ return 0;
+ if (a == 3U)
+ return 0;
+ if (3U != a)
+ return 0;
+ if (a != 3U)
+ return 0;
+ if (3U == a)
+ return 0;
+
+ return 1;
+}
diff --git a/test/Sema/tautological-unsigned-enum-zero-compare.c b/test/Sema/tautological-unsigned-enum-zero-compare.c
new file mode 100644
index 0000000000..43b768433d
--- /dev/null
+++ b/test/Sema/tautological-unsigned-enum-zero-compare.c
@@ -0,0 +1,260 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s
+
+// Okay, this is where it gets complicated.
+// Then default enum sigdness is target-specific.
+// On windows, it is signed by default. We do not want to warn in that case.
+
+int main() {
+ enum A { A_a = 0 };
+ enum A a;
+ enum B { B_a = -1 };
+ enum B b;
+
+#ifdef UNSIGNED
+ if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0 >= a)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0 < a)
+ return 0;
+
+ if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (b < 0)
+ return 0;
+ if (0 >= b)
+ return 0;
+ if (b > 0)
+ return 0;
+ if (0 <= b)
+ return 0;
+ if (b <= 0)
+ return 0;
+ if (0 > b)
+ return 0;
+ if (b >= 0)
+ return 0;
+ if (0 < b)
+ return 0;
+
+ if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= b)
+ return 0;
+ if (b > 0U)
+ return 0;
+ if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (b <= 0U)
+ return 0;
+ if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < b)
+ return 0;
+#elif defined(SIGNED)
+ if (a < 0)
+ return 0;
+ if (0 >= a)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (0 <= a)
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (0 > a)
+ return 0;
+ if (a >= 0)
+ return 0;
+ if (0 < a)
+ return 0;
+
+ if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (b < 0)
+ return 0;
+ if (0 >= b)
+ return 0;
+ if (b > 0)
+ return 0;
+ if (0 <= b)
+ return 0;
+ if (b <= 0)
+ return 0;
+ if (0 > b)
+ return 0;
+ if (b >= 0)
+ return 0;
+ if (0 < b)
+ return 0;
+
+ if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= b)
+ return 0;
+ if (b > 0U)
+ return 0;
+ if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (b <= 0U)
+ return 0;
+ if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < b)
+ return 0;
+#else
+ // expected-no-diagnostics
+
+ if (a < 0)
+ return 0;
+ if (0 >= a)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (0 <= a)
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (0 > a)
+ return 0;
+ if (a >= 0)
+ return 0;
+ if (0 < a)
+ return 0;
+
+ if (a < 0U)
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a)
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a)
+ return 0;
+ if (a >= 0U)
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (b < 0)
+ return 0;
+ if (0 >= b)
+ return 0;
+ if (b > 0)
+ return 0;
+ if (0 <= b)
+ return 0;
+ if (b <= 0)
+ return 0;
+ if (0 > b)
+ return 0;
+ if (b >= 0)
+ return 0;
+ if (0 < b)
+ return 0;
+
+ if (b < 0U)
+ return 0;
+ if (0U >= b)
+ return 0;
+ if (b > 0U)
+ return 0;
+ if (0U <= b)
+ return 0;
+ if (b <= 0U)
+ return 0;
+ if (0U > b)
+ return 0;
+ if (b >= 0U)
+ return 0;
+ if (0U < b)
+ return 0;
+#endif
+
+ if (a == 0)
+ return 0;
+ if (0 != a)
+ return 0;
+ if (a != 0)
+ return 0;
+ if (0 == a)
+ return 0;
+
+ if (a == 0U)
+ return 0;
+ if (0U != a)
+ return 0;
+ if (a != 0U)
+ return 0;
+ if (0U == a)
+ return 0;
+
+ if (b == 0)
+ return 0;
+ if (0 != b)
+ return 0;
+ if (b != 0)
+ return 0;
+ if (0 == b)
+ return 0;
+
+ if (b == 0U)
+ return 0;
+ if (0U != b)
+ return 0;
+ if (b != 0U)
+ return 0;
+ if (0U == b)
+ return 0;
+
+ return 1;
+}
diff --git a/test/Sema/tautological-unsigned-enum-zero-compare.cpp b/test/Sema/tautological-unsigned-enum-zero-compare.cpp
new file mode 100644
index 0000000000..f8d4560ef2
--- /dev/null
+++ b/test/Sema/tautological-unsigned-enum-zero-compare.cpp
@@ -0,0 +1,347 @@
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSILENCE -Wno-tautological-unsigned-enum-zero-compare -verify %s
+
+// Okay, this is where it gets complicated.
+// Then default enum sigdness is target-specific.
+// On windows, it is signed by default. We do not want to warn in that case.
+
+int main() {
+ enum A { A_foo = 0, A_bar, };
+ enum A a;
+
+ enum B : unsigned { B_foo = 0, B_bar, };
+ enum B b;
+
+ enum C : signed { C_foo = 0, C_bar, };
+ enum C c;
+
+#ifdef UNSIGNED
+ if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0 >= a)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0 < a)
+ return 0;
+
+ if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0 >= b)
+ return 0;
+ if (b > 0)
+ return 0;
+ if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (b <= 0)
+ return 0;
+ if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0 < b)
+ return 0;
+
+ if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= b)
+ return 0;
+ if (b > 0U)
+ return 0;
+ if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (b <= 0U)
+ return 0;
+ if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < b)
+ return 0;
+
+ if (c < 0)
+ return 0;
+ if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}}
+ return 0;
+ if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}}
+ return 0;
+ if (0 <= c)
+ return 0;
+ if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}}
+ return 0;
+ if (0 > c)
+ return 0;
+ if (c >= 0)
+ return 0;
+ if (0 < c) // expected-warning {{0 < 'enum C' is always false}}
+ return 0;
+
+ if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= c)
+ return 0;
+ if (c > 0U)
+ return 0;
+ if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (c <= 0U)
+ return 0;
+ if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < c)
+ return 0;
+#elif defined(SIGNED)
+ if (a < 0)
+ return 0;
+ if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}}
+ return 0;
+ if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}}
+ return 0;
+ if (0 <= a)
+ return 0;
+ if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}}
+ return 0;
+ if (0 > a)
+ return 0;
+ if (a >= 0)
+ return 0;
+ if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}}
+ return 0;
+
+ if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0 >= b)
+ return 0;
+ if (b > 0)
+ return 0;
+ if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (b <= 0)
+ return 0;
+ if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0 < b)
+ return 0;
+
+ if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= b)
+ return 0;
+ if (b > 0U)
+ return 0;
+ if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (b <= 0U)
+ return 0;
+ if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < b)
+ return 0;
+
+ if (c < 0)
+ return 0;
+ if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}}
+ return 0;
+ if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}}
+ return 0;
+ if (0 <= c)
+ return 0;
+ if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}}
+ return 0;
+ if (0 > c)
+ return 0;
+ if (c >= 0)
+ return 0;
+ if (0 < c) // expected-warning {{0 < 'enum C' is always false}}
+ return 0;
+
+ if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+ return 0;
+ if (0U >= c)
+ return 0;
+ if (c > 0U)
+ return 0;
+ if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+ return 0;
+ if (c <= 0U)
+ return 0;
+ if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+ return 0;
+ if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+ return 0;
+ if (0U < c)
+ return 0;
+#else
+ if (a < 0)
+ return 0;
+ if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}}
+ return 0;
+ if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}}
+ return 0;
+ if (0 <= a)
+ return 0;
+ if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}}
+ return 0;
+ if (0 > a)
+ return 0;
+ if (a >= 0)
+ return 0;
+ if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}}
+ return 0;
+
+ if (a < 0U)
+ return 0;
+ if (0U >= a)
+ return 0;
+ if (a > 0U)
+ return 0;
+ if (0U <= a)
+ return 0;
+ if (a <= 0U)
+ return 0;
+ if (0U > a)
+ return 0;
+ if (a >= 0U)
+ return 0;
+ if (0U < a)
+ return 0;
+
+ if (b < 0)
+ return 0;
+ if (0 >= b)
+ return 0;
+ if (b > 0)
+ return 0;
+ if (0 <= b)
+ return 0;
+ if (b <= 0)
+ return 0;
+ if (0 > b)
+ return 0;
+ if (b >= 0)
+ return 0;
+ if (0 < b)
+ return 0;
+
+ if (b < 0U)
+ return 0;
+ if (0U >= b)
+ return 0;
+ if (b > 0U)
+ return 0;
+ if (0U <= b)
+ return 0;
+ if (b <= 0U)
+ return 0;
+ if (0U > b)
+ return 0;
+ if (b >= 0U)
+ return 0;
+ if (0U < b)
+ return 0;
+
+ if (c < 0)
+ return 0;
+ if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}}
+ return 0;
+ if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}}
+ return 0;
+ if (0 <= c)
+ return 0;
+ if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}}
+ return 0;
+ if (0 > c)
+ return 0;
+ if (c >= 0)
+ return 0;
+ if (0 < c) // expected-warning {{0 < 'enum C' is always false}}
+ return 0;
+
+ if (c < 0U)
+ return 0;
+ if (0U >= c)
+ return 0;
+ if (c > 0U)
+ return 0;
+ if (0U <= c)
+ return 0;
+ if (c <= 0U)
+ return 0;
+ if (0U > c)
+ return 0;
+ if (c >= 0U)
+ return 0;
+ if (0U < c)
+ return 0;
+#endif
+
+ return 1;
+}
+
+namespace crash_enum_zero_width {
+int test() {
+ enum A : unsigned {
+ A_foo = 0
+ };
+ enum A a;
+
+ // used to crash in llvm::APSInt::getMaxValue()
+#ifndef SILENCE
+ if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+#else
+ if (a > 0)
+#endif
+ return 0;
+
+ return 1;
+}
+} // namespace crash_enum_zero_width
diff --git a/test/Sema/tautological-unsigned-zero-compare.c b/test/Sema/tautological-unsigned-zero-compare.c
new file mode 100644
index 0000000000..e0611cb400
--- /dev/null
+++ b/test/Sema/tautological-unsigned-zero-compare.c
@@ -0,0 +1,370 @@
+// RUN: %clang_cc1 -fsyntax-only -DTEST -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify %s
+// RUN: %clang_cc1 -fsyntax-only -DTEST -verify -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify -x c++ %s
+
+unsigned uvalue(void);
+signed int svalue(void);
+
+#define macro(val) val
+
+#ifdef __cplusplus
+template<typename T>
+void TFunc() {
+ // Make sure that we do warn for normal variables in template functions !
+ unsigned char c = svalue();
+#ifdef TEST
+ if (c < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ return;
+#else
+ if (c < 0)
+ return;
+#endif
+
+ if (c < macro(0))
+ return;
+
+ T v = svalue();
+ if (v < 0)
+ return;
+}
+#endif
+
+int main()
+{
+#ifdef __cplusplus
+ TFunc<unsigned char>();
+ TFunc<unsigned short>();
+#endif
+
+ unsigned un = uvalue();
+
+#ifdef TEST
+ if (un == 0)
+ return 0;
+ if (un != 0)
+ return 0;
+ if (un < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ return 0;
+ if (un <= 0)
+ return 0;
+ if (un > 0)
+ return 0;
+ if (un >= 0) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
+ return 0;
+
+ if (0 == un)
+ return 0;
+ if (0 != un)
+ return 0;
+ if (0 < un)
+ return 0;
+ if (0 <= un) // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+ return 0;
+ if (0 > un) // expected-warning {{comparison of 0 > unsigned expression is always false}}
+ return 0;
+ if (0 >= un)
+ return 0;
+
+ if (un == 0UL)
+ return 0;
+ if (un != 0UL)
+ return 0;
+ if (un < 0UL) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ return 0;
+ if (un <= 0UL)
+ return 0;
+ if (un > 0UL)
+ return 0;
+ if (un >= 0UL) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
+ return 0;
+
+ if (0UL == un)
+ return 0;
+ if (0UL != un)
+ return 0;
+ if (0UL < un)
+ return 0;
+ if (0UL <= un) // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+ return 0;
+ if (0UL > un) // expected-warning {{comparison of 0 > unsigned expression is always false}}
+ return 0;
+ if (0UL >= un)
+ return 0;
+#else
+// expected-no-diagnostics
+ if (un == 0)
+ return 0;
+ if (un != 0)
+ return 0;
+ if (un < 0)
+ return 0;
+ if (un <= 0)
+ return 0;
+ if (un > 0)
+ return 0;
+ if (un >= 0)
+ return 0;
+
+ if (0 == un)
+ return 0;
+ if (0 != un)
+ return 0;
+ if (0 < un)
+ return 0;
+ if (0 <= un)
+ return 0;
+ if (0 > un)
+ return 0;
+ if (0 >= un)
+ return 0;
+
+ if (un == 0UL)
+ return 0;
+ if (un != 0UL)
+ return 0;
+ if (un < 0UL)
+ return 0;
+ if (un <= 0UL)
+ return 0;
+ if (un > 0UL)
+ return 0;
+ if (un >= 0UL)
+ return 0;
+
+ if (0UL == un)
+ return 0;
+ if (0UL != un)
+ return 0;
+ if (0UL < un)
+ return 0;
+ if (0UL <= un)
+ return 0;
+ if (0UL > un)
+ return 0;
+ if (0UL >= un)
+ return 0;
+#endif
+
+
+ signed int a = svalue();
+
+#ifdef TEST
+ if (a == 0)
+ return 0;
+ if (a != 0)
+ return 0;
+ if (a < 0)
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (a >= 0)
+ return 0;
+
+ if (0 == a)
+ return 0;
+ if (0 != a)
+ return 0;
+ if (0 < a)
+ return 0;
+ if (0 <= a)
+ return 0;
+ if (0 > a)
+ return 0;
+ if (0 >= a)
+ return 0;
+
+ if (a == 0UL)
+ return 0;
+ if (a != 0UL)
+ return 0;
+ if (a < 0UL) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ return 0;
+ if (a <= 0UL)
+ return 0;
+ if (a > 0UL)
+ return 0;
+ if (a >= 0UL) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
+ return 0;
+
+ if (0UL == a)
+ return 0;
+ if (0UL != a)
+ return 0;
+ if (0UL < a)
+ return 0;
+ if (0UL <= a) // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+ return 0;
+ if (0UL > a) // expected-warning {{comparison of 0 > unsigned expression is always false}}
+ return 0;
+ if (0UL >= a)
+ return 0;
+#else
+// expected-no-diagnostics
+ if (a == 0)
+ return 0;
+ if (a != 0)
+ return 0;
+ if (a < 0)
+ return 0;
+ if (a <= 0)
+ return 0;
+ if (a > 0)
+ return 0;
+ if (a >= 0)
+ return 0;
+
+ if (0 == a)
+ return 0;
+ if (0 != a)
+ return 0;
+ if (0 < a)
+ return 0;
+ if (0 <= a)
+ return 0;
+ if (0 > a)
+ return 0;
+ if (0 >= a)
+ return 0;
+
+ if (a == 0UL)
+ return 0;
+ if (a != 0UL)
+ return 0;
+ if (a < 0UL)
+ return 0;
+ if (a <= 0UL)
+ return 0;
+ if (a > 0UL)
+ return 0;
+ if (a >= 0UL)
+ return 0;
+
+ if (0UL == a)
+ return 0;
+ if (0UL != a)
+ return 0;
+ if (0UL < a)
+ return 0;
+ if (0UL <= a)
+ return 0;
+ if (0UL > a)
+ return 0;
+ if (0UL >= a)
+ return 0;
+#endif
+
+
+ float fl = 0;
+
+ if (fl == 0)
+ return 0;
+ if (fl != 0)
+ return 0;
+ if (fl < 0)
+ return 0;
+ if (fl <= 0)
+ return 0;
+ if (fl > 0)
+ return 0;
+ if (fl >= 0)
+ return 0;
+
+ if (0 == fl)
+ return 0;
+ if (0 != fl)
+ return 0;
+ if (0 < fl)
+ return 0;
+ if (0 <= fl)
+ return 0;
+ if (0 > fl)
+ return 0;
+ if (0 >= fl)
+ return 0;
+
+ if (fl == 0UL)
+ return 0;
+ if (fl != 0UL)
+ return 0;
+ if (fl < 0UL)
+ return 0;
+ if (fl <= 0UL)
+ return 0;
+ if (fl > 0UL)
+ return 0;
+ if (fl >= 0UL)
+ return 0;
+
+ if (0UL == fl)
+ return 0;
+ if (0UL != fl)
+ return 0;
+ if (0UL < fl)
+ return 0;
+ if (0UL <= fl)
+ return 0;
+ if (0UL > fl)
+ return 0;
+ if (0UL >= fl)
+ return 0;
+
+
+ double dl = 0;
+
+ if (dl == 0)
+ return 0;
+ if (dl != 0)
+ return 0;
+ if (dl < 0)
+ return 0;
+ if (dl <= 0)
+ return 0;
+ if (dl > 0)
+ return 0;
+ if (dl >= 0)
+ return 0;
+
+ if (0 == dl)
+ return 0;
+ if (0 != dl)
+ return 0;
+ if (0 < dl)
+ return 0;
+ if (0 <= dl)
+ return 0;
+ if (0 > dl)
+ return 0;
+ if (0 >= dl)
+ return 0;
+
+ if (dl == 0UL)
+ return 0;
+ if (dl != 0UL)
+ return 0;
+ if (dl < 0UL)
+ return 0;
+ if (dl <= 0UL)
+ return 0;
+ if (dl > 0UL)
+ return 0;
+ if (dl >= 0UL)
+ return 0;
+
+ if (0UL == dl)
+ return 0;
+ if (0UL != dl)
+ return 0;
+ if (0UL < dl)
+ return 0;
+ if (0UL <= dl)
+ return 0;
+ if (0UL > dl)
+ return 0;
+ if (0UL >= dl)
+ return 0;
+
+ return 1;
+}
diff --git a/test/Sema/tls.c b/test/Sema/tls.c
index a3fdc8ea51..38bd3f2022 100644
--- a/test/Sema/tls.c
+++ b/test/Sema/tls.c
@@ -12,15 +12,11 @@
// RUN: %clang_cc1 -triple x86_64-pc-win32 -fsyntax-only %s
// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only %s
-// OpenBSD does not suppport TLS.
-// RUN: not %clang_cc1 -triple x86_64-pc-openbsd -fsyntax-only %s
-// RUN: not %clang_cc1 -triple i386-pc-openbsd -fsyntax-only %s
+// OpenBSD suppports TLS.
+// RUN: %clang_cc1 -triple x86_64-pc-openbsd -fsyntax-only %s
+// RUN: %clang_cc1 -triple i386-pc-openbsd -fsyntax-only %s
// Haiku does not suppport TLS.
// RUN: not %clang_cc1 -triple i586-pc-haiku -fsyntax-only %s
-// Bitrig suppports TLS.
-// RUN: %clang_cc1 -triple x86_64-pc-bitrig -fsyntax-only %s
-// RUN: %clang_cc1 -triple armv6-unknown-bitrig -fsyntax-only %s
-
__thread int x;
diff --git a/test/Sema/transparent-union.c b/test/Sema/transparent-union.c
index dfbadcfe62..0481127674 100644
--- a/test/Sema/transparent-union.c
+++ b/test/Sema/transparent-union.c
@@ -102,7 +102,7 @@ union pr15134v2 {
union pr30520v { void b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'void'}}
-union pr30520a { int b[]; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'int []'}}
+union pr30520a { int b[]; } __attribute__((transparent_union)); // expected-error {{flexible array member 'b' in a union is not allowed}}
// expected-note@+1 2 {{forward declaration of 'struct stb'}}
union pr30520s { struct stb b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'struct stb'}}
diff --git a/test/Sema/typo-correction.c b/test/Sema/typo-correction.c
index 59f022dfe5..78007015dc 100644
--- a/test/Sema/typo-correction.c
+++ b/test/Sema/typo-correction.c
@@ -80,3 +80,10 @@ int h() {
g(x, 5 ? z : 0); // expected-error 2 {{use of undeclared identifier}}
(x, 5 ? z : 0); // expected-error 2 {{use of undeclared identifier}}
}
+
+__attribute__((overloadable)) void func_overloadable(int);
+__attribute__((overloadable)) void func_overloadable(float);
+
+void overloadable_callexpr(int arg) {
+ func_overloadable(ar); //expected-error{{use of undeclared identifier}}
+}
diff --git a/test/Sema/varargs-aarch64.c b/test/Sema/varargs-aarch64.c
new file mode 100644
index 0000000000..145c821056
--- /dev/null
+++ b/test/Sema/varargs-aarch64.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple aarch64-linux-gnu
+
+void f1(int a, ...) {
+ __builtin_ms_va_list ap;
+ __builtin_ms_va_start(ap, a); // expected-error {{'__builtin_ms_va_start' used in System V ABI function}}
+}
+
+void __attribute__((ms_abi)) f2(int a, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, a); // expected-error {{'va_start' used in Win64 ABI function}}
+}
diff --git a/test/Sema/varargs-x86-32.c b/test/Sema/varargs-x86-32.c
index 6f57022ffc..0359e65892 100644
--- a/test/Sema/varargs-x86-32.c
+++ b/test/Sema/varargs-x86-32.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple i386-apple-darwin9
void foo(int a, ...) {
- __builtin_ms_va_start((void *)0, a); // expected-error {{this builtin is only available on x86-64 targets}}
+ __builtin_ms_va_start((void *)0, a); // expected-error {{this builtin is only available on x86-64 and aarch64 targets}}
}
diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c
index 25a5c72c42..0ade0cf0aa 100644
--- a/test/Sema/varargs.c
+++ b/test/Sema/varargs.c
@@ -27,7 +27,7 @@ void f3(float a, ...) { // expected-note 2{{parameter of type 'float' is declare
}
-// stdarg: PR3075
+// stdarg: PR3075 and PR2531
void f4(const char *msg, ...) {
__builtin_va_list ap;
__builtin_stdarg_start((ap), (msg));
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
index ea4acfac6a..2bdc00707d 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -48,14 +48,16 @@ typedef float float2 __attribute__ ((vector_size (8)));
typedef __attribute__((vector_size(8))) double float64x1_t;
typedef __attribute__((vector_size(16))) double float64x2_t;
float64x1_t vget_low_f64(float64x2_t __p0);
+typedef float float16 __attribute__((__vector_size__(16)));
+typedef signed int vSInt32 __attribute__((__vector_size__(16)));
+typedef unsigned int vUInt32 __attribute__((__vector_size__(16)));
void f4() {
float2 f2;
double d, a, b, c;
float64x2_t v = {0.0, 1.0};
- // FIXME: These diagnostics are inaccurate: should complain that 'double' to vector 'float2' involves truncation
- f2 += d; // expected-error {{cannot convert between vector values of different size ('float2' (vector of 2 'float' values) and 'double')}}
- d += f2; // expected-error {{cannot convert between vector values of different size}}
+ f2 += d; // expected-error {{cannot convert between scalar type 'double' and vector type 'float2' (vector of 2 'float' values) as implicit conversion would cause truncation}}
+ d += f2; // expected-error {{assigning to 'double' from incompatible type 'float2' (vector of 2 'float' values)}}
a = 3.0 + vget_low_f64(v);
b = vget_low_f64(v) + 3.0;
c = vget_low_f64(v);
@@ -74,3 +76,8 @@ void f5() {
v = ptr; // expected-error-re {{assigning to 'short_sizeof_pointer' (vector of {{[0-9]+}} 'short' values) from incompatible type 'void *'}}
ptr = v; // expected-error {{assigning to 'void *' from incompatible type 'short_sizeof_pointer'}}
}
+
+void f6(vSInt32 a0) {
+ vUInt32 counter = (float16){0.0f, 0.0f, 0.0f, 0.0f}; // expected-warning {{incompatible vector types initializing 'vUInt32' (vector of 4 'unsigned int' values) with an expression of type 'float16' (vector of 4 'float' values)}}
+ counter -= a0;
+}
diff --git a/test/Sema/vector-gcc-compat.c b/test/Sema/vector-gcc-compat.c
new file mode 100644
index 0000000000..9eb0569b25
--- /dev/null
+++ b/test/Sema/vector-gcc-compat.c
@@ -0,0 +1,330 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Weverything -triple x86_64-apple-darwin10
+
+// Test the compatibility of clang's vector extensions with gcc's vector
+// extensions for C. Notably &&, ||, ?: and ! are not available.
+typedef long long v2i64 __attribute__((vector_size(16)));
+typedef int v2i32 __attribute__((vector_size(8)));
+typedef short v2i16 __attribute__((vector_size(4)));
+typedef char v2i8 __attribute__((vector_size(2)));
+
+typedef unsigned long long v2u64 __attribute__((vector_size(16)));
+typedef unsigned int v2u32 __attribute__((vector_size(8)));
+typedef unsigned short v2u16 __attribute__((vector_size(4)));
+typedef unsigned char v2u8 __attribute__((vector_size(2)));
+
+typedef float v4f32 __attribute__((vector_size(16)));
+typedef double v2f64 __attribute__((vector_size(16)));
+typedef double v4f64 __attribute__((vector_size(32)));
+typedef int v4i32 __attribute((vector_size(16)));
+
+void arithmeticTest(void);
+void logicTest(void);
+void comparisonTest(void);
+void floatTestSignedType(char a, short b, int c, long long d);
+void floatTestUnsignedType(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d);
+void floatTestConstant(void);
+void intTestType(char a, short b, int c, long long d);
+void intTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d);
+void uintTestType(char a, short b, int c, long long d);
+void uintTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d);
+void uintTestConstant(v2u64 v2u64_a, v2u32 v2u32_a, v2u16 v2u16_a, v2u8 v2u8_a);
+void intTestConstant(v2i64 v2i64_a, v2i32 v2i32_a, v2i16 v2i16_a, v2i8 v2i8_a);
+
+void arithmeticTest(void) {
+ v2i64 v2i64_a = (v2i64){0, 1};
+ v2i64 v2i64_r;
+
+ v2i64_r = v2i64_a + 1;
+ v2i64_r = v2i64_a - 1;
+ v2i64_r = v2i64_a * 1;
+ v2i64_r = v2i64_a / 1;
+ v2i64_r = v2i64_a % 1;
+
+ v2i64_r = 1 + v2i64_a;
+ v2i64_r = 1 - v2i64_a;
+ v2i64_r = 1 * v2i64_a;
+ v2i64_r = 1 / v2i64_a;
+ v2i64_r = 1 % v2i64_a;
+
+ v2i64_a += 1;
+ v2i64_a -= 1;
+ v2i64_a *= 1;
+ v2i64_a /= 1;
+ v2i64_a %= 1;
+}
+
+void comparisonTest(void) {
+ v2i64 v2i64_a = (v2i64){0, 1};
+ v2i64 v2i64_r;
+
+ v2i64_r = v2i64_a == 1;
+ v2i64_r = v2i64_a != 1;
+ v2i64_r = v2i64_a < 1;
+ v2i64_r = v2i64_a > 1;
+ v2i64_r = v2i64_a <= 1;
+ v2i64_r = v2i64_a >= 1;
+
+ v2i64_r = 1 == v2i64_a;
+ v2i64_r = 1 != v2i64_a;
+ v2i64_r = 1 < v2i64_a;
+ v2i64_r = 1 > v2i64_a;
+ v2i64_r = 1 <= v2i64_a;
+ v2i64_r = 1 >= v2i64_a;
+}
+
+void logicTest(void) {
+ v2i64 v2i64_a = (v2i64){0, 1};
+ v2i64 v2i64_b = (v2i64){2, 1};
+ v2i64 v2i64_c = (v2i64){3, 1};
+ v2i64 v2i64_r;
+
+ v2i64_r = !v2i64_a; // expected-error {{invalid argument type 'v2i64' (vector of 2 'long long' values) to unary expression}}
+ v2i64_r = ~v2i64_a;
+
+ v2i64_r = v2i64_a ? v2i64_b : v2i64_c; // expected-error {{used type 'v2i64' (vector of 2 'long long' values) where arithmetic or pointer type is required}}
+
+ v2i64_r = v2i64_a & 1;
+ v2i64_r = v2i64_a | 1;
+ v2i64_r = v2i64_a ^ 1;
+
+ v2i64_r = 1 & v2i64_a;
+ v2i64_r = 1 | v2i64_a;
+ v2i64_r = 1 ^ v2i64_a;
+
+ v2i64_a &= 1;
+ v2i64_a |= 1;
+ v2i64_a ^= 1;
+
+ v2i64_r = v2i64_a && 1; // expected-error {{logical expression with vector type 'v2i64' (vector of 2 'long long' values) and non-vector type 'int' is only supported in C++}}
+ v2i64_r = v2i64_a || 1; // expected-error {{logical expression with vector type 'v2i64' (vector of 2 'long long' values) and non-vector type 'int' is only supported in C++}}
+
+ v2i64_r = v2i64_a && v2i64_a; // expected-error {{logical expression with vector types 'v2i64' (vector of 2 'long long' values) and 'v2i64' is only supported in C++}}
+ v2i64_r = v2i64_a || v2i64_a; // expected-error {{logical expression with vector types 'v2i64' (vector of 2 'long long' values) and 'v2i64' is only supported in C++}}
+
+ v2i64_r = v2i64_a << 1;
+ v2i64_r = v2i64_a >> 1;
+
+ v2i64_r = 1 << v2i64_a;
+ v2i64_r = 1 >> v2i64_a;
+
+ v2i64_a <<= 1;
+ v2i64_a >>= 1;
+}
+
+// For operations with floating point types, we check that interger constants
+// can be respresented, or failing that checking based on the integer types.
+void floatTestConstant(void) {
+ // Test that constants added to floats must be expressible as floating point
+ // numbers.
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4f32_a = v4f32_a + 1;
+ v4f32_a = v4f32_a + 0xFFFFFF;
+ v4f32_a = v4f32_a + (-1567563LL);
+ v4f32_a = v4f32_a + (16777208);
+ v4f32_a = v4f32_a + (16777219); // expected-error {{cannot convert between scalar type 'int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+}
+
+void floatTestConstantComparison(void);
+void doubleTestConstantComparison(void);
+
+void floatTestConstantComparison(void) {
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4i32 v4i32_r;
+ v4i32_r = v4f32_a > 0.4f;
+ v4i32_r = v4f32_a >= 0.4f;
+ v4i32_r = v4f32_a < 0.4f;
+ v4i32_r = v4f32_a <= 0.4f;
+ v4i32_r = v4f32_a == 0.4f; // expected-warning {{comparing floating point with == or != is unsafe}}
+ v4i32_r = v4f32_a != 0.4f; // expected-warning {{comparing floating point with == or != is unsafe}}
+}
+
+void doubleTestConstantComparison(void) {
+ v2f64 v2f64_a = {0.4, 0.4};
+ v2i64 v2i64_r;
+ v2i64_r = v2f64_a > 0.4;
+ v2i64_r = v2f64_a >= 0.4;
+ v2i64_r = v2f64_a < 0.4;
+ v2i64_r = v2f64_a <= 0.4;
+ v2i64_r = v2f64_a == 0.4; // expected-warning {{comparing floating point with == or != is unsafe}}
+ v2i64_r = v2f64_a != 0.4; // expected-warning {{comparing floating point with == or != is unsafe}}
+}
+
+void floatTestUnsignedType(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d) {
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4f64 v4f64_b = {0.4, 0.4, 0.4, 0.4};
+
+ v4f32_a = v4f32_a + a;
+ v4f32_a = v4f32_a + b;
+ v4f32_a = v4f32_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+ v4f32_a = v4f32_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+
+ v4f64_b = v4f64_b + a;
+ v4f64_b = v4f64_b + b;
+ v4f64_b = v4f64_b + c;
+ v4f64_b = v4f64_b + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v4f64' (vector of 4 'double' values) as implicit conversion would cause truncation}}
+}
+
+void floatTestSignedType(char a, short b, int c, long long d) {
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4f64 v4f64_b = {0.4, 0.4, 0.4, 0.4};
+
+ v4f32_a = v4f32_a + a;
+ v4f32_a = v4f32_a + b;
+ v4f32_a = v4f32_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+ v4f32_a = v4f32_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+
+ v4f64_b = v4f64_b + a;
+ v4f64_b = v4f64_b + b;
+ v4f64_b = v4f64_b + c;
+ v4f64_b = v4f64_b + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v4f64' (vector of 4 'double' values) as implicit conversion would cause truncation}}
+}
+
+void intTestType(char a, short b, int c, long long d) {
+ v2i64 v2i64_a = {1, 2};
+ v2i32 v2i32_a = {1, 2};
+ v2i16 v2i16_a = {1, 2};
+ v2i8 v2i8_a = {1, 2};
+
+ v2i64_a = v2i64_a + d;
+ v2i64_a = v2i64_a + c;
+ v2i64_a = v2i64_a + b;
+ v2i64_a = v2i64_a + a;
+
+ v2i32_a = v2i32_a + d; // expected-warning {{implicit conversion loses integer precision: 'long long' to 'v2i32' (vector of 2 'int' values)}}
+ v2i32_a = v2i32_a + c;
+ v2i32_a = v2i32_a + b;
+ v2i32_a = v2i32_a + a;
+
+ v2i16_a = v2i16_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+ v2i16_a = v2i16_a + c; // expected-warning {{implicit conversion loses integer precision: 'int' to 'v2i16' (vector of 2 'short' values)}}
+ v2i16_a = v2i16_a + b;
+ v2i16_a = v2i16_a + a;
+
+ v2i8_a = v2i8_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + b; // expected-warning {{implicit conversion loses integer precision: 'short' to 'v2i8' (vector of 2 'char' values)}}
+ v2i8_a = v2i8_a + a;
+}
+
+void intTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d) {
+ v2i64 v2i64_a = {1, 2};
+ v2i32 v2i32_a = {1, 2};
+ v2i16 v2i16_a = {1, 2};
+ v2i8 v2i8_a = {1, 2};
+
+ v2i64_a = v2i64_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i64' (vector of 2 'long long' values) as implicit conversion would cause truncation}}
+
+ v2i64_a = v2i64_a + c;
+ v2i64_a = v2i64_a + b;
+ v2i64_a = v2i64_a + a;
+
+ v2i32_a = v2i32_a + d; // expected-warning {{implicit conversion loses integer precision: 'unsigned long long' to 'v2i32' (vector of 2 'int' values)}}
+ v2i32_a = v2i32_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2i32' (vector of 2 'int' values) as implicit conversion would cause truncation}}
+ v2i32_a = v2i32_a + b;
+ v2i32_a = v2i32_a + a;
+
+ v2i16_a = v2i16_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+ v2i16_a = v2i16_a + c; // expected-warning {{implicit conversion loses integer precision: 'unsigned int' to 'v2i16' (vector of 2 'short' values)}}
+ v2i16_a = v2i16_a + b; // expected-error {{cannot convert between scalar type 'unsigned short' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+ v2i16_a = v2i16_a + a;
+
+ v2i8_a = v2i8_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + b; // expected-warning {{implicit conversion loses integer precision: 'unsigned short' to 'v2i8' (vector of 2 'char' values)}}
+ v2i8_a = v2i8_a + a; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+}
+
+void uintTestType(char a, short b, int c, long long d) {
+ v2u64 v2u64_a = {1, 2};
+ v2u32 v2u32_a = {1, 2};
+ v2u16 v2u16_a = {1, 2};
+ v2u8 v2u8_a = {1, 2};
+
+ v2u64_a = v2u64_a + d; // expected-warning {{implicit conversion changes signedness: 'long long' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+ v2u64_a = v2u64_a + c; // expected-warning {{implicit conversion changes signedness: 'int' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+ v2u64_a = v2u64_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+ v2u64_a = v2u64_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+
+ v2u32_a = v2u32_a + d; // expected-warning {{implicit conversion loses integer precision: 'long long' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + c; // expected-warning {{implicit conversion changes signedness: 'int' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u32' (vector of 2 'unsigned int' values)}}
+
+ v2u16_a = v2u16_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2u16' (vector of 2 'unsigned short' values) as implicit conversion would cause truncation}}
+ v2u16_a = v2u16_a + c; // expected-warning {{implicit conversion loses integer precision: 'int' to 'v2u16' (vector of 2 'unsigned short' values)}}
+ v2u16_a = v2u16_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u16' (vector of 2 'unsigned short' values)}}
+ v2u16_a = v2u16_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u16' (vector of 2 'unsigned short' values)}}
+
+ v2u8_a = v2u8_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + b; // expected-warning {{implicit conversion loses integer precision: 'short' to 'v2u8' (vector of 2 'unsigned char' values)}}
+ v2u8_a = v2u8_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u8' (vector of 2 'unsigned char' values)}}
+}
+
+void uintTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d) {
+ v2u64 v2u64_a = {1, 2};
+ v2u32 v2u32_a = {1, 2};
+ v2u16 v2u16_a = {1, 2};
+ v2u8 v2u8_a = {1, 2};
+
+ v2u64_a = v2u64_a + d;
+ v2u64_a = v2u64_a + c;
+ v2u64_a = v2u64_a + b;
+ v2u64_a = v2u64_a + a;
+
+ v2u32_a = v2u32_a + d; // expected-warning {{implicit conversion loses integer precision: 'unsigned long long' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + c;
+ v2u32_a = v2u32_a + b;
+ v2u32_a = v2u32_a + a;
+
+ v2u16_a = v2u16_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2u16' (vector of 2 'unsigned short' values) as implicit conversion would cause truncation}}
+ v2u16_a = v2u16_a + c; // expected-warning {{implicit conversion loses integer precision: 'unsigned int' to 'v2u16' (vector of 2 'unsigned short' values)}}
+ v2u16_a = v2u16_a + b;
+ v2u16_a = v2u16_a + a;
+
+ v2u8_a = v2u8_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + b; // expected-warning {{implicit conversion loses integer precision: 'unsigned short' to 'v2u8' (vector of 2 'unsigned char' values)}}
+ v2u8_a = v2u8_a + a;
+}
+
+void uintTestConstant(v2u64 v2u64_a, v2u32 v2u32_a, v2u16 v2u16_a,
+ v2u8 v2u8_a) {
+ v2u64_a = v2u64_a + 0xFFFFFFFFFFFFFFFF;
+ v2u32_a = v2u32_a + 0xFFFFFFFF;
+ v2u16_a = v2u16_a + 0xFFFF;
+ v2u8_a = v2u8_a + 0xFF;
+
+ v2u32_a = v2u32_a + 0x1FFFFFFFF; // expected-warning {{implicit conversion from 'long' to 'v2u32' (vector of 2 'unsigned int' values) changes value from 8589934591 to 4294967295}}
+ v2u16_a = v2u16_a + 0x1FFFF; // expected-warning {{implicit conversion from 'int' to 'v2u16' (vector of 2 'unsigned short' values) changes value from 131071 to 65535}}
+ v2u8_a = v2u8_a + 0x1FF; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+}
+
+void intTestConstant(v2i64 v2i64_a, v2i32 v2i32_a, v2i16 v2i16_a, v2i8 v2i8_a) {
+ // Legal upper bounds.
+ v2i64_a = v2i64_a + (long long)0x7FFFFFFFFFFFFFFF;
+ v2i32_a = v2i32_a + (int)0x7FFFFFFF;
+ v2i16_a = v2i16_a + (short)0x7FFF;
+ v2i8_a = v2i8_a + (char)0x7F;
+
+ // Legal lower bounds.
+ v2i64_a = v2i64_a + (-9223372036854775807);
+ v2i32_a = v2i32_a + (-2147483648);
+ v2i16_a = v2i16_a + (-32768);
+ v2i8_a = v2i8_a + (-128);
+
+ // One increment/decrement more than the type can hold
+ v2i32_a = v2i32_a + 2147483648; // expected-warning {{implicit conversion from 'long' to 'v2i32' (vector of 2 'int' values) changes value from 2147483648 to -2147483648}}
+ v2i16_a = v2i16_a + 32768; // expected-warning {{implicit conversion from 'int' to 'v2i16' (vector of 2 'short' values) changes value from 32768 to -32768}}
+ v2i8_a = v2i8_a + 128; // expected-warning {{implicit conversion from 'int' to 'v2i8' (vector of 2 'char' values) changes value from 128 to -128}}
+
+ v2i32_a = v2i32_a + (-2147483649); // expected-warning {{implicit conversion from 'long' to 'v2i32' (vector of 2 'int' values) changes value from -2147483649 to 2147483647}}
+ v2i16_a = v2i16_a + (-32769); // expected-warning {{implicit conversion from 'int' to 'v2i16' (vector of 2 'short' values) changes value from -32769 to 32767}}
+ v2i8_a = v2i8_a + (-129); // expected-error {{cannot convert between scalar type 'int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+}
diff --git a/test/Sema/vector-gcc-compat.cpp b/test/Sema/vector-gcc-compat.cpp
new file mode 100644
index 0000000000..12da314c32
--- /dev/null
+++ b/test/Sema/vector-gcc-compat.cpp
@@ -0,0 +1,328 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Weverything -std=c++11 -triple x86_64-apple-darwin10
+
+// Test the compatibility of clang++'s vector extensions with g++'s vector
+// extensions. In comparison to the extensions available in C, the !, ?:, && and
+// || operators work on vector types.
+
+typedef long long v2i64 __attribute__((vector_size(16))); // expected-warning {{'long long' is incompatible with C++98}}
+typedef int v2i32 __attribute__((vector_size(8)));
+typedef short v2i16 __attribute__((vector_size(4)));
+typedef char v2i8 __attribute__((vector_size(2)));
+
+typedef unsigned long long v2u64 __attribute__((vector_size(16))); // expected-warning {{'long long' is incompatible with C++98}}
+typedef unsigned int v2u32 __attribute__((vector_size(8)));
+typedef unsigned short v2u16 __attribute__((vector_size(4)));
+typedef unsigned char v2u8 __attribute__((vector_size(2)));
+
+typedef float v4f32 __attribute__((vector_size(16)));
+typedef double v2f64 __attribute__((vector_size(16)));
+typedef double v4f64 __attribute__((vector_size(32)));
+typedef int v4i32 __attribute((vector_size(16)));
+
+void arithmeticTest(void);
+void logicTest(void);
+void comparisonTest(void);
+void floatTestSignedType(char a, short b, int c, long long d); // expected-warning {{'long long' is incompatible with C++98}}
+void floatTestUnsignedType(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d); // expected-warning {{'long long' is incompatible with C++98}}
+void floatTestConstant(void);
+void intTestType(char a, short b, int c, long long d); // expected-warning {{'long long' is incompatible with C++98}}
+void intTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d); // expected-warning {{'long long' is incompatible with C++98}}
+void uintTestType(char a, short b, int c, long long d); // expected-warning {{'long long' is incompatible with C++98}}
+void uintTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d); // expected-warning {{'long long' is incompatible with C++98}}
+void uintTestConstant(v2u64 v2u64_a, v2u32 v2u32_a, v2u16 v2u16_a, v2u8 v2u8_a);
+void intTestConstant(v2i64 v2i64_a, v2i32 v2i32_a, v2i16 v2i16_a, v2i8 v2i8_a);
+
+void arithmeticTest(void) {
+ v2i64 v2i64_a = (v2i64){0, 1}; // expected-warning {{compound literals are a C99-specific feature}}
+ v2i64 v2i64_r;
+
+ v2i64_r = v2i64_a + 1;
+ v2i64_r = v2i64_a - 1;
+ v2i64_r = v2i64_a * 1;
+ v2i64_r = v2i64_a / 1;
+ v2i64_r = v2i64_a % 1;
+
+ v2i64_r = 1 + v2i64_a;
+ v2i64_r = 1 - v2i64_a;
+ v2i64_r = 1 * v2i64_a;
+ v2i64_r = 1 / v2i64_a;
+ v2i64_r = 1 % v2i64_a;
+
+ v2i64_a += 1;
+ v2i64_a -= 1;
+ v2i64_a *= 1;
+ v2i64_a /= 1;
+ v2i64_a %= 1;
+}
+
+void comparisonTest(void) {
+ v2i64 v2i64_a = (v2i64){0, 1}; // expected-warning {{compound literals are a C99-specific feature}}
+ v2i64 v2i64_r;
+
+ v2i64_r = v2i64_a == 1;
+ v2i64_r = v2i64_a != 1;
+ v2i64_r = v2i64_a < 1;
+ v2i64_r = v2i64_a > 1;
+ v2i64_r = v2i64_a <= 1;
+ v2i64_r = v2i64_a >= 1;
+
+ v2i64_r = 1 == v2i64_a;
+ v2i64_r = 1 != v2i64_a;
+ v2i64_r = 1 < v2i64_a;
+ v2i64_r = 1 > v2i64_a;
+ v2i64_r = 1 <= v2i64_a;
+ v2i64_r = 1 >= v2i64_a;
+}
+
+void logicTest(void) {
+ v2i64 v2i64_a = (v2i64){0, 1}; // expected-warning {{compound literals are a C99-specific feature}}
+ v2i64 v2i64_b = (v2i64){2, 1}; // expected-warning {{compound literals are a C99-specific feature}}
+ v2i64 v2i64_c = (v2i64){3, 1}; // expected-warning {{compound literals are a C99-specific feature}}
+ v2i64 v2i64_r;
+
+ v2i64_r = !v2i64_a; // expected-error {{invalid argument type 'v2i64' (vector of 2 'long long' values) to unary expression}}
+ v2i64_r = ~v2i64_a;
+
+ v2i64_r = v2i64_a ? v2i64_b : v2i64_c; // expected-error {{value of type 'v2i64' (vector of 2 'long long' values) is not contextually convertible to 'bool'}}
+
+ v2i64_r = v2i64_a & 1;
+ v2i64_r = v2i64_a | 1;
+ v2i64_r = v2i64_a ^ 1;
+
+ v2i64_r = 1 & v2i64_a;
+ v2i64_r = 1 | v2i64_a;
+ v2i64_r = 1 ^ v2i64_a;
+ v2i64_a &= 1;
+ v2i64_a |= 1;
+ v2i64_a ^= 1;
+
+ v2i64_r = v2i64_a && 1;
+ v2i64_r = v2i64_a || 1;
+
+ v2i64_r = v2i64_a << 1;
+ v2i64_r = v2i64_a >> 1;
+
+ v2i64_r = 1 << v2i64_a;
+ v2i64_r = 1 >> v2i64_a;
+
+ v2i64_a <<= 1;
+ v2i64_a >>= 1;
+}
+
+// For operations with floating point types, we check that interger constants
+// can be respresented, or failing that checking based on the integer types.
+void floatTestConstant(void) {
+ // Test that constants added to floats must be expressible as floating point
+ // numbers.
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4f32_a = v4f32_a + 1;
+ v4f32_a = v4f32_a + 0xFFFFFF;
+ v4f32_a = v4f32_a + (-1567563LL); // expected-warning {{'long long' is incompatible with C++98}}
+ v4f32_a = v4f32_a + (16777208);
+ v4f32_a = v4f32_a + (16777219); // expected-error {{cannot convert between scalar type 'int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+}
+
+void floatTestConstantComparison(void);
+void doubleTestConstantComparison(void);
+
+void floatTestConstantComparison(void) {
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4i32 v4i32_r;
+ v4i32_r = v4f32_a > 0.4f;
+ v4i32_r = v4f32_a >= 0.4f;
+ v4i32_r = v4f32_a < 0.4f;
+ v4i32_r = v4f32_a <= 0.4f;
+ v4i32_r = v4f32_a == 0.4f; // expected-warning {{comparing floating point with == or != is unsafe}}
+ v4i32_r = v4f32_a != 0.4f; // expected-warning {{comparing floating point with == or != is unsafe}}
+}
+
+void doubleTestConstantComparison(void) {
+ v2f64 v2f64_a = {0.4, 0.4};
+ v2i64 v2i64_r;
+ v2i64_r = v2f64_a > 0.4;
+ v2i64_r = v2f64_a >= 0.4;
+ v2i64_r = v2f64_a < 0.4;
+ v2i64_r = v2f64_a <= 0.4;
+ v2i64_r = v2f64_a == 0.4; // expected-warning {{comparing floating point with == or != is unsafe}}
+ v2i64_r = v2f64_a != 0.4; // expected-warning {{comparing floating point with == or != is unsafe}}
+}
+
+void floatTestUnsignedType(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d) { // expected-warning {{'long long' is incompatible with C++98}}
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4f64 v4f64_b = {0.4, 0.4, 0.4, 0.4};
+
+ v4f32_a = v4f32_a + a;
+ v4f32_a = v4f32_a + b;
+ v4f32_a = v4f32_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+ v4f32_a = v4f32_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+
+ v4f64_b = v4f64_b + a;
+ v4f64_b = v4f64_b + b;
+ v4f64_b = v4f64_b + c;
+ v4f64_b = v4f64_b + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v4f64' (vector of 4 'double' values) as implicit conversion would cause truncation}}
+}
+
+void floatTestSignedType(char a, short b, int c, long long d) { // expected-warning {{'long long' is incompatible with C++98}}
+ v4f32 v4f32_a = {0.4f, 0.4f, 0.4f, 0.4f};
+ v4f64 v4f64_b = {0.4, 0.4, 0.4, 0.4};
+
+ v4f32_a = v4f32_a + a;
+ v4f32_a = v4f32_a + b;
+ v4f32_a = v4f32_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+ v4f32_a = v4f32_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v4f32' (vector of 4 'float' values) as implicit conversion would cause truncation}}
+
+ v4f64_b = v4f64_b + a;
+ v4f64_b = v4f64_b + b;
+ v4f64_b = v4f64_b + c;
+ v4f64_b = v4f64_b + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v4f64' (vector of 4 'double' values) as implicit conversion would cause truncation}}
+}
+
+void intTestType(char a, short b, int c, long long d) { // expected-warning {{'long long' is incompatible with C++98}}
+ v2i64 v2i64_a = {1, 2};
+ v2i32 v2i32_a = {1, 2};
+ v2i16 v2i16_a = {1, 2};
+ v2i8 v2i8_a = {1, 2};
+
+ v2i64_a = v2i64_a + d;
+ v2i64_a = v2i64_a + c;
+ v2i64_a = v2i64_a + b;
+ v2i64_a = v2i64_a + a;
+
+ v2i32_a = v2i32_a + d; // expected-warning {{implicit conversion loses integer precision: 'long long' to 'v2i32' (vector of 2 'int' values)}}
+ v2i32_a = v2i32_a + c;
+ v2i32_a = v2i32_a + b;
+ v2i32_a = v2i32_a + a;
+
+ v2i16_a = v2i16_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+ v2i16_a = v2i16_a + c; // expected-warning {{implicit conversion loses integer precision: 'int' to 'v2i16' (vector of 2 'short' values)}}
+ v2i16_a = v2i16_a + b;
+ v2i16_a = v2i16_a + a;
+
+ v2i8_a = v2i8_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + b; // expected-warning {{implicit conversion loses integer precision: 'short' to 'v2i8' (vector of 2 'char' values)}}
+ v2i8_a = v2i8_a + a;
+}
+
+void intTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d) { // expected-warning {{'long long' is incompatible with C++98}}
+ v2i64 v2i64_a = {1, 2};
+ v2i32 v2i32_a = {1, 2};
+ v2i16 v2i16_a = {1, 2};
+ v2i8 v2i8_a = {1, 2};
+
+ v2i64_a = v2i64_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i64' (vector of 2 'long long' values) as implicit conversion would cause truncation}}
+
+ v2i64_a = v2i64_a + c;
+ v2i64_a = v2i64_a + b;
+ v2i64_a = v2i64_a + a;
+
+ v2i32_a = v2i32_a + d; // expected-warning {{implicit conversion loses integer precision: 'unsigned long long' to 'v2i32' (vector of 2 'int' values)}}
+ v2i32_a = v2i32_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2i32' (vector of 2 'int' values) as implicit conversion would cause truncation}}
+ v2i32_a = v2i32_a + b;
+ v2i32_a = v2i32_a + a;
+
+ v2i16_a = v2i16_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+ v2i16_a = v2i16_a + c; // expected-warning {{implicit conversion loses integer precision: 'unsigned int' to 'v2i16' (vector of 2 'short' values)}}
+ v2i16_a = v2i16_a + b; // expected-error {{cannot convert between scalar type 'unsigned short' and vector type 'v2i16' (vector of 2 'short' values) as implicit conversion would cause truncation}}
+ v2i16_a = v2i16_a + a;
+
+ v2i8_a = v2i8_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+ v2i8_a = v2i8_a + b; // expected-warning {{implicit conversion loses integer precision: 'unsigned short' to 'v2i8' (vector of 2 'char' values)}}
+ v2i8_a = v2i8_a + a; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+}
+
+void uintTestType(char a, short b, int c, long long d) { // expected-warning {{'long long' is incompatible with C++98}}
+ v2u64 v2u64_a = {1, 2};
+ v2u32 v2u32_a = {1, 2};
+ v2u16 v2u16_a = {1, 2};
+ v2u8 v2u8_a = {1, 2};
+
+ v2u64_a = v2u64_a + d; // expected-warning {{implicit conversion changes signedness: 'long long' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+ v2u64_a = v2u64_a + c; // expected-warning {{implicit conversion changes signedness: 'int' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+ v2u64_a = v2u64_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+ v2u64_a = v2u64_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u64' (vector of 2 'unsigned long long' values)}}
+
+ v2u32_a = v2u32_a + d; // expected-warning {{implicit conversion loses integer precision: 'long long' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + c; // expected-warning {{implicit conversion changes signedness: 'int' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u32' (vector of 2 'unsigned int' values)}}
+
+ v2u16_a = v2u16_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2u16' (vector of 2 'unsigned short' values) as implicit conversion would cause truncation}}
+ v2u16_a = v2u16_a + c; // expected-warning {{implicit conversion loses integer precision: 'int' to 'v2u16' (vector of 2 'unsigned short' values)}}
+ v2u16_a = v2u16_a + b; // expected-warning {{implicit conversion changes signedness: 'short' to 'v2u16' (vector of 2 'unsigned short' values)}}
+ v2u16_a = v2u16_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u16' (vector of 2 'unsigned short' values)}}
+
+ v2u8_a = v2u8_a + d; // expected-error {{cannot convert between scalar type 'long long' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + c; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + b; // expected-warning {{implicit conversion loses integer precision: 'short' to 'v2u8' (vector of 2 'unsigned char' values)}}
+ v2u8_a = v2u8_a + a; // expected-warning {{implicit conversion changes signedness: 'char' to 'v2u8' (vector of 2 'unsigned char' values)}}
+}
+
+void uintTestTypeUnsigned(unsigned char a, unsigned short b, unsigned int c,
+ unsigned long long d) { // expected-warning {{'long long' is incompatible with C++98}}
+ v2u64 v2u64_a = {1, 2};
+ v2u32 v2u32_a = {1, 2};
+ v2u16 v2u16_a = {1, 2};
+ v2u8 v2u8_a = {1, 2};
+
+ v2u64_a = v2u64_a + d;
+ v2u64_a = v2u64_a + c;
+ v2u64_a = v2u64_a + b;
+ v2u64_a = v2u64_a + a;
+
+ v2u32_a = v2u32_a + d; // expected-warning {{implicit conversion loses integer precision: 'unsigned long long' to 'v2u32' (vector of 2 'unsigned int' values)}}
+ v2u32_a = v2u32_a + c;
+ v2u32_a = v2u32_a + b;
+ v2u32_a = v2u32_a + a;
+
+ v2u16_a = v2u16_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2u16' (vector of 2 'unsigned short' values) as implicit conversion would cause truncation}}
+ v2u16_a = v2u16_a + c; // expected-warning {{implicit conversion loses integer precision: 'unsigned int' to 'v2u16' (vector of 2 'unsigned short' values)}}
+ v2u16_a = v2u16_a + b;
+ v2u16_a = v2u16_a + a;
+
+ v2u8_a = v2u8_a + d; // expected-error {{cannot convert between scalar type 'unsigned long long' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + c; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+ v2u8_a = v2u8_a + b; // expected-warning {{implicit conversion loses integer precision: 'unsigned short' to 'v2u8' (vector of 2 'unsigned char' values)}}
+ v2u8_a = v2u8_a + a;
+}
+
+void uintTestConstant(v2u64 v2u64_a, v2u32 v2u32_a, v2u16 v2u16_a,
+ v2u8 v2u8_a) {
+ v2u64_a = v2u64_a + 0xFFFFFFFFFFFFFFFF;
+ v2u32_a = v2u32_a + 0xFFFFFFFF;
+ v2u16_a = v2u16_a + 0xFFFF;
+ v2u8_a = v2u8_a + 0xFF;
+
+ v2u32_a = v2u32_a + 0x1FFFFFFFF; // expected-warning {{implicit conversion from 'long' to 'v2u32' (vector of 2 'unsigned int' values) changes value from 8589934591 to 4294967295}}
+ v2u16_a = v2u16_a + 0x1FFFF; // expected-warning {{implicit conversion from 'int' to 'v2u16' (vector of 2 'unsigned short' values) changes value from 131071 to 65535}}
+ v2u8_a = v2u8_a + 0x1FF; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2u8' (vector of 2 'unsigned char' values) as implicit conversion would cause truncation}}
+}
+
+void intTestConstant(v2i64 v2i64_a, v2i32 v2i32_a, v2i16 v2i16_a, v2i8 v2i8_a) {
+ // Legal upper bounds.
+ v2i64_a = v2i64_a + static_cast<long long>(0x7FFFFFFFFFFFFFFF); // expected-warning {{'long long' is incompatible with C++98}}
+ v2i32_a = v2i32_a + static_cast<int>(0x7FFFFFFF);
+ v2i16_a = v2i16_a + static_cast<short>(0x7FFF);
+ v2i8_a = v2i8_a + static_cast<char>(0x7F);
+
+ // Legal lower bounds.
+ v2i64_a = v2i64_a + (-9223372036854775807);
+ v2i32_a = v2i32_a + (-2147483648);
+ v2i16_a = v2i16_a + (-32768);
+ v2i8_a = v2i8_a + (-128);
+
+ // One increment/decrement more than the type can hold
+ v2i32_a = v2i32_a + 2147483648; // expected-warning {{implicit conversion from 'long' to 'v2i32' (vector of 2 'int' values) changes value from 2147483648 to -2147483648}}
+ v2i16_a = v2i16_a + 32768; // expected-warning {{implicit conversion from 'int' to 'v2i16' (vector of 2 'short' values) changes value from 32768 to -32768}}
+ v2i8_a = v2i8_a + 128; // expected-warning {{implicit conversion from 'int' to 'v2i8' (vector of 2 'char' values) changes value from 128 to -128}}
+
+ v2i32_a = v2i32_a + (-2147483649); // expected-warning {{implicit conversion from 'long' to 'v2i32' (vector of 2 'int' values) changes value from -2147483649 to 2147483647}}
+ v2i16_a = v2i16_a + (-32769); // expected-warning {{implicit conversion from 'int' to 'v2i16' (vector of 2 'short' values) changes value from -32769 to 32767}}
+ v2i8_a = v2i8_a + (-129); // expected-error {{cannot convert between scalar type 'int' and vector type 'v2i8' (vector of 2 'char' values) as implicit conversion would cause truncation}}
+}
diff --git a/test/Sema/vector-ops.c b/test/Sema/vector-ops.c
index f2953417f5..575f38b972 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,11 +13,11 @@ 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 array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u' (vector of 2 'unsigned int' values}}
int array2[17];
// FIXME: error message below needs type!
(void)(array2[v2ua]); // expected-error{{array subscript is not an integer}}
@@ -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-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2u'}}
+ v2ua = v2ua || v2ua; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2u'}}
+
+ v2ua = v2sa && v2ua; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2u' (vector of 2 'unsigned int' values)}}
+ v2ua = v2sa || v2ua; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2u' (vector of 2 'unsigned int' values)}}
+
+ v2ua = v2ua && v2fa; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2f' (vector of 2 'float' values)}}
+ v2ua = v2ua || v2fa; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2f' (vector of 2 'float' values)}}
+
+ v2ua = v2sa && v2fa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2f' (vector of 2 'float' values)}}
+ v2ua = v2sa || v2fa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2f' (vector of 2 'float' values)}}
+
+ v2sa = v2sa && v2sa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2s'}}
+ v2sa = v2sa || v2sa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2s'}}
+
+ v2sa = v2ua && v2ua; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2u'}}
+ v2sa = v2ua || v2ua; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2u'}}
+
+ v2sa = v2sa && v2ua; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2u' (vector of 2 'unsigned int' values)}}
+ v2sa = v2sa || v2ua; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2u' (vector of 2 'unsigned int' values)}}
+
+ v2sa = v2sa && v2fa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2f' (vector of 2 'float' values)}}
+ v2sa = v2sa || v2fa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2f' (vector of 2 'float' values)}}
+
+ v2sa = v2ua && v2fa; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2f' (vector of 2 'float' values)}}
+ v2sa = v2ua || v2fa; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2f' (vector of 2 'float' values)}}
+
+ v2fa = v2fa && v2fa; // expected-error {{logical expression with vector types 'v2f' (vector of 2 'float' values) and 'v2f'}}
+ v2fa = v2fa || v2fa; // expected-error {{logical expression with vector types 'v2f' (vector of 2 'float' values) and 'v2f'}}
+
+ v2fa = v2sa && v2fa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2f' (vector of 2 'float' values)}}
+ v2fa = v2sa || v2fa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2f' (vector of 2 'float' values)}}
+
+ v2fa = v2ua && v2fa; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2f' (vector of 2 'float' values)}}
+ v2fa = v2ua || v2fa; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2f' (vector of 2 'float' values)}}
+
+ v2fa = v2ua && v2ua; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2u'}}
+ v2fa = v2ua || v2ua; // expected-error {{logical expression with vector types 'v2u' (vector of 2 'unsigned int' values) and 'v2u'}}
+
+ v2fa = v2sa && v2sa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2s'}}
+ v2fa = v2sa || v2sa; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2s'}}
+
+ v2fa = v2sa && v2ua; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2u' (vector of 2 'unsigned int' values)}}
+ v2fa = v2sa || v2ua; // expected-error {{logical expression with vector types 'v2s' (vector of 2 'int' values) and 'v2u' (vector of 2 'unsigned int' values)}}
+}
+
+void testLogicalVecScalar(v2u v2ua, v2s v2sa, v2f v2fa) {
+ unsigned u1;
+ v2ua = v2ua && u1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'unsigned int' is only supported in C++}}
+ v2ua = v2ua || u1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'unsigned int' is only supported in C++}}
+
+ v2sa = v2sa && u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2s' (vector of 2 'int' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+ v2sa = v2sa || u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2s' (vector of 2 'int' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+
+ v2ua = v2sa && u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2s' (vector of 2 'int' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+ v2ua = v2sa || u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2s' (vector of 2 'int' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2s' (vector of 2 'int' values) and 'unsigned int')}}
+ v2sa = v2ua && u1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'unsigned int' is only supported in C++}}
+ v2sa = v2ua || u1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'unsigned int' is only supported in C++}}
+
+ v2ua = v2fa && u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+ v2ua = v2fa || u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+
+ v2sa = v2fa && u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+ v2sa = v2fa || u1; // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'unsigned int')}}
+
+ int s1;
+ v2ua = v2ua && s1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'int' is only supported in C++}}
+ v2ua = v2ua || s1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'int' is only supported in C++}}
+
+ v2sa = v2sa && s1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'int' is only supported in C++}}
+ v2sa = v2sa || s1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'int' is only supported in C++}}
+
+ v2ua = v2sa && s1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'int' is only supported in C++}}
+ v2ua = v2sa || s1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'int' is only supported in C++}}
+
+ v2sa = v2ua && s1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'int' is only supported in C++}}
+ v2sa = v2ua || s1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'int' is only supported in C++}}
+
+ v2ua = v2fa && s1; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int'}}
+ v2ua = v2fa || s1; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int'}}
+
+ v2sa = v2fa && s1; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int'}}
+ v2sa = v2fa || s1; // expected-error {{cannot convert between scalar type 'int' and vector type 'v2f' (vector of 2 'float' values) as implicit conversion would cause truncation}} expected-error {{invalid operands to binary expression ('v2f' (vector of 2 'float' values) and 'int'}}
+
+ float f1;
+ v2ua = v2ua && f1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'float' is only supported in C++}}
+ v2ua = v2ua || f1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'float' is only supported in C++}}
+
+ v2sa = v2sa && f1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'float' is only supported in C++}}
+ v2sa = v2sa || f1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'float' is only supported in C++}}
+
+ v2ua = v2sa && f1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'float' is only supported in C++}}
+ v2ua = v2sa || f1; // expected-error {{logical expression with vector type 'v2s' (vector of 2 'int' values) and non-vector type 'float' is only supported in C++}}
+
+ v2sa = v2ua && f1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'float' is only supported in C++}}
+ v2sa = v2ua || f1; // expected-error {{logical expression with vector type 'v2u' (vector of 2 'unsigned int' values) and non-vector type 'float' is only supported in C++}}
+
+ v2ua = v2fa && f1; // expected-error {{logical expression with vector type 'v2f' (vector of 2 'float' values) and non-vector type 'float' is only supported in C++}}
+ v2ua = v2fa || f1; // expected-error {{logical expression with vector type 'v2f' (vector of 2 'float' values) and non-vector type 'float' is only supported in C++}}
+
+ v2sa = v2fa && f1; // expected-error {{logical expression with vector type 'v2f' (vector of 2 'float' values) and non-vector type 'float' is only supported in C++}}
+ v2sa = v2fa || f1; // expected-error {{logical expression with vector type 'v2f' (vector of 2 'float' values) and non-vector type 'float' is only supported in C++}}
+
+}
diff --git a/test/Sema/vector_swizzle_length.c b/test/Sema/vector_swizzle_length.c
new file mode 100644
index 0000000000..5e6b1e7d67
--- /dev/null
+++ b/test/Sema/vector_swizzle_length.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -x c %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
+
+typedef float float8 __attribute__((ext_vector_type(8)));
+
+void foo() {
+ float8 f2 = (float8){0, 0, 0, 0, 0, 0, 0, 0};
+ (void)f2.s01234;
+ (void)f2.xyzxy;
+}
diff --git a/test/Sema/warn-cast-qual.c b/test/Sema/warn-cast-qual.c
index dc11f5717e..a682cad75e 100644
--- a/test/Sema/warn-cast-qual.c
+++ b/test/Sema/warn-cast-qual.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wcast-qual -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -x c++ -fsyntax-only -Wcast-qual -verify %s
#include <stdint.h>
@@ -26,4 +27,34 @@ void foo() {
const char **charptrptrc;
char **charptrptr = (char **)charptrptrc; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}}
+
+ const char *constcharptr;
+ char *charptr = (char *)constcharptr; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}}
+ const char *constcharptr2 = (char *)constcharptr; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}}
+ const char *charptr2 = (char *)charptr; // no warning
+}
+
+void bar_0() {
+ struct C {
+ const int a;
+ int b;
+ };
+
+ const struct C S = {0, 0};
+
+ *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ *(int *)(&S.b) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+}
+
+void bar_1() {
+ struct C {
+ const int a;
+ int b;
+ };
+
+ struct C S = {0, 0};
+ S.b = 0; // no warning
+
+ *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ *(int *)(&S.b) = 0; // no warning
}
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index 34d8f5fd2d..7ffaffc078 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -1186,7 +1186,7 @@ class Predicate
/// @brief A C++ wrapper class for providing threaded access to a value
/// of type T.
///
-/// A template specilization class.
+/// A template specialization class.
//----------------------------------------------------------------------
template<> class Predicate<int, char>
{
@@ -1210,3 +1210,97 @@ template <class T> T test_function (T arg);
/*! @function test_function<int>
*/
template <> int test_function<int> (int arg);
+
+namespace AllowParamAndReturnsOnFunctionPointerVars {
+
+/**
+ * functionPointerVariable
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+int (*functionPointerVariable)(int i);
+
+struct HasFields {
+ /**
+ * functionPointerField
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+ int (*functionPointerField)(int i);
+};
+
+// expected-warning@+5 {{'\returns' command used in a comment that is attached to a function returning void}}
+/**
+ * functionPointerVariable
+ *
+ * \param p not here.
+ * \returns integer.
+ */
+void (*functionPointerVariableThatLeadsNowhere)();
+
+// Still warn about param/returns commands for variables that don't specify
+// the type directly:
+
+/**
+ * FunctionPointerTypedef
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+typedef int (*FunctionPointerTypedef)(int i);
+
+/**
+ * FunctionPointerTypealias
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+using FunctionPointerTypealias = int (*)(int i);
+
+// expected-warning@+5 {{'@param' command used in a comment that is not attached to a function declaration}}
+// expected-warning@+5 {{'@returns' command used in a comment that is not attached to a function or method declaration}}
+/**
+ * functionPointerVariable
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+FunctionPointerTypedef functionPointerTypedefVariable;
+
+struct HasMoreFields {
+ // expected-warning@+5 {{'\param' command used in a comment that is not attached to a function declaration}}
+ // expected-warning@+5 {{'\returns' command used in a comment that is not attached to a function or method declaration}}
+ /**
+ * functionPointerTypealiasField
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+ FunctionPointerTypealias functionPointerTypealiasField;
+};
+
+}
+
+/*!
+ * Function pointer typedef with variadic params.
+ *
+ * @param a
+ * works
+ *
+ * @param ...
+ * now should work too.
+ */
+typedef void (*VariadicFnType)(int a, ...);
+
+/*!
+ * Function pointer type alias with variadic params.
+ *
+ * @param a
+ * works
+ *
+ * @param ...
+ * now should work too.
+ */
+using VariadicFnType2 = void (*)(int a, ...);
diff --git a/test/Sema/warn-documentation.m b/test/Sema/warn-documentation.m
index 5e95e2a1e8..18ab5bd9e0 100644
--- a/test/Sema/warn-documentation.m
+++ b/test/Sema/warn-documentation.m
@@ -229,3 +229,84 @@ int FooBar();
- (void) VarArgMeth : (id)arg, ... {}
@end
+/**
+ * blockPointerVariable
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+int (^blockPointerVariable)(int i);
+
+struct HasFields {
+ /**
+ * blockPointerField
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+ int (^blockPointerFields)(int i);
+};
+
+// expected-warning@+5 {{'\returns' command used in a comment that is attached to a function returning void}}
+/**
+ * functionPointerVariable
+ *
+ * \param p not here.
+ * \returns integer.
+ */
+void (^_Nullable blockPointerVariableThatLeadsNowhere)();
+
+@interface CheckFunctionBlockPointerVars {
+ /**
+ * functionPointerIVar
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+ int (*functionPointerIVar)(int i);
+
+ /**
+ * blockPointerIVar
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+ int (^blockPointerIVar)(int i);
+}
+
+/**
+ * functionPointerProperty
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+@property int (*functionPointerProperty)(int i);
+
+/**
+ * blockPointerProperty
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+@property int (^blockPointerProperty)(int i);
+
+/**
+ * blockReturnsNothing
+ *
+ * \returns Nothing, but can allow this as this pattern is used to document the
+ * value that the property getter returns.
+ */
+@property void (^blockReturnsNothing)();
+
+@end
+
+/*!
+ * Block typedef with variadic params.
+ *
+ * @param a
+ * works
+ *
+ * @param ...
+ * now should work too.
+ */
+typedef void (^VariadicBlockType)(int a, ...);
diff --git a/test/Sema/warn-strict-prototypes.m b/test/Sema/warn-strict-prototypes.m
index 4567dab019..66d574f75f 100644
--- a/test/Sema/warn-strict-prototypes.m
+++ b/test/Sema/warn-strict-prototypes.m
@@ -2,16 +2,16 @@
@interface Foo
-@property (nonatomic, copy) void (^noProtoBlock)(); // expected-warning {{this function declaration is not a prototype}}
+@property (nonatomic, copy) void (^noProtoBlock)(); // expected-warning {{this block declaration is not a prototype}}
@property (nonatomic, copy) void (^block)(void); // no warning
-- doStuff:(void (^)()) completionHandler; // expected-warning {{this function declaration is not a prototype}}
+- doStuff:(void (^)()) completionHandler; // expected-warning {{this block declaration is not a prototype}}
- doOtherStuff:(void (^)(void)) completionHandler; // no warning
@end
void foo() {
- void (^block)() = // expected-warning {{this function declaration is not a prototype}}
+ void (^block)() = // expected-warning {{this block declaration is not a prototype}}
^void(int arg) { // no warning
};
void (^block2)(void) = ^void() { // no warning
@@ -19,3 +19,8 @@ void foo() {
void (^block3)(void) = ^ { // no warning
};
}
+
+void (*(^(*(^block4)()) // expected-warning {{this block declaration is not a prototype}}
+ ()) // expected-warning {{this function declaration is not a prototype}}
+ ()) // expected-warning {{this block declaration is not a prototype}}
+ (); // expected-warning {{this function declaration is not a prototype}}
diff --git a/test/Sema/warn-unreachable-ms.c b/test/Sema/warn-unreachable-ms.c
new file mode 100644
index 0000000000..421415e932
--- /dev/null
+++ b/test/Sema/warn-unreachable-ms.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 %s -triple=i686-pc-win32 -fsyntax-only -verify -fms-extensions -Wunreachable-code
+
+void f();
+
+void g1() {
+ __try {
+ f();
+ __leave;
+ f(); // expected-warning{{will never be executed}}
+ } __except(1) {
+ f();
+ }
+
+ // Completely empty.
+ __try {
+ } __except(1) {
+ }
+
+ __try {
+ f();
+ return;
+ } __except(1) { // Filter expression should not be marked as unreachable.
+ // Empty __except body.
+ }
+}
+
+void g2() {
+ __try {
+ // Nested __try.
+ __try {
+ f();
+ __leave;
+ f(); // expected-warning{{will never be executed}}
+ } __except(2) {
+ }
+ f();
+ __leave;
+ f(); // expected-warning{{will never be executed}}
+ } __except(1) {
+ f();
+ }
+}
+
+void g3() {
+ __try {
+ __try {
+ f();
+ } __except (1) {
+ __leave; // should exit outer try
+ }
+ __leave;
+ f(); // expected-warning{{never be executed}}
+ } __except (1) {
+ }
+}
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
index 34e0296a20..440aa0a5a1 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/wchar.c b/test/Sema/wchar.c
index 74151edede..e84fe3e552 100644
--- a/test/Sema/wchar.c
+++ b/test/Sema/wchar.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
-// RUN: %clang_cc1 %s -fsyntax-only -fshort-wchar -verify -DSHORT_WCHAR
+// RUN: %clang_cc1 %s -fsyntax-only -fwchar-type=short -fno-signed-wchar -verify -DSHORT_WCHAR
typedef __WCHAR_TYPE__ wchar_t;
diff --git a/test/Sema/xray-log-args-class.cpp b/test/Sema/xray-log-args-class.cpp
new file mode 100644
index 0000000000..10da93f614
--- /dev/null
+++ b/test/Sema/xray-log-args-class.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -std=c++11 -x c++
+
+class Class {
+ [[clang::xray_always_instrument, clang::xray_log_args(1)]] void Method();
+ [[clang::xray_log_args(-1)]] void Invalid(); // expected-error {{'xray_log_args' attribute parameter 1 is out of bounds}}
+ [[clang::xray_log_args("invalid")]] void InvalidStringArg(); // expected-error {{'xray_log_args'}}
+};
diff --git a/test/Sema/zero-initializer.c b/test/Sema/zero-initializer.c
new file mode 100644
index 0000000000..0ab410d4c6
--- /dev/null
+++ b/test/Sema/zero-initializer.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c99 -Wmissing-field-initializers -Wmissing-braces -verify %s
+
+// Tests that using {0} in struct initialization or assignment is supported
+struct foo { int x; int y; };
+struct bar { struct foo a; struct foo b; };
+struct A { int a; };
+struct B { struct A a; };
+struct C { struct B b; };
+struct D { struct C c; int n; };
+
+int main(void)
+{
+ struct foo f = { 0 }; // no-warning
+ struct foo g = { 9 }; // expected-warning {{missing field 'y' initializer}}
+ struct foo h = { 9, 9 }; // no-warning
+ struct bar i = { 0 }; // no-warning
+ struct bar j = { 0, 0 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{missing field 'b' initializer}}
+ struct bar k = { { 9, 9 }, { 9, 9 } }; // no-warning
+ struct bar l = { { 9, 9 }, { 0 } }; // no-warning
+ struct bar m = { { 0 }, { 0 } }; // no-warning
+ struct bar n = { { 0 }, { 9, 9 } }; // no-warning
+ struct bar o = { { 9 }, { 9, 9 } }; // expected-warning {{missing field 'y' initializer}}
+ struct C p = { 0 }; // no-warning
+ struct C q = { 9 }; // warning suppressed for struct with single element
+ struct D r = { 9 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{missing field 'n' initializer}}
+ f = (struct foo ) { 0 }; // no-warning
+ g = (struct foo ) { 9 }; // expected-warning {{missing field 'y' initializer}}
+ h = (struct foo ) { 9, 9 }; // no-warning
+ i = (struct bar) { 0 }; // no-warning
+ j = (struct bar) { 0, 0 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{missing field 'b' initializer}}
+ k = (struct bar) { { 9, 9 }, { 9, 9 } }; // no-warning
+ l = (struct bar) { { 9, 9 }, { 0 } }; // no-warning
+ m = (struct bar) { { 0 }, { 0 } }; // no-warning
+ n = (struct bar) { { 0 }, { 9, 9 } }; // no-warning
+ o = (struct bar) { { 9 }, { 9, 9 } }; // expected-warning {{missing field 'y' initializer}}
+ p = (struct C) { 0 }; // no-warning
+ q = (struct C) { 9 }; // warning suppressed for struct with single element
+ r = (struct D) { 9 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{missing field 'n' initializer}}
+
+ return 0;
+}
diff --git a/test/Sema/zvector.c b/test/Sema/zvector.c
index d1cf1aa01f..740163fcd9 100644
--- a/test/Sema/zvector.c
+++ b/test/Sema/zvector.c
@@ -326,14 +326,14 @@ void foo(void)
bc = bc + sc2; // expected-error {{incompatible type}}
bc = sc + bc2; // expected-error {{incompatible type}}
- sc = sc + sc_scalar; // expected-error {{cannot convert}}
- sc = sc + uc_scalar; // expected-error {{cannot convert}}
- sc = sc_scalar + sc; // expected-error {{cannot convert}}
- sc = uc_scalar + sc; // expected-error {{cannot convert}}
- uc = uc + sc_scalar; // expected-error {{cannot convert}}
- uc = uc + uc_scalar; // expected-error {{cannot convert}}
- uc = sc_scalar + uc; // expected-error {{cannot convert}}
- uc = uc_scalar + uc; // expected-error {{cannot convert}}
+ sc = sc + sc_scalar;
+ sc = sc + uc_scalar; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type '__vector signed char' (vector of 16 'signed char' values) as implicit conversion would cause truncation}}
+ sc = sc_scalar + sc;
+ sc = uc_scalar + sc; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type '__vector signed char' (vector of 16 'signed char' values) as implicit conversion would cause truncation}}
+ uc = uc + sc_scalar; // expected-error {{implicit conversion changes signedness: 'signed char' to '__vector unsigned char' (vector of 16 'unsigned char' values)}}
+ uc = uc + uc_scalar;
+ uc = sc_scalar + uc; // expected-error {{implicit conversion changes signedness: 'signed char' to '__vector unsigned char' (vector of 16 'unsigned char' values)}}
+ uc = uc_scalar + uc;
ss = ss + ss2;
us = us + us2;
@@ -368,10 +368,10 @@ void foo(void)
sc += sl2; // expected-error {{cannot convert}}
sc += fd2; // expected-error {{cannot convert}}
- sc += sc_scalar; // expected-error {{cannot convert}}
- sc += uc_scalar; // expected-error {{cannot convert}}
- uc += sc_scalar; // expected-error {{cannot convert}}
- uc += uc_scalar; // expected-error {{cannot convert}}
+ sc += sc_scalar;
+ sc += uc_scalar; // expected-error {{cannot convert between scalar type 'unsigned char' and vector type '__vector signed char' (vector of 16 'signed char' values) as implicit conversion would cause truncation}}
+ uc += sc_scalar; // expected-error {{implicit conversion changes signedness: 'signed char' to '__vector unsigned char' (vector of 16 'unsigned char' values)}}
+ uc += uc_scalar;
ss += ss2;
us += us2;
diff --git a/test/Sema/zvector2.c b/test/Sema/zvector2.c
new file mode 100644
index 0000000000..0adc0315f0
--- /dev/null
+++ b/test/Sema/zvector2.c
@@ -0,0 +1,211 @@
+// RUN: %clang_cc1 -triple s390x-linux-gnu -fzvector -target-cpu z14 \
+// RUN: -fno-lax-vector-conversions -W -Wall -Wconversion \
+// RUN: -Werror -fsyntax-only -verify %s
+
+vector signed char sc, sc2;
+vector unsigned char uc, uc2;
+vector bool char bc, bc2;
+
+vector signed short ss, ss2;
+vector unsigned short us, us2;
+vector bool short bs, bs2;
+
+vector signed int si, si2;
+vector unsigned int ui, ui2;
+vector bool int bi, bi2;
+
+vector signed long long sl, sl2;
+vector unsigned long long ul, ul2;
+vector bool long long bl, bl2;
+
+vector double fd, fd2;
+
+vector float ff, ff2;
+
+void foo(void)
+{
+ // -------------------------------------------------------------------------
+ // Test assignment.
+ // -------------------------------------------------------------------------
+
+ ff = ff2;
+
+ sc = ff2; // expected-error {{incompatible type}}
+ ff = sc2; // expected-error {{incompatible type}}
+
+ uc = ff2; // expected-error {{incompatible type}}
+ ff = uc2; // expected-error {{incompatible type}}
+
+ bc = ff2; // expected-error {{incompatible type}}
+ ff = bc2; // expected-error {{incompatible type}}
+
+ fd = ff2; // expected-error {{incompatible type}}
+ ff = fd2; // expected-error {{incompatible type}}
+
+ // -------------------------------------------------------------------------
+ // Test casts to same element width.
+ // -------------------------------------------------------------------------
+
+ ui = (vector unsigned int)ff2;
+ ff = (vector float)si2;
+
+ // -------------------------------------------------------------------------
+ // Test casts to different element width.
+ // -------------------------------------------------------------------------
+
+ uc = (vector unsigned char)ff2;
+ us = (vector unsigned short)ff2;
+ ul = (vector unsigned long long)ff2;
+
+ ff = (vector float)sc2;
+ ff = (vector float)ss2;
+ ff = (vector float)sl2;
+
+ // -------------------------------------------------------------------------
+ // Test unary operators.
+ // -------------------------------------------------------------------------
+
+ ++ff2;
+ ff++;
+
+ --ff2;
+ ff--;
+
+ ff = +ff2;
+
+ ff = -ff2;
+
+ ff = ~ff2; // expected-error {{invalid argument}}
+
+ // -------------------------------------------------------------------------
+ // Test binary arithmetic operators.
+ // -------------------------------------------------------------------------
+
+ ff = ff + ff2;
+ ff = ff + ui2; // expected-error {{cannot convert}}
+ ff = si + ff2; // expected-error {{cannot convert}}
+ ff = fd + ff2; // expected-error {{cannot convert}}
+ ff += ff2;
+ ff += fd2; // expected-error {{cannot convert}}
+ sc += ff2; // expected-error {{cannot convert}}
+
+ ff = ff - ff2;
+ ff = ff - ui2; // expected-error {{cannot convert}}
+ ff = si - ff2; // expected-error {{cannot convert}}
+ ff = fd - ff2; // expected-error {{cannot convert}}
+ ff -= ff2;
+ ff -= fd2; // expected-error {{cannot convert}}
+ sc -= ff2; // expected-error {{cannot convert}}
+
+ ff = ff * ff2;
+ ff = ff * ui2; // expected-error {{cannot convert}}
+ ff = si * ff2; // expected-error {{cannot convert}}
+ ff = fd * ff2; // expected-error {{cannot convert}}
+ ff *= ff2;
+ ff *= fd2; // expected-error {{cannot convert}}
+ sc *= ff2; // expected-error {{cannot convert}}
+
+ ff = ff / ff2;
+ ff = ff / ui2; // expected-error {{cannot convert}}
+ ff = si / ff2; // expected-error {{cannot convert}}
+ ff = fd / ff2; // expected-error {{cannot convert}}
+ ff /= ff2;
+ ff /= fd2; // expected-error {{cannot convert}}
+ sc /= ff2; // expected-error {{cannot convert}}
+
+ ff = ff % ff2; // expected-error {{invalid operands}}
+ ff = ff % ui2; // expected-error {{invalid operands}}
+ ff = si % ff2; // expected-error {{invalid operands}}
+ ff = fd % ff2; // expected-error {{invalid operands}}
+ ff %= ff2; // expected-error {{invalid operands}}
+ ff %= fd2; // expected-error {{invalid operands}}
+ sc %= ff2; // expected-error {{invalid operands}}
+
+ // -------------------------------------------------------------------------
+ // Test bitwise binary operators.
+ // -------------------------------------------------------------------------
+
+ ff = ff & ff2; // expected-error {{invalid operands}}
+ ff = bi & ff2; // expected-error {{invalid operands}}
+ ff = fd & ff2; // expected-error {{invalid operands}}
+ ff = ff & bi2; // expected-error {{invalid operands}}
+ ff = ff & si2; // expected-error {{invalid operands}}
+ ff = ff & ui2; // expected-error {{invalid operands}}
+ sc &= ff2; // expected-error {{invalid operands}}
+ ff &= bc2; // expected-error {{invalid operands}}
+ ff &= fd2; // expected-error {{invalid operands}}
+
+ ff = ff | ff2; // expected-error {{invalid operands}}
+ ff = bi | ff2; // expected-error {{invalid operands}}
+ ff = fd | ff2; // expected-error {{invalid operands}}
+ ff = ff | bi2; // expected-error {{invalid operands}}
+ ff = ff | si2; // expected-error {{invalid operands}}
+ ff = ff | ui2; // expected-error {{invalid operands}}
+ sc |= ff2; // expected-error {{invalid operands}}
+ ff |= bc2; // expected-error {{invalid operands}}
+ ff |= fd2; // expected-error {{invalid operands}}
+
+ ff = ff ^ ff2; // expected-error {{invalid operands}}
+ ff = bi ^ ff2; // expected-error {{invalid operands}}
+ ff = fd ^ ff2; // expected-error {{invalid operands}}
+ ff = ff ^ bi2; // expected-error {{invalid operands}}
+ ff = ff ^ si2; // expected-error {{invalid operands}}
+ ff = ff ^ ui2; // expected-error {{invalid operands}}
+ sc ^= ff2; // expected-error {{invalid operands}}
+ ff ^= bc2; // expected-error {{invalid operands}}
+ ff ^= fd2; // expected-error {{invalid operands}}
+
+ // -------------------------------------------------------------------------
+ // Test shift operators.
+ // -------------------------------------------------------------------------
+
+ ff = ff << ff2; // expected-error {{integer is required}}
+ ff = ff << fd2; // expected-error {{integer is required}}
+ ff = ff << ui2; // expected-error {{integer is required}}
+ ff = sl << ff2; // expected-error {{integer is required}}
+ sc <<= ff2; // expected-error {{integer is required}}
+ ff <<= ff2; // expected-error {{integer is required}}
+ fd <<= ff2; // expected-error {{integer is required}}
+
+ ff = ff >> ff2; // expected-error {{integer is required}}
+ ff = ff >> fd2; // expected-error {{integer is required}}
+ ff = ff >> ui2; // expected-error {{integer is required}}
+ ff = sl >> ff2; // expected-error {{integer is required}}
+ sc >>= ff2; // expected-error {{integer is required}}
+ ff >>= ff2; // expected-error {{integer is required}}
+ fd >>= ff2; // expected-error {{integer is required}}
+
+ // -------------------------------------------------------------------------
+ // Test comparison operators.
+ // -------------------------------------------------------------------------
+
+ (void)(ff == ff2);
+ (void)(ff == fd2); // expected-error {{cannot convert}}
+ (void)(ff == ui2); // expected-error {{cannot convert}}
+ (void)(ui == ff2); // expected-error {{cannot convert}}
+
+ (void)(ff != ff2);
+ (void)(ff != fd2); // expected-error {{cannot convert}}
+ (void)(ff != ui2); // expected-error {{cannot convert}}
+ (void)(ui != ff2); // expected-error {{cannot convert}}
+
+ (void)(ff <= ff2);
+ (void)(ff <= fd2); // expected-error {{cannot convert}}
+ (void)(ff <= ui2); // expected-error {{cannot convert}}
+ (void)(ui <= ff2); // expected-error {{cannot convert}}
+
+ (void)(ff >= ff2);
+ (void)(ff >= fd2); // expected-error {{cannot convert}}
+ (void)(ff >= ui2); // expected-error {{cannot convert}}
+ (void)(ui >= ff2); // expected-error {{cannot convert}}
+
+ (void)(ff < ff2);
+ (void)(ff < fd2); // expected-error {{cannot convert}}
+ (void)(ff < ui2); // expected-error {{cannot convert}}
+ (void)(ui < ff2); // expected-error {{cannot convert}}
+
+ (void)(ff > ff2);
+ (void)(ff > fd2); // expected-error {{cannot convert}}
+ (void)(ff > ui2); // expected-error {{cannot convert}}
+ (void)(ui > ff2); // expected-error {{cannot convert}}
+}
diff --git a/test/SemaCUDA/error-includes-mode.cu b/test/SemaCUDA/error-includes-mode.cu
new file mode 100644
index 0000000000..257fdeceef
--- /dev/null
+++ b/test/SemaCUDA/error-includes-mode.cu
@@ -0,0 +1,7 @@
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck --check-prefix HOST %s
+// RUN: not %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_35 \
+// RUN: -fcuda-is-device -fsyntax-only %s 2>&1 | FileCheck --check-prefix SM35 %s
+
+// HOST: 1 error generated when compiling for host
+// SM35: 1 error generated when compiling for sm_35
+error;
diff --git a/test/SemaCUDA/function-overload.cu b/test/SemaCUDA/function-overload.cu
index 3d4c29c42c..adf488b5ee 100644
--- a/test/SemaCUDA/function-overload.cu
+++ b/test/SemaCUDA/function-overload.cu
@@ -222,7 +222,7 @@ GlobalFnPtr fp_g = g;
// Test overloading of destructors
// Can't mix H and unattributed destructors
struct d_h {
- ~d_h() {} // expected-note {{previous declaration is here}}
+ ~d_h() {} // expected-note {{previous definition is here}}
__host__ ~d_h() {} // expected-error {{destructor cannot be redeclared}}
};
diff --git a/test/SemaCUDA/no-destructor-overload.cu b/test/SemaCUDA/no-destructor-overload.cu
index aa6971ee8c..32dbb8db76 100644
--- a/test/SemaCUDA/no-destructor-overload.cu
+++ b/test/SemaCUDA/no-destructor-overload.cu
@@ -7,27 +7,27 @@
// giant change to clang, and the use cases seem quite limited.
struct A {
- ~A() {} // expected-note {{previous declaration is here}}
+ ~A() {} // expected-note {{previous definition is here}}
__device__ ~A() {} // expected-error {{destructor cannot be redeclared}}
};
struct B {
- __host__ ~B() {} // expected-note {{previous declaration is here}}
+ __host__ ~B() {} // expected-note {{previous definition is here}}
__host__ __device__ ~B() {} // expected-error {{destructor cannot be redeclared}}
};
struct C {
- __host__ __device__ ~C() {} // expected-note {{previous declaration is here}}
+ __host__ __device__ ~C() {} // expected-note {{previous definition is here}}
__host__ ~C() {} // expected-error {{destructor cannot be redeclared}}
};
struct D {
- __device__ ~D() {} // expected-note {{previous declaration is here}}
+ __device__ ~D() {} // expected-note {{previous definition is here}}
__host__ __device__ ~D() {} // expected-error {{destructor cannot be redeclared}}
};
struct E {
- __host__ __device__ ~E() {} // expected-note {{previous declaration is here}}
+ __host__ __device__ ~E() {} // expected-note {{previous definition is here}}
__device__ ~E() {} // expected-error {{destructor cannot be redeclared}}
};
diff --git a/test/SemaCXX/Inputs/nullability-completeness.h b/test/SemaCXX/Inputs/nullability-completeness.h
new file mode 100644
index 0000000000..1b30e1b4d9
--- /dev/null
+++ b/test/SemaCXX/Inputs/nullability-completeness.h
@@ -0,0 +1,4 @@
+template<typename T> struct Template final {
+ int *_Nonnull x;
+ T y;
+};
diff --git a/test/SemaCXX/Inputs/std-coroutine.h b/test/SemaCXX/Inputs/std-coroutine.h
new file mode 100644
index 0000000000..7a424f1e99
--- /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/Inputs/warn-zero-nullptr.h b/test/SemaCXX/Inputs/warn-zero-nullptr.h
new file mode 100644
index 0000000000..9b86c4b7b0
--- /dev/null
+++ b/test/SemaCXX/Inputs/warn-zero-nullptr.h
@@ -0,0 +1,3 @@
+#define NULL (0)
+#define SYSTEM_MACRO (0)
+#define OTHER_SYSTEM_MACRO (NULL)
diff --git a/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp b/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp
deleted file mode 100644
index 3b80d0937e..0000000000
--- a/test/SemaCXX/MicrosoftCompatibility-cxx98.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -std=c++98 -Wmicrosoft -verify -fms-compatibility -fexceptions -fcxx-exceptions
-
-
-//MSVC allows forward enum declaration
-enum ENUM; // expected-warning {{forward references to 'enum' types are a Microsoft extension}}
-ENUM *var = 0;
-ENUM var2 = (ENUM)3;
-enum ENUM1* var3 = 0;// expected-warning {{forward references to 'enum' types are a Microsoft extension}}
-
-typedef void (*FnPtrTy)();
-void (*PR23733_1)() = static_cast<FnPtrTy>((void *)0); // expected-warning {{static_cast between pointer-to-function and pointer-to-object is a Microsoft extension}}
-void (*PR23733_2)() = FnPtrTy((void *)0);
-void (*PR23733_3)() = (FnPtrTy)((void *)0);
-void (*PR23733_4)() = reinterpret_cast<FnPtrTy>((void *)0);
-
-long function_prototype(int a);
-long (*function_ptr)(int a);
-
-void function_to_voidptr_conv() {
- void *a1 = function_prototype; // expected-warning {{implicit conversion between pointer-to-function and pointer-to-object is a Microsoft extension}}
- void *a2 = &function_prototype; // expected-warning {{implicit conversion between pointer-to-function and pointer-to-object is a Microsoft extension}}
- void *a3 = function_ptr; // expected-warning {{implicit conversion between pointer-to-function and pointer-to-object is a Microsoft extension}}
-}
diff --git a/test/SemaCXX/MicrosoftCompatibility.cpp b/test/SemaCXX/MicrosoftCompatibility.cpp
index 26cd7825ee..d095f6edc6 100644
--- a/test/SemaCXX/MicrosoftCompatibility.cpp
+++ b/test/SemaCXX/MicrosoftCompatibility.cpp
@@ -224,6 +224,15 @@ template void function_missing_typename<D>(const D::Type param);
}
+//MSVC allows forward enum declaration
+enum ENUM; // expected-warning {{forward references to 'enum' types are a Microsoft extension}}
+ENUM *var = 0;
+ENUM var2 = (ENUM)3;
+enum ENUM1* var3 = 0;// expected-warning {{forward references to 'enum' types are a Microsoft extension}}
+
+enum ENUM1 { kA };
+enum ENUM1; // This way round is fine.
+
enum ENUM2 {
ENUM2_a = (enum ENUM2) 4,
ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
@@ -269,3 +278,18 @@ void g() {
f(0xffffffffffffffffi64);
}
}
+
+typedef void (*FnPtrTy)();
+void (*PR23733_1)() = static_cast<FnPtrTy>((void *)0); // expected-warning {{static_cast between pointer-to-function and pointer-to-object is a Microsoft extension}}
+void (*PR23733_2)() = FnPtrTy((void *)0);
+void (*PR23733_3)() = (FnPtrTy)((void *)0);
+void (*PR23733_4)() = reinterpret_cast<FnPtrTy>((void *)0);
+
+long function_prototype(int a);
+long (*function_ptr)(int a);
+
+void function_to_voidptr_conv() {
+ void *a1 = function_prototype; // expected-warning {{implicit conversion between pointer-to-function and pointer-to-object is a Microsoft extension}}
+ void *a2 = &function_prototype; // expected-warning {{implicit conversion between pointer-to-function and pointer-to-object is a Microsoft extension}}
+ void *a3 = function_ptr; // expected-warning {{implicit conversion between pointer-to-function and pointer-to-object is a Microsoft extension}}
+}
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 96088a0845..c605dcb912 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -2,6 +2,7 @@
// 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
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -std=c++11 -fms-compatibility -verify -DTEST3
#if TEST1
@@ -503,11 +504,32 @@ struct S {
int S::fn() { return 0; } // expected-warning {{is missing exception specification}}
}
+class PR34109_class {
+ PR34109_class() {}
+ virtual ~PR34109_class() {}
+};
+
+void operator delete(void *) throw();
+// expected-note@-1 {{previous declaration is here}}
+__declspec(dllexport) void operator delete(void *) throw();
+// expected-error@-1 {{redeclaration of 'operator delete' cannot add 'dllexport' attribute}}
+
+void PR34109(int* a) {
+ delete a;
+}
+
#elif TEST2
// Check that __unaligned is not recognized if MS extensions are not enabled
typedef char __unaligned *aligned_type; // expected-error {{expected ';' after top level declarator}}
+#elif TEST3
+
+namespace PR32750 {
+template<typename T> struct A {};
+template<typename T> struct B : A<A<T>> { A<T>::C::D d; }; // expected-error {{missing 'typename' prior to dependent type name 'A<T>::C::D'}}
+}
+
#else
#error Unknown test mode
diff --git a/test/SemaCXX/P30636.cpp b/test/SemaCXX/P30636.cpp
new file mode 100644
index 0000000000..2e2affb0cf
--- /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/PR16677.cpp b/test/SemaCXX/PR16677.cpp
index 7140ac79f0..efa4faaacd 100644
--- a/test/SemaCXX/PR16677.cpp
+++ b/test/SemaCXX/PR16677.cpp
@@ -10,7 +10,6 @@ class Base { };
template<class T, // Should be angle bracket instead of comma
class Derived : public Base<T> { // expected-error{{'Derived' cannot be defined in a type specifier}}
Class_With_Destructor member;
-}; // expected-error{{a non-type template parameter cannot have type 'class Derived'}}
- // expected-error@-1{{expected ',' or '>' in template-parameter-list}}
- // expected-warning@-2{{declaration does not declare anything}}
+}; // expected-error{{expected ',' or '>' in template-parameter-list}}
+ // expected-warning@-1{{declaration does not declare anything}}
diff --git a/test/SemaCXX/PR27037.cpp b/test/SemaCXX/PR27037.cpp
new file mode 100644
index 0000000000..422de0e637
--- /dev/null
+++ b/test/SemaCXX/PR27037.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {
+ void f();
+};
+
+struct B : A {};
+
+void m() {
+ const B b;
+ (b.*&B::f)(); // expected-error{{drops 'const' qualifier}}
+ ((&b)->*&B::f)(); // expected-error{{drops 'const' qualifier}}
+}
diff --git a/test/SemaCXX/accessible-base.cpp b/test/SemaCXX/accessible-base.cpp
index 6bf06ce126..2796985850 100644
--- a/test/SemaCXX/accessible-base.cpp
+++ b/test/SemaCXX/accessible-base.cpp
@@ -1,10 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMS -fms-compatibility -Wmicrosoft-inaccessible-base -fsyntax-only -verify %s
struct A {
int a;
};
-struct X1 : virtual A
+struct X1 : virtual A
{};
struct Y1 : X1, virtual A
@@ -13,7 +14,7 @@ struct Y1 : X1, virtual A
struct Y2 : X1, A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n struct Y2 -> struct X1 -> struct A\n struct Y2 -> struct A}}
{};
-struct X2 : A
+struct X2 : A
{};
struct Z1 : X2, virtual A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n struct Z1 -> struct X2 -> struct A\n struct Z1 -> struct A}}
@@ -21,3 +22,30 @@ struct Z1 : X2, virtual A // expected-warning{{direct base 'A' is inaccessible d
struct Z2 : X2, A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n struct Z2 -> struct X2 -> struct A\n struct Z2 -> struct A}}
{};
+
+A *y2_to_a(Y2 *p) {
+#ifdef MS
+ // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Y2' is a Microsoft extension}}
+#else
+ // expected-error@+2 {{ambiguous conversion}}
+#endif
+ return p;
+}
+
+A *z1_to_a(Z1 *p) {
+#ifdef MS
+ // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Z1' is a Microsoft extension}}
+#else
+ // expected-error@+2 {{ambiguous conversion}}
+#endif
+ return p;
+}
+
+A *z1_to_a(Z2 *p) {
+#ifdef MS
+ // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Z2' is a Microsoft extension}}
+#else
+ // expected-error@+2 {{ambiguous conversion}}
+#endif
+ return p;
+}
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index 7b6abd22ac..514473f9bc 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
// Verify that using an initializer list for a non-aggregate looks for
// constructors..
@@ -150,3 +150,33 @@ namespace ProtectedBaseCtor {
// expected-error@-5 {{protected constructor}}
// expected-note@-30 {{here}}
}
+
+namespace IdiomaticStdArrayInitDoesNotWarn {
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wmissing-braces"
+ template<typename T, int N> struct StdArray {
+ T contents[N];
+ };
+ StdArray<int, 3> x = {1, 2, 3};
+
+ template<typename T, int N> struct ArrayAndSomethingElse {
+ T contents[N];
+ int something_else;
+ };
+ ArrayAndSomethingElse<int, 3> y = {1, 2, 3}; // expected-warning {{suggest braces}}
+
+#if __cplusplus >= 201703L
+ template<typename T, int N> struct ArrayAndBaseClass : StdArray<int, 3> {
+ T contents[N];
+ };
+ ArrayAndBaseClass<int, 3> z = {1, 2, 3}; // expected-warning {{suggest braces}}
+
+ // It's not clear whether we should be warning in this case. If this
+ // pattern becomes idiomatic, it would be reasonable to suppress the
+ // warning here too.
+ template<typename T, int N> struct JustABaseClass : StdArray<T, N> {};
+ JustABaseClass<int, 3> w = {1, 2, 3}; // expected-warning {{suggest braces}}
+#endif
+
+#pragma clang diagnostic pop
+}
diff --git a/test/SemaCXX/alloc-align-attr.cpp b/test/SemaCXX/alloc-align-attr.cpp
new file mode 100644
index 0000000000..74cfb7d7e4
--- /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 3517466177..92f02838ad 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/amdgpu-sizeof-alignof.cpp b/test/SemaCXX/amdgpu-sizeof-alignof.cpp
new file mode 100644
index 0000000000..97da71a1a3
--- /dev/null
+++ b/test/SemaCXX/amdgpu-sizeof-alignof.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple amdgcn---amdgiz -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __attribute__((address_space(1))) void *global_ptr_t;
+typedef __attribute__((address_space(2))) void *constant_ptr_t;
+typedef __attribute__((address_space(3))) void *local_ptr_t;
+typedef __attribute__((address_space(5))) void *private_ptr_t;
+
+void test() {
+ static_assert(sizeof(size_t) == 8, "bad size");
+ static_assert(alignof(size_t) == 8, "bad alignment");
+ static_assert(sizeof(intptr_t) == 8, "bad size");
+ static_assert(alignof(intptr_t) == 8, "bad alignment");
+ static_assert(sizeof(uintptr_t) == 8, "bad size");
+ static_assert(alignof(uintptr_t) == 8, "bad alignment");
+ static_assert(sizeof(ptrdiff_t) == 8, "bad size");
+ static_assert(alignof(ptrdiff_t) == 8, "bad alignment");
+
+ static_assert(sizeof(char) == 1, "bad size");
+ static_assert(alignof(char) == 1, "bad alignment");
+ static_assert(sizeof(short) == 2, "bad size");
+ static_assert(alignof(short) == 2, "bad alignment");
+ static_assert(sizeof(int) == 4, "bad size");
+ static_assert(alignof(int) == 4, "bad alignment");
+ static_assert(sizeof(long) == 8, "bad size");
+ static_assert(alignof(long) == 8, "bad alignment");
+ static_assert(sizeof(long long) == 8, "bad size");
+ static_assert(alignof(long long) == 8, "bad alignment");
+ static_assert(sizeof(float) == 4, "bad size");
+ static_assert(alignof(float) == 4, "bad alignment");
+ static_assert(sizeof(double) == 8, "bad size");
+ static_assert(alignof(double) == 8, "bad alignment");
+
+ static_assert(sizeof(void*) == 8, "bad size");
+ static_assert(alignof(void*) == 8, "bad alignment");
+ static_assert(sizeof(global_ptr_t) == 8, "bad size");
+ static_assert(alignof(global_ptr_t) == 8, "bad alignment");
+ static_assert(sizeof(constant_ptr_t) == 8, "bad size");
+ static_assert(alignof(constant_ptr_t) == 8, "bad alignment");
+ static_assert(sizeof(local_ptr_t) == 4, "bad size");
+ static_assert(alignof(local_ptr_t) == 4, "bad alignment");
+ static_assert(sizeof(private_ptr_t) == 4, "bad size");
+ static_assert(alignof(private_ptr_t) == 4, "bad alignment");
+}
diff --git a/test/SemaCXX/anonymous-struct.cpp b/test/SemaCXX/anonymous-struct.cpp
index b584f89ff4..bb7e6eb92d 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/attr-cxx-disabled.cpp b/test/SemaCXX/attr-cxx-disabled.cpp
new file mode 100644
index 0000000000..a1a7533bd8
--- /dev/null
+++ b/test/SemaCXX/attr-cxx-disabled.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -fno-double-square-bracket-attributes -verify -pedantic -std=c++11 -DERRORS %s
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify -pedantic -std=c++11 %s
+
+struct [[]] S {};
+
+#ifdef ERRORS
+// expected-error@-3 {{declaration of anonymous struct must be a definition}}
+// expected-warning@-4 {{declaration does not declare anything}}
+#else
+// expected-no-diagnostics
+#endif
+
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
index eab5a1c0ec..5ba55f0c23 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}}
@@ -199,8 +199,8 @@ namespace test5 {
// rdar://problem/8518751
namespace test6 {
- enum __attribute__((deprecated)) A { // expected-note {{'A' has been explicitly marked deprecated here}}
- a0 // expected-note {{'a0' has been explicitly marked deprecated here}}
+ enum __attribute__((deprecated)) A { // expected-note 2 {{'A' has been explicitly marked deprecated here}}
+ a0
};
void testA() {
A x; // expected-warning {{'A' is deprecated}}
@@ -218,8 +218,8 @@ namespace test6 {
}
template <class T> struct C {
- enum __attribute__((deprecated)) Enum { // expected-note {{'Enum' has been explicitly marked deprecated here}}
- c0 // expected-note {{'c0' has been explicitly marked deprecated here}}
+ enum __attribute__((deprecated)) Enum { // expected-note 2 {{'Enum' has been explicitly marked deprecated here}}
+ c0
};
};
void testC() {
diff --git a/test/SemaCXX/attr-flag-enum-reject.cpp b/test/SemaCXX/attr-flag-enum-reject.cpp
deleted file mode 100644
index f28d60c0c2..0000000000
--- 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-non-x86-no_caller_saved_registers.cpp b/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp
new file mode 100644
index 0000000000..e31a16e340
--- /dev/null
+++ b/test/SemaCXX/attr-non-x86-no_caller_saved_registers.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++11 -triple armv7-unknown-linux-gnueabi -fsyntax-only -verify %s
+
+struct a {
+ int __attribute__((no_caller_saved_registers)) b; // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+ static void foo(int *a) __attribute__((no_caller_saved_registers)) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+};
+
+struct a test __attribute__((no_caller_saved_registers)); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+
+__attribute__((no_caller_saved_registers(999))) void bar(int *) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+
+__attribute__((no_caller_saved_registers)) void foo(int *){} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+
+[[gnu::no_caller_saved_registers]] void foo2(int *) {} // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+
+typedef __attribute__((no_caller_saved_registers)) void (*foo3)(int *); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+
+typedef void (*foo5)(int *);
+
+int (*foo4)(double a, __attribute__((no_caller_saved_registers)) float b); // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+
+int main(int argc, char **argv) {
+ void (*fp)(int *) = foo;
+ a::foo(&argc);
+ foo3 func = foo2;
+ func(&argc);
+ foo5 __attribute__((no_caller_saved_registers)) func2 = foo2; // expected-warning {{unknown attribute 'no_caller_saved_registers' ignored}}
+ return 0;
+}
diff --git a/test/SemaCXX/attr-require-constant-initialization.cpp b/test/SemaCXX/attr-require-constant-initialization.cpp
index 3ed51071cd..0df9f2e880 100644
--- a/test/SemaCXX/attr-require-constant-initialization.cpp
+++ b/test/SemaCXX/attr-require-constant-initialization.cpp
@@ -7,9 +7,9 @@
#define ATTR __attribute__((require_constant_initialization)) // expected-note 0+ {{expanded from macro}}
-int ReturnInt();
+int ReturnInt(); // expected-note 0+ {{declared here}}
-struct PODType {
+struct PODType { // expected-note 0+ {{declared here}}
int value;
int value2;
};
@@ -20,20 +20,20 @@ struct PODType {
struct LitType {
constexpr LitType() : value(0) {}
constexpr LitType(int x) : value(x) {}
- LitType(void *) : value(-1) {}
+ LitType(void *) : value(-1) {} // expected-note 0+ {{declared here}}
int value;
};
#endif
-struct NonLit {
+struct NonLit { // expected-note 0+ {{declared here}}
#if __cplusplus >= 201402L
constexpr NonLit() : value(0) {}
constexpr NonLit(int x) : value(x) {}
#else
- NonLit() : value(0) {}
+ NonLit() : value(0) {} // expected-note 0+ {{declared here}}
NonLit(int x) : value(x) {}
#endif
- NonLit(void *) : value(-1) {}
+ NonLit(void *) : value(-1) {} // expected-note 0+ {{declared here}}
~NonLit() {}
int value;
};
@@ -43,7 +43,7 @@ struct StoresNonLit {
constexpr StoresNonLit() : obj() {}
constexpr StoresNonLit(int x) : obj(x) {}
#else
- StoresNonLit() : obj() {}
+ StoresNonLit() : obj() {} // expected-note 0+ {{declared here}}
StoresNonLit(int x) : obj(x) {}
#endif
StoresNonLit(void *p) : obj(p) {}
@@ -82,6 +82,12 @@ 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_initialization' attribute here}}
+#if __cplusplus >= 201103L
+ // expected-note@-3 {{reference to 'non_global' is not a constant expression}}
+ // expected-note@-5 {{declared here}}
+#else
+ // expected-note@-6 {{subexpression not valid in a constant expression}}
+#endif
ATTR static const int &global_init = glvalue_int;
ATTR static const int &temp_init = 42;
}
@@ -89,8 +95,18 @@ void test_basic_start_static_2_1() {
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_initialization' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note@-3 {{non-literal type 'const NonLit' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
#if __cplusplus >= 201103L
ATTR const LitType &lit_temp_ref = 42;
@@ -99,6 +115,11 @@ ATTR const int &subobj_ref = LitType{}.value;
ATTR const int &nl_subobj_ref = NonLit().value; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note-re@-3 {{non-literal type '{{.*}}' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
struct TT1 {
ATTR static const int &no_init;
@@ -116,6 +137,8 @@ const int &TT1::subobj_init = PODType().value;
#if __cplusplus >= 201103L
thread_local const int &TT1::tl_glvalue_init = glvalue_int;
thread_local const int &TT1::tl_temp_init = 42; // expected-error {{variable does not have a constant initializer}}
+// expected-note@-1 {{reference to temporary is not a constant expression}}
+// expected-note@-2 {{temporary created here}}
#endif
// [basic.start.static]p2.2
@@ -129,17 +152,25 @@ void test_basic_start_static_2_2() {
#else
ATTR static PODType pod; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'PODType' cannot be used in a constant expression}}
#endif
ATTR static PODType pot2 = {ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
#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_initialization' attribute here}}
+ // expected-note@-2 {{non-constexpr constructor 'LitType' cannot be used in a constant expression}}
ATTR static LitType static_lit3 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+ // expected-note@-2 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
ATTR thread_local LitType tls = 42;
#endif
}
@@ -157,15 +188,23 @@ struct TT2 {
ATTR static const NonLit non_lit_copy_init; // expected-note {{required by 'require_constant_initialization' attribute here}}
#endif
};
-PODType TT2::pod_noinit;
+PODType TT2::pod_noinit; // expected-note 0+ {{declared here}}
#if __cplusplus >= 201103L
// expected-error@-2 {{variable does not have a constant initializer}}
+// expected-note@-3 {{non-constexpr constructor 'PODType' cannot be used in a constant expression}}
#endif
PODType TT2::pod_copy_init(TT2::pod_noinit); // expected-error {{variable does not have a constant initializer}}
+#if __cplusplus >= 201103L
+// expected-note@-2 {{read of non-constexpr variable 'pod_noinit' is not allowed in a constant expression}}
+// expected-note@-3 {{in call to 'PODType(pod_noinit)'}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
#if __cplusplus >= 201402L
const NonLit TT2::non_lit(42);
const NonLit TT2::non_lit_list_init = {42};
const NonLit TT2::non_lit_copy_init = 42; // expected-error {{variable does not have a constant initializer}}
+// expected-note@-1 {{subexpression not valid in a constant expression}}
#endif
#if __cplusplus >= 201103L
@@ -183,19 +222,25 @@ ATTR StoresNonLit snl;
#else
ATTR NonLit nl_ctor; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR NonLit nl_ctor2{}; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR NonLit nl_ctor3 = {}; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR thread_local NonLit nl_ctor_tl = {}; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR StoresNonLit snl; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'StoresNonLit' cannot be used in a constant expression}}
#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_initialization' attribute here}}
+// expected-note@-2 {{non-literal type 'NonLit' cannot be used in a constant expression}}
ATTR int lit_in_init = LitType{42}.value;
#endif
@@ -218,6 +263,11 @@ 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_initialization' attribute here}}
+#if __cplusplus >= 201103L
+// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
+#else
+// expected-note@-5 {{subexpression not valid in a constant expression}}
+#endif
#if __cplusplus >= 201103L
ATTR int val_init{};
@@ -233,15 +283,17 @@ typedef const char *StrType;
// initializer
struct NotC {
constexpr NotC(void *) {}
- NotC(int) {}
+ NotC(int) {} // expected-note 0+ {{declared here}}
};
template <class T>
struct TestCtor {
constexpr TestCtor(int x) : value(x) {}
+ // expected-note@-1 {{non-constexpr constructor 'NotC' cannot be used in a constant expression}}
T value;
};
ATTR TestCtor<NotC> t(42); // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{in call to 'TestCtor(42)'}}
#endif
// Test various array types
@@ -261,9 +313,11 @@ struct TestCtor {
ATTR LitType non_const_lit(nullptr); // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
+// expected-note@-2 {{non-constexpr constructor 'LitType' cannot be used in a constant expression}}
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_initialization' attribute here}}
+// expected-note@-3 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
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/attr-selectany.cpp b/test/SemaCXX/attr-selectany.cpp
index 9dc14b3c38..4afcb8130a 100644
--- a/test/SemaCXX/attr-selectany.cpp
+++ b/test/SemaCXX/attr-selectany.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-win32-macho -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s
+
// MSVC produces similar diagnostics.
__declspec(selectany) void foo() { } // expected-error{{'selectany' can only be applied to data items with external linkage}}
diff --git a/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp b/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp
new file mode 100644
index 0000000000..55500519c4
--- /dev/null
+++ b/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s
+
+struct a {
+ int b __attribute__((no_caller_saved_registers)); // expected-warning {{'no_caller_saved_registers' only applies to function types; type here is 'int'}}
+ static void foo(int *a) __attribute__((no_caller_saved_registers)) {}
+};
+
+struct a test __attribute__((no_caller_saved_registers)); // expected-warning {{'no_caller_saved_registers' only applies to function types; type here is 'struct a'}}
+
+__attribute__((no_caller_saved_registers(999))) void bar(int *) {} // expected-error {{'no_caller_saved_registers' attribute takes no arguments}}
+
+void __attribute__((no_caller_saved_registers)) foo(int *){}
+
+[[gnu::no_caller_saved_registers]] void foo2(int *) {}
+
+typedef __attribute__((no_caller_saved_registers)) void (*foo3)(int *);
+
+int (*foo4)(double a, __attribute__((no_caller_saved_registers)) float b); // expected-warning {{'no_caller_saved_registers' only applies to function types; type here is 'float'}}
+
+typedef void (*foo5)(int *);
+
+void foo6(){} // expected-note {{previous declaration is here}}
+
+void __attribute__((no_caller_saved_registers)) foo6(); // expected-error {{function declared with 'no_caller_saved_registers' attribute was previously declared without the 'no_caller_saved_registers' attribute}}
+
+int main(int argc, char **argv) {
+ void (*fp)(int *) = foo; // expected-error {{cannot initialize a variable of type 'void (*)(int *)' with an lvalue of type 'void (int *) __attribute__((no_caller_saved_registers))'}}
+ a::foo(&argc);
+ foo3 func = foo2;
+ func(&argc);
+ foo5 __attribute__((no_caller_saved_registers)) func2 = foo2;
+ return 0;
+}
diff --git a/test/SemaCXX/co_await-range-for.cpp b/test/SemaCXX/co_await-range-for.cpp
new file mode 100644
index 0000000000..4d999ea7db
--- /dev/null
+++ b/test/SemaCXX/co_await-range-for.cpp
@@ -0,0 +1,165 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN: -fblocks
+#include "Inputs/std-coroutine.h"
+
+using namespace std::experimental;
+
+
+template <class Begin>
+struct Awaiter {
+ bool await_ready();
+ void await_suspend(coroutine_handle<>);
+ Begin await_resume();
+};
+
+template <class Iter> struct BeginTag { BeginTag() = delete; };
+template <class Iter> struct IncTag { IncTag() = delete; };
+
+template <class Iter, bool Delete = false>
+struct CoawaitTag { CoawaitTag() = delete; };
+
+template <class T>
+struct Iter {
+ using value_type = T;
+ using reference = T &;
+ using pointer = T *;
+
+ IncTag<Iter> operator++();
+ reference operator*();
+ pointer operator->();
+};
+template <class T> bool operator==(Iter<T>, Iter<T>);
+template <class T> bool operator!=(Iter<T>, Iter<T>);
+
+template <class T>
+struct Range {
+ BeginTag<Iter<T>> begin();
+ Iter<T> end();
+};
+
+struct MyForLoopArrayAwaiter {
+ struct promise_type {
+ MyForLoopArrayAwaiter get_return_object() { return {}; }
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ template <class T>
+ Awaiter<T *> await_transform(T *) = delete; // expected-note {{explicitly deleted}}
+ };
+};
+MyForLoopArrayAwaiter g() {
+ int arr[10] = {0};
+ for co_await(auto i : arr) {}
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+
+struct ForLoopAwaiterBadBeginTransform {
+ struct promise_type {
+ ForLoopAwaiterBadBeginTransform get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+
+ template <class T>
+ Awaiter<T> await_transform(BeginTag<T>) = delete; // expected-note 1+ {{explicitly deleted}}
+
+ template <class T>
+ CoawaitTag<T> await_transform(IncTag<T>); // expected-note 1+ {{candidate}}
+ };
+};
+ForLoopAwaiterBadBeginTransform bad_begin() {
+ Range<int> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+template <class Dummy>
+ForLoopAwaiterBadBeginTransform bad_begin_template(Dummy) {
+ Range<Dummy> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{call to deleted member function 'await_transform'}}
+ // expected-note@-2 {{'await_transform' implicitly required by 'co_await' here}}
+}
+template ForLoopAwaiterBadBeginTransform bad_begin_template(int); // expected-note {{requested here}}
+
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, true>) = delete;
+// expected-note@-1 1+ {{explicitly deleted}}
+
+struct ForLoopAwaiterBadIncTransform {
+ struct promise_type {
+ ForLoopAwaiterBadIncTransform get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+
+ template <class T>
+ Awaiter<T> await_transform(BeginTag<T> e);
+
+ template <class T>
+ CoawaitTag<T, true> await_transform(IncTag<T>);
+ };
+};
+ForLoopAwaiterBadIncTransform bad_inc_transform() {
+ Range<float> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
+ // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<float>'}}
+}
+
+template <class Dummy>
+ForLoopAwaiterBadIncTransform bad_inc_transform_template(Dummy) {
+ Range<Dummy> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{overload resolution selected deleted operator 'co_await'}}
+ // expected-note@-2 {{in implicit call to 'operator++' for iterator of type 'Range<long>'}}
+}
+template ForLoopAwaiterBadIncTransform bad_inc_transform_template(long); // expected-note {{requested here}}
+
+// Ensure we mark and check the function as a coroutine even if it's
+// never instantiated.
+template <class T>
+constexpr void never_instant(T) {
+ static_assert(sizeof(T) != sizeof(T), "function should not be instantiated");
+ for co_await(auto i : foo(T{})) {}
+ // expected-error@-1 {{'co_await' cannot be used in a constexpr function}}
+}
+
+namespace NS {
+struct ForLoopAwaiterCoawaitLookup {
+ struct promise_type {
+ ForLoopAwaiterCoawaitLookup get_return_object();
+ void return_void();
+ void unhandled_exception();
+ suspend_never initial_suspend();
+ suspend_never final_suspend();
+ template <class T>
+ CoawaitTag<T, false> await_transform(BeginTag<T> e);
+ template <class T>
+ Awaiter<T> await_transform(IncTag<T>);
+ };
+};
+} // namespace NS
+using NS::ForLoopAwaiterCoawaitLookup;
+
+template <class T>
+ForLoopAwaiterCoawaitLookup test_coawait_lookup(T) {
+ Range<T> R;
+ for co_await(auto i : R) {}
+ // expected-error@-1 {{no member named 'await_ready' in 'CoawaitTag<Iter<int>, false>'}}
+}
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(int); // expected-note {{requested here}}
+
+// FIXME: This test should fail as well since the newly declared operator co_await
+// should not be found by lookup.
+namespace NS2 {
+template <class Iter>
+Awaiter<Iter> operator co_await(CoawaitTag<Iter, false>);
+}
+using NS2::operator co_await;
+template ForLoopAwaiterCoawaitLookup test_coawait_lookup(long);
diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp
index 0528b044fb..1d940be629 100644
--- a/test/SemaCXX/compare.cpp
+++ b/test/SemaCXX/compare.cpp
@@ -73,7 +73,7 @@ int test0(long a, unsigned long b) {
((int) a == (unsigned int) B) +
((short) a == (unsigned short) B) +
((signed char) a == (unsigned char) B) +
- (a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
+ (a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
(a < (unsigned int) B) +
(a < (unsigned short) B) +
(a < (unsigned char) B) +
@@ -81,8 +81,8 @@ int test0(long a, unsigned long b) {
((int) a < B) +
((short) a < B) +
((signed char) a < B) +
- ((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
- ((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}}
+ ((long) a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ ((int) a < (unsigned int) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
((short) a < (unsigned short) B) +
((signed char) a < (unsigned char) B) +
diff --git a/test/SemaCXX/complex-conversion.cpp b/test/SemaCXX/complex-conversion.cpp
new file mode 100644
index 0000000000..e8f0995816
--- /dev/null
+++ b/test/SemaCXX/complex-conversion.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T> void take(T);
+
+void func(float Real, _Complex float Complex) {
+ Real += Complex; // expected-error {{assigning to 'float' from incompatible type '_Complex float'}}
+ Real += (float)Complex;
+
+ Real = Complex; // expected-error {{implicit conversion from '_Complex float' to 'float' is not permitted in C++}}
+ Real = (float)Complex;
+
+ take<float>(Complex); // expected-error {{implicit conversion from '_Complex float' to 'float' is not permitted in C++}}
+ take<double>(1.0i); // expected-error {{implicit conversion from '_Complex double' to 'double' is not permitted in C++}}
+ take<_Complex float>(Complex);
+
+ // Conversion to bool doesn't actually discard the imaginary part.
+ take<bool>(Complex);
+}
diff --git a/test/SemaCXX/complex-overload.cpp b/test/SemaCXX/complex-overload.cpp
index 1381968751..9373e44de9 100644
--- a/test/SemaCXX/complex-overload.cpp
+++ b/test/SemaCXX/complex-overload.cpp
@@ -4,9 +4,10 @@ char *foo(float);
void test_foo_1(float fv, double dv, float _Complex fc, double _Complex dc) {
char *cp1 = foo(fv);
char *cp2 = foo(dv);
- // Note: GCC and EDG reject these two, but they are valid C99 conversions
- char *cp3 = foo(fc);
- char *cp4 = foo(dc);
+ // Note: GCC and EDG reject these two, they are valid C99 conversions but
+ // shouldn't be accepted in C++ because the result is surprising.
+ char *cp3 = foo(fc); // expected-error {{implicit conversion from '_Complex float' to 'float' is not permitted in C++}}
+ char *cp4 = foo(dc); // expected-error {{implicit conversion from '_Complex double' to 'float' is not permitted in C++}}
}
int *foo(float _Complex);
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 4abbc8e928..51dd6199e6 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -328,7 +328,7 @@ struct Str {
extern char externalvar[];
constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} expected-note {{reinterpret_cast}}
-constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}}
+constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}}
static_assert(0 != "foo", "");
}
@@ -364,7 +364,7 @@ void foo() {
constexpr B b3 { { 1 }, { 2 } }; // expected-error {{constant expression}} expected-note {{reference to temporary}} expected-note {{here}}
}
-constexpr B &&b4 = ((1, 2), 3, 4, B { {10}, {{20}} }); // expected-warning 4{{unused}}
+constexpr B &&b4 = ((1, 2), 3, 4, B { {10}, {{20}} });
static_assert(&b4 != &b2, "");
// Proposed DR: copy-elision doesn't trigger lifetime extension.
@@ -604,11 +604,38 @@ static_assert(NATDCArray{}[1][1].n == 0, "");
}
+// Per current CWG direction, we reject any cases where pointer arithmetic is
+// not statically known to be valid.
+namespace ArrayOfUnknownBound {
+ extern int arr[];
+ constexpr int *a = arr;
+ constexpr int *b = &arr[0];
+ static_assert(a == b, "");
+ constexpr int *c = &arr[1]; // expected-error {{constant}} expected-note {{indexing of array without known bound}}
+ constexpr int *d = &a[1]; // expected-error {{constant}} expected-note {{indexing of array without known bound}}
+ constexpr int *e = a + 1; // expected-error {{constant}} expected-note {{indexing of array without known bound}}
+
+ struct X {
+ int a;
+ int b[]; // expected-warning {{C99}}
+ };
+ extern X x;
+ constexpr int *xb = x.b; // expected-error {{constant}} expected-note {{not supported}}
+
+ struct Y { int a; };
+ extern Y yarr[];
+ constexpr Y *p = yarr;
+ constexpr int *q = &p->a;
+
+ extern const int carr[]; // expected-note {{here}}
+ constexpr int n = carr[0]; // expected-error {{constant}} expected-note {{non-constexpr variable}}
+}
+
namespace DependentValues {
struct I { int n; typedef I V[10]; };
I::V x, y;
-int g();
+int g(); // expected-note {{declared here}}
template<bool B, typename T> struct S : T {
int k;
void f() {
@@ -616,13 +643,23 @@ template<bool B, typename T> struct S : T {
I &i = cells[k];
switch (i.n) {}
- // FIXME: We should be able to diagnose this.
- constexpr int n = g();
+ constexpr int n = g(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr function 'g'}}
constexpr int m = this->g(); // ok, could be constexpr
}
};
+extern const int n;
+template<typename T> void f() {
+ // This is ill-formed, because a hypothetical instantiation at the point of
+ // template definition would be ill-formed due to a construct that does not
+ // depend on a template parameter.
+ constexpr int k = n; // expected-error {{must be initialized by a constant expression}}
+}
+// It doesn't matter that the instantiation could later become valid:
+constexpr int n = 4;
+template void f<int>();
+
}
namespace Class {
@@ -1894,6 +1931,22 @@ namespace Bitfields {
};
static_assert(X::f(3) == -1, "3 should truncate to -1");
}
+
+ struct HasUnnamedBitfield {
+ unsigned a;
+ unsigned : 20;
+ unsigned b;
+
+ constexpr HasUnnamedBitfield() : a(), b() {}
+ constexpr HasUnnamedBitfield(unsigned a, unsigned b) : a(a), b(b) {}
+ };
+
+ void testUnnamedBitfield() {
+ const HasUnnamedBitfield zero{};
+ int a = 1 / zero.b; // expected-warning {{division by zero is undefined}}
+ const HasUnnamedBitfield oneZero{1, 0};
+ int b = 1 / oneZero.b; // expected-warning {{division by zero is undefined}}
+ }
}
namespace ZeroSizeTypes {
@@ -1939,7 +1992,7 @@ namespace NeverConstantTwoWays {
constexpr int n = // expected-error {{must be initialized by a constant expression}}
(int *)(long)&n == &n ? // expected-note {{reinterpret_cast}}
- 1 / 0 : // expected-warning {{division by zero}}
+ 1 / 0 :
0;
}
diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp
index ac4e0fd471..12fec08516 100644
--- a/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -982,3 +982,42 @@ 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}}
}
+
+constexpr void Void(int n) {
+ void(n + 1);
+ void();
+}
+constexpr int void_test = (Void(0), 1);
+
+namespace PR19741 {
+constexpr void addone(int &m) { m++; }
+
+struct S {
+ int m = 0;
+ constexpr S() { addone(m); }
+};
+constexpr bool evalS() {
+ constexpr S s;
+ return s.m == 1;
+}
+static_assert(evalS(), "");
+
+struct Nested {
+ struct First { int x = 42; };
+ union {
+ First first;
+ int second;
+ };
+ int x;
+ constexpr Nested(int x) : first(), x(x) { x = 4; }
+ constexpr Nested() : Nested(42) {
+ addone(first.x);
+ x = 3;
+ }
+};
+constexpr bool evalNested() {
+ constexpr Nested N;
+ return N.first.x == 43;
+}
+static_assert(evalNested(), "");
+} // namespace PR19741
diff --git a/test/SemaCXX/constexpr-array-unknown-bound.cpp b/test/SemaCXX/constexpr-array-unknown-bound.cpp
new file mode 100644
index 0000000000..395c4cbd12
--- /dev/null
+++ b/test/SemaCXX/constexpr-array-unknown-bound.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++1z -fsyntax-only -verify
+
+const extern int arr[];
+constexpr auto p = arr; // ok
+constexpr int f(int i) {return p[i];} // expected-note {{read of dereferenced one-past-the-end pointer}}
+
+constexpr int arr[] {1, 2, 3};
+constexpr auto p2 = arr + 2; // ok
+constexpr int x = f(2); // ok
+constexpr int y = f(3); // expected-error {{constant expression}}
+// expected-note-re@-1 {{in call to 'f({{.*}})'}}
+
+// FIXME: consider permitting this case
+struct A {int m[];} a;
+constexpr auto p3 = a.m; // expected-error {{constant expression}} expected-note {{without known bound}}
+constexpr auto p4 = a.m + 1; // expected-error {{constant expression}} expected-note {{without known bound}}
+
+void g(int i) {
+ int arr[i];
+ constexpr auto *p = arr + 2; // expected-error {{constant expression}} expected-note {{without known bound}}
+
+ // FIXME: Give a better diagnostic here. The issue is that computing
+ // sizeof(*arr2) within the array indexing fails due to the VLA.
+ int arr2[2][i];
+ constexpr int m = ((void)arr2[2], 0); // expected-error {{constant expression}}
+}
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index c5de33cedb..102ff1e80d 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -302,3 +302,22 @@ namespace PR14073 {
struct S2 { union { union { int n; }; char c; }; S2() : n(n) {} }; // expected-warning {{field 'n' is uninitialized when used here}}
struct S3 { struct { int n; }; S3() : n(n) {} }; // expected-warning {{field 'n' is uninitialized when used here}}
}
+
+namespace PR10758 {
+struct A;
+struct B {
+ B (A const &); // expected-note 2 {{candidate constructor not viable: no known conversion from 'const PR10758::B' to 'const PR10758::A &' for 1st argument}}
+ B (B &); // expected-note 2 {{candidate constructor not viable: 1st argument ('const PR10758::B') would lose const qualifier}}
+};
+struct A {
+ A (B); // expected-note 2 {{passing argument to parameter here}}
+};
+
+B f(B const &b) {
+ return b; // expected-error {{no matching constructor for initialization of 'PR10758::B'}}
+}
+
+A f2(const B &b) {
+ return b; // expected-error {{no matching constructor for initialization of 'PR10758::B'}}
+}
+}
diff --git a/test/SemaCXX/coreturn.cpp b/test/SemaCXX/coreturn.cpp
index 2ec73916b8..7265d7c19c 100644
--- a/test/SemaCXX/coreturn.cpp
+++ b/test/SemaCXX/coreturn.cpp
@@ -1,24 +1,8 @@
-// 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
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify -fblocks -Wall -Wextra -Wno-error=unreachable-code
+#include "Inputs/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 *);
-};
-
-}
-}
+using std::experimental::suspend_always;
+using std::experimental::suspend_never;
struct awaitable {
bool await_ready();
@@ -26,23 +10,49 @@ struct awaitable {
void await_resume();
} a;
-struct suspend_always {
- bool await_ready() { return false; }
- void await_suspend(std::experimental::coroutine_handle<>) {}
- void await_resume() {}
-};
-
-struct suspend_never {
- bool await_ready() { return true; }
- void await_suspend(std::experimental::coroutine_handle<>) {}
- void await_resume() {}
-};
-
struct promise_void {
void get_return_object();
suspend_always initial_suspend();
suspend_always final_suspend();
void return_void();
+ void unhandled_exception();
+};
+
+struct promise_void_return_value {
+ void get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ void return_value(int);
+};
+
+struct VoidTagNoReturn {
+ struct promise_type {
+ VoidTagNoReturn get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ };
+};
+
+struct VoidTagReturnValue {
+ struct promise_type {
+ VoidTagReturnValue get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ void return_value(int);
+ };
+};
+
+struct VoidTagReturnVoid {
+ struct promise_type {
+ VoidTagReturnVoid get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ void return_void();
+ };
};
struct promise_float {
@@ -50,6 +60,7 @@ struct promise_float {
suspend_always initial_suspend();
suspend_always final_suspend();
void return_void();
+ void unhandled_exception();
};
struct promise_int {
@@ -57,10 +68,14 @@ struct promise_int {
suspend_always initial_suspend();
suspend_always final_suspend();
void return_value(int);
+ void unhandled_exception();
};
-template <typename... T>
-struct std::experimental::coroutine_traits<void, T...> { using promise_type = promise_void; };
+template <>
+struct std::experimental::coroutine_traits<void> { using promise_type = promise_void; };
+
+template <typename T1>
+struct std::experimental::coroutine_traits<void, T1> { using promise_type = promise_void_return_value; };
template <typename... T>
struct std::experimental::coroutine_traits<float, T...> { using promise_type = promise_float; };
@@ -73,10 +88,53 @@ float test1() { co_await a; }
int test2() {
co_await a;
-} // expected-warning {{control reaches end of non-void coroutine}}
+} // expected-warning {{control reaches end of coroutine; which is undefined behavior because the promise type 'std::experimental::coroutine_traits<int>::promise_type' (aka 'promise_int') does not declare 'return_void()'}}
+
+int test2a(bool b) {
+ if (b)
+ co_return 42;
+} // expected-warning {{control may reach end of coroutine; which is undefined behavior because the promise type 'std::experimental::coroutine_traits<int, bool>::promise_type' (aka 'promise_int') does not declare 'return_void()'}}
int test3() {
co_await a;
b:
goto b;
}
+
+int test4() {
+ co_return 42;
+}
+
+void test5(int) {
+ co_await a;
+} // expected-warning {{control reaches end of coroutine; which is undefined behavior because}}
+
+void test6(int x) {
+ if (x)
+ co_return 42;
+} // expected-warning {{control may reach end of coroutine; which is undefined behavior because}}
+
+void test7(int y) {
+ if (y)
+ co_return 42;
+ else
+ co_return 101;
+}
+
+VoidTagReturnVoid test8() {
+ co_await a;
+}
+
+VoidTagReturnVoid test9(bool b) {
+ if (b)
+ co_return;
+}
+
+VoidTagReturnValue test10() {
+ co_await a;
+} // expected-warning {{control reaches end of coroutine}}
+
+VoidTagReturnValue test11(bool b) {
+ if (b)
+ co_return 42;
+} // expected-warning {{control may reach end of coroutine}}
diff --git a/test/SemaCXX/coroutine-seh.cpp b/test/SemaCXX/coroutine-seh.cpp
new file mode 100644
index 0000000000..647bb68b31
--- /dev/null
+++ b/test/SemaCXX/coroutine-seh.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++1z -fcoroutines-ts -verify %s -fcxx-exceptions -fexceptions -triple x86_64-windows-msvc -fms-extensions
+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 *) noexcept;
+};
+template <> struct coroutine_handle<void> {
+ static coroutine_handle from_address(void *) noexcept;
+ coroutine_handle() = default;
+ template <class PromiseType>
+ coroutine_handle(coroutine_handle<PromiseType>) noexcept;
+};
+}
+
+struct suspend_always {
+ bool await_ready() noexcept;
+ void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+ void await_resume() noexcept;
+};
+
+template <> struct std::experimental::coroutine_traits<void> {
+ struct promise_type {
+ void get_return_object() noexcept;
+ suspend_always initial_suspend() noexcept;
+ suspend_always final_suspend() noexcept;
+ void return_void() noexcept;
+ void unhandled_exception() noexcept;
+ };
+};
+
+void SEH_used() {
+ __try { // expected-error {{cannot use SEH '__try' in a coroutine when C++ exceptions are enabled}}
+ co_return; // expected-note {{function is a coroutine due to use of 'co_return' here}}
+ } __except(0) {}
+}
diff --git a/test/SemaCXX/coroutine-unhandled_exception-warning.cpp b/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
new file mode 100644
index 0000000000..d819580462
--- /dev/null
+++ b/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN: -fblocks -Wno-unreachable-code -Wno-unused-value
+
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts \
+// RUN: -fsyntax-only -Wignored-qualifiers -Wno-error=return-type -verify \
+// RUN: -fblocks -Wno-unreachable-code -Wno-unused-value \
+// RUN: -DDISABLE_WARNING -Wno-coroutine-missing-unhandled-exception
+
+#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;
+
+#ifndef DISABLE_WARNING
+struct promise_void { // expected-note {{defined here}}
+#else
+struct promise_void {
+#endif
+ 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; };
+
+#ifndef DISABLE_WARNING
+void test0() { // expected-warning {{'promise_void' is required to declare the member 'unhandled_exception()' when exceptions are enabled}}
+ co_return;
+}
+#else
+void test0() { // expected-no-diagnostics
+ co_return;
+}
+#endif
diff --git a/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp b/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
new file mode 100644
index 0000000000..5bdb232d53
--- /dev/null
+++ b/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -std=c++14 -fcoroutines-ts -fsyntax-only -Wall -Wextra -Wuninitialized -fblocks
+#include "Inputs/std-coroutine.h"
+
+using namespace std::experimental;
+
+
+struct A {
+ bool await_ready() { return true; }
+ int await_resume() { return 42; }
+ template <typename F>
+ void await_suspend(F) {}
+};
+
+
+struct coro_t {
+ struct promise_type {
+ coro_t get_return_object() { return {}; }
+ suspend_never initial_suspend() { return {}; }
+ suspend_never final_suspend() { return {}; }
+ A yield_value(int) { return {}; }
+ void return_void() {}
+ static void unhandled_exception() {}
+ };
+};
+
+coro_t f(int n) {
+ if (n == 0)
+ co_return;
+ co_yield 42;
+ int x = co_await A{};
+}
+
+template <class Await>
+coro_t g(int n) {
+ if (n == 0)
+ co_return;
+ co_yield 42;
+ int x = co_await Await{};
+}
+
+int main() {
+ f(0);
+ g<A>(0);
+}
diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp
index 8876a14655..65e17abb11 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 -fcxx-exceptions
+// 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>}}
@@ -22,8 +22,24 @@ void no_coroutine_traits() {
namespace std {
namespace experimental {
-template <typename... T>
-struct coroutine_traits; // expected-note {{declared here}}
+
+template <class... Args>
+struct void_t_imp {
+ using type = void;
+};
+template <class... Args>
+using void_t = typename void_t_imp<Args...>::type;
+
+template <class T, class = void>
+struct traits_sfinae_base {};
+
+template <class T>
+struct traits_sfinae_base<T, void_t<typename T::promise_type>> {
+ using promise_type = typename T::promise_type;
+};
+
+template <class Ret, class... Args>
+struct coroutine_traits : public traits_sfinae_base<Ret> {};
}} // namespace std::experimental
template<typename Promise> struct coro {};
@@ -50,8 +66,15 @@ struct suspend_never {
void await_resume() {}
};
-void no_specialization() {
- co_await a; // expected-error {{implicit instantiation of undefined template 'std::experimental::coroutine_traits<void>'}}
+struct auto_await_suspend {
+ bool await_ready();
+ template <typename F> auto await_suspend(F) {}
+ void await_resume();
+};
+
+struct DummyVoidTag {};
+DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<DummyVoidTag>' has no member named 'promise_type'}}
+ co_await a;
}
template <typename... T>
@@ -101,6 +124,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 {
@@ -108,6 +132,7 @@ 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}}
@@ -140,6 +165,10 @@ void yield() {
co_yield yield; // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
}
+void check_auto_await_suspend() {
+ co_await auto_await_suspend{}; // Should compile successfully.
+}
+
void coreturn(int n) {
co_await a;
if (n == 0)
@@ -344,6 +373,8 @@ namespace dependent_operator_co_await_lookup {
transformed initial_suspend();
::adl_ns::coawait_arg_type final_suspend();
transformed await_transform(transform_awaitable);
+ void unhandled_exception();
+ void return_void();
};
template <class AwaitArg>
struct basic_promise {
@@ -351,6 +382,8 @@ namespace dependent_operator_co_await_lookup {
coro<basic_promise> get_return_object();
awaitable initial_suspend();
awaitable final_suspend();
+ void unhandled_exception();
+ void return_void();
};
awaitable operator co_await(await_arg_1);
@@ -435,6 +468,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();
};
};
@@ -467,6 +501,8 @@ namespace placeholder {
struct bad_promise_1 {
suspend_always initial_suspend();
suspend_always final_suspend();
+ void unhandled_exception();
+ void return_void();
};
coro<bad_promise_1> missing_get_return_object() { // expected-error {{no member named 'get_return_object' in 'bad_promise_1'}}
co_await a;
@@ -476,6 +512,8 @@ 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();
+ void return_void();
};
// FIXME: This shouldn't happen twice
coro<bad_promise_2> missing_initial_suspend() { // expected-error {{no member named 'initial_suspend' in 'bad_promise_2'}}
@@ -486,6 +524,8 @@ 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();
+ void return_void();
};
coro<bad_promise_3> missing_final_suspend() { // expected-error {{no member named 'final_suspend' in 'bad_promise_3'}}
co_await a;
@@ -495,6 +535,7 @@ struct bad_promise_4 {
coro<bad_promise_4> get_return_object();
not_awaitable initial_suspend();
suspend_always final_suspend();
+ void return_void();
};
// FIXME: This diagnostic is terrible.
coro<bad_promise_4> bad_initial_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
@@ -506,6 +547,7 @@ struct bad_promise_5 {
coro<bad_promise_5> get_return_object();
suspend_always initial_suspend();
not_awaitable final_suspend();
+ void return_void();
};
// FIXME: This diagnostic is terrible.
coro<bad_promise_5> bad_final_suspend() { // expected-error {{no member named 'await_ready' in 'not_awaitable'}}
@@ -517,29 +559,36 @@ struct bad_promise_6 {
coro<bad_promise_6> get_return_object();
suspend_always initial_suspend();
suspend_always final_suspend();
- void return_void();
- void return_value(int) const;
+ void unhandled_exception();
+ void return_void(); // expected-note 2 {{member 'return_void' first declared here}}
+ void return_value(int) const; // expected-note 2 {{member 'return_value' first declared here}}
void return_value(int);
};
coro<bad_promise_6> bad_implicit_return() { // expected-error {{'bad_promise_6' declares both 'return_value' and 'return_void'}}
co_await a;
}
-struct bad_promise_7 {
+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 { // expected-note 2 {{defined here}}
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_base {
private:
@@ -549,17 +598,24 @@ struct bad_promise_8 : bad_promise_base {
coro<bad_promise_8> get_return_object();
suspend_always initial_suspend();
suspend_always final_suspend();
- 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 set_exception has already failed.
+ // 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();
@@ -567,6 +623,7 @@ struct bad_promise_9 {
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'}}
@@ -579,6 +636,7 @@ struct bad_promise_10 {
suspend_always final_suspend();
int await_transform;
void return_void();
+ void unhandled_exception();
};
coro<bad_promise_10> bad_coawait() {
// FIXME this diagnostic is terrible
@@ -595,6 +653,7 @@ 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;
@@ -617,6 +676,7 @@ struct good_promise_2 {
suspend_always initial_suspend();
suspend_always final_suspend();
void return_void();
+ void unhandled_exception();
};
template<> struct std::experimental::coroutine_handle<good_promise_2> {};
@@ -627,3 +687,488 @@ float badly_specialized_coro_handle() { // expected-error {{std::experimental::c
//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}}
}
+
+namespace std {
+ struct nothrow_t {};
+ constexpr nothrow_t nothrow = {};
+}
+
+using SizeT = decltype(sizeof(int));
+
+void* operator new(SizeT __sz, const std::nothrow_t&) noexcept;
+void operator delete(void* __p, const std::nothrow_t&) noexcept;
+
+
+
+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}}
+
+struct bad_promise_12 {
+ coro<bad_promise_12> get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ void return_void();
+ static coro<bad_promise_12> get_return_object_on_allocation_failure();
+
+ static void* operator new(SizeT);
+ // expected-error@-1 2 {{'operator new' is required to have a non-throwing noexcept specification when the promise type declares 'get_return_object_on_allocation_failure()'}}
+};
+coro<bad_promise_12> throwing_in_class_new() { // expected-note {{call to 'operator new' implicitly required by coroutine function here}}
+ co_return;
+}
+
+template <class T>
+coro<T> dependent_throwing_in_class_new(T) { // expected-note {{call to 'operator new' implicitly required by coroutine function here}}
+ co_return;
+}
+template coro<bad_promise_12> dependent_throwing_in_class_new(bad_promise_12); // expected-note {{requested here}}
+
+
+struct good_promise_13 {
+ coro<good_promise_13> get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+ void return_void();
+ static coro<good_promise_13> get_return_object_on_allocation_failure();
+};
+coro<good_promise_13> uses_nothrow_new() {
+ co_return;
+}
+
+template <class T>
+coro<T> dependent_uses_nothrow_new(T) {
+ co_return;
+}
+template coro<good_promise_13> dependent_uses_nothrow_new(good_promise_13);
+
+struct mismatch_gro_type_tag1 {};
+template<>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag1> {
+ struct promise_type {
+ void get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ void return_void() {}
+ void unhandled_exception();
+ };
+};
+
+extern "C" int f(mismatch_gro_type_tag1) {
+ // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}}
+ co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct mismatch_gro_type_tag2 {};
+template<>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag2> {
+ struct promise_type {
+ void *get_return_object() {} //expected-note {{member 'get_return_object' declared here}}
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ void return_void() {}
+ void unhandled_exception();
+ };
+};
+
+extern "C" int f(mismatch_gro_type_tag2) {
+ // expected-error@-1 {{cannot initialize return object of type 'int' with an lvalue of type 'void *'}}
+ co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct mismatch_gro_type_tag3 {};
+template<>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag3> {
+ struct promise_type {
+ int get_return_object() {}
+ static void get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared here}}
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ void return_void() {}
+ void unhandled_exception();
+ };
+};
+
+extern "C" int f(mismatch_gro_type_tag3) {
+ // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}}
+ co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+
+struct mismatch_gro_type_tag4 {};
+template<>
+struct std::experimental::coroutine_traits<int, mismatch_gro_type_tag4> {
+ struct promise_type {
+ int get_return_object() {}
+ static char *get_return_object_on_allocation_failure() {} //expected-note {{member 'get_return_object_on_allocation_failure' declared}}
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ void return_void() {}
+ void unhandled_exception();
+ };
+};
+
+extern "C" int f(mismatch_gro_type_tag4) {
+ // expected-error@-1 {{cannot initialize return object of type 'int' with an rvalue of type 'char *'}}
+ co_return; //expected-note {{function is a coroutine due to use of 'co_return' here}}
+}
+
+struct bad_promise_no_return_func { // expected-note {{'bad_promise_no_return_func' defined here}}
+ coro<bad_promise_no_return_func> get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+ void unhandled_exception();
+};
+// FIXME: The PDTS currently specifies this as UB, technically forbidding a
+// diagnostic.
+coro<bad_promise_no_return_func> no_return_value_or_return_void() {
+ // expected-error@-1 {{'bad_promise_no_return_func' must declare either 'return_value' or 'return_void'}}
+ co_await a;
+}
+
+struct bad_await_suspend_return {
+ bool await_ready();
+ // expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'char')}}
+ char await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+struct bad_await_ready_return {
+ // expected-note@+1 {{return type of 'await_ready' is required to be contextually convertible to 'bool'}}
+ void await_ready();
+ bool await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+struct await_ready_explicit_bool {
+ struct BoolT {
+ explicit operator bool() const;
+ };
+ BoolT await_ready();
+ void await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+template <class SuspendTy>
+struct await_suspend_type_test {
+ bool await_ready();
+ // expected-error@+2 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &')}}
+ // expected-error@+1 {{return type of 'await_suspend' is required to be 'void' or 'bool' (have 'bool &&')}}
+ SuspendTy await_suspend(std::experimental::coroutine_handle<>);
+ void await_resume();
+};
+void test_bad_suspend() {
+ {
+ // FIXME: The actual error emitted here is terrible, and no number of notes can save it.
+ bad_await_ready_return a;
+ // expected-error@+1 {{value of type 'void' is not contextually convertible to 'bool'}}
+ co_await a; // expected-note {{call to 'await_ready' implicitly required by coroutine function here}}
+ }
+ {
+ bad_await_suspend_return b;
+ co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}}
+ }
+ {
+ await_ready_explicit_bool c;
+ co_await c; // OK
+ }
+ {
+ await_suspend_type_test<bool &&> a;
+ await_suspend_type_test<bool &> b;
+ await_suspend_type_test<const void> c;
+ await_suspend_type_test<const volatile bool> d;
+ co_await a; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}}
+ co_await b; // expected-note {{call to 'await_suspend' implicitly required by coroutine function here}}
+ co_await c; // OK
+ co_await d; // OK
+ }
+}
+
+template <int ID = 0>
+struct NoCopy {
+ NoCopy(NoCopy const&) = delete; // expected-note 2 {{deleted here}}
+};
+template <class T, class U>
+void test_dependent_param(T t, U) {
+ // expected-error@-1 {{call to deleted constructor of 'NoCopy<0>'}}
+ // expected-error@-2 {{call to deleted constructor of 'NoCopy<1>'}}
+ ((void)t);
+ co_return 42;
+}
+template void test_dependent_param(NoCopy<0>, NoCopy<1>); // expected-note {{requested here}}
+
+namespace CoroHandleMemberFunctionTest {
+struct CoroMemberTag {};
+struct BadCoroMemberTag {};
+
+template <class T, class U>
+constexpr bool IsSameV = false;
+template <class T>
+constexpr bool IsSameV<T, T> = true;
+
+template <class T>
+struct TypeTest {
+ template <class U>
+ static constexpr bool IsSame = IsSameV<T, U>;
+
+ template <class... Args>
+ static constexpr bool MatchesArgs = IsSameV<T,
+ std::experimental::coroutine_traits<CoroMemberTag, Args...>>;
+};
+
+template <class T>
+struct AwaitReturnsType {
+ bool await_ready() const;
+ void await_suspend(...) const;
+ T await_resume() const;
+};
+
+template <class... CoroTraitsArgs>
+struct CoroMemberPromise {
+ using TraitsT = std::experimental::coroutine_traits<CoroTraitsArgs...>;
+ using TypeTestT = TypeTest<TraitsT>;
+ using AwaitTestT = AwaitReturnsType<TypeTestT>;
+
+ CoroMemberTag get_return_object();
+ suspend_always initial_suspend();
+ suspend_always final_suspend();
+
+ AwaitTestT yield_value(int);
+
+ void return_void();
+ void unhandled_exception();
+};
+
+} // namespace CoroHandleMemberFunctionTest
+
+template <class... Args>
+struct ::std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::CoroMemberTag, Args...> {
+ using promise_type = CoroHandleMemberFunctionTest::CoroMemberPromise<CoroHandleMemberFunctionTest::CoroMemberTag, Args...>;
+};
+
+namespace CoroHandleMemberFunctionTest {
+struct TestType {
+
+ CoroMemberTag test_qual() {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<TestType &>, "");
+ static_assert(!TC.MatchesArgs<TestType>, "");
+ static_assert(!TC.MatchesArgs<TestType *>, "");
+ }
+
+ CoroMemberTag test_sanity(int *) const {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static_assert failed}}
+ static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static_assert failed}}
+ static_assert(TC.MatchesArgs<const TestType &, int *>, "");
+ }
+
+ CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<const TestType &, int *, const float &&, volatile void *volatile>, "");
+ }
+
+ CoroMemberTag test_qual() const volatile {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<const volatile TestType &>, "");
+ }
+
+ CoroMemberTag test_ref_qual() & {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<TestType &>, "");
+ }
+ CoroMemberTag test_ref_qual() const & {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<TestType const &>, "");
+ }
+ CoroMemberTag test_ref_qual() && {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<TestType &&>, "");
+ }
+ CoroMemberTag test_ref_qual(const char *&) const volatile && {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<TestType const volatile &&, const char *&>, "");
+ }
+
+ CoroMemberTag test_args(int) {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<TestType &, int>, "");
+ }
+ CoroMemberTag test_args(int, long &, void *) const {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<TestType const &, int, long &, void *>, "");
+ }
+
+ template <class... Args>
+ CoroMemberTag test_member_template(Args...) const && {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<TestType const &&, Args...>, "");
+ }
+
+ static CoroMemberTag test_static() {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<>, "");
+ static_assert(!TC.MatchesArgs<TestType>, "");
+ static_assert(!TC.MatchesArgs<TestType &>, "");
+ static_assert(!TC.MatchesArgs<TestType *>, "");
+ }
+
+ static CoroMemberTag test_static(volatile void *const, char &&) {
+ auto TC = co_yield 0;
+ static_assert(TC.MatchesArgs<volatile void *const, char &&>, "");
+ }
+
+ template <class Dummy>
+ static CoroMemberTag test_static_template(const char *volatile &, unsigned) {
+ auto TC = co_yield 0;
+ using TCT = decltype(TC);
+ static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, "");
+ static_assert(!TCT::MatchesArgs<TestType &, const char *volatile &, unsigned>, "");
+ }
+
+ BadCoroMemberTag test_diagnostics() {
+ // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, CoroHandleMemberFunctionTest::TestType &>' has no member named 'promise_type'}}
+ co_return;
+ }
+ BadCoroMemberTag test_diagnostics(int) const && {
+ // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, const CoroHandleMemberFunctionTest::TestType &&, int>' has no member named 'promise_type'}}
+ co_return;
+ }
+
+ static BadCoroMemberTag test_static_diagnostics(long *) {
+ // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, long *>' has no member named 'promise_type'}}
+ co_return;
+ }
+};
+
+template CoroMemberTag TestType::test_member_template(long, const char *) const &&;
+template CoroMemberTag TestType::test_static_template<void>(const char *volatile &, unsigned);
+
+template <class... Args>
+struct DepTestType {
+
+ CoroMemberTag test_sanity(int *) const {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<const DepTestType &>, ""); // expected-error {{static_assert failed}}
+ static_assert(TC.template MatchesArgs<>, ""); // expected-error {{static_assert failed}}
+ static_assert(TC.template MatchesArgs<const DepTestType &, int *>, "");
+ }
+
+ CoroMemberTag test_qual() {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType &>, "");
+ static_assert(!TC.template MatchesArgs<DepTestType>, "");
+ static_assert(!TC.template MatchesArgs<DepTestType *>, "");
+ }
+
+ CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<const DepTestType &, int *, const float &&, volatile void *volatile>, "");
+ }
+
+ CoroMemberTag test_qual() const volatile {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<const volatile DepTestType &>, "");
+ }
+
+ CoroMemberTag test_ref_qual() & {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType &>, "");
+ }
+ CoroMemberTag test_ref_qual() const & {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType const &>, "");
+ }
+ CoroMemberTag test_ref_qual() && {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType &&>, "");
+ }
+ CoroMemberTag test_ref_qual(const char *&) const volatile && {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType const volatile &&, const char *&>, "");
+ }
+
+ CoroMemberTag test_args(int) {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType &, int>, "");
+ }
+ CoroMemberTag test_args(int, long &, void *) const {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType const &, int, long &, void *>, "");
+ }
+
+ template <class... UArgs>
+ CoroMemberTag test_member_template(UArgs...) const && {
+ auto TC = co_yield 0;
+ static_assert(TC.template MatchesArgs<DepTestType const &&, UArgs...>, "");
+ }
+
+ static CoroMemberTag test_static() {
+ auto TC = co_yield 0;
+ using TCT = decltype(TC);
+ static_assert(TCT::MatchesArgs<>, "");
+ static_assert(!TCT::MatchesArgs<DepTestType>, "");
+ static_assert(!TCT::MatchesArgs<DepTestType &>, "");
+ static_assert(!TCT::MatchesArgs<DepTestType *>, "");
+
+ // Ensure diagnostics are actually being generated here
+ static_assert(TCT::MatchesArgs<int>, ""); // expected-error {{static_assert failed}}
+ }
+
+ static CoroMemberTag test_static(volatile void *const, char &&) {
+ auto TC = co_yield 0;
+ using TCT = decltype(TC);
+ static_assert(TCT::MatchesArgs<volatile void *const, char &&>, "");
+ }
+
+ template <class Dummy>
+ static CoroMemberTag test_static_template(const char *volatile &, unsigned) {
+ auto TC = co_yield 0;
+ using TCT = decltype(TC);
+ static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, "");
+ static_assert(!TCT::MatchesArgs<DepTestType &, const char *volatile &, unsigned>, "");
+ }
+};
+
+template struct DepTestType<int>; // expected-note {{requested here}}
+template CoroMemberTag DepTestType<int>::test_member_template(long, const char *) const &&;
+
+template CoroMemberTag DepTestType<int>::test_static_template<void>(const char *volatile &, unsigned);
+
+} // namespace CoroHandleMemberFunctionTest
diff --git a/test/SemaCXX/cxx-altivec.cpp b/test/SemaCXX/cxx-altivec.cpp
index baacbac7d0..50fb8ad014 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-compat.cpp b/test/SemaCXX/cxx0x-compat.cpp
index bcf0cf11dc..b9ccadd85c 100644
--- a/test/SemaCXX/cxx0x-compat.cpp
+++ b/test/SemaCXX/cxx0x-compat.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++11-compat -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++1z -Wc++11-compat -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++11-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++11-compat-pedantic -verify %s
#if __cplusplus < 201103L
@@ -42,14 +42,17 @@ void h(size_t foo, size_t bar) {
char c = 'x'_x; // expected-warning {{will be treated as a user-defined literal suffix}}
template<int ...N> int f() { // expected-warning {{C++11 extension}}
- return (N + ...); // expected-warning {{C++1z extension}}
+ return (N + ...); // expected-warning {{C++17 extension}}
}
#else
auto init_capture = [a(0)] {}; // expected-warning {{initialized lambda captures are incompatible with C++ standards before C++14}}
-static_assert(true); // expected-warning {{incompatible with C++ standards before C++1z}}
+static_assert(true); // expected-warning {{incompatible with C++ standards before C++17}}
-template<int ...N> int f() { return (N + ...); } // expected-warning {{incompatible with C++ standards before C++1z}}
+template<int ...N> int f() { return (N + ...); } // expected-warning {{incompatible with C++ standards before C++17}}
+
+namespace [[]] NS_with_attr {} // expected-warning {{incompatible with C++ standards before C++17}}
+enum { e [[]] }; // expected-warning {{incompatible with C++ standards before C++17}}
#endif
diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 17215fedf0..7a581fd519 100644
--- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -136,13 +136,13 @@ struct bad_decls {
};
struct DefaultDelete {
- DefaultDelete() = default; // expected-note {{previous declaration is here}}
+ DefaultDelete() = default; // expected-note {{previous definition is here}}
DefaultDelete() = delete; // expected-error {{constructor cannot be redeclared}}
- ~DefaultDelete() = default; // expected-note {{previous declaration is here}}
+ ~DefaultDelete() = default; // expected-note {{previous definition is here}}
~DefaultDelete() = delete; // expected-error {{destructor cannot be redeclared}}
- DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous declaration is here}}
+ DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous definition is here}}
DefaultDelete &operator=(const DefaultDelete &) = delete; // expected-error {{class member cannot be redeclared}}
};
diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp
index c10bee917a..07a233b56c 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 c64511193b..ce029d7f07 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 65b57a5584..90b11f3a9e 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/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 9b8fadd2f5..78ebc048b2 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -136,9 +136,15 @@ void auto_deduction() {
auto l3 {1};
static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
static_assert(same_type<decltype(l3), int>::value, "");
- auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
+ auto bl = {1, 2.0}; // expected-error {{deduced conflicting types ('int' vs 'double') for initializer list element type}}
+
+ void f1(int), f1(float), f2(int), f3(float);
+ auto fil = {f1, f2};
+ auto ffl = {f1, f3};
+ auto fl = {f1, f2, f3}; // expected-error {{deduced conflicting types ('void (*)(int)' vs 'void (*)(float)') for initializer list element type}}
for (int i : {1, 2, 3, 4}) {}
+ for (int j : {1.0, 2.0, 3.0f, 4.0}) {} // expected-error {{deduced conflicting types ('double' vs 'float') for initializer list element type}}
}
void dangle() {
diff --git a/test/SemaCXX/cxx17-compat.cpp b/test/SemaCXX/cxx17-compat.cpp
new file mode 100644
index 0000000000..3b814340c6
--- /dev/null
+++ b/test/SemaCXX/cxx17-compat.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++2a -Wc++17-compat-pedantic -verify %s
+
+struct A {};
+int (A::*pa)() const&;
+int use_pa = (A().*pa)();
+#if __cplusplus <= 201703L
+ // expected-warning@-2 {{invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension}}
+#else
+ // expected-warning@-4 {{invoking a pointer to a 'const &' member function on an rvalue is incompatible with C++ standards before C++2a}}
+#endif
+
+struct B {
+ void b() {
+ (void) [=, this] {};
+#if __cplusplus <= 201703L
+ // expected-warning@-2 {{explicit capture of 'this' with a capture default of '=' is a C++2a extension}}
+#else
+ // expected-warning@-4 {{explicit capture of 'this' with a capture default of '=' is incompatible with C++ standards before C++2a}}
+#endif
+ }
+
+ int n : 5 = 0;
+#if __cplusplus <= 201703L
+ // expected-warning@-2 {{default member initializer for bit-field is a C++2a extension}}
+#else
+ // expected-warning@-4 {{default member initializer for bit-field is incompatible with C++ standards before C++2a}}
+#endif
+};
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
index bfe0ab9dcd..13ff751aca 100644
--- a/test/SemaCXX/cxx1y-deduced-return-type.cpp
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -55,6 +55,25 @@ auto b(bool k) {
return "goodbye";
}
+// Allow 'operator auto' to call only the explicit operator auto.
+struct BothOps {
+ template <typename T> operator T();
+ template <typename T> operator T *();
+ operator auto() { return 0; }
+ operator auto *() { return this; }
+};
+struct JustTemplateOp {
+ template <typename T> operator T();
+ template <typename T> operator T *();
+};
+
+auto c() {
+ BothOps().operator auto(); // ok
+ BothOps().operator auto *(); // ok
+ JustTemplateOp().operator auto(); // expected-error {{no member named 'operator auto' in 'JustTemplateOp'}}
+ JustTemplateOp().operator auto *(); // expected-error {{no member named 'operator auto *' in 'JustTemplateOp'}}
+}
+
auto *ptr_1() {
return 100; // expected-error {{cannot deduce return type 'auto *' from returned value of type 'int'}}
}
diff --git a/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp b/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
index b08d58abd2..eaed45acd1 100644
--- a/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
+++ b/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
@@ -1376,3 +1376,149 @@ XT<int> xt{};
}
+
+void PR33318(int i) {
+ [&](auto) { static_assert(&i != nullptr, ""); }(0); // expected-warning 2{{always true}} expected-note {{instantiation}}
+}
+
+// Check to make sure that we don't capture when member-calls are made to members that are not of 'this' class.
+namespace PR34266 {
+// https://bugs.llvm.org/show_bug.cgi?id=34266
+namespace ns1 {
+struct A {
+ static void bar(int) { }
+ static void bar(double) { }
+};
+
+struct B
+{
+ template<class T>
+ auto f() {
+ auto L = [=] {
+ T{}.bar(3.0);
+ T::bar(3);
+
+ };
+ ASSERT_NO_CAPTURES(L);
+ return L;
+ };
+};
+
+void test() {
+ B{}.f<A>();
+}
+} // end ns1
+
+namespace ns2 {
+struct A {
+ static void bar(int) { }
+ static void bar(double) { }
+};
+
+struct B
+{
+ using T = A;
+ auto f() {
+ auto L = [=](auto a) {
+ T{}.bar(a);
+ T::bar(a);
+
+ };
+ ASSERT_NO_CAPTURES(L);
+ return L;
+ };
+};
+
+void test() {
+ B{}.f()(3.0);
+ B{}.f()(3);
+}
+} // end ns2
+
+namespace ns3 {
+struct A {
+ void bar(int) { }
+ static void bar(double) { }
+};
+
+struct B
+{
+ using T = A;
+ auto f() {
+ auto L = [=](auto a) {
+ T{}.bar(a);
+ T::bar(a); // This call ignores the instance member function because the implicit object argument fails to convert.
+
+ };
+ ASSERT_NO_CAPTURES(L);
+ return L;
+ };
+};
+
+void test() {
+ B{}.f()(3.0);
+ B{}.f()(3);
+}
+
+} // end ns3
+
+
+namespace ns4 {
+struct A {
+ void bar(int) { }
+ static void bar(double) { }
+};
+
+struct B : A
+{
+ using T = A;
+ auto f() {
+ auto L = [=](auto a) {
+ T{}.bar(a);
+ T::bar(a);
+
+ };
+ // just check to see if the size if >= 2 bytes (which should be the case if we capture anything)
+ ASSERT_CLOSURE_SIZE(L, 2);
+ return L;
+ };
+};
+
+void test() {
+ B{}.f()(3.0);
+ B{}.f()(3);
+}
+
+} // end ns4
+
+namespace ns5 {
+struct A {
+ void bar(int) { }
+ static void bar(double) { }
+};
+
+struct B
+{
+ template<class T>
+ auto f() {
+ auto L = [&](auto a) {
+ T{}.bar(a);
+ T::bar(a);
+
+ };
+
+ ASSERT_NO_CAPTURES(L);
+ return L;
+ };
+};
+
+void test() {
+ B{}.f<A>()(3.0);
+ B{}.f<A>()(3);
+}
+
+} // end ns5
+
+
+
+} // end PR34266
diff --git a/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp b/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
index b0b86e3877..b8022d2091 100644
--- a/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
+++ b/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
@@ -98,3 +98,27 @@ namespace variadic_expansion {
}
#endif
+namespace PR33082 {
+ template<int ...I> void a() {
+ int arr[] = { [](auto ...K) { (void)I; } ... }; // expected-error {{no viable conversion}} expected-note {{candidate}}
+ }
+
+ template<typename ...T> struct Pack {};
+ template<typename ...T, typename ...U> void b(Pack<U...>, T ...t) {
+ int arr[] = {[t...]() { // expected-error 2{{cannot initialize an array element of type 'int' with}}
+ U u;
+ return u;
+ }()...};
+ }
+
+ void c() {
+ int arr[] = {[](auto... v) {
+ v; // expected-error {{unexpanded parameter pack 'v'}}
+ }...}; // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
+ }
+
+ void run() {
+ a<1>(); // expected-note {{instantiation of}}
+ b(Pack<int*, float*>(), 1, 2, 3); // expected-note {{instantiation of}}
+ }
+}
diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp
index 1993c6e185..9f3c77591a 100644
--- a/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ b/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -986,3 +986,10 @@ class Enclosing3 {
);
};
}
+
+namespace PR32638 {
+ //https://bugs.llvm.org/show_bug.cgi?id=32638
+ void test() {
+ [](auto x) noexcept(noexcept(x)) { } (0);
+ }
+} \ No newline at end of file
diff --git a/test/SemaCXX/cxx1y-init-captures.cpp b/test/SemaCXX/cxx1y-init-captures.cpp
index d681954707..4b82452ed5 100644
--- a/test/SemaCXX/cxx1y-init-captures.cpp
+++ b/test/SemaCXX/cxx1y-init-captures.cpp
@@ -206,3 +206,11 @@ void test(double weight) {
find(weight); // expected-note {{in instantiation of function template specialization}}
}
}
+
+namespace init_capture_undeclared_identifier {
+ auto a = [x = y]{}; // expected-error{{use of undeclared identifier 'y'}}
+
+ int typo_foo; // expected-note 2 {{'typo_foo' declared here}}
+ auto b = [x = typo_boo]{}; // expected-error{{use of undeclared identifier 'typo_boo'; did you mean 'typo_foo'}}
+ auto c = [x(typo_boo)]{}; // expected-error{{use of undeclared identifier 'typo_boo'; did you mean 'typo_foo'}}
+}
diff --git a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
index b496364683..a78548b6f1 100644
--- a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
+++ b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
@@ -9,7 +9,7 @@
#endif
template<typename T>
-T pi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+T pi = T(3.1415926535897932385); // expected-note 2{{declared here}}
template<typename T>
CONST T cpi = T(3.1415926535897932385); // expected-note {{template is declared here}}
@@ -58,10 +58,9 @@ namespace use_in_top_level_funcs {
namespace shadow {
void foo() {
int ipi0 = pi<int>;
- int pi;
+ int pi; // expected-note {{found}}
int a = pi;
- int ipi = pi<int>; // expected-error {{expected '(' for function-style cast or type construction}} \
- // expected-error {{expected expression}}
+ int ipi = pi<int>; // expected-error {{'pi' does not name a template but is followed by template arguments; did you mean '::pi'?}}
}
}
diff --git a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 5eee34e809..9080f67fe0 100644
--- a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -1,4 +1,9 @@
-// RUN: %clang_cc1 -std=c++1z -verify %s
+// RUN: %clang_cc1 -std=c++1z -verify %s -DERRORS -Wundefined-func-template
+// RUN: %clang_cc1 -std=c++1z -verify %s -UERRORS -Wundefined-func-template
+
+// This test is split into two because we only produce "undefined internal"
+// warnings if we didn't produce any errors.
+#if ERRORS
namespace std {
using size_t = decltype(sizeof(0));
@@ -179,9 +184,9 @@ namespace default_args_from_ctor {
namespace transform_params {
template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]>
- struct A { // expected-note 2{{candidate}}
+ struct A {
template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W>
- A(U<X>, W<Y>); // expected-note {{[with V = int, M = 12, Y = &transform_params::n]}}
+ A(U<X>, W<Y>);
static constexpr T v = N;
};
@@ -189,9 +194,7 @@ namespace transform_params {
int n[12];
template<int (*)[12]> struct Q {};
Q<&n> qn;
- // FIXME: The class template argument deduction result here is correct, but
- // we incorrectly fail to deduce arguments for the constructor!
- A a(qn, qn); // expected-error {{no matching constructor for initialization of 'transform_params::A<int, 12, Q, &transform_params::n>'}}
+ A a(qn, qn);
static_assert(a.v == 12);
template<typename ...T> struct B {
@@ -203,19 +206,123 @@ namespace transform_params {
};
B b({1, 2, 3}, "foo", {'x', 'y', 'z', 'w'}); // ok
- // This should be accepted once -std=c++1z implies
- // -frelaxed-template-template-args. Without that, a template template
- // parameter 'template<int, int, int> typename' cannot bind to a template
- // template argument 'template<int...> typename'.
- template<typename ...T> struct C { // expected-note {{candidate}}
+ template<typename ...T> struct C {
template<T ...V, template<T...> typename X>
- C(X<V...>); // expected-note {{substitution failure [with T = <int, int, int>, V = <0, 1, 2>]}}
+ C(X<V...>);
};
template<int...> struct Y {};
- C c(Y<0, 1, 2>{}); // expected-error {{no viable constructor or deduction guide}}
+ C c(Y<0, 1, 2>{});
template<typename ...T> struct D {
template<T ...V> D(Y<V...>);
};
D d(Y<0, 1, 2>{});
}
+
+namespace variadic {
+ int arr3[3], arr4[4];
+
+ // PR32673
+ template<typename T> struct A {
+ template<typename ...U> A(T, U...);
+ };
+ A a(1, 2, 3);
+
+ template<typename T> struct B {
+ template<int ...N> B(T, int (&...r)[N]);
+ };
+ B b(1, arr3, arr4);
+
+ template<typename T> struct C {
+ template<template<typename> typename ...U> C(T, U<int>...);
+ };
+ C c(1, a, b);
+
+ template<typename ...U> struct X {
+ template<typename T> X(T, U...);
+ };
+ X x(1, 2, 3);
+
+ template<int ...N> struct Y {
+ template<typename T> Y(T, int (&...r)[N]);
+ };
+ Y y(1, arr3, arr4);
+
+ template<template<typename> typename ...U> struct Z {
+ template<typename T> Z(T, U<int>...);
+ };
+ Z z(1, a, b);
+}
+
+namespace tuple_tests {
+ // The converting n-ary constructor appears viable, deducing T as an empty
+ // pack (until we check its SFINAE constraints).
+ namespace libcxx_1 {
+ template<class ...T> struct tuple {
+ template<class ...Args> struct X { static const bool value = false; };
+ template<class ...U, bool Y = X<U...>::value> tuple(U &&...u);
+ };
+ tuple a = {1, 2, 3};
+ }
+
+ // Don't get caught by surprise when X<...> doesn't even exist in the
+ // selected specialization!
+ namespace libcxx_2 {
+ template<class ...T> struct tuple { // expected-note {{candidate}}
+ template<class ...Args> struct X { static const bool value = false; };
+ template<class ...U, bool Y = X<U...>::value> tuple(U &&...u);
+ // expected-note@-1 {{substitution failure [with T = <>, U = <int, int, int>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization}}
+ };
+ template <> class tuple<> {};
+ tuple a = {1, 2, 3}; // expected-error {{no viable constructor or deduction guide}}
+ }
+
+ namespace libcxx_3 {
+ template<typename ...T> struct scoped_lock {
+ scoped_lock(T...);
+ };
+ template<> struct scoped_lock<> {};
+ scoped_lock l = {};
+ }
+}
+
+namespace dependent {
+ template<typename T> struct X {
+ X(T);
+ };
+ template<typename T> int Var(T t) {
+ X x(t);
+ return X(x) + 1; // expected-error {{invalid operands}}
+ }
+ template<typename T> int Cast(T t) {
+ return X(X(t)) + 1; // expected-error {{invalid operands}}
+ }
+ template<typename T> int New(T t) {
+ return X(new X(t)) + 1; // expected-error {{invalid operands}}
+ };
+ template int Var(float); // expected-note {{instantiation of}}
+ template int Cast(float); // expected-note {{instantiation of}}
+ template int New(float); // expected-note {{instantiation of}}
+ template<typename T> int operator+(X<T>, int);
+ template int Var(int);
+ template int Cast(int);
+ template int New(int);
+}
+
+#else
+
+// expected-no-diagnostics
+namespace undefined_warnings {
+ // Make sure we don't get an "undefined but used internal symbol" warning for the deduction guide here.
+ namespace {
+ template <typename T>
+ struct TemplDObj {
+ explicit TemplDObj(T func) noexcept {}
+ };
+ auto test1 = TemplDObj(0);
+
+ TemplDObj(float) -> TemplDObj<double>;
+ auto test2 = TemplDObj(.0f);
+ }
+}
+#endif
diff --git a/test/SemaCXX/cxx1z-copy-omission.cpp b/test/SemaCXX/cxx1z-copy-omission.cpp
index e2b8fd7961..a7133d79b4 100644
--- a/test/SemaCXX/cxx1z-copy-omission.cpp
+++ b/test/SemaCXX/cxx1z-copy-omission.cpp
@@ -2,11 +2,11 @@
struct Noncopyable {
Noncopyable();
- Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}}
+ Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}} expected-note 1+ {{not viable}}
virtual ~Noncopyable();
};
struct Derived : Noncopyable {};
-struct NoncopyableAggr {
+struct NoncopyableAggr { // expected-note 3{{candidate}}
Noncopyable nc;
};
struct Indestructible {
@@ -38,11 +38,39 @@ Noncopyable nrvo() {
Noncopyable nc1 = make();
Noncopyable nc2 = Noncopyable();
Noncopyable nc3 = Derived(); // expected-error {{deleted constructor}}
+Noncopyable nc4((Noncopyable()));
+Noncopyable nc5 = {Noncopyable()};
+Noncopyable nc6{Noncopyable()};
NoncopyableAggr nca1 = NoncopyableAggr{};
NoncopyableAggr nca2 = NoncopyableAggr{{}};
NoncopyableAggr nca3 = NoncopyableAggr{NoncopyableAggr{Noncopyable()}};
+template<typename T> struct Convert { operator T(); }; // expected-note 1+{{candidate}}
+Noncopyable conv1 = Convert<Noncopyable>();
+Noncopyable conv2((Convert<Noncopyable>()));
+Noncopyable conv3 = {Convert<Noncopyable>()};
+Noncopyable conv4{Convert<Noncopyable>()};
+
+Noncopyable ref_conv1 = Convert<Noncopyable&>(); // expected-error {{deleted constructor}}
+Noncopyable ref_conv2((Convert<Noncopyable&>())); // expected-error {{deleted constructor}}
+Noncopyable ref_conv3 = {Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}
+Noncopyable ref_conv4{Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}
+
+Noncopyable derived_conv1 = Convert<Derived>(); // expected-error {{deleted constructor}}
+Noncopyable derived_conv2((Convert<Derived>())); // expected-error {{deleted constructor}}
+Noncopyable derived_conv3 = {Convert<Derived>()}; // expected-error {{deleted constructor}}
+Noncopyable derived_conv4{Convert<Derived>()}; // expected-error {{deleted constructor}}
+
+NoncopyableAggr nc_aggr1 = Convert<NoncopyableAggr>();
+NoncopyableAggr nc_aggr2((Convert<NoncopyableAggr>()));
+NoncopyableAggr nc_aggr3 = {Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
+NoncopyableAggr nc_aggr4{Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
+NoncopyableAggr nc_aggr5 = Convert<Noncopyable>(); // expected-error {{no viable}}
+NoncopyableAggr nc_aggr6((Convert<Noncopyable>())); // expected-error {{no matching constructor}}
+NoncopyableAggr nc_aggr7 = {Convert<Noncopyable>()};
+NoncopyableAggr nc_aggr8{Convert<Noncopyable>()};
+
void test_expressions(bool b) {
auto lambda = [a = make()] {};
@@ -132,3 +160,12 @@ struct AsDelegating final {
// classes?
AsDelegating(int n) : AsDelegating(make(n)) {} // expected-error {{deleted}}
};
+
+namespace CtorTemplateBeatsNonTemplateConversionFn {
+ struct Foo { template <typename Derived> Foo(const Derived &); };
+ template <typename Derived> struct Base { operator Foo() const = delete; }; // expected-note {{deleted}}
+ struct Derived : Base<Derived> {};
+
+ Foo f(Derived d) { return d; } // expected-error {{invokes a deleted function}}
+ Foo g(Derived d) { return Foo(d); } // ok, calls constructor
+}
diff --git a/test/SemaCXX/cxx1z-decomposition.cpp b/test/SemaCXX/cxx1z-decomposition.cpp
index d457ace5d8..7a4221784a 100644
--- a/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/test/SemaCXX/cxx1z-decomposition.cpp
@@ -70,4 +70,10 @@ int error_recovery() {
return foobar_; // expected-error {{undeclared identifier 'foobar_'}}
}
+// PR32172
+template <class T> void dependent_foreach(T t) {
+ for (auto [a,b,c] : t)
+ a,b,c;
+}
+
// FIXME: by-value array copies
diff --git a/test/SemaCXX/cxx1z-init-statement-template.cpp b/test/SemaCXX/cxx1z-init-statement-template.cpp
new file mode 100644
index 0000000000..cedd2c720d
--- /dev/null
+++ b/test/SemaCXX/cxx1z-init-statement-template.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++1z -verify -emit-llvm-only %s
+// expected-no-diagnostics
+
+// rdar://problem/33888545
+template <unsigned int BUFFER_SIZE> class Buffer {};
+
+class A {
+public:
+ int status;
+};
+
+template <unsigned int N> A parse(Buffer<N> buffer);
+
+template<unsigned int N>
+void init_in_if(Buffer<N> buffer) {
+ if (A a = parse(buffer); a.status > 0) {
+ }
+}
+
+template<unsigned int N>
+void init_in_switch(Buffer<N> buffer) {
+ switch (A a = parse(buffer); a.status) {
+ default:
+ break;
+ }
+}
+
+void test() {
+ Buffer<10> buffer;
+ init_in_if(buffer);
+ init_in_switch(buffer);
+}
diff --git a/test/SemaCXX/cxx1z-init-statement.cpp b/test/SemaCXX/cxx1z-init-statement.cpp
index 4afe0402d1..d37acd08ce 100644
--- a/test/SemaCXX/cxx1z-init-statement.cpp
+++ b/test/SemaCXX/cxx1z-init-statement.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify %s
void testIf() {
int x = 0;
diff --git a/test/SemaCXX/cxx1z-lambda-star-this.cpp b/test/SemaCXX/cxx1z-lambda-star-this.cpp
index a84e653f5c..2426e8f5a2 100644
--- a/test/SemaCXX/cxx1z-lambda-star-this.cpp
+++ b/test/SemaCXX/cxx1z-lambda-star-this.cpp
@@ -1,231 +1,300 @@
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -emit-llvm-only %s
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
-// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
-
-template<class, class> constexpr bool is_same = false;
-template<class T> constexpr bool is_same<T, T> = true;
-
-namespace test_star_this {
-namespace ns1 {
-class A {
- int x = 345;
- auto foo() {
- (void) [*this, this] { }; //expected-error{{'this' can appear only once}}
- (void) [this] { ++x; };
- (void) [*this] { ++x; }; //expected-error{{read-only variable}}
- (void) [*this] () mutable { ++x; };
- (void) [=] { return x; };
- (void) [&, this] { return x; };
- (void) [=, *this] { return x; };
- (void) [&, *this] { return x; };
- }
-};
-} // end ns1
-
-namespace ns2 {
- class B {
- B(const B&) = delete; //expected-note{{deleted here}}
- int *x = (int *) 456;
- void foo() {
- (void)[this] { return x; };
- (void)[*this] { return x; }; //expected-error{{call to deleted}}
- }
- };
-} // end ns2
-namespace ns3 {
- class B {
- B(const B&) = delete; //expected-note2{{deleted here}}
-
- int *x = (int *) 456;
- public:
- template<class T = int>
- void foo() {
- (void)[this] { return x; };
- (void)[*this] { return x; }; //expected-error2{{call to deleted}}
- }
-
- B() = default;
- } b;
- B *c = (b.foo(), nullptr); //expected-note{{in instantiation}}
-} // end ns3
-
-namespace ns4 {
-template<class U>
-class B {
- B(const B&) = delete; //expected-note{{deleted here}}
- double d = 3.14;
- public:
- template<class T = int>
- auto foo() {
- const auto &L = [*this] (auto a) mutable { //expected-error{{call to deleted}}
- d += a;
- return [this] (auto b) { return d +=b; };
- };
- }
-
- B() = default;
-};
-void main() {
- B<int*> b;
- b.foo(); //expected-note{{in instantiation}}
-} // end main
-} // end ns4
-namespace ns5 {
-
-struct X {
- double d = 3.14;
- X(const volatile X&);
- void foo() {
-
- }
-
- void foo() const { //expected-note{{const}}
-
- auto L = [*this] () mutable {
- static_assert(is_same<decltype(this), X*>);
- ++d;
- auto M = [this] {
- static_assert(is_same<decltype(this), X*>);
- ++d;
- auto N = [] {
- static_assert(is_same<decltype(this), X*>);
- };
- };
- };
-
- auto L1 = [*this] {
- static_assert(is_same<decltype(this), const X*>);
- auto M = [this] () mutable {
- static_assert(is_same<decltype(this), const X*>);
- auto N = [] {
- static_assert(is_same<decltype(this), const X*>);
- };
- };
- auto M2 = [*this] () mutable {
- static_assert(is_same<decltype(this), X*>);
- auto N = [] {
- static_assert(is_same<decltype(this), X*>);
- };
- };
- };
-
- auto GL1 = [*this] (auto a) {
- static_assert(is_same<decltype(this), const X*>);
- auto M = [this] (auto b) mutable {
- static_assert(is_same<decltype(this), const X*>);
- auto N = [] (auto c) {
- static_assert(is_same<decltype(this), const X*>);
- };
- return N;
- };
-
- auto M2 = [*this] (auto a) mutable {
- static_assert(is_same<decltype(this), X*>);
- auto N = [] (auto b) {
- static_assert(is_same<decltype(this), X*>);
- };
- return N;
- };
- return [=](auto a) mutable { M(a)(a); M2(a)(a); };
- };
-
- GL1("abc")("abc");
-
-
- auto L2 = [this] () mutable {
- static_assert(is_same<decltype(this), const X*>);
- ++d; //expected-error{{cannot assign}}
- };
- auto GL = [*this] (auto a) mutable {
- static_assert(is_same<decltype(this), X*>);
- ++d;
- auto M = [this] (auto b) {
- static_assert(is_same<decltype(this), X*>);
- ++d;
- auto N = [] (auto c) {
- static_assert(is_same<decltype(this), X*>);
- };
- N(3.14);
- };
- M("abc");
- };
- GL(3.14);
-
- }
- void foo() volatile const {
- auto L = [this] () {
- static_assert(is_same<decltype(this), const volatile X*>);
- auto M = [*this] () mutable {
- static_assert(is_same<decltype(this), X*>);
- auto N = [this] {
- static_assert(is_same<decltype(this), X*>);
- auto M = [] {
- static_assert(is_same<decltype(this), X*>);
- };
- };
- auto N2 = [*this] {
- static_assert(is_same<decltype(this), const X*>);
- };
- };
- auto M2 = [*this] () {
- static_assert(is_same<decltype(this), const X*>);
- auto N = [this] {
- static_assert(is_same<decltype(this), const X*>);
- };
- };
- };
- }
-
-};
-
-} //end ns5
-namespace ns6 {
-struct X {
- double d;
- auto foo() const {
- auto L = [*this] () mutable {
- auto M = [=] (auto a) {
- auto N = [this] {
- ++d;
- static_assert(is_same<decltype(this), X*>);
- auto O = [*this] {
- static_assert(is_same<decltype(this), const X*>);
- };
- };
- N();
- static_assert(is_same<decltype(this), X*>);
- };
- return M;
- };
- return L;
- }
-};
-
-int main() {
- auto L = X{}.foo();
- auto M = L();
- M(3.14);
-}
-} // end ns6
-namespace ns7 {
-
-struct X {
- double d;
- X();
- X(const X&);
- X(X&) = delete;
- auto foo() const {
- //OK - the object used to initialize our capture is a const object and so prefers the non-deleted ctor.
- const auto &&L = [*this] { };
- }
-
-};
-int main() {
- X x;
- x.foo();
-}
-} // end ns7
-
-} //end ns test_star_this
-
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -emit-llvm-only %s
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+template <class, class>
+constexpr bool is_same = false;
+template <class T>
+constexpr bool is_same<T, T> = true;
+
+namespace test_star_this {
+namespace ns1 {
+class A {
+ int x = 345;
+ auto foo() {
+ (void)[ *this, this ]{}; //expected-error{{'this' can appear only once}}
+ (void)[this] { ++x; };
+ (void)[*this] { ++x; }; //expected-error{{read-only variable}}
+ (void)[*this]() mutable { ++x; };
+ (void)[=] { return x; };
+ (void)[&, this ] { return x; };
+ (void)[ =, *this ] { return x; };
+ (void)[&, *this ] { return x; };
+ }
+};
+} // namespace ns1
+
+namespace ns2 {
+class B {
+ B(const B &) = delete; //expected-note{{deleted here}}
+ int *x = (int *)456;
+ void foo() {
+ (void)[this] { return x; };
+ (void)[*this] { return x; }; //expected-error{{call to deleted}}
+ }
+};
+} // namespace ns2
+
+namespace ns3 {
+class B {
+ B(const B &) = delete; //expected-note2{{deleted here}}
+
+ int *x = (int *)456;
+
+public:
+ template <class T = int>
+ void foo() {
+ (void)[this] { return x; };
+ (void)[*this] { return x; }; //expected-error2{{call to deleted}}
+ }
+
+ B() = default;
+} b;
+B *c = (b.foo(), nullptr); //expected-note{{in instantiation}}
+} // namespace ns3
+
+namespace ns4 {
+template <class U>
+class B {
+ B(const B &) = delete; //expected-note{{deleted here}}
+ double d = 3.14;
+
+public:
+ template <class T = int>
+ auto foo() {
+ const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}}
+ d += a;
+ return [this](auto b) { return d += b; };
+ };
+ }
+
+ B() = default;
+};
+void main() {
+ B<int *> b;
+ b.foo(); //expected-note{{in instantiation}}
+} // end main
+} // namespace ns4
+
+namespace ns5 {
+
+struct X {
+ double d = 3.14;
+ X(const volatile X &);
+ void foo() {
+ }
+
+ void foo() const { //expected-note{{const}}
+
+ auto L = [*this]() mutable {
+ static_assert(is_same<decltype(this), X *>);
+ ++d;
+ auto M = [this] {
+ static_assert(is_same<decltype(this), X *>);
+ ++d;
+ auto N = [] {
+ static_assert(is_same<decltype(this), X *>);
+ };
+ };
+ };
+
+ auto L1 = [*this] {
+ static_assert(is_same<decltype(this), const X *>);
+ auto M = [this]() mutable {
+ static_assert(is_same<decltype(this), const X *>);
+ auto N = [] {
+ static_assert(is_same<decltype(this), const X *>);
+ };
+ };
+ auto M2 = [*this]() mutable {
+ static_assert(is_same<decltype(this), X *>);
+ auto N = [] {
+ static_assert(is_same<decltype(this), X *>);
+ };
+ };
+ };
+
+ auto GL1 = [*this](auto a) {
+ static_assert(is_same<decltype(this), const X *>);
+ auto M = [this](auto b) mutable {
+ static_assert(is_same<decltype(this), const X *>);
+ auto N = [](auto c) {
+ static_assert(is_same<decltype(this), const X *>);
+ };
+ return N;
+ };
+
+ auto M2 = [*this](auto a) mutable {
+ static_assert(is_same<decltype(this), X *>);
+ auto N = [](auto b) {
+ static_assert(is_same<decltype(this), X *>);
+ };
+ return N;
+ };
+ return [=](auto a) mutable { M(a)(a); M2(a)(a); };
+ };
+
+ GL1("abc")
+ ("abc");
+
+ auto L2 = [this]() mutable {
+ static_assert(is_same<decltype(this), const X *>);
+ ++d; //expected-error{{cannot assign}}
+ };
+ auto GL = [*this](auto a) mutable {
+ static_assert(is_same<decltype(this), X *>);
+ ++d;
+ auto M = [this](auto b) {
+ static_assert(is_same<decltype(this), X *>);
+ ++d;
+ auto N = [](auto c) {
+ static_assert(is_same<decltype(this), X *>);
+ };
+ N(3.14);
+ };
+ M("abc");
+ };
+ GL(3.14);
+ }
+ void foo() volatile const {
+ auto L = [this]() {
+ static_assert(is_same<decltype(this), const volatile X *>);
+ auto M = [*this]() mutable {
+ static_assert(is_same<decltype(this), X *>);
+ auto N = [this] {
+ static_assert(is_same<decltype(this), X *>);
+ auto M = [] {
+ static_assert(is_same<decltype(this), X *>);
+ };
+ };
+ auto N2 = [*this] {
+ static_assert(is_same<decltype(this), const X *>);
+ };
+ };
+ auto M2 = [*this]() {
+ static_assert(is_same<decltype(this), const X *>);
+ auto N = [this] {
+ static_assert(is_same<decltype(this), const X *>);
+ };
+ };
+ };
+ }
+};
+
+} // namespace ns5
+namespace ns6 {
+struct X {
+ double d;
+ auto foo() const {
+ auto L = [*this]() mutable {
+ auto M = [=](auto a) {
+ auto N = [this] {
+ ++d;
+ static_assert(is_same<decltype(this), X *>);
+ auto O = [*this] {
+ static_assert(is_same<decltype(this), const X *>);
+ };
+ };
+ N();
+ static_assert(is_same<decltype(this), X *>);
+ };
+ return M;
+ };
+ return L;
+ }
+};
+
+int main() {
+ auto L = X{}.foo();
+ auto M = L();
+ M(3.14);
+}
+} // namespace ns6
+namespace ns7 {
+
+struct X {
+ double d;
+ X();
+ X(const X &);
+ X(X &) = delete;
+ auto foo() const {
+ //OK - the object used to initialize our capture is a const object and so prefers the non-deleted ctor.
+ const auto &&L = [*this]{};
+ }
+};
+int main() {
+ X x;
+ x.foo();
+}
+} // namespace ns7
+
+} // namespace test_star_this
+
+namespace PR32831 {
+// https://bugs.llvm.org/show_bug.cgi?id=32831
+namespace ns1 {
+template <typename Func>
+void fun_template(Func func) {
+ (void)[&]() {
+ func(0);
+ };
+}
+
+class A {
+ void member_foo() {
+ (void)[this] {
+ (void)[this] {
+ fun_template(
+ [this](auto X) {
+ auto L = [this](auto Y) { member_foo(); };
+ L(5);
+ });
+ fun_template(
+ [this](auto) { member_foo(); });
+ };
+ };
+ }
+};
+} // namespace ns1
+
+namespace ns2 {
+
+struct B {
+ int data = 0;
+ template <class F>
+ void mem2(F f) {
+ (void)[&](auto f) {
+ (void)[&] { f(this->data); };
+ }
+ (f);
+ }
+};
+
+class A {
+ void member_foo() {
+ (void)[this] {
+ (void)[this] {
+ B{}.mem2(
+ [this](auto X) {
+ auto L = [this](auto Y) { member_foo(); };
+ L(5);
+ });
+ B{}.mem2(
+ [this](auto) { member_foo(); });
+ };
+ };
+ }
+ int data = 0;
+ auto m2() {
+ return [this] { return [] () -> decltype(data){ return 0; }; };
+ }
+ auto m3() {
+ return [] { return [] () -> decltype(data){ return 0; }; };
+ }
+};
+
+} // namespace ns2
+
+} // namespace PR32831
+
diff --git a/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/test/SemaCXX/cxx1z-noexcept-function-type.cpp
index a3f7109704..814b04c6e4 100644
--- a/test/SemaCXX/cxx1z-noexcept-function-type.cpp
+++ b/test/SemaCXX/cxx1z-noexcept-function-type.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s
-// RUN: %clang_cc1 -std=c++1z -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec
+// RUN: %clang_cc1 -std=c++17 -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec
+// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-c++1z-compat-mangling -DNO_COMPAT_MANGLING %s
+// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-noexcept-type -DNO_COMPAT_MANGLING %s
#if __cplusplus > 201402L
@@ -16,7 +18,7 @@ template<typename A, typename B> void redecl3() throw(B); // expected-error {{do
typedef int I;
template<bool B> void redecl4(I) noexcept(B);
-template<bool B> void redecl4(I) noexcept(B); // expected-note {{failed template argument deduction}}
+template<bool B> void redecl4(I) noexcept(B); // expected-note {{could not match 'void (I) noexcept(false)' (aka 'void (int) noexcept(false)') against 'void (int) noexcept'}}
void (*init_with_exact_type_a)(int) noexcept = redecl4<true>;
void (*init_with_mismatched_type_a)(int) = redecl4<true>;
@@ -81,7 +83,7 @@ namespace CompatWarning {
auto f5() -> void (*)() throw();
auto f6() -> void (&)() throw();
auto f7() -> void (X::*)() throw();
-#if __cplusplus <= 201402L
+#if __cplusplus <= 201402L && !defined(NO_COMPAT_MANGLING)
// expected-warning@-8 {{mangled name of 'f1' will change in C++17 due to non-throwing exception specification in function signature}}
// expected-warning@-8 {{mangled name of 'f2' will change in C++17 due to non-throwing exception specification in function signature}}
// expected-warning@-8 {{mangled name of 'f3' will change in C++17 due to non-throwing exception specification in function signature}}
diff --git a/test/SemaCXX/cxx2a-destroying-delete.cpp b/test/SemaCXX/cxx2a-destroying-delete.cpp
new file mode 100644
index 0000000000..a085c11c26
--- /dev/null
+++ b/test/SemaCXX/cxx2a-destroying-delete.cpp
@@ -0,0 +1,103 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+namespace std {
+ using size_t = decltype(sizeof(0));
+ enum class align_val_t : size_t;
+
+ struct destroying_delete_t {
+ struct __construct { explicit __construct() = default; };
+ explicit destroying_delete_t(__construct) {}
+ };
+
+ inline constexpr destroying_delete_t destroying_delete(destroying_delete_t::__construct());
+}
+
+void operator delete(void*, std::destroying_delete_t); // ok, just a placement delete
+
+struct A;
+void operator delete(A*, std::destroying_delete_t); // expected-error {{first parameter of 'operator delete' must have type 'void *'}}
+
+struct A {
+ void operator delete(A*, std::destroying_delete_t);
+ void operator delete(A*, std::destroying_delete_t, std::size_t);
+ void operator delete(A*, std::destroying_delete_t, std::align_val_t);
+ void operator delete(A*, std::destroying_delete_t, std::size_t, std::align_val_t);
+ void operator delete(A*, std::destroying_delete_t, int); // expected-error {{destroying operator delete can have only an optional size and optional alignment parameter}}
+ // FIXME: It's probably a language defect that we permit usual operator delete to be variadic.
+ void operator delete(A*, std::destroying_delete_t, std::size_t, ...);
+
+ void operator delete(struct X*, std::destroying_delete_t, std::size_t, ...); // expected-error {{first parameter of 'operator delete' must have type 'A *'}}
+
+ void operator delete(void*, std::size_t);
+};
+
+void delete_A(A *a) { delete a; }
+
+namespace convert_param {
+ struct A {
+ void operator delete(
+ A*,
+ std::destroying_delete_t);
+ };
+ struct B : private A { using A::operator delete; }; // expected-note 2{{declared private here}}
+ struct C : B {};
+ void delete_C(C *c) { delete c; } // expected-error {{cannot cast 'convert_param::C' to its private base class 'convert_param::A'}}
+
+ // expected-error@-7 {{cannot cast 'convert_param::D' to its private base class 'convert_param::A'}}
+ struct D : B { virtual ~D() {} }; // expected-note {{while checking implicit 'delete this' for virtual destructor}}
+}
+
+namespace delete_selection {
+ struct B {
+ void operator delete(void*) = delete;
+ void operator delete(B *, std::destroying_delete_t) = delete; // expected-note {{deleted}}
+ };
+ void delete_B(B *b) { delete b; } // expected-error {{deleted}}
+
+ struct C {
+ C();
+ void *operator new(std::size_t);
+ void operator delete(void*) = delete;
+ void operator delete(C *, std::destroying_delete_t) = delete;
+ };
+ // FIXME: This should be ill-formed, but we incorrectly decide that overload
+ // resolution failed (because it selected a deleted function) and thus no
+ // 'operator delete' should be called.
+ C *new_C() { return new C; }
+
+ struct D {
+ void operator delete(D *, std::destroying_delete_t) = delete; // expected-note {{deleted}}
+ void operator delete(D *, std::destroying_delete_t, std::align_val_t) = delete;
+ };
+ void delete_D(D *d) { delete d; } // expected-error {{deleted}}
+
+ struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) E {
+ void operator delete(E *, std::destroying_delete_t) = delete;
+ void operator delete(E *, std::destroying_delete_t, std::align_val_t) = delete; // expected-note {{deleted}}
+ };
+ void delete_E(E *e) { delete e; } // expected-error {{deleted}}
+
+ struct F {
+ void operator delete(F *, std::destroying_delete_t) = delete; // expected-note {{deleted}}
+ void operator delete(F *, std::destroying_delete_t, std::size_t) = delete;
+ };
+ void delete_F(F *f) { delete f; } // expected-error {{deleted}}
+
+ struct G {
+ void operator delete(G *, std::destroying_delete_t, std::align_val_t) = delete;
+ void operator delete(G *, std::destroying_delete_t, std::size_t) = delete; // expected-note {{deleted}}
+ };
+ void delete_G(G *g) { delete g; } // expected-error {{deleted}}
+
+ struct H {
+ void operator delete(H *, std::destroying_delete_t, std::align_val_t) = delete; // expected-note {{deleted}}
+ void operator delete(H *, std::destroying_delete_t, std::size_t, std::align_val_t) = delete;
+ };
+ void delete_H(H *h) { delete h; } // expected-error {{deleted}}
+
+ struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) I {
+ void operator delete(I *, std::destroying_delete_t, std::size_t) = delete;
+ void operator delete(I *, std::destroying_delete_t, std::size_t, std::align_val_t) = delete; // expected-note {{deleted}}
+ };
+ void delete_I(I *i) { delete i; } // expected-error {{deleted}}
+}
diff --git a/test/SemaCXX/cxx2a-lambda-equals-this.cpp b/test/SemaCXX/cxx2a-lambda-equals-this.cpp
new file mode 100644
index 0000000000..ce6916322e
--- /dev/null
+++ b/test/SemaCXX/cxx2a-lambda-equals-this.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+// expected-no-diagnostics
+
+// This test does two things.
+// Deleting the copy constructor ensures that an [=, this] capture doesn't copy the object.
+// Accessing a member variable from the lambda ensures that the capture actually works.
+class A {
+ A(const A &) = delete;
+ int i;
+
+ void func() {
+ auto L = [=, this]() -> int { return i; };
+ L();
+ }
+};
diff --git a/test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp b/test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
new file mode 100644
index 0000000000..e9cbb1a185
--- /dev/null
+++ b/test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+struct X {
+ void ref() & {}
+ void cref() const& {}
+};
+
+void test() {
+ X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}}
+ X{}.cref(); // expected-no-error
+
+ (X{}.*&X::ref)(); // expected-error-re{{pointer-to-member function type 'void (X::*)() {{.*}}&' can only be called on an lvalue}}
+ (X{}.*&X::cref)(); // expected-no-error
+}
diff --git a/test/SemaCXX/cxx98-compat-flags.cpp b/test/SemaCXX/cxx98-compat-flags.cpp
index 62d687c49c..5e07964335 100644
--- a/test/SemaCXX/cxx98-compat-flags.cpp
+++ b/test/SemaCXX/cxx98-compat-flags.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Werror %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat-pedantic -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Wno-binary-literal -Werror %s
template<typename T> int TemplateFn(T) { return 0; }
void LocalTemplateArg() {
@@ -32,4 +32,6 @@ namespace CopyCtorIssues {
const NoViable &b = NoViable(); // expected-warning {{copying variable of type 'CopyCtorIssues::NoViable' when binding a reference to a temporary would find no viable constructor in C++98}}
const Ambiguous &c = Ambiguous(); // expected-warning {{copying variable of type 'CopyCtorIssues::Ambiguous' when binding a reference to a temporary would find ambiguous constructors in C++98}}
const Deleted &d = Deleted(); // expected-warning {{copying variable of type 'CopyCtorIssues::Deleted' when binding a reference to a temporary would invoke a deleted constructor in C++98}}
+
+ int n = 0b00100101001; // expected-warning {{binary integer literals are incompatible with C++ standards before C++14}}
}
diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp
index 1b1f7dc8a7..1e31d701d0 100644
--- a/test/SemaCXX/decl-expr-ambiguity.cpp
+++ b/test/SemaCXX/decl-expr-ambiguity.cpp
@@ -48,13 +48,20 @@ void f() {
struct RAII {
RAII();
+ RAII(int);
~RAII();
};
+struct NotRAII {
+ NotRAII();
+ NotRAII(int);
+};
+
void func();
void func2(short);
namespace N {
struct S;
+ int n;
void emptyParens() {
RAII raii(); // expected-warning {{function declaration}} expected-note {{remove parentheses to declare a variable}}
@@ -69,6 +76,23 @@ namespace N {
void nonEmptyParens() {
int f = 0, // g = 0; expected-note {{change this ',' to a ';' to call 'func2'}}
func2(short(f)); // expected-warning {{function declaration}} expected-note {{add a pair of parentheses}}
+
+ RAII(n); // expected-warning {{parentheses were disambiguated as redundant parentheses around declaration of variable named 'n'}}
+ // expected-note@-1 {{add a variable name to declare a 'RAII' initialized with 'n'}}
+ // expected-note@-2 {{add enclosing parentheses to perform a function-style cast}}
+ // expected-note@-3 {{remove parentheses to silence this warning}}
+
+ RAII(undeclared1);
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wredundant-parens"
+ RAII(undeclared2); // expected-warning {{redundant parentheses surrounding declarator}}
+#pragma clang diagnostic pop
+
+ {
+ NotRAII(n); // expected-warning {{parentheses were disambiguated as redundant parentheses around declaration of variable named 'n'}}
+ // expected-note@-1 {{add enclosing parentheses to perform a function-style cast}}
+ // expected-note@-2 {{remove parentheses to silence this warning}}
+ }
}
}
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index 80ceb3768d..57cb77d6cb 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -48,7 +48,7 @@ Z z2;
void f(X x, const X cx) {
x = cx;
#if __cplusplus <= 199711L
- // expected-note@-2 {{assignment operator for 'X' first required here}}
+ // expected-note@-2 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
diff --git a/test/SemaCXX/deprecated.cpp b/test/SemaCXX/deprecated.cpp
index 0fd275e2ce..773085bf2b 100644
--- a/test/SemaCXX/deprecated.cpp
+++ b/test/SemaCXX/deprecated.cpp
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -std=c++98 %s -Wdeprecated -verify -triple x86_64-linux-gnu
// RUN: %clang_cc1 -std=c++11 %s -Wdeprecated -verify -triple x86_64-linux-gnu
-// RUN: %clang_cc1 -std=c++1y %s -Wdeprecated -verify -triple x86_64-linux-gnu
-// RUN: %clang_cc1 -std=c++1z %s -Wdeprecated -verify -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++14 %s -Wdeprecated -verify -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++17 %s -Wdeprecated -verify -triple x86_64-linux-gnu
-// RUN: %clang_cc1 -std=c++1y %s -Wdeprecated -verify -triple x86_64-linux-gnu -Wno-deprecated-register -DNO_DEPRECATED_FLAGS
+// RUN: %clang_cc1 -std=c++14 %s -Wdeprecated -verify -triple x86_64-linux-gnu -Wno-deprecated-register -DNO_DEPRECATED_FLAGS
#include "Inputs/register.h"
@@ -12,18 +12,23 @@ void h() throw(int);
void i() throw(...);
#if __cplusplus > 201402L
// expected-warning@-4 {{dynamic exception specifications are deprecated}} expected-note@-4 {{use 'noexcept' instead}}
-// expected-error@-4 {{ISO C++1z does not allow dynamic exception specifications}} expected-note@-4 {{use 'noexcept(false)' instead}}
-// expected-error@-4 {{ISO C++1z does not allow dynamic exception specifications}} expected-note@-4 {{use 'noexcept(false)' instead}}
+// expected-error@-4 {{ISO C++17 does not allow dynamic exception specifications}} expected-note@-4 {{use 'noexcept(false)' instead}}
+// expected-error@-4 {{ISO C++17 does not allow dynamic exception specifications}} expected-note@-4 {{use 'noexcept(false)' instead}}
#elif __cplusplus >= 201103L
// expected-warning@-8 {{dynamic exception specifications are deprecated}} expected-note@-8 {{use 'noexcept' instead}}
// expected-warning@-8 {{dynamic exception specifications are deprecated}} expected-note@-8 {{use 'noexcept(false)' instead}}
// expected-warning@-8 {{dynamic exception specifications are deprecated}} expected-note@-8 {{use 'noexcept(false)' instead}}
#endif
-void stuff() {
+void stuff(register int q) {
+#if __cplusplus > 201402L
+ // expected-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}}
+#elif __cplusplus >= 201103L && !defined(NO_DEPRECATED_FLAGS)
+ // expected-warning@-4 {{'register' storage class specifier is deprecated}}
+#endif
register int n;
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow 'register' storage class specifier}}
+ // expected-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}}
#elif __cplusplus >= 201103L && !defined(NO_DEPRECATED_FLAGS)
// expected-warning@-4 {{'register' storage class specifier is deprecated}}
#endif
@@ -34,14 +39,14 @@ void stuff() {
bool b;
++b;
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow incrementing expression of type bool}}
+ // expected-error@-2 {{ISO C++17 does not allow incrementing expression of type bool}}
#else
// expected-warning@-4 {{incrementing expression of type bool is deprecated}}
#endif
b++;
#if __cplusplus > 201402L
- // expected-error@-2 {{ISO C++1z does not allow incrementing expression of type bool}}
+ // expected-error@-2 {{ISO C++17 does not allow incrementing expression of type bool}}
#else
// expected-warning@-4 {{incrementing expression of type bool is deprecated}}
#endif
@@ -75,21 +80,24 @@ namespace DeprecatedCopy {
struct Assign {
Assign &operator=(const Assign&); // expected-warning {{definition of implicit copy constructor for 'Assign' is deprecated because it has a user-declared copy assignment operator}}
};
- Assign a1, a2(a1); // expected-note {{implicit copy constructor for 'Assign' first required here}}
+ Assign a1, a2(a1); // expected-note {{implicit copy constructor for 'DeprecatedCopy::Assign' first required here}}
struct Ctor {
Ctor();
Ctor(const Ctor&); // expected-warning {{definition of implicit copy assignment operator for 'Ctor' is deprecated because it has a user-declared copy constructor}}
};
Ctor b1, b2;
- void f() { b1 = b2; } // expected-note {{implicit copy assignment operator for 'Ctor' first required here}}
+ void f() { b1 = b2; } // expected-note {{implicit copy assignment operator for 'DeprecatedCopy::Ctor' first required here}}
struct Dtor {
~Dtor();
// expected-warning@-1 {{definition of implicit copy constructor for 'Dtor' is deprecated because it has a user-declared destructor}}
// expected-warning@-2 {{definition of implicit copy assignment operator for 'Dtor' is deprecated because it has a user-declared destructor}}
};
- Dtor c1, c2(c1); // expected-note {{implicit copy constructor for 'Dtor' first required here}}
- void g() { c1 = c2; } // expected-note {{implicit copy assignment operator for 'Dtor' first required here}}
+ Dtor c1, c2(c1); // expected-note {{implicit copy constructor for 'DeprecatedCopy::Dtor' first required here}}
+ void g() { c1 = c2; } // expected-note {{implicit copy assignment operator for 'DeprecatedCopy::Dtor' first required here}}
}
#endif
+
+# 1 "/usr/include/system-header.h" 1 3
+void system_header_function(void) throw();
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index 49cdc50f3c..00d2fc5529 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -1,5 +1,36 @@
// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -fcxx-exceptions -verify %s
// RUN: %clang_cc1 -std=c++11 -triple %ms_abi_triple -DMSABI -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s
+
+#if defined(BE_THE_HEADER)
+
+// Wdelete-non-virtual-dtor should warn about the delete from smart pointer
+// classes in system headers (std::unique_ptr...) too.
+
+#pragma clang system_header
+namespace dnvd {
+
+struct SystemB {
+ virtual void foo();
+};
+
+template <typename T>
+class simple_ptr {
+public:
+ simple_ptr(T* t): _ptr(t) {}
+ ~simple_ptr() { delete _ptr; } // \
+ // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} \
+ // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}}
+ T& operator*() const { return *_ptr; }
+private:
+ T* _ptr;
+};
+}
+
+#else
+
+#define BE_THE_HEADER
+#include __FILE__
+
class A {
public:
~A();
@@ -213,18 +244,6 @@ struct VD: VB {};
struct VF final: VB {};
template <typename T>
-class simple_ptr {
-public:
- simple_ptr(T* t): _ptr(t) {}
- ~simple_ptr() { delete _ptr; } // \
- // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} \
- // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}}
- T& operator*() const { return *_ptr; }
-private:
- T* _ptr;
-};
-
-template <typename T>
class simple_ptr2 {
public:
simple_ptr2(T* t): _ptr(t) {}
@@ -235,6 +254,7 @@ private:
};
void use(B&);
+void use(SystemB&);
void use(VB&);
void nowarnstack() {
@@ -335,10 +355,28 @@ void warn0() {
}
}
+// Taken from libc++, slightly simplified.
+template <class>
+struct __is_destructible_apply { typedef int type; };
+struct __two {char __lx[2];};
+template <typename _Tp>
+struct __is_destructor_wellformed {
+ template <typename _Tp1>
+ static char __test(typename __is_destructible_apply<
+ decltype(_Tp1().~_Tp1())>::type);
+ template <typename _Tp1>
+ static __two __test (...);
+
+ static const bool value = sizeof(__test<_Tp>(12)) == sizeof(char);
+};
+
void warn0_explicit_dtor(B* b, B& br, D* d) {
b->~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}
b->B::~B(); // No warning when the call isn't virtual.
+ // No warning in unevaluated contexts.
+ (void)__is_destructor_wellformed<B>::value;
+
br.~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}
br.B::~B();
@@ -367,6 +405,10 @@ void nowarn1() {
simple_ptr<VF> vf(new VF());
use(*vf);
}
+ {
+ simple_ptr<SystemB> sb(new SystemB());
+ use(*sb);
+ }
}
void warn1() {
@@ -451,3 +493,4 @@ void foo1() {
x.foo1();
}
}
+#endif // BE_THE_HEADER
diff --git a/test/SemaCXX/dllimport-memptr.cpp b/test/SemaCXX/dllimport-memptr.cpp
new file mode 100644
index 0000000000..35bf5b8610
--- /dev/null
+++ b/test/SemaCXX/dllimport-memptr.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -verify -std=c++11 %s
+
+// expected-no-diagnostics
+
+struct __declspec(dllimport) Foo { int get_a(); };
+template <int (Foo::*Getter)()> struct HasValue { };
+HasValue<&Foo::get_a> hv;
diff --git a/test/SemaCXX/enable_if.cpp b/test/SemaCXX/enable_if.cpp
index 01b6f8fd3a..93014f50d5 100644
--- a/test/SemaCXX/enable_if.cpp
+++ b/test/SemaCXX/enable_if.cpp
@@ -472,3 +472,44 @@ 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'}}
+ }
+}
+}
+
+namespace TypeOfFn {
+ template <typename T, typename U>
+ struct is_same;
+
+ template <typename T> struct is_same<T, T> {
+ enum { value = 1 };
+ };
+
+ void foo(int a) __attribute__((enable_if(a, "")));
+ void foo(float a) __attribute__((enable_if(1, "")));
+
+ static_assert(is_same<__typeof__(foo)*, decltype(&foo)>::value, "");
+}
diff --git a/test/SemaCXX/enum-attr.cpp b/test/SemaCXX/enum-attr.cpp
new file mode 100644
index 0000000000..7726aff483
--- /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.cpp b/test/SemaCXX/enum.cpp
index 6b0824b751..cfe5760112 100644
--- a/test/SemaCXX/enum.cpp
+++ b/test/SemaCXX/enum.cpp
@@ -110,3 +110,13 @@ enum { overflow = 123456 * 234567 };
// expected-warning@-2 {{not an integral constant expression}}
// expected-note@-3 {{value 28958703552 is outside the range of representable values}}
#endif
+
+// PR28903
+struct PR28903 {
+ enum {
+ PR28903_A = (enum { // expected-error-re {{'PR28903::(anonymous enum at {{.*}})' cannot be defined in an enumeration}}
+ PR28903_B,
+ PR28903_C = PR28903_B
+ })
+ };
+};
diff --git a/test/SemaCXX/eval-crashes.cpp b/test/SemaCXX/eval-crashes.cpp
new file mode 100644
index 0000000000..23946845d8
--- /dev/null
+++ b/test/SemaCXX/eval-crashes.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+namespace pr32864_0 {
+ struct transfer_t {
+ void *fctx;
+ };
+ template <typename Ctx> class record {
+ void run() {
+ transfer_t t;
+ Ctx from{t.fctx};
+ }
+ };
+}
+
+namespace pr33140_0a {
+ struct S {
+ constexpr S(const int &a = 0) {}
+ };
+ void foo(void) { S s[2] = {}; }
+}
+
+namespace pr33140_0b {
+ bool bar(float const &f = 0);
+ bool foo() { return bar() && bar(); }
+}
+
+namespace pr33140_2 {
+ // FIXME: The declaration of 'b' below should lifetime-extend two int
+ // temporaries, invalidating this warning to some extent.
+ struct A { int &&r = 0; }; // expected-warning {{binding reference member 'r' to a temporary}} expected-note {{here}}
+ struct B { A x, y; };
+ B b = {};
+}
+
+namespace pr33140_3 {
+ typedef struct Y { unsigned int c; } Y_t;
+ struct X {
+ Y_t a;
+ };
+ struct X foo[2] = {[0 ... 1] = {.a = (Y_t){.c = 0}}};
+}
+
+namespace pr33140_6 {
+ struct Y { unsigned int c; };
+ struct X { struct Y *p; };
+ int f() {
+ // FIXME: This causes clang to crash.
+ //return (struct X[2]){ [0 ... 1] = { .p = &(struct Y&)(struct Y&&)(struct Y){0} } }[0].p->c;
+ return 0;
+ }
+}
+
+namespace pr33140_10 {
+ int a(const int &n = 0);
+ bool b() { return a() == a(); }
+}
diff --git a/test/SemaCXX/flexible-array-test.cpp b/test/SemaCXX/flexible-array-test.cpp
index 2d74fa5245..f2105ca361 100644
--- a/test/SemaCXX/flexible-array-test.cpp
+++ b/test/SemaCXX/flexible-array-test.cpp
@@ -66,6 +66,11 @@ union B {
char c[];
};
+class C {
+ char c[]; // expected-error {{flexible array member 'c' with type 'char []' is not at the end of class}}
+ int s; // expected-note {{next field declaration is here}}
+};
+
namespace rdar9065507 {
struct StorageBase {
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index 08a9982c63..d6b527ff8a 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -241,3 +241,37 @@ namespace pr18587 {
}
}
}
+
+namespace PR32933 {
+// https://bugs.llvm.org/show_bug.cgi?id=32933
+void foo ()
+{
+ int b = 1, a[b];
+ a[0] = 0;
+ [&] { for (int c : a) 0; } ();
+}
+
+
+int foo(int b) {
+ int varr[b][(b+=8)];
+ b = 15;
+ [&] {
+ int i = 0;
+ for (auto &c : varr)
+ {
+ c[0] = ++b;
+ }
+ [&] {
+ int i = 0;
+ for (auto &c : varr) {
+ int j = 0;
+ for(auto &c2 : c) {
+ ++j;
+ }
+ ++i;
+ }
+ }();
+ }();
+ return b;
+}
+} \ No newline at end of file
diff --git a/test/SemaCXX/friend2.cpp b/test/SemaCXX/friend2.cpp
index 347af0d61b..d1d4b628ba 100644
--- a/test/SemaCXX/friend2.cpp
+++ b/test/SemaCXX/friend2.cpp
@@ -170,3 +170,40 @@ struct Test {
template class Test<int>;
}
+
+namespace pr14785 {
+template<typename T>
+struct Somewhat {
+ void internal() const { }
+ friend void operator+(int const &, Somewhat<T> const &) {} // expected-error{{redefinition of 'operator+'}}
+};
+
+void operator+(int const &, Somewhat<char> const &x) { // expected-note {{previous definition is here}}
+ x.internal(); // expected-note{{in instantiation of template class 'pr14785::Somewhat<char>' requested here}}
+}
+}
+
+namespace D30375 {
+template <typename K> struct B {
+ template <typename A> bool insert(A &);
+};
+
+template <typename K>
+template <typename A> bool B<K>::insert(A &x) { return x < x; }
+
+template <typename K> class D {
+ B<K> t;
+
+public:
+ K x;
+ bool insert() { return t.insert(x); }
+ template <typename K1> friend bool operator<(const D<K1> &, const D<K1> &);
+};
+
+template <typename K> bool operator<(const D<K> &, const D<K> &);
+
+void func() {
+ D<D<int>> cache;
+ cache.insert();
+}
+}
diff --git a/test/SemaCXX/imaginary-constants.cpp b/test/SemaCXX/imaginary-constants.cpp
new file mode 100644
index 0000000000..bbff92755a
--- /dev/null
+++ b/test/SemaCXX/imaginary-constants.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -include %s -std=gnu++98
+// RUN: %clang_cc1 -fsyntax-only -verify %s -include %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -include %s -std=c++14 -DCXX14=1
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+_Complex int val1 = 2i;
+_Complex long val2 = 2il;
+_Complex long long val3 = 2ill;
+_Complex float val4 = 2.0if;
+_Complex double val5 = 2.0i;
+_Complex long double val6 = 2.0il;
+
+#if CXX14
+
+#pragma clang system_header
+
+namespace std {
+ template<typename T> struct complex {};
+ complex<float> operator""if(unsigned long long);
+ complex<float> operator""if(long double);
+
+ complex<double> operator"" i(unsigned long long);
+ complex<double> operator"" i(long double);
+
+ complex<long double> operator"" il(unsigned long long);
+ complex<long double> operator"" il(long double);
+}
+
+using namespace std;
+
+complex<float> f1 = 2.0if;
+complex<float> f2 = 2if;
+complex<double> d1 = 2.0i;
+complex<double> d2 = 2i;
+complex<long double> l1 = 2.0il;
+complex<long double> l2 = 2il;
+
+#endif
+
+#endif
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
index f400c222de..c21f773e94 100644
--- a/test/SemaCXX/implicit-exception-spec.cpp
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -121,7 +121,7 @@ namespace PotentiallyConstructed {
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}}
+ static_assert(noexcept(delete &a) == F, "");
// These are last because the first failure here causes instantiation to bail out.
static_assert(noexcept(new (nothrow) T()) == A, ""); // expected-error 2{{abstract}}
diff --git a/test/SemaCXX/init-expr-crash.cpp b/test/SemaCXX/init-expr-crash.cpp
new file mode 100644
index 0000000000..407da78e60
--- /dev/null
+++ b/test/SemaCXX/init-expr-crash.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11
+
+// Test reproduces a pair of crashes that were caused by code attempting
+// to materialize a default constructor's exception specifier.
+
+template <class T> struct A {
+ static T tab[];
+
+ const int M = UNDEFINED; // expected-error {{use of undeclared identifier}}
+
+ int main()
+ {
+ A<char> a;
+
+ return 0;
+ }
+};
+
+template <class T> struct B {
+ static T tab[];
+
+ // expected-error@+1 {{invalid application of 'sizeof' to an incomplete type}}
+ const int N = sizeof(B<char>::tab) / sizeof(char);
+
+ int main()
+ {
+ B<char> b;
+
+ return 0;
+ }
+};
diff --git a/test/SemaCXX/inline.cpp b/test/SemaCXX/inline.cpp
index b20bc18d0a..ba29521ce5 100644
--- a/test/SemaCXX/inline.cpp
+++ b/test/SemaCXX/inline.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s -Wc++98-c++11-c++14-compat
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s -Wc++98-c++11-c++14-compat
// Check that we don't allow illegal uses of inline
// (checking C++-only constructs here)
@@ -12,7 +12,7 @@ void localVar() {
// Check that we warn appropriately.
#if __cplusplus <= 201402L
-inline int a; // expected-warning{{inline variables are a C++1z extension}}
+inline int a; // expected-warning{{inline variables are a C++17 extension}}
#else
-inline int a; // expected-warning{{inline variables are incompatible with C++ standards before C++1z}}
+inline int a; // expected-warning{{inline variables are incompatible with C++ standards before C++17}}
#endif
diff --git a/test/SemaCXX/integer-overflow.cpp b/test/SemaCXX/integer-overflow.cpp
index a119f0eabe..6abc956144 100644
--- a/test/SemaCXX/integer-overflow.cpp
+++ b/test/SemaCXX/integer-overflow.cpp
@@ -164,7 +164,7 @@ uint64_t check_integer_overflows(int i) { //expected-note {{declared here}}
// expected-warning@+3 {{array index 536870912 is past the end of the array (which contains 10 elements)}}
// expected-note@+1 {{array 'a' declared here}}
uint64_t a[10];
- a[4608 * 1024 * 1024] = 1i;
+ a[4608 * 1024 * 1024] = 1;
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024)));
diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp
index 172be6b826..fd50d328da 100644
--- a/test/SemaCXX/invalid-member-expr.cpp
+++ b/test/SemaCXX/invalid-member-expr.cpp
@@ -53,9 +53,7 @@ namespace test3 {
namespace rdar11293995 {
struct Length {
- explicit Length(PassRefPtr<CalculationValue>); // expected-error {{unknown type name}} \
- expected-error {{expected ')'}} \
- expected-note {{to match this '('}}
+ explicit Length(PassRefPtr<CalculationValue>); // expected-error {{no template named 'PassRefPtr}} expected-error {{undeclared identifier 'CalculationValue'}}
};
struct LengthSize {
diff --git a/test/SemaCXX/invalid-template-params.cpp b/test/SemaCXX/invalid-template-params.cpp
new file mode 100644
index 0000000000..0c463fe13d
--- /dev/null
+++ b/test/SemaCXX/invalid-template-params.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+template<class> class Foo {
+ template<class UBar // expected-error {{expected ';' after class}}
+ // expected-note@-1 {{'UBar' declared here}}
+ void foo1(); // expected-error {{a non-type template parameter cannot have type 'class UBar'}}
+ // expected-error@-1 {{expected ',' or '>' in template-parameter-list}}
+ // expected-warning@-2 {{declaration does not declare anything}}
+};
+
+Foo<int>::UBar g1; // expected-error {{no type named 'UBar' in 'Foo<int>'}}
+
+class C0 {
+public:
+ template<typename T0, typename T1 = T0 // missing closing angle bracket
+ struct S0 {}; // expected-error {{'S0' cannot be defined in a type specifier}}
+ // expected-error@-1 {{cannot combine with previous 'type-name' declaration specifier}}
+ // expected-error@-2 {{expected ',' or '>' in template-parameter-list}}
+ // expected-warning@-3 {{declaration does not declare anything}}
+ C0() : m(new S0<int>) {} // expected-error {{expected '(' for function-style cast or type construction}}
+ // expected-error@-1 {{expected expression}}
+ S0<int> *m; // expected-error {{expected member name or ';' after declaration specifiers}}
+};
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
index e0ab15dc63..efbb47681a 100644
--- a/test/SemaCXX/lambda-expressions.cpp
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -525,9 +525,9 @@ template <int N>
class S {};
void foo() {
- const int num = 18; // expected-note {{'num' declared here}}
+ const int num = 18;
auto outer = []() {
- auto inner = [](S<num> &X) {}; // expected-error {{variable 'num' cannot be implicitly captured in a lambda with no capture-default specified}}
+ auto inner = [](S<num> &X) {};
};
}
}
@@ -573,3 +573,13 @@ void foo1() {
auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
}
}
+
+namespace PR25627_dont_odr_use_local_consts {
+
+ template<int> struct X {};
+
+ void foo() {
+ const int N = 10;
+ (void) [] { X<N> x; };
+ }
+}
diff --git a/test/SemaCXX/linkage2.cpp b/test/SemaCXX/linkage2.cpp
index a7eb15f7c6..6f43af39f7 100644
--- a/test/SemaCXX/linkage2.cpp
+++ b/test/SemaCXX/linkage2.cpp
@@ -143,9 +143,10 @@ namespace test13 {
}
namespace test14 {
+ // Anonymous namespace implies internal linkage, so 'static' has no effect.
namespace {
- void a(void); // expected-note {{previous declaration is here}}
- static void a(void) {} // expected-error {{static declaration of 'a' follows non-static declaration}}
+ void a(void);
+ static void a(void) {}
}
}
@@ -217,3 +218,34 @@ namespace PR18964 {
unsigned &*foo; //expected-error{{'foo' declared as a pointer to a reference of type}}
extern struct {} *foo; // don't assert
}
+
+namespace typedef_name_for_linkage {
+ template<typename T> struct Use {};
+
+ struct A { A(); A(const A&); ~A(); };
+
+ typedef struct {
+ A a;
+ } B;
+
+ struct C {
+ typedef struct {
+ A a;
+ } D;
+ };
+
+ typedef struct {
+ void f() { static int n; struct Inner {};}
+ } E;
+
+ // FIXME: Ideally this would be accepted in all modes. In C++98, we trigger a
+ // linkage calculation to drive the "internal linkage type as template
+ // argument" warning.
+ typedef struct {
+ void f() { struct Inner {}; Use<Inner> ui; }
+ } F;
+#if __cplusplus < 201103L
+ // expected-error@-2 {{unsupported: typedef changes linkage of anonymous type, but linkage was already computed}}
+ // expected-note@-5 {{use a tag name here}}
+#endif
+}
diff --git a/test/SemaCXX/local-classes.cpp b/test/SemaCXX/local-classes.cpp
index f4ca79159d..eb0b7e43eb 100644
--- a/test/SemaCXX/local-classes.cpp
+++ b/test/SemaCXX/local-classes.cpp
@@ -40,3 +40,15 @@ namespace Templates {
};
}
}
+
+namespace PR25627_dont_odr_use_local_consts {
+ template<int> struct X { X(); X(int); };
+
+ void foo() {
+ const int N = 10;
+
+ struct Local {
+ void f(X<N> = X<N>()) {} // OK
+ };
+ }
+}
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index c296baa5bc..82750878e5 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall %s
struct Bitfield {
- int n : 3 = 7; // expected-error {{bit-field member cannot have an in-class initializer}}
+ int n : 3 = 7; // expected-warning {{C++2a extension}} expected-warning {{changes value from 7 to -1}}
};
int a;
diff --git a/test/SemaCXX/microsoft-varargs.cpp b/test/SemaCXX/microsoft-varargs.cpp
index 35f31a97c4..5b0f90eb5c 100644
--- a/test/SemaCXX/microsoft-varargs.cpp
+++ b/test/SemaCXX/microsoft-varargs.cpp
@@ -20,3 +20,8 @@ int builtin(int i, ...) {
return __builtin_va_arg(ap, int);
}
+void test___va_start_ignore_const(const char *format, ...) {
+ va_list args;
+ ((void)(__va_start(&args, (&const_cast<char &>(reinterpret_cast<const volatile char &>(format))), ((sizeof(format) + 4 - 1) & ~(4 - 1)), (&const_cast<char &>(reinterpret_cast<const volatile char &>(format))))));
+}
+
diff --git a/test/SemaCXX/missing-members.cpp b/test/SemaCXX/missing-members.cpp
index 96bed074db..61dddcbe50 100644
--- a/test/SemaCXX/missing-members.cpp
+++ b/test/SemaCXX/missing-members.cpp
@@ -37,3 +37,17 @@ struct S : A::B::C {
using A::B::C::f; // expected-error {{no member named 'f' in 'A::B::C'}}
};
+
+struct S1 {};
+
+struct S2 : S1 {};
+
+struct S3 : S2 {
+ void run();
+};
+
+struct S4: S3 {};
+
+void test(S4 *ptr) {
+ ptr->S1::run(); // expected-error {{no member named 'run' in 'S1'}}
+}
diff --git a/test/SemaCXX/modules-ts.cppm b/test/SemaCXX/modules-ts.cppm
index 71c09d3bfe..f64a4c0ab4 100644
--- a/test/SemaCXX/modules-ts.cppm
+++ b/test/SemaCXX/modules-ts.cppm
@@ -1,24 +1,31 @@
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=0
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DTEST=1
-// RUN: not %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -DTEST=2 2>&1 | FileCheck %s --check-prefix=CHECK-2
-// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -Dfoo=bar -DTEST=3
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.0.pcm -verify -DTEST=0
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.1.pcm -verify -DTEST=1
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.0.pcm -o %t.2.pcm -verify -DTEST=2
+// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.0.pcm -o %t.3.pcm -verify -Dfoo=bar -DTEST=3
#if TEST == 0
// expected-no-diagnostics
#endif
-module foo;
-#if TEST == 1
-// expected-error@-2 {{expected module declaration at start of module interface}}
-#elif TEST == 2
-// CHECK-2: error: redefinition of module 'foo'
+export module foo;
+#if TEST == 2
+// expected-error@-2 {{redefinition of module 'foo'}}
+// expected-note@modules-ts.cppm:* {{loaded from}}
#endif
-static int m; // ok, internal linkage, so no redefinition error
+static int m;
+#if TEST == 2
+// expected-error@-2 {{redefinition of '}}
+// expected-note@-3 {{unguarded header; consider using #ifdef guards or #pragma once}}
+// FIXME: We should drop the "header from" in this diagnostic.
+// expected-note-re@modules-ts.cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site in header from module 'foo'}}
+#endif
int n;
-#if TEST == 3
+#if TEST == 2
// expected-error@-2 {{redefinition of '}}
-// expected-note@-3 {{previous}}
+// expected-note@-3 {{unguarded header; consider using #ifdef guards or #pragma once}}
+// FIXME: We should drop the "header from" in this diagnostic.
+// expected-note-re@modules-ts.cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site in header from module 'foo'}}
#endif
#if TEST == 0
@@ -53,7 +60,7 @@ int use_b = b;
int use_n = n; // FIXME: this should not be visible, because it is not exported
extern int n;
-static_assert(&n == p); // FIXME: these are not the same entity
+static_assert(&n != p);
#endif
diff --git a/test/SemaCXX/ms-interface.cpp b/test/SemaCXX/ms-interface.cpp
index 4a1c13ddcb..66ce376e2a 100644
--- a/test/SemaCXX/ms-interface.cpp
+++ b/test/SemaCXX/ms-interface.cpp
@@ -77,3 +77,32 @@ class C1 : I6<C> {
class C2 : I6<I> {
};
+
+
+// MSVC makes a special case in that an interface is allowed to have a data
+// member if it is a property.
+__interface HasProp {
+ __declspec(property(get = Get, put = Put)) int data;
+ int Get(void);
+ void Put(int);
+};
+
+struct __declspec(uuid("00000000-0000-0000-C000-000000000046"))
+ IUnknown {
+ void foo();
+ __declspec(property(get = Get, put = Put), deprecated) int data;
+ int Get(void);
+ void Put(int);
+};
+
+struct IFaceStruct : IUnknown {
+ __declspec(property(get = Get2, put = Put2), deprecated) int data2;
+ int Get2(void);
+ void Put2(int);
+};
+
+__interface IFaceInheritsStruct : IFaceStruct {};
+static_assert(!__is_interface_class(HasProp), "oops");
+static_assert(!__is_interface_class(IUnknown), "oops");
+static_assert(!__is_interface_class(IFaceStruct), "oops");
+static_assert(!__is_interface_class(IFaceInheritsStruct), "oops");
diff --git a/test/SemaCXX/ms-iunknown-inline-def.cpp b/test/SemaCXX/ms-iunknown-inline-def.cpp
new file mode 100644
index 0000000000..70f1107c2e
--- /dev/null
+++ b/test/SemaCXX/ms-iunknown-inline-def.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+
+struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
+ void foo() {}
+};
+
+// expected-error@+1{{interface type cannot inherit from}}
+__interface HasError : public IUnknown {};
diff --git a/test/SemaCXX/ms-iunknown-outofline-def.cpp b/test/SemaCXX/ms-iunknown-outofline-def.cpp
new file mode 100644
index 0000000000..b6e74d0eb6
--- /dev/null
+++ b/test/SemaCXX/ms-iunknown-outofline-def.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+
+struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
+ void foo();
+};
+
+__interface NoError : public IUnknown {};
+void IUnknown::foo() {}
+// expected-error@+1{{interface type cannot inherit from}}
+__interface HasError : public IUnknown {};
diff --git a/test/SemaCXX/ms-iunknown-template-function.cpp b/test/SemaCXX/ms-iunknown-template-function.cpp
new file mode 100644
index 0000000000..8f741a18ea
--- /dev/null
+++ b/test/SemaCXX/ms-iunknown-template-function.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+// expected-no-diagnostics
+typedef long HRESULT;
+typedef unsigned long ULONG;
+typedef struct _GUID {
+ unsigned long Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[8];
+} GUID;
+typedef GUID IID;
+
+// remove stdcall, since the warnings have nothing to do with
+// what is being tested.
+#define __stdcall
+
+extern "C" {
+extern "C++" {
+struct __declspec(uuid("00000000-0000-0000-C000-000000000046"))
+ IUnknown {
+public:
+ virtual HRESULT __stdcall QueryInterface(
+ const IID &riid,
+ void **ppvObject) = 0;
+
+ virtual ULONG __stdcall AddRef(void) = 0;
+
+ virtual ULONG __stdcall Release(void) = 0;
+
+ template <class Q>
+ HRESULT __stdcall QueryInterface(Q **pp) {
+ return QueryInterface(__uuidof(Q), (void **)pp);
+ }
+};
+}
+}
+
+__interface ISfFileIOPropertyPage : public IUnknown{};
+
diff --git a/test/SemaCXX/ms-iunknown.cpp b/test/SemaCXX/ms-iunknown.cpp
new file mode 100644
index 0000000000..df761d56a8
--- /dev/null
+++ b/test/SemaCXX/ms-iunknown.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+
+extern "C++" struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
+ void foo();
+ // Definitions aren't allowed, unless they are a template.
+ template<typename T>
+ void bar(T t){}
+};
+
+struct IPropertyPageBase : public IUnknown {};
+struct IPropertyPage : public IPropertyPageBase {};
+__interface ISfFileIOPropertyPage : public IPropertyPage {};
+
+
+namespace NS {
+ struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {};
+ // expected-error@+1 {{interface type cannot inherit from}}
+ __interface IPropertyPageBase : public IUnknown {};
+}
+
+namespace NS2 {
+extern "C++" struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {};
+// expected-error@+1 {{interface type cannot inherit from}}
+__interface IPropertyPageBase : public IUnknown{};
+}
+
+// expected-error@+1 {{interface type cannot inherit from}}
+__interface IPropertyPageBase2 : public NS::IUnknown {};
+
+__interface temp_iface {};
+struct bad_base : temp_iface {};
+// expected-error@+1 {{interface type cannot inherit from}}
+__interface bad_inherit : public bad_base{};
+
+struct mult_inher_base : temp_iface, IUnknown {};
+// expected-error@+1 {{interface type cannot inherit from}}
+__interface bad_inherit2 : public mult_inher_base{};
+
+struct PageBase : public IUnknown {};
+struct Page3 : public PageBase {};
+struct Page4 : public PageBase {};
+__interface PropertyPage : public Page4 {};
+
+struct Page5 : public Page3, Page4{};
+// expected-error@+1 {{interface type cannot inherit from}}
+__interface PropertyPage2 : public Page5 {};
+
+__interface IF1 {};
+__interface PP : IUnknown, IF1{};
+__interface PP2 : PP, Page3, Page4{};
diff --git a/test/SemaCXX/ms-uuid.cpp b/test/SemaCXX/ms-uuid.cpp
index 461e3c12ff..e29dda878e 100644
--- a/test/SemaCXX/ms-uuid.cpp
+++ b/test/SemaCXX/ms-uuid.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -Wno-deprecated-declarations
typedef struct _GUID {
unsigned long Data1;
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 6ae45ff633..725ac64ced 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -169,6 +169,13 @@ void N::f() { } // okay
struct Y; // expected-note{{forward declaration of 'Y'}}
Y::foo y; // expected-error{{incomplete type 'Y' named in nested name specifier}}
+namespace PR25156 {
+struct Y; // expected-note{{forward declaration of 'PR25156::Y'}}
+void foo() {
+ Y::~Y(); // expected-error{{incomplete type 'PR25156::Y' named in nested name specifier}}
+}
+}
+
X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}}
struct foo_S {
diff --git a/test/SemaCXX/nothrow-as-noexcept-ctor.cpp b/test/SemaCXX/nothrow-as-noexcept-ctor.cpp
new file mode 100644
index 0000000000..7cca414d7a
--- /dev/null
+++ b/test/SemaCXX/nothrow-as-noexcept-ctor.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s -fcxx-exceptions -fsyntax-only -Wexceptions -verify -std=c++14
+
+// expected-no-diagnostics
+struct Base {
+ __attribute__((nothrow)) Base() {}
+};
+
+struct Derived : Base {
+ Derived() noexcept = default;
+};
+
+struct Base2 {
+ Base2() noexcept {}
+};
+
+struct Derived2 : Base2 {
+ __attribute__((nothrow)) Derived2() = default;
+};
+
+struct Base3 {
+ __attribute__((nothrow)) Base3() {}
+};
+
+struct Derived3 : Base3 {
+ __attribute__((nothrow)) Derived3() = default;
+};
diff --git a/test/SemaCXX/null-cast.cpp b/test/SemaCXX/null-cast.cpp
new file mode 100644
index 0000000000..c80ab8fced
--- /dev/null
+++ b/test/SemaCXX/null-cast.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {};
+struct B : virtual A {};
+
+void foo() {
+ (void)static_cast<A&>(*(B *)0); // expected-warning {{binding dereferenced null pointer to reference has undefined behavior}}
+}
diff --git a/test/SemaCXX/nullability.cpp b/test/SemaCXX/nullability.cpp
index 160741b140..99375a9fdd 100644
--- a/test/SemaCXX/nullability.cpp
+++ b/test/SemaCXX/nullability.cpp
@@ -1,10 +1,12 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify -Wnullable-to-nonnull-conversion
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wno-nullability-declspec %s -verify -Wnullable-to-nonnull-conversion -I%S/Inputs
#if __has_feature(nullability)
#else
# error nullability feature should be defined
#endif
+#include "nullability-completeness.h"
+
typedef decltype(nullptr) nullptr_t;
class X {
@@ -130,3 +132,7 @@ void arraysInLambdas() {
withTypedef(nullptr); // expected-warning {{null passed to a callee that requires a non-null argument}}
auto withTypedefBad = [](INTS _Nonnull[2]) {}; // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int [4]')}}
}
+
+void testNullabilityCompletenessWithTemplate() {
+ Template<int*> tip;
+}
diff --git a/test/SemaCXX/nullptr-arithmetic.cpp b/test/SemaCXX/nullptr-arithmetic.cpp
new file mode 100644
index 0000000000..9963c8858e
--- /dev/null
+++ b/test/SemaCXX/nullptr-arithmetic.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wextra -std=c++11
+// RUN: %clang_cc1 %s -fsyntax-only -triple i686-unknown-unknown -verify -pedantic -Wextra -std=c++11
+// RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify -pedantic -Wextra -std=c++11
+
+#include <stdint.h>
+
+void f(intptr_t offset) {
+ // A zero offset from a nullptr is OK.
+ char *f = (char*)nullptr + 0;
+ int *g = (int*)0 + 0;
+ f = (char*)nullptr - 0;
+ g = (int*)nullptr - 0;
+ // adding other values is undefined.
+ f = (char*)nullptr + offset; // expected-warning {{arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension}}
+ // Cases that don't match the GNU inttoptr idiom get a different warning.
+ f = (char*)0 - offset; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior if the offset is nonzero}}
+ g = (int*)0 + offset; // expected-warning {{performing pointer arithmetic on a null pointer has undefined behavior if the offset is nonzero}}
+}
+
+// Value-dependent pointer arithmetic should not produce a nullptr warning.
+template<char *P>
+char* g(intptr_t offset) {
+ return P + offset;
+}
+
+// Value-dependent offsets should not produce a nullptr warning.
+template<intptr_t N>
+char *h() {
+ return (char*)nullptr + N;
+}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 369e9eb802..dff9350cc9 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -531,3 +531,57 @@ namespace NoADLForMemberOnlyOperators {
b3 / 0; // expected-note {{in instantiation of}} expected-error {{invalid operands to}}
}
}
+
+
+namespace PR27027 {
+ template <class T> void operator+(T, T) = delete; // expected-note 4 {{candidate}}
+ template <class T> void operator+(T) = delete; // expected-note 4 {{candidate}}
+
+ struct A {} a_global;
+ void f() {
+ A a;
+ +a; // expected-error {{overload resolution selected deleted operator '+'}}
+ a + a; // expected-error {{overload resolution selected deleted operator '+'}}
+ bool operator+(A);
+ extern bool operator+(A, A);
+ +a; // OK
+ a + a;
+ }
+ bool test_global_1 = +a_global; // expected-error {{overload resolution selected deleted operator '+'}}
+ bool test_global_2 = a_global + a_global; // expected-error {{overload resolution selected deleted operator '+'}}
+}
+
+namespace LateADLInNonDependentExpressions {
+ struct A {};
+ struct B : A {};
+ int &operator+(A, A);
+ int &operator!(A);
+ int &operator+=(A, A);
+ int &operator<<(A, A);
+ int &operator++(A);
+ int &operator++(A, int);
+ int &operator->*(A, A);
+
+ template<typename T> void f() {
+ // An instantiation-dependent value of type B.
+ // These are all non-dependent operator calls of type int&.
+#define idB ((void()), B())
+ int &a = idB + idB,
+ &b = !idB,
+ &c = idB += idB,
+ &d = idB << idB,
+ &e = ++idB,
+ &f = idB++,
+ &g = idB ->* idB;
+ }
+
+ // These should not be found by ADL in the template instantiation.
+ float &operator+(B, B);
+ float &operator!(B);
+ float &operator+=(B, B);
+ float &operator<<(B, B);
+ float &operator++(B);
+ float &operator++(B, int);
+ float &operator->*(B, B);
+ template void f<int>();
+}
diff --git a/test/SemaCXX/ptrtomember.cpp b/test/SemaCXX/ptrtomember.cpp
index aee535e559..d4a4507d02 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/short-wchar-sign.cpp b/test/SemaCXX/short-wchar-sign.cpp
index 7ce21c523c..a43e68a086 100644
--- a/test/SemaCXX/short-wchar-sign.cpp
+++ b/test/SemaCXX/short-wchar-sign.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -pedantic -verify %s
-// RUN: %clang_cc1 -fshort-wchar -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fwchar-type=short -fno-signed-wchar -fsyntax-only -pedantic -verify %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -pedantic -verify %s
// expected-no-diagnostics
diff --git a/test/SemaCXX/static-assert.cpp b/test/SemaCXX/static-assert.cpp
index 7de4d07b50..846303807a 100644
--- a/test/SemaCXX/static-assert.cpp
+++ b/test/SemaCXX/static-assert.cpp
@@ -49,5 +49,22 @@ struct X { ~X(); };
StaticAssertProtected<int> sap1;
StaticAssertProtected<X> sap2; // expected-note {{instantiation}}
-static_assert(true); // expected-warning {{C++1z extension}}
+static_assert(true); // expected-warning {{C++17 extension}}
static_assert(false); // expected-error-re {{failed{{$}}}} expected-warning {{extension}}
+
+
+// Diagnostics for static_assert with multiple conditions
+template<typename T> struct first_trait {
+ static const bool value = false;
+};
+
+template<>
+struct first_trait<X> {
+ static const bool value = true;
+};
+
+template<typename T> struct second_trait {
+ static const bool value = false;
+};
+
+static_assert(first_trait<X>::value && second_trait<X>::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait<X>::value' "message"}}
diff --git a/test/SemaCXX/suppress.cpp b/test/SemaCXX/suppress.cpp
new file mode 100644
index 0000000000..d88ae0bbca
--- /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-default-param-through-using.cpp b/test/SemaCXX/template-default-param-through-using.cpp
new file mode 100644
index 0000000000..4bf26d5811
--- /dev/null
+++ b/test/SemaCXX/template-default-param-through-using.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+namespace llvm {
+ template<typename T > struct StringSet;
+ template<int I > struct Int;
+ template <typename Inner, template <typename> class Outer>
+ struct TemplTempl;
+}
+
+namespace lld {
+ using llvm::StringSet;
+ using llvm::Int;
+ using llvm::TemplTempl;
+};
+
+namespace llvm {
+ template<typename T > struct StringSet;
+}
+
+template<typename T> struct Temp{};
+
+namespace llvm {
+ template<typename T = int> struct StringSet{};
+ template<int I = 5> struct Int{};
+ template <typename Inner, template <typename> class Outer = Temp>
+ struct TemplTempl{};
+};
+
+namespace lld {
+ StringSet<> s;
+ Int<> i;
+ TemplTempl<int> tt;
+}
diff --git a/test/SemaCXX/template-multiple-attr-propagation.cpp b/test/SemaCXX/template-multiple-attr-propagation.cpp
new file mode 100644
index 0000000000..8e7f4570ba
--- /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 ae7bc332fc..ae7bc332fc 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 7ae83638ad..98e960727b 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 c53b02774a..d6a3574f93 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))]; }
@@ -210,6 +252,11 @@ void is_pod()
{ int arr[F(__is_pod(void))]; }
{ int arr[F(__is_pod(cvoid))]; }
// { int arr[F(__is_pod(NonPODUnion))]; }
+
+ { int arr[T(__is_pod(ACompleteType))]; }
+ { int arr[F(__is_pod(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_pod(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_pod(AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
}
typedef Empty EmptyAr[10];
@@ -245,6 +292,11 @@ void is_empty()
{ int arr[F(__is_empty(IntArNB))]; }
{ int arr[F(__is_empty(HasAnonymousUnion))]; }
// { int arr[F(__is_empty(DerivesVirt))]; }
+
+ { int arr[T(__is_empty(ACompleteType))]; }
+ { int arr[F(__is_empty(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_empty(AnIncompleteType[]))]; }
+ { int arr[F(__is_empty(AnIncompleteType[1]))]; }
}
typedef Derives ClassType;
@@ -452,6 +504,85 @@ 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(AnIncompleteType[]); // expected-error {{incomplete type}}
+ __is_aggregate(AnIncompleteType[1]); // 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 +612,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))];
@@ -1104,6 +1232,13 @@ void is_trivial2()
int t32[F(__is_trivial(SuperNonTrivialStruct))];
int t33[F(__is_trivial(NonTCStruct))];
int t34[F(__is_trivial(ExtDefaulted))];
+
+ int t40[T(__is_trivial(ACompleteType))];
+ int t41[F(__is_trivial(AnIncompleteType))]; // expected-error {{incomplete type}}
+ int t42[F(__is_trivial(AnIncompleteType[]))]; // expected-error {{incomplete type}}
+ int t43[F(__is_trivial(AnIncompleteType[1]))]; // expected-error {{incomplete type}}
+ int t44[F(__is_trivial(void))];
+ int t45[F(__is_trivial(const volatile void))];
}
void is_trivially_copyable2()
@@ -1140,7 +1275,14 @@ void is_trivially_copyable2()
int t33[F(__is_trivially_copyable(ExtDefaulted))];
int t34[T(__is_trivially_copyable(const int))];
- int t35[F(__is_trivially_copyable(volatile int))];
+ int t35[T(__is_trivially_copyable(volatile int))];
+
+ int t40[T(__is_trivially_copyable(ACompleteType))];
+ int t41[F(__is_trivially_copyable(AnIncompleteType))]; // expected-error {{incomplete type}}
+ int t42[F(__is_trivially_copyable(AnIncompleteType[]))]; // expected-error {{incomplete type}}
+ int t43[F(__is_trivially_copyable(AnIncompleteType[1]))]; // expected-error {{incomplete type}}
+ int t44[F(__is_trivially_copyable(void))];
+ int t45[F(__is_trivially_copyable(const volatile void))];
}
struct CStruct {
@@ -1204,6 +1346,13 @@ void is_standard_layout()
int t15[F(__is_standard_layout(CppStructNonStandardByBaseAr))];
int t16[F(__is_standard_layout(CppStructNonStandardBySameBase))];
int t17[F(__is_standard_layout(CppStructNonStandardBy2ndVirtBase))];
+
+ int t40[T(__is_standard_layout(ACompleteType))];
+ int t41[F(__is_standard_layout(AnIncompleteType))]; // expected-error {{incomplete type}}
+ int t42[F(__is_standard_layout(AnIncompleteType[]))]; // expected-error {{incomplete type}}
+ int t43[F(__is_standard_layout(AnIncompleteType[1]))]; // expected-error {{incomplete type}}
+ int t44[F(__is_standard_layout(void))];
+ int t45[F(__is_standard_layout(const volatile void))];
}
void is_signed()
@@ -1298,7 +1447,9 @@ void has_trivial_default_constructor() {
{ int arr[T(__has_trivial_constructor(const Int))]; }
{ int arr[T(__has_trivial_constructor(AllDefaulted))]; }
{ int arr[T(__has_trivial_constructor(AllDeleted))]; }
+ { int arr[T(__has_trivial_constructor(ACompleteType[]))]; }
+ { int arr[F(__has_trivial_constructor(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_trivial_constructor(HasCons))]; }
{ int arr[F(__has_trivial_constructor(HasRef))]; }
{ int arr[F(__has_trivial_constructor(HasCopy))]; }
@@ -1329,7 +1480,9 @@ void has_trivial_move_constructor() {
{ int arr[T(__has_trivial_move_constructor(HasCons))]; }
{ int arr[T(__has_trivial_move_constructor(HasStaticMemberMoveCtor))]; }
{ int arr[T(__has_trivial_move_constructor(AllDeleted))]; }
-
+ { int arr[T(__has_trivial_move_constructor(ACompleteType[]))]; }
+
+ { int arr[F(__has_trivial_move_constructor(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_trivial_move_constructor(HasVirt))]; }
{ int arr[F(__has_trivial_move_constructor(DerivesVirt))]; }
{ int arr[F(__has_trivial_move_constructor(HasMoveCtor))]; }
@@ -1359,7 +1512,9 @@ void has_trivial_copy_constructor() {
{ int arr[T(__has_trivial_copy(AllDeleted))]; }
{ int arr[T(__has_trivial_copy(DerivesAr))]; }
{ int arr[T(__has_trivial_copy(DerivesHasRef))]; }
+ { int arr[T(__has_trivial_copy(ACompleteType[]))]; }
+ { int arr[F(__has_trivial_copy(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_trivial_copy(HasCopy))]; }
{ int arr[F(__has_trivial_copy(HasTemplateCons))]; }
{ int arr[F(__has_trivial_copy(VirtAr))]; }
@@ -1387,7 +1542,9 @@ void has_trivial_copy_assignment() {
{ int arr[T(__has_trivial_assign(AllDeleted))]; }
{ int arr[T(__has_trivial_assign(DerivesAr))]; }
{ int arr[T(__has_trivial_assign(DerivesHasRef))]; }
+ { int arr[T(__has_trivial_assign(ACompleteType[]))]; }
+ { int arr[F(__has_trivial_assign(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_trivial_assign(IntRef))]; }
{ int arr[F(__has_trivial_assign(HasCopyAssign))]; }
{ int arr[F(__has_trivial_assign(const Int))]; }
@@ -1423,8 +1580,10 @@ void has_trivial_destructor() {
{ int arr[T(__has_trivial_destructor(AllDefaulted))]; }
{ int arr[T(__has_trivial_destructor(AllDeleted))]; }
{ int arr[T(__has_trivial_destructor(DerivesHasRef))]; }
+ { int arr[T(__has_trivial_destructor(ACompleteType[]))]; }
{ int arr[F(__has_trivial_destructor(HasDest))]; }
+ { int arr[F(__has_trivial_destructor(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_trivial_destructor(void))]; }
{ int arr[F(__has_trivial_destructor(cvoid))]; }
{ int arr[F(__has_trivial_destructor(AllPrivate))]; }
@@ -1476,7 +1635,9 @@ void has_nothrow_assign() {
{ int arr[T(__has_nothrow_assign(AllPrivate))]; }
{ int arr[T(__has_nothrow_assign(UsingAssign))]; }
{ int arr[T(__has_nothrow_assign(DerivesAr))]; }
+ { int arr[T(__has_nothrow_assign(ACompleteType[]))]; }
+ { int arr[F(__has_nothrow_assign(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_nothrow_assign(IntRef))]; }
{ int arr[F(__has_nothrow_assign(HasCopyAssign))]; }
{ int arr[F(__has_nothrow_assign(HasMultipleCopyAssign))]; }
@@ -1501,8 +1662,9 @@ void has_nothrow_move_assign() {
{ int arr[T(__has_nothrow_move_assign(HasMemberNoThrowMoveAssign))]; }
{ int arr[T(__has_nothrow_move_assign(HasMemberNoExceptNoThrowMoveAssign))]; }
{ int arr[T(__has_nothrow_move_assign(AllDeleted))]; }
+ { int arr[T(__has_nothrow_move_assign(ACompleteType[]))]; }
-
+ { int arr[F(__has_nothrow_move_assign(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_nothrow_move_assign(HasThrowMoveAssign))]; }
{ int arr[F(__has_nothrow_move_assign(HasNoExceptFalseMoveAssign))]; }
{ int arr[F(__has_nothrow_move_assign(HasMemberThrowMoveAssign))]; }
@@ -1534,7 +1696,9 @@ void has_trivial_move_assign() {
{ int arr[T(__has_trivial_move_assign(Int))]; }
{ int arr[T(__has_trivial_move_assign(HasStaticMemberMoveAssign))]; }
{ int arr[T(__has_trivial_move_assign(AllDeleted))]; }
+ { int arr[T(__has_trivial_move_assign(ACompleteType[]))]; }
+ { int arr[F(__has_trivial_move_assign(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_trivial_move_assign(HasVirt))]; }
{ int arr[F(__has_trivial_move_assign(DerivesVirt))]; }
{ int arr[F(__has_trivial_move_assign(HasMoveAssign))]; }
@@ -1568,7 +1732,9 @@ void has_nothrow_copy() {
{ int arr[T(__has_nothrow_copy(HasTemplateCons))]; }
{ int arr[T(__has_nothrow_copy(AllPrivate))]; }
{ int arr[T(__has_nothrow_copy(DerivesAr))]; }
+ { int arr[T(__has_nothrow_copy(ACompleteType[]))]; }
+ { int arr[F(__has_nothrow_copy(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_nothrow_copy(HasCopy))]; }
{ int arr[F(__has_nothrow_copy(HasMultipleCopy))]; }
{ int arr[F(__has_nothrow_copy(VirtAr))]; }
@@ -1594,7 +1760,9 @@ void has_nothrow_constructor() {
{ int arr[T(__has_nothrow_constructor(HasVirtDest))]; }
// { int arr[T(__has_nothrow_constructor(VirtAr))]; } // not implemented
{ int arr[T(__has_nothrow_constructor(AllPrivate))]; }
+ { int arr[T(__has_nothrow_constructor(ACompleteType[]))]; }
+ { int arr[F(__has_nothrow_constructor(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[F(__has_nothrow_constructor(HasCons))]; }
{ int arr[F(__has_nothrow_constructor(HasRef))]; }
{ int arr[F(__has_nothrow_constructor(HasCopy))]; }
@@ -1630,7 +1798,9 @@ void has_virtual_destructor() {
{ int arr[F(__has_virtual_destructor(HasMoveAssign))]; }
{ int arr[F(__has_virtual_destructor(IntRef))]; }
{ int arr[F(__has_virtual_destructor(VirtAr))]; }
+ { int arr[F(__has_virtual_destructor(ACompleteType[]))]; }
+ { int arr[F(__has_virtual_destructor(AnIncompleteType[]))]; } // expected-error {{incomplete type}}
{ int arr[T(__has_virtual_destructor(HasVirtDest))]; }
{ int arr[T(__has_virtual_destructor(DerivedVirtDest))]; }
{ int arr[F(__has_virtual_destructor(VirtDestAr))]; }
@@ -2017,6 +2187,13 @@ void trivial_checks()
TrivialMoveButNotCopy)))]; }
{ int arr[T((__is_assignable(TrivialMoveButNotCopy &,
TrivialMoveButNotCopy &&)))]; }
+
+ { int arr[T(__is_assignable(ACompleteType, ACompleteType))]; }
+ { int arr[F(__is_assignable(AnIncompleteType, AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_assignable(AnIncompleteType[], AnIncompleteType[]))]; }
+ { int arr[F(__is_assignable(AnIncompleteType[1], AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_assignable(void, void))]; }
+ { int arr[F(__is_assignable(const volatile void, const volatile void))]; }
}
void constructible_checks() {
@@ -2048,6 +2225,19 @@ void constructible_checks() {
// PR25513
{ int arr[F(__is_constructible(int(int)))]; }
+
+ { int arr[T(__is_constructible(ACompleteType))]; }
+ { int arr[T(__is_nothrow_constructible(ACompleteType))]; }
+ { int arr[F(__is_constructible(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_nothrow_constructible(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_constructible(AnIncompleteType[]))]; }
+ { int arr[F(__is_nothrow_constructible(AnIncompleteType[]))]; }
+ { int arr[F(__is_constructible(AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_nothrow_constructible(AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_constructible(void))]; }
+ { int arr[F(__is_nothrow_constructible(void))]; }
+ { int arr[F(__is_constructible(const volatile void))]; }
+ { int arr[F(__is_nothrow_constructible(const volatile void))]; }
}
// Instantiation of __is_trivially_constructible
@@ -2076,6 +2266,13 @@ void is_trivially_constructible_test() {
{ int arr[F((is_trivially_constructible<NonTrivialDefault>::value))]; }
{ int arr[F((is_trivially_constructible<ThreeArgCtor, int*, char*, int&>::value))]; }
{ int arr[F((is_trivially_constructible<Abstract>::value))]; } // PR19178
+
+ { int arr[T(__is_trivially_constructible(ACompleteType))]; }
+ { int arr[F(__is_trivially_constructible(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_trivially_constructible(AnIncompleteType[]))]; }
+ { int arr[F(__is_trivially_constructible(AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_trivially_constructible(void))]; }
+ { int arr[F(__is_trivially_constructible(const volatile void))]; }
}
void array_rank() {
@@ -2102,6 +2299,13 @@ void is_destructible_test() {
{ int arr[F(__is_destructible(AllDeleted))]; }
{ int arr[T(__is_destructible(ThrowingDtor))]; }
{ int arr[T(__is_destructible(NoThrowDtor))]; }
+
+ { int arr[T(__is_destructible(ACompleteType))]; }
+ { int arr[F(__is_destructible(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_destructible(AnIncompleteType[]))]; }
+ { int arr[F(__is_destructible(AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_destructible(void))]; }
+ { int arr[F(__is_destructible(const volatile void))]; }
}
void is_nothrow_destructible_test() {
@@ -2118,4 +2322,266 @@ void is_nothrow_destructible_test() {
{ int arr[F(__is_nothrow_destructible(ThrowingDtor))]; }
{ int arr[T(__is_nothrow_destructible(NoExceptDtor))]; }
{ int arr[T(__is_nothrow_destructible(NoThrowDtor))]; }
+
+ { int arr[T(__is_nothrow_destructible(ACompleteType))]; }
+ { int arr[F(__is_nothrow_destructible(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_nothrow_destructible(AnIncompleteType[]))]; }
+ { int arr[F(__is_nothrow_destructible(AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_nothrow_destructible(void))]; }
+ { int arr[F(__is_nothrow_destructible(const volatile void))]; }
}
+
+void is_trivially_destructible_test() {
+ { int arr[T(__is_trivially_destructible(int))]; }
+ { int arr[T(__is_trivially_destructible(int[2]))]; }
+ { int arr[F(__is_trivially_destructible(int[]))]; }
+ { int arr[F(__is_trivially_destructible(void))]; }
+ { int arr[T(__is_trivially_destructible(int &))]; }
+ { int arr[F(__is_trivially_destructible(HasDest))]; }
+ { int arr[F(__is_trivially_destructible(AllPrivate))]; }
+ { int arr[F(__is_trivially_destructible(SuperNonTrivialStruct))]; }
+ { int arr[T(__is_trivially_destructible(AllDefaulted))]; }
+ { int arr[F(__is_trivially_destructible(AllDeleted))]; }
+ { int arr[F(__is_trivially_destructible(ThrowingDtor))]; }
+ { int arr[F(__is_trivially_destructible(NoThrowDtor))]; }
+
+ { int arr[T(__is_trivially_destructible(ACompleteType))]; }
+ { int arr[F(__is_trivially_destructible(AnIncompleteType))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_trivially_destructible(AnIncompleteType[]))]; }
+ { int arr[F(__is_trivially_destructible(AnIncompleteType[1]))]; } // expected-error {{incomplete type}}
+ { int arr[F(__is_trivially_destructible(void))]; }
+ { int arr[F(__is_trivially_destructible(const volatile void))]; }
+}
+
+// Instantiation of __has_unique_object_representations
+template <typename T>
+struct has_unique_object_representations {
+ static const bool value = __has_unique_object_representations(T);
+};
+
+static_assert(!has_unique_object_representations<void>::value, "void is never unique");
+static_assert(!has_unique_object_representations<const void>::value, "void is never unique");
+static_assert(!has_unique_object_representations<volatile void>::value, "void is never unique");
+static_assert(!has_unique_object_representations<const volatile void>::value, "void is never unique");
+
+static_assert(has_unique_object_representations<int>::value, "integrals are");
+static_assert(has_unique_object_representations<const int>::value, "integrals are");
+static_assert(has_unique_object_representations<volatile int>::value, "integrals are");
+static_assert(has_unique_object_representations<const volatile int>::value, "integrals are");
+
+static_assert(has_unique_object_representations<void *>::value, "as are pointers");
+static_assert(has_unique_object_representations<const void *>::value, "as are pointers");
+static_assert(has_unique_object_representations<volatile void *>::value, "are pointers");
+static_assert(has_unique_object_representations<const volatile void *>::value, "as are pointers");
+
+static_assert(has_unique_object_representations<int *>::value, "as are pointers");
+static_assert(has_unique_object_representations<const int *>::value, "as are pointers");
+static_assert(has_unique_object_representations<volatile int *>::value, "as are pointers");
+static_assert(has_unique_object_representations<const volatile int *>::value, "as are pointers");
+
+class C {};
+using FP = int (*)(int);
+using PMF = int (C::*)(int);
+using PMD = int C::*;
+
+static_assert(has_unique_object_representations<FP>::value, "even function pointers");
+static_assert(has_unique_object_representations<const FP>::value, "even function pointers");
+static_assert(has_unique_object_representations<volatile FP>::value, "even function pointers");
+static_assert(has_unique_object_representations<const volatile FP>::value, "even function pointers");
+
+static_assert(has_unique_object_representations<PMF>::value, "and pointer to members");
+static_assert(has_unique_object_representations<const PMF>::value, "and pointer to members");
+static_assert(has_unique_object_representations<volatile PMF>::value, "and pointer to members");
+static_assert(has_unique_object_representations<const volatile PMF>::value, "and pointer to members");
+
+static_assert(has_unique_object_representations<PMD>::value, "and pointer to members");
+static_assert(has_unique_object_representations<const PMD>::value, "and pointer to members");
+static_assert(has_unique_object_representations<volatile PMD>::value, "and pointer to members");
+static_assert(has_unique_object_representations<const volatile PMD>::value, "and pointer to members");
+
+static_assert(has_unique_object_representations<bool>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<char>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<signed char>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<unsigned char>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<short>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<unsigned short>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<int>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<unsigned int>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<long>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<unsigned long>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<long long>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<unsigned long long>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<wchar_t>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<char16_t>::value, "yes, all integral types");
+static_assert(has_unique_object_representations<char32_t>::value, "yes, all integral types");
+
+static_assert(!has_unique_object_representations<void>::value, "but not void!");
+static_assert(!has_unique_object_representations<decltype(nullptr)>::value, "or nullptr_t");
+static_assert(!has_unique_object_representations<float>::value, "definitely not Floating Point");
+static_assert(!has_unique_object_representations<double>::value, "definitely not Floating Point");
+static_assert(!has_unique_object_representations<long double>::value, "definitely not Floating Point");
+
+struct NoPadding {
+ int a;
+ int b;
+};
+
+static_assert(has_unique_object_representations<NoPadding>::value, "types without padding are");
+
+struct InheritsFromNoPadding : NoPadding {
+ int c;
+ int d;
+};
+
+static_assert(has_unique_object_representations<InheritsFromNoPadding>::value, "types without padding are");
+
+struct VirtuallyInheritsFromNoPadding : virtual NoPadding {
+ int c;
+ int d;
+};
+
+static_assert(!has_unique_object_representations<VirtuallyInheritsFromNoPadding>::value, "No virtual inheritence");
+
+struct Padding {
+ char a;
+ int b;
+};
+
+static_assert(!has_unique_object_representations<Padding>::value, "but not with padding");
+
+struct InheritsFromPadding : Padding {
+ int c;
+ int d;
+};
+
+static_assert(!has_unique_object_representations<InheritsFromPadding>::value, "or its subclasses");
+
+struct TailPadding {
+ int a;
+ char b;
+};
+
+static_assert(!has_unique_object_representations<TailPadding>::value, "even at the end");
+
+struct TinyStruct {
+ char a;
+};
+
+static_assert(has_unique_object_representations<TinyStruct>::value, "Should be no padding");
+
+struct InheritsFromTinyStruct : TinyStruct {
+ int b;
+};
+
+static_assert(!has_unique_object_representations<InheritsFromTinyStruct>::value, "Inherit causes padding");
+
+union NoPaddingUnion {
+ int a;
+ unsigned int b;
+};
+
+static_assert(has_unique_object_representations<NoPaddingUnion>::value, "unions follow the same rules as structs");
+
+union PaddingUnion {
+ int a;
+ long long b;
+};
+
+static_assert(!has_unique_object_representations<PaddingUnion>::value, "unions follow the same rules as structs");
+
+struct NotTriviallyCopyable {
+ int x;
+ NotTriviallyCopyable(const NotTriviallyCopyable &) {}
+};
+
+static_assert(!has_unique_object_representations<NotTriviallyCopyable>::value, "must be trivially copyable");
+
+struct HasNonUniqueMember {
+ float x;
+};
+
+static_assert(!has_unique_object_representations<HasNonUniqueMember>::value, "all members must be unique");
+
+enum ExampleEnum { xExample,
+ yExample };
+enum LLEnum : long long { xLongExample,
+ yLongExample };
+
+static_assert(has_unique_object_representations<ExampleEnum>::value, "Enums are integrals, so unique!");
+static_assert(has_unique_object_representations<LLEnum>::value, "Enums are integrals, so unique!");
+
+enum class ExampleEnumClass { xExample,
+ yExample };
+enum class LLEnumClass : long long { xLongExample,
+ yLongExample };
+
+static_assert(has_unique_object_representations<ExampleEnumClass>::value, "Enums are integrals, so unique!");
+static_assert(has_unique_object_representations<LLEnumClass>::value, "Enums are integrals, so unique!");
+
+// because reference types aren't object types
+static_assert(!has_unique_object_representations<int &>::value, "No references!");
+static_assert(!has_unique_object_representations<const int &>::value, "No references!");
+static_assert(!has_unique_object_representations<volatile int &>::value, "No references!");
+static_assert(!has_unique_object_representations<const volatile int &>::value, "No references!");
+
+static_assert(!has_unique_object_representations<Empty>::value, "No empty types!");
+
+class Compressed : Empty {
+ int x;
+};
+
+static_assert(has_unique_object_representations<Compressed>::value, "But inheriting from one is ok");
+
+class EmptyInheritor : Compressed {};
+
+static_assert(has_unique_object_representations<EmptyInheritor>::value, "As long as the base has items, empty is ok");
+
+class Dynamic {
+ virtual void A();
+ int i;
+};
+
+static_assert(!has_unique_object_representations<Dynamic>::value, "Dynamic types are not valid");
+
+class InheritsDynamic : Dynamic {
+ int j;
+};
+
+static_assert(!has_unique_object_representations<InheritsDynamic>::value, "Dynamic types are not valid");
+
+static_assert(has_unique_object_representations<int[42]>::value, "Arrays are fine, as long as their value type is");
+static_assert(has_unique_object_representations<int[]>::value, "Arrays are fine, as long as their value type is");
+static_assert(has_unique_object_representations<int[][42]>::value, "Arrays are fine, as long as their value type is");
+static_assert(!has_unique_object_representations<double[42]>::value, "So no array of doubles!");
+static_assert(!has_unique_object_representations<double[]>::value, "So no array of doubles!");
+static_assert(!has_unique_object_representations<double[][42]>::value, "So no array of doubles!");
+
+static_assert(!has_unique_object_representations<int(int)>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) const>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) volatile>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) const volatile>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) const &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) volatile &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) const volatile &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) &&>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) const &&>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) volatile &&>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int) const volatile &&>::value, "Functions are not unique");
+
+static_assert(!has_unique_object_representations<int(int, ...)>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) const>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) volatile>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) const volatile>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) const &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) volatile &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) const volatile &>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) &&>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) const &&>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) volatile &&>::value, "Functions are not unique");
+static_assert(!has_unique_object_representations<int(int, ...) const volatile &&>::value, "Functions are not unique");
+
+static auto lambda = []() {};
+static_assert(!has_unique_object_representations<decltype(lambda)>::value, "Lambdas are not unique");
+
diff --git a/test/SemaCXX/typo-correction-crash.cpp b/test/SemaCXX/typo-correction-crash.cpp
index 0b8383dbaf..b7b9c73a0c 100644
--- a/test/SemaCXX/typo-correction-crash.cpp
+++ b/test/SemaCXX/typo-correction-crash.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s
auto check1() {
return 1;
return s; // expected-error {{use of undeclared identifier 's'}}
@@ -19,3 +19,5 @@ struct FooRecord { };
FooRecord::NestedNamespace::type x; // expected-error {{no member named 'NestedNamespace' in 'FooRecord'; did you mean 'BarNamespace::NestedNamespace'?}}
void cast_expr(int g) { +int(n)(g); } // expected-error {{undeclared identifier 'n'}}
+
+void bind() { for (const auto& [test,_] : _test_) { }; } // expected-error {{undeclared identifier '_test_'}}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index 48597ded15..2d78f06c5d 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -524,13 +524,16 @@ namespace shadowed_template {
template <typename T> class Fizbin {}; // expected-note {{'::shadowed_template::Fizbin' declared here}}
class Baz {
int Fizbin();
- // TODO: Teach the parser to recover from the typo correction instead of
- // continuing to treat the template name as an implicit-int declaration.
- Fizbin<int> qux; // expected-error {{unknown type name 'Fizbin'; did you mean '::shadowed_template::Fizbin'?}} \
- // expected-error {{expected member name or ';' after declaration specifiers}}
+ Fizbin<int> qux; // expected-error {{no template named 'Fizbin'; did you mean '::shadowed_template::Fizbin'?}}
};
}
+namespace no_correct_template_id_to_non_template {
+ struct Frobnatz {}; // expected-note {{declared here}}
+ Frobnats fn; // expected-error {{unknown type name 'Frobnats'; did you mean 'Frobnatz'?}}
+ Frobnats<int> fni; // expected-error-re {{no template named 'Frobnats'{{$}}}}
+}
+
namespace PR18852 {
void func() {
struct foo {
@@ -679,3 +682,30 @@ int g() {
sizeof(c0is0)]; // expected-error {{use of undeclared identifier}}
};
}
+
+namespace avoidRedundantRedefinitionErrors {
+class Class {
+ void function(int pid); // expected-note {{'function' declared here}}
+};
+
+void Class::function2(int pid) { // expected-error {{out-of-line definition of 'function2' does not match any declaration in 'avoidRedundantRedefinitionErrors::Class'; did you mean 'function'?}}
+}
+
+// Expected no redefinition error here.
+void Class::function(int pid) { // expected-note {{previous definition is here}}
+}
+
+void Class::function(int pid) { // expected-error {{redefinition of 'function'}}
+}
+
+namespace ns {
+void create_test(); // expected-note {{'create_test' declared here}}
+}
+
+void ns::create_test2() { // expected-error {{out-of-line definition of 'create_test2' does not match any declaration in namespace 'avoidRedundantRedefinitionErrors::ns'; did you mean 'create_test'?}}
+}
+
+// Expected no redefinition error here.
+void ns::create_test() {
+}
+}
diff --git a/test/SemaCXX/unavailable_aligned_allocation.cpp b/test/SemaCXX/unavailable_aligned_allocation.cpp
new file mode 100644
index 0000000000..2000e0b6a3
--- /dev/null
+++ b/test/SemaCXX/unavailable_aligned_allocation.cpp
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -faligned-alloc-unavailable -std=c++1z -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++1z -verify -DNO_ERRORS %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -faligned-allocation -faligned-alloc-unavailable -std=c++14 -verify %s
+// RUN: %clang_cc1 -triple arm64-apple-ios10.0.0 -fexceptions -faligned-alloc-unavailable -std=c++1z -verify -DIOS %s
+// RUN: %clang_cc1 -triple arm64-apple-ios10.0.0 -fexceptions -std=c++1z -verify -DNO_ERRORS %s
+// RUN: %clang_cc1 -triple arm64-apple-tvos10.0.0 -fexceptions -faligned-alloc-unavailable -std=c++1z -verify -DTVOS %s
+// RUN: %clang_cc1 -triple arm64-apple-tvos10.0.0 -fexceptions -std=c++1z -verify -DNO_ERRORS %s
+// RUN: %clang_cc1 -triple armv7k-apple-watchos3.0.0 -fexceptions -faligned-alloc-unavailable -std=c++1z -verify -DWATCHOS %s
+// RUN: %clang_cc1 -triple armv7k-apple-watchos3.0.0 -fexceptions -std=c++1z -verify -DNO_ERRORS %s
+
+namespace std {
+ typedef decltype(sizeof(0)) size_t;
+ enum class align_val_t : std::size_t {};
+ struct nothrow_t {};
+ nothrow_t nothrow;
+}
+
+void *operator new(std::size_t __sz, const std::nothrow_t&) noexcept;
+void *operator new[](std::size_t __sz, const std::nothrow_t&) noexcept;
+
+void *operator new(std::size_t __sz, std::align_val_t, const std::nothrow_t&) noexcept;
+void *operator new[](std::size_t __sz, std::align_val_t, const std::nothrow_t&) noexcept;
+void operator delete(void *, std::align_val_t, const std::nothrow_t&);
+void operator delete[](void *, std::align_val_t, const std::nothrow_t&);
+void operator delete(void*, std::size_t, std::align_val_t) noexcept;
+void operator delete[](void*, std::size_t, std::align_val_t) noexcept;
+
+void *operator new(std::size_t, std::align_val_t, long long);
+
+struct alignas(256) OveralignedS {
+ int x[16];
+};
+
+struct S {
+ int x[16];
+};
+
+void test() {
+ auto *p = new S;
+ delete p;
+ p = new (std::nothrow) S;
+
+ auto *pa = new S[4];
+ delete[] pa;
+ pa = new (std::nothrow) S[4];
+}
+
+void testOveraligned() {
+ auto *p = new OveralignedS;
+ p = new ((std::align_val_t)8) OveralignedS;
+ delete p;
+ p = new (std::nothrow) OveralignedS;
+
+ auto *pa = new OveralignedS[4];
+ pa = new ((std::align_val_t)8) OveralignedS[4];
+ delete[] pa;
+ pa = new (std::nothrow) OveralignedS[4];
+ // No error here since it is not calling a replaceable allocation function.
+ p = new ((std::align_val_t)8, 10LL) OveralignedS;
+}
+
+#ifdef NO_ERRORS
+// expected-no-diagnostics
+#else
+// expected-error@-16 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
+// expected-note@-17 {{if you supply your own aligned allocation functions}}
+// expected-error@-18 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-19 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-20 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
+// expected-note@-21 {{if you supply your own aligned allocation functions}}
+// expected-error@-22 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-23 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-24 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-25 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-26 {{aligned allocation function of type 'void *(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept' is only available on}}
+// expected-note@-27 {{if you supply your own aligned allocation functions}}
+// expected-error@-28 {{aligned deallocation function of type 'void (void *, std::align_val_t, const std::nothrow_t &) noexcept' is only available on}}
+// expected-note@-29 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-29 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
+// expected-note@-30 {{if you supply your own aligned allocation functions}}
+// expected-error@-31 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-32 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-33 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
+// expected-note@-34 {{if you supply your own aligned allocation functions}}
+// expected-error@-35 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-36 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-37 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
+// expected-note@-38 {{if you supply your own aligned allocation functions}}
+
+// expected-error@-39 {{aligned allocation function of type 'void *(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept' is only available on}}
+// expected-note@-40 {{if you supply your own aligned allocation functions}}
+// expected-error@-41 {{aligned deallocation function of type 'void (void *, std::align_val_t, const std::nothrow_t &) noexcept' is only available on}}
+// expected-note@-42 {{if you supply your own aligned allocation functions}}
+
+#endif
+
+void testOveralignedCheckOS() {
+ auto *p = new OveralignedS;
+}
+
+#ifdef NO_ERRORS
+// expected-no-diagnostics
+#else
+#if defined(IOS)
+// expected-error@-7 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on iOS 11 or newer}}
+// expected-error@-8 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on iOS 11 or newer}}}
+#elif defined(TVOS)
+// expected-error@-10 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on tvOS 11 or newer}}}
+// expected-error@-11 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on tvOS 11 or newer}}}
+#elif defined(WATCHOS)
+// expected-error@-13 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on watchOS 4 or newer}}}
+// expected-error@-14 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on watchOS 4 or newer}}}
+#else
+// expected-error@-16 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on macOS 10.13 or newer}}}
+// expected-error@-17 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on macOS 10.13 or newer}}}
+#endif
+
+// expected-note@-20 2 {{if you supply your own aligned allocation functions}}
+#endif
+
+// No errors if user-defined aligned allocation functions are available.
+void *operator new(std::size_t __sz, std::align_val_t) {
+ static char array[256];
+ return &array;
+}
+
+void operator delete(void *p, std::align_val_t) {
+}
+
+void testOveraligned2() {
+ auto p = new ((std::align_val_t)8) OveralignedS;
+ delete p;
+}
diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp
index 32151b71ea..60fa202384 100644
--- a/test/SemaCXX/undefined-internal.cpp
+++ b/test/SemaCXX/undefined-internal.cpp
@@ -187,6 +187,10 @@ namespace OverloadUse {
void f();
void f(int); // expected-warning {{function 'OverloadUse::(anonymous namespace)::f' has internal linkage but is not defined}}
void f(int, int); // expected-warning {{function 'OverloadUse::(anonymous namespace)::f' has internal linkage but is not defined}}
+#if __cplusplus < 201103L
+ // expected-note@-3 {{here}}
+ // expected-note@-3 {{here}}
+#endif
}
template<void x()> void t() { x(); }
template<void x(int)> void t(int*) { x(10); }
@@ -194,6 +198,10 @@ namespace OverloadUse {
void g(int n) {
t<f>(&n); // expected-note {{used here}}
t<f>(&n, &n); // expected-note {{used here}}
+#if __cplusplus < 201103L
+ // expected-warning@-3 {{non-type template argument referring to function 'f' with internal linkage}}
+ // expected-warning@-3 {{non-type template argument referring to function 'f' with internal linkage}}
+#endif
}
}
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index e4928b8566..92f1c1472c 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -955,7 +955,7 @@ namespace record_fields {
A a13 = rref(std::move(a13)); // expected-warning {{uninitialized}}
A a14 = std::move(x ? a13 : (22, a14)); // expected-warning {{uninitialized}}
};
- D d;
+ D d; // expected-note {{in implicit default constructor for 'record_fields::D' first required here}}
struct E {
A a1 = a1;
A a2 = a2.get();
diff --git a/test/SemaCXX/unused.cpp b/test/SemaCXX/unused.cpp
index 09a179e7bb..abaf611b0d 100644
--- a/test/SemaCXX/unused.cpp
+++ b/test/SemaCXX/unused.cpp
@@ -1,14 +1,15 @@
-// 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
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 -Wunused %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wunused %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wunused %s
// PR4103 : Make sure we don't get a bogus unused expression warning
namespace PR4103 {
class APInt {
- char foo;
+ char foo; // expected-warning {{private field 'foo' is not used}}
};
class APSInt : public APInt {
- char bar;
+ char bar; // expected-warning {{private field 'bar' is not used}}
public:
APSInt &operator=(const APSInt &RHS);
};
@@ -69,3 +70,44 @@ namespace UnresolvedLookup {
}
};
}
+
+#if __cplusplus >= 201703L
+namespace PR33839 {
+ void a() {
+ struct X { int a, b; } x;
+ auto [a, b] = x; // expected-warning {{unused variable '[a, b]'}}
+ auto [c, d] = x;
+ (void)d;
+ }
+
+ template<typename T> void f() {
+ struct A { int n; } a[1];
+ for (auto [x] : a) {
+ (void)x;
+ }
+ auto [y] = a[0]; // expected-warning {{unused}}
+ }
+ template<bool b> void g() {
+ struct A { int n; } a[1];
+ for (auto [x] : a) {
+ if constexpr (b)
+ (void)x;
+ }
+
+ auto [y] = a[0];
+ if constexpr (b)
+ (void)y; // ok, even when b == false
+ }
+ template<typename T> void h() {
+ struct A { int n; } a[1];
+ for (auto [x] : a) { // expected-warning {{unused variable '[x]'}}
+ }
+ }
+ void use() {
+ f<int>(); // expected-note {{instantiation of}}
+ g<true>();
+ g<false>();
+ h<int>(); // expected-note {{instantiation of}}
+ }
+}
+#endif
diff --git a/test/SemaCXX/varargs.cpp b/test/SemaCXX/varargs.cpp
index 6a1883786a..f2f53dc200 100644
--- a/test/SemaCXX/varargs.cpp
+++ b/test/SemaCXX/varargs.cpp
@@ -1,12 +1,59 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++03 -verify %s
+// RUN: %clang_cc1 -std=c++03 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+__builtin_va_list ap;
class string;
void f(const string& s, ...) { // expected-note {{parameter of type 'const string &' is declared here}}
- __builtin_va_list ap;
__builtin_va_start(ap, s); // expected-warning {{passing an object of reference type to 'va_start' has undefined behavior}}
}
-void g(register int i, ...) {
- __builtin_va_list ap;
- __builtin_va_start(ap, i); // okay
+void g(register int i, ...) { // expected-warning 0-1{{deprecated}}
+ __builtin_va_start(ap, i); // UB in C, OK in C++
+}
+
+// Don't crash when there is no last parameter.
+void no_params(...) {
+ int a;
+ __builtin_va_start(ap, a); // expected-warning {{second argument to 'va_start' is not the last named parameter}}
+}
+
+// Reject this. The __builtin_va_start would execute in Foo's non-variadic
+// default ctor.
+void record_context(int a, ...) {
+ struct Foo {
+ // expected-error@+1 {{'va_start' cannot be used outside a function}}
+ void meth(int a, int b = (__builtin_va_start(ap, a), 0)) {}
+ };
+}
+
+#if __cplusplus >= 201103L
+// We used to have bugs identifying the correct enclosing function scope in a
+// lambda.
+
+void fixed_lambda_varargs_function(int a, ...) {
+ [](int b) {
+ __builtin_va_start(ap, b); // expected-error {{'va_start' used in function with fixed args}}
+ }(42);
+}
+void varargs_lambda_fixed_function(int a) {
+ [](int b, ...) {
+ __builtin_va_start(ap, b); // correct
+ }(42);
+}
+
+auto fixed_lambda_global = [](int f) {
+ __builtin_va_start(ap, f); // expected-error {{'va_start' used in function with fixed args}}
+};
+auto varargs_lambda_global = [](int f, ...) {
+ __builtin_va_start(ap, f); // correct
+};
+
+void record_member_init(int a, ...) {
+ struct Foo {
+ int a = 0;
+ // expected-error@+1 {{'va_start' cannot be used outside a function}}
+ int b = (__builtin_va_start(ap, a), 0);
+ };
}
+#endif
diff --git a/test/SemaCXX/vartemplate-lambda.cpp b/test/SemaCXX/vartemplate-lambda.cpp
index 5b91e232e3..6744968bcc 100644
--- a/test/SemaCXX/vartemplate-lambda.cpp
+++ b/test/SemaCXX/vartemplate-lambda.cpp
@@ -8,7 +8,7 @@ template<typename T> auto v1 = [](int a = T(1)) { return a; }();
struct S {
template<class T>
- static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' must be initialized by a constant expression}} expected-error{{a lambda expression may not appear inside of a constant expression}} expected-note{{cannot be used in a constant expression}}
+ static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' must be initialized by a constant expression}} expected-note{{cannot be used in a constant expression}}
};
template <typename X>
diff --git a/test/SemaCXX/vector-no-lax.cpp b/test/SemaCXX/vector-no-lax.cpp
index a85f7f9db0..3cedcb1e8c 100644
--- a/test/SemaCXX/vector-no-lax.cpp
+++ b/test/SemaCXX/vector-no-lax.cpp
@@ -4,6 +4,6 @@ typedef int __attribute__((vector_size (16))) vSInt32;
vSInt32 foo (vUInt32 a) {
vSInt32 b = { 0, 0, 0, 0 };
- b += a; // expected-error{{cannot convert between vector values}}
+ b += a; // expected-error{{cannot convert between vector type 'vUInt32' (vector of 4 'unsigned int' values) and vector type 'vSInt32' (vector of 4 'int' values) as implicit conversion would cause truncation}}
return b;
}
diff --git a/test/SemaCXX/virtual-base-used.cpp b/test/SemaCXX/virtual-base-used.cpp
index f0dcc969e8..583923b927 100644
--- a/test/SemaCXX/virtual-base-used.cpp
+++ b/test/SemaCXX/virtual-base-used.cpp
@@ -65,7 +65,7 @@ struct D : public virtual B {
#ifdef MSABI
D d;
#if __cplusplus <= 199711L
-// expected-note@-2 {{implicit default constructor for 'D' first required here}}
+// expected-note@-2 2{{implicit default constructor for 'D' first required here}}
#else
// expected-error@-4 {{call to implicitly-deleted default constructor of 'D'}}
#endif
@@ -118,8 +118,9 @@ struct G : public virtual F {
#ifdef MSABI
#if __cplusplus <= 199711L
// expected-note@-3 {{implicit default constructor for 'F' first required here}}
+// expected-note@-4 {{implicit destructor 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}}
+// expected-note@-6 {{default constructor of 'G' is implicitly deleted because base class 'F' has a deleted default constructor}}
#endif
#endif
@@ -133,7 +134,7 @@ struct G : public virtual F {
#ifdef MSABI
G g;
#if __cplusplus <= 199711L
-// expected-note@-2 {{implicit default constructor for 'G' first required here}}
+// expected-note@-2 2{{implicit default constructor for 'G' first required here}}
#else
// expected-error@-4 {{call to implicitly-deleted default constructor of 'G'}}
#endif
@@ -149,10 +150,6 @@ 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@-6 {{'H' declared here}}
-#endif
#endif
NoDestroy x;
@@ -171,11 +168,8 @@ struct H : public virtual A {
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}}
+#if __cplusplus > 199711L
+// expected-note@-3 {{default constructor of 'I' is implicitly deleted because base class 'H' has a deleted default constructor}}
#endif
#endif
@@ -189,7 +183,7 @@ struct J : public I {
#ifdef MSABI
#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}}
+// expected-note@-4 {{implicit destructor for 'H' first required here}}
#else
// expected-note@-6 {{default constructor of 'J' is implicitly deleted because base class 'I' has a deleted default constructor}}
#endif
@@ -202,7 +196,7 @@ struct J : public I {
#ifdef MSABI
J j;
#if __cplusplus <= 199711L
-// expected-note@-2 {{implicit default constructor for 'J' first required here}}
+// expected-note@-2 2{{implicit default constructor for 'J' first required here}}
#else
// expected-error@-4 {{call to implicitly-deleted default constructor of 'J'}}
#endif
diff --git a/test/SemaCXX/warn-absolute-value.cpp b/test/SemaCXX/warn-absolute-value.cpp
index 8a8a6fd67d..9a23054fd1 100644
--- a/test/SemaCXX/warn-absolute-value.cpp
+++ b/test/SemaCXX/warn-absolute-value.cpp
@@ -448,94 +448,16 @@ void test_long_double(long double x) {
}
void test_complex_float(_Complex float x) {
- (void)abs(x);
- // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"cabsf"
- (void)labs(x);
- // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsf"
- (void)llabs(x);
- // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsf"
-
- (void)fabsf(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsf"
- (void)fabs(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsf"
- (void)fabsl(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsf"
-
(void)cabsf(x);
(void)cabs(x);
(void)cabsl(x);
- (void)__builtin_abs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"__builtin_cabsf"
- (void)__builtin_labs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsf"
- (void)__builtin_llabs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsf"
-
- (void)__builtin_fabsf(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsf"
- (void)__builtin_fabs(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsf"
- (void)__builtin_fabsl(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsf' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsf"
-
(void)__builtin_cabsf(x);
(void)__builtin_cabs(x);
(void)__builtin_cabsl(x);
}
void test_complex_double(_Complex double x) {
- (void)abs(x);
- // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"cabs"
- (void)labs(x);
- // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabs"
- (void)llabs(x);
- // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabs"
-
- (void)fabsf(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabs"
- (void)fabs(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabs"
- (void)fabsl(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabs"
-
(void)cabsf(x);
// expected-warning@-1 {{absolute value function 'cabsf' given an argument of type '_Complex double' but has parameter of type '_Complex float' which may cause truncation of value}}
// expected-note@-2 {{use function 'cabs' instead}}
@@ -543,31 +465,6 @@ void test_complex_double(_Complex double x) {
(void)cabs(x);
(void)cabsl(x);
- (void)__builtin_abs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"__builtin_cabs"
- (void)__builtin_labs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabs"
- (void)__builtin_llabs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabs"
-
- (void)__builtin_fabsf(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabs"
- (void)__builtin_fabs(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabs"
- (void)__builtin_fabsl(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabs' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabs"
(void)__builtin_cabsf(x);
// expected-warning@-1 {{absolute value function '__builtin_cabsf' given an argument of type '_Complex double' but has parameter of type '_Complex float' which may cause truncation of value}}
@@ -578,32 +475,6 @@ void test_complex_double(_Complex double x) {
}
void test_complex_long_double(_Complex long double x) {
- (void)abs(x);
- // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"cabsl"
- (void)labs(x);
- // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsl"
- (void)llabs(x);
- // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsl"
-
- (void)fabsf(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsl"
- (void)fabs(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsl"
- (void)fabsl(x);
- // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of complex type}}
- // expected-note@-2 {{use function 'cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsl"
-
(void)cabsf(x);
// expected-warning@-1 {{absolute value function 'cabsf' given an argument of type '_Complex long double' but has parameter of type '_Complex float' which may cause truncation of value}}
// expected-note@-2 {{use function 'cabsl' instead}}
@@ -614,32 +485,6 @@ void test_complex_long_double(_Complex long double x) {
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsl"
(void)cabsl(x);
- (void)__builtin_abs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"__builtin_cabsl"
- (void)__builtin_labs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsl"
- (void)__builtin_llabs(x);
- // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsl"
-
- (void)__builtin_fabsf(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsl"
- (void)__builtin_fabs(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsl"
- (void)__builtin_fabsl(x);
- // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of complex type}}
- // expected-note@-2 {{use function '__builtin_cabsl' instead}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsl"
-
(void)__builtin_cabsf(x);
// expected-warning@-1 {{absolute value function '__builtin_cabsf' given an argument of type '_Complex long double' but has parameter of type '_Complex float' which may cause truncation of value}}
// expected-note@-2 {{use function '__builtin_cabsl' instead}}
diff --git a/test/SemaCXX/warn-bitfield-enum-conversion.cpp b/test/SemaCXX/warn-bitfield-enum-conversion.cpp
new file mode 100644
index 0000000000..7e7a202f8d
--- /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-c++1z-extensions.cpp b/test/SemaCXX/warn-c++1z-extensions.cpp
index 9b5e1c205c..a0d44a34ff 100644
--- a/test/SemaCXX/warn-c++1z-extensions.cpp
+++ b/test/SemaCXX/warn-c++1z-extensions.cpp
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s
void f() {
- if (bool b = true; b) {} // expected-warning {{'if' initialization statements are a C++1z extension}}
- switch (int n = 5; n) { // expected-warning {{'switch' initialization statements are a C++1z extension}}
+ if (bool b = true; b) {} // expected-warning {{'if' initialization statements are a C++17 extension}}
+ switch (int n = 5; n) { // expected-warning {{'switch' initialization statements are a C++17 extension}}
case 5: break;
}
}
diff --git a/test/SemaCXX/warn-cast-qual.cpp b/test/SemaCXX/warn-cast-qual.cpp
new file mode 100644
index 0000000000..d1f0cc73a6
--- /dev/null
+++ b/test/SemaCXX/warn-cast-qual.cpp
@@ -0,0 +1,140 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wcast-qual -verify %s
+
+#include <stdint.h>
+
+// do *NOT* warn on const_cast<>()
+// use clang-tidy's cppcoreguidelines-pro-type-const-cast for that.
+void foo_ptr() {
+ const char *const ptr = 0;
+ char *t0 = const_cast<char *>(ptr); // no warning
+
+ volatile char *ptr2 = 0;
+ char *t1 = const_cast<char *>(ptr2); // no warning
+
+ const volatile char *ptr3 = 0;
+ char *t2 = const_cast<char *>(ptr3); // no warning
+}
+
+void cstr() {
+ void* p0 = (void*)(const void*)"txt"; // expected-warning {{cast from 'const void *' to 'void *' drops const qualifier}}
+ void* p1 = (void*)"txt"; // FIXME
+ char* p2 = (char*)"txt"; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}}
+}
+
+void foo_0() {
+ const int a = 0;
+
+ const int &a0 = a; // no warning
+ const int &a1 = (const int &)a; // no warning
+
+ int &a2 = (int &)a; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ const int &a3 = (int &)a; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ int &a4 = (int &)((const int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ int &a5 = (int &)((int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ const int &a6 = (int &)((int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ const int &a7 = (int &)((const int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ const int &a8 = (const int &)((int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+}
+
+void foo_1() {
+ volatile int a = 0;
+
+ volatile int &a0 = a; // no warning
+ volatile int &a1 = (volatile int &)a; // no warning
+
+ int &a2 = (int &)a; // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}}
+ volatile int &a3 = (int &)a; // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}}
+ int &a4 = (int &)((volatile int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}}
+ int &a5 = (int &)((int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}}
+ volatile int &a6 = (int &)((int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}}
+ volatile int &a7 = (int &)((volatile int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}}
+ volatile int &a8 = (volatile int &)((int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}}
+}
+
+void foo_2() {
+ const volatile int a = 0;
+
+ const volatile int &a0 = a; // no warning
+ const volatile int &a1 = (const volatile int &)a; // no warning
+
+ int &a2 = (int &)a; // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}}
+ const volatile int &a3 = (int &)a; // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}}
+ int &a4 = (int &)((const volatile int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}}
+ int &a5 = (int &)((int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}}
+ const volatile int &a6 = (int &)((int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}}
+ const volatile int &a7 = (int &)((const volatile int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}}
+ const volatile int &a8 = (const volatile int &)((int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}}
+}
+
+void bar_0() {
+ const int *_a = 0;
+ const int **a = &_a;
+
+ int **a0 = (int **)((const int **)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ int **a1 = (int **)((int **)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+
+ // const int **a2 = (int **)((int **)a);
+ // const int **a3 = (int **)((const int **)a);
+
+ const int **a4 = (const int **)((int **)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} expected-warning {{cast from 'int **' to 'const int **' must have all intermediate pointers const qualified to be safe}}
+ const int **a5 = (const int **)((const int **)a); // no warning
+}
+
+void bar_1() {
+ const int *_a = 0;
+ const int *&a = _a;
+
+ int *&a0 = (int *&)((const int *&)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ int *&a1 = (int *&)((int *&)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+
+ // const int *&a2 = (int *&)((int *&)a);
+ // const int *&a3 = (int *&)((const int *&)a);
+
+ const int *&a4 = (const int *&)((int *&)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} expected-warning {{cast from 'int *' to 'const int *&' must have all intermediate pointers const qualified to be safe}}
+ const int *&a5 = (const int *&)((const int *&)a); // no warning
+}
+
+void baz_0() {
+ struct C {
+ void A() {}
+ void B() const {}
+ };
+
+ const C S;
+ S.B();
+
+ ((C &)S).B(); // expected-warning {{cast from 'const C' to 'C &' drops const qualifier}}
+ ((C &)S).A(); // expected-warning {{cast from 'const C' to 'C &' drops const qualifier}}
+
+ ((C *)&S)->B(); // expected-warning {{cast from 'const C *' to 'C *' drops const qualifier}}
+ ((C *)&S)->A(); // expected-warning {{cast from 'const C *' to 'C *' drops const qualifier}}
+}
+
+void baz_1() {
+ struct C {
+ const int a;
+ int b;
+
+ C() : a(0) {}
+ };
+
+ {
+ C S;
+ S.b = 0;
+
+ (int &)(S.a) = 0; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ (int &)(S.b) = 0; // no warning
+
+ *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ *(int *)(&S.b) = 0; // no warning
+ }
+ {
+ const C S;
+
+ (int &)(S.a) = 0; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+ (int &)(S.b) = 0; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}}
+
+ *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ *(int *)(&S.b) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ }
+}
diff --git a/test/SemaCXX/warn-enum-compare.cpp b/test/SemaCXX/warn-enum-compare.cpp
index 0c287948cd..95107a0146 100644
--- a/test/SemaCXX/warn-enum-compare.cpp
+++ b/test/SemaCXX/warn-enum-compare.cpp
@@ -4,6 +4,8 @@ enum Foo { FooA, FooB, FooC };
enum Bar { BarD, BarE, BarF };
enum { AnonAA = 42, AnonAB = 43 };
enum { AnonBA = 44, AnonBB = 45 };
+enum { Anon1, Anon2, Anon3 };
+typedef enum { TD1, TD2 } TD;
namespace name1 {
enum Foo {F1, F2, F3};
@@ -29,6 +31,7 @@ void test () {
name1::Foo a;
oneFoo b;
twoFoo c;
+ TD td;
while (x == FooA);
while (y == BarD);
@@ -65,6 +68,9 @@ void test () {
while ((((((B1))))) == (((name1::B2))));
while (B2 == ((((((name2::B1)))))));
+ while (td == Anon1);
+ while (td == AnonAA); // expected-warning {{comparison of constant 'AnonAA' (42) with expression of type 'TD' is always false}}
+
while (B1 == B2); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (name1::B2 == name2::B3); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (z == name2::B2); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
@@ -209,4 +215,65 @@ void test () {
while (getBar() > x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() < x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
+ while (td == FooA); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Foo')}}
+ while (td == BarD); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Bar')}}
+ while (name1::F1 == td); // expected-warning {{comparison of two values with different enumeration types ('name1::Foo' and 'TD')}}
+ while (name2::B1 == td); // expected-warning {{comparison of two values with different enumeration types ('name2::Baz' and 'TD')}}
+ while (td == a); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'name1::Foo')}}
+ while (td == b); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'oneFoo' (aka 'name1::Foo'))}}
+ while (td == c); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'twoFoo' (aka 'name1::Foo'))}}
+ while (td == x); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Foo')}}
+ while (td == y); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Bar')}}
+ while (td == z); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'name1::Baz')}}
+
+ while (a == TD1); // expected-warning {{comparison of two values with different enumeration types ('name1::Foo' and 'TD')}}
+ while (b == TD2); // expected-warning {{comparison of two values with different enumeration types ('oneFoo' (aka 'name1::Foo') and 'TD')}}
+ while (c == TD1); // expected-warning {{comparison of two values with different enumeration types ('twoFoo' (aka 'name1::Foo') and 'TD')}}
+ while (x == TD2); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'TD')}}
+ while (y == TD1); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'TD')}}
+ while (z == TD2); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'TD')}}
+
+ switch (a) {
+ case name1::F1: break;
+ case name1::F3: break;
+ case name2::B2: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('name1::Foo' and 'name2::Baz')}}
+ }
+
+ switch (x) {
+ case FooB: break;
+ case FooC: break;
+ case BarD: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('Foo' and 'Bar')}}
+ }
+
+ switch(getBar()) {
+ case BarE: break;
+ case BarF: break;
+ case FooA: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('Bar' and 'Foo')}}
+ }
+
+ switch(x) {
+ case AnonAA: break; // expected-warning {{case value not in enumerated type 'Foo'}}
+ case FooA: break;
+ case FooB: break;
+ case FooC: break;
+ }
+
+ switch (td) {
+ case TD1: break;
+ case FooB: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('TD' and 'Foo')}}
+ case BarF: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('TD' and 'Bar')}}
+ // expected-warning@-1 {{case value not in enumerated type 'TD'}}
+ case AnonAA: break; // expected-warning {{case value not in enumerated type 'TD'}}
+ }
+
+ switch (td) {
+ case Anon1: break;
+ case TD2: break;
+ }
+
+ switch (a) {
+ case TD1: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('name1::Foo' and 'TD')}}
+ case TD2: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('name1::Foo' and 'TD')}}
+ case name1::F3: break;
+ }
}
diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp
index 856826414a..430f239a3e 100644
--- a/test/SemaCXX/warn-global-constructors.cpp
+++ b/test/SemaCXX/warn-global-constructors.cpp
@@ -126,3 +126,22 @@ namespace pr20420 {
void *array_storage[1];
const int &global_reference = *(int *)array_storage;
}
+
+namespace bitfields {
+ struct HasUnnamedBitfield {
+ unsigned a;
+ unsigned : 20;
+ unsigned b;
+
+ constexpr HasUnnamedBitfield() : a(), b() {}
+ constexpr HasUnnamedBitfield(unsigned a, unsigned b) : a(a), b(b) {}
+ explicit HasUnnamedBitfield(unsigned a) {}
+ };
+
+ const HasUnnamedBitfield zeroConst{};
+ HasUnnamedBitfield zeroMutable{};
+ const HasUnnamedBitfield explicitConst{1, 2};
+ HasUnnamedBitfield explicitMutable{1, 2};
+ const HasUnnamedBitfield nonConstexprConst{1}; // expected-warning {{global constructor}}
+ HasUnnamedBitfield nonConstexprMutable{1}; // expected-warning {{global constructor}}
+}
diff --git a/test/SemaCXX/warn-loop-analysis.cpp b/test/SemaCXX/warn-loop-analysis.cpp
index 25ec7a7862..2934003848 100644
--- a/test/SemaCXX/warn-loop-analysis.cpp
+++ b/test/SemaCXX/warn-loop-analysis.cpp
@@ -202,6 +202,12 @@ void test7() {
if (true) continue;
i--;
}
+
+ // But do warn if the continue is in a nested loop.
+ for (;;i--) { // expected-note{{decremented here}}
+ for (int j = 0; j < 10; ++j) continue;
+ i--; // expected-warning{{decremented both}}
+ }
}
struct iterator {
@@ -259,6 +265,12 @@ void test8() {
if (true) continue;
i--;
}
+
+ // But do warn if the continue is in a nested loop.
+ for (;;i--) { // expected-note{{decremented here}}
+ for (int j = 0; j < 10; ++j) continue;
+ i--; // expected-warning{{decremented both}}
+ }
}
int f(int);
diff --git a/test/SemaCXX/warn-shadow.cpp b/test/SemaCXX/warn-shadow.cpp
index 1316b6dd88..3d09c78628 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,51 @@ 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.
+}
+
}
+extern "C" {
+typedef int externC; // expected-note {{previous declaration is here}}
+}
+void handleLinkageSpec() {
+ typedef void externC; // expected-warning {{declaration shadows a typedef in the global namespace}}
+}
+
+namespace PR33947 {
+void f(int a) {
+ struct A {
+ void g(int a) {}
+ A() { int a; }
+ };
+}
}
diff --git a/test/SemaCXX/warn-sign-conversion-cpp11.cpp b/test/SemaCXX/warn-sign-conversion-cpp11.cpp
new file mode 100644
index 0000000000..e18b7f5645
--- /dev/null
+++ b/test/SemaCXX/warn-sign-conversion-cpp11.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wsign-conversion -std=c++11 %s
+
+unsigned int test() {
+ short foo;
+ return foo; // expected-warning {{implicit conversion changes signedness}}
+
+}
+
+unsigned int test3() {
+ // For a non-defined enum, use the underlying type.
+ enum u8 : signed char;
+ u8 foo{static_cast<u8>(0)};
+ return foo; // expected-warning {{implicit conversion changes signedness}}
+
+}
+unsigned int test2() {
+ // For a non-defined enum, use the underlying type.
+ enum u8 : unsigned char;
+ u8 foo{static_cast<u8>(0)};
+ return foo;
+}
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index bbb4f9b48d..e6e9a0ac18 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_ASSERT_CAPABILITY=0 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_ASSERT_CAPABILITY=1 %s
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
@@ -13,8 +14,15 @@
#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__)))
#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__)))
+
+#if USE_ASSERT_CAPABILITY
+#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_capability(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...) __attribute__((assert_shared_capability(__VA_ARGS__)))
+#else
#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_exclusive_lock(__VA_ARGS__)))
#define ASSERT_SHARED_LOCK(...) __attribute__((assert_shared_lock(__VA_ARGS__)))
+#endif
+
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__)))
#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__)))
#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
@@ -3675,9 +3683,14 @@ class Foo {
SHARED_TRYLOCK_FUNCTION(true, mu2_);
void assertBoth() ASSERT_EXCLUSIVE_LOCK(mu1_)
ASSERT_EXCLUSIVE_LOCK(mu2_);
+
+ void alsoAssertBoth() ASSERT_EXCLUSIVE_LOCK(mu1_, mu2_);
+
void assertShared() ASSERT_SHARED_LOCK(mu1_)
ASSERT_SHARED_LOCK(mu2_);
+ void alsoAssertShared() ASSERT_SHARED_LOCK(mu1_, mu2_);
+
void test();
void testAssert();
void testAssertShared();
@@ -3741,17 +3754,33 @@ void Foo::test() {
// Force duplication of attributes
void Foo::assertBoth() { }
+void Foo::alsoAssertBoth() { }
void Foo::assertShared() { }
+void Foo::alsoAssertShared() { }
void Foo::testAssert() {
- assertBoth();
- a = 0;
- b = 0;
+ {
+ assertBoth();
+ a = 0;
+ b = 0;
+ }
+ {
+ alsoAssertBoth();
+ a = 0;
+ b = 0;
+ }
}
void Foo::testAssertShared() {
- assertShared();
- int zz = a + b;
+ {
+ assertShared();
+ int zz = a + b;
+ }
+
+ {
+ alsoAssertShared();
+ int zz = a + b;
+ }
}
@@ -5204,3 +5233,18 @@ class acquired_before_empty_str {
} // expected-warning {{mutex 'lock_' is still held at the end of function}}
Mutex lock_ ACQUIRED_BEFORE("");
};
+
+namespace PR34800 {
+struct A {
+ operator int() const;
+};
+struct B {
+ bool g() __attribute__((locks_excluded(h))); // expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
+ int h;
+};
+struct C {
+ B *operator[](int);
+};
+C c;
+void f() { c[A()]->g(); }
+} // namespace PR34800
diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp
index b43e24a897..ae32bfe9c9 100644
--- a/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -1,6 +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
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 %s -D CPP11
#define LOCKABLE __attribute__ ((lockable))
#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
@@ -1513,3 +1513,15 @@ public:
} // end namespace FunctionAttributesInsideClass_ICE_Test
+
+#ifdef CPP11
+namespace CRASH_POST_R301735 {
+ class SomeClass {
+ public:
+ void foo() {
+ auto l = [this] { auto l = [] () EXCLUSIVE_LOCKS_REQUIRED(mu_) {}; };
+ }
+ Mutex mu_;
+ };
+}
+#endif \ No newline at end of file
diff --git a/test/SemaCXX/warn-throw-out-noexcept-func.cpp b/test/SemaCXX/warn-throw-out-noexcept-func.cpp
new file mode 100644
index 0000000000..a6c23ddc6c
--- /dev/null
+++ b/test/SemaCXX/warn-throw-out-noexcept-func.cpp
@@ -0,0 +1,327 @@
+// RUN: %clang_cc1 %s -fdelayed-template-parsing -fcxx-exceptions -fsyntax-only -Wexceptions -verify -fdeclspec -std=c++11
+struct A_ShouldDiag {
+ ~A_ShouldDiag(); // implicitly noexcept(true)
+};
+A_ShouldDiag::~A_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but can still throw}}
+}
+struct B_ShouldDiag {
+ int i;
+ ~B_ShouldDiag() noexcept(true) {} //no disg, no throw stmt
+};
+struct R_ShouldDiag : A_ShouldDiag {
+ B_ShouldDiag b;
+ ~R_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+ __attribute__((nothrow)) R_ShouldDiag() {// expected-note {{function declared non-throwing here}}
+ throw 1;// expected-warning {{has a non-throwing exception specification but}}
+ }
+ void __attribute__((nothrow)) SomeThrow() {// expected-note {{function declared non-throwing here}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+ void __declspec(nothrow) SomeDeclspecThrow() {// expected-note {{function declared non-throwing here}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+
+struct M_ShouldNotDiag {
+ B_ShouldDiag b;
+ ~M_ShouldNotDiag() noexcept(false);
+};
+
+M_ShouldNotDiag::~M_ShouldNotDiag() noexcept(false) {
+ throw 1;
+}
+
+struct N_ShouldDiag {
+ B_ShouldDiag b;
+ ~N_ShouldDiag(); //implicitly noexcept(true)
+};
+
+N_ShouldDiag::~N_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+}
+struct X_ShouldDiag {
+ B_ShouldDiag b;
+ ~X_ShouldDiag() noexcept { // expected-note {{destructor has a non-throwing exception}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+struct Y_ShouldDiag : A_ShouldDiag {
+ ~Y_ShouldDiag() noexcept(true) { // expected-note {{destructor has a non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+struct C_ShouldNotDiag {
+ int i;
+ ~C_ShouldNotDiag() noexcept(false) {}
+};
+struct D_ShouldNotDiag {
+ C_ShouldNotDiag c;
+ ~D_ShouldNotDiag() { //implicitly noexcept(false)
+ throw 1;
+ }
+};
+struct E_ShouldNotDiag {
+ C_ShouldNotDiag c;
+ ~E_ShouldNotDiag(); //implicitly noexcept(false)
+};
+E_ShouldNotDiag::~E_ShouldNotDiag() //implicitly noexcept(false)
+{
+ throw 1;
+}
+
+template <typename T>
+class A1_ShouldDiag {
+ T b;
+
+public:
+ ~A1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+template <typename T>
+struct B1_ShouldDiag {
+ T i;
+ ~B1_ShouldDiag() noexcept(true) {}
+};
+template <typename T>
+struct R1_ShouldDiag : A1_ShouldDiag<T> //expected-note {{in instantiation of member function}}
+{
+ B1_ShouldDiag<T> b;
+ ~R1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+template <typename T>
+struct S1_ShouldDiag : A1_ShouldDiag<T> {
+ B1_ShouldDiag<T> b;
+ ~S1_ShouldDiag() noexcept { // expected-note {{destructor has a non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+void operator delete(void *ptr) noexcept { // expected-note {{deallocator has a non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+}
+struct except_fun {
+ static const bool i = false;
+};
+struct noexcept_fun {
+ static const bool i = true;
+};
+template <typename T>
+struct dependent_warn {
+ ~dependent_warn() noexcept(T::i) {
+ throw 1;
+ }
+};
+template <typename T>
+struct dependent_warn_noexcept {
+ ~dependent_warn_noexcept() noexcept(T::i) { // expected-note {{destructor has a non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+template <typename T>
+struct dependent_warn_both {
+ ~dependent_warn_both() noexcept(T::i) { // expected-note {{destructor has a non-throwing exception specification}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+void foo() noexcept { //expected-note {{function declared non-throwing here}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+}
+struct Throws {
+ ~Throws() noexcept(false);
+};
+
+struct ShouldDiagnose {
+ Throws T;
+ ~ShouldDiagnose() noexcept { //expected-note {{destructor has a non-throwing exception specification}}
+ throw; // expected-warning {{has a non-throwing exception specification but}}
+ }
+};
+struct ShouldNotDiagnose {
+ Throws T;
+ ~ShouldNotDiagnose() {
+ throw;
+ }
+};
+
+void bar_ShouldNotDiag() noexcept {
+ try {
+ throw 1;
+ } catch (...) {
+ }
+}
+void f_ShouldNotDiag() noexcept {
+ try {
+ throw 12;
+ } catch (int) {
+ }
+}
+void g_ShouldNotDiag() noexcept {
+ try {
+ throw 12;
+ } catch (...) {
+ }
+}
+
+void h_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw 12; // expected-warning {{has a non-throwing exception specification but}}
+ } catch (const char *) {
+ }
+}
+
+void i_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw 12;
+ } catch (int) {
+ throw; // expected-warning {{has a non-throwing exception specification but}}
+ }
+}
+void j_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw 12;
+ } catch (int) {
+ throw "haha"; // expected-warning {{has a non-throwing exception specification but}}
+ }
+}
+
+void k_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw 12;
+ } catch (...) {
+ throw; // expected-warning {{has a non-throwing exception specification but}}
+ }
+}
+
+void loo_ShouldDiag(int i) noexcept { //expected-note {{function declared non-throwing here}}
+ if (i)
+ try {
+ throw 12;
+ } catch (int) {
+ throw "haha"; //expected-warning {{has a non-throwing exception specification but}}
+ }
+ i = 10;
+}
+
+void loo1_ShouldNotDiag() noexcept {
+ if (0)
+ throw 12;
+}
+
+void loo2_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
+ if (1)
+ throw 12; // expected-warning {{has a non-throwing exception specification but}}
+}
+struct S {};
+
+void l_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw S{}; //expected-warning {{has a non-throwing exception specification but}}
+ } catch (S *s) {
+ }
+}
+
+void m_ShouldNotDiag() noexcept {
+ try {
+ const S &s = S{};
+ throw s;
+ } catch (S s) {
+ }
+}
+void n_ShouldNotDiag() noexcept {
+ try {
+ S s = S{};
+ throw s;
+ } catch (const S &s) {
+ }
+}
+// As seen in p34973, this should not throw the warning. If there is an active
+// exception, catch(...) catches everything.
+void o_ShouldNotDiag() noexcept {
+ try {
+ throw;
+ } catch (...) {
+ }
+}
+
+void p_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw; //expected-warning {{has a non-throwing exception specification but}}
+ } catch (int){
+ }
+}
+
+void q_ShouldNotDiag() noexcept {
+ try {
+ throw;
+ } catch (int){
+ } catch (...){
+ }
+}
+
+#define NOEXCEPT noexcept
+void with_macro() NOEXCEPT { //expected-note {{function declared non-throwing here}}
+ throw 1; // expected-warning {{has a non-throwing exception specification but}}
+}
+
+void with_try_block() try {
+ throw 2;
+} catch (...) {
+}
+
+void with_try_block1() noexcept try { //expected-note {{function declared non-throwing here}}
+ throw 2; // expected-warning {{has a non-throwing exception specification but}}
+} catch (char *) {
+}
+
+namespace derived {
+struct B {};
+struct D: B {};
+void goodPlain() noexcept {
+ try {
+ throw D();
+ } catch (B) {}
+}
+void goodReference() noexcept {
+ try {
+ throw D();
+ } catch (B &) {}
+}
+void goodPointer() noexcept {
+ D d;
+ try {
+ throw &d;
+ } catch (B *) {}
+}
+void badPlain() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw B(); // expected-warning {{'badPlain' has a non-throwing exception specification but can still throw}}
+ } catch (D) {}
+}
+void badReference() noexcept { //expected-note {{function declared non-throwing here}}
+ try {
+ throw B(); // expected-warning {{'badReference' has a non-throwing exception specification but can still throw}}
+ } catch (D &) {}
+}
+void badPointer() noexcept { //expected-note {{function declared non-throwing here}}
+ B b;
+ try {
+ throw &b; // expected-warning {{'badPointer' has a non-throwing exception specification but can still throw}}
+ } catch (D *) {}
+}
+}
+
+int main() {
+ R1_ShouldDiag<int> o; //expected-note {{in instantiation of member function}}
+ S1_ShouldDiag<int> b; //expected-note {{in instantiation of member function}}
+ dependent_warn<except_fun> f;
+ dependent_warn_noexcept<noexcept_fun> f1; //expected-note {{in instantiation of member function}}
+ dependent_warn_both<except_fun> f2;
+ dependent_warn_both<noexcept_fun> f3; //expected-note {{in instantiation of member function}}
+ ShouldDiagnose obj;
+ ShouldNotDiagnose obj1;
+}
diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp
index b08467ab51..08118147b7 100644
--- a/test/SemaCXX/warn-unreachable.cpp
+++ b/test/SemaCXX/warn-unreachable.cpp
@@ -49,22 +49,26 @@ void test3() {
(halt()); // expected-warning {{will never be executed}}
}
-void test4() {
+namespace Test4 {
struct S {
int mem;
} s;
S &foor();
- halt(), foor()// expected-warning {{will never be executed}}
- .mem;
+ void test4() {
+ halt(), foor()// expected-warning {{will never be executed}}
+ .mem;
+ }
}
-void test5() {
+namespace Test5 {
struct S {
int mem;
} s;
S &foonr() __attribute__((noreturn));
- foonr()
- .mem; // expected-warning {{will never be executed}}
+ void test5() {
+ foonr()
+ .mem; // expected-warning {{will never be executed}}
+ }
}
void test6() {
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index 18defee7d0..93c6bbd7ed 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-unused-local-typedefs -Wno-c++11-extensions -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-unused-local-typedefs -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-template -Wunused-member-function -Wno-unused-local-typedefs -Wno-c++11-extensions -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-template -Wunused-member-function -Wno-unused-local-typedefs -std=c++14 %s
#ifdef HEADER
@@ -65,7 +65,7 @@ namespace {
template <> void TS<int>::m() { } // expected-warning{{unused}}
template <typename T>
- void tf() { }
+ void tf() { } // expected-warning{{unused}}
template <> void tf<int>() { } // expected-warning{{unused}}
struct VS {
@@ -200,6 +200,18 @@ void bar() { void func() __attribute__((used)); }
static void func() {}
}
+namespace test9 {
+template<typename T>
+static void completeRedeclChainForTemplateSpecialization() { } // expected-warning {{unused}}
+}
+
+namespace test10 {
+#if __cplusplus >= 201103L
+template<class T>
+constexpr T pi = T(3.14); // expected-warning {{unused}}
+#endif
+}
+
namespace pr19713 {
#if __cplusplus >= 201103L
// FIXME: We should warn on both of these.
diff --git a/test/SemaCXX/warn-unused-lambda-capture.cpp b/test/SemaCXX/warn-unused-lambda-capture.cpp
index 48f8bfea7e..6ad8e26604 100644
--- a/test/SemaCXX/warn-unused-lambda-capture.cpp
+++ b/test/SemaCXX/warn-unused-lambda-capture.cpp
@@ -142,11 +142,14 @@ void test_templated() {
auto implicit_by_reference = [&] { i++; };
auto explicit_by_value_used = [i] { return i + 1; };
+ auto explicit_by_value_used_generic = [i](auto c) { 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_value_unused_const_generic = [k](auto c) { 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}}
@@ -161,6 +164,8 @@ void test_templated() {
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 explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; };
+ auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}}
auto nested = [&i] {
auto explicit_by_value_used = [i] { return i + 1; };
diff --git a/test/SemaCXX/warn-unused-private-field.cpp b/test/SemaCXX/warn-unused-private-field.cpp
index fb34fa98ea..fe44122a1d 100644
--- a/test/SemaCXX/warn-unused-private-field.cpp
+++ b/test/SemaCXX/warn-unused-private-field.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused-private-field -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-private-field -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++17 %s
class NotFullyDefined {
public:
@@ -246,3 +247,19 @@ namespace pr13543 {
X x[4]; // no-warning
};
}
+
+class implicit_special_member {
+public:
+ static implicit_special_member make() { return implicit_special_member(); }
+
+private:
+ int n; // expected-warning{{private field 'n' is not used}}
+};
+
+class defaulted_special_member {
+public:
+ defaulted_special_member(const defaulted_special_member&) = default;
+
+private:
+ int n; // expected-warning{{private field 'n' is not used}}
+};
diff --git a/test/SemaCXX/warn-unused-result.cpp b/test/SemaCXX/warn-unused-result.cpp
index 01bc457ec2..88f5ab1e85 100644
--- a/test/SemaCXX/warn-unused-result.cpp
+++ b/test/SemaCXX/warn-unused-result.cpp
@@ -160,3 +160,49 @@ void g() {
(void)noexcept(f(), false); // Should not warn.
}
}
+
+namespace {
+// C++ Methods should warn even in their own class.
+struct [[clang::warn_unused_result]] S {
+ S DoThing() { return {}; };
+ S operator++(int) { return {}; };
+ S operator--(int) { return {}; };
+ // Improperly written prefix.
+ S operator++() { return {}; };
+ S operator--() { return {}; };
+};
+
+struct [[clang::warn_unused_result]] P {
+ P DoThing() { return {}; };
+};
+
+P operator++(const P &, int) { return {}; };
+P operator--(const P &, int) { return {}; };
+// Improperly written prefix.
+P operator++(const P &) { return {}; };
+P operator--(const P &) { return {}; };
+
+void f() {
+ S s;
+ P p;
+ s.DoThing(); // expected-warning {{ignoring return value}}
+ p.DoThing(); // expected-warning {{ignoring return value}}
+ // Only postfix is expected to warn when written correctly.
+ s++; // expected-warning {{ignoring return value}}
+ s--; // expected-warning {{ignoring return value}}
+ p++; // expected-warning {{ignoring return value}}
+ p--; // expected-warning {{ignoring return value}}
+ // Improperly written prefix operators should still warn.
+ ++s; // expected-warning {{ignoring return value}}
+ --s; // expected-warning {{ignoring return value}}
+ ++p; // expected-warning {{ignoring return value}}
+ --p; // expected-warning {{ignoring return value}}
+
+ // Silencing the warning by cast to void still works.
+ (void)s.DoThing();
+ (void)s++;
+ (void)p++;
+ (void)++s;
+ (void)++p;
+}
+} // namespace
diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp
index d6ec0fb5d1..98e2a4e863 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/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index d7be785b35..a7ac9afc36 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++1y-extensions -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++1y-extensions -verify -std=c++11 %s
template<typename T> void f() {
T t;
t = 17;
@@ -194,3 +195,45 @@ void test() {
}
}
+
+#if __cplusplus >= 201103L
+namespace with_constexpr {
+template <typename T>
+struct Literal {
+ T i;
+ Literal() = default;
+ constexpr Literal(T i) : i(i) {}
+};
+
+struct NoLiteral {
+ int i;
+ NoLiteral() = default;
+ constexpr NoLiteral(int i) : i(i) {}
+ ~NoLiteral() {}
+};
+
+static Literal<int> gl1; // expected-warning {{unused variable 'gl1'}}
+static Literal<int> gl2(1); // expected-warning {{unused variable 'gl2'}}
+static const Literal<int> gl3(0); // expected-warning {{unused variable 'gl3'}}
+
+template <typename T>
+void test(int i) {
+ Literal<int> l1; // expected-warning {{unused variable 'l1'}}
+ Literal<int> l2(42); // expected-warning {{unused variable 'l2'}}
+ Literal<int> l3(i); // no-warning
+ Literal<T> l4(0); // no-warning
+ NoLiteral nl1; // no-warning
+ NoLiteral nl2(42); // no-warning
+}
+}
+
+namespace crash {
+struct a {
+ a(const char *);
+};
+template <typename b>
+void c() {
+ a d(b::e ? "" : "");
+}
+}
+#endif
diff --git a/test/SemaCXX/warn-zero-nullptr.cpp b/test/SemaCXX/warn-zero-nullptr.cpp
new file mode 100644
index 0000000000..45f05fa570
--- /dev/null
+++ b/test/SemaCXX/warn-zero-nullptr.cpp
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -Wzero-as-null-pointer-constant -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -DSYSTEM_WARNINGS -Wzero-as-null-pointer-constant -Wsystem-headers -std=c++11
+
+#include <warn-zero-nullptr.h>
+
+#define MACRO (0)
+#define MCRO(x) (x)
+
+struct S {};
+
+int (S::*mp0) = nullptr;
+void (*fp0)() = nullptr;
+void* p0 = nullptr;
+
+int (S::*mp1) = 0; // expected-warning{{zero as null pointer constant}}
+void (*fp1)() = 0; // expected-warning{{zero as null pointer constant}}
+void* p1 = 0; // expected-warning{{zero as null pointer constant}}
+
+// NULL is an integer constant expression, so warn on it too:
+void* p2 = __null; // expected-warning{{zero as null pointer constant}}
+void (*fp2)() = __null; // expected-warning{{zero as null pointer constant}}
+int (S::*mp2) = __null; // expected-warning{{zero as null pointer constant}}
+
+void f0(void* v = MACRO); // expected-warning{{zero as null pointer constant}}
+void f1(void* v = NULL); // expected-warning{{zero as null pointer constant}}
+void f2(void* v = MCRO(0)); // expected-warning{{zero as null pointer constant}}
+void f3(void* v = MCRO(NULL)); // expected-warning{{zero as null pointer constant}}
+void f4(void* v = 0); // expected-warning{{zero as null pointer constant}}
+void f5(void* v);
+
+void g() {
+ f1(0); // expected-warning{{zero as null pointer constant}}
+}
+
+// Warn on these too. Matches gcc and arguably makes sense.
+void* pp = (decltype(nullptr))0; // expected-warning{{zero as null pointer constant}}
+void* pp2 = static_cast<decltype(nullptr)>(0); // expected-warning{{zero as null pointer constant}}
+
+// Shouldn't warn.
+namespace pr34362 {
+struct A { operator int*() { return nullptr; } };
+void func() { if (nullptr == A()) {} }
+void func2() { if ((nullptr) == A()) {} }
+}
+
+template <typename T> void TmplFunc0(T var) {}
+void Func0Test() {
+ TmplFunc0<int>(0);
+ TmplFunc0<int*>(0); // expected-warning {{zero as null pointer constant}}
+ TmplFunc0<void*>(0); // expected-warning {{zero as null pointer constant}}
+}
+
+// FIXME: this one probably should not warn.
+template <typename T> void TmplFunc1(int a, T default_value = 0) {} // expected-warning{{zero as null pointer constant}} expected-warning{{zero as null pointer constant}}
+void FuncTest() {
+ TmplFunc1<int>(0);
+ TmplFunc1<int*>(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1<int *>' required here}}
+ TmplFunc1<void*>(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1<void *>' required here}}
+}
+
+template<typename T>
+class TemplateClass0 {
+ public:
+ explicit TemplateClass0(T var) {}
+};
+void TemplateClass0Test() {
+ TemplateClass0<int> a(0);
+ TemplateClass0<int*> b(0); // expected-warning {{zero as null pointer constant}}
+ TemplateClass0<void*> c(0); // expected-warning {{zero as null pointer constant}}
+}
+
+template<typename T>
+class TemplateClass1 {
+ public:
+// FIXME: this one should *NOT* warn.
+ explicit TemplateClass1(int a, T default_value = 0) {} // expected-warning{{zero as null pointer constant}} expected-warning{{zero as null pointer constant}}
+};
+void IgnoreSubstTemplateType1() {
+ TemplateClass1<int> a(1);
+ TemplateClass1<int*> b(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1<int *>' required here}}
+ TemplateClass1<void*> c(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1<void *>' required here}}
+}
+
+#ifndef SYSTEM_WARNINGS
+// Do not warn on *any* other macros from system headers, even if they
+// expand to/their expansion contains NULL.
+void* sys_init = SYSTEM_MACRO;
+void* sys_init2 = OTHER_SYSTEM_MACRO;
+#else
+void* sys_init = SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}}
+void* sys_init2 = OTHER_SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}}
+#endif
diff --git a/test/SemaObjC/Inputs/empty.h b/test/SemaObjC/Inputs/empty.h
new file mode 100644
index 0000000000..6b3def4d7a
--- /dev/null
+++ b/test/SemaObjC/Inputs/empty.h
@@ -0,0 +1 @@
+struct S { int x; };
diff --git a/test/SemaObjC/arc-nsconsumed-errors.m b/test/SemaObjC/arc-nsconsumed-errors.m
index 62e74aabaf..fd0d388ca9 100644
--- a/test/SemaObjC/arc-nsconsumed-errors.m
+++ b/test/SemaObjC/arc-nsconsumed-errors.m
@@ -1,6 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 -DOBJCARC %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
// rdar://10187884
+#ifdef OBJCARC
typedef void (^blk)(id arg1, __attribute((ns_consumed)) id arg2);
typedef void (^blk1)(__attribute((ns_consumed))id arg1, __attribute((ns_consumed)) id arg2);
blk a = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){}; // expected-error {{incompatible block pointer types initializing}}
@@ -18,3 +20,12 @@ blk1 b2 = ^void (id arg1, __attribute((ns_consumed)) id arg2){}; // expected-err
blk1 c3 = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){};
blk1 d4 = ^void (id arg1, id arg2) {}; // expected-error {{incompatible block pointer types initializing}}
+#else
+@interface Sub
+-(void) m:(id)p; // expected-note {{parameter declared here}}
+@end
+
+@interface Super : Sub
+-(void) m:(__attribute__((ns_consumed)) id)p; // expected-warning {{overriding method has mismatched ns_consumed attribute on its parameter}}
+@end
+#endif
diff --git a/test/SemaObjC/arc-peformselector.m b/test/SemaObjC/arc-peformselector.m
index 80fd6d8884..a7e5d3e823 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
@@ -31,9 +35,16 @@
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-property-decl-attrs.m b/test/SemaObjC/arc-property-decl-attrs.m
index 6c96ba481c..7393f58199 100644
--- a/test/SemaObjC/arc-property-decl-attrs.m
+++ b/test/SemaObjC/arc-property-decl-attrs.m
@@ -121,3 +121,134 @@ __attribute__((objc_root_class))
@implementation I2
@synthesize prop;
@end
+
+// rdar://31579994
+// Verify that the all of the property declarations in inherited protocols are
+// compatible when synthesing a property from a protocol.
+
+@protocol CopyVsAssign1
+@property (copy, nonatomic, readonly) id prop; // expected-error {{property with attribute 'copy' was selected for synthesis}}
+@end
+@protocol CopyVsAssign2
+@property (assign, nonatomic, readonly) id prop; // expected-note {{it could also be property without attribute 'copy' declared here}}
+@end
+
+@interface CopyVsAssign: Foo <CopyVsAssign1, CopyVsAssign2>
+@end
+@implementation CopyVsAssign
+@synthesize prop; // expected-note {{property synthesized here}}
+@end
+
+@protocol RetainVsNonRetain1
+@property (readonly) id prop; // expected-error {{property without attribute 'retain (or strong)' was selected for synthesis}}
+@end
+@protocol RetainVsNonRetain2
+@property (retain, readonly) id prop; // expected-note {{it could also be property with attribute 'retain (or strong)' declared here}}
+@end
+
+@interface RetainVsNonRetain: Foo <RetainVsNonRetain1, RetainVsNonRetain2>
+@end
+@implementation RetainVsNonRetain
+@synthesize prop; // expected-note {{property synthesized here}}
+@end
+
+@protocol AtomicVsNonatomic1
+@property (copy, nonatomic, readonly) id prop; // expected-error {{property without attribute 'atomic' was selected for synthesis}}
+@end
+@protocol AtomicVsNonatomic2
+@property (copy, atomic, readonly) id prop; // expected-note {{it could also be property with attribute 'atomic' declared here}}
+@end
+
+@interface AtomicVsNonAtomic: Foo <AtomicVsNonatomic1, AtomicVsNonatomic2>
+@end
+@implementation AtomicVsNonAtomic
+@synthesize prop; // expected-note {{property synthesized here}}
+@end
+
+@protocol Getter1
+@property (copy, readonly) id prop; // expected-error {{property with getter 'prop' was selected for synthesis}}
+@end
+@protocol Getter2
+@property (copy, getter=x, readonly) id prop; // expected-note {{it could also be property with getter 'x' declared here}}
+@end
+
+@interface GetterVsGetter: Foo <Getter1, Getter2>
+@end
+@implementation GetterVsGetter
+@synthesize prop; // expected-note {{property synthesized here}}
+@end
+
+@protocol Setter1
+@property (copy, readonly) id prop;
+@end
+@protocol Setter2
+@property (copy, setter=setp:, readwrite) id prop; // expected-error {{property with setter 'setp:' was selected for synthesis}}
+@end
+@protocol Setter3
+@property (copy, readwrite) id prop; // expected-note {{it could also be property with setter 'setProp:' declared here}}
+@end
+
+@interface SetterVsSetter: Foo <Setter1, Setter2, Setter3>
+@end
+@implementation SetterVsSetter
+@synthesize prop; // expected-note {{property synthesized here}}
+@end
+
+@protocol TypeVsAttribute1
+@property (assign, atomic, readonly) int prop; // expected-error {{property of type 'int' was selected for synthesis}}
+@end
+@protocol TypeVsAttribute2
+@property (assign, atomic, readonly) id prop; // expected-note {{it could also be property of type 'id' declared here}}
+@end
+@protocol TypeVsAttribute3
+@property (copy, readonly) id prop; // expected-note {{it could also be property with attribute 'copy' declared here}}
+@end
+
+@interface TypeVsAttribute: Foo <TypeVsAttribute1, TypeVsAttribute2, TypeVsAttribute3>
+@end
+@implementation TypeVsAttribute
+@synthesize prop; // expected-note {{property synthesized here}}
+@end
+
+@protocol TypeVsSetter1
+@property (assign, nonatomic, readonly) int prop; // expected-note {{it could also be property of type 'int' declared here}}
+@end
+@protocol TypeVsSetter2
+@property (assign, nonatomic, readonly) id prop; // ok
+@end
+@protocol TypeVsSetter3
+@property (assign, nonatomic, readwrite) id prop; // expected-error {{property of type 'id' was selected for synthesis}}
+@end
+
+@interface TypeVsSetter: Foo <TypeVsSetter1, TypeVsSetter2, TypeVsSetter3>
+@end
+@implementation TypeVsSetter
+@synthesize prop; // expected-note {{property synthesized here}}
+@end
+
+@protocol AutoStrongProp
+
+@property (nonatomic, readonly) NSObject *prop;
+
+@end
+
+@protocol AutoStrongProp_Internal <AutoStrongProp>
+
+// This property gets the 'strong' attribute automatically.
+@property (nonatomic, readwrite) NSObject *prop;
+
+@end
+
+@interface SynthesizeWithImplicitStrongNoError : NSObject <AutoStrongProp>
+@end
+
+@interface SynthesizeWithImplicitStrongNoError () <AutoStrongProp_Internal>
+
+@end
+
+@implementation SynthesizeWithImplicitStrongNoError
+
+// no error, 'strong' is implicit in the 'readwrite' property.
+@synthesize prop = _prop;
+
+@end
diff --git a/test/SemaObjC/arc-repeated-weak.mm b/test/SemaObjC/arc-repeated-weak.mm
index 8e2828fcac..37b2123ec1 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
@@ -473,5 +474,8 @@ enum E {
};
void foo1() {
- INTFPtrTy tmp = (INTFPtrTy)e1; // expected-error{{cast of 'E' to 'INTFPtrTy' (aka 'INTF *') is disallowed with ARC}}
+ 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 8274802743..c596168199 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/attr-availability.m b/test/SemaObjC/attr-availability.m
index 02b7c5c814..da1a664e91 100644
--- a/test/SemaObjC/attr-availability.m
+++ b/test/SemaObjC/attr-availability.m
@@ -13,7 +13,7 @@
@interface A <P>
- (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{'method' has been explicitly marked deprecated here}}
#if defined(WARN_PARTIAL)
- // expected-note@+2 {{'partialMethod' has been explicitly marked partial here}}
+ // expected-note@+2 2 {{'partialMethod' has been explicitly marked partial here}}
#endif
- (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
@@ -66,7 +66,10 @@ void f(A *a, B *b) {
@end
void f_after_redecl(A *a, B *b) {
- [a partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+ // expected-warning@+2{{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}}
+#endif
+ [a partialMethod];
[b partialMethod]; // no warning
[a partial_proto_method]; // no warning
[b partial_proto_method]; // no warning
@@ -133,6 +136,10 @@ id NSNibOwner, topNibObjects;
@end
@interface PartialI <PartialProt>
+#ifdef WARN_PARTIAL
+// expected-note@+3{{marked partial here}}
+// expected-note@+3{{marked partial here}}
+#endif
- (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
+ (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
@end
@@ -160,14 +167,20 @@ id NSNibOwner, topNibObjects;
@end
void partialfun(PartialI* a) {
- [a partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+ // expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2{{@available}}
+#endif
+ [a partialMethod];
[a ipartialMethod1]; // no warning
#if defined(WARN_PARTIAL)
// expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
#endif
[a ipartialMethod2];
[a ppartialMethod]; // no warning
- [PartialI partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+ // expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}}
+#endif
+ [PartialI partialMethod];
[PartialI ipartialMethod1]; // no warning
#if defined(WARN_PARTIAL)
// expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
@@ -177,20 +190,23 @@ void partialfun(PartialI* a) {
}
#if defined(WARN_PARTIAL)
- // expected-note@+2 {{'PartialI2' has been explicitly marked partial here}}
+ // expected-note@+2 2 {{'PartialI2' has been explicitly marked partial here}}
#endif
__attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2
@end
#if defined(WARN_PARTIAL)
- // expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'PartialI2' to silence this warning}}
+// expected-warning@+2 {{'PartialI2' is only available on macOS 10.8 or newer}} expected-note@+2 {{annotate 'partialinter1' with an availability attribute to silence}}
#endif
void partialinter1(PartialI2* p) {
}
@class PartialI2;
-void partialinter2(PartialI2* p) { // no warning
+#ifdef WARN_PARTIAL
+// expected-warning@+2 {{'PartialI2' is only available on macOS 10.8 or newer}} expected-note@+2 {{annotate 'partialinter2' with an availability attribute to silence}}
+#endif
+void partialinter2(PartialI2* p) {
}
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
index 59087bdf11..28031997af 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 {{'DEPRECATED' has been explicitly marked deprecated here}}
+@interface DEPRECATED {
@public int ivar;
DEPRECATED *ivar2; // no warning.
}
@@ -98,9 +98,17 @@ __attribute ((deprecated))
@end
@interface DEPRECATED (Category2) // no warning.
+- (id)meth;
@end
-@implementation DEPRECATED (Category2) // expected-warning {{'DEPRECATED' is deprecated}}
+__attribute__((deprecated))
+void depr_function();
+
+@implementation DEPRECATED (Category2) // no warning
+- (id)meth {
+ depr_function(); // no warning.
+ return 0;
+}
@end
@interface NS : DEPRECATED // expected-warning {{'DEPRECATED' is deprecated}}
@@ -121,9 +129,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/attr-ns_returns_retained.m b/test/SemaObjC/attr-ns_returns_retained.m
new file mode 100644
index 0000000000..83397a6556
--- /dev/null
+++ b/test/SemaObjC/attr-ns_returns_retained.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fblocks -verify %s
+
+// rdar://20130079
+
+#if __has_feature(objc_arc)
+__attribute__((ns_returns_retained)) id (^invalidBlockRedecl)(); // expected-note {{previous definition is here}}
+id (^invalidBlockRedecl)(); //expected-error {{redefinition of 'invalidBlockRedecl' with a different type: 'id (^__strong)()' vs 'id ((^__strong))() __attribute__((ns_returns_retained))'}}
+#else
+__attribute__((ns_returns_retained)) id (^invalidBlockRedecl)();
+id (^invalidBlockRedecl)();
+#endif
+
+typedef __attribute__((ns_returns_retained)) id (^blockType)();
+
+typedef __attribute__((ns_returns_retained)) int (^invalidBlockType)(); // expected-warning {{'ns_returns_retained' attribute only applies to functions that return an Objective-C object}}
+
+__attribute__((ns_returns_retained)) int functionDecl(); // expected-warning {{'ns_returns_retained' attribute only applies to functions that return an Objective-C object}}
diff --git a/test/SemaObjC/category-attribute.m b/test/SemaObjC/category-attribute.m
new file mode 100644
index 0000000000..7efe3df00e
--- /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 37df7a6416..d9f954dc47 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/class-unavail-warning.m b/test/SemaObjC/class-unavail-warning.m
index 268d51910b..f7d8f569ca 100644
--- a/test/SemaObjC/class-unavail-warning.m
+++ b/test/SemaObjC/class-unavail-warning.m
@@ -2,7 +2,7 @@
// rdar://9092208
__attribute__((unavailable("not available")))
-@interface MyClass { // expected-note 8 {{'MyClass' has been explicitly marked unavailable here}}
+@interface MyClass { // expected-note 7 {{'MyClass' has been explicitly marked unavailable here}}
@public
void *_test;
MyClass *ivar; // no error.
@@ -28,7 +28,7 @@ __attribute__((unavailable("not available")))
@interface MyClass (Cat2) // no error.
@end
-@implementation MyClass (Cat2) // expected-error {{unavailable}}
+@implementation MyClass (Cat2) // no error.
@end
int main() {
diff --git a/test/SemaObjC/default-synthesize-1.m b/test/SemaObjC/default-synthesize-1.m
index 731aa863e1..573434b3b3 100644
--- a/test/SemaObjC/default-synthesize-1.m
+++ b/test/SemaObjC/default-synthesize-1.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wobjc-missing-property-synthesis -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -Wobjc-missing-property-synthesis -verify -Wno-objc-root-class -triple=x86_64-apple-macos10.10 %s
// rdar://11295716
@interface NSObject
@@ -141,3 +141,17 @@
return _description; // expected-error {{use of undeclared identifier '_description'}}
}
@end
+
+@interface DontWarnOnUnavailable
+
+// No warning expected:
+@property (nonatomic, readonly) int un1 __attribute__((unavailable));
+@property (readwrite) int un2 __attribute__((availability(macos, unavailable)));
+
+@property (readwrite) int un3 __attribute__((availability(ios, unavailable))); // expected-warning {{auto property synthesis is synthesizing property not explicitly synthesized}}
+
+@end
+
+@implementation DontWarnOnUnavailable // expected-note {{detected while default synthesizing properties in class implementation}}
+
+@end
diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m
index dce9edabb9..9a05408aa0 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}}
@@ -173,13 +173,13 @@ typedef NSObject<Fooing> FooObject;
@end
@implementation Okay // expected-warning {{auto property synthesis will not synthesize property 'muahahaha' declared in protocol 'Fooing'}} expected-warning {{auto property synthesis will not synthesize property 'hoho' declared in protocol 'SubFooling'}}
-@end
+@end // expected-note 2 {{add a '@synthesize' directive}}
@interface Fail : FooObject
@end
@implementation Fail // expected-warning {{auto property synthesis will not synthesize property 'muahahaha' declared in protocol 'Fooing'}} expected-warning {{auto property synthesis will not synthesize property 'hoho' declared in protocol 'SubFooling'}}
-@end
+@end // expected-note 2 {{add a '@synthesize' directive}}
// rdar://16089191
@class NSURL;
diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m
index 3f0ae0261d..61ce9317c5 100644
--- a/test/SemaObjC/default-synthesize.m
+++ b/test/SemaObjC/default-synthesize.m
@@ -137,7 +137,7 @@
@end
@implementation MyClass // expected-warning {{auto property synthesis will not synthesize property 'requiredString' declared in protocol 'MyProtocol'}}
-@end
+@end // expected-note {{add a '@synthesize' directive}}
// rdar://18152478
@protocol NSObject @end
diff --git a/test/SemaObjC/diagnose_if.m b/test/SemaObjC/diagnose_if.m
new file mode 100644
index 0000000000..9f281e4252
--- /dev/null
+++ b/test/SemaObjC/diagnose_if.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -verify -fno-builtin
+
+_Static_assert(__has_feature(attribute_diagnose_if_objc), "feature check failed?");
+
+#define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
+
+@interface I
+-(void)meth _diagnose_if(1, "don't use this", "warning"); // expected-note 1{{from 'diagnose_if'}}
+@property (assign) id prop _diagnose_if(1, "don't use this", "warning"); // expected-note 2{{from 'diagnose_if'}}
+@end
+
+void test(I *i) {
+ [i meth]; // expected-warning {{don't use this}}
+ id o1 = i.prop; // expected-warning {{don't use this}}
+ id o2 = [i prop]; // expected-warning {{don't use this}}
+}
diff --git a/test/SemaObjC/flexible-array-arc.m b/test/SemaObjC/flexible-array-arc.m
new file mode 100644
index 0000000000..1490329b18
--- /dev/null
+++ b/test/SemaObjC/flexible-array-arc.m
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class -DNOARC %s
+#ifdef NOARC
+// expected-no-diagnostics
+#endif
+
+@interface RetainableArray {
+ id flexible[];
+#ifndef NOARC
+ // expected-error@-2 {{ARC forbids flexible array members with retainable object type}}
+#endif
+}
+@end
+@implementation RetainableArray
+@end
+
+// Emit diagnostic only if have @implementation.
+@interface RetainableArrayWithoutImpl {
+ id flexible[];
+}
+@end
+
+// With ARC flexible array member objects can be only __unsafe_unretained
+@interface UnsafeUnretainedArray {
+ __unsafe_unretained id flexible[];
+}
+@end
+@implementation UnsafeUnretainedArray
+@end
+
+@interface NotObjCLifetimeTypeArray {
+ char flexible[];
+}
+@end
+@implementation NotObjCLifetimeTypeArray
+@end
diff --git a/test/SemaObjC/flexible-array.m b/test/SemaObjC/flexible-array.m
new file mode 100644
index 0000000000..68e32d851f
--- /dev/null
+++ b/test/SemaObjC/flexible-array.m
@@ -0,0 +1,288 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+
+// # Flexible array member.
+// ## Instance variables only in interface.
+@interface LastIvar {
+ char flexible[];
+}
+@end
+
+@interface NotLastIvar {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+// ## Instance variables in implementation.
+@interface LastIvarInImpl
+@end
+@implementation LastIvarInImpl {
+ char flexible[]; // expected-warning {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}}
+}
+@end
+
+@interface NotLastIvarInImpl
+@end
+@implementation NotLastIvarInImpl {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+ // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+@implementation NotLastIvarInImplWithoutInterface { // expected-warning {{cannot find interface declaration for 'NotLastIvarInImplWithoutInterface'}}
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+ // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+@interface LastIvarInClass_OtherIvarInImpl {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+}
+@end
+@implementation LastIvarInClass_OtherIvarInImpl {
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+// ## Non-instance variables in implementation.
+@interface LastIvarInClass_UnrelatedVarInImpl {
+ char flexible[];
+}
+@end
+@implementation LastIvarInClass_UnrelatedVarInImpl
+int nonIvar;
+@end
+
+// ## Instance variables in class extension.
+@interface LastIvarInExtension
+@end
+@interface LastIvarInExtension() {
+ char flexible[]; // expected-warning {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}}
+}
+@end
+
+@interface NotLastIvarInExtension
+@end
+@interface NotLastIvarInExtension() {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+ // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+@interface LastIvarInClass_OtherIvarInExtension {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+}
+@end
+@interface LastIvarInClass_OtherIvarInExtension() {
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+@interface LastIvarInExtension_OtherIvarInExtension
+@end
+@interface LastIvarInExtension_OtherIvarInExtension() {
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+@interface LastIvarInExtension_OtherIvarInExtension()
+// Extension without ivars to test we see through such extensions.
+@end
+@interface LastIvarInExtension_OtherIvarInExtension() {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+ // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}}
+}
+@end
+
+@interface LastIvarInExtension_OtherIvarInImpl
+@end
+@interface LastIvarInExtension_OtherIvarInImpl() {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+ // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}}
+}
+@end
+@implementation LastIvarInExtension_OtherIvarInImpl {
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+// ## Instance variables in named categories.
+@interface IvarInNamedCategory
+@end
+@interface IvarInNamedCategory(Category) {
+ char flexible[]; // expected-error {{instance variables may not be placed in categories}}
+}
+@end
+
+// ## Synthesized instance variable.
+@interface LastIvarAndProperty {
+ char _flexible[];
+}
+@property char flexible[]; // expected-error {{property cannot have array or function type 'char []'}}
+@end
+
+// ## Synthesize other instance variables.
+@interface LastIvar_ExplicitlyNamedPropertyBackingIvarPreceding {
+ int _elementsCount;
+ char flexible[];
+}
+@property int count;
+@end
+@implementation LastIvar_ExplicitlyNamedPropertyBackingIvarPreceding
+@synthesize count = _elementsCount;
+@end
+
+@interface LastIvar_ImplicitlyNamedPropertyBackingIvarPreceding {
+ int count;
+ char flexible[];
+}
+@property int count;
+@end
+@implementation LastIvar_ImplicitlyNamedPropertyBackingIvarPreceding
+@synthesize count;
+@end
+
+@interface NotLastIvar_ExplicitlyNamedPropertyBackingIvarLast {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+}
+@property int count;
+@end
+@implementation NotLastIvar_ExplicitlyNamedPropertyBackingIvarLast
+@synthesize count = _elementsCount; // expected-note {{next synthesized instance variable is here}}
+@end
+
+@interface NotLastIvar_ImplicitlyNamedPropertyBackingIvarLast {
+ char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}}
+}
+@property int count; // expected-note {{next synthesized instance variable is here}}
+@end
+@implementation NotLastIvar_ImplicitlyNamedPropertyBackingIvarLast
+// Test auto-synthesize.
+//@synthesize count;
+@end
+
+
+// # Variable sized types.
+struct Packet {
+ unsigned int size;
+ char data[];
+};
+
+// ## Instance variables only in interface.
+@interface LastStructIvar {
+ struct Packet flexible;
+}
+@end
+
+@interface NotLastStructIvar {
+ struct Packet flexible; // expected-error {{field 'flexible' with variable sized type 'struct Packet' is not at the end of class}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+// ## Instance variables in implementation.
+@interface LastStructIvarInImpl
+@end
+@implementation LastStructIvarInImpl {
+ struct Packet flexible; // expected-warning {{field 'flexible' with variable sized type 'struct Packet' is not visible to subclasses and can conflict with their instance variables}}
+}
+@end
+
+@interface NotLastStructIvarInImpl
+@end
+@implementation NotLastStructIvarInImpl {
+ struct Packet flexible; // expected-error {{field 'flexible' with variable sized type 'struct Packet' is not at the end of class}}
+ // expected-warning@-1 {{field 'flexible' with variable sized type 'struct Packet' is not visible to subclasses and can conflict with their instance variables}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+@interface LastStructIvarInClass_OtherIvarInImpl {
+ struct Packet flexible; // expected-error {{field 'flexible' with variable sized type 'struct Packet' is not at the end of class}}
+}
+@end
+@implementation LastStructIvarInClass_OtherIvarInImpl {
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+// ## Synthesized instance variable.
+@interface LastSynthesizeStructIvar
+@property int first;
+@property struct Packet flexible; // expected-error {{synthesized property with variable size type 'struct Packet' requires an existing instance variable}}
+@end
+@implementation LastSynthesizeStructIvar
+@end
+
+@interface NotLastSynthesizeStructIvar
+@property struct Packet flexible; // expected-error {{synthesized property with variable size type 'struct Packet' requires an existing instance variable}}
+@property int last;
+@end
+@implementation NotLastSynthesizeStructIvar
+@end
+
+@interface LastStructIvarWithExistingIvarAndSynthesizedProperty {
+ struct Packet _flexible;
+}
+@property struct Packet flexible;
+@end
+@implementation LastStructIvarWithExistingIvarAndSynthesizedProperty
+@end
+
+
+// # Subclasses.
+@interface FlexibleArrayMemberBase {
+ char flexible[]; // expected-note6 {{'flexible' declared here}}
+}
+@end
+
+@interface NoIvarAdditions : FlexibleArrayMemberBase
+@end
+@implementation NoIvarAdditions
+@end
+
+@interface AddedIvarInInterface : FlexibleArrayMemberBase {
+ int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}}
+}
+@end
+
+@interface AddedIvarInImplementation : FlexibleArrayMemberBase
+@end
+@implementation AddedIvarInImplementation {
+ int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}}
+}
+@end
+
+@interface AddedIvarInExtension : FlexibleArrayMemberBase
+@end
+@interface AddedIvarInExtension() {
+ int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}}
+}
+@end
+
+@interface SynthesizedIvar : FlexibleArrayMemberBase
+@property int count;
+@end
+@implementation SynthesizedIvar
+@synthesize count; // expected-warning {{field 'count' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}}
+@end
+
+@interface WarnInSubclassOnlyOnce : FlexibleArrayMemberBase {
+ int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}}
+}
+@end
+@interface WarnInSubclassOnlyOnce() {
+ int laster;
+}
+@end
+@implementation WarnInSubclassOnlyOnce {
+ int lastest;
+}
+@end
+
+@interface AddedIvarInSubSubClass : NoIvarAdditions {
+ int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}}
+}
+@end
diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m
index 91ea2ec4e0..477c4fc383 100644
--- a/test/SemaObjC/foreach.m
+++ b/test/SemaObjC/foreach.m
@@ -55,3 +55,27 @@ void test2(NSObject<NSFastEnumeration> *collection) {
for (obj.prop in collection) { /* expected-error {{selector element is not a valid lvalue}} */
}
}
+
+int cond();
+
+void test3(NSObject<NSFastEnumeration> *a0, NSObject<NSFastEnumeration> *a1) {
+ for (id i in a0) { /* expected-note 2 {{jump enters Objective-C fast enumeration loop}} */
+ for (id j in a1) { /* expected-note 2 {{jump enters Objective-C fast enumeration loop}} */
+ (void)i, (void)j;
+label0:
+ if (cond())
+ goto label1;
+ }
+label1:
+ if (cond())
+ goto label0; /* expected-error {{cannot jump from this goto statement to its label}} */
+ if (cond())
+ goto label2;
+ }
+
+label2:
+ if (cond())
+ goto label0; /* expected-error {{cannot jump from this goto statement to its label}} */
+ if (cond())
+ goto label1; /* expected-error{{cannot jump from this goto statement to its label}} */
+}
diff --git a/test/SemaObjC/forward-protocol-incomplete-impl-warn.m b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
index c235e32316..583bb4dd89 100644
--- a/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
+++ b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
@@ -17,4 +17,4 @@
@implementation IBImageCatalogDocument // expected-warning {{auto property synthesis will not synthesize property 'Prop' declared in protocol 'DVTInvalidation'}} \
// expected-warning {{method 'invalidate' in protocol 'DVTInvalidation' not implemented}}
-@end
+@end // expected-note {{add a '@synthesize' directive}}
diff --git a/test/SemaObjC/illegal-nonarc-bridged-cast.m b/test/SemaObjC/illegal-nonarc-bridged-cast.m
index f3406ef983..23c7b96e37 100644
--- a/test/SemaObjC/illegal-nonarc-bridged-cast.m
+++ b/test/SemaObjC/illegal-nonarc-bridged-cast.m
@@ -1,8 +1,9 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fblocks -Wcast-qual -verify %s
// rdar://10597832
typedef const void *CFTypeRef;
typedef const struct __CFString *CFStringRef;
+@class NSString;
@interface NSString
@end
@@ -18,7 +19,7 @@ NSString *CreateNSString();
void from_cf() {
id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning {{'__bridge_transfer' casts have no effect when not using ARC}}
id obj2 = (__bridge_transfer NSString*)CFCreateString(); // expected-warning {{'__bridge_transfer' casts have no effect when not using ARC}}
- (__bridge int*)CFCreateSomething(); // expected-warning {{expression result unused}}
+ (__bridge int*)CFCreateSomething(); // expected-warning {{expression result unused}} expected-warning {{cast from 'const void *' to 'int *' drops const qualifier}}
id obj3 = (__bridge id)CFGetSomething();
id obj4 = (__bridge NSString*)CFGetString();
}
@@ -41,3 +42,15 @@ void to_cf_ignored(id obj) {
CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // no-warning
CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // no-warning
}
+
+// Check that clang doesn't warn about dropping const from Objective-C object
+// types.
+void test_wcast_qual() {
+ CFStringRef c;
+ NSString *n0 = (NSString *)c;
+ NSString **n1 = (NSString **)&c;
+ const NSString *n2;
+ const NSString **n3;
+ void *p0 = (void *)n2;
+ void **p1 = (void **)n3;
+}
diff --git a/test/SemaObjC/ivar-sem-check-1.m b/test/SemaObjC/ivar-sem-check-1.m
index de038f5487..48e0a54b62 100644
--- a/test/SemaObjC/ivar-sem-check-1.m
+++ b/test/SemaObjC/ivar-sem-check-1.m
@@ -6,14 +6,15 @@ typedef int FOO();
@interface INTF
{
struct F {} JJ;
- int arr[]; // expected-error {{field has incomplete type}}
+ int arr[]; // expected-error {{flexible array member 'arr' with type 'int []' is not at the end of class}}
struct S IC; // expected-error {{field has incomplete type}}
+ // expected-note@-1 {{next instance variable declaration is here}}
struct T { // expected-note {{previous definition is here}}
struct T {} X; // expected-error {{nested redefinition of 'T'}}
}YYY;
FOO BADFUNC; // expected-error {{field 'BADFUNC' declared as a function}}
int kaka; // expected-note {{previous declaration is here}}
int kaka; // expected-error {{duplicate member 'kaka'}}
- char ch[]; // expected-error {{field has incomplete type}}
+ char ch[];
}
@end
diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m
index ad67a34edb..a7f0745ddb 100644
--- a/test/SemaObjC/method-bad-param.m
+++ b/test/SemaObjC/method-bad-param.m
@@ -20,6 +20,12 @@
}
@end
+// Ensure that this function is properly marked as a failure.
+void func_with_bad_call(bar* b, foo* f) {
+ [b cccccc:5]; // expected-warning {{instance method '-cccccc:' not found}}
+ // expected-note@-17 {{receiver is instance of class declared here}}
+}
+
void somefunc(foo x) {} // expected-error {{interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
foo somefunc2() {} // expected-error {{interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
diff --git a/test/SemaObjC/objc-container-subscripting-1.m b/test/SemaObjC/objc-container-subscripting-1.m
index a58a7c3bda..b5ed5a68dd 100644
--- a/test/SemaObjC/objc-container-subscripting-1.m
+++ b/test/SemaObjC/objc-container-subscripting-1.m
@@ -16,8 +16,7 @@ id oldObject = array[10]; // expected-warning {{instance method '-objectAtIndexe
array[10] = 0; // expected-warning {{instance method '-setObject:atIndexedSubscript:' not found (return type defaults to 'id')}}
id<P> p_array;
-oldObject = p_array[10]; // expected-warning {{instance method '-objectAtIndexedSubscript:' not found (return type defaults to 'id')}}
+oldObject = p_array[10]; // expected-error {{expected method to read array element not found on object of type 'id<P>'}}
-p_array[10] = 0; // expected-warning {{instance method '-setObject:atIndexedSubscript:' not found (return type defaults to 'id')}}
+p_array[10] = 0; // expected-error {{expected method to write array element not found on object of type 'id<P>'}}
}
-
diff --git a/test/SemaObjC/objc-container-subscripting-2.m b/test/SemaObjC/objc-container-subscripting-2.m
index 62320fcebb..6e7ee7c40e 100644
--- a/test/SemaObjC/objc-container-subscripting-2.m
+++ b/test/SemaObjC/objc-container-subscripting-2.m
@@ -28,3 +28,22 @@ void test_unused() {
dict[array]; // expected-warning {{container access result unused - container access should not be used for side effects}}
}
+void testQualifiedId(id<P> qualifiedId) {
+ id object = qualifiedId[10]; // expected-error {{expected method to read array element not found on object of type 'id<P>'}}
+ qualifiedId[10] = qualifiedId; // expected-error {{expected method to write array element not found on object of type 'id<P>'}}
+}
+
+void testUnqualifiedId(id unqualId) {
+ id object = unqualId[10];
+ unqualId[10] = object;
+}
+
+@protocol Subscriptable
+- (id)objectAtIndexedSubscript:(size_t)index;
+- (void)setObject:(id)object atIndexedSubscript:(size_t)index;
+@end
+
+void testValidQualifiedId(id<Subscriptable> qualifiedId) {
+ id object = qualifiedId[10];
+ qualifiedId[10] = object;
+}
diff --git a/test/SemaObjC/property-ambiguous-synthesis.m b/test/SemaObjC/property-ambiguous-synthesis.m
index 98f5945074..5c652fa472 100644
--- a/test/SemaObjC/property-ambiguous-synthesis.m
+++ b/test/SemaObjC/property-ambiguous-synthesis.m
@@ -2,7 +2,7 @@
// rdar://13075400
@protocol FooAsID
-@property (copy) id foo; // expected-note 2 {{it could also be property of type 'id' declared here}} \\
+@property (assign) id foo; // expected-note 2 {{it could also be property of type 'id' declared here}} \\
// expected-warning {{property of type 'id' was selected for synthesis}}
@end
diff --git a/test/SemaObjC/property-implement-readonly-with-custom-setter.m b/test/SemaObjC/property-implement-readonly-with-custom-setter.m
new file mode 100644
index 0000000000..7ac1380767
--- /dev/null
+++ b/test/SemaObjC/property-implement-readonly-with-custom-setter.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://34192541
+
+@class NSString;
+
+@protocol MyProtocol
+@property (nonatomic, strong, readonly) NSString *myString;
+@end
+
+@interface MyClass <MyProtocol>
+// Don't warn about this setter:
+@property (nonatomic, strong, setter=setMYString:) NSString *myString;
+
+
+@property (nonatomic, strong, readonly) NSString *overridenInClass; // expected-note {{property declared here}}
+@end
+
+@interface MySubClass: MyClass
+@property (nonatomic, strong, setter=setMYOverride:) NSString *overridenInClass;
+// expected-warning@-1 {{'setter' attribute on property 'overridenInClass' does not match the property inherited from 'MyClass'}}
+@end
diff --git a/test/SemaObjC/property-typecheck-1.m b/test/SemaObjC/property-typecheck-1.m
index 5fb05c8bd3..85e8d4624b 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 9e16b331c2..b667c3c51c 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/suspicious-pragma-pack.m b/test/SemaObjC/suspicious-pragma-pack.m
new file mode 100644
index 0000000000..0befcaa86d
--- /dev/null
+++ b/test/SemaObjC/suspicious-pragma-pack.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -Wpragma-pack-suspicious-include -triple i686-apple-darwin9 -fsyntax-only -I%S/Inputs -verify %s
+
+#pragma pack (push, 1) // expected-note {{previous '#pragma pack' directive that modifies alignment is here}}
+#import "empty.h" // expected-warning {{non-default #pragma pack value changes the alignment of struct or union members in the included file}}
+
+#pragma pack (pop)
diff --git a/test/SemaObjC/typo-correction.m b/test/SemaObjC/typo-correction.m
index f19ec1a1fa..47e0ab0960 100644
--- a/test/SemaObjC/typo-correction.m
+++ b/test/SemaObjC/typo-correction.m
@@ -51,3 +51,23 @@ __attribute__ (( __objc_root_class__ ))
}
@end
+// rdar://problem/33102722
+// Typo correction for a property when it has as correction candidates
+// synthesized ivar and a class name, both at the same edit distance.
+@class TypoCandidate;
+
+__attribute__ (( __objc_root_class__ ))
+@interface PropertyType
+@property int x;
+@end
+
+__attribute__ (( __objc_root_class__ ))
+@interface InterfaceC
+@property(assign) PropertyType *typoCandidate; // expected-note {{'_typoCandidate' declared here}}
+@end
+
+@implementation InterfaceC
+-(void)method {
+ typoCandidate.x = 0; // expected-error {{use of undeclared identifier 'typoCandidate'; did you mean '_typoCandidate'?}}
+}
+@end
diff --git a/test/SemaObjC/unguarded-availability-new.m b/test/SemaObjC/unguarded-availability-new.m
new file mode 100644
index 0000000000..474730f0d3
--- /dev/null
+++ b/test/SemaObjC/unguarded-availability-new.m
@@ -0,0 +1,160 @@
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -xobjective-c++ -DMAC -triple x86_64-apple-macosx10.13 -fblocks -fsyntax-only -verify %s
+
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wunguarded-availability-new -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wno-unguarded-availability-new -DNO_WARNING -fblocks -fsyntax-only -verify %s
+
+// unguarded-availability implies unguarded-availability-new:
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wunguarded-availability -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.11 -Wunguarded-availability -Wno-unguarded-availability-new -DNO_WARNING -DWARN_PREV -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wno-unguarded-availability -DNO_WARNING -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -Wno-unguarded-availability -Wunguarded-availability-new -fblocks -fsyntax-only -verify %s
+
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.13 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-ios11 -DNO_WARNING -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMAC -triple x86_64-apple-macosx10.12 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s
+
+// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios11 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios11 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios11 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DIOS -triple x86_64-apple-ios10.3 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s
+
+// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos11 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos11 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos11 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DTVOS -triple x86_64-apple-tvos10 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s
+
+// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos4 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos4 -D TEST_FUNC_CURRENT -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos4 -D TEST_FUNC_NEXT -DNO_WARNING -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DWATCHOS -triple i386-apple-watchos3 -DWARN_CURRENT -fblocks -fsyntax-only -verify %s
+
+#ifdef MAC
+#define PLATFORM macos
+#define NEXT 10.14
+
+#define AVAILABLE_PREV __attribute__((availability(macos, introduced = 10.12)))
+#define AVAILABLE_CURRENT __attribute__((availability(macos, introduced = 10.13)))
+#define AVAILABLE_NEXT __attribute__((availability(macos, introduced = 10.14)))
+#endif
+
+#ifdef IOS
+#define PLATFORM ios
+#define NEXT 12
+
+#define AVAILABLE_PREV __attribute__((availability(ios, introduced = 10)))
+#define AVAILABLE_CURRENT __attribute__((availability(ios, introduced = 11)))
+#define AVAILABLE_NEXT __attribute__((availability(ios, introduced = 12)))
+#endif
+
+#ifdef TVOS
+#define PLATFORM tvos
+#define NEXT 13
+
+#define AVAILABLE_PREV __attribute__((availability(tvos, introduced = 10)))
+#define AVAILABLE_CURRENT __attribute__((availability(tvos, introduced = 11)))
+#define AVAILABLE_NEXT __attribute__((availability(tvos, introduced = 13)))
+#endif
+
+#ifdef WATCHOS
+#define PLATFORM watchos
+#define NEXT 5
+
+#define AVAILABLE_PREV __attribute__((availability(watchos, introduced = 3)))
+#define AVAILABLE_CURRENT __attribute__((availability(watchos, introduced = 4)))
+#define AVAILABLE_NEXT __attribute__((availability(watchos, introduced = 5)))
+#endif
+
+void previouslyAvailable() AVAILABLE_PREV;
+#ifdef WARN_PREV
+ // expected-note@-2 {{'previouslyAvailable' has been explicitly marked partial here}}
+#endif
+void currentlyAvailable() AVAILABLE_CURRENT;
+#ifdef WARN_CURRENT
+ // expected-note@-2 {{'currentlyAvailable' has been explicitly marked partial here}}
+#endif
+void willBeAvailabile() AVAILABLE_NEXT;
+#ifndef NO_WARNING
+ // expected-note@-2 {{'willBeAvailabile' has been explicitly marked partial here}}
+#endif
+
+#ifdef TEST_FUNC_CURRENT
+#define FUNC_AVAILABLE AVAILABLE_CURRENT
+#endif
+#ifdef TEST_FUNC_NEXT
+#define FUNC_AVAILABLE AVAILABLE_NEXT
+#endif
+#ifndef FUNC_AVAILABLE
+#define FUNC_AVAILABLE
+#endif
+
+typedef int AVAILABLE_NEXT new_int;
+#ifndef NO_WARNING
+ // expected-note@-2 {{'new_int' has been explicitly marked partial here}}
+#endif
+FUNC_AVAILABLE new_int x;
+#ifndef NO_WARNING
+#ifdef MAC
+ // expected-warning@-3 {{'new_int' is only available on macOS 10.14 or newer}} expected-note@-3 {{annotate 'x' with an availability attribute to silence this warning}}
+#endif
+#ifdef IOS
+ // expected-warning@-6 {{'new_int' is only available on iOS 12 or newer}} expected-note@-6 {{annotate 'x' with an availability attribute to silence this warning}}
+#endif
+#ifdef TVOS
+ // expected-warning@-9 {{'new_int' is only available on tvOS 13 or newer}} expected-note@-9 {{annotate 'x' with an availability attribute to silence this warning}}
+#endif
+#ifdef WATCHOS
+ // expected-warning@-12 {{'new_int' is only available on watchOS 5}} expected-note@-12 {{annotate 'x' with an availability attribute to silence this warning}}
+#endif
+#endif
+
+void test() FUNC_AVAILABLE {
+ previouslyAvailable();
+#ifdef WARN_PREV
+#ifdef MAC
+ // expected-warning@-3 {{'previouslyAvailable' is only available on macOS 10.12 or newer}}
+#endif
+ // expected-note@-5 {{enclose 'previouslyAvailable' in an @available check to silence this warning}}
+#endif
+ currentlyAvailable();
+#ifdef WARN_CURRENT
+#ifdef MAC
+ // expected-warning@-3 {{'currentlyAvailable' is only available on macOS 10.13 or newer}}
+#endif
+#ifdef IOS
+ // expected-warning@-6 {{'currentlyAvailable' is only available on iOS 11 or newer}}
+#endif
+#ifdef TVOS
+ // expected-warning@-9 {{'currentlyAvailable' is only available on tvOS 11 or newer}}
+#endif
+#ifdef WATCHOS
+ // expected-warning@-12 {{'currentlyAvailable' is only available on watchOS 4 or newer}}
+#endif
+ // expected-note@-14 {{enclose 'currentlyAvailable' in an @available check to silence this warning}}
+#endif
+ willBeAvailabile();
+#ifndef NO_WARNING
+#ifdef MAC
+ // expected-warning@-3 {{'willBeAvailabile' is only available on macOS 10.14 or newer}}
+#endif
+#ifdef IOS
+ // expected-warning@-6 {{'willBeAvailabile' is only available on iOS 12 or newer}}
+#endif
+#ifdef TVOS
+ // expected-warning@-9 {{'willBeAvailabile' is only available on tvOS 13 or newer}}
+#endif
+#ifdef WATCHOS
+ // expected-warning@-12 {{'willBeAvailabile' is only available on watchOS 5 or newer}}
+#endif
+ // expected-note@-14 {{enclose 'willBeAvailabile' in an @available check to silence this warning}}
+#endif
+ if (@available(PLATFORM NEXT, *))
+ willBeAvailabile(); // OK
+}
+
+#ifdef NO_WARNING
+#ifndef WARN_PREV
+// expected-no-diagnostics
+#endif
+#endif
diff --git a/test/SemaObjC/unguarded-availability.m b/test/SemaObjC/unguarded-availability.m
index 4369a0e329..b34cd0f982 100644
--- a/test/SemaObjC/unguarded-availability.m
+++ b/test/SemaObjC/unguarded-availability.m
@@ -1,16 +1,18 @@
// RUN: %clang_cc1 -triple x86_64-apple-macosx-10.9 -Wunguarded-availability -fblocks -fsyntax-only -verify %s
-// RUN: %clang_cc1 -xobjective-c++ -DOBJCPP -triple x86_64-apple-macosx-10.9 -Wunguarded-availability -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -xobjective-c++ -std=c++11 -DOBJCPP -triple x86_64-apple-macosx-10.9 -Wunguarded-availability -fblocks -fsyntax-only -verify %s
#define AVAILABLE_10_0 __attribute__((availability(macos, introduced = 10.0)))
#define AVAILABLE_10_11 __attribute__((availability(macos, introduced = 10.11)))
#define AVAILABLE_10_12 __attribute__((availability(macos, introduced = 10.12)))
+typedef int AVAILABLE_10_12 new_int; // expected-note + {{marked partial here}}
+
int func_10_11() AVAILABLE_10_11; // expected-note 4 {{'func_10_11' has been explicitly marked partial here}}
#ifdef OBJCPP
-// expected-note@+2 {{marked partial here}}
+// expected-note@+2 6 {{marked partial here}}
#endif
-int func_10_12() AVAILABLE_10_12; // expected-note 5 {{'func_10_12' has been explicitly marked partial here}}
+int func_10_12() AVAILABLE_10_12; // expected-note 7 {{'func_10_12' has been explicitly marked partial here}}
int func_10_0() AVAILABLE_10_0;
@@ -48,7 +50,7 @@ void star_case() {
} else
func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
- if (@available(macos 10.11, *)) {
+ if (@available(macOS 10.11, *)) {
if (@available(ios 8, *)) {
func_10_11();
func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{enclose}}
@@ -70,9 +72,9 @@ void use_typedef() {
}
__attribute__((objc_root_class))
-AVAILABLE_10_11 @interface Class_10_11 {
+AVAILABLE_10_11 @interface Class_10_11 { // expected-note{{annotate 'Class_10_11' with an availability attribute to silence}}
int_10_11 foo;
- int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
+ int_10_12 bar; // expected-warning {{'int_10_12' is only available on macOS 10.12 or newer}}
}
- (void)method1;
- (void)method2;
@@ -125,10 +127,46 @@ void test_blocks() {
};
}
-void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
+void test_params(int_10_12 x); // expected-warning {{'int_10_12' is only available on macOS 10.12 or newer}} expected-note{{annotate 'test_params' with an availability attribute to silence this warning}}
void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn
+void (^topLevelBlockDecl)() = ^ {
+ func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+ if (@available(macos 10.12, *))
+ func_10_12();
+};
+
+AVAILABLE_10_12
+__attribute__((objc_root_class))
+@interface InterWithProp // expected-note 2 {{marked partial here}}
+@property(class) int x;
++ (void) setX: (int)newX AVAILABLE_10_12; // expected-note{{marked partial here}}
+@end
+void test_property(void) {
+ int y = InterWithProp.x; // expected-warning{{'InterWithProp' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+ InterWithProp.x = y; // expected-warning{{'InterWithProp' is only available on macOS 10.12 or newer}} expected-note{{@available}} expected-warning{{'setX:' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+}
+
+__attribute__((objc_root_class))
+@interface Subscriptable
+- (id)objectAtIndexedSubscript:(int)sub AVAILABLE_10_12; // expected-note{{marked partial here}}
+@end
+
+void test_at(Subscriptable *x) {
+ id y = x[42]; // expected-warning{{'objectAtIndexedSubscript:' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+}
+
+void uncheckAtAvailable() {
+ if (@available(macOS 10.12, *) || 0) // expected-warning {{@available does not guard availability here; use if (@available) instead}}
+ func_10_12(); // expected-warning {{'func_10_12' is only available on macOS 10.12 or newer}}
+ // expected-note@-1 {{enclose 'func_10_12' in an @available check to silence this warning}}
+}
+
+void justAtAvailable() {
+ int availability = @available(macOS 10.12, *); // expected-warning {{@available does not guard availability here; use if (@available) instead}}
+}
+
#ifdef OBJCPP
int f(char) AVAILABLE_10_12;
@@ -170,10 +208,106 @@ int instantiate_with_availability_attr() {
}
int instantiate_availability() {
- if (@available(macos 10.12, *))
+ if (@available(macOS 10.12, *))
with_availability_attr<int_10_12>();
else
with_availability_attr<int_10_12>(); // expected-warning{{'with_availability_attr<int>' is only available on macOS 10.11 or newer}} expected-warning{{'int_10_12' is only available on macOS 10.12 or newer}} expected-note 2 {{enclose}}
}
+auto topLevelLambda = [] () {
+ func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+ if (@available(macos 10.12, *))
+ func_10_12();
+};
+
+void functionInFunction() {
+ func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+ struct DontWarnTwice {
+ void f() {
+ func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+ }
+ };
+ void([] () {
+ func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+ });
+ (void)(^ {
+ func_10_12(); // expected-warning{{'func_10_12' is only available on macOS 10.12 or newer}} expected-note{{@available}}
+ });
+}
+
+#endif
+
+struct InStruct { // expected-note{{annotate 'InStruct' with an availability attribute to silence}}
+ new_int mem; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}}
+
+ struct { new_int mem; } anon; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}} expected-note{{annotate anonymous struct with an availability attribute to silence}}
+};
+
+#ifdef OBJCPP
+static constexpr int AVAILABLE_10_12 SomeConstexprValue = 2; // expected-note{{marked partial here}}
+typedef enum { // expected-note{{annotate anonymous enum with an availability attribute}}
+ SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is only available on macOS 10.12 or newer}}
+} SomeEnum;
#endif
+
+@interface InInterface
+-(new_int)meth; // expected-warning{{'new_int' is only available on macOS 10.12 or newer}} expected-note{{annotate 'meth' with an availability attribute}}
+@end
+
+@interface Proper // expected-note{{annotate 'Proper' with an availability attribute}}
+@property (class) new_int x; // expected-warning{{'new_int' is only available}}
+@end
+
+void with_local_struct() {
+ struct local { // expected-note{{annotate 'local' with an availability attribute}}
+ new_int x; // expected-warning{{'new_int' is only available}}
+ };
+}
+
+// rdar://33156429:
+// Avoid the warning on protocol requirements.
+
+AVAILABLE_10_12
+@protocol NewProtocol // expected-note {{'NewProtocol' has been explicitly marked partial here}}
+@end
+
+@protocol ProtocolWithNewProtocolRequirement <NewProtocol> // expected-note {{annotate 'ProtocolWithNewProtocolRequirement' with an availability attribute to silence}}
+
+@property(copy) id<NewProtocol> prop; // expected-warning {{'NewProtocol' is only available on macOS 10.12 or newer}}
+
+@end
+
+@interface BaseClass
+@end
+
+@interface ClassWithNewProtocolRequirement : BaseClass <NewProtocol>
+
+@end
+
+@interface BaseClass (CategoryWithNewProtocolRequirement) <NewProtocol>
+
+@end
+
+typedef enum {
+ AK_Dodo __attribute__((availability(macos, deprecated=10.3))), // expected-note 3 {{marked deprecated here}}
+ AK_Cat __attribute__((availability(macos, introduced=10.4))),
+ AK_CyborgCat __attribute__((availability(macos, introduced=10.12))), // expected-note {{marked partial here}}
+} Animals;
+
+void switchAnimals(Animals a) {
+ switch (a) {
+ case AK_Dodo: break; // expected-warning{{'AK_Dodo' is deprecated}}
+ case AK_Cat: break;
+ case AK_Cat|AK_CyborgCat: break; // expected-warning{{case value not in enum}}
+ case AK_CyborgCat: break; // no warn
+ }
+
+ switch (a) {
+ case AK_Dodo...AK_CyborgCat: // expected-warning {{'AK_Dodo' is depr}}
+ break;
+ }
+
+ (void)AK_Dodo; // expected-warning{{'AK_Dodo' is deprecated}}
+ (void)AK_Cat; // no warning
+ (void)AK_CyborgCat; // expected-warning{{'AK_CyborgCat' is only available on macOS 10.12 or newer}} expected-note {{@available}}
+}
diff --git a/test/SemaObjC/warn-deprecated-implementations.m b/test/SemaObjC/warn-deprecated-implementations.m
index 6e208b5be7..440b2886f0 100644
--- a/test/SemaObjC/warn-deprecated-implementations.m
+++ b/test/SemaObjC/warn-deprecated-implementations.m
@@ -1,9 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdeprecated-implementations -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple=x86_64-apple-macos10.10 -fsyntax-only -Wdeprecated-implementations -verify -Wno-objc-root-class %s
// rdar://8973810
// rdar://12717705
@protocol P
- (void) D __attribute__((deprecated)); // expected-note {{method 'D' declared here}}
+
+- (void) unavailable __attribute__((__unavailable__)); // expected-note {{method 'unavailable' declared here}}
@end
@interface A <P>
@@ -16,8 +18,10 @@
@implementation A
+ (void)F { } // No warning, implementing its own deprecated method
-- (void) D {} // expected-warning {{Implementing deprecated method}}
+- (void) D {} // expected-warning {{implementing deprecated method}}
- (void) E {} // No warning, implementing deprecated method in its class extension.
+
+- (void) unavailable { } // expected-warning {{implementing unavailable metho}}
@end
@interface A(CAT)
@@ -28,15 +32,14 @@
- (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 {{'CL' has been explicitly marked deprecated here}}
+@interface CL // expected-note 2 {{class declared here}}
@end
-@implementation CL // expected-warning {{Implementing deprecated class}}
+@implementation CL // expected-warning {{implementing deprecated class}}
@end
-@implementation CL ( SomeCategory ) // expected-warning {{'CL' is deprecated}} \
- // expected-warning {{Implementing deprecated category}}
+@implementation CL (SomeCategory) // expected-warning {{implementing deprecated category}}
@end
@interface CL_SUB : CL // expected-warning {{'CL' is deprecated}}
@@ -44,13 +47,16 @@ __attribute__((deprecated))
@interface BASE
- (void) B __attribute__((deprecated)); // expected-note {{method 'B' declared here}}
+
++ (void) unavailable __attribute__((availability(macos, unavailable))); // expected-note {{method 'unavailable' declared here}}
@end
@interface SUB : BASE
@end
@implementation SUB
-- (void) B {} // expected-warning {{Implementing deprecated method}}
+- (void) B {} // expected-warning {{implementing deprecated method}}
++ (void) unavailable { } // expected-warning {{implementing unavailable method}}
@end
@interface Test
@@ -65,3 +71,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/SemaObjC/warn-messaging-id.mm b/test/SemaObjC/warn-messaging-id.mm
new file mode 100644
index 0000000000..8112cfa3d5
--- /dev/null
+++ b/test/SemaObjC/warn-messaging-id.mm
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class -Wobjc-messaging-id %s
+
+@interface CallMeMaybe
+
+- (void)doThing:(int)intThing;
+
+@property int thing;
+
+@end
+
+template<typename T>
+void instantiate(const T &x) {
+ [x setThing: 22]; // expected-warning {{messaging unqualified id}}
+}
+
+void fn() {
+ id myObject;
+ [myObject doThing: 10]; // expected-warning {{messaging unqualified id}}
+ [myObject setThing: 11]; // expected-warning {{messaging unqualified id}}
+ instantiate(myObject); // expected-note {{in instantiation}}
+}
diff --git a/test/SemaObjC/x86-method-vector-values.m b/test/SemaObjC/x86-method-vector-values.m
new file mode 100644
index 0000000000..23d07b1b41
--- /dev/null
+++ b/test/SemaObjC/x86-method-vector-values.m
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.10 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.4 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-darwin14 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -triple=i686-apple-ios8 -Wno-objc-root-class %s
+
+// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-macosx10.11 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-darwin15 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -DALLOW -DIOS -triple=i686-apple-ios9 -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-watchos -Wno-objc-root-class %s
+// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-tvos -Wno-objc-root-class %s
+
+// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=x86_64-apple-macosx10.10 -Wno-objc-root-class %s
+
+// rdar://21662309
+
+typedef __attribute__((__ext_vector_type__(3))) float float3;
+
+typedef float __m128 __attribute__((__vector_size__(16)));
+
+struct Aggregate { __m128 v; };
+struct AggregateFloat { float v; };
+
+#define AVAILABLE_MACOS_10_10 __attribute__((availability(macos, introduced = 10.10)))
+#define AVAILABLE_MACOS_10_11 __attribute__((availability(macos, introduced = 10.11)))
+
+#define AVAILABLE_IOS_8 __attribute__((availability(ios, introduced = 8.0)))
+#define AVAILABLE_IOS_9 __attribute__((availability(ios, introduced = 9.0)))
+
+@interface VectorMethods
+
+-(void)takeVector:(float3)v; // there should be no diagnostic at declaration
+-(void)takeM128:(__m128)v;
+
+@end
+
+@implementation VectorMethods
+
+#ifndef ALLOW
+
+-(void)takeVector:(float3)v {
+#ifdef MAC
+ // expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in macOS 10.11}}
+#else
+ // expected-error@-4 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in iOS 9}}
+#endif
+}
+
+-(float3)retVector { // expected-error {{'float3' (vector of 3 'float' values) return type is unsupported}}
+}
+
+-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
+}
+
+-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
+}
+
+-(void)takeVector4:(float3)v AVAILABLE_IOS_8 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
+}
+
+-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
+}
+
+- (__m128)retM128 { // expected-error {{'__m128' (vector of 4 'float' values) return type is unsupported}}
+}
+
+- (void)takeM128:(__m128)v { // expected-error {{'__m128' (vector of 4 'float' values) parameter type is unsupported}}
+}
+
+#else
+
+// expected-no-diagnostics
+
+-(void)takeVector:(float3)v {
+}
+
+-(float3)retVector {
+ return 0;
+}
+
+- (__m128)retM128 {
+ __m128 value;
+ return value;
+}
+
+- (void)takeM128:(__m128)v {
+}
+
+-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 {
+}
+
+- (__m128)retM128_2 AVAILABLE_MACOS_10_10 {
+ __m128 value;
+ return value;
+}
+
+-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // no error
+}
+
+-(void)takeVector4:(float3)v AVAILABLE_IOS_8 {
+}
+
+-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // no error
+}
+
+#ifdef OTHER
+// expected-no-diagnostics
+#endif
+
+#endif
+
+-(void)doStuff:(int)m { // no error
+}
+
+-(struct Aggregate)takesAndRetVectorInAggregate:(struct Aggregate)f { // no error
+ struct Aggregate result;
+ return result;
+}
+
+-(struct AggregateFloat)takesAndRetFloatInAggregate:(struct AggregateFloat)f { // no error
+ struct AggregateFloat result;
+ return result;
+}
+
+
+@end
diff --git a/test/SemaObjCXX/Inputs/nullability-completeness-cferror.h b/test/SemaObjCXX/Inputs/nullability-completeness-cferror.h
new file mode 100644
index 0000000000..4988a7491c
--- /dev/null
+++ b/test/SemaObjCXX/Inputs/nullability-completeness-cferror.h
@@ -0,0 +1,13 @@
+@class NSError;
+
+#pragma clang assume_nonnull begin
+
+#ifdef USE_MUTABLE
+typedef struct __attribute__((objc_bridge_mutable(NSError))) __CFError * CFErrorRef;
+#else
+typedef struct __attribute__((objc_bridge(NSError))) __CFError * CFErrorRef;
+#endif
+
+void func1(CFErrorRef *error);
+
+#pragma clang assume_nonnull end
diff --git a/test/SemaObjCXX/Inputs/nullability-consistency-2.h b/test/SemaObjCXX/Inputs/nullability-consistency-2.h
index 72f22e2ce4..84a1369618 100644
--- a/test/SemaObjCXX/Inputs/nullability-consistency-2.h
+++ b/test/SemaObjCXX/Inputs/nullability-consistency-2.h
@@ -6,9 +6,9 @@ void g2(int (^block)(int, int)); // expected-warning{{block pointer is missing a
void g3(const
id // expected-warning{{missing a nullability type specifier}}
+ volatile
// expected-note@-1 {{insert '_Nullable' if the pointer may be null}}
// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}}
- volatile
* // expected-warning{{missing a nullability type specifier}}
// expected-note@-1 {{insert '_Nullable' if the pointer may be null}}
// expected-note@-2 {{insert '_Nonnull' if the pointer should never be null}}
diff --git a/test/SemaObjCXX/arc-bridged-cast.mm b/test/SemaObjCXX/arc-bridged-cast.mm
index 55cdd3f2c4..b5d57740ee 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-overloading.mm b/test/SemaObjCXX/arc-overloading.mm
index a749417211..3ac9c51293 100644
--- a/test/SemaObjCXX/arc-overloading.mm
+++ b/test/SemaObjCXX/arc-overloading.mm
@@ -199,4 +199,4 @@ class rdar10142572 {
};
id rdar10142572::f() { return 0; } // okay: merged down
-id __attribute__((ns_returns_retained)) rdar10142572::g() { return 0; } // expected-error{{function declared with the ns_returns_retained attribute was previously declared without the ns_returns_retained attribute}}
+id __attribute__((ns_returns_retained)) rdar10142572::g() { return 0; } // expected-error{{function declared with 'ns_returns_retained' attribute was previously declared without the 'ns_returns_retained' attribute}}
diff --git a/test/SemaObjCXX/arc-ptr-comparison.mm b/test/SemaObjCXX/arc-ptr-comparison.mm
new file mode 100644
index 0000000000..8571a81795
--- /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-unavailable-for-weakref.mm b/test/SemaObjCXX/arc-unavailable-for-weakref.mm
index 2a80aebaf8..6528748df3 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/flexible-array.mm b/test/SemaObjCXX/flexible-array.mm
new file mode 100644
index 0000000000..5537876c30
--- /dev/null
+++ b/test/SemaObjCXX/flexible-array.mm
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+
+// Test only flexible array member functionality specific to C++.
+
+union VariableSizeUnion {
+ int s;
+ char c[];
+};
+
+@interface LastUnionIvar {
+ VariableSizeUnion flexible;
+}
+@end
+
+@interface NotLastUnionIvar {
+ VariableSizeUnion flexible; // expected-error {{field 'flexible' with variable sized type 'VariableSizeUnion' is not at the end of class}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
+
+
+class VariableSizeClass {
+public:
+ int s;
+ char c[];
+};
+
+@interface LastClassIvar {
+ VariableSizeClass flexible;
+}
+@end
+
+@interface NotLastClassIvar {
+ VariableSizeClass flexible; // expected-error {{field 'flexible' with variable sized type 'VariableSizeClass' is not at the end of class}}
+ int last; // expected-note {{next instance variable declaration is here}}
+}
+@end
diff --git a/test/SemaObjCXX/interface-return-type.mm b/test/SemaObjCXX/interface-return-type.mm
new file mode 100644
index 0000000000..9fff8610ae
--- /dev/null
+++ b/test/SemaObjCXX/interface-return-type.mm
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+@class NSObject;
+template<typename T> struct C {
+ static T f(); // expected-error {{interface type 'NSObject' cannot be returned by value; did you forget * in 'NSObject'?}}
+};
+int g() { NSObject *x = C<NSObject>::f(); }//expected-error {{no member named 'f' in 'C<NSObject>'}} expected-note {{in instantiation of template class 'C<NSObject>' requested here}}
diff --git a/test/SemaObjCXX/is-base-of.mm b/test/SemaObjCXX/is-base-of.mm
new file mode 100644
index 0000000000..9cf16661b0
--- /dev/null
+++ b/test/SemaObjCXX/is-base-of.mm
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+@interface NSObj
+@end
+
+@interface NSChild : NSObj
+@end
+
+static_assert(__is_base_of(NSObj, NSChild), "");
+static_assert(!__is_base_of(NSChild, NSObj), "");
+
+static_assert(__is_base_of(NSObj, NSObj), "");
+
+static_assert(!__is_base_of(NSObj *, NSChild *), "");
+static_assert(!__is_base_of(NSChild *, NSObj *), "");
+
+static_assert(__is_base_of(const volatile NSObj, NSChild), "");
+static_assert(__is_base_of(NSObj, const volatile NSChild), "");
+
+@class NSForward; // expected-note{{forward declaration of class}}
+
+static_assert(!__is_base_of(NSForward, NSObj), "");
+static_assert(!__is_base_of(NSObj, NSForward), ""); // expected-error{{incomplete type 'NSForward'}}
+
+static_assert(!__is_base_of(id, NSObj), "");
diff --git a/test/SemaObjCXX/noescape.mm b/test/SemaObjCXX/noescape.mm
new file mode 100644
index 0000000000..6c5d9897aa
--- /dev/null
+++ b/test/SemaObjCXX/noescape.mm
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=c++1z %s
+
+typedef void (^BlockTy)();
+
+struct S {
+ int i;
+ void m();
+};
+
+void noescapeFunc0(id, __attribute__((noescape)) BlockTy);
+void noescapeFunc1(id, [[clang::noescape]] BlockTy);
+void noescapeFunc2(__attribute__((noescape)) int *); // expected-note {{previous declaration is here}}
+void noescapeFunc3(__attribute__((noescape)) id);
+void noescapeFunc4(__attribute__((noescape)) int &);
+void noescapeFunc2(int *); // expected-error {{conflicting types for 'noescapeFunc2'}}
+
+void invalidFunc0(int __attribute__((noescape))); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
+void invalidFunc1(int __attribute__((noescape(0)))); // expected-error {{'noescape' attribute takes no arguments}}
+void invalidFunc2(int0 *__attribute__((noescape))); // expected-error {{use of undeclared identifier 'int0'; did you mean 'int'?}}
+void invalidFunc3(__attribute__((noescape)) int (S::*Ty)); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
+void invalidFunc4(__attribute__((noescape)) void (S::*Ty)()); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
+int __attribute__((noescape)) g; // expected-warning {{'noescape' attribute only applies to parameters}}
+
+struct S1 {
+ virtual void m0(int *__attribute__((noescape))); // expected-note {{parameter of overridden method is annotated with __attribute__((noescape))}}
+};
+
+struct S2 : S1 {
+ void m0(int *__attribute__((noescape))) override;
+};
+
+struct S3 : S1 {
+ void m0(int *) override; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
+};
+
+__attribute__((objc_root_class))
+@interface C0
+-(void) m0:(int*)__attribute__((noescape)) p; // expected-note {{parameter of overridden method is annotated with __attribute__((noescape))}}
+@end
+
+@implementation C0
+-(void) m0:(int*)__attribute__((noescape)) p {}
+@end
+
+@interface C1 : C0
+-(void) m0:(int*)__attribute__((noescape)) p;
+@end
+
+@implementation C1 : C0
+-(void) m0:(int*)__attribute__((noescape)) p {}
+@end
+
+@interface C2 : C0
+-(void) m0:(int*) p; // expected-warning {{parameter of overriding method should be annotated with __attribute__((noescape))}}
+@end
+
+@implementation C2 : C0
+-(void) m0:(int*) p {}
+@end
+
+void func0(int *);
+void (*fnptr0)(int *);
+void (*fnptr1)(__attribute__((noescape)) int *);
+template<void (*fn)(int*)> struct S4 {};
+template<void (*fn)(int* __attribute__((noescape)))> struct S5 {};
+
+#if __cplusplus < 201406
+ // expected-note@-4 {{template parameter is declared here}}
+ // expected-note@-4 {{template parameter is declared here}}
+#endif
+
+void test0() {
+ fnptr0 = &func0;
+ fnptr0 = &noescapeFunc2;
+ fnptr1 = &func0; // expected-error {{assigning to 'void (*)(__attribute__((noescape)) int *)' from incompatible type 'void (*)(int *)'}}
+ fnptr1 = &noescapeFunc2;
+ S4<&func0> e0;
+ S4<&noescapeFunc2> e1;
+ S5<&func0> ne0;
+
+#if __cplusplus < 201406
+ // expected-error@-4 {{non-type template argument of type 'void (*)(__attribute__((noescape)) int *)' cannot be converted to a value of type 'void (*)(int *)'}}
+ // expected-error@-4 {{non-type template argument of type 'void (*)(int *)' cannot be converted to a value of type 'void (*)(__attribute__((noescape)) int *)'}}
+#else
+ // expected-error@-6 {{value of type 'void (*)(int *)' is not implicitly convertible to 'void (*)(__attribute__((noescape)) int *)'}}
+#endif
+
+ S5<&noescapeFunc2> ne1;
+}
diff --git a/test/SemaObjCXX/nullability-completeness-cferror.mm b/test/SemaObjCXX/nullability-completeness-cferror.mm
new file mode 100644
index 0000000000..4cea9fba92
--- /dev/null
+++ b/test/SemaObjCXX/nullability-completeness-cferror.mm
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -I %S/Inputs -x objective-c -Wnullability-completeness -Werror -verify %s
+// RUN: %clang_cc1 -fsyntax-only -I %S/Inputs -x objective-c -Wnullability-completeness -Werror -verify -DUSE_MUTABLE %s
+// expected-no-diagnostics
+
+#include "nullability-completeness-cferror.h"
diff --git a/test/SemaObjCXX/objc-weak-type-traits.mm b/test/SemaObjCXX/objc-weak-type-traits.mm
new file mode 100644
index 0000000000..f425f47bd6
--- /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 0000000000..93c6af1aa3
--- /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 bb94d9ed92..018afc9b42 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/SemaObjCXX/pr32725.mm b/test/SemaObjCXX/pr32725.mm
new file mode 100644
index 0000000000..8d7d116325
--- /dev/null
+++ b/test/SemaObjCXX/pr32725.mm
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsyntax-only -verify -x objective-c++ %s -o /dev/null
+// REQUIRES: asserts
+
+struct objc_class {
+ unsigned long long bits;
+};
+typedef struct objc_class *Class;
+static void f(Class c) { (void)(c->bits & RW_HAS_OVERFLOW_REFCOUNT); }
+// expected-error@-1{{use of undeclared identifier 'RW_HAS_OVERFLOW_REFCOUNT}}
diff --git a/test/SemaObjCXX/typo-correction.mm b/test/SemaObjCXX/typo-correction.mm
index 5e33bfb8cb..3f8a082a84 100644
--- a/test/SemaObjCXX/typo-correction.mm
+++ b/test/SemaObjCXX/typo-correction.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wno-objc-root-class
class ClassA {};
@@ -36,3 +36,54 @@ void invalidNameInIvarAndPropertyBase() {
float a = ((InvalidNameInIvarAndPropertyBase*)node)->_a; // expected-error {{use of undeclared identifier 'node'}}
float b = ((InvalidNameInIvarAndPropertyBase*)node)._b; // expected-error {{use of undeclared identifier 'node'}}
}
+
+// rdar://problem/33102722
+// Typo correction for a property when it has as correction candidates
+// synthesized ivar and a class name, both at the same edit distance.
+@class TypoCandidate;
+
+@interface PropertyType : NSObject
+@property int x;
+@end
+
+@interface InterfaceC : NSObject
+@property(assign) PropertyType *typoCandidate; // expected-note {{'_typoCandidate' declared here}}
+@end
+
+@implementation InterfaceC
+-(void)method {
+ typoCandidate.x = 0; // expected-error {{use of undeclared identifier 'typoCandidate'; did you mean '_typoCandidate'?}}
+}
+@end
+
+// rdar://35172419
+// The scope of 'do-while' ends before typo-correction takes place.
+
+struct Mat2 { int rows; };
+
+@implementation ImplNoInt // expected-warning {{cannot find interface declaration for 'ImplNoInt'}}
+
+- (void)typoCorrentInDoWhile {
+ Mat2 tlMat1; // expected-note {{'tlMat1' declared here}}
+ // Create many scopes to exhaust the cache.
+ do {
+ for (int index = 0; index < 2; index++) {
+ if (true) {
+ for (int specialTileType = 1; specialTileType < 5; specialTileType++) {
+ for (int i = 0; i < 10; i++) {
+ for (double scale = 0.95; scale <= 1.055; scale += 0.05) {
+ for (int j = 0; j < 10; j++) {
+ if (1 > 0.9) {
+ for (int sptile = 1; sptile < 5; sptile++) {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } while (tlMat.rows); // expected-error {{use of undeclared identifier 'tlMat'; did you mean 'tlMat1'}}
+}
+
+@end
diff --git a/test/SemaOpenCL/address-spaces.cl b/test/SemaOpenCL/address-spaces.cl
index 7026d1bc08..97dd1f4f90 100644
--- a/test/SemaOpenCL/address-spaces.cl
+++ b/test/SemaOpenCL/address-spaces.cl
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -pedantic -fsyntax-only
__constant int ci = 1;
@@ -7,9 +8,15 @@ __kernel void foo(__global int *gip) {
__local int lj = 2; // expected-error {{'__local' variable cannot have an initializer}}
int *ip;
+#if __OPENCL_C_VERSION__ < 200
ip = gip; // expected-error {{assigning '__global int *' to 'int *' changes address space of pointer}}
ip = &li; // expected-error {{assigning '__local int *' to 'int *' changes address space of pointer}}
ip = &ci; // expected-error {{assigning '__constant int *' to 'int *' changes address space of pointer}}
+#else
+ ip = gip;
+ ip = &li;
+ ip = &ci; // expected-error {{assigning '__constant int *' to '__generic int *' changes address space of pointer}}
+#endif
}
void explicit_cast(global int* g, local int* l, constant int* c, private int* p, const constant int *cc)
@@ -40,3 +47,19 @@ void ok_explicit_casts(global int *g, global int* g2, local int* l, local int* l
l = (local int*) l2;
p = (private int*) p2;
}
+
+__private int func_return_priv(void); //expected-error {{return value cannot be qualified with address space}}
+__global int func_return_global(void); //expected-error {{return value cannot be qualified with address space}}
+__local int func_return_local(void); //expected-error {{return value cannot be qualified with address space}}
+__constant int func_return_constant(void); //expected-error {{return value cannot be qualified with address space}}
+#if __OPENCL_C_VERSION__ >= 200
+__generic int func_return_generic(void); //expected-error {{return value cannot be qualified with address space}}
+#endif
+
+void func_multiple_addr(void) {
+ typedef __private int private_int_t;
+ __local __private int var1; // expected-error {{multiple address spaces specified for type}}
+ __local __private int *var2; // expected-error {{multiple address spaces specified for type}}
+ __local private_int_t var3; // expected-error {{multiple address spaces specified for type}}
+ __local private_int_t *var4; // expected-error {{multiple address spaces specified for type}}
+}
diff --git a/test/SemaOpenCL/arithmetic-conversions.cl b/test/SemaOpenCL/arithmetic-conversions.cl
new file mode 100644
index 0000000000..23103caf85
--- /dev/null
+++ b/test/SemaOpenCL/arithmetic-conversions.cl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=CL1.2
+
+typedef float float2 __attribute__((ext_vector_type(2)));
+typedef long long2 __attribute__((ext_vector_type(2)));
+typedef int int2 __attribute__((ext_vector_type(2)));
+
+kernel void foo1(float2 in, global float2 *out) { *out = in + 0.5;} // expected-error {{scalar operand type has greater rank than the type of the vector element. ('float2' (vector of 2 'float' values) and 'double')}}
+
+kernel void foo2(float2 in, global float2 *out) { *out = 0.5 + in;} // expected-error {{scalar operand type has greater rank than the type of the vector element. ('double' and 'float2' (vector of 2 'float' values))}}
+
+kernel void foo3(float2 in, global float2 *out) { *out = 0.5f + in;}
+
+kernel void foo4(long2 in, global long2 *out) { *out = 5 + in;}
+
+kernel void foo5(float2 in, global float2 *out) {
+ float* f;
+ *out = f + in; // expected-error{{cannot convert between vector and non-scalar values ('float *' and 'float2' (vector of 2 'float' values))}}
+}
+
+kernel void foo6(int2 in, global int2 *out) {
+ int* f;
+ *out = f + in; // expected-error{{cannot convert between vector and non-scalar values ('int *' and 'int2' (vector of 2 'int' values))}}
+}
diff --git a/test/SemaOpenCL/array-init.cl b/test/SemaOpenCL/array-init.cl
new file mode 100644
index 0000000000..d9691d86dd
--- /dev/null
+++ b/test/SemaOpenCL/array-init.cl
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0
+// expected-no-diagnostics
+
+__kernel void k1(queue_t q1, queue_t q2) {
+ queue_t q[] = {q1, q2};
+}
+
+__kernel void k2(read_only pipe int p) {
+ reserve_id_t i1 = reserve_read_pipe(p, 1);
+ reserve_id_t i2 = reserve_read_pipe(p, 1);
+ reserve_id_t i[] = {i1, i2};
+}
+
+event_t create_event();
+__kernel void k3() {
+ event_t e1 = create_event();
+ event_t e2 = create_event();
+ event_t e[] = {e1, e2};
+}
+
diff --git a/test/SemaOpenCL/as_type.cl b/test/SemaOpenCL/as_type.cl
index f0bf4d7dae..ad418097d9 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 0000000000..8208a85c3d
--- /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/atomic-ops.cl b/test/SemaOpenCL/atomic-ops.cl
new file mode 100644
index 0000000000..2ec6cde211
--- /dev/null
+++ b/test/SemaOpenCL/atomic-ops.cl
@@ -0,0 +1,195 @@
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -fsyntax-only -triple=spir64
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -fsyntax-only -triple=amdgcn-amdhsa-amd-opencl
+
+// Basic parsing/Sema tests for __opencl_atomic_*
+
+#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
+#pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable
+
+typedef __INTPTR_TYPE__ intptr_t;
+typedef int int8 __attribute__((ext_vector_type(8)));
+
+typedef enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+typedef enum memory_scope {
+ memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM,
+ memory_scope_work_group = __OPENCL_MEMORY_SCOPE_WORK_GROUP,
+ memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE,
+ memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES,
+#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups)
+ memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP
+#endif
+} memory_scope;
+
+struct S { char c[3]; };
+
+char i8;
+short i16;
+int i32;
+int8 i64;
+
+atomic_int gn;
+void f(atomic_int *i, const atomic_int *ci,
+ atomic_intptr_t *p, atomic_float *d,
+ int *I, const int *CI,
+ intptr_t *P, float *D, struct S *s1, struct S *s2,
+ global atomic_int *i_g, local atomic_int *i_l, private atomic_int *i_p,
+ constant atomic_int *i_c) {
+ __opencl_atomic_init(I, 5); // expected-error {{address argument to atomic operation must be a pointer to _Atomic type ('__generic int *' invalid)}}
+ __opencl_atomic_init(ci, 5); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const __generic atomic_int *' (aka 'const __generic _Atomic(int) *') invalid)}}
+
+ __opencl_atomic_load(0); // expected-error {{too few arguments to function call, expected 3, have 1}}
+ __opencl_atomic_load(0, 0, 0, 0); // expected-error {{too many arguments to function call, expected 3, have 4}}
+ __opencl_atomic_store(0,0,0,0); // expected-error {{address argument to atomic builtin must be a pointer}}
+ __opencl_atomic_store((int *)0, 0, 0, 0); // expected-error {{address argument to atomic operation must be a pointer to _Atomic type ('__generic int *' invalid)}}
+ __opencl_atomic_store(i, 0, memory_order_relaxed, memory_scope_work_group);
+ __opencl_atomic_store(ci, 0, memory_order_relaxed, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const __generic atomic_int *' (aka 'const __generic _Atomic(int) *') invalid)}}
+ __opencl_atomic_store(i_g, 0, memory_order_relaxed, memory_scope_work_group);
+ __opencl_atomic_store(i_l, 0, memory_order_relaxed, memory_scope_work_group);
+ __opencl_atomic_store(i_p, 0, memory_order_relaxed, memory_scope_work_group);
+ __opencl_atomic_store(i_c, 0, memory_order_relaxed, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to non-constant _Atomic type ('__constant atomic_int *' (aka '__constant _Atomic(int) *') invalid)}}
+
+ __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_load(p, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_load(d, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_load(ci, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const __generic atomic_int *' (aka 'const __generic _Atomic(int) *') invalid)}}
+
+ __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_store(p, 1, memory_order_seq_cst, memory_scope_work_group);
+ (int)__opencl_atomic_store(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{operand of type 'void' where arithmetic or pointer type is required}}
+
+ int exchange_1 = __opencl_atomic_exchange(i, 1, memory_order_seq_cst, memory_scope_work_group);
+ int exchange_2 = __opencl_atomic_exchange(I, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to _Atomic}}
+
+ __opencl_atomic_fetch_add(i, 1, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_fetch_add(p, 1, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_fetch_add(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer or pointer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}}
+ __opencl_atomic_fetch_and(i, 1, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_fetch_and(p, 1, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_fetch_and(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to bitwise atomic operation must be a pointer to atomic integer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}}
+
+ __opencl_atomic_fetch_min(i, 1, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_fetch_max(i, 1, memory_order_seq_cst, memory_scope_work_group);
+ __opencl_atomic_fetch_min(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer or pointer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}}
+ __opencl_atomic_fetch_max(d, 1, memory_order_seq_cst, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to atomic integer or pointer ('__generic atomic_float *' (aka '__generic _Atomic(float) *') invalid)}}
+
+ bool cmpexch_1 = __opencl_atomic_compare_exchange_strong(i, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group);
+ bool cmpexch_2 = __opencl_atomic_compare_exchange_strong(p, P, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group);
+ bool cmpexch_3 = __opencl_atomic_compare_exchange_strong(d, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{incompatible pointer types passing '__generic int *' to parameter of type '__generic float *'}}
+ (void)__opencl_atomic_compare_exchange_strong(i, CI, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{passing 'const __generic int *' to parameter of type '__generic int *' discards qualifiers}}
+
+ bool cmpexchw_1 = __opencl_atomic_compare_exchange_weak(i, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group);
+ bool cmpexchw_2 = __opencl_atomic_compare_exchange_weak(p, P, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group);
+ bool cmpexchw_3 = __opencl_atomic_compare_exchange_weak(d, I, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{incompatible pointer types passing '__generic int *' to parameter of type '__generic float *'}}
+ (void)__opencl_atomic_compare_exchange_weak(i, CI, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); // expected-warning {{passing 'const __generic int *' to parameter of type '__generic int *' discards qualifiers}}
+
+ // Pointers to different address spaces are allowed.
+ bool cmpexch_10 = __opencl_atomic_compare_exchange_strong((global atomic_int *)0x308, (constant int *)0x309, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group);
+
+ __opencl_atomic_init(ci, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const __generic atomic_int *' (aka 'const __generic _Atomic(int) *') invalid)}}
+ __opencl_atomic_store(ci, 0, memory_order_release, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const __generic atomic_int *' (aka 'const __generic _Atomic(int) *') invalid)}}
+ __opencl_atomic_load(ci, memory_order_acquire, memory_scope_work_group); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const __generic atomic_int *' (aka 'const __generic _Atomic(int) *') invalid)}}
+
+ __opencl_atomic_init(&gn, 456);
+ __opencl_atomic_init(&gn, (void*)0); // expected-warning{{incompatible pointer to integer conversion passing '__generic void *' to parameter of type 'int'}}
+}
+
+void memory_checks(atomic_int *Ap, int *p, int val) {
+ // non-integer memory order argument is casted to integer type.
+ (void)__opencl_atomic_load(Ap, 1.0f, memory_scope_work_group);
+ float forder;
+ (void)__opencl_atomic_load(Ap, forder, memory_scope_work_group);
+ struct S s;
+ (void)__opencl_atomic_load(Ap, s, memory_scope_work_group); // expected-error {{passing 'struct S' to parameter of incompatible type 'int'}}
+
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_load(Ap, memory_order_acquire, memory_scope_work_group);
+ (void)__opencl_atomic_load(Ap, memory_order_consume, memory_scope_work_group); // expected-error {{use of undeclared identifier 'memory_order_consume'}}
+ (void)__opencl_atomic_load(Ap, memory_order_release, memory_scope_work_group); // expected-warning {{memory order argument to atomic operation is invalid}}
+ (void)__opencl_atomic_load(Ap, memory_order_acq_rel, memory_scope_work_group); // expected-warning {{memory order argument to atomic operation is invalid}}
+ (void)__opencl_atomic_load(Ap, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_store(Ap, val, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_store(Ap, val, memory_order_acquire, memory_scope_work_group); // expected-warning {{memory order argument to atomic operation is invalid}}
+ (void)__opencl_atomic_store(Ap, val, memory_order_release, memory_scope_work_group);
+ (void)__opencl_atomic_store(Ap, val, memory_order_acq_rel, memory_scope_work_group); // expected-warning {{memory order argument to atomic operation is invalid}}
+ (void)__opencl_atomic_store(Ap, val, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_fetch_add(Ap, 1, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_add(Ap, 1, memory_order_acquire, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_add(Ap, 1, memory_order_release, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_add(Ap, 1, memory_order_acq_rel, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_add(Ap, 1, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_init(Ap, val);
+
+ (void)__opencl_atomic_fetch_sub(Ap, val, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_sub(Ap, val, memory_order_acquire, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_sub(Ap, val, memory_order_release, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_sub(Ap, val, memory_order_acq_rel, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_sub(Ap, val, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_fetch_and(Ap, val, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_and(Ap, val, memory_order_acquire, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_and(Ap, val, memory_order_release, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_and(Ap, val, memory_order_acq_rel, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_and(Ap, val, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_fetch_or(Ap, val, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_or(Ap, val, memory_order_acquire, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_or(Ap, val, memory_order_release, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_or(Ap, val, memory_order_acq_rel, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_or(Ap, val, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_fetch_xor(Ap, val, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_xor(Ap, val, memory_order_acquire, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_xor(Ap, val, memory_order_release, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_xor(Ap, val, memory_order_acq_rel, memory_scope_work_group);
+ (void)__opencl_atomic_fetch_xor(Ap, val, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_exchange(Ap, val, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_exchange(Ap, val, memory_order_acquire, memory_scope_work_group);
+ (void)__opencl_atomic_exchange(Ap, val, memory_order_release, memory_scope_work_group);
+ (void)__opencl_atomic_exchange(Ap, val, memory_order_acq_rel, memory_scope_work_group);
+ (void)__opencl_atomic_exchange(Ap, val, memory_order_seq_cst, memory_scope_work_group);
+
+ (void)__opencl_atomic_compare_exchange_strong(Ap, p, val, memory_order_relaxed, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_strong(Ap, p, val, memory_order_acquire, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_strong(Ap, p, val, memory_order_release, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_strong(Ap, p, val, memory_order_acq_rel, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_strong(Ap, p, val, memory_order_seq_cst, memory_order_relaxed, memory_scope_work_group);
+
+ (void)__opencl_atomic_compare_exchange_weak(Ap, p, val, memory_order_relaxed, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_weak(Ap, p, val, memory_order_acquire, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_weak(Ap, p, val, memory_order_release, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_weak(Ap, p, val, memory_order_acq_rel, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_compare_exchange_weak(Ap, p, val, memory_order_seq_cst, memory_order_relaxed, memory_scope_work_group);
+}
+
+void synchscope_checks(atomic_int *Ap, int scope) {
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_work_item); // expected-error{{synchronization scope argument to atomic operation is invalid}}
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_work_group);
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_device);
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_all_svm_devices);
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, memory_scope_sub_group);
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, scope);
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, 10); //expected-error{{synchronization scope argument to atomic operation is invalid}}
+
+ // non-integer memory scope is casted to integer type.
+ float fscope;
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, 1.0f);
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, fscope);
+ struct S s;
+ (void)__opencl_atomic_load(Ap, memory_order_relaxed, s); //expected-error{{passing 'struct S' to parameter of incompatible type 'int'}}
+}
+
+void nullPointerWarning(atomic_int *Ap, int *p, int val) {
+ // The 'expected' pointer shouldn't be NULL.
+ (void)__opencl_atomic_compare_exchange_strong(Ap, (void *)0, val, memory_order_relaxed, memory_order_relaxed, memory_scope_work_group); // expected-warning {{null passed to a callee that requires a non-null argument}}
+}
diff --git a/test/SemaOpenCL/cl20-device-side-enqueue.cl b/test/SemaOpenCL/cl20-device-side-enqueue.cl
index 3e87cfcddf..207fe7d340 100644
--- a/test/SemaOpenCL/cl20-device-side-enqueue.cl
+++ b/test/SemaOpenCL/cl20-device-side-enqueue.cl
@@ -1,12 +1,14 @@
-// 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
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -triple "spir-unknown-unknown" -verify -pedantic -fsyntax-only -DB32 -DQUALS=
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -triple "spir-unknown-unknown" -verify -pedantic -fsyntax-only -DB32 -DQUALS="const volatile"
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -triple "spir64-unknown-unknown" -verify -pedantic -fsyntax-only -Wconversion -DWCONV -DQUALS=
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -triple "spir64-unknown-unknown" -verify -pedantic -fsyntax-only -Wconversion -DWCONV -DQUALS="const volatile"
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;
unsigned flags = 0;
- ndrange_t ndrange;
+ QUALS ndrange_t ndrange;
clk_event_t evt;
clk_event_t event_wait_list;
clk_event_t event_wait_list2[] = {evt, evt};
@@ -17,19 +19,19 @@ kernel void enqueue_kernel_tests() {
return 0;
});
- enqueue_kernel(vptr, flags, ndrange, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected 'queue_t' argument type}}
+ enqueue_kernel(vptr, flags, ndrange, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected 'queue_t' argument type}}
return 0;
});
- enqueue_kernel(default_queue, vptr, ndrange, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected 'kernel_enqueue_flags_t' (i.e. uint) argument type}}
+ enqueue_kernel(default_queue, vptr, ndrange, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected 'kernel_enqueue_flags_t' (i.e. uint) argument type}}
return 0;
});
- enqueue_kernel(default_queue, flags, vptr, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected 'ndrange_t' argument type}}
+ enqueue_kernel(default_queue, flags, vptr, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected 'ndrange_t' argument type}}
return 0;
});
- enqueue_kernel(default_queue, flags, ndrange, vptr); // expected-error{{illegal call to enqueue_kernel, expected block argument}}
+ 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 with parameters are not accepted in this prototype of enqueue_kernel call}}
return 0;
@@ -44,21 +46,21 @@ kernel void enqueue_kernel_tests() {
return 0;
});
- enqueue_kernel(default_queue, flags, ndrange, vptr, &event_wait_list, &evt, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected integer argument type}}
+ enqueue_kernel(default_queue, flags, ndrange, vptr, &event_wait_list, &evt, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected integer argument type}}
return 0;
});
- enqueue_kernel(default_queue, flags, ndrange, 1, vptr, &evt, ^(void) // expected-error{{illegal call to enqueue_kernel, expected 'clk_event_t *' argument type}}
+ enqueue_kernel(default_queue, flags, ndrange, 1, vptr, &evt, ^(void) // expected-error{{illegal call to 'enqueue_kernel', expected 'clk_event_t *' argument type}}
{
return 0;
});
- enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, vptr, ^(void) // expected-error{{illegal call to enqueue_kernel, expected 'clk_event_t *' argument type}}
+ enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, vptr, ^(void) // expected-error{{illegal call to 'enqueue_kernel', expected 'clk_event_t *' argument type}}
{
return 0;
});
- enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, &evt, vptr); // expected-error{{illegal call to enqueue_kernel, expected block argument}}
+ enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, &evt, vptr); // expected-error{{illegal call to 'enqueue_kernel', expected block argument}}
// Testing the third overload type
enqueue_kernel(default_queue, flags, ndrange,
@@ -207,3 +209,35 @@ kernel void work_group_size_tests() {
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}}
}
+
+#pragma OPENCL EXTENSION cl_khr_subgroups : enable
+
+kernel void foo(global int *buf)
+{
+ ndrange_t n;
+ buf[0] = get_kernel_max_sub_group_size_for_ndrange(n, ^(){});
+ buf[0] = get_kernel_max_sub_group_size_for_ndrange(0, ^(){}); // expected-error{{illegal call to 'get_kernel_max_sub_group_size_for_ndrange', expected 'ndrange_t' argument type}}
+ buf[0] = get_kernel_max_sub_group_size_for_ndrange(n, 1); // expected-error{{illegal call to 'get_kernel_max_sub_group_size_for_ndrange', expected block argument type}}
+}
+
+kernel void bar(global int *buf)
+{
+ __private ndrange_t n;
+ buf[0] = get_kernel_sub_group_count_for_ndrange(n, ^(){});
+ buf[0] = get_kernel_sub_group_count_for_ndrange(0, ^(){}); // expected-error{{illegal call to 'get_kernel_sub_group_count_for_ndrange', expected 'ndrange_t' argument type}}
+ buf[0] = get_kernel_sub_group_count_for_ndrange(n, 1); // expected-error{{illegal call to 'get_kernel_sub_group_count_for_ndrange', expected block argument type}}
+}
+
+#pragma OPENCL EXTENSION cl_khr_subgroups : disable
+
+kernel void foo1(global int *buf)
+{
+ ndrange_t n;
+ buf[0] = get_kernel_max_sub_group_size_for_ndrange(n, ^(){}); // expected-error {{use of declaration 'get_kernel_max_sub_group_size_for_ndrange' requires cl_khr_subgroups extension to be enabled}}
+}
+
+kernel void bar1(global int *buf)
+{
+ ndrange_t n;
+ buf[0] = get_kernel_sub_group_count_for_ndrange(n, ^(){}); // expected-error {{use of declaration 'get_kernel_sub_group_count_for_ndrange' requires cl_khr_subgroups extension to be enabled}}
+}
diff --git a/test/SemaOpenCL/clang-builtin-version.cl b/test/SemaOpenCL/clang-builtin-version.cl
index 8574682ab9..270345d86a 100644
--- a/test/SemaOpenCL/clang-builtin-version.cl
+++ b/test/SemaOpenCL/clang-builtin-version.cl
@@ -1,16 +1,16 @@
-// RUN: %clang_cc1 %s -fblocks -verify -pedantic -fsyntax-only -ferror-limit 100
+// RUN: %clang_cc1 %s -fblocks -verify -pedantic-errors -fsyntax-only -ferror-limit 100
// Confirm CL2.0 Clang builtins are not available in earlier versions
kernel void dse_builtins() {
int tmp;
- enqueue_kernel(tmp, tmp, tmp, ^(void) { // expected-warning{{implicit declaration of function 'enqueue_kernel' is invalid in C99}}
+ enqueue_kernel(tmp, tmp, tmp, ^(void) { // expected-error{{implicit declaration of function 'enqueue_kernel' is invalid in OpenCL}}
return;
});
- unsigned size = get_kernel_work_group_size(^(void) { // expected-warning{{implicit declaration of function 'get_kernel_work_group_size' is invalid in C99}}
+ unsigned size = get_kernel_work_group_size(^(void) { // expected-error{{implicit declaration of function 'get_kernel_work_group_size' is invalid in OpenCL}}
return;
});
- size = get_kernel_preferred_work_group_size_multiple(^(void) { // expected-warning{{implicit declaration of function 'get_kernel_preferred_work_group_size_multiple' is invalid in C99}}
+ size = get_kernel_preferred_work_group_size_multiple(^(void) { // expected-error{{implicit declaration of function 'get_kernel_preferred_work_group_size_multiple' is invalid in OpenCL}}
return;
});
}
@@ -18,27 +18,48 @@ kernel void dse_builtins() {
void pipe_builtins() {
int tmp;
- read_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'read_pipe' is invalid in C99}}
- write_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'write_pipe' is invalid in C99}}
+ foo(void); // expected-error{{implicit declaration of function 'foo' is invalid in OpenCL}}
+ // expected-note@-1{{'foo' declared here}}
+ // expected-error@-2{{expected expression}}
+ boo(); // expected-error{{implicit declaration of function 'boo' is invalid in OpenCL}}
+ // expected-note@-1{{did you mean 'foo'?}}
- reserve_read_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'reserve_read_pipe' is invalid in C99}}
- reserve_write_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'reserve_write_pipe' is invalid in C99}}
+ read_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'read_pipe' is invalid in OpenCL}}
+ write_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'write_pipe' is invalid in OpenCL}}
- work_group_reserve_read_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'work_group_reserve_read_pipe' is invalid in C99}}
- work_group_reserve_write_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'work_group_reserve_write_pipe' is invalid in C99}}
+ reserve_read_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'reserve_read_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{'reserve_read_pipe' declared here}}
+ reserve_write_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'reserve_write_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{did you mean 'reserve_read_pipe'?}}
- sub_group_reserve_write_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'sub_group_reserve_write_pipe' is invalid in C99}}
- sub_group_reserve_read_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'sub_group_reserve_read_pipe' is invalid in C99}}
+ work_group_reserve_read_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'work_group_reserve_read_pipe' is invalid in OpenCL}}
+ // expected-note@-1 2{{'work_group_reserve_read_pipe' declared here}}
+ work_group_reserve_write_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'work_group_reserve_write_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{did you mean 'work_group_reserve_read_pipe'?}}
+ // expected-note@-2{{'work_group_reserve_write_pipe' declared here}}
- commit_read_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'commit_read_pipe' is invalid in C99}}
- commit_write_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'commit_write_pipe' is invalid in C99}}
+ sub_group_reserve_write_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'sub_group_reserve_write_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{did you mean 'work_group_reserve_write_pipe'?}}
+ sub_group_reserve_read_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'sub_group_reserve_read_pipe' is invalid in OpenCL}}
- work_group_commit_read_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'work_group_commit_read_pipe' is invalid in C99}}
- work_group_commit_write_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'work_group_commit_write_pipe' is invalid in C99}}
+ commit_read_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'commit_read_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{'commit_read_pipe' declared here}}
+ commit_write_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'commit_write_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{did you mean 'commit_read_pipe'?}}
- sub_group_commit_write_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'sub_group_commit_write_pipe' is invalid in C99}}
- sub_group_commit_read_pipe(tmp, tmp); // expected-warning{{implicit declaration of function 'sub_group_commit_read_pipe' is invalid in C99}}
+ work_group_commit_read_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'work_group_commit_read_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{'work_group_commit_read_pipe' declared here}}
+ // expected-note@-2{{did you mean 'work_group_reserve_read_pipe'?}}
+ work_group_commit_write_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'work_group_commit_write_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{'work_group_commit_write_pipe' declared here}}
+ // expected-note@-2{{did you mean 'work_group_commit_read_pipe'?}}
- get_pipe_num_packets(tmp); // expected-warning{{implicit declaration of function 'get_pipe_num_packets' is invalid in C99}}
- get_pipe_max_packets(tmp); // expected-warning{{implicit declaration of function 'get_pipe_max_packets' is invalid in C99}}
+ sub_group_commit_write_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'sub_group_commit_write_pipe' is invalid in OpenCL}}
+ // expected-note@-1{{did you mean 'work_group_commit_write_pipe'?}}
+ sub_group_commit_read_pipe(tmp, tmp); // expected-error{{implicit declaration of function 'sub_group_commit_read_pipe' is invalid in OpenCL}}
+
+ get_pipe_num_packets(tmp); // expected-error{{implicit declaration of function 'get_pipe_num_packets' is invalid in OpenCL}}
+ // expected-note@-1{{'get_pipe_num_packets' declared here}}
+ get_pipe_max_packets(tmp); // expected-error{{implicit declaration of function 'get_pipe_max_packets' is invalid in OpenCL}}
+ // expected-note@-1{{did you mean 'get_pipe_num_packets'?}}
}
diff --git a/test/SemaOpenCL/cond.cl b/test/SemaOpenCL/cond.cl
index 60f70564d8..851947cd39 100644
--- a/test/SemaOpenCL/cond.cl
+++ b/test/SemaOpenCL/cond.cl
@@ -89,7 +89,7 @@ float2 ntest04(int2 C, int2 X, float2 Y)
float2 ntest05(int2 C, int2 X, float Y)
{
- return C ? X : Y; // expected-error {{cannot convert between vector values of different size ('int2' (vector of 2 'int' values) and 'float')}}
+ return C ? X : Y; // expected-error {{scalar operand type has greater rank than the type of the vector element. ('int2' (vector of 2 'int' values) and 'float'}}
}
char2 ntest06(int2 C, char2 X, char2 Y)
diff --git a/test/SemaOpenCL/extension-begin.cl b/test/SemaOpenCL/extension-begin.cl
index 3393458a89..92ea881432 100644
--- a/test/SemaOpenCL/extension-begin.cl
+++ b/test/SemaOpenCL/extension-begin.cl
@@ -46,7 +46,7 @@ void test_f2(void) {
const struct A test_A_local; // expected-error {{use of type 'struct A' requires my_ext extension to be enabled}}
TypedefOfA test_typedef_A; // expected-error {{use of type 'TypedefOfA' (aka 'struct A') requires my_ext extension to be enabled}}
PointerOfA test_A_pointer; // expected-error {{use of type 'PointerOfA' (aka 'const struct A *') requires my_ext extension to be enabled}}
- f(); // expected-error {{use of declaration requires my_ext extension to be enabled}}
+ f(); // expected-error {{use of declaration 'f' requires my_ext extension to be enabled}}
g(0); // expected-error {{no matching function for call to 'g'}}
// expected-note@-26 {{candidate disabled due to OpenCL extension}}
// expected-note@-22 {{candidate function not viable: requires 0 arguments, but 1 was provided}}
diff --git a/test/SemaOpenCL/extern.cl b/test/SemaOpenCL/extern.cl
deleted file mode 100644
index 66efd70058..0000000000
--- a/test/SemaOpenCL/extern.cl
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 -x cl -cl-opt-disable -cl-std=CL1.2 -emit-llvm -ffake-address-space-map %s -o - -verify | FileCheck %s
-// expected-no-diagnostics
-
-// CHECK: @foo = external addrspace(2) constant float
-extern constant float foo;
-
-kernel void test(global float* buf) {
- buf[0] += foo;
-}
diff --git a/test/SemaOpenCL/func.cl b/test/SemaOpenCL/func.cl
index ea3bab6c51..83c3b4a6bc 100644
--- a/test/SemaOpenCL/func.cl
+++ b/test/SemaOpenCL/func.cl
@@ -1,14 +1,24 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -triple spir-unknown-unknown
// Variadic functions
void vararg_f(int, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
void __vararg_f(int, ...);
typedef void (*vararg_fptr_t)(int, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
+ // expected-error@-1{{pointers to functions are not allowed}}
int printf(__constant const char *st, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
+// Struct type with function pointer field
+typedef struct s
+{
+ void (*f)(struct s *self, int *i); // expected-error{{pointers to functions are not allowed}}
+} s_t;
+
//Function pointer
void foo(void*);
+// Expect no diagnostics for an empty parameter list.
+void bar();
+
void bar()
{
// declaring a function pointer is an error
diff --git a/test/SemaOpenCL/images.cl b/test/SemaOpenCL/images.cl
index f963de4e13..9d6092c8c9 100644
--- a/test/SemaOpenCL/images.cl
+++ b/test/SemaOpenCL/images.cl
@@ -1,9 +1,32 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -pedantic -fsyntax-only
-void img2d_ro(__read_only image2d_t img) {} // expected-note{{passing argument to parameter 'img' here}} expected-note{{passing argument to parameter 'img' here}}
+void img2d_ro(read_only image2d_t); // expected-note 3{{passing argument to parameter here}}
+void img2d_wo(write_only image2d_t); // expected-note 2{{passing argument to parameter here}}
+void img2d_rw(read_write image2d_t); // expected-note 2{{passing argument to parameter here}}
+void img2d_default(image2d_t); // expected-note 2{{passing argument to parameter here}}
-void imgage_access_test(image2d_t img2dro, write_only image2d_t img2dwo, image3d_t img3dro) {
- img2d_ro(img2dro);
- img2d_ro(img2dwo); // expected-error{{passing '__write_only image2d_t' to parameter of incompatible type '__read_only image2d_t'}}
+void imgage_access_test(image2d_t img2dro, image3d_t img3dro) {
+ img2d_ro(img2dro); // read_only = read_only
img2d_ro(img3dro); // expected-error{{passing '__read_only image3d_t' to parameter of incompatible type '__read_only image2d_t'}}
}
+
+kernel void read_only_access_test(read_only image2d_t img) {
+ img2d_ro(img); // read_only = read_only
+ img2d_wo(img); // expected-error {{passing '__read_only image2d_t' to parameter of incompatible type '__write_only image2d_t'}}
+ img2d_rw(img); // expected-error {{passing '__read_only image2d_t' to parameter of incompatible type '__read_write image2d_t'}}
+ img2d_default(img); // read_only = read_only
+}
+
+kernel void write_only_access_test(write_only image2d_t img) {
+ img2d_ro(img); // expected-error {{passing '__write_only image2d_t' to parameter of incompatible type '__read_only image2d_t'}}
+ img2d_wo(img); // write_only = write_only
+ img2d_rw(img); // expected-error {{passing '__write_only image2d_t' to parameter of incompatible type '__read_write image2d_t'}}
+ img2d_default(img); // expected-error {{passing '__write_only image2d_t' to parameter of incompatible type '__read_only image2d_t'}}
+}
+
+kernel void read_write_access_test(read_write image2d_t img) {
+ img2d_ro(img); // expected-error {{passing '__read_write image2d_t' to parameter of incompatible type '__read_only image2d_t'}}
+ img2d_wo(img); // expected-error {{passing '__read_write image2d_t' to parameter of incompatible type '__write_only image2d_t'}}
+ img2d_rw(img); //read_write = read_write
+ img2d_default(img); // expected-error {{passing '__read_write image2d_t' to parameter of incompatible type '__read_only image2d_t'}}
+}
diff --git a/test/Sema/invalid-assignment-constant-address-space.c b/test/SemaOpenCL/invalid-assignment-constant-address-space.cl
index 77d6b331c2..32917c493c 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 89bf03264e..5d6dc380a3 100644
--- a/test/SemaOpenCL/invalid-block.cl
+++ b/test/SemaOpenCL/invalid-block.cl
@@ -81,3 +81,14 @@ kernel void f7() {
};
return;
}
+
+// Taking address of a capture is not allowed
+int g;
+kernel void f8(int a1) {
+ int a2;
+ void (^bl)(void) = ^(void) {
+ &g; //expected-warning{{expression result unused}}
+ &a1; //expected-error{{taking address of a capture is not allowed}}
+ &a2; //expected-error{{taking address of a capture is not allowed}}
+ };
+}
diff --git a/test/SemaOpenCL/invalid-kernel-attrs.cl b/test/SemaOpenCL/invalid-kernel-attrs.cl
index cedbb06646..1f1359ccee 100644
--- a/test/SemaOpenCL/invalid-kernel-attrs.cl
+++ b/test/SemaOpenCL/invalid-kernel-attrs.cl
@@ -33,3 +33,7 @@ void f_kernel_image2d_t( kernel image2d_t image ) { // expected-error {{'kernel'
kernel __attribute__((reqd_work_group_size(1,2,0))) void kernel11(){} // expected-error {{'reqd_work_group_size' attribute must be greater than 0}}
kernel __attribute__((reqd_work_group_size(1,0,2))) void kernel12(){} // expected-error {{'reqd_work_group_size' attribute must be greater than 0}}
kernel __attribute__((reqd_work_group_size(0,1,2))) void kernel13(){} // expected-error {{'reqd_work_group_size' attribute must be greater than 0}}
+
+__attribute__((intel_reqd_sub_group_size(8))) void kernel14(){} // expected-error {{attribute 'intel_reqd_sub_group_size' can only be applied to a kernel}}
+kernel __attribute__((intel_reqd_sub_group_size(0))) void kernel15(){} // expected-error {{'intel_reqd_sub_group_size' attribute must be greater than 0}}
+kernel __attribute__((intel_reqd_sub_group_size(8))) __attribute__((intel_reqd_sub_group_size(16))) void kernel16() {} //expected-warning{{attribute 'intel_reqd_sub_group_size' is already applied with different parameters}}
diff --git a/test/SemaOpenCL/invalid-pipe-builtin-cl2.0.cl b/test/SemaOpenCL/invalid-pipe-builtin-cl2.0.cl
index 386c6b6c74..619b359c7a 100644
--- a/test/SemaOpenCL/invalid-pipe-builtin-cl2.0.cl
+++ b/test/SemaOpenCL/invalid-pipe-builtin-cl2.0.cl
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 -cl-ext=+cl_khr_subgroups
+
+#pragma OPENCL EXTENSION cl_khr_subgroups : enable
void test1(read_only pipe int p, global int* ptr){
int tmp;
diff --git a/test/SemaOpenCL/invalid-pipes-cl2.0.cl b/test/SemaOpenCL/invalid-pipes-cl2.0.cl
index 5db953108b..463fd3d0da 100644
--- a/test/SemaOpenCL/invalid-pipes-cl2.0.cl
+++ b/test/SemaOpenCL/invalid-pipes-cl2.0.cl
@@ -3,6 +3,11 @@
global pipe int gp; // expected-error {{type '__global read_only pipe int' can only be used as a function parameter in OpenCL}}
global reserve_id_t rid; // expected-error {{the '__global reserve_id_t' type cannot be used to declare a program scope variable}}
+extern pipe write_only int get_pipe(); // expected-error {{type '__global write_only pipe int (void)' can only be used as a function parameter in OpenCL}}
+
+kernel void test_invalid_reserved_id(reserve_id_t ID) { // expected-error {{'reserve_id_t' cannot be used as the type of a kernel parameter}}
+}
+
void test1(pipe int *p) {// expected-error {{pipes packet types cannot be of reference type}}
}
void test2(pipe p) {// expected-error {{missing actual type specifier for pipe}}
diff --git a/test/SemaOpenCL/overload_addrspace_resolution.cl b/test/SemaOpenCL/overload_addrspace_resolution.cl
deleted file mode 100644
index c7cf5fcb8d..0000000000
--- a/test/SemaOpenCL/overload_addrspace_resolution.cl
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clang_cc1 -cl-std=CL2.0 -emit-llvm -o - -triple x86_64-unknown-unknown %s | FileCheck %s
-
-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);
-
-void kernel ker() {
- 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: call void @_Z3fooPU8CLglobaliS0_(i32* undef, i32* undef)
- foo(a, b);
- // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef)
- foo(b, c);
- // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef)
- foo(a, d);
-
- // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef)
- bar(gengen, genloc);
- // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef)
- bar(gengen, genglob);
- // CHECK: call void @_Z3barPU8CLglobalPU9CLgenericiS2_(i32** undef, i32** undef)
- bar(genglob, genglob);
-}
diff --git a/test/SemaOpenCL/sampler_t.cl b/test/SemaOpenCL/sampler_t.cl
index c87b6da7c7..4d68dd20a1 100644
--- a/test/SemaOpenCL/sampler_t.cl
+++ b/test/SemaOpenCL/sampler_t.cl
@@ -9,7 +9,8 @@
constant sampler_t glb_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
constant sampler_t glb_smp2; // expected-error{{variable in constant address space must be initialized}}
-global sampler_t glb_smp3 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST; // expected-error{{sampler type cannot be used with the __local and __global address space qualifiers}}
+global sampler_t glb_smp3 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST; // expected-error{{sampler type cannot be used with the __local and __global address space qualifiers}} expected-error {{global sampler requires a const or constant address space qualifier}}
+const global sampler_t glb_smp3_const = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR; // expected-error{{sampler type cannot be used with the __local and __global address space qualifiers}}
constant sampler_t glb_smp4 = 0;
#ifdef CHECK_SAMPLER_VALUE
@@ -30,7 +31,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}}
@@ -38,6 +39,11 @@ constant struct sampler_s {
sampler_t bad(void); //expected-error{{declaring function return value of type 'sampler_t' is not allowed}}
+sampler_t global_nonconst_smp = 0; // expected-error {{global sampler requires a const or constant address space qualifier}}
+
+const sampler_t glb_smp10 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
+const constant sampler_t glb_smp11 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
+
void kernel ker(sampler_t argsmp) {
local sampler_t smp; // expected-error{{sampler type cannot be used with the __local and __global address space qualifiers}}
const sampler_t const_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
@@ -65,7 +71,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/storageclass-cl20.cl b/test/SemaOpenCL/storageclass-cl20.cl
index 1eba64b44c..581701d2a6 100644
--- a/test/SemaOpenCL/storageclass-cl20.cl
+++ b/test/SemaOpenCL/storageclass-cl20.cl
@@ -1,19 +1,41 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0
-static constant int G1 = 0;
int G2 = 0;
global int G3 = 0;
local int G4 = 0; // expected-error{{program scope variable must reside in global or constant address space}}
-void kernel foo() {
- static int S1 = 5;
- static global int S2 = 5;
- static private int S3 = 5; // expected-error{{static local variable must reside in global or constant address space}}
+static float g_implicit_static_var = 0;
+static constant float g_constant_static_var = 0;
+static global float g_global_static_var = 0;
+static local float g_local_static_var = 0; // expected-error {{program scope variable must reside in global or constant address space}}
+static private float g_private_static_var = 0; // expected-error {{program scope variable must reside in global or constant address space}}
+static generic float g_generic_static_var = 0; // expected-error {{program scope variable must reside in global or constant address space}}
+
+extern float g_implicit_extern_var;
+extern constant float g_constant_extern_var;
+extern global float g_global_extern_var;
+extern local float g_local_extern_var; // expected-error {{extern variable must reside in global or constant address space}}
+extern private float g_private_extern_var; // expected-error {{extern variable must reside in global or constant address space}}
+extern generic float g_generic_extern_var; // expected-error {{extern variable must reside in global or constant address space}}
+void kernel foo() {
constant int L1 = 0;
local int L2;
- global int L3; // expected-error{{function scope variable cannot be declared in global address space}}
+ global int L3; // expected-error{{function scope variable cannot be declared in global address space}}
+ generic int L4; // expected-error{{automatic variable qualified with an invalid address space}}
+ __attribute__((address_space(100))) int L5; // expected-error{{automatic variable qualified with an invalid address space}}
+
+ static float l_implicit_static_var = 0;
+ static constant float l_constant_static_var = 0;
+ static global float l_global_static_var = 0;
+ static local float l_local_static_var = 0; // expected-error {{static local variable must reside in global or constant address space}}
+ static private float l_private_static_var = 0; // expected-error {{static local variable must reside in global or constant address space}}
+ static generic float l_generic_static_var = 0; // expected-error {{static local variable must reside in global or constant address space}}
- extern global int G5;
- extern int G6; // expected-error{{extern variable must reside in global or constant address space}}
+ extern float l_implicit_extern_var;
+ extern constant float l_constant_extern_var;
+ extern global float l_global_extern_var;
+ extern local float l_local_extern_var; // expected-error {{extern variable must reside in global or constant address space}}
+ extern private float l_private_extern_var; // expected-error {{extern variable must reside in global or constant address space}}
+ extern generic float l_generic_extern_var; // expected-error {{extern variable must reside in global or constant address space}}
}
diff --git a/test/SemaOpenCL/storageclass.cl b/test/SemaOpenCL/storageclass.cl
index a93f8244dc..cbcb94509b 100644
--- a/test/SemaOpenCL/storageclass.cl
+++ b/test/SemaOpenCL/storageclass.cl
@@ -5,7 +5,21 @@ constant int G2 = 0;
int G3 = 0; // expected-error{{program scope variable must reside in constant address space}}
global int G4 = 0; // expected-error{{program scope variable must reside in constant address space}}
-void kernel foo() {
+static float g_implicit_static_var = 0; // expected-error {{program scope variable must reside in constant address space}}
+static constant float g_constant_static_var = 0;
+static global float g_global_static_var = 0; // expected-error {{program scope variable must reside in constant address space}}
+static local float g_local_static_var = 0; // expected-error {{program scope variable must reside in constant address space}}
+static private float g_private_static_var = 0; // expected-error {{program scope variable must reside in constant address space}}
+static generic float g_generic_static_var = 0; // expected-error{{OpenCL version 1.2 does not support the 'generic' type qualifier}} // expected-error {{program scope variable must reside in constant address space}}
+
+extern float g_implicit_extern_var; // expected-error {{extern variable must reside in constant address space}}
+extern constant float g_constant_extern_var;
+extern global float g_global_extern_var; // expected-error {{extern variable must reside in constant address space}}
+extern local float g_local_extern_var; // expected-error {{extern variable must reside in constant address space}}
+extern private float g_private_extern_var; // expected-error {{extern variable must reside in constant address space}}
+extern generic float g_generic_extern_var; // expected-error{{OpenCL version 1.2 does not support the 'generic' type qualifier}} // expected-error {{extern variable must reside in constant address space}}
+
+void kernel foo(int x) {
// static is not allowed at local scope before CL2.0
static int S1 = 5; // expected-error{{variables in function scope cannot be declared static}}
static constant int S2 = 5; // expected-error{{variables in function scope cannot be declared static}}
@@ -13,20 +27,49 @@ void kernel foo() {
constant int L1 = 0;
local int L2;
- auto int L3 = 7; // expected-error{{OpenCL version 1.2 does not support the 'auto' storage class specifier}}
- global int L4; // expected-error{{function scope variable cannot be declared in global address space}}
+ if (true) {
+ local int L1; // expected-error {{variables in the local address space can only be declared in the outermost scope of a kernel function}}
+ constant int L1 = 42; // expected-error {{variables in the constant address space can only be declared in the outermost scope of a kernel function}}
+ }
+
+ auto int L3 = 7; // expected-error{{OpenCL version 1.2 does not support the 'auto' storage class specifier}}
+ global int L4; // expected-error{{function scope variable cannot be declared in global address space}}
+ __attribute__((address_space(100))) int L5; // expected-error{{automatic variable qualified with an invalid address space}}
+
+ constant int L6 = x; // expected-error {{initializer element is not a compile-time constant}}
+ global int *constant L7 = &G4;
+ private int *constant L8 = &x; // expected-error {{initializer element is not a compile-time constant}}
+ constant int *constant L9 = &L1;
+ local int *constant L10 = &L2; // expected-error {{initializer element is not a compile-time constant}}
}
static void kernel bar() { // expected-error{{kernel functions cannot be declared static}}
}
void f() {
- constant int L1 = 0; // expected-error{{non-kernel function variable cannot be declared in constant address space}}
- local int L2; // expected-error{{non-kernel function variable cannot be declared in local address space}}
+ constant int L1 = 0; // expected-error{{non-kernel function variable cannot be declared in constant address space}}
+ local int L2; // expected-error{{non-kernel function variable cannot be declared in local address space}}
+ global int L3; // expected-error{{function scope variable cannot be declared in global address space}}
+ __attribute__((address_space(100))) int L4; // expected-error{{automatic variable qualified with an invalid address space}}
+
{
- constant int L1 = 0; // expected-error{{non-kernel function variable cannot be declared in constant address space}}
- local int L2; // expected-error{{non-kernel function variable cannot be declared in local address space}}
+ constant int L1 = 0; // expected-error{{non-kernel function variable cannot be declared in constant address space}}
+ local int L2; // expected-error{{non-kernel function variable cannot be declared in local address space}}
+ global int L3; // expected-error{{function scope variable cannot be declared in global address space}}
+ __attribute__((address_space(100))) int L4; // expected-error{{automatic variable qualified with an invalid address space}}
}
- global int L3; // expected-error{{function scope variable cannot be declared in global address space}}
- extern constant float L4;
+
+ static float l_implicit_static_var = 0; // expected-error {{variables in function scope cannot be declared static}}
+ static constant float l_constant_static_var = 0; // expected-error {{variables in function scope cannot be declared static}}
+ static global float l_global_static_var = 0; // expected-error {{variables in function scope cannot be declared static}}
+ static local float l_local_static_var = 0; // expected-error {{variables in function scope cannot be declared static}}
+ static private float l_private_static_var = 0; // expected-error {{variables in function scope cannot be declared static}}
+ static generic float l_generic_static_var = 0; // expected-error{{OpenCL version 1.2 does not support the 'generic' type qualifier}} // expected-error {{variables in function scope cannot be declared static}}
+
+ extern float l_implicit_extern_var; // expected-error {{extern variable must reside in constant address space}}
+ extern constant float l_constant_extern_var;
+ extern global float l_global_extern_var; // expected-error {{extern variable must reside in constant address space}}
+ extern local float l_local_extern_var; // expected-error {{extern variable must reside in constant address space}}
+ extern private float l_private_extern_var; // expected-error {{extern variable must reside in constant address space}}
+ extern generic float l_generic_extern_var; // expected-error{{OpenCL version 1.2 does not support the 'generic' type qualifier}} // expected-error {{extern variable must reside in constant address space}}
}
diff --git a/test/SemaOpenCL/to_addr_builtin.cl b/test/SemaOpenCL/to_addr_builtin.cl
index a145626cfc..70956f007a 100644
--- a/test/SemaOpenCL/to_addr_builtin.cl
+++ b/test/SemaOpenCL/to_addr_builtin.cl
@@ -10,7 +10,7 @@ void test(void) {
glob = to_global(glob, loc);
#if __OPENCL_C_VERSION__ < CL_VERSION_2_0
- // expected-warning@-2{{implicit declaration of function 'to_global' is invalid in C99}}
+ // expected-warning@-2{{implicit declaration of function 'to_global' is invalid in OpenCL}}
// expected-warning@-3{{incompatible integer to pointer conversion assigning to '__global int *' from 'int'}}
#else
// expected-error@-5{{invalid number of arguments to function: 'to_global'}}
diff --git a/test/SemaOpenCL/types.cl b/test/SemaOpenCL/types.cl
new file mode 100644
index 0000000000..dc14800f35
--- /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_conv_invalid.cl b/test/SemaOpenCL/vector_conv_invalid.cl
index 90cec26a60..e32d84fd6a 100644
--- a/test/SemaOpenCL/vector_conv_invalid.cl
+++ b/test/SemaOpenCL/vector_conv_invalid.cl
@@ -5,10 +5,18 @@ typedef int int4 __attribute((ext_vector_type(4)));
typedef int int3 __attribute((ext_vector_type(3)));
typedef unsigned uint3 __attribute((ext_vector_type(3)));
-void vector_conv_invalid() {
+void vector_conv_invalid(const global int4 *const_global_ptr) {
uint4 u = (uint4)(1);
int4 i = u; // expected-error{{initializing 'int4' (vector of 4 'int' values) with an expression of incompatible type 'uint4' (vector of 4 'unsigned int' values)}}
int4 e = (int4)u; // expected-error{{invalid conversion between ext-vector type 'int4' (vector of 4 'int' values) and 'uint4' (vector of 4 'unsigned int' values)}}
uint3 u4 = (uint3)u; // expected-error{{invalid conversion between ext-vector type 'uint3' (vector of 3 'unsigned int' values) and 'uint4' (vector of 4 'unsigned int' values)}}
+
+ e = (const int4)i;
+ e = (constant int4)i;
+ e = (private int4)i;
+
+ private int4 *private_ptr = (const private int4 *)const_global_ptr; // expected-error{{casting 'const __global int4 *' to type 'const int4 *' changes address space of pointer}}
+ global int4 *global_ptr = const_global_ptr; // expected-warning {{initializing '__global int4 *' with an expression of type 'const __global int4 *' discards qualifiers}}
+ global_ptr = (global int4 *)const_global_ptr;
}
diff --git a/test/SemaOpenCL/vector_literals_invalid.cl b/test/SemaOpenCL/vector_literals_invalid.cl
index e4e23cd85f..4e502aad3b 100644
--- a/test/SemaOpenCL/vector_literals_invalid.cl
+++ b/test/SemaOpenCL/vector_literals_invalid.cl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify %s
typedef __attribute__(( ext_vector_type(4) )) float float4;
typedef __attribute__(( ext_vector_type(4) )) int int4;
@@ -10,4 +10,5 @@ void vector_literals_invalid()
int4 b = (int4)(1,2,3,4,5); // expected-error{{excess elements in vector}}
((float4)(1.0f))++; // expected-error{{cannot increment value of type 'float4'}}
int8 d = (int8)(a,(float4)(1)); // expected-error{{initializing 'int' with an expression of incompatible type 'float4'}}
+ ((int4)(0)).x = 8; // expected-error{{expression is not assignable}}
}
diff --git a/test/SemaOpenCL/vector_swizzle_length.cl b/test/SemaOpenCL/vector_swizzle_length.cl
new file mode 100644
index 0000000000..4dbb5bd76e
--- /dev/null
+++ b/test/SemaOpenCL/vector_swizzle_length.cl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -x cl %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/address_space-dependent.cpp b/test/SemaTemplate/address_space-dependent.cpp
new file mode 100644
index 0000000000..f3d2f3c15d
--- /dev/null
+++ b/test/SemaTemplate/address_space-dependent.cpp
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -x c++ -std=c++14 -fsyntax-only -verify %s
+
+template <int I, int J, int K>
+void car() {
+ int __attribute__((address_space(I))) __attribute__((address_space(J))) * Y; // expected-error {{multiple address spaces specified for type}}
+ int *__attribute__((address_space(I))) __attribute__((address_space(J))) * Z; // expected-error {{multiple address spaces specified for type}}
+
+ __attribute__((address_space(I))) int local; // expected-error {{automatic variable qualified with an address space}}
+ __attribute__((address_space(J))) int array[5]; // expected-error {{automatic variable qualified with an address space}}
+ __attribute__((address_space(I))) int arrarr[5][5]; // expected-error {{automatic variable qualified with an address space}}
+
+ __attribute__((address_space(J))) * x; // expected-error {{C++ requires a type specifier for all declarations}}
+
+ __attribute__((address_space(I))) float *B;
+
+ typedef __attribute__((address_space(J))) int AS2Int;
+ struct HasASFields {
+ AS2Int typedef_as_field; // expected-error {{field may not be qualified with an address space}}
+ };
+
+ struct _st {
+ int x, y;
+ } s __attribute((address_space(I))) = {1, 1};
+}
+
+template <int I>
+struct HasASTemplateFields {
+ __attribute__((address_space(I))) int as_field; // expected-error {{field may not be qualified with an address space}}
+};
+
+template <int I, int J>
+void foo(__attribute__((address_space(I))) float *a, // expected-note {{candidate template ignored: substitution failure [with I = 1, J = 2]: parameter may not be qualified with an address space}}
+ __attribute__((address_space(J))) float b) {
+ *a = 5.0f + b;
+}
+
+template void foo<1, 2>(float *, float); // expected-error {{explicit instantiation of 'foo' does not refer to a function template, variable template, member function, member class, or static data member}}
+
+template <int I>
+void neg() {
+ __attribute__((address_space(I))) int *bounds; // expected-error {{address space is negative}}
+}
+
+template <long int I>
+void tooBig() {
+ __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388598)}}
+}
+
+template <long int I>
+void correct() {
+ __attribute__((address_space(I))) int *bounds;
+}
+
+template <int I, int J>
+char *cmp(__attribute__((address_space(I))) char *x, __attribute__((address_space(J))) char *y) {
+ return x < y ? x : y; // expected-error {{comparison of distinct pointer types ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *')}}
+}
+
+typedef void ft(void);
+
+template <int I>
+struct fooFunction {
+ __attribute__((address_space(I))) void **const base = 0;
+
+ void *get_0(void) {
+ return base[0]; // expected-error {{cannot initialize return object of type 'void *' with an lvalue of type '__attribute__((address_space(1))) void *}}
+ }
+
+ __attribute__((address_space(I))) ft qf; // expected-error {{function type may not be qualified with an address space}}
+ __attribute__((address_space(I))) char *test3_val;
+
+ void test3(void) {
+ extern void test3_helper(char *p); // expected-note {{passing argument to parameter 'p' here}}
+ test3_helper(test3_val); // expected-error {{cannot initialize a parameter of type 'char *' with an lvalue of type '__attribute__((address_space(1))) char *'}}
+ }
+};
+
+template <typename T, int N>
+int GetAddressSpaceValue(T __attribute__((address_space(N))) * p) {
+ return N;
+}
+
+template <unsigned A> int __attribute__((address_space(A))) *same_template();
+template <unsigned B> int __attribute__((address_space(B))) *same_template();
+void test_same_template() { (void) same_template<0>(); }
+
+template <unsigned A> int __attribute__((address_space(A))) *different_template(); // expected-note {{candidate function [with A = 0]}}
+template <unsigned B> int __attribute__((address_space(B+1))) *different_template(); // expected-note {{candidate function [with B = 0]}}
+void test_different_template() { (void) different_template<0>(); } // expected-error {{call to 'different_template' is ambiguous}}
+
+template <typename T> struct partial_spec_deduce_as;
+template <typename T, unsigned AS>
+struct partial_spec_deduce_as <__attribute__((address_space(AS))) T *> {
+ static const unsigned value = AS;
+};
+
+int main() {
+ int __attribute__((address_space(1))) * p1;
+ int p = GetAddressSpaceValue(p1);
+
+ car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}}
+ HasASTemplateFields<1> HASTF;
+ neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}}
+ correct<0x7FFFF6>();
+ tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650>' requested here}}
+
+ __attribute__((address_space(1))) char *x;
+ __attribute__((address_space(2))) char *y;
+ cmp<1, 2>(x, y); // expected-note {{in instantiation of function template specialization 'cmp<1, 2>' requested here}}
+
+ fooFunction<1> ff;
+ ff.get_0(); // expected-note {{in instantiation of member function 'fooFunction<1>::get_0' requested here}}
+ ff.qf();
+ ff.test3(); // expected-note {{in instantiation of member function 'fooFunction<1>::test3' requested here}}
+
+ static_assert(partial_spec_deduce_as<int __attribute__((address_space(3))) *>::value == 3, "address space value has been incorrectly deduced");
+
+ return 0;
+}
diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp
index dfb8a07d3b..31dbdb617a 100644
--- a/test/SemaTemplate/constexpr-instantiate.cpp
+++ b/test/SemaTemplate/constexpr-instantiate.cpp
@@ -191,7 +191,7 @@ namespace Unevaluated {
static constexpr bool f() { return sizeof(T) < U::size; }
template<typename U>
- static typename enable_if<f<U>(), void>::type g() {} // expected-note {{disabled by 'enable_if'}}
+ static typename enable_if<f<U>(), void>::type g() {} // expected-note {{requirement 'f<Unevaluated::PR13423::U>()' was not satisfied}}
};
struct U { static constexpr int size = 2; };
diff --git a/test/SemaTemplate/crash-unparsed-exception.cpp b/test/SemaTemplate/crash-unparsed-exception.cpp
index 1226b35deb..3137d3fa19 100644
--- a/test/SemaTemplate/crash-unparsed-exception.cpp
+++ b/test/SemaTemplate/crash-unparsed-exception.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -fcxx-exceptions -fexceptions %s
+// expected-no-diagnostics
struct A {
virtual ~A();
@@ -11,7 +12,7 @@ struct C {
~D() throw();
};
struct E : A {
- D<int> d; //expected-error{{exception specification is not available until end of class definition}}
+ D<int> d;
};
- B<int> b; //expected-note{{in instantiation of template class 'B<int>' requested here}}
+ B<int> b;
};
diff --git a/test/SemaTemplate/cxx17-inline-variables.cpp b/test/SemaTemplate/cxx17-inline-variables.cpp
new file mode 100644
index 0000000000..c0180506be
--- /dev/null
+++ b/test/SemaTemplate/cxx17-inline-variables.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// expected-no-diagnostics
+template<bool> struct DominatorTreeBase {
+ static constexpr bool IsPostDominator = true;
+};
+extern template class DominatorTreeBase<false>;
+constexpr bool k = DominatorTreeBase<false>::IsPostDominator;
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index ff7421a910..2c58fefa06 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -1,14 +1,10 @@
-// RUN: not %clang_cc1 -fsyntax-only %s -std=c++11 2>&1| FileCheck %s
-
-// Note that the error count below doesn't matter. We just want to
-// make sure that the parser doesn't crash.
-// CHECK: 16 errors
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++1z -verify
// PR7511
-template<a>
+template<a> // expected-error +{{}}
struct int_;
-template<a>
+template<a> // expected-error +{{}}
template<int,typename T1,typename>
struct ac
{
@@ -17,7 +13,7 @@ struct ac
template<class>struct aaa
{
- typedef ac<1,int,int>::ae ae
+ typedef ac<1,int,int>::ae ae // expected-error +{{}}
};
template<class>
@@ -36,19 +32,19 @@ struct state_machine
struct In;
template<int my>
- struct In<a::int_<aaa::a>,my>;
+ struct In<a::int_<aaa::a>,my>; // expected-error +{{}}
template<class Event>
int process(Event)
{
- In<a::int_<0> > a;
+ In<a::int_<0> > a; // expected-error +{{}}
}
- }
+ } // expected-error +{{}}
template<class Event>
int ant(Event)
{
region_processing_helper<int>* helper;
- helper->process(0)
+ helper->process(0) // expected-error +{{}}
}
};
@@ -81,21 +77,21 @@ void endl( ) ;
extern basic_ostream<char> cout;
-int operator<<( basic_ostream<char> , pair ) ;
+int operator<<( basic_ostream<char> , pair ) ; // expected-note +{{}}
void register_object_imp ( )
{
-cout << endl<1>;
+cout << endl<1>; // expected-error +{{}}
}
// PR12933
-namespacae PR12933 {
- template<typename S>
+namespace PR12933 {
+ template<typename S> // expected-error +{{}}
template<typename T>
void function(S a, T b) {}
int main() {
- function(0, 1);
+ function(0, 1); // expected-error +{{}}
return 0;
}
}
@@ -142,3 +138,26 @@ namespace PR14281_part3 {
template <class T, int* i> struct B {};
A<B<int, &some_decl>, &some_decl>::type x;
}
+
+namespace var_template_partial_spec_incomplete {
+ template<typename T> int n;
+ template<typename T, typename U = void> int n<T *>; // expected-error +{{}} expected-note {{}}
+ int k = n<void *>;
+}
+
+namespace deduceFunctionSpecializationForInvalidOutOfLineFunction {
+
+template <typename InputT, typename OutputT>
+struct SourceSelectionRequirement {
+ template<typename T>
+ OutputT evaluateSelectionRequirement(InputT &&Value) {
+ }
+};
+
+template <typename InputT, typename OutputT>
+OutputT SourceSelectionRequirement<InputT, OutputT>::
+evaluateSelectionRequirement<void>(InputT &&Value) { // expected-error {{cannot specialize a member of an unspecialized template}}
+ return Value;
+}
+
+}
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index 8ac65aacd5..be86f18729 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -305,11 +305,11 @@ namespace nullptr_deduction {
template<typename T, T v> struct X {};
template<typename T, T v> void f(X<T, v>) {
- static_assert(!v, "");
+ static_assert(!v, ""); // expected-warning 2{{implicit conversion of nullptr constant to 'bool'}}
}
void g() {
- f(X<int*, nullptr>());
- f(X<nullptr_t, nullptr>());
+ f(X<int*, nullptr>()); // expected-note {{instantiation of}}
+ f(X<nullptr_t, nullptr>()); // expected-note {{instantiation of}}
}
template<template<typename T, T> class X, typename T, typename U, int *P>
@@ -483,16 +483,15 @@ namespace check_extended_pack {
}
namespace dependent_template_template_param_non_type_param_type {
- template<int N> struct A { // expected-note 2{{candidate}}
+ template<int N> struct A {
template<typename V = int, V M = 12, V (*Y)[M], template<V (*v)[M]> class W>
- A(W<Y>); // expected-note {{[with V = int, M = 12, Y = &dependent_template_template_param_non_type_param_type::n]}}
+ A(W<Y>);
};
int n[12];
template<int (*)[12]> struct Q {};
Q<&n> qn;
- // FIXME: This should be accepted, but we somehow fail to deduce W.
- A<0> a(qn); // expected-error {{no matching constructor for initialization}}
+ A<0> a(qn);
}
namespace dependent_list_deduction {
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
index d9fa2b4a82..c24ed12a02 100644
--- a/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -87,3 +87,30 @@ namespace PR13986 {
A<1> m_target;
};
}
+
+// rdar://problem/34167492
+// Template B is instantiated during checking if defaulted A copy constructor
+// is constexpr. For this we check if S<int> copy constructor is constexpr. And
+// for this we check S constructor template with default argument that mentions
+// template B. In turn, template instantiation triggers checking defaulted
+// members exception spec. The problem is that it checks defaulted members not
+// for instantiated class only, but all defaulted members so far. In this case
+// we try to check exception spec for A default constructor which requires
+// initializer for the field _a. But initializers are added after constexpr
+// check so we reject the code because cannot find _a initializer.
+namespace rdar34167492 {
+ template <typename T> struct B { using type = bool; };
+
+ template <typename T> struct S {
+ S() noexcept;
+
+ template <typename U, typename B<U>::type = true>
+ S(const S<U>&) noexcept;
+ };
+
+ class A {
+ A() noexcept = default;
+ A(const A&) noexcept = default;
+ S<int> _a{};
+ };
+}
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
index d3e249db7e..b5b042c64a 100644
--- a/test/SemaTemplate/default-arguments.cpp
+++ b/test/SemaTemplate/default-arguments.cpp
@@ -207,3 +207,19 @@ Y<false> y2;
} // end ns1
} // end ns PR26134
+
+namespace friends {
+ namespace ns {
+ template<typename> struct A {
+ template<typename> friend void f();
+ template<typename> friend struct X;
+ };
+ template<typename = int> void f(); // expected-warning 0-1{{extension}}
+ template<typename = int> struct X;
+ A<int> a;
+ }
+ namespace ns {
+ void g() { f(); }
+ X<int> *p;
+ }
+}
diff --git a/test/SemaTemplate/default-expr-arguments-3.cpp b/test/SemaTemplate/default-expr-arguments-3.cpp
index 173609c045..4449eb7100 100644
--- a/test/SemaTemplate/default-expr-arguments-3.cpp
+++ b/test/SemaTemplate/default-expr-arguments-3.cpp
@@ -21,7 +21,7 @@ namespace PR28795 {
}
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct class2 definition
-// CHECK-NEXT: TemplateArgument type 'int'
+// CHECK: TemplateArgument type 'int'
// CHECK: LambdaExpr {{.*}} 'class (lambda at
// CHECK: ParmVarDecl {{.*}} used f 'enum foo' cinit
// CHECK-NEXT: DeclRefExpr {{.*}} 'enum foo' EnumConstant {{.*}} 'a' 'enum foo'
diff --git a/test/SemaTemplate/dependent-template-recover.cpp b/test/SemaTemplate/dependent-template-recover.cpp
index 3c01f6586b..ac16230417 100644
--- a/test/SemaTemplate/dependent-template-recover.cpp
+++ b/test/SemaTemplate/dependent-template-recover.cpp
@@ -17,6 +17,28 @@ struct X {
}
};
+struct MrsBadcrumble {
+ friend MrsBadcrumble operator<(void (*)(int), MrsBadcrumble);
+ friend void operator>(MrsBadcrumble, int);
+} mb;
+
+template<int N, typename T> void f(T t) {
+ t.f<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'f'}}
+ t.T::f<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'f'}}
+ T::g<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}}
+
+ // Note: no diagnostic here, this is actually valid as a comparison between
+ // the decayed pointer to Y::g<> and mb!
+ T::g<mb>(0);
+}
+
+struct Y {
+ template <int> void f(int);
+ template <int = 0> static void g(int); // expected-warning 0-1{{extension}}
+};
+void q() { void (*p)(int) = Y::g; }
+template void f<0>(Y); // expected-note {{in instantiation of}}
+
namespace PR9401 {
// From GCC PR c++/45558
template <typename S, typename T>
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
index 853ba492f8..6570b64564 100644
--- a/test/SemaTemplate/destructor-template.cpp
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -86,3 +86,9 @@ namespace PR16852 {
template<typename T> decltype(S<T>().~S()) f(); // expected-note {{candidate template ignored: couldn't infer template argument 'T'}}
void g() { f(); } // expected-error {{no matching function for call to 'f'}}
}
+
+class PR33189
+{
+ template <class T>
+ ~PR33189() { } // expected-error{{destructor cannot be declared as a template}}
+};
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index 010716dd14..42d9f4d332 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -95,7 +95,7 @@ namespace PR7622 {
struct basic_streambuf;
template<typename,typename>
- struct basic_streambuf{friend bob<>()}; // expected-error{{unknown type name 'bob'}} \
+ struct basic_streambuf{friend bob<>()}; // expected-error{{no template named 'bob'}} \
// expected-error{{expected member name or ';' after declaration specifiers}}
template struct basic_streambuf<int>;
}
diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp
index f302836c7e..e8165ac9ca 100644
--- a/test/SemaTemplate/explicit-specialization-member.cpp
+++ b/test/SemaTemplate/explicit-specialization-member.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fcxx-exceptions
template<typename T>
struct X0 {
typedef T* type;
@@ -38,22 +38,27 @@ namespace PR18246 {
template<typename T>
template<int N>
- void Baz<T>::bar() { // expected-note {{couldn't infer template argument 'N'}}
+ void Baz<T>::bar() {
}
- // FIXME: We shouldn't try to match this against a prior declaration if
- // template parameter matching failed.
template<typename T>
- void Baz<T>::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}} \
- // expected-error {{no function template matches}}
+ void Baz<T>::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}}
}
}
namespace PR19340 {
template<typename T> struct Helper {
- template<int N> static void func(const T *m) {} // expected-note {{failed template argument deduction}}
+ template<int N> static void func(const T *m) {}
};
-template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot specialize a member}} \
- // expected-error {{no function template matches}}
+template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot specialize a member}}
+}
+
+namespace SpecLoc {
+ template <typename T> struct A {
+ static int n; // expected-note {{previous}}
+ static void f(); // expected-note {{previous}}
+ };
+ template<> float A<int>::n; // expected-error {{different type}}
+ template<> void A<int>::f() throw(); // expected-error {{does not match}}
}
diff --git a/test/SemaTemplate/extern-templates.cpp b/test/SemaTemplate/extern-templates.cpp
index 5eb9c9db12..acbc9d5712 100644
--- a/test/SemaTemplate/extern-templates.cpp
+++ b/test/SemaTemplate/extern-templates.cpp
@@ -71,3 +71,10 @@ extern template void X1<const void*>::g(const void*);
void g_X1_2(X1<const void *> x1, const void *ptr) {
x1.g(ptr);
}
+
+namespace static_const_member {
+ template <typename T> struct A { static const int n; };
+ template <typename T> const int A<T>::n = 3;
+ extern template struct A<int>;
+ int arr[A<int>::n];
+}
diff --git a/test/SemaTemplate/instantiate-friend-function.cpp b/test/SemaTemplate/instantiate-friend-function.cpp
new file mode 100644
index 0000000000..08602d522d
--- /dev/null
+++ b/test/SemaTemplate/instantiate-friend-function.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -S -triple %itanium_abi_triple -std=c++11 -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+namespace PR10856 {
+ template<typename T> class C;
+
+ template<typename S, typename R = S> C<R> operator - (C<S> m0, C<S> m1);
+ template<typename T> class C {
+ public:
+ template<typename S, typename R> friend C<R> operator - (C<S> m0, C<S> m1);
+ };
+
+ template<typename S, typename R> inline C<R> operator - (C<S> m0, C<S> m1) {
+ C<R> ret;
+ return ret;
+ }
+};
+
+int PR10856_main(int argc, char** argv) {
+ using namespace PR10856;
+ C<int> a;
+ a-a;
+ return 0;
+}
+
+// PR10856::C<int> PR10856::operator-<int, int>(PR10856::C<int>, PR10856::C<int>)
+// CHECK: define {{.*}} @_ZN7PR10856miIiiEENS_1CIT0_EENS1_IT_EES5_
+
+namespace PR10856_Root {
+ template<typename Value, typename Defaulted = void>
+ bool g(Value value);
+
+ template<typename ClassValue> class MyClass {
+ private:
+ template<typename Value, typename Defaulted>
+ friend bool g(Value value);
+ };
+}
+
+namespace PR10856_Root {
+ void f() {
+ MyClass<int> value;
+ g(value);
+ }
+}
+
+// bool PR10856_Root::g<PR10856_Root::MyClass<int>, void>(PR10856_Root::MyClass<int>)
+// CHECK: call {{.*}} @_ZN12PR10856_Root1gINS_7MyClassIiEEvEEbT_
diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
index 6afc709126..a41248ee1b 100644
--- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -347,8 +347,7 @@ template <typename T> struct B : A<T> {
};
template <typename T> struct C : A<T> {
// Incorrect form.
- NameFromBase<T> m; // expected-error {{unknown type name 'NameFromBase'}}
- //expected-error@-1 {{expected member name or ';' after declaration specifiers}}
+ NameFromBase<T> m; // expected-error {{no template named 'NameFromBase'}}
};
}
diff --git a/test/SemaTemplate/overload-candidates.cpp b/test/SemaTemplate/overload-candidates.cpp
index c0abb5b174..de998d74f9 100644
--- a/test/SemaTemplate/overload-candidates.cpp
+++ b/test/SemaTemplate/overload-candidates.cpp
@@ -47,7 +47,7 @@ namespace boost {
template<bool, typename = void> struct enable_if {};
template<typename T> struct enable_if<true, T> { typedef T type; };
}
-template<typename T> typename boost::enable_if<sizeof(T) == 4, int>::type if_size_4(); // expected-note{{candidate template ignored: disabled by 'enable_if' [with T = char]}}
+template<typename T> typename boost::enable_if<sizeof(T) == 4, int>::type if_size_4(); // expected-note{{candidate template ignored: requirement 'sizeof(char) == 4' was not satisfied [with T = char]}}
int k = if_size_4<char>(); // expected-error{{no matching function}}
namespace llvm {
@@ -61,7 +61,7 @@ void test_if_int() {
}
template<typename T> struct NonTemplateFunction {
- typename boost::enable_if<sizeof(T) == 4, int>::type f(); // expected-error{{no type named 'type' in 'boost::enable_if<false, int>'; 'enable_if' cannot be used to disable this declaration}}
+ typename boost::enable_if<sizeof(T) == 4, int>::type f(); // expected-error{{failed requirement 'sizeof(char) == 4'; 'enable_if' cannot be used to disable this declaration}}
};
NonTemplateFunction<char> NTFC; // expected-note{{here}}
@@ -100,7 +100,7 @@ namespace PR15673 {
#if __cplusplus <= 199711L
// expected-warning@-2 {{default template arguments for a function template are a C++11 extension}}
#endif
- // expected-note@-4 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
+ // expected-note@+1 {{candidate template ignored: requirement 'a_trait<int>::value' was not satisfied [with T = int]}}
void foo() {}
void bar() { foo<int>(); } // expected-error {{no matching function for call to 'foo'}}
@@ -128,7 +128,7 @@ namespace PR15673 {
#if __cplusplus <= 199711L
// expected-warning@-2 {{alias declarations are a C++11 extension}}
#endif
- // expected-note@-4 {{candidate template ignored: disabled by 'enable_if' [with T = int]}}
+ // expected-note@+7 {{candidate template ignored: requirement 'some_trait<int>::value' was not satisfied [with T = int]}}
template<typename T,
typename Requires = unicorns<T> >
@@ -137,4 +137,30 @@ namespace PR15673 {
#endif
void wibble() {}
void wobble() { wibble<int>(); } // expected-error {{no matching function for call to 'wibble'}}
+
+ template<typename T>
+ struct some_passing_trait : std::true_type {};
+
+#if __cplusplus <= 199711L
+ // expected-warning@+4 {{default template arguments for a function template are a C++11 extension}}
+ // expected-warning@+4 {{default template arguments for a function template are a C++11 extension}}
+#endif
+ template<typename T,
+ int n = 42,
+ typename std::enable_if<n == 43 || (some_passing_trait<T>::value && some_trait<T>::value), int>::type = 0>
+ void almost_rangesv3(); // expected-note{{candidate template ignored: requirement '42 == 43 || (some_passing_trait<int>::value && some_trait<int>::value)' was not satisfied}}
+ void test_almost_rangesv3() { almost_rangesv3<int>(); } // expected-error{{no matching function for call to 'almost_rangesv3'}}
+
+ #define CONCEPT_REQUIRES_(...) \
+ int x = 42, \
+ typename std::enable_if<(x == 43) || (__VA_ARGS__)>::type = 0
+
+#if __cplusplus <= 199711L
+ // expected-warning@+4 {{default template arguments for a function template are a C++11 extension}}
+ // expected-warning@+3 {{default template arguments for a function template are a C++11 extension}}
+#endif
+ template<typename T,
+ CONCEPT_REQUIRES_(some_passing_trait<T>::value && some_trait<T>::value)>
+ void rangesv3(); // expected-note{{candidate template ignored: requirement 'some_trait<int>::value' was not satisfied [with T = int, x = 42]}}
+ void test_rangesv3() { rangesv3<int>(); } // expected-error{{no matching function for call to 'rangesv3'}}
}
diff --git a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
index cfaad0cd0c..0b8f0eed16 100644
--- a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
+++ b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
@@ -25,7 +25,7 @@ namespace CanonicalNullptr {
}
namespace Auto {
- template<auto> struct A { }; // expected-error {{until C++1z}}
+ template<auto> struct A { }; // expected-error {{until C++17}}
}
namespace check_conversion_early {
diff --git a/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
index c1fcedd58d..d0fb25c047 100644
--- a/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -23,6 +23,9 @@ namespace Array {
A<const char*, &(&x)[1]> h; // expected-error {{refers to subobject '&x + 1'}}
A<const char*, 0> i; // expected-error {{not allowed in a converted constant}}
A<const char*, nullptr> j;
+
+ extern char aub[];
+ A<char[], aub> k;
}
namespace Function {
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
index b0df9149c6..59deae7018 100644
--- a/test/SemaTemplate/temp_arg_template.cpp
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -102,7 +102,49 @@ 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> {};
+}
+
+namespace PR10147 {
+ template<typename T> struct A {};
+ template<typename T = int> struct A;
+ template<template<typename...> class A> void f(A<int>*) { A<> a; } // expected-warning 0-1{{extension}}
+ void g() { f((A<>*)0); }
}
diff --git a/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/test/SemaTemplate/temp_arg_template_cxx1z.cpp
index e3f228e7ef..03ef78f8cf 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,18 +90,18 @@ 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}}
+ 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:
@@ -111,7 +111,7 @@ namespace 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_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp
index daad61c142..9069f63e02 100644
--- a/test/SemaTemplate/temp_arg_type.cpp
+++ b/test/SemaTemplate/temp_arg_type.cpp
@@ -1,6 +1,7 @@
// 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
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}}
@@ -53,3 +54,56 @@ A1<Array<int, 17>::type> ax;
// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
// belongs somewhere in the template instantiation section).
+
+#if __cplusplus >= 201703
+// As a defect resolution, we support deducing B in noexcept(B).
+namespace deduce_noexcept {
+ template<typename> struct function;
+ template<typename R, typename ...A, bool N>
+ struct function<R(A...) noexcept(N)> {
+ static constexpr bool Noexcept = N;
+ };
+ static_assert(function<int(float, double) noexcept>::Noexcept);
+ static_assert(!function<int(float, double)>::Noexcept);
+
+ void noexcept_function() noexcept;
+ void throwing_function();
+
+ template<typename T, bool B> float &deduce_function(T(*)() noexcept(B)); // expected-note {{candidate}}
+ template<typename T> int &deduce_function(T(*)() noexcept); // expected-note {{candidate}}
+ void test_function_deduction() {
+ // FIXME: This should probably unambiguously select the second overload.
+ int &r = deduce_function(noexcept_function); // expected-error {{ambiguous}}
+ float &s = deduce_function(throwing_function);
+ }
+
+ namespace low_priority_deduction {
+ template<int> struct A {};
+ template<auto B> void f(A<B>, void(*)() noexcept(B)) {
+ using T = decltype(B);
+ using T = int;
+ }
+ void g() { f(A<0>(), g); } // ok, deduce B as an int
+ }
+
+ // FIXME: It's not clear whether this should work. We're told to deduce with
+ // P being the function template type and A being the declared type, which
+ // would accept this, but considering the exception specification in such
+ // cases breaks new/delete matching.
+ template<bool Noexcept> void dep() noexcept(Noexcept) {} // expected-note 3{{couldn't infer template argument 'Noexcept'}}
+ template void dep(); // expected-error {{does not refer to a function template}}
+ template void dep() noexcept(true); // expected-error {{does not refer to a function template}}
+ template void dep() noexcept(false); // expected-error {{does not refer to a function template}}
+
+ // FIXME: It's also not clear whether this should be valid: do we substitute
+ // into the function type (including the exception specification) or not?
+ template<typename T> typename T::type1 f() noexcept(T::a);
+ template<typename T> typename T::type2 f() noexcept(T::b) {}
+ struct X {
+ static constexpr bool b = true;
+ using type1 = void;
+ using type2 = void;
+ };
+ template void f<X>();
+}
+#endif
diff --git a/test/SemaTemplate/typo-template-name.cpp b/test/SemaTemplate/typo-template-name.cpp
new file mode 100644
index 0000000000..fe5201a8e2
--- /dev/null
+++ b/test/SemaTemplate/typo-template-name.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -std=c++1z %s -verify -Wno-unused
+
+namespace InExpr {
+ namespace A {
+ void typo_first_a(); // expected-note {{found}}
+ template<typename T> void typo_first_b(); // expected-note 2{{declared here}}
+ }
+ void testA() { A::typo_first_a<int>(); } // expected-error {{'typo_first_a' does not name a template but is followed by template arguments; did you mean 'typo_first_b'?}}
+
+ namespace B {
+ void typo_first_b(); // expected-note {{found}}
+ }
+ void testB() { B::typo_first_b<int>(); } // expected-error {{'typo_first_b' does not name a template but is followed by template arguments; did you mean 'A::typo_first_b'?}}
+
+ struct Base {
+ template<typename T> static void foo(); // expected-note 4{{declared here}}
+ int n;
+ };
+ struct Derived : Base {
+ void foo(); // expected-note {{found}}
+ };
+ // We probably don't want to suggest correcting to .Base::foo<int>
+ void testMember() { Derived().foo<int>(); } // expected-error-re {{does not name a template but is followed by template arguments{{$}}}}
+
+ struct Derived2 : Base {
+ void goo(); // expected-note {{found}}
+ };
+ void testMember2() { Derived2().goo<int>(); } // expected-error {{member 'goo' of 'InExpr::Derived2' is not a template; did you mean 'foo'?}}
+
+ void no_correction() {
+ int foo; // expected-note 3{{found}}
+
+ foo<int>(); // expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}}
+ foo<>(); // expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}}
+ foo<Base *>(); // expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}}
+
+ // These are valid expressions.
+ foo<foo; // expected-warning {{self-comparison}}
+ foo<int()>(0);
+ foo<int(), true>(false);
+ foo<Base{}.n;
+ }
+}
diff --git a/test/Tooling/Inputs/clang-diff-basic-src.cpp b/test/Tooling/Inputs/clang-diff-basic-src.cpp
new file mode 100644
index 0000000000..8f15232916
--- /dev/null
+++ b/test/Tooling/Inputs/clang-diff-basic-src.cpp
@@ -0,0 +1,33 @@
+namespace src {
+
+void foo() {
+ int x = 321;
+}
+
+void main() { foo(); };
+
+const char *a = "foo";
+
+typedef unsigned int nat;
+
+int p = 1 * 2 * 3 * 4;
+int squared = p * p;
+
+class X {
+ const char *foo(int i) {
+ if (i == 0)
+ return "foo";
+ return 0;
+ }
+
+public:
+ X(){};
+
+ int id(int i) { return i; }
+};
+}
+
+void m() { int x = 0 + 0 + 0; }
+int um = 1 * 2 + 3;
+
+void f1() {{ (void) __func__;;; }}
diff --git a/test/Tooling/clang-diff-args.test b/test/Tooling/clang-diff-args.test
new file mode 100644
index 0000000000..a4ce1ea925
--- /dev/null
+++ b/test/Tooling/clang-diff-args.test
@@ -0,0 +1,12 @@
+RUN: echo a > %t.cpp
+
+CHECK: unknown type name 'X'
+
+check adding compiler cflags
+RUN: clang-diff -ast-dump -extra-arg=-Da=X %t.cpp -- 2>&1 | FileCheck %s
+RUN: clang-diff -ast-dump -extra-arg-before=-Da=X %t.cpp -- 2>&1 | FileCheck %s
+RUN: clang-diff -ast-dump %t.cpp -- 2>&1 -Da=X | FileCheck %s
+
+NOMATCH-CHECK-NOT: {{.}}
+RUN: clang-diff %S/clang-diff-ast.cpp %S/clang-diff-ast.cpp -- 2>&1 -std=c++11 \
+RUN: | FileCheck -check-prefix=NOMATCH-CHECK -allow-empty %s
diff --git a/test/Tooling/clang-diff-ast.cpp b/test/Tooling/clang-diff-ast.cpp
new file mode 100644
index 0000000000..a8efda50a4
--- /dev/null
+++ b/test/Tooling/clang-diff-ast.cpp
@@ -0,0 +1,92 @@
+// RUN: clang-diff -ast-dump %s -- -std=c++11 | FileCheck %s
+
+
+// CHECK: {{^}}TranslationUnitDecl(0)
+// CHECK: {{^}} NamespaceDecl: test;(
+namespace test {
+
+// CHECK: {{^}} FunctionDecl: :f(
+// CHECK: CompoundStmt(
+void f() {
+ // CHECK: VarDecl: i(int)(
+ // CHECK: IntegerLiteral: 1
+ auto i = 1;
+ // CHECK: FloatingLiteral: 1.5(
+ auto r = 1.5;
+ // CHECK: CXXBoolLiteralExpr: true(
+ auto b = true;
+ // CHECK: CallExpr(
+ // CHECK-NOT: ImplicitCastExpr
+ // CHECK: DeclRefExpr: :f(
+ f();
+ // CHECK: UnaryOperator: ++(
+ ++i;
+ // CHECK: BinaryOperator: =(
+ i = i;
+}
+
+} // end namespace test
+
+// CHECK: UsingDirectiveDecl: test(
+using namespace test;
+
+// CHECK: TypedefDecl: nat;unsigned int;(
+typedef unsigned nat;
+// CHECK: TypeAliasDecl: real;double;(
+using real = double;
+
+class Base {
+};
+
+// CHECK: CXXRecordDecl: X;X;(
+class X : Base {
+ int m;
+ // CHECK: CXXMethodDecl: :foo(const char *(int)
+ // CHECK: ParmVarDecl: i(int)(
+ const char *foo(int i) {
+ if (i == 0)
+ // CHECK: StringLiteral: foo(
+ return "foo";
+ // CHECK-NOT: ImplicitCastExpr
+ return 0;
+ }
+
+ // CHECK: AccessSpecDecl: public(
+public:
+ int not_initialized;
+ // CHECK: CXXConstructorDecl: :X(void (char, int){{( __attribute__\(\(thiscall\)\))?}})(
+ // CHECK-NEXT: ParmVarDecl: s(char)
+ // CHECK-NEXT: ParmVarDecl: (int)
+ // CHECK-NEXT: CXXCtorInitializer: Base
+ // CHECK-NEXT: CXXConstructExpr
+ // CHECK-NEXT: CXXCtorInitializer: m
+ // CHECK-NEXT: IntegerLiteral: 0
+ X(char s, int) : Base(), m(0) {
+ // CHECK-NEXT: CompoundStmt
+ // CHECK: MemberExpr: :m(
+ int x = m;
+ }
+ // CHECK: CXXConstructorDecl: :X(void (char){{( __attribute__\(\(thiscall\)\))?}})(
+ // CHECK: CXXCtorInitializer: X
+ X(char s) : X(s, 4) {}
+};
+
+#define M (void)1
+#define MA(a, b) (void)a, b
+// CHECK: FunctionDecl
+// CHECK-NEXT: CompoundStmt
+void macros() {
+ M;
+ MA(1, 2);
+}
+
+#ifndef GUARD
+#define GUARD
+// CHECK-NEXT: NamespaceDecl
+namespace world {
+// nodes from other files are excluded, there should be no output here
+#include "clang-diff-ast.cpp"
+}
+// CHECK-NEXT: FunctionDecl: sentinel
+void sentinel();
+#endif
diff --git a/test/Tooling/clang-diff-basic.cpp b/test/Tooling/clang-diff-basic.cpp
new file mode 100644
index 0000000000..a0c0163530
--- /dev/null
+++ b/test/Tooling/clang-diff-basic.cpp
@@ -0,0 +1,57 @@
+// RUN: clang-diff -dump-matches %S/Inputs/clang-diff-basic-src.cpp %s -- | FileCheck %s
+
+// CHECK: Match TranslationUnitDecl{{.*}} to TranslationUnitDecl
+// CHECK: Match NamespaceDecl: src{{.*}} to NamespaceDecl: dst
+namespace dst {
+// CHECK-NOT: Match NamespaceDecl: src{{.*}} to NamespaceDecl: inner
+namespace inner {
+void foo() {
+ // CHECK: Match IntegerLiteral: 321{{.*}} to IntegerLiteral: 322
+ int x = 322;
+}
+}
+
+// CHECK: Match DeclRefExpr: :foo{{.*}} to DeclRefExpr: :inner::foo
+void main() { inner::foo(); }
+
+// CHECK: Match StringLiteral: foo{{.*}} to StringLiteral: foo
+const char *b = "f" "o" "o";
+
+// unsigned is canonicalized to unsigned int
+// CHECK: Match TypedefDecl: :nat;unsigned int;{{.*}} to TypedefDecl: :nat;unsigned int;
+typedef unsigned nat;
+
+// CHECK: Match VarDecl: :p(int){{.*}} to VarDecl: :prod(double)
+// CHECK: Update VarDecl: :p(int){{.*}} to :prod(double)
+// CHECK: Match BinaryOperator: *{{.*}} to BinaryOperator: *
+double prod = 1 * 2 * 10;
+// CHECK: Update DeclRefExpr
+int squared = prod * prod;
+
+class X {
+ const char *foo(int i) {
+ if (i == 0)
+ return "Bar";
+ // CHECK: Insert IfStmt{{.*}} into IfStmt
+ // CHECK: Insert BinaryOperator: =={{.*}} into IfStmt
+ else if (i == -1)
+ return "foo";
+ return 0;
+ }
+ X(){}
+};
+}
+
+// CHECK: Move CompoundStmt{{.*}} into CompoundStmt
+void m() { { int x = 0 + 0 + 0; } }
+// CHECK: Update and Move IntegerLiteral: 7{{.*}} into BinaryOperator: +({{.*}}) at 1
+int um = 1 + 7;
+
+namespace {
+// match with parents of different type
+// CHECK: Match FunctionDecl: f1{{.*}} to FunctionDecl: (anonymous namespace)::f1
+void f1() {{ (void) __func__;;; }}
+}
+
+// CHECK: Delete AccessSpecDecl: public
+// CHECK: Delete CXXMethodDecl
diff --git a/test/Tooling/clang-diff-bottomup.cpp b/test/Tooling/clang-diff-bottomup.cpp
new file mode 100644
index 0000000000..bc5d2cbdf4
--- /dev/null
+++ b/test/Tooling/clang-diff-bottomup.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -E %s > %t.src.cpp
+// RUN: %clang_cc1 -E %s > %t.dst.cpp -DDEST
+// RUN: clang-diff -dump-matches -s=0 %t.src.cpp %t.dst.cpp -- | FileCheck %s
+//
+// Test the bottom-up matching, with maxsize set to 0, so that the optimal matching will never be applied.
+
+#ifndef DEST
+
+void f1() { ; {{;}} }
+void f2() { ;; {{;}} }
+
+#else
+
+// Jaccard similarity threshold is 0.5.
+
+void f1() {
+// CompoundStmt: 3 matched descendants, subtree sizes 4 and 5
+// Jaccard similarity = 3 / (4 + 5 - 3) = 3 / 6 >= 0.5
+// CHECK: Match FunctionDecl: f1(void ())(1) to FunctionDecl: f1(void ())(1)
+// CHECK: Match CompoundStmt(2) to CompoundStmt(2)
+// CHECK: Match CompoundStmt(4) to CompoundStmt(3)
+// CHECK: Match CompoundStmt(5) to CompoundStmt(4)
+// CHECK: Match NullStmt(6) to NullStmt(5)
+ {{;}} ;;
+}
+
+void f2() {
+// CompoundStmt: 3 matched descendants, subtree sizes 4 and 5
+// Jaccard similarity = 3 / (5 + 6 - 3) = 3 / 8 < 0.5
+// CHECK-NOT: Match FunctionDecl(9)
+// CHECK-NOT: Match CompoundStmt(10)
+// CHECK: Match CompoundStmt(11) to CompoundStmt(10)
+// CHECK: Match CompoundStmt(12) to CompoundStmt(11)
+// CHECK: Match NullStmt(13) to NullStmt(12)
+// CHECK-NOT: Match NullStmt(13)
+ {{;}} ;;;
+}
+
+#endif
diff --git a/test/Tooling/clang-diff-html.test b/test/Tooling/clang-diff-html.test
new file mode 100644
index 0000000000..00d9e07d2f
--- /dev/null
+++ b/test/Tooling/clang-diff-html.test
@@ -0,0 +1,36 @@
+RUN: clang-diff -html %S/Inputs/clang-diff-basic-src.cpp %S/clang-diff-basic.cpp -- | FileCheck %s
+
+CHECK: <pre><div id='L' class='code'><span id='L0' tid='R0' title='TranslationUnitDecl
+CHECK-NEXT: 0 -> 0'>
+
+match, update
+CHECK: <span id='L[[L:[0-9]+]]' tid='R[[R:[0-9]+]]' title='NamespaceDecl
+CHECK-NEXT: [[L]] -> [[R]]
+CHECK-NEXT: src;' class='u'>namespace src {
+
+match, move
+CHECK: <span id='L[[L:[0-9]+]]' tid='R[[R:[0-9]+]]' title='FunctionDecl
+CHECK-NEXT: [[L]] -> [[R]]
+CHECK-NEXT: :foo(void ())' class='m'>void foo()
+
+match
+CHECK: <span id='L[[L:[0-9]+]]' tid='R[[R:[0-9]+]]' title='FunctionDecl
+CHECK-NEXT: [[L]] -> [[R]]
+CHECK-NEXT: :main(void ())'>void main()
+
+deletion
+CHECK: <span id='L[[L:[0-9]+]]' tid='R-1' title='IntegerLiteral
+CHECK-NEXT: [[L]] -> -1
+CHECK-NEXT: 4' class='d'>4</span>
+
+update + move
+CHECK: 2' class='u m'>2</span>
+
+insertion
+CHECK: <span id='R[[R:[0-9]+]]' tid='L-1' title='StringLiteral
+CHECK-NEXT: -1 -> [[R]]
+CHECK-NEXT: Bar' class='i'>&quot;Bar&quot;</span>
+
+comments
+CHECK: // CHECK: Insert IfStmt{{.*}} into IfStmt
+CHECK: // CHECK: Delete AccessSpecDecl: public
diff --git a/test/Tooling/clang-diff-json.cpp b/test/Tooling/clang-diff-json.cpp
new file mode 100644
index 0000000000..9aac6fa8b1
--- /dev/null
+++ b/test/Tooling/clang-diff-json.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-diff -ast-dump-json %s -- \
+// RUN: | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
+// RUN: | FileCheck %s
+
+// CHECK: "begin": 299,
+// CHECK: "type": "FieldDecl",
+// CHECK: "end": 319,
+// CHECK: "type": "CXXRecordDecl",
+class A {
+ int x;
+};
+
+// CHECK: "children": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "begin":
+// CHECK-NEXT: "children": []
+// CHECK-NEXT: "end":
+// CHECK-NEXT: "id":
+// CHECK-NEXT: "type": "CharacterLiteral"
+// CHECK-NEXT: }
+// CHECK: ]
+// CHECK: "type": "VarDecl",
+char nl = '\n';
+
+// CHECK: "value": "abc \n\t\u0000\u001f"
+char s[] = "abc \n\t\0\x1f";
+
diff --git a/test/Tooling/clang-diff-opt.cpp b/test/Tooling/clang-diff-opt.cpp
new file mode 100644
index 0000000000..771c6abaec
--- /dev/null
+++ b/test/Tooling/clang-diff-opt.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -E %s > %t.src.cpp
+// RUN: %clang_cc1 -E %s > %t.dst.cpp -DDEST
+// RUN: clang-diff -dump-matches -s=10 %t.src.cpp %t.dst.cpp -- | FileCheck %s
+//
+// Test the behaviour of the matching according to the optimal tree edit
+// distance, implemented with Zhang and Shasha's algorithm.
+// Just for testing we use a tiny value of 10 for maxsize. Subtrees bigger than
+// this size will not be processed by the optimal algorithm.
+
+#ifndef DEST
+
+void f1() { {;} {{;}} }
+
+void f2() { {;} {{;;;;;}} }
+
+void f3() { {;} {{;;;;;;}} }
+
+#else
+
+void f1() {
+// Jaccard similarity = 3 / (5 + 4 - 3) = 3 / 6 >= 0.5
+// The optimal matching algorithm should move the ; into the outer block
+// CHECK: Match CompoundStmt(2) to CompoundStmt(2)
+// CHECK-NOT: Match CompoundStmt(3)
+// CHECK-NEXT: Match NullStmt(4) to NullStmt(3)
+ ; {{;}}
+}
+
+void f2() {
+ // Jaccard similarity = 7 / (10 + 10 - 7) >= 0.5
+ // As none of the subtrees is bigger than 10 nodes, the optimal algorithm
+ // will be run.
+ // CHECK: Match NullStmt(11) to NullStmt(9)
+ ;; {{;;;;;}}
+}
+
+void f3() {
+ // Jaccard similarity = 8 / (11 + 11 - 8) >= 0.5
+ // As the subtrees are bigger than 10 nodes, the optimal algorithm will not
+ // be run.
+ // CHECK: Delete NullStmt(22)
+ ;; {{;;;;;;}}
+}
+
+#endif
diff --git a/test/Tooling/clang-diff-topdown.cpp b/test/Tooling/clang-diff-topdown.cpp
new file mode 100644
index 0000000000..d6c1d77033
--- /dev/null
+++ b/test/Tooling/clang-diff-topdown.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -E %s > %t.src.cpp
+// RUN: %clang_cc1 -E %s > %t.dst.cpp -DDEST
+// RUN: clang-diff -dump-matches -stop-diff-after=topdown %t.src.cpp %t.dst.cpp -- -std=c++11 | FileCheck %s
+//
+// Test the top-down matching of identical subtrees only.
+
+#ifndef DEST
+
+void f1()
+{
+ // Match some subtree of height greater than 2.
+ // CHECK: Match CompoundStmt(3) to CompoundStmt(3)
+ // CHECK: Match CompoundStmt(4) to CompoundStmt(4)
+ // CHECK: Match NullStmt(5) to NullStmt(5)
+ {{;}}
+
+ // Don't match subtrees that are smaller.
+ // CHECK-NOT: Match CompoundStmt(6)
+ // CHECK-NOT: Match NullStmt(7)
+ {;}
+
+ // Greedy approach - use the first matching subtree when there are multiple
+ // identical subtrees.
+ // CHECK: Match CompoundStmt(8) to CompoundStmt(8)
+ // CHECK: Match CompoundStmt(9) to CompoundStmt(9)
+ // CHECK: Match NullStmt(10) to NullStmt(10)
+ {{;;}}
+}
+
+int x;
+
+namespace src {
+ int x;
+ int x1 = x + 1;
+ int x2 = ::x + 1;
+}
+
+class A { int x = 1 + 1; void f() { int x1 = x; } };
+
+#else
+
+
+void f1() {
+
+ {{;}}
+
+ {;}
+
+ {{;;}}
+ // CHECK-NOT: Match {{.*}} to CompoundStmt(11)
+ // CHECK-NOT: Match {{.*}} to CompoundStmt(12)
+ // CHECK-NOT: Match {{.*}} to NullStmt(13)
+ {{;;}}
+
+ // CHECK-NOT: Match {{.*}} to NullStmt(14)
+ ;
+}
+
+int x;
+
+namespace dst {
+ int x;
+ // CHECK: Match DeclRefExpr: :x(17) to DeclRefExpr: :x(22)
+ int x1 = x + 1;
+ // CHECK: Match DeclRefExpr: x(21) to DeclRefExpr: x(26)
+ int x2 = ::x + 1;
+}
+
+class B {
+ // Only the class name changed; it is not included in the field value,
+ // therefore there is no update.
+ // CHECK: Match FieldDecl: :x(int)(24) to FieldDecl: :x(int)(29)
+ // CHECK-NOT: Update FieldDecl: :x(int)(24)
+ int x = 1+1;
+ void f() {
+ // CHECK: Match MemberExpr: :x(32) to MemberExpr: :x(37)
+ // CHECK-NOT: Update MemberExpr: :x(32)
+ int x1 = B::x;
+ }
+
+};
+
+#endif
diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg
deleted file mode 100644
index 39fad0099c..0000000000
--- a/test/Unit/lit.cfg
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-import os
-import platform
-
-import lit.formats
-import lit.util
-
-# name: The name of this test suite.
-config.name = 'Clang-Unit'
-
-# suffixes: A list of file extensions to treat as test files.
-config.suffixes = []
-
-# test_source_root: The root path where tests are located.
-# test_exec_root: The root path where tests should be run.
-clang_obj_root = getattr(config, 'clang_obj_root', None)
-if clang_obj_root is not None:
- config.test_exec_root = os.path.join(clang_obj_root, 'unittests')
- config.test_source_root = config.test_exec_root
-
-# testFormat: The test format to use to interpret tests.
-llvm_build_mode = getattr(config, 'llvm_build_mode', "Debug")
-config.test_format = lit.formats.GoogleTest(llvm_build_mode, 'Tests')
-
-# Propagate the temp directory. Windows requires this because it uses \Windows\
-# if none of these are present.
-if 'TMP' in os.environ:
- config.environment['TMP'] = os.environ['TMP']
-if 'TEMP' in os.environ:
- config.environment['TEMP'] = os.environ['TEMP']
-
-# Propagate path to symbolizer for ASan/MSan.
-for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
- if symbolizer in os.environ:
- config.environment[symbolizer] = os.environ[symbolizer]
-
-###
-
-# Check that the object root is known.
-if config.test_exec_root is None:
- # Otherwise, we haven't loaded the site specific configuration (the user is
- # probably trying to run on a test file directly, and either the site
- # configuration hasn't been created by the build system, or we are in an
- # out-of-tree build situation).
-
- # Check for 'clang_unit_site_config' user parameter, and use that if available.
- site_cfg = lit_config.params.get('clang_unit_site_config', None)
- if site_cfg and os.path.exists(site_cfg):
- lit_config.load_config(config, site_cfg)
- raise SystemExit
-
- # Try to detect the situation where we are using an out-of-tree build by
- # looking for 'llvm-config'.
- #
- # FIXME: I debated (i.e., wrote and threw away) adding logic to
- # automagically generate the lit.site.cfg if we are in some kind of fresh
- # build situation. This means knowing how to invoke the build system
- # though, and I decided it was too much magic.
-
- llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
- if not llvm_config:
- lit_config.fatal('No site specific configuration available!')
-
- # Get the source and object roots.
- llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
- llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
- clang_src_root = os.path.join(llvm_src_root, "tools", "clang")
- clang_obj_root = os.path.join(llvm_obj_root, "tools", "clang")
-
- # Validate that we got a tree which points to here, using the standard
- # tools/clang layout.
- this_src_root = os.path.join(os.path.dirname(__file__),'..','..')
- if os.path.realpath(clang_src_root) != os.path.realpath(this_src_root):
- lit_config.fatal('No site specific configuration available!')
-
- # Check that the site specific configuration exists.
- site_cfg = os.path.join(clang_obj_root, 'test', 'Unit', 'lit.site.cfg')
- if not os.path.exists(site_cfg):
- lit_config.fatal('No site specific configuration available!')
-
- # Okay, that worked. Notify the user of the automagic, and reconfigure.
- lit_config.note('using out-of-tree build at %r' % clang_obj_root)
- lit_config.load_config(config, site_cfg)
- raise SystemExit
-
-shlibpath_var = ''
-if platform.system() == 'Linux':
- shlibpath_var = 'LD_LIBRARY_PATH'
-elif platform.system() == 'Darwin':
- shlibpath_var = 'DYLD_LIBRARY_PATH'
-elif platform.system() == 'Windows':
- shlibpath_var = 'PATH'
-
-# in stand-alone builds, shlibdir is clang's build tree
-# while llvm_libs_dir is installed LLVM (and possibly older clang)
-llvm_shlib_dir = getattr(config, 'shlibdir', None)
-if not llvm_shlib_dir:
- lit_config.fatal('No shlibdir set!')
-# Point the dynamic loader at dynamic libraries in 'lib'.
-llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
-if not llvm_libs_dir:
- lit_config.fatal('No LLVM libs dir set!')
-shlibpath = os.path.pathsep.join((llvm_shlib_dir, llvm_libs_dir,
- config.environment.get(shlibpath_var,'')))
-
-config.environment[shlibpath_var] = shlibpath
diff --git a/test/Unit/lit.cfg.py b/test/Unit/lit.cfg.py
new file mode 100644
index 0000000000..f4bcdd76d1
--- /dev/null
+++ b/test/Unit/lit.cfg.py
@@ -0,0 +1,57 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import os
+import platform
+import subprocess
+
+import lit.formats
+import lit.util
+
+# name: The name of this test suite.
+config.name = 'Clang-Unit'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = []
+
+# test_source_root: The root path where tests are located.
+# test_exec_root: The root path where tests should be run.
+config.test_exec_root = os.path.join(config.clang_obj_root, 'unittests')
+config.test_source_root = config.test_exec_root
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, 'Tests')
+
+# Propagate the temp directory. Windows requires this because it uses \Windows\
+# if none of these are present.
+if 'TMP' in os.environ:
+ config.environment['TMP'] = os.environ['TMP']
+if 'TEMP' in os.environ:
+ config.environment['TEMP'] = os.environ['TEMP']
+
+# Propagate path to symbolizer for ASan/MSan.
+for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
+ if symbolizer in os.environ:
+ config.environment[symbolizer] = os.environ[symbolizer]
+
+def find_shlibpath_var():
+ if platform.system() in ['Linux', 'FreeBSD', 'NetBSD']:
+ yield 'LD_LIBRARY_PATH'
+ elif platform.system() == 'Darwin':
+ yield 'DYLD_LIBRARY_PATH'
+ elif platform.system() == 'Windows':
+ yield 'PATH'
+
+for shlibpath_var in find_shlibpath_var():
+ # in stand-alone builds, shlibdir is clang's build tree
+ # while llvm_libs_dir is installed LLVM (and possibly older clang)
+ shlibpath = os.path.pathsep.join(
+ (config.shlibdir,
+ config.llvm_libs_dir,
+ config.environment.get(shlibpath_var, '')))
+ config.environment[shlibpath_var] = shlibpath
+ break
+else:
+ lit_config.warning("unable to inject shared library path on '{}'"
+ .format(platform.system()))
diff --git a/test/Unit/lit.site.cfg.in b/test/Unit/lit.site.cfg.py.in
index c2f81463f2..715b4d93f5 100644
--- a/test/Unit/lit.site.cfg.in
+++ b/test/Unit/lit.site.cfg.py.in
@@ -25,4 +25,4 @@ except KeyError:
lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
# Let the main config do the real work.
-lit_config.load_config(config, "@CLANG_SOURCE_DIR@/test/Unit/lit.cfg")
+lit_config.load_config(config, "@CLANG_SOURCE_DIR@/test/Unit/lit.cfg.py")
diff --git a/test/clang-rename/ClassAsTemplateArgument.cpp b/test/clang-rename/ClassAsTemplateArgument.cpp
new file mode 100644
index 0000000000..2e09a5b529
--- /dev/null
+++ b/test/clang-rename/ClassAsTemplateArgument.cpp
@@ -0,0 +1,21 @@
+class Foo /* Test 1 */ {}; // CHECK: class Bar /* Test 1 */ {};
+
+template <typename T>
+void func() {}
+
+template <typename T>
+class Baz {};
+
+int main() {
+ func<Foo>(); // CHECK: func<Bar>();
+ Baz<Foo> /* Test 2 */ obj; // CHECK: Baz<Bar> /* Test 2 */ obj;
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=215 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/ClassFindByName.cpp b/test/clang-rename/ClassFindByName.cpp
new file mode 100644
index 0000000000..4430891ec4
--- /dev/null
+++ b/test/clang-rename/ClassFindByName.cpp
@@ -0,0 +1,10 @@
+class Foo { // CHECK: class Bar {
+};
+
+int main() {
+ Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
diff --git a/test/clang-rename/ClassSimpleRenaming.cpp b/test/clang-rename/ClassSimpleRenaming.cpp
new file mode 100644
index 0000000000..086f55736c
--- /dev/null
+++ b/test/clang-rename/ClassSimpleRenaming.cpp
@@ -0,0 +1,14 @@
+class Foo /* Test 1 */ { // CHECK: class Bar /* Test 1 */ {
+public:
+ void foo(int x);
+};
+
+void Foo::foo(int x) /* Test 2 */ {} // CHECK: void Bar::foo(int x) /* Test 2 */ {}
+
+// Test 1.
+// RUN: clang-rename -offset=6 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=109 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/ClassTestMulti.cpp b/test/clang-rename/ClassTestMulti.cpp
new file mode 100644
index 0000000000..81e65c7606
--- /dev/null
+++ b/test/clang-rename/ClassTestMulti.cpp
@@ -0,0 +1,11 @@
+class Foo1 /* Offset 1 */ { // CHECK: class Bar1 /* Offset 1 */ {
+};
+
+class Foo2 /* Offset 2 */ { // CHECK: class Bar2 /* Offset 2 */ {
+};
+
+// Test 1.
+// RUN: clang-rename -offset=6 -new-name=Bar1 -offset=76 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/ClassTestMultiByName.cpp b/test/clang-rename/ClassTestMultiByName.cpp
new file mode 100644
index 0000000000..61b69a1bdf
--- /dev/null
+++ b/test/clang-rename/ClassTestMultiByName.cpp
@@ -0,0 +1,8 @@
+class Foo1 { // CHECK: class Bar1
+};
+
+class Foo2 { // CHECK: class Bar2
+};
+
+// Test 1.
+// RUN: clang-rename -qualified-name=Foo1 -new-name=Bar1 -qualified-name=Foo2 -new-name=Bar2 %s -- | sed 's,//.*,,' | FileCheck %s
diff --git a/test/clang-rename/ComplexFunctionOverride.cpp b/test/clang-rename/ComplexFunctionOverride.cpp
new file mode 100644
index 0000000000..ccf3a20e54
--- /dev/null
+++ b/test/clang-rename/ComplexFunctionOverride.cpp
@@ -0,0 +1,47 @@
+struct A {
+ virtual void foo() {} /* Test 1 */ // CHECK: virtual void bar() {}
+};
+
+struct B : A {
+ void foo() override {} /* Test 2 */ // CHECK: void bar() override {}
+};
+
+struct C : B {
+ void foo() override {} /* Test 3 */ // CHECK: void bar() override {}
+};
+
+struct D : B {
+ void foo() override {} /* Test 4 */ // CHECK: void bar() override {}
+};
+
+struct E : D {
+ void foo() override {} /* Test 5 */ // CHECK: void bar() override {}
+};
+
+int main() {
+ A a;
+ a.foo(); // CHECK: a.bar();
+ B b;
+ b.foo(); // CHECK: b.bar();
+ C c;
+ c.foo(); // CHECK: c.bar();
+ D d;
+ d.foo(); // CHECK: d.bar();
+ E e;
+ e.foo(); // CHECK: e.bar();
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=26 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=109 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=201 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 4.
+// RUN: clang-rename -offset=293 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 5.
+// RUN: clang-rename -offset=385 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'foo.*' <file>
diff --git a/test/clang-rename/ComplicatedClassType.cpp b/test/clang-rename/ComplicatedClassType.cpp
new file mode 100644
index 0000000000..8801953031
--- /dev/null
+++ b/test/clang-rename/ComplicatedClassType.cpp
@@ -0,0 +1,63 @@
+// Forward declaration.
+class Foo; /* Test 1 */ // CHECK: class Bar; /* Test 1 */
+
+class Baz {
+ virtual int getValue() const = 0;
+};
+
+class Foo : public Baz { /* Test 2 */// CHECK: class Bar : public Baz {
+public:
+ Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) : x(value) {}
+
+ Foo &operator++(int) { // CHECK: Bar &operator++(int) {
+ x++;
+ return *this;
+ }
+
+ bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const &rhs) {
+ return this->x < rhs.x;
+ }
+
+ int getValue() const {
+ return 0;
+ }
+
+private:
+ int x;
+};
+
+int main() {
+ Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
+ Foo Variable = Foo(10); // CHECK: Bar Variable = Bar(10);
+ for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it < Variable; it++) {
+ }
+ const Foo *C = new Foo(); // CHECK: const Bar *C = new Bar();
+ const_cast<Foo *>(C)->getValue(); // CHECK: const_cast<Bar *>(C)->getValue();
+ Foo foo; // CHECK: Bar foo;
+ const Baz &BazReference = foo;
+ const Baz *BazPointer = &foo;
+ dynamic_cast<const Foo &>(BazReference).getValue(); /* Test 3 */ // CHECK: dynamic_cast<const Bar &>(BazReference).getValue();
+ dynamic_cast<const Foo *>(BazPointer)->getValue(); /* Test 4 */ // CHECK: dynamic_cast<const Bar *>(BazPointer)->getValue();
+ reinterpret_cast<const Foo *>(BazPointer)->getValue(); /* Test 5 */ // CHECK: reinterpret_cast<const Bar *>(BazPointer)->getValue();
+ static_cast<const Foo &>(BazReference).getValue(); /* Test 6 */ // CHECK: static_cast<const Bar &>(BazReference).getValue();
+ static_cast<const Foo *>(BazPointer)->getValue(); /* Test 7 */ // CHECK: static_cast<const Bar *>(BazPointer)->getValue();
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=30 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=155 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=1133 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 4.
+// RUN: clang-rename -offset=1266 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 5.
+// RUN: clang-rename -offset=1402 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 6.
+// RUN: clang-rename -offset=1533 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+// Test 7.
+// RUN: clang-rename -offset=1665 -new-name=Bar %s -- -frtti | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/Ctor.cpp b/test/clang-rename/Ctor.cpp
new file mode 100644
index 0000000000..9908a4123d
--- /dev/null
+++ b/test/clang-rename/Ctor.cpp
@@ -0,0 +1,14 @@
+class Foo { // CHECK: class Bar {
+public:
+ Foo(); /* Test 1 */ // CHECK: Bar();
+};
+
+Foo::Foo() /* Test 2 */ {} // CHECK: Bar::Bar() /* Test 2 */ {}
+
+// Test 1.
+// RUN: clang-rename -offset=62 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=116 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/CtorInitializer.cpp b/test/clang-rename/CtorInitializer.cpp
new file mode 100644
index 0000000000..fed4f5b06c
--- /dev/null
+++ b/test/clang-rename/CtorInitializer.cpp
@@ -0,0 +1,17 @@
+class Baz {};
+
+class Qux {
+ Baz Foo; /* Test 1 */ // CHECK: Baz Bar;
+public:
+ Qux();
+};
+
+Qux::Qux() : Foo() /* Test 2 */ {} // CHECK: Qux::Qux() : Bar() /* Test 2 */ {}
+
+// Test 1.
+// RUN: clang-rename -offset=33 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=118 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/DeclRefExpr.cpp b/test/clang-rename/DeclRefExpr.cpp
new file mode 100644
index 0000000000..6462862d82
--- /dev/null
+++ b/test/clang-rename/DeclRefExpr.cpp
@@ -0,0 +1,24 @@
+class C {
+public:
+ static int Foo; /* Test 1 */ // CHECK: static int Bar;
+};
+
+int foo(int x) { return 0; }
+#define MACRO(a) foo(a)
+
+int main() {
+ C::Foo = 1; /* Test 2 */ // CHECK: C::Bar = 1;
+ MACRO(C::Foo); // CHECK: MACRO(C::Bar);
+ int y = C::Foo; /* Test 3 */ // CHECK: int y = C::Bar;
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=31 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=152 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=271 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/ForceMulti.cpp b/test/clang-rename/ForceMulti.cpp
new file mode 100644
index 0000000000..41983ce260
--- /dev/null
+++ b/test/clang-rename/ForceMulti.cpp
@@ -0,0 +1,8 @@
+class B /* Test 1 */ { // CHECK: class B2 /* Test 1 */ {
+};
+
+class D : public B /* Test 1 */ { // CHECK: class D : public B2 /* Test 1 */ {
+};
+
+// Test 1.
+// RUN: clang-rename -force -qualified-name B -new-name B2 -qualified-name E -new-name E2 %s -- | sed 's,//.*,,' | FileCheck %s
diff --git a/test/clang-rename/FunctionMacro.cpp b/test/clang-rename/FunctionMacro.cpp
new file mode 100644
index 0000000000..6e87026ec7
--- /dev/null
+++ b/test/clang-rename/FunctionMacro.cpp
@@ -0,0 +1,20 @@
+#define moo foo // CHECK: #define moo macro_function
+
+int foo() /* Test 1 */ { // CHECK: int macro_function() /* Test 1 */ {
+ return 42;
+}
+
+void boo(int value) {}
+
+void qoo() {
+ foo(); // CHECK: macro_function();
+ boo(foo()); // CHECK: boo(macro_function());
+ moo();
+ boo(moo());
+}
+
+// Test 1.
+// RUN: clang-rename -offset=68 -new-name=macro_function %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'foo.*' <file>
diff --git a/test/clang-rename/FunctionOverride.cpp b/test/clang-rename/FunctionOverride.cpp
new file mode 100644
index 0000000000..adfeb739e6
--- /dev/null
+++ b/test/clang-rename/FunctionOverride.cpp
@@ -0,0 +1,13 @@
+class A { virtual void foo(); /* Test 1 */ }; // CHECK: class A { virtual void bar();
+class B : public A { void foo(); /* Test 2 */ }; // CHECK: class B : public A { void bar();
+class C : public B { void foo(); /* Test 3 */ }; // CHECK: class C : public B { void bar();
+
+// Test 1.
+// RUN: clang-rename -offset=23 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=116 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=209 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'foo.*' <file>
diff --git a/test/clang-rename/FunctionWithClassFindByName.cpp b/test/clang-rename/FunctionWithClassFindByName.cpp
new file mode 100644
index 0000000000..2cae09a1c2
--- /dev/null
+++ b/test/clang-rename/FunctionWithClassFindByName.cpp
@@ -0,0 +1,12 @@
+void foo() {
+}
+
+class Foo { // CHECK: class Bar
+};
+
+int main() {
+ Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
+ return 0;
+}
+
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
diff --git a/test/clang-rename/IncludeHeaderWithSymbol.cpp b/test/clang-rename/IncludeHeaderWithSymbol.cpp
new file mode 100644
index 0000000000..cb2baee57b
--- /dev/null
+++ b/test/clang-rename/IncludeHeaderWithSymbol.cpp
@@ -0,0 +1,10 @@
+#include "Inputs/HeaderWithSymbol.h"
+
+int main() {
+ return 0; // CHECK: {{^ return 0;}}
+}
+
+// Test 1.
+// The file IncludeHeaderWithSymbol.cpp doesn't contain the symbol Foo
+// and is expected to be written to stdout without modifications
+// RUN: clang-rename -qualified-name=Foo -new-name=Bar %s -- | FileCheck %s
diff --git a/test/clang-rename/Inputs/HeaderWithSymbol.h b/test/clang-rename/Inputs/HeaderWithSymbol.h
new file mode 100644
index 0000000000..1fe02e8978
--- /dev/null
+++ b/test/clang-rename/Inputs/HeaderWithSymbol.h
@@ -0,0 +1 @@
+struct Foo {};
diff --git a/test/clang-rename/Inputs/OffsetToNewName.yaml b/test/clang-rename/Inputs/OffsetToNewName.yaml
new file mode 100644
index 0000000000..d8e972880f
--- /dev/null
+++ b/test/clang-rename/Inputs/OffsetToNewName.yaml
@@ -0,0 +1,6 @@
+---
+- Offset: 6
+ NewName: Bar1
+- Offset: 44
+ NewName: Bar2
+...
diff --git a/test/clang-rename/Inputs/QualifiedNameToNewName.yaml b/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
new file mode 100644
index 0000000000..6e3783671d
--- /dev/null
+++ b/test/clang-rename/Inputs/QualifiedNameToNewName.yaml
@@ -0,0 +1,6 @@
+---
+- QualifiedName: Foo1
+ NewName: Bar1
+- QualifiedName: Foo2
+ NewName: Bar2
+...
diff --git a/test/clang-rename/InvalidNewName.cpp b/test/clang-rename/InvalidNewName.cpp
new file mode 100644
index 0000000000..e6b38e5942
--- /dev/null
+++ b/test/clang-rename/InvalidNewName.cpp
@@ -0,0 +1,2 @@
+// RUN: not clang-rename -new-name=class -offset=133 %s 2>&1 | FileCheck %s
+// CHECK: ERROR: new name is not a valid identifier in C++17.
diff --git a/test/clang-rename/InvalidOffset.cpp b/test/clang-rename/InvalidOffset.cpp
new file mode 100644
index 0000000000..2ae04d01e4
--- /dev/null
+++ b/test/clang-rename/InvalidOffset.cpp
@@ -0,0 +1,9 @@
+#include "Inputs/HeaderWithSymbol.h"
+#define FOO int bar;
+FOO
+
+int foo;
+
+// RUN: not clang-rename -new-name=qux -offset=259 %s -- 2>&1 | FileCheck %s
+// CHECK-NOT: CHECK
+// CHECK: error: SourceLocation in file {{.*}}InvalidOffset.cpp at offset 259 is invalid
diff --git a/test/clang-rename/InvalidQualifiedName.cpp b/test/clang-rename/InvalidQualifiedName.cpp
new file mode 100644
index 0000000000..5280e3939c
--- /dev/null
+++ b/test/clang-rename/InvalidQualifiedName.cpp
@@ -0,0 +1,4 @@
+struct S {
+};
+
+// RUN: clang-rename -force -qualified-name S2 -new-name=T %s --
diff --git a/test/clang-rename/MemberExprMacro.cpp b/test/clang-rename/MemberExprMacro.cpp
new file mode 100644
index 0000000000..56cd8d95f6
--- /dev/null
+++ b/test/clang-rename/MemberExprMacro.cpp
@@ -0,0 +1,22 @@
+class Baz {
+public:
+ int Foo; /* Test 1 */ // CHECK: int Bar;
+};
+
+int qux(int x) { return 0; }
+#define MACRO(a) qux(a)
+
+int main() {
+ Baz baz;
+ baz.Foo = 1; /* Test 2 */ // CHECK: baz.Bar = 1;
+ MACRO(baz.Foo); // CHECK: MACRO(baz.Bar);
+ int y = baz.Foo; // CHECK: int y = baz.Bar;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=26 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=155 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/Namespace.cpp b/test/clang-rename/Namespace.cpp
new file mode 100644
index 0000000000..ec9630fded
--- /dev/null
+++ b/test/clang-rename/Namespace.cpp
@@ -0,0 +1,13 @@
+namespace gcc /* Test 1 */ { // CHECK: namespace clang /* Test 1 */ {
+ int x;
+}
+
+void boo() {
+ gcc::x = 42; // CHECK: clang::x = 42;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=10 -new-name=clang %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/NoNewName.cpp b/test/clang-rename/NoNewName.cpp
new file mode 100644
index 0000000000..4f882d83b0
--- /dev/null
+++ b/test/clang-rename/NoNewName.cpp
@@ -0,0 +1,4 @@
+// Check for an error while -new-name argument has not been passed to
+// clang-rename.
+// RUN: not clang-rename -offset=133 %s 2>&1 | FileCheck %s
+// CHECK: clang-rename: -new-name must be specified.
diff --git a/test/clang-rename/TemplateClassInstantiation.cpp b/test/clang-rename/TemplateClassInstantiation.cpp
new file mode 100644
index 0000000000..493d0951df
--- /dev/null
+++ b/test/clang-rename/TemplateClassInstantiation.cpp
@@ -0,0 +1,42 @@
+template <typename T>
+class Foo { /* Test 1 */ // CHECK: class Bar { /* Test 1 */
+public:
+ T foo(T arg, T& ref, T* ptr) {
+ T value;
+ int number = 42;
+ value = (T)number;
+ value = static_cast<T>(number);
+ return value;
+ }
+ static void foo(T value) {}
+ T member;
+};
+
+template <typename T>
+void func() {
+ Foo<T> obj; /* Test 2 */ // CHECK: Bar<T> obj;
+ obj.member = T();
+ Foo<T>::foo(); // CHECK: Bar<T>::foo();
+}
+
+int main() {
+ Foo<int> i; /* Test 3 */ // CHECK: Bar<int> i;
+ i.member = 0;
+ Foo<int>::foo(0); // CHECK: Bar<int>::foo(0);
+
+ Foo<bool> b; // CHECK: Bar<bool> b;
+ b.member = false;
+ Foo<bool>::foo(false); // CHECK: Bar<bool>::foo(false);
+
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=29 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=324 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=463 -new-name=Bar %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/TemplateTypename.cpp b/test/clang-rename/TemplateTypename.cpp
new file mode 100644
index 0000000000..559ec1f9ad
--- /dev/null
+++ b/test/clang-rename/TemplateTypename.cpp
@@ -0,0 +1,24 @@
+template <typename T /* Test 1 */> // CHECK: template <typename U /* Test 1 */>
+class Foo {
+T foo(T arg, T& ref, T* /* Test 2 */ ptr) { // CHECK: U foo(U arg, U& ref, U* /* Test 2 */ ptr) {
+ T value; // CHECK: U value;
+ int number = 42;
+ value = (T)number; // CHECK: value = (U)number;
+ value = static_cast<T /* Test 3 */>(number); // CHECK: value = static_cast<U /* Test 3 */>(number);
+ return value;
+}
+
+static void foo(T value) {} // CHECK: static void foo(U value) {}
+
+T member; // CHECK: U member;
+};
+
+// Test 1.
+// RUN: clang-rename -offset=19 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=126 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=392 -new-name=U %s -- -fno-delayed-template-parsing | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'T.*' <file>
diff --git a/test/clang-rename/TemplatedClassFunction.cpp b/test/clang-rename/TemplatedClassFunction.cpp
new file mode 100644
index 0000000000..d7f21e0847
--- /dev/null
+++ b/test/clang-rename/TemplatedClassFunction.cpp
@@ -0,0 +1,27 @@
+template <typename T>
+class A {
+public:
+ void foo() /* Test 1 */ {} // CHECK: void bar() /* Test 1 */ {}
+};
+
+int main(int argc, char **argv) {
+ A<int> a;
+ A<double> b;
+ A<float> c;
+ a.foo(); /* Test 2 */ // CHECK: a.bar(); /* Test 2 */
+ b.foo(); /* Test 3 */ // CHECK: b.bar(); /* Test 3 */
+ c.foo(); /* Test 4 */ // CHECK: c.bar(); /* Test 4 */
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=48 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=191 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=255 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 4.
+// RUN: clang-rename -offset=319 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'foo.*' <file>
diff --git a/test/clang-rename/UserDefinedConversion.cpp b/test/clang-rename/UserDefinedConversion.cpp
new file mode 100644
index 0000000000..60f251ab44
--- /dev/null
+++ b/test/clang-rename/UserDefinedConversion.cpp
@@ -0,0 +1,26 @@
+class Foo { /* Test 1 */ // CHECK: class Bar {
+public:
+ Foo() {} // CHECK: Bar() {}
+};
+
+class Baz {
+public:
+ operator Foo() /* Test 2 */ const { // CHECK: operator Bar() /* Test 2 */ const {
+ Foo foo; // CHECK: Bar foo;
+ return foo;
+ }
+};
+
+int main() {
+ Baz boo;
+ Foo foo = static_cast<Foo>(boo); // CHECK: Bar foo = static_cast<Bar>(boo);
+ return 0;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=7 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=164 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/Variable.cpp b/test/clang-rename/Variable.cpp
new file mode 100644
index 0000000000..d7e670fb43
--- /dev/null
+++ b/test/clang-rename/Variable.cpp
@@ -0,0 +1,33 @@
+#define NAMESPACE namespace A
+NAMESPACE {
+int Foo; /* Test 1 */ // CHECK: int Bar;
+}
+int Foo; // CHECK: int Foo;
+int Qux = Foo; // CHECK: int Qux = Foo;
+int Baz = A::Foo; /* Test 2 */ // CHECK: Baz = A::Bar;
+void fun() {
+ struct {
+ int Foo; // CHECK: int Foo;
+ } b = {100};
+ int Foo = 100; // CHECK: int Foo = 100;
+ Baz = Foo; // CHECK: Baz = Foo;
+ {
+ extern int Foo; // CHECK: extern int Foo;
+ Baz = Foo; // CHECK: Baz = Foo;
+ Foo = A::Foo /* Test 3 */ + Baz; // CHECK: Foo = A::Bar /* Test 3 */ + Baz;
+ A::Foo /* Test 4 */ = b.Foo; // CHECK: A::Bar /* Test 4 */ = b.Foo;
+ }
+ Foo = b.Foo; // Foo = b.Foo;
+}
+
+// Test 1.
+// RUN: clang-rename -offset=46 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=234 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=641 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 4.
+// RUN: clang-rename -offset=716 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/VariableMacro.cpp b/test/clang-rename/VariableMacro.cpp
new file mode 100644
index 0000000000..622e825d3e
--- /dev/null
+++ b/test/clang-rename/VariableMacro.cpp
@@ -0,0 +1,21 @@
+#define Baz Foo // CHECK: #define Baz Bar
+
+void foo(int value) {}
+
+void macro() {
+ int Foo; /* Test 1 */ // CHECK: int Bar;
+ Foo = 42; /* Test 2 */ // CHECK: Bar = 42;
+ Baz -= 0;
+ foo(Foo); /* Test 3 */ // CHECK: foo(Bar);
+ foo(Baz);
+}
+
+// Test 1.
+// RUN: clang-rename -offset=88 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -offset=129 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 3.
+// RUN: clang-rename -offset=191 -new-name=Bar %s -- | sed 's,//.*,,' | FileCheck %s
+
+// To find offsets after modifying the file, use:
+// grep -Ubo 'Foo.*' <file>
diff --git a/test/clang-rename/YAMLInput.cpp b/test/clang-rename/YAMLInput.cpp
new file mode 100644
index 0000000000..55dbc6d66a
--- /dev/null
+++ b/test/clang-rename/YAMLInput.cpp
@@ -0,0 +1,10 @@
+class Foo1 { // CHECK: class Bar1
+};
+
+class Foo2 { // CHECK: class Bar2
+};
+
+// Test 1.
+// RUN: clang-rename -input %S/Inputs/OffsetToNewName.yaml %s -- | sed 's,//.*,,' | FileCheck %s
+// Test 2.
+// RUN: clang-rename -input %S/Inputs/QualifiedNameToNewName.yaml %s -- | sed 's,//.*,,' | FileCheck %s
diff --git a/test/lit.cfg b/test/lit.cfg
deleted file mode 100644
index 5beecb65bd..0000000000
--- a/test/lit.cfg
+++ /dev/null
@@ -1,523 +0,0 @@
-# -*- Python -*-
-
-import os
-import platform
-import re
-import subprocess
-import tempfile
-
-import lit.formats
-import lit.util
-
-# Configuration file for the 'lit' test runner.
-
-# name: The name of this test suite.
-config.name = 'Clang'
-
-# Tweak PATH for Win32
-if platform.system() == 'Windows':
- # Seek sane tools in directories and set to $PATH.
- path = getattr(config, 'lit_tools_dir', None)
- path = lit_config.getToolsPath(path,
- config.environment['PATH'],
- ['cmp.exe', 'grep.exe', 'sed.exe'])
- if path is not None:
- path = os.path.pathsep.join((path,
- config.environment['PATH']))
- config.environment['PATH'] = path
-
-# Choose between lit's internal shell pipeline runner and a real shell. If
-# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
-use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
-if use_lit_shell:
- # 0 is external, "" is default, and everything else is internal.
- execute_external = (use_lit_shell == "0")
-else:
- # Otherwise we default to internal on Windows and external elsewhere, as
- # bash on Windows is usually very slow.
- execute_external = (not sys.platform in ['win32'])
-
-# testFormat: The test format to use to interpret tests.
-#
-# For now we require '&&' between commands, until they get globally killed and
-# the test runner updated.
-config.test_format = lit.formats.ShTest(execute_external)
-
-# suffixes: A list of file extensions to treat as test files.
-config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs']
-
-# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
-# subdirectories contain auxiliary inputs for various tests in their parent
-# directories.
-config.excludes = ['Inputs', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt']
-
-# test_source_root: The root path where tests are located.
-config.test_source_root = os.path.dirname(__file__)
-
-# test_exec_root: The root path where tests should be run.
-clang_obj_root = getattr(config, 'clang_obj_root', None)
-if clang_obj_root is not None:
- config.test_exec_root = os.path.join(clang_obj_root, 'test')
-
-# Set llvm_{src,obj}_root for use by others.
-config.llvm_src_root = getattr(config, 'llvm_src_root', None)
-config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)
-
-# Clear some environment variables that might affect Clang.
-#
-# This first set of vars are read by Clang, but shouldn't affect tests
-# that aren't specifically looking for these features, or are required
-# simply to run the tests at all.
-#
-# FIXME: Should we have a tool that enforces this?
-
-# safe_env_vars = ('TMPDIR', 'TEMP', 'TMP', 'USERPROFILE', 'PWD',
-# 'MACOSX_DEPLOYMENT_TARGET', 'IPHONEOS_DEPLOYMENT_TARGET',
-# 'VCINSTALLDIR', 'VC100COMNTOOLS', 'VC90COMNTOOLS',
-# 'VC80COMNTOOLS')
-possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
- 'CINDEXTEST_PREAMBLE_FILE', 'LIBRARY_PATH',
- 'CPATH', 'C_INCLUDE_PATH', 'CPLUS_INCLUDE_PATH',
- 'OBJC_INCLUDE_PATH', 'OBJCPLUS_INCLUDE_PATH',
- 'LIBCLANG_TIMING', 'LIBCLANG_OBJTRACKING',
- 'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX',
- 'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS',
- 'LIBCLANG_RESOURCE_USAGE',
- 'LIBCLANG_CODE_COMPLETION_LOGGING']
-# Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it.
-if platform.system() != 'Windows':
- possibly_dangerous_env_vars.append('INCLUDE')
-for name in possibly_dangerous_env_vars:
- if name in config.environment:
- del config.environment[name]
-
-# Tweak the PATH to include the tools dir and the scripts dir.
-if clang_obj_root is not None:
- clang_tools_dir = getattr(config, 'clang_tools_dir', None)
- if not clang_tools_dir:
- lit_config.fatal('No Clang tools dir set!')
- llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
- if not llvm_tools_dir:
- lit_config.fatal('No LLVM tools dir set!')
- path = os.path.pathsep.join((
- clang_tools_dir, llvm_tools_dir, config.environment['PATH']))
- config.environment['PATH'] = path
- # in stand-alone builds, llvm_shlib_dir is clang's build tree
- # while llvm_libs_dir is installed LLVM (and possibly older clang)
- llvm_shlib_dir = getattr(config, 'llvm_shlib_dir', None)
- if not llvm_shlib_dir:
- lit_config.fatal('No LLVM shlib dir set!')
- llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
- if not llvm_libs_dir:
- lit_config.fatal('No LLVM libs dir set!')
- path = os.path.pathsep.join((llvm_shlib_dir, llvm_libs_dir,
- config.environment.get('LD_LIBRARY_PATH','')))
- config.environment['LD_LIBRARY_PATH'] = path
-
-# Propagate path to symbolizer for ASan/MSan.
-for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
- if symbolizer in os.environ:
- config.environment[symbolizer] = os.environ[symbolizer]
-
-###
-
-# Check that the object root is known.
-if config.test_exec_root is None:
- # Otherwise, we haven't loaded the site specific configuration (the user is
- # probably trying to run on a test file directly, and either the site
- # configuration hasn't been created by the build system, or we are in an
- # out-of-tree build situation).
-
- # Check for 'clang_site_config' user parameter, and use that if available.
- site_cfg = lit_config.params.get('clang_site_config', None)
- if site_cfg and os.path.exists(site_cfg):
- lit_config.load_config(config, site_cfg)
- raise SystemExit
-
- # Try to detect the situation where we are using an out-of-tree build by
- # looking for 'llvm-config'.
- #
- # FIXME: I debated (i.e., wrote and threw away) adding logic to
- # automagically generate the lit.site.cfg if we are in some kind of fresh
- # build situation. This means knowing how to invoke the build system though,
- # and I decided it was too much magic. We should solve this by just having
- # the .cfg files generated during the configuration step.
-
- llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
- if not llvm_config:
- lit_config.fatal('No site specific configuration available!')
-
- # Get the source and object roots.
- llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
- llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
- clang_src_root = os.path.join(llvm_src_root, "tools", "clang")
- clang_obj_root = os.path.join(llvm_obj_root, "tools", "clang")
-
- # Validate that we got a tree which points to here, using the standard
- # tools/clang layout.
- this_src_root = os.path.dirname(config.test_source_root)
- if os.path.realpath(clang_src_root) != os.path.realpath(this_src_root):
- lit_config.fatal('No site specific configuration available!')
-
- # Check that the site specific configuration exists.
- site_cfg = os.path.join(clang_obj_root, 'test', 'lit.site.cfg')
- if not os.path.exists(site_cfg):
- lit_config.fatal(
- 'No site specific configuration available! You may need to '
- 'run "make test" in your Clang build directory.')
-
- # Okay, that worked. Notify the user of the automagic, and reconfigure.
- lit_config.note('using out-of-tree build at %r' % clang_obj_root)
- lit_config.load_config(config, site_cfg)
- raise SystemExit
-
-###
-
-# Discover the 'clang' and 'clangcc' to use.
-
-import os
-
-def inferClang(PATH):
- # Determine which clang to use.
- clang = os.getenv('CLANG')
-
- # If the user set clang in the environment, definitely use that and don't
- # try to validate.
- if clang:
- return clang
-
- # Otherwise look in the path.
- clang = lit.util.which('clang', PATH)
-
- if not clang:
- lit_config.fatal("couldn't find 'clang' program, try setting "
- "CLANG in your environment")
-
- return clang
-
-config.clang = inferClang(config.environment['PATH']).replace('\\', '/')
-if not lit_config.quiet:
- lit_config.note('using clang: %r' % config.clang)
-
-# Plugins (loadable modules)
-# TODO: This should be supplied by Makefile or autoconf.
-if sys.platform in ['win32', 'cygwin']:
- has_plugins = config.enable_shared
-else:
- has_plugins = True
-
-if has_plugins and config.llvm_plugin_ext:
- config.available_features.add('plugins')
-
-config.substitutions.append( ('%llvmshlibdir', config.llvm_shlib_dir) )
-config.substitutions.append( ('%pluginext', config.llvm_plugin_ext) )
-config.substitutions.append( ('%PATH%', config.environment['PATH']) )
-
-if config.clang_examples:
- config.available_features.add('examples')
-
-# Note that when substituting %clang_cc1 also fill in the include directory of
-# the builtin headers. Those are part of even a freestanding environment, but
-# Clang relies on the driver to locate them.
-def getClangBuiltinIncludeDir(clang):
- # FIXME: Rather than just getting the version, we should have clang print
- # out its resource dir here in an easy to scrape form.
- cmd = subprocess.Popen([clang, '-print-file-name=include'],
- stdout=subprocess.PIPE,
- env=config.environment)
- if not cmd.stdout:
- lit_config.fatal("Couldn't find the include dir for Clang ('%s')" % clang)
- dir = cmd.stdout.read().strip()
- if sys.platform in ['win32'] and execute_external:
- # Don't pass dosish path separator to msys bash.exe.
- dir = dir.replace('\\', '/')
- # Ensure the result is an ascii string, across Python2.5+ - Python3.
- return str(dir.decode('ascii'))
-
-def makeItaniumABITriple(triple):
- m = re.match(r'(\w+)-(\w+)-(\w+)', triple)
- if not m:
- lit_config.fatal("Could not turn '%s' into Itanium ABI triple" % triple)
- if m.group(3).lower() != 'win32':
- # All non-win32 triples use the Itanium ABI.
- return triple
- return m.group(1) + '-' + m.group(2) + '-mingw32'
-
-def makeMSABITriple(triple):
- m = re.match(r'(\w+)-(\w+)-(\w+)', triple)
- if not m:
- lit_config.fatal("Could not turn '%s' into MS ABI triple" % triple)
- isa = m.group(1).lower()
- vendor = m.group(2).lower()
- os = m.group(3).lower()
- 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):
- # 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,
- getClangBuiltinIncludeDir(config.clang))) )
-config.substitutions.append( ('%clang_cpp', ' ' + config.clang +
- ' --driver-mode=cpp '))
-config.substitutions.append( ('%clang_cl', ' ' + config.clang +
- ' --driver-mode=cl '))
-config.substitutions.append( ('%clangxx', ' ' + config.clang +
- ' --driver-mode=g++ '))
-config.substitutions.append( ('%clang', ' ' + config.clang + ' ') )
-config.substitutions.append( ('%test_debuginfo', ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ') )
-config.substitutions.append( ('%itanium_abi_triple', makeItaniumABITriple(config.target_triple)) )
-config.substitutions.append( ('%ms_abi_triple', makeMSABITriple(config.target_triple)) )
-config.substitutions.append( ('%resource_dir', getClangBuiltinIncludeDir(config.clang)) )
-
-# The host triple might not be set, at least if we're compiling clang from
-# an already installed llvm.
-if config.host_triple and config.host_triple != '@LLVM_HOST_TRIPLE@':
- config.substitutions.append( ('%target_itanium_abi_host_triple', '--target=%s' % makeItaniumABITriple(config.host_triple)) )
-else:
- config.substitutions.append( ('%target_itanium_abi_host_triple', '') )
-
-# FIXME: Find nicer way to prohibit this.
-config.substitutions.append(
- (' clang ', """*** Do not use 'clang' in tests, use '%clang'. ***""") )
-config.substitutions.append(
- (' clang\+\+ ', """*** Do not use 'clang++' in tests, use '%clangxx'. ***"""))
-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(
- (' %clang-cc1 ',
- """*** invalid substitution, use '%clang_cc1'. ***""") )
-config.substitutions.append(
- (' %clang-cpp ',
- """*** invalid substitution, use '%clang_cpp'. ***""") )
-config.substitutions.append(
- (' %clang-cl ',
- """*** invalid substitution, use '%clang_cl'. ***""") )
-
-# For each occurrence of a clang tool name as its own word, replace it
-# with the full path to the build directory holding that tool. This
-# ensures that we are testing the tools just built and not some random
-# tools that might happen to be in the user's PATH.
-tool_dirs = os.path.pathsep.join((clang_tools_dir, llvm_tools_dir))
-
-# Regex assertions to reject neighbor hyphens/dots (seen in some tests).
-# For example, don't match 'clang-check-' or '.clang-format'.
-NoPreHyphenDot = r"(?<!(-|\.))"
-NoPostHyphenDot = r"(?!(-|\.))"
-NoPostBar = r"(?!(/|\\))"
-
-tool_patterns = [r"\bFileCheck\b",
- r"\bc-index-test\b",
- NoPreHyphenDot + r"\bclang-check\b" + NoPostHyphenDot,
- NoPreHyphenDot + r"\bclang-format\b" + NoPostHyphenDot,
- # FIXME: Some clang test uses opt?
- NoPreHyphenDot + r"\bopt\b" + NoPostBar + NoPostHyphenDot,
- # Handle these specially as they are strings searched
- # for during testing.
- r"\| \bcount\b",
- r"\| \bnot\b"]
-
-if config.clang_examples:
- tool_patterns.append(NoPreHyphenDot + r"\bclang-interpreter\b" + NoPostHyphenDot)
-
-for pattern in tool_patterns:
- # Extract the tool name from the pattern. This relies on the tool
- # name being surrounded by \b word match operators. If the
- # pattern starts with "| ", include it in the string to be
- # substituted.
- tool_match = re.match(r"^(\\)?((\| )?)\W+b([0-9A-Za-z-_]+)\\b\W*$",
- pattern)
- tool_pipe = tool_match.group(2)
- tool_name = tool_match.group(4)
- tool_path = lit.util.which(tool_name, tool_dirs)
- if not tool_path:
- # Warn, but still provide a substitution.
- lit_config.note('Did not find ' + tool_name + ' in ' + tool_dirs)
- tool_path = clang_tools_dir + '/' + tool_name
- config.substitutions.append((pattern, tool_pipe + tool_path))
-
-###
-
-# Set available features we allow tests to conditionalize on.
-#
-if config.clang_default_cxx_stdlib != '':
- config.available_features.add('default-cxx-stdlib-set')
-
-# Enabled/disabled features
-if config.clang_staticanalyzer:
- config.available_features.add("staticanalyzer")
-
-# 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')
-
-# Shell execution
-if execute_external:
- config.available_features.add('shell')
-
-# For tests that require Darwin to run.
-# This is used by debuginfo-tests/*block*.m and debuginfo-tests/foreach.m.
-if platform.system() in ['Darwin']:
- config.available_features.add('system-darwin')
-elif platform.system() in ['Windows']:
- # For tests that require Windows to run.
- config.available_features.add('system-windows')
-
-# ANSI escape sequences in non-dumb terminal
-if platform.system() not in ['Windows']:
- config.available_features.add('ansi-escape-sequences')
-
-# Capability to print utf8 to the terminal.
-# Windows expects codepage, unless Wide API.
-if platform.system() not in ['Windows']:
- config.available_features.add('utf8-capable-terminal')
-
-# Support for libgcc runtime. Used to rule out tests that require
-# clang to run with -rtlib=libgcc.
-if platform.system() not in ['Darwin', 'Fuchsia']:
- config.available_features.add('libgcc')
-
-# Native compilation: Check if triples match.
-# FIXME: Consider cases that target can be executed
-# even if host_triple were different from target_triple.
-if config.host_triple == config.target_triple:
- config.available_features.add("native")
-
-# Test Driver/arch-specific-libdir-rpath.c is restricted to x86_64-linux
-if re.match(r'^x86_64.*-linux', config.target_triple):
- config.available_features.add("x86_64-linux")
-
-# Case-insensitive file system
-def is_filesystem_case_insensitive():
- handle, path = tempfile.mkstemp(prefix='case-test', dir=config.test_exec_root)
- isInsensitive = os.path.exists(
- os.path.join(
- os.path.dirname(path),
- os.path.basename(path).upper()
- ))
- os.close(handle)
- os.remove(path)
- return isInsensitive
-
-if is_filesystem_case_insensitive():
- config.available_features.add('case-insensitive-filesystem')
-
-# Tests that require the /dev/fd filesystem.
-if os.path.exists("/dev/fd/0") and sys.platform not in ['cygwin']:
- config.available_features.add('dev-fd-fs')
-
-# Not set on native MS environment.
-if not re.match(r'.*-win32$', config.target_triple):
- config.available_features.add('non-ms-sdk')
-
-# Not set on native PS4 environment.
-if not re.match(r'.*-scei-ps4', config.target_triple):
- config.available_features.add('non-ps4-sdk')
-
-# [PR8833] LLP64-incompatible tests
-if not re.match(r'^x86_64.*-(win32|mingw32|windows-gnu)$', config.target_triple):
- config.available_features.add('LP64')
-
-# [PR12920] "clang-driver" -- set if gcc driver is not used.
-if not re.match(r'.*-(cygwin)$', config.target_triple):
- config.available_features.add('clang-driver')
-
-# [PR18856] Depends to remove opened file. On win32, a file could be removed
-# only if all handles were closed.
-if platform.system() not in ['Windows']:
- config.available_features.add('can-remove-opened-file')
-
-# Returns set of available features, registered-target(s) and asserts.
-def get_llvm_config_props():
- set_of_features = set()
-
- cmd = subprocess.Popen(
- [
- os.path.join(llvm_tools_dir, 'llvm-config'),
- '--assertion-mode',
- '--targets-built',
- ],
- stdout=subprocess.PIPE,
- env=config.environment
- )
- # 1st line corresponds to --assertion-mode, "ON" or "OFF".
- line = cmd.stdout.readline().strip().decode('ascii')
- if line == "ON":
- set_of_features.add('asserts')
-
- # 2nd line corresponds to --targets-built, like;
- # AArch64 ARM CppBackend X86
- for arch in cmd.stdout.readline().decode('ascii').split():
- set_of_features.add(arch.lower() + '-registered-target')
-
- return set_of_features
-
-config.available_features.update(get_llvm_config_props())
-
-if lit.util.which('xmllint'):
- config.available_features.add('xmllint')
-
-# Sanitizers.
-if 'Address' in config.llvm_use_sanitizer:
- config.available_features.add("asan")
-else:
- config.available_features.add("not_asan")
-if 'Memory' in config.llvm_use_sanitizer:
- config.available_features.add("msan")
-if 'Undefined' in config.llvm_use_sanitizer:
- config.available_features.add("ubsan")
-else:
- config.available_features.add("not_ubsan")
-
-if config.enable_backtrace:
- config.available_features.add("backtrace")
-
-if config.have_zlib:
- config.available_features.add("zlib")
-else:
- config.available_features.add("nozlib")
-
-# Check if we should run long running tests.
-if lit_config.params.get("run_long_tests", None) == "true":
- config.available_features.add("long_tests")
-
-# Check if we should use gmalloc.
-use_gmalloc_str = lit_config.params.get('use_gmalloc', None)
-if use_gmalloc_str is not None:
- if use_gmalloc_str.lower() in ('1', 'true'):
- use_gmalloc = True
- elif use_gmalloc_str.lower() in ('', '0', 'false'):
- use_gmalloc = False
- else:
- lit_config.fatal('user parameter use_gmalloc should be 0 or 1')
-else:
- # Default to not using gmalloc
- use_gmalloc = False
-
-# Allow use of an explicit path for gmalloc library.
-# Will default to '/usr/lib/libgmalloc.dylib' if not set.
-gmalloc_path_str = lit_config.params.get('gmalloc_path',
- '/usr/lib/libgmalloc.dylib')
-if use_gmalloc:
- config.environment.update({'DYLD_INSERT_LIBRARIES' : gmalloc_path_str})
-
-# Check if we should allow outputs to console.
-run_console_tests = int(lit_config.params.get('enable_console', '0'))
-if run_console_tests != 0:
- config.available_features.add('console')
-
-lit.util.usePlatformSdkOnDarwin(config, lit_config)
diff --git a/test/lit.cfg.py b/test/lit.cfg.py
new file mode 100644
index 0000000000..39bdf36afd
--- /dev/null
+++ b/test/lit.cfg.py
@@ -0,0 +1,184 @@
+# -*- Python -*-
+
+import os
+import platform
+import re
+import subprocess
+import tempfile
+
+import lit.formats
+import lit.util
+
+from lit.llvm import llvm_config
+from lit.llvm.subst import ToolSubst
+from lit.llvm.subst import FindTool
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'Clang'
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu',
+ '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs']
+
+# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
+# subdirectories contain auxiliary inputs for various tests in their parent
+# directories.
+config.excludes = ['Inputs', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+config.test_exec_root = os.path.join(config.clang_obj_root, 'test')
+
+llvm_config.use_default_substitutions()
+
+llvm_config.use_clang()
+
+# Propagate path to symbolizer for ASan/MSan.
+llvm_config.with_system_environment(
+ ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH'])
+
+config.substitutions.append(('%PATH%', config.environment['PATH']))
+
+
+# For each occurrence of a clang tool name, replace it with the full path to
+# the build directory holding that tool. We explicitly specify the directories
+# to search to ensure that we get the tools just built and not some random
+# tools that might happen to be in the user's PATH.
+tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir]
+
+tools = [
+ 'c-index-test', 'clang-check', 'clang-diff', 'clang-format', 'opt',
+ ToolSubst('%test_debuginfo', command=os.path.join(
+ config.llvm_src_root, 'utils', 'test_debuginfo.pl')),
+ ToolSubst('%clang_func_map', command=FindTool(
+ 'clang-func-mapping'), unresolved='ignore'),
+]
+
+if config.clang_examples:
+ tools.append('clang-interpreter')
+
+llvm_config.add_tool_substitutions(tools, tool_dirs)
+
+# Plugins (loadable modules)
+# TODO: This should be supplied by Makefile or autoconf.
+if sys.platform in ['win32', 'cygwin']:
+ has_plugins = config.enable_shared
+else:
+ has_plugins = True
+
+if has_plugins and config.llvm_plugin_ext:
+ config.available_features.add('plugins')
+
+# Set available features we allow tests to conditionalize on.
+#
+if config.clang_default_cxx_stdlib != '':
+ config.available_features.add('default-cxx-stdlib-set')
+
+# Enabled/disabled features
+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')
+
+# ANSI escape sequences in non-dumb terminal
+if platform.system() not in ['Windows']:
+ config.available_features.add('ansi-escape-sequences')
+
+# Capability to print utf8 to the terminal.
+# Windows expects codepage, unless Wide API.
+if platform.system() not in ['Windows']:
+ config.available_features.add('utf8-capable-terminal')
+
+# Support for libgcc runtime. Used to rule out tests that require
+# clang to run with -rtlib=libgcc.
+if platform.system() not in ['Darwin', 'Fuchsia']:
+ config.available_features.add('libgcc')
+
+# Case-insensitive file system
+
+
+def is_filesystem_case_insensitive():
+ handle, path = tempfile.mkstemp(
+ prefix='case-test', dir=config.test_exec_root)
+ isInsensitive = os.path.exists(
+ os.path.join(
+ os.path.dirname(path),
+ os.path.basename(path).upper()
+ ))
+ os.close(handle)
+ os.remove(path)
+ return isInsensitive
+
+
+if is_filesystem_case_insensitive():
+ config.available_features.add('case-insensitive-filesystem')
+
+# Tests that require the /dev/fd filesystem.
+if os.path.exists('/dev/fd/0') and sys.platform not in ['cygwin']:
+ config.available_features.add('dev-fd-fs')
+
+# Not set on native MS environment.
+if not re.match(r'.*-win32$', config.target_triple):
+ config.available_features.add('non-ms-sdk')
+
+# Not set on native PS4 environment.
+if not re.match(r'.*-scei-ps4', config.target_triple):
+ config.available_features.add('non-ps4-sdk')
+
+# [PR8833] LLP64-incompatible tests
+if not re.match(r'^x86_64.*-(win32|mingw32|windows-gnu)$', config.target_triple):
+ config.available_features.add('LP64')
+
+# [PR12920] "clang-driver" -- set if gcc driver is not used.
+if not re.match(r'.*-(cygwin)$', config.target_triple):
+ config.available_features.add('clang-driver')
+
+# [PR18856] Depends to remove opened file. On win32, a file could be removed
+# only if all handles were closed.
+if platform.system() not in ['Windows']:
+ config.available_features.add('can-remove-opened-file')
+
+
+def calculate_arch_features(arch_string):
+ features = []
+ for arch in arch_string.split():
+ features.append(arch.lower() + '-registered-target')
+ return features
+
+
+llvm_config.feature_config(
+ [('--assertion-mode', {'ON': 'asserts'}),
+ ('--cxxflags', {r'-D_GLIBCXX_DEBUG\b': 'libstdcxx-safe-mode'}),
+ ('--targets-built', calculate_arch_features)
+ ])
+
+if lit.util.which('xmllint'):
+ config.available_features.add('xmllint')
+
+if config.enable_backtrace:
+ config.available_features.add('backtrace')
+
+# Check if we should allow outputs to console.
+run_console_tests = int(lit_config.params.get('enable_console', '0'))
+if run_console_tests != 0:
+ config.available_features.add('console')
+
+lit.util.usePlatformSdkOnDarwin(config, lit_config)
+macOSSDKVersion = lit.util.findPlatformSdkVersionOnMacOS(config, lit_config)
+if macOSSDKVersion is not None:
+ config.available_features.add('macos-sdk-' + macOSSDKVersion)
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.py.in
index ec447b6615..9d2b4c5918 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.py.in
@@ -10,18 +10,23 @@ config.llvm_shlib_dir = "@SHLIBDIR@"
config.llvm_plugin_ext = "@LLVM_PLUGIN_EXT@"
config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
config.clang_obj_root = "@CLANG_BINARY_DIR@"
+config.clang_src_dir = "@CLANG_SOURCE_DIR@"
config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
config.host_triple = "@LLVM_HOST_TRIPLE@"
config.target_triple = "@TARGET_TRIPLE@"
+config.host_cxx = "@CMAKE_CXX_COMPILER@"
config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
config.have_zlib = @HAVE_LIBZ@
config.clang_arcmt = @CLANG_ENABLE_ARCMT@
config.clang_default_cxx_stdlib = "@CLANG_DEFAULT_CXX_STDLIB@"
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.host_arch = "@HOST_ARCH@"
+config.enable_abi_breaking_checks = "@LLVM_ENABLE_ABI_BREAKING_CHECKS@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
# Support substitution of the tools and libs dirs with user parameters. This is
# used when we can't determine the tool dir at configuration time.
@@ -35,5 +40,7 @@ except KeyError:
key, = e.args
lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+@LIT_SITE_CFG_IN_FOOTER@
+
# Let the main config do the real work.
-lit_config.load_config(config, "@CLANG_SOURCE_DIR@/test/lit.cfg")
+lit_config.load_config(config, "@CLANG_SOURCE_DIR@/test/lit.cfg.py")
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index b0c97f0f1e..9f76d36dba 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -2,6 +2,7 @@ create_subdirectory_options(CLANG TOOL)
add_clang_subdirectory(diagtool)
add_clang_subdirectory(driver)
+add_clang_subdirectory(clang-diff)
add_clang_subdirectory(clang-format)
add_clang_subdirectory(clang-format-vs)
add_clang_subdirectory(clang-fuzzer)
@@ -10,6 +11,9 @@ add_clang_subdirectory(clang-offload-bundler)
add_clang_subdirectory(c-index-test)
+add_clang_subdirectory(clang-rename)
+add_clang_subdirectory(clang-refactor)
+
if(CLANG_ENABLE_ARCMT)
add_clang_subdirectory(arcmt-test)
add_clang_subdirectory(c-arcmt-test)
@@ -17,6 +21,7 @@ endif()
if(CLANG_ENABLE_STATIC_ANALYZER)
add_clang_subdirectory(clang-check)
+ add_clang_subdirectory(clang-func-mapping)
add_clang_subdirectory(scan-build)
add_clang_subdirectory(scan-view)
endif()
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index b6e6ded9cc..a11e03c846 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))
@@ -794,11 +804,57 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
printf(" (const)");
if (clang_CXXMethod_isPureVirtual(Cursor))
printf(" (pure)");
+ if (clang_EnumDecl_isScoped(Cursor))
+ printf(" (scoped)");
if (clang_Cursor_isVariadic(Cursor))
printf(" (variadic)");
if (clang_Cursor_isObjCOptional(Cursor))
printf(" (@optional)");
+ switch (clang_getCursorExceptionSpecificationType(Cursor))
+ {
+ case CXCursor_ExceptionSpecificationKind_None:
+ break;
+
+ case CXCursor_ExceptionSpecificationKind_DynamicNone:
+ printf(" (noexcept dynamic none)");
+ break;
+
+ case CXCursor_ExceptionSpecificationKind_Dynamic:
+ printf(" (noexcept dynamic)");
+ break;
+
+ case CXCursor_ExceptionSpecificationKind_MSAny:
+ printf(" (noexcept dynamic any)");
+ break;
+
+ case CXCursor_ExceptionSpecificationKind_BasicNoexcept:
+ printf(" (noexcept)");
+ break;
+
+ case CXCursor_ExceptionSpecificationKind_ComputedNoexcept:
+ printf(" (computed-noexcept)");
+ break;
+
+ case CXCursor_ExceptionSpecificationKind_Unevaluated:
+ case CXCursor_ExceptionSpecificationKind_Uninstantiated:
+ case CXCursor_ExceptionSpecificationKind_Unparsed:
+ break;
+ }
+
+ {
+ CXString language;
+ CXString definedIn;
+ unsigned generated;
+ if (clang_Cursor_isExternalSymbol(Cursor, &language, &definedIn,
+ &generated)) {
+ printf(" (external lang: %s, defined: %s, gen: %d)",
+ clang_getCString(language), clang_getCString(definedIn), generated);
+ clang_disposeString(language);
+ clang_disposeString(definedIn);
+ }
+ }
+
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
CXType T =
clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
@@ -1507,10 +1563,19 @@ static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p,
return CXChildVisit_Continue;
PrintCursor(cursor, NULL);
Manglings = clang_Cursor_getCXXManglings(cursor);
- for (I = 0, E = Manglings->Count; I < E; ++I)
- printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
- clang_disposeStringSet(Manglings);
- printf("\n");
+ if (Manglings) {
+ for (I = 0, E = Manglings->Count; I < E; ++I)
+ printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
+ clang_disposeStringSet(Manglings);
+ printf("\n");
+ }
+ Manglings = clang_Cursor_getObjCManglings(cursor);
+ if (Manglings) {
+ for (I = 0, E = Manglings->Count; I < E; ++I)
+ printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
+ clang_disposeStringSet(Manglings);
+ printf("\n");
+ }
return CXChildVisit_Recurse;
}
@@ -1550,6 +1615,51 @@ static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p,
}
/******************************************************************************/
+/* Target information testing. */
+/******************************************************************************/
+
+static int print_target_info(int argc, const char **argv) {
+ CXIndex Idx;
+ CXTranslationUnit TU;
+ CXTargetInfo TargetInfo;
+ CXString Triple;
+ const char *FileName;
+ enum CXErrorCode Err;
+ int PointerWidth;
+
+ if (argc == 0) {
+ fprintf(stderr, "No filename specified\n");
+ return 1;
+ }
+
+ FileName = argv[1];
+
+ Idx = clang_createIndex(0, 1);
+ Err = clang_parseTranslationUnit2(Idx, FileName, argv, argc, NULL, 0,
+ getDefaultParsingOptions(), &TU);
+ if (Err != CXError_Success) {
+ fprintf(stderr, "Couldn't parse translation unit!\n");
+ describeLibclangFailure(Err);
+ clang_disposeIndex(Idx);
+ return 1;
+ }
+
+ TargetInfo = clang_getTranslationUnitTargetInfo(TU);
+
+ Triple = clang_TargetInfo_getTriple(TargetInfo);
+ printf("TargetTriple: %s\n", clang_getCString(Triple));
+ clang_disposeString(Triple);
+
+ PointerWidth = clang_TargetInfo_getPointerWidth(TargetInfo);
+ printf("PointerWidth: %d\n", PointerWidth);
+
+ clang_TargetInfo_dispose(TargetInfo);
+ clang_disposeTranslationUnit(TU);
+ clang_disposeIndex(Idx);
+ return 0;
+}
+
+/******************************************************************************/
/* Loading ASTs/source. */
/******************************************************************************/
@@ -1674,6 +1784,8 @@ int perform_test_load_source(int argc, const char **argv,
return -1;
if (Repeats > 1) {
+ clang_suspendTranslationUnit(TU);
+
Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
clang_defaultReparseOptions(TU));
if (Err != CXError_Success) {
@@ -1780,6 +1892,34 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
return result;
}
+static int perform_single_file_parse(const char *filename) {
+ CXIndex Idx;
+ CXTranslationUnit TU;
+ enum CXErrorCode Err;
+ int result;
+
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */1,
+ /* displayDiagnostics=*/1);
+
+ Err = clang_parseTranslationUnit2(Idx, filename,
+ /*command_line_args=*/NULL,
+ /*num_command_line_args=*/0,
+ /*unsaved_files=*/NULL,
+ /*num_unsaved_files=*/0,
+ CXTranslationUnit_SingleFileParse, &TU);
+ if (Err != CXError_Success) {
+ fprintf(stderr, "Unable to load translation unit!\n");
+ describeLibclangFailure(Err);
+ clang_disposeIndex(Idx);
+ return 1;
+ }
+
+ result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, FilteredPrintingVisitor, /*PostVisit=*/NULL,
+ /*CommentSchemaFile=*/NULL);
+ clang_disposeIndex(Idx);
+ return result;
+}
+
/******************************************************************************/
/* Logic for testing clang_getCursor(). */
/******************************************************************************/
@@ -2427,11 +2567,14 @@ static void inspect_print_cursor(CXCursor Cursor) {
clang_Cursor_getObjCSelectorIndex(Cursor));
if (clang_Cursor_isDynamicCall(Cursor))
printf(" Dynamic-call");
- if (Cursor.kind == CXCursor_ObjCMessageExpr) {
+ if (Cursor.kind == CXCursor_ObjCMessageExpr ||
+ Cursor.kind == CXCursor_MemberRefExpr) {
CXType T = clang_Cursor_getReceiverType(Cursor);
- CXString S = clang_getTypeKindSpelling(T.kind);
- printf(" Receiver-type=%s", clang_getCString(S));
- clang_disposeString(S);
+ if (T.kind != CXType_Invalid) {
+ CXString S = clang_getTypeKindSpelling(T.kind);
+ printf(" Receiver-type=%s", clang_getCString(S));
+ clang_disposeString(S);
+ }
}
{
@@ -3004,6 +3147,7 @@ static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
case CXIdxEntityLang_C: return "C";
case CXIdxEntityLang_ObjC: return "ObjC";
case CXIdxEntityLang_CXX: return "C++";
+ case CXIdxEntityLang_Swift: return "Swift";
}
assert(0 && "Garbage language kind");
return 0;
@@ -4287,11 +4431,12 @@ static void print_usage(void) {
" c-index-test -test-print-type {<args>}*\n"
" c-index-test -test-print-type-size {<args>}*\n"
" c-index-test -test-print-bitwidth {<args>}*\n"
+ " c-index-test -test-print-target-info {<args>}*\n"
" c-index-test -test-print-type-declaration {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
- " c-index-test -print-usr-file <file>\n"
- " c-index-test -write-pch <file> <compiler arguments>\n");
+ " c-index-test -print-usr-file <file>\n");
fprintf(stderr,
+ " c-index-test -write-pch <file> <compiler arguments>\n"
" c-index-test -compilation-db [lookup <filename>] database\n");
fprintf(stderr,
" c-index-test -print-build-session-timestamp\n");
@@ -4364,6 +4509,8 @@ int cindextest_main(int argc, const char **argv) {
return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
postVisit);
}
+ else if (argc >= 3 && strcmp(argv[1], "-single-file-parse") == 0)
+ return perform_single_file_parse(argv[2]);
else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
return perform_file_scan(argv[2], argv[3],
argc >= 5 ? argv[4] : 0);
@@ -4397,6 +4544,8 @@ int cindextest_main(int argc, const char **argv) {
return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0)
return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-target-info") == 0)
+ return print_target_info(argc - 2, argv + 2);
else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
if (argc > 2)
return print_usrs(argv + 2, argv + argc);
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index 4f2c3cb34a..c255f54ba6 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -217,7 +217,7 @@ static bool printSourceSymbolsFromModule(StringRef modulePath,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
CompilerInstance::createDiagnostics(new DiagnosticOptions());
std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
- modulePath, *pchRdr, Diags,
+ modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
FileSystemOpts, /*UseDebugInfo=*/false,
/*OnlyLocalDecls=*/true, None,
/*CaptureDiagnostics=*/false,
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index dac11ff077..e190c0721a 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -124,8 +124,7 @@ public:
/// \c FixItRewriter.
class FixItAction : public clang::FixItAction {
public:
- bool BeginSourceFileAction(clang::CompilerInstance& CI,
- StringRef Filename) override {
+ bool BeginSourceFileAction(clang::CompilerInstance& CI) override {
FixItOpts.reset(new FixItOptions);
Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
CI.getLangOpts(), FixItOpts.get()));
diff --git a/tools/clang-diff/CMakeLists.txt b/tools/clang-diff/CMakeLists.txt
new file mode 100644
index 0000000000..a1fc6275be
--- /dev/null
+++ b/tools/clang-diff/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_executable(clang-diff
+ ClangDiff.cpp
+ )
+
+target_link_libraries(clang-diff
+ clangBasic
+ clangFrontend
+ clangTooling
+ clangToolingASTDiff
+ )
diff --git a/tools/clang-diff/ClangDiff.cpp b/tools/clang-diff/ClangDiff.cpp
new file mode 100644
index 0000000000..55cef91170
--- /dev/null
+++ b/tools/clang-diff/ClangDiff.cpp
@@ -0,0 +1,537 @@
+//===- ClangDiff.cpp - compare source files by AST nodes ------*- 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 a tool for syntax tree based comparison using
+// Tooling/ASTDiff.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ASTDiff/ASTDiff.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace clang::tooling;
+
+static cl::OptionCategory ClangDiffCategory("clang-diff options");
+
+static cl::opt<bool>
+ ASTDump("ast-dump",
+ cl::desc("Print the internal representation of the AST."),
+ cl::init(false), cl::cat(ClangDiffCategory));
+
+static cl::opt<bool> ASTDumpJson(
+ "ast-dump-json",
+ cl::desc("Print the internal representation of the AST as JSON."),
+ cl::init(false), cl::cat(ClangDiffCategory));
+
+static cl::opt<bool>
+ PrintMatches("dump-matches", cl::desc("Print the matched nodes."),
+ cl::init(false), cl::cat(ClangDiffCategory));
+
+static cl::opt<bool> HtmlDiff("html",
+ cl::desc("Output a side-by-side diff in HTML."),
+ cl::init(false), cl::cat(ClangDiffCategory));
+
+static cl::opt<std::string> SourcePath(cl::Positional, cl::desc("<source>"),
+ cl::Required,
+ cl::cat(ClangDiffCategory));
+
+static cl::opt<std::string> DestinationPath(cl::Positional,
+ cl::desc("<destination>"),
+ cl::Optional,
+ cl::cat(ClangDiffCategory));
+
+static cl::opt<std::string> StopAfter("stop-diff-after",
+ cl::desc("<topdown|bottomup>"),
+ cl::Optional, cl::init(""),
+ cl::cat(ClangDiffCategory));
+
+static cl::opt<int> MaxSize("s", cl::desc("<maxsize>"), cl::Optional,
+ cl::init(-1), cl::cat(ClangDiffCategory));
+
+static cl::opt<std::string> BuildPath("p", cl::desc("Build path"), cl::init(""),
+ cl::Optional, cl::cat(ClangDiffCategory));
+
+static cl::list<std::string> ArgsAfter(
+ "extra-arg",
+ cl::desc("Additional argument to append to the compiler command line"),
+ cl::cat(ClangDiffCategory));
+
+static cl::list<std::string> ArgsBefore(
+ "extra-arg-before",
+ cl::desc("Additional argument to prepend to the compiler command line"),
+ cl::cat(ClangDiffCategory));
+
+static void addExtraArgs(std::unique_ptr<CompilationDatabase> &Compilations) {
+ if (!Compilations)
+ return;
+ auto AdjustingCompilations =
+ llvm::make_unique<ArgumentsAdjustingCompilations>(
+ std::move(Compilations));
+ AdjustingCompilations->appendArgumentsAdjuster(
+ getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN));
+ AdjustingCompilations->appendArgumentsAdjuster(
+ getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
+ Compilations = std::move(AdjustingCompilations);
+}
+
+static std::unique_ptr<ASTUnit>
+getAST(const std::unique_ptr<CompilationDatabase> &CommonCompilations,
+ const StringRef Filename) {
+ std::string ErrorMessage;
+ std::unique_ptr<CompilationDatabase> Compilations;
+ if (!CommonCompilations) {
+ Compilations = CompilationDatabase::autoDetectFromSource(
+ BuildPath.empty() ? Filename : BuildPath, ErrorMessage);
+ if (!Compilations) {
+ llvm::errs()
+ << "Error while trying to load a compilation database, running "
+ "without flags.\n"
+ << ErrorMessage;
+ Compilations =
+ llvm::make_unique<clang::tooling::FixedCompilationDatabase>(
+ ".", std::vector<std::string>());
+ }
+ }
+ addExtraArgs(Compilations);
+ std::array<std::string, 1> Files = {{Filename}};
+ ClangTool Tool(Compilations ? *Compilations : *CommonCompilations, Files);
+ std::vector<std::unique_ptr<ASTUnit>> ASTs;
+ Tool.buildASTs(ASTs);
+ if (ASTs.size() != Files.size())
+ return nullptr;
+ return std::move(ASTs[0]);
+}
+
+static char hexdigit(int N) { return N &= 0xf, N + (N < 10 ? '0' : 'a' - 10); }
+
+static const char HtmlDiffHeader[] = R"(
+<html>
+<head>
+<meta charset='utf-8'/>
+<style>
+span.d { color: red; }
+span.u { color: #cc00cc; }
+span.i { color: green; }
+span.m { font-weight: bold; }
+span { font-weight: normal; color: black; }
+div.code {
+ width: 48%;
+ height: 98%;
+ overflow: scroll;
+ float: left;
+ padding: 0 0 0.5% 0.5%;
+ border: solid 2px LightGrey;
+ border-radius: 5px;
+}
+</style>
+</head>
+<script type='text/javascript'>
+highlightStack = []
+function clearHighlight() {
+ while (highlightStack.length) {
+ var [l, r] = highlightStack.pop()
+ document.getElementById(l).style.backgroundColor = 'inherit'
+ if (r[1] != '-')
+ document.getElementById(r).style.backgroundColor = 'inherit'
+ }
+}
+function highlight(event) {
+ var id = event.target['id']
+ doHighlight(id)
+}
+function doHighlight(id) {
+ clearHighlight()
+ source = document.getElementById(id)
+ if (!source.attributes['tid'])
+ return
+ var mapped = source
+ while (mapped && mapped.parentElement && mapped.attributes['tid'].value.substr(1) === '-1')
+ mapped = mapped.parentElement
+ var tid = null, target = null
+ if (mapped) {
+ tid = mapped.attributes['tid'].value
+ target = document.getElementById(tid)
+ }
+ if (source.parentElement && source.parentElement.classList.contains('code'))
+ return
+ source.style.backgroundColor = 'lightgrey'
+ source.scrollIntoView()
+ if (target) {
+ if (mapped === source)
+ target.style.backgroundColor = 'lightgrey'
+ target.scrollIntoView()
+ }
+ highlightStack.push([id, tid])
+ location.hash = '#' + id
+}
+function scrollToBoth() {
+ doHighlight(location.hash.substr(1))
+}
+function changed(elem) {
+ return elem.classList.length == 0
+}
+function nextChangedNode(prefix, increment, number) {
+ do {
+ number += increment
+ var elem = document.getElementById(prefix + number)
+ } while(elem && !changed(elem))
+ return elem ? number : null
+}
+function handleKey(e) {
+ var down = e.code === "KeyJ"
+ var up = e.code === "KeyK"
+ if (!down && !up)
+ return
+ var id = highlightStack[0] ? highlightStack[0][0] : 'R0'
+ var oldelem = document.getElementById(id)
+ var number = parseInt(id.substr(1))
+ var increment = down ? 1 : -1
+ var lastnumber = number
+ var prefix = id[0]
+ do {
+ number = nextChangedNode(prefix, increment, number)
+ var elem = document.getElementById(prefix + number)
+ if (up && elem) {
+ while (elem.parentElement && changed(elem.parentElement))
+ elem = elem.parentElement
+ number = elem.id.substr(1)
+ }
+ } while ((down && id !== 'R0' && oldelem.contains(elem)))
+ if (!number)
+ number = lastnumber
+ elem = document.getElementById(prefix + number)
+ doHighlight(prefix + number)
+}
+window.onload = scrollToBoth
+window.onkeydown = handleKey
+</script>
+<body>
+<div onclick='highlight(event)'>
+)";
+
+static void printHtml(raw_ostream &OS, char C) {
+ switch (C) {
+ case '&':
+ OS << "&amp;";
+ break;
+ case '<':
+ OS << "&lt;";
+ break;
+ case '>':
+ OS << "&gt;";
+ break;
+ case '\'':
+ OS << "&#x27;";
+ break;
+ case '"':
+ OS << "&quot;";
+ break;
+ default:
+ OS << C;
+ }
+}
+
+static void printHtml(raw_ostream &OS, const StringRef Str) {
+ for (char C : Str)
+ printHtml(OS, C);
+}
+
+static std::string getChangeKindAbbr(diff::ChangeKind Kind) {
+ switch (Kind) {
+ case diff::None:
+ return "";
+ case diff::Delete:
+ return "d";
+ case diff::Update:
+ return "u";
+ case diff::Insert:
+ return "i";
+ case diff::Move:
+ return "m";
+ case diff::UpdateMove:
+ return "u m";
+ }
+ llvm_unreachable("Invalid enumeration value.");
+}
+
+static unsigned printHtmlForNode(raw_ostream &OS, const diff::ASTDiff &Diff,
+ diff::SyntaxTree &Tree, bool IsLeft,
+ diff::NodeId Id, unsigned Offset) {
+ const diff::Node &Node = Tree.getNode(Id);
+ char MyTag, OtherTag;
+ diff::NodeId LeftId, RightId;
+ diff::NodeId TargetId = Diff.getMapped(Tree, Id);
+ if (IsLeft) {
+ MyTag = 'L';
+ OtherTag = 'R';
+ LeftId = Id;
+ RightId = TargetId;
+ } else {
+ MyTag = 'R';
+ OtherTag = 'L';
+ LeftId = TargetId;
+ RightId = Id;
+ }
+ unsigned Begin, End;
+ std::tie(Begin, End) = Tree.getSourceRangeOffsets(Node);
+ const SourceManager &SrcMgr = Tree.getASTContext().getSourceManager();
+ auto Code = SrcMgr.getBuffer(SrcMgr.getMainFileID())->getBuffer();
+ for (; Offset < Begin; ++Offset)
+ printHtml(OS, Code[Offset]);
+ OS << "<span id='" << MyTag << Id << "' "
+ << "tid='" << OtherTag << TargetId << "' ";
+ OS << "title='";
+ printHtml(OS, Node.getTypeLabel());
+ OS << "\n" << LeftId << " -> " << RightId;
+ std::string Value = Tree.getNodeValue(Node);
+ if (!Value.empty()) {
+ OS << "\n";
+ printHtml(OS, Value);
+ }
+ OS << "'";
+ if (Node.Change != diff::None)
+ OS << " class='" << getChangeKindAbbr(Node.Change) << "'";
+ OS << ">";
+
+ for (diff::NodeId Child : Node.Children)
+ Offset = printHtmlForNode(OS, Diff, Tree, IsLeft, Child, Offset);
+
+ for (; Offset < End; ++Offset)
+ printHtml(OS, Code[Offset]);
+ if (Id == Tree.getRootId()) {
+ End = Code.size();
+ for (; Offset < End; ++Offset)
+ printHtml(OS, Code[Offset]);
+ }
+ OS << "</span>";
+ return Offset;
+}
+
+static void printJsonString(raw_ostream &OS, const StringRef Str) {
+ for (signed char C : Str) {
+ switch (C) {
+ case '"':
+ OS << R"(\")";
+ break;
+ case '\\':
+ OS << R"(\\)";
+ break;
+ case '\n':
+ OS << R"(\n)";
+ break;
+ case '\t':
+ OS << R"(\t)";
+ break;
+ default:
+ if ('\x00' <= C && C <= '\x1f') {
+ OS << R"(\u00)" << hexdigit(C >> 4) << hexdigit(C);
+ } else {
+ OS << C;
+ }
+ }
+ }
+}
+
+static void printNodeAttributes(raw_ostream &OS, diff::SyntaxTree &Tree,
+ diff::NodeId Id) {
+ const diff::Node &N = Tree.getNode(Id);
+ OS << R"("id":)" << int(Id);
+ OS << R"(,"type":")" << N.getTypeLabel() << '"';
+ auto Offsets = Tree.getSourceRangeOffsets(N);
+ OS << R"(,"begin":)" << Offsets.first;
+ OS << R"(,"end":)" << Offsets.second;
+ std::string Value = Tree.getNodeValue(N);
+ if (!Value.empty()) {
+ OS << R"(,"value":")";
+ printJsonString(OS, Value);
+ OS << '"';
+ }
+}
+
+static void printNodeAsJson(raw_ostream &OS, diff::SyntaxTree &Tree,
+ diff::NodeId Id) {
+ const diff::Node &N = Tree.getNode(Id);
+ OS << "{";
+ printNodeAttributes(OS, Tree, Id);
+ auto Identifier = N.getIdentifier();
+ auto QualifiedIdentifier = N.getQualifiedIdentifier();
+ if (Identifier) {
+ OS << R"(,"identifier":")";
+ printJsonString(OS, *Identifier);
+ OS << R"(")";
+ if (QualifiedIdentifier && *Identifier != *QualifiedIdentifier) {
+ OS << R"(,"qualified_identifier":")";
+ printJsonString(OS, *QualifiedIdentifier);
+ OS << R"(")";
+ }
+ }
+ OS << R"(,"children":[)";
+ if (N.Children.size() > 0) {
+ printNodeAsJson(OS, Tree, N.Children[0]);
+ for (size_t I = 1, E = N.Children.size(); I < E; ++I) {
+ OS << ",";
+ printNodeAsJson(OS, Tree, N.Children[I]);
+ }
+ }
+ OS << "]}";
+}
+
+static void printNode(raw_ostream &OS, diff::SyntaxTree &Tree,
+ diff::NodeId Id) {
+ if (Id.isInvalid()) {
+ OS << "None";
+ return;
+ }
+ OS << Tree.getNode(Id).getTypeLabel();
+ std::string Value = Tree.getNodeValue(Id);
+ if (!Value.empty())
+ OS << ": " << Value;
+ OS << "(" << Id << ")";
+}
+
+static void printTree(raw_ostream &OS, diff::SyntaxTree &Tree) {
+ for (diff::NodeId Id : Tree) {
+ for (int I = 0; I < Tree.getNode(Id).Depth; ++I)
+ OS << " ";
+ printNode(OS, Tree, Id);
+ OS << "\n";
+ }
+}
+
+static void printDstChange(raw_ostream &OS, diff::ASTDiff &Diff,
+ diff::SyntaxTree &SrcTree, diff::SyntaxTree &DstTree,
+ diff::NodeId Dst) {
+ const diff::Node &DstNode = DstTree.getNode(Dst);
+ diff::NodeId Src = Diff.getMapped(DstTree, Dst);
+ switch (DstNode.Change) {
+ case diff::None:
+ break;
+ case diff::Delete:
+ llvm_unreachable("The destination tree can't have deletions.");
+ case diff::Update:
+ OS << "Update ";
+ printNode(OS, SrcTree, Src);
+ OS << " to " << DstTree.getNodeValue(Dst) << "\n";
+ break;
+ case diff::Insert:
+ case diff::Move:
+ case diff::UpdateMove:
+ if (DstNode.Change == diff::Insert)
+ OS << "Insert";
+ else if (DstNode.Change == diff::Move)
+ OS << "Move";
+ else if (DstNode.Change == diff::UpdateMove)
+ OS << "Update and Move";
+ OS << " ";
+ printNode(OS, DstTree, Dst);
+ OS << " into ";
+ printNode(OS, DstTree, DstNode.Parent);
+ OS << " at " << DstTree.findPositionInParent(Dst) << "\n";
+ break;
+ }
+}
+
+int main(int argc, const char **argv) {
+ std::string ErrorMessage;
+ std::unique_ptr<CompilationDatabase> CommonCompilations =
+ FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
+ if (!CommonCompilations && !ErrorMessage.empty())
+ llvm::errs() << ErrorMessage;
+ cl::HideUnrelatedOptions(ClangDiffCategory);
+ if (!cl::ParseCommandLineOptions(argc, argv)) {
+ cl::PrintOptionValues();
+ return 1;
+ }
+
+ addExtraArgs(CommonCompilations);
+
+ if (ASTDump || ASTDumpJson) {
+ if (!DestinationPath.empty()) {
+ llvm::errs() << "Error: Please specify exactly one filename.\n";
+ return 1;
+ }
+ std::unique_ptr<ASTUnit> AST = getAST(CommonCompilations, SourcePath);
+ if (!AST)
+ return 1;
+ diff::SyntaxTree Tree(AST->getASTContext());
+ if (ASTDump) {
+ printTree(llvm::outs(), Tree);
+ return 0;
+ }
+ llvm::outs() << R"({"filename":")";
+ printJsonString(llvm::outs(), SourcePath);
+ llvm::outs() << R"(","root":)";
+ printNodeAsJson(llvm::outs(), Tree, Tree.getRootId());
+ llvm::outs() << "}\n";
+ return 0;
+ }
+
+ if (DestinationPath.empty()) {
+ llvm::errs() << "Error: Exactly two paths are required.\n";
+ return 1;
+ }
+
+ std::unique_ptr<ASTUnit> Src = getAST(CommonCompilations, SourcePath);
+ std::unique_ptr<ASTUnit> Dst = getAST(CommonCompilations, DestinationPath);
+ if (!Src || !Dst)
+ return 1;
+
+ diff::ComparisonOptions Options;
+ if (MaxSize != -1)
+ Options.MaxSize = MaxSize;
+ if (!StopAfter.empty()) {
+ if (StopAfter == "topdown")
+ Options.StopAfterTopDown = true;
+ else if (StopAfter != "bottomup") {
+ llvm::errs() << "Error: Invalid argument for -stop-after\n";
+ return 1;
+ }
+ }
+ diff::SyntaxTree SrcTree(Src->getASTContext());
+ diff::SyntaxTree DstTree(Dst->getASTContext());
+ diff::ASTDiff Diff(SrcTree, DstTree, Options);
+
+ if (HtmlDiff) {
+ llvm::outs() << HtmlDiffHeader << "<pre>";
+ llvm::outs() << "<div id='L' class='code'>";
+ printHtmlForNode(llvm::outs(), Diff, SrcTree, true, SrcTree.getRootId(), 0);
+ llvm::outs() << "</div>";
+ llvm::outs() << "<div id='R' class='code'>";
+ printHtmlForNode(llvm::outs(), Diff, DstTree, false, DstTree.getRootId(),
+ 0);
+ llvm::outs() << "</div>";
+ llvm::outs() << "</pre></div></body></html>\n";
+ return 0;
+ }
+
+ for (diff::NodeId Dst : DstTree) {
+ diff::NodeId Src = Diff.getMapped(DstTree, Dst);
+ if (PrintMatches && Src.isValid()) {
+ llvm::outs() << "Match ";
+ printNode(llvm::outs(), SrcTree, Src);
+ llvm::outs() << " to ";
+ printNode(llvm::outs(), DstTree, Dst);
+ llvm::outs() << "\n";
+ }
+ printDstChange(llvm::outs(), Diff, SrcTree, DstTree, Dst);
+ }
+ for (diff::NodeId Src : SrcTree) {
+ if (Diff.getMapped(SrcTree, Src).isInvalid()) {
+ llvm::outs() << "Delete ";
+ printNode(llvm::outs(), SrcTree, Src);
+ llvm::outs() << "\n";
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/clang-format-vs/.gitignore b/tools/clang-format-vs/.gitignore
index c9d25d96c8..270d840cb6 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 d07a4f6ed5..1d44a47a31 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 73bf84e028..46d742bce3 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 5ce601d649..e5b7ec008a 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 c7eac42211..efb2147f2b 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,49 @@ 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();
+ if (!text.EndsWith(Environment.NewLine))
+ {
+ view.TextBuffer.Insert(view.TextBuffer.CurrentSnapshot.Length, Environment.NewLine);
+ text += Environment.NewLine;
+ }
- 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 +366,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 +376,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 +435,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 +452,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 0000000000..163f68dbda
--- /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 0000000000..0d86cb5982
--- /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 0000000000..9966c8123f
--- /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 38f64ed3a6..07dc281178 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 496fa40063..cf7186f73a 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="3cb18a5e-97e9-11e7-abc4-cec278b6b50a" 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/CMakeLists.txt b/tools/clang-format/CMakeLists.txt
index a13633eaef..c695ba3442 100644
--- a/tools/clang-format/CMakeLists.txt
+++ b/tools/clang-format/CMakeLists.txt
@@ -15,7 +15,7 @@ target_link_libraries(clang-format
${CLANG_FORMAT_LIB_DEPS}
)
-if( LLVM_USE_SANITIZE_COVERAGE )
+if( LLVM_LIB_FUZZING_ENGINE OR LLVM_USE_SANITIZE_COVERAGE )
add_subdirectory(fuzzer)
endif()
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index ac0d0a8512..e169b9e585 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -102,6 +102,10 @@ static cl::opt<bool> SortIncludes(
"SortIncludes style flag"),
cl::cat(ClangFormatCategory));
+static cl::opt<bool>
+ Verbose("verbose", cl::desc("If set, shows the list of processed files"),
+ cl::cat(ClangFormatCategory));
+
static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"),
cl::cat(ClangFormatCategory));
@@ -276,14 +280,17 @@ static bool format(StringRef FileName) {
}
// Get new affected ranges after sorting `#includes`.
Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
- bool IncompleteFormat = false;
+ FormattingAttemptStatus Status;
Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges,
- AssumedFileName, &IncompleteFormat);
+ AssumedFileName, &Status);
Replaces = Replaces.merge(FormatChanges);
if (OutputXML) {
outs() << "<?xml version='1.0'?>\n<replacements "
"xml:space='preserve' incomplete_format='"
- << (IncompleteFormat ? "true" : "false") << "'>\n";
+ << (Status.FormatComplete ? "false" : "true") << "'";
+ if (!Status.FormatComplete)
+ outs() << " line=" << Status.Line;
+ outs() << ">\n";
if (Cursor.getNumOccurrences() != 0)
outs() << "<cursor>"
<< FormatChanges.getShiftedCodePosition(CursorPosition)
@@ -307,11 +314,15 @@ static bool format(StringRef FileName) {
if (Rewrite.overwriteChangedFiles())
return true;
} else {
- if (Cursor.getNumOccurrences() != 0)
+ if (Cursor.getNumOccurrences() != 0) {
outs() << "{ \"Cursor\": "
<< FormatChanges.getShiftedCodePosition(CursorPosition)
<< ", \"IncompleteFormat\": "
- << (IncompleteFormat ? "true" : "false") << " }\n";
+ << (Status.FormatComplete ? "false" : "true");
+ if (!Status.FormatComplete)
+ outs() << ", \"Line\": " << Status.Line;
+ outs() << " }\n";
+ }
Rewrite.getEditBuffer(ID).write(outs());
}
}
@@ -321,8 +332,7 @@ static bool format(StringRef FileName) {
} // namespace format
} // namespace clang
-static void PrintVersion() {
- raw_ostream &OS = outs();
+static void PrintVersion(raw_ostream &OS) {
OS << clang::getClangToolFullVersion("clang-format") << '\n';
}
@@ -341,8 +351,10 @@ int main(int argc, const char **argv) {
"together with <file>s, the files are edited in-place. Otherwise, the\n"
"result is written to the standard output.\n");
- if (Help)
+ if (Help) {
cl::PrintHelpMessage();
+ return 0;
+ }
if (DumpConfig) {
llvm::Expected<clang::format::FormatStyle> FormatStyle =
@@ -359,23 +371,19 @@ int main(int argc, const char **argv) {
}
bool Error = false;
- switch (FileNames.size()) {
- case 0:
+ if (FileNames.empty()) {
Error = clang::format::format("-");
- break;
- case 1:
- Error = clang::format::format(FileNames[0]);
- break;
- default:
- if (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty()) {
- errs() << "error: -offset, -length and -lines can only be used for "
- "single file.\n";
- return 1;
- }
- for (unsigned i = 0; i < FileNames.size(); ++i)
- Error |= clang::format::format(FileNames[i]);
- break;
+ return Error ? 1 : 0;
+ }
+ if (FileNames.size() != 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) {
+ errs() << "error: -offset, -length and -lines can only be used for "
+ "single file.\n";
+ return 1;
+ }
+ for (const auto &FileName : FileNames) {
+ if (Verbose)
+ errs() << "Formatting " << FileName << "\n";
+ Error |= clang::format::format(FileName);
}
return Error ? 1 : 0;
}
-
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
index ae8a6ebf74..5fe592a920 100644
--- a/tools/clang-format/clang-format.py
+++ b/tools/clang-format/clang-format.py
@@ -62,9 +62,20 @@ def main():
# Determine range to format.
if vim.eval('exists("l:lines")') == '1':
- lines = vim.eval('l:lines')
+ lines = ['-lines', vim.eval('l:lines')]
+ elif vim.eval('exists("l:formatdiff")') == '1':
+ with open(vim.current.buffer.name, 'r') as f:
+ ondisk = f.read().splitlines();
+ sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)
+ lines = []
+ for op in reversed(sequence.get_opcodes()):
+ if op[0] not in ['equal', 'delete']:
+ lines += ['-lines', '%s:%s' % (op[3] + 1, op[4])]
+ if lines == []:
+ return
else:
- lines = '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1)
+ lines = ['-lines', '%s:%s' % (vim.current.range.start + 1,
+ vim.current.range.end + 1)]
# Determine the cursor position.
cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2
@@ -81,8 +92,8 @@ def main():
# Call formatter.
command = [binary, '-style', style, '-cursor', str(cursor)]
- if lines != 'all':
- command.extend(['-lines', lines])
+ if lines != ['-lines', 'all']:
+ command += lines
if fallback_style:
command.extend(['-fallback-style', fallback_style])
if vim.current.buffer.name:
diff --git a/tools/clang-format/fuzzer/CMakeLists.txt b/tools/clang-format/fuzzer/CMakeLists.txt
index c7772fcb2f..8f777324af 100644
--- a/tools/clang-format/fuzzer/CMakeLists.txt
+++ b/tools/clang-format/fuzzer/CMakeLists.txt
@@ -1,5 +1,9 @@
set(LLVM_LINK_COMPONENTS support)
+if(LLVM_USE_SANITIZE_COVERAGE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer")
+endif()
+
add_clang_executable(clang-format-fuzzer
EXCLUDE_FROM_ALL
ClangFormatFuzzer.cpp
@@ -7,5 +11,5 @@ add_clang_executable(clang-format-fuzzer
target_link_libraries(clang-format-fuzzer
${CLANG_FORMAT_LIB_DEPS}
- LLVMFuzzer
+ ${LLVM_LIB_FUZZING_ENGINE}
)
diff --git a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp
index 5334ce873e..d440a6124b 100644
--- a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp
+++ b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp
@@ -20,7 +20,10 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
std::string s((const char *)data, size);
auto Style = getGoogleStyle(clang::format::FormatStyle::LK_Cpp);
Style.ColumnLimit = 60;
- applyAllReplacements(s, clang::format::reformat(
- Style, s, {clang::tooling::Range(0, s.size())}));
+ auto Replaces = reformat(Style, s, clang::tooling::Range(0, s.size()));
+ auto Result = applyAllReplacements(s, Replaces);
+
+ // Output must be checked, as otherwise we crash.
+ if (!Result) {}
return 0;
}
diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format
index 74fd451a84..60cd4fb25b 100755
--- a/tools/clang-format/git-clang-format
+++ b/tools/clang-format/git-clang-format
@@ -20,9 +20,10 @@ clang-format on the changes in current files or a specific commit.
For further details, run:
git clang-format -h
-Requires Python 2.7
+Requires Python 2.7 or Python 3
"""
+from __future__ import print_function
import argparse
import collections
import contextlib
@@ -138,15 +139,15 @@ def main():
if opts.verbose >= 1:
ignored_files.difference_update(changed_lines)
if ignored_files:
- print 'Ignoring changes in the following files (wrong extension):'
+ print('Ignoring changes in the following files (wrong extension):')
for filename in ignored_files:
- print ' ', filename
+ print(' %s' % filename)
if changed_lines:
- print 'Running clang-format on the following files:'
+ print('Running clang-format on the following files:')
for filename in changed_lines:
- print ' ', filename
+ print(' %s' % filename)
if not changed_lines:
- print 'no modified files to format'
+ print('no modified files to format')
return
# The computed diff outputs absolute paths, so we must cd before accessing
# those files.
@@ -163,20 +164,20 @@ def main():
binary=opts.binary,
style=opts.style)
if opts.verbose >= 1:
- print 'old tree:', old_tree
- print 'new tree:', new_tree
+ print('old tree: %s' % old_tree)
+ print('new tree: %s' % new_tree)
if old_tree == new_tree:
if opts.verbose >= 0:
- print 'clang-format did not modify any files'
+ print('clang-format did not modify any files')
elif opts.diff:
print_diff(old_tree, new_tree)
else:
changed_files = apply_changes(old_tree, new_tree, force=opts.force,
patch_mode=opts.patch)
if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
- print 'changed files:'
+ print('changed files:')
for filename in changed_files:
- print ' ', filename
+ print(' %s' % filename)
def load_git_config(non_string_options=None):
@@ -257,7 +258,7 @@ def get_object_type(value):
stdout, stderr = p.communicate()
if p.returncode != 0:
return None
- return stdout.strip()
+ return convert_string(stdout.strip())
def compute_diff_and_extract_lines(commits, files):
@@ -300,6 +301,7 @@ def extract_lines(patch_file):
list of line `Range`s."""
matches = {}
for line in patch_file:
+ line = convert_string(line)
match = re.search(r'^\+\+\+\ [^/]+/(.*)', line)
if match:
filename = match.group(1).rstrip('\r\n')
@@ -320,8 +322,10 @@ def filter_by_extension(dictionary, allowed_extensions):
`allowed_extensions` must be a collection of lowercase file extensions,
excluding the period."""
allowed_extensions = frozenset(allowed_extensions)
- for filename in dictionary.keys():
+ for filename in list(dictionary.keys()):
base_ext = filename.rsplit('.', 1)
+ if len(base_ext) == 1 and '' in allowed_extensions:
+ continue
if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
del dictionary[filename]
@@ -344,8 +348,13 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None,
"""Run clang-format on each file and save the result to a git tree.
Returns the object ID (SHA-1) of the created tree."""
+ def iteritems(container):
+ try:
+ return container.iteritems() # Python 2
+ except AttributeError:
+ return container.items() # Python 3
def index_info_generator():
- for filename, line_ranges in changed_lines.iteritems():
+ for filename, line_ranges in iteritems(changed_lines):
if revision:
git_metadata_cmd = ['git', 'ls-tree',
'%s:%s' % (revision, os.path.dirname(filename)),
@@ -356,6 +365,9 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None,
mode = oct(int(stdout.split()[0], 8))
else:
mode = oct(os.stat(filename).st_mode)
+ # Adjust python3 octal format so that it matches what git expects
+ if mode.startswith('0o'):
+ mode = '0' + mode[2:]
blob_id = clang_format_to_blob(filename, line_ranges,
revision=revision,
binary=binary,
@@ -376,7 +388,7 @@ def create_tree(input_lines, mode):
with temporary_index_file():
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
for line in input_lines:
- p.stdin.write('%s\0' % line)
+ p.stdin.write(to_bytes('%s\0' % line))
p.stdin.close()
if p.wait() != 0:
die('`%s` failed' % ' '.join(cmd))
@@ -431,7 +443,7 @@ def clang_format_to_blob(filename, line_ranges, revision=None,
die('`%s` failed' % ' '.join(clang_format_cmd))
if git_show and git_show.wait() != 0:
die('`%s` failed' % ' '.join(git_show_cmd))
- return stdout.rstrip('\r\n')
+ return convert_string(stdout).rstrip('\r\n')
@contextlib.contextmanager
@@ -488,10 +500,10 @@ def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
if not force:
unstaged_files = run('git', 'diff-files', '--name-status', *changed_files)
if unstaged_files:
- print >>sys.stderr, ('The following files would be modified but '
- 'have unstaged changes:')
- print >>sys.stderr, unstaged_files
- print >>sys.stderr, 'Please commit, stage, or stash them first.'
+ print('The following files would be modified but '
+ 'have unstaged changes:', file=sys.stderr)
+ print(unstaged_files, file=sys.stderr)
+ print('Please commit, stage, or stash them first.', file=sys.stderr)
sys.exit(2)
if patch_mode:
# In patch mode, we could just as well create an index from the new tree
@@ -518,25 +530,50 @@ def run(*args, **kwargs):
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
stdout, stderr = p.communicate(input=stdin)
+
+ stdout = convert_string(stdout)
+ stderr = convert_string(stderr)
+
if p.returncode == 0:
if stderr:
if verbose:
- print >>sys.stderr, '`%s` printed to stderr:' % ' '.join(args)
- print >>sys.stderr, stderr.rstrip()
+ print('`%s` printed to stderr:' % ' '.join(args), file=sys.stderr)
+ print(stderr.rstrip(), file=sys.stderr)
if strip:
stdout = stdout.rstrip('\r\n')
return stdout
if verbose:
- print >>sys.stderr, '`%s` returned %s' % (' '.join(args), p.returncode)
+ print('`%s` returned %s' % (' '.join(args), p.returncode), file=sys.stderr)
if stderr:
- print >>sys.stderr, stderr.rstrip()
+ print(stderr.rstrip(), file=sys.stderr)
sys.exit(2)
def die(message):
- print >>sys.stderr, 'error:', message
+ print('error:', message, file=sys.stderr)
sys.exit(2)
+def to_bytes(str_input):
+ # Encode to UTF-8 to get binary data.
+ if isinstance(str_input, bytes):
+ return str_input
+ return str_input.encode('utf-8')
+
+
+def to_string(bytes_input):
+ if isinstance(bytes_input, str):
+ return bytes_input
+ return bytes_input.encode('utf-8')
+
+
+def convert_string(bytes_input):
+ try:
+ return to_string(bytes_input.decode('utf-8'))
+ except AttributeError: # 'str' object has no attribute 'decode'.
+ return str(bytes_input)
+ except UnicodeError:
+ return str(bytes_input)
+
if __name__ == '__main__':
main()
diff --git a/tools/clang-func-mapping/CMakeLists.txt b/tools/clang-func-mapping/CMakeLists.txt
new file mode 100644
index 0000000000..8c10fcd757
--- /dev/null
+++ b/tools/clang-func-mapping/CMakeLists.txt
@@ -0,0 +1,22 @@
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
+ support
+ mc
+ )
+
+add_clang_executable(clang-func-mapping
+ ClangFnMapGen.cpp
+ )
+
+target_link_libraries(clang-func-mapping
+ clangAST
+ clangBasic
+ clangCrossTU
+ clangFrontend
+ clangIndex
+ clangTooling
+ )
+
+install(TARGETS clang-func-mapping
+ RUNTIME DESTINATION bin)
diff --git a/tools/clang-func-mapping/ClangFnMapGen.cpp b/tools/clang-func-mapping/ClangFnMapGen.cpp
new file mode 100644
index 0000000000..4bf812fffe
--- /dev/null
+++ b/tools/clang-func-mapping/ClangFnMapGen.cpp
@@ -0,0 +1,124 @@
+//===- ClangFnMapGen.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+//
+// Clang tool which creates a list of defined functions and the files in which
+// they are defined.
+//
+//===--------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/GlobalDecl.h"
+#include "clang/AST/Mangle.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include <sstream>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace clang;
+using namespace clang::cross_tu;
+using namespace clang::tooling;
+
+static cl::OptionCategory ClangFnMapGenCategory("clang-fnmapgen options");
+
+class MapFunctionNamesConsumer : public ASTConsumer {
+public:
+ MapFunctionNamesConsumer(ASTContext &Context) : Ctx(Context) {}
+
+ ~MapFunctionNamesConsumer() {
+ // Flush results to standard output.
+ llvm::outs() << createCrossTUIndexString(Index);
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ handleDecl(Ctx.getTranslationUnitDecl());
+ }
+
+private:
+ void handleDecl(const Decl *D);
+
+ ASTContext &Ctx;
+ llvm::StringMap<std::string> Index;
+ std::string CurrentFileName;
+};
+
+void MapFunctionNamesConsumer::handleDecl(const Decl *D) {
+ if (!D)
+ return;
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isThisDeclarationADefinition()) {
+ if (const Stmt *Body = FD->getBody()) {
+ std::string LookupName = CrossTranslationUnitContext::getLookupName(FD);
+ const SourceManager &SM = Ctx.getSourceManager();
+ if (CurrentFileName.empty()) {
+ CurrentFileName =
+ SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName();
+ if (CurrentFileName.empty())
+ CurrentFileName = "invalid_file";
+ }
+
+ switch (FD->getLinkageInternal()) {
+ case ExternalLinkage:
+ case VisibleNoLinkage:
+ case UniqueExternalLinkage:
+ if (SM.isInMainFile(Body->getLocStart()))
+ Index[LookupName] = CurrentFileName;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (const auto *DC = dyn_cast<DeclContext>(D))
+ for (const Decl *D : DC->decls())
+ handleDecl(D);
+}
+
+class MapFunctionNamesAction : public ASTFrontendAction {
+protected:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef) {
+ std::unique_ptr<ASTConsumer> PFC(
+ new MapFunctionNamesConsumer(CI.getASTContext()));
+ return PFC;
+ }
+};
+
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+
+int main(int argc, const char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal(argv[0], false);
+ PrettyStackTraceProgram X(argc, argv);
+
+ const char *Overview = "\nThis tool collects the USR name and location "
+ "of all functions definitions in the source files "
+ "(excluding headers).\n";
+ CommonOptionsParser OptionsParser(argc, argv, ClangFnMapGenCategory,
+ cl::ZeroOrMore, Overview);
+
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+ Tool.run(newFrontendActionFactory<MapFunctionNamesAction>().get());
+ return 0;
+}
diff --git a/tools/clang-fuzzer/CMakeLists.txt b/tools/clang-fuzzer/CMakeLists.txt
index 87d21c6bf1..abc501511f 100644
--- a/tools/clang-fuzzer/CMakeLists.txt
+++ b/tools/clang-fuzzer/CMakeLists.txt
@@ -1,20 +1,71 @@
-if( LLVM_USE_SANITIZE_COVERAGE )
- set(LLVM_LINK_COMPONENTS support)
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} FuzzMutate)
+set(CXX_FLAGS_NOFUZZ ${CMAKE_CXX_FLAGS})
+set(DUMMY_MAIN DummyClangFuzzer.cpp)
+if(LLVM_LIB_FUZZING_ENGINE)
+ unset(DUMMY_MAIN)
+elseif(LLVM_USE_SANITIZE_COVERAGE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer")
+ set(CXX_FLAGS_NOFUZZ "${CXX_FLAGS_NOFUZZ} -fsanitize=fuzzer-no-link")
+ unset(DUMMY_MAIN)
+endif()
+
+# Hack to bypass LLVM's cmake sources check and allow multiple libraries and
+# executables from this directory.
+set(LLVM_OPTIONAL_SOURCES
+ ClangFuzzer.cpp
+ DummyClangFuzzer.cpp
+ ExampleClangProtoFuzzer.cpp
+ )
+
+if(CLANG_ENABLE_PROTO_FUZZER)
+ # Create protobuf .h and .cc files, and put them in a library for use by
+ # clang-proto-fuzzer components.
+ find_package(Protobuf REQUIRED)
+ add_definitions(-DGOOGLE_PROTOBUF_NO_RTTI)
+ include_directories(${PROTOBUF_INCLUDE_DIRS})
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+ protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS cxx_proto.proto)
+ set(LLVM_OPTIONAL_SOURCES ${LLVM_OPTIONAL_SOURCES} ${PROTO_SRCS})
+ add_clang_library(clangCXXProto
+ ${PROTO_SRCS}
+ ${PROTO_HDRS}
+
+ LINK_LIBS
+ ${PROTOBUF_LIBRARIES}
+ )
- add_clang_executable(clang-fuzzer
- EXCLUDE_FROM_ALL
- ClangFuzzer.cpp
+ # Build and include libprotobuf-mutator
+ include(ProtobufMutator)
+ include_directories(${ProtobufMutator_INCLUDE_DIRS})
+
+ # Build the protobuf->C++ translation library and driver.
+ add_clang_subdirectory(proto-to-cxx)
+
+ # Build the protobuf fuzzer
+ add_clang_executable(clang-proto-fuzzer
+ ${DUMMY_MAIN}
+ ExampleClangProtoFuzzer.cpp
)
- target_link_libraries(clang-fuzzer
- ${CLANG_FORMAT_LIB_DEPS}
- clangAST
- clangBasic
- clangDriver
- clangFrontend
- clangRewriteFrontend
- clangStaticAnalyzerFrontend
- clangTooling
- LLVMFuzzer
+ target_link_libraries(clang-proto-fuzzer
+ ${ProtobufMutator_LIBRARIES}
+ ${PROTOBUF_LIBRARIES}
+ ${LLVM_LIB_FUZZING_ENGINE}
+ clangCXXProto
+ clangHandleCXX
+ clangProtoToCXX
)
endif()
+
+add_clang_subdirectory(handle-cxx)
+
+add_clang_executable(clang-fuzzer
+ EXCLUDE_FROM_ALL
+ ${DUMMY_MAIN}
+ ClangFuzzer.cpp
+ )
+
+target_link_libraries(clang-fuzzer
+ ${LLVM_LIB_FUZZING_ENGINE}
+ clangHandleCXX
+ )
diff --git a/tools/clang-fuzzer/ClangFuzzer.cpp b/tools/clang-fuzzer/ClangFuzzer.cpp
index 1692882c0b..2d35fb7735 100644
--- a/tools/clang-fuzzer/ClangFuzzer.cpp
+++ b/tools/clang-fuzzer/ClangFuzzer.cpp
@@ -13,36 +13,14 @@
///
//===----------------------------------------------------------------------===//
-#include "clang/Tooling/Tooling.h"
-#include "clang/Frontend/FrontendActions.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "llvm/Option/Option.h"
+#include "handle-cxx/handle_cxx.h"
-using namespace clang;
+using namespace clang_fuzzer;
+
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { return 0; }
extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
std::string s((const char *)data, size);
- llvm::opt::ArgStringList CC1Args;
- CC1Args.push_back("-cc1");
- CC1Args.push_back("./test.cc");
- llvm::IntrusiveRefCntPtr<FileManager> Files(
- new FileManager(FileSystemOptions()));
- IgnoringDiagConsumer Diags;
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
- DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
- &Diags, false);
- std::unique_ptr<clang::CompilerInvocation> Invocation(
- tooling::newInvocation(&Diagnostics, CC1Args));
- std::unique_ptr<llvm::MemoryBuffer> Input =
- llvm::MemoryBuffer::getMemBuffer(s);
- Invocation->getPreprocessorOpts().addRemappedFile("./test.cc", Input.release());
- std::unique_ptr<tooling::ToolAction> action(
- tooling::newFrontendActionFactory<clang::SyntaxOnlyAction>());
- std::shared_ptr<PCHContainerOperations> PCHContainerOps =
- std::make_shared<PCHContainerOperations>();
- action->runInvocation(std::move(Invocation), Files.get(), PCHContainerOps,
- &Diags);
+ HandleCXX(s, {"-O2"});
return 0;
}
diff --git a/tools/clang-fuzzer/Dockerfile b/tools/clang-fuzzer/Dockerfile
new file mode 100644
index 0000000000..1946b8bf88
--- /dev/null
+++ b/tools/clang-fuzzer/Dockerfile
@@ -0,0 +1,37 @@
+#===- llvm/tools/clang/tools/clang-fuzzer ---------------------------------===//
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===----------------------------------------------------------------------===//
+# Produces an image that builds clang-proto-fuzzer
+FROM ubuntu:16.04
+RUN apt-get update -y
+RUN apt-get install -y autoconf automake libtool curl make g++ unzip wget git \
+ binutils liblzma-dev libz-dev python-all cmake ninja-build subversion \
+ pkg-config docbook2x
+
+WORKDIR /root
+
+# Get protobuf
+RUN wget -qO- https://github.com/google/protobuf/releases/download/v3.3.0/protobuf-cpp-3.3.0.tar.gz | tar zxf -
+RUN cd protobuf-3.3.0 && ./autogen.sh && ./configure && make -j $(nproc) && make check -j $(nproc) && make install && ldconfig
+# Get LLVM
+RUN svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
+RUN cd llvm/tools && svn co http://llvm.org/svn/llvm-project/cfe/trunk clang -r $(cd ../ && svn info | grep Revision | awk '{print $2}')
+RUN cd llvm/projects && svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt -r $(cd ../ && svn info | grep Revision | awk '{print $2}')
+# Build plain LLVM (stage 0)
+RUN mkdir build0 && cd build0 && cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llvm && ninja
+# Configure instrumented LLVM (stage 1)
+RUN mkdir build1 && cd build1 && cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llvm \
+ -DLLVM_ENABLE_ASSERTIONS=ON \
+ -DCMAKE_C_COMPILER=`pwd`/../build0/bin/clang \
+ -DCMAKE_CXX_COMPILER=`pwd`/../build0/bin/clang++ \
+ -DLLVM_USE_SANITIZE_COVERAGE=YES \
+ -DLLVM_USE_SANITIZER=Address -DCLANG_ENABLE_PROTO_FUZZER=ON
+# Build the fuzzers
+RUN cd build1 && ninja clang-fuzzer
+RUN cd build1 && ninja clang-proto-fuzzer
+RUN cd build1 && ninja clang-proto-to-cxx
diff --git a/tools/clang-fuzzer/DummyClangFuzzer.cpp b/tools/clang-fuzzer/DummyClangFuzzer.cpp
new file mode 100644
index 0000000000..382c161307
--- /dev/null
+++ b/tools/clang-fuzzer/DummyClangFuzzer.cpp
@@ -0,0 +1,21 @@
+//===-- DummyClangFuzzer.cpp - Entry point to sanity check fuzzers --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides a main() to build without linking libFuzzer.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/FuzzMutate/FuzzerCLI.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv);
+
+int main(int argc, char *argv[]) {
+ return llvm::runFuzzerOnInputs(argc, argv, LLVMFuzzerTestOneInput,
+ LLVMFuzzerInitialize);
+}
diff --git a/tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp b/tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp
new file mode 100644
index 0000000000..ab734e85b8
--- /dev/null
+++ b/tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp
@@ -0,0 +1,44 @@
+//===-- ExampleClangProtoFuzzer.cpp - Fuzz Clang --------------------------===//
+//
+// 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 a function that runs Clang on a single
+/// input and uses libprotobuf-mutator to find new inputs. This function is
+/// then linked into the Fuzzer library.
+///
+//===----------------------------------------------------------------------===//
+
+#include "cxx_proto.pb.h"
+#include "handle-cxx/handle_cxx.h"
+#include "proto-to-cxx/proto_to_cxx.h"
+
+#include "src/libfuzzer/libfuzzer_macro.h"
+
+#include <cstring>
+
+using namespace clang_fuzzer;
+
+static std::vector<const char *> CLArgs;
+
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ CLArgs.push_back("-O2");
+ for (int I = 1; I < *argc; I++) {
+ if (strcmp((*argv)[I], "-ignore_remaining_args=1") == 0) {
+ for (I++; I < *argc; I++)
+ CLArgs.push_back((*argv)[I]);
+ break;
+ }
+ }
+ return 0;
+}
+
+DEFINE_BINARY_PROTO_FUZZER(const Function& input) {
+ auto S = FunctionToString(input);
+ HandleCXX(S, CLArgs);
+}
diff --git a/tools/clang-fuzzer/README.txt b/tools/clang-fuzzer/README.txt
new file mode 100644
index 0000000000..66a6a6332c
--- /dev/null
+++ b/tools/clang-fuzzer/README.txt
@@ -0,0 +1,82 @@
+This directory contains two utilities for fuzzing Clang: clang-fuzzer and
+clang-proto-fuzzer. Both use libFuzzer to generate inputs to clang via
+coverage-guided mutation.
+
+The two utilities differ, however, in how they structure inputs to Clang.
+clang-fuzzer makes no attempt to generate valid C++ programs and is therefore
+primarily useful for stressing the surface layers of Clang (i.e. lexer, parser).
+clang-proto-fuzzer uses a protobuf class to describe a subset of the C++
+language and then uses libprotobuf-mutator to mutate instantiations of that
+class, producing valid C++ programs in the process. As a result,
+clang-proto-fuzzer is better at stressing deeper layers of Clang and LLVM.
+
+===================================
+ Building clang-fuzzer
+===================================
+Within your LLVM build directory, run CMake with the following variable
+definitions:
+- CMAKE_C_COMPILER=clang
+- CMAKE_CXX_COMPILER=clang++
+- LLVM_USE_SANITIZE_COVERAGE=YES
+- LLVM_USE_SANITIZER=Address
+
+Then build the clang-fuzzer target.
+
+Example:
+ cd $LLVM_SOURCE_DIR
+ mkdir build && cd build
+ cmake .. -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
+ -DLLVM_USE_SANITIZE_COVERAGE=YES -DLLVM_USE_SANITIZER=Address
+ ninja clang-fuzzer
+
+======================
+ Running clang-fuzzer
+======================
+ bin/clang-fuzzer CORPUS_DIR
+
+
+=======================================================
+ Building clang-proto-fuzzer (Linux-only instructions)
+=======================================================
+Install the necessary dependencies:
+- binutils // needed for libprotobuf-mutator
+- liblzma-dev // needed for libprotobuf-mutator
+- libz-dev // needed for libprotobuf-mutator
+- docbook2x // needed for libprotobuf-mutator
+- Recent version of protobuf [3.3.0 is known to work]
+
+Within your LLVM build directory, run CMake with the following variable
+definitions:
+- CMAKE_C_COMPILER=clang
+- CMAKE_CXX_COMPILER=clang++
+- LLVM_USE_SANITIZE_COVERAGE=YES
+- LLVM_USE_SANITIZER=Address
+- CLANG_ENABLE_PROTO_FUZZER=ON
+
+Then build the clang-proto-fuzzer and clang-proto-to-cxx targets. Optionally,
+you may also build clang-fuzzer with this setup.
+
+Example:
+ cd $LLVM_SOURCE_DIR
+ mkdir build && cd build
+ cmake .. -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
+ -DLLVM_USE_SANITIZE_COVERAGE=YES -DLLVM_USE_SANITIZER=Address \
+ -DCLANG_ENABLE_PROTO_FUZZER=ON
+ ninja clang-proto-fuzzer clang-proto-to-cxx
+
+This directory also contains a Dockerfile which sets up all required
+dependencies and builds the fuzzers.
+
+============================
+ Running clang-proto-fuzzer
+============================
+ bin/clang-proto-fuzzer CORPUS_DIR
+
+Arguments can be specified after -ignore_remaining_args=1 to modify the compiler
+invocation. For example, the following command line will fuzz LLVM with a
+custom optimization level and target triple:
+ bin/clang-proto-fuzzer CORPUS_DIR -ignore_remaining_args=1 -O3 -triple \
+ arm64apple-ios9
+
+To translate a clang-proto-fuzzer corpus output to C++:
+ bin/clang-proto-to-cxx CORPUS_OUTPUT_FILE
diff --git a/tools/clang-fuzzer/cxx_proto.proto b/tools/clang-fuzzer/cxx_proto.proto
new file mode 100644
index 0000000000..714a29861e
--- /dev/null
+++ b/tools/clang-fuzzer/cxx_proto.proto
@@ -0,0 +1,93 @@
+//===-- cxx_proto.proto - Protobuf description of 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 describes a subset of C++ as a protobuf. It is used to
+/// more easily find interesting inputs for fuzzing Clang.
+///
+//===----------------------------------------------------------------------===//
+
+syntax = "proto2";
+
+message VarRef {
+ required int32 varnum = 1;
+}
+
+message Lvalue {
+ required VarRef varref = 1;
+}
+
+message Const {
+ required int32 val = 1;
+}
+
+message BinaryOp {
+ enum Op {
+ PLUS = 0;
+ MINUS = 1;
+ MUL = 2;
+ DIV = 3;
+ MOD = 4;
+ XOR = 5;
+ AND = 6;
+ OR = 7;
+ EQ = 8;
+ NE = 9;
+ LE = 10;
+ GE = 11;
+ LT = 12;
+ GT = 13;
+ };
+ required Op op = 1;
+ required Rvalue left = 2;
+ required Rvalue right = 3;
+}
+
+message Rvalue {
+ oneof rvalue_oneof {
+ VarRef varref = 1;
+ Const cons = 2;
+ BinaryOp binop = 3;
+ }
+}
+
+message AssignmentStatement {
+ required Lvalue lvalue = 1;
+ required Rvalue rvalue = 2;
+}
+
+
+message IfElse {
+ required Rvalue cond = 1;
+ required StatementSeq if_body = 2;
+ required StatementSeq else_body = 3;
+}
+
+message While {
+ required Rvalue cond = 1;
+ required StatementSeq body = 2;
+}
+
+message Statement {
+ oneof stmt_oneof {
+ AssignmentStatement assignment = 1;
+ IfElse ifelse = 2;
+ While while_loop = 3;
+ }
+}
+
+message StatementSeq {
+ repeated Statement statements = 1;
+}
+
+message Function {
+ required StatementSeq statements = 1;
+}
+
+package clang_fuzzer;
diff --git a/tools/clang-fuzzer/handle-cxx/CMakeLists.txt b/tools/clang-fuzzer/handle-cxx/CMakeLists.txt
new file mode 100644
index 0000000000..caf1dba7af
--- /dev/null
+++ b/tools/clang-fuzzer/handle-cxx/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Support)
+
+add_clang_library(clangHandleCXX
+ handle_cxx.cpp
+
+ LINK_LIBS
+ clangBasic
+ clangCodeGen
+ clangFrontend
+ clangLex
+ clangTooling
+ )
diff --git a/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp b/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
new file mode 100644
index 0000000000..312ab91e5f
--- /dev/null
+++ b/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
@@ -0,0 +1,58 @@
+//==-- handle_cxx.cpp - Helper function for Clang fuzzers ------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements HandleCXX for use by the Clang fuzzers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "handle_cxx.h"
+
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace clang;
+
+void clang_fuzzer::HandleCXX(const std::string &S,
+ const std::vector<const char *> &ExtraArgs) {
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllAsmParsers();
+
+ llvm::opt::ArgStringList CC1Args;
+ CC1Args.push_back("-cc1");
+ for (auto &A : ExtraArgs)
+ CC1Args.push_back(A);
+ CC1Args.push_back("./test.cc");
+
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions()));
+ IgnoringDiagConsumer Diags;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &Diags, false);
+ std::unique_ptr<clang::CompilerInvocation> Invocation(
+ tooling::newInvocation(&Diagnostics, CC1Args));
+ std::unique_ptr<llvm::MemoryBuffer> Input =
+ llvm::MemoryBuffer::getMemBuffer(S);
+ Invocation->getPreprocessorOpts().addRemappedFile("./test.cc",
+ Input.release());
+ std::unique_ptr<tooling::ToolAction> action(
+ tooling::newFrontendActionFactory<clang::EmitObjAction>());
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps =
+ std::make_shared<PCHContainerOperations>();
+ action->runInvocation(std::move(Invocation), Files.get(), PCHContainerOps,
+ &Diags);
+}
+
diff --git a/tools/clang-fuzzer/handle-cxx/handle_cxx.h b/tools/clang-fuzzer/handle-cxx/handle_cxx.h
new file mode 100644
index 0000000000..e76311ff39
--- /dev/null
+++ b/tools/clang-fuzzer/handle-cxx/handle_cxx.h
@@ -0,0 +1,25 @@
+//==-- handle_cxx.h - Helper function for Clang fuzzers --------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines HandleCXX for use by the Clang fuzzers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_CLANG_FUZZER_HANDLE_CXX_HANDLECXX_H
+#define LLVM_CLANG_TOOLS_CLANG_FUZZER_HANDLE_CXX_HANDLECXX_H
+
+#include <string>
+#include <vector>
+
+namespace clang_fuzzer {
+void HandleCXX(const std::string &S,
+ const std::vector<const char *> &ExtraArgs);
+} // namespace clang_fuzzer
+
+#endif
diff --git a/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt b/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
new file mode 100644
index 0000000000..2b0ade4455
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD})
+set(CMAKE_CXX_FLAGS ${CXX_FLAGS_NOFUZZ})
+
+# Hack to bypass LLVM's CMake source checks so we can have both a library and
+# an executable built from this directory.
+set(LLVM_OPTIONAL_SOURCES proto_to_cxx.cpp proto_to_cxx_main.cpp)
+
+add_clang_library(clangProtoToCXX proto_to_cxx.cpp
+ DEPENDS clangCXXProto
+ LINK_LIBS clangCXXProto ${PROTOBUF_LIBRARIES}
+ )
+
+add_clang_executable(clang-proto-to-cxx proto_to_cxx_main.cpp)
+target_link_libraries(clang-proto-to-cxx clangProtoToCXX)
diff --git a/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp
new file mode 100644
index 0000000000..cd75e0c99c
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp
@@ -0,0 +1,102 @@
+//==-- proto_to_cxx.cpp - Protobuf-C++ conversion --------------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements functions for converting between protobufs and C++.
+//
+//===----------------------------------------------------------------------===//
+
+#include "proto_to_cxx.h"
+#include "cxx_proto.pb.h"
+
+#include <ostream>
+#include <sstream>
+
+namespace clang_fuzzer {
+
+// Forward decls.
+std::ostream &operator<<(std::ostream &os, const BinaryOp &x);
+std::ostream &operator<<(std::ostream &os, const StatementSeq &x);
+
+// Proto to C++.
+std::ostream &operator<<(std::ostream &os, const Const &x) {
+ return os << "(" << x.val() << ")";
+}
+std::ostream &operator<<(std::ostream &os, const VarRef &x) {
+ return os << "a[" << (static_cast<uint32_t>(x.varnum()) % 100) << "]";
+}
+std::ostream &operator<<(std::ostream &os, const Lvalue &x) {
+ return os << x.varref();
+}
+std::ostream &operator<<(std::ostream &os, const Rvalue &x) {
+ if (x.has_varref()) return os << x.varref();
+ if (x.has_cons()) return os << x.cons();
+ if (x.has_binop()) return os << x.binop();
+ return os << "1";
+}
+std::ostream &operator<<(std::ostream &os, const BinaryOp &x) {
+ os << "(" << x.left();
+ switch (x.op()) {
+ case BinaryOp::PLUS: os << "+"; break;
+ case BinaryOp::MINUS: os << "-"; break;
+ case BinaryOp::MUL: os << "*"; break;
+ case BinaryOp::DIV: os << "/"; break;
+ case BinaryOp::MOD: os << "%"; break;
+ case BinaryOp::XOR: os << "^"; break;
+ case BinaryOp::AND: os << "&"; break;
+ case BinaryOp::OR: os << "|"; break;
+ case BinaryOp::EQ: os << "=="; break;
+ case BinaryOp::NE: os << "!="; break;
+ case BinaryOp::LE: os << "<="; break;
+ case BinaryOp::GE: os << ">="; break;
+ case BinaryOp::LT: os << "<"; break;
+ case BinaryOp::GT: os << ">"; break;
+ }
+ return os << x.right() << ")";
+}
+std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) {
+ return os << x.lvalue() << "=" << x.rvalue() << ";\n";
+}
+std::ostream &operator<<(std::ostream &os, const IfElse &x) {
+ return os << "if (" << x.cond() << "){\n"
+ << x.if_body() << "} else { \n"
+ << x.else_body() << "}\n";
+}
+std::ostream &operator<<(std::ostream &os, const While &x) {
+ return os << "while (" << x.cond() << "){\n" << x.body() << "}\n";
+}
+std::ostream &operator<<(std::ostream &os, const Statement &x) {
+ if (x.has_assignment()) return os << x.assignment();
+ if (x.has_ifelse()) return os << x.ifelse();
+ if (x.has_while_loop()) return os << x.while_loop();
+ return os << "(void)0;\n";
+}
+std::ostream &operator<<(std::ostream &os, const StatementSeq &x) {
+ for (auto &st : x.statements()) os << st;
+ return os;
+}
+std::ostream &operator<<(std::ostream &os, const Function &x) {
+ return os << "void foo(int *a) {\n" << x.statements() << "}\n";
+}
+
+// ---------------------------------
+
+std::string FunctionToString(const Function &input) {
+ std::ostringstream os;
+ os << input;
+ return os.str();
+
+}
+std::string ProtoToCxx(const uint8_t *data, size_t size) {
+ Function message;
+ if (!message.ParseFromArray(data, size))
+ return "#error invalid proto\n";
+ return FunctionToString(message);
+}
+
+} // namespace clang_fuzzer
diff --git a/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h
new file mode 100644
index 0000000000..1985e91ba2
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h
@@ -0,0 +1,22 @@
+//==-- proto_to_cxx.h - Protobuf-C++ conversion ----------------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines functions for converting between protobufs and C++.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdint>
+#include <cstddef>
+#include <string>
+
+namespace clang_fuzzer {
+class Function;
+std::string FunctionToString(const Function &input);
+std::string ProtoToCxx(const uint8_t *data, size_t size);
+}
diff --git a/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx_main.cpp b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx_main.cpp
new file mode 100644
index 0000000000..73ef14b755
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx_main.cpp
@@ -0,0 +1,30 @@
+//==-- proto_to_cxx_main.cpp - Driver for protobuf-C++ conversion ----------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a simple driver to print a C++ program from a protobuf.
+//
+//===----------------------------------------------------------------------===//
+#include <fstream>
+#include <iostream>
+#include <streambuf>
+#include <string>
+
+#include "proto_to_cxx.h"
+
+int main(int argc, char **argv) {
+ for (int i = 1; i < argc; i++) {
+ std::fstream in(argv[i]);
+ std::string str((std::istreambuf_iterator<char>(in)),
+ std::istreambuf_iterator<char>());
+ std::cout << "// " << argv[i] << std::endl;
+ std::cout << clang_fuzzer::ProtoToCxx(
+ reinterpret_cast<const uint8_t *>(str.data()), str.size());
+ }
+}
+
diff --git a/tools/clang-import-test/CMakeLists.txt b/tools/clang-import-test/CMakeLists.txt
index bd4919694a..85e833d37b 100644
--- a/tools/clang-import-test/CMakeLists.txt
+++ b/tools/clang-import-test/CMakeLists.txt
@@ -17,6 +17,7 @@ set(CLANG_IMPORT_TEST_LIB_DEPS
clangAST
clangBasic
clangCodeGen
+ clangDriver
clangFrontend
clangLex
clangParse
diff --git a/tools/clang-import-test/clang-import-test.cpp b/tools/clang-import-test/clang-import-test.cpp
index 33190af4bf..1ea7ee3611 100644
--- a/tools/clang-import-test/clang-import-test.cpp
+++ b/tools/clang-import-test/clang-import-test.cpp
@@ -9,19 +9,25 @@
#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"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Driver/Types.h"
+#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Host.h"
@@ -40,11 +46,30 @@ static llvm::cl::list<std::string>
Imports("import", llvm::cl::ZeroOrMore,
llvm::cl::desc("Path to a file containing declarations to import"));
+static llvm::cl::opt<bool>
+ Direct("direct", llvm::cl::Optional,
+ llvm::cl::desc("Use the parsed declarations without indirection"));
+
+static llvm::cl::opt<bool>
+ UseOrigins("use-origins", llvm::cl::Optional,
+ llvm::cl::desc("Use DeclContext origin information for more accurate lookups"));
+
static llvm::cl::list<std::string>
ClangArgs("Xcc", llvm::cl::ZeroOrMore,
llvm::cl::desc("Argument to pass to the CompilerInvocation"),
llvm::cl::CommaSeparated);
+static llvm::cl::opt<std::string>
+ Input("x", llvm::cl::Optional,
+ llvm::cl::desc("The language to parse (default: c++)"),
+ llvm::cl::init("c++"));
+
+static llvm::cl::opt<bool> DumpAST("dump-ast", llvm::cl::init(false),
+ llvm::cl::desc("Dump combined AST"));
+
+static llvm::cl::opt<bool> DumpIR("dump-ir", llvm::cl::init(false),
+ llvm::cl::desc("Dump IR from final parse"));
+
namespace init_convenience {
class TestDiagnosticConsumer : public DiagnosticConsumer {
private:
@@ -98,6 +123,7 @@ private:
llvm::errs() << LineString << '\n';
llvm::errs().indent(LocColumn);
llvm::errs() << '^';
+ llvm::errs() << '\n';
}
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
@@ -130,8 +156,7 @@ private:
}
};
-std::unique_ptr<CompilerInstance>
-BuildCompilerInstance(ArrayRef<const char *> ClangArgv) {
+std::unique_ptr<CompilerInstance> BuildCompilerInstance() {
auto Ins = llvm::make_unique<CompilerInstance>();
auto DC = llvm::make_unique<TestDiagnosticConsumer>();
const bool ShouldOwnClient = true;
@@ -139,13 +164,27 @@ BuildCompilerInstance(ArrayRef<const char *> ClangArgv) {
auto Inv = llvm::make_unique<CompilerInvocation>();
+ std::vector<const char *> ClangArgv(ClangArgs.size());
+ std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
+ [](const std::string &s) -> const char * { return s.data(); });
CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(),
&ClangArgv.data()[ClangArgv.size()],
Ins->getDiagnostics());
- Inv->getLangOpts()->CPlusPlus = true;
- Inv->getLangOpts()->CPlusPlus11 = true;
- Inv->getHeaderSearchOpts().UseLibcxx = true;
+ {
+ using namespace driver::types;
+ ID Id = lookupTypeForTypeSpecifier(Input.c_str());
+ assert(Id != TY_INVALID);
+ if (isCXX(Id)) {
+ Inv->getLangOpts()->CPlusPlus = true;
+ Inv->getLangOpts()->CPlusPlus11 = true;
+ Inv->getHeaderSearchOpts().UseLibcxx = true;
+ }
+ if (isObjC(Id)) {
+ Inv->getLangOpts()->ObjC1 = 1;
+ Inv->getLangOpts()->ObjC2 = 1;
+ }
+ }
Inv->getLangOpts()->Bool = true;
Inv->getLangOpts()->WChar = true;
Inv->getLangOpts()->Blocks = true;
@@ -189,65 +228,59 @@ 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);
- }
+/// A container for a CompilerInstance (possibly with an ExternalASTMerger
+/// attached to its ASTContext).
+///
+/// Provides an accessor for the DeclContext origins associated with the
+/// ExternalASTMerger (or an empty list of origins if no ExternalASTMerger is
+/// attached).
+///
+/// This is the main unit of parsed source code maintained by clang-import-test.
+struct CIAndOrigins {
+ using OriginMap = clang::ExternalASTMerger::OriginMap;
+ std::unique_ptr<CompilerInstance> CI;
+
+ ASTContext &getASTContext() { return CI->getASTContext(); }
+ FileManager &getFileManager() { return CI->getFileManager(); }
+ const OriginMap &getOriginMap() {
+ static const OriginMap EmptyOriginMap;
+ if (ExternalASTSource *Source = CI->getASTContext().getExternalSource())
+ return static_cast<ExternalASTMerger *>(Source)->GetOrigins();
+ return EmptyOriginMap;
}
-
- 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;
- }
+ DiagnosticConsumer &getDiagnosticClient() {
+ return CI->getDiagnosticClient();
}
+ CompilerInstance &getCompilerInstance() { return *CI; }
};
-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();
+void AddExternalSource(CIAndOrigins &CI,
+ llvm::MutableArrayRef<CIAndOrigins> Imports) {
+ ExternalASTMerger::ImporterTarget Target(
+ {CI.getASTContext(), CI.getFileManager()});
+ llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources;
+ for (CIAndOrigins &Import : Imports)
+ Sources.push_back(
+ {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()});
+ auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
+ CI.getASTContext().setExternalSource(ES.release());
+ CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
+}
+
+CIAndOrigins BuildIndirect(CIAndOrigins &CI) {
+ CIAndOrigins IndirectCI{init_convenience::BuildCompilerInstance()};
+ auto ST = llvm::make_unique<SelectorTable>();
+ auto BC = llvm::make_unique<Builtin::Context>();
+ std::unique_ptr<ASTContext> AST = init_convenience::BuildASTContext(
+ IndirectCI.getCompilerInstance(), *ST, *BC);
+ IndirectCI.getCompilerInstance().setASTContext(AST.release());
+ AddExternalSource(IndirectCI, CI);
+ return IndirectCI;
}
llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
- CodeGenerator &CG) {
+ ASTConsumer &Consumer) {
SourceManager &SM = CI.getSourceManager();
const FileEntry *FE = CI.getFileManager().getFile(Path);
if (!FE) {
@@ -255,65 +288,91 @@ llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
llvm::Twine("Couldn't open ", Path), std::error_code());
}
SM.setMainFileID(SM.createFileID(FE, SourceLocation(), SrcMgr::C_User));
- ParseAST(CI.getPreprocessor(), &CG, CI.getASTContext());
+ ParseAST(CI.getPreprocessor(), &Consumer, CI.getASTContext());
return llvm::Error::success();
}
-llvm::Expected<std::unique_ptr<CompilerInstance>>
-Parse(const std::string &Path,
- llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
- std::vector<const char *> ClangArgv(ClangArgs.size());
- std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
- [](const std::string &s) -> const char * { return s.data(); });
- std::unique_ptr<CompilerInstance> CI =
- init_convenience::BuildCompilerInstance(ClangArgv);
+llvm::Expected<CIAndOrigins> Parse(const std::string &Path,
+ llvm::MutableArrayRef<CIAndOrigins> Imports,
+ bool ShouldDumpAST, bool ShouldDumpIR) {
+ CIAndOrigins CI{init_convenience::BuildCompilerInstance()};
auto ST = llvm::make_unique<SelectorTable>();
auto BC = llvm::make_unique<Builtin::Context>();
std::unique_ptr<ASTContext> AST =
- init_convenience::BuildASTContext(*CI, *ST, *BC);
- CI->setASTContext(AST.release());
- AddExternalSource(*CI, Imports);
+ init_convenience::BuildASTContext(CI.getCompilerInstance(), *ST, *BC);
+ CI.getCompilerInstance().setASTContext(AST.release());
+ if (Imports.size())
+ AddExternalSource(CI, Imports);
+
+ std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers;
auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
- std::unique_ptr<CodeGenerator> CG =
- init_convenience::BuildCodeGen(*CI, *LLVMCtx);
- CG->Initialize(CI->getASTContext());
+ ASTConsumers.push_back(
+ init_convenience::BuildCodeGen(CI.getCompilerInstance(), *LLVMCtx));
+ auto &CG = *static_cast<CodeGenerator *>(ASTConsumers.back().get());
- CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
- &CI->getPreprocessor());
- if (llvm::Error PE = ParseSource(Path, *CI, *CG)) {
+ if (ShouldDumpAST)
+ ASTConsumers.push_back(CreateASTDumper("", true, false, false));
+
+ CI.getDiagnosticClient().BeginSourceFile(
+ CI.getCompilerInstance().getLangOpts(),
+ &CI.getCompilerInstance().getPreprocessor());
+ MultiplexConsumer Consumers(std::move(ASTConsumers));
+ Consumers.Initialize(CI.getASTContext());
+
+ if (llvm::Error PE = ParseSource(Path, CI.getCompilerInstance(), Consumers))
return std::move(PE);
- }
- CI->getDiagnosticClient().EndSourceFile();
- if (CI->getDiagnosticClient().getNumErrors()) {
+ CI.getDiagnosticClient().EndSourceFile();
+ if (ShouldDumpIR)
+ CG.GetModule()->print(llvm::outs(), nullptr);
+ if (CI.getDiagnosticClient().getNumErrors())
return llvm::make_error<llvm::StringError>(
"Errors occured while parsing the expression.", std::error_code());
- } else {
- return std::move(CI);
- }
+ return std::move(CI);
}
+
+void Forget(CIAndOrigins &CI, llvm::MutableArrayRef<CIAndOrigins> Imports) {
+ llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources;
+ for (CIAndOrigins &Import : Imports)
+ Sources.push_back(
+ {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()});
+ ExternalASTSource *Source = CI.CI->getASTContext().getExternalSource();
+ auto *Merger = static_cast<ExternalASTMerger *>(Source);
+ Merger->RemoveSources(Sources);
+}
+
} // end namespace
int main(int argc, const char **argv) {
const bool DisableCrashReporting = true;
llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
llvm::cl::ParseCommandLineOptions(argc, argv);
- std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
+ std::vector<CIAndOrigins> ImportCIs;
for (auto I : Imports) {
- llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI = Parse(I, {});
+ llvm::Expected<CIAndOrigins> ImportCI = Parse(I, {}, false, false);
if (auto E = ImportCI.takeError()) {
llvm::errs() << llvm::toString(std::move(E));
exit(-1);
- } else {
- ImportCIs.push_back(std::move(*ImportCI));
+ }
+ ImportCIs.push_back(std::move(*ImportCI));
+ }
+ std::vector<CIAndOrigins> IndirectCIs;
+ if (!Direct || UseOrigins) {
+ for (auto &ImportCI : ImportCIs) {
+ CIAndOrigins IndirectCI = BuildIndirect(ImportCI);
+ IndirectCIs.push_back(std::move(IndirectCI));
}
}
- llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
- Parse(Expression, ImportCIs);
+ if (UseOrigins)
+ for (auto &ImportCI : ImportCIs)
+ IndirectCIs.push_back(std::move(ImportCI));
+ llvm::Expected<CIAndOrigins> ExpressionCI =
+ Parse(Expression, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs,
+ DumpAST, DumpIR);
if (auto E = ExpressionCI.takeError()) {
llvm::errs() << llvm::toString(std::move(E));
exit(-1);
- } else {
- return 0;
}
+ Forget(*ExpressionCI, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs);
+ return 0;
}
diff --git a/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
index f37868fb61..6ff4becb50 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
@@ -915,8 +915,7 @@ static bool UnbundleFiles() {
return false;
}
-static void PrintVersion() {
- raw_ostream &OS = outs();
+static void PrintVersion(raw_ostream &OS) {
OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n';
}
@@ -932,8 +931,10 @@ int main(int argc, const char **argv) {
"one. The resulting file can also be unbundled into different files by \n"
"this tool if -unbundle is provided.\n");
- if (Help)
+ if (Help) {
cl::PrintHelpMessage();
+ return 0;
+ }
bool Error = false;
if (Unbundle) {
diff --git a/tools/clang-refactor/CMakeLists.txt b/tools/clang-refactor/CMakeLists.txt
new file mode 100644
index 0000000000..c20e83bacf
--- /dev/null
+++ b/tools/clang-refactor/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_LINK_COMPONENTS
+ Option
+ Support
+ )
+
+add_clang_tool(clang-refactor
+ ClangRefactor.cpp
+ TestSupport.cpp
+ )
+
+target_link_libraries(clang-refactor
+ clangAST
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangLex
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ clangToolingRefactor
+ )
+
+install(TARGETS clang-refactor RUNTIME DESTINATION bin)
diff --git a/tools/clang-refactor/ClangRefactor.cpp b/tools/clang-refactor/ClangRefactor.cpp
new file mode 100644
index 0000000000..523c3a6220
--- /dev/null
+++ b/tools/clang-refactor/ClangRefactor.cpp
@@ -0,0 +1,577 @@
+//===--- ClangRefactor.cpp - Clang-based refactoring tool -----------------===//
+//
+// 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 a clang-refactor tool that performs various
+/// source transformations.
+///
+//===----------------------------------------------------------------------===//
+
+#include "TestSupport.h"
+#include "clang/Frontend/CommandLineSourceLoc.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+using namespace tooling;
+using namespace refactor;
+namespace cl = llvm::cl;
+
+namespace opts {
+
+static cl::OptionCategory CommonRefactorOptions("Refactoring options");
+
+static cl::opt<bool> Verbose("v", cl::desc("Use verbose output"),
+ cl::cat(cl::GeneralCategory),
+ cl::sub(*cl::AllSubCommands));
+
+static cl::opt<bool> Inplace("i", cl::desc("Inplace edit <file>s"),
+ cl::cat(cl::GeneralCategory),
+ cl::sub(*cl::AllSubCommands));
+
+} // end namespace opts
+
+namespace {
+
+/// Stores the parsed `-selection` argument.
+class SourceSelectionArgument {
+public:
+ virtual ~SourceSelectionArgument() {}
+
+ /// Parse the `-selection` argument.
+ ///
+ /// \returns A valid argument when the parse succedeed, null otherwise.
+ static std::unique_ptr<SourceSelectionArgument> fromString(StringRef Value);
+
+ /// Prints any additional state associated with the selection argument to
+ /// the given output stream.
+ virtual void print(raw_ostream &OS) {}
+
+ /// Returns a replacement refactoring result consumer (if any) that should
+ /// consume the results of a refactoring operation.
+ ///
+ /// The replacement refactoring result consumer is used by \c
+ /// TestSourceSelectionArgument to inject a test-specific result handling
+ /// logic into the refactoring operation. The test-specific consumer
+ /// ensures that the individual results in a particular test group are
+ /// identical.
+ virtual std::unique_ptr<ClangRefactorToolConsumerInterface>
+ createCustomConsumer() {
+ return nullptr;
+ }
+
+ /// Runs the give refactoring function for each specified selection.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ virtual bool
+ forAllRanges(const SourceManager &SM,
+ llvm::function_ref<void(SourceRange R)> Callback) = 0;
+};
+
+/// Stores the parsed -selection=test:<filename> option.
+class TestSourceSelectionArgument final : public SourceSelectionArgument {
+public:
+ TestSourceSelectionArgument(TestSelectionRangesInFile TestSelections)
+ : TestSelections(std::move(TestSelections)) {}
+
+ void print(raw_ostream &OS) override { TestSelections.dump(OS); }
+
+ std::unique_ptr<ClangRefactorToolConsumerInterface>
+ createCustomConsumer() override {
+ return TestSelections.createConsumer();
+ }
+
+ /// Testing support: invokes the selection action for each selection range in
+ /// the test file.
+ bool forAllRanges(const SourceManager &SM,
+ llvm::function_ref<void(SourceRange R)> Callback) override {
+ return TestSelections.foreachRange(SM, Callback);
+ }
+
+private:
+ TestSelectionRangesInFile TestSelections;
+};
+
+/// Stores the parsed -selection=filename:line:column[-line:column] option.
+class SourceRangeSelectionArgument final : public SourceSelectionArgument {
+public:
+ SourceRangeSelectionArgument(ParsedSourceRange Range)
+ : Range(std::move(Range)) {}
+
+ bool forAllRanges(const SourceManager &SM,
+ llvm::function_ref<void(SourceRange R)> Callback) override {
+ const FileEntry *FE = SM.getFileManager().getFile(Range.FileName);
+ FileID FID = FE ? SM.translateFile(FE) : FileID();
+ if (!FE || FID.isInvalid()) {
+ llvm::errs() << "error: -selection=" << Range.FileName
+ << ":... : given file is not in the target TU\n";
+ return true;
+ }
+
+ SourceLocation Start = SM.getMacroArgExpandedLocation(
+ SM.translateLineCol(FID, Range.Begin.first, Range.Begin.second));
+ SourceLocation End = SM.getMacroArgExpandedLocation(
+ SM.translateLineCol(FID, Range.End.first, Range.End.second));
+ if (Start.isInvalid() || End.isInvalid()) {
+ llvm::errs() << "error: -selection=" << Range.FileName << ':'
+ << Range.Begin.first << ':' << Range.Begin.second << '-'
+ << Range.End.first << ':' << Range.End.second
+ << " : invalid source location\n";
+ return true;
+ }
+ Callback(SourceRange(Start, End));
+ return false;
+ }
+
+private:
+ ParsedSourceRange Range;
+};
+
+std::unique_ptr<SourceSelectionArgument>
+SourceSelectionArgument::fromString(StringRef Value) {
+ if (Value.startswith("test:")) {
+ StringRef Filename = Value.drop_front(strlen("test:"));
+ Optional<TestSelectionRangesInFile> ParsedTestSelection =
+ findTestSelectionRanges(Filename);
+ if (!ParsedTestSelection)
+ return nullptr; // A parsing error was already reported.
+ return llvm::make_unique<TestSourceSelectionArgument>(
+ std::move(*ParsedTestSelection));
+ }
+ Optional<ParsedSourceRange> Range = ParsedSourceRange::fromString(Value);
+ if (Range)
+ return llvm::make_unique<SourceRangeSelectionArgument>(std::move(*Range));
+ llvm::errs() << "error: '-selection' option must be specified using "
+ "<file>:<line>:<column> or "
+ "<file>:<line>:<column>-<line>:<column> format\n";
+ return nullptr;
+}
+
+/// A container that stores the command-line options used by a single
+/// refactoring option.
+class RefactoringActionCommandLineOptions {
+public:
+ void addStringOption(const RefactoringOption &Option,
+ std::unique_ptr<cl::opt<std::string>> CLOption) {
+ StringOptions[&Option] = std::move(CLOption);
+ }
+
+ const cl::opt<std::string> &
+ getStringOption(const RefactoringOption &Opt) const {
+ auto It = StringOptions.find(&Opt);
+ return *It->second;
+ }
+
+private:
+ llvm::DenseMap<const RefactoringOption *,
+ std::unique_ptr<cl::opt<std::string>>>
+ StringOptions;
+};
+
+/// Passes the command-line option values to the options used by a single
+/// refactoring action rule.
+class CommandLineRefactoringOptionVisitor final
+ : public RefactoringOptionVisitor {
+public:
+ CommandLineRefactoringOptionVisitor(
+ const RefactoringActionCommandLineOptions &Options)
+ : Options(Options) {}
+
+ void visit(const RefactoringOption &Opt,
+ Optional<std::string> &Value) override {
+ const cl::opt<std::string> &CLOpt = Options.getStringOption(Opt);
+ if (!CLOpt.getValue().empty()) {
+ Value = CLOpt.getValue();
+ return;
+ }
+ Value = None;
+ if (Opt.isRequired())
+ MissingRequiredOptions.push_back(&Opt);
+ }
+
+ ArrayRef<const RefactoringOption *> getMissingRequiredOptions() const {
+ return MissingRequiredOptions;
+ }
+
+private:
+ llvm::SmallVector<const RefactoringOption *, 4> MissingRequiredOptions;
+ const RefactoringActionCommandLineOptions &Options;
+};
+
+/// Creates the refactoring options used by all the rules in a single
+/// refactoring action.
+class CommandLineRefactoringOptionCreator final
+ : public RefactoringOptionVisitor {
+public:
+ CommandLineRefactoringOptionCreator(
+ cl::OptionCategory &Category, cl::SubCommand &Subcommand,
+ RefactoringActionCommandLineOptions &Options)
+ : Category(Category), Subcommand(Subcommand), Options(Options) {}
+
+ void visit(const RefactoringOption &Opt, Optional<std::string> &) override {
+ if (Visited.insert(&Opt).second)
+ Options.addStringOption(Opt, create<std::string>(Opt));
+ }
+
+private:
+ template <typename T>
+ std::unique_ptr<cl::opt<T>> create(const RefactoringOption &Opt) {
+ if (!OptionNames.insert(Opt.getName()).second)
+ llvm::report_fatal_error("Multiple identical refactoring options "
+ "specified for one refactoring action");
+ // FIXME: cl::Required can be specified when this option is present
+ // in all rules in an action.
+ return llvm::make_unique<cl::opt<T>>(
+ Opt.getName(), cl::desc(Opt.getDescription()), cl::Optional,
+ cl::cat(Category), cl::sub(Subcommand));
+ }
+
+ llvm::SmallPtrSet<const RefactoringOption *, 8> Visited;
+ llvm::StringSet<> OptionNames;
+ cl::OptionCategory &Category;
+ cl::SubCommand &Subcommand;
+ RefactoringActionCommandLineOptions &Options;
+};
+
+/// A subcommand that corresponds to individual refactoring action.
+class RefactoringActionSubcommand : public cl::SubCommand {
+public:
+ RefactoringActionSubcommand(std::unique_ptr<RefactoringAction> Action,
+ RefactoringActionRules ActionRules,
+ cl::OptionCategory &Category)
+ : SubCommand(Action->getCommand(), Action->getDescription()),
+ Action(std::move(Action)), ActionRules(std::move(ActionRules)) {
+ // Check if the selection option is supported.
+ bool HasSelection = false;
+ for (const auto &Rule : this->ActionRules) {
+ if ((HasSelection = Rule->hasSelectionRequirement()))
+ break;
+ }
+ if (HasSelection) {
+ Selection = llvm::make_unique<cl::opt<std::string>>(
+ "selection",
+ cl::desc("The selected source range in which the refactoring should "
+ "be initiated (<file>:<line>:<column>-<line>:<column> or "
+ "<file>:<line>:<column>)"),
+ cl::cat(Category), cl::sub(*this));
+ }
+ // Create the refactoring options.
+ for (const auto &Rule : this->ActionRules) {
+ CommandLineRefactoringOptionCreator OptionCreator(Category, *this,
+ Options);
+ Rule->visitRefactoringOptions(OptionCreator);
+ }
+ }
+
+ ~RefactoringActionSubcommand() { unregisterSubCommand(); }
+
+ const RefactoringActionRules &getActionRules() const { return ActionRules; }
+
+ /// Parses the command-line arguments that are specific to this rule.
+ ///
+ /// \returns true on error, false otherwise.
+ bool parseArguments() {
+ if (Selection) {
+ ParsedSelection = SourceSelectionArgument::fromString(*Selection);
+ if (!ParsedSelection)
+ return true;
+ }
+ return false;
+ }
+
+ SourceSelectionArgument *getSelection() const {
+ assert(Selection && "selection not supported!");
+ return ParsedSelection.get();
+ }
+
+ const RefactoringActionCommandLineOptions &getOptions() const {
+ return Options;
+ }
+
+private:
+ std::unique_ptr<RefactoringAction> Action;
+ RefactoringActionRules ActionRules;
+ std::unique_ptr<cl::opt<std::string>> Selection;
+ std::unique_ptr<SourceSelectionArgument> ParsedSelection;
+ RefactoringActionCommandLineOptions Options;
+};
+
+class ClangRefactorConsumer final : public ClangRefactorToolConsumerInterface {
+public:
+ ClangRefactorConsumer() {}
+
+ void handleError(llvm::Error Err) override {
+ Optional<PartialDiagnosticAt> Diag = DiagnosticError::take(Err);
+ if (!Diag) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ return;
+ }
+ llvm::cantFail(std::move(Err)); // This is a success.
+ DiagnosticBuilder DB(
+ getDiags().Report(Diag->first, Diag->second.getDiagID()));
+ Diag->second.Emit(DB);
+ }
+
+ void handle(AtomicChanges Changes) override {
+ SourceChanges.insert(SourceChanges.begin(), Changes.begin(), Changes.end());
+ }
+
+ void handle(SymbolOccurrences Occurrences) override {
+ llvm_unreachable("symbol occurrence results are not handled yet");
+ }
+
+ const AtomicChanges &getSourceChanges() const { return SourceChanges; }
+
+private:
+ AtomicChanges SourceChanges;
+};
+
+class ClangRefactorTool {
+public:
+ std::vector<std::unique_ptr<RefactoringActionSubcommand>> SubCommands;
+
+ ClangRefactorTool() {
+ std::vector<std::unique_ptr<RefactoringAction>> Actions =
+ createRefactoringActions();
+
+ // Actions must have unique command names so that we can map them to one
+ // subcommand.
+ llvm::StringSet<> CommandNames;
+ for (const auto &Action : Actions) {
+ if (!CommandNames.insert(Action->getCommand()).second) {
+ llvm::errs() << "duplicate refactoring action command '"
+ << Action->getCommand() << "'!";
+ exit(1);
+ }
+ }
+
+ // Create subcommands and command-line options.
+ for (auto &Action : Actions) {
+ SubCommands.push_back(llvm::make_unique<RefactoringActionSubcommand>(
+ std::move(Action), Action->createActiveActionRules(),
+ opts::CommonRefactorOptions));
+ }
+ }
+
+ using TUCallbackType = llvm::function_ref<void(ASTContext &)>;
+
+ /// Parses the translation units that were given to the subcommand using
+ /// the 'sources' option and invokes the callback for each parsed
+ /// translation unit.
+ bool foreachTranslationUnit(const CompilationDatabase &DB,
+ ArrayRef<std::string> Sources,
+ TUCallbackType Callback) {
+ class ToolASTConsumer : public ASTConsumer {
+ public:
+ TUCallbackType Callback;
+ ToolASTConsumer(TUCallbackType Callback) : Callback(Callback) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ Callback(Context);
+ }
+ };
+ class ActionWrapper {
+ public:
+ TUCallbackType Callback;
+ ActionWrapper(TUCallbackType Callback) : Callback(Callback) {}
+
+ std::unique_ptr<ASTConsumer> newASTConsumer() {
+ return llvm::make_unique<ToolASTConsumer>(Callback);
+ }
+ };
+
+ ClangTool Tool(DB, Sources);
+ ActionWrapper ToolAction(Callback);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory =
+ tooling::newFrontendActionFactory(&ToolAction);
+ return Tool.run(Factory.get());
+ }
+
+ /// Logs an individual refactoring action invocation to STDOUT.
+ void logInvocation(RefactoringActionSubcommand &Subcommand,
+ const RefactoringRuleContext &Context) {
+ if (!opts::Verbose)
+ return;
+ llvm::outs() << "invoking action '" << Subcommand.getName() << "':\n";
+ if (Context.getSelectionRange().isValid()) {
+ SourceRange R = Context.getSelectionRange();
+ llvm::outs() << " -selection=";
+ R.getBegin().print(llvm::outs(), Context.getSources());
+ llvm::outs() << " -> ";
+ R.getEnd().print(llvm::outs(), Context.getSources());
+ llvm::outs() << "\n";
+ }
+ }
+
+ bool applySourceChanges(const AtomicChanges &Replacements) {
+ std::set<std::string> Files;
+ for (const auto &Change : Replacements)
+ Files.insert(Change.getFilePath());
+ // FIXME: Add automatic formatting support as well.
+ tooling::ApplyChangesSpec Spec;
+ // FIXME: We should probably cleanup the result by default as well.
+ Spec.Cleanup = false;
+ for (const auto &File : Files) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
+ llvm::MemoryBuffer::getFile(File);
+ if (!BufferErr) {
+ llvm::errs() << "error: failed to open " << File << " for rewriting\n";
+ return true;
+ }
+ auto Result = tooling::applyAtomicChanges(File, (*BufferErr)->getBuffer(),
+ Replacements, Spec);
+ if (!Result) {
+ llvm::errs() << toString(Result.takeError());
+ return true;
+ }
+
+ if (opts::Inplace) {
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ llvm::errs() << EC.message() << "\n";
+ return true;
+ }
+ OS << *Result;
+ continue;
+ }
+
+ llvm::outs() << *Result;
+ }
+ return false;
+ }
+
+ bool invokeAction(RefactoringActionSubcommand &Subcommand,
+ const CompilationDatabase &DB,
+ ArrayRef<std::string> Sources) {
+ // Find a set of matching rules.
+ SmallVector<RefactoringActionRule *, 4> MatchingRules;
+ llvm::StringSet<> MissingOptions;
+
+ bool HasSelection = false;
+ for (const auto &Rule : Subcommand.getActionRules()) {
+ bool SelectionMatches = true;
+ if (Rule->hasSelectionRequirement()) {
+ HasSelection = true;
+ if (!Subcommand.getSelection()) {
+ MissingOptions.insert("selection");
+ SelectionMatches = false;
+ }
+ }
+ CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
+ Rule->visitRefactoringOptions(Visitor);
+ if (SelectionMatches && Visitor.getMissingRequiredOptions().empty()) {
+ MatchingRules.push_back(Rule.get());
+ continue;
+ }
+ for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
+ MissingOptions.insert(Opt->getName());
+ }
+ if (MatchingRules.empty()) {
+ llvm::errs() << "error: '" << Subcommand.getName()
+ << "' can't be invoked with the given arguments:\n";
+ for (const auto &Opt : MissingOptions)
+ llvm::errs() << " missing '-" << Opt.getKey() << "' option\n";
+ return true;
+ }
+
+ ClangRefactorConsumer Consumer;
+ bool HasFailed = false;
+ if (foreachTranslationUnit(DB, Sources, [&](ASTContext &AST) {
+ RefactoringRuleContext Context(AST.getSourceManager());
+ Context.setASTContext(AST);
+
+ auto InvokeRule = [&](RefactoringResultConsumer &Consumer) {
+ logInvocation(Subcommand, Context);
+ for (RefactoringActionRule *Rule : MatchingRules) {
+ if (!Rule->hasSelectionRequirement())
+ continue;
+ Rule->invoke(Consumer, Context);
+ return;
+ }
+ // FIXME (Alex L): If more than one initiation succeeded, then the
+ // rules are ambiguous.
+ llvm_unreachable(
+ "The action must have at least one selection rule");
+ };
+
+ std::unique_ptr<ClangRefactorToolConsumerInterface> CustomConsumer;
+ if (HasSelection)
+ CustomConsumer = Subcommand.getSelection()->createCustomConsumer();
+ ClangRefactorToolConsumerInterface &ActiveConsumer =
+ CustomConsumer ? *CustomConsumer : Consumer;
+ ActiveConsumer.beginTU(AST);
+ if (HasSelection) {
+ assert(Subcommand.getSelection() && "Missing selection argument?");
+ if (opts::Verbose)
+ Subcommand.getSelection()->print(llvm::outs());
+ if (Subcommand.getSelection()->forAllRanges(
+ Context.getSources(), [&](SourceRange R) {
+ Context.setSelectionRange(R);
+ InvokeRule(ActiveConsumer);
+ }))
+ HasFailed = true;
+ ActiveConsumer.endTU();
+ return;
+ }
+ // FIXME (Alex L): Implement non-selection based invocation path.
+ ActiveConsumer.endTU();
+ }))
+ return true;
+ return HasFailed || applySourceChanges(Consumer.getSourceChanges());
+ }
+};
+
+} // end anonymous namespace
+
+int main(int argc, const char **argv) {
+ ClangRefactorTool Tool;
+
+ CommonOptionsParser Options(
+ argc, argv, cl::GeneralCategory, cl::ZeroOrMore,
+ "Clang-based refactoring tool for C, C++ and Objective-C");
+
+ // Figure out which action is specified by the user. The user must specify
+ // the action using a command-line subcommand, e.g. the invocation
+ // `clang-refactor local-rename` corresponds to the `LocalRename` refactoring
+ // action. All subcommands must have a unique names. This allows us to figure
+ // out which refactoring action should be invoked by looking at the first
+ // subcommand that's enabled by LLVM's command-line parser.
+ auto It = llvm::find_if(
+ Tool.SubCommands,
+ [](const std::unique_ptr<RefactoringActionSubcommand> &SubCommand) {
+ return !!(*SubCommand);
+ });
+ if (It == Tool.SubCommands.end()) {
+ llvm::errs() << "error: no refactoring action given\n";
+ llvm::errs() << "note: the following actions are supported:\n";
+ for (const auto &Subcommand : Tool.SubCommands)
+ llvm::errs().indent(2) << Subcommand->getName() << "\n";
+ return 1;
+ }
+ RefactoringActionSubcommand &ActionCommand = **It;
+
+ if (ActionCommand.parseArguments())
+ return 1;
+ if (Tool.invokeAction(ActionCommand, Options.getCompilations(),
+ Options.getSourcePathList()))
+ return 1;
+
+ return 0;
+}
diff --git a/tools/clang-refactor/TestSupport.cpp b/tools/clang-refactor/TestSupport.cpp
new file mode 100644
index 0000000000..9331dfd92e
--- /dev/null
+++ b/tools/clang-refactor/TestSupport.cpp
@@ -0,0 +1,392 @@
+//===--- TestSupport.cpp - Clang-based refactoring tool -------------------===//
+//
+// 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 routines that provide refactoring testing
+/// utilities.
+///
+//===----------------------------------------------------------------------===//
+
+#include "TestSupport.h"
+#include "clang/Basic/DiagnosticError.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace refactor {
+
+void TestSelectionRangesInFile::dump(raw_ostream &OS) const {
+ for (const auto &Group : GroupedRanges) {
+ OS << "Test selection group '" << Group.Name << "':\n";
+ for (const auto &Range : Group.Ranges) {
+ OS << " " << Range.Begin << "-" << Range.End << "\n";
+ }
+ }
+}
+
+bool TestSelectionRangesInFile::foreachRange(
+ const SourceManager &SM,
+ llvm::function_ref<void(SourceRange)> Callback) const {
+ const FileEntry *FE = SM.getFileManager().getFile(Filename);
+ FileID FID = FE ? SM.translateFile(FE) : FileID();
+ if (!FE || FID.isInvalid()) {
+ llvm::errs() << "error: -selection=test:" << Filename
+ << " : given file is not in the target TU";
+ return true;
+ }
+ SourceLocation FileLoc = SM.getLocForStartOfFile(FID);
+ for (const auto &Group : GroupedRanges) {
+ for (const TestSelectionRange &Range : Group.Ranges) {
+ // Translate the offset pair to a true source range.
+ SourceLocation Start =
+ SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Range.Begin));
+ SourceLocation End =
+ SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Range.End));
+ assert(Start.isValid() && End.isValid() && "unexpected invalid range");
+ Callback(SourceRange(Start, End));
+ }
+ }
+ return false;
+}
+
+namespace {
+
+void dumpChanges(const tooling::AtomicChanges &Changes, raw_ostream &OS) {
+ for (const auto &Change : Changes)
+ OS << const_cast<tooling::AtomicChange &>(Change).toYAMLString() << "\n";
+}
+
+bool areChangesSame(const tooling::AtomicChanges &LHS,
+ const tooling::AtomicChanges &RHS) {
+ if (LHS.size() != RHS.size())
+ return false;
+ for (const auto &I : llvm::zip(LHS, RHS)) {
+ if (!(std::get<0>(I) == std::get<1>(I)))
+ return false;
+ }
+ return true;
+}
+
+bool printRewrittenSources(const tooling::AtomicChanges &Changes,
+ raw_ostream &OS) {
+ std::set<std::string> Files;
+ for (const auto &Change : Changes)
+ Files.insert(Change.getFilePath());
+ tooling::ApplyChangesSpec Spec;
+ Spec.Cleanup = false;
+ for (const auto &File : Files) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
+ llvm::MemoryBuffer::getFile(File);
+ if (!BufferErr) {
+ llvm::errs() << "failed to open" << File << "\n";
+ return true;
+ }
+ auto Result = tooling::applyAtomicChanges(File, (*BufferErr)->getBuffer(),
+ Changes, Spec);
+ if (!Result) {
+ llvm::errs() << toString(Result.takeError());
+ return true;
+ }
+ OS << *Result;
+ }
+ return false;
+}
+
+class TestRefactoringResultConsumer final
+ : public ClangRefactorToolConsumerInterface {
+public:
+ TestRefactoringResultConsumer(const TestSelectionRangesInFile &TestRanges)
+ : TestRanges(TestRanges) {
+ Results.push_back({});
+ }
+
+ ~TestRefactoringResultConsumer() {
+ // Ensure all results are checked.
+ for (auto &Group : Results) {
+ for (auto &Result : Group) {
+ if (!Result) {
+ (void)llvm::toString(Result.takeError());
+ }
+ }
+ }
+ }
+
+ void handleError(llvm::Error Err) override { handleResult(std::move(Err)); }
+
+ void handle(tooling::AtomicChanges Changes) override {
+ handleResult(std::move(Changes));
+ }
+
+ void handle(tooling::SymbolOccurrences Occurrences) override {
+ tooling::RefactoringResultConsumer::handle(std::move(Occurrences));
+ }
+
+private:
+ bool handleAllResults();
+
+ void handleResult(Expected<tooling::AtomicChanges> Result) {
+ Results.back().push_back(std::move(Result));
+ size_t GroupIndex = Results.size() - 1;
+ if (Results.back().size() >=
+ TestRanges.GroupedRanges[GroupIndex].Ranges.size()) {
+ ++GroupIndex;
+ if (GroupIndex >= TestRanges.GroupedRanges.size()) {
+ if (handleAllResults())
+ exit(1); // error has occurred.
+ return;
+ }
+ Results.push_back({});
+ }
+ }
+
+ const TestSelectionRangesInFile &TestRanges;
+ std::vector<std::vector<Expected<tooling::AtomicChanges>>> Results;
+};
+
+std::pair<unsigned, unsigned> getLineColumn(StringRef Filename,
+ unsigned Offset) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ErrOrFile =
+ MemoryBuffer::getFile(Filename);
+ if (!ErrOrFile)
+ return {0, 0};
+ StringRef Source = ErrOrFile.get()->getBuffer();
+ Source = Source.take_front(Offset);
+ size_t LastLine = Source.find_last_of("\r\n");
+ return {Source.count('\n') + 1,
+ (LastLine == StringRef::npos ? Offset : Offset - LastLine) + 1};
+}
+
+} // end anonymous namespace
+
+bool TestRefactoringResultConsumer::handleAllResults() {
+ bool Failed = false;
+ for (auto &Group : llvm::enumerate(Results)) {
+ // All ranges in the group must produce the same result.
+ Optional<tooling::AtomicChanges> CanonicalResult;
+ Optional<std::string> CanonicalErrorMessage;
+ for (auto &I : llvm::enumerate(Group.value())) {
+ Expected<tooling::AtomicChanges> &Result = I.value();
+ std::string ErrorMessage;
+ bool HasResult = !!Result;
+ if (!HasResult) {
+ handleAllErrors(
+ Result.takeError(),
+ [&](StringError &Err) { ErrorMessage = Err.getMessage(); },
+ [&](DiagnosticError &Err) {
+ const PartialDiagnosticAt &Diag = Err.getDiagnostic();
+ llvm::SmallString<100> DiagText;
+ Diag.second.EmitToString(getDiags(), DiagText);
+ ErrorMessage = DiagText.str().str();
+ });
+ }
+ if (!CanonicalResult && !CanonicalErrorMessage) {
+ if (HasResult)
+ CanonicalResult = std::move(*Result);
+ else
+ CanonicalErrorMessage = std::move(ErrorMessage);
+ continue;
+ }
+
+ // Verify that this result corresponds to the canonical result.
+ if (CanonicalErrorMessage) {
+ // The error messages must match.
+ if (!HasResult && ErrorMessage == *CanonicalErrorMessage)
+ continue;
+ } else {
+ assert(CanonicalResult && "missing canonical result");
+ // The results must match.
+ if (HasResult && areChangesSame(*Result, *CanonicalResult))
+ continue;
+ }
+ Failed = true;
+ // Report the mismatch.
+ std::pair<unsigned, unsigned> LineColumn = getLineColumn(
+ TestRanges.Filename,
+ TestRanges.GroupedRanges[Group.index()].Ranges[I.index()].Begin);
+ llvm::errs()
+ << "error: unexpected refactoring result for range starting at "
+ << LineColumn.first << ':' << LineColumn.second << " in group '"
+ << TestRanges.GroupedRanges[Group.index()].Name << "':\n ";
+ if (HasResult)
+ llvm::errs() << "valid result";
+ else
+ llvm::errs() << "error '" << ErrorMessage << "'";
+ llvm::errs() << " does not match initial ";
+ if (CanonicalErrorMessage)
+ llvm::errs() << "error '" << *CanonicalErrorMessage << "'\n";
+ else
+ llvm::errs() << "valid result\n";
+ if (HasResult && !CanonicalErrorMessage) {
+ llvm::errs() << " Expected to Produce:\n";
+ dumpChanges(*CanonicalResult, llvm::errs());
+ llvm::errs() << " Produced:\n";
+ dumpChanges(*Result, llvm::errs());
+ }
+ }
+
+ // Dump the results:
+ const auto &TestGroup = TestRanges.GroupedRanges[Group.index()];
+ if (!CanonicalResult) {
+ llvm::outs() << TestGroup.Ranges.size() << " '" << TestGroup.Name
+ << "' results:\n";
+ llvm::outs() << *CanonicalErrorMessage << "\n";
+ } else {
+ llvm::outs() << TestGroup.Ranges.size() << " '" << TestGroup.Name
+ << "' results:\n";
+ if (printRewrittenSources(*CanonicalResult, llvm::outs()))
+ return true;
+ }
+ }
+ return Failed;
+}
+
+std::unique_ptr<ClangRefactorToolConsumerInterface>
+TestSelectionRangesInFile::createConsumer() const {
+ return llvm::make_unique<TestRefactoringResultConsumer>(*this);
+}
+
+/// Adds the \p ColumnOffset to file offset \p Offset, without going past a
+/// newline.
+static unsigned addColumnOffset(StringRef Source, unsigned Offset,
+ unsigned ColumnOffset) {
+ if (!ColumnOffset)
+ return Offset;
+ StringRef Substr = Source.drop_front(Offset).take_front(ColumnOffset);
+ size_t NewlinePos = Substr.find_first_of("\r\n");
+ return Offset +
+ (NewlinePos == StringRef::npos ? ColumnOffset : (unsigned)NewlinePos);
+}
+
+static unsigned addEndLineOffsetAndEndColumn(StringRef Source, unsigned Offset,
+ unsigned LineNumberOffset,
+ unsigned Column) {
+ StringRef Line = Source.drop_front(Offset);
+ unsigned LineOffset = 0;
+ for (; LineNumberOffset != 0; --LineNumberOffset) {
+ size_t NewlinePos = Line.find_first_of("\r\n");
+ // Line offset goes out of bounds.
+ if (NewlinePos == StringRef::npos)
+ break;
+ LineOffset += NewlinePos + 1;
+ Line = Line.drop_front(NewlinePos + 1);
+ }
+ // Source now points to the line at +lineOffset;
+ size_t LineStart = Source.find_last_of("\r\n", /*From=*/Offset + LineOffset);
+ return addColumnOffset(
+ Source, LineStart == StringRef::npos ? 0 : LineStart + 1, Column - 1);
+}
+
+Optional<TestSelectionRangesInFile>
+findTestSelectionRanges(StringRef Filename) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ErrOrFile =
+ MemoryBuffer::getFile(Filename);
+ if (!ErrOrFile) {
+ llvm::errs() << "error: -selection=test:" << Filename
+ << " : could not open the given file";
+ return None;
+ }
+ StringRef Source = ErrOrFile.get()->getBuffer();
+
+ // See the doc comment for this function for the explanation of this
+ // syntax.
+ static Regex RangeRegex("range[[:blank:]]*([[:alpha:]_]*)?[[:blank:]]*=[[:"
+ "blank:]]*(\\+[[:digit:]]+)?[[:blank:]]*(->[[:blank:]"
+ "]*[\\+\\:[:digit:]]+)?");
+
+ std::map<std::string, SmallVector<TestSelectionRange, 8>> GroupedRanges;
+
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = 1;
+ LangOpts.CPlusPlus11 = 1;
+ Lexer Lex(SourceLocation::getFromRawEncoding(0), LangOpts, Source.begin(),
+ Source.begin(), Source.end());
+ Lex.SetCommentRetentionState(true);
+ Token Tok;
+ for (Lex.LexFromRawLexer(Tok); Tok.isNot(tok::eof);
+ Lex.LexFromRawLexer(Tok)) {
+ if (Tok.isNot(tok::comment))
+ continue;
+ StringRef Comment =
+ Source.substr(Tok.getLocation().getRawEncoding(), Tok.getLength());
+ SmallVector<StringRef, 4> Matches;
+ // Try to detect mistyped 'range:' comments to ensure tests don't miss
+ // anything.
+ auto DetectMistypedCommand = [&]() -> bool {
+ if (Comment.contains_lower("range") && Comment.contains("=") &&
+ !Comment.contains_lower("run") && !Comment.contains("CHECK")) {
+ llvm::errs() << "error: suspicious comment '" << Comment
+ << "' that "
+ "resembles the range command found\n";
+ llvm::errs() << "note: please reword if this isn't a range command\n";
+ }
+ return false;
+ };
+ // Allow CHECK: comments to contain range= commands.
+ if (!RangeRegex.match(Comment, &Matches) || Comment.contains("CHECK")) {
+ if (DetectMistypedCommand())
+ return None;
+ continue;
+ }
+ unsigned Offset = Tok.getEndLoc().getRawEncoding();
+ unsigned ColumnOffset = 0;
+ if (!Matches[2].empty()) {
+ // Don't forget to drop the '+'!
+ if (Matches[2].drop_front().getAsInteger(10, ColumnOffset))
+ assert(false && "regex should have produced a number");
+ }
+ Offset = addColumnOffset(Source, Offset, ColumnOffset);
+ unsigned EndOffset;
+
+ if (!Matches[3].empty()) {
+ static Regex EndLocRegex(
+ "->[[:blank:]]*(\\+[[:digit:]]+):([[:digit:]]+)");
+ SmallVector<StringRef, 4> EndLocMatches;
+ if (!EndLocRegex.match(Matches[3], &EndLocMatches)) {
+ if (DetectMistypedCommand())
+ return None;
+ continue;
+ }
+ unsigned EndLineOffset = 0, EndColumn = 0;
+ if (EndLocMatches[1].drop_front().getAsInteger(10, EndLineOffset) ||
+ EndLocMatches[2].getAsInteger(10, EndColumn))
+ assert(false && "regex should have produced a number");
+ EndOffset = addEndLineOffsetAndEndColumn(Source, Offset, EndLineOffset,
+ EndColumn);
+ } else {
+ EndOffset = Offset;
+ }
+ TestSelectionRange Range = {Offset, EndOffset};
+ auto It = GroupedRanges.insert(std::make_pair(
+ Matches[1].str(), SmallVector<TestSelectionRange, 8>{Range}));
+ if (!It.second)
+ It.first->second.push_back(Range);
+ }
+ if (GroupedRanges.empty()) {
+ llvm::errs() << "error: -selection=test:" << Filename
+ << ": no 'range' commands";
+ return None;
+ }
+
+ TestSelectionRangesInFile TestRanges = {Filename.str(), {}};
+ for (auto &Group : GroupedRanges)
+ TestRanges.GroupedRanges.push_back({Group.first, std::move(Group.second)});
+ return std::move(TestRanges);
+}
+
+} // end namespace refactor
+} // end namespace clang
diff --git a/tools/clang-refactor/TestSupport.h b/tools/clang-refactor/TestSupport.h
new file mode 100644
index 0000000000..101f35bd94
--- /dev/null
+++ b/tools/clang-refactor/TestSupport.h
@@ -0,0 +1,107 @@
+//===--- TestSupport.h - Clang-based refactoring tool -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares datatypes and routines that are used by test-specific code
+/// in clang-refactor.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_CLANG_REFACTOR_TEST_SUPPORT_H
+#define LLVM_CLANG_TOOLS_CLANG_REFACTOR_TEST_SUPPORT_H
+
+#include "ToolRefactoringResultConsumer.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
+#include <map>
+#include <string>
+
+namespace clang {
+
+class SourceManager;
+
+namespace refactor {
+
+/// A source selection range that's specified in a test file using an inline
+/// command in the comment. These commands can take the following forms:
+///
+/// - /*range=*/ will create an empty selection range in the default group
+/// right after the comment.
+/// - /*range a=*/ will create an empty selection range in the 'a' group right
+/// after the comment.
+/// - /*range = +1*/ will create an empty selection range at a location that's
+/// right after the comment with one offset to the column.
+/// - /*range= -> +2:3*/ will create a selection range that starts at the
+/// location right after the comment, and ends at column 3 of the 2nd line
+/// after the line of the starting location.
+///
+/// Clang-refactor will expected all ranges in one test group to produce
+/// identical results.
+struct TestSelectionRange {
+ unsigned Begin, End;
+};
+
+/// A set of test selection ranges specified in one file.
+struct TestSelectionRangesInFile {
+ std::string Filename;
+ struct RangeGroup {
+ std::string Name;
+ SmallVector<TestSelectionRange, 8> Ranges;
+ };
+ std::vector<RangeGroup> GroupedRanges;
+
+ TestSelectionRangesInFile(TestSelectionRangesInFile &&) = default;
+ TestSelectionRangesInFile &operator=(TestSelectionRangesInFile &&) = default;
+
+ bool foreachRange(const SourceManager &SM,
+ llvm::function_ref<void(SourceRange)> Callback) const;
+
+ std::unique_ptr<ClangRefactorToolConsumerInterface> createConsumer() const;
+
+ void dump(llvm::raw_ostream &OS) const;
+};
+
+/// Extracts the grouped selection ranges from the file that's specified in
+/// the -selection=test:<filename> option.
+///
+/// The grouped ranges are specified in comments using the following syntax:
+/// "range" [ group-name ] "=" [ "+" starting-column-offset ] [ "->"
+/// "+" ending-line-offset ":"
+/// ending-column-position ]
+///
+/// The selection range is then computed from this command by taking the ending
+/// location of the comment, and adding 'starting-column-offset' to the column
+/// for that location. That location in turns becomes the whole selection range,
+/// unless 'ending-line-offset' and 'ending-column-position' are specified. If
+/// they are specified, then the ending location of the selection range is
+/// the starting location's line + 'ending-line-offset' and the
+/// 'ending-column-position' column.
+///
+/// All selection ranges in one group are expected to produce the same
+/// refactoring result.
+///
+/// When testing, zero is returned from clang-refactor even when a group
+/// produces an initiation error, which is different from normal invocation
+/// that returns a non-zero value. This is done on purpose, to ensure that group
+/// consistency checks can return non-zero, but still print the output of
+/// the group. So even if a test matches the output of group, it will still fail
+/// because clang-refactor should return zero on exit when the group results are
+/// consistent.
+///
+/// \returns None on failure (errors are emitted to stderr), or a set of
+/// grouped source ranges in the given file otherwise.
+Optional<TestSelectionRangesInFile> findTestSelectionRanges(StringRef Filename);
+
+} // end namespace refactor
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_CLANG_REFACTOR_TEST_SUPPORT_H
diff --git a/tools/clang-refactor/ToolRefactoringResultConsumer.h b/tools/clang-refactor/ToolRefactoringResultConsumer.h
new file mode 100644
index 0000000000..64a994d88b
--- /dev/null
+++ b/tools/clang-refactor/ToolRefactoringResultConsumer.h
@@ -0,0 +1,48 @@
+//===--- ToolRefactoringResultConsumer.h - ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_CLANG_REFACTOR_TOOL_REFACTORING_RESULT_CONSUMER_H
+#define LLVM_CLANG_TOOLS_CLANG_REFACTOR_TOOL_REFACTORING_RESULT_CONSUMER_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/Tooling/Refactoring/RefactoringResultConsumer.h"
+
+namespace clang {
+namespace refactor {
+
+/// An interface that subclasses the \c RefactoringResultConsumer interface
+/// that stores the reference to the TU-specific diagnostics engine.
+class ClangRefactorToolConsumerInterface
+ : public tooling::RefactoringResultConsumer {
+public:
+ /// Called when a TU is entered.
+ void beginTU(ASTContext &Context) {
+ assert(!Diags && "Diags has been set");
+ Diags = &Context.getDiagnostics();
+ }
+
+ /// Called when the tool is done with a TU.
+ void endTU() {
+ assert(Diags && "Diags unset");
+ Diags = nullptr;
+ }
+
+ DiagnosticsEngine &getDiags() const {
+ assert(Diags && "no diags");
+ return *Diags;
+ }
+
+private:
+ DiagnosticsEngine *Diags = nullptr;
+};
+
+} // end namespace refactor
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_CLANG_REFACTOR_TOOL_REFACTORING_RESULT_CONSUMER_H
diff --git a/tools/clang-rename/CMakeLists.txt b/tools/clang-rename/CMakeLists.txt
new file mode 100644
index 0000000000..e74f05d821
--- /dev/null
+++ b/tools/clang-rename/CMakeLists.txt
@@ -0,0 +1,22 @@
+set(LLVM_LINK_COMPONENTS
+ Option
+ Support
+ )
+
+add_clang_tool(clang-rename ClangRename.cpp)
+
+target_link_libraries(clang-rename
+ clangBasic
+ clangFrontend
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ clangToolingRefactor
+ )
+
+install(PROGRAMS clang-rename.py
+ DESTINATION share/clang
+ COMPONENT clang-rename)
+install(PROGRAMS clang-rename.el
+ DESTINATION share/clang
+ COMPONENT clang-rename)
diff --git a/tools/clang-rename/ClangRename.cpp b/tools/clang-rename/ClangRename.cpp
new file mode 100644
index 0000000000..fca12ca60c
--- /dev/null
+++ b/tools/clang-rename/ClangRename.cpp
@@ -0,0 +1,233 @@
+//===--- tools/extra/clang-rename/ClangRename.cpp - Clang rename tool -----===//
+//
+// 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 a clang-rename tool that automatically finds and
+/// renames symbols in C++ code.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace clang;
+
+/// \brief An oldname -> newname rename.
+struct RenameAllInfo {
+ unsigned Offset = 0;
+ std::string QualifiedName;
+ std::string NewName;
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(RenameAllInfo)
+
+namespace llvm {
+namespace yaml {
+
+/// \brief Specialized MappingTraits to describe how a RenameAllInfo is
+/// (de)serialized.
+template <> struct MappingTraits<RenameAllInfo> {
+ static void mapping(IO &IO, RenameAllInfo &Info) {
+ IO.mapOptional("Offset", Info.Offset);
+ IO.mapOptional("QualifiedName", Info.QualifiedName);
+ IO.mapRequired("NewName", Info.NewName);
+ }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+static cl::OptionCategory ClangRenameOptions("clang-rename common options");
+
+static cl::list<unsigned> SymbolOffsets(
+ "offset",
+ cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
+ cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited <file>s."),
+ cl::cat(ClangRenameOptions));
+static cl::list<std::string>
+ QualifiedNames("qualified-name",
+ cl::desc("The fully qualified name of the symbol."),
+ cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+
+static cl::list<std::string>
+ NewNames("new-name", cl::desc("The new name to change the symbol to."),
+ cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+static cl::opt<bool> PrintName(
+ "pn",
+ cl::desc("Print the found symbol's name prior to renaming to stderr."),
+ cl::cat(ClangRenameOptions));
+static cl::opt<bool> PrintLocations(
+ "pl", cl::desc("Print the locations affected by renaming to stderr."),
+ cl::cat(ClangRenameOptions));
+static cl::opt<std::string>
+ ExportFixes("export-fixes",
+ cl::desc("YAML file to store suggested fixes in."),
+ cl::value_desc("filename"), cl::cat(ClangRenameOptions));
+static cl::opt<std::string>
+ Input("input", cl::desc("YAML file to load oldname-newname pairs from."),
+ cl::Optional, cl::cat(ClangRenameOptions));
+static cl::opt<bool> Force("force",
+ cl::desc("Ignore nonexistent qualified names."),
+ cl::cat(ClangRenameOptions));
+
+int main(int argc, const char **argv) {
+ tooling::CommonOptionsParser OP(argc, argv, ClangRenameOptions);
+
+ if (!Input.empty()) {
+ // Populate QualifiedNames and NewNames from a YAML file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
+ llvm::MemoryBuffer::getFile(Input);
+ if (!Buffer) {
+ errs() << "clang-rename: failed to read " << Input << ": "
+ << Buffer.getError().message() << "\n";
+ return 1;
+ }
+
+ std::vector<RenameAllInfo> Infos;
+ llvm::yaml::Input YAML(Buffer.get()->getBuffer());
+ YAML >> Infos;
+ for (const auto &Info : Infos) {
+ if (!Info.QualifiedName.empty())
+ QualifiedNames.push_back(Info.QualifiedName);
+ else
+ SymbolOffsets.push_back(Info.Offset);
+ NewNames.push_back(Info.NewName);
+ }
+ }
+
+ // Check the arguments for correctness.
+ if (NewNames.empty()) {
+ errs() << "clang-rename: -new-name must be specified.\n\n";
+ return 1;
+ }
+
+ if (SymbolOffsets.empty() == QualifiedNames.empty()) {
+ errs() << "clang-rename: -offset and -qualified-name can't be present at "
+ "the same time.\n";
+ return 1;
+ }
+
+ // Check if NewNames is a valid identifier in C++17.
+ LangOptions Options;
+ Options.CPlusPlus = true;
+ Options.CPlusPlus1z = true;
+ IdentifierTable Table(Options);
+ for (const auto &NewName : NewNames) {
+ auto NewNameTokKind = Table.get(NewName).getTokenID();
+ if (!tok::isAnyIdentifier(NewNameTokKind)) {
+ errs() << "ERROR: new name is not a valid identifier in C++17.\n\n";
+ return 1;
+ }
+ }
+
+ if (SymbolOffsets.size() + QualifiedNames.size() != NewNames.size()) {
+ errs() << "clang-rename: number of symbol offsets(" << SymbolOffsets.size()
+ << ") + number of qualified names (" << QualifiedNames.size()
+ << ") must be equal to number of new names(" << NewNames.size()
+ << ").\n\n";
+ cl::PrintHelpMessage();
+ return 1;
+ }
+
+ auto Files = OP.getSourcePathList();
+ tooling::RefactoringTool Tool(OP.getCompilations(), Files);
+ tooling::USRFindingAction FindingAction(SymbolOffsets, QualifiedNames, Force);
+ Tool.run(tooling::newFrontendActionFactory(&FindingAction).get());
+ const std::vector<std::vector<std::string>> &USRList =
+ FindingAction.getUSRList();
+ const std::vector<std::string> &PrevNames = FindingAction.getUSRSpellings();
+ if (PrintName) {
+ for (const auto &PrevName : PrevNames) {
+ outs() << "clang-rename found name: " << PrevName << '\n';
+ }
+ }
+
+ if (FindingAction.errorOccurred()) {
+ // Diagnostics are already issued at this point.
+ return 1;
+ }
+
+ // Perform the renaming.
+ tooling::RenamingAction RenameAction(NewNames, PrevNames, USRList,
+ Tool.getReplacements(), PrintLocations);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory =
+ tooling::newFrontendActionFactory(&RenameAction);
+ int ExitCode;
+
+ if (Inplace) {
+ ExitCode = Tool.runAndSave(Factory.get());
+ } else {
+ ExitCode = Tool.run(Factory.get());
+
+ if (!ExportFixes.empty()) {
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
+ if (EC) {
+ llvm::errs() << "Error opening output file: " << EC.message() << '\n';
+ return 1;
+ }
+
+ // Export replacements.
+ tooling::TranslationUnitReplacements TUR;
+ const auto &FileToReplacements = Tool.getReplacements();
+ for (const auto &Entry : FileToReplacements)
+ TUR.Replacements.insert(TUR.Replacements.end(), Entry.second.begin(),
+ Entry.second.end());
+
+ yaml::Output YAML(OS);
+ YAML << TUR;
+ OS.close();
+ return 0;
+ }
+
+ // Write every file to stdout. Right now we just barf the files without any
+ // indication of which files start where, other than that we print the files
+ // in the same order we see them.
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &DiagnosticPrinter, false);
+ auto &FileMgr = Tool.getFiles();
+ SourceManager Sources(Diagnostics, FileMgr);
+ Rewriter Rewrite(Sources, DefaultLangOptions);
+
+ Tool.applyAllReplacements(Rewrite);
+ for (const auto &File : Files) {
+ const auto *Entry = FileMgr.getFile(File);
+ const auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
+ Rewrite.getEditBuffer(ID).write(outs());
+ }
+ }
+
+ return ExitCode;
+}
diff --git a/tools/clang-rename/clang-rename.el b/tools/clang-rename/clang-rename.el
new file mode 100644
index 0000000000..b6c3ed4c68
--- /dev/null
+++ b/tools/clang-rename/clang-rename.el
@@ -0,0 +1,79 @@
+;;; clang-rename.el --- Renames every occurrence of a symbol found at <offset>. -*- lexical-binding: t; -*-
+
+;; Keywords: tools, c
+
+;;; Commentary:
+
+;; To install clang-rename.el make sure the directory of this file is in your
+;; `load-path' and add
+;;
+;; (require 'clang-rename)
+;;
+;; to your .emacs configuration.
+
+;;; Code:
+
+(defgroup clang-rename nil
+ "Integration with clang-rename"
+ :group 'c)
+
+(defcustom clang-rename-binary "clang-rename"
+ "Path to clang-rename executable."
+ :type '(file :must-match t)
+ :group 'clang-rename)
+
+;;;###autoload
+(defun clang-rename (new-name)
+ "Rename all instances of the symbol at point to NEW-NAME using clang-rename."
+ (interactive "sEnter a new name: ")
+ (save-some-buffers :all)
+ ;; clang-rename should not be combined with other operations when undoing.
+ (undo-boundary)
+ (let ((output-buffer (get-buffer-create "*clang-rename*")))
+ (with-current-buffer output-buffer (erase-buffer))
+ (let ((exit-code (call-process
+ clang-rename-binary nil output-buffer nil
+ (format "-offset=%d"
+ ;; clang-rename wants file (byte) offsets, not
+ ;; buffer (character) positions.
+ (clang-rename--bufferpos-to-filepos
+ ;; Emacs treats one character after a symbol as
+ ;; part of the symbol, but clang-rename doesn’t.
+ ;; Use the beginning of the current symbol, if
+ ;; available, to resolve the inconsistency.
+ (or (car (bounds-of-thing-at-point 'symbol))
+ (point))
+ 'exact))
+ (format "-new-name=%s" new-name)
+ "-i" (buffer-file-name))))
+ (if (and (integerp exit-code) (zerop exit-code))
+ ;; Success; revert current buffer so it gets the modifications.
+ (progn
+ (kill-buffer output-buffer)
+ (revert-buffer :ignore-auto :noconfirm :preserve-modes))
+ ;; Failure; append exit code to output buffer and display it.
+ (let ((message (clang-rename--format-message
+ "clang-rename failed with %s %s"
+ (if (integerp exit-code) "exit status" "signal")
+ exit-code)))
+ (with-current-buffer output-buffer
+ (insert ?\n message ?\n))
+ (message "%s" message)
+ (display-buffer output-buffer))))))
+
+(defalias 'clang-rename--bufferpos-to-filepos
+ (if (fboundp 'bufferpos-to-filepos)
+ 'bufferpos-to-filepos
+ ;; Emacs 24 doesn’t have ‘bufferpos-to-filepos’, simulate it using
+ ;; ‘position-bytes’.
+ (lambda (position &optional _quality _coding-system)
+ (1- (position-bytes position)))))
+
+;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-rename--format-message
+ (if (fboundp 'format-message) 'format-message 'format))
+
+(provide 'clang-rename)
+
+;;; clang-rename.el ends here
diff --git a/tools/clang-rename/clang-rename.py b/tools/clang-rename/clang-rename.py
new file mode 100644
index 0000000000..3cc6644ff8
--- /dev/null
+++ b/tools/clang-rename/clang-rename.py
@@ -0,0 +1,61 @@
+'''
+Minimal clang-rename integration with Vim.
+
+Before installing make sure one of the following is satisfied:
+
+* clang-rename is in your PATH
+* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable
+* `binary` in clang-rename.py points to valid to clang-rename executable
+
+To install, simply put this into your ~/.vimrc
+
+ noremap <leader>cr :pyf <path-to>/clang-rename.py<cr>
+
+IMPORTANT NOTE: Before running the tool, make sure you saved the file.
+
+All you have to do now is to place a cursor on a variable/function/class which
+you would like to rename and press '<leader>cr'. You will be prompted for a new
+name if the cursor points to a valid symbol.
+'''
+
+import vim
+import subprocess
+import sys
+
+def main():
+ binary = 'clang-rename'
+ if vim.eval('exists("g:clang_rename_path")') == "1":
+ binary = vim.eval('g:clang_rename_path')
+
+ # Get arguments for clang-rename binary.
+ offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2
+ if offset < 0:
+ print >> sys.stderr, '''Couldn\'t determine cursor position.
+ Is your file empty?'''
+ return
+ filename = vim.current.buffer.name
+
+ new_name_request_message = 'type new name:'
+ new_name = vim.eval("input('{}\n')".format(new_name_request_message))
+
+ # Call clang-rename.
+ command = [binary,
+ filename,
+ '-i',
+ '-offset', str(offset),
+ '-new-name', str(new_name)]
+ # FIXME: make it possible to run the tool on unsaved file.
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+
+ if stderr:
+ print stderr
+
+ # Reload all buffers in Vim.
+ vim.command("checktime")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/diagtool/CMakeLists.txt b/tools/diagtool/CMakeLists.txt
index e88c2ab6e8..3f7d80385a 100644
--- a/tools/diagtool/CMakeLists.txt
+++ b/tools/diagtool/CMakeLists.txt
@@ -6,6 +6,7 @@ add_clang_executable(diagtool
diagtool_main.cpp
DiagTool.cpp
DiagnosticNames.cpp
+ FindDiagnosticID.cpp
ListWarnings.cpp
ShowEnabledWarnings.cpp
TreeView.cpp
diff --git a/tools/diagtool/DiagnosticNames.cpp b/tools/diagtool/DiagnosticNames.cpp
index a08da89577..b0ca7f9806 100644
--- a/tools/diagtool/DiagnosticNames.cpp
+++ b/tools/diagtool/DiagnosticNames.cpp
@@ -32,6 +32,7 @@ static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) \
{ #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticCommonKinds.inc"
+#include "clang/Basic/DiagnosticCrossTUKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#include "clang/Basic/DiagnosticSerializationKinds.inc"
@@ -41,6 +42,7 @@ static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
#include "clang/Basic/DiagnosticCommentKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
+#include "clang/Basic/DiagnosticRefactoringKinds.inc"
#undef DIAG
};
@@ -84,6 +86,11 @@ GroupRecord::subgroup_iterator GroupRecord::subgroup_end() const {
return nullptr;
}
+llvm::iterator_range<diagtool::GroupRecord::subgroup_iterator>
+GroupRecord::subgroups() const {
+ return llvm::make_range(subgroup_begin(), subgroup_end());
+}
+
GroupRecord::diagnostics_iterator GroupRecord::diagnostics_begin() const {
return DiagArrays + Members;
}
@@ -92,6 +99,11 @@ GroupRecord::diagnostics_iterator GroupRecord::diagnostics_end() const {
return nullptr;
}
+llvm::iterator_range<diagtool::GroupRecord::diagnostics_iterator>
+GroupRecord::diagnostics() const {
+ return llvm::make_range(diagnostics_begin(), diagnostics_end());
+}
+
llvm::ArrayRef<GroupRecord> diagtool::getDiagnosticGroups() {
return llvm::makeArrayRef(OptionTable);
}
diff --git a/tools/diagtool/DiagnosticNames.h b/tools/diagtool/DiagnosticNames.h
index ac1a098579..598ae6a0ba 100644
--- a/tools/diagtool/DiagnosticNames.h
+++ b/tools/diagtool/DiagnosticNames.h
@@ -20,7 +20,7 @@ namespace diagtool {
const char *NameStr;
short DiagID;
uint8_t NameLen;
-
+
llvm::StringRef getName() const {
return llvm::StringRef(NameStr, NameLen);
}
@@ -80,7 +80,7 @@ namespace diagtool {
bool operator==(group_iterator &Other) const {
return CurrentID == Other.CurrentID;
}
-
+
bool operator!=(group_iterator &Other) const {
return CurrentID != Other.CurrentID;
}
@@ -89,10 +89,12 @@ namespace diagtool {
typedef group_iterator<GroupRecord> subgroup_iterator;
subgroup_iterator subgroup_begin() const;
subgroup_iterator subgroup_end() const;
+ llvm::iterator_range<subgroup_iterator> subgroups() const;
typedef group_iterator<DiagnosticRecord> diagnostics_iterator;
diagnostics_iterator diagnostics_begin() const;
diagnostics_iterator diagnostics_end() const;
+ llvm::iterator_range<diagnostics_iterator> diagnostics() const;
bool operator<(llvm::StringRef Other) const {
return getName() < Other;
diff --git a/tools/diagtool/FindDiagnosticID.cpp b/tools/diagtool/FindDiagnosticID.cpp
new file mode 100644
index 0000000000..db6fe5e472
--- /dev/null
+++ b/tools/diagtool/FindDiagnosticID.cpp
@@ -0,0 +1,74 @@
+//===- FindDiagnosticID.cpp - diagtool tool for finding diagnostic id -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DiagTool.h"
+#include "DiagnosticNames.h"
+#include "clang/Basic/AllDiagnostics.h"
+#include "llvm/Support/CommandLine.h"
+
+DEF_DIAGTOOL("find-diagnostic-id", "Print the id of the given diagnostic",
+ FindDiagnosticID)
+
+using namespace clang;
+using namespace diagtool;
+
+static StringRef getNameFromID(StringRef Name) {
+ int DiagID;
+ if(!Name.getAsInteger(0, DiagID)) {
+ const DiagnosticRecord &Diag = getDiagnosticForID(DiagID);
+ return Diag.getName();
+ }
+ return StringRef();
+}
+
+static Optional<DiagnosticRecord>
+findDiagnostic(ArrayRef<DiagnosticRecord> Diagnostics, StringRef Name) {
+ for (const auto &Diag : Diagnostics) {
+ StringRef DiagName = Diag.getName();
+ if (DiagName == Name)
+ return Diag;
+ }
+ return None;
+}
+
+int FindDiagnosticID::run(unsigned int argc, char **argv,
+ llvm::raw_ostream &OS) {
+ static llvm::cl::OptionCategory FindDiagnosticIDOptions(
+ "diagtool find-diagnostic-id options");
+
+ static llvm::cl::opt<std::string> DiagnosticName(
+ llvm::cl::Positional, llvm::cl::desc("<diagnostic-name>"),
+ llvm::cl::Required, llvm::cl::cat(FindDiagnosticIDOptions));
+
+ std::vector<const char *> Args;
+ Args.push_back("diagtool find-diagnostic-id");
+ for (const char *A : llvm::makeArrayRef(argv, argc))
+ Args.push_back(A);
+
+ llvm::cl::HideUnrelatedOptions(FindDiagnosticIDOptions);
+ llvm::cl::ParseCommandLineOptions((int)Args.size(), Args.data(),
+ "Diagnostic ID mapping utility");
+
+ ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
+ Optional<DiagnosticRecord> Diag =
+ findDiagnostic(AllDiagnostics, DiagnosticName);
+ if (!Diag) {
+ // Name to id failed, so try id to name.
+ auto Name = getNameFromID(DiagnosticName);
+ if (!Name.empty()) {
+ OS << Name << '\n';
+ return 0;
+ }
+
+ llvm::errs() << "error: invalid diagnostic '" << DiagnosticName << "'\n";
+ return 1;
+ }
+ OS << Diag->DiagID << "\n";
+ return 0;
+}
diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp
index 3e6e88306e..8bf9df9401 100644
--- a/tools/diagtool/ListWarnings.cpp
+++ b/tools/diagtool/ListWarnings.cpp
@@ -23,7 +23,7 @@
DEF_DIAGTOOL("list-warnings",
"List warnings and their corresponding flags",
ListWarnings)
-
+
using namespace clang;
using namespace diagtool;
@@ -31,20 +31,19 @@ namespace {
struct Entry {
llvm::StringRef DiagName;
llvm::StringRef Flag;
-
+
Entry(llvm::StringRef diagN, llvm::StringRef flag)
: DiagName(diagN), Flag(flag) {}
-
+
bool operator<(const Entry &x) const { return DiagName < x.DiagName; }
};
}
static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
- for (std::vector<Entry>::iterator it = entries.begin(), ei = entries.end();
- it != ei; ++it) {
- out << " " << it->DiagName;
- if (!it->Flag.empty())
- out << " [-W" << it->Flag << "]";
+ for (const Entry &E : entries) {
+ out << " " << E.DiagName;
+ if (!E.Flag.empty())
+ out << " [-W" << E.Flag << "]";
out << '\n';
}
}
@@ -52,23 +51,18 @@ static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
std::vector<Entry> Flagged, Unflagged;
llvm::StringMap<std::vector<unsigned> > flagHistogram;
-
- ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
-
- for (ArrayRef<DiagnosticRecord>::iterator di = AllDiagnostics.begin(),
- de = AllDiagnostics.end();
- di != de; ++di) {
- unsigned diagID = di->DiagID;
-
+
+ for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
+ const unsigned diagID = DR.DiagID;
+
if (DiagnosticIDs::isBuiltinNote(diagID))
continue;
-
+
if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
continue;
-
- Entry entry(di->getName(),
- DiagnosticIDs::getWarningOptionForDiag(diagID));
-
+
+ Entry entry(DR.getName(), DiagnosticIDs::getWarningOptionForDiag(diagID));
+
if (entry.Flag.empty())
Unflagged.push_back(entry);
else {
@@ -76,24 +70,24 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
flagHistogram[entry.Flag].push_back(diagID);
}
}
-
+
out << "Warnings with flags (" << Flagged.size() << "):\n";
printEntries(Flagged, out);
-
+
out << "Warnings without flags (" << Unflagged.size() << "):\n";
printEntries(Unflagged, out);
out << "\nSTATISTICS:\n\n";
- double percentFlagged = ((double) Flagged.size())
- / (Flagged.size() + Unflagged.size()) * 100.0;
-
- out << " Percentage of warnings with flags: "
- << llvm::format("%.4g",percentFlagged) << "%\n";
-
+ double percentFlagged =
+ ((double)Flagged.size()) / (Flagged.size() + Unflagged.size()) * 100.0;
+
+ out << " Percentage of warnings with flags: "
+ << llvm::format("%.4g", percentFlagged) << "%\n";
+
out << " Number of unique flags: "
<< flagHistogram.size() << '\n';
-
+
double avgDiagsPerFlag = (double) Flagged.size() / flagHistogram.size();
out << " Average number of diagnostics per flag: "
<< llvm::format("%.4g", avgDiagsPerFlag) << '\n';
@@ -102,7 +96,7 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
<< flagHistogram["pedantic"].size() << '\n';
out << '\n';
-
+
return 0;
}
diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp
index e6ea786a9a..513abc15b2 100644
--- a/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/tools/diagtool/ShowEnabledWarnings.cpp
@@ -112,17 +112,14 @@ int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
// which ones are turned on.
// FIXME: It would be very nice to print which flags are turning on which
// diagnostics, but this can be done with a diff.
- ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
std::vector<PrettyDiag> Active;
- for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(),
- E = AllDiagnostics.end();
- I != E; ++I) {
- unsigned DiagID = I->DiagID;
-
+ for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
+ unsigned DiagID = DR.DiagID;
+
if (DiagnosticIDs::isBuiltinNote(DiagID))
continue;
-
+
if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
continue;
@@ -132,17 +129,16 @@ int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
continue;
StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
- Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
+ Active.push_back(PrettyDiag(DR.getName(), WarningOpt, DiagLevel));
}
// Print them all out.
- for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
- E = Active.end(); I != E; ++I) {
+ for (const PrettyDiag &PD : Active) {
if (ShouldShowLevels)
- Out << getCharForLevel(I->Level) << " ";
- Out << I->Name;
- if (!I->Flag.empty())
- Out << " [-W" << I->Flag << "]";
+ Out << getCharForLevel(PD.Level) << " ";
+ Out << PD.Name;
+ if (!PD.Flag.empty())
+ Out << " [-W" << PD.Flag << "]";
Out << '\n';
}
diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp
index 07af944ffc..b4846b5574 100644
--- a/tools/diagtool/TreeView.cpp
+++ b/tools/diagtool/TreeView.cpp
@@ -32,10 +32,10 @@ class TreePrinter {
public:
llvm::raw_ostream &out;
const bool ShowColors;
- bool FlagsOnly;
+ bool Internal;
TreePrinter(llvm::raw_ostream &out)
- : out(out), ShowColors(hasColors(out)), FlagsOnly(false) {}
+ : out(out), ShowColors(hasColors(out)), Internal(false) {}
void setColor(llvm::raw_ostream::Colors Color) {
if (ShowColors)
@@ -54,28 +54,42 @@ public:
return Diags.isIgnored(DiagID, SourceLocation());
}
+ static bool enabledByDefault(const GroupRecord &Group) {
+ for (const DiagnosticRecord &DR : Group.diagnostics()) {
+ if (isIgnored(DR.DiagID))
+ return false;
+ }
+
+ for (const GroupRecord &GR : Group.subgroups()) {
+ if (!enabledByDefault(GR))
+ return false;
+ }
+
+ return true;
+ }
+
void printGroup(const GroupRecord &Group, unsigned Indent = 0) {
out.indent(Indent * 2);
- setColor(llvm::raw_ostream::YELLOW);
+ if (enabledByDefault(Group))
+ setColor(llvm::raw_ostream::GREEN);
+ else
+ setColor(llvm::raw_ostream::YELLOW);
+
out << "-W" << Group.getName() << "\n";
resetColor();
++Indent;
- for (GroupRecord::subgroup_iterator I = Group.subgroup_begin(),
- E = Group.subgroup_end();
- I != E; ++I) {
- printGroup(*I, Indent);
+ for (const GroupRecord &GR : Group.subgroups()) {
+ printGroup(GR, Indent);
}
- if (!FlagsOnly) {
- for (GroupRecord::diagnostics_iterator I = Group.diagnostics_begin(),
- E = Group.diagnostics_end();
- I != E; ++I) {
- if (ShowColors && !isIgnored(I->DiagID))
+ if (Internal) {
+ for (const DiagnosticRecord &DR : Group.diagnostics()) {
+ if (ShowColors && !isIgnored(DR.DiagID))
setColor(llvm::raw_ostream::GREEN);
out.indent(Indent * 2);
- out << I->getName();
+ out << DR.getName();
resetColor();
out << "\n";
}
@@ -107,12 +121,9 @@ public:
ArrayRef<GroupRecord> AllGroups = getDiagnosticGroups();
llvm::DenseSet<unsigned> NonRootGroupIDs;
- for (ArrayRef<GroupRecord>::iterator I = AllGroups.begin(),
- E = AllGroups.end();
- I != E; ++I) {
- for (GroupRecord::subgroup_iterator SI = I->subgroup_begin(),
- SE = I->subgroup_end();
- SI != SE; ++SI) {
+ for (const GroupRecord &GR : AllGroups) {
+ for (auto SI = GR.subgroup_begin(), SE = GR.subgroup_end(); SI != SE;
+ ++SI) {
NonRootGroupIDs.insert((unsigned)SI.getID());
}
}
@@ -139,16 +150,16 @@ public:
};
static void printUsage() {
- llvm::errs() << "Usage: diagtool tree [--flags-only] [<diagnostic-group>]\n";
+ llvm::errs() << "Usage: diagtool tree [--internal] [<diagnostic-group>]\n";
}
int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
// First check our one flag (--flags-only).
- bool FlagsOnly = false;
+ bool Internal = false;
if (argc > 0) {
StringRef FirstArg(*argv);
- if (FirstArg.equals("--flags-only")) {
- FlagsOnly = true;
+ if (FirstArg.equals("--internal")) {
+ Internal = true;
--argc;
++argv;
}
@@ -175,7 +186,7 @@ int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
}
TreePrinter TP(out);
- TP.FlagsOnly = FlagsOnly;
+ TP.Internal = Internal;
TP.showKey();
return ShowAll ? TP.showAll() : TP.showGroup(RootGroup);
}
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index f6e26fa11f..901b6d62e4 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 2fa8edb81a..9b90562af9 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -88,12 +88,13 @@ struct AssemblerInvocation {
unsigned NoInitialTextSection : 1;
unsigned SaveTemporaryLabels : 1;
unsigned GenDwarfForAssembly : 1;
- unsigned CompressDebugSections : 1;
unsigned RelaxELFRelocations : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
std::string DwarfDebugProducer;
std::string DebugCompilationDir;
+ llvm::DebugCompressionType CompressDebugSections =
+ llvm::DebugCompressionType::None;
std::string MainFileName;
/// @}
@@ -201,7 +202,22 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
// Any DebugInfoKind implies GenDwarfForAssembly.
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
- Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections);
+
+ if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
+ OPT_compress_debug_sections_EQ)) {
+ if (A->getOption().getID() == OPT_compress_debug_sections) {
+ // TODO: be more clever about the compression type auto-detection
+ Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
+ } else {
+ Opts.CompressDebugSections =
+ llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
+ .Case("none", llvm::DebugCompressionType::None)
+ .Case("zlib", llvm::DebugCompressionType::Z)
+ .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+ .Default(llvm::DebugCompressionType::None);
+ }
+ }
+
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
@@ -314,8 +330,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// Ensure MCAsmInfo initialization occurs before any use, otherwise sections
// may be created with a combination of default and explicit settings.
- if (Opts.CompressDebugSections)
- MAI->setCompressDebugSections(DebugCompressionType::DCT_ZlibGnu);
+ MAI->setCompressDebugSections(Opts.CompressDebugSections);
MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
@@ -341,7 +356,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
PIC = false;
}
- MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, CodeModel::Default, Ctx);
+ MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
if (Opts.GenDwarfForAssembly)
@@ -404,8 +419,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
Opts.CPU, Options);
Triple T(Opts.Triple);
Str.reset(TheTarget->createMCObjectStreamer(
- T, Ctx, *MAB, *Out, CE, *STI, Opts.RelaxAll,
- Opts.IncrementalLinkerCompatible,
+ T, Ctx, std::unique_ptr<MCAsmBackend>(MAB), *Out, std::unique_ptr<MCCodeEmitter>(CE), *STI,
+ Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ true));
Str.get()->InitSections(Opts.NoExecStack);
}
@@ -489,7 +504,8 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
if (Asm.ShowHelp) {
std::unique_ptr<OptTable> Opts(driver::createDriverOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler",
- /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0);
+ /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
+ /*ShowAllAliases=*/false);
return 0;
}
@@ -506,12 +522,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// FIXME: Remove this, one day.
if (!Asm.LLVMArgs.empty()) {
unsigned NumArgs = Asm.LLVMArgs.size();
- const char **Args = new const char*[NumArgs + 2];
+ auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Asm.LLVMArgs[i].c_str();
Args[NumArgs + 1] = nullptr;
- llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
// Execute the invocation, unless there were parsing errors.
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 6161302862..fa757da953 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -53,8 +53,15 @@ using namespace clang::driver;
using namespace llvm::opt;
std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
- if (!CanonicalPrefixes)
- return Argv0;
+ if (!CanonicalPrefixes) {
+ SmallString<128> ExecutablePath(Argv0);
+ // Do a PATH lookup if Argv0 isn't a valid path.
+ if (!llvm::sys::fs::exists(ExecutablePath))
+ if (llvm::ErrorOr<std::string> P =
+ llvm::sys::findProgramByName(ExecutablePath))
+ ExecutablePath = *P;
+ return ExecutablePath.str();
+ }
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
@@ -199,23 +206,26 @@ extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
void *MainAddr);
-static void insertTargetAndModeArgs(StringRef Target, StringRef Mode,
+static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
SmallVectorImpl<const char *> &ArgVector,
std::set<std::string> &SavedStrings) {
- if (!Mode.empty()) {
+ // Put target and mode arguments at the start of argument list so that
+ // arguments specified in command line could override them. Avoid putting
+ // them at index 0, as an option like '-cc1' must remain the first.
+ auto InsertionPoint = ArgVector.begin();
+ if (InsertionPoint != ArgVector.end())
+ ++InsertionPoint;
+
+ if (NameParts.DriverMode) {
// Add the mode flag to the arguments.
- auto it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- ArgVector.insert(it, GetStableCStr(SavedStrings, Mode));
+ ArgVector.insert(InsertionPoint,
+ GetStableCStr(SavedStrings, NameParts.DriverMode));
}
- if (!Target.empty()) {
- auto it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- const char *arr[] = {"-target", GetStableCStr(SavedStrings, Target)};
- ArgVector.insert(it, std::begin(arr), std::end(arr));
+ if (NameParts.TargetIsValid) {
+ const char *arr[] = {"-target", GetStableCStr(SavedStrings,
+ NameParts.TargetPrefix)};
+ ArgVector.insert(InsertionPoint, std::begin(arr), std::end(arr));
}
}
@@ -323,9 +333,7 @@ int main(int argc_, const char **argv_) {
}
llvm::InitializeAllTargets();
- std::string ProgName = argv[0];
- std::pair<std::string, std::string> TargetAndMode =
- ToolChain::getTargetAndModeFromProgramName(ProgName);
+ auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
llvm::BumpPtrAllocator A;
llvm::StringSaver Saver(A);
@@ -338,7 +346,7 @@ int main(int argc_, const char **argv_) {
// Finally, our -cc1 tools don't care which tokenization mode we use because
// response files written by clang will tokenize the same way in either mode.
bool ClangCLMode = false;
- if (TargetAndMode.second == "--driver-mode=cl" ||
+ if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
std::find_if(argv.begin(), argv.end(), [](const char *F) {
return F && strcmp(F, "--driver-mode=cl") == 0;
}) != argv.end()) {
@@ -447,46 +455,48 @@ int main(int argc_, const char **argv_) {
Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
SetInstallDir(argv, TheDriver, CanonicalPrefixes);
+ TheDriver.setTargetAndMode(TargetAndMode);
- insertTargetAndModeArgs(TargetAndMode.first, TargetAndMode.second, argv,
- SavedStrings);
+ insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
SetBackdoorDriverOutputsFromEnvVars(TheDriver);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
- int Res = 0;
- SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
- if (C.get())
+ int Res = 1;
+ if (C && !C->containsError()) {
+ SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
- // Force a crash to test the diagnostics.
- if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) {
- Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH";
+ // Force a crash to test the diagnostics.
+ if (TheDriver.GenReproducer) {
+ Diags.Report(diag::err_drv_force_crash)
+ << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
- // Pretend that every command failed.
- FailingCommands.clear();
- for (const auto &J : C->getJobs())
- if (const Command *C = dyn_cast<Command>(&J))
- FailingCommands.push_back(std::make_pair(-1, C));
- }
+ // Pretend that every command failed.
+ FailingCommands.clear();
+ for (const auto &J : C->getJobs())
+ if (const Command *C = dyn_cast<Command>(&J))
+ FailingCommands.push_back(std::make_pair(-1, C));
+ }
- for (const auto &P : FailingCommands) {
- int CommandRes = P.first;
- const Command *FailingCommand = P.second;
- if (!Res)
- Res = CommandRes;
-
- // If result status is < 0, then the driver command signalled an error.
- // If result status is 70, then the driver command reported a fatal error.
- // On Windows, abort will return an exit code of 3. In these cases,
- // generate additional diagnostic information if possible.
- bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
+ for (const auto &P : FailingCommands) {
+ int CommandRes = P.first;
+ const Command *FailingCommand = P.second;
+ if (!Res)
+ Res = CommandRes;
+
+ // If result status is < 0, then the driver command signalled an error.
+ // If result status is 70, then the driver command reported a fatal error.
+ // On Windows, abort will return an exit code of 3. In these cases,
+ // generate additional diagnostic information if possible.
+ bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
#ifdef LLVM_ON_WIN32
- DiagnoseCrash |= CommandRes == 3;
+ DiagnoseCrash |= CommandRes == 3;
#endif
- if (DiagnoseCrash) {
- TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
- break;
+ if (DiagnoseCrash) {
+ TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
+ break;
+ }
}
}
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
index 44a60c4e3e..ed2ecdb29e 100644
--- a/tools/libclang/ARCMigrate.cpp
+++ b/tools/libclang/ARCMigrate.cpp
@@ -14,6 +14,7 @@
#include "clang-c/Index.h"
#include "CXString.h"
#include "clang/ARCMigrate/ARCMT.h"
+#include "clang/Config/config.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "llvm/Support/FileSystem.h"
@@ -33,7 +34,7 @@ struct Remap {
//===----------------------------------------------------------------------===//
CXRemapping clang_getRemappings(const char *migrate_dir_path) {
-#ifndef CLANG_ENABLE_ARCMT
+#if !CLANG_ENABLE_ARCMT
llvm::errs() << "error: feature not enabled in this build\n";
return nullptr;
#else
@@ -76,7 +77,7 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) {
CXRemapping clang_getRemappingsFromFileList(const char **filePaths,
unsigned numFiles) {
-#ifndef CLANG_ENABLE_ARCMT
+#if !CLANG_ENABLE_ARCMT
llvm::errs() << "error: feature not enabled in this build\n";
return nullptr;
#else
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 216322b9f9..fa3b970855 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -26,6 +26,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -906,7 +907,8 @@ bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (VisitTemplateParameters(D->getTemplateParameters()))
return true;
- return VisitFunctionDecl(D->getTemplatedDecl());
+ auto* FD = D->getTemplatedDecl();
+ return VisitAttributes(FD) || VisitFunctionDecl(FD);
}
bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) {
@@ -915,7 +917,8 @@ bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (VisitTemplateParameters(D->getTemplateParameters()))
return true;
- return VisitCXXRecordDecl(D->getTemplatedDecl());
+ auto* CD = D->getTemplatedDecl();
+ return VisitAttributes(CD) || VisitCXXRecordDecl(CD);
}
bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
@@ -1741,6 +1744,7 @@ DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType)
DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType)
DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType)
DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType)
+DEFAULT_TYPELOC_IMPL(DependentAddressSpace, Type)
DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type)
DEFAULT_TYPELOC_IMPL(Vector, Type)
DEFAULT_TYPELOC_IMPL(ExtVector, VectorType)
@@ -2263,6 +2267,42 @@ void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) {
Visitor->AddStmt(E);
}
}
+void OMPClauseEnqueue::VisitOMPTaskReductionClause(
+ const OMPTaskReductionClause *C) {
+ VisitOMPClauseList(C);
+ VisitOMPClauseWithPostUpdate(C);
+ for (auto *E : C->privates()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->lhs_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->rhs_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->reduction_ops()) {
+ Visitor->AddStmt(E);
+ }
+}
+void OMPClauseEnqueue::VisitOMPInReductionClause(
+ const OMPInReductionClause *C) {
+ VisitOMPClauseList(C);
+ VisitOMPClauseWithPostUpdate(C);
+ for (auto *E : C->privates()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->lhs_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->rhs_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->reduction_ops()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->taskgroup_descriptors())
+ Visitor->AddStmt(E);
+}
void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
VisitOMPClauseWithPostUpdate(C);
@@ -2720,6 +2760,8 @@ void EnqueueVisitor::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D) {
void EnqueueVisitor::VisitOMPTaskgroupDirective(
const OMPTaskgroupDirective *D) {
VisitOMPExecutableDirective(D);
+ if (const Expr *E = D->getReductionRef())
+ VisitStmt(E);
}
void EnqueueVisitor::VisitOMPFlushDirective(const OMPFlushDirective *D) {
@@ -3246,7 +3288,8 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
CompilerInstance::createDiagnostics(new DiagnosticOptions());
std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
- ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(), Diags,
+ ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(),
+ ASTUnit::LoadEverything, Diags,
FileSystemOpts, /*UseDebugInfo=*/false,
CXXIdx->getOnlyLocalDecls(), None,
/*CaptureDiagnostics=*/true,
@@ -3299,12 +3342,14 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
options & CXTranslationUnit_CreatePreambleOnFirstParse;
// FIXME: Add a flag for modules.
TranslationUnitKind TUKind
- = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
+ = (options & (CXTranslationUnit_Incomplete |
+ CXTranslationUnit_SingleFileParse))? TU_Prefix : TU_Complete;
bool CacheCodeCompletionResults
= options & CXTranslationUnit_CacheCompletionResults;
bool IncludeBriefCommentsInCodeCompletion
= options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
+ bool SingleFileParse = options & CXTranslationUnit_SingleFileParse;
bool ForSerialization = options & CXTranslationUnit_ForSerialization;
// Configure the diagnostics.
@@ -3312,7 +3357,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
if (options & CXTranslationUnit_KeepGoing)
- Diags->setFatalsAsError(true);
+ Diags->setSuppressAfterFatalError(false);
// Recover resources if we crash before exiting this function.
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
@@ -3371,7 +3416,10 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
Args->push_back("-Xclang");
Args->push_back("-detailed-preprocessing-record");
}
-
+
+ // Suppress any editor placeholder diagnostics.
+ Args->push_back("-fallow-editor-placeholders");
+
unsigned NumErrors = Diags->getClient()->getNumErrors();
std::unique_ptr<ASTUnit> ErrUnit;
// Unless the user specified that they want the preamble on the first parse
@@ -3386,7 +3434,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
/*CaptureDiagnostics=*/true, *RemappedFiles.get(),
/*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses,
TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion,
- /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies,
+ /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, SingleFileParse,
/*UserFilesAreVolatile=*/true, ForSerialization,
CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(),
&ErrUnit));
@@ -3459,6 +3507,12 @@ enum CXErrorCode clang_parseTranslationUnit2FullArgv(
CIdx, source_filename, command_line_args, num_command_line_args,
llvm::makeArrayRef(unsaved_files, num_unsaved_files), options, out_TU);
};
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ ParseTranslationUnitImpl();
+ return result;
+ }
+
llvm::CrashRecoveryContext CRC;
if (!RunSafely(CRC, ParseTranslationUnitImpl)) {
@@ -3914,6 +3968,20 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
}
}
+unsigned clang_suspendTranslationUnit(CXTranslationUnit CTUnit) {
+ if (CTUnit) {
+ ASTUnit *Unit = cxtu::getASTUnit(CTUnit);
+
+ if (Unit && Unit->isUnsafeToFree())
+ return false;
+
+ Unit->ResetForParse();
+ return true;
+ }
+
+ return false;
+}
+
unsigned clang_defaultReparseOptions(CXTranslationUnit TU) {
return CXReparse_None;
}
@@ -4015,6 +4083,50 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU);
}
+CXTargetInfo clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit) {
+ if (isNotUsableTU(CTUnit)) {
+ LOG_BAD_TU(CTUnit);
+ return nullptr;
+ }
+
+ CXTargetInfoImpl* impl = new CXTargetInfoImpl();
+ impl->TranslationUnit = CTUnit;
+ return impl;
+}
+
+CXString clang_TargetInfo_getTriple(CXTargetInfo TargetInfo) {
+ if (!TargetInfo)
+ return cxstring::createEmpty();
+
+ CXTranslationUnit CTUnit = TargetInfo->TranslationUnit;
+ assert(!isNotUsableTU(CTUnit) &&
+ "Unexpected unusable translation unit in TargetInfo");
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit);
+ std::string Triple =
+ CXXUnit->getASTContext().getTargetInfo().getTriple().normalize();
+ return cxstring::createDup(Triple);
+}
+
+int clang_TargetInfo_getPointerWidth(CXTargetInfo TargetInfo) {
+ if (!TargetInfo)
+ return -1;
+
+ CXTranslationUnit CTUnit = TargetInfo->TranslationUnit;
+ assert(!isNotUsableTU(CTUnit) &&
+ "Unexpected unusable translation unit in TargetInfo");
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit);
+ return CXXUnit->getASTContext().getTargetInfo().getMaxPointerWidth();
+}
+
+void clang_TargetInfo_dispose(CXTargetInfo TargetInfo) {
+ if (!TargetInfo)
+ return;
+
+ delete TargetInfo;
+}
+
//===----------------------------------------------------------------------===//
// CXFile Operations.
//===----------------------------------------------------------------------===//
@@ -4530,6 +4642,20 @@ CXStringSet *clang_Cursor_getCXXManglings(CXCursor C) {
return cxstring::createSet(Manglings);
}
+CXStringSet *clang_Cursor_getObjCManglings(CXCursor C) {
+ if (clang_isInvalid(C.kind) || !clang_isDeclaration(C.kind))
+ return nullptr;
+
+ const Decl *D = getCursorDecl(C);
+ if (!(isa<ObjCInterfaceDecl>(D) || isa<ObjCImplementationDecl>(D)))
+ return nullptr;
+
+ ASTContext &Ctx = D->getASTContext();
+ index::CodegenNameGenerator CGNameGen(Ctx);
+ std::vector<std::string> Manglings = CGNameGen.getAllManglings(D);
+ return cxstring::createSet(Manglings);
+}
+
CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
@@ -7021,8 +7147,10 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
switch (ND->getLinkageInternal()) {
case NoLinkage:
case VisibleNoLinkage: return CXLinkage_NoLinkage;
+ case ModuleInternalLinkage:
case InternalLinkage: return CXLinkage_Internal;
case UniqueExternalLinkage: return CXLinkage_UniqueExternal;
+ case ModuleLinkage:
case ExternalLinkage: return CXLinkage_External;
};
@@ -7152,15 +7280,11 @@ static CXVersion convertVersion(VersionTuple In) {
return Out;
}
-static int getCursorPlatformAvailabilityForDecl(const Decl *D,
- int *always_deprecated,
- CXString *deprecated_message,
- int *always_unavailable,
- CXString *unavailable_message,
- CXPlatformAvailability *availability,
- int availability_size) {
+static void getCursorPlatformAvailabilityForDecl(
+ const Decl *D, int *always_deprecated, CXString *deprecated_message,
+ int *always_unavailable, CXString *unavailable_message,
+ SmallVectorImpl<AvailabilityAttr *> &AvailabilityAttrs) {
bool HadAvailAttr = false;
- int N = 0;
for (auto A : D->attrs()) {
if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(A)) {
HadAvailAttr = true;
@@ -7172,7 +7296,7 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
}
continue;
}
-
+
if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(A)) {
HadAvailAttr = true;
if (always_unavailable)
@@ -7183,38 +7307,72 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
}
continue;
}
-
+
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(A)) {
+ AvailabilityAttrs.push_back(Avail);
HadAvailAttr = true;
- if (N < availability_size) {
- availability[N].Platform
- = cxstring::createDup(Avail->getPlatform()->getName());
- availability[N].Introduced = convertVersion(Avail->getIntroduced());
- availability[N].Deprecated = convertVersion(Avail->getDeprecated());
- availability[N].Obsoleted = convertVersion(Avail->getObsoleted());
- availability[N].Unavailable = Avail->getUnavailable();
- availability[N].Message = cxstring::createDup(Avail->getMessage());
- }
- ++N;
}
}
if (!HadAvailAttr)
if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D))
return getCursorPlatformAvailabilityForDecl(
- cast<Decl>(EnumConst->getDeclContext()),
- always_deprecated,
- deprecated_message,
- always_unavailable,
- unavailable_message,
- availability,
- availability_size);
-
- return N;
+ cast<Decl>(EnumConst->getDeclContext()), always_deprecated,
+ deprecated_message, always_unavailable, unavailable_message,
+ AvailabilityAttrs);
+
+ if (AvailabilityAttrs.empty())
+ return;
+
+ std::sort(AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
+ [](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
+ return LHS->getPlatform()->getName() <
+ RHS->getPlatform()->getName();
+ });
+ ASTContext &Ctx = D->getASTContext();
+ auto It = std::unique(
+ AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
+ [&Ctx](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
+ if (LHS->getPlatform() != RHS->getPlatform())
+ return false;
+
+ if (LHS->getIntroduced() == RHS->getIntroduced() &&
+ LHS->getDeprecated() == RHS->getDeprecated() &&
+ LHS->getObsoleted() == RHS->getObsoleted() &&
+ LHS->getMessage() == RHS->getMessage() &&
+ LHS->getReplacement() == RHS->getReplacement())
+ return true;
+
+ if ((!LHS->getIntroduced().empty() && !RHS->getIntroduced().empty()) ||
+ (!LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) ||
+ (!LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()))
+ return false;
+
+ if (LHS->getIntroduced().empty() && !RHS->getIntroduced().empty())
+ LHS->setIntroduced(Ctx, RHS->getIntroduced());
+
+ if (LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) {
+ LHS->setDeprecated(Ctx, RHS->getDeprecated());
+ if (LHS->getMessage().empty())
+ LHS->setMessage(Ctx, RHS->getMessage());
+ if (LHS->getReplacement().empty())
+ LHS->setReplacement(Ctx, RHS->getReplacement());
+ }
+
+ if (LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()) {
+ LHS->setObsoleted(Ctx, RHS->getObsoleted());
+ if (LHS->getMessage().empty())
+ LHS->setMessage(Ctx, RHS->getMessage());
+ if (LHS->getReplacement().empty())
+ LHS->setReplacement(Ctx, RHS->getReplacement());
+ }
+
+ return true;
+ });
+ AvailabilityAttrs.erase(It, AvailabilityAttrs.end());
}
-int clang_getCursorPlatformAvailability(CXCursor cursor,
- int *always_deprecated,
+int clang_getCursorPlatformAvailability(CXCursor cursor, int *always_deprecated,
CXString *deprecated_message,
int *always_unavailable,
CXString *unavailable_message,
@@ -7236,14 +7394,29 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
if (!D)
return 0;
- return getCursorPlatformAvailabilityForDecl(D, always_deprecated,
- deprecated_message,
- always_unavailable,
- unavailable_message,
- availability,
- availability_size);
+ SmallVector<AvailabilityAttr *, 8> AvailabilityAttrs;
+ getCursorPlatformAvailabilityForDecl(D, always_deprecated, deprecated_message,
+ always_unavailable, unavailable_message,
+ AvailabilityAttrs);
+ for (const auto &Avail :
+ llvm::enumerate(llvm::makeArrayRef(AvailabilityAttrs)
+ .take_front(availability_size))) {
+ availability[Avail.index()].Platform =
+ cxstring::createDup(Avail.value()->getPlatform()->getName());
+ availability[Avail.index()].Introduced =
+ convertVersion(Avail.value()->getIntroduced());
+ availability[Avail.index()].Deprecated =
+ convertVersion(Avail.value()->getDeprecated());
+ availability[Avail.index()].Obsoleted =
+ convertVersion(Avail.value()->getObsoleted());
+ availability[Avail.index()].Unavailable = Avail.value()->getUnavailable();
+ availability[Avail.index()].Message =
+ cxstring::createDup(Avail.value()->getMessage());
+ }
+
+ return AvailabilityAttrs.size();
}
-
+
void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
clang_disposeString(availability->Platform);
clang_disposeString(availability->Message);
@@ -7256,6 +7429,22 @@ CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
return CXLanguage_Invalid;
}
+CXTLSKind clang_getCursorTLSKind(CXCursor cursor) {
+ const Decl *D = cxcursor::getCursorDecl(cursor);
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ switch (VD->getTLSKind()) {
+ case VarDecl::TLS_None:
+ return CXTLS_None;
+ case VarDecl::TLS_Dynamic:
+ return CXTLS_Dynamic;
+ case VarDecl::TLS_Static:
+ return CXTLS_Static;
+ }
+ }
+
+ return CXTLS_None;
+}
+
/// \brief If the given cursor is the "templated" declaration
/// descibing a class or function template, return the class or
/// function template.
@@ -7431,6 +7620,26 @@ unsigned clang_Cursor_isVariadic(CXCursor C) {
return 0;
}
+unsigned clang_Cursor_isExternalSymbol(CXCursor C,
+ CXString *language, CXString *definedIn,
+ unsigned *isGenerated) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = getCursorDecl(C);
+
+ if (auto *attr = D->getExternalSourceSymbolAttr()) {
+ if (language)
+ *language = cxstring::createDup(attr->getLanguage());
+ if (definedIn)
+ *definedIn = cxstring::createDup(attr->getDefinedIn());
+ if (isGenerated)
+ *isGenerated = attr->getGeneratedDeclaration();
+ return 1;
+ }
+ return 0;
+}
+
CXSourceRange clang_Cursor_getCommentRange(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getNullRange();
@@ -7676,6 +7885,15 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) {
return (Method && Method->isVirtual()) ? 1 : 0;
}
+unsigned clang_EnumDecl_isScoped(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = cxcursor::getCursorDecl(C);
+ auto *Enum = dyn_cast_or_null<EnumDecl>(D);
+ return (Enum && Enum->isScoped()) ? 1 : 0;
+}
+
//===----------------------------------------------------------------------===//
// Attribute introspection.
//===----------------------------------------------------------------------===//
@@ -8055,7 +8273,7 @@ cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI, const Token &Tok,
return nullptr;
// Check that the identifier is not one of the macro arguments.
- if (std::find(MI->arg_begin(), MI->arg_end(), &II) != MI->arg_end())
+ if (std::find(MI->param_begin(), MI->param_end(), &II) != MI->param_end())
return nullptr;
MacroDirective *InnerMD = PP.getLocalMacroDirectiveHistory(&II);
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index ca68bc1cd2..c2b4c0bcb0 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/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index de223d3043..4e47b25a4b 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -110,40 +110,34 @@ public:
CurrentSet = &CD.getChildDiagnostics();
}
- void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
+ void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag D) override {
if (!D.isNull())
return;
CXSourceLocation L;
- if (SM)
- L = translateSourceLocation(*SM, LangOpts, Loc);
+ if (Loc.hasManager())
+ L = translateSourceLocation(Loc.getManager(), LangOpts, Loc);
else
L = clang_getNullLocation();
CurrentSet->appendDiagnostic(
llvm::make_unique<CXDiagnosticCustomNoteImpl>(Message, L));
}
- void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) override {}
+ ArrayRef<CharSourceRange> Ranges) override {}
- void emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) override {}
+ void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) override {}
- void emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) override {
+ void emitNote(FullSourceLoc Loc, StringRef Message) override {
CXSourceLocation L;
- if (SM)
- L = translateSourceLocation(*SM, LangOpts, Loc);
+ if (Loc.hasManager())
+ L = translateSourceLocation(Loc.getManager(), LangOpts, Loc);
else
L = clang_getNullLocation();
CurrentSet->appendDiagnostic(
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 2dd6703076..da2beca2ac 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -51,6 +51,9 @@ if (TARGET clangTidyPlugin)
add_definitions(-DCLANG_TOOL_EXTRA_BUILD)
list(APPEND LIBS clangTidyPlugin)
list(APPEND LIBS clangIncludeFixerPlugin)
+ if(LLVM_ENABLE_MODULES)
+ list(APPEND LLVM_COMPILE_FLAGS "-fmodules-ignore-macro=CLANG_TOOL_EXTRA_BUILD")
+ endif()
endif ()
find_library(DL_LIBRARY_PATH dl)
@@ -115,6 +118,12 @@ if(ENABLE_SHARED)
PROPERTIES
VERSION ${LIBCLANG_LIBRARY_VERSION}
DEFINE_SYMBOL _CINDEX_LIB_)
+ # FIXME: _CINDEX_LIB_ affects dllexport/dllimport on Win32.
+ if(LLVM_ENABLE_MODULES AND NOT WIN32)
+ target_compile_options(libclang PRIVATE
+ "-fmodules-ignore-macro=_CINDEX_LIB_"
+ )
+ endif()
endif()
endif()
@@ -132,6 +141,11 @@ install(DIRECTORY ../../include/clang-c
PATTERN ".svn" EXCLUDE
)
+# LLVM_DISTRIBUTION_COMPONENTS requires that each component have both a
+# component and an install-component target, so add a dummy libclang-headers
+# target to allow using it in LLVM_DISTRIBUTION_COMPONENTS.
+add_custom_target(libclang-headers)
+
if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's.
add_custom_target(install-libclang-headers
DEPENDS
diff --git a/tools/libclang/CXCompilationDatabase.cpp b/tools/libclang/CXCompilationDatabase.cpp
index c122ec8a6d..2ca532659d 100644
--- a/tools/libclang/CXCompilationDatabase.cpp
+++ b/tools/libclang/CXCompilationDatabase.cpp
@@ -145,36 +145,23 @@ clang_CompileCommand_getArg(CXCompileCommand CCmd, unsigned Arg)
unsigned
clang_CompileCommand_getNumMappedSources(CXCompileCommand CCmd)
{
- if (!CCmd)
- return 0;
-
- return static_cast<CompileCommand *>(CCmd)->MappedSources.size();
+ // Left here for backward compatibility. No mapped sources exists in the C++
+ // backend anymore.
+ return 0;
}
CXString
clang_CompileCommand_getMappedSourcePath(CXCompileCommand CCmd, unsigned I)
{
- if (!CCmd)
- return cxstring::createNull();
-
- CompileCommand *Cmd = static_cast<CompileCommand *>(CCmd);
-
- if (I >= Cmd->MappedSources.size())
- return cxstring::createNull();
-
- return cxstring::createRef(Cmd->MappedSources[I].first.c_str());
+ // Left here for backward compatibility. No mapped sources exists in the C++
+ // backend anymore.
+ return cxstring::createNull();
}
CXString
clang_CompileCommand_getMappedSourceContent(CXCompileCommand CCmd, unsigned I)
{
- if (!CCmd)
- return cxstring::createNull();
-
- CompileCommand *Cmd = static_cast<CompileCommand *>(CCmd);
-
- if (I >= Cmd->MappedSources.size())
- return cxstring::createNull();
-
- return cxstring::createRef(Cmd->MappedSources[I].second.c_str());
+ // Left here for backward compatibility. No mapped sources exists in the C++
+ // backend anymore.
+ return cxstring::createNull();
}
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index c19aa65ac6..fb61249a77 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -1523,6 +1523,10 @@ int clang_Cursor_isDynamicCall(CXCursor C) {
return true;
}
+ if (auto *PropRefE = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ return !PropRefE->isSuperReceiver();
+ }
+
const MemberExpr *ME = nullptr;
if (isa<MemberExpr>(E))
ME = cast<MemberExpr>(E);
@@ -1532,7 +1536,9 @@ int clang_Cursor_isDynamicCall(CXCursor C) {
if (ME) {
if (const CXXMethodDecl *
MD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl()))
- return MD->isVirtual() && !ME->hasQualifier();
+ return MD->isVirtual() &&
+ ME->performsVirtualDispatch(
+ cxcursor::getCursorContext(C).getLangOpts());
}
return 0;
@@ -1547,5 +1553,23 @@ CXType clang_Cursor_getReceiverType(CXCursor C) {
if (const ObjCMessageExpr *MsgE = dyn_cast_or_null<ObjCMessageExpr>(E))
return cxtype::MakeCXType(MsgE->getReceiverType(), TU);
+ if (auto *PropRefE = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ return cxtype::MakeCXType(
+ PropRefE->getReceiverType(cxcursor::getCursorContext(C)), TU);
+ }
+
+ const MemberExpr *ME = nullptr;
+ if (isa<MemberExpr>(E))
+ ME = cast<MemberExpr>(E);
+ else if (const CallExpr *CE = dyn_cast<CallExpr>(E))
+ ME = dyn_cast_or_null<MemberExpr>(CE->getCallee());
+
+ if (ME) {
+ if (dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl())) {
+ auto receiverTy = ME->getBase()->IgnoreImpCasts()->getType();
+ return cxtype::MakeCXType(receiverTy, TU);
+ }
+ }
+
return cxtype::MakeCXType(QualType(), TU);
}
diff --git a/tools/libclang/CXIndexDataConsumer.cpp b/tools/libclang/CXIndexDataConsumer.cpp
index 5d9776be3b..ffe5c486dd 100644
--- a/tools/libclang/CXIndexDataConsumer.cpp
+++ b/tools/libclang/CXIndexDataConsumer.cpp
@@ -423,11 +423,13 @@ bool CXIndexDataConsumer::isFunctionLocalDecl(const Decl *D) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
switch (ND->getFormalLinkage()) {
case NoLinkage:
- case VisibleNoLinkage:
case InternalLinkage:
return true;
+ case VisibleNoLinkage:
+ case ModuleInternalLinkage:
case UniqueExternalLinkage:
llvm_unreachable("Not a sema linkage");
+ case ModuleLinkage:
case ExternalLinkage:
return false;
}
@@ -1256,6 +1258,7 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
case SymbolKind::Module:
case SymbolKind::Macro:
case SymbolKind::ClassProperty:
+ case SymbolKind::Using:
return CXIdxEntity_Unexposed;
case SymbolKind::Enum: return CXIdxEntity_Enum;
@@ -1315,6 +1318,7 @@ static CXIdxEntityLanguage getEntityLangFromSymbolLang(SymbolLanguage L) {
case SymbolLanguage::C: return CXIdxEntityLang_C;
case SymbolLanguage::ObjC: return CXIdxEntityLang_ObjC;
case SymbolLanguage::CXX: return CXIdxEntityLang_CXX;
+ case SymbolLanguage::Swift: return CXIdxEntityLang_Swift;
}
llvm_unreachable("invalid symbol language");
}
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index 67c31d2dba..ce8469b501 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -35,6 +35,10 @@ struct CXTranslationUnitImpl {
clang::index::CommentToXMLConverter *CommentToXML;
};
+struct CXTargetInfoImpl {
+ CXTranslationUnit TranslationUnit;
+};
+
namespace clang {
namespace cxtu {
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 54549ef1e3..dfc0152477 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Frontend/ASTUnit.h"
using namespace clang;
@@ -52,6 +53,7 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
BTCASE(Float);
BTCASE(Double);
BTCASE(LongDouble);
+ BTCASE(Float16);
BTCASE(Float128);
BTCASE(NullPtr);
BTCASE(Overload);
@@ -59,6 +61,13 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
BTCASE(ObjCId);
BTCASE(ObjCClass);
BTCASE(ObjCSel);
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) BTCASE(Id);
+#include "clang/Basic/OpenCLImageTypes.def"
+#undef IMAGE_TYPE
+ BTCASE(OCLSampler);
+ BTCASE(OCLEvent);
+ BTCASE(OCLQueue);
+ BTCASE(OCLReserveID);
default:
return CXType_Unexposed;
}
@@ -94,6 +103,7 @@ static CXTypeKind GetTypeKind(QualType T) {
TKCASE(MemberPointer);
TKCASE(Auto);
TKCASE(Elaborated);
+ TKCASE(Pipe);
default:
return CXType_Unexposed;
}
@@ -386,6 +396,30 @@ unsigned clang_isRestrictQualifiedType(CXType CT) {
return T.isLocalRestrictQualified();
}
+unsigned clang_getAddressSpace(CXType CT) {
+ QualType T = GetQualType(CT);
+
+ // For non language-specific address space, use separate helper function.
+ if (T.getAddressSpace() >= LangAS::FirstTargetAddressSpace) {
+ return T.getQualifiers().getAddressSpaceAttributePrintValue();
+ }
+ // FIXME: this function returns either a LangAS or a target AS
+ // Those values can overlap which makes this function rather unpredictable
+ // for any caller
+ return (unsigned)T.getAddressSpace();
+}
+
+CXString clang_getTypedefName(CXType CT) {
+ QualType T = GetQualType(CT);
+ const TypedefType *TT = T->getAs<TypedefType>();
+ if (TT) {
+ TypedefNameDecl *TD = TT->getDecl();
+ if (TD)
+ return cxstring::createDup(TD->getNameAsString().c_str());
+ }
+ return cxstring::createEmpty();
+}
+
CXType clang_getPointeeType(CXType CT) {
QualType T = GetQualType(CT);
const Type *TP = T.getTypePtrOrNull();
@@ -490,7 +524,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Char_U);
TKIND(UChar);
TKIND(Char16);
- TKIND(Char32);
+ TKIND(Char32);
TKIND(UShort);
TKIND(UInt);
TKIND(ULong);
@@ -508,6 +542,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Float);
TKIND(Double);
TKIND(LongDouble);
+ TKIND(Float16);
TKIND(Float128);
TKIND(NullPtr);
TKIND(Overload);
@@ -535,6 +570,14 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(MemberPointer);
TKIND(Auto);
TKIND(Elaborated);
+ TKIND(Pipe);
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) TKIND(Id);
+#include "clang/Basic/OpenCLImageTypes.def"
+#undef IMAGE_TYPE
+ TKIND(OCLSampler);
+ TKIND(OCLEvent);
+ TKIND(OCLQueue);
+ TKIND(OCLReserveID);
}
#undef TKIND
return cxstring::createRef(s);
@@ -573,7 +616,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86Pascal);
TCALLINGCONV(X86RegCall);
TCALLINGCONV(X86VectorCall);
- TCALLINGCONV(X86_64Win64);
+ TCALLINGCONV(Win64);
TCALLINGCONV(X86_64SysV);
TCALLINGCONV(AAPCS);
TCALLINGCONV(AAPCS_VFP);
@@ -646,6 +689,24 @@ CXType clang_getCursorResultType(CXCursor C) {
return MakeCXType(QualType(), cxcursor::getCursorTU(C));
}
+int clang_getExceptionSpecificationType(CXType X) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return -1;
+
+ if (const auto *FD = T->getAs<FunctionProtoType>())
+ return static_cast<int>(FD->getExceptionSpecType());
+
+ return -1;
+}
+
+int clang_getCursorExceptionSpecificationType(CXCursor C) {
+ if (clang_isDeclaration(C.kind))
+ return clang_getExceptionSpecificationType(clang_getCursorType(C));
+
+ return -1;
+}
+
unsigned clang_isPODType(CXType X) {
QualType T = GetQualType(X);
if (T.isNull())
@@ -1039,3 +1100,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/Indexing.cpp b/tools/libclang/Indexing.cpp
index f98b258879..2a136242ef 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -262,7 +262,8 @@ public:
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
/// MI is released immediately following this callback.
void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) override {}
+ const MacroDefinition &MD,
+ const MacroDirective *UD) override {}
/// MacroExpands - This is called by when a macro invocation is found.
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
@@ -271,7 +272,8 @@ public:
/// SourceRangeSkipped - This hook is called when a source range is skipped.
/// \param Range The SourceRange that was skipped. The range begins at the
/// #if/#else directive and ends after the #endif/#else directive.
- void SourceRangeSkipped(SourceRange Range) override {}
+ void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override {
+ }
};
//===----------------------------------------------------------------------===//
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 222cb67839..fb4547a867 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -12,6 +12,7 @@ clang_CXXMethod_isConst
clang_CXXMethod_isPureVirtual
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
+clang_EnumDecl_isScoped
clang_Cursor_getArgument
clang_Cursor_getNumTemplateArguments
clang_Cursor_getTemplateArgumentKind
@@ -22,6 +23,7 @@ clang_Cursor_getBriefCommentText
clang_Cursor_getCommentRange
clang_Cursor_getCXXManglings
clang_Cursor_getMangling
+clang_Cursor_getObjCManglings
clang_Cursor_getParsedComment
clang_Cursor_getRawCommentText
clang_Cursor_getNumArguments
@@ -35,6 +37,7 @@ clang_Cursor_getReceiverType
clang_Cursor_isAnonymous
clang_Cursor_isBitField
clang_Cursor_isDynamicCall
+clang_Cursor_isExternalSymbol
clang_Cursor_isNull
clang_Cursor_isObjCOptional
clang_Cursor_isVariadic
@@ -79,6 +82,9 @@ clang_TParamCommandComment_getParamName
clang_TParamCommandComment_isParamPositionValid
clang_TParamCommandComment_getDepth
clang_TParamCommandComment_getIndex
+clang_TargetInfo_dispose
+clang_TargetInfo_getPointerWidth
+clang_TargetInfo_getTriple
clang_Type_getAlignOf
clang_Type_getClassType
clang_Type_getSizeOf
@@ -88,6 +94,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
@@ -142,6 +149,7 @@ clang_findReferencesInFile
clang_findReferencesInFileWithBlock
clang_formatDiagnostic
clang_free
+clang_getAddressSpace
clang_getAllSkippedRanges
clang_getArgType
clang_getArrayElementType
@@ -169,6 +177,7 @@ clang_getCursorCompletionString
clang_getCursorDefinition
clang_getCursorDisplayName
clang_getCursorExtent
+clang_getCursorExceptionSpecificationType
clang_getCursorKind
clang_getCursorKindSpelling
clang_getCursorLanguage
@@ -181,6 +190,7 @@ clang_getCursorReferenced
clang_getCursorResultType
clang_getCursorSemanticParent
clang_getCursorSpelling
+clang_getCursorTLSKind
clang_getCursorType
clang_getCursorUSR
clang_getCursorVisibility
@@ -204,6 +214,7 @@ clang_getElementType
clang_getEnumConstantDeclUnsignedValue
clang_getEnumConstantDeclValue
clang_getEnumDeclIntegerType
+clang_getExceptionSpecificationType
clang_getFieldDeclBitWidth
clang_getExpansionLocation
clang_getFile
@@ -249,10 +260,12 @@ clang_getTokenLocation
clang_getTokenSpelling
clang_getTranslationUnitCursor
clang_getTranslationUnitSpelling
+clang_getTranslationUnitTargetInfo
clang_getTypeDeclaration
clang_getTypeKindSpelling
clang_getTypeSpelling
clang_getTypedefDeclUnderlyingType
+clang_getTypedefName
clang_hashCursor
clang_indexLoc_getCXSourceLocation
clang_indexLoc_getFileLocation
@@ -299,6 +312,7 @@ clang_remap_getFilenames
clang_remap_getNumFiles
clang_reparseTranslationUnit
clang_saveTranslationUnit
+clang_suspendTranslationUnit
clang_sortCodeCompletionResults
clang_toggleCrashRecovery
clang_tokenize
diff --git a/tools/scan-build-py/libscanbuild/__init__.py b/tools/scan-build-py/libscanbuild/__init__.py
index ca75174912..800926ebb6 100644
--- a/tools/scan-build-py/libscanbuild/__init__.py
+++ b/tools/scan-build-py/libscanbuild/__init__.py
@@ -41,12 +41,6 @@ def duplicate_check(method):
return predicate
-def tempdir():
- """ Return the default temorary directory. """
-
- return os.getenv('TMPDIR', os.getenv('TEMP', os.getenv('TMP', '/tmp')))
-
-
def run_build(command, *args, **kwargs):
""" Run and report build command execution
diff --git a/tools/scan-build-py/libscanbuild/analyze.py b/tools/scan-build-py/libscanbuild/analyze.py
index 0485ca85f6..b5614b5b6d 100644
--- a/tools/scan-build-py/libscanbuild/analyze.py
+++ b/tools/scan-build-py/libscanbuild/analyze.py
@@ -16,18 +16,23 @@ import os
import os.path
import json
import logging
-import tempfile
import multiprocessing
+import tempfile
+import functools
+import subprocess
import contextlib
import datetime
+
from libscanbuild import command_entry_point, compiler_wrapper, \
- wrapper_environment, run_build
+ wrapper_environment, run_build, run_command
from libscanbuild.arguments import parse_args_for_scan_build, \
parse_args_for_analyze_build
-from libscanbuild.runner import run
from libscanbuild.intercept import capture
from libscanbuild.report import document
-from libscanbuild.compilation import split_command
+from libscanbuild.compilation import split_command, classify_source, \
+ compiler_language
+from libscanbuild.clang import get_version, get_arguments
+from libscanbuild.shell import decode
__all__ = ['scan_build', 'analyze_build', 'analyze_compiler_wrapper']
@@ -40,7 +45,8 @@ def scan_build():
""" Entry point for scan-build command. """
args = parse_args_for_scan_build()
- with report_directory(args.output, args.keep_empty) as target_dir:
+ # 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
@@ -50,13 +56,13 @@ def scan_build():
exit_code = capture(args)
# Run the analyzer against the captured commands.
if need_analyzer(args.build):
- run_analyzer(args, target_dir)
+ run_analyzer_parallel(args)
else:
# Run build command and analyzer with compiler wrappers.
- environment = setup_environment(args, target_dir)
+ environment = setup_environment(args)
exit_code = run_build(args.build, env=environment)
# Cover report generation and bug counting.
- number_of_bugs = document(args, target_dir, False)
+ number_of_bugs = document(args)
# Set exit status as it was requested.
return number_of_bugs if args.status_bugs else exit_code
@@ -66,11 +72,12 @@ def analyze_build():
""" Entry point for analyze-build command. """
args = parse_args_for_analyze_build()
- with report_directory(args.output, args.keep_empty) as target_dir:
+ # 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(args, target_dir)
+ run_analyzer_parallel(args)
# Cover report generation and bug counting.
- number_of_bugs = document(args, target_dir, True)
+ number_of_bugs = document(args)
# Set exit status as it was requested.
return number_of_bugs if args.status_bugs else 0
@@ -88,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):
@@ -98,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),
@@ -120,7 +127,7 @@ def run_analyzer(args, output_dir):
pool.join()
-def setup_environment(args, destination):
+def setup_environment(args):
""" Set up environment for build command to interpose compiler wrapper. """
environment = dict(os.environ)
@@ -129,7 +136,7 @@ def setup_environment(args, destination):
'CC': COMPILER_WRAPPER_CC,
'CXX': COMPILER_WRAPPER_CXX,
'ANALYZE_BUILD_CLANG': args.clang if need_analyzer(args.build) else '',
- '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)),
@@ -242,7 +249,7 @@ def analyzer_params(args):
if args.output_format:
result.append('-analyzer-output={0}'.format(args.output_format))
if args.analyzer_config:
- result.append(args.analyzer_config)
+ result.extend(['-analyzer-config', args.analyzer_config])
if args.verbose >= 4:
result.append('-analyzer-display-progress')
if args.plugins:
@@ -257,3 +264,277 @@ def analyzer_params(args):
result.append('-analyzer-viz-egraph-ubigraph')
return prefix_with('-Xclang', result)
+
+
+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_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:
+ 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
index fe5725dcdf..2735123f9f 100644
--- a/tools/scan-build-py/libscanbuild/arguments.py
+++ b/tools/scan-build-py/libscanbuild/arguments.py
@@ -17,7 +17,8 @@ import os
import sys
import argparse
import logging
-from libscanbuild import reconfigure_logging, tempdir
+import tempfile
+from libscanbuild import reconfigure_logging
from libscanbuild.clang import get_checkers
__all__ = ['parse_args_for_intercept_build', 'parse_args_for_analyze_build',
@@ -187,7 +188,7 @@ def create_analyze_parser(from_build_command):
'--output',
'-o',
metavar='<path>',
- default=tempdir(),
+ default=tempfile.gettempdir(),
help="""Specifies the output directory for analyzer reports.
Subdirectory will be created if default directory is targeted.""")
output.add_argument(
diff --git a/tools/scan-build-py/libscanbuild/intercept.py b/tools/scan-build-py/libscanbuild/intercept.py
index 71b957d83a..b9bf9e9175 100644
--- a/tools/scan-build-py/libscanbuild/intercept.py
+++ b/tools/scan-build-py/libscanbuild/intercept.py
@@ -31,7 +31,7 @@ import logging
from libear import build_libear, TemporaryDirectory
from libscanbuild import command_entry_point, compiler_wrapper, \
wrapper_environment, run_command, run_build
-from libscanbuild import duplicate_check, tempdir
+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
@@ -84,7 +84,7 @@ def capture(args):
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)
exit_code = run_build(args.build, env=environment)
diff --git a/tools/scan-build-py/libscanbuild/report.py b/tools/scan-build-py/libscanbuild/report.py
index 08170093f7..54b9695d92 100644
--- a/tools/scan-build-py/libscanbuild/report.py
+++ b/tools/scan-build-py/libscanbuild/report.py
@@ -18,58 +18,60 @@ import plistlib
import glob
import json
import logging
+import datetime
from libscanbuild import duplicate_check
from libscanbuild.clang import get_version
__all__ = ['document']
-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>
@@ -481,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 014b872479..0000000000
--- a/tools/scan-build-py/libscanbuild/runner.py
+++ /dev/null
@@ -1,294 +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 import run_command
-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_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:
- 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 dc8bf12eb4..6b7fd9fa0d 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 5cfc121266..a250ff2213 100644
--- a/tools/scan-build-py/tests/unit/test_analyze.py
+++ b/tools/scan-build-py/tests/unit/test_analyze.py
@@ -7,6 +7,10 @@
import libear
import libscanbuild.analyze as sut
import unittest
+import re
+import os
+import os.path
+
class ReportDirectoryTest(unittest.TestCase):
@@ -20,3 +24,312 @@ class ReportDirectoryTest(unittest.TestCase):
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_report.py b/tools/scan-build-py/tests/unit/test_report.py
index 3f249ce2aa..c943699156 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')
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 4b51e65284..0000000000
--- a/tools/scan-build-py/tests/unit/test_runner.py
+++ /dev/null
@@ -1,321 +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(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 78c243d8e0..380379300b 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-build/libexec/ccc-analyzer b/tools/scan-build/libexec/ccc-analyzer
index bfda1d326f..b0ec7e7e74 100755
--- a/tools/scan-build/libexec/ccc-analyzer
+++ b/tools/scan-build/libexec/ccc-analyzer
@@ -385,7 +385,8 @@ my %CompilerLinkerOptionMap = (
'-target' => 1,
'-v' => 0,
'-mmacosx-version-min' => 0, # This is really a 1 argument, but always has '='
- '-miphoneos-version-min' => 0 # This is really a 1 argument, but always has '='
+ '-miphoneos-version-min' => 0, # This is really a 1 argument, but always has '='
+ '--target' => 0
);
my %IgnoredOptionMap = (
diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp
index 57b41f12b0..aea5bfa39e 100644
--- a/unittests/AST/ASTImporterTest.cpp
+++ b/unittests/AST/ASTImporterTest.cpp
@@ -97,6 +97,10 @@ testImport(const std::string &FromCode, Language FromLang,
llvm::raw_svector_ostream ToNothing(ImportChecker);
ToCtx.getTranslationUnitDecl()->print(ToNothing);
+ // This traverses the AST to catch certain bugs like poorly or not
+ // implemented subtrees.
+ Imported->dump(ToNothing);
+
return Verifier.match(Imported, AMatcher);
}
@@ -252,35 +256,28 @@ AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
TEST(ImportExpr, ImportParenListExpr) {
MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(testImport(
+ "template<typename T> class dummy { void f() { dummy X(*this); } };"
+ "typedef dummy<int> declToImport;"
+ "template class dummy<int>;",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ typedefDecl(hasType(templateSpecializationType(
+ hasDeclaration(classTemplateSpecializationDecl(hasSpecializedTemplate(
+ classTemplateDecl(hasTemplateDecl(cxxRecordDecl(hasMethod(allOf(
+ hasName("f"),
+ hasBody(compoundStmt(has(declStmt(hasSingleDecl(
+ varDecl(hasInitializer(parenListExpr(has(unaryOperator(
+ hasOperatorName("*"),
+ hasUnaryOperand(cxxThisExpr()))))))))))))))))))))))));
+}
+
+TEST(ImportExpr, ImportSwitch) {
+ MatchVerifier<Decl> Verifier;
EXPECT_TRUE(
- testImport(
- "template<typename T> class dummy { void f() { dummy X(*this); } };"
- "typedef dummy<int> declToImport;"
- "template class dummy<int>;",
- Lang_CXX, "", Lang_CXX, Verifier,
- typedefDecl(
- hasType(
- templateSpecializationType(
- hasDeclaration(
- classTemplateDecl(
- hasTemplateDecl(
- cxxRecordDecl(
- hasMethod(
- allOf(
- hasName("f"),
- hasBody(
- compoundStmt(
- has(
- declStmt(
- hasSingleDecl(
- varDecl(
- hasInitializer(
- parenListExpr(
- has(
- unaryOperator(
- hasOperatorName("*"),
- hasUnaryOperand(cxxThisExpr())
- )))))))))))))))))))));
+ testImport("void declToImport() { int b; switch (b) { case 1: break; } }",
+ Lang_CXX, "", Lang_CXX, Verifier,
+ functionDecl(hasBody(compoundStmt(
+ has(switchStmt(has(compoundStmt(has(caseStmt()))))))))));
}
TEST(ImportExpr, ImportStmtExpr) {
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index a7008f3e7e..45dfa7a972 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_unittest(ASTTests
ASTVectorTest.cpp
CommentLexer.cpp
CommentParser.cpp
+ DataCollectionTest.cpp
DeclPrinterTest.cpp
DeclTest.cpp
EvaluateAsRValueTest.cpp
diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp
index 77ee22ffb4..f96d6cd15f 100644
--- a/unittests/AST/CommentLexer.cpp
+++ b/unittests/AST/CommentLexer.cpp
@@ -320,9 +320,10 @@ TEST_F(CommentLexerTest, DoxygenCommand4) {
ASSERT_EQ(array_lengthof(Text), Toks.size());
for (size_t j = 0, e = Toks.size(); j != e; j++) {
- if(Toks[j].is(tok::text))
+ if(Toks[j].is(tok::text)) {
ASSERT_EQ(StringRef(Text[j]), Toks[j].getText())
<< "index " << i;
+ }
}
}
}
diff --git a/unittests/AST/DataCollectionTest.cpp b/unittests/AST/DataCollectionTest.cpp
new file mode 100644
index 0000000000..e8ebd16217
--- /dev/null
+++ b/unittests/AST/DataCollectionTest.cpp
@@ -0,0 +1,173 @@
+//===- unittests/AST/DataCollectionTest.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 tests for the DataCollection module.
+//
+// They work by hashing the collected data of two nodes and asserting that the
+// hash values are equal iff the nodes are considered equal.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DataCollection.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace ast_matchers;
+
+namespace {
+class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector> {
+ ASTContext &Context;
+ llvm::MD5 &DataConsumer;
+
+ template <class T> void addData(const T &Data) {
+ data_collection::addDataToConsumer(DataConsumer, Data);
+ }
+
+public:
+ StmtDataCollector(const Stmt *S, ASTContext &Context, llvm::MD5 &DataConsumer)
+ : Context(Context), DataConsumer(DataConsumer) {
+ this->Visit(S);
+ }
+
+#define DEF_ADD_DATA(CLASS, CODE) \
+ template <class Dummy = void> Dummy Visit##CLASS(const CLASS *S) { \
+ CODE; \
+ ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
+ }
+
+#include "clang/AST/StmtDataCollectors.inc"
+};
+} // end anonymous namespace
+
+namespace {
+struct StmtHashMatch : public MatchFinder::MatchCallback {
+ unsigned NumFound;
+ llvm::MD5::MD5Result &Hash;
+ StmtHashMatch(llvm::MD5::MD5Result &Hash) : NumFound(0), Hash(Hash) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
+ if (!S)
+ return;
+ ++NumFound;
+ if (NumFound > 1)
+ return;
+ llvm::MD5 MD5;
+ StmtDataCollector(S, *Result.Context, MD5);
+ MD5.final(Hash);
+ }
+};
+} // end anonymous namespace
+
+static testing::AssertionResult hashStmt(llvm::MD5::MD5Result &Hash,
+ const StatementMatcher &StmtMatch,
+ StringRef Code) {
+ StmtHashMatch Hasher(Hash);
+ MatchFinder Finder;
+ Finder.addMatcher(StmtMatch, &Hasher);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ if (!runToolOnCode(Factory->create(), Code))
+ return testing::AssertionFailure()
+ << "Parsing error in \"" << Code.str() << "\"";
+ if (Hasher.NumFound == 0)
+ return testing::AssertionFailure() << "Matcher didn't find any statements";
+ if (Hasher.NumFound > 1)
+ return testing::AssertionFailure()
+ << "Matcher should match only one statement "
+ "(found "
+ << Hasher.NumFound << ")";
+ return testing::AssertionSuccess();
+}
+
+static testing::AssertionResult
+isStmtHashEqual(const StatementMatcher &StmtMatch, StringRef Code1,
+ StringRef Code2) {
+ llvm::MD5::MD5Result Hash1, Hash2;
+ testing::AssertionResult Result = hashStmt(Hash1, StmtMatch, Code1);
+ if (!Result)
+ return Result;
+ if (!(Result = hashStmt(Hash2, StmtMatch, Code2)))
+ return Result;
+
+ return testing::AssertionResult(Hash1 == Hash2);
+}
+
+TEST(StmtDataCollector, TestDeclRefExpr) {
+ ASSERT_TRUE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
+ "int x, r = x;"));
+ ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
+ "int y, r = y;"));
+ ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
+ "namespace n { int x, r = x; };"));
+}
+
+TEST(StmtDataCollector, TestMemberExpr) {
+ ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
+ "struct { int x; } X; int r = X.x;",
+ "struct { int x; } X; int r = (&X)->x;"));
+ ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
+ "struct { int x; } X; int r = X.x;",
+ "struct { int x; } Y; int r = Y.x;"));
+ ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
+ "struct { int x; } X; int r = X.x;",
+ "struct C { int x; } X; int r = X.C::x;"));
+ ASSERT_FALSE(isStmtHashEqual(memberExpr().bind("id"),
+ "struct { int x; } X; int r = X.x;",
+ "struct { int y; } X; int r = X.y;"));
+}
+
+TEST(StmtDataCollector, TestIntegerLiteral) {
+ ASSERT_TRUE(
+ isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 0;"));
+ ASSERT_TRUE(
+ isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x =00;"));
+ ASSERT_FALSE(
+ isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 1;"));
+}
+
+TEST(StmtDataCollector, TestFloatingLiteral) {
+ ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
+ "double x = .0;"));
+ ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .10;",
+ "double x = .1;"));
+ ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .1;",
+ "double x = 1e-1;"));
+ ASSERT_FALSE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
+ "double x = .1;"));
+}
+
+TEST(StmtDataCollector, TestStringLiteral) {
+ ASSERT_TRUE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
+ R"(char x[] = "0";)"));
+ ASSERT_FALSE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
+ R"(char x[] = "1";)"));
+}
+
+TEST(StmtDataCollector, TestCXXBoolLiteral) {
+ ASSERT_TRUE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
+ "bool x = false;"));
+ ASSERT_FALSE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
+ "bool x = true;"));
+}
+
+TEST(StmtDataCollector, TestCharacterLiteral) {
+ ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
+ "char x = '0';"));
+ ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"),
+ R"(char x = '\0';)",
+ R"(char x = '\x00';)"));
+ ASSERT_FALSE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
+ "char x = '1';"));
+}
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index e5a09a31f6..ae6d0f0dd2 100644
--- a/unittests/AST/DeclPrinterTest.cpp
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -1228,7 +1228,7 @@ TEST(DeclPrinter, TestObjCMethod1) {
"@end\n",
namedDecl(hasName("A:inRange:"),
hasDescendant(namedDecl(hasName("printThis")))).bind("id"),
- "- (int) A:(id)anObject inRange:(long)range"));
+ "- (int)A:(id)anObject inRange:(long)range"));
}
TEST(DeclPrinter, TestObjCProtocol1) {
diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp
index 12b203236c..a0644401a7 100644
--- a/unittests/AST/StmtPrinterTest.cpp
+++ b/unittests/AST/StmtPrinterTest.cpp
@@ -31,18 +31,26 @@ using namespace tooling;
namespace {
-void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S) {
+using PolicyAdjusterType =
+ Optional<llvm::function_ref<void(PrintingPolicy &Policy)>>;
+
+void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S,
+ PolicyAdjusterType PolicyAdjuster) {
assert(S != nullptr && "Expected non-null Stmt");
PrintingPolicy Policy = Context->getPrintingPolicy();
+ if (PolicyAdjuster)
+ (*PolicyAdjuster)(Policy);
S->printPretty(Out, /*Helper*/ nullptr, Policy);
}
class PrintMatch : public MatchFinder::MatchCallback {
SmallString<1024> Printed;
unsigned NumFoundStmts;
+ PolicyAdjusterType PolicyAdjuster;
public:
- PrintMatch() : NumFoundStmts(0) {}
+ PrintMatch(PolicyAdjusterType PolicyAdjuster)
+ : NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {}
void run(const MatchFinder::MatchResult &Result) override {
const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
@@ -53,7 +61,7 @@ public:
return;
llvm::raw_svector_ostream Out(Printed);
- PrintStmt(Out, Result.Context, S);
+ PrintStmt(Out, Result.Context, S, PolicyAdjuster);
}
StringRef getPrinted() const {
@@ -68,9 +76,10 @@ public:
template <typename T>
::testing::AssertionResult
PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
- const T &NodeMatch, StringRef ExpectedPrinted) {
+ const T &NodeMatch, StringRef ExpectedPrinted,
+ PolicyAdjusterType PolicyAdjuster = None) {
- PrintMatch Printer;
+ PrintMatch Printer(PolicyAdjuster);
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
std::unique_ptr<FrontendActionFactory> Factory(
@@ -122,11 +131,13 @@ PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch,
::testing::AssertionResult
PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
- StringRef ExpectedPrinted) {
+ StringRef ExpectedPrinted,
+ PolicyAdjusterType PolicyAdjuster = None) {
std::vector<std::string> Args;
Args.push_back("-std=c++11");
Args.push_back("-Wno-unused-value");
- return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
+ return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
+ PolicyAdjuster);
}
::testing::AssertionResult PrintedStmtMSMatches(
@@ -146,6 +157,17 @@ PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
ExpectedPrinted);
}
+::testing::AssertionResult
+PrintedStmtObjCMatches(StringRef Code, const StatementMatcher &NodeMatch,
+ StringRef ExpectedPrinted,
+ PolicyAdjusterType PolicyAdjuster = None) {
+ std::vector<std::string> Args;
+ Args.push_back("-ObjC");
+ Args.push_back("-fobjc-runtime=macosx-10.12.0");
+ return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
+ PolicyAdjuster);
+}
+
} // unnamed namespace
TEST(StmtPrinter, TestIntegerLiteral) {
@@ -214,3 +236,41 @@ TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
"(a & b)"));
// WRONG; Should be: (a & b).operator void *()
}
+
+TEST(StmtPrinter, TestNoImplicitBases) {
+ const char *CPPSource = R"(
+class A {
+ int field;
+ int member() { return field; }
+};
+)";
+ // No implicit 'this'.
+ ASSERT_TRUE(PrintedStmtCXX11Matches(
+ CPPSource, memberExpr(anything()).bind("id"), "field",
+ PolicyAdjusterType(
+ [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; })));
+ // Print implicit 'this'.
+ ASSERT_TRUE(PrintedStmtCXX11Matches(
+ CPPSource, memberExpr(anything()).bind("id"), "this->field"));
+
+ const char *ObjCSource = R"(
+@interface I {
+ int ivar;
+}
+@end
+@implementation I
+- (int) method {
+ return ivar;
+}
+@end
+ )";
+ // No implicit 'self'.
+ ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
+ "return ivar;\n",
+ PolicyAdjusterType([](PrintingPolicy &PP) {
+ PP.SuppressImplicitBase = true;
+ })));
+ // Print implicit 'self'.
+ ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
+ "return self->ivar;\n"));
+}
diff --git a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 6037127feb..7bc8421bab 100644
--- a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1108,26 +1108,35 @@ TEST(ConstructorDeclaration, IsExplicit) {
}
TEST(ConstructorDeclaration, Kinds) {
- EXPECT_TRUE(matches("struct S { S(); };",
- cxxConstructorDecl(isDefaultConstructor())));
- EXPECT_TRUE(notMatches("struct S { S(); };",
- cxxConstructorDecl(isCopyConstructor())));
- EXPECT_TRUE(notMatches("struct S { S(); };",
- cxxConstructorDecl(isMoveConstructor())));
-
- EXPECT_TRUE(notMatches("struct S { S(const S&); };",
- cxxConstructorDecl(isDefaultConstructor())));
- EXPECT_TRUE(matches("struct S { S(const S&); };",
- cxxConstructorDecl(isCopyConstructor())));
- EXPECT_TRUE(notMatches("struct S { S(const S&); };",
- cxxConstructorDecl(isMoveConstructor())));
-
- EXPECT_TRUE(notMatches("struct S { S(S&&); };",
- cxxConstructorDecl(isDefaultConstructor())));
- EXPECT_TRUE(notMatches("struct S { S(S&&); };",
- cxxConstructorDecl(isCopyConstructor())));
- EXPECT_TRUE(matches("struct S { S(S&&); };",
- cxxConstructorDecl(isMoveConstructor())));
+ EXPECT_TRUE(matches(
+ "struct S { S(); };",
+ cxxConstructorDecl(isDefaultConstructor(), unless(isImplicit()))));
+ EXPECT_TRUE(notMatches(
+ "struct S { S(); };",
+ cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
+ EXPECT_TRUE(notMatches(
+ "struct S { S(); };",
+ cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));
+
+ EXPECT_TRUE(notMatches(
+ "struct S { S(const S&); };",
+ cxxConstructorDecl(isDefaultConstructor(), unless(isImplicit()))));
+ EXPECT_TRUE(matches(
+ "struct S { S(const S&); };",
+ cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
+ EXPECT_TRUE(notMatches(
+ "struct S { S(const S&); };",
+ cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));
+
+ EXPECT_TRUE(notMatches(
+ "struct S { S(S&&); };",
+ cxxConstructorDecl(isDefaultConstructor(), unless(isImplicit()))));
+ EXPECT_TRUE(notMatches(
+ "struct S { S(S&&); };",
+ cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))));
+ EXPECT_TRUE(matches(
+ "struct S { S(S&&); };",
+ cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))));
}
TEST(ConstructorDeclaration, IsUserProvided) {
diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index dd45ca3ced..a24d8d338e 100644
--- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -666,6 +666,12 @@ TEST(Matcher, IntegerLiterals) {
EXPECT_TRUE(notMatches("int i = 'a';", HasIntLiteral));
EXPECT_TRUE(notMatches("int i = 1e10;", HasIntLiteral));
EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral));
+
+ // Negative integers.
+ EXPECT_TRUE(
+ matches("int i = -10;",
+ unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(equals(10))))));
}
TEST(Matcher, FloatLiterals) {
@@ -1020,6 +1026,29 @@ TEST(InitListExpression, MatchesInitListExpression) {
matches("int i[1] = {42, [0] = 43};", integerLiteral(equals(42))));
}
+TEST(CXXStdInitializerListExpression, MatchesCXXStdInitializerListExpression) {
+ const std::string code = "namespace std {"
+ "template <typename> class initializer_list {"
+ " public: initializer_list() noexcept {}"
+ "};"
+ "}"
+ "struct A {"
+ " A(std::initializer_list<int>) {}"
+ "};";
+ EXPECT_TRUE(matches(code + "A a{0};",
+ cxxConstructExpr(has(cxxStdInitializerListExpr()),
+ hasDeclaration(cxxConstructorDecl(
+ ofClass(hasName("A")))))));
+ EXPECT_TRUE(matches(code + "A a = {0};",
+ cxxConstructExpr(has(cxxStdInitializerListExpr()),
+ hasDeclaration(cxxConstructorDecl(
+ ofClass(hasName("A")))))));
+
+ EXPECT_TRUE(notMatches("int a[] = { 1, 2 };", cxxStdInitializerListExpr()));
+ EXPECT_TRUE(notMatches("struct B { int x, y; }; B b = { 5, 6 };",
+ cxxStdInitializerListExpr()));
+}
+
TEST(UsingDeclaration, MatchesUsingDeclarations) {
EXPECT_TRUE(matches("namespace X { int x; } using X::x;",
usingDecl()));
@@ -1155,6 +1184,10 @@ TEST(TypeMatching, MatchesAutoTypes) {
EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }",
autoType()));
+ EXPECT_TRUE(matches("auto i = 2;", varDecl(hasType(isInteger()))));
+ EXPECT_TRUE(matches("struct X{}; auto x = X{};",
+ varDecl(hasType(recordDecl(hasName("X"))))));
+
// FIXME: Matching against the type-as-written can't work here, because the
// type as written was not deduced.
//EXPECT_TRUE(matches("auto a = 1;",
@@ -1494,15 +1527,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 +1590,54 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) {
)));
}
+TEST(ObjCDeclMatcher, 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 "
+ "@implementation Thing (ABC) "
+ "- (void)abc_doThing {} "
+ "@end "
+ ;
+
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcProtocolDecl(hasName("Proto"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcImplementationDecl(hasName("Thing"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcCategoryDecl(hasName("ABC"))));
+ EXPECT_TRUE(matchesObjC(
+ ObjCString,
+ objcCategoryImplDecl(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 fdb273c672..7cfe5b9e37 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);
}
@@ -309,10 +320,12 @@ public:
ExpectedName(ExpectedName) {}
void onEndOfTranslationUnit() override {
- if (ExpectedCount != -1)
+ if (ExpectedCount != -1) {
EXPECT_EQ(ExpectedCount, Count);
- if (!ExpectedName.empty())
+ }
+ if (!ExpectedName.empty()) {
EXPECT_EQ(ExpectedName, Name);
+ }
Count = 0;
Name.clear();
}
@@ -335,8 +348,9 @@ public:
}
BoundNodes::IDToNodeMap::const_iterator I = M.find(Id);
EXPECT_NE(M.end(), I);
- if (I != M.end())
+ if (I != M.end()) {
EXPECT_EQ(Nodes->getNodeAs<T>(Id), I->second.get<T>());
+ }
return true;
}
EXPECT_TRUE(M.count(Id) == 0 ||
diff --git a/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 5957c7fa41..e699e19262 100644
--- a/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -230,6 +230,17 @@ TEST(HasDeclaration, HasGetDeclTraitTest) {
"Expected TemplateSpecializationType to *not* have a getDecl.");
}
+TEST(HasDeclaration, ElaboratedType) {
+ EXPECT_TRUE(matches(
+ "namespace n { template <typename T> struct X {}; }"
+ "void f(n::X<int>);",
+ parmVarDecl(hasType(qualType(hasDeclaration(cxxRecordDecl()))))));
+ EXPECT_TRUE(matches(
+ "namespace n { template <typename T> struct X {}; }"
+ "void f(n::X<int>);",
+ parmVarDecl(hasType(elaboratedType(hasDeclaration(cxxRecordDecl()))))));
+}
+
TEST(HasDeclaration, HasDeclarationOfTypeWithDecl) {
EXPECT_TRUE(matches("typedef int X; X a;",
varDecl(hasName("a"),
@@ -242,6 +253,13 @@ TEST(HasDeclaration, HasDeclarationOfTemplateSpecializationType) {
EXPECT_TRUE(matches("template <typename T> class A {}; A<int> a;",
varDecl(hasType(templateSpecializationType(
hasDeclaration(namedDecl(hasName("A"))))))));
+ EXPECT_TRUE(matches("template <typename T> class A {};"
+ "template <typename T> class B { A<T> a; };",
+ fieldDecl(hasType(templateSpecializationType(
+ hasDeclaration(namedDecl(hasName("A"))))))));
+ EXPECT_TRUE(matches("template <typename T> class A {}; A<int> a;",
+ varDecl(hasType(templateSpecializationType(
+ hasDeclaration(cxxRecordDecl()))))));
}
TEST(HasDeclaration, HasDeclarationOfCXXNewExpr) {
@@ -250,6 +268,12 @@ TEST(HasDeclaration, HasDeclarationOfCXXNewExpr) {
cxxNewExpr(hasDeclaration(functionDecl(parameterCountIs(1))))));
}
+TEST(HasDeclaration, HasDeclarationOfTypeAlias) {
+ EXPECT_TRUE(matches("template <typename T> using C = T; C<int> c;",
+ varDecl(hasType(templateSpecializationType(
+ hasDeclaration(typeAliasTemplateDecl()))))));
+}
+
TEST(HasUnqualifiedDesugaredType, DesugarsUsing) {
EXPECT_TRUE(
matches("struct A {}; using B = A; B b;",
@@ -785,14 +809,18 @@ TEST(HasAnyConstructorInitializer, ForField) {
static const char Code[] =
"class Baz { };"
"class Foo {"
- " Foo() : foo_() { }"
+ " Foo() : foo_(), bar_() { }"
" Baz foo_;"
- " Baz bar_;"
+ " struct {"
+ " Baz bar_;"
+ " };"
"};";
EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer(
forField(hasType(recordDecl(hasName("Baz"))))))));
EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer(
forField(hasName("foo_"))))));
+ EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer(
+ forField(hasName("bar_"))))));
EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer(
forField(hasType(recordDecl(hasName("Bar"))))))));
}
@@ -2207,8 +2235,7 @@ TEST(Matcher, HasAnyDeclaration) {
functionDecl(hasName("bar"))))));
}
-TEST(SubstTemplateTypeParmType, HasReplacementType)
-{
+TEST(SubstTemplateTypeParmType, HasReplacementType) {
std::string Fragment = "template<typename T>"
"double F(T t);"
"int i;"
@@ -2224,5 +2251,13 @@ TEST(SubstTemplateTypeParmType, HasReplacementType)
substTemplateTypeParmType(hasReplacementType(qualType()))));
}
+TEST(ClassTemplateSpecializationDecl, HasSpecializedTemplate) {
+ auto Matcher = classTemplateSpecializationDecl(
+ hasSpecializedTemplate(classTemplateDecl()));
+ EXPECT_TRUE(
+ matches("template<typename T> class A {}; typedef A<int> B;", Matcher));
+ EXPECT_TRUE(notMatches("template<typename T> class A {};", Matcher));
+}
+
} // namespace ast_matchers
} // namespace clang
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index d241f5ba2f..0c4c7dfd78 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -75,6 +75,30 @@ public:
ExpectedMatchersTy ExpectedMatchers;
};
+TEST(ParserTest, ParseBoolean) {
+ MockSema Sema;
+ Sema.parse("true");
+ Sema.parse("false");
+ EXPECT_EQ(2U, Sema.Values.size());
+ EXPECT_TRUE(Sema.Values[0].getBoolean());
+ EXPECT_FALSE(Sema.Values[1].getBoolean());
+}
+
+TEST(ParserTest, ParseDouble) {
+ MockSema Sema;
+ Sema.parse("1.0");
+ Sema.parse("2.0f");
+ Sema.parse("34.56e-78");
+ Sema.parse("4.E+6");
+ Sema.parse("1");
+ EXPECT_EQ(5U, Sema.Values.size());
+ EXPECT_EQ(1.0, Sema.Values[0].getDouble());
+ EXPECT_EQ("1:1: Error parsing numeric literal: <2.0f>", Sema.Errors[1]);
+ EXPECT_EQ(34.56e-78, Sema.Values[2].getDouble());
+ EXPECT_EQ(4e+6, Sema.Values[3].getDouble());
+ EXPECT_FALSE(Sema.Values[4].isDouble());
+}
+
TEST(ParserTest, ParseUnsigned) {
MockSema Sema;
Sema.parse("0");
@@ -86,8 +110,8 @@ TEST(ParserTest, ParseUnsigned) {
EXPECT_EQ(0U, Sema.Values[0].getUnsigned());
EXPECT_EQ(123U, Sema.Values[1].getUnsigned());
EXPECT_EQ(31U, Sema.Values[2].getUnsigned());
- EXPECT_EQ("1:1: Error parsing unsigned token: <12345678901>", Sema.Errors[3]);
- EXPECT_EQ("1:1: Error parsing unsigned token: <1a1>", Sema.Errors[4]);
+ EXPECT_EQ("1:1: Error parsing numeric literal: <12345678901>", Sema.Errors[3]);
+ EXPECT_EQ("1:1: Error parsing numeric literal: <1a1>", Sema.Errors[4]);
}
TEST(ParserTest, ParseString) {
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 6bbbc2bd35..aae229bd04 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -511,6 +511,49 @@ TEST_F(RegistryTest, ParenExpr) {
EXPECT_FALSE(matches("int i = 1;", Value));
}
+TEST_F(RegistryTest, EqualsMatcher) {
+ Matcher<Stmt> BooleanStmt = constructMatcher(
+ "cxxBoolLiteral", constructMatcher("equals", VariantValue(true)))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("bool x = true;", BooleanStmt));
+ EXPECT_FALSE(matches("bool x = false;", BooleanStmt));
+ EXPECT_FALSE(matches("bool x = 0;", BooleanStmt));
+
+ BooleanStmt = constructMatcher(
+ "cxxBoolLiteral", constructMatcher("equals", VariantValue(0)))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("bool x = false;", BooleanStmt));
+ EXPECT_FALSE(matches("bool x = true;", BooleanStmt));
+ EXPECT_FALSE(matches("bool x = 0;", BooleanStmt));
+
+ Matcher<Stmt> DoubleStmt = constructMatcher(
+ "floatLiteral", constructMatcher("equals", VariantValue(1.2)))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("double x = 1.2;", DoubleStmt));
+#if 0
+ // FIXME floatLiteral matching should work regardless of suffix.
+ EXPECT_TRUE(matches("double x = 1.2f;", DoubleStmt));
+ EXPECT_TRUE(matches("double x = 1.2l;", DoubleStmt));
+#endif
+ EXPECT_TRUE(matches("double x = 12e-1;", DoubleStmt));
+ EXPECT_FALSE(matches("double x = 1.23;", DoubleStmt));
+
+ Matcher<Stmt> IntegerStmt = constructMatcher(
+ "integerLiteral", constructMatcher("equals", VariantValue(42)))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("int x = 42;", IntegerStmt));
+ EXPECT_FALSE(matches("int x = 1;", IntegerStmt));
+
+ Matcher<Stmt> CharStmt = constructMatcher(
+ "characterLiteral", constructMatcher("equals", VariantValue('x')))
+ .getTypedMatcher<Stmt>();
+ EXPECT_TRUE(matches("int x = 'x';", CharStmt));
+ EXPECT_TRUE(matches("int x = L'x';", CharStmt));
+ EXPECT_TRUE(matches("int x = u'x';", CharStmt));
+ EXPECT_TRUE(matches("int x = U'x';", CharStmt));
+ EXPECT_FALSE(matches("int x = 120;", CharStmt));
+}
+
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
index 9df7b780d4..7d3a07028a 100644
--- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -75,12 +75,16 @@ TEST(VariantValueTest, Assignment) {
EXPECT_TRUE(Value.isString());
EXPECT_EQ("A", Value.getString());
EXPECT_TRUE(Value.hasValue());
+ EXPECT_FALSE(Value.isBoolean());
+ EXPECT_FALSE(Value.isDouble());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
EXPECT_EQ("String", Value.getTypeAsString());
Value = VariantMatcher::SingleMatcher(recordDecl());
EXPECT_TRUE(Value.hasValue());
+ EXPECT_FALSE(Value.isBoolean());
+ EXPECT_FALSE(Value.isDouble());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
@@ -88,15 +92,36 @@ TEST(VariantValueTest, Assignment) {
EXPECT_FALSE(Value.getMatcher().hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
+ Value = true;
+ EXPECT_TRUE(Value.isBoolean());
+ EXPECT_EQ(true, Value.getBoolean());
+ EXPECT_TRUE(Value.hasValue());
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isString());
+
+ Value = 3.14;
+ EXPECT_TRUE(Value.isDouble());
+ EXPECT_EQ(3.14, Value.getDouble());
+ EXPECT_TRUE(Value.hasValue());
+ EXPECT_FALSE(Value.isBoolean());
+ EXPECT_FALSE(Value.isUnsigned());
+ EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isString());
+
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(17U, Value.getUnsigned());
+ EXPECT_FALSE(Value.isBoolean());
+ EXPECT_FALSE(Value.isDouble());
EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isMatcher());
EXPECT_FALSE(Value.isString());
Value = VariantValue();
EXPECT_FALSE(Value.hasValue());
+ EXPECT_FALSE(Value.isBoolean());
+ EXPECT_FALSE(Value.isDouble());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
diff --git a/unittests/Analysis/CMakeLists.txt b/unittests/Analysis/CMakeLists.txt
index 926f586be3..62db8f652e 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 0000000000..965a4bc308
--- /dev/null
+++ b/unittests/Analysis/CloneDetectionTest.cpp
@@ -0,0 +1,112 @@
+//===- 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(),
+ RecursiveCloneTypeIIHashConstraint(),
+ MinComplexityConstraint(2), MinGroupSizeConstraint(2),
+ RecursiveCloneTypeIIVerifyConstraint(),
+ 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, RecursiveCloneTypeIIHashConstraint(),
+ MinComplexityConstraint(2), MinGroupSizeConstraint(2),
+ RecursiveCloneTypeIIVerifyConstraint(),
+ 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 3cb3cb8d3c..3a9f34f3d2 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/DiagnosticTest.cpp b/unittests/Basic/DiagnosticTest.cpp
index 4ffa0837bd..3068e1c340 100644
--- a/unittests/Basic/DiagnosticTest.cpp
+++ b/unittests/Basic/DiagnosticTest.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticError.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "gtest/gtest.h"
@@ -46,27 +47,51 @@ TEST(DiagnosticTest, suppressAndTrap) {
EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred());
}
-// Check that FatalsAsErrors works as intended
-TEST(DiagnosticTest, fatalsAsErrors) {
- DiagnosticsEngine Diags(new DiagnosticIDs(),
- new DiagnosticOptions,
- new IgnoringDiagConsumer());
- Diags.setFatalsAsError(true);
+// Check that SuppressAfterFatalError works as intended
+TEST(DiagnosticTest, suppressAfterFatalError) {
+ for (unsigned Suppress = 0; Suppress != 2; ++Suppress) {
+ DiagnosticsEngine Diags(new DiagnosticIDs(),
+ new DiagnosticOptions,
+ new IgnoringDiagConsumer());
+ Diags.setSuppressAfterFatalError(Suppress);
- // Diag that would set UncompilableErrorOccurred and ErrorOccurred.
- Diags.Report(diag::err_target_unknown_triple) << "unknown";
+ // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
+ Diags.Report(diag::err_cannot_open_file) << "file" << "error";
- // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
- Diags.Report(diag::err_cannot_open_file) << "file" << "error";
+ // Diag that would set FatalErrorOccurred
+ // (via non-note following a fatal error).
+ Diags.Report(diag::warn_mt_message) << "warning";
- // Diag that would set FatalErrorOccurred
- // (via non-note following a fatal error).
- Diags.Report(diag::warn_mt_message) << "warning";
+ EXPECT_TRUE(Diags.hasErrorOccurred());
+ EXPECT_TRUE(Diags.hasFatalErrorOccurred());
+ EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
+ EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
- EXPECT_TRUE(Diags.hasErrorOccurred());
- EXPECT_FALSE(Diags.hasFatalErrorOccurred());
- EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
- EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
+ // The warning should be emitted and counted only if we're not suppressing
+ // after fatal errors.
+ EXPECT_EQ(Diags.getNumWarnings(), Suppress ? 0u : 1u);
+ }
}
+TEST(DiagnosticTest, diagnosticError) {
+ DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+ new IgnoringDiagConsumer());
+ PartialDiagnostic::StorageAllocator Alloc;
+ llvm::Expected<std::pair<int, int>> Value = DiagnosticError::create(
+ SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc)
+ << "file"
+ << "error");
+ ASSERT_TRUE(!Value);
+ llvm::Error Err = Value.takeError();
+ Optional<PartialDiagnosticAt> ErrDiag = DiagnosticError::take(Err);
+ llvm::cantFail(std::move(Err));
+ ASSERT_FALSE(!ErrDiag);
+ EXPECT_EQ(ErrDiag->first, SourceLocation());
+ EXPECT_EQ(ErrDiag->second.getDiagID(), diag::err_cannot_open_file);
+
+ Value = std::make_pair(20, 1);
+ ASSERT_FALSE(!Value);
+ EXPECT_EQ(*Value, std::make_pair(20, 1));
+ EXPECT_EQ(Value->first, 20);
+}
}
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index 4cf21cd845..a2a6c6aebe 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -10,8 +10,10 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/FileSystemStatCache.h"
+#include "clang/Basic/VirtualFileSystem.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 +31,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 +63,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 +154,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 +179,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 +201,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 +249,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 +264,63 @@ 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
+TEST_F(FileManagerTest, makeAbsoluteUsesVFS) {
+ SmallString<64> CustomWorkingDir;
+#ifdef LLVM_ON_WIN32
+ CustomWorkingDir = "C:";
+#else
+ CustomWorkingDir = "/";
+#endif
+ llvm::sys::path::append(CustomWorkingDir, "some", "weird", "path");
+
+ auto FS =
+ IntrusiveRefCntPtr<vfs::InMemoryFileSystem>(new vfs::InMemoryFileSystem);
+ // setCurrentworkingdirectory must finish without error.
+ ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
+
+ FileSystemOptions Opts;
+ FileManager Manager(Opts, FS);
+
+ SmallString<64> Path("a/foo.cpp");
+
+ SmallString<64> ExpectedResult(CustomWorkingDir);
+ llvm::sys::path::append(ExpectedResult, Path);
+
+ ASSERT_TRUE(Manager.makeAbsolutePath(Path));
+ EXPECT_EQ(Path, ExpectedResult);
+}
+
} // anonymous namespace
diff --git a/unittests/Basic/MemoryBufferCacheTest.cpp b/unittests/Basic/MemoryBufferCacheTest.cpp
new file mode 100644
index 0000000000..99178f8150
--- /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 a967b0ec7c..8457d3b639 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"
@@ -50,24 +51,6 @@ protected:
IntrusiveRefCntPtr<TargetInfo> Target;
};
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
const char *source =
"#define M(x) [x]\n"
@@ -77,11 +60,12 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
SourceMgr.setMainFileID(mainFileID);
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader 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);
@@ -197,11 +181,12 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
HeaderBuf->getBufferSize(), 0);
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader 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);
@@ -246,12 +231,18 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
namespace {
struct MacroAction {
+ enum Kind { kExpansion, kDefinition, kUnDefinition};
+
SourceLocation Loc;
std::string Name;
- bool isDefinition; // if false, it is expansion.
-
- MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
- : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
+ unsigned MAKind : 3;
+
+ MacroAction(SourceLocation Loc, StringRef Name, unsigned K)
+ : Loc(Loc), Name(Name), MAKind(K) { }
+
+ bool isExpansion() const { return MAKind == kExpansion; }
+ bool isDefinition() const { return MAKind & kDefinition; }
+ bool isUnDefinition() const { return MAKind & kUnDefinition; }
};
class MacroTracker : public PPCallbacks {
@@ -264,13 +255,22 @@ public:
const MacroDirective *MD) override {
Macros.push_back(MacroAction(MD->getLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
- true));
+ MacroAction::kDefinition));
+ }
+ void MacroUndefined(const Token &MacroNameTok,
+ const MacroDefinition &MD,
+ const MacroDirective *UD) override {
+ Macros.push_back(
+ MacroAction(UD ? UD->getLocation() : SourceLocation(),
+ MacroNameTok.getIdentifierInfo()->getName(),
+ UD ? MacroAction::kDefinition | MacroAction::kUnDefinition
+ : MacroAction::kUnDefinition));
}
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
SourceRange Range, const MacroArgs *Args) override {
Macros.push_back(MacroAction(MacroNameTok.getLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
- false));
+ MacroAction::kExpansion));
}
};
@@ -278,7 +278,10 @@ public:
TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
const char *header =
- "#define MACRO_IN_INCLUDE 0\n";
+ "#define MACRO_IN_INCLUDE 0\n"
+ "#define MACRO_DEFINED\n"
+ "#undef MACRO_DEFINED\n"
+ "#undef MACRO_UNDEFINED\n";
const char *main =
"#define M(x) x\n"
@@ -297,11 +300,12 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
HeaderBuf->getBufferSize(), 0);
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader 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);
@@ -323,34 +327,46 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
// Make sure we got the tokens that we expected.
ASSERT_EQ(0U, toks.size());
- ASSERT_EQ(9U, Macros.size());
+ ASSERT_EQ(15U, Macros.size());
// #define M(x) x
- ASSERT_TRUE(Macros[0].isDefinition);
+ ASSERT_TRUE(Macros[0].isDefinition());
ASSERT_EQ("M", Macros[0].Name);
// #define INC "/test-header.h"
- ASSERT_TRUE(Macros[1].isDefinition);
+ ASSERT_TRUE(Macros[1].isDefinition());
ASSERT_EQ("INC", Macros[1].Name);
// M expansion in #include M(INC)
- ASSERT_FALSE(Macros[2].isDefinition);
+ ASSERT_FALSE(Macros[2].isDefinition());
ASSERT_EQ("M", Macros[2].Name);
// INC expansion in #include M(INC)
- ASSERT_FALSE(Macros[3].isDefinition);
+ ASSERT_TRUE(Macros[3].isExpansion());
ASSERT_EQ("INC", Macros[3].Name);
// #define MACRO_IN_INCLUDE 0
- ASSERT_TRUE(Macros[4].isDefinition);
+ ASSERT_TRUE(Macros[4].isDefinition());
ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
+ // #define MACRO_DEFINED
+ ASSERT_TRUE(Macros[5].isDefinition());
+ ASSERT_FALSE(Macros[5].isUnDefinition());
+ ASSERT_EQ("MACRO_DEFINED", Macros[5].Name);
+ // #undef MACRO_DEFINED
+ ASSERT_TRUE(Macros[6].isDefinition());
+ ASSERT_TRUE(Macros[6].isUnDefinition());
+ ASSERT_EQ("MACRO_DEFINED", Macros[6].Name);
+ // #undef MACRO_UNDEFINED
+ ASSERT_FALSE(Macros[7].isDefinition());
+ ASSERT_TRUE(Macros[7].isUnDefinition());
+ ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name);
// #define INC2 </test-header.h>
- ASSERT_TRUE(Macros[5].isDefinition);
- ASSERT_EQ("INC2", Macros[5].Name);
+ ASSERT_TRUE(Macros[8].isDefinition());
+ ASSERT_EQ("INC2", Macros[8].Name);
// M expansion in #include M(INC2)
- ASSERT_FALSE(Macros[6].isDefinition);
- ASSERT_EQ("M", Macros[6].Name);
+ ASSERT_FALSE(Macros[9].isDefinition());
+ ASSERT_EQ("M", Macros[9].Name);
// INC2 expansion in #include M(INC2)
- ASSERT_FALSE(Macros[7].isDefinition);
- ASSERT_EQ("INC2", Macros[7].Name);
+ ASSERT_TRUE(Macros[10].isExpansion());
+ ASSERT_EQ("INC2", Macros[10].Name);
// #define MACRO_IN_INCLUDE 0
- ASSERT_TRUE(Macros[8].isDefinition);
- ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name);
+ ASSERT_TRUE(Macros[11].isDefinition());
+ ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name);
// The INC expansion in #include M(INC) comes before the first
// MACRO_IN_INCLUDE definition of the included file.
@@ -358,7 +374,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
// The INC2 expansion in #include M(INC2) comes before the second
// MACRO_IN_INCLUDE definition of the included file.
- EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc));
+ EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
}
#endif
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index 92e3663f92..40add2195b 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -300,8 +300,9 @@ struct ScopedDir {
EXPECT_FALSE(EC);
}
~ScopedDir() {
- if (Path != "")
+ if (Path != "") {
EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
+ }
}
operator StringRef() { return Path.str(); }
};
@@ -316,8 +317,9 @@ struct ScopedLink {
EXPECT_FALSE(EC);
}
~ScopedLink() {
- if (Path != "")
+ if (Path != "") {
EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
+ }
}
operator StringRef() { return Path.str(); }
};
@@ -363,16 +365,22 @@ TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
I != E; I.increment(EC)) {
// Skip broken symlinks.
- if (EC == std::errc::no_such_file_or_directory) {
- EC = std::error_code();
+ 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() << "std::errc::no_such_file_or_directory: "
- << (int)std::errc::no_such_file_or_directory << "\n";
- outs() << "EC: " << EC.value() << "\n";
- outs() << "EC message: " << EC.message() << "\n";
+ 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);
@@ -441,16 +449,22 @@ TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
I != E; I.increment(EC)) {
// Skip broken symlinks.
- if (EC == std::errc::no_such_file_or_directory) {
- EC = std::error_code();
+ 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() << "std::errc::no_such_file_or_directory: "
- << (int)std::errc::no_such_file_or_directory << "\n";
- outs() << "EC: " << EC.value() << "\n";
- outs() << "EC message: " << EC.message() << "\n";
+ 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());
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 7d407ce3f6..090de3b06e 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -19,6 +19,7 @@ if(CLANG_ENABLE_STATIC_ANALYZER)
endif()
add_subdirectory(ASTMatchers)
add_subdirectory(AST)
+add_subdirectory(CrossTU)
add_subdirectory(Tooling)
add_subdirectory(Format)
add_subdirectory(Rewrite)
@@ -29,3 +30,4 @@ add_subdirectory(CodeGen)
if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD)
add_subdirectory(libclang)
endif()
+add_subdirectory(Rename)
diff --git a/unittests/CodeGen/CMakeLists.txt b/unittests/CodeGen/CMakeLists.txt
index 27a513a2f9..c49776bc02 100644
--- a/unittests/CodeGen/CMakeLists.txt
+++ b/unittests/CodeGen/CMakeLists.txt
@@ -5,11 +5,15 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(ClangCodeGenTests
BufferSourceTest.cpp
+ CodeGenExternalTest.cpp
+ IncrementalProcessingTest.cpp
)
target_link_libraries(ClangCodeGenTests
+ clangAST
clangBasic
clangCodeGen
clangFrontend
+ clangLex
clangParse
)
diff --git a/unittests/CodeGen/CodeGenExternalTest.cpp b/unittests/CodeGen/CodeGenExternalTest.cpp
new file mode 100644
index 0000000000..bcec3eab06
--- /dev/null
+++ b/unittests/CodeGen/CodeGenExternalTest.cpp
@@ -0,0 +1,302 @@
+//===- unittests/CodeGen/CodeGenExternalTest.cpp - test external CodeGen -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/GlobalDecl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/CodeGenABITypes.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// Mocks up a language using Clang code generation as a library and
+// tests some basic functionality there.
+// - CodeGen->GetAddrOfGlobal
+// - CodeGen::convertTypeForMemory
+// - CodeGen::getLLVMFieldNumber
+
+static const bool DebugThisTest = false;
+
+// forward declarations
+struct MyASTConsumer;
+static void test_codegen_fns(MyASTConsumer *my);
+static bool test_codegen_fns_ran;
+
+// This forwards the calls to the Clang CodeGenerator
+// so that we can test CodeGen functions while it is open.
+// It accumulates toplevel decls in HandleTopLevelDecl and
+// calls test_codegen_fns() in HandleTranslationUnit
+// before forwarding that function to the CodeGenerator.
+
+struct MyASTConsumer : public ASTConsumer {
+ std::unique_ptr<CodeGenerator> Builder;
+ std::vector<Decl*> toplevel_decls;
+
+ MyASTConsumer(std::unique_ptr<CodeGenerator> Builder_in)
+ : ASTConsumer(), Builder(std::move(Builder_in))
+ {
+ }
+
+ ~MyASTConsumer() { }
+
+ void Initialize(ASTContext &Context) override;
+ void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override;
+ bool HandleTopLevelDecl(DeclGroupRef D) override;
+ void HandleInlineFunctionDefinition(FunctionDecl *D) override;
+ void HandleInterestingDecl(DeclGroupRef D) override;
+ void HandleTranslationUnit(ASTContext &Ctx) override;
+ void HandleTagDeclDefinition(TagDecl *D) override;
+ void HandleTagDeclRequiredDefinition(const TagDecl *D) override;
+ void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override;
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
+ void HandleImplicitImportDecl(ImportDecl *D) override;
+ void CompleteTentativeDefinition(VarDecl *D) override;
+ void AssignInheritanceModel(CXXRecordDecl *RD) override;
+ void HandleVTable(CXXRecordDecl *RD) override;
+ ASTMutationListener *GetASTMutationListener() override;
+ ASTDeserializationListener *GetASTDeserializationListener() override;
+ void PrintStats() override;
+ bool shouldSkipFunctionBody(Decl *D) override;
+};
+
+void MyASTConsumer::Initialize(ASTContext &Context) {
+ Builder->Initialize(Context);
+}
+
+bool MyASTConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
+
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
+ toplevel_decls.push_back(*I);
+ }
+
+ return Builder->HandleTopLevelDecl(DG);
+}
+
+void MyASTConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) {
+ Builder->HandleInlineFunctionDefinition(D);
+}
+
+void MyASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
+ Builder->HandleInterestingDecl(D);
+}
+
+void MyASTConsumer::HandleTranslationUnit(ASTContext &Context) {
+ test_codegen_fns(this);
+ // HandleTranslationUnit can close the module
+ Builder->HandleTranslationUnit(Context);
+}
+
+void MyASTConsumer::HandleTagDeclDefinition(TagDecl *D) {
+ Builder->HandleTagDeclDefinition(D);
+}
+
+void MyASTConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) {
+ Builder->HandleTagDeclRequiredDefinition(D);
+}
+
+void MyASTConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
+ Builder->HandleCXXImplicitFunctionInstantiation(D);
+}
+
+void MyASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+ Builder->HandleTopLevelDeclInObjCContainer(D);
+}
+
+void MyASTConsumer::HandleImplicitImportDecl(ImportDecl *D) {
+ Builder->HandleImplicitImportDecl(D);
+}
+
+void MyASTConsumer::CompleteTentativeDefinition(VarDecl *D) {
+ Builder->CompleteTentativeDefinition(D);
+}
+
+void MyASTConsumer::AssignInheritanceModel(CXXRecordDecl *RD) {
+ Builder->AssignInheritanceModel(RD);
+}
+
+void MyASTConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ Builder->HandleCXXStaticMemberVarInstantiation(VD);
+}
+
+void MyASTConsumer::HandleVTable(CXXRecordDecl *RD) {
+ Builder->HandleVTable(RD);
+ }
+
+ASTMutationListener *MyASTConsumer::GetASTMutationListener() {
+ return Builder->GetASTMutationListener();
+}
+
+ASTDeserializationListener *MyASTConsumer::GetASTDeserializationListener() {
+ return Builder->GetASTDeserializationListener();
+}
+
+void MyASTConsumer::PrintStats() {
+ Builder->PrintStats();
+}
+
+bool MyASTConsumer::shouldSkipFunctionBody(Decl *D) {
+ return Builder->shouldSkipFunctionBody(D);
+}
+
+const char TestProgram[] =
+ "struct mytest_struct { char x; short y; char p; long z; };\n"
+ "int mytest_fn(int x) { return x; }\n";
+
+// This function has the real test code here
+static void test_codegen_fns(MyASTConsumer *my) {
+
+ bool mytest_fn_ok = false;
+ bool mytest_struct_ok = false;
+
+ CodeGen::CodeGenModule &CGM = my->Builder->CGM();
+
+ for (auto decl : my->toplevel_decls ) {
+ if (FunctionDecl *fd = dyn_cast<FunctionDecl>(decl)) {
+ if (fd->getName() == "mytest_fn") {
+ Constant *c = my->Builder->GetAddrOfGlobal(GlobalDecl(fd), false);
+ // Verify that we got a function.
+ ASSERT_TRUE(c != NULL);
+ if (DebugThisTest) {
+ c->print(dbgs(), true);
+ dbgs() << "\n";
+ }
+ mytest_fn_ok = true;
+ }
+ } else if(clang::RecordDecl *rd = dyn_cast<RecordDecl>(decl)) {
+ if (rd->getName() == "mytest_struct") {
+ RecordDecl *def = rd->getDefinition();
+ ASSERT_TRUE(def != NULL);
+ const clang::Type *clangTy = rd->getCanonicalDecl()->getTypeForDecl();
+ ASSERT_TRUE(clangTy != NULL);
+ QualType qType = clangTy->getCanonicalTypeInternal();
+
+ // Check convertTypeForMemory
+ llvm::Type *llvmTy = CodeGen::convertTypeForMemory(CGM, qType);
+ ASSERT_TRUE(llvmTy != NULL);
+ if (DebugThisTest) {
+ llvmTy->print(dbgs(), true);
+ dbgs() << "\n";
+ }
+
+ llvm::CompositeType* structTy = dyn_cast<CompositeType>(llvmTy);
+ ASSERT_TRUE(structTy != NULL);
+
+ // Check getLLVMFieldNumber
+ FieldDecl *xField = NULL;
+ FieldDecl *yField = NULL;
+ FieldDecl *zField = NULL;
+
+ for (auto field : rd->fields()) {
+ if (field->getName() == "x") xField = field;
+ if (field->getName() == "y") yField = field;
+ if (field->getName() == "z") zField = field;
+ }
+
+ ASSERT_TRUE(xField != NULL);
+ ASSERT_TRUE(yField != NULL);
+ ASSERT_TRUE(zField != NULL);
+
+ unsigned x = CodeGen::getLLVMFieldNumber(CGM, rd, xField);
+ unsigned y = CodeGen::getLLVMFieldNumber(CGM, rd, yField);
+ unsigned z = CodeGen::getLLVMFieldNumber(CGM, rd, zField);
+
+ ASSERT_NE(x, y);
+ ASSERT_NE(y, z);
+
+ llvm::Type* xTy = structTy->getTypeAtIndex(x);
+ llvm::Type* yTy = structTy->getTypeAtIndex(y);
+ llvm::Type* zTy = structTy->getTypeAtIndex(z);
+
+ ASSERT_TRUE(xTy != NULL);
+ ASSERT_TRUE(yTy != NULL);
+ ASSERT_TRUE(zTy != NULL);
+
+ if (DebugThisTest) {
+ xTy->print(dbgs(), true);
+ dbgs() << "\n";
+ yTy->print(dbgs(), true);
+ dbgs() << "\n";
+ zTy->print(dbgs(), true);
+ dbgs() << "\n";
+ }
+
+ ASSERT_GE(xTy->getPrimitiveSizeInBits(), 1u);
+ ASSERT_GE(yTy->getPrimitiveSizeInBits(), 16u); // short is at least 16b
+ ASSERT_GE(zTy->getPrimitiveSizeInBits(), 32u); // long is at least 32b
+
+ mytest_struct_ok = true;
+ }
+ }
+ }
+
+ ASSERT_TRUE(mytest_fn_ok);
+ ASSERT_TRUE(mytest_struct_ok);
+
+ test_codegen_fns_ran = true;
+}
+
+TEST(CodeGenExternalTest, CodeGenExternalTest) {
+ LLVMContext Context;
+ CompilerInstance compiler;
+
+ compiler.createDiagnostics();
+ compiler.getLangOpts().CPlusPlus = 1;
+ compiler.getLangOpts().CPlusPlus11 = 1;
+
+ compiler.getTargetOpts().Triple = llvm::Triple::normalize(
+ llvm::sys::getProcessTriple());
+ compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
+ compiler.getDiagnostics(),
+ std::make_shared<clang::TargetOptions>(
+ compiler.getTargetOpts())));
+
+ compiler.createFileManager();
+ compiler.createSourceManager(compiler.getFileManager());
+ compiler.createPreprocessor(clang::TU_Prefix);
+
+ compiler.createASTContext();
+
+
+ compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(
+ new MyASTConsumer(std::unique_ptr<CodeGenerator>(
+ CreateLLVMCodeGen(compiler.getDiagnostics(),
+ "MemoryTypesTest",
+ compiler.getHeaderSearchOpts(),
+ compiler.getPreprocessorOpts(),
+ compiler.getCodeGenOpts(),
+ Context)))));
+
+ compiler.createSema(clang::TU_Prefix, nullptr);
+
+ clang::SourceManager &sm = compiler.getSourceManager();
+ sm.setMainFileID(sm.createFileID(
+ llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
+
+ clang::ParseAST(compiler.getSema(), false, false);
+
+ ASSERT_TRUE(test_codegen_fns_ran);
+}
+
+} // end anonymous namespace
diff --git a/unittests/CodeGen/IncrementalProcessingTest.cpp b/unittests/CodeGen/IncrementalProcessingTest.cpp
new file mode 100644
index 0000000000..40b814bf31
--- /dev/null
+++ b/unittests/CodeGen/IncrementalProcessingTest.cpp
@@ -0,0 +1,174 @@
+//=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+#include <memory>
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// Incremental processing produces several modules, all using the same "main
+// file". Make sure CodeGen can cope with that, e.g. for static initializers.
+const char TestProgram1[] =
+ "extern \"C\" int funcForProg1() { return 17; }\n"
+ "struct EmitCXXGlobalInitFunc1 {\n"
+ " EmitCXXGlobalInitFunc1() {}\n"
+ "} test1;";
+
+const char TestProgram2[] =
+ "extern \"C\" int funcForProg2() { return 42; }\n"
+ "struct EmitCXXGlobalInitFunc2 {\n"
+ " EmitCXXGlobalInitFunc2() {}\n"
+ "} test2;";
+
+
+/// An incremental version of ParseAST().
+static std::unique_ptr<llvm::Module>
+IncrementalParseAST(CompilerInstance& CI, Parser& P,
+ CodeGenerator& CG, const char* code) {
+ static int counter = 0;
+ struct IncreaseCounterOnRet {
+ ~IncreaseCounterOnRet() {
+ ++counter;
+ }
+ } ICOR;
+
+ Sema& S = CI.getSema();
+ clang::SourceManager &SM = S.getSourceManager();
+ if (!code) {
+ // Main file
+ SM.setMainFileID(SM.createFileID(
+ llvm::MemoryBuffer::getMemBuffer(" "), clang::SrcMgr::C_User));
+
+ S.getPreprocessor().EnterMainSourceFile();
+ P.Initialize();
+ } else {
+ FileID FID = SM.createFileID(
+ llvm::MemoryBuffer::getMemBuffer(code), clang::SrcMgr::C_User);
+ SourceLocation MainStartLoc = SM.getLocForStartOfFile(SM.getMainFileID());
+ SourceLocation InclLoc = MainStartLoc.getLocWithOffset(counter);
+ S.getPreprocessor().EnterSourceFile(FID, 0, InclLoc);
+ }
+
+ ExternalASTSource *External = S.getASTContext().getExternalSource();
+ if (External)
+ External->StartTranslationUnit(&CG);
+
+ Parser::DeclGroupPtrTy ADecl;
+ for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
+ AtEOF = P.ParseTopLevelDecl(ADecl)) {
+ // If we got a null return and something *was* parsed, ignore it. This
+ // is due to a top-level semicolon, an action override, or a parse error
+ // skipping something.
+ if (ADecl && !CG.HandleTopLevelDecl(ADecl.get()))
+ return nullptr;
+ }
+
+ // Process any TopLevelDecls generated by #pragma weak.
+ for (Decl *D : S.WeakTopLevelDecls())
+ CG.HandleTopLevelDecl(DeclGroupRef(D));
+
+ CG.HandleTranslationUnit(S.getASTContext());
+
+ std::unique_ptr<llvm::Module> M(CG.ReleaseModule());
+ // Switch to next module.
+ CG.StartModule("incremental-module-" + std::to_string(counter),
+ M->getContext());
+ return M;
+}
+
+const Function* getGlobalInit(llvm::Module& M) {
+ for (const auto& Func: M)
+ if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_"))
+ return &Func;
+
+ return nullptr;
+}
+
+TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) {
+ LLVMContext Context;
+ CompilerInstance compiler;
+
+ compiler.createDiagnostics();
+ compiler.getLangOpts().CPlusPlus = 1;
+ compiler.getLangOpts().CPlusPlus11 = 1;
+
+ compiler.getTargetOpts().Triple = llvm::Triple::normalize(
+ llvm::sys::getProcessTriple());
+ compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
+ compiler.getDiagnostics(),
+ std::make_shared<clang::TargetOptions>(
+ compiler.getTargetOpts())));
+
+ compiler.createFileManager();
+ compiler.createSourceManager(compiler.getFileManager());
+ compiler.createPreprocessor(clang::TU_Prefix);
+ compiler.getPreprocessor().enableIncrementalProcessing();
+
+ compiler.createASTContext();
+
+ CodeGenerator* CG =
+ CreateLLVMCodeGen(
+ compiler.getDiagnostics(),
+ "main-module",
+ compiler.getHeaderSearchOpts(),
+ compiler.getPreprocessorOpts(),
+ compiler.getCodeGenOpts(),
+ Context);
+ compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(CG));
+ compiler.createSema(clang::TU_Prefix, nullptr);
+ Sema& S = compiler.getSema();
+
+ std::unique_ptr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
+ /*SkipFunctionBodies*/ false));
+ Parser &P = *ParseOP.get();
+
+ std::array<std::unique_ptr<llvm::Module>, 3> M;
+ M[0] = IncrementalParseAST(compiler, P, *CG, nullptr);
+ ASSERT_TRUE(M[0]);
+
+ M[1] = IncrementalParseAST(compiler, P, *CG, TestProgram1);
+ ASSERT_TRUE(M[1]);
+ ASSERT_TRUE(M[1]->getFunction("funcForProg1"));
+
+ M[2] = IncrementalParseAST(compiler, P, *CG, TestProgram2);
+ ASSERT_TRUE(M[2]);
+ ASSERT_TRUE(M[2]->getFunction("funcForProg2"));
+ // First code should not end up in second module:
+ ASSERT_FALSE(M[2]->getFunction("funcForProg1"));
+
+ // Make sure global inits exist and are unique:
+ const Function* GlobalInit1 = getGlobalInit(*M[1]);
+ ASSERT_TRUE(GlobalInit1);
+
+ const Function* GlobalInit2 = getGlobalInit(*M[2]);
+ ASSERT_TRUE(GlobalInit2);
+
+ ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName());
+
+}
+
+} // end anonymous namespace
diff --git a/unittests/CrossTU/CMakeLists.txt b/unittests/CrossTU/CMakeLists.txt
new file mode 100644
index 0000000000..3c479c4473
--- /dev/null
+++ b/unittests/CrossTU/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ Support
+ )
+
+add_clang_unittest(CrossTUTests
+ CrossTranslationUnitTest.cpp
+ )
+
+target_link_libraries(CrossTUTests
+ clangAST
+ clangBasic
+ clangCrossTU
+ clangFrontend
+ clangTooling
+ )
diff --git a/unittests/CrossTU/CrossTranslationUnitTest.cpp b/unittests/CrossTU/CrossTranslationUnitTest.cpp
new file mode 100644
index 0000000000..5fbf56ed43
--- /dev/null
+++ b/unittests/CrossTU/CrossTranslationUnitTest.cpp
@@ -0,0 +1,158 @@
+//===- unittest/Tooling/CrossTranslationUnitTest.cpp - Tooling 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/CrossTU/CrossTranslationUnit.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "gtest/gtest.h"
+#include <cassert>
+
+namespace clang {
+namespace cross_tu {
+
+namespace {
+
+class CTUASTConsumer : public clang::ASTConsumer {
+public:
+ explicit CTUASTConsumer(clang::CompilerInstance &CI, bool *Success)
+ : CTU(CI), Success(Success) {}
+
+ void HandleTranslationUnit(ASTContext &Ctx) {
+ const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
+ const FunctionDecl *FD = nullptr;
+ for (const Decl *D : TU->decls()) {
+ FD = dyn_cast<FunctionDecl>(D);
+ if (FD && FD->getName() == "f")
+ break;
+ }
+ assert(FD && FD->getName() == "f");
+ bool OrigFDHasBody = FD->hasBody();
+
+ // Prepare the index file and the AST file.
+ int ASTFD;
+ llvm::SmallString<256> ASTFileName;
+ ASSERT_FALSE(
+ llvm::sys::fs::createTemporaryFile("f_ast", "ast", ASTFD, ASTFileName));
+ llvm::ToolOutputFile ASTFile(ASTFileName, ASTFD);
+
+ int IndexFD;
+ llvm::SmallString<256> IndexFileName;
+ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
+ IndexFileName));
+ llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
+ IndexFile.os() << "c:@F@f#I# " << ASTFileName << "\n";
+ IndexFile.os().flush();
+ EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
+
+ StringRef SourceText = "int f(int) { return 0; }\n";
+ // This file must exist since the saved ASTFile will reference it.
+ int SourceFD;
+ llvm::SmallString<256> SourceFileName;
+ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("input", "cpp", SourceFD,
+ SourceFileName));
+ llvm::ToolOutputFile SourceFile(SourceFileName, SourceFD);
+ SourceFile.os() << SourceText;
+ SourceFile.os().flush();
+ EXPECT_TRUE(llvm::sys::fs::exists(SourceFileName));
+
+ std::unique_ptr<ASTUnit> ASTWithDefinition =
+ tooling::buildASTFromCode(SourceText, SourceFileName);
+ ASTWithDefinition->Save(ASTFileName.str());
+ EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName));
+
+ // Load the definition from the AST file.
+ llvm::Expected<const FunctionDecl *> NewFDorError =
+ CTU.getCrossTUDefinition(FD, "", IndexFileName);
+ EXPECT_TRUE((bool)NewFDorError);
+ const FunctionDecl *NewFD = *NewFDorError;
+
+ *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody;
+ }
+
+private:
+ CrossTranslationUnitContext CTU;
+ bool *Success;
+};
+
+class CTUAction : public clang::ASTFrontendAction {
+public:
+ CTUAction(bool *Success) : Success(Success) {}
+
+protected:
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override {
+ return llvm::make_unique<CTUASTConsumer>(CI, Success);
+ }
+
+private:
+ bool *Success;
+};
+
+} // end namespace
+
+TEST(CrossTranslationUnit, CanLoadFunctionDefinition) {
+ bool Success = false;
+ EXPECT_TRUE(tooling::runToolOnCode(new CTUAction(&Success), "int f(int);"));
+ EXPECT_TRUE(Success);
+}
+
+TEST(CrossTranslationUnit, IndexFormatCanBeParsed) {
+ llvm::StringMap<std::string> Index;
+ Index["a"] = "/b/f1";
+ Index["c"] = "/d/f2";
+ Index["e"] = "/f/f3";
+ std::string IndexText = createCrossTUIndexString(Index);
+
+ int IndexFD;
+ llvm::SmallString<256> IndexFileName;
+ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
+ IndexFileName));
+ llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
+ IndexFile.os() << IndexText;
+ IndexFile.os().flush();
+ EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
+ llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
+ parseCrossTUIndex(IndexFileName, "");
+ EXPECT_TRUE((bool)IndexOrErr);
+ llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get();
+ for (const auto &E : Index) {
+ EXPECT_TRUE(ParsedIndex.count(E.getKey()));
+ EXPECT_EQ(ParsedIndex[E.getKey()], E.getValue());
+ }
+ for (const auto &E : ParsedIndex)
+ EXPECT_TRUE(Index.count(E.getKey()));
+}
+
+TEST(CrossTranslationUnit, CTUDirIsHandledCorrectly) {
+ llvm::StringMap<std::string> Index;
+ Index["a"] = "/b/c/d";
+ std::string IndexText = createCrossTUIndexString(Index);
+
+ int IndexFD;
+ llvm::SmallString<256> IndexFileName;
+ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
+ IndexFileName));
+ llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
+ IndexFile.os() << IndexText;
+ IndexFile.os().flush();
+ EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
+ llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
+ parseCrossTUIndex(IndexFileName, "/ctudir");
+ EXPECT_TRUE((bool)IndexOrErr);
+ llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get();
+ EXPECT_EQ(ParsedIndex["a"], "/ctudir/b/c/d");
+}
+
+} // end namespace cross_tu
+} // end namespace clang
diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt
index a4f75d26f6..2a3f41d63b 100644
--- a/unittests/Driver/CMakeLists.txt
+++ b/unittests/Driver/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
Support
Option
)
diff --git a/unittests/Driver/ToolChainTest.cpp b/unittests/Driver/ToolChainTest.cpp
index f7ba3eeab2..93cf12b3c2 100644
--- a/unittests/Driver/ToolChainTest.cpp
+++ b/unittests/Driver/ToolChainTest.cpp
@@ -18,6 +18,8 @@
#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
using namespace clang;
@@ -60,6 +62,7 @@ TEST(ToolChainTest, VFSGCCInstallation) {
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
{"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
+ EXPECT_TRUE(C);
std::string S;
{
@@ -99,6 +102,7 @@ TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
{"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
+ EXPECT_TRUE(C);
std::string S;
{
@@ -128,18 +132,132 @@ TEST(ToolChainTest, DefaultDriverMode) {
Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
InMemoryFileSystem);
+ CCDriver.setCheckInputsExist(false);
Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
InMemoryFileSystem);
+ CXXDriver.setCheckInputsExist(false);
Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
InMemoryFileSystem);
+ CLDriver.setCheckInputsExist(false);
- std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation({"foo.cpp"}));
- std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation({"foo.cpp"}));
- std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation({"foo.cpp"}));
+ std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation(
+ { "/home/test/bin/clang", "foo.cpp"}));
+ std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation(
+ { "/home/test/bin/clang++", "foo.cpp"}));
+ std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation(
+ { "/home/test/bin/clang-cl", "foo.cpp"}));
+ EXPECT_TRUE(CC);
+ EXPECT_TRUE(CXX);
+ EXPECT_TRUE(CL);
EXPECT_TRUE(CCDriver.CCCIsCC());
EXPECT_TRUE(CXXDriver.CCCIsCXX());
EXPECT_TRUE(CLDriver.IsCLMode());
}
+TEST(ToolChainTest, InvalidArgument) {
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ struct TestDiagnosticConsumer : public DiagnosticConsumer {};
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+ Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
+ {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
+ EXPECT_TRUE(C);
+ EXPECT_TRUE(C->containsError());
+}
+
+TEST(ToolChainTest, ParsedClangName) {
+ ParsedClangName Empty;
+ EXPECT_TRUE(Empty.TargetPrefix.empty());
+ EXPECT_TRUE(Empty.ModeSuffix.empty());
+ EXPECT_TRUE(Empty.DriverMode == nullptr);
+ EXPECT_FALSE(Empty.TargetIsValid);
+
+ ParsedClangName DriverOnly("clang", nullptr);
+ EXPECT_TRUE(DriverOnly.TargetPrefix.empty());
+ EXPECT_TRUE(DriverOnly.ModeSuffix == "clang");
+ EXPECT_TRUE(DriverOnly.DriverMode == nullptr);
+ EXPECT_FALSE(DriverOnly.TargetIsValid);
+
+ ParsedClangName DriverOnly2("clang++", "--driver-mode=g++");
+ EXPECT_TRUE(DriverOnly2.TargetPrefix.empty());
+ EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++");
+ EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(DriverOnly2.TargetIsValid);
+
+ ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true);
+ EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386");
+ EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++");
+ EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(TargetAndMode.TargetIsValid);
+}
-} // end anonymous namespace
+TEST(ToolChainTest, GetTargetAndMode) {
+ llvm::InitializeAllTargets();
+ std::string IgnoredError;
+ if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError))
+ return;
+
+ ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang");
+ EXPECT_TRUE(Res.DriverMode == nullptr);
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("clang++");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("clang++-release");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++");
+ EXPECT_TRUE(Res.TargetPrefix == "x86_64");
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName(
+ "x86_64-linux-gnu-clang-c++");
+ EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
+ EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName(
+ "x86_64-linux-gnu-clang-c++-tot");
+ EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
+ EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("qqq");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix.empty());
+ EXPECT_TRUE(Res.DriverMode == nullptr);
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix.empty());
+ EXPECT_TRUE(Res.DriverMode == nullptr);
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl");
+ EXPECT_TRUE(Res.TargetPrefix == "qqq");
+ EXPECT_TRUE(Res.ModeSuffix == "clang-cl");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl");
+ EXPECT_FALSE(Res.TargetIsValid);
+}
+} // end anonymous namespace.
diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt
index 507d643ba1..992db0e508 100644
--- a/unittests/Format/CMakeLists.txt
+++ b/unittests/Format/CMakeLists.txt
@@ -10,10 +10,13 @@ add_clang_unittest(FormatTests
FormatTestJava.cpp
FormatTestObjC.cpp
FormatTestProto.cpp
+ FormatTestRawStrings.cpp
FormatTestSelective.cpp
+ FormatTestTextProto.cpp
NamespaceEndCommentsFixerTest.cpp
SortImportsTestJS.cpp
SortIncludesTest.cpp
+ UsingDeclarationsSorterTest.cpp
)
target_link_libraries(FormatTests
diff --git a/unittests/Format/CleanupTest.cpp b/unittests/Format/CleanupTest.cpp
index 6ac5f695d4..708fdf8968 100644
--- a/unittests/Format/CleanupTest.cpp
+++ b/unittests/Format/CleanupTest.cpp
@@ -36,11 +36,12 @@ protected:
// Returns code after cleanup around \p Offsets.
std::string cleanupAroundOffsets(llvm::ArrayRef<unsigned> Offsets,
- llvm::StringRef Code) {
+ llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle()) {
std::vector<tooling::Range> Ranges;
for (auto Offset : Offsets)
Ranges.push_back(tooling::Range(Offset, 0));
- return cleanup(Code, Ranges);
+ return cleanup(Code, Ranges, Style);
}
};
@@ -171,6 +172,14 @@ TEST_F(CleanupTest, ListRedundantComma) {
EXPECT_EQ(Expected, cleanupAroundOffsets({17, 22}, Code));
}
+TEST_F(CleanupTest, NoCleanupsForJavaScript) {
+ std::string Code = "function f() { var x = [a, b, , c]; }";
+ std::string Expected = "function f() { var x = [a, b, , c]; }";
+ const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript);
+
+ EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code, Style));
+}
+
TEST_F(CleanupTest, TrailingCommaInParens) {
std::string Code = "int main() { f(,1,,2,3,f(1,2,),4,,);}";
std::string Expected = "int main() { f(1,2,3,f(1,2),4);}";
@@ -292,7 +301,7 @@ protected:
}
inline std::string apply(StringRef Code,
- const tooling::Replacements Replaces) {
+ const tooling::Replacements &Replaces) {
auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
EXPECT_TRUE(static_cast<bool>(CleanReplaces))
<< llvm::toString(CleanReplaces.takeError()) << "\n";
@@ -302,8 +311,7 @@ protected:
}
inline std::string formatAndApply(StringRef Code,
- const tooling::Replacements Replaces) {
-
+ const tooling::Replacements &Replaces) {
auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
EXPECT_TRUE(static_cast<bool>(CleanReplaces))
<< llvm::toString(CleanReplaces.takeError()) << "\n";
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index bcbdbbf3e5..82530c0376 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -30,24 +30,25 @@ FormatStyle getGoogleStyle() { return getGoogleStyle(FormatStyle::LK_Cpp); }
class FormatTest : public ::testing::Test {
protected:
- enum IncompleteCheck {
- IC_ExpectComplete,
- IC_ExpectIncomplete,
- IC_DoNotCheck
+ enum StatusCheck {
+ SC_ExpectComplete,
+ SC_ExpectIncomplete,
+ SC_DoNotCheck
};
std::string format(llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle(),
- IncompleteCheck CheckIncomplete = IC_ExpectComplete) {
+ StatusCheck CheckComplete = SC_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;
+ FormattingAttemptStatus Status;
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";
+ reformat(Style, Code, Ranges, "<stdin>", &Status);
+ if (CheckComplete != SC_DoNotCheck) {
+ bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
+ EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
+ << Code << "\n\n";
}
ReplacementCount = Replaces.size();
auto Result = applyAllReplacements(Code, Replaces);
@@ -56,16 +57,17 @@ protected:
return *Result;
}
- FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
- FormatStyle Style = getLLVMStyle();
+ FormatStyle getStyleWithColumns(FormatStyle Style, unsigned ColumnLimit) {
Style.ColumnLimit = ColumnLimit;
return Style;
}
+ FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
+ return getStyleWithColumns(getLLVMStyle(), ColumnLimit);
+ }
+
FormatStyle getGoogleStyleWithColumns(unsigned ColumnLimit) {
- FormatStyle Style = getGoogleStyle();
- Style.ColumnLimit = ColumnLimit;
- return Style;
+ return getStyleWithColumns(getGoogleStyle(), ColumnLimit);
}
void verifyFormat(llvm::StringRef Code,
@@ -83,7 +85,7 @@ protected:
void verifyIncompleteFormat(llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle()) {
EXPECT_EQ(Code.str(),
- format(test::messUp(Code), Style, IC_ExpectIncomplete));
+ format(test::messUp(Code), Style, SC_ExpectIncomplete));
}
void verifyGoogleFormat(llvm::StringRef Code) {
@@ -98,7 +100,7 @@ protected:
/// \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);
+ format(Code, Style, SC_DoNotCheck);
}
int ReplacementCount;
@@ -331,6 +333,16 @@ TEST_F(FormatTest, RecognizesBinaryOperatorKeywords) {
verifyFormat("x = (a) xor (b);");
}
+TEST_F(FormatTest, RecognizesUnaryOperatorKeywords) {
+ verifyFormat("x = compl(a);");
+ verifyFormat("x = not(a);");
+ verifyFormat("x = bitand(a);");
+ // Unary operator must not be merged with the next identifier
+ verifyFormat("x = compl a;");
+ verifyFormat("x = not a;");
+ verifyFormat("x = bitand a;");
+}
+
//===----------------------------------------------------------------------===//
// Tests for control statements.
//===----------------------------------------------------------------------===//
@@ -339,9 +351,21 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatement) {
verifyFormat("if (true)\n f();\ng();");
verifyFormat("if (a)\n if (b)\n if (c)\n g();\nh();");
verifyFormat("if (a)\n if (b) {\n f();\n }\ng();");
+ verifyFormat("if constexpr (true)\n"
+ " f();\ng();");
+ verifyFormat("if constexpr (a)\n"
+ " if constexpr (b)\n"
+ " if constexpr (c)\n"
+ " g();\n"
+ "h();");
+ verifyFormat("if constexpr (a)\n"
+ " if constexpr (b) {\n"
+ " f();\n"
+ " }\n"
+ "g();");
FormatStyle AllowsMergedIf = getLLVMStyle();
- AllowsMergedIf.AlignEscapedNewlinesLeft = true;
+ AllowsMergedIf.AlignEscapedNewlines = FormatStyle::ENAS_Left;
AllowsMergedIf.AllowShortIfStatementsOnASingleLine = true;
verifyFormat("if (a)\n"
" // comment\n"
@@ -415,17 +439,28 @@ TEST_F(FormatTest, FormatLoopsWithoutCompoundStatement) {
TEST_F(FormatTest, FormatShortBracedStatements) {
FormatStyle AllowSimpleBracedStatements = getLLVMStyle();
+ AllowSimpleBracedStatements.ColumnLimit = 40;
AllowSimpleBracedStatements.AllowShortBlocksOnASingleLine = true;
AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = true;
AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = true;
+ AllowSimpleBracedStatements.BreakBeforeBraces = FormatStyle::BS_Custom;
+ AllowSimpleBracedStatements.BraceWrapping.AfterFunction = true;
+ AllowSimpleBracedStatements.BraceWrapping.SplitEmptyRecord = false;
+
verifyFormat("if (true) {}", AllowSimpleBracedStatements);
+ verifyFormat("if constexpr (true) {}", AllowSimpleBracedStatements);
verifyFormat("while (true) {}", AllowSimpleBracedStatements);
verifyFormat("for (;;) {}", AllowSimpleBracedStatements);
verifyFormat("if (true) { f(); }", AllowSimpleBracedStatements);
+ verifyFormat("if constexpr (true) { f(); }", AllowSimpleBracedStatements);
verifyFormat("while (true) { f(); }", AllowSimpleBracedStatements);
verifyFormat("for (;;) { f(); }", AllowSimpleBracedStatements);
+ verifyFormat("if (true) {\n"
+ " ffffffffffffffffffffffffffffffffffffffffffffffffffffff();\n"
+ "}",
+ AllowSimpleBracedStatements);
verifyFormat("if (true) { //\n"
" f();\n"
"}",
@@ -442,12 +477,21 @@ TEST_F(FormatTest, FormatShortBracedStatements) {
"}",
AllowSimpleBracedStatements);
+ verifyFormat("struct A2 {\n"
+ " int X;\n"
+ "};",
+ AllowSimpleBracedStatements);
+ verifyFormat("typedef struct A2 {\n"
+ " int X;\n"
+ "} A2_t;",
+ AllowSimpleBracedStatements);
verifyFormat("template <int> struct A2 {\n"
" struct B {};\n"
"};",
AllowSimpleBracedStatements);
AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = false;
+ verifyFormat("if (true) {}", AllowSimpleBracedStatements);
verifyFormat("if (true) {\n"
" f();\n"
"}",
@@ -460,14 +504,83 @@ TEST_F(FormatTest, FormatShortBracedStatements) {
AllowSimpleBracedStatements);
AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = false;
+ verifyFormat("while (true) {}", AllowSimpleBracedStatements);
verifyFormat("while (true) {\n"
" f();\n"
"}",
AllowSimpleBracedStatements);
+ verifyFormat("for (;;) {}", AllowSimpleBracedStatements);
verifyFormat("for (;;) {\n"
" f();\n"
"}",
AllowSimpleBracedStatements);
+
+ AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = true;
+ AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = true;
+ AllowSimpleBracedStatements.BraceWrapping.AfterControlStatement = true;
+
+ verifyFormat("if (true) {}", AllowSimpleBracedStatements);
+ verifyFormat("if constexpr (true) {}", AllowSimpleBracedStatements);
+ verifyFormat("while (true) {}", AllowSimpleBracedStatements);
+ verifyFormat("for (;;) {}", AllowSimpleBracedStatements);
+ verifyFormat("if (true) { f(); }", AllowSimpleBracedStatements);
+ verifyFormat("if constexpr (true) { f(); }", AllowSimpleBracedStatements);
+ verifyFormat("while (true) { f(); }", AllowSimpleBracedStatements);
+ verifyFormat("for (;;) { f(); }", AllowSimpleBracedStatements);
+ verifyFormat("if (true)\n"
+ "{\n"
+ " ffffffffffffffffffffffffffffffffffffffffffffffffffffff();\n"
+ "}",
+ AllowSimpleBracedStatements);
+ verifyFormat("if (true)\n"
+ "{ //\n"
+ " f();\n"
+ "}",
+ AllowSimpleBracedStatements);
+ verifyFormat("if (true)\n"
+ "{\n"
+ " f();\n"
+ " f();\n"
+ "}",
+ AllowSimpleBracedStatements);
+ verifyFormat("if (true)\n"
+ "{\n"
+ " f();\n"
+ "} else\n"
+ "{\n"
+ " f();\n"
+ "}",
+ AllowSimpleBracedStatements);
+
+ AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = false;
+ verifyFormat("if (true) {}", AllowSimpleBracedStatements);
+ verifyFormat("if (true)\n"
+ "{\n"
+ " f();\n"
+ "}",
+ AllowSimpleBracedStatements);
+ verifyFormat("if (true)\n"
+ "{\n"
+ " f();\n"
+ "} else\n"
+ "{\n"
+ " f();\n"
+ "}",
+ AllowSimpleBracedStatements);
+
+ AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = false;
+ verifyFormat("while (true) {}", AllowSimpleBracedStatements);
+ verifyFormat("while (true)\n"
+ "{\n"
+ " f();\n"
+ "}",
+ AllowSimpleBracedStatements);
+ verifyFormat("for (;;) {}", AllowSimpleBracedStatements);
+ verifyFormat("for (;;)\n"
+ "{\n"
+ " f();\n"
+ "}",
+ AllowSimpleBracedStatements);
}
TEST_F(FormatTest, ParseIfElse) {
@@ -494,6 +607,19 @@ TEST_F(FormatTest, ParseIfElse) {
"else {\n"
" i();\n"
"}");
+ verifyFormat("if (true)\n"
+ " if constexpr (true)\n"
+ " if (true) {\n"
+ " if constexpr (true)\n"
+ " f();\n"
+ " } else {\n"
+ " g();\n"
+ " }\n"
+ " else\n"
+ " h();\n"
+ "else {\n"
+ " i();\n"
+ "}");
verifyFormat("void f() {\n"
" if (a) {\n"
" } else {\n"
@@ -509,6 +635,12 @@ TEST_F(FormatTest, ElseIf) {
" g();\n"
"else\n"
" h();");
+ verifyFormat("if constexpr (a)\n"
+ " f();\n"
+ "else if constexpr (b)\n"
+ " g();\n"
+ "else\n"
+ " h();");
verifyFormat("if (a) {\n"
" f();\n"
"}\n"
@@ -526,6 +658,11 @@ TEST_F(FormatTest, ElseIf) {
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
"}",
getLLVMStyleWithColumns(62));
+ verifyFormat("if (a) {\n"
+ "} else if constexpr (\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
+ "}",
+ getLLVMStyleWithColumns(62));
}
TEST_F(FormatTest, FormatsForLoop) {
@@ -599,6 +736,10 @@ TEST_F(FormatTest, FormatsForLoop) {
" I != E;\n"
" ++I) {\n}",
NoBinPacking);
+
+ FormatStyle AlignLeft = getLLVMStyle();
+ AlignLeft.PointerAlignment = FormatStyle::PAS_Left;
+ verifyFormat("for (A* a = start; a < end; ++a, ++value) {\n}", AlignLeft);
}
TEST_F(FormatTest, RangeBasedForLoops) {
@@ -777,12 +918,35 @@ TEST_F(FormatTest, FormatsSwitchStatement) {
" case A:\n"
" f();\n"
" break;\n"
- " // On B:\n"
+ " // fallthrough\n"
" case B:\n"
" g();\n"
" break;\n"
" }\n"
"});");
+ EXPECT_EQ("DEBUG({\n"
+ " switch (x) {\n"
+ " case A:\n"
+ " f();\n"
+ " break;\n"
+ " // On B:\n"
+ " case B:\n"
+ " g();\n"
+ " break;\n"
+ " }\n"
+ "});",
+ format("DEBUG({\n"
+ " switch (x) {\n"
+ " case A:\n"
+ " f();\n"
+ " break;\n"
+ " // On B:\n"
+ " case B:\n"
+ " g();\n"
+ " break;\n"
+ " }\n"
+ "});",
+ getLLVMStyle()));
verifyFormat("switch (a) {\n"
"case (b):\n"
" return;\n"
@@ -826,6 +990,77 @@ TEST_F(FormatTest, ShortCaseLabels) {
"}",
Style);
verifyFormat("switch (a) {\n"
+ "case 0: return; // comment\n"
+ "case 1: break; // comment\n"
+ "case 2: return;\n"
+ "// comment\n"
+ "case 3: return;\n"
+ "// comment 1\n"
+ "// comment 2\n"
+ "// comment 3\n"
+ "case 4: break; /* comment */\n"
+ "case 5:\n"
+ " // comment\n"
+ " break;\n"
+ "case 6: /* comment */ x = 1; break;\n"
+ "case 7: x = /* comment */ 1; break;\n"
+ "case 8:\n"
+ " x = 1; /* comment */\n"
+ " break;\n"
+ "case 9:\n"
+ " break; // comment line 1\n"
+ " // comment line 2\n"
+ "}",
+ Style);
+ EXPECT_EQ("switch (a) {\n"
+ "case 1:\n"
+ " x = 8;\n"
+ " // fall through\n"
+ "case 2: x = 8;\n"
+ "// comment\n"
+ "case 3:\n"
+ " return; /* comment line 1\n"
+ " * comment line 2 */\n"
+ "case 4: i = 8;\n"
+ "// something else\n"
+ "#if FOO\n"
+ "case 5: break;\n"
+ "#endif\n"
+ "}",
+ format("switch (a) {\n"
+ "case 1: x = 8;\n"
+ " // fall through\n"
+ "case 2:\n"
+ " x = 8;\n"
+ "// comment\n"
+ "case 3:\n"
+ " return; /* comment line 1\n"
+ " * comment line 2 */\n"
+ "case 4:\n"
+ " i = 8;\n"
+ "// something else\n"
+ "#if FOO\n"
+ "case 5: break;\n"
+ "#endif\n"
+ "}",
+ Style));
+ EXPECT_EQ("switch (a) {\n" "case 0:\n"
+ " return; // long long long long long long long long long long long long comment\n"
+ " // line\n" "}",
+ format("switch (a) {\n"
+ "case 0: return; // long long long long long long long long long long long long comment line\n"
+ "}",
+ Style));
+ EXPECT_EQ("switch (a) {\n"
+ "case 0:\n"
+ " return; /* long long long long long long long long long long long long comment\n"
+ " line */\n"
+ "}",
+ format("switch (a) {\n"
+ "case 0: return; /* long long long long long long long long long long long long comment line */\n"
+ "}",
+ Style));
+ verifyFormat("switch (a) {\n"
"#if FOO\n"
"case 0: return 0;\n"
"#endif\n"
@@ -1172,6 +1407,32 @@ TEST_F(FormatTest, FormatsEnumTypes) {
verifyFormat("enum X : std::uint32_t { A, B };");
}
+TEST_F(FormatTest, FormatsTypedefEnum) {
+ FormatStyle Style = getLLVMStyle();
+ Style.ColumnLimit = 40;
+ verifyFormat("typedef enum {} EmptyEnum;");
+ verifyFormat("typedef enum { A, B, C } ShortEnum;");
+ verifyFormat("typedef enum {\n"
+ " ZERO = 0,\n"
+ " ONE = 1,\n"
+ " TWO = 2,\n"
+ " THREE = 3\n"
+ "} LongEnum;",
+ Style);
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterEnum = true;
+ verifyFormat("typedef enum {} EmptyEnum;");
+ verifyFormat("typedef enum { A, B, C } ShortEnum;");
+ verifyFormat("typedef enum\n"
+ "{\n"
+ " ZERO = 0,\n"
+ " ONE = 1,\n"
+ " TWO = 2,\n"
+ " THREE = 3\n"
+ "} LongEnum;",
+ Style);
+}
+
TEST_F(FormatTest, FormatsNSEnums) {
verifyGoogleFormat("typedef NS_ENUM(NSInteger, SomeName) { AAA, BBB }");
verifyGoogleFormat("typedef NS_ENUM(NSInteger, MyType) {\n"
@@ -1308,7 +1569,177 @@ TEST_F(FormatTest, FormatsNamespaces) {
Style));
}
-TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); }
+TEST_F(FormatTest, FormatsCompactNamespaces) {
+ FormatStyle Style = getLLVMStyle();
+ Style.CompactNamespaces = true;
+
+ verifyFormat("namespace A { namespace B {\n"
+ "}} // namespace A::B",
+ Style);
+
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ Style));
+
+ // Only namespaces which have both consecutive opening and end get compacted
+ EXPECT_EQ("namespace out {\n"
+ "namespace in1 {\n"
+ "} // namespace in1\n"
+ "namespace in2 {\n"
+ "} // namespace in2\n"
+ "} // namespace out",
+ format("namespace out {\n"
+ "namespace in1 {\n"
+ "} // namespace in1\n"
+ "namespace in2 {\n"
+ "} // namespace in2\n"
+ "} // namespace out",
+ Style));
+
+ EXPECT_EQ("namespace out {\n"
+ "int i;\n"
+ "namespace in {\n"
+ "int j;\n"
+ "} // namespace in\n"
+ "int k;\n"
+ "} // namespace out",
+ format("namespace out { int i;\n"
+ "namespace in { int j; } // namespace in\n"
+ "int k; } // namespace out",
+ Style));
+
+ EXPECT_EQ("namespace A { namespace B { namespace C {\n"
+ "}}} // namespace A::B::C\n",
+ format("namespace A { namespace B {\n"
+ "namespace C {\n"
+ "}} // namespace B::C\n"
+ "} // namespace A\n",
+ Style));
+
+ Style.ColumnLimit = 40;
+ EXPECT_EQ("namespace aaaaaaaaaa {\n"
+ "namespace bbbbbbbbbb {\n"
+ "}} // namespace aaaaaaaaaa::bbbbbbbbbb",
+ format("namespace aaaaaaaaaa {\n"
+ "namespace bbbbbbbbbb {\n"
+ "} // namespace bbbbbbbbbb\n"
+ "} // namespace aaaaaaaaaa",
+ Style));
+
+ EXPECT_EQ("namespace aaaaaa { namespace bbbbbb {\n"
+ "namespace cccccc {\n"
+ "}}} // namespace aaaaaa::bbbbbb::cccccc",
+ format("namespace aaaaaa {\n"
+ "namespace bbbbbb {\n"
+ "namespace cccccc {\n"
+ "} // namespace cccccc\n"
+ "} // namespace bbbbbb\n"
+ "} // namespace aaaaaa",
+ Style));
+ Style.ColumnLimit = 80;
+
+ // Extra semicolon after 'inner' closing brace prevents merging
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}; } // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "}; // namespace in\n"
+ "} // namespace out",
+ Style));
+
+ // Extra semicolon after 'outer' closing brace is conserved
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}}; // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "}; // namespace out",
+ Style));
+
+ Style.NamespaceIndentation = FormatStyle::NI_All;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ " int i;\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ Style));
+ EXPECT_EQ("namespace out { namespace mid {\n"
+ " namespace in {\n"
+ " int j;\n"
+ " } // namespace in\n"
+ " int k;\n"
+ "}} // namespace out::mid",
+ format("namespace out { namespace mid {\n"
+ "namespace in { int j; } // namespace in\n"
+ "int k; }} // namespace out::mid",
+ Style));
+
+ Style.NamespaceIndentation = FormatStyle::NI_Inner;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ " int i;\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ Style));
+ EXPECT_EQ("namespace out { namespace mid { namespace in {\n"
+ " int i;\n"
+ "}}} // namespace out::mid::in",
+ format("namespace out {\n"
+ "namespace mid {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "} // namespace in\n"
+ "} // namespace mid\n"
+ "} // namespace out",
+ Style));
+}
+
+TEST_F(FormatTest, FormatsExternC) {
+ verifyFormat("extern \"C\" {\nint a;");
+ verifyFormat("extern \"C\" {}");
+ verifyFormat("extern \"C\" {\n"
+ "int foo();\n"
+ "}");
+ verifyFormat("extern \"C\" int foo() {}");
+ verifyFormat("extern \"C\" int foo();");
+ verifyFormat("extern \"C\" int foo() {\n"
+ " int i = 42;\n"
+ " return i;\n"
+ "}");
+
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterFunction = true;
+ verifyFormat("extern \"C\" int foo() {}", Style);
+ verifyFormat("extern \"C\" int foo();", Style);
+ verifyFormat("extern \"C\" int foo()\n"
+ "{\n"
+ " int i = 42;\n"
+ " return i;\n"
+ "}",
+ Style);
+
+ Style.BraceWrapping.AfterExternBlock = true;
+ Style.BraceWrapping.SplitEmptyRecord = false;
+ verifyFormat("extern \"C\"\n"
+ "{}",
+ Style);
+ verifyFormat("extern \"C\"\n"
+ "{\n"
+ " int foo();\n"
+ "}",
+ Style);
+}
TEST_F(FormatTest, FormatsInlineASM) {
verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));");
@@ -1521,6 +1952,19 @@ TEST_F(FormatTest, DesignatedInitializers) {
" .eeeeeeeeeeeeeeeeeeeeeeeeeee = 5};");
verifyGoogleFormat("const struct A a = {.a = 1, .b = 2};");
+
+ verifyFormat("const struct A a = {[0] = 1, [1] = 2};");
+ verifyFormat("const struct A a = {[1] = aaaaaaaaaa,\n"
+ " [2] = bbbbbbbbbb,\n"
+ " [3] = cccccccccc,\n"
+ " [4] = dddddddddd,\n"
+ " [5] = eeeeeeeeee};");
+ verifyFormat("const struct Aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaa = {\n"
+ " [1] = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " [2] = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " [3] = cccccccccccccccccccccccccccccccccccccc,\n"
+ " [4] = dddddddddddddddddddddddddddddddddddddd,\n"
+ " [5] = eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee};");
}
TEST_F(FormatTest, NestedStaticInitializers) {
@@ -1986,8 +2430,191 @@ TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) {
getLLVMStyleWithColumns(11));
}
-TEST_F(FormatTest, IndentPreprocessorDirectivesAtZero) {
- EXPECT_EQ("{\n {\n#define A\n }\n}", format("{{\n#define A\n}}"));
+TEST_F(FormatTest, IndentPreprocessorDirectives) {
+ FormatStyle Style = getLLVMStyle();
+ Style.IndentPPDirectives = FormatStyle::PPDIS_None;
+ Style.ColumnLimit = 40;
+ verifyFormat("#ifdef _WIN32\n"
+ "#define A 0\n"
+ "#ifdef VAR2\n"
+ "#define B 1\n"
+ "#include <someheader.h>\n"
+ "#define MACRO \\\n"
+ " some_very_long_func_aaaaaaaaaa();\n"
+ "#endif\n"
+ "#else\n"
+ "#define A 1\n"
+ "#endif",
+ Style);
+ Style.IndentPPDirectives = FormatStyle::PPDIS_AfterHash;
+ verifyFormat("#ifdef _WIN32\n"
+ "# define A 0\n"
+ "# ifdef VAR2\n"
+ "# define B 1\n"
+ "# include <someheader.h>\n"
+ "# define MACRO \\\n"
+ " some_very_long_func_aaaaaaaaaa();\n"
+ "# endif\n"
+ "#else\n"
+ "# define A 1\n"
+ "#endif",
+ Style);
+ verifyFormat("#if A\n"
+ "# define MACRO \\\n"
+ " void a(int x) { \\\n"
+ " b(); \\\n"
+ " c(); \\\n"
+ " d(); \\\n"
+ " e(); \\\n"
+ " f(); \\\n"
+ " }\n"
+ "#endif",
+ Style);
+ // Comments before include guard.
+ verifyFormat("// file comment\n"
+ "// file comment\n"
+ "#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style);
+ // Test with include guards.
+ // EXPECT_EQ is used because verifyFormat() calls messUp() which incorrectly
+ // merges lines.
+ verifyFormat("#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style);
+ // Include guards must have a #define with the same variable immediately
+ // after #ifndef.
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define FOO\n"
+ "code();\n"
+ "#endif",
+ Style);
+
+ // Include guards must cover the entire file.
+ verifyFormat("code();\n"
+ "code();\n"
+ "#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#endif",
+ Style);
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#endif\n"
+ "code();",
+ Style);
+ // Test with trailing blank lines.
+ verifyFormat("#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif\n",
+ Style);
+ // Include guards don't have #else.
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#else\n"
+ "#endif",
+ Style);
+ verifyFormat("#ifndef NOT_GUARD\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#elif FOO\n"
+ "#endif",
+ Style);
+ // FIXME: This doesn't handle the case where there's code between the
+ // #ifndef and #define but all other conditions hold. This is because when
+ // the #define line is parsed, UnwrappedLineParser::Lines doesn't hold the
+ // previous code line yet, so we can't detect it.
+ EXPECT_EQ("#ifndef NOT_GUARD\n"
+ "code();\n"
+ "#define NOT_GUARD\n"
+ "code();\n"
+ "#endif",
+ format("#ifndef NOT_GUARD\n"
+ "code();\n"
+ "# define NOT_GUARD\n"
+ "code();\n"
+ "#endif",
+ Style));
+ // FIXME: This doesn't handle cases where legitimate preprocessor lines may
+ // be outside an include guard. Examples are #pragma once and
+ // #pragma GCC diagnostic, or anything else that does not change the meaning
+ // of the file if it's included multiple times.
+ EXPECT_EQ("#ifdef WIN32\n"
+ "# pragma once\n"
+ "#endif\n"
+ "#ifndef HEADER_H\n"
+ "# define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ format("#ifdef WIN32\n"
+ "# pragma once\n"
+ "#endif\n"
+ "#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style));
+ // FIXME: This does not detect when there is a single non-preprocessor line
+ // in front of an include-guard-like structure where other conditions hold
+ // because ScopedLineState hides the line.
+ EXPECT_EQ("code();\n"
+ "#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ format("code();\n"
+ "#ifndef HEADER_H\n"
+ "# define HEADER_H\n"
+ "code();\n"
+ "#endif",
+ Style));
+ // FIXME: The comment indent corrector in TokenAnnotator gets thrown off by
+ // preprocessor indentation.
+ EXPECT_EQ("#if 1\n"
+ " // comment\n"
+ "# define A 0\n"
+ "// comment\n"
+ "# define B 0\n"
+ "#endif",
+ format("#if 1\n"
+ "// comment\n"
+ "# define A 0\n"
+ " // comment\n"
+ "# define B 0\n"
+ "#endif",
+ Style));
+ // Test with tabs.
+ Style.UseTab = FormatStyle::UT_Always;
+ Style.IndentWidth = 8;
+ Style.TabWidth = 8;
+ verifyFormat("#ifdef _WIN32\n"
+ "#\tdefine A 0\n"
+ "#\tifdef VAR2\n"
+ "#\t\tdefine B 1\n"
+ "#\t\tinclude <someheader.h>\n"
+ "#\t\tdefine MACRO \\\n"
+ "\t\t\tsome_very_long_func_aaaaaaaaaa();\n"
+ "#\tendif\n"
+ "#else\n"
+ "#\tdefine A 1\n"
+ "#endif",
+ Style);
+
+ // Regression test: Multiline-macro inside include guards.
+ verifyFormat("#ifndef HEADER_H\n"
+ "#define HEADER_H\n"
+ "#define A() \\\n"
+ " int i; \\\n"
+ " int j;\n"
+ "#endif // HEADER_H",
+ getLLVMStyleWithColumns(20));
}
TEST_F(FormatTest, FormatHashIfNotAtStartOfLine) {
@@ -2002,13 +2629,63 @@ TEST_F(FormatTest, FormatUnbalancedStructuralElements) {
}
TEST_F(FormatTest, EscapedNewlines) {
- EXPECT_EQ(
- "#define A \\\n int i; \\\n int j;",
- format("#define A \\\nint i;\\\n int j;", getLLVMStyleWithColumns(11)));
+ FormatStyle Narrow = getLLVMStyleWithColumns(11);
+ EXPECT_EQ("#define A \\\n int i; \\\n int j;",
+ format("#define A \\\nint i;\\\n int j;", Narrow));
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("<a\n\\\\\n>", format("<a\n\\\\\n>"));
+
+ FormatStyle AlignLeft = getLLVMStyle();
+ AlignLeft.AlignEscapedNewlines = FormatStyle::ENAS_Left;
+ EXPECT_EQ("#define MACRO(x) \\\n"
+ "private: \\\n"
+ " int x(int a);\n",
+ format("#define MACRO(x) \\\n"
+ "private: \\\n"
+ " int x(int a);\n",
+ AlignLeft));
+
+ // CRLF line endings
+ EXPECT_EQ("#define A \\\r\n int i; \\\r\n int j;",
+ format("#define A \\\r\nint i;\\\r\n int j;", Narrow));
+ EXPECT_EQ("#define A\r\n\r\nint i;", format("#define A \\\r\n\r\n int i;"));
+ EXPECT_EQ("template <class T> f();", format("\\\ntemplate <class T> f();"));
+ EXPECT_EQ("/* \\ \\ \\\r\n */", format("\\\r\n/* \\ \\ \\\r\n */"));
+ EXPECT_EQ("<a\r\n\\\\\r\n>", format("<a\r\n\\\\\r\n>"));
+ EXPECT_EQ("#define MACRO(x) \\\r\n"
+ "private: \\\r\n"
+ " int x(int a);\r\n",
+ format("#define MACRO(x) \\\r\n"
+ "private: \\\r\n"
+ " int x(int a);\r\n",
+ AlignLeft));
+
+ FormatStyle DontAlign = getLLVMStyle();
+ DontAlign.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
+ DontAlign.MaxEmptyLinesToKeep = 3;
+ // FIXME: can't use verifyFormat here because the newline before
+ // "public:" is not inserted the first time it's reformatted
+ EXPECT_EQ("#define A \\\n"
+ " class Foo { \\\n"
+ " void bar(); \\\n"
+ "\\\n"
+ "\\\n"
+ "\\\n"
+ " public: \\\n"
+ " void baz(); \\\n"
+ " };",
+ format("#define A \\\n"
+ " class Foo { \\\n"
+ " void bar(); \\\n"
+ "\\\n"
+ "\\\n"
+ "\\\n"
+ " public: \\\n"
+ " void baz(); \\\n"
+ " };",
+ DontAlign));
}
TEST_F(FormatTest, CalculateSpaceOnConsecutiveLinesInMacro) {
@@ -2105,7 +2782,7 @@ TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) {
verifyIncompleteFormat("void f(\n"
"#if A\n"
- " );\n"
+ ");\n"
"#else\n"
"#endif");
}
@@ -2369,6 +3046,9 @@ TEST_F(FormatTest, LineBreakingInBinaryExpressions) {
verifyFormat("if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
" bbbbbbbbbbbbbbbbbb) && // aaaaaaaaaaaaaaaa\n"
" cccccc) {\n}");
+ verifyFormat("if constexpr ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " bbbbbbbbbbbbbbbbbb) && // aaaaaaaaaaa\n"
+ " cccccc) {\n}");
verifyFormat("b = a &&\n"
" // Comment\n"
" b.c && d;");
@@ -2590,6 +3270,60 @@ TEST_F(FormatTest, BreakingBeforeNonAssigmentOperators) {
Style);
}
+TEST_F(FormatTest, AllowBinPackingInsideArguments) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
+ Style.BinPackArguments = false;
+ Style.ColumnLimit = 40;
+ verifyFormat("void test() {\n"
+ " someFunction(\n"
+ " this + argument + is + quite\n"
+ " + long + so + it + gets + wrapped\n"
+ " + but + remains + bin - packed);\n"
+ "}",
+ Style);
+ verifyFormat("void test() {\n"
+ " someFunction(arg1,\n"
+ " this + argument + is\n"
+ " + quite + long + so\n"
+ " + it + gets + wrapped\n"
+ " + but + remains + bin\n"
+ " - packed,\n"
+ " arg3);\n"
+ "}",
+ Style);
+ verifyFormat("void test() {\n"
+ " someFunction(\n"
+ " arg1,\n"
+ " this + argument + has\n"
+ " + anotherFunc(nested,\n"
+ " calls + whose\n"
+ " + arguments\n"
+ " + are + also\n"
+ " + wrapped,\n"
+ " in + addition)\n"
+ " + to + being + bin - packed,\n"
+ " arg3);\n"
+ "}",
+ Style);
+
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
+ verifyFormat("void test() {\n"
+ " someFunction(\n"
+ " arg1,\n"
+ " this + argument + has +\n"
+ " anotherFunc(nested,\n"
+ " calls + whose +\n"
+ " arguments +\n"
+ " are + also +\n"
+ " wrapped,\n"
+ " in + addition) +\n"
+ " to + being + bin - packed,\n"
+ " arg3);\n"
+ "}",
+ Style);
+}
+
TEST_F(FormatTest, ConstructorInitializers) {
verifyFormat("Constructor() : Initializer(FitsOnTheLine) {}");
verifyFormat("Constructor() : Inttializer(FitsOnTheLine) {}",
@@ -2699,6 +3433,169 @@ TEST_F(FormatTest, ConstructorInitializers) {
" aaaa(aaaa) {}"));
}
+TEST_F(FormatTest, BreakConstructorInitializersAfterColon) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
+
+ verifyFormat("Constructor() : Initializer(FitsOnTheLine) {}");
+ verifyFormat("Constructor() : Initializer(FitsOnTheLine) {}",
+ getStyleWithColumns(Style, 45));
+ verifyFormat("Constructor() :\n"
+ " Initializer(FitsOnTheLine) {}",
+ getStyleWithColumns(Style, 44));
+ verifyFormat("Constructor() :\n"
+ " Initializer(FitsOnTheLine) {}",
+ getStyleWithColumns(Style, 43));
+
+ verifyFormat("template <typename T>\n"
+ "Constructor() : Initializer(FitsOnTheLine) {}",
+ getStyleWithColumns(Style, 50));
+
+ verifyFormat(
+ "SomeClass::Constructor() :\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}",
+ Style);
+
+ verifyFormat(
+ "SomeClass::Constructor() :\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ Style);
+ verifyFormat(
+ "SomeClass::Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}",
+ Style);
+ verifyFormat("Constructor(aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) :\n"
+ " aaaaaaaaaa(aaaaaa) {}",
+ Style);
+
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaa() {}",
+ Style);
+
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ Style);
+
+ verifyFormat("Constructor(int Parameter = 0) :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaa(aaaaaaaaaaaaaaaaa) {}",
+ Style);
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbbbbb(b) {\n"
+ "}",
+ getStyleWithColumns(Style, 60));
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa(aaaa, aaaa)) {}",
+ Style);
+
+ // Here a line could be saved by splitting the second initializer onto two
+ // lines, but that is not desirable.
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaa(aaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaat(aaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ Style);
+
+ FormatStyle OnePerLine = Style;
+ OnePerLine.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ OnePerLine.AllowAllParametersOfDeclarationOnNextLine = false;
+ verifyFormat("SomeClass::Constructor() :\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ OnePerLine);
+ verifyFormat("SomeClass::Constructor() :\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), // Some comment\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ OnePerLine);
+ verifyFormat("MyClass::MyClass(int var) :\n"
+ " some_var_(var), // 4 space indent\n"
+ " some_other_var_(var + 1) { // lined up\n"
+ "}",
+ OnePerLine);
+ verifyFormat("Constructor() :\n"
+ " aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa) {}",
+ OnePerLine);
+ verifyFormat("Constructor() :\n"
+ " aaaaa(aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaa) {}",
+ OnePerLine);
+ OnePerLine.BinPackParameters = false;
+ verifyFormat(
+ "Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaa().aaa(),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ OnePerLine);
+ OnePerLine.ColumnLimit = 60;
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaa(a),\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbb(b) {}",
+ OnePerLine);
+
+ EXPECT_EQ("Constructor() :\n"
+ " // Comment forcing unwanted break.\n"
+ " aaaa(aaaa) {}",
+ format("Constructor() :\n"
+ " // Comment forcing unwanted break.\n"
+ " aaaa(aaaa) {}",
+ Style));
+
+ Style.ColumnLimit = 0;
+ verifyFormat("SomeClass::Constructor() :\n"
+ " a(a) {}",
+ Style);
+ verifyFormat("SomeClass::Constructor() noexcept :\n"
+ " a(a) {}",
+ Style);
+ verifyFormat("SomeClass::Constructor() :\n"
+ " a(a), b(b), c(c) {}",
+ Style);
+ verifyFormat("SomeClass::Constructor() :\n"
+ " a(a) {\n"
+ " foo();\n"
+ " bar();\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ verifyFormat("SomeClass::Constructor() :\n"
+ " a(a), b(b), c(c) {\n"
+ "}",
+ Style);
+ verifyFormat("SomeClass::Constructor() :\n"
+ " a(a) {\n"
+ "}",
+ Style);
+
+ Style.ColumnLimit = 80;
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ Style.ConstructorInitializerIndentWidth = 2;
+ verifyFormat("SomeClass::Constructor() : a(a), b(b), c(c) {}",
+ Style);
+ verifyFormat("SomeClass::Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}",
+ Style);
+}
+
+#ifndef EXPENSIVE_CHECKS
+// Expensive checks enables libstdc++ checking which includes validating the
+// state of ranges used in std::priority_queue - this blows out the
+// runtime/scalability of the function and makes this test unacceptably slow.
TEST_F(FormatTest, MemoizationTests) {
// This breaks if the memoization lookup does not take \c Indent and
// \c LastSpace into account.
@@ -2777,6 +3674,7 @@ TEST_F(FormatTest, MemoizationTests) {
input += " a) {}";
verifyFormat(input, OnePerLine);
}
+#endif
TEST_F(FormatTest, BreaksAsHighAsPossible) {
verifyFormat(
@@ -3402,6 +4300,18 @@ TEST_F(FormatTest, BreaksAfterAssignments) {
" 1;");
}
+TEST_F(FormatTest, ConfigurableBreakAssignmentPenalty) {
+ FormatStyle Style = getLLVMStyle();
+ verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbb + cccccccccccccccccccccccccc;",
+ Style);
+
+ Style.PenaltyBreakAssignment = 20;
+ verifyFormat("int aaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbb +\n"
+ " cccccccccccccccccccccccccc;",
+ Style);
+}
+
TEST_F(FormatTest, AlignsAfterAssignments) {
verifyFormat(
"int Result = aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
@@ -4090,9 +5000,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));
@@ -4132,6 +5042,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();");
@@ -4417,7 +5330,7 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) {
EXPECT_EQ("static_cast<A< //\n"
" B> *>(\n"
"\n"
- " );",
+ ");",
format("static_cast<A<//\n"
" B>*>(\n"
"\n"
@@ -4728,7 +5641,8 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) {
verifyFormat("SomeType MemberFunction(const Deleted &) && {}");
verifyFormat("SomeType MemberFunction(const Deleted &) && final {}");
verifyFormat("SomeType MemberFunction(const Deleted &) && override {}");
- verifyFormat("SomeType MemberFunction(const Deleted &) const &;");
+ verifyFormat("void Fn(T const &) const &;");
+ verifyFormat("void Fn(T const volatile &&) const volatile &&;");
verifyFormat("template <typename T>\n"
"void F(T) && = delete;",
getGoogleStyle());
@@ -4745,7 +5659,8 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) {
verifyFormat("auto Function(T... t) & -> void {}", AlignLeft);
verifyFormat("auto Function(T) & -> void {}", AlignLeft);
verifyFormat("auto Function(T) & -> void;", AlignLeft);
- verifyFormat("SomeType MemberFunction(const Deleted&) const &;", AlignLeft);
+ verifyFormat("void Fn(T const&) const&;", AlignLeft);
+ verifyFormat("void Fn(T const volatile&&) const volatile&&;", AlignLeft);
FormatStyle Spaces = getLLVMStyle();
Spaces.SpacesInCStyleCastParentheses = true;
@@ -4890,6 +5805,11 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyFormat("x = *a(x) = *a(y);", Left);
verifyFormat("for (;; *a = b) {\n}", Left);
verifyFormat("return *this += 1;", Left);
+ verifyFormat("throw *x;", Left);
+ verifyFormat("delete *x;", Left);
+ verifyFormat("typedef typeof(int(int, int))* MyFuncPtr;", Left);
+ verifyFormat("[](const decltype(*a)* ptr) {}", Left);
+ verifyFormat("typedef typeof /*comment*/ (int(int, int))* MyFuncPtr;", Left);
verifyIndependentOfContext("a = *(x + y);");
verifyIndependentOfContext("a = &(x + y);");
@@ -4936,9 +5856,6 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyGoogleFormat("T** t = new T*;");
verifyGoogleFormat("T** t = new T*();");
- FormatStyle PointerLeft = getLLVMStyle();
- PointerLeft.PointerAlignment = FormatStyle::PAS_Left;
- verifyFormat("delete *x;", PointerLeft);
verifyFormat("STATIC_ASSERT((a & b) == 0);");
verifyFormat("STATIC_ASSERT(0 == (a & b));");
verifyFormat("template <bool a, bool b> "
@@ -5217,6 +6134,12 @@ TEST_F(FormatTest, FormatsFunctionTypes) {
verifyFormat("void f() { function(*some_pointer_var)[0] = 10; }");
verifyFormat("int x = f(&h)();");
verifyFormat("returnsFunction(&param1, &param2)(param);");
+ verifyFormat("std::function<\n"
+ " LooooooooooongTemplatedType<\n"
+ " SomeType>*(\n"
+ " LooooooooooooooooongType type)>\n"
+ " function;",
+ getGoogleStyleWithColumns(40));
}
TEST_F(FormatTest, FormatsPointersToArrayTypes) {
@@ -5571,7 +6494,10 @@ TEST_F(FormatTest, LayoutBraceInitializersInReturnStatement) {
TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
verifyFormat("vector<int> x{1, 2, 3, 4};");
verifyFormat("vector<int> x{\n"
- " 1, 2, 3, 4,\n"
+ " 1,\n"
+ " 2,\n"
+ " 3,\n"
+ " 4,\n"
"};");
verifyFormat("vector<T> x{{}, {}, {}, {}};");
verifyFormat("f({1, 2});");
@@ -5590,6 +6516,8 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
" T member = {arg1, arg2};\n"
"};");
verifyFormat("vector<int> foo = {::SomeGlobalFunction()};");
+ verifyFormat("const struct A a = {.a = 1, .b = 2};");
+ verifyFormat("const struct A a = {[0] = 1, [1] = 2};");
verifyFormat("static_assert(std::is_integral<int>{} + 0, \"\");");
verifyFormat("int a = std::is_integral<int>{} + 0;");
@@ -5614,6 +6542,17 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
"};");
verifyFormat("#define A {a, a},");
+ // Binpacking only if there is no trailing comma
+ verifyFormat("const Aaaaaa aaaaa = {aaaaaaaaaa, bbbbbbbbbb,\n"
+ " cccccccccc, dddddddddd};",
+ getLLVMStyleWithColumns(50));
+ verifyFormat("const Aaaaaa aaaaa = {\n"
+ " aaaaaaaaaaa,\n"
+ " bbbbbbbbbbb,\n"
+ " ccccccccccc,\n"
+ " ddddddddddd,\n"
+ "};", getLLVMStyleWithColumns(50));
+
// Cases where distinguising braced lists and blocks is hard.
verifyFormat("vector<int> v{12} GUARDED_BY(mutex);");
verifyFormat("void f() {\n"
@@ -5693,10 +6632,12 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
" // Second element:\n"
" 2};",
getLLVMStyleWithColumns(30)));
- // A trailing comma should still lead to an enforced line break.
+ // A trailing comma should still lead to an enforced line break and no
+ // binpacking.
EXPECT_EQ("vector<int> SomeVector = {\n"
" // aaa\n"
- " 1, 2,\n"
+ " 1,\n"
+ " 2,\n"
"};",
format("vector<int> SomeVector = { // aaa\n"
" 1, 2, };"));
@@ -5755,6 +6696,8 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
" aaaaaaa,\n"
" a};");
verifyFormat("vector<int> foo = { ::SomeGlobalFunction() };", ExtraSpaces);
+ verifyFormat("const struct A a = { .a = 1, .b = 2 };", ExtraSpaces);
+ verifyFormat("const struct A a = { [0] = 1, [1] = 2 };", ExtraSpaces);
}
TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
@@ -5860,7 +6803,7 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
" aaaaaaaaaaaa, a, aaaaaaaaaa, aaaaaaaaa, aaa}};");
// No column layout should be used here.
- verifyFormat("aaaaaaaaaaaaaaa = {aaaaaaaaaaaaaaaaaaaaaaaaaaa, 0, 0,\n"
+ verifyFormat("aaaaaaaaaaaaaaa = {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 0, 0,\n"
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb};");
verifyNoCrash("a<,");
@@ -6003,6 +6946,35 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
getLLVMStyleWithColumns(23));
}
+TEST_F(FormatTest, PullEmptyFunctionDefinitionsIntoSingleLine) {
+ FormatStyle MergeEmptyOnly = getLLVMStyle();
+ MergeEmptyOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeEmptyOnly);
+ verifyFormat("class C {\n"
+ " int f() {\n"
+ " return 42;\n"
+ " }\n"
+ "};",
+ MergeEmptyOnly);
+ verifyFormat("int f() {}", MergeEmptyOnly);
+ verifyFormat("int f() {\n"
+ " return 42;\n"
+ "}",
+ MergeEmptyOnly);
+
+ // Also verify behavior when BraceWrapping.AfterFunction = true
+ MergeEmptyOnly.BreakBeforeBraces = FormatStyle::BS_Custom;
+ MergeEmptyOnly.BraceWrapping.AfterFunction = true;
+ verifyFormat("int f() {}", MergeEmptyOnly);
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeEmptyOnly);
+}
+
TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
FormatStyle MergeInlineOnly = getLLVMStyle();
MergeInlineOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
@@ -6014,6 +6986,329 @@ TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
" return 42;\n"
"}",
MergeInlineOnly);
+
+ // SFS_Inline implies SFS_Empty
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f() {}", MergeInlineOnly);
+
+ // Also verify behavior when BraceWrapping.AfterFunction = true
+ MergeInlineOnly.BreakBeforeBraces = FormatStyle::BS_Custom;
+ MergeInlineOnly.BraceWrapping.AfterFunction = true;
+ verifyFormat("class C {\n"
+ " int f() { return 42; }\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f()\n"
+ "{\n"
+ " return 42;\n"
+ "}",
+ MergeInlineOnly);
+
+ // SFS_Inline implies SFS_Empty
+ verifyFormat("int f() {}", MergeInlineOnly);
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeInlineOnly);
+}
+
+TEST_F(FormatTest, PullInlineOnlyFunctionDefinitionsIntoSingleLine) {
+ FormatStyle MergeInlineOnly = getLLVMStyle();
+ MergeInlineOnly.AllowShortFunctionsOnASingleLine =
+ FormatStyle::SFS_InlineOnly;
+ verifyFormat("class C {\n"
+ " int f() { return 42; }\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f() {\n"
+ " return 42;\n"
+ "}",
+ MergeInlineOnly);
+
+ // SFS_InlineOnly does not imply SFS_Empty
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f() {\n"
+ "}",
+ MergeInlineOnly);
+
+ // Also verify behavior when BraceWrapping.AfterFunction = true
+ MergeInlineOnly.BreakBeforeBraces = FormatStyle::BS_Custom;
+ MergeInlineOnly.BraceWrapping.AfterFunction = true;
+ verifyFormat("class C {\n"
+ " int f() { return 42; }\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f()\n"
+ "{\n"
+ " return 42;\n"
+ "}",
+ MergeInlineOnly);
+
+ // SFS_InlineOnly does not imply SFS_Empty
+ verifyFormat("int f()\n"
+ "{\n"
+ "}",
+ MergeInlineOnly);
+ verifyFormat("class C {\n"
+ " int f() {}\n"
+ "};",
+ MergeInlineOnly);
+}
+
+TEST_F(FormatTest, SplitEmptyFunction) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterFunction = true;
+ Style.BraceWrapping.SplitEmptyFunction = false;
+ Style.ColumnLimit = 40;
+
+ verifyFormat("int f()\n"
+ "{}",
+ Style);
+ verifyFormat("int f()\n"
+ "{\n"
+ " return 42;\n"
+ "}",
+ Style);
+ verifyFormat("int f()\n"
+ "{\n"
+ " // some comment\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+ verifyFormat("int f() {}", Style);
+ verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ "{}",
+ Style);
+ verifyFormat("int f()\n"
+ "{\n"
+ " return 0;\n"
+ "}",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ verifyFormat("class Foo {\n"
+ " int f() {}\n"
+ "};\n",
+ Style);
+ verifyFormat("class Foo {\n"
+ " int f() { return 0; }\n"
+ "};\n",
+ Style);
+ verifyFormat("class Foo {\n"
+ " int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ " {}\n"
+ "};\n",
+ Style);
+ verifyFormat("class Foo {\n"
+ " int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ " {\n"
+ " return 0;\n"
+ " }\n"
+ "};\n",
+ Style);
+
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ verifyFormat("int f() {}", Style);
+ verifyFormat("int f() { return 0; }", Style);
+ verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ "{}",
+ Style);
+ verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n"
+ "{\n"
+ " return 0;\n"
+ "}",
+ Style);
+}
+TEST_F(FormatTest, KeepShortFunctionAfterPPElse) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ verifyFormat("#ifdef A\n"
+ "int f() {}\n"
+ "#else\n"
+ "int g() {}\n"
+ "#endif",
+ Style);
+}
+
+TEST_F(FormatTest, SplitEmptyClass) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterClass = true;
+ Style.BraceWrapping.SplitEmptyRecord = false;
+
+ verifyFormat("class Foo\n"
+ "{};",
+ Style);
+ verifyFormat("/* something */ class Foo\n"
+ "{};",
+ Style);
+ verifyFormat("template <typename X> class Foo\n"
+ "{};",
+ Style);
+ verifyFormat("class Foo\n"
+ "{\n"
+ " Foo();\n"
+ "};",
+ Style);
+ verifyFormat("typedef class Foo\n"
+ "{\n"
+ "} Foo_t;",
+ Style);
+}
+
+TEST_F(FormatTest, SplitEmptyStruct) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterStruct = true;
+ Style.BraceWrapping.SplitEmptyRecord = false;
+
+ verifyFormat("struct Foo\n"
+ "{};",
+ Style);
+ verifyFormat("/* something */ struct Foo\n"
+ "{};",
+ Style);
+ verifyFormat("template <typename X> struct Foo\n"
+ "{};",
+ Style);
+ verifyFormat("struct Foo\n"
+ "{\n"
+ " Foo();\n"
+ "};",
+ Style);
+ verifyFormat("typedef struct Foo\n"
+ "{\n"
+ "} Foo_t;",
+ Style);
+ //typedef struct Bar {} Bar_t;
+}
+
+TEST_F(FormatTest, SplitEmptyUnion) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterUnion = true;
+ Style.BraceWrapping.SplitEmptyRecord = false;
+
+ verifyFormat("union Foo\n"
+ "{};",
+ Style);
+ verifyFormat("/* something */ union Foo\n"
+ "{};",
+ Style);
+ verifyFormat("union Foo\n"
+ "{\n"
+ " A,\n"
+ "};",
+ Style);
+ verifyFormat("typedef union Foo\n"
+ "{\n"
+ "} Foo_t;",
+ Style);
+}
+
+TEST_F(FormatTest, SplitEmptyNamespace) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterNamespace = true;
+ Style.BraceWrapping.SplitEmptyNamespace = false;
+
+ verifyFormat("namespace Foo\n"
+ "{};",
+ Style);
+ verifyFormat("/* something */ namespace Foo\n"
+ "{};",
+ Style);
+ verifyFormat("inline namespace Foo\n"
+ "{};",
+ Style);
+ verifyFormat("namespace Foo\n"
+ "{\n"
+ "void Bar();\n"
+ "};",
+ Style);
+}
+
+TEST_F(FormatTest, NeverMergeShortRecords) {
+ FormatStyle Style = getLLVMStyle();
+
+ verifyFormat("class Foo {\n"
+ " Foo();\n"
+ "};",
+ Style);
+ verifyFormat("typedef class Foo {\n"
+ " Foo();\n"
+ "} Foo_t;",
+ Style);
+ verifyFormat("struct Foo {\n"
+ " Foo();\n"
+ "};",
+ Style);
+ verifyFormat("typedef struct Foo {\n"
+ " Foo();\n"
+ "} Foo_t;",
+ Style);
+ verifyFormat("union Foo {\n"
+ " A,\n"
+ "};",
+ Style);
+ verifyFormat("typedef union Foo {\n"
+ " A,\n"
+ "} Foo_t;",
+ Style);
+ verifyFormat("namespace Foo {\n"
+ "void Bar();\n"
+ "};",
+ Style);
+
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterClass = true;
+ Style.BraceWrapping.AfterStruct = true;
+ Style.BraceWrapping.AfterUnion = true;
+ Style.BraceWrapping.AfterNamespace = true;
+ verifyFormat("class Foo\n"
+ "{\n"
+ " Foo();\n"
+ "};",
+ Style);
+ verifyFormat("typedef class Foo\n"
+ "{\n"
+ " Foo();\n"
+ "} Foo_t;",
+ Style);
+ verifyFormat("struct Foo\n"
+ "{\n"
+ " Foo();\n"
+ "};",
+ Style);
+ verifyFormat("typedef struct Foo\n"
+ "{\n"
+ " Foo();\n"
+ "} Foo_t;",
+ Style);
+ verifyFormat("union Foo\n"
+ "{\n"
+ " A,\n"
+ "};",
+ Style);
+ verifyFormat("typedef union Foo\n"
+ "{\n"
+ " A,\n"
+ "} Foo_t;",
+ Style);
+ verifyFormat("namespace Foo\n"
+ "{\n"
+ "void Bar();\n"
+ "};",
+ Style);
}
TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
@@ -6132,6 +7427,10 @@ TEST_F(FormatTest, MergeHandlingInTheFaceOfPreprocessorDirectives) {
" if (true) continue;\n"
"}",
ShortMergedIf);
+ ShortMergedIf.ColumnLimit = 33;
+ verifyFormat("#define A \\\n"
+ " if constexpr (true) return 42;",
+ ShortMergedIf);
ShortMergedIf.ColumnLimit = 29;
verifyFormat("#define A \\\n"
" if (aaaaaaaaaa) return 1; \\\n"
@@ -6143,6 +7442,11 @@ TEST_F(FormatTest, MergeHandlingInTheFaceOfPreprocessorDirectives) {
" return 1; \\\n"
" return 2;",
ShortMergedIf);
+ verifyFormat("#define A \\\n"
+ " if constexpr (aaaaaaa) \\\n"
+ " return 1; \\\n"
+ " return 2;",
+ ShortMergedIf);
}
TEST_F(FormatTest, FormatStarDependingOnContext) {
@@ -6186,7 +7490,7 @@ TEST_F(FormatTest, SkipsDeeplyNestedLines) {
// Deeply nested part is untouched, rest is formatted.
EXPECT_EQ(std::string("int i;\n") + Code + "int j;\n",
format(std::string("int i;\n") + Code + "int j;\n",
- getLLVMStyle(), IC_ExpectIncomplete));
+ getLLVMStyle(), SC_ExpectIncomplete));
}
//===----------------------------------------------------------------------===//
@@ -6413,7 +7717,7 @@ TEST_F(FormatTest, BreaksStringLiterals) {
EXPECT_EQ("\"some text other\";", format("\"some text other\";", Style));
FormatStyle AlignLeft = getLLVMStyleWithColumns(12);
- AlignLeft.AlignEscapedNewlinesLeft = true;
+ AlignLeft.AlignEscapedNewlines = FormatStyle::ENAS_Left;
EXPECT_EQ("#define A \\\n"
" \"some \" \\\n"
" \"text \" \\\n"
@@ -6457,6 +7761,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.
@@ -6502,7 +7807,7 @@ TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) {
"#if !TEST\n"
" _T(\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXn\")\n"
"#endif\n"
- " );",
+ ");",
format("f(\n"
"#if !TEST\n"
"_T(\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXn\")\n"
@@ -6813,7 +8118,7 @@ TEST_F(FormatTest, ConfigurableUseOfTab) {
FormatStyle Tab = getLLVMStyleWithColumns(42);
Tab.IndentWidth = 8;
Tab.UseTab = FormatStyle::UT_Always;
- Tab.AlignEscapedNewlinesLeft = true;
+ Tab.AlignEscapedNewlines = FormatStyle::ENAS_Left;
EXPECT_EQ("if (aaaaaaaa && // q\n"
" bb)\t\t// w\n"
@@ -7594,14 +8899,21 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) {
"int oneTwoThree = 123;\n"
"int oneTwo = 12;",
Alignment));
- Alignment.AlignEscapedNewlinesLeft = true;
+ Alignment.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
+ verifyFormat("#define A \\\n"
+ " int aaaa = 12; \\\n"
+ " int b = 23; \\\n"
+ " int ccc = 234; \\\n"
+ " int dddddddddd = 2345;",
+ Alignment);
+ Alignment.AlignEscapedNewlines = FormatStyle::ENAS_Left;
verifyFormat("#define A \\\n"
" int aaaa = 12; \\\n"
" int b = 23; \\\n"
" int ccc = 234; \\\n"
" int dddddddddd = 2345;",
Alignment);
- Alignment.AlignEscapedNewlinesLeft = false;
+ Alignment.AlignEscapedNewlines = FormatStyle::ENAS_Right;
verifyFormat("#define A "
" \\\n"
" int aaaa = 12; "
@@ -7669,12 +8981,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"
@@ -7689,6 +9000,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) {
@@ -7756,7 +9074,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"
@@ -7766,6 +9134,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"
@@ -7790,14 +9180,21 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
"}",
Alignment));
Alignment.AlignConsecutiveAssignments = false;
- Alignment.AlignEscapedNewlinesLeft = true;
+ Alignment.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
+ verifyFormat("#define A \\\n"
+ " int aaaa = 12; \\\n"
+ " float b = 23; \\\n"
+ " const int ccc = 234; \\\n"
+ " unsigned dddddddddd = 2345;",
+ Alignment);
+ Alignment.AlignEscapedNewlines = FormatStyle::ENAS_Left;
verifyFormat("#define A \\\n"
" int aaaa = 12; \\\n"
" float b = 23; \\\n"
" const int ccc = 234; \\\n"
" unsigned dddddddddd = 2345;",
Alignment);
- Alignment.AlignEscapedNewlinesLeft = false;
+ Alignment.AlignEscapedNewlines = FormatStyle::ENAS_Right;
Alignment.ColumnLimit = 30;
verifyFormat("#define A \\\n"
" int aaaa = 12; \\\n"
@@ -7867,17 +9264,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;
@@ -7930,6 +9326,16 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
Alignment);
Alignment.BinPackParameters = true;
Alignment.ColumnLimit = 80;
+
+ // Bug 33507
+ Alignment.PointerAlignment = FormatStyle::PAS_Middle;
+ verifyFormat(
+ "auto found = range::find_if(vsProducts, [&](auto * aProduct) {\n"
+ " static const Version verVs2017;\n"
+ " return true;\n"
+ "});\n",
+ Alignment);
+ Alignment.PointerAlignment = FormatStyle::PAS_Right;
}
TEST_F(FormatTest, LinuxBraceBreaking) {
@@ -7953,7 +9359,7 @@ TEST_F(FormatTest, LinuxBraceBreaking) {
"struct B {\n"
" int x;\n"
"};\n"
- "}\n",
+ "} // namespace a\n",
LinuxBraceStyle);
verifyFormat("enum X {\n"
" Y = 0,\n"
@@ -8083,6 +9489,19 @@ TEST_F(FormatTest, StroustrupBraceBreaking) {
TEST_F(FormatTest, AllmanBraceBreaking) {
FormatStyle AllmanBraceStyle = getLLVMStyle();
AllmanBraceStyle.BreakBeforeBraces = FormatStyle::BS_Allman;
+
+ EXPECT_EQ("namespace a\n"
+ "{\n"
+ "void f();\n"
+ "void g();\n"
+ "} // namespace a\n",
+ format("namespace a\n"
+ "{\n"
+ "void f();\n"
+ "void g();\n"
+ "}\n",
+ AllmanBraceStyle));
+
verifyFormat("namespace a\n"
"{\n"
"class A\n"
@@ -8101,7 +9520,7 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
"{\n"
" int x;\n"
"};\n"
- "}",
+ "} // namespace a",
AllmanBraceStyle);
verifyFormat("void f()\n"
@@ -8221,7 +9640,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"
@@ -8253,11 +9679,24 @@ TEST_F(FormatTest, AllmanBraceBreaking) {
BreakBeforeBraceShortIfs);
verifyFormat("void f(bool b)\n"
"{\n"
+ " if constexpr (b)\n"
+ " {\n"
+ " return;\n"
+ " }\n"
+ "}\n",
+ BreakBeforeBraceShortIfs);
+ verifyFormat("void f(bool b)\n"
+ "{\n"
" if (b) return;\n"
"}\n",
BreakBeforeBraceShortIfs);
verifyFormat("void f(bool b)\n"
"{\n"
+ " if constexpr (b) return;\n"
+ "}\n",
+ BreakBeforeBraceShortIfs);
+ verifyFormat("void f(bool b)\n"
+ "{\n"
" while (b)\n"
" {\n"
" return;\n"
@@ -8287,7 +9726,7 @@ TEST_F(FormatTest, GNUBraceBreaking) {
" }\n"
" void g() { return; }\n"
"}\n"
- "}",
+ "} // namespace a",
GNUBraceStyle);
verifyFormat("void f()\n"
@@ -8576,7 +10015,6 @@ TEST_F(FormatTest, GetsCorrectBasedOnStyle) {
TEST_F(FormatTest, ParsesConfigurationBools) {
FormatStyle Style = {};
Style.Language = FormatStyle::LK_Cpp;
- CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
CHECK_PARSE_BOOL(AlignOperands);
CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AlignConsecutiveAssignments);
@@ -8591,9 +10029,9 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(BinPackParameters);
CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
- CHECK_PARSE_BOOL(BreakConstructorInitializersBeforeComma);
CHECK_PARSE_BOOL(BreakStringLiterals);
CHECK_PARSE_BOOL(BreakBeforeInheritanceComma)
+ CHECK_PARSE_BOOL(CompactNamespaces);
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
CHECK_PARSE_BOOL(DerivePointerAlignment);
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
@@ -8606,6 +10044,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(Cpp11BracedListStyle);
CHECK_PARSE_BOOL(ReflowComments);
CHECK_PARSE_BOOL(SortIncludes);
+ CHECK_PARSE_BOOL(SortUsingDeclarations);
CHECK_PARSE_BOOL(SpacesInParentheses);
CHECK_PARSE_BOOL(SpacesInSquareBrackets);
CHECK_PARSE_BOOL(SpacesInAngles);
@@ -8624,9 +10063,13 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterObjCDeclaration);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterStruct);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterUnion);
+ CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterExternBlock);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeCatch);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeElse);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, IndentBraces);
+ CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunction);
+ CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyRecord);
+ CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyNamespace);
}
#undef CHECK_PARSE_BOOL
@@ -8640,6 +10083,8 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("ObjCBlockIndentWidth: 1234", ObjCBlockIndentWidth, 1234u);
CHECK_PARSE("ColumnLimit: 1234", ColumnLimit, 1234u);
CHECK_PARSE("MaxEmptyLinesToKeep: 1234", MaxEmptyLinesToKeep, 1234u);
+ CHECK_PARSE("PenaltyBreakAssignment: 1234",
+ PenaltyBreakAssignment, 1234u);
CHECK_PARSE("PenaltyBreakBeforeFirstCallParameter: 1234",
PenaltyBreakBeforeFirstCallParameter, 1234u);
CHECK_PARSE("PenaltyExcessCharacter: 1234", PenaltyExcessCharacter, 1234u);
@@ -8686,6 +10131,17 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators,
FormatStyle::BOS_All);
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
+ CHECK_PARSE("BreakConstructorInitializers: BeforeComma",
+ BreakConstructorInitializers, FormatStyle::BCIS_BeforeComma);
+ CHECK_PARSE("BreakConstructorInitializers: AfterColon",
+ BreakConstructorInitializers, FormatStyle::BCIS_AfterColon);
+ CHECK_PARSE("BreakConstructorInitializers: BeforeColon",
+ BreakConstructorInitializers, FormatStyle::BCIS_BeforeColon);
+ // For backward compatibility:
+ CHECK_PARSE("BreakConstructorInitializersBeforeComma: true",
+ BreakConstructorInitializers, FormatStyle::BCIS_BeforeComma);
+
Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
CHECK_PARSE("AlignAfterOpenBracket: Align", AlignAfterOpenBracket,
FormatStyle::BAS_Align);
@@ -8699,6 +10155,19 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("AlignAfterOpenBracket: true", AlignAfterOpenBracket,
FormatStyle::BAS_Align);
+ Style.AlignEscapedNewlines = FormatStyle::ENAS_Left;
+ CHECK_PARSE("AlignEscapedNewlines: DontAlign", AlignEscapedNewlines,
+ FormatStyle::ENAS_DontAlign);
+ CHECK_PARSE("AlignEscapedNewlines: Left", AlignEscapedNewlines,
+ FormatStyle::ENAS_Left);
+ CHECK_PARSE("AlignEscapedNewlines: Right", AlignEscapedNewlines,
+ FormatStyle::ENAS_Right);
+ // For backward compatibility:
+ CHECK_PARSE("AlignEscapedNewlinesLeft: true", AlignEscapedNewlines,
+ FormatStyle::ENAS_Left);
+ CHECK_PARSE("AlignEscapedNewlinesLeft: false", AlignEscapedNewlines,
+ FormatStyle::ENAS_Right);
+
Style.UseTab = FormatStyle::UT_ForIndentation;
CHECK_PARSE("UseTab: Never", UseTab, FormatStyle::UT_Never);
CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation);
@@ -8811,6 +10280,20 @@ TEST_F(FormatTest, ParsesConfiguration) {
" Priority: 1",
IncludeCategories, ExpectedCategories);
CHECK_PARSE("IncludeIsMainRegex: 'abc$'", IncludeIsMainRegex, "abc$");
+
+ Style.RawStringFormats.clear();
+ std::vector<FormatStyle::RawStringFormat> ExpectedRawStringFormats = {
+ {"pb", FormatStyle::LK_TextProto, "llvm"},
+ {"cpp", FormatStyle::LK_Cpp, "google"}};
+
+ CHECK_PARSE("RawStringFormats:\n"
+ " - Delimiter: 'pb'\n"
+ " Language: TextProto\n"
+ " BasedOnStyle: llvm\n"
+ " - Delimiter: 'cpp'\n"
+ " Language: Cpp\n"
+ " BasedOnStyle: google",
+ RawStringFormats, ExpectedRawStringFormats);
}
TEST_F(FormatTest, ParsesConfigurationWithLanguages) {
@@ -9105,7 +10588,7 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) {
TEST_F(FormatTest, BreakConstructorInitializersBeforeComma) {
FormatStyle Style = getLLVMStyle();
- Style.BreakConstructorInitializersBeforeComma = true;
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Style.ConstructorInitializerIndentWidth = 4;
verifyFormat("SomeClass::Constructor()\n"
" : a(a)\n"
@@ -9350,6 +10833,8 @@ TEST_F(FormatTest, FormatsLambdas) {
verifyFormat("int c = [&a, &a, a] { [=, a, b, &c] { return b++; }(); }();\n");
verifyFormat("auto c = {[&a, &a, a] { [=, a, b, &c] { return b++; }(); }}\n");
verifyFormat("auto c = {[&a, &a, a] { [=, a, b, &c] {}(); }}\n");
+ verifyFormat("auto c = [a = [b = 42] {}] {};\n");
+ verifyFormat("auto c = [a = &i + 10, b = [] {}] {};\n");
verifyFormat("int x = f(*+[] {});");
verifyFormat("void f() {\n"
" other(x.begin(), x.end(), [&](int, int) { return 1; });\n"
@@ -9464,7 +10949,7 @@ TEST_F(FormatTest, FormatsLambdas) {
// Other corner cases.
verifyFormat("void f() {\n"
" bar([]() {} // Did not respect SpacesBeforeTrailingComments\n"
- " );\n"
+ " );\n"
"}");
// Lambdas created through weird macros.
@@ -9478,6 +10963,11 @@ TEST_F(FormatTest, FormatsLambdas) {
" doo_dah();\n"
" })) {\n"
"}");
+ verifyFormat("if constexpr (blah_blah(whatever, whatever, [] {\n"
+ " doo_dah();\n"
+ " doo_dah();\n"
+ " })) {\n"
+ "}");
verifyFormat("auto lambda = []() {\n"
" int a = 2\n"
"#if A\n"
@@ -9974,6 +11464,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.
@@ -10111,6 +11605,98 @@ TEST_F(ReplacementTest, SortIncludesAfterReplacement) {
EXPECT_EQ(Expected, *Result);
}
+TEST_F(FormatTest, FormatSortsUsingDeclarations) {
+ EXPECT_EQ("using std::cin;\n"
+ "using std::cout;",
+ format("using std::cout;\n"
+ "using std::cin;", getGoogleStyle()));
+}
+
+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';"));
+}
+
+TEST_F(FormatTest, DoNotFormatLikelyXml) {
+ EXPECT_EQ("<!-- ;> -->",
+ format("<!-- ;> -->", getGoogleStyle()));
+ EXPECT_EQ(" <!-- >; -->",
+ format(" <!-- >; -->", getGoogleStyle()));
+}
+
+TEST_F(FormatTest, StructuredBindings) {
+ // Structured bindings is a C++17 feature.
+ // all modes, including C++11, C++14 and C++17
+ verifyFormat("auto [a, b] = f();");
+ EXPECT_EQ("auto [a, b] = f();", format("auto[a, b] = f();"));
+ EXPECT_EQ("const auto [a, b] = f();", format("const auto[a, b] = f();"));
+ EXPECT_EQ("auto const [a, b] = f();", format("auto const[a, b] = f();"));
+ EXPECT_EQ("auto const volatile [a, b] = f();",
+ format("auto const volatile[a, b] = f();"));
+ EXPECT_EQ("auto [a, b, c] = f();", format("auto [ a , b,c ] = f();"));
+ EXPECT_EQ("auto &[a, b, c] = f();",
+ format("auto &[ a , b,c ] = f();"));
+ EXPECT_EQ("auto &&[a, b, c] = f();",
+ format("auto &&[ a , b,c ] = f();"));
+ EXPECT_EQ("auto const &[a, b] = f();", format("auto const&[a, b] = f();"));
+ EXPECT_EQ("auto const volatile &&[a, b] = f();",
+ format("auto const volatile &&[a, b] = f();"));
+ EXPECT_EQ("auto const &&[a, b] = f();", format("auto const && [a, b] = f();"));
+ EXPECT_EQ("const auto &[a, b] = f();", format("const auto & [a, b] = f();"));
+ EXPECT_EQ("const auto volatile &&[a, b] = f();",
+ format("const auto volatile &&[a, b] = f();"));
+ EXPECT_EQ("volatile const auto &&[a, b] = f();",
+ format("volatile const auto &&[a, b] = f();"));
+ EXPECT_EQ("const auto &&[a, b] = f();", format("const auto && [a, b] = f();"));
+
+ // Make sure we don't mistake structured bindings for lambdas.
+ FormatStyle PointerMiddle = getLLVMStyle();
+ PointerMiddle.PointerAlignment = FormatStyle::PAS_Middle;
+ verifyFormat("auto [a1, b]{A * i};", getGoogleStyle());
+ verifyFormat("auto [a2, b]{A * i};", getLLVMStyle());
+ verifyFormat("auto [a3, b]{A * i};", PointerMiddle);
+ verifyFormat("auto const [a1, b]{A * i};", getGoogleStyle());
+ verifyFormat("auto const [a2, b]{A * i};", getLLVMStyle());
+ verifyFormat("auto const [a3, b]{A * i};", PointerMiddle);
+ verifyFormat("auto const& [a1, b]{A * i};", getGoogleStyle());
+ verifyFormat("auto const &[a2, b]{A * i};", getLLVMStyle());
+ verifyFormat("auto const & [a3, b]{A * i};", PointerMiddle);
+ verifyFormat("auto const&& [a1, b]{A * i};", getGoogleStyle());
+ verifyFormat("auto const &&[a2, b]{A * i};", getLLVMStyle());
+ verifyFormat("auto const && [a3, b]{A * i};", PointerMiddle);
+
+ EXPECT_EQ("for (const auto &&[a, b] : some_range) {\n}",
+ format("for (const auto && [a, b] : some_range) {\n}"));
+ EXPECT_EQ("for (const auto &[a, b] : some_range) {\n}",
+ format("for (const auto & [a, b] : some_range) {\n}"));
+ EXPECT_EQ("for (const auto [a, b] : some_range) {\n}",
+ format("for (const auto[a, b] : some_range) {\n}"));
+ EXPECT_EQ("auto [x, y](expr);", format("auto[x,y] (expr);"));
+ EXPECT_EQ("auto &[x, y](expr);", format("auto & [x,y] (expr);"));
+ EXPECT_EQ("auto &&[x, y](expr);", format("auto && [x,y] (expr);"));
+ EXPECT_EQ("auto const &[x, y](expr);", format("auto const & [x,y] (expr);"));
+ EXPECT_EQ("auto const &&[x, y](expr);", format("auto const && [x,y] (expr);"));
+ EXPECT_EQ("auto [x, y]{expr};", format("auto[x,y] {expr};"));
+ EXPECT_EQ("auto const &[x, y]{expr};", format("auto const & [x,y] {expr};"));
+ EXPECT_EQ("auto const &&[x, y]{expr};", format("auto const && [x,y] {expr};"));
+
+ format::FormatStyle Spaces = format::getLLVMStyle();
+ Spaces.SpacesInSquareBrackets = true;
+ verifyFormat("auto [ a, b ] = f();", Spaces);
+ verifyFormat("auto &&[ a, b ] = f();", Spaces);
+ verifyFormat("auto &[ a, b ] = f();", Spaces);
+ verifyFormat("auto const &&[ a, b ] = f();", Spaces);
+ verifyFormat("auto const &[ a, b ] = f();", Spaces);
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/FormatTestComments.cpp b/unittests/Format/FormatTestComments.cpp
index df24abe261..ceccc83587 100644
--- a/unittests/Format/FormatTestComments.cpp
+++ b/unittests/Format/FormatTestComments.cpp
@@ -29,24 +29,25 @@ FormatStyle getGoogleStyle() { return getGoogleStyle(FormatStyle::LK_Cpp); }
class FormatTestComments : public ::testing::Test {
protected:
- enum IncompleteCheck {
- IC_ExpectComplete,
- IC_ExpectIncomplete,
- IC_DoNotCheck
+ enum StatusCheck {
+ SC_ExpectComplete,
+ SC_ExpectIncomplete,
+ SC_DoNotCheck
};
std::string format(llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle(),
- IncompleteCheck CheckIncomplete = IC_ExpectComplete) {
+ StatusCheck CheckComplete = SC_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;
+ FormattingAttemptStatus Status;
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";
+ reformat(Style, Code, Ranges, "<stdin>", &Status);
+ if (CheckComplete != SC_DoNotCheck) {
+ bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
+ EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
+ << Code << "\n\n";
}
ReplacementCount = Replaces.size();
auto Result = applyAllReplacements(Code, Replaces);
@@ -73,7 +74,7 @@ protected:
/// \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);
+ format(Code, Style, SC_DoNotCheck);
}
int ReplacementCount;
@@ -804,6 +805,279 @@ TEST_F(FormatTestComments, ParsesCommentsAdjacentToPPDirectives) {
format("namespace {}\n /* Test */ #define A"));
}
+TEST_F(FormatTestComments, KeepsLevelOfCommentBeforePPDirective) {
+ // Keep the current level if the comment was originally not aligned with
+ // the preprocessor directive.
+ EXPECT_EQ("void f() {\n"
+ " int i;\n"
+ " /* comment */\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}",
+ format("void f() {\n"
+ " int i;\n"
+ " /* comment */\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}"));
+
+ EXPECT_EQ("void f() {\n"
+ " int i;\n"
+ " /* comment */\n"
+ "\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}",
+ format("void f() {\n"
+ " int i;\n"
+ " /* comment */\n"
+ "\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " ++i;\n"
+ " }\n"
+ " // comment\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "#endif\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " ++i;\n"
+ " }\n"
+ " // comment\n"
+ "#ifdef A\n"
+ "int j;\n"
+ "#endif\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " // comment in else\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " // comment in else\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " /* comment in else */\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " /* comment in else */\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}"));
+
+ // Keep the current level if there is an empty line between the comment and
+ // the preprocessor directive.
+ EXPECT_EQ("void f() {\n"
+ " int i;\n"
+ " /* comment */\n"
+ "\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}",
+ format("void f() {\n"
+ " int i;\n"
+ "/* comment */\n"
+ "\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}"));
+
+ EXPECT_EQ("void f() {\n"
+ " int i;\n"
+ " return i;\n"
+ "}\n"
+ "// comment\n"
+ "\n"
+ "#ifdef A\n"
+ "int i;\n"
+ "#endif // A",
+ format("void f() {\n"
+ " int i;\n"
+ " return i;\n"
+ "}\n"
+ "// comment\n"
+ "\n"
+ "#ifdef A\n"
+ "int i;\n"
+ "#endif // A"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " ++i;\n"
+ " }\n"
+ " // comment\n"
+ "\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "#endif\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " ++i;\n"
+ " }\n"
+ " // comment\n"
+ "\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "#endif\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " // comment in else\n"
+ "\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ "// comment in else\n"
+ "\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " /* comment in else */\n"
+ "\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ "/* comment in else */\n"
+ "\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}"));
+
+ // Align with the preprocessor directive if the comment was originally aligned
+ // with the preprocessor directive and there is no newline between the comment
+ // and the preprocessor directive.
+ EXPECT_EQ("void f() {\n"
+ " int i;\n"
+ "/* comment */\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}",
+ format("void f() {\n"
+ " int i;\n"
+ "/* comment */\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " ++i;\n"
+ " }\n"
+ "// comment\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "#endif\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " ++i;\n"
+ " }\n"
+ "// comment\n"
+ "#ifdef A\n"
+ " int j;\n"
+ "#endif\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ "// comment in else\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " // comment in else\n"
+ " #ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}"));
+
+ EXPECT_EQ("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ "/* comment in else */\n"
+ "#ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}",
+ format("int f(int i) {\n"
+ " if (true) {\n"
+ " i++;\n"
+ " } else {\n"
+ " /* comment in else */\n"
+ " #ifdef A\n"
+ " j++;\n"
+ "#endif\n"
+ " }\n"
+ "}"));
+}
+
TEST_F(FormatTestComments, SplitsLongLinesInComments) {
EXPECT_EQ("/* This is a long\n"
" * comment that\n"
@@ -1019,6 +1293,62 @@ TEST_F(FormatTestComments, SplitsLongLinesInCommentsInPreprocessor) {
getLLVMStyleWithColumns(20)));
}
+TEST_F(FormatTestComments, KeepsTrailingPPCommentsAndSectionCommentsSeparate) {
+ verifyFormat("#ifdef A // line about A\n"
+ "// section comment\n"
+ "#endif",
+ getLLVMStyleWithColumns(80));
+ verifyFormat("#ifdef A // line 1 about A\n"
+ " // line 2 about A\n"
+ "// section comment\n"
+ "#endif",
+ getLLVMStyleWithColumns(80));
+ EXPECT_EQ("#ifdef A // line 1 about A\n"
+ " // line 2 about A\n"
+ "// section comment\n"
+ "#endif",
+ format("#ifdef A // line 1 about A\n"
+ " // line 2 about A\n"
+ "// section comment\n"
+ "#endif",
+ getLLVMStyleWithColumns(80)));
+ verifyFormat("int f() {\n"
+ " int i;\n"
+ "#ifdef A // comment about A\n"
+ " // section comment 1\n"
+ " // section comment 2\n"
+ " i = 2;\n"
+ "#else // comment about #else\n"
+ " // section comment 3\n"
+ " i = 4;\n"
+ "#endif\n"
+ "}", getLLVMStyleWithColumns(80));
+}
+
+TEST_F(FormatTestComments, AlignsPPElseEndifComments) {
+ verifyFormat("#if A\n"
+ "#else // A\n"
+ "int iiii;\n"
+ "#endif // B",
+ getLLVMStyleWithColumns(20));
+ verifyFormat("#if A\n"
+ "#else // A\n"
+ "int iiii; // CC\n"
+ "#endif // B",
+ getLLVMStyleWithColumns(20));
+ EXPECT_EQ("#if A\n"
+ "#else // A1\n"
+ " // A2\n"
+ "int ii;\n"
+ "#endif // B",
+ format("#if A\n"
+ "#else // A1\n"
+ " // A2\n"
+ "int ii;\n"
+ "#endif // B",
+ getLLVMStyleWithColumns(20)));
+}
+
TEST_F(FormatTestComments, CommentsInStaticInitializers) {
EXPECT_EQ(
"static SomeType type = {aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
@@ -1197,6 +1527,16 @@ TEST_F(FormatTestComments, ReflowsComments) {
format("/* long long long long\n"
" * long */",
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\n",
+ format("//!< long long long long\n"
+ "//!< long\n",
+ getLLVMStyleWithColumns(20)));
// Don't bring leading whitespace up while reflowing.
EXPECT_EQ("/* long long long\n"
@@ -1534,7 +1874,7 @@ TEST_F(FormatTestComments, ReflowsComments) {
" *\n"
" * long */",
getLLVMStyleWithColumns(20)));
-
+
// Don't reflow lines having content that is a single character.
EXPECT_EQ("// long long long\n"
"// long\n"
@@ -1559,7 +1899,7 @@ TEST_F(FormatTestComments, ReflowsComments) {
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"
@@ -1628,6 +1968,69 @@ TEST_F(FormatTestComments, ReflowsComments) {
"// long",
getLLVMStyleWithColumns(20)));
+ // Don't reflow separate bullets in list
+ EXPECT_EQ("// - long long long\n"
+ "// long\n"
+ "// - long",
+ format("// - long long long long\n"
+ "// - long",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// * long long long\n"
+ "// long\n"
+ "// * long",
+ format("// * long long long long\n"
+ "// * long",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// + long long long\n"
+ "// long\n"
+ "// + long",
+ format("// + long long long long\n"
+ "// + long",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// 1. long long long\n"
+ "// long\n"
+ "// 2. long",
+ format("// 1. long long long long\n"
+ "// 2. long",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// -# long long long\n"
+ "// long\n"
+ "// -# long",
+ format("// -# long long long long\n"
+ "// -# long",
+ getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("// - long long long\n"
+ "// long long long\n"
+ "// - long",
+ format("// - long long long long\n"
+ "// long long\n"
+ "// - long",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// - long long long\n"
+ "// long long long\n"
+ "// long\n"
+ "// - long",
+ format("// - long long long long\n"
+ "// long long long\n"
+ "// - long",
+ getLLVMStyleWithColumns(20)));
+
+ // Large number (>2 digits) are not list items
+ EXPECT_EQ("// long long long\n"
+ "// long 1024. long.",
+ format("// long long long long\n"
+ "// 1024. long.",
+ getLLVMStyleWithColumns(20)));
+
+ // Do not break before number, to avoid introducing a non-reflowable doxygen
+ // list item.
+ EXPECT_EQ("// long long\n"
+ "// long 10. long.",
+ format("// long long long 10.\n"
+ "// long.",
+ getLLVMStyleWithColumns(20)));
+
// Don't break or reflow after implicit string literals.
verifyFormat("#include <t> // l l l\n"
" // l",
@@ -2004,6 +2407,57 @@ TEST_F(FormatTestComments, BlockCommentsAtEndOfLine) {
getLLVMStyleWithColumns(15)));
}
+TEST_F(FormatTestComments, BreaksAfterMultilineBlockCommentsInParamLists) {
+ EXPECT_EQ("a = f(/* long\n"
+ " long\n"
+ " */\n"
+ " a);",
+ format("a = f(/* long long */ a);", getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ("a = f(/* long\n"
+ " long\n"
+ " */\n"
+ " a);",
+ format("a = f(/* long\n"
+ " long\n"
+ " */a);",
+ getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ("a = f(/* long\n"
+ " long\n"
+ " */\n"
+ " a);",
+ format("a = f(/* long\n"
+ " long\n"
+ " */ a);",
+ getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ("a = f(/* long\n"
+ " long\n"
+ " */\n"
+ " (1 + 1));",
+ format("a = f(/* long\n"
+ " long\n"
+ " */ (1 + 1));",
+ getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ(
+ "a = f(a,\n"
+ " /* long\n"
+ " long\n"
+ " */\n"
+ " b);",
+ format("a = f(a, /* long long */ b);", getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ(
+ "a = f(a,\n"
+ " /* long\n"
+ " long\n"
+ " */\n"
+ " (1 + 1));",
+ format("a = f(a, /* long long */ (1 + 1));", getLLVMStyleWithColumns(15)));
+}
+
TEST_F(FormatTestComments, IndentLineCommentsInStartOfBlockAtEndOfFile) {
verifyFormat("{\n"
" // a\n"
@@ -2018,7 +2472,7 @@ TEST_F(FormatTestComments, AlignTrailingComments) {
format("#define MACRO(V)\\\n"
"V(Rt2) /* one more char */ \\\n"
"V(Rs) /* than here */ \\\n"
- "/* comment 3 */ \\\n",
+ "/* comment 3 */\n",
getLLVMStyleWithColumns(40)));
EXPECT_EQ("int i = f(abc, // line 1\n"
" d, // line 2\n"
@@ -2064,6 +2518,22 @@ TEST_F(FormatTestComments, AlignTrailingComments) {
"// long",
getLLVMStyleWithColumns(15)));
+ // Don't align newly broken trailing comments if that would put them over the
+ // column limit.
+ EXPECT_EQ("int i, j; // line 1\n"
+ "int k; // line longg\n"
+ " // long",
+ format("int i, j; // line 1\n"
+ "int k; // line longg long",
+ getLLVMStyleWithColumns(20)));
+
+ // Always align if ColumnLimit = 0
+ EXPECT_EQ("int i, j; // line 1\n"
+ "int k; // line longg long",
+ format("int i, j; // line 1\n"
+ "int k; // line longg long",
+ getLLVMStyleWithColumns(0)));
+
// Align comment line sections aligned with the next token with the next
// token.
EXPECT_EQ("class A {\n"
@@ -2368,6 +2838,40 @@ TEST_F(FormatTestComments, AlignsBlockCommentDecorations) {
"* long */",
getLLVMStyleWithColumns(20)));
}
+
+TEST_F(FormatTestComments, NoCrush_Bug34236) {
+ // This is a test case from a crasher reported in:
+ // https://bugs.llvm.org/show_bug.cgi?id=34236
+ // Temporarily disable formatting for readability.
+ // clang-format off
+ EXPECT_EQ(
+"/* */ /*\n"
+" * a\n"
+" * b c\n"
+" * d*/",
+ format(
+"/* */ /*\n"
+" * a b\n"
+" * c d*/",
+ getLLVMStyleWithColumns(80)));
+ // clang-format on
+}
+
+TEST_F(FormatTestComments, NonTrailingBlockComments) {
+ verifyFormat("const /** comment comment */ A = B;",
+ getLLVMStyleWithColumns(40));
+
+ verifyFormat("const /** comment comment comment */ A =\n"
+ " B;",
+ getLLVMStyleWithColumns(40));
+
+ EXPECT_EQ("const /** comment comment comment\n"
+ " comment */\n"
+ " A = B;",
+ format("const /** comment comment comment comment */\n"
+ " A = B;",
+ getLLVMStyleWithColumns(40)));
+}
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index 62d7ec86c9..3df01663e9 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -24,10 +24,10 @@ protected:
DEBUG(llvm::errs() << "---\n");
DEBUG(llvm::errs() << Code << "\n\n");
std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
- bool IncompleteFormat = false;
+ FormattingAttemptStatus Status;
tooling::Replacements Replaces =
- reformat(Style, Code, Ranges, "<stdin>", &IncompleteFormat);
- EXPECT_FALSE(IncompleteFormat);
+ reformat(Style, Code, Ranges, "<stdin>", &Status);
+ EXPECT_TRUE(Status.FormatComplete);
auto Result = applyAllReplacements(Code, Replaces);
EXPECT_TRUE(static_cast<bool>(Result));
DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
@@ -65,6 +65,167 @@ protected:
TEST_F(FormatTestJS, BlockComments) {
verifyFormat("/* aaaaaaaaaaaaa */ aaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ // Breaks after a single line block comment.
+ EXPECT_EQ("aaaaa = bbbb.ccccccccccccccc(\n"
+ " /** @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala} */\n"
+ " mediaMessage);",
+ format("aaaaa = bbbb.ccccccccccccccc(\n"
+ " /** "
+ "@type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala} */ "
+ "mediaMessage);",
+ getGoogleJSStyleWithColumns(70)));
+ // Breaks after a multiline block comment.
+ EXPECT_EQ(
+ "aaaaa = bbbb.ccccccccccccccc(\n"
+ " /**\n"
+ " * @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala}\n"
+ " */\n"
+ " mediaMessage);",
+ format("aaaaa = bbbb.ccccccccccccccc(\n"
+ " /**\n"
+ " * @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala}\n"
+ " */ mediaMessage);",
+ getGoogleJSStyleWithColumns(70)));
+}
+
+TEST_F(FormatTestJS, JSDocComments) {
+ // Break the first line of a multiline jsdoc comment.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 1\n"
+ " * jsdoc line 2\n"
+ " */",
+ format("/** jsdoc line 1\n"
+ " * jsdoc line 2\n"
+ " */",
+ getGoogleJSStyleWithColumns(20)));
+ // Both break after '/**' and break the line itself.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line long\n"
+ " * long jsdoc line 2\n"
+ " */",
+ format("/** jsdoc line long long\n"
+ " * jsdoc line 2\n"
+ " */",
+ getGoogleJSStyleWithColumns(20)));
+ // Break a short first line if the ending '*/' is on a newline.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 1\n"
+ " */",
+ format("/** jsdoc line 1\n"
+ " */", getGoogleJSStyleWithColumns(20)));
+ // Don't break the first line of a short single line jsdoc comment.
+ EXPECT_EQ("/** jsdoc line 1 */",
+ format("/** jsdoc line 1 */", getGoogleJSStyleWithColumns(20)));
+ // Don't break the first line of a single line jsdoc comment if it just fits
+ // the column limit.
+ EXPECT_EQ("/** jsdoc line 12 */",
+ format("/** jsdoc line 12 */", getGoogleJSStyleWithColumns(20)));
+ // Don't break after '/**' and before '*/' if there is no space between
+ // '/**' and the content.
+ EXPECT_EQ(
+ "/*** nonjsdoc long\n"
+ " * line */",
+ format("/*** nonjsdoc long line */", getGoogleJSStyleWithColumns(20)));
+ EXPECT_EQ(
+ "/**strange long long\n"
+ " * line */",
+ format("/**strange long long line */", getGoogleJSStyleWithColumns(20)));
+ // Break the first line of a single line jsdoc comment if it just exceeds the
+ // column limit.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 123\n"
+ " */",
+ format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
+ // Break also if the leading indent of the first line is more than 1 column.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 123\n"
+ " */",
+ format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
+ // Break also if the leading indent of the first line is more than 1 column.
+ EXPECT_EQ("/**\n"
+ " * jsdoc line 123\n"
+ " */",
+ format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
+ // Break after the content of the last line.
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " */",
+ format("/**\n"
+ " * line 1\n"
+ " * line 2 */",
+ getGoogleJSStyleWithColumns(20)));
+ // Break both the content and after the content of the last line.
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line long long\n"
+ " * long\n"
+ " */",
+ format("/**\n"
+ " * line 1\n"
+ " * line long long long */",
+ getGoogleJSStyleWithColumns(20)));
+
+ // The comment block gets indented.
+ EXPECT_EQ("function f() {\n"
+ " /**\n"
+ " * comment about\n"
+ " * x\n"
+ " */\n"
+ " var x = 1;\n"
+ "}",
+ format("function f() {\n"
+ "/** comment about x */\n"
+ "var x = 1;\n"
+ "}",
+ getGoogleJSStyleWithColumns(20)));
+
+ // Don't break the first line of a single line short jsdoc comment pragma.
+ EXPECT_EQ("/** @returns j */",
+ format("/** @returns j */",
+ getGoogleJSStyleWithColumns(20)));
+
+ // Break a single line long jsdoc comment pragma.
+ EXPECT_EQ("/**\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** @returns {string} jsdoc line 12 */",
+ getGoogleJSStyleWithColumns(20)));
+
+ EXPECT_EQ("/**\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** @returns {string} jsdoc line 12 */",
+ getGoogleJSStyleWithColumns(20)));
+
+ EXPECT_EQ("/**\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** @returns {string} jsdoc line 12*/",
+ getGoogleJSStyleWithColumns(20)));
+
+ // Fix a multiline jsdoc comment ending in a comment pragma.
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " * @returns {string} jsdoc line 12\n"
+ " */",
+ format("/** line 1\n"
+ " * line 2\n"
+ " * @returns {string} jsdoc line 12 */",
+ getGoogleJSStyleWithColumns(20)));
+
+ EXPECT_EQ("/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " *\n"
+ " * @returns j\n"
+ " */",
+ format("/** line 1\n"
+ " * line 2\n"
+ " *\n"
+ " * @returns j */",
+ getGoogleJSStyleWithColumns(20)));
}
TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
@@ -131,12 +292,21 @@ TEST_F(FormatTestJS, ReservedWords) {
verifyFormat("x.case = 1;");
verifyFormat("x.interface = 1;");
verifyFormat("x.for = 1;");
- verifyFormat("x.of() = 1;");
- verifyFormat("x.in() = 1;");
- verifyFormat("x.let() = 1;");
- verifyFormat("x.var() = 1;");
- verifyFormat("x.for() = 1;");
- verifyFormat("x.as() = 1;");
+ verifyFormat("x.of();");
+ verifyFormat("of(null);");
+ verifyFormat("import {of} from 'x';");
+ verifyFormat("x.in();");
+ verifyFormat("x.let();");
+ verifyFormat("x.var();");
+ verifyFormat("x.for();");
+ verifyFormat("x.as();");
+ verifyFormat("x.instanceof();");
+ verifyFormat("x.switch();");
+ verifyFormat("x.case();");
+ verifyFormat("x.delete();");
+ verifyFormat("x.throw();");
+ verifyFormat("x.throws();");
+ verifyFormat("x.if();");
verifyFormat("x = {\n"
" a: 12,\n"
" interface: 1,\n"
@@ -147,6 +317,12 @@ TEST_F(FormatTestJS, ReservedWords) {
verifyFormat("var interface = 2;");
verifyFormat("interface = 2;");
verifyFormat("x = interface instanceof y;");
+ verifyFormat("interface Test {\n"
+ " x: string;\n"
+ " switch: string;\n"
+ " case: string;\n"
+ " default: string;\n"
+ "}\n");
}
TEST_F(FormatTestJS, ReservedWordsMethods) {
@@ -164,9 +340,21 @@ TEST_F(FormatTestJS, ReservedWordsMethods) {
"}\n");
}
+TEST_F(FormatTestJS, ReservedWordsParenthesized) {
+ // All of these are statements using the keyword, not function calls.
+ verifyFormat("throw (x + y);\n"
+ "await (await x).y;\n"
+ "typeof (x) === 'string';\n"
+ "void (0);\n"
+ "delete (x.y);\n"
+ "return (x);\n");
+}
+
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) {
@@ -314,6 +502,25 @@ TEST_F(FormatTestJS, MethodsInObjectLiterals) {
"};");
}
+TEST_F(FormatTestJS, GettersSettersVisibilityKeywords) {
+ // Don't break after "protected"
+ verifyFormat("class X {\n"
+ " protected get getter():\n"
+ " number {\n"
+ " return 1;\n"
+ " }\n"
+ "}",
+ getGoogleJSStyleWithColumns(12));
+ // Don't break after "get"
+ verifyFormat("class X {\n"
+ " protected get someReallyLongGetterName():\n"
+ " number {\n"
+ " return 1;\n"
+ " }\n"
+ "}",
+ getGoogleJSStyleWithColumns(40));
+}
+
TEST_F(FormatTestJS, SpacesInContainerLiterals) {
verifyFormat("var arr = [1, 2, 3];");
verifyFormat("f({a: 1, b: 2, c: 3});");
@@ -344,6 +551,25 @@ TEST_F(FormatTestJS, GoogScopes) {
"});");
}
+TEST_F(FormatTestJS, IIFEs) {
+ // Internal calling parens; no semi.
+ verifyFormat("(function() {\n"
+ "var a = 1;\n"
+ "}())");
+ // External calling parens; no semi.
+ verifyFormat("(function() {\n"
+ "var b = 2;\n"
+ "})()");
+ // Internal calling parens; with semi.
+ verifyFormat("(function() {\n"
+ "var c = 3;\n"
+ "}());");
+ // External calling parens; with semi.
+ verifyFormat("(function() {\n"
+ "var d = 4;\n"
+ "})();");
+}
+
TEST_F(FormatTestJS, GoogModules) {
verifyFormat("goog.module('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
@@ -353,8 +579,6 @@ TEST_F(FormatTestJS, GoogModules) {
getGoogleJSStyleWithColumns(40));
verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
- verifyFormat("goog.setTestOnly('this.is.really.absurdly.long');",
- getGoogleJSStyleWithColumns(40));
verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
@@ -362,6 +586,12 @@ TEST_F(FormatTestJS, GoogModules) {
verifyFormat(
"var MyLongClassName =\n"
" goog.module.get('my.long.module.name.followedBy.MyLongClassName');");
+ verifyFormat("function a() {\n"
+ " goog.setTestOnly();\n"
+ "}\n",
+ "function a() {\n"
+ "goog.setTestOnly();\n"
+ "}\n");
}
TEST_F(FormatTestJS, FormatsNamespaces) {
@@ -428,6 +658,15 @@ TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
" inner2(a, b);\n"
"}");
verifyFormat("function f() {}");
+ verifyFormat("function aFunction() {}\n"
+ "(function f() {\n"
+ " var x = 1;\n"
+ "}());\n");
+ verifyFormat("function aFunction() {}\n"
+ "{\n"
+ " let x = 1;\n"
+ " console.log(x);\n"
+ "}\n");
}
TEST_F(FormatTestJS, GeneratorFunctions) {
@@ -462,6 +701,20 @@ TEST_F(FormatTestJS, AsyncFunctions) {
" let x = 1;\n"
" return fetch(x);\n"
"}");
+ verifyFormat("async function f() {\n"
+ " return 1;\n"
+ "}\n"
+ "\n"
+ "function a() {\n"
+ " return 1;\n"
+ "}\n",
+ " async function f() {\n"
+ " return 1;\n"
+ "}\n"
+ "\n"
+ " function a() {\n"
+ " return 1;\n"
+ "} \n");
verifyFormat("async function* f() {\n"
" yield fetch(x);\n"
"}");
@@ -469,6 +722,9 @@ TEST_F(FormatTestJS, AsyncFunctions) {
" return fetch(x);\n"
"}");
verifyFormat("let x = async () => f();");
+ verifyFormat("let x = async function() {\n"
+ " f();\n"
+ "};");
verifyFormat("let x = async();");
verifyFormat("class X {\n"
" async asyncMethod() {\n"
@@ -479,6 +735,38 @@ TEST_F(FormatTestJS, AsyncFunctions) {
" // Comment.\n"
" return async.then();\n"
"}\n");
+ verifyFormat("for await (const x of y) {\n"
+ " console.log(x);\n"
+ "}\n");
+ verifyFormat("function asyncLoop() {\n"
+ " for await (const x of y) {\n"
+ " console.log(x);\n"
+ " }\n"
+ "}\n");
+}
+
+TEST_F(FormatTestJS, FunctionParametersTrailingComma) {
+ verifyFormat("function trailingComma(\n"
+ " p1,\n"
+ " p2,\n"
+ " p3,\n"
+ ") {\n"
+ " a; //\n"
+ "}\n",
+ "function trailingComma(p1, p2, p3,) {\n"
+ " a; //\n"
+ "}\n");
+ verifyFormat("trailingComma(\n"
+ " p1,\n"
+ " p2,\n"
+ " p3,\n"
+ ");\n",
+ "trailingComma(p1, p2, p3,);\n");
+ verifyFormat("trailingComma(\n"
+ " p1 // hello\n"
+ ");\n",
+ "trailingComma(p1 // hello\n"
+ ");\n");
}
TEST_F(FormatTestJS, ArrayLiterals) {
@@ -616,13 +904,18 @@ TEST_F(FormatTestJS, FunctionLiterals) {
" bar();\n"
"}.bind(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"
"})\n"
" .doSomethingElse(\n"
" // break\n"
- " );");
+ " );");
Style.ColumnLimit = 33;
verifyFormat("f({a: function() { return 1; }});", Style);
@@ -634,6 +927,15 @@ TEST_F(FormatTestJS, FunctionLiterals) {
}
+TEST_F(FormatTestJS, DontWrapEmptyLiterals) {
+ verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
+ " .and.returnValue(Observable.of([]));");
+ verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
+ " .and.returnValue(Observable.of({}));");
+ verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
+ " .and.returnValue(Observable.of(()));");
+}
+
TEST_F(FormatTestJS, InliningFunctionLiterals) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
@@ -789,7 +1091,10 @@ TEST_F(FormatTestJS, ArrowFunctions) {
"})\n"
" .doSomethingElse(\n"
" // break\n"
- " );");
+ " );");
+ verifyFormat("const f = (x: string|null): string|null => {\n"
+ " return x;\n"
+ "}\n");
}
TEST_F(FormatTestJS, ReturnStatements) {
@@ -825,6 +1130,18 @@ TEST_F(FormatTestJS, WrapRespectsAutomaticSemicolonInsertion) {
" aaa\n"
"];",
getGoogleJSStyleWithColumns(12));
+ verifyFormat("class X {\n"
+ " readonly ratherLongField =\n"
+ " 1;\n"
+ "}",
+ "class X {\n"
+ " readonly ratherLongField = 1;\n"
+ "}",
+ getGoogleJSStyleWithColumns(20));
+ verifyFormat("const x = (5 + 9)\n"
+ "const y = 3\n",
+ "const x = ( 5 + 9)\n"
+ "const y = 3\n");
}
TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
@@ -943,7 +1260,6 @@ TEST_F(FormatTestJS, TryCatch) {
// But, of course, "catch" is a perfectly fine function name in JavaScript.
verifyFormat("someObject.catch();");
verifyFormat("someObject.new();");
- verifyFormat("someObject.delete();");
}
TEST_F(FormatTestJS, StringLiteralConcatenation) {
@@ -1121,12 +1437,34 @@ TEST_F(FormatTestJS, UnionIntersectionTypes) {
verifyFormat("let x: Bar|Baz;");
verifyFormat("let x: Bar<X>|Baz;");
verifyFormat("let x: (Foo|Bar)[];");
+ verifyFormat("type X = {\n"
+ " a: Foo|Bar;\n"
+ "};");
+ verifyFormat("export type X = {\n"
+ " a: Foo|Bar;\n"
+ "};");
+}
+
+TEST_F(FormatTestJS, UnionIntersectionTypesInObjectType) {
+ verifyFormat("let x: {x: number|null} = {x: number | null};");
+ verifyFormat("let nested: {x: {y: number|null}};");
+ verifyFormat("let mixed: {x: [number|null, {w: number}]};");
+ verifyFormat("class X {\n"
+ " contructor(x: {\n"
+ " a: a|null,\n"
+ " b: b|null,\n"
+ " }) {}\n"
+ "}");
}
TEST_F(FormatTestJS, ClassDeclarations) {
verifyFormat("class C {\n x: string = 12;\n}");
verifyFormat("class C {\n x(): string => 12;\n}");
verifyFormat("class C {\n ['x' + 2]: string = 12;\n}");
+ verifyFormat("class C {\n"
+ " foo() {}\n"
+ " [bar]() {}\n"
+ "}\n");
verifyFormat("class C {\n private x: string = 12;\n}");
verifyFormat("class C {\n private static x: string = 12;\n}");
verifyFormat("class C {\n static x(): string {\n return 'asd';\n }\n}");
@@ -1184,6 +1522,17 @@ TEST_F(FormatTestJS, InterfaceDeclarations) {
"}");
}
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+ verifyFormat("class C extends {} {}");
+ verifyFormat("class C implements {bar: number} {}");
+ // Somewhat odd, but probably closest to reasonable formatting?
+ verifyFormat("class C implements {\n"
+ " bar: number,\n"
+ " baz: string,\n"
+ "} {}");
+ verifyFormat("class C<P extends {}> {}");
+}
+
TEST_F(FormatTestJS, EnumDeclarations) {
verifyFormat("enum Foo {\n"
" A = 1,\n"
@@ -1198,6 +1547,14 @@ TEST_F(FormatTestJS, EnumDeclarations) {
" B\n"
"}\n"
"var x = 1;");
+ verifyFormat("const enum Foo {\n"
+ " A = 1,\n"
+ " B\n"
+ "}");
+ verifyFormat("export const enum Foo {\n"
+ " A = 1,\n"
+ " B\n"
+ "}");
}
TEST_F(FormatTestJS, MetadataAnnotations) {
@@ -1216,6 +1573,9 @@ TEST_F(FormatTestJS, MetadataAnnotations) {
"}");
verifyFormat("class X {}\n"
"class Y {}");
+ verifyFormat("class X {\n"
+ " @property() private isReply = false;\n"
+ "}\n");
}
TEST_F(FormatTestJS, TypeAliases) {
@@ -1226,6 +1586,10 @@ TEST_F(FormatTestJS, TypeAliases) {
" y: number\n"
"};\n"
"class C {}");
+ verifyFormat("export type X = {\n"
+ " a: string,\n"
+ " b?: string,\n"
+ "};\n");
}
TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
@@ -1338,6 +1702,17 @@ TEST_F(FormatTestJS, ImportWrapping) {
" A,\n"
"} from 'some/module.js';",
Style);
+ Style.ColumnLimit = 40;
+ // Using this version of verifyFormat because test::messUp hides the issue.
+ verifyFormat("import {\n"
+ " A,\n"
+ "} from\n"
+ " 'some/path/longer/than/column/limit/module.js';",
+ " import { \n"
+ " A, \n"
+ " } from\n"
+ " 'some/path/longer/than/column/limit/module.js' ; ",
+ Style);
}
TEST_F(FormatTestJS, TemplateStrings) {
@@ -1443,32 +1818,28 @@ TEST_F(FormatTestJS, TemplateStrings) {
verifyFormat("var x = someFunction(`${})`) //\n"
" .oooooooooooooooooon();");
verifyFormat("var x = someFunction(`${aaaa}${\n"
- " aaaaa( //\n"
- " aaaaa)\n"
- " })`);");
+ " aaaaa( //\n"
+ " aaaaa)})`);");
}
TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${\n"
- " aaaaa + //\n"
- " bbbb\n"
- " }`;",
+ " aaaaa + //\n"
+ " bbbb}`;",
"var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa + //\n"
" bbbb}`;");
verifyFormat("var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${\n"
- " aaaaa + //\n"
- " bbbb\n"
- " }`;",
+ " aaaaa + //\n"
+ " bbbb}`;",
"var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${ aaaaa + //\n"
" bbbb }`;");
verifyFormat("var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${\n"
- " someFunction(\n"
- " aaaaa + //\n"
- " bbbb)\n"
- " }`;",
+ " someFunction(\n"
+ " aaaaa + //\n"
+ " bbbb)}`;",
"var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${someFunction (\n"
" aaaaa + //\n"
@@ -1477,9 +1848,9 @@ TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
// It might be preferable to wrap before "someFunction".
verifyFormat("var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${someFunction({\n"
- " aaaa: aaaaa,\n"
- " bbbb: bbbbb,\n"
- " })}`;",
+ " aaaa: aaaaa,\n"
+ " bbbb: bbbbb,\n"
+ "})}`;",
"var f = `\n"
" aaaaaaaaaaaaaaaaaa: ${someFunction ({\n"
" aaaa: aaaaa,\n"
@@ -1504,6 +1875,7 @@ TEST_F(FormatTestJS, NestedTemplateStrings) {
TEST_F(FormatTestJS, TaggedTemplateStrings) {
verifyFormat("var x = html`<ul>`;");
+ verifyFormat("yield `hello`;");
}
TEST_F(FormatTestJS, CastSyntax) {
@@ -1719,6 +2091,11 @@ TEST_F(FormatTestJS, NonNullAssertionOperator) {
verifyFormat("let x = !foo;\n");
verifyFormat("let x = foo[0]!;\n");
verifyFormat("let x = (foo)!;\n");
+ verifyFormat("let x = x(foo!);\n");
+ verifyFormat(
+ "a.aaaaaa(a.a!).then(\n"
+ " x => x(x));\n",
+ getGoogleJSStyleWithColumns(20));
verifyFormat("let x = foo! - 1;\n");
verifyFormat("let x = {foo: 1}!;\n");
verifyFormat(
@@ -1727,6 +2104,8 @@ TEST_F(FormatTestJS, NonNullAssertionOperator) {
" .foo()!\n"
" .foo()!;\n",
getGoogleJSStyleWithColumns(20));
+ verifyFormat("let x = namespace!;\n");
+ verifyFormat("return !!x;\n");
}
TEST_F(FormatTestJS, Conditional) {
@@ -1742,6 +2121,74 @@ TEST_F(FormatTestJS, ImportComments) {
verifyFormat("import {x} from 'x'; // from some location",
getGoogleJSStyleWithColumns(25));
verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10));
+ verifyFormat("/// <reference path=\"some/location\" />", getGoogleJSStyleWithColumns(10));
+}
+
+TEST_F(FormatTestJS, Exponentiation) {
+ verifyFormat("squared = x ** 2;");
+ verifyFormat("squared **= 2;");
+}
+
+TEST_F(FormatTestJS, NestedLiterals) {
+ FormatStyle FourSpaces = getGoogleJSStyleWithColumns(15);
+ FourSpaces.IndentWidth = 4;
+ verifyFormat("var l = [\n"
+ " [\n"
+ " 1,\n"
+ " ],\n"
+ "];", FourSpaces);
+ verifyFormat("var l = [\n"
+ " {\n"
+ " 1: 1,\n"
+ " },\n"
+ "];", FourSpaces);
+ verifyFormat("someFunction(\n"
+ " p1,\n"
+ " [\n"
+ " 1,\n"
+ " ],\n"
+ ");", FourSpaces);
+ verifyFormat("someFunction(\n"
+ " p1,\n"
+ " {\n"
+ " 1: 1,\n"
+ " },\n"
+ ");", FourSpaces);
+ verifyFormat("var o = {\n"
+ " 1: 1,\n"
+ " 2: {\n"
+ " 3: 3,\n"
+ " },\n"
+ "};", FourSpaces);
+ verifyFormat("var o = {\n"
+ " 1: 1,\n"
+ " 2: [\n"
+ " 3,\n"
+ " ],\n"
+ "};", FourSpaces);
}
+
+TEST_F(FormatTestJS, BackslashesInComments) {
+ verifyFormat("// hello \\\n"
+ "if (x) foo();\n",
+ "// hello \\\n"
+ " if ( x) \n"
+ " foo();\n");
+ verifyFormat("/* ignore \\\n"
+ " */\n"
+ "if (x) foo();\n",
+ "/* ignore \\\n"
+ " */\n"
+ " if ( x) foo();\n");
+ verifyFormat("// st \\ art\\\n"
+ "// comment"
+ "// continue \\\n"
+ "formatMe();\n",
+ "// st \\ art\\\n"
+ "// comment"
+ "// continue \\\n"
+ "formatMe( );\n");
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestJava.cpp b/unittests/Format/FormatTestJava.cpp
index ee09ca940f..2f376f765d 100644
--- a/unittests/Format/FormatTestJava.cpp
+++ b/unittests/Format/FormatTestJava.cpp
@@ -237,7 +237,10 @@ TEST_F(FormatTestJava, EnumDeclarations) {
TEST_F(FormatTestJava, ArrayInitializers) {
verifyFormat("new int[] {1, 2, 3, 4};");
verifyFormat("new int[] {\n"
- " 1, 2, 3, 4,\n"
+ " 1,\n"
+ " 2,\n"
+ " 3,\n"
+ " 4,\n"
"};");
FormatStyle Style = getStyleWithColumns(65);
@@ -330,6 +333,11 @@ TEST_F(FormatTestJava, Generics) {
verifyFormat("Iterable<? extends SomeObject> a;");
verifyFormat("A.<B>doSomething();");
+ verifyFormat("A.<B<C>>doSomething();");
+ verifyFormat("A.<B<C<D>>>doSomething();");
+ verifyFormat("A.<B<C<D<E>>>>doSomething();");
+
+ verifyFormat("OrderedPair<String, List<Box<Integer>>> p = null;");
verifyFormat("@Override\n"
"public Map<String, ?> getAll() {}");
@@ -409,6 +417,7 @@ TEST_F(FormatTestJava, SynchronizedKeyword) {
TEST_F(FormatTestJava, AssertKeyword) {
verifyFormat("assert a && b;");
+ verifyFormat("assert (a && b);");
}
TEST_F(FormatTestJava, PackageDeclarations) {
@@ -522,5 +531,26 @@ TEST_F(FormatTestJava, AlignsBlockComments) {
" void f() {}"));
}
+TEST_F(FormatTestJava, KeepsDelimitersOnOwnLineInJavaDocComments) {
+ EXPECT_EQ("/**\n"
+ " * javadoc line 1\n"
+ " * javadoc line 2\n"
+ " */",
+ format("/** javadoc line 1\n"
+ " * javadoc line 2 */"));
+}
+
+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 680ff92f75..1f9fc451d2 100644
--- a/unittests/Format/FormatTestObjC.cpp
+++ b/unittests/Format/FormatTestObjC.cpp
@@ -20,7 +20,6 @@
#define DEBUG_TYPE "format-test"
using clang::tooling::ReplacementTest;
-using clang::tooling::toReplacements;
namespace clang {
namespace format {
@@ -33,23 +32,24 @@ protected:
Style.Language = FormatStyle::LK_ObjC;
}
- enum IncompleteCheck {
- IC_ExpectComplete,
- IC_ExpectIncomplete,
- IC_DoNotCheck
+ enum StatusCheck {
+ SC_ExpectComplete,
+ SC_ExpectIncomplete,
+ SC_DoNotCheck
};
std::string format(llvm::StringRef Code,
- IncompleteCheck CheckIncomplete = IC_ExpectComplete) {
+ StatusCheck CheckComplete = SC_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;
+ FormattingAttemptStatus Status;
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";
+ reformat(Style, Code, Ranges, "<stdin>", &Status);
+ if (CheckComplete != SC_DoNotCheck) {
+ bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
+ EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
+ << Code << "\n\n";
}
auto Result = applyAllReplacements(Code, Replaces);
EXPECT_TRUE(static_cast<bool>(Result));
@@ -62,7 +62,7 @@ protected:
}
void verifyIncompleteFormat(StringRef Code) {
- EXPECT_EQ(Code.str(), format(test::messUp(Code), IC_ExpectIncomplete));
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), SC_ExpectIncomplete));
}
FormatStyle Style;
diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp
index d174c65a1f..df94d81727 100644
--- a/unittests/Format/FormatTestProto.cpp
+++ b/unittests/Format/FormatTestProto.cpp
@@ -61,6 +61,29 @@ TEST_F(FormatTestProto, FormatsMessages) {
" really.really.long.qualified.type.aaa.aaaaaaa.aaaaaaaa\n"
" another_fiiiiiiiiiiiiiiiiiiiiield = 2;\n"
"}");
+ verifyFormat("message SomeMessage {\n"
+ " map<string, Project> projects = 1;\n"
+ " optional map<string, int32> size_projects = 2;\n"
+ " map<int, really.really.really.long.qualified.type.nameeee>\n"
+ " projects = 3;\n"
+ " map<int, really.really.really.really.long.qualified.type\n"
+ " .nameeee> projects = 4;\n"
+ " map<int,\n"
+ " reallyreallyreallyreallyreallyreallyreallylongname>\n"
+ " projects = 5;\n"
+ " map<int, Project>\n"
+ " longlonglonglonglonglonglonglonglonglongonglon = 6;\n"
+ " map<releleallyreallyreallyreallyreallyreallyreallylongname,\n"
+ " int> projects = 7;\n"
+ " map<releleallyreallyreallyreallyreallyreallyreallylongname,\n"
+ " releleallyreallyreallyreallyreallyreallyreallylongname>\n"
+ " releleallyreallyreallyreallyreallyreallyreallylongnam =\n"
+ " 8;\n"
+ " map<relele.llyreal.yreallyr.allyreally.eallyreal\n"
+ " .sauenirylongname,\n"
+ " really.really.really.really.long.qualified.type\n"
+ " .nameeee> projects = 9;\n"
+ "}");
}
TEST_F(FormatTestProto, KeywordsInOtherLanguages) {
@@ -176,14 +199,181 @@ TEST_F(FormatTestProto, FormatsOptions) {
"};");
verifyFormat("option (MyProto.options) = {\n"
" field_c: \"OK\"\n"
- " msg_field{field_d: 123}\n"
+ " msg_field {field_d: 123}\n"
"};");
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_a: OK\n"
+ " field_b {field_c: OK}\n"
+ " field_d: OKOKOK\n"
+ " field_e: OK\n"
+ "}");
// Support syntax with <> instead of {}.
verifyFormat("option (MyProto.options) = {\n"
" field_c: \"OK\",\n"
" msg_field: <field_d: 123>\n"
"};");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_a: OK\n"
+ " field_b <field_c: OK>\n"
+ " field_d: OKOKOK\n"
+ " field_e: OK\n"
+ "}");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " msg_field: <>\n"
+ " field_c: \"OK\",\n"
+ " msg_field: <field_d: 123>\n"
+ " field_e: OK\n"
+ " msg_field: <field_d: 12>\n"
+ "};");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: OK\n"
+ " field_b: \"OK\"\n"
+ " field_c: 1\n"
+ " field_d: 12.5\n"
+ " field_e: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: OK,\n"
+ " field_b: \"OK\",\n"
+ " field_c: 1,\n"
+ " field_d: 12.5,\n"
+ " field_e: OK,\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: \"OK\"\n"
+ " msg_field: {field_b: OK}\n"
+ " field_g: OK\n"
+ " field_g: OK\n"
+ " field_g: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: \"OK\"\n"
+ " msg_field <\n"
+ " field_b: OK\n"
+ " field_c: OK\n"
+ " field_d: OK\n"
+ " field_e: OK\n"
+ " field_f: OK\n"
+ " >\n"
+ " field_g: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: \"OK\"\n"
+ " msg_field <\n"
+ " field_b: OK,\n"
+ " field_c: OK,\n"
+ " field_d: OK,\n"
+ " field_e: OK,\n"
+ " field_f: OK\n"
+ " >\n"
+ " field_g: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: \"OK\"\n"
+ " msg_field: <\n"
+ " field_b: OK\n"
+ " field_c: OK\n"
+ " field_d: OK\n"
+ " field_e: OK\n"
+ " field_f: OK\n"
+ " >\n"
+ " field_g: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: \"OK\"\n"
+ " msg_field: {\n"
+ " field_b: OK\n"
+ " field_c: OK\n"
+ " field_d: OK\n"
+ " field_e: OK\n"
+ " field_f: OK\n"
+ " }\n"
+ " field_g: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: \"OK\"\n"
+ " msg_field {\n"
+ " field_b: OK\n"
+ " field_c: OK\n"
+ " field_d: OK\n"
+ " field_e: OK\n"
+ " field_f: OK\n"
+ " }\n"
+ " field_g: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_a: \"OK\"\n"
+ " msg_field <\n"
+ " field_b: OK\n"
+ " field_c: OK\n"
+ " field_d: OK\n"
+ " field_e: OK\n"
+ " field_f: OK\n"
+ " >\n"
+ " field_g: OK\n"
+ "};");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " field_a: \"OK\"\n"
+ " msg_field: <\n"
+ " field_b: OK\n"
+ " field_c: OK\n"
+ " field_d: OK\n"
+ " field_e: OK\n"
+ " field_f: OK\n"
+ " >\n"
+ " field_g: OK\n"
+ "};");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " field_a: \"OK\"\n"
+ " msg_field {\n"
+ " field_b: OK\n"
+ " field_c: OK\n"
+ " field_d: OK\n"
+ " msg_field <\n"
+ " field_A: 1\n"
+ " field_B: 2\n"
+ " field_C: 3\n"
+ " field_D: 4\n"
+ " field_E: 5\n"
+ " >\n"
+ " msg_field <field_A: 1 field_B: 2 field_C: 3 field_D: 4>\n"
+ " field_e: OK\n"
+ " field_f: OK\n"
+ " }\n"
+ " field_g: OK\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " data1 <key1: value1>\n"
+ " data2 {key2: value2}\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = <\n"
+ " app_id: 'com.javax.swing.salsa.latino'\n"
+ " head_id: 1\n"
+ " data <key: value>\n"
+ ">;");
+
+ verifyFormat("option (MyProto.options) = {\n"
+ " app_id: 'com.javax.swing.salsa.latino'\n"
+ " head_id: 1\n"
+ " headheadheadheadheadhead_id: 1\n"
+ " product_data {product {1}}\n"
+ "};");
}
TEST_F(FormatTestProto, FormatsService) {
diff --git a/unittests/Format/FormatTestRawStrings.cpp b/unittests/Format/FormatTestRawStrings.cpp
new file mode 100644
index 0000000000..6e7b706587
--- /dev/null
+++ b/unittests/Format/FormatTestRawStrings.cpp
@@ -0,0 +1,733 @@
+//===- unittest/Format/FormatTestRawStrings.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;
+using clang::tooling::toReplacements;
+
+namespace clang {
+namespace format {
+namespace {
+
+class FormatTestRawStrings : public ::testing::Test {
+protected:
+ enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck };
+
+ std::string format(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle(),
+ StatusCheck CheckComplete = SC_ExpectComplete) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+ FormattingAttemptStatus Status;
+ tooling::Replacements Replaces =
+ reformat(Style, Code, Ranges, "<stdin>", &Status);
+ if (CheckComplete != SC_DoNotCheck) {
+ bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
+ EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
+ << 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 getStyleWithColumns(FormatStyle Style, unsigned ColumnLimit) {
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
+ return getStyleWithColumns(getLLVMStyle(), ColumnLimit);
+ }
+
+ int ReplacementCount;
+
+ FormatStyle getRawStringPbStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getLLVMStyle();
+ Style.ColumnLimit = ColumnLimit;
+ Style.RawStringFormats = {{/*Delimiter=*/"pb",
+ /*Kind=*/FormatStyle::LK_TextProto,
+ /*BasedOnStyle=*/"google"}};
+ return Style;
+ }
+
+ FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) {
+ FormatStyle Style = getLLVMStyle();
+ Style.RawStringFormats = {{/*Delimiter=*/"cpp",
+ /*Kind=*/FormatStyle::LK_Cpp, BasedOnStyle}};
+ return Style;
+ }
+
+ FormatStyle getRawStringGoogleCppStyleBasedOn(std::string BasedOnStyle) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
+ Style.RawStringFormats = {{/*Delimiter=*/"cpp",
+ /*Kind=*/FormatStyle::LK_Cpp, BasedOnStyle}};
+ return Style;
+ }
+
+ // Gcc 4.8 doesn't support raw string literals in macros, which breaks some
+ // build bots. We use this function instead.
+ void expect_eq(const std::string Expected, const std::string Actual) {
+ EXPECT_EQ(Expected, Actual);
+ }
+};
+
+TEST_F(FormatTestRawStrings, ReformatsAccordingToBaseStyle) {
+ // llvm style puts '*' on the right.
+ // google style puts '*' on the left.
+
+ // Use the llvm style if the raw string style has no BasedOnStyle.
+ expect_eq(R"test(int *i = R"cpp(int *p = nullptr;)cpp")test",
+ format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
+ getRawStringLLVMCppStyleBasedOn("")));
+
+ // Use the google style if the raw string style has BasedOnStyle=google.
+ expect_eq(R"test(int *i = R"cpp(int* p = nullptr;)cpp")test",
+ format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
+ getRawStringLLVMCppStyleBasedOn("google")));
+
+ // Use the llvm style if the raw string style has no BasedOnStyle=llvm.
+ expect_eq(R"test(int* i = R"cpp(int *p = nullptr;)cpp")test",
+ format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
+ getRawStringGoogleCppStyleBasedOn("llvm")));
+}
+
+TEST_F(FormatTestRawStrings, MatchesDelimitersCaseSensitively) {
+ // Don't touch the 'PB' raw string, format the 'pb' raw string.
+ expect_eq(R"test(
+s = R"PB(item:1)PB";
+t = R"pb(item: 1)pb";)test",
+ format(R"test(
+s = R"PB(item:1)PB";
+t = R"pb(item:1)pb";)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ FormatStyle MixedStyle = getLLVMStyle();
+ MixedStyle.RawStringFormats = {
+ {/*Delimiter=*/"cpp", /*Kind=*/FormatStyle::LK_Cpp,
+ /*BasedOnStyle=*/"llvm"},
+ {/*Delimiter=*/"CPP", /*Kind=*/FormatStyle::LK_Cpp,
+ /*BasedOnStyle=*/"google"}};
+
+ // Format the 'cpp' raw string with '*' on the right.
+ // Format the 'CPP' raw string with '*' on the left.
+ // Do not format the 'Cpp' raw string.
+ // Do not format non-raw strings.
+ expect_eq(R"test(
+a = R"cpp(int *i = 0;)cpp";
+b = R"CPP(int* j = 0;)CPP";
+c = R"Cpp(int * k = 0;)Cpp";
+d = R"cpp(int * k = 0;)Cpp";)test",
+ format(R"test(
+a = R"cpp(int * i = 0;)cpp";
+b = R"CPP(int * j = 0;)CPP";
+c = R"Cpp(int * k = 0;)Cpp";
+d = R"cpp(int * k = 0;)Cpp";)test",
+ MixedStyle));
+}
+
+TEST_F(FormatTestRawStrings, ReformatsShortRawStringsOnSingleLine) {
+ expect_eq(
+ R"test(P p = TP(R"pb()pb");)test",
+ format(
+ R"test(P p = TP(R"pb( )pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+ expect_eq(
+ R"test(P p = TP(R"pb(item_1: 1)pb");)test",
+ format(
+ R"test(P p = TP(R"pb(item_1:1)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+ expect_eq(
+ R"test(P p = TP(R"pb(item_1: 1)pb");)test",
+ format(
+ R"test(P p = TP(R"pb( item_1 : 1 )pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+ expect_eq(
+ R"test(P p = TP(R"pb(item_1: 1 item_2: 2)pb");)test",
+ format(
+ R"test(P p = TP(R"pb(item_1:1 item_2:2)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+ expect_eq(
+ R"test(P p = TP(R"pb(item_1 <1> item_2: {2})pb");)test",
+ format(
+ R"test(P p = TP(R"pb(item_1<1> item_2:{2})pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Merge two short lines into one.
+ expect_eq(R"test(
+std::string s = R"pb(
+ item_1: 1 item_2: 2
+)pb";
+)test",
+ format(R"test(
+std::string s = R"pb(
+ item_1:1
+ item_2:2
+)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, BreaksRawStringsExceedingColumnLimit) {
+ expect_eq(R"test(
+P p = TPPPPPPPPPPPPPPP(
+ R"pb(item_1: 1, item_2: 2)pb");)test",
+ format(R"test(
+P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+P p =
+ TPPPPPPPPPPPPPPP(
+ R"pb(item_1: 1,
+ item_2: 2,
+ item_3: 3)pb");)test",
+ format(R"test(
+P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2, item_3: 3)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+P p = TP(R"pb(item_1 <1>
+ item_2: <2>
+ item_3 {})pb");)test",
+ format(R"test(
+P p = TP(R"pb(item_1<1> item_2:<2> item_3{ })pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(
+ R"test(
+P p = TP(R"pb(item_1: 1,
+ item_2: 2,
+ item_3: 3,
+ item_4: 4)pb");)test",
+ format(
+ R"test(
+P p = TP(R"pb(item_1: 1, item_2: 2, item_3: 3, item_4: 4)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+P p = TPPPPPPPPPPPPPPP(
+ R"pb(item_1 <1>,
+ item_2: {2},
+ item_3: <3>,
+ item_4: {4})pb");)test",
+ format(R"test(
+P p = TPPPPPPPPPPPPPPP(R"pb(item_1<1>, item_2: {2}, item_3: <3>, item_4:{4})pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Breaks before a short raw string exceeding the column limit.
+ expect_eq(R"test(
+FFFFFFFFFFFFFFFFFFFFFFFFFFF(
+ R"pb(key: 1)pb");
+P p = TPPPPPPPPPPPPPPPPPPPP(
+ R"pb(key: 2)pb");
+auto TPPPPPPPPPPPPPPPPPPPP =
+ R"pb(key: 3)pb";
+P p = TPPPPPPPPPPPPPPPPPPPP(
+ R"pb(i: 1, j: 2)pb");
+
+int f(string s) {
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF(
+ R"pb(key: 1)pb");
+ P p = TPPPPPPPPPPPPPPPPPPPP(
+ R"pb(key: 2)pb");
+ auto TPPPPPPPPPPPPPPPPPPPP =
+ R"pb(key: 3)pb";
+ if (s.empty())
+ P p = TPPPPPPPPPPPPPPPPPPPP(
+ R"pb(i: 1, j: 2)pb");
+}
+)test",
+ format(R"test(
+FFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb");
+P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb");
+auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb";
+P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb");
+
+int f(string s) {
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb");
+ P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb");
+ auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb";
+ if (s.empty())
+ P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb");
+}
+)test",
+ getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, FormatsRawStringArguments) {
+ expect_eq(R"test(
+P p = TP(R"pb(key {1})pb", param_2);)test",
+ format(R"test(
+P p = TP(R"pb(key{1})pb",param_2);)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+PPPPPPPPPPPPP(R"pb(keykeyk)pb",
+ param_2);)test",
+ format(R"test(
+PPPPPPPPPPPPP(R"pb(keykeyk)pb", param_2);)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+P p =
+ TP(R"pb(item: {i: 1, s: 's'}
+ item: {i: 2, s: 't'})pb");)test",
+ format(R"test(
+P p = TP(R"pb(item: {i: 1, s: 's'} item: {i: 2, s: 't'})pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+ expect_eq(R"test(
+FFFFFFFFFFFFFFFFFFF(
+ R"pb(key: "value")pb",
+ R"pb(key2: "value")pb");)test",
+ format(R"test(
+FFFFFFFFFFFFFFFFFFF(R"pb(key: "value")pb", R"pb(key2: "value")pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Formats the first out of two arguments.
+ expect_eq(R"test(
+FFFFFFFF(R"pb(key: 1)pb", argument2);
+struct S {
+ const s =
+ f(R"pb(key: 1)pb", argument2);
+ void f() {
+ if (gol)
+ return g(R"pb(key: 1)pb",
+ 132789237);
+ return g(R"pb(key: 1)pb", "172893");
+ }
+};)test",
+ format(R"test(
+FFFFFFFF(R"pb(key:1)pb", argument2);
+struct S {
+const s = f(R"pb(key:1)pb", argument2);
+void f() {
+ if (gol)
+ return g(R"pb(key:1)pb", 132789237);
+ return g(R"pb(key:1)pb", "172893");
+}
+};)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Formats the second out of two arguments.
+ expect_eq(R"test(
+FFFFFFFF(argument1, R"pb(key: 2)pb");
+struct S {
+ const s =
+ f(argument1, R"pb(key: 2)pb");
+ void f() {
+ if (gol)
+ return g(12784137,
+ R"pb(key: 2)pb");
+ return g(17283122, R"pb(key: 2)pb");
+ }
+};)test",
+ format(R"test(
+FFFFFFFF(argument1, R"pb(key:2)pb");
+struct S {
+const s = f(argument1, R"pb(key:2)pb");
+void f() {
+ if (gol)
+ return g(12784137, R"pb(key:2)pb");
+ return g(17283122, R"pb(key:2)pb");
+}
+};)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Formats two short raw string arguments.
+ expect_eq(R"test(
+FFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test",
+ format(R"test(
+FFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+ // TODO(krasimir): The original source code fits on one line, so the
+ // non-optimizing formatter is chosen. But after the formatting in protos is
+ // made, the code doesn't fit on one line anymore and further formatting
+ // splits it.
+ //
+ // Should we disable raw string formatting for the non-optimizing formatter?
+ expect_eq(R"test(
+FFFFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test",
+ format(R"test(
+FFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Formats two short raw string arguments, puts second on newline.
+ expect_eq(R"test(
+FFFFFFFF(R"pb(key: 1)pb",
+ R"pb(key: 2)pb");)test",
+ format(R"test(
+FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Formats both arguments.
+ expect_eq(R"test(
+FFFFFFFF(R"pb(key: 1)pb",
+ R"pb(key: 2)pb");
+struct S {
+ const s = f(R"pb(key: 1)pb",
+ R"pb(key: 2)pb");
+ void f() {
+ if (gol)
+ return g(R"pb(key: 1)pb",
+ R"pb(key: 2)pb");
+ return g(R"pb(k1)pb", R"pb(k2)pb");
+ }
+};)test",
+ format(R"test(
+FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");
+struct S {
+const s = f(R"pb(key:1)pb", R"pb(key:2)pb");
+void f() {
+ if (gol)
+ return g(R"pb(key:1)pb", R"pb(key:2)pb");
+ return g(R"pb( k1 )pb", R"pb( k2 )pb");
+}
+};)test",
+ getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, RawStringStartingWithNewlines) {
+ expect_eq(R"test(
+std::string s = R"pb(
+ item_1: 1
+)pb";
+)test",
+ format(R"test(
+std::string s = R"pb(
+ item_1:1
+)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+std::string s = R"pb(
+
+ item_1: 1
+)pb";
+)test",
+ format(R"test(
+std::string s = R"pb(
+
+ item_1:1
+)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+std::string s = R"pb(
+ item_1: 1
+)pb";
+)test",
+ format(R"test(
+std::string s = R"pb(
+ item_1:1
+
+)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+std::string s = R"pb(
+ item_1: 1,
+ item_2: 2
+)pb";
+)test",
+ format(R"test(
+std::string s = R"pb(
+ item_1:1, item_2:2
+)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+std::string s = R"pb(
+ book {
+ title: "Alice's Adventures"
+ author: "Lewis Caroll"
+ }
+ book {
+ title: "Peter Pan"
+ author: "J. M. Barrie"
+ }
+)pb";
+)test",
+ format(R"test(
+std::string s = R"pb(
+ book { title: "Alice's Adventures" author: "Lewis Caroll" }
+ book { title: "Peter Pan" author: "J. M. Barrie" }
+)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, BreaksBeforeRawStrings) {
+ expect_eq(R"test(
+ASSERT_TRUE(
+ ParseFromString(R"pb(item_1: 1)pb"),
+ ptr);)test",
+ format(R"test(
+ASSERT_TRUE(ParseFromString(R"pb(item_1: 1)pb"), ptr);)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+ASSERT_TRUE(toolong::ParseFromString(
+ R"pb(item_1: 1)pb"),
+ ptr);)test",
+ format(R"test(
+ASSERT_TRUE(toolong::ParseFromString(R"pb(item_1: 1)pb"), ptr);)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+ASSERT_TRUE(ParseFromString(
+ R"pb(item_1: 1,
+ item_2: 2)pb"),
+ ptr);)test",
+ format(R"test(
+ASSERT_TRUE(ParseFromString(R"pb(item_1: 1, item_2: 2)pb"), ptr);)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+ASSERT_TRUE(
+ ParseFromString(
+ R"pb(item_1: 1 item_2: 2)pb"),
+ ptr);)test",
+ format(R"test(
+ASSERT_TRUE(ParseFromString(R"pb(item_1: 1 item_2: 2)pb"), ptr);)test",
+ getRawStringPbStyleWithColumns(40)));
+
+}
+
+TEST_F(FormatTestRawStrings, RawStringsInOperands) {
+ // Formats the raw string first operand of a binary operator expression.
+ expect_eq(R"test(auto S = R"pb(item_1: 1)pb" + rest;)test",
+ format(R"test(auto S = R"pb(item_1:1)pb" + rest;)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = R"pb(item_1: 1, item_2: 2)pb" +
+ rest;)test",
+ format(R"test(
+auto S = R"pb(item_1:1,item_2:2)pb"+rest;)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S =
+ R"pb(item_1: 1 item_2: 2)pb" + rest;)test",
+ format(R"test(
+auto S = R"pb(item_1:1 item_2:2)pb"+rest;)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+ item_2: 2,
+ item_3: 3)pb" + rest;)test",
+ format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+ item_2: 2,
+ item_3: 3)pb" +
+ longlongrest;)test",
+ format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Formats the raw string second operand of a binary operator expression.
+ expect_eq(R"test(auto S = first + R"pb(item_1: 1)pb";)test",
+ format(R"test(auto S = first + R"pb(item_1:1)pb";)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = first + R"pb(item_1: 1,
+ item_2: 2)pb";)test",
+ format(R"test(
+auto S = first+R"pb(item_1:1,item_2:2)pb";)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = first + R"pb(item_1: 1
+ item_2: 2)pb";)test",
+ format(R"test(
+auto S = first+R"pb(item_1:1 item_2:2)pb";)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+ item_2: 2,
+ item_3: 3)pb" + rest;)test",
+ format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+ item_2: 2,
+ item_3: 3)pb" +
+ longlongrest;)test",
+ format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ // Formats the raw string operands in expressions.
+ expect_eq(R"test(
+auto S = R"pb(item_1: 1)pb" +
+ R"pb(item_2: 2)pb";
+)test",
+ format(R"test(
+auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = R"pb(item_1: 1)pb" +
+ R"pb(item_2: 2)pb" +
+ R"pb(item_3: 3)pb";
+)test",
+ format(R"test(
+auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb"+R"pb(item_3:3)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S = (count < 3)
+ ? R"pb(item_1: 1)pb"
+ : R"pb(item_2: 2)pb";
+)test",
+ format(R"test(
+auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S =
+ (count < 3)
+ ? R"pb(item_1: 1, item_2: 2)pb"
+ : R"pb(item_3: 3)pb";
+)test",
+ format(R"test(
+auto S=(count<3)?R"pb(item_1:1,item_2:2)pb":R"pb(item_3:3)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+ expect_eq(R"test(
+auto S =
+ (count < 3)
+ ? R"pb(item_1: 1)pb"
+ : R"pb(item_2: 2, item_3: 3)pb";
+)test",
+ format(R"test(
+auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2,item_3:3)pb";
+)test",
+ getRawStringPbStyleWithColumns(40)));
+
+}
+
+TEST_F(FormatTestRawStrings, PrefixAndSuffixAlignment) {
+ // Keep the suffix at the end of line if not on newline.
+ expect_eq(R"test(
+int s() {
+ auto S = PTP(
+ R"pb(
+ item_1: 1,
+ item_2: 2)pb");
+})test",
+ format(R"test(
+int s() {
+ auto S = PTP(
+ R"pb(
+ item_1: 1,
+ item_2: 2)pb");
+})test",
+ getRawStringPbStyleWithColumns(20)));
+
+ // Align the suffix with the surrounding FirstIndent if the prefix is not on
+ // a line of its own.
+ expect_eq(R"test(
+int s() {
+ auto S = PTP(
+ R"pb(
+ item_1: 1,
+ item_2: 2
+ )pb");
+})test",
+ format(R"test(
+int s() {
+ auto S = PTP(R"pb(
+ item_1: 1,
+ item_2: 2
+ )pb");
+})test",
+ getRawStringPbStyleWithColumns(20)));
+
+ // Align the prefix with the suffix if both the prefix and suffix are on a
+ // line of their own.
+ expect_eq(R"test(
+int s() {
+ auto S = PTP(
+ R"pb(
+ item_1: 1,
+ item_2: 2,
+ )pb");
+})test",
+ format(R"test(
+int s() {
+ auto S = PTP(
+ R"pb(
+ item_1: 1,
+ item_2: 2,
+ )pb");
+})test",
+ getRawStringPbStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestRawStrings, EstimatesPenalty) {
+ // The penalty for characters exceeding the column limit in the raw string
+ // forces 'hh' to be put on a newline.
+ expect_eq(R"test(
+ff(gggggg,
+ hh(R"pb(key {
+ i1: k1
+ i2: k2
+ })pb"));
+)test",
+ format(R"test(
+ff(gggggg, hh(R"pb(key {
+ i1: k1
+ i2: k2
+ })pb"));
+)test",
+ getRawStringPbStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestRawStrings, DontFormatNonRawStrings) {
+ expect_eq(R"test(a = R"pb(key:value)";)test",
+ format(R"test(a = R"pb(key:value)";)test",
+ getRawStringPbStyleWithColumns(20)));
+}
+
+} // end namespace
+} // end namespace format
+} // end namespace clang
diff --git a/unittests/Format/FormatTestSelective.cpp b/unittests/Format/FormatTestSelective.cpp
index 367dbafcaf..182218fe96 100644
--- a/unittests/Format/FormatTestSelective.cpp
+++ b/unittests/Format/FormatTestSelective.cpp
@@ -24,10 +24,10 @@ protected:
DEBUG(llvm::errs() << "---\n");
DEBUG(llvm::errs() << Code << "\n\n");
std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
- bool IncompleteFormat = false;
+ FormattingAttemptStatus Status;
tooling::Replacements Replaces =
- reformat(Style, Code, Ranges, "<stdin>", &IncompleteFormat);
- EXPECT_FALSE(IncompleteFormat) << Code << "\n\n";
+ reformat(Style, Code, Ranges, "<stdin>", &Status);
+ EXPECT_TRUE(Status.FormatComplete) << Code << "\n\n";
auto Result = applyAllReplacements(Code, Replaces);
EXPECT_TRUE(static_cast<bool>(Result));
DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
@@ -325,7 +325,7 @@ TEST_F(FormatTestSelective, WrongIndent) {
}
TEST_F(FormatTestSelective, AlwaysFormatsEntireMacroDefinitions) {
- Style.AlignEscapedNewlinesLeft = true;
+ Style.AlignEscapedNewlines = FormatStyle::ENAS_Left;
EXPECT_EQ("int i;\n"
"#define A \\\n"
" int i; \\\n"
@@ -467,7 +467,7 @@ TEST_F(FormatTestSelective, ReformatRegionAdjustsIndent) {
TEST_F(FormatTestSelective, UnderstandsTabs) {
Style.IndentWidth = 8;
Style.UseTab = FormatStyle::UT_Always;
- Style.AlignEscapedNewlinesLeft = true;
+ Style.AlignEscapedNewlines = FormatStyle::ENAS_Left;
EXPECT_EQ("void f() {\n"
"\tf();\n"
"\tg();\n"
@@ -530,6 +530,14 @@ TEST_F(FormatTestSelective, SelectivelyRequoteJavaScript) {
20, 0));
}
+TEST_F(FormatTestSelective, KeepsIndentAfterCommentSectionImport) {
+ std::string Code = "#include <a> // line 1\n" // 23 chars long
+ " // line 2\n" // 23 chars long
+ "\n" // this newline is char 47
+ "int i;"; // this line is not indented
+ EXPECT_EQ(Code, format(Code, 47, 1));
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/FormatTestTextProto.cpp b/unittests/Format/FormatTestTextProto.cpp
new file mode 100644
index 0000000000..0a7bcdd823
--- /dev/null
+++ b/unittests/Format/FormatTestTextProto.cpp
@@ -0,0 +1,294 @@
+//===- unittest/Format/FormatTestProto.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatTestUtils.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test"
+
+namespace clang {
+namespace format {
+
+class FormatTestTextProto : public ::testing::Test {
+protected:
+ static std::string format(llvm::StringRef Code, unsigned Offset,
+ unsigned Length, const FormatStyle &Style) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+ tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+ auto Result = applyAllReplacements(Code, Replaces);
+ EXPECT_TRUE(static_cast<bool>(Result));
+ DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+ return *Result;
+ }
+
+ static std::string format(llvm::StringRef Code) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_TextProto);
+ Style.ColumnLimit = 60; // To make writing tests easier.
+ return format(Code, 0, Code.size(), Style);
+ }
+
+ static void verifyFormat(llvm::StringRef Code) {
+ EXPECT_EQ(Code.str(), format(test::messUp(Code)));
+ }
+};
+
+TEST_F(FormatTestTextProto, KeepsTopLevelEntriesFittingALine) {
+ verifyFormat("field_a: OK field_b: OK field_c: OK field_d: OK field_e: OK");
+}
+
+TEST_F(FormatTestTextProto, SupportsMessageFields) {
+ verifyFormat("msg_field: {}");
+
+ verifyFormat("msg_field: {field_a: A}");
+
+ verifyFormat("msg_field: {field_a: \"OK\" field_b: 123}");
+
+ verifyFormat("msg_field: {\n"
+ " field_a: 1\n"
+ " field_b: OK\n"
+ " field_c: \"OK\"\n"
+ " field_d: 123\n"
+ " field_e: 23\n"
+ "}");
+
+ verifyFormat("msg_field {}");
+
+ verifyFormat("msg_field {field_a: A}");
+
+ verifyFormat("msg_field {field_a: \"OK\" field_b: 123}");
+
+ verifyFormat("msg_field {\n"
+ " field_a: 1\n"
+ " field_b: OK\n"
+ " field_c: \"OK\"\n"
+ " field_d: 123\n"
+ " field_e: 23.0\n"
+ " field_f: false\n"
+ " field_g: 'lala'\n"
+ " field_h: 1234.567e-89\n"
+ "}");
+
+ verifyFormat("msg_field: {msg_field {field_a: 1}}");
+
+ verifyFormat("id: \"ala.bala\"\n"
+ "item {type: ITEM_A rank: 1 score: 90.0}\n"
+ "item {type: ITEM_B rank: 2 score: 70.5}\n"
+ "item {\n"
+ " type: ITEM_A\n"
+ " rank: 3\n"
+ " score: 20.0\n"
+ " description: \"the third item has a description\"\n"
+ "}");
+}
+
+TEST_F(FormatTestTextProto, AvoidsTopLevelBinPacking) {
+ verifyFormat("field_a: OK\n"
+ "field_b: OK\n"
+ "field_c: OK\n"
+ "field_d: OK\n"
+ "field_e: OK\n"
+ "field_f: OK");
+
+ verifyFormat("field_a: OK\n"
+ "field_b: \"OK\"\n"
+ "field_c: \"OK\"\n"
+ "msg_field: {field_d: 123}\n"
+ "field_e: OK\n"
+ "field_f: OK");
+
+ verifyFormat("field_a: OK\n"
+ "field_b: \"OK\"\n"
+ "field_c: \"OK\"\n"
+ "msg_field: {field_d: 123 field_e: OK}");
+
+ verifyFormat("a: {\n"
+ " field_a: OK\n"
+ " field_b {field_c: OK}\n"
+ " field_d: OKOKOK\n"
+ " field_e: OK\n"
+ "}");
+
+ verifyFormat("field_a: OK,\n"
+ "field_b {field_c: OK},\n"
+ "field_d: OKOKOK,\n"
+ "field_e: OK");
+}
+
+TEST_F(FormatTestTextProto, AddsNewlinesAfterTrailingComments) {
+ verifyFormat("field_a: OK // Comment\n"
+ "field_b: 1");
+
+ verifyFormat("field_a: OK\n"
+ "msg_field: {\n"
+ " field_b: OK // Comment\n"
+ "}");
+
+ verifyFormat("field_a: OK\n"
+ "msg_field {\n"
+ " field_b: OK // Comment\n"
+ "}");
+}
+
+TEST_F(FormatTestTextProto, SupportsAngleBracketMessageFields) {
+ // Single-line tests
+ verifyFormat("msg_field <>");
+ verifyFormat("msg_field: <>");
+ verifyFormat("msg_field <field_a: OK>");
+ verifyFormat("msg_field: <field_a: 123>");
+ verifyFormat("msg_field <field_a <>>");
+ verifyFormat("msg_field <field_a <field_b <>>>");
+ verifyFormat("msg_field: <field_a <field_b: <>>>");
+ verifyFormat("msg_field <field_a: OK, field_b: \"OK\">");
+ verifyFormat("msg_field <field_a: OK field_b: <>, field_c: OK>");
+ verifyFormat("msg_field <field_a {field_b: 1}, field_c: <field_d: 2>>");
+ verifyFormat("msg_field: <field_a: OK, field_b: \"OK\">");
+ verifyFormat("msg_field: <field_a: OK field_b: <>, field_c: OK>");
+ verifyFormat("msg_field: <field_a {field_b: 1}, field_c: <field_d: 2>>");
+ verifyFormat("field_a: \"OK\", msg_field: <field_b: 123>, field_c: {}");
+ verifyFormat("field_a <field_b: 1>, msg_field: <field_b: 123>, field_c <>");
+ verifyFormat("field_a <field_b: 1> msg_field: <field_b: 123> field_c <>");
+ verifyFormat("field <field <field: <>>, field <>> field: <field: 1>");
+
+ // Multiple lines tests
+ verifyFormat("msg_field <\n"
+ " field_a: OK\n"
+ " field_b: \"OK\"\n"
+ " field_c: 1\n"
+ " field_d: 12.5\n"
+ " field_e: OK\n"
+ ">");
+
+ verifyFormat("msg_field: <>\n"
+ "field_c: \"OK\",\n"
+ "msg_field: <field_d: 123>\n"
+ "field_e: OK\n"
+ "msg_field: <field_d: 12>");
+
+ verifyFormat("field_a: OK,\n"
+ "field_b <field_c: OK>,\n"
+ "field_d: <12.5>,\n"
+ "field_e: OK");
+
+ verifyFormat("field_a: OK\n"
+ "field_b <field_c: OK>\n"
+ "field_d: <12.5>\n"
+ "field_e: OKOKOK");
+
+ verifyFormat("msg_field <\n"
+ " field_a: OK,\n"
+ " field_b <field_c: OK>,\n"
+ " field_d: <12.5>,\n"
+ " field_e: OK\n"
+ ">");
+
+ verifyFormat("msg_field <\n"
+ " field_a: <field: OK>,\n"
+ " field_b <field_c: OK>,\n"
+ " field_d: <12.5>,\n"
+ " field_e: OK,\n"
+ ">");
+
+ verifyFormat("msg_field: <\n"
+ " field_a: \"OK\"\n"
+ " msg_field: {field_b: OK}\n"
+ " field_g: OK\n"
+ " field_g: OK\n"
+ " field_g: OK\n"
+ ">");
+
+ verifyFormat("field_a {\n"
+ " field_d: ok\n"
+ " field_b: <field_c: 1>\n"
+ " field_d: ok\n"
+ " field_d: ok\n"
+ "}");
+
+ verifyFormat("field_a: {\n"
+ " field_d: ok\n"
+ " field_b: <field_c: 1>\n"
+ " field_d: ok\n"
+ " field_d: ok\n"
+ "}");
+
+ verifyFormat("field_a: <f1: 1, f2: <>>\n"
+ "field_b <\n"
+ " field_b1: <>\n"
+ " field_b2: ok,\n"
+ " field_b3: <\n"
+ " field_x {} // Comment\n"
+ " field_y: {field_z: 1}\n"
+ " field_w: ok\n"
+ " >\n"
+ " field {\n"
+ " field_x <> // Comment\n"
+ " field_y: <field_z: 1>\n"
+ " field_w: ok\n"
+ " msg_field: <\n"
+ " field: <>\n"
+ " field: <field: 1>\n"
+ " field: <field: 2>\n"
+ " field: <field: 3>\n"
+ " field: <field: 4>\n"
+ " field: ok\n"
+ " >\n"
+ " }\n"
+ ">\n"
+ "field: OK,\n"
+ "field_c <field <field <>>>");
+
+ verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
+ "head_id: 1\n"
+ "data <key: value>");
+
+ verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
+ "head_id: 1\n"
+ "data <key: value>\n"
+ "tail_id: 2");
+
+ verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
+ "head_id: 1\n"
+ "data <key: value>\n"
+ "data {key: value}");
+
+ verifyFormat("app {\n"
+ " app_id: 'com.javax.swing.salsa.latino'\n"
+ " head_id: 1\n"
+ " data <key: value>\n"
+ "}");
+
+ verifyFormat("app: {\n"
+ " app_id: 'com.javax.swing.salsa.latino'\n"
+ " head_id: 1\n"
+ " data <key: value>\n"
+ "}");
+
+ verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
+ "headheadheadheadheadhead_id: 1\n"
+ "product_data {product {1}}");
+
+ verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
+ "headheadheadheadheadhead_id: 1\n"
+ "product_data <product {1}>");
+
+ verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
+ "headheadheadheadheadhead_id: 1\n"
+ "product_data <product <1>>");
+
+ verifyFormat("app <\n"
+ " app_id: 'com.javax.swing.salsa.latino'\n"
+ " headheadheadheadheadhead_id: 1\n"
+ " product_data <product {1}>\n"
+ ">");
+}
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Format/FormatTestUtils.h b/unittests/Format/FormatTestUtils.h
index bd340e5b0e..d82d84ebed 100644
--- a/unittests/Format/FormatTestUtils.h
+++ b/unittests/Format/FormatTestUtils.h
@@ -30,7 +30,8 @@ inline std::string messUp(llvm::StringRef Code) {
if (JustReplacedNewline)
MessedUp[i - 1] = '\n';
InComment = true;
- } else if (MessedUp[i] == '#' && (JustReplacedNewline || i == 0)) {
+ } else if (MessedUp[i] == '#' &&
+ (JustReplacedNewline || i == 0 || MessedUp[i - 1] == '\n')) {
if (i != 0)
MessedUp[i - 1] = '\n';
InPreprocessorDirective = true;
diff --git a/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/unittests/Format/NamespaceEndCommentsFixerTest.cpp
index 48ecdb038e..fda8b4d69f 100644
--- a/unittests/Format/NamespaceEndCommentsFixerTest.cpp
+++ b/unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -23,7 +23,7 @@ class NamespaceEndCommentsFixerTest : public ::testing::Test {
protected:
std::string
fixNamespaceEndComments(llvm::StringRef Code,
- std::vector<tooling::Range> Ranges,
+ const std::vector<tooling::Range> &Ranges,
const FormatStyle &Style = getLLVMStyle()) {
DEBUG(llvm::errs() << "---\n");
DEBUG(llvm::errs() << Code << "\n\n");
@@ -185,6 +185,41 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
"}\n"
"}"));
+ // Add comment for namespaces which will be 'compacted'
+ FormatStyle CompactNamespacesStyle = getLLVMStyle();
+ CompactNamespacesStyle.CompactNamespaces = true;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}}// namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}}",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "}// namespace out::in",
+ fixNamespaceEndComments("namespace out {\n"
+ "namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "}",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "};}// namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "int i;\n"
+ "int j;\n"
+ "};}",
+ CompactNamespacesStyle));
+
// Adds an end comment after a semicolon.
EXPECT_EQ("namespace {\n"
" int i;\n"
@@ -388,6 +423,27 @@ TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) {
fixNamespaceEndComments("namespace A {} // namespace"));
EXPECT_EQ("namespace A {}; // namespace A",
fixNamespaceEndComments("namespace A {}; // namespace"));
+
+ // Update invalid comments for compacted namespaces.
+ FormatStyle CompactNamespacesStyle = getLLVMStyle();
+ CompactNamespacesStyle.CompactNamespaces = true;
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "}} // namespace out",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "}} // namespace in",
+ CompactNamespacesStyle));
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}\n"
+ "} // namespace out::in",
+ fixNamespaceEndComments("namespace out { namespace in {\n"
+ "}// banamespace in\n"
+ "} // namespace out",
+ CompactNamespacesStyle));
}
TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) {
@@ -453,6 +509,134 @@ TEST_F(NamespaceEndCommentsFixerTest,
"}\n"));
}
+TEST_F(NamespaceEndCommentsFixerTest, AddEndCommentForNamespacesAroundMacros) {
+ // Conditional blocks around are fine
+ EXPECT_EQ("namespace A {\n"
+ "#if 1\n"
+ "int i;\n"
+ "#endif\n"
+ "}// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ "#if 1\n"
+ "int i;\n"
+ "#endif\n"
+ "}"));
+ EXPECT_EQ("#if 1\n"
+ "#endif\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A",
+ fixNamespaceEndComments("#if 1\n"
+ "#endif\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A\n"
+ "#if 1\n"
+ "#endif",
+ fixNamespaceEndComments("namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "#if 1\n"
+ "#endif"));
+ EXPECT_EQ("#if 1\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A\n"
+ "#endif",
+ fixNamespaceEndComments("#if 1\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "#endif"));
+
+ // Macro definition has no impact
+ EXPECT_EQ("namespace A {\n"
+ "#define FOO\n"
+ "int i;\n"
+ "}// namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ "#define FOO\n"
+ "int i;\n"
+ "}"));
+ EXPECT_EQ("#define FOO\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A",
+ fixNamespaceEndComments("#define FOO\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A\n"
+ "#define FOO\n",
+ fixNamespaceEndComments("namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "#define FOO\n"));
+
+ // No replacement if open & close in different conditional blocks
+ EXPECT_EQ("#if 1\n"
+ "namespace A {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "#if 1\n"
+ "}\n"
+ "#endif",
+ fixNamespaceEndComments("#if 1\n"
+ "namespace A {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "#if 1\n"
+ "}\n"
+ "#endif"));
+ EXPECT_EQ("#ifdef A\n"
+ "namespace A {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "#ifdef B\n"
+ "}\n"
+ "#endif",
+ fixNamespaceEndComments("#ifdef A\n"
+ "namespace A {\n"
+ "#endif\n"
+ "int i;\n"
+ "int j;\n"
+ "#ifdef B\n"
+ "}\n"
+ "#endif"));
+
+ // No replacement inside unreachable conditional block
+ EXPECT_EQ("#if 0\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "#endif",
+ fixNamespaceEndComments("#if 0\n"
+ "namespace A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}\n"
+ "#endif"));
+}
+
TEST_F(NamespaceEndCommentsFixerTest,
DoesNotAddEndCommentForNamespacesInMacroDeclarations) {
EXPECT_EQ("#ifdef 1\n"
@@ -582,6 +766,21 @@ TEST_F(NamespaceEndCommentsFixerTest,
"} // 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/Format/SortImportsTestJS.cpp b/unittests/Format/SortImportsTestJS.cpp
index 7e766e1969..91be0313cf 100644
--- a/unittests/Format/SortImportsTestJS.cpp
+++ b/unittests/Format/SortImportsTestJS.cpp
@@ -283,6 +283,31 @@ TEST_F(SortImportsTestJS, SortCaseInsensitive) {
"1;");
}
+TEST_F(SortImportsTestJS, SortMultiLine) {
+ // Reproduces issue where multi-line import was not parsed correctly.
+ verifySort("import {A} from 'a';\n"
+ "import {A} from 'b';\n"
+ "\n"
+ "1;",
+ "import\n"
+ "{\n"
+ "A\n"
+ "}\n"
+ "from\n"
+ "'b';\n"
+ "import {A} from 'a';\n"
+ "\n"
+ "1;");
+}
+
+TEST_F(SortImportsTestJS, SortDefaultImports) {
+ // Reproduces issue where multi-line import was not parsed correctly.
+ verifySort("import {A} from 'a';\n"
+ "import {default as B} from 'b';\n",
+ "import {default as B} from 'b';\n"
+ "import {A} from 'a';\n");
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/SortIncludesTest.cpp b/unittests/Format/SortIncludesTest.cpp
index c3c56a8130..ff3988776b 100644
--- a/unittests/Format/SortIncludesTest.cpp
+++ b/unittests/Format/SortIncludesTest.cpp
@@ -266,6 +266,29 @@ TEST_F(SortIncludesTest, LeavesMainHeaderFirst) {
"a.cc"));
}
+TEST_F(SortIncludesTest, SupportCaseInsensitiveMatching) {
+ // Setup an regex for main includes so we can cover those as well.
+ Style.IncludeIsMainRegex = "([-_](test|unittest))?$";
+
+ // Ensure both main header detection and grouping work in a case insensitive
+ // manner.
+ EXPECT_EQ("#include \"llvm/A.h\"\n"
+ "#include \"b.h\"\n"
+ "#include \"c.h\"\n"
+ "#include \"LLVM/z.h\"\n"
+ "#include \"llvm/X.h\"\n"
+ "#include \"GTest/GTest.h\"\n"
+ "#include \"gmock/gmock.h\"\n",
+ sort("#include \"c.h\"\n"
+ "#include \"b.h\"\n"
+ "#include \"GTest/GTest.h\"\n"
+ "#include \"llvm/A.h\"\n"
+ "#include \"gmock/gmock.h\"\n"
+ "#include \"llvm/X.h\"\n"
+ "#include \"LLVM/z.h\"\n",
+ "a_TEST.cc"));
+}
+
TEST_F(SortIncludesTest, NegativePriorities) {
Style.IncludeCategories = {{".*important_os_header.*", -1}, {".*", 1}};
EXPECT_EQ("#include \"important_os_header.h\"\n"
@@ -375,6 +398,17 @@ TEST_F(SortIncludesTest, ValidAffactedRangesAfterDeduplicatingIncludes) {
EXPECT_EQ(26u, Ranges[0].getLength());
}
+TEST_F(SortIncludesTest, DoNotSortLikelyXml) {
+ EXPECT_EQ("<!--;\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "-->",
+ sort("<!--;\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "-->"));
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/unittests/Format/UsingDeclarationsSorterTest.cpp b/unittests/Format/UsingDeclarationsSorterTest.cpp
new file mode 100644
index 0000000000..caa2f4380b
--- /dev/null
+++ b/unittests/Format/UsingDeclarationsSorterTest.cpp
@@ -0,0 +1,333 @@
+//===- UsingDeclarationsSorterTest.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 "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "using-declarations-sorter-test"
+
+namespace clang {
+namespace format {
+namespace {
+
+class UsingDeclarationsSorterTest : public ::testing::Test {
+protected:
+ std::string sortUsingDeclarations(llvm::StringRef Code,
+ const std::vector<tooling::Range> &Ranges,
+ const FormatStyle &Style = getLLVMStyle()) {
+ DEBUG(llvm::errs() << "---\n");
+ DEBUG(llvm::errs() << Code << "\n\n");
+ tooling::Replacements Replaces =
+ clang::format::sortUsingDeclarations(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 sortUsingDeclarations(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle()) {
+ return sortUsingDeclarations(Code,
+ /*Ranges=*/{1, tooling::Range(0, Code.size())},
+ Style);
+ }
+};
+
+TEST_F(UsingDeclarationsSorterTest, SwapsTwoConsecutiveUsingDeclarations) {
+ EXPECT_EQ("using a;\n"
+ "using b;",
+ sortUsingDeclarations("using a;\n"
+ "using b;"));
+ EXPECT_EQ("using a;\n"
+ "using aa;",
+ sortUsingDeclarations("using aa;\n"
+ "using a;"));
+ EXPECT_EQ("using ::a;\n"
+ "using a;",
+ sortUsingDeclarations("using a;\n"
+ "using ::a;"));
+
+ EXPECT_EQ("using a::bcd;\n"
+ "using a::cd;",
+ sortUsingDeclarations("using a::cd;\n"
+ "using a::bcd;"));
+
+ EXPECT_EQ("using a;\n"
+ "using a::a;",
+ sortUsingDeclarations("using a::a;\n"
+ "using a;"));
+
+ EXPECT_EQ("using a::ba::aa;\n"
+ "using a::bb::ccc;",
+ sortUsingDeclarations("using a::bb::ccc;\n"
+ "using a::ba::aa;"));
+
+ EXPECT_EQ("using a;\n"
+ "using typename a;",
+ sortUsingDeclarations("using typename a;\n"
+ "using a;"));
+
+ EXPECT_EQ("using typename z;\n"
+ "using typenamea;",
+ sortUsingDeclarations("using typenamea;\n"
+ "using typename z;"));
+
+ EXPECT_EQ("using a, b;\n"
+ "using aa;",
+ sortUsingDeclarations("using aa;\n"
+ "using a, b;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, SortsCaseInsensitively) {
+ EXPECT_EQ("using A;\n"
+ "using a;",
+ sortUsingDeclarations("using A;\n"
+ "using a;"));
+ EXPECT_EQ("using a;\n"
+ "using A;",
+ sortUsingDeclarations("using a;\n"
+ "using A;"));
+ EXPECT_EQ("using a;\n"
+ "using B;",
+ sortUsingDeclarations("using B;\n"
+ "using a;"));
+ EXPECT_EQ("using _;\n"
+ "using a;",
+ sortUsingDeclarations("using a;\n"
+ "using _;"));
+ EXPECT_EQ("using a::_;\n"
+ "using a::a;",
+ sortUsingDeclarations("using a::a;\n"
+ "using a::_;"));
+
+ EXPECT_EQ("using ::testing::_;\n"
+ "using ::testing::Aardvark;\n"
+ "using ::testing::apple::Honeycrisp;\n"
+ "using ::testing::Xylophone;\n"
+ "using ::testing::zebra::Stripes;",
+ sortUsingDeclarations("using ::testing::Aardvark;\n"
+ "using ::testing::Xylophone;\n"
+ "using ::testing::_;\n"
+ "using ::testing::apple::Honeycrisp;\n"
+ "using ::testing::zebra::Stripes;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, SortsStably) {
+ EXPECT_EQ("using a;\n"
+ "using a;\n"
+ "using A;\n"
+ "using a;\n"
+ "using A;\n"
+ "using a;\n"
+ "using A;\n"
+ "using a;\n"
+ "using B;\n"
+ "using b;\n"
+ "using b;\n"
+ "using B;\n"
+ "using b;\n"
+ "using b;\n"
+ "using b;\n"
+ "using B;\n"
+ "using b;",
+ sortUsingDeclarations("using a;\n"
+ "using B;\n"
+ "using a;\n"
+ "using b;\n"
+ "using A;\n"
+ "using a;\n"
+ "using b;\n"
+ "using B;\n"
+ "using b;\n"
+ "using A;\n"
+ "using a;\n"
+ "using b;\n"
+ "using b;\n"
+ "using B;\n"
+ "using b;\n"
+ "using A;\n"
+ "using a;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, SortsMultipleTopLevelDeclarations) {
+ EXPECT_EQ("using a;\n"
+ "using b;\n"
+ "using c;\n"
+ "using d;\n"
+ "using e;",
+ sortUsingDeclarations("using d;\n"
+ "using b;\n"
+ "using e;\n"
+ "using a;\n"
+ "using c;"));
+
+ EXPECT_EQ("#include <iostream>\n"
+ "using ::std::endl;\n"
+ "using std::cin;\n"
+ "using std::cout;\n"
+ "int main();",
+ sortUsingDeclarations("#include <iostream>\n"
+ "using std::cout;\n"
+ "using std::cin;\n"
+ "using ::std::endl;\n"
+ "int main();"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, BreaksOnEmptyLines) {
+ EXPECT_EQ("using b;\n"
+ "using c;\n"
+ "\n"
+ "using a;\n"
+ "using d;",
+ sortUsingDeclarations("using c;\n"
+ "using b;\n"
+ "\n"
+ "using d;\n"
+ "using a;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, BreaksOnUsingNamespace) {
+ EXPECT_EQ("using b;\n"
+ "using namespace std;\n"
+ "using a;",
+ sortUsingDeclarations("using b;\n"
+ "using namespace std;\n"
+ "using a;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, KeepsUsingDeclarationsInPPDirectives) {
+ EXPECT_EQ("#define A \\\n"
+ "using b;\\\n"
+ "using a;",
+ sortUsingDeclarations("#define A \\\n"
+ "using b;\\\n"
+ "using a;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, KeepsTypeAliases) {
+ auto Code = "struct C { struct B { struct A; }; };\n"
+ "using B = C::B;\n"
+ "using A = B::A;";
+ EXPECT_EQ(Code, sortUsingDeclarations(Code));
+}
+
+TEST_F(UsingDeclarationsSorterTest, MovesTrailingCommentsWithDeclarations) {
+ EXPECT_EQ("using a; // line a1\n"
+ "using b; /* line b1\n"
+ " * line b2\n"
+ " * line b3 */\n"
+ "using c; // line c1\n"
+ " // line c2",
+ sortUsingDeclarations("using c; // line c1\n"
+ " // line c2\n"
+ "using b; /* line b1\n"
+ " * line b2\n"
+ " * line b3 */\n"
+ "using a; // line a1"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, SortsInStructScope) {
+ EXPECT_EQ("struct pt3 : pt2 {\n"
+ " using pt2::x;\n"
+ " using pt2::y;\n"
+ " float z;\n"
+ "};",
+ sortUsingDeclarations("struct pt3 : pt2 {\n"
+ " using pt2::y;\n"
+ " using pt2::x;\n"
+ " float z;\n"
+ "};"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, KeepsOperators) {
+ EXPECT_EQ("using a::operator();\n"
+ "using a::operator-;\n"
+ "using a::operator+;",
+ sortUsingDeclarations("using a::operator();\n"
+ "using a::operator-;\n"
+ "using a::operator+;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, SortsUsingDeclarationsInsideNamespaces) {
+ EXPECT_EQ("namespace A {\n"
+ "struct B;\n"
+ "struct C;\n"
+ "}\n"
+ "namespace X {\n"
+ "using A::B;\n"
+ "using A::C;\n"
+ "}",
+ sortUsingDeclarations("namespace A {\n"
+ "struct B;\n"
+ "struct C;\n"
+ "}\n"
+ "namespace X {\n"
+ "using A::C;\n"
+ "using A::B;\n"
+ "}"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, SupportsClangFormatOff) {
+ EXPECT_EQ("// clang-format off\n"
+ "using b;\n"
+ "using a;\n"
+ "// clang-format on\n"
+ "using c;\n"
+ "using d;",
+ sortUsingDeclarations("// clang-format off\n"
+ "using b;\n"
+ "using a;\n"
+ "// clang-format on\n"
+ "using d;\n"
+ "using c;"));
+}
+
+TEST_F(UsingDeclarationsSorterTest, SortsPartialRangeOfUsingDeclarations) {
+ // Sorts the whole block of using declarations surrounding the range.
+ EXPECT_EQ("using a;\n"
+ "using b;\n"
+ "using c;",
+ sortUsingDeclarations("using b;\n"
+ "using c;\n" // starts at offset 10
+ "using a;",
+ {tooling::Range(10, 15)}));
+ EXPECT_EQ("using a;\n"
+ "using b;\n"
+ "using c;\n"
+ "using A = b;",
+ sortUsingDeclarations("using b;\n"
+ "using c;\n" // starts at offset 10
+ "using a;\n"
+ "using A = b;",
+ {tooling::Range(10, 15)}));
+
+ EXPECT_EQ("using d;\n"
+ "using c;\n"
+ "\n"
+ "using a;\n"
+ "using b;\n"
+ "\n"
+ "using f;\n"
+ "using e;",
+ sortUsingDeclarations("using d;\n"
+ "using c;\n"
+ "\n"
+ "using b;\n" // starts at offset 19
+ "using a;\n"
+ "\n"
+ "using f;\n"
+ "using e;",
+ {tooling::Range(19, 1)}));
+}
+
+} // end namespace
+} // end namespace format
+} // end namespace clang
diff --git a/unittests/Frontend/ASTUnitTest.cpp b/unittests/Frontend/ASTUnitTest.cpp
new file mode 100644
index 0000000000..4f529cf55d
--- /dev/null
+++ b/unittests/Frontend/ASTUnitTest.cpp
@@ -0,0 +1,87 @@
+//===- unittests/Frontend/ASTUnitTest.cpp - ASTUnit tests -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <fstream>
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+TEST(ASTUnit, SaveLoadPreservesLangOptionsInPrintingPolicy) {
+ // Check that the printing policy is restored with the correct language
+ // options when loading an ASTUnit from a file. To this end, an ASTUnit
+ // for a C++ translation unit is set up and written to a temporary file.
+
+ // By default `UseVoidForZeroParams` is true for non-C++ language options,
+ // thus we can check this field after loading the ASTUnit to deduce whether
+ // the correct (C++) language options were used when setting up the printing
+ // policy.
+
+ {
+ PrintingPolicy PolicyWithDefaultLangOpt(LangOptions{});
+ EXPECT_TRUE(PolicyWithDefaultLangOpt.UseVoidForZeroParams);
+ }
+
+ int FD;
+ llvm::SmallString<256> InputFileName;
+ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("ast-unit", "cpp", FD, InputFileName));
+ ToolOutputFile input_file(InputFileName, FD);
+ input_file.os() << "";
+
+ const char* Args[] = {"clang", "-xc++", InputFileName.c_str()};
+
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ CompilerInstance::createDiagnostics(new DiagnosticOptions());
+
+ std::shared_ptr<CompilerInvocation> CInvok =
+ createInvocationFromCommandLine(Args, Diags);
+
+ if (!CInvok)
+ FAIL() << "could not create compiler invocation";
+
+ FileManager *FileMgr =
+ new FileManager(FileSystemOptions(), vfs::getRealFileSystem());
+ auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
+
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
+ CInvok, PCHContainerOps, Diags, FileMgr);
+
+ if (!AST)
+ FAIL() << "failed to create ASTUnit";
+
+ EXPECT_FALSE(AST->getASTContext().getPrintingPolicy().UseVoidForZeroParams);
+
+ llvm::SmallString<256> ASTFileName;
+ ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("ast-unit", "ast", FD, ASTFileName));
+ ToolOutputFile ast_file(ASTFileName, FD);
+ AST->Save(ASTFileName.str());
+
+ EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName));
+
+ std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
+ ASTFileName.str(), PCHContainerOps->getRawReader(), ASTUnit::LoadEverything, Diags,
+ FileSystemOptions(), /*UseDebugInfo=*/false);
+
+ if (!AU)
+ FAIL() << "failed to load ASTUnit";
+
+ EXPECT_FALSE(AU->getASTContext().getPrintingPolicy().UseVoidForZeroParams);
+}
+
+} // anonymous namespace
diff --git a/unittests/Frontend/CMakeLists.txt b/unittests/Frontend/CMakeLists.txt
index 674f77bd01..c1f4f18635 100644
--- a/unittests/Frontend/CMakeLists.txt
+++ b/unittests/Frontend/CMakeLists.txt
@@ -3,8 +3,12 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_unittest(FrontendTests
+ ASTUnitTest.cpp
+ CompilerInstanceTest.cpp
FrontendActionTest.cpp
CodeGenActionTest.cpp
+ ParsedSourceLocationTest.cpp
+ PCHPreambleTest.cpp
)
target_link_libraries(FrontendTests
clangAST
diff --git a/unittests/Frontend/CodeGenActionTest.cpp b/unittests/Frontend/CodeGenActionTest.cpp
index 1d2a50c8bc..d90c2bce2f 100644
--- a/unittests/Frontend/CodeGenActionTest.cpp
+++ b/unittests/Frontend/CodeGenActionTest.cpp
@@ -46,7 +46,7 @@ TEST(CodeGenTest, TestNullCodeGen) {
"test.cc",
MemoryBuffer::getMemBuffer("").release());
Invocation->getFrontendOpts().Inputs.push_back(
- FrontendInputFile("test.cc", IK_CXX));
+ FrontendInputFile("test.cc", InputKind::CXX));
Invocation->getFrontendOpts().ProgramAction = EmitLLVM;
Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance Compiler;
diff --git a/unittests/Frontend/CompilerInstanceTest.cpp b/unittests/Frontend/CompilerInstanceTest.cpp
new file mode 100644
index 0000000000..b2d9f8bcf0
--- /dev/null
+++ b/unittests/Frontend/CompilerInstanceTest.cpp
@@ -0,0 +1,74 @@
+//===- unittests/Frontend/CompilerInstanceTest.cpp - CI tests -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
+ // Create a temporary VFS overlay yaml file.
+ int FD;
+ SmallString<256> FileName;
+ ASSERT_FALSE(sys::fs::createTemporaryFile("vfs", "yaml", FD, FileName));
+ ToolOutputFile File(FileName, FD);
+
+ SmallString<256> CurrentPath;
+ sys::fs::current_path(CurrentPath);
+ sys::fs::make_absolute(CurrentPath, FileName);
+
+ // Mount the VFS file itself on the path 'virtual.file'. Makes this test
+ // a bit shorter than creating a new dummy file just for this purpose.
+ const std::string CurrentPathStr = CurrentPath.str();
+ const std::string FileNameStr = FileName.str();
+ const char *VFSYaml = "{ 'version': 0, 'roots': [\n"
+ " { 'name': '%s',\n"
+ " 'type': 'directory',\n"
+ " 'contents': [\n"
+ " { 'name': 'vfs-virtual.file', 'type': 'file',\n"
+ " 'external-contents': '%s'\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ "]}\n";
+ File.os() << format(VFSYaml, CurrentPathStr.c_str(), FileName.c_str());
+ File.os().flush();
+
+ // Create a CompilerInvocation that uses this overlay file.
+ const std::string VFSArg = "-ivfsoverlay" + FileNameStr;
+ const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"};
+
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ CompilerInstance::createDiagnostics(new DiagnosticOptions());
+
+ std::shared_ptr<CompilerInvocation> CInvok =
+ createInvocationFromCommandLine(Args, Diags);
+
+ if (!CInvok)
+ FAIL() << "could not create compiler invocation";
+ // Create a minimal CompilerInstance which should use the VFS we specified
+ // in the CompilerInvocation (as we don't explicitly set our own).
+ CompilerInstance Instance;
+ Instance.setDiagnostics(Diags.get());
+ Instance.setInvocation(CInvok);
+ Instance.createFileManager();
+
+ // Check if the virtual file exists which means that our VFS is used by the
+ // CompilerInstance.
+ ASSERT_TRUE(Instance.getFileManager().getFile("vfs-virtual.file"));
+}
+
+} // anonymous namespace
diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp
index dd6be5fd4b..ce0144538d 100644
--- a/unittests/Frontend/FrontendActionTest.cpp
+++ b/unittests/Frontend/FrontendActionTest.cpp
@@ -37,12 +37,11 @@ public:
bool ActOnEndOfTranslationUnit;
std::vector<std::string> decl_names;
- bool BeginSourceFileAction(CompilerInstance &ci,
- StringRef filename) override {
+ bool BeginSourceFileAction(CompilerInstance &ci) override {
if (EnableIncrementalProcessing)
ci.getPreprocessor().enableIncrementalProcessing();
- return ASTFrontendAction::BeginSourceFileAction(ci, filename);
+ return ASTFrontendAction::BeginSourceFileAction(ci);
}
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
@@ -83,8 +82,8 @@ TEST(ASTFrontendAction, Sanity) {
invocation->getPreprocessorOpts().addRemappedFile(
"test.cc",
MemoryBuffer::getMemBuffer("int main() { float x; }").release());
- invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
- IK_CXX));
+ invocation->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile("test.cc", InputKind::CXX));
invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance compiler;
@@ -103,8 +102,8 @@ TEST(ASTFrontendAction, IncrementalParsing) {
invocation->getPreprocessorOpts().addRemappedFile(
"test.cc",
MemoryBuffer::getMemBuffer("int main() { float x; }").release());
- invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
- IK_CXX));
+ invocation->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile("test.cc", InputKind::CXX));
invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance compiler;
@@ -130,8 +129,8 @@ TEST(ASTFrontendAction, LateTemplateIncrementalParsing) {
" B(B const& b): A<T>(b.data) {}\n"
"};\n"
"B<char> c() { return B<char>(); }\n").release());
- invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
- IK_CXX));
+ invocation->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile("test.cc", InputKind::CXX));
invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance compiler;
@@ -177,7 +176,7 @@ TEST(PreprocessorFrontendAction, EndSourceFile) {
"test.cc",
MemoryBuffer::getMemBuffer("int main() { float x; }").release());
Invocation->getFrontendOpts().Inputs.push_back(
- FrontendInputFile("test.cc", IK_CXX));
+ FrontendInputFile("test.cc", InputKind::CXX));
Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance Compiler;
@@ -238,7 +237,7 @@ TEST(ASTFrontendAction, ExternalSemaSource) {
"int main() { foo(); }")
.release());
Invocation->getFrontendOpts().Inputs.push_back(
- FrontendInputFile("test.cc", IK_CXX));
+ FrontendInputFile("test.cc", InputKind::CXX));
Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance Compiler;
diff --git a/unittests/Frontend/PCHPreambleTest.cpp b/unittests/Frontend/PCHPreambleTest.cpp
new file mode 100644
index 0000000000..162a281b04
--- /dev/null
+++ b/unittests/Frontend/PCHPreambleTest.cpp
@@ -0,0 +1,200 @@
+//====-- unittests/Frontend/PCHPreambleTest.cpp - FrontendAction tests ---====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+class ReadCountingInMemoryFileSystem : public vfs::InMemoryFileSystem
+{
+ std::map<std::string, unsigned> ReadCounts;
+
+public:
+ ErrorOr<std::unique_ptr<vfs::File>> openFileForRead(const Twine &Path) override
+ {
+ SmallVector<char, 128> PathVec;
+ Path.toVector(PathVec);
+ llvm::sys::path::remove_dots(PathVec, true);
+ ++ReadCounts[std::string(PathVec.begin(), PathVec.end())];
+ return InMemoryFileSystem::openFileForRead(Path);
+ }
+
+ unsigned GetReadCount(const Twine &Path) const
+ {
+ auto it = ReadCounts.find(Path.str());
+ return it == ReadCounts.end() ? 0 : it->second;
+ }
+};
+
+class PCHPreambleTest : public ::testing::Test {
+ IntrusiveRefCntPtr<ReadCountingInMemoryFileSystem> VFS;
+ StringMap<std::string> RemappedFiles;
+ std::shared_ptr<PCHContainerOperations> PCHContainerOpts;
+ FileSystemOptions FSOpts;
+
+public:
+ void SetUp() override {
+ VFS = new ReadCountingInMemoryFileSystem();
+ // We need the working directory to be set to something absolute,
+ // otherwise it ends up being inadvertently set to the current
+ // working directory in the real file system due to a series of
+ // unfortunate conditions interacting badly.
+ // What's more, this path *must* be absolute on all (real)
+ // filesystems, so just '/' won't work (e.g. on Win32).
+ VFS->setCurrentWorkingDirectory("//./");
+ }
+
+ void TearDown() override {
+ }
+
+ void AddFile(const std::string &Filename, const std::string &Contents) {
+ ::time_t now;
+ ::time(&now);
+ VFS->addFile(Filename, now, MemoryBuffer::getMemBufferCopy(Contents, Filename));
+ }
+
+ void RemapFile(const std::string &Filename, const std::string &Contents) {
+ RemappedFiles[Filename] = Contents;
+ }
+
+ std::unique_ptr<ASTUnit> ParseAST(const std::string &EntryFile) {
+ PCHContainerOpts = std::make_shared<PCHContainerOperations>();
+ std::shared_ptr<CompilerInvocation> CI(new CompilerInvocation);
+ CI->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile(EntryFile, FrontendOptions::getInputKindForExtension(
+ llvm::sys::path::extension(EntryFile).substr(1))));
+
+ CI->getTargetOpts().Triple = "i386-unknown-linux-gnu";
+
+ CI->getPreprocessorOpts().RemappedFileBuffers = GetRemappedFiles();
+
+ PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
+ PPOpts.RemappedFilesKeepOriginalName = true;
+
+ IntrusiveRefCntPtr<DiagnosticsEngine>
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, new DiagnosticConsumer));
+
+ FileManager *FileMgr = new FileManager(FSOpts, VFS);
+
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
+ CI, PCHContainerOpts, Diags, FileMgr, false, false,
+ /*PrecompilePreambleAfterNParses=*/1);
+ return AST;
+ }
+
+ bool ReparseAST(const std::unique_ptr<ASTUnit> &AST) {
+ bool reparseFailed = AST->Reparse(PCHContainerOpts, GetRemappedFiles(), VFS);
+ return !reparseFailed;
+ }
+
+ unsigned GetFileReadCount(const std::string &Filename) const {
+ return VFS->GetReadCount(Filename);
+ }
+
+private:
+ std::vector<std::pair<std::string, llvm::MemoryBuffer *>>
+ GetRemappedFiles() const {
+ std::vector<std::pair<std::string, llvm::MemoryBuffer *>> Remapped;
+ for (const auto &RemappedFile : RemappedFiles) {
+ std::unique_ptr<MemoryBuffer> buf = MemoryBuffer::getMemBufferCopy(
+ RemappedFile.second, RemappedFile.first());
+ Remapped.emplace_back(RemappedFile.first(), buf.release());
+ }
+ return Remapped;
+ }
+};
+
+TEST_F(PCHPreambleTest, ReparseWithOverriddenFileDoesNotInvalidatePreamble) {
+ std::string Header1 = "//./header1.h";
+ std::string Header2 = "//./header2.h";
+ std::string MainName = "//./main.cpp";
+ AddFile(Header1, "");
+ AddFile(Header2, "#pragma once");
+ AddFile(MainName,
+ "#include \"//./foo/../header1.h\"\n"
+ "#include \"//./foo/../header2.h\"\n"
+ "int main() { return ZERO; }");
+ RemapFile(Header1, "static const int ZERO = 0;\n");
+
+ std::unique_ptr<ASTUnit> AST(ParseAST(MainName));
+ ASSERT_TRUE(AST.get());
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+ unsigned initialCounts[] = {
+ GetFileReadCount(MainName),
+ GetFileReadCount(Header1),
+ GetFileReadCount(Header2)
+ };
+
+ ASSERT_TRUE(ReparseAST(AST));
+
+ ASSERT_NE(initialCounts[0], GetFileReadCount(MainName));
+ ASSERT_EQ(initialCounts[1], GetFileReadCount(Header1));
+ ASSERT_EQ(initialCounts[2], GetFileReadCount(Header2));
+}
+
+TEST_F(PCHPreambleTest, ParseWithBom) {
+ std::string Header = "//./header.h";
+ std::string Main = "//./main.cpp";
+ AddFile(Header, "int random() { return 4; }");
+ AddFile(Main,
+ "\xef\xbb\xbf"
+ "#include \"//./header.h\"\n"
+ "int main() { return random() -2; }");
+
+ std::unique_ptr<ASTUnit> AST(ParseAST(Main));
+ ASSERT_TRUE(AST.get());
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+ unsigned HeaderReadCount = GetFileReadCount(Header);
+
+ ASSERT_TRUE(ReparseAST(AST));
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+ // Check preamble PCH was really reused
+ ASSERT_EQ(HeaderReadCount, GetFileReadCount(Header));
+
+ // Remove BOM
+ RemapFile(Main,
+ "#include \"//./header.h\"\n"
+ "int main() { return random() -2; }");
+
+ ASSERT_TRUE(ReparseAST(AST));
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+ ASSERT_LE(HeaderReadCount, GetFileReadCount(Header));
+ HeaderReadCount = GetFileReadCount(Header);
+
+ // Add BOM back
+ RemapFile(Main,
+ "\xef\xbb\xbf"
+ "#include \"//./header.h\"\n"
+ "int main() { return random() -2; }");
+
+ ASSERT_TRUE(ReparseAST(AST));
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+ ASSERT_LE(HeaderReadCount, GetFileReadCount(Header));
+}
+
+} // anonymous namespace
diff --git a/unittests/Frontend/ParsedSourceLocationTest.cpp b/unittests/Frontend/ParsedSourceLocationTest.cpp
new file mode 100644
index 0000000000..0cbdc7e1d5
--- /dev/null
+++ b/unittests/Frontend/ParsedSourceLocationTest.cpp
@@ -0,0 +1,37 @@
+//===- unittests/Frontend/ParsedSourceLocationTest.cpp - ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CommandLineSourceLoc.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+TEST(ParsedSourceRange, ParseTest) {
+ auto Check = [](StringRef Value, StringRef Filename, unsigned BeginLine,
+ unsigned BeginColumn, unsigned EndLine, unsigned EndColumn) {
+ Optional<ParsedSourceRange> PSR = ParsedSourceRange::fromString(Value);
+ ASSERT_TRUE(PSR);
+ EXPECT_EQ(PSR->FileName, Filename);
+ EXPECT_EQ(PSR->Begin.first, BeginLine);
+ EXPECT_EQ(PSR->Begin.second, BeginColumn);
+ EXPECT_EQ(PSR->End.first, EndLine);
+ EXPECT_EQ(PSR->End.second, EndColumn);
+ };
+
+ Check("/Users/test/a-b.cpp:1:2", "/Users/test/a-b.cpp", 1, 2, 1, 2);
+ Check("/Users/test/a-b.cpp:1:2-3:4", "/Users/test/a-b.cpp", 1, 2, 3, 4);
+
+ Check("C:/Users/bob/a-b.cpp:1:2", "C:/Users/bob/a-b.cpp", 1, 2, 1, 2);
+ Check("C:/Users/bob/a-b.cpp:1:2-3:4", "C:/Users/bob/a-b.cpp", 1, 2, 3, 4);
+}
+
+} // anonymous namespace
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index 918167bf43..894f8c7fd8 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -12,11 +12,14 @@
#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"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroArgs.h"
+#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
@@ -26,24 +29,6 @@ using namespace clang;
namespace {
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
// The test fixture.
class LexerTest : public ::testing::Test {
protected:
@@ -58,24 +43,33 @@ protected:
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
}
- std::vector<Token> Lex(StringRef Source) {
+ std::unique_ptr<Preprocessor> CreatePP(StringRef Source,
+ TrivialModuleLoader &ModLoader) {
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(Source);
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,
- /*OwnsHeaderSearch =*/false);
- PP.Initialize(*Target);
- PP.EnterMainSourceFile();
+ std::unique_ptr<Preprocessor> PP = llvm::make_unique<Preprocessor>(
+ std::make_shared<PreprocessorOptions>(), Diags, LangOpts, SourceMgr,
+ PCMCache, HeaderInfo, ModLoader,
+ /*IILookup =*/nullptr,
+ /*OwnsHeaderSearch =*/false);
+ PP->Initialize(*Target);
+ PP->EnterMainSourceFile();
+ return PP;
+ }
+
+ std::vector<Token> Lex(StringRef Source) {
+ TrivialModuleLoader ModLoader;
+ auto PP = CreatePP(Source, ModLoader);
std::vector<Token> toks;
while (1) {
Token tok;
- PP.Lex(tok);
+ PP->Lex(tok);
if (tok.is(tok::eof))
break;
toks.push_back(tok);
@@ -380,4 +374,108 @@ TEST_F(LexerTest, DontMergeMacroArgsFromDifferentMacroFiles) {
EXPECT_EQ(SourceMgr.getFileIDSize(SourceMgr.getFileID(helper1ArgLoc)), 8U);
}
+TEST_F(LexerTest, DontOverallocateStringifyArgs) {
+ TrivialModuleLoader ModLoader;
+ auto PP = CreatePP("\"StrArg\", 5, 'C'", ModLoader);
+
+ llvm::BumpPtrAllocator Allocator;
+ std::array<IdentifierInfo *, 3> ParamList;
+ MacroInfo *MI = PP->AllocateMacroInfo({});
+ MI->setIsFunctionLike();
+ MI->setParameterList(ParamList, Allocator);
+ EXPECT_EQ(3u, MI->getNumParams());
+ EXPECT_TRUE(MI->isFunctionLike());
+
+ Token Eof;
+ Eof.setKind(tok::eof);
+ std::vector<Token> ArgTokens;
+ while (1) {
+ Token tok;
+ PP->Lex(tok);
+ if (tok.is(tok::eof)) {
+ ArgTokens.push_back(Eof);
+ break;
+ }
+ if (tok.is(tok::comma))
+ ArgTokens.push_back(Eof);
+ else
+ ArgTokens.push_back(tok);
+ }
+
+ auto MacroArgsDeleter = [&PP](MacroArgs *M) { M->destroy(*PP); };
+ std::unique_ptr<MacroArgs, decltype(MacroArgsDeleter)> MA(
+ MacroArgs::create(MI, ArgTokens, false, *PP), MacroArgsDeleter);
+ Token Result = MA->getStringifiedArgument(0, *PP, {}, {});
+ EXPECT_EQ(tok::string_literal, Result.getKind());
+ EXPECT_STREQ("\"\\\"StrArg\\\"\"", Result.getLiteralData());
+ Result = MA->getStringifiedArgument(1, *PP, {}, {});
+ EXPECT_EQ(tok::string_literal, Result.getKind());
+ EXPECT_STREQ("\"5\"", Result.getLiteralData());
+ Result = MA->getStringifiedArgument(2, *PP, {}, {});
+ EXPECT_EQ(tok::string_literal, Result.getKind());
+ EXPECT_STREQ("\"'C'\"", Result.getLiteralData());
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(MA->getStringifiedArgument(3, *PP, {}, {}),
+ "Invalid argument number!");
+#endif
+}
+
+TEST_F(LexerTest, IsNewLineEscapedValid) {
+ auto hasNewLineEscaped = [](const char *S) {
+ return Lexer::isNewLineEscaped(S, S + strlen(S) - 1);
+ };
+
+ EXPECT_TRUE(hasNewLineEscaped("\\\r"));
+ EXPECT_TRUE(hasNewLineEscaped("\\\n"));
+ EXPECT_TRUE(hasNewLineEscaped("\\\r\n"));
+ EXPECT_TRUE(hasNewLineEscaped("\\\n\r"));
+ EXPECT_TRUE(hasNewLineEscaped("\\ \t\v\f\r"));
+ EXPECT_TRUE(hasNewLineEscaped("\\ \t\v\f\r\n"));
+
+ EXPECT_FALSE(hasNewLineEscaped("\\\r\r"));
+ EXPECT_FALSE(hasNewLineEscaped("\\\r\r\n"));
+ EXPECT_FALSE(hasNewLineEscaped("\\\n\n"));
+ EXPECT_FALSE(hasNewLineEscaped("\r"));
+ EXPECT_FALSE(hasNewLineEscaped("\n"));
+ EXPECT_FALSE(hasNewLineEscaped("\r\n"));
+ EXPECT_FALSE(hasNewLineEscaped("\n\r"));
+ EXPECT_FALSE(hasNewLineEscaped("\r\r"));
+ EXPECT_FALSE(hasNewLineEscaped("\n\n"));
+}
+
+TEST_F(LexerTest, GetBeginningOfTokenWithEscapedNewLine) {
+ // Each line should have the same length for
+ // further offset calculation to be more straightforward.
+ const unsigned IdentifierLength = 8;
+ std::string TextToLex = "rabarbar\n"
+ "foo\\\nbar\n"
+ "foo\\\rbar\n"
+ "fo\\\r\nbar\n"
+ "foo\\\n\rba\n";
+ std::vector<tok::TokenKind> ExpectedTokens{5, tok::identifier};
+ std::vector<Token> LexedTokens = CheckLex(TextToLex, ExpectedTokens);
+
+ for (const Token &Tok : LexedTokens) {
+ std::pair<FileID, unsigned> OriginalLocation =
+ SourceMgr.getDecomposedLoc(Tok.getLocation());
+ for (unsigned Offset = 0; Offset < IdentifierLength; ++Offset) {
+ SourceLocation LookupLocation =
+ Tok.getLocation().getLocWithOffset(Offset);
+
+ std::pair<FileID, unsigned> FoundLocation =
+ SourceMgr.getDecomposedExpansionLoc(
+ Lexer::GetBeginningOfToken(LookupLocation, SourceMgr, LangOpts));
+
+ // Check that location returned by the GetBeginningOfToken
+ // is the same as original token location reported by Lexer.
+ EXPECT_EQ(FoundLocation.second, OriginalLocation.second);
+ }
+ }
+}
+
+TEST_F(LexerTest, AvoidPastEndOfStringDereference) {
+ std::vector<Token> LexedTokens = Lex(" // \\\n");
+ EXPECT_TRUE(LexedTokens.empty());
+}
+
} // anonymous namespace
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index 064abafc4a..67b56a601c 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"
@@ -31,25 +32,6 @@ using namespace clang;
namespace {
-// Stub out module loading.
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
// Stub to collect data from InclusionDirective callbacks.
class InclusionDirectiveCallbacks : public PPCallbacks {
public:
@@ -160,14 +142,15 @@ protected:
llvm::MemoryBuffer::getMemBuffer(SourceText);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader 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);
@@ -197,12 +180,13 @@ protected:
llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader 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 dccfffdb2c..f7b6f717a1 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"
@@ -50,24 +51,6 @@ protected:
IntrusiveRefCntPtr<TargetInfo> Target;
};
-class VoidModuleLoader : public ModuleLoader {
- ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override { }
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
-};
-
TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
const char *source =
"0 1\n"
@@ -92,11 +75,12 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
llvm::MemoryBuffer::getMemBuffer(source);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
- VoidModuleLoader ModLoader;
+ TrivialModuleLoader 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/Rename/CMakeLists.txt b/unittests/Rename/CMakeLists.txt
new file mode 100644
index 0000000000..cecb2d39b9
--- /dev/null
+++ b/unittests/Rename/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+# We'd like clang/unittests/Tooling/RewriterTestContext.h in the test.
+include_directories(${CLANG_SOURCE_DIR})
+
+add_clang_unittest(ClangRenameTests
+ RenameClassTest.cpp
+ RenameEnumTest.cpp
+ RenameAliasTest.cpp
+ RenameMemberTest.cpp
+ RenameFunctionTest.cpp
+ )
+
+target_link_libraries(ClangRenameTests
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ clangToolingRefactor
+ )
diff --git a/unittests/Rename/ClangRenameTest.h b/unittests/Rename/ClangRenameTest.h
new file mode 100644
index 0000000000..0933dd5aaf
--- /dev/null
+++ b/unittests/Rename/ClangRenameTest.h
@@ -0,0 +1,112 @@
+//===-- ClangRenameTests.cpp - clang-rename unit tests --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "unittests/Tooling/RewriterTestContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+
+struct Case {
+ std::string Before;
+ std::string After;
+ std::string OldName;
+ std::string NewName;
+};
+
+class ClangRenameTest : public testing::Test,
+ public testing::WithParamInterface<Case> {
+protected:
+ void AppendToHeader(StringRef Code) { HeaderContent += Code.str(); }
+
+ std::string runClangRenameOnCode(llvm::StringRef Code,
+ llvm::StringRef OldName,
+ llvm::StringRef NewName) {
+ std::string NewCode;
+ llvm::raw_string_ostream(NewCode) << llvm::format(
+ "#include \"%s\"\n%s", HeaderName.c_str(), Code.str().c_str());
+ tooling::FileContentMappings FileContents = {{HeaderName, HeaderContent},
+ {CCName, NewCode}};
+ clang::RewriterTestContext Context;
+ Context.createInMemoryFile(HeaderName, HeaderContent);
+ clang::FileID InputFileID = Context.createInMemoryFile(CCName, NewCode);
+
+ tooling::USRFindingAction FindingAction({}, {OldName}, false);
+ std::unique_ptr<tooling::FrontendActionFactory> USRFindingActionFactory =
+ tooling::newFrontendActionFactory(&FindingAction);
+
+ if (!tooling::runToolOnCodeWithArgs(
+ USRFindingActionFactory->create(), NewCode, {"-std=c++11"}, CCName,
+ "clang-rename", std::make_shared<PCHContainerOperations>(),
+ FileContents))
+ return "";
+
+ const std::vector<std::vector<std::string>> &USRList =
+ FindingAction.getUSRList();
+ std::vector<std::string> NewNames = {NewName};
+ std::map<std::string, tooling::Replacements> FileToReplacements;
+ tooling::QualifiedRenamingAction RenameAction(NewNames, USRList,
+ FileToReplacements);
+ auto RenameActionFactory = tooling::newFrontendActionFactory(&RenameAction);
+ if (!tooling::runToolOnCodeWithArgs(
+ RenameActionFactory->create(), NewCode, {"-std=c++11"}, CCName,
+ "clang-rename", std::make_shared<PCHContainerOperations>(),
+ FileContents))
+ return "";
+
+ formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
+ return Context.getRewrittenText(InputFileID);
+ }
+
+ void CompareSnippets(StringRef Expected, StringRef Actual) {
+ std::string ExpectedCode;
+ llvm::raw_string_ostream(ExpectedCode) << llvm::format(
+ "#include \"%s\"\n%s", HeaderName.c_str(), Expected.str().c_str());
+ EXPECT_EQ(format(ExpectedCode), format(Actual));
+ }
+
+ std::string format(llvm::StringRef Code) {
+ tooling::Replacements Replaces = format::reformat(
+ format::getLLVMStyle(), Code, {tooling::Range(0, Code.size())});
+ auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
+ EXPECT_TRUE(static_cast<bool>(ChangedCode));
+ if (!ChangedCode) {
+ llvm::errs() << llvm::toString(ChangedCode.takeError());
+ return "";
+ }
+ return *ChangedCode;
+ }
+
+ std::string HeaderContent;
+ std::string HeaderName = "header.h";
+ std::string CCName = "input.cc";
+};
+
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang
diff --git a/unittests/Rename/RenameAliasTest.cpp b/unittests/Rename/RenameAliasTest.cpp
new file mode 100644
index 0000000000..59becaef68
--- /dev/null
+++ b/unittests/Rename/RenameAliasTest.cpp
@@ -0,0 +1,304 @@
+//===-- RenameAliasTest.cpp - unit tests for renaming alias ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangRenameTest.h"
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+namespace {
+
+class RenameAliasTest : public ClangRenameTest {
+public:
+ RenameAliasTest() {
+ AppendToHeader(R"(
+ #define MACRO(x) x
+ namespace some_ns {
+ class A {
+ public:
+ void foo() {}
+ struct Nested {
+ enum NestedEnum {
+ E1, E2,
+ };
+ };
+ };
+ } // namespace some_ns
+ namespace a {
+ typedef some_ns::A TA;
+ using UA = some_ns::A;
+ } // namespace a
+ namespace b {
+ typedef some_ns::A TA;
+ using UA = some_ns::A;
+ }
+ template <typename T> class ptr {};
+ template <typename T>
+
+ using TPtr = ptr<int>;
+ )");
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(
+ RenameAliasTests, RenameAliasTest,
+ testing::ValuesIn(std::vector<Case>({
+ // basic functions
+ {"void f(a::TA a1) {}", "void f(b::TB a1) {}", "a::TA", "b::TB"},
+ {"void f(a::UA a1) {}", "void f(b::UB a1) {}", "a::UA", "b::UB"},
+ {"void f(a::TA* a1) {}", "void f(b::TB* a1) {}", "a::TA", "b::TB"},
+ {"void f(a::TA** a1) {}", "void f(b::TB** a1) {}", "a::TA", "b::TB"},
+ {"a::TA f() { return a::TA(); }", "b::TB f() { return b::TB(); }",
+ "a::TA", "b::TB"},
+ {"a::TA f() { return a::UA(); }", "b::TB f() { return a::UA(); }",
+ "a::TA", "b::TB"},
+ {"a::TA f() { return a::UA(); }", "a::TA f() { return b::UB(); }",
+ "a::UA", "b::UB"},
+ {"void f() { a::TA a; }", "void f() { b::TB a; }", "a::TA", "b::TB"},
+ {"void f(const a::TA& a1) {}", "void f(const b::TB& a1) {}", "a::TA",
+ "b::TB"},
+ {"void f(const a::UA& a1) {}", "void f(const b::UB& a1) {}", "a::UA",
+ "b::UB"},
+ {"void f(const a::TA* a1) {}", "void f(const b::TB* a1) {}", "a::TA",
+ "b::TB"},
+ {"namespace a { void f(TA a1) {} }",
+ "namespace a { void f(b::TB a1) {} }", "a::TA", "b::TB"},
+ {"void f(MACRO(a::TA) a1) {}", "void f(MACRO(b::TB) a1) {}", "a::TA",
+ "b::TB"},
+ {"void f(MACRO(a::TA a1)) {}", "void f(MACRO(b::TB a1)) {}", "a::TA",
+ "b::TB"},
+
+ // shorten/add namespace.
+ {"namespace b { void f(a::UA a1) {} }",
+ "namespace b {void f(UB a1) {} }", "a::UA", "b::UB"},
+ {"namespace a { void f(UA a1) {} }",
+ "namespace a {void f(b::UB a1) {} }", "a::UA", "b::UB"},
+
+ // use namespace and typedefs
+ {"struct S { using T = a::TA; T a_; };",
+ "struct S { using T = b::TB; T a_; };", "a::TA", "b::TB"},
+ {"using T = a::TA; T gA;", "using T = b::TB; T gA;", "a::TA", "b::TB"},
+ {"using T = a::UA; T gA;", "using T = b::UB; T gA;", "a::UA", "b::UB"},
+ {"typedef a::TA T; T gA;", "typedef b::TB T; T gA;", "a::TA", "b::TB"},
+ {"typedef a::UA T; T gA;", "typedef b::UB T; T gA;", "a::UA", "b::UB"},
+ {"typedef MACRO(a::TA) T; T gA;", "typedef MACRO(b::TB) T; T gA;",
+ "a::TA", "b::TB"},
+
+ // types in using shadows.
+ {"using a::TA; TA gA;", "using b::TB; b::TB gA;", "a::TA", "b::TB"},
+ {"using a::UA; UA gA;", "using b::UB; b::UB gA;", "a::UA", "b::UB"},
+
+ // struct members and other oddities
+ {"struct S : public a::TA {};", "struct S : public b::TB {};", "a::TA",
+ "b::TB"},
+ {"struct S : public a::UA {};", "struct S : public b::UB {};", "a::UA",
+ "b::UB"},
+ {"struct F { void f(a::TA a1) {} };",
+ "struct F { void f(b::TB a1) {} };", "a::TA", "b::TB"},
+ {"struct F { a::TA a_; };", "struct F { b::TB a_; };", "a::TA",
+ "b::TB"},
+ {"struct F { ptr<a::TA> a_; };", "struct F { ptr<b::TB> a_; };",
+ "a::TA", "b::TB"},
+ {"struct F { ptr<a::UA> a_; };", "struct F { ptr<b::UB> a_; };",
+ "a::UA", "b::UB"},
+
+ // types in nested name specifiers
+ {"void f() { a::TA::Nested ne; }", "void f() { b::TB::Nested ne; }",
+ "a::TA", "b::TB"},
+ {"void f() { a::UA::Nested ne; }", "void f() { b::UB::Nested ne; }",
+ "a::UA", "b::UB"},
+ {"void f() { a::TA::Nested::NestedEnum e; }",
+ "void f() { b::TB::Nested::NestedEnum e; }", "a::TA", "b::TB"},
+ {"void f() { auto e = a::TA::Nested::NestedEnum::E1; }",
+ "void f() { auto e = b::TB::Nested::NestedEnum::E1; }", "a::TA",
+ "b::TB"},
+ {"void f() { auto e = a::TA::Nested::E1; }",
+ "void f() { auto e = b::TB::Nested::E1; }", "a::TA", "b::TB"},
+
+ // templates
+ {"template <typename T> struct Foo { T t; }; void f() { Foo<a::TA> "
+ "foo; }",
+ "template <typename T> struct Foo { T t; }; void f() { Foo<b::TB> "
+ "foo; }",
+ "a::TA", "b::TB"},
+ {"template <typename T> struct Foo { a::TA a; };",
+ "template <typename T> struct Foo { b::TB a; };", "a::TA", "b::TB"},
+ {"template <typename T> void f(T t) {} void g() { f<a::TA>(a::TA()); }",
+ "template <typename T> void f(T t) {} void g() { f<b::TB>(b::TB()); }",
+ "a::TA", "b::TB"},
+ {"template <typename T> void f(T t) {} void g() { f<a::UA>(a::UA()); }",
+ "template <typename T> void f(T t) {} void g() { f<b::UB>(b::UB()); }",
+ "a::UA", "b::UB"},
+ {"template <typename T> int f() { return 1; } template <> int "
+ "f<a::TA>() { return 2; } int g() { return f<a::TA>(); }",
+ "template <typename T> int f() { return 1; } template <> int "
+ "f<b::TB>() { return 2; } int g() { return f<b::TB>(); }",
+ "a::TA", "b::TB"},
+ {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "auto a = f.template foo<a::TA>(); }",
+ "struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "auto a = f.template foo<b::TB>(); }",
+ "a::TA", "b::TB"},
+ {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "auto a = f.template foo<a::UA>(); }",
+ "struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "auto a = f.template foo<b::UB>(); }",
+ "a::UA", "b::UB"},
+
+ // The following two templates are distilled from regressions found in
+ // unique_ptr<> and type_traits.h
+ {"template <typename T> struct outer { typedef T type; type Baz(); }; "
+ "outer<a::TA> g_A;",
+ "template <typename T> struct outer { typedef T type; type Baz(); }; "
+ "outer<b::TB> g_A;",
+ "a::TA", "b::TB"},
+ {"template <typename T> struct nested { typedef T type; }; template "
+ "<typename T> struct outer { typename nested<T>::type Foo(); }; "
+ "outer<a::TA> g_A;",
+ "template <typename T> struct nested { typedef T type; }; template "
+ "<typename T> struct outer { typename nested<T>::type Foo(); }; "
+ "outer<b::TB> g_A;",
+ "a::TA", "b::TB"},
+
+ // macros
+ {"#define FOO(T, t) T t\nvoid f() { FOO(a::TA, a1); FOO(a::TA, a2); }",
+ "#define FOO(T, t) T t\nvoid f() { FOO(b::TB, a1); FOO(b::TB, a2); }",
+ "a::TA", "b::TB"},
+ {"#define FOO(n) a::TA n\nvoid f() { FOO(a1); FOO(a2); }",
+ "#define FOO(n) b::TB n\nvoid f() { FOO(a1); FOO(a2); }", "a::TA",
+ "b::TB"},
+ {"#define FOO(n) a::UA n\nvoid f() { FOO(a1); FOO(a2); }",
+ "#define FOO(n) b::UB n\nvoid f() { FOO(a1); FOO(a2); }", "a::UA",
+ "b::UB"},
+
+ // Pointer to member functions
+ {"auto gA = &a::TA::foo;", "auto gA = &b::TB::foo;", "a::TA", "b::TB"},
+ {"using a::TA; auto gA = &TA::foo;",
+ "using b::TB; auto gA = &b::TB::foo;", "a::TA", "b::TB"},
+ {"typedef a::TA T; auto gA = &T::foo;",
+ "typedef b::TB T; auto gA = &T::foo;", "a::TA", "b::TB"},
+ {"auto gA = &MACRO(a::TA)::foo;", "auto gA = &MACRO(b::TB)::foo;",
+ "a::TA", "b::TB"},
+
+ // templated using alias.
+ {"void f(TPtr<int> p) {}", "void f(NewTPtr<int> p) {}", "TPtr",
+ "NewTPtr"},
+ {"void f(::TPtr<int> p) {}", "void f(::NewTPtr<int> p) {}", "TPtr",
+ "NewTPtr"},
+ })), );
+
+TEST_P(RenameAliasTest, RenameAlias) {
+ auto Param = GetParam();
+ assert(!Param.OldName.empty());
+ assert(!Param.NewName.empty());
+ std::string Actual =
+ runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+ CompareSnippets(Param.After, Actual);
+}
+
+TEST_F(RenameAliasTest, RenameTypedefDefinitions) {
+ std::string Before = R"(
+ class X {};
+ typedef X TOld;
+ )";
+ std::string Expected = R"(
+ class X {};
+ typedef X TNew;
+ )";
+ std::string After = runClangRenameOnCode(Before, "TOld", "TNew");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameAliasTest, RenameUsingAliasDefinitions) {
+ std::string Before = R"(
+ class X {};
+ using UOld = X;
+ )";
+ std::string Expected = R"(
+ class X {};
+ using UNew = X;
+ )";
+ std::string After = runClangRenameOnCode(Before, "UOld", "UNew");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameAliasTest, RenameTemplatedAliasDefinitions) {
+ std::string Before = R"(
+ template <typename T>
+ class X { T t; };
+
+ template <typename T>
+ using Old = X<T>;
+ )";
+ std::string Expected = R"(
+ template <typename T>
+ class X { T t; };
+
+ template <typename T>
+ using New = X<T>;
+ )";
+ std::string After = runClangRenameOnCode(Before, "Old", "New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameAliasTest, RenameAliasesInNamespaces) {
+ std::string Before = R"(
+ namespace x { class X {}; }
+ namespace ns {
+ using UOld = x::X;
+ }
+ )";
+ std::string Expected = R"(
+ namespace x { class X {}; }
+ namespace ns {
+ using UNew = x::X;
+ }
+ )";
+ std::string After = runClangRenameOnCode(Before, "ns::UOld", "ns::UNew");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameAliasTest, AliasesInMacros) {
+ std::string Before = R"(
+ namespace x { class Old {}; }
+ namespace ns {
+ #define REF(alias) alias alias_var;
+
+ #define ALIAS(old) \
+ using old##Alias = x::old; \
+ REF(old##Alias);
+
+ ALIAS(Old);
+
+ OldAlias old_alias;
+ }
+ )";
+ std::string Expected = R"(
+ namespace x { class Old {}; }
+ namespace ns {
+ #define REF(alias) alias alias_var;
+
+ #define ALIAS(old) \
+ using old##Alias = x::old; \
+ REF(old##Alias);
+
+ ALIAS(Old);
+
+ NewAlias old_alias;
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "ns::OldAlias", "ns::NewAlias");
+ CompareSnippets(Expected, After);
+}
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang
diff --git a/unittests/Rename/RenameClassTest.cpp b/unittests/Rename/RenameClassTest.cpp
new file mode 100644
index 0000000000..5845d63412
--- /dev/null
+++ b/unittests/Rename/RenameClassTest.cpp
@@ -0,0 +1,799 @@
+//===-- RenameClassTest.cpp - unit tests for renaming classes -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangRenameTest.h"
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+namespace {
+
+class RenameClassTest : public ClangRenameTest {
+public:
+ RenameClassTest() {
+ AppendToHeader(R"(
+ namespace a {
+ class Foo {
+ public:
+ struct Nested {
+ enum NestedEnum {E1, E2};
+ };
+ void func() {}
+ static int Constant;
+ };
+ class Goo {
+ public:
+ struct Nested {
+ enum NestedEnum {E1, E2};
+ };
+ };
+ int Foo::Constant = 1;
+ } // namespace a
+ namespace b {
+ class Foo {};
+ } // namespace b
+
+ #define MACRO(x) x
+
+ template<typename T> class ptr {};
+ )");
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(
+ RenameClassTests, RenameClassTest,
+ testing::ValuesIn(std::vector<Case>({
+ // basic classes
+ {"a::Foo f;", "b::Bar f;", "", ""},
+ {"::a::Foo f;", "::b::Bar f;", "", ""},
+ {"void f(a::Foo f) {}", "void f(b::Bar f) {}", "", ""},
+ {"void f(a::Foo *f) {}", "void f(b::Bar *f) {}", "", ""},
+ {"a::Foo f() { return a::Foo(); }", "b::Bar f() { return b::Bar(); }",
+ "", ""},
+ {"namespace a {a::Foo f() { return Foo(); }}",
+ "namespace a {b::Bar f() { return b::Bar(); }}", "", ""},
+ {"void f(const a::Foo& a1) {}", "void f(const b::Bar& a1) {}", "", ""},
+ {"void f(const a::Foo* a1) {}", "void f(const b::Bar* a1) {}", "", ""},
+ {"namespace a { void f(Foo a1) {} }",
+ "namespace a { void f(b::Bar a1) {} }", "", ""},
+ {"void f(MACRO(a::Foo) a1) {}", "void f(MACRO(b::Bar) a1) {}", "", ""},
+ {"void f(MACRO(a::Foo a1)) {}", "void f(MACRO(b::Bar a1)) {}", "", ""},
+ {"a::Foo::Nested ns;", "b::Bar::Nested ns;", "", ""},
+ {"auto t = a::Foo::Constant;", "auto t = b::Bar::Constant;", "", ""},
+ {"a::Foo::Nested ns;", "a::Foo::Nested2 ns;", "a::Foo::Nested",
+ "a::Foo::Nested2"},
+
+ // use namespace and typedefs
+ {"using a::Foo; Foo gA;", "using b::Bar; b::Bar gA;", "", ""},
+ {"using a::Foo; void f(Foo gA) {}", "using b::Bar; void f(Bar gA) {}",
+ "", ""},
+ {"using a::Foo; namespace x { Foo gA; }",
+ "using b::Bar; namespace x { Bar gA; }", "", ""},
+ {"struct S { using T = a::Foo; T a_; };",
+ "struct S { using T = b::Bar; T a_; };", "", ""},
+ {"using T = a::Foo; T gA;", "using T = b::Bar; T gA;", "", ""},
+ {"typedef a::Foo T; T gA;", "typedef b::Bar T; T gA;", "", ""},
+ {"typedef MACRO(a::Foo) T; T gA;", "typedef MACRO(b::Bar) T; T gA;", "",
+ ""},
+
+ // struct members and other oddities
+ {"struct S : public a::Foo {};", "struct S : public b::Bar {};", "",
+ ""},
+ {"struct F { void f(a::Foo a1) {} };",
+ "struct F { void f(b::Bar a1) {} };", "", ""},
+ {"struct F { a::Foo a_; };", "struct F { b::Bar a_; };", "", ""},
+ {"struct F { ptr<a::Foo> a_; };", "struct F { ptr<b::Bar> a_; };", "",
+ ""},
+
+ {"void f() { a::Foo::Nested ne; }", "void f() { b::Bar::Nested ne; }",
+ "", ""},
+ {"void f() { a::Goo::Nested ne; }", "void f() { a::Goo::Nested ne; }",
+ "", ""},
+ {"void f() { a::Foo::Nested::NestedEnum e; }",
+ "void f() { b::Bar::Nested::NestedEnum e; }", "", ""},
+ {"void f() { auto e = a::Foo::Nested::NestedEnum::E1; }",
+ "void f() { auto e = b::Bar::Nested::NestedEnum::E1; }", "", ""},
+ {"void f() { auto e = a::Foo::Nested::E1; }",
+ "void f() { auto e = b::Bar::Nested::E1; }", "", ""},
+
+ // templates
+ {"template <typename T> struct Foo { T t; };\n"
+ "void f() { Foo<a::Foo> foo; }",
+ "template <typename T> struct Foo { T t; };\n"
+ "void f() { Foo<b::Bar> foo; }",
+ "", ""},
+ {"template <typename T> struct Foo { a::Foo a; };",
+ "template <typename T> struct Foo { b::Bar a; };", "", ""},
+ {"template <typename T> void f(T t) {}\n"
+ "void g() { f<a::Foo>(a::Foo()); }",
+ "template <typename T> void f(T t) {}\n"
+ "void g() { f<b::Bar>(b::Bar()); }",
+ "", ""},
+ {"template <typename T> int f() { return 1; }\n"
+ "template <> int f<a::Foo>() { return 2; }\n"
+ "int g() { return f<a::Foo>(); }",
+ "template <typename T> int f() { return 1; }\n"
+ "template <> int f<b::Bar>() { return 2; }\n"
+ "int g() { return f<b::Bar>(); }",
+ "", ""},
+ {"struct Foo { template <typename T> T foo(); };\n"
+ "void g() { Foo f; auto a = f.template foo<a::Foo>(); }",
+ "struct Foo { template <typename T> T foo(); };\n"
+ "void g() { Foo f; auto a = f.template foo<b::Bar>(); }",
+ "", ""},
+
+ // The following two templates are distilled from regressions found in
+ // unique_ptr<> and type_traits.h
+ {"template <typename T> struct outer {\n"
+ " typedef T type;\n"
+ " type Baz();\n"
+ " };\n"
+ " outer<a::Foo> g_A;",
+ "template <typename T> struct outer {\n"
+ " typedef T type;\n"
+ " type Baz();\n"
+ " };\n"
+ " outer<b::Bar> g_A;",
+ "", ""},
+ {"template <typename T> struct nested { typedef T type; };\n"
+ "template <typename T> struct outer { typename nested<T>::type Foo(); "
+ "};\n"
+ "outer<a::Foo> g_A;",
+ "template <typename T> struct nested { typedef T type; };\n"
+ "template <typename T> struct outer { typename nested<T>::type Foo(); "
+ "};\n"
+ "outer<b::Bar> g_A;",
+ "", ""},
+
+ // macros
+ {"#define FOO(T, t) T t\n"
+ "void f() { FOO(a::Foo, a1); FOO(a::Foo, a2); }",
+ "#define FOO(T, t) T t\n"
+ "void f() { FOO(b::Bar, a1); FOO(b::Bar, a2); }",
+ "", ""},
+ {"#define FOO(n) a::Foo n\n"
+ " void f() { FOO(a1); FOO(a2); }",
+ "#define FOO(n) b::Bar n\n"
+ " void f() { FOO(a1); FOO(a2); }",
+ "", ""},
+
+ // Pointer to member functions
+ {"auto gA = &a::Foo::func;", "auto gA = &b::Bar::func;", "", ""},
+ {"using a::Foo; auto gA = &Foo::func;",
+ "using b::Bar; auto gA = &b::Bar::func;", "", ""},
+ {"using a::Foo; namespace x { auto gA = &Foo::func; }",
+ "using b::Bar; namespace x { auto gA = &Bar::func; }", "", ""},
+ {"typedef a::Foo T; auto gA = &T::func;",
+ "typedef b::Bar T; auto gA = &T::func;", "", ""},
+ {"auto gA = &MACRO(a::Foo)::func;", "auto gA = &MACRO(b::Bar)::func;",
+ "", ""},
+
+ // Short match inside a namespace
+ {"namespace a { void f(Foo a1) {} }",
+ "namespace a { void f(b::Bar a1) {} }", "", ""},
+
+ // Correct match.
+ {"using a::Foo; struct F { ptr<Foo> a_; };",
+ "using b::Bar; struct F { ptr<Bar> a_; };", "", ""},
+
+ // avoid false positives
+ {"void f(b::Foo a) {}", "void f(b::Foo a) {}", "", ""},
+ {"namespace b { void f(Foo a) {} }", "namespace b { void f(Foo a) {} }",
+ "", ""},
+
+ // friends, everyone needs friends.
+ {"class Foo { int i; friend class a::Foo; };",
+ "class Foo { int i; friend class b::Bar; };", "", ""},
+ })), );
+
+TEST_P(RenameClassTest, RenameClasses) {
+ auto Param = GetParam();
+ std::string OldName = Param.OldName.empty() ? "a::Foo" : Param.OldName;
+ std::string NewName = Param.NewName.empty() ? "b::Bar" : Param.NewName;
+ std::string Actual = runClangRenameOnCode(Param.Before, OldName, NewName);
+ CompareSnippets(Param.After, Actual);
+}
+
+class NamespaceDetectionTest : public ClangRenameTest {
+protected:
+ NamespaceDetectionTest() {
+ AppendToHeader(R"(
+ class Old {};
+ namespace o1 {
+ class Old {};
+ namespace o2 {
+ class Old {};
+ namespace o3 {
+ class Old {};
+ } // namespace o3
+ } // namespace o2
+ } // namespace o1
+ )");
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(
+ RenameClassTest, NamespaceDetectionTest,
+ ::testing::ValuesIn(std::vector<Case>({
+ // Test old and new namespace overlap.
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+ "o1::o2::o3::Old", "o1::o2::o3::New"},
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+ "namespace o1 { namespace o2 { namespace o3 { n3::New moo; } } }",
+ "o1::o2::o3::Old", "o1::o2::n3::New"},
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+ "namespace o1 { namespace o2 { namespace o3 { n2::n3::New moo; } } }",
+ "o1::o2::o3::Old", "o1::n2::n3::New"},
+ {"namespace o1 { namespace o2 { Old moo; } }",
+ "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old",
+ "::o1::o2::New"},
+ {"namespace o1 { namespace o2 { Old moo; } }",
+ "namespace o1 { namespace o2 { n2::New moo; } }", "::o1::o2::Old",
+ "::o1::n2::New"},
+ {"namespace o1 { namespace o2 { Old moo; } }",
+ "namespace o1 { namespace o2 { ::n1::n2::New moo; } }",
+ "::o1::o2::Old", "::n1::n2::New"},
+ {"namespace o1 { namespace o2 { Old moo; } }",
+ "namespace o1 { namespace o2 { n1::n2::New moo; } }", "::o1::o2::Old",
+ "n1::n2::New"},
+
+ // Test old and new namespace with differing depths.
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+ "o1::o2::o3::Old", "::o1::New"},
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+ "o1::o2::o3::Old", "::o1::o2::New"},
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+ "o1::o2::o3::Old", "o1::New"},
+ {"namespace o1 { namespace o2 { namespace o3 { Old moo; } } }",
+ "namespace o1 { namespace o2 { namespace o3 { New moo; } } }",
+ "o1::o2::o3::Old", "o1::o2::New"},
+ {"Old moo;", "o1::New moo;", "::Old", "o1::New"},
+ {"Old moo;", "o1::New moo;", "Old", "o1::New"},
+ {"namespace o1 { ::Old moo; }", "namespace o1 { New moo; }", "Old",
+ "o1::New"},
+ {"namespace o1 { namespace o2 { Old moo; } }",
+ "namespace o1 { namespace o2 { ::New moo; } }", "::o1::o2::Old",
+ "::New"},
+ {"namespace o1 { namespace o2 { Old moo; } }",
+ "namespace o1 { namespace o2 { New moo; } }", "::o1::o2::Old", "New"},
+
+ // Test moving into the new namespace at different levels.
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+ "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
+ "::n1::n2::New"},
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+ "namespace n1 { namespace n2 { New moo; } }", "::o1::o2::Old",
+ "n1::n2::New"},
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+ "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
+ "::n1::o2::New"},
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+ "namespace n1 { namespace n2 { o2::New moo; } }", "::o1::o2::Old",
+ "n1::o2::New"},
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+ "namespace n1 { namespace n2 { ::o1::o2::New moo; } }",
+ "::o1::o2::Old", "::o1::o2::New"},
+ {"namespace n1 { namespace n2 { o1::o2::Old moo; } }",
+ "namespace n1 { namespace n2 { o1::o2::New moo; } }", "::o1::o2::Old",
+ "o1::o2::New"},
+
+ // Test friends declarations.
+ {"class Foo { friend class o1::Old; };",
+ "class Foo { friend class o1::New; };", "o1::Old", "o1::New"},
+ {"class Foo { int i; friend class o1::Old; };",
+ "class Foo { int i; friend class ::o1::New; };", "::o1::Old",
+ "::o1::New"},
+ {"namespace o1 { class Foo { int i; friend class Old; }; }",
+ "namespace o1 { class Foo { int i; friend class New; }; }", "o1::Old",
+ "o1::New"},
+ {"namespace o1 { class Foo { int i; friend class Old; }; }",
+ "namespace o1 { class Foo { int i; friend class New; }; }",
+ "::o1::Old", "::o1::New"},
+ })), );
+
+TEST_P(NamespaceDetectionTest, RenameClasses) {
+ auto Param = GetParam();
+ std::string Actual =
+ runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+ CompareSnippets(Param.After, Actual);
+}
+
+class TemplatedClassRenameTest : public ClangRenameTest {
+protected:
+ TemplatedClassRenameTest() {
+ AppendToHeader(R"(
+ template <typename T> struct Old {
+ T t_;
+ T f() { return T(); };
+ static T s(T t) { return t; }
+ };
+ namespace ns {
+ template <typename T> struct Old {
+ T t_;
+ T f() { return T(); };
+ static T s(T t) { return t; }
+ };
+ } // namespace ns
+
+ namespace o1 {
+ namespace o2 {
+ namespace o3 {
+ template <typename T> struct Old {
+ T t_;
+ T f() { return T(); };
+ static T s(T t) { return t; }
+ };
+ } // namespace o3
+ } // namespace o2
+ } // namespace o1
+ )");
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(
+ RenameClassTests, TemplatedClassRenameTest,
+ ::testing::ValuesIn(std::vector<Case>({
+ {"Old<int> gI; Old<bool> gB;", "New<int> gI; New<bool> gB;", "Old",
+ "New"},
+ {"ns::Old<int> gI; ns::Old<bool> gB;",
+ "ns::New<int> gI; ns::New<bool> gB;", "ns::Old", "ns::New"},
+ {"auto gI = &Old<int>::f; auto gB = &Old<bool>::f;",
+ "auto gI = &New<int>::f; auto gB = &New<bool>::f;", "Old", "New"},
+ {"auto gI = &ns::Old<int>::f;", "auto gI = &ns::New<int>::f;",
+ "ns::Old", "ns::New"},
+
+ {"int gI = Old<int>::s(0); bool gB = Old<bool>::s(false);",
+ "int gI = New<int>::s(0); bool gB = New<bool>::s(false);", "Old",
+ "New"},
+ {"int gI = ns::Old<int>::s(0); bool gB = ns::Old<bool>::s(false);",
+ "int gI = ns::New<int>::s(0); bool gB = ns::New<bool>::s(false);",
+ "ns::Old", "ns::New"},
+
+ {"struct S { Old<int*> o_; };", "struct S { New<int*> o_; };", "Old",
+ "New"},
+ {"struct S { ns::Old<int*> o_; };", "struct S { ns::New<int*> o_; };",
+ "ns::Old", "ns::New"},
+
+ {"auto a = reinterpret_cast<Old<int>*>(new Old<int>);",
+ "auto a = reinterpret_cast<New<int>*>(new New<int>);", "Old", "New"},
+ {"auto a = reinterpret_cast<ns::Old<int>*>(new ns::Old<int>);",
+ "auto a = reinterpret_cast<ns::New<int>*>(new ns::New<int>);",
+ "ns::Old", "ns::New"},
+ {"auto a = reinterpret_cast<const Old<int>*>(new Old<int>);",
+ "auto a = reinterpret_cast<const New<int>*>(new New<int>);", "Old",
+ "New"},
+ {"auto a = reinterpret_cast<const ns::Old<int>*>(new ns::Old<int>);",
+ "auto a = reinterpret_cast<const ns::New<int>*>(new ns::New<int>);",
+ "ns::Old", "ns::New"},
+
+ {"Old<bool>& foo();", "New<bool>& foo();", "Old", "New"},
+ {"ns::Old<bool>& foo();", "ns::New<bool>& foo();", "ns::Old",
+ "ns::New"},
+ {"o1::o2::o3::Old<bool>& foo();", "o1::o2::o3::New<bool>& foo();",
+ "o1::o2::o3::Old", "o1::o2::o3::New"},
+ {"namespace ns { Old<bool>& foo(); }",
+ "namespace ns { New<bool>& foo(); }", "ns::Old", "ns::New"},
+ {"const Old<bool>& foo();", "const New<bool>& foo();", "Old", "New"},
+ {"const ns::Old<bool>& foo();", "const ns::New<bool>& foo();",
+ "ns::Old", "ns::New"},
+
+ // FIXME: figure out why this only works when Moo gets
+ // specialized at some point.
+ {"template <typename T> struct Moo { Old<T> o_; }; Moo<int> m;",
+ "template <typename T> struct Moo { New<T> o_; }; Moo<int> m;", "Old",
+ "New"},
+ {"template <typename T> struct Moo { ns::Old<T> o_; }; Moo<int> m;",
+ "template <typename T> struct Moo { ns::New<T> o_; }; Moo<int> m;",
+ "ns::Old", "ns::New"},
+ })), );
+
+TEST_P(TemplatedClassRenameTest, RenameTemplateClasses) {
+ auto Param = GetParam();
+ std::string Actual =
+ runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+ CompareSnippets(Param.After, Actual);
+}
+
+TEST_F(ClangRenameTest, RenameClassWithOutOfLineMembers) {
+ std::string Before = R"(
+ class Old {
+ public:
+ Old();
+ ~Old();
+
+ Old* next();
+
+ private:
+ Old* next_;
+ };
+
+ Old::Old() {}
+ Old::~Old() {}
+ Old* Old::next() { return next_; }
+ )";
+ std::string Expected = R"(
+ class New {
+ public:
+ New();
+ ~New();
+
+ New* next();
+
+ private:
+ New* next_;
+ };
+
+ New::New() {}
+ New::~New() {}
+ New* New::next() { return next_; }
+ )";
+ std::string After = runClangRenameOnCode(Before, "Old", "New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, RenameClassWithInlineMembers) {
+ std::string Before = R"(
+ class Old {
+ public:
+ Old() {}
+ ~Old() {}
+
+ Old* next() { return next_; }
+
+ private:
+ Old* next_;
+ };
+ )";
+ std::string Expected = R"(
+ class New {
+ public:
+ New() {}
+ ~New() {}
+
+ New* next() { return next_; }
+
+ private:
+ New* next_;
+ };
+ )";
+ std::string After = runClangRenameOnCode(Before, "Old", "New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, RenameClassWithNamespaceWithInlineMembers) {
+ std::string Before = R"(
+ namespace ns {
+ class Old {
+ public:
+ Old() {}
+ ~Old() {}
+
+ Old* next() { return next_; }
+
+ private:
+ Old* next_;
+ };
+ } // namespace ns
+ )";
+ std::string Expected = R"(
+ namespace ns {
+ class New {
+ public:
+ New() {}
+ ~New() {}
+
+ New* next() { return next_; }
+
+ private:
+ New* next_;
+ };
+ } // namespace ns
+ )";
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, RenameClassWithNamespaceWithOutOfInlineMembers) {
+ std::string Before = R"(
+ namespace ns {
+ class Old {
+ public:
+ Old();
+ ~Old();
+
+ Old* next();
+
+ private:
+ Old* next_;
+ };
+
+ Old::Old() {}
+ Old::~Old() {}
+ Old* Old::next() { return next_; }
+ } // namespace ns
+ )";
+ std::string Expected = R"(
+ namespace ns {
+ class New {
+ public:
+ New();
+ ~New();
+
+ New* next();
+
+ private:
+ New* next_;
+ };
+
+ New::New() {}
+ New::~New() {}
+ New* New::next() { return next_; }
+ } // namespace ns
+ )";
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, RenameClassInInheritedConstructor) {
+ // `using Base::Base;` will generate an implicit constructor containing usage
+ // of `::ns::Old` which should not be matched.
+ std::string Before = R"(
+ namespace ns {
+ class Old;
+ class Old {
+ int x;
+ };
+ class Base {
+ protected:
+ Old *moo_;
+ public:
+ Base(Old *moo) : moo_(moo) {}
+ };
+ class Derived : public Base {
+ public:
+ using Base::Base;
+ };
+ } // namespace ns
+ int main() {
+ ::ns::Old foo;
+ ::ns::Derived d(&foo);
+ return 0;
+ })";
+ std::string Expected = R"(
+ namespace ns {
+ class New;
+ class New {
+ int x;
+ };
+ class Base {
+ protected:
+ New *moo_;
+ public:
+ Base(New *moo) : moo_(moo) {}
+ };
+ class Derived : public Base {
+ public:
+ using Base::Base;
+ };
+ } // namespace ns
+ int main() {
+ ::ns::New foo;
+ ::ns::Derived d(&foo);
+ return 0;
+ })";
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "ns::New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, DontRenameReferencesInImplicitFunction) {
+ std::string Before = R"(
+ namespace ns {
+ class Old {
+ };
+ } // namespace ns
+ struct S {
+ int y;
+ ns::Old old;
+ };
+ void f() {
+ S s1, s2, s3;
+ // This causes an implicit assignment operator to be created.
+ s1 = s2 = s3;
+ }
+ )";
+ std::string Expected = R"(
+ namespace ns {
+ class New {
+ };
+ } // namespace ns
+ struct S {
+ int y;
+ ::new_ns::New old;
+ };
+ void f() {
+ S s1, s2, s3;
+ // This causes an implicit assignment operator to be created.
+ s1 = s2 = s3;
+ }
+ )";
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, ReferencesInLambdaFunctionParameters) {
+ std::string Before = R"(
+ template <class T>
+ class function;
+ template <class R, class... ArgTypes>
+ class function<R(ArgTypes...)> {
+ public:
+ template <typename Functor>
+ function(Functor f) {}
+
+ function() {}
+
+ R operator()(ArgTypes...) const {}
+ };
+
+ namespace ns {
+ class Old {};
+ void f() {
+ function<void(Old)> func;
+ }
+ } // namespace ns)";
+ std::string Expected = R"(
+ template <class T>
+ class function;
+ template <class R, class... ArgTypes>
+ class function<R(ArgTypes...)> {
+ public:
+ template <typename Functor>
+ function(Functor f) {}
+
+ function() {}
+
+ R operator()(ArgTypes...) const {}
+ };
+
+ namespace ns {
+ class New {};
+ void f() {
+ function<void(::new_ns::New)> func;
+ }
+ } // namespace ns)";
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, DontChangeIfSameName) {
+ std::string Before = R"(
+ namespace foo {
+ class Old {
+ public:
+ static void foo() {}
+ };
+ }
+
+ void f(foo::Old * x) {
+ foo::Old::foo() ;
+ }
+ using foo::Old;)";
+ std::string Expected = R"(
+ namespace foo {
+ class Old {
+ public:
+ static void foo() {}
+ };
+ }
+
+ void f(foo::Old * x) {
+ foo::Old::foo() ;
+ }
+ using foo::Old;)";
+ std::string After = runClangRenameOnCode(Before, "foo::Old", "foo::Old");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, ChangeIfNewNameWithLeadingDotDot) {
+ std::string Before = R"(
+ namespace foo {
+ class Old {
+ public:
+ static void foo() {}
+ };
+ }
+
+ void f(foo::Old * x) {
+ foo::Old::foo() ;
+ }
+ using foo::Old;)";
+ std::string Expected = R"(
+ namespace foo {
+ class Old {
+ public:
+ static void foo() {}
+ };
+ }
+
+ void f(::foo::Old * x) {
+ ::foo::Old::foo() ;
+ }
+ using ::foo::Old;)";
+ std::string After = runClangRenameOnCode(Before, "foo::Old", "::foo::Old");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, ChangeIfSameNameWithLeadingDotDot) {
+ std::string Before = R"(
+ namespace foo {
+ class Old {
+ public:
+ static void foo() {}
+ };
+ }
+
+ void f(foo::Old * x) {
+ foo::Old::foo() ;
+ }
+ using foo::Old;)";
+ std::string Expected = R"(
+ namespace foo {
+ class Old {
+ public:
+ static void foo() {}
+ };
+ }
+
+ void f(::foo::Old * x) {
+ ::foo::Old::foo() ;
+ }
+ using ::foo::Old;)";
+ std::string After = runClangRenameOnCode(Before, "::foo::Old", "::foo::Old");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameClassTest, UsingAlias) {
+ std::string Before = R"(
+ namespace a { struct A {}; }
+
+ namespace foo {
+ using Alias = a::A;
+ Alias a;
+ })";
+ std::string Expected = R"(
+ namespace a { struct B {}; }
+
+ namespace foo {
+ using Alias = b::B;
+ Alias a;
+ })";
+ std::string After = runClangRenameOnCode(Before, "a::A", "b::B");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(ClangRenameTest, NestedTemplates) {
+ std::string Before = R"(
+ namespace a { template <typename T> struct A {}; }
+ a::A<a::A<int>> foo;)";
+ std::string Expected = R"(
+ namespace a { template <typename T> struct B {}; }
+ b::B<b::B<int>> foo;)";
+ std::string After = runClangRenameOnCode(Before, "a::A", "b::B");
+ CompareSnippets(Expected, After);
+}
+
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang
diff --git a/unittests/Rename/RenameEnumTest.cpp b/unittests/Rename/RenameEnumTest.cpp
new file mode 100644
index 0000000000..55dcd11ac4
--- /dev/null
+++ b/unittests/Rename/RenameEnumTest.cpp
@@ -0,0 +1,189 @@
+#include "ClangRenameTest.h"
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+namespace {
+
+class RenameEnumTest : public ClangRenameTest {
+public:
+ RenameEnumTest() {
+ AppendToHeader(R"(
+ #define MACRO(x) x
+ namespace a {
+ enum A1 { Red };
+ enum class A2 { Blue };
+ struct C {
+ enum NestedEnum { White };
+ enum class NestedScopedEnum { Black };
+ };
+ namespace d {
+ enum A3 { Orange };
+ } // namespace d
+ enum A4 { Pink };
+ } // namespace a
+ enum A5 { Green };)");
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(
+ RenameEnumTests, RenameEnumTest,
+ testing::ValuesIn(std::vector<Case>({
+ {"void f(a::A2 arg) { a::A2 t = a::A2::Blue; }",
+ "void f(b::B2 arg) { b::B2 t = b::B2::Blue; }", "a::A2", "b::B2"},
+ {"void f() { a::A1* t1; }", "void f() { b::B1* t1; }", "a::A1",
+ "b::B1"},
+ {"void f() { a::A2* t1; }", "void f() { b::B2* t1; }", "a::A2",
+ "b::B2"},
+ {"void f() { enum a::A2 t = a::A2::Blue; }",
+ "void f() { enum b::B2 t = b::B2::Blue; }", "a::A2", "b::B2"},
+ {"void f() { enum a::A2 t = a::A2::Blue; }",
+ "void f() { enum b::B2 t = b::B2::Blue; }", "a::A2", "b::B2"},
+
+ {"void f() { a::A1 t = a::Red; }", "void f() { b::B1 t = b::B1::Red; }",
+ "a::A1", "b::B1"},
+ {"void f() { a::A1 t = a::A1::Red; }",
+ "void f() { b::B1 t = b::B1::Red; }", "a::A1", "b::B1"},
+ {"void f() { auto t = a::Red; }", "void f() { auto t = b::B1::Red; }",
+ "a::A1", "b::B1"},
+ {"namespace b { void f() { a::A1 t = a::Red; } }",
+ "namespace b { void f() { B1 t = B1::Red; } }", "a::A1", "b::B1"},
+ {"void f() { a::d::A3 t = a::d::Orange; }",
+ "void f() { a::b::B3 t = a::b::B3::Orange; }", "a::d::A3", "a::b::B3"},
+ {"namespace a { void f() { a::d::A3 t = a::d::Orange; } }",
+ "namespace a { void f() { b::B3 t = b::B3::Orange; } }", "a::d::A3",
+ "a::b::B3"},
+ {"void f() { A5 t = Green; }", "void f() { B5 t = Green; }", "A5",
+ "B5"},
+ // FIXME: the new namespace qualifier should be added to the unscoped
+ // enum constant.
+ {"namespace a { void f() { auto t = Green; } }",
+ "namespace a { void f() { auto t = Green; } }", "a::A1", "b::B1"},
+
+ // namespace qualifiers
+ {"namespace a { void f(A1 a1) {} }",
+ "namespace a { void f(b::B1 a1) {} }", "a::A1", "b::B1"},
+ {"namespace a { void f(A2 a2) {} }",
+ "namespace a { void f(b::B2 a2) {} }", "a::A2", "b::B2"},
+ {"namespace b { void f(a::A1 a1) {} }",
+ "namespace b { void f(B1 a1) {} }", "a::A1", "b::B1"},
+ {"namespace b { void f(a::A2 a2) {} }",
+ "namespace b { void f(B2 a2) {} }", "a::A2", "b::B2"},
+
+ // nested enums
+ {"void f() { a::C::NestedEnum t = a::C::White; }",
+ "void f() { a::C::NewNestedEnum t = a::C::NewNestedEnum::White; }",
+ "a::C::NestedEnum", "a::C::NewNestedEnum"},
+ {"void f() { a::C::NestedScopedEnum t = a::C::NestedScopedEnum::Black; "
+ "}",
+ "void f() { a::C::NewNestedScopedEnum t = "
+ "a::C::NewNestedScopedEnum::Black; }",
+ "a::C::NestedScopedEnum", "a::C::NewNestedScopedEnum"},
+
+ // macros
+ {"void f(MACRO(a::A1) a1) {}", "void f(MACRO(b::B1) a1) {}", "a::A1",
+ "b::B1"},
+ {"void f(MACRO(a::A2) a2) {}", "void f(MACRO(b::B2) a2) {}", "a::A2",
+ "b::B2"},
+ {"#define FOO(T, t) T t\nvoid f() { FOO(a::A1, a1); }",
+ "#define FOO(T, t) T t\nvoid f() { FOO(b::B1, a1); }", "a::A1",
+ "b::B1"},
+ {"#define FOO(T, t) T t\nvoid f() { FOO(a::A2, a2); }",
+ "#define FOO(T, t) T t\nvoid f() { FOO(b::B2, a2); }", "a::A2",
+ "b::B2"},
+ {"#define FOO(n) a::A1 n\nvoid f() { FOO(a1); FOO(a2); }",
+ "#define FOO(n) b::B1 n\nvoid f() { FOO(a1); FOO(a2); }", "a::A1",
+ "b::B1"},
+
+ // using and type alias
+ {"using a::A1; A1 gA;", "using b::B1; b::B1 gA;", "a::A1", "b::B1"},
+ {"using a::A2; A2 gA;", "using b::B2; b::B2 gA;", "a::A2", "b::B2"},
+ {"struct S { using T = a::A1; T a_; };",
+ "struct S { using T = b::B1; T a_; };", "a::A1", "b::B1"},
+ {"using T = a::A1; T gA;", "using T = b::B1; T gA;", "a::A1", "b::B1"},
+ {"using T = a::A2; T gA;", "using T = b::B2; T gA;", "a::A2", "b::B2"},
+ {"typedef a::A1 T; T gA;", "typedef b::B1 T; T gA;", "a::A1", "b::B1"},
+ {"typedef a::A2 T; T gA;", "typedef b::B2 T; T gA;", "a::A2", "b::B2"},
+ {"typedef MACRO(a::A1) T; T gA;", "typedef MACRO(b::B1) T; T gA;",
+ "a::A1", "b::B1"},
+
+ // templates
+ {"template<typename T> struct Foo { T t; }; void f() { Foo<a::A1> "
+ "foo1; }",
+ "template<typename T> struct Foo { T t; }; void f() { Foo<b::B1> "
+ "foo1; }",
+ "a::A1", "b::B1"},
+ {"template<typename T> struct Foo { T t; }; void f() { Foo<a::A2> "
+ "foo2; }",
+ "template<typename T> struct Foo { T t; }; void f() { Foo<b::B2> "
+ "foo2; }",
+ "a::A2", "b::B2"},
+ {"template<typename T> struct Foo { a::A1 a1; };",
+ "template<typename T> struct Foo { b::B1 a1; };", "a::A1", "b::B1"},
+ {"template<typename T> struct Foo { a::A2 a2; };",
+ "template<typename T> struct Foo { b::B2 a2; };", "a::A2", "b::B2"},
+ {"template<typename T> int f() { return 1; } template<> int f<a::A1>() "
+ "{ return 2; } int g() { return f<a::A1>(); }",
+ "template<typename T> int f() { return 1; } template<> int f<b::B1>() "
+ "{ return 2; } int g() { return f<b::B1>(); }",
+ "a::A1", "b::B1"},
+ {"template<typename T> int f() { return 1; } template<> int f<a::A2>() "
+ "{ return 2; } int g() { return f<a::A2>(); }",
+ "template<typename T> int f() { return 1; } template<> int f<b::B2>() "
+ "{ return 2; } int g() { return f<b::B2>(); }",
+ "a::A2", "b::B2"},
+ {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "f.foo<a::A1>(); }",
+ "struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "f.foo<b::B1>(); }",
+ "a::A1", "b::B1"},
+ {"struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "f.foo<a::A2>(); }",
+ "struct Foo { template <typename T> T foo(); }; void g() { Foo f; "
+ "f.foo<b::B2>(); }",
+ "a::A2", "b::B2"},
+ })), );
+
+TEST_P(RenameEnumTest, RenameEnums) {
+ auto Param = GetParam();
+ assert(!Param.OldName.empty());
+ assert(!Param.NewName.empty());
+ std::string Actual =
+ runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+ CompareSnippets(Param.After, Actual);
+}
+
+TEST_F(RenameEnumTest, RenameEnumDecl) {
+ std::string Before = R"(
+ namespace ns {
+ enum Old1 { Blue };
+ }
+ )";
+ std::string Expected = R"(
+ namespace ns {
+ enum New1 { Blue };
+ }
+ )";
+ std::string After = runClangRenameOnCode(Before, "ns::Old1", "ns::New1");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameEnumTest, RenameScopedEnumDecl) {
+ std::string Before = R"(
+ namespace ns {
+ enum class Old1 { Blue };
+ }
+ )";
+ std::string Expected = R"(
+ namespace ns {
+ enum class New1 { Blue };
+ }
+ )";
+ std::string After = runClangRenameOnCode(Before, "ns::Old1", "ns::New1");
+ CompareSnippets(Expected, After);
+}
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang
diff --git a/unittests/Rename/RenameFunctionTest.cpp b/unittests/Rename/RenameFunctionTest.cpp
new file mode 100644
index 0000000000..b27bbe273a
--- /dev/null
+++ b/unittests/Rename/RenameFunctionTest.cpp
@@ -0,0 +1,574 @@
+//===-- RenameFunctionTest.cpp - unit tests for renaming functions --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangRenameTest.h"
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+namespace {
+
+class RenameFunctionTest : public ClangRenameTest {
+public:
+ RenameFunctionTest() {
+ AppendToHeader(R"(
+ struct A {
+ static bool Foo();
+ static bool Spam();
+ };
+ struct B {
+ static void Same();
+ static bool Foo();
+ static int Eric(int x);
+ };
+ void Same(int x);
+ int Eric(int x);
+ namespace base {
+ void Same();
+ void ToNanoSeconds();
+ void ToInt64NanoSeconds();
+ })");
+ }
+};
+
+TEST_F(RenameFunctionTest, RefactorsAFoo) {
+ std::string Before = R"(
+ void f() {
+ A::Foo();
+ ::A::Foo();
+ })";
+ std::string Expected = R"(
+ void f() {
+ A::Bar();
+ ::A::Bar();
+ })";
+
+ std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RefactorsNonCallingAFoo) {
+ std::string Before = R"(
+ bool g(bool (*func)()) {
+ return func();
+ }
+ void f() {
+ auto *ref1 = A::Foo;
+ auto *ref2 = ::A::Foo;
+ g(A::Foo);
+ })";
+ std::string Expected = R"(
+ bool g(bool (*func)()) {
+ return func();
+ }
+ void f() {
+ auto *ref1 = A::Bar;
+ auto *ref2 = ::A::Bar;
+ g(A::Bar);
+ })";
+ std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RefactorsEric) {
+ std::string Before = R"(
+ void f() {
+ if (Eric(3)==4) ::Eric(2);
+ })";
+ std::string Expected = R"(
+ void f() {
+ if (Larry(3)==4) ::Larry(2);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RefactorsNonCallingEric) {
+ std::string Before = R"(
+ int g(int (*func)(int)) {
+ return func(1);
+ }
+ void f() {
+ auto *ref = ::Eric;
+ g(Eric);
+ })";
+ std::string Expected = R"(
+ int g(int (*func)(int)) {
+ return func(1);
+ }
+ void f() {
+ auto *ref = ::Larry;
+ g(Larry);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorBFoo) {
+ std::string Before = R"(
+ void f() {
+ B::Foo();
+ })";
+ std::string After = runClangRenameOnCode(Before, "A::Foo", "A::Bar");
+ CompareSnippets(Before, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorBEric) {
+ std::string Before = R"(
+ void f() {
+ B::Eric(2);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Before, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorCEric) {
+ std::string Before = R"(
+ namespace C { int Eric(int x); }
+ void f() {
+ if (C::Eric(3)==4) ::C::Eric(2);
+ })";
+ std::string Expected = R"(
+ namespace C { int Eric(int x); }
+ void f() {
+ if (C::Eric(3)==4) ::C::Eric(2);
+ })";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, DoesNotRefactorEricInNamespaceC) {
+ std::string Before = R"(
+ namespace C {
+ int Eric(int x);
+ void f() {
+ if (Eric(3)==4) Eric(2);
+ }
+ } // namespace C)";
+ std::string After = runClangRenameOnCode(Before, "Eric", "Larry");
+ CompareSnippets(Before, After);
+}
+
+TEST_F(RenameFunctionTest, NamespaceQualified) {
+ std::string Before = R"(
+ void f() {
+ base::ToNanoSeconds();
+ ::base::ToNanoSeconds();
+ }
+ void g() {
+ using base::ToNanoSeconds;
+ base::ToNanoSeconds();
+ ::base::ToNanoSeconds();
+ ToNanoSeconds();
+ }
+ namespace foo {
+ namespace base {
+ void ToNanoSeconds();
+ void f() {
+ base::ToNanoSeconds();
+ }
+ }
+ void f() {
+ ::base::ToNanoSeconds();
+ }
+ })";
+ std::string Expected = R"(
+ void f() {
+ base::ToInt64NanoSeconds();
+ ::base::ToInt64NanoSeconds();
+ }
+ void g() {
+ using base::ToInt64NanoSeconds;
+ base::ToInt64NanoSeconds();
+ ::base::ToInt64NanoSeconds();
+ base::ToInt64NanoSeconds();
+ }
+ namespace foo {
+ namespace base {
+ void ToNanoSeconds();
+ void f() {
+ base::ToNanoSeconds();
+ }
+ }
+ void f() {
+ ::base::ToInt64NanoSeconds();
+ }
+ })";
+ std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
+ "base::ToInt64NanoSeconds");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RenameFunctionDecls) {
+ std::string Before = R"(
+ namespace na {
+ void X();
+ void X() {}
+ })";
+ std::string Expected = R"(
+ namespace na {
+ void Y();
+ void Y() {}
+ })";
+ std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RenameTemplateFunctions) {
+ std::string Before = R"(
+ namespace na {
+ template<typename T> T X();
+ }
+ namespace na { void f() { X<int>(); } }
+ namespace nb { void g() { na::X <int>(); } }
+ )";
+ std::string Expected = R"(
+ namespace na {
+ template<typename T> T Y();
+ }
+ namespace na { void f() { nb::Y<int>(); } }
+ namespace nb { void g() { Y<int>(); } }
+ )";
+ std::string After = runClangRenameOnCode(Before, "na::X", "nb::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RenameOutOfLineFunctionDecls) {
+ std::string Before = R"(
+ namespace na {
+ void X();
+ }
+ void na::X() {}
+ )";
+ std::string Expected = R"(
+ namespace na {
+ void Y();
+ }
+ void na::Y() {}
+ )";
+ std::string After = runClangRenameOnCode(Before, "na::X", "na::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, NewNamespaceWithoutLeadingDotDot) {
+ std::string Before = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { old_ns::X(); }
+ namespace old_ns { void g() { X(); } }
+ namespace new_ns { void h() { ::old_ns::X(); } }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ void Y();
+ void Y() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { new_ns::Y(); }
+ namespace old_ns { void g() { new_ns::Y(); } }
+ namespace new_ns { void h() { Y(); } }
+ )";
+ std::string After = runClangRenameOnCode(Before, "::old_ns::X", "new_ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, NewNamespaceWithLeadingDotDot) {
+ std::string Before = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { old_ns::X(); }
+ namespace old_ns { void g() { X(); } }
+ namespace new_ns { void h() { ::old_ns::X(); } }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ void Y();
+ void Y() {}
+ }
+ // Assume that the reference is in another file.
+ void f() { ::new_ns::Y(); }
+ namespace old_ns { void g() { ::new_ns::Y(); } }
+ namespace new_ns { void h() { Y(); } }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::old_ns::X", "::new_ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, DontRenameSymbolsDefinedInAnonymousNamespace) {
+ std::string Before = R"(
+ namespace old_ns {
+ class X {};
+ namespace {
+ void X();
+ void X() {}
+ void f() { X(); }
+ }
+ }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ class Y {};
+ namespace {
+ void X();
+ void X() {}
+ void f() { X(); }
+ }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, NewNestedNamespace) {
+ std::string Before = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ namespace old_ns {
+ void f() { X(); }
+ }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ void X();
+ void X() {}
+ }
+ // Assume that the reference is in another file.
+ namespace old_ns {
+ void f() { older_ns::X(); }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::old_ns::X", "::old_ns::older_ns::X");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithoutLeadingDotDot) {
+ std::string Before = R"(
+ void X();
+ void X() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { X(); }
+ }
+ )";
+ std::string Expected = R"(
+ void X();
+ void X() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { ns::X(); }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::X", "ns::X");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, MoveFromGlobalToNamespaceWithLeadingDotDot) {
+ std::string Before = R"(
+ void Y() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { Y(); }
+ }
+ )";
+ std::string Expected = R"(
+ void Y() {}
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ void f() { ::ns::Y(); }
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "::Y", "::ns::Y");
+ CompareSnippets(Expected, After);
+}
+
+// FIXME: the rename of overloaded operator is not fully supported yet.
+TEST_F(RenameFunctionTest, DISABLED_DoNotRenameOverloadedOperatorCalls) {
+ std::string Before = R"(
+ namespace old_ns {
+ class T { public: int x; };
+ bool operator==(const T& lhs, const T& rhs) {
+ return lhs.x == rhs.x;
+ }
+ } // namespace old_ns
+
+ // Assume that the reference is in another file.
+ bool f() {
+ auto eq = old_ns::operator==;
+ old_ns::T t1, t2;
+ old_ns::operator==(t1, t2);
+ return t1 == t2;
+ }
+ )";
+ std::string Expected = R"(
+ namespace old_ns {
+ class T { public: int x; };
+ bool operator==(const T& lhs, const T& rhs) {
+ return lhs.x == rhs.x;
+ }
+ } // namespace old_ns
+
+ // Assume that the reference is in another file.
+ bool f() {
+ auto eq = new_ns::operator==;
+ old_ns::T t1, t2;
+ new_ns::operator==(t1, t2);
+ return t1 == t2;
+ }
+ )";
+ std::string After =
+ runClangRenameOnCode(Before, "old_ns::operator==", "new_ns::operator==");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, FunctionRefAsTemplate) {
+ std::string Before = R"(
+ void X();
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ template <void (*Func)(void)>
+ class TIterator {};
+
+ template <void (*Func)(void)>
+ class T {
+ public:
+ typedef TIterator<Func> IterType;
+ using TI = TIterator<Func>;
+ void g() {
+ Func();
+ auto func = Func;
+ TIterator<Func> iter;
+ }
+ };
+
+
+ void f() { T<X> tx; tx.g(); }
+ } // namespace some_ns
+ )";
+ std::string Expected = R"(
+ void X();
+
+ // Assume that the reference is in another file.
+ namespace some_ns {
+ template <void (*Func)(void)>
+ class TIterator {};
+
+ template <void (*Func)(void)>
+ class T {
+ public:
+ typedef TIterator<Func> IterType;
+ using TI = TIterator<Func>;
+ void g() {
+ Func();
+ auto func = Func;
+ TIterator<Func> iter;
+ }
+ };
+
+
+ void f() { T<ns::X> tx; tx.g(); }
+ } // namespace some_ns
+ )";
+ std::string After = runClangRenameOnCode(Before, "::X", "ns::X");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameFunctionTest, RenameFunctionInUsingDecl) {
+ std::string Before = R"(
+ using base::ToNanoSeconds;
+ namespace old_ns {
+ using base::ToNanoSeconds;
+ void f() {
+ using base::ToNanoSeconds;
+ }
+ }
+ )";
+ std::string Expected = R"(
+ using base::ToInt64NanoSeconds;
+ namespace old_ns {
+ using base::ToInt64NanoSeconds;
+ void f() {
+ using base::ToInt64NanoSeconds;
+ }
+ }
+ )";
+ std::string After = runClangRenameOnCode(Before, "base::ToNanoSeconds",
+ "base::ToInt64NanoSeconds");
+ CompareSnippets(Expected, After);
+}
+
+// FIXME: Fix the complex the case where the symbol being renamed is located in
+// `std::function<decltype<renamed_symbol>>`.
+TEST_F(ClangRenameTest, DISABLED_ReferencesInLambdaFunctionParameters) {
+ std::string Before = R"(
+ template <class T>
+ class function;
+ template <class R, class... ArgTypes>
+ class function<R(ArgTypes...)> {
+ public:
+ template <typename Functor>
+ function(Functor f) {}
+
+ function() {}
+
+ R operator()(ArgTypes...) const {}
+ };
+
+ namespace ns {
+ void Old() {}
+ void f() {
+ function<decltype(Old)> func;
+ }
+ } // namespace ns)";
+ std::string Expected = R"(
+ template <class T>
+ class function;
+ template <class R, class... ArgTypes>
+ class function<R(ArgTypes...)> {
+ public:
+ template <typename Functor>
+ function(Functor f) {}
+
+ function() {}
+
+ R operator()(ArgTypes...) const {}
+ };
+
+ namespace ns {
+ void New() {}
+ void f() {
+ function<decltype(::new_ns::New)> func;
+ }
+ } // namespace ns)";
+ std::string After = runClangRenameOnCode(Before, "ns::Old", "::new_ns::New");
+ CompareSnippets(Expected, After);
+}
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang
diff --git a/unittests/Rename/RenameMemberTest.cpp b/unittests/Rename/RenameMemberTest.cpp
new file mode 100644
index 0000000000..463f7c70de
--- /dev/null
+++ b/unittests/Rename/RenameMemberTest.cpp
@@ -0,0 +1,229 @@
+//===-- ClangMemberTests.cpp - unit tests for renaming class members ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangRenameTest.h"
+
+namespace clang {
+namespace clang_rename {
+namespace test {
+namespace {
+
+class RenameMemberTest : public ClangRenameTest {
+public:
+ RenameMemberTest() {
+ AppendToHeader(R"(
+ struct NA {
+ void Foo();
+ void NotFoo();
+ static void SFoo();
+ static void SNotFoo();
+ int Moo;
+ };
+ struct A {
+ virtual void Foo();
+ void NotFoo();
+ static void SFoo();
+ static void SNotFoo();
+ int Moo;
+ int NotMoo;
+ static int SMoo;
+ };
+ struct B : public A {
+ void Foo() override;
+ };
+ template <typename T> struct TA {
+ T* Foo();
+ T* NotFoo();
+ static T* SFoo();
+ static T* NotSFoo();
+ };
+ template <typename T> struct TB : public TA<T> {};
+ namespace ns {
+ template <typename T> struct TA {
+ T* Foo();
+ T* NotFoo();
+ static T* SFoo();
+ static T* NotSFoo();
+ static int SMoo;
+ };
+ template <typename T> struct TB : public TA<T> {};
+ struct A {
+ void Foo();
+ void NotFoo();
+ static void SFoo();
+ static void SNotFoo();
+ };
+ struct B : public A {};
+ struct C {
+ template <class T>
+ void SFoo(const T& t) {}
+ template <class T>
+ void Foo() {}
+ };
+ })");
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(
+ DISABLED_RenameTemplatedClassStaticVariableTest, RenameMemberTest,
+ testing::ValuesIn(std::vector<Case>({
+ // FIXME: support renaming static variables for template classes.
+ {"void f() { ns::TA<int>::SMoo; }",
+ "void f() { ns::TA<int>::SMeh; }", "ns::TA::SMoo", "ns::TA::SMeh"},
+ })), );
+
+INSTANTIATE_TEST_CASE_P(
+ RenameMemberTest, RenameMemberTest,
+ testing::ValuesIn(std::vector<Case>({
+ // Normal methods and fields.
+ {"void f() { A a; a.Foo(); }", "void f() { A a; a.Bar(); }", "A::Foo",
+ "A::Bar"},
+ {"void f() { ns::A a; a.Foo(); }", "void f() { ns::A a; a.Bar(); }",
+ "ns::A::Foo", "ns::A::Bar"},
+ {"void f() { A a; int x = a.Moo; }", "void f() { A a; int x = a.Meh; }",
+ "A::Moo", "A::Meh"},
+ {"void f() { B b; b.Foo(); }", "void f() { B b; b.Bar(); }", "B::Foo",
+ "B::Bar"},
+ {"void f() { ns::B b; b.Foo(); }", "void f() { ns::B b; b.Bar(); }",
+ "ns::A::Foo", "ns::A::Bar"},
+ {"void f() { B b; int x = b.Moo; }", "void f() { B b; int x = b.Meh; }",
+ "A::Moo", "A::Meh"},
+
+ // Static methods.
+ {"void f() { A::SFoo(); }", "void f() { A::SBar(); }", "A::SFoo",
+ "A::SBar"},
+ {"void f() { ns::A::SFoo(); }", "void f() { ns::A::SBar(); }",
+ "ns::A::SFoo", "ns::A::SBar"},
+ {"void f() { TA<int>::SFoo(); }", "void f() { TA<int>::SBar(); }",
+ "TA::SFoo", "TA::SBar"},
+ {"void f() { ns::TA<int>::SFoo(); }",
+ "void f() { ns::TA<int>::SBar(); }", "ns::TA::SFoo", "ns::TA::SBar"},
+
+ // Static variables.
+ {"void f() { A::SMoo; }",
+ "void f() { A::SMeh; }", "A::SMoo", "A::SMeh"},
+
+ // Templated methods.
+ {"void f() { TA<int> a; a.Foo(); }", "void f() { TA<int> a; a.Bar(); }",
+ "TA::Foo", "TA::Bar"},
+ {"void f() { ns::TA<int> a; a.Foo(); }",
+ "void f() { ns::TA<int> a; a.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"},
+ {"void f() { TB<int> b; b.Foo(); }", "void f() { TB<int> b; b.Bar(); }",
+ "TA::Foo", "TA::Bar"},
+ {"void f() { ns::TB<int> b; b.Foo(); }",
+ "void f() { ns::TB<int> b; b.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"},
+ {"void f() { ns::C c; int x; c.SFoo(x); }",
+ "void f() { ns::C c; int x; c.SBar(x); }", "ns::C::SFoo",
+ "ns::C::SBar"},
+ {"void f() { ns::C c; c.Foo<int>(); }",
+ "void f() { ns::C c; c.Bar<int>(); }", "ns::C::Foo", "ns::C::Bar"},
+
+ // Pointers to methods.
+ {"void f() { auto p = &A::Foo; }", "void f() { auto p = &A::Bar; }",
+ "A::Foo", "A::Bar"},
+ {"void f() { auto p = &A::SFoo; }", "void f() { auto p = &A::SBar; }",
+ "A::SFoo", "A::SBar"},
+ {"void f() { auto p = &B::Foo; }", "void f() { auto p = &B::Bar; }",
+ "B::Foo", "B::Bar"},
+ {"void f() { auto p = &ns::A::Foo; }",
+ "void f() { auto p = &ns::A::Bar; }", "ns::A::Foo", "ns::A::Bar"},
+ {"void f() { auto p = &ns::A::SFoo; }",
+ "void f() { auto p = &ns::A::SBar; }", "ns::A::SFoo", "ns::A::SBar"},
+ {"void f() { auto p = &ns::C::SFoo<int>; }",
+ "void f() { auto p = &ns::C::SBar<int>; }", "ns::C::SFoo",
+ "ns::C::SBar"},
+
+ // These methods are not declared or overrided in the subclass B, we
+ // have to use the qualified name with parent class A to identify them.
+ {"void f() { auto p = &ns::B::Foo; }",
+ "void f() { auto p = &ns::B::Bar; }", "ns::A::Foo", "ns::B::Bar"},
+ {"void f() { B::SFoo(); }", "void f() { B::SBar(); }", "A::SFoo",
+ "B::SBar"},
+ {"void f() { ns::B::SFoo(); }", "void f() { ns::B::SBar(); }",
+ "ns::A::SFoo", "ns::B::SBar"},
+ {"void f() { auto p = &B::SFoo; }", "void f() { auto p = &B::SBar; }",
+ "A::SFoo", "B::SBar"},
+ {"void f() { auto p = &ns::B::SFoo; }",
+ "void f() { auto p = &ns::B::SBar; }", "ns::A::SFoo", "ns::B::SBar"},
+ {"void f() { TB<int>::SFoo(); }", "void f() { TB<int>::SBar(); }",
+ "TA::SFoo", "TB::SBar"},
+ {"void f() { ns::TB<int>::SFoo(); }",
+ "void f() { ns::TB<int>::SBar(); }", "ns::TA::SFoo", "ns::TB::SBar"},
+ })), );
+
+TEST_P(RenameMemberTest, RenameMembers) {
+ auto Param = GetParam();
+ assert(!Param.OldName.empty());
+ assert(!Param.NewName.empty());
+ std::string Actual =
+ runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName);
+ CompareSnippets(Param.After, Actual);
+}
+
+TEST_F(RenameMemberTest, RenameMemberInsideClassMethods) {
+ std::string Before = R"(
+ struct X {
+ int Moo;
+ void Baz() { Moo = 1; }
+ };)";
+ std::string Expected = R"(
+ struct X {
+ int Meh;
+ void Baz() { Meh = 1; }
+ };)";
+ std::string After = runClangRenameOnCode(Before, "X::Moo", "Y::Meh");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameMemberTest, RenameMethodInsideClassMethods) {
+ std::string Before = R"(
+ struct X {
+ void Foo() {}
+ void Baz() { Foo(); }
+ };)";
+ std::string Expected = R"(
+ struct X {
+ void Bar() {}
+ void Baz() { Bar(); }
+ };)";
+ std::string After = runClangRenameOnCode(Before, "X::Foo", "X::Bar");
+ CompareSnippets(Expected, After);
+}
+
+TEST_F(RenameMemberTest, RenameCtorInitializer) {
+ std::string Before = R"(
+ class X {
+ public:
+ X();
+ A a;
+ A a2;
+ B b;
+ };
+
+ X::X():a(), b() {}
+ )";
+ std::string Expected = R"(
+ class X {
+ public:
+ X();
+ A bar;
+ A a2;
+ B b;
+ };
+
+ X::X():bar(), b() {}
+ )";
+ std::string After = runClangRenameOnCode(Before, "X::a", "X::bar");
+ CompareSnippets(Expected, After);
+}
+
+} // anonymous namespace
+} // namespace test
+} // namespace clang_rename
+} // namesdpace clang
diff --git a/unittests/Tooling/ASTSelectionTest.cpp b/unittests/Tooling/ASTSelectionTest.cpp
new file mode 100644
index 0000000000..1435334d6c
--- /dev/null
+++ b/unittests/Tooling/ASTSelectionTest.cpp
@@ -0,0 +1,975 @@
+//===- unittest/Tooling/ASTSelectionTest.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+struct FileLocation {
+ unsigned Line, Column;
+
+ SourceLocation translate(const SourceManager &SM) {
+ return SM.translateLineCol(SM.getMainFileID(), Line, Column);
+ }
+};
+
+using FileRange = std::pair<FileLocation, FileLocation>;
+
+class SelectionFinderVisitor : public TestVisitor<SelectionFinderVisitor> {
+ FileLocation Location;
+ Optional<FileRange> SelectionRange;
+ llvm::function_ref<void(SourceRange SelectionRange,
+ Optional<SelectedASTNode>)>
+ Consumer;
+
+public:
+ SelectionFinderVisitor(FileLocation Location,
+ Optional<FileRange> SelectionRange,
+ llvm::function_ref<void(SourceRange SelectionRange,
+ Optional<SelectedASTNode>)>
+ Consumer)
+ : Location(Location), SelectionRange(SelectionRange), Consumer(Consumer) {
+ }
+
+ bool VisitTranslationUnitDecl(const TranslationUnitDecl *TU) {
+ const ASTContext &Context = TU->getASTContext();
+ const SourceManager &SM = Context.getSourceManager();
+
+ SourceRange SelRange;
+ if (SelectionRange) {
+ SelRange = SourceRange(SelectionRange->first.translate(SM),
+ SelectionRange->second.translate(SM));
+ } else {
+ SourceLocation Loc = Location.translate(SM);
+ SelRange = SourceRange(Loc, Loc);
+ }
+ Consumer(SelRange, findSelectedASTNodes(Context, SelRange));
+ return false;
+ }
+};
+
+/// This is a test utility function that computes the AST selection at the
+/// given location with an optional selection range.
+///
+/// A location roughly corresponds to a cursor location in an editor, while
+/// the optional range corresponds to the selection range in an editor.
+void findSelectedASTNodesWithRange(
+ StringRef Source, FileLocation Location, Optional<FileRange> SelectionRange,
+ llvm::function_ref<void(SourceRange SelectionRange,
+ Optional<SelectedASTNode>)>
+ Consumer,
+ SelectionFinderVisitor::Language Language =
+ SelectionFinderVisitor::Lang_CXX11) {
+ SelectionFinderVisitor Visitor(Location, SelectionRange, Consumer);
+ EXPECT_TRUE(Visitor.runOver(Source, Language));
+}
+
+void findSelectedASTNodes(
+ StringRef Source, FileLocation Location, Optional<FileRange> SelectionRange,
+ llvm::function_ref<void(Optional<SelectedASTNode>)> Consumer,
+ SelectionFinderVisitor::Language Language =
+ SelectionFinderVisitor::Lang_CXX11) {
+ findSelectedASTNodesWithRange(
+ Source, Location, SelectionRange,
+ [&](SourceRange, Optional<SelectedASTNode> Selection) {
+ Consumer(std::move(Selection));
+ },
+ Language);
+}
+
+void checkNodeImpl(bool IsTypeMatched, const SelectedASTNode &Node,
+ SourceSelectionKind SelectionKind, unsigned NumChildren) {
+ ASSERT_TRUE(IsTypeMatched);
+ EXPECT_EQ(Node.Children.size(), NumChildren);
+ ASSERT_EQ(Node.SelectionKind, SelectionKind);
+}
+
+void checkDeclName(const SelectedASTNode &Node, StringRef Name) {
+ const auto *ND = Node.Node.get<NamedDecl>();
+ EXPECT_TRUE(!!ND);
+ ASSERT_EQ(ND->getName(), Name);
+}
+
+template <typename T>
+const SelectedASTNode &
+checkNode(const SelectedASTNode &StmtNode, SourceSelectionKind SelectionKind,
+ unsigned NumChildren = 0,
+ typename std::enable_if<std::is_base_of<Stmt, T>::value, T>::type
+ *StmtOverloadChecker = nullptr) {
+ checkNodeImpl(isa<T>(StmtNode.Node.get<Stmt>()), StmtNode, SelectionKind,
+ NumChildren);
+ return StmtNode;
+}
+
+template <typename T>
+const SelectedASTNode &
+checkNode(const SelectedASTNode &DeclNode, SourceSelectionKind SelectionKind,
+ unsigned NumChildren = 0, StringRef Name = "",
+ typename std::enable_if<std::is_base_of<Decl, T>::value, T>::type
+ *DeclOverloadChecker = nullptr) {
+ checkNodeImpl(isa<T>(DeclNode.Node.get<Decl>()), DeclNode, SelectionKind,
+ NumChildren);
+ if (!Name.empty())
+ checkDeclName(DeclNode, Name);
+ return DeclNode;
+}
+
+struct ForAllChildrenOf {
+ const SelectedASTNode &Node;
+
+ static void childKindVerifier(const SelectedASTNode &Node,
+ SourceSelectionKind SelectionKind) {
+ for (const SelectedASTNode &Child : Node.Children) {
+ ASSERT_EQ(Node.SelectionKind, SelectionKind);
+ childKindVerifier(Child, SelectionKind);
+ }
+ }
+
+public:
+ ForAllChildrenOf(const SelectedASTNode &Node) : Node(Node) {}
+
+ void shouldHaveSelectionKind(SourceSelectionKind Kind) {
+ childKindVerifier(Node, Kind);
+ }
+};
+
+ForAllChildrenOf allChildrenOf(const SelectedASTNode &Node) {
+ return ForAllChildrenOf(Node);
+}
+
+TEST(ASTSelectionFinder, CursorNoSelection) {
+ findSelectedASTNodes(
+ " void f() { }", {1, 1}, None,
+ [](Optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
+}
+
+TEST(ASTSelectionFinder, CursorAtStartOfFunction) {
+ findSelectedASTNodes(
+ "void f() { }", {1, 1}, None, [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ checkNode<TranslationUnitDecl>(*Node, SourceSelectionKind::None,
+ /*NumChildren=*/1);
+ checkNode<FunctionDecl>(Node->Children[0],
+ SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/0, /*Name=*/"f");
+
+ // Check that the dumping works.
+ std::string DumpValue;
+ llvm::raw_string_ostream OS(DumpValue);
+ Node->Children[0].dump(OS);
+ ASSERT_EQ(OS.str(), "FunctionDecl \"f\" contains-selection\n");
+ });
+}
+
+TEST(ASTSelectionFinder, RangeNoSelection) {
+ findSelectedASTNodes(
+ " void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
+ [](Optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
+ findSelectedASTNodes(
+ " void f() { }", {1, 1}, FileRange{{1, 1}, {1, 2}},
+ [](Optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
+}
+
+TEST(ASTSelectionFinder, EmptyRangeFallbackToCursor) {
+ findSelectedASTNodes("void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ checkNode<FunctionDecl>(
+ Node->Children[0],
+ SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/0, /*Name=*/"f");
+ });
+}
+
+TEST(ASTSelectionFinder, WholeFunctionSelection) {
+ StringRef Source = "int f(int x) { return x;\n}\nvoid f2() { }";
+ // From 'int' until just after '}':
+
+ findSelectedASTNodes(
+ Source, {1, 1}, FileRange{{1, 1}, {2, 2}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/2, /*Name=*/"f");
+ checkNode<ParmVarDecl>(Fn.Children[0],
+ SourceSelectionKind::InsideSelection);
+ const auto &Body = checkNode<CompoundStmt>(
+ Fn.Children[1], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ const auto &Return = checkNode<ReturnStmt>(
+ Body.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<ImplicitCastExpr>(Return.Children[0],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<DeclRefExpr>(Return.Children[0].Children[0],
+ SourceSelectionKind::InsideSelection);
+ });
+
+ // From 'int' until just before '}':
+ findSelectedASTNodes(
+ Source, {2, 1}, FileRange{{1, 1}, {2, 1}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/2, /*Name=*/"f");
+ const auto &Body = checkNode<CompoundStmt>(
+ Fn.Children[1], SourceSelectionKind::ContainsSelectionEnd,
+ /*NumChildren=*/1);
+ checkNode<ReturnStmt>(Body.Children[0],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ });
+ // From '{' until just after '}':
+ findSelectedASTNodes(
+ Source, {1, 14}, FileRange{{1, 14}, {2, 2}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"f");
+ const auto &Body = checkNode<CompoundStmt>(
+ Fn.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ checkNode<ReturnStmt>(Body.Children[0],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ });
+ // From 'x' until just after '}':
+ findSelectedASTNodes(
+ Source, {2, 2}, FileRange{{1, 11}, {2, 2}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/2, /*Name=*/"f");
+ checkNode<ParmVarDecl>(Fn.Children[0],
+ SourceSelectionKind::ContainsSelectionStart);
+ const auto &Body = checkNode<CompoundStmt>(
+ Fn.Children[1], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<ReturnStmt>(Body.Children[0],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ });
+}
+
+TEST(ASTSelectionFinder, MultipleFunctionSelection) {
+ StringRef Source = R"(void f0() {
+}
+void f1() { }
+void f2() { }
+void f3() { }
+)";
+ auto SelectedF1F2 = [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 2u);
+ checkNode<FunctionDecl>(Node->Children[0],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1, /*Name=*/"f1");
+ checkNode<FunctionDecl>(Node->Children[1],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1, /*Name=*/"f2");
+ };
+ // Just after '}' of f0 and just before 'void' of f3:
+ findSelectedASTNodes(Source, {2, 2}, FileRange{{2, 2}, {5, 1}}, SelectedF1F2);
+ // Just before 'void' of f1 and just after '}' of f2:
+ findSelectedASTNodes(Source, {3, 1}, FileRange{{3, 1}, {4, 14}},
+ SelectedF1F2);
+}
+
+TEST(ASTSelectionFinder, MultipleStatementSelection) {
+ StringRef Source = R"(void f(int x, int y) {
+ int z = x;
+ f(2, 3);
+ if (x == 0) {
+ return;
+ }
+ x = 1;
+ return;
+})";
+ // From 'f(2,3)' until just before 'x = 1;':
+ findSelectedASTNodes(
+ Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"f");
+ const auto &Body = checkNode<CompoundStmt>(
+ Fn.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/2);
+ allChildrenOf(checkNode<CallExpr>(Body.Children[0],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/3))
+ .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
+ allChildrenOf(checkNode<IfStmt>(Body.Children[1],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/2))
+ .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
+ });
+ // From 'f(2,3)' until just before ';' in 'x = 1;':
+ findSelectedASTNodes(
+ Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"f");
+ const auto &Body = checkNode<CompoundStmt>(
+ Fn.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/3);
+ checkNode<CallExpr>(Body.Children[0],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/3);
+ checkNode<IfStmt>(Body.Children[1],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/2);
+ checkNode<BinaryOperator>(Body.Children[2],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/2);
+ });
+ // From the middle of 'int z = 3' until the middle of 'x = 1;':
+ findSelectedASTNodes(
+ Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"f");
+ const auto &Body = checkNode<CompoundStmt>(
+ Fn.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/4);
+ checkNode<DeclStmt>(Body.Children[0],
+ SourceSelectionKind::ContainsSelectionStart,
+ /*NumChildren=*/1);
+ checkNode<CallExpr>(Body.Children[1],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/3);
+ checkNode<IfStmt>(Body.Children[2],
+ SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/2);
+ checkNode<BinaryOperator>(Body.Children[3],
+ SourceSelectionKind::ContainsSelectionEnd,
+ /*NumChildren=*/1);
+ });
+}
+
+TEST(ASTSelectionFinder, SelectionInFunctionInObjCImplementation) {
+ StringRef Source = R"(
+@interface I
+@end
+@implementation I
+
+int notSelected() { }
+
+int selected(int x) {
+ return x;
+}
+
+@end
+@implementation I(Cat)
+
+void catF() { }
+
+@end
+
+void outerFunction() { }
+)";
+ // Just the 'x' expression in 'selected':
+ findSelectedASTNodes(
+ Source, {9, 10}, FileRange{{9, 10}, {9, 11}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Impl = checkNode<ObjCImplementationDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"I");
+ const auto &Fn = checkNode<FunctionDecl>(
+ Impl.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"selected");
+ allChildrenOf(Fn).shouldHaveSelectionKind(
+ SourceSelectionKind::ContainsSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // The entire 'catF':
+ findSelectedASTNodes(
+ Source, {15, 1}, FileRange{{15, 1}, {15, 16}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Impl = checkNode<ObjCCategoryImplDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"Cat");
+ const auto &Fn = checkNode<FunctionDecl>(
+ Impl.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"catF");
+ allChildrenOf(Fn).shouldHaveSelectionKind(
+ SourceSelectionKind::ContainsSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // From the line before 'selected' to the line after 'catF':
+ findSelectedASTNodes(
+ Source, {16, 1}, FileRange{{7, 1}, {16, 1}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 2u);
+ const auto &Impl = checkNode<ObjCImplementationDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelectionStart,
+ /*NumChildren=*/1, /*Name=*/"I");
+ const auto &Selected = checkNode<FunctionDecl>(
+ Impl.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/2, /*Name=*/"selected");
+ allChildrenOf(Selected).shouldHaveSelectionKind(
+ SourceSelectionKind::InsideSelection);
+ const auto &Cat = checkNode<ObjCCategoryImplDecl>(
+ Node->Children[1], SourceSelectionKind::ContainsSelectionEnd,
+ /*NumChildren=*/1, /*Name=*/"Cat");
+ const auto &CatF = checkNode<FunctionDecl>(
+ Cat.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1, /*Name=*/"catF");
+ allChildrenOf(CatF).shouldHaveSelectionKind(
+ SourceSelectionKind::InsideSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // Just the 'outer' function:
+ findSelectedASTNodes(Source, {19, 1}, FileRange{{19, 1}, {19, 25}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ checkNode<FunctionDecl>(
+ Node->Children[0],
+ SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"outerFunction");
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+}
+
+TEST(ASTSelectionFinder, FunctionInObjCImplementationCarefulWithEarlyExit) {
+ StringRef Source = R"(
+@interface I
+@end
+@implementation I
+
+void selected() {
+}
+
+- (void) method { }
+
+@end
+)";
+ // Just 'selected'
+ findSelectedASTNodes(
+ Source, {6, 1}, FileRange{{6, 1}, {7, 2}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Impl = checkNode<ObjCImplementationDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"I");
+ checkNode<FunctionDecl>(Impl.Children[0],
+ SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, /*Name=*/"selected");
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+}
+
+TEST(ASTSelectionFinder, AvoidImplicitDeclarations) {
+ StringRef Source = R"(
+struct Copy {
+ int x;
+};
+void foo() {
+ Copy x;
+ Copy y = x;
+}
+)";
+ // The entire struct 'Copy':
+ findSelectedASTNodes(
+ Source, {2, 1}, FileRange{{2, 1}, {4, 3}},
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Record = checkNode<CXXRecordDecl>(
+ Node->Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1, /*Name=*/"Copy");
+ checkNode<FieldDecl>(Record.Children[0],
+ SourceSelectionKind::InsideSelection);
+ });
+}
+
+TEST(ASTSelectionFinder, CorrectEndForObjectiveCImplementation) {
+ StringRef Source = R"(
+@interface I
+@end
+@implementation I
+@ end
+)";
+ // Just after '@ end'
+ findSelectedASTNodes(Source, {5, 6}, None,
+ [](Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ checkNode<ObjCImplementationDecl>(
+ Node->Children[0],
+ SourceSelectionKind::ContainsSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+}
+
+const SelectedASTNode &checkFnBody(const Optional<SelectedASTNode> &Node,
+ StringRef Name) {
+ EXPECT_TRUE(Node);
+ EXPECT_EQ(Node->Children.size(), 1u);
+ const auto &Fn = checkNode<FunctionDecl>(
+ Node->Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1, Name);
+ return checkNode<CompoundStmt>(Fn.Children[0],
+ SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+}
+
+TEST(ASTSelectionFinder, SelectObjectiveCPseudoObjectExprs) {
+ StringRef Source = R"(
+@interface I
+@property(readwrite) int prop;
+@end
+void selectProp(I *i) {
+(void)i.prop;
+i.prop = 21;
+}
+
+
+@interface NSMutableArray
+- (id)objectAtIndexedSubscript:(unsigned int)index;
+- (void)setObject:(id)object atIndexedSubscript:(unsigned int)index;
+@end
+
+void selectSubscript(NSMutableArray *array, I *i) {
+ (void)array[10];
+ array[i.prop] = i;
+}
+)";
+ // Just 'i.prop'.
+ findSelectedASTNodes(
+ Source, {6, 7}, FileRange{{6, 7}, {6, 13}},
+ [](Optional<SelectedASTNode> Node) {
+ const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
+ const auto &CCast = checkNode<CStyleCastExpr>(
+ CS.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ const auto &POE = checkNode<PseudoObjectExpr>(
+ CCast.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ const auto &PRE = checkNode<ObjCPropertyRefExpr>(
+ POE.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ const auto &Cast = checkNode<ImplicitCastExpr>(
+ PRE.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<DeclRefExpr>(Cast.Children[0],
+ SourceSelectionKind::InsideSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // Just 'i.prop = 21'
+ findSelectedASTNodes(
+ Source, {7, 1}, FileRange{{7, 1}, {7, 12}},
+ [](Optional<SelectedASTNode> Node) {
+ const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
+ const auto &POE = checkNode<PseudoObjectExpr>(
+ CS.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ const auto &BinOp = checkNode<BinaryOperator>(
+ POE.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/2);
+ const auto &PRE = checkNode<ObjCPropertyRefExpr>(
+ BinOp.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ const auto &Cast = checkNode<ImplicitCastExpr>(
+ PRE.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<DeclRefExpr>(Cast.Children[0],
+ SourceSelectionKind::InsideSelection);
+ checkNode<IntegerLiteral>(BinOp.Children[1],
+ SourceSelectionKind::InsideSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // Just 'array[10]'
+ findSelectedASTNodes(
+ Source, {17, 9}, FileRange{{17, 9}, {17, 18}},
+ [](Optional<SelectedASTNode> Node) {
+ const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
+ const auto &CCast = checkNode<CStyleCastExpr>(
+ CS.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ const auto &POE = checkNode<PseudoObjectExpr>(
+ CCast.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
+ POE.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/2);
+ const auto &Cast = checkNode<ImplicitCastExpr>(
+ SRE.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<DeclRefExpr>(Cast.Children[0],
+ SourceSelectionKind::InsideSelection);
+ checkNode<IntegerLiteral>(SRE.Children[1],
+ SourceSelectionKind::InsideSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // Just 'array[i.prop] = array'
+ findSelectedASTNodes(
+ Source, {18, 3}, FileRange{{18, 3}, {18, 20}},
+ [](Optional<SelectedASTNode> Node) {
+ const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
+ const auto &POE = checkNode<PseudoObjectExpr>(
+ CS.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/1);
+ const auto &BinOp = checkNode<BinaryOperator>(
+ POE.Children[0], SourceSelectionKind::ContainsSelection,
+ /*NumChildren=*/2);
+ const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
+ BinOp.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/2);
+ const auto &Cast = checkNode<ImplicitCastExpr>(
+ SRE.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<DeclRefExpr>(Cast.Children[0],
+ SourceSelectionKind::InsideSelection);
+ const auto &POE2 = checkNode<PseudoObjectExpr>(
+ SRE.Children[1], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ const auto &PRE = checkNode<ObjCPropertyRefExpr>(
+ POE2.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ const auto &Cast2 = checkNode<ImplicitCastExpr>(
+ PRE.Children[0], SourceSelectionKind::InsideSelection,
+ /*NumChildren=*/1);
+ checkNode<DeclRefExpr>(Cast2.Children[0],
+ SourceSelectionKind::InsideSelection);
+ checkNode<DeclRefExpr>(BinOp.Children[1],
+ SourceSelectionKind::InsideSelection);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+}
+
+TEST(ASTSelectionFinder, SimpleCodeRangeASTSelection) {
+ StringRef Source = R"(void f(int x, int y) {
+ int z = x;
+ f(2, 3);
+ if (x == 0) {
+ return;
+ }
+ x = 1;
+ return;
+}
+void f2() {
+ int m = 0;
+}
+)";
+ // No selection range.
+ findSelectedASTNodesWithRange(
+ Source, {2, 2}, None,
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_FALSE(SelectedCode);
+ });
+ findSelectedASTNodesWithRange(
+ Source, {2, 2}, FileRange{{2, 2}, {2, 2}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_FALSE(SelectedCode);
+ });
+ // Range that spans multiple functions is an invalid code range.
+ findSelectedASTNodesWithRange(
+ Source, {2, 2}, FileRange{{7, 2}, {12, 1}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_FALSE(SelectedCode);
+ });
+ // Just 'z = x;':
+ findSelectedASTNodesWithRange(
+ Source, {2, 2}, FileRange{{2, 2}, {2, 13}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 1u);
+ EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 3u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // Function 'f' definition.
+ EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
+ // Function body of function 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
+ });
+ // From 'f(2,3)' until just before 'x = 1;':
+ findSelectedASTNodesWithRange(
+ Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 2u);
+ EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
+ EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 3u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // Function 'f' definition.
+ EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
+ // Function body of function 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
+ });
+ // From 'f(2,3)' until just before ';' in 'x = 1;':
+ findSelectedASTNodesWithRange(
+ Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 3u);
+ EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
+ EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
+ EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[2]));
+ });
+ // From the middle of 'int z = 3' until the middle of 'x = 1;':
+ findSelectedASTNodesWithRange(
+ Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 4u);
+ EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
+ EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[1]));
+ EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[2]));
+ EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[3]));
+ });
+}
+
+TEST(ASTSelectionFinder, OutOfBodyCodeRange) {
+ StringRef Source = R"(
+int codeRange = 2 + 3;
+)";
+ // '2+3' expression.
+ findSelectedASTNodesWithRange(
+ Source, {2, 17}, FileRange{{2, 17}, {2, 22}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 1u);
+ EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[0]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 2u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // Variable 'codeRange'.
+ EXPECT_TRUE(isa<VarDecl>(Parents[1].get().Node.get<Decl>()));
+ });
+}
+
+TEST(ASTSelectionFinder, SelectVarDeclStmt) {
+ StringRef Source = R"(
+void f() {
+ {
+ int a;
+ }
+}
+)";
+ // 'int a'
+ findSelectedASTNodesWithRange(
+ Source, {4, 8}, FileRange{{4, 8}, {4, 14}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 1u);
+ EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 4u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // Function 'f' definition.
+ EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
+ // Function body of function 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
+ // Compound statement in body of 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
+ });
+}
+
+TEST(ASTSelectionFinder, SelectEntireDeclStmtRange) {
+ StringRef Source = R"(
+void f(int x, int y) {
+ int a = x * y;
+}
+)";
+ // 'int a = x * y'
+ findSelectedASTNodesWithRange(
+ Source, {3, 4}, FileRange{{3, 4}, {3, 17}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 1u);
+ EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 3u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // Function 'f' definition.
+ EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
+ // Function body of function 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
+ });
+}
+
+TEST(ASTSelectionFinder, SelectEntireDeclStmtRangeWithMultipleDecls) {
+ StringRef Source = R"(
+void f(int x, int y) {
+ int a = x * y, b = x - y;
+}
+)";
+ // 'b = x - y'
+ findSelectedASTNodesWithRange(
+ Source, {3, 19}, FileRange{{3, 19}, {3, 28}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 1u);
+ EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 3u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // Function 'f' definition.
+ EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
+ // Function body of function 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
+ });
+}
+
+TEST(ASTSelectionFinder, SimpleCodeRangeASTSelectionInObjCMethod) {
+ StringRef Source = R"(@interface I @end
+@implementation I
+- (void) f:(int)x with:(int) y {
+ int z = x;
+ [self f: 2 with: 3];
+ if (x == 0) {
+ return;
+ }
+ x = 1;
+ return;
+}
+- (void)f2 {
+ int m = 0;
+}
+@end
+)";
+ // Range that spans multiple methods is an invalid code range.
+ findSelectedASTNodesWithRange(
+ Source, {9, 2}, FileRange{{9, 2}, {13, 1}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_FALSE(SelectedCode);
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // Just 'z = x;':
+ findSelectedASTNodesWithRange(
+ Source, {4, 2}, FileRange{{4, 2}, {4, 13}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 1u);
+ EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 4u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // 'I' @implementation.
+ EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
+ // Function 'f' definition.
+ EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
+ // Function body of function 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+ // From '[self f: 2 with: 3]' until just before 'x = 1;':
+ findSelectedASTNodesWithRange(
+ Source, {5, 2}, FileRange{{5, 2}, {9, 1}},
+ [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
+ EXPECT_TRUE(Node);
+ Optional<CodeRangeASTSelection> SelectedCode =
+ CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+ EXPECT_TRUE(SelectedCode);
+ EXPECT_EQ(SelectedCode->size(), 2u);
+ EXPECT_TRUE(isa<ObjCMessageExpr>((*SelectedCode)[0]));
+ EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
+ ArrayRef<SelectedASTNode::ReferenceType> Parents =
+ SelectedCode->getParents();
+ EXPECT_EQ(Parents.size(), 4u);
+ EXPECT_TRUE(
+ isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
+ // 'I' @implementation.
+ EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
+ // Function 'f' definition.
+ EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
+ // Function body of function 'F'.
+ EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
+ },
+ SelectionFinderVisitor::Lang_OBJC);
+}
+
+} // end anonymous namespace
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index b5af99bdfd..f9ddf7ffc1 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -11,9 +11,14 @@ if (MSVC)
endif()
add_clang_unittest(ToolingTests
+ ASTSelectionTest.cpp
+ CastExprTest.cpp
CommentHandlerTest.cpp
CompilationDatabaseTest.cpp
+ DiagnosticsYamlTest.cpp
+ ExecutionTest.cpp
FixItTest.cpp
+ LexicallyOrderedRecursiveASTVisitorTest.cpp
LookupTest.cpp
QualTypeNamesTest.cpp
RecursiveASTVisitorTest.cpp
@@ -21,6 +26,7 @@ add_clang_unittest(ToolingTests
RecursiveASTVisitorTestDeclVisitor.cpp
RecursiveASTVisitorTestExprVisitor.cpp
RecursiveASTVisitorTestTypeLocVisitor.cpp
+ RefactoringActionRulesTest.cpp
RefactoringCallbacksTest.cpp
RefactoringTest.cpp
ReplacementsYamlTest.cpp
diff --git a/unittests/Tooling/CastExprTest.cpp b/unittests/Tooling/CastExprTest.cpp
new file mode 100644
index 0000000000..5310c21254
--- /dev/null
+++ b/unittests/Tooling/CastExprTest.cpp
@@ -0,0 +1,38 @@
+//===- unittest/Tooling/CastExprTest.cpp ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+
+using namespace clang;
+
+namespace {
+
+struct CastExprVisitor : TestVisitor<CastExprVisitor> {
+ std::function<void(ExplicitCastExpr *)> OnExplicitCast;
+
+ bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) {
+ if (OnExplicitCast)
+ OnExplicitCast(Expr);
+ return true;
+ }
+};
+
+TEST(CastExprTest, GetSubExprAsWrittenThroughMaterializedTemporary) {
+ CastExprVisitor Visitor;
+ Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) {
+ auto Sub = Expr->getSubExprAsWritten();
+ EXPECT_TRUE(isa<DeclRefExpr>(Sub))
+ << "Expected DeclRefExpr, but saw " << Sub->getStmtClassName();
+ };
+ Visitor.runOver("struct S1 {};\n"
+ "struct S2 { operator S1(); };\n"
+ "S1 f(S2 s) { return static_cast<S1>(s); }\n");
+}
+
+}
diff --git a/unittests/Tooling/CommentHandlerTest.cpp b/unittests/Tooling/CommentHandlerTest.cpp
index b42b28b9c9..9c3abdc4b1 100644
--- a/unittests/Tooling/CommentHandlerTest.cpp
+++ b/unittests/Tooling/CommentHandlerTest.cpp
@@ -70,8 +70,7 @@ private:
CommentHandlerAction(CommentHandlerVisitor *Visitor)
: TestAction(Visitor) { }
- bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef FileName) override {
+ bool BeginSourceFileAction(CompilerInstance &CI) override {
CommentHandlerVisitor *V =
static_cast<CommentHandlerVisitor*>(this->Visitor);
V->PP = &CI.getPreprocessor();
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 1a6fffec93..fd8afe6b79 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -504,18 +504,22 @@ TEST(FixedCompilationDatabase, GetAllCompileCommands) {
TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
int Argc = 0;
- std::unique_ptr<FixedCompilationDatabase> Database(
- FixedCompilationDatabase::loadFromCommandLine(Argc, nullptr));
+ std::string ErrorMsg;
+ std::unique_ptr<FixedCompilationDatabase> Database =
+ FixedCompilationDatabase::loadFromCommandLine(Argc, nullptr, ErrorMsg);
EXPECT_FALSE(Database);
+ EXPECT_TRUE(ErrorMsg.empty());
EXPECT_EQ(0, Argc);
}
TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
int Argc = 2;
const char *Argv[] = { "1", "2" };
+ std::string ErrorMsg;
std::unique_ptr<FixedCompilationDatabase> Database(
- FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg));
EXPECT_FALSE(Database);
+ EXPECT_TRUE(ErrorMsg.empty());
EXPECT_EQ(2, Argc);
}
@@ -524,9 +528,11 @@ TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
const char *Argv[] = {
"1", "2", "--\0no-constant-folding", "-DDEF3", "-DDEF4"
};
+ std::string ErrorMsg;
std::unique_ptr<FixedCompilationDatabase> Database(
- FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg));
ASSERT_TRUE((bool)Database);
+ ASSERT_TRUE(ErrorMsg.empty());
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
@@ -543,9 +549,11 @@ TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
int Argc = 3;
const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
- std::unique_ptr<FixedCompilationDatabase> Database(
- FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
+ std::string ErrorMsg;
+ std::unique_ptr<FixedCompilationDatabase> Database =
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg);
ASSERT_TRUE((bool)Database);
+ ASSERT_TRUE(ErrorMsg.empty());
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
@@ -560,9 +568,11 @@ TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
TEST(ParseFixedCompilationDatabase, HandlesPositionalArgs) {
const char *Argv[] = {"1", "2", "--", "-c", "somefile.cpp", "-DDEF3"};
int Argc = sizeof(Argv) / sizeof(char*);
- std::unique_ptr<FixedCompilationDatabase> Database(
- FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
+ std::string ErrorMsg;
+ std::unique_ptr<FixedCompilationDatabase> Database =
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg);
ASSERT_TRUE((bool)Database);
+ ASSERT_TRUE(ErrorMsg.empty());
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
@@ -576,12 +586,35 @@ TEST(ParseFixedCompilationDatabase, HandlesPositionalArgs) {
EXPECT_EQ(2, Argc);
}
+TEST(ParseFixedCompilationDatabase, HandlesPositionalArgsSyntaxOnly) {
+ // Adjust the given command line arguments to ensure that any positional
+ // arguments in them are stripped.
+ const char *Argv[] = {"--", "somefile.cpp", "-fsyntax-only", "-DDEF3"};
+ int Argc = llvm::array_lengthof(Argv);
+ std::string ErrorMessage;
+ std::unique_ptr<CompilationDatabase> Database =
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMessage);
+ ASSERT_TRUE((bool)Database);
+ ASSERT_TRUE(ErrorMessage.empty());
+ std::vector<CompileCommand> Result = Database->getCompileCommands("source");
+ ASSERT_EQ(1ul, Result.size());
+ ASSERT_EQ(".", Result[0].Directory);
+ std::vector<std::string> Expected;
+ Expected.push_back("clang-tool");
+ Expected.push_back("-fsyntax-only");
+ Expected.push_back("-DDEF3");
+ Expected.push_back("source");
+ ASSERT_EQ(Expected, Result[0].CommandLine);
+}
+
TEST(ParseFixedCompilationDatabase, HandlesArgv0) {
const char *Argv[] = {"1", "2", "--", "mytool", "somefile.cpp"};
int Argc = sizeof(Argv) / sizeof(char*);
- std::unique_ptr<FixedCompilationDatabase> Database(
- FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
+ std::string ErrorMsg;
+ std::unique_ptr<FixedCompilationDatabase> Database =
+ FixedCompilationDatabase::loadFromCommandLine(Argc, Argv, ErrorMsg);
ASSERT_TRUE((bool)Database);
+ ASSERT_TRUE(ErrorMsg.empty());
std::vector<CompileCommand> Result =
Database->getCompileCommands("source");
ASSERT_EQ(1ul, Result.size());
diff --git a/unittests/Tooling/DiagnosticsYamlTest.cpp b/unittests/Tooling/DiagnosticsYamlTest.cpp
new file mode 100644
index 0000000000..83e09eaeef
--- /dev/null
+++ b/unittests/Tooling/DiagnosticsYamlTest.cpp
@@ -0,0 +1,167 @@
+//===- unittests/Tooling/DiagnosticsYamlTest.cpp - Serialization tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for serialization of Diagnostics.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/DiagnosticsYaml.h"
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang::tooling;
+using clang::tooling::Diagnostic;
+
+static Diagnostic makeDiagnostic(StringRef DiagnosticName,
+ const std::string &Message, int FileOffset,
+ const std::string &FilePath,
+ const StringMap<Replacements> &Fix) {
+ DiagnosticMessage DiagMessage;
+ DiagMessage.Message = Message;
+ DiagMessage.FileOffset = FileOffset;
+ DiagMessage.FilePath = FilePath;
+ return Diagnostic(DiagnosticName, DiagMessage, Fix, {}, Diagnostic::Warning,
+ "path/to/build/directory");
+}
+
+TEST(DiagnosticsYamlTest, serializesDiagnostics) {
+ TranslationUnitDiagnostics TUD;
+ TUD.MainSourceFile = "path/to/source.cpp";
+
+ StringMap<Replacements> Fix1 = {
+ {"path/to/source.cpp",
+ Replacements({"path/to/source.cpp", 100, 12, "replacement #1"})}};
+ TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#1", "message #1", 55,
+ "path/to/source.cpp", Fix1));
+
+ StringMap<Replacements> Fix2 = {
+ {"path/to/header.h",
+ Replacements({"path/to/header.h", 62, 2, "replacement #2"})}};
+ TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#2", "message #2", 60,
+ "path/to/header.h", Fix2));
+
+ TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#3", "message #3", 72,
+ "path/to/source2.cpp", {}));
+
+ std::string YamlContent;
+ raw_string_ostream YamlContentStream(YamlContent);
+
+ yaml::Output YAML(YamlContentStream);
+ YAML << TUD;
+
+ EXPECT_EQ("---\n"
+ "MainSourceFile: path/to/source.cpp\n"
+ "Diagnostics: \n"
+ " - DiagnosticName: 'diagnostic#1\'\n"
+ " Message: 'message #1'\n"
+ " FileOffset: 55\n"
+ " FilePath: path/to/source.cpp\n"
+ " Replacements: \n"
+ " - FilePath: path/to/source.cpp\n"
+ " Offset: 100\n"
+ " Length: 12\n"
+ " ReplacementText: 'replacement #1'\n"
+ " - DiagnosticName: 'diagnostic#2'\n"
+ " Message: 'message #2'\n"
+ " FileOffset: 60\n"
+ " FilePath: path/to/header.h\n"
+ " Replacements: \n"
+ " - FilePath: path/to/header.h\n"
+ " Offset: 62\n"
+ " Length: 2\n"
+ " ReplacementText: 'replacement #2'\n"
+ " - DiagnosticName: 'diagnostic#3'\n"
+ " Message: 'message #3'\n"
+ " FileOffset: 72\n"
+ " FilePath: path/to/source2.cpp\n"
+ " Replacements: \n"
+ "...\n",
+ YamlContentStream.str());
+}
+
+TEST(DiagnosticsYamlTest, deserializesDiagnostics) {
+ std::string YamlContent = "---\n"
+ "MainSourceFile: path/to/source.cpp\n"
+ "Diagnostics: \n"
+ " - DiagnosticName: 'diagnostic#1'\n"
+ " Message: 'message #1'\n"
+ " FileOffset: 55\n"
+ " FilePath: path/to/source.cpp\n"
+ " Replacements: \n"
+ " - FilePath: path/to/source.cpp\n"
+ " Offset: 100\n"
+ " Length: 12\n"
+ " ReplacementText: 'replacement #1'\n"
+ " - DiagnosticName: 'diagnostic#2'\n"
+ " Message: 'message #2'\n"
+ " FileOffset: 60\n"
+ " FilePath: path/to/header.h\n"
+ " Replacements: \n"
+ " - FilePath: path/to/header.h\n"
+ " Offset: 62\n"
+ " Length: 2\n"
+ " ReplacementText: 'replacement #2'\n"
+ " - DiagnosticName: 'diagnostic#3'\n"
+ " Message: 'message #3'\n"
+ " FileOffset: 98\n"
+ " FilePath: path/to/source.cpp\n"
+ " Replacements: \n"
+ "...\n";
+ TranslationUnitDiagnostics TUDActual;
+ yaml::Input YAML(YamlContent);
+ YAML >> TUDActual;
+
+ ASSERT_FALSE(YAML.error());
+ ASSERT_EQ(3u, TUDActual.Diagnostics.size());
+ EXPECT_EQ("path/to/source.cpp", TUDActual.MainSourceFile);
+
+ auto getFixes = [](const StringMap<Replacements> &Fix) {
+ std::vector<Replacement> Fixes;
+ for (auto &Replacements : Fix) {
+ for (auto &Replacement : Replacements.second) {
+ Fixes.push_back(Replacement);
+ }
+ }
+ return Fixes;
+ };
+
+ Diagnostic D1 = TUDActual.Diagnostics[0];
+ EXPECT_EQ("diagnostic#1", D1.DiagnosticName);
+ EXPECT_EQ("message #1", D1.Message.Message);
+ EXPECT_EQ(55u, D1.Message.FileOffset);
+ EXPECT_EQ("path/to/source.cpp", D1.Message.FilePath);
+ std::vector<Replacement> Fixes1 = getFixes(D1.Fix);
+ ASSERT_EQ(1u, Fixes1.size());
+ EXPECT_EQ("path/to/source.cpp", Fixes1[0].getFilePath());
+ EXPECT_EQ(100u, Fixes1[0].getOffset());
+ EXPECT_EQ(12u, Fixes1[0].getLength());
+ EXPECT_EQ("replacement #1", Fixes1[0].getReplacementText());
+
+ Diagnostic D2 = TUDActual.Diagnostics[1];
+ EXPECT_EQ("diagnostic#2", D2.DiagnosticName);
+ EXPECT_EQ("message #2", D2.Message.Message);
+ EXPECT_EQ(60u, D2.Message.FileOffset);
+ EXPECT_EQ("path/to/header.h", D2.Message.FilePath);
+ std::vector<Replacement> Fixes2 = getFixes(D2.Fix);
+ ASSERT_EQ(1u, Fixes2.size());
+ EXPECT_EQ("path/to/header.h", Fixes2[0].getFilePath());
+ EXPECT_EQ(62u, Fixes2[0].getOffset());
+ EXPECT_EQ(2u, Fixes2[0].getLength());
+ EXPECT_EQ("replacement #2", Fixes2[0].getReplacementText());
+
+ Diagnostic D3 = TUDActual.Diagnostics[2];
+ EXPECT_EQ("diagnostic#3", D3.DiagnosticName);
+ EXPECT_EQ("message #3", D3.Message.Message);
+ EXPECT_EQ(98u, D3.Message.FileOffset);
+ EXPECT_EQ("path/to/source.cpp", D3.Message.FilePath);
+ std::vector<Replacement> Fixes3 = getFixes(D3.Fix);
+ EXPECT_TRUE(Fixes3.empty());
+}
diff --git a/unittests/Tooling/ExecutionTest.cpp b/unittests/Tooling/ExecutionTest.cpp
new file mode 100644
index 0000000000..44e37b4009
--- /dev/null
+++ b/unittests/Tooling/ExecutionTest.cpp
@@ -0,0 +1,228 @@
+//===- unittest/Tooling/ExecutionTest.cpp - Tool execution 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/ASTConsumer.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/ToolExecutorPluginRegistry.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+#include <algorithm>
+#include <string>
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// This traverses the AST and outputs function name as key and "1" as value for
+// each function declaration.
+class ASTConsumerWithResult
+ : public ASTConsumer,
+ public RecursiveASTVisitor<ASTConsumerWithResult> {
+public:
+ using ASTVisitor = RecursiveASTVisitor<ASTConsumerWithResult>;
+
+ explicit ASTConsumerWithResult(ExecutionContext *Context) : Context(Context) {
+ assert(Context != nullptr);
+ }
+
+ void HandleTranslationUnit(clang::ASTContext &Context) override {
+ TraverseDecl(Context.getTranslationUnitDecl());
+ }
+
+ bool TraverseFunctionDecl(clang::FunctionDecl *Decl) {
+ Context->reportResult(Decl->getNameAsString(), "1");
+ return ASTVisitor::TraverseFunctionDecl(Decl);
+ }
+
+private:
+ ExecutionContext *const Context;
+};
+
+class ReportResultAction : public ASTFrontendAction {
+public:
+ explicit ReportResultAction(ExecutionContext *Context) : Context(Context) {
+ assert(Context != nullptr);
+ }
+
+protected:
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &compiler,
+ StringRef /* dummy */) override {
+ std::unique_ptr<clang::ASTConsumer> ast_consumer{
+ new ASTConsumerWithResult(Context)};
+ return ast_consumer;
+ }
+
+private:
+ ExecutionContext *const Context;
+};
+
+class ReportResultActionFactory : public FrontendActionFactory {
+public:
+ ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {}
+ FrontendAction *create() override { return new ReportResultAction(Context); }
+
+private:
+ ExecutionContext *const Context;
+};
+
+} // namespace
+
+class TestToolExecutor : public ToolExecutor {
+public:
+ static const char *ExecutorName;
+
+ TestToolExecutor(CommonOptionsParser Options)
+ : OptionsParser(std::move(Options)) {}
+
+ StringRef getExecutorName() const override { return ExecutorName; }
+
+ llvm::Error
+ execute(llvm::ArrayRef<std::pair<std::unique_ptr<FrontendActionFactory>,
+ ArgumentsAdjuster>>) override {
+ return llvm::Error::success();
+ }
+
+ ExecutionContext *getExecutionContext() override { return nullptr; };
+
+ ToolResults *getToolResults() override { return nullptr; }
+
+ llvm::ArrayRef<std::string> getSourcePaths() const {
+ return OptionsParser.getSourcePathList();
+ }
+
+ void mapVirtualFile(StringRef FilePath, StringRef Content) override {
+ VFS[FilePath] = Content;
+ }
+
+private:
+ CommonOptionsParser OptionsParser;
+ std::string SourcePaths;
+ std::map<std::string, std::string> VFS;
+};
+
+const char *TestToolExecutor::ExecutorName = "test-executor";
+
+class TestToolExecutorPlugin : public ToolExecutorPlugin {
+public:
+ llvm::Expected<std::unique_ptr<ToolExecutor>>
+ create(CommonOptionsParser &OptionsParser) override {
+ return llvm::make_unique<TestToolExecutor>(std::move(OptionsParser));
+ }
+};
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the plugin.
+extern volatile int ToolExecutorPluginAnchorSource;
+
+static int LLVM_ATTRIBUTE_UNUSED TestToolExecutorPluginAnchorDest =
+ ToolExecutorPluginAnchorSource;
+
+static ToolExecutorPluginRegistry::Add<TestToolExecutorPlugin>
+ X("test-executor", "Plugin for TestToolExecutor.");
+
+llvm::cl::OptionCategory TestCategory("execution-test options");
+
+TEST(CreateToolExecutorTest, FailedCreateExecutorUndefinedFlag) {
+ std::vector<const char *> argv = {"prog", "--fake_flag_no_no_no", "f"};
+ int argc = argv.size();
+ auto Executor =
+ createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
+ ASSERT_FALSE((bool)Executor);
+ llvm::consumeError(Executor.takeError());
+}
+
+TEST(CreateToolExecutorTest, RegisterFlagsBeforeReset) {
+ llvm::cl::opt<std::string> BeforeReset(
+ "before_reset", llvm::cl::desc("Defined before reset."),
+ llvm::cl::init(""));
+
+ llvm::cl::ResetAllOptionOccurrences();
+
+ std::vector<const char *> argv = {"prog", "--before_reset=set", "f"};
+ int argc = argv.size();
+ auto Executor =
+ createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
+ ASSERT_TRUE((bool)Executor);
+ EXPECT_EQ(BeforeReset, "set");
+ BeforeReset.removeArgument();
+}
+
+TEST(CreateToolExecutorTest, CreateStandaloneToolExecutor) {
+ std::vector<const char *> argv = {"prog", "standalone.cpp"};
+ int argc = argv.size();
+ auto Executor =
+ createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
+ ASSERT_TRUE((bool)Executor);
+ EXPECT_EQ(Executor->get()->getExecutorName(),
+ StandaloneToolExecutor::ExecutorName);
+}
+
+TEST(CreateToolExecutorTest, CreateTestToolExecutor) {
+ std::vector<const char *> argv = {"prog", "test.cpp",
+ "--executor=test-executor"};
+ int argc = argv.size();
+ auto Executor =
+ createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
+ ASSERT_TRUE((bool)Executor);
+ EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName);
+}
+
+TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) {
+ FixedCompilationDatabase Compilations(".", std::vector<std::string>());
+ StandaloneToolExecutor Executor(Compilations,
+ std::vector<std::string>(1, "a.cc"));
+ Executor.mapVirtualFile("a.cc", "int x = 0;");
+
+ auto Err = Executor.execute(newFrontendActionFactory<SyntaxOnlyAction>(),
+ getClangSyntaxOnlyAdjuster());
+ ASSERT_TRUE(!Err);
+}
+
+TEST(StandaloneToolTest, SimpleAction) {
+ FixedCompilationDatabase Compilations(".", std::vector<std::string>());
+ StandaloneToolExecutor Executor(Compilations,
+ std::vector<std::string>(1, "a.cc"));
+ Executor.mapVirtualFile("a.cc", "int x = 0;");
+
+ auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
+ new ReportResultActionFactory(Executor.getExecutionContext())));
+ ASSERT_TRUE(!Err);
+ auto KVs = Executor.getToolResults()->AllKVResults();
+ ASSERT_EQ(KVs.size(), 0u);
+}
+
+TEST(StandaloneToolTest, SimpleActionWithResult) {
+ FixedCompilationDatabase Compilations(".", std::vector<std::string>());
+ StandaloneToolExecutor Executor(Compilations,
+ std::vector<std::string>(1, "a.cc"));
+ Executor.mapVirtualFile("a.cc", "int x = 0; void f() {}");
+
+ auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
+ new ReportResultActionFactory(Executor.getExecutionContext())));
+ ASSERT_TRUE(!Err);
+ auto KVs = Executor.getToolResults()->AllKVResults();
+ ASSERT_EQ(KVs.size(), 1u);
+ EXPECT_EQ("f", KVs[0].first);
+ EXPECT_EQ("1", KVs[0].second);
+
+ Executor.getToolResults()->forEachResult(
+ [](StringRef, StringRef Value) { EXPECT_EQ("1", Value); });
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp b/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
new file mode 100644
index 0000000000..50727a55fc
--- /dev/null
+++ b/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
@@ -0,0 +1,227 @@
+//===- unittest/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
+#include <stack>
+
+using namespace clang;
+
+namespace {
+
+class DummyMatchVisitor;
+
+class LexicallyOrderedDeclVisitor
+ : public LexicallyOrderedRecursiveASTVisitor<LexicallyOrderedDeclVisitor> {
+public:
+ LexicallyOrderedDeclVisitor(DummyMatchVisitor &Matcher,
+ const SourceManager &SM, bool EmitDeclIndices,
+ bool EmitStmtIndices)
+ : LexicallyOrderedRecursiveASTVisitor(SM), Matcher(Matcher),
+ EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
+
+ bool TraverseDecl(Decl *D) {
+ TraversalStack.push_back(D);
+ LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
+ TraversalStack.pop_back();
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *S);
+
+ bool VisitNamedDecl(const NamedDecl *D);
+ bool VisitDeclRefExpr(const DeclRefExpr *D);
+
+private:
+ DummyMatchVisitor &Matcher;
+ bool EmitDeclIndices, EmitStmtIndices;
+ unsigned Index = 0;
+ llvm::SmallVector<Decl *, 8> TraversalStack;
+};
+
+class DummyMatchVisitor : public ExpectedLocationVisitor<DummyMatchVisitor> {
+ bool EmitDeclIndices, EmitStmtIndices;
+
+public:
+ DummyMatchVisitor(bool EmitDeclIndices = false, bool EmitStmtIndices = false)
+ : EmitDeclIndices(EmitDeclIndices), EmitStmtIndices(EmitStmtIndices) {}
+ bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+ const ASTContext &Context = TU->getASTContext();
+ const SourceManager &SM = Context.getSourceManager();
+ LexicallyOrderedDeclVisitor SubVisitor(*this, SM, EmitDeclIndices,
+ EmitStmtIndices);
+ SubVisitor.TraverseDecl(TU);
+ return false;
+ }
+
+ template <class T> void match(StringRef Path, const T *D) {
+ Match(Path, D->getLocStart());
+ }
+};
+
+bool LexicallyOrderedDeclVisitor::TraverseStmt(Stmt *S) {
+ Matcher.match("overridden TraverseStmt", S);
+ return LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
+}
+
+bool LexicallyOrderedDeclVisitor::VisitNamedDecl(const NamedDecl *D) {
+ std::string Path;
+ llvm::raw_string_ostream OS(Path);
+ assert(TraversalStack.back() == D);
+ for (const Decl *D : TraversalStack) {
+ if (isa<TranslationUnitDecl>(D)) {
+ OS << "/";
+ continue;
+ }
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ OS << ND->getNameAsString();
+ else
+ OS << "???";
+ if (isa<DeclContext>(D) || isa<TemplateDecl>(D))
+ OS << "/";
+ }
+ if (EmitDeclIndices)
+ OS << "@" << Index++;
+ Matcher.match(OS.str(), D);
+ return true;
+}
+
+bool LexicallyOrderedDeclVisitor::VisitDeclRefExpr(const DeclRefExpr *D) {
+ std::string Name = D->getFoundDecl()->getNameAsString();
+ llvm::raw_string_ostream OS(Name);
+ if (EmitStmtIndices)
+ OS << "@" << Index++;
+ Matcher.match(OS.str(), D);
+ return true;
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitDeclsInImplementation) {
+ StringRef Source = R"(
+@interface I
+@end
+@implementation I
+
+int nestedFunction() { }
+
+- (void) method{ }
+
+int anotherNestedFunction(int x) {
+ return x;
+}
+
+int innerVariable = 0;
+
+@end
+
+int outerVariable = 0;
+
+@implementation I(Cat)
+
+void catF() { }
+
+@end
+
+void outerFunction() { }
+)";
+ DummyMatchVisitor Visitor;
+ Visitor.DisallowMatch("/nestedFunction/", 6, 1);
+ Visitor.ExpectMatch("/I/nestedFunction/", 6, 1);
+ Visitor.ExpectMatch("/I/method/", 8, 1);
+ Visitor.DisallowMatch("/anotherNestedFunction/", 10, 1);
+ Visitor.ExpectMatch("/I/anotherNestedFunction/", 10, 1);
+ Visitor.DisallowMatch("/innerVariable", 14, 1);
+ Visitor.ExpectMatch("/I/innerVariable", 14, 1);
+ Visitor.ExpectMatch("/outerVariable", 18, 1);
+ Visitor.DisallowMatch("/catF/", 22, 1);
+ Visitor.ExpectMatch("/Cat/catF/", 22, 1);
+ Visitor.ExpectMatch("/outerFunction/", 26, 1);
+ EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitMacroDeclsInImplementation) {
+ StringRef Source = R"(
+@interface I
+@end
+
+void outerFunction() { }
+
+#define MACRO_F(x) void nestedFunction##x() { }
+
+@implementation I
+
+MACRO_F(1)
+
+@end
+
+MACRO_F(2)
+)";
+ DummyMatchVisitor Visitor;
+ Visitor.ExpectMatch("/outerFunction/", 5, 1);
+ Visitor.ExpectMatch("/I/nestedFunction1/", 7, 20);
+ Visitor.ExpectMatch("/nestedFunction2/", 7, 20);
+ EXPECT_TRUE(Visitor.runOver(Source, DummyMatchVisitor::Lang_OBJC));
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitTemplateDecl) {
+ StringRef Source = R"(
+template <class T> T f();
+template <class U, class = void> class Class {};
+)";
+ DummyMatchVisitor Visitor(/*EmitIndices=*/true);
+ Visitor.ExpectMatch("/f/T@1", 2, 11);
+ Visitor.ExpectMatch("/f/f/@2", 2, 20);
+ Visitor.ExpectMatch("/Class/U@4", 3, 11);
+ Visitor.ExpectMatch("/Class/@5", 3, 20);
+ Visitor.ExpectMatch("/Class/Class/@6", 3, 34);
+ EXPECT_TRUE(Visitor.runOver(Source));
+}
+
+TEST(LexicallyOrderedRecursiveASTVisitor, VisitCXXOperatorCallExpr) {
+ StringRef Source = R"(
+struct S {
+ S &operator+(S&);
+ S *operator->();
+ S &operator++();
+ S operator++(int);
+ void operator()(int, int);
+ void operator[](int);
+ void f();
+};
+S a, b, c;
+
+void test() {
+ a = b + c;
+ a->f();
+ a(1, 2);
+ b[0];
+ ++a;
+ b++;
+}
+)";
+ DummyMatchVisitor Visitor(/*EmitDeclIndices=*/false,
+ /*EmitStmtIndices=*/true);
+ // There are two overloaded operators that start at this point
+ // This makes sure they are both traversed using the overridden
+ // TraverseStmt, as the traversal is implemented by us for
+ // CXXOperatorCallExpr.
+ Visitor.ExpectMatch("overridden TraverseStmt", 14, 3, 2);
+ Visitor.ExpectMatch("a@0", 14, 3);
+ Visitor.ExpectMatch("operator=@1", 14, 5);
+ Visitor.ExpectMatch("b@2", 14, 7);
+ Visitor.ExpectMatch("operator+@3", 14, 9);
+ Visitor.ExpectMatch("c@4", 14, 11);
+ Visitor.ExpectMatch("operator->@6", 15, 4);
+ Visitor.ExpectMatch("operator()@8", 16, 4);
+ Visitor.ExpectMatch("operator[]@10", 17, 4);
+ Visitor.ExpectMatch("operator++@11", 18, 3);
+ Visitor.ExpectMatch("operator++@14", 19, 4);
+ EXPECT_TRUE(Visitor.runOver(Source));
+}
+
+} // end anonymous namespace
diff --git a/unittests/Tooling/LookupTest.cpp b/unittests/Tooling/LookupTest.cpp
index cc3922d01b..f42f31e9dd 100644
--- a/unittests/Tooling/LookupTest.cpp
+++ b/unittests/Tooling/LookupTest.cpp
@@ -143,8 +143,9 @@ TEST(LookupTest, replaceNestedClassName) {
Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
// Filter Types by name since there are other `RecordTypeLoc` in the test
// file.
- if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
+ if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
EXPECT_EQ("x::Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
+ }
};
Visitor.runOver("namespace a { namespace b {\n"
"class Foo;\n"
@@ -155,8 +156,9 @@ TEST(LookupTest, replaceNestedClassName) {
// Filter Types by name since there are other `RecordTypeLoc` in the test
// file.
// `a::b::Foo` in using shadow decl is not `TypeLoc`.
- if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo")
+ if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
EXPECT_EQ("Bar", replaceRecordTypeLoc(Type, "::a::x::Bar"));
+ }
};
Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n"
"namespace c { using a::b::Foo; Foo f();; }\n");
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 7e08f9619c..63dbd14754 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -52,6 +52,14 @@ TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) {
EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
}
+TEST(RecursiveASTVisitor, VisitsAttributedLambdaExpr) {
+ LambdaExprVisitor Visitor;
+ Visitor.ExpectMatch("", 1, 12);
+ EXPECT_TRUE(Visitor.runOver(
+ "void f() { [] () __attribute__ (( fastcall )) { return; }(); }",
+ LambdaExprVisitor::Lang_CXX14));
+}
+
// Matches the (optional) capture-default of a lambda-introducer.
class LambdaDefaultCaptureVisitor
: public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
@@ -150,4 +158,148 @@ TEST(RecursiveASTVisitor, DefaultArgumentsAreVisited) {
"static int k = f();\n"));
}
+// Check to ensure that InitListExpr is visited twice, once each for the
+// syntactic and semantic form.
+class InitListExprPreOrderVisitor
+ : public ExpectedLocationVisitor<InitListExprPreOrderVisitor> {
+public:
+ bool VisitInitListExpr(InitListExpr *ILE) {
+ Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart());
+ return true;
+ }
+};
+
+class InitListExprPostOrderVisitor
+ : public ExpectedLocationVisitor<InitListExprPostOrderVisitor> {
+public:
+ bool shouldTraversePostOrder() const { return true; }
+
+ bool VisitInitListExpr(InitListExpr *ILE) {
+ Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart());
+ return true;
+ }
+};
+
+class InitListExprPreOrderNoQueueVisitor
+ : public ExpectedLocationVisitor<InitListExprPreOrderNoQueueVisitor> {
+public:
+ bool TraverseInitListExpr(InitListExpr *ILE) {
+ return ExpectedLocationVisitor::TraverseInitListExpr(ILE);
+ }
+
+ bool VisitInitListExpr(InitListExpr *ILE) {
+ Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart());
+ return true;
+ }
+};
+
+class InitListExprPostOrderNoQueueVisitor
+ : public ExpectedLocationVisitor<InitListExprPostOrderNoQueueVisitor> {
+public:
+ bool shouldTraversePostOrder() const { return true; }
+
+ bool TraverseInitListExpr(InitListExpr *ILE) {
+ return ExpectedLocationVisitor::TraverseInitListExpr(ILE);
+ }
+
+ bool VisitInitListExpr(InitListExpr *ILE) {
+ Match(ILE->isSemanticForm() ? "semantic" : "syntactic", ILE->getLocStart());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, InitListExprIsPreOrderVisitedTwice) {
+ InitListExprPreOrderVisitor Visitor;
+ Visitor.ExpectMatch("syntactic", 2, 21);
+ Visitor.ExpectMatch("semantic", 2, 21);
+ EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
+ "static struct S s = {.x = 0};\n",
+ InitListExprPreOrderVisitor::Lang_C));
+}
+
+TEST(RecursiveASTVisitor, InitListExprIsPostOrderVisitedTwice) {
+ InitListExprPostOrderVisitor Visitor;
+ Visitor.ExpectMatch("syntactic", 2, 21);
+ Visitor.ExpectMatch("semantic", 2, 21);
+ EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
+ "static struct S s = {.x = 0};\n",
+ InitListExprPostOrderVisitor::Lang_C));
+}
+
+TEST(RecursiveASTVisitor, InitListExprIsPreOrderNoQueueVisitedTwice) {
+ InitListExprPreOrderNoQueueVisitor Visitor;
+ Visitor.ExpectMatch("syntactic", 2, 21);
+ Visitor.ExpectMatch("semantic", 2, 21);
+ EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
+ "static struct S s = {.x = 0};\n",
+ InitListExprPreOrderNoQueueVisitor::Lang_C));
+}
+
+TEST(RecursiveASTVisitor, InitListExprIsPostOrderNoQueueVisitedTwice) {
+ InitListExprPostOrderNoQueueVisitor Visitor;
+ Visitor.ExpectMatch("syntactic", 2, 21);
+ Visitor.ExpectMatch("semantic", 2, 21);
+ EXPECT_TRUE(Visitor.runOver("struct S { int x; };\n"
+ "static struct S s = {.x = 0};\n",
+ InitListExprPostOrderNoQueueVisitor::Lang_C));
+}
+
+// Check to ensure that nested name specifiers are visited.
+class NestedNameSpecifiersVisitor
+ : public ExpectedLocationVisitor<NestedNameSpecifiersVisitor> {
+public:
+ bool VisitRecordTypeLoc(RecordTypeLoc RTL) {
+ if (!RTL)
+ return true;
+ Match(RTL.getDecl()->getName(), RTL.getNameLoc());
+ return true;
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ if (!NNS)
+ return true;
+ if (const NamespaceDecl *ND =
+ NNS.getNestedNameSpecifier()->getAsNamespace())
+ Match(ND->getName(), NNS.getLocalBeginLoc());
+ return ExpectedLocationVisitor::TraverseNestedNameSpecifierLoc(NNS);
+ }
+};
+
+TEST(RecursiveASTVisitor,
+ NestedNameSpecifiersForTemplateSpecializationsAreVisited) {
+ StringRef Source = R"(
+namespace ns {
+struct Outer {
+ template<typename T, typename U>
+ struct Nested { };
+
+ template<typename T>
+ static T x;
+};
+}
+
+template<>
+struct ns::Outer::Nested<int, int>;
+
+template<>
+struct ns::Outer::Nested<int, int> { };
+
+template<typename T>
+struct ns::Outer::Nested<int, T> { };
+
+template<>
+int ns::Outer::x<int> = 0;
+)";
+ NestedNameSpecifiersVisitor Visitor;
+ Visitor.ExpectMatch("ns", 13, 8);
+ Visitor.ExpectMatch("ns", 16, 8);
+ Visitor.ExpectMatch("ns", 19, 8);
+ Visitor.ExpectMatch("ns", 22, 5);
+ Visitor.ExpectMatch("Outer", 13, 12);
+ Visitor.ExpectMatch("Outer", 16, 12);
+ Visitor.ExpectMatch("Outer", 19, 12);
+ Visitor.ExpectMatch("Outer", 22, 9);
+ EXPECT_TRUE(Visitor.runOver(Source, NestedNameSpecifiersVisitor::Lang_CXX14));
+}
+
} // end anonymous namespace
diff --git a/unittests/Tooling/RefactoringActionRulesTest.cpp b/unittests/Tooling/RefactoringActionRulesTest.cpp
new file mode 100644
index 0000000000..f0b6466fec
--- /dev/null
+++ b/unittests/Tooling/RefactoringActionRulesTest.cpp
@@ -0,0 +1,248 @@
+//===- unittest/Tooling/RefactoringTestActionRulesTest.cpp ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReplacementTest.h"
+#include "RewriterTestContext.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Errc.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+class RefactoringActionRulesTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ Context.Sources.setMainFileID(
+ Context.createInMemoryFile("input.cpp", DefaultCode));
+ }
+
+ RewriterTestContext Context;
+ std::string DefaultCode = std::string(100, 'a');
+};
+
+Expected<AtomicChanges>
+createReplacements(const std::unique_ptr<RefactoringActionRule> &Rule,
+ RefactoringRuleContext &Context) {
+ class Consumer final : public RefactoringResultConsumer {
+ void handleError(llvm::Error Err) override { Result = std::move(Err); }
+
+ void handle(AtomicChanges SourceReplacements) override {
+ Result = std::move(SourceReplacements);
+ }
+ void handle(SymbolOccurrences Occurrences) override {
+ RefactoringResultConsumer::handle(std::move(Occurrences));
+ }
+
+ public:
+ Optional<Expected<AtomicChanges>> Result;
+ };
+
+ Consumer C;
+ Rule->invoke(C, Context);
+ return std::move(*C.Result);
+}
+
+TEST_F(RefactoringActionRulesTest, MyFirstRefactoringRule) {
+ class ReplaceAWithB : public SourceChangeRefactoringRule {
+ std::pair<SourceRange, int> Selection;
+
+ public:
+ ReplaceAWithB(std::pair<SourceRange, int> Selection)
+ : Selection(Selection) {}
+
+ static Expected<ReplaceAWithB>
+ initiate(RefactoringRuleContext &Cotnext,
+ std::pair<SourceRange, int> Selection) {
+ return ReplaceAWithB(Selection);
+ }
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) {
+ const SourceManager &SM = Context.getSources();
+ SourceLocation Loc =
+ Selection.first.getBegin().getLocWithOffset(Selection.second);
+ AtomicChange Change(SM, Loc);
+ llvm::Error E = Change.replace(SM, Loc, 1, "b");
+ if (E)
+ return std::move(E);
+ return AtomicChanges{Change};
+ }
+ };
+
+ class SelectionRequirement : public SourceRangeSelectionRequirement {
+ public:
+ Expected<std::pair<SourceRange, int>>
+ evaluate(RefactoringRuleContext &Context) const {
+ Expected<SourceRange> R =
+ SourceRangeSelectionRequirement::evaluate(Context);
+ if (!R)
+ return R.takeError();
+ return std::make_pair(*R, 20);
+ }
+ };
+ auto Rule =
+ createRefactoringActionRule<ReplaceAWithB>(SelectionRequirement());
+
+ // When the requirements are satisifed, the rule's function must be invoked.
+ {
+ RefactoringRuleContext RefContext(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID())
+ .getLocWithOffset(10);
+ RefContext.setSelectionRange({Cursor, Cursor});
+
+ Expected<AtomicChanges> ErrorOrResult =
+ createReplacements(Rule, RefContext);
+ ASSERT_FALSE(!ErrorOrResult);
+ AtomicChanges Result = std::move(*ErrorOrResult);
+ ASSERT_EQ(Result.size(), 1u);
+ std::string YAMLString =
+ const_cast<AtomicChange &>(Result[0]).toYAMLString();
+
+ ASSERT_STREQ("---\n"
+ "Key: 'input.cpp:30'\n"
+ "FilePath: input.cpp\n"
+ "Error: ''\n"
+ "InsertedHeaders: \n"
+ "RemovedHeaders: \n"
+ "Replacements: \n" // Extra whitespace here!
+ " - FilePath: input.cpp\n"
+ " Offset: 30\n"
+ " Length: 1\n"
+ " ReplacementText: b\n"
+ "...\n",
+ YAMLString.c_str());
+ }
+
+ // When one of the requirements is not satisfied, invoke should return a
+ // valid error.
+ {
+ RefactoringRuleContext RefContext(Context.Sources);
+ Expected<AtomicChanges> ErrorOrResult =
+ createReplacements(Rule, RefContext);
+
+ ASSERT_TRUE(!ErrorOrResult);
+ unsigned DiagID;
+ llvm::handleAllErrors(ErrorOrResult.takeError(),
+ [&](DiagnosticError &Error) {
+ DiagID = Error.getDiagnostic().second.getDiagID();
+ });
+ EXPECT_EQ(DiagID, diag::err_refactor_no_selection);
+ }
+}
+
+TEST_F(RefactoringActionRulesTest, ReturnError) {
+ class ErrorRule : public SourceChangeRefactoringRule {
+ public:
+ static Expected<ErrorRule> initiate(RefactoringRuleContext &,
+ SourceRange R) {
+ return ErrorRule(R);
+ }
+
+ ErrorRule(SourceRange R) {}
+ Expected<AtomicChanges> createSourceReplacements(RefactoringRuleContext &) {
+ return llvm::make_error<llvm::StringError>(
+ "Error", llvm::make_error_code(llvm::errc::invalid_argument));
+ }
+ };
+
+ auto Rule =
+ createRefactoringActionRule<ErrorRule>(SourceRangeSelectionRequirement());
+ RefactoringRuleContext RefContext(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
+ RefContext.setSelectionRange({Cursor, Cursor});
+ Expected<AtomicChanges> Result = createReplacements(Rule, RefContext);
+
+ ASSERT_TRUE(!Result);
+ std::string Message;
+ llvm::handleAllErrors(Result.takeError(), [&](llvm::StringError &Error) {
+ Message = Error.getMessage();
+ });
+ EXPECT_EQ(Message, "Error");
+}
+
+Optional<SymbolOccurrences> findOccurrences(RefactoringActionRule &Rule,
+ RefactoringRuleContext &Context) {
+ class Consumer final : public RefactoringResultConsumer {
+ void handleError(llvm::Error) override {}
+ void handle(SymbolOccurrences Occurrences) override {
+ Result = std::move(Occurrences);
+ }
+ void handle(AtomicChanges Changes) override {
+ RefactoringResultConsumer::handle(std::move(Changes));
+ }
+
+ public:
+ Optional<SymbolOccurrences> Result;
+ };
+
+ Consumer C;
+ Rule.invoke(C, Context);
+ return std::move(C.Result);
+}
+
+TEST_F(RefactoringActionRulesTest, ReturnSymbolOccurrences) {
+ class FindOccurrences : public FindSymbolOccurrencesRefactoringRule {
+ SourceRange Selection;
+
+ public:
+ FindOccurrences(SourceRange Selection) : Selection(Selection) {}
+
+ static Expected<FindOccurrences> initiate(RefactoringRuleContext &,
+ SourceRange Selection) {
+ return FindOccurrences(Selection);
+ }
+
+ Expected<SymbolOccurrences>
+ findSymbolOccurrences(RefactoringRuleContext &) override {
+ SymbolOccurrences Occurrences;
+ Occurrences.push_back(SymbolOccurrence(SymbolName("test"),
+ SymbolOccurrence::MatchingSymbol,
+ Selection.getBegin()));
+ return std::move(Occurrences);
+ }
+ };
+
+ auto Rule = createRefactoringActionRule<FindOccurrences>(
+ SourceRangeSelectionRequirement());
+
+ RefactoringRuleContext RefContext(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
+ RefContext.setSelectionRange({Cursor, Cursor});
+ Optional<SymbolOccurrences> Result = findOccurrences(*Rule, RefContext);
+
+ ASSERT_FALSE(!Result);
+ SymbolOccurrences Occurrences = std::move(*Result);
+ EXPECT_EQ(Occurrences.size(), 1u);
+ EXPECT_EQ(Occurrences[0].getKind(), SymbolOccurrence::MatchingSymbol);
+ EXPECT_EQ(Occurrences[0].getNameRanges().size(), 1u);
+ EXPECT_EQ(Occurrences[0].getNameRanges()[0],
+ SourceRange(Cursor, Cursor.getLocWithOffset(strlen("test"))));
+}
+
+TEST_F(RefactoringActionRulesTest, EditorCommandBinding) {
+ const RefactoringDescriptor &Descriptor = ExtractFunction::describe();
+ EXPECT_EQ(Descriptor.Name, "extract-function");
+ EXPECT_EQ(
+ Descriptor.Description,
+ "(WIP action; use with caution!) Extracts code into a new function");
+ EXPECT_EQ(Descriptor.Title, "Extract Function");
+}
+
+} // end anonymous namespace
diff --git a/unittests/Tooling/RefactoringCallbacksTest.cpp b/unittests/Tooling/RefactoringCallbacksTest.cpp
index ad8aa8f98f..e226522a70 100644
--- a/unittests/Tooling/RefactoringCallbacksTest.cpp
+++ b/unittests/Tooling/RefactoringCallbacksTest.cpp
@@ -7,10 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Tooling/RefactoringCallbacks.h"
#include "RewriterTestContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/RefactoringCallbacks.h"
#include "gtest/gtest.h"
namespace clang {
@@ -19,11 +19,10 @@ namespace tooling {
using namespace ast_matchers;
template <typename T>
-void expectRewritten(const std::string &Code,
- const std::string &Expected,
- const T &AMatcher,
- RefactoringCallback &Callback) {
- MatchFinder Finder;
+void expectRewritten(const std::string &Code, const std::string &Expected,
+ const T &AMatcher, RefactoringCallback &Callback) {
+ std::map<std::string, Replacements> FileToReplace;
+ ASTMatchRefactorer Finder(FileToReplace);
Finder.addMatcher(AMatcher, &Callback);
std::unique_ptr<tooling::FrontendActionFactory> Factory(
tooling::newFrontendActionFactory(&Finder));
@@ -31,7 +30,7 @@ void expectRewritten(const std::string &Code,
<< "Parsing error in \"" << Code << "\"";
RewriterTestContext Context;
FileID ID = Context.createInMemoryFile("input.cc", Code);
- EXPECT_TRUE(tooling::applyAllReplacements(Callback.getReplacements(),
+ EXPECT_TRUE(tooling::applyAllReplacements(FileToReplace["input.cc"],
Context.Rewrite));
EXPECT_EQ(Expected, Context.getRewrittenText(ID));
}
@@ -61,18 +60,18 @@ TEST(RefactoringCallbacksTest, ReplacesInteger) {
std::string Code = "void f() { int i = 1; }";
std::string Expected = "void f() { int i = 2; }";
ReplaceStmtWithText Callback("id", "2");
- expectRewritten(Code, Expected, id("id", expr(integerLiteral())),
- Callback);
+ expectRewritten(Code, Expected, id("id", expr(integerLiteral())), Callback);
}
TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) {
std::string Code = "void f() { int i = false ? 1 : i * 2; }";
std::string Expected = "void f() { int i = i * 2; }";
ReplaceStmtWithStmt Callback("always-false", "should-be");
- expectRewritten(Code, Expected,
- id("always-false", conditionalOperator(
- hasCondition(cxxBoolLiteral(equals(false))),
- hasFalseExpression(id("should-be", expr())))),
+ expectRewritten(
+ Code, Expected,
+ id("always-false",
+ conditionalOperator(hasCondition(cxxBoolLiteral(equals(false))),
+ hasFalseExpression(id("should-be", expr())))),
Callback);
}
@@ -80,10 +79,10 @@ TEST(RefactoringCallbacksTest, ReplacesIfStmt) {
std::string Code = "bool a; void f() { if (a) f(); else a = true; }";
std::string Expected = "bool a; void f() { f(); }";
ReplaceIfStmtWithItsBody Callback("id", true);
- expectRewritten(Code, Expected,
- id("id", ifStmt(
- hasCondition(implicitCastExpr(hasSourceExpression(
- declRefExpr(to(varDecl(hasName("a"))))))))),
+ expectRewritten(
+ Code, Expected,
+ id("id", ifStmt(hasCondition(implicitCastExpr(hasSourceExpression(
+ declRefExpr(to(varDecl(hasName("a"))))))))),
Callback);
}
@@ -92,9 +91,63 @@ TEST(RefactoringCallbacksTest, RemovesEntireIfOnEmptyElse) {
std::string Expected = "void f() { }";
ReplaceIfStmtWithItsBody Callback("id", false);
expectRewritten(Code, Expected,
- id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false))))),
- Callback);
+ id("id", ifStmt(hasCondition(cxxBoolLiteral(equals(false))))),
+ Callback);
}
+TEST(RefactoringCallbacksTest, TemplateJustText) {
+ std::string Code = "void f() { int i = 1; }";
+ std::string Expected = "void f() { FOO }";
+ auto Callback = ReplaceNodeWithTemplate::create("id", "FOO");
+ EXPECT_FALSE(Callback.takeError());
+ expectRewritten(Code, Expected, id("id", declStmt()), **Callback);
+}
+
+TEST(RefactoringCallbacksTest, TemplateSimpleSubst) {
+ std::string Code = "void f() { int i = 1; }";
+ std::string Expected = "void f() { long x = 1; }";
+ auto Callback = ReplaceNodeWithTemplate::create("decl", "long x = ${init}");
+ EXPECT_FALSE(Callback.takeError());
+ expectRewritten(Code, Expected,
+ id("decl", varDecl(hasInitializer(id("init", expr())))),
+ **Callback);
+}
+
+TEST(RefactoringCallbacksTest, TemplateLiteral) {
+ std::string Code = "void f() { int i = 1; }";
+ std::string Expected = "void f() { string x = \"$-1\"; }";
+ auto Callback = ReplaceNodeWithTemplate::create("decl",
+ "string x = \"$$-${init}\"");
+ EXPECT_FALSE(Callback.takeError());
+ expectRewritten(Code, Expected,
+ id("decl", varDecl(hasInitializer(id("init", expr())))),
+ **Callback);
+}
+
+static void ExpectStringError(const std::string &Expected,
+ llvm::Error E) {
+ std::string Found;
+ handleAllErrors(std::move(E), [&](const llvm::StringError &SE) {
+ llvm::raw_string_ostream Stream(Found);
+ SE.log(Stream);
+ });
+ EXPECT_EQ(Expected, Found);
+}
+
+TEST(RefactoringCallbacksTest, TemplateUnterminated) {
+ auto Callback = ReplaceNodeWithTemplate::create("decl",
+ "string x = \"$$-${init\"");
+ ExpectStringError("Unterminated ${...} in replacement template near ${init\"",
+ Callback.takeError());
+}
+
+TEST(RefactoringCallbacksTest, TemplateUnknownDollar) {
+ auto Callback = ReplaceNodeWithTemplate::create("decl",
+ "string x = \"$<");
+ ExpectStringError("Invalid $ in replacement template near $<",
+ Callback.takeError());
+}
+
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index c5633d36ed..41836f11ee 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -1092,7 +1092,7 @@ TEST(DeduplicateByFileTest, NonExistingFilePath) {
class AtomicChangeTest : public ::testing::Test {
protected:
- void setUp() {
+ void SetUp() override {
DefaultFileID = Context.createInMemoryFile("input.cpp", DefaultCode);
DefaultLoc = Context.Sources.getLocForStartOfFile(DefaultFileID)
.getLocWithOffset(20);
@@ -1107,7 +1107,6 @@ class AtomicChangeTest : public ::testing::Test {
};
TEST_F(AtomicChangeTest, AtomicChangeToYAML) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
llvm::Error Err =
Change.insert(Context.Sources, DefaultLoc, "aa", /*InsertAfter=*/false);
@@ -1124,8 +1123,10 @@ TEST_F(AtomicChangeTest, AtomicChangeToYAML) {
"Key: 'input.cpp:20'\n"
"FilePath: input.cpp\n"
"Error: ''\n"
- "InsertedHeaders: [ a.h ]\n"
- "RemovedHeaders: [ b.h ]\n"
+ "InsertedHeaders: \n" // Extra whitespace here!
+ " - a.h\n"
+ "RemovedHeaders: \n" // Extra whitespace here!
+ " - b.h\n"
"Replacements: \n" // Extra whitespace here!
" - FilePath: input.cpp\n"
" Offset: 20\n"
@@ -1140,13 +1141,14 @@ TEST_F(AtomicChangeTest, AtomicChangeToYAML) {
}
TEST_F(AtomicChangeTest, YAMLToAtomicChange) {
- setUp();
std::string YamlContent = "---\n"
"Key: 'input.cpp:20'\n"
"FilePath: input.cpp\n"
"Error: 'ok'\n"
- "InsertedHeaders: [ a.h ]\n"
- "RemovedHeaders: [ b.h ]\n"
+ "InsertedHeaders: \n" // Extra whitespace here!
+ " - a.h\n"
+ "RemovedHeaders: \n" // Extra whitespace here!
+ " - b.h\n"
"Replacements: \n" // Extra whitespace here!
" - FilePath: input.cpp\n"
" Offset: 20\n"
@@ -1187,14 +1189,12 @@ TEST_F(AtomicChangeTest, YAMLToAtomicChange) {
}
TEST_F(AtomicChangeTest, CheckKeyAndKeyFile) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
EXPECT_EQ("input.cpp:20", Change.getKey());
EXPECT_EQ("input.cpp", Change.getFilePath());
}
TEST_F(AtomicChangeTest, Replace) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
llvm::Error Err = Change.replace(Context.Sources, DefaultLoc, 2, "aa");
ASSERT_TRUE(!Err);
@@ -1209,8 +1209,18 @@ TEST_F(AtomicChangeTest, Replace) {
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) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");
ASSERT_TRUE(!Err);
@@ -1225,7 +1235,6 @@ TEST_F(AtomicChangeTest, InsertBefore) {
}
TEST_F(AtomicChangeTest, InsertAfter) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");
ASSERT_TRUE(!Err);
@@ -1240,7 +1249,6 @@ TEST_F(AtomicChangeTest, InsertAfter) {
}
TEST_F(AtomicChangeTest, InsertBeforeWithInvalidLocation) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
llvm::Error Err =
Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);
@@ -1254,11 +1262,9 @@ TEST_F(AtomicChangeTest, InsertBeforeWithInvalidLocation) {
std::move(Err), replacement_error::wrong_file_path,
Replacement(Context.Sources, DefaultLoc, 0, "a"),
Replacement(Context.Sources, SourceLocation(), 0, "a")));
-
}
TEST_F(AtomicChangeTest, InsertBeforeToWrongFile) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
llvm::Error Err =
Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);
@@ -1276,7 +1282,6 @@ TEST_F(AtomicChangeTest, InsertBeforeToWrongFile) {
}
TEST_F(AtomicChangeTest, InsertAfterWithInvalidLocation) {
- setUp();
AtomicChange Change(Context.Sources, DefaultLoc);
llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "a");
ASSERT_TRUE(!Err);
@@ -1290,5 +1295,427 @@ TEST_F(AtomicChangeTest, InsertAfterWithInvalidLocation) {
Replacement(Context.Sources, SourceLocation(), 0, "b")));
}
+class ApplyAtomicChangesTest : public ::testing::Test {
+protected:
+ ApplyAtomicChangesTest() : FilePath("file.cc") {
+ Spec.Cleanup = true;
+ Spec.Format = ApplyChangesSpec::kAll;
+ Spec.Style = format::getLLVMStyle();
+ }
+
+ ~ApplyAtomicChangesTest() override {}
+
+ void setInput(llvm::StringRef Input) {
+ Code = Input;
+ FID = Context.createInMemoryFile(FilePath, Code);
+ }
+
+ SourceLocation getLoc(unsigned Offset) const {
+ return Context.Sources.getLocForStartOfFile(FID).getLocWithOffset(Offset);
+ }
+
+ AtomicChange replacementToAtomicChange(llvm::StringRef Key, unsigned Offset,
+ unsigned Length,
+ llvm::StringRef Text) {
+ AtomicChange Change(FilePath, Key);
+ llvm::Error Err =
+ Change.replace(Context.Sources, getLoc(Offset), Length, Text);
+ EXPECT_FALSE(Err);
+ return Change;
+ }
+
+ std::string rewrite(bool FailureExpected = false) {
+ llvm::Expected<std::string> ChangedCode =
+ applyAtomicChanges(FilePath, Code, Changes, Spec);
+ EXPECT_EQ(FailureExpected, !ChangedCode);
+ if (!ChangedCode) {
+ llvm::errs() << "Failed to apply changes: "
+ << llvm::toString(ChangedCode.takeError()) << "\n";
+ return "";
+ }
+ return *ChangedCode;
+ }
+
+ RewriterTestContext Context;
+ FileID FID;
+ ApplyChangesSpec Spec;
+ std::string Code;
+ std::string FilePath;
+ llvm::SmallVector<AtomicChange, 8> Changes;
+};
+
+TEST_F(ApplyAtomicChangesTest, BasicRefactoring) {
+ setInput("int a;");
+ AtomicChange Change(FilePath, "key1");
+ Changes.push_back(replacementToAtomicChange("key1", 4, 1, "b"));
+ EXPECT_EQ("int b;", rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, SeveralRefactorings) {
+ setInput("int a;\n"
+ "int b;");
+ Changes.push_back(replacementToAtomicChange("key1", 0, 3, "float"));
+ Changes.push_back(replacementToAtomicChange("key2", 4, 1, "f"));
+ Changes.push_back(replacementToAtomicChange("key3", 11, 1, "g"));
+ Changes.push_back(replacementToAtomicChange("key4", 7, 3, "float"));
+ EXPECT_EQ("float f;\n"
+ "float g;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, IgnorePathsInRefactorings) {
+ setInput("int a;\n"
+ "int b;");
+ Changes.push_back(replacementToAtomicChange("key1", 4, 1, "aa"));
+
+ FileID ID = Context.createInMemoryFile("AnotherFile", "12345678912345");
+ Changes.emplace_back("AnotherFile", "key2");
+ auto Err = Changes.back().replace(
+ Context.Sources,
+ Context.Sources.getLocForStartOfFile(ID).getLocWithOffset(11), 1, "bb");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ("int aa;\n"
+ "int bb;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, AppliesDuplicateInsertions) {
+ setInput("int a;");
+ Changes.push_back(replacementToAtomicChange("key1", 5, 0, "b"));
+ Changes.push_back(replacementToAtomicChange("key2", 5, 0, "b"));
+ EXPECT_EQ("int abb;", rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, BailsOnOverlappingRefactorings) {
+ setInput("int a;");
+ Changes.push_back(replacementToAtomicChange("key1", 0, 5, "float f"));
+ Changes.push_back(replacementToAtomicChange("key2", 4, 1, "b"));
+ EXPECT_EQ("", rewrite(/*FailureExpected=*/true));
+}
+
+TEST_F(ApplyAtomicChangesTest, BasicReformatting) {
+ setInput("int a;");
+ Changes.push_back(replacementToAtomicChange("key1", 5, 1, "b"));
+ EXPECT_EQ("int b;", rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, OnlyFormatWhenViolateColumnLimits) {
+ Spec.Format = ApplyChangesSpec::kViolations;
+ Spec.Style.ColumnLimit = 8;
+ setInput("int a;\n"
+ "int a;\n"
+ "int aaaaaaaa;\n");
+ Changes.push_back(replacementToAtomicChange("key1", 5, 1, "x"));
+ Changes.push_back(replacementToAtomicChange("key2", 15, 1, "x"));
+ Changes.push_back(replacementToAtomicChange("key3", 23, 8, "xx"));
+ EXPECT_EQ("int x;\n"
+ "int x;\n"
+ "int xx;\n",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, LastLineViolateColumnLimits) {
+ Spec.Format = ApplyChangesSpec::kViolations;
+ Spec.Style.ColumnLimit = 8;
+ setInput("int a;\n"
+ "int a;");
+ Changes.push_back(replacementToAtomicChange("key1", 0, 1, "i"));
+ Changes.push_back(replacementToAtomicChange("key2", 15, 2, "y;"));
+ EXPECT_EQ("int a;\n"
+ "int y;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, LastLineWithNewlineViolateColumnLimits) {
+ Spec.Format = ApplyChangesSpec::kViolations;
+ Spec.Style.ColumnLimit = 8;
+ setInput("int a;\n"
+ "int a;\n");
+ Changes.push_back(replacementToAtomicChange("key1", 0, 1, "i"));
+ Changes.push_back(replacementToAtomicChange("key2", 14, 3, "y;\n"));
+ EXPECT_EQ("int a;\n"
+ "int y;\n",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, Longer) {
+ setInput("int a;");
+ Changes.push_back(replacementToAtomicChange("key1", 5, 1, "bbb"));
+ EXPECT_EQ("int bbb;", rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, Shorter) {
+ setInput("int aaa;");
+ Changes.push_back(replacementToAtomicChange("key1", 5, 3, "b"));
+ EXPECT_EQ("int b;", rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, OnlyFormatChangedLines) {
+ setInput("int aaa;\n"
+ "int a = b;\n"
+ "int bbb;");
+ Changes.push_back(replacementToAtomicChange("key1", 14, 1, "b"));
+ EXPECT_EQ("int aaa;\n"
+ "int b = b;\n"
+ "int bbb;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, DisableFormatting) {
+ Spec.Format = ApplyChangesSpec::kNone;
+ setInput("int aaa;\n"
+ "int a = b;\n"
+ "int bbb;");
+ Changes.push_back(replacementToAtomicChange("key1", 14, 1, "b"));
+ EXPECT_EQ("int aaa;\n"
+ "int b = b;\n"
+ "int bbb;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, AdaptsToLocalPointerStyle) {
+ setInput("int *aaa;\n"
+ "int *bbb;");
+ Changes.push_back(replacementToAtomicChange("key1", 0, 0, "int* ccc;\n"));
+ EXPECT_EQ("int *ccc;\n"
+ "int *aaa;\n"
+ "int *bbb;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, AcceptsSurroundingFormatting) {
+ setInput(" int aaa;\n"
+ " int a = b;\n"
+ " int bbb;");
+ Changes.push_back(replacementToAtomicChange("key1", 20, 1, "b"));
+ EXPECT_EQ(" int aaa;\n"
+ " int b = b;\n"
+ " int bbb;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, BailsOutOnConflictingChanges) {
+ setInput("int c;\n"
+ "int f;");
+ // Insertions at the same offset are only allowed in the same AtomicChange.
+ Changes.push_back(replacementToAtomicChange("key1", 0, 0, "int a;\n"));
+ Changes.push_back(replacementToAtomicChange("key2", 0, 0, "int b;\n"));
+ EXPECT_EQ("", rewrite(/*FailureExpected=*/true));
+}
+
+TEST_F(ApplyAtomicChangesTest, InsertsNewIncludesInRightOrder) {
+ setInput("int a;");
+ Changes.emplace_back(FilePath, "key1");
+ Changes.back().addHeader("b");
+ Changes.back().addHeader("c");
+ Changes.emplace_back(FilePath, "key2");
+ Changes.back().addHeader("a");
+ EXPECT_EQ("#include \"a\"\n"
+ "#include \"b\"\n"
+ "#include \"c\"\n"
+ "int a;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, RemoveAndSortIncludes) {
+ setInput("#include \"a\"\n"
+ "#include \"b\"\n"
+ "#include \"c\"\n"
+ "\n"
+ "int a;");
+ Changes.emplace_back(FilePath, "key1");
+ Changes.back().removeHeader("b");
+ EXPECT_EQ("#include \"a\"\n"
+ "#include \"c\"\n"
+ "\n"
+ "int a;",
+ rewrite());
+}
+TEST_F(ApplyAtomicChangesTest, InsertsSystemIncludes) {
+ setInput("#include <asys>\n"
+ "#include <csys>\n"
+ "\n"
+ "#include \"a\"\n"
+ "#include \"c\"\n");
+ Changes.emplace_back(FilePath, "key1");
+ Changes.back().addHeader("<asys>"); // Already exists.
+ Changes.back().addHeader("<b>");
+ Changes.back().addHeader("<d>");
+ Changes.back().addHeader("\"b-already-escaped\"");
+ EXPECT_EQ("#include <asys>\n"
+ "#include <b>\n"
+ "#include <csys>\n"
+ "#include <d>\n"
+ "\n"
+ "#include \"a\"\n"
+ "#include \"b-already-escaped\"\n"
+ "#include \"c\"\n",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, RemoveSystemIncludes) {
+ setInput("#include <a>\n"
+ "#include <b>\n"
+ "\n"
+ "#include \"c\""
+ "\n"
+ "int a;");
+ Changes.emplace_back(FilePath, "key1");
+ Changes.back().removeHeader("<a>");
+ EXPECT_EQ("#include <b>\n"
+ "\n"
+ "#include \"c\""
+ "\n"
+ "int a;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest,
+ DoNotFormatFollowingLinesIfSeparatedWithNewline) {
+ setInput("#ifndef __H__\n"
+ "#define __H__\n"
+ "#include \"b\"\n"
+ "\n"
+ "int a;\n"
+ "int a;\n"
+ "int a;\n"
+ "#endif // __H__\n");
+ Changes.push_back(replacementToAtomicChange("key1",
+ llvm::StringRef("#ifndef __H__\n"
+ "#define __H__\n"
+ "\n"
+ "#include \"b\"\n"
+ "int a;\n"
+ "int ")
+ .size(),
+ 1, "b"));
+ Changes.back().addHeader("a");
+ EXPECT_EQ("#ifndef __H__\n"
+ "#define __H__\n"
+ "#include \"a\"\n"
+ "#include \"b\"\n"
+ "\n"
+ "int a;\n"
+ "int b;\n"
+ "int a;\n"
+ "#endif // __H__\n",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, FormatsCorrectLineWhenHeaderIsRemoved) {
+ setInput("#include \"a\"\n"
+ "\n"
+ "int a;\n"
+ "int a;\n"
+ "int a;");
+ Changes.push_back(replacementToAtomicChange("key1", 27, 1, "b"));
+ Changes.back().removeHeader("a");
+ EXPECT_EQ("\n"
+ "int a;\n"
+ "int b;\n"
+ "int a;",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, CleansUpCtorInitializers) {
+ setInput("A::A() : a(), b() {}\n"
+ "A::A() : a(), b() {}\n"
+ "A::A() : a(), b() {}\n"
+ "A::A() : a()/**/, b() {}\n"
+ "A::A() : a() ,// \n"
+ " /**/ b() {}");
+ Changes.emplace_back(FilePath, "key1");
+ auto Err = Changes.back().replace(Context.Sources, getLoc(9), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(35), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(51), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(56), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(72), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(97), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(118), 3, "");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ("A::A() : b() {}\n"
+ "A::A() : a() {}\n"
+ "A::A() {}\n"
+ "A::A() : b() {}\n"
+ "A::A() {}",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, CleansUpParameterLists) {
+ setInput("void f(int i, float f, string s);\n"
+ "f(1, 2.0f, \"a\");\n"
+ "g(1, 1);");
+ Changes.emplace_back(FilePath, "key1");
+ auto Err = Changes.back().replace(Context.Sources, getLoc(7), 5, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(23), 8, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(36), 1, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(45), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(53), 1, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(56), 1, "");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ("void f(float f);\n"
+ "f(2.0f);\n"
+ "g();",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, DisableCleanup) {
+ Spec.Cleanup = false;
+ setInput("void f(int i, float f, string s);\n"
+ "f(1, 2.0f, \"a\");\n"
+ "g(1, 1);");
+ Changes.emplace_back(FilePath, "key1");
+ auto Err = Changes.back().replace(Context.Sources, getLoc(7), 5, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(23), 8, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(36), 1, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(45), 3, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(53), 1, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(56), 1, "");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ("void f(, float f, );\n"
+ "f(, 2.0f, );\n"
+ "g(, );",
+ rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, EverythingDeleted) {
+ setInput("int a;");
+ Changes.push_back(replacementToAtomicChange("key1", 0, 6, ""));
+ EXPECT_EQ("", rewrite());
+}
+
+TEST_F(ApplyAtomicChangesTest, DoesNotDeleteInserts) {
+ setInput("int a;\n"
+ "int b;");
+ Changes.emplace_back(FilePath, "key1");
+ auto Err = Changes.back().replace(Context.Sources, getLoc(4), 1, "");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(4), 0, "b");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(11), 0, "a");
+ ASSERT_TRUE(!Err);
+ Err = Changes.back().replace(Context.Sources, getLoc(11), 1, "");
+ ASSERT_TRUE(!Err);
+ EXPECT_EQ("int b;\n"
+ "int a;",
+ rewrite());
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index a762ec8b14..fb6a76ccad 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -53,11 +53,17 @@ public:
bool runOver(StringRef Code, Language L = Lang_CXX) {
std::vector<std::string> Args;
switch (L) {
- case Lang_C: Args.push_back("-std=c99"); break;
+ case Lang_C:
+ Args.push_back("-x");
+ Args.push_back("c");
+ break;
case Lang_CXX98: Args.push_back("-std=c++98"); break;
case Lang_CXX11: Args.push_back("-std=c++11"); break;
case Lang_CXX14: Args.push_back("-std=c++14"); break;
- case Lang_OBJC: Args.push_back("-ObjC"); break;
+ case Lang_OBJC:
+ Args.push_back("-ObjC");
+ Args.push_back("-fobjc-runtime=macosx-10.12.0");
+ break;
case Lang_OBJCXX11:
Args.push_back("-ObjC++");
Args.push_back("-std=c++11");
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index 68b5ed2105..b179f033d3 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -203,7 +203,7 @@ TEST(ToolInvocation, TestVirtualModulesCompilation) {
struct VerifyEndCallback : public SourceFileCallbacks {
VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
- bool handleBeginSource(CompilerInstance &CI, StringRef Filename) override {
+ bool handleBeginSource(CompilerInstance &CI) override {
++BeginCalled;
return true;
}
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index c8e9537cb5..435529cdfd 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -6,6 +6,7 @@ add_tablegen(clang-tblgen CLANG
ClangCommentCommandInfoEmitter.cpp
ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
ClangCommentHTMLTagsEmitter.cpp
+ ClangDataCollectorsEmitter.cpp
ClangDiagnosticsEmitter.cpp
ClangOptionDocEmitter.cpp
ClangSACheckersEmitter.cpp
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 990b860dea..9284fe4081 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -12,13 +12,15 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
@@ -54,9 +56,9 @@ public:
V(Spelling.getValueAsString("Variety")),
N(Spelling.getValueAsString("Name")) {
- assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been"
- "flattened!");
- if (V == "CXX11" || V == "Pragma")
+ assert(V != "GCC" && V != "Clang" &&
+ "Given a GCC spelling, which means this hasn't been flattened!");
+ if (V == "CXX11" || V == "C2x" || V == "Pragma")
NS = Spelling.getValueAsString("Namespace");
bool Unset;
K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset);
@@ -76,11 +78,15 @@ GetFlattenedSpellings(const Record &Attr) {
std::vector<FlattenedSpelling> Ret;
for (const auto &Spelling : Spellings) {
- if (Spelling->getValueAsString("Variety") == "GCC") {
+ StringRef Variety = Spelling->getValueAsString("Variety");
+ StringRef Name = Spelling->getValueAsString("Name");
+ if (Variety == "GCC") {
// Gin up two new spelling objects to add into the list.
- Ret.emplace_back("GNU", Spelling->getValueAsString("Name"), "", true);
- Ret.emplace_back("CXX11", Spelling->getValueAsString("Name"), "gnu",
- true);
+ Ret.emplace_back("GNU", Name, "", true);
+ Ret.emplace_back("CXX11", Name, "gnu", true);
+ } else if (Variety == "Clang") {
+ Ret.emplace_back("GNU", Name, "", false);
+ Ret.emplace_back("CXX11", Name, "clang", false);
} else
Ret.push_back(FlattenedSpelling(*Spelling));
}
@@ -310,7 +316,7 @@ namespace {
}
void writeDump(raw_ostream &OS) const override {
- if (type == "FunctionDecl *") {
+ if (type == "FunctionDecl *" || type == "NamedDecl *") {
OS << " OS << \" \";\n";
OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
} else if (type == "IdentifierInfo *") {
@@ -488,6 +494,17 @@ namespace {
OS << "}\n";
}
+ void writeASTVisitorTraversal(raw_ostream &OS) const override {
+ StringRef Name = getUpperName();
+ OS << " if (A->is" << Name << "Expr()) {\n"
+ << " if (!getDerived().TraverseStmt(A->get" << Name << "Expr()))\n"
+ << " return false;\n"
+ << " } else if (auto *TSI = A->get" << Name << "Type()) {\n"
+ << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n"
+ << " return false;\n"
+ << " }\n";
+ }
+
void writeCloneArgs(raw_ostream &OS) const override {
OS << "is" << getLowerName() << "Expr, is" << getLowerName()
<< "Expr ? static_cast<void*>(" << getLowerName()
@@ -628,6 +645,10 @@ namespace {
<< "A->" << getLowerName() << "_size()";
}
+ void writeASTVisitorTraversal(raw_ostream &OS) const override {
+ // FIXME: Traverse the elements.
+ }
+
void writeCtorBody(raw_ostream &OS) const override {
OS << " std::copy(" << getUpperName() << ", " << getUpperName()
<< " + " << ArgSizeName << ", " << ArgName << ");\n";
@@ -716,9 +737,9 @@ namespace {
};
// Unique the enums, but maintain the original declaration ordering.
- std::vector<std::string>
- uniqueEnumsInOrder(const std::vector<std::string> &enums) {
- std::vector<std::string> uniques;
+ std::vector<StringRef>
+ uniqueEnumsInOrder(const std::vector<StringRef> &enums) {
+ std::vector<StringRef> uniques;
SmallDenseSet<StringRef, 8> unique_set;
for (const auto &i : enums) {
if (unique_set.insert(i).second)
@@ -729,7 +750,8 @@ namespace {
class EnumArgument : public Argument {
std::string type;
- std::vector<std::string> values, enums, uniques;
+ std::vector<StringRef> values, enums, uniques;
+
public:
EnumArgument(const Record &Arg, StringRef Attr)
: Argument(Arg, Attr), type(Arg.getValueAsString("Type")),
@@ -848,7 +870,7 @@ namespace {
class VariadicEnumArgument: public VariadicArgument {
std::string type, QualifiedTypeName;
- std::vector<std::string> values, enums, uniques;
+ std::vector<StringRef> values, enums, uniques;
protected:
void writeValueImpl(raw_ostream &OS) const override {
@@ -1036,7 +1058,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 +1105,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()
@@ -1150,6 +1172,12 @@ namespace {
OS << " }";
}
+ void writeASTVisitorTraversal(raw_ostream &OS) const override {
+ OS << " if (auto *TSI = A->get" << getUpperName() << "Loc())\n";
+ OS << " if (!getDerived().TraverseTypeLoc(TSI->getTypeLoc()))\n";
+ OS << " return false;\n";
+ }
+
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
OS << "A->get" << getUpperName() << "Loc()";
}
@@ -1179,6 +1207,8 @@ createArgument(const Record &Arg, StringRef Attr,
Ptr = llvm::make_unique<ExprArgument>(Arg, Attr);
else if (ArgName == "FunctionArgument")
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *");
+ else if (ArgName == "NamedArgument")
+ Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *");
else if (ArgName == "IdentifierArgument")
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *");
else if (ArgName == "DefaultBoolArgument")
@@ -1300,7 +1330,7 @@ writePrettyPrintFunction(Record &R,
if (Variety == "GNU") {
Prefix = " __attribute__((";
Suffix = "))";
- } else if (Variety == "CXX11") {
+ } else if (Variety == "CXX11" || Variety == "C2x") {
Prefix = " [[";
Suffix = "]]";
std::string Namespace = Spellings[I].nameSpace();
@@ -1414,7 +1444,7 @@ static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) {
assert(!SpellingList.empty() &&
"Attribute with empty spelling list can't have accessors!");
for (const auto *Accessor : Accessors) {
- std::string Name = Accessor->getValueAsString("Name");
+ const StringRef Name = Accessor->getValueAsString("Name");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Accessor);
OS << " bool " << Name << "() const { return SpellingListIndex == ";
@@ -1522,6 +1552,407 @@ static void emitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS)
OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n";
}
+static bool hasGNUorCXX11Spelling(const Record &Attribute) {
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute);
+ for (const auto &I : Spellings) {
+ if (I.variety() == "GNU" || I.variety() == "CXX11")
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+struct AttributeSubjectMatchRule {
+ const Record *MetaSubject;
+ const Record *Constraint;
+
+ AttributeSubjectMatchRule(const Record *MetaSubject, const Record *Constraint)
+ : MetaSubject(MetaSubject), Constraint(Constraint) {
+ assert(MetaSubject && "Missing subject");
+ }
+
+ bool isSubRule() const { return Constraint != nullptr; }
+
+ std::vector<Record *> getSubjects() const {
+ return (Constraint ? Constraint : MetaSubject)
+ ->getValueAsListOfDefs("Subjects");
+ }
+
+ std::vector<Record *> getLangOpts() const {
+ if (Constraint) {
+ // Lookup the options in the sub-rule first, in case the sub-rule
+ // overrides the rules options.
+ std::vector<Record *> Opts = Constraint->getValueAsListOfDefs("LangOpts");
+ if (!Opts.empty())
+ return Opts;
+ }
+ return MetaSubject->getValueAsListOfDefs("LangOpts");
+ }
+
+ // Abstract rules are used only for sub-rules
+ bool isAbstractRule() const { return getSubjects().empty(); }
+
+ StringRef getName() const {
+ return (Constraint ? Constraint : MetaSubject)->getValueAsString("Name");
+ }
+
+ bool isNegatedSubRule() const {
+ assert(isSubRule() && "Not a sub-rule");
+ return Constraint->getValueAsBit("Negated");
+ }
+
+ std::string getSpelling() const {
+ std::string Result = MetaSubject->getValueAsString("Name");
+ if (isSubRule()) {
+ Result += '(';
+ if (isNegatedSubRule())
+ Result += "unless(";
+ Result += getName();
+ if (isNegatedSubRule())
+ Result += ')';
+ Result += ')';
+ }
+ return Result;
+ }
+
+ std::string getEnumValueName() const {
+ SmallString<128> Result;
+ Result += "SubjectMatchRule_";
+ Result += MetaSubject->getValueAsString("Name");
+ if (isSubRule()) {
+ Result += "_";
+ if (isNegatedSubRule())
+ Result += "not_";
+ Result += Constraint->getValueAsString("Name");
+ }
+ if (isAbstractRule())
+ Result += "_abstract";
+ return Result.str();
+ }
+
+ std::string getEnumValue() const { return "attr::" + getEnumValueName(); }
+
+ static const char *EnumName;
+};
+
+const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule";
+
+struct PragmaClangAttributeSupport {
+ std::vector<AttributeSubjectMatchRule> Rules;
+
+ class RuleOrAggregateRuleSet {
+ std::vector<AttributeSubjectMatchRule> Rules;
+ bool IsRule;
+ RuleOrAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules,
+ bool IsRule)
+ : Rules(Rules), IsRule(IsRule) {}
+
+ public:
+ bool isRule() const { return IsRule; }
+
+ const AttributeSubjectMatchRule &getRule() const {
+ assert(IsRule && "not a rule!");
+ return Rules[0];
+ }
+
+ ArrayRef<AttributeSubjectMatchRule> getAggregateRuleSet() const {
+ return Rules;
+ }
+
+ static RuleOrAggregateRuleSet
+ getRule(const AttributeSubjectMatchRule &Rule) {
+ return RuleOrAggregateRuleSet(Rule, /*IsRule=*/true);
+ }
+ static RuleOrAggregateRuleSet
+ getAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules) {
+ return RuleOrAggregateRuleSet(Rules, /*IsRule=*/false);
+ }
+ };
+ llvm::DenseMap<const Record *, RuleOrAggregateRuleSet> SubjectsToRules;
+
+ PragmaClangAttributeSupport(RecordKeeper &Records);
+
+ bool isAttributedSupported(const Record &Attribute);
+
+ void emitMatchRuleList(raw_ostream &OS);
+
+ std::string generateStrictConformsTo(const Record &Attr, raw_ostream &OS);
+
+ void generateParsingHelpers(raw_ostream &OS);
+};
+
+} // end anonymous namespace
+
+static bool doesDeclDeriveFrom(const Record *D, const Record *Base) {
+ const Record *CurrentBase = D->getValueAsDef("Base");
+ if (!CurrentBase)
+ return false;
+ if (CurrentBase == Base)
+ return true;
+ return doesDeclDeriveFrom(CurrentBase, Base);
+}
+
+PragmaClangAttributeSupport::PragmaClangAttributeSupport(
+ RecordKeeper &Records) {
+ std::vector<Record *> MetaSubjects =
+ Records.getAllDerivedDefinitions("AttrSubjectMatcherRule");
+ auto MapFromSubjectsToRules = [this](const Record *SubjectContainer,
+ const Record *MetaSubject,
+ const Record *Constraint) {
+ Rules.emplace_back(MetaSubject, Constraint);
+ std::vector<Record *> ApplicableSubjects =
+ SubjectContainer->getValueAsListOfDefs("Subjects");
+ for (const auto *Subject : ApplicableSubjects) {
+ bool Inserted =
+ SubjectsToRules
+ .try_emplace(Subject, RuleOrAggregateRuleSet::getRule(
+ AttributeSubjectMatchRule(MetaSubject,
+ Constraint)))
+ .second;
+ if (!Inserted) {
+ PrintFatalError("Attribute subject match rules should not represent"
+ "same attribute subjects.");
+ }
+ }
+ };
+ for (const auto *MetaSubject : MetaSubjects) {
+ MapFromSubjectsToRules(MetaSubject, MetaSubject, /*Constraints=*/nullptr);
+ std::vector<Record *> Constraints =
+ MetaSubject->getValueAsListOfDefs("Constraints");
+ for (const auto *Constraint : Constraints)
+ MapFromSubjectsToRules(Constraint, MetaSubject, Constraint);
+ }
+
+ std::vector<Record *> Aggregates =
+ Records.getAllDerivedDefinitions("AttrSubjectMatcherAggregateRule");
+ std::vector<Record *> DeclNodes = Records.getAllDerivedDefinitions("DDecl");
+ for (const auto *Aggregate : Aggregates) {
+ Record *SubjectDecl = Aggregate->getValueAsDef("Subject");
+
+ // Gather sub-classes of the aggregate subject that act as attribute
+ // subject rules.
+ std::vector<AttributeSubjectMatchRule> Rules;
+ for (const auto *D : DeclNodes) {
+ if (doesDeclDeriveFrom(D, SubjectDecl)) {
+ auto It = SubjectsToRules.find(D);
+ if (It == SubjectsToRules.end())
+ continue;
+ if (!It->second.isRule() || It->second.getRule().isSubRule())
+ continue; // Assume that the rule will be included as well.
+ Rules.push_back(It->second.getRule());
+ }
+ }
+
+ bool Inserted =
+ SubjectsToRules
+ .try_emplace(SubjectDecl,
+ RuleOrAggregateRuleSet::getAggregateRuleSet(Rules))
+ .second;
+ if (!Inserted) {
+ PrintFatalError("Attribute subject match rules should not represent"
+ "same attribute subjects.");
+ }
+ }
+}
+
+static PragmaClangAttributeSupport &
+getPragmaAttributeSupport(RecordKeeper &Records) {
+ static PragmaClangAttributeSupport Instance(Records);
+ return Instance;
+}
+
+void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) {
+ OS << "#ifndef ATTR_MATCH_SUB_RULE\n";
+ OS << "#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, "
+ "IsNegated) "
+ << "ATTR_MATCH_RULE(Value, Spelling, IsAbstract)\n";
+ OS << "#endif\n";
+ for (const auto &Rule : Rules) {
+ OS << (Rule.isSubRule() ? "ATTR_MATCH_SUB_RULE" : "ATTR_MATCH_RULE") << '(';
+ OS << Rule.getEnumValueName() << ", \"" << Rule.getSpelling() << "\", "
+ << Rule.isAbstractRule();
+ if (Rule.isSubRule())
+ OS << ", "
+ << AttributeSubjectMatchRule(Rule.MetaSubject, nullptr).getEnumValue()
+ << ", " << Rule.isNegatedSubRule();
+ OS << ")\n";
+ }
+ OS << "#undef ATTR_MATCH_SUB_RULE\n";
+}
+
+bool PragmaClangAttributeSupport::isAttributedSupported(
+ const Record &Attribute) {
+ if (Attribute.getValueAsBit("ForcePragmaAttributeSupport"))
+ return true;
+ // Opt-out rules:
+ // FIXME: The documentation check should be moved before
+ // the ForcePragmaAttributeSupport check after annotate is documented.
+ // No documentation present.
+ if (Attribute.isValueUnset("Documentation"))
+ return false;
+ std::vector<Record *> Docs = Attribute.getValueAsListOfDefs("Documentation");
+ if (Docs.empty())
+ return false;
+ if (Docs.size() == 1 && Docs[0]->getName() == "Undocumented")
+ return false;
+ // An attribute requires delayed parsing (LateParsed is on)
+ if (Attribute.getValueAsBit("LateParsed"))
+ return false;
+ // An attribute has no GNU/CXX11 spelling
+ if (!hasGNUorCXX11Spelling(Attribute))
+ return false;
+ // An attribute subject list has a subject that isn't covered by one of the
+ // subject match rules or has no subjects at all.
+ if (Attribute.isValueUnset("Subjects"))
+ return false;
+ const Record *SubjectObj = Attribute.getValueAsDef("Subjects");
+ std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
+ if (Subjects.empty())
+ return false;
+ for (const auto *Subject : Subjects) {
+ if (SubjectsToRules.find(Subject) == SubjectsToRules.end())
+ return false;
+ }
+ return true;
+}
+
+std::string
+PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr,
+ raw_ostream &OS) {
+ if (!isAttributedSupported(Attr))
+ return "nullptr";
+ // Generate a function that constructs a set of matching rules that describe
+ // to which declarations the attribute should apply to.
+ std::string FnName = "matchRulesFor" + Attr.getName().str();
+ OS << "static void " << FnName << "(llvm::SmallVectorImpl<std::pair<"
+ << AttributeSubjectMatchRule::EnumName
+ << ", bool>> &MatchRules, const LangOptions &LangOpts) {\n";
+ if (Attr.isValueUnset("Subjects")) {
+ OS << "}\n\n";
+ return FnName;
+ }
+ const Record *SubjectObj = Attr.getValueAsDef("Subjects");
+ std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
+ for (const auto *Subject : Subjects) {
+ auto It = SubjectsToRules.find(Subject);
+ assert(It != SubjectsToRules.end() &&
+ "This attribute is unsupported by #pragma clang attribute");
+ for (const auto &Rule : It->getSecond().getAggregateRuleSet()) {
+ // The rule might be language specific, so only subtract it from the given
+ // rules if the specific language options are specified.
+ std::vector<Record *> LangOpts = Rule.getLangOpts();
+ OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue()
+ << ", /*IsSupported=*/";
+ if (!LangOpts.empty()) {
+ for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
+ const StringRef Part = (*I)->getValueAsString("Name");
+ if ((*I)->getValueAsBit("Negated"))
+ OS << "!";
+ OS << "LangOpts." << Part;
+ if (I + 1 != E)
+ OS << " || ";
+ }
+ } else
+ OS << "true";
+ OS << "));\n";
+ }
+ }
+ OS << "}\n\n";
+ return FnName;
+}
+
+void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
+ // Generate routines that check the names of sub-rules.
+ OS << "Optional<attr::SubjectMatchRule> "
+ "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n";
+ OS << " return None;\n";
+ OS << "}\n\n";
+
+ std::map<const Record *, std::vector<AttributeSubjectMatchRule>>
+ SubMatchRules;
+ for (const auto &Rule : Rules) {
+ if (!Rule.isSubRule())
+ continue;
+ SubMatchRules[Rule.MetaSubject].push_back(Rule);
+ }
+
+ for (const auto &SubMatchRule : SubMatchRules) {
+ OS << "Optional<attr::SubjectMatchRule> isAttributeSubjectMatchSubRuleFor_"
+ << SubMatchRule.first->getValueAsString("Name")
+ << "(StringRef Name, bool IsUnless) {\n";
+ OS << " if (IsUnless)\n";
+ OS << " return "
+ "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ for (const auto &Rule : SubMatchRule.second) {
+ if (Rule.isNegatedSubRule())
+ OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
+ << ").\n";
+ }
+ OS << " Default(None);\n";
+ OS << " return "
+ "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ for (const auto &Rule : SubMatchRule.second) {
+ if (!Rule.isNegatedSubRule())
+ OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
+ << ").\n";
+ }
+ OS << " Default(None);\n";
+ OS << "}\n\n";
+ }
+
+ // Generate the function that checks for the top-level rules.
+ OS << "std::pair<Optional<attr::SubjectMatchRule>, "
+ "Optional<attr::SubjectMatchRule> (*)(StringRef, "
+ "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n";
+ OS << " return "
+ "llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, "
+ "Optional<attr::SubjectMatchRule> (*) (StringRef, "
+ "bool)>>(Name).\n";
+ for (const auto &Rule : Rules) {
+ if (Rule.isSubRule())
+ continue;
+ std::string SubRuleFunction;
+ if (SubMatchRules.count(Rule.MetaSubject))
+ SubRuleFunction =
+ ("isAttributeSubjectMatchSubRuleFor_" + Rule.getName()).str();
+ else
+ SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor";
+ OS << " Case(\"" << Rule.getName() << "\", std::make_pair("
+ << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n";
+ }
+ OS << " Default(std::make_pair(None, "
+ "defaultIsAttributeSubjectMatchSubRuleFor));\n";
+ OS << "}\n\n";
+
+ // Generate the function that checks for the submatch rules.
+ OS << "const char *validAttributeSubjectMatchSubRules("
+ << AttributeSubjectMatchRule::EnumName << " Rule) {\n";
+ OS << " switch (Rule) {\n";
+ for (const auto &SubMatchRule : SubMatchRules) {
+ OS << " case "
+ << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue()
+ << ":\n";
+ OS << " return \"'";
+ bool IsFirst = true;
+ for (const auto &Rule : SubMatchRule.second) {
+ if (!IsFirst)
+ OS << ", '";
+ IsFirst = false;
+ if (Rule.isNegatedSubRule())
+ OS << "unless(";
+ OS << Rule.getName();
+ if (Rule.isNegatedSubRule())
+ OS << ')';
+ OS << "'";
+ }
+ OS << "\";\n";
+ }
+ OS << " default: return nullptr;\n";
+ OS << " }\n";
+ OS << "}\n\n";
+}
+
template <typename Fn>
static void forEachUniqueSpelling(const Record &Attr, Fn &&F) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
@@ -2109,6 +2540,17 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#undef PRAGMA_SPELLING_ATTR\n";
}
+// Emits the enumeration list for attributes.
+void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader(
+ "List of all attribute subject matching rules that Clang recognizes", OS);
+ PragmaClangAttributeSupport &PragmaAttributeSupport =
+ getPragmaAttributeSupport(Records);
+ emitDefaultDefine(OS, "ATTR_MATCH_RULE", nullptr);
+ PragmaAttributeSupport.emitMatchRuleList(OS);
+ OS << "#undef ATTR_MATCH_RULE\n";
+}
+
// Emits the code to read an attribute from a precompiled header.
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute deserialization code", OS);
@@ -2186,7 +2628,7 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
// append a unique suffix to distinguish this set of target checks from other
// TargetSpecificAttr records.
static void GenerateTargetSpecificAttrChecks(const Record *R,
- std::vector<std::string> &Arches,
+ std::vector<StringRef> &Arches,
std::string &Test,
std::string *FnName) {
// It is assumed that there will be an llvm::Triple object
@@ -2196,8 +2638,9 @@ static void GenerateTargetSpecificAttrChecks(const Record *R,
Test += "(";
for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) {
- std::string Part = *I;
- Test += "T.getArch() == llvm::Triple::" + Part;
+ StringRef Part = *I;
+ Test += "T.getArch() == llvm::Triple::";
+ Test += Part;
if (I + 1 != E)
Test += " || ";
if (FnName)
@@ -2210,11 +2653,12 @@ static void GenerateTargetSpecificAttrChecks(const Record *R,
// We know that there was at least one arch test, so we need to and in the
// OS tests.
Test += " && (";
- std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes");
+ std::vector<StringRef> OSes = R->getValueAsListOfStrings("OSes");
for (auto I = OSes.begin(), E = OSes.end(); I != E; ++I) {
- std::string Part = *I;
+ StringRef Part = *I;
- Test += "T.getOS() == llvm::Triple::" + Part;
+ Test += "T.getOS() == llvm::Triple::";
+ Test += Part;
if (I + 1 != E)
Test += " || ";
if (FnName)
@@ -2226,10 +2670,11 @@ static void GenerateTargetSpecificAttrChecks(const Record *R,
// If one or more CXX ABIs are specified, check those as well.
if (!R->isValueUnset("CXXABIs")) {
Test += " && (";
- std::vector<std::string> CXXABIs = R->getValueAsListOfStrings("CXXABIs");
+ std::vector<StringRef> CXXABIs = R->getValueAsListOfStrings("CXXABIs");
for (auto I = CXXABIs.begin(), E = CXXABIs.end(); I != E; ++I) {
- std::string Part = *I;
- Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part;
+ StringRef Part = *I;
+ Test += "Target.getCXXABI().getKind() == TargetCXXABI::";
+ Test += Part;
if (I + 1 != E)
Test += " || ";
if (FnName)
@@ -2267,16 +2712,20 @@ static void GenerateHasAttrSpellingStringSwitch(
std::string Test;
if (Attr->isSubClassOf("TargetSpecificAttr")) {
const Record *R = Attr->getValueAsDef("Target");
- std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
+ std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches");
GenerateTargetSpecificAttrChecks(R, Arches, Test, nullptr);
// If this is the C++11 variety, also add in the LangOpts test.
if (Variety == "CXX11")
Test += " && LangOpts.CPlusPlus11";
+ else if (Variety == "C2x")
+ Test += " && LangOpts.DoubleSquareBracketAttributes";
} else if (Variety == "CXX11")
// C++11 mode should be checked against LangOpts, which is presumed to be
// present in the caller.
Test = "LangOpts.CPlusPlus11";
+ else if (Variety == "C2x")
+ Test = "LangOpts.DoubleSquareBracketAttributes";
std::string TestStr =
!Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1";
@@ -2297,7 +2746,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// and declspecs. Then generate a big switch statement for each of them.
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<Record *> Declspec, Microsoft, GNU, Pragma;
- std::map<std::string, std::vector<Record *>> CXX;
+ std::map<std::string, std::vector<Record *>> CXX, C2x;
// Walk over the list of all attributes, and split them out based on the
// spelling variety.
@@ -2313,6 +2762,8 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
Microsoft.push_back(R);
else if (Variety == "CXX11")
CXX[SI.nameSpace()].push_back(R);
+ else if (Variety == "C2x")
+ C2x[SI.nameSpace()].push_back(R);
else if (Variety == "Pragma")
Pragma.push_back(R);
}
@@ -2332,20 +2783,25 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "case AttrSyntax::Pragma:\n";
OS << " return llvm::StringSwitch<int>(Name)\n";
GenerateHasAttrSpellingStringSwitch(Pragma, OS, "Pragma");
- OS << "case AttrSyntax::CXX: {\n";
- // C++11-style attributes are further split out based on the Scope.
- for (auto I = CXX.cbegin(), E = CXX.cend(); I != E; ++I) {
- if (I != CXX.begin())
- OS << " else ";
- if (I->first.empty())
- OS << "if (!Scope || Scope->getName() == \"\") {\n";
- else
- OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
- OS << " return llvm::StringSwitch<int>(Name)\n";
- GenerateHasAttrSpellingStringSwitch(I->second, OS, "CXX11", I->first);
- OS << "}";
- }
- OS << "\n}\n";
+ auto fn = [&OS](const char *Spelling, const char *Variety,
+ const std::map<std::string, std::vector<Record *>> &List) {
+ OS << "case AttrSyntax::" << Variety << ": {\n";
+ // C++11-style attributes are further split out based on the Scope.
+ for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) {
+ if (I != List.cbegin())
+ OS << " else ";
+ if (I->first.empty())
+ OS << "if (!Scope || Scope->getName() == \"\") {\n";
+ else
+ OS << "if (Scope->getName() == \"" << I->first << "\") {\n";
+ OS << " return llvm::StringSwitch<int>(Name)\n";
+ GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first);
+ OS << "}";
+ }
+ OS << "\n} break;\n";
+ };
+ fn("CXX11", "CXX", CXX);
+ fn("C2x", "C", C2x);
OS << "}\n";
}
@@ -2366,10 +2822,11 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
<< StringSwitch<unsigned>(Spellings[I].variety())
.Case("GNU", 0)
.Case("CXX11", 1)
- .Case("Declspec", 2)
- .Case("Microsoft", 3)
- .Case("Keyword", 4)
- .Case("Pragma", 5)
+ .Case("C2x", 2)
+ .Case("Declspec", 3)
+ .Case("Microsoft", 4)
+ .Case("Keyword", 5)
+ .Case("Pragma", 6)
.Default(0)
<< " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
<< " return " << I << ";\n";
@@ -2451,26 +2908,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 +2957,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";
}
@@ -2531,7 +3000,7 @@ static bool isArgVariadic(const Record &R, StringRef AttrName) {
return createArgument(R, AttrName)->isVariadic();
}
-static void emitArgInfo(const Record &R, std::stringstream &OS) {
+static void emitArgInfo(const Record &R, raw_ostream &OS) {
// This function will count the number of arguments specified for the
// attribute and emit the number of required arguments followed by the
// number of optional arguments.
@@ -2563,7 +3032,7 @@ static void GenerateDefaultAppertainsTo(raw_ostream &OS) {
static std::string CalculateDiagnostic(const Record &S) {
// If the SubjectList object has a custom diagnostic associated with it,
// return that directly.
- std::string CustomDiag = S.getValueAsString("CustomDiag");
+ const StringRef CustomDiag = S.getValueAsString("CustomDiag");
if (!CustomDiag.empty())
return CustomDiag;
@@ -2584,7 +3053,8 @@ static std::string CalculateDiagnostic(const Record &S) {
Field = 1U << 12,
CXXMethod = 1U << 13,
ObjCProtocol = 1U << 14,
- Enum = 1U << 15
+ Enum = 1U << 15,
+ Named = 1U << 16,
};
uint32_t SubMask = 0;
@@ -2619,6 +3089,7 @@ static std::string CalculateDiagnostic(const Record &S) {
.Case("Field", Field)
.Case("CXXMethod", CXXMethod)
.Case("Enum", Enum)
+ .Case("Named", Named)
.Default(0);
if (!V) {
// Something wasn't in our mapping, so be helpful and let the developer
@@ -2674,9 +3145,14 @@ static std::string CalculateDiagnostic(const Record &S) {
" : ExpectedVariableOrFunction))";
case ObjCMethod | ObjCProp: return "ExpectedMethodOrProperty";
+ case Func | ObjCMethod | ObjCProp:
+ return "ExpectedFunctionOrMethodOrProperty";
case ObjCProtocol | ObjCInterface:
return "ExpectedObjectiveCInterfaceOrProtocol";
case Field | Var: return "ExpectedFieldOrGlobalVar";
+
+ case Named:
+ return "ExpectedNamedDecl";
}
PrintFatalError(S.getLoc(),
@@ -2692,9 +3168,13 @@ static std::string GetSubjectWithSuffix(const Record *R) {
return B + "Decl";
}
+static std::string functionNameForCustomAppertainsTo(const Record &Subject) {
+ return "is" + Subject.getName().str();
+}
+
static std::string GenerateCustomAppertainsTo(const Record &Subject,
raw_ostream &OS) {
- std::string FnName = "is" + Subject.getName().str();
+ std::string FnName = functionNameForCustomAppertainsTo(Subject);
// If this code has already been generated, simply return the previous
// instance of it.
@@ -2779,6 +3259,42 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
return FnName;
}
+static void
+emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport,
+ raw_ostream &OS) {
+ OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, "
+ << AttributeSubjectMatchRule::EnumName << " rule) {\n";
+ OS << " switch (rule) {\n";
+ for (const auto &Rule : PragmaAttributeSupport.Rules) {
+ if (Rule.isAbstractRule()) {
+ OS << " case " << Rule.getEnumValue() << ":\n";
+ OS << " assert(false && \"Abstract matcher rule isn't allowed\");\n";
+ OS << " return false;\n";
+ continue;
+ }
+ std::vector<Record *> Subjects = Rule.getSubjects();
+ assert(!Subjects.empty() && "Missing subjects");
+ OS << " case " << Rule.getEnumValue() << ":\n";
+ OS << " return ";
+ for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) {
+ // If the subject has custom code associated with it, use the function
+ // that was generated for GenerateAppertainsTo to check if the declaration
+ // is valid.
+ if ((*I)->isSubClassOf("SubsetSubject"))
+ OS << functionNameForCustomAppertainsTo(**I) << "(D)";
+ else
+ OS << "isa<" << GetSubjectWithSuffix(*I) << ">(D)";
+
+ if (I + 1 != E)
+ OS << " || ";
+ }
+ OS << ";\n";
+ }
+ OS << " }\n";
+ OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n";
+ OS << "}\n\n";
+}
+
static void GenerateDefaultLangOptRequirements(raw_ostream &OS) {
OS << "static bool defaultDiagnoseLangOpts(Sema &, ";
OS << "const AttributeList &) {\n";
@@ -2800,12 +3316,13 @@ static std::string GenerateLangOptRequirements(const Record &R,
// codegen efficiency).
std::string FnName = "check", Test;
for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
- std::string Part = (*I)->getValueAsString("Name");
+ const StringRef Part = (*I)->getValueAsString("Name");
if ((*I)->getValueAsBit("Negated")) {
FnName += "Not";
Test += "!";
}
- Test += "S.LangOpts." + Part;
+ Test += "S.LangOpts.";
+ Test += Part;
if (I + 1 != E)
Test += " || ";
FnName += Part;
@@ -2847,7 +3364,7 @@ static std::string GenerateTargetRequirements(const Record &Attr,
// Get the list of architectures to be tested for.
const Record *R = Attr.getValueAsDef("Target");
- std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
+ std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches");
if (Arches.empty()) {
PrintError(Attr.getLoc(), "Empty list of target architectures for a "
"target-specific attr");
@@ -2861,12 +3378,13 @@ static std::string GenerateTargetRequirements(const Record &Attr,
// applies to multiple target architectures. In order for the attribute to be
// considered valid, all of its architectures need to be included.
if (!Attr.isValueUnset("ParseKind")) {
- std::string APK = Attr.getValueAsString("ParseKind");
+ const StringRef APK = Attr.getValueAsString("ParseKind");
for (const auto &I : Dupes) {
if (I.first == APK) {
- std::vector<std::string> DA = I.second->getValueAsDef("Target")
- ->getValueAsListOfStrings("Arches");
- std::move(DA.begin(), DA.end(), std::back_inserter(Arches));
+ std::vector<StringRef> DA =
+ I.second->getValueAsDef("Target")->getValueAsListOfStrings(
+ "Arches");
+ Arches.insert(Arches.end(), DA.begin(), DA.end());
}
}
}
@@ -2937,6 +3455,9 @@ static bool IsKnownToGCC(const Record &Attr) {
void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Parsed attribute helpers", OS);
+ PragmaClangAttributeSupport &PragmaAttributeSupport =
+ getPragmaAttributeSupport(Records);
+
// Get the list of parsed attributes, and accept the optional list of
// duplicates due to the ParseKind.
ParsedAttrMap Dupes;
@@ -2953,7 +3474,8 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
// another mapping. At the same time, generate the AttrInfoMap object
// contents. Due to the reliance on generated code, use separate streams so
// that code will not be interleaved.
- std::stringstream SS;
+ std::string Buffer;
+ raw_string_ostream SS {Buffer};
for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
// TODO: If the attribute's kind appears in the list of duplicates, that is
// because it is a target-specific attribute that appears multiple times.
@@ -2970,10 +3492,13 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
SS << ", " << I->second->isSubClassOf("TypeAttr");
SS << ", " << I->second->isSubClassOf("StmtAttr");
SS << ", " << IsKnownToGCC(*I->second);
+ SS << ", " << PragmaAttributeSupport.isAttributedSupported(*I->second);
SS << ", " << GenerateAppertainsTo(*I->second, OS);
SS << ", " << GenerateLangOptRequirements(*I->second, OS);
SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS);
SS << ", " << GenerateSpellingIndexToSemanticSpelling(*I->second, OS);
+ SS << ", "
+ << PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS);
SS << " }";
if (I + 1 != E)
@@ -2985,6 +3510,9 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n";
OS << SS.str();
OS << "};\n\n";
+
+ // Generate the attribute match rules.
+ emitAttributeMatchRules(PragmaAttributeSupport, OS);
}
// Emits the kind list of parsed attributes
@@ -2993,7 +3521,7 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<StringMatcher::StringPair> GNU, Declspec, Microsoft, CXX11,
- Keywords, Pragma;
+ Keywords, Pragma, C2x;
std::set<std::string> Seen;
for (const auto *A : Attrs) {
const Record &Attr = *A;
@@ -3031,6 +3559,10 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
Matches = &CXX11;
Spelling += S.nameSpace();
Spelling += "::";
+ } else if (Variety == "C2x") {
+ Matches = &C2x;
+ Spelling += S.nameSpace();
+ Spelling += "::";
} else if (Variety == "GNU")
Matches = &GNU;
else if (Variety == "Declspec")
@@ -3069,6 +3601,8 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
StringMatcher("Name", Microsoft, OS).Emit();
OS << " } else if (AttributeList::AS_CXX11 == Syntax) {\n";
StringMatcher("Name", CXX11, OS).Emit();
+ OS << " } else if (AttributeList::AS_C2x == Syntax) {\n";
+ StringMatcher("Name", C2x, OS).Emit();
OS << " } else if (AttributeList::AS_Keyword == Syntax || ";
OS << "AttributeList::AS_ContextSensitiveKeyword == Syntax) {\n";
StringMatcher("Name", Keywords, OS).Emit();
@@ -3124,24 +3658,34 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records,
emitClangAttrLateParsedList(Records, OS);
}
+void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
+ raw_ostream &OS) {
+ getPragmaAttributeSupport(Records).generateParsingHelpers(OS);
+}
+
class DocumentationData {
public:
const Record *Documentation;
const Record *Attribute;
-
- DocumentationData(const Record &Documentation, const Record &Attribute)
- : Documentation(&Documentation), Attribute(&Attribute) {}
+ std::string Heading;
+ unsigned SupportedSpellings;
+
+ DocumentationData(const Record &Documentation, const Record &Attribute,
+ const std::pair<std::string, unsigned> HeadingAndKinds)
+ : Documentation(&Documentation), Attribute(&Attribute),
+ Heading(std::move(HeadingAndKinds.first)),
+ SupportedSpellings(HeadingAndKinds.second) {}
};
static void WriteCategoryHeader(const Record *DocCategory,
raw_ostream &OS) {
- const std::string &Name = DocCategory->getValueAsString("Name");
- OS << Name << "\n" << std::string(Name.length(), '=') << "\n";
+ const StringRef Name = DocCategory->getValueAsString("Name");
+ OS << Name << "\n" << std::string(Name.size(), '=') << "\n";
// If there is content, print that as well.
- std::string ContentStr = DocCategory->getValueAsString("Content");
+ const StringRef ContentStr = DocCategory->getValueAsString("Content");
// Trim leading and trailing newlines and spaces.
- OS << StringRef(ContentStr).trim();
+ OS << ContentStr.trim();
OS << "\n\n";
}
@@ -3149,22 +3693,24 @@ static void WriteCategoryHeader(const Record *DocCategory,
enum SpellingKind {
GNU = 1 << 0,
CXX11 = 1 << 1,
- Declspec = 1 << 2,
- Microsoft = 1 << 3,
- Keyword = 1 << 4,
- Pragma = 1 << 5
+ C2x = 1 << 2,
+ Declspec = 1 << 3,
+ Microsoft = 1 << 4,
+ Keyword = 1 << 5,
+ Pragma = 1 << 6
};
-static void WriteDocumentation(const DocumentationData &Doc,
- raw_ostream &OS) {
+static std::pair<std::string, unsigned>
+GetAttributeHeadingAndSpellingKinds(const Record &Documentation,
+ const Record &Attribute) {
// FIXME: there is no way to have a per-spelling category for the attribute
// documentation. This may not be a limiting factor since the spellings
// should generally be consistently applied across the category.
- std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Doc.Attribute);
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute);
// Determine the heading to be used for this attribute.
- std::string Heading = Doc.Documentation->getValueAsString("Heading");
+ std::string Heading = Documentation.getValueAsString("Heading");
bool CustomHeading = !Heading.empty();
if (Heading.empty()) {
// If there's only one spelling, we can simply use that.
@@ -3186,7 +3732,7 @@ static void WriteDocumentation(const DocumentationData &Doc,
// If the heading is still empty, it is an error.
if (Heading.empty())
- PrintFatalError(Doc.Attribute->getLoc(),
+ PrintFatalError(Attribute.getLoc(),
"This attribute requires a heading to be specified");
// Gather a list of unique spellings; this is not the same as the semantic
@@ -3199,6 +3745,7 @@ static void WriteDocumentation(const DocumentationData &Doc,
SpellingKind Kind = StringSwitch<SpellingKind>(I.variety())
.Case("GNU", GNU)
.Case("CXX11", CXX11)
+ .Case("C2x", C2x)
.Case("Declspec", Declspec)
.Case("Microsoft", Microsoft)
.Case("Keyword", Keyword)
@@ -3208,7 +3755,7 @@ static void WriteDocumentation(const DocumentationData &Doc,
SupportedSpellings |= Kind;
std::string Name;
- if (Kind == CXX11 && !I.nameSpace().empty())
+ if ((Kind == CXX11 || Kind == C2x) && !I.nameSpace().empty())
Name = I.nameSpace() + "::";
Name += I.name();
@@ -3228,27 +3775,36 @@ static void WriteDocumentation(const DocumentationData &Doc,
}
Heading += ")";
}
- OS << Heading << "\n" << std::string(Heading.length(), '-') << "\n";
-
if (!SupportedSpellings)
- PrintFatalError(Doc.Attribute->getLoc(),
+ PrintFatalError(Attribute.getLoc(),
"Attribute has no supported spellings; cannot be "
"documented");
+ return std::make_pair(std::move(Heading), SupportedSpellings);
+}
+
+static void WriteDocumentation(RecordKeeper &Records,
+ const DocumentationData &Doc, raw_ostream &OS) {
+ OS << Doc.Heading << "\n" << std::string(Doc.Heading.length(), '-') << "\n";
// List what spelling syntaxes the attribute supports.
OS << ".. csv-table:: Supported Syntaxes\n";
- OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\",";
- OS << " \"Pragma\"\n\n";
+ OS << " :header: \"GNU\", \"C++11\", \"C2x\", \"__declspec\", \"Keyword\",";
+ OS << " \"Pragma\", \"Pragma clang attribute\"\n\n";
OS << " \"";
- if (SupportedSpellings & GNU) OS << "X";
+ if (Doc.SupportedSpellings & GNU) OS << "X";
+ OS << "\",\"";
+ if (Doc.SupportedSpellings & CXX11) OS << "X";
OS << "\",\"";
- if (SupportedSpellings & CXX11) OS << "X";
+ if (Doc.SupportedSpellings & C2x) OS << "X";
OS << "\",\"";
- if (SupportedSpellings & Declspec) OS << "X";
+ if (Doc.SupportedSpellings & Declspec) OS << "X";
OS << "\",\"";
- if (SupportedSpellings & Keyword) OS << "X";
+ if (Doc.SupportedSpellings & Keyword) OS << "X";
+ OS << "\", \"";
+ if (Doc.SupportedSpellings & Pragma) OS << "X";
OS << "\", \"";
- if (SupportedSpellings & Pragma) OS << "X";
+ if (getPragmaAttributeSupport(Records).isAttributedSupported(*Doc.Attribute))
+ OS << "X";
OS << "\"\n\n";
// If the attribute is deprecated, print a message about it, and possibly
@@ -3257,16 +3813,16 @@ static void WriteDocumentation(const DocumentationData &Doc,
OS << "This attribute has been deprecated, and may be removed in a future "
<< "version of Clang.";
const Record &Deprecated = *Doc.Documentation->getValueAsDef("Deprecated");
- std::string Replacement = Deprecated.getValueAsString("Replacement");
+ const StringRef Replacement = Deprecated.getValueAsString("Replacement");
if (!Replacement.empty())
OS << " This attribute has been superseded by ``"
<< Replacement << "``.";
OS << "\n\n";
}
- std::string ContentStr = Doc.Documentation->getValueAsString("Content");
+ const StringRef ContentStr = Doc.Documentation->getValueAsString("Content");
// Trim leading and trailing newlines and spaces.
- OS << StringRef(ContentStr).trim();
+ OS << ContentStr.trim();
OS << "\n\n\n";
}
@@ -3295,27 +3851,76 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
// If the category is "undocumented", then there cannot be any other
// documentation categories (otherwise, the attribute would become
// documented).
- std::string Cat = Category->getValueAsString("Name");
+ const StringRef Cat = Category->getValueAsString("Name");
bool Undocumented = Cat == "Undocumented";
if (Undocumented && Docs.size() > 1)
PrintFatalError(Doc.getLoc(),
"Attribute is \"Undocumented\", but has multiple "
- "documentation categories");
+ "documentation categories");
if (!Undocumented)
- SplitDocs[Category].push_back(DocumentationData(Doc, Attr));
+ SplitDocs[Category].push_back(DocumentationData(
+ Doc, Attr, GetAttributeHeadingAndSpellingKinds(Doc, Attr)));
}
}
// Having split the attributes out based on what documentation goes where,
// we can begin to generate sections of documentation.
- for (const auto &I : SplitDocs) {
+ for (auto &I : SplitDocs) {
WriteCategoryHeader(I.first, OS);
+ std::sort(I.second.begin(), I.second.end(),
+ [](const DocumentationData &D1, const DocumentationData &D2) {
+ return D1.Heading < D2.Heading;
+ });
+
// Walk over each of the attributes in the category and write out their
// documentation.
for (const auto &Doc : I.second)
- WriteDocumentation(Doc, OS);
+ WriteDocumentation(Records, Doc, OS);
+ }
+}
+
+void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
+ raw_ostream &OS) {
+ PragmaClangAttributeSupport Support = getPragmaAttributeSupport(Records);
+ ParsedAttrMap Attrs = getParsedAttrList(Records);
+ unsigned NumAttrs = 0;
+ for (const auto &I : Attrs) {
+ if (Support.isAttributedSupported(*I.second))
+ ++NumAttrs;
+ }
+ OS << "#pragma clang attribute supports " << NumAttrs << " attributes:\n";
+ for (const auto &I : Attrs) {
+ if (!Support.isAttributedSupported(*I.second))
+ continue;
+ OS << I.first;
+ if (I.second->isValueUnset("Subjects")) {
+ OS << " ()\n";
+ continue;
+ }
+ const Record *SubjectObj = I.second->getValueAsDef("Subjects");
+ std::vector<Record *> Subjects =
+ SubjectObj->getValueAsListOfDefs("Subjects");
+ OS << " (";
+ for (const auto &Subject : llvm::enumerate(Subjects)) {
+ if (Subject.index())
+ OS << ", ";
+ PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet =
+ Support.SubjectsToRules.find(Subject.value())->getSecond();
+ if (RuleSet.isRule()) {
+ OS << RuleSet.getRule().getEnumValueName();
+ continue;
+ }
+ OS << "(";
+ for (const auto &Rule : llvm::enumerate(RuleSet.getAggregateRuleSet())) {
+ if (Rule.index())
+ OS << ", ";
+ OS << Rule.value().getEnumValueName();
+ }
+ OS << ")";
+ }
+ OS << ")\n";
}
}
diff --git a/utils/TableGen/ClangDataCollectorsEmitter.cpp b/utils/TableGen/ClangDataCollectorsEmitter.cpp
new file mode 100644
index 0000000000..4079efc808
--- /dev/null
+++ b/utils/TableGen/ClangDataCollectorsEmitter.cpp
@@ -0,0 +1,18 @@
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+
+using namespace llvm;
+
+namespace clang {
+void EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) {
+ const auto &Defs = RK.getClasses();
+ for (const auto &Entry : Defs) {
+ Record &R = *Entry.second;
+ OS << "DEF_ADD_DATA(" << R.getName() << ", {\n";
+ auto Code = R.getValue("Code")->getValue();
+ OS << Code->getAsUnquotedString() << "}\n)";
+ OS << "\n";
+ }
+ OS << "#undef DEF_ADD_DATA\n";
+}
+} // end namespace clang
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index cad08afd84..d9d99e0bb0 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -1277,8 +1277,8 @@ void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
GroupInfo.SubGroups.size() == 1;
- writeHeader((IsRemarkGroup ? "-R" : "-W") +
- G->getValueAsString("GroupName"),
+ writeHeader(((IsRemarkGroup ? "-R" : "-W") +
+ G->getValueAsString("GroupName")).str(),
OS);
if (!IsSynonym) {
diff --git a/utils/TableGen/ClangOptionDocEmitter.cpp b/utils/TableGen/ClangOptionDocEmitter.cpp
index aa7502e2c8..59314510e0 100644
--- a/utils/TableGen/ClangOptionDocEmitter.cpp
+++ b/utils/TableGen/ClangOptionDocEmitter.cpp
@@ -83,7 +83,7 @@ Documentation extractDocumentation(RecordKeeper &Records) {
}
// Pretend no-X and Xno-Y options are aliases of X and XY.
- auto Name = R->getValueAsString("Name");
+ std::string Name = R->getValueAsString("Name");
if (Name.size() >= 4) {
if (Name.substr(0, 3) == "no-" && OptionsByName[Name.substr(3)]) {
Aliases[OptionsByName[Name.substr(3)]].push_back(R);
@@ -229,7 +229,7 @@ std::string getRSTStringWithTextFallback(const Record *R, StringRef Primary,
}
void emitOptionWithArgs(StringRef Prefix, const Record *Option,
- ArrayRef<std::string> Args, raw_ostream &OS) {
+ ArrayRef<StringRef> Args, raw_ostream &OS) {
OS << Prefix << escapeRST(Option->getValueAsString("Name"));
std::pair<StringRef, StringRef> Separators =
@@ -261,14 +261,15 @@ void emitOptionName(StringRef Prefix, const Record *Option, raw_ostream &OS) {
}
}
- emitOptionWithArgs(Prefix, Option, Args, OS);
+ emitOptionWithArgs(Prefix, Option, std::vector<StringRef>(Args.begin(), Args.end()), OS);
auto AliasArgs = Option->getValueAsListOfStrings("AliasArgs");
if (!AliasArgs.empty()) {
Record *Alias = Option->getValueAsDef("Alias");
OS << " (equivalent to ";
- emitOptionWithArgs(Alias->getValueAsListOfStrings("Prefixes").front(),
- Alias, Option->getValueAsListOfStrings("AliasArgs"), OS);
+ emitOptionWithArgs(
+ Alias->getValueAsListOfStrings("Prefixes").front(), Alias,
+ AliasArgs, OS);
OS << ")";
}
}
@@ -310,7 +311,7 @@ void emitOption(const DocumentedOption &Option, const Record *DocInfo,
forEachOptionName(Option, DocInfo, [&](const Record *Option) {
for (auto &Prefix : Option->getValueAsListOfStrings("Prefixes"))
SphinxOptionIDs.push_back(
- getSphinxOptionID(Prefix + Option->getValueAsString("Name")));
+ getSphinxOptionID((Prefix + Option->getValueAsString("Name")).str()));
});
assert(!SphinxOptionIDs.empty() && "no flags for option");
static std::map<std::string, int> NextSuffix;
diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp
index 115527ae33..8f3de0b67d 100644
--- a/utils/TableGen/ClangSACheckersEmitter.cpp
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -51,7 +51,8 @@ static std::string getParentPackageFullName(const Record *R) {
static std::string getPackageFullName(const Record *R) {
std::string name = getParentPackageFullName(R);
if (!name.empty()) name += ".";
- return name + R->getValueAsString("PackageName");
+ name += R->getValueAsString("PackageName");
+ return name;
}
static std::string getCheckerFullName(const Record *R) {
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index fd7999be38..840b330a73 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -25,8 +25,10 @@ using namespace clang;
enum ActionType {
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
+ GenClangAttrSubjectMatchRulesParserStringSwitches,
GenClangAttrImpl,
GenClangAttrList,
+ GenClangAttrSubjectMatchRuleList,
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
GenClangAttrHasAttributeImpl,
@@ -54,7 +56,9 @@ enum ActionType {
GenArmNeonTest,
GenAttrDocs,
GenDiagDocs,
- GenOptDocs
+ GenOptDocs,
+ GenDataCollectors,
+ GenTestPragmaAttributeSupportedAttributes
};
namespace {
@@ -66,10 +70,17 @@ cl::opt<ActionType> Action(
clEnumValN(GenClangAttrParserStringSwitches,
"gen-clang-attr-parser-string-switches",
"Generate all parser-related attribute string switches"),
+ clEnumValN(GenClangAttrSubjectMatchRulesParserStringSwitches,
+ "gen-clang-attr-subject-match-rules-parser-string-switches",
+ "Generate all parser-related attribute subject match rule"
+ "string switches"),
clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
"Generate clang attribute implementations"),
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
"Generate a clang attribute list"),
+ clEnumValN(GenClangAttrSubjectMatchRuleList,
+ "gen-clang-attr-subject-match-rule-list",
+ "Generate a clang attribute subject match rule list"),
clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read",
"Generate clang PCH attribute reader"),
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
@@ -80,8 +91,7 @@ cl::opt<ActionType> Action(
clEnumValN(GenClangAttrSpellingListIndex,
"gen-clang-attr-spelling-index",
"Generate a clang attribute spelling index"),
- clEnumValN(GenClangAttrASTVisitor,
- "gen-clang-attr-ast-visitor",
+ clEnumValN(GenClangAttrASTVisitor, "gen-clang-attr-ast-visitor",
"Generate a recursive AST visitor for clang attributes"),
clEnumValN(GenClangAttrTemplateInstantiate,
"gen-clang-attr-template-instantiate",
@@ -137,8 +147,13 @@ cl::opt<ActionType> Action(
"Generate attribute documentation"),
clEnumValN(GenDiagDocs, "gen-diag-docs",
"Generate diagnostic documentation"),
- clEnumValN(GenOptDocs, "gen-opt-docs",
- "Generate option documentation")));
+ clEnumValN(GenOptDocs, "gen-opt-docs", "Generate option documentation"),
+ clEnumValN(GenDataCollectors, "gen-clang-data-collectors",
+ "Generate data collectors for AST nodes"),
+ clEnumValN(GenTestPragmaAttributeSupportedAttributes,
+ "gen-clang-test-pragma-attribute-supported-attributes",
+ "Generate a list of attributes supported by #pragma clang "
+ "attribute for testing purposes")));
cl::opt<std::string>
ClangComponent("clang-component",
@@ -153,12 +168,18 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrParserStringSwitches:
EmitClangAttrParserStringSwitches(Records, OS);
break;
+ case GenClangAttrSubjectMatchRulesParserStringSwitches:
+ EmitClangAttrSubjectMatchRulesParserStringSwitches(Records, OS);
+ break;
case GenClangAttrImpl:
EmitClangAttrImpl(Records, OS);
break;
case GenClangAttrList:
EmitClangAttrList(Records, OS);
break;
+ case GenClangAttrSubjectMatchRuleList:
+ EmitClangAttrSubjectMatchRuleList(Records, OS);
+ break;
case GenClangAttrPCHRead:
EmitClangAttrPCHRead(Records, OS);
break;
@@ -244,6 +265,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenOptDocs:
EmitClangOptDocs(Records, OS);
break;
+ case GenDataCollectors:
+ EmitClangDataCollectors(Records, OS);
+ break;
+ case GenTestPragmaAttributeSupportedAttributes:
+ EmitTestPragmaAttributeSupportedAttributes(Records, OS);
+ break;
}
return false;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 033cb78f36..342c889ca4 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -33,9 +33,12 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
const std::string &N, const std::string &S);
void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
+ raw_ostream &OS);
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS);
@@ -72,6 +75,11 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangDataCollectors(RecordKeeper &Records, raw_ostream &OS);
+
+void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
+ raw_ostream &OS);
+
} // end namespace clang
#endif
diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py
index 2d1f44f688..2c0ed6aae3 100755
--- a/utils/analyzer/CmpRuns.py
+++ b/utils/analyzer/CmpRuns.py
@@ -6,8 +6,8 @@ which reports have been added, removed, or changed.
This is designed to support automated testing using the static analyzer, from
two perspectives:
- 1. To monitor changes in the static analyzer's reports on real code bases, for
- regression testing.
+ 1. To monitor changes in the static analyzer's reports on real code bases,
+ for regression testing.
2. For use by end users who want to integrate regular static analyzer testing
into a buildbot like environment.
@@ -28,7 +28,7 @@ Usage:
import os
import plistlib
-import CmpRuns
+
# Information about analysis run:
# path - the analysis output directory
@@ -40,6 +40,7 @@ class SingleRunInfo:
self.root = root.rstrip("/\\")
self.verboseLog = verboseLog
+
class AnalysisDiagnostic:
def __init__(self, data, report, htmlReport):
self._data = data
@@ -51,7 +52,7 @@ class AnalysisDiagnostic:
root = self._report.run.root
fileName = self._report.files[self._loc['file']]
if fileName.startswith(root) and len(root) > 0:
- return fileName[len(root)+1:]
+ return fileName[len(root) + 1:]
return fileName
def getLine(self):
@@ -66,12 +67,12 @@ class AnalysisDiagnostic:
def getDescription(self):
return self._data['description']
- def getIssueIdentifier(self) :
+ def getIssueIdentifier(self):
id = self.getFileName() + "+"
- if 'issue_context' in self._data :
- id += self._data['issue_context'] + "+"
- if 'issue_hash_content_of_line_in_context' in self._data :
- id += str(self._data['issue_hash_content_of_line_in_context'])
+ if 'issue_context' in self._data:
+ id += self._data['issue_context'] + "+"
+ if 'issue_hash_content_of_line_in_context' in self._data:
+ id += str(self._data['issue_hash_content_of_line_in_context'])
return id
def getReport(self):
@@ -89,29 +90,6 @@ class AnalysisDiagnostic:
def getRawData(self):
return self._data
-class multidict:
- def __init__(self, elts=()):
- self.data = {}
- for key,value in elts:
- self[key] = value
-
- def __getitem__(self, item):
- return self.data[item]
- def __setitem__(self, key, value):
- if key in self.data:
- self.data[key].append(value)
- else:
- self.data[key] = [value]
- def items(self):
- return self.data.items()
- def values(self):
- return self.data.values()
- def keys(self):
- return self.data.keys()
- def __len__(self):
- return len(self.data)
- def get(self, key, default=None):
- return self.data.get(key, default)
class CmpOptions:
def __init__(self, verboseLog=None, rootA="", rootB=""):
@@ -119,12 +97,14 @@ class CmpOptions:
self.rootB = rootB
self.verboseLog = verboseLog
+
class AnalysisReport:
def __init__(self, run, files):
self.run = run
self.files = files
self.diagnostics = []
+
class AnalysisRun:
def __init__(self, info):
self.path = info.path
@@ -145,14 +125,14 @@ class AnalysisRun:
# reports. Assume that all reports were created using the same
# clang version (this is always true and is more efficient).
if 'clang_version' in data:
- if self.clang_version == None:
+ if self.clang_version is None:
self.clang_version = data.pop('clang_version')
else:
data.pop('clang_version')
# Ignore/delete empty reports.
if not data['files']:
- if deleteEmpty == True:
+ if deleteEmpty:
os.remove(p)
return
@@ -169,8 +149,7 @@ class AnalysisRun:
report = AnalysisReport(self, data.pop('files'))
diagnostics = [AnalysisDiagnostic(d, report, h)
- for d,h in zip(data.pop('diagnostics'),
- htmlFiles)]
+ for d, h in zip(data.pop('diagnostics'), htmlFiles)]
assert not data
@@ -179,15 +158,21 @@ class AnalysisRun:
self.diagnostics.extend(diagnostics)
-# Backward compatibility API.
-def loadResults(path, opts, root = "", deleteEmpty=True):
+def loadResults(path, opts, root="", deleteEmpty=True):
+ """
+ Backwards compatibility API.
+ """
return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog),
deleteEmpty)
-# Load results of the analyzes from a given output folder.
-# - info is the SingleRunInfo object
-# - deleteEmpty specifies if the empty plist files should be deleted
+
def loadResultsFromSingleRun(info, deleteEmpty=True):
+ """
+ # Load results of the analyzes from a given output folder.
+ # - info is the SingleRunInfo object
+ # - deleteEmpty specifies if the empty plist files should be deleted
+
+ """
path = info.path
run = AnalysisRun(info)
@@ -203,9 +188,11 @@ def loadResultsFromSingleRun(info, deleteEmpty=True):
return run
-def cmpAnalysisDiagnostic(d) :
+
+def cmpAnalysisDiagnostic(d):
return d.getIssueIdentifier()
+
def compareResults(A, B):
"""
compareResults - Generate a relation from diagnostics in run A to
@@ -224,12 +211,12 @@ def compareResults(A, B):
neqB = []
eltsA = list(A.diagnostics)
eltsB = list(B.diagnostics)
- eltsA.sort(key = cmpAnalysisDiagnostic)
- eltsB.sort(key = cmpAnalysisDiagnostic)
+ eltsA.sort(key=cmpAnalysisDiagnostic)
+ eltsB.sort(key=cmpAnalysisDiagnostic)
while eltsA and eltsB:
a = eltsA.pop()
b = eltsB.pop()
- if (a.getIssueIdentifier() == b.getIssueIdentifier()) :
+ if (a.getIssueIdentifier() == b.getIssueIdentifier()):
res.append((a, b, 0))
elif a.getIssueIdentifier() > b.getIssueIdentifier():
eltsB.append(b)
@@ -240,11 +227,11 @@ def compareResults(A, B):
neqA.extend(eltsA)
neqB.extend(eltsB)
- # FIXME: Add fuzzy matching. One simple and possible effective idea would be
- # to bin the diagnostics, print them in a normalized form (based solely on
- # the structure of the diagnostic), compute the diff, then use that as the
- # basis for matching. This has the nice property that we don't depend in any
- # way on the diagnostic format.
+ # FIXME: Add fuzzy matching. One simple and possible effective idea would
+ # be to bin the diagnostics, print them in a normalized form (based solely
+ # on the structure of the diagnostic), compute the diff, then use that as
+ # the basis for matching. This has the nice property that we don't depend
+ # in any way on the diagnostic format.
for a in neqA:
res.append((a, None, None))
@@ -253,6 +240,7 @@ def compareResults(A, B):
return res
+
def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
# Load the run results.
resultsA = loadResults(dirA, opts, opts.rootA, deleteEmpty)
@@ -267,7 +255,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
diff = compareResults(resultsA, resultsB)
foundDiffs = 0
for res in diff:
- a,b,confidence = res
+ a, b, confidence = res
if a is None:
print "ADDED: %r" % b.getReadableName()
foundDiffs += 1
@@ -302,6 +290,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
return foundDiffs, len(resultsA.diagnostics), len(resultsB.diagnostics)
+
def main():
from optparse import OptionParser
parser = OptionParser("usage: %prog [options] [dir A] [dir B]")
@@ -312,7 +301,8 @@ def main():
help="Prefix to ignore on source files for directory B",
action="store", type=str, default="")
parser.add_option("", "--verbose-log", dest="verboseLog",
- help="Write additional information to LOG [default=None]",
+ help="Write additional information to LOG \
+ [default=None]",
action="store", type=str, default=None,
metavar="LOG")
(opts, args) = parser.parse_args()
@@ -320,9 +310,10 @@ def main():
if len(args) != 2:
parser.error("invalid number of arguments")
- dirA,dirB = args
+ dirA, dirB = args
dumpScanBuildResultsDiff(dirA, dirB, opts)
+
if __name__ == '__main__':
main()
diff --git a/utils/analyzer/SATestAdd.py b/utils/analyzer/SATestAdd.py
index 4b94a109ce..4c3e35cdcb 100755
--- a/utils/analyzer/SATestAdd.py
+++ b/utils/analyzer/SATestAdd.py
@@ -27,15 +27,17 @@ the Repository Directory.
- CachedSource/ - An optional directory containing the source of the
project being analyzed. If present,
download_project.sh will not be called.
- - changes_for_analyzer.patch - An optional patch file for any local changes
+ - changes_for_analyzer.patch - An optional patch file for any local
+ changes
(e.g., to adapt to newer version of clang)
that should be applied to CachedSource
before analysis. To construct this patch,
run the the download script to download
the project to CachedSource, copy the
CachedSource to another directory (for
- example, PatchedSource) and make any needed
- modifications to the the copied source.
+ example, PatchedSource) and make any
+ needed modifications to the the copied
+ source.
Then run:
diff -ur CachedSource PatchedSource \
> changes_for_analyzer.patch
@@ -46,18 +48,21 @@ import os
import csv
import sys
-def isExistingProject(PMapFile, projectID) :
+
+def isExistingProject(PMapFile, projectID):
PMapReader = csv.reader(PMapFile)
for I in PMapReader:
if projectID == I[0]:
return True
return False
-# Add a new project for testing: build it and add to the Project Map file.
-# Params:
-# Dir is the directory where the sources are.
-# ID is a short string used to identify a project.
-def addNewProject(ID, BuildMode) :
+
+def addNewProject(ID, BuildMode):
+ """
+ Add a new project for testing: build it and add to the Project Map file.
+ :param ID: is a short string used to identify a project.
+ """
+
CurDir = os.path.abspath(os.curdir)
Dir = SATestBuild.getProjectDir(ID)
if not os.path.exists(Dir):
@@ -65,36 +70,37 @@ def addNewProject(ID, BuildMode) :
sys.exit(-1)
# Build the project.
- SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir)
+ SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True)
# Add the project ID to the project map.
ProjectMapPath = os.path.join(CurDir, SATestBuild.ProjectMapFile)
+
if os.path.exists(ProjectMapPath):
- PMapFile = open(ProjectMapPath, "r+b")
+ FileMode = "r+b"
else:
print "Warning: Creating the Project Map file!!"
- PMapFile = open(ProjectMapPath, "w+b")
- try:
- if (isExistingProject(PMapFile, ID)) :
+ FileMode = "w+b"
+
+ with open(ProjectMapPath, FileMode) as PMapFile:
+ if (isExistingProject(PMapFile, ID)):
print >> sys.stdout, 'Warning: Project with ID \'', ID, \
'\' already exists.'
print >> sys.stdout, "Reference output has been regenerated."
else:
PMapWriter = csv.writer(PMapFile)
- PMapWriter.writerow( (ID, int(BuildMode)) );
+ PMapWriter.writerow((ID, int(BuildMode)))
print "The project map is updated: ", ProjectMapPath
- finally:
- PMapFile.close()
# TODO: Add an option not to build.
# TODO: Set the path to the Repository directory.
if __name__ == '__main__':
- if len(sys.argv) < 2:
- print >> sys.stderr, 'Usage: ', sys.argv[0],\
- 'project_ID <mode>' \
- 'mode - 0 for single file project; ' \
- '1 for scan_build; ' \
+ if len(sys.argv) < 2 or sys.argv[1] in ('-h', '--help'):
+ print >> sys.stderr, 'Add a new project for testing to the analyzer'\
+ '\nUsage: ', sys.argv[0],\
+ 'project_ID <mode>\n' \
+ 'mode: 0 for single file project, ' \
+ '1 for scan_build, ' \
'2 for single file c++11 project'
sys.exit(-1)
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index 18c5393988..60c8796e33 100755
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -3,8 +3,8 @@
"""
Static Analyzer qualification infrastructure.
-The goal is to test the analyzer against different projects, check for failures,
-compare results, and measure performance.
+The goal is to test the analyzer against different projects,
+check for failures, compare results, and measure performance.
Repository Directory will contain sources of the projects as well as the
information on how to build them and the expected output.
@@ -20,7 +20,8 @@ Note that the build tree must be inside the project dir.
To test the build of the analyzer one would:
- Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that
- the build directory does not pollute the repository to min network traffic).
+ the build directory does not pollute the repository to min network
+ traffic).
- Build all projects, until error. Produce logs to report errors.
- Compare results.
@@ -42,6 +43,7 @@ For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment
variable. It should contain a comma separated list.
"""
import CmpRuns
+import SATestUtils
import os
import csv
@@ -52,103 +54,53 @@ import shutil
import time
import plistlib
import argparse
-from subprocess import check_call, check_output, CalledProcessError
+from subprocess import check_call, CalledProcessError
+import multiprocessing
#------------------------------------------------------------------------------
# Helper functions.
#------------------------------------------------------------------------------
-def detectCPUs():
- """
- Detects the number of CPUs on a system. Cribbed from pp.
- """
- # Linux, Unix and MacOS:
- if hasattr(os, "sysconf"):
- if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
- # Linux & Unix:
- ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
- if isinstance(ncpus, int) and ncpus > 0:
- return ncpus
- else: # OSX:
- return int(capture(['sysctl', '-n', 'hw.ncpu']))
- # Windows:
- if os.environ.has_key("NUMBER_OF_PROCESSORS"):
- ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
- if ncpus > 0:
- return ncpus
- return 1 # Default
-
-def which(command, paths = None):
- """which(command, [paths]) - Look up the given command in the paths string
- (or the PATH environment variable, if unspecified)."""
-
- if paths is None:
- paths = os.environ.get('PATH','')
-
- # Check for absolute match first.
- if os.path.exists(command):
- return command
-
- # Would be nice if Python had a lib function for this.
- if not paths:
- paths = os.defpath
-
- # Get suffixes to search.
- # On Cygwin, 'PATHEXT' may exist but it should not be used.
- if os.pathsep == ';':
- pathext = os.environ.get('PATHEXT', '').split(';')
- else:
- pathext = ['']
-
- # Search the paths...
- for path in paths.split(os.pathsep):
- for ext in pathext:
- p = os.path.join(path, command + ext)
- if os.path.exists(p):
- return p
-
- return None
-
-# Make sure we flush the output after every print statement.
-class flushfile(object):
- def __init__(self, f):
- self.f = f
- def write(self, x):
- self.f.write(x)
- self.f.flush()
-
-sys.stdout = flushfile(sys.stdout)
+
+sys.stdout = SATestUtils.flushfile(sys.stdout)
+
def getProjectMapPath():
ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
ProjectMapFile)
if not os.path.exists(ProjectMapPath):
print "Error: Cannot find the Project Map file " + ProjectMapPath +\
- "\nRunning script for the wrong directory?"
- sys.exit(-1)
+ "\nRunning script for the wrong directory?"
+ sys.exit(1)
return ProjectMapPath
+
def getProjectDir(ID):
return os.path.join(os.path.abspath(os.curdir), ID)
-def getSBOutputDirName(IsReferenceBuild) :
- if IsReferenceBuild == True :
+
+def getSBOutputDirName(IsReferenceBuild):
+ if IsReferenceBuild:
return SBOutputDirReferencePrefix + SBOutputDirName
- else :
+ else:
return SBOutputDirName
#------------------------------------------------------------------------------
# Configuration setup.
#------------------------------------------------------------------------------
+
# Find Clang for static analysis.
-Clang = which("clang", os.environ['PATH'])
+if 'CC' in os.environ:
+ Clang = os.environ['CC']
+else:
+ Clang = SATestUtils.which("clang", os.environ['PATH'])
if not Clang:
print "Error: cannot find 'clang' in PATH"
- sys.exit(-1)
+ sys.exit(1)
# Number of jobs.
-Jobs = int(math.ceil(detectCPUs() * 0.75))
+Jobs = int(math.ceil(multiprocessing.cpu_count() * 0.75))
# Project map stores info about all the "registered" projects.
ProjectMapFile = "projectMap.csv"
@@ -168,16 +120,15 @@ BuildLogName = "run_static_analyzer.log"
# displayed when buildbot detects a build failure.
NumOfFailuresInSummary = 10
FailuresSummaryFileName = "failures.txt"
-# Summary of the result diffs.
-DiffsSummaryFileName = "diffs.txt"
# The scan-build result directory.
SBOutputDirName = "ScanBuildResults"
SBOutputDirReferencePrefix = "Ref"
-# The name of the directory storing the cached project source. If this directory
-# does not exist, the download script will be executed. That script should
-# create the "CachedSource" directory and download the project source into it.
+# The name of the directory storing the cached project source. If this
+# directory does not exist, the download script will be executed.
+# That script should create the "CachedSource" directory and download the
+# project source into it.
CachedSourceDirName = "CachedSource"
# The name of the directory containing the source code that will be analyzed.
@@ -193,7 +144,18 @@ PatchfileName = "changes_for_analyzer.patch"
# The list of checkers used during analyzes.
# Currently, consists of all the non-experimental checkers, plus a few alpha
# checkers we don't want to regress on.
-Checkers="alpha.unix.SimpleStream,alpha.security.taint,cplusplus.NewDeleteLeaks,core,cplusplus,deadcode,security,unix,osx"
+Checkers = ",".join([
+ "alpha.unix.SimpleStream",
+ "alpha.security.taint",
+ "cplusplus.NewDeleteLeaks",
+ "core",
+ "cplusplus",
+ "deadcode",
+ "security",
+ "unix",
+ "osx",
+ "nullability"
+])
Verbose = 1
@@ -201,46 +163,38 @@ Verbose = 1
# Test harness logic.
#------------------------------------------------------------------------------
-# Run pre-processing script if any.
+
def runCleanupScript(Dir, PBuildLogFile):
+ """
+ Run pre-processing script if any.
+ """
Cwd = os.path.join(Dir, PatchedSourceDirName)
ScriptPath = os.path.join(Dir, CleanupScript)
- runScript(ScriptPath, PBuildLogFile, Cwd)
+ SATestUtils.runScript(ScriptPath, PBuildLogFile, Cwd)
+
-# Run the script to download the project, if it exists.
def runDownloadScript(Dir, PBuildLogFile):
+ """
+ Run the script to download the project, if it exists.
+ """
ScriptPath = os.path.join(Dir, DownloadScript)
- runScript(ScriptPath, PBuildLogFile, Dir)
+ SATestUtils.runScript(ScriptPath, PBuildLogFile, Dir)
+
-# Run the provided script if it exists.
-def runScript(ScriptPath, PBuildLogFile, Cwd):
- if os.path.exists(ScriptPath):
- try:
- if Verbose == 1:
- print " Executing: %s" % (ScriptPath,)
- check_call("chmod +x '%s'" % ScriptPath, cwd = Cwd,
- stderr=PBuildLogFile,
- stdout=PBuildLogFile,
- shell=True)
- check_call("'%s'" % ScriptPath, cwd = Cwd, stderr=PBuildLogFile,
- stdout=PBuildLogFile,
- shell=True)
- except:
- print "Error: Running %s failed. See %s for details." % (ScriptPath,
- PBuildLogFile.name)
- sys.exit(-1)
-
-# Download the project and apply the local patchfile if it exists.
def downloadAndPatch(Dir, PBuildLogFile):
+ """
+ Download the project and apply the local patchfile if it exists.
+ """
CachedSourceDirPath = os.path.join(Dir, CachedSourceDirName)
# If the we don't already have the cached source, run the project's
# download script to download it.
if not os.path.exists(CachedSourceDirPath):
- runDownloadScript(Dir, PBuildLogFile)
- if not os.path.exists(CachedSourceDirPath):
- print "Error: '%s' not found after download." % (CachedSourceDirPath)
- exit(-1)
+ runDownloadScript(Dir, PBuildLogFile)
+ if not os.path.exists(CachedSourceDirPath):
+ print "Error: '%s' not found after download." % (
+ CachedSourceDirPath)
+ exit(1)
PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName)
@@ -252,6 +206,7 @@ def downloadAndPatch(Dir, PBuildLogFile):
shutil.copytree(CachedSourceDirPath, PatchedSourceDirPath, symlinks=True)
applyPatch(Dir, PBuildLogFile)
+
def applyPatch(Dir, PBuildLogFile):
PatchfilePath = os.path.join(Dir, PatchfileName)
PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName)
@@ -262,30 +217,33 @@ def applyPatch(Dir, PBuildLogFile):
print " Applying patch."
try:
check_call("patch -p1 < '%s'" % (PatchfilePath),
- cwd = PatchedSourceDirPath,
- stderr=PBuildLogFile,
- stdout=PBuildLogFile,
- shell=True)
+ cwd=PatchedSourceDirPath,
+ stderr=PBuildLogFile,
+ stdout=PBuildLogFile,
+ shell=True)
except:
print "Error: Patch failed. See %s for details." % (PBuildLogFile.name)
- sys.exit(-1)
+ sys.exit(1)
+
-# Build the project with scan-build by reading in the commands and
-# prefixing them with the scan-build options.
def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
+ """
+ Build the project with scan-build by reading in the commands and
+ prefixing them with the scan-build options.
+ """
BuildScriptPath = os.path.join(Dir, BuildScript)
if not os.path.exists(BuildScriptPath):
print "Error: build script is not defined: %s" % BuildScriptPath
- sys.exit(-1)
+ sys.exit(1)
AllCheckers = Checkers
- if os.environ.has_key('SA_ADDITIONAL_CHECKERS'):
+ if 'SA_ADDITIONAL_CHECKERS' in os.environ:
AllCheckers = AllCheckers + ',' + os.environ['SA_ADDITIONAL_CHECKERS']
# Run scan-build from within the patched source directory.
SBCwd = os.path.join(Dir, PatchedSourceDirName)
- SBOptions = "--use-analyzer '%s' " % Clang
+ SBOptions = "--use-analyzer '%s' " % Clang
SBOptions += "-plist-html -o '%s' " % SBOutputDir
SBOptions += "-enable-checker " + AllCheckers + " "
SBOptions += "--keep-empty "
@@ -298,80 +256,63 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
for Command in SBCommandFile:
Command = Command.strip()
if len(Command) == 0:
- continue;
+ continue
# If using 'make', auto imply a -jX argument
# to speed up analysis. xcodebuild will
# automatically use the maximum number of cores.
if (Command.startswith("make ") or Command == "make") and \
- "-j" not in Command:
+ "-j" not in Command:
Command += " -j%d" % Jobs
SBCommand = SBPrefix + Command
if Verbose == 1:
print " Executing: %s" % (SBCommand,)
- check_call(SBCommand, cwd = SBCwd, stderr=PBuildLogFile,
- stdout=PBuildLogFile,
- shell=True)
- except:
- print "Error: scan-build failed. See ",PBuildLogFile.name,\
- " for details."
- raise
-
-def hasNoExtension(FileName):
- (Root, Ext) = os.path.splitext(FileName)
- if ((Ext == "")) :
- return True
- return False
-
-def isValidSingleInputFile(FileName):
- (Root, Ext) = os.path.splitext(FileName)
- if ((Ext == ".i") | (Ext == ".ii") |
- (Ext == ".c") | (Ext == ".cpp") |
- (Ext == ".m") | (Ext == "")) :
- return True
- return False
-
-# Get the path to the SDK for the given SDK name. Returns None if
-# the path cannot be determined.
-def getSDKPath(SDKName):
- if which("xcrun") is None:
- return None
-
- Cmd = "xcrun --sdk " + SDKName + " --show-sdk-path"
- return check_output(Cmd, shell=True).rstrip()
-
-# Run analysis on a set of preprocessed files.
+ check_call(SBCommand, cwd=SBCwd,
+ stderr=PBuildLogFile,
+ stdout=PBuildLogFile,
+ shell=True)
+ except CalledProcessError:
+ print "Error: scan-build failed. Its output was: "
+ PBuildLogFile.seek(0)
+ shutil.copyfileobj(PBuildLogFile, sys.stdout)
+ sys.exit(1)
+
+
def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
+ """
+ Run analysis on a set of preprocessed files.
+ """
if os.path.exists(os.path.join(Dir, BuildScript)):
print "Error: The preprocessed files project should not contain %s" % \
- BuildScript
+ BuildScript
raise Exception()
CmdPrefix = Clang + " -cc1 "
# For now, we assume the preprocessed files should be analyzed
# with the OS X SDK.
- SDKPath = getSDKPath("macosx")
+ SDKPath = SATestUtils.getSDKPath("macosx")
if SDKPath is not None:
- CmdPrefix += "-isysroot " + SDKPath + " "
+ CmdPrefix += "-isysroot " + SDKPath + " "
CmdPrefix += "-analyze -analyzer-output=plist -w "
- CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
+ CmdPrefix += "-analyzer-checker=" + Checkers
+ CmdPrefix += " -fcxx-exceptions -fblocks "
- if (Mode == 2) :
+ if (Mode == 2):
CmdPrefix += "-std=c++11 "
PlistPath = os.path.join(Dir, SBOutputDir, "date")
- FailPath = os.path.join(PlistPath, "failures");
- os.makedirs(FailPath);
+ FailPath = os.path.join(PlistPath, "failures")
+ os.makedirs(FailPath)
for FullFileName in glob.glob(Dir + "/*"):
FileName = os.path.basename(FullFileName)
Failed = False
# Only run the analyzes on supported files.
- if (hasNoExtension(FileName)):
+ if SATestUtils.hasNoExtension(FileName):
continue
- if (isValidSingleInputFile(FileName) == False):
+ if not SATestUtils.isValidSingleInputFile(FileName):
print "Error: Invalid single input file %s." % (FullFileName,)
raise Exception()
@@ -382,44 +323,47 @@ def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
try:
if Verbose == 1:
print " Executing: %s" % (Command,)
- check_call(Command, cwd = Dir, stderr=LogFile,
- stdout=LogFile,
- shell=True)
+ check_call(Command, cwd=Dir, stderr=LogFile,
+ stdout=LogFile,
+ shell=True)
except CalledProcessError, e:
print "Error: Analyzes of %s failed. See %s for details." \
- "Error code %d." % \
- (FullFileName, LogFile.name, e.returncode)
+ "Error code %d." % (
+ FullFileName, LogFile.name, e.returncode)
Failed = True
finally:
LogFile.close()
# If command did not fail, erase the log file.
- if Failed == False:
- os.remove(LogFile.name);
+ if not Failed:
+ os.remove(LogFile.name)
+
def getBuildLogPath(SBOutputDir):
- return os.path.join(SBOutputDir, LogFolderName, BuildLogName)
+ return os.path.join(SBOutputDir, LogFolderName, BuildLogName)
+
def removeLogFile(SBOutputDir):
- BuildLogPath = getBuildLogPath(SBOutputDir)
- # Clean up the log file.
- if (os.path.exists(BuildLogPath)) :
- RmCommand = "rm '%s'" % BuildLogPath
- if Verbose == 1:
- print " Executing: %s" % (RmCommand,)
- check_call(RmCommand, shell=True)
+ BuildLogPath = getBuildLogPath(SBOutputDir)
+ # Clean up the log file.
+ if (os.path.exists(BuildLogPath)):
+ RmCommand = "rm '%s'" % BuildLogPath
+ if Verbose == 1:
+ print " Executing: %s" % (RmCommand,)
+ check_call(RmCommand, shell=True)
+
def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
TBegin = time.time()
BuildLogPath = getBuildLogPath(SBOutputDir)
print "Log file: %s" % (BuildLogPath,)
- print "Output directory: %s" %(SBOutputDir, )
+ print "Output directory: %s" % (SBOutputDir, )
removeLogFile(SBOutputDir)
# Clean up scan build results.
- if (os.path.exists(SBOutputDir)) :
+ if (os.path.exists(SBOutputDir)):
RmCommand = "rm -r '%s'" % SBOutputDir
if Verbose == 1:
print " Executing: %s" % (RmCommand,)
@@ -427,11 +371,8 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
assert(not os.path.exists(SBOutputDir))
os.makedirs(os.path.join(SBOutputDir, LogFolderName))
- # Open the log file.
- PBuildLogFile = open(BuildLogPath, "wb+")
-
# Build and analyze the project.
- try:
+ with open(BuildLogPath, "wb+") as PBuildLogFile:
if (ProjectBuildMode == 1):
downloadAndPatch(Dir, PBuildLogFile)
runCleanupScript(Dir, PBuildLogFile)
@@ -439,34 +380,48 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
else:
runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
- if IsReferenceBuild :
+ if IsReferenceBuild:
runCleanupScript(Dir, PBuildLogFile)
-
- # Make the absolute paths relative in the reference results.
- for (DirPath, Dirnames, Filenames) in os.walk(SBOutputDir):
- for F in Filenames:
- if (not F.endswith('plist')):
- continue
- Plist = os.path.join(DirPath, F)
- Data = plistlib.readPlist(Plist)
- PathPrefix = Dir
- if (ProjectBuildMode == 1):
- PathPrefix = os.path.join(Dir, PatchedSourceDirName)
- Paths = [SourceFile[len(PathPrefix)+1:]\
- if SourceFile.startswith(PathPrefix)\
- else SourceFile for SourceFile in Data['files']]
- Data['files'] = Paths
- plistlib.writePlist(Data, Plist)
-
- finally:
- PBuildLogFile.close()
+ normalizeReferenceResults(Dir, SBOutputDir, ProjectBuildMode)
print "Build complete (time: %.2f). See the log for more details: %s" % \
- ((time.time()-TBegin), BuildLogPath)
+ ((time.time() - TBegin), BuildLogPath)
+
+
+def normalizeReferenceResults(Dir, SBOutputDir, ProjectBuildMode):
+ """
+ Make the absolute paths relative in the reference results.
+ """
+ for (DirPath, Dirnames, Filenames) in os.walk(SBOutputDir):
+ for F in Filenames:
+ if (not F.endswith('plist')):
+ continue
+ Plist = os.path.join(DirPath, F)
+ Data = plistlib.readPlist(Plist)
+ PathPrefix = Dir
+ if (ProjectBuildMode == 1):
+ PathPrefix = os.path.join(Dir, PatchedSourceDirName)
+ Paths = [SourceFile[len(PathPrefix) + 1:]
+ if SourceFile.startswith(PathPrefix)
+ else SourceFile for SourceFile in Data['files']]
+ Data['files'] = Paths
+
+ # Remove transient fields which change from run to run.
+ for Diag in Data['diagnostics']:
+ if 'HTMLDiagnostics_files' in Diag:
+ Diag.pop('HTMLDiagnostics_files')
+ if 'clang_version' in Data:
+ Data.pop('clang_version')
+
+ plistlib.writePlist(Data, Plist)
+
-# A plist file is created for each call to the analyzer(each source file).
-# We are only interested on the once that have bug reports, so delete the rest.
def CleanUpEmptyPlists(SBOutputDir):
+ """
+ A plist file is created for each call to the analyzer(each source file).
+ We are only interested on the once that have bug reports,
+ so delete the rest.
+ """
for F in glob.glob(SBOutputDir + "/*/*.plist"):
P = os.path.join(SBOutputDir, F)
@@ -476,62 +431,65 @@ def CleanUpEmptyPlists(SBOutputDir):
os.remove(P)
continue
-# Given the scan-build output directory, checks if the build failed
-# (by searching for the failures directories). If there are failures, it
-# creates a summary file in the output directory.
+
+def CleanUpEmptyFolders(SBOutputDir):
+ """
+ Remove empty folders from results, as git would not store them.
+ """
+ Subfolders = glob.glob(SBOutputDir + "/*")
+ for Folder in Subfolders:
+ if not os.listdir(Folder):
+ os.removedirs(Folder)
+
+
def checkBuild(SBOutputDir):
+ """
+ Given the scan-build output directory, checks if the build failed
+ (by searching for the failures directories). If there are failures, it
+ creates a summary file in the output directory.
+
+ """
# Check if there are failures.
Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt")
- TotalFailed = len(Failures);
+ TotalFailed = len(Failures)
if TotalFailed == 0:
CleanUpEmptyPlists(SBOutputDir)
+ CleanUpEmptyFolders(SBOutputDir)
Plists = glob.glob(SBOutputDir + "/*/*.plist")
print "Number of bug reports (non-empty plist files) produced: %d" %\
- len(Plists)
- return;
-
- # Create summary file to display when the build fails.
- SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName)
- if (Verbose > 0):
- print " Creating the failures summary file %s" % (SummaryPath,)
+ len(Plists)
+ return
- SummaryLog = open(SummaryPath, "w+")
- try:
- SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
- if TotalFailed > NumOfFailuresInSummary:
- SummaryLog.write("See the first %d below.\n"
- % (NumOfFailuresInSummary,))
+ print "Error: analysis failed."
+ print "Total of %d failures discovered." % TotalFailed
+ if TotalFailed > NumOfFailuresInSummary:
+ print "See the first %d below.\n" % NumOfFailuresInSummary
# TODO: Add a line "See the results folder for more."
- FailuresCopied = NumOfFailuresInSummary
- Idx = 0
- for FailLogPathI in Failures:
- if Idx >= NumOfFailuresInSummary:
- break;
- Idx += 1
- SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,));
- FailLogI = open(FailLogPathI, "r");
- try:
- shutil.copyfileobj(FailLogI, SummaryLog);
- finally:
- FailLogI.close()
- finally:
- SummaryLog.close()
-
- print "Error: analysis failed. See ", SummaryPath
- sys.exit(-1)
-
-# Auxiliary object to discard stdout.
-class Discarder(object):
- def write(self, text):
- pass # do nothing
-
-# Compare the warnings produced by scan-build.
-# Strictness defines the success criteria for the test:
-# 0 - success if there are no crashes or analyzer failure.
-# 1 - success if there are no difference in the number of reported bugs.
-# 2 - success if all the bug reports are identical.
-def runCmpResults(Dir, Strictness = 0):
+ Idx = 0
+ for FailLogPathI in Failures:
+ if Idx >= NumOfFailuresInSummary:
+ break
+ Idx += 1
+ print "\n-- Error #%d -----------\n" % Idx
+ with open(FailLogPathI, "r") as FailLogI:
+ shutil.copyfileobj(FailLogI, sys.stdout)
+
+ sys.exit(1)
+
+
+def runCmpResults(Dir, Strictness=0):
+ """
+ Compare the warnings produced by scan-build.
+ Strictness defines the success criteria for the test:
+ 0 - success if there are no crashes or analyzer failure.
+ 1 - success if there are no difference in the number of reported bugs.
+ 2 - success if all the bug reports are identical.
+
+ :return success: Whether tests pass according to the Strictness
+ criteria.
+ """
+ TestsPassed = True
TBegin = time.time()
RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName)
@@ -547,9 +505,10 @@ def runCmpResults(Dir, Strictness = 0):
RefList.remove(RefLogDir)
NewList.remove(os.path.join(NewDir, LogFolderName))
- if len(RefList) == 0 or len(NewList) == 0:
- return False
- assert(len(RefList) == len(NewList))
+ if len(RefList) != len(NewList):
+ print "Mismatch in number of results folders: %s vs %s" % (
+ RefList, NewList)
+ sys.exit(1)
# There might be more then one folder underneath - one per each scan-build
# command (Ex: one for configure and one for make).
@@ -569,32 +528,31 @@ def runCmpResults(Dir, Strictness = 0):
if Verbose == 1:
print " Comparing Results: %s %s" % (RefDir, NewDir)
- DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName)
- Opts = CmpRuns.CmpOptions(DiffsPath, "", PatchedSourceDirPath)
- # Discard everything coming out of stdout (CmpRun produces a lot of them).
- OLD_STDOUT = sys.stdout
- sys.stdout = Discarder()
+ Opts = CmpRuns.CmpOptions(rootA="", rootB=PatchedSourceDirPath)
# Scan the results, delete empty plist files.
NumDiffs, ReportsInRef, ReportsInNew = \
CmpRuns.dumpScanBuildResultsDiff(RefDir, NewDir, Opts, False)
- sys.stdout = OLD_STDOUT
- if (NumDiffs > 0) :
- print "Warning: %r differences in diagnostics. See %s" % \
- (NumDiffs, DiffsPath,)
+ if (NumDiffs > 0):
+ print "Warning: %s differences in diagnostics." % NumDiffs
if Strictness >= 2 and NumDiffs > 0:
print "Error: Diffs found in strict mode (2)."
- sys.exit(-1)
+ TestsPassed = False
elif Strictness >= 1 and ReportsInRef != ReportsInNew:
- print "Error: The number of results are different in strict mode (1)."
- sys.exit(-1)
+ print "Error: The number of results are different in "\
+ "strict mode (1)."
+ TestsPassed = False
+
+ print "Diagnostic comparison complete (time: %.2f)." % (
+ time.time() - TBegin)
+ return TestsPassed
- print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
- return (NumDiffs > 0)
def cleanupReferenceResults(SBOutputDir):
- # Delete html, css, and js files from reference results. These can
- # include multiple copies of the benchmark source and so get very large.
+ """
+ Delete html, css, and js files from reference results. These can
+ include multiple copies of the benchmark source and so get very large.
+ """
Extensions = ["html", "css", "js"]
for E in Extensions:
for F in glob.glob("%s/*/*.%s" % (SBOutputDir, E)):
@@ -605,42 +563,18 @@ def cleanupReferenceResults(SBOutputDir):
# Remove the log file. It leaks absolute path names.
removeLogFile(SBOutputDir)
-def updateSVN(Mode, ProjectsMap):
- try:
- ProjectsMap.seek(0)
- for I in csv.reader(ProjectsMap):
- ProjName = I[0]
- Path = os.path.join(ProjName, getSBOutputDirName(True))
-
- if Mode == "delete":
- Command = "svn delete '%s'" % (Path,)
- else:
- Command = "svn add '%s'" % (Path,)
-
- if Verbose == 1:
- print " Executing: %s" % (Command,)
- check_call(Command, shell=True)
-
- if Mode == "delete":
- CommitCommand = "svn commit -m \"[analyzer tests] Remove " \
- "reference results.\""
- else:
- CommitCommand = "svn commit -m \"[analyzer tests] Add new " \
- "reference results.\""
- if Verbose == 1:
- print " Executing: %s" % (CommitCommand,)
- check_call(CommitCommand, shell=True)
- except:
- print "Error: SVN update failed."
- sys.exit(-1)
-def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0):
+def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Strictness=0):
+ """
+ Test a given project.
+ :return TestsPassed: Whether tests have passed according
+ to the :param Strictness: criteria.
+ """
print " \n\n--- Building project %s" % (ID,)
TBegin = time.time()
- if Dir is None :
- Dir = getProjectDir(ID)
+ Dir = getProjectDir(ID)
if Verbose == 1:
print " Build directory: %s." % (Dir,)
@@ -652,76 +586,78 @@ def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictne
checkBuild(SBOutputDir)
- if IsReferenceBuild == False:
- runCmpResults(Dir, Strictness)
- else:
+ if IsReferenceBuild:
cleanupReferenceResults(SBOutputDir)
+ TestsPassed = True
+ else:
+ TestsPassed = runCmpResults(Dir, Strictness)
print "Completed tests for project %s (time: %.2f)." % \
- (ID, (time.time()-TBegin))
+ (ID, (time.time() - TBegin))
+ return TestsPassed
-def isCommentCSVLine(Entries):
- # Treat CSV lines starting with a '#' as a comment.
- return len(Entries) > 0 and Entries[0].startswith("#")
-def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
- PMapFile = open(getProjectMapPath(), "rb")
- try:
- # Validate the input.
- for I in csv.reader(PMapFile):
- if (isCommentCSVLine(I)):
- continue
- if (len(I) != 2) :
- print "Error: Rows in the ProjectMapFile should have 3 entries."
- raise Exception()
- if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))):
- print "Error: Second entry in the ProjectMapFile should be 0" \
- " (single file), 1 (project), or 2(single file c++11)."
- raise Exception()
-
- # When we are regenerating the reference results, we might need to
- # update svn. Remove reference results from SVN.
- if UpdateSVN == True:
- assert(IsReferenceBuild == True);
- updateSVN("delete", PMapFile);
+def projectFileHandler():
+ return open(getProjectMapPath(), "rb")
- # Test the projects.
- PMapFile.seek(0)
- for I in csv.reader(PMapFile):
- if isCommentCSVLine(I):
- continue;
- testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness)
- # Add reference results to SVN.
- if UpdateSVN == True:
- updateSVN("add", PMapFile);
+def iterateOverProjects(PMapFile):
+ """
+ Iterate over all projects defined in the project file handler `PMapFile`
+ from the start.
+ """
+ PMapFile.seek(0)
+ for I in csv.reader(PMapFile):
+ if (SATestUtils.isCommentCSVLine(I)):
+ continue
+ yield I
+
+
+def validateProjectFile(PMapFile):
+ """
+ Validate project file.
+ """
+ for I in iterateOverProjects(PMapFile):
+ if len(I) != 2:
+ print "Error: Rows in the ProjectMapFile should have 2 entries."
+ raise Exception()
+ if I[1] not in ('0', '1', '2'):
+ print "Error: Second entry in the ProjectMapFile should be 0" \
+ " (single file), 1 (project), or 2(single file c++11)."
+ raise Exception()
+
+
+def testAll(IsReferenceBuild=False, Strictness=0):
+ TestsPassed = True
+ with projectFileHandler() as PMapFile:
+ validateProjectFile(PMapFile)
+
+ # Test the projects.
+ for (ProjName, ProjBuildMode) in iterateOverProjects(PMapFile):
+ TestsPassed &= testProject(
+ ProjName, int(ProjBuildMode), IsReferenceBuild, Strictness)
+ return TestsPassed
- except:
- print "Error occurred. Premature termination."
- raise
- finally:
- PMapFile.close()
if __name__ == '__main__':
# Parse command line arguments.
- Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.')
+ Parser = argparse.ArgumentParser(
+ description='Test the Clang Static Analyzer.')
Parser.add_argument('--strictness', dest='strictness', type=int, default=0,
- help='0 to fail on runtime errors, 1 to fail when the number\
- of found bugs are different from the reference, 2 to \
- fail on any difference from the reference. Default is 0.')
- Parser.add_argument('-r', dest='regenerate', action='store_true', default=False,
- help='Regenerate reference output.')
- Parser.add_argument('-rs', dest='update_reference', action='store_true',
- default=False, help='Regenerate reference output and update svn.')
+ help='0 to fail on runtime errors, 1 to fail when the \
+ number of found bugs are different from the \
+ reference, 2 to fail on any difference from the \
+ reference. Default is 0.')
+ Parser.add_argument('-r', dest='regenerate', action='store_true',
+ default=False, help='Regenerate reference output.')
Args = Parser.parse_args()
IsReference = False
- UpdateSVN = False
Strictness = Args.strictness
if Args.regenerate:
IsReference = True
- elif Args.update_reference:
- IsReference = True
- UpdateSVN = True
- testAll(IsReference, UpdateSVN, Strictness)
+ TestsPassed = testAll(IsReference, Strictness)
+ if not TestsPassed:
+ print "ERROR: Tests failed."
+ sys.exit(42)
diff --git a/utils/analyzer/SATestUpdateDiffs.py b/utils/analyzer/SATestUpdateDiffs.py
new file mode 100755
index 0000000000..2282af15a5
--- /dev/null
+++ b/utils/analyzer/SATestUpdateDiffs.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+"""
+Update reference results for static analyzer.
+"""
+
+import SATestBuild
+
+from subprocess import check_call
+import os
+import sys
+
+Verbose = 1
+
+
+def runCmd(Command):
+ if Verbose:
+ print "Executing %s" % Command
+ check_call(Command, shell=True)
+
+
+def updateReferenceResults(ProjName, ProjBuildMode):
+ ProjDir = SATestBuild.getProjectDir(ProjName)
+
+ RefResultsPath = os.path.join(
+ ProjDir,
+ SATestBuild.getSBOutputDirName(IsReferenceBuild=True))
+ CreatedResultsPath = os.path.join(
+ ProjDir,
+ SATestBuild.getSBOutputDirName(IsReferenceBuild=False))
+
+ if not os.path.exists(CreatedResultsPath):
+ print >> sys.stderr, "New results not found, was SATestBuild.py "\
+ "previously run?"
+ sys.exit(1)
+
+ # Remove reference results: in git, and then again for a good measure
+ # with rm, as git might not remove things fully if there are empty
+ # directories involved.
+ runCmd('git rm -r -q "%s"' % (RefResultsPath,))
+ runCmd('rm -rf "%s"' % (RefResultsPath,))
+
+ # Replace reference results with a freshly computed once.
+ runCmd('cp -r "%s" "%s"' % (CreatedResultsPath, RefResultsPath,))
+
+ # Run cleanup script.
+ BuildLogPath = SATestBuild.getBuildLogPath(RefResultsPath)
+ with open(BuildLogPath, "wb+") as PBuildLogFile:
+ SATestBuild.runCleanupScript(ProjDir, PBuildLogFile)
+
+ SATestBuild.normalizeReferenceResults(
+ ProjDir, RefResultsPath, ProjBuildMode)
+
+ # Clean up the generated difference results.
+ SATestBuild.cleanupReferenceResults(RefResultsPath)
+
+ runCmd('git add "%s"' % (RefResultsPath,))
+
+
+def main(argv):
+ if len(argv) == 2 and argv[1] in ('-h', '--help'):
+ print >> sys.stderr, "Update static analyzer reference results based "\
+ "\non the previous run of SATestBuild.py.\n"\
+ "\nN.B.: Assumes that SATestBuild.py was just run"
+ sys.exit(1)
+
+ with SATestBuild.projectFileHandler() as f:
+ for (ProjName, ProjBuildMode) in SATestBuild.iterateOverProjects(f):
+ updateReferenceResults(ProjName, int(ProjBuildMode))
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/utils/analyzer/SATestUtils.py b/utils/analyzer/SATestUtils.py
new file mode 100644
index 0000000000..9220acc1bd
--- /dev/null
+++ b/utils/analyzer/SATestUtils.py
@@ -0,0 +1,100 @@
+import os
+from subprocess import check_output, check_call
+import sys
+
+
+Verbose = 1
+
+def which(command, paths=None):
+ """which(command, [paths]) - Look up the given command in the paths string
+ (or the PATH environment variable, if unspecified)."""
+
+ if paths is None:
+ paths = os.environ.get('PATH', '')
+
+ # Check for absolute match first.
+ if os.path.exists(command):
+ return command
+
+ # Would be nice if Python had a lib function for this.
+ if not paths:
+ paths = os.defpath
+
+ # Get suffixes to search.
+ # On Cygwin, 'PATHEXT' may exist but it should not be used.
+ if os.pathsep == ';':
+ pathext = os.environ.get('PATHEXT', '').split(';')
+ else:
+ pathext = ['']
+
+ # Search the paths...
+ for path in paths.split(os.pathsep):
+ for ext in pathext:
+ p = os.path.join(path, command + ext)
+ if os.path.exists(p):
+ return p
+
+ return None
+
+
+class flushfile(object):
+ """
+ Wrapper to flush the output after every print statement.
+ """
+ def __init__(self, f):
+ self.f = f
+
+ def write(self, x):
+ self.f.write(x)
+ self.f.flush()
+
+
+def hasNoExtension(FileName):
+ (Root, Ext) = os.path.splitext(FileName)
+ return (Ext == "")
+
+
+def isValidSingleInputFile(FileName):
+ (Root, Ext) = os.path.splitext(FileName)
+ return Ext in (".i", ".ii", ".c", ".cpp", ".m", "")
+
+
+def getSDKPath(SDKName):
+ """
+ Get the path to the SDK for the given SDK name. Returns None if
+ the path cannot be determined.
+ """
+ if which("xcrun") is None:
+ return None
+
+ Cmd = "xcrun --sdk " + SDKName + " --show-sdk-path"
+ return check_output(Cmd, shell=True).rstrip()
+
+
+def runScript(ScriptPath, PBuildLogFile, Cwd):
+ """
+ Run the provided script if it exists.
+ """
+ if os.path.exists(ScriptPath):
+ try:
+ if Verbose == 1:
+ print " Executing: %s" % (ScriptPath,)
+ check_call("chmod +x '%s'" % ScriptPath, cwd=Cwd,
+ stderr=PBuildLogFile,
+ stdout=PBuildLogFile,
+ shell=True)
+ check_call("'%s'" % ScriptPath, cwd=Cwd,
+ stderr=PBuildLogFile,
+ stdout=PBuildLogFile,
+ shell=True)
+ except:
+ print "Error: Running %s failed. See %s for details." % (
+ ScriptPath, PBuildLogFile.name)
+ sys.exit(-1)
+
+
+def isCommentCSVLine(Entries):
+ """
+ Treat CSV lines starting with a '#' as a comment.
+ """
+ return len(Entries) > 0 and Entries[0].startswith("#")
diff --git a/utils/analyzer/SumTimerInfo.py b/utils/analyzer/SumTimerInfo.py
index 0c3585bbc2..50e1cb854f 100644
--- a/utils/analyzer/SumTimerInfo.py
+++ b/utils/analyzer/SumTimerInfo.py
@@ -5,11 +5,8 @@ Script to Summarize statistics in the scan-build output.
Statistics are enabled by passing '-internal-stats' option to scan-build
(or '-analyzer-stats' to the analyzer).
-
"""
-import string
-from operator import itemgetter
import sys
if __name__ == '__main__':
@@ -31,44 +28,42 @@ if __name__ == '__main__':
NumInlinedCallSites = 0
NumBifurcatedCallSites = 0
MaxCFGSize = 0
- Mode = 1
for line in f:
- if ("Miscellaneous Ungrouped Timers" in line) :
- Mode = 1
- if (("Analyzer Total Time" in line) and (Mode == 1)) :
- s = line.split()
- Time = Time + float(s[6])
- Count = Count + 1
- if (float(s[6]) > MaxTime) :
- MaxTime = float(s[6])
- if ((("warning generated." in line) or ("warnings generated" in line)) and Mode == 1) :
- s = line.split()
- Warnings = Warnings + int(s[0])
- if (("The # of functions analysed (as top level)" in line) and (Mode == 1)) :
- s = line.split()
- FunctionsAnalyzed = FunctionsAnalyzed + int(s[0])
- if (("The % of reachable basic blocks" in line) and (Mode == 1)) :
- s = line.split()
- ReachableBlocks = ReachableBlocks + int(s[0])
- if (("The # of times we reached the max number of steps" in line) and (Mode == 1)) :
- s = line.split()
- ReachedMaxSteps = ReachedMaxSteps + int(s[0])
- if (("The maximum number of basic blocks in a function" in line) and (Mode == 1)) :
- s = line.split()
- if (MaxCFGSize < int(s[0])) :
- MaxCFGSize = int(s[0])
- if (("The # of steps executed" in line) and (Mode == 1)) :
- s = line.split()
- NumSteps = NumSteps + int(s[0])
- if (("The # of times we inlined a call" in line) and (Mode == 1)) :
- s = line.split()
- NumInlinedCallSites = NumInlinedCallSites + int(s[0])
- if (("The # of times we split the path due to imprecise dynamic dispatch info" in line) and (Mode == 1)) :
- s = line.split()
- NumBifurcatedCallSites = NumBifurcatedCallSites + int(s[0])
- if ((") Total" in line) and (Mode == 1)) :
- s = line.split()
- TotalTime = TotalTime + float(s[6])
+ if ("Analyzer Total Time" in line):
+ s = line.split()
+ Time = Time + float(s[6])
+ Count = Count + 1
+ if (float(s[6]) > MaxTime):
+ MaxTime = float(s[6])
+ if ("warning generated." in line) or ("warnings generated" in line):
+ s = line.split()
+ Warnings = Warnings + int(s[0])
+ if "The # of functions analysed (as top level)" in line:
+ s = line.split()
+ FunctionsAnalyzed = FunctionsAnalyzed + int(s[0])
+ if "The % of reachable basic blocks" in line:
+ s = line.split()
+ ReachableBlocks = ReachableBlocks + int(s[0])
+ if "The # of times we reached the max number of steps" in line:
+ s = line.split()
+ ReachedMaxSteps = ReachedMaxSteps + int(s[0])
+ if "The maximum number of basic blocks in a function" in line:
+ s = line.split()
+ if MaxCFGSize < int(s[0]):
+ MaxCFGSize = int(s[0])
+ if "The # of steps executed" in line:
+ s = line.split()
+ NumSteps = NumSteps + int(s[0])
+ if "The # of times we inlined a call" in line:
+ s = line.split()
+ NumInlinedCallSites = NumInlinedCallSites + int(s[0])
+ if "The # of times we split the path due \
+ to imprecise dynamic dispatch info" in line:
+ s = line.split()
+ NumBifurcatedCallSites = NumBifurcatedCallSites + int(s[0])
+ if ") Total" in line:
+ s = line.split()
+ TotalTime = TotalTime + float(s[6])
print "TU Count %d" % (Count)
print "Time %f" % (Time)
@@ -77,7 +72,8 @@ if __name__ == '__main__':
print "Reachable Blocks %d" % (ReachableBlocks)
print "Reached Max Steps %d" % (ReachedMaxSteps)
print "Number of Steps %d" % (NumSteps)
- print "Number of Inlined calls %d (bifurcated %d)" % (NumInlinedCallSites, NumBifurcatedCallSites)
+ print "Number of Inlined calls %d (bifurcated %d)" % (
+ NumInlinedCallSites, NumBifurcatedCallSites)
print "MaxTime %f" % (MaxTime)
print "TotalTime %f" % (TotalTime)
print "Max CFG Size %d" % (MaxCFGSize)
diff --git a/utils/analyzer/ubiviz b/utils/analyzer/ubiviz
index 9d821c3c10..137e130fe7 100755
--- a/utils/analyzer/ubiviz
+++ b/utils/analyzer/ubiviz
@@ -5,69 +5,72 @@
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
-##===----------------------------------------------------------------------===##
+##===--------------------------------------------------------------------===##
#
# This script reads visualization data emitted by the static analyzer for
# display in Ubigraph.
#
-##===----------------------------------------------------------------------===##
+##===--------------------------------------------------------------------===##
import xmlrpclib
import sys
+
def Error(message):
print >> sys.stderr, 'ubiviz: ' + message
sys.exit(1)
+
def StreamData(filename):
- file = open(filename)
- for ln in file:
- yield eval(ln)
- file.close()
+ file = open(filename)
+ for ln in file:
+ yield eval(ln)
+ file.close()
+
def Display(G, data):
- action = data[0]
- if action == 'vertex':
- vertex = data[1]
- G.new_vertex_w_id(vertex)
- for attribute in data[2:]:
- G.set_vertex_attribute(vertex, attribute[0], attribute[1])
- elif action == 'edge':
- src = data[1]
- dst = data[2]
- edge = G.new_edge(src,dst)
- for attribute in data[3:]:
- G.set_edge_attribute(edge, attribute[0], attribute[1])
- elif action == "vertex_style":
- style_id = data[1]
- parent_id = data[2]
- G.new_vertex_style_w_id(style_id, parent_id)
- for attribute in data[3:]:
- G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
- elif action == "vertex_style_attribute":
- style_id = data[1]
- for attribute in data[2:]:
- G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
- elif action == "change_vertex_style":
- vertex_id = data[1]
- style_id = data[2]
- G.change_vertex_style(vertex_id,style_id)
+ action = data[0]
+ if action == 'vertex':
+ vertex = data[1]
+ G.new_vertex_w_id(vertex)
+ for attribute in data[2:]:
+ G.set_vertex_attribute(vertex, attribute[0], attribute[1])
+ elif action == 'edge':
+ src = data[1]
+ dst = data[2]
+ edge = G.new_edge(src, dst)
+ for attribute in data[3:]:
+ G.set_edge_attribute(edge, attribute[0], attribute[1])
+ elif action == "vertex_style":
+ style_id = data[1]
+ parent_id = data[2]
+ G.new_vertex_style_w_id(style_id, parent_id)
+ for attribute in data[3:]:
+ G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
+ elif action == "vertex_style_attribute":
+ style_id = data[1]
+ for attribute in data[2:]:
+ G.set_vertex_style_attribute(style_id, attribute[0], attribute[1])
+ elif action == "change_vertex_style":
+ vertex_id = data[1]
+ style_id = data[2]
+ G.change_vertex_style(vertex_id, style_id)
+
def main(args):
- if len(args) == 0:
- Error('no input files')
+ if len(args) == 0:
+ Error('no input files')
- server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2')
- G = server.ubigraph
+ server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2')
+ G = server.ubigraph
- for arg in args:
- G.clear()
- for x in StreamData(arg):
- Display(G,x)
+ for arg in args:
+ G.clear()
+ for x in StreamData(arg):
+ Display(G, x)
- sys.exit(0)
+ sys.exit(0)
if __name__ == '__main__':
main(sys.argv[1:])
-
diff --git a/utils/bash-autocomplete.sh b/utils/bash-autocomplete.sh
new file mode 100644
index 0000000000..ed815d2d7a
--- /dev/null
+++ b/utils/bash-autocomplete.sh
@@ -0,0 +1,83 @@
+# Please add "source /path/to/bash-autocomplete.sh" to your .bashrc to use this.
+
+_clang_filedir()
+{
+ # _filedir function provided by recent versions of bash-completion package is
+ # better than "compgen -f" because the former honors spaces in pathnames while
+ # the latter doesn't. So we use compgen only when _filedir is not provided.
+ _filedir 2> /dev/null || COMPREPLY=( $( compgen -f ) )
+}
+
+_clang()
+{
+ local cur prev words cword arg flags w1 w2
+ # If latest bash-completion is not supported just initialize COMPREPLY and
+ # initialize variables by setting manualy.
+ _init_completion -n 2> /dev/null
+ if [[ "$?" != 0 ]]; then
+ COMPREPLY=()
+ cword=$COMP_CWORD
+ cur="${COMP_WORDS[$cword]}"
+ fi
+
+ w1="${COMP_WORDS[$cword - 1]}"
+ if [[ $cword > 1 ]]; then
+ w2="${COMP_WORDS[$cword - 2]}"
+ fi
+
+ # Clang want to know if -cc1 or -Xclang option is specified or not, because we don't want to show
+ # cc1 options otherwise.
+ if [[ "${COMP_WORDS[1]}" == "-cc1" || "$w1" == "-Xclang" ]]; then
+ arg="#"
+ fi
+
+ # bash always separates '=' as a token even if there's no space before/after '='.
+ # On the other hand, '=' is just a regular character for clang options that
+ # contain '='. For example, "-stdlib=" is defined as is, instead of "-stdlib" and "=".
+ # So, we need to partially undo bash tokenization here for integrity.
+ if [[ "$cur" == -* ]]; then
+ # -foo<tab>
+ arg="$arg$cur"
+ elif [[ "$w1" == -* && "$cur" == '=' ]]; then
+ # -foo=<tab>
+ arg="$arg$w1=,"
+ elif [[ "$cur" == -*= ]]; then
+ # -foo=<tab>
+ arg="$arg$cur,"
+ elif [[ "$w1" == -* ]]; then
+ # -foo <tab> or -foo bar<tab>
+ arg="$arg$w1,$cur"
+ elif [[ "$w2" == -* && "$w1" == '=' ]]; then
+ # -foo=bar<tab>
+ arg="$arg$w2=,$cur"
+ elif [[ ${cur: -1} != '=' && ${cur/=} != $cur ]]; then
+ # -foo=bar<tab>
+ arg="$arg${cur%=*}=,${cur#*=}"
+ fi
+
+ # expand ~ to $HOME
+ eval local path=${COMP_WORDS[0]}
+ flags=$( "$path" --autocomplete="$arg" 2>/dev/null | sed -e 's/\t.*//' )
+ # If clang is old that it does not support --autocomplete,
+ # fall back to the filename completion.
+ if [[ "$?" != 0 ]]; then
+ _clang_filedir
+ return
+ fi
+
+ # When clang does not emit any possible autocompletion, or user pushed tab after " ",
+ # just autocomplete files.
+ if [[ "$flags" == "$(echo -e '\n')" || "$arg" == "" ]]; then
+ # If -foo=<tab> and there was no possible values, autocomplete files.
+ [[ "$cur" == '=' || "$cur" == -*= ]] && cur=""
+ _clang_filedir
+ elif [[ "$cur" == '=' ]]; then
+ COMPREPLY=( $( compgen -W "$flags" -- "") )
+ else
+ # Bash automatically appends a space after '=' by default.
+ # Disable it so that it works nicely for options in the form of -foo=bar.
+ [[ "${flags: -1}" == '=' ]] && compopt -o nospace 2> /dev/null
+ COMPREPLY=( $( compgen -W "$flags" -- "$cur" ) )
+ fi
+}
+complete -F _clang clang
diff --git a/utils/clangdiag.py b/utils/clangdiag.py
new file mode 100755
index 0000000000..f434bfeaa4
--- /dev/null
+++ b/utils/clangdiag.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+
+#----------------------------------------------------------------------
+# Be sure to add the python path that points to the LLDB shared library.
+#
+# # To use this in the embedded python interpreter using "lldb" just
+# import it with the full path using the "command script import"
+# command
+# (lldb) command script import /path/to/clandiag.py
+#----------------------------------------------------------------------
+
+import lldb
+import argparse
+import commands
+import shlex
+import os
+import re
+import subprocess
+
+class MyParser(argparse.ArgumentParser):
+ def format_help(self):
+ return ''' Commands for managing clang diagnostic breakpoints
+
+Syntax: clangdiag enable [<warning>|<diag-name>]
+ clangdiag disable
+ clangdiag diagtool [<path>|reset]
+
+The following subcommands are supported:
+
+ enable -- Enable clang diagnostic breakpoints.
+ disable -- Disable all clang diagnostic breakpoints.
+ diagtool -- Return, set, or reset diagtool path.
+
+This command sets breakpoints in clang, and clang based tools, that
+emit diagnostics. When a diagnostic is emitted, and clangdiag is
+enabled, it will use the appropriate diagtool application to determine
+the name of the DiagID, and set breakpoints in all locations that
+'diag::name' appears in the source. Since the new breakpoints are set
+after they are encountered, users will need to launch the executable a
+second time in order to hit the new breakpoints.
+
+For in-tree builds, the diagtool application, used to map DiagID's to
+names, is found automatically in the same directory as the target
+executable. However, out-or-tree builds must use the 'diagtool'
+subcommand to set the appropriate path for diagtool in the clang debug
+bin directory. Since this mapping is created at build-time, it's
+important for users to use the same version that was generated when
+clang was compiled, or else the id's won't match.
+
+Notes:
+- Substrings can be passed for both <warning> and <diag-name>.
+- If <warning> is passed, only enable the DiagID(s) for that warning.
+- If <diag-name> is passed, only enable that DiagID.
+- Rerunning enable clears existing breakpoints.
+- diagtool is used in breakpoint callbacks, so it can be changed
+ without the need to rerun enable.
+- Adding this to your ~.lldbinit file makes clangdiag available at startup:
+ "command script import /path/to/clangdiag.py"
+
+'''
+
+def create_diag_options():
+ parser = MyParser(prog='clangdiag')
+ subparsers = parser.add_subparsers(
+ title='subcommands',
+ dest='subcommands',
+ metavar='')
+ disable_parser = subparsers.add_parser('disable')
+ enable_parser = subparsers.add_parser('enable')
+ enable_parser.add_argument('id', nargs='?')
+ diagtool_parser = subparsers.add_parser('diagtool')
+ diagtool_parser.add_argument('path', nargs='?')
+ return parser
+
+def getDiagtool(target, diagtool = None):
+ id = target.GetProcess().GetProcessID()
+ if 'diagtool' not in getDiagtool.__dict__:
+ getDiagtool.diagtool = {}
+ if diagtool:
+ if diagtool == 'reset':
+ getDiagtool.diagtool[id] = None
+ elif os.path.exists(diagtool):
+ getDiagtool.diagtool[id] = diagtool
+ else:
+ print('clangdiag: %s not found.' % diagtool)
+ if not id in getDiagtool.diagtool or not getDiagtool.diagtool[id]:
+ getDiagtool.diagtool[id] = None
+ exe = target.GetExecutable()
+ if not exe.Exists():
+ print('clangdiag: Target (%s) not set.' % exe.GetFilename())
+ else:
+ diagtool = os.path.join(exe.GetDirectory(), 'diagtool')
+ if os.path.exists(diagtool):
+ getDiagtool.diagtool[id] = diagtool
+ else:
+ print('clangdiag: diagtool not found along side %s' % exe)
+
+ return getDiagtool.diagtool[id]
+
+def setDiagBreakpoint(frame, bp_loc, dict):
+ id = frame.FindVariable("DiagID").GetValue()
+ if id is None:
+ print('clangdiag: id is None')
+ return False
+
+ # Don't need to test this time, since we did that in enable.
+ target = frame.GetThread().GetProcess().GetTarget()
+ diagtool = getDiagtool(target)
+ name = subprocess.check_output([diagtool, "find-diagnostic-id", id]).rstrip();
+ # Make sure we only consider errors, warnings, and extentions.
+ # FIXME: Make this configurable?
+ prefixes = ['err_', 'warn_', 'exp_']
+ if len([prefix for prefix in prefixes+[''] if name.startswith(prefix)][0]):
+ bp = target.BreakpointCreateBySourceRegex(name, lldb.SBFileSpec())
+ bp.AddName("clang::Diagnostic")
+
+ return False
+
+def enable(exe_ctx, args):
+ # Always disable existing breakpoints
+ disable(exe_ctx)
+
+ target = exe_ctx.GetTarget()
+ numOfBreakpoints = target.GetNumBreakpoints()
+
+ if args.id:
+ # Make sure we only consider errors, warnings, and extentions.
+ # FIXME: Make this configurable?
+ prefixes = ['err_', 'warn_', 'exp_']
+ if len([prefix for prefix in prefixes+[''] if args.id.startswith(prefix)][0]):
+ bp = target.BreakpointCreateBySourceRegex(args.id, lldb.SBFileSpec())
+ bp.AddName("clang::Diagnostic")
+ else:
+ diagtool = getDiagtool(target)
+ list = subprocess.check_output([diagtool, "list-warnings"]).rstrip();
+ for line in list.splitlines(True):
+ m = re.search(r' *(.*) .*\[\-W' + re.escape(args.id) + r'.*].*', line)
+ # Make sure we only consider warnings.
+ if m and m.group(1).startswith('warn_'):
+ bp = target.BreakpointCreateBySourceRegex(m.group(1), lldb.SBFileSpec())
+ bp.AddName("clang::Diagnostic")
+ else:
+ print('Adding callbacks.')
+ bp = target.BreakpointCreateByName('DiagnosticsEngine::Report')
+ bp.SetScriptCallbackFunction('clangdiag.setDiagBreakpoint')
+ bp.AddName("clang::Diagnostic")
+
+ count = target.GetNumBreakpoints() - numOfBreakpoints
+ print('%i breakpoint%s added.' % (count, "s"[count==1:]))
+
+ return
+
+def disable(exe_ctx):
+ target = exe_ctx.GetTarget()
+ # Remove all diag breakpoints.
+ bkpts = lldb.SBBreakpointList(target)
+ target.FindBreakpointsByName("clang::Diagnostic", bkpts)
+ for i in range(bkpts.GetSize()):
+ target.BreakpointDelete(bkpts.GetBreakpointAtIndex(i).GetID())
+
+ return
+
+def the_diag_command(debugger, command, exe_ctx, result, dict):
+ # Use the Shell Lexer to properly parse up command options just like a
+ # shell would
+ command_args = shlex.split(command)
+ parser = create_diag_options()
+ try:
+ args = parser.parse_args(command_args)
+ except:
+ return
+
+ if args.subcommands == 'enable':
+ enable(exe_ctx, args)
+ elif args.subcommands == 'disable':
+ disable(exe_ctx)
+ else:
+ diagtool = getDiagtool(exe_ctx.GetTarget(), args.path)
+ print('diagtool = %s' % diagtool)
+
+ return
+
+def __lldb_init_module(debugger, dict):
+ # This initializer is being run from LLDB in the embedded command interpreter
+ # Make the options so we can generate the help text for the new LLDB
+ # command line command prior to registering it with LLDB below
+ parser = create_diag_options()
+ the_diag_command.__doc__ = parser.format_help()
+ # Add any commands contained in this module to LLDB
+ debugger.HandleCommand(
+ 'command script add -f clangdiag.the_diag_command clangdiag')
+ print 'The "clangdiag" command has been installed, type "help clangdiag" or "clangdiag --help" for detailed help.'
diff --git a/utils/perf-training/CMakeLists.txt b/utils/perf-training/CMakeLists.txt
index c046a1dac4..39f9a4ca3c 100644
--- a/utils/perf-training/CMakeLists.txt
+++ b/utils/perf-training/CMakeLists.txt
@@ -30,13 +30,13 @@ if(LLVM_BUILD_INSTRUMENTED)
endif()
if(NOT LLVM_PROFDATA)
- message(FATAL_ERROR "Must set LLVM_PROFDATA to point to llvm-profdata to use for merging PGO data")
+ message(STATUS "To enable merging PGO data LLVM_PROFDATA has to point to llvm-profdata")
+ else()
+ add_custom_target(generate-profdata
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py merge ${LLVM_PROFDATA} ${CMAKE_CURRENT_BINARY_DIR}/clang.profdata ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Merging profdata"
+ DEPENDS generate-profraw)
endif()
-
- add_custom_target(generate-profdata
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/perf-helper.py merge ${LLVM_PROFDATA} ${CMAKE_CURRENT_BINARY_DIR}/clang.profdata ${CMAKE_CURRENT_BINARY_DIR}
- COMMENT "Merging profdata"
- DEPENDS generate-profraw)
endif()
find_program(DTRACE dtrace)
diff --git a/utils/perf-training/lit.cfg b/utils/perf-training/lit.cfg
index edae551bed..671d44f83b 100644
--- a/utils/perf-training/lit.cfg
+++ b/utils/perf-training/lit.cfg
@@ -3,13 +3,14 @@
from lit import Test
import lit.formats
import lit.util
+import subprocess
def getSysrootFlagsOnDarwin(config, lit_config):
# On Darwin, support relocatable SDKs by providing Clang with a
# default system root path.
if 'darwin' in config.target_triple:
try:
- out = lit.util.capture(['xcrun', '--show-sdk-path']).strip()
+ out = subprocess.check_output(['xcrun', '--show-sdk-path']).strip()
res = 0
except OSError:
res = -1
diff --git a/utils/perf-training/order-files.lit.cfg b/utils/perf-training/order-files.lit.cfg
index a4fd81232a..93904ec84a 100644
--- a/utils/perf-training/order-files.lit.cfg
+++ b/utils/perf-training/order-files.lit.cfg
@@ -4,13 +4,14 @@ from lit import Test
import lit.formats
import lit.util
import os
+import subprocess
def getSysrootFlagsOnDarwin(config, lit_config):
# On Darwin, support relocatable SDKs by providing Clang with a
# default system root path.
if 'darwin' in config.target_triple:
try:
- out = lit.util.capture(['xcrun', '--show-sdk-path']).strip()
+ out = subprocess.check_output(['xcrun', '--show-sdk-path']).strip()
res = 0
except OSError:
res = -1
diff --git a/www/analyzer/alpha_checks.html b/www/analyzer/alpha_checks.html
index ce9392b996..7d84d23343 100644
--- a/www/analyzer/alpha_checks.html
+++ b/www/analyzer/alpha_checks.html
@@ -24,6 +24,7 @@ keep them from being on by default. They are likely to have false positives.
Bug reports are welcome but will likely not be investigated for some time.
Patches welcome!
<ul>
+<li><a href="#clone_alpha_checkers">Clone Alpha Checkers</a></li>
<li><a href="#core_alpha_checkers">Core Alpha Checkers</a></li>
<li><a href="#cplusplus_alpha_checkers">C++ Alpha Checkers</a></li>
<li><a href="#valist_alpha_checkers">Variable Argument Alpha Checkers</a></li>
@@ -33,6 +34,38 @@ Patches welcome!
<li><a href="#unix_alpha_checkers">Unix Alpha Checkers</a></li>
</ul>
+<!-- ============================= clone alpha ============================= -->
+
+<h3 id="clone_alpha_checkers">Clone Alpha Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.clone.CloneChecker</span><span class="lang">
+(C, C++, ObjC)</span><div class="descr">
+Reports similar pieces of code.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void log();
+
+int max(int a, int b) { // warn
+ log();
+ if (a > b)
+ return a;
+ return b;
+}
+
+int maxClone(int x, int y) { // similar code here
+ log();
+ if (x > y)
+ return x;
+ return y;
+}
+</pre></div></div></td></tr>
+</tbody></table>
+
<!-- ============================= core alpha ============================= -->
<h3 id="core_alpha_checkers">Core Alpha Checkers</h3>
<table class="checkers">
@@ -53,6 +86,28 @@ void test() {
<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.CallAndMessageUnInitRefArg</span><span class="lang">
+(C, C++)</span><div class="descr">
+Check for uninitialized arguments in function calls and Objective-C
+message expressions.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test(void) {
+ int t;
+ int &p = t;
+ int &s = p;
+ int &q = s;
+ foo(q); // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test(void) {
+ int x;
+ foo(&x); // warn
+}
+</pre></div></div></td></tr>
+
+<tr><td><div class="namedescr expandable"><span class="name">
alpha.core.CastSize</span><span class="lang">
(C)</span><div class="descr">
Check when casting a malloc'ed type T, whether the size is a multiple of the
@@ -91,6 +146,47 @@ void test(int *p) {
<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.Conversion</span><span class="lang">
+(C, C++, ObjC)</span><div class="descr">
+Loss of sign or precision in implicit conversions</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test(unsigned U, signed S) {
+ if (S > 10) {
+ if (U < S) {
+ }
+ }
+ if (S < -10) {
+ if (U < S) { // warn (loss of sign)
+ }
+ }
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ long long A = 1LL << 60;
+ short X = A; // warn (loss of precision)
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.DynamicTypeChecker</span><span class="lang">
+(ObjC)</span><div class="descr">
+Check for cases where the dynamic and the static type of an
+object are unrelated.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+id date = [NSDate date];
+
+// Warning: Object has a dynamic type 'NSDate *' which is
+// incompatible with static type 'NSNumber *'"
+NSNumber *number = date;
+[number doubleValue];
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
alpha.core.FixedAddr</span><span class="lang">
(C)</span><div class="descr">
Check for assignment of a fixed address to a pointer.</div></div></td>
@@ -178,6 +274,21 @@ int test(struct s *p) {
}
</pre></div></div></td></tr>
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.TestAfterDivZero</span><span class="lang">
+(C, C++, ObjC)</span><div class="descr">
+Check for division by variable that is later compared against 0.
+Either the comparison is useless or there is division by zero.
+</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test(int x) {
+ var = 77 / x;
+ if (x == 0) { } // warn
+}
+</pre></div></div></td></tr>
+
</tbody></table>
<!-- =========================== cplusplus alpha =========================== -->
@@ -188,19 +299,6 @@ int test(struct s *p) {
<tbody>
<tr><td><div class="namedescr expandable"><span class="name">
-alpha.cplusplus.NewDeleteLeaks</span><span class="lang">
-(C++)</span><div class="descr">
-Check for memory leaks. Traces memory managed by <code>new</code>/<code>
-delete</code>.</div></div></td>
-<td><div class="exampleContainer expandable">
-<div class="example"><pre>
-void test() {
- int *p = new int;
-} // warn
-</pre></div></div></td></tr>
-
-
-<tr><td><div class="namedescr expandable"><span class="name">
alpha.cplusplus.VirtualCall</span><span class="lang">
(C++)</span><div class="descr">
Check virtual member function calls during construction or
@@ -345,66 +443,6 @@ void test(id x) {
<tbody>
<tr><td><div class="namedescr expandable"><span class="name">
-alpha.osx.cocoa.Dealloc</span><span class="lang">
-(ObjC)</span><div class="descr">
-Warn about Objective-C classes that lack a correct implementation
-of <code>-dealloc</code>.
-</div></div></td>
-<td><div class="exampleContainer expandable">
-<div class="example"><pre>
-@interface MyObject : NSObject {
- id _myproperty;
-}
-@end
-
-@implementation MyObject // warn: lacks 'dealloc'
-@end
-</pre></div><div class="separator"></div>
-<div class="example"><pre>
-@interface MyObject : NSObject {}
-@property(assign) id myproperty;
-@end
-
-@implementation MyObject // warn: does not send 'dealloc' to super
-- (void)dealloc {
- self.myproperty = 0;
-}
-@end
-</pre></div><div class="separator"></div>
-<div class="example"><pre>
-@interface MyObject : NSObject {
- id _myproperty;
-}
-@property(retain) id myproperty;
-@end
-
-@implementation MyObject
-@synthesize myproperty = _myproperty;
- // warn: var was retained but wasn't released
-- (void)dealloc {
- [super dealloc];
-}
-@end
-</pre></div><div class="separator"></div>
-<div class="example"><pre>
-@interface MyObject : NSObject {
- id _myproperty;
-}
-@property(assign) id myproperty;
-@end
-
-@implementation MyObject
-@synthesize myproperty = _myproperty;
- // warn: var wasn't retained but was released
-- (void)dealloc {
- [_myproperty release];
- [super dealloc];
-}
-@end
-</pre></div></div></td></tr>
-
-
-<tr><td><div class="namedescr expandable"><span class="name">
alpha.osx.cocoa.DirectIvarAssignment</span><span class="lang">
(ObjC)</span><div class="descr">
Check that Objective C properties follow the following rule: the property
@@ -501,6 +539,32 @@ invalidatable instance variables.</div></div></td>
@end
</pre></div></div></td></tr>
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.osx.cocoa.localizability.PluralMisuseChecker</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warns against using one vs. many plural pattern in code
+when generating localized strings.
+</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+NSString *reminderText =
+ NSLocalizedString(@"None", @"Indicates no reminders");
+if (reminderCount == 1) {
+ // Warning: Plural cases are not supported accross all languages.
+ // Use a .stringsdict file instead
+ reminderText =
+ NSLocalizedString(@"1 Reminder", @"Indicates single reminder");
+} else if (reminderCount >= 2) {
+ // Warning: Plural cases are not supported accross all languages.
+ // Use a .stringsdict file instead
+ reminderText =
+ [NSString stringWithFormat:
+ NSLocalizedString(@"%@ Reminders", @"Indicates multiple reminders"),
+ reminderCount];
+}
+</pre></div></div></td></tr>
+
</tbody></table>
<!-- =========================== security alpha =========================== -->
@@ -675,52 +739,6 @@ void test() {
}
</pre></div></div></td></tr>
-
-<tr><td><div class="namedescr expandable"><span class="name">
-alpha.unix.MallocWithAnnotations</span><span class="lang">
-(C)</span><div class="descr">
-Check for memory leaks, double free, and use-after-free problems. Assumes that
-all user-defined functions which might free a pointer are
-annotated.</div></div></td>
-<td><div class="exampleContainer expandable">
-<div class="example"><pre>
-void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
-
-void test() {
- int *p = my_malloc(1);
-} // warn: potential leak
-</pre></div><div class="separator"></div>
-<div class="example"><pre>
-void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
-void __attribute((ownership_takes(malloc, 1))) my_free(void *);
-
-void test() {
- int *p = my_malloc(1);
- my_free(p);
- my_free(p); // warn: attempt to free released
-}
-</pre></div><div class="separator"></div>
-<div class="example"><pre>
-void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
-void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
-
-void test() {
- int *p = my_malloc(1);
- my_hold(p);
- free(p); // warn: attempt to free non-owned memory
-}
-</pre></div><div class="separator"></div>
-<div class="example"><pre>
-void __attribute((ownership_takes(malloc, 1))) my_free(void *);
-
-void test() {
- int *p = malloc(1);
- my_free(p);
- *p = 1; // warn: use after free
-}
-</pre></div></div></td></tr>
-
-
<tr><td><div class="namedescr expandable"><span class="name">
alpha.unix.PthreadLock</span><span class="lang">
(C)</span><div class="descr">
@@ -910,30 +928,6 @@ 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/analyzer/available_checks.html b/www/analyzer/available_checks.html
index 7707fc0150..eca8dca616 100644
--- a/www/analyzer/available_checks.html
+++ b/www/analyzer/available_checks.html
@@ -38,12 +38,14 @@ Experimental (Alpha) Checkers</a>.
<li><a href="#core_checkers">Core Checkers</a> model core language features and perform general-purpose checks such as division by zero, null pointer dereference, usage of uninitialized values, etc.</li>
<li><a href="#cplusplus_checkers">C++ Checkers</a> perform C++-specific checks</li>
<li><a href="#deadcode_checkers">Dead Code Checkers</a> check for unused code</li>
+<li><a href="#nullability_checkers">Nullability Checkers</a> </li>
+<li><a href="#optin_checkers">Optin Checkers</a> </li>
<li><a href="#osx_checkers">OS X Checkers</a> perform Objective-C-specific checks and check the use of Apple's SDKs (OS X and iOS)</li>
<li><a href="#security_checkers">Security Checkers</a> check for insecure API usage and perform checks based on the CERT Secure Coding Standards</li>
<li><a href="#unix_checkers">Unix Checkers</a> check the use of Unix and POSIX APIs</li>
</ul>
-<!------------------------------------ core ----------------------------------->
+<!-- =========================== core =========================== -->
<h3 id="core_checkers">Core Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
@@ -360,7 +362,7 @@ int test() {
</tbody></table>
-<!------------------------------------ C++ ------------------------------------>
+<!-- =========================== C++ =========================== -->
<h3 id="cplusplus_checkers">C++ Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
@@ -421,9 +423,21 @@ void test() {
}
</pre></div></div></td></tr>
+<tr><td><div class="namedescr expandable"><span class="name">
+cplusplus.NewDeleteLeaks</span><span class="lang">
+(C++)</span><div class="descr">
+Check for memory leaks. Traces memory managed by <code>new</code>/<code>
+delete</code>.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int *p = new int;
+} // warn
+</pre></div></div></td></tr>
+
</tbody></table>
-<!--------------------------------- dead code --------------------------------->
+<!-- =========================== dead code =========================== -->
<h3 id="deadcode_checkers">Dead Code Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
@@ -444,7 +458,161 @@ void test() {
</tbody></table>
-<!---------------------------------- OS X ------------------------------------>
+<!-- =========================== nullability =========================== -->
+<h3 id="nullability_checkers">Nullability Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+nullability.NullPassedToNonnull</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warns when a null pointer is passed to a pointer which has a
+_Nonnull type.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+if (name != nil)
+ return;
+// Warning: nil passed to a callee that requires a non-null 1st parameter
+NSString *greeting = [@"Hello " stringByAppendingString:name];
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+nullability.NullReturnedFromNonnull</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warns when a null pointer is returned from a function that has
+_Nonnull return type.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+- (nonnull id)firstChild {
+ id result = nil;
+ if ([_children count] > 0)
+ result = _children[0];
+
+ // Warning: nil returned from a method that is expected
+ // to return a non-null value
+ return result;
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+nullability.NullableDereferenced</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warns when a nullable pointer is dereferenced.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+struct LinkedList {
+ int data;
+ struct LinkedList *next;
+};
+
+struct LinkedList * _Nullable getNext(struct LinkedList *l);
+
+void updateNextData(struct LinkedList *list, int newData) {
+ struct LinkedList *next = getNext(list);
+ // Warning: Nullable pointer is dereferenced
+ next->data = 7;
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+nullability.NullablePassedToNonnull</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warns when a nullable pointer is passed to a pointer which has a _Nonnull type.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+typedef struct Dummy { int val; } Dummy;
+Dummy *_Nullable returnsNullable();
+void takesNonnull(Dummy *_Nonnull);
+
+void test() {
+ Dummy *p = returnsNullable();
+ takesNonnull(p); // warn
+}
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+<!-- =========================== optin =========================== -->
+<h3 id="optin_checkers">Optin Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+optin.mpi.MPI-Checker</span><span class="lang">
+(C)</span><div class="descr">
+Checks MPI code</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ double buf = 0;
+ MPI_Request sendReq1;
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM,
+ 0, MPI_COMM_WORLD, &sendReq1);
+} // warn: request 'sendReq1' has no matching wait.
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ double buf = 0;
+ MPI_Request sendReq;
+ MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq);
+ MPI_Irecv(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
+ MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
+ MPI_Wait(&sendReq, MPI_STATUS_IGNORE);
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void missingNonBlocking() {
+ int rank = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Request sendReq1[10][10][10];
+ MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+optin.osx.cocoa.localizability.EmptyLocalizationContextChecker</span><span class="lang">
+(ObjC)</span><div class="descr">
+Check that NSLocalizedString macros include a comment for context.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+- (void)test {
+ NSString *string = NSLocalizedString(@"LocalizedString", nil); // warn
+ NSString *string2 = NSLocalizedString(@"LocalizedString", @" "); // warn
+ NSString *string3 = NSLocalizedStringWithDefaultValue(
+ @"LocalizedString", nil, [[NSBundle alloc] init], nil,@""); // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+optin.osx.cocoa.localizability.NonLocalizedStringChecker</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warns about uses of non-localized NSStrings passed to UI methods
+expecting localized NSStrings</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+NSString *alarmText =
+ NSLocalizedString(@"Enabled", @"Indicates alarm is turned on");
+if (!isEnabled) {
+ alarmText = @"Disabled";
+}
+UILabel *alarmStateLabel = [[UILabel alloc] init];
+
+// Warning: User-facing text should use localized string macro
+[alarmStateLabel setText:alarmText];
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+<!-- =========================== OS X =========================== -->
<h3 id="osx_checkers">OS X Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
@@ -466,6 +634,22 @@ void test() {
<tr><td><div class="namedescr expandable"><span class="name">
+osx.NumberObjectConversion</span><span class="lang">
+(C, C++, ObjC)</span><div class="descr">
+Check for erroneous conversions of objects representing numbers
+into numbers</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
+// Warning: Comparing a pointer value of type 'NSNumber *'
+// to a scalar integer value
+if (photoCount > 0) {
+ [self displayPhotos];
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
osx.SecKeychainAPI</span><span class="lang">
(C)</span><div class="descr">
Check for improper uses of the Security framework's Keychain APIs:<div class=functions>
@@ -581,6 +765,66 @@ void test(void) {
<tr><td><div class="namedescr expandable"><span class="name">
+osx.cocoa.Dealloc</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warn about Objective-C classes that lack a correct implementation
+of <code>-dealloc</code>.
+</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+@interface MyObject : NSObject {
+ id _myproperty;
+}
+@end
+
+@implementation MyObject // warn: lacks 'dealloc'
+@end
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+@interface MyObject : NSObject {}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject // warn: does not send 'dealloc' to super
+- (void)dealloc {
+ self.myproperty = 0;
+}
+@end
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+@interface MyObject : NSObject {
+ id _myproperty;
+}
+@property(retain) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty = _myproperty;
+ // warn: var was retained but wasn't released
+- (void)dealloc {
+ [super dealloc];
+}
+@end
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+@interface MyObject : NSObject {
+ id _myproperty;
+}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty = _myproperty;
+ // warn: var wasn't retained but was released
+- (void)dealloc {
+ [_myproperty release];
+ [super dealloc];
+}
+@end
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
osx.cocoa.IncompatibleMethodTypes</span><span class="lang">
(ObjC)</span><div class="descr">
Check for an incompatible type signature when overriding an Objective-C method.</div></div></td>
@@ -688,6 +932,21 @@ NSComparisonResult test(NSString *s) {
<tr><td><div class="namedescr expandable"><span class="name">
+osx.cocoa.ObjCGenerics</span><span class="lang">
+(ObjC)</span><div class="descr">
+Check for type errors when using Objective-C generics</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+NSMutableArray<NSString *> *names = [NSMutableArray array];
+NSMutableArray *birthDates = names;
+
+// Warning: Conversion from value of type 'NSDate *'
+// to incompatible type 'NSString *'
+[birthDates addObject: [NSDate date]];
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
osx.cocoa.RetainCount</span><span class="lang">
(ObjC)</span><div class="descr">
Check for leaks and violations of the Cocoa Memory Management rules.</div></div></td>
@@ -742,6 +1001,26 @@ method.</div></div></td>
<tr><td><div class="namedescr expandable"><span class="name">
+osx.cocoa.SuperDealloc</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warn about improper use of '[super dealloc]' in Objective-C</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+@interface SuperDeallocThenReleaseIvarClass : NSObject {
+ NSObject *_ivar;
+}
+@end
+
+@implementation SuperDeallocThenReleaseIvarClass
+- (void)dealloc {
+ [super dealloc];
+ [_ivar release]; // warn
+}
+@end
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
osx.cocoa.UnusedIvars</span><span class="lang">
(ObjC)</span><div class="descr">
Warn about private ivars that are never used.</div></div></td>
@@ -855,7 +1134,7 @@ void test() {
</tbody></table>
-<!------------------------------- security ------------------------------------>
+<!-- =========================== security =========================== -->
<h3 id="security_checkers">Security Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
@@ -995,7 +1274,7 @@ void test() {
</tbody></table>
-<!--------------------------------- unix -------------------------------------->
+<!-- =========================== unix =========================== -->
<h3 id="unix_checkers">Unix Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
@@ -1188,6 +1467,38 @@ void test(NSUInteger dataLength) {
<tr><td><div class="namedescr expandable"><span class="name">
+unix.Vfork</span><span class="lang">
+(C)</span><div class="descr">
+Check for proper usage of vfork</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+int test(int x) {
+ pid_t pid = vfork(); // warn
+ if (pid != 0)
+ return 0;
+
+ switch (x) {
+ case 0:
+ pid = 1;
+ execl("", "", 0);
+ _exit(1);
+ break;
+ case 1:
+ x = 0; // warn: this assignment is prohibited
+ break;
+ case 2:
+ foo(); // warn: this function call is prohibited
+ break;
+ default:
+ return 0; // warn: return is prohibited
+ }
+
+ while(1);
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
unix.cstring.BadSizeArg</span><span class="lang">
(C)</span><div class="descr">
Check the size argument passed to <code>strncat</code> for common erroneous
diff --git a/www/analyzer/checker_dev_manual.html b/www/analyzer/checker_dev_manual.html
index 93c98913fd..4883556383 100644
--- a/www/analyzer/checker_dev_manual.html
+++ b/www/analyzer/checker_dev_manual.html
@@ -279,8 +279,8 @@ void ento::registerSimpleStreamChecker(CheckerManager &amp;mgr) {
}
</pre>
<li>A package was selected for the checker and the checker was defined in the
-table of checkers at <tt>lib/StaticAnalyzer/Checkers/Checkers.td</tt>. Since all
-checkers should first be developed as "alpha", and the SimpleStreamChecker
+table of checkers at <tt>include/clang/StaticAnalyzer/Checkers/Checkers.td</tt>.
+Since all checkers should first be developed as "alpha", and the SimpleStreamChecker
performs UNIX API checks, the correct package is "alpha.unix", and the following
was added to the corresponding <tt>UnixAlpha</tt> section of <tt>Checkers.td</tt>:
<pre class="code_example">
@@ -575,8 +575,8 @@ execute a single checker:
processing a large file use the <tt><b>-analyzer-display-progress</b></tt>
option.</p>
-<p>You can analyze a particular function within the file, which is often useful
-because the problem is always in a certain function:</p>
+<p>To selectively analyze only the given function, use the
+<tt><b>-analyze-function</b></tt> option:</p>
<pre class="code">
$ <b>clang -cc1 -analyze -analyzer-checker=core test.c -analyzer-display-progress</b>
ANALYZE (Syntax): test.c foo
@@ -588,6 +588,16 @@ because the problem is always in a certain function:</p>
ANALYZE (Path, Inline_Regular): test.c foo
</pre>
+<b>Note: </b> a fully qualified function name has to be used when selecting
+C++ functions and methods, Objective-C methods and blocks, e.g.:
+
+<pre class="code">
+ $ <b>clang -cc1 -analyze -analyzer-checker=core test.cc -analyze-function=foo(int)</b>
+</pre>
+
+The fully qualified name can be found from the
+<tt><b>-analyzer-display-progress</b></tt> output.
+
<p>The bug reporter mechanism removes path diagnostics inside intermediate
function calls that have returned by the time the bug was found and contain
no interesting pieces. Usually it is up to the checkers to produce more
diff --git a/www/analyzer/implicit_checks.html b/www/analyzer/implicit_checks.html
index a476c9bf32..948f4533b8 100644
--- a/www/analyzer/implicit_checks.html
+++ b/www/analyzer/implicit_checks.html
@@ -27,7 +27,7 @@ and <a href = "alpha_checks.html">Experimental (Alpha) Checkers</a>.
<li><a href="#osx_implicit_checkers">OS X Implicit Checkers</a></li>
</ul>
-<!------------------------------- core implicit ------------------------------->
+<!-- =========================== core implicit =========================== -->
<h3 id="core_implicit_checkers">Core Implicit Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
@@ -124,7 +124,7 @@ void test() {
</tbody></table>
-<!---------------------------- OS X implicit ---------------------------------->
+<!-- =========================== OS X implicit =========================== -->
<h3 id="osx_implicit_checkers">OS X Implicit Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
diff --git a/www/analyzer/open_projects.html b/www/analyzer/open_projects.html
index f354015c3f..744f4eca41 100644
--- a/www/analyzer/open_projects.html
+++ b/www/analyzer/open_projects.html
@@ -107,13 +107,6 @@ mailing list</a> to notify other members of the community.</p>
<li>Bug Reporting
<ul>
- <li>Add support for displaying cross-file diagnostic paths in HTML output
- (used by <tt>scan-build</tt>).
- <p>Currently <tt>scan-build</tt> output does not display reports that span
- multiple files. The main problem is that we do not have a good format to
- display such paths in HTML output. <i>(Difficulty: Medium)</i> </p>
- </li>
-
<li>Refactor path diagnostic generation in <a href="http://clang.llvm.org/doxygen/BugReporter_8cpp_source.html">BugReporter.cpp</a>.
<p>It would be great to have more code reuse between "Minimal" and
"Extensive" PathDiagnostic generation algorithms. One idea is to create an
diff --git a/www/analyzer/scripts/expandcollapse.js b/www/analyzer/scripts/expandcollapse.js
index 593a9831c8..c3ae286467 100644
--- a/www/analyzer/scripts/expandcollapse.js
+++ b/www/analyzer/scripts/expandcollapse.js
@@ -81,7 +81,7 @@ function initExpandCollapse() {
expander.onclick = function() {
expandCollapse(this.id);
// Hack for Opera - onmouseout callback is not invoked when page
- // content changes dinamically and mouse pointer goes out of an element.
+ // content changes dynamically and mouse pointer goes out of an element.
this.src = imgPath +
(getCellInfo(this.id).expanded ? "arrows_light.gif"
: "ellipses_light.gif");
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index 87a36205f5..4402c33a39 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -589,9 +589,9 @@
</tr>
<tr id="92">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#92">92</a></td>
- <td>WP</td>
+ <td>CD4</td>
<td>Should <I>exception-specification</I>s be part of the type system?</td>
- <td class="svn" align="center">Clang 4 (C++17 onwards)</td>
+ <td class="full" align="center">Clang 4 (C++17 onwards)</td>
</tr>
<tr id="93">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#93">93</a></td>
@@ -813,7 +813,7 @@
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#129">129</a></td>
<td>CD3</td>
<td>Stability of uninitialized auto variables</td>
- <td class="svn" align="center">Duplicate of <a href="#616">616</a></td>
+ <td class="full" align="center">Duplicate of <a href="#616">616</a></td>
</tr>
<tr id="130">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#130">130</a></td>
@@ -935,11 +935,11 @@
<td>Accessibility and ambiguity</td>
<td class="na" align="center">N/A</td>
</tr>
- <tr class="open" id="150">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#150">150</a></td>
- <td>open</td>
+ <tr id="150">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#150">150</a></td>
+ <td>DR</td>
<td>Template template parameters and default arguments</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="151">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#151">151</a></td>
@@ -1310,7 +1310,7 @@ accessible?</td>
</tr>
<tr id="212">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#212">212</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Implicit instantiation is not described clearly enough</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -1466,7 +1466,7 @@ accessible?</td>
</tr>
<tr id="238">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#238">238</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Precision and accuracy constraints on floating point</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -1480,7 +1480,7 @@ accessible?</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#240">240</a></td>
<td>CD3</td>
<td>Uninitialized values and undefined behavior</td>
- <td class="svn" align="center">Duplicate of <a href="#616">616</a></td>
+ <td class="full" align="center">Duplicate of <a href="#616">616</a></td>
</tr>
<tr id="241">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#241">241</a></td>
@@ -1490,7 +1490,7 @@ accessible?</td>
</tr>
<tr id="242">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#242">242</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Interpretation of old-style casts</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -1594,7 +1594,7 @@ accessible?</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#259">259</a></td>
<td>CD1</td>
<td>Restrictions on explicit specialization and instantiation</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr class="open" id="260">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#260">260</a></td>
@@ -1913,7 +1913,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#312">312</a></td>
<td>CD3</td>
<td>&#8220;use&#8221; of invalid pointer value not defined</td>
- <td class="svn" align="center">Duplicate of <a href="#616">616</a></td>
+ <td class="full" align="center">Duplicate of <a href="#616">616</a></td>
</tr>
<tr id="313">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#313">313</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="svn" align="center">Superseded by <a href="#1004">1004</a></td>
+ <td class="full" 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="svn" align="center">Superseded by <a href="#1310">1310</a></td>
+ <td class="full" 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>
@@ -2019,7 +2019,7 @@ of class templates</td>
</tr>
<tr id="330">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#330">330</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Qualification conversions and pointers to arrays of pointers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -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="full" align="center">Clang 5</td>
</tr>
<tr id="374">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#374">374</a></td>
@@ -2397,7 +2397,7 @@ of class templates</td>
</tr>
<tr id="393">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#393">393</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Pointer to array of unknown bound in template argument list in parameter</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -3017,7 +3017,7 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#496">496</a></td>
<td>CD3</td>
<td>Is a volatile-qualified type really a POD?</td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">Superseded by <a href="#2094">2094</a></td>
</tr>
<tr id="497">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#497">497</a></td>
@@ -3541,7 +3541,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#583">583</a></td>
<td>CD3</td>
<td>Relational pointer comparisons against the null pointer constant</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr id="584">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#584">584</a></td>
@@ -3587,7 +3587,7 @@ and <I>POD class</I></td>
</tr>
<tr id="591">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#591">591</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>When a dependent base class is the current instantiation</td>
<td class="none" align="center">No</td>
</tr>
@@ -3613,7 +3613,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#595">595</a></td>
<td>dup</td>
<td>Exception specifications in templates instantiated from class bodies</td>
- <td class="svn" align="center">Duplicate of <a href="#1330">1330</a></td>
+ <td class="full" align="center">Duplicate of <a href="#1330">1330</a></td>
</tr>
<tr class="open" id="596">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#596">596</a></td>
@@ -3695,7 +3695,7 @@ and <I>POD class</I></td>
</tr>
<tr id="609">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#609">609</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>What is a &#8220;top-level&#8221; cv-qualifier?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -3739,7 +3739,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#616">616</a></td>
<td>CD3</td>
<td>Definition of &#8220;indeterminate value&#8221;</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr class="open" id="617">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#617">617</a></td>
@@ -5735,7 +5735,7 @@ and <I>POD class</I></td>
</tr>
<tr id="987">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#987">987</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Which declarations introduce namespace members?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -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="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 5</td>
</tr>
<tr id="1005">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1005">1005</a></td>
@@ -5939,7 +5939,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1021">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1021">1021</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Definitions of namespace members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -6509,7 +6509,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1116">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1116">1116</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Aliasing of union members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7093,7 +7093,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1213">1213</a></td>
<td>CD3</td>
<td>Array subscripting and xvalues</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr id="1214">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1214">1214</a></td>
@@ -7295,7 +7295,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1247">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1247">1247</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Restriction on alias name appearing in <I>type-id</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -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="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 5</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>
@@ -7457,7 +7457,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1274">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1274">1274</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Common nonterminal for <I>expression</I> and <I>braced-init-list</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7517,7 +7517,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1284">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1284">1284</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Should the lifetime of an array be independent of that of its elements?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7565,7 +7565,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1292">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1292">1292</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Dependent calls with <I>braced-init-list</I>s containing a pack expansion</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7585,7 +7585,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1295">1295</a></td>
<td>CD3</td>
<td>Binding a reference to an rvalue bit-field</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr id="1296">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1296">1296</a></td>
@@ -7667,7 +7667,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1309">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1309">1309</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Incorrect note regarding lookup of a member of the current instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -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="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 5</td>
</tr>
<tr id="1311">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1311">1311</a></td>
@@ -7703,7 +7703,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1315">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1315">1315</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Restrictions on non-type template arguments in partial specializations</td>
<td class="partial" align="center">Partial</td>
</tr>
@@ -7795,7 +7795,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1330">1330</a></td>
<td>CD3</td>
<td>Delayed instantiation of <TT>noexcept</TT> specifiers</td>
- <td class="svn" align="center">Clang 4 (C++11 onwards)</td>
+ <td class="full" align="center">Clang 4 (C++11 onwards)</td>
</tr>
<tr class="open" id="1331">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1331">1331</a></td>
@@ -7841,7 +7841,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1338">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1338">1338</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Aliasing and allocation functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7870,8 +7870,8 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="1343">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1343">1343</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1343">1343</a></td>
+ <td>DR</td>
<td>Sequencing of non-class initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7919,7 +7919,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1351">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1351">1351</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Problems with implicitly-declared <I>exception-specification</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -7949,7 +7949,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1356">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1356">1356</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Exception specifications of copy assignment operators with virtual bases</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8143,7 +8143,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1388">1388</a></td>
<td>CD3</td>
<td>Missing non-deduced context following a function parameter pack</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr id="1389">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1389">1389</a></td>
@@ -8159,7 +8159,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1391">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1391">1391</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Conversions to parameter types with non-deduced template arguments</td>
<td class="partial" align="center">Partial</td>
</tr>
@@ -8182,8 +8182,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1395">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1395">1395</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1395">1395</a></td>
+ <td>DR</td>
<td>Partial ordering of variadic templates reconsidered</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8195,7 +8195,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1397">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397">1397</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Class completeness in non-static data member initializers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8209,7 +8209,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1399">1399</a></td>
<td>CD3</td>
<td>Deduction with multiple function parameter packs</td>
- <td class="svn" align="center">Duplicate of <a href="#1388">1388</a></td>
+ <td class="full" align="center">Duplicate of <a href="#1388">1388</a></td>
</tr>
<tr id="1400">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1400">1400</a></td>
@@ -8489,7 +8489,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1446">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1446">1446</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Member function with no <I>ref-qualifier</I> and non-member function with rvalue reference</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8603,7 +8603,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1465">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1465">1465</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>noexcept</TT> and <TT>std::bad_array_new_length</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8615,7 +8615,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1467">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467">1467</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>List-initialization of aggregate from same-type object</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -8717,7 +8717,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1484">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1484">1484</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unused local classes of function templates</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8753,7 +8753,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1490">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1490">1490</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>List-initialization from a string literal</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -8765,7 +8765,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1492">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1492">1492</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Exception specifications on template destructors</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8785,11 +8785,11 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1495">1495</a></td>
<td>CD3</td>
<td>Partial specialization of variadic class template</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr id="1496">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1496">1496</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Triviality with deleted and missing default constructors</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -8887,7 +8887,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1512">1512</a></td>
<td>CD3</td>
<td>Pointer comparison vs qualification conversions</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr class="open" id="1513">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1513">1513</a></td>
@@ -8921,9 +8921,9 @@ and <I>POD class</I></td>
</tr>
<tr id="1518">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1518">1518</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Explicit default constructors and copy-list-initialization</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr id="1519">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1519">1519</a></td>
@@ -9125,7 +9125,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1552">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1552">1552</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><I>exception-specification</I>s and defaulted special member functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9161,7 +9161,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1558">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1558">1558</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unused arguments in alias template specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9201,11 +9201,11 @@ and <I>POD class</I></td>
<td>Template argument deduction from an initializer list</td>
<td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="1565">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1565">1565</a></td>
- <td>drafting</td>
+ <tr id="1565">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1565">1565</a></td>
+ <td>NAD</td>
<td>Copy elision and lifetime of <TT>initializer_list</TT> underlying array</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1566">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1566">1566</a></td>
@@ -9239,19 +9239,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1571">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1571">1571</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>cv-qualification for indirect reference binding via conversion function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1572">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1572">1572</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Incorrect example for rvalue reference binding via conversion function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1573">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1573">1573</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Inherited constructor characteristics</td>
<td class="full" align="center">Clang 3.9</td>
</tr>
@@ -9347,7 +9347,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1589">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1589">1589</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Ambiguous ranking of list-initialization sequences</td>
<td class="full" align="center">Clang 3.7 (C++11 onwards)</td>
</tr>
@@ -9359,7 +9359,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1591">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1591">1591</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Deducing array bound and element type from initializer list</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9389,7 +9389,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1596">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1596">1596</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Non-array objects as <TT>array[1]</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9413,7 +9413,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1600">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1600">1600</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Erroneous reference initialization in example</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9431,7 +9431,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1603">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1603">1603</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Errors resulting from giving unnamed namespaces internal linkage</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -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="svn" align="center">Duplicate of <a href="#1658">1658</a></td>
+ <td class="full" 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>
@@ -9497,13 +9497,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1614">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1614">1614</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Address of pure virtual function vs odr-use</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1615">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1615">1615</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Alignment of types, variables, and members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9543,11 +9543,11 @@ and <I>POD class</I></td>
<td>Member initializers in anonymous unions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1622">
+ <tr id="1622">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1622">1622</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Empty aggregate initializer for union</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="1623">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1623">1623</a></td>
@@ -9593,13 +9593,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1630">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1630">1630</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Multiple default constructor templates</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1631">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1631">1631</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Incorrect overload resolution for single-element <I>initializer-list</I></td>
<td class="full" align="center">Clang 3.7</td>
</tr>
@@ -9611,7 +9611,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1633">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1633">1633</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Copy-initialization in member initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9641,13 +9641,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1638">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1638">1638</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Declaring an explicit specialization of a scoped enumeration</td>
<td class="full" align="center">Yes</td>
</tr>
<tr id="1639">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1639">1639</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><I>exception-specification</I>s and pointer/pointer-to-member expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9683,7 +9683,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1645">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1645">1645</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Identical inheriting constructors via default arguments</td>
<td class="full" align="center">Clang 3.9</td>
</tr>
@@ -9725,15 +9725,15 @@ and <I>POD class</I></td>
</tr>
<tr id="1652">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1652">1652</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Object addresses in <TT>constexpr</TT> expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1653">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1653">1653</a></td>
- <td>WP</td>
+ <td>CD4</td>
<td>Removing deprecated increment of <TT>bool</TT></td>
- <td class="svn" align="center">Clang 4 (C++17 onwards)</td>
+ <td class="full" align="center">Clang 4 (C++17 onwards)</td>
</tr>
<tr id="1654">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1654">1654</a></td>
@@ -9755,7 +9755,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1657">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1657">1657</a></td>
- <td>WP</td>
+ <td>CD4</td>
<td>Attributes for namespaces and enumerators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -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="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 5</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>
@@ -9845,7 +9845,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1672">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1672">1672</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Layout compatibility with multiple empty bases</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9873,11 +9873,11 @@ and <I>POD class</I></td>
<td><TT>auto</TT> return type for allocation and deallocation functions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1677">
+ <tr id="1677">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677">1677</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Constant initialization via aggregate initialization</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1678">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1678">1678</a></td>
@@ -9911,7 +9911,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1683">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1683">1683</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Incorrect example after <TT>constexpr</TT> changes</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9929,7 +9929,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1686">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1686">1686</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Which variables are &#8220;explicitly declared <TT>const</TT>?&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9977,7 +9977,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1694">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1694">1694</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Restriction on reference to temporary as a constant expression</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -9989,7 +9989,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1696">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1696">1696</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Temporary lifetime and non-static data member initializers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10043,7 +10043,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1705">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1705">1705</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unclear specification of &#8220;more specialized&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10061,7 +10061,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1708">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1708">1708</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>overly-strict requirements for names with C language linkage</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10085,7 +10085,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1712">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1712">1712</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>constexpr</TT> variable template declarations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10103,7 +10103,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1715">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1715">1715</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Access and inherited constructor templates</td>
<td class="full" align="center">Clang 3.9</td>
</tr>
@@ -10127,7 +10127,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1719">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1719">1719</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Layout compatibility and cv-qualification revisited</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10145,7 +10145,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1722">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1722">1722</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Should lambda to function pointer conversion function be <TT>noexcept</TT>?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10217,7 +10217,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1734">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1734">1734</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Nontrivial deleted copy functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10229,7 +10229,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1736">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1736">1736</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Inheriting constructor templates in a local class</td>
<td class="full" align="center">Clang 3.9</td>
</tr>
@@ -10277,7 +10277,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1744">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1744">1744</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unordered initialization for variable template specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10301,7 +10301,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1748">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1748">1748</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Placement new with a null pointer</td>
<td class="full" align="center">Clang 3.7</td>
</tr>
@@ -10313,25 +10313,25 @@ and <I>POD class</I></td>
</tr>
<tr id="1750">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1750">1750</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>&#8220;Argument&#8221; vs &#8220;parameter&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1751">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1751">1751</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Non-trivial operations vs non-trivial initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1752">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1752">1752</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Right-recursion in <I>mem-initializer-list</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1753">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1753">1753</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><I>decltype-specifier</I> in <I>nested-name-specifier</I> of destructor</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10349,19 +10349,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1756">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1756">1756</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Direct-list-initialization of a non-class object</td>
<td class="full" align="center">Clang 3.7</td>
</tr>
<tr id="1757">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1757">1757</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Const integral subobjects</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1758">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1758">1758</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Explicit conversion in copy/move list initialization</td>
<td class="full" align="center">Clang 3.7</td>
</tr>
@@ -10409,7 +10409,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1766">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1766">1766</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Values outside the range of the values of an enumeration</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10457,7 +10457,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1774">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1774">1774</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Discrepancy between subobject destruction and stack unwinding</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10469,13 +10469,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1776">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1776">1776</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Replacement of class objects containing reference members</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1777">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1777">1777</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Empty pack expansion in <I>dynamic-exception-specification</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10487,13 +10487,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1779">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1779">1779</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Type dependency of <TT>__func__</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1780">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1780">1780</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Explicit instantiation/specialization of generic lambda <TT>operator()</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10505,7 +10505,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1782">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1782">1782</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Form of initialization for <TT>nullptr_t</TT> to <TT>bool</TT> conversion</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10541,7 +10541,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1788">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1788">1788</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Sized deallocation of array of non-class type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10559,7 +10559,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1791">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1791">1791</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Incorrect restrictions on <I>cv-qualifier-seq</I> and <I>ref-qualifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10571,7 +10571,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1793">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1793">1793</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>thread_local</TT> in explicit specializations</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10583,19 +10583,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1795">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1795">1795</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Disambiguating <I>original-namespace-definition</I> and <I>extension-namespace-definition</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1796">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1796">1796</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Is all-bits-zero for null characters a meaningful requirement?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1797">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1797">1797</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Are all bit patterns of <TT>unsigned char</TT> distinct numbers?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10607,13 +10607,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1799">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1799">1799</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>mutable</TT> and non-explicit const qualification</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1800">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1800">1800</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Pointer to member of nested anonymous union</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10625,7 +10625,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1802">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1802">1802</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>char16_t</TT> string literals and surrogate pairs</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10637,25 +10637,25 @@ and <I>POD class</I></td>
</tr>
<tr id="1804">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1804">1804</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Partial specialization and friendship</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1805">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1805">1805</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Conversions of array operands in <I>conditional-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1806">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1806">1806</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Virtual bases and move-assignment</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1807">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1807">1807</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Order of destruction of array elements after an exception</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10667,19 +10667,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1809">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1809">1809</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Narrowing and template argument deduction</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1810">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1810">1810</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Invalid <I>ud-suffix</I>es</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1811">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1811">1811</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Lookup of deallocation function in a virtual destructor definition</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10691,25 +10691,25 @@ and <I>POD class</I></td>
</tr>
<tr id="1813">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1813">1813</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Direct vs indirect bases in standard-layout classes</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1814">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1814">1814</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Default arguments in <I>lambda-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1815">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1815">1815</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Lifetime extension in aggregate initialization</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1816">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1816">1816</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unclear specification of bit-field values</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10727,7 +10727,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1819">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1819">1819</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Acceptable scopes for definition of partial specialization</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10751,19 +10751,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1823">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1823">1823</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>String literal uniqueness in inline functions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1824">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1824">1824</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Completeness of return type vs point of instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1825">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1825">1825</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1825">1825</a></td>
+ <td>DR</td>
<td>Partial ordering between variadic and non-variadic function templates</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10793,7 +10793,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1830">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1830">1830</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Repeated specifiers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10805,7 +10805,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1832">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1832">1832</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Casting to incomplete enumeration</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10817,7 +10817,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1834">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1834">1834</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Constant initialization binding a reference to an xvalue</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10841,7 +10841,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1838">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1838">1838</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Definition via <I>unqualified-id</I> and <I>using-declaration</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10871,7 +10871,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1843">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1843">1843</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Bit-field in conditional operator with <TT>throw</TT> operand</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10889,19 +10889,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1846">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1846">1846</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Declaring explicitly-defaulted implicitly-deleted functions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1847">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1847">1847</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Clarifying compatibility during partial ordering</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1848">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1848">1848</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Parenthesized constructor and destructor declarators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10913,19 +10913,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1850">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1850">1850</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Differences between definition context and point of instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1851">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1851">1851</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>decltype(auto)</TT> in <I>new-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1852">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1852">1852</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Wording issues regarding <TT>decltype(auto)</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10961,7 +10961,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1858">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1858">1858</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Comparing pointers to union members</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10971,15 +10971,15 @@ and <I>POD class</I></td>
<td>UTF-16 in <TT>char16_t</TT> string literals</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="1860">
+ <tr id="1860">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1860">1860</a></td>
- <td>review</td>
+ <td>ready</td>
<td>What is a &#8220;direct member?&#8221;</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1861">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1861">1861</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Values of a bit-field</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -10991,7 +10991,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1863">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1863">1863</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Requirements on thrown object type to support <TT>std::current_exception()</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11003,13 +11003,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1865">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1865">1865</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Pointer arithmetic and multi-level qualification conversions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1866">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1866">1866</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Initializing variant members with non-trivial destructors</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11033,7 +11033,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1870">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1870">1870</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Contradictory wording about definitions vs explicit specialization/instantiation</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11045,25 +11045,25 @@ and <I>POD class</I></td>
</tr>
<tr id="1872">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1872">1872</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Instantiations of <TT>constexpr</TT> templates that cannot appear in constant expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1873">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1873">1873</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Protected member access from derived class friends</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1874">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1874">1874</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Type vs non-type template parameters with <TT>class</TT> keyword</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1875">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1875">1875</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Reordering declarations in class scope</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11075,13 +11075,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1877">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1877">1877</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Return type deduction from <TT>return</TT> with no operand</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1878">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1878">1878</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>operator auto</TT> template</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11099,13 +11099,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1881">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1881">1881</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Standard-layout classes and unnamed bit-fields</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1882">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1882">1882</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Reserved names without library use</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11123,25 +11123,25 @@ and <I>POD class</I></td>
</tr>
<tr id="1885">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1885">1885</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Return value of a function is underspecified</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1886">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1886">1886</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Language linkage for <TT>main()</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1887">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1887">1887</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Problems with <TT>::</TT> as <I>nested-name-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1888">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1888">1888</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Implicitly-declared default constructors and <TT>explicit</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11159,13 +11159,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1891">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1891">1891</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Move constructor/assignment for closure class</td>
- <td class="svn" align="center">Clang 4</td>
+ <td class="full" align="center">Clang 4</td>
</tr>
<tr id="1892">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1892">1892</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Use of <TT>auto</TT> in function type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11183,7 +11183,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1895">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1895">1895</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Deleted conversions in conditional operator operands</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11207,7 +11207,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1899">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1899">1899</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Value-dependent constant expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11225,13 +11225,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1902">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1902">1902</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>What makes a conversion &#8220;otherwise ill-formed&#8221;?</td>
<td class="full" align="center">Clang 3.7</td>
</tr>
<tr id="1903">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1903">1903</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>What declarations are introduced by a non-member <I>using-declaration</I>?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11267,7 +11267,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1909">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1909">1909</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Member class template with the same name as the class</td>
<td class="full" align="center">Yes</td>
</tr>
@@ -11279,7 +11279,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1911">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1911">1911</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>constexpr</TT> constructor with non-literal base class</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11309,7 +11309,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1916">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1916">1916</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>&#8220;Same cv-unqualified type&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11333,7 +11333,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1920">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1920">1920</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Qualification mismatch in <I>pseudo-destructor-name</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11345,7 +11345,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1922">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1922">1922</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Injected class template names and default arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11357,19 +11357,19 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="1924">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1924">1924</a></td>
- <td>drafting</td>
+ <td>review</td>
<td>Definition of &#8220;literal&#8221; and kinds of literals</td>
<td align="center">Not resolved</td>
</tr>
<tr id="1925">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1925">1925</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Bit-field prvalues</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1926">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1926">1926</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Potential results of subscript operator</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11387,13 +11387,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1929">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1929">1929</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>template</TT> keyword following namespace <I>nested-name-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1930">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1930">1930</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><I>init-declarator-list</I> vs <I>member-declarator-list</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11405,7 +11405,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1932">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1932">1932</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Bit-field results of conditional operators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11453,19 +11453,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1940">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1940">1940</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>static_assert</TT> in anonymous unions</td>
<td class="full" align="center">Yes</td>
</tr>
<tr id="1941">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1941">1941</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>SFINAE and inherited constructor default arguments</td>
<td class="full" align="center">Clang 3.9</td>
</tr>
<tr id="1942">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1942">1942</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Incorrect reference to <I>trailing-return-type</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11489,7 +11489,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1946">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1946">1946</a></td>
- <td>WP</td>
+ <td>CD4</td>
<td><I>exception-specification</I>s vs pointer dereference</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11507,7 +11507,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1949">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1949">1949</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>&#8220;sequenced after&#8221; instead of &#8220;sequenced before&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11519,13 +11519,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1951">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1951">1951</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Cv-qualification and literal types</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1952">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1952">1952</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Constant expressions and library undefined behavior</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11543,13 +11543,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1955">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1955">1955</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><TT>#elif</TT> with invalid controlling expression</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1956">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1956">1956</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Reuse of storage of automatic variables</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11561,13 +11561,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1958">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1958">1958</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><TT>decltype(auto)</TT> with parenthesized initializer</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1959">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1959">1959</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Inadvertently inherited copy constructor</td>
<td class="full" align="center">Clang 3.9</td>
</tr>
@@ -11578,8 +11578,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1961">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1961">1961</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1961">1961</a></td>
+ <td>DR</td>
<td>Potentially-concurrent actions within a signal handler</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11591,7 +11591,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1963">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1963">1963</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Implementation-defined identifier characters</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11609,13 +11609,13 @@ and <I>POD class</I></td>
</tr>
<tr id="1966">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1966">1966</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Colon following enumeration <I>elaborated-type-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1967">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1967">1967</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Temporary lifetime and move-elision</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11639,7 +11639,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1971">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1971">1971</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unclear disambiguation of destructor and <TT>operator~</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11663,7 +11663,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1975">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1975">1975</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Permissible declarations for <I>exception-specification</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11681,7 +11681,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1978">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1978">1978</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Redundant description of explicit constructor use</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11699,7 +11699,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1981">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1981">1981</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Implicit contextual conversions and <TT>explicit</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11741,7 +11741,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1988">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1988">1988</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Ambiguity between dependent and non-dependent bases in implicit member access</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11753,19 +11753,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1990">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1990">1990</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Ambiguity due to optional <I>decl-specifier-seq</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="1991">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1991">1991</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Inheriting constructors vs default arguments</td>
<td class="full" align="center">Clang 3.9</td>
</tr>
<tr id="1992">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1992">1992</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><TT>new (std::nothrow) int[N]</TT> can throw</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11783,7 +11783,7 @@ and <I>POD class</I></td>
</tr>
<tr id="1995">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1995">1995</a></td>
- <td>WP</td>
+ <td>CD4</td>
<td><I>exception-specification</I>s and non-type template parameters</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11807,19 +11807,19 @@ and <I>POD class</I></td>
</tr>
<tr id="1999">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1999">1999</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Representation of source characters as universal-character-names</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2000">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2000">2000</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td><I>header-name</I> outside <TT>#include</TT> directive</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2001">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2001">2001</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><I>non-directive</I> is underspecified</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11837,7 +11837,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2004">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2004">2004</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unions with mutable members in constant expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11849,7 +11849,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2006">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2006">2006</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Cv-qualified <TT>void</TT> types</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11861,7 +11861,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2008">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2008">2008</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Default <I>template-argument</I>s underspecified</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11873,7 +11873,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2010">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2010">2010</a></td>
- <td>WP</td>
+ <td>CD4</td>
<td><I>exception-specification</I>s and conversion operators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11885,7 +11885,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2012">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2012">2012</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Lifetime of references</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11903,19 +11903,19 @@ and <I>POD class</I></td>
</tr>
<tr id="2015">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2015">2015</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>odr-use of deleted virtual functions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2016">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2016">2016</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Confusing wording in description of conversion function</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2017">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2017">2017</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Flowing off end is not equivalent to no-expression return</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11927,7 +11927,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2019">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2019">2019</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Member references omitted from description of storage duration</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11945,7 +11945,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2022">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2022">2022</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Copy elision in constant expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11957,7 +11957,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2024">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2024">2024</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Dependent types and unexpanded parameter packs</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11969,13 +11969,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2026">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2026">2026</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Zero-initialization and <TT>constexpr</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2027">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2027">2027</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Unclear requirements for multiple <TT>alignas</TT> specifiers</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -11999,19 +11999,19 @@ and <I>POD class</I></td>
</tr>
<tr id="2031">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2031">2031</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Missing incompatibility for <TT>&amp;&amp;</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2032">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2032">2032</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Default <I>template-argument</I>s of variable templates</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2033">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2033">2033</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Redundant restriction on partial specialization argument</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12041,25 +12041,25 @@ and <I>POD class</I></td>
</tr>
<tr id="2038">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2038">2038</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Document C++14 incompatibility of new braced deduction rule</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2039">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2039">2039</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Constant conversions to <TT>bool</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2040">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2040">2040</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><I>trailing-return-type</I> no longer ambiguous</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2041">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2041">2041</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Namespace for explicit class template specialization</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12077,7 +12077,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2044">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2044">2044</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><TT>decltype(auto)</TT> and <TT>void</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12095,7 +12095,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2047">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2047">2047</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Coordinating &#8220;throws anything&#8221; specifications</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12125,7 +12125,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2052">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2052">2052</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Template argument deduction vs overloaded operators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12179,7 +12179,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2061">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2061">2061</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Inline namespace after simplifications</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12191,13 +12191,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2063">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2063">2063</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Type/nontype hiding in class scope</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2064">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2064">2064</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Conflicting specifications for dependent <I>decltype-specifier</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12209,7 +12209,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2066">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2066">2066</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Does type-dependent imply value-dependent?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12221,13 +12221,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2068">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2068">2068</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>When can/must a defaulted virtual destructor be defined?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2069">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2069">2069</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Do destructors have names?</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12239,7 +12239,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2071">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2071">2071</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><TT>typedef</TT> with no declarator</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12263,13 +12263,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2075">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2075">2075</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Passing short initializer lists to array reference parameters</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2076">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2076">2076</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>List-initialization of arguments for constructor parameters</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12287,7 +12287,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2079">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2079">2079</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><TT>[[</TT> appearing in a <I>balanced-token-seq</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12305,7 +12305,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2082">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2082">2082</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Referring to parameters in unevaluated operands of default arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12317,13 +12317,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2084">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2084">2084</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>NSDMIs and deleted union default constructors</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2085">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2085">2085</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Invalid example of adding special member function via default argument</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12359,7 +12359,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2091">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2091">2091</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Deducing reference non-type template arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12371,25 +12371,25 @@ and <I>POD class</I></td>
</tr>
<tr id="2093">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2093">2093</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Qualification conversion for pointer-to-member handler matching</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2094">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2094">2094</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094">2094</a></td>
+ <td>DR</td>
<td>Trivial copy/move constructor for class with volatile member</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Clang 5</td>
</tr>
<tr id="2095">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2095">2095</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Capturing rvalue references to functions by copy</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2096">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2096">2096</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Constraints on literal unions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12401,25 +12401,25 @@ and <I>POD class</I></td>
</tr>
<tr id="2098">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2098">2098</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Is <TT>uncaught_exceptions()</TT> per-thread?</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2099">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2099">2099</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Inferring the bound of an array static data member</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2100">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2100">2100</a></td>
- <td>tentatively ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2100">2100</a></td>
+ <td>DR</td>
<td>Value-dependent address of static data member of class template</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2101">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2101">2101</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Incorrect description of type- and value-dependence</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12437,7 +12437,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2104">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2104">2104</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Internal-linkage <TT>constexpr</TT> references and ODR requirements</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12449,13 +12449,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2106">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2106">2106</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Unclear restrictions on use of function-type template arguments</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2107">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2107">2107</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Lifetime of temporaries for default arguments in array copying</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12467,7 +12467,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2109">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2109">2109</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Value dependence underspecified</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12491,7 +12491,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2113">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2113">2113</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Incompete specification of types for declarators</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12533,7 +12533,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2120">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2120">2120</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Array as first non-static data member in standard-layout class</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12545,7 +12545,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2122">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2122">2122</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Glvalues of <TT>void</TT> type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12557,7 +12557,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2124">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2124">2124</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Signature of constructor template</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12587,13 +12587,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2129">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2129">2129</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Non-object prvalues and constant expressions</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2130">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2130">2130</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Over-aligned types in <I>new-expression</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12635,7 +12635,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2137">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2137">2137</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>List-initialization from object of same type</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12653,13 +12653,13 @@ and <I>POD class</I></td>
</tr>
<tr id="2140">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2140">2140</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Lvalue-to-rvalue conversion of <TT>std::nullptr_t</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2141">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2141">2141</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Ambiguity in <I>new-expression</I> with <I>elaborated-type-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12670,8 +12670,8 @@ and <I>POD class</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2143">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2143">2143</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2143">2143</a></td>
+ <td>DR</td>
<td>Value-dependency via injected-class-name</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12683,19 +12683,19 @@ and <I>POD class</I></td>
</tr>
<tr id="2145">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2145">2145</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Parenthesized declarator in function definition</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2146">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2146">2146</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Scalar object vs memory location in definition of &#8220;unsequenced&#8221;</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2147">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2147">2147</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Initializer-list arguments and pack deduction</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12731,31 +12731,31 @@ and <I>POD class</I></td>
</tr>
<tr id="2153">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2153">2153</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td><I>pure-specifier</I> in friend declaration</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2154">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2154">2154</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Ambiguity of <I>pure-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2155">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2155">2155</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2155">2155</a></td>
+ <td>DR</td>
<td>Defining classes and enumerations via <I>using-declaration</I>s</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2156">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2156">2156</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Definition of enumeration declared by <I>using-declaration</I></td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2157">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2157">2157</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Further disambiguation of enumeration <I>elaborated-type-specifier</I></td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12791,7 +12791,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2163">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2163">2163</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Labels in <TT>constexpr</TT> functions</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12815,7 +12815,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2167">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2167">2167</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Non-member references with lifetimes within the current evaluation</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12839,7 +12839,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2171">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2171">2171</a></td>
- <td>DRWP</td>
+ <td>CD4</td>
<td>Triviality of copy constructor with less-qualified parameter</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12855,21 +12855,21 @@ and <I>POD class</I></td>
<td>Partial specialization with non-deduced contexts</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2174">
+ <tr id="2174">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2174">2174</a></td>
- <td>drafting</td>
+ <td>ready</td>
<td>Unclear rules for friend definitions in templates</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="2175">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2175">2175</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Ambiguity with attribute in conversion operator declaration</td>
<td class="none" align="center">Unknown</td>
</tr>
<tr id="2176">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2176">2176</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Destroying the returned object when a destructor throws</td>
<td class="none" align="center">Unknown</td>
</tr>
@@ -12893,7 +12893,7 @@ and <I>POD class</I></td>
</tr>
<tr id="2180">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2180">2180</a></td>
- <td>DR</td>
+ <td>CD4</td>
<td>Virtual bases in destructors and defaulted assignment operators</td>
<td class="full" align="center">Yes</td>
</tr>
@@ -12915,11 +12915,11 @@ and <I>POD class</I></td>
<td>Problems in description of potential exceptions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2184">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2184">2184</a></td>
- <td>review</td>
+ <tr id="2184">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2184">2184</a></td>
+ <td>CD4</td>
<td>Missing C compatibility entry for decrement of <TT>bool</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2185">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2185">2185</a></td>
@@ -12957,11 +12957,11 @@ and <I>POD class</I></td>
<td>Insufficient specification of <TT>__has_include</TT></td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2191">
+ <tr id="2191">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2191">2191</a></td>
- <td>open</td>
+ <td>ready</td>
<td>Incorrect result for <TT>noexcept(typeid(v))</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2192">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2192">2192</a></td>
@@ -12975,11 +12975,11 @@ and <I>POD class</I></td>
<td><TT>numeric_limits&lt;int&gt;::radix</TT> and <TT>digits</TT></td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2194">
+ <tr id="2194">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2194">2194</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Impossible case in list initialization</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2195">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2195">2195</a></td>
@@ -12999,11 +12999,11 @@ and <I>POD class</I></td>
<td>Overload resolution and deleted special member functions</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2198">
+ <tr id="2198">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2198">2198</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Linkage of enumerators</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2199">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2199">2199</a></td>
@@ -13017,11 +13017,11 @@ and <I>POD class</I></td>
<td>Conversions in template argument deduction</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2201">
+ <tr id="2201">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2201">2201</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Cv-qualification of array types</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2202">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2202">2202</a></td>
@@ -13041,17 +13041,17 @@ and <I>POD class</I></td>
<td>Naming delegated constructors</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2205">
+ <tr id="2205">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2205">2205</a></td>
- <td>open</td>
+ <td>ready</td>
<td>Restrictions on use of <TT>alignas</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
- <tr class="open" id="2206">
+ <tr id="2206">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2206">2206</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Composite type of object and function pointers</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2207">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2207">2207</a></td>
@@ -13095,11 +13095,11 @@ and <I>POD class</I></td>
<td>Forward declaration of partial specializations</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2214">
+ <tr id="2214">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2214">2214</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Missing requirement on representation of integer values</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2215">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2215">2215</a></td>
@@ -13119,11 +13119,11 @@ and <I>POD class</I></td>
<td><TT>constexpr</TT> constructors for non-literal types</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2218">
+ <tr id="2218">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2218">2218</a></td>
- <td>open</td>
+ <td>ready</td>
<td>Ambiguity and namespace aliases</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2219">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2219">2219</a></td>
@@ -13131,11 +13131,11 @@ and <I>POD class</I></td>
<td>Dynamically-unreachable handlers</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2220">
+ <tr id="2220">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2220">2220</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Hiding index variable in range-based <TT>for</TT></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2221">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2221">2221</a></td>
@@ -13155,11 +13155,11 @@ and <I>POD class</I></td>
<td>Multiple <TT>alignas</TT> specifiers</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2224">
+ <tr id="2224">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2224">2224</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Member subobjects and base-class casts</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2225">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2225">2225</a></td>
@@ -13301,7 +13301,7 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="2248">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2248">2248</a></td>
- <td>open</td>
+ <td>review</td>
<td>Problems with sized delete</td>
<td align="center">Not resolved</td>
</tr>
@@ -13319,7 +13319,7 @@ and <I>POD class</I></td>
</tr>
<tr class="open" id="2251">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2251">2251</a></td>
- <td>open</td>
+ <td>review</td>
<td>Unreachable enumeration list-initialization</td>
<td align="center">Not resolved</td>
</tr>
@@ -13365,11 +13365,11 @@ and <I>POD class</I></td>
<td>Storage deallocation during period of destruction</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2259">
+ <tr id="2259">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2259">2259</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Unclear context describing ambiguity</td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2260">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2260">2260</a></td>
@@ -13383,11 +13383,11 @@ and <I>POD class</I></td>
<td>Explicit instantiation of in-class <TT>friend</TT> definition</td>
<td align="center">Not resolved</td>
</tr>
- <tr class="open" id="2262">
+ <tr id="2262">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2262">2262</a></td>
- <td>open</td>
+ <td>tentatively ready</td>
<td>Attributes for <I>asm-definition</I></td>
- <td align="center">Not resolved</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr class="open" id="2263">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2263">2263</a></td>
@@ -13438,11 +13438,47 @@ and <I>POD class</I></td>
<td align="center">Not resolved</td>
</tr>
<tr id="2271">
- <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2271">2271</a></td>
- <td>ready</td>
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2271">2271</a></td>
+ <td>DR</td>
<td>Aliasing <TT>this</TT></td>
<td class="none" align="center">Unknown</td>
</tr>
+ <tr class="open" id="2272">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2272">2272</a></td>
+ <td>open</td>
+ <td>Implicit initialization of aggregate members of reference type</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2273">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2273">2273</a></td>
+ <td>open</td>
+ <td>Inheriting constructors vs implicit default constructor</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2274">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2274">2274</a></td>
+ <td>open</td>
+ <td>Generic lambda capture vs constexpr if</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2275">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2275">2275</a></td>
+ <td>open</td>
+ <td>Type-dependence of function template</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2276">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2276">2276</a></td>
+ <td>open</td>
+ <td>Dependent <TT>noexcept</TT> and function type-dependence</td>
+ <td align="center">Not resolved</td>
+ </tr>
+ <tr class="open" id="2277">
+ <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2277">2277</a></td>
+ <td>open</td>
+ <td>Ambiguity inheriting constructors with default arguments</td>
+ <td align="center">Not resolved</td>
+ </tr>
</table>
</div>
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 736a08597d..729915e7c2 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -2,7 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang - C++1z, C++14, C++11 and C++98 Status</title>
+ <title>Clang - C++17, C++14, C++11 and C++98 Status</title>
<link type="text/css" rel="stylesheet" href="menu.css">
<link type="text/css" rel="stylesheet" href="content.css">
<style type="text/css">
@@ -11,9 +11,10 @@
.svn { background-color: #FFFF99 }
.full { background-color: #CCFF99 }
.na { background-color: #DDDDDD }
- span:target { background-color: #FFFFBB; outline: #DDDD55 solid thin; }
+ :target { background-color: #FFFFBB; outline: #DDDD55 solid thin; }
th { background-color: #FFDDAA }
td { vertical-align: middle }
+ tt { white-space: nowrap }
</style>
</head>
<body>
@@ -31,7 +32,7 @@
href="#cxx98">C++98 / C++03</a>, <a
href="#cxx11">C++11</a>, and <a
href="#cxx14">C++14</a>), and most of the upcoming <a
-href="#cxx17">C++1z</a> standard.
+href="#cxx17">C++17</a> standard.
<p>The Clang community is continually striving to improve C++ standards
compliance between releases by submitting and tracking <a
@@ -518,14 +519,13 @@ version 3.7.
</p>
</details>
-<h2 id="cxx17">C++1z implementation status</h2>
+<h2 id="cxx17">C++17 implementation status</h2>
-<p>Clang has <b>experimental</b> support for some proposed features of
-the C++ standard following C++14, provisionally named C++1z.
-Note that support for these features may change or be removed without notice,
-as the draft C++1z standard evolves.
+<p>Clang 5 and later implement all the features
+of the C++ 2017 Draft International Standard.
-<p>You can use Clang in C++1z mode with the <code>-std=c++1z</code> option.</p>
+<p>You can use Clang in C++17 mode with the <code>-std=c++17</code> option
+(use <code>-std=c++1z</code> in Clang 4 and earlier).</p>
<details open>
<summary>List of features and minimum Clang version with support</summary>
@@ -533,7 +533,7 @@ as the draft C++1z standard evolves.
<table width="689" border="1" cellspacing="0">
<tr>
<th>Language Feature</th>
- <th>C++1z Proposal</th>
+ <th>C++17 Proposal</th>
<th>Available in Clang?</th>
</tr>
<!-- Issaquah 2014 papers -->
@@ -550,7 +550,7 @@ as the draft C++1z standard evolves.
</tr>
<!--
<tr>
- <td rowspan="2">Terse range-based for loops (removed from C++1z)</td>
+ <td rowspan="2">Terse range-based for loops (removed from C++17)</td>
<td rowspan="2"><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3994.htm">N3994</a></td>
<td class="none" align="center">Clang 3.5: Yes</td>
</tr>
@@ -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="svn" align="center">SVN</td>
+ <td class="full" align="center">Clang 5</td>
</tr>
<tr>
<td>Differing <tt>begin</tt> and <tt>end</tt> types in range-based <tt>for</tt></td>
@@ -679,12 +679,12 @@ 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 rowspan="2">Template argument deduction for class templates</td>
<td><a href="http://wg21.link/p0091r3">P0091R3</a></td>
- <td rowspan="2" class="svn" align="center">SVN</td>
+ <td rowspan="2" class="full" align="center">Clang 5</td>
</tr>
<tr> <!-- from Issaquah -->
<td><a href="http://wg21.link/p0512r0">P0512R0</a></td>
@@ -692,17 +692,17 @@ as the draft C++1z standard evolves.
<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>
@@ -725,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>
@@ -741,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>
@@ -776,6 +776,74 @@ code. This issue is expected to be rectified soon.
</p>
</details>
+<h2 id="cxx20">C++2a implementation status</h2>
+
+<p>Clang has <b>experimental</b> support for some proposed features of
+the C++ standard following C++17, provisionally named C++2a.
+Note that support for these features may change or be removed without notice,
+as the draft C++2a standard evolves.
+
+<p>You can use Clang in C++2a mode with the <code>-std=c++2a</code> option.</p>
+
+<details open>
+<summary>List of features and minimum Clang version with support</summary>
+
+<table width="689" border="1" cellspacing="0">
+ <tr>
+ <th>Language Feature</th>
+ <th>C++2a Proposal</th>
+ <th>Available in Clang?</th>
+ </tr>
+ <!-- Toronto 2017 papers -->
+ <tr>
+ <td>Default member initializers for bit-fields</td>
+ <td><a href="http://wg21.link/p0683r1">P0683R1</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td><tt>const&amp;</tt>-qualified pointers to members</td>
+ <td><a href="http://wg21.link/p0704r1">P0704R1</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td>Allow <i>lambda-capture</i> <tt>[=, this]</tt></td>
+ <td><a href="http://wg21.link/p0409r2">P0409R2</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td><tt>__VA_OPT__</tt> for preprocessor comma elision</td>
+ <td><a href="http://wg21.link/p0306r4">P0306R4</a></td>
+ <td class="svn" align="center">SVN</td>
+ </tr>
+ <tr>
+ <td>Designated initializers</td>
+ <td><a href="http://wg21.link/p0329r4">P0329R4</a></td>
+ <td class="partial" align="center">Partial (extension)</td>
+ </tr>
+ <tr>
+ <td><i>template-parameter-list</i> for generic lambdas</td>
+ <td><a href="http://wg21.link/p0428r2">P0428R2</a></td>
+ <td class="none" align="center">No</td>
+ </tr>
+ <tr>
+ <td>Initializer list constructors in class template argument deduction</td>
+ <td><a href="http://wg21.link/p0702r1">P0702R1</a></td>
+ <td class="svn" align="center">SVN <a href="#p0702">(13)</a></td>
+ </tr>
+ <tr id="p0374">
+ <td>Concepts</td>
+ <td><a href="http://wg21.link/p0734r0">P0734R0</a></td>
+ <td class="none" align="center">No</td>
+ </tr>
+</table>
+</details>
+
+<p>
+<span id="p0702">(13): This is the resolution to a Defect Report, so is applied
+to all language versions supporting class template argument deduction.
+</span>
+</p>
+
<h2 id="ts">Technical specifications and standing documents</h2>
<p>ISO C++ also publishes a number of documents describing additional language
@@ -792,9 +860,9 @@ and library features that are not part of standard C++.</p>
<th>Available in Clang?</th>
</tr>
<tr>
- <td rowspan="3">SD-6: SG10 feature test recommendations</td>
- <td rowspan="3"><a href="http://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations">SD-6</a></td>
- <td rowspan="3">N/A</td>
+ <td rowspan="4">SD-6: SG10 feature test recommendations</td>
+ <td rowspan="4"><a href="http://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations">SD-6</a></td>
+ <td rowspan="4">N/A</td>
<td class="full" align="center">
Clang 3.4 (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3745">N3745</a>)</br>
</td>
@@ -809,6 +877,11 @@ and library features that are not part of standard C++.</p>
Clang 4 (<a href="http://wg21.link/p0096r3">P0096R3</a>)</a>
</td>
</tr>
+ <tr>
+ <td class="full" align="center">
+ Clang 5 (<a href="http://wg21.link/p0096r4">P0096R4</a>)</a>
+ </td>
+ </tr>
<!-- FIXME: Implement latest recommendations.
<tr>
<td class="svn" align="center">
@@ -827,13 +900,13 @@ and library features that are not part of standard C++.</p>
<td>[TS] Concepts</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0121r0.pdf">P0121R0</a></td>
<td></td>
- <td class="none" align="center">WIP</td>
+ <td class="na" align="center">Superseded by <a href="#p0374">P0734R0</a></td>
</tr>
<tr>
<td>[DRAFT TS] Coroutines</td>
- <td><a href="http://wg21.link/p0057r7">P0057R7</a></td>
- <td></td>
- <td class="none" align="center">WIP</td>
+ <td><a href="https://isocpp.org/files/papers/N4663.pdf">N4663</a></td>
+ <td><tt>-fcoroutines-ts<br>-stdlib=libc++</tt></td>
+ <td class="full" align="center">Clang 5</td>
</tr>
<tr>
<td>[TS] Library Fundamentals, Version 1 (invocation type traits)</td>
@@ -849,7 +922,7 @@ and library features that are not part of standard C++.</p>
</tr>
<tr>
<td>[DRAFT TS] Modules</td>
- <td><a href="http://wg21.link/n4592">N4592</a></td>
+ <td><a href="http://wg21.link/n4667">N4667</a></td>
<td><tt>-fmodules-ts</tt></td>
<td class="none" align="center">WIP</td>
</tr>
diff --git a/www/get_started.html b/www/get_started.html
index a8fe3c717f..ae6df0f3f4 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -196,6 +196,10 @@ Visual Studio:</p>
<li><tt>mkdir build</tt> (for building without polluting the source dir)</li>
<li><tt>cd build</tt></li>
<li>If you are using Visual Studio 2013: <tt>cmake -G "Visual Studio 12" ..\llvm</tt></li>
+ <li>By default, the Visual Studio project files generated by CMake use the
+ 32-bit toolset. If you are developing on a 64-bit version of Windows and
+ want to use the 64-bit toolset, pass the ``-Thost=x64`` flag when
+ generating the Visual Studio solution. This requires CMake 3.8.0 or later.</li>
<li>See the <a href="http://www.llvm.org/docs/CMake.html">LLVM CMake guide</a> for
more information on other configuration options for CMake.</li>
<li>The above, if successful, will have created an LLVM.sln file in the
diff --git a/www/hacking.html b/www/hacking.html
index 65d182dfec..96eb7f6594 100644
--- a/www/hacking.html
+++ b/www/hacking.html
@@ -246,9 +246,9 @@
<p>For example:</p>
<pre>
- python C:\Tool\llvm\utils\lit\lit.py -sv
+ python C:\Tools\llvm\utils\lit\lit.py -sv
--param=build_mode=Win32 --param=build_config=Debug
- --param=clang_site_config=c:\Tools\build\tools\clang\test\lit.site.cfg
+ --param=clang_site_config=C:\Tools\build\tools\clang\test\lit.site.cfg
C:\Tools\llvm\tools\clang\test\Sema\wchar.c
</pre>
diff --git a/www/index.html b/www/index.html
index 9a4050121d..63ecc38c86 100644
--- a/www/index.html
+++ b/www/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
<html>
@@ -14,18 +14,18 @@
<!--*********************************************************************-->
<h1>clang: a C language family frontend for LLVM</h1>
<!--*********************************************************************-->
-
+
<p>The goal of the Clang project is to create a new C based language
front-end: C, C++, Objective C/C++, OpenCL C and others for the
<a href="http://www.llvm.org/">LLVM</a> compiler. You can
<a href="get_started.html">get and build</a> the source today.</p>
-
+
<!--=====================================================================-->
<h2 id="goals">Features and Goals</h2>
<!--=====================================================================-->
-
+
<p>Some of the goals for the project include the following:</p>
-
+
<p><b><a href="features.html#enduser">End-User Features</a></b>:</p>
<ul>
@@ -34,7 +34,7 @@
<li>GCC compatibility</li>
</ul>
- <p><b><a href="features.html#applications">Utility and
+ <p><b><a href="features.html#applications">Utility and
Applications</a></b>:</p>
<ul>
@@ -45,7 +45,7 @@
<li>Use the LLVM 'BSD' License</li>
</ul>
- <p><b><a href="features.html#design">Internal Design and
+ <p><b><a href="features.html#design">Internal Design and
Implementation</a></b>:</p>
<ul>
@@ -56,60 +56,60 @@
</ul>
<p>Of course this is only a rough outline of the goals and features of
- Clang. To get a true sense of what it is all about, see the <a
+ Clang. To get a true sense of what it is all about, see the <a
href="features.html">Features</a> section, which breaks
each of these down and explains them in more detail.</p>
-
+
<!--=====================================================================-->
<h2>Why?</h2>
<!--=====================================================================-->
-
+
<p>Development of the new front-end was started out of a need
for a compiler that allows better diagnostics, better integration with
IDEs, a license that is compatible with commercial products, and a
nimble compiler that is easy to develop and maintain. All of these were
motivations for starting work on a new front-end that could
meet these needs.</p>
-
+
<p>A good (but quite dated) introduction to Clang can be found in the
following video lectures:</p>
-
+
<ul>
<li><a href="clang_video-05-25-2007.html">Clang Introduction</a>
(May 2007)</li>
- <li><a href="clang_video-07-25-2007.html">Features and Performance of
+ <li><a href="clang_video-07-25-2007.html">Features and Performance of
Clang</a> (July 2007)</li>
</ul>
-
+
<p>For a more detailed comparison between Clang and other compilers, please
see the <a href="comparison.html">clang comparison page</a>.</p>
-
+
<!--=====================================================================-->
<h2>Current Status</h2>
<!--=====================================================================-->
-
+
<p>Clang is considered to
- be a production quality C, Objective-C, C++ and Objective-C++ compiler when
- targeting X86-32, X86-64, and ARM (other targets may have caveats, but are
+ be a production quality C, Objective-C, C++ and Objective-C++ compiler when
+ targeting X86-32, X86-64, and ARM (other targets may have caveats, but are
usually easy to fix). If you are looking for source analysis or
source-to-source transformation tools, Clang is probably a great
- solution for you. Clang supports C++11, please see the <a
+ solution for you. Clang supports C++11, C++14 and C++17, please see the <a
href="cxx_status.html">C++ status</a> page for more
information.</p>
<!--=====================================================================-->
<h2>Get it and get involved!</h2>
<!--=====================================================================-->
-
+
<p>Start by <a href="get_started.html">getting the code, building it, and
playing with it</a>. This will show you the sorts of things we can do
today and will let you have the "Clang experience" first hand: hopefully
it will "resonate" with you. :)</p>
-
+
<p>Once you've done that, please consider <a href="get_involved.html">getting
involved in the clang community</a>. The Clang developers include numerous
- volunteer contributors with a variety of backgrounds. If you're
+ volunteer contributors with a variety of backgrounds. If you're
interested in
following the development of Clang, signing up for a mailing list is a good
way to learn about how the project works.</p>
diff --git a/www/make_cxx_dr_status b/www/make_cxx_dr_status
index 8a05d41c08..5fe7b9f887 100755
--- a/www/make_cxx_dr_status
+++ b/www/make_cxx_dr_status
@@ -108,12 +108,9 @@ def availability(issue):
if status == 'unknown':
avail = 'Unknown'
avail_style = ' class="none"'
- elif status == '5':
+ elif status == '6':
avail = 'SVN'
avail_style = ' class="svn"'
- elif status == '4':
- avail = 'Clang 4'
- avail_style = ' class="svn"'
elif re.match('^[0-9]+\.?[0-9]*', status):
avail = 'Clang %s' % status
avail_style = ' class="full"'
diff --git a/www/menu.html.incl b/www/menu.html.incl
index 61a44e8390..55b88a06f3 100644..100755
--- a/www/menu.html.incl
+++ b/www/menu.html.incl
@@ -56,9 +56,7 @@
<div class="submenu">
<label>Clang Events</label>
- <a href="http://llvm.org/devmtg/2009-10/">October 2009</a>
- <a href="http://llvm.org/devmtg/2010-11/">November 2010</a>
- <a href="http://llvm.org/devmtg/">LLVM events</a>
+ <a href="http://llvm.org/devmtg/">LLVM Meeting</a>
</div>
</div>